ui-web by alinaqi/claude-bootstrap
npx skills add https://github.com/alinaqi/claude-bootstrap --skill ui-web加载方式:base.md + react-web.md
这些规则是不可协商的。每个 UI 元素都必须通过这些检查。
文本对比度要求:
├── 普通文本(<18px):最低 4.5:1
├── 大文本(≥18px 粗体或 ≥24px):最低 3:1
├── UI 组件(按钮、输入框):最低 3:1
└── 焦点指示器:最低 3:1
禁止的颜色组合:
✗ gray-400 在白色上(#9CA3AF 在 #FFFFFF 上 = 2.6:1)- 失败
✗ gray-500 在白色上(#6B7280 在 #FFFFFF 上 = 4.6:1)- 勉强通过
✗ 白色在黄色上 - 失败
✗ 浅蓝色在白色上 - 通常失败
安全的颜色组合:
✓ gray-700 在白色上(#374151 在 #FFFFFF 上 = 9.2:1)
✓ gray-600 在白色上(#4B5563 在 #FFFFFF 上 = 6.4:1)
✓ gray-900 在白色上(#111827 在 #FFFFFF 上 = 16:1)
✓ 白色在 gray-900、blue-600、green-700 上
所有按钮必须具有:
✓ 可见的背景颜色 或 可见的边框(至少 1px)
✓ 与背景形成对比的文本颜色
✓ 最小高度:44px(触摸目标)
✓ 内边距:至少 px-4 py-2
切勿创建:
✗ 背景透明且无边框的按钮
✗ 文本颜色与背景颜色相同的按钮
✗ 没有可见边框的幽灵按钮
✗ 浅色背景上的白色文本
✗ 深色背景上的深色文本
// 每个按钮都需要可见的边界
// 主要按钮:实心背景
<button className="bg-gray-900 text-white px-4 py-3 rounded-lg">
Primary
</button>
// 次要按钮:可见背景
<button className="bg-gray-100 text-gray-900 px-4 py-3 rounded-lg">
Secondary
</button>
// 幽灵按钮:必须有可见边框
<button className="border border-gray-300 text-gray-700 px-4 py-3 rounded-lg">
Ghost
</button>
// 切勿这样做:
<button className="text-gray-500">Invisible Button</button> // ✗ 无边界
<button className="bg-white text-white">Hidden</button> // ✗ 无对比度
广告位招租
在这里展示您的产品或服务
触达数万 AI 开发者,精准高效
// 每个交互元素都需要可见的焦点状态
className="focus:outline-none focus-visible:ring-2 focus-visible:ring-blue-500 focus-visible:ring-offset-2"
// 切勿在没有替代方案的情况下移除焦点样式
className="outline-none" // ✗ 禁止在没有圆环替代方案的情况下使用
实施深色模式时:
├── 深色背景上的文本必须是浅色的(gray-100 到 white)
├── 边框必须可见(gray-700 或更浅)
├── 切勿在 gray-900 背景上使用 gray-400 文本(对比度失败)
└── 发布前测试两种模式
安全的深色模式文本:
✓ text-white 在 bg-gray-900 上
✓ text-gray-100 在 bg-gray-800 上
✓ text-gray-200 在 bg-gray-900 上
不安全的(对比度失败):
✗ text-gray-500 在 bg-gray-900 上(2.4:1)
✗ text-gray-400 在 bg-gray-800 上(3.1:1)
美观的 UI 不是装饰——它是沟通。 每个视觉选择都应服务于清晰度、层次结构和用户信心。默认选择优雅和克制。
主要操作 → 粗体、高对比度、突出
次要操作 → 微妙、低对比度
三级操作/链接 → 极简、文本样式
// Tailwind 间距比例 - 一致使用
const spacing = {
xs: 'p-1', // 4px - 紧凑内部
sm: 'p-2', // 8px - 紧凑
md: 'p-4', // 16px - 默认
lg: 'p-6', // 24px - 舒适
xl: 'p-8', // 32px - 宽敞
'2xl': 'p-12', // 48px - 区块间隙
};
// 规则:更多留白 = 更高级的感觉
// 规则:一致的间距 > 完美的间距
// 每页限制在 3-4 种字体大小
const typography = {
hero: 'text-4xl md:text-5xl font-bold tracking-tight',
heading: 'text-2xl md:text-3xl font-semibold',
subheading: 'text-lg md:text-xl font-medium',
body: 'text-base leading-relaxed',
caption: 'text-sm text-gray-500',
};
// 规则:切勿使用超过 2 种字体系列
// 规则:正文文本的行高为 1.5-1.7
// 现代玻璃效果 - 谨慎使用以突出重点
const GlassCard = ({ children, className = '' }) => (
<div className={`
backdrop-blur-xl
bg-white/10
border border-white/20
rounded-2xl
shadow-xl
shadow-black/5
${className}
`}>
{children}
</div>
);
// 浅色模式玻璃态
const lightGlass = `
backdrop-blur-xl
bg-white/70
border border-white/50
shadow-lg shadow-gray-200/50
`;
// 深色模式玻璃态
const darkGlass = `
backdrop-blur-xl
bg-gray-900/70
border border-white/10
shadow-xl shadow-black/20
`;
// 磨砂侧边栏
const frostedSidebar = `
backdrop-blur-2xl
bg-gradient-to-b from-white/80 to-white/60
border-r border-white/30
`;
// 浮动操作玻璃态
const floatingGlass = `
backdrop-blur-md
bg-white/90
rounded-full
shadow-lg shadow-black/10
border border-white/50
`;
✓ 带有图像背景的英雄区域
✓ 渐变背景上的浮动卡片
✓ 模态叠加层
✓ 导航栏(微妙的)
✓ 功能亮点
✗ 每张卡片(过度使用会破坏效果)
✗ 文本密集的内容区域
✗ 表单(降低对比度)
✗ 数据表格
const colors = {
// 操作
primary: 'bg-blue-600 hover:bg-blue-700',
secondary: 'bg-gray-100 hover:bg-gray-200 text-gray-900',
danger: 'bg-red-600 hover:bg-red-700',
success: 'bg-green-600 hover:bg-green-700',
// 表面
background: 'bg-gray-50 dark:bg-gray-950',
surface: 'bg-white dark:bg-gray-900',
elevated: 'bg-white dark:bg-gray-800 shadow-lg',
// 文本
textPrimary: 'text-gray-900 dark:text-white',
textSecondary: 'text-gray-600 dark:text-gray-400',
textMuted: 'text-gray-400 dark:text-gray-500',
};
// 微妙的网格渐变(现代、高级)
const meshGradient = `
bg-gradient-to-br
from-blue-50 via-white to-purple-50
dark:from-gray-950 dark:via-gray-900 dark:to-gray-950
`;
// 鲜艳的英雄区域渐变
const heroGradient = `
bg-gradient-to-r
from-blue-600 via-purple-600 to-pink-600
`;
// 微妙的径向发光
const radialGlow = `
bg-[radial-gradient(ellipse_at_top,_var(--tw-gradient-stops))]
from-blue-200/40 via-transparent to-transparent
`;
// 主要按钮 - 粗体、自信
const PrimaryButton = ({ children, ...props }) => (
<button
className="
px-6 py-3
bg-gray-900 dark:bg-white
text-white dark:text-gray-900
font-medium
rounded-xl
transition-all duration-200
hover:bg-gray-800 dark:hover:bg-gray-100
hover:shadow-lg hover:shadow-gray-900/20
active:scale-[0.98]
disabled:opacity-50 disabled:cursor-not-allowed
"
{...props}
>
{children}
</button>
);
// 次要按钮 - 微妙
const SecondaryButton = ({ children, ...props }) => (
<button
className="
px-6 py-3
bg-gray-100 dark:bg-gray-800
text-gray-900 dark:text-white
font-medium
rounded-xl
transition-all duration-200
hover:bg-gray-200 dark:hover:bg-gray-700
active:scale-[0.98]
"
{...props}
>
{children}
</button>
);
// 幽灵按钮 - 极简
const GhostButton = ({ children, ...props }) => (
<button
className="
px-4 py-2
text-gray-600 dark:text-gray-400
font-medium
rounded-lg
transition-colors duration-200
hover:text-gray-900 dark:hover:text-white
hover:bg-gray-100 dark:hover:bg-gray-800
"
{...props}
>
{children}
</button>
);
// 带有微妙提升效果的简洁卡片
const Card = ({ children, className = '' }) => (
<div className={`
bg-white dark:bg-gray-900
rounded-2xl
border border-gray-200 dark:border-gray-800
shadow-sm
hover:shadow-md
transition-shadow duration-300
${className}
`}>
{children}
</div>
);
// 交互式卡片
const InteractiveCard = ({ children, onClick }) => (
<button
onClick={onClick}
className="
w-full text-left
bg-white dark:bg-gray-900
rounded-2xl
border border-gray-200 dark:border-gray-800
p-6
transition-all duration-300
hover:border-gray-300 dark:hover:border-gray-700
hover:shadow-lg
hover:-translate-y-1
active:scale-[0.99]
"
>
{children}
</button>
);
const Input = ({ label, error, ...props }) => (
<div className="space-y-2">
{label && (
<label className="block text-sm font-medium text-gray-700 dark:text-gray-300">
{label}
</label>
)}
<input
className={`
w-full px-4 py-3
bg-gray-50 dark:bg-gray-800
border-2 rounded-xl
text-gray-900 dark:text-white
placeholder-gray-400 dark:placeholder-gray-500
transition-all duration-200
focus:outline-none focus:ring-0
${error
? 'border-red-500 focus:border-red-500'
: 'border-transparent focus:border-blue-500 focus:bg-white dark:focus:bg-gray-900'
}
`}
{...props}
/>
{error && (
<p className="text-sm text-red-500">{error}</p>
)}
</div>
);
// 标准过渡效果 - 始终使用
const transitions = {
fast: 'transition-all duration-150', // 悬停状态
normal: 'transition-all duration-200', // 大多数交互
slow: 'transition-all duration-300', // 卡片悬停、模态框
spring: 'transition-all duration-500 ease-out', // 页面过渡
};
// 规则:所有交互元素都应该有过渡效果
// 规则:150-300ms 感觉响应迅速,>500ms 感觉缓慢
// 悬停时缩放(按钮、卡片)
className="hover:scale-105 active:scale-95 transition-transform"
// 悬停时提升(卡片)
className="hover:-translate-y-1 hover:shadow-xl transition-all"
// 悬停时发光(行动号召)
className="hover:shadow-lg hover:shadow-blue-500/25 transition-shadow"
// 边框高亮(输入框、卡片)
className="hover:border-gray-300 transition-colors"
// 骨架屏加载器
const Skeleton = ({ className = '' }) => (
<div className={`
animate-pulse
bg-gray-200 dark:bg-gray-800
rounded-lg
${className}
`} />
);
// 旋转器
const Spinner = ({ size = 'md' }) => (
<div className={`
animate-spin rounded-full
border-2 border-gray-200 dark:border-gray-700
border-t-blue-600
${size === 'sm' ? 'w-4 h-4' : size === 'lg' ? 'w-8 h-8' : 'w-6 h-6'}
`} />
);
// 按钮加载状态
<button disabled className="relative">
<span className="opacity-0">Submit</span>
<Spinner className="absolute inset-0 m-auto" />
</button>
// 一致的最大宽度和内边距
const Container = ({ children, className = '' }) => (
<div className={`
max-w-7xl mx-auto
px-4 sm:px-6 lg:px-8
${className}
`}>
{children}
</div>
);
// 一致的垂直节奏
const Section = ({ children }) => (
<section className="py-16 md:py-24">
<Container>{children}</Container>
</section>
);
// 功能网格
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
{features.map(f => <FeatureCard key={f.id} {...f} />)}
</div>
// 便当网格(现代非对称)
<div className="grid grid-cols-2 md:grid-cols-4 gap-4">
<div className="col-span-2 row-span-2">Large</div>
<div className="col-span-1">Small</div>
<div className="col-span-1">Small</div>
<div className="col-span-2">Medium</div>
</div>
// 始终为两种模式设计
// 使用 CSS 变量或 Tailwind 的 dark: 前缀
// 主题切换
const ThemeToggle = () => {
const [dark, setDark] = useState(false);
useEffect(() => {
document.documentElement.classList.toggle('dark', dark);
}, [dark]);
return (
<button onClick={() => setDark(!dark)}>
{dark ? <SunIcon /> : <MoonIcon />}
</button>
);
};
浅色模式 深色模式
─────────────────────────────────
white gray-950
gray-50 gray-900
gray-100 gray-800
gray-200 gray-700
gray-900 (文本) white (文本)
gray-600 (次要) gray-400
blue-600 blue-500
WCAG AA:普通文本 4.5:1,大文本 3:1
WCAG AAA:普通文本 7:1,大文本 4.5:1
// 测试:使用浏览器开发者工具或对比度检查器
// 规则:切勿在白色背景上使用 gray-400 作为正文文本
// 始终可见的焦点环
className="
focus:outline-none
focus-visible:ring-2
focus-visible:ring-blue-500
focus-visible:ring-offset-2
"
// 切勿在没有替代方案的情况下移除焦点样式
// ✗ outline-none(单独使用)
// ✓ outline-none + focus-visible:ring
// 视觉上隐藏但可访问
const srOnly = "absolute w-px h-px p-0 -m-px overflow-hidden whitespace-nowrap border-0";
// 图标按钮需要标签
<button aria-label="关闭菜单">
<XIcon className="w-6 h-6" />
</button>
// 宣布动态内容
<div role="status" aria-live="polite">
{message}
</div>
✗ 一页上超过 3 种字体大小
✗ 随机的间距值(使用 8px 网格)
✗ 纯黑色(#000)在纯白色(#fff)上
✗ 未经对比度检查的彩色背景上的彩色文本
✗ UI 元素的动画时长超过 500ms
✗ 到处使用玻璃态拟物设计
✗ 所有元素都使用投影
✗ 文本上的渐变(难以阅读)
✗ 无法停止的自动播放动画
✗ 移除焦点指示器
✗ 对比度低于 4.5:1 的灰色文本
✗ 微小的点击目标(< 44px)
// ✗ 太多投影
className="shadow-sm shadow-md shadow-lg" // 选择一种
// ✗ 不一致的圆角
className="rounded-sm rounded-lg rounded-2xl" // 系统:sm, lg, xl, 2xl
// ✗ 竞争焦点
// 每个视口一个主要行动号召
// ✗ 过度装饰
// 如果它不服务于功能,就移除它
// 边框半径:12-16px(rounded-xl 到 rounded-2xl)
// 投影:微妙的(shadow-sm 到 shadow-md)
// 字体:Inter, SF Pro, system-ui
// 主要颜色:近黑色或品牌色
// 过渡效果:200ms ease-out
// 间距:8px 网格(Tailwind 默认)
□ 充足的留白
□ 微妙的投影(不刺眼)
□ 所有交互都有平滑的过渡效果
□ 一致的边框半径
□ 有限的调色板(最多 2-3 种颜色)
□ 排版层次结构(最多 3 种大小)
□ 高质量的图像
□ 悬停/焦点时的微交互
□ 支持深色模式
每周安装次数
124
仓库
GitHub 星标数
529
首次出现
2026年1月20日
安全审计
安装于
opencode102
gemini-cli98
codex96
claude-code87
cursor83
github-copilot83
Load with: base.md + react-web.md
These rules are NON-NEGOTIABLE. Every UI element must pass these checks.
Text Contrast Requirements:
├── Normal text (<18px): 4.5:1 minimum
├── Large text (≥18px bold or ≥24px): 3:1 minimum
├── UI components (buttons, inputs): 3:1 minimum
└── Focus indicators: 3:1 minimum
FORBIDDEN COLOR COMBINATIONS:
✗ gray-400 on white (#9CA3AF on #FFFFFF = 2.6:1) - FAILS
✗ gray-500 on white (#6B7280 on #FFFFFF = 4.6:1) - BARELY PASSES
✗ white on yellow - FAILS
✗ light blue on white - USUALLY FAILS
SAFE COLOR COMBINATIONS:
✓ gray-700 on white (#374151 on #FFFFFF = 9.2:1)
✓ gray-600 on white (#4B5563 on #FFFFFF = 6.4:1)
✓ gray-900 on white (#111827 on #FFFFFF = 16:1)
✓ white on gray-900, blue-600, green-700
ALL BUTTONS MUST HAVE:
✓ Visible background color OR visible border (min 1px)
✓ Text color that contrasts with background
✓ Minimum height: 44px (touch target)
✓ Padding: at least px-4 py-2
NEVER CREATE:
✗ Buttons with transparent background AND no border
✗ Text same color as background
✗ Ghost buttons without visible borders
✗ White text on light backgrounds
✗ Dark text on dark backgrounds
// EVERY button needs visible boundaries
// PRIMARY: solid background
<button className="bg-gray-900 text-white px-4 py-3 rounded-lg">
Primary
</button>
// SECONDARY: visible background
<button className="bg-gray-100 text-gray-900 px-4 py-3 rounded-lg">
Secondary
</button>
// GHOST: MUST have visible border
<button className="border border-gray-300 text-gray-700 px-4 py-3 rounded-lg">
Ghost
</button>
// NEVER DO THIS:
<button className="text-gray-500">Invisible Button</button> // ✗ NO BOUNDARY
<button className="bg-white text-white">Hidden</button> // ✗ NO CONTRAST
// EVERY interactive element needs visible focus
className="focus:outline-none focus-visible:ring-2 focus-visible:ring-blue-500 focus-visible:ring-offset-2"
// NEVER remove focus without replacement
className="outline-none" // ✗ FORBIDDEN without ring replacement
When implementing dark mode:
├── Text must be light (gray-100 to white) on dark backgrounds
├── Borders must be visible (gray-700 or lighter)
├── Never use gray-400 text on gray-900 bg (fails contrast)
└── Test BOTH modes before shipping
SAFE DARK MODE TEXT:
✓ text-white on bg-gray-900
✓ text-gray-100 on bg-gray-800
✓ text-gray-200 on bg-gray-900
UNSAFE (FAILS CONTRAST):
✗ text-gray-500 on bg-gray-900 (2.4:1)
✗ text-gray-400 on bg-gray-800 (3.1:1)
Beautiful UI is not decoration - it's communication. Every visual choice should serve clarity, hierarchy, and user confidence. Default to elegance and restraint.
Primary Action → Bold, high contrast, prominent
Secondary Action → Subtle, lower contrast
Tertiary/Links → Minimal, text-style
// Tailwind spacing scale - USE CONSISTENTLY
const spacing = {
xs: 'p-1', // 4px - tight internal
sm: 'p-2', // 8px - compact
md: 'p-4', // 16px - default
lg: 'p-6', // 24px - comfortable
xl: 'p-8', // 32px - spacious
'2xl': 'p-12', // 48px - section gaps
};
// Rule: More whitespace = more premium feel
// Rule: Consistent spacing > perfect spacing
// Limit to 3-4 font sizes per page
const typography = {
hero: 'text-4xl md:text-5xl font-bold tracking-tight',
heading: 'text-2xl md:text-3xl font-semibold',
subheading: 'text-lg md:text-xl font-medium',
body: 'text-base leading-relaxed',
caption: 'text-sm text-gray-500',
};
// Rule: Never use more than 2 font families
// Rule: Line height 1.5-1.7 for body text
// Modern glass effect - use sparingly for emphasis
const GlassCard = ({ children, className = '' }) => (
<div className={`
backdrop-blur-xl
bg-white/10
border border-white/20
rounded-2xl
shadow-xl
shadow-black/5
${className}
`}>
{children}
</div>
);
// Light mode glass
const lightGlass = `
backdrop-blur-xl
bg-white/70
border border-white/50
shadow-lg shadow-gray-200/50
`;
// Dark mode glass
const darkGlass = `
backdrop-blur-xl
bg-gray-900/70
border border-white/10
shadow-xl shadow-black/20
`;
// Frosted sidebar
const frostedSidebar = `
backdrop-blur-2xl
bg-gradient-to-b from-white/80 to-white/60
border-r border-white/30
`;
// Floating action glass
const floatingGlass = `
backdrop-blur-md
bg-white/90
rounded-full
shadow-lg shadow-black/10
border border-white/50
`;
✓ Hero sections with image backgrounds
✓ Floating cards over gradients
✓ Modal overlays
✓ Navigation bars (subtle)
✓ Feature highlights
✗ Every card (overuse kills the effect)
✗ Text-heavy content areas
✗ Forms (reduces contrast)
✗ Data tables
const colors = {
// Actions
primary: 'bg-blue-600 hover:bg-blue-700',
secondary: 'bg-gray-100 hover:bg-gray-200 text-gray-900',
danger: 'bg-red-600 hover:bg-red-700',
success: 'bg-green-600 hover:bg-green-700',
// Surfaces
background: 'bg-gray-50 dark:bg-gray-950',
surface: 'bg-white dark:bg-gray-900',
elevated: 'bg-white dark:bg-gray-800 shadow-lg',
// Text
textPrimary: 'text-gray-900 dark:text-white',
textSecondary: 'text-gray-600 dark:text-gray-400',
textMuted: 'text-gray-400 dark:text-gray-500',
};
// Subtle mesh gradient (modern, premium)
const meshGradient = `
bg-gradient-to-br
from-blue-50 via-white to-purple-50
dark:from-gray-950 dark:via-gray-900 dark:to-gray-950
`;
// Vibrant hero gradient
const heroGradient = `
bg-gradient-to-r
from-blue-600 via-purple-600 to-pink-600
`;
// Subtle radial glow
const radialGlow = `
bg-[radial-gradient(ellipse_at_top,_var(--tw-gradient-stops))]
from-blue-200/40 via-transparent to-transparent
`;
// Primary button - bold, confident
const PrimaryButton = ({ children, ...props }) => (
<button
className="
px-6 py-3
bg-gray-900 dark:bg-white
text-white dark:text-gray-900
font-medium
rounded-xl
transition-all duration-200
hover:bg-gray-800 dark:hover:bg-gray-100
hover:shadow-lg hover:shadow-gray-900/20
active:scale-[0.98]
disabled:opacity-50 disabled:cursor-not-allowed
"
{...props}
>
{children}
</button>
);
// Secondary button - subtle
const SecondaryButton = ({ children, ...props }) => (
<button
className="
px-6 py-3
bg-gray-100 dark:bg-gray-800
text-gray-900 dark:text-white
font-medium
rounded-xl
transition-all duration-200
hover:bg-gray-200 dark:hover:bg-gray-700
active:scale-[0.98]
"
{...props}
>
{children}
</button>
);
// Ghost button - minimal
const GhostButton = ({ children, ...props }) => (
<button
className="
px-4 py-2
text-gray-600 dark:text-gray-400
font-medium
rounded-lg
transition-colors duration-200
hover:text-gray-900 dark:hover:text-white
hover:bg-gray-100 dark:hover:bg-gray-800
"
{...props}
>
{children}
</button>
);
// Clean card with subtle elevation
const Card = ({ children, className = '' }) => (
<div className={`
bg-white dark:bg-gray-900
rounded-2xl
border border-gray-200 dark:border-gray-800
shadow-sm
hover:shadow-md
transition-shadow duration-300
${className}
`}>
{children}
</div>
);
// Interactive card
const InteractiveCard = ({ children, onClick }) => (
<button
onClick={onClick}
className="
w-full text-left
bg-white dark:bg-gray-900
rounded-2xl
border border-gray-200 dark:border-gray-800
p-6
transition-all duration-300
hover:border-gray-300 dark:hover:border-gray-700
hover:shadow-lg
hover:-translate-y-1
active:scale-[0.99]
"
>
{children}
</button>
);
const Input = ({ label, error, ...props }) => (
<div className="space-y-2">
{label && (
<label className="block text-sm font-medium text-gray-700 dark:text-gray-300">
{label}
</label>
)}
<input
className={`
w-full px-4 py-3
bg-gray-50 dark:bg-gray-800
border-2 rounded-xl
text-gray-900 dark:text-white
placeholder-gray-400 dark:placeholder-gray-500
transition-all duration-200
focus:outline-none focus:ring-0
${error
? 'border-red-500 focus:border-red-500'
: 'border-transparent focus:border-blue-500 focus:bg-white dark:focus:bg-gray-900'
}
`}
{...props}
/>
{error && (
<p className="text-sm text-red-500">{error}</p>
)}
</div>
);
// Standard transitions - ALWAYS use
const transitions = {
fast: 'transition-all duration-150', // Hover states
normal: 'transition-all duration-200', // Most interactions
slow: 'transition-all duration-300', // Card hovers, modals
spring: 'transition-all duration-500 ease-out', // Page transitions
};
// Rule: Everything interactive should transition
// Rule: 150-300ms feels responsive, >500ms feels slow
// Scale on hover (buttons, cards)
className="hover:scale-105 active:scale-95 transition-transform"
// Lift on hover (cards)
className="hover:-translate-y-1 hover:shadow-xl transition-all"
// Glow on hover (CTAs)
className="hover:shadow-lg hover:shadow-blue-500/25 transition-shadow"
// Border highlight (inputs, cards)
className="hover:border-gray-300 transition-colors"
// Skeleton loader
const Skeleton = ({ className = '' }) => (
<div className={`
animate-pulse
bg-gray-200 dark:bg-gray-800
rounded-lg
${className}
`} />
);
// Spinner
const Spinner = ({ size = 'md' }) => (
<div className={`
animate-spin rounded-full
border-2 border-gray-200 dark:border-gray-700
border-t-blue-600
${size === 'sm' ? 'w-4 h-4' : size === 'lg' ? 'w-8 h-8' : 'w-6 h-6'}
`} />
);
// Button loading state
<button disabled className="relative">
<span className="opacity-0">Submit</span>
<Spinner className="absolute inset-0 m-auto" />
</button>
// Consistent max-width and padding
const Container = ({ children, className = '' }) => (
<div className={`
max-w-7xl mx-auto
px-4 sm:px-6 lg:px-8
${className}
`}>
{children}
</div>
);
// Consistent vertical rhythm
const Section = ({ children }) => (
<section className="py-16 md:py-24">
<Container>{children}</Container>
</section>
);
// Feature grid
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
{features.map(f => <FeatureCard key={f.id} {...f} />)}
</div>
// Bento grid (modern asymmetric)
<div className="grid grid-cols-2 md:grid-cols-4 gap-4">
<div className="col-span-2 row-span-2">Large</div>
<div className="col-span-1">Small</div>
<div className="col-span-1">Small</div>
<div className="col-span-2">Medium</div>
</div>
// Always design for both modes
// Use CSS variables or Tailwind dark: prefix
// Theme toggle
const ThemeToggle = () => {
const [dark, setDark] = useState(false);
useEffect(() => {
document.documentElement.classList.toggle('dark', dark);
}, [dark]);
return (
<button onClick={() => setDark(!dark)}>
{dark ? <SunIcon /> : <MoonIcon />}
</button>
);
};
Light Mode Dark Mode
─────────────────────────────────
white gray-950
gray-50 gray-900
gray-100 gray-800
gray-200 gray-700
gray-900 (text) white (text)
gray-600 (secondary) gray-400
blue-600 blue-500
WCAG AA: 4.5:1 for normal text, 3:1 for large text
WCAG AAA: 7:1 for normal text, 4.5:1 for large text
// Test: Use browser devtools or contrast checker
// Rule: Never use gray-400 on white for body text
// Always visible focus rings
className="
focus:outline-none
focus-visible:ring-2
focus-visible:ring-blue-500
focus-visible:ring-offset-2
"
// Never remove focus styles without replacement
// ✗ outline-none (alone)
// ✓ outline-none + focus-visible:ring
// Visually hidden but accessible
const srOnly = "absolute w-px h-px p-0 -m-px overflow-hidden whitespace-nowrap border-0";
// Icon buttons need labels
<button aria-label="Close menu">
<XIcon className="w-6 h-6" />
</button>
// Announce dynamic content
<div role="status" aria-live="polite">
{message}
</div>
✗ More than 3 font sizes on a page
✗ Random spacing values (use 8px grid)
✗ Pure black (#000) on pure white (#fff)
✗ Colored text on colored backgrounds without checking contrast
✗ Animations longer than 500ms for UI elements
✗ Glassmorphism everywhere
✗ Drop shadows on everything
✗ Gradients on text (hard to read)
✗ Auto-playing animations that can't be stopped
✗ Removing focus indicators
✗ Gray text below 4.5:1 contrast
✗ Tiny click targets (< 44px)
// ✗ Too many shadows
className="shadow-sm shadow-md shadow-lg" // Pick ONE
// ✗ Inconsistent rounding
className="rounded-sm rounded-lg rounded-2xl" // System: sm, lg, xl, 2xl
// ✗ Competing focal points
// One primary CTA per viewport
// ✗ Over-decorated
// If it doesn't serve function, remove it
// Border radius: 12-16px (rounded-xl to rounded-2xl)
// Shadow: subtle (shadow-sm to shadow-md)
// Font: Inter, SF Pro, system-ui
// Primary: Near-black or brand color
// Transitions: 200ms ease-out
// Spacing: 8px grid (Tailwind default)
□ Generous whitespace
□ Subtle shadows (not harsh)
□ Smooth transitions on all interactions
□ Consistent border radius
□ Limited color palette (2-3 colors max)
□ Typography hierarchy (3 sizes max)
□ High-quality imagery
□ Micro-interactions on hover/focus
□ Dark mode support
Weekly Installs
124
Repository
GitHub Stars
529
First Seen
Jan 20, 2026
Security Audits
Gen Agent Trust HubPassSocketPassSnykPass
Installed on
opencode102
gemini-cli98
codex96
claude-code87
cursor83
github-copilot83
agentation - AI智能体可视化UI反馈工具,连接人眼与代码的桥梁
5,400 周安装
Binance币本位合约API开发指南 - 衍生品交易接口与数据查询
990 周安装
coding-agent 编码代理使用指南:Bash优先的AI编程助手配置与优化
995 周安装
Binance算法交易API指南:TWAP、VP订单、期货与现货交易接口详解
1,000 周安装
Apple Reminders CLI (remindctl) - 终端管理苹果提醒事项,同步iPhone/iPad
1,000 周安装
代码库入门引导:AI辅助快速理解项目架构与代码规范
1,000 周安装
Claude Hookify 规则编写指南:创建自定义监控与安全规则 | YAML 配置教程
1,000 周安装