polen 0.8.2-next.1 → 0.9.0-next.2
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/logger.d.ts +2 -1
- package/build/api/vite/logger.d.ts.map +1 -1
- package/build/api/vite/logger.js +23 -19
- package/build/api/vite/logger.js.map +1 -1
- package/build/api/vite/plugins/core.js +4 -4
- package/build/api/vite/plugins/core.js.map +1 -1
- package/build/api/vite/plugins/pages-tree.d.ts +1 -1
- package/build/api/vite/plugins/pages-tree.d.ts.map +1 -1
- package/build/api/vite/plugins/pages-tree.js +4 -3
- package/build/api/vite/plugins/pages-tree.js.map +1 -1
- package/build/api/vite/plugins/serve.d.ts.map +1 -1
- package/build/api/vite/plugins/serve.js +40 -7
- package/build/api/vite/plugins/serve.js.map +1 -1
- package/build/lib/file-router/sidebar/sidebar-tree.d.ts.map +1 -1
- package/build/lib/file-router/sidebar/sidebar-tree.js +13 -13
- package/build/lib/file-router/sidebar/sidebar-tree.js.map +1 -1
- package/build/lib/file-router/sidebar/types.d.ts +2 -2
- package/build/lib/file-router/sidebar/types.d.ts.map +1 -1
- package/build/lib/kit-temp.d.ts +6 -0
- package/build/lib/kit-temp.d.ts.map +1 -1
- package/build/lib/kit-temp.js +30 -0
- package/build/lib/kit-temp.js.map +1 -1
- package/build/template/components/Link.d.ts +7 -1
- package/build/template/components/Link.d.ts.map +1 -1
- package/build/template/components/Link.jsx +33 -5
- package/build/template/components/Link.jsx.map +1 -1
- package/build/template/components/Texts/MinorHeading.d.ts +4 -0
- package/build/template/components/Texts/MinorHeading.d.ts.map +1 -0
- package/build/template/components/Texts/MinorHeading.jsx +11 -0
- package/build/template/components/Texts/MinorHeading.jsx.map +1 -0
- package/build/template/components/Texts/index.d.ts +2 -0
- package/build/template/components/Texts/index.d.ts.map +1 -0
- package/build/template/components/Texts/index.js +2 -0
- package/build/template/components/Texts/index.js.map +1 -0
- package/build/template/components/Texts/texts.d.ts +2 -0
- package/build/template/components/Texts/texts.d.ts.map +1 -0
- package/build/template/components/Texts/texts.js +2 -0
- package/build/template/components/Texts/texts.js.map +1 -0
- package/build/template/components/sidebar/Sidebar.d.ts.map +1 -0
- package/build/template/components/sidebar/Sidebar.jsx +15 -0
- package/build/template/components/sidebar/Sidebar.jsx.map +1 -0
- package/build/template/components/sidebar/SidebarItem.d.ts +9 -0
- package/build/template/components/sidebar/SidebarItem.d.ts.map +1 -0
- package/build/template/components/sidebar/SidebarItem.jsx +94 -0
- package/build/template/components/sidebar/SidebarItem.jsx.map +1 -0
- package/build/template/components/sidebar/ToggleButton.d.ts +5 -0
- package/build/template/components/sidebar/ToggleButton.d.ts.map +1 -0
- package/build/template/components/sidebar/ToggleButton.jsx +6 -0
- package/build/template/components/sidebar/ToggleButton.jsx.map +1 -0
- package/build/template/routes/root.d.ts.map +1 -1
- package/build/template/routes/root.jsx +1 -1
- package/build/template/routes/root.jsx.map +1 -1
- package/package.json +15 -1
- package/src/api/vite/logger.ts +26 -21
- package/src/api/vite/plugins/core.ts +4 -4
- package/src/api/vite/plugins/pages-tree.ts +4 -3
- package/src/api/vite/plugins/serve.ts +42 -9
- package/src/lib/file-router/sidebar/sidebar-tree.test.ts +6 -6
- package/src/lib/file-router/sidebar/sidebar-tree.ts +14 -14
- package/src/lib/file-router/sidebar/types.ts +2 -2
- package/src/lib/kit-temp.ts +36 -0
- package/src/template/components/Link.tsx +53 -6
- package/src/template/components/Texts/MinorHeading.tsx +18 -0
- package/src/template/components/Texts/index.ts +1 -0
- package/src/template/components/Texts/texts.ts +1 -0
- package/src/template/components/sidebar/Sidebar.tsx +26 -0
- package/src/template/components/sidebar/SidebarItem.tsx +156 -0
- package/src/template/components/sidebar/ToggleButton.tsx +12 -0
- package/src/template/routes/root.tsx +1 -2
- package/build/template/components/Sidebar.d.ts.map +0 -1
- package/build/template/components/Sidebar.jsx +0 -115
- package/build/template/components/Sidebar.jsx.map +0 -1
- package/src/template/components/Sidebar.tsx +0 -194
- /package/build/template/components/{Sidebar.d.ts → sidebar/Sidebar.d.ts} +0 -0
package/src/lib/kit-temp.ts
CHANGED
@@ -59,3 +59,39 @@ export interface ImportEvent {
|
|
59
59
|
specifier: string
|
60
60
|
context: ResolveHookContext
|
61
61
|
}
|
62
|
+
|
63
|
+
export const ObjPick = <T extends object, K extends keyof T>(obj: T, keys: readonly K[]): Pick<T, K> => {
|
64
|
+
return keys.reduce((acc, key) => {
|
65
|
+
if (key in obj) {
|
66
|
+
acc[key] = obj[key]
|
67
|
+
}
|
68
|
+
return acc
|
69
|
+
}, {} as Pick<T, K>)
|
70
|
+
}
|
71
|
+
|
72
|
+
export const ObjOmit = <T extends object, K extends keyof T>(obj: T, keys: readonly K[]): Omit<T, K> => {
|
73
|
+
return keys.reduce((acc, key) => {
|
74
|
+
if (key in acc) {
|
75
|
+
// @ts-expect-error omitted already at type level
|
76
|
+
delete acc[key]
|
77
|
+
}
|
78
|
+
return acc
|
79
|
+
}, { ...obj } as Omit<T, K>)
|
80
|
+
}
|
81
|
+
|
82
|
+
export const ObjPartition = <T extends object, K extends keyof T>(
|
83
|
+
obj: T,
|
84
|
+
keys: readonly K[],
|
85
|
+
): { omitted: Omit<T, K>; picked: Pick<T, K> } => {
|
86
|
+
return keys.reduce((acc, key) => {
|
87
|
+
if (key in acc.omitted) {
|
88
|
+
// @ts-expect-error omitted already at type level
|
89
|
+
delete acc.omitted[key]
|
90
|
+
acc.picked[key] = obj[key]
|
91
|
+
}
|
92
|
+
return acc
|
93
|
+
}, {
|
94
|
+
omitted: { ...obj } as Omit<T, K>,
|
95
|
+
picked: {} as Pick<T, K>,
|
96
|
+
})
|
97
|
+
}
|
@@ -1,15 +1,62 @@
|
|
1
1
|
import type { FC } from 'react'
|
2
2
|
import type { LinkProps as LinkPropsReactRouter } from 'react-router'
|
3
|
-
import { Link as LinkReactRouter } from 'react-router'
|
3
|
+
import { Link as LinkReactRouter, useLocation } from 'react-router'
|
4
|
+
// todo: #lib/kit-temp does not work as import
|
5
|
+
import { ObjPartition } from '../../lib/kit-temp.js'
|
4
6
|
import type { LinkPropsRadix } from './RadixLink.jsx'
|
5
7
|
import { LinkRadix } from './RadixLink.jsx'
|
6
8
|
|
7
|
-
|
8
|
-
|
9
|
-
|
9
|
+
const reactRouterPropKeys = [
|
10
|
+
'discover',
|
11
|
+
'prefetch',
|
12
|
+
'reloadDocument',
|
13
|
+
'replace',
|
14
|
+
'state',
|
15
|
+
'preventScrollReset',
|
16
|
+
'relative',
|
17
|
+
'to',
|
18
|
+
'viewTransition',
|
19
|
+
'children',
|
20
|
+
] as const
|
21
|
+
|
22
|
+
export const Link: FC<LinkPropsReactRouter & Omit<LinkPropsRadix, 'asChild'>> = props => {
|
23
|
+
const location = useLocation()
|
24
|
+
const toPathExp = typeof props.to === 'string' ? props.to : props.to.pathname || ''
|
25
|
+
const active = getPathActiveReport(toPathExp, location.pathname)
|
26
|
+
|
27
|
+
const { picked: reactRouterProps, omitted: radixProps } = ObjPartition(props, reactRouterPropKeys)
|
28
|
+
|
10
29
|
return (
|
11
|
-
<LinkRadix
|
12
|
-
|
30
|
+
<LinkRadix
|
31
|
+
asChild
|
32
|
+
{...radixProps}
|
33
|
+
data-active={active.is || undefined}
|
34
|
+
data-active-direct={active.isDirect || undefined}
|
35
|
+
data-active-descendant={active.isdescendant || undefined}
|
36
|
+
>
|
37
|
+
<LinkReactRouter {...reactRouterProps} />
|
13
38
|
</LinkRadix>
|
14
39
|
)
|
15
40
|
}
|
41
|
+
|
42
|
+
export interface PathActiveReport {
|
43
|
+
is: boolean
|
44
|
+
isDirect: boolean
|
45
|
+
isdescendant: boolean
|
46
|
+
}
|
47
|
+
|
48
|
+
export const getPathActiveReport = (
|
49
|
+
pathExp: string,
|
50
|
+
currentPathExp: string,
|
51
|
+
): PathActiveReport => {
|
52
|
+
// Normalize paths for comparison - remove leading slash if present
|
53
|
+
const normalizedCurrentPath = currentPathExp.startsWith('/') ? currentPathExp.slice(1) : currentPathExp
|
54
|
+
const isDirect = normalizedCurrentPath === pathExp
|
55
|
+
const isdescendant = normalizedCurrentPath.startsWith(pathExp)
|
56
|
+
const is = isDirect || isdescendant
|
57
|
+
return {
|
58
|
+
is,
|
59
|
+
isDirect,
|
60
|
+
isdescendant,
|
61
|
+
}
|
62
|
+
}
|
@@ -0,0 +1,18 @@
|
|
1
|
+
import type { React } from '#dep/react/index'
|
2
|
+
import { Text, type TextProps } from '@radix-ui/themes'
|
3
|
+
|
4
|
+
export const MinorHeading: React.FC<TextProps> = (props) => {
|
5
|
+
return (
|
6
|
+
<Text
|
7
|
+
{...props}
|
8
|
+
weight='bold'
|
9
|
+
style={{
|
10
|
+
...props.style,
|
11
|
+
color: 'var(--accent-10)',
|
12
|
+
fontSize: '0.6rem',
|
13
|
+
letterSpacing: '0.025rem',
|
14
|
+
textTransform: 'uppercase',
|
15
|
+
}}
|
16
|
+
/>
|
17
|
+
)
|
18
|
+
}
|
@@ -0,0 +1 @@
|
|
1
|
+
export * as Texts from './texts.ts'
|
@@ -0,0 +1 @@
|
|
1
|
+
export * from './MinorHeading.tsx'
|
@@ -0,0 +1,26 @@
|
|
1
|
+
import type { FileRouter } from '#lib/file-router/index'
|
2
|
+
import { Box } from '@radix-ui/themes'
|
3
|
+
import { Items } from './SidebarItem.tsx'
|
4
|
+
|
5
|
+
interface SidebarProps {
|
6
|
+
items: FileRouter.Sidebar.Item[]
|
7
|
+
}
|
8
|
+
|
9
|
+
export const Sidebar = ({ items }: SidebarProps) => {
|
10
|
+
return (
|
11
|
+
<Box
|
12
|
+
data-testid='sidebar'
|
13
|
+
role='Sidebar'
|
14
|
+
flexShrink='0'
|
15
|
+
>
|
16
|
+
<style>
|
17
|
+
{`
|
18
|
+
div[role="Sidebar"] a:not([data-active]):hover {
|
19
|
+
background-color: var(--iris-2) !important;
|
20
|
+
}
|
21
|
+
`}
|
22
|
+
</style>
|
23
|
+
<Items items={items} />
|
24
|
+
</Box>
|
25
|
+
)
|
26
|
+
}
|
@@ -0,0 +1,156 @@
|
|
1
|
+
import type { React } from '#dep/react/index'
|
2
|
+
import type { FileRouter } from '#lib/file-router/index'
|
3
|
+
import { Texts } from '#template/components/Texts/index'
|
4
|
+
import { Box, Flex, Text } from '@radix-ui/themes'
|
5
|
+
import { useLocation } from 'react-router'
|
6
|
+
import { getPathActiveReport, Link } from '../Link.tsx'
|
7
|
+
|
8
|
+
export const Items: React.FC<{ items: FileRouter.Sidebar.Item[] }> = ({ items }) => {
|
9
|
+
return (
|
10
|
+
<Flex direction='column' gap='2px'>
|
11
|
+
{items.map((item) => (
|
12
|
+
<Item
|
13
|
+
key={item.pathExp}
|
14
|
+
item={item}
|
15
|
+
/>
|
16
|
+
))}
|
17
|
+
</Flex>
|
18
|
+
)
|
19
|
+
}
|
20
|
+
|
21
|
+
//
|
22
|
+
//
|
23
|
+
//
|
24
|
+
//
|
25
|
+
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ • SidebarItem
|
26
|
+
//
|
27
|
+
//
|
28
|
+
|
29
|
+
export const Item: React.FC<{ item: FileRouter.Sidebar.Item }> = ({ item }) => {
|
30
|
+
if (item.type === `ItemLink`) {
|
31
|
+
return <SBLink link={item} />
|
32
|
+
}
|
33
|
+
|
34
|
+
if (item.type === 'ItemSection' && item.isLinkToo) {
|
35
|
+
return <LinkedSection section={item} />
|
36
|
+
}
|
37
|
+
|
38
|
+
return <Section section={item} />
|
39
|
+
}
|
40
|
+
|
41
|
+
//
|
42
|
+
//
|
43
|
+
//
|
44
|
+
//
|
45
|
+
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ • SidebarItemLink
|
46
|
+
//
|
47
|
+
//
|
48
|
+
|
49
|
+
const SBLink: React.FC<{
|
50
|
+
link: FileRouter.Sidebar.ItemLink | FileRouter.Sidebar.ItemSection
|
51
|
+
}> = ({ link }) => {
|
52
|
+
const location = useLocation()
|
53
|
+
const currentPathExp = location.pathname
|
54
|
+
const active = getPathActiveReport(link.pathExp, currentPathExp)
|
55
|
+
|
56
|
+
return (
|
57
|
+
<Link
|
58
|
+
role='Sidebar Link'
|
59
|
+
color={active.is ? `iris` : `gray`}
|
60
|
+
data-testid={`sidebar-link-${link.pathExp}`}
|
61
|
+
to={`/${link.pathExp}`}
|
62
|
+
style={{
|
63
|
+
display: `block`,
|
64
|
+
textDecoration: `none`,
|
65
|
+
color: active.is ? `var(--accent-12)` : undefined,
|
66
|
+
backgroundColor: active.isDirect ? `var(--accent-2)` : active.isdescendant ? `var(--accent-1)` : `transparent`,
|
67
|
+
borderRadius: `var(--radius-2)`,
|
68
|
+
}}
|
69
|
+
>
|
70
|
+
<Box py='2' px='4'>{link.title}</Box>
|
71
|
+
</Link>
|
72
|
+
)
|
73
|
+
}
|
74
|
+
|
75
|
+
//
|
76
|
+
//
|
77
|
+
//
|
78
|
+
//
|
79
|
+
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ • Section
|
80
|
+
//
|
81
|
+
//
|
82
|
+
|
83
|
+
const Section: React.FC<{
|
84
|
+
section: FileRouter.Sidebar.ItemSection
|
85
|
+
}> = ({ section }) => {
|
86
|
+
return (
|
87
|
+
<Box mt='8'>
|
88
|
+
<Box ml='4' mb='2'>
|
89
|
+
<Texts.MinorHeading color='gray'>
|
90
|
+
{section.title}
|
91
|
+
</Texts.MinorHeading>
|
92
|
+
</Box>
|
93
|
+
<Items items={section.links} />
|
94
|
+
</Box>
|
95
|
+
)
|
96
|
+
}
|
97
|
+
|
98
|
+
//
|
99
|
+
//
|
100
|
+
//
|
101
|
+
//
|
102
|
+
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ • LinkedSection
|
103
|
+
//
|
104
|
+
//
|
105
|
+
|
106
|
+
const LinkedSection: React.FC<{
|
107
|
+
section: FileRouter.Sidebar.ItemSection
|
108
|
+
}> = ({ section }) => {
|
109
|
+
return (
|
110
|
+
<Box>
|
111
|
+
<SBLink link={section} />
|
112
|
+
{
|
113
|
+
<Flex
|
114
|
+
direction='column'
|
115
|
+
gap='2'
|
116
|
+
id={`section-${section.pathExp.replace(/\//g, '-')}`}
|
117
|
+
role='group'
|
118
|
+
ml='5'
|
119
|
+
py='2px'
|
120
|
+
style={{
|
121
|
+
borderLeft: `1px solid var(--gray-5)`,
|
122
|
+
}}
|
123
|
+
>
|
124
|
+
{section.links.map((link) => (
|
125
|
+
<SectionLink
|
126
|
+
key={link.pathExp}
|
127
|
+
link={link}
|
128
|
+
/>
|
129
|
+
))}
|
130
|
+
</Flex>
|
131
|
+
}
|
132
|
+
</Box>
|
133
|
+
)
|
134
|
+
}
|
135
|
+
|
136
|
+
const SectionLink: React.FC<{ link: FileRouter.Sidebar.ItemLink }> = ({ link }) => {
|
137
|
+
const location = useLocation()
|
138
|
+
const active = getPathActiveReport(link.pathExp, location.pathname)
|
139
|
+
|
140
|
+
return (
|
141
|
+
<Link
|
142
|
+
role='Sidebar Link'
|
143
|
+
to={'/' + link.pathExp}
|
144
|
+
color={active.is ? `iris` : `gray`}
|
145
|
+
style={{
|
146
|
+
textDecoration: `none`,
|
147
|
+
color: active.is ? `var(--accent-12)` : undefined,
|
148
|
+
backgroundColor: active.isDirect ? `var(--accent-2)` : active.isdescendant ? `var(--accent-1)` : `transparent`,
|
149
|
+
borderBottomRightRadius: `var(--radius-2)`,
|
150
|
+
borderTopRightRadius: `var(--radius-2)`,
|
151
|
+
}}
|
152
|
+
>
|
153
|
+
<Box py='2' px='4'>{link.title}</Box>
|
154
|
+
</Link>
|
155
|
+
)
|
156
|
+
}
|
@@ -0,0 +1,12 @@
|
|
1
|
+
import { ChevronDownIcon, ChevronRightIcon } from '@radix-ui/react-icons'
|
2
|
+
import { Button } from '@radix-ui/themes'
|
3
|
+
|
4
|
+
export const ToggleButton = ({ isExpanded, toggleExpanded }: { isExpanded: boolean; toggleExpanded: () => void }) => (
|
5
|
+
<Button
|
6
|
+
variant='ghost'
|
7
|
+
onClick={toggleExpanded}
|
8
|
+
aria-expanded={isExpanded}
|
9
|
+
>
|
10
|
+
{isExpanded ? <ChevronDownIcon /> : <ChevronRightIcon />}
|
11
|
+
</Button>
|
12
|
+
)
|
@@ -11,7 +11,7 @@ import { PROJECT_DATA } from 'virtual:polen/project/data'
|
|
11
11
|
import { pages } from 'virtual:polen/project/pages.jsx'
|
12
12
|
import { templateVariables } from 'virtual:polen/template/variables'
|
13
13
|
import { Link } from '../components/Link.jsx'
|
14
|
-
import { Sidebar } from '../components/Sidebar.
|
14
|
+
import { Sidebar } from '../components/sidebar/Sidebar.tsx'
|
15
15
|
import entryClientUrl from '../entry.client.jsx?url'
|
16
16
|
import { changelog } from './changelog.jsx'
|
17
17
|
import { index } from './index.jsx'
|
@@ -74,7 +74,6 @@ const Layout = () => {
|
|
74
74
|
const currentNavPathExp = getCurrentNavPathExp()
|
75
75
|
const sidebar = currentNavPathExp && PROJECT_DATA.sidebarIndex[currentNavPathExp]
|
76
76
|
const showSidebar = sidebar && sidebar.items.length > 0
|
77
|
-
|
78
77
|
return (
|
79
78
|
<Theme asChild>
|
80
79
|
<Box m='8'>
|
@@ -1 +0,0 @@
|
|
1
|
-
{"version":3,"file":"Sidebar.d.ts","sourceRoot":"","sources":["../../../src/template/components/Sidebar.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAA;AAMxD,UAAU,YAAY;IACpB,KAAK,EAAE,UAAU,CAAC,OAAO,CAAC,IAAI,EAAE,CAAA;CACjC;AAED,eAAO,MAAM,OAAO,GAAI,WAAW,YAAY,gCA+C9C,CAAA"}
|
@@ -1,115 +0,0 @@
|
|
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
|
-
export const Sidebar = ({ items }) => {
|
6
|
-
const location = useLocation();
|
7
|
-
return (<Box data-testid='sidebar' style={{
|
8
|
-
width: `240px`,
|
9
|
-
minWidth: `240px`,
|
10
|
-
flexShrink: 0,
|
11
|
-
borderRight: `1px solid var(--gray-3)`,
|
12
|
-
height: `100%`,
|
13
|
-
paddingRight: `var(--space-4)`,
|
14
|
-
}}>
|
15
|
-
<style>
|
16
|
-
{`
|
17
|
-
/* Using data attributes - more idiomatic for Radix UI */
|
18
|
-
.sidebar-nav-item:hover:not([data-active]) {
|
19
|
-
background-color: var(--gray-2) !important;
|
20
|
-
}
|
21
|
-
.sidebar-section:hover:not([data-active]):not([data-active-child]) {
|
22
|
-
background-color: var(--gray-2) !important;
|
23
|
-
}
|
24
|
-
|
25
|
-
/* Alternative with class names (current approach) */
|
26
|
-
/*
|
27
|
-
.sidebar-nav-item:hover:not(.active) {
|
28
|
-
background-color: var(--gray-2) !important;
|
29
|
-
}
|
30
|
-
.sidebar-section:hover:not(.active):not(.has-active-child) {
|
31
|
-
background-color: var(--gray-2) !important;
|
32
|
-
}
|
33
|
-
*/
|
34
|
-
`}
|
35
|
-
</style>
|
36
|
-
<Flex direction='column' gap='1'>
|
37
|
-
{items.map((item) => (<SidebarItem key={item.pathExp} item={item} currentPathExp={location.pathname}/>))}
|
38
|
-
</Flex>
|
39
|
-
</Box>);
|
40
|
-
};
|
41
|
-
const SidebarItem = ({ item, currentPathExp, level = 0 }) => {
|
42
|
-
if (item.type === `ItemLink`) {
|
43
|
-
return <SidebarItemLink nav={item} currentPathExp={currentPathExp} level={level}/>;
|
44
|
-
}
|
45
|
-
return <SidebarItemSection section={item} currentPathExp={currentPathExp} level={level}/>;
|
46
|
-
};
|
47
|
-
const SidebarItemLink = ({ nav, currentPathExp, level }) => {
|
48
|
-
// Normalize paths for comparison - remove leading slash if present
|
49
|
-
const normalizedCurrentPath = currentPathExp.startsWith('/') ? currentPathExp.slice(1) : currentPathExp;
|
50
|
-
const isActive = normalizedCurrentPath === nav.pathExp;
|
51
|
-
return (<Link to={`/${nav.pathExp}`} data-active={isActive || undefined} className='sidebar-nav-item' style={{
|
52
|
-
textDecoration: `none`,
|
53
|
-
color: isActive ? `var(--accent-11)` : `var(--gray-12)`,
|
54
|
-
padding: `var(--space-2) var(--space-3)`,
|
55
|
-
paddingLeft: `calc(var(--space-3) + ${(level * 16).toString()}px)`,
|
56
|
-
borderRadius: `var(--radius-2)`,
|
57
|
-
display: `block`,
|
58
|
-
backgroundColor: isActive ? `var(--accent-3)` : `transparent`,
|
59
|
-
transition: `background-color 0.2s ease, color 0.2s ease`,
|
60
|
-
}}>
|
61
|
-
<Text size='2' weight={isActive ? `medium` : `regular`}>
|
62
|
-
{nav.title}
|
63
|
-
</Text>
|
64
|
-
</Link>);
|
65
|
-
};
|
66
|
-
const SidebarItemSection = ({ section, currentPathExp, level }) => {
|
67
|
-
const [isExpanded, setIsExpanded] = useState(true);
|
68
|
-
// Normalize paths for comparison - remove leading slash if present
|
69
|
-
const normalizedCurrentPath = currentPathExp.startsWith('/') ? currentPathExp.slice(1) : currentPathExp;
|
70
|
-
const isDirectlyActive = normalizedCurrentPath === section.pathExp;
|
71
|
-
const hasActiveChild = section.navs.some(nav => normalizedCurrentPath === nav.pathExp);
|
72
|
-
const isActiveGroup = isDirectlyActive || hasActiveChild;
|
73
|
-
return (<>
|
74
|
-
<Flex align='center' data-active={isDirectlyActive || undefined} data-active-child={hasActiveChild || undefined} className='sidebar-section' style={{
|
75
|
-
padding: `var(--space-2) var(--space-3)`,
|
76
|
-
paddingLeft: `calc(var(--space-3) + ${(level * 16).toString()}px)`,
|
77
|
-
borderRadius: `var(--radius-2)`,
|
78
|
-
backgroundColor: isDirectlyActive ? `var(--accent-3)` : hasActiveChild ? `var(--accent-2)` : `transparent`,
|
79
|
-
transition: `background-color 0.2s ease`,
|
80
|
-
}}>
|
81
|
-
<Box onClick={() => {
|
82
|
-
setIsExpanded(!isExpanded);
|
83
|
-
}} style={{
|
84
|
-
display: `flex`,
|
85
|
-
alignItems: `center`,
|
86
|
-
cursor: `pointer`,
|
87
|
-
padding: `4px`,
|
88
|
-
marginRight: `4px`,
|
89
|
-
marginLeft: `-4px`,
|
90
|
-
}}>
|
91
|
-
{isExpanded ? <ChevronDownIcon /> : <ChevronRightIcon />}
|
92
|
-
</Box>
|
93
|
-
{section.isNavToo
|
94
|
-
? (<Link to={`/${section.pathExp}`} style={{
|
95
|
-
textDecoration: `none`,
|
96
|
-
color: isDirectlyActive ? `var(--accent-11)` : `var(--gray-12)`,
|
97
|
-
flex: 1,
|
98
|
-
}}>
|
99
|
-
<Text size='2' weight={isDirectlyActive ? `bold` : `medium`}>
|
100
|
-
{section.title}
|
101
|
-
</Text>
|
102
|
-
</Link>)
|
103
|
-
: (<Text size='2' weight={isDirectlyActive ? `bold` : `medium`} style={{
|
104
|
-
flex: 1,
|
105
|
-
color: isDirectlyActive ? `var(--accent-11)` : `var(--gray-12)`,
|
106
|
-
}}>
|
107
|
-
{section.title}
|
108
|
-
</Text>)}
|
109
|
-
</Flex>
|
110
|
-
{isExpanded && (<Flex direction='column' gap='1'>
|
111
|
-
{section.navs.map((nav) => (<SidebarItemLink key={nav.pathExp} nav={nav} currentPathExp={currentPathExp} level={level + 1}/>))}
|
112
|
-
</Flex>)}
|
113
|
-
</>);
|
114
|
-
};
|
115
|
-
//# sourceMappingURL=Sidebar.jsx.map
|
@@ -1 +0,0 @@
|
|
1
|
-
{"version":3,"file":"Sidebar.jsx","sourceRoot":"","sources":["../../../src/template/components/Sidebar.tsx"],"names":[],"mappings":"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"}
|
@@ -1,194 +0,0 @@
|
|
1
|
-
import type { FileRouter } from '#lib/file-router/index'
|
2
|
-
import { ChevronDownIcon, ChevronRightIcon } from '@radix-ui/react-icons'
|
3
|
-
import { Box, Flex, Text } from '@radix-ui/themes'
|
4
|
-
import { useState } from 'react'
|
5
|
-
import { Link, useLocation } from 'react-router'
|
6
|
-
|
7
|
-
interface SidebarProps {
|
8
|
-
items: FileRouter.Sidebar.Item[]
|
9
|
-
}
|
10
|
-
|
11
|
-
export const Sidebar = ({ items }: SidebarProps) => {
|
12
|
-
const location = useLocation()
|
13
|
-
|
14
|
-
return (
|
15
|
-
<Box
|
16
|
-
data-testid='sidebar'
|
17
|
-
style={{
|
18
|
-
width: `240px`,
|
19
|
-
minWidth: `240px`,
|
20
|
-
flexShrink: 0,
|
21
|
-
borderRight: `1px solid var(--gray-3)`,
|
22
|
-
height: `100%`,
|
23
|
-
paddingRight: `var(--space-4)`,
|
24
|
-
}}
|
25
|
-
>
|
26
|
-
<style>
|
27
|
-
{`
|
28
|
-
/* Using data attributes - more idiomatic for Radix UI */
|
29
|
-
.sidebar-nav-item:hover:not([data-active]) {
|
30
|
-
background-color: var(--gray-2) !important;
|
31
|
-
}
|
32
|
-
.sidebar-section:hover:not([data-active]):not([data-active-child]) {
|
33
|
-
background-color: var(--gray-2) !important;
|
34
|
-
}
|
35
|
-
|
36
|
-
/* Alternative with class names (current approach) */
|
37
|
-
/*
|
38
|
-
.sidebar-nav-item:hover:not(.active) {
|
39
|
-
background-color: var(--gray-2) !important;
|
40
|
-
}
|
41
|
-
.sidebar-section:hover:not(.active):not(.has-active-child) {
|
42
|
-
background-color: var(--gray-2) !important;
|
43
|
-
}
|
44
|
-
*/
|
45
|
-
`}
|
46
|
-
</style>
|
47
|
-
<Flex direction='column' gap='1'>
|
48
|
-
{items.map((item) => (
|
49
|
-
<SidebarItem
|
50
|
-
key={item.pathExp}
|
51
|
-
item={item}
|
52
|
-
currentPathExp={location.pathname}
|
53
|
-
/>
|
54
|
-
))}
|
55
|
-
</Flex>
|
56
|
-
</Box>
|
57
|
-
)
|
58
|
-
}
|
59
|
-
|
60
|
-
interface SidebarItemProps {
|
61
|
-
item: FileRouter.Sidebar.Item
|
62
|
-
currentPathExp: string
|
63
|
-
level?: number
|
64
|
-
}
|
65
|
-
|
66
|
-
const SidebarItem = ({ item, currentPathExp, level = 0 }: SidebarItemProps) => {
|
67
|
-
if (item.type === `ItemLink`) {
|
68
|
-
return <SidebarItemLink nav={item} currentPathExp={currentPathExp} level={level} />
|
69
|
-
}
|
70
|
-
|
71
|
-
return <SidebarItemSection section={item} currentPathExp={currentPathExp} level={level} />
|
72
|
-
}
|
73
|
-
|
74
|
-
interface SidebarItemLinkProps {
|
75
|
-
nav: FileRouter.Sidebar.ItemLink
|
76
|
-
currentPathExp: string
|
77
|
-
level: number
|
78
|
-
}
|
79
|
-
|
80
|
-
const SidebarItemLink = ({ nav, currentPathExp, level }: SidebarItemLinkProps) => {
|
81
|
-
// Normalize paths for comparison - remove leading slash if present
|
82
|
-
const normalizedCurrentPath = currentPathExp.startsWith('/') ? currentPathExp.slice(1) : currentPathExp
|
83
|
-
const isActive = normalizedCurrentPath === nav.pathExp
|
84
|
-
|
85
|
-
return (
|
86
|
-
<Link
|
87
|
-
to={`/${nav.pathExp}`}
|
88
|
-
data-active={isActive || undefined}
|
89
|
-
className='sidebar-nav-item'
|
90
|
-
style={{
|
91
|
-
textDecoration: `none`,
|
92
|
-
color: isActive ? `var(--accent-11)` : `var(--gray-12)`,
|
93
|
-
padding: `var(--space-2) var(--space-3)`,
|
94
|
-
paddingLeft: `calc(var(--space-3) + ${(level * 16).toString()}px)`,
|
95
|
-
borderRadius: `var(--radius-2)`,
|
96
|
-
display: `block`,
|
97
|
-
backgroundColor: isActive ? `var(--accent-3)` : `transparent`,
|
98
|
-
transition: `background-color 0.2s ease, color 0.2s ease`,
|
99
|
-
}}
|
100
|
-
>
|
101
|
-
<Text size='2' weight={isActive ? `medium` : `regular`}>
|
102
|
-
{nav.title}
|
103
|
-
</Text>
|
104
|
-
</Link>
|
105
|
-
)
|
106
|
-
}
|
107
|
-
|
108
|
-
interface SidebarItemSectionProps {
|
109
|
-
section: FileRouter.Sidebar.ItemSection
|
110
|
-
currentPathExp: string
|
111
|
-
level: number
|
112
|
-
}
|
113
|
-
|
114
|
-
const SidebarItemSection = ({ section, currentPathExp, level }: SidebarItemSectionProps) => {
|
115
|
-
const [isExpanded, setIsExpanded] = useState(true)
|
116
|
-
// Normalize paths for comparison - remove leading slash if present
|
117
|
-
const normalizedCurrentPath = currentPathExp.startsWith('/') ? currentPathExp.slice(1) : currentPathExp
|
118
|
-
const isDirectlyActive = normalizedCurrentPath === section.pathExp
|
119
|
-
const hasActiveChild = section.navs.some(nav => normalizedCurrentPath === nav.pathExp)
|
120
|
-
const isActiveGroup = isDirectlyActive || hasActiveChild
|
121
|
-
|
122
|
-
return (
|
123
|
-
<>
|
124
|
-
<Flex
|
125
|
-
align='center'
|
126
|
-
data-active={isDirectlyActive || undefined}
|
127
|
-
data-active-child={hasActiveChild || undefined}
|
128
|
-
className='sidebar-section'
|
129
|
-
style={{
|
130
|
-
padding: `var(--space-2) var(--space-3)`,
|
131
|
-
paddingLeft: `calc(var(--space-3) + ${(level * 16).toString()}px)`,
|
132
|
-
borderRadius: `var(--radius-2)`,
|
133
|
-
backgroundColor: isDirectlyActive ? `var(--accent-3)` : hasActiveChild ? `var(--accent-2)` : `transparent`,
|
134
|
-
transition: `background-color 0.2s ease`,
|
135
|
-
}}
|
136
|
-
>
|
137
|
-
<Box
|
138
|
-
onClick={() => {
|
139
|
-
setIsExpanded(!isExpanded)
|
140
|
-
}}
|
141
|
-
style={{
|
142
|
-
display: `flex`,
|
143
|
-
alignItems: `center`,
|
144
|
-
cursor: `pointer`,
|
145
|
-
padding: `4px`,
|
146
|
-
marginRight: `4px`,
|
147
|
-
marginLeft: `-4px`,
|
148
|
-
}}
|
149
|
-
>
|
150
|
-
{isExpanded ? <ChevronDownIcon /> : <ChevronRightIcon />}
|
151
|
-
</Box>
|
152
|
-
{section.isNavToo
|
153
|
-
? (
|
154
|
-
<Link
|
155
|
-
to={`/${section.pathExp}`}
|
156
|
-
style={{
|
157
|
-
textDecoration: `none`,
|
158
|
-
color: isDirectlyActive ? `var(--accent-11)` : `var(--gray-12)`,
|
159
|
-
flex: 1,
|
160
|
-
}}
|
161
|
-
>
|
162
|
-
<Text size='2' weight={isDirectlyActive ? `bold` : `medium`}>
|
163
|
-
{section.title}
|
164
|
-
</Text>
|
165
|
-
</Link>
|
166
|
-
)
|
167
|
-
: (
|
168
|
-
<Text
|
169
|
-
size='2'
|
170
|
-
weight={isDirectlyActive ? `bold` : `medium`}
|
171
|
-
style={{
|
172
|
-
flex: 1,
|
173
|
-
color: isDirectlyActive ? `var(--accent-11)` : `var(--gray-12)`,
|
174
|
-
}}
|
175
|
-
>
|
176
|
-
{section.title}
|
177
|
-
</Text>
|
178
|
-
)}
|
179
|
-
</Flex>
|
180
|
-
{isExpanded && (
|
181
|
-
<Flex direction='column' gap='1'>
|
182
|
-
{section.navs.map((nav) => (
|
183
|
-
<SidebarItemLink
|
184
|
-
key={nav.pathExp}
|
185
|
-
nav={nav}
|
186
|
-
currentPathExp={currentPathExp}
|
187
|
-
level={level + 1}
|
188
|
-
/>
|
189
|
-
))}
|
190
|
-
</Flex>
|
191
|
-
)}
|
192
|
-
</>
|
193
|
-
)
|
194
|
-
}
|
File without changes
|