6.1 KiB
6.1 KiB
MAL Design System
Overview
This design system is for the MAL anime streaming service. It provides reusable components, design tokens, and patterns for building consistent UI.
Design Tokens
Colors
| Token | Value | Usage |
|---|---|---|
--color-background |
#080808 |
Main page background |
--color-background-sidebar |
#0f0f0f |
Sidebar background |
--color-background-header |
#141414 |
Sticky header |
--color-background-surface |
#202020 |
Cards, dropdowns |
--color-background-button |
#1a1a1a |
Button default state |
--color-background-button-hover |
#252525 |
Button hover state |
--color-foreground-muted |
#6a6b70 |
Secondary text, icons |
--color-foreground |
#f8f9fa |
Primary text |
--color-accent |
#9f7aea |
Primary accent (violet) |
--color-danger |
#dc2626 |
Error states, delete actions |
Typography
| Role | Font | Size | Weight |
|---|---|---|---|
| Title | DM Sans | 20px | 600 |
| Body | DM Sans | 14px | 400 |
| Label | DM Sans | 14px | 500 |
| Small | DM Sans | 12px | 400 |
Spacing
| Token | Value |
|---|---|
--space-1 |
0.25rem |
--space-2 |
0.5rem |
--space-3 |
0.75rem |
--space-4 |
1rem |
--space-5 |
1.25rem |
--space-6 |
1.5rem |
--space-8 |
2rem |
Components
1. Anime Card (anime_card.gohtml)
A poster card with hover reveal.
Usage:
{{template "anime_card" dict "Anime" . "WithActions" true "IsWatchlist" false}}
Props:
Anime- Anime data objectWithActions- Show hover overlay with actions (bool)IsWatchlist- Show in-watchlist state (bool)Compact- Hide metadata below (bool)HideTitle- Hide title below image (bool)HasTopBadge- Adjust overlay padding for badge (bool)
States:
- Default: Image with subtle dark placeholder
- Hover: Black overlay (80%) reveals title, synopsis, watchlist button
2. Navigation (navigation.gohtml)
Sidebar navigation with active indicator.
Usage:
{{template "navigation" dict "CurrentPath" .CurrentPath}}
Props:
CurrentPath- Current page path for active state
Items:
- Home (
/) - Browse (
/browse) - Discover (
/discover) - Watchlist (
/watchlist)
States:
- Default: Muted gray text
- Hover:
bg-white/5 - Active: Accent text + left border (
w-0.5 bg-accent) + subtle glow
3. Dropdown (dropdown.gohtml)
Custom dropdown using <ui-dropdown> web component.
Usage:
<ui-dropdown class="relative block" data-align="left" data-width="w-48">
<div data-trigger>
<button>Trigger</button>
</div>
<div data-content class="hidden absolute ...">
<button>Option 1</button>
<button>Option 2</button>
</div>
</ui-dropdown>
Attributes:
data-align-leftorrightalignmentdata-width- Width (Tailwind class)
Styling:
- Background:
#1a1a1a - No border radius
- Items: 10px vertical padding, hover
bg-white/10
4. Filter Bar (filter_bar.gohtml)
Search and filter controls for browse page.
Usage:
{{template "filter_bar" .}}
Controls:
- Search input (text)
- Genre dropdown (multi-select)
- Status dropdown (airing, complete, upcoming)
- Type dropdown (tv, movie, ova, special, ona)
- Sort dropdown + order toggle
5. Header (header.gohtml)
Sticky header with logo, search, and user menu.
Usage:
{{template "header" .}}
Sections:
- Left: Mobile menu toggle, sidebar toggle, logo
- Center: Search input (desktop only)
- Right: User avatar dropdown
6. Watchlist Actions (watchlist_actions.gohtml)
Watchlist toggle button.
Usage:
{{template "watchlist_actions" dict "MalID" 123 "IsWatchlist" true}}
Props:
MalID- Anime MAL IDIsWatchlist- Current state
States:
- Not in watchlist: Outline icon, accent on hover
- In watchlist: Filled icon (
fill: currentColor)
7. Video Player (video_player.gohtml)
Video player container for episodes.
Usage:
{{template "video_player" dict "WatchData" .WatchData "TotalEpisodes" .Anime.Episodes}}
Props:
WatchData- Video source dataTotalEpisodes- Total episode count
8. Continue Watching (continue_watching.gohtml)
Horizontal row for continue watching section.
Usage:
{{template "continue_watching" .ContinueWatching}}
Props:
- Array of anime with watch progress
Patterns
Button Variants
Primary:
<button class="bg-accent text-black px-4 py-2">Action</button>
Secondary:
<button class="bg-white/5 text-neutral-300 px-4 py-2 hover:bg-white/10">Action</button>
Danger:
<button class="bg-red-500/10 text-red-400 px-4 py-2 hover:bg-red-500/20">Delete</button>
Empty State
<div class="flex flex-col items-center justify-center gap-4 py-24">
<svg class="h-16 w-16 opacity-30">...</svg>
<p class="text-neutral-300 font-medium">Title</p>
<p class="text-neutral-500 text-sm">Description</p>
<div class="flex gap-3 mt-2">
<a class="bg-accent/20 text-accent px-5 py-2.5">Action</a>
<a class="bg-white/10 text-neutral-200 px-5 py-2.5">Secondary</a>
</div>
</div>
Card Grid
<div class="grid grid-cols-2 gap-4 md:grid-cols-3 lg:grid-cols-4 2xl:grid-cols-6">
<!-- Cards -->
</div>
Episode List Item
<a class="flex items-center gap-3 px-3 py-2 hover:bg-white/5 border-l-2 {{if .Filler}}border-l-yellow-500{{end}} {{if .Recap}}border-l-blue-500{{end}} {{if $isCurrent}}bg-accent/20{{end}}">
<span class="w-10 shrink-0 text-xs font-medium text-neutral-500">EP{{.MalID}}</span>
<span class="truncate text-sm text-neutral-300">{{.Title}}</span>
</a>
Migration Guide
Adding a New Component
- Create template in
templates/components/ - Document props and usage in this file
- Add to component index above
Updating Existing Components
- Make changes in
templates/components/ - Update this documentation
- Test across all usage sites
Design Token Changes
- Update in
static/style.css - Update YAML frontmatter in
DESIGN.md - Update this token reference