@nextsparkjs/ai-workflow 0.1.0-beta.100
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/LICENSE +21 -0
- package/README.md +115 -0
- package/claude/_docs/workflows-optimizations.md +359 -0
- package/claude/agents/api-tester.md +634 -0
- package/claude/agents/architecture-supervisor.md +1351 -0
- package/claude/agents/backend-developer.md +997 -0
- package/claude/agents/backend-validator.md +417 -0
- package/claude/agents/bdd-docs-writer.md +737 -0
- package/claude/agents/block-developer.md +677 -0
- package/claude/agents/code-reviewer.md +1432 -0
- package/claude/agents/db-developer.md +721 -0
- package/claude/agents/db-validator.md +407 -0
- package/claude/agents/demo-video-generator.md +493 -0
- package/claude/agents/documentation-writer.md +1268 -0
- package/claude/agents/frontend-developer.md +1234 -0
- package/claude/agents/frontend-validator.md +777 -0
- package/claude/agents/functional-validator.md +630 -0
- package/claude/agents/mock-analyst.md +387 -0
- package/claude/agents/product-manager.md +963 -0
- package/claude/agents/qa-automation.md +1762 -0
- package/claude/agents/release-manager.md +634 -0
- package/claude/agents/selectors-translator.md +262 -0
- package/claude/agents/unit-test-writer.md +785 -0
- package/claude/agents/visual-comparator.md +329 -0
- package/claude/agents/workflow-maintainer.md +352 -0
- package/claude/commands/do/README.md +88 -0
- package/claude/commands/do/create-api.md +64 -0
- package/claude/commands/do/create-entity.md +66 -0
- package/claude/commands/do/create-migration.md +64 -0
- package/claude/commands/do/create-plugin.md +56 -0
- package/claude/commands/do/create-theme.md +70 -0
- package/claude/commands/do/mock-data.md +67 -0
- package/claude/commands/do/reset-db.md +71 -0
- package/claude/commands/do/setup-scheduled-action.md +75 -0
- package/claude/commands/do/sync-code-review.md +117 -0
- package/claude/commands/do/update-selectors.md +112 -0
- package/claude/commands/do/use-skills.md +90 -0
- package/claude/commands/do/validate-blocks.md +69 -0
- package/claude/commands/how-to/README.md +261 -0
- package/claude/commands/how-to/add-metadata.md +692 -0
- package/claude/commands/how-to/add-taxonomies.md +806 -0
- package/claude/commands/how-to/add-translations.md +571 -0
- package/claude/commands/how-to/create-api.md +577 -0
- package/claude/commands/how-to/create-block.md +575 -0
- package/claude/commands/how-to/create-child-entities.md +771 -0
- package/claude/commands/how-to/create-entity.md +597 -0
- package/claude/commands/how-to/create-migrations.md +605 -0
- package/claude/commands/how-to/create-plugin.md +654 -0
- package/claude/commands/how-to/customize-app.md +481 -0
- package/claude/commands/how-to/customize-dashboard.md +553 -0
- package/claude/commands/how-to/customize-theme.md +438 -0
- package/claude/commands/how-to/define-features-flows.md +632 -0
- package/claude/commands/how-to/deploy.md +507 -0
- package/claude/commands/how-to/handle-file-uploads.md +746 -0
- package/claude/commands/how-to/implement-search.md +1001 -0
- package/claude/commands/how-to/install-plugins.md +352 -0
- package/claude/commands/how-to/manage-test-coverage.md +984 -0
- package/claude/commands/how-to/run-tests.md +400 -0
- package/claude/commands/how-to/set-app-languages.md +601 -0
- package/claude/commands/how-to/set-plans-and-permissions.md +575 -0
- package/claude/commands/how-to/set-scheduled-actions.md +527 -0
- package/claude/commands/how-to/set-user-roles-and-permissions.md +550 -0
- package/claude/commands/how-to/setup-authentication.md +388 -0
- package/claude/commands/how-to/setup-claude-code.md +440 -0
- package/claude/commands/how-to/setup-database.md +274 -0
- package/claude/commands/how-to/setup-email-providers.md +598 -0
- package/claude/commands/how-to/setup-mobile-dev.md +627 -0
- package/claude/commands/how-to/start.md +500 -0
- package/claude/commands/how-to/use-devtools.md +639 -0
- package/claude/commands/how-to/use-superadmin.md +622 -0
- package/claude/commands/session/README.md +193 -0
- package/claude/commands/session/block-create.md +190 -0
- package/claude/commands/session/block-list.md +203 -0
- package/claude/commands/session/block-update.md +192 -0
- package/claude/commands/session/block-validate.md +218 -0
- package/claude/commands/session/changelog.md +115 -0
- package/claude/commands/session/close.md +225 -0
- package/claude/commands/session/commit.md +174 -0
- package/claude/commands/session/db-entity.md +206 -0
- package/claude/commands/session/db-fix.md +212 -0
- package/claude/commands/session/db-sample.md +206 -0
- package/claude/commands/session/demo.md +178 -0
- package/claude/commands/session/doc-bdd.md +207 -0
- package/claude/commands/session/doc-feature.md +218 -0
- package/claude/commands/session/doc-read.md +225 -0
- package/claude/commands/session/execute.md +204 -0
- package/claude/commands/session/explain.md +202 -0
- package/claude/commands/session/fix-bug.md +210 -0
- package/claude/commands/session/fix-build.md +182 -0
- package/claude/commands/session/fix-test.md +189 -0
- package/claude/commands/session/pending.md +232 -0
- package/claude/commands/session/refine.md +188 -0
- package/claude/commands/session/resume.md +192 -0
- package/claude/commands/session/review.md +192 -0
- package/claude/commands/session/scope-change.md +181 -0
- package/claude/commands/session/start-blocks.md +347 -0
- package/claude/commands/session/start.md +604 -0
- package/claude/commands/session/status.md +169 -0
- package/claude/commands/session/test-fix.md +221 -0
- package/claude/commands/session/test-run.md +203 -0
- package/claude/commands/session/test-write.md +242 -0
- package/claude/commands/session/validate.md +162 -0
- package/claude/config/context.json +40 -0
- package/claude/config/github.json +69 -0
- package/claude/config/github.schema.json +106 -0
- package/claude/config/team.json +46 -0
- package/claude/config/team.schema.json +106 -0
- package/claude/config/workspace.json +43 -0
- package/claude/config/workspace.schema.json +75 -0
- package/claude/skills/README.md +228 -0
- package/claude/skills/accessibility/SKILL.md +573 -0
- package/claude/skills/api-bypass-layers/SKILL.md +550 -0
- package/claude/skills/asana-integration/SKILL.md +499 -0
- package/claude/skills/better-auth/SKILL.md +666 -0
- package/claude/skills/billing-subscriptions/SKILL.md +660 -0
- package/claude/skills/block-decision-matrix/SKILL.md +359 -0
- package/claude/skills/clickup-integration/SKILL.md +434 -0
- package/claude/skills/core-theme-responsibilities/SKILL.md +485 -0
- package/claude/skills/create-plugin/SKILL.md +425 -0
- package/claude/skills/create-theme/SKILL.md +331 -0
- package/claude/skills/cypress-api/SKILL.md +511 -0
- package/claude/skills/cypress-api/scripts/generate-api-controller.py +329 -0
- package/claude/skills/cypress-api/scripts/generate-api-test.py +930 -0
- package/claude/skills/cypress-e2e/SKILL.md +526 -0
- package/claude/skills/cypress-e2e/scripts/extract-selectors.py +383 -0
- package/claude/skills/cypress-e2e/scripts/generate-uat-test.py +788 -0
- package/claude/skills/cypress-selectors/SKILL.md +309 -0
- package/claude/skills/cypress-selectors/scripts/extract-missing.py +243 -0
- package/claude/skills/cypress-selectors/scripts/generate-block-selectors.py +283 -0
- package/claude/skills/cypress-selectors/scripts/validate-selectors.py +145 -0
- package/claude/skills/database-migrations/SKILL.md +335 -0
- package/claude/skills/database-migrations/scripts/generate-sample-data.py +284 -0
- package/claude/skills/database-migrations/scripts/validate-migration.py +323 -0
- package/claude/skills/design-system/SKILL.md +682 -0
- package/claude/skills/documentation/SKILL.md +540 -0
- package/claude/skills/entity-api/SKILL.md +482 -0
- package/claude/skills/entity-system/SKILL.md +635 -0
- package/claude/skills/entity-system/scripts/generate-child-migration.py +298 -0
- package/claude/skills/entity-system/scripts/generate-metas-migration.py +233 -0
- package/claude/skills/entity-system/scripts/generate-migration.py +382 -0
- package/claude/skills/entity-system/scripts/generate-sample-data.py +418 -0
- package/claude/skills/entity-system/scripts/scaffold-entity.py +661 -0
- package/claude/skills/github/SKILL.md +467 -0
- package/claude/skills/i18n-nextintl/SKILL.md +302 -0
- package/claude/skills/i18n-nextintl/scripts/add-translation.py +243 -0
- package/claude/skills/i18n-nextintl/scripts/extract-hardcoded.py +246 -0
- package/claude/skills/i18n-nextintl/scripts/validate-translations.py +260 -0
- package/claude/skills/impact-analysis/SKILL.md +203 -0
- package/claude/skills/jest-unit/SKILL.md +306 -0
- package/claude/skills/jest-unit/references/component-testing.md +371 -0
- package/claude/skills/jest-unit/references/mocking-patterns.md +380 -0
- package/claude/skills/jest-unit/references/service-hook-testing.md +454 -0
- package/claude/skills/jira-integration/SKILL.md +539 -0
- package/claude/skills/media-library/SKILL.md +743 -0
- package/claude/skills/mock-analysis/SKILL.md +276 -0
- package/claude/skills/monorepo-architecture/SKILL.md +162 -0
- package/claude/skills/nextjs-api-development/SKILL.md +364 -0
- package/claude/skills/nextjs-api-development/scripts/generate-crud-tests.py +456 -0
- package/claude/skills/nextjs-api-development/scripts/scaffold-endpoint.py +481 -0
- package/claude/skills/nextjs-api-development/scripts/validate-api.py +283 -0
- package/claude/skills/notion-integration/SKILL.md +641 -0
- package/claude/skills/npm-development-workflow/SKILL.md +480 -0
- package/claude/skills/page-builder-blocks/SKILL.md +530 -0
- package/claude/skills/page-builder-blocks/scripts/scaffold-block.py +444 -0
- package/claude/skills/permissions-system/SKILL.md +619 -0
- package/claude/skills/plugins/SKILL.md +340 -0
- package/claude/skills/plugins/references/plugin-templates.md +414 -0
- package/claude/skills/plugins/references/plugin-testing.md +353 -0
- package/claude/skills/plugins/references/plugin-types.md +198 -0
- package/claude/skills/plugins/scripts/scaffold-plugin.py +443 -0
- package/claude/skills/pom-patterns/SKILL.md +452 -0
- package/claude/skills/pom-patterns/scripts/generate-pom.py +392 -0
- package/claude/skills/rate-limiting/SKILL.md +342 -0
- package/claude/skills/react-best-practices/AGENTS.md +2410 -0
- package/claude/skills/react-best-practices/README.md +123 -0
- package/claude/skills/react-best-practices/SKILL.md +125 -0
- package/claude/skills/react-best-practices/metadata.json +15 -0
- package/claude/skills/react-best-practices/rules/_sections.md +46 -0
- package/claude/skills/react-best-practices/rules/_template.md +28 -0
- package/claude/skills/react-best-practices/rules/advanced-event-handler-refs.md +55 -0
- package/claude/skills/react-best-practices/rules/advanced-use-latest.md +49 -0
- package/claude/skills/react-best-practices/rules/async-api-routes.md +38 -0
- package/claude/skills/react-best-practices/rules/async-defer-await.md +80 -0
- package/claude/skills/react-best-practices/rules/async-dependencies.md +36 -0
- package/claude/skills/react-best-practices/rules/async-parallel.md +28 -0
- package/claude/skills/react-best-practices/rules/async-suspense-boundaries.md +99 -0
- package/claude/skills/react-best-practices/rules/bundle-barrel-imports.md +59 -0
- package/claude/skills/react-best-practices/rules/bundle-conditional.md +31 -0
- package/claude/skills/react-best-practices/rules/bundle-defer-third-party.md +49 -0
- package/claude/skills/react-best-practices/rules/bundle-dynamic-imports.md +35 -0
- package/claude/skills/react-best-practices/rules/bundle-preload.md +50 -0
- package/claude/skills/react-best-practices/rules/client-event-listeners.md +74 -0
- package/claude/skills/react-best-practices/rules/client-localstorage-schema.md +71 -0
- package/claude/skills/react-best-practices/rules/client-passive-event-listeners.md +48 -0
- package/claude/skills/react-best-practices/rules/client-swr-dedup.md +56 -0
- package/claude/skills/react-best-practices/rules/js-batch-dom-css.md +82 -0
- package/claude/skills/react-best-practices/rules/js-cache-function-results.md +80 -0
- package/claude/skills/react-best-practices/rules/js-cache-property-access.md +28 -0
- package/claude/skills/react-best-practices/rules/js-cache-storage.md +70 -0
- package/claude/skills/react-best-practices/rules/js-combine-iterations.md +32 -0
- package/claude/skills/react-best-practices/rules/js-early-exit.md +50 -0
- package/claude/skills/react-best-practices/rules/js-hoist-regexp.md +45 -0
- package/claude/skills/react-best-practices/rules/js-index-maps.md +37 -0
- package/claude/skills/react-best-practices/rules/js-length-check-first.md +49 -0
- package/claude/skills/react-best-practices/rules/js-min-max-loop.md +82 -0
- package/claude/skills/react-best-practices/rules/js-set-map-lookups.md +24 -0
- package/claude/skills/react-best-practices/rules/js-tosorted-immutable.md +57 -0
- package/claude/skills/react-best-practices/rules/rendering-activity.md +26 -0
- package/claude/skills/react-best-practices/rules/rendering-animate-svg-wrapper.md +47 -0
- package/claude/skills/react-best-practices/rules/rendering-conditional-render.md +40 -0
- package/claude/skills/react-best-practices/rules/rendering-content-visibility.md +38 -0
- package/claude/skills/react-best-practices/rules/rendering-hoist-jsx.md +46 -0
- package/claude/skills/react-best-practices/rules/rendering-hydration-no-flicker.md +82 -0
- package/claude/skills/react-best-practices/rules/rendering-svg-precision.md +28 -0
- package/claude/skills/react-best-practices/rules/rerender-defer-reads.md +39 -0
- package/claude/skills/react-best-practices/rules/rerender-dependencies.md +45 -0
- package/claude/skills/react-best-practices/rules/rerender-derived-state.md +29 -0
- package/claude/skills/react-best-practices/rules/rerender-functional-setstate.md +74 -0
- package/claude/skills/react-best-practices/rules/rerender-lazy-state-init.md +58 -0
- package/claude/skills/react-best-practices/rules/rerender-memo.md +44 -0
- package/claude/skills/react-best-practices/rules/rerender-transitions.md +40 -0
- package/claude/skills/react-best-practices/rules/server-after-nonblocking.md +73 -0
- package/claude/skills/react-best-practices/rules/server-cache-lru.md +41 -0
- package/claude/skills/react-best-practices/rules/server-cache-react.md +76 -0
- package/claude/skills/react-best-practices/rules/server-parallel-fetching.md +83 -0
- package/claude/skills/react-best-practices/rules/server-serialization.md +38 -0
- package/claude/skills/react-patterns/SKILL.md +688 -0
- package/claude/skills/registry-system/SKILL.md +331 -0
- package/claude/skills/scheduled-actions/SKILL.md +671 -0
- package/claude/skills/scope-enforcement/SKILL.md +542 -0
- package/claude/skills/scope-enforcement/scripts/validate-scope.py +357 -0
- package/claude/skills/server-actions/SKILL.md +493 -0
- package/claude/skills/service-layer/SKILL.md +587 -0
- package/claude/skills/session-management/SKILL.md +266 -0
- package/claude/skills/session-management/scripts/create-session.py +166 -0
- package/claude/skills/session-management/scripts/iteration-close.sh +105 -0
- package/claude/skills/session-management/scripts/iteration-init.sh +180 -0
- package/claude/skills/session-management/scripts/session-archive.sh +87 -0
- package/claude/skills/session-management/scripts/session-close.sh +133 -0
- package/claude/skills/session-management/scripts/session-init.sh +225 -0
- package/claude/skills/session-management/scripts/session-list.sh +163 -0
- package/claude/skills/session-management/scripts/split-plan.sh +116 -0
- package/claude/skills/shadcn-components/SKILL.md +586 -0
- package/claude/skills/shadcn-theming/SKILL.md +446 -0
- package/claude/skills/suspense-loading/SKILL.md +280 -0
- package/claude/skills/tailwind-theming/SKILL.md +507 -0
- package/claude/skills/tanstack-query/SKILL.md +608 -0
- package/claude/skills/test-coverage/SKILL.md +239 -0
- package/claude/skills/web-design-guidelines/SKILL.md +39 -0
- package/claude/skills/zod-validation/SKILL.md +537 -0
- package/claude/templates/blocks/progress.md +86 -0
- package/claude/templates/iteration/changes.md +61 -0
- package/claude/templates/iteration/progress.md +55 -0
- package/claude/templates/log.md +31 -0
- package/claude/templates/story/context.md +77 -0
- package/claude/templates/story/pendings.md +37 -0
- package/claude/templates/story/plan.md +299 -0
- package/claude/templates/story/requirements.md +109 -0
- package/claude/templates/story/scope.json +10 -0
- package/claude/templates/story/tests.md +91 -0
- package/claude/templates/task/progress.md +58 -0
- package/claude/templates/task/requirements.md +54 -0
- package/claude/workflows/README.md +154 -0
- package/claude/workflows/blocks.md +614 -0
- package/claude/workflows/story.md +1207 -0
- package/claude/workflows/task.md +927 -0
- package/claude/workflows/tweak.md +527 -0
- package/cursor/.gitkeep +0 -0
- package/package.json +35 -0
- package/scripts/postinstall.mjs +198 -0
- package/scripts/setup.mjs +282 -0
- package/scripts/sync.mjs +209 -0
|
@@ -0,0 +1,446 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: shadcn-theming
|
|
3
|
+
description: |
|
|
4
|
+
shadcn/ui theme customization for NextSpark applications.
|
|
5
|
+
Covers tweakcn.com integration, CSS variable format, color space conversion, and theme initialization.
|
|
6
|
+
Use this skill when initializing or customizing the design system for a theme.
|
|
7
|
+
allowed-tools: Read, Glob, Grep, Bash
|
|
8
|
+
version: 1.0.0
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# shadcn Theming Skill
|
|
12
|
+
|
|
13
|
+
Patterns for customizing shadcn/ui themes in NextSpark using CSS variables and the tweakcn.com editor.
|
|
14
|
+
|
|
15
|
+
## Fundamental Principle
|
|
16
|
+
|
|
17
|
+
**THE THEME IS THE SINGLE SOURCE OF TRUTH FOR DESIGN TOKENS.**
|
|
18
|
+
|
|
19
|
+
All visual customization happens in the theme's `globals.css`. No inline colors, no hardcoded values.
|
|
20
|
+
|
|
21
|
+
```
|
|
22
|
+
themes/{THEME}/styles/globals.css → BUILD → core/theme-styles.css → App
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## When to Use This Skill
|
|
26
|
+
|
|
27
|
+
- **Initializing a new project's design system**
|
|
28
|
+
- **Customizing colors for a client project**
|
|
29
|
+
- **Converting design system from mock to theme**
|
|
30
|
+
- **Understanding the theme build process**
|
|
31
|
+
|
|
32
|
+
## Architecture Overview
|
|
33
|
+
|
|
34
|
+
```
|
|
35
|
+
THEME CSS STRUCTURE:
|
|
36
|
+
|
|
37
|
+
themes/{THEME}/styles/
|
|
38
|
+
├── globals.css # CSS variables (THE DESIGN SYSTEM)
|
|
39
|
+
│ ├── :root # Light mode tokens
|
|
40
|
+
│ ├── .dark # Dark mode tokens
|
|
41
|
+
│ └── @theme inline # Tailwind v4 mappings
|
|
42
|
+
│
|
|
43
|
+
└── components.css # Component-specific styles (optional)
|
|
44
|
+
|
|
45
|
+
BUILD OUTPUT:
|
|
46
|
+
└── core/theme-styles.css # Auto-generated (DO NOT EDIT)
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## Using tweakcn.com
|
|
50
|
+
|
|
51
|
+
### Step 1: Access the Editor
|
|
52
|
+
|
|
53
|
+
Navigate to: **https://tweakcn.com/editor/theme**
|
|
54
|
+
|
|
55
|
+
The editor provides:
|
|
56
|
+
- Visual color picker with OKLCH support
|
|
57
|
+
- Light/Dark mode preview
|
|
58
|
+
- Real-time component preview
|
|
59
|
+
- Export in CSS format
|
|
60
|
+
|
|
61
|
+
### Step 2: Customize Your Theme
|
|
62
|
+
|
|
63
|
+
1. **Base Colors:**
|
|
64
|
+
- Background/Foreground
|
|
65
|
+
- Primary/Secondary
|
|
66
|
+
- Accent/Muted
|
|
67
|
+
- Destructive
|
|
68
|
+
|
|
69
|
+
2. **Component Colors:**
|
|
70
|
+
- Card surfaces
|
|
71
|
+
- Popover/Dropdown
|
|
72
|
+
- Sidebar (if using dashboard)
|
|
73
|
+
|
|
74
|
+
3. **Design Tokens:**
|
|
75
|
+
- Border radius
|
|
76
|
+
- Shadows
|
|
77
|
+
- Typography (font families)
|
|
78
|
+
|
|
79
|
+
### Step 3: Export CSS
|
|
80
|
+
|
|
81
|
+
Click "Copy CSS" or "Export" to get:
|
|
82
|
+
|
|
83
|
+
```css
|
|
84
|
+
:root {
|
|
85
|
+
--background: oklch(1 0 0);
|
|
86
|
+
--foreground: oklch(0.145 0 0);
|
|
87
|
+
--primary: oklch(0.55 0.2 250);
|
|
88
|
+
--primary-foreground: oklch(0.985 0 0);
|
|
89
|
+
/* ... all variables */
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
.dark {
|
|
93
|
+
--background: oklch(0.145 0 0);
|
|
94
|
+
--foreground: oklch(0.985 0 0);
|
|
95
|
+
/* ... dark mode overrides */
|
|
96
|
+
}
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
## CSS Variable Reference
|
|
100
|
+
|
|
101
|
+
### Required Variables (All Must Be Defined)
|
|
102
|
+
|
|
103
|
+
```css
|
|
104
|
+
:root {
|
|
105
|
+
/* === SURFACE COLORS === */
|
|
106
|
+
--background: oklch(L C H); /* Page background */
|
|
107
|
+
--foreground: oklch(L C H); /* Primary text */
|
|
108
|
+
--card: oklch(L C H); /* Card surfaces */
|
|
109
|
+
--card-foreground: oklch(L C H); /* Card text */
|
|
110
|
+
--popover: oklch(L C H); /* Dropdown/popover bg */
|
|
111
|
+
--popover-foreground: oklch(L C H);
|
|
112
|
+
|
|
113
|
+
/* === INTERACTIVE COLORS === */
|
|
114
|
+
--primary: oklch(L C H); /* Primary buttons, links */
|
|
115
|
+
--primary-foreground: oklch(L C H); /* Text on primary */
|
|
116
|
+
--secondary: oklch(L C H); /* Secondary buttons */
|
|
117
|
+
--secondary-foreground: oklch(L C H);
|
|
118
|
+
--accent: oklch(L C H); /* Hover highlights */
|
|
119
|
+
--accent-foreground: oklch(L C H);
|
|
120
|
+
|
|
121
|
+
/* === STATE COLORS === */
|
|
122
|
+
--muted: oklch(L C H); /* Muted backgrounds */
|
|
123
|
+
--muted-foreground: oklch(L C H); /* Placeholder text */
|
|
124
|
+
--destructive: oklch(L C H); /* Error/danger */
|
|
125
|
+
--destructive-foreground: oklch(L C H);
|
|
126
|
+
|
|
127
|
+
/* === BORDER & INPUT === */
|
|
128
|
+
--border: oklch(L C H); /* Border color */
|
|
129
|
+
--input: oklch(L C H); /* Input border */
|
|
130
|
+
--ring: oklch(L C H); /* Focus ring */
|
|
131
|
+
|
|
132
|
+
/* === CHART COLORS === */
|
|
133
|
+
--chart-1: oklch(L C H);
|
|
134
|
+
--chart-2: oklch(L C H);
|
|
135
|
+
--chart-3: oklch(L C H);
|
|
136
|
+
--chart-4: oklch(L C H);
|
|
137
|
+
--chart-5: oklch(L C H);
|
|
138
|
+
|
|
139
|
+
/* === SIDEBAR (if dashboard) === */
|
|
140
|
+
--sidebar: oklch(L C H);
|
|
141
|
+
--sidebar-foreground: oklch(L C H);
|
|
142
|
+
--sidebar-primary: oklch(L C H);
|
|
143
|
+
--sidebar-primary-foreground: oklch(L C H);
|
|
144
|
+
--sidebar-accent: oklch(L C H);
|
|
145
|
+
--sidebar-accent-foreground: oklch(L C H);
|
|
146
|
+
--sidebar-border: oklch(L C H);
|
|
147
|
+
--sidebar-ring: oklch(L C H);
|
|
148
|
+
|
|
149
|
+
/* === TYPOGRAPHY === */
|
|
150
|
+
--font-sans: ui-sans-serif, system-ui, ...;
|
|
151
|
+
--font-serif: ui-serif, Georgia, ...;
|
|
152
|
+
--font-mono: ui-monospace, SFMono-Regular, ...;
|
|
153
|
+
|
|
154
|
+
/* === DESIGN TOKENS === */
|
|
155
|
+
--radius: 0.625rem; /* Base border radius */
|
|
156
|
+
--spacing: 0.25rem; /* Base spacing unit */
|
|
157
|
+
|
|
158
|
+
/* === SHADOWS === */
|
|
159
|
+
--shadow-2xs: ...;
|
|
160
|
+
--shadow-xs: ...;
|
|
161
|
+
--shadow-sm: ...;
|
|
162
|
+
--shadow: ...;
|
|
163
|
+
--shadow-md: ...;
|
|
164
|
+
--shadow-lg: ...;
|
|
165
|
+
--shadow-xl: ...;
|
|
166
|
+
--shadow-2xl: ...;
|
|
167
|
+
}
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
### Dark Mode Override
|
|
171
|
+
|
|
172
|
+
```css
|
|
173
|
+
.dark {
|
|
174
|
+
/* Only override colors that change in dark mode */
|
|
175
|
+
/* Typically invert backgrounds/foregrounds */
|
|
176
|
+
|
|
177
|
+
--background: oklch(0.145 0 0); /* Dark bg */
|
|
178
|
+
--foreground: oklch(0.985 0 0); /* Light text */
|
|
179
|
+
|
|
180
|
+
--card: oklch(0.205 0 0); /* Slightly lighter */
|
|
181
|
+
--card-foreground: oklch(0.985 0 0);
|
|
182
|
+
|
|
183
|
+
--primary: oklch(0.922 0 0); /* Often lighter in dark mode */
|
|
184
|
+
--primary-foreground: oklch(0.205 0 0);
|
|
185
|
+
|
|
186
|
+
--muted: oklch(0.269 0 0);
|
|
187
|
+
--muted-foreground: oklch(0.708 0 0);
|
|
188
|
+
|
|
189
|
+
--border: oklch(0.275 0 0);
|
|
190
|
+
--input: oklch(0.325 0 0);
|
|
191
|
+
|
|
192
|
+
/* Destructive typically stays similar hue but adjusted */
|
|
193
|
+
--destructive: oklch(0.704 0.191 22);
|
|
194
|
+
|
|
195
|
+
/* Chart colors usually stay the same */
|
|
196
|
+
}
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
### Tailwind v4 Theme Mapping
|
|
200
|
+
|
|
201
|
+
**REQUIRED:** Map CSS variables to Tailwind for class-based styling.
|
|
202
|
+
|
|
203
|
+
```css
|
|
204
|
+
@theme inline {
|
|
205
|
+
/* Colors */
|
|
206
|
+
--color-background: var(--background);
|
|
207
|
+
--color-foreground: var(--foreground);
|
|
208
|
+
--color-card: var(--card);
|
|
209
|
+
--color-card-foreground: var(--card-foreground);
|
|
210
|
+
--color-popover: var(--popover);
|
|
211
|
+
--color-popover-foreground: var(--popover-foreground);
|
|
212
|
+
--color-primary: var(--primary);
|
|
213
|
+
--color-primary-foreground: var(--primary-foreground);
|
|
214
|
+
--color-secondary: var(--secondary);
|
|
215
|
+
--color-secondary-foreground: var(--secondary-foreground);
|
|
216
|
+
--color-muted: var(--muted);
|
|
217
|
+
--color-muted-foreground: var(--muted-foreground);
|
|
218
|
+
--color-accent: var(--accent);
|
|
219
|
+
--color-accent-foreground: var(--accent-foreground);
|
|
220
|
+
--color-destructive: var(--destructive);
|
|
221
|
+
--color-destructive-foreground: var(--destructive-foreground);
|
|
222
|
+
--color-border: var(--border);
|
|
223
|
+
--color-input: var(--input);
|
|
224
|
+
--color-ring: var(--ring);
|
|
225
|
+
--color-chart-1: var(--chart-1);
|
|
226
|
+
--color-chart-2: var(--chart-2);
|
|
227
|
+
--color-chart-3: var(--chart-3);
|
|
228
|
+
--color-chart-4: var(--chart-4);
|
|
229
|
+
--color-chart-5: var(--chart-5);
|
|
230
|
+
--color-sidebar: var(--sidebar);
|
|
231
|
+
--color-sidebar-foreground: var(--sidebar-foreground);
|
|
232
|
+
--color-sidebar-primary: var(--sidebar-primary);
|
|
233
|
+
--color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
|
|
234
|
+
--color-sidebar-accent: var(--sidebar-accent);
|
|
235
|
+
--color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
|
|
236
|
+
--color-sidebar-border: var(--sidebar-border);
|
|
237
|
+
--color-sidebar-ring: var(--sidebar-ring);
|
|
238
|
+
|
|
239
|
+
/* Typography */
|
|
240
|
+
--font-sans: var(--font-sans);
|
|
241
|
+
--font-mono: var(--font-mono);
|
|
242
|
+
--font-serif: var(--font-serif);
|
|
243
|
+
|
|
244
|
+
/* Radius */
|
|
245
|
+
--radius-sm: calc(var(--radius) - 4px);
|
|
246
|
+
--radius-md: calc(var(--radius) - 2px);
|
|
247
|
+
--radius-lg: var(--radius);
|
|
248
|
+
--radius-xl: calc(var(--radius) + 4px);
|
|
249
|
+
|
|
250
|
+
/* Shadows */
|
|
251
|
+
--shadow-2xs: var(--shadow-2xs);
|
|
252
|
+
--shadow-xs: var(--shadow-xs);
|
|
253
|
+
--shadow-sm: var(--shadow-sm);
|
|
254
|
+
--shadow: var(--shadow);
|
|
255
|
+
--shadow-md: var(--shadow-md);
|
|
256
|
+
--shadow-lg: var(--shadow-lg);
|
|
257
|
+
--shadow-xl: var(--shadow-xl);
|
|
258
|
+
--shadow-2xl: var(--shadow-2xl);
|
|
259
|
+
}
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
## Color Space: OKLCH
|
|
263
|
+
|
|
264
|
+
shadcn/ui uses **OKLCH** color space for perceptually uniform colors.
|
|
265
|
+
|
|
266
|
+
### OKLCH Format
|
|
267
|
+
|
|
268
|
+
```
|
|
269
|
+
oklch(Lightness Chroma Hue)
|
|
270
|
+
|
|
271
|
+
- Lightness: 0-1 (0 = black, 1 = white)
|
|
272
|
+
- Chroma: 0-0.4 (0 = gray, higher = more saturated)
|
|
273
|
+
- Hue: 0-360 (color angle on color wheel)
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
### Common Colors in OKLCH
|
|
277
|
+
|
|
278
|
+
| Color | OKLCH | Notes |
|
|
279
|
+
|-------|-------|-------|
|
|
280
|
+
| White | `oklch(1 0 0)` | L=1, no chroma |
|
|
281
|
+
| Black | `oklch(0 0 0)` | L=0 |
|
|
282
|
+
| Pure Gray | `oklch(0.5 0 0)` | Mid gray, no chroma |
|
|
283
|
+
| Blue Primary | `oklch(0.55 0.2 250)` | Typical blue |
|
|
284
|
+
| Red Destructive | `oklch(0.577 0.245 27)` | shadcn default red |
|
|
285
|
+
| Green Success | `oklch(0.6 0.2 145)` | Typical green |
|
|
286
|
+
| Orange Warning | `oklch(0.7 0.2 65)` | Typical orange |
|
|
287
|
+
|
|
288
|
+
### Converting HEX to OKLCH
|
|
289
|
+
|
|
290
|
+
Use online converters or JavaScript:
|
|
291
|
+
|
|
292
|
+
```javascript
|
|
293
|
+
// Using culori library
|
|
294
|
+
import { oklch, formatCss } from 'culori'
|
|
295
|
+
|
|
296
|
+
const hex = '#137fec'
|
|
297
|
+
const oklchColor = oklch(hex)
|
|
298
|
+
// { mode: 'oklch', l: 0.55, c: 0.2, h: 250 }
|
|
299
|
+
|
|
300
|
+
const cssValue = `oklch(${oklchColor.l.toFixed(4)} ${oklchColor.c.toFixed(4)} ${oklchColor.h?.toFixed(4) || 0})`
|
|
301
|
+
// "oklch(0.5500 0.2000 250.0000)"
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
## DS Initialization Workflow
|
|
305
|
+
|
|
306
|
+
### Path 1: From tweakcn.com (Recommended)
|
|
307
|
+
|
|
308
|
+
```bash
|
|
309
|
+
# 1. Customize at tweakcn.com/editor/theme
|
|
310
|
+
# 2. Copy the CSS export
|
|
311
|
+
# 3. Run the command with the CSS file
|
|
312
|
+
|
|
313
|
+
/theme:design-system path/to/exported-theme.css
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
The command will:
|
|
317
|
+
1. Parse the CSS file
|
|
318
|
+
2. Validate required variables
|
|
319
|
+
3. Add missing `@theme inline` mappings if needed
|
|
320
|
+
4. Write to active theme's `globals.css`
|
|
321
|
+
5. Run `pnpm theme:build`
|
|
322
|
+
|
|
323
|
+
### Path 2: From Mock Analysis
|
|
324
|
+
|
|
325
|
+
Use `how-to:customize-theme` command with a mock folder:
|
|
326
|
+
|
|
327
|
+
```bash
|
|
328
|
+
# Extract DS from a mock design
|
|
329
|
+
how-to:customize-theme --from-mock path/to/mock/folder
|
|
330
|
+
```
|
|
331
|
+
|
|
332
|
+
The process will:
|
|
333
|
+
1. Read the `design-system` skill for patterns
|
|
334
|
+
2. Extract color palette from mock's Tailwind config
|
|
335
|
+
3. Convert HEX to OKLCH format
|
|
336
|
+
4. Generate dark mode by inverting lightness
|
|
337
|
+
5. Write to active theme's `globals.css`
|
|
338
|
+
6. Run `pnpm theme:build`
|
|
339
|
+
|
|
340
|
+
## Theme Build Process
|
|
341
|
+
|
|
342
|
+
After modifying `globals.css`:
|
|
343
|
+
|
|
344
|
+
```bash
|
|
345
|
+
# Rebuild theme CSS
|
|
346
|
+
pnpm theme:build
|
|
347
|
+
|
|
348
|
+
# Or with watch mode
|
|
349
|
+
pnpm theme:build --watch
|
|
350
|
+
```
|
|
351
|
+
|
|
352
|
+
**What Build Does:**
|
|
353
|
+
1. Reads `NEXT_PUBLIC_ACTIVE_THEME` from `.env`
|
|
354
|
+
2. Finds theme at `themes/{THEME}/styles/`
|
|
355
|
+
3. Concatenates `globals.css` + `components.css`
|
|
356
|
+
4. Writes to `core/theme-styles.css`
|
|
357
|
+
5. Copies assets to `public/theme/`
|
|
358
|
+
|
|
359
|
+
## Validation Checklist
|
|
360
|
+
|
|
361
|
+
Before finalizing theme customization:
|
|
362
|
+
|
|
363
|
+
- [ ] All required CSS variables defined in `:root`
|
|
364
|
+
- [ ] All dark mode overrides in `.dark`
|
|
365
|
+
- [ ] `@theme inline` section present with all mappings
|
|
366
|
+
- [ ] Colors use OKLCH format (not HEX or HSL)
|
|
367
|
+
- [ ] Font stacks include fallbacks
|
|
368
|
+
- [ ] `--radius` uses rem units
|
|
369
|
+
- [ ] `pnpm theme:build` runs without errors
|
|
370
|
+
- [ ] Light mode looks correct
|
|
371
|
+
- [ ] Dark mode looks correct
|
|
372
|
+
- [ ] Components render properly
|
|
373
|
+
|
|
374
|
+
## Common Patterns
|
|
375
|
+
|
|
376
|
+
### Brand Color Integration
|
|
377
|
+
|
|
378
|
+
```css
|
|
379
|
+
:root {
|
|
380
|
+
/* Brand blue as primary */
|
|
381
|
+
--primary: oklch(0.55 0.2 250); /* #137fec equivalent */
|
|
382
|
+
--primary-foreground: oklch(0.985 0 0); /* White text on blue */
|
|
383
|
+
|
|
384
|
+
/* Brand blue tint for secondary */
|
|
385
|
+
--secondary: oklch(0.95 0.03 250); /* Very light blue */
|
|
386
|
+
--secondary-foreground: oklch(0.25 0 0); /* Dark text */
|
|
387
|
+
|
|
388
|
+
/* Brand blue for accent */
|
|
389
|
+
--accent: oklch(0.92 0.05 250); /* Light blue hover */
|
|
390
|
+
--accent-foreground: oklch(0.25 0 0);
|
|
391
|
+
}
|
|
392
|
+
```
|
|
393
|
+
|
|
394
|
+
### Dark Theme with Color Preservation
|
|
395
|
+
|
|
396
|
+
```css
|
|
397
|
+
.dark {
|
|
398
|
+
/* Keep brand color vibrant in dark mode */
|
|
399
|
+
--primary: oklch(0.65 0.2 250); /* Slightly lighter */
|
|
400
|
+
--primary-foreground: oklch(0.1 0 0); /* Dark text on light primary */
|
|
401
|
+
|
|
402
|
+
/* Muted versions for backgrounds */
|
|
403
|
+
--secondary: oklch(0.25 0.03 250); /* Dark blue-gray */
|
|
404
|
+
--secondary-foreground: oklch(0.95 0 0); /* Light text */
|
|
405
|
+
}
|
|
406
|
+
```
|
|
407
|
+
|
|
408
|
+
## Anti-Patterns
|
|
409
|
+
|
|
410
|
+
```css
|
|
411
|
+
/* ❌ NEVER: Use HEX or HSL in globals.css */
|
|
412
|
+
--primary: #137fec;
|
|
413
|
+
--primary: hsl(210, 100%, 50%);
|
|
414
|
+
|
|
415
|
+
/* ✅ CORRECT: Use OKLCH */
|
|
416
|
+
--primary: oklch(0.55 0.2 250);
|
|
417
|
+
|
|
418
|
+
/* ❌ NEVER: Skip dark mode */
|
|
419
|
+
/* (Will look terrible in dark mode) */
|
|
420
|
+
|
|
421
|
+
/* ✅ CORRECT: Define complete dark mode */
|
|
422
|
+
.dark {
|
|
423
|
+
--background: oklch(0.145 0 0);
|
|
424
|
+
/* ... all overrides */
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
/* ❌ NEVER: Skip @theme inline */
|
|
428
|
+
/* (Tailwind classes won't work) */
|
|
429
|
+
|
|
430
|
+
/* ✅ CORRECT: Include complete mapping */
|
|
431
|
+
@theme inline {
|
|
432
|
+
--color-background: var(--background);
|
|
433
|
+
/* ... all mappings */
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
/* ❌ NEVER: Edit core/theme-styles.css */
|
|
437
|
+
/* (Will be overwritten on next build) */
|
|
438
|
+
|
|
439
|
+
/* ✅ CORRECT: Edit themes/{THEME}/styles/globals.css */
|
|
440
|
+
```
|
|
441
|
+
|
|
442
|
+
## Related Skills
|
|
443
|
+
|
|
444
|
+
- `tailwind-theming` - Tailwind CSS patterns and buildSectionClasses
|
|
445
|
+
- `design-system` - Token mapping from mocks
|
|
446
|
+
- `shadcn-components` - Component usage patterns
|
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: suspense-loading
|
|
3
|
+
description: |
|
|
4
|
+
Suspense and loading state patterns for this Next.js application.
|
|
5
|
+
Covers loading.tsx files, skeleton components, INP optimization, and streaming SSR.
|
|
6
|
+
Use this skill when implementing loading states or optimizing perceived performance.
|
|
7
|
+
allowed-tools: Read, Glob, Grep
|
|
8
|
+
version: 1.0.0
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# Suspense & Loading States Skill
|
|
12
|
+
|
|
13
|
+
Patterns for implementing loading states and Suspense boundaries in this Next.js 15 application.
|
|
14
|
+
|
|
15
|
+
## Architecture Overview
|
|
16
|
+
|
|
17
|
+
```
|
|
18
|
+
LOADING STATE ARCHITECTURE:
|
|
19
|
+
|
|
20
|
+
Route-Level Loading (loading.tsx):
|
|
21
|
+
├── app/dashboard/(main)/loading.tsx # Dashboard home skeleton
|
|
22
|
+
├── app/dashboard/settings/loading.tsx # Settings overview skeleton
|
|
23
|
+
├── app/dashboard/settings/*/loading.tsx # Setting-specific skeletons
|
|
24
|
+
├── app/dashboard/features/loading.tsx # Features placeholder skeleton
|
|
25
|
+
└── app/dashboard/(main)/[entity]/ # Entity list skeleton (existing)
|
|
26
|
+
|
|
27
|
+
Skeleton Components (core/components/ui/):
|
|
28
|
+
├── skeleton.tsx # Base Skeleton + SkeletonContainer + SkeletonText
|
|
29
|
+
├── skeleton-dashboard.tsx # SkeletonDashboardHome, SkeletonStatsGrid, etc.
|
|
30
|
+
├── skeleton-settings.tsx # SkeletonSettingsOverview, SkeletonProfileForm, etc.
|
|
31
|
+
├── skeleton-features.tsx # SkeletonFeaturePlaceholder, SkeletonAnalyticsPage
|
|
32
|
+
├── skeleton-list.tsx # SkeletonEntityList, SkeletonTable
|
|
33
|
+
├── skeleton-form.tsx # SkeletonEntityForm, SkeletonFormCard
|
|
34
|
+
└── skeleton-detail.tsx # SkeletonEntityDetail, SkeletonDetailCard
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## INP Optimizations
|
|
38
|
+
|
|
39
|
+
The skeleton system includes optimizations for Interaction to Next Paint (INP):
|
|
40
|
+
|
|
41
|
+
### 1. CSS Containment
|
|
42
|
+
|
|
43
|
+
```css
|
|
44
|
+
/* Isolates layout/paint calculations */
|
|
45
|
+
.skeleton-contained {
|
|
46
|
+
contain: content;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/* Container-level containment */
|
|
50
|
+
.skeleton-container {
|
|
51
|
+
contain: layout style;
|
|
52
|
+
}
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### 2. Content Visibility
|
|
56
|
+
|
|
57
|
+
```css
|
|
58
|
+
/* Skips rendering of off-screen skeleton items */
|
|
59
|
+
.skeleton-container > * {
|
|
60
|
+
content-visibility: auto;
|
|
61
|
+
contain-intrinsic-size: auto 100px;
|
|
62
|
+
}
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
### 3. GPU-Accelerated Animations
|
|
66
|
+
|
|
67
|
+
```css
|
|
68
|
+
@keyframes skeleton-pulse {
|
|
69
|
+
0%, 100% { opacity: 1; }
|
|
70
|
+
50% { opacity: 0.5; }
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
.animate-skeleton-pulse {
|
|
74
|
+
animation: skeleton-pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
|
|
75
|
+
will-change: opacity;
|
|
76
|
+
}
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### 4. Reduced Motion Support
|
|
80
|
+
|
|
81
|
+
```css
|
|
82
|
+
@media (prefers-reduced-motion: reduce) {
|
|
83
|
+
.animate-skeleton-pulse {
|
|
84
|
+
animation: none;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
## Component Patterns
|
|
90
|
+
|
|
91
|
+
### Base Skeleton
|
|
92
|
+
|
|
93
|
+
```typescript
|
|
94
|
+
import { Skeleton, SkeletonContainer, SkeletonText } from '@nextsparkjs/core/components/ui/skeleton'
|
|
95
|
+
|
|
96
|
+
// Simple skeleton
|
|
97
|
+
<Skeleton className="h-4 w-32" />
|
|
98
|
+
|
|
99
|
+
// Text skeleton with multiple lines
|
|
100
|
+
<SkeletonText lines={3} />
|
|
101
|
+
|
|
102
|
+
// Container for multiple skeletons (enables content-visibility)
|
|
103
|
+
<SkeletonContainer className="space-y-4">
|
|
104
|
+
<Skeleton className="h-10 w-full" />
|
|
105
|
+
<Skeleton className="h-10 w-full" />
|
|
106
|
+
<Skeleton className="h-10 w-full" />
|
|
107
|
+
</SkeletonContainer>
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
### Loading.tsx Pattern
|
|
111
|
+
|
|
112
|
+
```typescript
|
|
113
|
+
// app/dashboard/settings/profile/loading.tsx
|
|
114
|
+
import { SkeletonProfileForm } from '@nextsparkjs/core/components/ui/skeleton-settings'
|
|
115
|
+
|
|
116
|
+
export default function ProfileLoading() {
|
|
117
|
+
return <SkeletonProfileForm />
|
|
118
|
+
}
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
### Suspense Boundary in Component
|
|
122
|
+
|
|
123
|
+
```typescript
|
|
124
|
+
import { Suspense } from 'react'
|
|
125
|
+
import { SkeletonStatsGrid } from '@nextsparkjs/core/components/ui/skeleton-dashboard'
|
|
126
|
+
|
|
127
|
+
export default function DashboardPage() {
|
|
128
|
+
return (
|
|
129
|
+
<div>
|
|
130
|
+
{/* Header (instant) */}
|
|
131
|
+
<h1>Dashboard</h1>
|
|
132
|
+
|
|
133
|
+
{/* Stats with Suspense boundary (streamed) */}
|
|
134
|
+
<Suspense fallback={<SkeletonStatsGrid />}>
|
|
135
|
+
<DashboardStats />
|
|
136
|
+
</Suspense>
|
|
137
|
+
|
|
138
|
+
{/* Activity with Suspense boundary (streamed) */}
|
|
139
|
+
<Suspense fallback={<SkeletonActivity />}>
|
|
140
|
+
<RecentActivity />
|
|
141
|
+
</Suspense>
|
|
142
|
+
</div>
|
|
143
|
+
)
|
|
144
|
+
}
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
## Available Skeleton Components
|
|
148
|
+
|
|
149
|
+
### Dashboard
|
|
150
|
+
|
|
151
|
+
| Component | Description |
|
|
152
|
+
|-----------|-------------|
|
|
153
|
+
| `SkeletonDashboardHome` | Complete dashboard home page skeleton |
|
|
154
|
+
| `SkeletonStatsGrid` | 4-card stats grid |
|
|
155
|
+
| `SkeletonStatCard` | Single stat card |
|
|
156
|
+
| `SkeletonQuickActions` | Quick actions section |
|
|
157
|
+
| `SkeletonActivity` | Activity feed |
|
|
158
|
+
|
|
159
|
+
### Settings
|
|
160
|
+
|
|
161
|
+
| Component | Description |
|
|
162
|
+
|-----------|-------------|
|
|
163
|
+
| `SkeletonSettingsOverview` | Settings navigation cards |
|
|
164
|
+
| `SkeletonProfileForm` | Profile edit form |
|
|
165
|
+
| `SkeletonBillingPage` | Billing/plans page |
|
|
166
|
+
| `SkeletonPasswordPage` | Password change form |
|
|
167
|
+
| `SkeletonSecurityPage` | Sessions list |
|
|
168
|
+
| `SkeletonApiKeysPage` | API keys list |
|
|
169
|
+
| `SkeletonNotificationsPage` | Notification settings |
|
|
170
|
+
| `SkeletonTeamsPage` | Teams list |
|
|
171
|
+
| `SkeletonInvoicesPage` | Invoices table |
|
|
172
|
+
| `SkeletonPlansPage` | Plans grid |
|
|
173
|
+
|
|
174
|
+
### Features
|
|
175
|
+
|
|
176
|
+
| Component | Description |
|
|
177
|
+
|-----------|-------------|
|
|
178
|
+
| `SkeletonFeaturePlaceholder` | Feature gate placeholder |
|
|
179
|
+
| `SkeletonAnalyticsPage` | Analytics dashboard |
|
|
180
|
+
| `SkeletonWebhooksPage` | Webhooks configuration |
|
|
181
|
+
| `SkeletonAutomationPage` | Automation list |
|
|
182
|
+
|
|
183
|
+
### Entity Pages
|
|
184
|
+
|
|
185
|
+
| Component | Description |
|
|
186
|
+
|-----------|-------------|
|
|
187
|
+
| `SkeletonEntityList` | Complete entity list page |
|
|
188
|
+
| `SkeletonEntityForm` | Entity create/edit form |
|
|
189
|
+
| `SkeletonEntityDetail` | Entity detail view |
|
|
190
|
+
|
|
191
|
+
## Best Practices
|
|
192
|
+
|
|
193
|
+
### 1. Match Skeleton to Content
|
|
194
|
+
|
|
195
|
+
Skeletons should closely match the final content layout:
|
|
196
|
+
|
|
197
|
+
```typescript
|
|
198
|
+
// Good - matches actual content structure
|
|
199
|
+
<div className="max-w-4xl space-y-6">
|
|
200
|
+
<header>
|
|
201
|
+
<Skeleton className="h-8 w-32 mb-2" />
|
|
202
|
+
<Skeleton className="h-5 w-64" />
|
|
203
|
+
</header>
|
|
204
|
+
{/* ... */}
|
|
205
|
+
</div>
|
|
206
|
+
|
|
207
|
+
// Bad - generic box that doesn't match
|
|
208
|
+
<Skeleton className="h-[500px] w-full" />
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
### 2. Use Route-Level Loading
|
|
212
|
+
|
|
213
|
+
Prefer `loading.tsx` files over component-level loading states:
|
|
214
|
+
|
|
215
|
+
```
|
|
216
|
+
app/dashboard/settings/profile/
|
|
217
|
+
├── page.tsx # Actual content
|
|
218
|
+
└── loading.tsx # Skeleton shown during load
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
### 3. Wrap Multiple Skeletons
|
|
222
|
+
|
|
223
|
+
Use `SkeletonContainer` for lists to enable content-visibility:
|
|
224
|
+
|
|
225
|
+
```typescript
|
|
226
|
+
// Good - enables off-screen optimization
|
|
227
|
+
<SkeletonContainer className="divide-y">
|
|
228
|
+
{Array.from({ length: 10 }).map((_, i) => (
|
|
229
|
+
<SkeletonListItem key={i} />
|
|
230
|
+
))}
|
|
231
|
+
</SkeletonContainer>
|
|
232
|
+
|
|
233
|
+
// Less optimal - no content-visibility
|
|
234
|
+
<div className="divide-y">
|
|
235
|
+
{Array.from({ length: 10 }).map((_, i) => (
|
|
236
|
+
<SkeletonListItem key={i} />
|
|
237
|
+
))}
|
|
238
|
+
</div>
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
### 4. Consider Inheritance
|
|
242
|
+
|
|
243
|
+
Next.js inherits `loading.tsx` from parent routes. You only need specific loading files for pages with different layouts:
|
|
244
|
+
|
|
245
|
+
```
|
|
246
|
+
app/dashboard/settings/
|
|
247
|
+
├── loading.tsx # Covers /settings and simple subroutes
|
|
248
|
+
├── profile/
|
|
249
|
+
│ └── loading.tsx # Different layout, needs own skeleton
|
|
250
|
+
├── billing/
|
|
251
|
+
│ └── loading.tsx # Different layout, needs own skeleton
|
|
252
|
+
├── password/ # Uses parent loading.tsx
|
|
253
|
+
├── security/ # Uses parent loading.tsx
|
|
254
|
+
└── notifications/ # Uses parent loading.tsx
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
## Testing Loading States
|
|
258
|
+
|
|
259
|
+
```typescript
|
|
260
|
+
// Cypress test for loading states
|
|
261
|
+
it('should show skeleton while content loads', () => {
|
|
262
|
+
// Simulate slow network
|
|
263
|
+
cy.intercept('GET', '/api/**', (req) => {
|
|
264
|
+
req.on('response', (res) => res.setDelay(500))
|
|
265
|
+
})
|
|
266
|
+
|
|
267
|
+
cy.visit('/dashboard/settings/profile')
|
|
268
|
+
|
|
269
|
+
// Skeleton should appear briefly
|
|
270
|
+
// Content should replace skeleton
|
|
271
|
+
cy.get('[data-cy="settings-profile-container"]', { timeout: 10000 })
|
|
272
|
+
.should('be.visible')
|
|
273
|
+
})
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
## Related Skills
|
|
277
|
+
|
|
278
|
+
- `react-patterns` - Server/Client components, Suspense basics
|
|
279
|
+
- `shadcn-components` - UI component library
|
|
280
|
+
- `tanstack-query` - Data fetching with loading states
|