@whykusanagi/corrupted-theme 0.1.2 → 0.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +133 -0
- package/README.md +6 -0
- package/docs/CAPABILITIES.md +209 -0
- package/docs/CHARACTER_LEVEL_CORRUPTION.md +264 -0
- package/docs/CORRUPTION_PHRASES.md +529 -0
- package/docs/FUTURE_WORK.md +189 -0
- package/docs/IMPLEMENTATION_VALIDATION.md +401 -0
- package/docs/LLM_PROVIDERS.md +345 -0
- package/docs/PERSONALITY.md +128 -0
- package/docs/ROADMAP.md +266 -0
- package/docs/ROUTING.md +324 -0
- package/docs/STYLE_GUIDE.md +605 -0
- package/docs/brand/BRAND_OVERVIEW.md +413 -0
- package/docs/brand/COLOR_SYSTEM.md +583 -0
- package/docs/brand/DESIGN_TOKENS.md +1009 -0
- package/docs/brand/TRANSLATION_FAILURE_AESTHETIC.md +525 -0
- package/docs/brand/TYPOGRAPHY.md +624 -0
- package/docs/components/ANIMATION_GUIDELINES.md +901 -0
- package/docs/components/COMPONENT_LIBRARY.md +1061 -0
- package/docs/components/GLASSMORPHISM.md +602 -0
- package/docs/components/INTERACTIVE_STATES.md +766 -0
- package/docs/governance/CONTRIBUTION_GUIDELINES.md +593 -0
- package/docs/governance/DESIGN_SYSTEM_GOVERNANCE.md +451 -0
- package/docs/governance/VERSION_MANAGEMENT.md +447 -0
- package/docs/governance/VERSION_REFERENCES.md +229 -0
- package/docs/platforms/CLI_IMPLEMENTATION.md +1025 -0
- package/docs/platforms/COMPONENT_MAPPING.md +579 -0
- package/docs/platforms/NPM_PACKAGE.md +854 -0
- package/docs/platforms/WEB_IMPLEMENTATION.md +1221 -0
- package/docs/standards/ACCESSIBILITY.md +715 -0
- package/docs/standards/ANTI_PATTERNS.md +554 -0
- package/docs/standards/SPACING_SYSTEM.md +549 -0
- package/examples/button.html +1 -1
- package/examples/card.html +1 -1
- package/examples/form.html +1 -1
- package/examples/index.html +2 -2
- package/examples/layout.html +1 -1
- package/examples/nikke-team-builder.html +1 -1
- package/examples/showcase-complete.html +840 -15
- package/examples/showcase.html +1 -1
- package/package.json +4 -2
- package/src/css/components.css +676 -0
- package/src/lib/character-corruption.js +563 -0
- package/src/lib/components.js +283 -0
|
@@ -0,0 +1,1221 @@
|
|
|
1
|
+
# Web Implementation Guide
|
|
2
|
+
|
|
3
|
+
> **Celeste Brand System** | Platform Documentation
|
|
4
|
+
> **Document**: Web Implementation Guide
|
|
5
|
+
> **Version**: 1.0.0
|
|
6
|
+
> **Last Updated**: 2025-12-13
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## Table of Contents
|
|
11
|
+
|
|
12
|
+
1. [Overview](#overview)
|
|
13
|
+
2. [Responsive Design System](#responsive-design-system)
|
|
14
|
+
3. [CSS Integration](#css-integration)
|
|
15
|
+
4. [Framework Integration](#framework-integration)
|
|
16
|
+
5. [Performance Optimization](#performance-optimization)
|
|
17
|
+
6. [Browser Support](#browser-support)
|
|
18
|
+
7. [Accessibility](#accessibility)
|
|
19
|
+
8. [Implementation Examples](#implementation-examples)
|
|
20
|
+
9. [Common Patterns](#common-patterns)
|
|
21
|
+
10. [Troubleshooting](#troubleshooting)
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## Overview
|
|
26
|
+
|
|
27
|
+
This guide covers implementing the Celeste brand system on web platforms using the **@whykusanagi/corrupted-theme** npm package. The web implementation maintains the same translation-failure aesthetic as the CLI while adapting to responsive, interactive web interfaces.
|
|
28
|
+
|
|
29
|
+
### Key Web Features
|
|
30
|
+
|
|
31
|
+
- **Responsive Design**: Mobile-first approach with 3 breakpoints
|
|
32
|
+
- **Glassmorphism**: CSS backdrop-filter effects for frosted glass aesthetic
|
|
33
|
+
- **Modular CSS**: Import only what you need (9 modular files)
|
|
34
|
+
- **Design Tokens**: CSS custom properties for easy theming
|
|
35
|
+
- **Framework Agnostic**: Works with React, Vue, Svelte, vanilla JS
|
|
36
|
+
- **Accessibility**: WCAG AA compliant with keyboard navigation
|
|
37
|
+
- **Performance**: GPU-accelerated animations, optimized glass effects
|
|
38
|
+
|
|
39
|
+
### Quick Start
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
# Install corrupted-theme
|
|
43
|
+
npm install @whykusanagi/corrupted-theme
|
|
44
|
+
|
|
45
|
+
# Or use from local development
|
|
46
|
+
npm link /path/to/corrupted-theme
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
```html
|
|
50
|
+
<!-- Import full theme -->
|
|
51
|
+
<link rel="stylesheet" href="node_modules/@whykusanagi/corrupted-theme/src/css/theme.css">
|
|
52
|
+
|
|
53
|
+
<!-- Or import modularly -->
|
|
54
|
+
<link rel="stylesheet" href="node_modules/@whykusanagi/corrupted-theme/src/css/variables.css">
|
|
55
|
+
<link rel="stylesheet" href="node_modules/@whykusanagi/corrupted-theme/src/css/glass.css">
|
|
56
|
+
<link rel="stylesheet" href="node_modules/@whykusanagi/corrupted-theme/src/css/components.css">
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
---
|
|
60
|
+
|
|
61
|
+
## Responsive Design System
|
|
62
|
+
|
|
63
|
+
### Breakpoint Strategy
|
|
64
|
+
|
|
65
|
+
Celeste uses a **mobile-first** approach with 3 core breakpoints:
|
|
66
|
+
|
|
67
|
+
```css
|
|
68
|
+
/* Mobile: 0-640px (default - no media query needed) */
|
|
69
|
+
.container {
|
|
70
|
+
padding: 1rem;
|
|
71
|
+
max-width: 100%;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/* Tablet: 641px-1024px */
|
|
75
|
+
@media (min-width: 641px) {
|
|
76
|
+
.container {
|
|
77
|
+
padding: 2rem;
|
|
78
|
+
max-width: 768px;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/* Desktop: 1025px+ */
|
|
83
|
+
@media (min-width: 1025px) {
|
|
84
|
+
.container {
|
|
85
|
+
padding: 3rem;
|
|
86
|
+
max-width: 1200px;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### Breakpoint Reference
|
|
92
|
+
|
|
93
|
+
| Breakpoint | Range | Target Devices | Container Width |
|
|
94
|
+
|------------|-------|----------------|-----------------|
|
|
95
|
+
| **Mobile** | 0-640px | Phones (portrait) | 100% (16px padding) |
|
|
96
|
+
| **Tablet** | 641px-1024px | Tablets, phones (landscape) | 768px (32px padding) |
|
|
97
|
+
| **Desktop** | 1025px+ | Laptops, desktops, large screens | 1200px (48px padding) |
|
|
98
|
+
|
|
99
|
+
### Design Tokens for Breakpoints
|
|
100
|
+
|
|
101
|
+
```css
|
|
102
|
+
:root {
|
|
103
|
+
/* Breakpoint values */
|
|
104
|
+
--breakpoint-mobile: 640px;
|
|
105
|
+
--breakpoint-tablet: 641px;
|
|
106
|
+
--breakpoint-desktop: 1025px;
|
|
107
|
+
|
|
108
|
+
/* Container widths */
|
|
109
|
+
--container-mobile: 100%;
|
|
110
|
+
--container-tablet: 768px;
|
|
111
|
+
--container-desktop: 1200px;
|
|
112
|
+
|
|
113
|
+
/* Spacing scale (responsive) */
|
|
114
|
+
--spacing-xs: 0.25rem; /* 4px */
|
|
115
|
+
--spacing-sm: 0.5rem; /* 8px */
|
|
116
|
+
--spacing-md: 1rem; /* 16px */
|
|
117
|
+
--spacing-lg: 1.5rem; /* 24px */
|
|
118
|
+
--spacing-xl: 2rem; /* 32px */
|
|
119
|
+
--spacing-2xl: 3rem; /* 48px */
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/* Scale up spacing on larger screens */
|
|
123
|
+
@media (min-width: 1025px) {
|
|
124
|
+
:root {
|
|
125
|
+
--spacing-lg: 2rem; /* 32px on desktop */
|
|
126
|
+
--spacing-xl: 3rem; /* 48px on desktop */
|
|
127
|
+
--spacing-2xl: 4rem; /* 64px on desktop */
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
### Responsive Typography
|
|
133
|
+
|
|
134
|
+
Typography scales proportionally across breakpoints:
|
|
135
|
+
|
|
136
|
+
```css
|
|
137
|
+
/* Mobile typography (base) */
|
|
138
|
+
:root {
|
|
139
|
+
--font-size-h1: 2rem; /* 32px */
|
|
140
|
+
--font-size-h2: 1.5rem; /* 24px */
|
|
141
|
+
--font-size-h3: 1.25rem; /* 20px */
|
|
142
|
+
--font-size-body: 1rem; /* 16px */
|
|
143
|
+
--font-size-small: 0.875rem; /* 14px */
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/* Desktop typography (scaled up) */
|
|
147
|
+
@media (min-width: 1025px) {
|
|
148
|
+
:root {
|
|
149
|
+
--font-size-h1: 3.75rem; /* 60px */
|
|
150
|
+
--font-size-h2: 2.5rem; /* 40px */
|
|
151
|
+
--font-size-h3: 1.875rem; /* 30px */
|
|
152
|
+
--font-size-body: 1.125rem; /* 18px */
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/* Usage */
|
|
157
|
+
h1 {
|
|
158
|
+
font-size: var(--font-size-h1);
|
|
159
|
+
line-height: 1.2;
|
|
160
|
+
}
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
### Grid System (Optional)
|
|
164
|
+
|
|
165
|
+
For complex layouts, use CSS Grid with responsive columns:
|
|
166
|
+
|
|
167
|
+
```css
|
|
168
|
+
.grid {
|
|
169
|
+
display: grid;
|
|
170
|
+
gap: var(--spacing-md);
|
|
171
|
+
|
|
172
|
+
/* Mobile: 1 column */
|
|
173
|
+
grid-template-columns: 1fr;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
@media (min-width: 641px) {
|
|
177
|
+
.grid {
|
|
178
|
+
/* Tablet: 2 columns */
|
|
179
|
+
grid-template-columns: repeat(2, 1fr);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
@media (min-width: 1025px) {
|
|
184
|
+
.grid {
|
|
185
|
+
/* Desktop: 3-4 columns */
|
|
186
|
+
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
---
|
|
192
|
+
|
|
193
|
+
## CSS Integration
|
|
194
|
+
|
|
195
|
+
### Import Order (Critical)
|
|
196
|
+
|
|
197
|
+
CSS files must be imported in this **specific order** to ensure proper cascading:
|
|
198
|
+
|
|
199
|
+
```html
|
|
200
|
+
<!-- 1. Variables (design tokens) - MUST be first -->
|
|
201
|
+
<link rel="stylesheet" href="css/variables.css">
|
|
202
|
+
|
|
203
|
+
<!-- 2. Base styles (resets, typography) -->
|
|
204
|
+
<link rel="stylesheet" href="css/base.css">
|
|
205
|
+
|
|
206
|
+
<!-- 3. Animations (keyframes used by components) -->
|
|
207
|
+
<link rel="stylesheet" href="css/animations.css">
|
|
208
|
+
|
|
209
|
+
<!-- 4. Glass effects (backdrop-filter) -->
|
|
210
|
+
<link rel="stylesheet" href="css/glass.css">
|
|
211
|
+
|
|
212
|
+
<!-- 5. Layout utilities -->
|
|
213
|
+
<link rel="stylesheet" href="css/layout.css">
|
|
214
|
+
|
|
215
|
+
<!-- 6. Components -->
|
|
216
|
+
<link rel="stylesheet" href="css/components.css">
|
|
217
|
+
|
|
218
|
+
<!-- 7. Interactive states (hover, focus, active) -->
|
|
219
|
+
<link rel="stylesheet" href="css/interactive.css">
|
|
220
|
+
|
|
221
|
+
<!-- 8. Utilities (last to override) -->
|
|
222
|
+
<link rel="stylesheet" href="css/utilities.css">
|
|
223
|
+
|
|
224
|
+
<!-- 9. Your custom styles -->
|
|
225
|
+
<link rel="stylesheet" href="css/custom.css">
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
### Single File Import (Easier)
|
|
229
|
+
|
|
230
|
+
For simpler projects, use the pre-bundled theme:
|
|
231
|
+
|
|
232
|
+
```html
|
|
233
|
+
<!-- All styles included (8.2KB gzipped) -->
|
|
234
|
+
<link rel="stylesheet" href="node_modules/@whykusanagi/corrupted-theme/src/css/theme.css">
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
### CSS Custom Properties (Theming)
|
|
238
|
+
|
|
239
|
+
Override design tokens for custom theming:
|
|
240
|
+
|
|
241
|
+
```css
|
|
242
|
+
/* Override defaults in your custom CSS */
|
|
243
|
+
:root {
|
|
244
|
+
/* Change accent color from pink to purple */
|
|
245
|
+
--color-accent: #8b5cf6;
|
|
246
|
+
--color-accent-light: #a78bfa;
|
|
247
|
+
--color-accent-dark: #7c3aed;
|
|
248
|
+
|
|
249
|
+
/* Adjust glass opacity */
|
|
250
|
+
--glass-opacity: 0.8; /* Default is 0.7 */
|
|
251
|
+
|
|
252
|
+
/* Change border radius */
|
|
253
|
+
--radius-md: 12px; /* Default is 8px */
|
|
254
|
+
}
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
### CSS Architecture
|
|
258
|
+
|
|
259
|
+
The corrupted-theme package follows **ITCSS (Inverted Triangle CSS)** architecture:
|
|
260
|
+
|
|
261
|
+
```
|
|
262
|
+
Settings (variables.css) ← Most generic
|
|
263
|
+
↓
|
|
264
|
+
Tools (mixins, not included)
|
|
265
|
+
↓
|
|
266
|
+
Generic (base.css)
|
|
267
|
+
↓
|
|
268
|
+
Elements (typography, links)
|
|
269
|
+
↓
|
|
270
|
+
Objects (layout.css)
|
|
271
|
+
↓
|
|
272
|
+
Components (components.css) ← Most specific
|
|
273
|
+
↓
|
|
274
|
+
Utilities (utilities.css)
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
---
|
|
278
|
+
|
|
279
|
+
## Framework Integration
|
|
280
|
+
|
|
281
|
+
### Vanilla JavaScript
|
|
282
|
+
|
|
283
|
+
```html
|
|
284
|
+
<!DOCTYPE html>
|
|
285
|
+
<html lang="en">
|
|
286
|
+
<head>
|
|
287
|
+
<meta charset="UTF-8">
|
|
288
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
289
|
+
<title>Celeste App</title>
|
|
290
|
+
|
|
291
|
+
<!-- Import theme -->
|
|
292
|
+
<link rel="stylesheet" href="node_modules/@whykusanagi/corrupted-theme/src/css/theme.css">
|
|
293
|
+
</head>
|
|
294
|
+
<body>
|
|
295
|
+
<div class="glass-card">
|
|
296
|
+
<h2 class="corrupted-text">使US狀ERAGEMENT</h2>
|
|
297
|
+
<p>Your content here</p>
|
|
298
|
+
</div>
|
|
299
|
+
|
|
300
|
+
<script>
|
|
301
|
+
// Add corruption animation
|
|
302
|
+
function corruptText(text, intensity = 0.3) {
|
|
303
|
+
const japaneseChars = ['ア', 'イ', 'ウ', '使', '統', '計', 'ー'];
|
|
304
|
+
return text.split('').map((char, i) => {
|
|
305
|
+
if (Math.random() < intensity && /[a-zA-Z]/.test(char)) {
|
|
306
|
+
return japaneseChars[Math.floor(Math.random() * japaneseChars.length)];
|
|
307
|
+
}
|
|
308
|
+
return char;
|
|
309
|
+
}).join('');
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
// Apply corruption on hover
|
|
313
|
+
document.querySelectorAll('.corrupted-text').forEach(el => {
|
|
314
|
+
const original = el.textContent;
|
|
315
|
+
el.addEventListener('mouseenter', () => {
|
|
316
|
+
el.textContent = corruptText(original);
|
|
317
|
+
});
|
|
318
|
+
el.addEventListener('mouseleave', () => {
|
|
319
|
+
el.textContent = original;
|
|
320
|
+
});
|
|
321
|
+
});
|
|
322
|
+
</script>
|
|
323
|
+
</body>
|
|
324
|
+
</html>
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
### React
|
|
328
|
+
|
|
329
|
+
```jsx
|
|
330
|
+
// App.jsx
|
|
331
|
+
import '@whykusanagi/corrupted-theme/src/css/theme.css';
|
|
332
|
+
import { useState, useEffect } from 'react';
|
|
333
|
+
|
|
334
|
+
function GlassCard({ children }) {
|
|
335
|
+
return (
|
|
336
|
+
<div className="glass-card">
|
|
337
|
+
{children}
|
|
338
|
+
</div>
|
|
339
|
+
);
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
function CorruptedText({ text, intensity = 0.3 }) {
|
|
343
|
+
const [corrupted, setCorrupted] = useState(text);
|
|
344
|
+
|
|
345
|
+
const corruptText = (text) => {
|
|
346
|
+
const japaneseChars = ['ア', 'イ', 'ウ', '使', '統', '計'];
|
|
347
|
+
return text.split('').map((char) => {
|
|
348
|
+
if (Math.random() < intensity && /[a-zA-Z]/.test(char)) {
|
|
349
|
+
return japaneseChars[Math.floor(Math.random() * japaneseChars.length)];
|
|
350
|
+
}
|
|
351
|
+
return char;
|
|
352
|
+
}).join('');
|
|
353
|
+
};
|
|
354
|
+
|
|
355
|
+
useEffect(() => {
|
|
356
|
+
const interval = setInterval(() => {
|
|
357
|
+
setCorrupted(corruptText(text));
|
|
358
|
+
}, 3000);
|
|
359
|
+
return () => clearInterval(interval);
|
|
360
|
+
}, [text, intensity]);
|
|
361
|
+
|
|
362
|
+
return <span className="corrupted-text">{corrupted}</span>;
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
function App() {
|
|
366
|
+
return (
|
|
367
|
+
<div className="container">
|
|
368
|
+
<GlassCard>
|
|
369
|
+
<h2><CorruptedText text="USER MANAGEMENT" /></h2>
|
|
370
|
+
<p>Your content here</p>
|
|
371
|
+
</GlassCard>
|
|
372
|
+
</div>
|
|
373
|
+
);
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
export default App;
|
|
377
|
+
```
|
|
378
|
+
|
|
379
|
+
### Vue 3
|
|
380
|
+
|
|
381
|
+
```vue
|
|
382
|
+
<!-- App.vue -->
|
|
383
|
+
<script setup>
|
|
384
|
+
import { ref, onMounted, onUnmounted } from 'vue';
|
|
385
|
+
import '@whykusanagi/corrupted-theme/src/css/theme.css';
|
|
386
|
+
|
|
387
|
+
const props = defineProps({
|
|
388
|
+
text: String,
|
|
389
|
+
intensity: { type: Number, default: 0.3 }
|
|
390
|
+
});
|
|
391
|
+
|
|
392
|
+
const corrupted = ref(props.text);
|
|
393
|
+
|
|
394
|
+
function corruptText(text) {
|
|
395
|
+
const japaneseChars = ['ア', 'イ', 'ウ', '使', '統', '計'];
|
|
396
|
+
return text.split('').map((char) => {
|
|
397
|
+
if (Math.random() < props.intensity && /[a-zA-Z]/.test(char)) {
|
|
398
|
+
return japaneseChars[Math.floor(Math.random() * japaneseChars.length)];
|
|
399
|
+
}
|
|
400
|
+
return char;
|
|
401
|
+
}).join('');
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
let interval;
|
|
405
|
+
onMounted(() => {
|
|
406
|
+
interval = setInterval(() => {
|
|
407
|
+
corrupted.value = corruptText(props.text);
|
|
408
|
+
}, 3000);
|
|
409
|
+
});
|
|
410
|
+
|
|
411
|
+
onUnmounted(() => clearInterval(interval));
|
|
412
|
+
</script>
|
|
413
|
+
|
|
414
|
+
<template>
|
|
415
|
+
<div class="glass-card">
|
|
416
|
+
<h2 class="corrupted-text">{{ corrupted }}</h2>
|
|
417
|
+
<slot />
|
|
418
|
+
</div>
|
|
419
|
+
</template>
|
|
420
|
+
```
|
|
421
|
+
|
|
422
|
+
### Next.js (App Router)
|
|
423
|
+
|
|
424
|
+
```jsx
|
|
425
|
+
// app/layout.jsx
|
|
426
|
+
import '@whykusanagi/corrupted-theme/src/css/theme.css';
|
|
427
|
+
|
|
428
|
+
export const metadata = {
|
|
429
|
+
title: 'Celeste App',
|
|
430
|
+
description: 'Translation-failure aesthetic',
|
|
431
|
+
};
|
|
432
|
+
|
|
433
|
+
export default function RootLayout({ children }) {
|
|
434
|
+
return (
|
|
435
|
+
<html lang="en">
|
|
436
|
+
<body>{children}</body>
|
|
437
|
+
</html>
|
|
438
|
+
);
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
// app/page.jsx
|
|
442
|
+
'use client';
|
|
443
|
+
|
|
444
|
+
import { useEffect, useState } from 'react';
|
|
445
|
+
|
|
446
|
+
export default function Home() {
|
|
447
|
+
const [mounted, setMounted] = useState(false);
|
|
448
|
+
|
|
449
|
+
useEffect(() => {
|
|
450
|
+
setMounted(true);
|
|
451
|
+
}, []);
|
|
452
|
+
|
|
453
|
+
if (!mounted) return null; // Prevent SSR hydration mismatch
|
|
454
|
+
|
|
455
|
+
return (
|
|
456
|
+
<main className="container">
|
|
457
|
+
<div className="glass-card">
|
|
458
|
+
<h1 className="corrupted-text">使WE統LCOME</h1>
|
|
459
|
+
<p>Premium corrupted AI aesthetic</p>
|
|
460
|
+
</div>
|
|
461
|
+
</main>
|
|
462
|
+
);
|
|
463
|
+
}
|
|
464
|
+
```
|
|
465
|
+
|
|
466
|
+
---
|
|
467
|
+
|
|
468
|
+
## Performance Optimization
|
|
469
|
+
|
|
470
|
+
### Critical Rendering Path
|
|
471
|
+
|
|
472
|
+
1. **Inline critical CSS** for above-the-fold content:
|
|
473
|
+
|
|
474
|
+
```html
|
|
475
|
+
<head>
|
|
476
|
+
<style>
|
|
477
|
+
/* Critical CSS (variables + glass-card only) */
|
|
478
|
+
:root {
|
|
479
|
+
--color-accent: #d94f90;
|
|
480
|
+
--glass-bg: rgba(20, 12, 40, 0.7);
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
.glass-card {
|
|
484
|
+
background: var(--glass-bg);
|
|
485
|
+
backdrop-filter: blur(15px);
|
|
486
|
+
border-radius: 8px;
|
|
487
|
+
padding: 2rem;
|
|
488
|
+
}
|
|
489
|
+
</style>
|
|
490
|
+
|
|
491
|
+
<!-- Defer non-critical CSS -->
|
|
492
|
+
<link rel="preload" href="theme.css" as="style" onload="this.onload=null;this.rel='stylesheet'">
|
|
493
|
+
<noscript><link rel="stylesheet" href="theme.css"></noscript>
|
|
494
|
+
</head>
|
|
495
|
+
```
|
|
496
|
+
|
|
497
|
+
### Glass Effect Performance
|
|
498
|
+
|
|
499
|
+
Backdrop-filter is expensive. Follow these rules:
|
|
500
|
+
|
|
501
|
+
```css
|
|
502
|
+
/* ✅ Good: Limited glass elements */
|
|
503
|
+
.hero-card {
|
|
504
|
+
backdrop-filter: blur(15px);
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
/* ❌ Bad: Too many glass elements */
|
|
508
|
+
.every-card {
|
|
509
|
+
backdrop-filter: blur(15px); /* 20+ cards = janky scroll */
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
/* ✅ Good: Disable glass on scroll (mobile) */
|
|
513
|
+
@media (max-width: 640px) {
|
|
514
|
+
.scrolling .glass-card {
|
|
515
|
+
backdrop-filter: none; /* Improve scroll performance */
|
|
516
|
+
background: rgba(20, 12, 40, 0.95); /* Solid fallback */
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
```
|
|
520
|
+
|
|
521
|
+
### Code Splitting (React)
|
|
522
|
+
|
|
523
|
+
```jsx
|
|
524
|
+
import { lazy, Suspense } from 'react';
|
|
525
|
+
|
|
526
|
+
// Lazy load corrupted-theme for non-critical pages
|
|
527
|
+
const CorruptedDashboard = lazy(() => import('./CorruptedDashboard'));
|
|
528
|
+
|
|
529
|
+
function App() {
|
|
530
|
+
return (
|
|
531
|
+
<Suspense fallback={<div>Loading...</div>}>
|
|
532
|
+
<CorruptedDashboard />
|
|
533
|
+
</Suspense>
|
|
534
|
+
);
|
|
535
|
+
}
|
|
536
|
+
```
|
|
537
|
+
|
|
538
|
+
### Image Optimization
|
|
539
|
+
|
|
540
|
+
```html
|
|
541
|
+
<!-- Use WebP with fallback -->
|
|
542
|
+
<picture>
|
|
543
|
+
<source srcset="hero.webp" type="image/webp">
|
|
544
|
+
<img src="hero.jpg" alt="Hero" loading="lazy">
|
|
545
|
+
</picture>
|
|
546
|
+
|
|
547
|
+
<!-- Add blur placeholder for glassmorphism effect -->
|
|
548
|
+
<div class="glass-image-wrapper">
|
|
549
|
+
<img src="hero.jpg" alt="Hero" style="filter: blur(2px);">
|
|
550
|
+
</div>
|
|
551
|
+
```
|
|
552
|
+
|
|
553
|
+
### Animation Performance
|
|
554
|
+
|
|
555
|
+
```css
|
|
556
|
+
/* ✅ Good: GPU-accelerated properties only */
|
|
557
|
+
.btn {
|
|
558
|
+
transition: transform 0.15s ease, opacity 0.15s ease;
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
.btn:hover {
|
|
562
|
+
transform: scale(1.05);
|
|
563
|
+
opacity: 0.9;
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
/* ❌ Bad: CPU-bound properties */
|
|
567
|
+
.btn:hover {
|
|
568
|
+
width: 120px; /* Causes reflow */
|
|
569
|
+
margin-left: -10px; /* Causes reflow */
|
|
570
|
+
}
|
|
571
|
+
```
|
|
572
|
+
|
|
573
|
+
---
|
|
574
|
+
|
|
575
|
+
## Browser Support
|
|
576
|
+
|
|
577
|
+
### Target Browsers
|
|
578
|
+
|
|
579
|
+
Celeste supports **modern browsers** with graceful degradation:
|
|
580
|
+
|
|
581
|
+
| Browser | Minimum Version | Notes |
|
|
582
|
+
|---------|-----------------|-------|
|
|
583
|
+
| **Chrome** | 90+ | Full support (backdrop-filter) |
|
|
584
|
+
| **Firefox** | 88+ | Full support |
|
|
585
|
+
| **Safari** | 14+ | Full support (-webkit-backdrop-filter) |
|
|
586
|
+
| **Edge** | 90+ | Full support (Chromium-based) |
|
|
587
|
+
| **Mobile Safari** | iOS 14+ | Full support |
|
|
588
|
+
| **Chrome Android** | 90+ | Full support |
|
|
589
|
+
|
|
590
|
+
### Feature Detection
|
|
591
|
+
|
|
592
|
+
Use `@supports` for progressive enhancement:
|
|
593
|
+
|
|
594
|
+
```css
|
|
595
|
+
/* Fallback for browsers without backdrop-filter */
|
|
596
|
+
.glass-card {
|
|
597
|
+
background: rgba(20, 12, 40, 0.95); /* Solid fallback */
|
|
598
|
+
border: 1px solid rgba(217, 79, 144, 0.3);
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
/* Enhanced glass effect for modern browsers */
|
|
602
|
+
@supports (backdrop-filter: blur(15px)) or (-webkit-backdrop-filter: blur(15px)) {
|
|
603
|
+
.glass-card {
|
|
604
|
+
background: rgba(20, 12, 40, 0.7); /* More transparent */
|
|
605
|
+
backdrop-filter: blur(15px);
|
|
606
|
+
-webkit-backdrop-filter: blur(15px); /* Safari prefix */
|
|
607
|
+
}
|
|
608
|
+
}
|
|
609
|
+
```
|
|
610
|
+
|
|
611
|
+
### Vendor Prefixes
|
|
612
|
+
|
|
613
|
+
**Required prefixes** (already included in theme.css):
|
|
614
|
+
|
|
615
|
+
```css
|
|
616
|
+
.glass-card {
|
|
617
|
+
backdrop-filter: blur(15px); /* Standard */
|
|
618
|
+
-webkit-backdrop-filter: blur(15px); /* Safari/iOS */
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
.gradient-text {
|
|
622
|
+
background-clip: text; /* Standard */
|
|
623
|
+
-webkit-background-clip: text; /* Safari/Chrome */
|
|
624
|
+
-webkit-text-fill-color: transparent; /* Safari/Chrome */
|
|
625
|
+
}
|
|
626
|
+
```
|
|
627
|
+
|
|
628
|
+
### Polyfills (Optional)
|
|
629
|
+
|
|
630
|
+
For IE11 support (not recommended), use polyfills:
|
|
631
|
+
|
|
632
|
+
```html
|
|
633
|
+
<!-- CSS custom properties polyfill -->
|
|
634
|
+
<script src="https://cdn.jsdelivr.net/npm/css-vars-ponyfill@2"></script>
|
|
635
|
+
<script>
|
|
636
|
+
cssVars({
|
|
637
|
+
include: 'link[rel=stylesheet]',
|
|
638
|
+
onlyLegacy: true, // Only run for IE11
|
|
639
|
+
});
|
|
640
|
+
</script>
|
|
641
|
+
```
|
|
642
|
+
|
|
643
|
+
---
|
|
644
|
+
|
|
645
|
+
## Accessibility
|
|
646
|
+
|
|
647
|
+
### WCAG AA Compliance
|
|
648
|
+
|
|
649
|
+
All Celeste components meet **WCAG 2.1 Level AA** standards:
|
|
650
|
+
|
|
651
|
+
#### Color Contrast
|
|
652
|
+
|
|
653
|
+
```css
|
|
654
|
+
/* ✅ All combinations tested */
|
|
655
|
+
--color-bg: #0a0612; /* Dark background */
|
|
656
|
+
--color-text: #ffffff; /* White text: 21:1 ratio (AAA) */
|
|
657
|
+
--color-accent: #d94f90; /* Pink accent: 7.2:1 ratio (AAA) */
|
|
658
|
+
--color-muted: #a0a0a0; /* Muted text: 10.5:1 ratio (AAA) */
|
|
659
|
+
```
|
|
660
|
+
|
|
661
|
+
#### Keyboard Navigation
|
|
662
|
+
|
|
663
|
+
```css
|
|
664
|
+
/* Focus indicators (WCAG 2.4.7) */
|
|
665
|
+
.btn:focus-visible {
|
|
666
|
+
outline: 2px solid rgba(217, 79, 144, 0.7);
|
|
667
|
+
outline-offset: 2px;
|
|
668
|
+
}
|
|
669
|
+
|
|
670
|
+
/* Skip to main content link */
|
|
671
|
+
.skip-link {
|
|
672
|
+
position: absolute;
|
|
673
|
+
top: -40px;
|
|
674
|
+
left: 0;
|
|
675
|
+
background: var(--color-accent);
|
|
676
|
+
color: white;
|
|
677
|
+
padding: 8px;
|
|
678
|
+
z-index: 100;
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
.skip-link:focus {
|
|
682
|
+
top: 0;
|
|
683
|
+
}
|
|
684
|
+
```
|
|
685
|
+
|
|
686
|
+
#### Screen Reader Support
|
|
687
|
+
|
|
688
|
+
```html
|
|
689
|
+
<!-- ARIA labels for interactive elements -->
|
|
690
|
+
<button class="btn" aria-label="Close dialog">
|
|
691
|
+
<span aria-hidden="true">×</span>
|
|
692
|
+
</button>
|
|
693
|
+
|
|
694
|
+
<!-- ARIA live regions for dynamic content -->
|
|
695
|
+
<div class="toast" role="alert" aria-live="polite">
|
|
696
|
+
Success! Data saved.
|
|
697
|
+
</div>
|
|
698
|
+
|
|
699
|
+
<!-- Hidden text for corrupted content -->
|
|
700
|
+
<h2 class="corrupted-text" aria-label="User Management">
|
|
701
|
+
使US狀ERAGEMENT <!-- Visual corruption -->
|
|
702
|
+
</h2>
|
|
703
|
+
```
|
|
704
|
+
|
|
705
|
+
#### Motion Reduction
|
|
706
|
+
|
|
707
|
+
```css
|
|
708
|
+
/* Respect user preference (WCAG 2.3.3) */
|
|
709
|
+
@media (prefers-reduced-motion: reduce) {
|
|
710
|
+
* {
|
|
711
|
+
animation-duration: 0.01ms !important;
|
|
712
|
+
animation-iteration-count: 1 !important;
|
|
713
|
+
transition-duration: 0.01ms !important;
|
|
714
|
+
}
|
|
715
|
+
|
|
716
|
+
/* Disable decorative animations */
|
|
717
|
+
.corrupted-text,
|
|
718
|
+
.flicker,
|
|
719
|
+
.glitch-effect {
|
|
720
|
+
animation: none;
|
|
721
|
+
}
|
|
722
|
+
}
|
|
723
|
+
```
|
|
724
|
+
|
|
725
|
+
#### Touch Targets (Mobile)
|
|
726
|
+
|
|
727
|
+
```css
|
|
728
|
+
/* Minimum 44x44px touch targets (WCAG 2.5.5) */
|
|
729
|
+
.btn {
|
|
730
|
+
min-width: 44px;
|
|
731
|
+
min-height: 44px;
|
|
732
|
+
padding: 0.75rem 1.5rem;
|
|
733
|
+
}
|
|
734
|
+
|
|
735
|
+
/* Increase spacing between touch targets */
|
|
736
|
+
.btn + .btn {
|
|
737
|
+
margin-left: 0.5rem; /* 8px gap */
|
|
738
|
+
}
|
|
739
|
+
```
|
|
740
|
+
|
|
741
|
+
---
|
|
742
|
+
|
|
743
|
+
## Implementation Examples
|
|
744
|
+
|
|
745
|
+
### Example 1: Homepage Hero
|
|
746
|
+
|
|
747
|
+
```html
|
|
748
|
+
<section class="hero">
|
|
749
|
+
<div class="container">
|
|
750
|
+
<div class="glass-card hero-card">
|
|
751
|
+
<h1 class="corrupted-text" aria-label="Welcome to Celeste">
|
|
752
|
+
使WE統LCOME TO C理計E埋ESTE
|
|
753
|
+
</h1>
|
|
754
|
+
<p class="subtitle">
|
|
755
|
+
Premium corrupted AI aesthetic with translation-failure linguistics
|
|
756
|
+
</p>
|
|
757
|
+
<div class="btn-group">
|
|
758
|
+
<button class="btn btn-primary">Get Started</button>
|
|
759
|
+
<button class="btn btn-secondary">Learn More</button>
|
|
760
|
+
</div>
|
|
761
|
+
</div>
|
|
762
|
+
</div>
|
|
763
|
+
</section>
|
|
764
|
+
|
|
765
|
+
<style>
|
|
766
|
+
.hero {
|
|
767
|
+
min-height: 100vh;
|
|
768
|
+
display: flex;
|
|
769
|
+
align-items: center;
|
|
770
|
+
background: linear-gradient(135deg, #0a0612 0%, #1a0a2e 100%);
|
|
771
|
+
}
|
|
772
|
+
|
|
773
|
+
.hero-card {
|
|
774
|
+
text-align: center;
|
|
775
|
+
max-width: 600px;
|
|
776
|
+
margin: 0 auto;
|
|
777
|
+
}
|
|
778
|
+
|
|
779
|
+
.hero h1 {
|
|
780
|
+
font-size: clamp(2rem, 5vw, 3.75rem); /* Responsive font size */
|
|
781
|
+
margin-bottom: 1rem;
|
|
782
|
+
}
|
|
783
|
+
|
|
784
|
+
.subtitle {
|
|
785
|
+
font-size: 1.25rem;
|
|
786
|
+
color: rgba(255, 255, 255, 0.8);
|
|
787
|
+
margin-bottom: 2rem;
|
|
788
|
+
}
|
|
789
|
+
|
|
790
|
+
.btn-group {
|
|
791
|
+
display: flex;
|
|
792
|
+
gap: 1rem;
|
|
793
|
+
justify-content: center;
|
|
794
|
+
flex-wrap: wrap; /* Stack on mobile */
|
|
795
|
+
}
|
|
796
|
+
</style>
|
|
797
|
+
```
|
|
798
|
+
|
|
799
|
+
### Example 2: Dashboard Grid
|
|
800
|
+
|
|
801
|
+
```html
|
|
802
|
+
<div class="dashboard">
|
|
803
|
+
<div class="grid">
|
|
804
|
+
<div class="glass-card stat-card">
|
|
805
|
+
<div class="stat-icon">📊</div>
|
|
806
|
+
<h3>US使AGE</h3>
|
|
807
|
+
<p class="stat-value">1,234</p>
|
|
808
|
+
</div>
|
|
809
|
+
|
|
810
|
+
<div class="glass-card stat-card">
|
|
811
|
+
<div class="stat-icon">👥</div>
|
|
812
|
+
<h3>US統ERS</h3>
|
|
813
|
+
<p class="stat-value">567</p>
|
|
814
|
+
</div>
|
|
815
|
+
|
|
816
|
+
<div class="glass-card stat-card">
|
|
817
|
+
<div class="stat-icon">⚡</div>
|
|
818
|
+
<h3>AC計IVE</h3>
|
|
819
|
+
<p class="stat-value">89</p>
|
|
820
|
+
</div>
|
|
821
|
+
</div>
|
|
822
|
+
</div>
|
|
823
|
+
|
|
824
|
+
<style>
|
|
825
|
+
.dashboard {
|
|
826
|
+
padding: 2rem;
|
|
827
|
+
}
|
|
828
|
+
|
|
829
|
+
.grid {
|
|
830
|
+
display: grid;
|
|
831
|
+
gap: 1.5rem;
|
|
832
|
+
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
|
|
833
|
+
}
|
|
834
|
+
|
|
835
|
+
.stat-card {
|
|
836
|
+
text-align: center;
|
|
837
|
+
padding: 2rem;
|
|
838
|
+
transition: transform 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);
|
|
839
|
+
}
|
|
840
|
+
|
|
841
|
+
.stat-card:hover {
|
|
842
|
+
transform: translateY(-4px) scale(1.02);
|
|
843
|
+
}
|
|
844
|
+
|
|
845
|
+
.stat-icon {
|
|
846
|
+
font-size: 3rem;
|
|
847
|
+
margin-bottom: 1rem;
|
|
848
|
+
}
|
|
849
|
+
|
|
850
|
+
.stat-value {
|
|
851
|
+
font-size: 2.5rem;
|
|
852
|
+
font-weight: 700;
|
|
853
|
+
color: var(--color-accent);
|
|
854
|
+
}
|
|
855
|
+
</style>
|
|
856
|
+
```
|
|
857
|
+
|
|
858
|
+
### Example 3: Form with Validation
|
|
859
|
+
|
|
860
|
+
```html
|
|
861
|
+
<form class="glass-card form">
|
|
862
|
+
<h2>Sign計 US使UP</h2>
|
|
863
|
+
|
|
864
|
+
<div class="form-group">
|
|
865
|
+
<label for="email">Email</label>
|
|
866
|
+
<input
|
|
867
|
+
type="email"
|
|
868
|
+
id="email"
|
|
869
|
+
class="input"
|
|
870
|
+
placeholder="your@email.com"
|
|
871
|
+
required
|
|
872
|
+
>
|
|
873
|
+
<span class="error-message" role="alert"></span>
|
|
874
|
+
</div>
|
|
875
|
+
|
|
876
|
+
<div class="form-group">
|
|
877
|
+
<label for="password">Password</label>
|
|
878
|
+
<input
|
|
879
|
+
type="password"
|
|
880
|
+
id="password"
|
|
881
|
+
class="input"
|
|
882
|
+
placeholder="••••••••"
|
|
883
|
+
required
|
|
884
|
+
>
|
|
885
|
+
<span class="error-message" role="alert"></span>
|
|
886
|
+
</div>
|
|
887
|
+
|
|
888
|
+
<button type="submit" class="btn btn-primary">
|
|
889
|
+
Create Account
|
|
890
|
+
</button>
|
|
891
|
+
</form>
|
|
892
|
+
|
|
893
|
+
<style>
|
|
894
|
+
.form {
|
|
895
|
+
max-width: 400px;
|
|
896
|
+
margin: 2rem auto;
|
|
897
|
+
padding: 2rem;
|
|
898
|
+
}
|
|
899
|
+
|
|
900
|
+
.form-group {
|
|
901
|
+
margin-bottom: 1.5rem;
|
|
902
|
+
}
|
|
903
|
+
|
|
904
|
+
.form-group label {
|
|
905
|
+
display: block;
|
|
906
|
+
margin-bottom: 0.5rem;
|
|
907
|
+
font-weight: 500;
|
|
908
|
+
}
|
|
909
|
+
|
|
910
|
+
.input {
|
|
911
|
+
width: 100%;
|
|
912
|
+
padding: 0.75rem;
|
|
913
|
+
background: rgba(255, 255, 255, 0.05);
|
|
914
|
+
border: 1px solid rgba(217, 79, 144, 0.3);
|
|
915
|
+
border-radius: 8px;
|
|
916
|
+
color: white;
|
|
917
|
+
font-size: 1rem;
|
|
918
|
+
transition: border-color 0.15s ease;
|
|
919
|
+
}
|
|
920
|
+
|
|
921
|
+
.input:focus {
|
|
922
|
+
outline: none;
|
|
923
|
+
border-color: rgba(217, 79, 144, 0.7);
|
|
924
|
+
}
|
|
925
|
+
|
|
926
|
+
.input.error {
|
|
927
|
+
border-color: rgba(255, 68, 68, 0.7);
|
|
928
|
+
}
|
|
929
|
+
|
|
930
|
+
.error-message {
|
|
931
|
+
display: block;
|
|
932
|
+
color: rgba(255, 68, 68, 0.9);
|
|
933
|
+
font-size: 0.875rem;
|
|
934
|
+
margin-top: 0.25rem;
|
|
935
|
+
min-height: 1.25rem; /* Prevent layout shift */
|
|
936
|
+
}
|
|
937
|
+
</style>
|
|
938
|
+
|
|
939
|
+
<script>
|
|
940
|
+
// Client-side validation
|
|
941
|
+
document.querySelector('.form').addEventListener('submit', (e) => {
|
|
942
|
+
e.preventDefault();
|
|
943
|
+
|
|
944
|
+
const email = document.getElementById('email');
|
|
945
|
+
const password = document.getElementById('password');
|
|
946
|
+
|
|
947
|
+
// Validate email
|
|
948
|
+
if (!email.value.includes('@')) {
|
|
949
|
+
email.classList.add('error');
|
|
950
|
+
email.nextElementSibling.textContent = 'Invalid email address';
|
|
951
|
+
return;
|
|
952
|
+
}
|
|
953
|
+
|
|
954
|
+
// Validate password
|
|
955
|
+
if (password.value.length < 8) {
|
|
956
|
+
password.classList.add('error');
|
|
957
|
+
password.nextElementSibling.textContent = 'Password must be 8+ characters';
|
|
958
|
+
return;
|
|
959
|
+
}
|
|
960
|
+
|
|
961
|
+
// Success - submit form
|
|
962
|
+
console.log('Form submitted');
|
|
963
|
+
});
|
|
964
|
+
</script>
|
|
965
|
+
```
|
|
966
|
+
|
|
967
|
+
---
|
|
968
|
+
|
|
969
|
+
## Common Patterns
|
|
970
|
+
|
|
971
|
+
### Loading States
|
|
972
|
+
|
|
973
|
+
```html
|
|
974
|
+
<div class="glass-card loading">
|
|
975
|
+
<div class="spinner"></div>
|
|
976
|
+
<p>Loading...</p>
|
|
977
|
+
</div>
|
|
978
|
+
|
|
979
|
+
<style>
|
|
980
|
+
.spinner {
|
|
981
|
+
width: 40px;
|
|
982
|
+
height: 40px;
|
|
983
|
+
border: 3px solid rgba(217, 79, 144, 0.2);
|
|
984
|
+
border-top-color: #d94f90;
|
|
985
|
+
border-radius: 50%;
|
|
986
|
+
animation: spin 1s linear infinite;
|
|
987
|
+
margin: 0 auto 1rem;
|
|
988
|
+
}
|
|
989
|
+
|
|
990
|
+
@keyframes spin {
|
|
991
|
+
to { transform: rotate(360deg); }
|
|
992
|
+
}
|
|
993
|
+
</style>
|
|
994
|
+
```
|
|
995
|
+
|
|
996
|
+
### Toast Notifications
|
|
997
|
+
|
|
998
|
+
```html
|
|
999
|
+
<div class="toast toast-success" role="alert">
|
|
1000
|
+
✓ Success! Data saved.
|
|
1001
|
+
</div>
|
|
1002
|
+
|
|
1003
|
+
<style>
|
|
1004
|
+
.toast {
|
|
1005
|
+
position: fixed;
|
|
1006
|
+
bottom: 2rem;
|
|
1007
|
+
right: 2rem;
|
|
1008
|
+
background: rgba(20, 12, 40, 0.95);
|
|
1009
|
+
backdrop-filter: blur(15px);
|
|
1010
|
+
border: 1px solid rgba(217, 79, 144, 0.3);
|
|
1011
|
+
border-radius: 8px;
|
|
1012
|
+
padding: 1rem 1.5rem;
|
|
1013
|
+
box-shadow: 0 4px 16px rgba(217, 79, 144, 0.25);
|
|
1014
|
+
animation: slideIn 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);
|
|
1015
|
+
}
|
|
1016
|
+
|
|
1017
|
+
@keyframes slideIn {
|
|
1018
|
+
from {
|
|
1019
|
+
transform: translateX(400px);
|
|
1020
|
+
opacity: 0;
|
|
1021
|
+
}
|
|
1022
|
+
to {
|
|
1023
|
+
transform: translateX(0);
|
|
1024
|
+
opacity: 1;
|
|
1025
|
+
}
|
|
1026
|
+
}
|
|
1027
|
+
|
|
1028
|
+
.toast-success {
|
|
1029
|
+
border-left: 4px solid #10b981; /* Green accent */
|
|
1030
|
+
}
|
|
1031
|
+
</style>
|
|
1032
|
+
```
|
|
1033
|
+
|
|
1034
|
+
### Modal Dialog
|
|
1035
|
+
|
|
1036
|
+
```html
|
|
1037
|
+
<div class="modal-backdrop">
|
|
1038
|
+
<div class="modal glass-card" role="dialog" aria-modal="true">
|
|
1039
|
+
<button class="modal-close" aria-label="Close">×</button>
|
|
1040
|
+
<h2>Dialog計 使Title</h2>
|
|
1041
|
+
<p>Modal content here</p>
|
|
1042
|
+
<div class="modal-actions">
|
|
1043
|
+
<button class="btn btn-secondary">Cancel</button>
|
|
1044
|
+
<button class="btn btn-primary">Confirm</button>
|
|
1045
|
+
</div>
|
|
1046
|
+
</div>
|
|
1047
|
+
</div>
|
|
1048
|
+
|
|
1049
|
+
<style>
|
|
1050
|
+
.modal-backdrop {
|
|
1051
|
+
position: fixed;
|
|
1052
|
+
inset: 0;
|
|
1053
|
+
background: rgba(0, 0, 0, 0.8);
|
|
1054
|
+
backdrop-filter: blur(4px);
|
|
1055
|
+
display: flex;
|
|
1056
|
+
align-items: center;
|
|
1057
|
+
justify-content: center;
|
|
1058
|
+
z-index: 1000;
|
|
1059
|
+
}
|
|
1060
|
+
|
|
1061
|
+
.modal {
|
|
1062
|
+
max-width: 500px;
|
|
1063
|
+
width: 90%;
|
|
1064
|
+
max-height: 90vh;
|
|
1065
|
+
overflow-y: auto;
|
|
1066
|
+
animation: modalEnter 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);
|
|
1067
|
+
}
|
|
1068
|
+
|
|
1069
|
+
@keyframes modalEnter {
|
|
1070
|
+
from {
|
|
1071
|
+
opacity: 0;
|
|
1072
|
+
transform: scale(0.9) translateY(-20px);
|
|
1073
|
+
}
|
|
1074
|
+
to {
|
|
1075
|
+
opacity: 1;
|
|
1076
|
+
transform: scale(1) translateY(0);
|
|
1077
|
+
}
|
|
1078
|
+
}
|
|
1079
|
+
|
|
1080
|
+
.modal-close {
|
|
1081
|
+
position: absolute;
|
|
1082
|
+
top: 1rem;
|
|
1083
|
+
right: 1rem;
|
|
1084
|
+
background: none;
|
|
1085
|
+
border: none;
|
|
1086
|
+
font-size: 2rem;
|
|
1087
|
+
color: white;
|
|
1088
|
+
cursor: pointer;
|
|
1089
|
+
}
|
|
1090
|
+
|
|
1091
|
+
.modal-actions {
|
|
1092
|
+
display: flex;
|
|
1093
|
+
gap: 1rem;
|
|
1094
|
+
justify-content: flex-end;
|
|
1095
|
+
margin-top: 2rem;
|
|
1096
|
+
}
|
|
1097
|
+
</style>
|
|
1098
|
+
```
|
|
1099
|
+
|
|
1100
|
+
---
|
|
1101
|
+
|
|
1102
|
+
## Troubleshooting
|
|
1103
|
+
|
|
1104
|
+
### Issue: Backdrop-filter Not Working
|
|
1105
|
+
|
|
1106
|
+
**Symptoms**: Glass effect appears solid instead of translucent blur
|
|
1107
|
+
|
|
1108
|
+
**Causes**:
|
|
1109
|
+
1. Browser doesn't support backdrop-filter
|
|
1110
|
+
2. Missing `-webkit-` prefix for Safari
|
|
1111
|
+
3. Element has no positioned parent
|
|
1112
|
+
|
|
1113
|
+
**Solutions**:
|
|
1114
|
+
```css
|
|
1115
|
+
/* Add vendor prefix */
|
|
1116
|
+
.glass-card {
|
|
1117
|
+
backdrop-filter: blur(15px);
|
|
1118
|
+
-webkit-backdrop-filter: blur(15px); /* Safari */
|
|
1119
|
+
}
|
|
1120
|
+
|
|
1121
|
+
/* Ensure parent creates stacking context */
|
|
1122
|
+
.parent {
|
|
1123
|
+
position: relative;
|
|
1124
|
+
z-index: 0;
|
|
1125
|
+
}
|
|
1126
|
+
|
|
1127
|
+
/* Fallback for unsupported browsers */
|
|
1128
|
+
@supports not (backdrop-filter: blur(15px)) {
|
|
1129
|
+
.glass-card {
|
|
1130
|
+
background: rgba(20, 12, 40, 0.95); /* More opaque */
|
|
1131
|
+
}
|
|
1132
|
+
}
|
|
1133
|
+
```
|
|
1134
|
+
|
|
1135
|
+
### Issue: Animations Janky on Mobile
|
|
1136
|
+
|
|
1137
|
+
**Symptoms**: Scrolling/animations drop frames on mobile devices
|
|
1138
|
+
|
|
1139
|
+
**Solutions**:
|
|
1140
|
+
```css
|
|
1141
|
+
/* Disable expensive effects on mobile */
|
|
1142
|
+
@media (max-width: 640px) {
|
|
1143
|
+
.glass-card {
|
|
1144
|
+
backdrop-filter: none;
|
|
1145
|
+
background: rgba(20, 12, 40, 0.95);
|
|
1146
|
+
}
|
|
1147
|
+
|
|
1148
|
+
/* Simplify animations */
|
|
1149
|
+
* {
|
|
1150
|
+
animation-duration: 0.15s !important;
|
|
1151
|
+
}
|
|
1152
|
+
}
|
|
1153
|
+
|
|
1154
|
+
/* Use GPU acceleration */
|
|
1155
|
+
.animated-element {
|
|
1156
|
+
will-change: transform;
|
|
1157
|
+
transform: translateZ(0); /* Force GPU layer */
|
|
1158
|
+
}
|
|
1159
|
+
```
|
|
1160
|
+
|
|
1161
|
+
### Issue: Text Corruption Not Visible
|
|
1162
|
+
|
|
1163
|
+
**Symptoms**: Japanese characters not rendering or showing boxes
|
|
1164
|
+
|
|
1165
|
+
**Causes**:
|
|
1166
|
+
1. Font doesn't support Japanese characters
|
|
1167
|
+
2. Character encoding incorrect
|
|
1168
|
+
|
|
1169
|
+
**Solutions**:
|
|
1170
|
+
```html
|
|
1171
|
+
<!-- Ensure UTF-8 encoding -->
|
|
1172
|
+
<meta charset="UTF-8">
|
|
1173
|
+
|
|
1174
|
+
<!-- Use system fonts with Japanese support -->
|
|
1175
|
+
<style>
|
|
1176
|
+
body {
|
|
1177
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI',
|
|
1178
|
+
'Hiragino Sans', 'Yu Gothic', sans-serif;
|
|
1179
|
+
}
|
|
1180
|
+
</style>
|
|
1181
|
+
```
|
|
1182
|
+
|
|
1183
|
+
### Issue: CSS Custom Properties Not Working
|
|
1184
|
+
|
|
1185
|
+
**Symptoms**: Styles not applying, colors are wrong
|
|
1186
|
+
|
|
1187
|
+
**Causes**:
|
|
1188
|
+
1. Variables.css not imported first
|
|
1189
|
+
2. Typo in variable name
|
|
1190
|
+
|
|
1191
|
+
**Solutions**:
|
|
1192
|
+
```html
|
|
1193
|
+
<!-- MUST import variables FIRST -->
|
|
1194
|
+
<link rel="stylesheet" href="css/variables.css">
|
|
1195
|
+
<link rel="stylesheet" href="css/components.css">
|
|
1196
|
+
```
|
|
1197
|
+
|
|
1198
|
+
```css
|
|
1199
|
+
/* Check variable name spelling */
|
|
1200
|
+
.btn {
|
|
1201
|
+
background: var(--color-accent); /* Correct */
|
|
1202
|
+
/* background: var(--accent-color); ← Wrong variable name */
|
|
1203
|
+
}
|
|
1204
|
+
```
|
|
1205
|
+
|
|
1206
|
+
---
|
|
1207
|
+
|
|
1208
|
+
## Related Documentation
|
|
1209
|
+
|
|
1210
|
+
- [NPM_PACKAGE.md](./NPM_PACKAGE.md) - Package installation and configuration
|
|
1211
|
+
- [COMPONENT_MAPPING.md](./COMPONENT_MAPPING.md) - Web ↔ CLI component equivalents
|
|
1212
|
+
- [COMPONENT_LIBRARY.md](../components/COMPONENT_LIBRARY.md) - All available components
|
|
1213
|
+
- [ANIMATION_GUIDELINES.md](../components/ANIMATION_GUIDELINES.md) - Animation specifications
|
|
1214
|
+
- [ACCESSIBILITY.md](../standards/ACCESSIBILITY.md) - Full accessibility standards
|
|
1215
|
+
|
|
1216
|
+
---
|
|
1217
|
+
|
|
1218
|
+
**Last Updated**: 2025-12-13
|
|
1219
|
+
**Version**: 1.0.0
|
|
1220
|
+
**Maintainer**: Celeste Brand System
|
|
1221
|
+
**Status**: ✅ Ready for Production
|