@next-library/theme 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,565 @@
1
+ # @next-library/theme
2
+
3
+ Complete UI theme package for Next.js documentation framework. This package provides ready-made React components built on top of [`@next-library/core`](../core/README.md).
4
+
5
+ > **Looking for core utilities only?** Check out [`@next-library/core`](../core/README.md) which provides content management, i18n, and SEO utilities without UI components.
6
+
7
+ ## Features
8
+
9
+ - 🎨 **Complete UI Components** - Layout, navigation, markdown rendering, and more
10
+ - 🌍 **Multi-language Support** - Built-in translations for 20+ languages
11
+ - 📱 **Responsive Design** - Mobile-first with drawer navigation and responsive breadcrumbs
12
+ - 🎯 **Type-Safe** - Full TypeScript support
13
+ - ⚡ **Server/Client Separation** - Optimized for Next.js App Router
14
+ - 🎭 **Theme Support** - Dark mode with `next-themes`
15
+ - 📝 **Rich Markdown** - Syntax highlighting, math, diagrams, callouts
16
+
17
+ ## Installation
18
+
19
+ ```bash
20
+ # Using npm
21
+ npm install @next-library/theme @next-library/core
22
+
23
+ # Using pnpm
24
+ pnpm add @next-library/theme @next-library/core
25
+
26
+ # Using yarn
27
+ yarn add @next-library/theme @next-library/core
28
+ ```
29
+
30
+ **Required peer dependencies:**
31
+ - `next-themes` - For theme switching (dark/light mode)
32
+ - `@tailwindcss/typography` - For markdown prose styling
33
+
34
+ ```bash
35
+ pnpm add next-themes @tailwindcss/typography
36
+ ```
37
+
38
+ ## Quick Start
39
+
40
+ ### 1. Set Up Tailwind CSS v4
41
+
42
+ The theme package uses Tailwind CSS v4 with `@source` directives (Nextra-style approach). Create or update your `globals.css`:
43
+
44
+ ```css
45
+ /* app/globals.css */
46
+ @import 'tailwindcss';
47
+ @plugin "@tailwindcss/typography";
48
+
49
+ /* Import theme package styles to scan for Tailwind classes */
50
+ @import '@next-library/theme/style';
51
+
52
+ @custom-variant dark (&:is(.dark *));
53
+
54
+ :root {
55
+ /* Your CSS variables */
56
+ --background: oklch(1 0 0);
57
+ --foreground: oklch(0.145 0 0);
58
+ /* ... more variables */
59
+ }
60
+
61
+ .dark {
62
+ --background: oklch(0.145 0 0);
63
+ --foreground: oklch(0.985 0 0);
64
+ /* ... more variables */
65
+ }
66
+ ```
67
+
68
+ **Important:** The `@import '@next-library/theme/style'` line tells Tailwind where to scan for classes used in the theme components.
69
+
70
+ ### 2. Set Up Theme Provider
71
+
72
+ Create a theme provider wrapper:
73
+
74
+ ```typescript
75
+ // app/providers.tsx
76
+ 'use client';
77
+
78
+ import { ThemeProvider as NextThemesProvider } from 'next-themes';
79
+ import { ReactNode } from 'react';
80
+
81
+ export function ThemeProvider({ children }: { children: ReactNode }) {
82
+ return (
83
+ <NextThemesProvider attribute="class" defaultTheme="system" enableSystem>
84
+ {children}
85
+ </NextThemesProvider>
86
+ );
87
+ }
88
+ ```
89
+
90
+ Wrap your app in `app/layout.tsx`:
91
+
92
+ ```typescript
93
+ // app/layout.tsx
94
+ import { ThemeProvider } from './providers';
95
+
96
+ export default function RootLayout({ children }: { children: React.ReactNode }) {
97
+ return (
98
+ <html lang="en" suppressHydrationWarning>
99
+ <body>
100
+ <ThemeProvider>
101
+ {children}
102
+ </ThemeProvider>
103
+ </body>
104
+ </html>
105
+ );
106
+ }
107
+ ```
108
+
109
+ ### 3. Use Components
110
+
111
+ #### Server Components
112
+
113
+ Import server components from `@next-library/theme/server`:
114
+
115
+ ```typescript
116
+ // app/[locale]/layout.tsx
117
+ import { DocumentationLayout } from '@next-library/theme/server';
118
+
119
+ export default function LocaleLayout({ children, params }) {
120
+ const { locale } = await params;
121
+
122
+ return (
123
+ <DocumentationLayout language={locale}>
124
+ {children}
125
+ </DocumentationLayout>
126
+ );
127
+ }
128
+ ```
129
+
130
+ #### Client Components
131
+
132
+ Import client components from `@next-library/theme/client`:
133
+
134
+ ```typescript
135
+ // components/my-component.tsx
136
+ 'use client';
137
+
138
+ import { LanguageSwitcher, ThemeSwitcher } from '@next-library/theme/client';
139
+
140
+ export function MyComponent() {
141
+ return (
142
+ <div>
143
+ <LanguageSwitcher availableLocales={['en', 'fr', 'de']} />
144
+ <ThemeSwitcher />
145
+ </div>
146
+ );
147
+ }
148
+ ```
149
+
150
+ ## Component Exports
151
+
152
+ ### Server Components (`@next-library/theme/server`)
153
+
154
+ - `DocumentationLayout` - Main layout wrapper
155
+ - `NavigationBar` - Top navigation bar
156
+ - `LeftSidebar` - Left sidebar navigation
157
+ - `RightSidebar` - Right sidebar (TOC, contributors)
158
+ - `DocumentationFooter` - Footer component
159
+ - `StructuredData` - JSON-LD structured data renderer
160
+
161
+ ### Client Components (`@next-library/theme/client`)
162
+
163
+ **Navigation:**
164
+ - `Banner` - Top banner component
165
+ - `Logo` - Logo component
166
+ - `TopCategories` - Top category navigation
167
+ - `SearchBar` - Search input with keyboard shortcuts
168
+ - `ThemeSwitcher` - Dark/light theme toggle
169
+ - `LanguageSwitcher` - Language selection dropdown
170
+ - `MobileMenu` - Mobile navigation drawer
171
+ - `GithubStar` - GitHub star button
172
+ - `GithubLink` - GitHub repository link
173
+ - `Breadcrumbs` - Breadcrumb navigation
174
+ - `BreadcrumbToggle` - Responsive breadcrumb overflow
175
+ - `FolderCards` - Grid of folder cards
176
+ - `SidebarNavigation` - Sidebar navigation tree
177
+ - `TableOfContents` - Table of contents
178
+ - `GithubContributors` - Contributors list
179
+ - `LevelElevator` - Current level indicator
180
+ - `AnchorLinkHandler` - Anchor link copying
181
+
182
+ **Markdown:**
183
+ - `MarkdownRenderer` - Markdown content renderer
184
+ - `CopyPageButton` - Copy page content button with ChatGPT/Claude integration
185
+ - `PageHeader` - Page title with copy button
186
+ - `FallbackLocaleWarning` - Warning for fallback locale content
187
+
188
+ **UI Primitives:**
189
+ - `Button`, `Card`, `Avatar`, `Collapsible`, `Drawer`, `DropdownMenu`, `Select`, `Separator`, `Sheet`, `Tooltip`, `Input`, `Skeleton`
190
+ - Sidebar components (`SidebarProvider`, `SidebarContent`, `SidebarMenu`, etc.)
191
+ - Breadcrumb components (`Breadcrumb`, `BreadcrumbItem`, etc.)
192
+
193
+ **Tracking:**
194
+ - `CookieBanner` - Cookie consent banner
195
+
196
+ **Hooks:**
197
+ - `useMediaQuery` - Media query hook
198
+ - `useIsMobile` - Mobile detection hook
199
+
200
+ ## Complete Example
201
+
202
+ ### Layout Structure
203
+
204
+ ```typescript
205
+ // app/[locale]/layout.tsx
206
+ import { DocumentationLayout } from '@next-library/theme/server';
207
+
208
+ export default async function LocaleLayout({
209
+ children,
210
+ params
211
+ }: {
212
+ children: React.ReactNode;
213
+ params: Promise<{ locale: string }>;
214
+ }) {
215
+ const { locale } = await params;
216
+
217
+ return (
218
+ <DocumentationLayout language={locale}>
219
+ {children}
220
+ </DocumentationLayout>
221
+ );
222
+ }
223
+ ```
224
+
225
+ ### Documentation Page Layout
226
+
227
+ ```typescript
228
+ // app/[locale]/docs/[[...slug]]/layout.tsx
229
+ import { NavigationBar, LeftSidebar, RightSidebar } from '@next-library/theme/server';
230
+ import { Breadcrumbs, AnchorLinkHandler } from '@next-library/theme/client';
231
+ import { extractPageData, getSupportedLocales, type Locale } from '@next-library/core';
232
+
233
+ export default async function DocsLayout({
234
+ children,
235
+ params
236
+ }: {
237
+ children: React.ReactNode;
238
+ params: Promise<{ locale: string; slug?: string[] }>;
239
+ }) {
240
+ const { locale: rawLocale, slug } = await params;
241
+ const supportedLocales = getSupportedLocales();
242
+ const locale = (supportedLocales.includes(rawLocale) ? rawLocale : 'en') as Locale;
243
+ const safeSlug = Array.isArray(slug) ? slug : [];
244
+
245
+ const pageData = extractPageData(locale, safeSlug);
246
+
247
+ return (
248
+ <div>
249
+ {/* Mobile Navigation */}
250
+ <NavigationBar
251
+ language={locale}
252
+ className="block lg:hidden"
253
+ pageData={pageData}
254
+ />
255
+
256
+ {/* Main Content Layout */}
257
+ <div className="flex flex-row gap-12 w-full lg:w-[95vw] mx-auto pt-10">
258
+ {/* Left Sidebar */}
259
+ <LeftSidebar
260
+ data={pageData}
261
+ className="sticky top-28 hidden lg:flex lg:flex-[2] max-w-xs"
262
+ />
263
+
264
+ {/* Main Content */}
265
+ <main className="flex flex-col lg:gap-8 gap-4 flex-1 w-full lg:flex-[6] px-4 lg:px-0">
266
+ <Breadcrumbs data={pageData} locale={locale} />
267
+ {children}
268
+ </main>
269
+
270
+ {/* Right Sidebar */}
271
+ <RightSidebar
272
+ data={pageData}
273
+ className="sticky top-28 hidden lg:flex lg:flex-[1.5] max-w-xs"
274
+ />
275
+
276
+ {/* Anchor Link Handler */}
277
+ <AnchorLinkHandler locale={locale} />
278
+ </div>
279
+ </div>
280
+ );
281
+ }
282
+ ```
283
+
284
+ ### Documentation Page
285
+
286
+ ```typescript
287
+ // app/[locale]/docs/[[...slug]]/page.tsx
288
+ import { PageHeader, MarkdownRenderer, FallbackLocaleWarning } from '@next-library/theme';
289
+ import { extractPageData, generateArticleSchema, generateBreadcrumbSchema, generateCollectionPageSchema, getSupportedLocales, fetchRawFileContent } from '@next-library/core';
290
+ import { StructuredData } from '@next-library/theme/server';
291
+ import { notFound } from 'next/navigation';
292
+
293
+ export default async function DocPage({
294
+ params
295
+ }: {
296
+ params: Promise<{ locale: string; slug?: string[] }>;
297
+ }) {
298
+ const { locale: rawLocale, slug } = await params;
299
+ const supportedLocales = getSupportedLocales();
300
+ const locale = supportedLocales.includes(rawLocale) ? rawLocale : 'en';
301
+ const safeSlug = Array.isArray(slug) ? slug : [];
302
+
303
+ const pageData = extractPageData(locale, safeSlug);
304
+ const { node } = pageData;
305
+
306
+ if (!node) {
307
+ notFound();
308
+ }
309
+
310
+ // Fetch markdown content from GitHub
311
+ const rawMarkdown = await fetchRawFileContent(node.githubPath!);
312
+
313
+ // Generate structured data
314
+ const articleSchema = generateArticleSchema({ /* ... */ });
315
+ const breadcrumbSchema = generateBreadcrumbSchema(pageData.navigation.breadcrumbs);
316
+ const collectionPageSchema = generateCollectionPageSchema({ /* ... */ });
317
+
318
+ const schemas = [articleSchema, breadcrumbSchema, collectionPageSchema]
319
+ .filter(Boolean)
320
+ .map(schema => JSON.stringify(schema, null, 0).replace(/</g, '\\u003c'))
321
+ .join('\n');
322
+
323
+ return (
324
+ <div>
325
+ {/* Structured Data */}
326
+ {schemas && (
327
+ <script
328
+ type="application/ld+json"
329
+ dangerouslySetInnerHTML={{ __html: schemas }}
330
+ />
331
+ )}
332
+
333
+ {/* Page Header with Copy Button */}
334
+ <PageHeader
335
+ title={node.title}
336
+ markdown={rawMarkdown}
337
+ pageUrl={`https://example.com/${locale}/docs/${safeSlug.join('/')}`}
338
+ websiteTitle="My Documentation"
339
+ locale={locale}
340
+ />
341
+
342
+ {/* Fallback Warning */}
343
+ {node.fallback && (
344
+ <FallbackLocaleWarning locale={locale} />
345
+ )}
346
+
347
+ {/* Markdown Content */}
348
+ <MarkdownRenderer markdown={rawMarkdown} />
349
+ </div>
350
+ );
351
+ }
352
+ ```
353
+
354
+ ## Internationalization
355
+
356
+ The theme package includes translations for 20+ languages. Components automatically use translations based on the `locale` prop:
357
+
358
+ ```typescript
359
+ import { CopyPageButton } from '@next-library/theme/client';
360
+
361
+ // Uses default translations for locale
362
+ <CopyPageButton
363
+ sourceCode={markdown}
364
+ locale="fr" // French translations will be used
365
+ />
366
+
367
+ // Override specific translations
368
+ <CopyPageButton
369
+ sourceCode={markdown}
370
+ locale="fr"
371
+ translations={{
372
+ copyPage: 'Copier la page',
373
+ copied: 'Copié',
374
+ }}
375
+ />
376
+ ```
377
+
378
+ ### Supported Locales
379
+
380
+ - English (en)
381
+ - French (fr)
382
+ - German (de)
383
+ - Spanish (es)
384
+ - Arabic (ar) - RTL support
385
+ - Chinese (zh)
386
+ - Japanese (ja)
387
+ - Korean (ko)
388
+ - Portuguese (pt)
389
+ - Italian (it)
390
+ - Russian (ru)
391
+ - Dutch (nl)
392
+ - Swedish (sv)
393
+ - Norwegian (no)
394
+ - Danish (da)
395
+ - Finnish (fi)
396
+ - Polish (pl)
397
+ - Turkish (tr)
398
+ - Hebrew (he) - RTL support
399
+ - Hindi (hi)
400
+
401
+ ### Custom Translations
402
+
403
+ All components accept an optional `translations` prop to override default translations:
404
+
405
+ ```typescript
406
+ interface ComponentTranslations {
407
+ // Component-specific translation keys
408
+ copyPage?: string;
409
+ copied?: string;
410
+ // ... more keys
411
+ }
412
+ ```
413
+
414
+ ## Styling
415
+
416
+ ### Tailwind CSS v4
417
+
418
+ The theme uses Tailwind CSS v4 with `@source` directives. Make sure to import the theme style file in your `globals.css`:
419
+
420
+ ```css
421
+ @import '@next-library/theme/style';
422
+ ```
423
+
424
+ This tells Tailwind where to scan for classes used in theme components.
425
+
426
+ ### CSS Variables
427
+
428
+ The theme uses CSS variables for theming. Define your variables in `globals.css`:
429
+
430
+ ```css
431
+ :root {
432
+ --background: oklch(1 0 0);
433
+ --foreground: oklch(0.145 0 0);
434
+ --primary: oklch(0.205 0 0);
435
+ /* ... more variables */
436
+ }
437
+
438
+ .dark {
439
+ --background: oklch(0.145 0 0);
440
+ --foreground: oklch(0.985 0 0);
441
+ /* ... more variables */
442
+ }
443
+ ```
444
+
445
+ ### Customization
446
+
447
+ You can customize component styles by:
448
+
449
+ 1. **Overriding CSS variables** - Change theme colors via CSS variables
450
+ 2. **Using className prop** - Most components accept `className` for additional styling
451
+ 3. **Tailwind classes** - All components use Tailwind, so you can override with utility classes
452
+
453
+ ## Component Props
454
+
455
+ ### DocumentationLayout
456
+
457
+ ```typescript
458
+ interface DocumentationLayoutProps {
459
+ children: React.ReactNode;
460
+ language?: Locale;
461
+ bannerMessage?: React.ReactNode | null;
462
+ websiteTitle?: string;
463
+ }
464
+ ```
465
+
466
+ ### NavigationBar
467
+
468
+ ```typescript
469
+ interface NavigationBarProps {
470
+ language: Locale;
471
+ className?: string;
472
+ pageData?: PageData;
473
+ websiteTitle?: string;
474
+ }
475
+ ```
476
+
477
+ ### PageHeader
478
+
479
+ ```typescript
480
+ interface PageHeaderProps {
481
+ title: string;
482
+ markdown: string;
483
+ pageUrl?: string;
484
+ websiteTitle?: string;
485
+ className?: string;
486
+ locale?: Locale;
487
+ translations?: CopyPageButtonTranslations;
488
+ showCopyButton?: boolean;
489
+ }
490
+ ```
491
+
492
+ ### CopyPageButton
493
+
494
+ ```typescript
495
+ interface CopyPageButtonProps {
496
+ sourceCode: string;
497
+ pageUrl?: string;
498
+ websiteTitle?: string;
499
+ className?: string;
500
+ locale?: Locale;
501
+ translations?: CopyPageButtonTranslations;
502
+ }
503
+ ```
504
+
505
+ The `CopyPageButton` includes integration with ChatGPT and Claude:
506
+ - **Copy page** - Copies markdown content to clipboard
507
+ - **Open in ChatGPT** - Opens ChatGPT with prefilled message including website title and URL
508
+ - **Open in Claude** - Opens Claude with prefilled message including website title and URL
509
+
510
+ ## Server/Client Separation
511
+
512
+ The theme package properly separates server and client components:
513
+
514
+ - **Server components** are imported from `@next-library/theme/server`
515
+ - **Client components** are imported from `@next-library/theme/client`
516
+ - Server components can import client components (they're externalized in the build)
517
+
518
+ This ensures optimal performance with Next.js App Router.
519
+
520
+ ## TypeScript Support
521
+
522
+ The package is fully typed. Import types as needed:
523
+
524
+ ```typescript
525
+ import type {
526
+ DocumentationLayoutProps,
527
+ NavigationBarProps,
528
+ PageHeaderProps,
529
+ CopyPageButtonProps,
530
+ } from '@next-library/theme/server';
531
+ ```
532
+
533
+ ## Examples
534
+
535
+ See the [`example`](../../example/) directory for a complete working example.
536
+
537
+ ## API Reference
538
+
539
+ ### Server Components
540
+
541
+ - `DocumentationLayout` - Main layout wrapper
542
+ - `NavigationBar` - Top navigation
543
+ - `LeftSidebar` - Left sidebar navigation
544
+ - `RightSidebar` - Right sidebar (TOC, contributors)
545
+ - `DocumentationFooter` - Footer
546
+ - `StructuredData` - JSON-LD renderer
547
+
548
+ ### Client Components
549
+
550
+ See the [Component Exports](#component-exports) section above for the complete list.
551
+
552
+ ## Contributing
553
+
554
+ Contributions are welcome! Please see our [contributing guide](../../CONTRIBUTING.md) for details.
555
+
556
+ ## License
557
+
558
+ MIT
559
+
560
+ ## Support
561
+
562
+ - [Documentation](https://docs.example.com)
563
+ - [GitHub Issues](https://github.com/your-org/your-library/issues)
564
+ - [Discussions](https://github.com/your-org/your-library/discussions)
565
+