@korajs/cli 0.4.0 → 0.5.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/dist/bin.cjs +1609 -643
- package/dist/bin.cjs.map +1 -1
- package/dist/bin.js +1086 -139
- package/dist/bin.js.map +1 -1
- package/dist/{chunk-CMSX76KM.js → chunk-3WNFM3QB.js} +103 -96
- package/dist/chunk-3WNFM3QB.js.map +1 -0
- package/dist/{chunk-MVP5PDT4.js → chunk-PSRM56B7.js} +2 -2
- package/dist/{chunk-YGVO4POI.js → chunk-SOTZIWIF.js} +27 -15
- package/dist/chunk-SOTZIWIF.js.map +1 -0
- package/dist/create.cjs +54 -47
- package/dist/create.cjs.map +1 -1
- package/dist/create.js +2 -2
- package/dist/index.cjs +78 -59
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +5 -3
- package/dist/index.d.ts +5 -3
- package/dist/index.js +2 -2
- package/package.json +9 -3
- package/templates/react-basic/README.md.hbs +10 -1
- package/templates/react-basic/src/App.tsx +112 -126
- package/templates/react-basic/src/index.css +165 -159
- package/templates/react-basic/src/kora-worker.ts +0 -1
- package/templates/react-basic/src/main.tsx +12 -12
- package/templates/react-basic/src/modules/todos/todo.mutations.ts +25 -0
- package/templates/react-basic/src/modules/todos/todo.queries.ts +5 -0
- package/templates/react-basic/src/modules/todos/todo.schema.ts +10 -0
- package/templates/react-basic/src/modules/todos/useTodos.ts +31 -0
- package/templates/react-basic/src/schema.ts +6 -12
- package/templates/react-basic/src/vite-env.d.ts +17 -0
- package/templates/react-basic/{tsconfig.json → tsconfig.json.hbs} +1 -2
- package/templates/react-basic/vite.config.ts +57 -50
- package/templates/react-sync/.env.example +19 -0
- package/templates/react-sync/README.md.hbs +43 -1
- package/templates/react-sync/package.json.hbs +3 -0
- package/templates/react-sync/server.ts +90 -26
- package/templates/react-sync/src/App.tsx +132 -130
- package/templates/react-sync/src/auth.ts +25 -0
- package/templates/react-sync/src/index.css +212 -165
- package/templates/react-sync/src/kora-worker.ts +0 -1
- package/templates/react-sync/src/main.tsx +34 -18
- package/templates/react-sync/src/modules/todos/todo.mutations.ts +25 -0
- package/templates/react-sync/src/modules/todos/todo.queries.ts +5 -0
- package/templates/react-sync/src/modules/todos/todo.schema.ts +10 -0
- package/templates/react-sync/src/modules/todos/useTodos.ts +31 -0
- package/templates/react-sync/src/schema.ts +6 -12
- package/templates/react-sync/src/vite-env.d.ts +17 -0
- package/templates/react-sync/{tsconfig.json → tsconfig.json.hbs} +1 -2
- package/templates/react-sync/vite.config.ts +67 -60
- package/templates/react-tailwind/README.md.hbs +10 -1
- package/templates/react-tailwind/src/App.tsx +186 -197
- package/templates/react-tailwind/src/index.css +3 -3
- package/templates/react-tailwind/src/kora-worker.ts +0 -1
- package/templates/react-tailwind/src/main.tsx +19 -12
- package/templates/react-tailwind/src/modules/todos/todo.mutations.ts +25 -0
- package/templates/react-tailwind/src/modules/todos/todo.queries.ts +5 -0
- package/templates/react-tailwind/src/modules/todos/todo.schema.ts +10 -0
- package/templates/react-tailwind/src/modules/todos/useTodos.ts +31 -0
- package/templates/react-tailwind/src/schema.ts +6 -12
- package/templates/react-tailwind/src/vite-env.d.ts +17 -0
- package/templates/react-tailwind/{tsconfig.json → tsconfig.json.hbs} +1 -2
- package/templates/react-tailwind/vite.config.ts +57 -50
- package/templates/react-tailwind-sync/.env.example +19 -0
- package/templates/react-tailwind-sync/README.md.hbs +43 -1
- package/templates/react-tailwind-sync/package.json.hbs +3 -0
- package/templates/react-tailwind-sync/server.ts +90 -26
- package/templates/react-tailwind-sync/src/App.tsx +246 -222
- package/templates/react-tailwind-sync/src/auth.ts +25 -0
- package/templates/react-tailwind-sync/src/index.css +3 -3
- package/templates/react-tailwind-sync/src/kora-worker.ts +0 -1
- package/templates/react-tailwind-sync/src/main.tsx +48 -18
- package/templates/react-tailwind-sync/src/modules/todos/todo.mutations.ts +25 -0
- package/templates/react-tailwind-sync/src/modules/todos/todo.queries.ts +5 -0
- package/templates/react-tailwind-sync/src/modules/todos/todo.schema.ts +10 -0
- package/templates/react-tailwind-sync/src/modules/todos/useTodos.ts +31 -0
- package/templates/react-tailwind-sync/src/schema.ts +6 -12
- package/templates/react-tailwind-sync/src/vite-env.d.ts +17 -0
- package/templates/react-tailwind-sync/{tsconfig.json → tsconfig.json.hbs} +1 -2
- package/templates/react-tailwind-sync/vite.config.ts +67 -60
- package/templates/tauri-react/.env.example +20 -0
- package/templates/tauri-react/README.md.hbs +36 -1
- package/templates/tauri-react/dev.ts +11 -11
- package/templates/tauri-react/package.json.hbs +2 -0
- package/templates/tauri-react/server.ts +86 -12
- package/templates/tauri-react/src/App.tsx +769 -544
- package/templates/tauri-react/src/AppShell.tsx +125 -83
- package/templates/tauri-react/src/SetupScreen.tsx +257 -208
- package/templates/tauri-react/src/auth.ts +45 -0
- package/templates/tauri-react/src/main.tsx +3 -3
- package/templates/tauri-react/src/modules/todos/todo.mutations.ts +25 -0
- package/templates/tauri-react/src/modules/todos/todo.queries.ts +5 -0
- package/templates/tauri-react/src/modules/todos/todo.schema.ts +10 -0
- package/templates/tauri-react/src/modules/todos/useTodos.ts +31 -0
- package/templates/tauri-react/src/schema.ts +6 -12
- package/templates/tauri-react/src/sync-config.ts +47 -47
- package/templates/tauri-react/src/updater.ts +15 -15
- package/templates/tauri-react/src/vite-env.d.ts +17 -0
- package/templates/tauri-react/src-tauri/tauri.conf.json +1 -1
- package/templates/tauri-react/tsconfig.json.hbs +14 -0
- package/templates/tauri-react/vite.config.ts +9 -9
- package/dist/chunk-CMSX76KM.js.map +0 -1
- package/dist/chunk-YGVO4POI.js.map +0 -1
- package/templates/tauri-react/tsconfig.json +0 -15
- /package/dist/{chunk-MVP5PDT4.js.map → chunk-PSRM56B7.js.map} +0 -0
|
@@ -1,292 +1,339 @@
|
|
|
1
1
|
*,
|
|
2
2
|
*::before,
|
|
3
3
|
*::after {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
4
|
+
box-sizing: border-box;
|
|
5
|
+
margin: 0;
|
|
6
|
+
padding: 0;
|
|
7
7
|
}
|
|
8
8
|
|
|
9
9
|
:root {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
10
|
+
--color-bg: #0a0a0f;
|
|
11
|
+
--color-surface: #111118;
|
|
12
|
+
--color-border: #1e1e2a;
|
|
13
|
+
--color-border-hover: #2a2a3a;
|
|
14
|
+
--color-text: #e4e4e7;
|
|
15
|
+
--color-text-muted: #71717a;
|
|
16
|
+
--color-text-dim: #3f3f46;
|
|
17
|
+
--color-primary: #6366f1;
|
|
18
|
+
--color-primary-hover: #818cf8;
|
|
19
|
+
--color-success: #34d399;
|
|
20
|
+
--color-warning: #fbbf24;
|
|
21
|
+
--color-danger: #f87171;
|
|
22
|
+
--font-sans: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
|
|
23
|
+
--radius: 8px;
|
|
24
24
|
}
|
|
25
25
|
|
|
26
26
|
body {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
27
|
+
font-family: var(--font-sans);
|
|
28
|
+
background: var(--color-bg);
|
|
29
|
+
color: var(--color-text);
|
|
30
|
+
line-height: 1.6;
|
|
31
|
+
-webkit-font-smoothing: antialiased;
|
|
32
32
|
}
|
|
33
33
|
|
|
34
34
|
.app {
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
35
|
+
max-width: 640px;
|
|
36
|
+
margin: 0 auto;
|
|
37
|
+
padding: 48px 16px;
|
|
38
38
|
}
|
|
39
39
|
|
|
40
40
|
.header {
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
41
|
+
display: flex;
|
|
42
|
+
align-items: center;
|
|
43
|
+
justify-content: space-between;
|
|
44
|
+
margin-bottom: 32px;
|
|
45
45
|
}
|
|
46
46
|
|
|
47
47
|
.header h1 {
|
|
48
|
-
|
|
49
|
-
|
|
48
|
+
font-size: 1.5rem;
|
|
49
|
+
font-weight: 700;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
.header-actions {
|
|
53
|
+
display: flex;
|
|
54
|
+
align-items: center;
|
|
55
|
+
gap: 8px;
|
|
50
56
|
}
|
|
51
57
|
|
|
52
58
|
.sync-badge {
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
59
|
+
display: inline-flex;
|
|
60
|
+
align-items: center;
|
|
61
|
+
gap: 6px;
|
|
62
|
+
padding: 4px 12px;
|
|
63
|
+
border-radius: 999px;
|
|
64
|
+
background: var(--color-surface);
|
|
65
|
+
font-size: 0.8rem;
|
|
60
66
|
}
|
|
61
67
|
|
|
62
68
|
.sync-dot {
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
69
|
+
width: 8px;
|
|
70
|
+
height: 8px;
|
|
71
|
+
border-radius: 50%;
|
|
66
72
|
}
|
|
67
73
|
|
|
68
74
|
.sync-dot.connected,
|
|
69
|
-
.sync-dot.synced {
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
.sync-dot.
|
|
75
|
+
.sync-dot.synced {
|
|
76
|
+
background: var(--color-success);
|
|
77
|
+
}
|
|
78
|
+
.sync-dot.syncing {
|
|
79
|
+
background: var(--color-warning);
|
|
80
|
+
}
|
|
81
|
+
.sync-dot.offline {
|
|
82
|
+
background: var(--color-text-muted);
|
|
83
|
+
}
|
|
84
|
+
.sync-dot.error {
|
|
85
|
+
background: var(--color-danger);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
.auth-button {
|
|
89
|
+
border: 1px solid var(--color-border);
|
|
90
|
+
border-radius: 999px;
|
|
91
|
+
background: var(--color-surface);
|
|
92
|
+
color: var(--color-text);
|
|
93
|
+
cursor: pointer;
|
|
94
|
+
font-size: 0.8rem;
|
|
95
|
+
max-width: 180px;
|
|
96
|
+
overflow: hidden;
|
|
97
|
+
padding: 4px 12px;
|
|
98
|
+
text-overflow: ellipsis;
|
|
99
|
+
white-space: nowrap;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
.auth-button:hover {
|
|
103
|
+
border-color: var(--color-border-hover);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
.auth-error {
|
|
107
|
+
border: 1px solid rgba(248, 113, 113, 0.35);
|
|
108
|
+
border-radius: var(--radius);
|
|
109
|
+
color: var(--color-danger);
|
|
110
|
+
font-size: 0.85rem;
|
|
111
|
+
margin-bottom: 16px;
|
|
112
|
+
padding: 10px 12px;
|
|
113
|
+
}
|
|
73
114
|
|
|
74
115
|
.stats {
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
116
|
+
display: grid;
|
|
117
|
+
grid-template-columns: repeat(3, 1fr);
|
|
118
|
+
gap: 12px;
|
|
119
|
+
margin-bottom: 32px;
|
|
79
120
|
}
|
|
80
121
|
|
|
81
122
|
.stat-card {
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
123
|
+
background: var(--color-surface);
|
|
124
|
+
border: 1px solid var(--color-border);
|
|
125
|
+
border-radius: var(--radius);
|
|
126
|
+
padding: 16px;
|
|
86
127
|
}
|
|
87
128
|
|
|
88
129
|
.stat-card .label {
|
|
89
|
-
|
|
90
|
-
|
|
130
|
+
font-size: 0.8rem;
|
|
131
|
+
color: var(--color-text-muted);
|
|
91
132
|
}
|
|
92
133
|
|
|
93
134
|
.stat-card .value {
|
|
94
|
-
|
|
95
|
-
|
|
135
|
+
font-size: 1.5rem;
|
|
136
|
+
font-weight: 700;
|
|
96
137
|
}
|
|
97
138
|
|
|
98
|
-
.stat-card .value.muted {
|
|
99
|
-
|
|
100
|
-
|
|
139
|
+
.stat-card .value.muted {
|
|
140
|
+
color: var(--color-text-muted);
|
|
141
|
+
}
|
|
142
|
+
.stat-card .value.warning {
|
|
143
|
+
color: var(--color-warning);
|
|
144
|
+
}
|
|
145
|
+
.stat-card .value.success {
|
|
146
|
+
color: var(--color-success);
|
|
147
|
+
}
|
|
101
148
|
|
|
102
149
|
.add-form {
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
150
|
+
display: flex;
|
|
151
|
+
gap: 12px;
|
|
152
|
+
margin-bottom: 32px;
|
|
106
153
|
}
|
|
107
154
|
|
|
108
155
|
.add-form input {
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
156
|
+
flex: 1;
|
|
157
|
+
padding: 10px 16px;
|
|
158
|
+
border: 1px solid var(--color-border);
|
|
159
|
+
border-radius: var(--radius);
|
|
160
|
+
background: var(--color-surface);
|
|
161
|
+
color: var(--color-text);
|
|
162
|
+
font-size: 0.95rem;
|
|
163
|
+
outline: none;
|
|
117
164
|
}
|
|
118
165
|
|
|
119
166
|
.add-form input:focus {
|
|
120
|
-
|
|
167
|
+
border-color: var(--color-primary);
|
|
121
168
|
}
|
|
122
169
|
|
|
123
170
|
.add-form input::placeholder {
|
|
124
|
-
|
|
171
|
+
color: var(--color-text-muted);
|
|
125
172
|
}
|
|
126
173
|
|
|
127
174
|
.add-form button {
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
175
|
+
padding: 10px 20px;
|
|
176
|
+
border: none;
|
|
177
|
+
border-radius: var(--radius);
|
|
178
|
+
background: var(--color-primary);
|
|
179
|
+
color: white;
|
|
180
|
+
font-size: 0.95rem;
|
|
181
|
+
font-weight: 500;
|
|
182
|
+
cursor: pointer;
|
|
136
183
|
}
|
|
137
184
|
|
|
138
185
|
.add-form button:hover {
|
|
139
|
-
|
|
186
|
+
background: var(--color-primary-hover);
|
|
140
187
|
}
|
|
141
188
|
|
|
142
189
|
.add-form button:disabled {
|
|
143
|
-
|
|
144
|
-
|
|
190
|
+
opacity: 0.5;
|
|
191
|
+
cursor: not-allowed;
|
|
145
192
|
}
|
|
146
193
|
|
|
147
194
|
.filters {
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
195
|
+
display: flex;
|
|
196
|
+
gap: 8px;
|
|
197
|
+
margin-bottom: 24px;
|
|
151
198
|
}
|
|
152
199
|
|
|
153
200
|
.filter-btn {
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
201
|
+
padding: 6px 16px;
|
|
202
|
+
border: none;
|
|
203
|
+
border-radius: var(--radius);
|
|
204
|
+
background: var(--color-surface);
|
|
205
|
+
color: var(--color-text-muted);
|
|
206
|
+
font-size: 0.85rem;
|
|
207
|
+
font-weight: 500;
|
|
208
|
+
cursor: pointer;
|
|
162
209
|
}
|
|
163
210
|
|
|
164
211
|
.filter-btn:hover {
|
|
165
|
-
|
|
166
|
-
|
|
212
|
+
background: var(--color-border-hover);
|
|
213
|
+
color: var(--color-text);
|
|
167
214
|
}
|
|
168
215
|
|
|
169
216
|
.filter-btn.active {
|
|
170
|
-
|
|
171
|
-
|
|
217
|
+
background: var(--color-primary);
|
|
218
|
+
color: white;
|
|
172
219
|
}
|
|
173
220
|
|
|
174
221
|
.filter-btn .badge {
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
222
|
+
display: inline-block;
|
|
223
|
+
margin-left: 6px;
|
|
224
|
+
padding: 1px 6px;
|
|
225
|
+
border-radius: 999px;
|
|
226
|
+
font-size: 0.75rem;
|
|
227
|
+
background: rgba(255, 255, 255, 0.15);
|
|
181
228
|
}
|
|
182
229
|
|
|
183
230
|
.filter-btn:not(.active) .badge {
|
|
184
|
-
|
|
231
|
+
background: var(--color-border);
|
|
185
232
|
}
|
|
186
233
|
|
|
187
234
|
.todo-list {
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
235
|
+
display: flex;
|
|
236
|
+
flex-direction: column;
|
|
237
|
+
gap: 8px;
|
|
191
238
|
}
|
|
192
239
|
|
|
193
240
|
.todo-item {
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
241
|
+
display: flex;
|
|
242
|
+
align-items: center;
|
|
243
|
+
gap: 12px;
|
|
244
|
+
padding: 12px 16px;
|
|
245
|
+
border: 1px solid var(--color-border);
|
|
246
|
+
border-radius: var(--radius);
|
|
247
|
+
background: var(--color-surface);
|
|
201
248
|
}
|
|
202
249
|
|
|
203
250
|
.todo-item:hover {
|
|
204
|
-
|
|
251
|
+
border-color: var(--color-border-hover);
|
|
205
252
|
}
|
|
206
253
|
|
|
207
254
|
.todo-item .toggle {
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
255
|
+
background: none;
|
|
256
|
+
border: 2px solid var(--color-text-muted);
|
|
257
|
+
width: 20px;
|
|
258
|
+
height: 20px;
|
|
259
|
+
border-radius: 50%;
|
|
260
|
+
cursor: pointer;
|
|
261
|
+
display: flex;
|
|
262
|
+
align-items: center;
|
|
263
|
+
justify-content: center;
|
|
264
|
+
color: transparent;
|
|
265
|
+
font-size: 0.7rem;
|
|
266
|
+
flex-shrink: 0;
|
|
220
267
|
}
|
|
221
268
|
|
|
222
269
|
.todo-item .toggle.checked {
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
270
|
+
border-color: var(--color-success);
|
|
271
|
+
background: var(--color-success);
|
|
272
|
+
color: white;
|
|
226
273
|
}
|
|
227
274
|
|
|
228
275
|
.todo-item .title {
|
|
229
|
-
|
|
276
|
+
flex: 1;
|
|
230
277
|
}
|
|
231
278
|
|
|
232
279
|
.todo-item .title.done {
|
|
233
|
-
|
|
234
|
-
|
|
280
|
+
text-decoration: line-through;
|
|
281
|
+
color: var(--color-text-muted);
|
|
235
282
|
}
|
|
236
283
|
|
|
237
284
|
.todo-item .time {
|
|
238
|
-
|
|
239
|
-
|
|
285
|
+
font-size: 0.75rem;
|
|
286
|
+
color: var(--color-text-dim);
|
|
240
287
|
}
|
|
241
288
|
|
|
242
289
|
.todo-item .delete-btn {
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
290
|
+
background: none;
|
|
291
|
+
border: none;
|
|
292
|
+
color: var(--color-text-dim);
|
|
293
|
+
cursor: pointer;
|
|
294
|
+
padding: 4px;
|
|
295
|
+
opacity: 0;
|
|
296
|
+
transition: opacity 0.15s;
|
|
250
297
|
}
|
|
251
298
|
|
|
252
299
|
.todo-item:hover .delete-btn {
|
|
253
|
-
|
|
300
|
+
opacity: 1;
|
|
254
301
|
}
|
|
255
302
|
|
|
256
303
|
.todo-item .delete-btn:hover {
|
|
257
|
-
|
|
304
|
+
color: var(--color-danger);
|
|
258
305
|
}
|
|
259
306
|
|
|
260
307
|
.empty-state {
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
308
|
+
padding: 48px 0;
|
|
309
|
+
text-align: center;
|
|
310
|
+
color: var(--color-text-dim);
|
|
311
|
+
border: 1px dashed var(--color-border);
|
|
312
|
+
border-radius: var(--radius);
|
|
266
313
|
}
|
|
267
314
|
|
|
268
315
|
.footer {
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
316
|
+
display: flex;
|
|
317
|
+
justify-content: space-between;
|
|
318
|
+
margin-top: 24px;
|
|
319
|
+
font-size: 0.85rem;
|
|
320
|
+
color: var(--color-text-muted);
|
|
274
321
|
}
|
|
275
322
|
|
|
276
323
|
.footer button {
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
324
|
+
background: none;
|
|
325
|
+
border: none;
|
|
326
|
+
color: var(--color-text-muted);
|
|
327
|
+
cursor: pointer;
|
|
281
328
|
}
|
|
282
329
|
|
|
283
330
|
.footer button:hover {
|
|
284
|
-
|
|
331
|
+
color: var(--color-text);
|
|
285
332
|
}
|
|
286
333
|
|
|
287
334
|
.branding {
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
335
|
+
margin-top: 48px;
|
|
336
|
+
text-align: center;
|
|
337
|
+
font-size: 0.75rem;
|
|
338
|
+
color: var(--color-text-dim);
|
|
292
339
|
}
|
|
@@ -4,7 +4,6 @@
|
|
|
4
4
|
// Import the WASM binary URL so Vite resolves it with the correct content hash.
|
|
5
5
|
// Without this, production builds fail because sqlite3 looks for the unhashed filename.
|
|
6
6
|
import sqliteWasmUrl from '@sqlite.org/sqlite-wasm/sqlite3.wasm?url'
|
|
7
|
-
|
|
8
7
|
;(globalThis as Record<string, unknown>).__KORA_SQLITE_WASM_URL = sqliteWasmUrl
|
|
9
8
|
|
|
10
9
|
import '@korajs/store/sqlite-wasm/worker'
|
|
@@ -1,36 +1,52 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { createKoraAuthSync } from '@korajs/auth'
|
|
2
|
+
import { AuthProvider } from '@korajs/auth/react'
|
|
2
3
|
import { KoraProvider } from '@korajs/react'
|
|
4
|
+
import { createApp } from 'korajs'
|
|
3
5
|
import { StrictMode } from 'react'
|
|
4
6
|
import { createRoot } from 'react-dom/client'
|
|
5
|
-
import schema from './schema'
|
|
6
7
|
import { App } from './App'
|
|
8
|
+
import { authClient, completeOAuthCallbackFromLocation } from './auth'
|
|
9
|
+
import schema from './schema'
|
|
7
10
|
import './index.css'
|
|
8
11
|
import koraWorkerUrl from './kora-worker.ts?worker&url'
|
|
9
12
|
|
|
10
13
|
// Build sync URL: use env var if set, otherwise derive from current page host.
|
|
11
14
|
// This allows the Vite proxy (/kora-sync → ws://localhost:3001) to work in dev,
|
|
12
15
|
// and also works through any tunnel (ngrok, cloudflared) without extra configuration.
|
|
13
|
-
const syncUrl =
|
|
14
|
-
|
|
16
|
+
const syncUrl =
|
|
17
|
+
import.meta.env.VITE_SYNC_URL ||
|
|
18
|
+
`${window.location.protocol === 'https:' ? 'wss:' : 'ws:'}//${window.location.host}/kora-sync`
|
|
15
19
|
|
|
16
20
|
const app = createApp({
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
21
|
+
schema,
|
|
22
|
+
sync: {
|
|
23
|
+
url: syncUrl,
|
|
24
|
+
authClient: createKoraAuthSync({ authClient, schema }),
|
|
25
|
+
},
|
|
26
|
+
store: {
|
|
27
|
+
workerUrl: koraWorkerUrl,
|
|
28
|
+
},
|
|
29
|
+
devtools: true,
|
|
25
30
|
})
|
|
26
31
|
|
|
27
32
|
// Connect to sync server once the app is ready
|
|
28
33
|
app.ready.then(() => app.sync?.connect())
|
|
34
|
+
void completeOAuthCallbackFromLocation().catch((error) => {
|
|
35
|
+
console.error('[Kora Auth] OAuth callback failed:', error)
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
const rootElement = document.getElementById('root')
|
|
39
|
+
|
|
40
|
+
if (!rootElement) {
|
|
41
|
+
throw new Error('Root element not found')
|
|
42
|
+
}
|
|
29
43
|
|
|
30
|
-
createRoot(
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
44
|
+
createRoot(rootElement).render(
|
|
45
|
+
<StrictMode>
|
|
46
|
+
<AuthProvider client={authClient} fallback={<div>Restoring session...</div>}>
|
|
47
|
+
<KoraProvider app={app} fallback={<div>Loading...</div>}>
|
|
48
|
+
<App />
|
|
49
|
+
</KoraProvider>
|
|
50
|
+
</AuthProvider>
|
|
51
|
+
</StrictMode>,
|
|
36
52
|
)
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { CollectionAccessor } from 'korajs'
|
|
2
|
+
|
|
3
|
+
export interface CreateTodoInput {
|
|
4
|
+
title: string
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export interface UpdateTodoStatusInput {
|
|
8
|
+
completed: boolean
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function createTodo(todos: CollectionAccessor, data: CreateTodoInput) {
|
|
12
|
+
return todos.insert({ title: data.title })
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function updateTodoStatus(
|
|
16
|
+
todos: CollectionAccessor,
|
|
17
|
+
id: string,
|
|
18
|
+
data: UpdateTodoStatusInput,
|
|
19
|
+
) {
|
|
20
|
+
return todos.update(id, { completed: data.completed })
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function deleteTodo(todos: CollectionAccessor, id: string) {
|
|
24
|
+
return todos.delete(id)
|
|
25
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { useCollection, useMutation, useQuery } from '@korajs/react'
|
|
2
|
+
import {
|
|
3
|
+
type CreateTodoInput,
|
|
4
|
+
type UpdateTodoStatusInput,
|
|
5
|
+
createTodo,
|
|
6
|
+
deleteTodo,
|
|
7
|
+
updateTodoStatus,
|
|
8
|
+
} from './todo.mutations'
|
|
9
|
+
import { orderedTodos } from './todo.queries'
|
|
10
|
+
|
|
11
|
+
export function useTodos() {
|
|
12
|
+
const todos = useCollection('todos')
|
|
13
|
+
const allTodos = useQuery(orderedTodos(todos))
|
|
14
|
+
const addTodo = useMutation((data: CreateTodoInput) => createTodo(todos, data))
|
|
15
|
+
const toggleTodo = useMutation((id: string, data: UpdateTodoStatusInput) =>
|
|
16
|
+
updateTodoStatus(todos, id, data),
|
|
17
|
+
)
|
|
18
|
+
const removeTodo = useMutation((id: string) => deleteTodo(todos, id))
|
|
19
|
+
|
|
20
|
+
const activeTodos = allTodos.filter((todo) => !todo.completed)
|
|
21
|
+
const completedTodos = allTodos.filter((todo) => !!todo.completed)
|
|
22
|
+
|
|
23
|
+
return {
|
|
24
|
+
allTodos,
|
|
25
|
+
activeTodos,
|
|
26
|
+
completedTodos,
|
|
27
|
+
addTodo,
|
|
28
|
+
toggleTodo,
|
|
29
|
+
deleteTodo: removeTodo,
|
|
30
|
+
}
|
|
31
|
+
}
|
|
@@ -1,15 +1,9 @@
|
|
|
1
|
-
import { defineSchema
|
|
1
|
+
import { defineSchema } from 'korajs'
|
|
2
|
+
import { todos } from './modules/todos/todo.schema'
|
|
2
3
|
|
|
3
4
|
export default defineSchema({
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
title: t.string(),
|
|
9
|
-
completed: t.boolean().default(false),
|
|
10
|
-
createdAt: t.timestamp().auto(),
|
|
11
|
-
},
|
|
12
|
-
indexes: ['completed'],
|
|
13
|
-
},
|
|
14
|
-
},
|
|
5
|
+
version: 1,
|
|
6
|
+
collections: {
|
|
7
|
+
todos,
|
|
8
|
+
},
|
|
15
9
|
})
|