@clidey/dory 0.27.0 → 0.30.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 (95) hide show
  1. package/bin/dist/dory.js +115 -29
  2. package/bin/dist/dory.js.map +1 -1
  3. package/package.json +12 -4
  4. package/.dockerignore +0 -4
  5. package/CLAUDE.md +0 -178
  6. package/CODE_OF_CONDUCT.md +0 -128
  7. package/CONTRIBUTING.md +0 -91
  8. package/SECURITY.md +0 -11
  9. package/bin/dory.ts +0 -433
  10. package/dist/favicon.svg +0 -75
  11. package/dist/frontmatter.json +0 -77
  12. package/dist/index.html +0 -55
  13. package/dist/llms.txt +0 -561
  14. package/dist/logo/logo.svg +0 -18
  15. package/docs/api-playground-demo.mdx +0 -119
  16. package/docs/api-reference/asyncapi.json +0 -324
  17. package/docs/api-reference/openapi.json +0 -366
  18. package/docs/api-reference/operations/create.mdx +0 -5
  19. package/docs/api-reference/operations/delete.mdx +0 -5
  20. package/docs/api-reference/operations/get.mdx +0 -5
  21. package/docs/api-reference/operations/update.mdx +0 -5
  22. package/docs/api-reference/websocket-operations/receive-chat-message.mdx +0 -5
  23. package/docs/api-reference/websocket-operations/receive-notifications.mdx +0 -5
  24. package/docs/api-reference/websocket-operations/receive-presence-update.mdx +0 -5
  25. package/docs/api-reference/websocket-operations/send-chat-message.mdx +0 -5
  26. package/docs/api-reference/websocket-operations/send-presence-update.mdx +0 -5
  27. package/docs/dory.json +0 -64
  28. package/docs/favicon.svg +0 -75
  29. package/docs/features.mdx +0 -440
  30. package/docs/introduction.mdx +0 -44
  31. package/docs/logo/logo.svg +0 -18
  32. package/docs/websocket-playground-demo.mdx +0 -135
  33. package/index.html +0 -54
  34. package/scripts/generate-frontmatter-json.js +0 -154
  35. package/scripts/generate-llm-txt.js +0 -115
  36. package/src/app.css +0 -5
  37. package/src/app.tsx +0 -13
  38. package/src/components/dropdown.tsx +0 -53
  39. package/src/components/hooks.tsx +0 -28
  40. package/src/components/loading.tsx +0 -21
  41. package/src/components/mdx-provider.tsx +0 -13
  42. package/src/components/navigation.tsx +0 -58
  43. package/src/components/notification.tsx +0 -13
  44. package/src/components/routes.tsx +0 -92
  45. package/src/components/search-index.ts +0 -43
  46. package/src/components/search.tsx +0 -435
  47. package/src/components/store.ts +0 -216
  48. package/src/config/mdx.js +0 -12
  49. package/src/config/mdx.ts +0 -12
  50. package/src/main.tsx +0 -22
  51. package/src/mdx/accordion.tsx +0 -41
  52. package/src/mdx/api-playground.tsx +0 -659
  53. package/src/mdx/api.tsx +0 -354
  54. package/src/mdx/async-api.tsx +0 -353
  55. package/src/mdx/callout.tsx +0 -64
  56. package/src/mdx/card.tsx +0 -54
  57. package/src/mdx/code.tsx +0 -289
  58. package/src/mdx/expandable.tsx +0 -36
  59. package/src/mdx/fence.tsx +0 -74
  60. package/src/mdx/icon.tsx +0 -73
  61. package/src/mdx/latex.tsx +0 -26
  62. package/src/mdx/list.tsx +0 -7
  63. package/src/mdx/mdx.tsx +0 -47
  64. package/src/mdx/mermaid.tsx +0 -147
  65. package/src/mdx/open-api.tsx +0 -311
  66. package/src/mdx/processor.ts +0 -174
  67. package/src/mdx/source.tsx +0 -58
  68. package/src/mdx/step.tsx +0 -51
  69. package/src/mdx/table.tsx +0 -20
  70. package/src/mdx/tag.tsx +0 -53
  71. package/src/mdx/text.tsx +0 -99
  72. package/src/mdx/websocket-playground.tsx +0 -824
  73. package/src/plugins/docs-assets.ts +0 -79
  74. package/src/plugins/frontmatter-dev-server.ts +0 -158
  75. package/src/plugins/frontmatter-generator.ts +0 -157
  76. package/src/plugins/llm-txt-dev-server.ts +0 -183
  77. package/src/plugins/llm-txt-generator.ts +0 -186
  78. package/src/plugins/sanitize.ts +0 -163
  79. package/src/plugins/unified-mdx-plugin.ts +0 -35
  80. package/src/theme.scss +0 -72
  81. package/src/types/config.ts +0 -47
  82. package/src/ui/header.tsx +0 -91
  83. package/src/ui/layout.tsx +0 -193
  84. package/src/ui/mobile-navigation.tsx +0 -64
  85. package/src/ui/prev-next-link.tsx +0 -74
  86. package/src/ui/table-of-content.tsx +0 -166
  87. package/src/utils/colors.ts +0 -54
  88. package/src/utils/fonts.ts +0 -23
  89. package/src/utils/functions.ts +0 -12
  90. package/src/vite-env.d.ts +0 -1
  91. package/tsconfig.app.json +0 -33
  92. package/tsconfig.bin.json +0 -24
  93. package/tsconfig.json +0 -7
  94. package/tsconfig.node.json +0 -26
  95. package/vite.config.ts +0 -41
