fix: sync pr to main

This commit is contained in:
Torsten Dittmann
2024-07-04 13:14:39 +02:00
1311 changed files with 67753 additions and 11695 deletions

View File

@@ -1,6 +1,12 @@
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_COL_MESSAGES_ID=
PUBLIC_APPWRITE_FN_TLDR_ID= PUBLIC_APPWRITE_COL_THREADS_ID=
PUBLIC_APPWRITE_DB_MAIN_ID=
PUBLIC_APPWRITE_FN_TLDR_ID=
PUBLIC_APPWRITE_ENDPOINT=
PUBLIC_APPWRITE_PROJECT_ID=
PUBLIC_APPWRITE_PROJECT_INIT_ID=
PUBLIC_GROWTH_ENDPOINT=
APPWRITE_DB_INIT_ID=
APPWRITE_COL_INIT_ID=
APPWRITE_API_KEY_INIT=
SENTRY_AUTH_TOKEN=

View File

@@ -1,71 +1,77 @@
name: Production deployment name: Production deployment
on: on:
release: release:
types: [published] types: [published]
env: env:
TAG: ${{ github.event.release.tag_name }} TAG: ${{ github.event.release.tag_name }}
STACK_FILE: docker/production.yml STACK_FILE: docker/production.yml
REPOSITORY: website REPOSITORY: website
REGISTRY_USERNAME: christyjacob4 REGISTRY_USERNAME: christyjacob4
jobs: jobs:
build: build:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout the repo - name: Checkout the repo
uses: actions/checkout@v2 uses: actions/checkout@v2
- name: Login to DockerHub - name: Login to DockerHub
uses: docker/login-action@v1 uses: docker/login-action@v1
with: with:
registry: ghcr.io registry: ghcr.io
username: ${{ github.actor }} username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }} password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push - name: Build and push
uses: docker/build-push-action@v2 uses: docker/build-push-action@v2
with: with:
context: . context: .
push: true push: true
tags: ghcr.io/appwrite/website:${{ env.TAG }} tags: ghcr.io/appwrite/website:${{ env.TAG }}
build-args: | build-args: |
"PUBLIC_APPWRITE_PROJECT_INIT_ID=${{ vars.PUBLIC_APPWRITE_PROJECT_INIT_ID }}" "PUBLIC_APPWRITE_PROJECT_ID=${{ vars.PUBLIC_APPWRITE_PROJECT_ID }}"
"PUBLIC_APPWRITE_PROJECT_ID=${{ vars.PUBLIC_APPWRITE_PROJECT_ID }}" "PUBLIC_APPWRITE_DB_MAIN_ID=${{ vars.PUBLIC_APPWRITE_DB_MAIN_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_THREADS_ID=${{ vars.PUBLIC_APPWRITE_COL_THREADS_ID }}" "PUBLIC_APPWRITE_COL_MESSAGES_ID=${{ vars.PUBLIC_APPWRITE_COL_MESSAGES_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_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: deploy:
needs: build needs: build
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Execute SSH commands - name: Execute SSH commands
uses: appleboy/ssh-action@master uses: appleboy/ssh-action@master
with: with:
host: ${{ secrets.PRD_SSH_HOST }} host: ${{ secrets.PRD_SSH_HOST }}
username: ${{ secrets.PRD_SSH_USERNAME }} username: ${{ secrets.PRD_SSH_USERNAME }}
key: ${{ secrets.PRD_SSH_KEY }} key: ${{ secrets.PRD_SSH_KEY }}
script: | script: |
url="https://${{ github.actor }}:${{ secrets.GITHUB_TOKEN }}@github.com/appwrite/${{ env.REPOSITORY }}.git" 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 if ! git clone "${url}" "${{ env.REPOSITORY }}" 2>/dev/null && [ -d "${{ env.REPOSITORY }}" ] ; then
echo "Clone failed because the folder ${{ env.REPOSITORY }} exists" echo "Clone failed because the folder ${{ env.REPOSITORY }} exists"
fi fi
cd ${{ env.REPOSITORY }} cd ${{ env.REPOSITORY }}
git reset --hard HEAD git reset --hard HEAD
git remote set-url origin $url git remote set-url origin $url
git fetch origin git fetch origin
git checkout ${{ env.TAG }} git checkout ${{ env.TAG }}
rm -f .env rm -f .env
echo "_APP_VERSION=${{ env.TAG }}" >> .env echo "_APP_VERSION=${{ env.TAG }}" >> .env
echo "_APP_DOMAIN=${{ secrets.PRD_APP_DOMAIN }}" >> .env echo "_APP_DOMAIN=${{ secrets.PRD_APP_DOMAIN }}" >> .env
echo "_APP_SYSTEM_SECURITY_EMAIL_ADDRESS=${{ secrets.APP_SYSTEM_SECURITY_EMAIL_ADDRESS }}" >> .env echo "_APP_SYSTEM_SECURITY_EMAIL_ADDRESS=${{ secrets.APP_SYSTEM_SECURITY_EMAIL_ADDRESS }}" >> .env
echo "SEMATEXT_TOKEN=${{ secrets.SEMATEXT_TOKEN }}" >> .env echo "SEMATEXT_TOKEN=${{ secrets.SEMATEXT_TOKEN }}" >> .env
echo ${{ secrets.GH_REGISTRY_TOKEN }} | docker login ghcr.io --username ${{ env.REGISTRY_USERNAME }} --password-stdin echo ${{ secrets.GH_REGISTRY_TOKEN }} | docker login ghcr.io --username ${{ env.REGISTRY_USERNAME }} --password-stdin
docker-compose -f ${{ env.STACK_FILE }} config 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 }} env $(cat .env | xargs) docker stack deploy --prune --resolve-image always --with-registry-auth -c ${{ env.STACK_FILE }} ${{ env.REPOSITORY }}

View File

@@ -1,72 +1,79 @@
name: Staging deployment name: Staging deployment
on: on:
push: workflow_dispatch:
branches: push:
- main branches:
- main
env: env:
TAG: ${{ github.sha }} TAG: ${{ github.sha }}
STACK_FILE: docker/stage.yml STACK_FILE: docker/stage.yml
REPOSITORY: website REPOSITORY: website
REGISTRY_USERNAME: christyjacob4 REGISTRY_USERNAME: christyjacob4
jobs: jobs:
build: build:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout the repo - name: Checkout the repo
uses: actions/checkout@v2 uses: actions/checkout@v2
- name: Login to DockerHub - name: Login to DockerHub
uses: docker/login-action@v1 uses: docker/login-action@v1
with: with:
registry: ghcr.io registry: ghcr.io
username: ${{ github.actor }} username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }} password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push - name: Build and push
uses: docker/build-push-action@v2 uses: docker/build-push-action@v2
with: with:
context: . context: .
push: true push: true
tags: ghcr.io/appwrite/website:${{ env.TAG }} tags: ghcr.io/appwrite/website:${{ env.TAG }}
build-args: | build-args: |
"PUBLIC_APPWRITE_PROJECT_INIT_ID=${{ vars.PUBLIC_APPWRITE_PROJECT_INIT_ID }}" "PUBLIC_APPWRITE_PROJECT_ID=${{ vars.PUBLIC_APPWRITE_PROJECT_ID }}"
"PUBLIC_APPWRITE_PROJECT_ID=${{ vars.PUBLIC_APPWRITE_PROJECT_ID }}" "PUBLIC_APPWRITE_DB_MAIN_ID=${{ vars.PUBLIC_APPWRITE_DB_MAIN_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_THREADS_ID=${{ vars.PUBLIC_APPWRITE_COL_THREADS_ID }}" "PUBLIC_APPWRITE_COL_MESSAGES_ID=${{ vars.PUBLIC_APPWRITE_COL_MESSAGES_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_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: deploy:
needs: build needs: build
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Execute SSH commands - name: Execute SSH commands
uses: appleboy/ssh-action@master uses: appleboy/ssh-action@master
with: with:
host: ${{ secrets.STG_SSH_HOST }} host: ${{ secrets.STG_SSH_HOST }}
username: ${{ secrets.STG_SSH_USERNAME }} username: ${{ secrets.STG_SSH_USERNAME }}
key: ${{ secrets.STG_SSH_KEY }} key: ${{ secrets.STG_SSH_KEY }}
script: | script: |
url="https://${{ github.actor }}:${{ secrets.GITHUB_TOKEN }}@github.com/appwrite/${{ env.REPOSITORY }}.git" 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 if ! git clone "${url}" "${{ env.REPOSITORY }}" 2>/dev/null && [ -d "${{ env.REPOSITORY }}" ] ; then
echo "Clone failed because the folder ${{ env.REPOSITORY }} exists" echo "Clone failed because the folder ${{ env.REPOSITORY }} exists"
fi fi
cd ${{ env.REPOSITORY }} cd ${{ env.REPOSITORY }}
git reset --hard HEAD git reset --hard HEAD
git remote set-url origin $url git remote set-url origin $url
git fetch origin git fetch origin
git checkout ${{ env.TAG }} git checkout ${{ env.TAG }}
rm -f .env rm -f .env
echo "_APP_VERSION=${{ env.TAG }}" >> .env echo "_APP_VERSION=${{ env.TAG }}" >> .env
echo "_APP_DOMAIN=${{ secrets.STG_APP_DOMAIN }}" >> .env echo "_APP_DOMAIN=${{ secrets.STG_APP_DOMAIN }}" >> .env
echo "_APP_SYSTEM_SECURITY_EMAIL_ADDRESS=${{ secrets.APP_SYSTEM_SECURITY_EMAIL_ADDRESS }}" >> .env echo "_APP_SYSTEM_SECURITY_EMAIL_ADDRESS=${{ secrets.APP_SYSTEM_SECURITY_EMAIL_ADDRESS }}" >> .env
echo "SEMATEXT_TOKEN=${{ secrets.SEMATEXT_TOKEN }}" >> .env echo "SEMATEXT_TOKEN=${{ secrets.SEMATEXT_TOKEN }}" >> .env
echo ${{ secrets.GH_REGISTRY_TOKEN }} | docker login ghcr.io --username ${{ env.REGISTRY_USERNAME }} --password-stdin echo ${{ secrets.GH_REGISTRY_TOKEN }} | docker login ghcr.io --username ${{ env.REGISTRY_USERNAME }} --password-stdin
docker-compose -f ${{ env.STACK_FILE }} config 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 }} env $(cat .env | xargs) docker stack deploy --prune --resolve-image always --with-registry-auth -c ${{ env.STACK_FILE }} ${{ env.REPOSITORY }}

23
.github/workflows/stale.yml vendored Normal file
View File

@@ -0,0 +1,23 @@
name: Mark stale issues
on:
schedule:
- cron: "0 0 * * *" # Midnight Runtime
jobs:
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"

View File

