@design-ai/cli 4.55.0
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/.claude-plugin/plugin.json +164 -0
- package/AGENTS.ko.md +126 -0
- package/AGENTS.md +182 -0
- package/CHANGELOG.md +6883 -0
- package/CLAUDE.md +39 -0
- package/LICENSE +21 -0
- package/README.ko.md +245 -0
- package/README.md +277 -0
- package/agents/README.md +14 -0
- package/agents/a11y-reviewer.md +121 -0
- package/agents/component-architect.md +57 -0
- package/agents/design-critic.md +46 -0
- package/agents/token-extractor.md +63 -0
- package/cli/bin/design-ai-mcp.mjs +6 -0
- package/cli/bin/design-ai.mjs +40 -0
- package/cli/commands/audit.mjs +111 -0
- package/cli/commands/check.mjs +226 -0
- package/cli/commands/doctor.mjs +141 -0
- package/cli/commands/examples.mjs +58 -0
- package/cli/commands/help.mjs +271 -0
- package/cli/commands/install.mjs +161 -0
- package/cli/commands/learn.mjs +1871 -0
- package/cli/commands/list.mjs +143 -0
- package/cli/commands/mcp.mjs +27 -0
- package/cli/commands/pack.mjs +211 -0
- package/cli/commands/prompt.mjs +199 -0
- package/cli/commands/route.mjs +247 -0
- package/cli/commands/search.mjs +60 -0
- package/cli/commands/show.mjs +52 -0
- package/cli/commands/site.mjs +558 -0
- package/cli/commands/status.mjs +161 -0
- package/cli/commands/uninstall.mjs +119 -0
- package/cli/commands/update.mjs +184 -0
- package/cli/commands/version.mjs +94 -0
- package/cli/commands/workspace.mjs +176 -0
- package/cli/lib/brief.mjs +52 -0
- package/cli/lib/check.mjs +642 -0
- package/cli/lib/dispatch.mjs +109 -0
- package/cli/lib/doctor.mjs +505 -0
- package/cli/lib/examples.mjs +258 -0
- package/cli/lib/exec.mjs +63 -0
- package/cli/lib/help-flags.mjs +5 -0
- package/cli/lib/learn.mjs +3694 -0
- package/cli/lib/log.mjs +47 -0
- package/cli/lib/mcp-server.mjs +426 -0
- package/cli/lib/output.mjs +101 -0
- package/cli/lib/pack.mjs +599 -0
- package/cli/lib/paths.mjs +63 -0
- package/cli/lib/prompt.mjs +603 -0
- package/cli/lib/route.mjs +740 -0
- package/cli/lib/search.mjs +158 -0
- package/cli/lib/show.mjs +161 -0
- package/cli/lib/signals.mjs +2337 -0
- package/cli/lib/site.mjs +6617 -0
- package/cli/lib/skill-proposals.mjs +2046 -0
- package/cli/lib/suggest.mjs +66 -0
- package/cli/lib/workspace.mjs +1056 -0
- package/commands/README.md +25 -0
- package/commands/component-spec.md +34 -0
- package/commands/conversational.md +44 -0
- package/commands/design-from-brief.md +141 -0
- package/commands/design-review.md +62 -0
- package/commands/document-from-brief.md +47 -0
- package/commands/extract-tokens.md +38 -0
- package/commands/game-ui.md +40 -0
- package/commands/illustration.md +37 -0
- package/commands/iterate.md +167 -0
- package/commands/motion-design.md +54 -0
- package/commands/palette-from-brand.md +50 -0
- package/commands/print.md +49 -0
- package/commands/slide-deck.md +46 -0
- package/commands/spatial.md +47 -0
- package/commands/stability-review.md +74 -0
- package/commands/video.md +42 -0
- package/commands/website-improvement.md +77 -0
- package/docs/AGENT-DEVELOPMENT.md +658 -0
- package/docs/AI-LEARNING.md +429 -0
- package/docs/AIDER-INTEGRATION.md +224 -0
- package/docs/ARCHITECTURE.ko.md +183 -0
- package/docs/ARCHITECTURE.md +105 -0
- package/docs/CODEX-INTEGRATION.md +311 -0
- package/docs/COMPANY-WEBSITE-DOGFOOD.ko.md +144 -0
- package/docs/COMPANY-WEBSITE-DOGFOOD.md +150 -0
- package/docs/COMPANY-WEBSITE-INTAKE-TEMPLATE.ko.md +153 -0
- package/docs/COMPANY-WEBSITE-INTAKE-TEMPLATE.md +154 -0
- package/docs/CONTRIBUTING.ko.md +203 -0
- package/docs/CONTRIBUTING.md +242 -0
- package/docs/CURSOR-INTEGRATION.md +220 -0
- package/docs/DISTRIBUTION.ko.md +248 -0
- package/docs/DISTRIBUTION.md +253 -0
- package/docs/DOGFOOD-FINDINGS.md +180 -0
- package/docs/DOGFOOD-V4-FINDINGS.md +139 -0
- package/docs/DOGFOOD-V4-MKDOCS-FINDINGS.md +233 -0
- package/docs/DOGFOOD-V4-NPM-FINDINGS.md +157 -0
- package/docs/DOGFOOD-V4-VSCODE-FINDINGS.md +135 -0
- package/docs/FIGMA-INTEGRATION.md +222 -0
- package/docs/MCP-INTEGRATION.md +243 -0
- package/docs/MIGRATION-v4.md +121 -0
- package/docs/PLUGIN-PACKAGING.md +240 -0
- package/docs/PRODUCT-READINESS.md +66 -0
- package/docs/QUICKSTART.ko.md +178 -0
- package/docs/QUICKSTART.md +179 -0
- package/docs/RELEASE-CHECKLIST.md +292 -0
- package/docs/ROADMAP.md +19495 -0
- package/docs/SESSION-LOG.md +940 -0
- package/docs/TOKEN-SYNC.md +237 -0
- package/docs/USING.ko.md +206 -0
- package/docs/USING.md +218 -0
- package/docs/WEBSITE-IMPROVEMENT.ko.md +75 -0
- package/docs/WEBSITE-IMPROVEMENT.md +89 -0
- package/docs/announcements/README.md +56 -0
- package/docs/announcements/dev-to-korea.md +206 -0
- package/docs/announcements/hashnode-post.ko.md +232 -0
- package/docs/announcements/okky-post.ko.md +158 -0
- package/docs/announcements/press-kit.md +101 -0
- package/docs/announcements/reddit-r-korea.md +196 -0
- package/docs/announcements/show-hn.md +114 -0
- package/docs/announcements/twitter-thread.md +255 -0
- package/docs/external-status.md +34 -0
- package/docs/integrations/aider-walkthrough.ko.md +275 -0
- package/docs/integrations/aider-walkthrough.md +274 -0
- package/docs/integrations/codex-walkthrough.ko.md +297 -0
- package/docs/integrations/codex-walkthrough.md +297 -0
- package/docs/integrations/cursor-walkthrough.ko.md +281 -0
- package/docs/integrations/cursor-walkthrough.md +284 -0
- package/docs/integrations/design-ai-mcp-server.md +169 -0
- package/docs/integrations/figma-mcp.md +149 -0
- package/docs/integrations/github-mcp.md +178 -0
- package/docs/integrations/linear-mcp.md +215 -0
- package/docs/integrations/notion-mcp.md +174 -0
- package/docs/integrations/sdk-walkthrough.ko.md +375 -0
- package/docs/integrations/sdk-walkthrough.md +375 -0
- package/docs/integrations/slack-mcp.md +208 -0
- package/docs/integrations/vscode-walkthrough.ko.md +202 -0
- package/docs/integrations/vscode-walkthrough.md +205 -0
- package/docs/requirements.txt +16 -0
- package/docs/site-overrides/extra.css +83 -0
- package/docs/site-overrides/favicon.svg +4 -0
- package/docs/site-overrides/logo.svg +10 -0
- package/docs/site-overrides/main.html +18 -0
- package/docs/website-console/app.js +2540 -0
- package/docs/website-console/index.html +24 -0
- package/docs/website-console/styles.css +975 -0
- package/examples/README.md +252 -0
- package/examples/cases/dogfood-v4-korean-hr-onboarding.md +356 -0
- package/examples/component-accordion-actions.md +153 -0
- package/examples/component-accordion-details.md +147 -0
- package/examples/component-accordion-summary.md +180 -0
- package/examples/component-accordion.md +229 -0
- package/examples/component-account-card.md +284 -0
- package/examples/component-address-input.md +260 -0
- package/examples/component-affix.md +190 -0
- package/examples/component-alert-dialog.md +210 -0
- package/examples/component-alert-title.md +77 -0
- package/examples/component-alert.md +192 -0
- package/examples/component-amount-input.md +278 -0
- package/examples/component-anchor.md +198 -0
- package/examples/component-app-bar.md +249 -0
- package/examples/component-aspect-ratio.md +156 -0
- package/examples/component-auto-complete.md +199 -0
- package/examples/component-avatar-group.md +170 -0
- package/examples/component-avatar.md +191 -0
- package/examples/component-back-top.md +123 -0
- package/examples/component-backdrop.md +148 -0
- package/examples/component-badge.md +181 -0
- package/examples/component-banner.md +237 -0
- package/examples/component-biometric-gate.md +281 -0
- package/examples/component-blockquote.md +153 -0
- package/examples/component-border-beam.md +207 -0
- package/examples/component-bottom-navigation.md +226 -0
- package/examples/component-box.md +112 -0
- package/examples/component-breadcrumb.md +222 -0
- package/examples/component-button-base.md +190 -0
- package/examples/component-button-group.md +117 -0
- package/examples/component-button.md +213 -0
- package/examples/component-calendar.md +280 -0
- package/examples/component-callout.md +131 -0
- package/examples/component-card-actions.md +101 -0
- package/examples/component-card-content.md +90 -0
- package/examples/component-card-header.md +122 -0
- package/examples/component-card-media.md +79 -0
- package/examples/component-card.md +233 -0
- package/examples/component-carousel.md +266 -0
- package/examples/component-cascader.md +135 -0
- package/examples/component-category-picker.md +271 -0
- package/examples/component-chart.md +237 -0
- package/examples/component-chat-interface.md +399 -0
- package/examples/component-checkbox.md +149 -0
- package/examples/component-click-away-listener.md +87 -0
- package/examples/component-code.md +213 -0
- package/examples/component-collapsible.md +219 -0
- package/examples/component-color-picker.md +110 -0
- package/examples/component-combobox.md +267 -0
- package/examples/component-command.md +299 -0
- package/examples/component-config-provider.md +190 -0
- package/examples/component-context-menu.md +179 -0
- package/examples/component-css-baseline.md +148 -0
- package/examples/component-date-picker.md +249 -0
- package/examples/component-descriptions.md +242 -0
- package/examples/component-dialog-actions.md +111 -0
- package/examples/component-dialog-content-text.md +76 -0
- package/examples/component-dialog-content.md +105 -0
- package/examples/component-dialog-title.md +104 -0
- package/examples/component-dialog.md +176 -0
- package/examples/component-divider.md +182 -0
- package/examples/component-doc-page.md +217 -0
- package/examples/component-drawer.md +257 -0
- package/examples/component-dropdown.md +220 -0
- package/examples/component-email-layout.md +253 -0
- package/examples/component-empty-state.md +269 -0
- package/examples/component-empty.md +172 -0
- package/examples/component-fade.md +87 -0
- package/examples/component-feature-grid.md +201 -0
- package/examples/component-field.md +266 -0
- package/examples/component-filled-input.md +114 -0
- package/examples/component-flex.md +117 -0
- package/examples/component-float-button.md +214 -0
- package/examples/component-form-control-label.md +134 -0
- package/examples/component-form-control.md +113 -0
- package/examples/component-form-controls.md +251 -0
- package/examples/component-form-group.md +86 -0
- package/examples/component-form-helper-text.md +95 -0
- package/examples/component-form-label.md +98 -0
- package/examples/component-form.md +291 -0
- package/examples/component-game-hud.md +362 -0
- package/examples/component-game-menu.md +327 -0
- package/examples/component-grid.md +140 -0
- package/examples/component-grow.md +79 -0
- package/examples/component-hero-block.md +252 -0
- package/examples/component-hover-card.md +211 -0
- package/examples/component-icon-button.md +142 -0
- package/examples/component-icon.md +102 -0
- package/examples/component-illustration.md +280 -0
- package/examples/component-image-list.md +107 -0
- package/examples/component-image.md +282 -0
- package/examples/component-input-adornment.md +101 -0
- package/examples/component-input-base.md +134 -0
- package/examples/component-input-number.md +141 -0
- package/examples/component-input-otp.md +271 -0
- package/examples/component-input.md +213 -0
- package/examples/component-item.md +243 -0
- package/examples/component-kbd.md +197 -0
- package/examples/component-krw-amount.md +219 -0
- package/examples/component-label.md +118 -0
- package/examples/component-layout.md +217 -0
- package/examples/component-link.md +223 -0
- package/examples/component-list-item-avatar.md +72 -0
- package/examples/component-list-item-button.md +139 -0
- package/examples/component-list-item-icon.md +82 -0
- package/examples/component-list-item-text.md +98 -0
- package/examples/component-list-item.md +116 -0
- package/examples/component-list-subheader.md +70 -0
- package/examples/component-list.md +198 -0
- package/examples/component-loading-button.md +125 -0
- package/examples/component-loading-sequence.md +254 -0
- package/examples/component-lottie-player.md +279 -0
- package/examples/component-masonry.md +191 -0
- package/examples/component-mentions.md +189 -0
- package/examples/component-menu-item.md +102 -0
- package/examples/component-menu-list.md +98 -0
- package/examples/component-menu.md +139 -0
- package/examples/component-menubar.md +259 -0
- package/examples/component-message.md +162 -0
- package/examples/component-mobile-stepper.md +155 -0
- package/examples/component-modal.md +220 -0
- package/examples/component-navigation-menu.md +295 -0
- package/examples/component-notification.md +166 -0
- package/examples/component-otp-countdown.md +245 -0
- package/examples/component-outlined-input.md +145 -0
- package/examples/component-page-transition.md +281 -0
- package/examples/component-pagination.md +226 -0
- package/examples/component-paper.md +199 -0
- package/examples/component-pass-auth.md +265 -0
- package/examples/component-payment-brand-button.md +253 -0
- package/examples/component-payment-method-selector.md +272 -0
- package/examples/component-payment-receipt.md +277 -0
- package/examples/component-popconfirm.md +144 -0
- package/examples/component-popover.md +239 -0
- package/examples/component-popper.md +129 -0
- package/examples/component-pricing-cards.md +247 -0
- package/examples/component-progress.md +195 -0
- package/examples/component-qr-code.md +201 -0
- package/examples/component-radio.md +167 -0
- package/examples/component-rate.md +202 -0
- package/examples/component-resizable.md +163 -0
- package/examples/component-result.md +270 -0
- package/examples/component-scroll-area.md +199 -0
- package/examples/component-scroll-reveal.md +320 -0
- package/examples/component-segmented.md +178 -0
- package/examples/component-select.md +258 -0
- package/examples/component-separator.md +177 -0
- package/examples/component-sheet.md +277 -0
- package/examples/component-sidebar.md +257 -0
- package/examples/component-skeleton.md +178 -0
- package/examples/component-slide.md +89 -0
- package/examples/component-slider.md +208 -0
- package/examples/component-snackbar-content.md +92 -0
- package/examples/component-snackbar.md +121 -0
- package/examples/component-sonner.md +165 -0
- package/examples/component-space.md +125 -0
- package/examples/component-spatial-locomotion.md +373 -0
- package/examples/component-spatial-panel.md +330 -0
- package/examples/component-speed-dial-action.md +78 -0
- package/examples/component-speed-dial.md +177 -0
- package/examples/component-spin.md +173 -0
- package/examples/component-spinner.md +204 -0
- package/examples/component-splitter.md +210 -0
- package/examples/component-stack.md +130 -0
- package/examples/component-statistic.md +282 -0
- package/examples/component-step-button.md +157 -0
- package/examples/component-step-connector.md +157 -0
- package/examples/component-step-content.md +121 -0
- package/examples/component-step-icon.md +115 -0
- package/examples/component-step-label.md +101 -0
- package/examples/component-step.md +84 -0
- package/examples/component-steps.md +264 -0
- package/examples/component-stock-chart.md +251 -0
- package/examples/component-swipeable-drawer.md +149 -0
- package/examples/component-switch.md +99 -0
- package/examples/component-tab-scroll-button.md +180 -0
- package/examples/component-tab.md +120 -0
- package/examples/component-table-body.md +82 -0
- package/examples/component-table-cell.md +118 -0
- package/examples/component-table-container.md +75 -0
- package/examples/component-table-footer.md +72 -0
- package/examples/component-table-head.md +78 -0
- package/examples/component-table-pagination.md +137 -0
- package/examples/component-table-row.md +113 -0
- package/examples/component-table-sort-label.md +109 -0
- package/examples/component-table.md +202 -0
- package/examples/component-tabs.md +184 -0
- package/examples/component-tag-badge.md +309 -0
- package/examples/component-tag.md +102 -0
- package/examples/component-testimonial-carousel.md +218 -0
- package/examples/component-textarea-autosize.md +114 -0
- package/examples/component-textarea.md +173 -0
- package/examples/component-time-picker.md +205 -0
- package/examples/component-timeline.md +170 -0
- package/examples/component-toast.md +224 -0
- package/examples/component-toggle-button.md +129 -0
- package/examples/component-toggle.md +220 -0
- package/examples/component-toolbar.md +104 -0
- package/examples/component-tooltip.md +178 -0
- package/examples/component-tour.md +176 -0
- package/examples/component-transaction-list-item.md +243 -0
- package/examples/component-transfer.md +156 -0
- package/examples/component-tree-select.md +202 -0
- package/examples/component-tree.md +297 -0
- package/examples/component-typography.md +215 -0
- package/examples/component-upload.md +295 -0
- package/examples/component-video-hero.md +409 -0
- package/examples/component-video-player.md +340 -0
- package/examples/component-voice-input.md +408 -0
- package/examples/component-watermark.md +217 -0
- package/examples/component-zoom.md +92 -0
- package/examples/doc-explanation-example.md +196 -0
- package/examples/doc-how-to-example.md +205 -0
- package/examples/doc-tutorial-example.md +162 -0
- package/examples/dogfood-korean-fintech-system.md +433 -0
- package/examples/email-transactional-example.md +259 -0
- package/examples/palette-saas-violet.md +235 -0
- package/examples/print-business-card-spec.md +205 -0
- package/examples/print-packaging-spec.md +285 -0
- package/examples/report-example.md +228 -0
- package/examples/slide-deck-example.md +237 -0
- package/examples/website-improvement-report.md +128 -0
- package/examples/website-improvement-workspace.json +126 -0
- package/install.sh +189 -0
- package/knowledge/COVERAGE.md +740 -0
- package/knowledge/PRINCIPLES.md +108 -0
- package/knowledge/a11y/contrast.md +70 -0
- package/knowledge/a11y/keyboard-and-focus.md +108 -0
- package/knowledge/colors/color-theory.md +90 -0
- package/knowledge/colors/mui-palette-structure.md +105 -0
- package/knowledge/colors/palettes-by-product-type.md +876 -0
- package/knowledge/components/INDEX.md +231 -0
- package/knowledge/components/index.json +1470 -0
- package/knowledge/components/shadcn-registry.md +159 -0
- package/knowledge/conversational/ai-chat-interfaces.md +323 -0
- package/knowledge/conversational/chatbot-design.md +312 -0
- package/knowledge/conversational/conversational-ui-fundamentals.md +299 -0
- package/knowledge/conversational/korean-voice-conventions.md +281 -0
- package/knowledge/conversational/voice-ui-patterns.md +297 -0
- package/knowledge/design-tokens/ant-design.md +124 -0
- package/knowledge/design-tokens/material-3.md +235 -0
- package/knowledge/design-tokens/polaris-and-carbon.md +231 -0
- package/knowledge/design-tokens/tailwind-v4.md +284 -0
- package/knowledge/game-ui/game-accessibility.md +317 -0
- package/knowledge/game-ui/game-ui-fundamentals.md +281 -0
- package/knowledge/game-ui/hud-design.md +324 -0
- package/knowledge/game-ui/korean-gaming-conventions.md +312 -0
- package/knowledge/game-ui/menu-systems.md +388 -0
- package/knowledge/i18n/korean-app-store-visual.md +223 -0
- package/knowledge/i18n/korean-document-style.md +301 -0
- package/knowledge/i18n/korean-payments.md +211 -0
- package/knowledge/i18n/korean-product-conventions.md +96 -0
- package/knowledge/i18n/korean-publishing.md +139 -0
- package/knowledge/i18n/korean-typography.md +123 -0
- package/knowledge/icons/curated-sets.md +225 -0
- package/knowledge/illustration/hero-illustrations.md +234 -0
- package/knowledge/illustration/illustration-systems.md +221 -0
- package/knowledge/illustration/mascot-design.md +208 -0
- package/knowledge/illustration/spot-illustrations.md +246 -0
- package/knowledge/illustration/svg-optimization.md +308 -0
- package/knowledge/layout/spacing-and-grid.md +119 -0
- package/knowledge/motion/app-loading-sequences.md +277 -0
- package/knowledge/motion/choreography-depth.md +297 -0
- package/knowledge/motion/marketing-motion.md +223 -0
- package/knowledge/motion/micro-interactions.md +266 -0
- package/knowledge/motion/motion-tools.md +281 -0
- package/knowledge/motion/principles.md +126 -0
- package/knowledge/patterns/auth-flow-design.md +316 -0
- package/knowledge/patterns/b2b-onboarding-flows.md +182 -0
- package/knowledge/patterns/brand-identity.md +238 -0
- package/knowledge/patterns/brand-references.md +97 -0
- package/knowledge/patterns/chart-color-encoding.md +269 -0
- package/knowledge/patterns/chart-types.md +344 -0
- package/knowledge/patterns/dashboard-composition.md +299 -0
- package/knowledge/patterns/design-system-qa.md +356 -0
- package/knowledge/patterns/document-typography.md +248 -0
- package/knowledge/patterns/email-design.md +338 -0
- package/knowledge/patterns/empty-states.md +263 -0
- package/knowledge/patterns/error-states.md +318 -0
- package/knowledge/patterns/form-design.md +237 -0
- package/knowledge/patterns/information-architecture.md +341 -0
- package/knowledge/patterns/landing-hero-design.md +283 -0
- package/knowledge/patterns/landing-page-patterns.md +681 -0
- package/knowledge/patterns/list-and-feed.md +371 -0
- package/knowledge/patterns/mobile-navigation.md +278 -0
- package/knowledge/patterns/money-and-amount.md +301 -0
- package/knowledge/patterns/onboarding.md +300 -0
- package/knowledge/patterns/pricing-page-design.md +261 -0
- package/knowledge/patterns/realtime-data.md +280 -0
- package/knowledge/patterns/report-design.md +330 -0
- package/knowledge/patterns/search-ux.md +373 -0
- package/knowledge/patterns/settings-page.md +325 -0
- package/knowledge/patterns/slide-deck-design.md +316 -0
- package/knowledge/patterns/styles-catalog.md +2599 -0
- package/knowledge/patterns/technical-writing.md +306 -0
- package/knowledge/patterns/ui-reasoning.md +1853 -0
- package/knowledge/patterns/ux-guidelines.md +1454 -0
- package/knowledge/platforms/react-native.md +395 -0
- package/knowledge/print/brochures-and-flyers.md +276 -0
- package/knowledge/print/korean-print-conventions.md +284 -0
- package/knowledge/print/packaging.md +321 -0
- package/knowledge/print/print-fundamentals.md +238 -0
- package/knowledge/print/signage-and-posters.md +235 -0
- package/knowledge/print/stationery.md +262 -0
- package/knowledge/spatial/ar-patterns.md +253 -0
- package/knowledge/spatial/comfort-and-accessibility.md +245 -0
- package/knowledge/spatial/spatial-design-fundamentals.md +346 -0
- package/knowledge/spatial/spatial-ui-elements.md +343 -0
- package/knowledge/spatial/vr-patterns.md +302 -0
- package/knowledge/typography/font-pairings.md +332 -0
- package/knowledge/typography/mui-type-scale.md +57 -0
- package/knowledge/typography/type-scale-fundamentals.md +105 -0
- package/knowledge/video/in-product-video.md +277 -0
- package/knowledge/video/korean-video-conventions.md +247 -0
- package/knowledge/video/marketing-video.md +258 -0
- package/knowledge/video/social-and-short-form.md +257 -0
- package/knowledge/video/video-fundamentals.md +296 -0
- package/package.json +106 -0
- package/skills/README.md +39 -0
- package/skills/color-palette/PLAYBOOK.md +175 -0
- package/skills/color-palette/SKILL.md +6 -0
- package/skills/color-palette/TEMPLATE.md +103 -0
- package/skills/component-spec-writer/PLAYBOOK.md +169 -0
- package/skills/component-spec-writer/SKILL.md +6 -0
- package/skills/component-spec-writer/TEMPLATE.md +115 -0
- package/skills/conversational-ui-designer/PLAYBOOK.md +231 -0
- package/skills/conversational-ui-designer/SKILL.md +6 -0
- package/skills/design-broadcast/PLAYBOOK.md +146 -0
- package/skills/design-broadcast/SKILL.md +6 -0
- package/skills/design-critique/PLAYBOOK.md +137 -0
- package/skills/design-critique/SKILL.md +6 -0
- package/skills/design-pr-review/PLAYBOOK.md +171 -0
- package/skills/design-pr-review/SKILL.md +6 -0
- package/skills/design-system-builder/PLAYBOOK.md +218 -0
- package/skills/design-system-builder/SKILL.md +6 -0
- package/skills/design-system-qa/PLAYBOOK.md +163 -0
- package/skills/design-system-qa/SKILL.md +6 -0
- package/skills/document-author/PLAYBOOK.md +167 -0
- package/skills/document-author/SKILL.md +6 -0
- package/skills/figma-token-sync/PLAYBOOK.md +149 -0
- package/skills/figma-token-sync/SKILL.md +6 -0
- package/skills/game-ui-designer/PLAYBOOK.md +209 -0
- package/skills/game-ui-designer/SKILL.md +6 -0
- package/skills/handoff-spec/PLAYBOOK.md +170 -0
- package/skills/handoff-spec/SKILL.md +6 -0
- package/skills/illustration-designer/PLAYBOOK.md +166 -0
- package/skills/illustration-designer/SKILL.md +6 -0
- package/skills/motion-designer/PLAYBOOK.md +223 -0
- package/skills/motion-designer/SKILL.md +6 -0
- package/skills/print-designer/PLAYBOOK.md +209 -0
- package/skills/print-designer/SKILL.md +6 -0
- package/skills/slide-deck-author/PLAYBOOK.md +198 -0
- package/skills/slide-deck-author/SKILL.md +6 -0
- package/skills/spatial-designer/PLAYBOOK.md +238 -0
- package/skills/spatial-designer/SKILL.md +6 -0
- package/skills/ux-audit/PLAYBOOK.md +142 -0
- package/skills/ux-audit/SKILL.md +6 -0
- package/skills/video-designer/PLAYBOOK.md +240 -0
- package/skills/video-designer/SKILL.md +6 -0
- package/skills/website-improvement/PLAYBOOK.md +118 -0
- package/skills/website-improvement/SKILL.md +6 -0
- package/skills/website-improvement/TEMPLATE.md +103 -0
- package/tools/audit/changelog-generate.py +176 -0
- package/tools/audit/check-coverage.py +483 -0
- package/tools/audit/doctor_assertions.py +256 -0
- package/tools/audit/example-qa.py +108 -0
- package/tools/audit/frontmatter-check.py +199 -0
- package/tools/audit/integration-check.py +95 -0
- package/tools/audit/korean-copy-check.py +161 -0
- package/tools/audit/link-check.py +146 -0
- package/tools/audit/local-ci.py +558 -0
- package/tools/audit/package-contents.py +723 -0
- package/tools/audit/package-smoke.py +22443 -0
- package/tools/audit/raw-hex-check.py +252 -0
- package/tools/audit/registry-smoke.py +8188 -0
- package/tools/audit/release-metadata.py +9832 -0
- package/tools/audit/run-all.py +351 -0
- package/tools/audit/smoke_assertions.py +12742 -0
- package/tools/audit/stability-review.py +332 -0
- package/tools/audit/stale-check.py +156 -0
- package/tools/migrations/add-version-frontmatter.py +132 -0
- package/tools/migrations/bump-last-updated.py +131 -0
- package/tools/migrations/promote-stability.py +172 -0
- package/tools/preview/README.md +58 -0
- package/tools/preview/render-tokens.py +454 -0
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
# `EmailLayout` — spec
|
|
2
|
+
|
|
3
|
+
> The standard responsive email layout. Wraps content in the table-based scaffolding required for cross-client compatibility.
|
|
4
|
+
|
|
5
|
+
## Purpose
|
|
6
|
+
|
|
7
|
+
Provides the canonical email body structure: centered 600px container, table-based layout, inline CSS, mobile-responsive media queries. Use for both transactional and marketing emails.
|
|
8
|
+
|
|
9
|
+
## Anatomy
|
|
10
|
+
|
|
11
|
+
```
|
|
12
|
+
┌────────────────────────────────────────────────┐
|
|
13
|
+
│ outer wrapper (full-width, bg color) │
|
|
14
|
+
│ ┌──────────────────────────────────────────┐ │
|
|
15
|
+
│ │ inner wrapper (600px max, centered) │ │
|
|
16
|
+
│ │ ┌────────────────────────────────────┐ │ │
|
|
17
|
+
│ │ │ Header (logo) │ │ │
|
|
18
|
+
│ │ ├────────────────────────────────────┤ │ │
|
|
19
|
+
│ │ │ │ │ │
|
|
20
|
+
│ │ │ Body content │ │ │
|
|
21
|
+
│ │ │ │ │ │
|
|
22
|
+
│ │ ├────────────────────────────────────┤ │ │
|
|
23
|
+
│ │ │ Footer (legal, unsubscribe) │ │ │
|
|
24
|
+
│ │ └────────────────────────────────────┘ │ │
|
|
25
|
+
│ └──────────────────────────────────────────┘ │
|
|
26
|
+
└────────────────────────────────────────────────┘
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## API (React Email-flavored)
|
|
30
|
+
|
|
31
|
+
```tsx
|
|
32
|
+
<EmailLayout
|
|
33
|
+
preheader="Your tracking number is FX12345..."
|
|
34
|
+
brandColor="#7C3AED"
|
|
35
|
+
>
|
|
36
|
+
<EmailLayout.Header>
|
|
37
|
+
<Logo />
|
|
38
|
+
</EmailLayout.Header>
|
|
39
|
+
|
|
40
|
+
<EmailLayout.Body>
|
|
41
|
+
<Heading>주문이 발송되었습니다</Heading>
|
|
42
|
+
<Paragraph>안녕하세요, 김민지 님.</Paragraph>
|
|
43
|
+
<Paragraph>주문번호 #1234가 방금 발송되었습니다.</Paragraph>
|
|
44
|
+
<Button href="https://...">배송 조회</Button>
|
|
45
|
+
</EmailLayout.Body>
|
|
46
|
+
|
|
47
|
+
<EmailLayout.Footer>
|
|
48
|
+
<UnsubscribeLink />
|
|
49
|
+
<CompanyInfo />
|
|
50
|
+
</EmailLayout.Footer>
|
|
51
|
+
</EmailLayout>
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
| Prop | Type | Default | Description |
|
|
55
|
+
| --- | --- | --- | --- |
|
|
56
|
+
| `preheader` | `string` | — | Preview text shown in inbox; hidden in body |
|
|
57
|
+
| `brandColor` | `string` | system | Used for buttons, links |
|
|
58
|
+
| `bgColor` | `string` | `"#FAFAFA"` | Outer wrapper bg |
|
|
59
|
+
| `width` | `number` | `600` | Inner container width |
|
|
60
|
+
| `subject` | `string` | — | Used for `<title>` (read by some clients) |
|
|
61
|
+
| `lang` | `string` | `"ko"` | HTML `lang` attribute |
|
|
62
|
+
| `dir` | `"ltr" \| "rtl"` | `"ltr"` | |
|
|
63
|
+
| `children` | `ReactNode` | — | Body |
|
|
64
|
+
|
|
65
|
+
## Generated HTML structure
|
|
66
|
+
|
|
67
|
+
```html
|
|
68
|
+
<!doctype html>
|
|
69
|
+
<html lang="ko">
|
|
70
|
+
<head>
|
|
71
|
+
<meta charset="utf-8">
|
|
72
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
73
|
+
<meta name="x-apple-disable-message-reformatting">
|
|
74
|
+
<title>{subject}</title>
|
|
75
|
+
<style>
|
|
76
|
+
@media (max-width: 480px) {
|
|
77
|
+
.container { width: 100% !important; }
|
|
78
|
+
}
|
|
79
|
+
</style>
|
|
80
|
+
</head>
|
|
81
|
+
<body style="margin:0;padding:0;background:#FAFAFA;">
|
|
82
|
+
|
|
83
|
+
<!-- Preheader (hidden) -->
|
|
84
|
+
<div style="display:none;max-height:0;overflow:hidden;">{preheader}</div>
|
|
85
|
+
|
|
86
|
+
<!-- Outer table -->
|
|
87
|
+
<table role="presentation" cellpadding="0" cellspacing="0" border="0" width="100%">
|
|
88
|
+
<tr>
|
|
89
|
+
<td align="center" style="padding: 24px 0;">
|
|
90
|
+
<!-- Inner container -->
|
|
91
|
+
<table role="presentation" cellpadding="0" cellspacing="0" border="0" class="container" width="600" style="max-width: 600px;">
|
|
92
|
+
<tr><td>{header}</td></tr>
|
|
93
|
+
<tr><td>{body}</td></tr>
|
|
94
|
+
<tr><td>{footer}</td></tr>
|
|
95
|
+
</table>
|
|
96
|
+
</td>
|
|
97
|
+
</tr>
|
|
98
|
+
</table>
|
|
99
|
+
|
|
100
|
+
</body>
|
|
101
|
+
</html>
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
## Sub-components
|
|
105
|
+
|
|
106
|
+
### `<EmailLayout.Header>`
|
|
107
|
+
|
|
108
|
+
Top of email — logo. Padding 24px around.
|
|
109
|
+
|
|
110
|
+
```tsx
|
|
111
|
+
<EmailLayout.Header>
|
|
112
|
+
<Img src="/logo.png" alt="Brand" width="120" height="40" />
|
|
113
|
+
</EmailLayout.Header>
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
### `<EmailLayout.Body>`
|
|
117
|
+
|
|
118
|
+
Main content. Padding 24px. White bg by default.
|
|
119
|
+
|
|
120
|
+
Composition: `<Heading>`, `<Paragraph>`, `<Button>`, `<Hr>` etc.
|
|
121
|
+
|
|
122
|
+
### `<EmailLayout.Footer>`
|
|
123
|
+
|
|
124
|
+
Legal info, unsubscribe. Smaller text.
|
|
125
|
+
|
|
126
|
+
For Korean: must include sender's company info per Korean spam law:
|
|
127
|
+
|
|
128
|
+
```
|
|
129
|
+
[회사명] · 사업자등록번호 123-45-67890
|
|
130
|
+
[서울시 강남구 테헤란로 123] · 대표 [이름]
|
|
131
|
+
문의: support@example.com
|
|
132
|
+
|
|
133
|
+
수신거부: [unsubscribe link]
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
## Inline CSS
|
|
137
|
+
|
|
138
|
+
All styles must be inline. Frameworks (react-email, mjml) do this automatically.
|
|
139
|
+
|
|
140
|
+
For hand-written: use a tool like `juice` or `inline-css` to inline `<style>` rules.
|
|
141
|
+
|
|
142
|
+
## Tokens consumed
|
|
143
|
+
|
|
144
|
+
Email tokens are a **subset** of the broader design system — limited to email-safe values:
|
|
145
|
+
|
|
146
|
+
```
|
|
147
|
+
brand color, brand-on-color, neutral-bg, neutral-bg-elevated,
|
|
148
|
+
text-primary, text-secondary, text-on-brand,
|
|
149
|
+
border-default, link-color
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
Plus typography:
|
|
153
|
+
- font-family-stack (with system fallback)
|
|
154
|
+
- font-size-xs through font-size-2xl
|
|
155
|
+
|
|
156
|
+
Don't reference tokens via CSS variables — inline only.
|
|
157
|
+
|
|
158
|
+
## Buttons (bulletproof)
|
|
159
|
+
|
|
160
|
+
The "Track order" button uses the bulletproof button pattern (table cell + styled `<a>`):
|
|
161
|
+
|
|
162
|
+
```html
|
|
163
|
+
<table role="presentation" cellpadding="0" cellspacing="0" border="0">
|
|
164
|
+
<tr>
|
|
165
|
+
<td bgcolor="#7C3AED" style="border-radius: 8px;">
|
|
166
|
+
<a href="..." style="display: inline-block; padding: 14px 32px; color: #FFFFFF; text-decoration: none; font-family: sans-serif; font-size: 16px; font-weight: 600; border-radius: 8px;">
|
|
167
|
+
Track order
|
|
168
|
+
</a>
|
|
169
|
+
</td>
|
|
170
|
+
</tr>
|
|
171
|
+
</table>
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
Wrap as a sub-component:
|
|
175
|
+
|
|
176
|
+
```tsx
|
|
177
|
+
<Button href="..." style={{ background: "#7C3AED", color: "#FFFFFF" }}>
|
|
178
|
+
Track order
|
|
179
|
+
</Button>
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
## Korean transactional template
|
|
183
|
+
|
|
184
|
+
```tsx
|
|
185
|
+
<EmailLayout preheader="주문번호 #1234가 발송되었습니다" lang="ko">
|
|
186
|
+
<EmailLayout.Header>
|
|
187
|
+
<Img src="/logo.png" alt="회사명" width="120" height="40" />
|
|
188
|
+
</EmailLayout.Header>
|
|
189
|
+
|
|
190
|
+
<EmailLayout.Body>
|
|
191
|
+
<Heading style={{ fontSize: 24, fontWeight: 700 }}>
|
|
192
|
+
주문이 발송되었습니다
|
|
193
|
+
</Heading>
|
|
194
|
+
|
|
195
|
+
<Paragraph>안녕하세요, {{first_name}} 님.</Paragraph>
|
|
196
|
+
<Paragraph>
|
|
197
|
+
주문번호 <strong>#1234</strong>가 방금 발송되었습니다.
|
|
198
|
+
예상 도착일은 {{delivery_date}}입니다.
|
|
199
|
+
</Paragraph>
|
|
200
|
+
|
|
201
|
+
<Button href="https://...">배송 조회</Button>
|
|
202
|
+
|
|
203
|
+
<Paragraph style={{ color: "#64748B", fontSize: 14, marginTop: 32 }}>
|
|
204
|
+
문의사항이 있으시면 언제든 답장해 주세요.
|
|
205
|
+
</Paragraph>
|
|
206
|
+
</EmailLayout.Body>
|
|
207
|
+
|
|
208
|
+
<EmailLayout.Footer>
|
|
209
|
+
<Paragraph style={{ fontSize: 12, color: "#94A3B8" }}>
|
|
210
|
+
[회사명] · 사업자등록번호 123-45-67890<br />
|
|
211
|
+
서울시 강남구 테헤란로 123<br />
|
|
212
|
+
문의: <Link href="mailto:support@example.com">support@example.com</Link>
|
|
213
|
+
</Paragraph>
|
|
214
|
+
<Paragraph style={{ fontSize: 12, color: "#94A3B8" }}>
|
|
215
|
+
<Link href="...">수신거부</Link>
|
|
216
|
+
</Paragraph>
|
|
217
|
+
</EmailLayout.Footer>
|
|
218
|
+
</EmailLayout>
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
## Mobile responsive
|
|
222
|
+
|
|
223
|
+
The `@media (max-width: 480px)` rules in the inline `<style>` block:
|
|
224
|
+
- `.container { width: 100% !important; }`
|
|
225
|
+
- Reduce padding (24px → 16px).
|
|
226
|
+
- Stack horizontal items vertically.
|
|
227
|
+
|
|
228
|
+
For multi-column layouts: wrap each column in a `class="stack"` and have the media query unset float / inline-block.
|
|
229
|
+
|
|
230
|
+
## Don't
|
|
231
|
+
|
|
232
|
+
- Don't put critical info only in images (image-load-blocked clients see nothing).
|
|
233
|
+
- Don't use `<button>` — Outlook ignores styles.
|
|
234
|
+
- Don't use SVG (Outlook breaks it; use PNG).
|
|
235
|
+
- Don't use flexbox / grid (Outlook breaks).
|
|
236
|
+
- Don't use web fonts as the only font (Outlook desktop falls back).
|
|
237
|
+
- Don't omit preheader text.
|
|
238
|
+
- Don't omit unsubscribe (legal in many jurisdictions including Korea).
|
|
239
|
+
- Don't omit `[광고]` prefix on Korean marketing emails (legal requirement).
|
|
240
|
+
|
|
241
|
+
## References
|
|
242
|
+
|
|
243
|
+
- React Email: [react.email](https://react.email/) — modern React-based authoring.
|
|
244
|
+
- MJML: [mjml.io](https://mjml.io/) — markup language for emails.
|
|
245
|
+
- Litmus: [litmus.com](https://www.litmus.com/) — preview across clients.
|
|
246
|
+
- Korean spam law (정보통신망 이용촉진 및 정보보호 등에 관한 법률) — see [`knowledge/i18n/korean-publishing.md`](../knowledge/i18n/korean-publishing.md).
|
|
247
|
+
|
|
248
|
+
## Cross-reference
|
|
249
|
+
|
|
250
|
+
- [`knowledge/patterns/email-design.md`](../knowledge/patterns/email-design.md) — broader email design rules
|
|
251
|
+
- [`knowledge/patterns/document-typography.md`](../knowledge/patterns/document-typography.md) — body type rules
|
|
252
|
+
- [`knowledge/i18n/korean-product-conventions.md`](../knowledge/i18n/korean-product-conventions.md) — Korean voice
|
|
253
|
+
- [`knowledge/i18n/korean-publishing.md`](../knowledge/i18n/korean-publishing.md) — Korean spam law
|
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
<!-- hand-written -->
|
|
2
|
+
# `EmptyState` (custom — no-data + filtered-empty + first-run shell) — spec
|
|
3
|
+
|
|
4
|
+
> One component for every "nothing here" surface in the product. Pairs with [`knowledge/illustration/spot-illustrations.md`](../knowledge/illustration/spot-illustrations.md).
|
|
5
|
+
|
|
6
|
+
## Purpose
|
|
7
|
+
|
|
8
|
+
Most apps have 5-15 empty surfaces (no projects yet, no search results, no notifications, filter shows nothing, error reduced to empty). Without a single component, each team hand-rolls one and they drift.
|
|
9
|
+
|
|
10
|
+
`EmptyState` enforces:
|
|
11
|
+
1. **One layout** — illustration + headline + description + CTA stack.
|
|
12
|
+
2. **One illustration source** — pulls from the system's spot-illustration set.
|
|
13
|
+
3. **Voice consistency** — encouraging, not pitying.
|
|
14
|
+
4. **Accessibility** — illustration is decorative; meaning lives in text.
|
|
15
|
+
|
|
16
|
+
## Anatomy
|
|
17
|
+
|
|
18
|
+
```
|
|
19
|
+
┌────────────────────────────────────────┐
|
|
20
|
+
│ │
|
|
21
|
+
│ [illustration] │ ← optional; 120-200px
|
|
22
|
+
│ │
|
|
23
|
+
│ 찾으시는 결과가 없어요 │ ← headline
|
|
24
|
+
│ 다른 키워드로 검색해 보세요 │ ← description
|
|
25
|
+
│ │
|
|
26
|
+
│ [Primary CTA] │ ← optional
|
|
27
|
+
│ [Secondary link] │ ← optional
|
|
28
|
+
└────────────────────────────────────────┘
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## API
|
|
32
|
+
|
|
33
|
+
```tsx
|
|
34
|
+
<EmptyState
|
|
35
|
+
illustration="search-empty"
|
|
36
|
+
title="찾으시는 결과가 없어요"
|
|
37
|
+
description="다른 키워드로 검색해 보세요."
|
|
38
|
+
primaryAction={{ label: "검색 초기화", onClick: clearFilters }}
|
|
39
|
+
secondaryAction={{ label: "도움말 보기", href: "/help" }}
|
|
40
|
+
/>
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
| Prop | Type | Default | Description |
|
|
44
|
+
| --- | --- | --- | --- |
|
|
45
|
+
| `illustration` | `string \| ReactNode` | `undefined` | Name from illustration registry (e.g., `"search-empty"`) OR custom node. Omit for compact variant. |
|
|
46
|
+
| `title` | `string` | — | Headline. Required. |
|
|
47
|
+
| `description` | `string \| ReactNode` | — | One-sentence explanation. Optional. |
|
|
48
|
+
| `primaryAction` | `{ label: string; onClick?: () => void; href?: string; loading?: boolean }` | — | Main CTA. Optional. |
|
|
49
|
+
| `secondaryAction` | `{ label: string; onClick?: () => void; href?: string }` | — | Secondary link / button. Optional. |
|
|
50
|
+
| `size` | `"sm" \| "md" \| "lg"` | `"md"` | Visual scale; affects illustration + spacing |
|
|
51
|
+
| `align` | `"center" \| "start"` | `"center"` | Center for full-page; start for inline-in-card |
|
|
52
|
+
| `variant` | `"default" \| "subtle" \| "card"` | `"default"` | Visual treatment |
|
|
53
|
+
|
|
54
|
+
## Variants
|
|
55
|
+
|
|
56
|
+
### `default`
|
|
57
|
+
|
|
58
|
+
Full vertical stack with illustration. Used for primary empty surfaces.
|
|
59
|
+
|
|
60
|
+
### `subtle` (no illustration)
|
|
61
|
+
|
|
62
|
+
Compact — title + description + actions only. For inline empty (within a panel, drawer, or small card).
|
|
63
|
+
|
|
64
|
+
### `card`
|
|
65
|
+
|
|
66
|
+
Wrapped in a bordered card. Used when the empty state sits next to populated cards (visual consistency).
|
|
67
|
+
|
|
68
|
+
## Sizes
|
|
69
|
+
|
|
70
|
+
| size | Illustration | Title | Padding |
|
|
71
|
+
| --- | --- | --- | --- |
|
|
72
|
+
| `sm` | 80px (or none) | 16px / 600 | `--space-md` |
|
|
73
|
+
| `md` (default) | 120-160px | 20px / 600 | `--space-lg` |
|
|
74
|
+
| `lg` | 200-240px | 24px / 600 | `--space-xl` |
|
|
75
|
+
|
|
76
|
+
Choose by surface size, not importance:
|
|
77
|
+
- Inline within a small card: `sm`
|
|
78
|
+
- Standard empty page: `md`
|
|
79
|
+
- Onboarding / splash / first-run: `lg`
|
|
80
|
+
|
|
81
|
+
## States
|
|
82
|
+
|
|
83
|
+
| State | Visual |
|
|
84
|
+
| --- | --- |
|
|
85
|
+
| Default | Illustration + title + description + actions |
|
|
86
|
+
| Loading (CTA loading) | Primary CTA shows spinner; rest unchanged |
|
|
87
|
+
| Compact (inline) | `subtle` variant; no illustration |
|
|
88
|
+
| Truly empty (no actions, no description) | Title only — rare; means user can't act anyway |
|
|
89
|
+
|
|
90
|
+
## Illustration registry
|
|
91
|
+
|
|
92
|
+
`EmptyState` doesn't render arbitrary SVG. It pulls from a registry keyed by name:
|
|
93
|
+
|
|
94
|
+
```ts
|
|
95
|
+
// illustrations/empty-state-registry.ts
|
|
96
|
+
export const emptyStateIllustrations = {
|
|
97
|
+
"search-empty": SearchEmptyIllustration,
|
|
98
|
+
"filter-empty": FilterEmptyIllustration,
|
|
99
|
+
"no-projects": NoProjectsIllustration,
|
|
100
|
+
"no-notifications": NoNotificationsIllustration,
|
|
101
|
+
"no-transactions": NoTransactionsIllustration,
|
|
102
|
+
"no-bookmarks": NoBookmarksIllustration,
|
|
103
|
+
} as const;
|
|
104
|
+
|
|
105
|
+
export type EmptyStateIllustration = keyof typeof emptyStateIllustrations;
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
This forces the team to add an illustration intentionally (TypeScript catches typos) and keeps the registry as a single source of truth.
|
|
109
|
+
|
|
110
|
+
For one-off custom illustrations, pass a node directly:
|
|
111
|
+
|
|
112
|
+
```tsx
|
|
113
|
+
<EmptyState illustration={<MyCustomSVG />} title="..." />
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
But prefer extending the registry over passing custom nodes ad-hoc.
|
|
117
|
+
|
|
118
|
+
## Voice rules
|
|
119
|
+
|
|
120
|
+
| Tone | ✓ | ✗ |
|
|
121
|
+
| --- | --- | --- |
|
|
122
|
+
| Encouraging | "첫 거래를 시작해 보세요" | "거래 내역이 없습니다" |
|
|
123
|
+
| Specific | "다른 키워드로 검색해 보세요" | "결과가 없습니다" |
|
|
124
|
+
| Honest about state | "아직 알림이 없어요" | "받은 알림이 없습니다 (0개)" |
|
|
125
|
+
| Action-oriented | CTA: "프로젝트 만들기" | CTA: "확인" |
|
|
126
|
+
|
|
127
|
+
For Korean fintech: 해요체 (~해요) is friendlier, 합쇼체 (~합니다) is formal. Toss leans 해요체; KakaoBank mixes; banks lean 합쇼체. Default to 해요체 for empty / encouraging moments.
|
|
128
|
+
|
|
129
|
+
## Tokens consumed
|
|
130
|
+
|
|
131
|
+
```
|
|
132
|
+
--color-text-primary (title)
|
|
133
|
+
--color-text-secondary (description)
|
|
134
|
+
--color-fg-muted (illustration accent — via currentColor)
|
|
135
|
+
--color-bg-default (default variant bg)
|
|
136
|
+
--color-bg-subtle (subtle / card variant bg)
|
|
137
|
+
--space-md, --space-lg, --space-xl
|
|
138
|
+
--radius-md (card variant)
|
|
139
|
+
--font-size-base, --font-size-lg, --font-size-xl
|
|
140
|
+
--font-weight-semibold (title)
|
|
141
|
+
--max-width-prose (description max-width for readability)
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
## Accessibility
|
|
145
|
+
|
|
146
|
+
- Illustration is **decorative** by default: rendered with `aria-hidden="true"`. The title + description carry meaning.
|
|
147
|
+
- If illustration is the only conveyance (rare; only when no text accompanies): pass `illustrationLabel` prop to set `role="img" aria-label="..."`.
|
|
148
|
+
- Title is `<h2>` by default; configurable via `as="h3"` for nested contexts.
|
|
149
|
+
- Empty state should NOT use `role="alert"` or `aria-live` — it's not an alert, just a layout.
|
|
150
|
+
- Primary action gets focus on initial render in modal contexts (matches focus management of the parent modal).
|
|
151
|
+
- Touch targets ≥ 44pt for action buttons.
|
|
152
|
+
|
|
153
|
+
## Code example
|
|
154
|
+
|
|
155
|
+
```tsx
|
|
156
|
+
function ProjectsScreen() {
|
|
157
|
+
const { data: projects, isLoading, isError, error } = useProjects();
|
|
158
|
+
const [filters, setFilters] = useFilters();
|
|
159
|
+
|
|
160
|
+
if (isLoading) return <ProjectsSkeleton />;
|
|
161
|
+
if (isError) return <ErrorState error={error} />;
|
|
162
|
+
|
|
163
|
+
if (projects.length === 0 && filters.isEmpty) {
|
|
164
|
+
// First-run empty
|
|
165
|
+
return (
|
|
166
|
+
<EmptyState
|
|
167
|
+
size="lg"
|
|
168
|
+
illustration="no-projects"
|
|
169
|
+
title="첫 프로젝트를 시작해 보세요"
|
|
170
|
+
description="프로젝트를 만들면 팀과 함께 작업할 수 있어요."
|
|
171
|
+
primaryAction={{ label: "프로젝트 만들기", onClick: openCreateProject }}
|
|
172
|
+
secondaryAction={{ label: "예제 살펴보기", href: "/examples" }}
|
|
173
|
+
/>
|
|
174
|
+
);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
if (projects.length === 0) {
|
|
178
|
+
// Filter-induced empty
|
|
179
|
+
return (
|
|
180
|
+
<EmptyState
|
|
181
|
+
illustration="filter-empty"
|
|
182
|
+
title="필터에 맞는 프로젝트가 없어요"
|
|
183
|
+
description="필터 조건을 바꾸거나 초기화해 보세요."
|
|
184
|
+
primaryAction={{ label: "필터 초기화", onClick: () => setFilters({}) }}
|
|
185
|
+
/>
|
|
186
|
+
);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
return <ProjectsList projects={projects} />;
|
|
190
|
+
}
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
## Layout (CSS)
|
|
194
|
+
|
|
195
|
+
```css
|
|
196
|
+
.empty-state {
|
|
197
|
+
display: flex;
|
|
198
|
+
flex-direction: column;
|
|
199
|
+
align-items: center;
|
|
200
|
+
text-align: center;
|
|
201
|
+
padding: var(--space-lg);
|
|
202
|
+
gap: var(--space-md);
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
.empty-state[data-align="start"] {
|
|
206
|
+
align-items: flex-start;
|
|
207
|
+
text-align: left;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
.empty-state[data-variant="card"] {
|
|
211
|
+
background: var(--color-bg-default);
|
|
212
|
+
border: 1px solid var(--color-border-default);
|
|
213
|
+
border-radius: var(--radius-md);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
.empty-state[data-variant="subtle"] {
|
|
217
|
+
background: var(--color-bg-subtle);
|
|
218
|
+
border-radius: var(--radius-md);
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
.empty-state__illustration { color: var(--color-brand-default); }
|
|
222
|
+
.empty-state__title { font-size: var(--font-size-lg); font-weight: 600; }
|
|
223
|
+
.empty-state__description {
|
|
224
|
+
font-size: var(--font-size-base);
|
|
225
|
+
color: var(--color-text-secondary);
|
|
226
|
+
max-width: var(--max-width-prose);
|
|
227
|
+
}
|
|
228
|
+
.empty-state__actions {
|
|
229
|
+
display: flex;
|
|
230
|
+
gap: var(--space-sm);
|
|
231
|
+
margin-top: var(--space-sm);
|
|
232
|
+
}
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
## Edge cases
|
|
236
|
+
|
|
237
|
+
- **Description longer than 2 lines**: truncate or break into 2 sentences. EmptyState is not a long-form explanation. If you need that, link to docs / help.
|
|
238
|
+
- **Both primary + secondary actions**: layout horizontally on desktop, stacked on mobile.
|
|
239
|
+
- **No illustration registered**: fall back to a generic neutral illustration (`generic-empty`). Don't render the wrapper at illustration size 0.
|
|
240
|
+
- **Loading state inside CTA**: pass `loading: true` to action; button shows spinner; rest of EmptyState is unchanged.
|
|
241
|
+
- **RTL**: layout mirrors automatically via `text-align: start`. Illustrations should be flippable or center-symmetric.
|
|
242
|
+
- **Dark mode**: illustrations theme via `currentColor` + CSS variables. Test all illustrations in dark.
|
|
243
|
+
- **Reduced motion**: if illustration is animated (Lottie), show static frame. See [`examples/component-lottie-player.md`](component-lottie-player.md).
|
|
244
|
+
|
|
245
|
+
## Don't
|
|
246
|
+
|
|
247
|
+
- Don't use `EmptyState` for errors. That's `ErrorState`. Different voice, different illustration.
|
|
248
|
+
- Don't put 3+ CTAs. Primary + secondary max. More choices = paralysis.
|
|
249
|
+
- Don't write descriptions longer than one sentence.
|
|
250
|
+
- Don't omit the title. "Empty" is unhelpful; "First time? Try X" is helpful.
|
|
251
|
+
- Don't put a mascot doing the same pose in every empty state. Vary the illustration.
|
|
252
|
+
- Don't over-celebrate. "Welcome! No projects yet 🎉" is wrong. The user has nothing yet — guide them.
|
|
253
|
+
|
|
254
|
+
## References
|
|
255
|
+
|
|
256
|
+
Patterns drawn from:
|
|
257
|
+
- shadcn/ui — no built-in EmptyState, but recipe in docs
|
|
258
|
+
- Mantine `Center + Stack + Text + Button` pattern
|
|
259
|
+
- Ant Design `Empty` component (close upstream match)
|
|
260
|
+
- Toss / KakaoBank empty-state patterns
|
|
261
|
+
|
|
262
|
+
## Cross-reference
|
|
263
|
+
|
|
264
|
+
- [`knowledge/illustration/spot-illustrations.md`](../knowledge/illustration/spot-illustrations.md) — illustration rules
|
|
265
|
+
- [`knowledge/illustration/illustration-systems.md`](../knowledge/illustration/illustration-systems.md) — system foundation
|
|
266
|
+
- [`examples/component-illustration.md`](component-illustration.md) — generic illustration display
|
|
267
|
+
- [`examples/component-result.md`](component-result.md) — success / error variants (different concern)
|
|
268
|
+
- [`examples/component-lottie-player.md`](component-lottie-player.md) — animated empty illustrations
|
|
269
|
+
- [`knowledge/i18n/korean-document-style.md`](../knowledge/i18n/korean-document-style.md) — 해요체 vs 합쇼체
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
# `Empty` — spec
|
|
2
|
+
|
|
3
|
+
> Synthesized from Ant Design `Empty` and shadcn-ui `empty`. The canonical "no data" placeholder. A simpler primitive than [`EmptyState`](component-empty-state.md) — no illustration registry, no required title/description structure. Use as a building block.
|
|
4
|
+
|
|
5
|
+
## Empty vs EmptyState
|
|
6
|
+
|
|
7
|
+
| | `Empty` (this spec) | `EmptyState` |
|
|
8
|
+
| --- | --- | --- |
|
|
9
|
+
| Origin | Ant + shadcn primitive | design-ai custom (Korean fintech-aware) |
|
|
10
|
+
| Illustration | Optional, free-form | Registry-backed, typesafe names |
|
|
11
|
+
| Voice rules | None enforced | KR voice + 해요체 default |
|
|
12
|
+
| Use | Inline within a component (table empty, dropdown empty) | Full-page or section-level surfaces |
|
|
13
|
+
|
|
14
|
+
For most pages: use `EmptyState`. For inline empty within a component: use `Empty`.
|
|
15
|
+
|
|
16
|
+
## Anatomy
|
|
17
|
+
|
|
18
|
+
```
|
|
19
|
+
[optional image / icon]
|
|
20
|
+
|
|
21
|
+
No data found
|
|
22
|
+
|
|
23
|
+
Try a different search.
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## API
|
|
27
|
+
|
|
28
|
+
```tsx
|
|
29
|
+
<Empty>
|
|
30
|
+
No items
|
|
31
|
+
</Empty>
|
|
32
|
+
|
|
33
|
+
<Empty
|
|
34
|
+
image={<SearchIcon className="text-muted size-12" />}
|
|
35
|
+
description="No results match your search."
|
|
36
|
+
>
|
|
37
|
+
<Button onClick={clearFilters}>Clear filters</Button>
|
|
38
|
+
</Empty>
|
|
39
|
+
|
|
40
|
+
<Empty image="default">
|
|
41
|
+
No projects yet
|
|
42
|
+
</Empty>
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
| Prop | Type | Default | Description |
|
|
46
|
+
| --- | --- | --- | --- |
|
|
47
|
+
| `image` | `ReactNode \| "default" \| "presented"` | `"default"` | Visual; `"default"` = generic empty graphic, `"presented"` = simpler, custom node = override |
|
|
48
|
+
| `description` | `ReactNode` | — | Text explanation |
|
|
49
|
+
| `children` | `ReactNode` | — | Action(s) — typically buttons |
|
|
50
|
+
| `imageStyle` | `CSSProperties` | — | Style override on image |
|
|
51
|
+
|
|
52
|
+
## Variants
|
|
53
|
+
|
|
54
|
+
### Default (with image)
|
|
55
|
+
|
|
56
|
+
Generic empty illustration above text. Suitable for page-level empty.
|
|
57
|
+
|
|
58
|
+
### Image-only
|
|
59
|
+
|
|
60
|
+
`image="presented"` shows simpler graphic (often just an icon). Use inline / in dense surfaces.
|
|
61
|
+
|
|
62
|
+
### No image
|
|
63
|
+
|
|
64
|
+
`image={null}` shows just text. Use for very dense contexts (table cell empty, dropdown "no results").
|
|
65
|
+
|
|
66
|
+
## States
|
|
67
|
+
|
|
68
|
+
Stateless. Empty is purely presentational.
|
|
69
|
+
|
|
70
|
+
## Tokens consumed
|
|
71
|
+
|
|
72
|
+
```
|
|
73
|
+
--color-fg-default (description)
|
|
74
|
+
--color-fg-muted (default image / icon)
|
|
75
|
+
--space-md, --space-lg
|
|
76
|
+
--font-size-sm, --font-size-base
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
## Accessibility
|
|
80
|
+
|
|
81
|
+
- Container: `role="status"` so screen reader announces "Empty" content.
|
|
82
|
+
- Image: `aria-hidden="true"` if decorative; `alt` text only if conveying additional meaning.
|
|
83
|
+
- Don't use `role="alert"` — empty isn't an error.
|
|
84
|
+
|
|
85
|
+
## Use cases
|
|
86
|
+
|
|
87
|
+
### Inside a Table
|
|
88
|
+
|
|
89
|
+
```tsx
|
|
90
|
+
<Table>
|
|
91
|
+
<TableBody>
|
|
92
|
+
{rows.length === 0 ? (
|
|
93
|
+
<TableRow>
|
|
94
|
+
<TableCell colSpan={columns.length}>
|
|
95
|
+
<Empty description="No data" />
|
|
96
|
+
</TableCell>
|
|
97
|
+
</TableRow>
|
|
98
|
+
) : rows.map(...)}
|
|
99
|
+
</TableBody>
|
|
100
|
+
</Table>
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
### Inside a Combobox / Dropdown
|
|
104
|
+
|
|
105
|
+
```tsx
|
|
106
|
+
<Combobox.Empty>
|
|
107
|
+
<Empty image={null} description="No matches" />
|
|
108
|
+
</Combobox.Empty>
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
### Inside a List / feed
|
|
112
|
+
|
|
113
|
+
```tsx
|
|
114
|
+
{notifications.length === 0 && (
|
|
115
|
+
<Empty
|
|
116
|
+
image={<BellIcon className="text-muted size-10" />}
|
|
117
|
+
description="No notifications yet."
|
|
118
|
+
/>
|
|
119
|
+
)}
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
### Page-level — prefer EmptyState
|
|
123
|
+
|
|
124
|
+
```tsx
|
|
125
|
+
{/* For full pages, use EmptyState — registry-backed illustrations + Korean voice */}
|
|
126
|
+
<EmptyState
|
|
127
|
+
size="lg"
|
|
128
|
+
illustration="no-projects"
|
|
129
|
+
title="첫 프로젝트를 시작해 보세요"
|
|
130
|
+
description="프로젝트를 만들면 팀과 함께 작업할 수 있어요."
|
|
131
|
+
primaryAction={{ label: "프로젝트 만들기", onClick: createProject }}
|
|
132
|
+
/>
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
See [`component-empty-state.md`](component-empty-state.md).
|
|
136
|
+
|
|
137
|
+
## Korean conventions
|
|
138
|
+
|
|
139
|
+
For inline `Empty`:
|
|
140
|
+
- "데이터가 없어요" (해요체) / "데이터가 없습니다" (합쇼체)
|
|
141
|
+
- "결과가 없어요" / "결과가 없습니다"
|
|
142
|
+
- "해당하는 항목이 없어요"
|
|
143
|
+
|
|
144
|
+
Match the surrounding component's voice level.
|
|
145
|
+
|
|
146
|
+
## Edge cases
|
|
147
|
+
|
|
148
|
+
- **Inside a scrollable list**: Empty shouldn't fill the entire scroll viewport (looks broken). Cap at ~200px tall; align to top.
|
|
149
|
+
- **Loading state**: don't show Empty while data is loading — show Skeleton or Spinner instead. Empty is for "loaded with zero results", not "still loading".
|
|
150
|
+
- **Empty in a dropdown / command palette**: keep it brief, no image (single-line is fine).
|
|
151
|
+
- **Action button inside Empty**: works, but consider whether the user can act from this surface OR they need to navigate away. If "Create" works inline → button. If user needs to go to /create → link.
|
|
152
|
+
- **Reduced motion**: not applicable — Empty is static.
|
|
153
|
+
- **Dark mode**: tokens cascade; verify default image SVG visible against dark bg.
|
|
154
|
+
|
|
155
|
+
## Don't
|
|
156
|
+
|
|
157
|
+
- Don't use Empty for errors. Use Result with status="error" or an error pattern.
|
|
158
|
+
- Don't show Empty before data has loaded. Show loading state first.
|
|
159
|
+
- Don't make inline Empty as large as a full-page EmptyState. Match scale.
|
|
160
|
+
- Don't omit description for non-obvious empty states. Tell users why.
|
|
161
|
+
- Don't put long copy in inline Empty. Keep it < 1 sentence.
|
|
162
|
+
|
|
163
|
+
## References
|
|
164
|
+
|
|
165
|
+
- Ant: [`Empty`](../refs/ant-design/components/empty)
|
|
166
|
+
- shadcn-ui: [`empty`](../refs/shadcn-ui/apps/v4/registry/new-york-v4/ui/empty.tsx)
|
|
167
|
+
|
|
168
|
+
## Cross-reference
|
|
169
|
+
|
|
170
|
+
- [`examples/component-empty-state.md`](component-empty-state.md) — full-page custom variant with KR voice + illustration registry
|
|
171
|
+
- [`examples/component-result.md`](component-result.md) — for error / success full-page surfaces
|
|
172
|
+
- [`examples/component-table.md`](component-table.md) — common consumer of inline Empty
|