@wrnrlr/prelude 0.0.1 → 0.1.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.
- package/.github/workflows/publish.yml +46 -5
- package/deno.json +18 -9
- package/package.json +4 -6
- package/readme.md +163 -41
- package/src/constants.ts +2 -1
- package/src/{controlflow.js → controlflow.ts} +63 -50
- package/src/hyperscript.ts +7 -6
- package/src/mod.ts +19 -17
- package/src/reactive.ts +42 -14
- package/src/resource.js +184 -0
- package/src/router.js +65 -0
- package/src/runtime.ts +9 -8
- package/test/hyperscript.js +2 -2
- package/test/reactive.js +12 -4
- package/www/assets/css/presets.css +504 -0
- package/www/assets/css/style.css +90 -0
- package/www/assets/fonts/fab.ttf +0 -0
- package/www/assets/fonts/fab.woff2 +0 -0
- package/www/assets/fonts/far.ttf +0 -0
- package/www/assets/fonts/far.woff2 +0 -0
- package/www/assets/fonts/fas.ttf +0 -0
- package/www/assets/fonts/fas.woff2 +0 -0
- package/www/index.html +211 -0
- package/www/playground.html +183 -0
- package/www/public/example/admin.html +88 -0
- package/{example → www/public/example}/counter.html +1 -1
- package/{example → www/public/example}/greeting.html +1 -1
- package/{example → www/public/example}/show.html +1 -1
- package/{example → www/public/example}/todo.html +1 -1
- package/www/public/logo.svg +16 -0
- package/www/typedoc.json +13 -0
- package/www/vite.config.js +106 -0
- package/example/paint.html +0 -22
- package/index.html +0 -230
- package/presets.css +0 -284
- package/public/logo.svg +0 -5
- package/test/runtime.js +0 -7
- package/typedoc.jsonc +0 -31
- /package/{public → www/public}/banner.svg +0 -0
package/www/index.html
ADDED
@@ -0,0 +1,211 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<head>
|
3
|
+
<title>Prelude</title>
|
4
|
+
<link href="https://unpkg.com/prismjs@1.29.0/themes/prism.css" rel="stylesheet" />
|
5
|
+
<script src="https://unpkg.com/prismjs@1.29.0/components/prism-core.min.js"></script>
|
6
|
+
<script src="https://unpkg.com/prismjs@1.29.0/plugins/autoloader/prism-autoloader.min.js"></script>
|
7
|
+
<script async src="https://www.googletagmanager.com/gtag/js?id=G-EPMJYD1EK8"></script>
|
8
|
+
<script>window.dataLayer = window.dataLayer || [];function gtag(){dataLayer.push(arguments);}gtag('js', new Date());gtag('config', 'G-EPMJYD1EK8');</script>
|
9
|
+
</head>
|
10
|
+
|
11
|
+
<nav class="flex p-2 justify-between">
|
12
|
+
<div class="flex items-center gap-3">
|
13
|
+
<svg viewBox="0 0 709 709" style="width: 50px; --color:var(--neutral-900)"><use xlink:href="./logo.svg#loop"></use></svg>
|
14
|
+
<span class="prelude text-xl">Prelude</span>
|
15
|
+
</div>
|
16
|
+
<div class="flex items-center gap-5">
|
17
|
+
<a href="/prelude/docs/index.html">Get Started</a>
|
18
|
+
<a href="/prelude/docs/modules.html">API</a>
|
19
|
+
<a class="px-3 py-2 rounded-md bg-green-600 text-white font-weight-500 text-shadow-green shadow" href="/prelude/playground">Playground</a>
|
20
|
+
</div>
|
21
|
+
</nav>
|
22
|
+
|
23
|
+
<main>
|
24
|
+
<section class="flex column items-center py-8">
|
25
|
+
<svg class="py-8" viewBox="0 0 709 709" style="width:300px;--color:var(--neutral-700)"><use xlink:href="./logo.svg#loop"></use></svg>
|
26
|
+
<div class="flex column center items-center gap-6">
|
27
|
+
<span class="prelude text-6xl">Prelude</span>
|
28
|
+
<span class="text-3xl">A signal-based web library that lets you <br> develop in a familiar functional style</span>
|
29
|
+
<div class="flex gap-4">
|
30
|
+
<a class="px-3 py-2 rounded-md bg-neutral-200 text-xl font-weight-500" href="/prelude/docs/index.html">Get Started</a>
|
31
|
+
<a class="px-3 py-2 rounded-md bg-green-600 text-xl text-white font-weight-500 shadow" href="/prelude/playground">Open Playground</a>
|
32
|
+
</div>
|
33
|
+
</div>
|
34
|
+
</section>
|
35
|
+
|
36
|
+
<section class="flex column items-center py-8 gap-8">
|
37
|
+
<h1 class="center text-5xl">Just write JavaScript!</h1>
|
38
|
+
<p class="center text-2xl">Instead of JSX, Prelude uses HyperScript,<br>
|
39
|
+
a DSL that lets you defined components in JavaScript.</p>
|
40
|
+
<div class="flex items-center content-center gap-8">
|
41
|
+
<pre><code class="language-js">import {h, signal, render} from 'prelude'
|
42
|
+
|
43
|
+
function Counter() {
|
44
|
+
const n = signal(1)
|
45
|
+
const onClick = e => n(i => i+1)
|
46
|
+
return h('button', {onClick}, n)
|
47
|
+
}
|
48
|
+
|
49
|
+
render(Counter, window.counter)</code></pre>
|
50
|
+
<div class="card">
|
51
|
+
<div class="title center">Counter</div>
|
52
|
+
<div class="flex justify-center content-center flex-wrap content" id="counter"></div>
|
53
|
+
</div>
|
54
|
+
</div>
|
55
|
+
<div class="flex column gap-4 items-start text-xl pl-10">
|
56
|
+
<p>Create a reactive value with <code class="language-js">const n = signal(1)</code>.</p>
|
57
|
+
<p>Define an event handler that increments the signal <code class="language-js">n(i=>i+1)</code>.</p>
|
58
|
+
<p>The function returned from <code class="language-js">h(...)</code> will render a HTML button <br>
|
59
|
+
that handles <code class="language-js">onclick</code> events and displays the counter value.</p>
|
60
|
+
<p>Prelude has fine-grained reactivity and will only update<br>those parts of the DOM that needs to be changed.</p>
|
61
|
+
</div>
|
62
|
+
</section>
|
63
|
+
|
64
|
+
<section class="flex column items-center py-8">
|
65
|
+
<p class="center text-2xl">Try in your Browser</p>
|
66
|
+
<div class="flex items-center gap-4 pt-6">
|
67
|
+
<a class="px-3 py-2 rounded-md bg-green-600 text-xl text-white font-weight-500 text-shadow-green shadow" href="/prelude/playground">Open Playground</a>
|
68
|
+
</div>
|
69
|
+
</section>
|
70
|
+
|
71
|
+
<footer class="flex px-2 py-2 gap-8" style="background-color: var(--neutral-100);">
|
72
|
+
<div class="flex column justify-center gap-3">
|
73
|
+
<a href="https://npm.com/@wrnrlr/prelude">NPM</a>
|
74
|
+
<a href="https://jsr.io/@wrnrlr/prelude">JSR</a>
|
75
|
+
</div>
|
76
|
+
<div class="flex column justify-center gap-3">
|
77
|
+
<a href="https://x.com/wrnrlr">Twitter</a>
|
78
|
+
<a href="https://discord.gg/N3gPZnhdKV">Discord</a>
|
79
|
+
</div>
|
80
|
+
<div class="flex column-reverse center grow">Some rights reserved © 2024</div>
|
81
|
+
<svg viewBox="0 0 709 709" style="width: 100px; --color:var(--neutral-700)"><use xlink:href="./logo.svg#loop"></use></svg>
|
82
|
+
</footer>
|
83
|
+
</main>
|
84
|
+
|
85
|
+
<style>
|
86
|
+
@import url('./assets/css/style.css');
|
87
|
+
|
88
|
+
html {
|
89
|
+
font-size: 20px;
|
90
|
+
/* font-family: "Noto Sans Warang Citi", sans-serif; */
|
91
|
+
font-weight: 400;
|
92
|
+
font-style: normal;
|
93
|
+
margin: 0;
|
94
|
+
display: flex;
|
95
|
+
width: 100%;
|
96
|
+
height: 100%;
|
97
|
+
color: var(--neutral-900);
|
98
|
+
}
|
99
|
+
|
100
|
+
body {
|
101
|
+
display: flex;
|
102
|
+
flex-direction: column;
|
103
|
+
margin: 0;
|
104
|
+
flex-grow: 2;
|
105
|
+
width: 100%;
|
106
|
+
height: 100%;
|
107
|
+
}
|
108
|
+
|
109
|
+
main {
|
110
|
+
display: flex;
|
111
|
+
flex-direction: column;
|
112
|
+
gap: 1rem;
|
113
|
+
}
|
114
|
+
|
115
|
+
/* a:visited { color: inherit; } */
|
116
|
+
|
117
|
+
section {
|
118
|
+
}
|
119
|
+
section:nth-child(1) { background-color: var(--neutral-100); }
|
120
|
+
/* section:nth-child(even) { background-color: var(--neutral-100); } */
|
121
|
+
/* section:nth-child(odd) { background-color: var(--neutral-200); } */
|
122
|
+
|
123
|
+
section > .wrapper { width: 700px }
|
124
|
+
section > .wide.wrapper { width: 900px }
|
125
|
+
|
126
|
+
.button.playground {
|
127
|
+
color: var(--neutral-50);
|
128
|
+
background-color: var(--green-600);
|
129
|
+
text-shadow: 0px 0px 3px var(--emrald-800);
|
130
|
+
cursor: pointer;
|
131
|
+
}
|
132
|
+
|
133
|
+
#playground {
|
134
|
+
display: flex;
|
135
|
+
width: 100%;
|
136
|
+
height: 100%;
|
137
|
+
background-color: var(--neutral-50);
|
138
|
+
}
|
139
|
+
|
140
|
+
#playground.playing {
|
141
|
+
display: flex;
|
142
|
+
}
|
143
|
+
|
144
|
+
.prelude {
|
145
|
+
color: var(--neutral-700);
|
146
|
+
font-weight: norma;
|
147
|
+
}
|
148
|
+
|
149
|
+
.button {
|
150
|
+
/* padding: 0.75rem 1rem; */
|
151
|
+
/* border-radius: 0.5rem; */
|
152
|
+
/* background-color: var(--neutral-200); */
|
153
|
+
/* font-weight: 600; */
|
154
|
+
}
|
155
|
+
|
156
|
+
#counter > button {
|
157
|
+
color: var(--neutral-50);
|
158
|
+
font-weight: 800;
|
159
|
+
padding: 1rem 1.5rem;
|
160
|
+
border: 1px solid var(--blue-600);
|
161
|
+
border-radius: 0.5rem;
|
162
|
+
background-color: var(--blue-600);
|
163
|
+
height: fit-content;
|
164
|
+
min-width: 4.2rem;
|
165
|
+
text-align: center;
|
166
|
+
text-shadow: 0px 0px 3px var(--blue-800);
|
167
|
+
}
|
168
|
+
|
169
|
+
#counter > button:hover {
|
170
|
+
background-color: var(--blue-500);
|
171
|
+
}
|
172
|
+
|
173
|
+
.card {
|
174
|
+
width: 20rem;
|
175
|
+
display: flex;
|
176
|
+
flex-direction: column;
|
177
|
+
}
|
178
|
+
|
179
|
+
.card > .title {
|
180
|
+
font-weight: bold;
|
181
|
+
color: var(--gray-700);
|
182
|
+
padding: 0.5em;
|
183
|
+
background-color: var(--gray-300);
|
184
|
+
border-radius: 0.5em 0.5em 0 0;
|
185
|
+
}
|
186
|
+
|
187
|
+
.card > .content {
|
188
|
+
height: 220px;
|
189
|
+
background-color: var(--gray-200);
|
190
|
+
}
|
191
|
+
|
192
|
+
a.card {
|
193
|
+
text-decoration: none;
|
194
|
+
}
|
195
|
+
|
196
|
+
.w-half { width: 50% }
|
197
|
+
.CodeMirror { height: 100%; }
|
198
|
+
</style>
|
199
|
+
|
200
|
+
<script type="module">
|
201
|
+
import {h, signal, render} from '../src/mod.ts'
|
202
|
+
|
203
|
+
function Counter() {
|
204
|
+
const n = signal(1)
|
205
|
+
const onClick = e => n(i => i+1)
|
206
|
+
return h('button', {onClick}, n)
|
207
|
+
}
|
208
|
+
|
209
|
+
render(Counter, window.counter)
|
210
|
+
|
211
|
+
</script>
|
@@ -0,0 +1,183 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<head>
|
3
|
+
<title>Prelude</title>
|
4
|
+
<link href="https://unpkg.com/prismjs@1.29.0/themes/prism.css" rel="stylesheet" />
|
5
|
+
<script src="https://unpkg.com/prismjs@1.29.0/components/prism-core.min.js"></script>
|
6
|
+
<script src="https://unpkg.com/prismjs@1.29.0/plugins/autoloader/prism-autoloader.min.js"></script>
|
7
|
+
<script async src="https://www.googletagmanager.com/gtag/js?id=G-EPMJYD1EK8"></script>
|
8
|
+
<script>window.dataLayer = window.dataLayer || [];function gtag(){dataLayer.push(arguments);}gtag('js', new Date());gtag('config', 'G-EPMJYD1EK8');</script>
|
9
|
+
</head>
|
10
|
+
|
11
|
+
<script type="module">
|
12
|
+
|
13
|
+
import {h, signal, effect, untrack, resource, render, onMount, Show, List, Router} from '../src/mod.ts'
|
14
|
+
import {EditorView, basicSetup} from "codemirror"
|
15
|
+
import {html} from "@codemirror/lang-html"
|
16
|
+
|
17
|
+
const playing = signal(true)
|
18
|
+
const examples = [
|
19
|
+
{name:'counter',title:'Counter'},
|
20
|
+
{name:'todo',title:'Todo'},
|
21
|
+
// {name:'admin',title:'Admin'}
|
22
|
+
]
|
23
|
+
|
24
|
+
function Editor(props) {
|
25
|
+
const theme = EditorView.baseTheme({
|
26
|
+
'&.cm-editor': {height: '100%', backgroundColor:'var(--stone-100)'},
|
27
|
+
'&.cm-editor.cm-focused': {outline: 'none'},
|
28
|
+
'&.cm-focused > .cm-scroller > .cm-selectionLayer .cm-selectionBackground': { backgroundColor: 'var(--pink-200)'},
|
29
|
+
'&.cm-scroller': {overflow: 'auto'},
|
30
|
+
'&.cm-gutter': {backgroundColor:'var(--stone-200)'},
|
31
|
+
'&.cm-content': {height: "100%", backgroundColor:'var(--stone-100)'},
|
32
|
+
})
|
33
|
+
const ref = parent => {
|
34
|
+
let updateListener = EditorView.updateListener.of((update) => {
|
35
|
+
if (update.docChanged) {
|
36
|
+
console.log('doc change')
|
37
|
+
props.setValue(update.state.doc.toString())
|
38
|
+
// props.value(update.state.doc.toString())
|
39
|
+
}
|
40
|
+
});
|
41
|
+
let editor = new EditorView({
|
42
|
+
doc:'', parent,
|
43
|
+
extensions: [theme, basicSetup, html(), updateListener]
|
44
|
+
})
|
45
|
+
effect(()=>{
|
46
|
+
// console.log('loading', props.value.loading);
|
47
|
+
if (props.value.loading) return
|
48
|
+
const insert = props.value()
|
49
|
+
// console.log('set content',insert);
|
50
|
+
editor.dispatch({changes: {from: 0, to: editor.state.doc.length, insert}})
|
51
|
+
})
|
52
|
+
}
|
53
|
+
return h('.p-1.w-half.h-full.bg-stone-200',{ref,style:'position:relative'})
|
54
|
+
}
|
55
|
+
|
56
|
+
function Preview(props) {
|
57
|
+
return h('iframe.w-half.bg-stone-200', {srcdoc:props.value})
|
58
|
+
}
|
59
|
+
|
60
|
+
function TopMenu(props) {
|
61
|
+
return h('.flex.items-center.p-1.gap-2.bg-neutral-100',[
|
62
|
+
h('.button.rounded.text-xl.bg-neutral-100.p-1', {onClick:e=>(props.show(b=>!b))},
|
63
|
+
h('i.icon.menu')),
|
64
|
+
h('input.grow', {value:props.file, readonly:true}),
|
65
|
+
// h('.flex.px-2.py-1.rounded.text-md.bg-gray-300.font-weight-500.text-neutral-700.gap-2.shadow',
|
66
|
+
// [h('i.icon.plus.text-md'),'New']),
|
67
|
+
// h('.flex.px-2.py-1.rounded.text-md.bg-gray-300.font-weight-500.text-neutral-700.gap-2.shadow',
|
68
|
+
// [h('i.icon.clone.text-md'),'Clone']),
|
69
|
+
h('a.px-3.py-1.rounded-full.text-md.bg-blue-500.text-white.shadow', {href:'/prelude'},
|
70
|
+
h('i.icon.info.text-shadow-black'))])
|
71
|
+
}
|
72
|
+
|
73
|
+
function SideMenu(props) {
|
74
|
+
return h('.sidemenu.flex.column.px-2.py-2.gap-4.bg-stone-300',[
|
75
|
+
h('.flex.justify-around', [
|
76
|
+
h(PreludeLogo)
|
77
|
+
]),
|
78
|
+
h('.flex.column.gap-2', [
|
79
|
+
h(SrcMenu,{name:'example',title:'Example',file:()=>props.file,items:()=>()=>examples,src:()=>props.src}),
|
80
|
+
// h(SrcMenu,{name:'local',title:'Local Storage',file:()=>props.file,items:()=>props.local,src:()=>props.src})
|
81
|
+
])
|
82
|
+
])
|
83
|
+
}
|
84
|
+
|
85
|
+
function SrcMenu(props) {
|
86
|
+
effect(()=>console.log(props.src()===props.name))
|
87
|
+
return h('.flex.column.gap-1',[
|
88
|
+
h('button.flex.font-weight-600', {onClick:e=>props.src(props.name)}, props.title),
|
89
|
+
h(Show, {when:()=>props.src()===props.name},
|
90
|
+
h('.flex.column.gap-1.pl-2',
|
91
|
+
h(List, {each:()=>props.items}, (value,i) =>
|
92
|
+
h('button.flex', {onClick:e=>props.file(value().name)}, h('',()=>value().title))
|
93
|
+
)
|
94
|
+
)
|
95
|
+
)])
|
96
|
+
}
|
97
|
+
|
98
|
+
function Playground() {
|
99
|
+
const show = signal(true)
|
100
|
+
const src = signal('example')
|
101
|
+
const file = signal('counter')
|
102
|
+
const local = signal(examples)
|
103
|
+
const content = signal('')
|
104
|
+
const exs = ()=>examples
|
105
|
+
const doodle = resource(()=>({src:src(),file:file()}), async r => {
|
106
|
+
console.log('change resource',r)
|
107
|
+
if (r.src==='example') {
|
108
|
+
console.log('fetch',r.file)
|
109
|
+
const resp = await fetch('/prelude/example/' + r.file + '.html')
|
110
|
+
const text = await resp.text()
|
111
|
+
// console.log(text)
|
112
|
+
return text
|
113
|
+
// content(html)
|
114
|
+
} else {
|
115
|
+
console.log('local')
|
116
|
+
}
|
117
|
+
})
|
118
|
+
const setContent = s => {
|
119
|
+
console.log('set content')
|
120
|
+
content(s)
|
121
|
+
}
|
122
|
+
return h('.flex.w-full.h-full',{style:'background-color:var(--neutral-100)'},[
|
123
|
+
h(Show, {when:show}, h(SideMenu, {show:()=>show, src:()=>src, file:()=>file, local:()=>local})),
|
124
|
+
h('.flex.column.grow.items-stretch', [
|
125
|
+
h(TopMenu, {playing:()=>playing, show:()=>show, file:()=>file}),
|
126
|
+
h(Show, {when:()=>!doodle.loading, fallback: 'Loading...'},
|
127
|
+
h('.flex', {style:'overflow:auto;height:100%'}, [
|
128
|
+
h(Editor, {value:()=>doodle, setValue:setContent, src:()=>src, file:()=>file}),
|
129
|
+
h(Preview, {value:()=>content})
|
130
|
+
]))
|
131
|
+
])
|
132
|
+
])
|
133
|
+
}
|
134
|
+
|
135
|
+
render(Playground, document.body)
|
136
|
+
|
137
|
+
function PreludeLogo() {
|
138
|
+
return h('svg', {viewBox:'0 0 709 709',style:'width: 50px; --color:var(--neutral-700)'},
|
139
|
+
h('use', {'xlink:href':'./logo.svg#loop'}))
|
140
|
+
}
|
141
|
+
|
142
|
+
</script>
|
143
|
+
|
144
|
+
<style>
|
145
|
+
@import url('./assets/css/style.css');
|
146
|
+
|
147
|
+
html {
|
148
|
+
font-size: 20px;
|
149
|
+
/* font-family: "Noto Sans Warang Citi", sans-serif; */
|
150
|
+
font-weight: 400;
|
151
|
+
font-style: normal;
|
152
|
+
margin: 0;
|
153
|
+
display: flex;
|
154
|
+
width: 100%;
|
155
|
+
height: 100%;
|
156
|
+
color: var(--neutral-900);
|
157
|
+
}
|
158
|
+
|
159
|
+
body {
|
160
|
+
display: flex;
|
161
|
+
flex-direction: column;
|
162
|
+
margin: 0;
|
163
|
+
flex-grow: 2;
|
164
|
+
width: 100%;
|
165
|
+
height: 100%;
|
166
|
+
}
|
167
|
+
|
168
|
+
.prelude {
|
169
|
+
color: var(--neutral-700);
|
170
|
+
font-weight: normal;
|
171
|
+
}
|
172
|
+
|
173
|
+
.sidemenu {
|
174
|
+
min-width: max-content;
|
175
|
+
}
|
176
|
+
|
177
|
+
.button {
|
178
|
+
}
|
179
|
+
.button:hover {
|
180
|
+
background-color:var(--neutral-300)
|
181
|
+
}
|
182
|
+
|
183
|
+
</style>
|
@@ -0,0 +1,88 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<title>Admin</title>
|
3
|
+
|
4
|
+
<script type="module">
|
5
|
+
|
6
|
+
import {h,signal,effect,render,resource,memo,Router,List,Show} from '/prelude/bundle.js'
|
7
|
+
|
8
|
+
function makeApi(base,method='GET') {
|
9
|
+
return async (s='') => await (await fetch('https://dummyjson.com/'+base+s,{method})).json()
|
10
|
+
}
|
11
|
+
|
12
|
+
const getPosts = makeApi('posts')
|
13
|
+
|
14
|
+
function ResourceList(props) {
|
15
|
+
const when = () => !props.result.loading,
|
16
|
+
list = () => props.result()?.[props.key];
|
17
|
+
return h(Show,{when,fallback:()=>'loading...'},
|
18
|
+
h('ul', h(List, {each:()=>list}, props.children)))
|
19
|
+
}
|
20
|
+
|
21
|
+
function PostItem(props) {
|
22
|
+
const item = () => props.children(),
|
23
|
+
href = () => '#post/' + item().id
|
24
|
+
return h('li',h('a',{href},()=>item().title))
|
25
|
+
}
|
26
|
+
|
27
|
+
function Posts(props) {
|
28
|
+
const result = resource(async ()=>getPosts())
|
29
|
+
return [
|
30
|
+
h('h1','Posts'),
|
31
|
+
h(ResourceList, {key:'posts',result:()=>result}, (v,i) => h(PostItem,v))
|
32
|
+
]
|
33
|
+
}
|
34
|
+
|
35
|
+
function UserItem(props) {
|
36
|
+
const item = () => props.children()
|
37
|
+
return h('li',()=>item().name)
|
38
|
+
}
|
39
|
+
|
40
|
+
function Users(props) {
|
41
|
+
const result = resource(async ()=>getPosts())
|
42
|
+
return [
|
43
|
+
h('h1','Users'),
|
44
|
+
h(ResourceList, {key:'users',result:()=>result}, (v,i) => h(UserItem,v))
|
45
|
+
]
|
46
|
+
}
|
47
|
+
|
48
|
+
function Post(props) {
|
49
|
+
return h('h1','Post #123')
|
50
|
+
}
|
51
|
+
|
52
|
+
function App(props) {
|
53
|
+
return [
|
54
|
+
h('nav',[
|
55
|
+
h('a',{href:'/example/admin.html#'},'Posts'),
|
56
|
+
h('a',{href:'/example/admin.html#user'},'Users')
|
57
|
+
]),
|
58
|
+
h(Router,[
|
59
|
+
{path:'/', component:Posts},
|
60
|
+
{path:'/user', component:Users},
|
61
|
+
{path:'/post/:id', component:Post}
|
62
|
+
])
|
63
|
+
]
|
64
|
+
}
|
65
|
+
|
66
|
+
render(App, document.body)
|
67
|
+
|
68
|
+
</script>
|
69
|
+
|
70
|
+
<style>
|
71
|
+
nav {
|
72
|
+
display: flex;
|
73
|
+
gap: 1rem;
|
74
|
+
}
|
75
|
+
|
76
|
+
ul {
|
77
|
+
display: flex;
|
78
|
+
flex-direction: column;
|
79
|
+
padding:0;
|
80
|
+
gap: 0.5rem;
|
81
|
+
}
|
82
|
+
|
83
|
+
li {
|
84
|
+
list-style: none;
|
85
|
+
}
|
86
|
+
|
87
|
+
|
88
|
+
</style>
|
@@ -0,0 +1,16 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
+
<svg
|
3
|
+
id="loop"
|
4
|
+
width="709"
|
5
|
+
height="709"
|
6
|
+
viewBox="0 0 709 709"
|
7
|
+
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
8
|
+
<path
|
9
|
+
id="Rectangle"
|
10
|
+
style="stroke:var(--color,#444444); stroke-width:var(--width,40)"
|
11
|
+
fill="none"
|
12
|
+
stroke-linecap="round"
|
13
|
+
stroke-linejoin="round"
|
14
|
+
d="M 76 617 L 631 617 L 631 94 C 631 94 26 450 358 450 C 682 450 76 94 76 94 L 76 617 Z"
|
15
|
+
/>
|
16
|
+
</svg>
|
package/www/typedoc.json
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
{
|
2
|
+
"name": "prelude",
|
3
|
+
"out":"./docs/",
|
4
|
+
"compilerOptions": {
|
5
|
+
"strict": false,
|
6
|
+
"allowJs": true,
|
7
|
+
"checkJs": false,
|
8
|
+
"noImplicitThis": false,
|
9
|
+
"allowImportingTsExtensions": true,
|
10
|
+
"downlevelIteration": true
|
11
|
+
},
|
12
|
+
"entryPoints": ["../src/mod.ts"]
|
13
|
+
}
|
@@ -0,0 +1,106 @@
|
|
1
|
+
import * as path from '@std/path'
|
2
|
+
import * as fs from '@std/fs'
|
3
|
+
import {defineConfig} from 'vite'
|
4
|
+
import * as esbuild from 'esbuild'
|
5
|
+
import { Application, TSConfigReader, TypeDocReader } from 'typedoc'
|
6
|
+
|
7
|
+
export default defineConfig(({ command, mode }) => {
|
8
|
+
const root = path.join(__dirname, '')
|
9
|
+
|
10
|
+
const define = {}
|
11
|
+
let build
|
12
|
+
const optimizeDeps = {
|
13
|
+
// exclude: ['dist/','public/'],
|
14
|
+
}
|
15
|
+
const assetsInclude = [
|
16
|
+
// 'public/example/**'
|
17
|
+
]
|
18
|
+
|
19
|
+
const input = {
|
20
|
+
'index': path.join(root, 'index.html'),
|
21
|
+
'playground': path.join(root, 'playground.html'),
|
22
|
+
}
|
23
|
+
// const docs = path.join(root, 'distdocs/index.html')
|
24
|
+
// if (fs.existsSync(docs)) input.docs = docs
|
25
|
+
// console.log('docs',input.docs)
|
26
|
+
|
27
|
+
build = {
|
28
|
+
lib: {
|
29
|
+
entry: path.join(root, '../src/mod.ts'),
|
30
|
+
formats: ['es'],
|
31
|
+
name: 'mod',
|
32
|
+
fileName: (name) => 'prelude.js'
|
33
|
+
},
|
34
|
+
rollupOptions: {
|
35
|
+
input,
|
36
|
+
exports: 'named',
|
37
|
+
output: {
|
38
|
+
manualChunks(id) {
|
39
|
+
// if (id.endsWith('src/mod.ts')) return 'prelude'
|
40
|
+
}
|
41
|
+
}
|
42
|
+
}
|
43
|
+
}
|
44
|
+
|
45
|
+
return {
|
46
|
+
root,
|
47
|
+
define,
|
48
|
+
build,
|
49
|
+
optimizeDeps,
|
50
|
+
assetsInclude,
|
51
|
+
base: '/prelude',
|
52
|
+
plugins: [
|
53
|
+
esbuildPlugin(), typedocPlugin()
|
54
|
+
]
|
55
|
+
}
|
56
|
+
})
|
57
|
+
|
58
|
+
function esbuildPlugin() {
|
59
|
+
let ctx
|
60
|
+
return {
|
61
|
+
name: 'typedoc-plugin',
|
62
|
+
async buildStart() {
|
63
|
+
const entry = path.join(__dirname, '../src/mod.ts')
|
64
|
+
const options = {
|
65
|
+
entryPoints: [entry],
|
66
|
+
outfile: path.join(__dirname, './public/bundle.js'),
|
67
|
+
bundle: true,
|
68
|
+
format:'esm',
|
69
|
+
// minify: true,
|
70
|
+
// sourcemap: true,
|
71
|
+
target: ["es2020"],
|
72
|
+
}
|
73
|
+
ctx = await esbuild.context(options)
|
74
|
+
await ctx.watch()
|
75
|
+
},
|
76
|
+
async buildEnd() {
|
77
|
+
await ctx.dispose()
|
78
|
+
}
|
79
|
+
}
|
80
|
+
}
|
81
|
+
|
82
|
+
function typedocPlugin() {
|
83
|
+
let _config
|
84
|
+
return {
|
85
|
+
name: 'typedoc-plugin',
|
86
|
+
apply: 'build',
|
87
|
+
configResolved(config) { _config = config },
|
88
|
+
async writeBundle() {
|
89
|
+
const name = path.join(__dirname, 'typedoc.json')
|
90
|
+
const config = JSON.parse(await Deno.readTextFile(name))
|
91
|
+
config.hostedBaseUrl = 'https://wrnrlr.github.io/prelude/docs'
|
92
|
+
config.useHostedBaseUrlForAbsoluteLinks = true
|
93
|
+
config.out = path.join(__dirname, './dist/docs')
|
94
|
+
config.entryPoints = [path.join(__dirname, '../src/mod.ts')]
|
95
|
+
const app = await Application.bootstrap(config)
|
96
|
+
if (!app) Deno.exit()
|
97
|
+
const project = await app.convert()
|
98
|
+
if (!project) Deno.exit()
|
99
|
+
try {
|
100
|
+
await app.generateDocs(project, config.out)
|
101
|
+
} catch (e) {
|
102
|
+
console.error(e)
|
103
|
+
}
|
104
|
+
}
|
105
|
+
}
|
106
|
+
}
|
package/example/paint.html
DELETED
@@ -1,22 +0,0 @@
|
|
1
|
-
<!DOCTYPE html>
|
2
|
-
<title>Counter</title>
|
3
|
-
|
4
|
-
<script type="module">
|
5
|
-
|
6
|
-
import {h,signal,render,Canvas,Stroke,Line} from '../src/mod.ts'
|
7
|
-
|
8
|
-
function App() {
|
9
|
-
const count = signal(1)
|
10
|
-
return h(Canvas, h(Line, [0, 0, 200, 200]))
|
11
|
-
}
|
12
|
-
|
13
|
-
render(App, document.body)
|
14
|
-
|
15
|
-
</script>
|
16
|
-
|
17
|
-
<style>
|
18
|
-
body {
|
19
|
-
width:100%; height:100%;
|
20
|
-
background-color: grey;
|
21
|
-
}
|
22
|
-
</style>
|