@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,295 @@
|
|
|
1
|
+
# `NavigationMenu` — spec
|
|
2
|
+
|
|
3
|
+
> Synthesized from shadcn-ui `navigation-menu` (Radix) and patterns from MUI / Ant menu primitives. Top-of-page horizontal navigation with optional megamenu / dropdown panels. Common in marketing sites and B2B SaaS app headers.
|
|
4
|
+
|
|
5
|
+
## When to use
|
|
6
|
+
|
|
7
|
+
- **Marketing site top nav** with Product / Solutions / Resources mega-panels.
|
|
8
|
+
- **SaaS app header** for top-level sections.
|
|
9
|
+
- **Documentation site** primary nav.
|
|
10
|
+
|
|
11
|
+
When NOT to use:
|
|
12
|
+
- Vertical nav contexts → `Sidebar`.
|
|
13
|
+
- Action menus → `DropdownMenu`.
|
|
14
|
+
- Mobile-only contexts → `MobileNavigation` (separate component).
|
|
15
|
+
|
|
16
|
+
## Anatomy
|
|
17
|
+
|
|
18
|
+
```
|
|
19
|
+
[Logo] Product ▾ Solutions ▾ Pricing Docs [Sign in]
|
|
20
|
+
↓
|
|
21
|
+
┌────────────────────────────────────┐
|
|
22
|
+
│ Product overview [→] │
|
|
23
|
+
│ A platform for... │
|
|
24
|
+
│ │
|
|
25
|
+
│ Components Themes │
|
|
26
|
+
│ Templates Pricing │
|
|
27
|
+
│ │
|
|
28
|
+
│ Featured: New design tokens │
|
|
29
|
+
└────────────────────────────────────┘
|
|
30
|
+
(mega-menu panel, hover/click triggered)
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## API
|
|
34
|
+
|
|
35
|
+
```tsx
|
|
36
|
+
<NavigationMenu>
|
|
37
|
+
<NavigationMenu.List>
|
|
38
|
+
<NavigationMenu.Item>
|
|
39
|
+
<NavigationMenu.Trigger>Product</NavigationMenu.Trigger>
|
|
40
|
+
<NavigationMenu.Content>
|
|
41
|
+
<ul className="grid gap-2 p-4 md:w-[500px] grid-cols-2">
|
|
42
|
+
<li>
|
|
43
|
+
<NavigationMenu.Link href="/components">
|
|
44
|
+
<h3>Components</h3>
|
|
45
|
+
<p>Pre-built primitives.</p>
|
|
46
|
+
</NavigationMenu.Link>
|
|
47
|
+
</li>
|
|
48
|
+
<li>
|
|
49
|
+
<NavigationMenu.Link href="/themes">
|
|
50
|
+
<h3>Themes</h3>
|
|
51
|
+
<p>Beautiful color palettes.</p>
|
|
52
|
+
</NavigationMenu.Link>
|
|
53
|
+
</li>
|
|
54
|
+
</ul>
|
|
55
|
+
</NavigationMenu.Content>
|
|
56
|
+
</NavigationMenu.Item>
|
|
57
|
+
|
|
58
|
+
<NavigationMenu.Item>
|
|
59
|
+
<NavigationMenu.Link href="/pricing">Pricing</NavigationMenu.Link>
|
|
60
|
+
</NavigationMenu.Item>
|
|
61
|
+
|
|
62
|
+
<NavigationMenu.Item>
|
|
63
|
+
<NavigationMenu.Link href="/docs">Docs</NavigationMenu.Link>
|
|
64
|
+
</NavigationMenu.Item>
|
|
65
|
+
</NavigationMenu.List>
|
|
66
|
+
|
|
67
|
+
<NavigationMenu.Indicator /> {/* Animated underline */}
|
|
68
|
+
<NavigationMenu.Viewport /> {/* Container for active panel */}
|
|
69
|
+
</NavigationMenu>
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## Composition
|
|
73
|
+
|
|
74
|
+
| Part | Purpose |
|
|
75
|
+
| --- | --- |
|
|
76
|
+
| `NavigationMenu` | Wrapper |
|
|
77
|
+
| `List` | Horizontal list of top-level items |
|
|
78
|
+
| `Item` | Wrapper for a top-level entry |
|
|
79
|
+
| `Trigger` | Hover/click target that opens a panel |
|
|
80
|
+
| `Content` | Mega-menu panel content |
|
|
81
|
+
| `Link` | A direct navigation link (no panel) |
|
|
82
|
+
| `Indicator` | Animated underline / arrow pointing at active item |
|
|
83
|
+
| `Viewport` | Single shared container that panels animate into |
|
|
84
|
+
|
|
85
|
+
## Trigger modes
|
|
86
|
+
|
|
87
|
+
### Hover (marketing default)
|
|
88
|
+
|
|
89
|
+
Hover trigger → panel opens after 200ms. Mouse-leave → closes after 300ms (graceful).
|
|
90
|
+
|
|
91
|
+
### Click (for product apps)
|
|
92
|
+
|
|
93
|
+
Tap-or-click only. More predictable; preferred when nav has many panels.
|
|
94
|
+
|
|
95
|
+
### Mobile
|
|
96
|
+
|
|
97
|
+
NavigationMenu doesn't translate to mobile directly. On small screens:
|
|
98
|
+
- Collapse to a hamburger menu that opens a `Sheet`.
|
|
99
|
+
- Or use `MobileNavigation` (separate component).
|
|
100
|
+
|
|
101
|
+
## Mega-menu layouts
|
|
102
|
+
|
|
103
|
+
### List
|
|
104
|
+
|
|
105
|
+
```
|
|
106
|
+
┌─────────────────────────┐
|
|
107
|
+
│ Item 1 │
|
|
108
|
+
│ Item 2 │
|
|
109
|
+
│ Item 3 │
|
|
110
|
+
│ ───── │
|
|
111
|
+
│ Featured: ... │
|
|
112
|
+
└─────────────────────────┘
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
### Grid (most common)
|
|
116
|
+
|
|
117
|
+
```
|
|
118
|
+
┌──────────────┬──────────────┐
|
|
119
|
+
│ Components │ Themes │
|
|
120
|
+
│ Pre-built... │ Color... │
|
|
121
|
+
├──────────────┼──────────────┤
|
|
122
|
+
│ Templates │ Pricing │
|
|
123
|
+
│ Starter... │ Plans... │
|
|
124
|
+
└──────────────┴──────────────┘
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
### Featured + grid
|
|
128
|
+
|
|
129
|
+
```
|
|
130
|
+
┌─────────────┬───────────────────┐
|
|
131
|
+
│ │ Components │
|
|
132
|
+
│ Hero │ Themes │
|
|
133
|
+
│ Promo │ Templates │
|
|
134
|
+
│ + image │ Pricing │
|
|
135
|
+
│ │ │
|
|
136
|
+
└─────────────┴───────────────────┘
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
## States
|
|
140
|
+
|
|
141
|
+
| State | Visual |
|
|
142
|
+
| --- | --- |
|
|
143
|
+
| Resting | All triggers visible, no panel |
|
|
144
|
+
| Trigger hover | Underline indicator slides under hovered item |
|
|
145
|
+
| Panel open | Content visible below; Indicator points at active trigger |
|
|
146
|
+
| Switching panels | Indicator slides; Content cross-fades |
|
|
147
|
+
| Closing | Indicator hides; Content fades |
|
|
148
|
+
|
|
149
|
+
## Animations
|
|
150
|
+
|
|
151
|
+
```
|
|
152
|
+
Indicator: 200ms slide between triggers (transform: translateX)
|
|
153
|
+
Panel: 250ms cross-fade + slight slide (translateY -4px → 0)
|
|
154
|
+
Reduced motion: instant
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
## Tokens consumed
|
|
158
|
+
|
|
159
|
+
```
|
|
160
|
+
--color-bg-default
|
|
161
|
+
--color-fg-default
|
|
162
|
+
--color-fg-muted (panel description text)
|
|
163
|
+
--color-bg-overlay (panel bg)
|
|
164
|
+
--color-bg-overlay-hover (panel item hover)
|
|
165
|
+
--color-brand-default (active indicator)
|
|
166
|
+
--color-border-default
|
|
167
|
+
--radius-md
|
|
168
|
+
--shadow-overlay
|
|
169
|
+
--space-md, --space-lg
|
|
170
|
+
--font-size-base
|
|
171
|
+
--font-weight-medium
|
|
172
|
+
--motion-medium (panel transition)
|
|
173
|
+
--ease-out
|
|
174
|
+
--z-overlay
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
## Accessibility
|
|
178
|
+
|
|
179
|
+
- Wrapper: `<nav aria-label="Main">`.
|
|
180
|
+
- List: `<ul role="menubar">`.
|
|
181
|
+
- Item: `<li>` containing either `<NavigationMenu.Trigger>` or `<NavigationMenu.Link>`.
|
|
182
|
+
- Trigger: `<button aria-haspopup="true" aria-expanded="...">`.
|
|
183
|
+
- Content: `role="menu"` (or just rendered list).
|
|
184
|
+
- Active page: `aria-current="page"` on the corresponding link.
|
|
185
|
+
- Keyboard:
|
|
186
|
+
- Tab moves between top-level items.
|
|
187
|
+
- Enter / Space on Trigger opens panel; arrows navigate within panel.
|
|
188
|
+
- Esc closes panel.
|
|
189
|
+
- For touch: hover doesn't fire; panels open on tap (close on second tap of same trigger or outside).
|
|
190
|
+
|
|
191
|
+
## Mobile fallback pattern
|
|
192
|
+
|
|
193
|
+
```tsx
|
|
194
|
+
function ResponsiveNav() {
|
|
195
|
+
const isDesktop = useMediaQuery("(min-width: 1024px)");
|
|
196
|
+
|
|
197
|
+
if (isDesktop) {
|
|
198
|
+
return <NavigationMenu>...</NavigationMenu>;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
return (
|
|
202
|
+
<Sheet>
|
|
203
|
+
<Sheet.Trigger asChild>
|
|
204
|
+
<Button variant="ghost"><MenuIcon /></Button>
|
|
205
|
+
</Sheet.Trigger>
|
|
206
|
+
<Sheet.Content side="right">
|
|
207
|
+
<MobileNavList items={navItems} />
|
|
208
|
+
</Sheet.Content>
|
|
209
|
+
</Sheet>
|
|
210
|
+
);
|
|
211
|
+
}
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
## Code example (marketing site)
|
|
215
|
+
|
|
216
|
+
```tsx
|
|
217
|
+
function MarketingHeader() {
|
|
218
|
+
return (
|
|
219
|
+
<header className="site-header">
|
|
220
|
+
<Logo />
|
|
221
|
+
|
|
222
|
+
<NavigationMenu>
|
|
223
|
+
<NavigationMenu.List>
|
|
224
|
+
<NavigationMenu.Item>
|
|
225
|
+
<NavigationMenu.Trigger>Product</NavigationMenu.Trigger>
|
|
226
|
+
<NavigationMenu.Content>
|
|
227
|
+
<div className="mega-grid">
|
|
228
|
+
<div className="featured">
|
|
229
|
+
<Image src="/hero.jpg" alt="" />
|
|
230
|
+
<h3>What's new</h3>
|
|
231
|
+
<p>v3.2 just shipped — explore the spatial design domain.</p>
|
|
232
|
+
<a href="/changelog">See changelog →</a>
|
|
233
|
+
</div>
|
|
234
|
+
<ul className="links">
|
|
235
|
+
<li><a href="/components">Components</a></li>
|
|
236
|
+
<li><a href="/themes">Themes</a></li>
|
|
237
|
+
<li><a href="/templates">Templates</a></li>
|
|
238
|
+
</ul>
|
|
239
|
+
</div>
|
|
240
|
+
</NavigationMenu.Content>
|
|
241
|
+
</NavigationMenu.Item>
|
|
242
|
+
|
|
243
|
+
<NavigationMenu.Item>
|
|
244
|
+
<NavigationMenu.Link href="/pricing">Pricing</NavigationMenu.Link>
|
|
245
|
+
</NavigationMenu.Item>
|
|
246
|
+
|
|
247
|
+
<NavigationMenu.Item>
|
|
248
|
+
<NavigationMenu.Link href="/docs">Docs</NavigationMenu.Link>
|
|
249
|
+
</NavigationMenu.Item>
|
|
250
|
+
</NavigationMenu.List>
|
|
251
|
+
|
|
252
|
+
<NavigationMenu.Indicator />
|
|
253
|
+
<NavigationMenu.Viewport />
|
|
254
|
+
</NavigationMenu>
|
|
255
|
+
|
|
256
|
+
<div className="actions">
|
|
257
|
+
<a href="/login">Sign in</a>
|
|
258
|
+
<Button asChild><a href="/signup">Sign up</a></Button>
|
|
259
|
+
</div>
|
|
260
|
+
</header>
|
|
261
|
+
);
|
|
262
|
+
}
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
## Edge cases
|
|
266
|
+
|
|
267
|
+
- **Single-item nav** (only one trigger): NavigationMenu is overkill. Just use a button.
|
|
268
|
+
- **Trigger with active sub-route**: highlight Trigger when child route active (`aria-current="true"` if any descendant link matches current URL).
|
|
269
|
+
- **Mega-panel taller than viewport**: cap height; scroll inside panel.
|
|
270
|
+
- **Panel with images**: lazy-load; image-loading shouldn't block panel paint.
|
|
271
|
+
- **Hover into panel from trigger**: panel must remain open during hover-traversal; use `closeDelay`.
|
|
272
|
+
- **Mobile breakpoint switch mid-session**: re-render with appropriate component.
|
|
273
|
+
- **RTL**: flip indicator direction + alignment.
|
|
274
|
+
|
|
275
|
+
## Don't
|
|
276
|
+
|
|
277
|
+
- Don't use NavigationMenu for in-app navigation when a Sidebar is more appropriate. Top nav for marketing-feel + flat sites; sidebar for app-shell.
|
|
278
|
+
- Don't pack 7+ top-level items. Group via mega-menu or rethink IA.
|
|
279
|
+
- Don't ship without a mobile fallback. Top nav doesn't work on phones.
|
|
280
|
+
- Don't omit `aria-current` on active links.
|
|
281
|
+
- Don't have hover-only triggers on touch devices.
|
|
282
|
+
- Don't disable Esc to close panels.
|
|
283
|
+
|
|
284
|
+
## References
|
|
285
|
+
|
|
286
|
+
- shadcn-ui: [`navigation-menu`](../refs/shadcn-ui/apps/v4/registry/new-york-v4/ui/navigation-menu.tsx) (Radix)
|
|
287
|
+
- Patterns: Stripe, Linear, Vercel marketing nav
|
|
288
|
+
|
|
289
|
+
## Cross-reference
|
|
290
|
+
|
|
291
|
+
- [`examples/component-sidebar.md`](component-sidebar.md) — vertical nav
|
|
292
|
+
- [`examples/component-app-bar.md`](component-app-bar.md) — top app bar
|
|
293
|
+
- [`examples/component-sheet.md`](component-sheet.md) — mobile fallback
|
|
294
|
+
- [`knowledge/patterns/mobile-navigation.md`](../knowledge/patterns/mobile-navigation.md)
|
|
295
|
+
- [`knowledge/patterns/landing-hero-design.md`](../knowledge/patterns/landing-hero-design.md)
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
# `Notification` — spec
|
|
2
|
+
|
|
3
|
+
> Synthesized from Ant Design `Notification`. Richer card-style notification — title + description + optional actions, anchored to a screen corner. Distinct from `Toast` (smaller, action-focused), `Message` (top thin pill), and `Banner` (persistent in-page).
|
|
4
|
+
|
|
5
|
+
## When to use
|
|
6
|
+
|
|
7
|
+
- **System-level events** that need title + body description.
|
|
8
|
+
- **Multi-action notifications** ("New message from John" with Reply / Mark read buttons).
|
|
9
|
+
- **Push-notification surface** for in-app-only events.
|
|
10
|
+
|
|
11
|
+
When NOT to use:
|
|
12
|
+
- Brief result confirmation (use Message or Toast).
|
|
13
|
+
- Critical actions blocking workflow (use Modal / AlertDialog).
|
|
14
|
+
- In-page persistent strip (use Banner).
|
|
15
|
+
|
|
16
|
+
## Anatomy
|
|
17
|
+
|
|
18
|
+
```
|
|
19
|
+
┌───────────────────────────┐
|
|
20
|
+
│ ⓘ 새 알림 │
|
|
21
|
+
│ @sungjin이 댓글을 │
|
|
22
|
+
│ 남겼어요. │
|
|
23
|
+
│ │
|
|
24
|
+
│ [답장] [읽음 처리] [×] │
|
|
25
|
+
└───────────────────────────┘
|
|
26
|
+
↑ top-right corner
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## API
|
|
30
|
+
|
|
31
|
+
```tsx
|
|
32
|
+
import { notification } from "antd";
|
|
33
|
+
|
|
34
|
+
notification.open({
|
|
35
|
+
message: "새 알림",
|
|
36
|
+
description: "@sungjin이 댓글을 남겼어요.",
|
|
37
|
+
placement: "topRight",
|
|
38
|
+
duration: 4.5,
|
|
39
|
+
btn: <Button onClick={reply}>답장</Button>,
|
|
40
|
+
onClose: handleClose,
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
notification.success({ message: "성공", description: "저장됐어요." });
|
|
44
|
+
notification.error({ message: "실패", description: "저장에 실패했어요." });
|
|
45
|
+
notification.info({ message: "알림", description: "..." });
|
|
46
|
+
notification.warning({ message: "경고", description: "..." });
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
| Config field | Description |
|
|
50
|
+
| --- | --- |
|
|
51
|
+
| `message` | Title (bold) |
|
|
52
|
+
| `description` | Body (multiple lines OK) |
|
|
53
|
+
| `placement` | `"top" \| "topLeft" \| "topRight" \| "bottom" \| "bottomLeft" \| "bottomRight"` |
|
|
54
|
+
| `duration` | Seconds; 0 = persistent until dismissed |
|
|
55
|
+
| `key` | Unique key (replace existing) |
|
|
56
|
+
| `btn` | Custom action button(s) |
|
|
57
|
+
| `onClose` | Dismiss callback |
|
|
58
|
+
| `onClick` | Click on notification (optional) |
|
|
59
|
+
| `icon` | Custom icon override |
|
|
60
|
+
| `closable` | Show × dismiss button |
|
|
61
|
+
|
|
62
|
+
## States
|
|
63
|
+
|
|
64
|
+
| Severity | Visual |
|
|
65
|
+
| --- | --- |
|
|
66
|
+
| `open` (neutral) | Generic info icon |
|
|
67
|
+
| `success` | Green check |
|
|
68
|
+
| `error` | Red X |
|
|
69
|
+
| `info` | Blue info |
|
|
70
|
+
| `warning` | Amber triangle |
|
|
71
|
+
|
|
72
|
+
## Animation
|
|
73
|
+
|
|
74
|
+
```
|
|
75
|
+
Enter: slide-in from corner (250ms)
|
|
76
|
+
Hold: full opacity for `duration` seconds
|
|
77
|
+
Exit: fade + slide-out (200ms)
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
Reduced motion: fade only.
|
|
81
|
+
|
|
82
|
+
## Stacking
|
|
83
|
+
|
|
84
|
+
Multiple Notifications stack vertically in their corner. Newest on top (or bottom — configurable).
|
|
85
|
+
|
|
86
|
+
Cap visible: 3-5. Beyond that, oldest collapse to "+ N more" indicator.
|
|
87
|
+
|
|
88
|
+
## Tokens consumed
|
|
89
|
+
|
|
90
|
+
```
|
|
91
|
+
--notification-bg
|
|
92
|
+
--notification-fg
|
|
93
|
+
--notification-fg-muted (description)
|
|
94
|
+
--notification-success-icon
|
|
95
|
+
--notification-error-icon
|
|
96
|
+
--notification-warning-icon
|
|
97
|
+
--notification-info-icon
|
|
98
|
+
--notification-shadow
|
|
99
|
+
--radius-md
|
|
100
|
+
--space-md, --space-lg
|
|
101
|
+
--font-size-sm (description)
|
|
102
|
+
--font-weight-medium (title)
|
|
103
|
+
--motion-medium
|
|
104
|
+
--z-notification (above modals OR below; pick consciously)
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
## Accessibility
|
|
108
|
+
|
|
109
|
+
- `role="alert"` for time-sensitive (errors, warnings).
|
|
110
|
+
- `role="status"` for non-urgent.
|
|
111
|
+
- `aria-live="polite"` (status) or `assertive` (alert) — be sparing with assertive.
|
|
112
|
+
- Focus management: Notification doesn't steal focus by default. For action-required: persistent + focus the first button.
|
|
113
|
+
- Touch target ≥ 44pt for action buttons.
|
|
114
|
+
|
|
115
|
+
## Korean conventions
|
|
116
|
+
|
|
117
|
+
```
|
|
118
|
+
새 메시지
|
|
119
|
+
@sungjin이 메시지를 보냈어요.
|
|
120
|
+
[답장] [확인]
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
- 해요체 for casual brands; 합쇼체 for formal / banking.
|
|
124
|
+
- Title: 20자 이내; Body: 50자 이내.
|
|
125
|
+
- For 카카오톡 / KakaoTalk-style notifications: avatar + title + preview.
|
|
126
|
+
|
|
127
|
+
## Code example
|
|
128
|
+
|
|
129
|
+
```tsx
|
|
130
|
+
function NewMessageNotification({ message }: Props) {
|
|
131
|
+
return (
|
|
132
|
+
notification.info({
|
|
133
|
+
message: `새 메시지 — ${message.from}`,
|
|
134
|
+
description: message.preview,
|
|
135
|
+
placement: "topRight",
|
|
136
|
+
duration: 4.5,
|
|
137
|
+
icon: <Avatar src={message.fromAvatar} size="sm" />,
|
|
138
|
+
btn: (
|
|
139
|
+
<Button size="sm" onClick={() => navigate(`/messages/${message.id}`)}>
|
|
140
|
+
확인
|
|
141
|
+
</Button>
|
|
142
|
+
),
|
|
143
|
+
})
|
|
144
|
+
);
|
|
145
|
+
}
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
## Don't
|
|
149
|
+
|
|
150
|
+
- Don't use Notification for fleeting confirmation. Use Message or Toast.
|
|
151
|
+
- Don't show 6+ Notifications stacked. Cap visible.
|
|
152
|
+
- Don't auto-show on page load — feels like spam. Triggered by user action only.
|
|
153
|
+
- Don't put long body text. Description ≤ 2 lines; longer = open a Modal or page.
|
|
154
|
+
- Don't omit dismiss button on persistent notifications.
|
|
155
|
+
|
|
156
|
+
## References
|
|
157
|
+
|
|
158
|
+
- Ant: [`Notification`](../refs/ant-design/components/notification)
|
|
159
|
+
- Native browser Notification API (different — uses OS-level notifications)
|
|
160
|
+
- iOS / Android notification card patterns
|
|
161
|
+
|
|
162
|
+
## Cross-reference
|
|
163
|
+
|
|
164
|
+
- [`examples/component-toast.md`](component-toast.md) — smaller corner variant with Undo
|
|
165
|
+
- [`examples/component-message.md`](component-message.md) — top thin pill
|
|
166
|
+
- [`examples/component-banner.md`](component-banner.md) — persistent in-page strip
|
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
# `OTPCountdown` (custom — Korean SMS verification timer) — spec
|
|
2
|
+
|
|
3
|
+
> Korean fintech custom component. Pairs with `InputOTP` to manage SMS code resend cooldown + expiration timer. Shipped in every Korean SMS-auth flow.
|
|
4
|
+
|
|
5
|
+
## Purpose
|
|
6
|
+
|
|
7
|
+
Show:
|
|
8
|
+
1. **Time until code expires** (typically 3 minutes for SMS verification).
|
|
9
|
+
2. **Time until resend allowed** (typically 30–60 seconds cooldown).
|
|
10
|
+
3. **Resend button** when cooldown completes.
|
|
11
|
+
|
|
12
|
+
Without this: users frustrate themselves by tapping "재전송" repeatedly OR don't know when they can re-request.
|
|
13
|
+
|
|
14
|
+
## Anatomy
|
|
15
|
+
|
|
16
|
+
```
|
|
17
|
+
┌─────────────────────────────────────┐
|
|
18
|
+
│ 인증번호 입력 │
|
|
19
|
+
│ ┌──┐ ┌──┐ ┌──┐ ┌──┐ ┌──┐ ┌──┐ │
|
|
20
|
+
│ │ 1│ │ 2│ │ 3│ │ 4│ │ 5│ │ 6│ │ ← InputOTP
|
|
21
|
+
│ └──┘ └──┘ └──┘ └──┘ └──┘ └──┘ │
|
|
22
|
+
│ │
|
|
23
|
+
│ 남은 시간: 02:47 │ ← code expiration
|
|
24
|
+
│ [재전송하기] │ ← becomes active after cooldown
|
|
25
|
+
│ (30초 후 재전송 가능) │ ← cooldown indicator (alternates with button)
|
|
26
|
+
└─────────────────────────────────────┘
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## API
|
|
30
|
+
|
|
31
|
+
```tsx
|
|
32
|
+
<>
|
|
33
|
+
<InputOTP length={6} value={code} onValueChange={setCode} onComplete={verify} />
|
|
34
|
+
<OTPCountdown
|
|
35
|
+
expiresAt={codeExpiresAt} // 3 min from issue
|
|
36
|
+
cooldownSeconds={30} // resend cooldown
|
|
37
|
+
onResend={requestNewCode}
|
|
38
|
+
onExpired={() => setError("인증번호가 만료되었습니다.")}
|
|
39
|
+
/>
|
|
40
|
+
</>
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
| Prop | Type | Default | Description |
|
|
44
|
+
| --- | --- | --- | --- |
|
|
45
|
+
| `expiresAt` | `Date \| number` | — | When the code expires (Date or unix ms) |
|
|
46
|
+
| `cooldownSeconds` | `number` | `30` | Seconds before resend allowed |
|
|
47
|
+
| `onResend` | `() => void \| Promise<void>` | — | Trigger new code request |
|
|
48
|
+
| `onExpired` | `() => void` | — | Fired when expiresAt reached |
|
|
49
|
+
| `expiredMessage` | `string` | `"인증번호가 만료되었습니다"` | When code expires |
|
|
50
|
+
| `disabled` | `boolean` | `false` | Disable both timer + resend |
|
|
51
|
+
|
|
52
|
+
## Behavior
|
|
53
|
+
|
|
54
|
+
### Expiration timer
|
|
55
|
+
|
|
56
|
+
- Counts down from now to `expiresAt`.
|
|
57
|
+
- Format: `mm:ss` for typical 3-min window. `0:30` when under 1 min.
|
|
58
|
+
- Color shift to warning when < 30s remaining.
|
|
59
|
+
- At 0: fires `onExpired`, shows expired message, disables InputOTP.
|
|
60
|
+
|
|
61
|
+
### Resend cooldown
|
|
62
|
+
|
|
63
|
+
- Starts at `cooldownSeconds` after component mount (or after each resend).
|
|
64
|
+
- Shows "30초 후 재전송 가능" while counting down.
|
|
65
|
+
- At 0: replaces with active "재전송하기" button.
|
|
66
|
+
- Tapping resend: triggers `onResend`, restarts both timers (cooldown + expiration).
|
|
67
|
+
|
|
68
|
+
### State machine
|
|
69
|
+
|
|
70
|
+
```
|
|
71
|
+
┌──────────┐
|
|
72
|
+
│ initial │ ← timer starts, cooldown counts down
|
|
73
|
+
└─────┬────┘
|
|
74
|
+
│ cooldown reaches 0
|
|
75
|
+
▼
|
|
76
|
+
┌──────────────┐
|
|
77
|
+
│ resend ready │ ← button visible + active
|
|
78
|
+
└─────┬────────┘
|
|
79
|
+
│ user taps resend
|
|
80
|
+
▼
|
|
81
|
+
┌──────────┐
|
|
82
|
+
│ resending│ ← spinner; new request to server
|
|
83
|
+
└─────┬────┘
|
|
84
|
+
│ server returns new code expiry
|
|
85
|
+
▼ (loop back to initial with new timers)
|
|
86
|
+
|
|
87
|
+
OR (independent):
|
|
88
|
+
│ expiresAt reached
|
|
89
|
+
▼
|
|
90
|
+
┌──────────┐
|
|
91
|
+
│ expired │ ← onExpired fires; ui shows message
|
|
92
|
+
└──────────┘
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
## States
|
|
96
|
+
|
|
97
|
+
| State | Visual |
|
|
98
|
+
| --- | --- |
|
|
99
|
+
| Initial — counting down | "남은 시간 02:47" + cooldown indicator |
|
|
100
|
+
| Cooldown done | "재전송하기" button active |
|
|
101
|
+
| Expiration warning (<30s) | Timer text in `--color-warning` |
|
|
102
|
+
| Expired | "인증번호가 만료되었습니다" + reload button |
|
|
103
|
+
| Resending | Button shows spinner; cooldown restarts after success |
|
|
104
|
+
| Disabled | All elements muted |
|
|
105
|
+
|
|
106
|
+
## Tokens consumed
|
|
107
|
+
|
|
108
|
+
```
|
|
109
|
+
--color-text-primary (timer)
|
|
110
|
+
--color-text-secondary (cooldown indicator)
|
|
111
|
+
--color-warning (timer warning <30s)
|
|
112
|
+
--color-error (expired)
|
|
113
|
+
--color-primary-default (active resend button)
|
|
114
|
+
--color-text-tertiary (disabled cooldown)
|
|
115
|
+
--space-sm, --space-md
|
|
116
|
+
--font-feature-amount: 'tnum' (digits align)
|
|
117
|
+
--font-size-sm, --font-size-base
|
|
118
|
+
--motion-fast
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
## Tabular numerals (critical)
|
|
122
|
+
|
|
123
|
+
Timer "02:47" → "02:46" → "02:45" must not visually shift width. Use `font-feature-settings: 'tnum'` so digits are equal-width.
|
|
124
|
+
|
|
125
|
+
## Korean copy
|
|
126
|
+
|
|
127
|
+
| State | Copy |
|
|
128
|
+
| --- | --- |
|
|
129
|
+
| Time remaining | "남은 시간 mm:ss" or "유효시간 mm:ss" |
|
|
130
|
+
| Cooldown | "N초 후 재전송 가능" |
|
|
131
|
+
| Resend ready | "재전송하기" |
|
|
132
|
+
| Resending | "재전송 중..." |
|
|
133
|
+
| Expired | "인증번호가 만료되었습니다. 다시 발급받아 주세요." |
|
|
134
|
+
| Re-issue button | "인증번호 재발급" |
|
|
135
|
+
|
|
136
|
+
## Accessibility
|
|
137
|
+
|
|
138
|
+
- Timer in `<span aria-live="off">` — don't announce every second (chatter).
|
|
139
|
+
- Update `aria-label` at milestones: "1분 남음", "30초 남음", "만료됨".
|
|
140
|
+
- Resend button: standard a11y, `aria-disabled` when in cooldown.
|
|
141
|
+
- Screen reader on expiration: announce once via `role="alert"`.
|
|
142
|
+
|
|
143
|
+
## Implementation hints
|
|
144
|
+
|
|
145
|
+
```tsx
|
|
146
|
+
function OTPCountdown({ expiresAt, cooldownSeconds, onResend, ... }: Props) {
|
|
147
|
+
const [now, setNow] = useState(Date.now());
|
|
148
|
+
const [cooldownEnd, setCooldownEnd] = useState(Date.now() + cooldownSeconds * 1000);
|
|
149
|
+
const [resending, setResending] = useState(false);
|
|
150
|
+
|
|
151
|
+
useEffect(() => {
|
|
152
|
+
const id = setInterval(() => setNow(Date.now()), 500); // 500ms is enough; UI shows seconds
|
|
153
|
+
return () => clearInterval(id);
|
|
154
|
+
}, []);
|
|
155
|
+
|
|
156
|
+
const expiresMs = Math.max(0, expiresAt - now);
|
|
157
|
+
const cooldownMs = Math.max(0, cooldownEnd - now);
|
|
158
|
+
|
|
159
|
+
// ... render based on state
|
|
160
|
+
}
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
For server clock skew: pair `expiresAt` from server with a periodic time-sync. For 3-min SMS windows, ±5 seconds skew is tolerable.
|
|
164
|
+
|
|
165
|
+
## Code example
|
|
166
|
+
|
|
167
|
+
```tsx
|
|
168
|
+
function VerifyPhoneScreen({ phone }: Props) {
|
|
169
|
+
const [code, setCode] = useState("");
|
|
170
|
+
const [codeIssue, setCodeIssue] = useState({
|
|
171
|
+
expiresAt: Date.now() + 3 * 60 * 1000,
|
|
172
|
+
issuedAt: Date.now(),
|
|
173
|
+
});
|
|
174
|
+
const [error, setError] = useState<string>();
|
|
175
|
+
|
|
176
|
+
const handleResend = async () => {
|
|
177
|
+
const result = await api.resendCode({ phone });
|
|
178
|
+
setCodeIssue({
|
|
179
|
+
expiresAt: result.expiresAt,
|
|
180
|
+
issuedAt: Date.now(),
|
|
181
|
+
});
|
|
182
|
+
setCode(""); // clear input
|
|
183
|
+
};
|
|
184
|
+
|
|
185
|
+
const handleVerify = async (otpCode: string) => {
|
|
186
|
+
try {
|
|
187
|
+
await api.verifyCode({ phone, code: otpCode });
|
|
188
|
+
navigate("/success");
|
|
189
|
+
} catch (err) {
|
|
190
|
+
setError(err.message);
|
|
191
|
+
setCode("");
|
|
192
|
+
}
|
|
193
|
+
};
|
|
194
|
+
|
|
195
|
+
return (
|
|
196
|
+
<Page>
|
|
197
|
+
<Heading>인증번호 입력</Heading>
|
|
198
|
+
<p>{phone}로 보낸 6자리 인증번호를 입력해 주세요.</p>
|
|
199
|
+
|
|
200
|
+
<InputOTP
|
|
201
|
+
length={6}
|
|
202
|
+
value={code}
|
|
203
|
+
onValueChange={setCode}
|
|
204
|
+
onComplete={handleVerify}
|
|
205
|
+
autoFocus
|
|
206
|
+
errorText={error}
|
|
207
|
+
/>
|
|
208
|
+
|
|
209
|
+
<OTPCountdown
|
|
210
|
+
expiresAt={codeIssue.expiresAt}
|
|
211
|
+
cooldownSeconds={30}
|
|
212
|
+
onResend={handleResend}
|
|
213
|
+
onExpired={() => setError("인증번호가 만료되었습니다. 재발급 받아주세요.")}
|
|
214
|
+
/>
|
|
215
|
+
</Page>
|
|
216
|
+
);
|
|
217
|
+
}
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
## Edge cases
|
|
221
|
+
|
|
222
|
+
- **User backgrounds the app, returns minutes later**: timer continues based on real time (not React Time). On return: re-render with current diff.
|
|
223
|
+
- **Server-issued expiry slightly off from client clock**: tolerate ±5s.
|
|
224
|
+
- **Multiple rapid resends**: rate-limit via cooldown. If user spams tap: button stays cooldown.
|
|
225
|
+
- **Page navigation away + back**: timer state should persist (URL search params or shared store) — otherwise re-issuing on every nav is annoying.
|
|
226
|
+
- **Slow network on resend**: button stays in "재전송 중..." state until response. Don't allow second tap.
|
|
227
|
+
|
|
228
|
+
## Don't
|
|
229
|
+
|
|
230
|
+
- Don't restart the expiration timer on resend without re-issuing a new code from server.
|
|
231
|
+
- Don't omit cooldown — users will spam-resend, server-side rate-limit will kick in confusingly.
|
|
232
|
+
- Don't update timer every 100ms (60Hz updates are wasteful for a 1-second display).
|
|
233
|
+
- Don't expire silently — user must know.
|
|
234
|
+
- Don't allow more than 3-5 resends per session (typical Korean carrier limit).
|
|
235
|
+
|
|
236
|
+
## References
|
|
237
|
+
|
|
238
|
+
No upstream component matches exactly. This is a Korean-market-specific composition over `InputOTP` + countdown logic.
|
|
239
|
+
|
|
240
|
+
## Cross-reference
|
|
241
|
+
|
|
242
|
+
- [`examples/component-input-otp.md`](component-input-otp.md) — pairs with this
|
|
243
|
+
- [`knowledge/i18n/korean-product-conventions.md`](../knowledge/i18n/korean-product-conventions.md) — Korean phone-auth conventions
|
|
244
|
+
- [`knowledge/i18n/korean-payments.md`](../knowledge/i18n/korean-payments.md) — broader 본인인증
|
|
245
|
+
- [`examples/component-pass-auth.md`](component-pass-auth.md) — full PASS / 본인인증 wrapper
|