mirror of
https://github.com/LukeHagar/website.git
synced 2025-12-06 12:57:48 +00:00
prettier updates
This commit is contained in:
@@ -1,30 +1,30 @@
|
||||
module.exports = {
|
||||
root: true,
|
||||
extends: [
|
||||
'eslint:recommended',
|
||||
'plugin:@typescript-eslint/recommended',
|
||||
'plugin:svelte/recommended',
|
||||
'prettier'
|
||||
],
|
||||
parser: '@typescript-eslint/parser',
|
||||
plugins: ['@typescript-eslint'],
|
||||
parserOptions: {
|
||||
sourceType: 'module',
|
||||
ecmaVersion: 2020,
|
||||
extraFileExtensions: ['.svelte']
|
||||
},
|
||||
env: {
|
||||
browser: true,
|
||||
es2017: true,
|
||||
node: true
|
||||
},
|
||||
overrides: [
|
||||
{
|
||||
files: ['*.svelte'],
|
||||
parser: 'svelte-eslint-parser',
|
||||
parserOptions: {
|
||||
parser: '@typescript-eslint/parser'
|
||||
}
|
||||
}
|
||||
]
|
||||
root: true,
|
||||
extends: [
|
||||
'eslint:recommended',
|
||||
'plugin:@typescript-eslint/recommended',
|
||||
'plugin:svelte/recommended',
|
||||
'prettier'
|
||||
],
|
||||
parser: '@typescript-eslint/parser',
|
||||
plugins: ['@typescript-eslint'],
|
||||
parserOptions: {
|
||||
sourceType: 'module',
|
||||
ecmaVersion: 2020,
|
||||
extraFileExtensions: ['.svelte']
|
||||
},
|
||||
env: {
|
||||
browser: true,
|
||||
es2017: true,
|
||||
node: true
|
||||
},
|
||||
overrides: [
|
||||
{
|
||||
files: ['*.svelte'],
|
||||
parser: 'svelte-eslint-parser',
|
||||
parserOptions: {
|
||||
parser: '@typescript-eslint/parser'
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
36
.github/workflows/index.yml
vendored
36
.github/workflows/index.yml
vendored
@@ -1,23 +1,23 @@
|
||||
name: Search Index
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
|
||||
jobs:
|
||||
indexing:
|
||||
runs-on: ubuntu-latest
|
||||
name: Indexing
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
repository: 'meilisearch/scrapix'
|
||||
- name: Use Node.js
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: '20.x'
|
||||
- run: yarn
|
||||
- run: yarn start -c "$SCRAPIX_CONFIG"
|
||||
env:
|
||||
SCRAPIX_CONFIG: ${{ secrets.SCRAPIX_CONFIG }}
|
||||
indexing:
|
||||
runs-on: ubuntu-latest
|
||||
name: Indexing
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
repository: 'meilisearch/scrapix'
|
||||
- name: Use Node.js
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: '20.x'
|
||||
- run: yarn
|
||||
- run: yarn start -c "$SCRAPIX_CONFIG"
|
||||
env:
|
||||
SCRAPIX_CONFIG: ${{ secrets.SCRAPIX_CONFIG }}
|
||||
|
||||
34
.github/workflows/stale.yml
vendored
34
.github/workflows/stale.yml
vendored
@@ -1,23 +1,23 @@
|
||||
name: Mark stale issues
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: "0 0 * * *" # Midnight Runtime
|
||||
schedule:
|
||||
- cron: '0 0 * * *' # Midnight Runtime
|
||||
|
||||
jobs:
|
||||
stale:
|
||||
runs-on: ubuntu-latest
|
||||
stale:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/stale@v9
|
||||
with:
|
||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
stale-issue-message: "This issue has been labeled as a 'question', indicating that it requires additional information from the requestor. It has been inactive for 7 days. If no further activity occurs, this issue will be closed in 14 days."
|
||||
stale-issue-label: "stale"
|
||||
days-before-stale: 7
|
||||
days-before-close: 14
|
||||
remove-stale-when-updated: true
|
||||
close-issue-message: "This issue has been closed due to inactivity. If you still require assistance, please provide the requested information."
|
||||
close-issue-reason: "not_planned"
|
||||
operations-per-run: 100
|
||||
only-labels: "question"
|
||||
steps:
|
||||
- uses: actions/stale@v9
|
||||
with:
|
||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
stale-issue-message: "This issue has been labeled as a 'question', indicating that it requires additional information from the requestor. It has been inactive for 7 days. If no further activity occurs, this issue will be closed in 14 days."
|
||||
stale-issue-label: 'stale'
|
||||
days-before-stale: 7
|
||||
days-before-close: 14
|
||||
remove-stale-when-updated: true
|
||||
close-issue-message: 'This issue has been closed due to inactivity. If you still require assistance, please provide the requested information.'
|
||||
close-issue-reason: 'not_planned'
|
||||
operations-per-run: 100
|
||||
only-labels: 'question'
|
||||
|
||||
@@ -5,7 +5,5 @@
|
||||
# Learn more from ready-to-use templates: https://www.gitpod.io/docs/introduction/getting-started/quickstart
|
||||
|
||||
tasks:
|
||||
- init: pnpm install && pnpm run build
|
||||
command: pnpm run dev
|
||||
|
||||
|
||||
- init: pnpm install && pnpm run build
|
||||
command: pnpm run dev
|
||||
|
||||
30
CONTENT.md
30
CONTENT.md
@@ -49,9 +49,9 @@ Create ordered (numbered) and unordered (bulleted) lists using 1., \*, or -.
|
||||
**Unordered List**:
|
||||
|
||||
```md
|
||||
- Apple
|
||||
- Banana
|
||||
- Cherry
|
||||
- Apple
|
||||
- Banana
|
||||
- Cherry
|
||||
```
|
||||
|
||||
#### Links
|
||||
@@ -129,15 +129,20 @@ Alternatively, use markdoc tables.
|
||||
|
||||
```md
|
||||
{% table %}
|
||||
* Heading 1
|
||||
* Heading 2
|
||||
|
||||
- Heading 1
|
||||
- Heading 2
|
||||
|
||||
---
|
||||
* Row 1 Cell 1
|
||||
* Row 1 Cell 2
|
||||
|
||||
- Row 1 Cell 1
|
||||
- Row 1 Cell 2
|
||||
|
||||
---
|
||||
* Row 2 Cell 1
|
||||
* Row 2 cell 2
|
||||
{% /table %}
|
||||
|
||||
- Row 2 Cell 1
|
||||
- Row 2 cell 2
|
||||
{% /table %}
|
||||
```
|
||||
|
||||
#### Block Quotes
|
||||
@@ -186,7 +191,9 @@ print('test');
|
||||
</pre>
|
||||
|
||||
#### 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
|
||||
{% section #featured-products-1 step=1 title="Title" %}
|
||||
Lorem ipsum dolor sit amet consectetur.
|
||||
@@ -243,6 +250,7 @@ Available sizes are `s`, `m`, `l` and `xl`. Default: `s`.
|
||||
```
|
||||
|
||||
#### Cards
|
||||
|
||||
We use cards when we reference a list of links for navigation
|
||||
|
||||
```
|
||||
@@ -268,6 +276,7 @@ Get started with Appwrite and SvelteKit
|
||||
```
|
||||
|
||||
#### Cards with icons
|
||||
|
||||
We use cards when we reference a list of links for navigation, this variation has icons for extra hints visually.
|
||||
|
||||
```
|
||||
@@ -285,6 +294,7 @@ Configure FCM for push notification to Android and Apple devices.
|
||||
```
|
||||
|
||||
#### Accordions
|
||||
|
||||
Use accordions to reduce page size and collapse information that's not important when a reader is skilling the page.
|
||||
|
||||
```
|
||||
|
||||
@@ -60,11 +60,11 @@ doc-548-submit-a-pull-request-section-to-contribution-guide
|
||||
|
||||
When `TYPE` can be:
|
||||
|
||||
- **feat** - is a new feature
|
||||
- **doc** - documentation only changes
|
||||
- **cicd** - changes related to CI/CD system
|
||||
- **fix** - a bug fix
|
||||
- **refactor** - code change that neither fixes a bug nor adds a feature
|
||||
- **feat** - is a new feature
|
||||
- **doc** - documentation only changes
|
||||
- **cicd** - changes related to CI/CD system
|
||||
- **fix** - a bug fix
|
||||
- **refactor** - code change that neither fixes a bug nor adds a feature
|
||||
|
||||
**All PRs must include a commit message with a description of the changes made!**
|
||||
|
||||
|
||||
200
STYLE.md
200
STYLE.md
@@ -6,17 +6,17 @@ Read this document carefully before making PRs to the Appwrite Website repo.
|
||||
|
||||
The Appwrite documentation is meant to provide general guidance that's:
|
||||
|
||||
- Unopinionated
|
||||
- Focused on the correct use of Appwrite product
|
||||
- Includes examples for all relevant and applicable SDKs
|
||||
- Agnostic to the user's implementation and stack.
|
||||
- Unopinionated
|
||||
- Focused on the correct use of Appwrite product
|
||||
- Includes examples for all relevant and applicable SDKs
|
||||
- Agnostic to the user's implementation and stack.
|
||||
|
||||
Examples of things not fit for docs, and better as a blog or video:
|
||||
|
||||
- General programming advice
|
||||
- Opinionated implementation patterns like MVVM, factory methods, etc.
|
||||
- Examples that only include a select subset of Appwrite SDKs.
|
||||
- Examples that do not work for all developers using Appwrite, but specific to Appwrite + technology.
|
||||
- General programming advice
|
||||
- Opinionated implementation patterns like MVVM, factory methods, etc.
|
||||
- Examples that only include a select subset of Appwrite SDKs.
|
||||
- Examples that do not work for all developers using Appwrite, but specific to Appwrite + technology.
|
||||
|
||||
Note that the tutorials and blogs available on the Appwrite blog and docs are meant for these types of information.
|
||||
|
||||
@@ -28,39 +28,39 @@ Appwrite's navigation increases in complexity from top down. We expect users to
|
||||
|
||||
Introduction Section:
|
||||
|
||||
- [Homes](https://appwrite.io/docs)
|
||||
- [Quick start](https://appwrite.io/docs/quick-start)
|
||||
- [Tutorial](https://appwrite.io/docs/tutorial)
|
||||
- [SDKs](https://appwrite.io/docs/sdks)
|
||||
- [API references](https://appwrite.io/docs/references)
|
||||
- [Homes](https://appwrite.io/docs)
|
||||
- [Quick start](https://appwrite.io/docs/quick-start)
|
||||
- [Tutorial](https://appwrite.io/docs/tutorial)
|
||||
- [SDKs](https://appwrite.io/docs/sdks)
|
||||
- [API references](https://appwrite.io/docs/references)
|
||||
|
||||
Products section:
|
||||
|
||||
- [Auth](https://appwrite.io/docs/products/auth)
|
||||
- [Databases](https://appwrite.io/docs/products/databases)
|
||||
- [Functions](https://appwrite.io/docs/products/functions)
|
||||
- [Storage](https://appwrite.io/docs/products/storage)
|
||||
- [Messaging](https://appwrite.io/docs/products/messaging)
|
||||
- [AI](https://appwrite.io/docs/products/ai)
|
||||
- [Auth](https://appwrite.io/docs/products/auth)
|
||||
- [Databases](https://appwrite.io/docs/products/databases)
|
||||
- [Functions](https://appwrite.io/docs/products/functions)
|
||||
- [Storage](https://appwrite.io/docs/products/storage)
|
||||
- [Messaging](https://appwrite.io/docs/products/messaging)
|
||||
- [AI](https://appwrite.io/docs/products/ai)
|
||||
|
||||
APIs section:
|
||||
|
||||
- [GraphQL](https://appwrite.io/docs/apis/graphql)
|
||||
- [REST](https://appwrite.io/docs/apis/rest)
|
||||
- [Realtime](https://appwrite.io/docs/apis/realtime)
|
||||
- [GraphQL](https://appwrite.io/docs/apis/graphql)
|
||||
- [REST](https://appwrite.io/docs/apis/rest)
|
||||
- [Realtime](https://appwrite.io/docs/apis/realtime)
|
||||
|
||||
Tooling section:
|
||||
|
||||
- [Command Line](https://appwrite.io/docs/command-line)
|
||||
- [Command center](https://appwrite.io/docs/tooling/command-center)
|
||||
- [Assistant](https://appwrite.io/docs/tooling/assistant)
|
||||
- [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)
|
||||
- [Platform](https://appwrite.io/docs/advanced/platform)
|
||||
- [Migrations](https://appwrite.io/docs/advanced/migrations)
|
||||
- [Self-hosting](https://appwrite.io/docs/advanced/self-hosting)
|
||||
- [Security](https://appwrite.io/docs/advanced/security)
|
||||
|
||||
Here's the intended purpose and structure of each section.
|
||||
|
||||
@@ -70,10 +70,10 @@ This section is focused on introducing what Appwrite is and giving examples to t
|
||||
Documentation here is focused on a **single flow** which means a single platform/framework + Appwrite.
|
||||
Content here is not specific to a specific product, but usually covers multiple Appwrite products.
|
||||
|
||||
- If your tutorial can be followed in about 15 minutes and fits on one page, write it under quick start
|
||||
- If you're writing a long piece of documentation that integrates Appwrite with another technology, with lots of details that's opinionated or isn't relevant for all use cases, write it under tutorial. This is similar to "cook book" at other organizations.
|
||||
- If you have information like helpers and methods that are only on SDKs but not the API, they go under SDK
|
||||
- API references are generated from source from the appwrite/appwrite repo
|
||||
- If your tutorial can be followed in about 15 minutes and fits on one page, write it under quick start
|
||||
- If you're writing a long piece of documentation that integrates Appwrite with another technology, with lots of details that's opinionated or isn't relevant for all use cases, write it under tutorial. This is similar to "cook book" at other organizations.
|
||||
- If you have information like helpers and methods that are only on SDKs but not the API, they go under SDK
|
||||
- API references are generated from source from the appwrite/appwrite repo
|
||||
|
||||
### Products
|
||||
|
||||
@@ -82,17 +82,17 @@ Code examples should cover **all available SDKs**.
|
||||
|
||||
Each product page has three main sections
|
||||
|
||||
- Introduction
|
||||
- Overview - Describes at a high level, why you might need this product
|
||||
- Quick start - Shows the most basic and quickest example to make something happen with a product. Keep it really short.
|
||||
- Concept
|
||||
- These pages usually align with sections shown in the product in the Appwrite Console.
|
||||
- Focused on describing concepts a user should know, but not actions you might take.
|
||||
- Cover all the details
|
||||
- Journeys
|
||||
- These pages focus on common actions and work flows
|
||||
- Detailed examples that span many concepts
|
||||
- Like cookbook at other organizations' documentation.
|
||||
- Introduction
|
||||
- Overview - Describes at a high level, why you might need this product
|
||||
- Quick start - Shows the most basic and quickest example to make something happen with a product. Keep it really short.
|
||||
- Concept
|
||||
- These pages usually align with sections shown in the product in the Appwrite Console.
|
||||
- Focused on describing concepts a user should know, but not actions you might take.
|
||||
- Cover all the details
|
||||
- Journeys
|
||||
- These pages focus on common actions and work flows
|
||||
- Detailed examples that span many concepts
|
||||
- Like cookbook at other organizations' documentation.
|
||||
|
||||
### APIs section
|
||||
|
||||
@@ -106,10 +106,10 @@ Describes tools that help you work with Appwrite, but are usually non-essential
|
||||
|
||||
For information that's not used commonly during the development cycle.
|
||||
|
||||
- Platform: covers concepts that apply to the entire Appwrite Cloud platform, like API keys, rate limits, etc.
|
||||
- Migrations: covers migrations feature of Appwrite that helps you move data around.
|
||||
- Security: purely information about measures Appwrite use to ensure security of the platform and data.
|
||||
- Self-hosting: The Appwrite self-hosted platform is meant to behave identically to Cloud after being configured corrrectly. This section focuses on how to configure Appwrite self-hosted such that it behaves like Cloud.
|
||||
- Platform: covers concepts that apply to the entire Appwrite Cloud platform, like API keys, rate limits, etc.
|
||||
- Migrations: covers migrations feature of Appwrite that helps you move data around.
|
||||
- Security: purely information about measures Appwrite use to ensure security of the platform and data.
|
||||
- Self-hosting: The Appwrite self-hosted platform is meant to behave identically to Cloud after being configured corrrectly. This section focuses on how to configure Appwrite self-hosted such that it behaves like Cloud.
|
||||
|
||||
## Documentation sources
|
||||
|
||||
@@ -117,22 +117,22 @@ The Appwrite docs are compiled from different repositories. Here are the signifi
|
||||
|
||||
[appwrite/website](https://github.com/appwrite/website):
|
||||
|
||||
- Tutorials
|
||||
- Quick starts
|
||||
- Product, API, Tooling and Advanced sections
|
||||
- Tutorials
|
||||
- Quick starts
|
||||
- Product, API, Tooling and Advanced sections
|
||||
|
||||
[appwrite/appwrite](https://github.com/appwrite/appwrite):
|
||||
|
||||
- [API Reference](https://appwrite.io/docs/references) pages
|
||||
- API specification
|
||||
- API description
|
||||
- API endpoint description
|
||||
- API request parameters
|
||||
- API response model
|
||||
- [API Reference](https://appwrite.io/docs/references) pages
|
||||
- API specification
|
||||
- API description
|
||||
- API endpoint description
|
||||
- API request parameters
|
||||
- API response model
|
||||
|
||||
[appwrite/sdk-generator](https://github.com/appwrite/sdk-generator):
|
||||
|
||||
- Generated examples
|
||||
- Generated examples
|
||||
|
||||
## Markdown Style guidelines
|
||||
|
||||
@@ -141,10 +141,10 @@ the tone and voice remains consistent.
|
||||
|
||||
### Headings
|
||||
|
||||
- All titles, headings, buttons, and labels should be written in **sentence case**. If you're not sure what sentence case should look like, check [APA's style guide](https://apastyle.apa.org/style-grammar-guidelines/capitalization/sentence-case) or check with ChatGPT and other LLMs which reliably converts titles to sentence case.
|
||||
- All headings in a docs page begin with `# Heading` then `## Heading` and `### Heading`. Internally, they're converted to H2 to H4 tags.
|
||||
- All headings should have an ID label, for example `# Cool heading {% #cool-heading %}` the `#cool-heading` ID will be used to generate the table of contents and add links to the heading.
|
||||
- Prefer verbs over gerunds, for example, say "Create documents" not "Creating documents".
|
||||
- All titles, headings, buttons, and labels should be written in **sentence case**. If you're not sure what sentence case should look like, check [APA's style guide](https://apastyle.apa.org/style-grammar-guidelines/capitalization/sentence-case) or check with ChatGPT and other LLMs which reliably converts titles to sentence case.
|
||||
- All headings in a docs page begin with `# Heading` then `## Heading` and `### Heading`. Internally, they're converted to H2 to H4 tags.
|
||||
- All headings should have an ID label, for example `# Cool heading {% #cool-heading %}` the `#cool-heading` ID will be used to generate the table of contents and add links to the heading.
|
||||
- Prefer verbs over gerunds, for example, say "Create documents" not "Creating documents".
|
||||
|
||||
### Extended Markdoc components
|
||||
|
||||
@@ -152,14 +152,14 @@ Appwrite's documentation uses extended markdown syntax. You can find all of the
|
||||
|
||||
### Screenshots
|
||||
|
||||
- When contributing upload original screenshots. The Appwrite design team will edit the screenshot to be consistent with other screenshots in the docs.
|
||||
- Screenshots must be 16:9
|
||||
- Screnshots should be taken in a 1400 x 900 view port on 3x DPR in browser developer tools.
|
||||
- Use generic and sensible organization, project, and resource names. Avoid names like `test`, `demo`, or `sdlkfj`.
|
||||
- All screenshot should be take from a user named Walter O'Brien. You can change the name of your current user by going to your Appwrite Console and clicking the **top right profile icon** > **Your Account** > **Name**.
|
||||
- Screenshots are stored in the `/images/docs/` folder, in a parent folder that is consistent with the path of the docs that reference the image.
|
||||
- All screenshots must be both dark and light mode, with `/path/` holding the lightmode version and `/path/dark/` holding the dark mode version.
|
||||
- Screenshots should be uploaded as un-edited original. Request help from the Appwrite design team to help you edit and refine your photos according to our guidelines.
|
||||
- When contributing upload original screenshots. The Appwrite design team will edit the screenshot to be consistent with other screenshots in the docs.
|
||||
- Screenshots must be 16:9
|
||||
- Screnshots should be taken in a 1400 x 900 view port on 3x DPR in browser developer tools.
|
||||
- Use generic and sensible organization, project, and resource names. Avoid names like `test`, `demo`, or `sdlkfj`.
|
||||
- All screenshot should be take from a user named Walter O'Brien. You can change the name of your current user by going to your Appwrite Console and clicking the **top right profile icon** > **Your Account** > **Name**.
|
||||
- Screenshots are stored in the `/images/docs/` folder, in a parent folder that is consistent with the path of the docs that reference the image.
|
||||
- All screenshots must be both dark and light mode, with `/path/` holding the lightmode version and `/path/dark/` holding the dark mode version.
|
||||
- Screenshots should be uploaded as un-edited original. Request help from the Appwrite design team to help you edit and refine your photos according to our guidelines.
|
||||
|
||||
```md
|
||||
{% only_dark %}
|
||||
@@ -180,17 +180,23 @@ It should contain all the pages and headings with in them, maintainers may reque
|
||||
|
||||
```md
|
||||
# page 1
|
||||
|
||||
## heading a
|
||||
## heading b
|
||||
...
|
||||
|
||||
# page 2
|
||||
|
||||
## heading a
|
||||
## heading b
|
||||
...
|
||||
|
||||
# page 3
|
||||
|
||||
## heading a
|
||||
## heading b
|
||||
...
|
||||
|
||||
...
|
||||
```
|
||||
|
||||
@@ -204,41 +210,41 @@ Split content such that each piece makes sense without reading dependents or exp
|
||||
|
||||
### Release prep
|
||||
|
||||
- [ ] Add new version to [src/lib/utils/references.ts](src/lib/utils/references.ts)
|
||||
- [ ] Point Cloud to new version in [src/routes/docs/references/[version]/[platform]/[service]/+page.server.ts](src/routes/docs/references/[version]/[platform]/[service]/+page.server.ts)
|
||||
- [ ] Update install command in [/workspaces/website/src/routes/docs/advanced/self-hosting/+page.markdoc](/workspaces/website/src/routes/docs/advanced/self-hosting/+page.markdoc)
|
||||
- [ ] Update events [src/partials/[product]-events.md](src/partials/)
|
||||
- [ ] Update response code [src/routes/docs/advanced/platform/response-codes/+page.markdoc](src/routes/docs/advanced/platform/response-codes/+page.markdoc)
|
||||
- [ ] Bump latest SDK versions in SDKs page, quick start, and tutorials
|
||||
- [ ] Create new sections for new products
|
||||
- [ ] Create new concept and journey pages for new features
|
||||
- [ ] Update docs for breaking changes
|
||||
- [ ] Add new version to [src/lib/utils/references.ts](src/lib/utils/references.ts)
|
||||
- [ ] Point Cloud to new version in [src/routes/docs/references/[version]/[platform]/[service]/+page.server.ts](src/routes/docs/references/[version]/[platform]/[service]/+page.server.ts)
|
||||
- [ ] Update install command in [/workspaces/website/src/routes/docs/advanced/self-hosting/+page.markdoc](/workspaces/website/src/routes/docs/advanced/self-hosting/+page.markdoc)
|
||||
- [ ] Update events [src/partials/[product]-events.md](src/partials/)
|
||||
- [ ] Update response code [src/routes/docs/advanced/platform/response-codes/+page.markdoc](src/routes/docs/advanced/platform/response-codes/+page.markdoc)
|
||||
- [ ] Bump latest SDK versions in SDKs page, quick start, and tutorials
|
||||
- [ ] Create new sections for new products
|
||||
- [ ] Create new concept and journey pages for new features
|
||||
- [ ] Update docs for breaking changes
|
||||
|
||||
### Documenting a new API
|
||||
|
||||
- Add a new .md file describing the new API here: <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
|
||||
- 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
|
||||
- Copy a quick start from the [src/routes/docs/quick-starts](src/routes/docs/quick-starts) folder.
|
||||
- Add a new entry and logo to [src/routes/docs/quick-starts/+page.svelte](src/routes/docs/quick-starts/+page.svelte)
|
||||
- If you need a new logo, contact the Appwrite team to add one to Pink design.
|
||||
- Update the content of your tutorial. Remember to update the front matter!
|
||||
- Try to be consistent in both the quickstart's content and format when compared to existing quick starts
|
||||
- Add the quick start to the footer and front page of Appwrite
|
||||
- Use sections for steps on your page
|
||||
|
||||
### Adding a new tutorial
|
||||
|
||||
- Copy a tutorial from the [src/routes/docs/tutorials](src/routes/docs/tutorials) folder.
|
||||
- Update the `+page.ts`'s redirect, for example, the Android tutorial has this: [src/routes/docs/tutorials/android/+page.ts](src/routes/docs/tutorials/android/+page.ts)
|
||||
- Update [src/routes/docs/tutorials/+page.svelte](src/routes/docs/tutorials/+page.svelte) and add your new tutorial
|
||||
- Update [src/routes/docs/tutorials/android/+layout.ts](src/routes/docs/tutorials/android/+layout.ts) and add your new tutorial
|
||||
- Add the content of your tutorial. Keep pages short, separated by a different distinct feature for each step.
|
||||
- If you need a new logo, contact the Appwrite team to add one to Pink design.
|
||||
- Add the tutorial to the footer and front page of Appwrite
|
||||
- Copy a tutorial from the [src/routes/docs/tutorials](src/routes/docs/tutorials) folder.
|
||||
- Update the `+page.ts`'s redirect, for example, the Android tutorial has this: [src/routes/docs/tutorials/android/+page.ts](src/routes/docs/tutorials/android/+page.ts)
|
||||
- Update [src/routes/docs/tutorials/+page.svelte](src/routes/docs/tutorials/+page.svelte) and add your new tutorial
|
||||
- Update [src/routes/docs/tutorials/android/+layout.ts](src/routes/docs/tutorials/android/+layout.ts) and add your new tutorial
|
||||
- Add the content of your tutorial. Keep pages short, separated by a different distinct feature for each step.
|
||||
- If you need a new logo, contact the Appwrite team to add one to Pink design.
|
||||
- Add the tutorial to the footer and front page of Appwrite
|
||||
|
||||
## Language and diction
|
||||
|
||||
@@ -283,9 +289,11 @@ 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**.
|
||||
|
||||
@@ -1,58 +1,58 @@
|
||||
services:
|
||||
traefik:
|
||||
image: traefik:2.9
|
||||
command:
|
||||
- --log.level=DEBUG
|
||||
- --api.insecure=true
|
||||
- --providers.docker=true
|
||||
- --providers.docker.exposedByDefault=false
|
||||
- --entrypoints.web.address=:80
|
||||
- --entrypoints.websecure.address=:443
|
||||
- --providers.docker.constraints=Label(`traefik.constraint-label-stack`,`homepage`)
|
||||
- --accesslog=true
|
||||
labels:
|
||||
- traefik.http.routers.traefik.middlewares=traefik-compress
|
||||
- traefik.http.middlewares.traefik-compress.compress=true
|
||||
ports:
|
||||
- 80:80
|
||||
- 8080:8080
|
||||
volumes:
|
||||
# - /letsencrypt:/letsencrypt
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
networks:
|
||||
- homepage
|
||||
traefik:
|
||||
image: traefik:2.9
|
||||
command:
|
||||
- --log.level=DEBUG
|
||||
- --api.insecure=true
|
||||
- --providers.docker=true
|
||||
- --providers.docker.exposedByDefault=false
|
||||
- --entrypoints.web.address=:80
|
||||
- --entrypoints.websecure.address=:443
|
||||
- --providers.docker.constraints=Label(`traefik.constraint-label-stack`,`homepage`)
|
||||
- --accesslog=true
|
||||
labels:
|
||||
- traefik.http.routers.traefik.middlewares=traefik-compress
|
||||
- traefik.http.middlewares.traefik-compress.compress=true
|
||||
ports:
|
||||
- 80:80
|
||||
- 8080:8080
|
||||
volumes:
|
||||
# - /letsencrypt:/letsencrypt
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
networks:
|
||||
- homepage
|
||||
|
||||
homepage:
|
||||
image: homepage-dev
|
||||
build:
|
||||
context: .
|
||||
args:
|
||||
- PUBLIC_APPWRITE_PROJECT_INIT_ID=$PUBLIC_APPWRITE_PROJECT_INIT_ID
|
||||
- PUBLIC_APPWRITE_PROJECT_ID=$PUBLIC_APPWRITE_PROJECT_ID
|
||||
- PUBLIC_APPWRITE_DB_MAIN_ID=$PUBLIC_APPWRITE_DB_MAIN_ID
|
||||
- PUBLIC_APPWRITE_COL_THREADS_ID=$PUBLIC_APPWRITE_COL_THREADS_ID
|
||||
- PUBLIC_APPWRITE_COL_MESSAGES_ID=$PUBLIC_APPWRITE_COL_MESSAGES_ID
|
||||
- PUBLIC_APPWRITE_FN_TLDR_ID=$PUBLIC_APPWRITE_FN_TLDR_ID
|
||||
restart: always
|
||||
networks:
|
||||
- homepage
|
||||
labels:
|
||||
- traefik.enable=true
|
||||
- traefik.constraint-label-stack=homepage
|
||||
- traefik.docker.network=appwrite
|
||||
- traefik.http.middlewares.appwrite_middlewares.compress=true
|
||||
- traefik.http.services.appwrite_service.loadbalancer.server.port=3000
|
||||
#http
|
||||
- traefik.http.routers.appwrite.entrypoints=web
|
||||
- traefik.http.routers.appwrite.rule=PathPrefix(`/`)
|
||||
- traefik.http.routers.appwrite.service=appwrite_service
|
||||
- traefik.http.routers.appwrite.middlewares=appwrite_middlewares
|
||||
# https
|
||||
- traefik.http.routers.appwrite_secure.entrypoints=websecure
|
||||
- traefik.http.routers.appwrite_secure.rule=PathPrefix(`/`)
|
||||
- traefik.http.routers.appwrite_secure.service=appwrite_service
|
||||
- traefik.http.routers.appwrite_secure.tls=true
|
||||
- traefik.http.routers.appwrite_secure.middlewares=appwrite_middlewares
|
||||
homepage:
|
||||
image: homepage-dev
|
||||
build:
|
||||
context: .
|
||||
args:
|
||||
- PUBLIC_APPWRITE_PROJECT_INIT_ID=$PUBLIC_APPWRITE_PROJECT_INIT_ID
|
||||
- PUBLIC_APPWRITE_PROJECT_ID=$PUBLIC_APPWRITE_PROJECT_ID
|
||||
- PUBLIC_APPWRITE_DB_MAIN_ID=$PUBLIC_APPWRITE_DB_MAIN_ID
|
||||
- PUBLIC_APPWRITE_COL_THREADS_ID=$PUBLIC_APPWRITE_COL_THREADS_ID
|
||||
- PUBLIC_APPWRITE_COL_MESSAGES_ID=$PUBLIC_APPWRITE_COL_MESSAGES_ID
|
||||
- PUBLIC_APPWRITE_FN_TLDR_ID=$PUBLIC_APPWRITE_FN_TLDR_ID
|
||||
restart: always
|
||||
networks:
|
||||
- homepage
|
||||
labels:
|
||||
- traefik.enable=true
|
||||
- traefik.constraint-label-stack=homepage
|
||||
- traefik.docker.network=appwrite
|
||||
- traefik.http.middlewares.appwrite_middlewares.compress=true
|
||||
- traefik.http.services.appwrite_service.loadbalancer.server.port=3000
|
||||
#http
|
||||
- traefik.http.routers.appwrite.entrypoints=web
|
||||
- traefik.http.routers.appwrite.rule=PathPrefix(`/`)
|
||||
- traefik.http.routers.appwrite.service=appwrite_service
|
||||
- traefik.http.routers.appwrite.middlewares=appwrite_middlewares
|
||||
# https
|
||||
- traefik.http.routers.appwrite_secure.entrypoints=websecure
|
||||
- traefik.http.routers.appwrite_secure.rule=PathPrefix(`/`)
|
||||
- traefik.http.routers.appwrite_secure.service=appwrite_service
|
||||
- traefik.http.routers.appwrite_secure.tls=true
|
||||
- traefik.http.routers.appwrite_secure.middlewares=appwrite_middlewares
|
||||
|
||||
networks:
|
||||
homepage:
|
||||
homepage:
|
||||
|
||||
@@ -1,135 +1,135 @@
|
||||
x-logging: &x-logging
|
||||
logging:
|
||||
driver: 'json-file'
|
||||
options:
|
||||
max-file: '5'
|
||||
max-size: '20m'
|
||||
logging:
|
||||
driver: 'json-file'
|
||||
options:
|
||||
max-file: '5'
|
||||
max-size: '20m'
|
||||
|
||||
x-update-config: &x-update-config
|
||||
update_config:
|
||||
order: stop-first
|
||||
failure_action: rollback
|
||||
parallelism: 1
|
||||
delay: 10s
|
||||
rollback_config:
|
||||
failure_action: pause
|
||||
monitor: 5s
|
||||
parallelism: 2
|
||||
order: stop-first
|
||||
update_config:
|
||||
order: stop-first
|
||||
failure_action: rollback
|
||||
parallelism: 1
|
||||
delay: 10s
|
||||
rollback_config:
|
||||
failure_action: pause
|
||||
monitor: 5s
|
||||
parallelism: 2
|
||||
order: stop-first
|
||||
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
traefik:
|
||||
image: traefik:2.9
|
||||
<<: *x-logging
|
||||
command:
|
||||
- --log.level=DEBUG
|
||||
- --api.insecure=false
|
||||
- --providers.docker=true
|
||||
- --providers.docker.watch=true
|
||||
- --providers.docker.swarmMode=true
|
||||
- --providers.docker.exposedByDefault=false
|
||||
- --entrypoints.web.address=:80
|
||||
- --entrypoints.websecure.address=:443
|
||||
- --entrypoints.web.http.redirections.entrypoint.to=websecure
|
||||
- --entrypoints.web.http.redirections.entrypoint.scheme=https
|
||||
- --providers.docker.constraints=Label(`traefik.constraint-label-stack`,`appwrite`)
|
||||
- --certificatesresolvers.myresolver.acme.httpchallenge=true
|
||||
- --certificatesresolvers.myresolver.acme.httpchallenge.entrypoint=web
|
||||
- --certificatesresolvers.myresolver.acme.email=$_APP_SYSTEM_SECURITY_EMAIL_ADDRESS
|
||||
- --certificatesresolvers.myresolver.acme.storage=/letsencrypt/${_APP_DOMAIN}.json
|
||||
- --accesslog=true
|
||||
ports:
|
||||
- 80:80
|
||||
- 443:443
|
||||
volumes:
|
||||
- /letsencrypt:/letsencrypt
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
networks:
|
||||
- cloud
|
||||
deploy:
|
||||
replicas: 3
|
||||
<<: *x-update-config
|
||||
placement:
|
||||
max_replicas_per_node: 1
|
||||
constraints:
|
||||
- node.role == manager
|
||||
preferences:
|
||||
- spread: node.role == worker
|
||||
labels:
|
||||
- traefik.http.routers.traefik.middlewares=traefik-compress
|
||||
- traefik.http.middlewares.traefik-compress.compress=true
|
||||
traefik:
|
||||
image: traefik:2.9
|
||||
<<: *x-logging
|
||||
command:
|
||||
- --log.level=DEBUG
|
||||
- --api.insecure=false
|
||||
- --providers.docker=true
|
||||
- --providers.docker.watch=true
|
||||
- --providers.docker.swarmMode=true
|
||||
- --providers.docker.exposedByDefault=false
|
||||
- --entrypoints.web.address=:80
|
||||
- --entrypoints.websecure.address=:443
|
||||
- --entrypoints.web.http.redirections.entrypoint.to=websecure
|
||||
- --entrypoints.web.http.redirections.entrypoint.scheme=https
|
||||
- --providers.docker.constraints=Label(`traefik.constraint-label-stack`,`appwrite`)
|
||||
- --certificatesresolvers.myresolver.acme.httpchallenge=true
|
||||
- --certificatesresolvers.myresolver.acme.httpchallenge.entrypoint=web
|
||||
- --certificatesresolvers.myresolver.acme.email=$_APP_SYSTEM_SECURITY_EMAIL_ADDRESS
|
||||
- --certificatesresolvers.myresolver.acme.storage=/letsencrypt/${_APP_DOMAIN}.json
|
||||
- --accesslog=true
|
||||
ports:
|
||||
- 80:80
|
||||
- 443:443
|
||||
volumes:
|
||||
- /letsencrypt:/letsencrypt
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
networks:
|
||||
- cloud
|
||||
deploy:
|
||||
replicas: 3
|
||||
<<: *x-update-config
|
||||
placement:
|
||||
max_replicas_per_node: 1
|
||||
constraints:
|
||||
- node.role == manager
|
||||
preferences:
|
||||
- spread: node.role == worker
|
||||
labels:
|
||||
- traefik.http.routers.traefik.middlewares=traefik-compress
|
||||
- traefik.http.middlewares.traefik-compress.compress=true
|
||||
|
||||
server:
|
||||
image: ghcr.io/appwrite/website:$_APP_VERSION
|
||||
<<: *x-logging
|
||||
networks:
|
||||
- cloud
|
||||
environment:
|
||||
- PUBLIC_APPWRITE_PROJECT_INIT_ID
|
||||
- PUBLIC_APPWRITE_PROJECT_ID
|
||||
- PUBLIC_APPWRITE_DB_MAIN_ID
|
||||
- PUBLIC_APPWRITE_COL_THREADS_ID
|
||||
- PUBLIC_APPWRITE_COL_MESSAGES_ID
|
||||
- PUBLIC_APPWRITE_FN_TLDR_ID
|
||||
deploy:
|
||||
<<: *x-update-config
|
||||
mode: replicated
|
||||
replicas: 8
|
||||
placement:
|
||||
max_replicas_per_node: 2
|
||||
constraints:
|
||||
- node.role == worker
|
||||
preferences:
|
||||
- spread: node.role == worker
|
||||
labels:
|
||||
- traefik.enable=true
|
||||
- traefik.docker.lbswarm=true
|
||||
- traefik.constraint-label-stack=appwrite
|
||||
- traefik.http.services.appwrite_service.loadbalancer.server.port=3000
|
||||
- traefik.http.middlewares.appwrite_middlewares.compress=true
|
||||
#http
|
||||
- traefik.http.routers.appwrite.entrypoints=web
|
||||
- traefik.http.routers.appwrite.rule=Host(`$_APP_DOMAIN`) || Host(`www.$_APP_DOMAIN`)
|
||||
- traefik.http.routers.appwrite.service=appwrite_service
|
||||
- traefik.http.routers.appwrite.middlewares=appwrite_middlewares
|
||||
# https
|
||||
- traefik.http.routers.appwrite_secure.entrypoints=websecure
|
||||
- traefik.http.routers.appwrite_secure.rule=Host(`$_APP_DOMAIN`) || Host(`www.$_APP_DOMAIN`)
|
||||
- traefik.http.routers.appwrite_secure.service=appwrite_service
|
||||
- traefik.http.routers.appwrite_secure.tls=true
|
||||
- traefik.http.routers.appwrite_secure.tls.certresolver=myresolver
|
||||
- traefik.http.routers.appwrite_secure.middlewares=appwrite_middlewares
|
||||
server:
|
||||
image: ghcr.io/appwrite/website:$_APP_VERSION
|
||||
<<: *x-logging
|
||||
networks:
|
||||
- cloud
|
||||
environment:
|
||||
- PUBLIC_APPWRITE_PROJECT_INIT_ID
|
||||
- PUBLIC_APPWRITE_PROJECT_ID
|
||||
- PUBLIC_APPWRITE_DB_MAIN_ID
|
||||
- PUBLIC_APPWRITE_COL_THREADS_ID
|
||||
- PUBLIC_APPWRITE_COL_MESSAGES_ID
|
||||
- PUBLIC_APPWRITE_FN_TLDR_ID
|
||||
deploy:
|
||||
<<: *x-update-config
|
||||
mode: replicated
|
||||
replicas: 8
|
||||
placement:
|
||||
max_replicas_per_node: 2
|
||||
constraints:
|
||||
- node.role == worker
|
||||
preferences:
|
||||
- spread: node.role == worker
|
||||
labels:
|
||||
- traefik.enable=true
|
||||
- traefik.docker.lbswarm=true
|
||||
- traefik.constraint-label-stack=appwrite
|
||||
- traefik.http.services.appwrite_service.loadbalancer.server.port=3000
|
||||
- traefik.http.middlewares.appwrite_middlewares.compress=true
|
||||
#http
|
||||
- traefik.http.routers.appwrite.entrypoints=web
|
||||
- traefik.http.routers.appwrite.rule=Host(`$_APP_DOMAIN`) || Host(`www.$_APP_DOMAIN`)
|
||||
- traefik.http.routers.appwrite.service=appwrite_service
|
||||
- traefik.http.routers.appwrite.middlewares=appwrite_middlewares
|
||||
# https
|
||||
- traefik.http.routers.appwrite_secure.entrypoints=websecure
|
||||
- traefik.http.routers.appwrite_secure.rule=Host(`$_APP_DOMAIN`) || Host(`www.$_APP_DOMAIN`)
|
||||
- traefik.http.routers.appwrite_secure.service=appwrite_service
|
||||
- traefik.http.routers.appwrite_secure.tls=true
|
||||
- traefik.http.routers.appwrite_secure.tls.certresolver=myresolver
|
||||
- traefik.http.routers.appwrite_secure.middlewares=appwrite_middlewares
|
||||
|
||||
janitor:
|
||||
image: appwrite/docker-janitor
|
||||
deploy:
|
||||
mode: global
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
environment:
|
||||
- TIME_BETWEEN_RUNS=3600
|
||||
- UNUSED_TIME=6h
|
||||
janitor:
|
||||
image: appwrite/docker-janitor
|
||||
deploy:
|
||||
mode: global
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
environment:
|
||||
- TIME_BETWEEN_RUNS=3600
|
||||
- UNUSED_TIME=6h
|
||||
|
||||
sematext-agent:
|
||||
image: sematext/agent:latest
|
||||
environment:
|
||||
REGION: EU
|
||||
INFRA_TOKEN: $SEMATEXT_TOKEN
|
||||
deploy:
|
||||
mode: global
|
||||
restart_policy:
|
||||
condition: any
|
||||
volumes:
|
||||
- /:/hostfs:ro
|
||||
- /etc/passwd:/etc/passwd:ro
|
||||
- /etc/group:/etc/group:ro
|
||||
- /sys:/host/sys:ro
|
||||
- /dev:/hostfs/dev:ro
|
||||
- /var/run:/var/run
|
||||
- /sys/kernel/debug:/sys/kernel/debug
|
||||
sematext-agent:
|
||||
image: sematext/agent:latest
|
||||
environment:
|
||||
REGION: EU
|
||||
INFRA_TOKEN: $SEMATEXT_TOKEN
|
||||
deploy:
|
||||
mode: global
|
||||
restart_policy:
|
||||
condition: any
|
||||
volumes:
|
||||
- /:/hostfs:ro
|
||||
- /etc/passwd:/etc/passwd:ro
|
||||
- /etc/group:/etc/group:ro
|
||||
- /sys:/host/sys:ro
|
||||
- /dev:/hostfs/dev:ro
|
||||
- /var/run:/var/run
|
||||
- /sys/kernel/debug:/sys/kernel/debug
|
||||
|
||||
networks:
|
||||
cloud:
|
||||
driver: overlay
|
||||
cloud:
|
||||
driver: overlay
|
||||
|
||||
250
docker/stage.yml
250
docker/stage.yml
@@ -1,137 +1,137 @@
|
||||
x-logging: &x-logging
|
||||
logging:
|
||||
driver: 'json-file'
|
||||
options:
|
||||
max-file: '5'
|
||||
max-size: '20m'
|
||||
logging:
|
||||
driver: 'json-file'
|
||||
options:
|
||||
max-file: '5'
|
||||
max-size: '20m'
|
||||
|
||||
x-update-config: &x-update-config
|
||||
update_config:
|
||||
order: stop-first
|
||||
failure_action: rollback
|
||||
parallelism: 1
|
||||
delay: 10s
|
||||
rollback_config:
|
||||
failure_action: pause
|
||||
monitor: 5s
|
||||
parallelism: 2
|
||||
order: stop-first
|
||||
update_config:
|
||||
order: stop-first
|
||||
failure_action: rollback
|
||||
parallelism: 1
|
||||
delay: 10s
|
||||
rollback_config:
|
||||
failure_action: pause
|
||||
monitor: 5s
|
||||
parallelism: 2
|
||||
order: stop-first
|
||||
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
traefik:
|
||||
image: traefik:2.9
|
||||
<<: *x-logging
|
||||
command:
|
||||
- --log.level=DEBUG
|
||||
- --api.insecure=true
|
||||
- --providers.docker=true
|
||||
- --providers.docker.watch=true
|
||||
- --providers.docker.swarmMode=true
|
||||
- --providers.docker.exposedByDefault=false
|
||||
- --entrypoints.web.address=:80
|
||||
- --entrypoints.websecure.address=:443
|
||||
- --entrypoints.web.http.redirections.entrypoint.to=websecure
|
||||
- --entrypoints.web.http.redirections.entrypoint.scheme=https
|
||||
- --providers.docker.constraints=Label(`traefik.constraint-label-stack`,`appwrite`)
|
||||
- --certificatesresolvers.myresolver.acme.httpchallenge=true
|
||||
- --certificatesresolvers.myresolver.acme.httpchallenge.entrypoint=web
|
||||
- --certificatesresolvers.myresolver.acme.email=$_APP_SYSTEM_SECURITY_EMAIL_ADDRESS
|
||||
- --certificatesresolvers.myresolver.acme.storage=/letsencrypt/${_APP_DOMAIN}.json
|
||||
- --accesslog=true
|
||||
ports:
|
||||
- 80:80
|
||||
- 443:443
|
||||
- 8080:8080
|
||||
volumes:
|
||||
- /letsencrypt:/letsencrypt
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
networks:
|
||||
- cloud
|
||||
deploy:
|
||||
replicas: 3
|
||||
<<: *x-update-config
|
||||
placement:
|
||||
max_replicas_per_node: 1
|
||||
constraints:
|
||||
- node.role == manager
|
||||
preferences:
|
||||
- spread: node.role == worker
|
||||
labels:
|
||||
- traefik.http.routers.traefik.middlewares=traefik-compress
|
||||
- traefik.http.middlewares.traefik-compress.compress=true
|
||||
traefik:
|
||||
image: traefik:2.9
|
||||
<<: *x-logging
|
||||
command:
|
||||
- --log.level=DEBUG
|
||||
- --api.insecure=true
|
||||
- --providers.docker=true
|
||||
- --providers.docker.watch=true
|
||||
- --providers.docker.swarmMode=true
|
||||
- --providers.docker.exposedByDefault=false
|
||||
- --entrypoints.web.address=:80
|
||||
- --entrypoints.websecure.address=:443
|
||||
- --entrypoints.web.http.redirections.entrypoint.to=websecure
|
||||
- --entrypoints.web.http.redirections.entrypoint.scheme=https
|
||||
- --providers.docker.constraints=Label(`traefik.constraint-label-stack`,`appwrite`)
|
||||
- --certificatesresolvers.myresolver.acme.httpchallenge=true
|
||||
- --certificatesresolvers.myresolver.acme.httpchallenge.entrypoint=web
|
||||
- --certificatesresolvers.myresolver.acme.email=$_APP_SYSTEM_SECURITY_EMAIL_ADDRESS
|
||||
- --certificatesresolvers.myresolver.acme.storage=/letsencrypt/${_APP_DOMAIN}.json
|
||||
- --accesslog=true
|
||||
ports:
|
||||
- 80:80
|
||||
- 443:443
|
||||
- 8080:8080
|
||||
volumes:
|
||||
- /letsencrypt:/letsencrypt
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
networks:
|
||||
- cloud
|
||||
deploy:
|
||||
replicas: 3
|
||||
<<: *x-update-config
|
||||
placement:
|
||||
max_replicas_per_node: 1
|
||||
constraints:
|
||||
- node.role == manager
|
||||
preferences:
|
||||
- spread: node.role == worker
|
||||
labels:
|
||||
- traefik.http.routers.traefik.middlewares=traefik-compress
|
||||
- traefik.http.middlewares.traefik-compress.compress=true
|
||||
|
||||
server:
|
||||
image: ghcr.io/appwrite/website:$_APP_VERSION
|
||||
<<: *x-logging
|
||||
networks:
|
||||
- cloud
|
||||
environment:
|
||||
- PUBLIC_APPWRITE_PROJECT_INIT_ID
|
||||
- PUBLIC_APPWRITE_PROJECT_ID
|
||||
- PUBLIC_APPWRITE_DB_MAIN_ID
|
||||
- PUBLIC_APPWRITE_COL_THREADS_ID
|
||||
- PUBLIC_APPWRITE_COL_MESSAGES_ID
|
||||
- PUBLIC_APPWRITE_FN_TLDR_ID
|
||||
deploy:
|
||||
<<: *x-update-config
|
||||
mode: replicated
|
||||
replicas: 8
|
||||
placement:
|
||||
max_replicas_per_node: 2
|
||||
constraints:
|
||||
- node.role == worker
|
||||
preferences:
|
||||
- spread: node.role == worker
|
||||
labels:
|
||||
- traefik.enable=true
|
||||
- traefik.docker.lbswarm=true
|
||||
- traefik.constraint-label-stack=appwrite
|
||||
- traefik.http.services.appwrite_service.loadbalancer.server.port=3000
|
||||
- traefik.http.middlewares.appwrite_middlewares.compress=true
|
||||
#http
|
||||
- traefik.http.routers.appwrite.entrypoints=web
|
||||
- traefik.http.routers.appwrite.rule=Host(`$_APP_DOMAIN`) || Host(`www.$_APP_DOMAIN`)
|
||||
- traefik.http.routers.appwrite.service=appwrite_service
|
||||
- traefik.http.routers.appwrite.middlewares=appwrite_middlewares
|
||||
# https
|
||||
- traefik.http.routers.appwrite_secure.entrypoints=websecure
|
||||
- traefik.http.routers.appwrite_secure.rule=Host(`$_APP_DOMAIN`) || Host(`www.$_APP_DOMAIN`)
|
||||
- traefik.http.routers.appwrite_secure.service=appwrite_service
|
||||
- traefik.http.routers.appwrite_secure.tls=true
|
||||
- traefik.http.routers.appwrite_secure.tls.certresolver=myresolver
|
||||
- traefik.http.routers.appwrite_secure.middlewares=appwrite_middlewares
|
||||
server:
|
||||
image: ghcr.io/appwrite/website:$_APP_VERSION
|
||||
<<: *x-logging
|
||||
networks:
|
||||
- cloud
|
||||
environment:
|
||||
- PUBLIC_APPWRITE_PROJECT_INIT_ID
|
||||
- PUBLIC_APPWRITE_PROJECT_ID
|
||||
- PUBLIC_APPWRITE_DB_MAIN_ID
|
||||
- PUBLIC_APPWRITE_COL_THREADS_ID
|
||||
- PUBLIC_APPWRITE_COL_MESSAGES_ID
|
||||
- PUBLIC_APPWRITE_FN_TLDR_ID
|
||||
deploy:
|
||||
<<: *x-update-config
|
||||
mode: replicated
|
||||
replicas: 8
|
||||
placement:
|
||||
max_replicas_per_node: 2
|
||||
constraints:
|
||||
- node.role == worker
|
||||
preferences:
|
||||
- spread: node.role == worker
|
||||
labels:
|
||||
- traefik.enable=true
|
||||
- traefik.docker.lbswarm=true
|
||||
- traefik.constraint-label-stack=appwrite
|
||||
- traefik.http.services.appwrite_service.loadbalancer.server.port=3000
|
||||
- traefik.http.middlewares.appwrite_middlewares.compress=true
|
||||
#http
|
||||
- traefik.http.routers.appwrite.entrypoints=web
|
||||
- traefik.http.routers.appwrite.rule=Host(`$_APP_DOMAIN`) || Host(`www.$_APP_DOMAIN`)
|
||||
- traefik.http.routers.appwrite.service=appwrite_service
|
||||
- traefik.http.routers.appwrite.middlewares=appwrite_middlewares
|
||||
# https
|
||||
- traefik.http.routers.appwrite_secure.entrypoints=websecure
|
||||
- traefik.http.routers.appwrite_secure.rule=Host(`$_APP_DOMAIN`) || Host(`www.$_APP_DOMAIN`)
|
||||
- traefik.http.routers.appwrite_secure.service=appwrite_service
|
||||
- traefik.http.routers.appwrite_secure.tls=true
|
||||
- traefik.http.routers.appwrite_secure.tls.certresolver=myresolver
|
||||
- traefik.http.routers.appwrite_secure.middlewares=appwrite_middlewares
|
||||
|
||||
janitor:
|
||||
image: appwrite/docker-janitor
|
||||
deploy:
|
||||
mode: global
|
||||
environment:
|
||||
- TIME_BETWEEN_RUNS=600
|
||||
- UNUSED_TIME=10m
|
||||
- RUN_ON_STARTUP=true
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
janitor:
|
||||
image: appwrite/docker-janitor
|
||||
deploy:
|
||||
mode: global
|
||||
environment:
|
||||
- TIME_BETWEEN_RUNS=600
|
||||
- UNUSED_TIME=10m
|
||||
- RUN_ON_STARTUP=true
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
|
||||
sematext-agent:
|
||||
image: sematext/agent:latest
|
||||
environment:
|
||||
REGION: EU
|
||||
INFRA_TOKEN: $SEMATEXT_TOKEN
|
||||
deploy:
|
||||
mode: global
|
||||
restart_policy:
|
||||
condition: any
|
||||
volumes:
|
||||
- /:/hostfs:ro
|
||||
- /etc/passwd:/etc/passwd:ro
|
||||
- /etc/group:/etc/group:ro
|
||||
- /sys:/host/sys:ro
|
||||
- /dev:/hostfs/dev:ro
|
||||
- /var/run:/var/run
|
||||
- /sys/kernel/debug:/sys/kernel/debug
|
||||
sematext-agent:
|
||||
image: sematext/agent:latest
|
||||
environment:
|
||||
REGION: EU
|
||||
INFRA_TOKEN: $SEMATEXT_TOKEN
|
||||
deploy:
|
||||
mode: global
|
||||
restart_policy:
|
||||
condition: any
|
||||
volumes:
|
||||
- /:/hostfs:ro
|
||||
- /etc/passwd:/etc/passwd:ro
|
||||
- /etc/group:/etc/group:ro
|
||||
- /sys:/host/sys:ro
|
||||
- /dev:/hostfs/dev:ro
|
||||
- /var/run:/var/run
|
||||
- /sys/kernel/debug:/sys/kernel/debug
|
||||
|
||||
networks:
|
||||
cloud:
|
||||
driver: overlay
|
||||
cloud:
|
||||
driver: overlay
|
||||
|
||||
@@ -57,7 +57,7 @@
|
||||
"openapi-types": "^12.1.3",
|
||||
"oslllo-svg-fixer": "^3.0.0",
|
||||
"postcss": "^8.4.39",
|
||||
"prettier": "^3.3.2",
|
||||
"prettier": "^3.3.3",
|
||||
"prettier-plugin-svelte": "^3.2.5",
|
||||
"prettier-plugin-tailwindcss": "^0.6.5",
|
||||
"sass": "^1.77.6",
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import type { PlaywrightTestConfig } from '@playwright/test';
|
||||
|
||||
const config: PlaywrightTestConfig = {
|
||||
webServer: {
|
||||
command: 'npm run build && npm run preview',
|
||||
port: 4173
|
||||
},
|
||||
testDir: 'tests',
|
||||
testMatch: /(.+\.)?(test|spec)\.[jt]s/
|
||||
webServer: {
|
||||
command: 'npm run build && npm run preview',
|
||||
port: 4173
|
||||
},
|
||||
testDir: 'tests',
|
||||
testMatch: /(.+\.)?(test|spec)\.[jt]s/
|
||||
};
|
||||
|
||||
export default config;
|
||||
|
||||
24
pnpm-lock.yaml
generated
24
pnpm-lock.yaml
generated
@@ -109,14 +109,14 @@ importers:
|
||||
specifier: ^8.4.39
|
||||
version: 8.4.39
|
||||
prettier:
|
||||
specifier: ^3.3.2
|
||||
version: 3.3.2
|
||||
specifier: ^3.3.3
|
||||
version: 3.3.3
|
||||
prettier-plugin-svelte:
|
||||
specifier: ^3.2.5
|
||||
version: 3.2.5(prettier@3.3.2)(svelte@4.2.18)
|
||||
version: 3.2.5(prettier@3.3.3)(svelte@4.2.18)
|
||||
prettier-plugin-tailwindcss:
|
||||
specifier: ^0.6.5
|
||||
version: 0.6.5(prettier-plugin-svelte@3.2.5(prettier@3.3.2)(svelte@4.2.18))(prettier@3.3.2)
|
||||
version: 0.6.5(prettier-plugin-svelte@3.2.5(prettier@3.3.3)(svelte@4.2.18))(prettier@3.3.3)
|
||||
sass:
|
||||
specifier: ^1.77.6
|
||||
version: 1.77.6
|
||||
@@ -3388,8 +3388,8 @@ packages:
|
||||
prettier-plugin-svelte:
|
||||
optional: true
|
||||
|
||||
prettier@3.3.2:
|
||||
resolution: {integrity: sha512-rAVeHYMcv8ATV5d508CFdn+8/pHPpXeIid1DdrPwXnaAdH7cqjVbpJaT5eq4yRAFU/lsbwYwSF/n5iNrdJHPQA==}
|
||||
prettier@3.3.3:
|
||||
resolution: {integrity: sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew==}
|
||||
engines: {node: '>=14'}
|
||||
hasBin: true
|
||||
|
||||
@@ -7552,18 +7552,18 @@ snapshots:
|
||||
|
||||
prelude-ls@1.2.1: {}
|
||||
|
||||
prettier-plugin-svelte@3.2.5(prettier@3.3.2)(svelte@4.2.18):
|
||||
prettier-plugin-svelte@3.2.5(prettier@3.3.3)(svelte@4.2.18):
|
||||
dependencies:
|
||||
prettier: 3.3.2
|
||||
prettier: 3.3.3
|
||||
svelte: 4.2.18
|
||||
|
||||
prettier-plugin-tailwindcss@0.6.5(prettier-plugin-svelte@3.2.5(prettier@3.3.2)(svelte@4.2.18))(prettier@3.3.2):
|
||||
prettier-plugin-tailwindcss@0.6.5(prettier-plugin-svelte@3.2.5(prettier@3.3.3)(svelte@4.2.18))(prettier@3.3.3):
|
||||
dependencies:
|
||||
prettier: 3.3.2
|
||||
prettier: 3.3.3
|
||||
optionalDependencies:
|
||||
prettier-plugin-svelte: 3.2.5(prettier@3.3.2)(svelte@4.2.18)
|
||||
prettier-plugin-svelte: 3.2.5(prettier@3.3.3)(svelte@4.2.18)
|
||||
|
||||
prettier@3.3.2: {}
|
||||
prettier@3.3.3: {}
|
||||
|
||||
pretty-format@29.7.0:
|
||||
dependencies:
|
||||
|
||||
@@ -4,11 +4,13 @@ const perPage = 100;
|
||||
|
||||
const outputFile = `./src/lib/contributors.ts`;
|
||||
|
||||
const headers = process.env.GITHUB_TOKEN ? {
|
||||
Authorization: `token ${process.env.GITHUB_TOKEN}`
|
||||
} : {}
|
||||
const headers = process.env.GITHUB_TOKEN
|
||||
? {
|
||||
Authorization: `token ${process.env.GITHUB_TOKEN}`
|
||||
}
|
||||
: {};
|
||||
|
||||
console.log(`using github token: ${!!process.env.GITHUB_TOKEN}`)
|
||||
console.log(`using github token: ${!!process.env.GITHUB_TOKEN}`);
|
||||
|
||||
async function fetchRepositories() {
|
||||
let page = 1;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<!DOCTYPE html>
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
@@ -24,7 +24,7 @@
|
||||
if (isDocs) {
|
||||
const theme = localStorage.getItem('theme');
|
||||
if (theme) {
|
||||
document.body.classList.remove('theme-dark', 'theme-light');
|
||||
document.body.classList.remove('theme-dark', 'light');
|
||||
if (theme === 'system') {
|
||||
const systemTheme = window.matchMedia('(prefers-color-scheme: dark)')
|
||||
.matches
|
||||
|
||||
@@ -18,11 +18,13 @@ Sentry.init({
|
||||
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,
|
||||
})]
|
||||
integrations: [
|
||||
replayIntegration({
|
||||
maskAllInputs: true,
|
||||
maskAllText: false,
|
||||
blockAllMedia: false
|
||||
})
|
||||
]
|
||||
});
|
||||
|
||||
// If you have a custom error handler, pass it to `handleErrorWithSentry`
|
||||
|
||||
@@ -10,7 +10,7 @@ Sentry.init({
|
||||
dsn: SENTRY_DSN,
|
||||
tracesSampleRate: 1,
|
||||
allowUrls: [/appwrite\.io/]
|
||||
})
|
||||
});
|
||||
|
||||
const redirectMap = new Map(redirects.map(({ link, redirect }) => [link, redirect]));
|
||||
|
||||
@@ -36,4 +36,4 @@ const bannerRewriter: Handle = async ({ event, resolve }) => {
|
||||
};
|
||||
|
||||
export const handle = sequence(Sentry.sentryHandle(), redirecter, bannerRewriter);
|
||||
export const handleError = Sentry.handleErrorWithSentry();
|
||||
export const handleError = Sentry.handleErrorWithSentry();
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
import { generateIcons } from "./scripts.js";
|
||||
import { generateIcons } from './scripts.js';
|
||||
|
||||
generateIcons();
|
||||
generateIcons();
|
||||
|
||||
@@ -1,302 +1,302 @@
|
||||
{
|
||||
"apple": {
|
||||
"encodedCode": "\\ea01",
|
||||
"prefix": "web-icon",
|
||||
"className": "web-icon-apple",
|
||||
"unicode": ""
|
||||
},
|
||||
"appwrite": {
|
||||
"encodedCode": "\\ea02",
|
||||
"prefix": "web-icon",
|
||||
"className": "web-icon-appwrite",
|
||||
"unicode": ""
|
||||
},
|
||||
"arrow-down": {
|
||||
"encodedCode": "\\ea03",
|
||||
"prefix": "web-icon",
|
||||
"className": "web-icon-arrow-down",
|
||||
"unicode": ""
|
||||
},
|
||||
"arrow-ext-link": {
|
||||
"encodedCode": "\\ea04",
|
||||
"prefix": "web-icon",
|
||||
"className": "web-icon-arrow-ext-link",
|
||||
"unicode": ""
|
||||
},
|
||||
"arrow-left": {
|
||||
"encodedCode": "\\ea05",
|
||||
"prefix": "web-icon",
|
||||
"className": "web-icon-arrow-left",
|
||||
"unicode": ""
|
||||
},
|
||||
"arrow-right": {
|
||||
"encodedCode": "\\ea06",
|
||||
"prefix": "web-icon",
|
||||
"className": "web-icon-arrow-right",
|
||||
"unicode": ""
|
||||
},
|
||||
"arrow-up": {
|
||||
"encodedCode": "\\ea07",
|
||||
"prefix": "web-icon",
|
||||
"className": "web-icon-arrow-up",
|
||||
"unicode": ""
|
||||
},
|
||||
"calendar": {
|
||||
"encodedCode": "\\ea08",
|
||||
"prefix": "web-icon",
|
||||
"className": "web-icon-calendar",
|
||||
"unicode": ""
|
||||
},
|
||||
"check": {
|
||||
"encodedCode": "\\ea09",
|
||||
"prefix": "web-icon",
|
||||
"className": "web-icon-check",
|
||||
"unicode": ""
|
||||
},
|
||||
"chevron-down": {
|
||||
"encodedCode": "\\ea0a",
|
||||
"prefix": "web-icon",
|
||||
"className": "web-icon-chevron-down",
|
||||
"unicode": ""
|
||||
},
|
||||
"chevron-left": {
|
||||
"encodedCode": "\\ea0b",
|
||||
"prefix": "web-icon",
|
||||
"className": "web-icon-chevron-left",
|
||||
"unicode": ""
|
||||
},
|
||||
"chevron-right": {
|
||||
"encodedCode": "\\ea0c",
|
||||
"prefix": "web-icon",
|
||||
"className": "web-icon-chevron-right",
|
||||
"unicode": ""
|
||||
},
|
||||
"chevron-up": {
|
||||
"encodedCode": "\\ea0d",
|
||||
"prefix": "web-icon",
|
||||
"className": "web-icon-chevron-up",
|
||||
"unicode": ""
|
||||
},
|
||||
"close": {
|
||||
"encodedCode": "\\ea0e",
|
||||
"prefix": "web-icon",
|
||||
"className": "web-icon-close",
|
||||
"unicode": ""
|
||||
},
|
||||
"command": {
|
||||
"encodedCode": "\\ea0f",
|
||||
"prefix": "web-icon",
|
||||
"className": "web-icon-command",
|
||||
"unicode": ""
|
||||
},
|
||||
"copy": {
|
||||
"encodedCode": "\\ea10",
|
||||
"prefix": "web-icon",
|
||||
"className": "web-icon-copy",
|
||||
"unicode": ""
|
||||
},
|
||||
"dark": {
|
||||
"encodedCode": "\\ea11",
|
||||
"prefix": "web-icon",
|
||||
"className": "web-icon-dark",
|
||||
"unicode": ""
|
||||
},
|
||||
"discord": {
|
||||
"encodedCode": "\\ea12",
|
||||
"prefix": "web-icon",
|
||||
"className": "web-icon-discord",
|
||||
"unicode": ""
|
||||
},
|
||||
"divider-vertical": {
|
||||
"encodedCode": "\\ea13",
|
||||
"prefix": "web-icon",
|
||||
"className": "web-icon-divider-vertical",
|
||||
"unicode": ""
|
||||
},
|
||||
"download": {
|
||||
"encodedCode": "\\ea14",
|
||||
"prefix": "web-icon",
|
||||
"className": "web-icon-download",
|
||||
"unicode": ""
|
||||
},
|
||||
"ext-link": {
|
||||
"encodedCode": "\\ea15",
|
||||
"prefix": "web-icon",
|
||||
"className": "web-icon-ext-link",
|
||||
"unicode": ""
|
||||
},
|
||||
"firebase": {
|
||||
"encodedCode": "\\ea16",
|
||||
"prefix": "web-icon",
|
||||
"className": "web-icon-firebase",
|
||||
"unicode": ""
|
||||
},
|
||||
"github": {
|
||||
"encodedCode": "\\ea17",
|
||||
"prefix": "web-icon",
|
||||
"className": "web-icon-github",
|
||||
"unicode": ""
|
||||
},
|
||||
"google": {
|
||||
"encodedCode": "\\ea18",
|
||||
"prefix": "web-icon",
|
||||
"className": "web-icon-google",
|
||||
"unicode": ""
|
||||
},
|
||||
"hamburger-menu": {
|
||||
"encodedCode": "\\ea19",
|
||||
"prefix": "web-icon",
|
||||
"className": "web-icon-hamburger-menu",
|
||||
"unicode": ""
|
||||
},
|
||||
"light": {
|
||||
"encodedCode": "\\ea1a",
|
||||
"prefix": "web-icon",
|
||||
"className": "web-icon-light",
|
||||
"unicode": ""
|
||||
},
|
||||
"linkedin": {
|
||||
"encodedCode": "\\ea1b",
|
||||
"prefix": "web-icon",
|
||||
"className": "web-icon-linkedin",
|
||||
"unicode": ""
|
||||
},
|
||||
"location": {
|
||||
"encodedCode": "\\ea1c",
|
||||
"prefix": "web-icon",
|
||||
"className": "web-icon-location",
|
||||
"unicode": ""
|
||||
},
|
||||
"logout-left": {
|
||||
"encodedCode": "\\ea1d",
|
||||
"prefix": "web-icon",
|
||||
"className": "web-icon-logout-left",
|
||||
"unicode": ""
|
||||
},
|
||||
"logout-right": {
|
||||
"encodedCode": "\\ea1e",
|
||||
"prefix": "web-icon",
|
||||
"className": "web-icon-logout-right",
|
||||
"unicode": ""
|
||||
},
|
||||
"mailgun": {
|
||||
"encodedCode": "\\ea1f",
|
||||
"prefix": "web-icon",
|
||||
"className": "web-icon-mailgun",
|
||||
"unicode": ""
|
||||
},
|
||||
"message": {
|
||||
"encodedCode": "\\ea20",
|
||||
"prefix": "web-icon",
|
||||
"className": "web-icon-message",
|
||||
"unicode": ""
|
||||
},
|
||||
"microsoft": {
|
||||
"encodedCode": "\\ea21",
|
||||
"prefix": "web-icon",
|
||||
"className": "web-icon-microsoft",
|
||||
"unicode": ""
|
||||
},
|
||||
"minus": {
|
||||
"encodedCode": "\\ea22",
|
||||
"prefix": "web-icon",
|
||||
"className": "web-icon-minus",
|
||||
"unicode": ""
|
||||
},
|
||||
"nuxt": {
|
||||
"encodedCode": "\\ea23",
|
||||
"prefix": "web-icon",
|
||||
"className": "web-icon-nuxt",
|
||||
"unicode": ""
|
||||
},
|
||||
"platform": {
|
||||
"encodedCode": "\\ea24",
|
||||
"prefix": "web-icon",
|
||||
"className": "web-icon-platform",
|
||||
"unicode": ""
|
||||
},
|
||||
"play": {
|
||||
"encodedCode": "\\ea25",
|
||||
"prefix": "web-icon",
|
||||
"className": "web-icon-play",
|
||||
"unicode": ""
|
||||
},
|
||||
"plus": {
|
||||
"encodedCode": "\\ea26",
|
||||
"prefix": "web-icon",
|
||||
"className": "web-icon-plus",
|
||||
"unicode": ""
|
||||
},
|
||||
"product-hunt": {
|
||||
"encodedCode": "\\ea27",
|
||||
"prefix": "web-icon",
|
||||
"className": "web-icon-product-hunt",
|
||||
"unicode": ""
|
||||
},
|
||||
"refine": {
|
||||
"encodedCode": "\\ea28",
|
||||
"prefix": "web-icon",
|
||||
"className": "web-icon-refine",
|
||||
"unicode": ""
|
||||
},
|
||||
"rest": {
|
||||
"encodedCode": "\\ea29",
|
||||
"prefix": "web-icon",
|
||||
"className": "web-icon-rest",
|
||||
"unicode": ""
|
||||
},
|
||||
"search": {
|
||||
"encodedCode": "\\ea2a",
|
||||
"prefix": "web-icon",
|
||||
"className": "web-icon-search",
|
||||
"unicode": ""
|
||||
},
|
||||
"sendgrid": {
|
||||
"encodedCode": "\\ea2b",
|
||||
"prefix": "web-icon",
|
||||
"className": "web-icon-sendgrid",
|
||||
"unicode": ""
|
||||
},
|
||||
"star": {
|
||||
"encodedCode": "\\ea2c",
|
||||
"prefix": "web-icon",
|
||||
"className": "web-icon-star",
|
||||
"unicode": ""
|
||||
},
|
||||
"system": {
|
||||
"encodedCode": "\\ea2d",
|
||||
"prefix": "web-icon",
|
||||
"className": "web-icon-system",
|
||||
"unicode": ""
|
||||
},
|
||||
"textmagic": {
|
||||
"encodedCode": "\\ea2e",
|
||||
"prefix": "web-icon",
|
||||
"className": "web-icon-textmagic",
|
||||
"unicode": ""
|
||||
},
|
||||
"twitter": {
|
||||
"encodedCode": "\\ea2f",
|
||||
"prefix": "web-icon",
|
||||
"className": "web-icon-twitter",
|
||||
"unicode": ""
|
||||
},
|
||||
"vue": {
|
||||
"encodedCode": "\\ea30",
|
||||
"prefix": "web-icon",
|
||||
"className": "web-icon-vue",
|
||||
"unicode": ""
|
||||
},
|
||||
"x": {
|
||||
"encodedCode": "\\ea31",
|
||||
"prefix": "web-icon",
|
||||
"className": "web-icon-x",
|
||||
"unicode": ""
|
||||
},
|
||||
"youtube": {
|
||||
"encodedCode": "\\ea32",
|
||||
"prefix": "web-icon",
|
||||
"className": "web-icon-youtube",
|
||||
"unicode": ""
|
||||
}
|
||||
"apple": {
|
||||
"encodedCode": "\\ea01",
|
||||
"prefix": "web-icon",
|
||||
"className": "web-icon-apple",
|
||||
"unicode": ""
|
||||
},
|
||||
"appwrite": {
|
||||
"encodedCode": "\\ea02",
|
||||
"prefix": "web-icon",
|
||||
"className": "web-icon-appwrite",
|
||||
"unicode": ""
|
||||
},
|
||||
"arrow-down": {
|
||||
"encodedCode": "\\ea03",
|
||||
"prefix": "web-icon",
|
||||
"className": "web-icon-arrow-down",
|
||||
"unicode": ""
|
||||
},
|
||||
"arrow-ext-link": {
|
||||
"encodedCode": "\\ea04",
|
||||
"prefix": "web-icon",
|
||||
"className": "web-icon-arrow-ext-link",
|
||||
"unicode": ""
|
||||
},
|
||||
"arrow-left": {
|
||||
"encodedCode": "\\ea05",
|
||||
"prefix": "web-icon",
|
||||
"className": "web-icon-arrow-left",
|
||||
"unicode": ""
|
||||
},
|
||||
"arrow-right": {
|
||||
"encodedCode": "\\ea06",
|
||||
"prefix": "web-icon",
|
||||
"className": "web-icon-arrow-right",
|
||||
"unicode": ""
|
||||
},
|
||||
"arrow-up": {
|
||||
"encodedCode": "\\ea07",
|
||||
"prefix": "web-icon",
|
||||
"className": "web-icon-arrow-up",
|
||||
"unicode": ""
|
||||
},
|
||||
"calendar": {
|
||||
"encodedCode": "\\ea08",
|
||||
"prefix": "web-icon",
|
||||
"className": "web-icon-calendar",
|
||||
"unicode": ""
|
||||
},
|
||||
"check": {
|
||||
"encodedCode": "\\ea09",
|
||||
"prefix": "web-icon",
|
||||
"className": "web-icon-check",
|
||||
"unicode": ""
|
||||
},
|
||||
"chevron-down": {
|
||||
"encodedCode": "\\ea0a",
|
||||
"prefix": "web-icon",
|
||||
"className": "web-icon-chevron-down",
|
||||
"unicode": ""
|
||||
},
|
||||
"chevron-left": {
|
||||
"encodedCode": "\\ea0b",
|
||||
"prefix": "web-icon",
|
||||
"className": "web-icon-chevron-left",
|
||||
"unicode": ""
|
||||
},
|
||||
"chevron-right": {
|
||||
"encodedCode": "\\ea0c",
|
||||
"prefix": "web-icon",
|
||||
"className": "web-icon-chevron-right",
|
||||
"unicode": ""
|
||||
},
|
||||
"chevron-up": {
|
||||
"encodedCode": "\\ea0d",
|
||||
"prefix": "web-icon",
|
||||
"className": "web-icon-chevron-up",
|
||||
"unicode": ""
|
||||
},
|
||||
"close": {
|
||||
"encodedCode": "\\ea0e",
|
||||
"prefix": "web-icon",
|
||||
"className": "web-icon-close",
|
||||
"unicode": ""
|
||||
},
|
||||
"command": {
|
||||
"encodedCode": "\\ea0f",
|
||||
"prefix": "web-icon",
|
||||
"className": "web-icon-command",
|
||||
"unicode": ""
|
||||
},
|
||||
"copy": {
|
||||
"encodedCode": "\\ea10",
|
||||
"prefix": "web-icon",
|
||||
"className": "web-icon-copy",
|
||||
"unicode": ""
|
||||
},
|
||||
"dark": {
|
||||
"encodedCode": "\\ea11",
|
||||
"prefix": "web-icon",
|
||||
"className": "web-icon-dark",
|
||||
"unicode": ""
|
||||
},
|
||||
"discord": {
|
||||
"encodedCode": "\\ea12",
|
||||
"prefix": "web-icon",
|
||||
"className": "web-icon-discord",
|
||||
"unicode": ""
|
||||
},
|
||||
"divider-vertical": {
|
||||
"encodedCode": "\\ea13",
|
||||
"prefix": "web-icon",
|
||||
"className": "web-icon-divider-vertical",
|
||||
"unicode": ""
|
||||
},
|
||||
"download": {
|
||||
"encodedCode": "\\ea14",
|
||||
"prefix": "web-icon",
|
||||
"className": "web-icon-download",
|
||||
"unicode": ""
|
||||
},
|
||||
"ext-link": {
|
||||
"encodedCode": "\\ea15",
|
||||
"prefix": "web-icon",
|
||||
"className": "web-icon-ext-link",
|
||||
"unicode": ""
|
||||
},
|
||||
"firebase": {
|
||||
"encodedCode": "\\ea16",
|
||||
"prefix": "web-icon",
|
||||
"className": "web-icon-firebase",
|
||||
"unicode": ""
|
||||
},
|
||||
"github": {
|
||||
"encodedCode": "\\ea17",
|
||||
"prefix": "web-icon",
|
||||
"className": "web-icon-github",
|
||||
"unicode": ""
|
||||
},
|
||||
"google": {
|
||||
"encodedCode": "\\ea18",
|
||||
"prefix": "web-icon",
|
||||
"className": "web-icon-google",
|
||||
"unicode": ""
|
||||
},
|
||||
"hamburger-menu": {
|
||||
"encodedCode": "\\ea19",
|
||||
"prefix": "web-icon",
|
||||
"className": "web-icon-hamburger-menu",
|
||||
"unicode": ""
|
||||
},
|
||||
"light": {
|
||||
"encodedCode": "\\ea1a",
|
||||
"prefix": "web-icon",
|
||||
"className": "web-icon-light",
|
||||
"unicode": ""
|
||||
},
|
||||
"linkedin": {
|
||||
"encodedCode": "\\ea1b",
|
||||
"prefix": "web-icon",
|
||||
"className": "web-icon-linkedin",
|
||||
"unicode": ""
|
||||
},
|
||||
"location": {
|
||||
"encodedCode": "\\ea1c",
|
||||
"prefix": "web-icon",
|
||||
"className": "web-icon-location",
|
||||
"unicode": ""
|
||||
},
|
||||
"logout-left": {
|
||||
"encodedCode": "\\ea1d",
|
||||
"prefix": "web-icon",
|
||||
"className": "web-icon-logout-left",
|
||||
"unicode": ""
|
||||
},
|
||||
"logout-right": {
|
||||
"encodedCode": "\\ea1e",
|
||||
"prefix": "web-icon",
|
||||
"className": "web-icon-logout-right",
|
||||
"unicode": ""
|
||||
},
|
||||
"mailgun": {
|
||||
"encodedCode": "\\ea1f",
|
||||
"prefix": "web-icon",
|
||||
"className": "web-icon-mailgun",
|
||||
"unicode": ""
|
||||
},
|
||||
"message": {
|
||||
"encodedCode": "\\ea20",
|
||||
"prefix": "web-icon",
|
||||
"className": "web-icon-message",
|
||||
"unicode": ""
|
||||
},
|
||||
"microsoft": {
|
||||
"encodedCode": "\\ea21",
|
||||
"prefix": "web-icon",
|
||||
"className": "web-icon-microsoft",
|
||||
"unicode": ""
|
||||
},
|
||||
"minus": {
|
||||
"encodedCode": "\\ea22",
|
||||
"prefix": "web-icon",
|
||||
"className": "web-icon-minus",
|
||||
"unicode": ""
|
||||
},
|
||||
"nuxt": {
|
||||
"encodedCode": "\\ea23",
|
||||
"prefix": "web-icon",
|
||||
"className": "web-icon-nuxt",
|
||||
"unicode": ""
|
||||
},
|
||||
"platform": {
|
||||
"encodedCode": "\\ea24",
|
||||
"prefix": "web-icon",
|
||||
"className": "web-icon-platform",
|
||||
"unicode": ""
|
||||
},
|
||||
"play": {
|
||||
"encodedCode": "\\ea25",
|
||||
"prefix": "web-icon",
|
||||
"className": "web-icon-play",
|
||||
"unicode": ""
|
||||
},
|
||||
"plus": {
|
||||
"encodedCode": "\\ea26",
|
||||
"prefix": "web-icon",
|
||||
"className": "web-icon-plus",
|
||||
"unicode": ""
|
||||
},
|
||||
"product-hunt": {
|
||||
"encodedCode": "\\ea27",
|
||||
"prefix": "web-icon",
|
||||
"className": "web-icon-product-hunt",
|
||||
"unicode": ""
|
||||
},
|
||||
"refine": {
|
||||
"encodedCode": "\\ea28",
|
||||
"prefix": "web-icon",
|
||||
"className": "web-icon-refine",
|
||||
"unicode": ""
|
||||
},
|
||||
"rest": {
|
||||
"encodedCode": "\\ea29",
|
||||
"prefix": "web-icon",
|
||||
"className": "web-icon-rest",
|
||||
"unicode": ""
|
||||
},
|
||||
"search": {
|
||||
"encodedCode": "\\ea2a",
|
||||
"prefix": "web-icon",
|
||||
"className": "web-icon-search",
|
||||
"unicode": ""
|
||||
},
|
||||
"sendgrid": {
|
||||
"encodedCode": "\\ea2b",
|
||||
"prefix": "web-icon",
|
||||
"className": "web-icon-sendgrid",
|
||||
"unicode": ""
|
||||
},
|
||||
"star": {
|
||||
"encodedCode": "\\ea2c",
|
||||
"prefix": "web-icon",
|
||||
"className": "web-icon-star",
|
||||
"unicode": ""
|
||||
},
|
||||
"system": {
|
||||
"encodedCode": "\\ea2d",
|
||||
"prefix": "web-icon",
|
||||
"className": "web-icon-system",
|
||||
"unicode": ""
|
||||
},
|
||||
"textmagic": {
|
||||
"encodedCode": "\\ea2e",
|
||||
"prefix": "web-icon",
|
||||
"className": "web-icon-textmagic",
|
||||
"unicode": ""
|
||||
},
|
||||
"twitter": {
|
||||
"encodedCode": "\\ea2f",
|
||||
"prefix": "web-icon",
|
||||
"className": "web-icon-twitter",
|
||||
"unicode": ""
|
||||
},
|
||||
"vue": {
|
||||
"encodedCode": "\\ea30",
|
||||
"prefix": "web-icon",
|
||||
"className": "web-icon-vue",
|
||||
"unicode": ""
|
||||
},
|
||||
"x": {
|
||||
"encodedCode": "\\ea31",
|
||||
"prefix": "web-icon",
|
||||
"className": "web-icon-x",
|
||||
"unicode": ""
|
||||
},
|
||||
"youtube": {
|
||||
"encodedCode": "\\ea32",
|
||||
"prefix": "web-icon",
|
||||
"className": "web-icon-youtube",
|
||||
"unicode": ""
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,15 +1,18 @@
|
||||
@font-face {
|
||||
font-family: "web-icon";
|
||||
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- */
|
||||
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-"] {
|
||||
[class^='web-icon-'],
|
||||
[class*=' web-icon-'] {
|
||||
font-family: 'web-icon' !important;
|
||||
font-size: 20px;
|
||||
font-style: normal;
|
||||
@@ -17,53 +20,153 @@
|
||||
-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: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';
|
||||
}
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
<script lang="ts">
|
||||
import { melt } from '@melt-ui/svelte';
|
||||
import { getTabsContext } from './index.svelte';
|
||||
import { melt } from '@melt-ui/svelte';
|
||||
import { getTabsContext } from './index.svelte';
|
||||
|
||||
export let tab: string;
|
||||
export let tab: string;
|
||||
|
||||
const {
|
||||
elements: { content }
|
||||
} = getTabsContext();
|
||||
const {
|
||||
elements: { content }
|
||||
} = getTabsContext();
|
||||
</script>
|
||||
|
||||
<div use:melt={$content(tab)}>
|
||||
<slot />
|
||||
<slot />
|
||||
</div>
|
||||
|
||||
@@ -1,45 +1,45 @@
|
||||
<script lang="ts" context="module">
|
||||
const CTX_KEY = 'tabs';
|
||||
const CTX_KEY = 'tabs';
|
||||
|
||||
type Context = Tabs & {
|
||||
tabs: readonly string[];
|
||||
};
|
||||
type Context = Tabs & {
|
||||
tabs: readonly string[];
|
||||
};
|
||||
|
||||
const setTabsContext = (ctx: Context) => {
|
||||
setContext(CTX_KEY, ctx);
|
||||
};
|
||||
const setTabsContext = (ctx: Context) => {
|
||||
setContext(CTX_KEY, ctx);
|
||||
};
|
||||
|
||||
export const getTabsContext = () => {
|
||||
return getContext<Context>(CTX_KEY);
|
||||
};
|
||||
export const getTabsContext = () => {
|
||||
return getContext<Context>(CTX_KEY);
|
||||
};
|
||||
</script>
|
||||
|
||||
<script lang="ts">
|
||||
import { createTabs, melt, type Tabs } from '@melt-ui/svelte';
|
||||
import { getContext, setContext } from 'svelte';
|
||||
import List from './List.svelte';
|
||||
import Content from './Content.svelte';
|
||||
import { createTabs, melt, type Tabs } from '@melt-ui/svelte';
|
||||
import { getContext, setContext } from 'svelte';
|
||||
import List from './List.svelte';
|
||||
import Content from './Content.svelte';
|
||||
|
||||
export let tabs: Context['tabs'];
|
||||
export let tab = tabs[0];
|
||||
export let tabs: Context['tabs'];
|
||||
export let tab = tabs[0];
|
||||
|
||||
const ctx = createTabs({
|
||||
defaultValue: tab,
|
||||
onValueChange({ next }) {
|
||||
tab = next;
|
||||
return next;
|
||||
}
|
||||
});
|
||||
$: value.set(tab);
|
||||
const ctx = createTabs({
|
||||
defaultValue: tab,
|
||||
onValueChange({ next }) {
|
||||
tab = next;
|
||||
return next;
|
||||
}
|
||||
});
|
||||
$: value.set(tab);
|
||||
|
||||
setTabsContext({ ...ctx, tabs });
|
||||
setTabsContext({ ...ctx, tabs });
|
||||
|
||||
const {
|
||||
elements: { root },
|
||||
states: { value }
|
||||
} = ctx;
|
||||
const {
|
||||
elements: { root },
|
||||
states: { value }
|
||||
} = ctx;
|
||||
</script>
|
||||
|
||||
<div use:melt={$root}>
|
||||
<slot TabsList={List} TabContent={Content} />
|
||||
<slot TabsList={List} TabContent={Content} />
|
||||
</div>
|
||||
|
||||
@@ -2,54 +2,54 @@ import { tick } from 'svelte';
|
||||
import type { Action } from 'svelte/action';
|
||||
|
||||
export type PortalConfig =
|
||||
| { target?: string | HTMLElement | undefined; prepend?: boolean }
|
||||
| undefined;
|
||||
| { target?: string | HTMLElement | undefined; prepend?: boolean }
|
||||
| undefined;
|
||||
|
||||
const defaults: PortalConfig = {
|
||||
target: 'body',
|
||||
prepend: false
|
||||
target: 'body',
|
||||
prepend: false
|
||||
};
|
||||
|
||||
export const portal: Action<HTMLElement, PortalConfig> = (el, config?: PortalConfig) => {
|
||||
let targetEl;
|
||||
let targetEl;
|
||||
|
||||
async function update(newConfig: PortalConfig) {
|
||||
const { target, prepend } = { ...defaults, ...newConfig };
|
||||
async function update(newConfig: PortalConfig) {
|
||||
const { target, prepend } = { ...defaults, ...newConfig };
|
||||
|
||||
if (typeof target === 'string') {
|
||||
targetEl = document.querySelector(target);
|
||||
if (targetEl === null) {
|
||||
await tick();
|
||||
targetEl = document.querySelector(target);
|
||||
}
|
||||
if (targetEl === null) {
|
||||
throw new Error(`No element found matching css selector: "${target}"`);
|
||||
}
|
||||
} else if (target instanceof HTMLElement) {
|
||||
targetEl = target;
|
||||
} else {
|
||||
throw new TypeError(
|
||||
`Unknown portal target type: ${
|
||||
target === null ? 'null' : typeof target
|
||||
}. Allowed types: string (CSS selector) or HTMLElement.`
|
||||
);
|
||||
}
|
||||
el.dataset.portal = '';
|
||||
if (prepend) {
|
||||
targetEl.prepend(el);
|
||||
} else {
|
||||
targetEl.appendChild(el);
|
||||
}
|
||||
el.hidden = false;
|
||||
}
|
||||
if (typeof target === 'string') {
|
||||
targetEl = document.querySelector(target);
|
||||
if (targetEl === null) {
|
||||
await tick();
|
||||
targetEl = document.querySelector(target);
|
||||
}
|
||||
if (targetEl === null) {
|
||||
throw new Error(`No element found matching css selector: "${target}"`);
|
||||
}
|
||||
} else if (target instanceof HTMLElement) {
|
||||
targetEl = target;
|
||||
} else {
|
||||
throw new TypeError(
|
||||
`Unknown portal target type: ${
|
||||
target === null ? 'null' : typeof target
|
||||
}. Allowed types: string (CSS selector) or HTMLElement.`
|
||||
);
|
||||
}
|
||||
el.dataset.portal = '';
|
||||
if (prepend) {
|
||||
targetEl.prepend(el);
|
||||
} else {
|
||||
targetEl.appendChild(el);
|
||||
}
|
||||
el.hidden = false;
|
||||
}
|
||||
|
||||
function destroy() {
|
||||
el.remove();
|
||||
}
|
||||
function destroy() {
|
||||
el.remove();
|
||||
}
|
||||
|
||||
update(config ?? {});
|
||||
return {
|
||||
update,
|
||||
destroy
|
||||
};
|
||||
update(config ?? {});
|
||||
return {
|
||||
update,
|
||||
destroy
|
||||
};
|
||||
};
|
||||
|
||||
@@ -4,25 +4,25 @@ import type { Writable } from 'svelte/store';
|
||||
type Args = Writable<DOMRect | null>;
|
||||
|
||||
export const rect: Action<HTMLElement, Args> = (node, store) => {
|
||||
let observer: ResizeObserver | null = null;
|
||||
const update = (store: Args) => {
|
||||
observer?.disconnect();
|
||||
let observer: ResizeObserver | null = null;
|
||||
const update = (store: Args) => {
|
||||
observer?.disconnect();
|
||||
|
||||
store.set(node.getBoundingClientRect());
|
||||
store.set(node.getBoundingClientRect());
|
||||
|
||||
// Observe resize
|
||||
observer = new ResizeObserver(() => {
|
||||
store.set(node.getBoundingClientRect());
|
||||
});
|
||||
observer.observe(node);
|
||||
};
|
||||
// Observe resize
|
||||
observer = new ResizeObserver(() => {
|
||||
store.set(node.getBoundingClientRect());
|
||||
});
|
||||
observer.observe(node);
|
||||
};
|
||||
|
||||
update(store);
|
||||
update(store);
|
||||
|
||||
return {
|
||||
update,
|
||||
destroy() {
|
||||
// no-op
|
||||
}
|
||||
};
|
||||
return {
|
||||
update,
|
||||
destroy() {
|
||||
// no-op
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1,34 +1,34 @@
|
||||
<script lang="ts">
|
||||
import { rect } from '$lib/actions';
|
||||
import { writable } from 'svelte/store';
|
||||
import { rect } from '$lib/actions';
|
||||
import { writable } from 'svelte/store';
|
||||
|
||||
const bodyRect = writable<DOMRect | null>(null);
|
||||
const bodyRect = writable<DOMRect | null>(null);
|
||||
</script>
|
||||
|
||||
<div class="relative">
|
||||
<div
|
||||
class="true-body"
|
||||
style:width={`${$bodyRect?.width ?? 0}px`}
|
||||
style:height={`${$bodyRect?.height ?? 0}px`}
|
||||
/>
|
||||
<div class="body" use:rect={bodyRect}>
|
||||
<slot />
|
||||
</div>
|
||||
<div
|
||||
class="true-body"
|
||||
style:width={`${$bodyRect?.width ?? 0}px`}
|
||||
style:height={`${$bodyRect?.height ?? 0}px`}
|
||||
/>
|
||||
<div class="body" use:rect={bodyRect}>
|
||||
<slot />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style lang="scss">
|
||||
.relative {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
.relative {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.body {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
}
|
||||
.body {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
}
|
||||
|
||||
.true-body {
|
||||
transition: 0.2s ease;
|
||||
}
|
||||
.true-body {
|
||||
transition: 0.2s ease;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
<script lang="ts">
|
||||
import '$scss/hljs.css';
|
||||
import '$scss/hljs.css';
|
||||
|
||||
import { getCodeHtml } from '$lib/utils/code';
|
||||
import { getCodeHtml } from '$lib/utils/code';
|
||||
|
||||
export let content: string;
|
||||
$: codeHtml = getCodeHtml({ content, language: 'js' });
|
||||
export let content: string;
|
||||
$: codeHtml = getCodeHtml({ content, language: 'js' });
|
||||
</script>
|
||||
|
||||
<!-- eslint-disable-next-line svelte/no-at-html-tags -->
|
||||
|
||||
@@ -1,96 +1,96 @@
|
||||
<script>
|
||||
import AutoBox from '../AutoBox.svelte';
|
||||
import Code from './Code.svelte';
|
||||
import AutoBox from '../AutoBox.svelte';
|
||||
import Code from './Code.svelte';
|
||||
</script>
|
||||
|
||||
<div class="code-console">
|
||||
<div class="header">
|
||||
<div class="ellipse" />
|
||||
<div class="ellipse-2" />
|
||||
<div class="ellipse-3" />
|
||||
</div>
|
||||
<div class="block">
|
||||
<AutoBox>
|
||||
<slot {Code} />
|
||||
</AutoBox>
|
||||
</div>
|
||||
<div id="code-bottom" />
|
||||
<div class="header">
|
||||
<div class="ellipse" />
|
||||
<div class="ellipse-2" />
|
||||
<div class="ellipse-3" />
|
||||
</div>
|
||||
<div class="block">
|
||||
<AutoBox>
|
||||
<slot {Code} />
|
||||
</AutoBox>
|
||||
</div>
|
||||
<div id="code-bottom" />
|
||||
</div>
|
||||
|
||||
<style lang="scss">
|
||||
@use '$scss/abstract/mixins/border-gradient' as gradients;
|
||||
|
||||
.code-console {
|
||||
@include gradients.border-gradient;
|
||||
--p-radius: 16px;
|
||||
.code-console {
|
||||
@include gradients.border-gradient;
|
||||
--p-radius: 16px;
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
background-color: hsl(var(--web-color-card));
|
||||
border-radius: var(--p-radius);
|
||||
--m-border-radius: var(--p-radius);
|
||||
--m-border-gradient-before: linear-gradient(
|
||||
180deg,
|
||||
rgba(255, 255, 255, 0.12) 0%,
|
||||
rgba(255, 255, 255, 0) 125.11%
|
||||
);
|
||||
backdrop-filter: blur(8px);
|
||||
background-color: hsl(var(--web-color-card));
|
||||
border-radius: var(--p-radius);
|
||||
--m-border-radius: var(--p-radius);
|
||||
--m-border-gradient-before: linear-gradient(
|
||||
180deg,
|
||||
rgba(255, 255, 255, 0.12) 0%,
|
||||
rgba(255, 255, 255, 0) 125.11%
|
||||
);
|
||||
backdrop-filter: blur(8px);
|
||||
|
||||
min-width: 330px;
|
||||
width: fit-content;
|
||||
padding: 0 0.25rem 0.25rem;
|
||||
}
|
||||
min-width: 330px;
|
||||
width: fit-content;
|
||||
padding: 0 0.25rem 0.25rem;
|
||||
}
|
||||
|
||||
.block {
|
||||
width: 100%;
|
||||
flex-grow: 1;
|
||||
text-align: left;
|
||||
.block {
|
||||
width: 100%;
|
||||
flex-grow: 1;
|
||||
text-align: left;
|
||||
|
||||
border-radius: 12px;
|
||||
background: linear-gradient(129deg, rgba(0, 0, 0, 0.48) 22.38%, rgba(0, 0, 0, 0) 136.5%);
|
||||
padding: 20px;
|
||||
border-radius: 12px;
|
||||
background: linear-gradient(129deg, rgba(0, 0, 0, 0.48) 22.38%, rgba(0, 0, 0, 0) 136.5%);
|
||||
padding: 20px;
|
||||
|
||||
position: relative;
|
||||
}
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.header {
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.375rem;
|
||||
padding: 0.75rem;
|
||||
.header {
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.375rem;
|
||||
padding: 0.75rem;
|
||||
|
||||
.ellipse {
|
||||
background-color: #ec6a5e;
|
||||
.ellipse {
|
||||
background-color: #ec6a5e;
|
||||
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
top: 12px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
top: 12px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.ellipse-2 {
|
||||
background-color: #f5bf4f;
|
||||
.ellipse-2 {
|
||||
background-color: #f5bf4f;
|
||||
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
top: 12px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
top: 12px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.ellipse-3 {
|
||||
background-color: #61c554;
|
||||
.ellipse-3 {
|
||||
background-color: #61c554;
|
||||
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
top: 12px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
}
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
top: 12px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
}
|
||||
|
||||
.code-console :global(code) {
|
||||
white-space: pre;
|
||||
tab-size: 4;
|
||||
}
|
||||
.code-console :global(code) {
|
||||
white-space: pre;
|
||||
tab-size: 4;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -182,7 +182,7 @@
|
||||
class="web-card is-white web-u-min-block-size-320 u-flex-vertical oss-card"
|
||||
id="oss-discord"
|
||||
>
|
||||
<div class="u-flex-vertical u-main-space-between u-gap-32">
|
||||
<div class="u-flex-vertical u-main-space-between gap-8">
|
||||
<span
|
||||
class="web-icon-discord web-u-font-size-40"
|
||||
aria-hidden="true"
|
||||
@@ -197,7 +197,7 @@
|
||||
id="oss-github"
|
||||
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 gap-8">
|
||||
<span
|
||||
class="web-icon-github web-u-font-size-40"
|
||||
aria-hidden="true"
|
||||
@@ -212,7 +212,7 @@
|
||||
class="web-card is-white web-u-min-block-size-320 u-flex-vertical oss-card"
|
||||
id="oss-twitter"
|
||||
>
|
||||
<div class="u-flex-vertical u-main-space-between u-gap-32">
|
||||
<div class="u-flex-vertical u-main-space-between gap-8">
|
||||
<span
|
||||
class="web-icon-x web-u-font-size-40"
|
||||
aria-hidden="true"
|
||||
@@ -227,7 +227,7 @@
|
||||
class="web-card is-white web-u-min-block-size-320 u-flex-vertical oss-card"
|
||||
id="oss-youtube"
|
||||
>
|
||||
<div class="u-flex-vertical u-main-space-between u-gap-32">
|
||||
<div class="u-flex-vertical u-main-space-between gap-8">
|
||||
<span
|
||||
class="web-icon-youtube web-u-font-size-40"
|
||||
aria-hidden="true"
|
||||
@@ -242,7 +242,7 @@
|
||||
id="oss-commits"
|
||||
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 gap-8">
|
||||
<span
|
||||
class="web-icon-github web-u-font-size-40"
|
||||
aria-hidden="true"
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
<script lang="ts">
|
||||
export let id: string | undefined = undefined;
|
||||
export let id: string | undefined = undefined;
|
||||
</script>
|
||||
|
||||
<div class="phone" {id}>
|
||||
<div class="inner">
|
||||
<slot />
|
||||
</div>
|
||||
<div class="inner">
|
||||
<slot />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,55 +1,55 @@
|
||||
<script lang="ts">
|
||||
import AutoHeight from '../AutoBox.svelte';
|
||||
import AutoHeight from '../AutoBox.svelte';
|
||||
</script>
|
||||
|
||||
<div class="anim-box">
|
||||
<div class="top"><slot name="top" /></div>
|
||||
<div class="content">
|
||||
<AutoHeight>
|
||||
<slot />
|
||||
</AutoHeight>
|
||||
</div>
|
||||
<div class="top"><slot name="top" /></div>
|
||||
<div class="content">
|
||||
<AutoHeight>
|
||||
<slot />
|
||||
</AutoHeight>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style lang="scss">
|
||||
@use '$scss/abstract/mixins/border-gradient' as gradients;
|
||||
|
||||
.anim-box {
|
||||
@include gradients.border-gradient;
|
||||
--m-border-radius: 1rem;
|
||||
--m-border-gradient-before: linear-gradient(
|
||||
180deg,
|
||||
rgba(255, 255, 255, 0.12) 0%,
|
||||
rgba(255, 255, 255, 0) 125.11%
|
||||
);
|
||||
border-radius: var(--m-border-radius);
|
||||
background: hsl(var(--web-color-card));
|
||||
backdrop-filter: blur(8px);
|
||||
.anim-box {
|
||||
@include gradients.border-gradient;
|
||||
--m-border-radius: 1rem;
|
||||
--m-border-gradient-before: linear-gradient(
|
||||
180deg,
|
||||
rgba(255, 255, 255, 0.12) 0%,
|
||||
rgba(255, 255, 255, 0) 125.11%
|
||||
);
|
||||
border-radius: var(--m-border-radius);
|
||||
background: hsl(var(--web-color-card));
|
||||
backdrop-filter: blur(8px);
|
||||
|
||||
padding: 0.5rem;
|
||||
padding-block-start: 0;
|
||||
padding: 0.5rem;
|
||||
padding-block-start: 0;
|
||||
|
||||
text-align: left;
|
||||
text-align: left;
|
||||
|
||||
.top {
|
||||
color: var(--greyscale-50, #ededf0);
|
||||
font-family: Aeonik Pro;
|
||||
font-size: 1.25rem;
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
line-height: 2rem; /* 160% */
|
||||
letter-spacing: -0.0125rem;
|
||||
.top {
|
||||
color: var(--greyscale-50, #ededf0);
|
||||
font-family: Aeonik Pro;
|
||||
font-size: 1.25rem;
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
line-height: 2rem; /* 160% */
|
||||
letter-spacing: -0.0125rem;
|
||||
|
||||
padding: 1rem;
|
||||
text-align: left;
|
||||
}
|
||||
padding: 1rem;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.content {
|
||||
border-radius: 0.75rem;
|
||||
background: rgba(255, 255, 255, 0.04);
|
||||
backdrop-filter: blur(30px);
|
||||
.content {
|
||||
border-radius: 0.75rem;
|
||||
background: rgba(255, 255, 255, 0.04);
|
||||
backdrop-filter: blur(30px);
|
||||
|
||||
position: relative;
|
||||
}
|
||||
}
|
||||
position: relative;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -247,7 +247,7 @@
|
||||
Your backend, minus the hassle
|
||||
</h2>
|
||||
<p
|
||||
class="web-description web-u-max-width-700 u-margin-inline-auto"
|
||||
class="web-description web-u-max-width-700 mx-auto"
|
||||
transition:fly={{
|
||||
y: 16,
|
||||
delay: 400
|
||||
|
||||
@@ -1,61 +1,61 @@
|
||||
<script lang="ts">
|
||||
import { createCheckbox, melt } from '@melt-ui/svelte';
|
||||
import { createCheckbox, melt } from '@melt-ui/svelte';
|
||||
|
||||
export let checked = false;
|
||||
export let checked = false;
|
||||
|
||||
const {
|
||||
elements: { root },
|
||||
states: { checked: localChecked },
|
||||
helpers: { isChecked }
|
||||
} = createCheckbox({
|
||||
onCheckedChange({ next }) {
|
||||
if (typeof next === 'boolean') {
|
||||
checked = next;
|
||||
}
|
||||
return next;
|
||||
}
|
||||
});
|
||||
const {
|
||||
elements: { root },
|
||||
states: { checked: localChecked },
|
||||
helpers: { isChecked }
|
||||
} = createCheckbox({
|
||||
onCheckedChange({ next }) {
|
||||
if (typeof next === 'boolean') {
|
||||
checked = next;
|
||||
}
|
||||
return next;
|
||||
}
|
||||
});
|
||||
|
||||
$: localChecked.set(checked);
|
||||
$: localChecked.set(checked);
|
||||
</script>
|
||||
|
||||
<div class="wrapper">
|
||||
<button use:melt={$root} class="anim-checkbox">
|
||||
{#if $isChecked}
|
||||
<span class="web-icon-check" />
|
||||
{/if}
|
||||
</button>
|
||||
<button use:melt={$root} class="anim-checkbox">
|
||||
{#if $isChecked}
|
||||
<span class="web-icon-check" />
|
||||
{/if}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<style lang="scss">
|
||||
.wrapper {
|
||||
display: grid;
|
||||
place-items: center;
|
||||
}
|
||||
.wrapper {
|
||||
display: grid;
|
||||
place-items: center;
|
||||
}
|
||||
|
||||
.anim-checkbox {
|
||||
width: 1rem;
|
||||
height: 1rem;
|
||||
flex-shrink: 0;
|
||||
.anim-checkbox {
|
||||
width: 1rem;
|
||||
height: 1rem;
|
||||
flex-shrink: 0;
|
||||
|
||||
border-radius: 0.125rem;
|
||||
border: 1.5px solid var(--greyscale-500, #818186);
|
||||
border-radius: 0.125rem;
|
||||
border: 1.5px solid var(--greyscale-500, #818186);
|
||||
|
||||
position: relative;
|
||||
position: relative;
|
||||
|
||||
&:global(.anim-checkbox[data-state='checked']) {
|
||||
background-color: #7c67fe;
|
||||
border-color: #7c67fe;
|
||||
}
|
||||
}
|
||||
&:global(.anim-checkbox[data-state='checked']) {
|
||||
background-color: #7c67fe;
|
||||
border-color: #7c67fe;
|
||||
}
|
||||
}
|
||||
|
||||
[class*='icon-'] {
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
[class*='icon-'] {
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
|
||||
color: white;
|
||||
font-size: 1rem;
|
||||
}
|
||||
color: white;
|
||||
font-size: 1rem;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,64 +1,64 @@
|
||||
<script lang="ts">
|
||||
import { getInitials } from '$lib/animations';
|
||||
import { fly } from 'svelte/transition';
|
||||
import { authController } from '.';
|
||||
import { flip } from '$lib/utils/flip';
|
||||
import { getInitials } from '$lib/animations';
|
||||
import { fly } from 'svelte/transition';
|
||||
import { authController } from '.';
|
||||
import { flip } from '$lib/utils/flip';
|
||||
|
||||
const { state } = authController;
|
||||
const { state } = authController;
|
||||
|
||||
type AuthEntry = {
|
||||
avatar: string;
|
||||
name: string;
|
||||
email: string;
|
||||
id: number;
|
||||
};
|
||||
$: authData = [
|
||||
$state.submitted
|
||||
? {
|
||||
avatar: getInitials($state.name),
|
||||
name: $state.name,
|
||||
email: $state.email,
|
||||
id: 0
|
||||
}
|
||||
: undefined,
|
||||
{
|
||||
avatar: 'BD',
|
||||
name: 'Benjamin Davis',
|
||||
email: 'benjamin.davis@example.com',
|
||||
id: 1
|
||||
},
|
||||
{
|
||||
avatar: 'OS',
|
||||
name: 'Olivia Smith',
|
||||
email: 'olivia.smith@example.com',
|
||||
id: 2
|
||||
},
|
||||
{
|
||||
avatar: 'EW',
|
||||
name: 'Ethan Wilson',
|
||||
email: 'ethan.wilson@example.com',
|
||||
id: 3
|
||||
}
|
||||
].filter(Boolean) as AuthEntry[];
|
||||
type AuthEntry = {
|
||||
avatar: string;
|
||||
name: string;
|
||||
email: string;
|
||||
id: number;
|
||||
};
|
||||
$: authData = [
|
||||
$state.submitted
|
||||
? {
|
||||
avatar: getInitials($state.name),
|
||||
name: $state.name,
|
||||
email: $state.email,
|
||||
id: 0
|
||||
}
|
||||
: undefined,
|
||||
{
|
||||
avatar: 'BD',
|
||||
name: 'Benjamin Davis',
|
||||
email: 'benjamin.davis@example.com',
|
||||
id: 1
|
||||
},
|
||||
{
|
||||
avatar: 'OS',
|
||||
name: 'Olivia Smith',
|
||||
email: 'olivia.smith@example.com',
|
||||
id: 2
|
||||
},
|
||||
{
|
||||
avatar: 'EW',
|
||||
name: 'Ethan Wilson',
|
||||
email: 'ethan.wilson@example.com',
|
||||
id: 3
|
||||
}
|
||||
].filter(Boolean) as AuthEntry[];
|
||||
</script>
|
||||
|
||||
<div class="pseudo-table">
|
||||
<div class="header">
|
||||
<span class="web-eyebrow">Name</span>
|
||||
<span class="web-eyebrow">Identifier</span>
|
||||
</div>
|
||||
{#each authData as user (user.id)}
|
||||
<div
|
||||
class="row"
|
||||
in:fly={{ duration: 100, x: -16, delay: 100 }}
|
||||
out:fly={{ duration: 100, x: -16 }}
|
||||
animate:flip={{ duration: 150 }}
|
||||
>
|
||||
<div class="u-flex u-cross-center u-gap-12">
|
||||
<div class="avatar is-size-small">{user.avatar}</div>
|
||||
<span class="truncated">{user.name}</span>
|
||||
</div>
|
||||
<span class="truncated">{user.email}</span>
|
||||
</div>
|
||||
{/each}
|
||||
<div class="header">
|
||||
<span class="web-eyebrow">Name</span>
|
||||
<span class="web-eyebrow">Identifier</span>
|
||||
</div>
|
||||
{#each authData as user (user.id)}
|
||||
<div
|
||||
class="row"
|
||||
in:fly={{ duration: 100, x: -16, delay: 100 }}
|
||||
out:fly={{ duration: 100, x: -16 }}
|
||||
animate:flip={{ duration: 150 }}
|
||||
>
|
||||
<div class="flex u-cross-center gap-3">
|
||||
<div class="avatar is-size-small">{user.avatar}</div>
|
||||
<span class="truncated">{user.name}</span>
|
||||
</div>
|
||||
<span class="truncated">{user.email}</span>
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
|
||||
@@ -1,211 +1,220 @@
|
||||
<script lang="ts">
|
||||
import { fade } from 'svelte/transition';
|
||||
import { authController } from '.';
|
||||
import { objectKeys } from '$lib/utils/object';
|
||||
import { flip } from '$lib/utils/flip';
|
||||
import { fade } from 'svelte/transition';
|
||||
import { authController } from '.';
|
||||
import { objectKeys } from '$lib/utils/object';
|
||||
import { flip } from '$lib/utils/flip';
|
||||
|
||||
const { state } = authController;
|
||||
const { state } = authController;
|
||||
|
||||
$: controlsEnabled = $state.showControls && Object.values($state.controls).some(Boolean);
|
||||
$: controlsEnabled = $state.showControls && Object.values($state.controls).some(Boolean);
|
||||
</script>
|
||||
|
||||
<div data-theme-ignore class="inner-phone theme-light">
|
||||
<p class="title">Create an Account</p>
|
||||
<p class="subtitle">Please enter your details</p>
|
||||
<div class="inputs">
|
||||
<fieldset>
|
||||
<label for="name">Your Name</label>
|
||||
<input type="name" id="name" placeholder="Enter your name" bind:value={$state.name} />
|
||||
</fieldset>
|
||||
<fieldset>
|
||||
<label for="email">Your Email</label>
|
||||
<input type="email" id="email" placeholder="Enter your email" bind:value={$state.email} />
|
||||
</fieldset>
|
||||
<fieldset>
|
||||
<label for="password">Create Password</label>
|
||||
<input
|
||||
type="password"
|
||||
id="password"
|
||||
placeholder="Enter Password"
|
||||
bind:value={$state.password}
|
||||
/>
|
||||
</fieldset>
|
||||
</div>
|
||||
<button class="sign-up">Sign Up</button>
|
||||
{#if controlsEnabled}
|
||||
<span class="with-sep" transition:fade={{ duration: 100 }}>or sign up with</span>
|
||||
<div class="oauth-btns" transition:fade={{ duration: 100 }}>
|
||||
{#each objectKeys($state.controls).filter((p) => $state.controls[p]) as provider (provider)}
|
||||
<button class="oauth" transition:fade={{ duration: 100 }} animate:flip={{ duration: 250 }}>
|
||||
<div class="inner">
|
||||
<span class="web-icon-{provider.toLowerCase()}" />
|
||||
<span>{provider}</span>
|
||||
</div>
|
||||
</button>
|
||||
{/each}
|
||||
</div>
|
||||
{/if}
|
||||
<div data-theme-ignore class="inner-phone light">
|
||||
<p class="title">Create an Account</p>
|
||||
<p class="subtitle">Please enter your details</p>
|
||||
<div class="inputs">
|
||||
<fieldset>
|
||||
<label for="name">Your Name</label>
|
||||
<input type="name" id="name" placeholder="Enter your name" bind:value={$state.name} />
|
||||
</fieldset>
|
||||
<fieldset>
|
||||
<label for="email">Your Email</label>
|
||||
<input
|
||||
type="email"
|
||||
id="email"
|
||||
placeholder="Enter your email"
|
||||
bind:value={$state.email}
|
||||
/>
|
||||
</fieldset>
|
||||
<fieldset>
|
||||
<label for="password">Create Password</label>
|
||||
<input
|
||||
type="password"
|
||||
id="password"
|
||||
placeholder="Enter Password"
|
||||
bind:value={$state.password}
|
||||
/>
|
||||
</fieldset>
|
||||
</div>
|
||||
<button class="sign-up">Sign Up</button>
|
||||
{#if controlsEnabled}
|
||||
<span class="with-sep" transition:fade={{ duration: 100 }}>or sign up with</span>
|
||||
<div class="oauth-btns" transition:fade={{ duration: 100 }}>
|
||||
{#each objectKeys($state.controls).filter((p) => $state.controls[p]) as provider (provider)}
|
||||
<button
|
||||
class="oauth"
|
||||
transition:fade={{ duration: 100 }}
|
||||
animate:flip={{ duration: 250 }}
|
||||
>
|
||||
<div class="inner">
|
||||
<span class="web-icon-{provider.toLowerCase()}" />
|
||||
<span>{provider}</span>
|
||||
</div>
|
||||
</button>
|
||||
{/each}
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<style lang="scss">
|
||||
.inner-phone {
|
||||
padding-block: 3rem;
|
||||
padding-inline: 1rem;
|
||||
.inner-phone {
|
||||
padding-block: 3rem;
|
||||
padding-inline: 1rem;
|
||||
|
||||
color: rgba(67, 67, 71, 1);
|
||||
text-align: left;
|
||||
color: rgba(67, 67, 71, 1);
|
||||
text-align: left;
|
||||
|
||||
.title {
|
||||
color: #434347;
|
||||
font-family: Inter;
|
||||
font-size: 16px;
|
||||
font-style: normal;
|
||||
font-weight: 600;
|
||||
line-height: 22px; /* 137.5% */
|
||||
letter-spacing: -0.224px;
|
||||
}
|
||||
.title {
|
||||
color: #434347;
|
||||
font-family: Inter;
|
||||
font-size: 16px;
|
||||
font-style: normal;
|
||||
font-weight: 600;
|
||||
line-height: 22px; /* 137.5% */
|
||||
letter-spacing: -0.224px;
|
||||
}
|
||||
|
||||
.subtitle {
|
||||
color: var(--greyscale-700, var(--color-greyscale-700, #56565c));
|
||||
font-family: Inter;
|
||||
font-size: 14px;
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
line-height: 20px; /* 142.857% */
|
||||
letter-spacing: -0.196px;
|
||||
}
|
||||
.subtitle {
|
||||
color: var(--greyscale-700, var(--color-greyscale-700, #56565c));
|
||||
font-family: Inter;
|
||||
font-size: 14px;
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
line-height: 20px; /* 142.857% */
|
||||
letter-spacing: -0.196px;
|
||||
}
|
||||
|
||||
.inputs {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.75rem;
|
||||
margin-block-start: 1.5rem;
|
||||
.inputs {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.75rem;
|
||||
margin-block-start: 1.5rem;
|
||||
|
||||
fieldset {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.3125rem;
|
||||
width: 100%;
|
||||
fieldset {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.3125rem;
|
||||
width: 100%;
|
||||
|
||||
label {
|
||||
color: var(--color-greyscale-700, #56565c);
|
||||
font-family: Inter;
|
||||
font-size: 12px;
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
line-height: 16px; /* 133.333% */
|
||||
letter-spacing: -0.168px;
|
||||
}
|
||||
label {
|
||||
color: var(--color-greyscale-700, #56565c);
|
||||
font-family: Inter;
|
||||
font-size: 12px;
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
line-height: 16px; /* 133.333% */
|
||||
letter-spacing: -0.168px;
|
||||
}
|
||||
|
||||
input {
|
||||
all: unset;
|
||||
display: flex;
|
||||
padding: 8px 12px;
|
||||
align-items: flex-start;
|
||||
align-self: stretch;
|
||||
border-radius: 8px;
|
||||
border: 1px solid #d8d8db;
|
||||
input {
|
||||
all: unset;
|
||||
display: flex;
|
||||
padding: 8px 12px;
|
||||
align-items: flex-start;
|
||||
align-self: stretch;
|
||||
border-radius: 8px;
|
||||
border: 1px solid #d8d8db;
|
||||
|
||||
color: #434347;
|
||||
font-family: Inter;
|
||||
font-size: 12px;
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
line-height: 16px; /* 133.333% */
|
||||
letter-spacing: -0.168px;
|
||||
}
|
||||
}
|
||||
}
|
||||
color: #434347;
|
||||
font-family: Inter;
|
||||
font-size: 12px;
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
line-height: 16px; /* 133.333% */
|
||||
letter-spacing: -0.168px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.sign-up {
|
||||
padding: 0.375rem 0.75rem;
|
||||
text-align: center;
|
||||
width: 100%;
|
||||
margin-block-start: 1.25rem;
|
||||
.sign-up {
|
||||
padding: 0.375rem 0.75rem;
|
||||
text-align: center;
|
||||
width: 100%;
|
||||
margin-block-start: 1.25rem;
|
||||
|
||||
border-radius: 0.5rem;
|
||||
background: var(--appwrite-purple, #7c67fe);
|
||||
box-shadow: 0px 4px 8px 0px rgba(0, 0, 0, 0.06);
|
||||
border-radius: 0.5rem;
|
||||
background: var(--appwrite-purple, #7c67fe);
|
||||
box-shadow: 0px 4px 8px 0px rgba(0, 0, 0, 0.06);
|
||||
|
||||
color: var(--color-bw-white, #fff);
|
||||
text-align: center;
|
||||
color: var(--color-bw-white, #fff);
|
||||
text-align: center;
|
||||
|
||||
/* Responsive/SubBody-500 */
|
||||
font-family: Inter;
|
||||
font-size: 14px;
|
||||
font-style: normal;
|
||||
font-weight: 500;
|
||||
line-height: 22px; /* 157.143% */
|
||||
letter-spacing: -0.07px;
|
||||
}
|
||||
/* Responsive/SubBody-500 */
|
||||
font-family: Inter;
|
||||
font-size: 14px;
|
||||
font-style: normal;
|
||||
font-weight: 500;
|
||||
line-height: 22px; /* 157.143% */
|
||||
letter-spacing: -0.07px;
|
||||
}
|
||||
|
||||
.with-sep {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 1rem;
|
||||
.with-sep {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 1rem;
|
||||
|
||||
font-family: Inter;
|
||||
font-size: 0.75rem;
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
line-height: 1.25rem; /* 166.667% */
|
||||
letter-spacing: -0.0105rem;
|
||||
color: hsl(var(--web-color-greyscale-500));
|
||||
font-family: Inter;
|
||||
font-size: 0.75rem;
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
line-height: 1.25rem; /* 166.667% */
|
||||
letter-spacing: -0.0105rem;
|
||||
color: hsl(var(--web-color-greyscale-500));
|
||||
|
||||
margin-block-start: 0.75rem;
|
||||
margin-block-start: 0.75rem;
|
||||
|
||||
&::before,
|
||||
&::after {
|
||||
content: '';
|
||||
height: 1px;
|
||||
flex-grow: 1;
|
||||
background-color: hsl(var(--web-color-greyscale-200));
|
||||
}
|
||||
}
|
||||
&::before,
|
||||
&::after {
|
||||
content: '';
|
||||
height: 1px;
|
||||
flex-grow: 1;
|
||||
background-color: hsl(var(--web-color-greyscale-200));
|
||||
}
|
||||
}
|
||||
|
||||
.oauth-btns {
|
||||
--gap: 0.5rem;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: var(--gap);
|
||||
margin-block-start: 0.75rem;
|
||||
}
|
||||
.oauth-btns {
|
||||
--gap: 0.5rem;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: var(--gap);
|
||||
margin-block-start: 0.75rem;
|
||||
}
|
||||
|
||||
.oauth {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
.oauth {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
border-radius: 0.5rem;
|
||||
border: 1px solid #d9d9d9;
|
||||
color: hsl(var(--web-color-greyscale-750));
|
||||
text-align: center;
|
||||
border-radius: 0.5rem;
|
||||
border: 1px solid #d9d9d9;
|
||||
color: hsl(var(--web-color-greyscale-750));
|
||||
text-align: center;
|
||||
|
||||
/* Responsive/Caption-500 */
|
||||
font-family: Inter;
|
||||
font-size: 0.875rem;
|
||||
font-style: normal;
|
||||
font-weight: 500;
|
||||
line-height: 1.375rem; /* 157.143% */
|
||||
letter-spacing: -0.01575rem;
|
||||
/* Responsive/Caption-500 */
|
||||
font-family: Inter;
|
||||
font-size: 0.875rem;
|
||||
font-style: normal;
|
||||
font-weight: 500;
|
||||
line-height: 1.375rem; /* 157.143% */
|
||||
letter-spacing: -0.01575rem;
|
||||
|
||||
flex: 1 1 calc(50% - var(--gap));
|
||||
padding-block: 0.375rem;
|
||||
position: relative;
|
||||
height: 2.125rem;
|
||||
flex: 1 1 calc(50% - var(--gap));
|
||||
padding-block: 0.375rem;
|
||||
position: relative;
|
||||
height: 2.125rem;
|
||||
|
||||
.inner {
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
.inner {
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
transform: translate(-50%, -50%) scale(var(--inverse-sx, 1), var(--inverse-sy, 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
transform: translate(-50%, -50%) scale(var(--inverse-sx, 1), var(--inverse-sy, 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,54 +1,54 @@
|
||||
<script lang="ts">
|
||||
import { slide } from 'svelte/transition';
|
||||
import { databasesController } from '.';
|
||||
import { flip } from '$lib/utils/flip';
|
||||
import { slide } from 'svelte/transition';
|
||||
import { databasesController } from '.';
|
||||
import { flip } from '$lib/utils/flip';
|
||||
|
||||
const { state } = databasesController;
|
||||
const { state } = databasesController;
|
||||
</script>
|
||||
|
||||
<div class="pseudo-table">
|
||||
<div class="header">
|
||||
<span class="web-eyebrow">Document ID</span>
|
||||
<span class="web-eyebrow">Task</span>
|
||||
</div>
|
||||
{#each $state.tasks.slice(0, $state.tableSlice) as task (task.id)}
|
||||
<div class="row" transition:slide={{ duration: 150 }} animate:flip={{ duration: 150 }}>
|
||||
<div class="copy-button">
|
||||
<span class="web-icon-copy" />
|
||||
<span>{task.id}</span>
|
||||
</div>
|
||||
<span class="truncated">{task.title}</span>
|
||||
</div>
|
||||
{/each}
|
||||
<div class="header">
|
||||
<span class="web-eyebrow">Document ID</span>
|
||||
<span class="web-eyebrow">Task</span>
|
||||
</div>
|
||||
{#each $state.tasks.slice(0, $state.tableSlice) as task (task.id)}
|
||||
<div class="row" transition:slide={{ duration: 150 }} animate:flip={{ duration: 150 }}>
|
||||
<div class="copy-button">
|
||||
<span class="web-icon-copy" />
|
||||
<span>{task.id}</span>
|
||||
</div>
|
||||
<span class="truncated">{task.title}</span>
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
|
||||
<style lang="scss">
|
||||
.copy-button {
|
||||
display: flex;
|
||||
padding: 0.25rem 0.5rem;
|
||||
align-items: center;
|
||||
gap: 0.375rem;
|
||||
.copy-button {
|
||||
display: flex;
|
||||
padding: 0.25rem 0.5rem;
|
||||
align-items: center;
|
||||
gap: 0.375rem;
|
||||
|
||||
border-radius: 62.4375rem;
|
||||
border: 1px solid rgba(255, 255, 255, 0.08);
|
||||
background: rgba(255, 255, 255, 0.04);
|
||||
backdrop-filter: blur(2.6666667461395264px);
|
||||
border-radius: 62.4375rem;
|
||||
border: 1px solid rgba(255, 255, 255, 0.08);
|
||||
background: rgba(255, 255, 255, 0.04);
|
||||
backdrop-filter: blur(2.6666667461395264px);
|
||||
|
||||
[class*='icon-'] {
|
||||
font-size: 1.25rem;
|
||||
color: hsl(var(--web-color-greyscale-600));
|
||||
}
|
||||
[class*='icon-'] {
|
||||
font-size: 1.25rem;
|
||||
color: hsl(var(--web-color-greyscale-600));
|
||||
}
|
||||
|
||||
span:not([class*='icon-']) {
|
||||
color: var(--greyscale-400, #adadb1);
|
||||
font-family: Inter;
|
||||
font-size: 0.875rem;
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
line-height: 1.25rem; /* 142.857% */
|
||||
span:not([class*='icon-']) {
|
||||
color: var(--greyscale-400, #adadb1);
|
||||
font-family: Inter;
|
||||
font-size: 0.875rem;
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
line-height: 1.25rem; /* 142.857% */
|
||||
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
}
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<script lang="ts">
|
||||
import Code from '$lib/animations/CodeWindow/Code.svelte';
|
||||
import Code from '$lib/animations/CodeWindow/Code.svelte';
|
||||
|
||||
let content = `
|
||||
let content = `
|
||||
const result = databases.createDocument(
|
||||
'Your-tasks',
|
||||
tasks,
|
||||
|
||||
@@ -7,88 +7,88 @@ import { createResettable } from '$lib/utils/resettable';
|
||||
import { getElSelector } from '../Products.svelte';
|
||||
|
||||
type Task = {
|
||||
id: string;
|
||||
title: string;
|
||||
checked: boolean;
|
||||
id: string;
|
||||
title: string;
|
||||
checked: boolean;
|
||||
};
|
||||
|
||||
type State = {
|
||||
tasks: Task[];
|
||||
tableSlice: number;
|
||||
tasks: Task[];
|
||||
tableSlice: number;
|
||||
};
|
||||
|
||||
const state = createResettable<State>({
|
||||
tasks: [
|
||||
{
|
||||
id: '3397fecdedb13397fecdedb1',
|
||||
title: 'Research user needs',
|
||||
checked: true
|
||||
}
|
||||
],
|
||||
tableSlice: 1
|
||||
tasks: [
|
||||
{
|
||||
id: '3397fecdedb13397fecdedb1',
|
||||
title: 'Research user needs',
|
||||
checked: true
|
||||
}
|
||||
],
|
||||
tableSlice: 1
|
||||
});
|
||||
|
||||
const execute = async () => {
|
||||
const phone = getElSelector('phone');
|
||||
const box = getElSelector('box');
|
||||
const code = getElSelector('code');
|
||||
const { update } = state.reset();
|
||||
const phone = getElSelector('phone');
|
||||
const box = getElSelector('box');
|
||||
const code = getElSelector('code');
|
||||
const { update } = state.reset();
|
||||
|
||||
await Promise.all([
|
||||
safeAnimate(phone, { x: 390, y: 0 }, { duration: 0.5 })?.finished,
|
||||
safeAnimate(box, { x: 0, y: 32, opacity: 1 }, { duration: 0.5 })?.finished,
|
||||
safeAnimate(code, { x: 80, y: 320, opacity: 1 }, { duration: 0.5 })?.finished
|
||||
]);
|
||||
await Promise.all([
|
||||
safeAnimate(phone, { x: 390, y: 0 }, { duration: 0.5 })?.finished,
|
||||
safeAnimate(box, { x: 0, y: 32, opacity: 1 }, { duration: 0.5 })?.finished,
|
||||
safeAnimate(code, { x: 80, y: 320, opacity: 1 }, { duration: 0.5 })?.finished
|
||||
]);
|
||||
|
||||
await sleep(250);
|
||||
await sleep(250);
|
||||
|
||||
update((p) => ({
|
||||
...p,
|
||||
tasks: [
|
||||
...p.tasks,
|
||||
{
|
||||
id: '3397fecdedb13397fecdedb2',
|
||||
title: 'Create wireframes',
|
||||
checked: false
|
||||
}
|
||||
]
|
||||
}));
|
||||
await sleep(250);
|
||||
update((p) => ({
|
||||
...p,
|
||||
tasks: [
|
||||
...p.tasks,
|
||||
{
|
||||
id: '3397fecdedb13397fecdedb2',
|
||||
title: 'Create wireframes',
|
||||
checked: false
|
||||
}
|
||||
]
|
||||
}));
|
||||
await sleep(250);
|
||||
|
||||
update((p) => ({
|
||||
...p,
|
||||
tableSlice: p.tableSlice + 1
|
||||
}));
|
||||
update((p) => ({
|
||||
...p,
|
||||
tableSlice: p.tableSlice + 1
|
||||
}));
|
||||
|
||||
await sleep(250);
|
||||
await sleep(250);
|
||||
|
||||
update((p) => ({
|
||||
...p,
|
||||
tasks: [
|
||||
...p.tasks,
|
||||
{
|
||||
id: '3397fecdedb13397fecdedb3',
|
||||
title: 'Create visual design',
|
||||
checked: false
|
||||
}
|
||||
]
|
||||
}));
|
||||
update((p) => ({
|
||||
...p,
|
||||
tasks: [
|
||||
...p.tasks,
|
||||
{
|
||||
id: '3397fecdedb13397fecdedb3',
|
||||
title: 'Create visual design',
|
||||
checked: false
|
||||
}
|
||||
]
|
||||
}));
|
||||
|
||||
await sleep(250);
|
||||
await sleep(250);
|
||||
|
||||
update((p) => ({
|
||||
...p,
|
||||
tableSlice: p.tableSlice + 1
|
||||
}));
|
||||
update((p) => ({
|
||||
...p,
|
||||
tableSlice: p.tableSlice + 1
|
||||
}));
|
||||
};
|
||||
|
||||
export const databasesController = {
|
||||
execute,
|
||||
state
|
||||
execute,
|
||||
state
|
||||
};
|
||||
|
||||
export const Databases = {
|
||||
Phone,
|
||||
Box,
|
||||
Code
|
||||
Phone,
|
||||
Box,
|
||||
Code
|
||||
};
|
||||
|
||||
@@ -1,127 +1,127 @@
|
||||
<script lang="ts">
|
||||
import { fly } from 'svelte/transition';
|
||||
import { databasesController } from '.';
|
||||
import TaskCheckbox from '../TaskCheckbox.svelte';
|
||||
import { fly } from 'svelte/transition';
|
||||
import { databasesController } from '.';
|
||||
import TaskCheckbox from '../TaskCheckbox.svelte';
|
||||
|
||||
const { state } = databasesController;
|
||||
const { state } = databasesController;
|
||||
</script>
|
||||
|
||||
<div data-theme-ignore class="inner-phone theme-light">
|
||||
<div class="header">
|
||||
<p class="title">Your tasks</p>
|
||||
<span class="icon-menu" aria-label="menu" />
|
||||
</div>
|
||||
<div data-theme-ignore class="inner-phone light">
|
||||
<div class="header">
|
||||
<p class="title">Your tasks</p>
|
||||
<span class="icon-menu" aria-label="menu" />
|
||||
</div>
|
||||
|
||||
<div class="date">Today</div>
|
||||
<div class="tasks">
|
||||
{#each $state.tasks as task (task.id)}
|
||||
<div class="task" data-checked={task.checked ? '' : undefined} in:fly={{ x: -16 }}>
|
||||
<TaskCheckbox bind:checked={task.checked} />
|
||||
<span class="title">{task.title}</span>
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
<div class="date">Today</div>
|
||||
<div class="tasks">
|
||||
{#each $state.tasks as task (task.id)}
|
||||
<div class="task" data-checked={task.checked ? '' : undefined} in:fly={{ x: -16 }}>
|
||||
<TaskCheckbox bind:checked={task.checked} />
|
||||
<span class="title">{task.title}</span>
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
|
||||
<button class="add-btn">
|
||||
<span class="web-icon-plus" />
|
||||
</button>
|
||||
<button class="add-btn">
|
||||
<span class="web-icon-plus" />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<style lang="scss">
|
||||
.inner-phone {
|
||||
padding-block: 3rem;
|
||||
padding-inline: 1rem;
|
||||
.inner-phone {
|
||||
padding-block: 3rem;
|
||||
padding-inline: 1rem;
|
||||
|
||||
color: rgba(67, 67, 71, 1);
|
||||
text-align: left;
|
||||
color: rgba(67, 67, 71, 1);
|
||||
text-align: left;
|
||||
|
||||
position: relative;
|
||||
height: 100%;
|
||||
position: relative;
|
||||
height: 100%;
|
||||
|
||||
.header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
.header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
|
||||
.title {
|
||||
color: var(--color-greyscale-800, #2d2d31);
|
||||
font-family: Inter;
|
||||
font-size: 1rem;
|
||||
font-style: normal;
|
||||
font-weight: 600;
|
||||
line-height: 1.375rem; /* 137.5% */
|
||||
letter-spacing: -0.014rem;
|
||||
}
|
||||
.title {
|
||||
color: var(--color-greyscale-800, #2d2d31);
|
||||
font-family: Inter;
|
||||
font-size: 1rem;
|
||||
font-style: normal;
|
||||
font-weight: 600;
|
||||
line-height: 1.375rem; /* 137.5% */
|
||||
letter-spacing: -0.014rem;
|
||||
}
|
||||
|
||||
[class*='icon-'] {
|
||||
font-size: 1.25rem;
|
||||
color: hsl(var(--web-color-greyscale-500));
|
||||
}
|
||||
}
|
||||
[class*='icon-'] {
|
||||
font-size: 1.25rem;
|
||||
color: hsl(var(--web-color-greyscale-500));
|
||||
}
|
||||
}
|
||||
|
||||
.date {
|
||||
margin-block-start: 3rem;
|
||||
.date {
|
||||
margin-block-start: 3rem;
|
||||
|
||||
color: hsl(var(--web-color-greyscale-600));
|
||||
font-family: Inter;
|
||||
font-size: 0.75rem;
|
||||
font-style: normal;
|
||||
font-weight: 500;
|
||||
line-height: 1.25rem; /* 166.667% */
|
||||
}
|
||||
color: hsl(var(--web-color-greyscale-600));
|
||||
font-family: Inter;
|
||||
font-size: 0.75rem;
|
||||
font-style: normal;
|
||||
font-weight: 500;
|
||||
line-height: 1.25rem; /* 166.667% */
|
||||
}
|
||||
|
||||
.tasks {
|
||||
margin-block-start: 0.5rem;
|
||||
.tasks {
|
||||
margin-block-start: 0.5rem;
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.5rem;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.5rem;
|
||||
|
||||
.task {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.75rem;
|
||||
.task {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.75rem;
|
||||
|
||||
border-radius: 0.5rem;
|
||||
border: 1px solid hsl(var(--web-color-greyscale-50));
|
||||
background: hsl(var(--web-color-white));
|
||||
color: var(--greyscale-700, var(--color-greyscale-700, #56565c));
|
||||
border-radius: 0.5rem;
|
||||
border: 1px solid hsl(var(--web-color-greyscale-50));
|
||||
background: hsl(var(--web-color-white));
|
||||
color: var(--greyscale-700, var(--color-greyscale-700, #56565c));
|
||||
|
||||
padding-block: 0.55rem;
|
||||
padding-inline: 0.88rem;
|
||||
padding-block: 0.55rem;
|
||||
padding-inline: 0.88rem;
|
||||
|
||||
/* Responsive/SubBody-400 */
|
||||
font-family: Inter;
|
||||
font-size: 0.875rem;
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
line-height: 1.375rem; /* 157.143% */
|
||||
letter-spacing: -0.00394rem;
|
||||
/* Responsive/SubBody-400 */
|
||||
font-family: Inter;
|
||||
font-size: 0.875rem;
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
line-height: 1.375rem; /* 157.143% */
|
||||
letter-spacing: -0.00394rem;
|
||||
|
||||
transition: opacity 200ms ease;
|
||||
transition: opacity 200ms ease;
|
||||
|
||||
&[data-checked] {
|
||||
opacity: 0.6;
|
||||
}
|
||||
}
|
||||
}
|
||||
&[data-checked] {
|
||||
opacity: 0.6;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.add-btn {
|
||||
position: absolute;
|
||||
right: 1rem;
|
||||
bottom: 2.5rem;
|
||||
.add-btn {
|
||||
position: absolute;
|
||||
right: 1rem;
|
||||
bottom: 2.5rem;
|
||||
|
||||
width: 2.5rem;
|
||||
height: 2.5rem;
|
||||
flex-shrink: 0;
|
||||
box-shadow: 0px 2px 6px 0px rgba(0, 0, 0, 0.12);
|
||||
background-color: rgba(124, 103, 254, 1);
|
||||
color: rgba(237, 237, 240, 1);
|
||||
font-size: 1.5rem;
|
||||
width: 2.5rem;
|
||||
height: 2.5rem;
|
||||
flex-shrink: 0;
|
||||
box-shadow: 0px 2px 6px 0px rgba(0, 0, 0, 0.12);
|
||||
background-color: rgba(124, 103, 254, 1);
|
||||
color: rgba(237, 237, 240, 1);
|
||||
font-size: 1.5rem;
|
||||
|
||||
display: grid;
|
||||
place-items: center;
|
||||
border-radius: 100%;
|
||||
}
|
||||
}
|
||||
display: grid;
|
||||
place-items: center;
|
||||
border-radius: 100%;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
<script lang="ts">
|
||||
import { portal } from '$lib/actions';
|
||||
import Code from '$lib/animations/CodeWindow/Code.svelte';
|
||||
import { fade } from 'svelte/transition';
|
||||
import { functionsController } from '.';
|
||||
import { portal } from '$lib/actions';
|
||||
import Code from '$lib/animations/CodeWindow/Code.svelte';
|
||||
import { fade } from 'svelte/transition';
|
||||
import { functionsController } from '.';
|
||||
|
||||
let content = `
|
||||
let content = `
|
||||
const userId = req.headers['user-id'];
|
||||
|
||||
if (req.path === '/subscribe') {
|
||||
@@ -18,39 +18,39 @@ if (req.path === '/webhook') {
|
||||
|
||||
return res.json({ success: true });`.trim();
|
||||
|
||||
const { state } = functionsController;
|
||||
const { state } = functionsController;
|
||||
</script>
|
||||
|
||||
<Code {content} />
|
||||
|
||||
<div use:portal={{ target: '#code-bottom' }} class="bottom">
|
||||
{#if $state.submit !== 'idle'}
|
||||
<span class="web-icon-github" in:fade />
|
||||
{/if}
|
||||
{#if $state.submit === 'loading'}
|
||||
<span in:fade>Pushing to GitHub...</span>
|
||||
<div class="loader is-small" in:fade />
|
||||
{:else if $state.submit === 'success'}
|
||||
<span>Deployed to Appwrite Cloud</span>
|
||||
<span class="web-icon-check" />
|
||||
{/if}
|
||||
{#if $state.submit !== 'idle'}
|
||||
<span class="web-icon-github" in:fade />
|
||||
{/if}
|
||||
{#if $state.submit === 'loading'}
|
||||
<span in:fade>Pushing to GitHub...</span>
|
||||
<div class="loader is-small" in:fade />
|
||||
{:else if $state.submit === 'success'}
|
||||
<span>Deployed to Appwrite Cloud</span>
|
||||
<span class="web-icon-check" />
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<style lang="scss">
|
||||
.bottom {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
.bottom {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
|
||||
height: 3rem;
|
||||
padding-inline: 1rem;
|
||||
height: 3rem;
|
||||
padding-inline: 1rem;
|
||||
|
||||
color: var(--color-bw-white, #fff);
|
||||
font-family: Inter;
|
||||
font-size: 0.875rem;
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
line-height: 150%; /* 1.3125rem */
|
||||
letter-spacing: -0.00875rem;
|
||||
}
|
||||
color: var(--color-bw-white, #fff);
|
||||
font-family: Inter;
|
||||
font-size: 0.875rem;
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
line-height: 150%; /* 1.3125rem */
|
||||
letter-spacing: -0.00875rem;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -6,53 +6,53 @@ import { createResettable } from '$lib/utils/resettable';
|
||||
import { getElSelector } from '../Products.svelte';
|
||||
|
||||
type State = {
|
||||
submit: 'idle' | 'loading' | 'success';
|
||||
submit: 'idle' | 'loading' | 'success';
|
||||
};
|
||||
|
||||
const state = createResettable<State>({
|
||||
submit: 'idle'
|
||||
submit: 'idle'
|
||||
});
|
||||
|
||||
const execute = async () => {
|
||||
const phone = getElSelector('phone');
|
||||
const box = getElSelector('box');
|
||||
const code = getElSelector('code');
|
||||
const phone = getElSelector('phone');
|
||||
const box = getElSelector('box');
|
||||
const code = getElSelector('code');
|
||||
|
||||
const { update } = state.reset();
|
||||
const { update } = state.reset();
|
||||
|
||||
await Promise.all([
|
||||
safeAnimate(phone, { x: 430, y: 0, width: '275px' }, { duration: 0.5 })?.finished,
|
||||
safeAnimate(code, { x: 0, y: 200, opacity: 0 }, { duration: 0.5 })?.finished,
|
||||
safeAnimate(box, { opacity: 0 }, { duration: 0.5 })?.finished
|
||||
]);
|
||||
await Promise.all([
|
||||
safeAnimate(phone, { x: 430, y: 0, width: '275px' }, { duration: 0.5 })?.finished,
|
||||
safeAnimate(code, { x: 0, y: 200, opacity: 0 }, { duration: 0.5 })?.finished,
|
||||
safeAnimate(box, { opacity: 0 }, { duration: 0.5 })?.finished
|
||||
]);
|
||||
|
||||
await sleep(250);
|
||||
await sleep(250);
|
||||
|
||||
await safeAnimate(code, { zIndex: 0 }, { duration: 0 })?.finished;
|
||||
await safeAnimate(code, { y: [200 - 16, 200], opacity: 1 }, { duration: 0.5 })?.finished;
|
||||
await safeAnimate(code, { zIndex: 0 }, { duration: 0 })?.finished;
|
||||
await safeAnimate(code, { y: [200 - 16, 200], opacity: 1 }, { duration: 0.5 })?.finished;
|
||||
|
||||
await sleep(250);
|
||||
await sleep(250);
|
||||
|
||||
update((p) => ({
|
||||
...p,
|
||||
submit: 'loading'
|
||||
}));
|
||||
update((p) => ({
|
||||
...p,
|
||||
submit: 'loading'
|
||||
}));
|
||||
|
||||
await sleep(1500);
|
||||
await sleep(1500);
|
||||
|
||||
update((p) => ({
|
||||
...p,
|
||||
submit: 'success'
|
||||
}));
|
||||
update((p) => ({
|
||||
...p,
|
||||
submit: 'success'
|
||||
}));
|
||||
};
|
||||
|
||||
export const functionsController = {
|
||||
execute,
|
||||
state
|
||||
execute,
|
||||
state
|
||||
};
|
||||
|
||||
export const Functions = {
|
||||
Phone,
|
||||
Phone,
|
||||
|
||||
Code
|
||||
Code
|
||||
};
|
||||
|
||||
@@ -1,325 +1,325 @@
|
||||
<script lang="ts">
|
||||
import { flip } from '$lib/utils/flip';
|
||||
import { crossfade, scale, slide } from 'svelte/transition';
|
||||
import { functionsController } from '.';
|
||||
import { flip } from '$lib/utils/flip';
|
||||
import { crossfade, scale, slide } from 'svelte/transition';
|
||||
import { functionsController } from '.';
|
||||
|
||||
const { state } = functionsController;
|
||||
const { state } = functionsController;
|
||||
|
||||
type Method = {
|
||||
icon: string;
|
||||
label: string;
|
||||
};
|
||||
type Method = {
|
||||
icon: string;
|
||||
label: string;
|
||||
};
|
||||
|
||||
$: methods = [
|
||||
$state.submit === 'success' && {
|
||||
icon: '/images/animations/stripe.png',
|
||||
label: 'Stripe'
|
||||
},
|
||||
{
|
||||
icon: '/images/animations/credit-card.svg',
|
||||
label: 'Card'
|
||||
},
|
||||
{
|
||||
icon: '/images/animations/paypal.svg',
|
||||
label: 'PayPal'
|
||||
},
|
||||
{
|
||||
icon: '/images/animations/apple.svg',
|
||||
label: 'Apple'
|
||||
}
|
||||
].filter(Boolean) as Method[];
|
||||
$: methods = [
|
||||
$state.submit === 'success' && {
|
||||
icon: '/images/animations/stripe.png',
|
||||
label: 'Stripe'
|
||||
},
|
||||
{
|
||||
icon: '/images/animations/credit-card.svg',
|
||||
label: 'Card'
|
||||
},
|
||||
{
|
||||
icon: '/images/animations/paypal.svg',
|
||||
label: 'PayPal'
|
||||
},
|
||||
{
|
||||
icon: '/images/animations/apple.svg',
|
||||
label: 'Apple'
|
||||
}
|
||||
].filter(Boolean) as Method[];
|
||||
</script>
|
||||
|
||||
<div data-theme-ignore class="inner-phone theme-light">
|
||||
<div class="header">
|
||||
<p class="title">Upgrade plan</p>
|
||||
<span class="icon-menu" aria-label="menu" />
|
||||
</div>
|
||||
<div data-theme-ignore class="inner-phone light">
|
||||
<div class="header">
|
||||
<p class="title">Upgrade plan</p>
|
||||
<span class="icon-menu" aria-label="menu" />
|
||||
</div>
|
||||
|
||||
<div class="plan">
|
||||
<p class="title">Premium plan</p>
|
||||
<div class="subscription">
|
||||
<p class="price">$20</p>
|
||||
<p class="period">/month</p>
|
||||
</div>
|
||||
<ul>
|
||||
<li>Premium plan</li>
|
||||
<li>Premium plan</li>
|
||||
<li>Premium plan</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="plan">
|
||||
<p class="title">Premium plan</p>
|
||||
<div class="subscription">
|
||||
<p class="price">$20</p>
|
||||
<p class="period">/month</p>
|
||||
</div>
|
||||
<ul>
|
||||
<li>Premium plan</li>
|
||||
<li>Premium plan</li>
|
||||
<li>Premium plan</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<ul class="methods">
|
||||
{#each methods as method, i (method.label)}
|
||||
<li
|
||||
in:scale={{ delay: 150 }}
|
||||
animate:flip={{ duration: 500 }}
|
||||
data-active={i == 0 ? '' : undefined}
|
||||
>
|
||||
<img src={method.icon} alt="" />
|
||||
<p>{method.label}</p>
|
||||
</li>
|
||||
{/each}
|
||||
</ul>
|
||||
<ul class="methods">
|
||||
{#each methods as method, i (method.label)}
|
||||
<li
|
||||
in:scale={{ delay: 150 }}
|
||||
animate:flip={{ duration: 500 }}
|
||||
data-active={i == 0 ? '' : undefined}
|
||||
>
|
||||
<img src={method.icon} alt="" />
|
||||
<p>{method.label}</p>
|
||||
</li>
|
||||
{/each}
|
||||
</ul>
|
||||
|
||||
{#if $state.submit !== 'success'}
|
||||
<div class="form">
|
||||
<p>Card information</p>
|
||||
<div class="bordered">
|
||||
<div>
|
||||
<p>placeholder</p>
|
||||
<img src="/images/animations/visa.png" alt="" />
|
||||
<img src="/images/animations/mastercard.png" alt="" />
|
||||
</div>
|
||||
<div>
|
||||
<p>MM/YY</p>
|
||||
<p>CVV</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
{#if $state.submit !== 'success'}
|
||||
<div class="form">
|
||||
<p>Card information</p>
|
||||
<div class="bordered">
|
||||
<div>
|
||||
<p>placeholder</p>
|
||||
<img src="/images/animations/visa.png" alt="" />
|
||||
<img src="/images/animations/mastercard.png" alt="" />
|
||||
</div>
|
||||
<div>
|
||||
<p>MM/YY</p>
|
||||
<p>CVV</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<button>
|
||||
Pay $20.00
|
||||
{#if $state.submit === 'success'}
|
||||
<span in:slide={{ axis: 'x' }}>on Stripe</span>
|
||||
{/if}
|
||||
</button>
|
||||
<button>
|
||||
Pay $20.00
|
||||
{#if $state.submit === 'success'}
|
||||
<span in:slide={{ axis: 'x' }}>on Stripe</span>
|
||||
{/if}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<style lang="scss">
|
||||
.inner-phone {
|
||||
padding-block: 3rem 1.5rem;
|
||||
padding-inline: 1rem;
|
||||
.inner-phone {
|
||||
padding-block: 3rem 1.5rem;
|
||||
padding-inline: 1rem;
|
||||
|
||||
color: rgba(67, 67, 71, 1);
|
||||
text-align: left;
|
||||
color: rgba(67, 67, 71, 1);
|
||||
text-align: left;
|
||||
|
||||
position: relative;
|
||||
height: 100%;
|
||||
overflow: visible;
|
||||
position: relative;
|
||||
height: 100%;
|
||||
overflow: visible;
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
.header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
|
||||
.title {
|
||||
color: #434347;
|
||||
font-family: Inter;
|
||||
font-size: 1rem;
|
||||
font-style: normal;
|
||||
font-weight: 600;
|
||||
line-height: 1.375rem; /* 137.5% */
|
||||
letter-spacing: -0.014rem;
|
||||
}
|
||||
.title {
|
||||
color: #434347;
|
||||
font-family: Inter;
|
||||
font-size: 1rem;
|
||||
font-style: normal;
|
||||
font-weight: 600;
|
||||
line-height: 1.375rem; /* 137.5% */
|
||||
letter-spacing: -0.014rem;
|
||||
}
|
||||
|
||||
[class*='icon-'] {
|
||||
font-size: 1.25rem;
|
||||
color: hsl(var(--web-color-greyscale-500));
|
||||
}
|
||||
}
|
||||
[class*='icon-'] {
|
||||
font-size: 1.25rem;
|
||||
color: hsl(var(--web-color-greyscale-500));
|
||||
}
|
||||
}
|
||||
|
||||
.plan {
|
||||
display: flex;
|
||||
padding: 0.75rem 1rem;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: flex-start;
|
||||
.plan {
|
||||
display: flex;
|
||||
padding: 0.75rem 1rem;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: flex-start;
|
||||
|
||||
border-radius: 0.75rem;
|
||||
background: rgba(237, 237, 240, 0.5);
|
||||
border-radius: 0.75rem;
|
||||
background: rgba(237, 237, 240, 0.5);
|
||||
|
||||
margin-block-start: 1rem;
|
||||
margin-block-start: 1rem;
|
||||
|
||||
.title {
|
||||
color: var(--color-greyscale-700, #56565c);
|
||||
font-family: Inter;
|
||||
font-size: 0.75rem;
|
||||
font-style: normal;
|
||||
font-weight: 700;
|
||||
line-height: 1.25rem; /* 166.667% */
|
||||
}
|
||||
.title {
|
||||
color: var(--color-greyscale-700, #56565c);
|
||||
font-family: Inter;
|
||||
font-size: 0.75rem;
|
||||
font-style: normal;
|
||||
font-weight: 700;
|
||||
line-height: 1.25rem; /* 166.667% */
|
||||
}
|
||||
|
||||
.subscription {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
margin-block-start: 0.15rem;
|
||||
.subscription {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
margin-block-start: 0.15rem;
|
||||
|
||||
.price {
|
||||
color: var(--greyscale-700, var(--color-greyscale-700, #56565c));
|
||||
font-family: Inter;
|
||||
font-size: 1.125rem;
|
||||
font-style: normal;
|
||||
font-weight: 700;
|
||||
line-height: 1.25rem; /* 111.111% */
|
||||
}
|
||||
.price {
|
||||
color: var(--greyscale-700, var(--color-greyscale-700, #56565c));
|
||||
font-family: Inter;
|
||||
font-size: 1.125rem;
|
||||
font-style: normal;
|
||||
font-weight: 700;
|
||||
line-height: 1.25rem; /* 111.111% */
|
||||
}
|
||||
|
||||
.period {
|
||||
color: var(--greyscale-700, var(--color-greyscale-700, #56565c));
|
||||
font-family: Inter;
|
||||
font-size: 0.75rem;
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
line-height: 1.25rem;
|
||||
}
|
||||
}
|
||||
.period {
|
||||
color: var(--greyscale-700, var(--color-greyscale-700, #56565c));
|
||||
font-family: Inter;
|
||||
font-size: 0.75rem;
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
line-height: 1.25rem;
|
||||
}
|
||||
}
|
||||
|
||||
ul {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.125rem;
|
||||
margin-block-start: 0.75rem;
|
||||
ul {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.125rem;
|
||||
margin-block-start: 0.75rem;
|
||||
|
||||
li {
|
||||
color: var(--color-greyscale-500, #818186);
|
||||
font-family: Inter;
|
||||
font-size: 0.75rem;
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
line-height: 1.25rem; /* 166.667% */
|
||||
li {
|
||||
color: var(--color-greyscale-500, #818186);
|
||||
font-family: Inter;
|
||||
font-size: 0.75rem;
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
line-height: 1.25rem; /* 166.667% */
|
||||
|
||||
padding-inline-start: 1.5rem;
|
||||
padding-inline-start: 1.5rem;
|
||||
|
||||
position: relative;
|
||||
position: relative;
|
||||
|
||||
&::before {
|
||||
content: '';
|
||||
display: block;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
width: 1rem;
|
||||
height: 1rem;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
&::before {
|
||||
content: '';
|
||||
display: block;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
width: 1rem;
|
||||
height: 1rem;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
|
||||
background-image: url('/images/animations/check-circle.svg');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
background-image: url('/images/animations/check-circle.svg');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.methods {
|
||||
margin-block-start: 1.25rem;
|
||||
.methods {
|
||||
margin-block-start: 1.25rem;
|
||||
|
||||
display: flex;
|
||||
gap: 0.75rem;
|
||||
overflow: hidden;
|
||||
margin-inline: -1rem;
|
||||
padding-inline: 1rem;
|
||||
display: flex;
|
||||
gap: 0.75rem;
|
||||
overflow: hidden;
|
||||
margin-inline: -1rem;
|
||||
padding-inline: 1rem;
|
||||
|
||||
li {
|
||||
flex-shrink: 0;
|
||||
li {
|
||||
flex-shrink: 0;
|
||||
|
||||
display: flex;
|
||||
width: 5.5rem;
|
||||
padding: 0.75rem 0.75rem 0.625rem 0.75rem;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: flex-start;
|
||||
gap: 0.125rem;
|
||||
display: flex;
|
||||
width: 5.5rem;
|
||||
padding: 0.75rem 0.75rem 0.625rem 0.75rem;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: flex-start;
|
||||
gap: 0.125rem;
|
||||
|
||||
border-radius: 0.75rem;
|
||||
border: 1px solid var(--greyscale-50, #ededf0);
|
||||
border-radius: 0.75rem;
|
||||
border: 1px solid var(--greyscale-50, #ededf0);
|
||||
|
||||
color: var(--greyscale-700, var(--color-greyscale-700, #56565c));
|
||||
font-family: Inter;
|
||||
font-size: 0.75rem;
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
line-height: 1.25rem; /* 166.667% */
|
||||
color: var(--greyscale-700, var(--color-greyscale-700, #56565c));
|
||||
font-family: Inter;
|
||||
font-size: 0.75rem;
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
line-height: 1.25rem; /* 166.667% */
|
||||
|
||||
&[data-active] {
|
||||
border-color: var(--appwrite-purple, #7c67fe);
|
||||
}
|
||||
}
|
||||
}
|
||||
&[data-active] {
|
||||
border-color: var(--appwrite-purple, #7c67fe);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.form {
|
||||
margin-block-start: 1.25rem;
|
||||
.form {
|
||||
margin-block-start: 1.25rem;
|
||||
|
||||
> p {
|
||||
color: var(--dark-neutrals-150, #373b4d);
|
||||
font-family: Inter;
|
||||
font-size: 0.75rem;
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
line-height: 150%; /* 1.125rem */
|
||||
}
|
||||
> p {
|
||||
color: var(--dark-neutrals-150, #373b4d);
|
||||
font-family: Inter;
|
||||
font-size: 0.75rem;
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
line-height: 150%; /* 1.125rem */
|
||||
}
|
||||
|
||||
.bordered {
|
||||
margin-block-start: 0.25rem;
|
||||
.bordered {
|
||||
margin-block-start: 0.25rem;
|
||||
|
||||
border-radius: 0.5rem;
|
||||
border: 1px solid #ededf0;
|
||||
background: var(--color-bw-white, #fff);
|
||||
border-radius: 0.5rem;
|
||||
border: 1px solid #ededf0;
|
||||
background: var(--color-bw-white, #fff);
|
||||
|
||||
> div:first-child {
|
||||
display: flex;
|
||||
gap: 0.25rem;
|
||||
padding: 0.65rem 0.75rem;
|
||||
border-bottom: 1px solid #ededf0;
|
||||
> div:first-child {
|
||||
display: flex;
|
||||
gap: 0.25rem;
|
||||
padding: 0.65rem 0.75rem;
|
||||
border-bottom: 1px solid #ededf0;
|
||||
|
||||
> :nth-child(2) {
|
||||
margin-inline-start: auto;
|
||||
}
|
||||
}
|
||||
> :nth-child(2) {
|
||||
margin-inline-start: auto;
|
||||
}
|
||||
}
|
||||
|
||||
> div:nth-child(2) {
|
||||
display: flex;
|
||||
> div:nth-child(2) {
|
||||
display: flex;
|
||||
|
||||
> p {
|
||||
padding: 0.65rem 0.75rem;
|
||||
}
|
||||
> p {
|
||||
padding: 0.65rem 0.75rem;
|
||||
}
|
||||
|
||||
> p:first-child {
|
||||
flex-grow: 3;
|
||||
}
|
||||
> p:first-child {
|
||||
flex-grow: 3;
|
||||
}
|
||||
|
||||
> p:last-child {
|
||||
flex-grow: 1;
|
||||
border-inline-start: 1px solid #ededf0;
|
||||
}
|
||||
}
|
||||
> p:last-child {
|
||||
flex-grow: 1;
|
||||
border-inline-start: 1px solid #ededf0;
|
||||
}
|
||||
}
|
||||
|
||||
p {
|
||||
color: var(--light-neutrals-50, #c4c6d7);
|
||||
font-family: Inter;
|
||||
font-size: 0.75rem;
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
line-height: 150%; /* 1.125rem */
|
||||
}
|
||||
}
|
||||
}
|
||||
p {
|
||||
color: var(--light-neutrals-50, #c4c6d7);
|
||||
font-family: Inter;
|
||||
font-size: 0.75rem;
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
line-height: 150%; /* 1.125rem */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
> button {
|
||||
display: flex;
|
||||
text-align: center;
|
||||
padding: 0.5rem 1rem;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
gap: 0.25rem;
|
||||
> button {
|
||||
display: flex;
|
||||
text-align: center;
|
||||
padding: 0.5rem 1rem;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
gap: 0.25rem;
|
||||
|
||||
border-radius: 0.5rem;
|
||||
background: var(--appwrite-purple, #7c67fe);
|
||||
box-shadow: 0px 4px 8px 0px rgba(0, 0, 0, 0.06);
|
||||
border-radius: 0.5rem;
|
||||
background: var(--appwrite-purple, #7c67fe);
|
||||
box-shadow: 0px 4px 8px 0px rgba(0, 0, 0, 0.06);
|
||||
|
||||
color: var(--color-bw-white, #fff);
|
||||
text-align: center;
|
||||
font-family: Inter;
|
||||
font-size: 0.875rem;
|
||||
font-style: normal;
|
||||
font-weight: 500;
|
||||
line-height: 1.375rem; /* 157.143% */
|
||||
letter-spacing: -0.01225rem;
|
||||
color: var(--color-bw-white, #fff);
|
||||
text-align: center;
|
||||
font-family: Inter;
|
||||
font-size: 0.875rem;
|
||||
font-style: normal;
|
||||
font-weight: 500;
|
||||
line-height: 1.375rem; /* 157.143% */
|
||||
letter-spacing: -0.01225rem;
|
||||
|
||||
margin-block-start: auto;
|
||||
margin-block-start: auto;
|
||||
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<div data-theme-ignore class="inner-phone theme-light">
|
||||
<div data-theme-ignore class="inner-phone light">
|
||||
<div class="header">
|
||||
<p class="title">Your tasks</p>
|
||||
<span class="icon-menu" aria-label="menu" />
|
||||
|
||||
@@ -12,42 +12,42 @@ const executions = createResettable(0);
|
||||
const realtime = createResettable(0);
|
||||
|
||||
const execute = async () => {
|
||||
const phone = getElSelector('phone');
|
||||
const pd = getElSelector('pd');
|
||||
const phone = getElSelector('phone');
|
||||
const pd = getElSelector('pd');
|
||||
|
||||
const graphBox = getElSelector('graph-box');
|
||||
const graphBox = getElSelector('graph-box');
|
||||
|
||||
const boxesAndStates = [
|
||||
{ box: getElSelector('post-auth'), state: authentication.reset() },
|
||||
{ box: getElSelector('post-storage'), state: storage.reset() },
|
||||
{ box: getElSelector('post-bandwidth'), state: bandwidth.reset() },
|
||||
{ box: getElSelector('post-functions'), state: executions.reset() },
|
||||
{ box: getElSelector('post-databases'), state: databases.reset() },
|
||||
{ box: getElSelector('post-realtime'), state: realtime.reset() },
|
||||
{ box: getElSelector('post-requests'), state: requests.reset() }
|
||||
];
|
||||
const boxesAndStates = [
|
||||
{ box: getElSelector('post-auth'), state: authentication.reset() },
|
||||
{ box: getElSelector('post-storage'), state: storage.reset() },
|
||||
{ box: getElSelector('post-bandwidth'), state: bandwidth.reset() },
|
||||
{ box: getElSelector('post-functions'), state: executions.reset() },
|
||||
{ box: getElSelector('post-databases'), state: databases.reset() },
|
||||
{ box: getElSelector('post-realtime'), state: realtime.reset() },
|
||||
{ box: getElSelector('post-requests'), state: requests.reset() }
|
||||
];
|
||||
|
||||
await Promise.all([
|
||||
safeAnimate(pd, { opacity: 0, y: -16 }, { duration: 0.5 })?.finished,
|
||||
safeAnimate(graphBox, { opacity: 0, visibility: 'hidden' }, { duration: 0.5 })?.finished,
|
||||
safeAnimate(phone, { x: '-50%', width: '660px' }, { duration: 1, delay: 0.5 })?.finished
|
||||
]);
|
||||
await Promise.all([
|
||||
safeAnimate(pd, { opacity: 0, y: -16 }, { duration: 0.5 })?.finished,
|
||||
safeAnimate(graphBox, { opacity: 0, visibility: 'hidden' }, { duration: 0.5 })?.finished,
|
||||
safeAnimate(phone, { x: '-50%', width: '660px' }, { duration: 1, delay: 0.5 })?.finished
|
||||
]);
|
||||
|
||||
boxesAndStates.forEach(({ box, state }, i) => {
|
||||
safeAnimate(box, { opacity: 1, y: [1200, 0] }, { duration: 0.5, delay: i * 0.1 })?.finished;
|
||||
animate(state.set, { duration: 2, delay: (i + 1) * 0.25 });
|
||||
});
|
||||
boxesAndStates.forEach(({ box, state }, i) => {
|
||||
safeAnimate(box, { opacity: 1, y: [1200, 0] }, { duration: 0.5, delay: i * 0.1 })?.finished;
|
||||
animate(state.set, { duration: 2, delay: (i + 1) * 0.25 });
|
||||
});
|
||||
};
|
||||
|
||||
export const postController = {
|
||||
execute,
|
||||
state: {
|
||||
requests,
|
||||
databases,
|
||||
authentication,
|
||||
storage,
|
||||
bandwidth,
|
||||
executions,
|
||||
realtime
|
||||
}
|
||||
execute,
|
||||
state: {
|
||||
requests,
|
||||
databases,
|
||||
authentication,
|
||||
storage,
|
||||
bandwidth,
|
||||
executions,
|
||||
realtime
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,297 +1,300 @@
|
||||
<script lang="ts">
|
||||
import { toScale } from '$lib/utils/toScale';
|
||||
import { postController } from '.';
|
||||
import { elId } from '../Products.svelte';
|
||||
import { toScale } from '$lib/utils/toScale';
|
||||
import { postController } from '.';
|
||||
import { elId } from '../Products.svelte';
|
||||
|
||||
const {
|
||||
state: { authentication, bandwidth, databases, executions, requests, storage, realtime }
|
||||
} = postController;
|
||||
const {
|
||||
state: { authentication, bandwidth, databases, executions, requests, storage, realtime }
|
||||
} = postController;
|
||||
|
||||
const formatK = (num: number) => {
|
||||
if (num > 999) {
|
||||
return `${(num / 1000).toFixed(1)}K`;
|
||||
}
|
||||
return Math.floor(num);
|
||||
};
|
||||
const formatK = (num: number) => {
|
||||
if (num > 999) {
|
||||
return `${(num / 1000).toFixed(1)}K`;
|
||||
}
|
||||
return Math.floor(num);
|
||||
};
|
||||
</script>
|
||||
|
||||
<div class="gradient-box auth" id="post-auth-{$elId}">
|
||||
<div class="u-flex u-cross-center u-gap-8">
|
||||
<p class="icon-user-group" />
|
||||
<p class="f-eyebrow">Authentication</p>
|
||||
</div>
|
||||
<p class="f-display mbs-16">{formatK(toScale($authentication, [0, 1], [0, 4000]))}</p>
|
||||
<div class="u-flex u-cross-center justify-between mbs-4">
|
||||
<p class="f-sub">Users</p>
|
||||
<p class="f-idk">Sessions: 20K</p>
|
||||
</div>
|
||||
<div class="flex u-cross-center gap-2">
|
||||
<p class="icon-user-group" />
|
||||
<p class="f-eyebrow">Authentication</p>
|
||||
</div>
|
||||
<p class="f-display mbs-16">{formatK(toScale($authentication, [0, 1], [0, 4000]))}</p>
|
||||
<div class="flex u-cross-center justify-between mbs-4">
|
||||
<p class="f-sub">Users</p>
|
||||
<p class="f-idk">Sessions: 20K</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="gradient-box storage" id="post-storage-{$elId}">
|
||||
<div class="u-flex u-cross-center u-gap-8">
|
||||
<p class="icon-folder" />
|
||||
<p class="f-eyebrow">Storage</p>
|
||||
</div>
|
||||
<p class="f-display mbs-16">
|
||||
{toScale($storage, [0, 1], [0, 8]).toFixed(1)} <span class="f-tiny-display">GB</span>
|
||||
</p>
|
||||
<div class="u-flex u-cross-center justify-between mbs-4">
|
||||
<p class="f-sub">Storage</p>
|
||||
<p class="f-idk">Buckets: 44</p>
|
||||
</div>
|
||||
<div class="flex u-cross-center gap-2">
|
||||
<p class="icon-folder" />
|
||||
<p class="f-eyebrow">Storage</p>
|
||||
</div>
|
||||
<p class="f-display mbs-16">
|
||||
{toScale($storage, [0, 1], [0, 8]).toFixed(1)} <span class="f-tiny-display">GB</span>
|
||||
</p>
|
||||
<div class="flex u-cross-center justify-between mbs-4">
|
||||
<p class="f-sub">Storage</p>
|
||||
<p class="f-idk">Buckets: 44</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="gradient-box bandwidth" id="post-bandwidth-{$elId}">
|
||||
<p class="f-display">
|
||||
{toScale($bandwidth, [0, 1], [0, 1.2]).toFixed(2)} <span class="f-tiny-display">GB</span>
|
||||
</p>
|
||||
<p class="f-sub">Bandwidth</p>
|
||||
<img class="mbs-16" src="./images/animations/bandwidth-graph.svg" alt="" />
|
||||
<p class="f-display">
|
||||
{toScale($bandwidth, [0, 1], [0, 1.2]).toFixed(2)} <span class="f-tiny-display">GB</span>
|
||||
</p>
|
||||
<p class="f-sub">Bandwidth</p>
|
||||
<img class="mbs-16" src="./images/animations/bandwidth-graph.svg" alt="" />
|
||||
</div>
|
||||
|
||||
<div class="gradient-box functions" id="post-functions-{$elId}">
|
||||
<div class="u-flex u-cross-center u-gap-8">
|
||||
<p class="icon-lightning-bolt" />
|
||||
<p class="f-eyebrow">Functions</p>
|
||||
</div>
|
||||
<p class="f-display mbs-16">{toScale($executions, [0, 1], [0, 846]).toFixed(0)}</p>
|
||||
<div class="u-flex u-cross-center justify-between mbs-4">
|
||||
<p class="f-sub">Executions</p>
|
||||
</div>
|
||||
<div class="flex u-cross-center gap-2">
|
||||
<p class="icon-lightning-bolt" />
|
||||
<p class="f-eyebrow">Functions</p>
|
||||
</div>
|
||||
<p class="f-display mbs-16">{toScale($executions, [0, 1], [0, 846]).toFixed(0)}</p>
|
||||
<div class="flex u-cross-center justify-between mbs-4">
|
||||
<p class="f-sub">Executions</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="gradient-box databases" id="post-databases-{$elId}">
|
||||
<div class="u-flex u-cross-center u-gap-8">
|
||||
<p class="icon-database" />
|
||||
<p class="f-eyebrow">Databases</p>
|
||||
</div>
|
||||
<p class="f-display mbs-16">{toScale($databases, [0, 1], [0, 8]).toFixed(0)}</p>
|
||||
<div class="u-flex u-cross-center justify-between mbs-4">
|
||||
<p class="f-sub">Databases</p>
|
||||
<p class="f-idk">Documents: 20</p>
|
||||
</div>
|
||||
<div class="flex u-cross-center gap-2">
|
||||
<p class="icon-database" />
|
||||
<p class="f-eyebrow">Databases</p>
|
||||
</div>
|
||||
<p class="f-display mbs-16">{toScale($databases, [0, 1], [0, 8]).toFixed(0)}</p>
|
||||
<div class="flex u-cross-center justify-between mbs-4">
|
||||
<p class="f-sub">Databases</p>
|
||||
<p class="f-idk">Documents: 20</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="gradient-box requests" id="post-requests-{$elId}">
|
||||
<p class="f-display">{formatK(toScale($requests, [0, 1], [0, 6849]))}</p>
|
||||
<p class="f-sub">Requests</p>
|
||||
<img class="mbs-16" src="./images/animations/requests-graph.svg" alt="" />
|
||||
<p class="f-display">{formatK(toScale($requests, [0, 1], [0, 6849]))}</p>
|
||||
<p class="f-sub">Requests</p>
|
||||
<img class="mbs-16" src="./images/animations/requests-graph.svg" alt="" />
|
||||
</div>
|
||||
|
||||
<div class="gradient-box realtime" id="post-realtime-{$elId}">
|
||||
<p class="f-display">{formatK(toScale($realtime, [0, 1], [0, 100000]))}</p>
|
||||
<p class="f-sub">Realtime connections</p>
|
||||
<img class="mbs-16" src="./images/animations/realtime-graph.svg" alt="" />
|
||||
<p class="f-display">{formatK(toScale($realtime, [0, 1], [0, 100000]))}</p>
|
||||
<p class="f-sub">Realtime connections</p>
|
||||
<img class="mbs-16" src="./images/animations/realtime-graph.svg" alt="" />
|
||||
</div>
|
||||
|
||||
<div class="gradient-overlay u-flex u-flex-vertical">
|
||||
<h3>See your products grow</h3>
|
||||
<p>
|
||||
Keep track of your projects progress on the Appwrite Console and see them grow into products
|
||||
users love and use every day.
|
||||
</p>
|
||||
<div class="gradient-overlay flex u-flex-vertical">
|
||||
<h3>See your products grow</h3>
|
||||
<p>
|
||||
Keep track of your projects progress on the Appwrite Console and see them grow into products
|
||||
users love and use every day.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<style lang="scss">
|
||||
@use '$scss/abstract/mixins/border-gradient' as gradients;
|
||||
|
||||
// Utilities
|
||||
.f-eyebrow {
|
||||
color: #adadb0;
|
||||
/* Eyebrow headings/level 3 */
|
||||
font-family: Inter;
|
||||
font-size: 0.75rem;
|
||||
font-style: normal;
|
||||
font-weight: 500;
|
||||
line-height: 150%; /* 1.125rem */
|
||||
letter-spacing: 0.09rem;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
// Utilities
|
||||
.f-eyebrow {
|
||||
color: #adadb0;
|
||||
/* Eyebrow headings/level 3 */
|
||||
font-family: Inter;
|
||||
font-size: 0.75rem;
|
||||
font-style: normal;
|
||||
font-weight: 500;
|
||||
line-height: 150%; /* 1.125rem */
|
||||
letter-spacing: 0.09rem;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.f-display {
|
||||
color: #ededf0;
|
||||
font-family: Aeonik Pro;
|
||||
font-size: 2rem;
|
||||
font-style: normal;
|
||||
font-weight: 500;
|
||||
line-height: 2.25rem; /* 112.5% */
|
||||
}
|
||||
.f-display {
|
||||
color: #ededf0;
|
||||
font-family: Aeonik Pro;
|
||||
font-size: 2rem;
|
||||
font-style: normal;
|
||||
font-weight: 500;
|
||||
line-height: 2.25rem; /* 112.5% */
|
||||
}
|
||||
|
||||
.f-tiny-display {
|
||||
color: var(--greyscale-50, #ededf0);
|
||||
text-align: center;
|
||||
font-family: Inter;
|
||||
font-size: 0.875rem;
|
||||
font-style: normal;
|
||||
font-weight: 500;
|
||||
line-height: 1rem; /* 114.286% */
|
||||
}
|
||||
.f-tiny-display {
|
||||
color: var(--greyscale-50, #ededf0);
|
||||
text-align: center;
|
||||
font-family: Inter;
|
||||
font-size: 0.875rem;
|
||||
font-style: normal;
|
||||
font-weight: 500;
|
||||
line-height: 1rem; /* 114.286% */
|
||||
}
|
||||
|
||||
.f-sub {
|
||||
color: #97979b;
|
||||
font-family: Inter;
|
||||
font-size: 0.875rem;
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
line-height: 1.125rem; /* 128.571% */
|
||||
}
|
||||
.f-sub {
|
||||
color: #97979b;
|
||||
font-family: Inter;
|
||||
font-size: 0.875rem;
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
line-height: 1.125rem; /* 128.571% */
|
||||
}
|
||||
|
||||
.f-idk {
|
||||
color: var(--primary, #e4e4e7);
|
||||
text-align: right;
|
||||
font-family: Inter;
|
||||
font-size: 0.875rem;
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
line-height: 150%; /* 1.3125rem */
|
||||
opacity: 40%;
|
||||
}
|
||||
.f-idk {
|
||||
color: var(--primary, #e4e4e7);
|
||||
text-align: right;
|
||||
font-family: Inter;
|
||||
font-size: 0.875rem;
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
line-height: 150%; /* 1.3125rem */
|
||||
opacity: 40%;
|
||||
}
|
||||
|
||||
.mbs-16 {
|
||||
margin-block-start: 1rem;
|
||||
}
|
||||
.mbs-16 {
|
||||
margin-block-start: 1rem;
|
||||
}
|
||||
|
||||
.mbs-4 {
|
||||
margin-block-start: 0.25rem;
|
||||
}
|
||||
.mbs-4 {
|
||||
margin-block-start: 0.25rem;
|
||||
}
|
||||
|
||||
.justify-between {
|
||||
justify-content: space-between;
|
||||
}
|
||||
.justify-between {
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
// Components
|
||||
.gradient-box {
|
||||
@include gradients.border-gradient;
|
||||
--m-border-gradient-before: linear-gradient(
|
||||
180deg,
|
||||
rgba(255, 255, 255, 0.12) 0%,
|
||||
rgba(255, 255, 255, 0) 125.11%
|
||||
);
|
||||
--m-border-radius: 1rem;
|
||||
// Components
|
||||
.gradient-box {
|
||||
@include gradients.border-gradient;
|
||||
--m-border-gradient-before: linear-gradient(
|
||||
180deg,
|
||||
rgba(255, 255, 255, 0.12) 0%,
|
||||
rgba(255, 255, 255, 0) 125.11%
|
||||
);
|
||||
--m-border-radius: 1rem;
|
||||
|
||||
position: absolute;
|
||||
background: var(--card, rgba(35, 35, 37, 0.9));
|
||||
box-shadow: 0px 0px 0px 0px rgba(0, 0, 0, 0.06), -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(8px);
|
||||
position: absolute;
|
||||
background: var(--card, rgba(35, 35, 37, 0.9));
|
||||
box-shadow:
|
||||
0px 0px 0px 0px rgba(0, 0, 0, 0.06),
|
||||
-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(8px);
|
||||
|
||||
padding: 1.5rem;
|
||||
padding: 1.5rem;
|
||||
|
||||
z-index: 9999;
|
||||
z-index: 9999;
|
||||
|
||||
min-width: 20rem;
|
||||
}
|
||||
min-width: 20rem;
|
||||
}
|
||||
|
||||
@keyframes fadeIn {
|
||||
0% {
|
||||
opacity: 0;
|
||||
}
|
||||
100% {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
@keyframes fadeIn {
|
||||
0% {
|
||||
opacity: 0;
|
||||
}
|
||||
100% {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.gradient-overlay {
|
||||
position: absolute;
|
||||
z-index: 100;
|
||||
bottom: -7.5rem;
|
||||
width: 100%;
|
||||
height: 30rem;
|
||||
.gradient-overlay {
|
||||
position: absolute;
|
||||
z-index: 100;
|
||||
bottom: -7.5rem;
|
||||
width: 100%;
|
||||
height: 30rem;
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 1.25rem;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 1.25rem;
|
||||
|
||||
padding-block-start: 15rem;
|
||||
padding-block-start: 15rem;
|
||||
|
||||
opacity: 0;
|
||||
animation: fadeIn 0.75s ease-in-out 1.5s forwards;
|
||||
opacity: 0;
|
||||
animation: fadeIn 0.75s ease-in-out 1.5s forwards;
|
||||
|
||||
&::before {
|
||||
content: '';
|
||||
inset: 0;
|
||||
position: absolute;
|
||||
//background: #19191d; // old bg
|
||||
//filter: blur(125px); // break Safari
|
||||
background: #19191dcc;
|
||||
filter: blur(67px);
|
||||
&::before {
|
||||
content: '';
|
||||
inset: 0;
|
||||
position: absolute;
|
||||
//background: #19191d; // old bg
|
||||
//filter: blur(125px); // break Safari
|
||||
background: #19191dcc;
|
||||
filter: blur(67px);
|
||||
}
|
||||
|
||||
}
|
||||
h3 {
|
||||
position: relative;
|
||||
color: var(--primary, #e4e4e7);
|
||||
text-align: center;
|
||||
|
||||
h3 {
|
||||
position: relative;
|
||||
color: var(--primary, #e4e4e7);
|
||||
text-align: center;
|
||||
/* Desktop/Display */
|
||||
font-family: Aeonik Pro;
|
||||
font-size: 4rem;
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
line-height: 4.25rem; /* 106.25% */
|
||||
letter-spacing: -0.04rem;
|
||||
}
|
||||
|
||||
/* Desktop/Display */
|
||||
font-family: Aeonik Pro;
|
||||
font-size: 4rem;
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
line-height: 4.25rem; /* 106.25% */
|
||||
letter-spacing: -0.04rem;
|
||||
}
|
||||
p {
|
||||
position: relative;
|
||||
|
||||
p {
|
||||
position: relative;
|
||||
color: var(--secondary, #adadb0);
|
||||
text-align: center;
|
||||
|
||||
color: var(--secondary, #adadb0);
|
||||
text-align: center;
|
||||
/* Desktop/Description */
|
||||
font-family: Inter;
|
||||
font-size: 1.25rem;
|
||||
font-style: normal;
|
||||
font-weight: 500;
|
||||
line-height: 1.75rem; /* 140% */
|
||||
letter-spacing: -0.0175rem;
|
||||
max-width: 40rem;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
|
||||
/* Desktop/Description */
|
||||
font-family: Inter;
|
||||
font-size: 1.25rem;
|
||||
font-style: normal;
|
||||
font-weight: 500;
|
||||
line-height: 1.75rem; /* 140% */
|
||||
letter-spacing: -0.0175rem;
|
||||
max-width: 40rem;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
// Specifics
|
||||
.auth {
|
||||
opacity: 0;
|
||||
left: 4rem;
|
||||
top: -11rem;
|
||||
}
|
||||
|
||||
// Specifics
|
||||
.auth {
|
||||
opacity: 0;
|
||||
left: 4rem;
|
||||
top: -11rem;
|
||||
}
|
||||
.storage {
|
||||
opacity: 0;
|
||||
left: -10rem;
|
||||
top: -2rem;
|
||||
}
|
||||
|
||||
.storage {
|
||||
opacity: 0;
|
||||
left: -10rem;
|
||||
top: -2rem;
|
||||
}
|
||||
.bandwidth {
|
||||
opacity: 0;
|
||||
left: -4rem;
|
||||
top: 11rem;
|
||||
}
|
||||
|
||||
.bandwidth {
|
||||
opacity: 0;
|
||||
left: -4rem;
|
||||
top: 11rem;
|
||||
}
|
||||
.functions {
|
||||
opacity: 0;
|
||||
left: -6rem;
|
||||
top: 35rem;
|
||||
}
|
||||
|
||||
.functions {
|
||||
opacity: 0;
|
||||
left: -6rem;
|
||||
top: 35rem;
|
||||
}
|
||||
.databases {
|
||||
opacity: 0;
|
||||
top: -13rem;
|
||||
right: 10rem;
|
||||
}
|
||||
|
||||
.databases {
|
||||
opacity: 0;
|
||||
top: -13rem;
|
||||
right: 10rem;
|
||||
}
|
||||
.requests {
|
||||
opacity: 0;
|
||||
top: 17rem;
|
||||
right: -18rem;
|
||||
}
|
||||
|
||||
.requests {
|
||||
opacity: 0;
|
||||
top: 17rem;
|
||||
right: -18rem;
|
||||
}
|
||||
|
||||
.realtime {
|
||||
opacity: 0;
|
||||
top: -1rem;
|
||||
right: -7rem;
|
||||
}
|
||||
.realtime {
|
||||
opacity: 0;
|
||||
top: -1rem;
|
||||
right: -7rem;
|
||||
}
|
||||
</style>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,39 +1,39 @@
|
||||
<script lang="ts">
|
||||
import { slide } from 'svelte/transition';
|
||||
import { storageController } from '.';
|
||||
import { flip } from '$lib/utils/flip';
|
||||
import { slide } from 'svelte/transition';
|
||||
import { storageController } from '.';
|
||||
import { flip } from '$lib/utils/flip';
|
||||
|
||||
const { state } = storageController;
|
||||
const { state } = storageController;
|
||||
</script>
|
||||
|
||||
<div class="pseudo-table">
|
||||
<div class="header">
|
||||
<span class="web-eyebrow">Filename</span>
|
||||
<span class="web-eyebrow">Type</span>
|
||||
<span class="web-eyebrow">Size</span>
|
||||
</div>
|
||||
{#each $state.files as file (file.src)}
|
||||
<div class="row" in:slide={{ duration: 150 }} animate:flip={{ duration: 150 }}>
|
||||
<div class="img-wrapper">
|
||||
<img src={file.src} alt="" />
|
||||
<span>{file.filename}</span>
|
||||
</div>
|
||||
<span class="truncated">{file.type}</span>
|
||||
<span class="truncated">{file.size}</span>
|
||||
</div>
|
||||
{/each}
|
||||
<div class="header">
|
||||
<span class="web-eyebrow">Filename</span>
|
||||
<span class="web-eyebrow">Type</span>
|
||||
<span class="web-eyebrow">Size</span>
|
||||
</div>
|
||||
{#each $state.files as file (file.src)}
|
||||
<div class="row" in:slide={{ duration: 150 }} animate:flip={{ duration: 150 }}>
|
||||
<div class="img-wrapper">
|
||||
<img src={file.src} alt="" />
|
||||
<span>{file.filename}</span>
|
||||
</div>
|
||||
<span class="truncated">{file.type}</span>
|
||||
<span class="truncated">{file.size}</span>
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
|
||||
<style lang="scss">
|
||||
.header,
|
||||
.row {
|
||||
grid-template-columns: 7rem 1fr 1fr !important;
|
||||
gap: 1.5rem 3rem;
|
||||
}
|
||||
.header,
|
||||
.row {
|
||||
grid-template-columns: 7rem 1fr 1fr !important;
|
||||
gap: 1.5rem 3rem;
|
||||
}
|
||||
|
||||
.img-wrapper {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
.img-wrapper {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<script lang="ts">
|
||||
import Code from '$lib/animations/CodeWindow/Code.svelte';
|
||||
import Code from '$lib/animations/CodeWindow/Code.svelte';
|
||||
|
||||
let content = `
|
||||
let content = `
|
||||
const result = storage.createFile(
|
||||
'my-bucket',
|
||||
ID.unique(),
|
||||
|
||||
@@ -7,130 +7,131 @@ import { createResettable } from '$lib/utils/resettable';
|
||||
import { getElSelector } from '../Products.svelte';
|
||||
|
||||
type File = {
|
||||
src: string;
|
||||
filename: string;
|
||||
type: string;
|
||||
size: string;
|
||||
src: string;
|
||||
filename: string;
|
||||
type: string;
|
||||
size: string;
|
||||
};
|
||||
|
||||
type State = {
|
||||
files: File[];
|
||||
files: File[];
|
||||
};
|
||||
|
||||
const state = createResettable<State>({
|
||||
files: []
|
||||
files: []
|
||||
});
|
||||
|
||||
const execute = async () => {
|
||||
const phone = getElSelector('phone');
|
||||
const box = getElSelector('box');
|
||||
const code = getElSelector('code');
|
||||
const overlay = getElSelector('overlay');
|
||||
const drawer = getElSelector('drawer');
|
||||
const upload = getElSelector('upload');
|
||||
const uploadBtn = getElSelector('upload-btn');
|
||||
const uploadImg = getElSelector('upload-img');
|
||||
const uploadLoading = getElSelector('upload-loading');
|
||||
const uploadText = getElSelector('upload-text');
|
||||
const phone = getElSelector('phone');
|
||||
const box = getElSelector('box');
|
||||
const code = getElSelector('code');
|
||||
const overlay = getElSelector('overlay');
|
||||
const drawer = getElSelector('drawer');
|
||||
const upload = getElSelector('upload');
|
||||
const uploadBtn = getElSelector('upload-btn');
|
||||
const uploadImg = getElSelector('upload-img');
|
||||
const uploadLoading = getElSelector('upload-loading');
|
||||
const uploadText = getElSelector('upload-text');
|
||||
|
||||
const { update } = state.reset();
|
||||
const { update } = state.reset();
|
||||
|
||||
await Promise.all([
|
||||
safeAnimate(phone, { x: 0, y: 0 }, { duration: 0.5 })?.finished,
|
||||
safeAnimate(box, { opacity: 0 }, { duration: 0.5 })?.finished,
|
||||
safeAnimate(code, { opacity: 0 }, { duration: 0.5 })?.finished,
|
||||
safeAnimate(uploadLoading, { opacity: 0 }, { duration: 0 })?.finished
|
||||
]);
|
||||
await Promise.all([
|
||||
safeAnimate(phone, { x: 0, y: 0 }, { duration: 0.5 })?.finished,
|
||||
safeAnimate(box, { opacity: 0 }, { duration: 0.5 })?.finished,
|
||||
safeAnimate(code, { opacity: 0 }, { duration: 0.5 })?.finished,
|
||||
safeAnimate(uploadLoading, { opacity: 0 }, { duration: 0 })?.finished
|
||||
]);
|
||||
|
||||
await safeAnimate(code, { zIndex: 20 }, { duration: 0 })?.finished;
|
||||
await safeAnimate(code, { zIndex: 20 }, { duration: 0 })?.finished;
|
||||
|
||||
update((p) => ({
|
||||
...p,
|
||||
files: [
|
||||
...p.files,
|
||||
{
|
||||
src: '/images/animations/storage-1.png',
|
||||
filename: 'Profile.png',
|
||||
type: 'image/png',
|
||||
size: '362.6 KB'
|
||||
}
|
||||
]
|
||||
}));
|
||||
update((p) => ({
|
||||
...p,
|
||||
files: [
|
||||
...p.files,
|
||||
{
|
||||
src: '/images/animations/storage-1.png',
|
||||
filename: 'Profile.png',
|
||||
type: 'image/png',
|
||||
size: '362.6 KB'
|
||||
}
|
||||
]
|
||||
}));
|
||||
|
||||
await sleep(250);
|
||||
await sleep(250);
|
||||
|
||||
await Promise.all([
|
||||
safeAnimate(overlay, { opacity: 1 }, { duration: 0.25 })?.finished,
|
||||
safeAnimate(drawer, { y: [128, 0], opacity: 1 }, { duration: 0.5 })?.finished
|
||||
]);
|
||||
await Promise.all([
|
||||
safeAnimate(overlay, { opacity: 1 }, { duration: 0.25 })?.finished,
|
||||
safeAnimate(drawer, { y: [128, 0], opacity: 1 }, { duration: 0.5 })?.finished
|
||||
]);
|
||||
|
||||
await sleep(250);
|
||||
await sleep(250);
|
||||
|
||||
await safeAnimate(uploadBtn, { scale: [1, 0.9, 1] }, { duration: 0.25 })?.finished;
|
||||
await safeAnimate(uploadBtn, { scale: [1, 0.9, 1] }, { duration: 0.25 })?.finished;
|
||||
|
||||
await safeAnimate(code, { x: 300, y: 32 }, { duration: 0 })?.finished;
|
||||
await safeAnimate(code, { x: 300, y: 32 }, { duration: 0 })?.finished;
|
||||
|
||||
await Promise.all([
|
||||
safeAnimate(code, { y: [32 - 16, 32], opacity: 1 }, { duration: 0.5 })?.finished,
|
||||
safeAnimate(upload, { y: [-16, 0], opacity: 1 }, { duration: 0.5 })?.finished
|
||||
]);
|
||||
await Promise.all([
|
||||
safeAnimate(code, { y: [32 - 16, 32], opacity: 1 }, { duration: 0.5 })?.finished,
|
||||
safeAnimate(upload, { y: [-16, 0], opacity: 1 }, { duration: 0.5 })?.finished
|
||||
]);
|
||||
|
||||
await sleep(250);
|
||||
await sleep(250);
|
||||
|
||||
await safeAnimate(box, { x: 300, y: 300 }, { duration: 0 })?.finished;
|
||||
await safeAnimate(box, { x: 300, y: 300 }, { duration: 0 })?.finished;
|
||||
|
||||
await Promise.all([
|
||||
safeAnimate(uploadImg, { x: [64, 48], y: [80, 64], opacity: 1 }, { duration: 0.5 })?.finished,
|
||||
safeAnimate(box, { y: [300 - 16, 300], opacity: 1 }, { duration: 1 })?.finished
|
||||
]);
|
||||
await Promise.all([
|
||||
safeAnimate(uploadImg, { x: [64, 48], y: [80, 64], opacity: 1 }, { duration: 0.5 })
|
||||
?.finished,
|
||||
safeAnimate(box, { y: [300 - 16, 300], opacity: 1 }, { duration: 1 })?.finished
|
||||
]);
|
||||
|
||||
await sleep(250);
|
||||
await sleep(250);
|
||||
|
||||
await Promise.all([
|
||||
safeAnimate(uploadText, { opacity: 0 }, { duration: 0.5 })?.finished,
|
||||
safeAnimate(uploadLoading, { opacity: 1 }, { duration: 0.5 })?.finished,
|
||||
safeAnimate(uploadImg, { opacity: 0, y: 64 + 8 }, { duration: 0.5 })?.finished
|
||||
]);
|
||||
await sleep(250);
|
||||
await Promise.all([
|
||||
safeAnimate(uploadText, { opacity: 0 }, { duration: 0.5 })?.finished,
|
||||
safeAnimate(uploadLoading, { opacity: 1 }, { duration: 0.5 })?.finished,
|
||||
safeAnimate(uploadImg, { opacity: 0, y: 64 + 8 }, { duration: 0.5 })?.finished
|
||||
]);
|
||||
await sleep(250);
|
||||
|
||||
await safeAnimate(upload, { opacity: 0, y: 48 }, { duration: 0.5 })?.finished;
|
||||
await safeAnimate(upload, { opacity: 0, y: 48 }, { duration: 0.5 })?.finished;
|
||||
|
||||
update((p) => ({
|
||||
...p,
|
||||
files: [
|
||||
...p.files,
|
||||
{
|
||||
src: '/images/animations/storage-2.png',
|
||||
filename: 'Vector.svg',
|
||||
type: 'vector/svg',
|
||||
size: '1.5 KB'
|
||||
}
|
||||
]
|
||||
}));
|
||||
update((p) => ({
|
||||
...p,
|
||||
files: [
|
||||
...p.files,
|
||||
{
|
||||
src: '/images/animations/storage-2.png',
|
||||
filename: 'Vector.svg',
|
||||
type: 'vector/svg',
|
||||
size: '1.5 KB'
|
||||
}
|
||||
]
|
||||
}));
|
||||
|
||||
await sleep(250);
|
||||
await sleep(250);
|
||||
|
||||
update((p) => ({
|
||||
...p,
|
||||
files: [
|
||||
...p.files,
|
||||
{
|
||||
src: '/images/animations/storage-3.png',
|
||||
filename: 'img2.webp',
|
||||
type: 'image/webp',
|
||||
size: '3.2 MB'
|
||||
}
|
||||
]
|
||||
}));
|
||||
update((p) => ({
|
||||
...p,
|
||||
files: [
|
||||
...p.files,
|
||||
{
|
||||
src: '/images/animations/storage-3.png',
|
||||
filename: 'img2.webp',
|
||||
type: 'image/webp',
|
||||
size: '3.2 MB'
|
||||
}
|
||||
]
|
||||
}));
|
||||
};
|
||||
|
||||
export const storageController = {
|
||||
execute,
|
||||
state
|
||||
execute,
|
||||
state
|
||||
};
|
||||
|
||||
export const Storage = {
|
||||
Phone,
|
||||
Box,
|
||||
Code
|
||||
Phone,
|
||||
Box,
|
||||
Code
|
||||
};
|
||||
|
||||
@@ -1,284 +1,284 @@
|
||||
<script lang="ts">
|
||||
import { fly } from 'svelte/transition';
|
||||
import { storageController } from '.';
|
||||
import { elId } from '../Products.svelte';
|
||||
import TaskCheckbox from '../TaskCheckbox.svelte';
|
||||
import { databasesController } from '../databases';
|
||||
import { fly } from 'svelte/transition';
|
||||
import { storageController } from '.';
|
||||
import { elId } from '../Products.svelte';
|
||||
import TaskCheckbox from '../TaskCheckbox.svelte';
|
||||
import { databasesController } from '../databases';
|
||||
|
||||
const { state: dbState } = databasesController;
|
||||
const fixedTasks = $dbState.tasks;
|
||||
const { state: dbState } = databasesController;
|
||||
const fixedTasks = $dbState.tasks;
|
||||
|
||||
const { state } = storageController;
|
||||
const { state } = storageController;
|
||||
</script>
|
||||
|
||||
<div data-theme-ignore class="inner-phone theme-light">
|
||||
<div class="header">
|
||||
<p class="title">Your tasks</p>
|
||||
<span class="icon-menu" aria-label="menu" />
|
||||
</div>
|
||||
<div data-theme-ignore class="inner-phone light">
|
||||
<div class="header">
|
||||
<p class="title">Your tasks</p>
|
||||
<span class="icon-menu" aria-label="menu" />
|
||||
</div>
|
||||
|
||||
<div class="date">Today</div>
|
||||
<div class="tasks">
|
||||
{#each fixedTasks as task (task.id)}
|
||||
<div class="task" data-checked={task.checked ? '' : undefined} in:fly={{ x: -16 }}>
|
||||
<TaskCheckbox bind:checked={task.checked} />
|
||||
<span class="title">{task.title}</span>
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
<div class="date">Today</div>
|
||||
<div class="tasks">
|
||||
{#each fixedTasks as task (task.id)}
|
||||
<div class="task" data-checked={task.checked ? '' : undefined} in:fly={{ x: -16 }}>
|
||||
<TaskCheckbox bind:checked={task.checked} />
|
||||
<span class="title">{task.title}</span>
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
|
||||
<button class="add-btn">
|
||||
<span class="web-icon-plus" />
|
||||
</button>
|
||||
<button class="add-btn">
|
||||
<span class="web-icon-plus" />
|
||||
</button>
|
||||
|
||||
<div class="overlay" id="overlay-{$elId}">
|
||||
<div class="drawer" id="drawer-{$elId}">
|
||||
<p class="title">Edit images for website</p>
|
||||
<p class="subtitle">Edit the attached images to use in the website</p>
|
||||
<div class="overlay" id="overlay-{$elId}">
|
||||
<div class="drawer" id="drawer-{$elId}">
|
||||
<p class="title">Edit images for website</p>
|
||||
<p class="subtitle">Edit the attached images to use in the website</p>
|
||||
|
||||
<div class="upload" id="upload-btn-{$elId}">Upload media...</div>
|
||||
<div class="images">
|
||||
{#each $state.files.slice(1) as file}
|
||||
<img src={file.src} alt="" transition:fly={{ x: 16 }} />
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="upload" id="upload-btn-{$elId}">Upload media...</div>
|
||||
<div class="images">
|
||||
{#each $state.files.slice(1) as file}
|
||||
<img src={file.src} alt="" transition:fly={{ x: 16 }} />
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="upload-media" id="upload-{$elId}">
|
||||
<p class="title">Upload media</p>
|
||||
<div class="drop-zone">
|
||||
<span id="upload-text-{$elId}"> Drop media here </span>
|
||||
<div class="loading-overlay" id="upload-loading-{$elId}">
|
||||
<div class="loader" />
|
||||
</div>
|
||||
</div>
|
||||
<img id="upload-img-{$elId}" src="/images/animations/storage-2.png" alt="" />
|
||||
<p class="title">Upload media</p>
|
||||
<div class="drop-zone">
|
||||
<span id="upload-text-{$elId}"> Drop media here </span>
|
||||
<div class="loading-overlay" id="upload-loading-{$elId}">
|
||||
<div class="loader" />
|
||||
</div>
|
||||
</div>
|
||||
<img id="upload-img-{$elId}" src="/images/animations/storage-2.png" alt="" />
|
||||
</div>
|
||||
|
||||
<style lang="scss">
|
||||
.inner-phone {
|
||||
padding-block: 3rem;
|
||||
padding-inline: 1rem;
|
||||
.inner-phone {
|
||||
padding-block: 3rem;
|
||||
padding-inline: 1rem;
|
||||
|
||||
color: rgba(67, 67, 71, 1);
|
||||
text-align: left;
|
||||
color: rgba(67, 67, 71, 1);
|
||||
text-align: left;
|
||||
|
||||
position: relative;
|
||||
height: 100%;
|
||||
overflow: visible;
|
||||
position: relative;
|
||||
height: 100%;
|
||||
overflow: visible;
|
||||
|
||||
.header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
.header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
|
||||
.title {
|
||||
color: var(--color-greyscale-800, #2d2d31);
|
||||
font-family: Inter;
|
||||
font-size: 1rem;
|
||||
font-style: normal;
|
||||
font-weight: 600;
|
||||
line-height: 1.375rem; /* 137.5% */
|
||||
letter-spacing: -0.014rem;
|
||||
}
|
||||
.title {
|
||||
color: var(--color-greyscale-800, #2d2d31);
|
||||
font-family: Inter;
|
||||
font-size: 1rem;
|
||||
font-style: normal;
|
||||
font-weight: 600;
|
||||
line-height: 1.375rem; /* 137.5% */
|
||||
letter-spacing: -0.014rem;
|
||||
}
|
||||
|
||||
[class*='icon-'] {
|
||||
font-size: 1.25rem;
|
||||
color: hsl(var(--web-color-greyscale-500));
|
||||
}
|
||||
}
|
||||
[class*='icon-'] {
|
||||
font-size: 1.25rem;
|
||||
color: hsl(var(--web-color-greyscale-500));
|
||||
}
|
||||
}
|
||||
|
||||
.date {
|
||||
margin-block-start: 3rem;
|
||||
.date {
|
||||
margin-block-start: 3rem;
|
||||
|
||||
color: hsl(var(--web-color-greyscale-600));
|
||||
font-family: Inter;
|
||||
font-size: 0.75rem;
|
||||
font-style: normal;
|
||||
font-weight: 500;
|
||||
line-height: 1.25rem; /* 166.667% */
|
||||
}
|
||||
color: hsl(var(--web-color-greyscale-600));
|
||||
font-family: Inter;
|
||||
font-size: 0.75rem;
|
||||
font-style: normal;
|
||||
font-weight: 500;
|
||||
line-height: 1.25rem; /* 166.667% */
|
||||
}
|
||||
|
||||
.tasks {
|
||||
margin-block-start: 0.5rem;
|
||||
.tasks {
|
||||
margin-block-start: 0.5rem;
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.5rem;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.5rem;
|
||||
|
||||
.task {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.75rem;
|
||||
.task {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.75rem;
|
||||
|
||||
border-radius: 0.5rem;
|
||||
border: 1px solid hsl(var(--web-color-greyscale-50));
|
||||
background: hsl(var(--web-color-white));
|
||||
color: var(--greyscale-700, var(--color-greyscale-700, #56565c));
|
||||
border-radius: 0.5rem;
|
||||
border: 1px solid hsl(var(--web-color-greyscale-50));
|
||||
background: hsl(var(--web-color-white));
|
||||
color: var(--greyscale-700, var(--color-greyscale-700, #56565c));
|
||||
|
||||
padding-block: 0.55rem;
|
||||
padding-inline: 0.88rem;
|
||||
padding-block: 0.55rem;
|
||||
padding-inline: 0.88rem;
|
||||
|
||||
/* Responsive/SubBody-400 */
|
||||
font-family: Inter;
|
||||
font-size: 0.875rem;
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
line-height: 1.375rem; /* 157.143% */
|
||||
letter-spacing: -0.00394rem;
|
||||
/* Responsive/SubBody-400 */
|
||||
font-family: Inter;
|
||||
font-size: 0.875rem;
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
line-height: 1.375rem; /* 157.143% */
|
||||
letter-spacing: -0.00394rem;
|
||||
|
||||
transition: opacity 200ms ease;
|
||||
transition: opacity 200ms ease;
|
||||
|
||||
&[data-checked] {
|
||||
opacity: 0.6;
|
||||
}
|
||||
}
|
||||
}
|
||||
&[data-checked] {
|
||||
opacity: 0.6;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.add-btn {
|
||||
position: absolute;
|
||||
right: 1rem;
|
||||
bottom: 2.5rem;
|
||||
.add-btn {
|
||||
position: absolute;
|
||||
right: 1rem;
|
||||
bottom: 2.5rem;
|
||||
|
||||
width: 2.5rem;
|
||||
height: 2.5rem;
|
||||
flex-shrink: 0;
|
||||
box-shadow: 0px 2px 6px 0px rgba(0, 0, 0, 0.12);
|
||||
background-color: rgba(124, 103, 254, 1);
|
||||
color: rgba(237, 237, 240, 1);
|
||||
font-size: 1.5rem;
|
||||
width: 2.5rem;
|
||||
height: 2.5rem;
|
||||
flex-shrink: 0;
|
||||
box-shadow: 0px 2px 6px 0px rgba(0, 0, 0, 0.12);
|
||||
background-color: rgba(124, 103, 254, 1);
|
||||
color: rgba(237, 237, 240, 1);
|
||||
font-size: 1.5rem;
|
||||
|
||||
display: grid;
|
||||
place-items: center;
|
||||
border-radius: 100%;
|
||||
}
|
||||
}
|
||||
display: grid;
|
||||
place-items: center;
|
||||
border-radius: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.overlay {
|
||||
opacity: 0;
|
||||
.overlay {
|
||||
opacity: 0;
|
||||
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
overflow: hidden;
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
overflow: hidden;
|
||||
|
||||
background: rgba(0, 0, 0, 0.32);
|
||||
border-radius: 2rem;
|
||||
background: rgba(0, 0, 0, 0.32);
|
||||
border-radius: 2rem;
|
||||
|
||||
.drawer {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
height: 60%;
|
||||
opacity: 0;
|
||||
.drawer {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
height: 60%;
|
||||
opacity: 0;
|
||||
|
||||
background-color: white;
|
||||
border-radius: 0.88463rem 0.88463rem 2rem 2rem;
|
||||
background-color: white;
|
||||
border-radius: 0.88463rem 0.88463rem 2rem 2rem;
|
||||
|
||||
padding: 1rem;
|
||||
padding: 1rem;
|
||||
|
||||
.title {
|
||||
color: #434347;
|
||||
font-family: Inter;
|
||||
font-size: 0.88463rem;
|
||||
font-style: normal;
|
||||
font-weight: 600;
|
||||
line-height: 1.21638rem; /* 137.5% */
|
||||
letter-spacing: -0.01238rem;
|
||||
}
|
||||
.title {
|
||||
color: #434347;
|
||||
font-family: Inter;
|
||||
font-size: 0.88463rem;
|
||||
font-style: normal;
|
||||
font-weight: 600;
|
||||
line-height: 1.21638rem; /* 137.5% */
|
||||
letter-spacing: -0.01238rem;
|
||||
}
|
||||
|
||||
.subtitle {
|
||||
color: var(--greyscale-500, var(--color-greyscale-500, #818186));
|
||||
font-family: Inter;
|
||||
font-size: 0.77406rem;
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
line-height: 1.10575rem; /* 142.857% */
|
||||
letter-spacing: -0.01081rem;
|
||||
.subtitle {
|
||||
color: var(--greyscale-500, var(--color-greyscale-500, #818186));
|
||||
font-family: Inter;
|
||||
font-size: 0.77406rem;
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
line-height: 1.10575rem; /* 142.857% */
|
||||
letter-spacing: -0.01081rem;
|
||||
|
||||
margin-block-start: 0.2rem;
|
||||
}
|
||||
margin-block-start: 0.2rem;
|
||||
}
|
||||
|
||||
.upload {
|
||||
display: flex;
|
||||
padding: 0.44231rem 0.66344rem;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
align-self: stretch;
|
||||
.upload {
|
||||
display: flex;
|
||||
padding: 0.44231rem 0.66344rem;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
align-self: stretch;
|
||||
|
||||
border-radius: 0.66344rem;
|
||||
border: 1px dashed #d9d9d9;
|
||||
border-radius: 0.66344rem;
|
||||
border: 1px dashed #d9d9d9;
|
||||
|
||||
color: var(--greyscale-500, var(--color-greyscale-500, #818186));
|
||||
font-family: Inter;
|
||||
font-size: 0.77406rem;
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
line-height: 1.10575rem; /* 142.857% */
|
||||
letter-spacing: -0.01081rem;
|
||||
color: var(--greyscale-500, var(--color-greyscale-500, #818186));
|
||||
font-family: Inter;
|
||||
font-size: 0.77406rem;
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
line-height: 1.10575rem; /* 142.857% */
|
||||
letter-spacing: -0.01081rem;
|
||||
|
||||
margin-block-start: 2rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
margin-block-start: 2rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.upload-media {
|
||||
position: absolute;
|
||||
right: calc(0% - 24px);
|
||||
bottom: 8rem;
|
||||
background-color: white;
|
||||
box-shadow: 0px 4px 24px 0px rgba(0, 0, 0, 0.05);
|
||||
border-radius: 1rem;
|
||||
padding: 0.75rem;
|
||||
.upload-media {
|
||||
position: absolute;
|
||||
right: calc(0% - 24px);
|
||||
bottom: 8rem;
|
||||
background-color: white;
|
||||
box-shadow: 0px 4px 24px 0px rgba(0, 0, 0, 0.05);
|
||||
border-radius: 1rem;
|
||||
padding: 0.75rem;
|
||||
|
||||
opacity: 0;
|
||||
opacity: 0;
|
||||
|
||||
.title {
|
||||
color: var(--color-greyscale-800, #2d2d31);
|
||||
font-family: Inter;
|
||||
font-size: 0.85rem;
|
||||
font-style: normal;
|
||||
font-weight: 600;
|
||||
line-height: 1.375rem; /* 137.5% */
|
||||
letter-spacing: -0.014rem;
|
||||
}
|
||||
.title {
|
||||
color: var(--color-greyscale-800, #2d2d31);
|
||||
font-family: Inter;
|
||||
font-size: 0.85rem;
|
||||
font-style: normal;
|
||||
font-weight: 600;
|
||||
line-height: 1.375rem; /* 137.5% */
|
||||
letter-spacing: -0.014rem;
|
||||
}
|
||||
|
||||
.drop-zone {
|
||||
display: grid;
|
||||
place-items: center;
|
||||
border: 0.885px dashed #d9d9d9;
|
||||
border-radius: 0.5rem;
|
||||
.drop-zone {
|
||||
display: grid;
|
||||
place-items: center;
|
||||
border: 0.885px dashed #d9d9d9;
|
||||
border-radius: 0.5rem;
|
||||
|
||||
color: var(--greyscale-500, var(--color-greyscale-500, #818186));
|
||||
padding: 2rem 1.25rem;
|
||||
margin-block-start: 0.5rem;
|
||||
font-size: 0.65rem;
|
||||
font-family: Inter;
|
||||
color: var(--greyscale-500, var(--color-greyscale-500, #818186));
|
||||
padding: 2rem 1.25rem;
|
||||
margin-block-start: 0.5rem;
|
||||
font-size: 0.65rem;
|
||||
font-family: Inter;
|
||||
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
|
||||
.loading-overlay {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
opacity: 0;
|
||||
z-index: 100;
|
||||
.loading-overlay {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
opacity: 0;
|
||||
z-index: 100;
|
||||
|
||||
display: grid;
|
||||
place-items: center;
|
||||
}
|
||||
}
|
||||
display: grid;
|
||||
place-items: center;
|
||||
}
|
||||
}
|
||||
|
||||
img {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
img {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.images {
|
||||
display: flex;
|
||||
margin-block-start: 0.5rem;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
.images {
|
||||
display: flex;
|
||||
margin-block-start: 0.5rem;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -25,34 +25,21 @@
|
||||
</script>
|
||||
|
||||
<div
|
||||
class="scroll-indicator"
|
||||
class="scroll-indicator relative h-full w-px shrink-0 rounded-full"
|
||||
use:rect={elRect}
|
||||
style:--y={`${y}px`}
|
||||
style:--percentage={`${easedPercentage * 100}%`}
|
||||
>
|
||||
<div class="web-dot" />
|
||||
<div class="0)] absolute -top-[8px] left-1/2 translate-[-50%_var(--y," />
|
||||
</div>
|
||||
|
||||
<style lang="scss">
|
||||
.scroll-indicator {
|
||||
position: relative;
|
||||
|
||||
width: 1px;
|
||||
flex-shrink: 0;
|
||||
height: 100%;
|
||||
background: linear-gradient(
|
||||
to bottom,
|
||||
hsl(var(--web-color-accent)) 0%,
|
||||
hsl(var(--web-color-greyscale-700)) var(--percentage),
|
||||
hsl(var(--web-color-greyscale-700)) 100%
|
||||
);
|
||||
border-radius: 100%;
|
||||
}
|
||||
|
||||
.web-dot {
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
translate: -50% var(--y, 0);
|
||||
top: -8px;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -2,9 +2,7 @@ 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);
|
||||
client.setEndpoint('https://cloud.appwrite.io/v1').setProject(PUBLIC_APPWRITE_PROJECT_INIT_ID);
|
||||
|
||||
export const appwriteInit = {
|
||||
client,
|
||||
|
||||
@@ -7,4 +7,4 @@
|
||||
padding-block-start: 0;
|
||||
padding-block-end: 2rem;
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
import Root from "./Root.svelte";
|
||||
import Item from "./Item.svelte";
|
||||
import Root from './Root.svelte';
|
||||
import Item from './Item.svelte';
|
||||
|
||||
export {
|
||||
Root as Accordion,
|
||||
Item as AccordionItem
|
||||
}
|
||||
export { Root as Accordion, Item as AccordionItem };
|
||||
|
||||
@@ -27,8 +27,14 @@
|
||||
{title}
|
||||
</h4>
|
||||
<div class="web-author">
|
||||
<div class="u-flex u-cross-center u-gap-8">
|
||||
<img class="web-author-image" src={avatar} width="24" height="24" alt={author} />
|
||||
<div class="flex u-cross-center gap-2">
|
||||
<img
|
||||
class="web-author-image"
|
||||
src={avatar}
|
||||
width="24"
|
||||
height="24"
|
||||
alt={author}
|
||||
/>
|
||||
<div class="web-author-info">
|
||||
<h4 class="web-sub-body-400 web-u-color-text-primary">{author}</h4>
|
||||
<ul class="web-metadata web-caption-400 web-is-not-mobile">
|
||||
|
||||
@@ -42,9 +42,9 @@
|
||||
</script>
|
||||
|
||||
<div>
|
||||
<div class="u-flex u-flex-wrap u-cross-center u-margin-block-start-8">
|
||||
<div class="flex flex-wrap u-cross-center u-margin-block-start-8">
|
||||
<slot name="header" />
|
||||
<div class="u-flex u-gap-12 u-cross-end u-margin-inline-start-auto">
|
||||
<div class="flex gap-3 u-cross-end u-margin-inline-start-auto">
|
||||
<button
|
||||
class="web-icon-button"
|
||||
aria-label="Move carousel backward"
|
||||
@@ -108,7 +108,11 @@
|
||||
|
||||
&::after {
|
||||
right: 0;
|
||||
background: linear-gradient(to left, hsl(var(--web-color-background-docs)), transparent);
|
||||
background: linear-gradient(
|
||||
to left,
|
||||
hsl(var(--web-color-background-docs)),
|
||||
transparent
|
||||
);
|
||||
}
|
||||
|
||||
&[data-state='end']::after {
|
||||
|
||||
@@ -49,12 +49,12 @@
|
||||
<section class="web-content-footer">
|
||||
<header class="web-content-footer-header u-width-full-line">
|
||||
<div
|
||||
class="u-flex u-gap-32 u-main-space-between u-cross-center u-width-full-line"
|
||||
class="flex gap-8 u-main-space-between u-cross-center u-width-full-line"
|
||||
style="flex-wrap: wrap-reverse;"
|
||||
>
|
||||
<div class="u-flex u-gap-16 u-cross-center">
|
||||
<div class="flex gap-4 u-cross-center">
|
||||
<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="flex gap-2">
|
||||
<button
|
||||
class="web-radio-button"
|
||||
aria-label="helpful"
|
||||
@@ -88,7 +88,7 @@
|
||||
href="https://github.com/appwrite/website"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
class="web-link u-flex u-gap-4 u-cross-baseline"
|
||||
class="web-link flex gap-1 u-cross-baseline"
|
||||
>
|
||||
<span class="icon-pencil-alt u-contents" aria-hidden="true" />
|
||||
<span>Update on GitHub</span>
|
||||
@@ -104,7 +104,7 @@
|
||||
class="web-card is-normal"
|
||||
style="--card-padding:1rem"
|
||||
>
|
||||
<div class="u-flex-vertical u-gap-8">
|
||||
<div class="u-flex-vertical gap-2">
|
||||
<label for="message">
|
||||
<span class="web-u-color-text-primary">
|
||||
What did you {feedbackType === 'negative' ? 'dislike' : 'like'}? (optional)
|
||||
@@ -139,7 +139,7 @@
|
||||
</p>
|
||||
{/if}
|
||||
|
||||
<div class="u-flex u-main-end u-margin-block-start-16 u-gap-8">
|
||||
<div class="flex u-main-end u-margin-block-start-16 gap-2">
|
||||
<button class="web-button is-text" on:click={() => (showFeedback = false)}>
|
||||
<span>Cancel</span>
|
||||
</button>
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
export let images: Array<string>;
|
||||
</script>
|
||||
|
||||
<div class="u-position-absolute web-u-hide-mobile root">
|
||||
<div class="absolute web-u-hide-mobile root">
|
||||
{#each headPositions as [size, top, left], i}
|
||||
{@const image = clamp(0, images.length - 1, i % images.length)}
|
||||
<FloatingHead
|
||||
@@ -33,7 +33,7 @@
|
||||
{size}
|
||||
/>
|
||||
<div style:margin-block-end="0" style:padding="10%">
|
||||
<img style:border-radius="50%" class="u-block" alt="" />
|
||||
<img style:border-radius="50%" class="block" alt="" />
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
{ label: 'Functions', href: '/docs/products/functions' },
|
||||
{ label: 'Messaging', href: '/products/messaging' },
|
||||
{ label: 'Storage', href: '/docs/products/storage' },
|
||||
{ label: 'Realtime', href: '/docs/apis/realtime' },
|
||||
{ label: 'Realtime', href: '/docs/apis/realtime' }
|
||||
],
|
||||
Learn: [
|
||||
{ label: 'Docs', href: '/docs' },
|
||||
@@ -92,7 +92,7 @@
|
||||
|
||||
<nav
|
||||
aria-label="Footer"
|
||||
class="web-footer-nav u-margin-block-start-100 u-position-relative"
|
||||
class="web-footer-nav u-margin-block-start-100 relative"
|
||||
class:web-u-sep-block-start={!noBorder}
|
||||
>
|
||||
<img class="web-logo" src="/images/logos/appwrite.svg" alt="appwrite" height="24" width="130" />
|
||||
|
||||
@@ -4,12 +4,12 @@
|
||||
|
||||
export let variant: 'homepage' | 'docs' = 'homepage';
|
||||
|
||||
const year = new Date().getFullYear()
|
||||
const year = new Date().getFullYear();
|
||||
</script>
|
||||
|
||||
{#if variant === 'homepage'}
|
||||
<footer class="web-main-footer u-position-relative u-margin-block-start-48">
|
||||
<ul class="u-flex u-gap-8">
|
||||
<footer class="web-main-footer relative u-margin-block-start-48">
|
||||
<ul class="flex gap-2">
|
||||
{#each socials as social}
|
||||
<li>
|
||||
<a
|
||||
@@ -24,8 +24,8 @@
|
||||
</li>
|
||||
{/each}
|
||||
</ul>
|
||||
<div class="u-flex u-gap-16">
|
||||
<ul class="u-flex u-gap-8">
|
||||
<div class="flex gap-4">
|
||||
<ul class="flex gap-2">
|
||||
<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>
|
||||
@@ -34,11 +34,9 @@
|
||||
</div>
|
||||
</footer>
|
||||
{:else if variant === 'docs'}
|
||||
<footer
|
||||
class="web-main-footer is-with-bg-color u-margin-block-start-32 u-small u-position-relative"
|
||||
>
|
||||
<footer class="web-main-footer is-with-bg-color u-margin-block-start-32 u-small relative">
|
||||
<div class="web-main-footer-grid-1">
|
||||
<ul class="web-main-footer-grid-1-column-1 u-flex u-gap-8">
|
||||
<ul class="web-main-footer-grid-1-column-1 flex gap-2">
|
||||
{#each socials as social}
|
||||
<li>
|
||||
<a
|
||||
@@ -77,7 +75,7 @@
|
||||
{/if}
|
||||
|
||||
<style lang="scss">
|
||||
.web-icon-button {
|
||||
display: grid;
|
||||
}
|
||||
</style>
|
||||
.web-icon-button {
|
||||
display: grid;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -16,8 +16,11 @@
|
||||
|
||||
<nav class="web-side-nav web-is-not-desktop" class:u-hide={!open}>
|
||||
<div class="web-side-nav-wrapper web-u-padding-inline-16">
|
||||
<div class="u-flex items-center u-gap-8">
|
||||
<a href="https://cloud.appwrite.io/register" class="web-button is-secondary web-u-flex-1">
|
||||
<div class="flex items-center gap-2">
|
||||
<a
|
||||
href="https://cloud.appwrite.io/register"
|
||||
class="web-button is-secondary web-u-flex-1"
|
||||
>
|
||||
Sign up
|
||||
</a>
|
||||
<IsLoggedIn classes="web-u-flex-1" />
|
||||
|
||||
@@ -1,181 +1,194 @@
|
||||
<script context="module" lang="ts">
|
||||
export async function newsletter(name: string, email: string) {
|
||||
const response = await fetch('https://growth.appwrite.io/v1/newsletter/subscribe', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({
|
||||
name,
|
||||
email
|
||||
})
|
||||
});
|
||||
return response;
|
||||
}
|
||||
export async function newsletter(name: string, email: string) {
|
||||
const response = await fetch('https://growth.appwrite.io/v1/newsletter/subscribe', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({
|
||||
name,
|
||||
email
|
||||
})
|
||||
});
|
||||
return response;
|
||||
}
|
||||
</script>
|
||||
|
||||
<script lang="ts">
|
||||
let email = '';
|
||||
let name = '';
|
||||
let submitted = false;
|
||||
let error: string | undefined;
|
||||
let submitting = false;
|
||||
let email = '';
|
||||
let name = '';
|
||||
let submitted = false;
|
||||
let error: string | undefined;
|
||||
let submitting = false;
|
||||
|
||||
async function submit() {
|
||||
submitting = true;
|
||||
error = undefined;
|
||||
const response = await newsletter(name, email);
|
||||
submitting = false;
|
||||
if (response.status >= 400) {
|
||||
error = response.status >= 500 ? 'Server Error.' : 'Error submitting form.';
|
||||
return;
|
||||
}
|
||||
submitted = true;
|
||||
}
|
||||
async function submit() {
|
||||
submitting = true;
|
||||
error = undefined;
|
||||
const response = await newsletter(name, email);
|
||||
submitting = false;
|
||||
if (response.status >= 400) {
|
||||
error = response.status >= 500 ? 'Server Error.' : 'Error submitting form.';
|
||||
return;
|
||||
}
|
||||
submitted = true;
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="pre-footer-bg" style="pointer-events:none;">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="692"
|
||||
height="1171"
|
||||
viewBox="0 0 692 1171"
|
||||
fill="none"
|
||||
style="max-inline-size:100%;"
|
||||
>
|
||||
<g opacity="0.4" filter="url(#filter0_f_1577_37321)">
|
||||
<path
|
||||
d="M-96.9811 29.2126C-329.155 33.7322 -513.706 225.611 -509.186 457.785C-504.667 689.959 -312.788 874.51 -80.6141 869.99C33.1857 867.775 -132.237 523.592 -36.8339 437.579C62.4044 348.109 394.063 627.529 391.759 509.155C387.239 276.98 135.193 24.693 -96.9811 29.2126Z"
|
||||
fill="url(#paint0_radial_1577_37321)"
|
||||
/>
|
||||
</g>
|
||||
<defs>
|
||||
<filter
|
||||
id="filter0_f_1577_37321"
|
||||
x="-809.268"
|
||||
y="-270.847"
|
||||
width="1501.04"
|
||||
height="1440.92"
|
||||
filterUnits="userSpaceOnUse"
|
||||
color-interpolation-filters="sRGB"
|
||||
>
|
||||
<feFlood flood-opacity="0" result="BackgroundImageFix" />
|
||||
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape" />
|
||||
<feGaussianBlur stdDeviation="150" result="effect1_foregroundBlur_1577_37321" />
|
||||
</filter>
|
||||
<radialGradient
|
||||
id="paint0_radial_1577_37321"
|
||||
cx="0"
|
||||
cy="0"
|
||||
r="1"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="translate(-88.7975 449.601) rotate(178.885) scale(420.468 420.468)"
|
||||
>
|
||||
<stop offset="0.281696" stop-color="#FE9567" />
|
||||
<stop offset="0.59375" stop-color="#FD366E" />
|
||||
</radialGradient>
|
||||
</defs>
|
||||
</svg>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="692"
|
||||
height="1171"
|
||||
viewBox="0 0 692 1171"
|
||||
fill="none"
|
||||
style="max-inline-size:100%;"
|
||||
>
|
||||
<g opacity="0.4" filter="url(#filter0_f_1577_37321)">
|
||||
<path
|
||||
d="M-96.9811 29.2126C-329.155 33.7322 -513.706 225.611 -509.186 457.785C-504.667 689.959 -312.788 874.51 -80.6141 869.99C33.1857 867.775 -132.237 523.592 -36.8339 437.579C62.4044 348.109 394.063 627.529 391.759 509.155C387.239 276.98 135.193 24.693 -96.9811 29.2126Z"
|
||||
fill="url(#paint0_radial_1577_37321)"
|
||||
/>
|
||||
</g>
|
||||
<defs>
|
||||
<filter
|
||||
id="filter0_f_1577_37321"
|
||||
x="-809.268"
|
||||
y="-270.847"
|
||||
width="1501.04"
|
||||
height="1440.92"
|
||||
filterUnits="userSpaceOnUse"
|
||||
color-interpolation-filters="sRGB"
|
||||
>
|
||||
<feFlood flood-opacity="0" result="BackgroundImageFix" />
|
||||
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape" />
|
||||
<feGaussianBlur stdDeviation="150" result="effect1_foregroundBlur_1577_37321" />
|
||||
</filter>
|
||||
<radialGradient
|
||||
id="paint0_radial_1577_37321"
|
||||
cx="0"
|
||||
cy="0"
|
||||
r="1"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="translate(-88.7975 449.601) rotate(178.885) scale(420.468 420.468)"
|
||||
>
|
||||
<stop offset="0.281696" stop-color="#FE9567" />
|
||||
<stop offset="0.59375" stop-color="#FD366E" />
|
||||
</radialGradient>
|
||||
</defs>
|
||||
</svg>
|
||||
</div>
|
||||
|
||||
<div class="web-big-padding-section">
|
||||
<div class="web-big-padding-section-level-1">
|
||||
<div class="web-big-padding-section-level-2">
|
||||
<div class="web-container">
|
||||
<div class="web-grid-1-1-opt-2 u-gap-32">
|
||||
<div class="">
|
||||
<div class="web-u-max-inline-size-none-mobile" class:web-u-max-width-380={!submitted}>
|
||||
<section class="u-flex-vertical web-u-gap-20">
|
||||
<h1 class="web-title web-u-color-text-primary">Subscribe to our newsletter</h1>
|
||||
<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
|
||||
about engineering, product design, building community, and tips & tricks for using
|
||||
Appwrite.
|
||||
</p>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
{#if submitted}
|
||||
<div class="u-flex u-gap-8 u-cross-center">
|
||||
<svg
|
||||
width="18"
|
||||
height="18"
|
||||
viewBox="0 0 18 18"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<circle
|
||||
cx="9"
|
||||
cy="9"
|
||||
r="8"
|
||||
fill="#FD366E"
|
||||
fill-opacity="0.08"
|
||||
stroke="#FD366E"
|
||||
stroke-opacity="0.32"
|
||||
stroke-width="1.2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M5.25 10.5L7.75 12.5L12.75 6"
|
||||
stroke="#E4E4E7"
|
||||
stroke-width="1.2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
/>
|
||||
</svg>
|
||||
<div class="web-big-padding-section-level-1">
|
||||
<div class="web-big-padding-section-level-2">
|
||||
<div class="web-container">
|
||||
<div class="grid grid-cols-2-opt-2 gap-8">
|
||||
<div class="">
|
||||
<div
|
||||
class="web-u-max-inline-size-none-mobile"
|
||||
class:web-u-max-width-380={!submitted}
|
||||
>
|
||||
<section class="u-flex-vertical web-gap-5">
|
||||
<h1 class="web-title web-u-color-text-primary">
|
||||
Subscribe to our newsletter
|
||||
</h1>
|
||||
<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 about engineering, product design, building
|
||||
community, and tips & tricks for using Appwrite.
|
||||
</p>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
{#if submitted}
|
||||
<div class="flex gap-2 u-cross-center">
|
||||
<svg
|
||||
width="18"
|
||||
height="18"
|
||||
viewBox="0 0 18 18"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<circle
|
||||
cx="9"
|
||||
cy="9"
|
||||
r="8"
|
||||
fill="#FD366E"
|
||||
fill-opacity="0.08"
|
||||
stroke="#FD366E"
|
||||
stroke-opacity="0.32"
|
||||
stroke-width="1.2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M5.25 10.5L7.75 12.5L12.75 6"
|
||||
stroke="#E4E4E7"
|
||||
stroke-width="1.2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
/>
|
||||
</svg>
|
||||
|
||||
<span class="text">
|
||||
Thank you for subscribing! An email has been sent to your inbox.
|
||||
</span>
|
||||
</div>
|
||||
{:else}
|
||||
<form method="post" on:submit|preventDefault={submit} class="u-flex-vertical u-gap-16">
|
||||
<div class="u-flex u-flex-vertical u-gap-4">
|
||||
<label for="name">Your name</label>
|
||||
<input
|
||||
class="web-input-text"
|
||||
type="text"
|
||||
placeholder="Enter your name"
|
||||
id="name"
|
||||
name="name"
|
||||
required
|
||||
bind:value={name}
|
||||
/>
|
||||
</div>
|
||||
<div class="u-flex u-flex-vertical u-gap-4">
|
||||
<label for="email">Your email</label>
|
||||
<input
|
||||
class="web-input-text"
|
||||
type="email"
|
||||
placeholder="Enter your email"
|
||||
required
|
||||
id="email"
|
||||
name="email"
|
||||
bind:value={email}
|
||||
/>
|
||||
</div>
|
||||
<button type="submit" class="web-button" disabled={submitting}>Sign up</button>
|
||||
{#if error}
|
||||
<span class="text"> Something went wrong. Please try again later. </span>
|
||||
{/if}
|
||||
</form>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<span class="text">
|
||||
Thank you for subscribing! An email has been sent to your inbox.
|
||||
</span>
|
||||
</div>
|
||||
{:else}
|
||||
<form
|
||||
method="post"
|
||||
on:submit|preventDefault={submit}
|
||||
class="u-flex-vertical gap-4"
|
||||
>
|
||||
<div class="flex u-flex-vertical gap-1">
|
||||
<label for="name">Your name</label>
|
||||
<input
|
||||
class="web-input-text"
|
||||
type="text"
|
||||
placeholder="Enter your name"
|
||||
id="name"
|
||||
name="name"
|
||||
required
|
||||
bind:value={name}
|
||||
/>
|
||||
</div>
|
||||
<div class="flex u-flex-vertical gap-1">
|
||||
<label for="email">Your email</label>
|
||||
<input
|
||||
class="web-input-text"
|
||||
type="email"
|
||||
placeholder="Enter your email"
|
||||
required
|
||||
id="email"
|
||||
name="email"
|
||||
bind:value={email}
|
||||
/>
|
||||
</div>
|
||||
<button type="submit" class="web-button" disabled={submitting}
|
||||
>Sign up</button
|
||||
>
|
||||
{#if error}
|
||||
<span class="text">
|
||||
Something went wrong. Please try again later.
|
||||
</span>
|
||||
{/if}
|
||||
</form>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style lang="scss">
|
||||
.pre-footer-bg {
|
||||
position: absolute;
|
||||
top: clamp(300px, 50vw, 50%);
|
||||
left: clamp(300px, 50vw, 50%);
|
||||
transform: translate(-50%, -70%);
|
||||
width: clamp(1200px, 100vw, 3000px);
|
||||
height: auto;
|
||||
max-inline-size: unset;
|
||||
max-block-size: unset;
|
||||
}
|
||||
.pre-footer-bg {
|
||||
position: absolute;
|
||||
top: clamp(300px, 50vw, 50%);
|
||||
left: clamp(300px, 50vw, 50%);
|
||||
transform: translate(-50%, -70%);
|
||||
width: clamp(1200px, 100vw, 3000px);
|
||||
height: auto;
|
||||
max-inline-size: unset;
|
||||
max-block-size: unset;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -3,9 +3,9 @@
|
||||
|
||||
<img src="/images/bgs/pre-footer.png" alt="" class="web-pre-footer-bg" style="z-index:-1" />
|
||||
|
||||
<div class="web-grid-1-1 u-gap-32 web-u-row-gap-80 u-position-relative">
|
||||
<section class="web-hero u-flex web-u-row-gap-32 u-main-center u-cross-center">
|
||||
<h2 class="web-display u-max-width-500 web-u-text-align-center web-u-color-text-primary">
|
||||
<div class="grid grid-cols-2 gap-8 web-u-row-gap-80 relative">
|
||||
<section class="web-hero flex web-u-row-gap-32 u-main-center u-cross-center">
|
||||
<h2 class="web-display u-max-width-500 text-center web-u-color-text-primary">
|
||||
Start building today
|
||||
</h2>
|
||||
<a
|
||||
@@ -16,7 +16,7 @@
|
||||
</a>
|
||||
</section>
|
||||
<section
|
||||
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"
|
||||
class="web-card is-transparent has-border-gradient web-u-max-inline-width-584-mobile web-mx-auto-mobile web-u-inline-width-100-percent-mobile"
|
||||
>
|
||||
<header class="web-strip-plans-header">
|
||||
<div class="web-strip-plans-header-wrapper web-u-row-gap-24">
|
||||
|
||||
@@ -61,7 +61,7 @@
|
||||
}
|
||||
|
||||
function createHref(hit: Hit<Props>): string {
|
||||
const anchor = hit.anchor === '#' ? '' : hit.anchor ?? '';
|
||||
const anchor = hit.anchor === '#' ? '' : (hit.anchor ?? '');
|
||||
const target = hit.url + anchor;
|
||||
|
||||
return target.toString();
|
||||
@@ -147,7 +147,7 @@
|
||||
<!-- svelte-ignore a11y-no-static-element-interactions -->
|
||||
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
||||
<div
|
||||
class="wrapper u-position-fixed u-padding-0 u-inset-0 u-flex u-main-center u-cross-center"
|
||||
class="wrapper u-padding-0 u-inset-0 u-main-center u-cross-center fixed flex"
|
||||
data-visible={open ? true : undefined}
|
||||
style:z-index="100"
|
||||
style:background="hsl(var(--web-color-black) / 0.3)"
|
||||
@@ -159,15 +159,11 @@
|
||||
<div
|
||||
class="web-input-text-search-wrapper web-u-max-width-680 web-u-margin-inline-20 u-width-full-line"
|
||||
>
|
||||
<span
|
||||
class="web-icon-search u-z-index-5"
|
||||
aria-hidden="true"
|
||||
style="inset-block-start:0.9rem"
|
||||
/>
|
||||
<span class="web-icon-search z-[5]" aria-hidden="true" style="inset-block-start:0.9rem" />
|
||||
<div id="searchbox" />
|
||||
|
||||
<input
|
||||
class="web-input-button -u-padding-block-0 u-position-relative u-z-index-1"
|
||||
class="web-input-button -u-padding-block-0 relative z-1"
|
||||
type="text"
|
||||
id="search"
|
||||
bind:value
|
||||
@@ -184,7 +180,7 @@
|
||||
}}
|
||||
/>
|
||||
<div
|
||||
class="web-card is-normal u-flex-vertical u-gap-24"
|
||||
class="web-card is-normal u-flex-vertical gap-6"
|
||||
use:melt={$menu}
|
||||
style="--card-padding-mobile:1rem; border-radius:0 0 0.5rem 0.5rem;"
|
||||
>
|
||||
@@ -192,15 +188,15 @@
|
||||
<section>
|
||||
{#if results.length > 0}
|
||||
<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-margin-block-start-8 gap-1">
|
||||
{#each results as hit, i (hit.uid)}
|
||||
{@const relevantSubtitle = getRelevantSubtitle(hit)}
|
||||
<li>
|
||||
<a
|
||||
data-hit={i}
|
||||
href={createHref(hit)}
|
||||
class="web-button web-caption-400 is-text u-flex-vertical u-gap-8 u-min-width-100-percent
|
||||
web-u-padding-block-8 web-padding-inline-12 web-u-cross-start u-max-width-100-percent"
|
||||
class="web-button web-caption-400 is-text u-flex-vertical u-min-width-100-percent web-u-padding-block-8
|
||||
web-padding-inline-12 web-u-cross-start u-max-width-100-percent gap-2"
|
||||
use:melt={$option({
|
||||
value: hit,
|
||||
label: hit.title ?? i.toString()
|
||||
@@ -216,9 +212,7 @@
|
||||
{/if}
|
||||
</div>
|
||||
{#if hit.p}
|
||||
<div
|
||||
class="web-u-color-text-secondary web-u-trim-1"
|
||||
>
|
||||
<div class="web-u-color-text-secondary web-u-trim-1">
|
||||
{hit.p}
|
||||
</div>
|
||||
{/if}
|
||||
@@ -235,7 +229,7 @@
|
||||
{/if}
|
||||
<section>
|
||||
<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-margin-block-start-8 gap-1">
|
||||
{#each recommended as hit, i (hit.uid)}
|
||||
{@const index = i + (results.length ? results.length : 0)}
|
||||
<li>
|
||||
@@ -246,7 +240,7 @@
|
||||
value: hit,
|
||||
label: hit.title ?? i.toString()
|
||||
})}
|
||||
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"
|
||||
class="web-button web-caption-400 is-text u-flex-vertical u-min-width-100-percent web-u-padding-block-4 web-u-cross-start gap-2"
|
||||
>
|
||||
<div class="web-u-trim-1">
|
||||
<span class="web-u-color-text-secondary">{hit.h1}</span>
|
||||
|
||||
@@ -106,7 +106,7 @@
|
||||
{#each groups as group}
|
||||
{@const isDefault = group.label === DEFAULT_GROUP}
|
||||
{#if isDefault}
|
||||
<div class="u-flex u-flex-vertical u-gap-2">
|
||||
<div class="flex u-flex-vertical gap-0.5">
|
||||
{#each group.options as option}
|
||||
<button class="web-select-option" use:melt={$optionEl(option)}>
|
||||
{#if option.icon}
|
||||
|
||||
@@ -1,68 +1,68 @@
|
||||
<script lang="ts">
|
||||
import { createSwitch, melt } from '@melt-ui/svelte';
|
||||
import { createSwitch, melt } from '@melt-ui/svelte';
|
||||
|
||||
export let checked = false;
|
||||
export let checked = false;
|
||||
|
||||
const {
|
||||
elements: { root },
|
||||
states: { checked: meltChecked }
|
||||
} = createSwitch({
|
||||
onCheckedChange({ next }) {
|
||||
checked = next;
|
||||
return next;
|
||||
}
|
||||
});
|
||||
const {
|
||||
elements: { root },
|
||||
states: { checked: meltChecked }
|
||||
} = createSwitch({
|
||||
onCheckedChange({ next }) {
|
||||
checked = next;
|
||||
return next;
|
||||
}
|
||||
});
|
||||
|
||||
$: meltChecked.set(checked);
|
||||
$: meltChecked.set(checked);
|
||||
</script>
|
||||
|
||||
<div class="melt-switch">
|
||||
<button use:melt={$root}>
|
||||
<span class="thumb" />
|
||||
</button>
|
||||
<button use:melt={$root}>
|
||||
<span class="thumb" />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<style lang="scss">
|
||||
.melt-switch {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
.melt-switch {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
button {
|
||||
--padding: 0.125rem;
|
||||
--width: 2.25rem;
|
||||
button {
|
||||
--padding: 0.125rem;
|
||||
--width: 2.25rem;
|
||||
|
||||
position: relative;
|
||||
height: 1.5rem;
|
||||
width: var(--width);
|
||||
cursor: default;
|
||||
border-radius: 9999px;
|
||||
background-color: #19191d;
|
||||
transition: ease 150ms;
|
||||
}
|
||||
position: relative;
|
||||
height: 1.5rem;
|
||||
width: var(--width);
|
||||
cursor: default;
|
||||
border-radius: 9999px;
|
||||
background-color: #19191d;
|
||||
transition: ease 150ms;
|
||||
}
|
||||
|
||||
.melt-switch :global([data-state='checked']) {
|
||||
background-color: #fd366e;
|
||||
}
|
||||
.melt-switch :global([data-state='checked']) {
|
||||
background-color: #fd366e;
|
||||
}
|
||||
|
||||
.thumb {
|
||||
--thumb-size: 1.25rem;
|
||||
.thumb {
|
||||
--thumb-size: 1.25rem;
|
||||
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
|
||||
display: block;
|
||||
height: var(--thumb-size);
|
||||
width: var(--thumb-size);
|
||||
border-radius: 9999px;
|
||||
background-color: #ffffff;
|
||||
transform: translateX(var(--padding)) translateY(-50%);
|
||||
display: block;
|
||||
height: var(--thumb-size);
|
||||
width: var(--thumb-size);
|
||||
border-radius: 9999px;
|
||||
background-color: #ffffff;
|
||||
transform: translateX(var(--padding)) translateY(-50%);
|
||||
|
||||
transition: ease 150ms;
|
||||
}
|
||||
transition: ease 150ms;
|
||||
}
|
||||
|
||||
:global(button[data-state='checked']) .thumb {
|
||||
--x: calc(var(--width) - var(--thumb-size) - var(--padding));
|
||||
transform: translateX(var(--x)) translateY(-50%);
|
||||
}
|
||||
:global(button[data-state='checked']) .thumb {
|
||||
--x: calc(var(--width) - var(--thumb-size) - var(--padding));
|
||||
transform: translateX(var(--x)) translateY(-50%);
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -38,7 +38,7 @@
|
||||
href: '/docs/quick-starts/angular',
|
||||
image: `/images/platforms/${$themeInUse}/angular.svg`
|
||||
},
|
||||
{
|
||||
{
|
||||
name: 'Refine',
|
||||
href: '/docs/quick-starts/refine',
|
||||
image: `/images/platforms/${$themeInUse}/refine.svg`
|
||||
@@ -57,8 +57,7 @@
|
||||
name: 'React Native',
|
||||
href: '/docs/quick-starts/react-native',
|
||||
image: `/images/platforms/${$themeInUse}/react-native.svg`
|
||||
},
|
||||
|
||||
}
|
||||
] as Array<{
|
||||
name: string;
|
||||
href: string;
|
||||
@@ -66,12 +65,17 @@
|
||||
}>;
|
||||
</script>
|
||||
|
||||
<ul class="u-flex u-flex-wrap u-gap-16 web-u-margin-block-32-mobile web-u-margin-block-40-not-mobile">
|
||||
<ul class="flex flex-wrap gap-4 web-u-margin-block-32-mobile web-u-margin-block-40-not-mobile">
|
||||
{#each platforms as platform}
|
||||
<Tooltip>
|
||||
<li>
|
||||
<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>
|
||||
</li>
|
||||
<svelte:fragment slot="tooltip">{platform.name}</svelte:fragment>
|
||||
|
||||
@@ -16,7 +16,10 @@
|
||||
|
||||
<aside class="web-grid-120-1fr-auto-side" class:web-is-mobile-closed={!showToc}>
|
||||
<div class="web-page-steps">
|
||||
<div class="web-page-steps-location web-is-not-mobile" style="--location:{progress * 100}%;">
|
||||
<div
|
||||
class="web-page-steps-location web-is-not-mobile"
|
||||
style="--location:{progress * 100}%;"
|
||||
>
|
||||
<span class="web-page-steps-location-button">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
export const GITHUB_STARS = '41.9K';
|
||||
export const BANNER_KEY = 'discord-banner-01'; // Change key to force banner to show again
|
||||
export const SENTRY_DSN = 'https://27d41dc8bb67b596f137924ab8599e59@o1063647.ingest.us.sentry.io/4507497727000576'
|
||||
export const SENTRY_DSN =
|
||||
'https://27d41dc8bb67b596f137924ab8599e59@o1063647.ingest.us.sentry.io/4507497727000576';
|
||||
|
||||
/**
|
||||
* History:
|
||||
|
||||
@@ -78,7 +78,7 @@
|
||||
|
||||
<svelte:window on:keydown={handleKeydown} />
|
||||
|
||||
<div class="u-position-relative">
|
||||
<div class="relative">
|
||||
<section class="web-mobile-header is-transparent">
|
||||
<div class="web-mobile-header-start">
|
||||
<a href="/" aria-label="homepage">
|
||||
@@ -102,7 +102,11 @@
|
||||
<a href="https://cloud.appwrite.io" class="web-button web-is-only-desktop">
|
||||
<span class="web-sub-body-500">Go to Console</span>
|
||||
</a>
|
||||
<button class="web-button is-text" aria-label="open navigation" on:click={toggleSidenav}>
|
||||
<button
|
||||
class="web-button is-text"
|
||||
aria-label="open navigation"
|
||||
on:click={toggleSidenav}
|
||||
>
|
||||
{#if $layoutState.showSidenav}
|
||||
<span aria-hidden="true" class="web-icon-close" />
|
||||
{:else}
|
||||
@@ -140,7 +144,7 @@
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
<div class="u-flex u-stretch web-u-margin-inline-start-48">
|
||||
<div class="flex u-stretch web-u-margin-inline-start-48">
|
||||
<button
|
||||
class="web-input-button web-u-flex-basis-400"
|
||||
on:click={() => ($layoutState.showSearch = true)}
|
||||
@@ -148,7 +152,7 @@
|
||||
<span class="web-icon-search" aria-hidden="true" />
|
||||
<span class="text">Search in docs</span>
|
||||
|
||||
<div class="u-flex u-gap-4 u-margin-inline-start-auto">
|
||||
<div class="flex gap-1 u-margin-inline-start-auto">
|
||||
{#if isMac()}
|
||||
<span class="web-kbd" aria-label="command">⌘</span>
|
||||
{:else}
|
||||
@@ -160,7 +164,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="web-main-header-end">
|
||||
<div class="u-flex u-gap-8">
|
||||
<div class="flex gap-2">
|
||||
<a
|
||||
href="https://github.com/appwrite/appwrite/stargazers"
|
||||
target="_blank"
|
||||
|
||||
@@ -39,13 +39,13 @@
|
||||
<ul class="web-metadata web-caption-400">
|
||||
<slot name="metadata" />
|
||||
</ul>
|
||||
<div class="u-position-relative u-flex u-cross-center">
|
||||
<div class="relative flex u-cross-center">
|
||||
{#if back}
|
||||
<a
|
||||
href={back}
|
||||
class="
|
||||
web-button is-text is-icon web-u-cross-center web-u-size-40
|
||||
u-position-absolute u-inset-inline-start-0 web-u-translate-x-negative"
|
||||
absolute u-inset-inline-start-0 web-u-translate-x-negative"
|
||||
aria-label="previous page"
|
||||
>
|
||||
<span
|
||||
@@ -66,14 +66,12 @@
|
||||
<aside class="web-references-menu web-u-padding-inline-start-24">
|
||||
<div class="web-references-menu-content">
|
||||
{#if toc && toc.length > 0}
|
||||
<div class="u-flex u-main-space-between u-cross-center u-gap-16">
|
||||
<div class="flex u-main-space-between u-cross-center gap-4">
|
||||
<h5 class="web-references-menu-title web-eyebrow">On This Page</h5>
|
||||
</div>
|
||||
<ol class="web-references-menu-list">
|
||||
{#each toc as parent (parent.href)}
|
||||
<li
|
||||
class="web-references-menu-item"
|
||||
>
|
||||
<li class="web-references-menu-item">
|
||||
<a
|
||||
href={parent.href}
|
||||
class="web-references-menu-link"
|
||||
@@ -94,7 +92,8 @@
|
||||
href={child.href}
|
||||
class="web-references-menu-link"
|
||||
>
|
||||
<span class="web-caption-400">{child.title}</span
|
||||
<span class="web-caption-400"
|
||||
>{child.title}</span
|
||||
>
|
||||
</a>
|
||||
</li>
|
||||
@@ -105,10 +104,7 @@
|
||||
{/each}
|
||||
</ol>
|
||||
<div class="u-sep-block-start u-padding-block-start-20">
|
||||
<button
|
||||
class="web-link u-inline-flex u-cross-center u-gap-8"
|
||||
use:scrollToTop
|
||||
>
|
||||
<button class="web-link u-inline-flex u-cross-center gap-2" use:scrollToTop>
|
||||
<span class="web-icon-arrow-up" aria-hidden="true" />
|
||||
<span class="web-caption-400">Back to top</span>
|
||||
</button>
|
||||
@@ -117,4 +113,4 @@
|
||||
</div>
|
||||
</aside>
|
||||
</article>
|
||||
</main>
|
||||
</main>
|
||||
|
||||
@@ -20,22 +20,19 @@
|
||||
<article class="web-article u-contents">
|
||||
<header class="web-article-header">
|
||||
<div class="web-article-header-start u-flex-vertical web-u-cross-start">
|
||||
<button
|
||||
class="web-icon-button web-is-only-mobile"
|
||||
aria-label="previous page"
|
||||
>
|
||||
<button class="web-icon-button web-is-only-mobile" aria-label="previous page">
|
||||
<span class="icon-cheveron-left" aria-hidden="true" />
|
||||
</button>
|
||||
<ul class="web-metadata web-caption-400">
|
||||
<slot name="metadata" />
|
||||
</ul>
|
||||
<div class="u-position-relative u-flex u-cross-center">
|
||||
<div class="relative flex u-cross-center">
|
||||
{#if back}
|
||||
<a
|
||||
href={back}
|
||||
class="
|
||||
web-button is-text is-only-icon web-u-cross-center web-u-size-40
|
||||
u-position-absolute u-inset-inline-start-0 web-u-translate-x-negative"
|
||||
absolute u-inset-inline-start-0 web-u-translate-x-negative"
|
||||
aria-label="previous page"
|
||||
>
|
||||
<span
|
||||
@@ -51,7 +48,7 @@
|
||||
</header>
|
||||
<div class="web-article-content">
|
||||
<slot />
|
||||
<div class="u-flex u-main-space-between">
|
||||
<div class="flex u-main-space-between">
|
||||
{#if prevStep}
|
||||
<a href={prevStep.href} class="web-button is-text">
|
||||
<span class="icon-cheveron-left" aria-hidden="true" />
|
||||
@@ -82,7 +79,7 @@
|
||||
</div>
|
||||
<aside class="web-references-menu web-u-padding-inline-start-24">
|
||||
<div class="web-references-menu-content">
|
||||
<div class="u-flex u-main-space-between u-cross-center u-gap-16">
|
||||
<div class="flex u-main-space-between u-cross-center gap-4">
|
||||
<h5 class="web-references-menu-title web-eyebrow">Tutorial Steps</h5>
|
||||
</div>
|
||||
<ol class="web-references-menu-list">
|
||||
@@ -100,9 +97,9 @@
|
||||
</a>
|
||||
{#if isCurrentStep}
|
||||
<ol
|
||||
class="web-references-menu-list u-margin-block-start-16 u-margin-inline-start-32"
|
||||
class="web-references-menu-list u-margin-block-start-16 u-margin-inline-start-32"
|
||||
>
|
||||
{#each toc as parent}
|
||||
{#each toc as parent}
|
||||
<li class="web-references-menu-item">
|
||||
<a
|
||||
href={parent.href}
|
||||
@@ -136,14 +133,14 @@
|
||||
</ol>
|
||||
{/if}
|
||||
</li>
|
||||
{/each}
|
||||
{/each}
|
||||
</ol>
|
||||
{/if}
|
||||
</li>
|
||||
{/each}
|
||||
</ol>
|
||||
<div class="u-sep-block-start u-padding-block-start-20">
|
||||
<button class="web-link u-inline-flex u-cross-center u-gap-8" use:scrollToTop>
|
||||
<button class="web-link u-inline-flex u-cross-center gap-2" use:scrollToTop>
|
||||
<span class="web-icon-arrow-up" aria-hidden="true" />
|
||||
<span class="web-caption-400">Back to top</span>
|
||||
</button>
|
||||
@@ -152,5 +149,3 @@
|
||||
</aside>
|
||||
</article>
|
||||
</main>
|
||||
|
||||
|
||||
|
||||
@@ -68,7 +68,7 @@
|
||||
}
|
||||
|
||||
function getVisibleTheme() {
|
||||
const themes = Array.from(document.querySelectorAll('.theme-dark, .theme-light')).filter(
|
||||
const themes = Array.from(document.querySelectorAll('.theme-dark, .light')).filter(
|
||||
(element) => {
|
||||
const { classList, dataset } = element as HTMLElement;
|
||||
if (
|
||||
@@ -85,7 +85,7 @@
|
||||
|
||||
for (const theme of themes) {
|
||||
if (isInViewport(theme)) {
|
||||
return theme.classList.contains('theme-light') ? 'light' : 'dark';
|
||||
return theme.classList.contains('light') ? 'light' : 'dark';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -144,7 +144,7 @@
|
||||
};
|
||||
</script>
|
||||
|
||||
<div class="u-position-relative">
|
||||
<div class="relative">
|
||||
<section
|
||||
class="web-mobile-header theme-{resolvedTheme}"
|
||||
class:is-transparent={browser && !$isMobileNavOpen}
|
||||
|
||||
@@ -59,7 +59,8 @@
|
||||
<a href={parent.href} aria-label="go back">
|
||||
<span class="icon-cheveron-left" aria-hidden="true" />
|
||||
</a>
|
||||
<span class="web-side-nav-wrapper-parent-title web-eyebrow">{parent.label}</span>
|
||||
<span class="web-side-nav-wrapper-parent-title web-eyebrow">{parent.label}</span
|
||||
>
|
||||
</section>
|
||||
{/if}
|
||||
{#each navigation as navGroup}
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
export function capitalize(str: string) {
|
||||
return str.charAt(0).toUpperCase() + str.slice(1);
|
||||
return str.charAt(0).toUpperCase() + str.slice(1);
|
||||
}
|
||||
|
||||
@@ -3,114 +3,114 @@ type Cancel = () => void;
|
||||
type Promised<T> = T extends Promise<infer U> ? U : T;
|
||||
|
||||
type Args<T> = {
|
||||
returned: Promised<T>;
|
||||
cancel: Cancel;
|
||||
returned: Promised<T>;
|
||||
cancel: Cancel;
|
||||
};
|
||||
|
||||
export type Chain = {
|
||||
execute: () => Promise<void>;
|
||||
cancel: Cancel;
|
||||
execute: () => Promise<void>;
|
||||
cancel: Cancel;
|
||||
};
|
||||
|
||||
interface ChainFn {
|
||||
<A>(fn1: (args: Args<undefined>) => A): Chain;
|
||||
<A, B>(fn1: (args: Args<undefined>) => A, fn2: (args: Args<A>) => B): Chain;
|
||||
<A, B, C>(
|
||||
fn1: (args: Args<undefined>) => A,
|
||||
fn2: (args: Args<A>) => B,
|
||||
fn3: (args: Args<B>) => C
|
||||
): Chain;
|
||||
<A, B, C, D>(
|
||||
fn1: (args: Args<undefined>) => A,
|
||||
fn2: (args: Args<A>) => B,
|
||||
fn3: (args: Args<B>) => C,
|
||||
fn4: (args: Args<C>) => D
|
||||
): Chain;
|
||||
<A, B, C, D, E>(
|
||||
fn1: (args: Args<undefined>) => A,
|
||||
fn2: (args: Args<A>) => B,
|
||||
fn3: (args: Args<B>) => C,
|
||||
fn4: (args: Args<C>) => D,
|
||||
fn5: (args: Args<D>) => E
|
||||
): Chain;
|
||||
<A, B, C, D, E, F>(
|
||||
fn1: (args: Args<undefined>) => A,
|
||||
fn2: (args: Args<A>) => B,
|
||||
fn3: (args: Args<B>) => C,
|
||||
fn4: (args: Args<C>) => D,
|
||||
fn5: (args: Args<D>) => E,
|
||||
fn6: (args: Args<E>) => F
|
||||
): Chain;
|
||||
<A, B, C, D, E, F, G>(
|
||||
fn1: (args: Args<undefined>) => A,
|
||||
fn2: (args: Args<A>) => B,
|
||||
fn3: (args: Args<B>) => C,
|
||||
fn4: (args: Args<C>) => D,
|
||||
fn5: (args: Args<D>) => E,
|
||||
fn6: (args: Args<E>) => F,
|
||||
fn7: (args: Args<F>) => G
|
||||
): Chain;
|
||||
<A, B, C, D, E, F, G, H>(
|
||||
fn1: (args: Args<undefined>) => A,
|
||||
fn2: (args: Args<A>) => B,
|
||||
fn3: (args: Args<B>) => C,
|
||||
fn4: (args: Args<C>) => D,
|
||||
fn5: (args: Args<D>) => E,
|
||||
fn6: (args: Args<E>) => F,
|
||||
fn7: (args: Args<F>) => G,
|
||||
fn8: (args: Args<G>) => H
|
||||
): Chain;
|
||||
<A, B, C, D, E, F, G, H, I>(
|
||||
fn1: (args: Args<undefined>) => A,
|
||||
fn2: (args: Args<A>) => B,
|
||||
fn3: (args: Args<B>) => C,
|
||||
fn4: (args: Args<C>) => D,
|
||||
fn5: (args: Args<D>) => E,
|
||||
fn6: (args: Args<E>) => F,
|
||||
fn7: (args: Args<F>) => G,
|
||||
fn8: (args: Args<G>) => H,
|
||||
fn9: (args: Args<H>) => I
|
||||
): Chain;
|
||||
<A, B, C, D, E, F, G, H, I, J>(
|
||||
fn1: (args: Args<undefined>) => A,
|
||||
fn2: (args: Args<A>) => B,
|
||||
fn3: (args: Args<B>) => C,
|
||||
fn4: (args: Args<C>) => D,
|
||||
fn5: (args: Args<D>) => E,
|
||||
fn6: (args: Args<E>) => F,
|
||||
fn7: (args: Args<F>) => G,
|
||||
fn8: (args: Args<G>) => H,
|
||||
fn9: (args: Args<H>) => I,
|
||||
fn10: (args: Args<I>) => J
|
||||
): Chain;
|
||||
<A, B, C, D, E, F, G, H, I, J, K>(
|
||||
fn1: (args: Args<undefined>) => A,
|
||||
fn2: (args: Args<A>) => B,
|
||||
fn3: (args: Args<B>) => C,
|
||||
fn4: (args: Args<C>) => D,
|
||||
fn5: (args: Args<D>) => E,
|
||||
fn6: (args: Args<E>) => F,
|
||||
fn7: (args: Args<F>) => G,
|
||||
fn8: (args: Args<G>) => H,
|
||||
fn9: (args: Args<H>) => I,
|
||||
fn10: (args: Args<I>) => J,
|
||||
fn11: (args: Args<J>) => K
|
||||
): Chain;
|
||||
<A, B, C, D, E, F, G, H, I, J, K, L>(
|
||||
fn1: (args: Args<undefined>) => A,
|
||||
fn2: (args: Args<A>) => B,
|
||||
fn3: (args: Args<B>) => C,
|
||||
fn4: (args: Args<C>) => D,
|
||||
fn5: (args: Args<D>) => E,
|
||||
fn6: (args: Args<E>) => F,
|
||||
fn7: (args: Args<F>) => G,
|
||||
fn8: (args: Args<G>) => H,
|
||||
fn9: (args: Args<H>) => I,
|
||||
fn10: (args: Args<I>) => J,
|
||||
fn11: (args: Args<J>) => K,
|
||||
fn12: (args: Args<K>) => L
|
||||
): Chain;
|
||||
// So on...
|
||||
<A>(fn1: (args: Args<undefined>) => A): Chain;
|
||||
<A, B>(fn1: (args: Args<undefined>) => A, fn2: (args: Args<A>) => B): Chain;
|
||||
<A, B, C>(
|
||||
fn1: (args: Args<undefined>) => A,
|
||||
fn2: (args: Args<A>) => B,
|
||||
fn3: (args: Args<B>) => C
|
||||
): Chain;
|
||||
<A, B, C, D>(
|
||||
fn1: (args: Args<undefined>) => A,
|
||||
fn2: (args: Args<A>) => B,
|
||||
fn3: (args: Args<B>) => C,
|
||||
fn4: (args: Args<C>) => D
|
||||
): Chain;
|
||||
<A, B, C, D, E>(
|
||||
fn1: (args: Args<undefined>) => A,
|
||||
fn2: (args: Args<A>) => B,
|
||||
fn3: (args: Args<B>) => C,
|
||||
fn4: (args: Args<C>) => D,
|
||||
fn5: (args: Args<D>) => E
|
||||
): Chain;
|
||||
<A, B, C, D, E, F>(
|
||||
fn1: (args: Args<undefined>) => A,
|
||||
fn2: (args: Args<A>) => B,
|
||||
fn3: (args: Args<B>) => C,
|
||||
fn4: (args: Args<C>) => D,
|
||||
fn5: (args: Args<D>) => E,
|
||||
fn6: (args: Args<E>) => F
|
||||
): Chain;
|
||||
<A, B, C, D, E, F, G>(
|
||||
fn1: (args: Args<undefined>) => A,
|
||||
fn2: (args: Args<A>) => B,
|
||||
fn3: (args: Args<B>) => C,
|
||||
fn4: (args: Args<C>) => D,
|
||||
fn5: (args: Args<D>) => E,
|
||||
fn6: (args: Args<E>) => F,
|
||||
fn7: (args: Args<F>) => G
|
||||
): Chain;
|
||||
<A, B, C, D, E, F, G, H>(
|
||||
fn1: (args: Args<undefined>) => A,
|
||||
fn2: (args: Args<A>) => B,
|
||||
fn3: (args: Args<B>) => C,
|
||||
fn4: (args: Args<C>) => D,
|
||||
fn5: (args: Args<D>) => E,
|
||||
fn6: (args: Args<E>) => F,
|
||||
fn7: (args: Args<F>) => G,
|
||||
fn8: (args: Args<G>) => H
|
||||
): Chain;
|
||||
<A, B, C, D, E, F, G, H, I>(
|
||||
fn1: (args: Args<undefined>) => A,
|
||||
fn2: (args: Args<A>) => B,
|
||||
fn3: (args: Args<B>) => C,
|
||||
fn4: (args: Args<C>) => D,
|
||||
fn5: (args: Args<D>) => E,
|
||||
fn6: (args: Args<E>) => F,
|
||||
fn7: (args: Args<F>) => G,
|
||||
fn8: (args: Args<G>) => H,
|
||||
fn9: (args: Args<H>) => I
|
||||
): Chain;
|
||||
<A, B, C, D, E, F, G, H, I, J>(
|
||||
fn1: (args: Args<undefined>) => A,
|
||||
fn2: (args: Args<A>) => B,
|
||||
fn3: (args: Args<B>) => C,
|
||||
fn4: (args: Args<C>) => D,
|
||||
fn5: (args: Args<D>) => E,
|
||||
fn6: (args: Args<E>) => F,
|
||||
fn7: (args: Args<F>) => G,
|
||||
fn8: (args: Args<G>) => H,
|
||||
fn9: (args: Args<H>) => I,
|
||||
fn10: (args: Args<I>) => J
|
||||
): Chain;
|
||||
<A, B, C, D, E, F, G, H, I, J, K>(
|
||||
fn1: (args: Args<undefined>) => A,
|
||||
fn2: (args: Args<A>) => B,
|
||||
fn3: (args: Args<B>) => C,
|
||||
fn4: (args: Args<C>) => D,
|
||||
fn5: (args: Args<D>) => E,
|
||||
fn6: (args: Args<E>) => F,
|
||||
fn7: (args: Args<F>) => G,
|
||||
fn8: (args: Args<G>) => H,
|
||||
fn9: (args: Args<H>) => I,
|
||||
fn10: (args: Args<I>) => J,
|
||||
fn11: (args: Args<J>) => K
|
||||
): Chain;
|
||||
<A, B, C, D, E, F, G, H, I, J, K, L>(
|
||||
fn1: (args: Args<undefined>) => A,
|
||||
fn2: (args: Args<A>) => B,
|
||||
fn3: (args: Args<B>) => C,
|
||||
fn4: (args: Args<C>) => D,
|
||||
fn5: (args: Args<D>) => E,
|
||||
fn6: (args: Args<E>) => F,
|
||||
fn7: (args: Args<F>) => G,
|
||||
fn8: (args: Args<G>) => H,
|
||||
fn9: (args: Args<H>) => I,
|
||||
fn10: (args: Args<I>) => J,
|
||||
fn11: (args: Args<J>) => K,
|
||||
fn12: (args: Args<K>) => L
|
||||
): Chain;
|
||||
// So on...
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -120,32 +120,32 @@ interface ChainFn {
|
||||
* The cancel method will cancel the execution of the remaining callbacks.
|
||||
*/
|
||||
export const chain: ChainFn = (...fns: Function[]) => {
|
||||
const cancelled = {} as Record<string, boolean>;
|
||||
const cancelled = {} as Record<string, boolean>;
|
||||
|
||||
const cancel = () => {
|
||||
Object.keys(cancelled).forEach((key) => (cancelled[key] = true));
|
||||
};
|
||||
const cancel = () => {
|
||||
Object.keys(cancelled).forEach((key) => (cancelled[key] = true));
|
||||
};
|
||||
|
||||
let lastRes: any = undefined;
|
||||
let lastRes: any = undefined;
|
||||
|
||||
const execute = async () => {
|
||||
const executionId = stupidId();
|
||||
cancelled[executionId] = false;
|
||||
const execute = async () => {
|
||||
const executionId = stupidId();
|
||||
cancelled[executionId] = false;
|
||||
|
||||
for (let i = 0; i < fns.length; i++) {
|
||||
const fn = fns[i];
|
||||
if (cancelled[executionId]) {
|
||||
delete cancelled[executionId];
|
||||
return;
|
||||
}
|
||||
for (let i = 0; i < fns.length; i++) {
|
||||
const fn = fns[i];
|
||||
if (cancelled[executionId]) {
|
||||
delete cancelled[executionId];
|
||||
return;
|
||||
}
|
||||
|
||||
lastRes = await fn({ returned: lastRes, cancel });
|
||||
}
|
||||
lastRes = await fn({ returned: lastRes, cancel });
|
||||
}
|
||||
|
||||
delete cancelled[executionId];
|
||||
};
|
||||
delete cancelled[executionId];
|
||||
};
|
||||
|
||||
return { execute, cancel };
|
||||
return { execute, cancel };
|
||||
};
|
||||
|
||||
// Stupid way of generating unique id
|
||||
|
||||
@@ -4,24 +4,24 @@ import { clamp } from './clamp';
|
||||
import type { TestCases } from './test';
|
||||
|
||||
const testCases: TestCases<typeof clamp> = [
|
||||
{
|
||||
args: [0, 5, 10],
|
||||
expected: 5
|
||||
},
|
||||
{
|
||||
args: [0, -5, 10],
|
||||
expected: 0
|
||||
},
|
||||
{
|
||||
args: [0, 15, 10],
|
||||
expected: 10
|
||||
}
|
||||
{
|
||||
args: [0, 5, 10],
|
||||
expected: 5
|
||||
},
|
||||
{
|
||||
args: [0, -5, 10],
|
||||
expected: 0
|
||||
},
|
||||
{
|
||||
args: [0, 15, 10],
|
||||
expected: 10
|
||||
}
|
||||
];
|
||||
|
||||
describe('clamp', () => {
|
||||
testCases.forEach(({ args, expected }) => {
|
||||
it(`should return ${expected} when given ${JSON.stringify(args)}`, () => {
|
||||
expect(clamp(...args)).toBe(expected);
|
||||
});
|
||||
});
|
||||
testCases.forEach(({ args, expected }) => {
|
||||
it(`should return ${expected} when given ${JSON.stringify(args)}`, () => {
|
||||
expect(clamp(...args)).toBe(expected);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
export function clamp(min: number, value: number, max: number) {
|
||||
return Math.min(Math.max(min, value), max);
|
||||
return Math.min(Math.max(min, value), max);
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
let lastScrollPos = 0;
|
||||
|
||||
export function getScrollDir() {
|
||||
const scrollPos = window.scrollY;
|
||||
const scrollDir = scrollPos > lastScrollPos ? 'down' : 'up';
|
||||
lastScrollPos = scrollPos;
|
||||
return scrollDir;
|
||||
const scrollPos = window.scrollY;
|
||||
const scrollDir = scrollPos > lastScrollPos ? 'down' : 'up';
|
||||
lastScrollPos = scrollPos;
|
||||
return scrollDir;
|
||||
}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
export function isVisible(
|
||||
element: Element,
|
||||
visRect: { left: number; right: number; top: number; bottom: number }
|
||||
element: Element,
|
||||
visRect: { left: number; right: number; top: number; bottom: number }
|
||||
) {
|
||||
const rect = element.getBoundingClientRect();
|
||||
const vertInView = rect.top <= visRect.bottom && rect.bottom >= visRect.top;
|
||||
const horInView = rect.left <= visRect.right && rect.right >= visRect.left;
|
||||
const rect = element.getBoundingClientRect();
|
||||
const vertInView = rect.top <= visRect.bottom && rect.bottom >= visRect.top;
|
||||
const horInView = rect.left <= visRect.right && rect.right >= visRect.left;
|
||||
|
||||
return vertInView && horInView;
|
||||
return vertInView && horInView;
|
||||
}
|
||||
|
||||
@@ -1,34 +1,35 @@
|
||||
import type { AuthorData, PostsData } from "$routes/blog/content";
|
||||
import type { AuthorData, PostsData } from '$routes/blog/content';
|
||||
|
||||
export const DEFAULT_HOST = 'https://appwrite.io';
|
||||
export const DEFAULT_DESCRIPTION = 'Appwrite is an open-source platform for building applications at any scale, using your preferred programming languages and tools.';
|
||||
export const DEFAULT_DESCRIPTION =
|
||||
'Appwrite is an open-source platform for building applications at any scale, using your preferred programming languages and tools.';
|
||||
export function buildOpenGraphImage(title: string, description: string): string {
|
||||
return `https://og.appwrite.global/image.png?title=${encodeURIComponent(
|
||||
title
|
||||
)}&subtitle=${encodeURIComponent(description)}`;
|
||||
return `https://og.appwrite.global/image.png?title=${encodeURIComponent(
|
||||
title
|
||||
)}&subtitle=${encodeURIComponent(description)}`;
|
||||
}
|
||||
|
||||
export function createSchemaAuthor(author: AuthorData): string {
|
||||
return (
|
||||
`< script type="application/ld+json">${JSON.stringify({
|
||||
'@context': 'https://schema.org',
|
||||
'@type': 'Person',
|
||||
name: author.name,
|
||||
url: author.href,
|
||||
image: author.avatar
|
||||
})}</` + 'script>'
|
||||
);
|
||||
return (
|
||||
`< script type="application/ld+json">${JSON.stringify({
|
||||
'@context': 'https://schema.org',
|
||||
'@type': 'Person',
|
||||
name: author.name,
|
||||
url: author.href,
|
||||
image: author.avatar
|
||||
})}</` + 'script>'
|
||||
);
|
||||
}
|
||||
|
||||
export function createSchemaPost(post: PostsData): string {
|
||||
return (
|
||||
`< script type="application/ld+json">${JSON.stringify({
|
||||
'@context': 'https://schema.org',
|
||||
'@type': 'BlogPosting',
|
||||
headline: post.title,
|
||||
image: post.cover,
|
||||
datePublished: post.date,
|
||||
dateModified: post.date
|
||||
})}</` + 'script>'
|
||||
);
|
||||
return (
|
||||
`< script type="application/ld+json">${JSON.stringify({
|
||||
'@context': 'https://schema.org',
|
||||
'@type': 'BlogPosting',
|
||||
headline: post.title,
|
||||
image: post.cover,
|
||||
datePublished: post.date,
|
||||
dateModified: post.date
|
||||
})}</` + 'script>'
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
export const noop = () => {
|
||||
// Do nothing
|
||||
// Do nothing
|
||||
};
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
export function objectKeys<T extends object>(obj: T): Array<keyof T> {
|
||||
return Object.keys(obj) as Array<keyof T>;
|
||||
return Object.keys(obj) as Array<keyof T>;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
export function randomPick<T>(arr: T[]): T {
|
||||
return arr[Math.floor(Math.random() * arr.length)];
|
||||
return arr[Math.floor(Math.random() * arr.length)];
|
||||
}
|
||||
|
||||
export const deterministicRandom = <T>(options: T[], seed: string): T => {
|
||||
|
||||
@@ -2,7 +2,16 @@ import { writable } from 'svelte/store';
|
||||
import type { Language } from './code';
|
||||
import { browser } from '$app/environment';
|
||||
|
||||
const allVersions = ['1.5.x', '1.4.x', '1.3.x', '1.2.x', '1.1.x', '1.0.x', '0.15.x', 'cloud'] as const;
|
||||
const allVersions = [
|
||||
'1.5.x',
|
||||
'1.4.x',
|
||||
'1.3.x',
|
||||
'1.2.x',
|
||||
'1.1.x',
|
||||
'1.0.x',
|
||||
'0.15.x',
|
||||
'cloud'
|
||||
] as const;
|
||||
|
||||
export type Version = (typeof allVersions)[number];
|
||||
|
||||
@@ -20,7 +29,7 @@ export enum Service {
|
||||
Locale = 'locale',
|
||||
Storage = 'storage',
|
||||
Teams = 'teams',
|
||||
Users = 'users',
|
||||
Users = 'users'
|
||||
}
|
||||
|
||||
export enum Platform {
|
||||
@@ -114,7 +123,7 @@ export const serviceMap: Record<Service, string> = {
|
||||
[Service.Locale]: 'Locale',
|
||||
[Service.Storage]: 'Storage',
|
||||
[Service.Teams]: 'Teams',
|
||||
[Service.Users]: 'Users',
|
||||
[Service.Users]: 'Users'
|
||||
};
|
||||
|
||||
export const preferredVersion = writable<Version | null>(
|
||||
|
||||
@@ -52,11 +52,11 @@ export type AppwriteSchemaObject = OpenAPIV3.SchemaObject & {
|
||||
};
|
||||
|
||||
export interface Property {
|
||||
name: string;
|
||||
items?: {
|
||||
type?: string;
|
||||
oneOf?: OpenAPIV3.ReferenceObject[];
|
||||
} & OpenAPIV3.ReferenceObject;
|
||||
name: string;
|
||||
items?: {
|
||||
type?: string;
|
||||
oneOf?: OpenAPIV3.ReferenceObject[];
|
||||
} & OpenAPIV3.ReferenceObject;
|
||||
}
|
||||
|
||||
export enum ModelType {
|
||||
@@ -182,7 +182,8 @@ export function getSchema(id: string, api: OpenAPIV3.Document): OpenAPIV3.Schema
|
||||
if (schema) {
|
||||
return schema;
|
||||
}
|
||||
throw new Error(`Schema doesn't exist for id: ${id}`);}
|
||||
throw new Error(`Schema doesn't exist for id: ${id}`);
|
||||
}
|
||||
|
||||
const specs = import.meta.glob(
|
||||
'$appwrite/app/config/specs/open-api3*-(client|server|console).json',
|
||||
@@ -354,15 +355,18 @@ export function resolveReference(
|
||||
throw new Error("Schema doesn't exist");
|
||||
}
|
||||
|
||||
export const generateExample = (schema: OpenAPIV3.SchemaObject, api: OpenAPIV3.Document<{}>, modelType: ModelType = ModelType.REST): Object => {
|
||||
|
||||
const properties = Object.keys(schema.properties ?? {}).map((key) =>{
|
||||
export const generateExample = (
|
||||
schema: OpenAPIV3.SchemaObject,
|
||||
api: OpenAPIV3.Document<{}>,
|
||||
modelType: ModelType = ModelType.REST
|
||||
): Object => {
|
||||
const properties = Object.keys(schema.properties ?? {}).map((key) => {
|
||||
const name = key;
|
||||
const fields = schema.properties?.[key];
|
||||
return {
|
||||
name,
|
||||
...fields
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
const example = properties.reduce((carry, currentValue) => {
|
||||
@@ -370,29 +374,32 @@ export const generateExample = (schema: OpenAPIV3.SchemaObject, api: OpenAPIV3.D
|
||||
let propertyName;
|
||||
switch (modelType) {
|
||||
case ModelType.REST:
|
||||
propertyName = property.name;
|
||||
break;
|
||||
propertyName = property.name;
|
||||
break;
|
||||
case ModelType.GRAPHQL:
|
||||
propertyName = property.name.replace('$', '_');
|
||||
break;
|
||||
propertyName = property.name.replace('$', '_');
|
||||
break;
|
||||
default:
|
||||
propertyName = property.name;
|
||||
break;
|
||||
propertyName = property.name;
|
||||
break;
|
||||
}
|
||||
|
||||
if (property.type === 'array') {
|
||||
// If it's an array type containing primatives
|
||||
if (property.items?.type){
|
||||
if (property.items?.type) {
|
||||
return {
|
||||
...carry,
|
||||
[propertyName]: property['x-example']
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
if (property.items && 'anyOf' in property.items) {
|
||||
// default to first child type if multiple available
|
||||
const firstSchema = (property.items as unknown as AppwriteSchemaObject)?.anyOf?.[0];
|
||||
const schema = getSchema(getIdFromReference(firstSchema as OpenAPIV3.ReferenceObject), api)
|
||||
const schema = getSchema(
|
||||
getIdFromReference(firstSchema as OpenAPIV3.ReferenceObject),
|
||||
api
|
||||
);
|
||||
|
||||
return {
|
||||
...carry,
|
||||
@@ -401,37 +408,43 @@ export const generateExample = (schema: OpenAPIV3.SchemaObject, api: OpenAPIV3.D
|
||||
}
|
||||
|
||||
// if an array of objects without child types
|
||||
const schema = getSchema(getIdFromReference(property.items as OpenAPIV3.ReferenceObject), api);
|
||||
const schema = getSchema(
|
||||
getIdFromReference(property.items as OpenAPIV3.ReferenceObject),
|
||||
api
|
||||
);
|
||||
return {
|
||||
...carry,
|
||||
[propertyName]: [generateExample(schema, api, modelType)]
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// If it's an object type, but not in an array.
|
||||
if (property.type === 'object') {
|
||||
if (property.items?.oneOf){
|
||||
if (property.items?.oneOf) {
|
||||
// default to first child type if multiple available
|
||||
const schema = getSchema(getIdFromReference(property.items.oneOf[0] as OpenAPIV3.ReferenceObject), api);
|
||||
const schema = getSchema(
|
||||
getIdFromReference(property.items.oneOf[0] as OpenAPIV3.ReferenceObject),
|
||||
api
|
||||
);
|
||||
return {
|
||||
...carry,
|
||||
[propertyName]: generateExample(schema, api, modelType)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
if (property.items){
|
||||
if (property.items) {
|
||||
const schema = getSchema(getIdFromReference(property.items), api);
|
||||
return {
|
||||
...carry,
|
||||
[propertyName]: generateExample(schema, api, modelType)
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
...carry,
|
||||
[propertyName]: property['x-example']
|
||||
}
|
||||
};
|
||||
}, {});
|
||||
return example;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -2,6 +2,6 @@
|
||||
type UnknownFn = (...args: any[]) => any;
|
||||
|
||||
export type TestCases<Fn extends UnknownFn> = {
|
||||
args: Parameters<Fn>;
|
||||
expected: ReturnType<Fn>;
|
||||
args: Parameters<Fn>;
|
||||
expected: ReturnType<Fn>;
|
||||
}[];
|
||||
|
||||
@@ -4,24 +4,24 @@ import { toScale } from './toScale';
|
||||
import type { TestCases } from './test';
|
||||
|
||||
const testCases: TestCases<typeof toScale> = [
|
||||
{
|
||||
args: [5, [0, 10], [0, 100]],
|
||||
expected: 50
|
||||
},
|
||||
{
|
||||
args: [0.5, [0, 1], [0, 100]],
|
||||
expected: 50
|
||||
},
|
||||
{
|
||||
args: [0.4, [0.2, 1], [0, 1]],
|
||||
expected: 0.25
|
||||
}
|
||||
{
|
||||
args: [5, [0, 10], [0, 100]],
|
||||
expected: 50
|
||||
},
|
||||
{
|
||||
args: [0.5, [0, 1], [0, 100]],
|
||||
expected: 50
|
||||
},
|
||||
{
|
||||
args: [0.4, [0.2, 1], [0, 1]],
|
||||
expected: 0.25
|
||||
}
|
||||
];
|
||||
|
||||
describe('toScale', () => {
|
||||
testCases.forEach(({ args, expected }) => {
|
||||
it(`should return ${expected} when given ${JSON.stringify(args)}`, () => {
|
||||
expect(toScale(...args)).toBe(expected);
|
||||
});
|
||||
});
|
||||
testCases.forEach(({ args, expected }) => {
|
||||
it(`should return ${expected} when given ${JSON.stringify(args)}`, () => {
|
||||
expect(toScale(...args)).toBe(expected);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -8,5 +8,5 @@ export type Scale = [number, number];
|
||||
* `to` { lower: 0, upper: 100 } => `number` 30
|
||||
*/
|
||||
export function toScale(value: number, from: Scale, to: Scale): number {
|
||||
return ((value - from[0]) * (to[1] - to[0])) / (from[1] - from[0]) + to[0];
|
||||
return ((value - from[0]) * (to[1] - to[0])) / (from[1] - from[0]) + to[0];
|
||||
}
|
||||
|
||||
@@ -2,21 +2,21 @@ import { base } from '$app/paths';
|
||||
import type { Tutorial } from '$markdoc/layouts/Tutorial.svelte';
|
||||
|
||||
export function globToTutorial(data: { tutorials: Record<string, unknown>; pathname: string }) {
|
||||
return Object.entries(data.tutorials)
|
||||
.map(([filepath, tutorial]) => {
|
||||
const { frontmatter } = tutorial as {
|
||||
frontmatter: Tutorial;
|
||||
};
|
||||
const slug = filepath.replace('./', '').replace('/+page.markdoc', '');
|
||||
const tutorialName = data.pathname.split('/').slice(0, -1).join('/');
|
||||
return Object.entries(data.tutorials)
|
||||
.map(([filepath, tutorial]) => {
|
||||
const { frontmatter } = tutorial as {
|
||||
frontmatter: Tutorial;
|
||||
};
|
||||
const slug = filepath.replace('./', '').replace('/+page.markdoc', '');
|
||||
const tutorialName = data.pathname.split('/').slice(0, -1).join('/');
|
||||
|
||||
return {
|
||||
title: frontmatter.title,
|
||||
step: frontmatter.step,
|
||||
href: `${base}${tutorialName}/${slug}`
|
||||
};
|
||||
})
|
||||
.sort((a, b) => {
|
||||
return a.step - b.step;
|
||||
});
|
||||
return {
|
||||
title: frontmatter.title,
|
||||
step: frontmatter.step,
|
||||
href: `${base}${tutorialName}/${slug}`
|
||||
};
|
||||
})
|
||||
.sort((a, b) => {
|
||||
return a.step - b.step;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -45,10 +45,8 @@
|
||||
</svelte:head>
|
||||
|
||||
<Main>
|
||||
<div class="web-big-padding-section-level-1 u-position-relative u-overflow-hidden">
|
||||
<div
|
||||
class="u-position-absolute u-inset-inline-start-0 u-inset-block-end-0 web-u-pointer-events-none"
|
||||
>
|
||||
<div class="web-big-padding-section-level-1 relative overflow-hidden">
|
||||
<div class="absolute u-inset-inline-start-0 u-inset-block-end-0 web-u-pointer-events-none">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="660"
|
||||
@@ -102,9 +100,9 @@
|
||||
</svg>
|
||||
</div>
|
||||
|
||||
<div class="web-big-padding-section-level-2 u-position-relative">
|
||||
<div class="web-big-padding-section-level-2 relative">
|
||||
<div class="web-container">
|
||||
<div class="web-author-section u-block">
|
||||
<div class="web-author-section block">
|
||||
{#if avatar}
|
||||
<FloatingHead --position="relative" src={avatar} alt={name} size={112} />
|
||||
{/if}
|
||||
@@ -119,7 +117,7 @@
|
||||
{bio}
|
||||
</p>
|
||||
{/if}
|
||||
<ul class="u-flex u-main-center u-gap-8 u-margin-block-start-16">
|
||||
<ul class="flex u-main-center gap-2 u-margin-block-start-16">
|
||||
{#if github}
|
||||
<li>
|
||||
<a
|
||||
@@ -171,7 +169,7 @@
|
||||
<h2 class="web-title web-u-color-text-primary">Articles</h2>
|
||||
|
||||
<!-- <div class="web-is-only-mobile u-margin-block-start-32">
|
||||
<label class="u-block web-select is-colored" for="articles">
|
||||
<label class="block web-select is-colored" for="articles">
|
||||
<select id="articles">
|
||||
<option>Latest</option>
|
||||
<option>News</option>
|
||||
@@ -183,7 +181,7 @@
|
||||
</label>
|
||||
</div> -->
|
||||
<!--<div class="web-is-not-mobile">
|
||||
<div class="u-flex u-main-space-between u-gap-16 u-margin-block-start-24">
|
||||
<div class="flex u-main-space-between gap-4 u-margin-block-start-24">
|
||||
<ul
|
||||
class="web-secondary-tabs is-transparent"
|
||||
role="tablist"
|
||||
@@ -264,7 +262,7 @@
|
||||
</ul> -->
|
||||
<!-- <div class="web-input-text-search-wrapper">
|
||||
<span class="icon-search" aria-hidden="true" />
|
||||
<input class="web-input-text web-u-block-size-48" type="search" placeholder="Search" />
|
||||
<input class="web-input-text web-block-size-48" type="search" placeholder="Search" />
|
||||
</div>
|
||||
</div>
|
||||
</div>-->
|
||||
@@ -287,7 +285,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="web-big-padding-section-level-2 is-margin-replace-padding u-position-relative u-overflow-hidden"
|
||||
class="web-big-padding-section-level-2 is-margin-replace-padding relative overflow-hidden"
|
||||
>
|
||||
<div class="web-container">
|
||||
<FooterNav />
|
||||
|
||||
@@ -53,7 +53,7 @@
|
||||
</div>
|
||||
<!-- <div class="web-input-text-search-wrapper u-inline-width-100-percent-mobile">
|
||||
<span class="icon-search" aria-hidden="true" />
|
||||
<input class="web-input-text web-u-block-size-48" type="search" placeholder="Search" />
|
||||
<input class="web-input-text web-block-size-48" type="search" placeholder="Search" />
|
||||
</div> -->
|
||||
</div>
|
||||
|
||||
@@ -76,7 +76,7 @@
|
||||
</ul>
|
||||
</div>
|
||||
<div
|
||||
class="web-big-padding-section-level-2 is-margin-replace-padding u-position-relative u-overflow-hidden"
|
||||
class="web-big-padding-section-level-2 is-margin-replace-padding relative overflow-hidden"
|
||||
>
|
||||
<div class="web-container">
|
||||
<FooterNav />
|
||||
|
||||
@@ -72,7 +72,7 @@
|
||||
<h1 class="web-title web-u-color-text-primary">{title}</h1>
|
||||
</header>
|
||||
<button
|
||||
class="toc-btn u-position-sticky u-flex u-width-full-line u-main-space-between u-cross-center
|
||||
class="toc-btn sticky flex u-width-full-line u-main-space-between u-cross-center
|
||||
web-u-padding-20 web-u-margin-inline-20-negative web-u-color-text-primary web-is-only-mobile
|
||||
u-margin-block-start-24 web-u-sep-block web-u-filter-blur-8"
|
||||
style:--inset-block-start="4.5rem"
|
||||
|
||||
@@ -88,10 +88,7 @@
|
||||
{/if}
|
||||
{#if authorData}
|
||||
<div class="web-author u-margin-block-start-16">
|
||||
<a
|
||||
href={authorData.href}
|
||||
class="u-flex u-cross-center u-gap-8"
|
||||
>
|
||||
<a href={authorData.href} class="flex u-cross-center gap-2">
|
||||
{#if authorData.avatar}
|
||||
<img
|
||||
class="web-author-image"
|
||||
@@ -103,13 +100,15 @@
|
||||
/>
|
||||
{/if}
|
||||
<div class="u-flex-vertical">
|
||||
<h4 class="web-sub-body-400 web-u-color-text-primary">
|
||||
<h4
|
||||
class="web-sub-body-400 web-u-color-text-primary"
|
||||
>
|
||||
{authorData.name}
|
||||
</h4>
|
||||
<p class="web-caption-400">{authorData.role}</p>
|
||||
</div>
|
||||
</a>
|
||||
<!-- <ul class="u-flex u-gap-8 u-margin-inline-start-auto u-cross-child-center">
|
||||
<!-- <ul class="flex gap-2 u-margin-inline-start-auto u-cross-child-center">
|
||||
{#if authorData.twitter}
|
||||
<li>
|
||||
<a
|
||||
@@ -155,7 +154,7 @@
|
||||
</header>
|
||||
{#if cover}
|
||||
<div class="web-media-container">
|
||||
<Media class="u-block" src={cover} />
|
||||
<Media class="block" src={cover} />
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
@@ -164,7 +163,7 @@
|
||||
</div>
|
||||
</article>
|
||||
<!-- {#if categories?.length}
|
||||
<div class="u-flex u-gap-16">
|
||||
<div class="flex gap-4">
|
||||
{#each categories as cat}
|
||||
<a href={cat.href} class="web-tag">{cat.name}</a>
|
||||
{/each}
|
||||
@@ -200,7 +199,7 @@
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
<div class="web-big-padding-section-level-2 u-position-relative u-overflow-hidden">
|
||||
<div class="web-big-padding-section-level-2 relative overflow-hidden">
|
||||
<div class="web-container">
|
||||
<Newsletter />
|
||||
<FooterNav />
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
<script lang="ts">
|
||||
import { setContext } from "svelte";
|
||||
import { setContext } from 'svelte';
|
||||
|
||||
setContext("no-paragraph", true);
|
||||
setContext('no-paragraph', true);
|
||||
</script>
|
||||
|
||||
<blockquote class="web-blockquote">
|
||||
<p class="web-description">
|
||||
<slot />
|
||||
</p>
|
||||
<p class="web-description">
|
||||
<slot />
|
||||
</p>
|
||||
</blockquote>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script lang="ts">
|
||||
export let content: string;
|
||||
export let content: string;
|
||||
</script>
|
||||
|
||||
<span class="web-inline-code web-code">{content}</span>
|
||||
|
||||
@@ -65,13 +65,13 @@
|
||||
<header class="web-code-snippet-header">
|
||||
<div class="web-code-snippet-header-start">
|
||||
{#if badgeValue}
|
||||
<div class="u-flex u-gap-16">
|
||||
<div class="flex gap-4">
|
||||
<div class="web-tag"><span class="text">{badgeValue}</span></div>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
<div class="web-code-snippet-header-end">
|
||||
<ul class="buttons-list u-flex u-gap-8">
|
||||
<ul class="buttons-list flex gap-2">
|
||||
<li class="buttons-list-item web-u-padding-inline-start-20">
|
||||
<Tooltip>
|
||||
<button
|
||||
|
||||
@@ -1 +1 @@
|
||||
<strong class="u-bold"><slot /></strong>
|
||||
<strong class="u-bold"><slot /></strong>
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
<script lang="ts">
|
||||
import type { HTMLTdAttributes } from 'svelte/elements';
|
||||
import type { HTMLTdAttributes } from 'svelte/elements';
|
||||
|
||||
export let align: HTMLTdAttributes['align'] = undefined;
|
||||
export let width: HTMLTdAttributes['width'] = undefined;
|
||||
export let align: HTMLTdAttributes['align'] = undefined;
|
||||
export let width: HTMLTdAttributes['width'] = undefined;
|
||||
</script>
|
||||
|
||||
<td
|
||||
style:width={width ? `${width}px` : undefined}
|
||||
style:min-inline-size={width ? 'unset' : undefined}
|
||||
role="columnheader"
|
||||
class="web-table-head-col"
|
||||
{align}
|
||||
style:width={width ? `${width}px` : undefined}
|
||||
style:min-inline-size={width ? 'unset' : undefined}
|
||||
role="columnheader"
|
||||
class="web-table-head-col"
|
||||
{align}
|
||||
>
|
||||
<span class="web-eyebrow">
|
||||
<slot />
|
||||
</span>
|
||||
<span class="web-eyebrow">
|
||||
<slot />
|
||||
</span>
|
||||
</td>
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
<tr class="web-table-row">
|
||||
<slot />
|
||||
</tr>
|
||||
<slot />
|
||||
</tr>
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
<script context="module">
|
||||
export { default as Blockquote } from './Blockquote.svelte';
|
||||
export { default as Blockquote } from './Blockquote.svelte';
|
||||
export { default as Code } from './Code.svelte';
|
||||
export { default as Fence } from './Fence.svelte';
|
||||
export { default as Heading } from './Heading.svelte';
|
||||
export { default as List } from './List.svelte';
|
||||
export { default as Paragraph } from './Paragraph.svelte';
|
||||
export { default as Strong } from './Strong.svelte';
|
||||
export { default as Image } from './Image.svelte';
|
||||
export { default as Item } from './Item.svelte';
|
||||
export { default as Link } from './Link.svelte';
|
||||
export { default as Table } from './Table.svelte';
|
||||
export { default as Tbody } from './Tbody.svelte';
|
||||
export { default as Td } from './Td.svelte';
|
||||
export { default as Th } from './Th.svelte';
|
||||
export { default as Thead } from './Thead.svelte';
|
||||
export { default as Tr } from './Tr.svelte';
|
||||
export { default as Heading } from './Heading.svelte';
|
||||
export { default as List } from './List.svelte';
|
||||
export { default as Paragraph } from './Paragraph.svelte';
|
||||
export { default as Strong } from './Strong.svelte';
|
||||
export { default as Image } from './Image.svelte';
|
||||
export { default as Item } from './Item.svelte';
|
||||
export { default as Link } from './Link.svelte';
|
||||
export { default as Table } from './Table.svelte';
|
||||
export { default as Tbody } from './Tbody.svelte';
|
||||
export { default as Td } from './Td.svelte';
|
||||
export { default as Th } from './Th.svelte';
|
||||
export { default as Thead } from './Thead.svelte';
|
||||
export { default as Tr } from './Tr.svelte';
|
||||
</script>
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user