create-rue 0.0.7 → 0.0.11

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.
@@ -1,67 +1,221 @@
1
- import { type FC } from '@rue-js/rue'
1
+ import { computed, type FC, ref, useEffect, watch } from '@rue-js/rue'
2
2
  import { RouterLink, useRoute } from '@rue-js/router'
3
3
 
4
+ const themeStorageKey = 'rue.base.theme'
5
+ const reportHeaderStorageKey = 'rue.base.report.hideHeader'
6
+
4
7
  const navItems = [
5
8
  { to: '/', label: '首页' },
6
- { to: '/guide', label: '快速上手' },
7
- { to: '/packages', label: '包与集成' },
8
- { to: '/ecosystem', label: '生态能力' },
9
+ { to: '/report', label: '报表' },
10
+ { to: '/todo', label: 'Todo App' },
11
+ ]
12
+
13
+ const themes = [
14
+ 'light',
15
+ 'dark',
16
+ 'cupcake',
17
+ 'bumblebee',
18
+ 'corporate',
19
+ 'emerald',
20
+ 'synthwave',
21
+ 'retro',
22
+ 'cyberpunk',
23
+ 'valentine',
24
+ 'halloween',
25
+ 'garden',
26
+ 'forest',
27
+ 'aqua',
28
+ 'lofi',
29
+ 'pastel',
30
+ 'fantasy',
31
+ 'wireframe',
32
+ 'black',
33
+ 'luxury',
34
+ 'dracula',
35
+ 'cmyk',
36
+ 'autumn',
37
+ 'business',
38
+ 'acid',
39
+ 'lemonade',
40
+ 'night',
41
+ 'coffee',
42
+ 'winter',
43
+ 'dim',
44
+ 'nord',
45
+ 'sunset',
9
46
  ]
10
47
 
48
+ const themeLabels: Record<string, string> = {
49
+ light: '亮色',
50
+ dark: '暗色',
51
+ cupcake: '纸杯蛋糕',
52
+ bumblebee: '大黄蜂',
53
+ corporate: '企业',
54
+ emerald: '祖母绿',
55
+ synthwave: '合成波',
56
+ retro: '复古',
57
+ cyberpunk: '赛博朋克',
58
+ valentine: '情人节',
59
+ halloween: '万圣节',
60
+ garden: '花园',
61
+ forest: '森林',
62
+ aqua: '海洋蓝',
63
+ lofi: '低保真',
64
+ pastel: '粉彩',
65
+ fantasy: '奇幻',
66
+ wireframe: '线框',
67
+ black: '黑色',
68
+ luxury: '奢华',
69
+ dracula: '德古拉',
70
+ cmyk: 'CMYK',
71
+ autumn: '秋天',
72
+ business: '商务',
73
+ acid: '酸性',
74
+ lemonade: '柠檬水',
75
+ night: '夜间',
76
+ coffee: '咖啡',
77
+ winter: '冬季',
78
+ dim: '昏暗',
79
+ nord: '北欧',
80
+ sunset: '日落',
81
+ }
82
+
83
+ const getStoredTheme = () => localStorage.getItem(themeStorageKey) || 'light'
84
+
85
+ const getStoredHeaderHidden = () => localStorage.getItem(reportHeaderStorageKey) === '1'
86
+
87
+ const applyTheme = (theme: string) => {
88
+ document.documentElement.setAttribute('data-theme', theme)
89
+ }
90
+
91
+ const ThemePicker: FC = () => {
92
+ const theme = ref(getStoredTheme())
93
+
94
+ useEffect(() => {
95
+ applyTheme(theme.value)
96
+ })
97
+
98
+ watch(
99
+ () => theme.value,
100
+ () => {
101
+ applyTheme(theme.value)
102
+ localStorage.setItem(themeStorageKey, theme.value)
103
+ },
104
+ )
105
+
106
+ return (
107
+ <select
108
+ aria-label="切换主题"
109
+ className="select select-bordered select-sm w-40"
110
+ onChange={(event: Event) => {
111
+ theme.value = (event.currentTarget as HTMLSelectElement).value
112
+ }}
113
+ >
114
+ {themes.map(name => (
115
+ <option key={name} value={name} selected={theme.value === name}>
116
+ {themeLabels[name] || name}
117
+ </option>
118
+ ))}
119
+ </select>
120
+ )
121
+ }
122
+
11
123
  const Header: FC = () => {
12
124
  const route = useRoute()
13
- const currentPath = route.get()?.path || '/'
125
+ const currentPath = computed(() => route.get()?.path || '/')
14
126
 
15
127
  return (
16
- <header className="site-header">
17
- <div className="shell header-inner">
18
- <RouterLink to="/" className="brand">
19
- <span className="brand-mark">R</span>
20
- <span className="brand-copy">
21
- <span className="brand-title">Rue.js</span>
22
- <span className="brand-subtitle">The Vapor Native DOM Framework</span>
23
- </span>
24
- </RouterLink>
25
- <nav className="main-nav">
128
+ <header className="sticky top-0 z-40 border-b border-base-300/70 bg-base-100/85 backdrop-blur">
129
+ <div className="content-width navbar min-h-0 gap-4 py-3">
130
+ <div className="navbar-start min-w-0">
131
+ <RouterLink to="/" className="flex min-w-0 items-center gap-3">
132
+ <div className="flex h-10 w-10 items-center justify-center rounded-2xl bg-primary text-primary-content shadow-lg shadow-primary/20">
133
+ R
134
+ </div>
135
+ <div className="min-w-0">
136
+ <div className="truncate text-base font-semibold sm:text-lg">Rue Base Template</div>
137
+ </div>
138
+ </RouterLink>
139
+ </div>
140
+ <nav className="navbar-center hidden flex-1 justify-center gap-2 md:flex">
26
141
  {navItems.map(item => (
27
142
  <RouterLink
28
143
  key={item.to}
29
144
  to={item.to}
30
- className={`nav-link ${currentPath === item.to ? 'is-active' : ''}`}
145
+ className={`btn btn-sm ${currentPath.get() === item.to ? 'btn-primary' : 'btn-ghost'}`}
31
146
  >
32
147
  {item.label}
33
148
  </RouterLink>
34
149
  ))}
35
150
  </nav>
151
+ <div className="navbar-end flex items-center gap-2">
152
+ <ThemePicker />
153
+ </div>
36
154
  </div>
37
155
  </header>
38
156
  )
39
157
  }
