diff --git a/aside-react/.gitignore b/aside-react/.gitignore new file mode 100644 index 00000000..b9470778 --- /dev/null +++ b/aside-react/.gitignore @@ -0,0 +1,2 @@ +node_modules/ +dist/ diff --git a/aside-react/README.md b/aside-react/README.md new file mode 100644 index 00000000..629810dc --- /dev/null +++ b/aside-react/README.md @@ -0,0 +1,58 @@ +# Recordly landing page and reference archive + +This project contains two separate deliverables: + +- `extracted/index.original.html`: the public homepage HTML downloaded directly from https://aside.com/. +- `extracted/public-source/`: 61 linked public JavaScript, CSS, font, and image resources, with provenance in `extracted/manifest.json`. +- `src/`: the Recordly landing page, with Recordly demos, recording/editing features, cloud-sharing information, and legal routes. The established layout and locally saved visual assets are preserved. + +The extraction is compiled public output, not Aside's original Next.js source or backend. It is a reference archive, not a standalone runnable mirror; additional lazy-loaded routes and API responses are not archived. Original third-party assets retain their owners' rights. The React application does not run the archived scripts or tracking code. + +## Run + +```sh +npm install +npm run dev +``` + +Open http://127.0.0.1:5178. Run `npm run build` for production output and `npm run preview` to inspect it. + +## Implementation + +The blog lives at `/blog` and starts with an empty state. It uses the same +`SiteHeader.jsx`, font, navigation controls, and button styles as the landing page. +The light header preserves the original accent-blue Recordly mark. Blog is a +direct navigation link; there is no Tutorials page or generated article content. + +Add hand-written articles to the empty array in `src/blog/posts.js` when needed. +The existing article renderer supports paragraphs, lists, tables, and code blocks. +`npm run build` prerenders the blog and any authored articles with metadata and a +sitemap. Set `VITE_SITE_URL` at build time to the actual deployment origin; its +default matches the existing review host. Run `node scripts/check-blog.mjs` after +building to verify that no generated articles or tutorial routes remain. + +The header's Pricing link opens `/pricing`, a dedicated Free/Cloud comparison +based on the source pricing layout. The Cloud amount and numeric limits load +from the public managed-service catalog; an unavailable or invalid response shows +a retry state instead of an invented price. Subscriptions are started in the +Recordly app. `/billing` remains the separate billing-and-refunds policy. + +The hero announcement is hidden by default: set `heroAnnouncement` in +`src/main.jsx` to `{ title, href }` when a post should be featured. + +The Recordly legal drafts are available at `/privacy`, `/terms`, `/billing` and +`/contact`, with `/policy/privacy` and `/policy/terms` aliases for existing links. +They mirror `services/recordly-share/worker/web/src/pages/`; keep both copies in +sync when changing policy wording. Pages remain marked as drafts and `noindex` +until the `VITE_LEGAL_*` publication details are valid and explicitly approved +after operator review. Production hosting must serve `index.html` for these +client-side routes. + +- Responsive desktop/mobile navigation with dropdowns, Escape handling, and outside-click dismissal. +- Recordly hero video, sticky Record/Preview/Share walkthrough, automatic-zoom and cursor demos, pricing overview, privacy information, and footer. +- Reduced-motion support, keyboard focus styling, semantic sections, and a skip link. +- Download buttons lead to the official Recordly GitHub releases page. No unpublished beta artifact is advertised. Availability was checked against GitHub on 2026-10-24: v1.4.0 is the latest public release and 2.0 beta remains in preparation. Update that availability text when the beta is published. +- Pricing amounts are deliberately not duplicated here. The desktop app displays the server-verified `/api/billing/catalog` entry and checks it against the account's checkout price; this page links to the billing policy and directs visitors to the app for current pricing. +- `wrangler.jsonc` deploys this app as the separate `recordly-beta-landing` static-assets Worker, including SPA fallback for legal routes. After `npm run build`, deploy from this directory using the existing Cloudflare CLI (`wrangler deploy`). The review preview is https://recordly-beta-landing.youngchen3442.workers.dev. This configuration does not attach a custom domain. The existing root website and `videos.recordly.dev` service remain separate; root-domain cutover requires an explicit hosting/domain decision. + +Public resources were extracted on 2026-09-21. To refresh the reference archive, run `python3 extracted/extract.py` after replacing `extracted/index.original.html` with a fresh download. The script fetches only static resources referenced by that HTML and its linked bundles. diff --git a/aside-react/index.html b/aside-react/index.html new file mode 100644 index 00000000..2c68b30d --- /dev/null +++ b/aside-react/index.html @@ -0,0 +1,2 @@ + +Recordly — Beautiful, shareable screen recordings.
diff --git a/aside-react/package-lock.json b/aside-react/package-lock.json new file mode 100644 index 00000000..3d0c4cbc --- /dev/null +++ b/aside-react/package-lock.json @@ -0,0 +1,973 @@ +{ + "name": "aside-react-landing", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "aside-react-landing", + "version": "1.0.0", + "dependencies": { + "@solar-icons/react": "^2.3.0", + "motion": "^12.23.24", + "react": "18.3.1", + "react-dom": "18.3.1" + }, + "devDependencies": { + "vite": "^8.3.0" + } + }, + "node_modules/@oxc-project/types": { + "version": "0.155.0", + "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.155.0.tgz", + "integrity": "sha512-SeE8JPwW1xs1tHeNycjUtUBdhorRa8o4jlvjwk49R7/Z291i+4DQa7JJIgOm/TaYQZx+QrPQbVJ/9c8dMIZN8Q==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/oxc-project" + } + }, + "node_modules/@rolldown/binding-android-arm-eabi": { + "version": "1.2.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm-eabi/-/binding-android-arm-eabi-1.2.15.tgz", + "integrity": "sha512-aLcgK9gIJ3YRvrrtfSBbRa27F5WrpiTaPulnFpsHPxpUHgFlSgnU4854MHwoRGEBhfRJDWCS2WQ7lIjskE9Olw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-android-arm64": { + "version": "1.2.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.2.15.tgz", + "integrity": "sha512-xD7DdZCrbThKuxNg7ooQmvp07ys4J/pnSEMTG3/OdOWl6daC67m/Q4fL78sRHMxTH/N4fGUbYhcPM0MF5WFHkg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-darwin-arm64": { + "version": "1.2.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.2.15.tgz", + "integrity": "sha512-m2WuQ6r0B4OTYxyPpNLtXaMRbRDUbG8YQV2Q3KTdSSK8Th6KHCnC8jVCJt8bvYeSB5WivkkNbc85mKadaSdOxA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-darwin-x64": { + "version": "1.2.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.2.15.tgz", + "integrity": "sha512-5RtnsHM36nodM9WbMy+zip0LGS/G+y5wro5RHrpOlr4ac24+1zSi9kiV2MP1myZeZ/ifEHfulQcWjnAXzc2C2A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-freebsd-x64": { + "version": "1.2.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.2.15.tgz", + "integrity": "sha512-g3l09pyFqhu+135JKkbkwiKGQmwU5hUMUPJ4VdBADvuqR8d33L6H578rh8m7rtxbdp+VmX/+nzI7nvhSZlzpUQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm-gnueabihf": { + "version": "1.2.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.2.15.tgz", + "integrity": "sha512-nIe3VugI97nGQtspPxDqA4sXMUpeiocKIP/CqpY/u/vgbT+alX+cVxu1C/oVBPKg4feNTmYovE91v4DgXvXNwQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm64-gnu": { + "version": "1.2.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.2.15.tgz", + "integrity": "sha512-iTBjXx+B5QSvgI89lJfmqh4wTh8NabR1YZIIN3hNx4zSG0EVfVqkOvLulNpG4251pbd6/IAmZ/LefVk1Y4rPhw==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm64-musl": { + "version": "1.2.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.2.15.tgz", + "integrity": "sha512-uN26XOnVR7rqQupG3V9oAG2EGGatWjcJHOeDOHUFCh4TBWmP2tHTFoVN13aYbwfm0aHqJAEmcwhAu6sooIjfqQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-ppc64-gnu": { + "version": "1.2.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.2.15.tgz", + "integrity": "sha512-9nWkcdd+H+XhaA3fQIwpHnKIrfx/PQ6rO0pivr78Og07tXlUlctBBJoEYLPfhTmCR/QxEVdn6uPjHV5SymPhdw==", + "cpu": [ + "ppc64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-s390x-gnu": { + "version": "1.2.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.2.15.tgz", + "integrity": "sha512-Ggh0ciFjLwIusLSLz7LZYEaGdxOAUJXI+Qu5JCbhPJJHEt8vP+IjRATTJheiJsdzzTYgUiHUiw3X1Ea3ZpMBdA==", + "cpu": [ + "s390x" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-x64-gnu": { + "version": "1.2.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.2.15.tgz", + "integrity": "sha512-FHg60rS6DBePAYZ9X9F67x+JObFdmgn6tupA1C/a3B+CufFmTD4mX+e8M75tCiAO3foR/6xwVBI0KQiI7sn/rw==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-x64-musl": { + "version": "1.2.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.2.15.tgz", + "integrity": "sha512-/cvV/7v5VGz/moiz0XKRj2dE8DzsKyhIu1KpOvJGPjRywg3yscON889UGvAe8zfiJLHup7VLjBduoGWi3HusWQ==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-openharmony-arm64": { + "version": "1.2.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.2.15.tgz", + "integrity": "sha512-MyzC5Hrv/sm+Z7TSGKP/j8001RO2xQm1zOpCNVL4j0cY/VhBZviludA2YFQ7i4lH6ZAXxQm0lcMdBzM+99mE7w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-win32-arm64-msvc": { + "version": "1.2.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.2.15.tgz", + "integrity": "sha512-+PgYiS+AH5omy6L45ZLxybasauJaj3M8buoT83D+nzPmCayXlxUV9hydhciCKVyIg0B/v0BtXPDE1uGqNwCPpg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-win32-x64-msvc": { + "version": "1.2.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.2.15.tgz", + "integrity": "sha512-HFZd2QNQYn1JbIi+Hpd7H+r/lkWxcfIu28nirZ6eCn2LafuvmExMlb/P96Sfx5tf7pPArw39IdhmCF8vmV+NhQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/pluginutils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.1.tgz", + "integrity": "sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@solar-icons/react": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@solar-icons/react/-/react-2.3.0.tgz", + "integrity": "sha512-ihrnDrdksuX76wsea9i0jlEtln0Vgkzj0TxhIJ2JRWhDSwvX+ItXT3KR30C6ldMmFrEMcbpRCfGxOIHNlOZr0g==", + "license": "MIT", + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "react": ">= 16.8", + "react-dom": ">= 16.8" + } + }, + "node_modules/detect-libc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, + "node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/framer-motion": { + "version": "12.43.0", + "resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-12.43.0.tgz", + "integrity": "sha512-1eaL3RvR/kAlbG7UYcpMptEyzPoENO0c6w7ZnB3/hh2vSAz/6uGAFn6fdoqTBguNstf3MsFhJHsD/0DHiclG+g==", + "license": "MIT", + "dependencies": { + "motion-dom": "^12.43.0", + "motion-utils": "^12.39.0", + "tslib": "^2.4.0" + }, + "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 + } + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "license": "MIT" + }, + "node_modules/lightningcss": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.33.0.tgz", + "integrity": "sha512-WkUDrojuJs0xkgGf2udWxa3yGBRxPtxUkB79i6aCZLRgc7PM8fZe9TosfPDcvEpQZbuFASnHYmRLBLUbmLOIIA==", + "dev": true, + "license": "MPL-2.0", + "dependencies": { + "detect-libc": "^2.0.3" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "lightningcss-android-arm64": "1.33.0", + "lightningcss-darwin-arm64": "1.33.0", + "lightningcss-darwin-x64": "1.33.0", + "lightningcss-freebsd-x64": "1.33.0", + "lightningcss-linux-arm-gnueabihf": "1.33.0", + "lightningcss-linux-arm64-gnu": "1.33.0", + "lightningcss-linux-arm64-musl": "1.33.0", + "lightningcss-linux-x64-gnu": "1.33.0", + "lightningcss-linux-x64-musl": "1.33.0", + "lightningcss-win32-arm64-msvc": "1.33.0", + "lightningcss-win32-x64-msvc": "1.33.0" + } + }, + "node_modules/lightningcss-android-arm64": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.33.0.tgz", + "integrity": "sha512-gEpRTalKdosp4Bb8qWtc2iOgE5SeIHlpS1up9bFq2wAyYhl1UdTObYiHe98zEM9SQvSoqQZ1IQD0JNpg3Ml5pg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-arm64": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.33.0.tgz", + "integrity": "sha512-Sciaz8eenNTKn9b3t7+xr0ipTp9YxKQY4npwQ3mrRuL0BAVHBLyZxofhaKBAVtzmtRZ/zTyo0/to4B1uWG/Djg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-x64": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.33.0.tgz", + "integrity": "sha512-Z5UPAxzrjlWNNyGy6i65cJzzvgJ5D3T6wMvs+gWpY9d7qRhANrxqAp6LhxIgZhWEw18RfJTGcRxjuLIBr+m8XQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-freebsd-x64": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.33.0.tgz", + "integrity": "sha512-QQM/Ti/hQajJwCY+RiWuCZ9sdtI/XQk7nDK5vC8kkdwixezOlDgvDx7+RT+QjK6FcFT4MpsuoBnHIo/O3StRRg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm-gnueabihf": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.33.0.tgz", + "integrity": "sha512-N7FVBe6iS24MlM6R/4RBTxGhQheZGs7tiQ9U32UtF75NzP5Q7xWPRqLBCKxlRQRk3rY1jCIPLzx7WzOhuUIRLQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-gnu": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.33.0.tgz", + "integrity": "sha512-j2v/itmy4HlNxlc6voKXYgBqNi0Ng2LShg4z7GufpEgs05P+2suBVyi9I6YHq5uoVFx9ETin3eCEhLVyXGQnKg==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-musl": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.33.0.tgz", + "integrity": "sha512-yiO5ROMuYQgXbC60yjZU5CYSFZGKXL0HFATXt9mHJn1+zW55oCtMI9NfcVhYLMFDL7gV7oBPon/EmMMGg2OvtQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-gnu": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.33.0.tgz", + "integrity": "sha512-ar+Ju7LmcN0Jo4FpL4hpFybwNG9/3A/Br5KW2n2jyODg3MEZXaDYADdemoNS+BDNfMgKvylJLj4S5tyRActuAg==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-musl": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.33.0.tgz", + "integrity": "sha512-RYiYbkokw0trfKqqzfF55lginwEPrD3OJDfTuJzFs1MK6iFnDenaz1fqLLtX4ITG3OktJQXOeTaw1awrBAlZPw==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-arm64-msvc": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.33.0.tgz", + "integrity": "sha512-1K+MPfLSFVpphzpdbfkhlWk6wBrTObBzS2T6db10PNOZgR9GoVsAWzwNyuhUYYbTp23j+4RrncfujZ4uAzXvwA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-x64-msvc": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.33.0.tgz", + "integrity": "sha512-OlEICDx/Xl0FqSp4bry8zFnCvGpig3Gl4gCquvYwHuqJKEC1+n9NgDniFvqHGmMv1ZkqDJrDqKKSykTDX+ehuA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "license": "MIT", + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/motion": { + "version": "12.23.24", + "resolved": "https://registry.npmjs.org/motion/-/motion-12.23.24.tgz", + "integrity": "sha512-Rc5E7oe2YZ72N//S3QXGzbnXgqNrTESv8KKxABR20q2FLch9gHLo0JLyYo2hZ238bZ9Gx6cWhj9VO0IgwbMjCw==", + "license": "MIT", + "dependencies": { + "framer-motion": "^12.23.24", + "tslib": "^2.4.0" + }, + "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 + } + } + }, + "node_modules/motion-dom": { + "version": "12.43.0", + "resolved": "https://registry.npmjs.org/motion-dom/-/motion-dom-12.43.0.tgz", + "integrity": "sha512-azKON4d9S65PEoFUiQTMTgPheEmzf2QngdRc50AKfJp9Q9mmcBVw22c8eMq9k8kxOFHdL7+WZY7N/5F/lwiDag==", + "license": "MIT", + "dependencies": { + "motion-utils": "^12.39.0" + } + }, + "node_modules/motion-utils": { + "version": "12.39.0", + "resolved": "https://registry.npmjs.org/motion-utils/-/motion-utils-12.39.0.tgz", + "integrity": "sha512-8nadJAJjTtqRkmRF36FoJTrywK9nnFmnPwnSMyxaOCU7GDjN9RTMJIxx9De8ErM+vpPhMccr/6fo5WciyQLnMQ==", + "license": "MIT" + }, + "node_modules/nanoid": { + "version": "3.3.20", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.20.tgz", + "integrity": "sha512-uKdg2G3GNCKQn9byYOpxbGqrT2fGO5KRt5J/8b3pok8rT6qxGWF6hxMyJiEYtAf+FVyYuD9hRaDqX5uPFYJ4ZQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.7.tgz", + "integrity": "sha512-qcJu88Q2IWqJsDD529JKMdwGm/dvInW4HvQnRwiH9JtihJvzGOscDtHE3x1pBKeUOTysQ8kVmLnJ2kJu7yhcGA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/postcss": { + "version": "8.5.31", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.31.tgz", + "integrity": "sha512-YUbWYCgErwnMAVkjUnYa+KlMBzGpHwiIt/DE7f0G33AuX2LH9UcTk6KgWxd3zRU+pN3u/C+Xl3EnMLM4Hea7Sg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.20", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.2" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/react": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", + "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dom": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", + "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0", + "scheduler": "^0.23.2" + }, + "peerDependencies": { + "react": "^18.3.1" + } + }, + "node_modules/rolldown": { + "version": "1.2.15", + "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.2.15.tgz", + "integrity": "sha512-6odND+fel5zVw3I4Yc2e69gvguDnX0CAAGiNDZSq4ik5WUcaLrkD2GLuog0XcODbor31hZ5ayEMgVDno+KPV5g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@oxc-project/types": "=0.155.0", + "@rolldown/pluginutils": "^1.0.0" + }, + "bin": { + "rolldown": "bin/cli.mjs" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "optionalDependencies": { + "@rolldown/binding-android-arm-eabi": "1.2.15", + "@rolldown/binding-android-arm64": "1.2.15", + "@rolldown/binding-darwin-arm64": "1.2.15", + "@rolldown/binding-darwin-x64": "1.2.15", + "@rolldown/binding-freebsd-x64": "1.2.15", + "@rolldown/binding-linux-arm-gnueabihf": "1.2.15", + "@rolldown/binding-linux-arm64-gnu": "1.2.15", + "@rolldown/binding-linux-arm64-musl": "1.2.15", + "@rolldown/binding-linux-ppc64-gnu": "1.2.15", + "@rolldown/binding-linux-s390x-gnu": "1.2.15", + "@rolldown/binding-linux-x64-gnu": "1.2.15", + "@rolldown/binding-linux-x64-musl": "1.2.15", + "@rolldown/binding-openharmony-arm64": "1.2.15", + "@rolldown/binding-win32-arm64-msvc": "1.2.15", + "@rolldown/binding-win32-x64-msvc": "1.2.15" + } + }, + "node_modules/scheduler": { + "version": "0.23.2", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", + "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0" + } + }, + "node_modules/source-map-js": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.2.tgz", + "integrity": "sha512-KGj/8Y43x35aZVDtt+J4mK1hoLGHULMYfSkODJNQjNDC3oW1PqPoxMwo0pLUsWM/UEGzON/NxeHywEfNXNP3Vw==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/tinyglobby": { + "version": "0.2.17", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz", + "integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.4" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/tslib": { + "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/vite": { + "version": "8.3.5", + "resolved": "https://registry.npmjs.org/vite/-/vite-8.3.5.tgz", + "integrity": "sha512-z1YpjieJ9g0ebTmQpLBv/oq9E3F9EIlOe+7LahW8SrE3LTiG3udBRUXQOlYXP9b+IC2q2phHeVxj9xGlw34OEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "lightningcss": "^1.33.0", + "picomatch": "^4.0.7", + "postcss": "^8.5.30", + "rolldown": "~1.2.14", + "tinyglobby": "^0.2.17" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^20.19.0 || >=22.12.0", + "@vitejs/devtools": "^0.7.1 || ^0.8.0", + "esbuild": "^0.27.0 || ^0.28.0", + "jiti": ">=1.21.0", + "less": "^4.0.0", + "sass": "^1.70.0", + "sass-embedded": "^1.70.0", + "stylus": ">=0.54.8", + "sugarss": "^5.0.0", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "@vitejs/devtools": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + } + } +} diff --git a/aside-react/package.json b/aside-react/package.json new file mode 100644 index 00000000..2737b506 --- /dev/null +++ b/aside-react/package.json @@ -0,0 +1,20 @@ +{ + "name": "aside-react-landing", + "version": "1.0.0", + "private": true, + "type": "module", + "scripts": { + "dev": "vite --host 127.0.0.1", + "build": "vite build && node scripts/prerender-blog.mjs", + "preview": "vite preview --host 127.0.0.1" + }, + "dependencies": { + "@solar-icons/react": "^2.3.0", + "motion": "^12.23.24", + "react": "18.3.1", + "react-dom": "18.3.1" + }, + "devDependencies": { + "vite": "^8.3.0" + } +} diff --git a/aside-react/public/assets/1.128t-vhmdbwp7.png b/aside-react/public/assets/1.128t-vhmdbwp7.png new file mode 100644 index 00000000..e34f2f00 Binary files /dev/null and b/aside-react/public/assets/1.128t-vhmdbwp7.png differ diff --git a/aside-react/public/assets/1.1d6n3khmb26p_.webp b/aside-react/public/assets/1.1d6n3khmb26p_.webp new file mode 100644 index 00000000..34b464ac Binary files /dev/null and b/aside-react/public/assets/1.1d6n3khmb26p_.webp differ diff --git a/aside-react/public/assets/1.3-b62prl6in98.png b/aside-react/public/assets/1.3-b62prl6in98.png new file mode 100644 index 00000000..575959e2 Binary files /dev/null and b/aside-react/public/assets/1.3-b62prl6in98.png differ diff --git a/aside-react/public/assets/2.0sjx52o1m2j5u.png b/aside-react/public/assets/2.0sjx52o1m2j5u.png new file mode 100644 index 00000000..094769b3 Binary files /dev/null and b/aside-react/public/assets/2.0sjx52o1m2j5u.png differ diff --git a/aside-react/public/assets/2.23cqtpb5x3dng.webp b/aside-react/public/assets/2.23cqtpb5x3dng.webp new file mode 100644 index 00000000..6de6a3c2 Binary files /dev/null and b/aside-react/public/assets/2.23cqtpb5x3dng.webp differ diff --git a/aside-react/public/assets/2.3ukhkerkzdgq8.png b/aside-react/public/assets/2.3ukhkerkzdgq8.png new file mode 100644 index 00000000..2a4c4c51 Binary files /dev/null and b/aside-react/public/assets/2.3ukhkerkzdgq8.png differ diff --git a/aside-react/public/assets/3.2t8whzu_s0tv6.webp b/aside-react/public/assets/3.2t8whzu_s0tv6.webp new file mode 100644 index 00000000..54baeac2 Binary files /dev/null and b/aside-react/public/assets/3.2t8whzu_s0tv6.webp differ diff --git a/aside-react/public/assets/3.3tb2mnvz7y2i6.png b/aside-react/public/assets/3.3tb2mnvz7y2i6.png new file mode 100644 index 00000000..a9372d34 Binary files /dev/null and b/aside-react/public/assets/3.3tb2mnvz7y2i6.png differ diff --git a/aside-react/public/assets/4fa387ec64143e14-s.3f4zuumv8svu0.woff2 b/aside-react/public/assets/4fa387ec64143e14-s.3f4zuumv8svu0.woff2 new file mode 100644 index 00000000..4fc15d1f Binary files /dev/null and b/aside-react/public/assets/4fa387ec64143e14-s.3f4zuumv8svu0.woff2 differ diff --git a/aside-react/public/assets/53b9e256198e5412-s.2gwoz23eiro2t.woff2 b/aside-react/public/assets/53b9e256198e5412-s.2gwoz23eiro2t.woff2 new file mode 100644 index 00000000..0bcca1b2 Binary files /dev/null and b/aside-react/public/assets/53b9e256198e5412-s.2gwoz23eiro2t.woff2 differ diff --git a/aside-react/public/assets/5ce348bf30bf5439-s.27spqqad3wyeo.woff2 b/aside-react/public/assets/5ce348bf30bf5439-s.27spqqad3wyeo.woff2 new file mode 100644 index 00000000..c7700cdf Binary files /dev/null and b/aside-react/public/assets/5ce348bf30bf5439-s.27spqqad3wyeo.woff2 differ diff --git a/aside-react/public/assets/6306c77e7c8268e4-s.34r5yzckw0h2s.woff2 b/aside-react/public/assets/6306c77e7c8268e4-s.34r5yzckw0h2s.woff2 new file mode 100644 index 00000000..29dd20f5 Binary files /dev/null and b/aside-react/public/assets/6306c77e7c8268e4-s.34r5yzckw0h2s.woff2 differ diff --git a/aside-react/public/assets/7178b3e590c64307-s.0i3h3th1vs4m7.woff2 b/aside-react/public/assets/7178b3e590c64307-s.0i3h3th1vs4m7.woff2 new file mode 100644 index 00000000..8a1d3df6 Binary files /dev/null and b/aside-react/public/assets/7178b3e590c64307-s.0i3h3th1vs4m7.woff2 differ diff --git a/aside-react/public/assets/797e433ab948586e-s.p.1v5bejj26fx9h.woff2 b/aside-react/public/assets/797e433ab948586e-s.p.1v5bejj26fx9h.woff2 new file mode 100644 index 00000000..cf24126b Binary files /dev/null and b/aside-react/public/assets/797e433ab948586e-s.p.1v5bejj26fx9h.woff2 differ diff --git a/aside-react/public/assets/7d817b4c03b0c5f1-s.2jyz_zw3a8jit.woff2 b/aside-react/public/assets/7d817b4c03b0c5f1-s.2jyz_zw3a8jit.woff2 new file mode 100644 index 00000000..873f580e Binary files /dev/null and b/aside-react/public/assets/7d817b4c03b0c5f1-s.2jyz_zw3a8jit.woff2 differ diff --git a/aside-react/public/assets/8a480f0b521d4e75-s.3j-a226dh71aj.woff2 b/aside-react/public/assets/8a480f0b521d4e75-s.3j-a226dh71aj.woff2 new file mode 100644 index 00000000..f385e23a Binary files /dev/null and b/aside-react/public/assets/8a480f0b521d4e75-s.3j-a226dh71aj.woff2 differ diff --git a/aside-react/public/assets/AsideDisplay_Variable-s.p.1sv22ercfkh3x.woff2 b/aside-react/public/assets/AsideDisplay_Variable-s.p.1sv22ercfkh3x.woff2 new file mode 100644 index 00000000..8f96340a Binary files /dev/null and b/aside-react/public/assets/AsideDisplay_Variable-s.p.1sv22ercfkh3x.woff2 differ diff --git a/aside-react/public/assets/apple.svg b/aside-react/public/assets/apple.svg new file mode 100644 index 00000000..0ba1a906 --- /dev/null +++ b/aside-react/public/assets/apple.svg @@ -0,0 +1 @@ + diff --git a/aside-react/public/assets/background.2tnr0c16bt-fz.webp b/aside-react/public/assets/background.2tnr0c16bt-fz.webp new file mode 100644 index 00000000..957a255b Binary files /dev/null and b/aside-react/public/assets/background.2tnr0c16bt-fz.webp differ diff --git a/aside-react/public/assets/banner.1c099t9pt7-1c.webp b/aside-react/public/assets/banner.1c099t9pt7-1c.webp new file mode 100644 index 00000000..3866a78f Binary files /dev/null and b/aside-react/public/assets/banner.1c099t9pt7-1c.webp differ diff --git a/aside-react/public/assets/bbc41e54d2fcbd21-s.30bdpjkrtcces.woff2 b/aside-react/public/assets/bbc41e54d2fcbd21-s.30bdpjkrtcces.woff2 new file mode 100644 index 00000000..751a04d2 Binary files /dev/null and b/aside-react/public/assets/bbc41e54d2fcbd21-s.30bdpjkrtcces.woff2 differ diff --git a/aside-react/public/assets/caa3a2e1cccd8315-s.p.0zr6hhvz-h9nw.woff2 b/aside-react/public/assets/caa3a2e1cccd8315-s.p.0zr6hhvz-h9nw.woff2 new file mode 100644 index 00000000..8f01e763 Binary files /dev/null and b/aside-react/public/assets/caa3a2e1cccd8315-s.p.0zr6hhvz-h9nw.woff2 differ diff --git a/aside-react/public/assets/caveat-OFL.txt b/aside-react/public/assets/caveat-OFL.txt new file mode 100644 index 00000000..5303054d --- /dev/null +++ b/aside-react/public/assets/caveat-OFL.txt @@ -0,0 +1,93 @@ +Copyright 2014 The Caveat Project Authors (https://github.com/googlefonts/caveat) + +This Font Software is licensed under the SIL Open Font License, Version 1.1. +This license is copied below, and is also available with a FAQ at: +http://scripts.sil.org/OFL + + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/aside-react/public/assets/caveat-variable.ttf b/aside-react/public/assets/caveat-variable.ttf new file mode 100644 index 00000000..f84acf2c Binary files /dev/null and b/aside-react/public/assets/caveat-variable.ttf differ diff --git a/aside-react/public/assets/dm-sans-OFL.txt b/aside-react/public/assets/dm-sans-OFL.txt new file mode 100644 index 00000000..a0eedfbf --- /dev/null +++ b/aside-react/public/assets/dm-sans-OFL.txt @@ -0,0 +1,93 @@ +Copyright 2014 The DM Sans Project Authors (https://github.com/googlefonts/dm-fonts) + +This Font Software is licensed under the SIL Open Font License, Version 1.1. +This license is copied below, and is also available with a FAQ at: +https://scripts.sil.org/OFL + + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/aside-react/public/assets/dm-sans-italic-variable.ttf b/aside-react/public/assets/dm-sans-italic-variable.ttf new file mode 100644 index 00000000..bf6819b0 Binary files /dev/null and b/aside-react/public/assets/dm-sans-italic-variable.ttf differ diff --git a/aside-react/public/assets/dm-sans-variable.ttf b/aside-react/public/assets/dm-sans-variable.ttf new file mode 100644 index 00000000..c672f980 Binary files /dev/null and b/aside-react/public/assets/dm-sans-variable.ttf differ diff --git a/aside-react/public/assets/fef07dbb0973bf53-s.00az9qtie3ho1.woff2 b/aside-react/public/assets/fef07dbb0973bf53-s.00az9qtie3ho1.woff2 new file mode 100644 index 00000000..7ab581f7 Binary files /dev/null and b/aside-react/public/assets/fef07dbb0973bf53-s.00az9qtie3ho1.woff2 differ diff --git a/aside-react/public/assets/figma.svg b/aside-react/public/assets/figma.svg new file mode 100644 index 00000000..979e69e4 --- /dev/null +++ b/aside-react/public/assets/figma.svg @@ -0,0 +1 @@ + diff --git a/aside-react/public/assets/icon-google.0me3_e-g89-ei.png b/aside-react/public/assets/icon-google.0me3_e-g89-ei.png new file mode 100644 index 00000000..94ce6e83 Binary files /dev/null and b/aside-react/public/assets/icon-google.0me3_e-g89-ei.png differ diff --git a/aside-react/public/assets/icon-slack.2tnril4x7v74t.png b/aside-react/public/assets/icon-slack.2tnril4x7v74t.png new file mode 100644 index 00000000..0c1b09c4 Binary files /dev/null and b/aside-react/public/assets/icon-slack.2tnril4x7v74t.png differ diff --git a/aside-react/public/assets/icon-ycombinator.3g_mp0zdg4us-.png b/aside-react/public/assets/icon-ycombinator.3g_mp0zdg4us-.png new file mode 100644 index 00000000..d1fe13ec Binary files /dev/null and b/aside-react/public/assets/icon-ycombinator.3g_mp0zdg4us-.png differ diff --git a/aside-react/public/assets/icons.07sng_y96t659.webp b/aside-react/public/assets/icons.07sng_y96t659.webp new file mode 100644 index 00000000..915848d6 Binary files /dev/null and b/aside-react/public/assets/icons.07sng_y96t659.webp differ diff --git a/aside-react/public/assets/logo.svg b/aside-react/public/assets/logo.svg new file mode 100644 index 00000000..0a1a241f --- /dev/null +++ b/aside-react/public/assets/logo.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/aside-react/public/assets/mark.svg b/aside-react/public/assets/mark.svg new file mode 100644 index 00000000..b3d75d3e --- /dev/null +++ b/aside-react/public/assets/mark.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/aside-react/public/assets/microsoft.svg b/aside-react/public/assets/microsoft.svg new file mode 100644 index 00000000..1f739764 --- /dev/null +++ b/aside-react/public/assets/microsoft.svg @@ -0,0 +1 @@ +MS-SymbolLockup \ No newline at end of file diff --git a/aside-react/public/assets/page-curl-top.1t35kmrgmqhj0.png b/aside-react/public/assets/page-curl-top.1t35kmrgmqhj0.png new file mode 100644 index 00000000..12a551fb Binary files /dev/null and b/aside-react/public/assets/page-curl-top.1t35kmrgmqhj0.png differ diff --git a/aside-react/public/assets/platform-icons-LICENSE.txt b/aside-react/public/assets/platform-icons-LICENSE.txt new file mode 100644 index 00000000..e2eb0bd0 --- /dev/null +++ b/aside-react/public/assets/platform-icons-LICENSE.txt @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2020 Phosphor Icons + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/aside-react/public/assets/platform-linux.svg b/aside-react/public/assets/platform-linux.svg new file mode 100644 index 00000000..ca56d1b2 --- /dev/null +++ b/aside-react/public/assets/platform-linux.svg @@ -0,0 +1 @@ + diff --git a/aside-react/public/assets/platform-macos.svg b/aside-react/public/assets/platform-macos.svg new file mode 100644 index 00000000..09310da7 --- /dev/null +++ b/aside-react/public/assets/platform-macos.svg @@ -0,0 +1 @@ + diff --git a/aside-react/public/assets/platform-windows.svg b/aside-react/public/assets/platform-windows.svg new file mode 100644 index 00000000..7155015e --- /dev/null +++ b/aside-react/public/assets/platform-windows.svg @@ -0,0 +1 @@ + diff --git a/aside-react/public/assets/recordly-auto-zoom-demo.mp4 b/aside-react/public/assets/recordly-auto-zoom-demo.mp4 new file mode 100644 index 00000000..c3674773 Binary files /dev/null and b/aside-react/public/assets/recordly-auto-zoom-demo.mp4 differ diff --git a/aside-react/public/assets/recordly-auto-zoom-poster.jpg b/aside-react/public/assets/recordly-auto-zoom-poster.jpg new file mode 100644 index 00000000..dd3ed561 Binary files /dev/null and b/aside-react/public/assets/recordly-auto-zoom-poster.jpg differ diff --git a/aside-react/public/assets/recordly-blue-satin.png b/aside-react/public/assets/recordly-blue-satin.png new file mode 100644 index 00000000..ec86fc03 Binary files /dev/null and b/aside-react/public/assets/recordly-blue-satin.png differ diff --git a/aside-react/public/assets/recordly-blue-sky-balanced.png b/aside-react/public/assets/recordly-blue-sky-balanced.png new file mode 100644 index 00000000..fb4652ba Binary files /dev/null and b/aside-react/public/assets/recordly-blue-sky-balanced.png differ diff --git a/aside-react/public/assets/recordly-blue-sky-sparse.png b/aside-react/public/assets/recordly-blue-sky-sparse.png new file mode 100644 index 00000000..0da3ded4 Binary files /dev/null and b/aside-react/public/assets/recordly-blue-sky-sparse.png differ diff --git a/aside-react/public/assets/recordly-blue-sky.png b/aside-react/public/assets/recordly-blue-sky.png new file mode 100644 index 00000000..f6692c9a Binary files /dev/null and b/aside-react/public/assets/recordly-blue-sky.png differ diff --git a/aside-react/public/assets/recordly-cursor-demo.mp4 b/aside-react/public/assets/recordly-cursor-demo.mp4 new file mode 100644 index 00000000..61209613 Binary files /dev/null and b/aside-react/public/assets/recordly-cursor-demo.mp4 differ diff --git a/aside-react/public/assets/recordly-cursor-poster.jpg b/aside-react/public/assets/recordly-cursor-poster.jpg new file mode 100644 index 00000000..4a4c1bd9 Binary files /dev/null and b/aside-react/public/assets/recordly-cursor-poster.jpg differ diff --git a/aside-react/public/assets/recordly-dawn-sky.png b/aside-react/public/assets/recordly-dawn-sky.png new file mode 100644 index 00000000..478e7a70 Binary files /dev/null and b/aside-react/public/assets/recordly-dawn-sky.png differ diff --git a/aside-react/public/assets/recordly-hero-intro-hold-1p3.mp4 b/aside-react/public/assets/recordly-hero-intro-hold-1p3.mp4 new file mode 100644 index 00000000..af6e4a7d Binary files /dev/null and b/aside-react/public/assets/recordly-hero-intro-hold-1p3.mp4 differ diff --git a/aside-react/public/assets/recordly-hero-intro-hold.mp4 b/aside-react/public/assets/recordly-hero-intro-hold.mp4 new file mode 100644 index 00000000..8def23d2 Binary files /dev/null and b/aside-react/public/assets/recordly-hero-intro-hold.mp4 differ diff --git a/aside-react/public/assets/recordly-hero-intro-poster.jpg b/aside-react/public/assets/recordly-hero-intro-poster.jpg new file mode 100644 index 00000000..3c6cfa35 Binary files /dev/null and b/aside-react/public/assets/recordly-hero-intro-poster.jpg differ diff --git a/aside-react/public/assets/recordly-hero-poster.jpg b/aside-react/public/assets/recordly-hero-poster.jpg new file mode 100644 index 00000000..204ec865 Binary files /dev/null and b/aside-react/public/assets/recordly-hero-poster.jpg differ diff --git a/aside-react/public/assets/recordly-hero.mp4 b/aside-react/public/assets/recordly-hero.mp4 new file mode 100644 index 00000000..1e247c49 Binary files /dev/null and b/aside-react/public/assets/recordly-hero.mp4 differ diff --git a/aside-react/public/assets/recordly-mark-white.svg b/aside-react/public/assets/recordly-mark-white.svg new file mode 100644 index 00000000..03b2a264 --- /dev/null +++ b/aside-react/public/assets/recordly-mark-white.svg @@ -0,0 +1 @@ + diff --git a/aside-react/public/assets/recordly-mark.svg b/aside-react/public/assets/recordly-mark.svg new file mode 100644 index 00000000..6774e561 --- /dev/null +++ b/aside-react/public/assets/recordly-mark.svg @@ -0,0 +1 @@ + diff --git a/aside-react/public/assets/recordly-preview-feature.png b/aside-react/public/assets/recordly-preview-feature.png new file mode 100644 index 00000000..717dc977 Binary files /dev/null and b/aside-react/public/assets/recordly-preview-feature.png differ diff --git a/aside-react/public/assets/recordly-record-feature.png b/aside-react/public/assets/recordly-record-feature.png new file mode 100644 index 00000000..45133be8 Binary files /dev/null and b/aside-react/public/assets/recordly-record-feature.png differ diff --git a/aside-react/public/assets/recordly-share-feature.png b/aside-react/public/assets/recordly-share-feature.png new file mode 100644 index 00000000..e5dde7fb Binary files /dev/null and b/aside-react/public/assets/recordly-share-feature.png differ diff --git a/aside-react/public/assets/recordly-vibrant-sky.png b/aside-react/public/assets/recordly-vibrant-sky.png new file mode 100644 index 00000000..471bd0dc Binary files /dev/null and b/aside-react/public/assets/recordly-vibrant-sky.png differ diff --git a/aside-react/public/assets/recordly.svg b/aside-react/public/assets/recordly.svg new file mode 100644 index 00000000..57910c64 --- /dev/null +++ b/aside-react/public/assets/recordly.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/aside-react/public/assets/sample-profile.3kbfbkbz9b977.png b/aside-react/public/assets/sample-profile.3kbfbkbz9b977.png new file mode 100644 index 00000000..17c560bf Binary files /dev/null and b/aside-react/public/assets/sample-profile.3kbfbkbz9b977.png differ diff --git a/aside-react/public/assets/task-briefing.00ed4ci_knaoh.png b/aside-react/public/assets/task-briefing.00ed4ci_knaoh.png new file mode 100644 index 00000000..767bc333 Binary files /dev/null and b/aside-react/public/assets/task-briefing.00ed4ci_knaoh.png differ diff --git a/aside-react/public/assets/task-park.0eqyq6gfd0zm4.png b/aside-react/public/assets/task-park.0eqyq6gfd0zm4.png new file mode 100644 index 00000000..977116a9 Binary files /dev/null and b/aside-react/public/assets/task-park.0eqyq6gfd0zm4.png differ diff --git a/aside-react/public/assets/task-view-amazon.2x755srssjvo7.png b/aside-react/public/assets/task-view-amazon.2x755srssjvo7.png new file mode 100644 index 00000000..70c83115 Binary files /dev/null and b/aside-react/public/assets/task-view-amazon.2x755srssjvo7.png differ diff --git a/aside-react/public/assets/task-view-chase-screenshot-2.1w_va_ioz2l0g.png b/aside-react/public/assets/task-view-chase-screenshot-2.1w_va_ioz2l0g.png new file mode 100644 index 00000000..f7b71c2d Binary files /dev/null and b/aside-react/public/assets/task-view-chase-screenshot-2.1w_va_ioz2l0g.png differ diff --git a/aside-react/public/assets/task-view-chase-screenshot.049dbx6i4oitp.png b/aside-react/public/assets/task-view-chase-screenshot.049dbx6i4oitp.png new file mode 100644 index 00000000..d2e79d65 Binary files /dev/null and b/aside-react/public/assets/task-view-chase-screenshot.049dbx6i4oitp.png differ diff --git a/aside-react/public/assets/task-view-chase.3lqkry5dwyv4c.png b/aside-react/public/assets/task-view-chase.3lqkry5dwyv4c.png new file mode 100644 index 00000000..b29075ff Binary files /dev/null and b/aside-react/public/assets/task-view-chase.3lqkry5dwyv4c.png differ diff --git a/aside-react/public/assets/task-view-netflix.420h3-1n00_th.png b/aside-react/public/assets/task-view-netflix.420h3-1n00_th.png new file mode 100644 index 00000000..e8f81f42 Binary files /dev/null and b/aside-react/public/assets/task-view-netflix.420h3-1n00_th.png differ diff --git a/aside-react/public/assets/task-view-tab-preview.049dbx6i4oitp.png b/aside-react/public/assets/task-view-tab-preview.049dbx6i4oitp.png new file mode 100644 index 00000000..d2e79d65 Binary files /dev/null and b/aside-react/public/assets/task-view-tab-preview.049dbx6i4oitp.png differ diff --git a/aside-react/public/assets/task-website-design.3xvdo7pmp6g4z.png b/aside-react/public/assets/task-website-design.3xvdo7pmp6g4z.png new file mode 100644 index 00000000..8f902cd0 Binary files /dev/null and b/aside-react/public/assets/task-website-design.3xvdo7pmp6g4z.png differ diff --git a/aside-react/scripts/check-blog.mjs b/aside-react/scripts/check-blog.mjs new file mode 100644 index 00000000..ecb4f5a4 --- /dev/null +++ b/aside-react/scripts/check-blog.mjs @@ -0,0 +1,24 @@ +import assert from "node:assert/strict"; +import { readFile, readdir, access } from "node:fs/promises"; +import { dirname, resolve } from "node:path"; +import { fileURLToPath } from "node:url"; +const root = resolve(dirname(fileURLToPath(import.meta.url)), ".."); +const blog = resolve(root, "dist/blog"); +const contents = await readdir(blog, {withFileTypes:true}); +assert.equal(contents.filter((entry) => entry.isDirectory()).length, 0, "Generated article routes must be removed"); +const html = await readFile(resolve(blog, "index.html"), "utf8"); +assert.match(html, /id="root" data-prerendered/); +assert.match(html, /

Blog<\/h1>/); +assert.match(html, /No posts yet\./); +assert.doesNotMatch(html, /class="blog-card"|class="blog-filters"|BlogPosting|\/tutorials|assets\/blog\//); +assert.match(html, /Blog<\/a>/); +assert.match(html, /recordly-mark\.svg/); +assert.equal((html.match(/(.*?)<\/script>/s)[1]); +assert.equal(schema["@type"], "CollectionPage"); +assert.deepEqual(schema.mainEntity.itemListElement, []); +const sitemap = await readFile(resolve(root,"dist/sitemap.xml"), "utf8"); +assert.doesNotMatch(sitemap, /\/tutorials|\/blog\//); +await assert.rejects(access(resolve(root, "dist/tutorials"))); +console.log("Passed: empty Blog, direct navigation, blue logo, clean metadata, and no generated article or tutorial routes."); diff --git a/aside-react/scripts/check-pricing.mjs b/aside-react/scripts/check-pricing.mjs new file mode 100644 index 00000000..028d68ab --- /dev/null +++ b/aside-react/scripts/check-pricing.mjs @@ -0,0 +1,28 @@ +import assert from "node:assert/strict"; +import {readFile} from "node:fs/promises"; +import {fileURLToPath} from "node:url"; +import {resolve,dirname} from "node:path"; +import {parseCatalog,dollars,gigabytes} from "../src/pricing/catalog.js"; +const valid = {prices:[{interval:"monthly",currency:"usd",unitAmount:900,regularUnitAmount:1500,promotion:"early_bird"}],limits:{freeRecordingLimit:5,freeMaxRecordingBytes:1e9,plusMaxRecordingBytes:1e10,storageLimitBytes:null}}; +const parsed = parseCatalog(valid); +assert.equal(dollars(parsed.amount), "$9"); +assert.equal(dollars(parsed.regular), "$15"); +assert.equal(gigabytes(parsed.cloudBytes), "10 GB"); +assert.equal(parseCatalog({...valid,prices:[{...valid.prices[0],promotion:undefined}]}).regular,null); +for (const unitAmount of [0,-900,9.5,"900",NaN]) assert.throws(()=>parseCatalog({...valid,prices:[{...valid.prices[0],unitAmount}]})); +assert.throws(()=>parseCatalog({...valid,prices:[{...valid.prices[0],currency:"eur"}]})); +assert.throws(()=>parseCatalog({...valid,limits:{...valid.limits,plusMaxRecordingBytes:1}})); +assert.throws(()=>parseCatalog(null)); +const root=resolve(dirname(fileURLToPath(import.meta.url)),".."); +const html=await readFile(resolve(root,"dist/pricing/index.html"),"utf8"); +assert.match(html, /Pricing \| Recordly<\/title>/); +assert.match(html, /<a href="\/pricing">Pricing<\/a>/); +assert.match(html, /id="free-plan"/); +assert.match(html, /id="cloud-plan"/); +assert.doesNotMatch(html, /id="get-cloud"|href="#get-cloud"|Your plan lives in Recordly/); +assert.match(html, /href="\/billing">Billing & refunds/); +assert.doesNotMatch(html, /<a href="\/billing">Pricing/); +const blog=await readFile(resolve(root,"dist/blog/index.html"),"utf8"); +assert.match(blog, /<a href="\/pricing">Pricing<\/a>/); +assert.match(blog, /No posts yet/); +console.log("Passed: validated prices/limits, safe rejection of invalid catalogs, pricing route, separate policy link, and empty blog preserved."); diff --git a/aside-react/scripts/prerender-blog.mjs b/aside-react/scripts/prerender-blog.mjs new file mode 100644 index 00000000..866d4a61 --- /dev/null +++ b/aside-react/scripts/prerender-blog.mjs @@ -0,0 +1,44 @@ +import { createServer, loadEnv } from "vite"; +import { readFile, writeFile, mkdir, mkdtemp, rm } from "node:fs/promises"; +import { fileURLToPath } from "node:url"; +import { dirname, resolve } from "node:path"; +import { tmpdir } from "node:os"; + +const root = resolve(dirname(fileURLToPath(import.meta.url)), ".."); +const env = loadEnv("production", root, "VITE_"); +const origin = (process.env.VITE_SITE_URL || env.VITE_SITE_URL || "https://recordly-beta-landing.youngchen3442.workers.dev").replace(/\/+$/, ""); +const parsedOrigin = new URL(origin); +if (!["https:", "http:"].includes(parsedOrigin.protocol) || parsedOrigin.origin !== origin) throw new Error("VITE_SITE_URL must be an absolute http(s) origin without a path."); +const cacheDir = await mkdtemp(resolve(tmpdir(), "recordly-blog-prerender-")); +const server = await createServer({root, cacheDir, mode:"production", server:{middlewareMode:true}, appType:"custom", optimizeDeps:{noDiscovery:true}}); +const escapeHtml = (value) => String(value).replace(/[&<>"']/g, (char) => ({"&":"&", "<":"<", ">":">", '"':""", "'":"'"}[char])); +const metaTag = (kind, name, content) => `<meta ${kind}="${name}" content="${escapeHtml(content)}">`; +try { + const {blogPaths, renderBlog} = await server.ssrLoadModule("/src/blog/render.jsx"); + const template = await readFile(resolve(root, "dist/index.html"), "utf8"); + if (!template.includes('<div id="root"></div>')) throw new Error("Built HTML is missing the expected React root."); + for (const path of blogPaths) { + const {body, meta} = renderBlog(path, origin); + const tags = [ + metaTag("name", "description", meta.description), metaTag("name", "robots", meta.robots), + `<link rel="canonical" href="${escapeHtml(meta.canonical)}">`, + ...Object.entries({"og:title":meta.title, "og:description":meta.description, "og:type":meta.post ? "article" : "website", "og:url":meta.canonical, "og:image":meta.image, "og:image:width":meta.image ? "1200" : null, "og:image:height":meta.image ? "630" : null, "og:site_name":"Recordly"}).filter(([,value]) => value).map(([key,value]) => metaTag("property", key, value)), + ...Object.entries({"twitter:card":meta.image ? "summary_large_image" : "summary", "twitter:title":meta.title, "twitter:description":meta.description, "twitter:image":meta.image}).filter(([,value]) => value).map(([key,value]) => metaTag("name", key, value)), + ...(meta.post ? [metaTag("property", "article:published_time", meta.post.datePublished), metaTag("property", "article:modified_time", meta.post.dateModified)] : []), + `<script type="application/ld+json" data-blog-schema>${JSON.stringify(meta.structuredData).replace(/</g, "\\u003c")}</script>` + ].join("\n"); + const html = template.replace(/<title>[^<]*<\/title>/, `<title>${escapeHtml(meta.title)}`) + .replace(/]*>/, "") + .replace("", `${tags}\n`) + .replace('
', `
${body}
`); + const folder = resolve(root, "dist", path.slice(1)); + await mkdir(folder, {recursive:true}); + await writeFile(resolve(folder, "index.html"), html); + } + const entries = ["/", ...blogPaths].map((path) => `${escapeHtml(`${origin}${path}`)}`).join("\n"); + await writeFile(resolve(root, "dist/sitemap.xml"), `\n${entries}\n`); + console.log(`Prerendered ${blogPaths.length} blog pages with metadata, article content, and sitemap.`); +} finally { + await server.close(); + await rm(cacheDir, {recursive:true, force:true}); +} diff --git a/aside-react/src/ActionWord.jsx b/aside-react/src/ActionWord.jsx new file mode 100644 index 00000000..b9b5cc99 --- /dev/null +++ b/aside-react/src/ActionWord.jsx @@ -0,0 +1,12 @@ +import React from "react"; + +const actionEmojis = { capture: "🎥", edit: "✂️", share: "📤" }; + +export default function ActionWord({ action, children }) { + return ( + + + {children} + + ); +} diff --git a/aside-react/src/BentoArtwork.jsx b/aside-react/src/BentoArtwork.jsx new file mode 100644 index 00000000..26a1dd6e --- /dev/null +++ b/aside-react/src/BentoArtwork.jsx @@ -0,0 +1,16 @@ +import React from "react"; +import SharingIllustration from "./SharingIllustration"; +import { WebcamIllustration, CaptionsIllustration, ExportIllustration, CloudIllustration } from "./FeatureIllustrations"; + +const illustrations = { + webcam: WebcamIllustration, + captions: CaptionsIllustration, + export: ExportIllustration, + sharing: SharingIllustration, + cloud: CloudIllustration, +}; + +export default function BentoArtwork({ feature }) { + const Illustration = illustrations[feature]; + return Illustration ? : null; +} diff --git a/aside-react/src/DemoVideo.jsx b/aside-react/src/DemoVideo.jsx new file mode 100644 index 00000000..d399acfd --- /dev/null +++ b/aside-react/src/DemoVideo.jsx @@ -0,0 +1,56 @@ +import React, { useEffect, useRef } from "react"; + +export default function DemoVideo({ src, poster, label, className, width = 1920, height = 1198, enabled = true, controls = true, onPlaybackFrame }) { + const videoRef = useRef(null); + // biome-ignore lint/correctness/useExhaustiveDependencies: a new source needs a fresh playback-frame subscription. + useEffect(() => { + if (!onPlaybackFrame) return; + const video = videoRef.current; + let frame; + const sync = () => onPlaybackFrame(video.currentTime, video.duration); + const stop = () => { + cancelAnimationFrame(frame); + sync(); + }; + const tick = () => { + sync(); + if (!video.paused && !video.ended) frame = requestAnimationFrame(tick); + }; + const start = () => { cancelAnimationFrame(frame); tick(); }; + const events = { play: start, pause: stop, ended: stop, loadedmetadata: sync, durationchange: sync, seeked: sync }; + for (const [event, handler] of Object.entries(events)) video.addEventListener(event, handler); + start(); + return () => { + cancelAnimationFrame(frame); + for (const [event, handler] of Object.entries(events)) video.removeEventListener(event, handler); + }; + }, [src, onPlaybackFrame]); + // biome-ignore lint/correctness/useExhaustiveDependencies: re-evaluate visibility playback when the video source changes. + useEffect(() => { + const video = videoRef.current; + const reducedMotion = window.matchMedia("(prefers-reduced-motion: reduce)"); + let inView = false; + const updatePlayback = () => { + if (!enabled || !inView || document.hidden || reducedMotion.matches) video.pause(); + else video.play().catch(() => { + // Autoplay may be blocked; the video controls still allow manual playback. + }); + }; + const observer = new IntersectionObserver(([entry]) => { + inView = entry.isIntersecting && entry.intersectionRatio >= .1; + updatePlayback(); + }, { threshold: .1 }); + observer.observe(video); + reducedMotion.addEventListener("change", updatePlayback); + document.addEventListener("visibilitychange", updatePlayback); + return () => { + observer.disconnect(); + reducedMotion.removeEventListener("change", updatePlayback); + document.removeEventListener("visibilitychange", updatePlayback); + }; + }, [src, enabled]); + return
Watch {label} + ; +} diff --git a/aside-react/src/FeatureArtwork.jsx b/aside-react/src/FeatureArtwork.jsx new file mode 100644 index 00000000..e3e05841 --- /dev/null +++ b/aside-react/src/FeatureArtwork.jsx @@ -0,0 +1,29 @@ +import React from "react"; +import ShareArtwork from "./ShareArtwork"; +import DemoVideo from "./DemoVideo"; + +export default function FeatureArtwork({ feature, active = true }) { + if (feature === "Automatic zooms" || feature === "Smooth cursor") { + const name = feature === "Automatic zooms" ? "auto-zoom" : "cursor"; + return
+ +
; + } + if (feature === "Record") return ( +
+ Recordly recording controls over a coastal desktop background +
+ ); + if (feature === "Preview") return ( +
+ Recordly video editor with background controls, video preview and zoom timeline +
+ ); + if (feature === "Share" || feature === "Share anywhere") return ( +
+ +
+ ); + return