@stamprally/admin-ui 0.6.0 → 0.8.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/index.cjs CHANGED
@@ -5,6 +5,751 @@ var react = require('react');
5
5
  var jsxRuntime = require('react/jsx-runtime');
6
6
 
7
7
  // src/index.tsx
8
+ function universalText(value, locale) {
9
+ return typeof value === "string" ? value : value?.[locale] ?? "";
10
+ }
11
+ function updateUniversalText(value, locale, next) {
12
+ return { ...typeof value === "string" ? {} : value, [locale]: next };
13
+ }
14
+ var newUniversalCondition = () => ({ type: "passcode", code: "" });
15
+ function defaultUniversalSpot(index) {
16
+ return {
17
+ id: `spot-${index + 1}`,
18
+ orderIndex: index,
19
+ name: { ja: `\u30B9\u30DD\u30C3\u30C8 ${index + 1}`, en: `Spot ${index + 1}` },
20
+ conditions: [newUniversalCondition()]
21
+ };
22
+ }
23
+ function defaultUniversalReward(index) {
24
+ return {
25
+ id: `reward-${index + 1}`,
26
+ title: { ja: `\u666F\u54C1 ${index + 1}`, en: `Reward ${index + 1}` },
27
+ type: "digital",
28
+ redemptionMethod: "manual_slide",
29
+ requiredStampCount: 1
30
+ };
31
+ }
32
+ function updateUniversalCondition(condition, field, value) {
33
+ if (condition.type === "gps") {
34
+ return { ...condition, [field]: Number(value) };
35
+ }
36
+ return { ...condition, [field]: value };
37
+ }
38
+ function UniversalSpotForm({
39
+ spot,
40
+ spots,
41
+ onChange,
42
+ onDelete,
43
+ onMoveUp,
44
+ onMoveDown
45
+ }) {
46
+ const update = (next) => onChange({ ...spot, ...next });
47
+ const references = spot.externalReferences ?? [];
48
+ const conditions = spot.conditions;
49
+ return /* @__PURE__ */ jsxRuntime.jsxs("fieldset", { className: "stamprally-admin-card", "aria-label": `Spot ${spot.id}`, children: [
50
+ /* @__PURE__ */ jsxRuntime.jsxs("legend", { children: [
51
+ "Spot ",
52
+ spot.orderIndex + 1
53
+ ] }),
54
+ /* @__PURE__ */ jsxRuntime.jsxs("label", { children: [
55
+ "ID ",
56
+ /* @__PURE__ */ jsxRuntime.jsx("input", { value: spot.id, onChange: (event) => update({ id: event.target.value }) })
57
+ ] }),
58
+ /* @__PURE__ */ jsxRuntime.jsxs("label", { children: [
59
+ "Name (ja)",
60
+ " ",
61
+ /* @__PURE__ */ jsxRuntime.jsx(
62
+ "input",
63
+ {
64
+ value: universalText(spot.name, "ja"),
65
+ onChange: (event) => update({ name: updateUniversalText(spot.name, "ja", event.target.value) })
66
+ }
67
+ )
68
+ ] }),
69
+ /* @__PURE__ */ jsxRuntime.jsxs("label", { children: [
70
+ "Name (en)",
71
+ " ",
72
+ /* @__PURE__ */ jsxRuntime.jsx(
73
+ "input",
74
+ {
75
+ value: universalText(spot.name, "en"),
76
+ onChange: (event) => update({ name: updateUniversalText(spot.name, "en", event.target.value) })
77
+ }
78
+ )
79
+ ] }),
80
+ /* @__PURE__ */ jsxRuntime.jsxs("label", { children: [
81
+ "Description (ja)",
82
+ " ",
83
+ /* @__PURE__ */ jsxRuntime.jsx(
84
+ "textarea",
85
+ {
86
+ value: universalText(spot.description, "ja"),
87
+ onChange: (event) => update({ description: updateUniversalText(spot.description, "ja", event.target.value) })
88
+ }
89
+ )
90
+ ] }),
91
+ /* @__PURE__ */ jsxRuntime.jsxs("label", { children: [
92
+ "Order index",
93
+ " ",
94
+ /* @__PURE__ */ jsxRuntime.jsx(
95
+ "input",
96
+ {
97
+ type: "number",
98
+ value: spot.orderIndex,
99
+ onChange: (event) => update({ orderIndex: Number(event.target.value) })
100
+ }
101
+ )
102
+ ] }),
103
+ /* @__PURE__ */ jsxRuntime.jsxs("label", { children: [
104
+ "Prerequisite spot",
105
+ /* @__PURE__ */ jsxRuntime.jsxs(
106
+ "select",
107
+ {
108
+ value: "",
109
+ onChange: (event) => {
110
+ if (event.target.value !== "")
111
+ update({ prerequisites: [...spot.prerequisites ?? [], event.target.value] });
112
+ },
113
+ children: [
114
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "", children: "Select a prerequisite" }),
115
+ spots.filter((item) => item.id !== spot.id && !spot.prerequisites?.includes(item.id)).map((item) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: item.id, children: item.id }, item.id))
116
+ ]
117
+ }
118
+ )
119
+ ] }),
120
+ (spot.prerequisites ?? []).map((id) => /* @__PURE__ */ jsxRuntime.jsxs(
121
+ "button",
122
+ {
123
+ type: "button",
124
+ onClick: () => update({ prerequisites: (spot.prerequisites ?? []).filter((item) => item !== id) }),
125
+ children: [
126
+ "Remove prerequisite: ",
127
+ id
128
+ ]
129
+ },
130
+ id
131
+ )),
132
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
133
+ /* @__PURE__ */ jsxRuntime.jsx("h4", { children: "External references" }),
134
+ references.map((reference, index) => /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
135
+ /* @__PURE__ */ jsxRuntime.jsxs("label", { children: [
136
+ "Reference type",
137
+ " ",
138
+ /* @__PURE__ */ jsxRuntime.jsx(
139
+ "input",
140
+ {
141
+ value: reference.type,
142
+ onChange: (event) => update({
143
+ externalReferences: references.map(
144
+ (item, itemIndex) => itemIndex === index ? { ...item, type: event.target.value } : item
145
+ )
146
+ })
147
+ }
148
+ )
149
+ ] }),
150
+ /* @__PURE__ */ jsxRuntime.jsxs("label", { children: [
151
+ "Reference ID",
152
+ " ",
153
+ /* @__PURE__ */ jsxRuntime.jsx(
154
+ "input",
155
+ {
156
+ value: reference.id,
157
+ onChange: (event) => update({
158
+ externalReferences: references.map(
159
+ (item, itemIndex) => itemIndex === index ? { ...item, id: event.target.value } : item
160
+ )
161
+ })
162
+ }
163
+ )
164
+ ] }),
165
+ /* @__PURE__ */ jsxRuntime.jsxs("label", { children: [
166
+ "Reference URL",
167
+ " ",
168
+ /* @__PURE__ */ jsxRuntime.jsx(
169
+ "input",
170
+ {
171
+ value: reference.url ?? "",
172
+ onChange: (event) => update({
173
+ externalReferences: references.map(
174
+ (item, itemIndex) => itemIndex === index ? { ...item, url: event.target.value } : item
175
+ )
176
+ })
177
+ }
178
+ )
179
+ ] }),
180
+ /* @__PURE__ */ jsxRuntime.jsxs("label", { children: [
181
+ "Reference metadata",
182
+ " ",
183
+ /* @__PURE__ */ jsxRuntime.jsx(
184
+ "textarea",
185
+ {
186
+ value: JSON.stringify(reference.metadata ?? {}, null, 2),
187
+ onChange: (event) => {
188
+ try {
189
+ const metadata = JSON.parse(event.target.value);
190
+ if (typeof metadata === "object" && metadata !== null && !Array.isArray(metadata))
191
+ update({
192
+ externalReferences: references.map(
193
+ (item, itemIndex) => itemIndex === index ? { ...item, metadata } : item
194
+ )
195
+ });
196
+ } catch {
197
+ }
198
+ }
199
+ }
200
+ )
201
+ ] }),
202
+ /* @__PURE__ */ jsxRuntime.jsx(
203
+ "button",
204
+ {
205
+ type: "button",
206
+ onClick: () => update({
207
+ externalReferences: references.filter((_, itemIndex) => itemIndex !== index)
208
+ }),
209
+ children: "Remove reference"
210
+ }
211
+ )
212
+ ] }, `${reference.type}:${reference.id}`)),
213
+ /* @__PURE__ */ jsxRuntime.jsx(
214
+ "button",
215
+ {
216
+ type: "button",
217
+ onClick: () => update({
218
+ externalReferences: [...references, { type: "", id: "" }]
219
+ }),
220
+ children: "Add external reference"
221
+ }
222
+ )
223
+ ] }),
224
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
225
+ /* @__PURE__ */ jsxRuntime.jsx("h4", { children: "Conditions" }),
226
+ conditions.map((condition, index) => /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
227
+ /* @__PURE__ */ jsxRuntime.jsxs("label", { children: [
228
+ "Condition type",
229
+ /* @__PURE__ */ jsxRuntime.jsxs(
230
+ "select",
231
+ {
232
+ value: condition.type,
233
+ onChange: (event) => {
234
+ const next = event.target.value === "qr" ? { type: "qr", secretToken: "" } : event.target.value === "gps" ? { type: "gps", latitude: 0, longitude: 0, radiusMeters: 100 } : event.target.value === "custom" ? { type: "custom", validatorName: "" } : { type: "passcode", code: "" };
235
+ onChange({
236
+ ...spot,
237
+ conditions: conditions.map(
238
+ (item, itemIndex) => itemIndex === index ? next : item
239
+ )
240
+ });
241
+ },
242
+ children: [
243
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "qr", children: "QR" }),
244
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "passcode", children: "Passcode" }),
245
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "gps", children: "GPS" }),
246
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "custom", children: "Custom" })
247
+ ]
248
+ }
249
+ )
250
+ ] }),
251
+ condition.type === "qr" && /* @__PURE__ */ jsxRuntime.jsxs("label", { children: [
252
+ "QR secret token",
253
+ " ",
254
+ /* @__PURE__ */ jsxRuntime.jsx(
255
+ "input",
256
+ {
257
+ value: condition.secretToken,
258
+ onChange: (event) => onChange({
259
+ ...spot,
260
+ conditions: conditions.map(
261
+ (item, itemIndex) => itemIndex === index ? updateUniversalCondition(item, "secretToken", event.target.value) : item
262
+ )
263
+ })
264
+ }
265
+ )
266
+ ] }),
267
+ condition.type === "passcode" && /* @__PURE__ */ jsxRuntime.jsxs("label", { children: [
268
+ "Passcode",
269
+ " ",
270
+ /* @__PURE__ */ jsxRuntime.jsx(
271
+ "input",
272
+ {
273
+ value: condition.code,
274
+ onChange: (event) => onChange({
275
+ ...spot,
276
+ conditions: conditions.map(
277
+ (item, itemIndex) => itemIndex === index ? updateUniversalCondition(item, "code", event.target.value) : item
278
+ )
279
+ })
280
+ }
281
+ )
282
+ ] }),
283
+ condition.type === "custom" && /* @__PURE__ */ jsxRuntime.jsxs("label", { children: [
284
+ "Validator name",
285
+ " ",
286
+ /* @__PURE__ */ jsxRuntime.jsx(
287
+ "input",
288
+ {
289
+ value: condition.validatorName,
290
+ onChange: (event) => onChange({
291
+ ...spot,
292
+ conditions: conditions.map(
293
+ (item, itemIndex) => itemIndex === index ? updateUniversalCondition(item, "validatorName", event.target.value) : item
294
+ )
295
+ })
296
+ }
297
+ )
298
+ ] }),
299
+ condition.type === "gps" && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
300
+ /* @__PURE__ */ jsxRuntime.jsxs("label", { children: [
301
+ "Latitude",
302
+ " ",
303
+ /* @__PURE__ */ jsxRuntime.jsx(
304
+ "input",
305
+ {
306
+ type: "number",
307
+ value: condition.latitude,
308
+ onChange: (event) => onChange({
309
+ ...spot,
310
+ conditions: conditions.map(
311
+ (item, itemIndex) => itemIndex === index ? updateUniversalCondition(item, "latitude", event.target.value) : item
312
+ )
313
+ })
314
+ }
315
+ )
316
+ ] }),
317
+ /* @__PURE__ */ jsxRuntime.jsxs("label", { children: [
318
+ "Longitude",
319
+ " ",
320
+ /* @__PURE__ */ jsxRuntime.jsx(
321
+ "input",
322
+ {
323
+ type: "number",
324
+ value: condition.longitude,
325
+ onChange: (event) => onChange({
326
+ ...spot,
327
+ conditions: conditions.map(
328
+ (item, itemIndex) => itemIndex === index ? updateUniversalCondition(item, "longitude", event.target.value) : item
329
+ )
330
+ })
331
+ }
332
+ )
333
+ ] }),
334
+ /* @__PURE__ */ jsxRuntime.jsxs("label", { children: [
335
+ "Radius meters",
336
+ " ",
337
+ /* @__PURE__ */ jsxRuntime.jsx(
338
+ "input",
339
+ {
340
+ type: "number",
341
+ value: condition.radiusMeters,
342
+ onChange: (event) => onChange({
343
+ ...spot,
344
+ conditions: conditions.map(
345
+ (item, itemIndex) => itemIndex === index ? updateUniversalCondition(item, "radiusMeters", event.target.value) : item
346
+ )
347
+ })
348
+ }
349
+ )
350
+ ] })
351
+ ] }),
352
+ conditions.length > 1 && /* @__PURE__ */ jsxRuntime.jsx(
353
+ "button",
354
+ {
355
+ type: "button",
356
+ onClick: () => update({ conditions: conditions.filter((_, itemIndex) => itemIndex !== index) }),
357
+ children: "Remove condition"
358
+ }
359
+ )
360
+ ] }, JSON.stringify(condition))),
361
+ /* @__PURE__ */ jsxRuntime.jsx(
362
+ "button",
363
+ {
364
+ type: "button",
365
+ onClick: () => update({ conditions: [...conditions, newUniversalCondition()] }),
366
+ children: "Add condition"
367
+ }
368
+ )
369
+ ] }),
370
+ /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", onClick: onMoveUp, disabled: spot.orderIndex === 0, children: "Move spot up" }),
371
+ /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", onClick: onMoveDown, disabled: spot.orderIndex === spots.length - 1, children: "Move spot down" }),
372
+ /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", onClick: onDelete, children: "Remove spot" })
373
+ ] });
374
+ }
375
+ function UniversalRewardForm({
376
+ reward,
377
+ spots,
378
+ onChange,
379
+ onDelete
380
+ }) {
381
+ const update = (next) => onChange({ ...reward, ...next });
382
+ const conditions = reward.conditions ?? [];
383
+ return /* @__PURE__ */ jsxRuntime.jsxs("fieldset", { className: "stamprally-admin-card", "aria-label": `Reward ${reward.id}`, children: [
384
+ /* @__PURE__ */ jsxRuntime.jsx("legend", { children: "Reward" }),
385
+ /* @__PURE__ */ jsxRuntime.jsxs("label", { children: [
386
+ "ID ",
387
+ /* @__PURE__ */ jsxRuntime.jsx("input", { value: reward.id, onChange: (event) => update({ id: event.target.value }) })
388
+ ] }),
389
+ /* @__PURE__ */ jsxRuntime.jsxs("label", { children: [
390
+ "Title (ja)",
391
+ " ",
392
+ /* @__PURE__ */ jsxRuntime.jsx(
393
+ "input",
394
+ {
395
+ value: universalText(reward.title, "ja"),
396
+ onChange: (event) => update({ title: updateUniversalText(reward.title, "ja", event.target.value) })
397
+ }
398
+ )
399
+ ] }),
400
+ /* @__PURE__ */ jsxRuntime.jsxs("label", { children: [
401
+ "Title (en)",
402
+ " ",
403
+ /* @__PURE__ */ jsxRuntime.jsx(
404
+ "input",
405
+ {
406
+ value: universalText(reward.title, "en"),
407
+ onChange: (event) => update({ title: updateUniversalText(reward.title, "en", event.target.value) })
408
+ }
409
+ )
410
+ ] }),
411
+ /* @__PURE__ */ jsxRuntime.jsxs("label", { children: [
412
+ "Required stamps",
413
+ " ",
414
+ /* @__PURE__ */ jsxRuntime.jsx(
415
+ "input",
416
+ {
417
+ type: "number",
418
+ min: 0,
419
+ value: reward.requiredStampCount,
420
+ onChange: (event) => update({ requiredStampCount: Number(event.target.value) })
421
+ }
422
+ )
423
+ ] }),
424
+ /* @__PURE__ */ jsxRuntime.jsxs("label", { children: [
425
+ "Stock limit",
426
+ " ",
427
+ /* @__PURE__ */ jsxRuntime.jsx(
428
+ "input",
429
+ {
430
+ type: "number",
431
+ min: 0,
432
+ value: reward.stockLimit ?? "",
433
+ onChange: (event) => {
434
+ if (event.target.value === "") {
435
+ const { stockLimit: _removed, ...rest } = reward;
436
+ onChange(rest);
437
+ } else update({ stockLimit: Number(event.target.value) });
438
+ }
439
+ }
440
+ )
441
+ ] }),
442
+ /* @__PURE__ */ jsxRuntime.jsxs("label", { children: [
443
+ "User claim limit",
444
+ " ",
445
+ /* @__PURE__ */ jsxRuntime.jsx(
446
+ "input",
447
+ {
448
+ type: "number",
449
+ min: 0,
450
+ value: reward.userClaimLimit ?? "",
451
+ onChange: (event) => {
452
+ if (event.target.value === "") {
453
+ const { userClaimLimit: _removed, ...rest } = reward;
454
+ onChange(rest);
455
+ } else update({ userClaimLimit: Number(event.target.value) });
456
+ }
457
+ }
458
+ )
459
+ ] }),
460
+ /* @__PURE__ */ jsxRuntime.jsxs("label", { children: [
461
+ "Staff passcode",
462
+ " ",
463
+ /* @__PURE__ */ jsxRuntime.jsx(
464
+ "input",
465
+ {
466
+ type: "password",
467
+ value: reward.staffPasscode ?? "",
468
+ onChange: (event) => {
469
+ if (event.target.value === "") {
470
+ const { staffPasscode: _removed, ...rest } = reward;
471
+ onChange(rest);
472
+ } else update({ staffPasscode: event.target.value });
473
+ }
474
+ }
475
+ )
476
+ ] }),
477
+ /* @__PURE__ */ jsxRuntime.jsxs("label", { children: [
478
+ "Redemption method",
479
+ " ",
480
+ /* @__PURE__ */ jsxRuntime.jsxs(
481
+ "select",
482
+ {
483
+ value: reward.redemptionMethod,
484
+ onChange: (event) => update({ redemptionMethod: event.target.value }),
485
+ children: [
486
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "manual_slide", children: "manual_slide" }),
487
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "staff_passcode", children: "staff_passcode" }),
488
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "view_only", children: "view_only" }),
489
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "server_claim", children: "server_claim" })
490
+ ]
491
+ }
492
+ )
493
+ ] }),
494
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
495
+ /* @__PURE__ */ jsxRuntime.jsx("h4", { children: "Unlock conditions" }),
496
+ conditions.map((condition, index) => /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
497
+ /* @__PURE__ */ jsxRuntime.jsxs("label", { children: [
498
+ "Reward condition type",
499
+ " ",
500
+ /* @__PURE__ */ jsxRuntime.jsxs(
501
+ "select",
502
+ {
503
+ value: condition.type,
504
+ onChange: (event) => {
505
+ const type = event.target.value;
506
+ const next = type === "stamps" ? { type: "stamps", stampIds: [] } : type === "all" || type === "any" ? { type, conditions: [{ type: "stamp_count", count: 1 }] } : { type: "stamp_count", count: 1 };
507
+ update({
508
+ conditions: conditions.map(
509
+ (item, itemIndex) => itemIndex === index ? next : item
510
+ )
511
+ });
512
+ },
513
+ children: [
514
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "stamp_count", children: "Stamp count" }),
515
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "stamps", children: "Specific spots" }),
516
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "all", children: "All" }),
517
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "any", children: "Any" })
518
+ ]
519
+ }
520
+ )
521
+ ] }),
522
+ condition.type === "stamp_count" && /* @__PURE__ */ jsxRuntime.jsxs("label", { children: [
523
+ "Required stamp count",
524
+ " ",
525
+ /* @__PURE__ */ jsxRuntime.jsx(
526
+ "input",
527
+ {
528
+ type: "number",
529
+ min: 0,
530
+ value: condition.count,
531
+ onChange: (event) => update({
532
+ conditions: conditions.map(
533
+ (item, itemIndex) => itemIndex === index ? { ...condition, count: Number(event.target.value) } : item
534
+ )
535
+ })
536
+ }
537
+ )
538
+ ] }),
539
+ condition.type === "stamps" && /* @__PURE__ */ jsxRuntime.jsxs("label", { children: [
540
+ "Specific spot IDs",
541
+ " ",
542
+ /* @__PURE__ */ jsxRuntime.jsx(
543
+ "input",
544
+ {
545
+ value: condition.stampIds.join(", "),
546
+ placeholder: spots.map((item) => item.id).join(", "),
547
+ onChange: (event) => update({
548
+ conditions: conditions.map(
549
+ (item, itemIndex) => itemIndex === index ? {
550
+ ...condition,
551
+ stampIds: event.target.value.split(",").map((id) => id.trim()).filter(Boolean)
552
+ } : item
553
+ )
554
+ })
555
+ }
556
+ )
557
+ ] }),
558
+ /* @__PURE__ */ jsxRuntime.jsx(
559
+ "button",
560
+ {
561
+ type: "button",
562
+ onClick: () => update({ conditions: conditions.filter((_, itemIndex) => itemIndex !== index) }),
563
+ children: "Remove reward condition"
564
+ }
565
+ )
566
+ ] }, JSON.stringify(condition))),
567
+ /* @__PURE__ */ jsxRuntime.jsx(
568
+ "button",
569
+ {
570
+ type: "button",
571
+ onClick: () => update({ conditions: [...conditions, { type: "stamp_count", count: 1 }] }),
572
+ children: "Add reward condition"
573
+ }
574
+ )
575
+ ] }),
576
+ /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", onClick: onDelete, children: "Remove reward" })
577
+ ] });
578
+ }
579
+ function AdminRallyEditor({ config, locale = "ja", onChange }) {
580
+ const spots = config.spots;
581
+ const rewards = config.rewards;
582
+ const theme = config.theme ?? core.DEFAULT_SHEET_THEME;
583
+ const setConfig = (next) => onChange({ ...config, ...next });
584
+ return /* @__PURE__ */ jsxRuntime.jsxs("section", { "aria-label": "Universal rally editor", className: "stamprally-admin-card", children: [
585
+ /* @__PURE__ */ jsxRuntime.jsxs("fieldset", { children: [
586
+ /* @__PURE__ */ jsxRuntime.jsx("legend", { children: "Basic settings" }),
587
+ /* @__PURE__ */ jsxRuntime.jsxs("label", { children: [
588
+ "Title (",
589
+ locale,
590
+ ")",
591
+ " ",
592
+ /* @__PURE__ */ jsxRuntime.jsx(
593
+ "input",
594
+ {
595
+ value: universalText(config.title, locale),
596
+ onChange: (event) => setConfig({
597
+ title: updateUniversalText(
598
+ config.title,
599
+ locale,
600
+ event.target.value
601
+ )
602
+ })
603
+ }
604
+ )
605
+ ] }),
606
+ /* @__PURE__ */ jsxRuntime.jsxs("label", { children: [
607
+ "Description (",
608
+ locale,
609
+ ")",
610
+ " ",
611
+ /* @__PURE__ */ jsxRuntime.jsx(
612
+ "textarea",
613
+ {
614
+ value: universalText(config.description, locale),
615
+ onChange: (event) => {
616
+ if (event.target.value === "") {
617
+ const { description: _removed, ...rest } = config;
618
+ onChange(rest);
619
+ } else
620
+ setConfig({
621
+ description: updateUniversalText(config.description, locale, event.target.value)
622
+ });
623
+ }
624
+ }
625
+ )
626
+ ] }),
627
+ /* @__PURE__ */ jsxRuntime.jsxs("label", { children: [
628
+ "Theme preset",
629
+ " ",
630
+ /* @__PURE__ */ jsxRuntime.jsxs(
631
+ "select",
632
+ {
633
+ value: core.THEME_PRESETS.find((preset) => JSON.stringify(preset.theme) === JSON.stringify(theme))?.id ?? "custom",
634
+ onChange: (event) => {
635
+ const preset = core.THEME_PRESETS.find((item) => item.id === event.target.value);
636
+ if (preset !== void 0) setConfig({ theme: preset.theme });
637
+ },
638
+ children: [
639
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "custom", children: "custom" }),
640
+ core.THEME_PRESETS.map((preset) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: preset.id, children: core.resolveLocalizedText(preset.name, locale) }, preset.id))
641
+ ]
642
+ }
643
+ )
644
+ ] }),
645
+ /* @__PURE__ */ jsxRuntime.jsxs("label", { children: [
646
+ "Primary color",
647
+ " ",
648
+ /* @__PURE__ */ jsxRuntime.jsx(
649
+ "input",
650
+ {
651
+ type: "color",
652
+ value: theme.primaryColor,
653
+ onChange: (event) => setConfig({ theme: { ...theme, primaryColor: event.target.value } })
654
+ }
655
+ )
656
+ ] }),
657
+ /* @__PURE__ */ jsxRuntime.jsxs("label", { children: [
658
+ "Font family",
659
+ " ",
660
+ /* @__PURE__ */ jsxRuntime.jsxs(
661
+ "select",
662
+ {
663
+ value: theme.fontFamily ?? "serif",
664
+ onChange: (event) => setConfig({
665
+ theme: {
666
+ ...theme,
667
+ fontFamily: event.target.value
668
+ }
669
+ }),
670
+ children: [
671
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "system-ui", children: "system-ui" }),
672
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "serif", children: "serif" }),
673
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "rounded-sans", children: "rounded-sans" }),
674
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "monospace", children: "monospace" }),
675
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "handwritten", children: "handwritten" })
676
+ ]
677
+ }
678
+ )
679
+ ] })
680
+ ] }),
681
+ /* @__PURE__ */ jsxRuntime.jsxs("section", { "aria-label": "Universal spots", children: [
682
+ /* @__PURE__ */ jsxRuntime.jsx("h2", { children: "Spots" }),
683
+ spots.map((spot, index) => /* @__PURE__ */ jsxRuntime.jsx(
684
+ UniversalSpotForm,
685
+ {
686
+ spot,
687
+ spots,
688
+ onChange: (next) => setConfig({
689
+ spots: spots.map(
690
+ (item, itemIndex) => itemIndex === index ? { ...next, orderIndex: next.orderIndex } : item
691
+ )
692
+ }),
693
+ onMoveUp: () => {
694
+ if (index === 0) return;
695
+ const current = spots[index];
696
+ const previous = spots[index - 1];
697
+ if (current === void 0 || previous === void 0) return;
698
+ const reordered = spots.map(
699
+ (item, itemIndex) => itemIndex === index - 1 ? { ...current, orderIndex: index - 1 } : itemIndex === index ? { ...previous, orderIndex: index } : item
700
+ );
701
+ setConfig({ spots: reordered });
702
+ },
703
+ onMoveDown: () => {
704
+ if (index === spots.length - 1) return;
705
+ const current = spots[index];
706
+ const next = spots[index + 1];
707
+ if (current === void 0 || next === void 0) return;
708
+ const reordered = spots.map(
709
+ (item, itemIndex) => itemIndex === index ? { ...next, orderIndex: index } : itemIndex === index + 1 ? { ...current, orderIndex: index + 1 } : item
710
+ );
711
+ setConfig({ spots: reordered });
712
+ },
713
+ onDelete: () => setConfig({
714
+ spots: spots.filter((_, itemIndex) => itemIndex !== index).map((item, itemIndex) => ({ ...item, orderIndex: itemIndex }))
715
+ })
716
+ },
717
+ spot.id
718
+ )),
719
+ /* @__PURE__ */ jsxRuntime.jsx(
720
+ "button",
721
+ {
722
+ type: "button",
723
+ onClick: () => setConfig({ spots: [...spots, defaultUniversalSpot(spots.length)] }),
724
+ children: "Add spot"
725
+ }
726
+ )
727
+ ] }),
728
+ /* @__PURE__ */ jsxRuntime.jsxs("section", { "aria-label": "Universal rewards", children: [
729
+ /* @__PURE__ */ jsxRuntime.jsx("h2", { children: "Rewards" }),
730
+ rewards.map((reward, index) => /* @__PURE__ */ jsxRuntime.jsx(
731
+ UniversalRewardForm,
732
+ {
733
+ reward,
734
+ spots,
735
+ onChange: (next) => setConfig({
736
+ rewards: rewards.map((item, itemIndex) => itemIndex === index ? next : item)
737
+ }),
738
+ onDelete: () => setConfig({ rewards: rewards.filter((_, itemIndex) => itemIndex !== index) })
739
+ },
740
+ reward.id
741
+ )),
742
+ /* @__PURE__ */ jsxRuntime.jsx(
743
+ "button",
744
+ {
745
+ type: "button",
746
+ onClick: () => setConfig({ rewards: [...rewards, defaultUniversalReward(rewards.length)] }),
747
+ children: "Add reward"
748
+ }
749
+ )
750
+ ] })
751
+ ] });
752
+ }
8
753
  var localePair = (value) => {
9
754
  if (typeof value === "string") return { ja: value, en: "" };
10
755
  const result = {};
@@ -731,6 +1476,7 @@ function RallyEditor({
731
1476
  ] });
732
1477
  }
733
1478
 
1479
+ exports.AdminRallyEditor = AdminRallyEditor;
734
1480
  exports.ConditionEditor = ConditionEditor;
735
1481
  exports.GeneralSettingsForm = GeneralSettingsForm;
736
1482
  exports.JsonConfigIO = JsonConfigIO;