diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 37612457..c83fb407 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -41,6 +41,8 @@ jobs: - name: Build site shell: bash run: ./ci/build.sh + env: + VITE_GITHUB_TOKEN: ${{ secrets.VITE_GITHUB_TOKEN }} - name: Deploy to GitHub Pages if: (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/master') && github.event_name == 'push' uses: JamesIves/github-pages-deploy-action@v4 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 00000000..a3cf25a4 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,55 @@ +# Contributing to the Spyder Website + +1. Create a fork of the repository +2. Clone it and create a new branch for your changes +3. Install dependencies with `npm install` + +## Creating a Blog Post + +1. If the blog post author(s) haven't been added yet: + 1. Create a new folder in `static/assets/authors` using a simple identifier (no spaces/special characters) + 2. Inside this folder: + - Add a square avatar image (recommended: 512×512px WEBP) + - Create `metadata.json` with: + ```json + { + "name": "Author's Display Name", + "image": "filename.webp" + } + ``` + +2. Create a blog post folder in `src/routes/blog` (name becomes URL slug - lowercase, no spaces) + +3. Add a `+page.md` file with this frontmatter: +```yaml +--- +title: Blog Post Title # Required +author: author-id # Required. For multiple authors, use an array of identifiers +pub_date: YYYY-MM-DD # Required +category: Category Name # Optional +tags: Tag1, Tag2 # Optional +summary: Concise overview of content # Required +--- +``` + +5. Write content using mdsvex Markdown: + - [Never indent code blocks](https://mdsvex.pngwn.io/docs#limitations) + - Use standard Markdown syntax for formatting + +6. For images: + ```markdown + ![Meaningful description](image.webp "Optional caption") + ``` + - Store images in the post's folder + - All images require *descriptive* alt text (avoid "image of...", "picture of...", "photo of...", etc.) + +7. Preview locally with: +```bash +npm run dev +``` + - Verify post appears at `/blog/` + - Check author metadata and image display + +8. There is no need to build for production, the workflow will run the build on GitHub Actions. + +9. Create PR against upstream `main` branch. diff --git a/README.md b/README.md index 2618c94c..013cbd79 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,7 @@ Minimal static [SvelteKit](https://kit.svelte.dev/) set-up made deployable to [GitHub Pages](https://metonym.github.io/sveltekit-gh-pages/). Based on [sveltekit-gh-pages](https://metonym.github.io/sveltekit-gh-pages/) +- Made with Svelte 4 - PostCSS framework provided by [TailwindCSS](https://tailwindcss.com/) - Icons from the [Svelte Icons Pack](https://leshak.github.io/svelte-icons-pack/) - Markdown files processed with [mdsvex](https://mdsvex.pngwn.io/) @@ -35,3 +36,7 @@ npm run preview ``` And preview your built site at [https://localhost:5174](https://localhost:5174) + +## Contributing + +See [CONTRIBUTING.md](CONTRIBUTING.md) diff --git a/package-lock.json b/package-lock.json index d3cc9cb1..8b9a491f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,19 +1,21 @@ { - "name": "website-proposal", + "name": "spyder-website", "lockfileVersion": 3, "requires": true, "packages": { "": { "license": "MIT", "dependencies": { - "@sveltejs/adapter-static": "^3.0.5", - "@sveltejs/kit": "^2.6.3", + "@sveltejs/adapter-static": "^3.0.6", + "@sveltejs/kit": "^2.9.1", "@sveltejs/vite-plugin-svelte": "^3.1.2", "@tailwindcss/typography": "^0.5.15", "@types/three": "^0.169.0", "autoprefixer": "^10.4.20", + "cookie": "^1.0.2", "gh-pages": "^6.1.1", "gray-matter": "^4.0.3", + "js-yaml": "^4.1.0", "mdsvex": "^0.12.3", "postcss": "^8.4.47", "rehype-class-names": "^2.0.0", @@ -22,8 +24,9 @@ "remark-smartypants": "^3.0.2", "sharp": "^0.33.5", "svelte": "^4.2.19", + "svelte-i18n": "^4.0.1", "svelte-icons-pack": "^3.1.3", - "svelte-youtube-embed": "^0.3.0", + "svelte-youtube-embed": "^0.3.3", "svooltip": "^0.8.3", "tailwindcss": "^3.4.16", "vite": "^5.4.8" @@ -54,426 +57,534 @@ "node": ">=6.0.0" } }, - "node_modules/@emnapi/runtime": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.3.0.tgz", - "integrity": "sha512-XMBySMuNZs3DM96xcJmLW4EfGnf+uGmFNjzpehMjuX5PLB5j87ar2Zc4e3PVeZ3I5g3tYtAqskB28manlF69Zw==", + "node_modules/@esbuild/aix-ppc64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.19.12.tgz", + "integrity": "sha512-bmoCYyWdEL3wDQIVbcyzRyeKLgk2WtWLTWz1ZIAZF/EGbNOwSA6ew3PftJ1PqMiOOGu0OyFMzG53L0zqIpPeNA==", + "cpu": [ + "ppc64" + ], "license": "MIT", "optional": true, - "dependencies": { - "tslib": "^2.4.0" + "os": [ + "aix" + ], + "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==", + "node_modules/@esbuild/android-arm": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.19.12.tgz", + "integrity": "sha512-qg/Lj1mu3CdQlDEEiWrlC4eaPZ1KztwGJ9B6J+/6G+/4ewxJg7gqj8eVYWvao1bXrqGiW2rsBZFSX3q2lcW05w==", "cpu": [ - "x64" + "arm" ], "license": "MIT", "optional": true, "os": [ - "linux" + "android" ], "engines": { "node": ">=12" } }, - "node_modules/@floating-ui/core": { - "version": "1.6.8", - "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.6.8.tgz", - "integrity": "sha512-7XJ9cPU+yI2QeLS+FCSlqNFZJq8arvswefkZrYI1yQBbftw6FyrZOxYSh+9S7z7TpeWlRt9zJ5IhM1WIL334jA==", + "node_modules/@esbuild/android-arm64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.19.12.tgz", + "integrity": "sha512-P0UVNGIienjZv3f5zq0DP3Nt2IE/3plFzuaS96vihvD0Hd6H/q4WXUGpCxD/E8YrSXfNyRPbpTq+T8ZQioSuPA==", + "cpu": [ + "arm64" + ], "license": "MIT", - "dependencies": { - "@floating-ui/utils": "^0.2.8" + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" } }, - "node_modules/@floating-ui/dom": { - "version": "1.6.11", - "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.6.11.tgz", - "integrity": "sha512-qkMCxSR24v2vGkhYDo/UzxfJN3D4syqSjyuTFz6C7XcpU1pASPRieNI0Kj5VP3/503mOfYiGY891ugBX1GlABQ==", + "node_modules/@esbuild/android-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.19.12.tgz", + "integrity": "sha512-3k7ZoUW6Q6YqhdhIaq/WZ7HwBpnFBlW905Fa4s4qWJyiNOgT1dOqDiVAQFwBH7gBRZr17gLrlFCRzF6jFh7Kew==", + "cpu": [ + "x64" + ], "license": "MIT", - "dependencies": { - "@floating-ui/core": "^1.6.0", - "@floating-ui/utils": "^0.2.8" + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" } }, - "node_modules/@floating-ui/utils": { - "version": "0.2.8", - "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.8.tgz", - "integrity": "sha512-kym7SodPp8/wloecOpcmSnWJsK7M0E5Wg8UcFA+uO4B9s5d0ywXOEro/8HM9x0rW+TljRzul/14UYz3TleT3ig==", - "license": "MIT" - }, - "node_modules/@img/sharp-darwin-arm64": { - "version": "0.33.5", - "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.33.5.tgz", - "integrity": "sha512-UT4p+iz/2H4twwAoLCqfA9UH5pI6DggwKEGuaPy7nCVQ8ZsiY5PIcrRvD1DzuY3qYL07NtIQcWnBSY/heikIFQ==", + "node_modules/@esbuild/darwin-arm64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.19.12.tgz", + "integrity": "sha512-B6IeSgZgtEzGC42jsI+YYu9Z3HKRxp8ZT3cqhvliEHovq8HSX2YX8lNocDn79gCKJXOSaEot9MVYky7AKjCs8g==", "cpu": [ "arm64" ], - "license": "Apache-2.0", + "license": "MIT", "optional": true, "os": [ "darwin" ], "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-darwin-arm64": "1.0.4" + "node": ">=12" } }, - "node_modules/@img/sharp-darwin-x64": { - "version": "0.33.5", - "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.33.5.tgz", - "integrity": "sha512-fyHac4jIc1ANYGRDxtiqelIbdWkIuQaI84Mv45KvGRRxSAa7o7d1ZKAOBaYbnepLC1WqxfpimdeWfvqqSGwR2Q==", + "node_modules/@esbuild/darwin-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.19.12.tgz", + "integrity": "sha512-hKoVkKzFiToTgn+41qGhsUJXFlIjxI/jSYeZf3ugemDYZldIXIxhvwN6erJGlX4t5h417iFuheZ7l+YVn05N3A==", "cpu": [ "x64" ], - "license": "Apache-2.0", + "license": "MIT", "optional": true, "os": [ "darwin" ], "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-darwin-x64": "1.0.4" + "node": ">=12" } }, - "node_modules/@img/sharp-libvips-darwin-arm64": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.0.4.tgz", - "integrity": "sha512-XblONe153h0O2zuFfTAbQYAX2JhYmDHeWikp1LM9Hul9gVPjFY427k6dFEcOL72O01QxQsWi761svJ/ev9xEDg==", + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.19.12.tgz", + "integrity": "sha512-4aRvFIXmwAcDBw9AueDQ2YnGmz5L6obe5kmPT8Vd+/+x/JMVKCgdcRwH6APrbpNXsPz+K653Qg8HB/oXvXVukA==", "cpu": [ "arm64" ], - "license": "LGPL-3.0-or-later", + "license": "MIT", "optional": true, "os": [ - "darwin" + "freebsd" ], - "funding": { - "url": "https://opencollective.com/libvips" + "engines": { + "node": ">=12" } }, - "node_modules/@img/sharp-libvips-darwin-x64": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.0.4.tgz", - "integrity": "sha512-xnGR8YuZYfJGmWPvmlunFaWJsb9T/AO2ykoP3Fz/0X5XV2aoYBPkX6xqCQvUTKKiLddarLaxpzNe+b1hjeWHAQ==", + "node_modules/@esbuild/freebsd-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.19.12.tgz", + "integrity": "sha512-EYoXZ4d8xtBoVN7CEwWY2IN4ho76xjYXqSXMNccFSx2lgqOG/1TBPW0yPx1bJZk94qu3tX0fycJeeQsKovA8gg==", "cpu": [ "x64" ], - "license": "LGPL-3.0-or-later", + "license": "MIT", "optional": true, "os": [ - "darwin" + "freebsd" ], - "funding": { - "url": "https://opencollective.com/libvips" + "engines": { + "node": ">=12" } }, - "node_modules/@img/sharp-libvips-linux-arm": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.0.5.tgz", - "integrity": "sha512-gvcC4ACAOPRNATg/ov8/MnbxFDJqf/pDePbBnuBDcjsI8PssmjoKMAz4LtLaVi+OnSb5FK/yIOamqDwGmXW32g==", + "node_modules/@esbuild/linux-arm": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.19.12.tgz", + "integrity": "sha512-J5jPms//KhSNv+LO1S1TX1UWp1ucM6N6XuL6ITdKWElCu8wXP72l9MM0zDTzzeikVyqFE6U8YAV9/tFyj0ti+w==", "cpu": [ "arm" ], - "license": "LGPL-3.0-or-later", + "license": "MIT", "optional": true, "os": [ "linux" ], - "funding": { - "url": "https://opencollective.com/libvips" + "engines": { + "node": ">=12" } }, - "node_modules/@img/sharp-libvips-linux-arm64": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.0.4.tgz", - "integrity": "sha512-9B+taZ8DlyyqzZQnoeIvDVR/2F4EbMepXMc/NdVbkzsJbzkUjhXv/70GQJ7tdLA4YJgNP25zukcxpX2/SueNrA==", + "node_modules/@esbuild/linux-arm64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.19.12.tgz", + "integrity": "sha512-EoTjyYyLuVPfdPLsGVVVC8a0p1BFFvtpQDB/YLEhaXyf/5bczaGeN15QkR+O4S5LeJ92Tqotve7i1jn35qwvdA==", "cpu": [ "arm64" ], - "license": "LGPL-3.0-or-later", + "license": "MIT", "optional": true, "os": [ "linux" ], - "funding": { - "url": "https://opencollective.com/libvips" + "engines": { + "node": ">=12" } }, - "node_modules/@img/sharp-libvips-linux-s390x": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.0.4.tgz", - "integrity": "sha512-u7Wz6ntiSSgGSGcjZ55im6uvTrOxSIS8/dgoVMoiGE9I6JAfU50yH5BoDlYA1tcuGS7g/QNtetJnxA6QEsCVTA==", + "node_modules/@esbuild/linux-ia32": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.19.12.tgz", + "integrity": "sha512-Thsa42rrP1+UIGaWz47uydHSBOgTUnwBwNq59khgIwktK6x60Hivfbux9iNR0eHCHzOLjLMLfUMLCypBkZXMHA==", "cpu": [ - "s390x" + "ia32" ], - "license": "LGPL-3.0-or-later", + "license": "MIT", "optional": true, "os": [ "linux" ], - "funding": { - "url": "https://opencollective.com/libvips" + "engines": { + "node": ">=12" } }, - "node_modules/@img/sharp-libvips-linux-x64": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.0.4.tgz", - "integrity": "sha512-MmWmQ3iPFZr0Iev+BAgVMb3ZyC4KeFc3jFxnNbEPas60e1cIfevbtuyf9nDGIzOaW9PdnDciJm+wFFaTlj5xYw==", + "node_modules/@esbuild/linux-loong64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.19.12.tgz", + "integrity": "sha512-LiXdXA0s3IqRRjm6rV6XaWATScKAXjI4R4LoDlvO7+yQqFdlr1Bax62sRwkVvRIrwXxvtYEHHI4dm50jAXkuAA==", "cpu": [ - "x64" + "loong64" ], - "license": "LGPL-3.0-or-later", + "license": "MIT", "optional": true, "os": [ "linux" ], - "funding": { - "url": "https://opencollective.com/libvips" + "engines": { + "node": ">=12" } }, - "node_modules/@img/sharp-libvips-linuxmusl-arm64": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.0.4.tgz", - "integrity": "sha512-9Ti+BbTYDcsbp4wfYib8Ctm1ilkugkA/uscUn6UXK1ldpC1JjiXbLfFZtRlBhjPZ5o1NCLiDbg8fhUPKStHoTA==", + "node_modules/@esbuild/linux-mips64el": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.19.12.tgz", + "integrity": "sha512-fEnAuj5VGTanfJ07ff0gOA6IPsvrVHLVb6Lyd1g2/ed67oU1eFzL0r9WL7ZzscD+/N6i3dWumGE1Un4f7Amf+w==", "cpu": [ - "arm64" + "mips64el" ], - "license": "LGPL-3.0-or-later", + "license": "MIT", "optional": true, "os": [ "linux" ], - "funding": { - "url": "https://opencollective.com/libvips" + "engines": { + "node": ">=12" } }, - "node_modules/@img/sharp-libvips-linuxmusl-x64": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.0.4.tgz", - "integrity": "sha512-viYN1KX9m+/hGkJtvYYp+CCLgnJXwiQB39damAO7WMdKWlIhmYTfHjwSbQeUK/20vY154mwezd9HflVFM1wVSw==", + "node_modules/@esbuild/linux-ppc64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.19.12.tgz", + "integrity": "sha512-nYJA2/QPimDQOh1rKWedNOe3Gfc8PabU7HT3iXWtNUbRzXS9+vgB0Fjaqr//XNbd82mCxHzik2qotuI89cfixg==", "cpu": [ - "x64" + "ppc64" ], - "license": "LGPL-3.0-or-later", + "license": "MIT", "optional": true, "os": [ "linux" ], - "funding": { - "url": "https://opencollective.com/libvips" + "engines": { + "node": ">=12" } }, - "node_modules/@img/sharp-linux-arm": { - "version": "0.33.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.33.5.tgz", - "integrity": "sha512-JTS1eldqZbJxjvKaAkxhZmBqPRGmxgu+qFKSInv8moZ2AmT5Yib3EQ1c6gp493HvrvV8QgdOXdyaIBrhvFhBMQ==", + "node_modules/@esbuild/linux-riscv64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.19.12.tgz", + "integrity": "sha512-2MueBrlPQCw5dVJJpQdUYgeqIzDQgw3QtiAHUC4RBz9FXPrskyyU3VI1hw7C0BSKB9OduwSJ79FTCqtGMWqJHg==", "cpu": [ - "arm" + "riscv64" ], - "license": "Apache-2.0", + "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linux-arm": "1.0.5" + "node": ">=12" } }, - "node_modules/@img/sharp-linux-arm64": { - "version": "0.33.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.33.5.tgz", - "integrity": "sha512-JMVv+AMRyGOHtO1RFBiJy/MBsgz0x4AWrT6QoEVVTyh1E39TrCUpTRI7mx9VksGX4awWASxqCYLCV4wBZHAYxA==", + "node_modules/@esbuild/linux-s390x": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.19.12.tgz", + "integrity": "sha512-+Pil1Nv3Umes4m3AZKqA2anfhJiVmNCYkPchwFJNEJN5QxmTs1uzyy4TvmDrCRNT2ApwSari7ZIgrPeUx4UZDg==", "cpu": [ - "arm64" + "s390x" ], - "license": "Apache-2.0", + "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linux-arm64": "1.0.4" + "node": ">=12" } }, - "node_modules/@img/sharp-linux-s390x": { - "version": "0.33.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.33.5.tgz", - "integrity": "sha512-y/5PCd+mP4CA/sPDKl2961b+C9d+vPAveS33s6Z3zfASk2j5upL6fXVPZi7ztePZ5CuH+1kW8JtvxgbuXHRa4Q==", + "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": [ - "s390x" + "x64" ], - "license": "Apache-2.0", + "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linux-s390x": "1.0.4" + "node": ">=12" } }, - "node_modules/@img/sharp-linux-x64": { - "version": "0.33.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.33.5.tgz", - "integrity": "sha512-opC+Ok5pRNAzuvq1AG0ar+1owsu842/Ab+4qvU879ippJBHvyY5n2mxF1izXqkPYlGuP/M556uh53jRLJmzTWA==", + "node_modules/@esbuild/netbsd-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.19.12.tgz", + "integrity": "sha512-3ltjQ7n1owJgFbuC61Oj++XhtzmymoCihNFgT84UAmJnxJfm4sYCiSLTXZtE00VWYpPMYc+ZQmB6xbSdVh0JWA==", "cpu": [ "x64" ], - "license": "Apache-2.0", + "license": "MIT", "optional": true, "os": [ - "linux" + "netbsd" ], "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linux-x64": "1.0.4" + "node": ">=12" } }, - "node_modules/@img/sharp-linuxmusl-arm64": { - "version": "0.33.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.33.5.tgz", - "integrity": "sha512-XrHMZwGQGvJg2V/oRSUfSAfjfPxO+4DkiRh6p2AFjLQztWUuY/o8Mq0eMQVIY7HJ1CDQUJlxGGZRw1a5bqmd1g==", + "node_modules/@esbuild/openbsd-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.19.12.tgz", + "integrity": "sha512-RbrfTB9SWsr0kWmb9srfF+L933uMDdu9BIzdA7os2t0TXhCRjrQyCeOt6wVxr79CKD4c+p+YhCj31HBkYcXebw==", "cpu": [ - "arm64" + "x64" ], - "license": "Apache-2.0", + "license": "MIT", "optional": true, "os": [ - "linux" + "openbsd" ], "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linuxmusl-arm64": "1.0.4" + "node": ">=12" } }, - "node_modules/@img/sharp-linuxmusl-x64": { - "version": "0.33.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.33.5.tgz", - "integrity": "sha512-WT+d/cgqKkkKySYmqoZ8y3pxx7lx9vVejxW/W4DOFMYVSkErR+w7mf2u8m/y4+xHe7yY9DAXQMWQhpnMuFfScw==", + "node_modules/@esbuild/sunos-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.19.12.tgz", + "integrity": "sha512-HKjJwRrW8uWtCQnQOz9qcU3mUZhTUQvi56Q8DPTLLB+DawoiQdjsYq+j+D3s9I8VFtDr+F9CjgXKKC4ss89IeA==", "cpu": [ "x64" ], - "license": "Apache-2.0", + "license": "MIT", "optional": true, "os": [ - "linux" + "sunos" ], "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linuxmusl-x64": "1.0.4" + "node": ">=12" } }, - "node_modules/@img/sharp-wasm32": { - "version": "0.33.5", - "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.33.5.tgz", - "integrity": "sha512-ykUW4LVGaMcU9lu9thv85CbRMAwfeadCJHRsg2GmeRa/cJxsVY9Rbd57JcMxBkKHag5U/x7TSBpScF4U8ElVzg==", + "node_modules/@esbuild/win32-arm64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.19.12.tgz", + "integrity": "sha512-URgtR1dJnmGvX864pn1B2YUYNzjmXkuJOIqG2HdU62MVS4EHpU2946OZoTMnRUHklGtJdJZ33QfzdjGACXhn1A==", "cpu": [ - "wasm32" + "arm64" ], - "license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT", + "license": "MIT", "optional": true, - "dependencies": { - "@emnapi/runtime": "^1.2.0" - }, + "os": [ + "win32" + ], "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" + "node": ">=12" } }, - "node_modules/@img/sharp-win32-ia32": { - "version": "0.33.5", - "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.33.5.tgz", - "integrity": "sha512-T36PblLaTwuVJ/zw/LaH0PdZkRz5rd3SmMHX8GSmR7vtNSP5Z6bQkExdSK7xGWyxLw4sUknBuugTelgw2faBbQ==", + "node_modules/@esbuild/win32-ia32": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.19.12.tgz", + "integrity": "sha512-+ZOE6pUkMOJfmxmBZElNOx72NKpIa/HFOMGzu8fqzQJ5kgf6aTGrcJaFsNiVMH4JKpMipyK+7k0n2UXN7a8YKQ==", "cpu": [ "ia32" ], - "license": "Apache-2.0 AND LGPL-3.0-or-later", + "license": "MIT", "optional": true, "os": [ "win32" ], "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" + "node": ">=12" } }, - "node_modules/@img/sharp-win32-x64": { - "version": "0.33.5", - "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.33.5.tgz", - "integrity": "sha512-MpY/o8/8kj+EcnxwvrP4aTJSWw/aZ7JIGR4aBeZkZw5B7/Jn+tY9/VNwtcoGmdT7GfggGIU4kygOMSbYnOrAbg==", + "node_modules/@esbuild/win32-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.19.12.tgz", + "integrity": "sha512-T1QyPSDCyMXaO3pzBkF96E8xMkiRYbUEZADd29SyPGabqxMViNoii+NcK7eWJAEoU6RZyEm5lVSIjTmcdoB9HA==", "cpu": [ "x64" ], - "license": "Apache-2.0 AND LGPL-3.0-or-later", + "license": "MIT", "optional": true, "os": [ "win32" ], "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" + "node": ">=12" } }, - "node_modules/@isaacs/cliui": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", - "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", - "license": "ISC", - "dependencies": { - "string-width": "^5.1.2", - "string-width-cjs": "npm:string-width@^4.2.0", + "node_modules/@floating-ui/core": { + "version": "1.6.8", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.6.8.tgz", + "integrity": "sha512-7XJ9cPU+yI2QeLS+FCSlqNFZJq8arvswefkZrYI1yQBbftw6FyrZOxYSh+9S7z7TpeWlRt9zJ5IhM1WIL334jA==", + "license": "MIT", + "dependencies": { + "@floating-ui/utils": "^0.2.8" + } + }, + "node_modules/@floating-ui/dom": { + "version": "1.6.11", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.6.11.tgz", + "integrity": "sha512-qkMCxSR24v2vGkhYDo/UzxfJN3D4syqSjyuTFz6C7XcpU1pASPRieNI0Kj5VP3/503mOfYiGY891ugBX1GlABQ==", + "license": "MIT", + "dependencies": { + "@floating-ui/core": "^1.6.0", + "@floating-ui/utils": "^0.2.8" + } + }, + "node_modules/@floating-ui/utils": { + "version": "0.2.8", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.8.tgz", + "integrity": "sha512-kym7SodPp8/wloecOpcmSnWJsK7M0E5Wg8UcFA+uO4B9s5d0ywXOEro/8HM9x0rW+TljRzul/14UYz3TleT3ig==", + "license": "MIT" + }, + "node_modules/@formatjs/ecma402-abstract": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/@formatjs/ecma402-abstract/-/ecma402-abstract-2.3.1.tgz", + "integrity": "sha512-Ip9uV+/MpLXWRk03U/GzeJMuPeOXpJBSB5V1tjA6kJhvqssye5J5LoYLc7Z5IAHb7nR62sRoguzrFiVCP/hnzw==", + "license": "MIT", + "dependencies": { + "@formatjs/fast-memoize": "2.2.5", + "@formatjs/intl-localematcher": "0.5.9", + "decimal.js": "10", + "tslib": "2" + } + }, + "node_modules/@formatjs/fast-memoize": { + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/@formatjs/fast-memoize/-/fast-memoize-2.2.5.tgz", + "integrity": "sha512-6PoewUMrrcqxSoBXAOJDiW1m+AmkrAj0RiXnOMD59GRaswjXhm3MDhgepXPBgonc09oSirAJTsAggzAGQf6A6g==", + "license": "MIT", + "dependencies": { + "tslib": "2" + } + }, + "node_modules/@formatjs/icu-messageformat-parser": { + "version": "2.9.7", + "resolved": "https://registry.npmjs.org/@formatjs/icu-messageformat-parser/-/icu-messageformat-parser-2.9.7.tgz", + "integrity": "sha512-cuEHyRM5VqLQobANOjtjlgU7+qmk9Q3fDQuBiRRJ3+Wp3ZoZhpUPtUfuimZXsir6SaI2TaAJ+SLo9vLnV5QcbA==", + "license": "MIT", + "dependencies": { + "@formatjs/ecma402-abstract": "2.3.1", + "@formatjs/icu-skeleton-parser": "1.8.11", + "tslib": "2" + } + }, + "node_modules/@formatjs/icu-skeleton-parser": { + "version": "1.8.11", + "resolved": "https://registry.npmjs.org/@formatjs/icu-skeleton-parser/-/icu-skeleton-parser-1.8.11.tgz", + "integrity": "sha512-8LlHHE/yL/zVJZHAX3pbKaCjZKmBIO6aJY1mkVh4RMSEu/2WRZ4Ysvv3kKXJ9M8RJLBHdnk1/dUQFdod1Dt7Dw==", + "license": "MIT", + "dependencies": { + "@formatjs/ecma402-abstract": "2.3.1", + "tslib": "2" + } + }, + "node_modules/@formatjs/intl-localematcher": { + "version": "0.5.9", + "resolved": "https://registry.npmjs.org/@formatjs/intl-localematcher/-/intl-localematcher-0.5.9.tgz", + "integrity": "sha512-8zkGu/sv5euxbjfZ/xmklqLyDGQSxsLqg8XOq88JW3cmJtzhCP8EtSJXlaKZnVO4beEaoiT9wj4eIoCQ9smwxA==", + "license": "MIT", + "dependencies": { + "tslib": "2" + } + }, + "node_modules/@img/sharp-libvips-linux-x64": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.0.4.tgz", + "integrity": "sha512-MmWmQ3iPFZr0Iev+BAgVMb3ZyC4KeFc3jFxnNbEPas60e1cIfevbtuyf9nDGIzOaW9PdnDciJm+wFFaTlj5xYw==", + "cpu": [ + "x64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linuxmusl-x64": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.0.4.tgz", + "integrity": "sha512-viYN1KX9m+/hGkJtvYYp+CCLgnJXwiQB39damAO7WMdKWlIhmYTfHjwSbQeUK/20vY154mwezd9HflVFM1wVSw==", + "cpu": [ + "x64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-linux-x64": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.33.5.tgz", + "integrity": "sha512-opC+Ok5pRNAzuvq1AG0ar+1owsu842/Ab+4qvU879ippJBHvyY5n2mxF1izXqkPYlGuP/M556uh53jRLJmzTWA==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-x64": "1.0.4" + } + }, + "node_modules/@img/sharp-linuxmusl-x64": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.33.5.tgz", + "integrity": "sha512-WT+d/cgqKkkKySYmqoZ8y3pxx7lx9vVejxW/W4DOFMYVSkErR+w7mf2u8m/y4+xHe7yY9DAXQMWQhpnMuFfScw==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linuxmusl-x64": "1.0.4" + } + }, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "license": "ISC", + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", "strip-ansi": "^7.0.1", "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", "wrap-ansi": "^8.1.0", @@ -609,9 +720,9 @@ ] }, "node_modules/@sveltejs/adapter-static": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/@sveltejs/adapter-static/-/adapter-static-3.0.5.tgz", - "integrity": "sha512-kFJR7RxeB6FBvrKZWAEzIALatgy11ISaaZbcPup8JdWUdrmmfUHHTJ738YHJTEfnCiiXi6aX8Q6ePY7tnSMD6Q==", + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@sveltejs/adapter-static/-/adapter-static-3.0.6.tgz", + "integrity": "sha512-MGJcesnJWj7FxDcB/GbrdYD3q24Uk0PIL4QIX149ku+hlJuj//nxUbb0HxUTpjkecWfHjVveSUnUaQWnPRXlpg==", "license": "MIT", "peerDependencies": { "@sveltejs/kit": "^2.0.0" @@ -649,6 +760,15 @@ "vite": "^5.0.3 || ^6.0.0" } }, + "node_modules/@sveltejs/kit/node_modules/cookie": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", + "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, "node_modules/@sveltejs/vite-plugin-svelte": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte/-/vite-plugin-svelte-3.1.2.tgz", @@ -839,13 +959,10 @@ "license": "MIT" }, "node_modules/argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "license": "MIT", - "dependencies": { - "sprintf-js": "~1.0.2" - } + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "license": "Python-2.0" }, "node_modules/aria-query": { "version": "5.3.2", @@ -1102,6 +1219,22 @@ "node": ">= 6" } }, + "node_modules/cli-color": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/cli-color/-/cli-color-2.0.4.tgz", + "integrity": "sha512-zlnpg0jNcibNrO7GG9IeHH7maWFeCz+Ja1wx/7tZNU5ASSSSZ+/qZciM0/LHCYxSdqv5h2sdbQ/PXYdOuetXvA==", + "license": "ISC", + "dependencies": { + "d": "^1.0.1", + "es5-ext": "^0.10.64", + "es6-iterator": "^2.0.3", + "memoizee": "^0.4.15", + "timers-ext": "^0.1.7" + }, + "engines": { + "node": ">=0.10" + } + }, "node_modules/code-red": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/code-red/-/code-red-1.0.4.tgz", @@ -1188,12 +1321,12 @@ "license": "MIT" }, "node_modules/cookie": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", - "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-1.0.2.tgz", + "integrity": "sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA==", "license": "MIT", "engines": { - "node": ">= 0.6" + "node": ">=18" } }, "node_modules/cross-spawn": { @@ -1251,6 +1384,19 @@ "node": ">=4" } }, + "node_modules/d": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/d/-/d-1.0.2.tgz", + "integrity": "sha512-MOqHvMWF9/9MX6nza0KgvFH4HpMU0EF5uUDXqX/BtxtU8NfB0QzRtJ8Oe/6SuS4kbhyzVJwjd97EA4PKrzJ8bw==", + "license": "ISC", + "dependencies": { + "es5-ext": "^0.10.64", + "type": "^2.7.2" + }, + "engines": { + "node": ">=0.12" + } + }, "node_modules/debug": { "version": "4.3.7", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", @@ -1268,6 +1414,12 @@ } } }, + "node_modules/decimal.js": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.4.3.tgz", + "integrity": "sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==", + "license": "MIT" + }, "node_modules/deepmerge": { "version": "4.3.1", "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", @@ -1283,122 +1435,526 @@ "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", "license": "MIT", "engines": { - "node": ">=6" + "node": ">=6" + } + }, + "node_modules/detect-libc": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.3.tgz", + "integrity": "sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==", + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, + "node_modules/devalue": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/devalue/-/devalue-5.1.1.tgz", + "integrity": "sha512-maua5KUiapvEwiEAe+XnlZ3Rh0GD+qI1J/nb9vrJc3muPXvcF/8gXYTWF76+5DAqHyDUtOIImEuo0YKE9mshVw==", + "license": "MIT" + }, + "node_modules/devlop": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/devlop/-/devlop-1.1.0.tgz", + "integrity": "sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==", + "license": "MIT", + "dependencies": { + "dequal": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/didyoumean": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", + "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==", + "license": "Apache-2.0" + }, + "node_modules/direction": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/direction/-/direction-2.0.1.tgz", + "integrity": "sha512-9S6m9Sukh1cZNknO1CWAr2QAWsbKLafQiyM5gZ7VgXHeuaoUwffKN4q6NC4A/Mf9iiPlOXQEKW/Mv/mh9/3YFA==", + "license": "MIT", + "bin": { + "direction": "cli.js" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/dlv": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", + "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==", + "license": "MIT" + }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "license": "MIT" + }, + "node_modules/electron-to-chromium": { + "version": "1.5.29", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.29.tgz", + "integrity": "sha512-PF8n2AlIhCKXQ+gTpiJi0VhcHDb69kYX4MtCiivctc2QD3XuNZ/XIOlbGzt7WAjjEev0TtaH6Cu3arZExm5DOw==", + "license": "ISC" + }, + "node_modules/email-addresses": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/email-addresses/-/email-addresses-5.0.0.tgz", + "integrity": "sha512-4OIPYlA6JXqtVn8zpHpGiI7vE6EQOAg16aGnDMIAlZVinnoZ8208tW1hAbjWydgN/4PLTT9q+O1K6AH/vALJGw==", + "license": "MIT" + }, + "node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "license": "MIT" + }, + "node_modules/es5-ext": { + "version": "0.10.64", + "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.64.tgz", + "integrity": "sha512-p2snDhiLaXe6dahss1LddxqEm+SkuDvV8dnIQG0MWjyHpcMNfXKPE+/Cc0y+PhxJX3A4xGNeFCj5oc0BUh6deg==", + "hasInstallScript": true, + "license": "ISC", + "dependencies": { + "es6-iterator": "^2.0.3", + "es6-symbol": "^3.1.3", + "esniff": "^2.0.1", + "next-tick": "^1.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/es6-iterator": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", + "integrity": "sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==", + "license": "MIT", + "dependencies": { + "d": "1", + "es5-ext": "^0.10.35", + "es6-symbol": "^3.1.1" + } + }, + "node_modules/es6-symbol": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.4.tgz", + "integrity": "sha512-U9bFFjX8tFiATgtkJ1zg25+KviIXpgRvRHS8sau3GfhVzThRQrOeksPeT0BWW2MNZs1OEWJ1DPXOQMn0KKRkvg==", + "license": "ISC", + "dependencies": { + "d": "^1.0.2", + "ext": "^1.7.0" + }, + "engines": { + "node": ">=0.12" + } + }, + "node_modules/es6-weak-map": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.3.tgz", + "integrity": "sha512-p5um32HOTO1kP+w7PRnB+5lQ43Z6muuMuIMffvDN8ZB4GcnjLBV6zGStpbASIMk4DCAvEaamhe2zhyCb/QXXsA==", + "license": "ISC", + "dependencies": { + "d": "1", + "es5-ext": "^0.10.46", + "es6-iterator": "^2.0.3", + "es6-symbol": "^3.1.1" + } + }, + "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==", + "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/esbuild/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" + ], + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild/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" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild/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" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild/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" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild/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" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild/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" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild/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" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild/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" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild/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" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild/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" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild/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" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild/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" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild/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" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild/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" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild/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" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild/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" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild/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" + ], + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild/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" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" } }, - "node_modules/detect-libc": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.3.tgz", - "integrity": "sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==", - "license": "Apache-2.0", + "node_modules/esbuild/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" + ], + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], "engines": { - "node": ">=8" + "node": ">=12" } }, - "node_modules/devalue": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/devalue/-/devalue-5.1.1.tgz", - "integrity": "sha512-maua5KUiapvEwiEAe+XnlZ3Rh0GD+qI1J/nb9vrJc3muPXvcF/8gXYTWF76+5DAqHyDUtOIImEuo0YKE9mshVw==", - "license": "MIT" - }, - "node_modules/devlop": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/devlop/-/devlop-1.1.0.tgz", - "integrity": "sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==", + "node_modules/esbuild/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" + ], "license": "MIT", - "dependencies": { - "dequal": "^2.0.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" } }, - "node_modules/didyoumean": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", - "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==", - "license": "Apache-2.0" - }, - "node_modules/direction": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/direction/-/direction-2.0.1.tgz", - "integrity": "sha512-9S6m9Sukh1cZNknO1CWAr2QAWsbKLafQiyM5gZ7VgXHeuaoUwffKN4q6NC4A/Mf9iiPlOXQEKW/Mv/mh9/3YFA==", + "node_modules/esbuild/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" + ], "license": "MIT", - "bin": { - "direction": "cli.js" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" } }, - "node_modules/dlv": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", - "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==", - "license": "MIT" - }, - "node_modules/eastasianwidth": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", - "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", - "license": "MIT" - }, - "node_modules/electron-to-chromium": { - "version": "1.5.29", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.29.tgz", - "integrity": "sha512-PF8n2AlIhCKXQ+gTpiJi0VhcHDb69kYX4MtCiivctc2QD3XuNZ/XIOlbGzt7WAjjEev0TtaH6Cu3arZExm5DOw==", - "license": "ISC" - }, - "node_modules/email-addresses": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/email-addresses/-/email-addresses-5.0.0.tgz", - "integrity": "sha512-4OIPYlA6JXqtVn8zpHpGiI7vE6EQOAg16aGnDMIAlZVinnoZ8208tW1hAbjWydgN/4PLTT9q+O1K6AH/vALJGw==", - "license": "MIT" - }, - "node_modules/emoji-regex": { - "version": "9.2.2", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", - "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", - "license": "MIT" - }, - "node_modules/esbuild": { + "node_modules/esbuild/node_modules/@esbuild/win32-x64": { "version": "0.21.5", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz", - "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==", - "hasInstallScript": true, + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz", + "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==", + "cpu": [ + "x64" + ], "license": "MIT", - "bin": { - "esbuild": "bin/esbuild" - }, + "optional": true, + "os": [ + "win32" + ], "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": { @@ -1425,6 +1981,21 @@ "integrity": "sha512-U9JedYYjCnadUlXk7e1Kr+aENQhtUaoaV9+gZm1T8LC/YBAPJx3NSPIAurFOC0U5vrdSevnUJS2/wUVxGwPhng==", "license": "MIT" }, + "node_modules/esniff": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/esniff/-/esniff-2.0.1.tgz", + "integrity": "sha512-kTUIGKQ/mDPFoJ0oVfcmyJn4iBDRptjNVIzwIFR7tqWXdVI9xfA2RMwY/gbSpJG3lkdWNEjLap/NqVHZiJsdfg==", + "license": "ISC", + "dependencies": { + "d": "^1.0.1", + "es5-ext": "^0.10.62", + "event-emitter": "^0.3.5", + "type": "^2.7.2" + }, + "engines": { + "node": ">=0.10" + } + }, "node_modules/esprima": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", @@ -1447,6 +2018,25 @@ "@types/estree": "^1.0.0" } }, + "node_modules/event-emitter": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz", + "integrity": "sha512-D9rRn9y7kLPnJ+hMq7S/nhvoKwwvVJahBi2BPmx3bvbsEdK3W9ii8cBSGjP+72/LnM4n6fo3+dkCX5FeTQruXA==", + "license": "MIT", + "dependencies": { + "d": "1", + "es5-ext": "~0.10.14" + } + }, + "node_modules/ext": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/ext/-/ext-1.7.0.tgz", + "integrity": "sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw==", + "license": "ISC", + "dependencies": { + "type": "^2.7.2" + } + }, "node_modules/extend": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", @@ -1738,6 +2328,28 @@ "node": ">=6.0" } }, + "node_modules/gray-matter/node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "license": "MIT", + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/gray-matter/node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "license": "MIT", + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, "node_modules/hasown": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", @@ -1933,6 +2545,18 @@ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", "license": "ISC" }, + "node_modules/intl-messageformat": { + "version": "10.7.10", + "resolved": "https://registry.npmjs.org/intl-messageformat/-/intl-messageformat-10.7.10.tgz", + "integrity": "sha512-hp7iejCBiJdW3zmOe18FdlJu8U/JsADSDiBPQhfdSeI8B9POtvPRvPh3nMlvhYayGMKLv6maldhR7y3Pf1vkpw==", + "license": "BSD-3-Clause", + "dependencies": { + "@formatjs/ecma402-abstract": "2.3.1", + "@formatjs/fast-memoize": "2.2.5", + "@formatjs/icu-messageformat-parser": "2.9.7", + "tslib": "2" + } + }, "node_modules/is-arrayish": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", @@ -2026,13 +2650,19 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/is-promise": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.2.2.tgz", + "integrity": "sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==", + "license": "MIT" + }, "node_modules/is-reference": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-3.0.2.tgz", - "integrity": "sha512-v3rht/LgVcsdZa3O2Nqs+NMowLOxeOm7Ay9+/ARQ2F+qEoANRcqrjAZKGN0v8ymUetZGgkp26LTnGT7H0Qo9Pg==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-3.0.3.tgz", + "integrity": "sha512-ixkJoqQvAP88E6wLydLGGqCJsrFUnqoH6HnaczB8XmDH1oaWU+xxdptvikTgaEhtZ53Ky6YXiBuUI2WXLMCwjw==", "license": "MIT", "dependencies": { - "@types/estree": "*" + "@types/estree": "^1.0.6" } }, "node_modules/isexe": { @@ -2066,13 +2696,12 @@ } }, "node_modules/js-yaml": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", - "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", "license": "MIT", "dependencies": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" + "argparse": "^2.0.1" }, "bin": { "js-yaml": "bin/js-yaml.js" @@ -2168,6 +2797,15 @@ "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", "license": "ISC" }, + "node_modules/lru-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/lru-queue/-/lru-queue-0.1.0.tgz", + "integrity": "sha512-BpdYkt9EvGl8OfWHDQPISVpcl5xZthb+XPsbELj5AQXxIC8IriDZIQYjBJPEm5rS420sjZ0TLEzRcq5KdBhYrQ==", + "license": "MIT", + "dependencies": { + "es5-ext": "~0.10.2" + } + }, "node_modules/magic-string": { "version": "0.30.11", "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.11.tgz", @@ -2213,6 +2851,25 @@ "svelte": "^3.56.0 || ^4.0.0 || ^5.0.0-next.120" } }, + "node_modules/memoizee": { + "version": "0.4.17", + "resolved": "https://registry.npmjs.org/memoizee/-/memoizee-0.4.17.tgz", + "integrity": "sha512-DGqD7Hjpi/1or4F/aYAspXKNm5Yili0QDAFAY4QYvpqpgiY6+1jOfqpmByzjxbWd/T9mChbCArXAbDAsTm5oXA==", + "license": "ISC", + "dependencies": { + "d": "^1.0.2", + "es5-ext": "^0.10.64", + "es6-weak-map": "^2.0.3", + "event-emitter": "^0.3.5", + "is-promise": "^2.2.2", + "lru-queue": "^0.1.0", + "next-tick": "^1.1.0", + "timers-ext": "^0.1.7" + }, + "engines": { + "node": ">=0.12" + } + }, "node_modules/merge2": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", @@ -2315,6 +2972,12 @@ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" } }, + "node_modules/next-tick": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.1.0.tgz", + "integrity": "sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==", + "license": "ISC" + }, "node_modules/nlcst-to-string": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/nlcst-to-string/-/nlcst-to-string-4.0.0.tgz", @@ -3465,6 +4128,90 @@ "svelte": "^3.19.0 || ^4.0.0" } }, + "node_modules/svelte-i18n": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/svelte-i18n/-/svelte-i18n-4.0.1.tgz", + "integrity": "sha512-jaykGlGT5PUaaq04JWbJREvivlCnALtT+m87Kbm0fxyYHynkQaxQMnIKHLm2WeIuBRoljzwgyvz0Z6/CMwfdmQ==", + "license": "MIT", + "dependencies": { + "cli-color": "^2.0.3", + "deepmerge": "^4.2.2", + "esbuild": "^0.19.2", + "estree-walker": "^2", + "intl-messageformat": "^10.5.3", + "sade": "^1.8.1", + "tiny-glob": "^0.2.9" + }, + "bin": { + "svelte-i18n": "dist/cli.js" + }, + "engines": { + "node": ">= 16" + }, + "peerDependencies": { + "svelte": "^3 || ^4 || ^5" + } + }, + "node_modules/svelte-i18n/node_modules/@esbuild/linux-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.19.12.tgz", + "integrity": "sha512-B71g1QpxfwBvNrfyJdVDexenDIt1CiDN1TIXLbhOw0KhJzE78KIFGX6OJ9MrtC0oOqMWf+0xop4qEU8JrJTwCg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/svelte-i18n/node_modules/esbuild": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.19.12.tgz", + "integrity": "sha512-aARqgq8roFBj054KvQr5f1sFu0D65G+miZRCuJyJ0G13Zwx7vRar5Zhn2tkQNzIXcBrNVsv/8stehpj+GAjgbg==", + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.19.12", + "@esbuild/android-arm": "0.19.12", + "@esbuild/android-arm64": "0.19.12", + "@esbuild/android-x64": "0.19.12", + "@esbuild/darwin-arm64": "0.19.12", + "@esbuild/darwin-x64": "0.19.12", + "@esbuild/freebsd-arm64": "0.19.12", + "@esbuild/freebsd-x64": "0.19.12", + "@esbuild/linux-arm": "0.19.12", + "@esbuild/linux-arm64": "0.19.12", + "@esbuild/linux-ia32": "0.19.12", + "@esbuild/linux-loong64": "0.19.12", + "@esbuild/linux-mips64el": "0.19.12", + "@esbuild/linux-ppc64": "0.19.12", + "@esbuild/linux-riscv64": "0.19.12", + "@esbuild/linux-s390x": "0.19.12", + "@esbuild/linux-x64": "0.19.12", + "@esbuild/netbsd-x64": "0.19.12", + "@esbuild/openbsd-x64": "0.19.12", + "@esbuild/sunos-x64": "0.19.12", + "@esbuild/win32-arm64": "0.19.12", + "@esbuild/win32-ia32": "0.19.12", + "@esbuild/win32-x64": "0.19.12" + } + }, + "node_modules/svelte-i18n/node_modules/estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", + "license": "MIT" + }, "node_modules/svelte-icons-pack": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/svelte-icons-pack/-/svelte-icons-pack-3.1.3.tgz", @@ -3475,9 +4222,9 @@ } }, "node_modules/svelte-youtube-embed": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/svelte-youtube-embed/-/svelte-youtube-embed-0.3.0.tgz", - "integrity": "sha512-Hg0IzZHSHgc8wvA1vhSqf3nPZolWSCClEjsCLscLPZRE9EDE2SjbBGsk7KvSfAgKJ5fIYmc5KqWHlC4b8wa5mw==", + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/svelte-youtube-embed/-/svelte-youtube-embed-0.3.3.tgz", + "integrity": "sha512-g4+53JauVB+Jwz486lVqW8PUTnoP1SinECWhmQSCaKuh6zrYiAOFRpzMG6vW1TaQfSigiLWyUactFWipo4lsfQ==", "peerDependencies": { "svelte": "^4.0.0" } @@ -3564,6 +4311,19 @@ "node": ">=0.8" } }, + "node_modules/timers-ext": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/timers-ext/-/timers-ext-0.1.8.tgz", + "integrity": "sha512-wFH7+SEAcKfJpfLPkrgMPvvwnEtj8W4IurvEyrKsDleXnKLCDw71w8jltvfLa8Rm4qQxxT4jmDBYbJG/z7qoww==", + "license": "ISC", + "dependencies": { + "es5-ext": "^0.10.64", + "next-tick": "^1.1.0" + }, + "engines": { + "node": ">=0.12" + } + }, "node_modules/tiny-glob": { "version": "0.2.9", "resolved": "https://registry.npmjs.org/tiny-glob/-/tiny-glob-0.2.9.tgz", @@ -3624,11 +4384,16 @@ "license": "Apache-2.0" }, "node_modules/tslib": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.7.0.tgz", - "integrity": "sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==", - "license": "0BSD", - "optional": true + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" + }, + "node_modules/type": { + "version": "2.7.3", + "resolved": "https://registry.npmjs.org/type/-/type-2.7.3.tgz", + "integrity": "sha512-8j+1QmAbPvLZow5Qpi6NCaN8FB60p/6x8/vfNqOk/hC+HuvFZhL4+WfekuhQLiqFZXOgQdrs3B+XxEmCc6b3FQ==", + "license": "ISC" }, "node_modules/unified": { "version": "11.0.5", diff --git a/package.json b/package.json index a7ed7fb5..6ef6ad75 100644 --- a/package.json +++ b/package.json @@ -10,14 +10,16 @@ "deploy": "gh-pages -d build -t true" }, "dependencies": { - "@sveltejs/adapter-static": "^3.0.5", - "@sveltejs/kit": "^2.6.3", + "@sveltejs/adapter-static": "^3.0.6", + "@sveltejs/kit": "^2.9.1", "@sveltejs/vite-plugin-svelte": "^3.1.2", "@tailwindcss/typography": "^0.5.15", "@types/three": "^0.169.0", "autoprefixer": "^10.4.20", + "cookie": "^1.0.2", "gh-pages": "^6.1.1", "gray-matter": "^4.0.3", + "js-yaml": "^4.1.0", "mdsvex": "^0.12.3", "postcss": "^8.4.47", "rehype-class-names": "^2.0.0", @@ -26,8 +28,9 @@ "remark-smartypants": "^3.0.2", "sharp": "^0.33.5", "svelte": "^4.2.19", + "svelte-i18n": "^4.0.1", "svelte-icons-pack": "^3.1.3", - "svelte-youtube-embed": "^0.3.0", + "svelte-youtube-embed": "^0.3.3", "svooltip": "^0.8.3", "tailwindcss": "^3.4.16", "vite": "^5.4.8" diff --git a/src/hooks.server.js b/src/hooks.server.js index b28f855d..1eac6454 100644 --- a/src/hooks.server.js +++ b/src/hooks.server.js @@ -1,10 +1,16 @@ import { existsSync, createReadStream } from "fs"; import { join } from "path"; +import { locale } from 'svelte-i18n'; export default join; /** @type {import('@sveltejs/kit').Handle} */ export async function handle({ event, resolve }) { + const lang = event.request.headers.get('accept-language')?.split(',')[0]; + if (lang) { + locale.set(lang); + } + if ( event.url.pathname.startsWith("/blog/") && event.url.pathname.match( diff --git a/src/lib/blocks/Blog.svelte b/src/lib/blocks/Blog.svelte index f57c91e1..74d5574c 100644 --- a/src/lib/blocks/Blog.svelte +++ b/src/lib/blocks/Blog.svelte @@ -1,7 +1,9 @@ - + -
-

- {blogTitle} -

+{#await waitLocale()} + +{:then} +
+

+ {$_("config.blog.title")} +

-
- {#await postsWithAuthor} - - {:then loadedPosts} -
- {#each loadedPosts as post} -
-

+
+ {#await postsWithAuthor} + + {:then loadedPosts} +
+ {#each loadedPosts as post} +

- {#if post.authorMetadata} -
- {#each post.authorMetadata as author} - {author.name} - {/each} -
-
- {#each post.authorMetadata as author} -

{author.name}

- {/each} -
- - Published on {formattedPubDate(post.meta.pub_date)} - -
-
- {/if} -

- {post.meta.summary} -

- - Read More… - -
- {/each} -
- - {:catch error} -

Error loading posts: {error.message}

- {/await} -
-
+ + {/each} +
+ + {:catch error} +

{$_("config.blog.error")}: {error.message}

+ {/await} + + +{/await} \ No newline at end of file + diff --git a/src/lib/blocks/BlogPage.svelte b/src/lib/blocks/BlogPage.svelte new file mode 100644 index 00000000..f457c538 --- /dev/null +++ b/src/lib/blocks/BlogPage.svelte @@ -0,0 +1,37 @@ + + + diff --git a/src/lib/blocks/ContentBlock.svelte b/src/lib/blocks/ContentBlock.svelte index 24672833..7b2ed289 100644 --- a/src/lib/blocks/ContentBlock.svelte +++ b/src/lib/blocks/ContentBlock.svelte @@ -1,16 +1,14 @@ @@ -100,100 +106,58 @@ {/if}
{#if content || buttons} -
- {#if content} -
- -
- {/if} - {#if buttons} - {#if buttons.length > 1} -
- {#each buttons as button} -
- {:else} -
- {#each buttons as button} -
- {/if} - {/if} -
+ + + {/if} {#if videoId || videoSources || tabs || imgSrc || innerColumns} -
- {#if videoId} - - {:else if videoSources} - - {:else if imgSrc} - {#if imgLink} - - - - {:else} - - {/if} - {:else if tabs} - - {:else if innerColumns} -
- {#each innerColumns as innerColumn} - {#if innerColumn.link} - - - - {:else} - - {/if} - {/each} -
- {/if} -
+ {/if}
- {#if $$slots.extraContent || extraContent} + {#if extraContent}
- {#if $$slots.extraContent} - + {#if typeof extraContent !== "object"} + {#if extraContent} + + {/if} {:else} - + {#if extraContent.title} + {#if extraContent.titleTag} + + {extraContent.title} + + {:else} +

{extraContent.title}

+ {/if} + {/if} + {#if extraContent.text} + {@html extraContent.text} + {/if} {/if}
{/if} diff --git a/src/lib/blocks/ContributorBlock.svelte b/src/lib/blocks/ContributorBlock.svelte index f0a352cd..be7e8e86 100644 --- a/src/lib/blocks/ContributorBlock.svelte +++ b/src/lib/blocks/ContributorBlock.svelte @@ -6,54 +6,47 @@ export let contributors; export let size = "medium"; - function isLastRow(index, columns) { - if (contributors.length === 0) { - console.error("There are no contributors to count"); - return - }; - const total = contributors.length; - const lastRowStart = Math.floor(total / columns) * columns; - return index >= lastRowStart; - } + // Define size-specific classes + const containerSizeClass = { + medium: "max-w-6xl", + large: "max-w-full" + }; + + const introSizeClass = { + small: "max-w-4xl text-md", + medium: "max-w-4xl text-xl", + large: "max-w-6xl text-xl" + }; + + const gridSizeClass = { + small: "grid grid-cols-1 grid-cols-8 sm:grid-cols-12 lg:grid-cols-23", + medium: "flex flex-wrap sm:gap-6 lg:gap-8", + large: "grid grid-cols-1 sm:grid-cols-3 md:grid-cols-3 sm:gap-6 lg:gap-8" + }; {#if contributors && contributors.length > 0}
{#if title}

{title}

{/if} + {#if intro}

{@html intro}

{/if} +
- {#each contributors as contributor, index} + {#each contributors as contributor}
diff --git a/src/lib/blocks/Footer.svelte b/src/lib/blocks/Footer.svelte index 6b234a91..9fe63ddb 100644 --- a/src/lib/blocks/Footer.svelte +++ b/src/lib/blocks/Footer.svelte @@ -1,36 +1,42 @@ -
- -
-

{footerTitle}

-
- {#each socialIcons as [icon, href]} -
-
+ +{/await} diff --git a/src/lib/blocks/Header.svelte b/src/lib/blocks/Header.svelte index ed5cc43e..e82e2b58 100644 --- a/src/lib/blocks/Header.svelte +++ b/src/lib/blocks/Header.svelte @@ -1,92 +1,122 @@ -
-
- - - - {title} {description} - +{#await waitLocale()} + +{:then} +
+
+ + + + {$_("config.site.title")} {$_("config.site.description")} + + + +
+ + - -
- - + + - - + + - - + + +
-
-
+
- -{#if isMenuOpen} -
-
- - + + {#if isMenuOpen} +
+
+ + +
-
-{/if} + {/if} +{/await} diff --git a/src/lib/blocks/Post.svelte b/src/lib/blocks/Post.svelte index f89226ca..d4a4a69f 100644 --- a/src/lib/blocks/Post.svelte +++ b/src/lib/blocks/Post.svelte @@ -1,12 +1,16 @@ diff --git a/src/lib/components/Button.svelte b/src/lib/components/Button.svelte index acbf1067..6262c20d 100644 --- a/src/lib/components/Button.svelte +++ b/src/lib/components/Button.svelte @@ -16,17 +16,17 @@ import { VscTerminalLinux } from "svelte-icons-pack/vsc"; let icons = { + download: BsDownload, facebook: BsFacebook, github: BsGithub, instagram: BsInstagram, - mastodon: BsMastodon, - twitter: BsTwitterX, - windows: BsWindows, linux: VscTerminalLinux, mac: BsApple, - unknown: BsQuestionCircleFill, - download: BsDownload, + mastodon: BsMastodon, rss: BsRssFill, + twitter: BsTwitterX, + unknown: BsQuestionCircleFill, + windows: BsWindows, }; export let button = true; @@ -42,29 +42,22 @@ export let fullwidth = false; export let textSize = ""; - let currentIcon = icons[icon]; + let currentIcon = icons[icon] || null; + let hasIcon = !!currentIcon && icon !== ""; - let hasIcon = icon !== "" && currentIcon !== undefined ? true : false; - let iconLeft = hasIcon && iconPosition === "left" ? true : false; - let iconRight = hasIcon && iconPosition === "right" ? true : false; - - if (textSize === 'xs') { - iconSize = iconSize * 0.8 - } else if (textSize === 'sm') { - iconSize = iconSize * 0.9 - } else if (textSize === 'lg') { - iconSize = iconSize * 1.2 - } else if (textSize === 'xl') { - iconSize = iconSize * 1.3 + if (textSize === "xs") { + iconSize *= 0.8; + } else if (textSize === "sm") { + iconSize *= 0.9; + } else if (textSize === "lg") { + iconSize *= 1.2; + } else if (textSize === "xl") { + iconSize *= 1.3; } - {#if iconLeft} - + {#if hasIcon && iconPosition === "left"} + {/if} @@ -91,8 +88,8 @@ {text} {/if} - {#if iconRight} - + {#if hasIcon && iconPosition === "right"} + {/if} @@ -111,11 +108,11 @@ @apply from-mine-shaft-50 to-mine-shaft-100 text-neutral-700 border border-mine-shaft-300; } - .button .icon-right { + .icon-left { margin-right: -0.4em; } - .button .icon-left { + .icon-right { margin-left: -0.4em; } diff --git a/src/lib/components/Card.svelte b/src/lib/components/Card.svelte index 002a1ed0..1bcb4cd3 100644 --- a/src/lib/components/Card.svelte +++ b/src/lib/components/Card.svelte @@ -2,21 +2,23 @@ import DynamicIcon from "$lib/components/DynamicIcon.svelte"; import Image from "$lib/components/Image.svelte"; - export let aspect = ""; export let innerColumn; + export let aspect = ""; export let classes = ""; + export let size = 48;
{#if innerColumn.icon} - + {:else if innerColumn.imgSrc} diff --git a/src/lib/components/ContentSection.svelte b/src/lib/components/ContentSection.svelte new file mode 100644 index 00000000..26e0567e --- /dev/null +++ b/src/lib/components/ContentSection.svelte @@ -0,0 +1,52 @@ + + +
+ {#if content} +
+ {#if typeof content !== "object"} + + {:else} + {#if content.title} + {#if content.titleTag} + + {content.title} + + {:else} +

{content.title}

+ {/if} + {/if} + {#if content.text} + {@html content.text} + {/if} + {/if} +
+ {/if} + {#if buttons} + {#if buttons.length > 1} +
+ {#each buttons as button} +
+ {:else} +
+ {#each buttons as button} +
+ {/if} + {/if} +
\ No newline at end of file diff --git a/src/lib/components/ContributorCard.svelte b/src/lib/components/ContributorCard.svelte index befd2387..c9705a8b 100644 --- a/src/lib/components/ContributorCard.svelte +++ b/src/lib/components/ContributorCard.svelte @@ -28,7 +28,7 @@ let tooltipHTML, tooltipOptions; - if (contributor.tooltip) { + $: if (contributor.tooltip) { tooltipHTML = generateTooltipHTML(contributor.tooltip); tooltipOptions = { content: tooltipHTML, diff --git a/src/lib/components/LanguageSelect.svelte b/src/lib/components/LanguageSelect.svelte new file mode 100644 index 00000000..d528c19c --- /dev/null +++ b/src/lib/components/LanguageSelect.svelte @@ -0,0 +1,134 @@ + + + + +
+ + + {#if isDropdownOpen} + + {/if} +
+ + diff --git a/src/lib/components/Loader.svelte b/src/lib/components/Loader.svelte index 1a26c313..fe3aa3f1 100644 --- a/src/lib/components/Loader.svelte +++ b/src/lib/components/Loader.svelte @@ -1,16 +1,15 @@ -
+
- +
diff --git a/src/lib/components/MediaSection.svelte b/src/lib/components/MediaSection.svelte new file mode 100644 index 00000000..4a8ff13e --- /dev/null +++ b/src/lib/components/MediaSection.svelte @@ -0,0 +1,65 @@ + + +
+ {#if videoId} + + {:else if videoSources} + + {:else if imgSrc} + {#if imgLink} + + + + {:else} + + {/if} + {:else if tabs} + + {:else if innerColumns} +
+ {#each innerColumns as innerColumn} + {#if innerColumn.link} + + + + {:else} + + {/if} + {/each} +
+ {/if} +
\ No newline at end of file diff --git a/src/lib/components/Metadata.svelte b/src/lib/components/Metadata.svelte index 1b5e23a4..73c6ebc4 100644 --- a/src/lib/components/Metadata.svelte +++ b/src/lib/components/Metadata.svelte @@ -1,16 +1,25 @@ - {$metadata.title} + {$metadata.title || title} @@ -19,7 +28,7 @@ rel="alternate" type="application/rss+xml" title="Spyder's Blog" - href="{siteUrl}{blogSlug}/feed.xml" + href="{siteUrl}/blog/feed.xml" /> @@ -28,8 +37,10 @@ - - + {#if $metadata.image.startsWith("https")} + + {/if} + diff --git a/src/lib/components/Pagination.svelte b/src/lib/components/Pagination.svelte index b2a76b9e..211bdd1d 100644 --- a/src/lib/components/Pagination.svelte +++ b/src/lib/components/Pagination.svelte @@ -1,4 +1,6 @@ + +{#if !socials} + +{:else} +
+ {#each socialIcons as [icon, href]} +
+{/if} diff --git a/src/lib/components/Tabs.svelte b/src/lib/components/Tabs.svelte index 6fcd50b0..d1d814d8 100644 --- a/src/lib/components/Tabs.svelte +++ b/src/lib/components/Tabs.svelte @@ -1,103 +1,170 @@ -
- {#each tabs as tab} + {#each tabs as tab, i} {/each}
-
- {#if isLoading} -
-
-
- {:else} - {#key currentKey} - {#if current.isVideo === true} -
- {#if VideoPlayer} - + {#key currentKey} + {#if current?.isVideo === true} +
+ {#if isLoading} +
+
+
+ {/if} +
+
+ {#if current.content.videoCaption}

{current.content.videoCaption}

{/if} - {/if} +
- {:else} -
+
+ {:else} +
+ {#if typeof current.content !== "object"} -
- {/if} - {/key} - {/if} + {:else if current.content.imgSrc} +
+ {current.content.imgAlt} + {#if current.content.text} +
{@html current.content.text}
+ {/if} +
+ {/if} +
+ {/if} + {/key}
diff --git a/src/lib/components/VideoPlayer.svelte b/src/lib/components/VideoPlayer.svelte index c791b4f7..9a3e8475 100644 --- a/src/lib/components/VideoPlayer.svelte +++ b/src/lib/components/VideoPlayer.svelte @@ -1,33 +1,51 @@ - {#if videoSources.length > 0} -
- - - -
- - - {#if info} -
- click anywhere to {paused ? "play" : "pause"} / drag to seek -
- {format(time)} - / - {format(duration)} + {#each videoSources as source} + {#if source.src} + + {/if} + {/each} + + + +
{ + showControls = true; + clearTimeout(showControlsTimeout); + }} + > + + + {#if info} +
+ + click anywhere to {paused ? "play" : "pause"} / drag to seek + +
+ {formatTime(time)} + / + {formatTime(duration || 0)} +
-
- {/if} + {/if} - {#if progress} - - {/if} + {#if progress} + + {/if} +
{/if} diff --git a/src/lib/config/data/config.yaml b/src/lib/config/data/config.yaml new file mode 100644 index 00000000..f610db9f --- /dev/null +++ b/src/lib/config/data/config.yaml @@ -0,0 +1,35 @@ +site: + keywords: + - Python + - IDE + - Spyder + - Matplotlib + - iPython + - Jupyter + - Science + - Data-Science + - Data-Analytics + - Programming + navigation: + - - href: /download/ + target: _self + - href: /about/ + target: _self + - href: /blog/ + target: _self + - href: https://docs.spyder-ide.org/ + target: _blank + heroImages: + dark: /assets/media/screenshot_dark.webp + light: /assets/media/screenshot_light.webp + githubButton: + highlight: false + icon: github + href: https://github.com/spyder-ide/spyder/ + socials: + github: https://github.com/spyder-ide/spyder + twitter: https://twitter.com/spyder_ide + facebook: https://www.facebook.com/SpyderIDE/ + mastodon: https://fosstodon.org/@Spyder + instagram: https://instagram.com/spyderide + rss: https://www.spyder-ide.org/blog/feed.xml diff --git a/src/lib/config/data/contributors.yaml b/src/lib/config/data/contributors.yaml new file mode 100644 index 00000000..bb6b6f83 --- /dev/null +++ b/src/lib/config/data/contributors.yaml @@ -0,0 +1,43 @@ +current: + - id: 365293 + name: Carlos Córdoba + - id: 16781833 + name: Daniel Althviz + - id: 17051931 + name: C.A.M. Gerlach + avatar_url: /assets/authors/camgerlach/pic.webp + - id: 6740194 + name: Quentin Peter + - id: 9618975 + name: Ryan Clary + - id: 7941918 + name: Jitse Niesen + - id: 42411448 + name: Juan Sebastian Bautista + - id: 5204788 + name: Hendrik D. Louzada + - id: 5027583 + name: Andrés Montoya +past: + - id: 1311787 + name: Pierre Raybaut + - id: 1878982 + name: Edgar Margffoy + - id: 50221806 + name: Isabela Presedo-Floyd + - id: 3627835 + name: Gonzalo Peña-Castellanos + - id: 18587879 + name: Juanita Gómez + - id: 10170372 + name: Jean-Sébastien Gosselin + - id: 20992645 + name: Stephannie Jimenez + - id: 2397974 + name: Sylvain Corlay + - id: 2024217 + name: Rafael Laverde + - id: 10513354 + name: Brian Olsen + - id: 2096628 + name: Steve Silvester diff --git a/src/lib/config/data/frontpage.yaml b/src/lib/config/data/frontpage.yaml new file mode 100644 index 00000000..91e55d93 --- /dev/null +++ b/src/lib/config/data/frontpage.yaml @@ -0,0 +1,89 @@ +- id: what-is-spyder-section + imgSrc: /assets/media/banner.svg + background: /assets/media/bg.svg + columns: false + divider: true + boxed: true + +- id: interactive-section + title: Interactive programming built in + divider: true + border: false + tabs: + - isVideo: true + content: + videoSources: + - src: /assets/media/variable_explorer.mp4 + - isVideo: true + content: + videoSources: + - src: /assets/media/help.mp4 + - isVideo: true + content: + videoSources: + - src: /assets/media/editor.mp4 + +- id: pydata-section + divider: true + tabs: + - content: + imgSrc: /assets/media/matplotlib.webp + - content: + imgSrc: /assets/media/pandas.webp + - content: + imgSrc: /assets/media/numpy.webp + - content: + imgSrc: /assets/media/conda.webp + - content: + imgSrc: /assets/media/sympy.webp + +- id: growth-section + divider: true + tabs: + - content: + imgSrc: /assets/media/developer_tools.webp + - content: + imgSrc: /assets/media/projects.webp + - content: + imgSrc: /assets/media/code_analysis.webp + - content: + imgSrc: /assets/media/search.webp + +- id: setup-section + divider: true + imgSrc: /assets/media/windows.webp + buttons: [] + +- id: sponsors-section + content: + titleTag: h1 + divider: true + columns: false + boxed: true + extraImage: /assets/media/sponsors.svg + extraImageLink: https://opencollective.com/spyder#support + innerColumns: + - imgSrc: /assets/media/czi_light.svg + imgSrcDark: /assets/media/czi_dark.svg + link: https://chanzuckerberg.com/ + - imgSrc: /assets/media/numfocus_lrg.png + link: https://numfocus.org/ + +- id: learn-more-section + columns: false + boxed: true + background: /assets/media/bg_more.svg + backgroundDark: /assets/media/bg_more_dark.svg + innerColumns: + - icon: BsYoutube + link: https://www.youtube.com/c/spyderide + aspect: xl:aspect-square + - icon: BsBookHalf + link: https://docs.spyder-ide.org + aspect: xl:aspect-square + - icon: BsGithub + link: https://github.com/spyder-ide/spyder + aspect: xl:aspect-square + - icon: BsHeartFill + link: https://opencollective.com/spyder + aspect: xl:aspect-square diff --git a/src/lib/config/data/releases.yaml b/src/lib/config/data/releases.yaml new file mode 100644 index 00000000..d012ecef --- /dev/null +++ b/src/lib/config/data/releases.yaml @@ -0,0 +1,15 @@ +windows: + x64: + name: Windows 10+ + link: https://github.com/spyder-ide/spyder/releases/latest/download/Spyder-Windows-x86_64.exe +linux: + x64: + name: Linux + link: https://github.com/spyder-ide/spyder/releases/latest/download/Spyder-Linux-x86_64.sh +mac: + arm64: + name: macOS 14.0+ (M1) + link: https://github.com/spyder-ide/spyder/releases/latest/download/Spyder-macOS-arm64.pkg + x64: + name: macOS 12.0+ (Intel) + link: https://github.com/spyder-ide/spyder/releases/latest/download/Spyder-macOS-x86_64.pkg diff --git a/src/lib/config/index.js b/src/lib/config/index.js index b272d8c9..50ed8aa5 100644 --- a/src/lib/config/index.js +++ b/src/lib/config/index.js @@ -1,124 +1,22 @@ -// Imports import { dev } from "$app/environment"; -import { base } from "$app/paths"; -import { PUBLIC_SITE_URL } from '$env/static/public'; +import { PUBLIC_SITE_URL } from "$env/static/public"; +import { loadYamlSafely } from "$lib/utils/yaml"; -////////////////////////////////////////////////////////////////// -// Site config -////////////////////////////////////////////////////////////////// +// Configuration options in YAML +import rawConfig from "./data/config.yaml?raw"; +import rawContributors from "./data/contributors.yaml?raw"; +import rawReleases from "./data/releases.yaml?raw"; +import rawFrontPage from "./data/frontpage.yaml?raw"; -// Base URL +// Site config export const siteUrl = dev ? "http://localhost:5173" : PUBLIC_SITE_URL; - -// Website metadata -export const title = "Spyder"; -export const subtitle = - "The Python IDE that scientists and data analysts deserve"; -export const comment = - "Designed by the community, for the community"; -export const author = "Spyder Website Contributors"; -export const description = "Get the ease of use of Jupyter along with many advanced features found in PyCharm and VSCode in a single programming environment"; -export const ogImage = `${siteUrl}assets/media/website_screenshot.png`; -export const keywords = [ - "Python", - "IDE", - "Spyder", - "Matplotlib", - "iPython", - "Jupyter", - "Science", - "Data-Science", - "Data-Analytics", - "Programming", -]; - -// Blog metadata -export const blogTitle = "Welcome to Spyder's Blog"; -export const blogDescription = description; -export const blogSlug = "blog"; -export const ogSlug = "og"; -export const ogImageBlog = `${siteUrl}assets/media/blog_screenshot.png`; - -// Navigation -export const navigation = [ - [ - { - text: "Download", - href: `${base}/download/`, - target: "_self", - }, - { - text: "About", - href: `${base}/about/`, - target: "_self", - }, - { - text: "Blog", - href: `${base}/${blogSlug}/`, - target: "_self", - }, - { - text: "Docs", - href: "https://docs.spyder-ide.org/", - target: "_blank", - }, - ], -]; - -// Social links (for footer and others) -export const socials = { - github: "https://github.com/spyder-ide/spyder", - twitter: "https://twitter.com/spyder_ide", - facebook: "https://www.facebook.com/SpyderIDE/", - mastodon: "https://fosstodon.org/@Spyder", - instagram: "https://instagram.com/spyderide", - rss: `${base}/blog/feed.xml` -}; - -// Hero content -export const heroContent = { - title: subtitle, - description: comment, -}; - -// Images in hero -export const heroImages = { - dark: `${base}/assets/media/screenshot_dark.webp`, - light: `${base}/assets/media/screenshot_light.webp`, -}; - -// Github button -export const githubButton = { - highlight: false, - icon: "github", - text: "Checkout on GitHub", - href: "https://github.com/spyder-ide/spyder/", -} - -// Download links -export const releases = { - windows: { - x64: { - name: "Windows 10+", - link: "https://github.com/spyder-ide/spyder/releases/latest/download/Spyder-Windows-x86_64.exe", - }, - }, - linux: { - x64: { - name: "Linux", - link: "https://github.com/spyder-ide/spyder/releases/latest/download/Spyder-Linux-x86_64.sh", - }, - }, - mac: { - arm64: { - name: "macOS 14.0+ (M1)", - link: "https://github.com/spyder-ide/spyder/releases/latest/download/Spyder-macOS-arm64.pkg", - }, - x64: { - name: "macOS 12.0+ (Intel)", - link: "https://github.com/spyder-ide/spyder/releases/latest/download/Spyder-macOS-x86_64.pkg", - }, - }, -}; - -export const footerTitle = "Connect with us on"; +export const ogImage = `${siteUrl}/assets/media/website_screenshot.png`; +export const ogImageBlog = `${siteUrl}/assets/media/blog_screenshot.png`; +export const blogPageStart = 1; +export const blogPageSize = 10; + +// Load configurations +export const config = loadYamlSafely(rawConfig, "config"); +export const contributors = loadYamlSafely(rawContributors, "contributors"); +export const releases = loadYamlSafely(rawReleases, "releases"); +export const frontpage = loadYamlSafely(rawFrontPage, "frontpage"); diff --git a/src/lib/content/code-analysis.md b/src/lib/content/code-analysis.md deleted file mode 100644 index 551d45b6..00000000 --- a/src/lib/content/code-analysis.md +++ /dev/null @@ -1 +0,0 @@ -![Spyder Code Analysis pane showing the results for a file, including an overall score and a listing of errors, warnings, refactoring and convention issues; each has a name, code, line number and message](/assets/media/code_analysis.webp "Get in-depth insight on issues and improvements with your code") \ No newline at end of file diff --git a/src/lib/content/conda.md b/src/lib/content/conda.md deleted file mode 100644 index a58b621b..00000000 --- a/src/lib/content/conda.md +++ /dev/null @@ -1 +0,0 @@ -![Spyder Consoles menu with the "New console in environment" submenu selected, showing a listing of Conda environments by name, type and Python version](/assets/media/conda.webp "Work with multiple environments at once") \ No newline at end of file diff --git a/src/lib/content/developer-tools.md b/src/lib/content/developer-tools.md deleted file mode 100644 index b4ccd274..00000000 --- a/src/lib/content/developer-tools.md +++ /dev/null @@ -1 +0,0 @@ -![Spyder Editor pane, with several real-time code analysis warnings shown on different lines and the affected code underlined. A hovered-over warning is showing its associated message, while the Source menu is open to the left showing the "Underline errors and warnings" option enabled](/assets/media/developer_tools.webp "Take advantage of real-time hints and help to improve your code") \ No newline at end of file diff --git a/src/lib/content/donations.md b/src/lib/content/donations.md deleted file mode 100644 index 0b6a9a08..00000000 --- a/src/lib/content/donations.md +++ /dev/null @@ -1 +0,0 @@ -## and the donations we have received from our users around the world through Open Collective: diff --git a/src/lib/content/ecosystem.md b/src/lib/content/ecosystem.md deleted file mode 100644 index 7609185b..00000000 --- a/src/lib/content/ecosystem.md +++ /dev/null @@ -1,3 +0,0 @@ -## A perfect fit with the most popular scientific libraries - -Spyder includes out of the box integration with [Matplotlib](https://matplotlib.org/), [Pandas](https://pandas.pydata.org/) and many other libraries to help you work more efficiently with them. diff --git a/src/lib/content/footer-content.md b/src/lib/content/footer-content.md deleted file mode 100644 index 81a3b847..00000000 --- a/src/lib/content/footer-content.md +++ /dev/null @@ -1,5 +0,0 @@ -© 2024 [Spyder Website Contributors](https://github.com/spyder-ide/spyder-website/graphs/contributors) | [MIT License](https://github.com/spyder-ide/spyder-website/blob/main/LICENSE.md) - -Made by [@conradolandia](https://github.com/conradolandia/) with 🖤 using [SvelteKit](https://kit.svelte.dev/) - -Feature icons by [sip](https://github.com/leshak/svelte-icons-pack) | Markdown processed using [mdsvex](https://mdsvex.pngwn.io/) diff --git a/src/lib/content/growth.md b/src/lib/content/growth.md deleted file mode 100644 index c5a63e0f..00000000 --- a/src/lib/content/growth.md +++ /dev/null @@ -1,3 +0,0 @@ -## Make a bigger impact with reusable research - -The software you write is critical for new scientific discoveries and engineering solutions. Spyder helps you move from single scripts to structured, reusable modules and packages without losing interactivity. It also includes powerful software development tools whenever you’re ready for them. diff --git a/src/lib/content/interactive.md b/src/lib/content/interactive.md deleted file mode 100644 index 763a9284..00000000 --- a/src/lib/content/interactive.md +++ /dev/null @@ -1,3 +0,0 @@ -## Works the way scientists do - -Data analysts, scientists and engineers require a lot of experimentation, quick feedback and short iteration cycles while programming. Spyder was built from the ground up around that workflow. diff --git a/src/lib/content/matplotlib.md b/src/lib/content/matplotlib.md deleted file mode 100644 index 505464f1..00000000 --- a/src/lib/content/matplotlib.md +++ /dev/null @@ -1 +0,0 @@ -![Spyder plots pane displaying a 3D visualization in the main panel, with options above for saving, zooming or removing it, and a right panel with thumbnails of other previous plots](/assets/media/matplotlib.webp "Browse all your plots in a single place") \ No newline at end of file diff --git a/src/lib/content/numpy.md b/src/lib/content/numpy.md deleted file mode 100644 index bfa84255..00000000 --- a/src/lib/content/numpy.md +++ /dev/null @@ -1 +0,0 @@ -![Spyder Variable Explorer pane displaying a three-dimensional NumPy in a "spreadsheet" style view, with cell colors forming a heatmap of values and options to adjust the axis and index of the array slice](/assets/media/numpy.webp "Explore and edit multi-dimensional arrays") \ No newline at end of file diff --git a/src/lib/content/pandas.md b/src/lib/content/pandas.md deleted file mode 100644 index fb1714df..00000000 --- a/src/lib/content/pandas.md +++ /dev/null @@ -1 +0,0 @@ -![Spyder Variable Explorer pane showing a pandas dataframe containing weather observations in a "spreadsheet" style view, with multi-level index columns, per-column heatmaps and toolbar options for displaying and editing the data](/assets/media/pandas.webp "Interact with the contents of your dataframes") \ No newline at end of file diff --git a/src/lib/content/projects.md b/src/lib/content/projects.md deleted file mode 100644 index e3950484..00000000 --- a/src/lib/content/projects.md +++ /dev/null @@ -1 +0,0 @@ -![Spyder Editor pane showing the Projects pane to its left, listing the files and directories of a project in a tree-style layout](/assets/media/projects.webp "Easily switch between projects and browse their files") \ No newline at end of file diff --git a/src/lib/content/search.md b/src/lib/content/search.md deleted file mode 100644 index fdcfd201..00000000 --- a/src/lib/content/search.md +++ /dev/null @@ -1 +0,0 @@ -![Spyder Find pane, showing an example search for a method name, buttons toggling search options, an exclude field listing various file extensions, a dropdown for search location and a count and list of results per-file, including the file name and path and the line, column and context for each result](/assets/media/search.webp "Quickly find uses of a variable or word across files") \ No newline at end of file diff --git a/src/lib/content/setup.md b/src/lib/content/setup.md deleted file mode 100644 index bc49f9ee..00000000 --- a/src/lib/content/setup.md +++ /dev/null @@ -1,3 +0,0 @@ -## Install with a single click and be productive right away - -Spyder offers standalone installers to make it as easy and reliable as possible to get started and keep it up to date. diff --git a/src/lib/content/sponsors.md b/src/lib/content/sponsors.md deleted file mode 100644 index 0e58341a..00000000 --- a/src/lib/content/sponsors.md +++ /dev/null @@ -1 +0,0 @@ -# Spyder is funded thanks to the generous support of diff --git a/src/lib/content/sympy.md b/src/lib/content/sympy.md deleted file mode 100644 index c5fccc87..00000000 --- a/src/lib/content/sympy.md +++ /dev/null @@ -1 +0,0 @@ -![Spyder's IPython Console pane, showing individual lines of code constructing SymPy expressions, and several complex symbolic formulas rendered inline in publication-style rich mathematical notation](/assets/media/sympy.webp "View rich symbolic expressions rendered with LaTeX") \ No newline at end of file diff --git a/src/lib/content/what-is.md b/src/lib/content/what-is.md deleted file mode 100644 index 71391e96..00000000 --- a/src/lib/content/what-is.md +++ /dev/null @@ -1 +0,0 @@ -### Get the ease of use of Jupyter along with many advanced features found in PyCharm and VSCode in a single programming environment diff --git a/src/lib/i18n/en-US/about.yaml b/src/lib/i18n/en-US/about.yaml new file mode 100644 index 00000000..3f922159 --- /dev/null +++ b/src/lib/i18n/en-US/about.yaml @@ -0,0 +1,10 @@ +pageTitle: Who We Are +pageIntro: >- + Spyder is an open source, community-developed scientific environment and IDE written in Python, for Python. + As scientists, engineers and analysts just like you, we built it to combine the power of a comprehensive development tool with the speed of an interactive data exploration package, all in one easy-to-use interface. +currentTitle: Core team +pastTitle: Past team members +remainingTitle: Contributor community +remainingIntro: >- + Spyder is made possible by a collective of developers, testers, translators and donors, hailing from all around the globe! + We exist by and for our worldwide community, and even the smallest contribution makes a world of different for us all. diff --git a/src/lib/i18n/en-US/config.yaml b/src/lib/i18n/en-US/config.yaml new file mode 100644 index 00000000..df7de421 --- /dev/null +++ b/src/lib/i18n/en-US/config.yaml @@ -0,0 +1,32 @@ +site: + title: Spyder + subtitle: The Python IDE that scientists and data analysts deserve + comment: Designed by the community, for the community + author: Spyder Website Contributors + description: Get the ease of use of Jupyter along with many advanced features found in PyCharm and VSCode in a single programming environment + navigation: + - - text: Download + - text: About + - text: Blog + - text: Docs + footer: + title: Connect with us on + content: >- +

© 2024 Spyder Website Contributors | MIT License

+

Made by @conradolandia with 🖤 using SvelteKit

+

Feature icons by sip | Markdown processed using mdsvex

+ heroContent: + title: The Python IDE that scientists and data analysts deserve + description: Designed by the community, for the community + githubButton: + text: Checkout on GitHub + +blog: + title: "Welcome to Spyder's Blog" + description: Get the ease of use of Jupyter along with many advanced features found in PyCharm and VSCode in a single programming environment + previous: Previous + next: Next + publishedOn: Published on + readMore: Read More + error: Error loading posts + metadataError: Error fetching author metadata diff --git a/src/lib/i18n/en-US/contributors.yaml b/src/lib/i18n/en-US/contributors.yaml new file mode 100644 index 00000000..fd7ab758 --- /dev/null +++ b/src/lib/i18n/en-US/contributors.yaml @@ -0,0 +1,125 @@ +current: + - id: 365293 + role: Lead mantainer + tooltip: + - list: + - Lead maintainer since 2013 + - id: 16781833 + role: Co-mantainer + tooltip: + - list: + - Release manager + - Maintainer of QtPy and QtAwesome + - Manager of NumFOCUS small development grants + - id: 17051931 + role: Core developer + tooltip: + - list: + - Docs maintainer + - "Technical, grant and blog writer" + - Outreach lead + - id: 6740194 + role: Core developer + tooltip: + - list: + - Re-architectured communications between Spyder and Spyder-Kernels + - Creator of the Debugger pane + - Many improvements to the IPython console + - id: 9618975 + role: Core developer + tooltip: + - list: + - Maintainer of the standalone installers + - id: 7941918 + role: Core developer + tooltip: + - list: + - External plugins maintainer + - id: 42411448 + role: Junior developer + tooltip: + - list: + - "Improvements to the Windows installer, QtConsole and Spyder's UI/UX" + - id: 5204788 + role: Junior developer + tooltip: + - list: + - Developed backend for the remote client plugin + - id: 5027583 + role: Graphic and web designer + tooltip: + - list: + - Developer and maintainer of this website + - UI/UX improvements + - Social media graphics designer +past: + - id: 1311787 + role: Spyder Creator + tooltip: + - list: + - Created Spyder in 2009 + - Lead maintainer until 2013 + - id: 1878982 + role: Core developer + tooltip: + - list: + - LSP support for the entire application + - Re-architectured plugin registration and interactions + - New architecture for the Run plugin + - "Add global registries for actions, menus and toolbars" + - id: 50221806 + role: Designer + tooltip: + - list: + - New color system and palette for the application + - Logo redesign + - Many UI/UX improvements + - id: 3627835 + role: Core developer + tooltip: + - list: + - Redesigned the plugins API + - Creator of QtPy + - Improved configuration system and added tests for it + - Many improvements to the Editor + - id: 18587879 + role: Core developer + tooltip: + - list: + - Docs writer + - "Main content creator for Spyder's YouTube channel" + - Community manager + - id: 10170372 + role: Core developer + tooltip: + - list: + - Creator of the Plots plane + - Many improvements across the entire application + - id: 20992645 + role: Core developer + tooltip: + - list: + - Spyder-Terminal maintainer + - New architecture for the Run plugin + - Enhancements to the icon manager + - id: 2397974 + role: Core developer + tooltip: + - list: + - New icon theme for Spyder + - Creator of QtAwesome + - id: 2024217 + role: Core developer + tooltip: + - list: + - Improvements to the Editor + - id: 10513354 + role: Core developer + tooltip: + - list: + - Improvements to the IPython console + - id: 2096628 + role: Core developer + tooltip: + - list: + - "Code completion, keybindings and file opening improvements" diff --git a/src/lib/i18n/en-US/download.yaml b/src/lib/i18n/en-US/download.yaml new file mode 100644 index 00000000..d1728c96 --- /dev/null +++ b/src/lib/i18n/en-US/download.yaml @@ -0,0 +1,10 @@ +title: Download Spyder +subtitle: If the download does not start automatically, please click the button below +alternative: To download Spyder for the detected OS, please click the button below +detected: detected +button: + message: Download for +action: + name: Download + title: Download Started... + alternative: Alternatively, you can manually select the package you want from the buttons below, or visit our releases page on GitHub. diff --git a/src/lib/i18n/en-US/frontpage.yaml b/src/lib/i18n/en-US/frontpage.yaml new file mode 100644 index 00000000..fe7825f5 --- /dev/null +++ b/src/lib/i18n/en-US/frontpage.yaml @@ -0,0 +1,109 @@ +- id: what-is-spyder-section + title: The Spyder advantage + extraContent: + title: >- + Get the ease of use of Jupyter along with many advanced features + found in PyCharm and VSCode in a single programming environment + +- id: interactive-section + title: Interactive programming built in + content: + title: Works the way scientists do + text: >- +

Data analysts, scientists and engineers require a lot of + experimentation, quick feedback and short iteration cycles + while programming. Spyder was built from the ground up + around that workflow.

+ tabs: + - title: Variable Explorer + content: + videoCaption: Explore variables after execution + - title: Help + content: + videoCaption: Get help for code you're working on with one click + - title: Editor + content: + videoCaption: Run code in line by line or in sections called "cells" + +- id: pydata-section + title: Seamless integration with the PyData ecosystem + content: + title: A perfect fit with the most popular scientific libraries + text: >- +

Spyder includes out of the box integration with + Matplotlib, + Pandas + and many other libraries to help you work more efficiently with them.

+ tabs: + - title: Matplotlib + content: + text: Browse all your plots in a single place + imgAlt: Spyder plots pane displaying a 3D visualization in the main panel, with options above for saving, zooming or removing it, and a right panel with thumbnails of other previous plots + - title: Pandas + content: + text: Interact with the contents of your dataframes + imgAlt: Spyder Variable Explorer pane showing a pandas dataframe containing weather observations in a "spreadsheet" style view, with multi-level index columns, per-column heatmaps and toolbar options for displaying and editing the data + - title: Numpy + content: + text: Explore and edit multi-dimensional arrays + imgAlt: Spyder Variable Explorer pane displaying a three-dimensional NumPy in a "spreadsheet" style view, with cell colors forming a heatmap of values and options to adjust the axis and index of the array slice + - title: Conda + content: + text: Work with multiple environments at once + imgAlt: Spyder Consoles menu with the "New console in environment" submenu selected, showing a listing of Conda environments by name, type and Python version + - title: Sympy + content: + text: View rich symbolic expressions rendered with LaTeX + imgAlt: Spyder's IPython Console pane, showing individual lines of code constructing SymPy expressions, and several complex symbolic formulas rendered inline in publication-style rich mathematical notation + +- id: growth-section + title: Ready to take you to the next level + content: + title: Make a bigger impact with reusable research + text: >- +

The software you write is critical for new scientific discoveries and engineering solutions. Spyder helps you move from single scripts to structured, reusable modules and packages without losing interactivity. It also includes powerful software development tools whenever you're ready for them.

+ tabs: + - title: Developer tools + content: + text: Take advantage of real-time hints and help to improve your code + imgAlt: Spyder Editor pane, with several real-time code analysis warnings shown on different lines and the affected code underlined. A hovered-over warning is showing its associated message, while the Source menu is open to the left showing the "Underline errors and warnings" option enabled + - title: Projects + content: + text: Easily switch between projects and browse their files + imgAlt: Spyder Editor pane showing the Projects pane to its left, listing the files and directories of a project in a tree-style layout + - title: Code analysis + content: + text: Get in-depth insight on issues and improvements with your code + imgAlt: Spyder Code Analysis pane showing the results for a file, including an overall score and a listing of errors, warnings, refactoring and convention issues; each has a name, code, line number and message + - title: Code search + content: + text: Quickly find uses of a variable or word across files + imgAlt: Spyder Find pane, showing an example search for a method name, buttons toggling search options, an exclude field listing various file extensions, a dropdown for search location and a count and list of results per-file, including the file name and path and the line, column and context for each result + +- id: setup-section + title: Simple install and update process + content: + title: Install with a single click and be productive right away + text:

Spyder offers standalone installers to make it as easy and reliable as possible to get started and keep it up to date.

+ +- id: sponsors-section + title: Sponsors + content: + title: Spyder is funded thanks to the generous support of + extraContent: + title: "and the donations we have received from our users around the world through Open Collective:" + extraImageAlt: Donate to our project + innerColumns: + - imgAlt: Chan Zuckerberg Initiative logo + - imgAlt: NumFocus logo + +- id: learn-more-section + innerColumns: + - title: YouTube + content: Learn more + - title: Documentation + content: Read the docs + - title: GitHub + content: Check out the source + - title: Donations + content: Show your support diff --git a/src/lib/i18n/es-ES/about.yaml b/src/lib/i18n/es-ES/about.yaml new file mode 100644 index 00000000..a1fd7abb --- /dev/null +++ b/src/lib/i18n/es-ES/about.yaml @@ -0,0 +1,9 @@ +pageTitle: Quienes somos +pageIntro: >- + Spyder es un entorno científico e IDE de código abierto, desarrollado de forma comunitaria y escrito en Python para Python. + Al ser científicos, ingenieros y analistas de datos como tú, lo hemos desarrollado para combinar la potencia de una herramienta de desarrollo integral con la velocidad de un paquete de exploración de datos interactivo, todo en una interfaz fácil de usar. +currentTitle: Equipo principal +pastTitle: Antiguos miembros +remainingTitle: Comunidad de contribuyentes +remainingIntro: >- + !Spyder es posible gracias a un colectivo de desarrolladores, evaluadores, traductores y donantes de todo el mundo! Nosotros existimos por y para nuestra comunidad mundial, e incluso la contribución más pequeña supone una gran diferencia para todos nosotros para todos nosotros. diff --git a/src/lib/i18n/es-ES/config.yaml b/src/lib/i18n/es-ES/config.yaml new file mode 100644 index 00000000..38782f95 --- /dev/null +++ b/src/lib/i18n/es-ES/config.yaml @@ -0,0 +1,32 @@ +site: + title: Spyder + subtitle: El entorno de desarrollo para Python que los científicos y analistas de datos merecen + comment: Diseñado por la comunidad, para la comunidad + author: Contribuyentes al sitio web de Spyder + description: Obtenga la facilidad de uso de Jupyter junto a muchas funciones avanzadas que se encuentran en PyCharm y VSCode en un único entorno de programación + navigation: + - - text: Descarga + - text: Acerca de + - text: Blog + - text: Docs + footer: + title: Conecta con nosotros en + content: >- +

© 2024 Spyder Website Contributors | MIT License

+

Hecho por @conradolandia con 🖤 usando SvelteKit

+

Se usan íconos de sip | Markdown procesado con mdsvex

+ heroContent: + title: El entorno de desarrollo para Python que los científicos y analistas de datos merecen + description: Diseñado por la comunidad, para la comunidad + githubButton: + text: Checkout en GitHub + +blog: + title: Bienvenidos al Blog de Spyder + description: Obtenga la facilidad de uso de Jupyter junto a muchas funciones avanzadas que se encuentran en PyCharm y VSCode en un único entorno de programación + previous: Anterior + next: Siguiente + publishedOn: Publicado el + readMore: Leer más + error: Error cargando entradas + metadataError: Error obteniendo metadatos de autor diff --git a/src/lib/i18n/es-ES/contributors.yaml b/src/lib/i18n/es-ES/contributors.yaml new file mode 100644 index 00000000..e220a129 --- /dev/null +++ b/src/lib/i18n/es-ES/contributors.yaml @@ -0,0 +1,146 @@ +current: + - id: 365293 + name: Carlos Córdoba + role: Responsable principal de mantenimiento + tooltip: + - list: + - Responsable principal desde el 2013 + - id: 16781833 + name: Daniel Althviz + role: Co-responsable de mantenimiento + tooltip: + - list: + - Mánager de lanzamientos + - Responsable del mantenimiento de QtPy y QtAwesome + - Mánager de pequeñas becas de desarrollo de NumFOCUS + - id: 17051931 + name: C.A.M. Gerlach + role: Desarrollador principal + avatar_url: /assets/authors/camgerlach/pic.webp + tooltip: + - list: + - Responsable de la documentación + - "Escritor técnico, de blogs y propuestas" + - Responsable de divulgación + - id: 6740194 + name: Quentin Peter + role: Desarrollador principal + tooltip: + - list: + - Rediseñó las comunicaciones entre Spyder y Spyder-Kernels + - Creador del panel del Depurador + - Muchas mejoras a la Terminal de IPython + - id: 9618975 + name: Ryan Clary + role: Desarrollador principal + tooltip: + - list: + - Responsable de los instaladores independientes + - id: 7941918 + name: Jitse Niesen + role: Desarrollador principal + tooltip: + - list: + - Responsable de los plugins externos + - id: 42411448 + name: Juan Sebastian Bautista + role: Desarrollador junior + tooltip: + - list: + - "Mejoras al instalador de Windows, QtConsole y el UI/UX de Spyder" + - id: 5204788 + name: Hendrik D. Louzada + role: Desarrollador junior + tooltip: + - list: + - Desarrolló el backend para el plugin del cliente remoto + - id: 5027583 + name: Andrés Montoya + role: Diseñador gráfico y web + tooltip: + - list: + - Desarrollador y responsable de este sitio web + - Mejoras de UI/UX + - Diseñador de gráficos para redes sociales +past: + - id: 1311787 + name: Pierre Raybaut + role: Creador de Spyder + tooltip: + - list: + - Creó Spyder en el 2009 + - Responsable principal hasta el 2013 + - id: 1878982 + name: Edgar Margffoy + role: Desarrollador principal + tooltip: + - list: + - Soporte de LSP para toda la applicación + - Rediseñó el registro y la interacción entre plugins + - Nueva arquitectura para el plugin de Run + - "Añadió registros globales para acciones, menús y toolbars" + - id: 50221806 + name: Isabela Presedo-Floyd + role: Diseñadora + tooltip: + - list: + - Nuevo sistema de colores y paleta para la aplicación + - Rediseño del logo + - Muchas mejoras de UI/UX + - id: 3627835 + name: Gonzalo Peña-Castellanos + role: Desarrollador principal + tooltip: + - list: + - Rediseñó la API de los plugins + - Creador de QtPy + - Mejoró el sistema configuración y añadió tests al mismo + - Muchas mejoras al Editor + - id: 18587879 + name: Juanita Gómez + role: Desarrolladora principal + tooltip: + - list: + - Escritora de documentación + - "Principal creadora de contenido para el canal de YouTube de Spyder" + - Gestora comunitaria + - id: 10170372 + name: Jean-Sébastien Gosselin + role: Desarrollador principal + tooltip: + - list: + - Creador del panel de Gráficos + - Muchas mejoras en toda la aplicación + - id: 20992645 + name: Stephannie Jimenez + role: Desarrolladora principal + tooltip: + - list: + - Responsable de Spyder-Terminal + - Nueva arquitectura para el plugin de Run + - Mejoras al gestor de iconos + - id: 2397974 + name: Sylvain Corlay + role: Desarrollador principal + tooltip: + - list: + - Nuevo tema de íconos para Spyder + - Creador de QtAwesome + - id: 2024217 + name: Rafael Laverde + role: Desarrollador principal + tooltip: + - list: + - Mejoras al editor + - id: 10513354 + name: Brian Olsen + role: Desarrollador principal + tooltip: + - list: + - Mejoras a la Terminal de IPython + - id: 2096628 + name: Steve Silvester + role: Desarrollador principal + tooltip: + - list: + - "Mejoras al completado de código, atajos de teclado y apertura de archivos" diff --git a/src/lib/i18n/es-ES/download.yaml b/src/lib/i18n/es-ES/download.yaml new file mode 100644 index 00000000..a6319a4f --- /dev/null +++ b/src/lib/i18n/es-ES/download.yaml @@ -0,0 +1,10 @@ +title: Descargar Spyder +subtitle: Si la descarga no se inicia automáticamente, usa el siguiente botón +alternative: Descarga Spyder para el sistema operativo detectado usando el siguiente botón +detected: detectado +button: + message: Descargar para +action: + name: Descarga + title: Descarga iniciada... + alternative: De manera alternativa, puedes seleccionar manualmente el paquete que deseas descargar usando los siguientes botones, o visitar nuestra página de lanzamientos en GitHub. diff --git a/src/lib/i18n/es-ES/frontpage.yaml b/src/lib/i18n/es-ES/frontpage.yaml new file mode 100644 index 00000000..03a5491b --- /dev/null +++ b/src/lib/i18n/es-ES/frontpage.yaml @@ -0,0 +1,109 @@ +- id: what-is-spyder-section + title: La ventaja de Spyder + extraContent: + title: >- + Obtenga la facilidad de uso de Jupyter, junto a muchas más características avanzadas + que se encuentran en PyCharm y VSCode, en un solo entorno de programación + +- id: interactive-section + title: Programación interactiva integrada + content: + title: Trabaja como lo hacen los científicos + text: >- +

Los analistas de datos, científicos e ingenieros requieren mucha + experimentación, retroalimentación rápida y ciclos de iteración + cortos al programar. Spyder fue diseñado desde el inicio + en torno a ese flujo de trabajo.

+ tabs: + - title: Explorador de Variables + content: + videoCaption: Explora variables tras la ejecución + - title: Ayuda + content: + videoCaption: Obtén ayuda para el código en el que estás trabajando con un solo clic + - title: Editor + content: + videoCaption: Ejecuta código línea por línea o en secciones llamadas "celdas" + +- id: pydata-section + title: Perfecta integración con el ecosistema PyData + content: + title: Se integra muy bien con las librerías científicas más populares + text: >- +

Spyder incluye integración lista para usar con + Matplotlib, + Pandas + y muchas otras librerías para ayudarte a trabajar más eficientemente con ellas.

+ tabs: + - title: Matplotlib + content: + text: Examina todos tus gráficos en un solo lugar + imgAlt: Panel de gráficos de Spyder mostrando una visualización 3D en el panel principal, con opciones en la parte superior para guardar, ampliar o eliminar imágenes, y un panel derecho con miniaturas de otros gráficos anteriores + - title: Pandas + content: + text: Interactúa con el contenido de tus dataframes + imgAlt: Explorador de Variables de Spyder mostrando un dataframe de pandas con observaciones meteorológicas, en un estilo de vista tipo "hoja de cálculo", con columnas de índice de múltiples niveles, mapas de calor por columna y opciones de barra de herramientas para mostrar y editar los datos + - title: Numpy + content: + text: Explora y edita arreglos multidimensionales + imgAlt: Explorador de Variables de Spyder mostrando un arreglo tridimensional de NumPy, en un estilo de vista tipo "hoja de cálculo", con colores de celda que forman un mapa de calor de valores y opciones para ajustar el eje y el índice del slicing del arreglo + - title: Conda + content: + text: Trabaja con múltiples entornos a la vez + imgAlt: Menú Terminales de Spyder con el submenú "Nueva terminal en entorno" seleccionado, mostrando una lista de entornos Conda por nombre, tipo y versión de Python + - title: Sympy + content: + text: Visualiza expresiones simbólicas enriquecidas renderizadas con LaTeX + imgAlt: Panel de Terminal de IPython de Spyder, mostrando líneas individuales de código construyendo expresiones de SymPy, y varias fórmulas simbólicas complejas renderizadas en línea con notación matemática enriquecida estilo publicación + +- id: growth-section + title: Preparado para llevarte al siguiente nivel + content: + title: Logra un mayor impacto con investigación reutilizable + text: >- +

El software que escribes es fundamental para nuevos descubrimientos científicos y soluciones de ingeniería. Spyder te ayuda a pasar de archivos individuales a módulos y paquetes estructurados y reutilizables sin perder interactividad. También incluye potentes herramientas de desarrollo de software cuando estés listo para usarlas.

+ tabs: + - title: Herramientas para desarrolladores + content: + text: Aprovecha sugerencias y ayuda en tiempo real para mejorar tu código + imgAlt: Panel del Editor de Spyder, con varias advertencias de análisis de código en tiempo real mostradas en diferentes líneas y el código afectado subrayado. Una advertencia seleccionada muestra su mensaje asociado, mientras que el menú Código fuente está abierto a la izquierda con la opción "Subrayar errores y advertencias" habilitada + - title: Proyectos + content: + text: Cambia fácilmente entre proyectos y explora sus archivos + imgAlt: Panel del Editor de Spyder mostrando a la izquierda el panel de Proyectos, que lista los archivos y directorios de un proyecto en un diseño tipo árbol + - title: Análisis de código + content: + text: Obtén una visión más profunda sobre problemas y mejoras en tu código + imgAlt: Panel de Análisis del Código de Spyder mostrando los resultados para un archivo, incluyendo un puntaje general y un listado de errores, advertencias, problemas de refactorización y convenciones; cada uno con un nombre, código, número de línea y mensaje + - title: Búsqueda de código + content: + text: Encuentra rápidamente los usos de una variable o palabra en distintos archivos + imgAlt: Panel de Búsqueda de Spyder, mostrando un ejemplo de búsqueda de un nombre de método, botones que activan opciones de búsqueda, un campo de exclusión con varias extensiones de archivo, un desplegable para localizar la búsqueda y un conteo/listado de resultados por archivo, incluyendo nombre, ruta, número de línea, columna y el contexto de cada resultado + +- id: setup-section + title: Sencillo proceso de instalación y actualización + content: + title: Instala Spyder con un solo clic y sé productivo de inmediato + text:

Spyder ofrece instaladores independientes que hacen que sea lo más fácil y confiable posible iniciar con el programa y mantenerlo actualizado.

+ +- id: sponsors-section + title: Patrocinadores + content: + title: Spyder es financiado gracias al generoso apoyo de + extraContent: + title: "y las donaciones que hemos recibido de nuestros usuarios en todo el mundo a través de Open Collective:" + extraImageAlt: Dona a nuestro proyecto + innerColumns: + - imgAlt: Logo de Chan Zuckerberg Initiative + - imgAlt: Logo de NumFocus + +- id: learn-more-section + innerColumns: + - title: YouTube + content: Aprende más + - title: Documentación + content: Lee la documentación + - title: GitHub + content: Explora el código fuente + - title: Donaciones + content: Muestra tu apoyo \ No newline at end of file diff --git a/src/lib/i18n/index.js b/src/lib/i18n/index.js new file mode 100644 index 00000000..da3eac09 --- /dev/null +++ b/src/lib/i18n/index.js @@ -0,0 +1,198 @@ +import { init, register } from "svelte-i18n"; +import { browser } from "$app/environment"; +import { loadYamlSafely } from '$lib/utils/yaml'; + +/** + * A minimal dictionary object containing basic site configuration + * Used as a fallback when translation files cannot be loaded + * @type {Object} Dictionary containing site configuration + * @property {Object} config - Configuration object + * @property {Object} config.site - Site-specific configuration + * @property {string} config.site.title - The site title + * @property {string} config.site.description - The site description + * @property {string} config.site.author - The site author/contributors + */ +const MINIMAL_DICTIONARY = { + config: { + site: { + title: 'Spyder IDE', + description: 'The Scientific Python Development Environment', + author: 'Spyder Project Contributors' + } + } +} + +/** + * Maps language codes to their normalized variants based on available languages + * This helps map similar locales to our supported ones (e.g., 'en-GB' -> 'en-US') + * @type {Object.} + */ +const LANGUAGE_MAPPINGS = { + // English variants + "en": "en-US", + "en-GB": "en-US", + "en-AU": "en-US", + "en-CA": "en-US", + "en-NZ": "en-US", + "en-ZA": "en-US", + // Spanish variants + "es": "es-ES", + "es-MX": "es-ES", + "es-AR": "es-ES", + "es-CO": "es-ES", + "es-CL": "es-ES", + "es-PE": "es-ES", + "es-VE": "es-ES", + "es-419": "es-ES", // Latin American Spanish +}; + +/** + * Configuration object for available languages in the application + * @type {Object. Object. Promise> + * }>} + */ +export const availableLanguages = { + "en-US": { + name: "English", + loader: () => + import.meta.glob("./en-US/*.yaml", { query: "?raw", import: "default" }), + }, + "es-ES": { + name: "Español", + loader: () => + import.meta.glob("./es-ES/*.yaml", { query: "?raw", import: "default" }), + }, +}; + +// Convert availableLanguages to format needed for language selection +export const languageOptions = Object.entries(availableLanguages).map(( + [code, config], +) => ({ + code, + name: config.name, +})); + +// Use loaders from availableLanguages configuration +const languages = Object.fromEntries( + Object.entries(availableLanguages).map(( + [locale, config], + ) => [locale, config.loader]), +); + +/** + * Normalizes a locale string to a supported locale + * @param {string} locale - The locale string to normalize + * @returns {string} A supported locale from availableLanguages + */ +export const normalizeLocale = (locale = "en-US") => { + // If the locale is already supported, return it + if (availableLanguages[locale]) { + return locale; + } + + // Try to find a direct mapping + const normalizedLocale = LANGUAGE_MAPPINGS[locale]; + if (normalizedLocale && availableLanguages[normalizedLocale]) { + return normalizedLocale; + } + + // Try to match just the language part (e.g., 'en' from 'en-GB') + const languageCode = locale.split("-")[0]; + const mappedLanguage = LANGUAGE_MAPPINGS[languageCode]; + if (mappedLanguage && availableLanguages[mappedLanguage]) { + return mappedLanguage; + } + + // If no mapping found, return the default locale + console.warn(`Unsupported locale: ${locale}, falling back to en-US`); + return "en-US"; +}; + +/** + * Generates a dictionary of translations from YAML files + * @param {Object.} modules - Object containing module paths and their loader functions + * @returns {Promise} Dictionary of translations or fallback dictionary if loading fails + * @throws {Error} When no valid translation files are loaded + */ +const generateDictionary = async (modules) => { + try { + const dictionary = {}; + + for (const [path, loader] of Object.entries(modules)) { + try { + const content = await loader(); + const data = loadYamlSafely(content, 'content'); + + if (!data) { + console.warn(`Empty or invalid YAML content in ${path}`); + continue; + } + + const filename = path.split("/").pop().replace(".yaml", ""); + dictionary[filename] = data; + } catch (error) { + console.error(`Error loading translation file ${path}:`, error); + } + } + + if (Object.keys(dictionary).length === 0) { + throw new Error("No valid translation files loaded"); + } + + return dictionary; + } catch (error) { + console.error("Error generating dictionary:", error); + // Return a minimal dictionary to prevent complete failure + return MINIMAL_DICTIONARY; + } +}; + +/** + * Registers a language loader for svelte-i18n + * @param {string} locale - The locale identifier (e.g., 'en-US', 'es-ES') + * @param {Function} getModules - Function that returns an object of module loaders + * @returns {Promise} + */ +const registerLanguage = async (locale, getModules) => { + try { + const modules = getModules(); + register(locale, async () => { + const dict = await generateDictionary(modules); + return dict; + }); + } catch (error) { + console.error(`Error registering ${locale}:`, error); + // Register a minimal fallback dictionary + register(locale, () => MINIMAL_DICTIONARY); + } +}; + +/** + * Register all available languages from the languages object + * @description Iterates through each locale and its corresponding module loader function, + * registering them with the i18n system + */ +Object.entries(languages).forEach(([locale, getModules]) => { + registerLanguage(locale, getModules); +}); + +/** + * Initialize the i18n system with configuration options + * @description Sets up internationalization with the following settings: + * - Fallback to en-US if a translation is missing + * - Initial locale set to en-US in browser environments + * - 200ms loading delay to prevent flashing + * - Custom message handling for missing translations + */ +init({ + fallbackLocale: "en-US", + initialLocale: browser ? "en-US" : undefined, // Start with English in browser + loadingDelay: 200, + formats: {}, // Add any custom formats here + handleMissingMessage: ({ locale, id, defaultValue }) => { + console.warn(`Missing translation: ${id} for locale: ${locale}`); + return defaultValue || id; + }, +}); diff --git a/src/lib/utils/content.js b/src/lib/utils/content.js new file mode 100644 index 00000000..34b68996 --- /dev/null +++ b/src/lib/utils/content.js @@ -0,0 +1,157 @@ +/** + * @typedef {Object} ContentBlock + * @property {string} id - Block identifier + * @property {string} [title] - Block title + * @property {Object} [content] - Block content + * @property {string} [content.title] - Content title + * @property {string} [content.text] - Content text + * @property {Array} [tabs] - Block tabs + * @property {string} [imgSrc] - Image source + * @property {string} [imgAlt] - Image alt text + * @property {boolean} [divider] - Show divider + * @property {boolean} [columns] - Use columns layout + * @property {boolean} [boxed] - Use boxed layout + * @property {Object} [extraContent] - Additional content + * @property {string} [extraContent.title] - Extra content title + * @property {string} [extraContent.text] - Extra content text + */ + +/** + * @typedef {Object} TabContent + * @property {string} [title] - Tab title + * @property {boolean} [isVideo] - Whether the tab contains video content + * @property {Object} content - Tab content + * @property {string} [content.text] - Text content + * @property {string} [content.videoCaption] - Video caption + * @property {Array<{src: string}>} [content.videoSources] - Video sources + * @property {string} [content.imgSrc] - Image source + * @property {string} [content.imgAlt] - Image alt text + */ + +/** + * Options for deep merge operation + * @typedef {Object} MergeOptions + * @property {boolean} [arrayMode='replace'] - How to handle arrays: 'replace' | 'merge' + * @property {boolean} [skipUndefined=true] - Whether to skip undefined values + * @property {boolean} [skipNull=false] - Whether to skip null values + * @property {Array} [skipPaths=[]] - Paths to skip during merge (e.g., ['id', 'imgSrc']) + */ + +/** + * Deep merges two objects or arrays, with the second taking precedence + * @template T + * @param {T} target - The target object/array to merge into + * @param {T} source - The source object/array to merge from + * @param {MergeOptions} [options] - Merge options + * @returns {T} The merged result + */ +function deepMerge(target, source, options = {}) { + const { + arrayMode = 'replace', + skipUndefined = true, + skipNull = false, + skipPaths = [] + } = options; + + // Handle null/undefined cases + if (!source) return target; + if (!target) return source; + + // If either is not an object (including arrays), source takes precedence + if (typeof target !== 'object' || typeof source !== 'object') { + if ((skipUndefined && source === undefined) || (skipNull && source === null)) { + return target; + } + return source; + } + + // Handle arrays + if (Array.isArray(target) && Array.isArray(source)) { + if (arrayMode === 'replace') return source; + return target.map((item, index) => + source[index] ? deepMerge(item, source[index], options) : item + ); + } + + // Handle objects + const merged = { ...target }; + for (const key in source) { + // Skip specified paths + if (skipPaths.includes(key)) continue; + + if (Object.prototype.hasOwnProperty.call(source, key)) { + const sourceValue = source[key]; + + // Skip undefined/null values based on options + if ((skipUndefined && sourceValue === undefined) || + (skipNull && sourceValue === null)) continue; + + if (sourceValue !== null && typeof sourceValue === 'object') { + merged[key] = deepMerge(target[key], sourceValue, options); + } else { + merged[key] = sourceValue; + } + } + } + return merged; +} + +/** + * Merges configuration data with translations + * @param {Array} configBlocks - Content blocks from config + * @param {Array} translatedBlocks - Content blocks from translations + * @param {MergeOptions} [options] - Merge options + * @returns {Array} Merged content blocks + */ +export function mergeContentBlocks(configBlocks, translatedBlocks, options = {}) { + if (!Array.isArray(configBlocks) || !Array.isArray(translatedBlocks)) { + console.warn('Invalid content blocks provided'); + return []; + } + + // Default options for content blocks + const defaultOptions = { + skipPaths: ['id', 'imgSrc', 'background', 'backgroundDark'], + skipUndefined: true, + skipNull: true, + arrayMode: 'merge' + }; + + return configBlocks.map(configBlock => { + const translatedBlock = translatedBlocks.find(block => block.id === configBlock.id) || {}; + return deepMerge(configBlock, translatedBlock, { ...defaultOptions, ...options }); + }); +} + +/** + * Validates a content block against the expected schema + * @param {ContentBlock} block - The content block to validate + * @returns {{ valid: boolean, errors: string[] }} Validation result + */ +export function validateContentBlock(block) { + const errors = []; + + if (!block.id) { + errors.push('Content block must have an id'); + } + + if (block.tabs) { + if (!Array.isArray(block.tabs)) { + errors.push('Tabs must be an array'); + } else { + block.tabs.forEach((tab, index) => { + if (!tab.content) { + errors.push(`Tab ${index} must have content`); + } + if (tab.isVideo && (!tab.content.videoSources || !Array.isArray(tab.content.videoSources))) { + errors.push(`Video tab ${index} must have valid videoSources array`); + } + }); + } + } + + return { + valid: errors.length === 0, + errors + }; +} diff --git a/src/lib/utils/index.js b/src/lib/utils/index.js index 98392c11..61c1401d 100644 --- a/src/lib/utils/index.js +++ b/src/lib/utils/index.js @@ -1,7 +1,28 @@ -// Determine if a variable has a value (even `false` or `0`) -export const hasValue = (a) => a !== undefined && a !== null; +import { browser } from "$app/environment"; +import { blogPageSize, blogPageStart, releases } from "$lib/config"; -// Fetch all blog posts, sorted by date, optionally paginated +const dataURL = + "https://api.github.com/repos/spyder-ide/spyder/contributors?per_page=100"; +let githubToken; + +if (import.meta.env.VITE_GITHUB_TOKEN) { + githubToken = import.meta.env.VITE_GITHUB_TOKEN; +} + +/** + * Determines if a variable has a value (even `false` or `0`) + * @param {*} variable - The value to check + * @returns {boolean} True if the value is neither undefined nor null + */ +export const hasValue = (variable) => + variable !== undefined && variable !== null; + +/** + * Fetches all blog posts, optionally paginated and sorted by date + * @param {number} [pageNum] - The page number for pagination + * @param {number} [pageSize] - Number of posts per page + * @returns {Promise|{posts: Array<{meta: object, path: string}>, pageNum: number, totalPages: number}>} + */ export const fetchMarkdownPosts = async (pageNum, pageSize) => { // Load all posts const allPostFiles = import.meta.glob("/src/routes/blog/**/*.md", { @@ -45,16 +66,28 @@ export const fetchMarkdownPosts = async (pageNum, pageSize) => { }; }; -// Format the date -export function formattedPubDate(date) { +/** + * Formats a date string according to locale + * @param {string|Date} date - The date to format + * @param {string} [i18n="en-US"] - The locale identifier + * @returns {string} Formatted date string + */ +export function formattedPubDate(date, i18n = "en-US") { const options = { year: "numeric", month: "long", day: "numeric" }; - return new Date(date).toLocaleDateString("en-US", options); + return new Date(date).toLocaleDateString(i18n, options); } -// Fetch the author's metadata +/** + * Fetches metadata for a single author + * @param {string} author - Author identifier + * @param {Function} [customFetch] - Optional custom fetch function for testing + * @returns {Promise<{src: string, name: string}|null>} Author metadata or null if fetch fails + */ export async function fetchAuthorMetadata(author, customFetch) { try { - const response = await (customFetch || fetch)(`/assets/authors/${author}/metadata.json`); + const response = await (customFetch || fetch)( + `/assets/authors/${author}/metadata.json`, + ); if (!response.ok) { throw new Error("Failed to load author metadata"); } @@ -69,29 +102,47 @@ export async function fetchAuthorMetadata(author, customFetch) { } } +/** + * Fetches metadata for multiple authors + * @param {string[]} authors - Array of author identifiers + * @returns {Promise>} Array of author metadata + */ export async function fetchAuthorsMetadata(authors) { if (!authors || !Array.isArray(authors)) { console.error("Invalid authors data:", authors); return []; } - const metadataList = await Promise.all(authors.map(author => fetchAuthorMetadata(author))); + const metadataList = await Promise.all( + authors.map((author) => fetchAuthorMetadata(author)), + ); return metadataList; } -// Sort posts by date +/** + * Sorts posts by publication date in descending order + * @param {Array<{meta: {pub_date: string|Date}}>} posts - Array of post objects + * @returns {Array<{meta: {pub_date: string|Date}}>} Sorted posts array + */ export const sortPostsByDate = (posts) => posts.sort((a, b) => new Date(b.meta.pub_date) - new Date(a.meta.pub_date)); -// Generate random ID +/** + * Generates a random ID string + * @param {number} [length=24] - Length of the ID to generate + * @returns {string} Random ID string + */ export const randomId = (length) => Math.random() .toString(length || 24) .replace(/[^a-z]+/g, ""); -// Determine the operating system and return it +/** + * Determines the user's operating system from browser user agent + * @returns {('mac'|'windows'|'linux')} Operating system identifier, defaults to 'windows' if unknown + */ export const getOS = () => { - if (typeof window !== "undefined") { + if (browser) { const userAgent = navigator.userAgent.toLowerCase(); const os = { mac: ["mac"], @@ -104,51 +155,45 @@ export const getOS = () => { } } } + return "windows"; }; +/** + * Gets the download buttons configuration for a specific operating system + * @param {string} base - Base URL for download links + * @param {('mac'|'windows'|'linux')} os - Operating system identifier + * @returns {Array<{highlight: boolean, icon: string, version: string, href: string}>} Array of button configurations + * @description Generates download button configurations based on OS and processor architecture. + * For macOS, generates buttons for both ARM64 and x64 architectures. For Windows and Linux, + * generates a single x64 button. + */ export const getOSButtons = (base, os) => { - let osButtons = [{}]; - let str = ""; - - if (os === "windows") { - str = "for Windows 10+"; - } else if (os === "linux") { - str = "for Linux"; - } else if (os === "mac") { - str = "for macOS"; - const m1 = "14.0+ (M1)"; - const intel = "12.0+ (Intel)"; - osButtons = [ - { - highlight: true, - icon: `${os}`, - text: `Download ${str} ${m1}`, - href: `${base}/download?os=${os}&arch=arm64`, - }, - { - highlight: true, - icon: `${os}`, - text: `Download ${str} ${intel}`, - href: `${base}/download?os=${os}&arch=x64`, - }, - ]; - } + let osButtons = []; + let processorFamily = []; - if (os === "windows" || os === "linux") { - osButtons = [ - { - highlight: true, - icon: `${os}`, - text: `Download ${str}`, - href: `${base}/download?os=${os}&arch=x64`, - }, - ]; + if (os === "mac") { + processorFamily = ["arm64", "x64"]; + } else { + processorFamily = ["x64"]; } + processorFamily.forEach((arch) => { + osButtons.push({ + highlight: true, + icon: `${os}`, + text: releases[os][arch].name, + href: `${base}/download?os=${os}&arch=${arch}`, + }); + }); + return osButtons; }; -// Load an icon dynamically +/** + * Dynamically loads an icon from svelte-icons-pack + * @param {string} iconName - Name of the icon to load + * @returns {Promise} Icon component or null if loading fails + */ export async function getIcon(iconName) { try { const module = await import("svelte-icons-pack/bs"); @@ -158,3 +203,150 @@ export async function getIcon(iconName) { return null; } } + +/** + * Processes and merges different contributor lists + * @param {Array<{id: string|number}>} current - Current contributors + * @param {Array<{id: string|number}>} past - Past contributors + * @param {Array<{id: string|number}>} all - All contributors + * @returns {{updatedCurrent: Array, updatedPast: Array, remainingContributors: Array}} + */ +export const processContributors = (current, past, all) => { + // Update current/past contributors from GitHub with custom data + const updateContributor = (contributor, allContributors) => { + const match = allContributors.find((c) => c.id === contributor.id); + return match ? { ...match, ...contributor } : contributor; + }; + + const updatedCurrent = current.map((contributor) => + updateContributor(contributor, all) + ); + const updatedPast = past.map((contributor) => + updateContributor(contributor, all) + ); + + // Get the remaining contributors that are not in the current/past lists + const remainingContributors = all.filter( + (contributor) => + !current.some((c) => c.id === contributor.id) && + !past.some((p) => p.id === contributor.id), + ); + + return { + updatedCurrent, + updatedPast, + remainingContributors, + }; +}; + +/** + * Fetches contributors data from GitHub API + * @param {Function} [customFetch] - Optional custom fetch function + * @param {string} [dataSrc] - GitHub API URL + * @param {string} [token] - GitHub authentication token + * @param {number} [startPage=1] - Starting page number + * @param {number} [maxPages=3] - Maximum number of pages to fetch + * @returns {Promise<{contributors: Array, loading?: boolean, error: string|null}>} + */ +export const getContributors = async ( + customFetch = undefined, + dataSrc = dataURL || "", + token = githubToken || undefined, + startPage = 1, + maxPages = 3, +) => { + let headers, response; + let contributors = []; + + if (token) { + headers = { + Authorization: `token ${token}`, + Accept: "application/vnd.github.v3+json", + }; + } + + try { + // Fetch the contributors data with authentication + for (let n = startPage; n <= maxPages; n++) { + if (!dataSrc) throw new Error(`There is no data source to fetch!`); + if (headers) { + response = await (customFetch || fetch)(`${dataSrc}&page=${n}`, { + headers, + }); + } else { + response = await (customFetch || fetch)(`${dataSrc}&page=${n}`); + } + if (!response.ok) { + throw new Error(`HTTP error! status: ${response.status}`); + } + const data = await response.json(); + contributors.push(...data); + } + + return { + contributors, + loading: false, + error: null, + }; + } catch (error) { + console.error("Failed to fetch contributors:", error); + return { + contributors: [], + error: error.message, + }; + } +}; + +/** + * Creates a map of contributors by their ID + * @param {Array} contributors - Array of contributor objects + * @returns {Map} Map of contributors with ID as key + */ +export const createContributorsMap = (contributors) => { + const map = new Map(); + contributors.forEach((element) => map.set(element.id, element)); + return map; +}; + +/** + * Merges contributor data with translations + * @param {Array} rawContributors - Raw contributor data + * @param {Map} translationsMap - Map of translated contributor data + * @returns {Array} Merged contributor data + */ +export const mergeContributorData = (rawContributors, translationsMap) => { + return rawContributors.map((element) => ({ + ...element, + ...translationsMap.get(element.id), + })); +}; + +/** + * Shared loader function for blog pages + * @param {number} [page] - Page number to load (optional) + * @returns {Promise<{props: {posts: Array, pageNum: number, totalPages: number}}>} + */ +export async function loadBlogPage(page = blogPageStart) { + const pageSize = blogPageSize; + const { posts, totalPages } = await fetchMarkdownPosts(page, pageSize); + + return { + props: { + posts, + pageNum: page, + totalPages, + }, + }; +} + +/** + * Generate static routes for blog pages + * @returns {Promise>} + */ +export async function generateBlogEntries() { + const { _, totalPages } = await fetchMarkdownPosts(1, blogPageSize); + return Array.from( + { length: totalPages }, + (_, i) => ({ page: `${i + 1}` }), + ); +} diff --git a/src/lib/utils/yaml.js b/src/lib/utils/yaml.js new file mode 100644 index 00000000..ef62bb9a --- /dev/null +++ b/src/lib/utils/yaml.js @@ -0,0 +1,26 @@ +import yaml from "js-yaml"; + +/** + * Safely loads and validates YAML content + * @param {string} content - Raw YAML content to parse + * @param {string} name - Name of the config for error messages + * @returns {object} Parsed YAML content + * @throws {Error} If YAML parsing fails or content is invalid + */ +export function loadYamlSafely(content, name) { + try { + const data = yaml.load(content, { + json: true, // Forces JSON compatible output + schema: yaml.JSON_SCHEMA, // Restricts to JSON-like types only + }); + + if (!data || typeof data !== "object") { + throw new Error(`Invalid ${name} format: must be an object`); + } + + return data; + } catch (error) { + console.error(`Error loading ${name}:`, error); + throw new Error(`Failed to load ${name}: ${error.message}`); + } +} diff --git a/src/routes/+error.svelte b/src/routes/+error.svelte new file mode 100644 index 00000000..fc233bb5 --- /dev/null +++ b/src/routes/+error.svelte @@ -0,0 +1,12 @@ + + +
+
+

+ {$page.status} +

+

{$page.error.message}

+
+
diff --git a/src/routes/+layout.js b/src/routes/+layout.js index e325c179..000eb267 100644 --- a/src/routes/+layout.js +++ b/src/routes/+layout.js @@ -1,2 +1,38 @@ +import { browser } from "$app/environment"; +import { locale, waitLocale, getLocaleFromNavigator } from "svelte-i18n"; +import { normalizeLocale } from "$lib/i18n"; +import "$lib/i18n"; + +export const load = async () => { + if (browser) { + try { + const savedLocale = localStorage.getItem('preferred-locale'); + let detectedLocale; + + if (savedLocale) { + detectedLocale = savedLocale; + } else { + detectedLocale = getLocaleFromNavigator(); + } + + // Normalize the locale before setting it + const normalizedLocale = normalizeLocale(detectedLocale); + locale.set(normalizedLocale); + + // Save the normalized locale + localStorage.setItem('preferred-locale', normalizedLocale); + } catch (error) { + console.warn('Error setting locale:', error); + locale.set('en-US'); // Fallback to English + } + } + + await waitLocale(); + + return { + i18n: { ready: true } + }; +}; + export const prerender = true; export const trailingSlash = "always"; diff --git a/src/routes/+layout.svelte b/src/routes/+layout.svelte index bca6ffdd..6d1afb01 100644 --- a/src/routes/+layout.svelte +++ b/src/routes/+layout.svelte @@ -1,17 +1,37 @@ -
-
-
- -
-
-
+{#await waitLocale()} +
+
+
+ +
+
+
+{:then} +
+
+
+ +
+
+
+{:catch error} +
+
+
Error loading translations: {error.message}
+
+
+{/await}