diff --git a/.eslintrc.cjs b/.eslintrc.cjs index 04fd19248..77a3369f7 100644 --- a/.eslintrc.cjs +++ b/.eslintrc.cjs @@ -1,30 +1,30 @@ module.exports = { - root: true, - extends: [ - "eslint:recommended", - "plugin:@typescript-eslint/recommended", - "plugin:svelte/recommended", - "prettier", - ], - parser: "@typescript-eslint/parser", - plugins: ["@typescript-eslint"], - parserOptions: { - sourceType: "module", - ecmaVersion: 2020, - extraFileExtensions: [".svelte"], - }, - env: { - browser: true, - es2017: true, - node: true, - }, - overrides: [ - { - files: ["*.svelte"], - parser: "svelte-eslint-parser", - parserOptions: { - parser: "@typescript-eslint/parser", - }, + root: true, + extends: [ + 'eslint:recommended', + 'plugin:@typescript-eslint/recommended', + 'plugin:svelte/recommended', + 'prettier' + ], + parser: '@typescript-eslint/parser', + plugins: ['@typescript-eslint'], + parserOptions: { + sourceType: 'module', + ecmaVersion: 2020, + extraFileExtensions: ['.svelte'] }, - ], + env: { + browser: true, + es2017: true, + node: true + }, + overrides: [ + { + files: ['*.svelte'], + parser: 'svelte-eslint-parser', + parserOptions: { + parser: '@typescript-eslint/parser' + } + } + ] }; diff --git a/.github/workflows/index.yml b/.github/workflows/index.yml index 2a33898cc..dab0a7b44 100644 --- a/.github/workflows/index.yml +++ b/.github/workflows/index.yml @@ -1,23 +1,23 @@ name: Search Index on: - push: - branches: - - main + push: + branches: + - main jobs: - indexing: - runs-on: ubuntu-latest - name: Indexing - steps: - - uses: actions/checkout@v4 - with: - repository: "meilisearch/scrapix" - - name: Use Node.js - uses: actions/setup-node@v3 - with: - node-version: "20.x" - - run: yarn - - run: yarn start -c "$SCRAPIX_CONFIG" - env: - SCRAPIX_CONFIG: ${{ secrets.SCRAPIX_CONFIG }} + indexing: + runs-on: ubuntu-latest + name: Indexing + steps: + - uses: actions/checkout@v4 + with: + repository: 'meilisearch/scrapix' + - name: Use Node.js + uses: actions/setup-node@v3 + with: + node-version: '20.x' + - run: yarn + - run: yarn start -c "$SCRAPIX_CONFIG" + env: + SCRAPIX_CONFIG: ${{ secrets.SCRAPIX_CONFIG }} diff --git a/.github/workflows/production.yml b/.github/workflows/production.yml index 687b5db00..cc4a93bd2 100644 --- a/.github/workflows/production.yml +++ b/.github/workflows/production.yml @@ -1,79 +1,79 @@ name: Production deployment on: - release: - types: [published] + release: + types: [published] env: - TAG: ${{ github.event.release.tag_name }} - STACK_FILE: docker/production.yml - REPOSITORY: website - REGISTRY_USERNAME: christyjacob4 + TAG: ${{ github.event.release.tag_name }} + STACK_FILE: docker/production.yml + REPOSITORY: website + REGISTRY_USERNAME: christyjacob4 jobs: - build: - runs-on: ubuntu-latest - steps: - - name: Checkout the repo - uses: actions/checkout@v2 + build: + runs-on: ubuntu-latest + steps: + - name: Checkout the repo + uses: actions/checkout@v2 - - name: Login to DockerHub - uses: docker/login-action@v1 - with: - registry: ghcr.io - username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} + - name: Login to DockerHub + uses: docker/login-action@v1 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} - - name: Build and push - uses: docker/build-push-action@v2 - with: - context: . - push: true - tags: ghcr.io/appwrite/website:${{ env.TAG }} - build-args: | - "PUBLIC_APPWRITE_ENDPOINT=${{ secrets.PUBLIC_APPWRITE_ENDPOINT }}" - "PUBLIC_APPWRITE_DASHBOARD=${{ secrets.PUBLIC_APPWRITE_DASHBOARD }}" - "PUBLIC_APPWRITE_PROJECT_ID=${{ vars.PUBLIC_APPWRITE_PROJECT_ID }}" - "PUBLIC_APPWRITE_DB_MAIN_ID=${{ vars.PUBLIC_APPWRITE_DB_MAIN_ID }}" - "PUBLIC_APPWRITE_COL_THREADS_ID=${{ vars.PUBLIC_APPWRITE_COL_THREADS_ID }}" - "PUBLIC_APPWRITE_COL_MESSAGES_ID=${{ vars.PUBLIC_APPWRITE_COL_MESSAGES_ID }}" - "PUBLIC_APPWRITE_FN_TLDR_ID=${{ vars.PUBLIC_APPWRITE_FN_TLDR_ID }}" - "PUBLIC_APPWRITE_PROJECT_INIT_ID=${{ vars.PUBLIC_APPWRITE_PROJECT_INIT_ID }}" - "PUBLIC_GROWTH_ENDPOINT=${{ vars.PUBLIC_GROWTH_ENDPOINT }}" - "APPWRITE_DB_INIT_ID=${{ secrets.APPWRITE_DB_INIT_ID }}" - "APPWRITE_COL_INIT_ID=${{ secrets.APPWRITE_COL_INIT_ID }}" - "APPWRITE_API_KEY_INIT=${{ secrets.APPWRITE_API_KEY_INIT }}" - "GITHUB_TOKEN=${{ secrets.GITHUB_TOKEN }}" - "SENTRY_AUTH_TOKEN=${{ secrets.SENTRY_AUTH_TOKEN }}" + - name: Build and push + uses: docker/build-push-action@v2 + with: + context: . + push: true + tags: ghcr.io/appwrite/website:${{ env.TAG }} + build-args: | + "PUBLIC_APPWRITE_ENDPOINT=${{ secrets.PUBLIC_APPWRITE_ENDPOINT }}" + "PUBLIC_APPWRITE_DASHBOARD=${{ secrets.PUBLIC_APPWRITE_DASHBOARD }}" + "PUBLIC_APPWRITE_PROJECT_ID=${{ vars.PUBLIC_APPWRITE_PROJECT_ID }}" + "PUBLIC_APPWRITE_DB_MAIN_ID=${{ vars.PUBLIC_APPWRITE_DB_MAIN_ID }}" + "PUBLIC_APPWRITE_COL_THREADS_ID=${{ vars.PUBLIC_APPWRITE_COL_THREADS_ID }}" + "PUBLIC_APPWRITE_COL_MESSAGES_ID=${{ vars.PUBLIC_APPWRITE_COL_MESSAGES_ID }}" + "PUBLIC_APPWRITE_FN_TLDR_ID=${{ vars.PUBLIC_APPWRITE_FN_TLDR_ID }}" + "PUBLIC_APPWRITE_PROJECT_INIT_ID=${{ vars.PUBLIC_APPWRITE_PROJECT_INIT_ID }}" + "PUBLIC_GROWTH_ENDPOINT=${{ vars.PUBLIC_GROWTH_ENDPOINT }}" + "APPWRITE_DB_INIT_ID=${{ secrets.APPWRITE_DB_INIT_ID }}" + "APPWRITE_COL_INIT_ID=${{ secrets.APPWRITE_COL_INIT_ID }}" + "APPWRITE_API_KEY_INIT=${{ secrets.APPWRITE_API_KEY_INIT }}" + "GITHUB_TOKEN=${{ secrets.GITHUB_TOKEN }}" + "SENTRY_AUTH_TOKEN=${{ secrets.SENTRY_AUTH_TOKEN }}" - deploy: - needs: build - runs-on: ubuntu-latest - steps: - - name: Execute SSH commands - uses: appleboy/ssh-action@master - with: - host: ${{ secrets.PRD_SSH_HOST }} - username: ${{ secrets.PRD_SSH_USERNAME }} - key: ${{ secrets.PRD_SSH_KEY }} - script: | - url="https://${{ github.actor }}:${{ secrets.GITHUB_TOKEN }}@github.com/appwrite/${{ env.REPOSITORY }}.git" - if ! git clone "${url}" "${{ env.REPOSITORY }}" 2>/dev/null && [ -d "${{ env.REPOSITORY }}" ] ; then - echo "Clone failed because the folder ${{ env.REPOSITORY }} exists" - fi + deploy: + needs: build + runs-on: ubuntu-latest + steps: + - name: Execute SSH commands + uses: appleboy/ssh-action@master + with: + host: ${{ secrets.PRD_SSH_HOST }} + username: ${{ secrets.PRD_SSH_USERNAME }} + key: ${{ secrets.PRD_SSH_KEY }} + script: | + url="https://${{ github.actor }}:${{ secrets.GITHUB_TOKEN }}@github.com/appwrite/${{ env.REPOSITORY }}.git" + if ! git clone "${url}" "${{ env.REPOSITORY }}" 2>/dev/null && [ -d "${{ env.REPOSITORY }}" ] ; then + echo "Clone failed because the folder ${{ env.REPOSITORY }} exists" + fi - cd ${{ env.REPOSITORY }} - git reset --hard HEAD - git remote set-url origin $url - git fetch origin - git checkout ${{ env.TAG }} + cd ${{ env.REPOSITORY }} + git reset --hard HEAD + git remote set-url origin $url + git fetch origin + git checkout ${{ env.TAG }} - rm -f .env - echo "_APP_VERSION=${{ env.TAG }}" >> .env - echo "_APP_DOMAIN=${{ secrets.PRD_APP_DOMAIN }}" >> .env - echo "_APP_SYSTEM_SECURITY_EMAIL_ADDRESS=${{ secrets.APP_SYSTEM_SECURITY_EMAIL_ADDRESS }}" >> .env - echo "SEMATEXT_TOKEN=${{ secrets.SEMATEXT_TOKEN }}" >> .env + rm -f .env + echo "_APP_VERSION=${{ env.TAG }}" >> .env + echo "_APP_DOMAIN=${{ secrets.PRD_APP_DOMAIN }}" >> .env + echo "_APP_SYSTEM_SECURITY_EMAIL_ADDRESS=${{ secrets.APP_SYSTEM_SECURITY_EMAIL_ADDRESS }}" >> .env + echo "SEMATEXT_TOKEN=${{ secrets.SEMATEXT_TOKEN }}" >> .env - echo ${{ secrets.GH_REGISTRY_TOKEN }} | docker login ghcr.io --username ${{ env.REGISTRY_USERNAME }} --password-stdin - docker-compose -f ${{ env.STACK_FILE }} config - env $(cat .env | xargs) docker stack deploy --prune --resolve-image always --with-registry-auth -c ${{ env.STACK_FILE }} ${{ env.REPOSITORY }} + echo ${{ secrets.GH_REGISTRY_TOKEN }} | docker login ghcr.io --username ${{ env.REGISTRY_USERNAME }} --password-stdin + docker-compose -f ${{ env.STACK_FILE }} config + env $(cat .env | xargs) docker stack deploy --prune --resolve-image always --with-registry-auth -c ${{ env.STACK_FILE }} ${{ env.REPOSITORY }} diff --git a/.github/workflows/staging.yml b/.github/workflows/staging.yml index b51cb7a48..babdbaeb4 100644 --- a/.github/workflows/staging.yml +++ b/.github/workflows/staging.yml @@ -1,81 +1,81 @@ name: Staging deployment on: - workflow_dispatch: - push: - branches: - - main + workflow_dispatch: + push: + branches: + - main env: - TAG: ${{ github.sha }} - STACK_FILE: docker/stage.yml - REPOSITORY: website - REGISTRY_USERNAME: christyjacob4 + TAG: ${{ github.sha }} + STACK_FILE: docker/stage.yml + REPOSITORY: website + REGISTRY_USERNAME: christyjacob4 jobs: - build: - runs-on: ubuntu-latest - steps: - - name: Checkout the repo - uses: actions/checkout@v2 + build: + runs-on: ubuntu-latest + steps: + - name: Checkout the repo + uses: actions/checkout@v2 - - name: Login to DockerHub - uses: docker/login-action@v1 - with: - registry: ghcr.io - username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} + - name: Login to DockerHub + uses: docker/login-action@v1 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} - - name: Build and push - uses: docker/build-push-action@v2 - with: - context: . - push: true - tags: ghcr.io/appwrite/website:${{ env.TAG }} - build-args: | - "PUBLIC_APPWRITE_ENDPOINT=${{ secrets.PUBLIC_APPWRITE_ENDPOINT }}" - "PUBLIC_APPWRITE_DASHBOARD=${{ secrets.PUBLIC_APPWRITE_DASHBOARD }}" - "PUBLIC_APPWRITE_PROJECT_ID=${{ vars.PUBLIC_APPWRITE_PROJECT_ID }}" - "PUBLIC_APPWRITE_DB_MAIN_ID=${{ vars.PUBLIC_APPWRITE_DB_MAIN_ID }}" - "PUBLIC_APPWRITE_COL_THREADS_ID=${{ vars.PUBLIC_APPWRITE_COL_THREADS_ID }}" - "PUBLIC_APPWRITE_COL_MESSAGES_ID=${{ vars.PUBLIC_APPWRITE_COL_MESSAGES_ID }}" - "PUBLIC_APPWRITE_FN_TLDR_ID=${{ vars.PUBLIC_APPWRITE_FN_TLDR_ID }}" - "PUBLIC_APPWRITE_PROJECT_INIT_ID=${{ vars.PUBLIC_APPWRITE_PROJECT_INIT_ID }}" - "PUBLIC_GROWTH_ENDPOINT=${{ vars.PUBLIC_GROWTH_ENDPOINT }}" - "APPWRITE_DB_INIT_ID=${{ secrets.APPWRITE_DB_INIT_ID }}" - "APPWRITE_COL_INIT_ID=${{ secrets.APPWRITE_COL_INIT_ID }}" - "APPWRITE_API_KEY_INIT=${{ secrets.APPWRITE_API_KEY_INIT }}" - "GITHUB_TOKEN=${{ secrets.GITHUB_TOKEN }}" - "SENTRY_AUTH_TOKEN=${{ secrets.SENTRY_AUTH_TOKEN }}" + - name: Build and push + uses: docker/build-push-action@v2 + with: + context: . + push: true + tags: ghcr.io/appwrite/website:${{ env.TAG }} + build-args: | + "PUBLIC_APPWRITE_ENDPOINT=${{ secrets.PUBLIC_APPWRITE_ENDPOINT }}" + "PUBLIC_APPWRITE_DASHBOARD=${{ secrets.PUBLIC_APPWRITE_DASHBOARD }}" + "PUBLIC_APPWRITE_PROJECT_ID=${{ vars.PUBLIC_APPWRITE_PROJECT_ID }}" + "PUBLIC_APPWRITE_DB_MAIN_ID=${{ vars.PUBLIC_APPWRITE_DB_MAIN_ID }}" + "PUBLIC_APPWRITE_COL_THREADS_ID=${{ vars.PUBLIC_APPWRITE_COL_THREADS_ID }}" + "PUBLIC_APPWRITE_COL_MESSAGES_ID=${{ vars.PUBLIC_APPWRITE_COL_MESSAGES_ID }}" + "PUBLIC_APPWRITE_FN_TLDR_ID=${{ vars.PUBLIC_APPWRITE_FN_TLDR_ID }}" + "PUBLIC_APPWRITE_PROJECT_INIT_ID=${{ vars.PUBLIC_APPWRITE_PROJECT_INIT_ID }}" + "PUBLIC_GROWTH_ENDPOINT=${{ vars.PUBLIC_GROWTH_ENDPOINT }}" + "APPWRITE_DB_INIT_ID=${{ secrets.APPWRITE_DB_INIT_ID }}" + "APPWRITE_COL_INIT_ID=${{ secrets.APPWRITE_COL_INIT_ID }}" + "APPWRITE_API_KEY_INIT=${{ secrets.APPWRITE_API_KEY_INIT }}" + "GITHUB_TOKEN=${{ secrets.GITHUB_TOKEN }}" + "SENTRY_AUTH_TOKEN=${{ secrets.SENTRY_AUTH_TOKEN }}" - deploy: - needs: build - runs-on: ubuntu-latest - steps: - - name: Execute SSH commands - uses: appleboy/ssh-action@master - with: - host: ${{ secrets.STG_SSH_HOST }} - username: ${{ secrets.STG_SSH_USERNAME }} - key: ${{ secrets.STG_SSH_KEY }} - script: | - url="https://${{ github.actor }}:${{ secrets.GITHUB_TOKEN }}@github.com/appwrite/${{ env.REPOSITORY }}.git" - if ! git clone "${url}" "${{ env.REPOSITORY }}" 2>/dev/null && [ -d "${{ env.REPOSITORY }}" ] ; then - echo "Clone failed because the folder ${{ env.REPOSITORY }} exists" - fi + deploy: + needs: build + runs-on: ubuntu-latest + steps: + - name: Execute SSH commands + uses: appleboy/ssh-action@master + with: + host: ${{ secrets.STG_SSH_HOST }} + username: ${{ secrets.STG_SSH_USERNAME }} + key: ${{ secrets.STG_SSH_KEY }} + script: | + url="https://${{ github.actor }}:${{ secrets.GITHUB_TOKEN }}@github.com/appwrite/${{ env.REPOSITORY }}.git" + if ! git clone "${url}" "${{ env.REPOSITORY }}" 2>/dev/null && [ -d "${{ env.REPOSITORY }}" ] ; then + echo "Clone failed because the folder ${{ env.REPOSITORY }} exists" + fi - cd ${{ env.REPOSITORY }} - git reset --hard HEAD - git remote set-url origin $url - git fetch origin - git checkout ${{ env.TAG }} + cd ${{ env.REPOSITORY }} + git reset --hard HEAD + git remote set-url origin $url + git fetch origin + git checkout ${{ env.TAG }} - rm -f .env - echo "_APP_VERSION=${{ env.TAG }}" >> .env - echo "_APP_DOMAIN=${{ secrets.STG_APP_DOMAIN }}" >> .env - echo "_APP_SYSTEM_SECURITY_EMAIL_ADDRESS=${{ secrets.APP_SYSTEM_SECURITY_EMAIL_ADDRESS }}" >> .env - echo "SEMATEXT_TOKEN=${{ secrets.SEMATEXT_TOKEN }}" >> .env + rm -f .env + echo "_APP_VERSION=${{ env.TAG }}" >> .env + echo "_APP_DOMAIN=${{ secrets.STG_APP_DOMAIN }}" >> .env + echo "_APP_SYSTEM_SECURITY_EMAIL_ADDRESS=${{ secrets.APP_SYSTEM_SECURITY_EMAIL_ADDRESS }}" >> .env + echo "SEMATEXT_TOKEN=${{ secrets.SEMATEXT_TOKEN }}" >> .env - echo ${{ secrets.GH_REGISTRY_TOKEN }} | docker login ghcr.io --username ${{ env.REGISTRY_USERNAME }} --password-stdin - docker-compose -f ${{ env.STACK_FILE }} config - env $(cat .env | xargs) docker stack deploy --prune --resolve-image always --with-registry-auth -c ${{ env.STACK_FILE }} ${{ env.REPOSITORY }} + echo ${{ secrets.GH_REGISTRY_TOKEN }} | docker login ghcr.io --username ${{ env.REGISTRY_USERNAME }} --password-stdin + docker-compose -f ${{ env.STACK_FILE }} config + env $(cat .env | xargs) docker stack deploy --prune --resolve-image always --with-registry-auth -c ${{ env.STACK_FILE }} ${{ env.REPOSITORY }} diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index e69afd61a..d018dbf91 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -1,23 +1,23 @@ name: Mark stale issues on: - schedule: - - cron: "0 0 * * *" # Midnight Runtime + schedule: + - cron: '0 0 * * *' # Midnight Runtime jobs: - stale: - runs-on: ubuntu-latest + stale: + runs-on: ubuntu-latest - steps: - - uses: actions/stale@v9 - with: - repo-token: ${{ secrets.GITHUB_TOKEN }} - stale-issue-message: "This issue has been labeled as a 'question', indicating that it requires additional information from the requestor. It has been inactive for 7 days. If no further activity occurs, this issue will be closed in 14 days." - stale-issue-label: "stale" - days-before-stale: 7 - days-before-close: 14 - remove-stale-when-updated: true - close-issue-message: "This issue has been closed due to inactivity. If you still require assistance, please provide the requested information." - close-issue-reason: "not_planned" - operations-per-run: 100 - only-labels: "question" + steps: + - uses: actions/stale@v9 + with: + repo-token: ${{ secrets.GITHUB_TOKEN }} + stale-issue-message: "This issue has been labeled as a 'question', indicating that it requires additional information from the requestor. It has been inactive for 7 days. If no further activity occurs, this issue will be closed in 14 days." + stale-issue-label: 'stale' + days-before-stale: 7 + days-before-close: 14 + remove-stale-when-updated: true + close-issue-message: 'This issue has been closed due to inactivity. If you still require assistance, please provide the requested information.' + close-issue-reason: 'not_planned' + operations-per-run: 100 + only-labels: 'question' diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 214cb9613..2310a75db 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -1,50 +1,50 @@ name: Tests on: - pull_request_target: - branches: ["**"] + pull_request_target: + branches: ['**'] permissions: read-all jobs: - build: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - with: - ref: ${{ github.event.pull_request.head.sha }} - - name: Use Node.js - uses: actions/setup-node@v3 - with: - node-version: 20 - - name: Install pnpm - run: corepack enable - - name: Get pnpm store directory - shell: bash - run: | - echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + ref: ${{ github.event.pull_request.head.sha }} + - name: Use Node.js + uses: actions/setup-node@v3 + with: + node-version: 20 + - name: Install pnpm + run: corepack enable + - name: Get pnpm store directory + shell: bash + run: | + echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV - - uses: actions/cache@v3 - name: Setup pnpm cache - with: - path: ${{ env.STORE_PATH }} - key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} - restore-keys: | - ${{ runner.os }}-pnpm-store- - - name: Install dependencies - run: pnpm install --frozen-lockfile - - name: Build Website - env: - NODE_OPTIONS: "--max_old_space_size=8192" - PUBLIC_APPWRITE_PROJECT_ID: ${{ secrets.PUBLIC_APPWRITE_PROJECT_ID }} - PUBLIC_APPWRITE_DB_MAIN_ID: ${{ secrets.PUBLIC_APPWRITE_DB_MAIN_ID }} - PUBLIC_APPWRITE_COL_THREADS_ID: ${{ secrets.PUBLIC_APPWRITE_COL_THREADS_ID }} - PUBLIC_APPWRITE_COL_MESSAGES_ID: ${{ secrets.PUBLIC_APPWRITE_COL_MESSAGES_ID }} - PUBLIC_APPWRITE_FN_TLDR_ID: ${{ secrets.PUBLIC_APPWRITE_FN_TLDR_ID }} - PUBLIC_APPWRITE_PROJECT_INIT_ID: ${{ secrets.PUBLIC_APPWRITE_PROJECT_INIT_ID }} - PUBLIC_GROWTH_ENDPOINT: ${{ secrets.PUBLIC_GROWTH_ENDPOINT }} - APPWRITE_DB_INIT_ID: ${{ secrets.APPWRITE_DB_INIT_ID }} - APPWRITE_COL_INIT_ID: ${{ secrets.APPWRITE_COL_INIT_ID }} - APPWRITE_API_KEY_INIT: ${{ secrets.APPWRITE_API_KEY_INIT }} - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: pnpm run build + - uses: actions/cache@v3 + name: Setup pnpm cache + with: + path: ${{ env.STORE_PATH }} + key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} + restore-keys: | + ${{ runner.os }}-pnpm-store- + - name: Install dependencies + run: pnpm install --frozen-lockfile + - name: Build Website + env: + NODE_OPTIONS: '--max_old_space_size=8192' + PUBLIC_APPWRITE_PROJECT_ID: ${{ secrets.PUBLIC_APPWRITE_PROJECT_ID }} + PUBLIC_APPWRITE_DB_MAIN_ID: ${{ secrets.PUBLIC_APPWRITE_DB_MAIN_ID }} + PUBLIC_APPWRITE_COL_THREADS_ID: ${{ secrets.PUBLIC_APPWRITE_COL_THREADS_ID }} + PUBLIC_APPWRITE_COL_MESSAGES_ID: ${{ secrets.PUBLIC_APPWRITE_COL_MESSAGES_ID }} + PUBLIC_APPWRITE_FN_TLDR_ID: ${{ secrets.PUBLIC_APPWRITE_FN_TLDR_ID }} + PUBLIC_APPWRITE_PROJECT_INIT_ID: ${{ secrets.PUBLIC_APPWRITE_PROJECT_INIT_ID }} + PUBLIC_GROWTH_ENDPOINT: ${{ secrets.PUBLIC_GROWTH_ENDPOINT }} + APPWRITE_DB_INIT_ID: ${{ secrets.APPWRITE_DB_INIT_ID }} + APPWRITE_COL_INIT_ID: ${{ secrets.APPWRITE_COL_INIT_ID }} + APPWRITE_API_KEY_INIT: ${{ secrets.APPWRITE_API_KEY_INIT }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: pnpm run build diff --git a/.gitpod.yml b/.gitpod.yml index da7ef5e86..ae5811d62 100644 --- a/.gitpod.yml +++ b/.gitpod.yml @@ -5,5 +5,5 @@ # Learn more from ready-to-use templates: https://www.gitpod.io/docs/introduction/getting-started/quickstart tasks: - - init: pnpm install && pnpm run build - command: pnpm run dev + - init: pnpm install && pnpm run build + command: pnpm run dev diff --git a/.prettierrc b/.prettierrc index c45a0a8ea..d657bce4d 100644 --- a/.prettierrc +++ b/.prettierrc @@ -1,10 +1,10 @@ { - "useTabs": false, - "tabWidth": 4, - "singleQuote": true, - "trailingComma": "none", - "printWidth": 100, - "plugins": ["prettier-plugin-tailwindcss", "prettier-plugin-svelte"], - "pluginSearchDirs": ["."], - "overrides": [{ "files": "*.svelte", "options": { "parser": "svelte" } }] + "useTabs": false, + "tabWidth": 4, + "singleQuote": true, + "trailingComma": "none", + "printWidth": 100, + "plugins": ["prettier-plugin-tailwindcss", "prettier-plugin-svelte"], + "pluginSearchDirs": ["."], + "overrides": [{ "files": "*.svelte", "options": { "parser": "svelte" } }] } diff --git a/CONTENT.md b/CONTENT.md index 11f382e21..6dd40a505 100644 --- a/CONTENT.md +++ b/CONTENT.md @@ -49,9 +49,9 @@ Create ordered (numbered) and unordered (bulleted) lists using 1., \*, or -. **Unordered List**: ```md -- Apple -- Banana -- Cherry +- Apple +- Banana +- Cherry ``` #### Links @@ -130,19 +130,19 @@ Alternatively, use markdoc tables. ```md {% table %} -- Heading 1 -- Heading 2 +- Heading 1 +- Heading 2 --- -- Row 1 Cell 1 -- Row 1 Cell 2 +- Row 1 Cell 1 +- Row 1 Cell 2 --- -- Row 2 Cell 1 -- Row 2 cell 2 - {% /table %} +- Row 2 Cell 1 +- Row 2 cell 2 + {% /table %} ``` #### Block Quotes diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index bda5fee9d..db89ef5c1 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -60,11 +60,11 @@ doc-548-submit-a-pull-request-section-to-contribution-guide When `TYPE` can be: -- **feat** - is a new feature -- **doc** - documentation only changes -- **cicd** - changes related to CI/CD system -- **fix** - a bug fix -- **refactor** - code change that neither fixes a bug nor adds a feature +- **feat** - is a new feature +- **doc** - documentation only changes +- **cicd** - changes related to CI/CD system +- **fix** - a bug fix +- **refactor** - code change that neither fixes a bug nor adds a feature **All PRs must include a commit message with a description of the changes made!** diff --git a/README.md b/README.md index b037b5769..cff29e035 100644 --- a/README.md +++ b/README.md @@ -10,8 +10,8 @@ The Appwrite Website repo features the main Appwrite website, including our [hom The Appwrite Website has been built with the following frameworks: -- [Svelte](https://svelte.dev/) -- [SvelteKit](https://kit.svelte.dev/) +- [Svelte](https://svelte.dev/) +- [SvelteKit](https://kit.svelte.dev/) ## Development diff --git a/STYLE.md b/STYLE.md index dc3214379..aefa0047e 100644 --- a/STYLE.md +++ b/STYLE.md @@ -6,17 +6,17 @@ Read this document carefully before making PRs to the Appwrite Website repo. The Appwrite documentation is meant to provide general guidance that's: -- Unopinionated -- Focused on the correct use of Appwrite product -- Includes examples for all relevant and applicable SDKs -- Agnostic to the user's implementation and stack. +- Unopinionated +- Focused on the correct use of Appwrite product +- Includes examples for all relevant and applicable SDKs +- Agnostic to the user's implementation and stack. Examples of things not fit for docs, and better as a blog or video: -- General programming advice -- Opinionated implementation patterns like MVVM, factory methods, etc. -- Examples that only include a select subset of Appwrite SDKs. -- Examples that do not work for all developers using Appwrite, but specific to Appwrite + technology. +- General programming advice +- Opinionated implementation patterns like MVVM, factory methods, etc. +- Examples that only include a select subset of Appwrite SDKs. +- Examples that do not work for all developers using Appwrite, but specific to Appwrite + technology. Note that the tutorials and blogs available on the Appwrite blog and docs are meant for these types of information. @@ -28,39 +28,39 @@ Appwrite's navigation increases in complexity from top down. We expect users to Introduction Section: -- [Homes](https://appwrite.io/docs) -- [Quick start](https://appwrite.io/docs/quick-start) -- [Tutorial](https://appwrite.io/docs/tutorial) -- [SDKs](https://appwrite.io/docs/sdks) -- [API references](https://appwrite.io/docs/references) +- [Homes](https://appwrite.io/docs) +- [Quick start](https://appwrite.io/docs/quick-start) +- [Tutorial](https://appwrite.io/docs/tutorial) +- [SDKs](https://appwrite.io/docs/sdks) +- [API references](https://appwrite.io/docs/references) Products section: -- [Auth](https://appwrite.io/docs/products/auth) -- [Databases](https://appwrite.io/docs/products/databases) -- [Functions](https://appwrite.io/docs/products/functions) -- [Storage](https://appwrite.io/docs/products/storage) -- [Messaging](https://appwrite.io/docs/products/messaging) -- [AI](https://appwrite.io/docs/products/ai) +- [Auth](https://appwrite.io/docs/products/auth) +- [Databases](https://appwrite.io/docs/products/databases) +- [Functions](https://appwrite.io/docs/products/functions) +- [Storage](https://appwrite.io/docs/products/storage) +- [Messaging](https://appwrite.io/docs/products/messaging) +- [AI](https://appwrite.io/docs/products/ai) APIs section: -- [GraphQL](https://appwrite.io/docs/apis/graphql) -- [REST](https://appwrite.io/docs/apis/rest) -- [Realtime](https://appwrite.io/docs/apis/realtime) +- [GraphQL](https://appwrite.io/docs/apis/graphql) +- [REST](https://appwrite.io/docs/apis/rest) +- [Realtime](https://appwrite.io/docs/apis/realtime) Tooling section: -- [CLI](https://appwrite.io/docs/command-line) -- [Command center](https://appwrite.io/docs/tooling/command-center) -- [Assistant](https://appwrite.io/docs/tooling/assistant) +- [CLI](https://appwrite.io/docs/command-line) +- [Command center](https://appwrite.io/docs/tooling/command-center) +- [Assistant](https://appwrite.io/docs/tooling/assistant) Advanced section: -- [Platform](https://appwrite.io/docs/advanced/platform) -- [Migrations](https://appwrite.io/docs/advanced/migrations) -- [Self-hosting](https://appwrite.io/docs/advanced/self-hosting) -- [Security](https://appwrite.io/docs/advanced/security) +- [Platform](https://appwrite.io/docs/advanced/platform) +- [Migrations](https://appwrite.io/docs/advanced/migrations) +- [Self-hosting](https://appwrite.io/docs/advanced/self-hosting) +- [Security](https://appwrite.io/docs/advanced/security) Here's the intended purpose and structure of each section. @@ -70,10 +70,10 @@ This section is focused on introducing what Appwrite is and giving examples to t Documentation here is focused on a **single flow** which means a single platform/framework + Appwrite. Content here is not specific to a specific product, but usually covers multiple Appwrite products. -- If your tutorial can be followed in about 15 minutes and fits on one page, write it under quick start -- If you're writing a long piece of documentation that integrates Appwrite with another technology, with lots of details that's opinionated or isn't relevant for all use cases, write it under tutorial. This is similar to "cook book" at other organizations. -- If you have information like helpers and methods that are only on SDKs but not the API, they go under SDK -- API references are generated from source from the appwrite/appwrite repo +- If your tutorial can be followed in about 15 minutes and fits on one page, write it under quick start +- If you're writing a long piece of documentation that integrates Appwrite with another technology, with lots of details that's opinionated or isn't relevant for all use cases, write it under tutorial. This is similar to "cook book" at other organizations. +- If you have information like helpers and methods that are only on SDKs but not the API, they go under SDK +- API references are generated from source from the appwrite/appwrite repo ### Products @@ -82,17 +82,17 @@ Code examples should cover **all available SDKs**. Each product page has three main sections -- Introduction - - Overview - Describes at a high level, why you might need this product - - Quick start - Shows the most basic and quickest example to make something happen with a product. Keep it really short. -- Concept - - These pages usually align with sections shown in the product in the Appwrite Console. - - Focused on describing concepts a user should know, but not actions you might take. - - Cover all the details -- Journeys - - These pages focus on common actions and work flows - - Detailed examples that span many concepts - - Like cookbook at other organizations' documentation. +- Introduction + - Overview - Describes at a high level, why you might need this product + - Quick start - Shows the most basic and quickest example to make something happen with a product. Keep it really short. +- Concept + - These pages usually align with sections shown in the product in the Appwrite Console. + - Focused on describing concepts a user should know, but not actions you might take. + - Cover all the details +- Journeys + - These pages focus on common actions and work flows + - Detailed examples that span many concepts + - Like cookbook at other organizations' documentation. ### APIs section @@ -106,10 +106,10 @@ Describes tools that help you work with Appwrite, but are usually non-essential For information that's not used commonly during the development cycle. -- Platform: covers concepts that apply to the entire Appwrite Cloud platform, like API keys, rate limits, etc. -- Migrations: covers migrations feature of Appwrite that helps you move data around. -- Security: purely information about measures Appwrite use to ensure security of the platform and data. -- Self-hosting: The Appwrite self-hosted platform is meant to behave identically to Cloud after being configured corrrectly. This section focuses on how to configure Appwrite self-hosted such that it behaves like Cloud. +- Platform: covers concepts that apply to the entire Appwrite Cloud platform, like API keys, rate limits, etc. +- Migrations: covers migrations feature of Appwrite that helps you move data around. +- Security: purely information about measures Appwrite use to ensure security of the platform and data. +- Self-hosting: The Appwrite self-hosted platform is meant to behave identically to Cloud after being configured corrrectly. This section focuses on how to configure Appwrite self-hosted such that it behaves like Cloud. ## Documentation sources @@ -117,22 +117,22 @@ The Appwrite docs are compiled from different repositories. Here are the signifi [appwrite/website](https://github.com/appwrite/website): -- Tutorials -- Quick starts -- Product, API, Tooling and Advanced sections +- Tutorials +- Quick starts +- Product, API, Tooling and Advanced sections [appwrite/appwrite](https://github.com/appwrite/appwrite): -- [API Reference](https://appwrite.io/docs/references) pages -- API specification -- API description -- API endpoint description -- API request parameters -- API response model +- [API Reference](https://appwrite.io/docs/references) pages +- API specification +- API description +- API endpoint description +- API request parameters +- API response model [appwrite/sdk-generator](https://github.com/appwrite/sdk-generator): -- Generated examples +- Generated examples ## Markdown Style guidelines @@ -141,10 +141,10 @@ the tone and voice remains consistent. ### Headings -- All titles, headings, buttons, and labels should be written in **sentence case**. If you're not sure what sentence case should look like, check [APA's style guide](https://apastyle.apa.org/style-grammar-guidelines/capitalization/sentence-case) or check with ChatGPT and other LLMs which reliably converts titles to sentence case. -- All headings in a docs page begin with `# Heading` then `## Heading` and `### Heading`. Internally, they're converted to H2 to H4 tags. -- All headings should have an ID label, for example `# Cool heading {% #cool-heading %}` the `#cool-heading` ID will be used to generate the table of contents and add links to the heading. -- Prefer verbs over gerunds, for example, say "Create documents" not "Creating documents". +- All titles, headings, buttons, and labels should be written in **sentence case**. If you're not sure what sentence case should look like, check [APA's style guide](https://apastyle.apa.org/style-grammar-guidelines/capitalization/sentence-case) or check with ChatGPT and other LLMs which reliably converts titles to sentence case. +- All headings in a docs page begin with `# Heading` then `## Heading` and `### Heading`. Internally, they're converted to H2 to H4 tags. +- All headings should have an ID label, for example `# Cool heading {% #cool-heading %}` the `#cool-heading` ID will be used to generate the table of contents and add links to the heading. +- Prefer verbs over gerunds, for example, say "Create documents" not "Creating documents". ### Extended Markdoc components @@ -152,14 +152,14 @@ Appwrite's documentation uses extended markdown syntax. You can find all of the ### Screenshots -- When contributing upload original screenshots. The Appwrite design team will edit the screenshot to be consistent with other screenshots in the docs. -- Screenshots must be 16:9 -- Screnshots should be taken in a 1400 x 900 view port on 3x DPR in browser developer tools. -- Use generic and sensible organization, project, and resource names. Avoid names like `test`, `demo`, or `sdlkfj`. -- All screenshot should be take from a user named Walter O'Brien. You can change the name of your current user by going to your Appwrite Console and clicking the **top right profile icon** > **Your Account** > **Name**. -- Screenshots are stored in the `/images/docs/` folder, in a parent folder that is consistent with the path of the docs that reference the image. -- All screenshots must be both dark and light mode, with `/path/` holding the lightmode version and `/path/dark/` holding the dark mode version. -- Screenshots should be uploaded as un-edited original. Request help from the Appwrite design team to help you edit and refine your photos according to our guidelines. +- When contributing upload original screenshots. The Appwrite design team will edit the screenshot to be consistent with other screenshots in the docs. +- Screenshots must be 16:9 +- Screnshots should be taken in a 1400 x 900 view port on 3x DPR in browser developer tools. +- Use generic and sensible organization, project, and resource names. Avoid names like `test`, `demo`, or `sdlkfj`. +- All screenshot should be take from a user named Walter O'Brien. You can change the name of your current user by going to your Appwrite Console and clicking the **top right profile icon** > **Your Account** > **Name**. +- Screenshots are stored in the `/images/docs/` folder, in a parent folder that is consistent with the path of the docs that reference the image. +- All screenshots must be both dark and light mode, with `/path/` holding the lightmode version and `/path/dark/` holding the dark mode version. +- Screenshots should be uploaded as un-edited original. Request help from the Appwrite design team to help you edit and refine your photos according to our guidelines. ```md {% only_dark %} @@ -210,41 +210,41 @@ Split content such that each piece makes sense without reading dependents or exp ### Release prep -- [ ] Add new version to [src/lib/utils/references.ts](src/lib/utils/references.ts) -- [ ] Point Cloud to new version in [src/routes/docs/references/[version]/[platform]/[service]/+page.server.ts](src/routes/docs/references/[version]/[platform]/[service]/+page.server.ts) -- [ ] Update install command in [/workspaces/website/src/routes/docs/advanced/self-hosting/+page.markdoc](/workspaces/website/src/routes/docs/advanced/self-hosting/+page.markdoc) -- [ ] Update events [src/partials/[product]-events.md](src/partials/) -- [ ] Update response code [src/routes/docs/advanced/platform/response-codes/+page.markdoc](src/routes/docs/advanced/platform/response-codes/+page.markdoc) -- [ ] Bump latest SDK versions in SDKs page, quick start, and tutorials -- [ ] Create new sections for new products -- [ ] Create new concept and journey pages for new features -- [ ] Update docs for breaking changes +- [ ] Add new version to [src/lib/utils/references.ts](src/lib/utils/references.ts) +- [ ] Point Cloud to new version in [src/routes/docs/references/[version]/[platform]/[service]/+page.server.ts](src/routes/docs/references/[version]/[platform]/[service]/+page.server.ts) +- [ ] Update install command in [/workspaces/website/src/routes/docs/advanced/self-hosting/+page.markdoc](/workspaces/website/src/routes/docs/advanced/self-hosting/+page.markdoc) +- [ ] Update events [src/partials/[product]-events.md](src/partials/) +- [ ] Update response code [src/routes/docs/advanced/platform/response-codes/+page.markdoc](src/routes/docs/advanced/platform/response-codes/+page.markdoc) +- [ ] Bump latest SDK versions in SDKs page, quick start, and tutorials +- [ ] Create new sections for new products +- [ ] Create new concept and journey pages for new features +- [ ] Update docs for breaking changes ### Documenting a new API -- Add a new .md file describing the new API here: -- Add descriptions for methods and parameters in the controller code: -- Check new response models have meaningful descriptions +- Add a new .md file describing the new API here: +- Add descriptions for methods and parameters in the controller code: +- Check new response models have meaningful descriptions ### Adding a new quickstart -- Copy a quick start from the [src/routes/docs/quick-starts](src/routes/docs/quick-starts) folder. -- Add a new entry and logo to [src/routes/docs/quick-starts/+page.svelte](src/routes/docs/quick-starts/+page.svelte) -- If you need a new logo, contact the Appwrite team to add one to Pink design. -- Update the content of your tutorial. Remember to update the front matter! -- Try to be consistent in both the quickstart's content and format when compared to existing quick starts -- Add the quick start to the footer and front page of Appwrite -- Use sections for steps on your page +- Copy a quick start from the [src/routes/docs/quick-starts](src/routes/docs/quick-starts) folder. +- Add a new entry and logo to [src/routes/docs/quick-starts/+page.svelte](src/routes/docs/quick-starts/+page.svelte) +- If you need a new logo, contact the Appwrite team to add one to Pink design. +- Update the content of your tutorial. Remember to update the front matter! +- Try to be consistent in both the quickstart's content and format when compared to existing quick starts +- Add the quick start to the footer and front page of Appwrite +- Use sections for steps on your page ### Adding a new tutorial -- Copy a tutorial from the [src/routes/docs/tutorials](src/routes/docs/tutorials) folder. -- Update the `+page.ts`'s redirect, for example, the Android tutorial has this: [src/routes/docs/tutorials/android/+page.ts](src/routes/docs/tutorials/android/+page.ts) -- Update [src/routes/docs/tutorials/+page.svelte](src/routes/docs/tutorials/+page.svelte) and add your new tutorial -- Update [src/routes/docs/tutorials/android/+layout.ts](src/routes/docs/tutorials/android/+layout.ts) and add your new tutorial -- Add the content of your tutorial. Keep pages short, separated by a different distinct feature for each step. -- If you need a new logo, contact the Appwrite team to add one to Pink design. -- Add the tutorial to the footer and front page of Appwrite +- Copy a tutorial from the [src/routes/docs/tutorials](src/routes/docs/tutorials) folder. +- Update the `+page.ts`'s redirect, for example, the Android tutorial has this: [src/routes/docs/tutorials/android/+page.ts](src/routes/docs/tutorials/android/+page.ts) +- Update [src/routes/docs/tutorials/+page.svelte](src/routes/docs/tutorials/+page.svelte) and add your new tutorial +- Update [src/routes/docs/tutorials/android/+layout.ts](src/routes/docs/tutorials/android/+layout.ts) and add your new tutorial +- Add the content of your tutorial. Keep pages short, separated by a different distinct feature for each step. +- If you need a new logo, contact the Appwrite team to add one to Pink design. +- Add the tutorial to the footer and front page of Appwrite ## Language and diction diff --git a/docker-compose.yml b/docker-compose.yml index ed7508e36..e03cab6fa 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,60 +1,60 @@ services: - traefik: - image: traefik:2.9 - command: - - --log.level=DEBUG - - --api.insecure=true - - --providers.docker=true - - --providers.docker.exposedByDefault=false - - --entrypoints.web.address=:80 - - --entrypoints.websecure.address=:443 - - --providers.docker.constraints=Label(`traefik.constraint-label-stack`,`homepage`) - - --accesslog=true - labels: - - traefik.http.routers.traefik.middlewares=traefik-compress - - traefik.http.middlewares.traefik-compress.compress=true - ports: - - 80:80 - - 8080:8080 - volumes: - # - /letsencrypt:/letsencrypt - - /var/run/docker.sock:/var/run/docker.sock - networks: - - homepage + traefik: + image: traefik:2.9 + command: + - --log.level=DEBUG + - --api.insecure=true + - --providers.docker=true + - --providers.docker.exposedByDefault=false + - --entrypoints.web.address=:80 + - --entrypoints.websecure.address=:443 + - --providers.docker.constraints=Label(`traefik.constraint-label-stack`,`homepage`) + - --accesslog=true + labels: + - traefik.http.routers.traefik.middlewares=traefik-compress + - traefik.http.middlewares.traefik-compress.compress=true + ports: + - 80:80 + - 8080:8080 + volumes: + # - /letsencrypt:/letsencrypt + - /var/run/docker.sock:/var/run/docker.sock + networks: + - homepage - homepage: - image: homepage-dev - build: - context: . - args: - - PUBLIC_APPWRITE_ENDPOINT=$PUBLIC_APPWRITE_ENDPOINT - - PUBLIC_APPWRITE_DASHBOARD=$PUBLIC_APPWRITE_DASHBOARD - - PUBLIC_APPWRITE_PROJECT_INIT_ID=$PUBLIC_APPWRITE_PROJECT_INIT_ID - - PUBLIC_APPWRITE_PROJECT_ID=$PUBLIC_APPWRITE_PROJECT_ID - - PUBLIC_APPWRITE_DB_MAIN_ID=$PUBLIC_APPWRITE_DB_MAIN_ID - - PUBLIC_APPWRITE_COL_THREADS_ID=$PUBLIC_APPWRITE_COL_THREADS_ID - - PUBLIC_APPWRITE_COL_MESSAGES_ID=$PUBLIC_APPWRITE_COL_MESSAGES_ID - - PUBLIC_APPWRITE_FN_TLDR_ID=$PUBLIC_APPWRITE_FN_TLDR_ID - restart: always - networks: - - homepage - labels: - - traefik.enable=true - - traefik.constraint-label-stack=homepage - - traefik.docker.network=appwrite - - traefik.http.middlewares.appwrite_middlewares.compress=true - - traefik.http.services.appwrite_service.loadbalancer.server.port=3000 - #http - - traefik.http.routers.appwrite.entrypoints=web - - traefik.http.routers.appwrite.rule=PathPrefix(`/`) - - traefik.http.routers.appwrite.service=appwrite_service - - traefik.http.routers.appwrite.middlewares=appwrite_middlewares - # https - - traefik.http.routers.appwrite_secure.entrypoints=websecure - - traefik.http.routers.appwrite_secure.rule=PathPrefix(`/`) - - traefik.http.routers.appwrite_secure.service=appwrite_service - - traefik.http.routers.appwrite_secure.tls=true - - traefik.http.routers.appwrite_secure.middlewares=appwrite_middlewares + homepage: + image: homepage-dev + build: + context: . + args: + - PUBLIC_APPWRITE_ENDPOINT=$PUBLIC_APPWRITE_ENDPOINT + - PUBLIC_APPWRITE_DASHBOARD=$PUBLIC_APPWRITE_DASHBOARD + - PUBLIC_APPWRITE_PROJECT_INIT_ID=$PUBLIC_APPWRITE_PROJECT_INIT_ID + - PUBLIC_APPWRITE_PROJECT_ID=$PUBLIC_APPWRITE_PROJECT_ID + - PUBLIC_APPWRITE_DB_MAIN_ID=$PUBLIC_APPWRITE_DB_MAIN_ID + - PUBLIC_APPWRITE_COL_THREADS_ID=$PUBLIC_APPWRITE_COL_THREADS_ID + - PUBLIC_APPWRITE_COL_MESSAGES_ID=$PUBLIC_APPWRITE_COL_MESSAGES_ID + - PUBLIC_APPWRITE_FN_TLDR_ID=$PUBLIC_APPWRITE_FN_TLDR_ID + restart: always + networks: + - homepage + labels: + - traefik.enable=true + - traefik.constraint-label-stack=homepage + - traefik.docker.network=appwrite + - traefik.http.middlewares.appwrite_middlewares.compress=true + - traefik.http.services.appwrite_service.loadbalancer.server.port=3000 + #http + - traefik.http.routers.appwrite.entrypoints=web + - traefik.http.routers.appwrite.rule=PathPrefix(`/`) + - traefik.http.routers.appwrite.service=appwrite_service + - traefik.http.routers.appwrite.middlewares=appwrite_middlewares + # https + - traefik.http.routers.appwrite_secure.entrypoints=websecure + - traefik.http.routers.appwrite_secure.rule=PathPrefix(`/`) + - traefik.http.routers.appwrite_secure.service=appwrite_service + - traefik.http.routers.appwrite_secure.tls=true + - traefik.http.routers.appwrite_secure.middlewares=appwrite_middlewares networks: - homepage: + homepage: diff --git a/docker/production.yml b/docker/production.yml index e60fa61ff..0668e0e7d 100644 --- a/docker/production.yml +++ b/docker/production.yml @@ -1,135 +1,135 @@ x-logging: &x-logging - logging: - driver: "json-file" - options: - max-file: "5" - max-size: "20m" + logging: + driver: 'json-file' + options: + max-file: '5' + max-size: '20m' x-update-config: &x-update-config - update_config: - order: stop-first - failure_action: rollback - parallelism: 1 - delay: 10s - rollback_config: - failure_action: pause - monitor: 5s - parallelism: 2 - order: stop-first + update_config: + order: stop-first + failure_action: rollback + parallelism: 1 + delay: 10s + rollback_config: + failure_action: pause + monitor: 5s + parallelism: 2 + order: stop-first -version: "3.8" +version: '3.8' services: - traefik: - image: traefik:2.9 - <<: *x-logging - command: - - --log.level=DEBUG - - --api.insecure=false - - --providers.docker=true - - --providers.docker.watch=true - - --providers.docker.swarmMode=true - - --providers.docker.exposedByDefault=false - - --entrypoints.web.address=:80 - - --entrypoints.websecure.address=:443 - - --entrypoints.web.http.redirections.entrypoint.to=websecure - - --entrypoints.web.http.redirections.entrypoint.scheme=https - - --providers.docker.constraints=Label(`traefik.constraint-label-stack`,`appwrite`) - - --certificatesresolvers.myresolver.acme.httpchallenge=true - - --certificatesresolvers.myresolver.acme.httpchallenge.entrypoint=web - - --certificatesresolvers.myresolver.acme.email=$_APP_SYSTEM_SECURITY_EMAIL_ADDRESS - - --certificatesresolvers.myresolver.acme.storage=/letsencrypt/${_APP_DOMAIN}.json - - --accesslog=true - ports: - - 80:80 - - 443:443 - volumes: - - /letsencrypt:/letsencrypt - - /var/run/docker.sock:/var/run/docker.sock - networks: - - cloud - deploy: - replicas: 3 - <<: *x-update-config - placement: - max_replicas_per_node: 1 - constraints: - - node.role == manager - preferences: - - spread: node.role == worker - labels: - - traefik.http.routers.traefik.middlewares=traefik-compress - - traefik.http.middlewares.traefik-compress.compress=true + traefik: + image: traefik:2.9 + <<: *x-logging + command: + - --log.level=DEBUG + - --api.insecure=false + - --providers.docker=true + - --providers.docker.watch=true + - --providers.docker.swarmMode=true + - --providers.docker.exposedByDefault=false + - --entrypoints.web.address=:80 + - --entrypoints.websecure.address=:443 + - --entrypoints.web.http.redirections.entrypoint.to=websecure + - --entrypoints.web.http.redirections.entrypoint.scheme=https + - --providers.docker.constraints=Label(`traefik.constraint-label-stack`,`appwrite`) + - --certificatesresolvers.myresolver.acme.httpchallenge=true + - --certificatesresolvers.myresolver.acme.httpchallenge.entrypoint=web + - --certificatesresolvers.myresolver.acme.email=$_APP_SYSTEM_SECURITY_EMAIL_ADDRESS + - --certificatesresolvers.myresolver.acme.storage=/letsencrypt/${_APP_DOMAIN}.json + - --accesslog=true + ports: + - 80:80 + - 443:443 + volumes: + - /letsencrypt:/letsencrypt + - /var/run/docker.sock:/var/run/docker.sock + networks: + - cloud + deploy: + replicas: 3 + <<: *x-update-config + placement: + max_replicas_per_node: 1 + constraints: + - node.role == manager + preferences: + - spread: node.role == worker + labels: + - traefik.http.routers.traefik.middlewares=traefik-compress + - traefik.http.middlewares.traefik-compress.compress=true - server: - image: ghcr.io/appwrite/website:$_APP_VERSION - <<: *x-logging - networks: - - cloud - environment: - - PUBLIC_APPWRITE_PROJECT_INIT_ID - - PUBLIC_APPWRITE_PROJECT_ID - - PUBLIC_APPWRITE_DB_MAIN_ID - - PUBLIC_APPWRITE_COL_THREADS_ID - - PUBLIC_APPWRITE_COL_MESSAGES_ID - - PUBLIC_APPWRITE_FN_TLDR_ID - deploy: - <<: *x-update-config - mode: replicated - replicas: 8 - placement: - max_replicas_per_node: 2 - constraints: - - node.role == worker - preferences: - - spread: node.role == worker - labels: - - traefik.enable=true - - traefik.docker.lbswarm=true - - traefik.constraint-label-stack=appwrite - - traefik.http.services.appwrite_service.loadbalancer.server.port=3000 - - traefik.http.middlewares.appwrite_middlewares.compress=true - #http - - traefik.http.routers.appwrite.entrypoints=web - - traefik.http.routers.appwrite.rule=Host(`$_APP_DOMAIN`) || Host(`www.$_APP_DOMAIN`) - - traefik.http.routers.appwrite.service=appwrite_service - - traefik.http.routers.appwrite.middlewares=appwrite_middlewares - # https - - traefik.http.routers.appwrite_secure.entrypoints=websecure - - traefik.http.routers.appwrite_secure.rule=Host(`$_APP_DOMAIN`) || Host(`www.$_APP_DOMAIN`) - - traefik.http.routers.appwrite_secure.service=appwrite_service - - traefik.http.routers.appwrite_secure.tls=true - - traefik.http.routers.appwrite_secure.tls.certresolver=myresolver - - traefik.http.routers.appwrite_secure.middlewares=appwrite_middlewares + server: + image: ghcr.io/appwrite/website:$_APP_VERSION + <<: *x-logging + networks: + - cloud + environment: + - PUBLIC_APPWRITE_PROJECT_INIT_ID + - PUBLIC_APPWRITE_PROJECT_ID + - PUBLIC_APPWRITE_DB_MAIN_ID + - PUBLIC_APPWRITE_COL_THREADS_ID + - PUBLIC_APPWRITE_COL_MESSAGES_ID + - PUBLIC_APPWRITE_FN_TLDR_ID + deploy: + <<: *x-update-config + mode: replicated + replicas: 8 + placement: + max_replicas_per_node: 2 + constraints: + - node.role == worker + preferences: + - spread: node.role == worker + labels: + - traefik.enable=true + - traefik.docker.lbswarm=true + - traefik.constraint-label-stack=appwrite + - traefik.http.services.appwrite_service.loadbalancer.server.port=3000 + - traefik.http.middlewares.appwrite_middlewares.compress=true + #http + - traefik.http.routers.appwrite.entrypoints=web + - traefik.http.routers.appwrite.rule=Host(`$_APP_DOMAIN`) || Host(`www.$_APP_DOMAIN`) + - traefik.http.routers.appwrite.service=appwrite_service + - traefik.http.routers.appwrite.middlewares=appwrite_middlewares + # https + - traefik.http.routers.appwrite_secure.entrypoints=websecure + - traefik.http.routers.appwrite_secure.rule=Host(`$_APP_DOMAIN`) || Host(`www.$_APP_DOMAIN`) + - traefik.http.routers.appwrite_secure.service=appwrite_service + - traefik.http.routers.appwrite_secure.tls=true + - traefik.http.routers.appwrite_secure.tls.certresolver=myresolver + - traefik.http.routers.appwrite_secure.middlewares=appwrite_middlewares - janitor: - image: appwrite/docker-janitor - deploy: - mode: global - volumes: - - /var/run/docker.sock:/var/run/docker.sock - environment: - - TIME_BETWEEN_RUNS=3600 - - UNUSED_TIME=6h + janitor: + image: appwrite/docker-janitor + deploy: + mode: global + volumes: + - /var/run/docker.sock:/var/run/docker.sock + environment: + - TIME_BETWEEN_RUNS=3600 + - UNUSED_TIME=6h - sematext-agent: - image: sematext/agent:latest - environment: - REGION: EU - INFRA_TOKEN: $SEMATEXT_TOKEN - deploy: - mode: global - restart_policy: - condition: any - volumes: - - /:/hostfs:ro - - /etc/passwd:/etc/passwd:ro - - /etc/group:/etc/group:ro - - /sys:/host/sys:ro - - /dev:/hostfs/dev:ro - - /var/run:/var/run - - /sys/kernel/debug:/sys/kernel/debug + sematext-agent: + image: sematext/agent:latest + environment: + REGION: EU + INFRA_TOKEN: $SEMATEXT_TOKEN + deploy: + mode: global + restart_policy: + condition: any + volumes: + - /:/hostfs:ro + - /etc/passwd:/etc/passwd:ro + - /etc/group:/etc/group:ro + - /sys:/host/sys:ro + - /dev:/hostfs/dev:ro + - /var/run:/var/run + - /sys/kernel/debug:/sys/kernel/debug networks: - cloud: - driver: overlay + cloud: + driver: overlay diff --git a/docker/stage.yml b/docker/stage.yml index d2e0ba703..79f8a3c9a 100644 --- a/docker/stage.yml +++ b/docker/stage.yml @@ -1,137 +1,137 @@ x-logging: &x-logging - logging: - driver: "json-file" - options: - max-file: "5" - max-size: "20m" + logging: + driver: 'json-file' + options: + max-file: '5' + max-size: '20m' x-update-config: &x-update-config - update_config: - order: stop-first - failure_action: rollback - parallelism: 1 - delay: 10s - rollback_config: - failure_action: pause - monitor: 5s - parallelism: 2 - order: stop-first + update_config: + order: stop-first + failure_action: rollback + parallelism: 1 + delay: 10s + rollback_config: + failure_action: pause + monitor: 5s + parallelism: 2 + order: stop-first -version: "3.8" +version: '3.8' services: - traefik: - image: traefik:2.9 - <<: *x-logging - command: - - --log.level=DEBUG - - --api.insecure=true - - --providers.docker=true - - --providers.docker.watch=true - - --providers.docker.swarmMode=true - - --providers.docker.exposedByDefault=false - - --entrypoints.web.address=:80 - - --entrypoints.websecure.address=:443 - - --entrypoints.web.http.redirections.entrypoint.to=websecure - - --entrypoints.web.http.redirections.entrypoint.scheme=https - - --providers.docker.constraints=Label(`traefik.constraint-label-stack`,`appwrite`) - - --certificatesresolvers.myresolver.acme.httpchallenge=true - - --certificatesresolvers.myresolver.acme.httpchallenge.entrypoint=web - - --certificatesresolvers.myresolver.acme.email=$_APP_SYSTEM_SECURITY_EMAIL_ADDRESS - - --certificatesresolvers.myresolver.acme.storage=/letsencrypt/${_APP_DOMAIN}.json - - --accesslog=true - ports: - - 80:80 - - 443:443 - - 8080:8080 - volumes: - - /letsencrypt:/letsencrypt - - /var/run/docker.sock:/var/run/docker.sock - networks: - - cloud - deploy: - replicas: 3 - <<: *x-update-config - placement: - max_replicas_per_node: 1 - constraints: - - node.role == manager - preferences: - - spread: node.role == worker - labels: - - traefik.http.routers.traefik.middlewares=traefik-compress - - traefik.http.middlewares.traefik-compress.compress=true + traefik: + image: traefik:2.9 + <<: *x-logging + command: + - --log.level=DEBUG + - --api.insecure=true + - --providers.docker=true + - --providers.docker.watch=true + - --providers.docker.swarmMode=true + - --providers.docker.exposedByDefault=false + - --entrypoints.web.address=:80 + - --entrypoints.websecure.address=:443 + - --entrypoints.web.http.redirections.entrypoint.to=websecure + - --entrypoints.web.http.redirections.entrypoint.scheme=https + - --providers.docker.constraints=Label(`traefik.constraint-label-stack`,`appwrite`) + - --certificatesresolvers.myresolver.acme.httpchallenge=true + - --certificatesresolvers.myresolver.acme.httpchallenge.entrypoint=web + - --certificatesresolvers.myresolver.acme.email=$_APP_SYSTEM_SECURITY_EMAIL_ADDRESS + - --certificatesresolvers.myresolver.acme.storage=/letsencrypt/${_APP_DOMAIN}.json + - --accesslog=true + ports: + - 80:80 + - 443:443 + - 8080:8080 + volumes: + - /letsencrypt:/letsencrypt + - /var/run/docker.sock:/var/run/docker.sock + networks: + - cloud + deploy: + replicas: 3 + <<: *x-update-config + placement: + max_replicas_per_node: 1 + constraints: + - node.role == manager + preferences: + - spread: node.role == worker + labels: + - traefik.http.routers.traefik.middlewares=traefik-compress + - traefik.http.middlewares.traefik-compress.compress=true - server: - image: ghcr.io/appwrite/website:$_APP_VERSION - <<: *x-logging - networks: - - cloud - environment: - - PUBLIC_APPWRITE_PROJECT_INIT_ID - - PUBLIC_APPWRITE_PROJECT_ID - - PUBLIC_APPWRITE_DB_MAIN_ID - - PUBLIC_APPWRITE_COL_THREADS_ID - - PUBLIC_APPWRITE_COL_MESSAGES_ID - - PUBLIC_APPWRITE_FN_TLDR_ID - deploy: - <<: *x-update-config - mode: replicated - replicas: 8 - placement: - max_replicas_per_node: 2 - constraints: - - node.role == worker - preferences: - - spread: node.role == worker - labels: - - traefik.enable=true - - traefik.docker.lbswarm=true - - traefik.constraint-label-stack=appwrite - - traefik.http.services.appwrite_service.loadbalancer.server.port=3000 - - traefik.http.middlewares.appwrite_middlewares.compress=true - #http - - traefik.http.routers.appwrite.entrypoints=web - - traefik.http.routers.appwrite.rule=Host(`$_APP_DOMAIN`) || Host(`www.$_APP_DOMAIN`) - - traefik.http.routers.appwrite.service=appwrite_service - - traefik.http.routers.appwrite.middlewares=appwrite_middlewares - # https - - traefik.http.routers.appwrite_secure.entrypoints=websecure - - traefik.http.routers.appwrite_secure.rule=Host(`$_APP_DOMAIN`) || Host(`www.$_APP_DOMAIN`) - - traefik.http.routers.appwrite_secure.service=appwrite_service - - traefik.http.routers.appwrite_secure.tls=true - - traefik.http.routers.appwrite_secure.tls.certresolver=myresolver - - traefik.http.routers.appwrite_secure.middlewares=appwrite_middlewares + server: + image: ghcr.io/appwrite/website:$_APP_VERSION + <<: *x-logging + networks: + - cloud + environment: + - PUBLIC_APPWRITE_PROJECT_INIT_ID + - PUBLIC_APPWRITE_PROJECT_ID + - PUBLIC_APPWRITE_DB_MAIN_ID + - PUBLIC_APPWRITE_COL_THREADS_ID + - PUBLIC_APPWRITE_COL_MESSAGES_ID + - PUBLIC_APPWRITE_FN_TLDR_ID + deploy: + <<: *x-update-config + mode: replicated + replicas: 8 + placement: + max_replicas_per_node: 2 + constraints: + - node.role == worker + preferences: + - spread: node.role == worker + labels: + - traefik.enable=true + - traefik.docker.lbswarm=true + - traefik.constraint-label-stack=appwrite + - traefik.http.services.appwrite_service.loadbalancer.server.port=3000 + - traefik.http.middlewares.appwrite_middlewares.compress=true + #http + - traefik.http.routers.appwrite.entrypoints=web + - traefik.http.routers.appwrite.rule=Host(`$_APP_DOMAIN`) || Host(`www.$_APP_DOMAIN`) + - traefik.http.routers.appwrite.service=appwrite_service + - traefik.http.routers.appwrite.middlewares=appwrite_middlewares + # https + - traefik.http.routers.appwrite_secure.entrypoints=websecure + - traefik.http.routers.appwrite_secure.rule=Host(`$_APP_DOMAIN`) || Host(`www.$_APP_DOMAIN`) + - traefik.http.routers.appwrite_secure.service=appwrite_service + - traefik.http.routers.appwrite_secure.tls=true + - traefik.http.routers.appwrite_secure.tls.certresolver=myresolver + - traefik.http.routers.appwrite_secure.middlewares=appwrite_middlewares - janitor: - image: appwrite/docker-janitor - deploy: - mode: global - environment: - - TIME_BETWEEN_RUNS=600 - - UNUSED_TIME=10m - - RUN_ON_STARTUP=true - volumes: - - /var/run/docker.sock:/var/run/docker.sock + janitor: + image: appwrite/docker-janitor + deploy: + mode: global + environment: + - TIME_BETWEEN_RUNS=600 + - UNUSED_TIME=10m + - RUN_ON_STARTUP=true + volumes: + - /var/run/docker.sock:/var/run/docker.sock - sematext-agent: - image: sematext/agent:latest - environment: - REGION: EU - INFRA_TOKEN: $SEMATEXT_TOKEN - deploy: - mode: global - restart_policy: - condition: any - volumes: - - /:/hostfs:ro - - /etc/passwd:/etc/passwd:ro - - /etc/group:/etc/group:ro - - /sys:/host/sys:ro - - /dev:/hostfs/dev:ro - - /var/run:/var/run - - /sys/kernel/debug:/sys/kernel/debug + sematext-agent: + image: sematext/agent:latest + environment: + REGION: EU + INFRA_TOKEN: $SEMATEXT_TOKEN + deploy: + mode: global + restart_policy: + condition: any + volumes: + - /:/hostfs:ro + - /etc/passwd:/etc/passwd:ro + - /etc/group:/etc/group:ro + - /sys:/host/sys:ro + - /dev:/hostfs/dev:ro + - /var/run:/var/run + - /sys/kernel/debug:/sys/kernel/debug networks: - cloud: - driver: overlay + cloud: + driver: overlay diff --git a/markdoc.config.json b/markdoc.config.json index 32217b492..45be77be2 100644 --- a/markdoc.config.json +++ b/markdoc.config.json @@ -1,12 +1,12 @@ [ - { - "id": "appwrite", - "path": "src/", - "schema": { - "path": ".svelte-kit/markdoc_schema.js", - "type": "esm", - "property": "default", - "watch": true + { + "id": "appwrite", + "path": "src/", + "schema": { + "path": ".svelte-kit/markdoc_schema.js", + "type": "esm", + "property": "default", + "watch": true + } } - } ] diff --git a/package.json b/package.json index baa14dc90..1688658a6 100644 --- a/package.json +++ b/package.json @@ -1,94 +1,88 @@ { - "name": "appwrite-website", - "version": "0.0.1", - "private": true, - "type": "module", - "scripts": { - "build": "node ./scripts/build.js", - "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json", - "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch", - "clean": "rm -rf node_modules && rm -rf .svelte_kit && pnpm i", - "dev": "vite dev", - "download-contributors": "node ./scripts/download-contributor-data.js", - "format": "prettier --plugin-search-dir . --write .", - "icons:build": "node ./src/icons/build.js", - "icons:generate": "node ./src/icons/optimize.js && node ./src/icons/build.js", - "icons:optimize": "node ./src/icons/optimize.js", - "lint": "prettier --plugin-search-dir . --check . && eslint .", - "preview": "vite preview", - "test": "npm run test:integration && npm run test:unit", - "test:integration": "playwright test", - "test:unit": "vitest", - "optimize": "node ./scripts/optimize-assets.js" - }, - "packageManager": "pnpm@9.4.0+sha512.f549b8a52c9d2b8536762f99c0722205efc5af913e77835dbccc3b0b0b2ca9e7dc8022b78062c17291c48e88749c70ce88eb5a74f1fa8c4bf5e18bb46c8bd83a", - "dependencies": { - "@sentry/sveltekit": "^8.12.0", - "clsx": "^2.1.1", - "cva": "npm:class-variance-authority@^0.7.0", - "fuse.js": "^7.0.0", - "h3": "^1.12.0", - "sharp": "^0.33.4", - "tailwind-merge": "^2.4.0" - }, - "prettier": { - "plugins": [ - "prettier-plugin-svelte", - "prettier-plugin-tailwindcss" - ] - }, - "devDependencies": { - "@appwrite.io/console": "^0.6.2", - "@appwrite.io/pink": "~0.26.0", - "@appwrite.io/pink-icons": "~0.26.0", - "@appwrite.io/repo": "github:appwrite/appwrite#1.6.x", - "@internationalized/date": "3.5.0", - "@melt-ui/pp": "^0.3.2", - "@melt-ui/svelte": "^0.74.4", - "@playwright/test": "^1.44.1", - "@sveltejs/adapter-node": "^4.0.1", - "@sveltejs/enhanced-img": "^0.1.9", - "@sveltejs/kit": "^2.5.17", - "@sveltejs/vite-plugin-svelte": "^3.1.1", - "@tailwindcss/postcss": "4.0.0-alpha.17", - "@types/compression": "^1.7.5", - "@types/glob": "^8.1.0", - "@types/markdown-it": "^13.0.8", - "@types/morgan": "^1.9.9", - "@typescript-eslint/eslint-plugin": "^7.13.1", - "@typescript-eslint/parser": "^7.13.1", - "date-fns": "^3.6.0", - "dequal": "^2.0.3", - "embla-carousel": "^8.1.5", - "embla-carousel-svelte": "^8.1.5", - "embla-carousel-wheel-gestures": "^8.0.1", - "eslint": "^8.57.0", - "eslint-config-prettier": "^8.10.0", - "eslint-plugin-svelte": "^2.40.0", - "highlight.js": "^11.9.0", - "markdown-it": "^14.1.0", - "meilisearch": "^0.37.0", - "motion": "^10.18.0", - "node-html-parser": "^6.1.13", - "openapi-types": "^12.1.3", - "oslllo-svg-fixer": "^3.0.0", - "postcss": "^8.4.39", - "prettier": "^3.3.3", - "prettier-plugin-svelte": "^3.2.5", - "prettier-plugin-tailwindcss": "^0.6.5", - "remeda": "^2.10.0", - "sass": "^1.77.6", - "svelte": "^4.2.18", - "svelte-check": "^3.8.1", - "svelte-markdoc-preprocess": "^2.0.0", - "svelte-markdown": "^0.4.1", - "svgtofont": "^4.2.1", - "tailwindcss": "4.0.0-alpha.17", - "tslib": "^2.6.3", - "typescript": "^5.5.2", - "vite": "^5.3.1", - "vite-plugin-dynamic-import": "^1.5.0", - "vite-plugin-image-optimizer": "^1.1.8", - "vitest": "^1.6.0" - } + "name": "appwrite-website", + "version": "0.0.1", + "private": true, + "type": "module", + "scripts": { + "build": "node ./scripts/build.js", + "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json", + "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch", + "clean": "rm -rf node_modules && rm -rf .svelte_kit && pnpm i", + "dev": "vite dev", + "download-contributors": "node ./scripts/download-contributor-data.js", + "format": "prettier --plugin-search-dir . --write .", + "icons:build": "node ./src/icons/build.js", + "icons:generate": "node ./src/icons/optimize.js && node ./src/icons/build.js", + "icons:optimize": "node ./src/icons/optimize.js", + "lint": "prettier --plugin-search-dir . --check . && eslint .", + "preview": "vite preview", + "test": "npm run test:integration && npm run test:unit", + "test:integration": "playwright test", + "test:unit": "vitest", + "optimize": "node ./scripts/optimize-assets.js" + }, + "packageManager": "pnpm@9.4.0+sha512.f549b8a52c9d2b8536762f99c0722205efc5af913e77835dbccc3b0b0b2ca9e7dc8022b78062c17291c48e88749c70ce88eb5a74f1fa8c4bf5e18bb46c8bd83a", + "dependencies": { + "@sentry/sveltekit": "^8.12.0", + "clsx": "^2.1.1", + "cva": "npm:class-variance-authority@^0.7.0", + "fuse.js": "^7.0.0", + "h3": "^1.12.0", + "sharp": "^0.33.4", + "tailwind-merge": "^2.4.0" + }, + "devDependencies": { + "@appwrite.io/console": "^0.6.2", + "@appwrite.io/pink": "~0.26.0", + "@appwrite.io/pink-icons": "~0.26.0", + "@appwrite.io/repo": "github:appwrite/appwrite#1.6.x", + "@internationalized/date": "3.5.0", + "@melt-ui/pp": "^0.3.2", + "@melt-ui/svelte": "^0.74.4", + "@playwright/test": "^1.44.1", + "@sveltejs/adapter-node": "^4.0.1", + "@sveltejs/enhanced-img": "^0.1.9", + "@sveltejs/kit": "^2.5.17", + "@sveltejs/vite-plugin-svelte": "^3.1.1", + "@tailwindcss/postcss": "4.0.0-alpha.17", + "@types/compression": "^1.7.5", + "@types/glob": "^8.1.0", + "@types/markdown-it": "^13.0.8", + "@types/morgan": "^1.9.9", + "@typescript-eslint/eslint-plugin": "^7.13.1", + "@typescript-eslint/parser": "^7.13.1", + "date-fns": "^3.6.0", + "dequal": "^2.0.3", + "embla-carousel": "^8.1.5", + "embla-carousel-svelte": "^8.1.5", + "embla-carousel-wheel-gestures": "^8.0.1", + "eslint": "^8.57.0", + "eslint-config-prettier": "^8.10.0", + "eslint-plugin-svelte": "^2.40.0", + "highlight.js": "^11.9.0", + "markdown-it": "^14.1.0", + "meilisearch": "^0.37.0", + "motion": "^10.18.0", + "node-html-parser": "^6.1.13", + "openapi-types": "^12.1.3", + "oslllo-svg-fixer": "^3.0.0", + "postcss": "^8.4.39", + "prettier": "^3.3.3", + "prettier-plugin-svelte": "^3.2.5", + "prettier-plugin-tailwindcss": "^0.6.5", + "remeda": "^2.10.0", + "sass": "^1.77.6", + "svelte": "^4.2.18", + "svelte-check": "^3.8.1", + "svelte-markdoc-preprocess": "^2.0.0", + "svelte-markdown": "^0.4.1", + "svgtofont": "^4.2.1", + "tailwindcss": "4.0.0-alpha.17", + "tslib": "^2.6.3", + "typescript": "^5.5.2", + "vite": "^5.3.1", + "vite-plugin-dynamic-import": "^1.5.0", + "vite-plugin-image-optimizer": "^1.1.8", + "vitest": "^1.6.0" + } } diff --git a/playwright.config.ts b/playwright.config.ts index 92e6d0810..62187d0a9 100644 --- a/playwright.config.ts +++ b/playwright.config.ts @@ -1,12 +1,12 @@ -import type { PlaywrightTestConfig } from "@playwright/test"; +import type { PlaywrightTestConfig } from '@playwright/test'; const config: PlaywrightTestConfig = { - webServer: { - command: "npm run build && npm run preview", - port: 4173, - }, - testDir: "tests", - testMatch: /(.+\.)?(test|spec)\.[jt]s/, + webServer: { + command: 'npm run build && npm run preview', + port: 4173 + }, + testDir: 'tests', + testMatch: /(.+\.)?(test|spec)\.[jt]s/ }; export default config; diff --git a/postcss.config.js b/postcss.config.js index c2ddf7482..154df1f25 100644 --- a/postcss.config.js +++ b/postcss.config.js @@ -1,5 +1,5 @@ export default { - plugins: { - "@tailwindcss/postcss": {}, - }, + plugins: { + '@tailwindcss/postcss': {} + } }; diff --git a/scripts/build.js b/scripts/build.js index eeaa949e0..5141e582a 100644 --- a/scripts/build.js +++ b/scripts/build.js @@ -1,9 +1,9 @@ -import { build } from "vite"; -import { downloadContributors } from "./download-contributor-data.js"; +import { build } from 'vite'; +import { downloadContributors } from './download-contributor-data.js'; async function main() { - await downloadContributors(); - await build(); + await downloadContributors(); + await build(); } main(); diff --git a/scripts/download-contributor-data.js b/scripts/download-contributor-data.js index 1ed4e266a..649485bdc 100644 --- a/scripts/download-contributor-data.js +++ b/scripts/download-contributor-data.js @@ -1,108 +1,100 @@ -import fs from "fs"; +import fs from 'fs'; const perPage = 100; const outputFile = `./src/lib/contributors.ts`; const headers = process.env.GITHUB_TOKEN - ? { - Authorization: `token ${process.env.GITHUB_TOKEN}`, - } - : {}; + ? { + Authorization: `token ${process.env.GITHUB_TOKEN}` + } + : {}; console.log(`using github token: ${!!process.env.GITHUB_TOKEN}`); async function fetchRepositories() { - let page = 1; - let repositoriesData = []; - let hasMoreData = true; + let page = 1; + let repositoriesData = []; + let hasMoreData = true; - while (hasMoreData) { - console.log(`Fetching page ${page} of repositories...`); - const url = `https://api.github.com/orgs/appwrite/repos?page=${page}&per_page=${perPage}`; + while (hasMoreData) { + console.log(`Fetching page ${page} of repositories...`); + const url = `https://api.github.com/orgs/appwrite/repos?page=${page}&per_page=${perPage}`; - const response = await fetch(url, { - headers, - }); + const response = await fetch(url, { + headers + }); - if (!response.ok) { - console.error(`Failed to fetch data from ${url}`); - break; + if (!response.ok) { + console.error(`Failed to fetch data from ${url}`); + break; + } + + const data = await response.json(); + if (data.length === 0) { + hasMoreData = false; + } else { + repositoriesData = repositoriesData.concat(data); + page++; + } + console.log(`Fetched ${data.length} repositories. Total: ${repositoriesData.length}...\n`); } - const data = await response.json(); - if (data.length === 0) { - hasMoreData = false; - } else { - repositoriesData = repositoriesData.concat(data); - page++; - } - console.log( - `Fetched ${data.length} repositories. Total: ${repositoriesData.length}...\n`, - ); - } - - return repositoriesData.map((repo) => repo.full_name); + return repositoriesData.map((repo) => repo.full_name); } async function fetchContributors(apiUrl) { - let page = 1; - let contributorsData = []; - let hasMoreData = true; + let page = 1; + let contributorsData = []; + let hasMoreData = true; - while (hasMoreData) { - console.log(`Fetching page ${page} of contributors...`); - const url = `${apiUrl}?page=${page}&per_page=${perPage}`; - const response = await fetch(url, { - headers, - }); + while (hasMoreData) { + console.log(`Fetching page ${page} of contributors...`); + const url = `${apiUrl}?page=${page}&per_page=${perPage}`; + const response = await fetch(url, { + headers + }); - if (!response.ok) { - console.error(`Failed to fetch data from ${url}`, await response.text()); - break; + if (!response.ok) { + console.error(`Failed to fetch data from ${url}`, await response.text()); + break; + } + + const data = await response.json(); + + if (data.length === 0) { + hasMoreData = false; + } else { + contributorsData = contributorsData.concat(data.map((c) => c.login)); + page++; + } + + console.log(`Fetched ${data.length} contributors. Total: ${contributorsData.length}...\n`); } - const data = await response.json(); - - if (data.length === 0) { - hasMoreData = false; - } else { - contributorsData = contributorsData.concat(data.map((c) => c.login)); - page++; - } - - console.log( - `Fetched ${data.length} contributors. Total: ${contributorsData.length}...\n`, - ); - } - - return contributorsData; + return contributorsData; } export async function downloadContributors() { - const contributors = new Set(); + const contributors = new Set(); - for (const repo of [ - "appwrite/appwrite", - "appwrite/console", - "appwrite/sdk-generator", - ]) { - console.log(`Fetching contributors for ${repo}...`); - const url = `https://api.github.com/repos/${repo}/contributors`; - const data = await fetchContributors(url); + for (const repo of ['appwrite/appwrite', 'appwrite/console', 'appwrite/sdk-generator']) { + console.log(`Fetching contributors for ${repo}...`); + const url = `https://api.github.com/repos/${repo}/contributors`; + const data = await fetchContributors(url); - data.forEach((contributor) => contributors.add(contributor)); - } + data.forEach((contributor) => contributors.add(contributor)); + } - const contributorsArray = Array.from(contributors); - const contributorsString = JSON.stringify(contributorsArray, null, 4); - const contributorsFile = `export const contributors = ${contributorsString};`; + const contributorsArray = Array.from(contributors); + const contributorsString = JSON.stringify(contributorsArray, null, 4); + const contributorsFile = `export const contributors = ${contributorsString};`; - const currentContributors = fs.readFileSync(outputFile, "utf8"); - if (currentContributors.length >= contributorsFile.length) { - console.log("No new contributors found. Exiting..."); - return; - } + const currentContributors = fs.readFileSync(outputFile, 'utf8'); + if (currentContributors.length >= contributorsFile.length) { + console.log('No new contributors found. Exiting...'); + return; + } - fs.writeFileSync(outputFile, contributorsFile); + fs.writeFileSync(outputFile, contributorsFile); } diff --git a/scripts/optimize-assets.js b/scripts/optimize-assets.js index 3758cb83c..4ba1b221b 100644 --- a/scripts/optimize-assets.js +++ b/scripts/optimize-assets.js @@ -1,11 +1,11 @@ -import { readdirSync, statSync } from "fs"; -import { join, relative } from "path"; -import sharp from "sharp"; -import { fileURLToPath } from "url"; +import { readdirSync, statSync } from 'fs'; +import { join, relative } from 'path'; +import sharp from 'sharp'; +import { fileURLToPath } from 'url'; -const __dirname = fileURLToPath(new URL(".", import.meta.url)); -const root_dir = join(__dirname, "../static"); -const exceptions = ["assets/"]; +const __dirname = fileURLToPath(new URL('.', import.meta.url)); +const root_dir = join(__dirname, '../static'); +const exceptions = ['assets/']; /** * @type {{ @@ -17,79 +17,78 @@ const exceptions = ["assets/"]; * }} */ const config = { - jpeg: { - quality: 100, - }, - webp: { - lossless: true, - }, - png: { - quality: 100, - }, - gif: { - quality: 100, - }, - avif: { - lossless: true, - }, + jpeg: { + quality: 100 + }, + webp: { + lossless: true + }, + png: { + quality: 100 + }, + gif: { + quality: 100 + }, + avif: { + lossless: true + } }; /** @type {sharp.ResizeOptions} */ const resize_config = { - width: 1280, - height: 1280, - fit: sharp.fit.inside, - withoutEnlargement: true, + width: 1280, + height: 1280, + fit: sharp.fit.inside, + withoutEnlargement: true }; function* walk_directory(dir) { - const files = readdirSync(dir); + const files = readdirSync(dir); - for (const file of files) { - const pathToFile = join(dir, file); - const isDirectory = statSync(pathToFile).isDirectory(); - if (isDirectory) { - yield* walk_directory(pathToFile); - } else { - yield pathToFile; + for (const file of files) { + const pathToFile = join(dir, file); + const isDirectory = statSync(pathToFile).isDirectory(); + if (isDirectory) { + yield* walk_directory(pathToFile); + } else { + yield pathToFile; + } } - } } function is_image(file) { - const extension = file.split(".").pop().toLowerCase(); + const extension = file.split('.').pop().toLowerCase(); - return Object.keys(config).includes(extension); + return Object.keys(config).includes(extension); } function get_relative_path(file) { - return relative(root_dir, file); + return relative(root_dir, file); } async function main() { - for (const file of walk_directory(join(__dirname, "../static"))) { - const relative_path = get_relative_path(file); - const is_animated = file.endsWith(".gif"); - if (!is_image(file)) continue; - if (exceptions.some((exception) => relative_path.startsWith(exception))) - continue; + for (const file of walk_directory(join(__dirname, '../static'))) { + const relative_path = get_relative_path(file); + const is_animated = file.endsWith('.gif'); + if (!is_image(file)) continue; + if (exceptions.some((exception) => relative_path.startsWith(exception))) continue; - const image = sharp(file, { - animated: is_animated, - }); - const size_before = (await image.toBuffer()).length; - const meta = await image.metadata(); - const buffer = await image[meta.format](config[meta.format]) - .resize(resize_config) - .toBuffer(); - const size_after = buffer.length; + const image = sharp(file, { + animated: is_animated + }); + const size_before = (await image.toBuffer()).length; + const meta = await image.metadata(); + const buffer = await image[meta.format](config[meta.format]) + .resize(resize_config) + .toBuffer(); + const size_after = buffer.length; - if (size_after >= size_before) continue; + if (size_after >= size_before) continue; - console.log(relative_path); + console.log(relative_path); - await sharp(buffer).toFile(file); - } + await sharp(buffer).toFile(file); + } } await main(); diff --git a/server/main.js b/server/main.js index d04da3ab9..1fb7bf9b1 100644 --- a/server/main.js +++ b/server/main.js @@ -1,17 +1,17 @@ -import { createApp, fromNodeMiddleware, toNodeListener } from "h3"; -import { createServer } from "node:http"; -import { handler } from "../build/handler.js"; -import { sitemap } from "./sitemap.js"; +import { createApp, fromNodeMiddleware, toNodeListener } from 'h3'; +import { createServer } from 'node:http'; +import { handler } from '../build/handler.js'; +import { sitemap } from './sitemap.js'; async function main() { - const port = process.env.PORT || 3000; - const app = createApp(); - app.use("/sitemap.xml", await sitemap()); - app.use(fromNodeMiddleware(handler)); - const server = createServer(toNodeListener(app)).listen(port); - server.addListener("listening", () => { - console.log(`Listening on http://0.0.0.0:${port}`); - }); + const port = process.env.PORT || 3000; + const app = createApp(); + app.use('/sitemap.xml', await sitemap()); + app.use(fromNodeMiddleware(handler)); + const server = createServer(toNodeListener(app)).listen(port); + server.addListener('listening', () => { + console.log(`Listening on http://0.0.0.0:${port}`); + }); } main(); diff --git a/server/sitemap.js b/server/sitemap.js index b15978711..923521074 100644 --- a/server/sitemap.js +++ b/server/sitemap.js @@ -1,45 +1,43 @@ -import { createRequire } from "node:module"; -import { defineEventHandler, setResponseHeader } from "h3"; +import { createRequire } from 'node:module'; +import { defineEventHandler, setResponseHeader } from 'h3'; /** * @returns {Promise} */ export async function sitemap() { - console.info("Preparing Sitemap..."); - const manifest = await import("../build/server/manifest.js"); - const prerendered = manifest.prerendered; - const file_route_extensions = [".json", ".xml"]; - const routes = [...prerendered, ...collectThreads()].filter( - (route) => !file_route_extensions.some((ext) => route.endsWith(ext)), - ); - console.info(`Sitemap loaded with ${routes.length} routes!`); + console.info('Preparing Sitemap...'); + const manifest = await import('../build/server/manifest.js'); + const prerendered = manifest.prerendered; + const file_route_extensions = ['.json', '.xml']; + const routes = [...prerendered, ...collectThreads()].filter( + (route) => !file_route_extensions.some((ext) => route.endsWith(ext)) + ); + console.info(`Sitemap loaded with ${routes.length} routes!`); - const sitemap = ` + const sitemap = ` ${routes - .map( - (route) => ` + .map( + (route) => ` https://appwrite.io${route} - `, - ) - .join("")} + ` + ) + .join('')} `; - return defineEventHandler((event) => { - setResponseHeader(event, "Content-Type", "application/xml"); + return defineEventHandler((event) => { + setResponseHeader(event, 'Content-Type', 'application/xml'); - return sitemap; - }); + return sitemap; + }); } /** * @returns {string[]} */ function collectThreads() { - const threads = createRequire(import.meta.url)( - "../build/prerendered/threads/data.json", - ); + const threads = createRequire(import.meta.url)('../build/prerendered/threads/data.json'); - return threads.map((id) => `/threads/${id}`); + return threads.map((id) => `/threads/${id}`); } diff --git a/src/app.css b/src/app.css index d0ced432f..aa91ce6f9 100644 --- a/src/app.css +++ b/src/app.css @@ -1,124 +1,124 @@ -@import "tailwindcss"; +@import 'tailwindcss'; @theme { - /* Colors */ - --color-*: initial; + /* Colors */ + --color-*: initial; - /* base */ - --color-primary: hsl(var(--color-primary)); - --color-secondary: hsl(var(--color-secondary)); - --color-accent: var(--color-secondary); - --color-border-primary: hsl(var(--color-greyscale-hue) 5.7% 10.4% / 0.04); + /* base */ + --color-primary: hsl(var(--color-primary)); + --color-secondary: hsl(var(--color-secondary)); + --color-accent: var(--color-secondary); + --color-border-primary: hsl(var(--color-greyscale-hue) 5.7% 10.4% / 0.04); - /* pink */ - --color-pink-200: hsl(var(--color-pink-hue) 98% 84%); - --color-pink-500: hsl(var(--color-pink-hue) 98% 60%); - --color-pink-600: hsl(var(--color-pink-hue) 65% 48%); - --color-pink-700: hsl(var(--color-pink-hue) 65% 36%); + /* pink */ + --color-pink-200: hsl(var(--color-pink-hue) 98% 84%); + --color-pink-500: hsl(var(--color-pink-hue) 98% 60%); + --color-pink-600: hsl(var(--color-pink-hue) 65% 48%); + --color-pink-700: hsl(var(--color-pink-hue) 65% 36%); - /* red */ - --color-red-200: calc(hsl(var(--color-red-hue) - 2) 100% 92%); - --color-red-500: hsl(var(--color-red-hue) 100% 61%); - --color-red-700: calc(hsl(var(--color-red-hue) - 3) 82% 39%); + /* red */ + --color-red-200: calc(hsl(var(--color-red-hue) - 2) 100% 92%); + --color-red-500: hsl(var(--color-red-hue) 100% 61%); + --color-red-700: calc(hsl(var(--color-red-hue) - 3) 82% 39%); - /* orange */ - --color-orange-200: hsl(var(--color-orange-hue) 100% 88%); - --color-orange-500: hsl(var(--color-orange-hue) 99% 70%); - --color-orange-700: hsl(var(--color-orange-hue) 42% 42%); + /* orange */ + --color-orange-200: hsl(var(--color-orange-hue) 100% 88%); + --color-orange-500: hsl(var(--color-orange-hue) 99% 70%); + --color-orange-700: hsl(var(--color-orange-hue) 42% 42%); - /* mint */ - --color-mint-200: hsl(var(--color-mint-hue) 56% 88%); - --color-mint-500: calc(hsl(var(--color-mint-hue) + 1) 54% 69%); - --color-mint-700: calc(hsl(var(--color-mint-hue) + 2) 24% 41%); + /* mint */ + --color-mint-200: hsl(var(--color-mint-hue) 56% 88%); + --color-mint-500: calc(hsl(var(--color-mint-hue) + 1) 54% 69%); + --color-mint-700: calc(hsl(var(--color-mint-hue) + 2) 24% 41%); - /* purple */ - --color-purple-200: hsl(var(--color-purple-hue) 100% 88%); - --color-purple-500: calc(hsl(var(--color-purple-hue) - 1) 99% 70%); - --color-purple-700: calc(hsl(var(--color-purple-hue) - 1) 42% 42%); + /* purple */ + --color-purple-200: hsl(var(--color-purple-hue) 100% 88%); + --color-purple-500: calc(hsl(var(--color-purple-hue) - 1) 99% 70%); + --color-purple-700: calc(hsl(var(--color-purple-hue) - 1) 42% 42%); - /* yellow */ - --color-yellow-200: hsl(var(--color-yellow-hue) 100% 88%); - --color-yellow-500: hsl(var(--color-yellow-hue) 99% 70%); - --color-yellow-700: calc(hsl(var(--color-yellow-hue) + 1) 42% 42%); + /* yellow */ + --color-yellow-200: hsl(var(--color-yellow-hue) 100% 88%); + --color-yellow-500: hsl(var(--color-yellow-hue) 99% 70%); + --color-yellow-700: calc(hsl(var(--color-yellow-hue) + 1) 42% 42%); - /* blue */ - --color-blue-200: hsl(var(--color-blue-hue) 100% 88%); - --color-blue-500: calc(hsl(var(--color-blue-hue) - 1) 99% 70%); - --color-blue-700: calc(hsl(var(--color-blue-hue) - 1) 42% 42%); + /* blue */ + --color-blue-200: hsl(var(--color-blue-hue) 100% 88%); + --color-blue-500: calc(hsl(var(--color-blue-hue) - 1) 99% 70%); + --color-blue-700: calc(hsl(var(--color-blue-hue) - 1) 42% 42%); - /* secondary */ - --color-secondary-100: hsl(var(--color-secondary-hue) 99% 66%); + /* secondary */ + --color-secondary-100: hsl(var(--color-secondary-hue) 99% 66%); - /* greyscale */ - --color-white: hsl(0 0% 100%); - --color-black: hsl(0 0% 0%); - --color-greyscale-25: hsl(var(--color-greyscale-hue) 11% 98%); - --color-greyscale-50: hsl(var(--color-greyscale-hue) 11% 94%); - --color-greyscale-100: hsl(var(--color-greyscale-hue) 6% 90%); - --color-greyscale-200: hsl(var(--color-greyscale-hue) 4% 85%); - --color-greyscale-250: hsl(var(--color-greyscale-hue) 3% 77%); - --color-greyscale-300: hsl(var(--color-greyscale-hue) 2% 68%); - --color-greyscale-400: hsl(var(--color-greyscale-hue) 2% 60%); - --color-greyscale-500: hsl(var(--color-greyscale-hue) 2% 52%); - --color-greyscale-600: hsl(var(--color-greyscale-hue) 2% 43%); - --color-greyscale-700: hsl(var(--color-greyscale-hue) 3% 35%); - --color-greyscale-750: hsl(var(--color-greyscale-hue) 4% 26%); - --color-greyscale-800: hsl(var(--color-greyscale-hue) 4% 18%); - --color-greyscale-850: hsl(var(--color-greyscale-hue) 3% 14%); - --color-greyscale-900: hsl(var(--color-greyscale-hue) 5.7% 10.4%); + /* greyscale */ + --color-white: hsl(0 0% 100%); + --color-black: hsl(0 0% 0%); + --color-greyscale-25: hsl(var(--color-greyscale-hue) 11% 98%); + --color-greyscale-50: hsl(var(--color-greyscale-hue) 11% 94%); + --color-greyscale-100: hsl(var(--color-greyscale-hue) 6% 90%); + --color-greyscale-200: hsl(var(--color-greyscale-hue) 4% 85%); + --color-greyscale-250: hsl(var(--color-greyscale-hue) 3% 77%); + --color-greyscale-300: hsl(var(--color-greyscale-hue) 2% 68%); + --color-greyscale-400: hsl(var(--color-greyscale-hue) 2% 60%); + --color-greyscale-500: hsl(var(--color-greyscale-hue) 2% 52%); + --color-greyscale-600: hsl(var(--color-greyscale-hue) 2% 43%); + --color-greyscale-700: hsl(var(--color-greyscale-hue) 3% 35%); + --color-greyscale-750: hsl(var(--color-greyscale-hue) 4% 26%); + --color-greyscale-800: hsl(var(--color-greyscale-hue) 4% 18%); + --color-greyscale-850: hsl(var(--color-greyscale-hue) 3% 14%); + --color-greyscale-900: hsl(var(--color-greyscale-hue) 5.7% 10.4%); - /* Animations */ - --animate-scale-in: scale-in 200ms ease-out forwards; + /* Animations */ + --animate-scale-in: scale-in 200ms ease-out forwards; - /* Pink polyfills */ - --transition: 0.2s; + /* Pink polyfills */ + --transition: 0.2s; - /* Keyframes */ - @keyframes scale-in { - 0% { - transform: scale(0); + /* Keyframes */ + @keyframes scale-in { + 0% { + transform: scale(0); + } + 100% { + transform: scale(1); + } } - 100% { - transform: scale(1); - } - } - /* Fonts */ - --font-family-sans: "Inter", arial, sans-serif; - --font-family-mono: "Fira Code", monospace; - --font-family-aeonik-fono: "Aenoik Fono", monospace; - --font-family-aeonik-pro: "Aeonik Pro", var(--font-family-sans); - --font-family-archia: "Archia", arial, sans-serif; + /* Fonts */ + --font-family-sans: 'Inter', arial, sans-serif; + --font-family-mono: 'Fira Code', monospace; + --font-family-aeonik-fono: 'Aenoik Fono', monospace; + --font-family-aeonik-pro: 'Aeonik Pro', var(--font-family-sans); + --font-family-archia: 'Archia', arial, sans-serif; } /* Themes */ :root, .light { - --color-pink-hue: 343; - --color-secondary-hue: 351; - --color-red-hue: 3; - --color-orange-hue: 18; - --color-mint-hue: 177; - --color-purple-hue: 249; - --color-yellow-hue: 42; - --color-blue-hue: 217; - --color-greyscale-hue: 240; + --color-pink-hue: 343; + --color-secondary-hue: 351; + --color-red-hue: 3; + --color-orange-hue: 18; + --color-mint-hue: 177; + --color-purple-hue: 249; + --color-yellow-hue: 42; + --color-blue-hue: 217; + --color-greyscale-hue: 240; - /* base */ - --color-primary: var(--color-greyscale-900); - --color-secondary: var(--color-greyscale-700); - --color-accent: var(--color-pink-600); + /* base */ + --color-primary: var(--color-greyscale-900); + --color-secondary: var(--color-greyscale-700); + --color-accent: var(--color-pink-600); } /* dark theme */ .dark { - --color-primary: var(--color-greyscale-100); - --color-secondary: var(--color-greyscale-300); + --color-primary: var(--color-greyscale-100); + --color-secondary: var(--color-greyscale-300); } /* Container */ @layer components { - .container { - @apply mx-auto box-content max-w-[75rem] px-8; - } + .container { + @apply mx-auto box-content max-w-[75rem] px-8; + } } diff --git a/src/app.d.ts b/src/app.d.ts index 72c5e25e5..7b32cc9ae 100644 --- a/src/app.d.ts +++ b/src/app.d.ts @@ -1,14 +1,14 @@ // See https://kit.svelte.dev/docs/types#app // for information about these interfaces declare global { - namespace App { - // interface Error {} - // interface Locals {} - interface PageData { - changelogEntries: number; + namespace App { + // interface Error {} + // interface Locals {} + interface PageData { + changelogEntries: number; + } + // interface Platform {} } - // interface Platform {} - } } export {}; diff --git a/src/app.html b/src/app.html index e1313d459..05a180566 100644 --- a/src/app.html +++ b/src/app.html @@ -1,60 +1,59 @@ - - - - - - - + + + + + + + - %sveltekit.head% - + %sveltekit.head% + - - -
%sveltekit.body%
- + // Banner + const BANNER_KEY = '%aw_banner_key%'; + const hideBanner = localStorage.getItem(BANNER_KEY); + if (hideBanner === 'true') { + document.body.dataset.bannerHidden = ''; + } + // Is logged in + const isLoggedIn = localStorage.getItem('appwrite:user'); + if (isLoggedIn) { + document.body.dataset.loggedIn = ''; + } + +
%sveltekit.body%
+ diff --git a/src/hooks.client.ts b/src/hooks.client.ts index 0d0323119..daad26c3d 100644 --- a/src/hooks.client.ts +++ b/src/hooks.client.ts @@ -1,30 +1,30 @@ -import { dev } from "$app/environment"; -import { SENTRY_DSN } from "$lib/constants"; -import { handleErrorWithSentry, replayIntegration } from "@sentry/sveltekit"; -import * as Sentry from "@sentry/sveltekit"; +import { dev } from '$app/environment'; +import { SENTRY_DSN } from '$lib/constants'; +import { handleErrorWithSentry, replayIntegration } from '@sentry/sveltekit'; +import * as Sentry from '@sentry/sveltekit'; Sentry.init({ - enabled: !dev, - dsn: SENTRY_DSN, - allowUrls: [/appwrite\.io/], - tracesSampleRate: 1.0, + enabled: !dev, + dsn: SENTRY_DSN, + allowUrls: [/appwrite\.io/], + tracesSampleRate: 1.0, - // This sets the sample rate to be 10%. You may want this to be 100% while - // in development and sample at a lower rate in production - replaysSessionSampleRate: 0, + // This sets the sample rate to be 10%. You may want this to be 100% while + // in development and sample at a lower rate in production + replaysSessionSampleRate: 0, - // If the entire session is not sampled, use the below sample rate to sample - // sessions when an error occurs. - replaysOnErrorSampleRate: 1.0, + // If the entire session is not sampled, use the below sample rate to sample + // sessions when an error occurs. + replaysOnErrorSampleRate: 1.0, - // If you don't want to use Session Replay, just remove the line below: - integrations: [ - replayIntegration({ - maskAllInputs: true, - maskAllText: false, - blockAllMedia: false, - }), - ], + // If you don't want to use Session Replay, just remove the line below: + integrations: [ + replayIntegration({ + maskAllInputs: true, + maskAllText: false, + blockAllMedia: false + }) + ] }); // If you have a custom error handler, pass it to `handleErrorWithSentry` diff --git a/src/hooks.server.ts b/src/hooks.server.ts index 90ae2272c..990f47aa1 100644 --- a/src/hooks.server.ts +++ b/src/hooks.server.ts @@ -1,46 +1,39 @@ -import * as Sentry from "@sentry/sveltekit"; -import type { Handle } from "@sveltejs/kit"; -import redirects from "./redirects.json"; -import { sequence } from "@sveltejs/kit/hooks"; -import { BANNER_KEY, SENTRY_DSN } from "$lib/constants"; -import { dev } from "$app/environment"; +import * as Sentry from '@sentry/sveltekit'; +import type { Handle } from '@sveltejs/kit'; +import redirects from './redirects.json'; +import { sequence } from '@sveltejs/kit/hooks'; +import { BANNER_KEY, SENTRY_DSN } from '$lib/constants'; +import { dev } from '$app/environment'; Sentry.init({ - enabled: !dev, - dsn: SENTRY_DSN, - tracesSampleRate: 1, - allowUrls: [/appwrite\.io/], + enabled: !dev, + dsn: SENTRY_DSN, + tracesSampleRate: 1, + allowUrls: [/appwrite\.io/] }); -const redirectMap = new Map( - redirects.map(({ link, redirect }) => [link, redirect]), -); +const redirectMap = new Map(redirects.map(({ link, redirect }) => [link, redirect])); const redirecter: Handle = async ({ event, resolve }) => { - const currentPath = event.url.pathname; - if (redirectMap.has(currentPath)) { - return new Response(null, { - status: 308, - headers: { - location: redirectMap.get(currentPath) ?? "", - }, - }); - } + const currentPath = event.url.pathname; + if (redirectMap.has(currentPath)) { + return new Response(null, { + status: 308, + headers: { + location: redirectMap.get(currentPath) ?? '' + } + }); + } - return await resolve(event); + return await resolve(event); }; const bannerRewriter: Handle = async ({ event, resolve }) => { - const response = await resolve(event, { - transformPageChunk: ({ html }) => - html.replace("%aw_banner_key%", BANNER_KEY), - }); - return response; + const response = await resolve(event, { + transformPageChunk: ({ html }) => html.replace('%aw_banner_key%', BANNER_KEY) + }); + return response; }; -export const handle = sequence( - Sentry.sentryHandle(), - redirecter, - bannerRewriter, -); +export const handle = sequence(Sentry.sentryHandle(), redirecter, bannerRewriter); export const handleError = Sentry.handleErrorWithSentry(); diff --git a/src/icons/build.js b/src/icons/build.js index c064235de..4ea6d57a7 100644 --- a/src/icons/build.js +++ b/src/icons/build.js @@ -1,3 +1,3 @@ -import { generateIcons } from "./scripts.js"; +import { generateIcons } from './scripts.js'; generateIcons(); diff --git a/src/icons/optimize.js b/src/icons/optimize.js index db0b6ca25..f4a916df6 100644 --- a/src/icons/optimize.js +++ b/src/icons/optimize.js @@ -1,3 +1,3 @@ -import { optimizeSVG } from "./scripts.js"; +import { optimizeSVG } from './scripts.js'; optimizeSVG(); diff --git a/src/icons/output/info.json b/src/icons/output/info.json index 6e9be45ec..fc00f8f50 100644 --- a/src/icons/output/info.json +++ b/src/icons/output/info.json @@ -1,314 +1,314 @@ { - "apple": { - "encodedCode": "\\ea01", - "prefix": "web-icon", - "className": "web-icon-apple", - "unicode": "" - }, - "appwrite": { - "encodedCode": "\\ea02", - "prefix": "web-icon", - "className": "web-icon-appwrite", - "unicode": "" - }, - "arrow-down": { - "encodedCode": "\\ea03", - "prefix": "web-icon", - "className": "web-icon-arrow-down", - "unicode": "" - }, - "arrow-ext-link": { - "encodedCode": "\\ea04", - "prefix": "web-icon", - "className": "web-icon-arrow-ext-link", - "unicode": "" - }, - "arrow-left": { - "encodedCode": "\\ea05", - "prefix": "web-icon", - "className": "web-icon-arrow-left", - "unicode": "" - }, - "arrow-right": { - "encodedCode": "\\ea06", - "prefix": "web-icon", - "className": "web-icon-arrow-right", - "unicode": "" - }, - "arrow-up": { - "encodedCode": "\\ea07", - "prefix": "web-icon", - "className": "web-icon-arrow-up", - "unicode": "" - }, - "calendar": { - "encodedCode": "\\ea08", - "prefix": "web-icon", - "className": "web-icon-calendar", - "unicode": "" - }, - "check": { - "encodedCode": "\\ea09", - "prefix": "web-icon", - "className": "web-icon-check", - "unicode": "" - }, - "chevron-down": { - "encodedCode": "\\ea0a", - "prefix": "web-icon", - "className": "web-icon-chevron-down", - "unicode": "" - }, - "chevron-left": { - "encodedCode": "\\ea0b", - "prefix": "web-icon", - "className": "web-icon-chevron-left", - "unicode": "" - }, - "chevron-right": { - "encodedCode": "\\ea0c", - "prefix": "web-icon", - "className": "web-icon-chevron-right", - "unicode": "" - }, - "chevron-up": { - "encodedCode": "\\ea0d", - "prefix": "web-icon", - "className": "web-icon-chevron-up", - "unicode": "" - }, - "close": { - "encodedCode": "\\ea0e", - "prefix": "web-icon", - "className": "web-icon-close", - "unicode": "" - }, - "command": { - "encodedCode": "\\ea0f", - "prefix": "web-icon", - "className": "web-icon-command", - "unicode": "" - }, - "copy": { - "encodedCode": "\\ea10", - "prefix": "web-icon", - "className": "web-icon-copy", - "unicode": "" - }, - "daily-dev": { - "encodedCode": "\\ea11", - "prefix": "web-icon", - "className": "web-icon-daily-dev", - "unicode": "" - }, - "dark": { - "encodedCode": "\\ea12", - "prefix": "web-icon", - "className": "web-icon-dark", - "unicode": "" - }, - "discord": { - "encodedCode": "\\ea13", - "prefix": "web-icon", - "className": "web-icon-discord", - "unicode": "" - }, - "divider-vertical": { - "encodedCode": "\\ea14", - "prefix": "web-icon", - "className": "web-icon-divider-vertical", - "unicode": "" - }, - "download": { - "encodedCode": "\\ea15", - "prefix": "web-icon", - "className": "web-icon-download", - "unicode": "" - }, - "ext-link": { - "encodedCode": "\\ea16", - "prefix": "web-icon", - "className": "web-icon-ext-link", - "unicode": "" - }, - "firebase": { - "encodedCode": "\\ea17", - "prefix": "web-icon", - "className": "web-icon-firebase", - "unicode": "" - }, - "github": { - "encodedCode": "\\ea18", - "prefix": "web-icon", - "className": "web-icon-github", - "unicode": "" - }, - "google": { - "encodedCode": "\\ea19", - "prefix": "web-icon", - "className": "web-icon-google", - "unicode": "" - }, - "hamburger-menu": { - "encodedCode": "\\ea1a", - "prefix": "web-icon", - "className": "web-icon-hamburger-menu", - "unicode": "" - }, - "light": { - "encodedCode": "\\ea1b", - "prefix": "web-icon", - "className": "web-icon-light", - "unicode": "" - }, - "linkedin": { - "encodedCode": "\\ea1c", - "prefix": "web-icon", - "className": "web-icon-linkedin", - "unicode": "" - }, - "location": { - "encodedCode": "\\ea1d", - "prefix": "web-icon", - "className": "web-icon-location", - "unicode": "" - }, - "logout-left": { - "encodedCode": "\\ea1e", - "prefix": "web-icon", - "className": "web-icon-logout-left", - "unicode": "" - }, - "logout-right": { - "encodedCode": "\\ea1f", - "prefix": "web-icon", - "className": "web-icon-logout-right", - "unicode": "" - }, - "mailgun": { - "encodedCode": "\\ea20", - "prefix": "web-icon", - "className": "web-icon-mailgun", - "unicode": "" - }, - "message": { - "encodedCode": "\\ea21", - "prefix": "web-icon", - "className": "web-icon-message", - "unicode": "" - }, - "microsoft": { - "encodedCode": "\\ea22", - "prefix": "web-icon", - "className": "web-icon-microsoft", - "unicode": "" - }, - "minus": { - "encodedCode": "\\ea23", - "prefix": "web-icon", - "className": "web-icon-minus", - "unicode": "" - }, - "nuxt": { - "encodedCode": "\\ea24", - "prefix": "web-icon", - "className": "web-icon-nuxt", - "unicode": "" - }, - "platform": { - "encodedCode": "\\ea25", - "prefix": "web-icon", - "className": "web-icon-platform", - "unicode": "" - }, - "play": { - "encodedCode": "\\ea26", - "prefix": "web-icon", - "className": "web-icon-play", - "unicode": "" - }, - "plus": { - "encodedCode": "\\ea27", - "prefix": "web-icon", - "className": "web-icon-plus", - "unicode": "" - }, - "product-hunt": { - "encodedCode": "\\ea28", - "prefix": "web-icon", - "className": "web-icon-product-hunt", - "unicode": "" - }, - "refine": { - "encodedCode": "\\ea29", - "prefix": "web-icon", - "className": "web-icon-refine", - "unicode": "" - }, - "rest": { - "encodedCode": "\\ea2a", - "prefix": "web-icon", - "className": "web-icon-rest", - "unicode": "" - }, - "search": { - "encodedCode": "\\ea2b", - "prefix": "web-icon", - "className": "web-icon-search", - "unicode": "" - }, - "sendgrid": { - "encodedCode": "\\ea2c", - "prefix": "web-icon", - "className": "web-icon-sendgrid", - "unicode": "" - }, - "star": { - "encodedCode": "\\ea2d", - "prefix": "web-icon", - "className": "web-icon-star", - "unicode": "" - }, - "system": { - "encodedCode": "\\ea2e", - "prefix": "web-icon", - "className": "web-icon-system", - "unicode": "" - }, - "textmagic": { - "encodedCode": "\\ea2f", - "prefix": "web-icon", - "className": "web-icon-textmagic", - "unicode": "" - }, - "twitter": { - "encodedCode": "\\ea30", - "prefix": "web-icon", - "className": "web-icon-twitter", - "unicode": "" - }, - "vue": { - "encodedCode": "\\ea31", - "prefix": "web-icon", - "className": "web-icon-vue", - "unicode": "" - }, - "x": { - "encodedCode": "\\ea32", - "prefix": "web-icon", - "className": "web-icon-x", - "unicode": "" - }, - "ycombinator": { - "encodedCode": "\\ea33", - "prefix": "web-icon", - "className": "web-icon-ycombinator", - "unicode": "" - }, - "youtube": { - "encodedCode": "\\ea34", - "prefix": "web-icon", - "className": "web-icon-youtube", - "unicode": "" - } + "apple": { + "encodedCode": "\\ea01", + "prefix": "web-icon", + "className": "web-icon-apple", + "unicode": "" + }, + "appwrite": { + "encodedCode": "\\ea02", + "prefix": "web-icon", + "className": "web-icon-appwrite", + "unicode": "" + }, + "arrow-down": { + "encodedCode": "\\ea03", + "prefix": "web-icon", + "className": "web-icon-arrow-down", + "unicode": "" + }, + "arrow-ext-link": { + "encodedCode": "\\ea04", + "prefix": "web-icon", + "className": "web-icon-arrow-ext-link", + "unicode": "" + }, + "arrow-left": { + "encodedCode": "\\ea05", + "prefix": "web-icon", + "className": "web-icon-arrow-left", + "unicode": "" + }, + "arrow-right": { + "encodedCode": "\\ea06", + "prefix": "web-icon", + "className": "web-icon-arrow-right", + "unicode": "" + }, + "arrow-up": { + "encodedCode": "\\ea07", + "prefix": "web-icon", + "className": "web-icon-arrow-up", + "unicode": "" + }, + "calendar": { + "encodedCode": "\\ea08", + "prefix": "web-icon", + "className": "web-icon-calendar", + "unicode": "" + }, + "check": { + "encodedCode": "\\ea09", + "prefix": "web-icon", + "className": "web-icon-check", + "unicode": "" + }, + "chevron-down": { + "encodedCode": "\\ea0a", + "prefix": "web-icon", + "className": "web-icon-chevron-down", + "unicode": "" + }, + "chevron-left": { + "encodedCode": "\\ea0b", + "prefix": "web-icon", + "className": "web-icon-chevron-left", + "unicode": "" + }, + "chevron-right": { + "encodedCode": "\\ea0c", + "prefix": "web-icon", + "className": "web-icon-chevron-right", + "unicode": "" + }, + "chevron-up": { + "encodedCode": "\\ea0d", + "prefix": "web-icon", + "className": "web-icon-chevron-up", + "unicode": "" + }, + "close": { + "encodedCode": "\\ea0e", + "prefix": "web-icon", + "className": "web-icon-close", + "unicode": "" + }, + "command": { + "encodedCode": "\\ea0f", + "prefix": "web-icon", + "className": "web-icon-command", + "unicode": "" + }, + "copy": { + "encodedCode": "\\ea10", + "prefix": "web-icon", + "className": "web-icon-copy", + "unicode": "" + }, + "daily-dev": { + "encodedCode": "\\ea11", + "prefix": "web-icon", + "className": "web-icon-daily-dev", + "unicode": "" + }, + "dark": { + "encodedCode": "\\ea12", + "prefix": "web-icon", + "className": "web-icon-dark", + "unicode": "" + }, + "discord": { + "encodedCode": "\\ea13", + "prefix": "web-icon", + "className": "web-icon-discord", + "unicode": "" + }, + "divider-vertical": { + "encodedCode": "\\ea14", + "prefix": "web-icon", + "className": "web-icon-divider-vertical", + "unicode": "" + }, + "download": { + "encodedCode": "\\ea15", + "prefix": "web-icon", + "className": "web-icon-download", + "unicode": "" + }, + "ext-link": { + "encodedCode": "\\ea16", + "prefix": "web-icon", + "className": "web-icon-ext-link", + "unicode": "" + }, + "firebase": { + "encodedCode": "\\ea17", + "prefix": "web-icon", + "className": "web-icon-firebase", + "unicode": "" + }, + "github": { + "encodedCode": "\\ea18", + "prefix": "web-icon", + "className": "web-icon-github", + "unicode": "" + }, + "google": { + "encodedCode": "\\ea19", + "prefix": "web-icon", + "className": "web-icon-google", + "unicode": "" + }, + "hamburger-menu": { + "encodedCode": "\\ea1a", + "prefix": "web-icon", + "className": "web-icon-hamburger-menu", + "unicode": "" + }, + "light": { + "encodedCode": "\\ea1b", + "prefix": "web-icon", + "className": "web-icon-light", + "unicode": "" + }, + "linkedin": { + "encodedCode": "\\ea1c", + "prefix": "web-icon", + "className": "web-icon-linkedin", + "unicode": "" + }, + "location": { + "encodedCode": "\\ea1d", + "prefix": "web-icon", + "className": "web-icon-location", + "unicode": "" + }, + "logout-left": { + "encodedCode": "\\ea1e", + "prefix": "web-icon", + "className": "web-icon-logout-left", + "unicode": "" + }, + "logout-right": { + "encodedCode": "\\ea1f", + "prefix": "web-icon", + "className": "web-icon-logout-right", + "unicode": "" + }, + "mailgun": { + "encodedCode": "\\ea20", + "prefix": "web-icon", + "className": "web-icon-mailgun", + "unicode": "" + }, + "message": { + "encodedCode": "\\ea21", + "prefix": "web-icon", + "className": "web-icon-message", + "unicode": "" + }, + "microsoft": { + "encodedCode": "\\ea22", + "prefix": "web-icon", + "className": "web-icon-microsoft", + "unicode": "" + }, + "minus": { + "encodedCode": "\\ea23", + "prefix": "web-icon", + "className": "web-icon-minus", + "unicode": "" + }, + "nuxt": { + "encodedCode": "\\ea24", + "prefix": "web-icon", + "className": "web-icon-nuxt", + "unicode": "" + }, + "platform": { + "encodedCode": "\\ea25", + "prefix": "web-icon", + "className": "web-icon-platform", + "unicode": "" + }, + "play": { + "encodedCode": "\\ea26", + "prefix": "web-icon", + "className": "web-icon-play", + "unicode": "" + }, + "plus": { + "encodedCode": "\\ea27", + "prefix": "web-icon", + "className": "web-icon-plus", + "unicode": "" + }, + "product-hunt": { + "encodedCode": "\\ea28", + "prefix": "web-icon", + "className": "web-icon-product-hunt", + "unicode": "" + }, + "refine": { + "encodedCode": "\\ea29", + "prefix": "web-icon", + "className": "web-icon-refine", + "unicode": "" + }, + "rest": { + "encodedCode": "\\ea2a", + "prefix": "web-icon", + "className": "web-icon-rest", + "unicode": "" + }, + "search": { + "encodedCode": "\\ea2b", + "prefix": "web-icon", + "className": "web-icon-search", + "unicode": "" + }, + "sendgrid": { + "encodedCode": "\\ea2c", + "prefix": "web-icon", + "className": "web-icon-sendgrid", + "unicode": "" + }, + "star": { + "encodedCode": "\\ea2d", + "prefix": "web-icon", + "className": "web-icon-star", + "unicode": "" + }, + "system": { + "encodedCode": "\\ea2e", + "prefix": "web-icon", + "className": "web-icon-system", + "unicode": "" + }, + "textmagic": { + "encodedCode": "\\ea2f", + "prefix": "web-icon", + "className": "web-icon-textmagic", + "unicode": "" + }, + "twitter": { + "encodedCode": "\\ea30", + "prefix": "web-icon", + "className": "web-icon-twitter", + "unicode": "" + }, + "vue": { + "encodedCode": "\\ea31", + "prefix": "web-icon", + "className": "web-icon-vue", + "unicode": "" + }, + "x": { + "encodedCode": "\\ea32", + "prefix": "web-icon", + "className": "web-icon-x", + "unicode": "" + }, + "ycombinator": { + "encodedCode": "\\ea33", + "prefix": "web-icon", + "className": "web-icon-ycombinator", + "unicode": "" + }, + "youtube": { + "encodedCode": "\\ea34", + "prefix": "web-icon", + "className": "web-icon-youtube", + "unicode": "" + } } diff --git a/src/icons/output/web-icon.css b/src/icons/output/web-icon.css index b6a0bb6f3..1946420c2 100644 --- a/src/icons/output/web-icon.css +++ b/src/icons/output/web-icon.css @@ -1,178 +1,178 @@ @font-face { - font-family: "web-icon"; - font-display: swap; - src: url("web-icon.eot"); /* IE9*/ - src: - url("web-icon.eot#iefix") format("embedded-opentype"), - /* IE6-IE8 */ url("web-icon.woff2") format("woff2"), - url("web-icon.woff") format("woff"), - url("web-icon.ttf") format("truetype"), - /* chrome, firefox, opera, Safari, Android, iOS 4.2+*/ - url("web-icon.svg#web-icon") format("svg"); /* iOS 4.1- */ + font-family: 'web-icon'; + font-display: swap; + src: url('web-icon.eot'); /* IE9*/ + src: + url('web-icon.eot#iefix') format('embedded-opentype'), + /* IE6-IE8 */ url('web-icon.woff2') format('woff2'), + url('web-icon.woff') format('woff'), + url('web-icon.ttf') format('truetype'), + /* chrome, firefox, opera, Safari, Android, iOS 4.2+*/ url('web-icon.svg#web-icon') + format('svg'); /* iOS 4.1- */ } -[class^="web-icon-"], -[class*=" web-icon-"] { - font-family: "web-icon" !important; - font-size: 20px; - font-style: normal; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; +[class^='web-icon-'], +[class*=' web-icon-'] { + font-family: 'web-icon' !important; + font-size: 20px; + font-style: normal; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; } .web-icon-apple:before { - content: "\ea01"; + content: '\ea01'; } .web-icon-appwrite:before { - content: "\ea02"; + content: '\ea02'; } .web-icon-arrow-down:before { - content: "\ea03"; + content: '\ea03'; } .web-icon-arrow-ext-link:before { - content: "\ea04"; + content: '\ea04'; } .web-icon-arrow-left:before { - content: "\ea05"; + content: '\ea05'; } .web-icon-arrow-right:before { - content: "\ea06"; + content: '\ea06'; } .web-icon-arrow-up:before { - content: "\ea07"; + content: '\ea07'; } .web-icon-calendar:before { - content: "\ea08"; + content: '\ea08'; } .web-icon-check:before { - content: "\ea09"; + content: '\ea09'; } .web-icon-chevron-down:before { - content: "\ea0a"; + content: '\ea0a'; } .web-icon-chevron-left:before { - content: "\ea0b"; + content: '\ea0b'; } .web-icon-chevron-right:before { - content: "\ea0c"; + content: '\ea0c'; } .web-icon-chevron-up:before { - content: "\ea0d"; + content: '\ea0d'; } .web-icon-close:before { - content: "\ea0e"; + content: '\ea0e'; } .web-icon-command:before { - content: "\ea0f"; + content: '\ea0f'; } .web-icon-copy:before { - content: "\ea10"; + content: '\ea10'; } .web-icon-daily-dev:before { - content: "\ea11"; + content: '\ea11'; } .web-icon-dark:before { - content: "\ea12"; + content: '\ea12'; } .web-icon-discord:before { - content: "\ea13"; + content: '\ea13'; } .web-icon-divider-vertical:before { - content: "\ea14"; + content: '\ea14'; } .web-icon-download:before { - content: "\ea15"; + content: '\ea15'; } .web-icon-ext-link:before { - content: "\ea16"; + content: '\ea16'; } .web-icon-firebase:before { - content: "\ea17"; + content: '\ea17'; } .web-icon-github:before { - content: "\ea18"; + content: '\ea18'; } .web-icon-google:before { - content: "\ea19"; + content: '\ea19'; } .web-icon-hamburger-menu:before { - content: "\ea1a"; + content: '\ea1a'; } .web-icon-light:before { - content: "\ea1b"; + content: '\ea1b'; } .web-icon-linkedin:before { - content: "\ea1c"; + content: '\ea1c'; } .web-icon-location:before { - content: "\ea1d"; + content: '\ea1d'; } .web-icon-logout-left:before { - content: "\ea1e"; + content: '\ea1e'; } .web-icon-logout-right:before { - content: "\ea1f"; + content: '\ea1f'; } .web-icon-mailgun:before { - content: "\ea20"; + content: '\ea20'; } .web-icon-message:before { - content: "\ea21"; + content: '\ea21'; } .web-icon-microsoft:before { - content: "\ea22"; + content: '\ea22'; } .web-icon-minus:before { - content: "\ea23"; + content: '\ea23'; } .web-icon-nuxt:before { - content: "\ea24"; + content: '\ea24'; } .web-icon-platform:before { - content: "\ea25"; + content: '\ea25'; } .web-icon-play:before { - content: "\ea26"; + content: '\ea26'; } .web-icon-plus:before { - content: "\ea27"; + content: '\ea27'; } .web-icon-product-hunt:before { - content: "\ea28"; + content: '\ea28'; } .web-icon-refine:before { - content: "\ea29"; + content: '\ea29'; } .web-icon-rest:before { - content: "\ea2a"; + content: '\ea2a'; } .web-icon-search:before { - content: "\ea2b"; + content: '\ea2b'; } .web-icon-sendgrid:before { - content: "\ea2c"; + content: '\ea2c'; } .web-icon-star:before { - content: "\ea2d"; + content: '\ea2d'; } .web-icon-system:before { - content: "\ea2e"; + content: '\ea2e'; } .web-icon-textmagic:before { - content: "\ea2f"; + content: '\ea2f'; } .web-icon-twitter:before { - content: "\ea30"; + content: '\ea30'; } .web-icon-vue:before { - content: "\ea31"; + content: '\ea31'; } .web-icon-x:before { - content: "\ea32"; + content: '\ea32'; } .web-icon-ycombinator:before { - content: "\ea33"; + content: '\ea33'; } .web-icon-youtube:before { - content: "\ea34"; + content: '\ea34'; } diff --git a/src/icons/scripts.js b/src/icons/scripts.js index 87d6b618b..1d697f169 100644 --- a/src/icons/scripts.js +++ b/src/icons/scripts.js @@ -1,40 +1,40 @@ // @ts-expect-error missing types -import SVGFixer from "oslllo-svg-fixer"; -import svgtofont from "svgtofont"; -import { resolve } from "path"; +import SVGFixer from 'oslllo-svg-fixer'; +import svgtofont from 'svgtofont'; +import { resolve } from 'path'; -const src = resolve(process.cwd(), "src/icons/svg"); -const optimized = resolve(process.cwd(), "src/icons/optimized"); -const dist = resolve(process.cwd(), "src/icons/output"); +const src = resolve(process.cwd(), 'src/icons/svg'); +const optimized = resolve(process.cwd(), 'src/icons/optimized'); +const dist = resolve(process.cwd(), 'src/icons/output'); export const optimizeSVG = async () => { - const fixer = new SVGFixer(src, optimized, { - showProgressBar: true, - }); + const fixer = new SVGFixer(src, optimized, { + showProgressBar: true + }); - await fixer.fix(); + await fixer.fix(); }; export const generateIcons = async () => { - await svgtofont({ - classNamePrefix: "web-icon", - src: optimized, - dist: dist, - fontName: "web-icon", - styleTemplates: resolve(process.cwd(), "src/icons/templates"), - css: { - fontSize: "20px", - }, - outSVGReact: false, - svgicons2svgfont: { - centerHorizontally: true, - centerVertically: true, - fixedWidth: true, - fontHeight: 1000, - normalize: true, - descent: 200, - }, - emptyDist: true, - generateInfoData: true, - }); + await svgtofont({ + classNamePrefix: 'web-icon', + src: optimized, + dist: dist, + fontName: 'web-icon', + styleTemplates: resolve(process.cwd(), 'src/icons/templates'), + css: { + fontSize: '20px' + }, + outSVGReact: false, + svgicons2svgfont: { + centerHorizontally: true, + centerVertically: true, + fixedWidth: true, + fontHeight: 1000, + normalize: true, + descent: 200 + }, + emptyDist: true, + generateInfoData: true + }); }; diff --git a/src/lib/UI/Media.svelte b/src/lib/UI/Media.svelte index 13265c53c..b00d1c838 100644 --- a/src/lib/UI/Media.svelte +++ b/src/lib/UI/Media.svelte @@ -1,20 +1,20 @@ {#if isVideo} - - + + {:else} - + {/if} diff --git a/src/lib/UI/Tabs/Content.svelte b/src/lib/UI/Tabs/Content.svelte index 753e22f07..632c7f23c 100644 --- a/src/lib/UI/Tabs/Content.svelte +++ b/src/lib/UI/Tabs/Content.svelte @@ -1,14 +1,14 @@
- +
diff --git a/src/lib/UI/Tabs/List.svelte b/src/lib/UI/Tabs/List.svelte index 9ff8330a0..5c14eb940 100644 --- a/src/lib/UI/Tabs/List.svelte +++ b/src/lib/UI/Tabs/List.svelte @@ -1,31 +1,31 @@
    - {#each tabs as tab} -
  • - -
  • - {/each} + {#each tabs as tab} +
  • + +
  • + {/each}
diff --git a/src/lib/UI/Tabs/index.svelte b/src/lib/UI/Tabs/index.svelte index 2bb462f6a..56a0795ab 100644 --- a/src/lib/UI/Tabs/index.svelte +++ b/src/lib/UI/Tabs/index.svelte @@ -1,45 +1,45 @@
- +
diff --git a/src/lib/UI/index.ts b/src/lib/UI/index.ts index b70f898a4..ec5c08c6e 100644 --- a/src/lib/UI/index.ts +++ b/src/lib/UI/index.ts @@ -1,2 +1,2 @@ -export { default as Tabs } from "./Tabs/index.svelte"; -export { default as Media } from "./Media.svelte"; +export { default as Tabs } from './Tabs/index.svelte'; +export { default as Media } from './Media.svelte'; diff --git a/src/lib/actions/autoHash.ts b/src/lib/actions/autoHash.ts index 5bc1b32ff..e14487e50 100644 --- a/src/lib/actions/autoHash.ts +++ b/src/lib/actions/autoHash.ts @@ -1,12 +1,12 @@ export const autoHash = ( - node: Element, - callback: (entries: IntersectionObserverEntry[]) => void, + node: Element, + callback: (entries: IntersectionObserverEntry[]) => void ) => { - const observer = new IntersectionObserver(callback, { - threshold: 1, - }); + const observer = new IntersectionObserver(callback, { + threshold: 1 + }); - observer.observe(node); + observer.observe(node); - return { destroy: () => observer.disconnect() }; + return { destroy: () => observer.disconnect() }; }; diff --git a/src/lib/actions/clickOutside.ts b/src/lib/actions/clickOutside.ts index 3d1acc3ef..47a28d9bd 100644 --- a/src/lib/actions/clickOutside.ts +++ b/src/lib/actions/clickOutside.ts @@ -1,18 +1,15 @@ -export function clickOutside( - node: HTMLElement, - callback: (e: MouseEvent) => void, -) { - const handleClick = (event: MouseEvent) => { - if (node && !node.contains(event.target as Node)) { - callback(event); - } - }; +export function clickOutside(node: HTMLElement, callback: (e: MouseEvent) => void) { + const handleClick = (event: MouseEvent) => { + if (node && !node.contains(event.target as Node)) { + callback(event); + } + }; - document.addEventListener("click", handleClick, true); + document.addEventListener('click', handleClick, true); - return { - destroy() { - document.removeEventListener("click", handleClick, true); - }, - }; + return { + destroy() { + document.removeEventListener('click', handleClick, true); + } + }; } diff --git a/src/lib/actions/highlight.ts b/src/lib/actions/highlight.ts index dcb60850d..8055de859 100644 --- a/src/lib/actions/highlight.ts +++ b/src/lib/actions/highlight.ts @@ -1,6 +1,6 @@ export const highlight = (node: HTMLElement, text: string[]) => { - text.forEach((word) => { - const regex = new RegExp(`(${word})`, "gi"); - node.innerHTML = node.innerHTML.replace(regex, "$1"); - }); + text.forEach((word) => { + const regex = new RegExp(`(${word})`, 'gi'); + node.innerHTML = node.innerHTML.replace(regex, '$1'); + }); }; diff --git a/src/lib/actions/index.ts b/src/lib/actions/index.ts index dae59d586..63d2e52fd 100644 --- a/src/lib/actions/index.ts +++ b/src/lib/actions/index.ts @@ -1,3 +1,3 @@ -export * from "./portal"; -export * from "./rect"; -export * from "./visible"; +export * from './portal'; +export * from './rect'; +export * from './visible'; diff --git a/src/lib/actions/portal.ts b/src/lib/actions/portal.ts index 521735d8a..8f9d12dbd 100644 --- a/src/lib/actions/portal.ts +++ b/src/lib/actions/portal.ts @@ -1,58 +1,55 @@ -import { tick } from "svelte"; -import type { Action } from "svelte/action"; +import { tick } from 'svelte'; +import type { Action } from 'svelte/action'; export type PortalConfig = - | { target?: string | HTMLElement | undefined; prepend?: boolean } - | undefined; + | { target?: string | HTMLElement | undefined; prepend?: boolean } + | undefined; const defaults: PortalConfig = { - target: "body", - prepend: false, + target: 'body', + prepend: false }; -export const portal: Action = ( - el, - config?: PortalConfig, -) => { - let targetEl; +export const portal: Action = (el, config?: PortalConfig) => { + let targetEl; - async function update(newConfig: PortalConfig) { - const { target, prepend } = { ...defaults, ...newConfig }; + async function update(newConfig: PortalConfig) { + const { target, prepend } = { ...defaults, ...newConfig }; - if (typeof target === "string") { - targetEl = document.querySelector(target); - if (targetEl === null) { - await tick(); - targetEl = document.querySelector(target); - } - if (targetEl === null) { - throw new Error(`No element found matching css selector: "${target}"`); - } - } else if (target instanceof HTMLElement) { - targetEl = target; - } else { - throw new TypeError( - `Unknown portal target type: ${ - target === null ? "null" : typeof target - }. Allowed types: string (CSS selector) or HTMLElement.`, - ); + if (typeof target === 'string') { + targetEl = document.querySelector(target); + if (targetEl === null) { + await tick(); + targetEl = document.querySelector(target); + } + if (targetEl === null) { + throw new Error(`No element found matching css selector: "${target}"`); + } + } else if (target instanceof HTMLElement) { + targetEl = target; + } else { + throw new TypeError( + `Unknown portal target type: ${ + target === null ? 'null' : typeof target + }. Allowed types: string (CSS selector) or HTMLElement.` + ); + } + el.dataset.portal = ''; + if (prepend) { + targetEl.prepend(el); + } else { + targetEl.appendChild(el); + } + el.hidden = false; } - el.dataset.portal = ""; - if (prepend) { - targetEl.prepend(el); - } else { - targetEl.appendChild(el); + + function destroy() { + el.remove(); } - el.hidden = false; - } - function destroy() { - el.remove(); - } - - update(config ?? {}); - return { - update, - destroy, - }; + update(config ?? {}); + return { + update, + destroy + }; }; diff --git a/src/lib/actions/rect.ts b/src/lib/actions/rect.ts index c9176c5aa..7a7bc82f1 100644 --- a/src/lib/actions/rect.ts +++ b/src/lib/actions/rect.ts @@ -1,28 +1,28 @@ -import type { Action } from "svelte/action"; -import type { Writable } from "svelte/store"; +import type { Action } from 'svelte/action'; +import type { Writable } from 'svelte/store'; type Args = Writable; export const rect: Action = (node, store) => { - let observer: ResizeObserver | null = null; - const update = (store: Args) => { - observer?.disconnect(); + let observer: ResizeObserver | null = null; + const update = (store: Args) => { + observer?.disconnect(); - store.set(node.getBoundingClientRect()); + store.set(node.getBoundingClientRect()); - // Observe resize - observer = new ResizeObserver(() => { - store.set(node.getBoundingClientRect()); - }); - observer.observe(node); - }; + // Observe resize + observer = new ResizeObserver(() => { + store.set(node.getBoundingClientRect()); + }); + observer.observe(node); + }; - update(store); + update(store); - return { - update, - destroy() { - // no-op - }, - }; + return { + update, + destroy() { + // no-op + } + }; }; diff --git a/src/lib/actions/scrollToTop.ts b/src/lib/actions/scrollToTop.ts index c05240269..c2f09f2eb 100644 --- a/src/lib/actions/scrollToTop.ts +++ b/src/lib/actions/scrollToTop.ts @@ -1,16 +1,16 @@ export const scrollToTop = (node: HTMLElement) => { - const handleClick = () => { - window.scrollTo({ - top: 0, - behavior: "smooth", - }); - }; + const handleClick = () => { + window.scrollTo({ + top: 0, + behavior: 'smooth' + }); + }; - node.addEventListener("click", handleClick); + node.addEventListener('click', handleClick); - return { - destroy() { - node.removeEventListener("click", handleClick); - }, - }; + return { + destroy() { + node.removeEventListener('click', handleClick); + } + }; }; diff --git a/src/lib/actions/visible.ts b/src/lib/actions/visible.ts index cd24f108b..11933b2e5 100644 --- a/src/lib/actions/visible.ts +++ b/src/lib/actions/visible.ts @@ -1,58 +1,58 @@ -import { isVisible } from "$lib/utils/isVisible"; -import type { Action } from "svelte/action"; +import { isVisible } from '$lib/utils/isVisible'; +import type { Action } from 'svelte/action'; type Args = - | { - top?: number; - bottom?: number; - left?: number; - right?: number; - } - | undefined; + | { + top?: number; + bottom?: number; + left?: number; + right?: number; + } + | undefined; export const visible: Action< - HTMLElement, - Args, - { "on:visible": (e: CustomEvent) => void } + HTMLElement, + Args, + { 'on:visible': (e: CustomEvent) => void } > = (node, args) => { - let visible = false; + let visible = false; - const createVisibilityHandler = (newArgs: Args) => { - const argsWithDefaults = { - top: 0, - bottom: window.innerHeight, - left: 0, - right: window.innerWidth, - ...newArgs, + const createVisibilityHandler = (newArgs: Args) => { + const argsWithDefaults = { + top: 0, + bottom: window.innerHeight, + left: 0, + right: window.innerWidth, + ...newArgs + }; + return () => { + visible = isVisible(node, argsWithDefaults); + node.dispatchEvent(new CustomEvent('visible', { detail: visible })); + }; }; - return () => { - visible = isVisible(node, argsWithDefaults); - node.dispatchEvent(new CustomEvent("visible", { detail: visible })); + + let handleVisibility = createVisibilityHandler(args); + handleVisibility(); + + function destroy() { + window.removeEventListener('scroll', handleVisibility); + window.removeEventListener('resize', handleVisibility); + } + + function update(args: Args) { + destroy(); + handleVisibility = createVisibilityHandler(args); + window.addEventListener('scroll', handleVisibility); + window.addEventListener('resize', handleVisibility); + } + + update(args); + + return { + update, + destroy() { + window.removeEventListener('scroll', handleVisibility); + window.removeEventListener('resize', handleVisibility); + } }; - }; - - let handleVisibility = createVisibilityHandler(args); - handleVisibility(); - - function destroy() { - window.removeEventListener("scroll", handleVisibility); - window.removeEventListener("resize", handleVisibility); - } - - function update(args: Args) { - destroy(); - handleVisibility = createVisibilityHandler(args); - window.addEventListener("scroll", handleVisibility); - window.addEventListener("resize", handleVisibility); - } - - update(args); - - return { - update, - destroy() { - window.removeEventListener("scroll", handleVisibility); - window.removeEventListener("resize", handleVisibility); - }, - }; }; diff --git a/src/lib/animations/AutoBox.svelte b/src/lib/animations/AutoBox.svelte index 8e10a65f5..328232490 100644 --- a/src/lib/animations/AutoBox.svelte +++ b/src/lib/animations/AutoBox.svelte @@ -1,34 +1,34 @@
-
-
- -
+
+
+ +
diff --git a/src/lib/animations/CodeWindow/Code.svelte b/src/lib/animations/CodeWindow/Code.svelte index cee26a675..30e781742 100644 --- a/src/lib/animations/CodeWindow/Code.svelte +++ b/src/lib/animations/CodeWindow/Code.svelte @@ -1,10 +1,10 @@ diff --git a/src/lib/animations/CodeWindow/CodeWindow.svelte b/src/lib/animations/CodeWindow/CodeWindow.svelte index 143326c6a..abb5413fc 100644 --- a/src/lib/animations/CodeWindow/CodeWindow.svelte +++ b/src/lib/animations/CodeWindow/CodeWindow.svelte @@ -1,100 +1,96 @@
-
-
-
-
-
-
- - - -
-
+
+
+
+
+
+
+ + + +
+
diff --git a/src/lib/animations/OpenSource.svelte b/src/lib/animations/OpenSource.svelte index bc1bea291..816be5332 100644 --- a/src/lib/animations/OpenSource.svelte +++ b/src/lib/animations/OpenSource.svelte @@ -1,407 +1,387 @@
{ - const { percentage } = detail; - scrollHandler(percentage); - }} - on:web-resize={({ detail }) => { - scrollHandler.reset(); - const { percentage } = detail; + id="open-source" + use:scroll + on:web-scroll={({ detail }) => { + const { percentage } = detail; + scrollHandler(percentage); + }} + on:web-resize={({ detail }) => { + scrollHandler.reset(); + const { percentage } = detail; - scrollHandler(percentage); - }} + scrollHandler(percentage); + }} > -
-

Powered by Open Source

+ diff --git a/src/lib/animations/Phone.svelte b/src/lib/animations/Phone.svelte index 53a73079c..1014d12f0 100644 --- a/src/lib/animations/Phone.svelte +++ b/src/lib/animations/Phone.svelte @@ -1,9 +1,9 @@
-
- -
+
+ +
diff --git a/src/lib/animations/Products/AnimatedBox.svelte b/src/lib/animations/Products/AnimatedBox.svelte index e5535e947..1dc705c18 100644 --- a/src/lib/animations/Products/AnimatedBox.svelte +++ b/src/lib/animations/Products/AnimatedBox.svelte @@ -1,55 +1,55 @@
-
-
- - - -
+
+
+ + + +
diff --git a/src/lib/animations/Products/Products.svelte b/src/lib/animations/Products/Products.svelte index fc1b4352d..eac54635e 100644 --- a/src/lib/animations/Products/Products.svelte +++ b/src/lib/animations/Products/Products.svelte @@ -1,703 +1,696 @@
{ - scrollInfo = detail; - }} + id="products" + use:scroll + on:web-scroll={({ detail }) => { + scrollInfo = detail; + }} > -
- - {#if scrollInfo.percentage < 0.075} -
- {#if scrollInfo.percentage > -0.1} - Products_ + {#if scrollInfo.percentage < 0.075} +
+ {#if scrollInfo.percentage > -0.1} + Products_ -

- Your backend, minus the hassle -

-

- Build secure and scalable applications with less code. Add - authentication, databases, storage, and more using Appwrite's - development platform. -

- {/if} -
- {:else} -
0.075 ? "" : undefined} - > -
- -
    - {#each products as product} - {@const copy = infos[product]} - {@const isActive = active.product === product} - - {#if copy} -
  • -

    - - {copy.title} -

    - {#if isActive} -
    -

    {copy.subtitle}

    -

    - {copy.description} -

    -
      - {#each copy.features as feature} -
    • {feature}
    • - {/each} -
    -
    - {/if} -
  • - {/if} - {/each} -
-
- -
-
- -
-

- {#if active.product === "auth"} - Users - {:else if active.product === "databases"} - Tasks - {:else if active.product === "storage"} - Files - {:else if active.product === "functions"} - - {:else if active.product === "messaging"} - Messages - {:else if active.product === "realtime"} - Realtime - {/if} -

-
- - {#if active.product === "auth"} - - {:else if active.product === "messaging"} - - {:else if active.product === "databases"} - - {:else if active.product === "storage"} - - {/if} -
-
- -
- - {#if active.product === "auth"} - - {:else if active.product === "databases"} - - {:else if active.product === "storage"} - - {:else if active.product === "functions"} - - {:else if active.product === "messaging"} - - {/if} - -
- - {#if active.product === "auth"} -
- +

+ Your backend, minus the hassle +

+

+ Build secure and scalable applications with less code. Add authentication, + databases, storage, and more using Appwrite's development platform. +

+ {/if}
- {/if} -
+ {:else} +
0.075 ? '' : undefined} + > +
+ +
    + {#each products as product} + {@const copy = infos[product]} + {@const isActive = active.product === product} -
    -
    - {#if active.product === "auth"} - - {:else if active.product === "databases"} - - {:else if active.product === "storage"} - - {:else if active.product === "messaging"} - - {:else if active.product === "functions"} - - {:else if !["auth", "databases", "storage", "messaging", "functions"].includes(active.product)} - - {/if} -
    -
    + {#if copy} +
  • +

    + + {copy.title} +

    + {#if isActive} +
    +

    {copy.subtitle}

    +

    + {copy.description} +

    +
      + {#each copy.features as feature} +
    • {feature}
    • + {/each} +
    +
    + {/if} +
  • + {/if} + {/each} +
+
- {#if !["auth", "databases", "storage", "functions", "messaging", "realtime"].includes(anyify(active.product))} - +
+
+ +
+

+ {#if active.product === 'auth'} + Users + {:else if active.product === 'databases'} + Tasks + {:else if active.product === 'storage'} + Files + {:else if active.product === 'functions'} + + {:else if active.product === 'messaging'} + Messages + {:else if active.product === 'realtime'} + Realtime + {/if} +

+
+ + {#if active.product === 'auth'} + + {:else if active.product === 'messaging'} + + {:else if active.product === 'databases'} + + {:else if active.product === 'storage'} + + {/if} +
+
+ +
+ + {#if active.product === 'auth'} + + {:else if active.product === 'databases'} + + {:else if active.product === 'storage'} + + {:else if active.product === 'functions'} + + {:else if active.product === 'messaging'} + + {/if} + +
+ + {#if active.product === 'auth'} +
+ +
+ {/if} +
+ +
+
+ {#if active.product === 'auth'} + + {:else if active.product === 'databases'} + + {:else if active.product === 'storage'} + + {:else if active.product === 'messaging'} + + {:else if active.product === 'functions'} + + {:else if !['auth', 'databases', 'storage', 'messaging', 'functions'].includes(active.product)} + + {/if} +
+
+ + {#if !['auth', 'databases', 'storage', 'functions', 'messaging', 'realtime'].includes(anyify(active.product))} + + {/if} +
{/if} -
- {/if} -
+
diff --git a/src/lib/animations/Products/ProductsMobile.svelte b/src/lib/animations/Products/ProductsMobile.svelte index 8888a3fc5..66e23bb82 100644 --- a/src/lib/animations/Products/ProductsMobile.svelte +++ b/src/lib/animations/Products/ProductsMobile.svelte @@ -1,224 +1,220 @@
-
- Products_ +
+ Products_ -

- Your backend, minus the hassle -

+

Your backend, minus the hassle

-

- Build secure and scalable applications with less code. Add authentication, - databases, storage, and more using Appwrite's development platform. -

+

+ Build secure and scalable applications with less code. Add authentication, databases, + storage, and more using Appwrite's development platform. +

-
- {#each objectKeys(infos) as prod, i} - {@const info = infos[prod]} - {@const isLast = i === objectKeys(infos).length - 1} +
+ {#each objectKeys(infos) as prod, i} + {@const info = infos[prod]} + {@const isLast = i === objectKeys(infos).length - 1} - {#if info} -
-

- - {info.title} -

+ {#if info} +
+

+ + {info.title} +

-

{info.subtitle}

+

{info.subtitle}

+

+ {info.description} +

+
    + {#each info.features as feature} +
  • {feature}
  • + {/each} +
+ + {#if info.shot} + + {/if} +
+ + {#if !isLast} +
+ {/if} + {/if} + {/each} +
+ +
+ + +

See your products grow

- {info.description} + Keep track of your projects progress on the Appwrite Console and see them grow into + products users love and use every day.

-
    - {#each info.features as feature} -
  • {feature}
  • - {/each} -
- - {#if info.shot} - - {/if} -
- - {#if !isLast} -
- {/if} - {/if} - {/each} +
- -
- - -

See your products grow

-

- Keep track of your projects progress on the Appwrite Console and see - them grow into products users love and use every day. -

-
-
-
+
diff --git a/src/lib/animations/Products/TaskCheckbox.svelte b/src/lib/animations/Products/TaskCheckbox.svelte index db4b89c76..bdfc8dbc5 100644 --- a/src/lib/animations/Products/TaskCheckbox.svelte +++ b/src/lib/animations/Products/TaskCheckbox.svelte @@ -1,61 +1,61 @@
- +
diff --git a/src/lib/animations/Products/auth/box.svelte b/src/lib/animations/Products/auth/box.svelte index 5a8cf3706..0589de482 100644 --- a/src/lib/animations/Products/auth/box.svelte +++ b/src/lib/animations/Products/auth/box.svelte @@ -1,64 +1,64 @@
-
- Name - Identifier -
- {#each authData as user (user.id)} -
-
-
{user.avatar}
- {user.name} -
- {user.email} +
+ Name + Identifier
- {/each} + {#each authData as user (user.id)} +
+
+
{user.avatar}
+ {user.name} +
+ {user.email} +
+ {/each}
diff --git a/src/lib/animations/Products/auth/code.svelte b/src/lib/animations/Products/auth/code.svelte index 9b59647af..5bc78f46b 100644 --- a/src/lib/animations/Products/auth/code.svelte +++ b/src/lib/animations/Products/auth/code.svelte @@ -1,10 +1,10 @@
- {#each objectKeys($state.controls) as provider, i} - {@const isLast = i === objectKeys($state.controls).length - 1} -
- - {provider} - -
- {#if !isLast} -
- {/if} - {/each} + {#each objectKeys($state.controls) as provider, i} + {@const isLast = i === objectKeys($state.controls).length - 1} +
+ + {provider} + +
+ {#if !isLast} +
+ {/if} + {/each}
diff --git a/src/lib/animations/Products/auth/index.ts b/src/lib/animations/Products/auth/index.ts index 12eed3c07..ea4ad63d0 100644 --- a/src/lib/animations/Products/auth/index.ts +++ b/src/lib/animations/Products/auth/index.ts @@ -1,110 +1,95 @@ -import Box from "./box.svelte"; -import Code from "./code.svelte"; -import Controls from "./controls.svelte"; -import Phone from "./phone.svelte"; +import Box from './box.svelte'; +import Code from './code.svelte'; +import Controls from './controls.svelte'; +import Phone from './phone.svelte'; export const Auth = { - Phone, - Box, - Code, - Controls, + Phone, + Box, + Code, + Controls }; -import { safeAnimate, sleep, write } from "$lib/animations"; -import { createResettable } from "$lib/utils/resettable"; -import { getElSelector } from "../Products.svelte"; +import { safeAnimate, sleep, write } from '$lib/animations'; +import { createResettable } from '$lib/utils/resettable'; +import { getElSelector } from '../Products.svelte'; type State = { - email: string; - password: string; - name: string; + email: string; + password: string; + name: string; - showControls: boolean; - submitted: boolean; - controls: { - GitHub: boolean; - Google: boolean; - Apple: boolean; - Microsoft: boolean; - }; + showControls: boolean; + submitted: boolean; + controls: { + GitHub: boolean; + Google: boolean; + Apple: boolean; + Microsoft: boolean; + }; }; const state = createResettable({ - email: "", - password: "", - name: "Walter O'Brian", - showControls: false, - submitted: false, - controls: { - GitHub: true, - Google: false, - Apple: false, - Microsoft: false, - }, + email: '', + password: '', + name: "Walter O'Brian", + showControls: false, + submitted: false, + controls: { + GitHub: true, + Google: false, + Apple: false, + Microsoft: false + } }); -const emailToSet = "walterobrian@example.com"; -const passwordToSet = "password"; +const emailToSet = 'walterobrian@example.com'; +const passwordToSet = 'password'; const execute = async () => { - const phone = getElSelector("phone"); - const box = getElSelector("box"); - const code = getElSelector("code"); - const controls = getElSelector("controls"); + const phone = getElSelector('phone'); + const box = getElSelector('box'); + const code = getElSelector('code'); + const controls = getElSelector('controls'); - // Reset - const { update } = state.reset(); + // Reset + const { update } = state.reset(); - await Promise.all([ - safeAnimate(box, { x: 310, y: 140, opacity: 0 }, { duration: 0.5 }) - ?.finished, - safeAnimate(code, { x: 200, y: 460, opacity: 0 }, { duration: 0.5 }) - ?.finished, - safeAnimate(phone, { x: 0, y: 0 }, { duration: 0.5 })?.finished, - safeAnimate(controls, { x: 420, y: 0, opacity: 0 }, { duration: 0.5 }) - ?.finished, - ]); + await Promise.all([ + safeAnimate(box, { x: 310, y: 140, opacity: 0 }, { duration: 0.5 })?.finished, + safeAnimate(code, { x: 200, y: 460, opacity: 0 }, { duration: 0.5 })?.finished, + safeAnimate(phone, { x: 0, y: 0 }, { duration: 0.5 })?.finished, + safeAnimate(controls, { x: 420, y: 0, opacity: 0 }, { duration: 0.5 })?.finished + ]); - // Start - await safeAnimate( - box, - { y: [48, 140], opacity: 1 }, - { duration: 0.25, delay: 0.25 }, - )?.finished; + // Start + await safeAnimate(box, { y: [48, 140], opacity: 1 }, { duration: 0.25, delay: 0.25 })?.finished; - await sleep(50); + await sleep(50); - await write(emailToSet, (v) => update((p) => ({ ...p, email: v })), 300); - await sleep(50); + await write(emailToSet, (v) => update((p) => ({ ...p, email: v })), 300); + await sleep(50); - await write( - passwordToSet, - (v) => update((p) => ({ ...p, password: v })), - 300, - ); - await sleep(50); + await write(passwordToSet, (v) => update((p) => ({ ...p, password: v })), 300); + await sleep(50); - await safeAnimate( - code, - { x: [200, 200], y: [460 + 16, 460], opacity: [0, 1] }, - { duration: 0.25 }, - )?.finished; + await safeAnimate( + code, + { x: [200, 200], y: [460 + 16, 460], opacity: [0, 1] }, + { duration: 0.25 } + )?.finished; - await sleep(350); + await sleep(350); - update((p) => ({ ...p, submitted: true })); + update((p) => ({ ...p, submitted: true })); - await sleep(1000); + await sleep(1000); - update((p) => ({ ...p, showControls: true })); - safeAnimate( - controls, - { x: [420, 420], y: [16, 0], opacity: 1 }, - { duration: 0.5 }, - ); + update((p) => ({ ...p, showControls: true })); + safeAnimate(controls, { x: [420, 420], y: [16, 0], opacity: 1 }, { duration: 0.5 }); }; export const authController = { - execute, - state, + execute, + state }; diff --git a/src/lib/animations/Products/auth/phone.svelte b/src/lib/animations/Products/auth/phone.svelte index ffb13ce46..a10054a12 100644 --- a/src/lib/animations/Products/auth/phone.svelte +++ b/src/lib/animations/Products/auth/phone.svelte @@ -1,229 +1,220 @@
-

Create an Account

-

Please enter your details

-
-
- - -
-
- - -
-
- - -
-
- - {#if controlsEnabled} - or sign up with -
- {#each objectKeys($state.controls).filter((p) => $state.controls[p]) as provider (provider)} - - {/each} +

Create an Account

+

Please enter your details

+
+
+ + +
+
+ + +
+
+ + +
- {/if} + + {#if controlsEnabled} + or sign up with +
+ {#each objectKeys($state.controls).filter((p) => $state.controls[p]) as provider (provider)} + + {/each} +
+ {/if}
diff --git a/src/lib/animations/Products/databases/box.svelte b/src/lib/animations/Products/databases/box.svelte index b4931c7ef..7b449c4e9 100644 --- a/src/lib/animations/Products/databases/box.svelte +++ b/src/lib/animations/Products/databases/box.svelte @@ -1,58 +1,54 @@
-
- Document ID - Task -
- {#each $state.tasks.slice(0, $state.tableSlice) as task (task.id)} -
-
- - {task.id} -
- {task.title} +
+ Document ID + Task
- {/each} + {#each $state.tasks.slice(0, $state.tableSlice) as task (task.id)} +
+
+ + {task.id} +
+ {task.title} +
+ {/each}
diff --git a/src/lib/animations/Products/databases/code.svelte b/src/lib/animations/Products/databases/code.svelte index de2f230c1..b42ba7e18 100644 --- a/src/lib/animations/Products/databases/code.svelte +++ b/src/lib/animations/Products/databases/code.svelte @@ -1,7 +1,7 @@
-
-

Your tasks

- -
+
+

Your tasks

+ +
-
Today
-
- {#each $state.tasks as task (task.id)} -
- - {task.title} -
- {/each} -
+
Today
+
+ {#each $state.tasks as task (task.id)} +
+ + {task.title} +
+ {/each} +
- +
diff --git a/src/lib/animations/Products/functions/code.svelte b/src/lib/animations/Products/functions/code.svelte index 792959f65..fdeff2264 100644 --- a/src/lib/animations/Products/functions/code.svelte +++ b/src/lib/animations/Products/functions/code.svelte @@ -1,10 +1,10 @@ -
- {#if $state.submit !== "idle"} - - {/if} - {#if $state.submit === "loading"} - Pushing to GitHub... -
- {:else if $state.submit === "success"} - Deployed to Appwrite Cloud - - {/if} +
+ {#if $state.submit !== 'idle'} + + {/if} + {#if $state.submit === 'loading'} + Pushing to GitHub... +
+ {:else if $state.submit === 'success'} + Deployed to Appwrite Cloud + + {/if}
diff --git a/src/lib/animations/Products/functions/index.ts b/src/lib/animations/Products/functions/index.ts index 4aac6330d..0c17bbc04 100644 --- a/src/lib/animations/Products/functions/index.ts +++ b/src/lib/animations/Products/functions/index.ts @@ -1,61 +1,58 @@ -import Code from "./code.svelte"; -import Phone from "./phone.svelte"; +import Code from './code.svelte'; +import Phone from './phone.svelte'; -import { safeAnimate, sleep } from "$lib/animations"; -import { createResettable } from "$lib/utils/resettable"; -import { getElSelector } from "../Products.svelte"; +import { safeAnimate, sleep } from '$lib/animations'; +import { createResettable } from '$lib/utils/resettable'; +import { getElSelector } from '../Products.svelte'; type State = { - submit: "idle" | "loading" | "success"; + submit: 'idle' | 'loading' | 'success'; }; const state = createResettable({ - submit: "idle", + submit: 'idle' }); const execute = async () => { - const phone = getElSelector("phone"); - const box = getElSelector("box"); - const code = getElSelector("code"); + const phone = getElSelector('phone'); + const box = getElSelector('box'); + const code = getElSelector('code'); - const { update } = state.reset(); + const { update } = state.reset(); - await Promise.all([ - safeAnimate(phone, { x: 430, y: 0, width: "275px" }, { duration: 0.5 }) - ?.finished, - safeAnimate(code, { x: 0, y: 200, opacity: 0 }, { duration: 0.5 }) - ?.finished, - safeAnimate(box, { opacity: 0 }, { duration: 0.5 })?.finished, - ]); + await Promise.all([ + safeAnimate(phone, { x: 430, y: 0, width: '275px' }, { duration: 0.5 })?.finished, + safeAnimate(code, { x: 0, y: 200, opacity: 0 }, { duration: 0.5 })?.finished, + safeAnimate(box, { opacity: 0 }, { duration: 0.5 })?.finished + ]); - await sleep(250); + await sleep(250); - await safeAnimate(code, { zIndex: 0 }, { duration: 0 })?.finished; - await safeAnimate(code, { y: [200 - 16, 200], opacity: 1 }, { duration: 0.5 }) - ?.finished; + await safeAnimate(code, { zIndex: 0 }, { duration: 0 })?.finished; + await safeAnimate(code, { y: [200 - 16, 200], opacity: 1 }, { duration: 0.5 })?.finished; - await sleep(250); + await sleep(250); - update((p) => ({ - ...p, - submit: "loading", - })); + update((p) => ({ + ...p, + submit: 'loading' + })); - await sleep(1500); + await sleep(1500); - update((p) => ({ - ...p, - submit: "success", - })); + update((p) => ({ + ...p, + submit: 'success' + })); }; export const functionsController = { - execute, - state, + execute, + state }; export const Functions = { - Phone, + Phone, - Code, + Code }; diff --git a/src/lib/animations/Products/functions/phone.svelte b/src/lib/animations/Products/functions/phone.svelte index f3209bf65..c162fe3a9 100644 --- a/src/lib/animations/Products/functions/phone.svelte +++ b/src/lib/animations/Products/functions/phone.svelte @@ -1,325 +1,325 @@
-
-

Upgrade plan

- -
- -
-

Premium plan

-
-

$20

-

/month

+
+

Upgrade plan

+
-
    -
  • Premium plan
  • -
  • Premium plan
  • -
  • Premium plan
  • + +
    +

    Premium plan

    +
    +

    $20

    +

    /month

    +
    +
      +
    • Premium plan
    • +
    • Premium plan
    • +
    • Premium plan
    • +
    +
    + +
      + {#each methods as method, i (method.label)} +
    • + +

      {method.label}

      +
    • + {/each}
    -
-
    - {#each methods as method, i (method.label)} -
  • - -

    {method.label}

    -
  • - {/each} -
- - {#if $state.submit !== "success"} -
-

Card information

-
-
-

placeholder

- - + {#if $state.submit !== 'success'} +
+

Card information

+
+
+

placeholder

+ + +
+
+

MM/YY

+

CVV

+
+
-
-

MM/YY

-

CVV

-
-
-
- {/if} - - + +
diff --git a/src/lib/animations/Products/messaging/box.svelte b/src/lib/animations/Products/messaging/box.svelte index b4e64b923..b53af040c 100644 --- a/src/lib/animations/Products/messaging/box.svelte +++ b/src/lib/animations/Products/messaging/box.svelte @@ -1,120 +1,116 @@
-
- Message ID - Type - Status -
- {#each $state.messages.slice(0, $state.tableSlice) as task (task.id)} -
-
- - {task.id} -
-
-
- -
- {task.type} -
- -
- {#if task.status === "sending"} -
- {:else} - - {/if} -
+
+ Message ID + Type + Status
- {/each} + {#each $state.messages.slice(0, $state.tableSlice) as task (task.id)} +
+
+ + {task.id} +
+
+
+ +
+ {task.type} +
+ +
+ {#if task.status === 'sending'} +
+ {:else} + + {/if} +
+
+ {/each}
diff --git a/src/lib/animations/Products/messaging/code.svelte b/src/lib/animations/Products/messaging/code.svelte index 7635b0e55..52854edca 100644 --- a/src/lib/animations/Products/messaging/code.svelte +++ b/src/lib/animations/Products/messaging/code.svelte @@ -1,10 +1,10 @@ -{#if $state.submit === "success"} -
-
-
-
-

New task assigned to you

- now -
-

- You were assigned a new task in your board. Tap to check it out. -

+{#if $state.submit === 'success'} +
+
+
+
+

New task assigned to you

+ now +
+

You were assigned a new task in your board. Tap to check it out.

+
-
{/if}
-
-

Your tasks

- -
+
+

Your tasks

+ +
-
Today
-
- {#each $state.tasks as task (task.id)} -
- - {task.title} -
- {/each} -
- +
Today
+
+ {#each $state.tasks as task (task.id)} +
+ + {task.title} +
+ {/each} +
+
diff --git a/src/lib/animations/Products/post/index.ts b/src/lib/animations/Products/post/index.ts index dcee0fd0a..b198bc6a7 100644 --- a/src/lib/animations/Products/post/index.ts +++ b/src/lib/animations/Products/post/index.ts @@ -1,7 +1,7 @@ -import { safeAnimate, sleep } from "$lib/animations"; -import { createResettable } from "$lib/utils/resettable"; -import { animate } from "motion"; -import { getElSelector } from "../Products.svelte"; +import { safeAnimate, sleep } from '$lib/animations'; +import { createResettable } from '$lib/utils/resettable'; +import { animate } from 'motion'; +import { getElSelector } from '../Products.svelte'; const requests = createResettable(0); const databases = createResettable(0); @@ -12,54 +12,42 @@ const executions = createResettable(0); const realtime = createResettable(0); const execute = async () => { - const phone = getElSelector("phone"); - const pd = getElSelector("pd"); + const phone = getElSelector('phone'); + const pd = getElSelector('pd'); - const graphBox = getElSelector("graph-box"); + const graphBox = getElSelector('graph-box'); - const boxesAndStates = [ - { box: getElSelector("post-auth"), state: authentication.reset() }, - { box: getElSelector("post-storage"), state: storage.reset() }, - { box: getElSelector("post-bandwidth"), state: bandwidth.reset() }, - { box: getElSelector("post-functions"), state: executions.reset() }, - { box: getElSelector("post-databases"), state: databases.reset() }, - { box: getElSelector("post-realtime"), state: realtime.reset() }, - { box: getElSelector("post-requests"), state: requests.reset() }, - ]; + const boxesAndStates = [ + { box: getElSelector('post-auth'), state: authentication.reset() }, + { box: getElSelector('post-storage'), state: storage.reset() }, + { box: getElSelector('post-bandwidth'), state: bandwidth.reset() }, + { box: getElSelector('post-functions'), state: executions.reset() }, + { box: getElSelector('post-databases'), state: databases.reset() }, + { box: getElSelector('post-realtime'), state: realtime.reset() }, + { box: getElSelector('post-requests'), state: requests.reset() } + ]; - await Promise.all([ - safeAnimate(pd, { opacity: 0, y: -16 }, { duration: 0.5 })?.finished, - safeAnimate( - graphBox, - { opacity: 0, visibility: "hidden" }, - { duration: 0.5 }, - )?.finished, - safeAnimate( - phone, - { x: "-50%", width: "660px" }, - { duration: 1, delay: 0.5 }, - )?.finished, - ]); + await Promise.all([ + safeAnimate(pd, { opacity: 0, y: -16 }, { duration: 0.5 })?.finished, + safeAnimate(graphBox, { opacity: 0, visibility: 'hidden' }, { duration: 0.5 })?.finished, + safeAnimate(phone, { x: '-50%', width: '660px' }, { duration: 1, delay: 0.5 })?.finished + ]); - boxesAndStates.forEach(({ box, state }, i) => { - safeAnimate( - box, - { opacity: 1, y: [1200, 0] }, - { duration: 0.5, delay: i * 0.1 }, - )?.finished; - animate(state.set, { duration: 2, delay: (i + 1) * 0.25 }); - }); + boxesAndStates.forEach(({ box, state }, i) => { + safeAnimate(box, { opacity: 1, y: [1200, 0] }, { duration: 0.5, delay: i * 0.1 })?.finished; + animate(state.set, { duration: 2, delay: (i + 1) * 0.25 }); + }); }; export const postController = { - execute, - state: { - requests, - databases, - authentication, - storage, - bandwidth, - executions, - realtime, - }, + execute, + state: { + requests, + databases, + authentication, + storage, + bandwidth, + executions, + realtime + } }; diff --git a/src/lib/animations/Products/post/post.svelte b/src/lib/animations/Products/post/post.svelte index e15714c96..a8fb48c8c 100644 --- a/src/lib/animations/Products/post/post.svelte +++ b/src/lib/animations/Products/post/post.svelte @@ -1,316 +1,308 @@
-
-

-

Authentication

-
-

- {formatK(toScale($authentication, [0, 1], [0, 4000]))} -

-
-

Users

-

Sessions: 20K

-
+
+

+

Authentication

+
+

+ {formatK(toScale($authentication, [0, 1], [0, 4000]))} +

+
+

Users

+

Sessions: 20K

+
-
-

-

Storage

-
-

- {toScale($storage, [0, 1], [0, 8]).toFixed(1)} - GB -

-
-

Storage

-

Buckets: 44

-
+
+

+

Storage

+
+

+ {toScale($storage, [0, 1], [0, 8]).toFixed(1)} + GB +

+
+

Storage

+

Buckets: 44

+
-

- {toScale($bandwidth, [0, 1], [0, 1.2]).toFixed(2)} - GB -

-

Bandwidth

- +

+ {toScale($bandwidth, [0, 1], [0, 1.2]).toFixed(2)} + GB +

+

Bandwidth

+
-
-

-

Functions

-
-

- {toScale($executions, [0, 1], [0, 846]).toFixed(0)} -

-
-

Executions

-
+
+

+

Functions

+
+

+ {toScale($executions, [0, 1], [0, 846]).toFixed(0)} +

+
+

Executions

+
-
-

-

Databases

-
-

- {toScale($databases, [0, 1], [0, 8]).toFixed(0)} -

-
-

Databases

-

Documents: 20

-
+
+

+

Databases

+
+

+ {toScale($databases, [0, 1], [0, 8]).toFixed(0)} +

+
+

Databases

+

Documents: 20

+
-

{formatK(toScale($requests, [0, 1], [0, 6849]))}

-

Requests

- +

{formatK(toScale($requests, [0, 1], [0, 6849]))}

+

Requests

+
-

{formatK(toScale($realtime, [0, 1], [0, 100000]))}

-

Realtime connections

- +

{formatK(toScale($realtime, [0, 1], [0, 100000]))}

+

Realtime connections

+
-

See your products grow

-

- Keep track of your projects progress on the Appwrite Console and see them - grow into products users love and use every day. -

+

See your products grow

+

+ Keep track of your projects progress on the Appwrite Console and see them grow into products + users love and use every day. +

diff --git a/src/lib/animations/Products/realtime/index.ts b/src/lib/animations/Products/realtime/index.ts index 744c267eb..8f3f37613 100644 --- a/src/lib/animations/Products/realtime/index.ts +++ b/src/lib/animations/Products/realtime/index.ts @@ -1,286 +1,238 @@ -import Phone from "./phone.svelte"; +import Phone from './phone.svelte'; -import { safeAnimate, sleep } from "$lib/animations"; -import { createResettable } from "$lib/utils/resettable"; -import { getElSelector } from "../Products.svelte"; -import { animate } from "motion"; +import { safeAnimate, sleep } from '$lib/animations'; +import { createResettable } from '$lib/utils/resettable'; +import { getElSelector } from '../Products.svelte'; +import { animate } from 'motion'; type Task = { - title: string; - tags: string[]; - images?: string[]; + title: string; + tags: string[]; + images?: string[]; }; type User = { - name: string; - color: string; + name: string; + color: string; }; type State = { - tasks: { - todo: Task[]; - doing: Task[]; - done: Task[]; - }; - users: User[]; + tasks: { + todo: Task[]; + doing: Task[]; + done: Task[]; + }; + users: User[]; }; const state = createResettable({ - tasks: { - todo: [ - { - title: "Edit images for website", - tags: ["design", "content"], - images: [ - "./images/animations/storage-2.png", - "./images/animations/storage-3.png", + tasks: { + todo: [ + { + title: 'Edit images for website', + tags: ['design', 'content'], + images: ['./images/animations/storage-2.png', './images/animations/storage-3.png'] + } ], - }, - ], - doing: [ - { - title: "Handoff meet", - tags: ["design", "dev"], - }, - ], - done: [], - }, - users: [], + doing: [ + { + title: 'Handoff meet', + tags: ['design', 'dev'] + } + ], + done: [] + }, + users: [] }); export const connectionsProg = createResettable(0); const addUser = (update: typeof state.update, user: User) => { - update((p) => ({ - ...p, - users: [...p.users, user], - })); + update((p) => ({ + ...p, + users: [...p.users, user] + })); }; -const addTask = ( - update: typeof state.update, - group: keyof State["tasks"], - task: Task, -) => { - update((p) => ({ - ...p, - tasks: { - ...p.tasks, - [group]: [task, ...p.tasks[group]], - }, - })); +const addTask = (update: typeof state.update, group: keyof State['tasks'], task: Task) => { + update((p) => ({ + ...p, + tasks: { + ...p.tasks, + [group]: [task, ...p.tasks[group]] + } + })); }; const execute = async () => { - const phone = getElSelector("phone"); - const code = getElSelector("code"); - const box = getElSelector("box"); + const phone = getElSelector('phone'); + const code = getElSelector('code'); + const box = getElSelector('box'); - const walter = getElSelector("user-Walter"); - const aditya = getElSelector("user-Aditya"); - const sara = getElSelector("user-Sara"); + const walter = getElSelector('user-Walter'); + const aditya = getElSelector('user-Aditya'); + const sara = getElSelector('user-Sara'); - const addTodo = getElSelector("add-todo"); - const addDoing = getElSelector("add-doing"); - const addDone = getElSelector("add-done"); + const addTodo = getElSelector('add-todo'); + const addDoing = getElSelector('add-doing'); + const addDone = getElSelector('add-done'); - const graphBox = getElSelector("graph-box"); + const graphBox = getElSelector('graph-box'); - const pd = getElSelector("pd"); + const pd = getElSelector('pd'); - const { update } = state.reset(); - const { set: setConn } = connectionsProg.reset(); - - await Promise.all([ - safeAnimate(box, { opacity: 0 }, { duration: 0.5 })?.finished, - safeAnimate(phone, { x: 0, y: 0, width: "660px" }, { duration: 0.5 }) - ?.finished, - safeAnimate(code, { opacity: 0 }, { duration: 0.5 })?.finished, - safeAnimate( - graphBox, - { opacity: 0, x: 0, y: 0, visibility: "visible" }, - { duration: 0 }, - )?.finished, - safeAnimate(pd, { opacity: 1, y: 0 }, { duration: 0.5 })?.finished, - ]); - - // Graphbox - sleep(1250).then(async () => { - await safeAnimate(graphBox, { opacity: 1 }, { duration: 0.5 })?.finished; - - animate( - (y) => { - setConn(y); - }, - { duration: 2.5, easing: "ease-in" }, - ); - }); - - // Walter - sleep(500).then(async () => { - addUser(update, { name: "Walter", color: "#fd366e" }); - await sleep(500); - await safeAnimate(walter, { x: -200, y: -100, scale: 1 }, { duration: 0.5 }) - ?.finished; - await Promise.all([ - safeAnimate(walter, { scale: [1, 0.9, 1] }, { duration: 0.25 })?.finished, - safeAnimate(addTodo, { scale: [1, 0.9, 1] }, { duration: 0.25 }) - ?.finished, - ]); - - addTask(update, "todo", { - title: "Handoff meet", - tags: ["design", "dev"], - }); - - await safeAnimate( - walter, - { scale: 1, x: -180, y: -160 }, - { duration: 0.75, delay: 0.5 }, - )?.finished; - - await sleep(500); - - await safeAnimate(walter, { x: 210, y: -100, scale: 1 }, { duration: 0.5 }) - ?.finished; + const { update } = state.reset(); + const { set: setConn } = connectionsProg.reset(); await Promise.all([ - safeAnimate(walter, { scale: [1, 0.9, 1] }, { duration: 0.25 })?.finished, - safeAnimate(addDone, { scale: [1, 0.9, 1] }, { duration: 0.25 }) - ?.finished, + safeAnimate(box, { opacity: 0 }, { duration: 0.5 })?.finished, + safeAnimate(phone, { x: 0, y: 0, width: '660px' }, { duration: 0.5 })?.finished, + safeAnimate(code, { opacity: 0 }, { duration: 0.5 })?.finished, + safeAnimate(graphBox, { opacity: 0, x: 0, y: 0, visibility: 'visible' }, { duration: 0 }) + ?.finished, + safeAnimate(pd, { opacity: 1, y: 0 }, { duration: 0.5 })?.finished ]); - addTask(update, "done", { - title: "Create migrations script", - tags: ["Dev"], + // Graphbox + sleep(1250).then(async () => { + await safeAnimate(graphBox, { opacity: 1 }, { duration: 0.5 })?.finished; + + animate( + (y) => { + setConn(y); + }, + { duration: 2.5, easing: 'ease-in' } + ); }); - safeAnimate( - walter, - { scale: 1, x: 230, y: -20 }, - { duration: 0.75, delay: 0.5 }, - ); + // Walter + sleep(500).then(async () => { + addUser(update, { name: 'Walter', color: '#fd366e' }); + await sleep(500); + await safeAnimate(walter, { x: -200, y: -100, scale: 1 }, { duration: 0.5 })?.finished; + await Promise.all([ + safeAnimate(walter, { scale: [1, 0.9, 1] }, { duration: 0.25 })?.finished, + safeAnimate(addTodo, { scale: [1, 0.9, 1] }, { duration: 0.25 })?.finished + ]); - await sleep(750); + addTask(update, 'todo', { + title: 'Handoff meet', + tags: ['design', 'dev'] + }); - await safeAnimate(walter, { x: -10, y: -100, scale: 1 }, { duration: 0.5 }) - ?.finished; + await safeAnimate(walter, { scale: 1, x: -180, y: -160 }, { duration: 0.75, delay: 0.5 }) + ?.finished; - await Promise.all([ - safeAnimate(walter, { scale: [1, 0.9, 1] }, { duration: 0.25 })?.finished, - safeAnimate(addDoing, { scale: [1, 0.9, 1] }, { duration: 0.25 }) - ?.finished, - ]); + await sleep(500); - addTask(update, "doing", { - title: "Configure blog SEO", - tags: ["dev", "content"], + await safeAnimate(walter, { x: 210, y: -100, scale: 1 }, { duration: 0.5 })?.finished; + + await Promise.all([ + safeAnimate(walter, { scale: [1, 0.9, 1] }, { duration: 0.25 })?.finished, + safeAnimate(addDone, { scale: [1, 0.9, 1] }, { duration: 0.25 })?.finished + ]); + + addTask(update, 'done', { + title: 'Create migrations script', + tags: ['Dev'] + }); + + safeAnimate(walter, { scale: 1, x: 230, y: -20 }, { duration: 0.75, delay: 0.5 }); + + await sleep(750); + + await safeAnimate(walter, { x: -10, y: -100, scale: 1 }, { duration: 0.5 })?.finished; + + await Promise.all([ + safeAnimate(walter, { scale: [1, 0.9, 1] }, { duration: 0.25 })?.finished, + safeAnimate(addDoing, { scale: [1, 0.9, 1] }, { duration: 0.25 })?.finished + ]); + + addTask(update, 'doing', { + title: 'Configure blog SEO', + tags: ['dev', 'content'] + }); + + await safeAnimate(walter, { scale: 1, x: -70, y: 80 }, { duration: 0.75, delay: 0.25 }); }); - await safeAnimate( - walter, - { scale: 1, x: -70, y: 80 }, - { duration: 0.75, delay: 0.25 }, - ); - }); + // Aditya + sleep(1500).then(async () => { + addUser(update, { name: 'Aditya', color: 'rgba(124, 103, 254, 1)' }); + await sleep(500); + await safeAnimate(aditya, { x: 200, y: -100, scale: 1 }, { duration: 0.5 })?.finished; + await Promise.all([ + safeAnimate(aditya, { scale: [1, 0.9, 1] }, { duration: 0.25 })?.finished, + safeAnimate(addDone, { scale: [1, 0.9, 1] }, { duration: 0.25 })?.finished + ]); - // Aditya - sleep(1500).then(async () => { - addUser(update, { name: "Aditya", color: "rgba(124, 103, 254, 1)" }); - await sleep(500); - await safeAnimate(aditya, { x: 200, y: -100, scale: 1 }, { duration: 0.5 }) - ?.finished; - await Promise.all([ - safeAnimate(aditya, { scale: [1, 0.9, 1] }, { duration: 0.25 })?.finished, - safeAnimate(addDone, { scale: [1, 0.9, 1] }, { duration: 0.25 }) - ?.finished, - ]); + addTask(update, 'done', { + title: 'Write up briefing', + tags: ['dev-rel'] + }); - addTask(update, "done", { - title: "Write up briefing", - tags: ["dev-rel"], + await safeAnimate(aditya, { scale: 1, x: 180, y: 60 }, { duration: 0.75, delay: 0.5 }) + ?.finished; + + await sleep(750); + + await safeAnimate(aditya, { x: -210, y: -100, scale: 1 }, { duration: 0.5 })?.finished; + + await Promise.all([ + safeAnimate(aditya, { scale: [1, 0.9, 1] }, { duration: 0.25 })?.finished, + safeAnimate(addTodo, { scale: [1, 0.9, 1] }, { duration: 0.25 })?.finished + ]); + + addTask(update, 'todo', { + title: 'Review branding blog post', + tags: ['dev-rel'] + }); + + await safeAnimate(aditya, { scale: 1, x: 70, y: -220 }, { duration: 0.75, delay: 0.5 }) + ?.finished; }); - await safeAnimate( - aditya, - { scale: 1, x: 180, y: 60 }, - { duration: 0.75, delay: 0.5 }, - )?.finished; + // Sara + sleep(2500).then(async () => { + addUser(update, { name: 'Sara', color: 'rgba(103, 163, 254, 1)' }); + await sleep(500); + await safeAnimate(sara, { x: 0, y: -100, scale: 1 }, { duration: 0.5 })?.finished; + await Promise.all([ + safeAnimate(sara, { scale: [1, 0.9, 1] }, { duration: 0.25 })?.finished, + safeAnimate(addDoing, { scale: [1, 0.9, 1] }, { duration: 0.25 })?.finished + ]); - await sleep(750); + addTask(update, 'doing', { + title: 'Prepare design system presentation', + tags: ['design'] + }); - await safeAnimate(aditya, { x: -210, y: -100, scale: 1 }, { duration: 0.5 }) - ?.finished; + await safeAnimate(sara, { scale: 1, y: 60, x: -50 }, { duration: 0.75, delay: 0.5 }) + ?.finished; + await sleep(250); - await Promise.all([ - safeAnimate(aditya, { scale: [1, 0.9, 1] }, { duration: 0.25 })?.finished, - safeAnimate(addTodo, { scale: [1, 0.9, 1] }, { duration: 0.25 }) - ?.finished, - ]); + await safeAnimate(sara, { x: 200, y: -100, scale: 1 }, { duration: 0.5 })?.finished; - addTask(update, "todo", { - title: "Review branding blog post", - tags: ["dev-rel"], + await Promise.all([ + safeAnimate(sara, { scale: [1, 0.9, 1] }, { duration: 0.25 })?.finished, + safeAnimate(addDone, { scale: [1, 0.9, 1] }, { duration: 0.25 })?.finished + ]); + + addTask(update, 'done', { + title: 'QA branding animations', + tags: ['Dev'] + }); + + await safeAnimate(sara, { scale: 1, x: 180, y: 60 }, { duration: 0.75, delay: 0.5 }) + ?.finished; }); - - await safeAnimate( - aditya, - { scale: 1, x: 70, y: -220 }, - { duration: 0.75, delay: 0.5 }, - )?.finished; - }); - - // Sara - sleep(2500).then(async () => { - addUser(update, { name: "Sara", color: "rgba(103, 163, 254, 1)" }); - await sleep(500); - await safeAnimate(sara, { x: 0, y: -100, scale: 1 }, { duration: 0.5 }) - ?.finished; - await Promise.all([ - safeAnimate(sara, { scale: [1, 0.9, 1] }, { duration: 0.25 })?.finished, - safeAnimate(addDoing, { scale: [1, 0.9, 1] }, { duration: 0.25 }) - ?.finished, - ]); - - addTask(update, "doing", { - title: "Prepare design system presentation", - tags: ["design"], - }); - - await safeAnimate( - sara, - { scale: 1, y: 60, x: -50 }, - { duration: 0.75, delay: 0.5 }, - )?.finished; - await sleep(250); - - await safeAnimate(sara, { x: 200, y: -100, scale: 1 }, { duration: 0.5 }) - ?.finished; - - await Promise.all([ - safeAnimate(sara, { scale: [1, 0.9, 1] }, { duration: 0.25 })?.finished, - safeAnimate(addDone, { scale: [1, 0.9, 1] }, { duration: 0.25 }) - ?.finished, - ]); - - addTask(update, "done", { - title: "QA branding animations", - tags: ["Dev"], - }); - - await safeAnimate( - sara, - { scale: 1, x: 180, y: 60 }, - { duration: 0.75, delay: 0.5 }, - )?.finished; - }); }; export const realtimeController = { - execute, - state, + execute, + state }; export const Realtime = { - Phone, + Phone }; diff --git a/src/lib/animations/Products/realtime/phone.svelte b/src/lib/animations/Products/realtime/phone.svelte index c333eff61..6d8ae8c3b 100644 --- a/src/lib/animations/Products/realtime/phone.svelte +++ b/src/lib/animations/Products/realtime/phone.svelte @@ -1,674 +1,657 @@
-
-
-
-

My Team's tasks

-
-
- {#each $state.users as user} -
- {getInitial(user.name)} -
- {/each} -
-
- +
+
+
+

My Team's tasks

+
+
+ {#each $state.users as user} +
+ {getInitial(user.name)} +
+ {/each} +
+
+ +
+
+
+ +
+ + +
+
-
-
- -
- - -
-
-
-
+
-
- {#each objectKeys($state.tasks) as col, i} - {@const tasks = $state.tasks[col]} - {@const isLast = i === objectKeys($state.tasks).length - 1} -
-
- {col} - {tasks.length} - -
-
- - {#each tasks as task (task.title)} -
- {#if task.images} -
    - {#each task.images as image} - - {/each} -
+
+ {#each objectKeys($state.tasks) as col, i} + {@const tasks = $state.tasks[col]} + {@const isLast = i === objectKeys($state.tasks).length - 1} +
+
+ {col} + {tasks.length} + +
+
+ + {#each tasks as task (task.title)} +
+ {#if task.images} +
    + {#each task.images as image} + + {/each} +
+ {/if} +

{task.title}

+
    + {#each task.tags as tag} +
  • {tag}
  • + {/each} +
+
+ {/each} +
+
+ {#if !isLast} +
{/if} -

{task.title}

-
    - {#each task.tags as tag} -
  • {tag}
  • - {/each} -
-
{/each} -
- {#if !isLast} -
- {/if} - {/each} + + {#each $state.users as user} +
+ + + +

{user.name}

+
+ {/each}
- {#each $state.users as user} -
+
+

{formatNumber(connections)}

+

Realtime Connections

+ - + + + + + + + + + + + + + + + + + + + {#each progressedLines as line, i} + {@const x = 57 + i * 24} + {@const y = 124 - line} + {#if line > 3} + + + {/if} + {/each} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -

{user.name}

-
- {/each} -
- -
-

{formatNumber(connections)}

-

Realtime Connections

- - - - - - - - - - - - - - - - - - - - - {#each progressedLines as line, i} - {@const x = 57 + i * 24} - {@const y = 124 - line} - {#if line > 3} - - - {/if} - {/each} - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
diff --git a/src/lib/animations/Products/storage/box.svelte b/src/lib/animations/Products/storage/box.svelte index a979ca049..1cabda509 100644 --- a/src/lib/animations/Products/storage/box.svelte +++ b/src/lib/animations/Products/storage/box.svelte @@ -1,43 +1,39 @@
-
- Filename - Type - Size -
- {#each $state.files as file (file.src)} -
-
- - {file.filename} -
- {file.type} - {file.size} +
+ Filename + Type + Size
- {/each} + {#each $state.files as file (file.src)} +
+
+ + {file.filename} +
+ {file.type} + {file.size} +
+ {/each}
diff --git a/src/lib/animations/Products/storage/code.svelte b/src/lib/animations/Products/storage/code.svelte index 5b7fb1c51..c54899395 100644 --- a/src/lib/animations/Products/storage/code.svelte +++ b/src/lib/animations/Products/storage/code.svelte @@ -1,7 +1,7 @@
-
-

Your tasks

- -
- -
Today
-
- {#each fixedTasks as task (task.id)} -
- - {task.title} -
- {/each} -
- - - -
-
-

Edit images for website

-

Edit the attached images to use in the website

- -
Upload media...
-
- {#each $state.files.slice(1) as file} - - {/each} -
+
+

Your tasks

+ +
+ +
Today
+
+ {#each fixedTasks as task (task.id)} +
+ + {task.title} +
+ {/each} +
+ + + +
+
+

Edit images for website

+

Edit the attached images to use in the website

+ +
Upload media...
+
+ {#each $state.files.slice(1) as file} + + {/each} +
+
-
-

Upload media

-
- Drop media here -
-
+

Upload media

+
+ Drop media here +
+
+
-
- +
diff --git a/src/lib/animations/index.ts b/src/lib/animations/index.ts index e4d2b171b..6e0e24b53 100644 --- a/src/lib/animations/index.ts +++ b/src/lib/animations/index.ts @@ -1,198 +1,188 @@ -import type { Action } from "svelte/action"; +import type { Action } from 'svelte/action'; import { - animate as motionAnimate, - type ElementOrSelector, - type MotionKeyframesDefinition, - type AnimationOptionsWithOverrides, - animate, -} from "motion"; + animate as motionAnimate, + type ElementOrSelector, + type MotionKeyframesDefinition, + type AnimationOptionsWithOverrides, + animate +} from 'motion'; export function animation( - elementOrSelector: ElementOrSelector, - keyframes: MotionKeyframesDefinition, - options?: AnimationOptionsWithOverrides, + elementOrSelector: ElementOrSelector, + keyframes: MotionKeyframesDefinition, + options?: AnimationOptionsWithOverrides ) { - const play = () => { - const played = motionAnimate(elementOrSelector, keyframes, options); - return played; - }; + const play = () => { + const played = motionAnimate(elementOrSelector, keyframes, options); + return played; + }; - const reverse = () => { - const reversedKeyframes = Object.fromEntries( - Object.entries(keyframes).map(([key, keyframe]) => { - return [ - key, - Array.isArray(keyframe) ? [...keyframe].reverse() : keyframe, - ]; - }), - ) as typeof keyframes; - const reversed = motionAnimate( - elementOrSelector, - reversedKeyframes, - options, - ); - return reversed; - }; + const reverse = () => { + const reversedKeyframes = Object.fromEntries( + Object.entries(keyframes).map(([key, keyframe]) => { + return [key, Array.isArray(keyframe) ? [...keyframe].reverse() : keyframe]; + }) + ) as typeof keyframes; + const reversed = motionAnimate(elementOrSelector, reversedKeyframes, options); + return reversed; + }; - return { - play, - reverse, - }; + return { + play, + reverse + }; } export type Animation = ReturnType; export const safeAnimate = ( - elementOrSelector: ElementOrSelector, - keyframes: MotionKeyframesDefinition, - options?: AnimationOptionsWithOverrides, + elementOrSelector: ElementOrSelector, + keyframes: MotionKeyframesDefinition, + options?: AnimationOptionsWithOverrides ) => { - try { - return animate(elementOrSelector, keyframes, options); - } catch { - // do nothing lol - } + try { + return animate(elementOrSelector, keyframes, options); + } catch { + // do nothing lol + } }; type Unsubscriber = () => void; -type PreviousScroll = "before" | "after" | undefined; +type PreviousScroll = 'before' | 'after' | undefined; type ScrollCallbackState = { - previous?: PreviousScroll; - unsubscribe?: Unsubscriber; - executedCount: number; + previous?: PreviousScroll; + unsubscribe?: Unsubscriber; + executedCount: number; }; export type ScrollCallback = { - percentage: number; - whenAfter?: ( - args: Omit, - ) => Unsubscriber | void; + percentage: number; + whenAfter?: (args: Omit) => Unsubscriber | void; }; export function createScrollHandler(callbacks: ScrollCallback[]) { - const states: ScrollCallbackState[] = callbacks.map(() => ({ - executedCount: 0, - })); + const states: ScrollCallbackState[] = callbacks.map(() => ({ + executedCount: 0 + })); - const handler = function (scrollPercentage: number) { - callbacks.forEach((callback, i) => { - const { percentage, whenAfter } = callback; - const { previous, unsubscribe, executedCount } = states[i]; + const handler = function (scrollPercentage: number) { + callbacks.forEach((callback, i) => { + const { percentage, whenAfter } = callback; + const { previous, unsubscribe, executedCount } = states[i]; - if (scrollPercentage >= percentage && previous !== "after") { - // Execute whenAfter - states[i].unsubscribe = - whenAfter?.({ previous, executedCount }) ?? undefined; - states[i].previous = "after"; - if (whenAfter) { - states[i].executedCount++; - } - } else if (scrollPercentage < percentage && previous === "after") { - unsubscribe?.(); - states[i].unsubscribe = undefined; - states[i].previous = "before"; - } - }); - }; + if (scrollPercentage >= percentage && previous !== 'after') { + // Execute whenAfter + states[i].unsubscribe = whenAfter?.({ previous, executedCount }) ?? undefined; + states[i].previous = 'after'; + if (whenAfter) { + states[i].executedCount++; + } + } else if (scrollPercentage < percentage && previous === 'after') { + unsubscribe?.(); + states[i].unsubscribe = undefined; + states[i].previous = 'before'; + } + }); + }; - handler.reset = () => { - states.forEach((state) => { - // state.unsubscribe?.(); - state.unsubscribe = undefined; - state.previous = undefined; - state.executedCount = 0; - }); - }; + handler.reset = () => { + states.forEach((state) => { + // state.unsubscribe?.(); + state.unsubscribe = undefined; + state.previous = undefined; + state.executedCount = 0; + }); + }; - return handler; + return handler; } export type ScrollInfo = { - percentage: number; - traversed: number; - remaning: number; + percentage: number; + traversed: number; + remaning: number; }; export const scroll: Action< - HTMLElement, - undefined, - { - "on:web-scroll": (e: CustomEvent) => void; - "on:web-resize": (e: CustomEvent) => void; - } + HTMLElement, + undefined, + { + 'on:web-scroll': (e: CustomEvent) => void; + 'on:web-resize': (e: CustomEvent) => void; + } > = (node) => { - function getScrollInfo(): ScrollInfo { - const { top, height } = node.getBoundingClientRect(); - const { innerHeight } = window; + function getScrollInfo(): ScrollInfo { + const { top, height } = node.getBoundingClientRect(); + const { innerHeight } = window; - const scrollHeight = height - innerHeight; - const scrollPercentage = (-1 * top) / scrollHeight; + const scrollHeight = height - innerHeight; + const scrollPercentage = (-1 * top) / scrollHeight; - const traversed = scrollPercentage * scrollHeight; - const remaning = scrollHeight - traversed; + const traversed = scrollPercentage * scrollHeight; + const remaning = scrollHeight - traversed; + + return { + percentage: scrollPercentage, + traversed, + remaning + }; + } + + const createHandler = (eventName: 'web-scroll' | 'web-resize') => { + return () => { + node.dispatchEvent( + new CustomEvent(eventName, { + detail: getScrollInfo() + }) + ); + }; + }; + + const handleScroll = createHandler('web-scroll'); + const handleResize = createHandler('web-resize'); + + handleScroll(); + handleResize(); + + window.addEventListener('scroll', handleScroll); + window.addEventListener('resize', handleResize); return { - percentage: scrollPercentage, - traversed, - remaning, + destroy() { + window.removeEventListener('scroll', handleScroll); + window.removeEventListener('resize', handleResize); + } }; - } - - const createHandler = (eventName: "web-scroll" | "web-resize") => { - return () => { - node.dispatchEvent( - new CustomEvent(eventName, { - detail: getScrollInfo(), - }), - ); - }; - }; - - const handleScroll = createHandler("web-scroll"); - const handleResize = createHandler("web-resize"); - - handleScroll(); - handleResize(); - - window.addEventListener("scroll", handleScroll); - window.addEventListener("resize", handleResize); - - return { - destroy() { - window.removeEventListener("scroll", handleScroll); - window.removeEventListener("resize", handleResize); - }, - }; }; type TimelineEvent = { - at: number; - callback: () => void; + at: number; + callback: () => void; }; export function createTimeline(events: TimelineEvent[]) { - let timeoutIds: NodeJS.Timeout[] = []; + let timeoutIds: NodeJS.Timeout[] = []; - const play = () => { - events.forEach((event) => { - const timeoutId = setTimeout(event.callback, event.at); - timeoutIds.push(timeoutId); - }); - }; + const play = () => { + events.forEach((event) => { + const timeoutId = setTimeout(event.callback, event.at); + timeoutIds.push(timeoutId); + }); + }; - const cancel = () => { - timeoutIds.forEach(clearTimeout); - timeoutIds = []; - }; + const cancel = () => { + timeoutIds.forEach(clearTimeout); + timeoutIds = []; + }; - return { play, cancel }; + return { play, cancel }; } type ProgressEvent = { - percentage: number; - callback: () => void; + percentage: number; + callback: () => void; }; /** @@ -203,56 +193,54 @@ type ProgressEvent = { * handler(0.45) // will execute the event with percentage 0.4. */ export function createProgressSequence(events: ProgressEvent[]) { - // Sort from highest to lowest percentage - const sortedEvents = [...events].sort((a, b) => b.percentage - a.percentage); + // Sort from highest to lowest percentage + const sortedEvents = [...events].sort((a, b) => b.percentage - a.percentage); - let lastEventIdx = -1; + let lastEventIdx = -1; - const handler = (percentage: number) => { - const idx = sortedEvents.findIndex( - (event) => event.percentage <= percentage, - ); - if (idx === lastEventIdx) { - return; - } - const event = sortedEvents[idx]; - event?.callback(); - lastEventIdx = idx; - }; + const handler = (percentage: number) => { + const idx = sortedEvents.findIndex((event) => event.percentage <= percentage); + if (idx === lastEventIdx) { + return; + } + const event = sortedEvents[idx]; + event?.callback(); + lastEventIdx = idx; + }; - handler.resetLastEventIdx = () => { - lastEventIdx = -1; - }; + handler.resetLastEventIdx = () => { + lastEventIdx = -1; + }; - return handler; + return handler; } export type ProgressSequence = ReturnType; export function write(text: string, cb: (v: string) => void, duration = 500) { - const step = duration / text.length; - let i = 0; - return new Promise((resolve) => { - const interval = setInterval(() => { - cb(text.slice(0, ++i)); - if (i === text.length) { - clearInterval(interval); - resolve(undefined); - } - }, step); - }); + const step = duration / text.length; + let i = 0; + return new Promise((resolve) => { + const interval = setInterval(() => { + cb(text.slice(0, ++i)); + if (i === text.length) { + clearInterval(interval); + resolve(undefined); + } + }, step); + }); } export function sleep(duration: number) { - return new Promise((resolve) => { - setTimeout(resolve, duration); - }); + return new Promise((resolve) => { + setTimeout(resolve, duration); + }); } export function getInitials(name: string) { - return name - .split(" ") - .map((word) => word?.[0]?.toUpperCase() ?? "") - .join("") - .slice(0, 2); + return name + .split(' ') + .map((word) => word?.[0]?.toUpperCase() ?? '') + .join('') + .slice(0, 2); } diff --git a/src/lib/animations/scroll-indicator.svelte b/src/lib/animations/scroll-indicator.svelte index 95aa9e437..e70643bd6 100644 --- a/src/lib/animations/scroll-indicator.svelte +++ b/src/lib/animations/scroll-indicator.svelte @@ -1,45 +1,45 @@
-
+
diff --git a/src/lib/appwrite/index.ts b/src/lib/appwrite/index.ts index 6e3c364ff..e56c1ae75 100644 --- a/src/lib/appwrite/index.ts +++ b/src/lib/appwrite/index.ts @@ -1,14 +1,9 @@ -import { - PUBLIC_APPWRITE_ENDPOINT, - PUBLIC_APPWRITE_PROJECT_ID, -} from "$env/static/public"; -import { Client, Databases, Functions } from "@appwrite.io/console"; +import { PUBLIC_APPWRITE_ENDPOINT, PUBLIC_APPWRITE_PROJECT_ID } from '$env/static/public'; +import { Client, Databases, Functions } from '@appwrite.io/console'; export const client = new Client(); -client - .setEndpoint(PUBLIC_APPWRITE_ENDPOINT) - .setProject(PUBLIC_APPWRITE_PROJECT_ID); +client.setEndpoint(PUBLIC_APPWRITE_ENDPOINT).setProject(PUBLIC_APPWRITE_PROJECT_ID); export const databases = new Databases(client); export const functions = new Functions(client); diff --git a/src/lib/appwrite/init.server.ts b/src/lib/appwrite/init.server.ts index 0a851a403..85a6d2fab 100644 --- a/src/lib/appwrite/init.server.ts +++ b/src/lib/appwrite/init.server.ts @@ -1,17 +1,14 @@ -import { APPWRITE_API_KEY_INIT } from "$env/static/private"; -import { - PUBLIC_APPWRITE_ENDPOINT, - PUBLIC_APPWRITE_PROJECT_INIT_ID, -} from "$env/static/public"; -import { Account, Client, Databases } from "@appwrite.io/console"; +import { APPWRITE_API_KEY_INIT } from '$env/static/private'; +import { PUBLIC_APPWRITE_ENDPOINT, PUBLIC_APPWRITE_PROJECT_INIT_ID } from '$env/static/public'; +import { Account, Client, Databases } from '@appwrite.io/console'; const clientServer = new Client(); clientServer - .setEndpoint(PUBLIC_APPWRITE_ENDPOINT) - .setProject(PUBLIC_APPWRITE_PROJECT_INIT_ID) - .setKey(APPWRITE_API_KEY_INIT); + .setEndpoint(PUBLIC_APPWRITE_ENDPOINT) + .setProject(PUBLIC_APPWRITE_PROJECT_INIT_ID) + .setKey(APPWRITE_API_KEY_INIT); export const appwriteInitServer = { - account: new Account(clientServer), - databases: new Databases(clientServer), + account: new Account(clientServer), + databases: new Databases(clientServer) }; diff --git a/src/lib/appwrite/init.ts b/src/lib/appwrite/init.ts index 81d384b9e..bcefa6503 100644 --- a/src/lib/appwrite/init.ts +++ b/src/lib/appwrite/init.ts @@ -1,15 +1,10 @@ -import { - PUBLIC_APPWRITE_ENDPOINT, - PUBLIC_APPWRITE_PROJECT_INIT_ID, -} from "$env/static/public"; -import { Client, Account } from "@appwrite.io/console"; +import { PUBLIC_APPWRITE_ENDPOINT, PUBLIC_APPWRITE_PROJECT_INIT_ID } from '$env/static/public'; +import { Client, Account } from '@appwrite.io/console'; const client = new Client(); -client - .setEndpoint(PUBLIC_APPWRITE_ENDPOINT) - .setProject(PUBLIC_APPWRITE_PROJECT_INIT_ID); +client.setEndpoint(PUBLIC_APPWRITE_ENDPOINT).setProject(PUBLIC_APPWRITE_PROJECT_INIT_ID); export const appwriteInit = { - client, - account: new Account(client), + client, + account: new Account(client) }; diff --git a/src/lib/components/Accordion/Item.svelte b/src/lib/components/Accordion/Item.svelte index d7783ecaf..4471776f3 100644 --- a/src/lib/components/Accordion/Item.svelte +++ b/src/lib/components/Accordion/Item.svelte @@ -1,35 +1,35 @@
  • -
    - - {title} -
    -
    -
    -
    - -
    -
    +
    + + {title} +
    +
    +
    +
    + +
    +
  • diff --git a/src/lib/components/Accordion/Root.svelte b/src/lib/components/Accordion/Root.svelte index cf328e084..1b1b181c7 100644 --- a/src/lib/components/Accordion/Root.svelte +++ b/src/lib/components/Accordion/Root.svelte @@ -1,13 +1,10 @@ -
      - +
        +
      diff --git a/src/lib/components/Accordion/index.ts b/src/lib/components/Accordion/index.ts index e1d8909fb..aad12a5d2 100644 --- a/src/lib/components/Accordion/index.ts +++ b/src/lib/components/Accordion/index.ts @@ -1,4 +1,4 @@ -import Root from "./Root.svelte"; -import Item from "./Item.svelte"; +import Root from './Root.svelte'; +import Item from './Item.svelte'; export { Root as Accordion, Item as AccordionItem }; diff --git a/src/lib/components/AnnouncementBanner.svelte b/src/lib/components/AnnouncementBanner.svelte index 9573615b1..275430850 100644 --- a/src/lib/components/AnnouncementBanner.svelte +++ b/src/lib/components/AnnouncementBanner.svelte @@ -1,24 +1,24 @@
      -
      - - {#if browser} - - {/if} -
      +
      + + {#if browser} + + {/if} +
      diff --git a/src/lib/components/Article.svelte b/src/lib/components/Article.svelte index b102b38ae..2acc7fb97 100644 --- a/src/lib/components/Article.svelte +++ b/src/lib/components/Article.svelte @@ -1,52 +1,52 @@
    • - -
      - -
      -
      -

      - {title} -

      -
      - +
      +

      + {title} +

      +
      +
      + {author} +
      +

      {author}

      + +
      +
      +
      +
      +
    • diff --git a/src/lib/components/Carousel.svelte b/src/lib/components/Carousel.svelte index d7b8bfe7c..876f32cf4 100644 --- a/src/lib/components/Carousel.svelte +++ b/src/lib/components/Carousel.svelte @@ -1,152 +1,146 @@
      -
      - - - +
      diff --git a/src/lib/components/DropdownMenu/DropdownCheckboxItem.svelte b/src/lib/components/DropdownMenu/DropdownCheckboxItem.svelte index 24dbca850..7aa2a4fc7 100644 --- a/src/lib/components/DropdownMenu/DropdownCheckboxItem.svelte +++ b/src/lib/components/DropdownMenu/DropdownCheckboxItem.svelte @@ -1,24 +1,24 @@ diff --git a/src/lib/components/DropdownMenu/DropdownMenu.svelte b/src/lib/components/DropdownMenu/DropdownMenu.svelte index bca7726c3..25de115b5 100644 --- a/src/lib/components/DropdownMenu/DropdownMenu.svelte +++ b/src/lib/components/DropdownMenu/DropdownMenu.svelte @@ -1,33 +1,33 @@ diff --git a/src/lib/components/Feedback.svelte b/src/lib/components/Feedback.svelte index 394d49edc..2b2b17bbc 100644 --- a/src/lib/components/Feedback.svelte +++ b/src/lib/components/Feedback.svelte @@ -1,166 +1,152 @@
    +
    +
    +

    + {#if error} + {error} + {/if} +

    + +
    + + {/if}
    - -
  • - - -
  • -
  • - -
    - - -
    -
  • - {#if hasCreatedIntegration} -
  • - - -
  • - {/if} -
  • - - -
  • -
  • - - -
  • - -
    -
    -

    - {#if error} - {error} - {/if} -

    - -
    - - {/if} +
    +
    + + +
    +
    -
    -
    - - -
    -
    -
    diff --git a/src/routes/oss-program/+page.svelte b/src/routes/oss-program/+page.svelte index 63be895b8..72697396b 100644 --- a/src/routes/oss-program/+page.svelte +++ b/src/routes/oss-program/+page.svelte @@ -1,263 +1,259 @@ - - {title} - - - - - - - - - - - - + + {title} + + + + + + + + + + + +
    - +
    -
    -
    -
    -
    -
    -
    -
    - {#if submitted} -
    -

    - Thank you for your application -

    -

    - Your application has been sent. Our team will try to get - back to you as soon as possible. -

    - - Back to homepage - -
    - {:else} -
    -

    - OSS program -

    -

    - Apply to the OSS Program by filling out this form. Our - team will reach out to you to confirm your application was - accepted. -

    -
    - {/if} -
    -

    Follow us

    -
      - {#each socials as social} -
    • - - -
    • - {/each} -
    -
    -
    -
    +
    +
    +
    +
    +
    +
    +
    + {#if submitted} +
    +

    + Thank you for your application +

    +

    + Your application has been sent. Our team will try to get + back to you as soon as possible. +

    + + Back to homepage + +
    + {:else} +
    +

    + OSS program +

    +

    + Apply to the OSS Program by filling out this form. Our + team will reach out to you to confirm your application + was accepted. +

    +
    + {/if} +
    +

    Follow us

    +
      + {#each socials as social} +
    • + + +
    • + {/each} +
    +
    +
    +
    +
    + {#if !submitted} +
    +
    +
      +
    • +
      Full name
      + +
    • +
    • +
      Email address
      + +
    • +
    • +
      Project or company name
      + +
    • +
    • +
      GitHub URL
      + +
    • +
    • +
      Website URL
      + +
    • +
    • +
      OSS license
      + +
    • +
    • +
      Message
      +