@sntlr/registry-shell 1.0.0 → 1.1.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.
Files changed (36) hide show
  1. package/README.md +2 -5
  2. package/dist/adapter/custom.d.ts +1 -1
  3. package/dist/adapter/default.d.ts +3 -3
  4. package/dist/adapter/default.js +3 -3
  5. package/dist/cli/init.js +0 -3
  6. package/dist/cli/init.js.map +1 -1
  7. package/dist/cli/shared.js +0 -5
  8. package/dist/cli/shared.js.map +1 -1
  9. package/dist/config-loader.d.ts +0 -2
  10. package/dist/config-loader.js +0 -1
  11. package/dist/define-config.d.ts +0 -6
  12. package/package.json +1 -1
  13. package/src/adapter/custom.ts +1 -1
  14. package/src/adapter/default.ts +3 -3
  15. package/src/cli/init.ts +0 -3
  16. package/src/cli/shared.ts +0 -4
  17. package/src/config-loader.ts +0 -3
  18. package/src/define-config.ts +0 -7
  19. package/src/next-app/app/globals.css +329 -329
  20. package/src/next-app/app/page.tsx +1 -1
  21. package/src/next-app/components/component-icon.tsx +140 -140
  22. package/src/next-app/components/heading-anchor.tsx +52 -52
  23. package/src/next-app/{fallback → components}/homepage.tsx +2 -3
  24. package/src/next-app/components/navigation-progress.tsx +62 -62
  25. package/src/next-app/components/resizable-preview.tsx +101 -101
  26. package/src/next-app/components/sidebar-provider.tsx +75 -75
  27. package/src/next-app/hooks/use-controls.ts +72 -72
  28. package/src/next-app/lib/i18n.tsx +630 -630
  29. package/src/next-app/lib/registry-adapter.ts +6 -32
  30. package/src/next-app/lib/utils.ts +6 -6
  31. package/src/next-app/next-env.d.ts +6 -6
  32. package/src/next-app/next.config.ts +0 -5
  33. package/src/next-app/postcss.config.mjs +7 -7
  34. package/src/next-app/user-aliases.d.ts +0 -7
  35. package/src/next-app/app/_user-global.css +0 -6
  36. package/src/next-app/app/_user-sources.css +0 -9
