polen 0.8.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 -112
  72. package/build/template/components/Sidebar.jsx.map +0 -1
  73. package/src/template/components/Sidebar.tsx +0 -190
  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,gCA0B9C,CAAA"}
@@ -1,112 +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
- <Flex direction='column' gap='1'>
16
- {items.map((item) => (<SidebarItemComponent key={item.pathExp} item={item} currentPathExp={location.pathname}/>))}
17
- </Flex>
18
- </Box>);
19
- };
20
- const SidebarItemComponent = ({ item, currentPathExp, level = 0 }) => {
21
- if (item.type === `ItemLink`) {
22
- return <SidebarNavItem nav={item} currentPathExp={currentPathExp} level={level}/>;
23
- }
24
- return <SidebarSectionItem section={item} currentPathExp={currentPathExp} level={level}/>;
25
- };
26
- const SidebarNavItem = ({ nav, currentPathExp, level }) => {
27
- // Normalize paths for comparison - remove leading slash if present
28
- const normalizedCurrentPath = currentPathExp.startsWith('/') ? currentPathExp.slice(1) : currentPathExp;
29
- const isActive = normalizedCurrentPath === nav.pathExp;
30
- return (<Link to={`/${nav.pathExp}`} style={{
31
- textDecoration: `none`,
32
- color: isActive ? `var(--accent-11)` : `var(--gray-12)`,
33
- padding: `var(--space-2) var(--space-3)`,
34
- paddingLeft: `calc(var(--space-3) + ${(level * 16).toString()}px)`,
35
- borderRadius: `var(--radius-2)`,
36
- display: `block`,
37
- backgroundColor: isActive ? `var(--accent-3)` : `transparent`,
38
- transition: `background-color 0.2s ease, color 0.2s ease`,
39
- }} onMouseEnter={(e) => {
40
- if (!isActive) {
41
- e.currentTarget.style.backgroundColor = `var(--gray-2)`;
42
- }
43
- }} onMouseLeave={(e) => {
44
- if (!isActive) {
45
- e.currentTarget.style.backgroundColor = `transparent`;
46
- }
47
- }}>
48
- <Text size='2' weight={isActive ? `medium` : `regular`}>
49
- {nav.title}
50
- </Text>
51
- </Link>);
52
- };
53
- const SidebarSectionItem = ({ section, currentPathExp, level }) => {
54
- const [isExpanded, setIsExpanded] = useState(true);
55
- // Normalize paths for comparison - remove leading slash if present
56
- const normalizedCurrentPath = currentPathExp.startsWith('/') ? currentPathExp.slice(1) : currentPathExp;
57
- const isDirectlyActive = normalizedCurrentPath === section.pathExp;
58
- const hasActiveChild = section.navs.some(nav => normalizedCurrentPath === nav.pathExp);
59
- const isActiveGroup = isDirectlyActive || hasActiveChild;
60
- return (<>
61
- <Flex align='center' style={{
62
- padding: `var(--space-2) var(--space-3)`,
63
- paddingLeft: `calc(var(--space-3) + ${(level * 16).toString()}px)`,
64
- borderRadius: `var(--radius-2)`,
65
- backgroundColor: isDirectlyActive ? `var(--accent-3)` : hasActiveChild ? `var(--accent-2)` : `transparent`,
66
- transition: `background-color 0.2s ease`,
67
- }} onMouseEnter={(e) => {
68
- if (!isActiveGroup) {
69
- e.currentTarget.style.backgroundColor = `var(--gray-2)`;
70
- }
71
- }} onMouseLeave={(e) => {
72
- if (!isActiveGroup) {
73
- e.currentTarget.style.backgroundColor = `transparent`;
74
- }
75
- }}>
76
- <Box onClick={(e) => {
77
- e.stopPropagation();
78
- console.log(`Chevron clicked!`);
79
- setIsExpanded(!isExpanded);
80
- }} style={{
81
- display: `flex`,
82
- alignItems: `center`,
83
- cursor: `pointer`,
84
- padding: `4px`,
85
- marginRight: `4px`,
86
- marginLeft: `-4px`,
87
- }}>
88
- {isExpanded ? <ChevronDownIcon /> : <ChevronRightIcon />}
89
- </Box>
90
- {section.isNavToo
91
- ? (<Link to={`/${section.pathExp}`} style={{
92
- textDecoration: `none`,
93
- color: isDirectlyActive ? `var(--accent-11)` : `var(--gray-12)`,
94
- flex: 1,
95
- }}>
96
- <Text size='2' weight={isDirectlyActive ? `bold` : `medium`}>
97
- {section.title}
98
- </Text>
99
- </Link>)
100
- : (<Text size='2' weight={isDirectlyActive ? `bold` : `medium`} style={{
101
- flex: 1,
102
- color: isDirectlyActive ? `var(--accent-11)` : `var(--gray-12)`,
103
- }}>
104
- {section.title}
105
- </Text>)}
106
- </Flex>
107
- {isExpanded && (<Flex direction='column' gap='1'>
108
- {section.navs.map((nav) => (<SidebarNavItem key={nav.pathExp} nav={nav} currentPathExp={currentPathExp} level={level + 1}/>))}
109
- </Flex>)}
110
- </>);
111
- };
112
- //# 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,190 +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
- <Flex direction='column' gap='1'>
27
- {items.map((item) => (
28
- <SidebarItemComponent
29
- key={item.pathExp}
30
- item={item}
31
- currentPathExp={location.pathname}
32
- />
33
- ))}
34
- </Flex>
35
- </Box>
36
- )
37
- }
38
-
39
- interface SidebarItemComponentProps {
40
- item: FileRouter.Sidebar.Item
41
- currentPathExp: string
42
- level?: number
43
- }
44
-
45
- const SidebarItemComponent = ({ item, currentPathExp, level = 0 }: SidebarItemComponentProps) => {
46
- if (item.type === `ItemLink`) {
47
- return <SidebarNavItem nav={item} currentPathExp={currentPathExp} level={level} />
48
- }
49
-
50
- return <SidebarSectionItem section={item} currentPathExp={currentPathExp} level={level} />
51
- }
52
-
53
- interface SidebarNavItemProps {
54
- nav: FileRouter.Sidebar.ItemLink
55
- currentPathExp: string
56
- level: number
57
- }
58
-
59
- const SidebarNavItem = ({ nav, currentPathExp, level }: SidebarNavItemProps) => {
60
- // Normalize paths for comparison - remove leading slash if present
61
- const normalizedCurrentPath = currentPathExp.startsWith('/') ? currentPathExp.slice(1) : currentPathExp
62
- const isActive = normalizedCurrentPath === nav.pathExp
63
-
64
- return (
65
- <Link
66
- to={`/${nav.pathExp}`}
67
- style={{
68
- textDecoration: `none`,
69
- color: isActive ? `var(--accent-11)` : `var(--gray-12)`,
70
- padding: `var(--space-2) var(--space-3)`,
71
- paddingLeft: `calc(var(--space-3) + ${(level * 16).toString()}px)`,
72
- borderRadius: `var(--radius-2)`,
73
- display: `block`,
74
- backgroundColor: isActive ? `var(--accent-3)` : `transparent`,
75
- transition: `background-color 0.2s ease, color 0.2s ease`,
76
- }}
77
- onMouseEnter={(e) => {
78
- if (!isActive) {
79
- e.currentTarget.style.backgroundColor = `var(--gray-2)`
80
- }
81
- }}
82
- onMouseLeave={(e) => {
83
- if (!isActive) {
84
- e.currentTarget.style.backgroundColor = `transparent`
85
- }
86
- }}
87
- >
88
- <Text size='2' weight={isActive ? `medium` : `regular`}>
89
- {nav.title}
90
- </Text>
91
- </Link>
92
- )
93
- }
94
-
95
- interface SidebarSectionItemProps {
96
- section: FileRouter.Sidebar.ItemSection
97
- currentPathExp: string
98
- level: number
99
- }
100
-
101
- const SidebarSectionItem = ({ section, currentPathExp, level }: SidebarSectionItemProps) => {
102
- const [isExpanded, setIsExpanded] = useState(true)
103
- // Normalize paths for comparison - remove leading slash if present
104
- const normalizedCurrentPath = currentPathExp.startsWith('/') ? currentPathExp.slice(1) : currentPathExp
105
- const isDirectlyActive = normalizedCurrentPath === section.pathExp
106
- const hasActiveChild = section.navs.some(nav => normalizedCurrentPath === nav.pathExp)
107
- const isActiveGroup = isDirectlyActive || hasActiveChild
108
-
109
- return (
110
- <>
111
- <Flex
112
- align='center'
113
- style={{
114
- padding: `var(--space-2) var(--space-3)`,
115
- paddingLeft: `calc(var(--space-3) + ${(level * 16).toString()}px)`,
116
- borderRadius: `var(--radius-2)`,
117
- backgroundColor: isDirectlyActive ? `var(--accent-3)` : hasActiveChild ? `var(--accent-2)` : `transparent`,
118
- transition: `background-color 0.2s ease`,
119
- }}
120
- onMouseEnter={(e) => {
121
- if (!isActiveGroup) {
122
- e.currentTarget.style.backgroundColor = `var(--gray-2)`
123
- }
124
- }}
125
- onMouseLeave={(e) => {
126
- if (!isActiveGroup) {
127
- e.currentTarget.style.backgroundColor = `transparent`
128
- }
129
- }}
130
- >
131
- <Box
132
- onClick={(e) => {
133
- e.stopPropagation()
134
- console.log(`Chevron clicked!`)
135
- setIsExpanded(!isExpanded)
136
- }}
137
- style={{
138
- display: `flex`,
139
- alignItems: `center`,
140
- cursor: `pointer`,
141
- padding: `4px`,
142
- marginRight: `4px`,
143
- marginLeft: `-4px`,
144
- }}
145
- >
146
- {isExpanded ? <ChevronDownIcon /> : <ChevronRightIcon />}
147
- </Box>
148
- {section.isNavToo
149
- ? (
150
- <Link
151
- to={`/${section.pathExp}`}
152
- style={{
153
- textDecoration: `none`,
154
- color: isDirectlyActive ? `var(--accent-11)` : `var(--gray-12)`,
155
- flex: 1,
156
- }}
157
- >
158
- <Text size='2' weight={isDirectlyActive ? `bold` : `medium`}>
159
- {section.title}
160
- </Text>
161
- </Link>
162
- )
163
- : (
164
- <Text
165
- size='2'
166
- weight={isDirectlyActive ? `bold` : `medium`}
167
- style={{
168
- flex: 1,
169
- color: isDirectlyActive ? `var(--accent-11)` : `var(--gray-12)`,
170
- }}
171
- >
172
- {section.title}
173
- </Text>
174
- )}
175
- </Flex>
176
- {isExpanded && (
177
- <Flex direction='column' gap='1'>
178
- {section.navs.map((nav) => (
179
- <SidebarNavItem
180
- key={nav.pathExp}
181
- nav={nav}
182
- currentPathExp={currentPathExp}
183
- level={level + 1}
184
- />
185
- ))}
186
- </Flex>
187
- )}
188
- </>
189
- )
190
- }