├── .github └── workflows │ └── deploy.yml ├── .gitignore ├── README.md ├── bb.edn ├── index.html ├── package-lock.json ├── package.json ├── squint.edn ├── src ├── app.cljs └── app.css └── vite.config.mjs /.github/workflows/deploy.yml: -------------------------------------------------------------------------------- 1 | name: Deploy to GitHub Pages 2 | 3 | on: 4 | push: 5 | branches: [ main ] 6 | 7 | jobs: 8 | build: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - name: Checkout 12 | uses: actions/checkout@v3 13 | 14 | - name: Set up Node.js 15 | uses: actions/setup-node@v3 16 | with: 17 | node-version: '18' 18 | cache: 'npm' 19 | 20 | - name: Install Node dependencies 21 | run: npm ci 22 | 23 | - name: Install Babashka 24 | uses: just-sultanov/setup-babashka@v2 25 | with: 26 | version: '1.3.186' # Specify the version you need 27 | 28 | - name: Build 29 | run: bb build 30 | 31 | - name: Upload static files as artifact 32 | uses: actions/upload-pages-artifact@v3 # or specific "vX.X.X" version tag for this action 33 | id: deployment 34 | with: 35 | path: dist/ 36 | 37 | deploy: 38 | runs-on: ubuntu-latest 39 | needs: build 40 | permissions: 41 | pages: write 42 | id-token: write 43 | environment: 44 | name: github-pages 45 | url: ${{ steps.deployment.outputs.page_url }} 46 | steps: 47 | - name: Deploy to GitHub Pages 48 | id: deployment 49 | uses: actions/deploy-pages@v4 50 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .calva/ 2 | .clj-kondo/* 3 | !.clj-kondo/config.edn 4 | .cpcache/ 5 | .lsp/ 6 | .nrepl-port 7 | node_modules/ 8 | resources/public/assets/ 9 | resources/public/.vite/ 10 | resources/public/js/ 11 | .portal/ 12 | .npm_pid 13 | dist/ 14 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # hiccupad 2 | 3 | Convert HTML to Hiccup 4 | 5 | Use at: https://brianium.github.io/hiccupad/ 6 | 7 | ## About 8 | 9 | Really just an excuse to deploy something small with [squint](https://github.com/squint-cljs/squint), [tailwindcss](https://tailwindcss.com/), and [daisyui](https://daisyui.com/). 10 | 11 | app.cljs almost entirely written using [Cursor](https://www.cursor.com/) and [Claude 3.7 Sonnet](https://www.anthropic.com/claude/sonnet). 12 | 13 | ## Features 14 | 15 | - Convert HTML to Hiccup 16 | - Entirely client side 17 | - Copy to clipboard 18 | - Dark mode 19 | - Mobile friendly 20 | - Wraps multiple root elements in a `(list)` form 21 | 22 | ## Dev 23 | 24 | Requires 25 | - [babashka](https://github.com/babashka/babashka) for building and development. 26 | - [vite](https://vite.dev/) 27 | 28 | To develop, just run the `bb dev` task: 29 | 30 | ```bash 31 | $ bb dev 32 | ``` 33 | 34 | This will start squint's watch mode and the vite dev server. View the app at [http://localhost:5173](http://localhost:5173). 35 | 36 | 37 | -------------------------------------------------------------------------------- /bb.edn: -------------------------------------------------------------------------------- 1 | {:deps 2 | {org.babashka/json {:mvn/version "0.1.6"}} 3 | 4 | :tasks 5 | {:requires ([babashka.json :as json] 6 | [clojure.string :as str]) 7 | 8 | dev:squint (shell "npx squint watch --repl true") 9 | dev:vite (shell "npx vite") 10 | -dev {:depends [dev:squint dev:vite]} 11 | dev (run '-dev {:parallel true}) 12 | 13 | build:squint (shell "npx squint compile") 14 | build:vite (shell "npx vite build") 15 | 16 | update-html {:doc "Update index.html with hashed filenames from Vite manifest" 17 | :task (let [manifest (json/read-str (slurp "dist/.vite/manifest.json") {:key-fn identity}) 18 | css-path (get-in manifest ["src/app.css" "file"]) 19 | js-path (get-in manifest ["dist/app.js" "file"]) 20 | html (slurp "index.html") 21 | updated-html (-> html 22 | (str/replace "/src/app.css" css-path) 23 | (str/replace "/dist/app.js" js-path))] 24 | ;; Copy index.html to dist directory 25 | (spit "dist/index.html" updated-html) 26 | (println "✓ Updated index.html with manifest paths and copied to dist/"))} 27 | 28 | build {:depends [build:squint build:vite update-html]}}} 29 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | hiccupad - HTML to Hiccup 10 | 19 | 20 | 21 |
22 | 38 | 39 |
40 |
41 | 42 | 47 |
48 |
49 |
50 |
51 |
52 | 60 |
61 |
62 |
63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "hiccalpine", 3 | "version": "1.0.0", 4 | "lockfileVersion": 3, 5 | "requires": true, 6 | "packages": { 7 | "": { 8 | "name": "hiccalpine", 9 | "version": "1.0.0", 10 | "license": "MIT", 11 | "dependencies": { 12 | "squint-cljs": "^0.8.141", 13 | "tailwindcss": "^4.0.12" 14 | }, 15 | "devDependencies": { 16 | "@tailwindcss/vite": "^4.0.13", 17 | "daisyui": "^5.0.2", 18 | "vite": "^6.2.1" 19 | } 20 | }, 21 | "node_modules/@esbuild/aix-ppc64": { 22 | "version": "0.25.1", 23 | "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.1.tgz", 24 | "integrity": "sha512-kfYGy8IdzTGy+z0vFGvExZtxkFlA4zAxgKEahG9KE1ScBjpQnFsNOX8KTU5ojNru5ed5CVoJYXFtoxaq5nFbjQ==", 25 | "cpu": [ 26 | "ppc64" 27 | ], 28 | "dev": true, 29 | "optional": true, 30 | "os": [ 31 | "aix" 32 | ], 33 | "engines": { 34 | "node": ">=18" 35 | } 36 | }, 37 | "node_modules/@esbuild/android-arm": { 38 | "version": "0.25.1", 39 | "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.1.tgz", 40 | "integrity": "sha512-dp+MshLYux6j/JjdqVLnMglQlFu+MuVeNrmT5nk6q07wNhCdSnB7QZj+7G8VMUGh1q+vj2Bq8kRsuyA00I/k+Q==", 41 | "cpu": [ 42 | "arm" 43 | ], 44 | "dev": true, 45 | "optional": true, 46 | "os": [ 47 | "android" 48 | ], 49 | "engines": { 50 | "node": ">=18" 51 | } 52 | }, 53 | "node_modules/@esbuild/android-arm64": { 54 | "version": "0.25.1", 55 | "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.1.tgz", 56 | "integrity": "sha512-50tM0zCJW5kGqgG7fQ7IHvQOcAn9TKiVRuQ/lN0xR+T2lzEFvAi1ZcS8DiksFcEpf1t/GYOeOfCAgDHFpkiSmA==", 57 | "cpu": [ 58 | "arm64" 59 | ], 60 | "dev": true, 61 | "optional": true, 62 | "os": [ 63 | "android" 64 | ], 65 | "engines": { 66 | "node": ">=18" 67 | } 68 | }, 69 | "node_modules/@esbuild/android-x64": { 70 | "version": "0.25.1", 71 | "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.1.tgz", 72 | "integrity": "sha512-GCj6WfUtNldqUzYkN/ITtlhwQqGWu9S45vUXs7EIYf+7rCiiqH9bCloatO9VhxsL0Pji+PF4Lz2XXCES+Q8hDw==", 73 | "cpu": [ 74 | "x64" 75 | ], 76 | "dev": true, 77 | "optional": true, 78 | "os": [ 79 | "android" 80 | ], 81 | "engines": { 82 | "node": ">=18" 83 | } 84 | }, 85 | "node_modules/@esbuild/darwin-arm64": { 86 | "version": "0.25.1", 87 | "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.1.tgz", 88 | "integrity": "sha512-5hEZKPf+nQjYoSr/elb62U19/l1mZDdqidGfmFutVUjjUZrOazAtwK+Kr+3y0C/oeJfLlxo9fXb1w7L+P7E4FQ==", 89 | "cpu": [ 90 | "arm64" 91 | ], 92 | "dev": true, 93 | "optional": true, 94 | "os": [ 95 | "darwin" 96 | ], 97 | "engines": { 98 | "node": ">=18" 99 | } 100 | }, 101 | "node_modules/@esbuild/darwin-x64": { 102 | "version": "0.25.1", 103 | "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.1.tgz", 104 | "integrity": "sha512-hxVnwL2Dqs3fM1IWq8Iezh0cX7ZGdVhbTfnOy5uURtao5OIVCEyj9xIzemDi7sRvKsuSdtCAhMKarxqtlyVyfA==", 105 | "cpu": [ 106 | "x64" 107 | ], 108 | "dev": true, 109 | "optional": true, 110 | "os": [ 111 | "darwin" 112 | ], 113 | "engines": { 114 | "node": ">=18" 115 | } 116 | }, 117 | "node_modules/@esbuild/freebsd-arm64": { 118 | "version": "0.25.1", 119 | "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.1.tgz", 120 | "integrity": "sha512-1MrCZs0fZa2g8E+FUo2ipw6jw5qqQiH+tERoS5fAfKnRx6NXH31tXBKI3VpmLijLH6yriMZsxJtaXUyFt/8Y4A==", 121 | "cpu": [ 122 | "arm64" 123 | ], 124 | "dev": true, 125 | "optional": true, 126 | "os": [ 127 | "freebsd" 128 | ], 129 | "engines": { 130 | "node": ">=18" 131 | } 132 | }, 133 | "node_modules/@esbuild/freebsd-x64": { 134 | "version": "0.25.1", 135 | "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.1.tgz", 136 | "integrity": "sha512-0IZWLiTyz7nm0xuIs0q1Y3QWJC52R8aSXxe40VUxm6BB1RNmkODtW6LHvWRrGiICulcX7ZvyH6h5fqdLu4gkww==", 137 | "cpu": [ 138 | "x64" 139 | ], 140 | "dev": true, 141 | "optional": true, 142 | "os": [ 143 | "freebsd" 144 | ], 145 | "engines": { 146 | "node": ">=18" 147 | } 148 | }, 149 | "node_modules/@esbuild/linux-arm": { 150 | "version": "0.25.1", 151 | "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.1.tgz", 152 | "integrity": "sha512-NdKOhS4u7JhDKw9G3cY6sWqFcnLITn6SqivVArbzIaf3cemShqfLGHYMx8Xlm/lBit3/5d7kXvriTUGa5YViuQ==", 153 | "cpu": [ 154 | "arm" 155 | ], 156 | "dev": true, 157 | "optional": true, 158 | "os": [ 159 | "linux" 160 | ], 161 | "engines": { 162 | "node": ">=18" 163 | } 164 | }, 165 | "node_modules/@esbuild/linux-arm64": { 166 | "version": "0.25.1", 167 | "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.1.tgz", 168 | "integrity": "sha512-jaN3dHi0/DDPelk0nLcXRm1q7DNJpjXy7yWaWvbfkPvI+7XNSc/lDOnCLN7gzsyzgu6qSAmgSvP9oXAhP973uQ==", 169 | "cpu": [ 170 | "arm64" 171 | ], 172 | "dev": true, 173 | "optional": true, 174 | "os": [ 175 | "linux" 176 | ], 177 | "engines": { 178 | "node": ">=18" 179 | } 180 | }, 181 | "node_modules/@esbuild/linux-ia32": { 182 | "version": "0.25.1", 183 | "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.1.tgz", 184 | "integrity": "sha512-OJykPaF4v8JidKNGz8c/q1lBO44sQNUQtq1KktJXdBLn1hPod5rE/Hko5ugKKZd+D2+o1a9MFGUEIUwO2YfgkQ==", 185 | "cpu": [ 186 | "ia32" 187 | ], 188 | "dev": true, 189 | "optional": true, 190 | "os": [ 191 | "linux" 192 | ], 193 | "engines": { 194 | "node": ">=18" 195 | } 196 | }, 197 | "node_modules/@esbuild/linux-loong64": { 198 | "version": "0.25.1", 199 | "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.1.tgz", 200 | "integrity": "sha512-nGfornQj4dzcq5Vp835oM/o21UMlXzn79KobKlcs3Wz9smwiifknLy4xDCLUU0BWp7b/houtdrgUz7nOGnfIYg==", 201 | "cpu": [ 202 | "loong64" 203 | ], 204 | "dev": true, 205 | "optional": true, 206 | "os": [ 207 | "linux" 208 | ], 209 | "engines": { 210 | "node": ">=18" 211 | } 212 | }, 213 | "node_modules/@esbuild/linux-mips64el": { 214 | "version": "0.25.1", 215 | "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.1.tgz", 216 | "integrity": "sha512-1osBbPEFYwIE5IVB/0g2X6i1qInZa1aIoj1TdL4AaAb55xIIgbg8Doq6a5BzYWgr+tEcDzYH67XVnTmUzL+nXg==", 217 | "cpu": [ 218 | "mips64el" 219 | ], 220 | "dev": true, 221 | "optional": true, 222 | "os": [ 223 | "linux" 224 | ], 225 | "engines": { 226 | "node": ">=18" 227 | } 228 | }, 229 | "node_modules/@esbuild/linux-ppc64": { 230 | "version": "0.25.1", 231 | "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.1.tgz", 232 | "integrity": "sha512-/6VBJOwUf3TdTvJZ82qF3tbLuWsscd7/1w+D9LH0W/SqUgM5/JJD0lrJ1fVIfZsqB6RFmLCe0Xz3fmZc3WtyVg==", 233 | "cpu": [ 234 | "ppc64" 235 | ], 236 | "dev": true, 237 | "optional": true, 238 | "os": [ 239 | "linux" 240 | ], 241 | "engines": { 242 | "node": ">=18" 243 | } 244 | }, 245 | "node_modules/@esbuild/linux-riscv64": { 246 | "version": "0.25.1", 247 | "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.1.tgz", 248 | "integrity": "sha512-nSut/Mx5gnilhcq2yIMLMe3Wl4FK5wx/o0QuuCLMtmJn+WeWYoEGDN1ipcN72g1WHsnIbxGXd4i/MF0gTcuAjQ==", 249 | "cpu": [ 250 | "riscv64" 251 | ], 252 | "dev": true, 253 | "optional": true, 254 | "os": [ 255 | "linux" 256 | ], 257 | "engines": { 258 | "node": ">=18" 259 | } 260 | }, 261 | "node_modules/@esbuild/linux-s390x": { 262 | "version": "0.25.1", 263 | "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.1.tgz", 264 | "integrity": "sha512-cEECeLlJNfT8kZHqLarDBQso9a27o2Zd2AQ8USAEoGtejOrCYHNtKP8XQhMDJMtthdF4GBmjR2au3x1udADQQQ==", 265 | "cpu": [ 266 | "s390x" 267 | ], 268 | "dev": true, 269 | "optional": true, 270 | "os": [ 271 | "linux" 272 | ], 273 | "engines": { 274 | "node": ">=18" 275 | } 276 | }, 277 | "node_modules/@esbuild/linux-x64": { 278 | "version": "0.25.1", 279 | "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.1.tgz", 280 | "integrity": "sha512-xbfUhu/gnvSEg+EGovRc+kjBAkrvtk38RlerAzQxvMzlB4fXpCFCeUAYzJvrnhFtdeyVCDANSjJvOvGYoeKzFA==", 281 | "cpu": [ 282 | "x64" 283 | ], 284 | "dev": true, 285 | "optional": true, 286 | "os": [ 287 | "linux" 288 | ], 289 | "engines": { 290 | "node": ">=18" 291 | } 292 | }, 293 | "node_modules/@esbuild/netbsd-arm64": { 294 | "version": "0.25.1", 295 | "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.1.tgz", 296 | "integrity": "sha512-O96poM2XGhLtpTh+s4+nP7YCCAfb4tJNRVZHfIE7dgmax+yMP2WgMd2OecBuaATHKTHsLWHQeuaxMRnCsH8+5g==", 297 | "cpu": [ 298 | "arm64" 299 | ], 300 | "dev": true, 301 | "optional": true, 302 | "os": [ 303 | "netbsd" 304 | ], 305 | "engines": { 306 | "node": ">=18" 307 | } 308 | }, 309 | "node_modules/@esbuild/netbsd-x64": { 310 | "version": "0.25.1", 311 | "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.1.tgz", 312 | "integrity": "sha512-X53z6uXip6KFXBQ+Krbx25XHV/NCbzryM6ehOAeAil7X7oa4XIq+394PWGnwaSQ2WRA0KI6PUO6hTO5zeF5ijA==", 313 | "cpu": [ 314 | "x64" 315 | ], 316 | "dev": true, 317 | "optional": true, 318 | "os": [ 319 | "netbsd" 320 | ], 321 | "engines": { 322 | "node": ">=18" 323 | } 324 | }, 325 | "node_modules/@esbuild/openbsd-arm64": { 326 | "version": "0.25.1", 327 | "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.1.tgz", 328 | "integrity": "sha512-Na9T3szbXezdzM/Kfs3GcRQNjHzM6GzFBeU1/6IV/npKP5ORtp9zbQjvkDJ47s6BCgaAZnnnu/cY1x342+MvZg==", 329 | "cpu": [ 330 | "arm64" 331 | ], 332 | "dev": true, 333 | "optional": true, 334 | "os": [ 335 | "openbsd" 336 | ], 337 | "engines": { 338 | "node": ">=18" 339 | } 340 | }, 341 | "node_modules/@esbuild/openbsd-x64": { 342 | "version": "0.25.1", 343 | "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.1.tgz", 344 | "integrity": "sha512-T3H78X2h1tszfRSf+txbt5aOp/e7TAz3ptVKu9Oyir3IAOFPGV6O9c2naym5TOriy1l0nNf6a4X5UXRZSGX/dw==", 345 | "cpu": [ 346 | "x64" 347 | ], 348 | "dev": true, 349 | "optional": true, 350 | "os": [ 351 | "openbsd" 352 | ], 353 | "engines": { 354 | "node": ">=18" 355 | } 356 | }, 357 | "node_modules/@esbuild/sunos-x64": { 358 | "version": "0.25.1", 359 | "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.1.tgz", 360 | "integrity": "sha512-2H3RUvcmULO7dIE5EWJH8eubZAI4xw54H1ilJnRNZdeo8dTADEZ21w6J22XBkXqGJbe0+wnNJtw3UXRoLJnFEg==", 361 | "cpu": [ 362 | "x64" 363 | ], 364 | "dev": true, 365 | "optional": true, 366 | "os": [ 367 | "sunos" 368 | ], 369 | "engines": { 370 | "node": ">=18" 371 | } 372 | }, 373 | "node_modules/@esbuild/win32-arm64": { 374 | "version": "0.25.1", 375 | "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.1.tgz", 376 | "integrity": "sha512-GE7XvrdOzrb+yVKB9KsRMq+7a2U/K5Cf/8grVFRAGJmfADr/e/ODQ134RK2/eeHqYV5eQRFxb1hY7Nr15fv1NQ==", 377 | "cpu": [ 378 | "arm64" 379 | ], 380 | "dev": true, 381 | "optional": true, 382 | "os": [ 383 | "win32" 384 | ], 385 | "engines": { 386 | "node": ">=18" 387 | } 388 | }, 389 | "node_modules/@esbuild/win32-ia32": { 390 | "version": "0.25.1", 391 | "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.1.tgz", 392 | "integrity": "sha512-uOxSJCIcavSiT6UnBhBzE8wy3n0hOkJsBOzy7HDAuTDE++1DJMRRVCPGisULScHL+a/ZwdXPpXD3IyFKjA7K8A==", 393 | "cpu": [ 394 | "ia32" 395 | ], 396 | "dev": true, 397 | "optional": true, 398 | "os": [ 399 | "win32" 400 | ], 401 | "engines": { 402 | "node": ">=18" 403 | } 404 | }, 405 | "node_modules/@esbuild/win32-x64": { 406 | "version": "0.25.1", 407 | "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.1.tgz", 408 | "integrity": "sha512-Y1EQdcfwMSeQN/ujR5VayLOJ1BHaK+ssyk0AEzPjC+t1lITgsnccPqFjb6V+LsTp/9Iov4ysfjxLaGJ9RPtkVg==", 409 | "cpu": [ 410 | "x64" 411 | ], 412 | "dev": true, 413 | "optional": true, 414 | "os": [ 415 | "win32" 416 | ], 417 | "engines": { 418 | "node": ">=18" 419 | } 420 | }, 421 | "node_modules/@rollup/rollup-android-arm-eabi": { 422 | "version": "4.35.0", 423 | "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.35.0.tgz", 424 | "integrity": "sha512-uYQ2WfPaqz5QtVgMxfN6NpLD+no0MYHDBywl7itPYd3K5TjjSghNKmX8ic9S8NU8w81NVhJv/XojcHptRly7qQ==", 425 | "cpu": [ 426 | "arm" 427 | ], 428 | "dev": true, 429 | "optional": true, 430 | "os": [ 431 | "android" 432 | ] 433 | }, 434 | "node_modules/@rollup/rollup-android-arm64": { 435 | "version": "4.35.0", 436 | "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.35.0.tgz", 437 | "integrity": "sha512-FtKddj9XZudurLhdJnBl9fl6BwCJ3ky8riCXjEw3/UIbjmIY58ppWwPEvU3fNu+W7FUsAsB1CdH+7EQE6CXAPA==", 438 | "cpu": [ 439 | "arm64" 440 | ], 441 | "dev": true, 442 | "optional": true, 443 | "os": [ 444 | "android" 445 | ] 446 | }, 447 | "node_modules/@rollup/rollup-darwin-arm64": { 448 | "version": "4.35.0", 449 | "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.35.0.tgz", 450 | "integrity": "sha512-Uk+GjOJR6CY844/q6r5DR/6lkPFOw0hjfOIzVx22THJXMxktXG6CbejseJFznU8vHcEBLpiXKY3/6xc+cBm65Q==", 451 | "cpu": [ 452 | "arm64" 453 | ], 454 | "dev": true, 455 | "optional": true, 456 | "os": [ 457 | "darwin" 458 | ] 459 | }, 460 | "node_modules/@rollup/rollup-darwin-x64": { 461 | "version": "4.35.0", 462 | "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.35.0.tgz", 463 | "integrity": "sha512-3IrHjfAS6Vkp+5bISNQnPogRAW5GAV1n+bNCrDwXmfMHbPl5EhTmWtfmwlJxFRUCBZ+tZ/OxDyU08aF6NI/N5Q==", 464 | "cpu": [ 465 | "x64" 466 | ], 467 | "dev": true, 468 | "optional": true, 469 | "os": [ 470 | "darwin" 471 | ] 472 | }, 473 | "node_modules/@rollup/rollup-freebsd-arm64": { 474 | "version": "4.35.0", 475 | "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.35.0.tgz", 476 | "integrity": "sha512-sxjoD/6F9cDLSELuLNnY0fOrM9WA0KrM0vWm57XhrIMf5FGiN8D0l7fn+bpUeBSU7dCgPV2oX4zHAsAXyHFGcQ==", 477 | "cpu": [ 478 | "arm64" 479 | ], 480 | "dev": true, 481 | "optional": true, 482 | "os": [ 483 | "freebsd" 484 | ] 485 | }, 486 | "node_modules/@rollup/rollup-freebsd-x64": { 487 | "version": "4.35.0", 488 | "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.35.0.tgz", 489 | "integrity": "sha512-2mpHCeRuD1u/2kruUiHSsnjWtHjqVbzhBkNVQ1aVD63CcexKVcQGwJ2g5VphOd84GvxfSvnnlEyBtQCE5hxVVw==", 490 | "cpu": [ 491 | "x64" 492 | ], 493 | "dev": true, 494 | "optional": true, 495 | "os": [ 496 | "freebsd" 497 | ] 498 | }, 499 | "node_modules/@rollup/rollup-linux-arm-gnueabihf": { 500 | "version": "4.35.0", 501 | "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.35.0.tgz", 502 | "integrity": "sha512-mrA0v3QMy6ZSvEuLs0dMxcO2LnaCONs1Z73GUDBHWbY8tFFocM6yl7YyMu7rz4zS81NDSqhrUuolyZXGi8TEqg==", 503 | "cpu": [ 504 | "arm" 505 | ], 506 | "dev": true, 507 | "optional": true, 508 | "os": [ 509 | "linux" 510 | ] 511 | }, 512 | "node_modules/@rollup/rollup-linux-arm-musleabihf": { 513 | "version": "4.35.0", 514 | "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.35.0.tgz", 515 | "integrity": "sha512-DnYhhzcvTAKNexIql8pFajr0PiDGrIsBYPRvCKlA5ixSS3uwo/CWNZxB09jhIapEIg945KOzcYEAGGSmTSpk7A==", 516 | "cpu": [ 517 | "arm" 518 | ], 519 | "dev": true, 520 | "optional": true, 521 | "os": [ 522 | "linux" 523 | ] 524 | }, 525 | "node_modules/@rollup/rollup-linux-arm64-gnu": { 526 | "version": "4.35.0", 527 | "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.35.0.tgz", 528 | "integrity": "sha512-uagpnH2M2g2b5iLsCTZ35CL1FgyuzzJQ8L9VtlJ+FckBXroTwNOaD0z0/UF+k5K3aNQjbm8LIVpxykUOQt1m/A==", 529 | "cpu": [ 530 | "arm64" 531 | ], 532 | "dev": true, 533 | "optional": true, 534 | "os": [ 535 | "linux" 536 | ] 537 | }, 538 | "node_modules/@rollup/rollup-linux-arm64-musl": { 539 | "version": "4.35.0", 540 | "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.35.0.tgz", 541 | "integrity": "sha512-XQxVOCd6VJeHQA/7YcqyV0/88N6ysSVzRjJ9I9UA/xXpEsjvAgDTgH3wQYz5bmr7SPtVK2TsP2fQ2N9L4ukoUg==", 542 | "cpu": [ 543 | "arm64" 544 | ], 545 | "dev": true, 546 | "optional": true, 547 | "os": [ 548 | "linux" 549 | ] 550 | }, 551 | "node_modules/@rollup/rollup-linux-loongarch64-gnu": { 552 | "version": "4.35.0", 553 | "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.35.0.tgz", 554 | "integrity": "sha512-5pMT5PzfgwcXEwOaSrqVsz/LvjDZt+vQ8RT/70yhPU06PTuq8WaHhfT1LW+cdD7mW6i/J5/XIkX/1tCAkh1W6g==", 555 | "cpu": [ 556 | "loong64" 557 | ], 558 | "dev": true, 559 | "optional": true, 560 | "os": [ 561 | "linux" 562 | ] 563 | }, 564 | "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { 565 | "version": "4.35.0", 566 | "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.35.0.tgz", 567 | "integrity": "sha512-c+zkcvbhbXF98f4CtEIP1EBA/lCic5xB0lToneZYvMeKu5Kamq3O8gqrxiYYLzlZH6E3Aq+TSW86E4ay8iD8EA==", 568 | "cpu": [ 569 | "ppc64" 570 | ], 571 | "dev": true, 572 | "optional": true, 573 | "os": [ 574 | "linux" 575 | ] 576 | }, 577 | "node_modules/@rollup/rollup-linux-riscv64-gnu": { 578 | "version": "4.35.0", 579 | "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.35.0.tgz", 580 | "integrity": "sha512-s91fuAHdOwH/Tad2tzTtPX7UZyytHIRR6V4+2IGlV0Cej5rkG0R61SX4l4y9sh0JBibMiploZx3oHKPnQBKe4g==", 581 | "cpu": [ 582 | "riscv64" 583 | ], 584 | "dev": true, 585 | "optional": true, 586 | "os": [ 587 | "linux" 588 | ] 589 | }, 590 | "node_modules/@rollup/rollup-linux-s390x-gnu": { 591 | "version": "4.35.0", 592 | "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.35.0.tgz", 593 | "integrity": "sha512-hQRkPQPLYJZYGP+Hj4fR9dDBMIM7zrzJDWFEMPdTnTy95Ljnv0/4w/ixFw3pTBMEuuEuoqtBINYND4M7ujcuQw==", 594 | "cpu": [ 595 | "s390x" 596 | ], 597 | "dev": true, 598 | "optional": true, 599 | "os": [ 600 | "linux" 601 | ] 602 | }, 603 | "node_modules/@rollup/rollup-linux-x64-gnu": { 604 | "version": "4.35.0", 605 | "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.35.0.tgz", 606 | "integrity": "sha512-Pim1T8rXOri+0HmV4CdKSGrqcBWX0d1HoPnQ0uw0bdp1aP5SdQVNBy8LjYncvnLgu3fnnCt17xjWGd4cqh8/hA==", 607 | "cpu": [ 608 | "x64" 609 | ], 610 | "dev": true, 611 | "optional": true, 612 | "os": [ 613 | "linux" 614 | ] 615 | }, 616 | "node_modules/@rollup/rollup-linux-x64-musl": { 617 | "version": "4.35.0", 618 | "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.35.0.tgz", 619 | "integrity": "sha512-QysqXzYiDvQWfUiTm8XmJNO2zm9yC9P/2Gkrwg2dH9cxotQzunBHYr6jk4SujCTqnfGxduOmQcI7c2ryuW8XVg==", 620 | "cpu": [ 621 | "x64" 622 | ], 623 | "dev": true, 624 | "optional": true, 625 | "os": [ 626 | "linux" 627 | ] 628 | }, 629 | "node_modules/@rollup/rollup-win32-arm64-msvc": { 630 | "version": "4.35.0", 631 | "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.35.0.tgz", 632 | "integrity": "sha512-OUOlGqPkVJCdJETKOCEf1mw848ZyJ5w50/rZ/3IBQVdLfR5jk/6Sr5m3iO2tdPgwo0x7VcncYuOvMhBWZq8ayg==", 633 | "cpu": [ 634 | "arm64" 635 | ], 636 | "dev": true, 637 | "optional": true, 638 | "os": [ 639 | "win32" 640 | ] 641 | }, 642 | "node_modules/@rollup/rollup-win32-ia32-msvc": { 643 | "version": "4.35.0", 644 | "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.35.0.tgz", 645 | "integrity": "sha512-2/lsgejMrtwQe44glq7AFFHLfJBPafpsTa6JvP2NGef/ifOa4KBoglVf7AKN7EV9o32evBPRqfg96fEHzWo5kw==", 646 | "cpu": [ 647 | "ia32" 648 | ], 649 | "dev": true, 650 | "optional": true, 651 | "os": [ 652 | "win32" 653 | ] 654 | }, 655 | "node_modules/@rollup/rollup-win32-x64-msvc": { 656 | "version": "4.35.0", 657 | "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.35.0.tgz", 658 | "integrity": "sha512-PIQeY5XDkrOysbQblSW7v3l1MDZzkTEzAfTPkj5VAu3FW8fS4ynyLg2sINp0fp3SjZ8xkRYpLqoKcYqAkhU1dw==", 659 | "cpu": [ 660 | "x64" 661 | ], 662 | "dev": true, 663 | "optional": true, 664 | "os": [ 665 | "win32" 666 | ] 667 | }, 668 | "node_modules/@tailwindcss/node": { 669 | "version": "4.0.13", 670 | "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.0.13.tgz", 671 | "integrity": "sha512-P9TmtE9Vew0vv5FwyD4bsg/dHHsIsAuUXkenuGUc5gm8fYgaxpdoxIKngCyEMEQxyCKR8PQY5V5VrrKNOx7exg==", 672 | "dev": true, 673 | "dependencies": { 674 | "enhanced-resolve": "^5.18.1", 675 | "jiti": "^2.4.2", 676 | "tailwindcss": "4.0.13" 677 | } 678 | }, 679 | "node_modules/@tailwindcss/oxide": { 680 | "version": "4.0.13", 681 | "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.0.13.tgz", 682 | "integrity": "sha512-pTH3Ex5zAWC9LbS+WsYAFmkXQW3NRjmvxkKJY3NP1x0KHBWjz0Q2uGtdGMJzsa0EwoZ7wq9RTbMH1UNPceCpWw==", 683 | "dev": true, 684 | "engines": { 685 | "node": ">= 10" 686 | }, 687 | "optionalDependencies": { 688 | "@tailwindcss/oxide-android-arm64": "4.0.13", 689 | "@tailwindcss/oxide-darwin-arm64": "4.0.13", 690 | "@tailwindcss/oxide-darwin-x64": "4.0.13", 691 | "@tailwindcss/oxide-freebsd-x64": "4.0.13", 692 | "@tailwindcss/oxide-linux-arm-gnueabihf": "4.0.13", 693 | "@tailwindcss/oxide-linux-arm64-gnu": "4.0.13", 694 | "@tailwindcss/oxide-linux-arm64-musl": "4.0.13", 695 | "@tailwindcss/oxide-linux-x64-gnu": "4.0.13", 696 | "@tailwindcss/oxide-linux-x64-musl": "4.0.13", 697 | "@tailwindcss/oxide-win32-arm64-msvc": "4.0.13", 698 | "@tailwindcss/oxide-win32-x64-msvc": "4.0.13" 699 | } 700 | }, 701 | "node_modules/@tailwindcss/oxide-android-arm64": { 702 | "version": "4.0.13", 703 | "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.0.13.tgz", 704 | "integrity": "sha512-+9zmwaPQ8A9ycDcdb+hRkMn6NzsmZ4YJBsW5Xqq5EdOu9xlIgmuMuJauVzDPB5BSbIWfhPdZ+le8NeRZpl1coA==", 705 | "cpu": [ 706 | "arm64" 707 | ], 708 | "dev": true, 709 | "optional": true, 710 | "os": [ 711 | "android" 712 | ], 713 | "engines": { 714 | "node": ">= 10" 715 | } 716 | }, 717 | "node_modules/@tailwindcss/oxide-darwin-arm64": { 718 | "version": "4.0.13", 719 | "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.0.13.tgz", 720 | "integrity": "sha512-Bj1QGlEJSjs/205CIRfb5/jeveOqzJ4pFMdRxu0gyiYWxBRyxsExXqaD+7162wnLP/EDKh6S1MC9E/1GwEhLtA==", 721 | "cpu": [ 722 | "arm64" 723 | ], 724 | "dev": true, 725 | "optional": true, 726 | "os": [ 727 | "darwin" 728 | ], 729 | "engines": { 730 | "node": ">= 10" 731 | } 732 | }, 733 | "node_modules/@tailwindcss/oxide-darwin-x64": { 734 | "version": "4.0.13", 735 | "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.0.13.tgz", 736 | "integrity": "sha512-lRTkxjTpMGXhLLM5GjZ0MtjPczMuhAo9j7PeSsaU6Imkm7W7RbrXfT8aP934kS7cBBV+HKN5U19Z0WWaORfb8Q==", 737 | "cpu": [ 738 | "x64" 739 | ], 740 | "dev": true, 741 | "optional": true, 742 | "os": [ 743 | "darwin" 744 | ], 745 | "engines": { 746 | "node": ">= 10" 747 | } 748 | }, 749 | "node_modules/@tailwindcss/oxide-freebsd-x64": { 750 | "version": "4.0.13", 751 | "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.0.13.tgz", 752 | "integrity": "sha512-p/YLyKhs+xFibVeAPlpMGDVMKgjChgzs12VnDFaaqRSJoOz+uJgRSKiir2tn50e7Nm4YYw35q/DRBwpDBNo1MQ==", 753 | "cpu": [ 754 | "x64" 755 | ], 756 | "dev": true, 757 | "optional": true, 758 | "os": [ 759 | "freebsd" 760 | ], 761 | "engines": { 762 | "node": ">= 10" 763 | } 764 | }, 765 | "node_modules/@tailwindcss/oxide-linux-arm-gnueabihf": { 766 | "version": "4.0.13", 767 | "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.0.13.tgz", 768 | "integrity": "sha512-Ua/5ydE/QOTX8jHuc7M9ICWnaLi6K2MV/r+Ws2OppsOjy8tdlPbqYainJJ6Kl7ofm524K+4Fk9CQITPzeIESPw==", 769 | "cpu": [ 770 | "arm" 771 | ], 772 | "dev": true, 773 | "optional": true, 774 | "os": [ 775 | "linux" 776 | ], 777 | "engines": { 778 | "node": ">= 10" 779 | } 780 | }, 781 | "node_modules/@tailwindcss/oxide-linux-arm64-gnu": { 782 | "version": "4.0.13", 783 | "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.0.13.tgz", 784 | "integrity": "sha512-/W1+Q6tBAVgZWh/bhfOHo4n7Ryh6E7zYj4bJd9SRbkPyLtRioyK3bi6RLuDj57sa7Amk/DeomSV9iycS0xqIPA==", 785 | "cpu": [ 786 | "arm64" 787 | ], 788 | "dev": true, 789 | "optional": true, 790 | "os": [ 791 | "linux" 792 | ], 793 | "engines": { 794 | "node": ">= 10" 795 | } 796 | }, 797 | "node_modules/@tailwindcss/oxide-linux-arm64-musl": { 798 | "version": "4.0.13", 799 | "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.0.13.tgz", 800 | "integrity": "sha512-GQj6TWevNxwsYw20FdT2r2d1f7uiRsF07iFvNYxPIvIyPEV74eZ0zgFEsAH1daK1OxPy+LXdZ4grV17P5tVzhQ==", 801 | "cpu": [ 802 | "arm64" 803 | ], 804 | "dev": true, 805 | "optional": true, 806 | "os": [ 807 | "linux" 808 | ], 809 | "engines": { 810 | "node": ">= 10" 811 | } 812 | }, 813 | "node_modules/@tailwindcss/oxide-linux-x64-gnu": { 814 | "version": "4.0.13", 815 | "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.0.13.tgz", 816 | "integrity": "sha512-sQRH09faifF9w9WS6TKDWr1oLi4hoPx0EIWXZHQK/jcjarDpXGQ2DbF0KnALJCwWBxOIP/1nrmU01fZwwMzY3g==", 817 | "cpu": [ 818 | "x64" 819 | ], 820 | "dev": true, 821 | "optional": true, 822 | "os": [ 823 | "linux" 824 | ], 825 | "engines": { 826 | "node": ">= 10" 827 | } 828 | }, 829 | "node_modules/@tailwindcss/oxide-linux-x64-musl": { 830 | "version": "4.0.13", 831 | "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.0.13.tgz", 832 | "integrity": "sha512-Or1N8DIF3tP+LsloJp+UXLTIMMHMUcWXFhJLCsM4T7MzFzxkeReewRWXfk5mk137cdqVeUEH/R50xAhY1mOkTQ==", 833 | "cpu": [ 834 | "x64" 835 | ], 836 | "dev": true, 837 | "optional": true, 838 | "os": [ 839 | "linux" 840 | ], 841 | "engines": { 842 | "node": ">= 10" 843 | } 844 | }, 845 | "node_modules/@tailwindcss/oxide-win32-arm64-msvc": { 846 | "version": "4.0.13", 847 | "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.0.13.tgz", 848 | "integrity": "sha512-u2mQyqCFrr9vVTP6sfDRfGE6bhOX3/7rInehzxNhHX1HYRIx09H3sDdXzTxnZWKOjIg3qjFTCrYFUZckva5PIg==", 849 | "cpu": [ 850 | "arm64" 851 | ], 852 | "dev": true, 853 | "optional": true, 854 | "os": [ 855 | "win32" 856 | ], 857 | "engines": { 858 | "node": ">= 10" 859 | } 860 | }, 861 | "node_modules/@tailwindcss/oxide-win32-x64-msvc": { 862 | "version": "4.0.13", 863 | "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.0.13.tgz", 864 | "integrity": "sha512-sOEc4iCanp1Yqyeu9suQcEzfaUcHnqjBUgDg0ZXpjUMUwdSi37S1lu1RGoV1BYInvvGu3y3HHTmvsSfDhx2L8w==", 865 | "cpu": [ 866 | "x64" 867 | ], 868 | "dev": true, 869 | "optional": true, 870 | "os": [ 871 | "win32" 872 | ], 873 | "engines": { 874 | "node": ">= 10" 875 | } 876 | }, 877 | "node_modules/@tailwindcss/vite": { 878 | "version": "4.0.13", 879 | "resolved": "https://registry.npmjs.org/@tailwindcss/vite/-/vite-4.0.13.tgz", 880 | "integrity": "sha512-0XTd/NoVUAktIDaA4MdXhve0QWYh7WlZg20EHCuBFR80F8FhbVkRX+AY5cjbUP/IO2itHzt0iHc0iSE5kBUMhQ==", 881 | "dev": true, 882 | "dependencies": { 883 | "@tailwindcss/node": "4.0.13", 884 | "@tailwindcss/oxide": "4.0.13", 885 | "lightningcss": "1.29.2", 886 | "tailwindcss": "4.0.13" 887 | }, 888 | "peerDependencies": { 889 | "vite": "^5.2.0 || ^6" 890 | } 891 | }, 892 | "node_modules/@types/estree": { 893 | "version": "1.0.6", 894 | "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", 895 | "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==", 896 | "dev": true 897 | }, 898 | "node_modules/chokidar": { 899 | "version": "4.0.3", 900 | "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", 901 | "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", 902 | "dependencies": { 903 | "readdirp": "^4.0.1" 904 | }, 905 | "engines": { 906 | "node": ">= 14.16.0" 907 | }, 908 | "funding": { 909 | "url": "https://paulmillr.com/funding/" 910 | } 911 | }, 912 | "node_modules/daisyui": { 913 | "version": "5.0.2", 914 | "resolved": "https://registry.npmjs.org/daisyui/-/daisyui-5.0.2.tgz", 915 | "integrity": "sha512-AfOlwcE+Ukwuh2NSrMDE8VXOl9UWidj2Q5f64DEYqtZVW0Z9pELBA50iGEKg2FpBUvztFY5DFv7+eZgRts70BA==", 916 | "dev": true, 917 | "funding": { 918 | "url": "https://github.com/saadeghi/daisyui?sponsor=1" 919 | } 920 | }, 921 | "node_modules/detect-libc": { 922 | "version": "2.0.3", 923 | "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.3.tgz", 924 | "integrity": "sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==", 925 | "dev": true, 926 | "engines": { 927 | "node": ">=8" 928 | } 929 | }, 930 | "node_modules/enhanced-resolve": { 931 | "version": "5.18.1", 932 | "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.1.tgz", 933 | "integrity": "sha512-ZSW3ma5GkcQBIpwZTSRAI8N71Uuwgs93IezB7mf7R60tC8ZbJideoDNKjHn2O9KIlx6rkGTTEk1xUCK2E1Y2Yg==", 934 | "dev": true, 935 | "dependencies": { 936 | "graceful-fs": "^4.2.4", 937 | "tapable": "^2.2.0" 938 | }, 939 | "engines": { 940 | "node": ">=10.13.0" 941 | } 942 | }, 943 | "node_modules/esbuild": { 944 | "version": "0.25.1", 945 | "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.1.tgz", 946 | "integrity": "sha512-BGO5LtrGC7vxnqucAe/rmvKdJllfGaYWdyABvyMoXQlfYMb2bbRuReWR5tEGE//4LcNJj9XrkovTqNYRFZHAMQ==", 947 | "dev": true, 948 | "hasInstallScript": true, 949 | "bin": { 950 | "esbuild": "bin/esbuild" 951 | }, 952 | "engines": { 953 | "node": ">=18" 954 | }, 955 | "optionalDependencies": { 956 | "@esbuild/aix-ppc64": "0.25.1", 957 | "@esbuild/android-arm": "0.25.1", 958 | "@esbuild/android-arm64": "0.25.1", 959 | "@esbuild/android-x64": "0.25.1", 960 | "@esbuild/darwin-arm64": "0.25.1", 961 | "@esbuild/darwin-x64": "0.25.1", 962 | "@esbuild/freebsd-arm64": "0.25.1", 963 | "@esbuild/freebsd-x64": "0.25.1", 964 | "@esbuild/linux-arm": "0.25.1", 965 | "@esbuild/linux-arm64": "0.25.1", 966 | "@esbuild/linux-ia32": "0.25.1", 967 | "@esbuild/linux-loong64": "0.25.1", 968 | "@esbuild/linux-mips64el": "0.25.1", 969 | "@esbuild/linux-ppc64": "0.25.1", 970 | "@esbuild/linux-riscv64": "0.25.1", 971 | "@esbuild/linux-s390x": "0.25.1", 972 | "@esbuild/linux-x64": "0.25.1", 973 | "@esbuild/netbsd-arm64": "0.25.1", 974 | "@esbuild/netbsd-x64": "0.25.1", 975 | "@esbuild/openbsd-arm64": "0.25.1", 976 | "@esbuild/openbsd-x64": "0.25.1", 977 | "@esbuild/sunos-x64": "0.25.1", 978 | "@esbuild/win32-arm64": "0.25.1", 979 | "@esbuild/win32-ia32": "0.25.1", 980 | "@esbuild/win32-x64": "0.25.1" 981 | } 982 | }, 983 | "node_modules/fsevents": { 984 | "version": "2.3.3", 985 | "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", 986 | "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", 987 | "dev": true, 988 | "hasInstallScript": true, 989 | "optional": true, 990 | "os": [ 991 | "darwin" 992 | ], 993 | "engines": { 994 | "node": "^8.16.0 || ^10.6.0 || >=11.0.0" 995 | } 996 | }, 997 | "node_modules/graceful-fs": { 998 | "version": "4.2.11", 999 | "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", 1000 | "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", 1001 | "dev": true 1002 | }, 1003 | "node_modules/jiti": { 1004 | "version": "2.4.2", 1005 | "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.4.2.tgz", 1006 | "integrity": "sha512-rg9zJN+G4n2nfJl5MW3BMygZX56zKPNVEYYqq7adpmMh4Jn2QNEwhvQlFy6jPVdcod7txZtKHWnyZiA3a0zP7A==", 1007 | "dev": true, 1008 | "bin": { 1009 | "jiti": "lib/jiti-cli.mjs" 1010 | } 1011 | }, 1012 | "node_modules/lightningcss": { 1013 | "version": "1.29.2", 1014 | "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.29.2.tgz", 1015 | "integrity": "sha512-6b6gd/RUXKaw5keVdSEtqFVdzWnU5jMxTUjA2bVcMNPLwSQ08Sv/UodBVtETLCn7k4S1Ibxwh7k68IwLZPgKaA==", 1016 | "dev": true, 1017 | "dependencies": { 1018 | "detect-libc": "^2.0.3" 1019 | }, 1020 | "engines": { 1021 | "node": ">= 12.0.0" 1022 | }, 1023 | "funding": { 1024 | "type": "opencollective", 1025 | "url": "https://opencollective.com/parcel" 1026 | }, 1027 | "optionalDependencies": { 1028 | "lightningcss-darwin-arm64": "1.29.2", 1029 | "lightningcss-darwin-x64": "1.29.2", 1030 | "lightningcss-freebsd-x64": "1.29.2", 1031 | "lightningcss-linux-arm-gnueabihf": "1.29.2", 1032 | "lightningcss-linux-arm64-gnu": "1.29.2", 1033 | "lightningcss-linux-arm64-musl": "1.29.2", 1034 | "lightningcss-linux-x64-gnu": "1.29.2", 1035 | "lightningcss-linux-x64-musl": "1.29.2", 1036 | "lightningcss-win32-arm64-msvc": "1.29.2", 1037 | "lightningcss-win32-x64-msvc": "1.29.2" 1038 | } 1039 | }, 1040 | "node_modules/lightningcss-darwin-arm64": { 1041 | "version": "1.29.2", 1042 | "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.29.2.tgz", 1043 | "integrity": "sha512-cK/eMabSViKn/PG8U/a7aCorpeKLMlK0bQeNHmdb7qUnBkNPnL+oV5DjJUo0kqWsJUapZsM4jCfYItbqBDvlcA==", 1044 | "cpu": [ 1045 | "arm64" 1046 | ], 1047 | "dev": true, 1048 | "optional": true, 1049 | "os": [ 1050 | "darwin" 1051 | ], 1052 | "engines": { 1053 | "node": ">= 12.0.0" 1054 | }, 1055 | "funding": { 1056 | "type": "opencollective", 1057 | "url": "https://opencollective.com/parcel" 1058 | } 1059 | }, 1060 | "node_modules/lightningcss-darwin-x64": { 1061 | "version": "1.29.2", 1062 | "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.29.2.tgz", 1063 | "integrity": "sha512-j5qYxamyQw4kDXX5hnnCKMf3mLlHvG44f24Qyi2965/Ycz829MYqjrVg2H8BidybHBp9kom4D7DR5VqCKDXS0w==", 1064 | "cpu": [ 1065 | "x64" 1066 | ], 1067 | "dev": true, 1068 | "optional": true, 1069 | "os": [ 1070 | "darwin" 1071 | ], 1072 | "engines": { 1073 | "node": ">= 12.0.0" 1074 | }, 1075 | "funding": { 1076 | "type": "opencollective", 1077 | "url": "https://opencollective.com/parcel" 1078 | } 1079 | }, 1080 | "node_modules/lightningcss-freebsd-x64": { 1081 | "version": "1.29.2", 1082 | "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.29.2.tgz", 1083 | "integrity": "sha512-wDk7M2tM78Ii8ek9YjnY8MjV5f5JN2qNVO+/0BAGZRvXKtQrBC4/cn4ssQIpKIPP44YXw6gFdpUF+Ps+RGsCwg==", 1084 | "cpu": [ 1085 | "x64" 1086 | ], 1087 | "dev": true, 1088 | "optional": true, 1089 | "os": [ 1090 | "freebsd" 1091 | ], 1092 | "engines": { 1093 | "node": ">= 12.0.0" 1094 | }, 1095 | "funding": { 1096 | "type": "opencollective", 1097 | "url": "https://opencollective.com/parcel" 1098 | } 1099 | }, 1100 | "node_modules/lightningcss-linux-arm-gnueabihf": { 1101 | "version": "1.29.2", 1102 | "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.29.2.tgz", 1103 | "integrity": "sha512-IRUrOrAF2Z+KExdExe3Rz7NSTuuJ2HvCGlMKoquK5pjvo2JY4Rybr+NrKnq0U0hZnx5AnGsuFHjGnNT14w26sg==", 1104 | "cpu": [ 1105 | "arm" 1106 | ], 1107 | "dev": true, 1108 | "optional": true, 1109 | "os": [ 1110 | "linux" 1111 | ], 1112 | "engines": { 1113 | "node": ">= 12.0.0" 1114 | }, 1115 | "funding": { 1116 | "type": "opencollective", 1117 | "url": "https://opencollective.com/parcel" 1118 | } 1119 | }, 1120 | "node_modules/lightningcss-linux-arm64-gnu": { 1121 | "version": "1.29.2", 1122 | "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.29.2.tgz", 1123 | "integrity": "sha512-KKCpOlmhdjvUTX/mBuaKemp0oeDIBBLFiU5Fnqxh1/DZ4JPZi4evEH7TKoSBFOSOV3J7iEmmBaw/8dpiUvRKlQ==", 1124 | "cpu": [ 1125 | "arm64" 1126 | ], 1127 | "dev": true, 1128 | "optional": true, 1129 | "os": [ 1130 | "linux" 1131 | ], 1132 | "engines": { 1133 | "node": ">= 12.0.0" 1134 | }, 1135 | "funding": { 1136 | "type": "opencollective", 1137 | "url": "https://opencollective.com/parcel" 1138 | } 1139 | }, 1140 | "node_modules/lightningcss-linux-arm64-musl": { 1141 | "version": "1.29.2", 1142 | "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.29.2.tgz", 1143 | "integrity": "sha512-Q64eM1bPlOOUgxFmoPUefqzY1yV3ctFPE6d/Vt7WzLW4rKTv7MyYNky+FWxRpLkNASTnKQUaiMJ87zNODIrrKQ==", 1144 | "cpu": [ 1145 | "arm64" 1146 | ], 1147 | "dev": true, 1148 | "optional": true, 1149 | "os": [ 1150 | "linux" 1151 | ], 1152 | "engines": { 1153 | "node": ">= 12.0.0" 1154 | }, 1155 | "funding": { 1156 | "type": "opencollective", 1157 | "url": "https://opencollective.com/parcel" 1158 | } 1159 | }, 1160 | "node_modules/lightningcss-linux-x64-gnu": { 1161 | "version": "1.29.2", 1162 | "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.29.2.tgz", 1163 | "integrity": "sha512-0v6idDCPG6epLXtBH/RPkHvYx74CVziHo6TMYga8O2EiQApnUPZsbR9nFNrg2cgBzk1AYqEd95TlrsL7nYABQg==", 1164 | "cpu": [ 1165 | "x64" 1166 | ], 1167 | "dev": true, 1168 | "optional": true, 1169 | "os": [ 1170 | "linux" 1171 | ], 1172 | "engines": { 1173 | "node": ">= 12.0.0" 1174 | }, 1175 | "funding": { 1176 | "type": "opencollective", 1177 | "url": "https://opencollective.com/parcel" 1178 | } 1179 | }, 1180 | "node_modules/lightningcss-linux-x64-musl": { 1181 | "version": "1.29.2", 1182 | "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.29.2.tgz", 1183 | "integrity": "sha512-rMpz2yawkgGT8RULc5S4WiZopVMOFWjiItBT7aSfDX4NQav6M44rhn5hjtkKzB+wMTRlLLqxkeYEtQ3dd9696w==", 1184 | "cpu": [ 1185 | "x64" 1186 | ], 1187 | "dev": true, 1188 | "optional": true, 1189 | "os": [ 1190 | "linux" 1191 | ], 1192 | "engines": { 1193 | "node": ">= 12.0.0" 1194 | }, 1195 | "funding": { 1196 | "type": "opencollective", 1197 | "url": "https://opencollective.com/parcel" 1198 | } 1199 | }, 1200 | "node_modules/lightningcss-win32-arm64-msvc": { 1201 | "version": "1.29.2", 1202 | "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.29.2.tgz", 1203 | "integrity": "sha512-nL7zRW6evGQqYVu/bKGK+zShyz8OVzsCotFgc7judbt6wnB2KbiKKJwBE4SGoDBQ1O94RjW4asrCjQL4i8Fhbw==", 1204 | "cpu": [ 1205 | "arm64" 1206 | ], 1207 | "dev": true, 1208 | "optional": true, 1209 | "os": [ 1210 | "win32" 1211 | ], 1212 | "engines": { 1213 | "node": ">= 12.0.0" 1214 | }, 1215 | "funding": { 1216 | "type": "opencollective", 1217 | "url": "https://opencollective.com/parcel" 1218 | } 1219 | }, 1220 | "node_modules/lightningcss-win32-x64-msvc": { 1221 | "version": "1.29.2", 1222 | "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.29.2.tgz", 1223 | "integrity": "sha512-EdIUW3B2vLuHmv7urfzMI/h2fmlnOQBk1xlsDxkN1tCWKjNFjfLhGxYk8C8mzpSfr+A6jFFIi8fU6LbQGsRWjA==", 1224 | "cpu": [ 1225 | "x64" 1226 | ], 1227 | "dev": true, 1228 | "optional": true, 1229 | "os": [ 1230 | "win32" 1231 | ], 1232 | "engines": { 1233 | "node": ">= 12.0.0" 1234 | }, 1235 | "funding": { 1236 | "type": "opencollective", 1237 | "url": "https://opencollective.com/parcel" 1238 | } 1239 | }, 1240 | "node_modules/nanoid": { 1241 | "version": "3.3.9", 1242 | "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.9.tgz", 1243 | "integrity": "sha512-SppoicMGpZvbF1l3z4x7No3OlIjP7QJvC9XR7AhZr1kL133KHnKPztkKDc+Ir4aJ/1VhTySrtKhrsycmrMQfvg==", 1244 | "dev": true, 1245 | "funding": [ 1246 | { 1247 | "type": "github", 1248 | "url": "https://github.com/sponsors/ai" 1249 | } 1250 | ], 1251 | "bin": { 1252 | "nanoid": "bin/nanoid.cjs" 1253 | }, 1254 | "engines": { 1255 | "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" 1256 | } 1257 | }, 1258 | "node_modules/picocolors": { 1259 | "version": "1.1.1", 1260 | "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", 1261 | "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", 1262 | "dev": true 1263 | }, 1264 | "node_modules/postcss": { 1265 | "version": "8.5.3", 1266 | "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.3.tgz", 1267 | "integrity": "sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A==", 1268 | "dev": true, 1269 | "funding": [ 1270 | { 1271 | "type": "opencollective", 1272 | "url": "https://opencollective.com/postcss/" 1273 | }, 1274 | { 1275 | "type": "tidelift", 1276 | "url": "https://tidelift.com/funding/github/npm/postcss" 1277 | }, 1278 | { 1279 | "type": "github", 1280 | "url": "https://github.com/sponsors/ai" 1281 | } 1282 | ], 1283 | "dependencies": { 1284 | "nanoid": "^3.3.8", 1285 | "picocolors": "^1.1.1", 1286 | "source-map-js": "^1.2.1" 1287 | }, 1288 | "engines": { 1289 | "node": "^10 || ^12 || >=14" 1290 | } 1291 | }, 1292 | "node_modules/readdirp": { 1293 | "version": "4.1.2", 1294 | "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", 1295 | "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", 1296 | "engines": { 1297 | "node": ">= 14.18.0" 1298 | }, 1299 | "funding": { 1300 | "type": "individual", 1301 | "url": "https://paulmillr.com/funding/" 1302 | } 1303 | }, 1304 | "node_modules/rollup": { 1305 | "version": "4.35.0", 1306 | "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.35.0.tgz", 1307 | "integrity": "sha512-kg6oI4g+vc41vePJyO6dHt/yl0Rz3Thv0kJeVQ3D1kS3E5XSuKbPc29G4IpT/Kv1KQwgHVcN+HtyS+HYLNSvQg==", 1308 | "dev": true, 1309 | "dependencies": { 1310 | "@types/estree": "1.0.6" 1311 | }, 1312 | "bin": { 1313 | "rollup": "dist/bin/rollup" 1314 | }, 1315 | "engines": { 1316 | "node": ">=18.0.0", 1317 | "npm": ">=8.0.0" 1318 | }, 1319 | "optionalDependencies": { 1320 | "@rollup/rollup-android-arm-eabi": "4.35.0", 1321 | "@rollup/rollup-android-arm64": "4.35.0", 1322 | "@rollup/rollup-darwin-arm64": "4.35.0", 1323 | "@rollup/rollup-darwin-x64": "4.35.0", 1324 | "@rollup/rollup-freebsd-arm64": "4.35.0", 1325 | "@rollup/rollup-freebsd-x64": "4.35.0", 1326 | "@rollup/rollup-linux-arm-gnueabihf": "4.35.0", 1327 | "@rollup/rollup-linux-arm-musleabihf": "4.35.0", 1328 | "@rollup/rollup-linux-arm64-gnu": "4.35.0", 1329 | "@rollup/rollup-linux-arm64-musl": "4.35.0", 1330 | "@rollup/rollup-linux-loongarch64-gnu": "4.35.0", 1331 | "@rollup/rollup-linux-powerpc64le-gnu": "4.35.0", 1332 | "@rollup/rollup-linux-riscv64-gnu": "4.35.0", 1333 | "@rollup/rollup-linux-s390x-gnu": "4.35.0", 1334 | "@rollup/rollup-linux-x64-gnu": "4.35.0", 1335 | "@rollup/rollup-linux-x64-musl": "4.35.0", 1336 | "@rollup/rollup-win32-arm64-msvc": "4.35.0", 1337 | "@rollup/rollup-win32-ia32-msvc": "4.35.0", 1338 | "@rollup/rollup-win32-x64-msvc": "4.35.0", 1339 | "fsevents": "~2.3.2" 1340 | } 1341 | }, 1342 | "node_modules/source-map-js": { 1343 | "version": "1.2.1", 1344 | "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", 1345 | "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", 1346 | "dev": true, 1347 | "engines": { 1348 | "node": ">=0.10.0" 1349 | } 1350 | }, 1351 | "node_modules/squint-cljs": { 1352 | "version": "0.8.141", 1353 | "resolved": "https://registry.npmjs.org/squint-cljs/-/squint-cljs-0.8.141.tgz", 1354 | "integrity": "sha512-wJfvnBsfTG1CNimZILiLlXEO2WEpGbdXbm3CZbjx0i3I02RGBcGps5UCvS8UI/m2LPxDBWBKPt96WA03m7XoJA==", 1355 | "funding": [ 1356 | { 1357 | "type": "github", 1358 | "url": "https://github.com/sponsors/borkdude" 1359 | } 1360 | ], 1361 | "dependencies": { 1362 | "chokidar": "^4.0.1" 1363 | }, 1364 | "bin": { 1365 | "squint": "node_cli.js" 1366 | } 1367 | }, 1368 | "node_modules/tailwindcss": { 1369 | "version": "4.0.13", 1370 | "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.0.13.tgz", 1371 | "integrity": "sha512-gbvFrB0fOsTv/OugXWi2PtflJ4S6/ctu6Mmn3bCftmLY/6xRsQVEJPgIIpABwpZ52DpONkCA3bEj5b54MHxF2Q==" 1372 | }, 1373 | "node_modules/tapable": { 1374 | "version": "2.2.1", 1375 | "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", 1376 | "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", 1377 | "dev": true, 1378 | "engines": { 1379 | "node": ">=6" 1380 | } 1381 | }, 1382 | "node_modules/vite": { 1383 | "version": "6.2.1", 1384 | "resolved": "https://registry.npmjs.org/vite/-/vite-6.2.1.tgz", 1385 | "integrity": "sha512-n2GnqDb6XPhlt9B8olZPrgMD/es/Nd1RdChF6CBD/fHW6pUyUTt2sQW2fPRX5GiD9XEa6+8A6A4f2vT6pSsE7Q==", 1386 | "dev": true, 1387 | "dependencies": { 1388 | "esbuild": "^0.25.0", 1389 | "postcss": "^8.5.3", 1390 | "rollup": "^4.30.1" 1391 | }, 1392 | "bin": { 1393 | "vite": "bin/vite.js" 1394 | }, 1395 | "engines": { 1396 | "node": "^18.0.0 || ^20.0.0 || >=22.0.0" 1397 | }, 1398 | "funding": { 1399 | "url": "https://github.com/vitejs/vite?sponsor=1" 1400 | }, 1401 | "optionalDependencies": { 1402 | "fsevents": "~2.3.3" 1403 | }, 1404 | "peerDependencies": { 1405 | "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", 1406 | "jiti": ">=1.21.0", 1407 | "less": "*", 1408 | "lightningcss": "^1.21.0", 1409 | "sass": "*", 1410 | "sass-embedded": "*", 1411 | "stylus": "*", 1412 | "sugarss": "*", 1413 | "terser": "^5.16.0", 1414 | "tsx": "^4.8.1", 1415 | "yaml": "^2.4.2" 1416 | }, 1417 | "peerDependenciesMeta": { 1418 | "@types/node": { 1419 | "optional": true 1420 | }, 1421 | "jiti": { 1422 | "optional": true 1423 | }, 1424 | "less": { 1425 | "optional": true 1426 | }, 1427 | "lightningcss": { 1428 | "optional": true 1429 | }, 1430 | "sass": { 1431 | "optional": true 1432 | }, 1433 | "sass-embedded": { 1434 | "optional": true 1435 | }, 1436 | "stylus": { 1437 | "optional": true 1438 | }, 1439 | "sugarss": { 1440 | "optional": true 1441 | }, 1442 | "terser": { 1443 | "optional": true 1444 | }, 1445 | "tsx": { 1446 | "optional": true 1447 | }, 1448 | "yaml": { 1449 | "optional": true 1450 | } 1451 | } 1452 | } 1453 | } 1454 | } 1455 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "hiccalpine", 3 | "version": "1.0.0", 4 | "description": "npm for hiccalpine dev environment", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "Brian Scaturro", 10 | "license": "MIT", 11 | "dependencies": { 12 | "squint-cljs": "^0.8.141", 13 | "tailwindcss": "^4.0.12" 14 | }, 15 | "devDependencies": { 16 | "@tailwindcss/vite": "^4.0.13", 17 | "daisyui": "^5.0.2", 18 | "vite": "^6.2.1" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /squint.edn: -------------------------------------------------------------------------------- 1 | {:paths ["src"] 2 | :output-dir "dist" 3 | :extension "js"} 4 | -------------------------------------------------------------------------------- /src/app.cljs: -------------------------------------------------------------------------------- 1 | (ns app 2 | (:require [clojure.string :as str])) 3 | 4 | (defn get-element-by-id [id] 5 | (js/document.getElementById id)) 6 | 7 | (defn parse-attributes [attrs-string] 8 | (when (and attrs-string (not (str/blank? attrs-string))) 9 | (let [attr-pattern #"([^\s=]+)(?:=\"([^\"]*)\")?" 10 | matches (re-seq attr-pattern attrs-string)] 11 | (into {} 12 | (map (fn [[_ name value]] 13 | [(str ":" name) (or value true)]) 14 | matches))))) 15 | 16 | (defn strip-html-comments [html] 17 | (str/replace html #"" "")) 18 | 19 | (defn normalize-whitespace [text] 20 | (-> text 21 | (str/replace #"\s+" " ") 22 | str/trim)) 23 | 24 | (defn js-array->clj-vec [arr] 25 | (let [result (transient []) 26 | len (.-length arr)] 27 | (loop [i 0] 28 | (if (< i len) 29 | (do 30 | (conj! result (aget arr i)) 31 | (recur (inc i))) 32 | (persistent! result))))) 33 | 34 | (defn has-multiple-roots? [html] 35 | (let [cleaned-html (-> html 36 | strip-html-comments 37 | str/trim) 38 | ;; Create a temporary DOM to count top-level elements 39 | temp-div (js/document.createElement "div")] 40 | 41 | ;; Set the HTML content 42 | (set! (.-innerHTML temp-div) cleaned-html) 43 | 44 | ;; Count the number of element nodes (nodeType 1) at the top level 45 | (let [child-nodes (.-childNodes temp-div) 46 | element-count (loop [i 0 47 | count 0] 48 | (if (< i (.-length child-nodes)) 49 | (let [node (aget child-nodes i)] 50 | (recur (inc i) 51 | (if (= (.-nodeType node) 1) 52 | (inc count) 53 | count))) 54 | count))] 55 | (> element-count 1)))) 56 | 57 | (defn simple-html->hiccup [html] 58 | (let [html (-> html 59 | strip-html-comments 60 | str/trim) 61 | has-html-tag (re-find #"]" html) 62 | has-body-tag (re-find #"]" html) 63 | has-head-tag (re-find #"]" html) 64 | 65 | ;; Check for multiple roots 66 | multiple-roots (has-multiple-roots? html) 67 | 68 | ;; For multiple root elements, wrap in a container 69 | parse-html (if multiple-roots 70 | (str "
" html "
") 71 | html) 72 | 73 | dom-parser (js/DOMParser.) 74 | doc (.parseFromString dom-parser parse-html "text/html")] 75 | 76 | (letfn [(element->hiccup [el] 77 | (if (= (.-nodeType el) 3) ; Text node 78 | (let [text (normalize-whitespace (.-textContent el))] 79 | (when-not (str/blank? text) 80 | text)) 81 | 82 | (when (= (.-nodeType el) 1) ; Element node 83 | (let [tag-name (str/lower-case (.-tagName el)) 84 | is-wrapper (and multiple-roots 85 | (= tag-name "div") 86 | (= (.-id el) "multiple-roots-wrapper")) 87 | skip-tag (or 88 | (and (= tag-name "html") (not has-html-tag)) 89 | (and (= tag-name "body") (not has-body-tag)) 90 | (and (= tag-name "head") (not has-head-tag))) 91 | tag-kw (str ":" tag-name) 92 | attrs (when (.-attributes el) 93 | (let [attrs-map {}] 94 | (loop [i 0 95 | result attrs-map] 96 | (if (< i (.-length (.-attributes el))) 97 | (let [attr (aget (.-attributes el) i) 98 | name (str ":" (.-name attr)) 99 | value (.-value attr)] 100 | (recur (inc i) (assoc result name value))) 101 | (when (> (count result) 0) 102 | result))))) 103 | children (js-array->clj-vec (.-childNodes el)) 104 | child-hiccups (filter identity (map element->hiccup children))] 105 | 106 | (cond 107 | ;; If this is our multiple roots wrapper, return children with special marker 108 | is-wrapper 109 | (into ["__multiple_roots__"] child-hiccups) 110 | 111 | ;; If we're skipping this tag, just return its children directly 112 | skip-tag 113 | (if (empty? child-hiccups) 114 | nil 115 | (if (= (count child-hiccups) 1) 116 | (first child-hiccups) 117 | child-hiccups)) 118 | 119 | ;; Otherwise return the normal hiccup form 120 | :else 121 | (if attrs 122 | (into [tag-kw attrs] child-hiccups) 123 | (into [tag-kw] child-hiccups)))))))] 124 | 125 | ;; Process the document and extract the actual content 126 | (let [raw-result (element->hiccup (.-documentElement doc))] 127 | (js/console.log "Multiple roots:" multiple-roots) 128 | 129 | ;; Check if we have multiple roots that need to be wrapped in a list 130 | (cond 131 | ;; If we have multiple roots, wrap children in a list 132 | (and multiple-roots 133 | (vector? raw-result) 134 | (= (first raw-result) "__multiple_roots__")) 135 | (into ["list"] (rest raw-result)) 136 | 137 | ;; If we have a single root but got the special marker, just return the first child 138 | (and (not multiple-roots) 139 | (vector? raw-result) 140 | (= (first raw-result) "__multiple_roots__") 141 | (> (count raw-result) 1)) 142 | (second raw-result) 143 | 144 | ;; If we got a single hiccup vector, return it 145 | (and (vector? raw-result) 146 | (string? (first raw-result)) 147 | (str/starts-with? (first raw-result) ":")) 148 | raw-result 149 | 150 | ;; If we got a collection, find the first real element 151 | (vector? raw-result) 152 | (loop [items raw-result] 153 | (cond 154 | (empty? items) nil 155 | (and (vector? (first items)) 156 | (not (empty? (first items))) 157 | (string? (first (first items))) 158 | (str/starts-with? (first (first items)) ":")) 159 | (first items) 160 | :else 161 | (recur (rest items)))) 162 | 163 | ;; Otherwise just return what we got 164 | :else raw-result))))) 165 | 166 | (defn pretty-print-hiccup [hiccup] 167 | (let [indent-level (atom 0) 168 | result (atom "")] 169 | 170 | (letfn [(indent [] 171 | (apply str (repeat (* 2 @indent-level) " "))) 172 | 173 | (append! [s] 174 | (swap! result str s)) 175 | 176 | (pp-map [m] 177 | (append! "{") 178 | (let [entries (js/Object.entries m) 179 | len (.-length entries)] 180 | (loop [i 0] 181 | (when (< i len) 182 | (let [entry (aget entries i) 183 | k (aget entry 0) 184 | v (aget entry 1)] 185 | (append! k) 186 | (append! " ") 187 | (append! (pr-str v)) 188 | ;; Add space instead of comma between entries 189 | (when (< (inc i) len) 190 | (append! " "))) 191 | (recur (inc i))))) 192 | (append! "}")) 193 | 194 | (pp [form] 195 | (cond 196 | (and (vector? form) (= (first form) "list")) 197 | (do 198 | (append! "(list") 199 | (swap! indent-level inc) 200 | (doseq [child (rest form)] 201 | (append! "\n") 202 | (append! (indent)) 203 | (pp child)) 204 | (swap! indent-level dec) 205 | (append! ")")) 206 | 207 | (vector? form) 208 | (do 209 | (append! "[") 210 | (when-let [tag (first form)] 211 | (append! tag) 212 | (when (and (> (count form) 1) (map? (second form))) 213 | (append! " ") 214 | (pp-map (second form)))) 215 | (when (> (count form) (if (map? (second form)) 2 1)) 216 | (swap! indent-level inc) 217 | (doseq [child (drop (if (map? (second form)) 2 1) form)] 218 | (append! "\n") 219 | (append! (indent)) 220 | (pp child)) 221 | (swap! indent-level dec)) 222 | (append! "]")) 223 | 224 | (map? form) 225 | (pp-map form) 226 | 227 | :else (append! (pr-str form))))] 228 | 229 | (pp hiccup) 230 | @result))) 231 | 232 | (defn translate [event] 233 | (let [html-input (.. event -target -value) 234 | result-el (get-element-by-id "result-output")] 235 | (when (and html-input (not (str/blank? html-input))) 236 | (try 237 | (let [hiccup (simple-html->hiccup html-input) 238 | pretty-hiccup (pretty-print-hiccup hiccup)] 239 | ;; Clear the result element 240 | (set! (.-innerHTML result-el) "") 241 | (.setAttribute result-el "data-count" (count hiccup)) 242 | ;; Create pre and code elements 243 | (let [pre-el (js/document.createElement "pre") 244 | code-el (js/document.createElement "code")] 245 | 246 | ;; Add classes to elements 247 | (.add (.-classList pre-el) "whitespace-pre-wrap") 248 | 249 | ;; Add Tailwind classes for compact text 250 | (.add (.-classList code-el) "text-xs") 251 | (.add (.-classList code-el) "leading-tight") 252 | (.add (.-classList code-el) "font-mono") 253 | (.add (.-classList code-el) "language-clojure") ;; Add language class for Prism 254 | 255 | ;; Set the hiccup content 256 | (set! (.-textContent code-el) pretty-hiccup) 257 | 258 | ;; Append elements 259 | (.appendChild pre-el code-el) 260 | (.appendChild result-el pre-el) 261 | 262 | ;; Apply syntax highlighting 263 | (when (and js/window.Prism js/window.Prism.highlightElement) 264 | (js/window.Prism.highlightElement code-el)))) 265 | (catch js/Error e 266 | (set! (.-innerHTML result-el) 267 | (str "
Error parsing HTML: " 268 | (.-message e) 269 | "
"))))) 270 | 271 | (js/console.log "Translation complete"))) 272 | 273 | (defn toggle-convert-button [] 274 | (let [textarea (get-element-by-id "html-input") 275 | convert-button (get-element-by-id "convert-button")] 276 | (if (and textarea (not (str/blank? (.-value textarea)))) 277 | (.remove (.-classList convert-button) "hidden") 278 | (.add (.-classList convert-button) "hidden")))) 279 | 280 | (defn copy-to-clipboard [] 281 | (let [result-el (get-element-by-id "result-output") 282 | copy-button (get-element-by-id "copy-button") 283 | code-el (when result-el (.querySelector result-el "code"))] 284 | (when (and code-el copy-button) 285 | (let [text-content (.-textContent code-el) 286 | temp-textarea (js/document.createElement "textarea")] 287 | (set! (.-value temp-textarea) text-content) 288 | (set! (.-style temp-textarea) "position: absolute; left: -9999px;") 289 | (.appendChild js/document.body temp-textarea) 290 | (.select temp-textarea) 291 | (js/document.execCommand "copy") 292 | (.removeChild js/document.body temp-textarea) 293 | 294 | ;; Show success feedback 295 | (let [icon-elements (.querySelectorAll copy-button "svg")] 296 | (when (and (> (.-length icon-elements) 0) (> (.-length icon-elements) 1)) 297 | (.add (.-classList (aget icon-elements 0)) "hidden") 298 | (.remove (.-classList (aget icon-elements 1)) "hidden") 299 | (js/setTimeout (fn [] 300 | (.remove (.-classList (aget icon-elements 0)) "hidden") 301 | (.add (.-classList (aget icon-elements 1)) "hidden")) 302 | 1500))))))) 303 | 304 | (defn init [] 305 | (let [textarea (get-element-by-id "html-input") 306 | convert-button (get-element-by-id "convert-button") 307 | copy-button (get-element-by-id "copy-button")] 308 | (when (and textarea convert-button copy-button) 309 | (.addEventListener textarea "input" (fn [_] (toggle-convert-button))) 310 | (.addEventListener textarea "blur" translate) 311 | (.addEventListener convert-button "click" translate) 312 | (.addEventListener copy-button "click" (fn [_] (copy-to-clipboard)))))) 313 | 314 | (init) 315 | -------------------------------------------------------------------------------- /src/app.css: -------------------------------------------------------------------------------- 1 | @import "tailwindcss"; 2 | @plugin "daisyui" { 3 | themes: winter --default, sunset --prefersdark; 4 | } 5 | 6 | @theme { 7 | --font-sans: InterVariable, sans-serif; 8 | } 9 | 10 | [data-count="0"] + #copy-button { 11 | display: none; 12 | } 13 | -------------------------------------------------------------------------------- /vite.config.mjs: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite'; 2 | import tailwindcss from '@tailwindcss/vite'; 3 | 4 | export default defineConfig({ 5 | plugins: [ 6 | tailwindcss() 7 | ], 8 | build: { 9 | outDir: 'dist', 10 | emptyOutDir: false, 11 | manifest: true, 12 | rollupOptions: { 13 | input: ['src/app.css', 'dist/app.js'] 14 | }, 15 | }, 16 | }); 17 | --------------------------------------------------------------------------------