@@ -1,140 +1,140 @@
1
- "use client"
2
-
3
- import {
4
- AlertTriangle,
5
- ChevronsDown,
6
- Terminal,
7
- Hash,
8
- BookMarked,
9
- RectangleHorizontal,
10
- BadgeCheck,
11
- ChevronRight,
12
- CalendarDays,
13
- CreditCard,
14
- CheckSquare,
15
- ChevronsUpDown,
16
- MousePointerClick,
17
- Inbox,
18
- Keyboard,
19
- PanelTop,
20
- ChevronDown,
21
- TextCursorInput,
22
- Tag,
23
- Layers,
24
- CircleDot,
25
- ListFilter,
26
- SeparatorHorizontal,
27
- PanelRight,
28
- LayoutDashboard,
29
- Square,
30
- Bell,
31
- Table2,
32
- Columns3,
33
- AlignLeft,
34
- ToggleLeft,
35
- MessageSquare,
36
- Pipette,
37
- Palette,
38
- TableProperties,
39
- FunctionSquare,
40
- Upload,
41
- SplitSquareHorizontal,
42
- TextCursor,
43
- MousePointer2,
44
- KeyRound,
45
- ArrowLeftRight,
46
- ShieldAlert,
47
- SquarePen,
48
- Filter,
49
- Users,
50
- Link2,
51
- LogIn,
52
- UserPlus,
53
- Smartphone,
54
- Mail,
55
- Lock,
56
- Shield,
57
- UserCog,
58
- Building2,
59
- Users2,
60
- ShieldCheck,
61
- Component,
62
- type LucideIcon,
63
- } from "lucide-react"
64
-
65
- const iconMap: Record<string, LucideIcon> = {
66
- accordion: ChevronsDown,
67
- alert: AlertTriangle,
68
- avatar: CircleDot,
69
- badge: BadgeCheck,
70
- breadcrumb: ChevronRight,
71
- button: RectangleHorizontal,
72
- calendar: CalendarDays,
73
- card: CreditCard,
74
- checkbox: CheckSquare,
75
- collapsible: ChevronsUpDown,
76
- command: Terminal,
77
- "confirm-dialog": ShieldAlert,
78
- "context-menu": MousePointerClick,
79
- "color-picker": Pipette,
80
- "color-swatch": Palette,
81
- "data-table": TableProperties,
82
- "empty-state": Inbox,
83
- "file-upload": Upload,
84
- "form-section": SquarePen,
85
- kbd: Keyboard,
86
- "formula-editor": FunctionSquare,
87
- "app-switcher": ArrowLeftRight,
88
- dialog: PanelTop,
89
- "dropdown-menu": ChevronDown,
90
- input: TextCursorInput,
91
- "input-otp": Hash,
92
- label: Tag,
93
- "live-caret": TextCursor,
94
- "live-cursor": MousePointer2,
95
- pagination: BookMarked,
96
- popover: Layers,
97
- "radio-group": CircleDot,
98
- "search-filter-bar": Filter,
99
- select: ListFilter,
100
- separator: SeparatorHorizontal,
101
- "password-input": KeyRound,
102
- sheet: PanelRight,
103
- sidebar: LayoutDashboard,
104
- skeleton: Square,
105
- "split-button": SplitSquareHorizontal,
106
- sonner: Bell,
107
- table: Table2,
108
- tabs: Columns3,
109
- textarea: AlignLeft,
110
- toggle: ToggleLeft,
111
- tooltip: MessageSquare,
112
- "social-links": Link2,
113
- "user-status": Users,
114
- "auth-login": LogIn,
115
- "auth-register": UserPlus,
116
- "authorized-devices": Smartphone,
117
- "email-update-form": Mail,
118
- "password-reset-form": Lock,
119
- "mfa-form": Shield,
120
- "profile-form": UserCog,
121
- "account-deletion-form": AlertTriangle,
122
- "org-settings-form": Building2,
123
- "org-roles-form": ShieldCheck,
124
- "org-members-form": Users2,
125
- }
126
-
127
- export function ComponentHeroIcon({ name }: { name: string }) {
128
- const Icon = iconMap[name] ?? Component
129
-
130
- return (
131
- <Icon
132
- className="absolute right-0 top-1/2 -translate-y-1/2 size-28 text-foreground/4 -rotate-12 pointer-events-none"
133
- strokeWidth={1.5}
134
- />
135
- )
136
- }
137
-
138
- export function getComponentIcon(name: string): LucideIcon {
139
- return iconMap[name] ?? Component
140
- }
1
+ "use client"
2
+
3
+ import {
4
+ AlertTriangle,
5
+ ChevronsDown,
6
+ Terminal,
7
+ Hash,
8
+ BookMarked,
9
+ RectangleHorizontal,
10
+ BadgeCheck,
11
+ ChevronRight,
12
+ CalendarDays,
13
+ CreditCard,
14
+ CheckSquare,
15
+ ChevronsUpDown,
16
+ MousePointerClick,
17
+ Inbox,
18
+ Keyboard,
19
+ PanelTop,
20
+ ChevronDown,
21
+ TextCursorInput,
22
+ Tag,
23
+ Layers,
24
+ CircleDot,
25
+ ListFilter,
26
+ SeparatorHorizontal,
27
+ PanelRight,
28
+ LayoutDashboard,
29
+ Square,
30
+ Bell,
31
+ Table2,
32
+ Columns3,
33
+ AlignLeft,
34
+ ToggleLeft,
35
+ MessageSquare,
36
+ Pipette,
37
+ Palette,
38
+ TableProperties,
39
+ FunctionSquare,
40
+ Upload,
41
+ SplitSquareHorizontal,
42
+ TextCursor,
43
+ MousePointer2,
44
+ KeyRound,
45
+ ArrowLeftRight,
46
+ ShieldAlert,
47
+ SquarePen,
48
+ Filter,
49
+ Users,
50
+ Link2,
51
+ LogIn,
52
+ UserPlus,
53
+ Smartphone,
54
+ Mail,
55
+ Lock,
56
+ Shield,
57
+ UserCog,
58
+ Building2,
59
+ Users2,
60
+ ShieldCheck,
61
+ Component,
62
+ type LucideIcon,
63
+ } from "lucide-react"
64
+
65
+ const iconMap: Record<string, LucideIcon> = {
66
+ accordion: ChevronsDown,
67
+ alert: AlertTriangle,
68
+ avatar: CircleDot,
69
+ badge: BadgeCheck,
70
+ breadcrumb: ChevronRight,
71
+ button: RectangleHorizontal,
72
+ calendar: CalendarDays,
73
+ card: CreditCard,
74
+ checkbox: CheckSquare,
75
+ collapsible: ChevronsUpDown,
76
+ command: Terminal,
77
+ "confirm-dialog": ShieldAlert,
78
+ "context-menu": MousePointerClick,
79
+ "color-picker": Pipette,
80
+ "color-swatch": Palette,
81
+ "data-table": TableProperties,
82
+ "empty-state": Inbox,
83
+ "file-upload": Upload,
84
+ "form-section": SquarePen,
85
+ kbd: Keyboard,
86
+ "formula-editor": FunctionSquare,
87
+ "app-switcher": ArrowLeftRight,
88
+ dialog: PanelTop,
89
+ "dropdown-menu": ChevronDown,
90
+ input: TextCursorInput,
91
+ "input-otp": Hash,
92
+ label: Tag,
93
+ "live-caret": TextCursor,
94
+ "live-cursor": MousePointer2,
95
+ pagination: BookMarked,
96
+ popover: Layers,
97
+ "radio-group": CircleDot,
98
+ "search-filter-bar": Filter,
99
+ select: ListFilter,
100
+ separator: SeparatorHorizontal,
101
+ "password-input": KeyRound,
102
+ sheet: PanelRight,
103
+ sidebar: LayoutDashboard,
104
+ skeleton: Square,
105
+ "split-button": SplitSquareHorizontal,
106
+ sonner: Bell,
107
+ table: Table2,
108
+ tabs: Columns3,
109
+ textarea: AlignLeft,
110
+ toggle: ToggleLeft,
111
+ tooltip: MessageSquare,
112
+ "social-links": Link2,
113
+ "user-status": Users,
114
+ "auth-login": LogIn,
115
+ "auth-register": UserPlus,
116
+ "authorized-devices": Smartphone,
117
+ "email-update-form": Mail,
118
+ "password-reset-form": Lock,
119
+ "mfa-form": Shield,
120
+ "profile-form": UserCog,
121
+ "account-deletion-form": AlertTriangle,
122
+ "org-settings-form": Building2,
123
+ "org-roles-form": ShieldCheck,
124
+ "org-members-form": Users2,
125
+ }
126
+
127
+ export function ComponentHeroIcon({ name }: { name: string }) {
128
+ const Icon = iconMap[name] ?? Component
129
+
130
+ return (
131
+ <Icon
132
+ className="absolute right-0 top-1/2 -translate-y-1/2 size-28 text-foreground/4 -rotate-12 pointer-events-none"
133
+ strokeWidth={1.5}
134
+ />
135
+ )
136
+ }
137
+
138
+ export function getComponentIcon(name: string): LucideIcon {
139
+ return iconMap[name] ?? Component
140
+ }
@@ -1,52 +1,52 @@
1
- "use client"
2
-
3
- import { Link as LinkIcon } from "lucide-react"
4
-
5
- function slugify(text: string): string {
6
- return text
7
- .toLowerCase()
8
- .replace(/[^\w\s-]/g, "")
9
- .replace(/\s+/g, "-")
10
- }
11
-
12
- interface HeadingProps extends React.HTMLAttributes<HTMLHeadingElement> {
13
- children?: React.ReactNode
14
- }
15
-
16
- function createHeading(level: 1 | 2 | 3 | 4 | 5 | 6) {
17
- const Tag = `h${level}` as const
18
-
19
- return function Heading({ children, id, ...props }: HeadingProps) {
20
- const headingId = id || slugify(typeof children === "string" ? children : "")
21
- if (!headingId) return <Tag {...props}>{children}</Tag>
22
-
23
- return (
24
- <Tag id={headingId} className="group relative scroll-mt-20" {...props}>
25
- {children}
26
- <a
27
- href={`#${headingId}`}
28
- onClick={(e) => {
29
- e.preventDefault()
30
- history.replaceState(null, "", `#${headingId}`)
31
- document.getElementById(headingId)?.scrollIntoView({ behavior: "smooth", block: "start" })
32
- // Copy link to clipboard
33
- navigator.clipboard?.writeText(window.location.href)
34
- }}
35
- className="inline-flex items-center ml-2 opacity-0 group-hover:opacity-100 transition-opacity text-muted-foreground hover:text-foreground"
36
- aria-label={`Link to ${typeof children === "string" ? children : "section"}`}
37
- >
38
- <LinkIcon className="size-4" />
39
- </a>
40
- </Tag>
41
- )
42
- }
43
- }
44
-
45
- export const mdxHeadings = {
46
- h1: createHeading(1),
47
- h2: createHeading(2),
48
- h3: createHeading(3),
49
- h4: createHeading(4),
50
- h5: createHeading(5),
51
- h6: createHeading(6),
52
- }
1
+ "use client"
2
+
3
+ import { Link as LinkIcon } from "lucide-react"
4
+
5
+ function slugify(text: string): string {
6
+ return text
7
+ .toLowerCase()
8
+ .replace(/[^\w\s-]/g, "")
9
+ .replace(/\s+/g, "-")
10
+ }
11
+
12
+ interface HeadingProps extends React.HTMLAttributes<HTMLHeadingElement> {
13
+ children?: React.ReactNode
14
+ }
15
+
16
+ function createHeading(level: 1 | 2 | 3 | 4 | 5 | 6) {
17
+ const Tag = `h${level}` as const
18
+
19
+ return function Heading({ children, id, ...props }: HeadingProps) {
20
+ const headingId = id || slugify(typeof children === "string" ? children : "")
21
+ if (!headingId) return <Tag {...props}>{children}</Tag>
22
+
23
+ return (
24
+ <Tag id={headingId} className="group relative scroll-mt-20" {...props}>
25
+ {children}
26
+ <a
27
+ href={`#${headingId}`}
28
+ onClick={(e) => {
29
+ e.preventDefault()
30
+ history.replaceState(null, "", `#${headingId}`)
31
+ document.getElementById(headingId)?.scrollIntoView({ behavior: "smooth", block: "start" })
32
+ // Copy link to clipboard
33
+ navigator.clipboard?.writeText(window.location.href)
34
+ }}
35
+ className="inline-flex items-center ml-2 opacity-0 group-hover:opacity-100 transition-opacity text-muted-foreground hover:text-foreground"
36
+ aria-label={`Link to ${typeof children === "string" ? children : "section"}`}
37
+ >
38
+ <LinkIcon className="size-4" />
39
+ </a>
40
+ </Tag>
41
+ )
42
+ }
43
+ }
44
+
45
+ export const mdxHeadings = {
46
+ h1: createHeading(1),
47
+ h2: createHeading(2),
48
+ h3: createHeading(3),
49
+ h4: createHeading(4),
50
+ h5: createHeading(5),
51
+ h6: createHeading(6),
52
+ }
@@ -1,6 +1,5 @@
1
1
  /**
2
- * Fallback homepage rendered at `/` when the user's config has no custom
3
- * `homePage`. Two states:
2
+ * The shell's homepage rendered at `/`. Two states:
4
3
  * - Registry has content → generic index listing components/blocks/docs.
5
4
  * - Registry empty / absent → terse "no registry wired" placeholder
6
5
  * pointing at the shell's documentation site.
@@ -10,7 +9,7 @@ import { getAllComponents } from "@shell/lib/components-nav"
10
9
  import { getAllDocs } from "@shell/lib/docs"
11
10
  import type { HomePageProps } from "@shell/lib/registry-adapter"
12
11
 
13
- export default function FallbackHomePage({ firstDocSlug }: HomePageProps) {
12
+ export default function HomePage({ firstDocSlug }: HomePageProps) {
14
13
  const items = getAllComponents()
15
14
  const docs = getAllDocs()
16
15
 
@@ -1,62 +1,62 @@
1
- "use client"
2
-
3
- import { useEffect, useRef, useSyncExternalStore } from "react"
4
- import { usePathname } from "next/navigation"
5
-
6
- // Simple external store for navigation state
7
- let listeners: Array<() => void> = []
8
- let navProgress = { loading: false, progress: 0 }
9
-
10
- function setNav(updates: Partial<typeof navProgress>) {
11
- navProgress = { ...navProgress, ...updates }
12
- listeners.forEach((l) => l())
13
- }
14
-
15
- function subscribe(listener: () => void) {
16
- listeners.push(listener)
17
- return () => { listeners = listeners.filter((l) => l !== listener) }
18
- }
19
-
20
- function getSnapshot() { return navProgress }
21
-
22
- export function NavigationProgress() {
23
- const pathname = usePathname()
24
- const state = useSyncExternalStore(subscribe, getSnapshot, getSnapshot)
25
- const prevPathname = useRef(pathname)
26
-
27
- useEffect(() => {
28
- if (prevPathname.current !== pathname) {
29
- prevPathname.current = pathname
30
- setNav({ progress: 100 })
31
- const timer = setTimeout(() => setNav({ loading: false, progress: 0 }), 200)
32
- return () => clearTimeout(timer)
33
- }
34
- }, [pathname])
35
-
36
- // Intercept link clicks to show progress
37
- useEffect(() => {
38
- function handleClick(e: MouseEvent) {
39
- const link = (e.target as HTMLElement).closest("a")
40
- if (!link) return
41
- const href = link.getAttribute("href")
42
- if (!href || href.startsWith("#") || href.startsWith("http") || href.startsWith("mailto:")) return
43
- if (href === pathname) return
44
- setNav({ loading: true, progress: 30 })
45
- setTimeout(() => setNav({ progress: 70 }), 100)
46
- }
47
- document.addEventListener("click", handleClick)
48
- return () => document.removeEventListener("click", handleClick)
49
- }, [pathname])
50
-
51
- if (!state.loading && state.progress === 0) return null
52
-
53
- return (
54
- <div
55
- className="fixed top-0 left-0 z-[100] h-0.5 bg-primary transition-all duration-300 ease-out"
56
- style={{
57
- width: `${state.progress}%`,
58
- opacity: state.progress >= 100 ? 0 : 1,
59
- }}
60
- />
61
- )
62
- }
1
+ "use client"
2
+
3
+ import { useEffect, useRef, useSyncExternalStore } from "react"
4
+ import { usePathname } from "next/navigation"
5
+
6
+ // Simple external store for navigation state
7
+ let listeners: Array<() => void> = []
8
+ let navProgress = { loading: false, progress: 0 }
9
+
10
+ function setNav(updates: Partial<typeof navProgress>) {
11
+ navProgress = { ...navProgress, ...updates }
12
+ listeners.forEach((l) => l())
13
+ }
14
+
15
+ function subscribe(listener: () => void) {
16
+ listeners.push(listener)
17
+ return () => { listeners = listeners.filter((l) => l !== listener) }
18
+ }
19
+
20
+ function getSnapshot() { return navProgress }
21
+
22
+ export function NavigationProgress() {
23
+ const pathname = usePathname()
24
+ const state = useSyncExternalStore(subscribe, getSnapshot, getSnapshot)
25
+ const prevPathname = useRef(pathname)
26
+
27
+ useEffect(() => {
28
+ if (prevPathname.current !== pathname) {
29
+ prevPathname.current = pathname
30
+ setNav({ progress: 100 })
31
+ const timer = setTimeout(() => setNav({ loading: false, progress: 0 }), 200)
32
+ return () => clearTimeout(timer)
33
+ }
34
+ }, [pathname])
35
+
36
+ // Intercept link clicks to show progress
37
+ useEffect(() => {
38
+ function handleClick(e: MouseEvent) {
39
+ const link = (e.target as HTMLElement).closest("a")
40
+ if (!link) return
41
+ const href = link.getAttribute("href")
42
+ if (!href || href.startsWith("#") || href.startsWith("http") || href.startsWith("mailto:")) return
43
+ if (href === pathname) return
44
+ setNav({ loading: true, progress: 30 })
45
+ setTimeout(() => setNav({ progress: 70 }), 100)
46
+ }
47
+ document.addEventListener("click", handleClick)
48
+ return () => document.removeEventListener("click", handleClick)
49
+ }, [pathname])
50
+
51
+ if (!state.loading && state.progress === 0) return null
52
+
53
+ return (
54
+ <div
55
+ className="fixed top-0 left-0 z-[100] h-0.5 bg-primary transition-all duration-300 ease-out"
56
+ style={{
57
+ width: `${state.progress}%`,
58
+ opacity: state.progress >= 100 ? 0 : 1,
59
+ }}
60
+ />
61
+ )
62
+ }