skillshare-ui-website-style

SkillWeb & browsing

Lets your agent build and style React dashboard components and website pages following a consistent design system.

Available today. Use it from your connected AI after setup.

Connect ahel once, and every AI you use reads what you have installed.

Then ask your AI: use the skillshare-ui-website-style skill

About this capability

Skillshare frontend design system for the React dashboard (ui/) and Docusaurus website (website/). Use this skill whenever you: build or modify a dashboard page or component in ui/src/, style or layout website pages or custom CSS in website/, create new React components for the dashboard, add pages

What this skill tells your AI

The instructions your AI receives, as published by runkids/skillshare in .skillshare/skills/skillshare-ui-website-style/SKILL.md and read by ahel’s review.

Enforce the skillshare design system across the two frontends. $ARGUMENTS is the file or area being worked on.

Companion skill: For UX design decisions beyond token/component usage — layout strategy, information hierarchy, interaction patterns, micro-copy, or when designing a new page from scratch — also invoke /ui-ux-pro-max for higher-level design guidance. This skill handles what components and tokens to use; /ui-ux-pro-max handles how to design the experience.

The project has two distinct design systems sharing semantic color names but with different visual treatments:

AspectUI Dashboard (ui/)Website (website/)
StackReact 19 + Vite + Tailwind CSS v4Docusaurus 3 + custom CSS
Font bodyDM SansIBM Plex Sans
Font headingDM SansInter
Font monoSFMono-Regular, MenloJetBrains Mono
Border-radiusClean: 4px/8px/12px/pillWobbly: 255px 15px 225px 15px / ...
ShadowsSubtle blur: 0 1px 3px rgba(...)Hard offset: 4px 4px 0px 0px #2d2d2d
BackgroundFlat #f7f6f3Dot grid on #fdfbf7
Philosophyskillshare-inspired minimalHand-drawn sketchy organic

UI Dashboard (ui/)

Reference implementation: ui/src/pages/LogPage.tsx

For the full human-readable style guide (design philosophy, visual rules, anti-patterns), see references/STYLE_GUIDE.md bundled with this skill.

Design Tokens

Defined in ui/src/index.css (@theme) and ui/src/design.ts:

// ui/src/design.ts
import { radius, shadows, palette } from '../design';

radius.sm   // '4px'  — badges, chips
radius.md   // '8px'  — cards, containers
radius.lg   // '12px' — modals, panels
radius.btn  // '9999px' — pill buttons (skillshare style)
radius.full // '9999px' — avatars

shadows.sm / .md / .lg / .hover / .active / .accent / .blue
palette.accent / .info / .success / .warning / .danger

Color Tokens (Tailwind classes)

RoleClassWhen
Primary texttext-pencilTitles, names, values
Secondarytext-pencil-lightDescriptions, timestamps, labels
Tertiarytext-muted-darkHints, placeholders
Successtext-successPassed, synced, clean
Warningtext-warningDirty, behind, partial
Dangertext-dangerFailed, blocked, critical
Info / Bluetext-blueLinks, info badges, repo URLs
Backgroundbg-surfaceCards, inputs
Page bgbg-paperRoot background
Bordersborder-mutedDefault borders

Rule: Max one accent color per visual region. Don't double up — if a row has a colored dot, skip the colored badge (or vice versa).

Typography

  • Body: DM Sans (via --font-hand)
  • font-mono: timestamps, file paths, durations, code, hashes
  • uppercase tracking-wider: command names, stat labels
  • Size: text-2xl > text-xl > text-base > text-sm > text-xs

Page Structure (mandatory order)

Every page follows this layout:

<div className="space-y-5 animate-fade-in">
  <PageHeader icon={<Icon />} title="..." subtitle="..." actions={<>...</>} />

  {/* Toolbar: tabs + filters */}
  <div className="flex flex-wrap items-end gap-3">
    <SegmentedControl ... />
    <Select ... />
  </div>

  {/* Summary line or stat cards */}
  <SummaryLine ... />

  {/* Content: table, card list, or card grid */}
  {empty ? <EmptyState ... /> : <ContentArea />}

  {/* Dialogs (rendered at bottom, portal via DialogShell) */}
  <ConfirmDialog ... />
