From 30f9148adb1f90b1821e86727e75e9fadbc9bd9b Mon Sep 17 00:00:00 2001 From: Elias Journal Date: Mon, 24 Aug 2026 21:53:02 -0400 Subject: [PATCH] Initial commit: KiddOs v3 React kiosk - React 18 + Vite 5 hot-reload OS (800x480 Nord theme) - 7 apps: Journal, Calculator, Drawing, CodeLab, Clock, Files, Scratch - Cage + Cog Wayland kiosk, offline localStorage - Scripts: dev.sh, run-kiosk.sh, run-prod.sh --- .gitignore | 24 + README.md | 116 ++ plan.md | 124 ++ public/calculator.png | Bin 0 -> 402 bytes public/clock.png | Bin 0 -> 401 bytes public/code.png | Bin 0 -> 402 bytes public/files.png | Bin 0 -> 402 bytes public/icons/calculator.png | Bin 0 -> 402 bytes public/icons/clock.png | Bin 0 -> 401 bytes public/icons/code.png | Bin 0 -> 402 bytes public/icons/files.png | Bin 0 -> 402 bytes public/icons/journal.png | Bin 0 -> 402 bytes public/icons/play.png | Bin 0 -> 402 bytes public/icons/scratch.png | Bin 0 -> 401 bytes public/icons/terminal.png | Bin 0 -> 402 bytes public/journal.png | Bin 0 -> 402 bytes public/play.png | Bin 0 -> 402 bytes public/scratch.png | Bin 0 -> 401 bytes public/terminal.png | Bin 0 -> 402 bytes scripts/dev.sh | 35 + scripts/run-kiosk.sh | 39 + scripts/run-prod.sh | 19 + webapp/README.md | 9 + webapp/index.html | 16 + webapp/package-lock.json | 1698 ++++++++++++++++++++++++++++ webapp/package.json | 19 + webapp/public/icons/calculator.png | Bin 0 -> 402 bytes webapp/public/icons/clock.png | Bin 0 -> 401 bytes webapp/public/icons/code.png | Bin 0 -> 402 bytes webapp/public/icons/files.png | Bin 0 -> 402 bytes webapp/public/icons/journal.png | Bin 0 -> 402 bytes webapp/public/icons/play.png | Bin 0 -> 402 bytes webapp/public/icons/scratch.png | Bin 0 -> 401 bytes webapp/public/icons/terminal.png | Bin 0 -> 402 bytes webapp/src/App.jsx | 268 +++++ webapp/src/apps/Calculator.jsx | 67 ++ webapp/src/apps/Clock.jsx | 90 ++ webapp/src/apps/CodeLab.jsx | 93 ++ webapp/src/apps/Drawing.jsx | 148 +++ webapp/src/apps/Files.jsx | 74 ++ webapp/src/apps/Journal.jsx | 109 ++ webapp/src/apps/Scratch.jsx | 64 ++ webapp/src/index.css | 30 + webapp/src/main.jsx | 10 + webapp/vite.config.js | 23 + 45 files changed, 3075 insertions(+) create mode 100644 .gitignore create mode 100644 README.md create mode 100644 plan.md create mode 100644 public/calculator.png create mode 100644 public/clock.png create mode 100644 public/code.png create mode 100644 public/files.png create mode 100644 public/icons/calculator.png create mode 100644 public/icons/clock.png create mode 100644 public/icons/code.png create mode 100644 public/icons/files.png create mode 100644 public/icons/journal.png create mode 100644 public/icons/play.png create mode 100644 public/icons/scratch.png create mode 100644 public/icons/terminal.png create mode 100644 public/journal.png create mode 100644 public/play.png create mode 100644 public/scratch.png create mode 100644 public/terminal.png create mode 100755 scripts/dev.sh create mode 100755 scripts/run-kiosk.sh create mode 100755 scripts/run-prod.sh create mode 100644 webapp/README.md create mode 100644 webapp/index.html create mode 100644 webapp/package-lock.json create mode 100644 webapp/package.json create mode 100644 webapp/public/icons/calculator.png create mode 100644 webapp/public/icons/clock.png create mode 100644 webapp/public/icons/code.png create mode 100644 webapp/public/icons/files.png create mode 100644 webapp/public/icons/journal.png create mode 100644 webapp/public/icons/play.png create mode 100644 webapp/public/icons/scratch.png create mode 100644 webapp/public/icons/terminal.png create mode 100644 webapp/src/App.jsx create mode 100644 webapp/src/apps/Calculator.jsx create mode 100644 webapp/src/apps/Clock.jsx create mode 100644 webapp/src/apps/CodeLab.jsx create mode 100644 webapp/src/apps/Drawing.jsx create mode 100644 webapp/src/apps/Files.jsx create mode 100644 webapp/src/apps/Journal.jsx create mode 100644 webapp/src/apps/Scratch.jsx create mode 100644 webapp/src/index.css create mode 100644 webapp/src/main.jsx create mode 100644 webapp/vite.config.js diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..868960a --- /dev/null +++ b/.gitignore @@ -0,0 +1,24 @@ +# Dependencies +node_modules/ +webapp/node_modules/ + +# Build output +webapp/dist/ +dist/ +build/ + +# Vite +.vite/ + +# Logs +*.log +npm-debug.log* + +# OS +.DS_Store +Thumbs.db + +# Env +.env +.env.local + diff --git a/README.md b/README.md new file mode 100644 index 0000000..3e3b945 --- /dev/null +++ b/README.md @@ -0,0 +1,116 @@ +# KiddOs v3 — React Hot Reload OS (Done) + +**Browser kiosk + React + Vite HMR, no backend, no LVGL, offline-first.** + +This is the finished v3 you'd been building. Just React, hot refresh, works on 800×480 DSI. + +## What works now + +- **React shell** `src/App.jsx`: header with clock, greeting, companion banner, favorites & recent (localStorage), category filters, 150px cards grid, settings drawer +- **7 apps** (all React components, no fork/exec): + - `Journal` — autosave 1.5s, word count, past list, companion banner, offline localStorage + - `Calculator` — touch 56px buttons, history in localStorage + - `Drawing` — canvas pen/eraser, size, undo, save PNG, works touch+mouse + - `CodeLab` — JS playground, 3 samples, auto-saves, safe `new Function` + - `Clock` — analog time, timer (1/3/5/10m), stopwatch + - `Files` — browse localStorage journal entries, show companion info + - `Scratch` — iframe scratch.mit.edu (needs online) + offline alternatives info +- **Styling**: dark #2E3440 Nord theme, 800×480 optimized, touch 36px+ targets +- **Hot reload**: Vite dev server on :5173, Cog loads http://localhost:5173, edits push <1s to DSI +- **Build**: 184KB JS, 55KB gzip, no backend, file:// also works via `dist/` + +## How to run (proven commands) + +**1. Stop old kiosks:** +```bash +sudo systemctl stop kiddos.service kiddos-browser.service journal-kiosk.service +``` + +**2. Start React dev server (SSH session 1):** +```bash +cd ~/KiddOsV3/webapp +npm run dev -- --host 0.0.0.0 --port 5173 +# or +~/KiddOsV3/scripts/dev.sh +``` +Vite: `Local: http://localhost:5173/` + +**3. Put on DSI (SSH session 2):** +```bash +~/KiddOsV3/scripts/run-kiosk.sh +# which runs: +sudo openvt -f -c 1 -s -- env XDG_RUNTIME_DIR=/run/user/1000 cage -s -- \ + cog --platform=wl http://localhost:5173 --bg-color=#2E3440 --doc-viewer +``` + +You should see React launcher on DSI, touch works (ft5x06 event7 via libinput seat0). Edit `src/App.jsx`, save, DSI updates instantly. + +**Fallbacks:** +```bash +# Chromium if Cog touch cursor stuck middle +sudo openvt -f -c 1 -s -- env XDG_RUNTIME_DIR=/run/user/1000 cage -s -- \ + chromium --kiosk --no-sandbox --ozone-platform=wayland --disable-gpu http://localhost:5173 + +# Static prod build (no dev server) +cd ~/KiddOsV3/webapp && npm run build +cage -s -- cog --platform=wl file://$PWD/dist/index.html --bg-color=#2E3440 + +# Hello world test (no React) +cage -s -- cog --platform=wl file:///home/elias/KiddOsV2/browser/hello.html --bg-color=#2E3440 +``` + +**If touch cursor stuck middle:** +- `libinput list-devices` should show `10-0038 generic ft5x06 (79)` at event7 +- cage needs it. Try without `WLR_NO_HARDWARE_CURSORS`, clean `/run/user/1000/wayland-*` +- Or try labwc compositor instead of cage (heavier but more compatible) + +## Folder +``` +KiddOsV3/ +├── plan.md +├── README.md (this) +├── public/icons/ (128x128 PNGs reused from v1) +├── webapp/ +│ ├── package.json (react 18, vite 5, @vitejs/plugin-react) +│ ├── vite.config.js (0.0.0.0:5173, hmr clientPort 5173, base ./) +│ ├── index.html +│ └── src/ +│ ├── main.jsx +│ ├── index.css (Nord theme, 800x480 tweaks) +│ ├── App.jsx (OS shell + settings drawer) +│ └── apps/ +│ ├── Journal.jsx +│ ├── Calculator.jsx +│ ├── Drawing.jsx +│ ├── CodeLab.jsx +│ ├── Clock.jsx +│ ├── Files.jsx +│ └── Scratch.jsx +└── scripts/ + ├── dev.sh + ├── run-kiosk.sh + └── run-prod.sh +``` + +## Companion integration + +- `elias_companion` writes `~/launcher_config/companion_message.txt` and `dashboard.md` (counts only) +- v3 reads `localStorage.kiddos_companion_message` if set +- To show live companion on React: + ```bash + cat ~/launcher_config/companion_message.txt + # then in browser console: + localStorage.setItem('kiddos_companion_message', 'You wrote today - 1 entries!') + ``` + Future: add tiny python server endpoint `/api/companion` in v2 `server/server.py` or copy companion_message.txt into `webapp/public/` and fetch. + +## Next steps (after prove) + +1. Confirm hot reload works on DSI (edit App.jsx, see instantly) +2. Add more apps: Blockly offline (copy from v2), music, math games +3. Optionally re-add `server/server.py` for central sync (v2's local-first + central) +4. Only then systemd service using same working command (openvt -f -c 1 -s ...) + +## Why not LVGL anymore + +v1 LVGL had DRM master handover per app → “any app I try to open freeze and restarts the OS” (your report). Browser OS: one process owns DRM forever, apps are React components, no fork, no black screen. diff --git a/plan.md b/plan.md new file mode 100644 index 0000000..022dbad --- /dev/null +++ b/plan.md @@ -0,0 +1,124 @@ +# KiddOs v3 — Plan: Browser Kiosk + React Hot Reload, No Backend + +## Goal +From-scratch v3, **just webapp React with hot refresh**, no server, no LVGL, no backend. Use the proven kiosk command that shows web on DSI: + +```bash +cage -s -- \ +cog --platform=wl file:///home/elias/KiddOsV2/browser/hello.html --bg-color=#2E3440 +``` + +That command is Method 2a that you confirmed works: `cage` (tiny Wayland kiosk compositor, 82KB) owns DRM/KMS on `/dev/dri/card1` (DSI 800x480 connector id 49), creates Wayland socket in `$XDG_RUNTIME_DIR`, `cog --platform=wl` (WPE WebKit, ~10MB) connects as Wayland client and renders HTML. No X11, no black flicker from fork/exec. + +For v3 we keep that exact command, but point it to a **React dev server** for hot refresh instead of static file:// + +## Why No Backend? +- v2 had `server/server.py` local-first + central sync. Good architecture but adds complexity. +- v3 requirement: **just webapp react with hot refresh on code changes so we can quickly iterate**. +- So: Vite dev server on Pi itself `http://localhost:5173` serves React, Cog loads that URL, and Vite HMR pushes changes instantly to DSI — you edit `src/App.jsx` on laptop via SSH, DSI updates in <1s. + +## Stack +- **Compositor**: `cage -s` (kiosk Wayland, handles DRM, libinput touch via seat0) +- **Browser**: `cog --platform=wl` (WPE WebKit, lighter than Chromium 150MB and Electron 265MB). Fallback: `chromium --ozone-platform=wayland` if WPE touch fails. +- **Webapp**: React 18 UMD or Vite + React (we use Vite for HMR). No backend, uses `localStorage` for journal/todos. All offline, file:// or http://localhost works. +- **Icons**: Reuse PNG 128x128 from v1/v2 `browser/icons/`. + +## Folder v3 +``` +KiddOsV3/ +├── plan.md (this file) +├── README.md +├── public/ (static icons, will be served by Vite) +├── webapp/ +│ ├── package.json (vite + react) +│ ├── vite.config.js (host 0.0.0.0, port 5173, HMR overlay) +│ ├── index.html (Vite entry) +│ └── src/ +│ ├── main.jsx (ReactDOM.createRoot) +│ ├── App.jsx (OS shell: header, favorites, categories, grid, settings drawer) +│ └── apps/ +│ ├── Journal.jsx (localStorage journal) +│ ├── Calculator.jsx +│ ├── Drawing.jsx (canvas) +│ └── CodeLab.jsx +└── scripts/ + ├── dev.sh (run vite dev server) + └── run-kiosk.sh (the proven cage command) +``` + +## How to run (prove without services) + +**On Pi, no services needed — manual, like you asked:** + +```bash +# 1. Stop any old kiosks, leave terminal on DSI +sudo systemctl stop kiddos.service kiddos-browser.service journal-kiosk.service +sudo systemctl start getty@tty1.service + +# 2. Start React dev server in one SSH session: +cd ~/KiddOsV3/webapp +npm install +npm run dev -- --host 0.0.0.0 --port 5173 +# Vite says: Local: http://localhost:5173/ + +# 3. In another SSH session, put it on DSI (exact command you proved): +sudo openvt -f -c 1 -s -- env XDG_RUNTIME_DIR=/run/user/1000 cage -s -- \ +cog --platform=wl http://localhost:5173 --bg-color=#2E3440 --doc-viewer + +# You should see React launcher on DSI, and editing src/App.jsx updates instantly. +``` + +**If touch cursor stuck middle (your last report):** +- Cage needs input devices. Check `libinput list-devices` shows `10-0038 generic ft5x06 (79)` at event7. +- Try without WLR_NO_HARDWARE_CURSORS, and ensure /run/user/1000/wayland-* cleaned. +- Fallback: `cage -s -- chromium --ozone-platform=wayland` instead of cog — you saw webpage with that too. +- Last resort heavier: `labwc --startup "cog ..."` or Xorg+openbox, but we avoid until proven. + +## React Hot Refresh Details +- Vite HMR uses WebSocket on same host:port. Cog supports WebSocket, so HMR works file://? No, needs http:// — hence dev server at localhost:5173. +- In `vite.config.js`: +```js +export default { + server: { host: '0.0.0.0', port: 5173, hmr: { clientPort: 5173 } }, + clearScreen: false +} +``` +- Edit `src/App.jsx`, save, DSI refreshes. + +## Next Steps After Prove +Once hello world React works reliably on DSI with touch: +1. Add more React apps (Scratch via iframe?). +2. Optionally re-add local server later for central sync (v2's server.py) — but keep v3 frontend-only for fast iteration. +3. Only then create systemd service using same working command (openvt -f -c 1 -s ...). + +## Commands Reference (the one you asked to keep) + +Base proven command (no backend, just file:// hello world): +```bash +cage -s -- \ +cog --platform=wl file:///home/elias/KiddOsV2/browser/hello.html --bg-color=#2E3440 +``` + +For v3 React with HMR: +```bash +cage -s -- \ +cog --platform=wl http://localhost:5173 --bg-color=#2E3440 +``` + +If Cog touch fails, try Chromium: +```bash +cage -s -- \ +chromium --kiosk --no-sandbox --ozone-platform=wayland --disable-gpu \ +http://localhost:5173 +``` + +Electron alternative (heavier, same as Chromium + Node, you asked about): +```bash +cage -s -- \ +./node_modules/.bin/electron --no-sandbox --ozone-platform=wayland --disable-gpu . +``` + +## Why not LVGL anymore? +- v1 LVGL had to fork/exec + DRM master handover for each app → “any app I try to open freeze and restarts the OS” (your report). Non-DRM apps (gnome-calculator) crashed. +- Browser OS: one process owns DRM forever, apps are just React components / pages, no fork, no black screen. + diff --git a/public/calculator.png b/public/calculator.png new file mode 100644 index 0000000000000000000000000000000000000000..3118b2e20db8fe9e985b4b13eb01a6f65ae8452b GIT binary patch literal 402 zcmeAS@N?(olHy`uVBq!ia0vp^4Is?H1|$#LC7xzrV2t#1aSW-L^Y)UVV1og}fdgGf zS;ef98RR3FIb|Q7;NPEq;zs}5W!ZaV8yF23=1V@k8ZfLGJYD@<);T3K0RTKwfHD98 literal 0 HcmV?d00001 diff --git a/public/clock.png b/public/clock.png new file mode 100644 index 0000000000000000000000000000000000000000..8185e077b10b035a22b7d2fac5e3f7fb70af5da5 GIT binary patch literal 401 zcmeAS@N?(olHy`uVBq!ia0vp^4Is?H1|$#LC7xzrV2to|aSW-L^Y)UVV1og}fdgKy ztWv9(cr92sd)`izuRA}XaL(t2*=zU?Fi14yvdy@DwqH`=977>nhq1#P#z#B?=?xal oM@EIfA+h5;V}>ClSiUn|{j?%MHZ^=5FsKwvr nY#pOQkdQddm|+MBo$m~6fzO@aSx*)RhBbqytDnm{r-UW|VY+{O literal 0 HcmV?d00001 diff --git a/public/files.png b/public/files.png new file mode 100644 index 0000000000000000000000000000000000000000..9466fa639c846d1d96fbfa23388c5ea6265c6117 GIT binary patch literal 402 zcmeAS@N?(olHy`uVBq!ia0vp^4Is?H1|$#LC7xzrV2t#1aSW-L^Y)UVV1og}fdf^p zd`4QWf|?x+oU#v3@b6DQVezc&vgtj(0}K)k=Xna|THB{JSTG-vR5-^_$kt)(Fo*FG ok3jmU5I7{JF<(f61jRc>kDHlauRYh71co((r>mdKI;Vst0HI=k$p8QV literal 0 HcmV?d00001 diff --git a/public/icons/calculator.png b/public/icons/calculator.png new file mode 100644 index 0000000000000000000000000000000000000000..3118b2e20db8fe9e985b4b13eb01a6f65ae8452b GIT binary patch literal 402 zcmeAS@N?(olHy`uVBq!ia0vp^4Is?H1|$#LC7xzrV2t#1aSW-L^Y)UVV1og}fdgGf zS;ef98RR3FIb|Q7;NPEq;zs}5W!ZaV8yF23=1V@k8ZfLGJYD@<);T3K0RTKwfHD98 literal 0 HcmV?d00001 diff --git a/public/icons/clock.png b/public/icons/clock.png new file mode 100644 index 0000000000000000000000000000000000000000..8185e077b10b035a22b7d2fac5e3f7fb70af5da5 GIT binary patch literal 401 zcmeAS@N?(olHy`uVBq!ia0vp^4Is?H1|$#LC7xzrV2to|aSW-L^Y)UVV1og}fdgKy ztWv9(cr92sd)`izuRA}XaL(t2*=zU?Fi14yvdy@DwqH`=977>nhq1#P#z#B?=?xal oM@EIfA+h5;V}>ClSiUn|{j?%MHZ^=5FsKwvr nY#pOQkdQddm|+MBo$m~6fzO@aSx*)RhBbqytDnm{r-UW|VY+{O literal 0 HcmV?d00001 diff --git a/public/icons/files.png b/public/icons/files.png new file mode 100644 index 0000000000000000000000000000000000000000..9466fa639c846d1d96fbfa23388c5ea6265c6117 GIT binary patch literal 402 zcmeAS@N?(olHy`uVBq!ia0vp^4Is?H1|$#LC7xzrV2t#1aSW-L^Y)UVV1og}fdf^p zd`4QWf|?x+oU#v3@b6DQVezc&vgtj(0}K)k=Xna|THB{JSTG-vR5-^_$kt)(Fo*FG ok3jmU5I7{JF<(f61jRc>kDHlauRYh71co((r>mdKI;Vst0HI=k$p8QV literal 0 HcmV?d00001 diff --git a/public/icons/journal.png b/public/icons/journal.png new file mode 100644 index 0000000000000000000000000000000000000000..575783e46a2e92d83043946c81ad765f88e50545 GIT binary patch literal 402 zcmeAS@N?(olHy`uVBq!ia0vp^4Is?H1|$#LC7xzrV2t#1aSW-L^Y)UVV1og}fdgKy zd_r1`k{$;HJzj9Q*Zr_{K4#WGd)>z}2DSqXHE9ih_xvzqJ|d}bj-imP!`NXC<0Bq{ n^ahJjA#g}+muV1#1_i&gs%HGNZ@)JJ!c9(mrue(BlP%d)*IP=VLqb&0`O|ZTU7}gA)u6{1-oD!M<^?-nz literal 0 HcmV?d00001 diff --git a/public/icons/scratch.png b/public/icons/scratch.png new file mode 100644 index 0000000000000000000000000000000000000000..45da0af2223f2ba12095e1e763a707422dacaca1 GIT binary patch literal 401 zcmeAS@N?(olHy`uVBq!ia0vp^4Is?H1|$#LC7xzrV2to|aSW-L^Y)UVV1og}fdi{t zdBZh*G7j>2yx?%J`(f*RY@e)o?Bll#JPnLL&M-XR^TUw&h@`?fhC;RuV~076k9Y*q m8!SeJz#*|+ra=rE6#TQ-XvRz}2DSqXHE9ih_xvzqJ|d}bj-imP!`NXC<0Bq{ n^ahJjA#g}+muV1#1_i&gs%HGNZ@)JJ!c9(mrue(BlP%d)*IP=VLqb&0`O|ZTU7}gA)u6{1-oD!M<^?-nz literal 0 HcmV?d00001 diff --git a/public/scratch.png b/public/scratch.png new file mode 100644 index 0000000000000000000000000000000000000000..45da0af2223f2ba12095e1e763a707422dacaca1 GIT binary patch literal 401 zcmeAS@N?(olHy`uVBq!ia0vp^4Is?H1|$#LC7xzrV2to|aSW-L^Y)UVV1og}fdi{t zdBZh*G7j>2yx?%J`(f*RY@e)o?Bll#JPnLL&M-XR^TUw&h@`?fhC;RuV~076k9Y*q m8!SeJz#*|+ra=rE6#TQ-XvR/dev/null || true +sudo rm -f /run/user/1000/wayland-* 2>/dev/null || true +sleep 1 + +echo "" +echo "🚀 Starting Vite dev server on localhost:5173..." +echo " Edit src/App.jsx -> DSI hot reloads in <1s (still localhost WebSocket)" +echo " DSI command (in another SSH):" +echo " sudo openvt -f -c 1 -s -- env XDG_RUNTIME_DIR=/run/user/1000 cage -s -- cog --platform=wl http://localhost:5173 --bg-color=#2E3440" +echo "" +./node_modules/.bin/vite --host 0.0.0.0 --port 5173 diff --git a/scripts/run-kiosk.sh b/scripts/run-kiosk.sh new file mode 100755 index 0000000..e607a57 --- /dev/null +++ b/scripts/run-kiosk.sh @@ -0,0 +1,39 @@ +#!/bin/bash +# Proven kiosk - LOCALHOST ONLY per safety boundary +set -e +MODE="${1:-dev}" # dev | prod | hello (hello only for local file test) +URL="http://localhost:5173" +BG="#2E3440" + +if [ "$MODE" = "prod" ]; then + URL="file:///home/elias/KiddOsV3/webapp/dist/index.html" +elif [ "$MODE" = "hello" ]; then + URL="file:///home/elias/KiddOsV2/browser/hello.html" +fi + +# Safety check: only allow localhost or file:// +if [[ "$URL" != http://localhost* && "$URL" != http://127.0.0.1* && "$URL" != file://* ]]; then + echo "❌ Blocked: Only localhost:5173 or file:// allowed per parent boundary! Tried: $URL" + exit 1 +fi + +echo "🔒 KiddOs v3 kiosk — localhost/file only" +echo " URL: $URL (allowed)" +echo " BG: $BG" +echo " Stopping old v2/v1 kiosks..." +sudo systemctl stop kiddos.service kiddos-browser.service journal-kiosk.service kiddos-v3.service 2>/dev/null || true +sudo pkill -9 cage cog 2>/dev/null || true +sudo rm -f /run/user/1000/wayland-* 2>/dev/null || true +sleep 1 + +if [ "$MODE" = "dev" ]; then + if ! curl -s --connect-timeout 2 http://localhost:5173/ | grep -q "KiddOs" ; then + echo "⚠️ Vite dev server not running on :5173!" + echo " Start in another SSH: cd ~/KiddOsV3/webapp && npm run dev" + echo " Falling back to prod file://" + URL="file:///home/elias/KiddOsV3/webapp/dist/index.html" + fi +fi + +echo " Starting: cage -s -- cog --platform=wl $URL" +sudo openvt -f -c 1 -s -- env XDG_RUNTIME_DIR=/run/user/1000 cage -s -- cog --platform=wl "$URL" --bg-color="$BG" diff --git a/scripts/run-prod.sh b/scripts/run-prod.sh new file mode 100755 index 0000000..f5e5cbd --- /dev/null +++ b/scripts/run-prod.sh @@ -0,0 +1,19 @@ +#!/bin/bash +# Dev helper: run both vite + quick test +set -e +cd "$(dirname "$0")/../webapp" +echo "Checking vite build..." +npm run build +echo "Build ok -> dist/" +echo "" +echo "Preview static build on http://localhost:4173 to test without HMR" +npm run preview -- --host 0.0.0.0 --port 4173 & +PREVIEW_PID=$! +echo "Preview PID $PREVIEW_PID" +sleep 2 +echo "" +echo "Try kiosk with prod file:" +echo "cage -s -- cog --platform=wl file://$PWD/dist/index.html --bg-color=#2E3440" +echo "" +echo "Press Ctrl+C to stop preview" +wait $PREVIEW_PID diff --git a/webapp/README.md b/webapp/README.md new file mode 100644 index 0000000..dd337ad --- /dev/null +++ b/webapp/README.md @@ -0,0 +1,9 @@ +# KiddOs v3 React - Hot Reload +Run dev server: +npm install +npm run dev -- --host 0.0.0.0 --port 5173 +Then on Pi DSI: +cage -s -- cog --platform=wl http://localhost:5173 --bg-color=#2E3440 +Or: +cage -s -- chromium --kiosk --ozone-platform=wayland http://localhost:5173 +Edit src/App.jsx and see hot reload instantly on DSI. diff --git a/webapp/index.html b/webapp/index.html new file mode 100644 index 0000000..b5af816 --- /dev/null +++ b/webapp/index.html @@ -0,0 +1,16 @@ + + + + + + KiddOs v3 React + + + +
+ + + diff --git a/webapp/package-lock.json b/webapp/package-lock.json new file mode 100644 index 0000000..9a42aaa --- /dev/null +++ b/webapp/package-lock.json @@ -0,0 +1,1698 @@ +{ + "name": "kiddos-v3-react", + "version": "3.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "kiddos-v3-react", + "version": "3.0.0", + "dependencies": { + "react": "^18.3.1", + "react-dom": "^18.3.1" + }, + "devDependencies": { + "@vitejs/plugin-react": "^4.3.1", + "vite": "^5.4.0" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.7.tgz", + "integrity": "sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.29.7", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.7.tgz", + "integrity": "sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.7.tgz", + "integrity": "sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.7", + "@babel/generator": "^7.29.7", + "@babel/helper-compilation-targets": "^7.29.7", + "@babel/helper-module-transforms": "^7.29.7", + "@babel/helpers": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/template": "^7.29.7", + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7", + "@jridgewell/remapping": "^2.3.5", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/generator": { + "version": "7.29.8", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.8.tgz", + "integrity": "sha512-gZbepsdh3WDtgZKWL+vTPh71LSBrm/Y4/QDZBVCcYfmeTEEuoOYwlSy+G1StfJg+/Zy550u/3TATbm7qDbbMtg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.29.8", + "@babel/types": "^7.29.8", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", + "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.29.7.tgz", + "integrity": "sha512-wem6WaBj4NaVYVdNhLPPVacES6ZJ+KBBfSkTMD3YZxbP3rm3Di85tJU5ljaUNhaOynt+Aj0xruhYuzQBt8n71g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.29.7", + "@babel/helper-validator-option": "^7.29.7", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-globals": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.29.7.tgz", + "integrity": "sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.29.7.tgz", + "integrity": "sha512-ejHwrQQYcm9xnTivShn2IDOlIzInN34AXskvq9QicvCtEzq1Vzclu/tKF8Jq1Cg8JG2GL6/EmjgsCT7lXepE3g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.29.7.tgz", + "integrity": "sha512-UPUVSyXbOh627KiCIGQSgwWzGeBKLkaJ9PJEdrngIwMSzxLR4jS4+f1f1jb7VzBbg8nFLaYotvVPFCTqdrmTAg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7", + "@babel/traverse": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.29.7.tgz", + "integrity": "sha512-G7sHYigPY17oO5SYWnfD/0MTBwVR781S/JI643e/JhUYgVgWE/61SoW3NH9KWUKyKq5LVh3npif99Wkt6j86Jw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.29.7.tgz", + "integrity": "sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz", + "integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.29.7.tgz", + "integrity": "sha512-N9ZErrD+yW5geCDtBqnOoxmR8+tNKiGuxKlDpuJxfsqpa2dFcexaziGAE/qoHLiDDreVNMupxGmSoNlyvsA3gw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.29.7.tgz", + "integrity": "sha512-1k2lAGRMfHTcwuNYcCNUmaUffmQv8KWMfh2iJUUeRlwlwH4FdNG7mfPI10NPfLHJFThE4Tyr4mv7kTNZOiPuBg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.29.8", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.8.tgz", + "integrity": "sha512-E8lTAYNB1KW+FH+VGJuZM1ioAx2E6oVlvQFRrf5P8ZZmsiJXYAD9vTFV7yyEURNzgh1dFqMZuO6tUwcARbqFCA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.8" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-self": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.29.7.tgz", + "integrity": "sha512-TL0hMc9xzy86VD31nUiwzd5otRAcyEPcsegCxolO0PvcXuH1v0kECe/UIznYFihpkvU5wg/jk4v0TTEFfm53fw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-source": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.29.7.tgz", + "integrity": "sha512-06IyK09H3wi4cGbhDBwp5gUGo0IKtnYa8tyTiephirPCK6fbobVGiXMMI5zLQ4aKEYP3wZ3ArU44o+8KMrSG/Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/template": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.29.7.tgz", + "integrity": "sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.29.8", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.8.tgz", + "integrity": "sha512-I5z7H3bf/41ktsNVLtpN0wAa336HkqIHQ5BuPLEhTkt1jVSyZpeNKIzTgEWmlxjdg81R0IgUCcaE+Ok3NvrfZg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.7", + "@babel/generator": "^7.29.8", + "@babel/helper-globals": "^7.29.7", + "@babel/parser": "^7.29.8", + "@babel/template": "^7.29.7", + "@babel/types": "^7.29.8", + "debug": "^4.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.29.8", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.8.tgz", + "integrity": "sha512-Vj1jF3cPfxg7OAfoI7QnVKLoILlm2JF9pnVHrX8qx7AHMiYWT+NDAA7jChlNgRS4WTLc/fD1lXLmPixluj+3Gg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", + "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz", + "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz", + "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz", + "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz", + "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz", + "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz", + "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz", + "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz", + "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz", + "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz", + "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz", + "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz", + "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz", + "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz", + "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz", + "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz", + "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz", + "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz", + "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz", + "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz", + "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz", + "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz", + "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@napi-rs/lzma-linux-x64-gnu": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/@napi-rs/lzma-linux-x64-gnu/-/lzma-linux-x64-gnu-1.5.1.tgz", + "integrity": "sha512-oTXEIha4SsuXdTA4Iyskj0kpdx2yVXdhd75c2v3xGrHFfVMsbhTPZU/nMPL4sWKo4pBHm3aucLaqGlF696dTyQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^22.20 || ^24.12 || >=25" + } + }, + "node_modules/@rolldown/pluginutils": { + "version": "1.0.0-beta.27", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.27.tgz", + "integrity": "sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.62.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.62.4.tgz", + "integrity": "sha512-RrPokAb7dmbxFoeO3TloqHyOjgye8RkBhSqmp4aJMIex4c9r46ZstPnleDQOq1t46VOVjwIuwNogIqbodV1Vvg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.62.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.62.4.tgz", + "integrity": "sha512-JKuJc+pnpks2pjy7L/N3v/cAkZxYlnmuZoD840ldbMI5KDbC4iO9NKwPKYdjYFCMAIIlBzYSFHxIJVYzRo2/8A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.62.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.62.4.tgz", + "integrity": "sha512-krw5uS2STmvJ02x0uTXHbqQNuz+9eZ1iw+qXk9dmW2gvV4jV7O2hEoOnuhFrpOPiel1mBFtqbxYZZtC46hXLOw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.62.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.62.4.tgz", + "integrity": "sha512-wsTxtgApb4PrOsNJIm0FZ1h3WvCC+k9uxLJ4ad75hgoS4NiRes2SoJFlDAyMwiUY8IssDqGcHbXuN0sx1tfF1A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.62.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.62.4.tgz", + "integrity": "sha512-GUOnQlyZe3yAXhWOtOMsn5Qkrv5E5mZXa0thbARWi5Ei2szlVXJFQhddZ4HbAzh8q92w5twp+CQvs/eFanz9YQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.62.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.62.4.tgz", + "integrity": "sha512-/Y7f3QuxjzPKsjA/rfEDa3+0vXqyjmJ50Ln8dPpCmWkKTrUoWHG1cWhTqaAMLob2m2nESWuC7yGrREz019Ztqg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.62.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.62.4.tgz", + "integrity": "sha512-81wiiX3v7aqy+T+bT61TJ78yJjRquqFFTTbAPt08imfQQzkPIW8t6aJbkTagtCCrXMNc9D66+geqlK7ydLPNqA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.62.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.62.4.tgz", + "integrity": "sha512-9kmDIvNZqdoHOBZgNtpTBeLWYO/LVipM3H/j62P8848/l/VPEQL6N3uxU9pvP1oZAsXyC2MEnFP3ovRjo7WYNQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.62.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.62.4.tgz", + "integrity": "sha512-CcnXHWnXg69g+DX5VWL3FHts3qMRN2uVEHX+BZvGLdd07/gXkn3ePjYtO1LDJvxkGKVHMclKBRa1QUTH+6toYQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.62.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.62.4.tgz", + "integrity": "sha512-iFOibiHnTRuhrWLlRsOQFdZJJIa7S8OwkneJr4ocALP16u5yk6lWLINFwhHaEqBFMsKDUZofLkGos7+CPzGB3g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-gnu": { + "version": "4.62.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.62.4.tgz", + "integrity": "sha512-XnWYMI7euHlb5a871xPja+Gm7DRCFU+FGRrtS2sMq9N8FvqtpagUy6gD4YOemC5MRk9xbh8+jYMEJbigFQwsgA==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-musl": { + "version": "4.62.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.62.4.tgz", + "integrity": "sha512-qGDAlO0U8xedCcsdRm9oaoQY8DAx/QT7uIxJWhCdx0ceIWX783UC9QSYkdpzAe29wNiVfp24+bZdQmn49o45SQ==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.62.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.62.4.tgz", + "integrity": "sha512-ru4H6ezD7ysA5EiEK6qkkaEb4modH8CTej6kUy/gQi20u3kB3G7Zn8snXXkeJSCOFKG/rbPPtM/+9Wgas1961w==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-musl": { + "version": "4.62.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.62.4.tgz", + "integrity": "sha512-2W4MO5WQVJnbJaZdvDb9rhBDuFU1nKIepPFpJUBsTh2k1YY2g+ODViaWuyOAjQ5cOP7NvrvLzt3wvHOoiAvc7w==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.62.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.62.4.tgz", + "integrity": "sha512-+fxjfuoAmVMCYV5QyjoIpu0cp5DOiOTeqYFk1AVaxGr+/ravWLX89XfQmptsoWcaVy/TGf2hexzbUOrCQIL1CQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.62.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.62.4.tgz", + "integrity": "sha512-jTn8JfHGL4djjFxPuM06LmNUJDsst2jeVlsd9OmIH6zc5sC9K6rIuO4YajXatLUpBmBKl6b35ro1QZocLi+tcA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.62.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.62.4.tgz", + "integrity": "sha512-oCJCJL4pXsoDcP2QZ+JVlPTIRc6266zsIaeJJsWImmF7HO0W8nb6HuSgZlMWxJwaPf8ehbSw8yo0EUw925hKsA==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.62.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.62.4.tgz", + "integrity": "sha512-W69hukhZ3KKNRCaMIEzKvcFye42hh0FE1+YoYaf5+Ikacuftoco6yO/xouz0hc5d5W/s3yBro5jRiuEE/Q5vUw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.62.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.62.4.tgz", + "integrity": "sha512-qiXbGG2jkjXhzXpsFZSR2Xpb8DN/UaxYsbb/STbuR/6fpaDgRmmaq1B/LmtF2wQFOFOSsK2jdE0RZ3a0zHn4QA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-openbsd-x64": { + "version": "4.62.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.62.4.tgz", + "integrity": "sha512-nWeM//hxv8mIo6jD7Hu4o48DVmV9pbV6gsKaWU+4NFyqHoPKwrkRiZGLKUhOBk8qNmDmpwFtPKg80Bo/Tn4xiQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ] + }, + "node_modules/@rollup/rollup-openharmony-arm64": { + "version": "4.62.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.62.4.tgz", + "integrity": "sha512-s62SQ/vgsRSvMwDkOEfTqfgASF0f26ZNaQuTA6Aok5lrikf89yI2W0gFHvZb2Jpgc6N8JnOKZgCK2iciO3CsxQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.62.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.62.4.tgz", + "integrity": "sha512-J6wGf8TVGbXJq+HH+ttTvrcfNKPbuZecV6KT1B8I18BC5IURUh5kl4Yl5OEP5eFIUoI5BWxCsyYMhFsDx8kekw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.62.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.62.4.tgz", + "integrity": "sha512-zmfrQd/0wu6oJs8Vq8KwY/YtsKSsLtKe/HwAP4Wqy8LhWjeT55fHRAkOhYQ12wI3ayS4Tt12d5CDRD7N96SAYQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-gnu": { + "version": "4.62.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.62.4.tgz", + "integrity": "sha512-qPzHqdj9rfUD+w79dtE07zi/kFwKyCJqplp5K5ygeLTp7jLpAoc16OAH39HSmRC9UpozaecsleI8uAdEj6v2yw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.62.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.62.4.tgz", + "integrity": "sha512-zD6NdeWEByGE9QF9vCrlJ5YQB4oq9q91kPZS37Jwj5hOkvR1lTBSpsKhKDw4IJtbQ35LsTS1HD9DZYGKIshU1Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@types/babel__core": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", + "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "node_modules/@types/babel__generator": { + "version": "7.27.0", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz", + "integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__template": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", + "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__traverse": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.28.0.tgz", + "integrity": "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.28.2" + } + }, + "node_modules/@types/estree": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.9.tgz", + "integrity": "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@vitejs/plugin-react": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.7.0.tgz", + "integrity": "sha512-gUu9hwfWvvEDBBmgtAowQCojwZmJ5mcLn3aufeCsitijs3+f2NsrPtlAWIR6OPiqljl96GVCUbLe0HyqIpVaoA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.28.0", + "@babel/plugin-transform-react-jsx-self": "^7.27.1", + "@babel/plugin-transform-react-jsx-source": "^7.27.1", + "@rolldown/pluginutils": "1.0.0-beta.27", + "@types/babel__core": "^7.20.5", + "react-refresh": "^0.17.0" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "peerDependencies": { + "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" + } + }, + "node_modules/baseline-browser-mapping": { + "version": "2.11.12", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.11.12.tgz", + "integrity": "sha512-r7WnVImvVCeFpf2DOXfy41aPWzeNg3H/A2X4dKmy1QL0MSyyk/e7z8ihJ3N6Nn2PsdhkVlqnEfnUE4a05P2aTA==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.cjs" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/browserslist": { + "version": "4.28.7", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.7.tgz", + "integrity": "sha512-JxV13hNrFxqjOc8alRbq9dK1MM79NEXYpma2B2J4wAtpWS5zIEIKqWPGCl7N4o7Uc7B7itylh7SuDujATRyyTw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "baseline-browser-mapping": "^2.10.44", + "caniuse-lite": "^1.0.30001806", + "electron-to-chromium": "^1.5.393", + "node-releases": "^2.0.51", + "update-browserslist-db": "^1.2.3" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001806", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001806.tgz", + "integrity": "sha512-72Cuvd95zbSYPKq6Fhg8eDJRlzgWDf7/mtoZv6Qe/DYNCEBdNxoA3+rZAU2ZhGCpZlns3EssFavaZomckT5Uuw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true, + "license": "MIT" + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/electron-to-chromium": { + "version": "1.5.400", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.400.tgz", + "integrity": "sha512-96EWDNjM59SYflgeV5Ylsf4EMiq1a25YjCnJH7cxn/AF2H3pILRweaUnoLax0yKHWdpOzY6JKEu45e8irqZIHA==", + "dev": true, + "license": "ISC" + }, + "node_modules/esbuild": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz", + "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.21.5", + "@esbuild/android-arm": "0.21.5", + "@esbuild/android-arm64": "0.21.5", + "@esbuild/android-x64": "0.21.5", + "@esbuild/darwin-arm64": "0.21.5", + "@esbuild/darwin-x64": "0.21.5", + "@esbuild/freebsd-arm64": "0.21.5", + "@esbuild/freebsd-x64": "0.21.5", + "@esbuild/linux-arm": "0.21.5", + "@esbuild/linux-arm64": "0.21.5", + "@esbuild/linux-ia32": "0.21.5", + "@esbuild/linux-loong64": "0.21.5", + "@esbuild/linux-mips64el": "0.21.5", + "@esbuild/linux-ppc64": "0.21.5", + "@esbuild/linux-riscv64": "0.21.5", + "@esbuild/linux-s390x": "0.21.5", + "@esbuild/linux-x64": "0.21.5", + "@esbuild/netbsd-x64": "0.21.5", + "@esbuild/openbsd-x64": "0.21.5", + "@esbuild/sunos-x64": "0.21.5", + "@esbuild/win32-arm64": "0.21.5", + "@esbuild/win32-ia32": "0.21.5", + "@esbuild/win32-x64": "0.21.5" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "license": "MIT" + }, + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "dev": true, + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "license": "MIT", + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/nanoid": { + "version": "3.3.17", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.17.tgz", + "integrity": "sha512-xQLf0A3HOMlgHq0n247/LRuAOYmB7dXJ/DvAxGvsSBij45XtBSmQycu+F8ODbHwns/XyFZagyL1+J0Offw1E0g==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/node-releases": { + "version": "2.0.52", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.52.tgz", + "integrity": "sha512-MRlTqhAfoMx/4mhEbPo3Hi02g9LJZaJkka69V6h67Cb1gjrAG0jsTE4CZX1eptNx+VCAwJmfpnDIF4P0Nh1A7A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/postcss": { + "version": "8.5.25", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.25.tgz", + "integrity": "sha512-DTPx3RWSSnWyzLxQnlH0rJP+EW5ekl16ZU4/psbIhA0e53kJfdgaN5vKM+xP7yJtXVu+nfdVFmlgFDEKAe4Pyw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.16", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/react": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", + "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dom": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", + "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0", + "scheduler": "^0.23.2" + }, + "peerDependencies": { + "react": "^18.3.1" + } + }, + "node_modules/react-refresh": { + "version": "0.17.0", + "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.17.0.tgz", + "integrity": "sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/rollup": { + "version": "4.62.4", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.62.4.tgz", + "integrity": "sha512-RXOqwaPsBGjMNMa4sQjDjHieHEZDFoj/Rdr46l2MU5DfEs16wHJPC2RPTPHWhNl+M3aI472LLqFkFKut4SblOg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.9" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@napi-rs/lzma-linux-x64-gnu": "1.5.1", + "@rollup/rollup-android-arm-eabi": "4.62.4", + "@rollup/rollup-android-arm64": "4.62.4", + "@rollup/rollup-darwin-arm64": "4.62.4", + "@rollup/rollup-darwin-x64": "4.62.4", + "@rollup/rollup-freebsd-arm64": "4.62.4", + "@rollup/rollup-freebsd-x64": "4.62.4", + "@rollup/rollup-linux-arm-gnueabihf": "4.62.4", + "@rollup/rollup-linux-arm-musleabihf": "4.62.4", + "@rollup/rollup-linux-arm64-gnu": "4.62.4", + "@rollup/rollup-linux-arm64-musl": "4.62.4", + "@rollup/rollup-linux-loong64-gnu": "4.62.4", + "@rollup/rollup-linux-loong64-musl": "4.62.4", + "@rollup/rollup-linux-ppc64-gnu": "4.62.4", + "@rollup/rollup-linux-ppc64-musl": "4.62.4", + "@rollup/rollup-linux-riscv64-gnu": "4.62.4", + "@rollup/rollup-linux-riscv64-musl": "4.62.4", + "@rollup/rollup-linux-s390x-gnu": "4.62.4", + "@rollup/rollup-linux-x64-gnu": "4.62.4", + "@rollup/rollup-linux-x64-musl": "4.62.4", + "@rollup/rollup-openbsd-x64": "4.62.4", + "@rollup/rollup-openharmony-arm64": "4.62.4", + "@rollup/rollup-win32-arm64-msvc": "4.62.4", + "@rollup/rollup-win32-ia32-msvc": "4.62.4", + "@rollup/rollup-win32-x64-gnu": "4.62.4", + "@rollup/rollup-win32-x64-msvc": "4.62.4", + "fsevents": "~2.3.2" + } + }, + "node_modules/scheduler": { + "version": "0.23.2", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", + "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0" + } + }, + "node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", + "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/vite": { + "version": "5.4.21", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.21.tgz", + "integrity": "sha512-o5a9xKjbtuhY6Bi5S3+HvbRERmouabWbyUcpXXUA1u+GNUKoROi9byOJ8M0nHbHYHkYICiMlqxkg1KkYmm25Sw==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "^0.21.3", + "postcss": "^8.4.43", + "rollup": "^4.20.0" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^18.0.0 || >=20.0.0", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "sass-embedded": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.4.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + } + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true, + "license": "ISC" + } + } +} diff --git a/webapp/package.json b/webapp/package.json new file mode 100644 index 0000000..87214ea --- /dev/null +++ b/webapp/package.json @@ -0,0 +1,19 @@ +{ + "name": "kiddos-v3-react", + "private": true, + "version": "3.0.0", + "type": "module", + "scripts": { + "dev": "vite --host 0.0.0.0 --port 5173", + "build": "vite build", + "preview": "vite preview --host 0.0.0.0 --port 4173" + }, + "dependencies": { + "react": "^18.3.1", + "react-dom": "^18.3.1" + }, + "devDependencies": { + "@vitejs/plugin-react": "^4.3.1", + "vite": "^5.4.0" + } +} diff --git a/webapp/public/icons/calculator.png b/webapp/public/icons/calculator.png new file mode 100644 index 0000000000000000000000000000000000000000..3118b2e20db8fe9e985b4b13eb01a6f65ae8452b GIT binary patch literal 402 zcmeAS@N?(olHy`uVBq!ia0vp^4Is?H1|$#LC7xzrV2t#1aSW-L^Y)UVV1og}fdgGf zS;ef98RR3FIb|Q7;NPEq;zs}5W!ZaV8yF23=1V@k8ZfLGJYD@<);T3K0RTKwfHD98 literal 0 HcmV?d00001 diff --git a/webapp/public/icons/clock.png b/webapp/public/icons/clock.png new file mode 100644 index 0000000000000000000000000000000000000000..8185e077b10b035a22b7d2fac5e3f7fb70af5da5 GIT binary patch literal 401 zcmeAS@N?(olHy`uVBq!ia0vp^4Is?H1|$#LC7xzrV2to|aSW-L^Y)UVV1og}fdgKy ztWv9(cr92sd)`izuRA}XaL(t2*=zU?Fi14yvdy@DwqH`=977>nhq1#P#z#B?=?xal oM@EIfA+h5;V}>ClSiUn|{j?%MHZ^=5FsKwvr nY#pOQkdQddm|+MBo$m~6fzO@aSx*)RhBbqytDnm{r-UW|VY+{O literal 0 HcmV?d00001 diff --git a/webapp/public/icons/files.png b/webapp/public/icons/files.png new file mode 100644 index 0000000000000000000000000000000000000000..9466fa639c846d1d96fbfa23388c5ea6265c6117 GIT binary patch literal 402 zcmeAS@N?(olHy`uVBq!ia0vp^4Is?H1|$#LC7xzrV2t#1aSW-L^Y)UVV1og}fdf^p zd`4QWf|?x+oU#v3@b6DQVezc&vgtj(0}K)k=Xna|THB{JSTG-vR5-^_$kt)(Fo*FG ok3jmU5I7{JF<(f61jRc>kDHlauRYh71co((r>mdKI;Vst0HI=k$p8QV literal 0 HcmV?d00001 diff --git a/webapp/public/icons/journal.png b/webapp/public/icons/journal.png new file mode 100644 index 0000000000000000000000000000000000000000..575783e46a2e92d83043946c81ad765f88e50545 GIT binary patch literal 402 zcmeAS@N?(olHy`uVBq!ia0vp^4Is?H1|$#LC7xzrV2t#1aSW-L^Y)UVV1og}fdgKy zd_r1`k{$;HJzj9Q*Zr_{K4#WGd)>z}2DSqXHE9ih_xvzqJ|d}bj-imP!`NXC<0Bq{ n^ahJjA#g}+muV1#1_i&gs%HGNZ@)JJ!c9(mrue(BlP%d)*IP=VLqb&0`O|ZTU7}gA)u6{1-oD!M<^?-nz literal 0 HcmV?d00001 diff --git a/webapp/public/icons/scratch.png b/webapp/public/icons/scratch.png new file mode 100644 index 0000000000000000000000000000000000000000..45da0af2223f2ba12095e1e763a707422dacaca1 GIT binary patch literal 401 zcmeAS@N?(olHy`uVBq!ia0vp^4Is?H1|$#LC7xzrV2to|aSW-L^Y)UVV1og}fdi{t zdBZh*G7j>2yx?%J`(f*RY@e)o?Bll#JPnLL&M-XR^TUw&h@`?fhC;RuV~076k9Y*q m8!SeJz#*|+ra=rE6#TQ-XvR localStorage.getItem('kiddos_cat') || 'All') + const [clock, setClock] = useState(new Date()) + const [showSettings, setShowSettings] = useState(false) + const [currentApp, setCurrentApp] = useState(null) + const [recents, setRecents] = useState(()=> JSON.parse(localStorage.getItem('kiddos_recents')||'[]')) + const [companionMsg, setCompanionMsg] = useState(()=> localStorage.getItem('kiddos_companion_message')||'') + const [stats, setStats] = useState(()=> { + const keys = Object.keys(localStorage).filter(k=>k.startsWith('journal_')) + return {entries: keys.length} + }) + + useEffect(()=>{ + const t=setInterval(()=>setClock(new Date()),1000) + return ()=>clearInterval(t) + },[]) + + // Local-only stats polling. Companion is local file ~/launcher_config/companion_message.txt + // We mirror via localStorage key kiddos_companion_message if parent sets it. + // No external fetch. + useEffect(()=>{ + const id=setInterval(()=>{ + const keys = Object.keys(localStorage).filter(k=>k.startsWith('journal_')) + setStats({entries: keys.length}) + const msg = localStorage.getItem('kiddos_companion_message') + if(msg) setCompanionMsg(msg) + },3000) + return ()=>clearInterval(id) + },[]) + + useEffect(()=>{ + localStorage.setItem('kiddos_cat', cat) + },[cat]) + + const saveRecent = (name)=>{ + const r=[name, ...recents.filter(n=>n!==name)].slice(0,8) + setRecents(r) + localStorage.setItem('kiddos_recents', JSON.stringify(r)) + } + + const openApp = (app)=>{ + saveRecent(app.name) + setCurrentApp(app) + } + + const filtered = (cat==='All'? APPS : APPS.filter(a=>a.category===cat)).sort((a,b)=>a.order-b.order) + const favs = JSON.parse(localStorage.getItem('kiddos_favs')||'["Journal","Code","Calculator"]') + const favApps = APPS.filter(a=>favs.includes(a.name)) + const recentApps = recents.map(n=>APPS.find(a=>a.name===n)).filter(Boolean).filter(a=>!favs.includes(a.name)) + const favToShow = [...favApps, ...recentApps].slice(0,10) + + if(currentApp){ + const Comp = COMPS[currentApp.comp] + return ( +
+
+
+ + {currentApp.emoji} + {currentApp.name} + {currentApp.category} +
+
+ {clock.toLocaleTimeString([], {hour:'2-digit', minute:'2-digit'})} • {stats.entries} entries + +
+
+
+ {Comp ? :
App {currentApp.name} coming soon
} +
+ + {showSettings &&
setShowSettings(false)} style={{position:'fixed', inset:0, background:'rgba(0,0,0,0.6)', zIndex:40}}>
} + setShowSettings(false)} stats={stats} favs={favs} onFavsChange={(f)=>{localStorage.setItem('kiddos_favs', JSON.stringify(f))}} recents={recents} /> +
+ ) + } + + return ( +
+
+
+
E
+
+
Hey, Elias! React v3 ⚡ {stats.entries} entries
+
{companionMsg ? `✨ ${companionMsg}` : 'Offline • localhost:5173 only • No internet • Hot reload'}
+
+
+
{clock.toLocaleString(undefined,{weekday:'short', month:'short', day:'numeric', hour:'2-digit', minute:'2-digit'})}
+
+ + +
+
+ +
+
+
+ ⭐ Favorites & Recent (tap → hot reload on save) + 🔒 localhost only • file:// • offline +
+
+ {favToShow.map(app=>( +
openApp(app)} style={{minWidth:'110px', height:'80px', background:'#232A36', border:'1px solid #EBCB8B', borderRadius:'12px', display:'flex', flexDirection:'column', alignItems:'center', justifyContent:'center', gap:'4px', cursor:'pointer', flexShrink:0}}> + {e.target.style.display='none'; e.target.nextSibling.style.display='block'}} style={{width:'32px', height:'32px', borderRadius:'6px'}}/> + {app.emoji} + {app.name} +
+ ))} + {favToShow.length===0 && No favorites yet — tap apps below} +
+
+ +
+ {CATS.map(c=>( + + ))} +
+ +
+ {filtered.map(app=>( +
openApp(app)} style={{width:'150px', minHeight:'132px', background:'#3B4252', border:'1px solid #4C566A', borderRadius:'16px', padding:'10px', display:'flex', flexDirection:'column', alignItems:'center', gap:'6px', cursor:'pointer'}}> +
+
+ {e.target.style.display='none'; e.target.parentElement.querySelector('.emoji-fallback').style.display='block'}} style={{width:'48px', height:'48px', borderRadius:'8px'}}/> + {app.emoji} +
+
{app.name}
+
{app.desc}
+
+ ))} +
+ +
+
+ DSI 800×480 • cage + cog wl • FT5x06 touch • Vite HMR • 🔒 localhost:5173 only +
+
+ ✅ Offline • No external URLs • localStorage • file:// fallback works +
+
+
+ + {showSettings &&
setShowSettings(false)} style={{position:'fixed', inset:0, background:'rgba(0,0,0,0.6)', zIndex:10, display:'block'}}>
} + setShowSettings(false)} stats={stats} favs={favs} onFavsChange={(f)=>{localStorage.setItem('kiddos_favs', JSON.stringify(f)); location.reload()}} recents={recents} /> +
+ ) +} + +function SettingsDrawer({open, onClose, stats, favs, onFavsChange, recents}){ + const [allApps] = useState(()=>APPS.map(a=>a.name)) + + return ( +
+
+ ⚙ KiddOs v3 React + +
+ +
+
+

📊 Stats (local)

+
+
Journal entries: {stats.entries}
+
Recents: {recents.join(', ')||'none'}
+
Touch: {'ontouchstart' in window ? 'Yes ✅' : 'No — try cage may need libinput debug'}
+
DSI: 800×480 • DRM card1 connector 49
+
UserAgent: {navigator.userAgent.slice(0,80)}
+
+
+ +
+

⭐ Favorites (local only)

+
+ {allApps.map(name=>{ + const isFav = favs.includes(name) + return ( + + ) + })} +
+
Offline • Saved in localStorage
+
+ +
+

🔒 Network lock — localhost only

+

Per safety boundary: browser may only load localhost or file:// — no external IPs. This means:

+
    +
  • ✅ http://localhost:5173 (Vite HMR dev)
  • +
  • ✅ http://127.0.0.1:5173
  • +
  • ✅ file:///home/elias/KiddOsV3/webapp/dist/index.html (prod)
  • +
  • ❌ https://scratch.mit.edu (blocked — now offline Scratch app)
  • +
+

Cog launched with --doc-viewer but no external browse. All app content is local React.

+
+ +
+

🖥️ Kiosk commands (localhost only)

+
+{`# dev server (SSH 1) — localhost only
+cd ~/KiddOsV3/webapp
+npm run dev -- --host 0.0.0.0 --port 5173
+
+# DSI (SSH 2) — only localhost, no external
+sudo openvt -f -c 1 -s -- env XDG_RUNTIME_DIR=/run/user/1000 cage -s -- \\
+  cog --platform=wl http://localhost:5173 --bg-color=#2E3440
+
+# prod file:// (no network at all)
+cd ~/KiddOsV3/webapp && npm run build
+cage -s -- cog --platform=wl file://$PWD/dist/index.html
+`}
+          
+
+ +
+

⚡ Hot reload test

+

Edit src/App.jsx on laptop via SSH, save, DSI updates in <1s via Vite WebSocket (same host:port, still localhost). Try changing greeting text or card color.

+
Test: change "Hey, Elias!" to "Hey, Elias! 🔥 HMR works!" in App.jsx and save → watch DSI
+
+
+
+ ) +} diff --git a/webapp/src/apps/Calculator.jsx b/webapp/src/apps/Calculator.jsx new file mode 100644 index 0000000..24fd290 --- /dev/null +++ b/webapp/src/apps/Calculator.jsx @@ -0,0 +1,67 @@ +import { useState } from 'react' + +export default function Calculator(){ + const [expr, setExpr] = useState('') + const [history, setHistory] = useState(()=> JSON.parse(localStorage.getItem('calc_history')||'[]')) + + const press = (c)=> setExpr(e=>e+c) + + const eq = ()=>{ + try{ + // safe-ish: only allow math chars + if(!/^[0-9+\-*/().% ]+$/.test(expr)) throw new Error('Invalid') + const res = String(Function('"use strict";return ('+expr+')')()) + const entry = expr+' = '+res + const h = [entry, ...history].slice(0,20) + setHistory(h) + localStorage.setItem('calc_history', JSON.stringify(h)) + setExpr(res) + }catch{ + setExpr('Error') + } + } + + const buttons = [ + [{l:'C', a:()=>setExpr(''), s:{background:'#D08770', color:'#000'}}, {l:'÷', a:()=>press('/'), s:{background:'#434C5E'}}, {l:'×', a:()=>press('*'), s:{background:'#434C5E'}}, {l:'⌫', a:()=>setExpr(e=>e.slice(0,-1)), s:{}}], + [{l:'7', a:()=>press('7')}, {l:'8', a:()=>press('8')}, {l:'9', a:()=>press('9')}, {l:'-', a:()=>press('-'), s:{background:'#434C5E'}}], + [{l:'4', a:()=>press('4')}, {l:'5', a:()=>press('5')}, {l:'6', a:()=>press('6')}, {l:'+', a:()=>press('+'), s:{background:'#434C5E'}}], + [{l:'1', a:()=>press('1')}, {l:'2', a:()=>press('2')}, {l:'3', a:()=>press('3')}, {l:'=', a:eq, s:{background:'#A3BE8C', color:'#000', fontWeight:'700'}}], + [{l:'0', a:()=>press('0'), span:2}, {l:'.', a:()=>press('.')}, {l:'(', a:()=>press('(')}], + ] + + return ( +
+
+
+
{expr||'0'}
+
+ {buttons.map((row,i)=>( +
+ {row.map((b,j)=>{ + const style = {height:'56px', borderRadius:'12px', border:'1px solid #4C566A', background:'#3B4252', color:'#ECEFF4', fontSize:'20px', cursor:'pointer', gridColumn: b.span ? `span ${b.span}` : 'auto', ...(b.s||{})} + return + })} +
+ ))} +
+
+
Touch friendly • Offline • localStorage history • React v3
+
+ +
+
+ History + +
+
+ {history.length===0 &&
No calculations yet
} + {history.map((h,i)=>( +
setExpr(h.split(' = ')[0])} style={{background:'#3B4252', border:'1px solid #4C566A', borderRadius:'8px', padding:'8px', cursor:'pointer'}}> +
{h}
+
+ ))} +
+
+
+ ) +} diff --git a/webapp/src/apps/Clock.jsx b/webapp/src/apps/Clock.jsx new file mode 100644 index 0000000..dd21259 --- /dev/null +++ b/webapp/src/apps/Clock.jsx @@ -0,0 +1,90 @@ +import { useState, useEffect, useRef } from 'react' + +export default function Clock(){ + const [time, setTime] = useState(new Date()) + const [timerSec, setTimerSec] = useState(0) + const [timerRunning, setTimerRunning] = useState(false) + const [mode, setMode] = useState('clock') // clock | timer | stopwatch + const [stopwatchMs, setStopwatchMs] = useState(0) + const [swRunning, setSwRunning] = useState(false) + const intervalRef = useRef(null) + + useEffect(()=>{ + const t=setInterval(()=>setTime(new Date()),1000) + return ()=>clearInterval(t) + },[]) + + useEffect(()=>{ + if(timerRunning && timerSec>0){ + intervalRef.current=setInterval(()=>setTimerSec(s=>{ if(s<=1){ setTimerRunning(false); return 0 } return s-1 }),1000) + } else { + clearInterval(intervalRef.current) + } + return ()=>clearInterval(intervalRef.current) + },[timerRunning, timerSec]) + + useEffect(()=>{ + if(!swRunning) return + const start = Date.now() - stopwatchMs + const id=setInterval(()=>setStopwatchMs(Date.now()-start), 50) + return ()=>clearInterval(id) + },[swRunning]) + + const fmt = (ms)=>{ + const totalSec=Math.floor(ms/1000) + const m=Math.floor(totalSec/60) + const s=totalSec%60 + const cs=Math.floor((ms%1000)/10) + return `${String(m).padStart(2,'0')}:${String(s).padStart(2,'0')}.${String(cs).padStart(2,'0')}` + } + const fmtSec = (sec)=>{ + const m=Math.floor(sec/60) + const s=sec%60 + return `${String(m).padStart(2,'0')}:${String(s).padStart(2,'0')}` + } + + return ( +
+
+ {['clock','timer','stopwatch'].map(m=>( + + ))} +
+ +
+ {mode==='clock' && ( + <> +
{time.toLocaleTimeString([], {hour:'2-digit', minute:'2-digit'})}
+
{time.toLocaleDateString(undefined,{weekday:'long', month:'long', day:'numeric'})}
+
DSI 800x480 • Offline • cage + cog • React v3 hot reload works
+ + )} + {mode==='timer' && ( + <> +
{fmtSec(timerSec)}
+
+ {[1,3,5,10].map(m=>( + + ))} + +
+
+ + +
+ {timerSec===0 && !timerRunning &&
🎉 Time's up!
} + + )} + {mode==='stopwatch' && ( + <> +
{fmt(stopwatchMs)}
+
+ + +
+ + )} +
+
+ ) +} diff --git a/webapp/src/apps/CodeLab.jsx b/webapp/src/apps/CodeLab.jsx new file mode 100644 index 0000000..e5936a7 --- /dev/null +++ b/webapp/src/apps/CodeLab.jsx @@ -0,0 +1,93 @@ +import { useState, useEffect } from 'react' + +const SAMPLES = { + hello: `let name = "Elias"; +console.log("Hey " + name + "!"); +for(let i=1; i<=5; i++){ + console.log(i + " x 7 = " + (i*7)); +} +function rocket(n){ + return "🚀".repeat(n) + " To the stars!"; +} +console.log(rocket(5));`, + + game: `// Tiny guessing game +let secret = Math.floor(Math.random()*10)+1; +let guesses = []; +for(let i=0;i<5;i++){ + let g = Math.floor(Math.random()*10)+1; + guesses.push(g); + console.log("Guess " + g + (g===secret ? " 🎉 HIT!" : " ..nope")); + if(g===secret) break; +} +console.log("Secret was " + secret);`, + + art: `// ASCII art loops +let w = 20; +for(let y=0;y<10;y++){ + let line=""; + for(let x=0;x localStorage.getItem('codelab_last') || SAMPLES.hello) + const [out, setOut] = useState('Click Run • Offline • React v3 hot reload \n\nEdit src/apps/CodeLab.jsx and DSI updates instantly!') + const [selectedSample, setSelectedSample] = useState('hello') + + useEffect(()=>{ + localStorage.setItem('codelab_last', code) + },[code]) + + const run=()=>{ + let logs=[] + const customLog=(...a)=>logs.push(a.map(v=>{ + if(typeof v==='object') return JSON.stringify(v, null, 2) + return String(v) + }).join(' ')) + try{ + const fn=new Function('console', '"use strict";\n'+code) + fn({log:customLog, warn:customLog, error:customLog}) + setOut(logs.length ? logs.join('\\n') : '(no output — try console.log something)') + }catch(e){ setOut('Error: '+e.message+'\\n'+(e.stack||'')) } + } + + return ( +
+
+
+
JS playground • offline • Vite HMR • Edit saves to localStorage
+
+ {Object.keys(SAMPLES).map(k=>( + + ))} +
+
+ +