@@ -1,154 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- import fs from 'fs';
4
- import path from 'path';
5
- import { fileURLToPath } from 'url';
6
-
7
- const __filename = fileURLToPath(import.meta.url);
8
- const __dirname = path.dirname(__filename);
9
-
10
- // Read dory.json to get navigation order (flat list, in order)
11
- function getNavigationOrder(docsDir) {
12
- const doryJsonPath = path.join(docsDir, 'dory.json');
13
- if (!fs.existsSync(doryJsonPath)) return [];
14
- const doryJson = JSON.parse(fs.readFileSync(doryJsonPath, 'utf-8'));
15
- const order = [];
16
-
17
- function walkPages(pages) {
18
- for (const page of pages) {
19
- if (typeof page === 'string') {
20
- order.push(page);
21
- } else if (typeof page === 'object' && page.pages) {
22
- walkPages(page.pages);
23
- }
24
- }
25
- }
26
-
27
- if (doryJson.navigation && Array.isArray(doryJson.navigation.tabs)) {
28
- for (const tab of doryJson.navigation.tabs) {
29
- if (tab.groups && Array.isArray(tab.groups)) {
30
- for (const group of tab.groups) {
31
- if (group.pages && Array.isArray(group.pages)) {
32
- walkPages(group.pages);
33
- }
34
- }
35
- }
36
- }
37
- }
38
- return order;
39
- }
40
-
41
- // Function to parse frontmatter from MDX content
42
- function parseFrontmatter(content) {
43
- const frontmatterMatch = content.match(/^---\n([\s\S]*?)\n---/);
44
- if (!frontmatterMatch) return { data: {}, content };
45
-
46
- const frontmatter = frontmatterMatch[1];
47
- const data = {};
48
-
49
- frontmatter.split('\n').forEach(line => {
50
- const [key, ...valueParts] = line.split(':');
51
- if (key && valueParts.length) {
52
- const value = valueParts.join(':').trim();
53
- data[key.trim()] = value.replace(/^["']|["']$/g, '');
54
- }
55
- });
56
-
57
- return { data, content: content.slice(frontmatterMatch[0].length) };
58
- }
59
-
60
- // Convert filename to path format used by the store
61
- function pathFromFilename(filename, docsDir) {
62
- return filename
63
- .replace(docsDir, '')
64
- .replace(/\/?index\.mdx$/, '/')
65
- .replace(/\.mdx$/, '')
66
- .replace(/\\/g, '/')
67
- .toLowerCase();
68
- }
69
-
70
- // Function to recursively find all MDX files and map by relative path (without .mdx)
71
- function findMdxFilesMap(dir, baseDir) {
72
- const files = {};
73
- const items = fs.readdirSync(dir, { withFileTypes: true });
74
-
75
- for (const item of items) {
76
- const fullPath = path.join(dir, item.name);
77
- if (item.isDirectory()) {
78
- Object.assign(files, findMdxFilesMap(fullPath, baseDir));
79
- } else if (item.isFile() && item.name.endsWith('.mdx')) {
80
- // Key: relative path without .mdx, with forward slashes
81
- let rel = path.relative(baseDir, fullPath).replace(/\\/g, '/');
82
- if (rel.endsWith('.mdx')) rel = rel.slice(0, -4);
83
- files[rel] = fullPath;
84
- }
85
- }
86
-
87
- return files;
88
- }
89
-
90
- // Main function to generate frontmatter JSON
91
- async function generateFrontmatterJson() {
92
- const docsDir = path.join(__dirname, '..', 'docs');
93
- const outputDir = path.join(__dirname, '..', 'dist');
94
-
95
- // Ensure output directory exists
96
- if (!fs.existsSync(outputDir)) {
97
- fs.mkdirSync(outputDir, { recursive: true });
98
- }
99
-
100
- const navOrder = getNavigationOrder(docsDir);
101
- const mdxFilesMap = findMdxFilesMap(docsDir, docsDir);
102
- const usedKeys = new Set();
103
- const frontmatterArray = [];
104
-
105
- // Process files in navigation order first
106
- for (const navKey of navOrder) {
107
- // Try both with and without "index"
108
- let fileKey = navKey;
109
- if (mdxFilesMap[fileKey]) {
110
- usedKeys.add(fileKey);
111
- } else if (mdxFilesMap[`${fileKey}/index`]) {
112
- fileKey = `${fileKey}/index`;
113
- usedKeys.add(fileKey);
114
- } else {
115
- continue;
116
- }
117
-
118
- const filePath = mdxFilesMap[fileKey];
119
- const rawContent = fs.readFileSync(filePath, 'utf-8');
120
- const { data } = parseFrontmatter(rawContent);
121
- const pathname = pathFromFilename(filePath, docsDir);
122
-
123
- frontmatterArray.push({
124
- ...data,
125
- path: pathname
126
- });
127
- }
128
-
129
- // Process any extra files not in navigation order, sorted
130
- const extraKeys = Object.keys(mdxFilesMap).filter(k => !usedKeys.has(k)).sort();
131
- for (const fileKey of extraKeys) {
132
- const filePath = mdxFilesMap[fileKey];
133
- const rawContent = fs.readFileSync(filePath, 'utf-8');
134
- const { data } = parseFrontmatter(rawContent);
135
- const pathname = pathFromFilename(filePath, docsDir);
136
-
137
- frontmatterArray.push({
138
- ...data,
139
- path: pathname
140
- });
141
- }
142
-
143
- // Write to output file
144
- const jsonContent = JSON.stringify(frontmatterArray, null, 2);
145
- const outputPath = path.join(outputDir, 'frontmatter.json');
146
- fs.writeFileSync(outputPath, jsonContent);
147
-
148
- console.log(`✅ Generated frontmatter JSON file: ${outputPath}`);
149
- console.log(`📄 Processed ${frontmatterArray.length} MDX files`);
150
- console.log(`📝 Total JSON size: ${jsonContent.length} characters`);
151
- }
152
-
153
- // Run the script
154
- generateFrontmatterJson().catch(console.error);
@@ -1,115 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- import fs from 'fs';
4
- import path from 'path';
5
- import { fileURLToPath } from 'url';
6
-
7
- const __filename = fileURLToPath(import.meta.url);
8
- const __dirname = path.dirname(__filename);
9
-
10
- // Function to parse frontmatter from MDX content
11
- function parseFrontmatter(content) {
12
- const frontmatterMatch = content.match(/^---\n([\s\S]*?)\n---\n/);
13
- if (!frontmatterMatch) return { data: {}, content };
14
-
15
- const frontmatter = frontmatterMatch[1];
16
- const data = {};
17
-
18
- frontmatter.split('\n').forEach(line => {
19
- const [key, ...valueParts] = line.split(':');
20
- if (key && valueParts.length) {
21
- const value = valueParts.join(':').trim();
22
- data[key.trim()] = value.replace(/^["']|["']$/g, '');
23
- }
24
- });
25
-
26
- return { data, content: content.slice(frontmatterMatch[0].length) };
27
- }
28
-
29
- // Function to recursively find all MDX files
30
- function findMdxFiles(dir) {
31
- const files = [];
32
- const items = fs.readdirSync(dir, { withFileTypes: true });
33
-
34
- for (const item of items) {
35
- const fullPath = path.join(dir, item.name);
36
- if (item.isDirectory()) {
37
- files.push(...findMdxFiles(fullPath));
38
- } else if (item.isFile() && item.name.endsWith('.mdx')) {
39
- files.push(fullPath);
40
- }
41
- }
42
-
43
- return files;
44
- }
45
-
46
- // Function to clean MDX content for LLM consumption
47
- function cleanMdxContent(content) {
48
- // Remove JSX components but keep their content
49
- let cleaned = content
50
- // Remove JSX opening/closing tags but keep content
51
- .replace(/<(\w+)([^>]*?)>/g, '')
52
- .replace(/<\/\w+>/g, '')
53
- // Remove code block language specifiers
54
- .replace(/```(\w+)/g, '```')
55
- // Remove HTML comments
56
- .replace(/<!--[\s\S]*?-->/g, '')
57
- // Remove excessive whitespace
58
- .replace(/\n\s*\n\s*\n/g, '\n\n')
59
- // Remove leading/trailing whitespace
60
- .trim();
61
-
62
- return cleaned;
63
- }
64
-
65
- // Main function to generate LLM text
66
- async function generateLlmTxt() {
67
- const docsDir = path.join(__dirname, '..', 'docs');
68
- const outputDir = path.join(__dirname, '..', 'dist');
69
-
70
- // Ensure output directory exists
71
- if (!fs.existsSync(outputDir)) {
72
- fs.mkdirSync(outputDir, { recursive: true });
73
- }
74
-
75
- const mdxFiles = findMdxFiles(docsDir);
76
- let aggregatedContent = '';
77
-
78
- // Sort files for consistent output
79
- mdxFiles.sort();
80
-
81
- for (const filePath of mdxFiles) {
82
- const rawContent = fs.readFileSync(filePath, 'utf-8');
83
- const { data, content } = parseFrontmatter(rawContent);
84
- const cleanedContent = cleanMdxContent(content);
85
-
86
- // Add file header
87
- const relativePath = path.relative(docsDir, filePath);
88
- aggregatedContent += `\n# ${relativePath}\n`;
89
-
90
- // Add title if available
91
- if (data.title) {
92
- aggregatedContent += `## ${data.title}\n\n`;
93
- }
94
-
95
- // Add description if available
96
- if (data.description) {
97
- aggregatedContent += `${data.description}\n\n`;
98
- }
99
-
100
- // Add cleaned content
101
- aggregatedContent += cleanedContent + '\n\n';
102
- aggregatedContent += '---\n\n';
103
- }
104
-
105
- // Write to output file
106
- const outputPath = path.join(outputDir, 'llms.txt');
107
- fs.writeFileSync(outputPath, aggregatedContent.trim());
108
-
109
- console.log(`✅ Generated LLM text file: ${outputPath}`);
110
- console.log(`📄 Processed ${mdxFiles.length} MDX files`);
111
- console.log(`📝 Total content size: ${aggregatedContent.length} characters`);
112
- }
113
-
114
- // Run the script
115
- generateLlmTxt().catch(console.error);
package/src/app.css DELETED
@@ -1,5 +0,0 @@
1
- @import "tailwindcss";
2
-
3
- @custom-variant dark (&:where(.dark, .dark *));
4
-
5
-
package/src/app.tsx DELETED
@@ -1,13 +0,0 @@
1
- import './app.css'
2
- import './theme.scss'
3
- import Routes from './components/routes'
4
-
5
- export function App() {
6
- return (
7
- <div className="h-full antialiased">
8
- <div className="flex min-h-full">
9
- <Routes />
10
- </div>
11
- </div>
12
- )
13
- }
@@ -1,53 +0,0 @@
1
- import {
2
- DropdownMenu,
3
- DropdownMenuTrigger,
4
- DropdownMenuContent,
5
- DropdownMenuItem,
6
- DropdownMenuSeparator,
7
- Button
8
- } from '@clidey/ux'
9
- import { ChevronDownIcon } from '@heroicons/react/20/solid'
10
- import type { ComponentChildren } from 'preact'
11
- import type { ReactNode } from 'preact/compat'
12
-
13
- interface DropdownItem {
14
- icon?: ComponentChildren
15
- label: string
16
- href?: string
17
- onClick?: () => void
18
- divider?: boolean
19
- }
20
-
21
- interface DropdownProps {
22
- buttonLabel: string | ReactNode;
23
- items: DropdownItem[]
24
- className?: string
25
- }
26
-
27
- export default function Dropdown({ buttonLabel, items, className = '' }: DropdownProps) {
28
- return (
29
- <DropdownMenu>
30
- <DropdownMenuTrigger>
31
- <Button className={className}>
32
- {buttonLabel}
33
- <ChevronDownIcon className="ml-2 h-4 w-4" />
34
- </Button>
35
- </DropdownMenuTrigger>
36
- <DropdownMenuContent>
37
- {items.map((item, index) => (
38
- <>
39
- {item.divider && index > 0 && <DropdownMenuSeparator />}
40
- <DropdownMenuItem
41
- key={index}
42
- onClick={item.onClick}
43
- className="cursor-pointer"
44
- >
45
- {item.icon && <span className="mr-2">{item.icon}</span>}
46
- {item.label}
47
- </DropdownMenuItem>
48
- </>
49
- ))}
50
- </DropdownMenuContent>
51
- </DropdownMenu>
52
- )
53
- }
@@ -1,28 +0,0 @@
1
- import { useEffect, useState } from 'preact/hooks';
2
- import { useLocation } from 'wouter-preact';
3
-
4
- /**
5
- * Custom hook to get the current pathname
6
- */
7
- export const usePathname = () => {
8
- const [pathname] = useLocation();
9
- return pathname;
10
- };
11
-
12
- /**
13
- * Custom hook to get the URL search params as a URLSearchParams instance
14
- */
15
- export const useSearchParams = () => {
16
- const [searchParams, setSearchParams] = useState(new URLSearchParams(window.location.search));
17
-
18
- useEffect(() => {
19
- const handlePopState = () => {
20
- setSearchParams(new URLSearchParams(window.location.search));
21
- };
22
-
23
- window.addEventListener('popstate', handlePopState);
24
- return () => window.removeEventListener('popstate', handlePopState);
25
- }, []);
26
-
27
- return searchParams;
28
- };
@@ -1,21 +0,0 @@
1
- import { Spinner } from '@clidey/ux';
2
- import classNames from "classnames";
3
-
4
- type ILoadingProps = {
5
- className?: string;
6
- showText?: boolean;
7
- loadingText?: string;
8
- textClassName?: string;
9
- }
10
-
11
- export const Loading = ({ className, showText = false, loadingText, textClassName }: ILoadingProps) => {
12
- return (
13
- <div className="h-full w-full flex flex-col justify-center items-center gap-2 min-h-[400px]" role="status">
14
- <Spinner className={className} />
15
- {
16
- showText &&
17
- <div className={classNames("text-sm text-gray-500", textClassName)}>{ loadingText ?? "Loading..."}</div>
18
- }
19
- </div>
20
- )
21
- }
@@ -1,13 +0,0 @@
1
- import { MDXProvider } from '@mdx-js/preact';
2
- import Layout from '../ui/layout';
3
- import * as mdx from '../mdx/mdx';
4
-
5
- export const withMDX = (Content: preact.ComponentType) => () => {
6
- return (
7
- <MDXProvider components={mdx}>
8
- <Layout>
9
- <Content />
10
- </Layout>
11
- </MDXProvider>
12
- );
13
- };
@@ -1,58 +0,0 @@
1
- import classNames from 'classnames';
2
- import { useMemo } from 'preact/hooks';
3
- import { Link } from 'wouter-preact';
4
- import { usePathname } from './hooks';
5
- import { ALL_NAVIGATION } from './store';
6
-
7
- export function Navigation() {
8
- const pathname = usePathname();
9
-
10
- const effectivePath = pathname === '/'
11
- ? ALL_NAVIGATION[0]?.groups[0]?.pages[0]?.href ?? '/'
12
- : pathname;
13
-
14
- const currentTab = useMemo(() => {
15
- return ALL_NAVIGATION.find(tab =>
16
- tab.groups.some(group =>
17
- group.pages.some(page => page.href === effectivePath)
18
- )
19
- );
20
- }, [effectivePath]);
21
-
22
- return (
23
- <nav className="dory-navigation text-base lg:text-sm">
24
- <ul role="list" className="space-y-9">
25
- {currentTab && (
26
- <li key={currentTab.title}>
27
- <h2 className="font-display font-medium text-xs">{currentTab.title}</h2>
28
- {currentTab.groups.map(group => (
29
- <div key={group.title}>
30
- <h3 className="mt-4 text-sm font-semibold">{group.title}</h3>
31
- <ul role="list" className="mt-2 space-y-2 border-l-2 border-slate-100 lg:mt-4 lg:space-y-4 lg:border-slate-200 dark:border-slate-800">
32
- {group.pages.map((page) => {
33
- const isActive = effectivePath === page.href;
34
- return (
35
- <li key={page.href} className="relative">
36
- <Link
37
- href={page.href}
38
- className={classNames(
39
- 'block w-full pl-3.5 before:pointer-events-none before:absolute before:top-1/2 before:-left-1 before:h-1.5 before:w-1.5 before:-translate-y-1/2 before:rounded-full',
40
- {
41
- 'font-semibold text-brand-foreground': isActive,
42
- 'text-slate-500 before:hidden before:bg-slate-300 hover:text-slate-600 hover:before:block dark:text-slate-400 dark:before:bg-slate-700 dark:hover:text-slate-300': !isActive
43
- },
44
- )}>
45
- {page.title}
46
- </Link>
47
- </li>
48
- );
49
- })}
50
- </ul>
51
- </div>
52
- ))}
53
- </li>
54
- )}
55
- </ul>
56
- </nav>
57
- );
58
- }
@@ -1,13 +0,0 @@
1
- import { toast } from '@clidey/ux';
2
- import { InfoIcon } from 'lucide-react';
3
-
4
- export function useNotification() {
5
- return {
6
- showNotification: (message: string, description?: string) => {
7
- toast(message, {
8
- icon: <InfoIcon className="h-4 w-4" />,
9
- description: description,
10
- });
11
- }
12
- };
13
- }
@@ -1,92 +0,0 @@
1
- import { useEffect, useState } from 'preact/hooks';
2
- import { Route, Router, useLocation } from 'wouter-preact';
3
- import { usePathname } from './hooks';
4
- import { ALL_NAVIGATION, ALL_PAGES, pathFromFilename } from './store';
5
- import { Loading } from './loading';
6
-
7
-
8
- export default function Routes() {
9
- const [routes, setRoutes] = useState<any[]>([]);
10
- const pathname = usePathname();
11
- const [, navigate] = useLocation();
12
- const [loading, setLoading] = useState(true);
13
-
14
- useEffect(() => {
15
- const links = document.querySelectorAll('.dory-navigation a');
16
- const listeners: (() => void)[] = [];
17
- const preloaded = new Set();
18
-
19
- links.forEach(link => {
20
- const href = link.getAttribute('href');
21
- if (!href) return;
22
-
23
- const loaderEntry = Object.entries(ALL_PAGES).find(
24
- ([path]) => path === href
25
- );
26
-
27
- if (!loaderEntry) return;
28
-
29
- const [path, loader] = loaderEntry;
30
-
31
- const handleMouseEnter = () => {
32
- if (!preloaded.has(path)) {
33
- loader();
34
- preloaded.add(path);
35
- }
36
- };
37
-
38
- link.addEventListener('mouseenter', handleMouseEnter);
39
- listeners.push(() => link.removeEventListener('mouseenter', handleMouseEnter));
40
- });
41
-
42
- return () => {
43
- listeners.forEach(unsub => unsub());
44
- };
45
- }, []);
46
-
47
- useEffect(() => {
48
- setLoading(true);
49
- const loadRoutes = async () => {
50
- // For root path, load the first navigation page
51
- const targetPath = pathname === '/' ? ALL_NAVIGATION[0].groups[0].pages[0].href : pathname;
52
-
53
- const entries = await Promise.all(
54
- Object.entries(ALL_PAGES).filter(([path]) => path === targetPath).map(async ([path, loader]) => {
55
- const module = await loader();
56
- const routePath = pathname === '/' ? '/' : pathFromFilename(path);
57
- return {
58
- path: routePath,
59
- component: module.default,
60
- };
61
- })
62
- );
63
- setRoutes(entries);
64
- setLoading(false);
65
- };
66
-
67
- loadRoutes();
68
- }, [pathname]);
69
-
70
- useEffect(() => {
71
- const page = ALL_NAVIGATION.find((tab) => tab.groups.find((group) => group.pages.find((page) => page.href === pathname)));
72
- if (!page && pathname !== '/') {
73
- navigate(ALL_NAVIGATION[0].groups[0].pages[0].href);
74
- window.location.reload();
75
- }
76
- }, [routes, pathname]);
77
-
78
- useEffect(() => {
79
- window.scrollTo({ top: 0, behavior: 'smooth' });
80
- }, [pathname]);
81
-
82
-
83
- if (loading) return <div className="h-[25vh] flex grow"><Loading /></div>;
84
-
85
- return (
86
- <Router>
87
- {routes.map(({ path, component: Component }) => (
88
- <Route key={path} path={path} component={Component} />
89
- ))}
90
- </Router>
91
- );
92
- }
@@ -1,43 +0,0 @@
1
- import { Document } from "flexsearch";
2
-
3
- export const searchIndex = new Document({
4
- tokenize: 'full',
5
- document: {
6
- id: 'url',
7
- index: 'content',
8
- store: ['title', 'pageTitle'],
9
- },
10
- context: {
11
- resolution: 9,
12
- depth: 2,
13
- bidirectional: true
14
- }
15
- });
16
-
17
- export function addToSearchIndex(filename: string, data: any, content: string) {
18
- searchIndex.add({
19
- url: filename,
20
- title: data.title || '',
21
- content: content,
22
- pageTitle: data.title
23
- });
24
- }
25
-
26
- export function search(query: string, options = {}) {
27
- if (!searchIndex) return [];
28
-
29
- const result = searchIndex.search(query, {
30
- ...options,
31
- enrich: true,
32
- });
33
-
34
- if (result.length === 0) {
35
- return [];
36
- }
37
-
38
- return result[0].result.map((item) => ({
39
- url: item.id,
40
- title: item.doc?.title || '',
41
- pageTitle: item.doc?.pageTitle || '',
42
- }));
43
- }