polen 0.10.0-next.5 → 0.10.0-next.7
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/build/api/content/$$.d.ts +1 -0
- package/build/api/content/$$.d.ts.map +1 -1
- package/build/api/content/$$.js +1 -0
- package/build/api/content/$$.js.map +1 -1
- package/build/api/content/navbar.d.ts +10 -0
- package/build/api/content/navbar.d.ts.map +1 -0
- package/build/api/content/navbar.js +45 -0
- package/build/api/content/navbar.js.map +1 -0
- package/build/api/content/sidebar.d.ts +85 -5
- package/build/api/content/sidebar.d.ts.map +1 -1
- package/build/api/content/sidebar.js +151 -75
- package/build/api/content/sidebar.js.map +1 -1
- package/build/api/vite/plugins/pages.d.ts +1 -4
- package/build/api/vite/plugins/pages.d.ts.map +1 -1
- package/build/api/vite/plugins/pages.js +4 -42
- package/build/api/vite/plugins/pages.js.map +1 -1
- package/build/lib/file-router/scan.d.ts.map +1 -1
- package/build/lib/file-router/scan.js +6 -1
- package/build/lib/file-router/scan.js.map +1 -1
- package/build/sandbox.js +17 -2
- package/build/sandbox.js.map +1 -1
- package/build/template/components/HamburgerMenu.d.ts +9 -0
- package/build/template/components/HamburgerMenu.d.ts.map +1 -0
- package/build/template/components/HamburgerMenu.jsx +53 -0
- package/build/template/components/HamburgerMenu.jsx.map +1 -0
- package/build/template/components/NotFound.d.ts +2 -0
- package/build/template/components/NotFound.d.ts.map +1 -0
- package/build/template/components/NotFound.jsx +26 -0
- package/build/template/components/NotFound.jsx.map +1 -0
- package/build/template/components/ThemeToggle.d.ts +3 -0
- package/build/template/components/ThemeToggle.d.ts.map +1 -0
- package/build/template/components/ThemeToggle.jsx +10 -0
- package/build/template/components/ThemeToggle.jsx.map +1 -0
- package/build/template/contexts/ThemeContext.d.ts +12 -0
- package/build/template/contexts/ThemeContext.d.ts.map +1 -0
- package/build/template/contexts/ThemeContext.jsx +41 -0
- package/build/template/contexts/ThemeContext.jsx.map +1 -0
- package/build/template/routes/root.d.ts.map +1 -1
- package/build/template/routes/root.jsx +55 -39
- package/build/template/routes/root.jsx.map +1 -1
- package/package.json +1 -1
- package/src/api/content/$$.ts +1 -0
- package/src/api/content/navbar.test.ts +55 -0
- package/src/api/content/navbar.ts +61 -0
- package/src/api/content/sidebar.test.ts +297 -0
- package/src/api/content/sidebar.ts +235 -88
- package/src/api/vite/plugins/pages.ts +5 -51
- package/src/lib/file-router/scan.ts +7 -1
- package/src/sandbox.ts +20 -1
- package/src/template/components/HamburgerMenu.tsx +96 -0
- package/src/template/components/NotFound.tsx +28 -0
- package/src/template/components/ThemeToggle.tsx +21 -0
- package/src/template/contexts/ThemeContext.tsx +60 -0
- package/src/template/routes/root.tsx +74 -51
@@ -59,7 +59,12 @@ export const filePathToRoute = (filePathExpression, rootDir) => {
|
|
59
59
|
};
|
60
60
|
};
|
61
61
|
export const filePathToRouteLogical = (filePath) => {
|
62
|
-
const
|
62
|
+
const dirSegments = Str.split(Str.removeSurrounding(filePath.dir, Path.sep), Path.sep);
|
63
|
+
// Parse numbered prefixes from directory segments
|
64
|
+
const dirPath = dirSegments.map(segment => {
|
65
|
+
const prefixMatch = Str.match(segment, conventions.numberedPrefix.pattern);
|
66
|
+
return prefixMatch?.groups.name ?? segment;
|
67
|
+
});
|
63
68
|
// Parse numbered prefix from filename
|
64
69
|
const prefixMatch = Str.match(filePath.name, conventions.numberedPrefix.pattern);
|
65
70
|
const order = prefixMatch ? parseInt(prefixMatch.groups.order, 10) : undefined;
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"scan.js","sourceRoot":"","sources":["../../../src/lib/file-router/scan.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAA;AACnD,OAAO,EAAE,IAAI,EAAE,GAAG,EAAE,MAAM,iBAAiB,CAAA;AAC3C,OAAO,EAAmB,IAAI,EAAE,MAAM,aAAa,CAAA;AACnD,OAAO,EAAiD,MAAM,YAAY,CAAA;AAE1E,EAAE;AACF,EAAE;AACF,EAAE;AACF,EAAE;AACF,yDAAyD;AACzD,EAAE;AACF,EAAE;AAEF,MAAM,WAAW,GAAG;IAClB,KAAK,EAAE;QACL,IAAI,EAAE,OAAO;KACd;IACD,cAAc,EAAE;QACd,OAAO,EAAE,GAAG,CAAC,OAAO,CAAgC,gCAAgC,CAAC;KACtF;CACF,CAAA;AAeD,EAAE;AACF,EAAE;AACF,EAAE;AACF,EAAE;AACF,oDAAoD;AACpD,EAAE;AACF,EAAE;AAEF,MAAM,CAAC,MAAM,IAAI,GAAG,KAAK,EAAE,UAG1B,EAAuB,EAAE;IACxB,MAAM,EAAE,GAAG,EAAE,IAAI,GAAG,eAAe,EAAE,GAAG,UAAU,CAAA;IAElD,yBAAyB;IACzB,MAAM,SAAS,GAAG,MAAM,UAAU,CAAC,IAAI,CAAC,IAAI,EAAE;QAC5C,QAAQ,EAAE,IAAI;QACd,GAAG,EAAE,GAAG;QACR,SAAS,EAAE,IAAI;KAChB,CAAC,CAAA;IAEF,oBAAoB;IACpB,MAAM,MAAM,GAAG,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,eAAe,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC,CAAA;IAExE,gBAAgB;IAChB,MAAM,UAAU,GAAG,IAAI,CAAC,MAAM,CAAC,CAAA;IAE/B,OAAO,UAAU,CAAA;AACnB,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,kBAA0B,EAAE,OAAe,EAAS,EAAE;IACpF,MAAM,IAAI,GAAc;QACtB,IAAI,EAAE;YACJ,QAAQ,EAAE,IAAI,CAAC,KAAK,CAAC,kBAAkB,CAAC;YACxC,QAAQ,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,EAAE,kBAAkB,CAAC,CAAC;SACjE;KACF,CAAA;IACD,MAAM,OAAO,GAAG,sBAAsB,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;IAE1D,6CAA6C;IAC7C,MAAM,EAAE,GAAG,kBAAkB,CAAA,CAAC,iCAAiC;IAC/D,MAAM,YAAY,GAAG,IAAI,CAAC,QAAQ,CAAC,OAAO,EAAE,kBAAkB,CAAC,CAAA;IAC/D,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,YAAY,CAAC,CAAA;IAC5C,MAAM,QAAQ,GAAG,SAAS,KAAK,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,SAAS,CAAC,CAAA;IAEzE,OAAO;QACL,OAAO;QACP,IAAI;QACJ,EAAE;QACF,QAAQ;KACT,CAAA;AACH,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,sBAAsB,GAAG,CAAC,QAAqB,EAAgB,EAAE;IAC5E,MAAM,
|
1
|
+
{"version":3,"file":"scan.js","sourceRoot":"","sources":["../../../src/lib/file-router/scan.ts"],"names":[],"mappings":"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"}
|
package/build/sandbox.js
CHANGED
@@ -1,3 +1,18 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
import { filePathToRouteLogical } from '#lib/file-router/scan';
|
2
|
+
import { Path } from '@wollybeard/kit';
|
3
|
+
// Test parsing of numbered directory
|
4
|
+
const testPath1 = Path.parse('a/10_b/index.md');
|
5
|
+
const logical1 = filePathToRouteLogical(testPath1);
|
6
|
+
console.log('Path 1:', testPath1);
|
7
|
+
console.log('Logical 1:', logical1);
|
8
|
+
// Test parsing of numbered file
|
9
|
+
const testPath2 = Path.parse('a/10_b/g.md');
|
10
|
+
const logical2 = filePathToRouteLogical(testPath2);
|
11
|
+
console.log('\nPath 2:', testPath2);
|
12
|
+
console.log('Logical 2:', logical2);
|
13
|
+
// Test directory structure
|
14
|
+
const testPath3 = Path.parse('a/30_d/index.md');
|
15
|
+
const logical3 = filePathToRouteLogical(testPath3);
|
16
|
+
console.log('\nPath 3:', testPath3);
|
17
|
+
console.log('Logical 3:', logical3);
|
3
18
|
//# sourceMappingURL=sandbox.js.map
|
package/build/sandbox.js.map
CHANGED
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"sandbox.js","sourceRoot":"","sources":["../src/sandbox.ts"],"names":[],"mappings":"
|
1
|
+
{"version":3,"file":"sandbox.js","sourceRoot":"","sources":["../src/sandbox.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAA;AAC9D,OAAO,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAA;AAEtC,qCAAqC;AACrC,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,iBAAiB,CAAC,CAAA;AAC/C,MAAM,QAAQ,GAAG,sBAAsB,CAAC,SAAS,CAAC,CAAA;AAClD,OAAO,CAAC,GAAG,CAAC,SAAS,EAAE,SAAS,CAAC,CAAA;AACjC,OAAO,CAAC,GAAG,CAAC,YAAY,EAAE,QAAQ,CAAC,CAAA;AAEnC,gCAAgC;AAChC,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,aAAa,CAAC,CAAA;AAC3C,MAAM,QAAQ,GAAG,sBAAsB,CAAC,SAAS,CAAC,CAAA;AAClD,OAAO,CAAC,GAAG,CAAC,WAAW,EAAE,SAAS,CAAC,CAAA;AACnC,OAAO,CAAC,GAAG,CAAC,YAAY,EAAE,QAAQ,CAAC,CAAA;AAEnC,2BAA2B;AAC3B,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,iBAAiB,CAAC,CAAA;AAC/C,MAAM,QAAQ,GAAG,sBAAsB,CAAC,SAAS,CAAC,CAAA;AAClD,OAAO,CAAC,GAAG,CAAC,WAAW,EAAE,SAAS,CAAC,CAAA;AACnC,OAAO,CAAC,GAAG,CAAC,YAAY,EAAE,QAAQ,CAAC,CAAA"}
|
@@ -0,0 +1,9 @@
|
|
1
|
+
import type { Content } from '#api/content/$';
|
2
|
+
export interface HamburgerMenuProps {
|
3
|
+
isOpen: boolean;
|
4
|
+
onToggle: () => void;
|
5
|
+
onClose: () => void;
|
6
|
+
sidebarData: Content.Item[];
|
7
|
+
}
|
8
|
+
export declare const HamburgerMenu: React.FC<HamburgerMenuProps>;
|
9
|
+
//# sourceMappingURL=HamburgerMenu.d.ts.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"HamburgerMenu.d.ts","sourceRoot":"","sources":["../../../src/template/components/HamburgerMenu.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAA;AAM7C,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,OAAO,CAAA;IACf,QAAQ,EAAE,MAAM,IAAI,CAAA;IACpB,OAAO,EAAE,MAAM,IAAI,CAAA;IACnB,WAAW,EAAE,OAAO,CAAC,IAAI,EAAE,CAAA;CAC5B;AAED,eAAO,MAAM,aAAa,EAAE,KAAK,CAAC,EAAE,CAAC,kBAAkB,CAkFtD,CAAA"}
|
@@ -0,0 +1,53 @@
|
|
1
|
+
import { Cross2Icon, HamburgerMenuIcon } from '@radix-ui/react-icons';
|
2
|
+
import { Box, Flex, IconButton, Text } from '@radix-ui/themes';
|
3
|
+
import { useEffect } from 'react';
|
4
|
+
import { Sidebar } from "../components/sidebar/Sidebar.jsx";
|
5
|
+
export const HamburgerMenu = ({ isOpen, onToggle, onClose, sidebarData, }) => {
|
6
|
+
// Prevent body scroll when mobile menu is open
|
7
|
+
useEffect(() => {
|
8
|
+
if (isOpen) {
|
9
|
+
document.body.style.overflow = 'hidden';
|
10
|
+
}
|
11
|
+
else {
|
12
|
+
document.body.style.overflow = '';
|
13
|
+
}
|
14
|
+
// Cleanup
|
15
|
+
return () => {
|
16
|
+
document.body.style.overflow = '';
|
17
|
+
};
|
18
|
+
}, [isOpen]);
|
19
|
+
return (<>
|
20
|
+
{/* Mobile menu button - show on mobile/tablet, hide on desktop */}
|
21
|
+
<Box display={{ initial: 'block', xs: 'block', sm: 'block', md: 'none', lg: 'none', xl: 'none' }}>
|
22
|
+
<IconButton size='2' variant='ghost' onClick={onToggle} aria-label='Toggle navigation menu'>
|
23
|
+
{isOpen ? <Cross2Icon width='18' height='18'/> : <HamburgerMenuIcon width='18' height='18'/>}
|
24
|
+
</IconButton>
|
25
|
+
</Box>
|
26
|
+
|
27
|
+
{/* Mobile Sidebar Drawer */}
|
28
|
+
{isOpen && (<>
|
29
|
+
{/* Backdrop */}
|
30
|
+
<Box position='fixed' inset='0' style={{
|
31
|
+
backgroundColor: 'var(--black-a9)',
|
32
|
+
zIndex: 50,
|
33
|
+
}} onClick={onClose} display={{ initial: 'block', xs: 'block', sm: 'block', md: 'none', lg: 'none', xl: 'none' }}/>
|
34
|
+
|
35
|
+
{/* Drawer */}
|
36
|
+
<Box position='fixed' top='0' left='0' bottom='0' width='280px' style={{
|
37
|
+
backgroundColor: 'var(--color-background)',
|
38
|
+
boxShadow: 'var(--shadow-6)',
|
39
|
+
zIndex: 100,
|
40
|
+
overflowY: 'auto',
|
41
|
+
}} p='4' display={{ initial: 'block', xs: 'block', sm: 'block', md: 'none', lg: 'none', xl: 'none' }}>
|
42
|
+
<Flex justify='between' align='center' mb='4'>
|
43
|
+
<Text size='5' weight='bold'>Navigation</Text>
|
44
|
+
<IconButton size='2' variant='ghost' onClick={onClose} aria-label='Close navigation menu'>
|
45
|
+
<Cross2Icon width='18' height='18'/>
|
46
|
+
</IconButton>
|
47
|
+
</Flex>
|
48
|
+
<Sidebar data={sidebarData}/>
|
49
|
+
</Box>
|
50
|
+
</>)}
|
51
|
+
</>);
|
52
|
+
};
|
53
|
+
//# sourceMappingURL=HamburgerMenu.jsx.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"HamburgerMenu.jsx","sourceRoot":"","sources":["../../../src/template/components/HamburgerMenu.tsx"],"names":[],"mappings":"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"}
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"NotFound.d.ts","sourceRoot":"","sources":["../../../src/template/components/NotFound.tsx"],"names":[],"mappings":"AAGA,eAAO,MAAM,QAAQ,EAAE,KAAK,CAAC,EAwB5B,CAAA"}
|
@@ -0,0 +1,26 @@
|
|
1
|
+
import { Box, Button, Flex, Heading, Text } from '@radix-ui/themes';
|
2
|
+
import { Link as LinkReactRouter } from 'react-router';
|
3
|
+
export const NotFound = () => {
|
4
|
+
return (<Flex direction='column' align='center' gap='6' style={{ textAlign: `center`, paddingTop: `4rem` }}>
|
5
|
+
<Heading size='9' style={{ color: `var(--gray-12)` }}>404</Heading>
|
6
|
+
<Box>
|
7
|
+
<Heading size='5' mb='2'>Page Not Found</Heading>
|
8
|
+
<Text size='3' color='gray'>
|
9
|
+
The page you're looking for doesn't exist or has been moved.
|
10
|
+
</Text>
|
11
|
+
</Box>
|
12
|
+
<Flex gap='3'>
|
13
|
+
<LinkReactRouter to='/'>
|
14
|
+
<Button variant='soft' size='3'>
|
15
|
+
Go Home
|
16
|
+
</Button>
|
17
|
+
</LinkReactRouter>
|
18
|
+
<LinkReactRouter to='/reference'>
|
19
|
+
<Button variant='outline' size='3'>
|
20
|
+
View API Reference
|
21
|
+
</Button>
|
22
|
+
</LinkReactRouter>
|
23
|
+
</Flex>
|
24
|
+
</Flex>);
|
25
|
+
};
|
26
|
+
//# sourceMappingURL=NotFound.jsx.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"NotFound.jsx","sourceRoot":"","sources":["../../../src/template/components/NotFound.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAA;AACnE,OAAO,EAAE,IAAI,IAAI,eAAe,EAAE,MAAM,cAAc,CAAA;AAEtD,MAAM,CAAC,MAAM,QAAQ,GAAa,GAAG,EAAE;IACrC,OAAO,CACL,CAAC,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,SAAS,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,EAAE,CAAC,CACjG;MAAA,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,EAAE,gBAAgB,EAAE,CAAC,CAAC,GAAG,EAAE,OAAO,CAClE;MAAA,CAAC,GAAG,CACF;QAAA,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,cAAc,EAAE,OAAO,CAChD;QAAA,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CACzB;;QACF,EAAE,IAAI,CACR;MAAA,EAAE,GAAG,CACL;MAAA,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CACX;QAAA,CAAC,eAAe,CAAC,EAAE,CAAC,GAAG,CACrB;UAAA,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAC7B;;UACF,EAAE,MAAM,CACV;QAAA,EAAE,eAAe,CACjB;QAAA,CAAC,eAAe,CAAC,EAAE,CAAC,YAAY,CAC9B;UAAA,CAAC,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,IAAI,CAAC,GAAG,CAChC;;UACF,EAAE,MAAM,CACV;QAAA,EAAE,eAAe,CACnB;MAAA,EAAE,IAAI,CACR;IAAA,EAAE,IAAI,CAAC,CACR,CAAA;AACH,CAAC,CAAA"}
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"ThemeToggle.d.ts","sourceRoot":"","sources":["../../../src/template/components/ThemeToggle.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAA;AAK7C,eAAO,MAAM,WAAW,EAAE,KAAK,CAAC,EAe/B,CAAA"}
|
@@ -0,0 +1,10 @@
|
|
1
|
+
import { MoonIcon, SunIcon } from '@radix-ui/react-icons';
|
2
|
+
import { IconButton } from '@radix-ui/themes';
|
3
|
+
import { useTheme } from "../contexts/ThemeContext.jsx";
|
4
|
+
export const ThemeToggle = () => {
|
5
|
+
const { appearance, toggleTheme } = useTheme();
|
6
|
+
return (<IconButton size='2' variant='ghost' color='gray' onClick={toggleTheme} aria-label={`Switch to ${appearance === 'light' ? 'dark' : 'light'} theme`} style={{ cursor: 'pointer' }}>
|
7
|
+
{appearance === 'light' ? <MoonIcon width='18' height='18'/> : <SunIcon width='18' height='18'/>}
|
8
|
+
</IconButton>);
|
9
|
+
};
|
10
|
+
//# sourceMappingURL=ThemeToggle.jsx.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"ThemeToggle.jsx","sourceRoot":"","sources":["../../../src/template/components/ThemeToggle.tsx"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAA;AACzD,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAC7C,OAAO,EAAE,QAAQ,EAAE,MAAM,8BAA8B,CAAA;AAEvD,MAAM,CAAC,MAAM,WAAW,GAAa,GAAG,EAAE;IACxC,MAAM,EAAE,UAAU,EAAE,WAAW,EAAE,GAAG,QAAQ,EAAE,CAAA;IAE9C,OAAO,CACL,CAAC,UAAU,CACT,IAAI,CAAC,GAAG,CACR,OAAO,CAAC,OAAO,CACf,KAAK,CAAC,MAAM,CACZ,OAAO,CAAC,CAAC,WAAW,CAAC,CACrB,UAAU,CAAC,CAAC,aAAa,UAAU,KAAK,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,QAAQ,CAAC,CAC3E,KAAK,CAAC,CAAC,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC,CAE7B;MAAA,CAAC,UAAU,KAAK,OAAO,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,EAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,EAAG,CACpG;IAAA,EAAE,UAAU,CAAC,CACd,CAAA;AACH,CAAC,CAAA"}
|
@@ -0,0 +1,12 @@
|
|
1
|
+
import type { React } from '#dep/react/index';
|
2
|
+
type ThemeAppearance = 'light' | 'dark';
|
3
|
+
interface ThemeContextValue {
|
4
|
+
appearance: ThemeAppearance;
|
5
|
+
toggleTheme: () => void;
|
6
|
+
}
|
7
|
+
export declare const ThemeProvider: React.FC<{
|
8
|
+
children: React.ReactNode;
|
9
|
+
}>;
|
10
|
+
export declare const useTheme: () => ThemeContextValue;
|
11
|
+
export {};
|
12
|
+
//# sourceMappingURL=ThemeContext.d.ts.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"ThemeContext.d.ts","sourceRoot":"","sources":["../../../src/template/contexts/ThemeContext.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAA;AAG7C,KAAK,eAAe,GAAG,OAAO,GAAG,MAAM,CAAA;AAEvC,UAAU,iBAAiB;IACzB,UAAU,EAAE,eAAe,CAAA;IAC3B,WAAW,EAAE,MAAM,IAAI,CAAA;CACxB;AAMD,eAAO,MAAM,aAAa,EAAE,KAAK,CAAC,EAAE,CAAC;IAAE,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAA;CAAE,CAqCjE,CAAA;AAED,eAAO,MAAM,QAAQ,yBAMpB,CAAA"}
|
@@ -0,0 +1,41 @@
|
|
1
|
+
import { createContext, useContext, useEffect, useState } from 'react';
|
2
|
+
const ThemeContext = createContext(undefined);
|
3
|
+
const THEME_STORAGE_KEY = 'polen-theme-preference';
|
4
|
+
export const ThemeProvider = ({ children }) => {
|
5
|
+
const [appearance, setAppearance] = useState(() => {
|
6
|
+
// Check if we're in the browser
|
7
|
+
if (typeof window === 'undefined') {
|
8
|
+
return 'light';
|
9
|
+
}
|
10
|
+
// Check localStorage first
|
11
|
+
const stored = localStorage.getItem(THEME_STORAGE_KEY);
|
12
|
+
if (stored === 'light' || stored === 'dark') {
|
13
|
+
return stored;
|
14
|
+
}
|
15
|
+
// Check system preference
|
16
|
+
if (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) {
|
17
|
+
return 'dark';
|
18
|
+
}
|
19
|
+
return 'light';
|
20
|
+
});
|
21
|
+
useEffect(() => {
|
22
|
+
// Persist to localStorage
|
23
|
+
if (typeof window !== 'undefined') {
|
24
|
+
localStorage.setItem(THEME_STORAGE_KEY, appearance);
|
25
|
+
}
|
26
|
+
}, [appearance]);
|
27
|
+
const toggleTheme = () => {
|
28
|
+
setAppearance(prev => prev === 'light' ? 'dark' : 'light');
|
29
|
+
};
|
30
|
+
return (<ThemeContext.Provider value={{ appearance, toggleTheme }}>
|
31
|
+
{children}
|
32
|
+
</ThemeContext.Provider>);
|
33
|
+
};
|
34
|
+
export const useTheme = () => {
|
35
|
+
const context = useContext(ThemeContext);
|
36
|
+
if (!context) {
|
37
|
+
throw new Error('useTheme must be used within a ThemeProvider');
|
38
|
+
}
|
39
|
+
return context;
|
40
|
+
};
|
41
|
+
//# sourceMappingURL=ThemeContext.jsx.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"ThemeContext.jsx","sourceRoot":"","sources":["../../../src/template/contexts/ThemeContext.tsx"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAA;AAStE,MAAM,YAAY,GAAG,aAAa,CAAgC,SAAS,CAAC,CAAA;AAE5E,MAAM,iBAAiB,GAAG,wBAAwB,CAAA;AAElD,MAAM,CAAC,MAAM,aAAa,GAA4C,CAAC,EAAE,QAAQ,EAAE,EAAE,EAAE;IACrF,MAAM,CAAC,UAAU,EAAE,aAAa,CAAC,GAAG,QAAQ,CAAkB,GAAG,EAAE;QACjE,gCAAgC;QAChC,IAAI,OAAO,MAAM,KAAK,WAAW,EAAE,CAAC;YAClC,OAAO,OAAO,CAAA;QAChB,CAAC;QAED,2BAA2B;QAC3B,MAAM,MAAM,GAAG,YAAY,CAAC,OAAO,CAAC,iBAAiB,CAAC,CAAA;QACtD,IAAI,MAAM,KAAK,OAAO,IAAI,MAAM,KAAK,MAAM,EAAE,CAAC;YAC5C,OAAO,MAAM,CAAA;QACf,CAAC;QAED,0BAA0B;QAC1B,IAAI,MAAM,CAAC,UAAU,IAAI,MAAM,CAAC,UAAU,CAAC,8BAA8B,CAAC,CAAC,OAAO,EAAE,CAAC;YACnF,OAAO,MAAM,CAAA;QACf,CAAC;QAED,OAAO,OAAO,CAAA;IAChB,CAAC,CAAC,CAAA;IAEF,SAAS,CAAC,GAAG,EAAE;QACb,0BAA0B;QAC1B,IAAI,OAAO,MAAM,KAAK,WAAW,EAAE,CAAC;YAClC,YAAY,CAAC,OAAO,CAAC,iBAAiB,EAAE,UAAU,CAAC,CAAA;QACrD,CAAC;IACH,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,CAAA;IAEhB,MAAM,WAAW,GAAG,GAAG,EAAE;QACvB,aAAa,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,KAAK,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,CAAA;IAC5D,CAAC,CAAA;IAED,OAAO,CACL,CAAC,YAAY,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,UAAU,EAAE,WAAW,EAAE,CAAC,CACxD;MAAA,CAAC,QAAQ,CACX;IAAA,EAAE,YAAY,CAAC,QAAQ,CAAC,CACzB,CAAA;AACH,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,QAAQ,GAAG,GAAG,EAAE;IAC3B,MAAM,OAAO,GAAG,UAAU,CAAC,YAAY,CAAC,CAAA;IACxC,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,MAAM,IAAI,KAAK,CAAC,8CAA8C,CAAC,CAAA;IACjE,CAAC;IACD,OAAO,OAAO,CAAA;AAChB,CAAC,CAAA"}
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"root.d.ts","sourceRoot":"","sources":["../../../src/template/routes/root.tsx"],"names":[],"mappings":"
|
1
|
+
{"version":3,"file":"root.d.ts","sourceRoot":"","sources":["../../../src/template/routes/root.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAA;AAoC1D,eAAO,MAAM,SAAS,mCAuBrB,CAAA;AAsMD,eAAO,MAAM,IAAI;;;;CAIf,CAAA"}
|
@@ -1,9 +1,9 @@
|
|
1
|
-
import { assetUrl } from '#api/utils/asset-url/index';
|
2
1
|
import { createRoute } from '#lib/react-router-aid/react-router-aid';
|
3
|
-
import { Box,
|
2
|
+
import { Box, Grid } from '@radix-ui/themes';
|
4
3
|
import { Flex, Theme } from '@radix-ui/themes';
|
5
4
|
import radixStylesUrl from '@radix-ui/themes/styles.css?url';
|
6
5
|
import { Arr } from '@wollybeard/kit';
|
6
|
+
import { useEffect, useState } from 'react';
|
7
7
|
import { Link as LinkReactRouter } from 'react-router';
|
8
8
|
import { Outlet, ScrollRestoration, useLocation } from 'react-router';
|
9
9
|
import logoSrc from 'virtual:polen/project/assets/logo.svg';
|
@@ -12,13 +12,17 @@ import projectDataNavbar from 'virtual:polen/project/data/navbar.jsonsuper';
|
|
12
12
|
import projectDataPages from 'virtual:polen/project/data/pages.jsonsuper';
|
13
13
|
import { pages } from 'virtual:polen/project/pages.jsx';
|
14
14
|
import { templateVariables } from 'virtual:polen/template/variables';
|
15
|
-
import {
|
16
|
-
import {
|
17
|
-
import {
|
15
|
+
import { HamburgerMenu } from "../components/HamburgerMenu.jsx";
|
16
|
+
import { Link } from "../components/Link.jsx";
|
17
|
+
import { Logo } from "../components/Logo.jsx";
|
18
|
+
import { NotFound } from "../components/NotFound.jsx";
|
19
|
+
import { Sidebar } from "../components/sidebar/Sidebar.jsx";
|
20
|
+
import { ThemeToggle } from "../components/ThemeToggle.jsx";
|
21
|
+
import { ThemeProvider, useTheme } from "../contexts/ThemeContext.jsx";
|
18
22
|
import entryClientUrl from '../entry.client.jsx?url';
|
19
|
-
import { changelog } from
|
20
|
-
import { index } from
|
21
|
-
import { reference } from
|
23
|
+
import { changelog } from "./changelog.jsx";
|
24
|
+
import { index } from "./index.jsx";
|
25
|
+
import { reference } from "./reference.jsx";
|
22
26
|
// todo: not needed anymore because not using hono dev vite plugin right?
|
23
27
|
const reactRefreshPreamble = `
|
24
28
|
import RefreshRuntime from "/@react-refresh";
|
@@ -41,7 +45,9 @@ export const Component = () => {
|
|
41
45
|
{/* <meta name='theme-color' content='#000000' /> */}
|
42
46
|
</head>
|
43
47
|
<body style={{ margin: 0 }}>
|
44
|
-
<
|
48
|
+
<ThemeProvider>
|
49
|
+
<Layout />
|
50
|
+
</ThemeProvider>
|
45
51
|
<ScrollRestoration />
|
46
52
|
{import.meta.env.DEV && <script type='module' src={entryClientUrl}></script>}
|
47
53
|
</body>
|
@@ -49,6 +55,12 @@ export const Component = () => {
|
|
49
55
|
};
|
50
56
|
const Layout = () => {
|
51
57
|
const location = useLocation();
|
58
|
+
const { appearance } = useTheme();
|
59
|
+
const [mobileMenuOpen, setMobileMenuOpen] = useState(false);
|
60
|
+
// Close mobile menu on route change
|
61
|
+
useEffect(() => {
|
62
|
+
setMobileMenuOpen(false);
|
63
|
+
}, [location.pathname]);
|
52
64
|
// Determine if we should show sidebar based on current path
|
53
65
|
const getCurrentNavPathExp = () => {
|
54
66
|
// todo: general path manipulation lib because we are duplicating logic here found in FileRouter
|
@@ -62,22 +74,44 @@ const Layout = () => {
|
|
62
74
|
const currentNavPathExp = getCurrentNavPathExp();
|
63
75
|
const sidebar = currentNavPathExp && projectDataPages.sidebarIndex[currentNavPathExp];
|
64
76
|
const isShowSidebar = sidebar && sidebar.items.length > 0;
|
65
|
-
const header = (<Flex gridArea={'header'} align='center' gap='8' pb='4' mb='8' style={{
|
77
|
+
const header = (<Flex gridArea={'header'} align='center' gap={{ initial: '4', md: '8' }} pb='4' mb={{ initial: '4', md: '8' }} style={{
|
66
78
|
borderBottom: `1px solid var(--gray-3)`,
|
67
79
|
}}>
|
80
|
+
{/* Mobile menu - only show when sidebar exists */}
|
81
|
+
{isShowSidebar && (<HamburgerMenu isOpen={mobileMenuOpen} onToggle={() => setMobileMenuOpen(!mobileMenuOpen)} onClose={() => setMobileMenuOpen(false)} sidebarData={sidebar.items}/>)}
|
82
|
+
|
68
83
|
<LinkReactRouter to='/' style={{ color: `inherit`, textDecoration: `none` }}>
|
69
|
-
<
|
84
|
+
<Box display={{ initial: 'block', md: 'block' }}>
|
85
|
+
<Logo src={logoSrc} title={templateVariables.title} height={30} showTitle={true}/>
|
86
|
+
</Box>
|
70
87
|
</LinkReactRouter>
|
71
|
-
<Flex direction='row' gap='4'>
|
88
|
+
<Flex direction='row' gap='4' style={{ flex: 1 }}>
|
72
89
|
{projectDataNavbar.map((item, key) => (<Link key={key} color='gray' to={item.pathExp}>
|
73
90
|
{item.title}
|
74
91
|
</Link>))}
|
75
92
|
</Flex>
|
93
|
+
<ThemeToggle />
|
76
94
|
</Flex>);
|
77
|
-
return (<Theme asChild>
|
78
|
-
<Grid width={{ initial: '
|
95
|
+
return (<Theme asChild appearance={appearance}>
|
96
|
+
<Grid width={{ initial: '100%', sm: '100%', md: 'var(--container-4)' }} maxWidth='100vw' areas={{
|
97
|
+
initial: "'header' 'content'",
|
98
|
+
sm: "'header' 'content'",
|
99
|
+
md: "'header header header header header header header header' 'sidebar sidebar . content content content content content'",
|
100
|
+
}} rows='min-content auto' columns={{ initial: '1fr', sm: '1fr', md: 'repeat(8, 1fr)' }} gapX={{ initial: '0', sm: '0', md: '2' }} my={{ initial: '0', sm: '0', md: '8' }} mx='auto' px={{ initial: '4', sm: '4', md: '0' }} py={{ initial: '4', sm: '4', md: '0' }}>
|
79
101
|
<style>
|
80
102
|
{`
|
103
|
+
/* Responsive container fixes */
|
104
|
+
@media (max-width: 768px) {
|
105
|
+
body {
|
106
|
+
overflow-x: hidden;
|
107
|
+
}
|
108
|
+
}
|
109
|
+
|
110
|
+
/* Ensure proper centering on all screen sizes */
|
111
|
+
.rt-Grid {
|
112
|
+
box-sizing: border-box;
|
113
|
+
}
|
114
|
+
|
81
115
|
/* Shiki code blocks */
|
82
116
|
pre.shiki {
|
83
117
|
margin: 1rem 0;
|
@@ -111,7 +145,12 @@ const Layout = () => {
|
|
111
145
|
`}
|
112
146
|
</style>
|
113
147
|
{header}
|
114
|
-
|
148
|
+
|
149
|
+
{/* Desktop Sidebar */}
|
150
|
+
{isShowSidebar && (<Box display={{ initial: 'none', xs: 'none', sm: 'none', md: 'block' }} gridColumn='1 / 3' gridRow='2 / auto'>
|
151
|
+
<Sidebar data={sidebar.items}/>
|
152
|
+
</Box>)}
|
153
|
+
|
115
154
|
<Box gridArea='content / content / auto / 8'>
|
116
155
|
<Outlet />
|
117
156
|
</Box>
|
@@ -142,33 +181,10 @@ if (PROJECT_DATA.schema) {
|
|
142
181
|
//
|
143
182
|
//
|
144
183
|
//
|
145
|
-
const NotFoundComponent = () => {
|
146
|
-
return (<Flex direction='column' align='center' gap='6' style={{ textAlign: `center`, paddingTop: `4rem` }}>
|
147
|
-
<Heading size='9' style={{ color: `var(--gray-12)` }}>404</Heading>
|
148
|
-
<Box>
|
149
|
-
<Heading size='5' mb='2'>Page Not Found</Heading>
|
150
|
-
<Text size='3' color='gray'>
|
151
|
-
The page you're looking for doesn't exist or has been moved.
|
152
|
-
</Text>
|
153
|
-
</Box>
|
154
|
-
<Flex gap='3'>
|
155
|
-
<LinkReactRouter to='/'>
|
156
|
-
<Button variant='soft' size='3'>
|
157
|
-
Go Home
|
158
|
-
</Button>
|
159
|
-
</LinkReactRouter>
|
160
|
-
<LinkReactRouter to='/reference'>
|
161
|
-
<Button variant='outline' size='3'>
|
162
|
-
View API Reference
|
163
|
-
</Button>
|
164
|
-
</LinkReactRouter>
|
165
|
-
</Flex>
|
166
|
-
</Flex>);
|
167
|
-
};
|
168
184
|
const notFoundRoute = createRoute({
|
169
185
|
id: `*_not_found`,
|
170
186
|
path: `*`,
|
171
|
-
Component:
|
187
|
+
Component: NotFound,
|
172
188
|
handle: {
|
173
189
|
statusCode: 404,
|
174
190
|
},
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"root.jsx","sourceRoot":"","sources":["../../../src/template/routes/root.tsx"],"names":[],"mappings":"
|
1
|
+
{"version":3,"file":"root.jsx","sourceRoot":"","sources":["../../../src/template/routes/root.tsx"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
package/src/api/content/$$.ts
CHANGED
@@ -0,0 +1,55 @@
|
|
1
|
+
import { describe, expect, it } from 'vitest'
|
2
|
+
import { createNavbar } from './navbar.ts'
|
3
|
+
import type { Page } from './page.ts'
|
4
|
+
|
5
|
+
const createPage = (path: string[], fileName = 'index', hidden = false): Page => ({
|
6
|
+
route: {
|
7
|
+
id: path.join('/'),
|
8
|
+
parentId: path.length > 1 ? path.slice(0, -1).join('/') : null,
|
9
|
+
logical: { path },
|
10
|
+
file: {
|
11
|
+
path: {
|
12
|
+
absolute: { root: '/', dir: `/pages/${path.join('/')}`, base: `${fileName}.md`, ext: '.md', name: fileName },
|
13
|
+
relative: { root: '', dir: path.join('/'), base: `${fileName}.md`, ext: '.md', name: fileName },
|
14
|
+
},
|
15
|
+
},
|
16
|
+
},
|
17
|
+
metadata: { description: undefined, hidden },
|
18
|
+
})
|
19
|
+
|
20
|
+
describe('createNavbar', () => {
|
21
|
+
it('returns empty for empty input', () => {
|
22
|
+
expect(createNavbar([])).toEqual([])
|
23
|
+
})
|
24
|
+
|
25
|
+
it('excludes hidden pages', () => {
|
26
|
+
const pages = [createPage(['visible'], 'index', false), createPage(['hidden'], 'index', true)]
|
27
|
+
const result = createNavbar(pages)
|
28
|
+
expect(result).toEqual([{ pathExp: '/visible', title: 'Visible' }])
|
29
|
+
})
|
30
|
+
|
31
|
+
it('includes directories with index pages', () => {
|
32
|
+
const pages = [createPage(['guide'], 'index'), createPage(['guide', 'intro'], 'intro')]
|
33
|
+
const result = createNavbar(pages)
|
34
|
+
expect(result).toEqual([{ pathExp: '/guide', title: 'Guide' }])
|
35
|
+
})
|
36
|
+
|
37
|
+
it('excludes directories without index pages', () => {
|
38
|
+
const pages = [createPage(['guide', 'intro'], 'intro')]
|
39
|
+
const result = createNavbar(pages)
|
40
|
+
expect(result).toEqual([])
|
41
|
+
})
|
42
|
+
|
43
|
+
it('includes single top-level pages', () => {
|
44
|
+
const pages = [createPage(['about'], 'about')]
|
45
|
+
const result = createNavbar(pages)
|
46
|
+
expect(result).toEqual([{ pathExp: '/about', title: 'About' }])
|
47
|
+
})
|
48
|
+
|
49
|
+
it('sorts results alphabetically', () => {
|
50
|
+
const pages = [createPage(['zebra'], 'zebra'), createPage(['alpha'], 'alpha')]
|
51
|
+
const result = createNavbar(pages)
|
52
|
+
expect(result[0]!.title).toBe('Alpha')
|
53
|
+
expect(result[1]!.title).toBe('Zebra')
|
54
|
+
})
|
55
|
+
})
|
@@ -0,0 +1,61 @@
|
|
1
|
+
import { Str } from '@wollybeard/kit'
|
2
|
+
import type { Page } from './page.ts'
|
3
|
+
|
4
|
+
export interface NavbarItem {
|
5
|
+
pathExp: string
|
6
|
+
title: string
|
7
|
+
}
|
8
|
+
|
9
|
+
/**
|
10
|
+
* Generate navbar items from a list of pages
|
11
|
+
*/
|
12
|
+
export const createNavbar = (pages: Page[]): NavbarItem[] => {
|
13
|
+
const navbarItems: NavbarItem[] = []
|
14
|
+
|
15
|
+
// Group pages by their top-level directory/segment
|
16
|
+
const topLevelGroups = new Map<string, Page[]>()
|
17
|
+
|
18
|
+
pages.forEach(page => {
|
19
|
+
// Skip hidden pages
|
20
|
+
if (page.metadata.hidden) return
|
21
|
+
|
22
|
+
const firstSegment = page.route.logical.path[0]
|
23
|
+
if (firstSegment) {
|
24
|
+
if (!topLevelGroups.has(firstSegment)) {
|
25
|
+
topLevelGroups.set(firstSegment, [])
|
26
|
+
}
|
27
|
+
topLevelGroups.get(firstSegment)!.push(page)
|
28
|
+
}
|
29
|
+
})
|
30
|
+
|
31
|
+
// Add each top-level group to navbar
|
32
|
+
topLevelGroups.forEach((pages, segment) => {
|
33
|
+
// For directories, check if there's an index page
|
34
|
+
const indexPage = pages.find(p =>
|
35
|
+
p.route.logical.path.length === 1
|
36
|
+
&& p.route.file.path.relative.name === 'index'
|
37
|
+
)
|
38
|
+
|
39
|
+
// For single non-index files at top level
|
40
|
+
const singlePage = pages.length === 1 && pages[0]!.route.logical.path.length === 1
|
41
|
+
&& pages[0]!.route.file.path.relative.name !== 'index'
|
42
|
+
|
43
|
+
// Include in navbar if:
|
44
|
+
// 1. It's a directory with an index page, OR
|
45
|
+
// 2. It's a single top-level page (not index)
|
46
|
+
if (indexPage || singlePage) {
|
47
|
+
const title = Str.titlizeSlug(segment)
|
48
|
+
const pathExp = `/${segment}`
|
49
|
+
|
50
|
+
navbarItems.push({
|
51
|
+
pathExp,
|
52
|
+
title,
|
53
|
+
})
|
54
|
+
}
|
55
|
+
})
|
56
|
+
|
57
|
+
// Sort navbar items alphabetically for consistency
|
58
|
+
navbarItems.sort((a, b) => a.title.localeCompare(b.title))
|
59
|
+
|
60
|
+
return navbarItems
|
61
|
+
}
|