@stamprally/admin-ui 0.2.1
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 +21 -0
- package/dist/index.cjs +502 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +68 -0
- package/dist/index.d.ts +68 -0
- package/dist/index.js +491 -0
- package/dist/index.js.map +1 -0
- package/package.json +55 -0
- package/src/styles.css +35 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 nitta-a
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,502 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var core = require('@stamprally/core');
|
|
4
|
+
var react = require('react');
|
|
5
|
+
var jsxRuntime = require('react/jsx-runtime');
|
|
6
|
+
|
|
7
|
+
// src/index.tsx
|
|
8
|
+
var localePair = (value) => ({
|
|
9
|
+
ja: core.resolveLocalizedText(value, "ja"),
|
|
10
|
+
en: core.resolveLocalizedText(value, "en")
|
|
11
|
+
});
|
|
12
|
+
function updateText(value, locale, next) {
|
|
13
|
+
const current = localePair(value);
|
|
14
|
+
return { ...current, [locale]: next };
|
|
15
|
+
}
|
|
16
|
+
function GeneralSettingsForm({ config, locale = "ja", onChange }) {
|
|
17
|
+
const pair = localePair(config.title);
|
|
18
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("fieldset", { className: "stamprally-admin-card", children: [
|
|
19
|
+
/* @__PURE__ */ jsxRuntime.jsx("legend", { children: "General settings" }),
|
|
20
|
+
/* @__PURE__ */ jsxRuntime.jsxs("label", { children: [
|
|
21
|
+
"ID ",
|
|
22
|
+
/* @__PURE__ */ jsxRuntime.jsx("input", { value: config.id, readOnly: true })
|
|
23
|
+
] }),
|
|
24
|
+
/* @__PURE__ */ jsxRuntime.jsxs("label", { children: [
|
|
25
|
+
"Title (",
|
|
26
|
+
locale,
|
|
27
|
+
")",
|
|
28
|
+
" ",
|
|
29
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
30
|
+
"input",
|
|
31
|
+
{
|
|
32
|
+
value: pair[locale],
|
|
33
|
+
required: true,
|
|
34
|
+
onChange: (event) => onChange({ ...config, title: updateText(config.title, locale, event.target.value) })
|
|
35
|
+
}
|
|
36
|
+
)
|
|
37
|
+
] }),
|
|
38
|
+
/* @__PURE__ */ jsxRuntime.jsxs("label", { children: [
|
|
39
|
+
"Start date",
|
|
40
|
+
" ",
|
|
41
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
42
|
+
"input",
|
|
43
|
+
{
|
|
44
|
+
type: "datetime-local",
|
|
45
|
+
value: config.startDate?.slice(0, 16) ?? "",
|
|
46
|
+
onChange: (event) => {
|
|
47
|
+
if (event.target.value === "") {
|
|
48
|
+
const { startDate: _startDate, ...rest } = config;
|
|
49
|
+
onChange(rest);
|
|
50
|
+
} else onChange({ ...config, startDate: new Date(event.target.value).toISOString() });
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
)
|
|
54
|
+
] }),
|
|
55
|
+
/* @__PURE__ */ jsxRuntime.jsxs("label", { children: [
|
|
56
|
+
"End date",
|
|
57
|
+
" ",
|
|
58
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
59
|
+
"input",
|
|
60
|
+
{
|
|
61
|
+
type: "datetime-local",
|
|
62
|
+
value: config.endDate?.slice(0, 16) ?? "",
|
|
63
|
+
onChange: (event) => {
|
|
64
|
+
if (event.target.value === "") {
|
|
65
|
+
const { endDate: _endDate, ...rest } = config;
|
|
66
|
+
onChange(rest);
|
|
67
|
+
} else onChange({ ...config, endDate: new Date(event.target.value).toISOString() });
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
)
|
|
71
|
+
] }),
|
|
72
|
+
/* @__PURE__ */ jsxRuntime.jsxs("label", { children: [
|
|
73
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
74
|
+
"input",
|
|
75
|
+
{
|
|
76
|
+
type: "checkbox",
|
|
77
|
+
checked: config.isSequential === true,
|
|
78
|
+
onChange: (event) => onChange({ ...config, isSequential: event.target.checked })
|
|
79
|
+
}
|
|
80
|
+
),
|
|
81
|
+
" ",
|
|
82
|
+
"Sequential check-in"
|
|
83
|
+
] })
|
|
84
|
+
] });
|
|
85
|
+
}
|
|
86
|
+
function ConditionEditor({ condition, onChange }) {
|
|
87
|
+
const type = condition.type;
|
|
88
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("fieldset", { className: "stamprally-admin-card", children: [
|
|
89
|
+
/* @__PURE__ */ jsxRuntime.jsx("legend", { children: "Check-in condition" }),
|
|
90
|
+
/* @__PURE__ */ jsxRuntime.jsxs("label", { children: [
|
|
91
|
+
"Type",
|
|
92
|
+
" ",
|
|
93
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
94
|
+
"select",
|
|
95
|
+
{
|
|
96
|
+
value: type,
|
|
97
|
+
onChange: (event) => {
|
|
98
|
+
const next = event.target.value;
|
|
99
|
+
if (next === "token") onChange({ type: "token", token: "" });
|
|
100
|
+
else if (next === "geo")
|
|
101
|
+
onChange({ type: "geo", latitude: 0, longitude: 0, radiusMeters: 100 });
|
|
102
|
+
else onChange({ type: "instant" });
|
|
103
|
+
},
|
|
104
|
+
children: [
|
|
105
|
+
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "instant", children: "Instant" }),
|
|
106
|
+
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "token", children: "QR / passcode" }),
|
|
107
|
+
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "geo", children: "GPS" })
|
|
108
|
+
]
|
|
109
|
+
}
|
|
110
|
+
)
|
|
111
|
+
] }),
|
|
112
|
+
condition.type === "token" && /* @__PURE__ */ jsxRuntime.jsxs("label", { children: [
|
|
113
|
+
"Token",
|
|
114
|
+
" ",
|
|
115
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
116
|
+
"input",
|
|
117
|
+
{
|
|
118
|
+
value: condition.token,
|
|
119
|
+
onChange: (event) => onChange({ ...condition, token: event.target.value })
|
|
120
|
+
}
|
|
121
|
+
)
|
|
122
|
+
] }),
|
|
123
|
+
condition.type === "geo" && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
124
|
+
/* @__PURE__ */ jsxRuntime.jsxs("label", { children: [
|
|
125
|
+
"Latitude",
|
|
126
|
+
" ",
|
|
127
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
128
|
+
"input",
|
|
129
|
+
{
|
|
130
|
+
type: "number",
|
|
131
|
+
min: -90,
|
|
132
|
+
max: 90,
|
|
133
|
+
value: condition.latitude,
|
|
134
|
+
onChange: (event) => onChange({ ...condition, latitude: Number(event.target.value) })
|
|
135
|
+
}
|
|
136
|
+
)
|
|
137
|
+
] }),
|
|
138
|
+
/* @__PURE__ */ jsxRuntime.jsxs("label", { children: [
|
|
139
|
+
"Longitude",
|
|
140
|
+
" ",
|
|
141
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
142
|
+
"input",
|
|
143
|
+
{
|
|
144
|
+
type: "number",
|
|
145
|
+
min: -180,
|
|
146
|
+
max: 180,
|
|
147
|
+
value: condition.longitude,
|
|
148
|
+
onChange: (event) => onChange({ ...condition, longitude: Number(event.target.value) })
|
|
149
|
+
}
|
|
150
|
+
)
|
|
151
|
+
] }),
|
|
152
|
+
/* @__PURE__ */ jsxRuntime.jsxs("label", { children: [
|
|
153
|
+
"Radius (m)",
|
|
154
|
+
" ",
|
|
155
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
156
|
+
"input",
|
|
157
|
+
{
|
|
158
|
+
type: "number",
|
|
159
|
+
min: 1,
|
|
160
|
+
value: condition.radiusMeters,
|
|
161
|
+
onChange: (event) => onChange({ ...condition, radiusMeters: Number(event.target.value) })
|
|
162
|
+
}
|
|
163
|
+
)
|
|
164
|
+
] })
|
|
165
|
+
] })
|
|
166
|
+
] });
|
|
167
|
+
}
|
|
168
|
+
function SpotItemForm({
|
|
169
|
+
spot,
|
|
170
|
+
index = 0,
|
|
171
|
+
locale = "ja",
|
|
172
|
+
onChange,
|
|
173
|
+
onDelete
|
|
174
|
+
}) {
|
|
175
|
+
const pair = localePair(spot.name);
|
|
176
|
+
const setField = (field, event) => {
|
|
177
|
+
if (event.target.value === "") {
|
|
178
|
+
const { [field]: _removed, ...rest } = spot;
|
|
179
|
+
onChange(rest);
|
|
180
|
+
} else onChange({ ...spot, [field]: event.target.value });
|
|
181
|
+
};
|
|
182
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("article", { className: "stamprally-admin-card", children: [
|
|
183
|
+
/* @__PURE__ */ jsxRuntime.jsxs("header", { children: [
|
|
184
|
+
/* @__PURE__ */ jsxRuntime.jsxs("strong", { children: [
|
|
185
|
+
"Spot ",
|
|
186
|
+
index + 1
|
|
187
|
+
] }),
|
|
188
|
+
onDelete !== void 0 && /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", onClick: onDelete, children: "Delete" })
|
|
189
|
+
] }),
|
|
190
|
+
/* @__PURE__ */ jsxRuntime.jsxs("label", { children: [
|
|
191
|
+
"ID",
|
|
192
|
+
" ",
|
|
193
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
194
|
+
"input",
|
|
195
|
+
{
|
|
196
|
+
value: spot.id,
|
|
197
|
+
onChange: (event) => onChange({ ...spot, id: event.target.value })
|
|
198
|
+
}
|
|
199
|
+
)
|
|
200
|
+
] }),
|
|
201
|
+
/* @__PURE__ */ jsxRuntime.jsxs("label", { children: [
|
|
202
|
+
"Name (",
|
|
203
|
+
locale,
|
|
204
|
+
")",
|
|
205
|
+
" ",
|
|
206
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
207
|
+
"input",
|
|
208
|
+
{
|
|
209
|
+
value: pair[locale],
|
|
210
|
+
required: true,
|
|
211
|
+
onChange: (event) => onChange({ ...spot, name: updateText(spot.name, locale, event.target.value) })
|
|
212
|
+
}
|
|
213
|
+
)
|
|
214
|
+
] }),
|
|
215
|
+
/* @__PURE__ */ jsxRuntime.jsxs("label", { children: [
|
|
216
|
+
"Icon URL",
|
|
217
|
+
" ",
|
|
218
|
+
/* @__PURE__ */ jsxRuntime.jsx("input", { value: spot.iconUrl ?? "", onChange: (event) => setField("iconUrl", event) })
|
|
219
|
+
] }),
|
|
220
|
+
/* @__PURE__ */ jsxRuntime.jsxs("label", { children: [
|
|
221
|
+
"Image URL",
|
|
222
|
+
" ",
|
|
223
|
+
/* @__PURE__ */ jsxRuntime.jsx("input", { value: spot.imageUrl ?? "", onChange: (event) => setField("imageUrl", event) })
|
|
224
|
+
] }),
|
|
225
|
+
/* @__PURE__ */ jsxRuntime.jsxs("label", { children: [
|
|
226
|
+
"External URL",
|
|
227
|
+
" ",
|
|
228
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
229
|
+
"input",
|
|
230
|
+
{
|
|
231
|
+
value: spot.externalUrl ?? "",
|
|
232
|
+
onChange: (event) => setField("externalUrl", event)
|
|
233
|
+
}
|
|
234
|
+
)
|
|
235
|
+
] }),
|
|
236
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
237
|
+
ConditionEditor,
|
|
238
|
+
{
|
|
239
|
+
condition: spot.condition,
|
|
240
|
+
onChange: (condition) => onChange({ ...spot, condition }),
|
|
241
|
+
locale
|
|
242
|
+
}
|
|
243
|
+
)
|
|
244
|
+
] });
|
|
245
|
+
}
|
|
246
|
+
function SpotListEditor({ spots, locale = "ja", onChange }) {
|
|
247
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("section", { "aria-label": "Spots", children: [
|
|
248
|
+
/* @__PURE__ */ jsxRuntime.jsx("h2", { children: "Spots" }),
|
|
249
|
+
spots.map((spot, index) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
250
|
+
SpotItemForm,
|
|
251
|
+
{
|
|
252
|
+
spot,
|
|
253
|
+
index,
|
|
254
|
+
locale,
|
|
255
|
+
onChange: (next) => onChange(spots.map((item, itemIndex) => itemIndex === index ? next : item)),
|
|
256
|
+
onDelete: () => onChange(spots.filter((_, itemIndex) => itemIndex !== index))
|
|
257
|
+
},
|
|
258
|
+
spot.id
|
|
259
|
+
))
|
|
260
|
+
] });
|
|
261
|
+
}
|
|
262
|
+
function RewardListEditor({ rewards, locale = "ja", onChange }) {
|
|
263
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("section", { "aria-label": "Rewards", children: [
|
|
264
|
+
/* @__PURE__ */ jsxRuntime.jsx("h2", { children: "Rewards" }),
|
|
265
|
+
rewards.map((reward, index) => /* @__PURE__ */ jsxRuntime.jsxs("article", { className: "stamprally-admin-card", children: [
|
|
266
|
+
/* @__PURE__ */ jsxRuntime.jsxs("label", { children: [
|
|
267
|
+
"ID",
|
|
268
|
+
" ",
|
|
269
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
270
|
+
"input",
|
|
271
|
+
{
|
|
272
|
+
value: reward.id,
|
|
273
|
+
onChange: (event) => onChange(
|
|
274
|
+
rewards.map(
|
|
275
|
+
(item, itemIndex) => itemIndex === index ? { ...item, id: event.target.value } : item
|
|
276
|
+
)
|
|
277
|
+
)
|
|
278
|
+
}
|
|
279
|
+
)
|
|
280
|
+
] }),
|
|
281
|
+
/* @__PURE__ */ jsxRuntime.jsxs("label", { children: [
|
|
282
|
+
"Title (",
|
|
283
|
+
locale,
|
|
284
|
+
")",
|
|
285
|
+
" ",
|
|
286
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
287
|
+
"input",
|
|
288
|
+
{
|
|
289
|
+
value: core.resolveLocalizedText(reward.title, locale),
|
|
290
|
+
onChange: (event) => onChange(
|
|
291
|
+
rewards.map(
|
|
292
|
+
(item, itemIndex) => itemIndex === index ? { ...item, title: updateText(item.title, locale, event.target.value) } : item
|
|
293
|
+
)
|
|
294
|
+
)
|
|
295
|
+
}
|
|
296
|
+
)
|
|
297
|
+
] }),
|
|
298
|
+
/* @__PURE__ */ jsxRuntime.jsxs("label", { children: [
|
|
299
|
+
"Required stamps",
|
|
300
|
+
" ",
|
|
301
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
302
|
+
"input",
|
|
303
|
+
{
|
|
304
|
+
type: "number",
|
|
305
|
+
min: 0,
|
|
306
|
+
value: reward.requiredStampCount,
|
|
307
|
+
onChange: (event) => onChange(
|
|
308
|
+
rewards.map(
|
|
309
|
+
(item, itemIndex) => itemIndex === index ? { ...item, requiredStampCount: Number(event.target.value) } : item
|
|
310
|
+
)
|
|
311
|
+
)
|
|
312
|
+
}
|
|
313
|
+
)
|
|
314
|
+
] }),
|
|
315
|
+
/* @__PURE__ */ jsxRuntime.jsxs("label", { children: [
|
|
316
|
+
"Valid until",
|
|
317
|
+
" ",
|
|
318
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
319
|
+
"input",
|
|
320
|
+
{
|
|
321
|
+
type: "datetime-local",
|
|
322
|
+
value: reward.validUntil?.slice(0, 16) ?? "",
|
|
323
|
+
onChange: (event) => onChange(
|
|
324
|
+
rewards.map((item, itemIndex) => {
|
|
325
|
+
if (itemIndex !== index) return item;
|
|
326
|
+
if (event.target.value === "") {
|
|
327
|
+
const { validUntil: _validUntil, ...rest } = item;
|
|
328
|
+
return rest;
|
|
329
|
+
}
|
|
330
|
+
return { ...item, validUntil: new Date(event.target.value).toISOString() };
|
|
331
|
+
})
|
|
332
|
+
)
|
|
333
|
+
}
|
|
334
|
+
)
|
|
335
|
+
] })
|
|
336
|
+
] }, reward.id))
|
|
337
|
+
] });
|
|
338
|
+
}
|
|
339
|
+
function ThemePresetSelector({ value, locale = "ja", onChange }) {
|
|
340
|
+
const selected = core.THEME_PRESETS.find((preset) => JSON.stringify(preset.theme) === JSON.stringify(value))?.id ?? "custom";
|
|
341
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("label", { children: [
|
|
342
|
+
"Theme preset",
|
|
343
|
+
" ",
|
|
344
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
345
|
+
"select",
|
|
346
|
+
{
|
|
347
|
+
value: selected,
|
|
348
|
+
onChange: (event) => {
|
|
349
|
+
const preset = core.THEME_PRESETS.find((item) => item.id === event.target.value);
|
|
350
|
+
if (preset !== void 0) onChange(preset.theme);
|
|
351
|
+
},
|
|
352
|
+
children: [
|
|
353
|
+
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "custom", children: "Custom" }),
|
|
354
|
+
core.THEME_PRESETS.map((preset) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: preset.id, children: core.resolveLocalizedText(preset.name, locale) }, preset.id))
|
|
355
|
+
]
|
|
356
|
+
}
|
|
357
|
+
)
|
|
358
|
+
] });
|
|
359
|
+
}
|
|
360
|
+
function ThemeEditor({
|
|
361
|
+
theme = core.DEFAULT_SHEET_THEME,
|
|
362
|
+
locale = "ja",
|
|
363
|
+
onChange
|
|
364
|
+
}) {
|
|
365
|
+
const update = (field, value) => onChange({ ...theme, [field]: value });
|
|
366
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("fieldset", { className: "stamprally-admin-card", children: [
|
|
367
|
+
/* @__PURE__ */ jsxRuntime.jsx("legend", { children: "Theme" }),
|
|
368
|
+
/* @__PURE__ */ jsxRuntime.jsx(ThemePresetSelector, { value: theme, locale, onChange }),
|
|
369
|
+
/* @__PURE__ */ jsxRuntime.jsxs("label", { children: [
|
|
370
|
+
"Primary color",
|
|
371
|
+
" ",
|
|
372
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
373
|
+
"input",
|
|
374
|
+
{
|
|
375
|
+
type: "color",
|
|
376
|
+
value: theme.primaryColor,
|
|
377
|
+
onChange: (event) => update("primaryColor", event.target.value)
|
|
378
|
+
}
|
|
379
|
+
)
|
|
380
|
+
] }),
|
|
381
|
+
/* @__PURE__ */ jsxRuntime.jsxs("label", { children: [
|
|
382
|
+
"Grid columns",
|
|
383
|
+
" ",
|
|
384
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
385
|
+
"input",
|
|
386
|
+
{
|
|
387
|
+
type: "number",
|
|
388
|
+
min: 1,
|
|
389
|
+
max: 6,
|
|
390
|
+
value: theme.gridColumns,
|
|
391
|
+
onChange: (event) => update("gridColumns", Number(event.target.value))
|
|
392
|
+
}
|
|
393
|
+
)
|
|
394
|
+
] })
|
|
395
|
+
] });
|
|
396
|
+
}
|
|
397
|
+
function QrExportModal({ open, config, locale = "ja", onClose }) {
|
|
398
|
+
if (!open) return null;
|
|
399
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { role: "dialog", "aria-modal": "true", className: "stamprally-qr-modal", children: [
|
|
400
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "stamprally-qr-modal__toolbar", children: [
|
|
401
|
+
/* @__PURE__ */ jsxRuntime.jsx("h2", { children: "QR print kit" }),
|
|
402
|
+
/* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", onClick: () => window.print(), children: "Print" }),
|
|
403
|
+
/* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", onClick: onClose, children: "Close" })
|
|
404
|
+
] }),
|
|
405
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "stamprally-qr-modal__grid", children: config.stamps.map((spot) => /* @__PURE__ */ jsxRuntime.jsxs("article", { children: [
|
|
406
|
+
/* @__PURE__ */ jsxRuntime.jsx("h3", { children: core.resolveLocalizedText(spot.name, locale) }),
|
|
407
|
+
/* @__PURE__ */ jsxRuntime.jsx("pre", { children: JSON.stringify({
|
|
408
|
+
version: core.CURRENT_RALLY_CONFIG_VERSION,
|
|
409
|
+
rallyId: config.id,
|
|
410
|
+
stampId: spot.id
|
|
411
|
+
}) })
|
|
412
|
+
] }, spot.id)) })
|
|
413
|
+
] });
|
|
414
|
+
}
|
|
415
|
+
function JsonConfigIO({ config, onImport }) {
|
|
416
|
+
const [value, setValue] = react.useState(() => JSON.stringify(core.stripSensitiveConfig(config), null, 2));
|
|
417
|
+
const [error, setError] = react.useState(null);
|
|
418
|
+
const importConfig = () => {
|
|
419
|
+
try {
|
|
420
|
+
const migrated = core.migrateRallyConfig(JSON.parse(value));
|
|
421
|
+
const validation = core.validateRallyConfig(migrated);
|
|
422
|
+
if (!validation.valid) {
|
|
423
|
+
setError(validation.errors.map((item) => `${item.path}: ${item.message}`).join(" "));
|
|
424
|
+
return;
|
|
425
|
+
}
|
|
426
|
+
onImport(migrated);
|
|
427
|
+
setError(null);
|
|
428
|
+
} catch {
|
|
429
|
+
setError("Invalid rally JSON.");
|
|
430
|
+
}
|
|
431
|
+
};
|
|
432
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("section", { className: "stamprally-admin-card", "aria-label": "JSON configuration", children: [
|
|
433
|
+
/* @__PURE__ */ jsxRuntime.jsx("textarea", { value, onChange: (event) => setValue(event.target.value) }),
|
|
434
|
+
/* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", onClick: importConfig, children: "Import and migrate" }),
|
|
435
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
436
|
+
"button",
|
|
437
|
+
{
|
|
438
|
+
type: "button",
|
|
439
|
+
onClick: () => navigator.clipboard?.writeText(JSON.stringify(core.stripSensitiveConfig(config), null, 2)),
|
|
440
|
+
children: "Copy public JSON"
|
|
441
|
+
}
|
|
442
|
+
),
|
|
443
|
+
error !== null && /* @__PURE__ */ jsxRuntime.jsx("p", { role: "alert", children: error })
|
|
444
|
+
] });
|
|
445
|
+
}
|
|
446
|
+
function RallyEditor({ config, locale = "ja", onChange }) {
|
|
447
|
+
const [showQr, setShowQr] = react.useState(false);
|
|
448
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("main", { className: "stamprally-admin", children: [
|
|
449
|
+
/* @__PURE__ */ jsxRuntime.jsxs("header", { children: [
|
|
450
|
+
/* @__PURE__ */ jsxRuntime.jsx("h1", { children: core.resolveLocalizedText(config.title, locale) || config.id }),
|
|
451
|
+
/* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", onClick: () => setShowQr(true), children: "QR export" })
|
|
452
|
+
] }),
|
|
453
|
+
/* @__PURE__ */ jsxRuntime.jsx(GeneralSettingsForm, { config, locale, onChange }),
|
|
454
|
+
config.theme === void 0 ? /* @__PURE__ */ jsxRuntime.jsx(ThemeEditor, { locale, onChange: (theme) => onChange({ ...config, theme }) }) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
455
|
+
ThemeEditor,
|
|
456
|
+
{
|
|
457
|
+
theme: config.theme,
|
|
458
|
+
locale,
|
|
459
|
+
onChange: (theme) => onChange({ ...config, theme })
|
|
460
|
+
}
|
|
461
|
+
),
|
|
462
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
463
|
+
SpotListEditor,
|
|
464
|
+
{
|
|
465
|
+
spots: config.stamps,
|
|
466
|
+
locale,
|
|
467
|
+
onChange: (stamps) => onChange({ ...config, stamps })
|
|
468
|
+
}
|
|
469
|
+
),
|
|
470
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
471
|
+
RewardListEditor,
|
|
472
|
+
{
|
|
473
|
+
rewards: config.rewards ?? [],
|
|
474
|
+
locale,
|
|
475
|
+
onChange: (rewards) => onChange({ ...config, rewards })
|
|
476
|
+
}
|
|
477
|
+
),
|
|
478
|
+
/* @__PURE__ */ jsxRuntime.jsx(JsonConfigIO, { config, onImport: onChange }),
|
|
479
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
480
|
+
QrExportModal,
|
|
481
|
+
{
|
|
482
|
+
open: showQr,
|
|
483
|
+
config,
|
|
484
|
+
locale,
|
|
485
|
+
onClose: () => setShowQr(false)
|
|
486
|
+
}
|
|
487
|
+
)
|
|
488
|
+
] });
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
exports.ConditionEditor = ConditionEditor;
|
|
492
|
+
exports.GeneralSettingsForm = GeneralSettingsForm;
|
|
493
|
+
exports.JsonConfigIO = JsonConfigIO;
|
|
494
|
+
exports.QrExportModal = QrExportModal;
|
|
495
|
+
exports.RallyEditor = RallyEditor;
|
|
496
|
+
exports.RewardListEditor = RewardListEditor;
|
|
497
|
+
exports.SpotItemForm = SpotItemForm;
|
|
498
|
+
exports.SpotListEditor = SpotListEditor;
|
|
499
|
+
exports.ThemeEditor = ThemeEditor;
|
|
500
|
+
exports.ThemePresetSelector = ThemePresetSelector;
|
|
501
|
+
//# sourceMappingURL=index.cjs.map
|
|
502
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.tsx"],"names":["resolveLocalizedText","jsxs","jsx","Fragment","THEME_PRESETS","DEFAULT_SHEET_THEME","CURRENT_RALLY_CONFIG_VERSION","useState","stripSensitiveConfig","migrateRallyConfig","validateRallyConfig"],"mappings":"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","file":"index.cjs","sourcesContent":["import {\n CURRENT_RALLY_CONFIG_VERSION,\n DEFAULT_SHEET_THEME,\n type LocalizedText,\n migrateRallyConfig,\n type RallyConfig,\n type RewardItem,\n resolveLocalizedText,\n type SheetTheme,\n type SpotItem,\n type StampCondition,\n type SupportedLocale,\n stripSensitiveConfig,\n THEME_PRESETS,\n validateRallyConfig,\n} from \"@stamprally/core\";\nimport type { ChangeEvent } from \"react\";\nimport { useState } from \"react\";\n\nconst localePair = (value: LocalizedText | undefined): { ja: string; en: string } => ({\n ja: resolveLocalizedText(value, \"ja\"),\n en: resolveLocalizedText(value, \"en\"),\n});\n\nfunction updateText(\n value: LocalizedText | undefined,\n locale: \"ja\" | \"en\",\n next: string,\n): LocalizedText {\n const current = localePair(value);\n return { ...current, [locale]: next };\n}\n\nexport interface GeneralSettingsFormProps {\n readonly config: RallyConfig;\n readonly locale?: SupportedLocale;\n readonly onChange: (config: RallyConfig) => void;\n}\nexport function GeneralSettingsForm({ config, locale = \"ja\", onChange }: GeneralSettingsFormProps) {\n const pair = localePair(config.title);\n return (\n <fieldset className=\"stamprally-admin-card\">\n <legend>General settings</legend>\n <label>\n ID <input value={config.id} readOnly />\n </label>\n <label>\n Title ({locale}){\" \"}\n <input\n value={pair[locale]}\n required\n onChange={(event) =>\n onChange({ ...config, title: updateText(config.title, locale, event.target.value) })\n }\n />\n </label>\n <label>\n Start date{\" \"}\n <input\n type=\"datetime-local\"\n value={config.startDate?.slice(0, 16) ?? \"\"}\n onChange={(event) => {\n if (event.target.value === \"\") {\n const { startDate: _startDate, ...rest } = config;\n onChange(rest);\n } else onChange({ ...config, startDate: new Date(event.target.value).toISOString() });\n }}\n />\n </label>\n <label>\n End date{\" \"}\n <input\n type=\"datetime-local\"\n value={config.endDate?.slice(0, 16) ?? \"\"}\n onChange={(event) => {\n if (event.target.value === \"\") {\n const { endDate: _endDate, ...rest } = config;\n onChange(rest);\n } else onChange({ ...config, endDate: new Date(event.target.value).toISOString() });\n }}\n />\n </label>\n <label>\n <input\n type=\"checkbox\"\n checked={config.isSequential === true}\n onChange={(event) => onChange({ ...config, isSequential: event.target.checked })}\n />{\" \"}\n Sequential check-in\n </label>\n </fieldset>\n );\n}\n\nexport interface ConditionEditorProps {\n readonly condition: StampCondition;\n readonly onChange: (condition: StampCondition) => void;\n readonly locale?: SupportedLocale;\n}\nexport function ConditionEditor({ condition, onChange }: ConditionEditorProps) {\n const type = condition.type;\n return (\n <fieldset className=\"stamprally-admin-card\">\n <legend>Check-in condition</legend>\n <label>\n Type{\" \"}\n <select\n value={type}\n onChange={(event) => {\n const next = event.target.value;\n if (next === \"token\") onChange({ type: \"token\", token: \"\" });\n else if (next === \"geo\")\n onChange({ type: \"geo\", latitude: 0, longitude: 0, radiusMeters: 100 });\n else onChange({ type: \"instant\" });\n }}\n >\n <option value=\"instant\">Instant</option>\n <option value=\"token\">QR / passcode</option>\n <option value=\"geo\">GPS</option>\n </select>\n </label>\n {condition.type === \"token\" && (\n <label>\n Token{\" \"}\n <input\n value={condition.token}\n onChange={(event) => onChange({ ...condition, token: event.target.value })}\n />\n </label>\n )}\n {condition.type === \"geo\" && (\n <>\n <label>\n Latitude{\" \"}\n <input\n type=\"number\"\n min={-90}\n max={90}\n value={condition.latitude}\n onChange={(event) => onChange({ ...condition, latitude: Number(event.target.value) })}\n />\n </label>\n <label>\n Longitude{\" \"}\n <input\n type=\"number\"\n min={-180}\n max={180}\n value={condition.longitude}\n onChange={(event) =>\n onChange({ ...condition, longitude: Number(event.target.value) })\n }\n />\n </label>\n <label>\n Radius (m){\" \"}\n <input\n type=\"number\"\n min={1}\n value={condition.radiusMeters}\n onChange={(event) =>\n onChange({ ...condition, radiusMeters: Number(event.target.value) })\n }\n />\n </label>\n </>\n )}\n </fieldset>\n );\n}\n\nexport interface SpotItemFormProps {\n readonly spot: SpotItem;\n readonly index?: number;\n readonly locale?: SupportedLocale;\n readonly onChange: (spot: SpotItem) => void;\n readonly onDelete?: () => void;\n}\nexport function SpotItemForm({\n spot,\n index = 0,\n locale = \"ja\",\n onChange,\n onDelete,\n}: SpotItemFormProps) {\n const pair = localePair(spot.name);\n const setField = (\n field: \"iconUrl\" | \"imageUrl\" | \"externalUrl\" | \"guideId\" | \"groupId\" | \"deckId\",\n event: ChangeEvent<HTMLInputElement>,\n ) => {\n if (event.target.value === \"\") {\n const { [field]: _removed, ...rest } = spot;\n onChange(rest);\n } else onChange({ ...spot, [field]: event.target.value });\n };\n return (\n <article className=\"stamprally-admin-card\">\n <header>\n <strong>Spot {index + 1}</strong>\n {onDelete !== undefined && (\n <button type=\"button\" onClick={onDelete}>\n Delete\n </button>\n )}\n </header>\n <label>\n ID{\" \"}\n <input\n value={spot.id}\n onChange={(event) => onChange({ ...spot, id: event.target.value })}\n />\n </label>\n <label>\n Name ({locale}){\" \"}\n <input\n value={pair[locale]}\n required\n onChange={(event) =>\n onChange({ ...spot, name: updateText(spot.name, locale, event.target.value) })\n }\n />\n </label>\n <label>\n Icon URL{\" \"}\n <input value={spot.iconUrl ?? \"\"} onChange={(event) => setField(\"iconUrl\", event)} />\n </label>\n <label>\n Image URL{\" \"}\n <input value={spot.imageUrl ?? \"\"} onChange={(event) => setField(\"imageUrl\", event)} />\n </label>\n <label>\n External URL{\" \"}\n <input\n value={spot.externalUrl ?? \"\"}\n onChange={(event) => setField(\"externalUrl\", event)}\n />\n </label>\n <ConditionEditor\n condition={spot.condition}\n onChange={(condition) => onChange({ ...spot, condition })}\n locale={locale}\n />\n </article>\n );\n}\n\nexport interface SpotListEditorProps {\n readonly spots: ReadonlyArray<SpotItem>;\n readonly locale?: SupportedLocale;\n readonly onChange: (spots: ReadonlyArray<SpotItem>) => void;\n}\nexport function SpotListEditor({ spots, locale = \"ja\", onChange }: SpotListEditorProps) {\n return (\n <section aria-label=\"Spots\">\n <h2>Spots</h2>\n {spots.map((spot, index) => (\n <SpotItemForm\n key={spot.id}\n spot={spot}\n index={index}\n locale={locale}\n onChange={(next) =>\n onChange(spots.map((item, itemIndex) => (itemIndex === index ? next : item)))\n }\n onDelete={() => onChange(spots.filter((_, itemIndex) => itemIndex !== index))}\n />\n ))}\n </section>\n );\n}\n\nexport interface RewardListEditorProps {\n readonly rewards: ReadonlyArray<RewardItem>;\n readonly locale?: SupportedLocale;\n readonly onChange: (rewards: ReadonlyArray<RewardItem>) => void;\n}\nexport function RewardListEditor({ rewards, locale = \"ja\", onChange }: RewardListEditorProps) {\n return (\n <section aria-label=\"Rewards\">\n <h2>Rewards</h2>\n {rewards.map((reward, index) => (\n <article className=\"stamprally-admin-card\" key={reward.id}>\n <label>\n ID{\" \"}\n <input\n value={reward.id}\n onChange={(event) =>\n onChange(\n rewards.map((item, itemIndex) =>\n itemIndex === index ? { ...item, id: event.target.value } : item,\n ),\n )\n }\n />\n </label>\n <label>\n Title ({locale}){\" \"}\n <input\n value={resolveLocalizedText(reward.title, locale)}\n onChange={(event) =>\n onChange(\n rewards.map((item, itemIndex) =>\n itemIndex === index\n ? { ...item, title: updateText(item.title, locale, event.target.value) }\n : item,\n ),\n )\n }\n />\n </label>\n <label>\n Required stamps{\" \"}\n <input\n type=\"number\"\n min={0}\n value={reward.requiredStampCount}\n onChange={(event) =>\n onChange(\n rewards.map((item, itemIndex) =>\n itemIndex === index\n ? { ...item, requiredStampCount: Number(event.target.value) }\n : item,\n ),\n )\n }\n />\n </label>\n <label>\n Valid until{\" \"}\n <input\n type=\"datetime-local\"\n value={reward.validUntil?.slice(0, 16) ?? \"\"}\n onChange={(event) =>\n onChange(\n rewards.map((item, itemIndex) => {\n if (itemIndex !== index) return item;\n if (event.target.value === \"\") {\n const { validUntil: _validUntil, ...rest } = item;\n return rest;\n }\n return { ...item, validUntil: new Date(event.target.value).toISOString() };\n }),\n )\n }\n />\n </label>\n </article>\n ))}\n </section>\n );\n}\n\nexport interface ThemePresetSelectorProps {\n readonly value?: SheetTheme;\n readonly locale?: SupportedLocale;\n readonly onChange: (theme: SheetTheme) => void;\n}\nexport function ThemePresetSelector({ value, locale = \"ja\", onChange }: ThemePresetSelectorProps) {\n const selected =\n THEME_PRESETS.find((preset) => JSON.stringify(preset.theme) === JSON.stringify(value))?.id ??\n \"custom\";\n return (\n <label>\n Theme preset{\" \"}\n <select\n value={selected}\n onChange={(event) => {\n const preset = THEME_PRESETS.find((item) => item.id === event.target.value);\n if (preset !== undefined) onChange(preset.theme);\n }}\n >\n <option value=\"custom\">Custom</option>\n {THEME_PRESETS.map((preset) => (\n <option key={preset.id} value={preset.id}>\n {resolveLocalizedText(preset.name, locale)}\n </option>\n ))}\n </select>\n </label>\n );\n}\n\nexport interface ThemeEditorProps {\n readonly theme?: SheetTheme;\n readonly locale?: SupportedLocale;\n readonly onChange: (theme: SheetTheme) => void;\n}\nexport function ThemeEditor({\n theme = DEFAULT_SHEET_THEME,\n locale = \"ja\",\n onChange,\n}: ThemeEditorProps) {\n const update = (field: keyof SheetTheme, value: string | number) =>\n onChange({ ...theme, [field]: value });\n return (\n <fieldset className=\"stamprally-admin-card\">\n <legend>Theme</legend>\n <ThemePresetSelector value={theme} locale={locale} onChange={onChange} />\n <label>\n Primary color{\" \"}\n <input\n type=\"color\"\n value={theme.primaryColor}\n onChange={(event) => update(\"primaryColor\", event.target.value)}\n />\n </label>\n <label>\n Grid columns{\" \"}\n <input\n type=\"number\"\n min={1}\n max={6}\n value={theme.gridColumns}\n onChange={(event) => update(\"gridColumns\", Number(event.target.value))}\n />\n </label>\n </fieldset>\n );\n}\n\nexport interface QrExportModalProps {\n readonly open: boolean;\n readonly config: RallyConfig;\n readonly locale?: SupportedLocale;\n readonly onClose: () => void;\n}\nexport function QrExportModal({ open, config, locale = \"ja\", onClose }: QrExportModalProps) {\n if (!open) return null;\n return (\n <div role=\"dialog\" aria-modal=\"true\" className=\"stamprally-qr-modal\">\n <div className=\"stamprally-qr-modal__toolbar\">\n <h2>QR print kit</h2>\n <button type=\"button\" onClick={() => window.print()}>\n Print\n </button>\n <button type=\"button\" onClick={onClose}>\n Close\n </button>\n </div>\n <div className=\"stamprally-qr-modal__grid\">\n {config.stamps.map((spot) => (\n <article key={spot.id}>\n <h3>{resolveLocalizedText(spot.name, locale)}</h3>\n <pre>\n {JSON.stringify({\n version: CURRENT_RALLY_CONFIG_VERSION,\n rallyId: config.id,\n stampId: spot.id,\n })}\n </pre>\n </article>\n ))}\n </div>\n </div>\n );\n}\n\nexport interface JsonConfigIOProps {\n readonly config: RallyConfig;\n readonly onImport: (config: RallyConfig) => void;\n readonly locale?: SupportedLocale;\n}\nexport function JsonConfigIO({ config, onImport }: JsonConfigIOProps) {\n const [value, setValue] = useState(() => JSON.stringify(stripSensitiveConfig(config), null, 2));\n const [error, setError] = useState<string | null>(null);\n const importConfig = (): void => {\n try {\n const migrated = migrateRallyConfig(JSON.parse(value) as unknown);\n const validation = validateRallyConfig(migrated);\n if (!validation.valid) {\n setError(validation.errors.map((item) => `${item.path}: ${item.message}`).join(\" \"));\n return;\n }\n onImport(migrated);\n setError(null);\n } catch {\n setError(\"Invalid rally JSON.\");\n }\n };\n return (\n <section className=\"stamprally-admin-card\" aria-label=\"JSON configuration\">\n <textarea value={value} onChange={(event) => setValue(event.target.value)} />\n <button type=\"button\" onClick={importConfig}>\n Import and migrate\n </button>\n <button\n type=\"button\"\n onClick={() =>\n navigator.clipboard?.writeText(JSON.stringify(stripSensitiveConfig(config), null, 2))\n }\n >\n Copy public JSON\n </button>\n {error !== null && <p role=\"alert\">{error}</p>}\n </section>\n );\n}\n\nexport interface RallyEditorProps {\n readonly config: RallyConfig;\n readonly locale?: SupportedLocale;\n readonly onChange: (config: RallyConfig) => void;\n}\nexport function RallyEditor({ config, locale = \"ja\", onChange }: RallyEditorProps) {\n const [showQr, setShowQr] = useState(false);\n return (\n <main className=\"stamprally-admin\">\n <header>\n <h1>{resolveLocalizedText(config.title, locale) || config.id}</h1>\n <button type=\"button\" onClick={() => setShowQr(true)}>\n QR export\n </button>\n </header>\n <GeneralSettingsForm config={config} locale={locale} onChange={onChange} />\n {config.theme === undefined ? (\n <ThemeEditor locale={locale} onChange={(theme) => onChange({ ...config, theme })} />\n ) : (\n <ThemeEditor\n theme={config.theme}\n locale={locale}\n onChange={(theme) => onChange({ ...config, theme })}\n />\n )}\n <SpotListEditor\n spots={config.stamps}\n locale={locale}\n onChange={(stamps) => onChange({ ...config, stamps })}\n />\n <RewardListEditor\n rewards={config.rewards ?? []}\n locale={locale}\n onChange={(rewards) => onChange({ ...config, rewards })}\n />\n <JsonConfigIO config={config} onImport={onChange} />\n <QrExportModal\n open={showQr}\n config={config}\n locale={locale}\n onClose={() => setShowQr(false)}\n />\n </main>\n );\n}\n"]}
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import * as react from 'react';
|
|
2
|
+
import { StampCondition, SupportedLocale, RallyConfig, RewardItem, SpotItem, SheetTheme } from '@stamprally/core';
|
|
3
|
+
|
|
4
|
+
interface GeneralSettingsFormProps {
|
|
5
|
+
readonly config: RallyConfig;
|
|
6
|
+
readonly locale?: SupportedLocale;
|
|
7
|
+
readonly onChange: (config: RallyConfig) => void;
|
|
8
|
+
}
|
|
9
|
+
declare function GeneralSettingsForm({ config, locale, onChange }: GeneralSettingsFormProps): react.JSX.Element;
|
|
10
|
+
interface ConditionEditorProps {
|
|
11
|
+
readonly condition: StampCondition;
|
|
12
|
+
readonly onChange: (condition: StampCondition) => void;
|
|
13
|
+
readonly locale?: SupportedLocale;
|
|
14
|
+
}
|
|
15
|
+
declare function ConditionEditor({ condition, onChange }: ConditionEditorProps): react.JSX.Element;
|
|
16
|
+
interface SpotItemFormProps {
|
|
17
|
+
readonly spot: SpotItem;
|
|
18
|
+
readonly index?: number;
|
|
19
|
+
readonly locale?: SupportedLocale;
|
|
20
|
+
readonly onChange: (spot: SpotItem) => void;
|
|
21
|
+
readonly onDelete?: () => void;
|
|
22
|
+
}
|
|
23
|
+
declare function SpotItemForm({ spot, index, locale, onChange, onDelete, }: SpotItemFormProps): react.JSX.Element;
|
|
24
|
+
interface SpotListEditorProps {
|
|
25
|
+
readonly spots: ReadonlyArray<SpotItem>;
|
|
26
|
+
readonly locale?: SupportedLocale;
|
|
27
|
+
readonly onChange: (spots: ReadonlyArray<SpotItem>) => void;
|
|
28
|
+
}
|
|
29
|
+
declare function SpotListEditor({ spots, locale, onChange }: SpotListEditorProps): react.JSX.Element;
|
|
30
|
+
interface RewardListEditorProps {
|
|
31
|
+
readonly rewards: ReadonlyArray<RewardItem>;
|
|
32
|
+
readonly locale?: SupportedLocale;
|
|
33
|
+
readonly onChange: (rewards: ReadonlyArray<RewardItem>) => void;
|
|
34
|
+
}
|
|
35
|
+
declare function RewardListEditor({ rewards, locale, onChange }: RewardListEditorProps): react.JSX.Element;
|
|
36
|
+
interface ThemePresetSelectorProps {
|
|
37
|
+
readonly value?: SheetTheme;
|
|
38
|
+
readonly locale?: SupportedLocale;
|
|
39
|
+
readonly onChange: (theme: SheetTheme) => void;
|
|
40
|
+
}
|
|
41
|
+
declare function ThemePresetSelector({ value, locale, onChange }: ThemePresetSelectorProps): react.JSX.Element;
|
|
42
|
+
interface ThemeEditorProps {
|
|
43
|
+
readonly theme?: SheetTheme;
|
|
44
|
+
readonly locale?: SupportedLocale;
|
|
45
|
+
readonly onChange: (theme: SheetTheme) => void;
|
|
46
|
+
}
|
|
47
|
+
declare function ThemeEditor({ theme, locale, onChange, }: ThemeEditorProps): react.JSX.Element;
|
|
48
|
+
interface QrExportModalProps {
|
|
49
|
+
readonly open: boolean;
|
|
50
|
+
readonly config: RallyConfig;
|
|
51
|
+
readonly locale?: SupportedLocale;
|
|
52
|
+
readonly onClose: () => void;
|
|
53
|
+
}
|
|
54
|
+
declare function QrExportModal({ open, config, locale, onClose }: QrExportModalProps): react.JSX.Element | null;
|
|
55
|
+
interface JsonConfigIOProps {
|
|
56
|
+
readonly config: RallyConfig;
|
|
57
|
+
readonly onImport: (config: RallyConfig) => void;
|
|
58
|
+
readonly locale?: SupportedLocale;
|
|
59
|
+
}
|
|
60
|
+
declare function JsonConfigIO({ config, onImport }: JsonConfigIOProps): react.JSX.Element;
|
|
61
|
+
interface RallyEditorProps {
|
|
62
|
+
readonly config: RallyConfig;
|
|
63
|
+
readonly locale?: SupportedLocale;
|
|
64
|
+
readonly onChange: (config: RallyConfig) => void;
|
|
65
|
+
}
|
|
66
|
+
declare function RallyEditor({ config, locale, onChange }: RallyEditorProps): react.JSX.Element;
|
|
67
|
+
|
|
68
|
+
export { ConditionEditor, type ConditionEditorProps, GeneralSettingsForm, type GeneralSettingsFormProps, JsonConfigIO, type JsonConfigIOProps, QrExportModal, type QrExportModalProps, RallyEditor, type RallyEditorProps, RewardListEditor, type RewardListEditorProps, SpotItemForm, type SpotItemFormProps, SpotListEditor, type SpotListEditorProps, ThemeEditor, type ThemeEditorProps, ThemePresetSelector, type ThemePresetSelectorProps };
|