@@ -1,25 +1,22 @@
name: Tests name: Tests
on: on:
push: pull_request_target:
branches: [main] branches: ['**']
pull_request:
branches: [main]
jobs: jobs:
build: build:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
with:
ref: ${{ github.event.pull_request.head.sha }}
- name: Use Node.js - name: Use Node.js
uses: actions/setup-node@v3 uses: actions/setup-node@v3
with: with:
node-version: 18 node-version: 20
- uses: pnpm/action-setup@v2 - name: Install pnpm
name: Install pnpm run: corepack enable
with:
version: 8
run_install: false
- name: Get pnpm store directory - name: Get pnpm store directory
shell: bash shell: bash
run: | run: |
@@ -37,10 +34,15 @@ jobs:
- name: Build Website - name: Build Website
env: env:
NODE_OPTIONS: '--max_old_space_size=8192' NODE_OPTIONS: '--max_old_space_size=8192'
PUBLIC_APPWRITE_PROJECT_INIT_ID: ${{ secrets.PUBLIC_APPWRITE_PROJECT_INIT_ID }}
PUBLIC_APPWRITE_PROJECT_ID: ${{ secrets.PUBLIC_APPWRITE_PROJECT_ID }} PUBLIC_APPWRITE_PROJECT_ID: ${{ secrets.PUBLIC_APPWRITE_PROJECT_ID }}
PUBLIC_APPWRITE_DB_MAIN_ID: ${{ secrets.PUBLIC_APPWRITE_DB_MAIN_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_THREADS_ID: ${{ secrets.PUBLIC_APPWRITE_COL_THREADS_ID }}
PUBLIC_APPWRITE_COL_MESSAGES_ID: ${{ secrets.PUBLIC_APPWRITE_COL_MESSAGES_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_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 run: pnpm run build

5
.gitignore vendored
View File

@@ -11,4 +11,7 @@ node_modules
vite.config.js.timestamp-* vite.config.js.timestamp-*
vite.config.ts.timestamp-* vite.config.ts.timestamp-*
package-lock.json package-lock.json
.tool-versions .tool-versions
.vscode
# Sentry Config File
.sentryclirc

View File

@@ -71,6 +71,17 @@ Embed images using the `![alt text](image URL)` syntax.
![Logo](https://example.com/logo.png) ![Logo](https://example.com/logo.png)
``` ```
In most cases, we need images in both light and dark mode such as:
```md
{% only_dark %}
![Project settings screen](/images/docs/platform/dark/create-api-key.png)
{% /only_dark %}
{% only_light %}
![Project settings screen](/images/docs/platform/create-api-key.png)
{% /only_light %}
```
#### Code Blocks #### Code Blocks
Format code blocks using triple backticks (```). Format code blocks using triple backticks (```).
@@ -82,6 +93,8 @@ def hello_world():
``` ```
</pre> </pre>
Remember to use a specific language label if the code is using an Appwrite SDK. Find the [list of available labels here](https://github.com/appwrite/website/blob/41bb6c71a8647016c88393003d3cf6c4edba1f76/src/lib/utils/references.ts#L26).
#### Inline Code #### Inline Code
Highlight inline code with backticks (`) around the code snippet. Highlight inline code with backticks (`) around the code snippet.
@@ -94,6 +107,8 @@ Use the `print()` function to display text.
Use asterisks (\*) or underscores (\_) for emphasis and double asterisks or underscores for strong text. Use asterisks (\*) or underscores (\_) for emphasis and double asterisks or underscores for strong text.
**We use bold for representing text as seen on UI**. For example: "Click the button **Create new document**."
```md ```md
_Italic Text_ or _Italic Text_ _Italic Text_ or _Italic Text_
**Bold Text** or **Bold Text** **Bold Text** or **Bold Text**
@@ -110,6 +125,21 @@ Tables allow you to display structured data in your documentation. Use pipes (|)
| Row 2, Col 1 | Row 2, Col 2 | Row 2, Col 3 | | Row 2, Col 1 | Row 2, Col 2 | Row 2, Col 3 |
``` ```
Alternatively, use markdoc tables.
```md
{% table %}
* Heading 1
* Heading 2
---
* Row 1 Cell 1
* Row 1 Cell 2
---
* Row 2 Cell 1
* Row 2 cell 2
{% /table %}
```
#### Block Quotes #### Block Quotes
Block quotes are used to emphasize or highlight text. To create a block quote, use the > symbol at the beginning of the quoted text. Block quotes are used to emphasize or highlight text. To create a block quote, use the > symbol at the beginning of the quoted text.
@@ -156,7 +186,7 @@ print('test');
</pre> </pre>
#### Sections #### Sections
Use sections when there is a clear step-by-step format to a page. This is used mainly in journey pages and tutorials.
```md ```md
{% section #featured-products-1 step=1 title="Title" %} {% section #featured-products-1 step=1 title="Title" %}
Lorem ipsum dolor sit amet consectetur. Lorem ipsum dolor sit amet consectetur.
@@ -204,6 +234,65 @@ Available sizes are `s`, `m`, `l` and `xl`. Default: `s`.
#### Only Light/Dark Theme #### Only Light/Dark Theme
``` ```
{% only_dark %}I am only shown in Dark Theme{% /only_dark %} {% only_dark %}
{% only_light %}I am only shown in Light Theme{% /only_light %} ![Project settings screen](/images/docs/platform/dark/create-api-key.png)
{% /only_dark %}
{% only_light %}
![Project settings screen](/images/docs/platform/create-api-key.png)
{% /only_light %}
```
#### Cards
We use cards when we reference a list of links for navigation
```
{% cards %}
{% cards_item href="/docs/quick-starts/react" title="React" %}
Get started with Appwrite and React
{% /cards_item %}
{% cards_item href="/docs/quick-starts/vue" title="Vue.js" %}
Get started with Appwrite and Vue.js
{% /cards_item %}
{% cards_item href="/docs/quick-starts/nuxt" title="Nuxt" %}
Get started with Appwrite and Nuxt
{% /cards_item %}
{% cards_item href="/docs/quick-starts/sveltekit" title="SvelteKit" %}
Get started with Appwrite and SvelteKit
{% /cards_item %}
{% /cards %}
```
#### Cards with icons
We use cards when we reference a list of links for navigation, this variation has icons for extra hints visually.
```
{% cards %}
{% cards_item href="/docs/products/messaging/apns" title="APNS" icon="icon-apple" %}
Configure APNs for push notification to Apple devices.
{% /cards_item %}
{% cards_item href="/docs/products/messaging/fcm" title="FCM" icon="web-icon-firebase" %}
Configure FCM for push notification to Android and Apple devices.
{% /cards_item %}
{% /cards %}
```
#### Accordions
Use accordions to reduce page size and collapse information that's not important when a reader is skilling the page.
```
{% accordion %}
{% accordion_item title="Team ID" %}
{% /accordion_item %}
{% accordion_item title="Bundle ID" %}
{% /accordion_item %}
{% /accordion %}
``` ```

View File

@@ -25,9 +25,11 @@ Then, [clone the respository](https://docs.github.com/en/repositories/creating-a
Alternatively, you can develop the website repo in your browser using [Code Spaces](https://github.com/features/codespaces) or [GitPod](https://www.gitpod.io/#https://github.com/appwrite/website). Alternatively, you can develop the website repo in your browser using [Code Spaces](https://github.com/features/codespaces) or [GitPod](https://www.gitpod.io/#https://github.com/appwrite/website).
## Development ## Development
The Appwrite website uses [PNPM](https://pnpm.io). Start by following their [installation](https://pnpm.io/installation) documentation. The Appwrite website uses [PNPM](https://pnpm.io). Start by following their [installation](https://pnpm.io/installation) documentation.
Once you've cloned the Appwrite website repo, running the following command to install dependencies: Once you've cloned the Appwrite website repo, running the following command to install dependencies:
```sh ```sh
pnpm i pnpm i
``` ```
@@ -58,11 +60,11 @@ doc-548-submit-a-pull-request-section-to-contribution-guide
When `TYPE` can be: When `TYPE` can be:
- **feat** - is a new feature - **feat** - is a new feature
- **doc** - documentation only changes - **doc** - documentation only changes
- **cicd** - changes related to CI/CD system - **cicd** - changes related to CI/CD system
- **fix** - a bug fix - **fix** - a bug fix
- **refactor** - code change that neither fixes a bug nor adds a feature - **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!** **All PRs must include a commit message with a description of the changes made!**
@@ -71,20 +73,20 @@ Start by forking the project and use the `git clone` command to download the rep
1. Before creating a new branch, pull the changes from upstream to make sure your default branch is up to date. 1. Before creating a new branch, pull the changes from upstream to make sure your default branch is up to date.
``` ```
$ git pull git pull
``` ```
2. Create a new branch from the default branch. For example `doc-548-submit-a-pull-request-section-to-contribution-guide` 2. Create a new branch from the default branch. For example `doc-548-submit-a-pull-request-section-to-contribution-guide`
``` ```
$ git checkout -b [name_of_your_new_branch] git checkout -b [name_of_your_new_branch]
``` ```
3. Work - commit - repeat ( be sure to be in your branch ) 3. Work - commit - repeat ( be sure to be in your branch )
4. Push changes to GitHub 4. Push changes to GitHub
``` ```
$ git push origin [name_of_your_new_branch] git push origin [name_of_your_new_branch]
``` ```
6. Submit your changes for review. If you go to your repository on GitHub, you'll see a `Compare & pull request` button. Click on that button. 6. Submit your changes for review. If you go to your repository on GitHub, you'll see a `Compare & pull request` button. Click on that button.
@@ -97,43 +99,5 @@ $ git push origin [name_of_your_new_branch]
10. After approval, your PR will be merged. 10. After approval, your PR will be merged.
## Documentation style ## Documentation style
For consistency the Appwrite documentation follows a strict set of style guidelines, so no matter who is writing the documentation,
the tone and voice remains consistent.
### Headings When contributing to the Appwrite docs, follow the guide in [STYLE.md](./STYLE.md).
- 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
Appwrite's documentation uses extended markdown syntax. You can find all of the available partials types in the [CONTENT.md file](./CONTENT.md).
### Screenshots
- When contributing upload original screenshots. The Appwrite design team will edit the screenshot to be consistent with other screenshots in the docs.
- 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**.
### Content consistency
If you're contributing a **new piece of content**, always follow the closest example as an outline. For example, a new web quick start should use one of the existing web quick starts as example, with the same content and pages.
If you can't find a similar piece of content as example, the Appwrite team will request an ourline from you.
It should contain all the pages and headings with in them, maintainers may request clarification on headings.
```md
# page 1
## heading a
## heading b
...
# page 2
## heading a
## heading b
...
# page 3
## heading a
## heading b
...
...
```

View File

@@ -1,4 +1,4 @@
FROM node:20-bullseye AS build FROM node:20-bullseye as base
ARG PUBLIC_APPWRITE_COL_MESSAGES_ID ARG PUBLIC_APPWRITE_COL_MESSAGES_ID
ENV PUBLIC_APPWRITE_COL_MESSAGES_ID ${PUBLIC_APPWRITE_COL_MESSAGES_ID} ENV PUBLIC_APPWRITE_COL_MESSAGES_ID ${PUBLIC_APPWRITE_COL_MESSAGES_ID}
@@ -15,21 +15,52 @@ ENV PUBLIC_APPWRITE_FN_TLDR_ID ${PUBLIC_APPWRITE_FN_TLDR_ID}
ARG PUBLIC_APPWRITE_PROJECT_ID ARG PUBLIC_APPWRITE_PROJECT_ID
ENV PUBLIC_APPWRITE_PROJECT_ID ${PUBLIC_APPWRITE_PROJECT_ID} ENV PUBLIC_APPWRITE_PROJECT_ID ${PUBLIC_APPWRITE_PROJECT_ID}
ARG PUBLIC_APPWRITE_PROJECT_INIT_ID
ENV PUBLIC_APPWRITE_PROJECT_INIT_ID ${PUBLIC_APPWRITE_PROJECT_INIT_ID}
ARG PUBLIC_GROWTH_ENDPOINT
ENV PUBLIC_GROWTH_ENDPOINT ${PUBLIC_GROWTH_ENDPOINT}
ARG APPWRITE_DB_INIT_ID
ENV APPWRITE_DB_INIT_ID ${APPWRITE_DB_INIT_ID}
ARG APPWRITE_COL_INIT_ID
ENV APPWRITE_COL_INIT_ID ${APPWRITE_COL_INIT_ID}
ARG APPWRITE_API_KEY_INIT
ENV APPWRITE_API_KEY_INIT ${APPWRITE_API_KEY_INIT}
ARG GITHUB_TOKEN
ENV GITHUB_TOKEN ${GITHUB_TOKEN}
ARG SENTRY_AUTH_TOKEN
ENV SENTRY_AUTH_TOKEN ${SENTRY_AUTH_TOKEN}
ENV PNPM_HOME="/pnpm" ENV PNPM_HOME="/pnpm"
ENV PATH="$PNPM_HOME:$PATH" ENV PATH="$PNPM_HOME:$PATH"
WORKDIR /app WORKDIR /app
COPY . . COPY package.json package.json
COPY pnpm-lock.yaml pnpm-lock.yaml
RUN corepack enable RUN corepack enable
FROM base as build
COPY . .
RUN --mount=type=cache,id=pnpm,target=/pnpm/store pnpm install --frozen-lockfile RUN --mount=type=cache,id=pnpm,target=/pnpm/store pnpm install --frozen-lockfile
RUN NODE_OPTIONS=--max_old_space_size=8192 pnpm run build RUN NODE_OPTIONS=--max_old_space_size=8192 pnpm run build
# Node alpine image to serve the generated static files FROM base as final
FROM node:20-alpine AS serve
WORKDIR /app # Install fontconfig
COPY --from=build /app . COPY ./local-fonts /usr/share/fonts
RUN apt-get update && \
apt-get install -y fontconfig && \
apt-get autoremove --purge && \
rm -rf /var/lib/apt/lists/*
RUN fc-cache -f -v
COPY --from=build /app/build/ build
COPY --from=build /app/server/ server
RUN --mount=type=cache,id=pnpm,target=/pnpm/store pnpm install --frozen-lockfile --prod
EXPOSE 3000
CMD [ "node", "server/main.js"] CMD [ "node", "server/main.js"]

View File

@@ -15,7 +15,7 @@ The Appwrite Website has been built with the following frameworks:
## Development ## Development
*If this is your first time setting up the repository, please run `pnpm install` inside the repo's directory.* _If this is your first time setting up the repository, please run `pnpm install` inside the repo's directory._
To get the repo up and running in your local environment, use the following command: To get the repo up and running in your local environment, use the following command:
@@ -37,8 +37,8 @@ For security issues, kindly email us at [security@appwrite.io](mailto:security@a
## Follow Us ## Follow Us
Join our growing community around the world! See our official [Blog](https://medium.com/appwrite-io). Follow us on [Twitter](https://twitter.com/appwrite), [Facebook Page](https://www.facebook.com/appwrite.io), [Facebook Group](https://www.facebook.com/groups/appwrite.developers/), and [Dev Community](https://dev.to/appwrite) or join our live [Discord server](https://appwrite.io/discord) for more help, ideas, and discussions. Join our growing community around the world! See our official [Blog](https://appwrite.io/blog). Follow us on [X](https://twitter.com/appwrite), [Facebook Page](https://www.facebook.com/appwrite.io), [Facebook Group](https://www.facebook.com/groups/appwrite.developers/), and [Dev Community](https://dev.to/appwrite) or join our live [Discord server](https://appwrite.io/discord) for more help, ideas, and discussions.
## License ## License
Appwrite website, docs and blog © 2023 by Appwrite is licensed under [CC BY-NC-ND 4.0](https://creativecommons.org/licenses/by-nc-nd/4.0/). Appwrite website, docs and blog © 2024 by Appwrite is licensed under [CC BY-NC-ND 4.0](https://creativecommons.org/licenses/by-nc-nd/4.0/).

97
RELEASE.md Normal file
View File

@@ -0,0 +1,97 @@
# Steps to releasing a new Appwrite version
There are a handful of steps required to udpate the website for a new version of Appwrite:
1. Replace all references of appwrite/appwrite:x.y.z with the latest version
1. Update manual installation files
1. Bump appwrite repo so latest main commit is used
To simplify the process, you may use the following script:
```shell
#!/bin/bash
# exit on error
set -e
if [ -z "$1" ]
then
echo "Usage: $0 <version>"
exit 1
fi
VERSION=$1
git stash
git checkout main
git pull
git checkout -b feat-$VERSION-release
# Replace all references of appwrite/appwrite:x.y.z with appwrite/appwrite:$VERSION
PATHS=(
'src/routes/docs/advanced/self-hosting'
'src/routes/blog/post'
)
for p in "${PATHS[@]}"; do
grep -rl "appwrite/appwrite:[0-9]*\.[0-9]*\.[0-9]*" "$p" | xargs sed -i.bak "s#appwrite/appwrite:.*#appwrite/appwrite:$VERSION#g"
git add "$p/**/*.markdoc"
git add "$p/*.markdoc"
done
# Update manual installation files
cd static/install
docker run -it --rm \
--volume /var/run/docker.sock:/var/run/docker.sock \
--volume "$(pwd)"/appwrite:/usr/src/code/appwrite:rw \
--entrypoint="install" \
appwrite/appwrite:$VERSION --http-port=80 --https-port=443 --interactive=N --no-start=true
cp appwrite/docker-compose.yml compose
cp appwrite/.env env
sed -i.bak "s#_APP_OPENSSL_KEY_V1=.*#_APP_OPENSSL_KEY_V1=your-secret-key#g" env
sed -i.bak "s#_APP_DB_PASS=.*#_APP_DB_PASS=password#g" env
sed -i.bak "s#_APP_DB_ROOT_PASS=.*#_APP_DB_ROOT_PASS=rootsecretpassword#g" env
git add compose env
rm -rf appwrite
cd -
# Bump appwrite repo so latest main commit is used
pnpm update @appwrite.io/repo
git add pnpm-lock.yaml
git commit -m "Bump Appwrite version to $VERSION"
read -p "Ready to push? (y/n) " -n 1 -r
if [[ $REPLY =~ ^[Yy]$ ]]; then
git push -u origin HEAD
fi
echo PR Link:
echo "https://github.com/appwrite/website/compare/main...feat-$VERSION-release?expand=1&title=Bump%20Appwrite%20version%20to%20$VERSION&body=%23%23%20What%20does%20this%20PR%20do%3F%0A%0AUpdate%20installation%20and%20upgrade%20instructions%20to%20use%20the%20latest%20Appwrite%20version%0A%0A%23%23%20Test%20Plan%0A%0AManual%0A%0A%23%23%20Related%20PRs%20and%20Issues%0A%0ANone%0A%0A%23%23%23%20Have%20you%20read%20the%20%5BContributing%20Guidelines%20on%20issues%5D%28https%3A%2F%2Fgithub.com%2Fappwrite%2Fappwrite%2Fblob%2Fmaster%2FCONTRIBUTING.md%29%3F%0A%0AYes"
echo
echo PR Subject:
echo "Bump Appwrite version to $VERSION"
echo
echo PR Body:
echo "## What does this PR do?
Update installation and upgrade instructions to use the latest Appwrite version
## Test Plan
Manual
## Related PRs and Issues
None
### Have you read the [Contributing Guidelines on issues](https://github.com/appwrite/appwrite/blob/master/CONTRIBUTING.md)?
Yes"
```
Run the script like:
```shell
./prep_release.sh 1.5.7
```
It will also output a link you can use to create PR with a populated description.

323
STYLE.md Normal file
View File

@@ -0,0 +1,323 @@
# Documentation contributing guide
Read this document carefully before making PRs to the Appwrite Website repo.
## What goes in docs?
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.
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.
Note that the tutorials and blogs available on the Appwrite blog and docs are meant for these types of information.
## Documentation structure
The Appwrite docs is split into sections, each with its intended purpose and content.
Appwrite's navigation increases in complexity from top down. We expect users to view links later in navigation later in their development journey.
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)
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)
APIs section:
- [GraphQL](https://appwrite.io/docs/apis/graphql)
- [REST](https://appwrite.io/docs/apis/rest)
- [Realtime](https://appwrite.io/docs/apis/realtime)
Tooling section:
- [Command Line](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)
Here's the intended purpose and structure of each section.
### Introduction
This section is focused on introducing what Appwrite is and giving examples to the user to understand both how to get started and how to perform canned tasks.
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
### Products
Each page covers an Appwrite product. These pages describe the expected behavior of the product and are **unopinionated** and **technology-agnostic**.
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.
### APIs section
Describes consuming APIs, which are a little more advanced, like using REST API directly or GraphQL directly.
### Tooling section
Describes tools that help you work with Appwrite, but are usually non-essential and not end-user facing.
### Advanced section
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.
## Documentation sources
The Appwrite docs are compiled from different repositories. Here are the significant touch points you need to know about.
[appwrite/website](https://github.com/appwrite/website):
- 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
[appwrite/sdk-generator](https://github.com/appwrite/sdk-generator):
- Generated examples
## Markdown Style guidelines
For consistency the Appwrite documentation follows a strict set of style guidelines, so no matter who is writing the documentation,
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".
### Extended Markdoc components
Appwrite's documentation uses extended markdown syntax. You can find all of the available partials types in the [CONTENT.md file](./CONTENT.md).
### 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.
```md
{% only_dark %}
![Project settings screen](/images/docs/platform/dark/create-api-key.png)
{% /only_dark %}
{% only_light %}
![Project settings screen](/images/docs/platform/create-api-key.png)
{% /only_light %}
```
### Content consistency
If you're contributing a **new piece of content**, always follow the closest example as an outline. For example, a new web quick start should use one of the existing web quick starts as example, with the same content and pages.
If you can't find a similar piece of content as example, the Appwrite team will request an outline from you.
It should contain all the pages and headings with in them, maintainers may request clarification on headings.
```md
# page 1
## heading a
## heading b
...
# page 2
## heading a
## heading b
...
# page 3
## heading a
## heading b
...
...
```
### Content splitting
Split content to make them easier to read. Split long sentences and long paragraphs such that key concepts can be obtained even when skimming through only first few words of paragraphs.
Split content such that each piece makes sense without reading dependents or explicitly link pre-requisit material.
## Common workflows
### 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
### Documenting a new API
- Add a new .md file describing the new API here: <https://github.com/appwrite/appwrite/tree/main/docs/references>
- Add descriptions for methods and parameters in the controller code: <https://github.com/appwrite/appwrite/tree/main/app/controllers/api>
- 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
### 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
## Language and diction
### Headings
Prefer simple nouns and root form verbs.
✅ Create screen (root verb, noun)
✅ Authentication (noun)
❌ Authenticating (present participle verb)
❌ Create a new screen (too wordy)
Try your best to stick to simple headings, if it's not possible, don't worry and write a full heading if need be.
### Links
Avoid unclear [links](https://www.youtube.com/watch?v=dQw4w9WgXcQ) such as learn more [here](https://www.youtube.com/watch?v=dQw4w9WgXcQ).
Readers will be unsure where a link may take them. Those using a screen reader will find it especially difficult.
✅ [Learn more about authentication](https://appwrite.io/docs/products/auth/email-password#login)
❌ Learn more about authentication [here](https://www.youtube.com/watch?v=dQw4w9WgXcQ)
### Sentences
Use a directive that's straight to the point when providing an action a developer must perform.
The action and verb always comes first, the explanation after.
✅ Create a new database.
✅ Update a document so its permissions include your new users.
❌ To allow access, update your permissions.
❌ You can create a new database for each tenant.
❌ Creating a new bucket lets you set different permissions for images uploaded by users.
The action always comes first and is in the beginning of the sentence, which makes important steps easier to follow.
If a step is more of a suggestion or is optional, you can intentially use another form to make it easier for users
to skip and scan a document.
### Paragraphs
Like sentences, important information always comes first.
This makes it easier to scan through the page.
✅ Clear, important information such as actions come first
> Store secrets as environment variables in vaults by navigating to **settings** > **security** > **vault**. Your secrets should never be shared. You must ensure data privacy, sharing secrets can compromise security during development.
❌ Unclear, important information is in the middle of the paragraph
> Security is important in development. That's why you should take care to protect secrets. Secrets should be safely stored as a environment variable in a vault. You can find vaults under **settings** > **security** > **vault**. Don't share this with anyone!
If there are multiple important actions or pieces of information, **break up the paragraph**.
Even if your paragraph is just one or two sentences, shorter paragraphs are easier to scan.
### Diction
If you're unsure about which word to use to describe a concept, you shuold look for precedence in the following order.
1. Appwrite docs
2. Appwrite Console
3. Appwrite API specs
4. Existing blogs
5. Follow other products when possible.
6. If all other avenues are explored, propose a new term. Clearly outline in your PR and come to agreement with the Appwrite team.
### Page structure
Quick starts, tutorials, product docs, and other pages should stick very close to existing examples.
This applies to tone, structure, and content. Unless no exisitng examples of a page type exist,
or a page needs to be sufficiently different from existing pages, follow exisitng examples.
If you are proposing a new type of page, discuss an outline in your PR and ask for the Appwrite team's review.
## Code snippets
For quick starts and tutorials, a developer must be able to follow code examples from beginning to end
easily, and the code example is expected to be runnable and complete.
This means, you need to include imports, dependencies, and all parts needed to arrive at a functional example.
For concept and journey product pages, still try your best to have complete examples, unless:
1. The example will become opinionated. We avoid opinionated implementation and choices in product pages. Keep them in blogs, quick starts, and tutorials.
2. The example cannot be given in a complete form cleanly. For example, many of the Messaging services's examples cannot be given in complete form because the boiler plate and set up is complex and documented in Android/Swift documentation.

View File

@@ -1,5 +1,3 @@
version: '3.8'
services: services:
traefik: traefik:
image: traefik:2.9 image: traefik:2.9
@@ -12,11 +10,14 @@ services:
- --entrypoints.websecure.address=:443 - --entrypoints.websecure.address=:443
- --providers.docker.constraints=Label(`traefik.constraint-label-stack`,`homepage`) - --providers.docker.constraints=Label(`traefik.constraint-label-stack`,`homepage`)
- --accesslog=true - --accesslog=true
labels:
- traefik.http.routers.traefik.middlewares=traefik-compress
- traefik.http.middlewares.traefik-compress.compress=true
ports: ports:
- 80:80 - 80:80
- 8080:8080 - 8080:8080
volumes: volumes:
- /letsencrypt:/letsencrypt # - /letsencrypt:/letsencrypt
- /var/run/docker.sock:/var/run/docker.sock - /var/run/docker.sock:/var/run/docker.sock
networks: networks:
- homepage - homepage
@@ -25,23 +26,33 @@ services:
image: homepage-dev image: homepage-dev
build: build:
context: . context: .
args:
- 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 restart: always
networks: networks:
- homepage - homepage
labels: labels:
- traefik.enable=true - traefik.enable=true
- traefik.constraint-label-stack=homepage - traefik.constraint-label-stack=homepage
- traefik.docker.network=homepage - traefik.docker.network=appwrite
- traefik.http.services.homepage.loadbalancer.server.port=3000 - traefik.http.middlewares.appwrite_middlewares.compress=true
- traefik.http.services.appwrite_service.loadbalancer.server.port=3000
#http #http
- traefik.http.routers.homepage.entrypoints=web - traefik.http.routers.appwrite.entrypoints=web
- traefik.http.routers.homepage.rule=PathPrefix(`/`) - traefik.http.routers.appwrite.rule=PathPrefix(`/`)
- traefik.http.routers.homepage.service=homepage - traefik.http.routers.appwrite.service=appwrite_service
- traefik.http.routers.appwrite.middlewares=appwrite_middlewares
# https # https
- traefik.http.routers.homepage_secure.entrypoints=websecure - traefik.http.routers.appwrite_secure.entrypoints=websecure
- traefik.http.routers.homepage_secure.rule=PathPrefix(`/`) - traefik.http.routers.appwrite_secure.rule=PathPrefix(`/`)
- traefik.http.routers.homepage_secure.service=homepage - traefik.http.routers.appwrite_secure.service=appwrite_service
- traefik.http.routers.homepage_secure.tls=true - traefik.http.routers.appwrite_secure.tls=true
- traefik.http.routers.appwrite_secure.middlewares=appwrite_middlewares
networks: networks:
homepage: homepage:

View File

@@ -9,8 +9,8 @@ x-update-config: &x-update-config
update_config: update_config:
order: stop-first order: stop-first
failure_action: rollback failure_action: rollback
parallelism: 2 parallelism: 1
delay: 5s delay: 10s
rollback_config: rollback_config:
failure_action: pause failure_action: pause
monitor: 5s monitor: 5s
@@ -49,11 +49,17 @@ services:
networks: networks:
- cloud - cloud
deploy: deploy:
replicas: 1 replicas: 3
<<: *x-update-config <<: *x-update-config
placement: placement:
max_replicas_per_node: 1
constraints: constraints:
- node.role == manager - node.role == manager
preferences:
- spread: node.role == worker
labels:
- traefik.http.routers.traefik.middlewares=traefik-compress
- traefik.http.middlewares.traefik-compress.compress=true
server: server:
image: ghcr.io/appwrite/website:$_APP_VERSION image: ghcr.io/appwrite/website:$_APP_VERSION
@@ -70,7 +76,7 @@ services:
deploy: deploy:
<<: *x-update-config <<: *x-update-config
mode: replicated mode: replicated
replicas: 5 replicas: 8
placement: placement:
max_replicas_per_node: 2 max_replicas_per_node: 2
constraints: constraints:
@@ -79,18 +85,22 @@ services:
- spread: node.role == worker - spread: node.role == worker
labels: labels:
- traefik.enable=true - traefik.enable=true
- traefik.docker.lbswarm=true
- traefik.constraint-label-stack=appwrite - traefik.constraint-label-stack=appwrite
- traefik.http.services.appwrite_api.loadbalancer.server.port=3000 - traefik.http.services.appwrite_service.loadbalancer.server.port=3000
- traefik.http.middlewares.appwrite_middlewares.compress=true
#http #http
- traefik.http.routers.appwrite.entrypoints=web - traefik.http.routers.appwrite.entrypoints=web
- traefik.http.routers.appwrite.rule=Host(`$_APP_DOMAIN`) || Host(`www.$_APP_DOMAIN`) - traefik.http.routers.appwrite.rule=Host(`$_APP_DOMAIN`) || Host(`www.$_APP_DOMAIN`)
- traefik.http.routers.appwrite.service=appwrite_api - traefik.http.routers.appwrite.service=appwrite_service
- traefik.http.routers.appwrite.middlewares=appwrite_middlewares
# https # https
- traefik.http.routers.appwrite_secure.entrypoints=websecure - 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.rule=Host(`$_APP_DOMAIN`) || Host(`www.$_APP_DOMAIN`)
- traefik.http.routers.appwrite_secure.service=appwrite_api - traefik.http.routers.appwrite_secure.service=appwrite_service
- traefik.http.routers.appwrite_secure.tls=true - traefik.http.routers.appwrite_secure.tls=true
- traefik.http.routers.appwrite_secure.tls.certresolver=myresolver - traefik.http.routers.appwrite_secure.tls.certresolver=myresolver
- traefik.http.routers.appwrite_secure.middlewares=appwrite_middlewares
janitor: janitor:
image: appwrite/docker-janitor image: appwrite/docker-janitor

View File

@@ -9,8 +9,8 @@ x-update-config: &x-update-config
update_config: update_config:
order: stop-first order: stop-first
failure_action: rollback failure_action: rollback
parallelism: 2 parallelism: 1
delay: 5s delay: 10s
rollback_config: rollback_config:
failure_action: pause failure_action: pause
monitor: 5s monitor: 5s
@@ -50,11 +50,17 @@ services:
networks: networks:
- cloud - cloud
deploy: deploy:
replicas: 1 replicas: 3
<<: *x-update-config <<: *x-update-config
placement: placement:
max_replicas_per_node: 1
constraints: constraints:
- node.role == manager - node.role == manager
preferences:
- spread: node.role == worker
labels:
- traefik.http.routers.traefik.middlewares=traefik-compress
- traefik.http.middlewares.traefik-compress.compress=true
server: server:
image: ghcr.io/appwrite/website:$_APP_VERSION image: ghcr.io/appwrite/website:$_APP_VERSION
@@ -71,7 +77,7 @@ services:
deploy: deploy:
<<: *x-update-config <<: *x-update-config
mode: replicated mode: replicated
replicas: 5 replicas: 8
placement: placement:
max_replicas_per_node: 2 max_replicas_per_node: 2
constraints: constraints:
@@ -80,18 +86,22 @@ services:
- spread: node.role == worker - spread: node.role == worker
labels: labels:
- traefik.enable=true - traefik.enable=true
- traefik.docker.lbswarm=true
- traefik.constraint-label-stack=appwrite - traefik.constraint-label-stack=appwrite
- traefik.http.services.appwrite_api.loadbalancer.server.port=3000 - traefik.http.services.appwrite_service.loadbalancer.server.port=3000
- traefik.http.middlewares.appwrite_middlewares.compress=true
#http #http
- traefik.http.routers.appwrite.entrypoints=web - traefik.http.routers.appwrite.entrypoints=web
- traefik.http.routers.appwrite.rule=Host(`$_APP_DOMAIN`) || Host(`www.$_APP_DOMAIN`) - traefik.http.routers.appwrite.rule=Host(`$_APP_DOMAIN`) || Host(`www.$_APP_DOMAIN`)
- traefik.http.routers.appwrite.service=appwrite_api - traefik.http.routers.appwrite.service=appwrite_service
- traefik.http.routers.appwrite.middlewares=appwrite_middlewares
# https # https
- traefik.http.routers.appwrite_secure.entrypoints=websecure - 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.rule=Host(`$_APP_DOMAIN`) || Host(`www.$_APP_DOMAIN`)
- traefik.http.routers.appwrite_secure.service=appwrite_api - traefik.http.routers.appwrite_secure.service=appwrite_service
- traefik.http.routers.appwrite_secure.tls=true - traefik.http.routers.appwrite_secure.tls=true
- traefik.http.routers.appwrite_secure.tls.certresolver=myresolver - traefik.http.routers.appwrite_secure.tls.certresolver=myresolver
- traefik.http.routers.appwrite_secure.middlewares=appwrite_middlewares
janitor: janitor:
image: appwrite/docker-janitor image: appwrite/docker-janitor

Binary file not shown.

Binary file not shown.

View File

@@ -1,74 +1,74 @@
{ {
"name": "website-svelte", "name": "appwrite-website",
"version": "0.0.1", "version": "0.0.1",
"private": true, "private": true,
"type": "module",
"scripts": { "scripts": {
"dev": "vite dev", "build": "pnpm download-contributors && vite build",
"build": "vite build",
"preview": "vite preview",
"test": "npm run test:integration && npm run test:unit",
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json", "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch", "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
"lint": "prettier --plugin-search-dir . --check . && eslint .",
"format": "prettier --plugin-search-dir . --write .",
"clean": "rm -rf node_modules && rm -rf .svelte_kit && pnpm i", "clean": "rm -rf node_modules && rm -rf .svelte_kit && pnpm i",
"test:integration": "playwright test", "dev": "vite dev",
"test:unit": "vitest", "download-contributors": "node ./scripts/download-contributor-data.js",
"format": "prettier --plugin-search-dir . --write .",
"icons:build": "node ./src/icons/build.js", "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", "icons:optimize": "node ./src/icons/optimize.js",
"icons:generate": "node ./src/icons/optimize.js && node ./src/icons/build.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"
},
"packageManager": "pnpm@9.4.0+sha512.f549b8a52c9d2b8536762f99c0722205efc5af913e77835dbccc3b0b0b2ca9e7dc8022b78062c17291c48e88749c70ce88eb5a74f1fa8c4bf5e18bb46c8bd83a",
"dependencies": {
"@sentry/sveltekit": "^8.12.0",
"h3": "^1.12.0"
}, },
"devDependencies": { "devDependencies": {
"@melt-ui/pp": "^0.1.4", "@appwrite.io/console": "^0.6.2",
"@melt-ui/svelte": "^0.65.0", "@appwrite.io/pink": "~0.16.0",
"@playwright/test": "^1.40.0", "@appwrite.io/pink-icons": "~0.16.0",
"@sveltejs/adapter-node": "^1.3.1", "@appwrite.io/repo": "github:appwrite/appwrite#main",
"@sveltejs/adapter-static": "^2.0.3", "@internationalized/date": "3.5.0",
"@sveltejs/enhanced-img": "^0.1.2", "@melt-ui/pp": "^0.3.2",
"@sveltejs/kit": "1.30.0", "@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",
"@types/compression": "^1.7.5", "@types/compression": "^1.7.5",
"@types/glob": "^8.1.0", "@types/glob": "^8.1.0",
"@types/markdown-it": "^13.0.7", "@types/markdown-it": "^13.0.8",
"@types/morgan": "^1.9.9", "@types/morgan": "^1.9.9",
"@typescript-eslint/eslint-plugin": "^5.62.0", "@typescript-eslint/eslint-plugin": "^7.13.1",
"@typescript-eslint/parser": "^5.62.0", "@typescript-eslint/parser": "^7.13.1",
"appwrite": "^13.0.1", "dequal": "^2.0.3",
"eslint": "^8.54.0", "eslint": "^8.57.0",
"eslint-config-prettier": "^8.10.0", "eslint-config-prettier": "^8.10.0",
"eslint-plugin-svelte": "^2.35.1", "eslint-plugin-svelte": "^2.40.0",
"glob": "^10.3.10", "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", "openapi-types": "^12.1.3",
"oslllo-svg-fixer": "^3.0.0", "oslllo-svg-fixer": "^3.0.0",
"prettier": "^2.8.8", "prettier": "^3.3.2",
"prettier-plugin-svelte": "^2.10.1", "prettier-plugin-svelte": "^3.2.5",
"sass": "^1.69.7", "sass": "^1.77.6",
"svelte": "^4.2.7", "sharp": "^0.33.4",
"svelte-check": "^3.6.0", "svelte": "^4.2.18",
"svelte-markdoc-preprocess": "^1.1.3", "svelte-check": "^3.8.1",
"svelte-sequential-preprocessor": "^2.0.1", "svelte-markdoc-preprocess": "^2.0.0",
"sveltekit-search-params": "^1.0.16", "svelte-markdown": "^0.4.1",
"svgo": "^3.0.4", "svgtofont": "^4.2.1",
"svgtofont": "^4.0.0", "tslib": "^2.6.3",
"tslib": "^2.6.2", "typescript": "^5.5.2",
"typescript": "^5.3.2", "vite": "^5.3.1",
"vite": "^4.5.1",
"vite-plugin-dynamic-import": "^1.5.0", "vite-plugin-dynamic-import": "^1.5.0",
"vite-plugin-image-optimizer": "^1.1.7", "vite-plugin-image-optimizer": "^1.1.8",
"vitest": "^0.32.4" "vitest": "^1.6.0"
},
"type": "module",
"dependencies": {
"@appwrite.io/pink": "0.1.0-next.9",
"@appwrite.io/pink-icons": "0.1.0-next.9",
"@appwrite.io/repo": "github:appwrite/appwrite#main",
"@splinetool/viewer": "0.9.455",
"compression": "^1.7.4",
"express": "^4.18.2",
"highlight.js": "^11.9.0",
"markdown-it": "^13.0.2",
"meilisearch": "^0.35.1",
"motion": "^10.16.4",
"sharp": "^0.32.6",
"svelte-markdown": "^0.4.0"
} }
} }

10794
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,100 @@
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}`
} : {}
console.log(`using github token: ${!!process.env.GITHUB_TOKEN}`)
async function fetchRepositories() {
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}`;
const response = await fetch(url, {
headers
});
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`);
}
return repositoriesData.map((repo) => repo.full_name);
}
async function fetchContributors(apiUrl) {
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
});
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`);
}
return contributorsData;
}
async function main() {
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);
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 currentContributors = fs.readFileSync(outputFile, 'utf8');
if (currentContributors.length >= contributorsFile.length) {
console.log('No new contributors found. Exiting...');
return;
}
fs.writeFileSync(outputFile, contributorsFile);
}
main();

View File

@@ -1,37 +0,0 @@
import { existsSync } from 'fs';
import { globSync } from 'glob';
import path from 'path';
import sharp from 'sharp';
console.log('Transforming images...');
const inputFormats = ['png', 'jpg', 'svg'];
const outputFormats = ['png', 'jpg'];
const files = globSync(`./static/assets/**/*.{${inputFormats.join(',')}}`);
console.log('Found files:', files);
files.forEach((file) => {
const fileName = path.basename(file, path.extname(file));
const fileDir = path.dirname(file);
console.log('Transforming file:', file);
outputFormats.forEach((format) => {
const outputFile = path.join(fileDir, `${fileName}.${format}`);
if (!existsSync(outputFile)) {
sharp(file)
.toFormat(format)
.toFile(outputFile, (err) => {
if (err) {
console.error(`Error transforming file ${file} to ${format}:`, err);
} else {
console.log(`Transformed file ${file} to ${format}`);
}
});
} else {
console.log(`File ${outputFile} already exists. Skipping transformation.`);
}
});
});

View File

@@ -1,9 +0,0 @@
/**
* @returns {import('express').RequestHandler}
*/
export function cache() {
return function (_req, res, next) {
res.setHeader('Cache-Control', 'max-age=3600, no-cache');
next();
}
}

View File

@@ -1,18 +1,17 @@
import express from 'express'; import { createApp, fromNodeMiddleware, toNodeListener } from 'h3';
import compression from 'compression' import { createServer } from 'node:http';
import { cache } from './cache.js';
import { sitemap } from './sitemap.js'
import { handler } from '../build/handler.js'; import { handler } from '../build/handler.js';
import { sitemap } from './sitemap.js';
async function main() { async function main() {
const app = express(); const port = process.env.PORT || 3000;
app.use(cache()); const app = createApp();
app.use(compression()); app.use('/sitemap.xml', await sitemap());
app.use(await sitemap()); app.use(fromNodeMiddleware(handler));
app.use(handler); const server = createServer(toNodeListener(app)).listen(port);
app.listen(3000, () => { server.addListener('listening', () => {
console.log('Listening on http://0.0.0.0:3000'); console.log(`Listening on http://0.0.0.0:${port}`);
}); });
} }
main(); main();

