@nikala-ui/docs 0.12.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/README.md +22 -0
- package/dist/cli/commands/build.d.ts +5 -0
- package/dist/cli/commands/build.d.ts.map +1 -0
- package/dist/cli/commands/build.js +27 -0
- package/dist/cli/commands/build.js.map +1 -0
- package/dist/cli/commands/dev.d.ts +7 -0
- package/dist/cli/commands/dev.d.ts.map +1 -0
- package/dist/cli/commands/dev.js +32 -0
- package/dist/cli/commands/dev.js.map +1 -0
- package/dist/cli/commands/init.d.ts +2 -0
- package/dist/cli/commands/init.d.ts.map +1 -0
- package/dist/cli/commands/init.js +308 -0
- package/dist/cli/commands/init.js.map +1 -0
- package/dist/cli/commands/preview.d.ts +7 -0
- package/dist/cli/commands/preview.d.ts.map +1 -0
- package/dist/cli/commands/preview.js +24 -0
- package/dist/cli/commands/preview.js.map +1 -0
- package/dist/cli/commands/serve.d.ts +7 -0
- package/dist/cli/commands/serve.d.ts.map +1 -0
- package/dist/cli/commands/serve.js +33 -0
- package/dist/cli/commands/serve.js.map +1 -0
- package/dist/cli/index.d.ts +3 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +53 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/client/App.d.ts +5 -0
- package/dist/client/App.d.ts.map +1 -0
- package/dist/client/App.jsx +31 -0
- package/dist/client/App.jsx.map +1 -0
- package/dist/client/app-types.d.ts +14 -0
- package/dist/client/app-types.d.ts.map +1 -0
- package/dist/client/app-types.js +2 -0
- package/dist/client/app-types.js.map +1 -0
- package/dist/client/components/DocsLayoutShell.d.ts +21 -0
- package/dist/client/components/DocsLayoutShell.d.ts.map +1 -0
- package/dist/client/components/DocsLayoutShell.jsx +14 -0
- package/dist/client/components/DocsLayoutShell.jsx.map +1 -0
- package/dist/client/components/DocsPageContent.d.ts +9 -0
- package/dist/client/components/DocsPageContent.d.ts.map +1 -0
- package/dist/client/components/DocsPageContent.jsx +10 -0
- package/dist/client/components/DocsPageContent.jsx.map +1 -0
- package/dist/client/entry.d.ts +2 -0
- package/dist/client/entry.d.ts.map +1 -0
- package/dist/client/entry.jsx +28 -0
- package/dist/client/entry.jsx.map +1 -0
- package/dist/client/index.html +21 -0
- package/dist/client/navigation/page-navigation.d.ts +9 -0
- package/dist/client/navigation/page-navigation.d.ts.map +1 -0
- package/dist/client/navigation/page-navigation.js +51 -0
- package/dist/client/navigation/page-navigation.js.map +1 -0
- package/dist/client/routing/use-docs-router.d.ts +17 -0
- package/dist/client/routing/use-docs-router.d.ts.map +1 -0
- package/dist/client/routing/use-docs-router.js +71 -0
- package/dist/client/routing/use-docs-router.js.map +1 -0
- package/dist/client/ssr-entry.d.ts +3 -0
- package/dist/client/ssr-entry.d.ts.map +1 -0
- package/dist/client/ssr-entry.jsx +13 -0
- package/dist/client/ssr-entry.jsx.map +1 -0
- package/dist/client/style.css +183 -0
- package/dist/client/utils/sidebar.d.ts +2 -0
- package/dist/client/utils/sidebar.d.ts.map +1 -0
- package/dist/client/utils/sidebar.js +2 -0
- package/dist/client/utils/sidebar.js.map +1 -0
- package/dist/components/mdx-components.d.ts +34 -0
- package/dist/components/mdx-components.d.ts.map +1 -0
- package/dist/components/mdx-components.jsx +131 -0
- package/dist/components/mdx-components.jsx.map +1 -0
- package/dist/config.d.ts +6 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +105 -0
- package/dist/config.js.map +1 -0
- package/dist/core/content-scanner.d.ts +10 -0
- package/dist/core/content-scanner.d.ts.map +1 -0
- package/dist/core/content-scanner.js +153 -0
- package/dist/core/content-scanner.js.map +1 -0
- package/dist/core/route-tree.d.ts +19 -0
- package/dist/core/route-tree.d.ts.map +1 -0
- package/dist/core/route-tree.js +176 -0
- package/dist/core/route-tree.js.map +1 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +14 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/cn.d.ts +6 -0
- package/dist/lib/cn.d.ts.map +1 -0
- package/dist/lib/cn.js +9 -0
- package/dist/lib/cn.js.map +1 -0
- package/dist/mdx/compiler.d.ts +13 -0
- package/dist/mdx/compiler.d.ts.map +1 -0
- package/dist/mdx/compiler.js +38 -0
- package/dist/mdx/compiler.js.map +1 -0
- package/dist/mdx/highlighter.d.ts +22 -0
- package/dist/mdx/highlighter.d.ts.map +1 -0
- package/dist/mdx/highlighter.js +139 -0
- package/dist/mdx/highlighter.js.map +1 -0
- package/dist/mdx/rehype-shiki.d.ts +3 -0
- package/dist/mdx/rehype-shiki.d.ts.map +1 -0
- package/dist/mdx/rehype-shiki.js +83 -0
- package/dist/mdx/rehype-shiki.js.map +1 -0
- package/dist/navigation/index.d.ts +2 -0
- package/dist/navigation/index.d.ts.map +1 -0
- package/dist/navigation/index.js +2 -0
- package/dist/navigation/index.js.map +1 -0
- package/dist/navigation/sidebar-state.d.ts +6 -0
- package/dist/navigation/sidebar-state.d.ts.map +1 -0
- package/dist/navigation/sidebar-state.js +20 -0
- package/dist/navigation/sidebar-state.js.map +1 -0
- package/dist/navigation/sidebar-tree.d.ts +7 -0
- package/dist/navigation/sidebar-tree.d.ts.map +1 -0
- package/dist/navigation/sidebar-tree.js +11 -0
- package/dist/navigation/sidebar-tree.js.map +1 -0
- package/dist/registry/accordion.json +18 -0
- package/dist/registry/alert.json +18 -0
- package/dist/registry/api-table.json +21 -0
- package/dist/registry/aspect-ratio.json +17 -0
- package/dist/registry/avatar.json +17 -0
- package/dist/registry/badge.json +18 -0
- package/dist/registry/banner.json +19 -0
- package/dist/registry/breadcrumb.json +17 -0
- package/dist/registry/bubble.json +18 -0
- package/dist/registry/button-group.json +20 -0
- package/dist/registry/button.json +21 -0
- package/dist/registry/callout.json +19 -0
- package/dist/registry/card.json +17 -0
- package/dist/registry/checkbox.json +20 -0
- package/dist/registry/code-block.json +26 -0
- package/dist/registry/code-group.json +20 -0
- package/dist/registry/collapsible.json +18 -0
- package/dist/registry/combobox.json +21 -0
- package/dist/registry/command.json +27 -0
- package/dist/registry/component-viewer.json +25 -0
- package/dist/registry/container.json +18 -0
- package/dist/registry/context-menu.json +24 -0
- package/dist/registry/create-active-element.json +13 -0
- package/dist/registry/create-app-updater.json +13 -0
- package/dist/registry/create-audio.json +7 -0
- package/dist/registry/create-battery.json +13 -0
- package/dist/registry/create-chat-scroll.json +13 -0
- package/dist/registry/create-click-outside.json +13 -0
- package/dist/registry/create-clipboard.json +13 -0
- package/dist/registry/create-color-mode.json +13 -0
- package/dist/registry/create-controllable-signal.json +13 -0
- package/dist/registry/create-debounce.json +13 -0
- package/dist/registry/create-disclosure.json +13 -0
- package/dist/registry/create-document-tabs.json +13 -0
- package/dist/registry/create-document-title.json +13 -0
- package/dist/registry/create-drop-zone.json +13 -0
- package/dist/registry/create-event-source.json +13 -0
- package/dist/registry/create-favicon.json +13 -0
- package/dist/registry/create-fetch.json +13 -0
- package/dist/registry/create-focus-trap.json +13 -0
- package/dist/registry/create-form.json +13 -0
- package/dist/registry/create-fullscreen.json +13 -0
- package/dist/registry/create-geolocation.json +13 -0
- package/dist/registry/create-global-shortcut.json +13 -0
- package/dist/registry/create-hover.json +13 -0
- package/dist/registry/create-idle.json +13 -0
- package/dist/registry/create-infinite-scroll.json +13 -0
- package/dist/registry/create-input-mask.json +13 -0
- package/dist/registry/create-intersection-observer.json +13 -0
- package/dist/registry/create-keybindings.json +13 -0
- package/dist/registry/create-lock-scroll.json +13 -0
- package/dist/registry/create-long-press.json +13 -0
- package/dist/registry/create-media-query.json +13 -0
- package/dist/registry/create-mouse-position.json +13 -0
- package/dist/registry/create-network-status.json +13 -0
- package/dist/registry/create-orientation.json +13 -0
- package/dist/registry/create-pagination.json +13 -0
- package/dist/registry/create-permission.json +13 -0
- package/dist/registry/create-previous.json +13 -0
- package/dist/registry/create-resize-observer.json +13 -0
- package/dist/registry/create-scroll-into-view.json +13 -0
- package/dist/registry/create-scroll-position.json +13 -0
- package/dist/registry/create-storage.json +13 -0
- package/dist/registry/create-tauri-window.json +13 -0
- package/dist/registry/create-timer.json +13 -0
- package/dist/registry/create-tiptap-editor.json +34 -0
- package/dist/registry/create-undo-redo.json +13 -0
- package/dist/registry/create-web-notification.json +13 -0
- package/dist/registry/create-websocket.json +13 -0
- package/dist/registry/create-window-size.json +13 -0
- package/dist/registry/dialog.json +21 -0
- package/dist/registry/dropdown-menu.json +22 -0
- package/dist/registry/dropzone.json +21 -0
- package/dist/registry/empty.json +17 -0
- package/dist/registry/field.json +20 -0
- package/dist/registry/file-tree.json +21 -0
- package/dist/registry/footer.json +18 -0
- package/dist/registry/forgot-password-01.json +28 -0
- package/dist/registry/form-message.json +17 -0
- package/dist/registry/form.json +17 -0
- package/dist/registry/hero-01.json +22 -0
- package/dist/registry/hover-card.json +18 -0
- package/dist/registry/icon-button.json +20 -0
- package/dist/registry/index.json +1489 -0
- package/dist/registry/input-group.json +21 -0
- package/dist/registry/input.json +17 -0
- package/dist/registry/kbd.json +18 -0
- package/dist/registry/label.json +18 -0
- package/dist/registry/list.json +20 -0
- package/dist/registry/login-01.json +28 -0
- package/dist/registry/logo.json +17 -0
- package/dist/registry/marker.json +17 -0
- package/dist/registry/marquee.json +17 -0
- package/dist/registry/message.json +17 -0
- package/dist/registry/navbar.json +19 -0
- package/dist/registry/navigation-menu.json +22 -0
- package/dist/registry/number-input.json +24 -0
- package/dist/registry/otp-verification-01.json +26 -0
- package/dist/registry/package-manager-tabs.json +24 -0
- package/dist/registry/pager.json +21 -0
- package/dist/registry/pagination.json +22 -0
- package/dist/registry/pin-input.json +17 -0
- package/dist/registry/popover.json +22 -0
- package/dist/registry/progress.json +18 -0
- package/dist/registry/radio-group.json +18 -0
- package/dist/registry/rating.json +19 -0
- package/dist/registry/register-01.json +31 -0
- package/dist/registry/resizable.json +21 -0
- package/dist/registry/review-card.json +23 -0
- package/dist/registry/rich-text-editor.json +95 -0
- package/dist/registry/scroll-area.json +21 -0
- package/dist/registry/section-heading.json +21 -0
- package/dist/registry/select.json +22 -0
- package/dist/registry/separator.json +17 -0
- package/dist/registry/sheet.json +22 -0
- package/dist/registry/sidebar.json +24 -0
- package/dist/registry/skeleton.json +17 -0
- package/dist/registry/slider.json +18 -0
- package/dist/registry/spinner.json +18 -0
- package/dist/registry/stat.json +19 -0
- package/dist/registry/status.json +18 -0
- package/dist/registry/steps.json +20 -0
- package/dist/registry/switch.json +20 -0
- package/dist/registry/table-of-contents.json +23 -0
- package/dist/registry/table.json +17 -0
- package/dist/registry/tabs.json +20 -0
- package/dist/registry/textarea.json +17 -0
- package/dist/registry/theme-manager.json +39 -0
- package/dist/registry/timeline.json +18 -0
- package/dist/registry/titlebar-tabs.json +24 -0
- package/dist/registry/titlebar.json +26 -0
- package/dist/registry/toast.json +20 -0
- package/dist/registry/toggle-group.json +21 -0
- package/dist/registry/toggle.json +18 -0
- package/dist/registry/tooltip.json +18 -0
- package/dist/registry/updater-modal.json +26 -0
- package/dist/server/index.d.ts +18 -0
- package/dist/server/index.d.ts.map +1 -0
- package/dist/server/index.js +526 -0
- package/dist/server/index.js.map +1 -0
- package/dist/server/plugin.d.ts +10 -0
- package/dist/server/plugin.d.ts.map +1 -0
- package/dist/server/plugin.js +271 -0
- package/dist/server/plugin.js.map +1 -0
- package/dist/themes/default/content/breadcrumbs.d.ts +4 -0
- package/dist/themes/default/content/breadcrumbs.d.ts.map +1 -0
- package/dist/themes/default/content/breadcrumbs.jsx +31 -0
- package/dist/themes/default/content/breadcrumbs.jsx.map +1 -0
- package/dist/themes/default/content/pager.d.ts +5 -0
- package/dist/themes/default/content/pager.d.ts.map +1 -0
- package/dist/themes/default/content/pager.jsx +9 -0
- package/dist/themes/default/content/pager.jsx.map +1 -0
- package/dist/themes/default/content/table-of-contents.d.ts +4 -0
- package/dist/themes/default/content/table-of-contents.d.ts.map +1 -0
- package/dist/themes/default/content/table-of-contents.jsx +19 -0
- package/dist/themes/default/content/table-of-contents.jsx.map +1 -0
- package/dist/themes/default/index.d.ts +11 -0
- package/dist/themes/default/index.d.ts.map +1 -0
- package/dist/themes/default/index.js +30 -0
- package/dist/themes/default/index.js.map +1 -0
- package/dist/themes/default/layout.d.ts +4 -0
- package/dist/themes/default/layout.d.ts.map +1 -0
- package/dist/themes/default/layout.jsx +75 -0
- package/dist/themes/default/layout.jsx.map +1 -0
- package/dist/themes/default/navbar.d.ts +4 -0
- package/dist/themes/default/navbar.d.ts.map +1 -0
- package/dist/themes/default/navbar.jsx +74 -0
- package/dist/themes/default/navbar.jsx.map +1 -0
- package/dist/themes/default/navigation/mobile-table-of-contents.d.ts +4 -0
- package/dist/themes/default/navigation/mobile-table-of-contents.d.ts.map +1 -0
- package/dist/themes/default/navigation/mobile-table-of-contents.jsx +22 -0
- package/dist/themes/default/navigation/mobile-table-of-contents.jsx.map +1 -0
- package/dist/themes/default/navigation/sidebar-tree.d.ts +8 -0
- package/dist/themes/default/navigation/sidebar-tree.d.ts.map +1 -0
- package/dist/themes/default/navigation/sidebar-tree.jsx +100 -0
- package/dist/themes/default/navigation/sidebar-tree.jsx.map +1 -0
- package/dist/themes/default/overlays/search-dialog.d.ts +4 -0
- package/dist/themes/default/overlays/search-dialog.d.ts.map +1 -0
- package/dist/themes/default/overlays/search-dialog.jsx +34 -0
- package/dist/themes/default/overlays/search-dialog.jsx.map +1 -0
- package/dist/themes/default/sidebar.d.ts +4 -0
- package/dist/themes/default/sidebar.d.ts.map +1 -0
- package/dist/themes/default/sidebar.jsx +60 -0
- package/dist/themes/default/sidebar.jsx.map +1 -0
- package/dist/themes/index.d.ts +4 -0
- package/dist/themes/index.d.ts.map +1 -0
- package/dist/themes/index.js +5 -0
- package/dist/themes/index.js.map +1 -0
- package/dist/themes/types.d.ts +83 -0
- package/dist/themes/types.d.ts.map +1 -0
- package/dist/themes/types.js +2 -0
- package/dist/themes/types.js.map +1 -0
- package/dist/types.d.ts +97 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +3 -0
- package/dist/types.js.map +1 -0
- package/dist/vendor/core-src/index.css +11 -0
- package/dist/vendor/core-src/index.ts +48 -0
- package/dist/vendor/core-src/lib/cn.ts +9 -0
- package/dist/vendor/core-src/registry/blocks/forgot-password-01.tsx +141 -0
- package/dist/vendor/core-src/registry/blocks/hero-01.tsx +28 -0
- package/dist/vendor/core-src/registry/blocks/login-01.tsx +231 -0
- package/dist/vendor/core-src/registry/blocks/otp-verification-01.tsx +170 -0
- package/dist/vendor/core-src/registry/blocks/register-01.tsx +318 -0
- package/dist/vendor/core-src/registry/components/ui/accordion.tsx +128 -0
- package/dist/vendor/core-src/registry/components/ui/alert.tsx +155 -0
- package/dist/vendor/core-src/registry/components/ui/api-table.tsx +117 -0
- package/dist/vendor/core-src/registry/components/ui/aspect-ratio.tsx +31 -0
- package/dist/vendor/core-src/registry/components/ui/avatar.tsx +114 -0
- package/dist/vendor/core-src/registry/components/ui/badge.tsx +56 -0
- package/dist/vendor/core-src/registry/components/ui/banner.tsx +187 -0
- package/dist/vendor/core-src/registry/components/ui/breadcrumb.tsx +136 -0
- package/dist/vendor/core-src/registry/components/ui/bubble.tsx +142 -0
- package/dist/vendor/core-src/registry/components/ui/button-group.tsx +42 -0
- package/dist/vendor/core-src/registry/components/ui/button.tsx +82 -0
- package/dist/vendor/core-src/registry/components/ui/callout.tsx +137 -0
- package/dist/vendor/core-src/registry/components/ui/card.tsx +113 -0
- package/dist/vendor/core-src/registry/components/ui/checkbox.tsx +74 -0
- package/dist/vendor/core-src/registry/components/ui/code-block.tsx +326 -0
- package/dist/vendor/core-src/registry/components/ui/code-group.tsx +105 -0
- package/dist/vendor/core-src/registry/components/ui/collapsible.tsx +73 -0
- package/dist/vendor/core-src/registry/components/ui/combobox.tsx +299 -0
- package/dist/vendor/core-src/registry/components/ui/command.tsx +378 -0
- package/dist/vendor/core-src/registry/components/ui/component-viewer.tsx +363 -0
- package/dist/vendor/core-src/registry/components/ui/container.tsx +45 -0
- package/dist/vendor/core-src/registry/components/ui/context-menu.tsx +237 -0
- package/dist/vendor/core-src/registry/components/ui/dialog.tsx +200 -0
- package/dist/vendor/core-src/registry/components/ui/dropdown-menu.tsx +298 -0
- package/dist/vendor/core-src/registry/components/ui/dropzone.tsx +189 -0
- package/dist/vendor/core-src/registry/components/ui/empty.tsx +83 -0
- package/dist/vendor/core-src/registry/components/ui/field.tsx +71 -0
- package/dist/vendor/core-src/registry/components/ui/file-tree.tsx +181 -0
- package/dist/vendor/core-src/registry/components/ui/footer.tsx +247 -0
- package/dist/vendor/core-src/registry/components/ui/form-message.tsx +36 -0
- package/dist/vendor/core-src/registry/components/ui/form.tsx +21 -0
- package/dist/vendor/core-src/registry/components/ui/hover-card.tsx +105 -0
- package/dist/vendor/core-src/registry/components/ui/icon-button.tsx +34 -0
- package/dist/vendor/core-src/registry/components/ui/input-group.tsx +80 -0
- package/dist/vendor/core-src/registry/components/ui/input.tsx +28 -0
- package/dist/vendor/core-src/registry/components/ui/kbd.tsx +73 -0
- package/dist/vendor/core-src/registry/components/ui/label.tsx +30 -0
- package/dist/vendor/core-src/registry/components/ui/list.tsx +222 -0
- package/dist/vendor/core-src/registry/components/ui/logo.tsx +68 -0
- package/dist/vendor/core-src/registry/components/ui/marker.tsx +102 -0
- package/dist/vendor/core-src/registry/components/ui/marquee.tsx +118 -0
- package/dist/vendor/core-src/registry/components/ui/message.tsx +168 -0
- package/dist/vendor/core-src/registry/components/ui/navbar.tsx +375 -0
- package/dist/vendor/core-src/registry/components/ui/navigation-menu.tsx +358 -0
- package/dist/vendor/core-src/registry/components/ui/number-input.tsx +150 -0
- package/dist/vendor/core-src/registry/components/ui/package-manager-tabs.tsx +226 -0
- package/dist/vendor/core-src/registry/components/ui/pager.tsx +102 -0
- package/dist/vendor/core-src/registry/components/ui/pagination.tsx +258 -0
- package/dist/vendor/core-src/registry/components/ui/pin-input.tsx +198 -0
- package/dist/vendor/core-src/registry/components/ui/popover.tsx +90 -0
- package/dist/vendor/core-src/registry/components/ui/progress.tsx +66 -0
- package/dist/vendor/core-src/registry/components/ui/radio-group.tsx +95 -0
- package/dist/vendor/core-src/registry/components/ui/rating.tsx +185 -0
- package/dist/vendor/core-src/registry/components/ui/resizable.tsx +195 -0
- package/dist/vendor/core-src/registry/components/ui/review-card.tsx +195 -0
- package/dist/vendor/core-src/registry/components/ui/rich-text-editor/bubble-menu.tsx +236 -0
- package/dist/vendor/core-src/registry/components/ui/rich-text-editor/editor.tsx +308 -0
- package/dist/vendor/core-src/registry/components/ui/rich-text-editor/extensions.ts +116 -0
- package/dist/vendor/core-src/registry/components/ui/rich-text-editor/footer.tsx +36 -0
- package/dist/vendor/core-src/registry/components/ui/rich-text-editor/image-dialog.tsx +75 -0
- package/dist/vendor/core-src/registry/components/ui/rich-text-editor/index.ts +11 -0
- package/dist/vendor/core-src/registry/components/ui/rich-text-editor/link-dialog.tsx +48 -0
- package/dist/vendor/core-src/registry/components/ui/rich-text-editor/markdown.ts +170 -0
- package/dist/vendor/core-src/registry/components/ui/rich-text-editor/slash-command.tsx +301 -0
- package/dist/vendor/core-src/registry/components/ui/rich-text-editor/table-controls.tsx +68 -0
- package/dist/vendor/core-src/registry/components/ui/rich-text-editor/toolbar.tsx +465 -0
- package/dist/vendor/core-src/registry/components/ui/rich-text-editor/use-editor.ts +231 -0
- package/dist/vendor/core-src/registry/components/ui/scroll-area.tsx +228 -0
- package/dist/vendor/core-src/registry/components/ui/section-heading.tsx +108 -0
- package/dist/vendor/core-src/registry/components/ui/select.tsx +156 -0
- package/dist/vendor/core-src/registry/components/ui/separator.tsx +37 -0
- package/dist/vendor/core-src/registry/components/ui/sheet.tsx +220 -0
- package/dist/vendor/core-src/registry/components/ui/sidebar.tsx +692 -0
- package/dist/vendor/core-src/registry/components/ui/skeleton.tsx +24 -0
- package/dist/vendor/core-src/registry/components/ui/slider.tsx +153 -0
- package/dist/vendor/core-src/registry/components/ui/spinner.tsx +41 -0
- package/dist/vendor/core-src/registry/components/ui/stat.tsx +245 -0
- package/dist/vendor/core-src/registry/components/ui/status.tsx +121 -0
- package/dist/vendor/core-src/registry/components/ui/steps.tsx +198 -0
- package/dist/vendor/core-src/registry/components/ui/switch.tsx +68 -0
- package/dist/vendor/core-src/registry/components/ui/table-of-contents.tsx +131 -0
- package/dist/vendor/core-src/registry/components/ui/table.tsx +160 -0
- package/dist/vendor/core-src/registry/components/ui/tabs.tsx +204 -0
- package/dist/vendor/core-src/registry/components/ui/textarea.tsx +82 -0
- package/dist/vendor/core-src/registry/components/ui/theme-toggle.tsx +238 -0
- package/dist/vendor/core-src/registry/components/ui/timeline.tsx +350 -0
- package/dist/vendor/core-src/registry/components/ui/titlebar-tabs.tsx +773 -0
- package/dist/vendor/core-src/registry/components/ui/titlebar.tsx +468 -0
- package/dist/vendor/core-src/registry/components/ui/toast.tsx +124 -0
- package/dist/vendor/core-src/registry/components/ui/toggle-group.tsx +203 -0
- package/dist/vendor/core-src/registry/components/ui/toggle.tsx +101 -0
- package/dist/vendor/core-src/registry/components/ui/tooltip.tsx +41 -0
- package/dist/vendor/core-src/registry/components/ui/updater-modal.tsx +254 -0
- package/dist/vendor/core-src/registry/index.ts +50 -0
- package/dist/vendor/core-src/registry/metadata.ts +742 -0
- package/dist/vendor/core-src/registry/providers/theme-provider.tsx +216 -0
- package/dist/vendor/core-src/registry/providers/theme-script.tsx +78 -0
- package/dist/vendor/core-src/registry/providers/theme-transitions.ts +139 -0
- package/dist/vendor/hooks-src/create-active-element.ts +51 -0
- package/dist/vendor/hooks-src/create-app-updater.ts +272 -0
- package/dist/vendor/hooks-src/create-audio-video.ts +444 -0
- package/dist/vendor/hooks-src/create-battery.ts +78 -0
- package/dist/vendor/hooks-src/create-chat-scroll.ts +113 -0
- package/dist/vendor/hooks-src/create-click-outside.ts +82 -0
- package/dist/vendor/hooks-src/create-clipboard.ts +69 -0
- package/dist/vendor/hooks-src/create-color-mode.ts +115 -0
- package/dist/vendor/hooks-src/create-controllable-signal.ts +56 -0
- package/dist/vendor/hooks-src/create-debounce.ts +90 -0
- package/dist/vendor/hooks-src/create-disclosure.ts +82 -0
- package/dist/vendor/hooks-src/create-document-tabs.ts +267 -0
- package/dist/vendor/hooks-src/create-document-title.ts +33 -0
- package/dist/vendor/hooks-src/create-drop-zone.ts +317 -0
- package/dist/vendor/hooks-src/create-event-source.ts +126 -0
- package/dist/vendor/hooks-src/create-favicon.ts +52 -0
- package/dist/vendor/hooks-src/create-fetch.ts +93 -0
- package/dist/vendor/hooks-src/create-focus-trap.ts +94 -0
- package/dist/vendor/hooks-src/create-form.ts +200 -0
- package/dist/vendor/hooks-src/create-fullscreen.ts +105 -0
- package/dist/vendor/hooks-src/create-geolocation.ts +140 -0
- package/dist/vendor/hooks-src/create-global-shortcut.ts +140 -0
- package/dist/vendor/hooks-src/create-hover.ts +88 -0
- package/dist/vendor/hooks-src/create-idle.ts +109 -0
- package/dist/vendor/hooks-src/create-infinite-scroll.ts +90 -0
- package/dist/vendor/hooks-src/create-input-mask.ts +109 -0
- package/dist/vendor/hooks-src/create-intersection-observer.ts +82 -0
- package/dist/vendor/hooks-src/create-keybindings.ts +148 -0
- package/dist/vendor/hooks-src/create-lock-scroll.ts +97 -0
- package/dist/vendor/hooks-src/create-long-press.ts +85 -0
- package/dist/vendor/hooks-src/create-media-query.ts +94 -0
- package/dist/vendor/hooks-src/create-mouse-position.ts +87 -0
- package/dist/vendor/hooks-src/create-network-status.ts +100 -0
- package/dist/vendor/hooks-src/create-orientation.ts +129 -0
- package/dist/vendor/hooks-src/create-pagination.ts +208 -0
- package/dist/vendor/hooks-src/create-permission.ts +91 -0
- package/dist/vendor/hooks-src/create-previous.ts +21 -0
- package/dist/vendor/hooks-src/create-resize-observer.ts +89 -0
- package/dist/vendor/hooks-src/create-scroll-into-view.ts +57 -0
- package/dist/vendor/hooks-src/create-scroll-position.ts +129 -0
- package/dist/vendor/hooks-src/create-storage.ts +106 -0
- package/dist/vendor/hooks-src/create-tauri-window.ts +628 -0
- package/dist/vendor/hooks-src/create-timer.ts +150 -0
- package/dist/vendor/hooks-src/create-tiptap-editor.ts +326 -0
- package/dist/vendor/hooks-src/create-undo-redo.ts +100 -0
- package/dist/vendor/hooks-src/create-web-notification.ts +111 -0
- package/dist/vendor/hooks-src/create-websocket.ts +179 -0
- package/dist/vendor/hooks-src/create-window-size.ts +41 -0
- package/dist/vendor/hooks-src/index.ts +48 -0
- package/package.json +87 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "input-group",
|
|
3
|
+
"title": "Input Group",
|
|
4
|
+
"description": "Compound input wrapper for combining text inputs with prefix and suffix addons.",
|
|
5
|
+
"type": "registry:ui",
|
|
6
|
+
"dependencies": [
|
|
7
|
+
"clsx",
|
|
8
|
+
"tailwind-merge",
|
|
9
|
+
"class-variance-authority"
|
|
10
|
+
],
|
|
11
|
+
"registryDependencies": [
|
|
12
|
+
"kbd"
|
|
13
|
+
],
|
|
14
|
+
"files": [
|
|
15
|
+
{
|
|
16
|
+
"path": "ui/input-group.tsx",
|
|
17
|
+
"content": "// src/components/ui/input-group.tsx\nimport { splitProps, type Component, type JSX } from \"solid-js\";\nimport { cva, type VariantProps } from \"class-variance-authority\";\nimport { cn } from \"@/lib/cn\";\n\n/* --- Main InputGroup Wrapper --- */\nexport interface InputGroupProps extends JSX.HTMLAttributes<HTMLDivElement> {\n class?: string;\n}\n\nexport const InputGroup: Component<InputGroupProps> = (props) => {\n const [local, rest] = splitProps(props, [\"class\", \"children\"]);\n\n return (\n <div\n class={cn(\n \"relative flex w-full items-center rounded-md border border-input bg-muted text-sm shadow-2xs transition-colors focus-within:border-primary focus-within:ring-1 focus-within:ring-primary\",\n local.class\n )}\n {...rest}\n >\n {local.children}\n </div>\n );\n};\n\n/* --- InputGroup Addon (Prefix / Suffix) --- */\nexport const addonVariants = cva(\n \"flex items-center shrink-0 text-muted-foreground select-none\",\n {\n variants: {\n align: {\n \"inline-start\": \"order-first pl-3 pr-1\",\n \"inline-end\": \"order-last pr-3 pl-1 gap-1\",\n },\n },\n defaultVariants: {\n align: \"inline-start\",\n },\n }\n);\n\nexport interface InputGroupAddonProps\n extends JSX.HTMLAttributes<HTMLDivElement>,\n VariantProps<typeof addonVariants> {\n class?: string;\n}\n\nexport const InputGroupAddon: Component<InputGroupAddonProps> = (props) => {\n const [local, rest] = splitProps(props, [\"align\", \"class\", \"children\"]);\n\n return (\n <div\n class={cn(addonVariants({ align: local.align }), local.class)}\n {...rest}\n >\n {local.children}\n </div>\n );\n};\n\n/* --- InputGroup Native Input --- */\nexport interface InputGroupInputProps\n extends JSX.InputHTMLAttributes<HTMLInputElement> {\n class?: string;\n}\n\nexport const InputGroupInput: Component<InputGroupInputProps> = (props) => {\n const [local, rest] = splitProps(props, [\"class\"]);\n\n return (\n <input\n class={cn(\n \"flex h-9 w-full flex-1 border-0 px-2.5 py-1 text-sm outline-none placeholder:text-muted-foreground disabled:cursor-not-allowed disabled:opacity-50\",\n local.class\n )}\n {...rest}\n />\n );\n};",
|
|
18
|
+
"type": "registry:ui"
|
|
19
|
+
}
|
|
20
|
+
]
|
|
21
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "input",
|
|
3
|
+
"title": "Input",
|
|
4
|
+
"description": "A standard text input field with styling variants.",
|
|
5
|
+
"type": "registry:ui",
|
|
6
|
+
"dependencies": [
|
|
7
|
+
"clsx",
|
|
8
|
+
"tailwind-merge"
|
|
9
|
+
],
|
|
10
|
+
"files": [
|
|
11
|
+
{
|
|
12
|
+
"path": "ui/input.tsx",
|
|
13
|
+
"content": "import { splitProps, type Component, type JSX } from \"solid-js\";\nimport { cn } from \"@/lib/cn\";\n\n/**\n * Props interface for the Input component extending standard HTML input attributes.\n */\nexport interface InputProps extends JSX.InputHTMLAttributes<HTMLInputElement> {\n class?: string;\n}\n\n/**\n * Nikala UI Input component built for SolidJS with Tailwind CSS v4 styling.\n */\nexport const Input: Component<InputProps> = (props) => {\n // Use splitProps to preserve SolidJS reactivity for destructured props\n const [local, rest] = splitProps(props, [\"class\", \"type\"]);\n\n return (\n <input\n type={local.type || \"text\"}\n class={cn(\n \"flex h-9 w-full rounded-md border border-input bg-muted px-3 py-1 text-base shadow-sm transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-primary disabled:cursor-not-allowed disabled:opacity-50 md:text-sm\",\n local.class\n )}\n {...rest}\n />\n );\n};",
|
|
14
|
+
"type": "registry:ui"
|
|
15
|
+
}
|
|
16
|
+
]
|
|
17
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "kbd",
|
|
3
|
+
"title": "Kbd (Keyboard Key)",
|
|
4
|
+
"description": "Keyboard key and shortcut group indicators for displaying hotkeys.",
|
|
5
|
+
"type": "registry:ui",
|
|
6
|
+
"dependencies": [
|
|
7
|
+
"clsx",
|
|
8
|
+
"tailwind-merge",
|
|
9
|
+
"class-variance-authority"
|
|
10
|
+
],
|
|
11
|
+
"files": [
|
|
12
|
+
{
|
|
13
|
+
"path": "ui/kbd.tsx",
|
|
14
|
+
"content": "// src/components/ui/kbd.tsx\nimport { splitProps, type Component, type JSX } from \"solid-js\";\nimport { cva, type VariantProps } from \"class-variance-authority\";\nimport { cn } from \"@/lib/cn\";\n\nexport const kbdVariants = cva(\n \"pointer-events-none inline-flex select-none items-center justify-center gap-1 rounded border border-border bg-muted font-mono font-medium text-muted-foreground shadow-2xs transition-colors\",\n {\n variants: {\n variant: {\n default: \"border-border bg-muted text-muted-foreground\",\n outline: \"border-border bg-transparent text-foreground\",\n },\n size: {\n sm: \"h-4 min-w-[16px] px-1 text-[9px]\",\n md: \"h-5 min-w-[20px] px-1.5 text-[10px]\",\n lg: \"h-6 min-w-[24px] px-2 text-xs\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n size: \"md\",\n },\n }\n);\n\nexport interface KbdProps\n extends JSX.HTMLAttributes<HTMLElement>,\n VariantProps<typeof kbdVariants> {\n class?: string;\n}\n\n/**\n * Nikala UI Kbd (Keyboard Key) Component.\n */\nexport const Kbd: Component<KbdProps> = (props) => {\n const [local, rest] = splitProps(props, [\n \"variant\",\n \"size\",\n \"class\",\n \"children\",\n ]);\n\n return (\n <kbd\n class={cn(\n kbdVariants({ variant: local.variant, size: local.size }),\n local.class\n )}\n {...rest}\n >\n {local.children}\n </kbd>\n );\n};\n\n/* --- Kbd Group Container --- */\nexport interface KbdGroupProps extends JSX.HTMLAttributes<HTMLDivElement> {\n class?: string;\n}\n\nexport const KbdGroup: Component<KbdGroupProps> = (props) => {\n const [local, rest] = splitProps(props, [\"class\", \"children\"]);\n\n return (\n <div\n class={cn(\"inline-flex items-center gap-1\", local.class)}\n {...rest}\n >\n {local.children}\n </div>\n );\n};",
|
|
15
|
+
"type": "registry:ui"
|
|
16
|
+
}
|
|
17
|
+
]
|
|
18
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "label",
|
|
3
|
+
"title": "Label",
|
|
4
|
+
"description": "Accessible caption label for form controls and inputs.",
|
|
5
|
+
"type": "registry:ui",
|
|
6
|
+
"dependencies": [
|
|
7
|
+
"clsx",
|
|
8
|
+
"tailwind-merge",
|
|
9
|
+
"class-variance-authority"
|
|
10
|
+
],
|
|
11
|
+
"files": [
|
|
12
|
+
{
|
|
13
|
+
"path": "ui/label.tsx",
|
|
14
|
+
"content": "import { splitProps, type Component, type JSX } from \"solid-js\";\nimport { cva, type VariantProps } from \"class-variance-authority\";\nimport { cn } from \"@/lib/cn\";\n\nexport const labelVariants = cva(\n \"text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70 text-foreground select-none\"\n);\n\nexport interface LabelProps\n extends JSX.LabelHTMLAttributes<HTMLLabelElement>,\n VariantProps<typeof labelVariants> {\n class?: string;\n}\n\n/**\n * Nikala UI Label component for form controls built for SolidJS with Tailwind CSS v4 styling.\n */\nexport const Label: Component<LabelProps> = (props) => {\n /* Use splitProps to preserve SolidJS signal reactivity */\n const [local, rest] = splitProps(props, [\"class\", \"children\"]);\n\n return (\n <label\n class={cn(labelVariants(), local.class)}\n {...rest}\n >\n {local.children}\n </label>\n );\n};",
|
|
15
|
+
"type": "registry:ui"
|
|
16
|
+
}
|
|
17
|
+
]
|
|
18
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "list",
|
|
3
|
+
"title": "List / List Item",
|
|
4
|
+
"description": "Compound list components supporting icons, avatars, titles, subtitles, hotkey badges, chevron indicators, and interactive links.",
|
|
5
|
+
"type": "registry:ui",
|
|
6
|
+
"dependencies": [
|
|
7
|
+
"clsx",
|
|
8
|
+
"tailwind-merge",
|
|
9
|
+
"class-variance-authority",
|
|
10
|
+
"lucide-solid",
|
|
11
|
+
"@kobalte/core"
|
|
12
|
+
],
|
|
13
|
+
"files": [
|
|
14
|
+
{
|
|
15
|
+
"path": "ui/list.tsx",
|
|
16
|
+
"content": "// src/components/ui/list.tsx\nimport {\n splitProps,\n Show,\n type Component,\n type JSX,\n} from \"solid-js\";\nimport { Dynamic } from \"solid-js/web\";\nimport { cva, type VariantProps } from \"class-variance-authority\";\nimport { ChevronRight } from \"lucide-solid\";\nimport { cn } from \"@/lib/cn\";\n\n/* --- List Container --- */\nexport interface ListProps extends JSX.HTMLAttributes<HTMLDivElement> {\n class?: string;\n}\n\nexport const List: Component<ListProps> = (props) => {\n const [local, rest] = splitProps(props, [\"class\", \"children\"]);\n return (\n <div role=\"list\" class={cn(\"flex flex-col gap-1 w-full p-1\", local.class)} {...rest}>\n {local.children}\n </div>\n );\n};\n\n/* --- List Group Container --- */\nexport interface ListGroupProps extends JSX.HTMLAttributes<HTMLDivElement> {\n class?: string;\n}\n\nexport const ListGroup: Component<ListGroupProps> = (props) => {\n const [local, rest] = splitProps(props, [\"class\", \"children\"]);\n return (\n <div class={cn(\"flex flex-col gap-1 w-full\", local.class)} {...rest}>\n {local.children}\n </div>\n );\n};\n\n/* --- List Group Header --- */\nexport interface ListHeaderProps extends JSX.HTMLAttributes<HTMLDivElement> {\n title: string;\n class?: string;\n}\n\nexport const ListHeader: Component<ListHeaderProps> = (props) => {\n const [local, rest] = splitProps(props, [\"title\", \"class\"]);\n return (\n <div\n class={cn(\n \"px-2 py-1.5 text-xs font-semibold uppercase tracking-wider text-muted-foreground select-none\",\n local.class\n )}\n {...rest}\n >\n {local.title}\n </div>\n );\n};\n\n/* --- List Item Variants --- */\nexport const listItemVariants = cva(\n \"group relative flex w-full items-center justify-between gap-3 rounded-lg px-3 py-2 text-sm font-medium transition-colors outline-none cursor-pointer select-none disabled:pointer-events-none disabled:opacity-50 transform duration-150 ease-in-out\",\n {\n variants: {\n hoverVariant: {\n default:\n \"hover:bg-accent hover:text-accent-foreground data-highlighted:bg-accent data-highlighted:text-accent-foreground\",\n accent:\n \"hover:bg-accent/80 hover:text-accent-foreground data-highlighted:bg-accent/80\",\n primary:\n \"hover:bg-primary/10 hover:text-primary data-highlighted:bg-primary/10 data-highlighted:text-primary\",\n muted:\n \"hover:bg-muted hover:text-foreground data-highlighted:bg-muted\",\n },\n size: {\n sm: \"px-2.5 py-1.5 text-xs\",\n md: \"px-3 py-2 text-sm\",\n lg: \"px-4 py-3 text-base\",\n },\n active: {\n true: \"bg-accent text-accent-foreground font-semibold\",\n false: \"\",\n },\n },\n defaultVariants: {\n hoverVariant: \"default\",\n size: \"md\",\n active: false,\n },\n }\n);\n\nexport interface ListItemProps\n extends JSX.HTMLAttributes<HTMLDivElement>,\n VariantProps<typeof listItemVariants> {\n title?: string;\n subtitle?: string;\n avatar?: string;\n avatarFallback?: string;\n icon?: Component<{ class?: string }>;\n shortcut?: string;\n showChevron?: boolean;\n href?: string;\n disabled?: boolean;\n active?: boolean;\n class?: string;\n}\n\n/**\n * Nikala UI ListItem Component.\n */\nexport const ListItem: Component<ListItemProps> = (props) => {\n const [local, rest] = splitProps(props, [\n \"title\",\n \"subtitle\",\n \"avatar\",\n \"avatarFallback\",\n \"icon\",\n \"shortcut\",\n \"showChevron\",\n \"href\",\n \"disabled\",\n \"active\",\n \"hoverVariant\",\n \"size\",\n \"class\",\n \"children\",\n ]);\n\n const content = () => (\n <>\n {/* Left Visual: Icon, Avatar, or Image */}\n <div class=\"flex items-center gap-2.5 min-w-0\">\n <Show when={local.avatar}>\n <img\n src={local.avatar}\n alt={local.title || \"Avatar\"}\n class=\"w-10 h-10 rounded-lg object-cover shrink-0 border border-border\"\n />\n </Show>\n\n <Show when={!local.avatar && local.avatarFallback}>\n <span class=\"w-10 h-10 rounded-lg bg-primary/10 text-primary text-[10px] font-bold flex items-center justify-center shrink-0 uppercase\">\n {local.avatarFallback}\n </span>\n </Show>\n\n <Show when={!local.avatar && !local.avatarFallback && local.icon}>\n <span class=\"shrink-0 text-muted-foreground group-hover:text-foreground transition-colors\">\n <Dynamic component={local.icon} class=\"w-4 h-4\" />\n </span>\n </Show>\n\n {/* Main Text Content */}\n <div class=\"flex flex-col min-w-0 text-left\">\n <Show when={local.title}>\n <span class=\"truncate font-medium leading-none\">\n {local.title}\n </span>\n </Show>\n <Show when={local.subtitle}>\n <span class=\"truncate text-xs opacity-50 font-normal mt-1\">\n {local.subtitle}\n </span>\n </Show>\n {local.children}\n </div>\n </div>\n\n {/* Right Visual: Shortcut Badge & Trailing Chevron */}\n <div class=\"flex items-center gap-2 shrink-0\">\n <Show when={local.shortcut}>\n <kbd class=\"pointer-events-none inline-flex h-5 select-none items-center gap-1 rounded border border-border bg-muted px-1.5 font-mono text-[10px] font-medium text-muted-foreground\">\n {local.shortcut}\n </kbd>\n </Show>\n\n <Show when={local.showChevron}>\n <ChevronRight class=\"w-4 h-4 text-muted-foreground transition-colors\" />\n </Show>\n </div>\n </>\n );\n\n const itemClasses = () =>\n cn(\n listItemVariants({\n hoverVariant: local.hoverVariant,\n size: local.size,\n active: local.active,\n }),\n local.class\n );\n\n return (\n <Show\n when={local.href}\n fallback={\n <div\n role=\"listitem\"\n class={itemClasses()}\n aria-disabled={local.disabled}\n {...rest}\n >\n {content()}\n </div>\n }\n >\n <a\n role=\"listitem\"\n href={local.href}\n class={itemClasses()}\n aria-disabled={local.disabled}\n {...(rest as JSX.AnchorHTMLAttributes<HTMLAnchorElement>)}\n >\n {content()}\n </a>\n </Show>\n );\n};",
|
|
17
|
+
"type": "registry:ui"
|
|
18
|
+
}
|
|
19
|
+
]
|
|
20
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "login-01",
|
|
3
|
+
"title": "Login 01 — Split Screen with Social Auth & Testimonial",
|
|
4
|
+
"description": "A modern split-screen authentication page block with OAuth providers, email sign-in form, and brand testimonial visual.",
|
|
5
|
+
"type": "registry:block",
|
|
6
|
+
"dependencies": [
|
|
7
|
+
"clsx",
|
|
8
|
+
"tailwind-merge",
|
|
9
|
+
"lucide-solid"
|
|
10
|
+
],
|
|
11
|
+
"registryDependencies": [
|
|
12
|
+
"button",
|
|
13
|
+
"input",
|
|
14
|
+
"label",
|
|
15
|
+
"checkbox",
|
|
16
|
+
"separator",
|
|
17
|
+
"form",
|
|
18
|
+
"field",
|
|
19
|
+
"form-message"
|
|
20
|
+
],
|
|
21
|
+
"files": [
|
|
22
|
+
{
|
|
23
|
+
"path": "blocks/login-01.tsx",
|
|
24
|
+
"content": "import { createSignal, Show, type Component } from \"solid-js\";\nimport { createForm } from \"@nikala-ui/hooks\";\nimport { Form } from \"../components/ui/form\";\nimport { Field, FieldLabel } from \"../components/ui/field\";\nimport { FormMessage } from \"../components/ui/form-message\";\nimport { Button } from \"../components/ui/button\";\nimport { Input } from \"../components/ui/input\";\nimport { Checkbox } from \"../components/ui/checkbox\";\nimport { Label } from \"../components/ui/label\";\nimport { Separator } from \"../components/ui/separator\";\nimport { Eye, EyeOff, Sparkles, ArrowRight } from \"lucide-solid\";\n\nexport const Login01: Component = () => {\n const [showPassword, setShowPassword] = createSignal(false);\n\n const form = createForm({\n initialValues: {\n email: \"\",\n password: \"\",\n rememberMe: true,\n },\n validate: (values) => {\n const errors: Record<string, string> = {};\n if (!values.email) {\n errors.email = \"Email is required\";\n } else if (!values.email.includes(\"@\")) {\n errors.email = \"Please enter a valid email address\";\n }\n if (!values.password) {\n errors.password = \"Password is required\";\n }\n return errors;\n },\n onSubmit: async (values) => {\n // Simulate API request\n await new Promise((resolve) => setTimeout(resolve, 1200));\n },\n });\n\n const isFormValid = () =>\n form.values().email.trim() !== \"\" &&\n form.values().email.includes(\"@\") &&\n form.values().password.trim() !== \"\";\n\n return (\n <div class=\"@container w-full min-h-[560px] @5xl:min-h-[700px] grid grid-cols-1 @5xl:grid-cols-2 bg-background text-foreground rounded-lg border border-border overflow-hidden shadow-xs\">\n {/* Left Column: Login Form */}\n <div class=\"flex flex-col justify-between p-6 @md:p-10 @5xl:p-12 w-full\">\n {/* Brand Header */}\n <div class=\"flex items-center gap-2.5\">\n <div class=\"size-8 rounded-lg bg-primary flex items-center justify-center text-primary-foreground font-bold text-sm shadow-2xs shrink-0\">\n N\n </div>\n <span class=\"font-bold text-lg tracking-tight\">Nikala UI</span>\n </div>\n\n {/* Form Container */}\n <div class=\"mx-auto w-full max-w-sm my-auto py-6 @md:py-8\">\n <div class=\"space-y-1.5 text-left mb-6\">\n <h1 class=\"text-2xl @md:text-3xl font-bold tracking-tight text-foreground\">\n Welcome back\n </h1>\n <p class=\"text-xs @md:text-sm text-muted-foreground\">\n Enter your credentials to access your account dashboard\n </p>\n </div>\n\n {/* Social OAuth Buttons */}\n <div class=\"grid grid-cols-1 @xs:grid-cols-2 gap-2.5 mb-6\">\n <Button variant=\"outline\" class=\"w-full justify-center text-xs @md:text-sm h-9\">\n <svg class=\"size-4 mr-2 shrink-0\" viewBox=\"0 0 24 24\" fill=\"currentColor\">\n <path d=\"M12 0C5.37 0 0 5.37 0 12c0 5.31 3.435 9.795 8.205 11.385.6.105.825-.255.825-.57 0-.285-.015-1.23-.015-2.235-3.015.555-3.795-.735-4.035-1.41-.135-.345-.72-1.41-1.23-1.695-.42-.225-1.02-.78-.015-.795.945-.015 1.62.87 1.845 1.23 1.08 1.815 2.805 1.305 3.495.99.105-.78.42-1.305.765-1.605-2.67-.3-5.46-1.335-5.46-5.925 0-1.305.465-2.385 1.23-3.225-.12-.3-.54-1.53.12-3.18 0 0 1.005-.315 3.3 1.23.96-.27 1.98-.405 3-.405s2.04.135 3 .405c2.295-1.56 3.3-1.23 3.3-1.23.66 1.65.24 2.88.12 3.18.765.84 1.23 1.905 1.23 3.225 0 4.605-2.805 5.625-5.475 5.925.435.375.81 1.095.81 2.22 0 1.605-.015 2.895-.015 3.3 0 .315.225.69.825.57A12.02 12.02 0 0024 12c0-6.63-5.37-12-12-12z\" />\n </svg>\n GitHub\n </Button>\n <Button variant=\"outline\" class=\"w-full justify-center text-xs @md:text-sm h-9\">\n <svg class=\"size-4 mr-2 shrink-0\" viewBox=\"0 0 24 24\">\n <path\n fill=\"#4285F4\"\n d=\"M23.745 12.27c0-.7-.06-1.4-.19-2.07H12v4.51h6.6c-.29 1.52-1.14 2.82-2.4 3.68v3.05h3.88c2.27-2.09 3.66-5.17 3.66-9.17z\"\n />\n <path\n fill=\"#34A853\"\n d=\"M12 24c3.24 0 5.95-1.08 7.93-2.91l-3.88-3.05c-1.08.72-2.45 1.16-4.05 1.16-3.12 0-5.77-2.1-6.72-4.93H1.25v3.15C3.26 21.36 7.33 24 12 24z\"\n />\n <path\n fill=\"#FBBC05\"\n d=\"M5.28 14.27c-.25-.72-.38-1.49-.38-2.27s.13-1.55.38-2.27V6.58H1.25C.45 8.18 0 10.03 0 12s.45 3.82 1.25 5.42l4.03-3.15z\"\n />\n <path\n fill=\"#EA4335\"\n d=\"M12 4.75c1.77 0 3.35.61 4.6 1.8l3.42-3.42C17.95 1.19 15.24 0 12 0 7.33 0 3.26 2.64 1.25 6.58l4.03 3.15c.95-2.83 3.6-4.98 6.72-4.98z\"\n />\n </svg>\n Google\n </Button>\n </div>\n\n <div class=\"relative mb-6\">\n <div class=\"absolute inset-0 flex items-center\">\n <Separator />\n </div>\n <div class=\"relative flex justify-center text-xs uppercase\">\n <span class=\"bg-background px-3 text-muted-foreground font-medium text-[11px]\">\n Or continue with email\n </span>\n </div>\n </div>\n\n {/* Form with Nikala UI Form & Field ecosystem */}\n <Form onSubmit={form.handleSubmit} loading={form.isSubmitting()} class=\"space-y-4\">\n <Field>\n <FieldLabel for=\"login-email\" class=\"text-xs @md:text-sm\">Email address</FieldLabel>\n <Input\n id=\"login-email\"\n type=\"email\"\n placeholder=\"name@company.com\"\n value={form.values().email}\n onInput={form.handleChange(\"email\")}\n onBlur={form.handleBlur(\"email\")}\n autocomplete=\"email\"\n />\n <FormMessage form={form} name=\"email\" />\n </Field>\n\n <Field>\n <div class=\"flex items-center justify-between\">\n <FieldLabel for=\"login-password\" class=\"text-xs @md:text-sm\">Password</FieldLabel>\n <a\n href=\"/blocks/forgot-password-01\"\n class=\"text-[11px] @md:text-xs text-primary font-medium hover:underline\"\n >\n Forgot password?\n </a>\n </div>\n <div class=\"relative\">\n <Input\n id=\"login-password\"\n type={showPassword() ? \"text\" : \"password\"}\n placeholder=\"••••••••\"\n value={form.values().password}\n onInput={form.handleChange(\"password\")}\n onBlur={form.handleBlur(\"password\")}\n autocomplete=\"current-password\"\n class=\"pr-10\"\n />\n <button\n type=\"button\"\n onClick={() => setShowPassword(!showPassword())}\n class=\"absolute right-3 top-1/2 -translate-y-1/2 text-muted-foreground hover:text-foreground transition-colors p-1 cursor-pointer\"\n aria-label={showPassword() ? \"Hide password\" : \"Show password\"}\n >\n <Show when={showPassword()} fallback={<Eye class=\"size-4\" />}>\n <EyeOff class=\"size-4\" />\n </Show>\n </button>\n </div>\n <FormMessage form={form} name=\"password\" />\n </Field>\n\n <div class=\"flex items-center space-x-2 pt-1\">\n <Checkbox\n id=\"remember\"\n checked={form.values().rememberMe}\n onChange={(checked) => form.setFieldValue(\"rememberMe\", checked)}\n />\n <Label\n for=\"remember\"\n class=\"text-xs font-normal text-muted-foreground cursor-pointer select-none\"\n >\n Remember me for 30 days\n </Label>\n </div>\n\n <Button\n type=\"submit\"\n class=\"w-full mt-2 font-medium\"\n disabled={form.isSubmitting() || !isFormValid()}\n >\n <Show when={form.isSubmitting()} fallback={<>Sign In <ArrowRight class=\"ml-2 size-4\" /></>}>\n Signing in...\n </Show>\n </Button>\n </Form>\n\n <p class=\"text-center text-xs text-muted-foreground mt-6\">\n Don't have an account?{\" \"}\n <a href=\"/blocks/register-01\" class=\"text-primary font-semibold hover:underline\">\n Sign up\n </a>\n </p>\n </div>\n\n {/* Footer info */}\n <div class=\"text-center @md:text-left text-xs text-muted-foreground pt-4 @md:pt-0\">\n By signing in, you agree to our{\" \"}\n <a href=\"#terms\" class=\"underline hover:text-foreground\">Terms of Service</a>{\" \"}\n and{\" \"}\n <a href=\"#privacy\" class=\"underline hover:text-foreground\">Privacy Policy</a>.\n </div>\n </div>\n\n {/* Right Column: Hero Visual & Art / Testimonial Showcase */}\n <div class=\"hidden @5xl:flex relative flex-col justify-between p-10 bg-muted/40 border-l border-border overflow-hidden\">\n <div class=\"absolute inset-0 bg-gradient-to-tr from-primary/10 via-transparent to-primary/5 pointer-events-none\" />\n\n <div class=\"relative z-10 flex items-center gap-2 text-sm font-semibold text-foreground/80\">\n <Sparkles class=\"size-4 text-primary\" />\n <span>Production Ready SolidJS UI</span>\n </div>\n\n <div class=\"relative z-10 max-w-md space-y-6\">\n <blockquote class=\"text-xl @md:text-2xl font-semibold tracking-tight text-foreground leading-snug\">\n \"Nikala UI transformed the way our team builds web applications with SolidJS. Fine-grained reactivity meets Tailwind v4 simplicity.\"\n </blockquote>\n <div class=\"space-y-1\">\n <p class=\"text-sm font-semibold text-foreground\">Davit Kakhidze</p>\n <p class=\"text-xs text-muted-foreground\">Head of Engineering at Studio</p>\n </div>\n </div>\n\n <div class=\"relative z-10 flex items-center justify-between text-xs text-muted-foreground\">\n <span>Honoring Niko Pirosmani</span>\n <span>© 2026 Nikala UI</span>\n </div>\n </div>\n </div>\n );\n};\n\nexport default Login01;\n",
|
|
25
|
+
"type": "registry:block"
|
|
26
|
+
}
|
|
27
|
+
]
|
|
28
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "logo",
|
|
3
|
+
"title": "Logo",
|
|
4
|
+
"description": "logo component.",
|
|
5
|
+
"type": "registry:ui",
|
|
6
|
+
"dependencies": [
|
|
7
|
+
"clsx",
|
|
8
|
+
"tailwind-merge"
|
|
9
|
+
],
|
|
10
|
+
"files": [
|
|
11
|
+
{
|
|
12
|
+
"path": "ui/logo.tsx",
|
|
13
|
+
"content": "import { splitProps, type Component, type JSX } from \"solid-js\";\nimport { cn } from \"@/lib/cn\";\n\nexport interface LogoProps extends JSX.SvgSVGAttributes<SVGSVGElement> {\n class?: string;\n}\n\n/**\n * Official Nikala UI Logo Component with dynamic contrast stroke and accent fill.\n */\nexport const Logo: Component<LogoProps> = (props) => {\n const [local, rest] = splitProps(props, [\"class\"]);\n\n return (\n <svg\n viewBox=\"0 0 223 223\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n class={cn(\"h-7 w-7 shrink-0 select-none\", local.class)}\n {...rest}\n >\n <g clip-path=\"url(#nikala-logo-clip0)\">\n {/* Background Box with Dynamic Theme Accent */}\n <path\n d=\"M0 10C0 4.47716 4.47715 0 10 0H213C218.523 0 223 4.47715 223 10V213C223 218.523 218.523 223 213 223H10C4.47716 223 0 218.523 0 213V10Z\"\n fill=\"currentColor\"\n class=\"text-primary\"\n />\n <g clip-path=\"url(#nikala-logo-clip1)\">\n {/* Paintbrush Vector Paths Adapting to --primary-foreground */}\n <path\n d=\"M304.406 364.173C303.147 366.03 301.738 366.903 299.847 368.109C299.093 368.594 298.339 369.08 297.563 369.58C296.746 370.096 295.929 370.613 295.087 371.145C294.245 371.684 293.402 372.224 292.56 372.764C290.346 374.183 288.127 375.594 285.907 377.003C283.642 378.443 281.381 379.891 279.119 381.338C274.684 384.175 270.243 387.003 265.799 389.826C263.196 387.86 261.543 385.492 259.734 382.813C257.432 379.465 255.089 376.207 252.52 373.055C249.122 368.864 246.081 364.457 243.017 360.02C240.337 356.141 237.507 352.385 234.645 348.639C233.944 347.722 233.244 346.804 232.544 345.886C232.19 345.421 231.836 344.956 231.471 344.477C228.856 341.031 226.35 337.519 223.876 333.97C222.068 331.395 220.171 328.922 218.188 326.48C214.782 322.267 211.726 317.844 208.65 313.389C205.969 309.51 203.14 305.755 200.277 302.009C199.577 301.091 198.877 300.173 198.177 299.255C197.823 298.79 197.468 298.326 197.103 297.847C194.79 294.798 192.553 291.706 190.364 288.567C188.267 285.56 186.094 282.644 183.786 279.794C179.935 275.035 176.476 270.016 173.005 264.978C176.445 262.305 179.941 259.802 183.612 257.457C184.099 257.143 184.587 256.829 185.089 256.505C186.679 255.481 188.271 254.461 189.863 253.441C190.975 252.726 192.086 252.011 193.197 251.296C196.106 249.425 199.016 247.557 201.927 245.689C204.903 243.779 207.878 241.866 210.853 239.953C216.678 236.208 222.505 232.466 228.333 228.726C230.86 230.623 232.252 232.791 233.788 235.512C234.053 235.974 234.319 236.435 234.592 236.911C236.235 239.797 237.775 242.723 239.261 245.694C241.392 249.953 243.79 254.007 246.245 258.083C248.04 261.081 249.715 264.098 251.272 267.229C253.667 272.041 256.413 276.612 259.173 281.219C261.596 285.264 263.845 289.394 266.071 293.549C266.617 294.566 267.163 295.584 267.709 296.601C267.986 297.115 268.262 297.63 268.547 298.161C270.366 301.528 272.256 304.843 274.208 308.135C276.068 311.27 277.812 314.435 279.438 317.698C281.864 322.542 284.628 327.154 287.41 331.798C289.839 335.853 292.092 339.995 294.328 344.159C294.597 344.658 294.866 345.158 295.143 345.673C295.7 346.71 296.256 347.748 296.81 348.786C298.15 351.28 299.518 353.74 300.998 356.154C301.259 356.583 301.519 357.012 301.788 357.454C302.503 358.619 303.23 359.775 303.958 360.931C304.8 362.85 304.8 362.85 304.406 364.173Z\"\n fill=\"var(--primary-foreground, #ffffff)\"\n />\n <path\n d=\"M147.908 159.434C143.029 162.624 138.255 165.222 132.524 166.53C131.568 166.759 131.568 166.759 130.593 166.992C117.641 169.419 104.681 165.652 93.8424 158.557C84.6301 151.709 78.5873 142.443 75.2903 131.528C75.0234 130.675 75.0234 130.675 74.7511 129.804C72.9741 122.986 73.9008 115.665 74.4194 108.713C75.7267 91.1539 72.9686 78.0313 62.8484 63.365C61.808 61.5353 61.808 61.5353 62.2756 59.3756C74.2777 52.1095 87.8993 50.9005 101.359 53.9904C102.212 54.1829 103.066 54.3753 103.945 54.5736C110.197 56.0433 115.833 57.7788 121.484 60.8918C121.926 61.1331 122.368 61.3745 122.823 61.6232C141.727 72.123 158.382 89.1592 164.804 110.159C170.072 129.189 164.608 147.982 147.908 159.434Z\"\n fill=\"var(--primary-foreground, #ffffff)\"\n />\n <path\n d=\"M224.945 222.724C223.467 224.948 221.157 226.154 218.937 227.554C218.142 228.066 218.142 228.067 217.331 228.589C215.58 229.716 213.822 230.833 212.065 231.95C210.849 232.73 209.634 233.51 208.418 234.291C205.22 236.344 202.016 238.389 198.811 240.432C195.542 242.519 192.277 244.613 189.012 246.706C182.605 250.813 176.192 254.911 169.776 259.003C163.425 254.055 159.038 246.461 154.501 239.887C151.859 236.063 149.162 232.301 146.129 228.777C140.59 220.962 138.709 211.47 139.907 202.042C141.806 192.774 145.937 185.415 153.125 179.281C153.821 178.654 154.516 178.028 155.232 177.382C161.199 173.349 167.362 171.636 174.492 171.096C175.187 171.029 175.187 171.029 175.896 170.961C185.36 171.183 194.837 174.7 201.562 181.385C202.406 182.334 203.235 183.298 204.044 184.277C204.596 184.933 204.596 184.933 205.159 185.602C207.879 189.006 209.907 192.696 211.94 196.538C212.966 198.458 213.996 200.376 215.027 202.293C215.301 202.803 215.574 203.312 215.856 203.837C218.216 208.207 220.709 212.489 223.254 216.754C225.579 220.827 225.579 220.827 224.945 222.724Z\"\n fill=\"var(--primary-foreground, #ffffff)\"\n />\n <path\n d=\"M346.445 469.84C341.579 473.016 337.792 473.996 331.992 473.069C323.666 471.041 319.697 464.544 315.142 457.786C314.41 456.773 313.671 455.764 312.923 454.762C312.555 454.269 312.187 453.775 311.808 453.267C310.744 451.858 309.676 450.454 308.605 449.052C304.588 443.792 300.674 438.482 296.873 433.064C294.268 429.365 291.554 425.754 288.807 422.16C288.108 421.244 287.41 420.328 286.711 419.412C286.181 418.717 286.181 418.717 285.639 418.007C283.312 414.94 281.064 411.828 278.863 408.669C275.954 404.511 272.86 400.557 269.591 396.676C270.596 393.987 272.077 392.99 274.463 391.469C275.568 390.758 275.568 390.758 276.694 390.032C277.891 389.276 277.891 389.276 279.111 388.505C279.926 387.983 280.74 387.461 281.58 386.923C283.742 385.538 285.909 384.16 288.077 382.784C290.29 381.378 292.498 379.965 294.707 378.552C299.039 375.782 303.376 373.02 307.716 370.264C310.189 371.73 310.549 372.854 311.779 375.43C313.714 379.343 315.815 383.09 318.072 386.826C320.626 391.064 322.954 395.349 325.158 399.782C326.672 402.673 328.329 405.458 330.013 408.252C332.566 412.491 334.894 416.776 337.098 421.209C338.613 424.099 340.27 426.884 341.953 429.678C344.974 434.704 347.722 439.785 350.305 445.052C350.628 445.646 350.95 446.239 351.282 446.851C355.467 454.895 353.749 464.19 346.445 469.84Z\"\n fill=\"var(--primary-foreground, #ffffff)\"\n />\n <path\n d=\"M175.175 164.461C174.611 164.495 174.047 164.529 173.466 164.565C161.822 165.517 151.451 170.117 143.632 178.98C141.188 182.058 138.963 185.278 136.798 188.557C134.916 187.16 133.636 185.817 132.364 183.853C132.04 183.352 131.717 182.852 131.383 182.336C131.053 181.817 130.724 181.297 130.384 180.762C130.043 180.241 129.703 179.719 129.351 179.182C129.031 178.682 128.711 178.182 128.381 177.668C128.089 177.211 127.796 176.755 127.495 176.285C126.898 175.109 126.898 175.109 127.21 173.669C127.885 173.594 127.885 173.594 128.573 173.517C144.325 171.353 156.368 162.585 166.151 150.449C168.977 152.315 170.506 155.002 172.283 157.806C172.597 158.285 172.911 158.765 173.234 159.26C175.527 162.839 175.527 162.839 175.175 164.461Z\"\n fill=\"var(--primary-foreground, #ffffff)\"\n />\n </g>\n </g>\n <defs>\n <clipPath id=\"nikala-logo-clip0\">\n <rect width=\"223\" height=\"223\" rx=\"10\" fill=\"white\" />\n </clipPath>\n <clipPath id=\"nikala-logo-clip1\">\n <rect\n width=\"377.121\"\n height=\"377.121\"\n fill=\"white\"\n transform=\"translate(431.932 116.81) rotate(102.218)\"\n />\n </clipPath>\n </defs>\n </svg>\n );\n};",
|
|
14
|
+
"type": "registry:ui"
|
|
15
|
+
}
|
|
16
|
+
]
|
|
17
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "marker",
|
|
3
|
+
"title": "Marker",
|
|
4
|
+
"description": "System chat events, date dividers, and live typing indicator badges.",
|
|
5
|
+
"type": "registry:ui",
|
|
6
|
+
"dependencies": [
|
|
7
|
+
"clsx",
|
|
8
|
+
"tailwind-merge"
|
|
9
|
+
],
|
|
10
|
+
"files": [
|
|
11
|
+
{
|
|
12
|
+
"path": "ui/marker.tsx",
|
|
13
|
+
"content": "import {\n splitProps,\n type Component,\n type JSX,\n type ParentComponent,\n Show,\n} from \"solid-js\";\nimport { cn } from \"@/lib/cn\";\n\n/* --- 1. Marker Root --- */\nexport interface MarkerProps extends JSX.HTMLAttributes<HTMLDivElement> {\n class?: string;\n}\n\nexport const Marker: ParentComponent<MarkerProps> = (props) => {\n const [local, rest] = splitProps(props, [\"class\", \"children\"]);\n\n return (\n <div\n role=\"status\"\n class={cn(\"flex w-full items-center justify-center my-3 text-center select-none\", local.class)}\n {...rest}\n >\n {local.children}\n </div>\n );\n};\n\n/* --- 2. MarkerContent --- */\nexport interface MarkerContentProps extends JSX.HTMLAttributes<HTMLDivElement> {\n class?: string;\n}\n\nexport const MarkerContent: ParentComponent<MarkerContentProps> = (props) => {\n const [local, rest] = splitProps(props, [\"class\", \"children\"]);\n\n return (\n <div\n class={cn(\n \"inline-flex items-center gap-1.5 rounded-lg border border-border/60 bg-muted/40 px-3 py-1 text-xs text-muted-foreground shadow-2xs backdrop-blur-xs\",\n local.class\n )}\n {...rest}\n >\n {local.children}\n </div>\n );\n};\n\n/* --- 3. MarkerDate (Date Divider) --- */\nexport interface MarkerDateProps extends JSX.HTMLAttributes<HTMLDivElement> {\n date?: string;\n class?: string;\n}\n\nexport const MarkerDate: ParentComponent<MarkerDateProps> = (props) => {\n const [local, rest] = splitProps(props, [\"date\", \"class\", \"children\"]);\n\n return (\n <div\n class={cn(\"relative flex w-full items-center justify-center my-4\", local.class)}\n {...rest}\n >\n <div class=\"absolute inset-0 flex items-center\">\n <div class=\"w-full border-t border-border/50\" />\n </div>\n <div class=\"relative flex items-center gap-1 bg-background px-3 py-0.5 text-[11px] font-medium uppercase tracking-wider text-muted-foreground rounded-md border border-border/40\">\n {local.children || local.date}\n </div>\n </div>\n );\n};\n\n/* --- 4. MarkerTyping (Live Typing Indicator) --- */\nexport interface MarkerTypingProps extends JSX.HTMLAttributes<HTMLDivElement> {\n name?: string;\n class?: string;\n}\n\nexport const MarkerTyping: Component<MarkerTypingProps> = (props) => {\n const [local, rest] = splitProps(props, [\"name\", \"class\"]);\n\n return (\n <div\n role=\"status\"\n aria-label={`${local.name || \"Someone\"} is typing`}\n class={cn(\"flex w-full items-center gap-2 text-xs text-muted-foreground my-2\", local.class)}\n {...rest}\n >\n <Show when={local.name}>\n <span class=\"font-medium text-foreground\">{local.name}</span> is typing\n </Show>\n\n {/* 3 Animated Bouncing Dots */}\n <span class=\"inline-flex items-center gap-1 px-2 py-1 rounded-md bg-muted/60 border border-border/40\">\n <span class=\"size-1.5 rounded-lg bg-foreground/60 animate-bounce [animation-delay:-0.3s]\" />\n <span class=\"size-1.5 rounded-lg bg-foreground/60 animate-bounce [animation-delay:-0.15s]\" />\n <span class=\"size-1.5 rounded-lg bg-foreground/60 animate-bounce\" />\n </span>\n </div>\n );\n};\n",
|
|
14
|
+
"type": "registry:ui"
|
|
15
|
+
}
|
|
16
|
+
]
|
|
17
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "marquee",
|
|
3
|
+
"title": "Marquee",
|
|
4
|
+
"description": "A smooth, GPU-accelerated infinite scrolling ticker component for logo clouds, testimonials, and live ribbons.",
|
|
5
|
+
"type": "registry:ui",
|
|
6
|
+
"dependencies": [
|
|
7
|
+
"clsx",
|
|
8
|
+
"tailwind-merge"
|
|
9
|
+
],
|
|
10
|
+
"files": [
|
|
11
|
+
{
|
|
12
|
+
"path": "ui/marquee.tsx",
|
|
13
|
+
"content": "import {\n splitProps,\n createMemo,\n Index,\n type JSX,\n type ParentComponent,\n} from \"solid-js\";\nimport { cn } from \"@/lib/cn\";\n\nexport interface MarqueeProps extends JSX.HTMLAttributes<HTMLDivElement> {\n class?: string;\n reverse?: boolean;\n pauseOnHover?: boolean;\n vertical?: boolean;\n repeat?: number;\n duration?: number | string;\n gap?: string;\n fadeEdges?: boolean;\n}\n\nexport const Marquee: ParentComponent<MarqueeProps> = (props) => {\n const [local, rest] = splitProps(props, [\n \"class\",\n \"reverse\",\n \"pauseOnHover\",\n \"vertical\",\n \"repeat\",\n \"duration\",\n \"gap\",\n \"fadeEdges\",\n \"children\",\n ]);\n\n const repeatCount = () => local.repeat ?? 4;\n const durationValue = () =>\n typeof local.duration === \"number\"\n ? `${local.duration}s`\n : local.duration || \"40s\";\n const gapValue = () => local.gap || \"1rem\";\n\n const repeatArray = createMemo(() =>\n Array.from({ length: repeatCount() }, (_, i) => i)\n );\n\n return (\n <>\n <style>{`\n @keyframes nikala-marquee {\n from {\n transform: translateX(0);\n }\n to {\n transform: translateX(calc(-100% - var(--marquee-gap, 1rem)));\n }\n }\n @keyframes nikala-marquee-vertical {\n from {\n transform: translateY(0);\n }\n to {\n transform: translateY(calc(-100% - var(--marquee-gap, 1rem)));\n }\n }\n .nikala-marquee-track {\n animation: nikala-marquee var(--marquee-duration, 40s) linear infinite;\n }\n .nikala-marquee-track-vertical {\n animation: nikala-marquee-vertical var(--marquee-duration, 40s) linear infinite;\n }\n [data-reverse=\"true\"] .nikala-marquee-track,\n [data-reverse=\"true\"] .nikala-marquee-track-vertical {\n animation-direction: reverse;\n }\n [data-pause=\"true\"]:hover .nikala-marquee-track,\n [data-pause=\"true\"]:hover .nikala-marquee-track-vertical {\n animation-play-state: paused;\n }\n `}</style>\n <div\n data-reverse={local.reverse ? \"true\" : \"false\"}\n data-pause={local.pauseOnHover ? \"true\" : \"false\"}\n style={{\n \"--marquee-duration\": durationValue(),\n \"--marquee-gap\": gapValue(),\n }}\n class={cn(\n \"group flex overflow-hidden p-2 select-none\",\n local.vertical ? \"flex-col h-full\" : \"flex-row w-full\",\n local.fadeEdges &&\n (local.vertical\n ? \"[mask-image:linear-gradient(to_bottom,transparent,black_10%,black_90%,transparent)]\"\n : \"[mask-image:linear-gradient(to_right,transparent,black_10%,black_90%,transparent)]\"),\n local.class\n )}\n {...rest}\n >\n <Index each={repeatArray()}>\n {() => (\n <div\n class={cn(\n \"flex shrink-0 justify-around items-center\",\n local.vertical\n ? \"flex-col min-h-full nikala-marquee-track-vertical\"\n : \"flex-row min-w-full nikala-marquee-track\"\n )}\n style={{\n gap: gapValue(),\n [local.vertical ? \"margin-bottom\" : \"margin-right\"]: gapValue(),\n }}\n >\n {local.children}\n </div>\n )}\n </Index>\n </div>\n </>\n );\n};\n",
|
|
14
|
+
"type": "registry:ui"
|
|
15
|
+
}
|
|
16
|
+
]
|
|
17
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "message",
|
|
3
|
+
"title": "Message",
|
|
4
|
+
"description": "A structured chat and conversation message layout with avatars, alignment, headers, footers, and actions.",
|
|
5
|
+
"type": "registry:ui",
|
|
6
|
+
"dependencies": [
|
|
7
|
+
"clsx",
|
|
8
|
+
"tailwind-merge"
|
|
9
|
+
],
|
|
10
|
+
"files": [
|
|
11
|
+
{
|
|
12
|
+
"path": "ui/message.tsx",
|
|
13
|
+
"content": "import {\n createContext,\n useContext,\n splitProps,\n type Component,\n type JSX,\n type ParentComponent,\n type Accessor,\n} from \"solid-js\";\nimport { cn } from \"@/lib/cn\";\n\n/* --- 1. Message Context --- */\nexport type MessageAlignment = \"start\" | \"end\";\n\ninterface MessageContextValue {\n align: Accessor<MessageAlignment>;\n}\n\nconst MessageContext = createContext<MessageContextValue>();\n\nexport function useMessage() {\n const context = useContext(MessageContext);\n if (!context) {\n throw new Error(\"useMessage must be used within a <Message />\");\n }\n return context;\n}\n\n/* --- 2. Message Root --- */\nexport interface MessageProps extends JSX.HTMLAttributes<HTMLDivElement> {\n align?: MessageAlignment;\n class?: string;\n}\n\nexport const Message: ParentComponent<MessageProps> = (props) => {\n const [local, rest] = splitProps(props, [\"align\", \"class\", \"children\"]);\n const align = () => local.align ?? \"start\";\n\n const contextValue: MessageContextValue = {\n align,\n };\n\n return (\n <MessageContext.Provider value={contextValue}>\n <div\n data-align={align()}\n class={cn(\n \"group/message flex w-full gap-3\",\n align() === \"end\" ? \"flex-row-reverse items-start\" : \"flex-row items-start\",\n local.class\n )}\n {...rest}\n >\n {local.children}\n </div>\n </MessageContext.Provider>\n );\n};\n\n/* --- 3. MessageAvatar --- */\nexport interface MessageAvatarProps extends JSX.HTMLAttributes<HTMLDivElement> {\n class?: string;\n}\n\nexport const MessageAvatar: ParentComponent<MessageAvatarProps> = (props) => {\n const [local, rest] = splitProps(props, [\"class\", \"children\"]);\n\n return (\n <div\n class={cn(\"shrink-0 select-none pt-0.5\", local.class)}\n {...rest}\n >\n {local.children}\n </div>\n );\n};\n\n/* --- 4. MessageHeader --- */\nexport interface MessageHeaderProps extends JSX.HTMLAttributes<HTMLDivElement> {\n class?: string;\n}\n\nexport const MessageHeader: ParentComponent<MessageHeaderProps> = (props) => {\n const [local, rest] = splitProps(props, [\"class\", \"children\"]);\n const { align } = useMessage();\n\n return (\n <div\n class={cn(\n \"flex items-center gap-2 text-xs text-muted-foreground select-none mb-1\",\n align() === \"end\" ? \"justify-end\" : \"justify-start\",\n local.class\n )}\n {...rest}\n >\n {local.children}\n </div>\n );\n};\n\n/* --- 5. MessageContent --- */\nexport interface MessageContentProps extends JSX.HTMLAttributes<HTMLDivElement> {\n class?: string;\n}\n\nexport const MessageContent: ParentComponent<MessageContentProps> = (props) => {\n const [local, rest] = splitProps(props, [\"class\", \"children\"]);\n const { align } = useMessage();\n\n return (\n <div\n class={cn(\n \"flex flex-col gap-1.5 max-w-[85%] sm:max-w-[75%]\",\n align() === \"end\" ? \"items-end text-right\" : \"items-start text-left\",\n local.class\n )}\n {...rest}\n >\n {local.children}\n </div>\n );\n};\n\n/* --- 6. MessageFooter --- */\nexport interface MessageFooterProps extends JSX.HTMLAttributes<HTMLDivElement> {\n class?: string;\n}\n\nexport const MessageFooter: ParentComponent<MessageFooterProps> = (props) => {\n const [local, rest] = splitProps(props, [\"class\", \"children\"]);\n const { align } = useMessage();\n\n return (\n <div\n class={cn(\n \"flex items-center gap-1.5 text-[11px] text-muted-foreground select-none mt-1\",\n align() === \"end\" ? \"justify-end\" : \"justify-start\",\n local.class\n )}\n {...rest}\n >\n {local.children}\n </div>\n );\n};\n\n/* --- 7. MessageActions --- */\nexport interface MessageActionsProps extends JSX.HTMLAttributes<HTMLDivElement> {\n class?: string;\n}\n\nexport const MessageActions: ParentComponent<MessageActionsProps> = (props) => {\n const [local, rest] = splitProps(props, [\"class\", \"children\"]);\n const { align } = useMessage();\n\n return (\n <div\n class={cn(\n \"opacity-0 group-hover/message:opacity-100 focus-within:opacity-100 transition-opacity flex items-center gap-1 p-0.5 rounded-md border border-border bg-background shadow-xs\",\n align() === \"end\" ? \"flex-row-reverse\" : \"flex-row\",\n local.class\n )}\n {...rest}\n >\n {local.children}\n </div>\n );\n};\n",
|
|
14
|
+
"type": "registry:ui"
|
|
15
|
+
}
|
|
16
|
+
]
|
|
17
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "navbar",
|
|
3
|
+
"title": "Navbar",
|
|
4
|
+
"description": "A responsive, accessible, and composable top navigation header suite supporting nested dropdown flyouts, floating card containers, and mobile navigation drawers.",
|
|
5
|
+
"type": "registry:ui",
|
|
6
|
+
"dependencies": [
|
|
7
|
+
"clsx",
|
|
8
|
+
"tailwind-merge",
|
|
9
|
+
"class-variance-authority",
|
|
10
|
+
"lucide-solid"
|
|
11
|
+
],
|
|
12
|
+
"files": [
|
|
13
|
+
{
|
|
14
|
+
"path": "ui/navbar.tsx",
|
|
15
|
+
"content": "import {\n createContext,\n createSignal,\n useContext,\n splitProps,\n Show,\n type JSX,\n type ParentComponent,\n type Component,\n type Accessor,\n type ValidComponent,\n} from \"solid-js\";\nimport { Dynamic } from \"solid-js/web\";\nimport { cva, type VariantProps } from \"class-variance-authority\";\nimport { Menu, X } from \"lucide-solid\";\nimport { cn } from \"@/lib/cn\";\n\n/* --- Navbar Context --- */\ninterface NavbarContextValue {\n isOpen: Accessor<boolean>;\n setIsOpen: (open: boolean) => void;\n toggleMobileMenu: () => void;\n}\n\nconst NavbarContext = createContext<NavbarContextValue>();\n\nexport function useNavbar() {\n const context = useContext(NavbarContext);\n if (!context) {\n throw new Error(\"useNavbar must be used within a <Navbar /> component\");\n }\n return context;\n}\n\n/* --- Root Navbar --- */\nexport const navbarVariants = cva(\n \"w-full transition-all duration-200 z-40\",\n {\n variants: {\n variant: {\n default: \"border-b border-border/60 bg-background/80 backdrop-blur-md\",\n floating: \"my-3 rounded-lg border border-border/80 bg-background/90 backdrop-blur-md shadow-sm\",\n bordered: \"border-b border-border bg-background\",\n transparent: \"bg-transparent border-transparent\",\n },\n isSticky: {\n true: \"sticky top-0\",\n false: \"relative\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n isSticky: true,\n },\n }\n);\n\nexport interface NavbarProps\n extends JSX.HTMLAttributes<HTMLElement>,\n VariantProps<typeof navbarVariants> {\n maxWidth?: \"sm\" | \"md\" | \"lg\" | \"xl\" | \"2xl\" | \"full\";\n open?: boolean;\n onOpenChange?: (open: boolean) => void;\n}\n\nexport const Navbar: ParentComponent<NavbarProps> = (props) => {\n const [local, rest] = splitProps(props, [\n \"class\",\n \"variant\",\n \"isSticky\",\n \"maxWidth\",\n \"open\",\n \"onOpenChange\",\n \"children\",\n ]);\n\n const [internalOpen, setInternalOpen] = createSignal(false);\n const isOpen = () => (local.open !== undefined ? local.open : internalOpen());\n\n const setIsOpen = (open: boolean) => {\n if (local.open === undefined) {\n setInternalOpen(open);\n }\n local.onOpenChange?.(open);\n };\n\n const toggleMobileMenu = () => setIsOpen(!isOpen());\n\n const maxWidthClass = () => {\n switch (local.maxWidth) {\n case \"sm\":\n return \"max-w-screen-sm\";\n case \"md\":\n return \"max-w-screen-md\";\n case \"lg\":\n return \"max-w-screen-lg\";\n case \"xl\":\n return \"max-w-screen-xl\";\n case \"full\":\n return \"max-w-full\";\n case \"2xl\":\n default:\n return \"max-w-screen-2xl\";\n }\n };\n\n return (\n <NavbarContext.Provider value={{ isOpen, setIsOpen, toggleMobileMenu }}>\n <header\n class={cn(\n navbarVariants({\n variant: local.variant,\n isSticky: local.isSticky,\n }),\n local.variant === \"floating\" && cn(\"mx-auto\", maxWidthClass()),\n local.class\n )}\n {...rest}\n >\n <div class={cn(\"w-full\", local.variant !== \"floating\" && cn(\"mx-auto\", maxWidthClass()))}>\n {local.children}\n </div>\n </header>\n </NavbarContext.Provider>\n );\n};\n\n/* --- Navbar Container (Top Flex Row) --- */\nexport interface NavbarContainerProps extends JSX.HTMLAttributes<HTMLDivElement> {\n class?: string;\n}\n\nexport const NavbarContainer: ParentComponent<NavbarContainerProps> = (props) => {\n const [local, rest] = splitProps(props, [\"class\", \"children\"]);\n\n return (\n <div\n class={cn(\n \"flex h-14 md:h-16 items-center justify-between px-4 sm:px-6 lg:px-8 gap-3 w-full\",\n local.class\n )}\n {...rest}\n >\n {local.children}\n </div>\n );\n};\n\n/* --- Navbar Brand / Logo Container --- */\nexport interface NavbarBrandProps<T extends ValidComponent = \"a\"> extends JSX.AnchorHTMLAttributes<HTMLAnchorElement> {\n class?: string;\n as?: T;\n href?: string;\n}\n\nexport const NavbarBrand = <T extends ValidComponent = \"a\">(props: NavbarBrandProps<T>) => {\n const [local, rest] = splitProps(props as NavbarBrandProps, [\"class\", \"as\", \"children\"]);\n\n return (\n <Dynamic\n component={local.as || \"a\"}\n class={cn(\n \"flex items-center gap-2 font-bold text-foreground transition-opacity hover:opacity-90 cursor-pointer shrink-0\",\n local.class\n )}\n {...rest}\n >\n {local.children}\n </Dynamic>\n );\n};\n\n/* --- Navbar Content / Section --- */\nexport const navbarContentVariants = cva(\"flex items-center gap-1 sm:gap-2 h-full\", {\n variants: {\n justify: {\n start: \"justify-start flex-1\",\n center: \"justify-center flex-1\",\n end: \"justify-end flex-1\",\n },\n },\n defaultVariants: {\n justify: \"center\",\n },\n});\n\nexport interface NavbarContentProps\n extends JSX.HTMLAttributes<HTMLDivElement>,\n VariantProps<typeof navbarContentVariants> {\n class?: string;\n hideOnMobile?: boolean;\n}\n\nexport const NavbarContent: ParentComponent<NavbarContentProps> = (props) => {\n const [local, rest] = splitProps(props, [\"class\", \"justify\", \"hideOnMobile\", \"children\"]);\n\n return (\n <div\n class={cn(\n navbarContentVariants({ justify: local.justify }),\n local.class\n )}\n {...rest}\n >\n {local.children}\n </div>\n );\n};\n\n/* --- Navbar Item --- */\nexport interface NavbarItemProps extends JSX.HTMLAttributes<HTMLDivElement> {\n class?: string;\n isActive?: boolean;\n}\n\nexport const NavbarItem: ParentComponent<NavbarItemProps> = (props) => {\n const [local, rest] = splitProps(props, [\"class\", \"isActive\", \"children\"]);\n\n return (\n <div\n class={cn(\n \"relative flex items-center h-full text-sm font-medium\",\n local.class\n )}\n {...rest}\n >\n {local.children}\n <Show when={local.isActive}>\n <div class=\"absolute -bottom-px left-0 right-0 h-0.5 bg-primary rounded-lg z-10\" />\n </Show>\n </div>\n );\n};\n\n/* --- Navbar Link --- */\nexport const navbarLinkVariants = cva(\n \"inline-flex h-9 items-center justify-center rounded-md px-3 text-sm font-medium transition-colors cursor-pointer select-none focus-visible:outline-hidden\",\n {\n variants: {\n variant: {\n default:\n \"text-muted-foreground hover:bg-muted hover:text-foreground\",\n active:\n \"text-foreground font-semibold bg-muted/80\",\n ghost:\n \"text-foreground hover:text-primary\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n },\n }\n);\n\nexport interface NavbarLinkProps<T extends ValidComponent = \"a\">\n extends JSX.AnchorHTMLAttributes<HTMLAnchorElement>,\n VariantProps<typeof navbarLinkVariants> {\n class?: string;\n isActive?: boolean;\n as?: T;\n href?: string;\n}\n\nexport const NavbarLink = <T extends ValidComponent = \"a\">(props: NavbarLinkProps<T>) => {\n const [local, rest] = splitProps(props as NavbarLinkProps, [\"class\", \"variant\", \"isActive\", \"as\", \"children\"]);\n\n return (\n <Dynamic\n component={local.as || \"a\"}\n class={cn(\n navbarLinkVariants({\n variant: local.isActive ? \"active\" : local.variant,\n }),\n local.class\n )}\n {...rest}\n >\n {local.children}\n </Dynamic>\n );\n};\n\n/* --- Navbar Actions Container --- */\nexport interface NavbarActionsProps extends JSX.HTMLAttributes<HTMLDivElement> {\n class?: string;\n}\n\nexport const NavbarActions: ParentComponent<NavbarActionsProps> = (props) => {\n const [local, rest] = splitProps(props, [\"class\", \"children\"]);\n\n return (\n <div class={cn(\"flex items-center gap-2 shrink-0\", local.class)} {...rest}>\n {local.children}\n </div>\n );\n};\n\n/* --- Navbar Mobile Toggle Button --- */\nexport interface NavbarMobileToggleProps extends JSX.ButtonHTMLAttributes<HTMLButtonElement> {\n class?: string;\n}\n\nexport const NavbarMobileToggle: Component<NavbarMobileToggleProps> = (props) => {\n const [local, rest] = splitProps(props, [\"class\"]);\n const { isOpen, toggleMobileMenu } = useNavbar();\n\n return (\n <button\n type=\"button\"\n onClick={toggleMobileMenu}\n aria-label=\"Toggle navigation menu\"\n aria-expanded={isOpen()}\n class={cn(\n \"inline-flex md:hidden size-8 items-center justify-center rounded-md border border-border/60 bg-muted/30 text-muted-foreground hover:bg-muted hover:text-foreground transition-colors cursor-pointer focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring shrink-0\",\n local.class\n )}\n {...rest}\n >\n <Show when={isOpen()} fallback={<Menu class=\"size-4\" />}>\n <X class=\"size-4\" />\n </Show>\n </button>\n );\n};\n\n/* --- Navbar Mobile Menu Container --- */\nexport interface NavbarMobileMenuProps extends JSX.HTMLAttributes<HTMLDivElement> {\n class?: string;\n}\n\nexport const NavbarMobileMenu: ParentComponent<NavbarMobileMenuProps> = (props) => {\n const [local, rest] = splitProps(props, [\"class\", \"children\"]);\n const { isOpen } = useNavbar();\n\n return (\n <Show when={isOpen()}>\n <div\n class={cn(\n \"md:hidden w-full border-t border-border/60 bg-background/95 backdrop-blur-lg px-4 py-3 space-y-1 shadow-md transition-all\",\n local.class\n )}\n {...rest}\n >\n {local.children}\n </div>\n </Show>\n );\n};\n\n/* --- Navbar Mobile Item & Link --- */\nexport interface NavbarMobileLinkProps extends JSX.AnchorHTMLAttributes<HTMLAnchorElement> {\n class?: string;\n isActive?: boolean;\n}\n\nexport const NavbarMobileLink: ParentComponent<NavbarMobileLinkProps> = (props) => {\n const [local, rest] = splitProps(props, [\"class\", \"isActive\", \"children\"]);\n const { setIsOpen } = useNavbar();\n\n return (\n <a\n onClick={() => setIsOpen(false)}\n class={cn(\n \"flex w-full items-center justify-between rounded-md px-3 py-2 text-sm font-medium transition-colors cursor-pointer\",\n local.isActive\n ? \"bg-primary text-primary-foreground font-semibold shadow-2xs\"\n : \"text-muted-foreground hover:bg-muted/80 hover:text-foreground\",\n local.class\n )}\n {...rest}\n >\n {local.children}\n </a>\n );\n};\n",
|
|
16
|
+
"type": "registry:ui"
|
|
17
|
+
}
|
|
18
|
+
]
|
|
19
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "navigation-menu",
|
|
3
|
+
"title": "Navigation Menu",
|
|
4
|
+
"description": "A responsive and accessible top header navigation menu with mega-menu dropdowns and link previews.",
|
|
5
|
+
"type": "registry:ui",
|
|
6
|
+
"dependencies": [
|
|
7
|
+
"clsx",
|
|
8
|
+
"tailwind-merge",
|
|
9
|
+
"class-variance-authority",
|
|
10
|
+
"lucide-solid"
|
|
11
|
+
],
|
|
12
|
+
"registryDependencies": [
|
|
13
|
+
"create-click-outside"
|
|
14
|
+
],
|
|
15
|
+
"files": [
|
|
16
|
+
{
|
|
17
|
+
"path": "ui/navigation-menu.tsx",
|
|
18
|
+
"content": "import {\n createContext,\n createSignal,\n useContext,\n splitProps,\n onCleanup,\n type Component,\n type JSX,\n type ParentComponent,\n type Accessor,\n Show,\n} from \"solid-js\";\nimport { cva, type VariantProps } from \"class-variance-authority\";\nimport { createClickOutside } from \"@/hooks/create-click-outside\";\nimport { cn } from \"@/lib/cn\";\nimport { ChevronDown } from \"lucide-solid\";\n\n/* --- Context Definition --- */\ninterface NavigationMenuContextValue {\n activeValue: Accessor<string | null>;\n setActiveValue: (value: string | null) => void;\n onItemMouseEnter: (value: string) => void;\n onItemMouseLeave: () => void;\n delayMs: Accessor<number>;\n}\n\nconst NavigationMenuContext = createContext<NavigationMenuContextValue>();\n\nfunction useNavigationMenu() {\n const context = useContext(NavigationMenuContext);\n if (!context) {\n throw new Error(\"useNavigationMenu must be used within a <NavigationMenu />\");\n }\n return context;\n}\n\n/* --- 1. NavigationMenu Root --- */\nexport interface NavigationMenuProps extends JSX.HTMLAttributes<HTMLElement> {\n class?: string;\n delayMs?: number;\n value?: string | null;\n onValueChange?: (value: string | null) => void;\n}\n\nexport const NavigationMenu: ParentComponent<NavigationMenuProps> = (props) => {\n const [local, rest] = splitProps(props, [\"class\", \"delayMs\", \"value\", \"onValueChange\", \"children\"]);\n\n const [internalValue, setInternalValue] = createSignal<string | null>(local.value ?? null);\n const activeValue = () => (local.value !== undefined ? local.value : internalValue());\n\n const setActiveValue = (val: string | null) => {\n if (local.value === undefined) {\n setInternalValue(val);\n }\n local.onValueChange?.(val);\n };\n\n let rootRef!: HTMLElement;\n let timer: ReturnType<typeof setTimeout> | undefined;\n const delay = () => local.delayMs ?? 150;\n\n const onItemMouseEnter = (val: string) => {\n clearTimeout(timer);\n const ms = delay();\n if (ms <= 0) {\n setActiveValue(val);\n } else {\n timer = setTimeout(() => {\n setActiveValue(val);\n }, ms);\n }\n };\n\n const onItemMouseLeave = () => {\n clearTimeout(timer);\n const ms = delay();\n timer = setTimeout(() => {\n setActiveValue(null);\n }, Math.max(50, ms));\n };\n\n createClickOutside({\n target: () => rootRef,\n onInteractOutside: () => {\n setActiveValue(null);\n },\n });\n\n onCleanup(() => {\n clearTimeout(timer);\n });\n\n const contextValue: NavigationMenuContextValue = {\n activeValue,\n setActiveValue,\n onItemMouseEnter,\n onItemMouseLeave,\n delayMs: delay,\n };\n\n return (\n <NavigationMenuContext.Provider value={contextValue}>\n <nav\n ref={rootRef}\n aria-label=\"Main Navigation\"\n class={cn(\"relative z-10 flex max-w-max flex-1 items-center justify-center\", local.class)}\n {...rest}\n >\n {local.children}\n </nav>\n </NavigationMenuContext.Provider>\n );\n};\n\n/* --- 2. NavigationMenuList --- */\nexport interface NavigationMenuListProps extends JSX.HTMLAttributes<HTMLUListElement> {\n class?: string;\n}\n\nexport const NavigationMenuList: ParentComponent<NavigationMenuListProps> = (props) => {\n const [local, rest] = splitProps(props, [\"class\", \"children\"]);\n\n return (\n <ul\n class={cn(\n \"group flex flex-1 list-none items-center justify-center space-x-1 p-1\",\n local.class\n )}\n {...rest}\n >\n {local.children}\n </ul>\n );\n};\n\n/* --- 3. NavigationMenuItem Context & Component --- */\ninterface NavigationMenuItemContextValue {\n value: string;\n isOpen: Accessor<boolean>;\n}\n\nconst NavigationMenuItemContext = createContext<NavigationMenuItemContextValue>();\n\nfunction useNavigationMenuItem() {\n const context = useContext(NavigationMenuItemContext);\n if (!context) {\n throw new Error(\"useNavigationMenuItem must be used within a <NavigationMenuItem />\");\n }\n return context;\n}\n\nexport interface NavigationMenuItemProps extends JSX.HTMLAttributes<HTMLLIElement> {\n value?: string;\n class?: string;\n}\n\nlet itemCounter = 0;\n\nexport const NavigationMenuItem: ParentComponent<NavigationMenuItemProps> = (props) => {\n const itemId = props.value ?? `nav-item-${++itemCounter}`;\n const [local, rest] = splitProps(props, [\"class\", \"value\", \"children\"]);\n const rootContext = useNavigationMenu();\n\n const isOpen = () => rootContext.activeValue() === itemId;\n\n const itemContext: NavigationMenuItemContextValue = {\n value: itemId,\n isOpen,\n };\n\n return (\n <NavigationMenuItemContext.Provider value={itemContext}>\n <li\n class={cn(\"relative\", local.class)}\n onMouseEnter={() => rootContext.onItemMouseEnter(itemId)}\n onMouseLeave={() => rootContext.onItemMouseLeave()}\n {...rest}\n >\n {local.children}\n </li>\n </NavigationMenuItemContext.Provider>\n );\n};\n\n/* --- 4. Trigger Style Helper --- */\nexport const navigationMenuTriggerVariants = cva(\n \"group inline-flex h-9 items-center justify-center rounded-md px-3 text-sm font-medium transition-colors focus-visible:outline-hidden disabled:pointer-events-none disabled:opacity-50 cursor-pointer select-none gap-1\",\n {\n variants: {\n variant: {\n default:\n \"bg-transparent text-muted-foreground hover:bg-muted hover:text-foreground data-[state=open]:bg-muted data-[state=open]:text-foreground\",\n filled:\n \"bg-muted/60 text-foreground hover:bg-muted border border-border/40 data-[state=open]:bg-muted\",\n ghost:\n \"bg-transparent text-foreground hover:bg-accent hover:text-accent-foreground data-[state=open]:bg-accent/60\",\n outline:\n \"border border-border bg-background hover:bg-accent hover:text-accent-foreground shadow-2xs data-[state=open]:bg-accent\",\n },\n size: {\n default: \"h-9 px-3 text-sm\",\n sm: \"h-8 px-2.5 text-xs\",\n lg: \"h-10 px-4 text-base\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n size: \"default\",\n },\n }\n);\n\nexport function navigationMenuTriggerStyle(\n variants?: VariantProps<typeof navigationMenuTriggerVariants>\n) {\n return navigationMenuTriggerVariants(variants);\n}\n\n/* --- 5. NavigationMenuTrigger --- */\nexport interface NavigationMenuTriggerProps\n extends JSX.ButtonHTMLAttributes<HTMLButtonElement>,\n VariantProps<typeof navigationMenuTriggerVariants> {\n class?: string;\n hideChevron?: boolean;\n}\n\nexport const NavigationMenuTrigger: ParentComponent<NavigationMenuTriggerProps> = (props) => {\n const [local, rest] = splitProps(props, [\"class\", \"variant\", \"size\", \"hideChevron\", \"children\"]);\n const rootContext = useNavigationMenu();\n const itemContext = useNavigationMenuItem();\n\n const handleClick = (e: MouseEvent) => {\n e.preventDefault();\n if (itemContext.isOpen()) {\n rootContext.setActiveValue(null);\n } else {\n rootContext.setActiveValue(itemContext.value);\n }\n };\n\n return (\n <button\n type=\"button\"\n aria-expanded={itemContext.isOpen()}\n data-state={itemContext.isOpen() ? \"open\" : \"closed\"}\n onClick={handleClick}\n class={cn(\n navigationMenuTriggerVariants({ variant: local.variant, size: local.size }),\n \"gap-1.5\",\n local.class\n )}\n {...rest}\n >\n {local.children}\n <Show when={!local.hideChevron}>\n <ChevronDown\n class={cn(\n \"size-3.5 text-muted-foreground transition-transform duration-200\",\n itemContext.isOpen() && \"rotate-180 text-foreground\"\n )}\n aria-hidden=\"true\"\n />\n </Show>\n </button>\n );\n};\n\n/* --- 6. NavigationMenuContent (Mega Menu Flyout) --- */\nexport interface NavigationMenuContentProps extends JSX.HTMLAttributes<HTMLDivElement> {\n class?: string;\n}\n\nexport const NavigationMenuContent: ParentComponent<NavigationMenuContentProps> = (props) => {\n const [local, rest] = splitProps(props, [\"class\", \"children\"]);\n const itemContext = useNavigationMenuItem();\n\n return (\n <Show when={itemContext.isOpen()}>\n <div\n data-state={itemContext.isOpen() ? \"open\" : \"closed\"}\n class={cn(\n \"absolute left-0 top-full mt-1.5 w-auto rounded-lg border border-border bg-popover p-4 text-popover-foreground shadow-lg outline-hidden z-50\",\n \"animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 duration-200\",\n local.class\n )}\n {...rest}\n >\n {local.children}\n </div>\n </Show>\n );\n};\n\n/* --- 7. NavigationMenuLink --- */\nexport interface NavigationMenuLinkProps extends JSX.AnchorHTMLAttributes<HTMLAnchorElement> {\n class?: string;\n active?: boolean;\n}\n\nexport const NavigationMenuLink: ParentComponent<NavigationMenuLinkProps> = (props) => {\n const [local, rest] = splitProps(props, [\"class\", \"active\", \"children\"]);\n\n return (\n <a\n data-active={local.active ? \"\" : undefined}\n class={cn(\n \"block select-none space-y-1 rounded-md p-3 leading-none no-underline outline-hidden transition-colors hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground\",\n local.active && \"bg-accent/60 text-accent-foreground\",\n local.class\n )}\n {...rest}\n >\n {local.children}\n </a>\n );\n};\n\n/* --- 8. NavigationMenuViewport --- */\nexport interface NavigationMenuViewportProps extends JSX.HTMLAttributes<HTMLDivElement> {\n class?: string;\n}\n\nexport const NavigationMenuViewport: Component<NavigationMenuViewportProps> = (props) => {\n const [local, rest] = splitProps(props, [\"class\"]);\n\n return (\n <div class=\"absolute left-0 top-full flex justify-center\">\n <div\n class={cn(\n \"origin-top-center relative mt-1.5 h-[var(--radix-navigation-menu-viewport-height)] w-full overflow-hidden rounded-md border border-border bg-popover text-popover-foreground shadow-lg transition-all\",\n local.class\n )}\n {...rest}\n />\n </div>\n );\n};\n\n/* --- 9. NavigationMenuIndicator --- */\nexport interface NavigationMenuIndicatorProps extends JSX.HTMLAttributes<HTMLDivElement> {\n class?: string;\n}\n\nexport const NavigationMenuIndicator: Component<NavigationMenuIndicatorProps> = (props) => {\n const [local, rest] = splitProps(props, [\"class\"]);\n\n return (\n <div\n class={cn(\n \"top-full z-1 flex h-1.5 items-end justify-center overflow-hidden transition-[width,transform] duration-200\",\n local.class\n )}\n {...rest}\n >\n <div class=\"relative top-[60%] h-2 w-2 rotate-45 rounded-tl-xs bg-border shadow-md\" />\n </div>\n );\n};\n",
|
|
19
|
+
"type": "registry:ui"
|
|
20
|
+
}
|
|
21
|
+
]
|
|
22
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "number-input",
|
|
3
|
+
"title": "Number Input",
|
|
4
|
+
"description": "A numeric stepper input component supporting min, max, step, negative values, and long-press auto-repeat, built on Kobalte primitives.",
|
|
5
|
+
"type": "registry:ui",
|
|
6
|
+
"dependencies": [
|
|
7
|
+
"clsx",
|
|
8
|
+
"tailwind-merge",
|
|
9
|
+
"@kobalte/core",
|
|
10
|
+
"lucide-solid"
|
|
11
|
+
],
|
|
12
|
+
"registryDependencies": [
|
|
13
|
+
"input",
|
|
14
|
+
"button",
|
|
15
|
+
"create-long-press"
|
|
16
|
+
],
|
|
17
|
+
"files": [
|
|
18
|
+
{
|
|
19
|
+
"path": "ui/number-input.tsx",
|
|
20
|
+
"content": "import { createSignal, onCleanup, splitProps, type Component, type JSX } from \"solid-js\";\nimport { NumberField as KobalteNumberField } from \"@kobalte/core/number-field\";\nimport { Plus, Minus } from \"lucide-solid\";\nimport { Input } from \"@/components/ui/input\";\nimport { Button } from \"@/components/ui/button\";\nimport { createLongPress } from \"@/hooks/create-long-press\";\nimport { cn } from \"@/lib/cn\";\n\nexport interface NumberInputProps {\n value?: number;\n defaultValue?: number;\n onValueChange?: (value: number) => void;\n minValue?: number;\n maxValue?: number;\n step?: number;\n allowNegative?: boolean;\n disabled?: boolean;\n readOnly?: boolean;\n class?: string;\n id?: string;\n}\n\nexport const NumberInput: Component<NumberInputProps> = (props) => {\n const [local, rest] = splitProps(props, [\n \"value\",\n \"defaultValue\",\n \"onValueChange\",\n \"minValue\",\n \"maxValue\",\n \"step\",\n \"allowNegative\",\n \"disabled\",\n \"readOnly\",\n \"class\",\n \"id\",\n ]);\n\n const [internalVal, setInternalVal] = createSignal<number>(\n local.value !== undefined\n ? local.value\n : local.defaultValue !== undefined\n ? local.defaultValue\n : 0\n );\n\n let autoRepeatInterval: ReturnType<typeof setInterval> | undefined;\n\n const currentVal = () => (local.value !== undefined ? local.value : internalVal());\n\n const effectiveMin = () => {\n if (local.minValue !== undefined) return local.minValue;\n return local.allowNegative ? -Infinity : 0;\n };\n\n const effectiveMax = () => {\n if (local.maxValue !== undefined) return local.maxValue;\n return Infinity;\n };\n\n const handleValueChange = (val: number) => {\n if (isNaN(val)) return;\n const clamped = Math.max(effectiveMin(), Math.min(effectiveMax(), val));\n setInternalVal(clamped);\n local.onValueChange?.(clamped);\n };\n\n const stopAutoRepeat = () => {\n if (autoRepeatInterval) {\n clearInterval(autoRepeatInterval);\n autoRepeatInterval = undefined;\n }\n };\n\n const startAutoRepeat = (direction: 1 | -1) => {\n if (local.disabled || local.readOnly) return;\n stopAutoRepeat();\n const stepAmount = local.step || 1;\n autoRepeatInterval = setInterval(() => {\n handleValueChange(currentVal() + direction * stepAmount);\n }, 75);\n };\n\n /* Nikala UI createLongPress hook for Increment Trigger */\n const incrementLongPress = createLongPress(\n () => {\n startAutoRepeat(1);\n },\n {\n threshold: 300,\n onCancel: stopAutoRepeat,\n }\n );\n\n /* Nikala UI createLongPress hook for Decrement Trigger */\n const decrementLongPress = createLongPress(\n () => {\n startAutoRepeat(-1);\n },\n {\n threshold: 300,\n onCancel: stopAutoRepeat,\n }\n );\n\n onCleanup(() => stopAutoRepeat());\n\n return (\n <KobalteNumberField\n value={currentVal()}\n onRawValueChange={handleValueChange}\n minValue={effectiveMin()}\n maxValue={effectiveMax()}\n step={local.step || 1}\n disabled={local.disabled}\n readOnly={local.readOnly}\n id={local.id}\n class={cn(\"relative flex items-center max-w-[160px]\", local.class)}\n {...rest}\n >\n <KobalteNumberField.Input\n as={Input}\n class=\"pr-16 text-center font-mono focus-visible:ring-1\"\n />\n\n <div class=\"absolute right-1 flex items-center gap-0.5\">\n <KobalteNumberField.DecrementTrigger\n as={Button}\n variant=\"ghost\"\n size=\"icon\"\n class=\"h-7 w-7 rounded-sm p-0 text-muted-foreground hover:text-foreground select-none\"\n aria-label=\"Decrement value\"\n {...decrementLongPress.props}\n >\n <Minus class=\"h-3.5 w-3.5\" />\n </KobalteNumberField.DecrementTrigger>\n\n <KobalteNumberField.IncrementTrigger\n as={Button}\n variant=\"ghost\"\n size=\"icon\"\n class=\"h-7 w-7 rounded-sm p-0 text-muted-foreground hover:text-foreground select-none\"\n aria-label=\"Increment value\"\n {...incrementLongPress.props}\n >\n <Plus class=\"h-3.5 w-3.5\" />\n </KobalteNumberField.IncrementTrigger>\n </div>\n </KobalteNumberField>\n );\n};\n",
|
|
21
|
+
"type": "registry:ui"
|
|
22
|
+
}
|
|
23
|
+
]
|
|
24
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "otp-verification-01",
|
|
3
|
+
"title": "OTP Verification 01 — Two-Factor Security Code",
|
|
4
|
+
"description": "A clean 2-Factor Authentication block with a 6-digit PIN input, countdown resend timer, and security notifications.",
|
|
5
|
+
"type": "registry:block",
|
|
6
|
+
"dependencies": [
|
|
7
|
+
"clsx",
|
|
8
|
+
"tailwind-merge",
|
|
9
|
+
"lucide-solid"
|
|
10
|
+
],
|
|
11
|
+
"registryDependencies": [
|
|
12
|
+
"card",
|
|
13
|
+
"pin-input",
|
|
14
|
+
"button",
|
|
15
|
+
"alert",
|
|
16
|
+
"badge",
|
|
17
|
+
"form"
|
|
18
|
+
],
|
|
19
|
+
"files": [
|
|
20
|
+
{
|
|
21
|
+
"path": "blocks/otp-verification-01.tsx",
|
|
22
|
+
"content": "import { createSignal, onMount, onCleanup, Show, type Component } from \"solid-js\";\nimport {\n Card,\n CardHeader,\n CardTitle,\n CardDescription,\n CardContent,\n CardFooter,\n} from \"../components/ui/card\";\nimport { Form } from \"../components/ui/form\";\nimport { Button } from \"../components/ui/button\";\nimport { PinInput, PinInputInput } from \"../components/ui/pin-input\";\nimport { Alert, AlertTitle, AlertDescription } from \"../components/ui/alert\";\nimport { Badge } from \"../components/ui/badge\";\nimport { KeyRound, Mail, CheckCircle2, RotateCcw, ArrowRight } from \"lucide-solid\";\n\nexport const OtpVerification01: Component = () => {\n const [code, setCode] = createSignal(\"\");\n const [loading, setLoading] = createSignal(false);\n const [verified, setVerified] = createSignal(false);\n const [countdown, setCountdown] = createSignal(59);\n const [canResend, setCanResend] = createSignal(false);\n\n let timerId: ReturnType<typeof setInterval> | undefined;\n\n const startCountdown = () => {\n setCountdown(59);\n setCanResend(false);\n clearInterval(timerId);\n timerId = setInterval(() => {\n setCountdown((prev) => {\n if (prev <= 1) {\n clearInterval(timerId);\n setCanResend(true);\n return 0;\n }\n return prev - 1;\n });\n }, 1000);\n };\n\n onMount(() => {\n startCountdown();\n });\n\n onCleanup(() => {\n clearInterval(timerId);\n });\n\n const handleVerify = (e: Event) => {\n e.preventDefault();\n if (code().length < 6) return;\n setLoading(true);\n setTimeout(() => {\n setLoading(false);\n setVerified(true);\n }, 1200);\n };\n\n const handleResend = () => {\n if (!canResend()) return;\n setCode(\"\");\n startCountdown();\n };\n\n return (\n <div class=\"@container w-full min-h-[500px] flex items-center justify-center p-4 sm:p-6 md:p-10\">\n <Card class=\"w-full max-w-md border-border shadow-md bg-card\">\n {/* Card Header */}\n <CardHeader class=\"space-y-2 text-center pb-4\">\n <div class=\"mx-auto size-12 rounded-lg bg-primary/10 text-primary flex items-center justify-center mb-1 shadow-2xs\">\n <KeyRound class=\"size-6\" />\n </div>\n <div class=\"flex items-center justify-center gap-2\">\n <CardTitle class=\"text-2xl font-bold tracking-tight\">Two-Factor Auth</CardTitle>\n <Badge variant=\"secondary\" class=\"text-[10px] px-1.5 py-0 font-mono\">\n 2FA\n </Badge>\n </div>\n <CardDescription class=\"text-xs sm:text-sm\">\n Enter the 6-digit security code sent to your registered email address\n </CardDescription>\n </CardHeader>\n\n <CardContent class=\"space-y-6\">\n {/* Info Alert */}\n <Alert class=\"bg-muted/40 border-border/70 py-2.5\">\n <Mail class=\"size-4 text-primary shrink-0\" />\n <AlertTitle class=\"text-xs font-semibold\">Verification Code Sent</AlertTitle>\n <AlertDescription class=\"text-[11px] text-muted-foreground\">\n Sent to <span class=\"font-medium text-foreground font-mono\">dev***@nikala.dev</span>\n </AlertDescription>\n </Alert>\n\n {/* Form */}\n <Form onSubmit={handleVerify} loading={loading()} class=\"space-y-6\">\n {/* Responsive 6-Digit PinInput */}\n <div class=\"flex flex-col items-center justify-center space-y-2 w-full\">\n <PinInput\n value={code()}\n onValueChange={setCode}\n length={6}\n type=\"numeric\"\n class=\"justify-center items-center gap-1.5 @sm:gap-2.5 max-w-full\"\n >\n <PinInputInput index={0} class=\"h-9 w-9 @sm:h-11 @sm:w-11 text-sm @sm:text-base font-semibold\" />\n <PinInputInput index={1} class=\"h-9 w-9 @sm:h-11 @sm:w-11 text-sm @sm:text-base font-semibold\" />\n <PinInputInput index={2} class=\"h-9 w-9 @sm:h-11 @sm:w-11 text-sm @sm:text-base font-semibold\" />\n <PinInputInput index={3} class=\"h-9 w-9 @sm:h-11 @sm:w-11 text-sm @sm:text-base font-semibold\" />\n <PinInputInput index={4} class=\"h-9 w-9 @sm:h-11 @sm:w-11 text-sm @sm:text-base font-semibold\" />\n <PinInputInput index={5} class=\"h-9 w-9 @sm:h-11 @sm:w-11 text-sm @sm:text-base font-semibold\" />\n </PinInput>\n\n <Show when={verified()}>\n <div class=\"flex items-center gap-1.5 text-xs text-emerald-500 font-medium pt-1\">\n <CheckCircle2 class=\"size-3.5\" />\n <span>Code verified successfully!</span>\n </div>\n </Show>\n </div>\n\n {/* Countdown / Resend Action */}\n <div class=\"flex items-center justify-between text-xs text-muted-foreground px-1\">\n <span>Didn't receive code?</span>\n <Show\n when={canResend()}\n fallback={\n <span class=\"font-mono text-primary text-[11px]\">\n Resend in 00:{countdown() < 10 ? `0${countdown()}` : countdown()}s\n </span>\n }\n >\n <Button\n variant=\"link\"\n size=\"sm\"\n type=\"button\"\n onClick={handleResend}\n class=\"h-auto p-0 text-xs text-primary font-semibold gap-1\"\n >\n <RotateCcw class=\"size-3\" /> Resend Code\n </Button>\n </Show>\n </div>\n\n {/* Submit Button */}\n <Button\n type=\"submit\"\n class=\"w-full font-medium\"\n disabled={loading() || code().length < 6 || verified()}\n >\n <Show when={loading()} fallback={<>Verify Account <ArrowRight class=\"ml-2 size-4\" /></>}>\n Verifying...\n </Show>\n </Button>\n </Form>\n </CardContent>\n\n {/* Card Footer */}\n <CardFooter class=\"justify-center border-t border-border/50 py-4 text-xs text-muted-foreground\">\n Need help?{\" \"}\n <a href=\"#support\" class=\"text-primary font-semibold hover:underline ml-1\">\n Contact Security Team\n </a>\n </CardFooter>\n </Card>\n </div>\n );\n};\n\nexport default OtpVerification01;\n",
|
|
23
|
+
"type": "registry:block"
|
|
24
|
+
}
|
|
25
|
+
]
|
|
26
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "package-manager-tabs",
|
|
3
|
+
"title": "Package Manager Tabs",
|
|
4
|
+
"description": "An interactive command tab bar supporting customizable package managers (bun, pnpm, npm, yarn, deno, bunx, npx) with copy functionality.",
|
|
5
|
+
"type": "registry:ui",
|
|
6
|
+
"dependencies": [
|
|
7
|
+
"clsx",
|
|
8
|
+
"tailwind-merge",
|
|
9
|
+
"lucide-solid"
|
|
10
|
+
],
|
|
11
|
+
"registryDependencies": [
|
|
12
|
+
"button",
|
|
13
|
+
"tooltip",
|
|
14
|
+
"tabs",
|
|
15
|
+
"create-clipboard"
|
|
16
|
+
],
|
|
17
|
+
"files": [
|
|
18
|
+
{
|
|
19
|
+
"path": "ui/package-manager-tabs.tsx",
|
|
20
|
+
"content": "import {\n createSignal,\n createMemo,\n splitProps,\n For,\n Show,\n type JSX,\n type ParentComponent,\n} from \"solid-js\";\nimport { Check, Copy } from \"lucide-solid\";\nimport { Button } from \"@/components/ui/button\";\nimport { Tabs, TabsList, TabsTrigger } from \"@/components/ui/tabs\";\nimport { Tooltip, TooltipTrigger, TooltipContent } from \"@/components/ui/tooltip\";\nimport { createClipboard } from \"@/hooks/create-clipboard\";\nimport { cn } from \"@/lib/cn\";\n\nexport type DefaultPackageManager = \"bun\" | \"pnpm\" | \"npm\" | \"yarn\" | \"bunx\" | \"npx\" | \"deno\";\n\nexport interface PackageManagerTabsProps\n extends Omit<JSX.HTMLAttributes<HTMLDivElement>, \"onChange\"> {\n /** List of package managers to show in the switcher tabs */\n managers?: string[];\n /** Single CLI command template (e.g. \"add @nikala-ui/core\", \"create @nikala-ui/docs my-app\") */\n command?: string;\n /** Explicit map of custom commands per manager (e.g. { bun: \"bun add foo\", npm: \"npm i foo\" }) */\n commands?: Record<string, string>;\n /** Selected manager (controlled) */\n value?: string;\n /** Initial selected manager (uncontrolled) */\n defaultValue?: string;\n /** Callback fired when the active package manager changes */\n onChange?: (manager: string) => void;\n /** Whether to show the copy button in the header */\n copyable?: boolean;\n class?: string;\n}\n\n/**\n * Automatically formats a command string for a specific package manager.\n */\nfunction resolvePmCommand(manager: string, command: string): string {\n const trimmed = command.trim();\n const pm = manager.toLowerCase();\n\n // 1. \"create\" command\n const createMatch = trimmed.match(/^(?:bun|npm|npx|pnpm|yarn|deno)?\\s*create\\s+(.*)$/);\n if (createMatch) {\n const args = createMatch[1];\n if (pm === \"bun\" || pm === \"bunx\") return `bun create ${args}`;\n if (pm === \"pnpm\") return `pnpm create ${args}`;\n if (pm === \"yarn\") return `yarn create ${args}`;\n if (pm === \"deno\") return `deno run -A npm:create-${args}`;\n return `npm create ${args}`;\n }\n\n // 2. \"add\" / \"install\" command\n const addMatch = trimmed.match(/^(?:bun\\s+add|npm\\s+i|npm\\s+install|pnpm\\s+add|yarn\\s+add|deno\\s+add|add|install|i)\\s+(.*)$/);\n if (addMatch) {\n const args = addMatch[1];\n if (pm === \"npm\") return `npm i ${args}`;\n if (pm === \"pnpm\") return `pnpm add ${args}`;\n if (pm === \"yarn\") return `yarn add ${args}`;\n if (pm === \"deno\") return `deno add ${args}`;\n return `bun add ${args}`;\n }\n\n // 3. CLI runner (e.g. \"nikala add button\" or \"@nikala-ui/cli add button\")\n const runnerMatch = trimmed.match(/^(?:bunx|npx|pnpm\\s+dlx|yarn\\s+dlx)?\\s*(.*)$/);\n if (runnerMatch) {\n const rest = runnerMatch[1];\n if (pm === \"npx\") return `npx ${rest}`;\n if (pm === \"pnpm\") return `pnpm dlx ${rest}`;\n if (pm === \"yarn\") return `yarn dlx ${rest}`;\n if (pm === \"bun\" || pm === \"bunx\") return `bunx ${rest}`;\n return `${pm} ${rest}`;\n }\n\n return trimmed;\n}\n\nfunction highlightCliCommandText(code: string): string {\n const trimmed = code.trim();\n if (!trimmed) return \"\";\n const parts = trimmed.split(/\\s+/);\n\n let pkgIndex = 1;\n if ((parts[0] === \"pnpm\" || parts[0] === \"yarn\") && parts[1] === \"dlx\") {\n pkgIndex = 2;\n } else if (parts[0] === \"bun\" && (parts[1] === \"create\" || parts[1] === \"add\" || parts[1] === \"run\")) {\n pkgIndex = 2;\n } else if (parts[0] === \"npm\" && (parts[1] === \"create\" || parts[1] === \"run\")) {\n pkgIndex = 2;\n }\n\n const mainPart = parts.slice(0, pkgIndex).join(\" \");\n const restTokens = parts.slice(pkgIndex);\n\n const highlightedRest = restTokens\n .map((token) => {\n if (token.startsWith(\"-\")) {\n return `<span class=\"text-amber-500 dark:text-amber-400 font-medium\">${token}</span>`;\n }\n if ([\"add\", \"create\", \"init\", \"run\", \"dev\", \"build\", \"set\", \"theme\", \"diff\", \"list\"].includes(token)) {\n return `<span class=\"text-sky-500 dark:text-sky-400 font-semibold\">${token}</span>`;\n }\n return `<span class=\"text-violet-500 dark:text-violet-400 font-medium\">${token}</span>`;\n })\n .join(\" \");\n\n return `<span class=\"text-emerald-500 dark:text-emerald-400 font-semibold\">${mainPart}</span>${\n highlightedRest ? \" \" + highlightedRest : \"\"\n }`;\n}\n\nexport const PackageManagerTabs: ParentComponent<PackageManagerTabsProps> = (props) => {\n const [local, rest] = splitProps(props, [\n \"managers\",\n \"command\",\n \"commands\",\n \"value\",\n \"defaultValue\",\n \"onChange\",\n \"copyable\",\n \"class\",\n ]);\n\n const defaultManagers = [\"bun\", \"pnpm\", \"npm\", \"yarn\"];\n const managersList = () => local.managers || defaultManagers;\n\n const [internalActive, setInternalActive] = createSignal(\n local.defaultValue || managersList()[0] || \"bun\"\n );\n\n const activeManager = () => local.value ?? internalActive();\n\n const handleSelect = (pm: string) => {\n if (local.value === undefined) {\n setInternalActive(pm);\n }\n local.onChange?.(pm);\n };\n\n const currentCommand = createMemo(() => {\n const pm = activeManager();\n if (local.commands && local.commands[pm]) {\n return local.commands[pm];\n }\n if (local.command) {\n return resolvePmCommand(pm, local.command);\n }\n return \"\";\n });\n\n const clipboard = createClipboard();\n const copyable = () => local.copyable ?? true;\n\n const handleCopy = async () => {\n const text = currentCommand();\n if (!text) return;\n await clipboard.copy(text);\n };\n\n return (\n <div\n class={cn(\n \"group relative my-4 w-full overflow-hidden rounded-lg border border-border bg-muted/40 font-mono text-sm shadow-2xs\",\n local.class\n )}\n {...rest}\n >\n {/* Header with Manager Switcher Tabs and Copy Button */}\n <div class=\"flex h-9 items-center justify-between border-b border-border/70 bg-muted/70 px-3.5 select-none\">\n {/* Switcher Tabs */}\n <Tabs\n value={activeManager()}\n onChange={handleSelect}\n class=\"w-auto flex-none\"\n >\n <TabsList class=\"w-auto inline-flex h-auto bg-background/60 p-0.5 border border-border/50 gap-0.5 rounded-md font-mono\">\n <For each={managersList()}>\n {(pm) => (\n <TabsTrigger\n value={pm}\n class=\"rounded-xs px-2 py-0.5 text-[11px] font-mono transition-colors cursor-pointer data-[state=active]:bg-primary data-[state=active]:text-primary-foreground data-[state=active]:font-semibold data-[state=active]:shadow-2xs\"\n >\n {pm}\n </TabsTrigger>\n )}\n </For>\n </TabsList>\n </Tabs>\n\n {/* Copy Button */}\n <Show when={copyable() && currentCommand()}>\n <Tooltip>\n <TooltipTrigger\n as={Button}\n variant=\"ghost\"\n size=\"icon\"\n onClick={handleCopy}\n aria-label={clipboard.copied() ? \"Copied command\" : \"Copy command\"}\n class=\"size-6 p-0 rounded-xs text-muted-foreground hover:bg-background hover:text-foreground cursor-pointer\"\n >\n <Show when={clipboard.copied()} fallback={<Copy class=\"size-3.5\" />}>\n <Check class=\"size-3.5 text-emerald-500 dark:text-emerald-400\" />\n </Show>\n </TooltipTrigger>\n <TooltipContent class=\"text-[10px] py-1 px-2\">\n {clipboard.copied() ? \"Copied!\" : \"Copy command\"}\n </TooltipContent>\n </Tooltip>\n </Show>\n </div>\n\n {/* Command Box Content */}\n <div class=\"overflow-x-auto p-4 text-[13px] leading-relaxed [scrollbar-width:thin]\">\n <pre class=\"font-mono\">\n <code>\n <span class=\"text-sky-500 dark:text-sky-400 font-semibold select-none\">$ </span>\n <span innerHTML={highlightCliCommandText(currentCommand())} />\n </code>\n </pre>\n </div>\n </div>\n );\n};\n",
|
|
21
|
+
"type": "registry:ui"
|
|
22
|
+
}
|
|
23
|
+
]
|
|
24
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "pager",
|
|
3
|
+
"title": "Pager",
|
|
4
|
+
"description": "Previous and next article navigation links with card previews for documentation and blog layouts.",
|
|
5
|
+
"type": "registry:ui",
|
|
6
|
+
"dependencies": [
|
|
7
|
+
"clsx",
|
|
8
|
+
"tailwind-merge",
|
|
9
|
+
"lucide-solid"
|
|
10
|
+
],
|
|
11
|
+
"registryDependencies": [
|
|
12
|
+
"card"
|
|
13
|
+
],
|
|
14
|
+
"files": [
|
|
15
|
+
{
|
|
16
|
+
"path": "ui/pager.tsx",
|
|
17
|
+
"content": "import { splitProps, Show, children, type Component, type JSX } from \"solid-js\";\nimport { ChevronLeft, ChevronRight } from \"lucide-solid\";\nimport {\n Card,\n CardHeader,\n CardTitle,\n CardDescription,\n} from \"@/components/ui/card\";\nimport { cn } from \"@/lib/cn\";\n\nexport interface PagerItem {\n title: string;\n href: string;\n}\n\nexport interface PagerLinkProps extends JSX.AnchorHTMLAttributes<HTMLAnchorElement> {\n title: string;\n href: string;\n type: \"prev\" | \"next\";\n class?: string;\n}\n\n/**\n * Individual Next or Previous page navigation card.\n */\nexport const PagerLink: Component<PagerLinkProps> = (props) => {\n const [local, rest] = splitProps(props, [\"title\", \"href\", \"type\", \"class\"]);\n\n const isNext = () => local.type === \"next\";\n\n return (\n <a\n href={local.href}\n class={cn(\n \"group block rounded-lg transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring\",\n isNext() && \"sm:col-start-2\",\n local.class\n )}\n {...rest}\n >\n <Card class=\"h-full transition-all group-hover:bg-accent/40 group-hover:shadow-2xs\">\n <CardHeader class={cn(\"p-4 flex flex-col space-y-1.5\", isNext() && \"items-end text-right\")}>\n <CardDescription class=\"flex items-center gap-1 text-xs font-medium text-muted-foreground\">\n <Show when={!isNext()}>\n <ChevronLeft class=\"size-3.5 transition-transform group-hover:-translate-x-0.5\" />\n <span>Previous</span>\n </Show>\n <Show when={isNext()}>\n <span>Next</span>\n <ChevronRight class=\"size-3.5 transition-transform group-hover:translate-x-0.5\" />\n </Show>\n </CardDescription>\n <CardTitle class=\"text-sm font-semibold tracking-tight group-hover:text-primary transition-colors line-clamp-1\">\n {local.title}\n </CardTitle>\n </CardHeader>\n </Card>\n </a>\n );\n};\n\nexport interface PagerProps extends JSX.HTMLAttributes<HTMLDivElement> {\n /** Previous documentation page item */\n prev?: PagerItem | null;\n /** Next documentation page item */\n next?: PagerItem | null;\n class?: string;\n}\n\n/**\n * Documentation Next / Previous article navigation block composed of Nikala UI Card primitives.\n */\nexport const Pager: Component<PagerProps> = (props) => {\n const [local, rest] = splitProps(props, [\"prev\", \"next\", \"class\", \"children\"]);\n const resolved = children(() => local.children);\n\n return (\n <div\n class={cn(\"grid grid-cols-1 gap-4 sm:grid-cols-2 mt-10 pt-6 border-t border-border\", local.class)}\n {...rest}\n >\n <Show\n when={resolved()}\n fallback={\n <>\n <Show\n when={local.prev}\n fallback={<span class=\"hidden sm:block\" />}\n >\n <PagerLink type=\"prev\" title={local.prev!.title} href={local.prev!.href} />\n </Show>\n <Show when={local.next}>\n <PagerLink type=\"next\" title={local.next!.title} href={local.next!.href} />\n </Show>\n </>\n }\n >\n {resolved()}\n </Show>\n </div>\n );\n};\n",
|
|
18
|
+
"type": "registry:ui"
|
|
19
|
+
}
|
|
20
|
+
]
|
|
21
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "pagination",
|
|
3
|
+
"title": "Pagination",
|
|
4
|
+
"description": "An accessible multi-page navigation bar with previous, next, page numbers, and ellipsis controls.",
|
|
5
|
+
"type": "registry:ui",
|
|
6
|
+
"dependencies": [
|
|
7
|
+
"clsx",
|
|
8
|
+
"tailwind-merge",
|
|
9
|
+
"class-variance-authority",
|
|
10
|
+
"lucide-solid"
|
|
11
|
+
],
|
|
12
|
+
"registryDependencies": [
|
|
13
|
+
"create-pagination"
|
|
14
|
+
],
|
|
15
|
+
"files": [
|
|
16
|
+
{
|
|
17
|
+
"path": "ui/pagination.tsx",
|
|
18
|
+
"content": "import { splitProps, type Component, type JSX, type ParentComponent, Show } from \"solid-js\";\nimport { cva, type VariantProps } from \"class-variance-authority\";\nimport { cn } from \"@/lib/cn\";\nimport { ChevronLeft, ChevronRight, ChevronsLeft, ChevronsRight, MoreHorizontal } from \"lucide-solid\";\n\n/* --- 1. Button Variants for Pagination Links --- */\nexport const paginationButtonVariants = cva(\n \"inline-flex items-center justify-center whitespace-nowrap rounded-md font-medium transition-colors focus-visible:outline-hidden focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 cursor-pointer select-none\",\n {\n variants: {\n variant: {\n default: \"hover:bg-accent hover:text-accent-foreground data-[active=true]:bg-primary data-[active=true]:text-primary-foreground data-[active=true]:font-bold data-[active=true]:shadow-2xs\",\n outline: \"border border-border bg-background hover:bg-accent hover:text-accent-foreground data-[active=true]:border-primary data-[active=true]:bg-primary/10 data-[active=true]:text-primary data-[active=true]:font-bold\",\n ghost: \"hover:bg-accent/80 hover:text-accent-foreground data-[active=true]:bg-accent data-[active=true]:text-foreground data-[active=true]:font-bold\",\n flat: \"hover:bg-muted/80 data-[active=true]:bg-muted data-[active=true]:text-foreground data-[active=true]:font-bold\",\n },\n size: {\n default: \"h-9 min-w-9 px-3 text-sm\",\n sm: \"h-8 min-w-8 px-2 text-xs\",\n lg: \"h-10 min-w-10 px-4 text-base\",\n icon: \"h-9 w-9 p-0 text-sm\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n size: \"default\",\n },\n }\n);\n\n/* --- 2. Pagination Root --- */\nexport interface PaginationProps extends JSX.HTMLAttributes<HTMLElement> {\n class?: string;\n}\n\nexport const Pagination: ParentComponent<PaginationProps> = (props) => {\n const [local, rest] = splitProps(props, [\"class\", \"children\"]);\n\n return (\n <nav\n role=\"navigation\"\n aria-label=\"pagination\"\n class={cn(\"mx-auto flex w-full justify-center\", local.class)}\n {...rest}\n >\n {local.children}\n </nav>\n );\n};\n\n/* --- 3. PaginationContent --- */\nexport interface PaginationContentProps extends JSX.HTMLAttributes<HTMLUListElement> {\n class?: string;\n}\n\nexport const PaginationContent: ParentComponent<PaginationContentProps> = (props) => {\n const [local, rest] = splitProps(props, [\"class\", \"children\"]);\n\n return (\n <ul\n class={cn(\"flex flex-row items-center gap-1 flex-wrap\", local.class)}\n {...rest}\n >\n {local.children}\n </ul>\n );\n};\n\n/* --- 4. PaginationItem --- */\nexport interface PaginationItemProps extends JSX.HTMLAttributes<HTMLLIElement> {\n class?: string;\n}\n\nexport const PaginationItem: ParentComponent<PaginationItemProps> = (props) => {\n const [local, rest] = splitProps(props, [\"class\", \"children\"]);\n\n return (\n <li class={cn(\"\", local.class)} {...rest}>\n {local.children}\n </li>\n );\n};\n\n/* --- 5. PaginationLink --- */\nexport interface PaginationLinkProps\n extends JSX.ButtonHTMLAttributes<HTMLButtonElement>,\n VariantProps<typeof paginationButtonVariants> {\n isActive?: boolean;\n class?: string;\n}\n\nexport const PaginationLink: ParentComponent<PaginationLinkProps> = (props) => {\n const [local, rest] = splitProps(props, [\"class\", \"variant\", \"size\", \"isActive\", \"children\"]);\n\n return (\n <button\n type=\"button\"\n aria-current={local.isActive ? \"page\" : undefined}\n data-active={local.isActive ? \"true\" : \"false\"}\n class={cn(\n paginationButtonVariants({\n variant: local.variant,\n size: local.size,\n }),\n local.class\n )}\n {...rest}\n >\n {local.children}\n </button>\n );\n};\n\n/* --- 6. PaginationPrevious --- */\nexport interface PaginationPreviousProps\n extends JSX.ButtonHTMLAttributes<HTMLButtonElement>,\n VariantProps<typeof paginationButtonVariants> {\n class?: string;\n hideText?: boolean;\n}\n\nexport const PaginationPrevious: Component<PaginationPreviousProps> = (props) => {\n const [local, rest] = splitProps(props, [\"class\", \"variant\", \"size\", \"hideText\"]);\n\n return (\n <PaginationLink\n aria-label=\"Go to previous page\"\n variant={local.variant}\n size={local.size}\n class={cn(\"gap-1 pl-2.5\", local.hideText && \"p-0 min-w-8\", local.class)}\n {...rest}\n >\n <ChevronLeft class=\"size-4\" />\n <Show when={!local.hideText}>\n <span>Previous</span>\n </Show>\n </PaginationLink>\n );\n};\n\n/* --- 7. PaginationNext --- */\nexport interface PaginationNextProps\n extends JSX.ButtonHTMLAttributes<HTMLButtonElement>,\n VariantProps<typeof paginationButtonVariants> {\n class?: string;\n hideText?: boolean;\n}\n\nexport const PaginationNext: Component<PaginationNextProps> = (props) => {\n const [local, rest] = splitProps(props, [\"class\", \"variant\", \"size\", \"hideText\"]);\n\n return (\n <PaginationLink\n aria-label=\"Go to next page\"\n variant={local.variant}\n size={local.size}\n class={cn(\"gap-1 pr-2.5\", local.hideText && \"p-0 min-w-8\", local.class)}\n {...rest}\n >\n <Show when={!local.hideText}>\n <span>Next</span>\n </Show>\n <ChevronRight class=\"size-4\" />\n </PaginationLink>\n );\n};\n\n/* --- 8. PaginationFirst --- */\nexport interface PaginationFirstProps\n extends JSX.ButtonHTMLAttributes<HTMLButtonElement>,\n VariantProps<typeof paginationButtonVariants> {\n class?: string;\n hideText?: boolean;\n}\n\nexport const PaginationFirst: Component<PaginationFirstProps> = (props) => {\n const [local, rest] = splitProps(props, [\"class\", \"variant\", \"size\", \"hideText\"]);\n\n return (\n <PaginationLink\n aria-label=\"Go to first page\"\n variant={local.variant}\n size={local.size}\n class={cn(\"gap-1 p-0 min-w-8\", local.class)}\n {...rest}\n >\n <ChevronsLeft class=\"size-4\" />\n <Show when={!local.hideText}>\n <span class=\"sr-only\">First page</span>\n </Show>\n </PaginationLink>\n );\n};\n\n/* --- 9. PaginationLast --- */\nexport interface PaginationLastProps\n extends JSX.ButtonHTMLAttributes<HTMLButtonElement>,\n VariantProps<typeof paginationButtonVariants> {\n class?: string;\n hideText?: boolean;\n}\n\nexport const PaginationLast: Component<PaginationLastProps> = (props) => {\n const [local, rest] = splitProps(props, [\"class\", \"variant\", \"size\", \"hideText\"]);\n\n return (\n <PaginationLink\n aria-label=\"Go to last page\"\n variant={local.variant}\n size={local.size}\n class={cn(\"gap-1 p-0 min-w-8\", local.class)}\n {...rest}\n >\n <ChevronsRight class=\"size-4\" />\n <Show when={!local.hideText}>\n <span class=\"sr-only\">Last page</span>\n </Show>\n </PaginationLink>\n );\n};\n\n/* --- 10. PaginationEllipsis --- */\nexport interface PaginationEllipsisProps extends JSX.HTMLAttributes<HTMLSpanElement> {\n class?: string;\n}\n\nexport const PaginationEllipsis: Component<PaginationEllipsisProps> = (props) => {\n const [local, rest] = splitProps(props, [\"class\"]);\n\n return (\n <span\n aria-hidden=\"true\"\n class={cn(\"flex h-9 w-9 items-center justify-center text-muted-foreground\", local.class)}\n {...rest}\n >\n <MoreHorizontal class=\"size-4\" />\n <span class=\"sr-only\">More pages</span>\n </span>\n );\n};\n\n/* --- 11. PaginationSummary --- */\nexport interface PaginationSummaryProps extends JSX.HTMLAttributes<HTMLDivElement> {\n class?: string;\n}\n\nexport const PaginationSummary: ParentComponent<PaginationSummaryProps> = (props) => {\n const [local, rest] = splitProps(props, [\"class\", \"children\"]);\n\n return (\n <div\n class={cn(\"text-xs text-muted-foreground font-mono select-none\", local.class)}\n {...rest}\n >\n {local.children}\n </div>\n );\n};\n",
|
|
19
|
+
"type": "registry:ui"
|
|
20
|
+
}
|
|
21
|
+
]
|
|
22
|
+
}
|