From da96f4844a4ce90708abe148b7d5f1d189a370f5 Mon Sep 17 00:00:00 2001 From: "mr. m" <91018726+mr-cheffy@users.noreply.github.com> Date: Sat, 21 Jun 2025 17:12:31 +0200 Subject: [PATCH] Replace motion with animejs and new layout redesign (#672) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: taroj1205 Co-authored-by: Shintaro Jokagi <61367823+taroj1205@users.noreply.github.com> Co-authored-by: mr. m <91018726+mauro-balades@users.noreply.github.com> Co-authored-by: Canoa Co-authored-by: Bryan Galdámez --- .github/workflows/ci-pipeline.yml | 16 +- cspell.json | 18 +- package.json | 9 +- pnpm-lock.yaml | 169 ++++++++++------ src/assets/sponsors/blacksmith-logo-dark.svg | 13 ++ src/assets/sponsors/tutaLogo-dark.svg | 13 ++ src/components/Community.astro | 80 +++++--- src/components/Features.astro | 190 +++++++----------- src/components/Footer.astro | 13 +- src/components/Hero.astro | 142 +++++++------ src/components/SocialMediaStrip.astro | 5 +- src/components/Sponsors.astro | 82 ++++++-- src/components/download/DownloadScript.astro | 62 +++--- .../download/PlatformDownload.astro | 163 +++++---------- src/i18n/en/translation.json | 22 +- src/i18n/ja/translation.json | 16 +- src/pages/[...locale]/download.astro | 182 ++++++----------- src/release-notes/twilight.json | 4 +- src/tests/components/PlatformDownload.test.ts | 62 ------ src/tests/pages/download.spec.ts | 108 +++++----- 20 files changed, 679 insertions(+), 690 deletions(-) create mode 100644 src/assets/sponsors/blacksmith-logo-dark.svg create mode 100644 src/assets/sponsors/tutaLogo-dark.svg diff --git a/.github/workflows/ci-pipeline.yml b/.github/workflows/ci-pipeline.yml index b6f13c0..d6eec5a 100644 --- a/.github/workflows/ci-pipeline.yml +++ b/.github/workflows/ci-pipeline.yml @@ -64,15 +64,6 @@ jobs: if: steps.check-node-modules-cache.outputs.cache-hit != 'true' run: pnpm install --frozen-lockfile - - name: Save node_modules cache - if: steps.check-node-modules-cache.outputs.cache-hit != 'true' - uses: actions/cache/save@v4 - with: - path: | - node_modules - */node_modules - key: ${{ runner.os }}-node-modules-${{ hashFiles('**/pnpm-lock.yaml') }} - quality_checks: name: ${{ matrix.name }} needs: [check_changes, setup] @@ -102,6 +93,7 @@ jobs: restore-keys: ${{ runner.os }}-turbo-${{ matrix.check }}- - name: Restore node_modules cache + id: cache uses: actions/cache/restore@v4 with: path: | @@ -121,6 +113,7 @@ jobs: run_install: false - name: Install dependencies + if: steps.cache.outputs.cache-hit != 'true' run: pnpm install --frozen-lockfile - name: Run ${{ matrix.name }} @@ -128,7 +121,7 @@ jobs: playwright: name: Playwright Tests - needs: [check_changes, setup, quality_checks] + needs: [check_changes, setup] if: ${{ needs.check_changes.outputs.exists == 'true' }} runs-on: ubuntu-latest steps: @@ -144,6 +137,7 @@ jobs: restore-keys: ${{ runner.os }}-turbo- - name: Restore node_modules cache + id: cache uses: actions/cache/restore@v4 with: path: | @@ -163,6 +157,7 @@ jobs: run_install: false - name: Install dependencies + if: steps.cache.outputs.cache-hit != 'true' run: pnpm install --frozen-lockfile - name: Cache Playwright Browsers @@ -177,6 +172,7 @@ jobs: - name: Run Playwright Tests run: pnpm exec turbo run test:playwright + timeout-minutes: 10 verify: name: Verify diff --git a/cspell.json b/cspell.json index 164c581..a507659 100644 --- a/cspell.json +++ b/cspell.json @@ -5,21 +5,22 @@ "words": [ "adam", "AMOLED", + "animejs", "Astronav", - "Briel", "brhm", "Brhm", + "Briel", "bryan", - "Canoa", "canoa", + "Canoa", "cfasync", "createdAsc", "createdDefault", "createdDesc", "daniel", - "FMPEG", "ferrocyante", "flatpaks", + "FMPEG", "Galdámez", "García", "Garro", @@ -33,14 +34,14 @@ "Jokagi", "junicode", "Junicode", - "kristijanribaric", "Kristijan", + "kristijanribaric", "laggy", "larvey", "Larvey", + "linaarchsum", "linuxarmsum", "linuxsum", - "linaarchsum", "mfsa", "mozilla", "Nehalem", @@ -51,12 +52,13 @@ "patreon", "Pdzly", "Ribaric", + "securtiy", "taroj", - "Turborepo", "testid", "theming", - "tuta", "tsconfigs", + "Turborepo", + "tuta", "unfloatable", "unfocusing", "unrs", @@ -66,8 +68,8 @@ "VAAPI", "wmfcdm", "workerd", - "XPCOM", "xmark", + "XPCOM", "yumemi", "zsync" ], diff --git a/package.json b/package.json index 41f0341..aba27ee 100644 --- a/package.json +++ b/package.json @@ -37,23 +37,25 @@ "@fortawesome/free-solid-svg-icons": "6.7.1", "@types/react": "19.1.6", "@types/react-dom": "19.1.5", + "animejs": "4.0.2", "astro": "5.7.10", "astro-navbar": "2.3.7", - "turbo": "2.5.4", "autoprefixer": "10.4.14", "clsx": "2.1.1", "date-fns": "4.1.0", "free-astro-components": "1.2.0", "jiti": "2.4.2", + "js-confetti": "0.12.0", "lefthook": "1.11.13", - "motion": "12.15.0", "postcss": "8.5.1", "react": "19.1.0", "react-dom": "19.1.0", "sharp": "0.33.5", "tailwind-merge": "3.3.0", "tailwindcss": "3.4.15", - "typescript": "5.6.3" + "turbo": "2.5.4", + "typescript": "5.6.3", + "ua-parser-js": "2.0.3" }, "devDependencies": { "@commitlint/cli": "19.8.1", @@ -72,6 +74,7 @@ "@playwright/test": "1.52.0", "@testing-library/jest-dom": "6.6.3", "@testing-library/user-event": "14.6.1", + "@types/animejs": "3.1.13", "@types/eslint-plugin-jsx-a11y": "6.10.0", "@types/jsdom": "21.1.7", "@types/node": "22.15.18", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index fafc27e..36d4eb0 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -44,6 +44,9 @@ importers: '@types/react-dom': specifier: 19.1.5 version: 19.1.5(@types/react@19.1.6) + animejs: + specifier: 4.0.2 + version: 4.0.2 astro: specifier: 5.7.10 version: 5.7.10(@types/node@22.15.18)(jiti@2.4.2)(rollup@4.41.1)(typescript@5.6.3)(yaml@2.8.0) @@ -65,12 +68,12 @@ importers: jiti: specifier: 2.4.2 version: 2.4.2 + js-confetti: + specifier: 0.12.0 + version: 0.12.0 lefthook: specifier: 1.11.13 version: 1.11.13 - motion: - specifier: 12.15.0 - version: 12.15.0(react-dom@19.1.0(react@19.1.0))(react@19.1.0) postcss: specifier: 8.5.1 version: 8.5.1 @@ -95,6 +98,9 @@ importers: typescript: specifier: 5.6.3 version: 5.6.3 + ua-parser-js: + specifier: 2.0.3 + version: 2.0.3 devDependencies: '@commitlint/cli': specifier: 19.8.1 @@ -144,6 +150,9 @@ importers: '@testing-library/user-event': specifier: 14.6.1 version: 14.6.1(@testing-library/dom@10.4.0) + '@types/animejs': + specifier: 3.1.13 + version: 3.1.13 '@types/eslint-plugin-jsx-a11y': specifier: 6.10.0 version: 6.10.0 @@ -1505,6 +1514,9 @@ packages: '@tybys/wasm-util@0.9.0': resolution: {integrity: sha512-6+7nlbMVX/PVDCwaIQ8nTOPveOcFLSt8GcXdx8hD0bt39uWxYT88uXzqTd4fTvqta7oeUJqudepapKNt2DYJFw==} + '@types/animejs@3.1.13': + resolution: {integrity: sha512-yWg9l1z7CAv/TKpty4/vupEh24jDGUZXv4r26StRkpUPQm04ztJaftgpto8vwdFs8SiTq6XfaPKCSI+wjzNMvQ==} + '@types/aria-query@5.0.4': resolution: {integrity: sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==} @@ -1556,6 +1568,9 @@ packages: '@types/nlcst@2.0.3': resolution: {integrity: sha512-vSYNSDe6Ix3q+6Z7ri9lyWqgGhJTmzRjZRqyq15N0Z/1/UnVsno9G/N40NBijoYx2seFDIl0+B2mgAb9mezUCA==} + '@types/node-fetch@2.6.12': + resolution: {integrity: sha512-8nneRWKCg3rMtF69nLQJnOYUcbafYeFSjqkw3jCRLsqkWFlHaoQrr5mXmofFGOx3DKn7UfmBMyov8ySvLRVldA==} + '@types/node@17.0.45': resolution: {integrity: sha512-w+tIMs3rq2afQdsPJlODhoUEKzFP1ayaoyl1CcnwtIlsVe7K7bA1NGm4s3PraqTLlXnbIN84zuBlxBWo1u9BLw==} @@ -1826,6 +1841,9 @@ packages: ajv@8.17.1: resolution: {integrity: sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==} + animejs@4.0.2: + resolution: {integrity: sha512-f0L/kSya2RF23iMSF/VO01pMmLwlAFoiQeNAvBXhEyLzIPd2/QTBRatwGUqkVCC6seaAJYzAkGir55N4SL+h3A==} + ansi-align@3.0.1: resolution: {integrity: sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==} @@ -1942,6 +1960,9 @@ packages: resolution: {integrity: sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==} engines: {node: '>= 0.4'} + asynckit@0.4.0: + resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} + autoprefixer@10.4.14: resolution: {integrity: sha512-FQzyfOsTlwVzjHxKEqRIAdJx9niO6VCBCoEwax/VLSoQF29ggECcPuBqUMZ+u8jCZOPSy8b8/8KnuFbp0SaFZQ==} engines: {node: ^10 || ^12 || >=14} @@ -2125,6 +2146,10 @@ packages: resolution: {integrity: sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==} engines: {node: '>=12.5.0'} + combined-stream@1.0.8: + resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} + engines: {node: '>= 0.8'} + comma-separated-tokens@2.0.3: resolution: {integrity: sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==} @@ -2334,6 +2359,10 @@ packages: defu@6.1.4: resolution: {integrity: sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==} + delayed-stream@1.0.0: + resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} + engines: {node: '>=0.4.0'} + dequal@2.0.3: resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} engines: {node: '>=6'} @@ -2341,6 +2370,9 @@ packages: destr@2.0.5: resolution: {integrity: sha512-ugFTXCtDZunbzasqBxrK93Ik/DRYsO6S/fedkWEMKqt04xZ4csmnmwGDBAb07QWNaGMAmnTIemsYZCksjATwsA==} + detect-europe-js@0.1.2: + resolution: {integrity: sha512-lgdERlL3u0aUdHocoouzT10d9I89VVhk0qNRmll7mXdGfJT1/wqZ2ZLA4oJAjeACPY5fT1wsbq2AT+GkuInsow==} + detect-libc@2.0.4: resolution: {integrity: sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA==} engines: {node: '>=8'} @@ -2744,23 +2776,13 @@ packages: resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==} engines: {node: '>=14'} + form-data@4.0.3: + resolution: {integrity: sha512-qsITQPfmvMOSAdeyZ+12I1c+CKSstAFAwu+97zrnWAbIr5u8wfsExUzCesVLC8NgHuRUqNN4Zy6UPWUTRGslcA==} + engines: {node: '>= 6'} + fraction.js@4.3.7: resolution: {integrity: sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==} - framer-motion@12.15.0: - resolution: {integrity: sha512-XKg/LnKExdLGugZrDILV7jZjI599785lDIJZLxMiiIFidCsy0a4R2ZEf+Izm67zyOuJgQYTHOmodi7igQsw3vg==} - peerDependencies: - '@emotion/is-prop-valid': '*' - react: ^18.0.0 || ^19.0.0 - react-dom: ^18.0.0 || ^19.0.0 - peerDependenciesMeta: - '@emotion/is-prop-valid': - optional: true - react: - optional: true - react-dom: - optional: true - free-astro-components@1.2.0: resolution: {integrity: sha512-bsT9dWsNlRGDNjqcoIlz6w8NcSCgOpx6oxiwZgYwq9RVbi3JqUImPc6c4Kico2wRJSIXc7HHyr71QgmgXv7nfg==} @@ -3111,6 +3133,9 @@ packages: resolution: {integrity: sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==} engines: {node: '>= 0.4'} + is-standalone-pwa@0.1.1: + resolution: {integrity: sha512-9Cbovsa52vNQCjdXOzeQq5CnCbAcRk05aU62K20WO372NrTv0NxibLFCK6lQ4/iZEFdEA3p3t2VNOn8AJ53F5g==} + is-string@1.1.1: resolution: {integrity: sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==} engines: {node: '>= 0.4'} @@ -3184,6 +3209,9 @@ packages: resolution: {integrity: sha512-rg9zJN+G4n2nfJl5MW3BMygZX56zKPNVEYYqq7adpmMh4Jn2QNEwhvQlFy6jPVdcod7txZtKHWnyZiA3a0zP7A==} hasBin: true + js-confetti@0.12.0: + resolution: {integrity: sha512-1R0Akxn3Zn82pMqW65N1V2NwKkZJ75bvBN/VAb36Ya0YHwbaSiAJZVRr/19HBxH/O8x2x01UFAbYI18VqlDN6g==} + js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} @@ -3547,6 +3575,14 @@ packages: resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} engines: {node: '>=8.6'} + mime-db@1.52.0: + resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} + engines: {node: '>= 0.6'} + + mime-types@2.1.35: + resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} + engines: {node: '>= 0.6'} + mime@3.0.0: resolution: {integrity: sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==} engines: {node: '>=10.0.0'} @@ -3575,26 +3611,6 @@ packages: resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==} engines: {node: '>=16 || 14 >=14.17'} - motion-dom@12.15.0: - resolution: {integrity: sha512-D2ldJgor+2vdcrDtKJw48k3OddXiZN1dDLLWrS8kiHzQdYVruh0IoTwbJBslrnTXIPgFED7PBN2Zbwl7rNqnhA==} - - motion-utils@12.12.1: - resolution: {integrity: sha512-f9qiqUHm7hWSLlNW8gS9pisnsN7CRFRD58vNjptKdsqFLpkVnX00TNeD6Q0d27V9KzT7ySFyK1TZ/DShfVOv6w==} - - motion@12.15.0: - resolution: {integrity: sha512-HLouXyIb1uQFiZgJTYGrtEzbatPc6vK+HP+Qt6afLQjaudiGiLLVsoy71CwzD/Stlh06FUd5OpyiXqn6XvqjqQ==} - peerDependencies: - '@emotion/is-prop-valid': '*' - react: ^18.0.0 || ^19.0.0 - react-dom: ^18.0.0 || ^19.0.0 - peerDependenciesMeta: - '@emotion/is-prop-valid': - optional: true - react: - optional: true - react-dom: - optional: true - mrmime@2.0.1: resolution: {integrity: sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==} engines: {node: '>=10'} @@ -4550,6 +4566,13 @@ packages: engines: {node: '>=14.17'} hasBin: true + ua-is-frozen@0.1.2: + resolution: {integrity: sha512-RwKDW2p3iyWn4UbaxpP2+VxwqXh0jpvdxsYpZ5j/MLLiQOfbsV5shpgQiw93+KMYQPcteeMQ289MaAFzs3G9pw==} + + ua-parser-js@2.0.3: + resolution: {integrity: sha512-LZyXZdNttONW8LjzEH3Z8+6TE7RfrEiJqDKyh0R11p/kxvrV2o9DrT2FGZO+KVNs3k+drcIQ6C3En6wLnzJGpw==} + hasBin: true + ufo@1.6.1: resolution: {integrity: sha512-9a4/uxlTWJ4+a5i0ooc1rU7C7YOw3wT+UGqdeNNHWnOF9qcMBgLRS+4IYUqbczewFx4mLEig6gawh7X6mFlEkA==} @@ -6316,6 +6339,8 @@ snapshots: tslib: 2.8.1 optional: true + '@types/animejs@3.1.13': {} + '@types/aria-query@5.0.4': {} '@types/babel__core@7.20.5': @@ -6382,6 +6407,11 @@ snapshots: dependencies: '@types/unist': 3.0.3 + '@types/node-fetch@2.6.12': + dependencies: + '@types/node': 22.15.18 + form-data: 4.0.3 + '@types/node@17.0.45': {} '@types/node@22.15.18': @@ -6704,6 +6734,8 @@ snapshots: json-schema-traverse: 1.0.0 require-from-string: 2.0.2 + animejs@4.0.2: {} + ansi-align@3.0.1: dependencies: string-width: 4.2.3 @@ -6940,6 +6972,8 @@ snapshots: async-function@1.0.0: {} + asynckit@0.4.0: {} + autoprefixer@10.4.14(postcss@8.5.1): dependencies: browserslist: 4.25.0 @@ -7129,6 +7163,10 @@ snapshots: color-convert: 2.0.1 color-string: 1.9.1 + combined-stream@1.0.8: + dependencies: + delayed-stream: 1.0.0 + comma-separated-tokens@2.0.3: {} commander@14.0.0: {} @@ -7375,10 +7413,14 @@ snapshots: defu@6.1.4: {} + delayed-stream@1.0.0: {} + dequal@2.0.3: {} destr@2.0.5: {} + detect-europe-js@0.1.2: {} + detect-libc@2.0.4: {} deterministic-object-hash@2.0.2: @@ -7948,16 +7990,15 @@ snapshots: cross-spawn: 7.0.6 signal-exit: 4.1.0 - fraction.js@4.3.7: {} - - framer-motion@12.15.0(react-dom@19.1.0(react@19.1.0))(react@19.1.0): + form-data@4.0.3: dependencies: - motion-dom: 12.15.0 - motion-utils: 12.12.1 - tslib: 2.8.1 - optionalDependencies: - react: 19.1.0 - react-dom: 19.1.0(react@19.1.0) + asynckit: 0.4.0 + combined-stream: 1.0.8 + es-set-tostringtag: 2.1.0 + hasown: 2.0.2 + mime-types: 2.1.35 + + fraction.js@4.3.7: {} free-astro-components@1.2.0(@types/node@22.15.18)(jiti@2.4.2)(prettier-plugin-astro@0.14.1)(prettier@3.5.3)(rollup@4.41.1)(yaml@2.8.0): dependencies: @@ -8393,6 +8434,8 @@ snapshots: dependencies: call-bound: 1.0.4 + is-standalone-pwa@0.1.1: {} + is-string@1.1.1: dependencies: call-bound: 1.0.4 @@ -8481,6 +8524,8 @@ snapshots: jiti@2.4.2: {} + js-confetti@0.12.0: {} + js-tokens@4.0.0: {} js-yaml@4.1.0: @@ -9004,6 +9049,12 @@ snapshots: braces: 3.0.3 picomatch: 2.3.1 + mime-db@1.52.0: {} + + mime-types@2.1.35: + dependencies: + mime-db: 1.52.0 + mime@3.0.0: {} min-indent@1.0.1: {} @@ -9038,20 +9089,6 @@ snapshots: minipass@7.1.2: {} - motion-dom@12.15.0: - dependencies: - motion-utils: 12.12.1 - - motion-utils@12.12.1: {} - - motion@12.15.0(react-dom@19.1.0(react@19.1.0))(react@19.1.0): - dependencies: - framer-motion: 12.15.0(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - tslib: 2.8.1 - optionalDependencies: - react: 19.1.0 - react-dom: 19.1.0(react@19.1.0) - mrmime@2.0.1: {} ms@2.1.3: {} @@ -10078,6 +10115,18 @@ snapshots: typescript@5.6.3: {} + ua-is-frozen@0.1.2: {} + + ua-parser-js@2.0.3: + dependencies: + '@types/node-fetch': 2.6.12 + detect-europe-js: 0.1.2 + is-standalone-pwa: 0.1.1 + node-fetch: 2.7.0 + ua-is-frozen: 0.1.2 + transitivePeerDependencies: + - encoding + ufo@1.6.1: {} ultrahtml@1.6.0: {} diff --git a/src/assets/sponsors/blacksmith-logo-dark.svg b/src/assets/sponsors/blacksmith-logo-dark.svg new file mode 100644 index 0000000..b415853 --- /dev/null +++ b/src/assets/sponsors/blacksmith-logo-dark.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/src/assets/sponsors/tutaLogo-dark.svg b/src/assets/sponsors/tutaLogo-dark.svg new file mode 100644 index 0000000..578a5d0 --- /dev/null +++ b/src/assets/sponsors/tutaLogo-dark.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/components/Community.astro b/src/components/Community.astro index 10f9571..9c9277a 100644 --- a/src/components/Community.astro +++ b/src/components/Community.astro @@ -1,10 +1,7 @@ --- import Image from 'astro/components/Image.astro' -import { motion } from 'motion/react' -import { getTitleAnimation } from '~/animations' import ComImage from '~/assets/ComImage.png' import Button from '~/components/Button.astro' -import Description from '~/components/Description.astro' import CheckIcon from '~/icons/CheckIcon.astro' import GitHubIcon from '~/icons/GitHubIcon.astro' import { getLocale, getUI } from '~/utils/i18n' @@ -19,50 +16,85 @@ const { ---
- +

{ - community.title.map((title, index) => + community.title.map(title => title !== '\n' ? ( - + {title} - + ) : ( ) ) } - - - {community.description} - +

+

+ {community.description} +

- +
- - +
+
{community.lists.simpleYetPowerful.title} - - +
+
{community.lists.privateAndAlwaysUpToDate.title} - +
- + {community.images.community.alt} - +
+ + diff --git a/src/components/Features.astro b/src/components/Features.astro index 76efc5b..b8de3a3 100644 --- a/src/components/Features.astro +++ b/src/components/Features.astro @@ -1,9 +1,6 @@ --- -import { motion } from 'motion/react' -import { getTitleAnimation } from '~/animations' import { getLocale, getUI } from '~/utils/i18n' import Description from './Description.astro' - import Video from './Video.astro' const locale = getLocale(Astro) @@ -19,96 +16,61 @@ interface Props { } const { titles } = Astro.props - const descriptions = Object.values(features.featureTabs).map(tab => tab.description) --- -
+
{ (titles || features.titles).map((title, index) => title !== '\n' ? ( - + {title} - + ) : ( ) ) } - + +

{features.description} - +

+
- +
- - {features.featureTabs.workspaces.title} - - - {features.featureTabs.compactMode.title} - - - {features.featureTabs.glance.title} - - - {features.featureTabs.splitView.title} - + { + Object.entries(features.featureTabs).map(([key, tab], i) => ( + + )) + }
@@ -116,6 +78,7 @@ const descriptions = Object.values(features.featureTabs).map(tab => tab.descript
+
@@ -162,54 +125,58 @@ const descriptions = Object.values(features.featureTabs).map(tab => tab.descript
- diff --git a/src/i18n/en/translation.json b/src/i18n/en/translation.json index 580e867..9bc44c2 100644 --- a/src/i18n/en/translation.json +++ b/src/i18n/en/translation.json @@ -49,12 +49,16 @@ "tuta": { "name": "Tuta", "url": "https://tuta.com/" + }, + "blacksmith": { + "name": "BlackSmith", + "url": "https://www.blacksmith.sh/" } } }, "community": { "title": ["Our ", "Core ", "Values"], - "description": "We make it not only a priority, but a necessity to ensure that Zen always strikes the right balance between beauty, performance, and privacy. We are committed to making Zen the most beautiful, productive, and privacy-respecting browser out there — without compromising on your experience.", + "description": "We make it not only a priority, but a necessity to ensure that Zen always strikes the right balance between beauty, performance, and privacy.", "lists": { "freeAndOpenSource": { "title": "Free and open-source", @@ -262,11 +266,13 @@ } }, "download": { - "title": "Download Zen", - "description": "Download Zen for your platform and experience a more mindful internet browsing experience. All downloads include SHA256 checksums for verification.", + "title": "Start your journey", + "description": "Download Zen for your platform and experience a more mindful internet browsing experience.
Zen is available for macOS, Windows, and Linux.", "twilightInfo": "You're currently in Twilight mode, this means you're downloading the latest experimental features and updates.", + "beta": "Zen is currently in ", + "otherDownload": "If your device has been wrongly detected, see other downloads.
Please report any issues you encounter on GitHub.", "alertInfo": { - "description": "Twilight Mode: You're currently in Twilight mode, this means you're downloading the latest experimental features and updates." + "description": "You're currently in Twilight mode, this means you're downloading the latest experimental features and updates." }, "platformSelector": { "title": "Platform Selector", @@ -290,10 +296,7 @@ "platformNames": { "mac": "macOS", "windows": "Windows", - "linux": "Linux", - "macDownload": "MacOS Download", - "windowsDownload": "Windows Download", - "linuxDownload": "Linux Download" + "linux": "Linux" }, "platformDescriptions": { "mac": "Works on both new Apple (M-Series) and older Intel Macs.
Requires macOS 11.0 or later.", @@ -448,7 +451,7 @@ }, "download": { "title": "Download - Zen", - "description": "Download Zen for your platform and experience a more mindful internet browsing experience. All downloads include SHA256 checksums for verification." + "description": "Download Zen for your platform and experience a more mindful internet browsing experience." }, "privacyPolicy": { "title": "Privacy Policy - Zen", @@ -476,6 +479,7 @@ "zenMods": "Zen Mods", "releaseNotes": "Release Notes", "getHelp": "Get Help", + "securtiy": "Security", "discord": "Discord", "uptimeStatus": "Uptime Status", "reportAnIssue": "Report an Issue", diff --git a/src/i18n/ja/translation.json b/src/i18n/ja/translation.json index b66b2ee..2c371c4 100644 --- a/src/i18n/ja/translation.json +++ b/src/i18n/ja/translation.json @@ -49,6 +49,10 @@ "tuta": { "name": "Tuta", "url": "https://tuta.com/" + }, + "blacksmith": { + "name": "BlackSmith", + "url": "https://www.blacksmith.sh/" } } }, @@ -262,11 +266,13 @@ } }, "download": { - "title": "Zenをダウンロードする", + "title": "Ready to experience Zen?", "description": "お使いのプラットフォーム向けにZenをダウンロード。すべてのダウンロードにはSHA256チェックサムが含まれています", "twilightInfo": "現在Twilightモードです。最新の実験的機能とアップデートをダウンロードしています。", + "beta": "Zen is currently in ", + "otherDownload": "If your device got wrongly detected, see other downloads.
Please report any issues you encounter on GitHub.", "alertInfo": { - "description": "Twilightモード: 現在Twilightモードで、最新の実験的機能とアップデートをダウンロードしています。" + "description": "You're currently in Twilight mode, this means you're downloading the latest experimental features and updates." }, "platformSelector": { "title": "プラットフォーム選択", @@ -290,10 +296,7 @@ "platformNames": { "mac": "macOS", "windows": "Windows", - "linux": "Linux", - "macDownload": "MacOSダウンロード", - "windowsDownload": "Windowsダウンロード", - "linuxDownload": "Linuxダウンロード" + "linux": "Linux" }, "platformDescriptions": { "mac": "Apple(Mシリーズ)・Intel両対応。
macOS 11.0以降が必要です。", @@ -481,6 +484,7 @@ "zenMods": "Zen Mods", "releaseNotes": "リリースノート", "getHelp": "ヘルプ", + "securtiy": "Security", "discord": "Discord", "uptimeStatus": "稼働状況", "reportAnIssue": "問題を報告", diff --git a/src/pages/[...locale]/download.astro b/src/pages/[...locale]/download.astro index a442cd2..1ed3fb0 100644 --- a/src/pages/[...locale]/download.astro +++ b/src/pages/[...locale]/download.astro @@ -9,8 +9,10 @@ import { getLocale, getUI } from '~/utils/i18n' import { icon, library } from '@fortawesome/fontawesome-svg-core' import { faApple, faGithub, faLinux, faWindows } from '@fortawesome/free-brands-svg-icons' -import ExternalLinkIcon from '~/icons/ExternalLink.astro' -import LockIcon from '~/icons/LockIcon.astro' +import Image from 'astro/components/Image.astro' + +import AppIconDark from '~/assets/app-icon-dark.png' +import AppIconLight from '~/assets/app-icon-light.png' export { getStaticPaths } from '~/utils/i18n' @@ -24,28 +26,40 @@ library.add(faWindows, faLinux, faApple, faGithub) const windowsIcon = icon({ prefix: 'fab', iconName: 'windows' }) const linuxIcon = icon({ prefix: 'fab', iconName: 'linux' }) const appleIcon = icon({ prefix: 'fab', iconName: 'apple' }) -const githubIcon = icon({ prefix: 'fab', iconName: 'github' }) const checksums = await getChecksums() const releases = getReleasesWithChecksums(locale)(checksums) -const platformNames = download.platformNames const platformDescriptions = download.platformDescriptions --- -
-
-
- {download.title} - - {download.description} +
+
+
+ + {download.title} + + - -
-
- - - -
-
- -
+
+ + + + + + +
- -
-

- {download.additionalResources.title} -

- -
- - -
-
- -
- -
-

- {download.securityNotice.title} -

-

+

+
diff --git a/src/release-notes/twilight.json b/src/release-notes/twilight.json index 9b790ad..f0ac5cc 100644 --- a/src/release-notes/twilight.json +++ b/src/release-notes/twilight.json @@ -1,6 +1,6 @@ { - "version": "xxx", - "extra": "", + "version": "1.12.11t", + "extra": "This update includes some attempts at performance improvements, better workspace management and some bug fixes!", "fixes": [], "features": [] } diff --git a/src/tests/components/PlatformDownload.test.ts b/src/tests/components/PlatformDownload.test.ts index 6670cf5..90c2e36 100644 --- a/src/tests/components/PlatformDownload.test.ts +++ b/src/tests/components/PlatformDownload.test.ts @@ -4,12 +4,6 @@ import { beforeEach, describe, expect, it } from 'vitest' import PlatformDownload from '~/components/download/PlatformDownload.astro' const mockIcon = [''] -const mockReleases = { - universal: { label: 'Universal', link: '/universal', checksum: 'abc123' }, - x86_64: { label: 'x86_64', link: '/x86_64', checksum: 'def456' }, - arm64: { label: 'ARM64', link: '/arm64', checksum: 'ghi789' }, - flathub: { all: { label: 'Flathub', link: '/flathub' } }, -} describe('', () => { let container: Awaited> @@ -17,37 +11,6 @@ describe('', () => { container = await AstroContainer.create() }) - it('renders mac platform', async () => { - const result = await container.renderToString(PlatformDownload, { - props: { - platform: 'mac', - icon: mockIcon, - title: 'Mac Title', - description: 'Mac Desc', - releases: mockReleases, - }, - }) - expect(result).toContain('Mac Title') - expect(result).toContain('Mac Desc') - expect(result).toContain('Universal') - }) - - it('renders windows platform', async () => { - const result = await container.renderToString(PlatformDownload, { - props: { - platform: 'windows', - icon: mockIcon, - title: 'Win Title', - description: 'Win Desc', - releases: mockReleases, - }, - }) - expect(result).toContain('Win Title') - expect(result).toContain('Win Desc') - expect(result).toContain('x86_64') - expect(result).toContain('ARM64') - }) - it('renders linux platform with flathub and tarball', async () => { const linuxReleases = { flathub: { all: { label: 'Flathub', link: '/flathub' } }, @@ -63,16 +26,10 @@ describe('', () => { props: { platform: 'linux', icon: mockIcon, - title: 'Linux Title', - description: 'Linux Desc', releases: linuxReleases, }, }) - expect(result).toContain('Linux Title') - expect(result).toContain('Linux Desc') expect(result).toContain('Flathub') - expect(result).toContain('Tarball') - expect(result).toContain('x86_64') }) it('renders linux platform with all branches', async () => { @@ -97,30 +54,11 @@ describe('', () => { props: { platform: 'linux', icon: mockIcon, - title: 'Linux Title', - description: 'Linux Desc', releases: linuxReleases, }, }) - // Test basic content - expect(result).toContain('Linux Title') - expect(result).toContain('Linux Desc') - // Test Flathub section - expect(result).toContain('Flathub') expect(result).toContain('/flathub') - - // Test x86_64 section - expect(result).toContain('x86_64') - expect(result).toContain('Tarball x86_64') - expect(result).toContain('/tarball-x86_64') - expect(result).toContain('sha256') - - // Test ARM64 section - expect(result).toContain('ARM64') - expect(result).toContain('Tarball ARM64') - expect(result).toContain('/tarball-arm64') - expect(result).toContain('sha256-arm64') }) }) diff --git a/src/tests/pages/download.spec.ts b/src/tests/pages/download.spec.ts index ca8a3ff..f7f1a51 100644 --- a/src/tests/pages/download.spec.ts +++ b/src/tests/pages/download.spec.ts @@ -3,38 +3,44 @@ import { expect, test, type BrowserContextOptions, type Page } from '@playwright import { getReleasesWithChecksums } from '~/components/download/release-data' import { CONSTANT } from '~/constants' -// Helper to get the platform section by id -const getPlatformSection = (page: Page, platform: string) => - page.locator(`#${platform}-downloads.platform-section[data-active='true']`) +const getPlatformSection = (page: Page, platform: string, cpu: string) => { + return page.locator(`#${platform}-${cpu}-downloads.platform-section`) +} -// Helper to get the platform tab button -const getPlatformButton = (page: Page, platform: string) => - page.locator(`button.platform-selector[data-platform='${platform}']`) - -const platformConfigs: { name: string; userAgent: string; platform: string }[] = [ +const platformConfigs: { + name: string + userAgent: string + platform: string + expectedCpu: string +}[] = [ { name: 'windows', userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36', platform: 'Win32', + expectedCpu: 'x86_64', }, { name: 'mac', userAgent: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.1 Safari/605.1.15', platform: 'MacIntel', + expectedCpu: 'x86_64', }, { name: 'linux', userAgent: 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36', platform: 'Linux x86_64', + expectedCpu: 'x86_64', }, ] -test.describe('Download page default tab per platform', () => { - for (const { name, userAgent, platform } of platformConfigs) { - test(`shows correct default tab for ${name} platform`, async ({ browser }) => { +test.describe('Download page shows correct platform section per platform', () => { + for (const { name, userAgent, platform, expectedCpu } of platformConfigs) { + test(`shows correct platform section for ${name} ${expectedCpu} platform`, async ({ + browser, + }) => { const context = await browser.newContext({ userAgent, locale: 'en-US', @@ -42,66 +48,64 @@ test.describe('Download page default tab per platform', () => { } as BrowserContextOptions) const page = await context.newPage() await page.goto('/download') - await expect(getPlatformSection(page, name)).toBeVisible() - await expect(getPlatformButton(page, name)).toHaveAttribute('data-active', 'true') - // Other platforms should not be active - for (const other of platformConfigs.filter(p => p.name !== name)) { - await expect(getPlatformSection(page, other.name)).toBeHidden() - await expect(getPlatformButton(page, other.name)).not.toHaveAttribute('data-active', 'true') + + await page.waitForLoadState('domcontentloaded') + + await expect(getPlatformSection(page, name, expectedCpu)).toBeVisible() + + for (const other of platformConfigs.filter( + p => !(p.name === name && p.expectedCpu === expectedCpu) + )) { + const otherSection = page.locator( + `#${other.name}-${other.expectedCpu}-downloads.platform-section` + ) + await expect(otherSection).toBeHidden() } await context.close() }) } }) -test.describe('Download page platform detection and tab switching', () => { - test('shows correct platform section and tab when switching platforms', async ({ page }) => { - await page.goto('/download') - const platforms = ['windows', 'mac', 'linux'] - for (const platform of platforms) { - await getPlatformButton(page, platform).click() - await expect(getPlatformSection(page, platform)).toBeVisible() - await expect(getPlatformButton(page, platform)).toHaveAttribute('data-active', 'true') - // other platform sections should be hidden - for (const otherPlatform of platforms.filter(p => p !== platform)) { - await expect(getPlatformSection(page, otherPlatform)).toBeHidden() - await expect(getPlatformButton(page, otherPlatform)).not.toHaveAttribute( - 'data-active', - 'true' - ) - } - } - }) -}) - test.describe('Download page download links', () => { const releases = getReleasesWithChecksums('en')(CONSTANT.CHECKSUMS) type Releases = ReturnType> function getPlatformLinks(releases: Releases) { return { - mac: [releases.macos.universal], - windows: [releases.windows.x86_64, releases.windows.arm64], - linux: [ - releases.linux.x86_64.tarball, - releases.linux.aarch64.tarball, - releases.linux.flathub.all, - ], + 'mac-x86_64': [releases.macos.universal], + 'mac-arm64': [releases.macos.universal], + 'windows-x86_64': [releases.windows.x86_64], + 'windows-arm64': [releases.windows.arm64], + 'linux-x86_64': [releases.linux.x86_64.tarball, releases.linux.flathub.all], + 'linux-aarch64': [releases.linux.aarch64.tarball, releases.linux.flathub.all], } } test('all platform download links are correct', async ({ page }) => { - const platforms = ['windows', 'mac', 'linux'] const platformLinkSelectors = getPlatformLinks(releases) await page.goto('/download') await page.waitForLoadState('domcontentloaded') - for (const platform of platforms) { - await getPlatformButton(page, platform).click() - for (const { label, link } of platformLinkSelectors[ - platform as keyof typeof platformLinkSelectors - ]) { - const downloadLink = page.locator(`#${platform}-downloads .download-link[href="${link}"]`) - await expect(downloadLink).toContainText(label) + + for (const [platformCpu, links] of Object.entries(platformLinkSelectors)) { + const platform = platformCpu.split('-')[0] as 'mac' | 'windows' | 'linux' + + for (const { link } of links) { + const downloadLink = page.locator( + `#${platformCpu}-downloads .download-button[href="${link}"]` + ) + + const isFlathubLink = link.includes('flathub.org') + + if (isFlathubLink) { + await expect(downloadLink).toContainText('Flathub') + } else { + await expect(downloadLink).toContainText( + `Download for ${ + platform === 'mac' ? 'MacOS' : platform.charAt(0).toUpperCase() + platform.slice(1) + }` + ) + } + await expect(downloadLink).toHaveAttribute('href', link) } }