gladvn 0.2.14
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 +112 -0
- package/bin/cli.js +326 -0
- package/dist/components/macro/accordion-preset.d.ts +14 -0
- package/dist/components/macro/accordion-preset.d.ts.map +1 -0
- package/dist/components/macro/alert-dialog-preset.d.ts +26 -0
- package/dist/components/macro/alert-dialog-preset.d.ts.map +1 -0
- package/dist/components/macro/alert-preset.d.ts +14 -0
- package/dist/components/macro/alert-preset.d.ts.map +1 -0
- package/dist/components/macro/avatar-preset.d.ts +11 -0
- package/dist/components/macro/avatar-preset.d.ts.map +1 -0
- package/dist/components/macro/breadcrumb-preset.d.ts +12 -0
- package/dist/components/macro/breadcrumb-preset.d.ts.map +1 -0
- package/dist/components/macro/card-preset.d.ts +10 -0
- package/dist/components/macro/card-preset.d.ts.map +1 -0
- package/dist/components/macro/carousel-preset.d.ts +18 -0
- package/dist/components/macro/carousel-preset.d.ts.map +1 -0
- package/dist/components/macro/checkbox-preset.d.ts +14 -0
- package/dist/components/macro/checkbox-preset.d.ts.map +1 -0
- package/dist/components/macro/combobox-preset.d.ts +27 -0
- package/dist/components/macro/combobox-preset.d.ts.map +1 -0
- package/dist/components/macro/command-preset.d.ts +16 -0
- package/dist/components/macro/command-preset.d.ts.map +1 -0
- package/dist/components/macro/date-picker.d.ts +62 -0
- package/dist/components/macro/date-picker.d.ts.map +1 -0
- package/dist/components/macro/dialog-preset.d.ts +24 -0
- package/dist/components/macro/dialog-preset.d.ts.map +1 -0
- package/dist/components/macro/empty-preset.d.ts +15 -0
- package/dist/components/macro/empty-preset.d.ts.map +1 -0
- package/dist/components/macro/field-preset.d.ts +15 -0
- package/dist/components/macro/field-preset.d.ts.map +1 -0
- package/dist/components/macro/index.d.ts +22 -0
- package/dist/components/macro/index.d.ts.map +1 -0
- package/dist/components/macro/input-otp-preset.d.ts +13 -0
- package/dist/components/macro/input-otp-preset.d.ts.map +1 -0
- package/dist/components/macro/input-preset.d.ts +21 -0
- package/dist/components/macro/input-preset.d.ts.map +1 -0
- package/dist/components/macro/pagination-preset.d.ts +13 -0
- package/dist/components/macro/pagination-preset.d.ts.map +1 -0
- package/dist/components/macro/progress-preset.d.ts +10 -0
- package/dist/components/macro/progress-preset.d.ts.map +1 -0
- package/dist/components/macro/radio-group-preset.d.ts +22 -0
- package/dist/components/macro/radio-group-preset.d.ts.map +1 -0
- package/dist/components/macro/select-preset.d.ts +42 -0
- package/dist/components/macro/select-preset.d.ts.map +1 -0
- package/dist/components/macro/slider-preset.d.ts +12 -0
- package/dist/components/macro/slider-preset.d.ts.map +1 -0
- package/dist/components/macro/switch-preset.d.ts +12 -0
- package/dist/components/macro/switch-preset.d.ts.map +1 -0
- package/dist/components/macro/tabs-preset.d.ts +17 -0
- package/dist/components/macro/tabs-preset.d.ts.map +1 -0
- package/dist/components/macro/textarea-preset.d.ts +17 -0
- package/dist/components/macro/textarea-preset.d.ts.map +1 -0
- package/dist/components/micro/accordion.d.ts +8 -0
- package/dist/components/micro/accordion.d.ts.map +1 -0
- package/dist/components/micro/alert-dialog.d.ts +33 -0
- package/dist/components/micro/alert-dialog.d.ts.map +1 -0
- package/dist/components/micro/alert.d.ts +28 -0
- package/dist/components/micro/alert.d.ts.map +1 -0
- package/dist/components/micro/aspect-ratio.d.ts +13 -0
- package/dist/components/micro/aspect-ratio.d.ts.map +1 -0
- package/dist/components/micro/avatar.d.ts +23 -0
- package/dist/components/micro/avatar.d.ts.map +1 -0
- package/dist/components/micro/badge.d.ts +16 -0
- package/dist/components/micro/badge.d.ts.map +1 -0
- package/dist/components/micro/breadcrumb.d.ts +24 -0
- package/dist/components/micro/breadcrumb.d.ts.map +1 -0
- package/dist/components/micro/button.d.ts +39 -0
- package/dist/components/micro/button.d.ts.map +1 -0
- package/dist/components/micro/calendar.d.ts +28 -0
- package/dist/components/micro/calendar.d.ts.map +1 -0
- package/dist/components/micro/card.d.ts +28 -0
- package/dist/components/micro/card.d.ts.map +1 -0
- package/dist/components/micro/carousel.d.ts +29 -0
- package/dist/components/micro/carousel.d.ts.map +1 -0
- package/dist/components/micro/chart.d.ts +49 -0
- package/dist/components/micro/chart.d.ts.map +1 -0
- package/dist/components/micro/checkbox.d.ts +17 -0
- package/dist/components/micro/checkbox.d.ts.map +1 -0
- package/dist/components/micro/collapsible.d.ts +15 -0
- package/dist/components/micro/collapsible.d.ts.map +1 -0
- package/dist/components/micro/combobox.d.ts +33 -0
- package/dist/components/micro/combobox.d.ts.map +1 -0
- package/dist/components/micro/command.d.ts +79 -0
- package/dist/components/micro/command.d.ts.map +1 -0
- package/dist/components/micro/context-menu.d.ts +60 -0
- package/dist/components/micro/context-menu.d.ts.map +1 -0
- package/dist/components/micro/dialog.d.ts +14 -0
- package/dist/components/micro/dialog.d.ts.map +1 -0
- package/dist/components/micro/direction.d.ts +2 -0
- package/dist/components/micro/direction.d.ts.map +1 -0
- package/dist/components/micro/drawer.d.ts +17 -0
- package/dist/components/micro/drawer.d.ts.map +1 -0
- package/dist/components/micro/dropdown-menu.d.ts +37 -0
- package/dist/components/micro/dropdown-menu.d.ts.map +1 -0
- package/dist/components/micro/empty.d.ts +23 -0
- package/dist/components/micro/empty.d.ts.map +1 -0
- package/dist/components/micro/field.d.ts +29 -0
- package/dist/components/micro/field.d.ts.map +1 -0
- package/dist/components/micro/hover-card.d.ts +17 -0
- package/dist/components/micro/hover-card.d.ts.map +1 -0
- package/dist/components/micro/input-group.d.ts +17 -0
- package/dist/components/micro/input-group.d.ts.map +1 -0
- package/dist/components/micro/input-otp.d.ts +44 -0
- package/dist/components/micro/input-otp.d.ts.map +1 -0
- package/dist/components/micro/input.d.ts +22 -0
- package/dist/components/micro/input.d.ts.map +1 -0
- package/dist/components/micro/item.d.ts +31 -0
- package/dist/components/micro/item.d.ts.map +1 -0
- package/dist/components/micro/kbd.d.ts +9 -0
- package/dist/components/micro/kbd.d.ts.map +1 -0
- package/dist/components/micro/label.d.ts +15 -0
- package/dist/components/micro/label.d.ts.map +1 -0
- package/dist/components/micro/menubar.d.ts +41 -0
- package/dist/components/micro/menubar.d.ts.map +1 -0
- package/dist/components/micro/navigation-menu.d.ts +18 -0
- package/dist/components/micro/navigation-menu.d.ts.map +1 -0
- package/dist/components/micro/pagination.d.ts +33 -0
- package/dist/components/micro/pagination.d.ts.map +1 -0
- package/dist/components/micro/popover.d.ts +23 -0
- package/dist/components/micro/popover.d.ts.map +1 -0
- package/dist/components/micro/progress.d.ts +19 -0
- package/dist/components/micro/progress.d.ts.map +1 -0
- package/dist/components/micro/radio-group.d.ts +13 -0
- package/dist/components/micro/radio-group.d.ts.map +1 -0
- package/dist/components/micro/resizable.d.ts +12 -0
- package/dist/components/micro/resizable.d.ts.map +1 -0
- package/dist/components/micro/scroll-area.d.ts +12 -0
- package/dist/components/micro/scroll-area.d.ts.map +1 -0
- package/dist/components/micro/select.d.ts +21 -0
- package/dist/components/micro/select.d.ts.map +1 -0
- package/dist/components/micro/separator.d.ts +9 -0
- package/dist/components/micro/separator.d.ts.map +1 -0
- package/dist/components/micro/sheet.d.ts +17 -0
- package/dist/components/micro/sheet.d.ts.map +1 -0
- package/dist/components/micro/sidebar.d.ts +28 -0
- package/dist/components/micro/sidebar.d.ts.map +1 -0
- package/dist/components/micro/skeleton.d.ts +9 -0
- package/dist/components/micro/skeleton.d.ts.map +1 -0
- package/dist/components/micro/slider.d.ts +14 -0
- package/dist/components/micro/slider.d.ts.map +1 -0
- package/dist/components/micro/sonner.d.ts +5 -0
- package/dist/components/micro/sonner.d.ts.map +1 -0
- package/dist/components/micro/spinner.d.ts +21 -0
- package/dist/components/micro/spinner.d.ts.map +1 -0
- package/dist/components/micro/switch.d.ts +13 -0
- package/dist/components/micro/switch.d.ts.map +1 -0
- package/dist/components/micro/table.d.ts +17 -0
- package/dist/components/micro/table.d.ts.map +1 -0
- package/dist/components/micro/tabs.d.ts +13 -0
- package/dist/components/micro/tabs.d.ts.map +1 -0
- package/dist/components/micro/textarea.d.ts +17 -0
- package/dist/components/micro/textarea.d.ts.map +1 -0
- package/dist/components/micro/theme-provider.d.ts +76 -0
- package/dist/components/micro/theme-provider.d.ts.map +1 -0
- package/dist/components/micro/toggle-group.d.ts +22 -0
- package/dist/components/micro/toggle-group.d.ts.map +1 -0
- package/dist/components/micro/toggle.d.ts +16 -0
- package/dist/components/micro/toggle.d.ts.map +1 -0
- package/dist/components/micro/tooltip.d.ts +20 -0
- package/dist/components/micro/tooltip.d.ts.map +1 -0
- package/dist/dev/App.d.ts +3 -0
- package/dist/dev/App.d.ts.map +1 -0
- package/dist/dev/components/GladcnLogo.d.ts +10 -0
- package/dist/dev/components/GladcnLogo.d.ts.map +1 -0
- package/dist/dev/components/code-highlighter.d.ts +5 -0
- package/dist/dev/components/code-highlighter.d.ts.map +1 -0
- package/dist/dev/components/dev-context.d.ts +12 -0
- package/dist/dev/components/dev-context.d.ts.map +1 -0
- package/dist/dev/components/showcase.d.ts +72 -0
- package/dist/dev/components/showcase.d.ts.map +1 -0
- package/dist/dev/data.d.ts +68 -0
- package/dist/dev/data.d.ts.map +1 -0
- package/dist/dev/main.d.ts +1 -0
- package/dist/dev/main.d.ts.map +1 -0
- package/dist/dev/sections/buttons.d.ts +2 -0
- package/dist/dev/sections/buttons.d.ts.map +1 -0
- package/dist/dev/sections/display.d.ts +2 -0
- package/dist/dev/sections/display.d.ts.map +1 -0
- package/dist/dev/sections/feedback.d.ts +2 -0
- package/dist/dev/sections/feedback.d.ts.map +1 -0
- package/dist/dev/sections/forms.d.ts +2 -0
- package/dist/dev/sections/forms.d.ts.map +1 -0
- package/dist/dev/sections/interactive.d.ts +2 -0
- package/dist/dev/sections/interactive.d.ts.map +1 -0
- package/dist/dev/sections/overview.d.ts +2 -0
- package/dist/dev/sections/overview.d.ts.map +1 -0
- package/dist/dev/showcase/accordion.d.ts +2 -0
- package/dist/dev/showcase/accordion.d.ts.map +1 -0
- package/dist/dev/showcase/alert-dialog.d.ts +2 -0
- package/dist/dev/showcase/alert-dialog.d.ts.map +1 -0
- package/dist/dev/showcase/alert.d.ts +2 -0
- package/dist/dev/showcase/alert.d.ts.map +1 -0
- package/dist/dev/showcase/aspect-ratio.d.ts +2 -0
- package/dist/dev/showcase/aspect-ratio.d.ts.map +1 -0
- package/dist/dev/showcase/avatar.d.ts +2 -0
- package/dist/dev/showcase/avatar.d.ts.map +1 -0
- package/dist/dev/showcase/badge.d.ts +2 -0
- package/dist/dev/showcase/badge.d.ts.map +1 -0
- package/dist/dev/showcase/breadcrumb.d.ts +2 -0
- package/dist/dev/showcase/breadcrumb.d.ts.map +1 -0
- package/dist/dev/showcase/button.d.ts +2 -0
- package/dist/dev/showcase/button.d.ts.map +1 -0
- package/dist/dev/showcase/calendar.d.ts +2 -0
- package/dist/dev/showcase/calendar.d.ts.map +1 -0
- package/dist/dev/showcase/card.d.ts +2 -0
- package/dist/dev/showcase/card.d.ts.map +1 -0
- package/dist/dev/showcase/carousel.d.ts +2 -0
- package/dist/dev/showcase/carousel.d.ts.map +1 -0
- package/dist/dev/showcase/chart.d.ts +2 -0
- package/dist/dev/showcase/chart.d.ts.map +1 -0
- package/dist/dev/showcase/checkbox.d.ts +2 -0
- package/dist/dev/showcase/checkbox.d.ts.map +1 -0
- package/dist/dev/showcase/collapsible.d.ts +3 -0
- package/dist/dev/showcase/collapsible.d.ts.map +1 -0
- package/dist/dev/showcase/combobox.d.ts +2 -0
- package/dist/dev/showcase/combobox.d.ts.map +1 -0
- package/dist/dev/showcase/command.d.ts +2 -0
- package/dist/dev/showcase/command.d.ts.map +1 -0
- package/dist/dev/showcase/context-menu.d.ts +2 -0
- package/dist/dev/showcase/context-menu.d.ts.map +1 -0
- package/dist/dev/showcase/dialog.d.ts +2 -0
- package/dist/dev/showcase/dialog.d.ts.map +1 -0
- package/dist/dev/showcase/drawer.d.ts +2 -0
- package/dist/dev/showcase/drawer.d.ts.map +1 -0
- package/dist/dev/showcase/dropdown-menu.d.ts +2 -0
- package/dist/dev/showcase/dropdown-menu.d.ts.map +1 -0
- package/dist/dev/showcase/empty.d.ts +2 -0
- package/dist/dev/showcase/empty.d.ts.map +1 -0
- package/dist/dev/showcase/hover-card.d.ts +2 -0
- package/dist/dev/showcase/hover-card.d.ts.map +1 -0
- package/dist/dev/showcase/input-group.d.ts +2 -0
- package/dist/dev/showcase/input-group.d.ts.map +1 -0
- package/dist/dev/showcase/input-otp.d.ts +2 -0
- package/dist/dev/showcase/input-otp.d.ts.map +1 -0
- package/dist/dev/showcase/input.d.ts +2 -0
- package/dist/dev/showcase/input.d.ts.map +1 -0
- package/dist/dev/showcase/item.d.ts +2 -0
- package/dist/dev/showcase/item.d.ts.map +1 -0
- package/dist/dev/showcase/kbd.d.ts +2 -0
- package/dist/dev/showcase/kbd.d.ts.map +1 -0
- package/dist/dev/showcase/label.d.ts +2 -0
- package/dist/dev/showcase/label.d.ts.map +1 -0
- package/dist/dev/showcase/menubar.d.ts +2 -0
- package/dist/dev/showcase/menubar.d.ts.map +1 -0
- package/dist/dev/showcase/navigation-menu.d.ts +3 -0
- package/dist/dev/showcase/navigation-menu.d.ts.map +1 -0
- package/dist/dev/showcase/overview.d.ts +2 -0
- package/dist/dev/showcase/overview.d.ts.map +1 -0
- package/dist/dev/showcase/pagination.d.ts +2 -0
- package/dist/dev/showcase/pagination.d.ts.map +1 -0
- package/dist/dev/showcase/popover.d.ts +2 -0
- package/dist/dev/showcase/popover.d.ts.map +1 -0
- package/dist/dev/showcase/progress.d.ts +2 -0
- package/dist/dev/showcase/progress.d.ts.map +1 -0
- package/dist/dev/showcase/radio-group.d.ts +2 -0
- package/dist/dev/showcase/radio-group.d.ts.map +1 -0
- package/dist/dev/showcase/resizable.d.ts +2 -0
- package/dist/dev/showcase/resizable.d.ts.map +1 -0
- package/dist/dev/showcase/scroll-area.d.ts +2 -0
- package/dist/dev/showcase/scroll-area.d.ts.map +1 -0
- package/dist/dev/showcase/select.d.ts +2 -0
- package/dist/dev/showcase/select.d.ts.map +1 -0
- package/dist/dev/showcase/separator.d.ts +2 -0
- package/dist/dev/showcase/separator.d.ts.map +1 -0
- package/dist/dev/showcase/sheet.d.ts +2 -0
- package/dist/dev/showcase/sheet.d.ts.map +1 -0
- package/dist/dev/showcase/sidebar.d.ts +2 -0
- package/dist/dev/showcase/sidebar.d.ts.map +1 -0
- package/dist/dev/showcase/skeleton.d.ts +2 -0
- package/dist/dev/showcase/skeleton.d.ts.map +1 -0
- package/dist/dev/showcase/slider.d.ts +2 -0
- package/dist/dev/showcase/slider.d.ts.map +1 -0
- package/dist/dev/showcase/sonner.d.ts +2 -0
- package/dist/dev/showcase/sonner.d.ts.map +1 -0
- package/dist/dev/showcase/spinner.d.ts +2 -0
- package/dist/dev/showcase/spinner.d.ts.map +1 -0
- package/dist/dev/showcase/switch.d.ts +2 -0
- package/dist/dev/showcase/switch.d.ts.map +1 -0
- package/dist/dev/showcase/table.d.ts +2 -0
- package/dist/dev/showcase/table.d.ts.map +1 -0
- package/dist/dev/showcase/tabs.d.ts +2 -0
- package/dist/dev/showcase/tabs.d.ts.map +1 -0
- package/dist/dev/showcase/textarea.d.ts +2 -0
- package/dist/dev/showcase/textarea.d.ts.map +1 -0
- package/dist/dev/showcase/theme-provider.d.ts +2 -0
- package/dist/dev/showcase/theme-provider.d.ts.map +1 -0
- package/dist/dev/showcase/toast.d.ts +2 -0
- package/dist/dev/showcase/toast.d.ts.map +1 -0
- package/dist/dev/showcase/toggle-group.d.ts +2 -0
- package/dist/dev/showcase/toggle-group.d.ts.map +1 -0
- package/dist/dev/showcase/toggle.d.ts +2 -0
- package/dist/dev/showcase/toggle.d.ts.map +1 -0
- package/dist/dev/showcase/tooltip.d.ts +2 -0
- package/dist/dev/showcase/tooltip.d.ts.map +1 -0
- package/dist/hooks/use-controllable-state.d.ts +14 -0
- package/dist/hooks/use-controllable-state.d.ts.map +1 -0
- package/dist/hooks/use-mobile.d.ts +2 -0
- package/dist/hooks/use-mobile.d.ts.map +1 -0
- package/dist/index.cjs +5099 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.ts +58 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +4740 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/types.d.ts +4 -0
- package/dist/lib/types.d.ts.map +1 -0
- package/dist/lib/utils.d.ts +3 -0
- package/dist/lib/utils.d.ts.map +1 -0
- package/dist/preset.d.ts +18 -0
- package/dist/preset.d.ts.map +1 -0
- package/dist/test/setup.d.ts +1 -0
- package/dist/test/setup.d.ts.map +1 -0
- package/llms.txt +74 -0
- package/package.json +117 -0
- package/scripts/add-icononly-prop.ts +84 -0
- package/scripts/audit-best-practices.ts +114 -0
- package/scripts/audit-showcase.ts +262 -0
- package/scripts/audit-showcases.ts +83 -0
- package/scripts/clean-imports.ts +21 -0
- package/scripts/count_missing.ts +24 -0
- package/scripts/find-css-vars.ts +62 -0
- package/scripts/fix-portals.ts +90 -0
- package/scripts/full-audit.ts +89 -0
- package/scripts/merge-components.cjs +65 -0
- package/scripts/merge-components.js +64 -0
- package/scripts/optimize-barrel.ts +116 -0
- package/scripts/postinstall.cjs +228 -0
- package/scripts/refactor_divs.ts +39 -0
- package/scripts/remove_div_wrappers.ts +17 -0
- package/scripts/update-gaps.ts +83 -0
- package/scripts/update_showcase_codestrings.ts +87 -0
- package/src/components/macro/accordion-preset.test.tsx +37 -0
- package/src/components/macro/accordion-preset.tsx +41 -0
- package/src/components/macro/alert-dialog-preset.tsx +116 -0
- package/src/components/macro/alert-preset.tsx +94 -0
- package/src/components/macro/avatar-preset.tsx +54 -0
- package/src/components/macro/breadcrumb-preset.tsx +50 -0
- package/src/components/macro/card-preset.tsx +44 -0
- package/src/components/macro/carousel-preset.tsx +150 -0
- package/src/components/macro/checkbox-preset.test.tsx +49 -0
- package/src/components/macro/checkbox-preset.tsx +84 -0
- package/src/components/macro/combobox-preset.tsx +171 -0
- package/src/components/macro/command-preset.tsx +74 -0
- package/src/components/macro/date-picker.tsx +289 -0
- package/src/components/macro/dialog-preset.tsx +105 -0
- package/src/components/macro/empty-preset.tsx +46 -0
- package/src/components/macro/field-preset.test.tsx +69 -0
- package/src/components/macro/field-preset.tsx +65 -0
- package/src/components/macro/index.ts +21 -0
- package/src/components/macro/input-otp-preset.tsx +98 -0
- package/src/components/macro/input-preset.test.tsx +52 -0
- package/src/components/macro/input-preset.tsx +139 -0
- package/src/components/macro/pagination-preset.tsx +153 -0
- package/src/components/macro/progress-preset.test.tsx +65 -0
- package/src/components/macro/progress-preset.tsx +45 -0
- package/src/components/macro/radio-group-preset.tsx +115 -0
- package/src/components/macro/select-preset.tsx +168 -0
- package/src/components/macro/slider-preset.test.tsx +43 -0
- package/src/components/macro/slider-preset.tsx +86 -0
- package/src/components/macro/switch-preset.test.tsx +53 -0
- package/src/components/macro/switch-preset.tsx +70 -0
- package/src/components/macro/tabs-preset.test.tsx +31 -0
- package/src/components/macro/tabs-preset.tsx +51 -0
- package/src/components/macro/textarea-preset.test.tsx +39 -0
- package/src/components/macro/textarea-preset.tsx +55 -0
- package/src/components/micro/accordion.tsx +76 -0
- package/src/components/micro/alert-dialog.tsx +213 -0
- package/src/components/micro/alert.tsx +146 -0
- package/src/components/micro/aspect-ratio.tsx +38 -0
- package/src/components/micro/avatar.tsx +143 -0
- package/src/components/micro/badge.tsx +207 -0
- package/src/components/micro/breadcrumb.tsx +162 -0
- package/src/components/micro/button.test.tsx +25 -0
- package/src/components/micro/button.tsx +361 -0
- package/src/components/micro/calendar.tsx +383 -0
- package/src/components/micro/card.tsx +112 -0
- package/src/components/micro/carousel.tsx +341 -0
- package/src/components/micro/chart.tsx +392 -0
- package/src/components/micro/checkbox.tsx +74 -0
- package/src/components/micro/collapsible.tsx +65 -0
- package/src/components/micro/combobox.tsx +349 -0
- package/src/components/micro/command.tsx +238 -0
- package/src/components/micro/context-menu.tsx +285 -0
- package/src/components/micro/dialog.tsx +143 -0
- package/src/components/micro/direction.tsx +13 -0
- package/src/components/micro/drawer.tsx +149 -0
- package/src/components/micro/dropdown-menu.tsx +305 -0
- package/src/components/micro/empty.tsx +144 -0
- package/src/components/micro/field.tsx +311 -0
- package/src/components/micro/hover-card.tsx +86 -0
- package/src/components/micro/input-group.tsx +269 -0
- package/src/components/micro/input-otp.tsx +130 -0
- package/src/components/micro/input.tsx +56 -0
- package/src/components/micro/item.tsx +206 -0
- package/src/components/micro/kbd.tsx +38 -0
- package/src/components/micro/label.tsx +48 -0
- package/src/components/micro/menubar.tsx +302 -0
- package/src/components/micro/navigation-menu.tsx +197 -0
- package/src/components/micro/pagination.tsx +162 -0
- package/src/components/micro/popover.tsx +131 -0
- package/src/components/micro/progress.tsx +144 -0
- package/src/components/micro/radio-group.tsx +73 -0
- package/src/components/micro/resizable.tsx +64 -0
- package/src/components/micro/scroll-area.tsx +68 -0
- package/src/components/micro/select.tsx +234 -0
- package/src/components/micro/separator.tsx +37 -0
- package/src/components/micro/sheet.tsx +144 -0
- package/src/components/micro/sidebar.tsx +238 -0
- package/src/components/micro/skeleton.tsx +29 -0
- package/src/components/micro/slider.tsx +135 -0
- package/src/components/micro/sonner.tsx +85 -0
- package/src/components/micro/spinner.tsx +44 -0
- package/src/components/micro/switch.tsx +70 -0
- package/src/components/micro/table.tsx +210 -0
- package/src/components/micro/tabs.tsx +100 -0
- package/src/components/micro/textarea.tsx +53 -0
- package/src/components/micro/theme-provider.tsx +163 -0
- package/src/components/micro/toggle-group.tsx +121 -0
- package/src/components/micro/toggle.tsx +55 -0
- package/src/components/micro/tooltip.tsx +105 -0
- package/src/dev/App.tsx +322 -0
- package/src/dev/_debug_select.html +29 -0
- package/src/dev/components/GladcnLogo.tsx +80 -0
- package/src/dev/components/code-highlighter.tsx +67 -0
- package/src/dev/components/dev-context.tsx +31 -0
- package/src/dev/components/showcase.tsx +413 -0
- package/src/dev/data.ts +341 -0
- package/src/dev/index.css +55 -0
- package/src/dev/main.tsx +30 -0
- package/src/dev/sections/buttons.tsx +303 -0
- package/src/dev/sections/display.tsx +270 -0
- package/src/dev/sections/feedback.tsx +371 -0
- package/src/dev/sections/forms.tsx +652 -0
- package/src/dev/sections/interactive.tsx +51 -0
- package/src/dev/sections/overview.tsx +396 -0
- package/src/dev/showcase/accordion.tsx +947 -0
- package/src/dev/showcase/alert-dialog.tsx +1056 -0
- package/src/dev/showcase/alert.tsx +756 -0
- package/src/dev/showcase/aspect-ratio.tsx +339 -0
- package/src/dev/showcase/avatar.tsx +470 -0
- package/src/dev/showcase/badge.tsx +227 -0
- package/src/dev/showcase/breadcrumb.tsx +269 -0
- package/src/dev/showcase/button.tsx +309 -0
- package/src/dev/showcase/calendar.tsx +380 -0
- package/src/dev/showcase/card.tsx +448 -0
- package/src/dev/showcase/carousel.tsx +562 -0
- package/src/dev/showcase/chart.tsx +130 -0
- package/src/dev/showcase/checkbox.tsx +611 -0
- package/src/dev/showcase/collapsible.tsx +298 -0
- package/src/dev/showcase/combobox.tsx +777 -0
- package/src/dev/showcase/command.tsx +245 -0
- package/src/dev/showcase/context-menu.tsx +239 -0
- package/src/dev/showcase/dialog.tsx +1141 -0
- package/src/dev/showcase/drawer.tsx +392 -0
- package/src/dev/showcase/dropdown-menu.tsx +420 -0
- package/src/dev/showcase/empty.tsx +493 -0
- package/src/dev/showcase/hover-card.tsx +336 -0
- package/src/dev/showcase/input-group.tsx +511 -0
- package/src/dev/showcase/input-otp.tsx +404 -0
- package/src/dev/showcase/input.tsx +530 -0
- package/src/dev/showcase/item.tsx +295 -0
- package/src/dev/showcase/kbd.tsx +276 -0
- package/src/dev/showcase/label.tsx +121 -0
- package/src/dev/showcase/menubar.tsx +392 -0
- package/src/dev/showcase/navigation-menu.tsx +304 -0
- package/src/dev/showcase/overview.tsx +1106 -0
- package/src/dev/showcase/pagination.tsx +312 -0
- package/src/dev/showcase/popover.tsx +374 -0
- package/src/dev/showcase/progress.tsx +299 -0
- package/src/dev/showcase/radio-group.tsx +612 -0
- package/src/dev/showcase/resizable.tsx +237 -0
- package/src/dev/showcase/scroll-area.tsx +157 -0
- package/src/dev/showcase/select.tsx +628 -0
- package/src/dev/showcase/separator.tsx +126 -0
- package/src/dev/showcase/sheet.tsx +566 -0
- package/src/dev/showcase/sidebar.tsx +120 -0
- package/src/dev/showcase/skeleton.tsx +213 -0
- package/src/dev/showcase/slider.tsx +506 -0
- package/src/dev/showcase/sonner.tsx +376 -0
- package/src/dev/showcase/spinner.tsx +124 -0
- package/src/dev/showcase/switch.tsx +602 -0
- package/src/dev/showcase/table.tsx +196 -0
- package/src/dev/showcase/tabs.tsx +662 -0
- package/src/dev/showcase/textarea.tsx +498 -0
- package/src/dev/showcase/theme-provider.tsx +894 -0
- package/src/dev/showcase/toast.tsx +119 -0
- package/src/dev/showcase/toggle-group.tsx +223 -0
- package/src/dev/showcase/toggle.tsx +171 -0
- package/src/dev/showcase/tooltip.tsx +372 -0
- package/src/hooks/use-controllable-state.ts +87 -0
- package/src/hooks/use-mobile.ts +21 -0
- package/src/index.ts +62 -0
- package/src/lib/types.ts +14 -0
- package/src/lib/utils.test.ts +14 -0
- package/src/lib/utils.ts +6 -0
- package/src/preset.ts +17 -0
- package/src/styles/gladcn.css +116 -0
- package/src/styles/tokens.css +213 -0
- package/src/test/setup.ts +8 -0
- package/src/vite-env.d.ts +1 -0
|
@@ -0,0 +1,1106 @@
|
|
|
1
|
+
import {
|
|
2
|
+
AccessibilityIcon,
|
|
3
|
+
ArrowRightIcon,
|
|
4
|
+
BlocksIcon,
|
|
5
|
+
BoxIcon,
|
|
6
|
+
CheckIcon,
|
|
7
|
+
ComponentIcon,
|
|
8
|
+
CopyIcon,
|
|
9
|
+
DatabaseIcon,
|
|
10
|
+
LayersIcon,
|
|
11
|
+
PaintbrushIcon,
|
|
12
|
+
PaletteIcon,
|
|
13
|
+
ShieldCheckIcon,
|
|
14
|
+
SlidersHorizontalIcon,
|
|
15
|
+
SparklesIcon,
|
|
16
|
+
CodeIcon,
|
|
17
|
+
} from "lucide-react";
|
|
18
|
+
import { useEffect, useState } from "react";
|
|
19
|
+
import { toast } from "sonner";
|
|
20
|
+
import { GladcnLogo } from "../../dev/components/GladcnLogo";
|
|
21
|
+
|
|
22
|
+
import { ProgressPreset as Progress } from "../../components/macro/progress-preset";
|
|
23
|
+
import { Badge } from "../../components/micro/badge";
|
|
24
|
+
import { Button } from "../../components/micro/button";
|
|
25
|
+
import {
|
|
26
|
+
Card,
|
|
27
|
+
CardContent,
|
|
28
|
+
CardHeader,
|
|
29
|
+
CardTitle,
|
|
30
|
+
} from "../../components/micro/card";
|
|
31
|
+
import { Label } from "../../components/micro/label";
|
|
32
|
+
import {
|
|
33
|
+
Select,
|
|
34
|
+
SelectContent,
|
|
35
|
+
SelectItem,
|
|
36
|
+
SelectTrigger,
|
|
37
|
+
SelectValue, SelectPortal } from "../../components/micro/select";
|
|
38
|
+
import { Switch } from "../../components/micro/switch";
|
|
39
|
+
import { ColorSwatch } from "../../dev/components/showcase";
|
|
40
|
+
import { COLORS, STATS } from "../../dev/data";
|
|
41
|
+
import { cn } from "../../lib/utils";
|
|
42
|
+
|
|
43
|
+
function CodeBlock({
|
|
44
|
+
type,
|
|
45
|
+
title,
|
|
46
|
+
children,
|
|
47
|
+
}: {
|
|
48
|
+
type: "success" | "destructive";
|
|
49
|
+
title: string;
|
|
50
|
+
children: React.ReactNode;
|
|
51
|
+
}) {
|
|
52
|
+
const isSuccess = type === "success";
|
|
53
|
+
return (
|
|
54
|
+
<div
|
|
55
|
+
className={cn(
|
|
56
|
+
"p-4 rounded-xl border border-border shadow-sm text-[11px] sm:text-xs font-mono",
|
|
57
|
+
isSuccess
|
|
58
|
+
? "border-success/20 bg-success/5"
|
|
59
|
+
: "border-destructive/20 bg-destructive/5 opacity-80",
|
|
60
|
+
)}
|
|
61
|
+
>
|
|
62
|
+
<div
|
|
63
|
+
className={cn(
|
|
64
|
+
"font-semibold mb-2 flex items-center gap-2",
|
|
65
|
+
isSuccess ? "text-success" : "text-destructive",
|
|
66
|
+
)}
|
|
67
|
+
>
|
|
68
|
+
{isSuccess ? "✅" : "❌"} {title}
|
|
69
|
+
</div>
|
|
70
|
+
<div
|
|
71
|
+
className={cn(
|
|
72
|
+
"text-muted-foreground pl-3 border-l-2 leading-relaxed",
|
|
73
|
+
isSuccess ? "border-success/50" : "border-destructive/50",
|
|
74
|
+
)}
|
|
75
|
+
>
|
|
76
|
+
{children}
|
|
77
|
+
</div>
|
|
78
|
+
</div>
|
|
79
|
+
);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export default function OverviewSection() {
|
|
83
|
+
const [copied, setCopied] = useState(false);
|
|
84
|
+
const [mounted, setMounted] = useState(false);
|
|
85
|
+
|
|
86
|
+
useEffect(() => {
|
|
87
|
+
setMounted(true);
|
|
88
|
+
}, []);
|
|
89
|
+
|
|
90
|
+
const handleCopy = () => {
|
|
91
|
+
navigator.clipboard.writeText("npx gladvn init");
|
|
92
|
+
setCopied(true);
|
|
93
|
+
toast.success("Đã copy lệnh vào clipboard");
|
|
94
|
+
setTimeout(() => setCopied(false), 2000);
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
return (
|
|
98
|
+
<div className="space-y-24 overflow-hidden pb-24 font-sans">
|
|
99
|
+
{/* 🌌 HERO SECTION - Breathtaking Aurora / Glassmorphism */}
|
|
100
|
+
<section className="relative pt-20 pb-32">
|
|
101
|
+
{/* Animated Background Mesh */}
|
|
102
|
+
<div className="absolute inset-0 -z-10 h-full w-full bg-background bg-[radial-gradient(ellipse_80%_80%_at_50%_-20%,rgba(var(--primary-rgb),0.2),rgba(255,255,255,0))] dark:bg-[radial-gradient(ellipse_80%_80%_at_50%_-20%,rgba(var(--primary-rgb),0.15),rgba(255,255,255,0))]" />
|
|
103
|
+
|
|
104
|
+
<div className="absolute top-0 inset-x-0 flex justify-center -z-10 pointer-events-none opacity-50 dark:opacity-40 blur-[100px]">
|
|
105
|
+
<div
|
|
106
|
+
className="w-[30rem] h-[20rem] bg-primary/40 rounded-full mix-blend-multiply animate-pulse"
|
|
107
|
+
style={{ animationDuration: "8s" }}
|
|
108
|
+
/>
|
|
109
|
+
<div
|
|
110
|
+
className="w-[20rem] h-[15rem] bg-info/30 rounded-full mix-blend-multiply animate-pulse absolute top-10"
|
|
111
|
+
style={{ animationDuration: "10s" }}
|
|
112
|
+
/>
|
|
113
|
+
</div>
|
|
114
|
+
|
|
115
|
+
<div className="container relative z-10 flex flex-col items-center text-center px-4">
|
|
116
|
+
<div
|
|
117
|
+
className="inline-flex items-center gap-2 px-4 py-1.5 mb-8 text-sm font-medium rounded-full border border-primary/20 bg-background/50 backdrop-blur-md shadow-sm animate-fade-up"
|
|
118
|
+
>
|
|
119
|
+
<CodeIcon className="w-3.5 h-3.5 text-primary" />
|
|
120
|
+
<span className="text-muted-foreground">
|
|
121
|
+
Copy code · Own everything · Zero lock-in
|
|
122
|
+
</span>
|
|
123
|
+
</div>
|
|
124
|
+
|
|
125
|
+
<h1
|
|
126
|
+
className="max-w-4xl text-5xl md:text-7xl font-extrabold tracking-tighter mb-8 animate-fade-up"
|
|
127
|
+
style={{ animationDelay: "100ms", animationFillMode: "both" }}
|
|
128
|
+
>
|
|
129
|
+
<span className="block text-foreground drop-shadow-sm">
|
|
130
|
+
Mọi component.
|
|
131
|
+
</span>
|
|
132
|
+
<span className="block mt-2 bg-gradient-to-r leading-[1.2] from-primary via-info to-primary bg-[length:200%_auto] bg-clip-text text-transparent animate-[spin_8s_linear_infinite] [animation-name:gradient] [animation-duration:8s] [animation-timing-function:linear] [animation-iteration-count:infinite]">
|
|
133
|
+
Trong thư mục của bạn.
|
|
134
|
+
</span>
|
|
135
|
+
</h1>
|
|
136
|
+
|
|
137
|
+
<p
|
|
138
|
+
className="max-w-2xl text-lg md:text-xl text-muted-foreground leading-relaxed mb-10 animate-fade-up"
|
|
139
|
+
style={{ animationDelay: "200ms", animationFillMode: "both" }}
|
|
140
|
+
>
|
|
141
|
+
Component library thường đòi bạn follow quy tắc của họ mãi mãi.
|
|
142
|
+
gladcn đặt toàn bộ source code vào tay bạn ngay từ đầu —{" "}
|
|
143
|
+
<strong className="text-foreground">
|
|
144
|
+
không vendor lock-in, không breaking change bất ngờ, không
|
|
145
|
+
node_modules ẩn.
|
|
146
|
+
</strong>
|
|
147
|
+
</p>
|
|
148
|
+
</div>
|
|
149
|
+
|
|
150
|
+
{/* 3D Floating Showcase Dashboard */}
|
|
151
|
+
<div
|
|
152
|
+
className="mt-20 relative max-w-5xl mx-auto px-4 sm:px-6 lg:px-8 animate-fade-up"
|
|
153
|
+
style={{ animationDelay: "500ms", animationFillMode: "both" }}
|
|
154
|
+
>
|
|
155
|
+
<div className="absolute inset-0 bg-gradient-to-t from-background via-transparent to-transparent z-20 pointer-events-none h-full w-full" />
|
|
156
|
+
|
|
157
|
+
<div className="relative rounded-2xl border border-border bg-card/40 backdrop-blur-2xl shadow-2xl overflow-hidden [transform:perspective(1200px)_rotateX(5deg)] [transform-origin:top_center] hover:[transform:perspective(1200px)_rotateX(0deg)] transition-transform duration-700 ease-out">
|
|
158
|
+
<div className="h-12 bg-muted/30 border-b border-b-border flex items-center px-4 gap-2">
|
|
159
|
+
<div className="flex gap-2">
|
|
160
|
+
<div className="size-3.5 rounded-full bg-destructive/80 shadow-sm" />
|
|
161
|
+
<div className="size-3.5 rounded-full bg-warning/80 shadow-sm" />
|
|
162
|
+
<div className="size-3.5 rounded-full bg-success/80 shadow-sm" />
|
|
163
|
+
</div>
|
|
164
|
+
</div>
|
|
165
|
+
|
|
166
|
+
<div className="p-8 grid grid-cols-1 md:grid-cols-3 gap-8 relative">
|
|
167
|
+
<div className="space-y-6 md:col-span-1 z-10">
|
|
168
|
+
<Card className="bg-background/80 shadow-lg border-border/50 backdrop-blur-xl group hover:border-primary/50 transition-colors">
|
|
169
|
+
<CardHeader className="pb-3">
|
|
170
|
+
<CardTitle className="text-sm font-medium flex items-center gap-2">
|
|
171
|
+
<div className="size-2 rounded-full bg-success animate-pulse shadow-[0_0_8px_var(--success)]" />
|
|
172
|
+
Hệ thống Thời gian thực
|
|
173
|
+
</CardTitle>
|
|
174
|
+
</CardHeader>
|
|
175
|
+
<CardContent>
|
|
176
|
+
<div className="space-y-5">
|
|
177
|
+
<div className="space-y-2">
|
|
178
|
+
<div className="flex justify-between text-xs font-medium">
|
|
179
|
+
<span className="text-muted-foreground">Tải CPU</span>
|
|
180
|
+
<span className="text-primary font-mono">
|
|
181
|
+
{mounted ? "24%" : "0%"}
|
|
182
|
+
</span>
|
|
183
|
+
</div>
|
|
184
|
+
<Progress value={mounted ? 24 : 0} className="h-1.5" />
|
|
185
|
+
</div>
|
|
186
|
+
<div className="space-y-2">
|
|
187
|
+
<div className="flex justify-between text-xs font-medium">
|
|
188
|
+
<span className="text-muted-foreground">Bộ nhớ</span>
|
|
189
|
+
<span className="text-warning font-mono">
|
|
190
|
+
{mounted ? "82%" : "0%"}
|
|
191
|
+
</span>
|
|
192
|
+
</div>
|
|
193
|
+
<Progress
|
|
194
|
+
value={mounted ? 82 : 0}
|
|
195
|
+
color="warning"
|
|
196
|
+
className="h-1.5"
|
|
197
|
+
/>
|
|
198
|
+
</div>
|
|
199
|
+
</div>
|
|
200
|
+
</CardContent>
|
|
201
|
+
</Card>
|
|
202
|
+
|
|
203
|
+
<div className="flex flex-col gap-4 p-5 rounded-xl border border-border/50 bg-background/60 backdrop-blur-xl shadow-lg">
|
|
204
|
+
<div className="flex items-center justify-between">
|
|
205
|
+
<Label className="text-sm font-medium cursor-pointer">
|
|
206
|
+
Auto-scaling
|
|
207
|
+
</Label>
|
|
208
|
+
<Switch defaultChecked />
|
|
209
|
+
</div>
|
|
210
|
+
<Select defaultValue="edge">
|
|
211
|
+
<SelectTrigger className="w-full bg-background/50">
|
|
212
|
+
<SelectValue placeholder="Chọn vùng" />
|
|
213
|
+
</SelectTrigger>
|
|
214
|
+
<SelectPortal>
|
|
215
|
+
<SelectContent>
|
|
216
|
+
<SelectItem value="edge">
|
|
217
|
+
Edge Network (Toàn cầu)
|
|
218
|
+
</SelectItem>
|
|
219
|
+
<SelectItem value="us-east">
|
|
220
|
+
US East (Virginia)
|
|
221
|
+
</SelectItem>
|
|
222
|
+
<SelectItem value="ap-se">
|
|
223
|
+
AP South East (Sing)
|
|
224
|
+
</SelectItem>
|
|
225
|
+
</SelectContent>
|
|
226
|
+
</SelectPortal>
|
|
227
|
+
</Select>
|
|
228
|
+
</div>
|
|
229
|
+
</div>
|
|
230
|
+
|
|
231
|
+
<div className="md:col-span-2 rounded-xl border border-border/50 bg-muted/20 p-6 flex items-center justify-center relative overflow-hidden group/canvas">
|
|
232
|
+
<div className="absolute inset-0 bg-[radial-gradient(circle_at_center,rgba(var(--primary-rgb),0.1)_0,transparent_100%)] opacity-0 group-hover/canvas:opacity-100 transition-opacity duration-700" />
|
|
233
|
+
|
|
234
|
+
<div className="relative z-10 w-full max-w-md space-y-4 perspective-1000">
|
|
235
|
+
<div className="flex items-center gap-4 p-5 rounded-xl bg-background shadow-xl border border-border/50 transform group-hover/canvas:-translate-y-2 group-hover/canvas:rotate-1 transition-all duration-500 delay-75">
|
|
236
|
+
<div className="p-3 bg-primary/10 rounded-lg text-primary shadow-inner">
|
|
237
|
+
<LayersIcon className="size-6" />
|
|
238
|
+
</div>
|
|
239
|
+
<div>
|
|
240
|
+
<h4 className="font-bold text-sm">
|
|
241
|
+
Kiến trúc Micro/Macro
|
|
242
|
+
</h4>
|
|
243
|
+
<p className="text-xs text-muted-foreground font-medium mt-1">
|
|
244
|
+
Lắp ráp từ những mảnh ghép tối giản
|
|
245
|
+
</p>
|
|
246
|
+
</div>
|
|
247
|
+
</div>
|
|
248
|
+
|
|
249
|
+
<div className="flex items-center gap-4 p-5 rounded-xl bg-background shadow-xl border border-border/50 transform group-hover/canvas:translate-x-2 group-hover/canvas:-rotate-1 transition-all duration-500 delay-150">
|
|
250
|
+
<div className="p-3 bg-info/10 rounded-lg text-info shadow-inner">
|
|
251
|
+
<DatabaseIcon className="size-6" />
|
|
252
|
+
</div>
|
|
253
|
+
<div>
|
|
254
|
+
<h4 className="font-bold text-sm">Data-Driven Design</h4>
|
|
255
|
+
<p className="text-xs text-muted-foreground font-medium mt-1">
|
|
256
|
+
Dữ liệu quyết định cấu trúc UI
|
|
257
|
+
</p>
|
|
258
|
+
</div>
|
|
259
|
+
</div>
|
|
260
|
+
|
|
261
|
+
<div className="flex items-center gap-4 p-5 rounded-xl bg-background shadow-xl border border-border/50 transform group-hover/canvas:-translate-y-1 transition-all duration-500 delay-200">
|
|
262
|
+
<div className="p-3 bg-success/10 rounded-lg text-success shadow-inner">
|
|
263
|
+
<ShieldCheckIcon className="size-6" />
|
|
264
|
+
</div>
|
|
265
|
+
<div>
|
|
266
|
+
<h4 className="font-bold text-sm">Strict Styling</h4>
|
|
267
|
+
<p className="text-xs text-muted-foreground font-medium mt-1">
|
|
268
|
+
Nói không với Magic CSS
|
|
269
|
+
</p>
|
|
270
|
+
</div>
|
|
271
|
+
</div>
|
|
272
|
+
</div>
|
|
273
|
+
</div>
|
|
274
|
+
</div>
|
|
275
|
+
</div>
|
|
276
|
+
</div>
|
|
277
|
+
</section>
|
|
278
|
+
|
|
279
|
+
{/* 📈 STATS STRIP */}
|
|
280
|
+
<section className="container max-w-6xl mx-auto border-y border-y-border bg-muted/5 py-12 relative overflow-hidden">
|
|
281
|
+
<div className="absolute inset-0 bg-gradient-to-r from-transparent via-primary/5 to-transparent animate-[pulse_4s_ease-in-out_infinite]" />
|
|
282
|
+
<div className="grid grid-cols-2 md:grid-cols-4 gap-8 md:gap-4 divide-x-0 md:divide-x relative z-10">
|
|
283
|
+
{STATS.map((s) => (
|
|
284
|
+
<div
|
|
285
|
+
key={s.label}
|
|
286
|
+
className="flex flex-col items-center justify-center text-center space-y-2 group"
|
|
287
|
+
>
|
|
288
|
+
<div className="text-4xl md:text-5xl font-black tracking-tighter text-foreground group-hover:text-primary group-hover:scale-110 transition-all duration-300">
|
|
289
|
+
{s.value}
|
|
290
|
+
</div>
|
|
291
|
+
<div className="text-xs md:text-sm font-bold uppercase tracking-[0.2em] text-muted-foreground">
|
|
292
|
+
{s.label}
|
|
293
|
+
</div>
|
|
294
|
+
</div>
|
|
295
|
+
))}
|
|
296
|
+
</div>
|
|
297
|
+
</section>
|
|
298
|
+
|
|
299
|
+
{/* 🧠 BENTO BOX PHILOSOPHIES */}
|
|
300
|
+
<section className="container max-w-6xl mx-auto space-y-12 px-4">
|
|
301
|
+
<div className="text-center max-w-2xl mx-auto space-y-4">
|
|
302
|
+
<h2 className="text-3xl md:text-4xl font-extrabold tracking-tight">
|
|
303
|
+
Tường minh từ thiết kế. Bền vững theo thời gian.
|
|
304
|
+
</h2>
|
|
305
|
+
<p className="text-muted-foreground text-lg">
|
|
306
|
+
Phần lớn component library hỏng ở năm thứ hai — khi team cần thay
|
|
307
|
+
đổi nhưng không ai dám sửa vì không biết gì sẽ vỡ. gladcn được xây
|
|
308
|
+
trên{" "}
|
|
309
|
+
<strong className="text-foreground">Các nguyên tắc tường minh</strong>
|
|
310
|
+
{" "}để bạn luôn biết mình đang sửa ở tầng nào và điều gì sẽ bị ảnh
|
|
311
|
+
hưởng.
|
|
312
|
+
</p>
|
|
313
|
+
</div>
|
|
314
|
+
|
|
315
|
+
{/* FULL OWNERSHIP - FEATURED BANNER */}
|
|
316
|
+
<div
|
|
317
|
+
id="ownership-section"
|
|
318
|
+
className="mb-12 rounded-[2.5rem] border-2 border-primary/50 bg-primary/5 p-4 sm:p-6 md:p-12 flex flex-col gap-10 group overflow-hidden relative hover:bg-primary/10 transition-colors duration-500 shadow-2xl shadow-primary/10"
|
|
319
|
+
>
|
|
320
|
+
<div className="flex flex-col md:flex-row items-start gap-6 md:gap-8">
|
|
321
|
+
<div className="relative z-10 flex-1 space-y-6">
|
|
322
|
+
<div className="inline-flex items-center gap-2 px-4 py-1.5 rounded-full bg-primary text-primary-foreground text-sm font-bold uppercase tracking-wider shadow-lg shadow-primary/20">
|
|
323
|
+
<SparklesIcon className="size-4" /> Điểm khác biệt lớn nhất
|
|
324
|
+
</div>
|
|
325
|
+
<h3 className="text-3xl md:text-5xl font-extrabold tracking-tight">
|
|
326
|
+
Sở hữu 100% mã nguồn
|
|
327
|
+
</h3>
|
|
328
|
+
<p className="text-muted-foreground text-lg leading-relaxed max-w-2xl">
|
|
329
|
+
Chạy một lệnh duy nhất — toàn bộ source code (components, hooks,
|
|
330
|
+
styles, contexts) được sao chép thẳng vào thư mục{" "}
|
|
331
|
+
<code className="text-sm bg-primary/20 text-primary px-1.5 py-0.5 rounded">
|
|
332
|
+
src/
|
|
333
|
+
</code>{" "}
|
|
334
|
+
của dự án bạn.{" "}
|
|
335
|
+
<strong className="text-foreground">
|
|
336
|
+
Không cài qua node_modules, không bị vendor lock-in
|
|
337
|
+
</strong>{" "}
|
|
338
|
+
— bạn đọc được, sửa được, xoá được từng dòng code.
|
|
339
|
+
</p>
|
|
340
|
+
|
|
341
|
+
<div className="flex items-center gap-4 pt-2">
|
|
342
|
+
<button
|
|
343
|
+
onClick={handleCopy}
|
|
344
|
+
className="bg-background/80 hover:bg-background border-border backdrop-blur-md px-6 py-4 rounded-2xl border hover:border-primary/50 transition-colors font-mono text-sm shadow-inner flex items-center gap-4 cursor-pointer group/copy"
|
|
345
|
+
>
|
|
346
|
+
<span className="text-primary font-bold">~</span>
|
|
347
|
+
<span>npx gladvn init</span>
|
|
348
|
+
<div className="ml-4 text-muted-foreground group-hover/copy:text-primary transition-colors">
|
|
349
|
+
{copied ? (
|
|
350
|
+
<CheckIcon className="size-4 text-success" />
|
|
351
|
+
) : (
|
|
352
|
+
<CopyIcon className="size-4" />
|
|
353
|
+
)}
|
|
354
|
+
</div>
|
|
355
|
+
</button>
|
|
356
|
+
</div>
|
|
357
|
+
</div>
|
|
358
|
+
|
|
359
|
+
<div className="relative z-10 w-full md:w-1/3 flex flex-col gap-4">
|
|
360
|
+
<div className="p-3 sm:p-5 rounded-2xl border border-success/30 bg-success/10 shadow-sm flex items-start gap-4 transform group-hover:-translate-x-2 transition-transform">
|
|
361
|
+
<div className="bg-success text-success-foreground p-2 rounded-full mt-1">
|
|
362
|
+
<CheckIcon className="size-4" />
|
|
363
|
+
</div>
|
|
364
|
+
<div>
|
|
365
|
+
<h4 className="font-bold text-success text-lg">
|
|
366
|
+
Toàn bộ Component & Hook
|
|
367
|
+
</h4>
|
|
368
|
+
<p className="text-xs text-success/80 mt-1">
|
|
369
|
+
Nằm gọn trong{" "}
|
|
370
|
+
<code className="opacity-80">
|
|
371
|
+
src/components/micro/ & macro/
|
|
372
|
+
</code>
|
|
373
|
+
</p>
|
|
374
|
+
</div>
|
|
375
|
+
</div>
|
|
376
|
+
<div className="p-3 sm:p-5 rounded-2xl border border-success/30 bg-success/10 shadow-sm flex items-start gap-4 transform group-hover:translate-x-2 transition-transform">
|
|
377
|
+
<div className="bg-success text-success-foreground p-2 rounded-full mt-1">
|
|
378
|
+
<CheckIcon className="size-4" />
|
|
379
|
+
</div>
|
|
380
|
+
<div>
|
|
381
|
+
<h4 className="font-bold text-success text-lg">
|
|
382
|
+
CSS Token & Theme Config
|
|
383
|
+
</h4>
|
|
384
|
+
<p className="text-xs text-success/80 mt-1">
|
|
385
|
+
OKLCH color tokens, dark/light mode — đẹp ngay từ đầu
|
|
386
|
+
</p>
|
|
387
|
+
</div>
|
|
388
|
+
</div>
|
|
389
|
+
<div className="p-3 sm:p-5 rounded-2xl border border-success/30 bg-success/10 shadow-sm flex items-start gap-4 transform group-hover:-translate-x-2 transition-transform">
|
|
390
|
+
<div className="bg-success text-success-foreground p-2 rounded-full mt-1">
|
|
391
|
+
<CheckIcon className="size-4" />
|
|
392
|
+
</div>
|
|
393
|
+
<div>
|
|
394
|
+
<h4 className="font-bold text-success text-lg">
|
|
395
|
+
Tự động cài Dependency
|
|
396
|
+
</h4>
|
|
397
|
+
<p className="text-xs text-success/80 mt-1">
|
|
398
|
+
Tự nhận diện npm, yarn, pnpm, bun
|
|
399
|
+
</p>
|
|
400
|
+
</div>
|
|
401
|
+
</div>
|
|
402
|
+
</div>
|
|
403
|
+
</div>
|
|
404
|
+
|
|
405
|
+
{/* WHERE TO EDIT GUIDE */}
|
|
406
|
+
<div className="relative z-10 border-t border-primary/20 pt-8">
|
|
407
|
+
<p className="text-sm font-bold uppercase tracking-wider text-primary mb-5">
|
|
408
|
+
Tuỳ chỉnh theo từng tầng kiến trúc
|
|
409
|
+
</p>
|
|
410
|
+
<div className="grid sm:grid-cols-3 gap-4">
|
|
411
|
+
|
|
412
|
+
{/* MACRO — RECOMMENDED */}
|
|
413
|
+
<div className="p-5 rounded-2xl border-2 border-primary/40 bg-primary/5 space-y-3 relative">
|
|
414
|
+
<div className="absolute top-3 right-3 text-[10px] font-bold uppercase tracking-wider text-primary bg-primary/10 px-2 py-0.5 rounded-full">
|
|
415
|
+
Nên bắt đầu ở đây
|
|
416
|
+
</div>
|
|
417
|
+
<div className="font-mono text-xs text-primary/70">
|
|
418
|
+
src/components/macro/
|
|
419
|
+
</div>
|
|
420
|
+
<h4 className="font-bold text-foreground text-base">
|
|
421
|
+
Sửa Macro — an toàn nhất
|
|
422
|
+
</h4>
|
|
423
|
+
<p className="text-sm text-muted-foreground leading-relaxed">
|
|
424
|
+
Đây là nơi bạn nên chỉnh trước tiên. Mỗi Macro là một preset
|
|
425
|
+
độc lập — thêm footer cho DatePicker, bỏ nút đóng của Dialog,
|
|
426
|
+
điều chỉnh placeholder của Combobox.{" "}
|
|
427
|
+
<strong className="text-foreground">
|
|
428
|
+
Thay đổi chỉ ảnh hưởng đúng preset đó
|
|
429
|
+
</strong>
|
|
430
|
+
, không lan ra component nào khác.
|
|
431
|
+
</p>
|
|
432
|
+
</div>
|
|
433
|
+
|
|
434
|
+
{/* MICRO — CAUTION */}
|
|
435
|
+
<div className="p-5 rounded-2xl border border-warning/40 bg-warning/5 space-y-3 relative">
|
|
436
|
+
<div className="absolute top-3 right-3 text-[10px] font-bold uppercase tracking-wider text-warning bg-warning/10 px-2 py-0.5 rounded-full">
|
|
437
|
+
Cẩn thận
|
|
438
|
+
</div>
|
|
439
|
+
<div className="font-mono text-xs text-warning/70">
|
|
440
|
+
src/components/micro/
|
|
441
|
+
</div>
|
|
442
|
+
<h4 className="font-bold text-foreground text-base">
|
|
443
|
+
Sửa Micro — ảnh hưởng rộng
|
|
444
|
+
</h4>
|
|
445
|
+
<p className="text-sm text-muted-foreground leading-relaxed">
|
|
446
|
+
Micro là nền tảng — mọi Macro đều xây trên chúng. Sửa một
|
|
447
|
+
variant của Button hay thay animation của Tooltip sẽ{" "}
|
|
448
|
+
<strong className="text-foreground">
|
|
449
|
+
tác động đồng loạt đến toàn bộ nơi dùng component đó
|
|
450
|
+
</strong>{" "}
|
|
451
|
+
trong ứng dụng. Chỉ chỉnh khi bạn rõ mình đang làm gì.
|
|
452
|
+
</p>
|
|
453
|
+
</div>
|
|
454
|
+
|
|
455
|
+
{/* CSS — HIGHEST IMPACT */}
|
|
456
|
+
<div className="p-5 rounded-2xl border border-destructive/30 bg-destructive/5 space-y-3 relative">
|
|
457
|
+
<div className="absolute top-3 right-3 text-[10px] font-bold uppercase tracking-wider text-destructive bg-destructive/10 px-2 py-0.5 rounded-full">
|
|
458
|
+
Ảnh hưởng toàn cục
|
|
459
|
+
</div>
|
|
460
|
+
<div className="font-mono text-xs text-destructive/60">
|
|
461
|
+
src/index.css
|
|
462
|
+
</div>
|
|
463
|
+
<h4 className="font-bold text-foreground text-base">
|
|
464
|
+
Sửa CSS — chạm toàn bộ hệ thống
|
|
465
|
+
</h4>
|
|
466
|
+
<p className="text-sm text-muted-foreground leading-relaxed">
|
|
467
|
+
CSS token là ngôn ngữ chung của mọi component — màu sắc,
|
|
468
|
+
typography, border-radius. Thay đổi một token ở đây{" "}
|
|
469
|
+
<strong className="text-foreground">
|
|
470
|
+
tức thời cập nhật toàn bộ giao diện
|
|
471
|
+
</strong>
|
|
472
|
+
, từ Button đến Dialog. Dùng khi bạn muốn rebrand hoặc thay
|
|
473
|
+
đổi design language, không phải để vá từng chỗ.
|
|
474
|
+
</p>
|
|
475
|
+
</div>
|
|
476
|
+
|
|
477
|
+
</div>
|
|
478
|
+
</div>
|
|
479
|
+
</div>
|
|
480
|
+
|
|
481
|
+
<div className="columns-1 md:columns-2 gap-6">
|
|
482
|
+
{/* Micro/Macro (Spans 2 columns) */}
|
|
483
|
+
<div className="break-inside-avoid mb-6 rounded-[2rem] border border-border bg-card/20 p-4 md:p-10 flex flex-col justify-between group overflow-hidden relative hover:bg-card/40 transition-colors duration-500">
|
|
484
|
+
<div className="absolute -top-10 -right-10 p-8 opacity-5 group-hover:opacity-10 transition-all pointer-events-none transform group-hover:scale-110 group-hover:-rotate-12 duration-700">
|
|
485
|
+
<BlocksIcon className="w-80 h-80" />
|
|
486
|
+
</div>
|
|
487
|
+
<div className="relative z-10 space-y-4 mb-10">
|
|
488
|
+
<h3 className="text-2xl md:text-4xl font-extrabold tracking-tight">
|
|
489
|
+
Micro & Macro Architecture
|
|
490
|
+
</h3>
|
|
491
|
+
<p className="text-muted-foreground max-w-lg text-lg leading-relaxed">
|
|
492
|
+
Tách biệt rõ ràng Core components linh hoạt (Micro) và các
|
|
493
|
+
pattern tiện dụng (Macro).
|
|
494
|
+
<strong className="text-foreground">
|
|
495
|
+
Micro tuyệt đối không áp đặt layout phức tạp (Opinionated).
|
|
496
|
+
Mọi logic lắp ráp giao diện đều phải uỷ quyền (Delegate) hoàn
|
|
497
|
+
toàn cho Macro.
|
|
498
|
+
</strong>
|
|
499
|
+
</p>
|
|
500
|
+
</div>
|
|
501
|
+
<div className="relative z-10 mt-auto pt-6 space-y-3">
|
|
502
|
+
<CodeBlock type="success" title="Uỷ quyền cho Macro (Preset):">
|
|
503
|
+
<span className="text-success/80">
|
|
504
|
+
{
|
|
505
|
+
"/* Macro thấy toàn bộ cấu trúc nên gắn class thẳng vào đích */"
|
|
506
|
+
}
|
|
507
|
+
</span>
|
|
508
|
+
<br />
|
|
509
|
+
<span className="text-foreground">{"<AlertDialogFooter>"}</span>
|
|
510
|
+
<br />
|
|
511
|
+
<span className="pl-4">
|
|
512
|
+
{'<Button variant="ghost">Trợ giúp</Button>'}
|
|
513
|
+
</span>
|
|
514
|
+
<br />
|
|
515
|
+
<span className="pl-4 text-success font-bold">
|
|
516
|
+
{'<Button className="ml-auto">Xác nhận</Button>'}
|
|
517
|
+
</span>
|
|
518
|
+
<br />
|
|
519
|
+
<span className="text-foreground">
|
|
520
|
+
{"</AlertDialogFooter>"}
|
|
521
|
+
</span>
|
|
522
|
+
</CodeBlock>
|
|
523
|
+
|
|
524
|
+
<CodeBlock
|
|
525
|
+
type="destructive"
|
|
526
|
+
title="Ép Layout ở Micro (Primitive):"
|
|
527
|
+
>
|
|
528
|
+
<span className="text-destructive/80">
|
|
529
|
+
{
|
|
530
|
+
"/* Micro mù mờ về thẻ con nên phải dùng Magic CSS đoán mò */"
|
|
531
|
+
}
|
|
532
|
+
</span>
|
|
533
|
+
<br />
|
|
534
|
+
<span className="text-foreground">{"<AlertDialogFooter"}</span>
|
|
535
|
+
<br />
|
|
536
|
+
<span className="pl-4 text-destructive font-bold line-through">
|
|
537
|
+
{'className="[&>*:last-child]:ml-auto"'}
|
|
538
|
+
</span>
|
|
539
|
+
<br />
|
|
540
|
+
<span className="text-foreground">{">"}</span>
|
|
541
|
+
<br />
|
|
542
|
+
<span className="pl-4">{"{children}"}</span>
|
|
543
|
+
<br />
|
|
544
|
+
<span className="text-foreground">
|
|
545
|
+
{"</AlertDialogFooter>"}
|
|
546
|
+
</span>
|
|
547
|
+
</CodeBlock>
|
|
548
|
+
</div>
|
|
549
|
+
</div>
|
|
550
|
+
|
|
551
|
+
{/* Style Encapsulation */}
|
|
552
|
+
<div className="break-inside-avoid mb-6 rounded-[2rem] border border-border bg-card/20 p-4 md:p-10 flex flex-col group overflow-hidden relative hover:bg-card/40 transition-colors duration-500">
|
|
553
|
+
<div className="absolute top-0 right-0 p-8 opacity-5 group-hover:opacity-10 transition-all pointer-events-none transform group-hover:scale-110 group-hover:rotate-12 duration-700">
|
|
554
|
+
<ShieldCheckIcon className="w-56 h-56" />
|
|
555
|
+
</div>
|
|
556
|
+
<div className="relative z-10 space-y-4">
|
|
557
|
+
<h3 className="text-2xl font-extrabold tracking-tight">
|
|
558
|
+
Style Encapsulation
|
|
559
|
+
</h3>
|
|
560
|
+
<p className="text-muted-foreground text-base leading-relaxed">
|
|
561
|
+
Mỗi component là một hộp đen styling. Consumer chỉ tác động
|
|
562
|
+
vào bên trong qua{" "}
|
|
563
|
+
<code>data-slot</code> — contract đã được khai báo chính thức
|
|
564
|
+
trong API.{" "}
|
|
565
|
+
<strong className="text-foreground">
|
|
566
|
+
Refactor nội tại không bao giờ phá vỡ code của người dùng.
|
|
567
|
+
</strong>
|
|
568
|
+
</p>
|
|
569
|
+
</div>
|
|
570
|
+
<div className="relative z-10 mt-auto pt-6 space-y-3">
|
|
571
|
+
<div className="p-3 rounded-xl border border-destructive/20 bg-destructive/5 text-xs font-mono shadow-sm flex items-center">
|
|
572
|
+
<span className="text-destructive font-bold mr-3 text-lg">❌</span>
|
|
573
|
+
<span className="opacity-80 line-through">{"[&>div>span]:color"}</span>
|
|
574
|
+
</div>
|
|
575
|
+
<div className="p-3 rounded-xl border border-success/20 bg-success/5 text-xs font-mono shadow-sm flex items-center">
|
|
576
|
+
<span className="text-success font-bold mr-3 text-lg">✅</span>
|
|
577
|
+
<span className="text-foreground font-medium">data-[slot=icon]:color</span>
|
|
578
|
+
</div>
|
|
579
|
+
</div>
|
|
580
|
+
</div>
|
|
581
|
+
|
|
582
|
+
{/* Orthogonal Styling (Spans 2 columns) */}
|
|
583
|
+
<div className="break-inside-avoid mb-6 rounded-[2rem] border border-border bg-card/20 p-4 md:p-10 flex flex-col group overflow-hidden relative hover:bg-card/40 transition-colors duration-500">
|
|
584
|
+
<div className="absolute top-0 right-0 p-8 opacity-5 group-hover:opacity-10 transition-all pointer-events-none transform group-hover:scale-110 group-hover:-rotate-12 duration-700">
|
|
585
|
+
<SlidersHorizontalIcon className="w-80 h-80" />
|
|
586
|
+
</div>
|
|
587
|
+
<div className="relative z-10 space-y-4">
|
|
588
|
+
<h3 className="text-2xl md:text-4xl font-extrabold tracking-tight">
|
|
589
|
+
Orthogonal Styling
|
|
590
|
+
</h3>
|
|
591
|
+
<p className="text-muted-foreground text-lg leading-relaxed max-w-lg">
|
|
592
|
+
Tách biệt rõ ràng trục cấu trúc (Variant) và trục màu sắc
|
|
593
|
+
(Color) thành các style độc lập, giúp tránh bùng nổ tổ hợp CSS
|
|
594
|
+
class.
|
|
595
|
+
</p>
|
|
596
|
+
</div>
|
|
597
|
+
<div className="relative z-10 mt-auto pt-8 grid sm:grid-cols-2 gap-4">
|
|
598
|
+
<div className="p-3 sm:p-5 rounded-2xl border border-border bg-background/60 backdrop-blur-md shadow-sm hover:shadow-md transition-shadow">
|
|
599
|
+
<strong className="block text-foreground text-base mb-2 flex items-center gap-2">
|
|
600
|
+
<BoxIcon className="size-4 text-muted-foreground" /> Trục
|
|
601
|
+
Variant
|
|
602
|
+
</strong>
|
|
603
|
+
<span className="text-sm text-muted-foreground leading-relaxed">
|
|
604
|
+
solid, outline, ghost, soft. Quyết định viền, nền, độ trong
|
|
605
|
+
suốt.
|
|
606
|
+
</span>
|
|
607
|
+
</div>
|
|
608
|
+
<div className="p-3 sm:p-5 rounded-2xl border border-border bg-background/60 backdrop-blur-md shadow-sm hover:shadow-md transition-shadow">
|
|
609
|
+
<strong className="block text-foreground text-base mb-2 flex items-center gap-2">
|
|
610
|
+
<PaintbrushIcon className="size-4 text-muted-foreground" />{" "}
|
|
611
|
+
Trục Color
|
|
612
|
+
</strong>
|
|
613
|
+
<span className="text-sm text-muted-foreground leading-relaxed">
|
|
614
|
+
primary, secondary, destructive. Quyết định dải màu sắc (hue).
|
|
615
|
+
</span>
|
|
616
|
+
</div>
|
|
617
|
+
</div>
|
|
618
|
+
</div>
|
|
619
|
+
|
|
620
|
+
{/* Zero-Prop Defaults */}
|
|
621
|
+
<div className="break-inside-avoid mb-6 rounded-[2rem] border border-border bg-card/20 p-4 md:p-10 flex flex-col group overflow-hidden relative hover:bg-card/40 transition-colors duration-500">
|
|
622
|
+
<div className="absolute top-0 right-0 p-8 opacity-5 group-hover:opacity-10 transition-all pointer-events-none transform group-hover:scale-110 group-hover:-rotate-12 duration-700">
|
|
623
|
+
<ComponentIcon className="w-80 h-80" />
|
|
624
|
+
</div>
|
|
625
|
+
<div className="relative z-10 space-y-4">
|
|
626
|
+
<h3 className="text-2xl md:text-4xl font-extrabold tracking-tight">
|
|
627
|
+
Zero-prop Defaults
|
|
628
|
+
</h3>
|
|
629
|
+
<p className="text-muted-foreground text-lg leading-relaxed max-w-lg">
|
|
630
|
+
Component phải hoạt động mượt mà và render đúng UI chuẩn kể cả
|
|
631
|
+
khi dev không truyền bất kỳ prop nào vào.{" "}
|
|
632
|
+
<strong className="text-foreground">
|
|
633
|
+
Nếu không, mỗi lần dùng là một lần tra tài liệu.
|
|
634
|
+
</strong>
|
|
635
|
+
</p>
|
|
636
|
+
</div>
|
|
637
|
+
<div className="relative z-10 mt-auto pt-8 flex flex-col gap-4">
|
|
638
|
+
<div className="flex items-center justify-between gap-4 p-4 rounded-xl border border-success/20 bg-success/5 shadow-sm">
|
|
639
|
+
<Button>Click Me</Button>
|
|
640
|
+
<span className="text-[11px] sm:text-xs font-mono text-success font-medium">
|
|
641
|
+
{"<Button>Click Me</Button>"}
|
|
642
|
+
</span>
|
|
643
|
+
</div>
|
|
644
|
+
<div className="flex items-center justify-between gap-4 p-4 rounded-xl border border-destructive/20 bg-destructive/5 shadow-sm opacity-60">
|
|
645
|
+
<Button size="md" color="primary">
|
|
646
|
+
Click Me
|
|
647
|
+
</Button>
|
|
648
|
+
<span className="text-[11px] sm:text-xs font-mono text-destructive font-medium line-through">
|
|
649
|
+
{'<Button size="md" color="primary">...'}
|
|
650
|
+
</span>
|
|
651
|
+
</div>
|
|
652
|
+
</div>
|
|
653
|
+
</div>
|
|
654
|
+
|
|
655
|
+
{/* Headless Behavior Layer */}
|
|
656
|
+
<div className="break-inside-avoid mb-6 rounded-[2rem] border border-border bg-card/20 p-4 md:p-10 flex flex-col group overflow-hidden relative hover:bg-card/40 transition-colors duration-500">
|
|
657
|
+
<div className="absolute top-0 right-0 p-8 opacity-5 group-hover:opacity-10 transition-all pointer-events-none transform group-hover:scale-110 group-hover:rotate-12 duration-700">
|
|
658
|
+
<LayersIcon className="w-56 h-56" />
|
|
659
|
+
</div>
|
|
660
|
+
<div className="relative z-10 space-y-4">
|
|
661
|
+
<h3 className="text-2xl font-extrabold tracking-tight">
|
|
662
|
+
Headless Behavior Layer
|
|
663
|
+
</h3>
|
|
664
|
+
<p className="text-muted-foreground text-base leading-relaxed">
|
|
665
|
+
Keyboard navigation, focus management, ARIA state — tất cả được
|
|
666
|
+
tách sang lớp Headless UI (Base UI). Micro component chỉ wrap
|
|
667
|
+
và thêm visual style, không tự implement logic tương tác.{" "}
|
|
668
|
+
<strong className="text-foreground">
|
|
669
|
+
Behavior đúng mặc định, không cần test lại từng lần.
|
|
670
|
+
</strong>
|
|
671
|
+
</p>
|
|
672
|
+
</div>
|
|
673
|
+
<div className="relative z-10 mt-auto pt-8">
|
|
674
|
+
<div className="p-4 rounded-xl bg-foreground/5 border border-border/50 text-[11px] sm:text-xs font-mono shadow-inner space-y-1">
|
|
675
|
+
<div className="text-muted-foreground">// Micro = Headless + Style</div>
|
|
676
|
+
<div>
|
|
677
|
+
<span className="text-primary">{'<Base UI Select>'}</span>
|
|
678
|
+
<span className="text-muted-foreground"> ← behavior</span>
|
|
679
|
+
</div>
|
|
680
|
+
<div className="pl-4">
|
|
681
|
+
<span className="text-success">{'<SelectTrigger>'}</span>
|
|
682
|
+
<span className="text-muted-foreground"> ← style only</span>
|
|
683
|
+
</div>
|
|
684
|
+
</div>
|
|
685
|
+
</div>
|
|
686
|
+
</div>
|
|
687
|
+
{/* CSS Token Architecture */}
|
|
688
|
+
<div className="break-inside-avoid mb-6 rounded-[2rem] border border-border bg-card/20 p-4 md:p-10 flex flex-col group overflow-hidden relative hover:bg-card/40 transition-colors duration-500">
|
|
689
|
+
<div className="absolute top-0 right-0 p-8 opacity-5 group-hover:opacity-10 transition-all pointer-events-none transform group-hover:scale-110 group-hover:rotate-12 duration-700">
|
|
690
|
+
<PaletteIcon className="w-56 h-56" />
|
|
691
|
+
</div>
|
|
692
|
+
<div className="relative z-10 space-y-4">
|
|
693
|
+
<h3 className="text-2xl md:text-4xl font-extrabold tracking-tight">
|
|
694
|
+
CSS Token Architecture
|
|
695
|
+
</h3>
|
|
696
|
+
<p className="text-muted-foreground text-lg leading-relaxed max-w-lg">
|
|
697
|
+
Không component nào được hardcode màu sắc, spacing hay
|
|
698
|
+
border-radius trực tiếp. Tất cả tham chiếu CSS custom property
|
|
699
|
+
từ hệ thống token.{" "}
|
|
700
|
+
<strong className="text-foreground">
|
|
701
|
+
Thay đổi một token — toàn hệ thống cập nhật tức thì.
|
|
702
|
+
</strong>
|
|
703
|
+
</p>
|
|
704
|
+
</div>
|
|
705
|
+
<div className="relative z-10 mt-auto pt-8 grid sm:grid-cols-2 gap-4">
|
|
706
|
+
<div className="p-4 rounded-xl border border-success/20 bg-success/5 shadow-sm">
|
|
707
|
+
<div className="text-success font-semibold mb-2 text-sm">✅ Token</div>
|
|
708
|
+
<div className="text-[11px] font-mono text-success/80">
|
|
709
|
+
oklch(var(--primary))
|
|
710
|
+
</div>
|
|
711
|
+
</div>
|
|
712
|
+
<div className="p-4 rounded-xl border border-destructive/20 bg-destructive/5 shadow-sm opacity-60">
|
|
713
|
+
<div className="text-destructive font-semibold mb-2 text-sm">❌ Hardcode</div>
|
|
714
|
+
<div className="text-[11px] font-mono text-destructive/80 line-through">
|
|
715
|
+
#2563eb
|
|
716
|
+
</div>
|
|
717
|
+
</div>
|
|
718
|
+
</div>
|
|
719
|
+
</div>
|
|
720
|
+
|
|
721
|
+
{/* Strict Polymorphism */}
|
|
722
|
+
<div className="break-inside-avoid mb-6 rounded-[2rem] border border-border bg-card/20 p-4 md:p-10 flex flex-col group overflow-hidden relative hover:bg-card/40 transition-colors duration-500">
|
|
723
|
+
<div className="absolute top-0 right-0 p-8 opacity-5 group-hover:opacity-10 transition-all pointer-events-none transform group-hover:scale-110 group-hover:rotate-12 duration-700">
|
|
724
|
+
<CopyIcon className="w-56 h-56" />
|
|
725
|
+
</div>
|
|
726
|
+
<div className="relative z-10 space-y-4">
|
|
727
|
+
<h3 className="text-2xl font-extrabold tracking-tight">
|
|
728
|
+
Strict Polymorphism
|
|
729
|
+
</h3>
|
|
730
|
+
<p className="text-muted-foreground text-base leading-relaxed">
|
|
731
|
+
Dùng pattern <code>asChild</code> hoặc <code>render</code> prop
|
|
732
|
+
để thay đổi thẻ HTML root, không đẻ bừa các prop lồng nhau.
|
|
733
|
+
</p>
|
|
734
|
+
</div>
|
|
735
|
+
<div className="relative z-10 mt-auto pt-6 space-y-3">
|
|
736
|
+
<div className="p-3 rounded-xl border border-success/20 bg-success/5 text-[11px] font-mono shadow-sm flex items-center">
|
|
737
|
+
<span className="text-success font-bold mr-3 text-lg">✅</span>
|
|
738
|
+
<span className="text-success/90">
|
|
739
|
+
<Button render={<Link/>}>
|
|
740
|
+
</span>
|
|
741
|
+
</div>
|
|
742
|
+
<div className="p-3 rounded-xl border border-destructive/20 bg-destructive/5 text-[11px] font-mono shadow-sm flex items-center opacity-70">
|
|
743
|
+
<span className="text-destructive font-bold mr-3 text-lg">
|
|
744
|
+
❌
|
|
745
|
+
</span>
|
|
746
|
+
<span className="text-destructive/80 line-through">
|
|
747
|
+
<Button as="a" href="/">
|
|
748
|
+
</span>
|
|
749
|
+
</div>
|
|
750
|
+
</div>
|
|
751
|
+
</div>
|
|
752
|
+
|
|
753
|
+
{/* Dumb Primitives */}
|
|
754
|
+
<div className="break-inside-avoid mb-6 rounded-[2rem] border border-border bg-card/20 p-4 md:p-10 flex flex-col group overflow-hidden relative hover:bg-card/40 transition-colors duration-500">
|
|
755
|
+
<div className="absolute top-0 right-0 p-8 opacity-5 group-hover:opacity-10 transition-all pointer-events-none transform group-hover:scale-110 group-hover:rotate-12 duration-700">
|
|
756
|
+
<BoxIcon className="w-56 h-56" />
|
|
757
|
+
</div>
|
|
758
|
+
<div className="relative z-10 space-y-4">
|
|
759
|
+
<h3 className="text-2xl font-extrabold tracking-tight">
|
|
760
|
+
Dumb Primitives
|
|
761
|
+
</h3>
|
|
762
|
+
<p className="text-muted-foreground text-base leading-relaxed">
|
|
763
|
+
Micro component không được chứa{" "}
|
|
764
|
+
<code>useState</code> hay <code>useEffect</code>. Chúng hoàn
|
|
765
|
+
toàn stateless — mọi state đều thuộc về Headless UI hoặc Macro
|
|
766
|
+
preset.{" "}
|
|
767
|
+
<strong className="text-foreground">
|
|
768
|
+
Primitive càng "ngu" càng dễ test và dễ tin tưởng.
|
|
769
|
+
</strong>
|
|
770
|
+
</p>
|
|
771
|
+
</div>
|
|
772
|
+
<div className="relative z-10 mt-auto pt-6 space-y-3">
|
|
773
|
+
<div className="p-3 rounded-xl border border-success/20 bg-success/5 text-[11px] font-mono shadow-sm flex items-center">
|
|
774
|
+
<span className="text-success font-bold mr-3 text-lg">✅</span>
|
|
775
|
+
<span className="text-success/90">{"function Button({ ...props })"}</span>
|
|
776
|
+
</div>
|
|
777
|
+
<div className="p-3 rounded-xl border border-destructive/20 bg-destructive/5 text-[11px] font-mono shadow-sm flex items-center opacity-70">
|
|
778
|
+
<span className="text-destructive font-bold mr-3 text-lg">❌</span>
|
|
779
|
+
<span className="text-destructive/80 line-through">
|
|
780
|
+
{"const [open, setOpen] = useState()"}
|
|
781
|
+
</span>
|
|
782
|
+
</div>
|
|
783
|
+
</div>
|
|
784
|
+
</div>
|
|
785
|
+
|
|
786
|
+
{/* Accessibility First */}
|
|
787
|
+
<div className="break-inside-avoid mb-6 rounded-[2rem] border border-border bg-card/20 p-4 md:p-10 flex flex-col group overflow-hidden relative hover:bg-card/40 transition-colors duration-500">
|
|
788
|
+
<div className="absolute top-0 right-0 p-8 opacity-5 group-hover:opacity-10 transition-all pointer-events-none transform group-hover:scale-110 group-hover:rotate-12 duration-700">
|
|
789
|
+
<AccessibilityIcon className="w-56 h-56" />
|
|
790
|
+
</div>
|
|
791
|
+
<div className="relative z-10 space-y-4">
|
|
792
|
+
<h3 className="text-2xl font-extrabold tracking-tight">
|
|
793
|
+
Accessibility First
|
|
794
|
+
</h3>
|
|
795
|
+
<p className="text-muted-foreground text-base leading-relaxed">
|
|
796
|
+
Ưu tiên HTML semantic, liên kết form qua{" "}
|
|
797
|
+
<code>aria-describedby</code>, ẩn icon trang trí bằng{" "}
|
|
798
|
+
<code>aria-hidden</code> để đảm bảo WCAG AAA/AA.{" "}
|
|
799
|
+
<strong className="text-foreground">
|
|
800
|
+
Accessibility là thứ không ai để ý — cho đến khi bị audit.
|
|
801
|
+
</strong>
|
|
802
|
+
</p>
|
|
803
|
+
</div>
|
|
804
|
+
<div className="relative z-10 mt-auto pt-6 space-y-3">
|
|
805
|
+
<div className="p-3 rounded-xl border border-success/20 bg-success/5 text-[11px] font-mono shadow-sm flex items-center">
|
|
806
|
+
<span className="text-success font-bold mr-3 text-lg">✅</span>
|
|
807
|
+
<span className="text-success/90">
|
|
808
|
+
<svg aria-hidden="true" />
|
|
809
|
+
</span>
|
|
810
|
+
</div>
|
|
811
|
+
<div className="p-3 rounded-xl border border-destructive/20 bg-destructive/5 text-[11px] font-mono shadow-sm flex items-center opacity-70">
|
|
812
|
+
<span className="text-destructive font-bold mr-3 text-lg">
|
|
813
|
+
❌
|
|
814
|
+
</span>
|
|
815
|
+
<span className="text-destructive/80 line-through">
|
|
816
|
+
<div role="button">
|
|
817
|
+
</span>
|
|
818
|
+
</div>
|
|
819
|
+
</div>
|
|
820
|
+
</div>
|
|
821
|
+
|
|
822
|
+
{/* Explicit State Contract */}
|
|
823
|
+
<div className="break-inside-avoid mb-6 rounded-[2rem] border border-border bg-card/20 p-4 md:p-10 flex flex-col group overflow-hidden relative hover:bg-card/40 transition-colors duration-500">
|
|
824
|
+
<div className="absolute top-0 right-0 p-8 opacity-5 group-hover:opacity-10 transition-all pointer-events-none transform group-hover:scale-110 group-hover:rotate-12 duration-700">
|
|
825
|
+
<DatabaseIcon className="w-56 h-56" />
|
|
826
|
+
</div>
|
|
827
|
+
<div className="relative z-10 space-y-4">
|
|
828
|
+
<h3 className="text-2xl font-extrabold tracking-tight">
|
|
829
|
+
Explicit State Contract
|
|
830
|
+
</h3>
|
|
831
|
+
<p className="text-muted-foreground text-base leading-relaxed">
|
|
832
|
+
Component expose trạng thái ra ngoài qua{" "}
|
|
833
|
+
<code>data-attributes</code>, không phải qua imperative ref
|
|
834
|
+
methods. Consumer CSS và animation target chính xác từng
|
|
835
|
+
trạng thái mà không cần JavaScript.{" "}
|
|
836
|
+
<strong className="text-foreground">
|
|
837
|
+
State là public API — phải tường minh và ổn định.
|
|
838
|
+
</strong>
|
|
839
|
+
</p>
|
|
840
|
+
</div>
|
|
841
|
+
<div className="relative z-10 mt-auto pt-8">
|
|
842
|
+
<div className="p-4 rounded-xl bg-foreground/5 border border-border/50 text-[11px] sm:text-xs font-mono shadow-inner space-y-2">
|
|
843
|
+
<div>
|
|
844
|
+
<span className="text-success">data-[state=open]</span>
|
|
845
|
+
<span className="text-muted-foreground">:rotate-180</span>
|
|
846
|
+
</div>
|
|
847
|
+
<div>
|
|
848
|
+
<span className="text-success">data-disabled</span>
|
|
849
|
+
<span className="text-muted-foreground">:opacity-50</span>
|
|
850
|
+
</div>
|
|
851
|
+
<div className="pt-1 border-t border-border/30">
|
|
852
|
+
<span className="text-destructive/60 line-through">ref.current.isOpen</span>
|
|
853
|
+
</div>
|
|
854
|
+
</div>
|
|
855
|
+
</div>
|
|
856
|
+
</div>
|
|
857
|
+
|
|
858
|
+
{/* 3-Layer Source Ownership */}
|
|
859
|
+
<div className="break-inside-avoid mb-6 rounded-[2rem] border border-border bg-card/20 p-4 md:p-10 flex flex-col group overflow-hidden relative hover:bg-card/40 transition-colors duration-500">
|
|
860
|
+
<div className="absolute top-0 right-0 p-8 opacity-5 group-hover:opacity-10 transition-all pointer-events-none transform group-hover:scale-110 group-hover:rotate-12 duration-700">
|
|
861
|
+
<SlidersHorizontalIcon className="w-56 h-56" />
|
|
862
|
+
</div>
|
|
863
|
+
<div className="relative z-10 space-y-4">
|
|
864
|
+
<h3 className="text-2xl font-extrabold tracking-tight">
|
|
865
|
+
3-Layer Source Ownership
|
|
866
|
+
</h3>
|
|
867
|
+
<p className="text-muted-foreground text-base leading-relaxed">
|
|
868
|
+
Source được phân tầng: <code>micro/</code> (primitive không
|
|
869
|
+
có layout cứng nhắc), <code>macro/</code> (preset lắp ráp có
|
|
870
|
+
chủ đích), <code>index.css</code> (token toàn hệ thống).{" "}
|
|
871
|
+
<strong className="text-foreground">
|
|
872
|
+
Sửa ở tầng nào chỉ ảnh hưởng đến tầng đó.
|
|
873
|
+
</strong>
|
|
874
|
+
</p>
|
|
875
|
+
</div>
|
|
876
|
+
<div className="relative z-10 mt-auto pt-6 space-y-2">
|
|
877
|
+
<div className="p-3 rounded-xl border border-border bg-background/60 text-[11px] font-mono flex items-center gap-3">
|
|
878
|
+
<span className="text-destructive font-bold">CSS</span>
|
|
879
|
+
<span className="text-muted-foreground">index.css — token toàn cục</span>
|
|
880
|
+
</div>
|
|
881
|
+
<div className="p-3 rounded-xl border border-border bg-background/60 text-[11px] font-mono flex items-center gap-3">
|
|
882
|
+
<span className="text-warning font-bold">Macro</span>
|
|
883
|
+
<span className="text-muted-foreground">macro/ — preset lắp ráp</span>
|
|
884
|
+
</div>
|
|
885
|
+
<div className="p-3 rounded-xl border border-border bg-background/60 text-[11px] font-mono flex items-center gap-3">
|
|
886
|
+
<span className="text-success font-bold">Micro</span>
|
|
887
|
+
<span className="text-muted-foreground">micro/ — primitive thuần</span>
|
|
888
|
+
</div>
|
|
889
|
+
</div>
|
|
890
|
+
</div>
|
|
891
|
+
|
|
892
|
+
{/* Pure Composition */}
|
|
893
|
+
<div className="break-inside-avoid mb-6 rounded-[2rem] border border-border bg-card/20 p-4 md:p-10 flex flex-col group overflow-hidden relative hover:bg-card/40 transition-colors duration-500">
|
|
894
|
+
<div className="absolute top-0 right-0 p-8 opacity-5 group-hover:opacity-10 transition-all pointer-events-none transform group-hover:scale-110 group-hover:rotate-12 duration-700">
|
|
895
|
+
<BlocksIcon className="w-56 h-56" />
|
|
896
|
+
</div>
|
|
897
|
+
<div className="relative z-10 space-y-4">
|
|
898
|
+
<h3 className="text-2xl font-extrabold tracking-tight">
|
|
899
|
+
Pure Composition
|
|
900
|
+
</h3>
|
|
901
|
+
<p className="text-muted-foreground text-base leading-relaxed">
|
|
902
|
+
Design component theo dạng lắp ghép (ví dụ: Root, Trigger,
|
|
903
|
+
Content) thay vì ôm đồm nhận vào một mảng data rồi tự{" "}
|
|
904
|
+
<code>map()</code> bên trong.
|
|
905
|
+
</p>
|
|
906
|
+
</div>
|
|
907
|
+
<div className="relative z-10 mt-auto pt-6 space-y-3">
|
|
908
|
+
<div className="p-3 rounded-xl border border-success/20 bg-success/5 text-[11px] font-mono shadow-sm flex items-center">
|
|
909
|
+
<span className="text-success font-bold mr-3 text-lg">✅</span>
|
|
910
|
+
<span className="text-success/90">
|
|
911
|
+
<Select>
|
|
912
|
+
<br />
|
|
913
|
+
<SelectTrigger/>
|
|
914
|
+
<br />
|
|
915
|
+
<SelectContent/>
|
|
916
|
+
<br />
|
|
917
|
+
</Select>
|
|
918
|
+
</span>
|
|
919
|
+
</div>
|
|
920
|
+
<div className="p-3 rounded-xl border border-destructive/20 bg-destructive/5 text-[11px] font-mono shadow-sm flex items-center opacity-70">
|
|
921
|
+
<span className="text-destructive font-bold mr-3 text-lg">
|
|
922
|
+
❌
|
|
923
|
+
</span>
|
|
924
|
+
<span className="text-destructive/80 line-through">
|
|
925
|
+
<Select items={[...]} />
|
|
926
|
+
</span>
|
|
927
|
+
</div>
|
|
928
|
+
</div>
|
|
929
|
+
</div>
|
|
930
|
+
</div>
|
|
931
|
+
</section>
|
|
932
|
+
|
|
933
|
+
{/* ✨ KILLER FEATURE: SCOPED THEME TUNNEL */}
|
|
934
|
+
<section className="container max-w-6xl mx-auto px-4 mb-16">
|
|
935
|
+
<div className="rounded-[2.5rem] border border-warning/30 bg-warning/5 p-10 md:p-16 shadow-xl relative overflow-hidden group">
|
|
936
|
+
<div className="absolute -top-10 -right-10 p-8 opacity-10 pointer-events-none group-hover:rotate-12 group-hover:scale-125 transition-all duration-1000 text-warning">
|
|
937
|
+
<SparklesIcon className="size-64 md:size-[400px]" />
|
|
938
|
+
</div>
|
|
939
|
+
|
|
940
|
+
<div className="relative z-10 max-w-3xl mb-14 space-y-5">
|
|
941
|
+
<h3 className="text-3xl md:text-5xl font-extrabold tracking-tight text-warning">
|
|
942
|
+
Scoped Theme Tunnel
|
|
943
|
+
</h3>
|
|
944
|
+
<p className="text-muted-foreground text-xl leading-relaxed">
|
|
945
|
+
Tưởng tượng: app đang chạy Light Mode nhưng bạn cần một vùng nền
|
|
946
|
+
tối nổi bật — hero section, dark sidebar, CTA banner. Bọc vùng đó
|
|
947
|
+
trong{" "}
|
|
948
|
+
<code className="text-sm bg-warning/20 text-warning px-1.5 py-0.5 rounded">
|
|
949
|
+
{"<ThemeProvider defaultMode=\"dark\">"}
|
|
950
|
+
</code>{" "}
|
|
951
|
+
là đủ để mọi component con hiểu ngữ cảnh đang là Dark và tự điều
|
|
952
|
+
chỉnh màu sắc.
|
|
953
|
+
</p>
|
|
954
|
+
<p className="text-muted-foreground text-xl leading-relaxed">
|
|
955
|
+
<strong className="text-foreground">
|
|
956
|
+
Nhưng có một bẫy ẩn:
|
|
957
|
+
</strong>{" "}
|
|
958
|
+
khi người dùng mở Tooltip hoặc Dialog từ bên trong vùng tối đó,
|
|
959
|
+
component này render ra{" "}
|
|
960
|
+
<code className="text-sm bg-warning/20 text-warning px-1.5 py-0.5 rounded">
|
|
961
|
+
document.body
|
|
962
|
+
</code>{" "}
|
|
963
|
+
qua React Portal — thoát hoàn toàn khỏi DOM tree. CSS variable
|
|
964
|
+
dark mode mất theo. Tooltip hiện ra{" "}
|
|
965
|
+
<strong className="text-foreground">trắng lạc quẻ</strong> giữa
|
|
966
|
+
nền đen. Đây là điểm mà hầu hết thư viện bỏ cuộc.
|
|
967
|
+
</p>
|
|
968
|
+
<p className="text-muted-foreground text-xl leading-relaxed">
|
|
969
|
+
gladcn giải quyết bằng{" "}
|
|
970
|
+
<code className="text-sm bg-warning/20 text-warning px-1.5 py-0.5 rounded">
|
|
971
|
+
{"<ThemeWrapper>"}
|
|
972
|
+
</code>{" "}
|
|
973
|
+
— một lớp được đặt{" "}
|
|
974
|
+
<strong className="text-foreground">ngay bên trong Portal</strong>{" "}
|
|
975
|
+
để đọc theme context từ trước khi vượt qua ranh giới Portal và
|
|
976
|
+
tái-inject nó vào phía bên kia.{" "}
|
|
977
|
+
<strong className="text-foreground">
|
|
978
|
+
Theme không bị chặn lại ở ranh giới — nó được đào hầm xuyên
|
|
979
|
+
qua.
|
|
980
|
+
</strong>{" "}
|
|
981
|
+
Kết quả: Dialog, Tooltip, Select... luôn hiển thị đúng màu dark
|
|
982
|
+
dù chúng render ở đâu trong DOM.
|
|
983
|
+
</p>
|
|
984
|
+
</div>
|
|
985
|
+
|
|
986
|
+
<div className="relative z-10 grid sm:grid-cols-2 gap-6 max-w-3xl">
|
|
987
|
+
<div className="p-6 rounded-2xl border border-success/30 bg-success/10 shadow-sm flex flex-col gap-2">
|
|
988
|
+
<div className="text-success font-semibold text-lg flex items-center gap-2">
|
|
989
|
+
✅ gladcn — ThemeWrapper
|
|
990
|
+
</div>
|
|
991
|
+
<p className="text-success/80 text-sm leading-relaxed">
|
|
992
|
+
Theme được tunnel xuyên qua Portal boundary. Dialog, Tooltip,
|
|
993
|
+
Select... luôn hiển thị đúng dark mode dù render tại{" "}
|
|
994
|
+
<code className="opacity-80">document.body</code>.
|
|
995
|
+
</p>
|
|
996
|
+
</div>
|
|
997
|
+
<div className="p-6 rounded-2xl border border-destructive/30 bg-destructive/10 shadow-sm opacity-80 flex flex-col gap-2">
|
|
998
|
+
<div className="text-destructive font-semibold text-lg flex items-center gap-2">
|
|
999
|
+
❌ Các thư viện thông thường
|
|
1000
|
+
</div>
|
|
1001
|
+
<p className="text-destructive/80 text-sm leading-relaxed">
|
|
1002
|
+
Theme bị mất khi vượt qua Portal. Tooltip, Dialog bên trong
|
|
1003
|
+
dark section vẫn hiển thị màu Light Mode — lỗi thầm lặng, khó
|
|
1004
|
+
debug.
|
|
1005
|
+
</p>
|
|
1006
|
+
</div>
|
|
1007
|
+
</div>
|
|
1008
|
+
|
|
1009
|
+
<div className="relative z-10 mt-10">
|
|
1010
|
+
<Button
|
|
1011
|
+
render={<a href="?component=theme-provider" />}
|
|
1012
|
+
variant="outline"
|
|
1013
|
+
color="warning"
|
|
1014
|
+
className="gap-2 font-bold px-6 py-5 rounded-xl border-warning/30 bg-warning/10 hover:bg-warning/20 shadow-sm"
|
|
1015
|
+
>
|
|
1016
|
+
Xem Demo Thực tế
|
|
1017
|
+
<ArrowRightIcon className="size-4" />
|
|
1018
|
+
</Button>
|
|
1019
|
+
</div>
|
|
1020
|
+
</div>
|
|
1021
|
+
</section>
|
|
1022
|
+
|
|
1023
|
+
{/* 🎨 OKLCH COLOR TOKENS */}
|
|
1024
|
+
<section className="container max-w-6xl mx-auto px-4">
|
|
1025
|
+
<div className="rounded-[2.5rem] border border-border bg-card/30 p-10 md:p-16 shadow-xl relative overflow-hidden group">
|
|
1026
|
+
<div className="absolute -top-10 -right-10 p-8 opacity-5 pointer-events-none group-hover:rotate-12 group-hover:scale-125 transition-all duration-1000">
|
|
1027
|
+
<PaletteIcon className="size-64 md:size-[400px]" />
|
|
1028
|
+
</div>
|
|
1029
|
+
|
|
1030
|
+
<div className="relative z-10 max-w-3xl mb-14 space-y-5">
|
|
1031
|
+
<h3 className="text-3xl md:text-5xl font-extrabold tracking-tight">
|
|
1032
|
+
Không gian màu OKLCH
|
|
1033
|
+
</h3>
|
|
1034
|
+
<p className="text-muted-foreground text-xl leading-relaxed">
|
|
1035
|
+
Mọi token màu sắc được tính toán toán học trên không gian OKLCH.
|
|
1036
|
+
Đảm bảo độ chuyển sắc hoàn hảo, tỉ lệ tương phản WCAG AAA/AA trên
|
|
1037
|
+
mọi theme mà không cần định nghĩa thủ công từng dải màu.
|
|
1038
|
+
</p>
|
|
1039
|
+
</div>
|
|
1040
|
+
|
|
1041
|
+
<div className="relative z-10 flex flex-wrap gap-6 md:gap-8 justify-center">
|
|
1042
|
+
{COLORS.map((c, i) => (
|
|
1043
|
+
<div
|
|
1044
|
+
key={c}
|
|
1045
|
+
className="animate-fade-up"
|
|
1046
|
+
style={{
|
|
1047
|
+
animationDelay: `${i * 50}ms`,
|
|
1048
|
+
animationFillMode: "both",
|
|
1049
|
+
}}
|
|
1050
|
+
>
|
|
1051
|
+
<ColorSwatch color={c} />
|
|
1052
|
+
</div>
|
|
1053
|
+
))}
|
|
1054
|
+
</div>
|
|
1055
|
+
</div>
|
|
1056
|
+
</section>
|
|
1057
|
+
|
|
1058
|
+
{/* 🚀 FINAL CTA */}
|
|
1059
|
+
<section className="container max-w-6xl mx-auto px-4">
|
|
1060
|
+
<div className="rounded-[2.5rem] border-2 border-primary/40 bg-gradient-to-br from-primary/10 via-background to-info/5 p-10 md:p-16 shadow-2xl shadow-primary/5 text-center relative overflow-hidden">
|
|
1061
|
+
<div className="absolute inset-0 bg-[radial-gradient(ellipse_60%_60%_at_50%_0%,rgba(var(--primary-rgb),0.15),transparent)] pointer-events-none" />
|
|
1062
|
+
<div className="relative z-10 space-y-6 max-w-2xl mx-auto">
|
|
1063
|
+
<h2 className="text-3xl md:text-5xl font-extrabold tracking-tight">
|
|
1064
|
+
Sẵn sàng bắt đầu?
|
|
1065
|
+
</h2>
|
|
1066
|
+
<p className="text-muted-foreground text-lg leading-relaxed">
|
|
1067
|
+
Toàn bộ source code sẽ nằm trong thư mục{" "}
|
|
1068
|
+
<code className="text-sm bg-primary/20 text-primary px-1.5 py-0.5 rounded">
|
|
1069
|
+
src/
|
|
1070
|
+
</code>{" "}
|
|
1071
|
+
của bạn trong vòng 30 giây. Không cần config. Không cần đọc thêm
|
|
1072
|
+
tài liệu.
|
|
1073
|
+
</p>
|
|
1074
|
+
<div className="flex flex-col sm:flex-row items-center justify-center gap-4 pt-2">
|
|
1075
|
+
<button
|
|
1076
|
+
onClick={handleCopy}
|
|
1077
|
+
className="bg-primary text-primary-foreground hover:bg-primary/90 px-8 py-4 rounded-2xl font-mono text-sm shadow-lg shadow-primary/20 flex items-center gap-4 cursor-pointer transition-all hover:scale-105 active:scale-95"
|
|
1078
|
+
>
|
|
1079
|
+
<span className="font-bold opacity-70">~</span>
|
|
1080
|
+
<span>npx gladvn init</span>
|
|
1081
|
+
<div className="ml-2">
|
|
1082
|
+
{copied ? (
|
|
1083
|
+
<CheckIcon className="size-4" />
|
|
1084
|
+
) : (
|
|
1085
|
+
<CopyIcon className="size-4" />
|
|
1086
|
+
)}
|
|
1087
|
+
</div>
|
|
1088
|
+
</button>
|
|
1089
|
+
<Button
|
|
1090
|
+
render={<a href="?component=overview" />}
|
|
1091
|
+
variant="ghost"
|
|
1092
|
+
className="text-muted-foreground hover:text-foreground"
|
|
1093
|
+
>
|
|
1094
|
+
Xem tài liệu đầy đủ
|
|
1095
|
+
<ArrowRightIcon className="size-4 ml-1" />
|
|
1096
|
+
</Button>
|
|
1097
|
+
</div>
|
|
1098
|
+
<p className="text-xs text-muted-foreground pt-2">
|
|
1099
|
+
Tương thích với npm, yarn, pnpm và bun. Hỗ trợ React 18+.
|
|
1100
|
+
</p>
|
|
1101
|
+
</div>
|
|
1102
|
+
</div>
|
|
1103
|
+
</section>
|
|
1104
|
+
</div>
|
|
1105
|
+
);
|
|
1106
|
+
}
|