polen 0.8.0-next.4 → 0.8.0-next.6
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/vite/plugins/core.d.ts.map +1 -1
- package/build/api/vite/plugins/core.js +146 -52
- package/build/api/vite/plugins/core.js.map +1 -1
- package/build/lib/file-router/linter.d.ts.map +1 -1
- package/build/lib/file-router/linter.js +3 -3
- package/build/lib/file-router/linter.js.map +1 -1
- package/build/lib/file-router/route.d.ts +48 -10
- package/build/lib/file-router/route.d.ts.map +1 -1
- package/build/lib/file-router/route.js +68 -3
- package/build/lib/file-router/route.js.map +1 -1
- package/build/lib/file-router/scan.d.ts +2 -2
- package/build/lib/file-router/scan.d.ts.map +1 -1
- package/build/lib/file-router/scan.js +8 -8
- package/build/lib/file-router/scan.js.map +1 -1
- package/build/lib/file-router/sidebar.d.ts +2 -0
- package/build/lib/file-router/sidebar.d.ts.map +1 -0
- package/build/lib/file-router/sidebar.js +2 -0
- package/build/lib/file-router/sidebar.js.map +1 -0
- package/build/lib/kit-temp.d.ts +2 -0
- package/build/lib/kit-temp.d.ts.map +1 -0
- package/build/lib/kit-temp.js +23 -0
- package/build/lib/kit-temp.js.map +1 -0
- package/build/project-data.d.ts +21 -1
- package/build/project-data.d.ts.map +1 -1
- package/build/template/components/Sidebar.d.ts +7 -0
- package/build/template/components/Sidebar.d.ts.map +1 -0
- package/build/template/components/Sidebar.jsx +108 -0
- package/build/template/components/Sidebar.jsx.map +1 -0
- package/build/template/routes/root.d.ts.map +1 -1
- package/build/template/routes/root.jsx +28 -5
- package/build/template/routes/root.jsx.map +1 -1
- package/package.json +1 -1
- package/src/api/vite/plugins/core.ts +178 -54
- package/src/lib/file-router/index.test.ts +5 -5
- package/src/lib/file-router/linter.ts +3 -3
- package/src/lib/file-router/route.ts +147 -11
- package/src/lib/file-router/scan.ts +9 -9
- package/src/lib/file-router/sidebar.ts +0 -0
- package/src/lib/kit-temp.ts +21 -0
- package/src/project-data.ts +26 -1
- package/src/template/components/Sidebar.tsx +185 -0
- package/src/template/routes/root.tsx +35 -5
@@ -1,9 +1,45 @@
|
|
1
|
-
import
|
1
|
+
import { arrayEquals } from '#lib/kit-temp.js'
|
2
|
+
import { type Path } from '@wollybeard/kit'
|
2
3
|
|
3
|
-
|
4
|
+
//
|
5
|
+
//
|
6
|
+
//
|
7
|
+
//
|
8
|
+
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ • Path
|
9
|
+
//
|
10
|
+
//
|
4
11
|
|
5
|
-
export
|
6
|
-
|
12
|
+
export type Path = PathSegment[]
|
13
|
+
|
14
|
+
export type PathRoot = []
|
15
|
+
|
16
|
+
export type PathTop = [PathSegment]
|
17
|
+
|
18
|
+
export type PathSub = [PathSegment, PathSegment, ...PathSegment[]]
|
19
|
+
|
20
|
+
export type PathSegment = string
|
21
|
+
|
22
|
+
export const sep = `/`
|
23
|
+
|
24
|
+
export const pathToExpression = (path: Path) => {
|
25
|
+
return sep + path.join(sep)
|
26
|
+
}
|
27
|
+
|
28
|
+
//
|
29
|
+
//
|
30
|
+
//
|
31
|
+
//
|
32
|
+
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ • Route (Generic)
|
33
|
+
//
|
34
|
+
//
|
35
|
+
|
36
|
+
export interface Route {
|
37
|
+
logical: RouteLogical
|
38
|
+
file: RouteFile
|
39
|
+
}
|
40
|
+
|
41
|
+
export interface RouteLogical {
|
42
|
+
path: Path
|
7
43
|
}
|
8
44
|
|
9
45
|
export interface RouteFile {
|
@@ -13,21 +49,121 @@ export interface RouteFile {
|
|
13
49
|
}
|
14
50
|
}
|
15
51
|
|
16
|
-
|
17
|
-
|
18
|
-
|
52
|
+
//
|
53
|
+
//
|
54
|
+
//
|
55
|
+
//
|
56
|
+
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ • Top Level Route
|
57
|
+
//
|
58
|
+
//
|
59
|
+
|
60
|
+
export interface TopLevelRoute extends Route {
|
61
|
+
logical: TopLevelRouteLogical
|
19
62
|
}
|
20
63
|
|
21
|
-
export
|
64
|
+
export interface TopLevelRouteLogical {
|
65
|
+
path: PathTop
|
66
|
+
}
|
22
67
|
|
23
|
-
|
24
|
-
|
68
|
+
/**
|
69
|
+
* Route is top level meaning exists directly under the root.
|
70
|
+
*
|
71
|
+
* It excludes the root level route.
|
72
|
+
*/
|
73
|
+
export const routeIsTopLevel = (route: Route): route is TopLevelRoute => {
|
74
|
+
return route.logical.path.length === 1
|
25
75
|
}
|
26
76
|
|
27
|
-
|
77
|
+
//
|
78
|
+
// ━━ Sub Level
|
79
|
+
//
|
80
|
+
|
81
|
+
//
|
82
|
+
//
|
83
|
+
//
|
84
|
+
//
|
85
|
+
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ • Sub Level Route
|
86
|
+
//
|
87
|
+
//
|
88
|
+
|
89
|
+
export interface RouteSubLevel extends Route {
|
90
|
+
logical: RoutePathSubLevel
|
91
|
+
}
|
92
|
+
|
93
|
+
export interface RoutePathSubLevel {
|
94
|
+
path: PathSub
|
95
|
+
}
|
96
|
+
|
97
|
+
/**
|
98
|
+
* Route is not top or root level
|
99
|
+
*/
|
100
|
+
export const routeIsSubLevel = (route: Route): route is RouteSubLevel => {
|
101
|
+
return route.logical.path.length > 1
|
102
|
+
}
|
103
|
+
|
104
|
+
//
|
105
|
+
// ━━ Root Level
|
106
|
+
//
|
107
|
+
|
108
|
+
//
|
109
|
+
//
|
110
|
+
//
|
111
|
+
//
|
112
|
+
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ • Root Level Route
|
113
|
+
//
|
114
|
+
//
|
115
|
+
|
116
|
+
/**
|
117
|
+
* Route is the singular root route.
|
118
|
+
|
119
|
+
* This is the case of index under root.
|
120
|
+
*/
|
121
|
+
export const routeIsRootLevel = (route: Route): route is TopLevelRoute => {
|
122
|
+
// No need to check for name "index"
|
123
|
+
// Segments is uniquely empty for <root>/index
|
124
|
+
return route.logical.path.length === 0
|
125
|
+
}
|
126
|
+
|
127
|
+
//
|
128
|
+
//
|
129
|
+
//
|
130
|
+
// ━━━━━━━━━━━━━━ • Route Functions
|
131
|
+
//
|
132
|
+
//
|
133
|
+
|
134
|
+
export const routeIsFromIndexFile = (route: Route): boolean => {
|
28
135
|
return route.file.path.relative.name === conventions.index.name
|
29
136
|
}
|
30
137
|
|
138
|
+
export const routeIsSubOf = (route: Route, potentialAncestorPath: PathSegment[]): boolean => {
|
139
|
+
if (route.logical.path.length <= potentialAncestorPath.length) {
|
140
|
+
return false
|
141
|
+
}
|
142
|
+
return arrayEquals(
|
143
|
+
route.logical.path.slice(0, potentialAncestorPath.length),
|
144
|
+
potentialAncestorPath,
|
145
|
+
)
|
146
|
+
}
|
147
|
+
|
148
|
+
/**
|
149
|
+
* You are responsible for ensuring given ancestor path is really an ancestor of given route's path.
|
150
|
+
*/
|
151
|
+
export const makeRelativeUnsafe = (route: Route, assumedAncestorPath: PathSegment[]): Route => {
|
152
|
+
// We assume that we're working with paths where index is elided per our FileRouter system.
|
153
|
+
const newPath = route.logical.path.slice(assumedAncestorPath.length)
|
154
|
+
return {
|
155
|
+
...route,
|
156
|
+
logical: {
|
157
|
+
...route.logical,
|
158
|
+
path: newPath,
|
159
|
+
},
|
160
|
+
}
|
161
|
+
}
|
162
|
+
|
163
|
+
export const routeToPathExpression = (route: Route) => {
|
164
|
+
return pathToExpression(route.logical.path)
|
165
|
+
}
|
166
|
+
|
31
167
|
const conventions = {
|
32
168
|
index: {
|
33
169
|
name: `index`,
|
@@ -1,7 +1,7 @@
|
|
1
1
|
import { TinyGlobby } from '#dep/tiny-globby/index.js'
|
2
2
|
import { Path, Str } from '@wollybeard/kit'
|
3
3
|
import { type Diagnostic, lint } from './linter.js'
|
4
|
-
import type { Route, RouteFile,
|
4
|
+
import type { Route, RouteFile, RouteLogical } from './route.js'
|
5
5
|
|
6
6
|
//
|
7
7
|
//
|
@@ -64,26 +64,26 @@ export const filePathToRoute = (filePathExpression: string, rootDir: string): Ro
|
|
64
64
|
relative: Path.parse(Path.relative(rootDir, filePathExpression)),
|
65
65
|
},
|
66
66
|
}
|
67
|
-
const
|
67
|
+
const logical = filePathToRouteLogical(file.path.relative)
|
68
68
|
|
69
69
|
return {
|
70
|
-
|
70
|
+
logical,
|
71
71
|
file,
|
72
72
|
}
|
73
73
|
}
|
74
74
|
|
75
|
-
export const
|
76
|
-
const
|
75
|
+
export const filePathToRouteLogical = (filePath: Path.Parsed): RouteLogical => {
|
76
|
+
const dirPath = Str.split(Str.removeSurrounding(filePath.dir, Path.sep), Path.sep)
|
77
77
|
|
78
78
|
if (Str.isMatch(filePath.name, conventions.index.name)) {
|
79
|
-
const
|
79
|
+
const path = dirPath
|
80
80
|
return {
|
81
|
-
|
81
|
+
path,
|
82
82
|
}
|
83
83
|
}
|
84
84
|
|
85
|
-
const
|
85
|
+
const path = dirPath.concat(filePath.name)
|
86
86
|
return {
|
87
|
-
|
87
|
+
path,
|
88
88
|
}
|
89
89
|
}
|
File without changes
|
@@ -0,0 +1,21 @@
|
|
1
|
+
//
|
2
|
+
//
|
3
|
+
//
|
4
|
+
//
|
5
|
+
//
|
6
|
+
// Holding Module for Missing @wollybeard/kit Functionality
|
7
|
+
//
|
8
|
+
// ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄
|
9
|
+
//
|
10
|
+
// Code here is meant to be migrated eventually to @wollybeard/kit.
|
11
|
+
//
|
12
|
+
//
|
13
|
+
//
|
14
|
+
|
15
|
+
export const arrayEquals = (a: any[], b: any[]) => {
|
16
|
+
if (a.length !== b.length) return false
|
17
|
+
for (let i = 0; i < a.length; i++) {
|
18
|
+
if (a[i] !== b[i]) return false
|
19
|
+
}
|
20
|
+
return true
|
21
|
+
}
|
package/src/project-data.ts
CHANGED
@@ -5,6 +5,7 @@ import type { Schema } from './api/schema/index.js'
|
|
5
5
|
export interface ProjectData {
|
6
6
|
schema: null | Schema.Schema
|
7
7
|
siteNavigationItems: SiteNavigationItem[]
|
8
|
+
sidebarIndex: SidebarIndex
|
8
9
|
faviconPath: string
|
9
10
|
paths: Configurator.Config[`paths`][`project`]
|
10
11
|
pagesScanResult: FileRouter.ScanResult
|
@@ -18,5 +19,29 @@ export interface ProjectData {
|
|
18
19
|
|
19
20
|
export interface SiteNavigationItem {
|
20
21
|
title: string
|
21
|
-
|
22
|
+
pathExp: string
|
23
|
+
}
|
24
|
+
|
25
|
+
export interface SidebarIndex {
|
26
|
+
[pathExpression: string]: Sidebar
|
27
|
+
}
|
28
|
+
|
29
|
+
export interface Sidebar {
|
30
|
+
items: SidebarItem[]
|
31
|
+
}
|
32
|
+
|
33
|
+
export type SidebarItem = SidebarNav | SidebarSection
|
34
|
+
|
35
|
+
export interface SidebarNav {
|
36
|
+
type: `SidebarItem`
|
37
|
+
title: string
|
38
|
+
pathExp: string
|
39
|
+
}
|
40
|
+
|
41
|
+
export interface SidebarSection {
|
42
|
+
type: `SidebarSection`
|
43
|
+
title: string
|
44
|
+
pathExp: string
|
45
|
+
isNavToo: boolean
|
46
|
+
navs: SidebarNav[]
|
22
47
|
}
|
@@ -0,0 +1,185 @@
|
|
1
|
+
import { ChevronDownIcon, ChevronRightIcon } from '@radix-ui/react-icons'
|
2
|
+
import { Box, Flex, Text } from '@radix-ui/themes'
|
3
|
+
import { useState } from 'react'
|
4
|
+
import { Link, useLocation } from 'react-router'
|
5
|
+
import type { SidebarItem, SidebarNav, SidebarSection } from '../../project-data.js'
|
6
|
+
|
7
|
+
interface SidebarProps {
|
8
|
+
items: SidebarItem[]
|
9
|
+
}
|
10
|
+
|
11
|
+
export const Sidebar = ({ items }: SidebarProps) => {
|
12
|
+
const location = useLocation()
|
13
|
+
|
14
|
+
return (
|
15
|
+
<Box
|
16
|
+
style={{
|
17
|
+
width: `240px`,
|
18
|
+
minWidth: `240px`,
|
19
|
+
flexShrink: 0,
|
20
|
+
borderRight: `1px solid var(--gray-3)`,
|
21
|
+
height: `100%`,
|
22
|
+
paddingRight: `var(--space-4)`,
|
23
|
+
}}
|
24
|
+
>
|
25
|
+
<Flex direction='column' gap='1'>
|
26
|
+
{items.map((item) => (
|
27
|
+
<SidebarItemComponent
|
28
|
+
key={item.pathExp}
|
29
|
+
item={item}
|
30
|
+
currentPathExp={location.pathname}
|
31
|
+
/>
|
32
|
+
))}
|
33
|
+
</Flex>
|
34
|
+
</Box>
|
35
|
+
)
|
36
|
+
}
|
37
|
+
|
38
|
+
interface SidebarItemComponentProps {
|
39
|
+
item: SidebarItem
|
40
|
+
currentPathExp: string
|
41
|
+
level?: number
|
42
|
+
}
|
43
|
+
|
44
|
+
const SidebarItemComponent = ({ item, currentPathExp, level = 0 }: SidebarItemComponentProps) => {
|
45
|
+
if (item.type === `SidebarItem`) {
|
46
|
+
return <SidebarNavItem nav={item} currentPathExp={currentPathExp} level={level} />
|
47
|
+
}
|
48
|
+
|
49
|
+
return <SidebarSectionItem section={item} currentPathExp={currentPathExp} level={level} />
|
50
|
+
}
|
51
|
+
|
52
|
+
interface SidebarNavItemProps {
|
53
|
+
nav: SidebarNav
|
54
|
+
currentPathExp: string
|
55
|
+
level: number
|
56
|
+
}
|
57
|
+
|
58
|
+
const SidebarNavItem = ({ nav, currentPathExp, level }: SidebarNavItemProps) => {
|
59
|
+
const isActive = currentPathExp === nav.pathExp
|
60
|
+
|
61
|
+
return (
|
62
|
+
<Link
|
63
|
+
to={nav.pathExp}
|
64
|
+
style={{
|
65
|
+
textDecoration: `none`,
|
66
|
+
color: isActive ? `var(--accent-11)` : `var(--gray-12)`,
|
67
|
+
padding: `var(--space-2) var(--space-3)`,
|
68
|
+
paddingLeft: `calc(var(--space-3) + ${(level * 16).toString()}px)`,
|
69
|
+
borderRadius: `var(--radius-2)`,
|
70
|
+
display: `block`,
|
71
|
+
backgroundColor: isActive ? `var(--accent-3)` : `transparent`,
|
72
|
+
transition: `background-color 0.2s ease, color 0.2s ease`,
|
73
|
+
}}
|
74
|
+
onMouseEnter={(e) => {
|
75
|
+
if (!isActive) {
|
76
|
+
e.currentTarget.style.backgroundColor = `var(--gray-2)`
|
77
|
+
}
|
78
|
+
}}
|
79
|
+
onMouseLeave={(e) => {
|
80
|
+
if (!isActive) {
|
81
|
+
e.currentTarget.style.backgroundColor = `transparent`
|
82
|
+
}
|
83
|
+
}}
|
84
|
+
>
|
85
|
+
<Text size='2' weight={isActive ? `medium` : `regular`}>
|
86
|
+
{nav.title}
|
87
|
+
</Text>
|
88
|
+
</Link>
|
89
|
+
)
|
90
|
+
}
|
91
|
+
|
92
|
+
interface SidebarSectionItemProps {
|
93
|
+
section: SidebarSection
|
94
|
+
currentPathExp: string
|
95
|
+
level: number
|
96
|
+
}
|
97
|
+
|
98
|
+
const SidebarSectionItem = ({ section, currentPathExp, level }: SidebarSectionItemProps) => {
|
99
|
+
const [isExpanded, setIsExpanded] = useState(true)
|
100
|
+
const isDirectlyActive = currentPathExp === section.pathExp
|
101
|
+
const hasActiveChild = section.navs.some(nav => currentPathExp === nav.pathExp)
|
102
|
+
const isActiveGroup = isDirectlyActive || hasActiveChild
|
103
|
+
|
104
|
+
return (
|
105
|
+
<>
|
106
|
+
<Flex
|
107
|
+
align='center'
|
108
|
+
style={{
|
109
|
+
padding: `var(--space-2) var(--space-3)`,
|
110
|
+
paddingLeft: `calc(var(--space-3) + ${(level * 16).toString()}px)`,
|
111
|
+
borderRadius: `var(--radius-2)`,
|
112
|
+
backgroundColor: isDirectlyActive ? `var(--accent-3)` : hasActiveChild ? `var(--accent-2)` : `transparent`,
|
113
|
+
transition: `background-color 0.2s ease`,
|
114
|
+
}}
|
115
|
+
onMouseEnter={(e) => {
|
116
|
+
if (!isActiveGroup) {
|
117
|
+
e.currentTarget.style.backgroundColor = `var(--gray-2)`
|
118
|
+
}
|
119
|
+
}}
|
120
|
+
onMouseLeave={(e) => {
|
121
|
+
if (!isActiveGroup) {
|
122
|
+
e.currentTarget.style.backgroundColor = `transparent`
|
123
|
+
}
|
124
|
+
}}
|
125
|
+
>
|
126
|
+
<Box
|
127
|
+
onClick={(e) => {
|
128
|
+
e.stopPropagation()
|
129
|
+
console.log(`Chevron clicked!`)
|
130
|
+
setIsExpanded(!isExpanded)
|
131
|
+
}}
|
132
|
+
style={{
|
133
|
+
display: `flex`,
|
134
|
+
alignItems: `center`,
|
135
|
+
cursor: `pointer`,
|
136
|
+
padding: `4px`,
|
137
|
+
marginRight: `4px`,
|
138
|
+
marginLeft: `-4px`,
|
139
|
+
}}
|
140
|
+
>
|
141
|
+
{isExpanded ? <ChevronDownIcon /> : <ChevronRightIcon />}
|
142
|
+
</Box>
|
143
|
+
{section.isNavToo
|
144
|
+
? (
|
145
|
+
<Link
|
146
|
+
to={section.pathExp}
|
147
|
+
style={{
|
148
|
+
textDecoration: `none`,
|
149
|
+
color: isDirectlyActive ? `var(--accent-11)` : `var(--gray-12)`,
|
150
|
+
flex: 1,
|
151
|
+
}}
|
152
|
+
>
|
153
|
+
<Text size='2' weight={isDirectlyActive ? `bold` : `medium`}>
|
154
|
+
{section.title}
|
155
|
+
</Text>
|
156
|
+
</Link>
|
157
|
+
)
|
158
|
+
: (
|
159
|
+
<Text
|
160
|
+
size='2'
|
161
|
+
weight={isDirectlyActive ? `bold` : `medium`}
|
162
|
+
style={{
|
163
|
+
flex: 1,
|
164
|
+
color: isDirectlyActive ? `var(--accent-11)` : `var(--gray-12)`,
|
165
|
+
}}
|
166
|
+
>
|
167
|
+
{section.title}
|
168
|
+
</Text>
|
169
|
+
)}
|
170
|
+
</Flex>
|
171
|
+
{isExpanded && (
|
172
|
+
<Flex direction='column' gap='1'>
|
173
|
+
{section.navs.map((nav) => (
|
174
|
+
<SidebarNavItem
|
175
|
+
key={nav.pathExp}
|
176
|
+
nav={nav}
|
177
|
+
currentPathExp={currentPathExp}
|
178
|
+
level={level + 1}
|
179
|
+
/>
|
180
|
+
))}
|
181
|
+
</Flex>
|
182
|
+
)}
|
183
|
+
</>
|
184
|
+
)
|
185
|
+
}
|
@@ -5,10 +5,11 @@ import { Box, Button, Heading, Text } from '@radix-ui/themes'
|
|
5
5
|
import { Flex, Theme } from '@radix-ui/themes'
|
6
6
|
import radixStylesUrl from '@radix-ui/themes/styles.css?url'
|
7
7
|
import { Link as LinkReactRouter } from 'react-router'
|
8
|
-
import { Outlet, ScrollRestoration } from 'react-router'
|
8
|
+
import { Outlet, ScrollRestoration, useLocation } from 'react-router'
|
9
9
|
import { PROJECT_DATA } from 'virtual:polen/project/data'
|
10
10
|
import { templateVariables } from 'virtual:polen/template/variables'
|
11
11
|
import { Link } from '../components/Link.jsx'
|
12
|
+
import { Sidebar } from '../components/Sidebar.jsx'
|
12
13
|
import entryClientUrl from '../entry.client.jsx?url'
|
13
14
|
import { changelog } from './changelog.jsx'
|
14
15
|
import { index } from './index.jsx'
|
@@ -55,6 +56,23 @@ export const Component = () => {
|
|
55
56
|
}
|
56
57
|
|
57
58
|
const Layout = () => {
|
59
|
+
const location = useLocation()
|
60
|
+
|
61
|
+
// Determine if we should show sidebar based on current path
|
62
|
+
const getCurrentNavPathExp = (): string | null => {
|
63
|
+
// todo: general path manipulation lib because we are duplicating logic here found in FileRouter
|
64
|
+
// todo: kit: try a Str.split that returns [] | string[] so that our predicates can refine on it?
|
65
|
+
const segments = location.pathname.split(`/`).filter(Boolean)
|
66
|
+
if (Arr.isntEmpty(segments)) {
|
67
|
+
return `/${segments[0]}`
|
68
|
+
}
|
69
|
+
return null
|
70
|
+
}
|
71
|
+
|
72
|
+
const currentNavPathExp = getCurrentNavPathExp()
|
73
|
+
const sidebar = currentNavPathExp && PROJECT_DATA.sidebarIndex[currentNavPathExp]
|
74
|
+
const showSidebar = sidebar && sidebar.items.length > 0
|
75
|
+
|
58
76
|
return (
|
59
77
|
<Theme asChild>
|
60
78
|
<Box m='8'>
|
@@ -80,15 +98,26 @@ const Layout = () => {
|
|
80
98
|
</LinkReactRouter>
|
81
99
|
<Flex direction='row' gap='4'>
|
82
100
|
{PROJECT_DATA.siteNavigationItems.map((item, key) => (
|
83
|
-
<Link key={key} color='gray' to={item.
|
101
|
+
<Link key={key} color='gray' to={item.pathExp}>
|
84
102
|
{item.title}
|
85
103
|
</Link>
|
86
104
|
))}
|
87
105
|
</Flex>
|
88
106
|
</Flex>
|
89
|
-
|
90
|
-
|
91
|
-
|
107
|
+
{showSidebar
|
108
|
+
? (
|
109
|
+
<Flex gap='8'>
|
110
|
+
<Sidebar items={sidebar.items} />
|
111
|
+
<Box style={{ flex: 1 }}>
|
112
|
+
<Outlet />
|
113
|
+
</Box>
|
114
|
+
</Flex>
|
115
|
+
)
|
116
|
+
: (
|
117
|
+
<Box>
|
118
|
+
<Outlet />
|
119
|
+
</Box>
|
120
|
+
)}
|
92
121
|
</Box>
|
93
122
|
</Theme>
|
94
123
|
)
|
@@ -165,6 +194,7 @@ children.push(notFoundRoute)
|
|
165
194
|
//
|
166
195
|
//
|
167
196
|
|
197
|
+
import { Arr } from '@wollybeard/kit'
|
168
198
|
import { pages } from 'virtual:polen/project/pages.jsx'
|
169
199
|
|
170
200
|
export const root = createRoute({
|