@docubook/create 2.0.0 → 2.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@docubook/create",
3
- "version": "2.0.0",
3
+ "version": "2.2.0",
4
4
  "description": "CLI to create DocuBook projects",
5
5
  "main": "src/index.js",
6
6
  "type": "module",
@@ -15,7 +15,7 @@ export default function Home() {
15
15
  return (
16
16
  <div className="flex flex-col items-center justify-center px-2 py-8 text-center sm:py-36">
17
17
  <Link
18
- href="/docs/changelog/version-1"
18
+ href="/docs/changelog/version-2"
19
19
  className="mb-5 sm:text-lg flex items-center gap-2 underline underline-offset-4 sm:-mt-12"
20
20
  >
21
21
  <div className="z-10 flex min-h-10 items-center justify-center max-[800px]:mt-10">
@@ -25,7 +25,7 @@ export default function Home() {
25
25
  )}
26
26
  >
27
27
  <AnimatedShinyText className="inline-flex items-center justify-center px-4 py-1 transition ease-out hover:text-neutral-100 hover:duration-300 hover:dark:text-neutral-200">
28
- <span>🚀 Release v2.0.0</span>
28
+ <span>🚀 Release v2.2.0</span>
29
29
  <ArrowRightIcon className="ml-1 size-3 transition-transform duration-300 ease-in-out group-hover:translate-x-0.5" />
30
30
  </AnimatedShinyText>
31
31
  </div>
@@ -12,25 +12,29 @@ function Release({ version, title, date, children }: ReleaseProps) {
12
12
 
13
13
  return (
14
14
  <div className="mb-16 group">
15
- <div className="mb-6">
16
- <div className="flex items-center gap-3 mb-2">
17
- <div className="bg-primary/10 text-primary border-2 border-primary/20 rounded-full px-4 py-1.5 text-base font-medium">
18
- v{version}
19
- </div>
20
- {date && (
21
- <div className="text-muted-foreground text-sm">
15
+ <div className="flex items-center gap-3 mt-6 mb-2">
16
+ <div
17
+ id={version}
18
+ className="inline-flex items-center rounded-full border border-primary/20 bg-primary/10 px-3 py-1 text-sm font-semibold text-primary transition-colors hover:bg-primary/15 scroll-m-20 backdrop-blur-sm"
19
+ >
20
+ v{version}
21
+ </div>
22
+ {date && (
23
+ <div className="flex items-center gap-3 text-sm font-medium text-muted-foreground">
24
+ <span className="h-1 w-1 rounded-full bg-muted-foreground/30"></span>
25
+ <time dateTime={date}>
22
26
  {new Date(date).toLocaleDateString('en-US', {
23
27
  year: 'numeric',
24
28
  month: 'long',
25
29
  day: 'numeric'
26
30
  })}
27
- </div>
28
- )}
29
- </div>
30
- <h2 className="text-2xl font-bold text-foreground/90 mb-3">
31
- {title}
32
- </h2>
31
+ </time>
32
+ </div>
33
+ )}
33
34
  </div>
35
+ <h3 className="text-2xl font-bold text-foreground/90 mb-6 !mt-0">
36
+ {title}
37
+ </h3>
34
38
  <div className="space-y-8">
35
39
  {children}
36
40
  </div>
@@ -41,6 +41,12 @@ export default function MobToc({ tocs }: MobTocProps) {
41
41
  // Only show on /docs pages
42
42
  const isDocsPage = useMemo(() => pathname?.startsWith('/docs'), [pathname]);
43
43
 
44
+ const [mounted, setMounted] = React.useState(false);
45
+
46
+ React.useEffect(() => {
47
+ setMounted(true);
48
+ }, []);
49
+
44
50
  // Toggle expanded state
45
51
  const toggleExpanded = React.useCallback((e: React.MouseEvent) => {
46
52
  e.stopPropagation();
@@ -68,7 +74,7 @@ export default function MobToc({ tocs }: MobTocProps) {
68
74
  }, [isExpanded]);
69
75
 
70
76
  // Don't render anything if not on docs page or no TOC items
71
- if (!isDocsPage || !tocs?.length) return null;
77
+ if (!isDocsPage || !tocs?.length || !mounted) return null;
72
78
 
73
79
  const chevronIcon = isExpanded ? (
74
80
  <ChevronUp className="w-4 h-4 text-muted-foreground flex-shrink-0" />
@@ -78,51 +84,51 @@ export default function MobToc({ tocs }: MobTocProps) {
78
84
 
79
85
  return (
80
86
  <AnimatePresence>
81
- <motion.div
82
- ref={tocRef}
83
- className="lg:hidden fixed top-16 left-0 right-0 z-50"
84
- initial={{ y: -100, opacity: 0 }}
85
- animate={{ y: 0, opacity: 1 }}
86
- exit={{ y: -100, opacity: 0 }}
87
- transition={{ duration: 0.2, ease: 'easeInOut' }}
88
- >
89
- <div className="w-full bg-background/95 backdrop-blur-sm border-b border-stone-200 dark:border-stone-800 shadow-sm">
90
- <div className="sm:px-8 px-4 py-2">
91
- <Button
92
- variant="ghost"
93
- size="sm"
94
- className="w-full justify-between h-auto py-2 px-2 -mx-1 rounded-md hover:bg-transparent hover:text-inherit"
95
- onClick={toggleExpanded}
96
- aria-label={isExpanded ? 'Collapse table of contents' : 'Expand table of contents'}
97
- >
98
- <div className="flex items-center gap-2">
99
- <List className="w-4 h-4 text-muted-foreground flex-shrink-0" />
100
- <span className="font-medium text-sm">On this page</span>
101
- </div>
102
- {chevronIcon}
103
- </Button>
104
-
105
- <AnimatePresence>
106
- {isExpanded && (
107
- <motion.div
108
- ref={contentRef}
109
- className="mt-2 pb-2 max-h-[60vh] overflow-y-auto px-1 -mx-1"
110
- initial={{ opacity: 0, height: 0 }}
111
- animate={{ opacity: 1, height: 'auto' }}
112
- exit={{ opacity: 0, height: 0 }}
113
- transition={{ duration: 0.2, ease: 'easeInOut' }}
114
- >
115
- <TocObserver
116
- data={tocs}
117
- activeId={activeId}
118
- onActiveIdChange={setActiveId}
119
- />
120
- </motion.div>
121
- )}
122
- </AnimatePresence>
123
- </div>
87
+ <motion.div
88
+ ref={tocRef}
89
+ className="lg:hidden fixed top-16 left-0 right-0 z-50"
90
+ initial={{ y: -100, opacity: 0 }}
91
+ animate={{ y: 0, opacity: 1 }}
92
+ exit={{ y: -100, opacity: 0 }}
93
+ transition={{ duration: 0.2, ease: 'easeInOut' }}
94
+ >
95
+ <div className="w-full bg-background/95 backdrop-blur-sm border-b border-stone-200 dark:border-stone-800 shadow-sm">
96
+ <div className="sm:px-8 px-4 py-2">
97
+ <Button
98
+ variant="ghost"
99
+ size="sm"
100
+ className="w-full justify-between h-auto py-2 px-2 -mx-1 rounded-md hover:bg-transparent hover:text-inherit"
101
+ onClick={toggleExpanded}
102
+ aria-label={isExpanded ? 'Collapse table of contents' : 'Expand table of contents'}
103
+ >
104
+ <div className="flex items-center gap-2">
105
+ <List className="w-4 h-4 text-muted-foreground flex-shrink-0" />
106
+ <span className="font-medium text-sm">On this page</span>
107
+ </div>
108
+ {chevronIcon}
109
+ </Button>
110
+
111
+ <AnimatePresence>
112
+ {isExpanded && (
113
+ <motion.div
114
+ ref={contentRef}
115
+ className="mt-2 pb-2 max-h-[60vh] overflow-y-auto px-1 -mx-1"
116
+ initial={{ opacity: 0, height: 0 }}
117
+ animate={{ opacity: 1, height: 'auto' }}
118
+ exit={{ opacity: 0, height: 0 }}
119
+ transition={{ duration: 0.2, ease: 'easeInOut' }}
120
+ >
121
+ <TocObserver
122
+ data={tocs}
123
+ activeId={activeId}
124
+ onActiveIdChange={setActiveId}
125
+ />
126
+ </motion.div>
127
+ )}
128
+ </AnimatePresence>
124
129
  </div>
125
- </motion.div>
130
+ </div>
131
+ </motion.div>
126
132
  </AnimatePresence>
127
133
  );
128
134
  }
@@ -174,19 +174,37 @@ export async function getDocsForSlug(slug: string) {
174
174
  export async function getDocsTocs(slug: string) {
175
175
  const contentPath = getDocsContentPath(slug);
176
176
  const rawMdx = await fs.readFile(contentPath, "utf-8");
177
- // captures between ## - #### can modify accordingly
178
- const headingsRegex = /^(#{2,4})\s(.+)$/gm;
177
+
178
+ // Regex to match code blocks (```...```), standard markdown headings (##), and <Release> tags
179
+ const combinedRegex = /(```[\s\S]*?```)|^(#{2,4})\s(.+)$|<Release[^>]*version="([^"]+)"/gm;
180
+
179
181
  let match;
180
182
  const extractedHeadings = [];
181
- while ((match = headingsRegex.exec(rawMdx)) !== null) {
182
- const headingLevel = match[1].length;
183
- const headingText = match[2].trim();
184
- const slug = sluggify(headingText);
185
- extractedHeadings.push({
186
- level: headingLevel,
187
- text: headingText,
188
- href: `#${slug}`,
189
- });
183
+
184
+ while ((match = combinedRegex.exec(rawMdx)) !== null) {
185
+ // match[1] -> Code block content (ignore)
186
+ if (match[1]) continue;
187
+
188
+ // match[2] & match[3] -> Markdown headings
189
+ if (match[2]) {
190
+ const headingLevel = match[2].length;
191
+ const headingText = match[3].trim();
192
+ const slug = sluggify(headingText);
193
+ extractedHeadings.push({
194
+ level: headingLevel,
195
+ text: headingText,
196
+ href: `#${slug}`,
197
+ });
198
+ }
199
+ // match[4] -> Release component version
200
+ else if (match[4]) {
201
+ const version = match[4];
202
+ extractedHeadings.push({
203
+ level: 2,
204
+ text: `v${version}`,
205
+ href: `#${version}`,
206
+ });
207
+ }
190
208
  }
191
209
  return extractedHeadings;
192
210
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "docubook",
3
- "version": "2.0.0",
3
+ "version": "2.2.0",
4
4
  "private": true,
5
5
  "scripts": {
6
6
  "dev": "next dev",
@@ -32,7 +32,7 @@
32
32
  "gray-matter": "^4.0.3",
33
33
  "lucide-react": "^0.511.0",
34
34
  "next": "^16.1.6",
35
- "next-mdx-remote": "^5.0.0",
35
+ "next-mdx-remote": "^6.0.0",
36
36
  "next-themes": "^0.4.4",
37
37
  "react": "19.2.3",
38
38
  "react-dom": "19.2.3",