40
158
 
41
159
  const Footer: FC = () => (
42
- <footer className="site-footer">
43
- <div className="shell footer-inner">
160
+ <footer className="border-t border-base-300/70 bg-base-100/75 backdrop-blur">
161
+ <div className="content-width flex flex-col gap-3 py-6 text-sm text-base-content/70 sm:flex-row sm:items-center sm:justify-between">
44
162
  <div>
45
- <div className="footer-title">Rue.js</div>
46
- <p className="footer-copy">已切换为基于 npm 已发布包的官网入口,可直接部署静态站点。</p>
163
+ <div className="font-semibold text-base-content">Rue Base Template</div>
47
164
  </div>
48
- <div className="footer-meta">
49
- <span>@rue-js/rue</span>
50
- <span>@rue-js/router</span>
51
- <span>@rue-js/vite-plugin-rue</span>
165
+ <div className="flex flex-wrap gap-2">
166
+ <span className="badge badge-outline">@rue-js/rue</span>
167
+ <span className="badge badge-outline">@rue-js/router</span>
168
+ <span className="badge badge-outline">DaisyUI Themes</span>
52
169
  </div>
53
170
  </div>
54
171
  </footer>
55
172
  )
56
173
 
57
- const SiteLayout: FC = props => (
58
- <div className="site-frame">
59
- <Header />
60
- <main className="site-main">
61
- <div className="shell">{props.children}</div>
62
- </main>
63
- <Footer />
64
- </div>
174
+ const HeaderToggleButton: FC<{ hidden: boolean; onToggle: () => void }> = props => (
175
+ <button
176
+ type="button"
177
+ className="btn btn-circle btn-sm fixed left-3 top-3 z-50 border-base-300 bg-base-100/90 shadow-lg backdrop-blur"
178
+ aria-label={props.hidden ? '显示顶部导航' : '隐藏顶部导航'}
179
+ title={props.hidden ? '显示顶部导航' : '隐藏顶部导航'}
180
+ onClick={props.onToggle}
181
+ >
182
+ {props.hidden ? '显' : '隐'}
183
+ </button>
65
184
  )
66
185
 
186
+ const SiteLayout: FC = props => {
187
+ const route = useRoute()
188
+ const reportHeaderHidden = ref(getStoredHeaderHidden())
189
+ const currentPath = computed(() => route.get()?.path || '/')
190
+ const isReportRoute = computed(() => currentPath.get() === '/report')
191
+ const hideHeader = computed(() => isReportRoute.get() && reportHeaderHidden.value)
192
+
193
+ watch(
194
+ () => reportHeaderHidden.value,
195
+ () => {
196
+ localStorage.setItem(reportHeaderStorageKey, reportHeaderHidden.value ? '1' : '0')
197
+ },
198
+ )
199
+
200
+ return (
201
+ <div className="app-shell">
202
+ <div className="app-surface">
203
+ {!hideHeader.get() && <Header />}
204
+ {isReportRoute.get() && (
205
+ <HeaderToggleButton
206
+ hidden={hideHeader.get()}
207
+ onToggle={() => {
208
+ reportHeaderHidden.value = !reportHeaderHidden.value
209
+ }}
210
+ />
211
+ )}
212
+ <main className={`content-width pb-10 ${hideHeader.get() ? 'pt-6 sm:pt-8' : 'pt-6 sm:pt-8'}`}>
213
+ {props.children}
214
+ </main>
215
+ <Footer />
216
+ </div>
217
+ </div>
218
+ )
219
+ }
220
+
67
221
  export default SiteLayout
@@ -3,9 +3,8 @@ import { createRouter, createWebHashHistory } from '@rue-js/router'
3
3
 
4
4
  const routes = [
5
5
  { path: '/', component: useComponent(() => import('./pages/Home')) },
6
- { path: '/guide', component: useComponent(() => import('./pages/Guide')) },
7
- { path: '/packages', component: useComponent(() => import('./pages/Packages')) },
8
- { path: '/ecosystem', component: useComponent(() => import('./pages/Ecosystem')) },
6
+ { path: '/report', component: useComponent(() => import('./pages/Report')) },
7
+ { path: '/todo', component: useComponent(() => import('./pages/TodoApp')) },
9
8
  ]
10
9
 
11
10
  export default createRouter({