- SPEC.md: Complete UI/UX specification with design principles, layout architecture, interaction patterns, data flow, and accessibility requirements - VIEWS.md: Text-based wireframes for Dashboard, Document Viewer, Document Editor, and Library Browser views (desktop and mobile) - COMPONENTS.md: Reusable component library with buttons, inputs, cards, tags, navigation, modals, and feedback components - STYLES.md: Style guide with design tokens (colors, typography, spacing), global styles, animations, responsive breakpoints, and dark mode implementation Design follows dark mode first approach inspired by Mission Control dashboard, with full mobile responsiveness.
1030 lines
20 KiB
Markdown
1030 lines
20 KiB
Markdown
# SimpleNote Web - Style Guide
|
|
|
|
## 1. Design Tokens
|
|
|
|
Design tokens are CSS custom properties that define the visual language. They enable theming (dark/light modes) and ensure consistency.
|
|
|
|
### 1.1 Color Palette
|
|
|
|
```css
|
|
:root {
|
|
/* === Dark Theme (Default) === */
|
|
/* Backgrounds */
|
|
--color-bg: #0f1117;
|
|
--color-surface: #1a1d26;
|
|
--color-surface-raised: #22262f;
|
|
--color-hover: rgba(255, 255, 255, 0.05);
|
|
--color-active: rgba(255, 255, 255, 0.08);
|
|
|
|
/* Text */
|
|
--color-text: #e4e6eb;
|
|
--color-text-secondary: #b0b3b8;
|
|
--color-text-muted: #65676b;
|
|
|
|
/* Borders */
|
|
--color-border: #303338;
|
|
--color-border-light: #404249;
|
|
|
|
/* Accent (Primary brand color - cyan/teal) */
|
|
--color-accent: #00d4aa;
|
|
--color-accent-hover: #00e8bb;
|
|
--color-accent-alpha: rgba(0, 212, 170, 0.15);
|
|
|
|
/* Semantic Colors */
|
|
--color-success: #31a065;
|
|
--color-success-bg: rgba(49, 160, 101, 0.15);
|
|
--color-warning: #cf9d2c;
|
|
--color-warning-bg: rgba(207, 157, 44, 0.15);
|
|
--color-danger: #cf4a4a;
|
|
--color-danger-hover: #e05555;
|
|
--color-info: #4a90cf;
|
|
--color-info-bg: rgba(74, 144, 207, 0.15);
|
|
|
|
/* Type-specific colors */
|
|
--color-requirement: #00d4aa; /* Matches accent */
|
|
--color-note: #4a90cf;
|
|
--color-spec: #9b59b6;
|
|
--color-general: #65676b;
|
|
|
|
/* Priority */
|
|
--color-priority-high: #cf4a4a;
|
|
--color-priority-medium: #cf9d2c;
|
|
--color-priority-low: #31a065;
|
|
|
|
/* Shadows */
|
|
--shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.3);
|
|
--shadow-md: 0 4px 12px rgba(0, 0, 0, 0.25);
|
|
--shadow-lg: 0 8px 24px rgba(0, 0, 0, 0.3);
|
|
--shadow-xl: 0 20px 60px rgba(0, 0, 0, 0.4);
|
|
|
|
/* Focus ring */
|
|
--focus-ring: 0 0 0 3px rgba(0, 212, 170, 0.4);
|
|
}
|
|
|
|
/* === Light Theme === */
|
|
[data-theme="light"] {
|
|
--color-bg: #f5f6f8;
|
|
--color-surface: #ffffff;
|
|
--color-surface-raised: #f0f1f3;
|
|
--color-hover: rgba(0, 0, 0, 0.04);
|
|
--color-active: rgba(0, 0, 0, 0.06);
|
|
|
|
--color-text: #1a1d26;
|
|
--color-text-secondary: #4a4f5c;
|
|
--color-text-muted: #8b919d;
|
|
|
|
--color-border: #e1e3e8;
|
|
--color-border-light: #ebedf2;
|
|
|
|
--color-accent: #00a884;
|
|
--color-accent-hover: #00c49a;
|
|
--color-accent-alpha: rgba(0, 168, 132, 0.12);
|
|
|
|
--color-success: #22863a;
|
|
--color-success-bg: rgba(34, 134, 58, 0.1);
|
|
--color-warning: #b08800;
|
|
--color-warning-bg: rgba(176, 136, 0, 0.1);
|
|
--color-danger: #cb2431;
|
|
--color-danger-hover: #d93542;
|
|
--color-info: #0366d6;
|
|
--color-info-bg: rgba(3, 102, 214, 0.1);
|
|
|
|
--color-requirement: #00a884;
|
|
--color-note: #0366d6;
|
|
--color-spec: #6f42c1;
|
|
--color-general: #6a737d;
|
|
|
|
--shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.06);
|
|
--shadow-md: 0 4px 12px rgba(0, 0, 0, 0.08);
|
|
--shadow-lg: 0 8px 24px rgba(0, 0, 0, 0.1);
|
|
--shadow-xl: 0 20px 60px rgba(0, 0, 0, 0.15);
|
|
|
|
--focus-ring: 0 0 0 3px rgba(0, 168, 132, 0.35);
|
|
}
|
|
```
|
|
|
|
### 1.2 Typography
|
|
|
|
```css
|
|
:root {
|
|
/* Font Families */
|
|
--font-sans: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
--font-mono: 'JetBrains Mono', 'Fira Code', 'Monaco', 'Consolas', monospace;
|
|
|
|
/* Font Sizes (1.25 scale) */
|
|
--text-xs: 0.64rem; /* 10.24px */
|
|
--text-sm: 0.8rem; /* 12.8px */
|
|
--text-base: 1rem; /* 16px */
|
|
--text-lg: 1.25rem; /* 20px */
|
|
--text-xl: 1.563rem; /* 25px */
|
|
--text-2xl: 1.953rem; /* 31.25px */
|
|
--text-3xl: 2.441rem; /* 39px */
|
|
|
|
/* Line Heights */
|
|
--leading-tight: 1.25;
|
|
--leading-normal: 1.5;
|
|
--leading-relaxed: 1.75;
|
|
|
|
/* Font Weights */
|
|
--font-normal: 400;
|
|
--font-medium: 500;
|
|
--font-semibold: 600;
|
|
--font-bold: 700;
|
|
|
|
/* Letter Spacing */
|
|
--tracking-tight: -0.025em;
|
|
--tracking-normal: 0;
|
|
--tracking-wide: 0.025em;
|
|
--tracking-wider: 0.05em;
|
|
}
|
|
|
|
/* Google Fonts Import */
|
|
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap');
|
|
```
|
|
|
|
#### Typography Scale
|
|
|
|
| Element | Size | Weight | Line Height |
|
|
|---------|------|--------|-------------|
|
|
| H1 | 2rem (32px) | 700 | 1.2 |
|
|
| H2 | 1.5rem (24px) | 600 | 1.25 |
|
|
| H3 | 1.25rem (20px) | 600 | 1.3 |
|
|
| H4 | 1rem (16px) | 600 | 1.4 |
|
|
| Body | 1rem (16px) | 400 | 1.5 |
|
|
| Small | 0.875rem (14px) | 400 | 1.5 |
|
|
| Caption | 0.75rem (12px) | 400 | 1.4 |
|
|
| Code | 0.9375rem (15px) | 400 | 1.6 |
|
|
|
|
### 1.3 Spacing
|
|
|
|
```css
|
|
:root {
|
|
/* Spacing scale (4px base) */
|
|
--space-0: 0;
|
|
--space-1: 0.25rem; /* 4px */
|
|
--space-2: 0.5rem; /* 8px */
|
|
--space-3: 0.75rem; /* 12px */
|
|
--space-4: 1rem; /* 16px */
|
|
--space-5: 1.25rem; /* 20px */
|
|
--space-6: 1.5rem; /* 24px */
|
|
--space-8: 2rem; /* 32px */
|
|
--space-10: 2.5rem; /* 40px */
|
|
--space-12: 3rem; /* 48px */
|
|
--space-16: 4rem; /* 64px */
|
|
--space-20: 5rem; /* 80px */
|
|
|
|
/* Border Radius */
|
|
--radius-sm: 4px;
|
|
--radius-md: 6px;
|
|
--radius-lg: 8px;
|
|
--radius-xl: 12px;
|
|
--radius-2xl: 16px;
|
|
--radius-full: 9999px;
|
|
|
|
/* Transitions */
|
|
--transition-fast: 0.1s ease;
|
|
--transition-normal: 0.15s ease;
|
|
--transition-slow: 0.25s ease;
|
|
--transition-spring: 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);
|
|
}
|
|
```
|
|
|
|
### 1.4 Z-Index Scale
|
|
|
|
```css
|
|
:root {
|
|
--z-base: 0;
|
|
--z-dropdown: 100;
|
|
--z-sticky: 200;
|
|
--z-modal-backdrop: 500;
|
|
--z-modal: 600;
|
|
--z-toast: 700;
|
|
--z-tooltip: 800;
|
|
--z-max: 9999;
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## 2. Global Styles
|
|
|
|
### 2.1 CSS Reset
|
|
|
|
```css
|
|
*, *::before, *::after {
|
|
box-sizing: border-box;
|
|
margin: 0;
|
|
padding: 0;
|
|
}
|
|
|
|
html {
|
|
font-size: 16px;
|
|
-webkit-font-smoothing: antialiased;
|
|
-moz-osx-font-smoothing: grayscale;
|
|
text-rendering: optimizeLegibility;
|
|
}
|
|
|
|
body {
|
|
font-family: var(--font-sans);
|
|
font-size: var(--text-base);
|
|
line-height: var(--leading-normal);
|
|
color: var(--color-text);
|
|
background: var(--color-bg);
|
|
min-height: 100vh;
|
|
}
|
|
|
|
img, svg {
|
|
display: block;
|
|
max-width: 100%;
|
|
}
|
|
|
|
button {
|
|
font: inherit;
|
|
cursor: pointer;
|
|
}
|
|
|
|
input, textarea, select {
|
|
font: inherit;
|
|
}
|
|
|
|
a {
|
|
color: var(--color-accent);
|
|
text-decoration: none;
|
|
}
|
|
|
|
a:hover {
|
|
text-decoration: underline;
|
|
}
|
|
|
|
ul, ol {
|
|
list-style: none;
|
|
}
|
|
|
|
/* Scrollbar styling */
|
|
::-webkit-scrollbar {
|
|
width: 8px;
|
|
height: 8px;
|
|
}
|
|
|
|
::-webkit-scrollbar-track {
|
|
background: var(--color-surface);
|
|
}
|
|
|
|
::-webkit-scrollbar-thumb {
|
|
background: var(--color-border);
|
|
border-radius: var(--radius-full);
|
|
}
|
|
|
|
::-webkit-scrollbar-thumb:hover {
|
|
background: var(--color-text-muted);
|
|
}
|
|
|
|
/* Selection */
|
|
::selection {
|
|
background: var(--color-accent-alpha);
|
|
color: var(--color-text);
|
|
}
|
|
```
|
|
|
|
### 2.2 Focus Styles
|
|
|
|
```css
|
|
:focus {
|
|
outline: none;
|
|
}
|
|
|
|
:focus-visible {
|
|
outline: none;
|
|
box-shadow: var(--focus-ring);
|
|
border-radius: var(--radius-sm);
|
|
}
|
|
```
|
|
|
|
### 2.3 Smooth Scrolling
|
|
|
|
```css
|
|
html {
|
|
scroll-behavior: smooth;
|
|
}
|
|
|
|
@media (prefers-reduced-motion: reduce) {
|
|
html {
|
|
scroll-behavior: auto;
|
|
}
|
|
|
|
*, *::before, *::after {
|
|
animation-duration: 0.01ms !important;
|
|
animation-iteration-count: 1 !important;
|
|
transition-duration: 0.01ms !important;
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## 3. Typography Components
|
|
|
|
### 3.1 Headings
|
|
|
|
```css
|
|
h1, .h1 {
|
|
font-size: var(--text-2xl);
|
|
font-weight: var(--font-bold);
|
|
line-height: var(--leading-tight);
|
|
letter-spacing: var(--tracking-tight);
|
|
color: var(--color-text);
|
|
}
|
|
|
|
h2, .h2 {
|
|
font-size: var(--text-xl);
|
|
font-weight: var(--font-semibold);
|
|
line-height: 1.25;
|
|
letter-spacing: var(--tracking-tight);
|
|
}
|
|
|
|
h3, .h3 {
|
|
font-size: var(--text-lg);
|
|
font-weight: var(--font-semibold);
|
|
line-height: 1.3;
|
|
}
|
|
|
|
h4, .h4 {
|
|
font-size: var(--text-base);
|
|
font-weight: var(--font-semibold);
|
|
line-height: 1.4;
|
|
}
|
|
```
|
|
|
|
### 3.2 Body Text
|
|
|
|
```css
|
|
p {
|
|
margin-bottom: var(--space-4);
|
|
}
|
|
|
|
p:last-child {
|
|
margin-bottom: 0;
|
|
}
|
|
|
|
.text-sm {
|
|
font-size: var(--text-sm);
|
|
}
|
|
|
|
.text-xs {
|
|
font-size: var(--text-xs);
|
|
}
|
|
|
|
.text-muted {
|
|
color: var(--color-text-muted);
|
|
}
|
|
|
|
.text-secondary {
|
|
color: var(--color-text-secondary);
|
|
}
|
|
|
|
.font-mono {
|
|
font-family: var(--font-mono);
|
|
}
|
|
```
|
|
|
|
### 3.3 Prose (Markdown Content)
|
|
|
|
```css
|
|
.prose {
|
|
max-width: 70ch;
|
|
color: var(--color-text);
|
|
}
|
|
|
|
.prose h1 { /* ... */ }
|
|
.prose h2 { /* ... */ }
|
|
.prose h3 { /* ... */ }
|
|
.prose h4 { /* ... */ }
|
|
|
|
.prose p {
|
|
margin-bottom: 1em;
|
|
line-height: 1.7;
|
|
}
|
|
|
|
.prose ul,
|
|
.prose ol {
|
|
margin-bottom: 1em;
|
|
padding-left: 1.5em;
|
|
}
|
|
|
|
.prose ul { list-style-type: disc; }
|
|
.prose ol { list-style-type: decimal; }
|
|
|
|
.prose li {
|
|
margin-bottom: 0.25em;
|
|
line-height: 1.6;
|
|
}
|
|
|
|
.prose code {
|
|
font-family: var(--font-mono);
|
|
font-size: 0.875em;
|
|
background: var(--color-surface);
|
|
padding: 0.125em 0.375em;
|
|
border-radius: var(--radius-sm);
|
|
color: var(--color-accent);
|
|
}
|
|
|
|
.prose pre {
|
|
background: var(--color-surface);
|
|
border: 1px solid var(--color-border);
|
|
border-radius: var(--radius-lg);
|
|
padding: 1rem;
|
|
overflow-x: auto;
|
|
margin-bottom: 1em;
|
|
}
|
|
|
|
.prose pre code {
|
|
background: transparent;
|
|
padding: 0;
|
|
color: var(--color-text);
|
|
font-size: 0.875rem;
|
|
line-height: 1.6;
|
|
}
|
|
|
|
.prose blockquote {
|
|
border-left: 4px solid var(--color-accent);
|
|
padding-left: 1rem;
|
|
margin: 1em 0;
|
|
color: var(--color-text-secondary);
|
|
font-style: italic;
|
|
}
|
|
|
|
.prose table {
|
|
width: 100%;
|
|
border-collapse: collapse;
|
|
margin-bottom: 1em;
|
|
}
|
|
|
|
.prose th,
|
|
.prose td {
|
|
padding: 0.5rem 0.75rem;
|
|
border: 1px solid var(--color-border);
|
|
text-align: left;
|
|
}
|
|
|
|
.prose th {
|
|
background: var(--color-surface);
|
|
font-weight: var(--font-semibold);
|
|
}
|
|
|
|
.prose tr:hover td {
|
|
background: var(--color-hover);
|
|
}
|
|
|
|
/* Task list checkboxes */
|
|
.prose input[type="checkbox"] {
|
|
margin-right: 0.5em;
|
|
accent-color: var(--color-accent);
|
|
}
|
|
|
|
.prose a {
|
|
color: var(--color-accent);
|
|
text-decoration: underline;
|
|
}
|
|
|
|
.prose img {
|
|
max-width: 100%;
|
|
border-radius: var(--radius-lg);
|
|
margin: 1em 0;
|
|
}
|
|
|
|
.prose hr {
|
|
border: none;
|
|
border-top: 1px solid var(--color-border);
|
|
margin: 2em 0;
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## 4. Animation Guidelines
|
|
|
|
### 4.1 Motion Principles
|
|
|
|
1. **Purposeful**: Animation should communicate state changes, not decorate
|
|
2. **Quick**: Most transitions should be 150-250ms
|
|
3. **Responsive**: Motion should feel immediate to user input
|
|
4. **Respectful**: Don't animate if user prefers reduced motion
|
|
|
|
### 4.2 Standard Animations
|
|
|
|
```css
|
|
/* Fade in */
|
|
@keyframes fadeIn {
|
|
from { opacity: 0; }
|
|
to { opacity: 1; }
|
|
}
|
|
|
|
/* Slide in from bottom */
|
|
@keyframes slideInUp {
|
|
from {
|
|
opacity: 0;
|
|
transform: translateY(10px);
|
|
}
|
|
to {
|
|
opacity: 1;
|
|
transform: translateY(0);
|
|
}
|
|
}
|
|
|
|
/* Slide in from right (toasts) */
|
|
@keyframes slideInRight {
|
|
from {
|
|
opacity: 0;
|
|
transform: translateX(100%);
|
|
}
|
|
to {
|
|
opacity: 1;
|
|
transform: translateX(0);
|
|
}
|
|
}
|
|
|
|
/* Scale in (modals) */
|
|
@keyframes scaleIn {
|
|
from {
|
|
opacity: 0;
|
|
transform: scale(0.95);
|
|
}
|
|
to {
|
|
opacity: 1;
|
|
transform: scale(1);
|
|
}
|
|
}
|
|
|
|
/* Pulse (saving indicator) */
|
|
@keyframes pulse {
|
|
0%, 100% { opacity: 1; }
|
|
50% { opacity: 0.5; }
|
|
}
|
|
|
|
/* Spin (loading) */
|
|
@keyframes spin {
|
|
to { transform: rotate(360deg); }
|
|
}
|
|
|
|
/* Shimmer (skeleton) */
|
|
@keyframes shimmer {
|
|
0% { background-position: 200% 0; }
|
|
100% { background-position: -200% 0; }
|
|
}
|
|
```
|
|
|
|
### 4.3 Reduced Motion
|
|
|
|
```css
|
|
@media (prefers-reduced-motion: reduce) {
|
|
*,
|
|
*::before,
|
|
*::after {
|
|
animation-duration: 0.01ms !important;
|
|
animation-iteration-count: 1 !important;
|
|
transition-duration: 0.01ms !important;
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## 5. Responsive Breakpoints
|
|
|
|
```css
|
|
/* Mobile first breakpoints */
|
|
/* sm: 640px - Large phones */
|
|
/* md: 768px - Tablets */
|
|
/* lg: 1024px - Laptops */
|
|
/* xl: 1280px - Desktops */
|
|
/* 2xl: 1536px - Large screens */
|
|
|
|
@media (min-width: 640px) {
|
|
/* sm */
|
|
}
|
|
|
|
@media (min-width: 768px) {
|
|
/* md */
|
|
}
|
|
|
|
@media (min-width: 1024px) {
|
|
/* lg */
|
|
}
|
|
|
|
@media (min-width: 1280px) {
|
|
/* xl */
|
|
}
|
|
|
|
@media (min-width: 1536px) {
|
|
/* 2xl */
|
|
}
|
|
|
|
/* Mobile-only (no breakpoint, mobile first) */
|
|
/* styles apply to all, tablet+ override below */
|
|
|
|
/* Tablet and up */
|
|
@media (min-width: 768px) {
|
|
.hide-tablet { display: none; }
|
|
}
|
|
|
|
/* Desktop only */
|
|
@media (min-width: 1024px) {
|
|
.hide-desktop { display: none; }
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## 6. Icon Guidelines
|
|
|
|
### 6.1 Icon System
|
|
|
|
Using Lucide Icons (SVG-based, MIT licensed).
|
|
|
|
```html
|
|
<!-- Size variants -->
|
|
<svg class="icon icon-sm" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
<!-- icon path -->
|
|
</svg>
|
|
|
|
<svg class="icon" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
<!-- icon path -->
|
|
</svg>
|
|
|
|
<svg class="icon icon-lg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
<!-- icon path -->
|
|
</svg>
|
|
```
|
|
|
|
### 6.2 Icon Usage
|
|
|
|
```css
|
|
.icon {
|
|
display: inline-block;
|
|
vertical-align: middle;
|
|
flex-shrink: 0;
|
|
}
|
|
|
|
.icon-sm { width: 1rem; height: 1rem; }
|
|
.icon-md { width: 1.25rem; height: 1.25rem; }
|
|
.icon-lg { width: 1.5rem; height: 1.5rem; }
|
|
|
|
/* Buttons with icons */
|
|
.btn-icon {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
gap: var(--space-2);
|
|
}
|
|
|
|
/* Icon-only buttons need proper sizing */
|
|
.btn-icon-only {
|
|
width: 2.5rem;
|
|
height: 2.5rem;
|
|
padding: 0;
|
|
display: inline-flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
}
|
|
```
|
|
|
|
### 6.3 Common Icons
|
|
|
|
| Icon | Use Case |
|
|
|------|----------|
|
|
| `search` | Search input |
|
|
| `plus` | Create new items |
|
|
| `folder-plus` | Create library |
|
|
| `file-plus` | Create document |
|
|
| `edit` / `pencil` | Edit |
|
|
| `trash-2` | Delete |
|
|
| `download` | Export |
|
|
| `chevron-down` | Dropdown toggle |
|
|
| `chevron-right` | Tree expand |
|
|
| `x` | Close, dismiss |
|
|
| `check` | Confirm, saved |
|
|
| `alert-circle` | Error |
|
|
| `info` | Info toast |
|
|
| `settings` | Settings |
|
|
| `moon` | Dark mode |
|
|
| `sun` | Light mode |
|
|
| `home` | Dashboard |
|
|
| `folder` | Library |
|
|
| `file-text` | Document |
|
|
| `tag` | Tag |
|
|
| `link` | Internal link |
|
|
| `external-link` | External link |
|
|
| `copy` | Copy to clipboard |
|
|
| `eye` | Preview |
|
|
| `eye-off` | Hide |
|
|
| `keyboard` | Shortcuts |
|
|
|
|
---
|
|
|
|
## 7. Form Styling
|
|
|
|
### 7.1 Form Layouts
|
|
|
|
```css
|
|
/* Vertical form (default) */
|
|
.form-vertical {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: var(--space-4);
|
|
}
|
|
|
|
.form-horizontal {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
gap: var(--space-4);
|
|
align-items: flex-start;
|
|
}
|
|
|
|
.form-horizontal .form-group {
|
|
flex: 1;
|
|
min-width: 200px;
|
|
}
|
|
|
|
/* Inline form */
|
|
.form-inline {
|
|
display: flex;
|
|
gap: var(--space-2);
|
|
align-items: center;
|
|
}
|
|
```
|
|
|
|
### 7.2 Fieldset & Legend
|
|
|
|
```css
|
|
fieldset {
|
|
border: 1px solid var(--color-border);
|
|
border-radius: var(--radius-lg);
|
|
padding: var(--space-4);
|
|
margin-bottom: var(--space-4);
|
|
}
|
|
|
|
legend {
|
|
font-size: var(--text-sm);
|
|
font-weight: var(--font-semibold);
|
|
color: var(--color-text-muted);
|
|
text-transform: uppercase;
|
|
letter-spacing: var(--tracking-wider);
|
|
padding: 0 var(--space-2);
|
|
}
|
|
```
|
|
|
|
### 7.3 Help Text & Errors
|
|
|
|
```css
|
|
.help-text {
|
|
font-size: var(--text-sm);
|
|
color: var(--color-text-muted);
|
|
margin-top: var(--space-1);
|
|
}
|
|
|
|
.error-message {
|
|
font-size: var(--text-sm);
|
|
color: var(--color-danger);
|
|
margin-top: var(--space-1);
|
|
display: flex;
|
|
align-items: center;
|
|
gap: var(--space-1);
|
|
}
|
|
|
|
.input:invalid,
|
|
.input.error {
|
|
border-color: var(--color-danger);
|
|
}
|
|
|
|
.input:invalid:focus,
|
|
.input.error:focus {
|
|
box-shadow: 0 0 0 3px rgba(207, 74, 74, 0.25);
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## 8. Status & State Colors
|
|
|
|
### 8.1 Status Badge Colors
|
|
|
|
| Status | Background | Text | Border |
|
|
|--------|------------|------|--------|
|
|
| draft | `var(--color-warning-bg)` | `var(--color-warning)` | none |
|
|
| approved | `var(--color-info-bg)` | `var(--color-info)` | none |
|
|
| implemented | `var(--color-success-bg)` | `var(--color-success)` | none |
|
|
|
|
### 8.2 Priority Colors
|
|
|
|
| Priority | Color | Emoji |
|
|
|----------|-------|-------|
|
|
| high | `var(--color-priority-high)` | 🔴 |
|
|
| medium | `var(--color-priority-medium)` | 🟡 |
|
|
| low | `var(--color-priority-low)` | 🟢 |
|
|
|
|
### 8.3 Type Badge Colors
|
|
|
|
| Type | Border | Text |
|
|
|------|--------|------|
|
|
| requirement | `var(--color-requirement)` | `var(--color-requirement)` |
|
|
| note | `var(--color-note)` | `var(--color-note)` |
|
|
| spec | `var(--color-spec)` | `var(--color-spec)` |
|
|
| general | `var(--color-border)` | `var(--color-text-muted)` |
|
|
|
|
---
|
|
|
|
## 9. Loading & Skeleton States
|
|
|
|
### 9.1 Skeleton Colors
|
|
|
|
```css
|
|
.skeleton {
|
|
background: linear-gradient(
|
|
90deg,
|
|
var(--color-border) 25%,
|
|
var(--color-hover) 50%,
|
|
var(--color-border) 75%
|
|
);
|
|
background-size: 200% 100%;
|
|
animation: shimmer 1.5s infinite;
|
|
}
|
|
|
|
@keyframes shimmer {
|
|
0% { background-position: 200% 0; }
|
|
100% { background-position: -200% 0; }
|
|
}
|
|
|
|
/* Dark mode adjustment */
|
|
[data-theme="dark"] .skeleton {
|
|
background: linear-gradient(
|
|
90deg,
|
|
var(--color-surface) 25%,
|
|
var(--color-surface-raised) 50%,
|
|
var(--color-surface) 75%
|
|
);
|
|
background-size: 200% 100%;
|
|
}
|
|
```
|
|
|
|
### 9.2 Loading Overlay
|
|
|
|
```css
|
|
.loading-overlay {
|
|
position: absolute;
|
|
inset: 0;
|
|
background: rgba(var(--color-bg), 0.8);
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
z-index: var(--z-sticky);
|
|
}
|
|
|
|
[data-theme="dark"] .loading-overlay {
|
|
background: rgba(15, 17, 23, 0.8);
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## 10. Dark Mode Implementation
|
|
|
|
### 10.1 Theme Toggle
|
|
|
|
```javascript
|
|
// Theme toggle component
|
|
function ThemeToggle() {
|
|
const toggle = () => {
|
|
const current = document.documentElement.getAttribute('data-theme');
|
|
const next = current === 'light' ? 'dark' : 'light';
|
|
document.documentElement.setAttribute('data-theme', next);
|
|
localStorage.setItem('theme', next);
|
|
};
|
|
|
|
return `
|
|
<button class="btn-ghost" onclick="toggleTheme()" aria-label="Toggle theme">
|
|
${document.documentElement.getAttribute('data-theme') === 'dark' ? '☀️' : '🌙'}
|
|
</button>
|
|
`;
|
|
}
|
|
|
|
// Initialize theme on load
|
|
function initTheme() {
|
|
const saved = localStorage.getItem('theme');
|
|
const preferred = window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
|
|
const theme = saved || preferred;
|
|
document.documentElement.setAttribute('data-theme', theme);
|
|
}
|
|
```
|
|
|
|
### 10.2 CSS Variables at :root vs [data-theme]
|
|
|
|
```css
|
|
/* Default (dark) - no selector needed */
|
|
:root {
|
|
--color-bg: #0f1117;
|
|
/* ... */
|
|
}
|
|
|
|
/* Light theme - explicit selector */
|
|
[data-theme="light"] {
|
|
--color-bg: #f5f6f8;
|
|
/* ... */
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## 11. Code Syntax Highlighting
|
|
|
|
Using highlight.js or Prism for code blocks within markdown.
|
|
|
|
```css
|
|
/* Code highlighting tokens - dark theme */
|
|
.hljs {
|
|
background: var(--color-surface);
|
|
color: var(--color-text);
|
|
}
|
|
|
|
.hljs-keyword { color: #c678dd; }
|
|
.hljs-string { color: #98c379; }
|
|
.hljs-number { color: #d19a66; }
|
|
.hljs-function { color: #61afef; }
|
|
.hljs-comment { color: #5c6370; font-style: italic; }
|
|
.hljs-variable { color: #e06c75; }
|
|
.hljs-attr { color: #d19a66; }
|
|
.hljs-tag { color: #e06c75; }
|
|
.hljs-attribute { color: #d19a66; }
|
|
|
|
/* Code highlighting - light theme adjustments */
|
|
[data-theme="light"] .hljs-keyword { color: #a626a4; }
|
|
[data-theme="light"] .hljs-string { color: #50a14f; }
|
|
[data-theme="light"] .hljs-number { color: #986801; }
|
|
[data-theme="light"] .hljs-function { color: #4078f2; }
|
|
[data-theme="light"] .hljs-comment { color: #a0a1a7; }
|
|
[data-theme="light"] .hljs-variable { color: #e45649; }
|
|
[data-theme="light"] .hljs-attr { color: #986801; }
|
|
[data-theme="light"] .hljs-tag { color: #e45649; }
|
|
[data-theme="light"] .hljs-attribute { color: #986801; }
|
|
```
|
|
|
|
---
|
|
|
|
## 12. Print Styles
|
|
|
|
```css
|
|
@media print {
|
|
/* Hide navigation, sidebars, buttons */
|
|
.sidebar,
|
|
.app-header,
|
|
.toolbar,
|
|
.bottom-nav,
|
|
.btn,
|
|
.btn-ghost {
|
|
display: none !important;
|
|
}
|
|
|
|
/* Expand content */
|
|
.main-content {
|
|
width: 100% !important;
|
|
padding: 0 !important;
|
|
}
|
|
|
|
/* Adjust colors for print */
|
|
body {
|
|
background: white;
|
|
color: black;
|
|
}
|
|
|
|
/* Ensure links show URLs */
|
|
a[href^="http"]::after {
|
|
content: " (" attr(href) ")";
|
|
font-size: 0.8em;
|
|
}
|
|
|
|
/* Avoid page breaks inside elements */
|
|
.doc-card,
|
|
.prose h1,
|
|
.prose h2,
|
|
.prose h3,
|
|
.prose table {
|
|
break-inside: avoid;
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## 13. Accessibility Checklist
|
|
|
|
- [ ] All interactive elements have visible focus indicators
|
|
- [ ] Color contrast ratio ≥ 4.5:1 for text
|
|
- [ ] All images have alt text (or aria-hidden="true")
|
|
- [ ] Form inputs have associated labels
|
|
- [ ] Buttons have accessible names
|
|
- [ ] Icons have aria-label or visible text
|
|
- [ ] Modals trap focus and can be closed with Escape
|
|
- [ ] Toast notifications use role="alert" or role="status"
|
|
- [ ] Loading states announce to screen readers
|
|
- [ ] Reduced motion is respected
|
|
- [ ] Skip-to-content link is provided
|
|
- [ ] Semantic HTML is used (nav, main, aside, article, etc.)
|