xote 1.0.2 → 1.2.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/LICENSE +11 -18
- package/README.md +97 -41
- package/dist/xote.cjs +1 -0
- package/dist/xote.mjs +1041 -0
- package/dist/xote.umd.js +1 -0
- package/package.json +23 -3
- package/.gitattributes +0 -2
- package/.github/workflows/release.yml +0 -44
- package/dist/index.cjs +0 -2
- package/dist/index.cjs.map +0 -1
- package/dist/index.mjs +0 -9
- package/dist/index.mjs.map +0 -1
- package/dist/index.umd.js +0 -2
- package/dist/index.umd.js.map +0 -1
- package/docs/CHANGELOG.md +0 -27
- package/index.html +0 -28
- package/rescript.json +0 -18
- package/src/Xote.res +0 -5
- package/src/Xote.res.mjs +0 -21
- package/src/Xote__Component.res +0 -151
- package/src/Xote__Component.res.mjs +0 -202
- package/src/Xote__Computed.res +0 -43
- package/src/Xote__Computed.res.mjs +0 -61
- package/src/Xote__Core.res +0 -105
- package/src/Xote__Core.res.mjs +0 -148
- package/src/Xote__Effect.res +0 -36
- package/src/Xote__Effect.res.mjs +0 -57
- package/src/Xote__Example.res +0 -266
- package/src/Xote__Example.res.mjs +0 -303
- package/src/Xote__Id.res +0 -5
- package/src/Xote__Id.res.mjs +0 -17
- package/src/Xote__Observer.res +0 -12
- package/src/Xote__Observer.res.mjs +0 -12
- package/src/Xote__Signal.res +0 -31
- package/src/Xote__Signal.res.mjs +0 -64
- package/src/demo/TodoApp.res +0 -289
- package/src/demo/TodoApp.res.mjs +0 -326
- package/vite.config.js +0 -45
package/src/demo/TodoApp.res
DELETED
|
@@ -1,289 +0,0 @@
|
|
|
1
|
-
open Xote
|
|
2
|
-
|
|
3
|
-
type todo = {
|
|
4
|
-
id: int,
|
|
5
|
-
text: string,
|
|
6
|
-
completed: bool,
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
let todos = Signal.make([{id: 1, text: "Buy Milk", completed: true}])
|
|
10
|
-
let nextId = ref(0)
|
|
11
|
-
let inputValue = Signal.make("")
|
|
12
|
-
let darkMode = Signal.make(false)
|
|
13
|
-
|
|
14
|
-
// Computed values derived from todos
|
|
15
|
-
let completedCount = Computed.make(() => {
|
|
16
|
-
Signal.get(todos)->Array.filter(todo => todo.completed)->Array.length
|
|
17
|
-
})
|
|
18
|
-
|
|
19
|
-
let activeCount = Computed.make(() => {
|
|
20
|
-
Signal.get(todos)->Array.filter(todo => !todo.completed)->Array.length
|
|
21
|
-
})
|
|
22
|
-
|
|
23
|
-
let totalCount = Computed.make(() => {
|
|
24
|
-
Signal.get(todos)->Array.length
|
|
25
|
-
})
|
|
26
|
-
|
|
27
|
-
let addTodo = (text: string) => {
|
|
28
|
-
if String.trim(text) != "" {
|
|
29
|
-
Signal.update(todos, list => {
|
|
30
|
-
Array.concat(list, [{id: nextId.contents, text, completed: false}])
|
|
31
|
-
})
|
|
32
|
-
nextId := nextId.contents + 1
|
|
33
|
-
Signal.set(inputValue, "")
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
let toggleTodo = (id: int) => {
|
|
38
|
-
todos->Signal.update(todos => {
|
|
39
|
-
let markAsComplete = todo => todo.id == id ? {...todo, completed: !todo.completed} : todo
|
|
40
|
-
todos->Array.map(markAsComplete)
|
|
41
|
-
})
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
let removeTodo = (id: int) => {
|
|
45
|
-
todos->Signal.update(todos => todos->Array.filter(todo => todo.id != id))
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
@val @scope("document") external querySelector: string => Nullable.t<Dom.element> = "querySelector"
|
|
49
|
-
@get external target: Dom.event => Dom.element = "target"
|
|
50
|
-
@get external value: Dom.element => string = "value"
|
|
51
|
-
@set external setValue: (Dom.element, string) => unit = "value"
|
|
52
|
-
@get external key: Dom.event => string = "key"
|
|
53
|
-
|
|
54
|
-
let clearInput = () => {
|
|
55
|
-
switch querySelector(".todo-input")->Nullable.toOption {
|
|
56
|
-
| Some(input) => setValue(input, "")
|
|
57
|
-
| None => ()
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
let handleInput = (evt: Dom.event) => {
|
|
62
|
-
let newValue = evt->target->value
|
|
63
|
-
Signal.set(inputValue, newValue)
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
let getInputValue = () => {
|
|
67
|
-
switch querySelector(".todo-input")->Nullable.toOption {
|
|
68
|
-
| Some(input) => input->value
|
|
69
|
-
| None => ""
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
let handleKeyDown = (evt: Dom.event) => {
|
|
74
|
-
if evt->key == "Enter" {
|
|
75
|
-
addTodo(getInputValue())
|
|
76
|
-
clearInput()
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
let handleAddClick = (_evt: Dom.event) => {
|
|
81
|
-
addTodo(getInputValue())
|
|
82
|
-
clearInput()
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
let toggleTheme = (_evt: Dom.event) => {
|
|
86
|
-
Signal.update(darkMode, mode => !mode)
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
// Effect to sync dark mode with HTML class
|
|
90
|
-
let _ = Effect.run(() => {
|
|
91
|
-
let isDark = Signal.get(darkMode)
|
|
92
|
-
if isDark {
|
|
93
|
-
%raw(`document.documentElement.classList.add('dark')`)
|
|
94
|
-
} else {
|
|
95
|
-
%raw(`document.documentElement.classList.remove('dark')`)
|
|
96
|
-
}
|
|
97
|
-
})
|
|
98
|
-
|
|
99
|
-
let todoItem = (todo: todo) => {
|
|
100
|
-
let checkboxAttrs = todo.completed
|
|
101
|
-
? [("type", "checkbox"), ("checked", "checked"), ("class", "w-5 h-5 cursor-pointer")]
|
|
102
|
-
: [("type", "checkbox"), ("class", "w-5 h-5 cursor-pointer")]
|
|
103
|
-
|
|
104
|
-
Component.li(
|
|
105
|
-
~attrs=[
|
|
106
|
-
(
|
|
107
|
-
"class",
|
|
108
|
-
"flex items-center gap-3 p-3 bg-white dark:bg-gray-800 rounded-lg border border-gray-200 dark:border-gray-700 mb-2 " ++ (
|
|
109
|
-
todo.completed ? "completed" : ""
|
|
110
|
-
),
|
|
111
|
-
),
|
|
112
|
-
],
|
|
113
|
-
~children=[
|
|
114
|
-
Component.input(~attrs=checkboxAttrs, ~events=[("change", _ => toggleTodo(todo.id))], ()),
|
|
115
|
-
Component.span(
|
|
116
|
-
~attrs=[("class", "flex-1 text-gray-900 dark:text-gray-100")],
|
|
117
|
-
~children=[Component.text(todo.text)],
|
|
118
|
-
(),
|
|
119
|
-
),
|
|
120
|
-
Component.button(
|
|
121
|
-
~events=[("click", _ => removeTodo(todo.id))],
|
|
122
|
-
~children=[Component.Text("Delete")],
|
|
123
|
-
(),
|
|
124
|
-
),
|
|
125
|
-
],
|
|
126
|
-
(),
|
|
127
|
-
)
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
let inputElement = Component.input(
|
|
131
|
-
~attrs=[
|
|
132
|
-
("type", "text"),
|
|
133
|
-
("placeholder", "What needs to be done?"),
|
|
134
|
-
(
|
|
135
|
-
"class",
|
|
136
|
-
"todo-input flex-1 px-4 py-2 border border-gray-300 dark:border-gray-600 rounded-lg bg-white dark:bg-gray-800 text-gray-900 dark:text-gray-100 focus:outline-none focus:ring-2 focus:ring-blue-500",
|
|
137
|
-
),
|
|
138
|
-
],
|
|
139
|
-
~events=[("input", handleInput), ("keydown", handleKeyDown)],
|
|
140
|
-
(),
|
|
141
|
-
)
|
|
142
|
-
|
|
143
|
-
let app = Component.div(
|
|
144
|
-
~attrs=[("class", "max-w-2xl mx-auto p-6 space-y-6")],
|
|
145
|
-
~children=[
|
|
146
|
-
Component.div(
|
|
147
|
-
~attrs=[("class", "bg-white dark:bg-gray-800 rounded-xl shadow-lg p-8")],
|
|
148
|
-
~children=[
|
|
149
|
-
Component.div(
|
|
150
|
-
~attrs=[("class", "flex items-center justify-between mb-6")],
|
|
151
|
-
~children=[
|
|
152
|
-
Component.h1(
|
|
153
|
-
~attrs=[("class", "text-3xl font-bold text-gray-900 dark:text-white")],
|
|
154
|
-
~children=[Component.text("Todo List")],
|
|
155
|
-
(),
|
|
156
|
-
),
|
|
157
|
-
Component.button(
|
|
158
|
-
~attrs=[
|
|
159
|
-
(
|
|
160
|
-
"class",
|
|
161
|
-
"px-4 py-2 rounded-lg bg-gray-200 dark:bg-gray-700 text-gray-800 dark:text-gray-200 hover:bg-gray-300 dark:hover:bg-gray-600 transition-colors",
|
|
162
|
-
),
|
|
163
|
-
],
|
|
164
|
-
~events=[("click", toggleTheme)],
|
|
165
|
-
~children=[
|
|
166
|
-
Component.textSignal(
|
|
167
|
-
Computed.make(() => Signal.get(darkMode) ? "☀️ Light" : "🌙 Dark"),
|
|
168
|
-
),
|
|
169
|
-
],
|
|
170
|
-
(),
|
|
171
|
-
),
|
|
172
|
-
],
|
|
173
|
-
(),
|
|
174
|
-
),
|
|
175
|
-
Component.div(
|
|
176
|
-
~attrs=[
|
|
177
|
-
(
|
|
178
|
-
"class",
|
|
179
|
-
"grid grid-cols-3 gap-4 mb-6 p-4 bg-gray-50 dark:bg-gray-900 rounded-lg border border-gray-200 dark:border-gray-700",
|
|
180
|
-
),
|
|
181
|
-
],
|
|
182
|
-
~children=[
|
|
183
|
-
Component.div(
|
|
184
|
-
~attrs=[("class", "flex flex-col items-center")],
|
|
185
|
-
~children=[
|
|
186
|
-
Component.span(
|
|
187
|
-
~attrs=[
|
|
188
|
-
(
|
|
189
|
-
"class",
|
|
190
|
-
"text-xs text-gray-600 dark:text-gray-400 uppercase tracking-wide mb-1",
|
|
191
|
-
),
|
|
192
|
-
],
|
|
193
|
-
~children=[Component.text("Total")],
|
|
194
|
-
(),
|
|
195
|
-
),
|
|
196
|
-
Component.span(
|
|
197
|
-
~attrs=[("class", "text-2xl font-bold text-gray-900 dark:text-white")],
|
|
198
|
-
~children=[
|
|
199
|
-
Component.textSignal(Computed.make(() => Int.toString(Signal.get(totalCount)))),
|
|
200
|
-
],
|
|
201
|
-
(),
|
|
202
|
-
),
|
|
203
|
-
],
|
|
204
|
-
(),
|
|
205
|
-
),
|
|
206
|
-
Component.div(
|
|
207
|
-
~attrs=[("class", "flex flex-col items-center")],
|
|
208
|
-
~children=[
|
|
209
|
-
Component.span(
|
|
210
|
-
~attrs=[
|
|
211
|
-
(
|
|
212
|
-
"class",
|
|
213
|
-
"text-xs text-gray-600 dark:text-gray-400 uppercase tracking-wide mb-1",
|
|
214
|
-
),
|
|
215
|
-
],
|
|
216
|
-
~children=[Component.text("Active")],
|
|
217
|
-
(),
|
|
218
|
-
),
|
|
219
|
-
Component.span(
|
|
220
|
-
~attrs=[("class", "text-2xl font-bold text-blue-600 dark:text-blue-400")],
|
|
221
|
-
~children=[
|
|
222
|
-
Component.textSignal(
|
|
223
|
-
Computed.make(() => Int.toString(Signal.get(activeCount))),
|
|
224
|
-
),
|
|
225
|
-
],
|
|
226
|
-
(),
|
|
227
|
-
),
|
|
228
|
-
],
|
|
229
|
-
(),
|
|
230
|
-
),
|
|
231
|
-
Component.div(
|
|
232
|
-
~attrs=[("class", "flex flex-col items-center")],
|
|
233
|
-
~children=[
|
|
234
|
-
Component.span(
|
|
235
|
-
~attrs=[
|
|
236
|
-
(
|
|
237
|
-
"class",
|
|
238
|
-
"text-xs text-gray-600 dark:text-gray-400 uppercase tracking-wide mb-1",
|
|
239
|
-
),
|
|
240
|
-
],
|
|
241
|
-
~children=[Component.text("Completed")],
|
|
242
|
-
(),
|
|
243
|
-
),
|
|
244
|
-
Component.span(
|
|
245
|
-
~attrs=[("class", "text-2xl font-bold text-green-600 dark:text-green-400")],
|
|
246
|
-
~children=[
|
|
247
|
-
Component.textSignal(
|
|
248
|
-
Computed.make(() => Int.toString(Signal.get(completedCount))),
|
|
249
|
-
),
|
|
250
|
-
],
|
|
251
|
-
(),
|
|
252
|
-
),
|
|
253
|
-
],
|
|
254
|
-
(),
|
|
255
|
-
),
|
|
256
|
-
],
|
|
257
|
-
(),
|
|
258
|
-
),
|
|
259
|
-
Component.div(
|
|
260
|
-
~attrs=[("class", "flex gap-2 mb-6")],
|
|
261
|
-
~children=[
|
|
262
|
-
inputElement,
|
|
263
|
-
Component.button(
|
|
264
|
-
~attrs=[
|
|
265
|
-
(
|
|
266
|
-
"class",
|
|
267
|
-
"px-6 py-2 bg-blue-600 hover:bg-blue-700 text-white rounded-lg font-medium transition-colors focus:outline-none focus:ring-2 focus:ring-blue-500",
|
|
268
|
-
),
|
|
269
|
-
],
|
|
270
|
-
~events=[("click", handleAddClick)],
|
|
271
|
-
~children=[Component.text("Add")],
|
|
272
|
-
(),
|
|
273
|
-
),
|
|
274
|
-
],
|
|
275
|
-
(),
|
|
276
|
-
),
|
|
277
|
-
Component.ul(
|
|
278
|
-
~attrs=[("class", "todo-list space-y-2")],
|
|
279
|
-
~children=[Component.list(todos, todoItem)],
|
|
280
|
-
(),
|
|
281
|
-
),
|
|
282
|
-
],
|
|
283
|
-
(),
|
|
284
|
-
),
|
|
285
|
-
],
|
|
286
|
-
(),
|
|
287
|
-
)
|
|
288
|
-
|
|
289
|
-
Component.mountById(app, "app")
|
package/src/demo/TodoApp.res.mjs
DELETED
|
@@ -1,326 +0,0 @@
|
|
|
1
|
-
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
|
-
|
|
3
|
-
import * as Xote__Effect from "../Xote__Effect.res.mjs";
|
|
4
|
-
import * as Xote__Signal from "../Xote__Signal.res.mjs";
|
|
5
|
-
import * as Xote__Computed from "../Xote__Computed.res.mjs";
|
|
6
|
-
import * as Xote__Component from "../Xote__Component.res.mjs";
|
|
7
|
-
|
|
8
|
-
var todos = Xote__Signal.make([{
|
|
9
|
-
id: 1,
|
|
10
|
-
text: "Buy Milk",
|
|
11
|
-
completed: true
|
|
12
|
-
}]);
|
|
13
|
-
|
|
14
|
-
var nextId = {
|
|
15
|
-
contents: 0
|
|
16
|
-
};
|
|
17
|
-
|
|
18
|
-
var inputValue = Xote__Signal.make("");
|
|
19
|
-
|
|
20
|
-
var darkMode = Xote__Signal.make(false);
|
|
21
|
-
|
|
22
|
-
var completedCount = Xote__Computed.make(function () {
|
|
23
|
-
return Xote__Signal.get(todos).filter(function (todo) {
|
|
24
|
-
return todo.completed;
|
|
25
|
-
}).length;
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
var activeCount = Xote__Computed.make(function () {
|
|
29
|
-
return Xote__Signal.get(todos).filter(function (todo) {
|
|
30
|
-
return !todo.completed;
|
|
31
|
-
}).length;
|
|
32
|
-
});
|
|
33
|
-
|
|
34
|
-
var totalCount = Xote__Computed.make(function () {
|
|
35
|
-
return Xote__Signal.get(todos).length;
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
function addTodo(text) {
|
|
39
|
-
if (text.trim() !== "") {
|
|
40
|
-
Xote__Signal.update(todos, (function (list) {
|
|
41
|
-
return list.concat([{
|
|
42
|
-
id: nextId.contents,
|
|
43
|
-
text: text,
|
|
44
|
-
completed: false
|
|
45
|
-
}]);
|
|
46
|
-
}));
|
|
47
|
-
nextId.contents = nextId.contents + 1 | 0;
|
|
48
|
-
return Xote__Signal.set(inputValue, "");
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
function toggleTodo(id) {
|
|
54
|
-
Xote__Signal.update(todos, (function (todos) {
|
|
55
|
-
var markAsComplete = function (todo) {
|
|
56
|
-
if (todo.id === id) {
|
|
57
|
-
return {
|
|
58
|
-
id: todo.id,
|
|
59
|
-
text: todo.text,
|
|
60
|
-
completed: !todo.completed
|
|
61
|
-
};
|
|
62
|
-
} else {
|
|
63
|
-
return todo;
|
|
64
|
-
}
|
|
65
|
-
};
|
|
66
|
-
return todos.map(markAsComplete);
|
|
67
|
-
}));
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
function removeTodo(id) {
|
|
71
|
-
Xote__Signal.update(todos, (function (todos) {
|
|
72
|
-
return todos.filter(function (todo) {
|
|
73
|
-
return todo.id !== id;
|
|
74
|
-
});
|
|
75
|
-
}));
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
function clearInput() {
|
|
79
|
-
var input = document.querySelector(".todo-input");
|
|
80
|
-
if (!(input == null)) {
|
|
81
|
-
input.value = "";
|
|
82
|
-
return ;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
function handleInput(evt) {
|
|
88
|
-
var newValue = evt.target.value;
|
|
89
|
-
Xote__Signal.set(inputValue, newValue);
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
function getInputValue() {
|
|
93
|
-
var input = document.querySelector(".todo-input");
|
|
94
|
-
if (input == null) {
|
|
95
|
-
return "";
|
|
96
|
-
} else {
|
|
97
|
-
return input.value;
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
function handleKeyDown(evt) {
|
|
102
|
-
if (evt.key === "Enter") {
|
|
103
|
-
addTodo(getInputValue());
|
|
104
|
-
return clearInput();
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
function handleAddClick(_evt) {
|
|
110
|
-
addTodo(getInputValue());
|
|
111
|
-
clearInput();
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
function toggleTheme(_evt) {
|
|
115
|
-
Xote__Signal.update(darkMode, (function (mode) {
|
|
116
|
-
return !mode;
|
|
117
|
-
}));
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
Xote__Effect.run(function () {
|
|
121
|
-
var isDark = Xote__Signal.get(darkMode);
|
|
122
|
-
if (isDark) {
|
|
123
|
-
return (document.documentElement.classList.add('dark'));
|
|
124
|
-
} else {
|
|
125
|
-
return (document.documentElement.classList.remove('dark'));
|
|
126
|
-
}
|
|
127
|
-
});
|
|
128
|
-
|
|
129
|
-
function todoItem(todo) {
|
|
130
|
-
var checkboxAttrs = todo.completed ? [
|
|
131
|
-
[
|
|
132
|
-
"type",
|
|
133
|
-
"checkbox"
|
|
134
|
-
],
|
|
135
|
-
[
|
|
136
|
-
"checked",
|
|
137
|
-
"checked"
|
|
138
|
-
],
|
|
139
|
-
[
|
|
140
|
-
"class",
|
|
141
|
-
"w-5 h-5 cursor-pointer"
|
|
142
|
-
]
|
|
143
|
-
] : [
|
|
144
|
-
[
|
|
145
|
-
"type",
|
|
146
|
-
"checkbox"
|
|
147
|
-
],
|
|
148
|
-
[
|
|
149
|
-
"class",
|
|
150
|
-
"w-5 h-5 cursor-pointer"
|
|
151
|
-
]
|
|
152
|
-
];
|
|
153
|
-
return Xote__Component.li([[
|
|
154
|
-
"class",
|
|
155
|
-
"flex items-center gap-3 p-3 bg-white dark:bg-gray-800 rounded-lg border border-gray-200 dark:border-gray-700 mb-2 " + (
|
|
156
|
-
todo.completed ? "completed" : ""
|
|
157
|
-
)
|
|
158
|
-
]], undefined, [
|
|
159
|
-
Xote__Component.input(checkboxAttrs, [[
|
|
160
|
-
"change",
|
|
161
|
-
(function (param) {
|
|
162
|
-
toggleTodo(todo.id);
|
|
163
|
-
})
|
|
164
|
-
]], undefined),
|
|
165
|
-
Xote__Component.span([[
|
|
166
|
-
"class",
|
|
167
|
-
"flex-1 text-gray-900 dark:text-gray-100"
|
|
168
|
-
]], undefined, [Xote__Component.text(todo.text)], undefined),
|
|
169
|
-
Xote__Component.button(undefined, [[
|
|
170
|
-
"click",
|
|
171
|
-
(function (param) {
|
|
172
|
-
removeTodo(todo.id);
|
|
173
|
-
})
|
|
174
|
-
]], [{
|
|
175
|
-
TAG: "Text",
|
|
176
|
-
_0: "Delete"
|
|
177
|
-
}], undefined)
|
|
178
|
-
], undefined);
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
var inputElement = Xote__Component.input([
|
|
182
|
-
[
|
|
183
|
-
"type",
|
|
184
|
-
"text"
|
|
185
|
-
],
|
|
186
|
-
[
|
|
187
|
-
"placeholder",
|
|
188
|
-
"What needs to be done?"
|
|
189
|
-
],
|
|
190
|
-
[
|
|
191
|
-
"class",
|
|
192
|
-
"todo-input flex-1 px-4 py-2 border border-gray-300 dark:border-gray-600 rounded-lg bg-white dark:bg-gray-800 text-gray-900 dark:text-gray-100 focus:outline-none focus:ring-2 focus:ring-blue-500"
|
|
193
|
-
]
|
|
194
|
-
], [
|
|
195
|
-
[
|
|
196
|
-
"input",
|
|
197
|
-
handleInput
|
|
198
|
-
],
|
|
199
|
-
[
|
|
200
|
-
"keydown",
|
|
201
|
-
handleKeyDown
|
|
202
|
-
]
|
|
203
|
-
], undefined);
|
|
204
|
-
|
|
205
|
-
var app = Xote__Component.div([[
|
|
206
|
-
"class",
|
|
207
|
-
"max-w-2xl mx-auto p-6 space-y-6"
|
|
208
|
-
]], undefined, [Xote__Component.div([[
|
|
209
|
-
"class",
|
|
210
|
-
"bg-white dark:bg-gray-800 rounded-xl shadow-lg p-8"
|
|
211
|
-
]], undefined, [
|
|
212
|
-
Xote__Component.div([[
|
|
213
|
-
"class",
|
|
214
|
-
"flex items-center justify-between mb-6"
|
|
215
|
-
]], undefined, [
|
|
216
|
-
Xote__Component.h1([[
|
|
217
|
-
"class",
|
|
218
|
-
"text-3xl font-bold text-gray-900 dark:text-white"
|
|
219
|
-
]], undefined, [Xote__Component.text("Todo List")], undefined),
|
|
220
|
-
Xote__Component.button([[
|
|
221
|
-
"class",
|
|
222
|
-
"px-4 py-2 rounded-lg bg-gray-200 dark:bg-gray-700 text-gray-800 dark:text-gray-200 hover:bg-gray-300 dark:hover:bg-gray-600 transition-colors"
|
|
223
|
-
]], [[
|
|
224
|
-
"click",
|
|
225
|
-
toggleTheme
|
|
226
|
-
]], [Xote__Component.textSignal(Xote__Computed.make(function () {
|
|
227
|
-
if (Xote__Signal.get(darkMode)) {
|
|
228
|
-
return "☀️ Light";
|
|
229
|
-
} else {
|
|
230
|
-
return "🌙 Dark";
|
|
231
|
-
}
|
|
232
|
-
}))], undefined)
|
|
233
|
-
], undefined),
|
|
234
|
-
Xote__Component.div([[
|
|
235
|
-
"class",
|
|
236
|
-
"grid grid-cols-3 gap-4 mb-6 p-4 bg-gray-50 dark:bg-gray-900 rounded-lg border border-gray-200 dark:border-gray-700"
|
|
237
|
-
]], undefined, [
|
|
238
|
-
Xote__Component.div([[
|
|
239
|
-
"class",
|
|
240
|
-
"flex flex-col items-center"
|
|
241
|
-
]], undefined, [
|
|
242
|
-
Xote__Component.span([[
|
|
243
|
-
"class",
|
|
244
|
-
"text-xs text-gray-600 dark:text-gray-400 uppercase tracking-wide mb-1"
|
|
245
|
-
]], undefined, [Xote__Component.text("Total")], undefined),
|
|
246
|
-
Xote__Component.span([[
|
|
247
|
-
"class",
|
|
248
|
-
"text-2xl font-bold text-gray-900 dark:text-white"
|
|
249
|
-
]], undefined, [Xote__Component.textSignal(Xote__Computed.make(function () {
|
|
250
|
-
return Xote__Signal.get(totalCount).toString();
|
|
251
|
-
}))], undefined)
|
|
252
|
-
], undefined),
|
|
253
|
-
Xote__Component.div([[
|
|
254
|
-
"class",
|
|
255
|
-
"flex flex-col items-center"
|
|
256
|
-
]], undefined, [
|
|
257
|
-
Xote__Component.span([[
|
|
258
|
-
"class",
|
|
259
|
-
"text-xs text-gray-600 dark:text-gray-400 uppercase tracking-wide mb-1"
|
|
260
|
-
]], undefined, [Xote__Component.text("Active")], undefined),
|
|
261
|
-
Xote__Component.span([[
|
|
262
|
-
"class",
|
|
263
|
-
"text-2xl font-bold text-blue-600 dark:text-blue-400"
|
|
264
|
-
]], undefined, [Xote__Component.textSignal(Xote__Computed.make(function () {
|
|
265
|
-
return Xote__Signal.get(activeCount).toString();
|
|
266
|
-
}))], undefined)
|
|
267
|
-
], undefined),
|
|
268
|
-
Xote__Component.div([[
|
|
269
|
-
"class",
|
|
270
|
-
"flex flex-col items-center"
|
|
271
|
-
]], undefined, [
|
|
272
|
-
Xote__Component.span([[
|
|
273
|
-
"class",
|
|
274
|
-
"text-xs text-gray-600 dark:text-gray-400 uppercase tracking-wide mb-1"
|
|
275
|
-
]], undefined, [Xote__Component.text("Completed")], undefined),
|
|
276
|
-
Xote__Component.span([[
|
|
277
|
-
"class",
|
|
278
|
-
"text-2xl font-bold text-green-600 dark:text-green-400"
|
|
279
|
-
]], undefined, [Xote__Component.textSignal(Xote__Computed.make(function () {
|
|
280
|
-
return Xote__Signal.get(completedCount).toString();
|
|
281
|
-
}))], undefined)
|
|
282
|
-
], undefined)
|
|
283
|
-
], undefined),
|
|
284
|
-
Xote__Component.div([[
|
|
285
|
-
"class",
|
|
286
|
-
"flex gap-2 mb-6"
|
|
287
|
-
]], undefined, [
|
|
288
|
-
inputElement,
|
|
289
|
-
Xote__Component.button([[
|
|
290
|
-
"class",
|
|
291
|
-
"px-6 py-2 bg-blue-600 hover:bg-blue-700 text-white rounded-lg font-medium transition-colors focus:outline-none focus:ring-2 focus:ring-blue-500"
|
|
292
|
-
]], [[
|
|
293
|
-
"click",
|
|
294
|
-
handleAddClick
|
|
295
|
-
]], [Xote__Component.text("Add")], undefined)
|
|
296
|
-
], undefined),
|
|
297
|
-
Xote__Component.ul([[
|
|
298
|
-
"class",
|
|
299
|
-
"todo-list space-y-2"
|
|
300
|
-
]], undefined, [Xote__Component.list(todos, todoItem)], undefined)
|
|
301
|
-
], undefined)], undefined);
|
|
302
|
-
|
|
303
|
-
Xote__Component.mountById(app, "app");
|
|
304
|
-
|
|
305
|
-
export {
|
|
306
|
-
todos ,
|
|
307
|
-
nextId ,
|
|
308
|
-
inputValue ,
|
|
309
|
-
darkMode ,
|
|
310
|
-
completedCount ,
|
|
311
|
-
activeCount ,
|
|
312
|
-
totalCount ,
|
|
313
|
-
addTodo ,
|
|
314
|
-
toggleTodo ,
|
|
315
|
-
removeTodo ,
|
|
316
|
-
clearInput ,
|
|
317
|
-
handleInput ,
|
|
318
|
-
getInputValue ,
|
|
319
|
-
handleKeyDown ,
|
|
320
|
-
handleAddClick ,
|
|
321
|
-
toggleTheme ,
|
|
322
|
-
todoItem ,
|
|
323
|
-
inputElement ,
|
|
324
|
-
app ,
|
|
325
|
-
}
|
|
326
|
-
/* todos Not a pure module */
|
package/vite.config.js
DELETED
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
import { defineConfig } from "vite";
|
|
2
|
-
import path from "node:path";
|
|
3
|
-
import { readFileSync } from "node:fs";
|
|
4
|
-
|
|
5
|
-
// Read package.json to auto-externalize deps & name the UMD build
|
|
6
|
-
const pkg = JSON.parse(
|
|
7
|
-
readFileSync(new URL("./package.json", import.meta.url), "utf-8")
|
|
8
|
-
);
|
|
9
|
-
|
|
10
|
-
// Allow overriding the entry with ENV: ENTRY=src/whatever.ts
|
|
11
|
-
const entryFromEnv = process.env.ENTRY;
|
|
12
|
-
|
|
13
|
-
export default defineConfig(() => ({
|
|
14
|
-
build: {
|
|
15
|
-
outDir: "dist",
|
|
16
|
-
sourcemap: true,
|
|
17
|
-
lib: {
|
|
18
|
-
// Default entry is src/index.ts; override with ENTRY env var
|
|
19
|
-
entry: path.resolve(process.cwd(), entryFromEnv ?? "src/Xote.res.mjs"),
|
|
20
|
-
// A safe global name for UMD; falls back to "Library"
|
|
21
|
-
name:
|
|
22
|
-
(pkg.name?.replace?.(/[^a-zA-Z0-9_$]/g, "_")) ||
|
|
23
|
-
"xote",
|
|
24
|
-
formats: ["es", "cjs", "umd"],
|
|
25
|
-
fileName: (format) =>
|
|
26
|
-
format === "es"
|
|
27
|
-
? "index.mjs"
|
|
28
|
-
: format === "cjs"
|
|
29
|
-
? "index.cjs"
|
|
30
|
-
: "index.umd.js",
|
|
31
|
-
},
|
|
32
|
-
rollupOptions: {
|
|
33
|
-
external: [
|
|
34
|
-
...Object.keys(pkg.dependencies ?? {}),
|
|
35
|
-
...Object.keys(pkg.peerDependencies ?? {}),
|
|
36
|
-
],
|
|
37
|
-
output: {
|
|
38
|
-
},
|
|
39
|
-
},
|
|
40
|
-
// Tweak if you want smaller/faster builds
|
|
41
|
-
minify: "esbuild",
|
|
42
|
-
target: "es2019",
|
|
43
|
-
emptyOutDir: true,
|
|
44
|
-
},
|
|
45
|
-
}));
|