View File

@@ -1,23 +1,43 @@
import { createRequire } from 'node:module';
import { defineEventHandler, setResponseHeader } from 'h3';
/** /**
* @returns {Promise<import('express').RequestHandler>} * @returns {Promise<import('h3').EventHandler>}
*/ */
export async function sitemap() { export async function sitemap() {
console.info('Preparing Sitemap...');
const manifest = await import('../build/server/manifest.js'); const manifest = await import('../build/server/manifest.js');
const prerendered = manifest.prerendered; 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 = `<?xml version="1.0" encoding="UTF-8"?> const sitemap = `<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"> <urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
${[...prerendered].filter(route => !route.endsWith('.json')).map(route => `<url> ${routes
.map(
(route) => `<url>
<loc>https://appwrite.io${route}</loc> <loc>https://appwrite.io${route}</loc>
</url> </url>
`).join('')} `
)
.join('')}
</urlset>`; </urlset>`;
return async (req, res, next) => { return defineEventHandler((event) => {
if (req.url === '/sitemap.xml') { setResponseHeader(event, 'Content-Type', 'application/xml');
res.setHeader('Content-Type', 'application/xml');
return res.send(sitemap); return sitemap;
} });
next(); }
}
} /**
* @returns {string[]}
*/
function collectThreads() {
const threads = createRequire(import.meta.url)('../build/prerendered/threads/data.json');
return threads.map((id) => `/threads/${id}`);
}

View File

@@ -33,6 +33,8 @@
document.body.classList.add(`theme-${systemTheme}`); document.body.classList.add(`theme-${systemTheme}`);
} else { } else {
document.body.classList.add(`theme-${theme}`); document.body.classList.add(`theme-${theme}`);
// Color scheme in html
document.documentElement.style.setProperty('color-scheme', theme);
} }
} }
} }
@@ -46,6 +48,11 @@
if (hideBanner === 'true') { if (hideBanner === 'true') {
document.body.dataset.bannerHidden = ''; document.body.dataset.bannerHidden = '';
} }
// Is logged in
const isLoggedIn = localStorage.getItem('appwrite:user');
if (isLoggedIn) {
document.body.dataset.loggedIn = '';
}
</script> </script>
<div style="display: contents">%sveltekit.body%</div> <div style="display: contents">%sveltekit.body%</div>
</body> </body>

29
src/hooks.client.ts Normal file
View File

@@ -0,0 +1,29 @@
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,
// 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 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`
export const handleError = handleErrorWithSentry();

View File

@@ -1,7 +1,16 @@
import * as Sentry from '@sentry/sveltekit';
import type { Handle } from '@sveltejs/kit'; import type { Handle } from '@sveltejs/kit';
import redirects from './redirects.json'; import redirects from './redirects.json';
import { sequence } from '@sveltejs/kit/hooks'; import { sequence } from '@sveltejs/kit/hooks';
import { BANNER_KEY } from '$lib/constants'; 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/]
})
const redirectMap = new Map(redirects.map(({ link, redirect }) => [link, redirect])); const redirectMap = new Map(redirects.map(({ link, redirect }) => [link, redirect]));
@@ -26,4 +35,5 @@ const bannerRewriter: Handle = async ({ event, resolve }) => {
return response; return response;
}; };
export const handle = sequence(redirecter, bannerRewriter); export const handle = sequence(Sentry.sentryHandle(), redirecter, bannerRewriter);
export const handleError = Sentry.handleErrorWithSentry();

View File

@@ -0,0 +1 @@
<svg width="18" height="17" viewBox="0 0 18 17" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M7.232 0.031 C 5.975 0.153,4.795 0.554,3.754 1.214 C 2.817 1.808,1.918 2.698,1.313 3.630 C 0.623 4.692,0.155 6.011,0.028 7.250 C -0.026 7.774,0.007 9.014,0.087 9.480 C 0.288 10.645,0.725 11.762,1.344 12.690 C 1.698 13.220,1.949 13.528,2.370 13.952 C 3.726 15.316,5.458 16.113,7.380 16.259 C 7.634 16.278,9.695 16.290,12.893 16.290 L 18.000 16.290 18.000 14.250 L 18.000 12.210 12.817 12.210 C 7.090 12.210,7.351 12.218,6.731 12.017 C 6.099 11.812,5.664 11.544,5.172 11.055 C 4.403 10.291,4.012 9.404,3.970 8.325 C 3.943 7.637,4.040 7.083,4.288 6.508 C 4.810 5.296,5.845 4.437,7.125 4.153 C 7.450 4.081,8.144 4.065,8.515 4.122 C 9.216 4.229,9.955 4.572,10.471 5.029 C 10.694 5.226,11.001 5.565,11.130 5.755 L 11.235 5.910 13.387 5.910 C 14.571 5.910,15.540 5.901,15.540 5.891 C 15.540 5.834,15.397 5.401,15.278 5.100 C 14.860 4.036,14.271 3.139,13.456 2.323 C 12.234 1.099,10.744 0.344,9.045 0.087 C 8.592 0.019,7.659 -0.010,7.232 0.031 M11.768 7.103 C 11.870 7.659,11.885 7.836,11.869 8.295 C 11.852 8.795,11.812 9.032,11.680 9.435 C 11.503 9.973,11.186 10.520,10.831 10.899 L 10.643 11.100 14.322 11.100 L 18.000 11.100 18.000 9.060 L 18.000 7.020 14.877 7.020 L 11.753 7.020 11.768 7.103 " fill="#414146" stroke="none" fill-rule="evenodd"></path></svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@@ -0,0 +1 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M7.057 1.039 C 6.917 1.095,6.771 1.304,6.744 1.487 C 6.730 1.582,6.243 4.729,5.662 8.480 C 5.082 12.231,4.611 15.304,4.616 15.309 C 4.621 15.314,5.836 13.141,7.316 10.480 L 10.007 5.642 8.827 3.411 C 7.572 1.036,7.546 0.997,7.264 1.003 C 7.196 1.004,7.103 1.020,7.057 1.039 M11.858 4.123 C 11.791 4.142,11.699 4.199,11.654 4.249 C 11.596 4.314,4.496 17.042,4.329 17.380 C 4.292 17.454,5.075 16.671,9.573 12.128 C 12.041 9.635,14.065 7.574,14.071 7.547 C 14.084 7.490,12.471 4.382,12.369 4.267 C 12.303 4.192,12.076 4.076,12.011 4.084 C 11.994 4.086,11.925 4.103,11.858 4.123 M17.223 5.542 C 17.114 5.579,15.666 6.998,11.330 11.313 C 3.959 18.648,4.015 18.592,4.061 18.632 C 4.083 18.651,5.730 19.613,7.722 20.770 C 10.202 22.210,11.418 22.895,11.580 22.942 C 11.853 23.021,12.258 23.004,12.500 22.903 C 12.646 22.841,19.793 18.733,19.931 18.631 C 19.995 18.584,19.926 18.142,18.939 12.240 C 18.355 8.753,17.858 5.850,17.834 5.789 C 17.745 5.566,17.472 5.456,17.223 5.542 " fill="#414146" stroke="none" fill-rule="evenodd"></path></svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -0,0 +1 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M11.340 3.024 C 10.026 3.160,9.091 3.415,8.060 3.918 C 5.286 5.272,3.420 7.912,3.059 10.992 C 2.620 14.745,4.632 18.403,8.060 20.083 C 10.550 21.304,13.449 21.303,15.940 20.081 C 16.582 19.766,17.102 19.438,17.626 19.018 C 18.006 18.712,18.680 18.067,18.680 18.008 C 18.680 17.971,17.301 16.800,17.257 16.800 C 17.242 16.800,17.064 16.959,16.861 17.153 C 15.819 18.149,14.530 18.779,13.040 19.019 C 12.484 19.108,11.445 19.100,10.874 19.002 C 8.375 18.573,6.351 16.954,5.421 14.640 C 4.863 13.253,4.764 11.638,5.146 10.184 C 5.789 7.736,7.736 5.789,10.184 5.146 C 11.293 4.854,12.639 4.844,13.716 5.119 C 15.446 5.561,16.918 6.602,17.915 8.090 C 18.686 9.242,19.117 10.715,19.070 12.040 C 19.048 12.676,18.964 12.950,18.710 13.226 C 18.317 13.652,17.612 13.539,17.370 13.010 C 17.276 12.805,17.272 12.768,17.299 12.346 C 17.449 9.933,15.959 7.735,13.648 6.961 C 13.120 6.784,12.658 6.715,12.000 6.715 C 11.342 6.715,10.880 6.784,10.352 6.961 C 8.603 7.547,7.306 8.938,6.856 10.710 C 6.342 12.740,7.080 14.884,8.740 16.179 C 10.131 17.265,11.925 17.587,13.612 17.054 C 14.628 16.733,15.591 16.048,16.230 15.193 C 16.375 14.999,16.498 14.840,16.504 14.840 C 16.510 14.840,16.606 14.936,16.717 15.053 C 17.082 15.439,17.534 15.614,18.160 15.612 C 20.167 15.606,21.267 13.779,20.941 10.992 C 20.819 9.950,20.536 8.984,20.083 8.060 C 19.190 6.237,17.762 4.810,15.944 3.923 C 15.066 3.494,14.269 3.244,13.320 3.101 C 12.911 3.039,11.662 2.991,11.340 3.024 M12.840 8.702 C 12.983 8.738,13.263 8.845,13.462 8.941 C 14.174 9.282,14.717 9.824,15.057 10.534 C 15.314 11.070,15.377 11.357,15.377 12.000 C 15.377 12.642,15.314 12.930,15.059 13.462 C 14.718 14.176,14.200 14.700,13.500 15.041 C 12.914 15.326,12.689 15.377,12.000 15.377 C 11.311 15.377,11.086 15.326,10.500 15.041 C 9.800 14.700,9.282 14.176,8.941 13.462 C 8.686 12.930,8.623 12.642,8.623 12.000 C 8.623 11.363,8.685 11.077,8.938 10.540 C 9.401 9.558,10.294 8.869,11.380 8.657 C 11.731 8.588,12.481 8.611,12.840 8.702 M11.601 10.502 C 11.149 10.628,10.787 10.934,10.584 11.360 C 10.472 11.594,10.460 11.658,10.460 12.000 C 10.460 12.343,10.472 12.405,10.585 12.640 C 10.850 13.192,11.417 13.560,12.003 13.560 C 12.458 13.560,12.968 13.294,13.254 12.907 C 13.853 12.098,13.501 10.914,12.554 10.554 C 12.270 10.446,11.876 10.424,11.601 10.502 " fill="#414146" stroke="none" fill-rule="evenodd"></path></svg>

After

Width:  |  Height:  |  Size: 2.4 KiB

View File

@@ -0,0 +1 @@
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M5.473 3.821 C 5.412 3.852,5.322 3.930,5.273 3.994 L 5.183 4.111 5.175 9.897 C 5.167 15.548,5.168 15.686,5.230 15.788 C 5.266 15.845,5.351 15.935,5.420 15.988 C 5.527 16.070,5.574 16.083,5.748 16.081 L 5.950 16.078 11.115 13.303 C 13.956 11.777,16.324 10.497,16.377 10.459 C 16.494 10.376,16.599 10.160,16.599 10.000 C 16.599 9.864,16.504 9.641,16.413 9.562 C 16.378 9.532,14.017 8.221,11.167 6.649 C 6.134 3.873,5.978 3.789,5.783 3.777 C 5.641 3.768,5.551 3.781,5.473 3.821 M11.573 8.243 C 13.310 9.200,14.720 9.993,14.707 10.006 C 14.666 10.045,6.459 14.442,6.395 14.458 C 6.335 14.474,6.333 14.328,6.333 9.943 C 6.333 7.450,6.342 5.403,6.352 5.393 C 6.362 5.383,6.831 5.628,7.393 5.939 C 7.956 6.249,9.837 7.286,11.573 8.243 " stroke="none" fill-rule="evenodd" fill="black"></path></svg>

After

Width:  |  Height:  |  Size: 894 B

View File

@@ -0,0 +1 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M9.664 3.063 C 9.436 3.146,9.257 3.297,9.131 3.511 L 9.020 3.700 9.020 6.000 L 9.020 8.300 9.131 8.489 C 9.192 8.592,9.301 8.723,9.374 8.778 C 9.667 9.001,9.649 9.000,12.227 9.000 C 14.850 9.000,14.763 8.992,14.922 9.252 C 14.997 9.375,15.000 9.470,15.000 11.760 C 15.000 13.276,15.015 14.194,15.042 14.289 C 15.104 14.512,15.316 14.763,15.539 14.878 L 15.738 14.980 17.936 14.991 C 20.430 15.003,20.395 15.007,20.701 14.701 C 21.023 14.379,21.003 14.790,20.991 8.918 L 20.980 3.700 20.869 3.511 C 20.740 3.291,20.563 3.146,20.322 3.061 C 20.070 2.972,9.906 2.974,9.664 3.063 M3.708 9.058 C 3.444 9.152,3.264 9.300,3.139 9.524 L 3.020 9.740 3.020 15.000 C 3.020 20.122,3.022 20.264,3.097 20.416 C 3.196 20.615,3.385 20.804,3.584 20.903 C 3.736 20.978,3.888 20.980,8.914 20.991 C 12.237 20.997,14.140 20.987,14.234 20.962 C 14.498 20.890,14.731 20.710,14.860 20.477 L 14.980 20.260 14.991 18.089 C 14.998 16.719,14.988 15.863,14.962 15.769 C 14.890 15.502,14.711 15.269,14.477 15.140 L 14.260 15.020 11.771 15.000 L 9.281 14.980 9.151 14.849 L 9.020 14.719 9.000 12.229 L 8.980 9.740 8.860 9.523 C 8.732 9.292,8.502 9.112,8.241 9.040 C 8.157 9.016,7.250 9.001,5.980 9.002 C 4.301 9.003,3.828 9.015,3.708 9.058 " fill="#414146" stroke="none" fill-rule="evenodd"></path></svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@@ -0,0 +1 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M3.000 9.040 L 3.000 15.080 4.100 15.080 L 5.200 15.080 5.200 18.529 C 5.200 21.957,5.200 21.977,5.279 21.899 C 5.322 21.855,6.606 20.308,8.133 18.460 L 10.908 15.100 8.054 15.090 L 5.200 15.079 5.200 10.160 L 5.200 5.240 12.126 5.240 C 18.719 5.240,19.049 5.243,18.992 5.310 C 18.705 5.640,10.960 15.040,10.960 15.057 C 10.960 15.070,13.219 15.080,15.980 15.080 L 21.000 15.080 21.000 9.040 L 21.000 3.000 12.000 3.000 L 3.000 3.000 3.000 9.040 " fill="#414146" stroke="none" fill-rule="evenodd"></path></svg>

After

Width:  |  Height:  |  Size: 614 B

View File

@@ -1,44 +1,50 @@
$aw-icon-apple: "\ea01"; $web-icon-apple: "\ea01";
$aw-icon-arrow-down: "\ea02"; $web-icon-appwrite: "\ea02";
$aw-icon-arrow-ext-link: "\ea03"; $web-icon-arrow-down: "\ea03";
$aw-icon-arrow-left: "\ea04"; $web-icon-arrow-ext-link: "\ea04";
$aw-icon-arrow-right: "\ea05"; $web-icon-arrow-left: "\ea05";
$aw-icon-arrow-up: "\ea06"; $web-icon-arrow-right: "\ea06";
$aw-icon-calendar: "\ea07"; $web-icon-arrow-up: "\ea07";
$aw-icon-check: "\ea08"; $web-icon-calendar: "\ea08";
$aw-icon-chevron-down: "\ea09"; $web-icon-check: "\ea09";
$aw-icon-chevron-left: "\ea0a"; $web-icon-chevron-down: "\ea0a";
$aw-icon-chevron-right: "\ea0b"; $web-icon-chevron-left: "\ea0b";
$aw-icon-chevron-up: "\ea0c"; $web-icon-chevron-right: "\ea0c";
$aw-icon-close: "\ea0d"; $web-icon-chevron-up: "\ea0d";
$aw-icon-command: "\ea0e"; $web-icon-close: "\ea0e";
$aw-icon-copy: "\ea0f"; $web-icon-command: "\ea0f";
$aw-icon-dark: "\ea10"; $web-icon-copy: "\ea10";
$aw-icon-discord: "\ea11"; $web-icon-dark: "\ea11";
$aw-icon-divider-vertical: "\ea12"; $web-icon-discord: "\ea12";
$aw-icon-download: "\ea13"; $web-icon-divider-vertical: "\ea13";
$aw-icon-ext-link: "\ea14"; $web-icon-download: "\ea14";
$aw-icon-github: "\ea15"; $web-icon-ext-link: "\ea15";
$aw-icon-google: "\ea16"; $web-icon-firebase: "\ea16";
$aw-icon-hamburger-menu: "\ea17"; $web-icon-github: "\ea17";
$aw-icon-light: "\ea18"; $web-icon-google: "\ea18";
$aw-icon-linkedin: "\ea19"; $web-icon-hamburger-menu: "\ea19";
$aw-icon-location: "\ea1a"; $web-icon-light: "\ea1a";
$aw-icon-logout-left: "\ea1b"; $web-icon-linkedin: "\ea1b";
$aw-icon-logout-right: "\ea1c"; $web-icon-location: "\ea1c";
$aw-icon-message: "\ea1d"; $web-icon-logout-left: "\ea1d";
$aw-icon-microsoft: "\ea1e"; $web-icon-logout-right: "\ea1e";
$aw-icon-minus: "\ea1f"; $web-icon-mailgun: "\ea1f";
$aw-icon-nuxt: "\ea20"; $web-icon-message: "\ea20";
$aw-icon-platform: "\ea21"; $web-icon-microsoft: "\ea21";
$aw-icon-plus: "\ea22"; $web-icon-minus: "\ea22";
$aw-icon-product-hunt: "\ea23"; $web-icon-nuxt: "\ea23";
$aw-icon-refine: "\ea24"; $web-icon-platform: "\ea24";
$aw-icon-rest: "\ea25"; $web-icon-play: "\ea25";
$aw-icon-search: "\ea26"; $web-icon-plus: "\ea26";
$aw-icon-star: "\ea27"; $web-icon-product-hunt: "\ea27";
$aw-icon-system: "\ea28"; $web-icon-refine: "\ea28";
$aw-icon-twitter: "\ea29"; $web-icon-rest: "\ea29";
$aw-icon-vue: "\ea2a"; $web-icon-search: "\ea2a";
$aw-icon-x: "\ea2b"; $web-icon-sendgrid: "\ea2b";
$aw-icon-youtube: "\ea2c"; $web-icon-star: "\ea2c";
$web-icon-system: "\ea2d";
$web-icon-textmagic: "\ea2e";
$web-icon-twitter: "\ea2f";
$web-icon-vue: "\ea30";
$web-icon-x: "\ea31";
$web-icon-youtube: "\ea32";

