phoenix-duskmoon-design
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChinesePhoenix DuskMoon Design Conventions
Phoenix DuskMoon 设计规范
Design Thinking
设计思路
Before building any page or view, commit to an intentional aesthetic direction within the DuskMoon design system:
- Purpose: What does this page do? Dashboard, form, marketing, admin, content?
- Density: Dense data UI vs generous editorial spacing — pick one per view
- Emphasis: Identify the single most important action or content block — that gets primary color; everything else recedes
- Depth: How many surface layers does this view need? Flat (1-2 levels) vs layered (3-4 levels)
DuskMoon provides the tokens — your job is to use them with intention, not uniformly.
在构建任何页面或视图前,需遵循DuskMoon设计系统的明确美学方向:
- 用途:该页面的功能是什么?仪表盘、表单、营销页、管理后台还是内容页?
- 密度:选择密集型数据UI或宽松型编辑排版——每个视图仅选一种
- 重点:确定单个最重要的操作或内容区块——使用主色调;其余元素弱化显示
- 深度:该视图需要多少层表面?扁平化(1-2层)还是分层式(3-4层)
DuskMoon提供设计令牌——你的任务是有针对性地使用它们,而非统一套用。
Theme Setup
主题设置
CSS Entry (Required)
CSS 入口(必填)
css
@import "tailwindcss";
@plugin "@duskmoon-dev/core/plugin";
@import "phoenix_duskmoon/components";css
@import "tailwindcss";
@plugin "@duskmoon-dev/core/plugin";
@import "phoenix_duskmoon/components";HTML Root (Required)
HTML 根节点(必填)
heex
<html lang="en" data-theme="sunshine">Themes: (light), (dark).
sunshinemoonlightheex
<html lang="en" data-theme="sunshine">主题选项:(浅色)、(深色)。
sunshinemoonlightBody Base
基础Body设置
heex
<body class="bg-surface text-on-surface">Every page starts on with text. No exceptions.
surfaceon-surfaceheex
<body class="bg-surface text-on-surface">所有页面均以背景搭配文本开始,无例外。
surfaceon-surfaceTheme Switcher
主题切换器
Always include in the appbar. Requires hook.
<.dm_theme_switcher />ThemeSwitcher需始终在应用栏中包含,依赖钩子。
<.dm_theme_switcher />ThemeSwitcherComponent Default Colors
组件默认颜色
Page Shell
页面框架
| Component | Color | Class / Pattern |
|---|---|---|
| Appbar | primary | |
| Page background | surface | |
| Sidebar | secondary | |
| Footer | surface-container-high | |
| Bottom nav | primary | |
| Drawer | secondary | |
The appbar is the brand anchor — always primary. The sidebar and drawer use secondary to create a strong navigation identity distinct from the content area. The page body is always surface. Footer uses higher surface elevation for subtle separation.
heex
<.dm_appbar title={@page_title} sticky>
<:logo>...</:logo>
<:menu to={~p"/dashboard"} active={@active == :dashboard}>Dashboard</:menu>
<:user_profile><.dm_theme_switcher /></:user_profile>
</.dm_appbar>
<div class="flex">
<aside class="bg-secondary text-secondary-content w-64 min-h-screen p-4">
<.dm_left_menu active={@current_path}>
<:menu>...</:menu>
</.dm_left_menu>
</aside>
<main class="flex-1 p-6">
<%= @inner_content %>
</main>
</div>
<.dm_page_footer label="© 2026 MyApp" />| 组件 | 颜色 | 类名 / 模式 |
|---|---|---|
| 应用栏 | primary | |
| 页面背景 | surface | |
| 侧边栏 | secondary | |
| 页脚 | surface-container-high | |
| 底部导航 | primary | |
| 抽屉 | secondary | |
应用栏是品牌锚点——始终使用主色调。侧边栏和抽屉使用次要色调,打造与内容区明确区分的导航标识。页面主体始终为surface。页脚使用更高层级的表面实现微妙分隔。
heex
<.dm_appbar title={@page_title} sticky>
<:logo>...</:logo>
<:menu to={~p"/dashboard"} active={@active == :dashboard}>Dashboard</:menu>
<:user_profile><.dm_theme_switcher /></:user_profile>
</.dm_appbar>
<div class="flex">
<aside class="bg-secondary text-secondary-content w-64 min-h-screen p-4">
<.dm_left_menu active={@current_path}>
<:menu>...</:menu>
</.dm_left_menu>
</aside>
<main class="flex-1 p-6">
<%= @inner_content %>
</main>
</div>
<.dm_page_footer label="© 2026 MyApp" />Actions
操作组件
| Component | Default | When to Change |
|---|---|---|
| Primary button | | Main page action — one per view |
| Secondary button | | Alternative actions |
| Tertiary button | | Accent features, special highlights |
| Destructive button | | Delete, remove, irreversible |
| Ghost button | | Toolbar, low-emphasis, cancel |
| Link button | | Inline text actions |
| Outline button | | Medium emphasis, toggleable |
heex
<div class="flex gap-2">
<.dm_btn variant="ghost">Cancel</.dm_btn>
<.dm_btn variant="primary">Save Changes</.dm_btn>
</div>| 组件 | 默认值 | 变更场景 |
|---|---|---|
| 主按钮 | | 页面核心操作——每个视图仅一个 |
| 次要按钮 | | 备选操作 |
| 三级按钮 | | 特色功能、特殊高亮 |
| 破坏性按钮 | | 删除、移除等不可逆操作 |
| 幽灵按钮 | | 工具栏、低强调、取消操作 |
| 链接按钮 | | 行内文本操作 |
| 轮廓按钮 | | 中等强调、可切换状态 |
heex
<div class="flex gap-2">
<.dm_btn variant="ghost">Cancel</.dm_btn>
<.dm_btn variant="primary">Save Changes</.dm_btn>
</div>Content
内容组件
| Component | Color | Notes |
|---|---|---|
| Card | surface-container | Default CSS — no class needed |
| Card (elevated) | surface-container-high | Add |
| Modal / Dialog | surface-container-highest | Highest elevation |
| Tooltip | primary | |
| Popover | surface-container-high | |
| Accordion | surface-container | |
| Bottom sheet | surface-container-high | |
| Snackbar | inverse-surface or type-based | Use |
| 组件 | 颜色 | 说明 |
|---|---|---|
| 卡片 | surface-container | 默认CSS——无需额外类名 |
| 卡片(带阴影) | surface-container-high | 添加 |
| 模态框 / 对话框 | surface-container-highest | 最高层级 |
| 提示框 | primary | 默认 |
| 弹出框 | surface-container-high | |
| 折叠面板 | surface-container | |
| 底部面板 | surface-container-high | |
| Snackbar | inverse-surface 或基于类型 | 使用 |
Data Display
数据展示组件
| Component | Color | Notes |
|---|---|---|
| Badge | | Use |
| Chip | | Semantic colors for status: |
| Progress | | |
| Avatar | | Initials placeholder color |
| Stat | no color | |
| Timeline | semantic per item | |
| Table | no color | |
| 组件 | 颜色 | 说明 |
|---|---|---|
| 徽章 | | 使用 |
| 芯片 | | 状态使用语义色: |
| 进度条 | | 完成状态用 |
| 头像 | | 首字母占位符颜色 |
| 统计组件 | 无颜色 | 关键指标仅使用 |
| 时间线 | 每项使用语义色 | |
| 表格 | 无颜色 | |
Forms
表单组件
| Component | Color | Notes |
|---|---|---|
| Input | no color | Uses outline border. Set |
| Checkbox | | |
| Radio | | |
| Switch | | |
| Select | no color | |
| Slider | | |
| Rating | | |
| 组件 | 颜色 | 说明 |
|---|---|---|
| 输入框 | 无颜色 | 使用轮廓边框,仅在强调场景设置 |
| 复选框 | | |
| 单选框 | | |
| 开关 | | |
| 选择器 | 无颜色 | |
| 滑块 | | |
| 评分组件 | | 星级评分用 |
Feedback
反馈组件
| Component | Color | Notes |
|---|---|---|
| Alert | type-based | |
| Flash | kind-based | |
| Toast | type-based | Always set |
| Loading spinner | |
| 组件 | 颜色 | 说明 |
|---|---|---|
| 提示框 | 基于类型 | |
| 消息闪框 | 基于类型 | |
| 吐司提示 | 基于类型 | 需始终设置 |
| 加载 spinner | |
Navigation
导航组件
| Component | Color | Notes |
|---|---|---|
| Appbar | primary | Always |
| Navbar | surface-container-high | |
| Tabs | no color | Active = primary underline |
| Breadcrumb | on-surface-variant | Muted text |
| Steps | | Completed = filled, upcoming = outline |
| Left menu | secondary | Active item = primary-content highlight |
| 组件 | 颜色 | 说明 |
|---|---|---|
| 应用栏 | primary | 始终使用 |
| 导航栏 | surface-container-high | |
| 标签页 | 无颜色 | 激活项用主色调下划线 |
| 面包屑 | on-surface-variant | 弱化文本 |
| 步骤条 | | 已完成=填充,待完成=轮廓 |
| 左侧菜单 | secondary | 激活项用primary-content高亮 |
Color Rules
配色规则
Rule 1: No Hardcoded Colors
规则1:禁止硬编码颜色
Never use hex, rgb, hsl, named colors, or Tailwind palette classes (, ). All colors from design tokens only.
bg-blue-500text-slate-600heex
<%# FORBIDDEN %>
<div style="background: #3b82f6;">
<div class="bg-blue-500 text-white">
<%# CORRECT %>
<div class="bg-primary text-primary-content">绝不要使用十六进制、rgb、hsl、命名颜色或Tailwind调色板类(、)。所有颜色仅使用设计令牌。
bg-blue-500text-slate-600heex
<%# 禁止写法 %>
<div style="background: #3b82f6;">
<div class="bg-blue-500 text-white">
<%# 正确写法 %>
<div class="bg-primary text-primary-content">Rule 2: Pair Background + Text
规则2:背景与文本配对使用
Every background token has a text counterpart. Always use them together.
| Background | Text |
|---|---|
| |
| |
| |
| |
| |
| |
| |
| |
| |
每个背景令牌都有对应的文本令牌,需始终配对使用。
| 背景 | 文本 |
|---|---|
| |
| |
| |
| |
| |
| |
| |
| |
| |
Rule 3: Surface Elevation — Low to High
规则3:表面层级从低到高
Nest surfaces from low to high. Never place lower elevation inside higher.
surface (page)
├─ secondary (sidebar, drawer)
└─ surface-container (card)
└─ surface-container-high (navbar, popover, elevated card)
└─ surface-container-highest (dialog, tooltip)从低到高嵌套表面,绝不要在高层级内放置低层级元素。
surface (页面)
├─ secondary (侧边栏、抽屉)
└─ surface-container (卡片)
└─ surface-container-high (导航栏、弹出框、带阴影卡片)
└─ surface-container-highest (对话框、提示框)Rule 4: Semantic Colors for States Only
规则4:语义色仅用于状态
successwarningerrorinfoheex
<%# CORRECT %>
<.dm_alert variant="error">Validation failed</.dm_alert>
<.dm_badge variant="success">Active</.dm_badge>
<%# WRONG %>
<.dm_btn variant="success">Submit</.dm_btn> <%# Use primary %>successwarningerrorinfoheex
<%# 正确写法 %>
<.dm_alert variant="error">验证失败</.dm_alert>
<.dm_badge variant="success">已激活</.dm_badge>
<%# 错误写法 %>
<.dm_btn variant="success">提交</.dm_btn> <%# 应使用primary %>Rule 5: Primary = Brand, Secondary = Support, Tertiary = Accent
规则5:主色调=品牌,次要色调=辅助,第三色调=强调
| Role | Purpose | Examples |
|---|---|---|
| Primary | Brand identity, main actions, key focus | Appbar, main CTA, active nav |
| Secondary | Supporting actions, alternative emphasis | Secondary CTA, toggles |
| Tertiary | Special highlights, decorative accents | Feature badges, accent cards |
| 角色 | 用途 | 示例 |
|---|---|---|
| 主色调 | 品牌标识、核心操作、关键焦点 | 应用栏、主CTA、激活导航项 |
| 次要色调 | 辅助操作、备选强调 | 次要CTA、切换按钮 |
| 第三色调 | 特殊高亮、装饰性强调 | 功能徽章、强调卡片 |
Rule 6: One Primary Action Per View
规则6:每个视图仅一个主操作
One button per visible section. Supporting actions use , , or .
variant="primary"secondaryghostoutline每个可见区域仅保留一个按钮。辅助操作使用、或。
variant="primary"secondaryghostoutlineRule 7: Icons Inherit Color
规则7:图标继承颜色
dm_mdidm_bsicurrentcolorcolor=dm_mdidm_bsicurrentcolorcolor=Rule 8: Container Colors for Soft Emphasis
规则8:容器色用于柔和强调
Use / for tinted backgrounds with lower contrast. Good for featured sections, highlight cards, selected states.
primary-containeron-primary-containerheex
<div class="bg-primary-container text-on-primary-container p-4 rounded-lg">
Featured content with softer emphasis
</div>使用 / 实现低对比度的 tinted 背景,适用于特色区块、高亮卡片、选中状态。
primary-containeron-primary-containerheex
<div class="bg-primary-container text-on-primary-container p-4 rounded-lg">
带有柔和强调的特色内容
</div>Typography
排版
Font Strategy
字体策略
DuskMoon does not prescribe a typeface — projects choose their own. Rules:
- Pick a distinctive display font for headings — avoid Inter, Roboto, Arial, system-ui. Load from Google Fonts or self-host.
- Pair with a clean body font that complements the display choice.
- Use a monospace font for code blocks — JetBrains Mono, Fira Code, or similar.
- Define fonts as CSS variables, not inline.
css
/* Project CSS — after DuskMoon imports */
:root {
--font-display: 'Instrument Serif', serif;
--font-body: 'DM Sans', sans-serif;
--font-mono: 'JetBrains Mono', monospace;
}
body { font-family: var(--font-body); }
h1, h2, h3 { font-family: var(--font-display); }
code, pre { font-family: var(--font-mono); }DuskMoon不指定字体——项目可自行选择。规则:
- 为标题选择独特的显示字体——避免Inter、Roboto、Arial、system-ui。从Google Fonts加载或自行托管。
- 搭配简洁的正文字体,与显示字体互补。
- 为代码块使用等宽字体——JetBrains Mono、Fira Code或类似字体。
- 将字体定义为CSS变量,而非内联设置。
css
/* 项目CSS —— 在DuskMoon导入之后 */
:root {
--font-display: 'Instrument Serif', serif;
--font-body: 'DM Sans', sans-serif;
--font-mono: 'JetBrains Mono', monospace;
}
body { font-family: var(--font-body); }
h1, h2, h3 { font-family: var(--font-display); }
code, pre { font-family: var(--font-mono); }Type Scale
字体层级
| Element | Class | Usage |
|---|---|---|
| Page title | | One per page |
| Section heading | | |
| Card title | | |
| Body text | | Default |
| Secondary text | | Muted supporting info |
| Caption | | Timestamps, metadata |
| 元素 | 类名 | 用途 |
|---|---|---|
| 页面标题 | | 每页一个 |
| 区块标题 | | |
| 卡片标题 | | |
| 正文文本 | | 默认 |
| 次要文本 | | 弱化的辅助信息 |
| 说明文字 | | 时间戳、元数据 |
Text Color Hierarchy
文本颜色层级
| Priority | Token | Usage |
|---|---|---|
| Primary text | | Headings, body text, labels |
| Secondary text | | Descriptions, hints, timestamps |
| Disabled text | | Disabled states |
| Link text | | Clickable inline text |
| 优先级 | 令牌 | 用途 |
|---|---|---|
| 主文本 | | 标题、正文、标签 |
| 次要文本 | | 描述、提示、时间戳 |
| 禁用文本 | | 禁用状态 |
| 链接文本 | | 可点击的行内文本 |
Layout Composition
布局构成
Spatial Principles
空间原则
- Content pages: Generous whitespace — or
p-6on main,p-8between cardsgap-6 - Data views: Dense spacing — on main,
p-4between itemsgap-3 - Consistent gaps: Pick one scale per view (or
gap-4, not mixed)gap-6 - Max width: Content areas should constrain width — for wide,
max-w-7xl mx-autofor text-heavymax-w-3xl
- 内容页:宽松留白——主容器使用或
p-6,卡片间使用p-8gap-6 - 数据视图:密集排版——主容器使用,元素间使用
p-4gap-3 - 统一间距:每个视图选择一种间距尺度(或
gap-4,不要混合使用)gap-6 - 最大宽度:内容区域应限制宽度——宽屏内容用,文本密集内容用
max-w-7xl mx-automax-w-3xl
Card Grid
卡片网格
heex
<div class="grid grid-cols-auto-fit-80 gap-6">
<.dm_card :for={item <- @items}>
<:title><%= item.name %></:title>
<%= item.description %>
</.dm_card>
</div>heex
<div class="grid grid-cols-auto-fit-80 gap-6">
<.dm_card :for={item <- @items}>
<:title><%= item.name %></:title>
<%= item.description %>
</.dm_card>
</div>Sidebar + Content
侧边栏+内容布局
heex
<div class="flex min-h-screen">
<aside class="bg-secondary text-secondary-content w-64 border-r border-outline-variant p-4 shrink-0">
<.dm_left_menu active={@current_path} />
</aside>
<main class="flex-1 bg-surface p-6 overflow-auto">
<%= @inner_content %>
</main>
</div>heex
<div class="flex min-h-screen">
<aside class="bg-secondary text-secondary-content w-64 border-r border-outline-variant p-4 shrink-0">
<.dm_left_menu active={@current_path} />
</aside>
<main class="flex-1 bg-surface p-6 overflow-auto">
<%= @inner_content %>
</main>
</div>Stacked Sections with Depth
带深度的堆叠区块
heex
<section class="bg-surface-container-low p-8 rounded-2xl">
<h2 class="text-2xl font-semibold mb-6">Featured</h2>
<div class="grid grid-cols-3 gap-4">
<.dm_card shadow="md">...</.dm_card>
<.dm_card shadow="md">...</.dm_card>
<.dm_card shadow="md">...</.dm_card>
</div>
</section>heex
<section class="bg-surface-container-low p-8 rounded-2xl">
<h2 class="text-2xl font-semibold mb-6">Featured</h2>
<div class="grid grid-cols-3 gap-4">
<.dm_card shadow="md">...</.dm_card>
<.dm_card shadow="md">...</.dm_card>
<.dm_card shadow="md">...</.dm_card>
</div>
</section>Backgrounds & Depth
背景与深度
Surface Layering
表面分层
Don't use flat pages. Build depth with surface tokens:
heex
<body class="bg-surface text-on-surface">
<header class="bg-primary text-primary-content">...</header>
<div class="bg-surface-container-low -mt-8 pt-12 pb-8 rounded-t-3xl">
<div class="max-w-6xl mx-auto px-6">
<.dm_card shadow="lg" class="bg-surface-container">
...
</.dm_card>
</div>
</div>
</body>不要使用扁平化页面。使用表面令牌构建深度:
heex
<body class="bg-surface text-on-surface">
<header class="bg-primary text-primary-content">...</header>
<div class="bg-surface-container-low -mt-8 pt-12 pb-8 rounded-t-3xl">
<div class="max-w-6xl mx-auto px-6">
<.dm_card shadow="lg" class="bg-surface-container">
...
</.dm_card>
</div>
</div>
</body>Hero Sections
Hero区块
Use container color gradients for hero areas:
css
.hero {
background: linear-gradient(
135deg,
var(--color-primary-container) 0%,
var(--color-tertiary-container) 100%
);
}为Hero区域使用容器色渐变:
css
.hero {
background: linear-gradient(
135deg,
var(--color-primary-container) 0%,
var(--color-tertiary-container) 100%
);
}Scrim & Overlays
遮罩与覆盖层
css
.overlay {
background-color: hsl(var(--color-scrim) / 0.5);
backdrop-filter: blur(4px);
}css
.overlay {
background-color: hsl(var(--color-scrim) / 0.5);
backdrop-filter: blur(4px);
}Borders & Dividers
边框与分隔线
- → subtle dividers, decorative borders
outline-variant - → interactive borders (inputs, focused states)
outline
heex
<hr class="border-outline-variant" />
<div class="border border-outline rounded-lg">Interactive element</div>- → 微妙分隔线、装饰性边框
outline-variant - → 交互式边框(输入框、聚焦状态)
outline
heex
<hr class="border-outline-variant" />
<div class="border border-outline rounded-lg">交互式元素</div>Motion & Transitions
动效与过渡
Theme Transition
主题过渡
css
* {
transition: background-color 0.2s ease, color 0.2s ease, border-color 0.2s ease;
}css
* {
transition: background-color 0.2s ease, color 0.2s ease, border-color 0.2s ease;
}Card Hover
卡片悬停效果
css
.interactive-card {
transition: transform 0.15s ease, box-shadow 0.15s ease;
}
.interactive-card:hover {
transform: translateY(-2px);
box-shadow: var(--shadow-md);
}css
.interactive-card {
transition: transform 0.15s ease, box-shadow 0.15s ease;
}
.interactive-card:hover {
transform: translateY(-2px);
box-shadow: var(--shadow-md);
}Reduced Motion
减少动效
Always respect user preference:
css
@media (prefers-reduced-motion: reduce) {
* { transition: none !important; animation: none !important; }
}始终尊重用户偏好:
css
@media (prefers-reduced-motion: reduce) {
* { transition: none !important; animation: none !important; }
}Motion Principles
动效原则
- One transition property per interaction — don't animate everything
- Page-level animations on route change (LiveView transitions)
- Subtle hover states on cards and buttons — max
translateY(-2px) - Loading states use or skeleton components — no custom spinners
dm_loading_spinner
- 每次交互仅设置一个过渡属性——不要动画所有元素
- 路由切换时添加页面级动画(LiveView过渡)
- 卡片和按钮添加微妙悬停状态——最多
translateY(-2px) - 加载状态使用或骨架组件——不要自定义spinner
dm_loading_spinner
Anti-Patterns
反模式
- Tailwind color scale — No ,
bg-blue-500. Breaks theme switching.text-gray-600 - Hardcoded colors — No hex, rgb, hsl, or named colors.
- Opacity faking surfaces — No . Use
bg-white/80tokens.surface-container-* - Inline color styles — No .
style="color: ..." - Raw HTML over components — Use components when available.
dm_* - Uniform primary everywhere — One primary action per view. Supporting actions recede.
- Semantic colors as decoration — /
success/error/warningare for states only.info - Generic fonts — No Inter, Roboto, Arial as conscious choices. Pick distinctive typefaces.
- Missing text pairing — Every needs its
bg-*ortext-*-content.text-on-* - Flat layouts — Use surface elevation for depth. Pages should never feel like a single flat plane.
- Timid color usage — A dominant primary with sharp accents outperforms evenly-distributed, wishy-washy palettes. Commit to the hierarchy.
- Cookie-cutter pages — Each view type (dashboard, form, content, marketing) should have a distinct spatial composition. Don't copy-paste the same layout everywhere.
- 使用Tailwind颜色刻度——禁止、
bg-blue-500,会破坏主题切换功能。text-gray-600 - 硬编码颜色——禁止使用十六进制、rgb、hsl或命名颜色。
- 用透明度模拟表面——禁止,使用
bg-white/80令牌。surface-container-* - 内联颜色样式——禁止。
style="color: ..." - 原生HTML替代组件——可用组件时优先使用。
dm_* - 全局使用主色调——每个视图仅一个主操作,辅助操作需弱化。
- 语义色用于装饰——/
success/error/warning仅用于状态。info - 通用字体——不要刻意选择Inter、Roboto、Arial,需挑选独特字体。
- 缺失文本配对——每个需搭配对应的
bg-*或text-*-content。text-on-* - 扁平化布局——使用表面层级打造深度,页面不应是单一平面。
- 保守的颜色使用——主色调主导搭配鲜明强调色,优于均匀分布的模糊调色板,需明确层级。
- 千篇一律的页面——每种视图类型(仪表盘、表单、内容、营销)应有独特的空间布局,不要到处复制粘贴相同布局。