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.
Files changed (74) hide show
  1. package/build/api/vite/logger.d.ts +2 -1
  2. package/build/api/vite/logger.d.ts.map +1 -1
  3. package/build/api/vite/logger.js +23 -19
  4. package/build/api/vite/logger.js.map +1 -1
  5. package/build/api/vite/plugins/core.js +4 -4
  6. package/build/api/vite/plugins/core.js.map +1 -1
  7. package/build/api/vite/plugins/pages-tree.d.ts +1 -1
  8. package/build/api/vite/plugins/pages-tree.d.ts.map +1 -1
  9. package/build/api/vite/plugins/pages-tree.js +4 -3
  10. package/build/api/vite/plugins/pages-tree.js.map +1 -1
  11. package/build/api/vite/plugins/serve.d.ts.map +1 -1
  12. package/build/api/vite/plugins/serve.js +40 -7
  13. package/build/api/vite/plugins/serve.js.map +1 -1
  14. package/build/lib/file-router/sidebar/sidebar-tree.d.ts.map +1 -1
  15. package/build/lib/file-router/sidebar/sidebar-tree.js +13 -13
  16. package/build/lib/file-router/sidebar/sidebar-tree.js.map +1 -1
  17. package/build/lib/file-router/sidebar/types.d.ts +2 -2
  18. package/build/lib/file-router/sidebar/types.d.ts.map +1 -1
  19. package/build/lib/kit-temp.d.ts +6 -0
  20. package/build/lib/kit-temp.d.ts.map +1 -1
  21. package/build/lib/kit-temp.js +30 -0
  22. package/build/lib/kit-temp.js.map +1 -1
  23. package/build/template/components/Link.d.ts +7 -1
  24. package/build/template/components/Link.d.ts.map +1 -1
  25. package/build/template/components/Link.jsx +33 -5
  26. package/build/template/components/Link.jsx.map +1 -1
  27. package/build/template/components/Texts/MinorHeading.d.ts +4 -0
  28. package/build/template/components/Texts/MinorHeading.d.ts.map +1 -0
  29. package/build/template/components/Texts/MinorHeading.jsx +11 -0
  30. package/build/template/components/Texts/MinorHeading.jsx.map +1 -0
  31. package/build/template/components/Texts/index.d.ts +2 -0
  32. package/build/template/components/Texts/index.d.ts.map +1 -0
  33. package/build/template/components/Texts/index.js +2 -0
  34. package/build/template/components/Texts/index.js.map +1 -0
  35. package/build/template/components/Texts/texts.d.ts +2 -0
  36. package/build/template/components/Texts/texts.d.ts.map +1 -0
  37. package/build/template/components/Texts/texts.js +2 -0
  38. package/build/template/components/Texts/texts.js.map +1 -0
  39. package/build/template/components/sidebar/Sidebar.d.ts.map +1 -0
  40. package/build/template/components/sidebar/Sidebar.jsx +15 -0
  41. package/build/template/components/sidebar/Sidebar.jsx.map +1 -0
  42. package/build/template/components/sidebar/SidebarItem.d.ts +9 -0
  43. package/build/template/components/sidebar/SidebarItem.d.ts.map +1 -0
  44. package/build/template/components/sidebar/SidebarItem.jsx +94 -0
  45. package/build/template/components/sidebar/SidebarItem.jsx.map +1 -0
  46. package/build/template/components/sidebar/ToggleButton.d.ts +5 -0
  47. package/build/template/components/sidebar/ToggleButton.d.ts.map +1 -0
  48. package/build/template/components/sidebar/ToggleButton.jsx +6 -0
  49. package/build/template/components/sidebar/ToggleButton.jsx.map +1 -0
  50. package/build/template/routes/root.d.ts.map +1 -1
  51. package/build/template/routes/root.jsx +1 -1
  52. package/build/template/routes/root.jsx.map +1 -1
  53. package/package.json +15 -1
  54. package/src/api/vite/logger.ts +26 -21
  55. package/src/api/vite/plugins/core.ts +4 -4
  56. package/src/api/vite/plugins/pages-tree.ts +4 -3
  57. package/src/api/vite/plugins/serve.ts +42 -9
  58. package/src/lib/file-router/sidebar/sidebar-tree.test.ts +6 -6
  59. package/src/lib/file-router/sidebar/sidebar-tree.ts +14 -14
  60. package/src/lib/file-router/sidebar/types.ts +2 -2
  61. package/src/lib/kit-temp.ts +36 -0
  62. package/src/template/components/Link.tsx +53 -6
  63. package/src/template/components/Texts/MinorHeading.tsx +18 -0
  64. package/src/template/components/Texts/index.ts +1 -0
  65. package/src/template/components/Texts/texts.ts +1 -0
  66. package/src/template/components/sidebar/Sidebar.tsx +26 -0
  67. package/src/template/components/sidebar/SidebarItem.tsx +156 -0
  68. package/src/template/components/sidebar/ToggleButton.tsx +12 -0
  69. package/src/template/routes/root.tsx +1 -2
  70. package/build/template/components/Sidebar.d.ts.map +0 -1
  71. package/build/template/components/Sidebar.jsx +0 -115
  72. package/build/template/components/Sidebar.jsx.map +0 -1
  73. package/src/template/components/Sidebar.tsx +0 -194
  74. /package/build/template/components/{Sidebar.d.ts → sidebar/Sidebar.d.ts} +0 -0
@@ -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
- export const Link: FC<LinkPropsReactRouter & LinkPropsRadix> = props => {
8
- const { underline, color, m, mt, mb, ml, mr, my, mx } = props
9
- const radixProps = { underline, color, m, mt, mb, ml, mr, my, mx }
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 asChild {...radixProps}>
12
- <LinkReactRouter {...props}></LinkReactRouter>
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.jsx'
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
- }