</div>

Component Library

ComponentFileAPI
CardCard.tsxvariant="default|accent|outlined", hover, overflow, tilt?, padding="none|sm|md" — accent uses thicker border for emphasis (no stripe)
ButtonButton.tsxvariant="primary|secondary|danger|ghost|link", size="sm|md|lg", loading?
BadgeBadge.tsxvariant="default|success|warning|danger|info|accent", size="sm|md", dot?
PageHeaderPageHeader.tsxicon, title, subtitle?, actions?, backTo? (styled back arrow)
EmptyStateEmptyState.tsxicon (LucideIcon), title, description?, action?
ConfirmDialogConfirmDialog.tsxopen, onConfirm, onCancel, title, message, variant="default|danger"
DialogShellDialogShell.tsxopen, onClose, maxWidth, preventClose (backdrop blur + dialog-in animation)
InputInput.tsxlabel? + standard input props (re-exports Checkbox, Select)
TextareaInput.tsxlabel? + standard textarea props
SelectSelect.tsxlabel?, value, onChange, options[], size="sm|md"
CheckboxCheckbox.tsxlabel, checked, onChange, indeterminate?, disabled?, size="sm|md"
SpinnerSpinner.tsxsize="sm|md|lg" — use instead of <RefreshCw className="animate-spin">
TooltipTooltip.tsxcontent: string, side="top|bottom" — portal-based, 200ms delay
SegmentedControlSegmentedControl.tsxvalue, onChange, options[], connected?, colorFn?
PaginationPagination.tsxpage, totalPages, onPageChange, rangeText?, pageSize?
StatusBadgeStatusBadge.tsxStatus display
Skeleton / PageSkeletonSkeleton.tsxShimmer animation loading states
Toast / useToastToast.tsxtoast(message, 'success'|'error') — exit animation, progress bar, hover pause
FilterTagInputFilterTagInput.tsxTag-based filter input
IconButtonIconButton.tsxIcon-only button with aria-label

Stats Patterns (choose one)

PatternWhen
Inline summary text1-3 stats: "42 ops · 3 errors · last: 2m ago"
Stat card gridDashboard overview KPIs only

Status Patterns (choose one per element)

PatternMarkupWhen
Colored dotw-2 h-2 rounded-fullTable rows, list items, audit findings/rules
Badge<Badge variant="...">Standalone labels

List Patterns

PatternWhen
TableUniform rows, sortable columns, many items
Card list (vertical)Mixed content per row, expandable
Card gridVisual overview, few fields per item

Button Variants

VariantWhen
dangerPermanent destructive: clear log, empty trash, delete forever
secondaryReversible removal: uninstall, remove, restore
ghostCancel, clear filter, reset
primaryPositive action: save, sync, install, run

Separator

Always: border-dashed border-pencil-light/30 (unified opacity, not /20 or /40)

Animations

ContextValue
Card rotationrotate(+-0.15deg) via :nth-child(odd/even)
Standalone accentMax rotate(+-0.3deg)
Hovertransition-all duration-150
Page entryanimate-fade-in (0.2s ease-out)

Keyboard Shortcuts

Registered in KeyboardShortcutsModal.tsx and useGlobalShortcuts.ts:

  • ? — shortcuts modal
  • / — focus search
  • g d/s/t/l — go to Dashboard/Skills/Targets/Log
  • r — refresh page
  • Only fire when no <input> / <textarea> focused
  • Chord timeout: 500ms
  • New shortcuts must be added to KeyboardShortcutsModal
  • Never override browser-native shortcuts (Cmd+C, etc.)

Accessibility

ConcernRequirement
Focus ringfocus:ring-2 focus:ring-blue/20
Touch targetMin 44x44px
Color contrast4.5:1 (WCAG AA)
Icon buttonsaria-label required
Modalsrole="dialog" + aria-modal="true" + useFocusTrap
Selectrole="combobox" + aria-expanded + role="listbox/option"

