Skillshare skillshare-ui-website-style
git clone https://github.com/runkids/skillshare
T=$(mktemp -d) && git clone --depth=1 https://github.com/runkids/skillshare "$T" && mkdir -p ~/.claude/skills && cp -r "$T/.skillshare/skills/skillshare-ui-website-style" ~/.claude/skills/runkids-skillshare-skillshare-ui-website-style && rm -rf "$T"
.skillshare/skills/skillshare-ui-website-style/SKILL.mdEnforce 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:
| Aspect | UI Dashboard () | Website () |
|---|---|---|
| Stack | React 19 + Vite + Tailwind CSS v4 | Docusaurus 3 + custom CSS |
| Font body | DM Sans | IBM Plex Sans |
| Font heading | DM Sans | Inter |
| Font mono | SFMono-Regular, Menlo | JetBrains Mono |
| Border-radius | Clean: ///pill | Wobbly: |
| Shadows | Subtle blur: | Hard offset: |
| Background | Flat | Dot grid on |
| Philosophy | skillshare-inspired minimal | Hand-drawn sketchy organic |
UI Dashboard (ui/
)
ui/Reference implementation:
ui/src/pages/LogPage.tsx
For the full human-readable style guide (design philosophy, visual rules, anti-patterns), see
bundled with this skill.references/STYLE_GUIDE.md
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)
| Role | Class | When |
|---|---|---|
| Primary text | | Titles, names, values |
| Secondary | | Descriptions, timestamps, labels |
| Tertiary | | Hints, placeholders |
| Success | | Passed, synced, clean |
| Warning | | Dirty, behind, partial |
| Danger | | Failed, blocked, critical |
| Info / Blue | | Links, info badges, repo URLs |
| Background | | Cards, inputs |
| Page bg | | Root background |
| Borders | | Default 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
: timestamps, file paths, durations, code, hashesfont-mono
: command names, stat labelsuppercase tracking-wider- Size:
>text-2xl
>text-xl
>text-base
>text-smtext-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
| Component | File | API |
|---|---|---|
| | , , , , — accent uses thicker border for emphasis (no stripe) |
| | , , |
| | , , |
| | , , , , (styled back arrow) |
| | (LucideIcon), , , |
| | , , , , , |
| | , , , (backdrop blur + dialog-in animation) |
| | + standard input props (re-exports Checkbox, Select) |
| | + standard textarea props |
| | , , , , |
| | , , , , , |
| | — use instead of |
| | , — portal-based, 200ms delay |
| | , , , , |
| | , , , , |
| | Status display |
/ | | Shimmer animation loading states |
/ | | — exit animation, progress bar, hover pause |
| | Tag-based filter input |
| | Icon-only button with |
Stats Patterns (choose one)
| Pattern | When |
|---|---|
| Inline summary text | 1-3 stats: |
| Stat card grid | Dashboard overview KPIs only |
Status Patterns (choose one per element)
| Pattern | Markup | When |
|---|---|---|
| Colored dot | | Table rows, list items, audit findings/rules |
| Badge | | Standalone labels |
List Patterns
| Pattern | When |
|---|---|
| Table | Uniform rows, sortable columns, many items |
| Card list (vertical) | Mixed content per row, expandable |
| Card grid | Visual overview, few fields per item |
Button Variants
| Variant | When |
|---|---|
| Permanent destructive: clear log, empty trash, delete forever |
| Reversible removal: uninstall, remove, restore |
| Cancel, clear filter, reset |
| Positive action: save, sync, install, run |
Separator
Always:
border-dashed border-pencil-light/30 (unified opacity, not /20 or /40)
Animations
| Context | Value |
|---|---|
| Card rotation | via |
| Standalone accent | Max |
| Hover | |
| Page entry | (0.2s ease-out) |
Keyboard Shortcuts
Registered in
KeyboardShortcutsModal.tsx and useGlobalShortcuts.ts:
— shortcuts modal?
— focus search/
— go to Dashboard/Skills/Targets/Logg d/s/t/l
— refresh pager- Only fire when no
/<input>
focused<textarea> - Chord timeout: 500ms
- New shortcuts must be added to
KeyboardShortcutsModal - Never override browser-native shortcuts (
, etc.)Cmd+C
Accessibility
| Concern | Requirement |
|---|---|
| Focus ring | |
| Touch target | Min 44x44px |
| Color contrast | 4.5:1 (WCAG AA) |
| Icon buttons | required |
| Modals | + + |
| Select | + + |
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:
providesui/src/context/AppContext.tsx{ isProjectMode, projectRoot }
Website (website/
)
website/Docusaurus with hand-drawn "sketchy organic" design in
website/src/css/custom.css.
Key Differences from UI Dashboard
- Wobbly borders:
(not clean px values)border-radius: var(--radius-wobbly) - Hard shadows:
(no blur)4px 4px 0px 0px #2d2d2d - Dot grid bg:
on bodyradial-gradient(var(--color-muted) 1px, transparent 1px) - Post-it yellow:
for highlights--color-postit: #fff9c4 - Dashed borders everywhere: navbar, sidebar, tables, pagination, code blocks
- Button hover:
+ shadow shrinks (press-down feel)transform: translate(2px, 2px) - Links: wavy underline (
)text-decoration-style: wavy - Dark mode: amber/gold primary (
) instead of blue#e8a84c
CSS Variables
See
website/src/css/custom.css for full list. Key additions beyond shared palette:
— hand-drawn border-radius--radius-wobbly[-sm|-md|-btn]
— yellow highlight--color-postit[-dark]
— hard offset--shadow-md: 4px 4px 0px 0px #2d2d2d
,--card-bg
,--card-border
— component-specific--install-bg
Docusaurus Classes
— green bg, pencil border, hard shadow.button--primary
— dashed border, no fill.button--secondary
— dashed bottom border.markdown h2
— wobbly border-radius, left stripe.admonition
— post-it yellow background.menu__link--active
— wobbly border for target grid.target-badge- Code blocks get
box-shadow: 4px 4px 0px 0px #101827
Homepage Components (website/src/pages/index.tsx
)
website/src/pages/index.tsx
array for random hand-drawn tiltCARD_ROTATIONS
— SVG dashed wavy line between sectionsWavyDivider
— tabbed install commands with copy buttonInstallTabs- Hero has hand-drawn SVG connector + underline
Anti-Patterns (Both Systems)
| Don't | Do Instead |
|---|---|
| Emojis as status icons | Colored dots, badges, or semantic icons |
| Stat cards for 1-3 values | Inline summary text |
Left-border colored stripes () | Colored dots or badges — never use left stripe for emphasis or status |
| Stripe + badge for same status | Pick one per element |
Mixed separator opacity (, ) | Always |
| component |
| Custom empty-state markup | component |
| Inline styles for design tokens | Use Tailwind classes or exports |
on Card without prop | Pass prop to Card |
Dropdowns inside title rows | Put 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 (
, not hardcodedtext-pencil
)#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 -
on root containeranimate-fade-in - Dark mode works (check both themes)