duto 0.260915.0 → 0.261011.0
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/README.md +1 -1
- package/package.json +1 -1
- package/src/commands/new.ts +55 -30
- package/src/commands/templates/pages/README.md +21 -0
- package/src/commands/templates/pages/_gitignore +24 -0
- package/src/commands/templates/pages/components/html.tsx +55 -0
- package/src/commands/templates/pages/components/locale-select.tsx +59 -0
- package/src/commands/templates/pages/components/select.tsx +95 -0
- package/src/commands/templates/pages/components/theme-select.tsx +60 -0
- package/src/commands/templates/pages/i18n/en.ts +23 -0
- package/src/commands/templates/pages/i18n/index.ts +19 -0
- package/src/commands/templates/pages/i18n/pt-br.ts +23 -0
- package/src/commands/templates/pages/package.json +22 -0
- package/src/commands/templates/pages/pages/404.tsx +12 -0
- package/src/commands/templates/pages/pages/blog/[slug].tsx +88 -0
- package/src/commands/templates/pages/pages/blog/index.tsx +74 -0
- package/src/commands/templates/pages/pages/index.tsx +26 -0
- package/src/commands/templates/pages/pages/layout.tsx +26 -0
- package/src/commands/templates/pages/public/favicon.ico +0 -0
- package/src/commands/templates/pages/public/favicon.svg +1 -0
- package/src/commands/templates/pages/style.css +127 -0
- package/src/commands/templates/pages/tsconfig.json +56 -0
- package/src/commands/templates/pages/types.ts +8 -0
- package/src/commands/templates/server/base/.editorconfig +21 -0
- package/src/commands/templates/{base → server/base}/README.md +1 -1
- package/src/pages/cli/commands/dev.ts +10 -4
- package/src/pages/cli/utils.ts +7 -23
- package/src/pages/client/app.tsx +193 -91
- package/src/pages/client/link.ts +15 -41
- package/src/pages/client/storage.ts +1 -1
- package/src/pages/client/theme.ts +49 -0
- package/src/pages/compiler/aliases.ts +2 -8
- package/src/pages/compiler/ast.ts +1 -538
- package/src/pages/compiler/constants.ts +97 -13
- package/src/pages/compiler/index.ts +55 -140
- package/src/pages/compiler/meta.ts +40 -253
- package/src/pages/compiler/routes.ts +4 -5
- package/src/pages/compiler/types.ts +16 -125
- package/src/pages/compiler/vite-plugin.ts +64 -27
- package/src/pages/components/link.tsx +11 -19
- package/src/pages/i18n/client.ts +21 -10
- package/src/pages/i18n/server.ts +21 -6
- package/src/pages/index.ts +4 -22
- package/src/server/app.ts +2 -1
- package/src/server/routes.ts +4 -26
- package/src/utils.ts +34 -3
- package/src/pages/client/router.ts +0 -329
- package/src/pages/compiler/island.ts +0 -108
- /package/src/commands/templates/{base → pages}/.editorconfig +0 -0
- /package/src/commands/templates/{base → server/base}/.env.dev.example +0 -0
- /package/src/commands/templates/{base → server/base}/.env.prod.example +0 -0
- /package/src/commands/templates/{base → server/base}/_gitignore +0 -0
- /package/src/commands/templates/{base → server/base}/actions/blog/index.get.ts +0 -0
- /package/src/commands/templates/{base → server/base}/actions/blog/post/[id].get.ts +0 -0
- /package/src/commands/templates/{base → server/base}/actions/index.get.ts +0 -0
- /package/src/commands/templates/{base → server/base}/configs/duto.ts +0 -0
- /package/src/commands/templates/{base → server/base}/configs/roles.ts +0 -0
- /package/src/commands/templates/{base → server/base}/package.json +0 -0
- /package/src/commands/templates/{base → server/base}/tsconfig.json +0 -0
- /package/src/commands/templates/{workerd → server/workerd}/wrangler.toml +0 -0
package/src/pages/client/app.tsx
CHANGED
|
@@ -1,123 +1,225 @@
|
|
|
1
1
|
// @ts-ignore
|
|
2
2
|
import ':duto/hmr'
|
|
3
3
|
|
|
4
|
-
import { render,
|
|
4
|
+
import { render, h, type ComponentChild } from 'preact'
|
|
5
|
+
import { flushSync, useLayoutEffect, useState } from 'preact/compat'
|
|
5
6
|
import { Switch, Route, Router } from 'wouter-preact'
|
|
6
7
|
import { useLocation, useParams, useSearchParams, } from 'wouter-preact'
|
|
8
|
+
import type { AroundNavHandler } from 'wouter-preact'
|
|
9
|
+
import type { Params, StaticProps, View } from '#/compiler/types'
|
|
7
10
|
|
|
8
|
-
import {
|
|
9
|
-
fallbackLocale, locales, messages, routes, routeMap,
|
|
10
|
-
// @ts-ignore
|
|
11
|
-
} from ':duto/i18n'
|
|
12
|
-
// import i18n from '../i18n/client'
|
|
13
|
-
import i18n, { updatePickers } from '../i18n/client'
|
|
14
11
|
|
|
15
|
-
|
|
12
|
+
import { setThemeAttr, getTheme } from './theme'
|
|
16
13
|
|
|
14
|
+
setThemeAttr(getTheme())
|
|
15
|
+
|
|
16
|
+
// @ts-ignore
|
|
17
|
+
import { fallbackLocale, locales, routeMap } from ':duto/i18n'
|
|
18
|
+
// import i18n from '../i18n/client'
|
|
19
|
+
import i18n, {
|
|
20
|
+
detect, isPrefixed,
|
|
21
|
+
getLocale, setLocale,
|
|
22
|
+
cache, cached,
|
|
23
|
+
r, redirect,
|
|
24
|
+
route,
|
|
25
|
+
d, t, tl,
|
|
26
|
+
updatePickers,
|
|
27
|
+
} from '../i18n/client'
|
|
28
|
+
|
|
29
|
+
await i18n(fallbackLocale, locales, {}, {}, routeMap)
|
|
30
|
+
|
|
31
|
+
// Custom elements
|
|
17
32
|
import EI18n from '../i18n/element'
|
|
18
|
-
import Island from './island'
|
|
19
33
|
import Link from './link'
|
|
20
34
|
|
|
21
|
-
|
|
35
|
+
for (let [tag, el, opts] of [
|
|
36
|
+
['i-i', EI18n],
|
|
37
|
+
['i-l', Link, { extends: 'a' }],
|
|
38
|
+
] as [string, new () => HTMLElement, ElementDefinitionOptions?][]) {
|
|
39
|
+
!customElements.get(tag) && customElements.define(tag, el, opts)
|
|
40
|
+
}
|
|
22
41
|
|
|
23
42
|
import {
|
|
24
|
-
views,
|
|
43
|
+
views,
|
|
25
44
|
// @ts-ignore
|
|
26
45
|
} from ':duto'
|
|
27
46
|
// @ts-ignore
|
|
28
47
|
import ':root/styles'
|
|
29
48
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
49
|
+
|
|
50
|
+
// var props = {}
|
|
51
|
+
// const propKey = "props"
|
|
52
|
+
// const script = document.currentScript || ('function' == typeof document.querySelector ? document.querySelector(`script[${propKey}]`) : void 0)
|
|
53
|
+
// if (script) {
|
|
54
|
+
// const opts = script.getAttribute(propKey)
|
|
55
|
+
// if (opts) {
|
|
56
|
+
// try {
|
|
57
|
+
// props = JSON.parse(opts)
|
|
58
|
+
// } catch (e) { }
|
|
59
|
+
// }
|
|
60
|
+
// }
|
|
61
|
+
|
|
62
|
+
// @ts-ignore
|
|
63
|
+
self.$duto = self.$duto || {}
|
|
64
|
+
// @ts-ignore
|
|
65
|
+
Object.assign(self.$duto, {
|
|
66
|
+
// props,
|
|
67
|
+
// location: '/',
|
|
68
|
+
// navigate: {},
|
|
69
|
+
// params: {},
|
|
70
|
+
// search: {},
|
|
71
|
+
// setSearch: {},
|
|
72
|
+
i18n: {
|
|
73
|
+
detect, isPrefixed,
|
|
74
|
+
getLocale, setLocale,
|
|
75
|
+
cache, cached,
|
|
76
|
+
r, redirect,
|
|
77
|
+
route,
|
|
78
|
+
d, t, tl,
|
|
79
|
+
},
|
|
80
|
+
})
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
function normalizeParams(
|
|
84
|
+
raw: Record<string, string>,
|
|
85
|
+
paramDefs: Params
|
|
86
|
+
): Record<string, string | string[] | undefined> {
|
|
87
|
+
const result: Record<string, string | string[] | undefined> = {}
|
|
88
|
+
for (const def of paramDefs) {
|
|
89
|
+
const val = raw[def.name]
|
|
90
|
+
if (def.catchAll) {
|
|
91
|
+
result[def.name] = val
|
|
92
|
+
? val.split('/').filter(Boolean)
|
|
93
|
+
: def.optional ? undefined : []
|
|
94
|
+
} else {
|
|
95
|
+
result[def.name] = val === undefined && def.optional ? undefined : val
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
return result
|
|
37
99
|
}
|
|
38
|
-
import { renderRoute } from './router'
|
|
39
|
-
// import { navigate } from 'wouter-preact/use-hash-location'
|
|
40
100
|
|
|
41
|
-
|
|
42
|
-
[
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
101
|
+
async function resolveRoute(
|
|
102
|
+
[, Component, defs, getProps, layouts]: View,
|
|
103
|
+
rawParams: Record<string, string>,
|
|
104
|
+
) {
|
|
105
|
+
let props: StaticProps = defs ? normalizeParams(rawParams, defs) : { ...rawParams },
|
|
106
|
+
sProps = null
|
|
107
|
+
|
|
108
|
+
if (typeof Component === 'string') {
|
|
109
|
+
const mod = await import(/* @vite-ignore */ Component)
|
|
110
|
+
Component = mod.default
|
|
111
|
+
getProps = getProps === 1 ? mod.getProps : 0
|
|
112
|
+
sProps = mod.props ?? null
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// @ts-ignore
|
|
116
|
+
// const sProps = self.$duto?.props
|
|
117
|
+
// if (sProps && typeof sProps === 'object') { // @ts-ignore
|
|
118
|
+
// self.$duto.props = null
|
|
119
|
+
// Object.assign(props, sProps)
|
|
120
|
+
// } else
|
|
121
|
+
|
|
122
|
+
if (typeof getProps === 'function') {
|
|
123
|
+
try {
|
|
124
|
+
props = {
|
|
125
|
+
...(await getProps(props as Record<string, string | string[] | undefined>, sProps)),
|
|
126
|
+
...props
|
|
127
|
+
}
|
|
128
|
+
} catch (e) {
|
|
129
|
+
console.error('[ssg] getProps failed:', e)
|
|
130
|
+
}
|
|
131
|
+
} else if (sProps && typeof sProps === 'object' && !Array.isArray(sProps)) {
|
|
132
|
+
Object.assign(props, sProps)
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
let el = h(Component, props as any)
|
|
136
|
+
for (const layout of [layouts ?? []].flat())
|
|
137
|
+
el = h(layout, null, el)
|
|
138
|
+
|
|
139
|
+
return el
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
const promises = new Map<string, Promise<ComponentChild>>()
|
|
143
|
+
const resolved = new Map<string, ComponentChild>()
|
|
144
|
+
let last: ComponentChild = null
|
|
145
|
+
|
|
146
|
+
const keyOf = (view: View, params: Record<string, string>) => view[0] + '|' + JSON.stringify(params)
|
|
147
|
+
function load(view: View, params: Record<string, string>) {
|
|
148
|
+
const key = keyOf(view, params)
|
|
149
|
+
if (!promises.has(key)) {
|
|
150
|
+
promises.set(key, resolveRoute(view, params).then((el) => {
|
|
151
|
+
resolved.set(key, el)
|
|
152
|
+
return el
|
|
153
|
+
}))
|
|
154
|
+
}
|
|
155
|
+
return promises.get(key)
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
function View({ view, params }: { view: View, params: Record<string, string>}) {
|
|
159
|
+
const { 0: _wild, ...clean } = params
|
|
160
|
+
const key = keyOf(view, clean)
|
|
161
|
+
|
|
162
|
+
const [loaded, setLoaded] = useState(() => resolved.get(key) ?? last)
|
|
163
|
+
const el = resolved.get(key) ?? loaded
|
|
164
|
+
if (resolved.has(key)) last = el
|
|
165
|
+
|
|
166
|
+
useLayoutEffect(() => {
|
|
167
|
+
let cancelled = false
|
|
168
|
+
self.$duto.route = { pattern: view[0], params: clean, path: location.pathname }
|
|
169
|
+
|
|
170
|
+
load(view, clean).then(el => {
|
|
171
|
+
if (cancelled) return
|
|
172
|
+
last = el
|
|
173
|
+
setLoaded(el)
|
|
174
|
+
// self.dispatchEvent(new CustomEvent('d:load'))
|
|
175
|
+
})
|
|
176
|
+
return () => { cancelled = true }
|
|
177
|
+
}, [key])
|
|
178
|
+
|
|
179
|
+
return el
|
|
48
180
|
}
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
//
|
|
52
|
-
|
|
53
|
-
//
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
//
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
//
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
// path,
|
|
69
|
-
// component: ({ params }: { params: Record<string, string> }) => {
|
|
70
|
-
// // Trigger async render (updates container imperatively to avoid
|
|
71
|
-
// // React/Preact hook rules issues with async components)
|
|
72
|
-
|
|
73
|
-
// renderRoute(document.body, Component, params, defs, getProps)
|
|
74
|
-
// // Return null — renderRoute will call render() directly on the container
|
|
75
|
-
// return null
|
|
76
|
-
// },
|
|
77
|
-
// })
|
|
78
|
-
// ),
|
|
79
|
-
|
|
80
|
-
// ) ), document.body)
|
|
81
|
-
render(<Router>
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
// enable view transitions for navigation
|
|
184
|
+
const aroundNav: AroundNavHandler = (navigate, to, options) => {
|
|
185
|
+
// feature detection for browsers that dont support View Transitions
|
|
186
|
+
if (!document.startViewTransition)
|
|
187
|
+
return navigate(to, options)
|
|
188
|
+
|
|
189
|
+
// only use view transitions if explicitly requested
|
|
190
|
+
options?.transition
|
|
191
|
+
? document.startViewTransition(() => flushSync(() => navigate(to, options)))
|
|
192
|
+
: navigate(to, options)
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// clean prerendered content
|
|
196
|
+
while (document.body.firstChild)
|
|
197
|
+
document.body.removeChild(document.body.firstChild)
|
|
198
|
+
|
|
199
|
+
render(<Router aroundNav={aroundNav}>
|
|
82
200
|
{h(() => {
|
|
83
201
|
document.body.removeAttribute('hidden')
|
|
202
|
+
|
|
84
203
|
const [location, navigate] = useLocation()
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
204
|
+
self.$duto.location = location
|
|
205
|
+
self.$duto.navigate = (to,options) => {
|
|
206
|
+
to = new URL(to).pathname
|
|
207
|
+
navigate(to, options)
|
|
208
|
+
}
|
|
209
|
+
self.$duto.params = useParams()
|
|
210
|
+
|
|
88
211
|
const [search, setSearch] = useSearchParams()
|
|
89
|
-
|
|
90
|
-
|
|
212
|
+
self.$duto.search = search
|
|
213
|
+
self.$duto.setSearch = setSearch
|
|
91
214
|
|
|
92
|
-
// TODO: talvez registrar todos os valores pelo id do elemento em uma fila e atualizar nesse tick...
|
|
93
|
-
// input, select etc registra um update val e aqui popula..
|
|
94
215
|
updatePickers()
|
|
95
|
-
|
|
96
|
-
// React.useEffect(() => {
|
|
97
|
-
// document.body.removeAttribute('hidden');
|
|
98
|
-
// navigateRef.current = navigate;
|
|
99
|
-
// updatePickers();
|
|
100
|
-
// }, [navigate]);
|
|
101
|
-
// return null;
|
|
216
|
+
self.dispatchEvent(new CustomEvent('d:load'))
|
|
102
217
|
}, null)}
|
|
103
218
|
<Switch>
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
{/* @ts-ignore */}
|
|
109
|
-
{...views.map(([path, Component, defs, getProps, layouts]) => (
|
|
110
|
-
<Route path={path} component={({ params }: { params: Record<string, string> }) => {
|
|
111
|
-
// Trigger async render (updates container imperatively to avoid
|
|
112
|
-
// React/Preact hook rules issues with async components)
|
|
113
|
-
|
|
114
|
-
delete params[0]
|
|
115
|
-
window.$duto.route = { pattern: path, params, path: location.pathname }
|
|
116
|
-
|
|
117
|
-
renderRoute(document.body, Component, params, defs, getProps, layouts)
|
|
118
|
-
// Return null — renderRoute will call render() directly on the container
|
|
119
|
-
return null
|
|
120
|
-
}} />
|
|
219
|
+
{views.map(v => (
|
|
220
|
+
<Route key={v[0]} path={v[0]}>
|
|
221
|
+
{(params) => <View view={v} params={params} />}
|
|
222
|
+
</Route>
|
|
121
223
|
))}
|
|
122
224
|
</Switch>
|
|
123
225
|
</Router>, document.body)
|
package/src/pages/client/link.ts
CHANGED
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
self.addEventListener('d:navigate', e => {
|
|
2
|
+
const el = (e as CustomEvent<HTMLAnchorElement>).detail
|
|
3
|
+
|
|
4
|
+
console.warn('d:navigate', el)
|
|
5
|
+
if (el.href) self.$duto.navigate?.(el.href)
|
|
6
|
+
})
|
|
7
|
+
|
|
1
8
|
export default class Link extends HTMLAnchorElement {
|
|
2
9
|
static observedAttributes = [
|
|
3
10
|
'href',
|
|
@@ -12,7 +19,6 @@ export default class Link extends HTMLAnchorElement {
|
|
|
12
19
|
|
|
13
20
|
constructor() {
|
|
14
21
|
super()
|
|
15
|
-
|
|
16
22
|
this.addEventListener('click', this.#onClick)
|
|
17
23
|
}
|
|
18
24
|
|
|
@@ -21,50 +27,18 @@ export default class Link extends HTMLAnchorElement {
|
|
|
21
27
|
}
|
|
22
28
|
|
|
23
29
|
#onClick = (e: MouseEvent) => {
|
|
24
|
-
// Respeita comportamento padrão
|
|
25
30
|
if (
|
|
26
|
-
e.defaultPrevented
|
|
31
|
+
e.defaultPrevented // respects default behavior
|
|
27
32
|
|| this.target === '_blank'
|
|
28
|
-
|
|
29
|
-
|| e.ctrlKey
|
|
30
|
-
|| e.shiftKey
|
|
31
|
-
|| e.altKey
|
|
33
|
+
// allow ctrl/cmd+click to open in new tab normally
|
|
34
|
+
|| e.metaKey || e.ctrlKey || e.shiftKey || e.altKey
|
|
32
35
|
|| e.button !== 0
|
|
33
|
-
)
|
|
34
|
-
return
|
|
35
|
-
}
|
|
36
|
-
// Allow ctrl/cmd+click to open in new tab normally
|
|
37
|
-
if (e.metaKey || e.ctrlKey || e.shiftKey || e.altKey) return
|
|
38
|
-
// e.preventDefault()
|
|
39
|
-
if ((e.target as HTMLAnchorElement).hasAttribute('href'))
|
|
40
|
-
window.dispatchEvent(new CustomEvent('d:navigate', { detail: e.target }))
|
|
36
|
+
) return
|
|
41
37
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
}
|
|
38
|
+
e.preventDefault()
|
|
39
|
+
if (this.hasAttribute('href'))
|
|
40
|
+
self.dispatchEvent(new CustomEvent('d:navigate', { detail: this }))
|
|
46
41
|
|
|
47
|
-
|
|
48
|
-
get url() {
|
|
49
|
-
return new URL(this.href)
|
|
42
|
+
// TODO: scroll from #hash to elements
|
|
50
43
|
}
|
|
51
44
|
}
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
window.addEventListener('d:navigate', e => {
|
|
55
|
-
const el = (e as CustomEvent<HTMLAnchorElement>).detail
|
|
56
|
-
|
|
57
|
-
console.warn('d:navigate', el)
|
|
58
|
-
// if (href) _navigate?.(href)
|
|
59
|
-
// _navigate?.('/haha-2')
|
|
60
|
-
})
|
|
61
|
-
|
|
62
|
-
// const links = document.querySelectorAll('a[d]')
|
|
63
|
-
// for (const link of links) { // @ts-ignore
|
|
64
|
-
// link.addEventListener('click', (e: MouseEvent) => {
|
|
65
|
-
// // Allow ctrl/cmd+click to open in new tab normally
|
|
66
|
-
// if (e.metaKey || e.ctrlKey || e.shiftKey || e.altKey) return
|
|
67
|
-
// e.preventDefault()
|
|
68
|
-
// window.dispatchEvent(new CustomEvent('d:navigate', { detail: e.target }))
|
|
69
|
-
// })
|
|
70
|
-
// }
|
|
@@ -6,7 +6,7 @@ interface IStoreChange<TValue> {
|
|
|
6
6
|
old: TValue | null,
|
|
7
7
|
}
|
|
8
8
|
|
|
9
|
-
type IStoreListener<TValue> = (change: IStoreChange<TValue>) => void
|
|
9
|
+
export type IStoreListener<TValue> = (change: IStoreChange<TValue>) => void
|
|
10
10
|
|
|
11
11
|
/**
|
|
12
12
|
* Store reativo que encapsula o localStorage.
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { local, type IStoreListener } from './storage'
|
|
2
|
+
|
|
3
|
+
export type Theme = 'auto' | 'dark' | 'light'
|
|
4
|
+
|
|
5
|
+
const key = 'theme'
|
|
6
|
+
const themes = ['dark', 'light']
|
|
7
|
+
const match = () => matchMedia('(prefers-color-scheme: dark)')
|
|
8
|
+
export const preferredColorScheme = () => match().matches ? 'dark' : 'light'
|
|
9
|
+
export const setThemeAttr = (theme: Theme) => {
|
|
10
|
+
if (theme == 'auto') theme = preferredColorScheme()
|
|
11
|
+
document.documentElement.classList.toggle('dark', theme == 'dark')
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const isValid = (val: string) => themes.includes(val)
|
|
15
|
+
export const getTheme = () => {
|
|
16
|
+
const val = local.get<string>(key) || ''
|
|
17
|
+
return isValid(val) ? val : 'auto'
|
|
18
|
+
}
|
|
19
|
+
export const setTheme = (theme: Theme) => {
|
|
20
|
+
setThemeAttr(theme)
|
|
21
|
+
isValid(theme)
|
|
22
|
+
? local.set(key, theme)
|
|
23
|
+
: local.remove(key)
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export const onThemeChange = (e: IStoreListener<any>) => {
|
|
27
|
+
const mm = match()
|
|
28
|
+
mm.addEventListener('change', e)
|
|
29
|
+
return [local.subscribe(key, e), () => mm.removeEventListener('change', e)]
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// export function updatePickers(theme = storedTheme || 'auto') {
|
|
33
|
+
// document.querySelectorAll('.theme-select').forEach(el => {
|
|
34
|
+
// const select = el.querySelector('select')
|
|
35
|
+
// if (select) select.value = theme
|
|
36
|
+
// const tmpl = document.querySelector(`#theme-icons`)
|
|
37
|
+
// const newIcon = tmpl && tmpl.content.querySelector('.' + theme)
|
|
38
|
+
// if (newIcon) {
|
|
39
|
+
// const oldIcon = el.querySelector('svg.label-icon')
|
|
40
|
+
// if (oldIcon) oldIcon.replaceChildren(...newIcon.cloneNode(true).childNodes)
|
|
41
|
+
// }
|
|
42
|
+
// })
|
|
43
|
+
// }
|
|
44
|
+
|
|
45
|
+
// <template id="theme-icons">
|
|
46
|
+
// <Icon name="lucide:sun" class="light" />
|
|
47
|
+
// <Icon name="lucide:moon-star" class="dark" />
|
|
48
|
+
// <Icon name="lucide:swatch-book" class="auto" />
|
|
49
|
+
// </template>
|
|
@@ -1,14 +1,8 @@
|
|
|
1
1
|
import { join, resolve } from 'node:path'
|
|
2
|
-
import { readFileSync } from 'node:fs'
|
|
3
2
|
import { resolveExtension } from './file'
|
|
4
3
|
|
|
5
|
-
export function
|
|
6
|
-
const
|
|
7
|
-
return JSON.parse(content.replace(/\/\/.*$/gm, '').replace(/\/\*[\s\S]*?\*\//g, ''))
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
export function getAliases(root: string) {
|
|
11
|
-
const tsconfig = getTsConfig(join(root, './tsconfig.json'))
|
|
4
|
+
export async function getAliases(root: string) {
|
|
5
|
+
const tsconfig = await import(join(root, './tsconfig.json')) // @ts-ignore
|
|
12
6
|
const compilerOptions = tsconfig.compilerOptions || {}
|
|
13
7
|
const paths = Object.entries(compilerOptions.paths || {})
|
|
14
8
|
const baseUrl = compilerOptions.baseUrl || '.'
|