Card Overflow Gotcha

Card.tsx has overflow-hidden by default for border-radius clipping. Absolute-positioned children (dropdowns, tooltips) get clipped. Fix: pass overflow prop or add className="!overflow-visible".

Data Fetching Pattern

Pages use @tanstack/react-query:

const { data, isPending } = useQuery({
  queryKey: queryKeys.someKey(...),
  queryFn: () => api.someEndpoint(...),
  staleTime: staleTimes.someCategory,
});
  • Query keys: ui/src/lib/queryKeys.ts
  • API client: ui/src/api/client.ts
  • App context: ui/src/context/AppContext.tsx provides { isProjectMode, projectRoot }

Website (website/)

Docusaurus with hand-drawn "sketchy organic" design in website/src/css/custom.css.

Key Differences from UI Dashboard

  • Wobbly borders: border-radius: var(--radius-wobbly) (not clean px values)
  • Hard shadows: 4px 4px 0px 0px #2d2d2d (no blur)
  • Dot grid bg: radial-gradient(var(--color-muted) 1px, transparent 1px) on body
  • Post-it yellow: --color-postit: #fff9c4 for highlights
  • Dashed borders everywhere: navbar, sidebar, tables, pagination, code blocks
  • Button hover: transform: translate(2px, 2px) + shadow shrinks (press-down feel)
  • Links: wavy underline (text-decoration-style: wavy)
  • Dark mode: amber/gold primary (#e8a84c) instead of blue

CSS Variables

See website/src/css/custom.css for full list. Key additions beyond shared palette:

  • --radius-wobbly[-sm|-md|-btn] — hand-drawn border-radius
  • --color-postit[-dark] — yellow highlight
  • --shadow-md: 4px 4px 0px 0px #2d2d2d — hard offset
  • --card-bg, --card-border, --install-bg — component-specific

Docusaurus Classes

  • .button--primary — green bg, pencil border, hard shadow
  • .button--secondary — dashed border, no fill
  • .markdown h2 — dashed bottom border
  • .admonition — wobbly border-radius, left stripe
  • .menu__link--active — post-it yellow background
  • .target-badge — wobbly border for target grid
  • Code blocks get box-shadow: 4px 4px 0px 0px #101827

Homepage Components (website/src/pages/index.tsx)

  • CARD_ROTATIONS array for random hand-drawn tilt
  • WavyDivider — SVG dashed wavy line between sections
  • InstallTabs — tabbed install commands with copy button
  • Hero has hand-drawn SVG connector + underline

Anti-Patterns (Both Systems)

Don'tDo Instead
Emojis as status iconsColored dots, badges, or semantic icons
Stat cards for 1-3 valuesInline summary text
Left-border colored stripes (border-l-*)Colored dots or badges — never use left stripe for emphasis or status
Stripe + badge for same statusPick one per element
Mixed separator opacity (/20, /40)Always border-pencil-light/30
window.confirm()<ConfirmDialog> component
Custom empty-state markup<EmptyState> component
Inline styles for design tokensUse Tailwind classes or design.ts exports
overflow-visible on Card without overflow propPass overflow prop to Card
Dropdowns inside flex-wrap title rowsPut dropdowns on their own row

Checklist Before Submitting

  • Uses existing components (Card, Badge, Button, etc.) — no custom markup for solved patterns
  • Page follows PageHeader → Toolbar → Summary → Content structure
  • Color tokens from Tailwind (text-pencil, not hardcoded #141312)
  • Separator is border-dashed border-pencil-light/30
  • Empty states use <EmptyState>
  • Destructive actions use <ConfirmDialog>
  • All icon buttons have aria-label
  • New shortcuts registered in KeyboardShortcutsModal
  • animate-fade-in on root container
  • Dark mode works (check both themes)

Signals

GitHub stars
3k
Forks
163
Last commit
Sep 2026
Advanced
Catalog kind
skill
Gateway key
skillshare-ui-website-style
Source
github.com/runkids/skillshare