View File

@@ -1,63 +0,0 @@
@font-face {
font-family: "aw-icon";
font-display: swap;
src: url('aw-icon.eot'); /* IE9*/
src: url('aw-icon.eot#iefix') format('embedded-opentype'), /* IE6-IE8 */
url("aw-icon.woff2") format("woff2"),
url("aw-icon.woff") format("woff"),
url('aw-icon.ttf') format('truetype'), /* chrome, firefox, opera, Safari, Android, iOS 4.2+*/
url('aw-icon.svg#aw-icon') format('svg'); /* iOS 4.1- */
}
[class^="aw-icon-"], [class*=" aw-icon-"] {
font-family: 'aw-icon' !important;
font-size: 20px;
font-style: normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.aw-icon-apple:before { content: "\ea01"; }
.aw-icon-arrow-down:before { content: "\ea02"; }
.aw-icon-arrow-ext-link:before { content: "\ea03"; }
.aw-icon-arrow-left:before { content: "\ea04"; }
.aw-icon-arrow-right:before { content: "\ea05"; }
.aw-icon-arrow-up:before { content: "\ea06"; }
.aw-icon-calendar:before { content: "\ea07"; }
.aw-icon-check:before { content: "\ea08"; }
.aw-icon-chevron-down:before { content: "\ea09"; }
.aw-icon-chevron-left:before { content: "\ea0a"; }
.aw-icon-chevron-right:before { content: "\ea0b"; }
.aw-icon-chevron-up:before { content: "\ea0c"; }
.aw-icon-close:before { content: "\ea0d"; }
.aw-icon-command:before { content: "\ea0e"; }
.aw-icon-copy:before { content: "\ea0f"; }
.aw-icon-dark:before { content: "\ea10"; }
.aw-icon-discord:before { content: "\ea11"; }
.aw-icon-divider-vertical:before { content: "\ea12"; }
.aw-icon-download:before { content: "\ea13"; }
.aw-icon-ext-link:before { content: "\ea14"; }
.aw-icon-github:before { content: "\ea15"; }
.aw-icon-google:before { content: "\ea16"; }
.aw-icon-hamburger-menu:before { content: "\ea17"; }
.aw-icon-light:before { content: "\ea18"; }
.aw-icon-linkedin:before { content: "\ea19"; }
.aw-icon-location:before { content: "\ea1a"; }
.aw-icon-logout-left:before { content: "\ea1b"; }
.aw-icon-logout-right:before { content: "\ea1c"; }
.aw-icon-message:before { content: "\ea1d"; }
.aw-icon-microsoft:before { content: "\ea1e"; }
.aw-icon-minus:before { content: "\ea1f"; }
.aw-icon-nuxt:before { content: "\ea20"; }
.aw-icon-platform:before { content: "\ea21"; }
.aw-icon-plus:before { content: "\ea22"; }
.aw-icon-product-hunt:before { content: "\ea23"; }
.aw-icon-refine:before { content: "\ea24"; }
.aw-icon-rest:before { content: "\ea25"; }
.aw-icon-search:before { content: "\ea26"; }
.aw-icon-star:before { content: "\ea27"; }
.aw-icon-system:before { content: "\ea28"; }
.aw-icon-twitter:before { content: "\ea29"; }
.aw-icon-vue:before { content: "\ea2a"; }
.aw-icon-x:before { content: "\ea2b"; }
.aw-icon-youtube:before { content: "\ea2c"; }

Binary file not shown.

View File

@@ -1,107 +0,0 @@
@font-face {font-family: "aw-icon";
src: url('aw-icon.eot'); /* IE9*/
src: url('aw-icon.eot#iefix') format('embedded-opentype'), /* IE6-IE8 */
url("aw-icon.woff2") format("woff2"),
url("aw-icon.woff") format("woff"),
url('aw-icon.ttf') format('truetype'), /* chrome, firefox, opera, Safari, Android, iOS 4.2+*/
url('aw-icon.svg#aw-icon') format('svg'); /* iOS 4.1- */
}
[class^="aw-icon-"], [class*=" aw-icon-"] {
font-family: 'aw-icon' !important;
font-size: 20px;
font-display: swap;
font-style: normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.aw-icon-apple:before { content: "\ea01"; }
.aw-icon-arrow-down:before { content: "\ea02"; }
.aw-icon-arrow-ext-link:before { content: "\ea03"; }
.aw-icon-arrow-left:before { content: "\ea04"; }
.aw-icon-arrow-right:before { content: "\ea05"; }
.aw-icon-arrow-up:before { content: "\ea06"; }
.aw-icon-calendar:before { content: "\ea07"; }
.aw-icon-check:before { content: "\ea08"; }
.aw-icon-chevron-down:before { content: "\ea09"; }
.aw-icon-chevron-left:before { content: "\ea0a"; }
.aw-icon-chevron-right:before { content: "\ea0b"; }
.aw-icon-chevron-up:before { content: "\ea0c"; }
.aw-icon-close:before { content: "\ea0d"; }
.aw-icon-command:before { content: "\ea0e"; }
.aw-icon-copy:before { content: "\ea0f"; }
.aw-icon-dark:before { content: "\ea10"; }
.aw-icon-discord:before { content: "\ea11"; }
.aw-icon-divider-vertical:before { content: "\ea12"; }
.aw-icon-download:before { content: "\ea13"; }
.aw-icon-ext-link:before { content: "\ea14"; }
.aw-icon-github:before { content: "\ea15"; }
.aw-icon-google:before { content: "\ea16"; }
.aw-icon-hamburger-menu:before { content: "\ea17"; }
.aw-icon-light:before { content: "\ea18"; }
.aw-icon-linkedin:before { content: "\ea19"; }
.aw-icon-location:before { content: "\ea1a"; }
.aw-icon-logout-left:before { content: "\ea1b"; }
.aw-icon-logout-right:before { content: "\ea1c"; }
.aw-icon-message:before { content: "\ea1d"; }
.aw-icon-microsoft:before { content: "\ea1e"; }
.aw-icon-minus:before { content: "\ea1f"; }
.aw-icon-nuxt:before { content: "\ea20"; }
.aw-icon-platform:before { content: "\ea21"; }
.aw-icon-plus:before { content: "\ea22"; }
.aw-icon-product-hunt:before { content: "\ea23"; }
.aw-icon-refine:before { content: "\ea24"; }
.aw-icon-rest:before { content: "\ea25"; }
.aw-icon-search:before { content: "\ea26"; }
.aw-icon-star:before { content: "\ea27"; }
.aw-icon-system:before { content: "\ea28"; }
.aw-icon-twitter:before { content: "\ea29"; }
.aw-icon-vue:before { content: "\ea2a"; }
.aw-icon-x:before { content: "\ea2b"; }
.aw-icon-youtube:before { content: "\ea2c"; }
$aw-icon-apple: "\ea01";
$aw-icon-arrow-down: "\ea02";
$aw-icon-arrow-ext-link: "\ea03";
$aw-icon-arrow-left: "\ea04";
$aw-icon-arrow-right: "\ea05";
$aw-icon-arrow-up: "\ea06";
$aw-icon-calendar: "\ea07";
$aw-icon-check: "\ea08";
$aw-icon-chevron-down: "\ea09";
$aw-icon-chevron-left: "\ea0a";
$aw-icon-chevron-right: "\ea0b";
$aw-icon-chevron-up: "\ea0c";
$aw-icon-close: "\ea0d";
$aw-icon-command: "\ea0e";
$aw-icon-copy: "\ea0f";
$aw-icon-dark: "\ea10";
$aw-icon-discord: "\ea11";
$aw-icon-divider-vertical: "\ea12";
$aw-icon-download: "\ea13";
$aw-icon-ext-link: "\ea14";
$aw-icon-github: "\ea15";
$aw-icon-google: "\ea16";
$aw-icon-hamburger-menu: "\ea17";
$aw-icon-light: "\ea18";
$aw-icon-linkedin: "\ea19";
$aw-icon-location: "\ea1a";
$aw-icon-logout-left: "\ea1b";
$aw-icon-logout-right: "\ea1c";
$aw-icon-message: "\ea1d";
$aw-icon-microsoft: "\ea1e";
$aw-icon-minus: "\ea1f";
$aw-icon-nuxt: "\ea20";
$aw-icon-platform: "\ea21";
$aw-icon-plus: "\ea22";
$aw-icon-product-hunt: "\ea23";
$aw-icon-refine: "\ea24";
$aw-icon-rest: "\ea25";
$aw-icon-search: "\ea26";
$aw-icon-star: "\ea27";
$aw-icon-system: "\ea28";
$aw-icon-twitter: "\ea29";
$aw-icon-vue: "\ea2a";
$aw-icon-x: "\ea2b";
$aw-icon-youtube: "\ea2c";

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 144 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 61 KiB

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -1,266 +1,302 @@
{ {
"apple": { "apple": {
"encodedCode": "\\ea01", "encodedCode": "\\ea01",
"prefix": "aw-icon", "prefix": "web-icon",
"className": "aw-icon-apple", "className": "web-icon-apple",
"unicode": "&#59905;" "unicode": "&#59905;"
}, },
"arrow-down": { "appwrite": {
"encodedCode": "\\ea02", "encodedCode": "\\ea02",
"prefix": "aw-icon", "prefix": "web-icon",
"className": "aw-icon-arrow-down", "className": "web-icon-appwrite",
"unicode": "&#59906;" "unicode": "&#59906;"
}, },
"arrow-ext-link": { "arrow-down": {
"encodedCode": "\\ea03", "encodedCode": "\\ea03",
"prefix": "aw-icon", "prefix": "web-icon",
"className": "aw-icon-arrow-ext-link", "className": "web-icon-arrow-down",
"unicode": "&#59907;" "unicode": "&#59907;"
}, },
"arrow-left": { "arrow-ext-link": {
"encodedCode": "\\ea04", "encodedCode": "\\ea04",
"prefix": "aw-icon", "prefix": "web-icon",
"className": "aw-icon-arrow-left", "className": "web-icon-arrow-ext-link",
"unicode": "&#59908;" "unicode": "&#59908;"
}, },
"arrow-right": { "arrow-left": {
"encodedCode": "\\ea05", "encodedCode": "\\ea05",
"prefix": "aw-icon", "prefix": "web-icon",
"className": "aw-icon-arrow-right", "className": "web-icon-arrow-left",
"unicode": "&#59909;" "unicode": "&#59909;"
}, },
"arrow-up": { "arrow-right": {
"encodedCode": "\\ea06", "encodedCode": "\\ea06",
"prefix": "aw-icon", "prefix": "web-icon",
"className": "aw-icon-arrow-up", "className": "web-icon-arrow-right",
"unicode": "&#59910;" "unicode": "&#59910;"
}, },
"calendar": { "arrow-up": {
"encodedCode": "\\ea07", "encodedCode": "\\ea07",
"prefix": "aw-icon", "prefix": "web-icon",
"className": "aw-icon-calendar", "className": "web-icon-arrow-up",
"unicode": "&#59911;" "unicode": "&#59911;"
}, },
"check": { "calendar": {
"encodedCode": "\\ea08", "encodedCode": "\\ea08",
"prefix": "aw-icon", "prefix": "web-icon",
"className": "aw-icon-check", "className": "web-icon-calendar",
"unicode": "&#59912;" "unicode": "&#59912;"
}, },
"chevron-down": { "check": {
"encodedCode": "\\ea09", "encodedCode": "\\ea09",
"prefix": "aw-icon", "prefix": "web-icon",
"className": "aw-icon-chevron-down", "className": "web-icon-check",
"unicode": "&#59913;" "unicode": "&#59913;"
}, },
"chevron-left": { "chevron-down": {
"encodedCode": "\\ea0a", "encodedCode": "\\ea0a",
"prefix": "aw-icon", "prefix": "web-icon",
"className": "aw-icon-chevron-left", "className": "web-icon-chevron-down",
"unicode": "&#59914;" "unicode": "&#59914;"
}, },
"chevron-right": { "chevron-left": {
"encodedCode": "\\ea0b", "encodedCode": "\\ea0b",
"prefix": "aw-icon", "prefix": "web-icon",
"className": "aw-icon-chevron-right", "className": "web-icon-chevron-left",
"unicode": "&#59915;" "unicode": "&#59915;"
}, },
"chevron-up": { "chevron-right": {
"encodedCode": "\\ea0c", "encodedCode": "\\ea0c",
"prefix": "aw-icon", "prefix": "web-icon",
"className": "aw-icon-chevron-up", "className": "web-icon-chevron-right",
"unicode": "&#59916;" "unicode": "&#59916;"
}, },
"close": { "chevron-up": {
"encodedCode": "\\ea0d", "encodedCode": "\\ea0d",
"prefix": "aw-icon", "prefix": "web-icon",
"className": "aw-icon-close", "className": "web-icon-chevron-up",
"unicode": "&#59917;" "unicode": "&#59917;"
}, },
"command": { "close": {
"encodedCode": "\\ea0e", "encodedCode": "\\ea0e",
"prefix": "aw-icon", "prefix": "web-icon",
"className": "aw-icon-command", "className": "web-icon-close",
"unicode": "&#59918;" "unicode": "&#59918;"
}, },
"copy": { "command": {
"encodedCode": "\\ea0f", "encodedCode": "\\ea0f",
"prefix": "aw-icon", "prefix": "web-icon",
"className": "aw-icon-copy", "className": "web-icon-command",
"unicode": "&#59919;" "unicode": "&#59919;"
}, },
"dark": { "copy": {
"encodedCode": "\\ea10", "encodedCode": "\\ea10",
"prefix": "aw-icon", "prefix": "web-icon",
"className": "aw-icon-dark", "className": "web-icon-copy",
"unicode": "&#59920;" "unicode": "&#59920;"
}, },
"discord": { "dark": {
"encodedCode": "\\ea11", "encodedCode": "\\ea11",
"prefix": "aw-icon", "prefix": "web-icon",
"className": "aw-icon-discord", "className": "web-icon-dark",
"unicode": "&#59921;" "unicode": "&#59921;"
}, },
"divider-vertical": { "discord": {
"encodedCode": "\\ea12", "encodedCode": "\\ea12",
"prefix": "aw-icon", "prefix": "web-icon",
"className": "aw-icon-divider-vertical", "className": "web-icon-discord",
"unicode": "&#59922;" "unicode": "&#59922;"
}, },
"download": { "divider-vertical": {
"encodedCode": "\\ea13", "encodedCode": "\\ea13",
"prefix": "aw-icon", "prefix": "web-icon",
"className": "aw-icon-download", "className": "web-icon-divider-vertical",
"unicode": "&#59923;" "unicode": "&#59923;"
}, },
"ext-link": { "download": {
"encodedCode": "\\ea14", "encodedCode": "\\ea14",
"prefix": "aw-icon", "prefix": "web-icon",
"className": "aw-icon-ext-link", "className": "web-icon-download",
"unicode": "&#59924;" "unicode": "&#59924;"
}, },
"github": { "ext-link": {
"encodedCode": "\\ea15", "encodedCode": "\\ea15",
"prefix": "aw-icon", "prefix": "web-icon",
"className": "aw-icon-github", "className": "web-icon-ext-link",
"unicode": "&#59925;" "unicode": "&#59925;"
}, },
"google": { "firebase": {
"encodedCode": "\\ea16", "encodedCode": "\\ea16",
"prefix": "aw-icon", "prefix": "web-icon",
"className": "aw-icon-google", "className": "web-icon-firebase",
"unicode": "&#59926;" "unicode": "&#59926;"
}, },
"hamburger-menu": { "github": {
"encodedCode": "\\ea17", "encodedCode": "\\ea17",
"prefix": "aw-icon", "prefix": "web-icon",
"className": "aw-icon-hamburger-menu", "className": "web-icon-github",
"unicode": "&#59927;" "unicode": "&#59927;"
}, },
"light": { "google": {
"encodedCode": "\\ea18", "encodedCode": "\\ea18",
"prefix": "aw-icon", "prefix": "web-icon",
"className": "aw-icon-light", "className": "web-icon-google",
"unicode": "&#59928;" "unicode": "&#59928;"
}, },
"linkedin": { "hamburger-menu": {
"encodedCode": "\\ea19", "encodedCode": "\\ea19",
"prefix": "aw-icon", "prefix": "web-icon",
"className": "aw-icon-linkedin", "className": "web-icon-hamburger-menu",
"unicode": "&#59929;" "unicode": "&#59929;"
}, },
"location": { "light": {
"encodedCode": "\\ea1a", "encodedCode": "\\ea1a",
"prefix": "aw-icon", "prefix": "web-icon",
"className": "aw-icon-location", "className": "web-icon-light",
"unicode": "&#59930;" "unicode": "&#59930;"
}, },
"logout-left": { "linkedin": {
"encodedCode": "\\ea1b", "encodedCode": "\\ea1b",
"prefix": "aw-icon", "prefix": "web-icon",
"className": "aw-icon-logout-left", "className": "web-icon-linkedin",
"unicode": "&#59931;" "unicode": "&#59931;"
}, },
"logout-right": { "location": {
"encodedCode": "\\ea1c", "encodedCode": "\\ea1c",
"prefix": "aw-icon", "prefix": "web-icon",
"className": "aw-icon-logout-right", "className": "web-icon-location",
"unicode": "&#59932;" "unicode": "&#59932;"
}, },
"message": { "logout-left": {
"encodedCode": "\\ea1d", "encodedCode": "\\ea1d",
"prefix": "aw-icon", "prefix": "web-icon",
"className": "aw-icon-message", "className": "web-icon-logout-left",
"unicode": "&#59933;" "unicode": "&#59933;"
}, },
"microsoft": { "logout-right": {
"encodedCode": "\\ea1e", "encodedCode": "\\ea1e",
"prefix": "aw-icon", "prefix": "web-icon",
"className": "aw-icon-microsoft", "className": "web-icon-logout-right",
"unicode": "&#59934;" "unicode": "&#59934;"
}, },
"minus": { "mailgun": {
"encodedCode": "\\ea1f", "encodedCode": "\\ea1f",
"prefix": "aw-icon", "prefix": "web-icon",
"className": "aw-icon-minus", "className": "web-icon-mailgun",
"unicode": "&#59935;" "unicode": "&#59935;"
}, },
"nuxt": { "message": {
"encodedCode": "\\ea20", "encodedCode": "\\ea20",
"prefix": "aw-icon", "prefix": "web-icon",
"className": "aw-icon-nuxt", "className": "web-icon-message",
"unicode": "&#59936;" "unicode": "&#59936;"
}, },
"platform": { "microsoft": {
"encodedCode": "\\ea21", "encodedCode": "\\ea21",
"prefix": "aw-icon", "prefix": "web-icon",
"className": "aw-icon-platform", "className": "web-icon-microsoft",
"unicode": "&#59937;" "unicode": "&#59937;"
}, },
"plus": { "minus": {
"encodedCode": "\\ea22", "encodedCode": "\\ea22",
"prefix": "aw-icon", "prefix": "web-icon",
"className": "aw-icon-plus", "className": "web-icon-minus",
"unicode": "&#59938;" "unicode": "&#59938;"
}, },
"product-hunt": { "nuxt": {
"encodedCode": "\\ea23", "encodedCode": "\\ea23",
"prefix": "aw-icon", "prefix": "web-icon",
"className": "aw-icon-product-hunt", "className": "web-icon-nuxt",
"unicode": "&#59939;" "unicode": "&#59939;"
}, },
"refine": { "platform": {
"encodedCode": "\\ea24", "encodedCode": "\\ea24",
"prefix": "aw-icon", "prefix": "web-icon",
"className": "aw-icon-refine", "className": "web-icon-platform",
"unicode": "&#59940;" "unicode": "&#59940;"
}, },
"rest": { "play": {
"encodedCode": "\\ea25", "encodedCode": "\\ea25",
"prefix": "aw-icon", "prefix": "web-icon",
"className": "aw-icon-rest", "className": "web-icon-play",
"unicode": "&#59941;" "unicode": "&#59941;"
}, },
"search": { "plus": {
"encodedCode": "\\ea26", "encodedCode": "\\ea26",
"prefix": "aw-icon", "prefix": "web-icon",
"className": "aw-icon-search", "className": "web-icon-plus",
"unicode": "&#59942;" "unicode": "&#59942;"
}, },
"star": { "product-hunt": {
"encodedCode": "\\ea27", "encodedCode": "\\ea27",
"prefix": "aw-icon", "prefix": "web-icon",
"className": "aw-icon-star", "className": "web-icon-product-hunt",
"unicode": "&#59943;" "unicode": "&#59943;"
}, },
"system": { "refine": {
"encodedCode": "\\ea28", "encodedCode": "\\ea28",
"prefix": "aw-icon", "prefix": "web-icon",
"className": "aw-icon-system", "className": "web-icon-refine",
"unicode": "&#59944;" "unicode": "&#59944;"
}, },
"twitter": { "rest": {
"encodedCode": "\\ea29", "encodedCode": "\\ea29",
"prefix": "aw-icon", "prefix": "web-icon",
"className": "aw-icon-twitter", "className": "web-icon-rest",
"unicode": "&#59945;" "unicode": "&#59945;"
}, },
"vue": { "search": {
"encodedCode": "\\ea2a", "encodedCode": "\\ea2a",
"prefix": "aw-icon", "prefix": "web-icon",
"className": "aw-icon-vue", "className": "web-icon-search",
"unicode": "&#59946;" "unicode": "&#59946;"
}, },
"x": { "sendgrid": {
"encodedCode": "\\ea2b", "encodedCode": "\\ea2b",
"prefix": "aw-icon", "prefix": "web-icon",
"className": "aw-icon-x", "className": "web-icon-sendgrid",
"unicode": "&#59947;" "unicode": "&#59947;"
}, },
"youtube": { "star": {
"encodedCode": "\\ea2c", "encodedCode": "\\ea2c",
"prefix": "aw-icon", "prefix": "web-icon",
"className": "aw-icon-youtube", "className": "web-icon-star",
"unicode": "&#59948;" "unicode": "&#59948;"
},
"system": {
"encodedCode": "\\ea2d",
"prefix": "web-icon",
"className": "web-icon-system",
"unicode": "&#59949;"
},
"textmagic": {
"encodedCode": "\\ea2e",
"prefix": "web-icon",
"className": "web-icon-textmagic",
"unicode": "&#59950;"
},
"twitter": {
"encodedCode": "\\ea2f",
"prefix": "web-icon",
"className": "web-icon-twitter",
"unicode": "&#59951;"
},
"vue": {
"encodedCode": "\\ea30",
"prefix": "web-icon",
"className": "web-icon-vue",
"unicode": "&#59952;"
},
"x": {
"encodedCode": "\\ea31",
"prefix": "web-icon",
"className": "web-icon-x",
"unicode": "&#59953;"
},
"youtube": {
"encodedCode": "\\ea32",
"prefix": "web-icon",
"className": "web-icon-youtube",
"unicode": "&#59954;"
} }
} }

View File

@@ -0,0 +1,69 @@
@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- */
}
[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"; }
.web-icon-appwrite:before { content: "\ea02"; }
.web-icon-arrow-down:before { content: "\ea03"; }
.web-icon-arrow-ext-link:before { content: "\ea04"; }
.web-icon-arrow-left:before { content: "\ea05"; }
.web-icon-arrow-right:before { content: "\ea06"; }
.web-icon-arrow-up:before { content: "\ea07"; }
.web-icon-calendar:before { content: "\ea08"; }
.web-icon-check:before { content: "\ea09"; }
.web-icon-chevron-down:before { content: "\ea0a"; }
.web-icon-chevron-left:before { content: "\ea0b"; }
.web-icon-chevron-right:before { content: "\ea0c"; }
.web-icon-chevron-up:before { content: "\ea0d"; }
.web-icon-close:before { content: "\ea0e"; }
.web-icon-command:before { content: "\ea0f"; }
.web-icon-copy:before { content: "\ea10"; }
.web-icon-dark:before { content: "\ea11"; }
.web-icon-discord:before { content: "\ea12"; }
.web-icon-divider-vertical:before { content: "\ea13"; }
.web-icon-download:before { content: "\ea14"; }
.web-icon-ext-link:before { content: "\ea15"; }
.web-icon-firebase:before { content: "\ea16"; }
.web-icon-github:before { content: "\ea17"; }
.web-icon-google:before { content: "\ea18"; }
.web-icon-hamburger-menu:before { content: "\ea19"; }
.web-icon-light:before { content: "\ea1a"; }
.web-icon-linkedin:before { content: "\ea1b"; }
.web-icon-location:before { content: "\ea1c"; }
.web-icon-logout-left:before { content: "\ea1d"; }
.web-icon-logout-right:before { content: "\ea1e"; }
.web-icon-mailgun:before { content: "\ea1f"; }
.web-icon-message:before { content: "\ea20"; }
.web-icon-microsoft:before { content: "\ea21"; }
.web-icon-minus:before { content: "\ea22"; }
.web-icon-nuxt:before { content: "\ea23"; }
.web-icon-platform:before { content: "\ea24"; }
.web-icon-play:before { content: "\ea25"; }
.web-icon-plus:before { content: "\ea26"; }
.web-icon-product-hunt:before { content: "\ea27"; }
.web-icon-refine:before { content: "\ea28"; }
.web-icon-rest:before { content: "\ea29"; }
.web-icon-search:before { content: "\ea2a"; }
.web-icon-sendgrid:before { content: "\ea2b"; }
.web-icon-star:before { content: "\ea2c"; }
.web-icon-system:before { content: "\ea2d"; }
.web-icon-textmagic:before { content: "\ea2e"; }
.web-icon-twitter:before { content: "\ea2f"; }
.web-icon-vue:before { content: "\ea30"; }
.web-icon-x:before { content: "\ea31"; }
.web-icon-youtube:before { content: "\ea32"; }

Binary file not shown.

View File

@@ -0,0 +1,119 @@
@font-face {font-family: "web-icon";
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-display: swap;
font-style: normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.web-icon-apple:before { content: "\ea01"; }
.web-icon-appwrite:before { content: "\ea02"; }
.web-icon-arrow-down:before { content: "\ea03"; }
.web-icon-arrow-ext-link:before { content: "\ea04"; }
.web-icon-arrow-left:before { content: "\ea05"; }
.web-icon-arrow-right:before { content: "\ea06"; }
.web-icon-arrow-up:before { content: "\ea07"; }
.web-icon-calendar:before { content: "\ea08"; }
.web-icon-check:before { content: "\ea09"; }
.web-icon-chevron-down:before { content: "\ea0a"; }
.web-icon-chevron-left:before { content: "\ea0b"; }
.web-icon-chevron-right:before { content: "\ea0c"; }
.web-icon-chevron-up:before { content: "\ea0d"; }
.web-icon-close:before { content: "\ea0e"; }
.web-icon-command:before { content: "\ea0f"; }
.web-icon-copy:before { content: "\ea10"; }
.web-icon-dark:before { content: "\ea11"; }
.web-icon-discord:before { content: "\ea12"; }
.web-icon-divider-vertical:before { content: "\ea13"; }
.web-icon-download:before { content: "\ea14"; }
.web-icon-ext-link:before { content: "\ea15"; }
.web-icon-firebase:before { content: "\ea16"; }
.web-icon-github:before { content: "\ea17"; }
.web-icon-google:before { content: "\ea18"; }
.web-icon-hamburger-menu:before { content: "\ea19"; }
.web-icon-light:before { content: "\ea1a"; }
.web-icon-linkedin:before { content: "\ea1b"; }
.web-icon-location:before { content: "\ea1c"; }
.web-icon-logout-left:before { content: "\ea1d"; }
.web-icon-logout-right:before { content: "\ea1e"; }
.web-icon-mailgun:before { content: "\ea1f"; }
.web-icon-message:before { content: "\ea20"; }
.web-icon-microsoft:before { content: "\ea21"; }
.web-icon-minus:before { content: "\ea22"; }
.web-icon-nuxt:before { content: "\ea23"; }
.web-icon-platform:before { content: "\ea24"; }
.web-icon-play:before { content: "\ea25"; }
.web-icon-plus:before { content: "\ea26"; }
.web-icon-product-hunt:before { content: "\ea27"; }
.web-icon-refine:before { content: "\ea28"; }
.web-icon-rest:before { content: "\ea29"; }
.web-icon-search:before { content: "\ea2a"; }
.web-icon-sendgrid:before { content: "\ea2b"; }
.web-icon-star:before { content: "\ea2c"; }
.web-icon-system:before { content: "\ea2d"; }
.web-icon-textmagic:before { content: "\ea2e"; }
.web-icon-twitter:before { content: "\ea2f"; }
.web-icon-vue:before { content: "\ea30"; }
.web-icon-x:before { content: "\ea31"; }
.web-icon-youtube:before { content: "\ea32"; }
$web-icon-apple: "\ea01";
$web-icon-appwrite: "\ea02";
$web-icon-arrow-down: "\ea03";
$web-icon-arrow-ext-link: "\ea04";
$web-icon-arrow-left: "\ea05";
$web-icon-arrow-right: "\ea06";
$web-icon-arrow-up: "\ea07";
$web-icon-calendar: "\ea08";
$web-icon-check: "\ea09";
$web-icon-chevron-down: "\ea0a";
$web-icon-chevron-left: "\ea0b";
$web-icon-chevron-right: "\ea0c";
$web-icon-chevron-up: "\ea0d";
$web-icon-close: "\ea0e";
$web-icon-command: "\ea0f";
$web-icon-copy: "\ea10";
$web-icon-dark: "\ea11";
$web-icon-discord: "\ea12";
$web-icon-divider-vertical: "\ea13";
$web-icon-download: "\ea14";
$web-icon-ext-link: "\ea15";
$web-icon-firebase: "\ea16";
$web-icon-github: "\ea17";
$web-icon-google: "\ea18";
$web-icon-hamburger-menu: "\ea19";
$web-icon-light: "\ea1a";
$web-icon-linkedin: "\ea1b";
$web-icon-location: "\ea1c";
$web-icon-logout-left: "\ea1d";
$web-icon-logout-right: "\ea1e";
$web-icon-mailgun: "\ea1f";
$web-icon-message: "\ea20";
$web-icon-microsoft: "\ea21";
$web-icon-minus: "\ea22";
$web-icon-nuxt: "\ea23";
$web-icon-platform: "\ea24";
$web-icon-play: "\ea25";
$web-icon-plus: "\ea26";
$web-icon-product-hunt: "\ea27";
$web-icon-refine: "\ea28";
$web-icon-rest: "\ea29";
$web-icon-search: "\ea2a";
$web-icon-sendgrid: "\ea2b";
$web-icon-star: "\ea2c";
$web-icon-system: "\ea2d";
$web-icon-textmagic: "\ea2e";
$web-icon-twitter: "\ea2f";
$web-icon-vue: "\ea30";
$web-icon-x: "\ea31";
$web-icon-youtube: "\ea32";

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 162 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -17,10 +17,10 @@ export const optimizeSVG = async () => {
export const generateIcons = async () => { export const generateIcons = async () => {
await svgtofont({ await svgtofont({
classNamePrefix: 'aw-icon', classNamePrefix: 'web-icon',
src: optimized, src: optimized,
dist: dist, dist: dist,
fontName: 'aw-icon', fontName: 'web-icon',
styleTemplates: resolve(process.cwd(), 'src/icons/templates'), styleTemplates: resolve(process.cwd(), 'src/icons/templates'),
css: { css: {
fontSize: '20px' fontSize: '20px'

View File

@@ -0,0 +1,6 @@
<svg width="18" height="17" viewBox="0 0 18 17" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="appwrite">
<path id="Vector" d="M18 12.2017V16.2689H7.91783C4.98048 16.2689 2.41575 14.6331 1.04357 12.2017C0.844087 11.8482 0.669498 11.4773 0.523046 11.0924C0.235551 10.3381 0.0548296 9.52877 0 8.68426V7.58463C0.0119038 7.39643 0.0306613 7.20971 0.0551903 7.02521C0.105331 6.64658 0.181082 6.2761 0.280641 5.91596C1.22248 2.50171 4.28501 0 7.91783 0C11.5506 0 14.6128 2.50171 15.5547 5.91596H11.2437C10.5359 4.80302 9.31093 4.06723 7.91783 4.06723C6.52472 4.06723 5.29971 4.80302 4.59198 5.91596C4.37627 6.25428 4.20889 6.62736 4.09923 7.02521C4.00184 7.37794 3.9499 7.74991 3.9499 8.13445C3.9499 9.30026 4.42821 10.3511 5.19511 11.0924C5.90573 11.7805 6.8638 12.2017 7.91783 12.2017H18Z" fill="#414146"/>
<path id="Vector_2" d="M18.0001 7.02527V11.0925H10.6406C11.4075 10.3512 11.8858 9.30033 11.8858 8.13451C11.8858 7.74997 11.8339 7.37801 11.7365 7.02527H18.0001Z" fill="#414146"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1002 B

View File

@@ -0,0 +1,3 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M4.59955 15.3633L6.75636 1.42672C6.83091 0.951425 7.46318 0.839133 7.68636 1.26401L10.0045 5.63882L4.59955 15.3633ZM20 18.6001L17.8755 5.91382C17.86 5.82314 17.8203 5.73844 17.7606 5.66889C17.7009 5.59935 17.6234 5.54761 17.5366 5.51928C17.4498 5.49096 17.3569 5.48712 17.2681 5.50819C17.1793 5.52926 17.0979 5.57443 17.0327 5.63882L4 18.6001L11.2436 22.8126C11.4659 22.9356 11.7153 23 11.9689 23C12.2224 23 12.4718 22.9356 12.6941 22.8126L20 18.6001ZM14.1073 7.55099L12.4464 4.36373C12.4051 4.28185 12.3421 4.21309 12.2644 4.16507C12.1868 4.11704 12.0975 4.09162 12.0064 4.09162C11.9153 4.09162 11.8259 4.11704 11.7483 4.16507C11.6706 4.21309 11.6077 4.28185 11.5664 4.36373L4.265 17.4882L14.1073 7.55099Z" fill="#414146"/>
</svg>

After

Width:  |  Height:  |  Size: 837 B

View File

@@ -0,0 +1,3 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M11.9999 10.4423C12.8603 10.4423 13.5578 11.1396 13.5578 11.9998C13.5578 12.8602 12.8603 13.5576 11.9999 13.5576C11.1397 13.5576 10.4422 12.86 10.4422 11.9998C10.4422 11.1396 11.1397 10.4423 11.9999 10.4423ZM6.69232 11.9998C6.69232 9.06851 9.0686 6.69233 11.9999 6.69233C14.9315 6.69233 17.3076 9.06851 17.3076 11.9998C17.3076 12.1938 17.2973 12.3852 17.277 12.5735C17.2367 13.091 17.6164 13.4859 18.1305 13.4859C19.003 13.4859 19.0959 12.3609 19.0959 11.9998C19.0959 8.08063 15.919 4.90382 11.9999 4.90382C8.08071 4.90382 4.90385 8.0807 4.90385 11.9998C4.90385 15.9187 8.08071 19.0956 11.9998 19.0956C14.0812 19.0956 15.9532 18.2001 17.2514 16.7729L18.7101 17.9978C17.0624 19.8398 14.6665 21 11.9999 21C7.02933 21 3 16.9703 3 11.9998C3 7.02927 7.02933 3 11.9999 3C16.9707 3 21 7.02927 21 11.9999C21 13.9978 20.0487 15.6202 18.1379 15.6202C17.2969 15.6202 16.7857 15.2349 16.5066 14.8049C15.5693 16.3073 13.9017 17.3077 11.9999 17.3077C9.06853 17.3077 6.69232 14.931 6.69232 11.9998ZM11.9999 8.59601C10.1201 8.59601 8.59603 10.1199 8.59603 11.9998C8.59603 13.8797 10.1201 15.4037 11.9999 15.4037C13.8797 15.4037 15.4039 13.8797 15.4039 11.9998C15.4039 10.1199 13.8797 8.59601 11.9999 8.59601Z" fill="#414146"/>
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

3
src/icons/svg/play.svg Normal file
View File

@@ -0,0 +1,3 @@
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M16 10L5.75003 4.35001L5.75003 15.5L16 10Z" stroke="#19191C" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 241 B

View File

@@ -0,0 +1,4 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M20.9067 3.57748C20.7474 3.23637 20.4013 3 20.0001 3L16 3C15.9965 3 15.9931 3.00002 15.9896 3.00005H10C9.44772 3.00005 9 3.44777 9 4.00005V8.00009C9 8.55237 9.44772 9.00009 10 9.00009H14.5C14.7762 9.00009 15 9.22395 15 9.50009V14.0001C15 14.5524 15.4477 15.0001 16 15.0001L20.0001 15.0001C20.5523 15.0001 21.0001 14.5524 21.0001 14.0001L21.0001 8.00607C21.0001 8.00408 21.0001 8.00208 21.0001 8.00009V4.00005C21.0001 3.931 20.9931 3.86358 20.9797 3.79847C20.9639 3.72118 20.9392 3.64715 20.9067 3.57748Z" fill="#414146"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M3.09333 20.4225C3.25257 20.7636 3.59866 21 3.99995 21L7.99998 21C8.00345 21 8.00692 21 8.01038 20.9999H14C14.5523 20.9999 15 20.5522 15 19.9999V15.9999C15 15.4476 14.5523 14.9999 14 14.9999H9.49998C9.22384 14.9999 8.99998 14.7761 8.99998 14.4999V9.99993C8.99998 9.44765 8.55227 8.99993 7.99998 8.99993L3.99995 8.99993C3.44766 8.99993 2.99995 9.44765 2.99995 9.99993L2.99995 15.9939C2.99994 15.9959 2.99993 15.9979 2.99993 15.9999V19.9999C2.99993 20.069 3.00694 20.1364 3.02026 20.2015C3.03608 20.2788 3.06081 20.3529 3.09333 20.4225Z" fill="#414146"/>
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@@ -0,0 +1,3 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M21 3H3V15.0654H5.20701V22L10.9358 15.0654H21V3ZM10.9358 15.0654L19.0467 5.2473H5.20701V15.0654H10.9358Z" fill="#414146"/>
</svg>

After

Width:  |  Height:  |  Size: 275 B

View File

@@ -14,16 +14,16 @@
export { className as class }; export { className as class };
</script> </script>
<ul class="aw-secondary-tabs {className}" use:melt={$list} {style}> <ul class="web-secondary-tabs {className}" use:melt={$list} {style}>
{#each tabs as tab} {#each tabs as tab}
<li class="aw-secondary-tabs-item" class:u-stretch={stretch}> <li class="web-secondary-tabs-item" class:u-stretch={stretch}>
<button <button
class="aw-secondary-tabs-button u-width-full-line" class="web-secondary-tabs-button u-width-full-line"
class:is-selected={$value === tab} class:is-selected={$value === tab}
use:melt={$trigger(tab)} use:melt={$trigger(tab)}
> >
<slot {tab}> <slot {tab}>
<span class="aw-main-body-500">{tab}</span> <span class="web-main-body-500">{tab}</span>
</slot> </slot>
</button> </button>
</li> </li>

View File

@@ -18,14 +18,16 @@
</div> </div>
<style lang="scss"> <style lang="scss">
@use '$scss/abstract/mixins/border-gradient' as gradients;
.code-console { .code-console {
@include border-gradient; @include gradients.border-gradient;
--p-radius: 16px; --p-radius: 16px;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
background-color: hsl(var(--aw-color-card)); background-color: hsl(var(--web-color-card));
border-radius: var(--p-radius); border-radius: var(--p-radius);
--m-border-radius: var(--p-radius); --m-border-radius: var(--p-radius);
--m-border-gradient-before: linear-gradient( --m-border-gradient-before: linear-gradient(

View File

@@ -2,6 +2,7 @@
import { toScale, type Scale } from '$lib/utils/toScale'; import { toScale, type Scale } from '$lib/utils/toScale';
import { spring, type AnimationListOptions, type SpringOptions } from 'motion'; import { spring, type AnimationListOptions, type SpringOptions } from 'motion';
import { animation, createScrollHandler, scroll, type Animation } from '.'; import { animation, createScrollHandler, scroll, type Animation } from '.';
import { GITHUB_STARS } from '$lib/constants';
const springOptions: SpringOptions = { stiffness: 58.78, mass: 1, damping: 17.14 }; const springOptions: SpringOptions = { stiffness: 58.78, mass: 1, damping: 17.14 };
const animationOptions: AnimationListOptions = { const animationOptions: AnimationListOptions = {
@@ -159,11 +160,11 @@
<div <div
id="open-source" id="open-source"
use:scroll use:scroll
on:aw-scroll={({ detail }) => { on:web-scroll={({ detail }) => {
const { percentage } = detail; const { percentage } = detail;
scrollHandler(percentage); scrollHandler(percentage);
}} }}
on:aw-resize={({ detail }) => { on:web-resize={({ detail }) => {
scrollHandler.reset(); scrollHandler.reset();
const { percentage } = detail; const { percentage } = detail;
@@ -171,84 +172,84 @@
}} }}
> >
<div class="sticky-wrapper"> <div class="sticky-wrapper">
<h3 class="aw-display aw-u-color-text-primary">Powered by Open Source</h3> <h3 class="web-display web-u-color-text-primary">Powered by Open Source</h3>
<div class="cards-wrapper"> <div class="cards-wrapper">
<a <a
href="/discord" href="/discord"
target="_blank" target="_blank"
rel="noopener noreferrer" rel="noopener noreferrer"
class="aw-card is-white aw-u-min-block-size-320 u-flex-vertical oss-card" class="web-card is-white web-u-min-block-size-320 u-flex-vertical oss-card"
id="oss-discord" id="oss-discord"
> >
<div class="u-flex-vertical u-main-space-between u-gap-32"> <div class="u-flex-vertical u-main-space-between u-gap-32">
<span <span
class="aw-icon-discord aw-u-font-size-40" class="web-icon-discord web-u-font-size-40"
aria-hidden="true" aria-hidden="true"
aria-label="Discord" aria-label="Discord"
/> />
</div> </div>
<div class="aw-title u-margin-block-start-auto">17k+ Discord Members</div> <div class="web-title u-margin-block-start-auto">17k+ Discord Members</div>
</a> </a>
<a <a
class="aw-card is-white aw-u-min-block-size-320 u-flex-vertical oss-card" class="web-card is-white web-u-min-block-size-320 u-flex-vertical oss-card"
id="oss-github" id="oss-github"
href="https://github.com/appwrite/appwrite" href="https://github.com/appwrite/appwrite"
> >
<div class="u-flex-vertical u-main-space-between u-gap-32"> <div class="u-flex-vertical u-main-space-between u-gap-32">
<span <span
class="aw-icon-github aw-u-font-size-40" class="web-icon-github web-u-font-size-40"
aria-hidden="true" aria-hidden="true"
aria-label="GitHub" aria-label="GitHub"
/> />
</div> </div>
<div class="aw-title u-margin-block-start-auto">38k+ GitHub Stars</div> <div class="web-title u-margin-block-start-auto">{GITHUB_STARS}+ GitHub Stars</div>
</a> </a>
<a <a
href="https://twitter.com/appwrite" href="https://twitter.com/appwrite"
class="aw-card is-white aw-u-min-block-size-320 u-flex-vertical oss-card" class="web-card is-white web-u-min-block-size-320 u-flex-vertical oss-card"
id="oss-twitter" id="oss-twitter"
> >
<div class="u-flex-vertical u-main-space-between u-gap-32"> <div class="u-flex-vertical u-main-space-between u-gap-32">
<span <span
class="aw-icon-x aw-u-font-size-40" class="web-icon-x web-u-font-size-40"
aria-hidden="true" aria-hidden="true"
aria-label="Twitter" aria-label="Twitter"
/> />
</div> </div>
<div class="aw-title u-margin-block-start-auto">128k+ Twitter Followers</div> <div class="web-title u-margin-block-start-auto">128k+ Twitter Followers</div>
</a> </a>
<a <a
href="https://www.youtube.com/@Appwrite" href="https://www.youtube.com/@Appwrite"
class="aw-card is-white aw-u-min-block-size-320 u-flex-vertical oss-card" class="web-card is-white web-u-min-block-size-320 u-flex-vertical oss-card"
id="oss-youtube" id="oss-youtube"
> >
<div class="u-flex-vertical u-main-space-between u-gap-32"> <div class="u-flex-vertical u-main-space-between u-gap-32">
<span <span
class="aw-icon-youtube aw-u-font-size-40" class="web-icon-youtube web-u-font-size-40"
aria-hidden="true" aria-hidden="true"
aria-label="YouTube" aria-label="YouTube"
/> />
</div> </div>
<div class="aw-title u-margin-block-start-auto">4k+ Youtube Subscribers</div> <div class="web-title u-margin-block-start-auto">4k+ Youtube Subscribers</div>
</a> </a>
<a <a
class="aw-card is-white aw-u-min-block-size-320 u-flex-vertical oss-card" class="web-card is-white web-u-min-block-size-320 u-flex-vertical oss-card"
id="oss-commits" id="oss-commits"
href="https://github.com/appwrite/appwrite" href="https://github.com/appwrite/appwrite"
> >
<div class="u-flex-vertical u-main-space-between u-gap-32"> <div class="u-flex-vertical u-main-space-between u-gap-32">
<span <span
class="aw-icon-github aw-u-font-size-40" class="web-icon-github web-u-font-size-40"
aria-hidden="true" aria-hidden="true"
aria-label="GitHub" aria-label="GitHub"
/> />
</div> </div>
<div class="aw-title u-margin-block-start-auto">18k+ Code Commits</div> <div class="web-title u-margin-block-start-auto">18k+ Code Commits</div>
</a> </a>
</div> </div>
</div> </div>
@@ -285,8 +286,8 @@
&::after { &::after {
background: linear-gradient( background: linear-gradient(
to top, to top,
hsl(var(--aw-color-background)) 0%, hsl(var(--web-color-background)) 0%,
hsl(var(--aw-color-background) / 0) 5% hsl(var(--web-color-background) / 0) 5%
); );
position: absolute; position: absolute;
inset: 0; inset: 0;

View File

@@ -12,8 +12,10 @@
</div> </div>
<style lang="scss"> <style lang="scss">
@use '$scss/abstract/mixins/border-gradient' as gradients;
.anim-box { .anim-box {
@include border-gradient; @include gradients.border-gradient;
--m-border-radius: 1rem; --m-border-radius: 1rem;
--m-border-gradient-before: linear-gradient( --m-border-gradient-before: linear-gradient(
180deg, 180deg,
@@ -21,7 +23,7 @@
rgba(255, 255, 255, 0) 125.11% rgba(255, 255, 255, 0) 125.11%
); );
border-radius: var(--m-border-radius); border-radius: var(--m-border-radius);
background: hsl(var(--aw-color-card)); background: hsl(var(--web-color-card));
backdrop-filter: blur(8px); backdrop-filter: blur(8px);
padding: 0.5rem; padding: 0.5rem;

View File

@@ -35,7 +35,7 @@
title: 'Auth', title: 'Auth',
subtitle: 'Secure login for all users', subtitle: 'Secure login for all users',
description: description:
'Authenticate users securely with multiple login methods like Email/Password, SMS, OAuth, Annoymous, Magic URLs and more.', 'Authenticate users securely with multiple login methods like Email/Password, SMS, OAuth, Anonymous, Magic URLs and more.',
features: [ features: [
'30+ login methods', '30+ login methods',
'Support for teams, roles and user labels', 'Support for teams, roles and user labels',
@@ -151,8 +151,8 @@
return scrollInfo.percentage >= min && scrollInfo.percentage < max; return scrollInfo.percentage >= min && scrollInfo.percentage < max;
}); });
const product = products[activeIdx] as Product | undefined; const product = products[activeIdx] as Product;
const scale = productsScales[activeIdx] as Scale | undefined; const scale = productsScales[activeIdx] as Scale;
const percent = scale ? toScale(scrollInfo.percentage, scale, [0, 1]) : 0; const percent = scale ? toScale(scrollInfo.percentage, scale, [0, 1]) : 0;
return { return {
@@ -188,26 +188,12 @@
} }
}); });
})(); })();
function navigateToProduct(product: Product) {
const i = products.indexOf(product);
const scale = productsScales[i][0];
const productsWrapper = document.getElementById('products');
if (!productsWrapper) return;
const rect = productsWrapper.getBoundingClientRect();
window.scrollTo({
top: rect.top + window.scrollY + rect.height * scale,
behavior: 'smooth'
});
}
</script> </script>
<div <div
id="products" id="products"
use:scroll use:scroll
on:aw-scroll={({ detail }) => { on:web-scroll={({ detail }) => {
scrollInfo = detail; scrollInfo = detail;
}} }}
> >
@@ -222,18 +208,18 @@
in:fly={{ duration: 250, delay: 250, y: -300 }} in:fly={{ duration: 250, delay: 250, y: -300 }}
> >
{#if scrollInfo.percentage > -0.1} {#if scrollInfo.percentage > -0.1}
<span class="aw-badges aw-eyebrow" transition:slide={{ axis: 'x' }} <span class="web-badges web-eyebrow" transition:slide={{ axis: 'x' }}
>Products_</span >Products_</span
> >
<h2 <h2
class="aw-display aw-u-color-text-primary" class="web-display web-u-color-text-primary"
transition:fly={{ y: 16, delay: 250 }} transition:fly={{ y: 16, delay: 250 }}
> >
Your backend, minus the hassle Your backend, minus the hassle
</h2> </h2>
<p <p
class="aw-description aw-u-max-width-700 u-margin-inline-auto" class="web-description web-u-max-width-700 u-margin-inline-auto"
transition:fly={{ transition:fly={{
y: 16, y: 16,
delay: 400 delay: 400
@@ -262,23 +248,18 @@
{#if copy} {#if copy}
<li data-active={isActive ? '' : undefined}> <li data-active={isActive ? '' : undefined}>
<button on:click={() => navigateToProduct(product)}> <h3>
<h3> <img
<img src={isActive ? copy.icon.active : copy.icon.inactive}
src={isActive alt=""
? copy.icon.active width="32"
: copy.icon.inactive} height="32"
alt="" />
width="32" <span class="web-label">{copy.title}</span>
height="32" </h3>
/>
<span class="aw-label">{copy.title}</span>
</h3>
</button>
{#if isActive} {#if isActive}
<div transition:slide> <div transition:slide>
<h4 class="aw-title">{copy.subtitle}</h4> <h4 class="web-title">{copy.subtitle}</h4>
<p> <p>
{copy.description} {copy.description}
</p> </p>
@@ -355,7 +336,7 @@
<Storage.Phone /> <Storage.Phone />
{:else if active.product === 'functions'} {:else if active.product === 'functions'}
<Functions.Phone /> <Functions.Phone />
{:else if !['auth', 'databases', 'storage', 'functions'].includes(anyify(active.product))} {:else if !['auth', 'databases', 'storage', 'functions'].includes(active.product)}
<Realtime.Phone /> <Realtime.Phone />
{/if} {/if}
</div> </div>
@@ -370,6 +351,8 @@
</div> </div>
<style lang="scss"> <style lang="scss">
@use '$scss/abstract/mixins/border-gradient' as gradients;
#products { #products {
min-height: 500vh; min-height: 500vh;
height: 5000px; height: 5000px;
@@ -475,7 +458,7 @@
&[data-active] { &[data-active] {
h3 { h3 {
color: hsl(var(--aw-color-primary)); color: hsl(var(--web-color-primary));
margin-block-end: 0.75rem; margin-block-end: 0.75rem;
} }
} }
@@ -486,13 +469,13 @@
align-items: center; align-items: center;
gap: 0.75rem; gap: 0.75rem;
.aw-label { .web-label {
margin-block-start: 0.25rem; margin-block-start: 0.25rem;
} }
} }
h4 { h4 {
color: hsl(var(--aw-color-primary)); color: hsl(var(--web-color-primary));
} }
p { p {
@@ -539,7 +522,7 @@
} }
.phone { .phone {
@include border-gradient; @include gradients.border-gradient;
--m-border-size: 1px; --m-border-size: 1px;
--m-border-radius: 2.5rem; --m-border-radius: 2.5rem;
--m-border-gradient-after: linear-gradient( --m-border-gradient-after: linear-gradient(
@@ -608,7 +591,7 @@
} }
:global(.header) { :global(.header) {
border-bottom: 1px solid hsl(var(--aw-color-greyscale-700)); border-bottom: 1px solid hsl(var(--web-color-greyscale-700));
color: var(--greyscale-400, #adadb1); color: var(--greyscale-400, #adadb1);
text-transform: uppercase; text-transform: uppercase;
@@ -628,8 +611,8 @@
} }
:global(.avatar) { :global(.avatar) {
background-color: hsl(var(--aw-color-greyscale-700)); background-color: hsl(var(--web-color-greyscale-700));
border-color: hsl(var(--aw-color-greyscale-700)); border-color: hsl(var(--web-color-greyscale-700));
} }
:global(.truncated) { :global(.truncated) {
@@ -649,7 +632,7 @@
} }
.controls { .controls {
@include border-gradient; @include gradients.border-gradient;
--m-border-radius: 1rem; --m-border-radius: 1rem;
--m-border-gradient-before: linear-gradient( --m-border-gradient-before: linear-gradient(
180deg, 180deg,
@@ -664,9 +647,13 @@
opacity: 0; opacity: 0;
background: rgba(255, 255, 255, 0.08); background: rgba(255, 255, 255, 0.08);
box-shadow: 0px 0px 0px 0px rgba(0, 0, 0, 0.06), -2px 4px 9px 0px rgba(0, 0, 0, 0.06), box-shadow:
-8px 15px 17px 0px rgba(0, 0, 0, 0.05), -19px 34px 23px 0px rgba(0, 0, 0, 0.03), 0px 0px 0px 0px rgba(0, 0, 0, 0.06),
-33px 60px 27px 0px rgba(0, 0, 0, 0.01), -52px 94px 30px 0px rgba(0, 0, 0, 0); -2px 4px 9px 0px rgba(0, 0, 0, 0.06),
-8px 15px 17px 0px rgba(0, 0, 0, 0.05),
-19px 34px 23px 0px rgba(0, 0, 0, 0.03),
-33px 60px 27px 0px rgba(0, 0, 0, 0.01),
-52px 94px 30px 0px rgba(0, 0, 0, 0);
backdrop-filter: blur(20px); backdrop-filter: blur(20px);
} }
</style> </style>

View File

@@ -5,13 +5,13 @@
<div class="outside"> <div class="outside">
<div class="wrapper"> <div class="wrapper">
<span class="aw-badges aw-eyebrow">Products_</span> <span class="web-badges web-eyebrow">Products_</span>
<h2 class="aw-display aw-u-color-text-primary u-margin-block-start-16"> <h2 class="web-display web-u-color-text-primary u-margin-block-start-16">
Your backend, minus the hassle Your backend, minus the hassle
</h2> </h2>
<p class="aw-description u-margin-block-start-16"> <p class="web-description u-margin-block-start-16">
Build secure and scalable applications with less code. Add authentication, databases, Build secure and scalable applications with less code. Add authentication, databases,
storage, and more using Appwrite's development platform. storage, and more using Appwrite's development platform.
</p> </p>
@@ -25,10 +25,10 @@
<div class="info"> <div class="info">
<h3> <h3>
<img src={info.icon.active} alt="" /> <img src={info.icon.active} alt="" />
<span class="aw-label aw-u-color-text-primary">{info.title}</span> <span class="web-label web-u-color-text-primary">{info.title}</span>
</h3> </h3>
<h4 class="aw-title">{info.subtitle}</h4> <h4 class="web-title">{info.subtitle}</h4>
<p> <p>
{info.description} {info.description}
</p> </p>
@@ -109,13 +109,13 @@
align-items: center; align-items: center;
gap: 0.75rem; gap: 0.75rem;
.aw-label { .web-label {
margin-block-start: 0.25rem; margin-block-start: 0.25rem;
} }
} }
h4 { h4 {
color: hsl(var(--aw-color-primary)); color: hsl(var(--web-color-primary));
margin-block-start: 0.75rem; margin-block-start: 0.75rem;
} }
@@ -159,7 +159,7 @@
} }
hr { hr {
border: 1px solid hsl(var(--aw-color-smooth)); border: 1px solid hsl(var(--web-color-smooth));
margin-inline: calc(var(--padding-inline) * -1); margin-inline: calc(var(--padding-inline) * -1);
} }
} }

View File

@@ -22,7 +22,7 @@
<div class="wrapper"> <div class="wrapper">
<button use:melt={$root} class="anim-checkbox"> <button use:melt={$root} class="anim-checkbox">
{#if $isChecked} {#if $isChecked}
<span class="aw-icon-check" /> <span class="web-icon-check" />
{/if} {/if}
</button> </button>
</div> </div>

View File

@@ -44,8 +44,8 @@
<div class="pseudo-table"> <div class="pseudo-table">
<div class="header"> <div class="header">
<span class="aw-eyebrow">Name</span> <span class="web-eyebrow">Name</span>
<span class="aw-eyebrow">Identifier</span> <span class="web-eyebrow">Identifier</span>
</div> </div>
{#each authData as user (user.id)} {#each authData as user (user.id)}
<div <div

View File

@@ -6,7 +6,7 @@
const { state } = authController; const { state } = authController;
const getIcon = (provider: string) => { const getIcon = (provider: string) => {
return `aw-icon-${provider.toLowerCase()}`; return `web-icon-${provider.toLowerCase()}`;
}; };
</script> </script>
@@ -39,7 +39,7 @@
> :nth-child(2) { > :nth-child(2) {
margin-left: 0.75rem; margin-left: 0.75rem;
color: hsl(var(--aw-color-white)); color: hsl(var(--web-color-white));
font-family: Inter; font-family: Inter;
font-size: 0.875rem; font-size: 0.875rem;
@@ -66,7 +66,7 @@
font-size: var(--size); font-size: var(--size);
width: var(--size); width: var(--size);
height: var(--size); height: var(--size);
color: hsl(var(--aw-color-greayscale-50)); color: hsl(var(--web-color-greayscale-50));
position: relative; position: relative;

View File

@@ -38,7 +38,7 @@
{#each objectKeys($state.controls).filter((p) => $state.controls[p]) as provider (provider)} {#each objectKeys($state.controls).filter((p) => $state.controls[p]) as provider (provider)}
<button class="oauth" transition:fade={{ duration: 100 }} animate:flip={{ duration: 250 }}> <button class="oauth" transition:fade={{ duration: 100 }} animate:flip={{ duration: 250 }}>
<div class="inner"> <div class="inner">
<span class="aw-icon-{provider.toLowerCase()}" /> <span class="web-icon-{provider.toLowerCase()}" />
<span>{provider}</span> <span>{provider}</span>
</div> </div>
</button> </button>
@@ -151,7 +151,7 @@
font-weight: 400; font-weight: 400;
line-height: 1.25rem; /* 166.667% */ line-height: 1.25rem; /* 166.667% */
letter-spacing: -0.0105rem; letter-spacing: -0.0105rem;
color: hsl(var(--aw-color-greyscale-500)); color: hsl(var(--web-color-greyscale-500));
margin-block-start: 0.75rem; margin-block-start: 0.75rem;
@@ -160,7 +160,7 @@
content: ''; content: '';
height: 1px; height: 1px;
flex-grow: 1; flex-grow: 1;
background-color: hsl(var(--aw-color-greyscale-200)); background-color: hsl(var(--web-color-greyscale-200));
} }
} }
@@ -179,7 +179,7 @@
border-radius: 0.5rem; border-radius: 0.5rem;
border: 1px solid #d9d9d9; border: 1px solid #d9d9d9;
color: hsl(var(--aw-color-greyscale-750)); color: hsl(var(--web-color-greyscale-750));
text-align: center; text-align: center;
/* Responsive/Caption-500 */ /* Responsive/Caption-500 */

View File

@@ -8,13 +8,13 @@
<div class="pseudo-table"> <div class="pseudo-table">
<div class="header"> <div class="header">
<span class="aw-eyebrow">Document ID</span> <span class="web-eyebrow">Document ID</span>
<span class="aw-eyebrow">Task</span> <span class="web-eyebrow">Task</span>
</div> </div>
{#each $state.tasks.slice(0, $state.tableSlice) as task (task.id)} {#each $state.tasks.slice(0, $state.tableSlice) as task (task.id)}
<div class="row" transition:slide={{ duration: 150 }} animate:flip={{ duration: 150 }}> <div class="row" transition:slide={{ duration: 150 }} animate:flip={{ duration: 150 }}>
<div class="copy-button"> <div class="copy-button">
<span class="aw-icon-copy" /> <span class="web-icon-copy" />
<span>{task.id}</span> <span>{task.id}</span>
</div> </div>
<span class="truncated">{task.title}</span> <span class="truncated">{task.title}</span>
@@ -36,7 +36,7 @@
[class*='icon-'] { [class*='icon-'] {
font-size: 1.25rem; font-size: 1.25rem;
color: hsl(var(--aw-color-greyscale-600)); color: hsl(var(--web-color-greyscale-600));
} }
span:not([class*='icon-']) { span:not([class*='icon-']) {

View File

@@ -23,7 +23,7 @@
</div> </div>
<button class="add-btn"> <button class="add-btn">
<span class="aw-icon-plus" /> <span class="web-icon-plus" />
</button> </button>
</div> </div>
@@ -55,14 +55,14 @@
[class*='icon-'] { [class*='icon-'] {
font-size: 1.25rem; font-size: 1.25rem;
color: hsl(var(--aw-color-greyscale-500)); color: hsl(var(--web-color-greyscale-500));
} }
} }
.date { .date {
margin-block-start: 3rem; margin-block-start: 3rem;
color: hsl(var(--aw-color-greyscale-600)); color: hsl(var(--web-color-greyscale-600));
font-family: Inter; font-family: Inter;
font-size: 0.75rem; font-size: 0.75rem;
font-style: normal; font-style: normal;
@@ -83,8 +83,8 @@
gap: 0.75rem; gap: 0.75rem;
border-radius: 0.5rem; border-radius: 0.5rem;
border: 1px solid hsl(var(--aw-color-greyscale-50)); border: 1px solid hsl(var(--web-color-greyscale-50));
background: hsl(var(--aw-color-white)); background: hsl(var(--web-color-white));
color: var(--greyscale-700, var(--color-greyscale-700, #56565c)); color: var(--greyscale-700, var(--color-greyscale-700, #56565c));
padding-block: 0.55rem; padding-block: 0.55rem;

View File

@@ -25,14 +25,14 @@ return res.json({ success: true });`.trim();
<div use:portal={{ target: '#code-bottom' }} class="bottom"> <div use:portal={{ target: '#code-bottom' }} class="bottom">
{#if $state.submit !== 'idle'} {#if $state.submit !== 'idle'}
<span class="aw-icon-github" in:fade /> <span class="web-icon-github" in:fade />
{/if} {/if}
{#if $state.submit === 'loading'} {#if $state.submit === 'loading'}
<span in:fade>Pushing to GitHub...</span> <span in:fade>Pushing to GitHub...</span>
<div class="loader is-small" in:fade /> <div class="loader is-small" in:fade />
{:else if $state.submit === 'success'} {:else if $state.submit === 'success'}
<span>Deployed to Appwrite Cloud</span> <span>Deployed to Appwrite Cloud</span>
<span class="aw-icon-check" /> <span class="web-icon-check" />
{/if} {/if}
</div> </div>

View File

@@ -119,7 +119,7 @@
[class*='icon-'] { [class*='icon-'] {
font-size: 1.25rem; font-size: 1.25rem;
color: hsl(var(--aw-color-greyscale-500)); color: hsl(var(--web-color-greyscale-500));
} }
} }

View File

@@ -93,6 +93,8 @@
</div> </div>
<style lang="scss"> <style lang="scss">
@use '$scss/abstract/mixins/border-gradient' as gradients;
// Utilities // Utilities
.f-eyebrow { .f-eyebrow {
color: #adadb0; color: #adadb0;
@@ -159,7 +161,7 @@
// Components // Components
.gradient-box { .gradient-box {
@include border-gradient; @include gradients.border-gradient;
--m-border-gradient-before: linear-gradient( --m-border-gradient-before: linear-gradient(
180deg, 180deg,
rgba(255, 255, 255, 0.12) 0%, rgba(255, 255, 255, 0.12) 0%,

View File

@@ -61,7 +61,7 @@
</div> </div>
<div class="row"> <div class="row">
<div class="search"> <div class="search">
<span class="aw-icon-search" /> <span class="web-icon-search" />
<span class="text"> Search </span> <span class="text"> Search </span>
</div> </div>
<div class="flow gap-8"> <div class="flow gap-8">
@@ -305,6 +305,8 @@
</div> </div>
<style lang="scss"> <style lang="scss">
@use '$scss/abstract/mixins/border-gradient' as gradients;
// Utilities // Utilities
.flow { .flow {
display: flex; display: flex;
@@ -390,7 +392,7 @@
} }
hr { hr {
border-bottom: 1px solid hsl(var(--aw-color-greyscale-50)); border-bottom: 1px solid hsl(var(--web-color-greyscale-50));
margin-block: 1rem; margin-block: 1rem;
} }
@@ -403,7 +405,7 @@
align-self: stretch; align-self: stretch;
border-radius: 0.625rem; border-radius: 0.625rem;
border: 1px dashed hsl(var(--aw-color-greyscale-50)); border: 1px dashed hsl(var(--web-color-greyscale-50));
color: #56565c; color: #56565c;
.text { .text {
@@ -594,7 +596,7 @@
} }
.graph-box { .graph-box {
@include border-gradient; @include gradients.border-gradient;
--m-border-gradient-before: linear-gradient( --m-border-gradient-before: linear-gradient(
180deg, 180deg,
rgba(255, 255, 255, 0.12) 0%, rgba(255, 255, 255, 0.12) 0%,

View File

@@ -8,9 +8,9 @@
<div class="pseudo-table"> <div class="pseudo-table">
<div class="header"> <div class="header">
<span class="aw-eyebrow">Filename</span> <span class="web-eyebrow">Filename</span>
<span class="aw-eyebrow">Type</span> <span class="web-eyebrow">Type</span>
<span class="aw-eyebrow">Size</span> <span class="web-eyebrow">Size</span>
</div> </div>
{#each $state.files as file (file.src)} {#each $state.files as file (file.src)}
<div class="row" in:slide={{ duration: 150 }} animate:flip={{ duration: 150 }}> <div class="row" in:slide={{ duration: 150 }} animate:flip={{ duration: 150 }}>

View File

@@ -28,7 +28,7 @@
</div> </div>
<button class="add-btn"> <button class="add-btn">
<span class="aw-icon-plus" /> <span class="web-icon-plus" />
</button> </button>
<div class="overlay" id="overlay-{$elId}"> <div class="overlay" id="overlay-{$elId}">
@@ -85,14 +85,14 @@
[class*='icon-'] { [class*='icon-'] {
font-size: 1.25rem; font-size: 1.25rem;
color: hsl(var(--aw-color-greyscale-500)); color: hsl(var(--web-color-greyscale-500));
} }
} }
.date { .date {
margin-block-start: 3rem; margin-block-start: 3rem;
color: hsl(var(--aw-color-greyscale-600)); color: hsl(var(--web-color-greyscale-600));
font-family: Inter; font-family: Inter;
font-size: 0.75rem; font-size: 0.75rem;
font-style: normal; font-style: normal;
@@ -113,8 +113,8 @@
gap: 0.75rem; gap: 0.75rem;
border-radius: 0.5rem; border-radius: 0.5rem;
border: 1px solid hsl(var(--aw-color-greyscale-50)); border: 1px solid hsl(var(--web-color-greyscale-50));
background: hsl(var(--aw-color-white)); background: hsl(var(--web-color-white));
color: var(--greyscale-700, var(--color-greyscale-700, #56565c)); color: var(--greyscale-700, var(--color-greyscale-700, #56565c));
padding-block: 0.55rem; padding-block: 0.55rem;

View File

@@ -107,8 +107,8 @@ export const scroll: Action<
HTMLElement, HTMLElement,
undefined, undefined,
{ {
'on:aw-scroll': (e: CustomEvent<ScrollInfo>) => void; 'on:web-scroll': (e: CustomEvent<ScrollInfo>) => void;
'on:aw-resize': (e: CustomEvent<ScrollInfo>) => void; 'on:web-resize': (e: CustomEvent<ScrollInfo>) => void;
} }
> = (node) => { > = (node) => {
function getScrollInfo(): ScrollInfo { function getScrollInfo(): ScrollInfo {
@@ -128,7 +128,7 @@ export const scroll: Action<
}; };
} }
const createHandler = (eventName: 'aw-scroll' | 'aw-resize') => { const createHandler = (eventName: 'web-scroll' | 'web-resize') => {
return () => { return () => {
node.dispatchEvent( node.dispatchEvent(
new CustomEvent<ScrollInfo>(eventName, { new CustomEvent<ScrollInfo>(eventName, {
@@ -138,8 +138,8 @@ export const scroll: Action<
}; };
}; };
const handleScroll = createHandler('aw-scroll'); const handleScroll = createHandler('web-scroll');
const handleResize = createHandler('aw-resize'); const handleResize = createHandler('web-resize');
handleScroll(); handleScroll();
handleResize(); handleResize();

View File

@@ -30,7 +30,7 @@
style:--y={`${y}px`} style:--y={`${y}px`}
style:--percentage={`${easedPercentage * 100}%`} style:--percentage={`${easedPercentage * 100}%`}
> >
<div class="aw-dot" /> <div class="web-dot" />
</div> </div>
<style lang="scss"> <style lang="scss">
@@ -42,14 +42,14 @@
height: 100%; height: 100%;
background: linear-gradient( background: linear-gradient(
to bottom, to bottom,
hsl(var(--aw-color-accent)) 0%, hsl(var(--web-color-accent)) 0%,
hsl(var(--aw-color-greyscale-700)) var(--percentage), hsl(var(--web-color-greyscale-700)) var(--percentage),
hsl(var(--aw-color-greyscale-700)) 100% hsl(var(--web-color-greyscale-700)) 100%
); );
border-radius: 100%; border-radius: 100%;
} }
.aw-dot { .web-dot {
position: absolute; position: absolute;
left: 50%; left: 50%;
translate: -50% var(--y, 0); translate: -50% var(--y, 0);

View File

@@ -1,5 +1,5 @@
import { PUBLIC_APPWRITE_PROJECT_ID } from '$env/static/public'; import { PUBLIC_APPWRITE_PROJECT_ID } from '$env/static/public';
import { Client, Databases, Functions } from 'appwrite'; import { Client, Databases, Functions } from '@appwrite.io/console';
export const client = new Client(); export const client = new Client();

View File

@@ -0,0 +1,13 @@
import { APPWRITE_API_KEY_INIT } from '$env/static/private';
import { PUBLIC_APPWRITE_PROJECT_INIT_ID } from '$env/static/public';
import { Client, Databases } from '@appwrite.io/console';
const clientServer = new Client();
clientServer
.setEndpoint('https://cloud.appwrite.io/v1')
.setProject(PUBLIC_APPWRITE_PROJECT_INIT_ID)
.setKey(APPWRITE_API_KEY_INIT);
export const appwriteInitServer = {
databases: new Databases(clientServer)
};

12
src/lib/appwrite/init.ts Normal file
View File

@@ -0,0 +1,12 @@
import { PUBLIC_APPWRITE_PROJECT_INIT_ID } from '$env/static/public';
import { Client, Account } from '@appwrite.io/console';
const client = new Client();
client
.setEndpoint('https://cloud.appwrite.io/v1')
.setProject(PUBLIC_APPWRITE_PROJECT_INIT_ID);
export const appwriteInit = {
client,
account: new Account(client)
};

View File

@@ -0,0 +1,35 @@
<script lang="ts">
export let open: boolean = false;
export let title: string;
</script>
<li class="collapsible-item">
<details class="collapsible-wrapper" {open}>
<summary class="collapsible-button">
<span class="text">{title}</span>
<div class="icon web-u-color-text-primary">
<span class="icon-cheveron-down" aria-hidden="true" />
</div>
</summary>
<div class="collapsible-content u-flex-vertical">
<slot />
</div>
</details>
</li>
<style>
.collapsible-item {
border-block-end: 0.0625rem solid hsl(var(--web-color-offset));
}
.collapsible-button {
padding-block-start: 1rem;
padding-block-end: 1rem;
}
.collapsible-content {
margin-block-start: 0;
padding-block-end: 0;
gap: 4px;
}
</style>

View File

@@ -0,0 +1,10 @@
<ul class="collapsible u-width-full-line" style="--p-toggle-border-color: var(--web-color-border);">
<slot />
</ul>
<style>
.collapsible {
padding-block-start: 0;
padding-block-end: 2rem;
}
</style>

View File

@@ -0,0 +1,7 @@
import Root from "./Root.svelte";
import Item from "./Item.svelte";
export {
Root as Accordion,
Item as AccordionItem
}

View File

@@ -12,26 +12,26 @@
</script> </script>
<li> <li>
<a class="aw-grid-articles-item is-transparent" {href}> <a class="web-grid-articles-item is-transparent" {href}>
<div class="aw-grid-articles-item-image"> <div class="web-grid-articles-item-image">
<Media <Media
src={cover} src={cover}
class="aw-u-media-ratio-16-9" class="web-u-media-ratio-16-9"
alt={title} alt={title}
autoplay autoplay
controls={false} controls={false}
/> />
</div> </div>
<div class="aw-grid-articles-item-content"> <div class="web-grid-articles-item-content">
<h4 class="aw-label aw-u-color-text-primary"> <h4 class="web-label web-u-color-text-primary">
{title} {title}
</h4> </h4>
<div class="aw-author"> <div class="web-author">
<div class="u-flex u-cross-center u-gap-8"> <div class="u-flex u-cross-center u-gap-8">
<img class="aw-author-image" src={avatar} width="24" height="24" alt={author} /> <img class="web-author-image" src={avatar} width="24" height="24" alt={author} />
<div class="aw-author-info"> <div class="web-author-info">
<h4 class="aw-sub-body-400 aw-u-color-text-primary">{author}</h4> <h4 class="web-sub-body-400 web-u-color-text-primary">{author}</h4>
<ul class="aw-metadata aw-caption-400 aw-is-not-mobile"> <ul class="web-metadata web-caption-400 web-is-not-mobile">
<li> <li>
{formatDate(date)} {formatDate(date)}
</li> </li>

View File

@@ -46,27 +46,27 @@
<slot name="header" /> <slot name="header" />
<div class="u-flex u-gap-12 u-cross-end u-margin-inline-start-auto"> <div class="u-flex u-gap-12 u-cross-end u-margin-inline-start-auto">
<button <button
class="aw-icon-button" class="web-icon-button"
aria-label="Move carousel backward" aria-label="Move carousel backward"
disabled={isStart} disabled={isStart}
on:click={() => prev()} on:click={() => prev()}
> >
<span class="aw-icon-arrow-left" aria-hidden="true" /> <span class="web-icon-arrow-left" aria-hidden="true" />
</button> </button>
<button <button
class="aw-icon-button" class="web-icon-button"
aria-label="Move carousel forward" aria-label="Move carousel forward"
disabled={isEnd} disabled={isEnd}
on:click={() => next()} on:click={() => next()}
> >
<span class="aw-icon-arrow-right" aria-hidden="true" /> <span class="web-icon-arrow-right" aria-hidden="true" />
</button> </button>
</div> </div>
</div> </div>
<div class="carousel-wrapper" data-state={isStart ? 'start' : isEnd ? 'end' : 'middle'}> <div class="carousel-wrapper" data-state={isStart ? 'start' : isEnd ? 'end' : 'middle'}>
<ul <ul
class="aw-grid-articles u-margin-block-start-32 carousel" class="web-grid-articles u-margin-block-start-32 carousel"
class:is-medium={size === 'medium'} class:is-medium={size === 'medium'}
class:is-big={size === 'big'} class:is-big={size === 'big'}
style:gap="{gap}px" style:gap="{gap}px"
@@ -97,7 +97,7 @@
left: 0; left: 0;
background: linear-gradient( background: linear-gradient(
to right, to right,
hsl(var(--aw-color-background-docs)), hsl(var(--web-color-background-docs)),
transparent transparent
); );
} }
@@ -108,7 +108,7 @@
&::after { &::after {
right: 0; right: 0;
background: linear-gradient(to left, hsl(var(--aw-color-background-docs)), transparent); background: linear-gradient(to left, hsl(var(--web-color-background-docs)), transparent);
} }
&[data-state='end']::after { &[data-state='end']::after {

View File

@@ -46,17 +46,17 @@
} }
</script> </script>
<section class="aw-content-footer"> <section class="web-content-footer">
<header class="aw-content-footer-header u-width-full-line"> <header class="web-content-footer-header u-width-full-line">
<div <div
class="u-flex u-gap-32 u-main-space-between u-cross-center u-width-full-line" class="u-flex u-gap-32 u-main-space-between u-cross-center u-width-full-line"
style="flex-wrap: wrap-reverse;" style="flex-wrap: wrap-reverse;"
> >
<div class="u-flex u-gap-16 u-cross-center"> <div class="u-flex u-gap-16 u-cross-center">
<h5 class="aw-main-body-600 aw-u-color-text-primary">Was this page helpful?</h5> <h5 class="web-main-body-600 web-u-color-text-primary">Was this page helpful?</h5>
<div class="u-flex u-gap-8"> <div class="u-flex u-gap-8">
<button <button
class="aw-radio-button" class="web-radio-button"
aria-label="helpful" aria-label="helpful"
on:click={() => { on:click={() => {
showFeedback = feedbackType === 'positive' ? false : true; showFeedback = feedbackType === 'positive' ? false : true;
@@ -66,7 +66,7 @@
<span class="icon-thumb-up" /> <span class="icon-thumb-up" />
</button> </button>
<button <button
class="aw-radio-button" class="web-radio-button"
aria-label="unhelpful" aria-label="unhelpful"
on:click={() => { on:click={() => {
showFeedback = feedbackType === 'negative' ? false : true; showFeedback = feedbackType === 'negative' ? false : true;
@@ -78,8 +78,8 @@
</button> </button>
</div> </div>
</div> </div>
<div class="aw-content-footer-header-end"> <div class="web-content-footer-header-end">
<ul class="aw-metadata aw-caption-400"> <ul class="web-metadata web-caption-400">
{#if date} {#if date}
<li>Last updated on {new Date(date)?.toLocaleDateString()}</li> <li>Last updated on {new Date(date)?.toLocaleDateString()}</li>
{/if} {/if}
@@ -88,7 +88,7 @@
href="https://github.com/appwrite/website" href="https://github.com/appwrite/website"
target="_blank" target="_blank"
rel="noopener noreferrer" rel="noopener noreferrer"
class="aw-link u-flex u-gap-4 u-cross-baseline" class="web-link u-flex u-gap-4 u-cross-baseline"
> >
<span class="icon-pencil-alt u-contents" aria-hidden="true" /> <span class="icon-pencil-alt u-contents" aria-hidden="true" />
<span>Update on GitHub</span> <span>Update on GitHub</span>
@@ -101,26 +101,26 @@
{#if showFeedback} {#if showFeedback}
<form <form
on:submit|preventDefault={handleSubmit} on:submit|preventDefault={handleSubmit}
class="aw-card is-normal" class="web-card is-normal"
style="--card-padding:1rem" style="--card-padding:1rem"
> >
<div class="u-flex-vertical u-gap-8"> <div class="u-flex-vertical u-gap-8">
<label for="message"> <label for="message">
<span class="aw-u-color-text-primary"> <span class="web-u-color-text-primary">
What did you {feedbackType === 'negative' ? 'dislike' : 'like'}? (optional) What did you {feedbackType === 'negative' ? 'dislike' : 'like'}? (optional)
</span> </span>
</label> </label>
<textarea <textarea
class="aw-input-text" class="web-input-text"
id="message" id="message"
placeholder="Write your message" placeholder="Write your message"
bind:value={comment} bind:value={comment}
/> />
<label for="message" class="u-margin-block-start-8"> <label for="message" class="u-margin-block-start-8">
<span class="aw-u-color-text-primary">Email</span> <span class="web-u-color-text-primary">Email</span>
</label> </label>
<input <input
class="aw-input-text" class="web-input-text"
placeholder="Enter your email" placeholder="Enter your email"
type="email" type="email"
name="email" name="email"
@@ -129,21 +129,21 @@
/> />
</div> </div>
{#if submitted} {#if submitted}
<p class="aw-u-color-text-primary u-margin-block-start-16"> <p class="web-u-color-text-primary u-margin-block-start-16">
Your message has been sent successfully. We appreciate your feedback. Your message has been sent successfully. We appreciate your feedback.
</p> </p>
{/if} {/if}
{#if error} {#if error}
<p class="aw-u-color-text-primary u-margin-block-start-16"> <p class="web-u-color-text-primary u-margin-block-start-16">
There was an error submitting your feedback. Please try again later. There was an error submitting your feedback. Please try again later.
</p> </p>
{/if} {/if}
<div class="u-flex u-main-end u-margin-block-start-16 u-gap-8"> <div class="u-flex u-main-end u-margin-block-start-16 u-gap-8">
<button class="aw-button is-text" on:click={() => (showFeedback = false)}> <button class="web-button is-text" on:click={() => (showFeedback = false)}>
<span>Cancel</span> <span>Cancel</span>
</button> </button>
<button type="submit" class="aw-button" disabled={submitting || !email}> <button type="submit" class="web-button" disabled={submitting || !email}>
<span>Submit</span> <span>Submit</span>
</button> </button>
</div> </div>

View File

@@ -12,8 +12,10 @@
</div> </div>
<style lang="scss"> <style lang="scss">
@use '$scss/abstract/mixins/border-gradient' as gradients;
.head-wrapper { .head-wrapper {
@include border-gradient; @include gradients.border-gradient;
--m-border-radius: 50%; --m-border-radius: 50%;
--m-border-gradient-before: linear-gradient( --m-border-gradient-before: linear-gradient(
135.1deg, 135.1deg,
@@ -43,5 +45,7 @@
img { img {
border-radius: 50%; border-radius: 50%;
padding: 10%; padding: 10%;
aspect-ratio: 1 / 1;
object-fit: cover;
} }
</style> </style>

View File

@@ -23,7 +23,7 @@
export let images: Array<string>; export let images: Array<string>;
</script> </script>
<div class="u-position-absolute aw-u-hide-mobile root"> <div class="u-position-absolute web-u-hide-mobile root">
{#each headPositions as [size, top, left], i} {#each headPositions as [size, top, left], i}
{@const image = clamp(0, images.length - 1, i % images.length)} {@const image = clamp(0, images.length - 1, i % images.length)}
<FloatingHead <FloatingHead

View File

@@ -15,30 +15,43 @@
const links: Record<string, { label: string; href: string; target?: string; rel?: string }[]> = const links: Record<string, { label: string; href: string; target?: string; rel?: string }[]> =
{ {
'Quick starts': [ 'Quick starts': [
{ label: 'Flutter', href: '/docs/quick-starts/flutter' }, { label: 'Web', href: '/docs/quick-starts/web' },
{ label: 'Next.js', href: '/docs/quick-starts/nextjs' }, { label: 'Next.js', href: '/docs/quick-starts/nextjs' },
{ label: 'React', href: '/docs/quick-starts/react' },
{ label: 'Vue.js', href: '/docs/quick-starts/vue' }, { label: 'Vue.js', href: '/docs/quick-starts/vue' },
{ label: 'Nuxt', href: '/docs/quick-starts/nuxt' },
{ label: 'SvelteKit', href: '/docs/quick-starts/sveltekit' }, { label: 'SvelteKit', href: '/docs/quick-starts/sveltekit' },
{ label: 'Refine', href: '/docs/quick-starts/refine' },
{ label: 'Angular', href: '/docs/quick-starts/angular' },
{ label: 'React Native', href: '/docs/quick-starts/react-native' },
{ label: 'Flutter', href: '/docs/quick-starts/flutter' },
{ label: 'Apple', href: '/docs/quick-starts/apple' }, { label: 'Apple', href: '/docs/quick-starts/apple' },
{ label: 'Android', href: '/docs/quick-starts/android' }, { label: 'Android', href: '/docs/quick-starts/android' },
{ label: 'Nuxt', href: '/docs/quick-starts/nuxt' },
{ label: 'Angular', href: '/docs/quick-starts/angular' },
{ label: 'Qwik', href: '/docs/quick-starts/qwik' }, { label: 'Qwik', href: '/docs/quick-starts/qwik' },
{ label: 'Astro', href: '/docs/quick-starts/astro' } { label: 'Astro', href: '/docs/quick-starts/astro' },
{ label: 'Solid', href: '/docs/quick-starts/solid' }
], ],
Products: [ Products: [
{ label: 'Auth', href: '/docs/products/auth' }, { label: 'Auth', href: '/docs/products/auth' },
{ label: 'Databases', href: '/docs/products/databases' }, { label: 'Databases', href: '/docs/products/databases' },
{ label: 'Functions', href: '/docs/products/functions' }, { label: 'Functions', href: '/docs/products/functions' },
{ label: 'Messaging', href: '/products/messaging' },
{ label: 'Storage', href: '/docs/products/storage' }, { label: 'Storage', href: '/docs/products/storage' },
{ label: 'Realtime', href: '/docs/apis/realtime' }, { label: 'Realtime', href: '/docs/apis/realtime' },
], ],
Learn: [ Learn: [
{ label: 'Docs', href: '/docs' }, { label: 'Docs', href: '/docs' },
{ label: 'Community', href: '/community' }, { label: 'Community', href: '/community' },
{ label: 'Init', href: '/init' },
{ label: 'Threads', href: '/threads' }, { label: 'Threads', href: '/threads' },
{ label: 'Blog', href: '/blog' }, { label: 'Blog', href: '/blog' },
{ label: 'Changelog', href: '/changelog' }, { label: 'Changelog', href: '/changelog' },
{
label: 'Roadmap',
href: 'https://github.com/orgs/appwrite/projects',
target: '_blank',
rel: 'noopener noreferrer'
},
{ {
label: 'Source code', label: 'Source code',
href: 'https://github.com/appwrite', href: 'https://github.com/appwrite',
@@ -52,6 +65,10 @@
rel: 'noopener noreferrer' rel: 'noopener noreferrer'
} }
], ],
Program: [
{ label: 'Heroes', href: '/heroes' },
{ label: 'Startups', href: '/startups' }
],
About: [ About: [
{ label: 'Company', href: '/company' }, { label: 'Company', href: '/company' },
{ label: 'Pricing', href: '/pricing' }, { label: 'Pricing', href: '/pricing' },
@@ -61,7 +78,6 @@
target: '_blank', target: '_blank',
rel: 'noopener noreferrer' rel: 'noopener noreferrer'
}, },
{ label: 'Heroes', href: '/heroes' },
{ {
label: 'Store', label: 'Store',
href: 'https://appwrite.store', href: 'https://appwrite.store',
@@ -69,61 +85,57 @@
rel: 'noopener noreferrer' rel: 'noopener noreferrer'
}, },
{ label: 'Contact us', href: '/contact-us' }, { label: 'Contact us', href: '/contact-us' },
{ label: 'Assets', href: '/assets' }, { label: 'Assets', href: '/assets' }
],
Policies: [
{ label: 'Terms', href: '/terms' },
{ label: 'Privacy', href: '/privacy' },
{ label: 'Cookies', href: '/cookies' }
] ]
}; };
</script> </script>
<nav aria-label="Footer" <nav
class="aw-footer-nav u-margin-block-start-100 u-position-relative" aria-label="Footer"
class:aw-u-sep-block-start={!noBorder} class="web-footer-nav u-margin-block-start-100 u-position-relative"
class:web-u-sep-block-start={!noBorder}
> >
<img class="aw-logo" src="/images/logos/appwrite.svg" alt="appwrite" height="24" width="130" /> <img class="web-logo" src="/images/logos/appwrite.svg" alt="appwrite" height="24" width="130" />
<ul class="aw-footer-nav-main-list" use:melt={$root}> <ul class="web-footer-nav-main-list" use:melt={$root}>
{#each Object.entries(links) as [title, items]} {#each Object.entries(links) as [title, items]}
<li class="aw-footer-nav-main-item aw-is-not-mobile"> <li class="web-footer-nav-main-item web-is-not-mobile">
<h5 class="aw-footer-nav-main-title aw-is-not-mobile aw-caption-500 aw-eyebrow"> <h2 class="web-footer-nav-main-title web-is-not-mobile web-caption-500 web-eyebrow">
{title} {title}
</h5> </h2>
<ul class="aw-footer-nav-secondary-list aw-sub-body-400"> <ul class="web-footer-nav-secondary-list web-sub-body-400">
{#each items as { href, label, target, rel }} {#each items as { href, label, target, rel }}
<li> <li>
<a class="aw-link" {href} {target} {rel}>{label}</a> <a class="web-link" {href} {target} {rel}>{label}</a>
</li> </li>
{/each} {/each}
</ul> </ul>
</li> </li>
<li <li
class="aw-footer-nav-main-item aw-is-only-mobile" class="web-footer-nav-main-item web-is-only-mobile"
use:melt={$item({ value: title })} use:melt={$item({ value: title })}
> >
<h5 use:melt={$heading({ level: 5 })}> <h5 use:melt={$heading({ level: 5 })}>
<button <button
class="aw-footer-nav-button aw-is-only-mobile" class="web-footer-nav-button web-is-only-mobile"
use:melt={$trigger({ value: title })} use:melt={$trigger({ value: title })}
> >
<span class="aw-caption-500 aw-eyebrow">{title}</span> <span class="web-caption-500 web-eyebrow">{title}</span>
<span <span
class="aw-icon-chevron-down aw-u-transition" class="web-icon-chevron-down web-u-transition"
class:aw-u-rotate-180={$isSelected(title)} class:web-u-rotate-180={$isSelected(title)}
style:font-size="1rem" style:font-size="1rem"
/> />
</button> </button>
</h5> </h5>
{#if $isSelected(title)} {#if $isSelected(title)}
<ul <ul
class="aw-footer-nav-secondary-list aw-sub-body-400" class="web-footer-nav-secondary-list web-sub-body-400"
use:melt={$content({ value: title })} use:melt={$content({ value: title })}
transition:slide={{ duration: 250 }} transition:slide={{ duration: 250 }}
> >
{#each items as { href, label, target, rel }} {#each items as { href, label, target, rel }}
<li> <li>
<a class="aw-link" {href} {target} {rel}>{label}</a> <a class="web-link" {href} {target} {rel}>{label}</a>
</li> </li>
{/each} {/each}
</ul> </ul>

View File

@@ -0,0 +1,25 @@
<script lang="ts">
export let classes = '';
</script>
<a href="https://cloud.appwrite.io" class={`web-button ${classes}`}>
<span class="logged-in"><slot name="isLoggedIn">Go to Console</slot></span>
<span class="not-logged-in"><slot name="isNotLoggedIn">Get started</slot></span>
</a>
<style lang="scss">
:global(body[data-logged-in]) {
.logged-in {
display: block;
}
.not-logged-in {
display: none;
}
}
.not-logged-in {
display: block;
}
.logged-in {
display: none;
}
</style>

View File

@@ -8,13 +8,13 @@
</script> </script>
{#if variant === 'homepage'} {#if variant === 'homepage'}
<footer class="aw-main-footer u-position-relative u-margin-block-start-48"> <footer class="web-main-footer u-position-relative u-margin-block-start-48">
<ul class="u-flex u-gap-8"> <ul class="u-flex u-gap-8">
{#each socials as social} {#each socials as social}
<li> <li>
<a <a
href={social.link} href={social.link}
class="aw-icon-button" class="web-icon-button"
aria-label={social.label} aria-label={social.label}
target="_blank" target="_blank"
rel="noopener noreferrer" rel="noopener noreferrer"
@@ -24,19 +24,26 @@
</li> </li>
{/each} {/each}
</ul> </ul>
<div>Copyright © {year} Appwrite</div> <div class="u-flex u-gap-16">
<ul class="u-flex u-gap-8">
<li><a class="web-link" href="/terms">Terms</a></li>
<li><a class="web-link" href="/privacy">Privacy</a></li>
<li><a class="web-link" href="/cookies">Cookies</a></li>
</ul>
<div>Copyright © {year} Appwrite</div>
</div>
</footer> </footer>
{:else if variant === 'docs'} {:else if variant === 'docs'}
<footer <footer
class="aw-main-footer is-with-bg-color u-margin-block-start-32 u-small u-position-relative" class="web-main-footer is-with-bg-color u-margin-block-start-32 u-small u-position-relative"
> >
<div class="aw-main-footer-grid-1"> <div class="web-main-footer-grid-1">
<ul class="aw-main-footer-grid-1-column-1 u-flex u-gap-8"> <ul class="web-main-footer-grid-1-column-1 u-flex u-gap-8">
{#each socials as social} {#each socials as social}
<li> <li>
<a <a
href={social.link} href={social.link}
class="aw-icon-button" class="web-icon-button"
aria-label={social.label} aria-label={social.label}
target="_blank" target="_blank"
rel="noopener noreferrer" rel="noopener noreferrer"
@@ -46,10 +53,10 @@
</li> </li>
{/each} {/each}
</ul> </ul>
<div class="aw-main-footer-grid-1-column-2"> <div class="web-main-footer-grid-1-column-2">
<ThemeSelect /> <ThemeSelect />
</div> </div>
<ul class="aw-main-footer-grid-1-column-3 aw-main-footer-links"> <ul class="web-main-footer-grid-1-column-3 web-main-footer-links">
<li> <li>
<a href="/discord" target="_blank" rel="noopener noreferrer">Support</a> <a href="/discord" target="_blank" rel="noopener noreferrer">Support</a>
</li> </li>
@@ -62,7 +69,7 @@
<a href="https://github.com/appwrite/appwrite/releases" target="_blank" rel="noopener noreferrer">Changelog</a> <a href="https://github.com/appwrite/appwrite/releases" target="_blank" rel="noopener noreferrer">Changelog</a>
</li> --> </li> -->
</ul> </ul>
<div class="aw-main-footer-grid-1-column-4 aw-main-footer-copyright"> <div class="web-main-footer-grid-1-column-4 web-main-footer-copyright">
Copyright © {year} Appwrite Copyright © {year} Appwrite
</div> </div>
</div> </div>
@@ -70,7 +77,7 @@
{/if} {/if}
<style lang="scss"> <style lang="scss">
.aw-icon-button { .web-icon-button {
display: grid; display: grid;
} }
</style> </style>

View File

@@ -3,13 +3,13 @@
export let description: string; export let description: string;
</script> </script>
<div class="aw-card is-normal has-border-gradient"> <div class="web-card is-normal has-border-gradient">
<div class="aw-title aw-u-color-text-primary">{metric}</div> <div class="web-title web-u-color-text-primary">{metric}</div>
<div class="aw-description">{description}</div> <div class="web-description">{description}</div>
</div> </div>
<style lang="scss"> <style lang="scss">
.aw-card { .web-card {
padding: 1.25rem; padding: 1.25rem;
} }
</style> </style>

View File

@@ -1,5 +1,6 @@
<script lang="ts"> <script lang="ts">
import { afterNavigate } from '$app/navigation'; import { afterNavigate } from '$app/navigation';
import { IsLoggedIn } from '$lib/components';
import { GITHUB_STARS } from '$lib/constants'; import { GITHUB_STARS } from '$lib/constants';
import type { NavLink } from '$lib/layouts/Main.svelte'; import type { NavLink } from '$lib/layouts/Main.svelte';
@@ -13,38 +14,37 @@
<svelte:window on:resize={() => open && (open = false)} /> <svelte:window on:resize={() => open && (open = false)} />
<nav class="aw-side-nav aw-is-not-desktop" class:u-hide={!open}> <nav class="web-side-nav web-is-not-desktop" class:u-hide={!open}>
<div class="aw-side-nav-wrapper aw-u-padding-inline-16"> <div class="web-side-nav-wrapper web-u-padding-inline-16">
<div class="u-flex items-center u-gap-8"> <div class="u-flex items-center u-gap-8">
<a href="https://cloud.appwrite.io/register" class="aw-button is-secondary aw-u-flex-1"> <a href="https://cloud.appwrite.io/register" class="web-button is-secondary web-u-flex-1">
Sign up Sign up
</a> </a>
<IsLoggedIn classes="web-u-flex-1" />
<a href="https://cloud.appwrite.io" class="aw-button aw-u-flex-1">Get started</a>
</div> </div>
<div class="aw-side-nav-scroll"> <div class="web-side-nav-scroll">
<section> <section>
<ul> <ul>
{#each links as { href, label }} {#each links as { href, label }}
<li> <li>
<a class="aw-side-nav-button" {href}> <a class="web-side-nav-button" {href}>
<span class="aw-caption-400">{label}</span> <span class="web-caption-400">{label}</span>
</a> </a>
</li> </li>
{/each} {/each}
</ul> </ul>
</section> </section>
</div> </div>
<div class="aw-side-nav-mobile-footer-buttons"> <div class="web-side-nav-mobile-footer-buttons">
<a <a
href="https://github.com/appwrite/appwrite/stargazers" href="https://github.com/appwrite/appwrite/stargazers"
target="_blank" target="_blank"
rel="noopener noreferrer" rel="noopener noreferrer"
class="aw-button is-text aw-u-inline-width-100-percent-mobile" class="web-button is-text web-u-inline-width-100-percent-mobile"
> >
<span class="aw-icon-star" aria-hidden="true" /> <span class="web-icon-star" aria-hidden="true" />
<span class="text">Star on GitHub</span> <span class="text">Star on GitHub</span>
<span class="aw-inline-tag aw-sub-body-400">{GITHUB_STARS}</span> <span class="web-inline-tag web-sub-body-400">{GITHUB_STARS}</span>
</a> </a>
</div> </div>
</div> </div>

View File

@@ -78,16 +78,16 @@
</svg> </svg>
</div> </div>
<div class="aw-big-padding-section"> <div class="web-big-padding-section">
<div class="aw-big-padding-section-level-1"> <div class="web-big-padding-section-level-1">
<div class="aw-big-padding-section-level-2"> <div class="web-big-padding-section-level-2">
<div class="aw-container"> <div class="web-container">
<div class="aw-grid-1-1-opt-2 u-gap-32"> <div class="web-grid-1-1-opt-2 u-gap-32">
<div class=""> <div class="">
<div class="aw-u-max-inline-size-none-mobile" class:aw-u-max-width-380={!submitted}> <div class="web-u-max-inline-size-none-mobile" class:web-u-max-width-380={!submitted}>
<section class="u-flex-vertical aw-u-gap-20"> <section class="u-flex-vertical web-u-gap-20">
<h1 class="aw-title aw-u-color-text-primary">Subscribe to our newsletter</h1> <h1 class="web-title web-u-color-text-primary">Subscribe to our newsletter</h1>
<p class="aw-description aw-u-padding-block-end-40"> <p class="web-description web-u-padding-block-end-40">
Sign up to our company blog and get the latest insights from Appwrite. Learn more Sign up to our company blog and get the latest insights from Appwrite. Learn more
about engineering, product design, building community, and tips & tricks for using about engineering, product design, building community, and tips & tricks for using
Appwrite. Appwrite.
@@ -134,7 +134,7 @@
<div class="u-flex u-flex-vertical u-gap-4"> <div class="u-flex u-flex-vertical u-gap-4">
<label for="name">Your name</label> <label for="name">Your name</label>
<input <input
class="aw-input-text" class="web-input-text"
type="text" type="text"
placeholder="Enter your name" placeholder="Enter your name"
id="name" id="name"
@@ -146,7 +146,7 @@
<div class="u-flex u-flex-vertical u-gap-4"> <div class="u-flex u-flex-vertical u-gap-4">
<label for="email">Your email</label> <label for="email">Your email</label>
<input <input
class="aw-input-text" class="web-input-text"
type="email" type="email"
placeholder="Enter your email" placeholder="Enter your email"
required required
@@ -155,7 +155,7 @@
bind:value={email} bind:value={email}
/> />
</div> </div>
<button type="submit" class="aw-button" disabled={submitting}>Sign up</button> <button type="submit" class="web-button" disabled={submitting}>Sign up</button>
{#if error} {#if error}
<span class="text"> Something went wrong. Please try again later. </span> <span class="text"> Something went wrong. Please try again later. </span>
{/if} {/if}

View File

@@ -1,80 +1,81 @@
<script lang="ts"> <script lang="ts">
</script> </script>
<img src="/images/bgs/pre-footer.png" alt="" class="aw-pre-footer-bg" style="z-index:-1" /> <img src="/images/bgs/pre-footer.png" alt="" class="web-pre-footer-bg" style="z-index:-1" />
<div class="aw-grid-1-1 u-gap-32 aw-u-row-gap-80 u-position-relative"> <div class="web-grid-1-1 u-gap-32 web-u-row-gap-80 u-position-relative">
<section class="aw-hero u-flex aw-u-row-gap-32 u-main-center u-cross-center"> <section class="web-hero u-flex web-u-row-gap-32 u-main-center u-cross-center">
<h2 class="aw-display u-max-width-500 aw-u-text-align-center aw-u-color-text-primary"> <h2 class="web-display u-max-width-500 web-u-text-align-center web-u-color-text-primary">
Start building today Start building today
</h2> </h2>
<a <a
href="https://cloud.appwrite.io" href="https://cloud.appwrite.io"
class="aw-button is-transparent aw-u-cross-child-center" class="web-button is-transparent web-u-cross-child-center"
> >
<span class="text">Get started</span> <span class="text">Get started</span>
</a> </a>
</section> </section>
<section <section
class="aw-card is-transparent has-border-gradient aw-u-max-inline-width-584-mobile aw-u-margin-inline-auto-mobile aw-u-inline-width-100-percent-mobile" class="web-card is-transparent has-border-gradient web-u-max-inline-width-584-mobile web-u-margin-inline-auto-mobile web-u-inline-width-100-percent-mobile"
> >
<header class="aw-strip-plans-header"> <header class="web-strip-plans-header">
<div class="aw-strip-plans-header-wrapper aw-u-row-gap-24"> <div class="web-strip-plans-header-wrapper web-u-row-gap-24">
<h3 class="aw-title aw-u-color-text-primary">Our plans</h3> <h3 class="web-title web-u-color-text-primary">Our plans</h3>
</div> </div>
</header> </header>
<ul class="aw-strip-plans"> <ul class="web-strip-plans">
<li class="aw-strip-plans-item aw-strip-plans-container-query"> <li class="web-strip-plans-item web-strip-plans-container-query">
<div class="aw-strip-plans-item-wrapper"> <div class="web-strip-plans-item-wrapper">
<div class="aw-strip-plans-plan"> <div class="web-strip-plans-plan">
<h4 class="title aw-description">Starter</h4> <h4 class="title web-description">Free</h4>
<div class="aw-title aw-u-color-text-primary">$0</div> <div class="web-title web-u-color-text-primary">$0</div>
<div class="info aw-caption-500" /> <div class="info web-caption-500" />
</div> </div>
<p class="aw-strip-plans-info aw-caption-500"> <p class="web-strip-plans-info web-caption-500">
For personal hobby projects and students. For personal hobby projects and students.
</p> </p>
<a <a
href="https://cloud.appwrite.io/register" href="https://cloud.appwrite.io/register"
class="aw-button is-secondary is-full-width-mobile aw-u-cross-child-end" class="web-button is-secondary is-full-width-mobile web-u-cross-child-end"
> >
<span class="text">Get started</span> <span class="text">Get started</span>
</a> </a>
</div> </div>
</li> </li>
<li class="aw-strip-plans-item aw-strip-plans-container-query"> <li class="web-strip-plans-item web-strip-plans-container-query">
<div class="aw-strip-plans-item-wrapper"> <div class="web-strip-plans-item-wrapper">
<div class="aw-strip-plans-plan"> <div class="web-strip-plans-plan">
<h4 class="title aw-description">Pro</h4> <h4 class="title web-description">Pro</h4>
<div class="aw-title aw-u-color-text-primary">$15</div> <div class="web-title web-u-color-text-primary">$15</div>
<div class="info aw-caption-500">per member/month</div> <div class="info web-caption-500">per member/month</div>
</div> </div>
<p class="aw-strip-plans-info aw-caption-500"> <p class="web-strip-plans-info web-caption-500">
For pro developers and teams that need to scale their products. For pro developers and teams that need to scale their products.
</p> </p>
<a <a
href="https://cloud.appwrite.io/console?type=createPro" href="https://cloud.appwrite.io/console?type=createPro"
class="aw-button is-full-width-mobile aw-u-cross-child-end" class="web-button is-full-width-mobile web-u-cross-child-end"
target="_blank" target="_blank"
rel="noopener noreferrer" rel="noopener noreferrer"
> >
<span class="text">Start trial</span> <!-- <span class="text">Start trial</span> -->
<span class="text">Start building</span>
</a> </a>
</div> </div>
</li> </li>
<li class="aw-strip-plans-item aw-strip-plans-container-query"> <li class="web-strip-plans-item web-strip-plans-container-query">
<div class="aw-strip-plans-item-wrapper"> <div class="web-strip-plans-item-wrapper">
<div class="aw-strip-plans-plan"> <div class="web-strip-plans-plan">
<h4 class="title aw-description">Scale</h4> <h4 class="title web-description">Scale</h4>
<div class="aw-title aw-u-color-text-primary">$685</div> <div class="web-title web-u-color-text-primary">$599</div>
<div class="info aw-caption-500">per org/month</div> <div class="info web-caption-500">per org/month</div>
</div> </div>
<p class="aw-strip-plans-info aw-caption-500"> <p class="web-strip-plans-info web-caption-500">
For pro developers and production projects that need the ability to scale. For pro developers and production projects that need the ability to scale.
</p> </p>
<button <button
class="aw-button is-full-width-mobile is-secondary aw-u-cross-child-end" class="web-button is-full-width-mobile is-secondary web-u-cross-child-end"
disabled disabled
> >
<span class="text">Coming soon</span> <span class="text">Coming soon</span>
@@ -86,7 +87,7 @@
</div> </div>
<style lang="scss"> <style lang="scss">
.aw-pre-footer-bg { .web-pre-footer-bg {
position: absolute; position: absolute;
top: clamp(300px, 50vw, 50%); top: clamp(300px, 50vw, 50%);
left: clamp(300px, 50vw, 50%); left: clamp(300px, 50vw, 50%);

View File

@@ -136,6 +136,10 @@
$layoutState.showSearch = false; $layoutState.showSearch = false;
} }
} }
function getRelevantSubtitle(hit: Hit): string {
return hit.h2 ?? hit.h3 ?? hit.h4 ?? hit.h5 ?? hit.h6 ?? null;
}
</script> </script>
<svelte:window on:keydown={handleKeypress} /> <svelte:window on:keydown={handleKeypress} />
@@ -146,29 +150,30 @@
class="wrapper u-position-fixed u-padding-0 u-inset-0 u-flex u-main-center u-cross-center" class="wrapper u-position-fixed u-padding-0 u-inset-0 u-flex u-main-center u-cross-center"
data-visible={open ? true : undefined} data-visible={open ? true : undefined}
style:z-index="100" style:z-index="100"
style:background="hsl(var(--aw-color-black) / 0.3)" style:background="hsl(var(--web-color-black) / 0.3)"
style:backdrop-filter="blur(15px)" style:backdrop-filter="blur(15px)"
style:-webkit-backdrop-filter="blur(15px)" style:-webkit-backdrop-filter="blur(15px)"
bind:this={container} bind:this={container}
on:click={handleExit} on:click={handleExit}
> >
<div <div
class="aw-input-text-search-wrapper aw-u-max-width-680 aw-u-margin-inline-20 u-width-full-line" class="web-input-text-search-wrapper web-u-max-width-680 web-u-margin-inline-20 u-width-full-line"
> >
<span <span
class="aw-icon-search u-z-index-5" class="web-icon-search u-z-index-5"
aria-hidden="true" aria-hidden="true"
style="inset-block-start:0.9rem" style="inset-block-start:0.9rem"
/> />
<div id="searchbox" /> <div id="searchbox" />
<input <input
class="aw-input-button -u-padding-block-0 u-position-relative u-z-index-1" class="web-input-button -u-padding-block-0 u-position-relative u-z-index-1"
type="text" type="text"
id="search" id="search"
bind:value bind:value
placeholder="Search in docs" placeholder="Search in docs"
style="border-end-start-radius:0; border-end-end-radius:0;" style="border-end-start-radius:0; border-end-end-radius:0;"
style:inline-size="100%"
use:melt={$input} use:melt={$input}
bind:this={inputEl} bind:this={inputEl}
data-hit="-1" data-hit="-1"
@@ -179,38 +184,40 @@
}} }}
/> />
<div <div
class="aw-card is-normal u-flex-vertical u-gap-24" class="web-card is-normal u-flex-vertical u-gap-24"
use:melt={$menu} use:melt={$menu}
style="--card-padding-mobile:1rem; border-radius:0 0 0.5rem 0.5rem;" style="--card-padding-mobile:1rem; border-radius:0 0 0.5rem 0.5rem;"
> >
{#if value} {#if value}
<section> <section>
{#if results.length > 0} {#if results.length > 0}
<h6 class="aw-eyebrow">{results.length} results found</h6> <h6 class="web-eyebrow">{results.length} results found</h6>
<ul class="u-flex-vertical u-gap-4 u-margin-block-start-8"> <ul class="u-flex-vertical u-gap-4 u-margin-block-start-8">
{#each results as hit, i (hit.uid)} {#each results as hit, i (hit.uid)}
{@const relevantSubtitle = getRelevantSubtitle(hit)}
<li> <li>
<a <a
data-hit={i} data-hit={i}
href={createHref(hit)} href={createHref(hit)}
class="aw-button aw-caption-400 is-text u-flex-vertical u-gap-8 u-min-width-100-percent class="web-button web-caption-400 is-text u-flex-vertical u-gap-8 u-min-width-100-percent
aw-u-padding-block-8 aw-padding-inline-12 aw-u-cross-start u-max-width-100-percent" web-u-padding-block-8 web-padding-inline-12 web-u-cross-start u-max-width-100-percent"
use:melt={$option({ use:melt={$option({
value: hit, value: hit,
label: hit.title ?? i.toString() label: hit.title ?? i.toString()
})} })}
> >
<div class="aw-u-trim-1"> <div class="web-u-trim-1">
<span class="aw-u-color-text-secondary">{hit.h1}</span> <span class="web-u-color-text-secondary">{hit.h1}</span>
{#if hit.h2} {#if relevantSubtitle}
<span class="aw-u-color-text-secondary"> / </span> <span class="web-u-color-text-secondary"> / </span>
<span class="aw-u-color-text-primary">{hit.h2}</span <span class="web-u-color-text-primary">
> {relevantSubtitle}
</span>
{/if} {/if}
</div> </div>
{#if hit.p} {#if hit.p}
<div <div
class="u-inline aw-u-color-text-secondary aw-u-trim-1" class="web-u-color-text-secondary web-u-trim-1"
> >
{hit.p} {hit.p}
</div> </div>
@@ -220,14 +227,14 @@
{/each} {/each}
</ul> </ul>
{:else} {:else}
<p class="aw-caption-400"> <p class="web-caption-400">
No results found for <span class="u-bold">{value}</span> No results found for <span class="u-bold">{value}</span>
</p> </p>
{/if} {/if}
</section> </section>
{/if} {/if}
<section> <section>
<h6 class="aw-eyebrow">Recommended</h6> <h6 class="web-eyebrow">Recommended</h6>
<ul class="u-flex-vertical u-gap-4 u-margin-block-start-8"> <ul class="u-flex-vertical u-gap-4 u-margin-block-start-8">
{#each recommended as hit, i (hit.uid)} {#each recommended as hit, i (hit.uid)}
{@const index = i + (results.length ? results.length : 0)} {@const index = i + (results.length ? results.length : 0)}
@@ -239,13 +246,13 @@
value: hit, value: hit,
label: hit.title ?? i.toString() label: hit.title ?? i.toString()
})} })}
class="aw-button aw-caption-400 is-text u-flex-vertical u-gap-8 u-min-width-100-percent aw-u-padding-block-4 aw-u-cross-start" class="web-button web-caption-400 is-text u-flex-vertical u-gap-8 u-min-width-100-percent web-u-padding-block-4 web-u-cross-start"
> >
<div class="aw-u-trim-1"> <div class="web-u-trim-1">
<span class="aw-u-color-text-secondary">{hit.h1}</span> <span class="web-u-color-text-secondary">{hit.h1}</span>
{#if hit.h2} {#if hit.h2}
<span class="aw-u-color-text-secondary"> / </span> <span class="web-u-color-text-secondary"> / </span>
<span class="aw-u-color-text-primary">{hit.h2}</span> <span class="web-u-color-text-primary">{hit.h2}</span>
{/if} {/if}
</div> </div>
</a> </a>
@@ -269,11 +276,11 @@
pointer-events: auto; pointer-events: auto;
} }
a.aw-button { a.web-button {
scroll-margin-block: 1rem; scroll-margin-block: 1rem;
} }
.aw-card { .web-card {
margin-block-start: -0.0625rem; margin-block-start: -0.0625rem;
max-block-size: min(18.75rem, calc(100vh - 5.5rem)); max-block-size: min(18.75rem, calc(100vh - 5.5rem));
border-block-start-width: 0; border-block-start-width: 0;

View File

@@ -33,7 +33,6 @@
preventScroll, preventScroll,
positioning: { positioning: {
sameWidth: true, sameWidth: true,
fitViewport: true,
placement placement
}, },
forceVisible: true, forceVisible: true,
@@ -45,7 +44,9 @@
dispatch('change', next?.value); dispatch('change', next?.value);
return next; return next;
} },
portal: null,
scrollAlignment: 'center'
}); });
$: selectedOption = options.find((o) => o.value === value); $: selectedOption = options.find((o) => o.value === value);
@@ -79,9 +80,9 @@
</script> </script>
<button <button
class="aw-select is-colored" class="web-select is-colored"
{id} {id}
class:aw-is-not-mobile={nativeMobile} class:web-is-not-mobile={nativeMobile}
use:melt={$trigger} use:melt={$trigger}
aria-label="Select theme" aria-label="Select theme"
> >
@@ -96,8 +97,8 @@
{#if $open} {#if $open}
<div <div
class="aw-select-menu" class="web-select-menu"
class:aw-is-not-mobile={nativeMobile} class:web-is-not-mobile={nativeMobile}
style:z-index={10000} style:z-index={10000}
use:melt={$menu} use:melt={$menu}
transition:fly={flyParams} transition:fly={flyParams}
@@ -107,7 +108,7 @@
{#if isDefault} {#if isDefault}
<div class="u-flex u-flex-vertical u-gap-2"> <div class="u-flex u-flex-vertical u-gap-2">
{#each group.options as option} {#each group.options as option}
<button class="aw-select-option" use:melt={$optionEl(option)}> <button class="web-select-option" use:melt={$optionEl(option)}>
{#if option.icon} {#if option.icon}
<span class={option.icon} aria-hidden="true" /> <span class={option.icon} aria-hidden="true" />
{/if} {/if}
@@ -116,13 +117,13 @@
{/each} {/each}
</div> </div>
{:else} {:else}
<div class="aw-select-group" use:melt={$groupEl(group.label)}> <div class="web-select-group" use:melt={$groupEl(group.label)}>
<span class="aw-select-group-label" use:melt={$groupLabel(group.label)}> <span class="web-select-group-label" use:melt={$groupLabel(group.label)}>
{group.label} {group.label}
</span> </span>
{#each group.options as option} {#each group.options as option}
<button class="aw-select-option" use:melt={$optionEl(option)}> <button class="web-select-option" use:melt={$optionEl(option)}>
{#if option.icon} {#if option.icon}
<span class={option.icon} aria-hidden="true" /> <span class={option.icon} aria-hidden="true" />
{/if} {/if}
@@ -136,7 +137,7 @@
{/if} {/if}
<div <div
class="aw-select is-colored aw-is-only-mobile aw-u-inline-width-100-percent-mobile-break1" class="web-select is-colored web-is-only-mobile web-u-inline-width-100-percent-mobile-break1"
style:display={nativeMobile ? undefined : 'none'} style:display={nativeMobile ? undefined : 'none'}
> >
{#if selectedOption?.icon} {#if selectedOption?.icon}
@@ -166,7 +167,7 @@
</div> </div>
<style lang="scss"> <style lang="scss">
.aw-select { .web-select {
min-width: var(--min-width, var(--p-select-min-width)); min-width: var(--min-width, var(--p-select-min-width));
} }
</style> </style>

View File

@@ -1,54 +0,0 @@
<script lang="ts">
import type { SplineViewer } from '@splinetool/viewer';
import { onMount } from 'svelte';
import { writable } from 'svelte/store';
import { fade } from 'svelte/transition';
export let url: SplineViewer['url'];
export let width: SplineViewer['width'] = undefined;
export let height: SplineViewer['height'] = undefined;
export let loading: SplineViewer['loading'] = 'auto';
let loaded = writable(false);
let spline: SplineViewer;
onMount(async () => {
await import('@splinetool/viewer');
const onLoad = () => {
const shadowRoot = spline.shadowRoot;
if (shadowRoot) {
shadowRoot.querySelector('#logo')?.remove(); // Remove Spline logo
const canvas = shadowRoot.getElementById('spline');
if (canvas) {
canvas.style.width = '100%';
canvas.style.height = '100%';
}
}
setTimeout(() => {
loaded.set(true);
}, 150);
};
spline.addEventListener('load-complete', onLoad);
});
const ENABLED = false;
</script>
{#if ENABLED}
<spline-viewer
style="position: absolute;"
{url}
{width}
{height}
{loading}
bind:this={spline}
/>
{/if}
{#if $$slots?.default && !$loaded}
<div out:fade={{ duration: 50 }}>
<slot />
</div>
{/if}

View File

@@ -53,6 +53,11 @@
href: '/docs/quick-starts/android', href: '/docs/quick-starts/android',
image: `/images/platforms/${$themeInUse}/android.svg` image: `/images/platforms/${$themeInUse}/android.svg`
}, },
{
name: 'React Native',
href: '/docs/quick-starts/react-native',
image: `/images/platforms/${$themeInUse}/react-native.svg`
},
] as Array<{ ] as Array<{
name: string; name: string;
@@ -61,11 +66,11 @@
}>; }>;
</script> </script>
<ul class="u-flex u-flex-wrap u-gap-16 aw-u-margin-block-32-mobile aw-u-margin-block-40-not-mobile"> <ul class="u-flex u-flex-wrap u-gap-16 web-u-margin-block-32-mobile web-u-margin-block-40-not-mobile">
{#each platforms as platform} {#each platforms as platform}
<Tooltip> <Tooltip>
<li> <li>
<a href={platform.href} class="aw-icon-button aw-box-icon has-border-gradient"> <a href={platform.href} class="web-icon-button web-box-icon has-border-gradient">
<img src={platform.image} alt="{platform.name} quick start" width="32" height="32" /> <img src={platform.image} alt="{platform.name} quick start" width="32" height="32" />
</a> </a>
</li> </li>

Some files were not shown because too many files have changed in this diff Show More