create-rue 0.0.8 → 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.
- package/bundle.js +2 -2
- package/package.json +14 -17
- package/template/base/app/pages/Home.tsx +136 -55
- package/template/base/app/pages/Report.tsx +192 -0
- package/template/base/app/pages/TodoApp.tsx +464 -0
- package/template/base/app/pages/components/Layout.tsx +186 -32
- package/template/base/app/router.ts +2 -3
- package/template/base/package-lock.json +352 -350
- package/template/base/package.json +7 -7
- package/template/base/pnpm-lock.yaml +51 -51
- package/template/base/style.css +26 -415
- package/template/base/app/pages/Ecosystem.tsx +0 -47
- package/template/base/app/pages/Guide.tsx +0 -49
- package/template/base/app/pages/Packages.tsx +0 -52
|
@@ -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: '/
|
|
7
|
-
{ to: '/
|
|
8
|
-
|
|
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="
|
|
17
|
-
<div className="
|
|
18
|
-
<
|
|
19
|
-
<
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
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={`
|
|
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="
|
|
43
|
-
<div className="
|
|
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="
|
|
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="
|
|
49
|
-
<span>@rue-js/rue</span>
|
|
50
|
-
<span>@rue-js/router</span>
|
|
51
|
-
<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
|
|
58
|
-
<
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
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: '/
|
|
7
|
-
{ path: '/
|
|
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({
|