mirror of
https://github.com/LukeHagar/website.git
synced 2025-12-06 04:22:07 +00:00
prettify
This commit is contained in:
@@ -1,30 +1,30 @@
|
||||
module.exports = {
|
||||
root: true,
|
||||
extends: [
|
||||
'eslint:recommended',
|
||||
'plugin:@typescript-eslint/recommended',
|
||||
'plugin:svelte/recommended',
|
||||
'prettier'
|
||||
"eslint:recommended",
|
||||
"plugin:@typescript-eslint/recommended",
|
||||
"plugin:svelte/recommended",
|
||||
"prettier",
|
||||
],
|
||||
parser: '@typescript-eslint/parser',
|
||||
plugins: ['@typescript-eslint'],
|
||||
parser: "@typescript-eslint/parser",
|
||||
plugins: ["@typescript-eslint"],
|
||||
parserOptions: {
|
||||
sourceType: 'module',
|
||||
sourceType: "module",
|
||||
ecmaVersion: 2020,
|
||||
extraFileExtensions: ['.svelte']
|
||||
extraFileExtensions: [".svelte"],
|
||||
},
|
||||
env: {
|
||||
browser: true,
|
||||
es2017: true,
|
||||
node: true
|
||||
node: true,
|
||||
},
|
||||
overrides: [
|
||||
{
|
||||
files: ['*.svelte'],
|
||||
parser: 'svelte-eslint-parser',
|
||||
files: ["*.svelte"],
|
||||
parser: "svelte-eslint-parser",
|
||||
parserOptions: {
|
||||
parser: '@typescript-eslint/parser'
|
||||
}
|
||||
}
|
||||
]
|
||||
parser: "@typescript-eslint/parser",
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
4
.github/workflows/index.yml
vendored
4
.github/workflows/index.yml
vendored
@@ -12,11 +12,11 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
repository: 'meilisearch/scrapix'
|
||||
repository: "meilisearch/scrapix"
|
||||
- name: Use Node.js
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: '20.x'
|
||||
node-version: "20.x"
|
||||
- run: yarn
|
||||
- run: yarn start -c "$SCRAPIX_CONFIG"
|
||||
env:
|
||||
|
||||
10
.github/workflows/stale.yml
vendored
10
.github/workflows/stale.yml
vendored
@@ -2,7 +2,7 @@ name: Mark stale issues
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: '0 0 * * *' # Midnight Runtime
|
||||
- cron: "0 0 * * *" # Midnight Runtime
|
||||
|
||||
jobs:
|
||||
stale:
|
||||
@@ -13,11 +13,11 @@ jobs:
|
||||
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'
|
||||
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'
|
||||
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'
|
||||
only-labels: "question"
|
||||
|
||||
4
.github/workflows/tests.yml
vendored
4
.github/workflows/tests.yml
vendored
@@ -2,7 +2,7 @@ name: Tests
|
||||
|
||||
on:
|
||||
pull_request_target:
|
||||
branches: ['**']
|
||||
branches: ["**"]
|
||||
|
||||
permissions: read-all
|
||||
|
||||
@@ -35,7 +35,7 @@ jobs:
|
||||
run: pnpm install --frozen-lockfile
|
||||
- name: Build Website
|
||||
env:
|
||||
NODE_OPTIONS: '--max_old_space_size=8192'
|
||||
NODE_OPTIONS: "--max_old_space_size=8192"
|
||||
PUBLIC_APPWRITE_PROJECT_ID: ${{ secrets.PUBLIC_APPWRITE_PROJECT_ID }}
|
||||
PUBLIC_APPWRITE_DB_MAIN_ID: ${{ secrets.PUBLIC_APPWRITE_DB_MAIN_ID }}
|
||||
PUBLIC_APPWRITE_COL_THREADS_ID: ${{ secrets.PUBLIC_APPWRITE_COL_THREADS_ID }}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
x-logging: &x-logging
|
||||
logging:
|
||||
driver: 'json-file'
|
||||
driver: "json-file"
|
||||
options:
|
||||
max-file: '5'
|
||||
max-size: '20m'
|
||||
max-file: "5"
|
||||
max-size: "20m"
|
||||
|
||||
x-update-config: &x-update-config
|
||||
update_config:
|
||||
@@ -17,7 +17,7 @@ x-update-config: &x-update-config
|
||||
parallelism: 2
|
||||
order: stop-first
|
||||
|
||||
version: '3.8'
|
||||
version: "3.8"
|
||||
|
||||
services:
|
||||
traefik:
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
x-logging: &x-logging
|
||||
logging:
|
||||
driver: 'json-file'
|
||||
driver: "json-file"
|
||||
options:
|
||||
max-file: '5'
|
||||
max-size: '20m'
|
||||
max-file: "5"
|
||||
max-size: "20m"
|
||||
|
||||
x-update-config: &x-update-config
|
||||
update_config:
|
||||
@@ -17,7 +17,7 @@ x-update-config: &x-update-config
|
||||
parallelism: 2
|
||||
order: stop-first
|
||||
|
||||
version: '3.8'
|
||||
version: "3.8"
|
||||
|
||||
services:
|
||||
traefik:
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import type { PlaywrightTestConfig } from '@playwright/test';
|
||||
import type { PlaywrightTestConfig } from "@playwright/test";
|
||||
|
||||
const config: PlaywrightTestConfig = {
|
||||
webServer: {
|
||||
command: 'npm run build && npm run preview',
|
||||
port: 4173
|
||||
command: "npm run build && npm run preview",
|
||||
port: 4173,
|
||||
},
|
||||
testDir: 'tests',
|
||||
testMatch: /(.+\.)?(test|spec)\.[jt]s/
|
||||
testDir: "tests",
|
||||
testMatch: /(.+\.)?(test|spec)\.[jt]s/,
|
||||
};
|
||||
|
||||
export default config;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
export default {
|
||||
plugins: {
|
||||
'@tailwindcss/postcss': {}
|
||||
}
|
||||
"@tailwindcss/postcss": {},
|
||||
},
|
||||
};
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { build } from 'vite';
|
||||
import { downloadContributors } from './download-contributor-data.js';
|
||||
import { build } from "vite";
|
||||
import { downloadContributors } from "./download-contributor-data.js";
|
||||
|
||||
async function main() {
|
||||
await downloadContributors();
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import fs from 'fs';
|
||||
import fs from "fs";
|
||||
|
||||
const perPage = 100;
|
||||
|
||||
@@ -6,7 +6,7 @@ const outputFile = `./src/lib/contributors.ts`;
|
||||
|
||||
const headers = process.env.GITHUB_TOKEN
|
||||
? {
|
||||
Authorization: `token ${process.env.GITHUB_TOKEN}`
|
||||
Authorization: `token ${process.env.GITHUB_TOKEN}`,
|
||||
}
|
||||
: {};
|
||||
|
||||
@@ -22,7 +22,7 @@ async function fetchRepositories() {
|
||||
const url = `https://api.github.com/orgs/appwrite/repos?page=${page}&per_page=${perPage}`;
|
||||
|
||||
const response = await fetch(url, {
|
||||
headers
|
||||
headers,
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
@@ -37,7 +37,9 @@ async function fetchRepositories() {
|
||||
repositoriesData = repositoriesData.concat(data);
|
||||
page++;
|
||||
}
|
||||
console.log(`Fetched ${data.length} repositories. Total: ${repositoriesData.length}...\n`);
|
||||
console.log(
|
||||
`Fetched ${data.length} repositories. Total: ${repositoriesData.length}...\n`,
|
||||
);
|
||||
}
|
||||
|
||||
return repositoriesData.map((repo) => repo.full_name);
|
||||
@@ -52,7 +54,7 @@ async function fetchContributors(apiUrl) {
|
||||
console.log(`Fetching page ${page} of contributors...`);
|
||||
const url = `${apiUrl}?page=${page}&per_page=${perPage}`;
|
||||
const response = await fetch(url, {
|
||||
headers
|
||||
headers,
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
@@ -69,7 +71,9 @@ async function fetchContributors(apiUrl) {
|
||||
page++;
|
||||
}
|
||||
|
||||
console.log(`Fetched ${data.length} contributors. Total: ${contributorsData.length}...\n`);
|
||||
console.log(
|
||||
`Fetched ${data.length} contributors. Total: ${contributorsData.length}...\n`,
|
||||
);
|
||||
}
|
||||
|
||||
return contributorsData;
|
||||
@@ -78,7 +82,11 @@ async function fetchContributors(apiUrl) {
|
||||
export async function downloadContributors() {
|
||||
const contributors = new Set();
|
||||
|
||||
for (const repo of ['appwrite/appwrite', 'appwrite/console', 'appwrite/sdk-generator']) {
|
||||
for (const repo of [
|
||||
"appwrite/appwrite",
|
||||
"appwrite/console",
|
||||
"appwrite/sdk-generator",
|
||||
]) {
|
||||
console.log(`Fetching contributors for ${repo}...`);
|
||||
const url = `https://api.github.com/repos/${repo}/contributors`;
|
||||
const data = await fetchContributors(url);
|
||||
@@ -90,9 +98,9 @@ export async function downloadContributors() {
|
||||
const contributorsString = JSON.stringify(contributorsArray, null, 4);
|
||||
const contributorsFile = `export const contributors = ${contributorsString};`;
|
||||
|
||||
const currentContributors = fs.readFileSync(outputFile, 'utf8');
|
||||
const currentContributors = fs.readFileSync(outputFile, "utf8");
|
||||
if (currentContributors.length >= contributorsFile.length) {
|
||||
console.log('No new contributors found. Exiting...');
|
||||
console.log("No new contributors found. Exiting...");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import { readdirSync, statSync } from 'fs';
|
||||
import { join, relative } from 'path';
|
||||
import sharp from 'sharp';
|
||||
import { fileURLToPath } from 'url';
|
||||
import { readdirSync, statSync } from "fs";
|
||||
import { join, relative } from "path";
|
||||
import sharp from "sharp";
|
||||
import { fileURLToPath } from "url";
|
||||
|
||||
const __dirname = fileURLToPath(new URL('.', import.meta.url));
|
||||
const root_dir = join(__dirname, '../static');
|
||||
const exceptions = ['assets/'];
|
||||
const __dirname = fileURLToPath(new URL(".", import.meta.url));
|
||||
const root_dir = join(__dirname, "../static");
|
||||
const exceptions = ["assets/"];
|
||||
|
||||
/**
|
||||
* @type {{
|
||||
@@ -18,20 +18,20 @@ const exceptions = ['assets/'];
|
||||
*/
|
||||
const config = {
|
||||
jpeg: {
|
||||
quality: 100
|
||||
quality: 100,
|
||||
},
|
||||
webp: {
|
||||
lossless: true
|
||||
lossless: true,
|
||||
},
|
||||
png: {
|
||||
quality: 100
|
||||
quality: 100,
|
||||
},
|
||||
gif: {
|
||||
quality: 100
|
||||
quality: 100,
|
||||
},
|
||||
avif: {
|
||||
lossless: true
|
||||
}
|
||||
lossless: true,
|
||||
},
|
||||
};
|
||||
|
||||
/** @type {sharp.ResizeOptions} */
|
||||
@@ -39,7 +39,7 @@ const resize_config = {
|
||||
width: 1280,
|
||||
height: 1280,
|
||||
fit: sharp.fit.inside,
|
||||
withoutEnlargement: true
|
||||
withoutEnlargement: true,
|
||||
};
|
||||
|
||||
function* walk_directory(dir) {
|
||||
@@ -57,7 +57,7 @@ function* walk_directory(dir) {
|
||||
}
|
||||
|
||||
function is_image(file) {
|
||||
const extension = file.split('.').pop().toLowerCase();
|
||||
const extension = file.split(".").pop().toLowerCase();
|
||||
|
||||
return Object.keys(config).includes(extension);
|
||||
}
|
||||
@@ -67,14 +67,15 @@ function get_relative_path(file) {
|
||||
}
|
||||
|
||||
async function main() {
|
||||
for (const file of walk_directory(join(__dirname, '../static'))) {
|
||||
for (const file of walk_directory(join(__dirname, "../static"))) {
|
||||
const relative_path = get_relative_path(file);
|
||||
const is_animated = file.endsWith('.gif');
|
||||
const is_animated = file.endsWith(".gif");
|
||||
if (!is_image(file)) continue;
|
||||
if (exceptions.some((exception) => relative_path.startsWith(exception))) continue;
|
||||
if (exceptions.some((exception) => relative_path.startsWith(exception)))
|
||||
continue;
|
||||
|
||||
const image = sharp(file, {
|
||||
animated: is_animated
|
||||
animated: is_animated,
|
||||
});
|
||||
const size_before = (await image.toBuffer()).length;
|
||||
const meta = await image.metadata();
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
import { createApp, fromNodeMiddleware, toNodeListener } from 'h3';
|
||||
import { createServer } from 'node:http';
|
||||
import { handler } from '../build/handler.js';
|
||||
import { sitemap } from './sitemap.js';
|
||||
import { createApp, fromNodeMiddleware, toNodeListener } from "h3";
|
||||
import { createServer } from "node:http";
|
||||
import { handler } from "../build/handler.js";
|
||||
import { sitemap } from "./sitemap.js";
|
||||
|
||||
async function main() {
|
||||
const port = process.env.PORT || 3000;
|
||||
const app = createApp();
|
||||
app.use('/sitemap.xml', await sitemap());
|
||||
app.use("/sitemap.xml", await sitemap());
|
||||
app.use(fromNodeMiddleware(handler));
|
||||
const server = createServer(toNodeListener(app)).listen(port);
|
||||
server.addListener('listening', () => {
|
||||
server.addListener("listening", () => {
|
||||
console.log(`Listening on http://0.0.0.0:${port}`);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
import { createRequire } from 'node:module';
|
||||
import { defineEventHandler, setResponseHeader } from 'h3';
|
||||
import { createRequire } from "node:module";
|
||||
import { defineEventHandler, setResponseHeader } from "h3";
|
||||
|
||||
/**
|
||||
* @returns {Promise<import('h3').EventHandler>}
|
||||
*/
|
||||
export async function sitemap() {
|
||||
console.info('Preparing Sitemap...');
|
||||
const manifest = await import('../build/server/manifest.js');
|
||||
console.info("Preparing Sitemap...");
|
||||
const manifest = await import("../build/server/manifest.js");
|
||||
const prerendered = manifest.prerendered;
|
||||
const file_route_extensions = ['.json', '.xml'];
|
||||
const file_route_extensions = [".json", ".xml"];
|
||||
const routes = [...prerendered, ...collectThreads()].filter(
|
||||
(route) => !file_route_extensions.some((ext) => route.endsWith(ext))
|
||||
(route) => !file_route_extensions.some((ext) => route.endsWith(ext)),
|
||||
);
|
||||
console.info(`Sitemap loaded with ${routes.length} routes!`);
|
||||
|
||||
@@ -21,13 +21,13 @@ export async function sitemap() {
|
||||
(route) => `<url>
|
||||
<loc>https://appwrite.io${route}</loc>
|
||||
</url>
|
||||
`
|
||||
`,
|
||||
)
|
||||
.join('')}
|
||||
.join("")}
|
||||
</urlset>`;
|
||||
|
||||
return defineEventHandler((event) => {
|
||||
setResponseHeader(event, 'Content-Type', 'application/xml');
|
||||
setResponseHeader(event, "Content-Type", "application/xml");
|
||||
|
||||
return sitemap;
|
||||
});
|
||||
@@ -37,7 +37,9 @@ export async function sitemap() {
|
||||
* @returns {string[]}
|
||||
*/
|
||||
function collectThreads() {
|
||||
const threads = createRequire(import.meta.url)('../build/prerendered/threads/data.json');
|
||||
const threads = createRequire(import.meta.url)(
|
||||
"../build/prerendered/threads/data.json",
|
||||
);
|
||||
|
||||
return threads.map((id) => `/threads/${id}`);
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { dev } from '$app/environment';
|
||||
import { SENTRY_DSN } from '$lib/constants';
|
||||
import { handleErrorWithSentry, replayIntegration } from '@sentry/sveltekit';
|
||||
import * as Sentry from '@sentry/sveltekit';
|
||||
import { dev } from "$app/environment";
|
||||
import { SENTRY_DSN } from "$lib/constants";
|
||||
import { handleErrorWithSentry, replayIntegration } from "@sentry/sveltekit";
|
||||
import * as Sentry from "@sentry/sveltekit";
|
||||
|
||||
Sentry.init({
|
||||
enabled: !dev,
|
||||
@@ -22,9 +22,9 @@ Sentry.init({
|
||||
replayIntegration({
|
||||
maskAllInputs: true,
|
||||
maskAllText: false,
|
||||
blockAllMedia: false
|
||||
})
|
||||
]
|
||||
blockAllMedia: false,
|
||||
}),
|
||||
],
|
||||
});
|
||||
|
||||
// If you have a custom error handler, pass it to `handleErrorWithSentry`
|
||||
|
||||
@@ -1,18 +1,20 @@
|
||||
import * as Sentry from '@sentry/sveltekit';
|
||||
import type { Handle } from '@sveltejs/kit';
|
||||
import redirects from './redirects.json';
|
||||
import { sequence } from '@sveltejs/kit/hooks';
|
||||
import { BANNER_KEY, SENTRY_DSN } from '$lib/constants';
|
||||
import { dev } from '$app/environment';
|
||||
import * as Sentry from "@sentry/sveltekit";
|
||||
import type { Handle } from "@sveltejs/kit";
|
||||
import redirects from "./redirects.json";
|
||||
import { sequence } from "@sveltejs/kit/hooks";
|
||||
import { BANNER_KEY, SENTRY_DSN } from "$lib/constants";
|
||||
import { dev } from "$app/environment";
|
||||
|
||||
Sentry.init({
|
||||
enabled: !dev,
|
||||
dsn: SENTRY_DSN,
|
||||
tracesSampleRate: 1,
|
||||
allowUrls: [/appwrite\.io/]
|
||||
allowUrls: [/appwrite\.io/],
|
||||
});
|
||||
|
||||
const redirectMap = new Map(redirects.map(({ link, redirect }) => [link, redirect]));
|
||||
const redirectMap = new Map(
|
||||
redirects.map(({ link, redirect }) => [link, redirect]),
|
||||
);
|
||||
|
||||
const redirecter: Handle = async ({ event, resolve }) => {
|
||||
const currentPath = event.url.pathname;
|
||||
@@ -20,8 +22,8 @@ const redirecter: Handle = async ({ event, resolve }) => {
|
||||
return new Response(null, {
|
||||
status: 308,
|
||||
headers: {
|
||||
location: redirectMap.get(currentPath) ?? ''
|
||||
}
|
||||
location: redirectMap.get(currentPath) ?? "",
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -30,10 +32,15 @@ const redirecter: Handle = async ({ event, resolve }) => {
|
||||
|
||||
const bannerRewriter: Handle = async ({ event, resolve }) => {
|
||||
const response = await resolve(event, {
|
||||
transformPageChunk: ({ html }) => html.replace('%aw_banner_key%', BANNER_KEY)
|
||||
transformPageChunk: ({ html }) =>
|
||||
html.replace("%aw_banner_key%", BANNER_KEY),
|
||||
});
|
||||
return response;
|
||||
};
|
||||
|
||||
export const handle = sequence(Sentry.sentryHandle(), redirecter, bannerRewriter);
|
||||
export const handle = sequence(
|
||||
Sentry.sentryHandle(),
|
||||
redirecter,
|
||||
bannerRewriter,
|
||||
);
|
||||
export const handleError = Sentry.handleErrorWithSentry();
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
import { generateIcons } from './scripts.js';
|
||||
import { generateIcons } from "./scripts.js";
|
||||
|
||||
generateIcons();
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
import { optimizeSVG } from './scripts.js';
|
||||
import { optimizeSVG } from "./scripts.js";
|
||||
|
||||
optimizeSVG();
|
||||
|
||||
@@ -1,71 +1,178 @@
|
||||
@font-face {
|
||||
font-family: "web-icon";
|
||||
font-display: swap;
|
||||
src: url('web-icon.eot'); /* IE9*/
|
||||
src: url('web-icon.eot#iefix') format('embedded-opentype'), /* IE6-IE8 */
|
||||
url("web-icon.woff2") format("woff2"),
|
||||
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- */
|
||||
url("web-icon.ttf") format("truetype"),
|
||||
/* chrome, firefox, opera, Safari, Android, iOS 4.2+*/
|
||||
url("web-icon.svg#web-icon") format("svg"); /* iOS 4.1- */
|
||||
}
|
||||
|
||||
[class^="web-icon-"], [class*=" web-icon-"] {
|
||||
font-family: 'web-icon' !important;
|
||||
[class^="web-icon-"],
|
||||
[class*=" web-icon-"] {
|
||||
font-family: "web-icon" !important;
|
||||
font-size: 20px;
|
||||
font-style: normal;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
.web-icon-apple:before { content: "\ea01"; }
|
||||
.web-icon-appwrite:before { content: "\ea02"; }
|
||||
.web-icon-arrow-down:before { content: "\ea03"; }
|
||||
.web-icon-arrow-ext-link:before { content: "\ea04"; }
|
||||
.web-icon-arrow-left:before { content: "\ea05"; }
|
||||
.web-icon-arrow-right:before { content: "\ea06"; }
|
||||
.web-icon-arrow-up:before { content: "\ea07"; }
|
||||
.web-icon-calendar:before { content: "\ea08"; }
|
||||
.web-icon-check:before { content: "\ea09"; }
|
||||
.web-icon-chevron-down:before { content: "\ea0a"; }
|
||||
.web-icon-chevron-left:before { content: "\ea0b"; }
|
||||
.web-icon-chevron-right:before { content: "\ea0c"; }
|
||||
.web-icon-chevron-up:before { content: "\ea0d"; }
|
||||
.web-icon-close:before { content: "\ea0e"; }
|
||||
.web-icon-command:before { content: "\ea0f"; }
|
||||
.web-icon-copy:before { content: "\ea10"; }
|
||||
.web-icon-daily-dev:before { content: "\ea11"; }
|
||||
.web-icon-dark:before { content: "\ea12"; }
|
||||
.web-icon-discord:before { content: "\ea13"; }
|
||||
.web-icon-divider-vertical:before { content: "\ea14"; }
|
||||
.web-icon-download:before { content: "\ea15"; }
|
||||
.web-icon-ext-link:before { content: "\ea16"; }
|
||||
.web-icon-firebase:before { content: "\ea17"; }
|
||||
.web-icon-github:before { content: "\ea18"; }
|
||||
.web-icon-google:before { content: "\ea19"; }
|
||||
.web-icon-hamburger-menu:before { content: "\ea1a"; }
|
||||
.web-icon-light:before { content: "\ea1b"; }
|
||||
.web-icon-linkedin:before { content: "\ea1c"; }
|
||||
.web-icon-location:before { content: "\ea1d"; }
|
||||
.web-icon-logout-left:before { content: "\ea1e"; }
|
||||
.web-icon-logout-right:before { content: "\ea1f"; }
|
||||
.web-icon-mailgun:before { content: "\ea20"; }
|
||||
.web-icon-message:before { content: "\ea21"; }
|
||||
.web-icon-microsoft:before { content: "\ea22"; }
|
||||
.web-icon-minus:before { content: "\ea23"; }
|
||||
.web-icon-nuxt:before { content: "\ea24"; }
|
||||
.web-icon-platform:before { content: "\ea25"; }
|
||||
.web-icon-play:before { content: "\ea26"; }
|
||||
.web-icon-plus:before { content: "\ea27"; }
|
||||
.web-icon-product-hunt:before { content: "\ea28"; }
|
||||
.web-icon-refine:before { content: "\ea29"; }
|
||||
.web-icon-rest:before { content: "\ea2a"; }
|
||||
.web-icon-search:before { content: "\ea2b"; }
|
||||
.web-icon-sendgrid:before { content: "\ea2c"; }
|
||||
.web-icon-star:before { content: "\ea2d"; }
|
||||
.web-icon-system:before { content: "\ea2e"; }
|
||||
.web-icon-textmagic:before { content: "\ea2f"; }
|
||||
.web-icon-twitter:before { content: "\ea30"; }
|
||||
.web-icon-vue:before { content: "\ea31"; }
|
||||
.web-icon-x:before { content: "\ea32"; }
|
||||
.web-icon-ycombinator:before { content: "\ea33"; }
|
||||
.web-icon-youtube:before { content: "\ea34"; }
|
||||
.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-daily-dev:before {
|
||||
content: "\ea11";
|
||||
}
|
||||
.web-icon-dark:before {
|
||||
content: "\ea12";
|
||||
}
|
||||
.web-icon-discord:before {
|
||||
content: "\ea13";
|
||||
}
|
||||
.web-icon-divider-vertical:before {
|
||||
content: "\ea14";
|
||||
}
|
||||
.web-icon-download:before {
|
||||
content: "\ea15";
|
||||
}
|
||||
.web-icon-ext-link:before {
|
||||
content: "\ea16";
|
||||
}
|
||||
.web-icon-firebase:before {
|
||||
content: "\ea17";
|
||||
}
|
||||
.web-icon-github:before {
|
||||
content: "\ea18";
|
||||
}
|
||||
.web-icon-google:before {
|
||||
content: "\ea19";
|
||||
}
|
||||
.web-icon-hamburger-menu:before {
|
||||
content: "\ea1a";
|
||||
}
|
||||
.web-icon-light:before {
|
||||
content: "\ea1b";
|
||||
}
|
||||
.web-icon-linkedin:before {
|
||||
content: "\ea1c";
|
||||
}
|
||||
.web-icon-location:before {
|
||||
content: "\ea1d";
|
||||
}
|
||||
.web-icon-logout-left:before {
|
||||
content: "\ea1e";
|
||||
}
|
||||
.web-icon-logout-right:before {
|
||||
content: "\ea1f";
|
||||
}
|
||||
.web-icon-mailgun:before {
|
||||
content: "\ea20";
|
||||
}
|
||||
.web-icon-message:before {
|
||||
content: "\ea21";
|
||||
}
|
||||
.web-icon-microsoft:before {
|
||||
content: "\ea22";
|
||||
}
|
||||
.web-icon-minus:before {
|
||||
content: "\ea23";
|
||||
}
|
||||
.web-icon-nuxt:before {
|
||||
content: "\ea24";
|
||||
}
|
||||
.web-icon-platform:before {
|
||||
content: "\ea25";
|
||||
}
|
||||
.web-icon-play:before {
|
||||
content: "\ea26";
|
||||
}
|
||||
.web-icon-plus:before {
|
||||
content: "\ea27";
|
||||
}
|
||||
.web-icon-product-hunt:before {
|
||||
content: "\ea28";
|
||||
}
|
||||
.web-icon-refine:before {
|
||||
content: "\ea29";
|
||||
}
|
||||
.web-icon-rest:before {
|
||||
content: "\ea2a";
|
||||
}
|
||||
.web-icon-search:before {
|
||||
content: "\ea2b";
|
||||
}
|
||||
.web-icon-sendgrid:before {
|
||||
content: "\ea2c";
|
||||
}
|
||||
.web-icon-star:before {
|
||||
content: "\ea2d";
|
||||
}
|
||||
.web-icon-system:before {
|
||||
content: "\ea2e";
|
||||
}
|
||||
.web-icon-textmagic:before {
|
||||
content: "\ea2f";
|
||||
}
|
||||
.web-icon-twitter:before {
|
||||
content: "\ea30";
|
||||
}
|
||||
.web-icon-vue:before {
|
||||
content: "\ea31";
|
||||
}
|
||||
.web-icon-x:before {
|
||||
content: "\ea32";
|
||||
}
|
||||
.web-icon-ycombinator:before {
|
||||
content: "\ea33";
|
||||
}
|
||||
.web-icon-youtube:before {
|
||||
content: "\ea34";
|
||||
}
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
// @ts-expect-error missing types
|
||||
import SVGFixer from 'oslllo-svg-fixer';
|
||||
import svgtofont from 'svgtofont';
|
||||
import { resolve } from 'path';
|
||||
import SVGFixer from "oslllo-svg-fixer";
|
||||
import svgtofont from "svgtofont";
|
||||
import { resolve } from "path";
|
||||
|
||||
const src = resolve(process.cwd(), 'src/icons/svg');
|
||||
const optimized = resolve(process.cwd(), 'src/icons/optimized');
|
||||
const dist = resolve(process.cwd(), 'src/icons/output');
|
||||
const src = resolve(process.cwd(), "src/icons/svg");
|
||||
const optimized = resolve(process.cwd(), "src/icons/optimized");
|
||||
const dist = resolve(process.cwd(), "src/icons/output");
|
||||
|
||||
export const optimizeSVG = async () => {
|
||||
const fixer = new SVGFixer(src, optimized, {
|
||||
showProgressBar: true
|
||||
showProgressBar: true,
|
||||
});
|
||||
|
||||
await fixer.fix();
|
||||
@@ -17,13 +17,13 @@ export const optimizeSVG = async () => {
|
||||
|
||||
export const generateIcons = async () => {
|
||||
await svgtofont({
|
||||
classNamePrefix: 'web-icon',
|
||||
classNamePrefix: "web-icon",
|
||||
src: optimized,
|
||||
dist: dist,
|
||||
fontName: 'web-icon',
|
||||
styleTemplates: resolve(process.cwd(), 'src/icons/templates'),
|
||||
fontName: "web-icon",
|
||||
styleTemplates: resolve(process.cwd(), "src/icons/templates"),
|
||||
css: {
|
||||
fontSize: '20px'
|
||||
fontSize: "20px",
|
||||
},
|
||||
outSVGReact: false,
|
||||
svgicons2svgfont: {
|
||||
@@ -32,9 +32,9 @@ export const generateIcons = async () => {
|
||||
fixedWidth: true,
|
||||
fontHeight: 1000,
|
||||
normalize: true,
|
||||
descent: 200
|
||||
descent: 200,
|
||||
},
|
||||
emptyDist: true,
|
||||
generateInfoData: true
|
||||
generateInfoData: true,
|
||||
});
|
||||
};
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
<script lang="ts">
|
||||
export let src: string;
|
||||
export let alt = '';
|
||||
export let alt = "";
|
||||
export let controls = true;
|
||||
export let autoplay = false;
|
||||
let className = '';
|
||||
let className = "";
|
||||
export { className as class };
|
||||
|
||||
const videoExtensions = ['mp4', 'webm', 'ogg'] as const;
|
||||
const videoExtensions = ["mp4", "webm", "ogg"] as const;
|
||||
$: isVideo = videoExtensions.some((ext) => src.endsWith(ext));
|
||||
</script>
|
||||
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
<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;
|
||||
|
||||
const {
|
||||
elements: { content }
|
||||
elements: { content },
|
||||
} = getTabsContext();
|
||||
</script>
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script lang="ts" context="module">
|
||||
const CTX_KEY = 'tabs';
|
||||
const CTX_KEY = "tabs";
|
||||
|
||||
type Context = Tabs & {
|
||||
tabs: readonly string[];
|
||||
@@ -15,12 +15,12 @@
|
||||
</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 tabs: Context["tabs"];
|
||||
export let tab = tabs[0];
|
||||
|
||||
const ctx = createTabs({
|
||||
@@ -28,7 +28,7 @@
|
||||
onValueChange({ next }) {
|
||||
tab = next;
|
||||
return next;
|
||||
}
|
||||
},
|
||||
});
|
||||
$: value.set(tab);
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
|
||||
const {
|
||||
elements: { root },
|
||||
states: { value }
|
||||
states: { value },
|
||||
} = ctx;
|
||||
</script>
|
||||
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
export { default as Tabs } from './Tabs/index.svelte';
|
||||
export { default as Media } from './Media.svelte';
|
||||
export { default as Tabs } from "./Tabs/index.svelte";
|
||||
export { default as Media } from "./Media.svelte";
|
||||
|
||||
@@ -1,15 +1,18 @@
|
||||
export function clickOutside(node: HTMLElement, callback: (e: MouseEvent) => void) {
|
||||
export function clickOutside(
|
||||
node: HTMLElement,
|
||||
callback: (e: MouseEvent) => void,
|
||||
) {
|
||||
const handleClick = (event: MouseEvent) => {
|
||||
if (node && !node.contains(event.target as Node)) {
|
||||
callback(event);
|
||||
}
|
||||
};
|
||||
|
||||
document.addEventListener('click', handleClick, true);
|
||||
document.addEventListener("click", handleClick, true);
|
||||
|
||||
return {
|
||||
destroy() {
|
||||
document.removeEventListener('click', handleClick, true);
|
||||
}
|
||||
document.removeEventListener("click", handleClick, true);
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
export const highlight = (node: HTMLElement, text: string[]) => {
|
||||
text.forEach((word) => {
|
||||
const regex = new RegExp(`(${word})`, 'gi');
|
||||
node.innerHTML = node.innerHTML.replace(regex, '<mark>$1</mark>');
|
||||
const regex = new RegExp(`(${word})`, "gi");
|
||||
node.innerHTML = node.innerHTML.replace(regex, "<mark>$1</mark>");
|
||||
});
|
||||
};
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
export * from './portal';
|
||||
export * from './rect';
|
||||
export * from './visible';
|
||||
export * from "./portal";
|
||||
export * from "./rect";
|
||||
export * from "./visible";
|
||||
|
||||
@@ -1,22 +1,25 @@
|
||||
import { tick } from 'svelte';
|
||||
import type { Action } from 'svelte/action';
|
||||
import { tick } from "svelte";
|
||||
import type { Action } from "svelte/action";
|
||||
|
||||
export type PortalConfig =
|
||||
| { target?: string | HTMLElement | undefined; prepend?: boolean }
|
||||
| undefined;
|
||||
|
||||
const defaults: PortalConfig = {
|
||||
target: 'body',
|
||||
prepend: false
|
||||
target: "body",
|
||||
prepend: false,
|
||||
};
|
||||
|
||||
export const portal: Action<HTMLElement, PortalConfig> = (el, config?: PortalConfig) => {
|
||||
export const portal: Action<HTMLElement, PortalConfig> = (
|
||||
el,
|
||||
config?: PortalConfig,
|
||||
) => {
|
||||
let targetEl;
|
||||
|
||||
async function update(newConfig: PortalConfig) {
|
||||
const { target, prepend } = { ...defaults, ...newConfig };
|
||||
|
||||
if (typeof target === 'string') {
|
||||
if (typeof target === "string") {
|
||||
targetEl = document.querySelector(target);
|
||||
if (targetEl === null) {
|
||||
await tick();
|
||||
@@ -30,11 +33,11 @@ export const portal: Action<HTMLElement, PortalConfig> = (el, config?: PortalCon
|
||||
} else {
|
||||
throw new TypeError(
|
||||
`Unknown portal target type: ${
|
||||
target === null ? 'null' : typeof target
|
||||
}. Allowed types: string (CSS selector) or HTMLElement.`
|
||||
target === null ? "null" : typeof target
|
||||
}. Allowed types: string (CSS selector) or HTMLElement.`,
|
||||
);
|
||||
}
|
||||
el.dataset.portal = '';
|
||||
el.dataset.portal = "";
|
||||
if (prepend) {
|
||||
targetEl.prepend(el);
|
||||
} else {
|
||||
@@ -50,6 +53,6 @@ export const portal: Action<HTMLElement, PortalConfig> = (el, config?: PortalCon
|
||||
update(config ?? {});
|
||||
return {
|
||||
update,
|
||||
destroy
|
||||
destroy,
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import type { Action } from 'svelte/action';
|
||||
import type { Writable } from 'svelte/store';
|
||||
import type { Action } from "svelte/action";
|
||||
import type { Writable } from "svelte/store";
|
||||
|
||||
type Args = Writable<DOMRect | null>;
|
||||
|
||||
@@ -23,6 +23,6 @@ export const rect: Action<HTMLElement, Args> = (node, store) => {
|
||||
update,
|
||||
destroy() {
|
||||
// no-op
|
||||
}
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
@@ -2,15 +2,15 @@ export const scrollToTop = (node: HTMLElement) => {
|
||||
const handleClick = () => {
|
||||
window.scrollTo({
|
||||
top: 0,
|
||||
behavior: 'smooth'
|
||||
behavior: "smooth",
|
||||
});
|
||||
};
|
||||
|
||||
node.addEventListener('click', handleClick);
|
||||
node.addEventListener("click", handleClick);
|
||||
|
||||
return {
|
||||
destroy() {
|
||||
node.removeEventListener('click', handleClick);
|
||||
}
|
||||
node.removeEventListener("click", handleClick);
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { isVisible } from '$lib/utils/isVisible';
|
||||
import type { Action } from 'svelte/action';
|
||||
import { isVisible } from "$lib/utils/isVisible";
|
||||
import type { Action } from "svelte/action";
|
||||
|
||||
type Args =
|
||||
| {
|
||||
@@ -13,7 +13,7 @@ type Args =
|
||||
export const visible: Action<
|
||||
HTMLElement,
|
||||
Args,
|
||||
{ 'on:visible': (e: CustomEvent<boolean>) => void }
|
||||
{ "on:visible": (e: CustomEvent<boolean>) => void }
|
||||
> = (node, args) => {
|
||||
let visible = false;
|
||||
|
||||
@@ -23,11 +23,11 @@ export const visible: Action<
|
||||
bottom: window.innerHeight,
|
||||
left: 0,
|
||||
right: window.innerWidth,
|
||||
...newArgs
|
||||
...newArgs,
|
||||
};
|
||||
return () => {
|
||||
visible = isVisible(node, argsWithDefaults);
|
||||
node.dispatchEvent(new CustomEvent('visible', { detail: visible }));
|
||||
node.dispatchEvent(new CustomEvent("visible", { detail: visible }));
|
||||
};
|
||||
};
|
||||
|
||||
@@ -35,15 +35,15 @@ export const visible: Action<
|
||||
handleVisibility();
|
||||
|
||||
function destroy() {
|
||||
window.removeEventListener('scroll', handleVisibility);
|
||||
window.removeEventListener('resize', handleVisibility);
|
||||
window.removeEventListener("scroll", handleVisibility);
|
||||
window.removeEventListener("resize", handleVisibility);
|
||||
}
|
||||
|
||||
function update(args: Args) {
|
||||
destroy();
|
||||
handleVisibility = createVisibilityHandler(args);
|
||||
window.addEventListener('scroll', handleVisibility);
|
||||
window.addEventListener('resize', handleVisibility);
|
||||
window.addEventListener("scroll", handleVisibility);
|
||||
window.addEventListener("resize", handleVisibility);
|
||||
}
|
||||
|
||||
update(args);
|
||||
@@ -51,8 +51,8 @@ export const visible: Action<
|
||||
return {
|
||||
update,
|
||||
destroy() {
|
||||
window.removeEventListener('scroll', handleVisibility);
|
||||
window.removeEventListener('resize', handleVisibility);
|
||||
}
|
||||
window.removeEventListener("scroll", handleVisibility);
|
||||
window.removeEventListener("resize", handleVisibility);
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<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);
|
||||
</script>
|
||||
|
||||
@@ -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' });
|
||||
$: codeHtml = getCodeHtml({ content, language: "js" });
|
||||
</script>
|
||||
|
||||
<!-- eslint-disable-next-line svelte/no-at-html-tags -->
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<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">
|
||||
@@ -18,7 +18,7 @@
|
||||
</div>
|
||||
|
||||
<style lang="scss">
|
||||
@use '$scss/abstract/mixins/border-gradient' as gradients;
|
||||
@use "$scss/abstract/mixins/border-gradient" as gradients;
|
||||
|
||||
.code-console {
|
||||
@include gradients.border-gradient;
|
||||
@@ -48,7 +48,11 @@
|
||||
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%);
|
||||
background: linear-gradient(
|
||||
129deg,
|
||||
rgba(0, 0, 0, 0.48) 22.38%,
|
||||
rgba(0, 0, 0, 0) 136.5%
|
||||
);
|
||||
padding: 20px;
|
||||
|
||||
position: relative;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script lang="ts">
|
||||
import AutoHeight from '../AutoBox.svelte';
|
||||
import AutoHeight from "../AutoBox.svelte";
|
||||
</script>
|
||||
|
||||
<div class="anim-box">
|
||||
@@ -12,7 +12,7 @@
|
||||
</div>
|
||||
|
||||
<style lang="scss">
|
||||
@use '$scss/abstract/mixins/border-gradient' as gradients;
|
||||
@use "$scss/abstract/mixins/border-gradient" as gradients;
|
||||
|
||||
.anim-box {
|
||||
@include gradients.border-gradient;
|
||||
|
||||
@@ -1,19 +1,19 @@
|
||||
<script lang="ts">
|
||||
import { createCheckbox, melt } from '@melt-ui/svelte';
|
||||
import { createCheckbox, melt } from "@melt-ui/svelte";
|
||||
|
||||
export let checked = false;
|
||||
|
||||
const {
|
||||
elements: { root },
|
||||
states: { checked: localChecked },
|
||||
helpers: { isChecked }
|
||||
helpers: { isChecked },
|
||||
} = createCheckbox({
|
||||
onCheckedChange({ next }) {
|
||||
if (typeof next === 'boolean') {
|
||||
if (typeof next === "boolean") {
|
||||
checked = next;
|
||||
}
|
||||
return next;
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
$: localChecked.set(checked);
|
||||
@@ -43,13 +43,13 @@
|
||||
|
||||
position: relative;
|
||||
|
||||
&:global(.anim-checkbox[data-state='checked']) {
|
||||
&:global(.anim-checkbox[data-state="checked"]) {
|
||||
background-color: #7c67fe;
|
||||
border-color: #7c67fe;
|
||||
}
|
||||
}
|
||||
|
||||
[class*='icon-'] {
|
||||
[class*="icon-"] {
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script lang="ts">
|
||||
import Code from '$lib/animations/CodeWindow/Code.svelte';
|
||||
import { authController } from '.';
|
||||
import Code from "$lib/animations/CodeWindow/Code.svelte";
|
||||
import { authController } from ".";
|
||||
|
||||
const { state } = authController;
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<script lang="ts">
|
||||
import { Switch } from '$lib/components';
|
||||
import { objectKeys } from '$lib/utils/object';
|
||||
import { authController } from '.';
|
||||
import { Switch } from "$lib/components";
|
||||
import { objectKeys } from "$lib/utils/object";
|
||||
import { authController } from ".";
|
||||
|
||||
const { state } = authController;
|
||||
|
||||
@@ -61,7 +61,7 @@
|
||||
margin-block: 0.5rem;
|
||||
}
|
||||
|
||||
[class*='icon-'] {
|
||||
[class*="icon-"] {
|
||||
--size: 2rem;
|
||||
font-size: var(--size);
|
||||
width: var(--size);
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
import Box from './box.svelte';
|
||||
import Code from './code.svelte';
|
||||
import Controls from './controls.svelte';
|
||||
import Phone from './phone.svelte';
|
||||
import Box from "./box.svelte";
|
||||
import Code from "./code.svelte";
|
||||
import Controls from "./controls.svelte";
|
||||
import Phone from "./phone.svelte";
|
||||
|
||||
export const Auth = {
|
||||
Phone,
|
||||
Box,
|
||||
Code,
|
||||
Controls
|
||||
Controls,
|
||||
};
|
||||
|
||||
import { safeAnimate, sleep, write } from '$lib/animations';
|
||||
import { createResettable } from '$lib/utils/resettable';
|
||||
import { getElSelector } from '../Products.svelte';
|
||||
import { safeAnimate, sleep, write } from "$lib/animations";
|
||||
import { createResettable } from "$lib/utils/resettable";
|
||||
import { getElSelector } from "../Products.svelte";
|
||||
|
||||
type State = {
|
||||
email: string;
|
||||
@@ -30,8 +30,8 @@ type State = {
|
||||
};
|
||||
|
||||
const state = createResettable<State>({
|
||||
email: '',
|
||||
password: '',
|
||||
email: "",
|
||||
password: "",
|
||||
name: "Walter O'Brian",
|
||||
showControls: false,
|
||||
submitted: false,
|
||||
@@ -39,44 +39,55 @@ const state = createResettable<State>({
|
||||
GitHub: true,
|
||||
Google: false,
|
||||
Apple: false,
|
||||
Microsoft: false
|
||||
}
|
||||
Microsoft: false,
|
||||
},
|
||||
});
|
||||
|
||||
const emailToSet = 'walterobrian@example.com';
|
||||
const passwordToSet = 'password';
|
||||
const emailToSet = "walterobrian@example.com";
|
||||
const passwordToSet = "password";
|
||||
|
||||
const execute = async () => {
|
||||
const phone = getElSelector('phone');
|
||||
const box = getElSelector('box');
|
||||
const code = getElSelector('code');
|
||||
const controls = getElSelector('controls');
|
||||
const phone = getElSelector("phone");
|
||||
const box = getElSelector("box");
|
||||
const code = getElSelector("code");
|
||||
const controls = getElSelector("controls");
|
||||
|
||||
// Reset
|
||||
const { update } = state.reset();
|
||||
|
||||
await Promise.all([
|
||||
safeAnimate(box, { x: 310, y: 140, opacity: 0 }, { duration: 0.5 })?.finished,
|
||||
safeAnimate(code, { x: 200, y: 460, opacity: 0 }, { duration: 0.5 })?.finished,
|
||||
safeAnimate(box, { x: 310, y: 140, opacity: 0 }, { duration: 0.5 })
|
||||
?.finished,
|
||||
safeAnimate(code, { x: 200, y: 460, opacity: 0 }, { duration: 0.5 })
|
||||
?.finished,
|
||||
safeAnimate(phone, { x: 0, y: 0 }, { duration: 0.5 })?.finished,
|
||||
safeAnimate(controls, { x: 420, y: 0, opacity: 0 }, { duration: 0.5 })?.finished
|
||||
safeAnimate(controls, { x: 420, y: 0, opacity: 0 }, { duration: 0.5 })
|
||||
?.finished,
|
||||
]);
|
||||
|
||||
// Start
|
||||
await safeAnimate(box, { y: [48, 140], opacity: 1 }, { duration: 0.25, delay: 0.25 })?.finished;
|
||||
await safeAnimate(
|
||||
box,
|
||||
{ y: [48, 140], opacity: 1 },
|
||||
{ duration: 0.25, delay: 0.25 },
|
||||
)?.finished;
|
||||
|
||||
await sleep(50);
|
||||
|
||||
await write(emailToSet, (v) => update((p) => ({ ...p, email: v })), 300);
|
||||
await sleep(50);
|
||||
|
||||
await write(passwordToSet, (v) => update((p) => ({ ...p, password: v })), 300);
|
||||
await write(
|
||||
passwordToSet,
|
||||
(v) => update((p) => ({ ...p, password: v })),
|
||||
300,
|
||||
);
|
||||
await sleep(50);
|
||||
|
||||
await safeAnimate(
|
||||
code,
|
||||
{ x: [200, 200], y: [460 + 16, 460], opacity: [0, 1] },
|
||||
{ duration: 0.25 }
|
||||
{ duration: 0.25 },
|
||||
)?.finished;
|
||||
|
||||
await sleep(350);
|
||||
@@ -86,10 +97,14 @@ const execute = async () => {
|
||||
await sleep(1000);
|
||||
|
||||
update((p) => ({ ...p, showControls: true }));
|
||||
safeAnimate(controls, { x: [420, 420], y: [16, 0], opacity: 1 }, { duration: 0.5 });
|
||||
safeAnimate(
|
||||
controls,
|
||||
{ x: [420, 420], y: [16, 0], opacity: 1 },
|
||||
{ duration: 0.5 },
|
||||
);
|
||||
};
|
||||
|
||||
export const authController = {
|
||||
execute,
|
||||
state
|
||||
state,
|
||||
};
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
<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;
|
||||
|
||||
$: 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 light">
|
||||
@@ -15,7 +16,12 @@
|
||||
<div class="inputs">
|
||||
<fieldset>
|
||||
<label for="name">Your Name</label>
|
||||
<input type="name" id="name" placeholder="Enter your name" bind:value={$state.name} />
|
||||
<input
|
||||
type="name"
|
||||
id="name"
|
||||
placeholder="Enter your name"
|
||||
bind:value={$state.name}
|
||||
/>
|
||||
</fieldset>
|
||||
<fieldset>
|
||||
<label for="email">Your Email</label>
|
||||
@@ -38,7 +44,9 @@
|
||||
</div>
|
||||
<button class="sign-up">Sign Up</button>
|
||||
{#if controlsEnabled}
|
||||
<span class="with-sep" transition:fade={{ duration: 100 }}>or sign up with</span>
|
||||
<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
|
||||
@@ -166,7 +174,7 @@
|
||||
|
||||
&::before,
|
||||
&::after {
|
||||
content: '';
|
||||
content: "";
|
||||
height: 1px;
|
||||
flex-grow: 1;
|
||||
background-color: hsl(var(--web-color-greyscale-200));
|
||||
@@ -213,7 +221,8 @@
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
transform: translate(-50%, -50%) scale(var(--inverse-sx, 1), var(--inverse-sy, 1));
|
||||
transform: translate(-50%, -50%)
|
||||
scale(var(--inverse-sx, 1), var(--inverse-sy, 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<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;
|
||||
</script>
|
||||
@@ -12,7 +12,11 @@
|
||||
<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="row"
|
||||
transition:slide={{ duration: 150 }}
|
||||
animate:flip={{ duration: 150 }}
|
||||
>
|
||||
<div class="copy-button">
|
||||
<span class="web-icon-copy" />
|
||||
<span>{task.id}</span>
|
||||
@@ -34,12 +38,12 @@
|
||||
background: rgba(255, 255, 255, 0.04);
|
||||
backdrop-filter: blur(2.6666667461395264px);
|
||||
|
||||
[class*='icon-'] {
|
||||
[class*="icon-"] {
|
||||
font-size: 1.25rem;
|
||||
color: hsl(var(--web-color-greyscale-600));
|
||||
}
|
||||
|
||||
span:not([class*='icon-']) {
|
||||
span:not([class*="icon-"]) {
|
||||
color: var(--greyscale-400, #adadb1);
|
||||
font-family: Inter;
|
||||
font-size: 0.875rem;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script lang="ts">
|
||||
import Code from '$lib/animations/CodeWindow/Code.svelte';
|
||||
import Code from "$lib/animations/CodeWindow/Code.svelte";
|
||||
|
||||
let content = `
|
||||
const result = databases.createDocument(
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import Box from './box.svelte';
|
||||
import Code from './code.svelte';
|
||||
import Phone from './phone.svelte';
|
||||
import Box from "./box.svelte";
|
||||
import Code from "./code.svelte";
|
||||
import Phone from "./phone.svelte";
|
||||
|
||||
import { safeAnimate, sleep } from '$lib/animations';
|
||||
import { createResettable } from '$lib/utils/resettable';
|
||||
import { getElSelector } from '../Products.svelte';
|
||||
import { safeAnimate, sleep } from "$lib/animations";
|
||||
import { createResettable } from "$lib/utils/resettable";
|
||||
import { getElSelector } from "../Products.svelte";
|
||||
|
||||
type Task = {
|
||||
id: string;
|
||||
@@ -20,24 +20,25 @@ type State = {
|
||||
const state = createResettable<State>({
|
||||
tasks: [
|
||||
{
|
||||
id: '3397fecdedb13397fecdedb1',
|
||||
title: 'Research user needs',
|
||||
checked: true
|
||||
}
|
||||
id: "3397fecdedb13397fecdedb1",
|
||||
title: "Research user needs",
|
||||
checked: true,
|
||||
},
|
||||
],
|
||||
tableSlice: 1
|
||||
tableSlice: 1,
|
||||
});
|
||||
|
||||
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();
|
||||
|
||||
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
|
||||
safeAnimate(code, { x: 80, y: 320, opacity: 1 }, { duration: 0.5 })
|
||||
?.finished,
|
||||
]);
|
||||
|
||||
await sleep(250);
|
||||
@@ -47,17 +48,17 @@ const execute = async () => {
|
||||
tasks: [
|
||||
...p.tasks,
|
||||
{
|
||||
id: '3397fecdedb13397fecdedb2',
|
||||
title: 'Create wireframes',
|
||||
checked: false
|
||||
}
|
||||
]
|
||||
id: "3397fecdedb13397fecdedb2",
|
||||
title: "Create wireframes",
|
||||
checked: false,
|
||||
},
|
||||
],
|
||||
}));
|
||||
await sleep(250);
|
||||
|
||||
update((p) => ({
|
||||
...p,
|
||||
tableSlice: p.tableSlice + 1
|
||||
tableSlice: p.tableSlice + 1,
|
||||
}));
|
||||
|
||||
await sleep(250);
|
||||
@@ -67,28 +68,28 @@ const execute = async () => {
|
||||
tasks: [
|
||||
...p.tasks,
|
||||
{
|
||||
id: '3397fecdedb13397fecdedb3',
|
||||
title: 'Create visual design',
|
||||
checked: false
|
||||
}
|
||||
]
|
||||
id: "3397fecdedb13397fecdedb3",
|
||||
title: "Create visual design",
|
||||
checked: false,
|
||||
},
|
||||
],
|
||||
}));
|
||||
|
||||
await sleep(250);
|
||||
|
||||
update((p) => ({
|
||||
...p,
|
||||
tableSlice: p.tableSlice + 1
|
||||
tableSlice: p.tableSlice + 1,
|
||||
}));
|
||||
};
|
||||
|
||||
export const databasesController = {
|
||||
execute,
|
||||
state
|
||||
state,
|
||||
};
|
||||
|
||||
export const Databases = {
|
||||
Phone,
|
||||
Box,
|
||||
Code
|
||||
Code,
|
||||
};
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<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;
|
||||
</script>
|
||||
@@ -15,7 +15,11 @@
|
||||
<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 }}>
|
||||
<div
|
||||
class="task"
|
||||
data-checked={task.checked ? "" : undefined}
|
||||
in:fly={{ x: -16 }}
|
||||
>
|
||||
<TaskCheckbox bind:checked={task.checked} />
|
||||
<span class="title">{task.title}</span>
|
||||
</div>
|
||||
@@ -53,7 +57,7 @@
|
||||
letter-spacing: -0.014rem;
|
||||
}
|
||||
|
||||
[class*='icon-'] {
|
||||
[class*="icon-"] {
|
||||
font-size: 1.25rem;
|
||||
color: hsl(var(--web-color-greyscale-500));
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<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 = `
|
||||
const userId = req.headers['user-id'];
|
||||
@@ -23,14 +23,14 @@ return res.json({ success: true });`.trim();
|
||||
|
||||
<Code {content} />
|
||||
|
||||
<div use:portal={{ target: '#code-bottom' }} class="bottom">
|
||||
{#if $state.submit !== 'idle'}
|
||||
<div use:portal={{ target: "#code-bottom" }} class="bottom">
|
||||
{#if $state.submit !== "idle"}
|
||||
<span class="web-icon-github" in:fade />
|
||||
{/if}
|
||||
{#if $state.submit === 'loading'}
|
||||
{#if $state.submit === "loading"}
|
||||
<span in:fade>Pushing to GitHub...</span>
|
||||
<div class="loader is-small" in:fade />
|
||||
{:else if $state.submit === 'success'}
|
||||
{:else if $state.submit === "success"}
|
||||
<span>Deployed to Appwrite Cloud</span>
|
||||
<span class="web-icon-check" />
|
||||
{/if}
|
||||
|
||||
@@ -1,58 +1,61 @@
|
||||
import Code from './code.svelte';
|
||||
import Phone from './phone.svelte';
|
||||
import Code from "./code.svelte";
|
||||
import Phone from "./phone.svelte";
|
||||
|
||||
import { safeAnimate, sleep } from '$lib/animations';
|
||||
import { createResettable } from '$lib/utils/resettable';
|
||||
import { getElSelector } from '../Products.svelte';
|
||||
import { safeAnimate, sleep } from "$lib/animations";
|
||||
import { createResettable } from "$lib/utils/resettable";
|
||||
import { getElSelector } from "../Products.svelte";
|
||||
|
||||
type State = {
|
||||
submit: 'idle' | 'loading' | 'success';
|
||||
submit: "idle" | "loading" | "success";
|
||||
};
|
||||
|
||||
const state = createResettable<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();
|
||||
|
||||
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
|
||||
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 safeAnimate(code, { zIndex: 0 }, { duration: 0 })?.finished;
|
||||
await safeAnimate(code, { y: [200 - 16, 200], opacity: 1 }, { duration: 0.5 })?.finished;
|
||||
await safeAnimate(code, { y: [200 - 16, 200], opacity: 1 }, { duration: 0.5 })
|
||||
?.finished;
|
||||
|
||||
await sleep(250);
|
||||
|
||||
update((p) => ({
|
||||
...p,
|
||||
submit: 'loading'
|
||||
submit: "loading",
|
||||
}));
|
||||
|
||||
await sleep(1500);
|
||||
|
||||
update((p) => ({
|
||||
...p,
|
||||
submit: 'success'
|
||||
submit: "success",
|
||||
}));
|
||||
};
|
||||
|
||||
export const functionsController = {
|
||||
execute,
|
||||
state
|
||||
state,
|
||||
};
|
||||
|
||||
export const Functions = {
|
||||
Phone,
|
||||
|
||||
Code
|
||||
Code,
|
||||
};
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<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;
|
||||
|
||||
@@ -11,22 +11,22 @@
|
||||
};
|
||||
|
||||
$: methods = [
|
||||
$state.submit === 'success' && {
|
||||
icon: '/images/animations/stripe.png',
|
||||
label: 'Stripe'
|
||||
$state.submit === "success" && {
|
||||
icon: "/images/animations/stripe.png",
|
||||
label: "Stripe",
|
||||
},
|
||||
{
|
||||
icon: '/images/animations/credit-card.svg',
|
||||
label: 'Card'
|
||||
icon: "/images/animations/credit-card.svg",
|
||||
label: "Card",
|
||||
},
|
||||
{
|
||||
icon: '/images/animations/paypal.svg',
|
||||
label: 'PayPal'
|
||||
icon: "/images/animations/paypal.svg",
|
||||
label: "PayPal",
|
||||
},
|
||||
{
|
||||
icon: '/images/animations/apple.svg',
|
||||
label: 'Apple'
|
||||
}
|
||||
icon: "/images/animations/apple.svg",
|
||||
label: "Apple",
|
||||
},
|
||||
].filter(Boolean) as Method[];
|
||||
</script>
|
||||
|
||||
@@ -54,7 +54,7 @@
|
||||
<li
|
||||
in:scale={{ delay: 150 }}
|
||||
animate:flip={{ duration: 500 }}
|
||||
data-active={i == 0 ? '' : undefined}
|
||||
data-active={i == 0 ? "" : undefined}
|
||||
>
|
||||
<img src={method.icon} alt="" />
|
||||
<p>{method.label}</p>
|
||||
@@ -62,7 +62,7 @@
|
||||
{/each}
|
||||
</ul>
|
||||
|
||||
{#if $state.submit !== 'success'}
|
||||
{#if $state.submit !== "success"}
|
||||
<div class="form">
|
||||
<p>Card information</p>
|
||||
<div class="bordered">
|
||||
@@ -81,8 +81,8 @@
|
||||
|
||||
<button>
|
||||
Pay $20.00
|
||||
{#if $state.submit === 'success'}
|
||||
<span in:slide={{ axis: 'x' }}>on Stripe</span>
|
||||
{#if $state.submit === "success"}
|
||||
<span in:slide={{ axis: "x" }}>on Stripe</span>
|
||||
{/if}
|
||||
</button>
|
||||
</div>
|
||||
@@ -117,7 +117,7 @@
|
||||
letter-spacing: -0.014rem;
|
||||
}
|
||||
|
||||
[class*='icon-'] {
|
||||
[class*="icon-"] {
|
||||
font-size: 1.25rem;
|
||||
color: hsl(var(--web-color-greyscale-500));
|
||||
}
|
||||
@@ -187,7 +187,7 @@
|
||||
position: relative;
|
||||
|
||||
&::before {
|
||||
content: '';
|
||||
content: "";
|
||||
display: block;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
@@ -196,7 +196,7 @@
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
|
||||
background-image: url('/images/animations/check-circle.svg');
|
||||
background-image: url("/images/animations/check-circle.svg");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<script lang="ts">
|
||||
import { fade, slide } from 'svelte/transition';
|
||||
import { messagingController } from '.';
|
||||
import { flip } from '$lib/utils/flip';
|
||||
import { fade, slide } from "svelte/transition";
|
||||
import { messagingController } from ".";
|
||||
import { flip } from "$lib/utils/flip";
|
||||
|
||||
const { state } = messagingController;
|
||||
</script>
|
||||
@@ -13,7 +13,11 @@
|
||||
<span class="web-eyebrow" style:text-align="center">Status</span>
|
||||
</div>
|
||||
{#each $state.messages.slice(0, $state.tableSlice) as task (task.id)}
|
||||
<div class="row" transition:slide={{ duration: 150 }} animate:flip={{ duration: 150 }}>
|
||||
<div
|
||||
class="row"
|
||||
transition:slide={{ duration: 150 }}
|
||||
animate:flip={{ duration: 150 }}
|
||||
>
|
||||
<div class="copy-button">
|
||||
<span class="web-icon-copy" />
|
||||
<span>{task.id}</span>
|
||||
@@ -26,7 +30,7 @@
|
||||
</div>
|
||||
|
||||
<div class="status-indicator">
|
||||
{#if task.status === 'sending'}
|
||||
{#if task.status === "sending"}
|
||||
<div class="loader is-small" in:fade />
|
||||
{:else}
|
||||
<span class="web-icon-check" />
|
||||
@@ -55,12 +59,12 @@
|
||||
background: rgba(255, 255, 255, 0.04);
|
||||
backdrop-filter: blur(2.6666667461395264px);
|
||||
|
||||
[class*='icon-'] {
|
||||
[class*="icon-"] {
|
||||
font-size: 1.25rem;
|
||||
color: hsl(var(--web-color-greyscale-600));
|
||||
}
|
||||
|
||||
span:not([class*='icon-']) {
|
||||
span:not([class*="icon-"]) {
|
||||
color: var(--greyscale-400, #adadb1);
|
||||
font-family: Inter;
|
||||
font-size: 0.875rem;
|
||||
@@ -90,7 +94,7 @@
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
span:not([class*='icon-']) {
|
||||
span:not([class*="icon-"]) {
|
||||
color: var(--greyscale-400, #adadb1);
|
||||
font-family: Inter;
|
||||
font-size: 0.875rem;
|
||||
@@ -108,7 +112,7 @@
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
[class*='icon-'] {
|
||||
[class*="icon-"] {
|
||||
font-size: 1.25rem;
|
||||
color: hsl(var(--web-color-greyscale-600));
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script lang="ts">
|
||||
import { messagingController } from '.';
|
||||
import Code from '$lib/animations/CodeWindow/Code.svelte';
|
||||
import { messagingController } from ".";
|
||||
import Code from "$lib/animations/CodeWindow/Code.svelte";
|
||||
|
||||
const { state } = messagingController;
|
||||
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import Box from './box.svelte';
|
||||
import Code from './code.svelte';
|
||||
import Phone from './phone.svelte';
|
||||
import Box from "./box.svelte";
|
||||
import Code from "./code.svelte";
|
||||
import Phone from "./phone.svelte";
|
||||
|
||||
import { safeAnimate, sleep, write } from '$lib/animations';
|
||||
import { createResettable } from '$lib/utils/resettable';
|
||||
import { getElSelector } from '../Products.svelte';
|
||||
import { safeAnimate, sleep, write } from "$lib/animations";
|
||||
import { createResettable } from "$lib/utils/resettable";
|
||||
import { getElSelector } from "../Products.svelte";
|
||||
|
||||
type Task = {
|
||||
id: string;
|
||||
@@ -16,7 +16,7 @@ type Message = {
|
||||
id: string;
|
||||
type: string;
|
||||
icon: string;
|
||||
status: 'sending' | 'sent';
|
||||
status: "sending" | "sent";
|
||||
};
|
||||
|
||||
type State = {
|
||||
@@ -25,47 +25,53 @@ type State = {
|
||||
tasks: Task[];
|
||||
messages: Message[];
|
||||
tableSlice: number;
|
||||
submit: 'loading' | 'success';
|
||||
submit: "loading" | "success";
|
||||
};
|
||||
|
||||
const state = createResettable<State>({
|
||||
heading: '',
|
||||
message: '',
|
||||
heading: "",
|
||||
message: "",
|
||||
tasks: [
|
||||
{
|
||||
id: '3397fecdedb13397fecdedb1',
|
||||
title: 'Research user needs',
|
||||
checked: true
|
||||
}
|
||||
id: "3397fecdedb13397fecdedb1",
|
||||
title: "Research user needs",
|
||||
checked: true,
|
||||
},
|
||||
],
|
||||
messages: [
|
||||
{
|
||||
id: '...3397fecdedb1',
|
||||
type: 'SMS',
|
||||
icon: './images/icons/illustrated/dark/sms.svg',
|
||||
status: 'sent'
|
||||
id: "...3397fecdedb1",
|
||||
type: "SMS",
|
||||
icon: "./images/icons/illustrated/dark/sms.svg",
|
||||
status: "sent",
|
||||
},
|
||||
{
|
||||
id: '...2224gabjger4',
|
||||
type: 'Email',
|
||||
icon: './images/icons/illustrated/dark/email.svg',
|
||||
status: 'sent'
|
||||
}
|
||||
id: "...2224gabjger4",
|
||||
type: "Email",
|
||||
icon: "./images/icons/illustrated/dark/email.svg",
|
||||
status: "sent",
|
||||
},
|
||||
],
|
||||
tableSlice: 2,
|
||||
submit: 'loading'
|
||||
submit: "loading",
|
||||
});
|
||||
|
||||
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();
|
||||
|
||||
await Promise.all([
|
||||
safeAnimate(phone, { x: 365, y: 0, width: '275px' }, { duration: 0.5 })?.finished,
|
||||
safeAnimate(code, { x: 80, y: 325, opacity: 0, zIndex: 100 }, { duration: 0.5 })?.finished,
|
||||
safeAnimate(box, { x: 0, y: 32, opacity: 1 }, { duration: 0.5, delay: 1 })?.finished
|
||||
safeAnimate(phone, { x: 365, y: 0, width: "275px" }, { duration: 0.5 })
|
||||
?.finished,
|
||||
safeAnimate(
|
||||
code,
|
||||
{ x: 80, y: 325, opacity: 0, zIndex: 100 },
|
||||
{ duration: 0.5 },
|
||||
)?.finished,
|
||||
safeAnimate(box, { x: 0, y: 32, opacity: 1 }, { duration: 0.5, delay: 1 })
|
||||
?.finished,
|
||||
]);
|
||||
|
||||
await sleep(250);
|
||||
@@ -75,17 +81,17 @@ const execute = async () => {
|
||||
tasks: [
|
||||
...p.tasks,
|
||||
{
|
||||
id: '3397fecdedb13397fecdedb2',
|
||||
title: 'Create wireframes',
|
||||
checked: false
|
||||
}
|
||||
]
|
||||
id: "3397fecdedb13397fecdedb2",
|
||||
title: "Create wireframes",
|
||||
checked: false,
|
||||
},
|
||||
],
|
||||
}));
|
||||
await sleep(250);
|
||||
|
||||
update((p) => ({
|
||||
...p,
|
||||
tableSlice: p.tableSlice + 1
|
||||
tableSlice: p.tableSlice + 1,
|
||||
}));
|
||||
|
||||
await sleep(250);
|
||||
@@ -95,37 +101,38 @@ const execute = async () => {
|
||||
tasks: [
|
||||
...p.tasks,
|
||||
{
|
||||
id: '3397fecdedb13397fecdedb3',
|
||||
title: 'Create visual design',
|
||||
checked: false
|
||||
}
|
||||
]
|
||||
id: "3397fecdedb13397fecdedb3",
|
||||
title: "Create visual design",
|
||||
checked: false,
|
||||
},
|
||||
],
|
||||
}));
|
||||
|
||||
await sleep(250);
|
||||
|
||||
update((p) => ({
|
||||
...p,
|
||||
tableSlice: p.tableSlice + 1
|
||||
tableSlice: p.tableSlice + 1,
|
||||
}));
|
||||
|
||||
await sleep(250);
|
||||
|
||||
safeAnimate(code, { opacity: 1 }, { duration: 0.5 })?.finished, await sleep(250);
|
||||
safeAnimate(code, { opacity: 1 }, { duration: 0.5 })?.finished,
|
||||
await sleep(250);
|
||||
await write(
|
||||
'New task assigned to you',
|
||||
"New task assigned to you",
|
||||
(v) => {
|
||||
state.update((n) => ({ ...n, heading: v }));
|
||||
},
|
||||
300
|
||||
300,
|
||||
);
|
||||
|
||||
await write(
|
||||
'You were assigned a new task in your board. Tap to check it out.',
|
||||
"You were assigned a new task in your board. Tap to check it out.",
|
||||
(v) => {
|
||||
state.update((n) => ({ ...n, message: v }));
|
||||
},
|
||||
300
|
||||
300,
|
||||
);
|
||||
|
||||
await sleep(250);
|
||||
@@ -135,30 +142,32 @@ const execute = async () => {
|
||||
messages: [
|
||||
...p.messages,
|
||||
{
|
||||
id: '...5689fdoerre2',
|
||||
type: 'Push',
|
||||
icon: './images/icons/illustrated/dark/push.svg',
|
||||
status: 'sending'
|
||||
}
|
||||
]
|
||||
id: "...5689fdoerre2",
|
||||
type: "Push",
|
||||
icon: "./images/icons/illustrated/dark/push.svg",
|
||||
status: "sending",
|
||||
},
|
||||
],
|
||||
}));
|
||||
|
||||
await sleep(1250);
|
||||
|
||||
update((p) => ({
|
||||
...p,
|
||||
submit: 'success',
|
||||
messages: p.messages.map((m) => (m.id === '...5689fdoerre2' ? { ...m, status: 'sent' } : m))
|
||||
submit: "success",
|
||||
messages: p.messages.map((m) =>
|
||||
m.id === "...5689fdoerre2" ? { ...m, status: "sent" } : m,
|
||||
),
|
||||
}));
|
||||
};
|
||||
|
||||
export const messagingController = {
|
||||
execute,
|
||||
state
|
||||
state,
|
||||
};
|
||||
|
||||
export const Messaging = {
|
||||
Phone,
|
||||
Box,
|
||||
Code
|
||||
Code,
|
||||
};
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
<script lang="ts">
|
||||
import { fly } from 'svelte/transition';
|
||||
import { messagingController } from '.';
|
||||
import TaskCheckbox from '../TaskCheckbox.svelte';
|
||||
import { fly } from "svelte/transition";
|
||||
import { messagingController } from ".";
|
||||
import TaskCheckbox from "../TaskCheckbox.svelte";
|
||||
|
||||
const { state } = messagingController;
|
||||
</script>
|
||||
|
||||
{#if $state.submit === 'success'}
|
||||
{#if $state.submit === "success"}
|
||||
<div class="push-notification" in:fly={{ y: -20 }}>
|
||||
<div class="icon" />
|
||||
<div class="content">
|
||||
@@ -14,7 +14,9 @@
|
||||
<h3 class="title">New task assigned to you</h3>
|
||||
<span class="time">now</span>
|
||||
</div>
|
||||
<p class="message">You were assigned a new task in your board. Tap to check it out.</p>
|
||||
<p class="message">
|
||||
You were assigned a new task in your board. Tap to check it out.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
@@ -28,7 +30,11 @@
|
||||
<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 }}>
|
||||
<div
|
||||
class="task"
|
||||
data-checked={task.checked ? "" : undefined}
|
||||
in:fly={{ x: -16 }}
|
||||
>
|
||||
<TaskCheckbox bind:checked={task.checked} />
|
||||
<span class="title">{task.title}</span>
|
||||
</div>
|
||||
@@ -131,7 +137,7 @@
|
||||
letter-spacing: -0.014rem;
|
||||
}
|
||||
|
||||
[class*='icon-'] {
|
||||
[class*="icon-"] {
|
||||
font-size: 1.25rem;
|
||||
color: hsl(var(--web-color-greyscale-500));
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { safeAnimate, sleep } from '$lib/animations';
|
||||
import { createResettable } from '$lib/utils/resettable';
|
||||
import { animate } from 'motion';
|
||||
import { getElSelector } from '../Products.svelte';
|
||||
import { safeAnimate, sleep } from "$lib/animations";
|
||||
import { createResettable } from "$lib/utils/resettable";
|
||||
import { animate } from "motion";
|
||||
import { getElSelector } from "../Products.svelte";
|
||||
|
||||
const requests = createResettable(0);
|
||||
const databases = createResettable(0);
|
||||
@@ -12,29 +12,41 @@ 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() }
|
||||
{ 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
|
||||
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;
|
||||
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 });
|
||||
});
|
||||
};
|
||||
@@ -48,6 +60,6 @@ export const postController = {
|
||||
storage,
|
||||
bandwidth,
|
||||
executions,
|
||||
realtime
|
||||
}
|
||||
realtime,
|
||||
},
|
||||
};
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import Phone from './phone.svelte';
|
||||
import Phone from "./phone.svelte";
|
||||
|
||||
import { safeAnimate, sleep } from '$lib/animations';
|
||||
import { createResettable } from '$lib/utils/resettable';
|
||||
import { getElSelector } from '../Products.svelte';
|
||||
import { animate } from 'motion';
|
||||
import { safeAnimate, sleep } from "$lib/animations";
|
||||
import { createResettable } from "$lib/utils/resettable";
|
||||
import { getElSelector } from "../Products.svelte";
|
||||
import { animate } from "motion";
|
||||
|
||||
type Task = {
|
||||
title: string;
|
||||
@@ -29,20 +29,23 @@ const state = createResettable<State>({
|
||||
tasks: {
|
||||
todo: [
|
||||
{
|
||||
title: 'Edit images for website',
|
||||
tags: ['design', 'content'],
|
||||
images: ['./images/animations/storage-2.png', './images/animations/storage-3.png']
|
||||
}
|
||||
title: "Edit images for website",
|
||||
tags: ["design", "content"],
|
||||
images: [
|
||||
"./images/animations/storage-2.png",
|
||||
"./images/animations/storage-3.png",
|
||||
],
|
||||
},
|
||||
],
|
||||
doing: [
|
||||
{
|
||||
title: 'Handoff meet',
|
||||
tags: ['design', 'dev']
|
||||
}
|
||||
],
|
||||
done: []
|
||||
title: "Handoff meet",
|
||||
tags: ["design", "dev"],
|
||||
},
|
||||
users: []
|
||||
],
|
||||
done: [],
|
||||
},
|
||||
users: [],
|
||||
});
|
||||
|
||||
export const connectionsProg = createResettable(0);
|
||||
@@ -50,47 +53,55 @@ export const connectionsProg = createResettable(0);
|
||||
const addUser = (update: typeof state.update, user: User) => {
|
||||
update((p) => ({
|
||||
...p,
|
||||
users: [...p.users, user]
|
||||
users: [...p.users, user],
|
||||
}));
|
||||
};
|
||||
|
||||
const addTask = (update: typeof state.update, group: keyof State['tasks'], task: Task) => {
|
||||
const addTask = (
|
||||
update: typeof state.update,
|
||||
group: keyof State["tasks"],
|
||||
task: Task,
|
||||
) => {
|
||||
update((p) => ({
|
||||
...p,
|
||||
tasks: {
|
||||
...p.tasks,
|
||||
[group]: [task, ...p.tasks[group]]
|
||||
}
|
||||
[group]: [task, ...p.tasks[group]],
|
||||
},
|
||||
}));
|
||||
};
|
||||
|
||||
const execute = async () => {
|
||||
const phone = getElSelector('phone');
|
||||
const code = getElSelector('code');
|
||||
const box = getElSelector('box');
|
||||
const phone = getElSelector("phone");
|
||||
const code = getElSelector("code");
|
||||
const box = getElSelector("box");
|
||||
|
||||
const walter = getElSelector('user-Walter');
|
||||
const aditya = getElSelector('user-Aditya');
|
||||
const sara = getElSelector('user-Sara');
|
||||
const walter = getElSelector("user-Walter");
|
||||
const aditya = getElSelector("user-Aditya");
|
||||
const sara = getElSelector("user-Sara");
|
||||
|
||||
const addTodo = getElSelector('add-todo');
|
||||
const addDoing = getElSelector('add-doing');
|
||||
const addDone = getElSelector('add-done');
|
||||
const addTodo = getElSelector("add-todo");
|
||||
const addDoing = getElSelector("add-doing");
|
||||
const addDone = getElSelector("add-done");
|
||||
|
||||
const graphBox = getElSelector('graph-box');
|
||||
const graphBox = getElSelector("graph-box");
|
||||
|
||||
const pd = getElSelector('pd');
|
||||
const pd = getElSelector("pd");
|
||||
|
||||
const { update } = state.reset();
|
||||
const { set: setConn } = connectionsProg.reset();
|
||||
|
||||
await Promise.all([
|
||||
safeAnimate(box, { opacity: 0 }, { duration: 0.5 })?.finished,
|
||||
safeAnimate(phone, { x: 0, y: 0, width: '660px' }, { duration: 0.5 })?.finished,
|
||||
safeAnimate(code, { opacity: 0 }, { duration: 0.5 })?.finished,
|
||||
safeAnimate(graphBox, { opacity: 0, x: 0, y: 0, visibility: 'visible' }, { duration: 0 })
|
||||
safeAnimate(phone, { x: 0, y: 0, width: "660px" }, { duration: 0.5 })
|
||||
?.finished,
|
||||
safeAnimate(pd, { opacity: 1, y: 0 }, { duration: 0.5 })?.finished
|
||||
safeAnimate(code, { opacity: 0 }, { duration: 0.5 })?.finished,
|
||||
safeAnimate(
|
||||
graphBox,
|
||||
{ opacity: 0, x: 0, y: 0, visibility: "visible" },
|
||||
{ duration: 0 },
|
||||
)?.finished,
|
||||
safeAnimate(pd, { opacity: 1, y: 0 }, { duration: 0.5 })?.finished,
|
||||
]);
|
||||
|
||||
// Graphbox
|
||||
@@ -101,138 +112,175 @@ const execute = async () => {
|
||||
(y) => {
|
||||
setConn(y);
|
||||
},
|
||||
{ duration: 2.5, easing: 'ease-in' }
|
||||
{ duration: 2.5, easing: "ease-in" },
|
||||
);
|
||||
});
|
||||
|
||||
// Walter
|
||||
sleep(500).then(async () => {
|
||||
addUser(update, { name: 'Walter', color: '#fd366e' });
|
||||
addUser(update, { name: "Walter", color: "#fd366e" });
|
||||
await sleep(500);
|
||||
await safeAnimate(walter, { x: -200, y: -100, scale: 1 }, { duration: 0.5 })?.finished;
|
||||
await safeAnimate(walter, { x: -200, y: -100, scale: 1 }, { duration: 0.5 })
|
||||
?.finished;
|
||||
await Promise.all([
|
||||
safeAnimate(walter, { scale: [1, 0.9, 1] }, { duration: 0.25 })?.finished,
|
||||
safeAnimate(addTodo, { scale: [1, 0.9, 1] }, { duration: 0.25 })?.finished
|
||||
safeAnimate(addTodo, { scale: [1, 0.9, 1] }, { duration: 0.25 })
|
||||
?.finished,
|
||||
]);
|
||||
|
||||
addTask(update, 'todo', {
|
||||
title: 'Handoff meet',
|
||||
tags: ['design', 'dev']
|
||||
addTask(update, "todo", {
|
||||
title: "Handoff meet",
|
||||
tags: ["design", "dev"],
|
||||
});
|
||||
|
||||
await safeAnimate(walter, { scale: 1, x: -180, y: -160 }, { duration: 0.75, delay: 0.5 })
|
||||
await safeAnimate(
|
||||
walter,
|
||||
{ scale: 1, x: -180, y: -160 },
|
||||
{ duration: 0.75, delay: 0.5 },
|
||||
)?.finished;
|
||||
|
||||
await sleep(500);
|
||||
|
||||
await safeAnimate(walter, { x: 210, y: -100, scale: 1 }, { duration: 0.5 })
|
||||
?.finished;
|
||||
|
||||
await sleep(500);
|
||||
|
||||
await safeAnimate(walter, { x: 210, y: -100, scale: 1 }, { duration: 0.5 })?.finished;
|
||||
|
||||
await Promise.all([
|
||||
safeAnimate(walter, { scale: [1, 0.9, 1] }, { duration: 0.25 })?.finished,
|
||||
safeAnimate(addDone, { scale: [1, 0.9, 1] }, { duration: 0.25 })?.finished
|
||||
safeAnimate(addDone, { scale: [1, 0.9, 1] }, { duration: 0.25 })
|
||||
?.finished,
|
||||
]);
|
||||
|
||||
addTask(update, 'done', {
|
||||
title: 'Create migrations script',
|
||||
tags: ['Dev']
|
||||
addTask(update, "done", {
|
||||
title: "Create migrations script",
|
||||
tags: ["Dev"],
|
||||
});
|
||||
|
||||
safeAnimate(walter, { scale: 1, x: 230, y: -20 }, { duration: 0.75, delay: 0.5 });
|
||||
safeAnimate(
|
||||
walter,
|
||||
{ scale: 1, x: 230, y: -20 },
|
||||
{ duration: 0.75, delay: 0.5 },
|
||||
);
|
||||
|
||||
await sleep(750);
|
||||
|
||||
await safeAnimate(walter, { x: -10, y: -100, scale: 1 }, { duration: 0.5 })?.finished;
|
||||
await safeAnimate(walter, { x: -10, y: -100, scale: 1 }, { duration: 0.5 })
|
||||
?.finished;
|
||||
|
||||
await Promise.all([
|
||||
safeAnimate(walter, { scale: [1, 0.9, 1] }, { duration: 0.25 })?.finished,
|
||||
safeAnimate(addDoing, { scale: [1, 0.9, 1] }, { duration: 0.25 })?.finished
|
||||
safeAnimate(addDoing, { scale: [1, 0.9, 1] }, { duration: 0.25 })
|
||||
?.finished,
|
||||
]);
|
||||
|
||||
addTask(update, 'doing', {
|
||||
title: 'Configure blog SEO',
|
||||
tags: ['dev', 'content']
|
||||
addTask(update, "doing", {
|
||||
title: "Configure blog SEO",
|
||||
tags: ["dev", "content"],
|
||||
});
|
||||
|
||||
await safeAnimate(walter, { scale: 1, x: -70, y: 80 }, { duration: 0.75, delay: 0.25 });
|
||||
await safeAnimate(
|
||||
walter,
|
||||
{ scale: 1, x: -70, y: 80 },
|
||||
{ duration: 0.75, delay: 0.25 },
|
||||
);
|
||||
});
|
||||
|
||||
// Aditya
|
||||
sleep(1500).then(async () => {
|
||||
addUser(update, { name: 'Aditya', color: 'rgba(124, 103, 254, 1)' });
|
||||
addUser(update, { name: "Aditya", color: "rgba(124, 103, 254, 1)" });
|
||||
await sleep(500);
|
||||
await safeAnimate(aditya, { x: 200, y: -100, scale: 1 }, { duration: 0.5 })?.finished;
|
||||
await safeAnimate(aditya, { x: 200, y: -100, scale: 1 }, { duration: 0.5 })
|
||||
?.finished;
|
||||
await Promise.all([
|
||||
safeAnimate(aditya, { scale: [1, 0.9, 1] }, { duration: 0.25 })?.finished,
|
||||
safeAnimate(addDone, { scale: [1, 0.9, 1] }, { duration: 0.25 })?.finished
|
||||
safeAnimate(addDone, { scale: [1, 0.9, 1] }, { duration: 0.25 })
|
||||
?.finished,
|
||||
]);
|
||||
|
||||
addTask(update, 'done', {
|
||||
title: 'Write up briefing',
|
||||
tags: ['dev-rel']
|
||||
addTask(update, "done", {
|
||||
title: "Write up briefing",
|
||||
tags: ["dev-rel"],
|
||||
});
|
||||
|
||||
await safeAnimate(aditya, { scale: 1, x: 180, y: 60 }, { duration: 0.75, delay: 0.5 })
|
||||
?.finished;
|
||||
await safeAnimate(
|
||||
aditya,
|
||||
{ scale: 1, x: 180, y: 60 },
|
||||
{ duration: 0.75, delay: 0.5 },
|
||||
)?.finished;
|
||||
|
||||
await sleep(750);
|
||||
|
||||
await safeAnimate(aditya, { x: -210, y: -100, scale: 1 }, { duration: 0.5 })?.finished;
|
||||
await safeAnimate(aditya, { x: -210, y: -100, scale: 1 }, { duration: 0.5 })
|
||||
?.finished;
|
||||
|
||||
await Promise.all([
|
||||
safeAnimate(aditya, { scale: [1, 0.9, 1] }, { duration: 0.25 })?.finished,
|
||||
safeAnimate(addTodo, { scale: [1, 0.9, 1] }, { duration: 0.25 })?.finished
|
||||
safeAnimate(addTodo, { scale: [1, 0.9, 1] }, { duration: 0.25 })
|
||||
?.finished,
|
||||
]);
|
||||
|
||||
addTask(update, 'todo', {
|
||||
title: 'Review branding blog post',
|
||||
tags: ['dev-rel']
|
||||
addTask(update, "todo", {
|
||||
title: "Review branding blog post",
|
||||
tags: ["dev-rel"],
|
||||
});
|
||||
|
||||
await safeAnimate(aditya, { scale: 1, x: 70, y: -220 }, { duration: 0.75, delay: 0.5 })
|
||||
?.finished;
|
||||
await safeAnimate(
|
||||
aditya,
|
||||
{ scale: 1, x: 70, y: -220 },
|
||||
{ duration: 0.75, delay: 0.5 },
|
||||
)?.finished;
|
||||
});
|
||||
|
||||
// Sara
|
||||
sleep(2500).then(async () => {
|
||||
addUser(update, { name: 'Sara', color: 'rgba(103, 163, 254, 1)' });
|
||||
addUser(update, { name: "Sara", color: "rgba(103, 163, 254, 1)" });
|
||||
await sleep(500);
|
||||
await safeAnimate(sara, { x: 0, y: -100, scale: 1 }, { duration: 0.5 })?.finished;
|
||||
await safeAnimate(sara, { x: 0, y: -100, scale: 1 }, { duration: 0.5 })
|
||||
?.finished;
|
||||
await Promise.all([
|
||||
safeAnimate(sara, { scale: [1, 0.9, 1] }, { duration: 0.25 })?.finished,
|
||||
safeAnimate(addDoing, { scale: [1, 0.9, 1] }, { duration: 0.25 })?.finished
|
||||
safeAnimate(addDoing, { scale: [1, 0.9, 1] }, { duration: 0.25 })
|
||||
?.finished,
|
||||
]);
|
||||
|
||||
addTask(update, 'doing', {
|
||||
title: 'Prepare design system presentation',
|
||||
tags: ['design']
|
||||
addTask(update, "doing", {
|
||||
title: "Prepare design system presentation",
|
||||
tags: ["design"],
|
||||
});
|
||||
|
||||
await safeAnimate(sara, { scale: 1, y: 60, x: -50 }, { duration: 0.75, delay: 0.5 })
|
||||
?.finished;
|
||||
await safeAnimate(
|
||||
sara,
|
||||
{ scale: 1, y: 60, x: -50 },
|
||||
{ duration: 0.75, delay: 0.5 },
|
||||
)?.finished;
|
||||
await sleep(250);
|
||||
|
||||
await safeAnimate(sara, { x: 200, y: -100, scale: 1 }, { duration: 0.5 })?.finished;
|
||||
await safeAnimate(sara, { x: 200, y: -100, scale: 1 }, { duration: 0.5 })
|
||||
?.finished;
|
||||
|
||||
await Promise.all([
|
||||
safeAnimate(sara, { scale: [1, 0.9, 1] }, { duration: 0.25 })?.finished,
|
||||
safeAnimate(addDone, { scale: [1, 0.9, 1] }, { duration: 0.25 })?.finished
|
||||
safeAnimate(addDone, { scale: [1, 0.9, 1] }, { duration: 0.25 })
|
||||
?.finished,
|
||||
]);
|
||||
|
||||
addTask(update, 'done', {
|
||||
title: 'QA branding animations',
|
||||
tags: ['Dev']
|
||||
addTask(update, "done", {
|
||||
title: "QA branding animations",
|
||||
tags: ["Dev"],
|
||||
});
|
||||
|
||||
await safeAnimate(sara, { scale: 1, x: 180, y: 60 }, { duration: 0.75, delay: 0.5 })
|
||||
?.finished;
|
||||
await safeAnimate(
|
||||
sara,
|
||||
{ scale: 1, x: 180, y: 60 },
|
||||
{ duration: 0.75, delay: 0.5 },
|
||||
)?.finished;
|
||||
});
|
||||
};
|
||||
|
||||
export const realtimeController = {
|
||||
execute,
|
||||
state
|
||||
state,
|
||||
};
|
||||
|
||||
export const Realtime = {
|
||||
Phone
|
||||
Phone,
|
||||
};
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
<script lang="ts">
|
||||
import { objectKeys } from '$lib/utils/object';
|
||||
import { scale } from 'svelte/transition';
|
||||
import { connectionsProg, realtimeController } from '.';
|
||||
import { elId } from '../Products.svelte';
|
||||
import { flip } from '$lib/utils/flip';
|
||||
import { toScale } from '$lib/utils/toScale';
|
||||
import { objectKeys } from "$lib/utils/object";
|
||||
import { scale } from "svelte/transition";
|
||||
import { connectionsProg, realtimeController } from ".";
|
||||
import { elId } from "../Products.svelte";
|
||||
import { flip } from "$lib/utils/flip";
|
||||
import { toScale } from "$lib/utils/toScale";
|
||||
|
||||
const { state } = realtimeController;
|
||||
|
||||
@@ -118,8 +118,18 @@
|
||||
</div>
|
||||
|
||||
{#each $state.users as user}
|
||||
<div class="user" style:--color={user.color} id="user-{user.name}-{$elId}" in:scale>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 18 18">
|
||||
<div
|
||||
class="user"
|
||||
style:--color={user.color}
|
||||
id="user-{user.name}-{$elId}"
|
||||
in:scale
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="18"
|
||||
height="18"
|
||||
viewBox="0 0 18 18"
|
||||
>
|
||||
<path
|
||||
d="M2.58814 0.558469C1.60242 0.224627 1.10955 0.0577053 0.782928 0.173472C0.498743 0.274197 0.275173 0.497766 0.174449 0.781951C0.0586818 1.10858 0.225603 1.60144 0.559445 2.58716L4.67494 14.7388C5.13698 16.1031 5.368 16.7852 5.71194 16.9722C6.00951 17.134 6.36873 17.1341 6.66644 16.9726C7.01055 16.7859 7.24216 16.104 7.70539 14.7402L9.23555 10.235C9.32861 9.96103 9.37513 9.82404 9.45345 9.7101C9.52283 9.60918 9.61015 9.52185 9.71108 9.45248C9.82502 9.37416 9.96201 9.32763 10.236 9.23457L14.7411 7.70441C16.105 7.24118 16.7869 7.00957 16.9736 6.66547C17.1351 6.36776 17.1349 6.00853 16.9732 5.71096C16.7862 5.36702 16.1041 5.136 14.7398 4.67396L2.58814 0.558469Z"
|
||||
/>
|
||||
@@ -203,7 +213,14 @@
|
||||
{@const y = 124 - line}
|
||||
{#if line > 3}
|
||||
<circle cx={x} cy={y} r="3" fill="#FD366E" />
|
||||
<line x1={x} y1={y} x2={x} y2="124" stroke="#FD366E" stroke-width="6" />
|
||||
<line
|
||||
x1={x}
|
||||
y1={y}
|
||||
x2={x}
|
||||
y2="124"
|
||||
stroke="#FD366E"
|
||||
stroke-width="6"
|
||||
/>
|
||||
{/if}
|
||||
{/each}
|
||||
</g>
|
||||
@@ -309,7 +326,7 @@
|
||||
</div>
|
||||
|
||||
<style lang="scss">
|
||||
@use '$scss/abstract/mixins/border-gradient' as gradients;
|
||||
@use "$scss/abstract/mixins/border-gradient" as gradients;
|
||||
|
||||
// Utilities
|
||||
.flow {
|
||||
@@ -420,7 +437,7 @@
|
||||
line-height: 1.08563rem; /* 142.857% */
|
||||
}
|
||||
|
||||
[class*='icon'] {
|
||||
[class*="icon"] {
|
||||
font-size: 1rem;
|
||||
}
|
||||
}
|
||||
@@ -517,7 +534,7 @@
|
||||
border-radius: 0.5rem;
|
||||
border: 1.869px solid var(--greyscale-50, #ededf0);
|
||||
|
||||
[class*='icon'] {
|
||||
[class*="icon"] {
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
@@ -590,7 +607,7 @@
|
||||
line-height: 0.875rem; /* 140% */
|
||||
}
|
||||
|
||||
[class*='icon'] {
|
||||
[class*="icon"] {
|
||||
font-size: 1rem;
|
||||
margin-inline-start: auto;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<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;
|
||||
</script>
|
||||
@@ -13,7 +13,11 @@
|
||||
<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="row"
|
||||
in:slide={{ duration: 150 }}
|
||||
animate:flip={{ duration: 150 }}
|
||||
>
|
||||
<div class="img-wrapper">
|
||||
<img src={file.src} alt="" />
|
||||
<span>{file.filename}</span>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script lang="ts">
|
||||
import Code from '$lib/animations/CodeWindow/Code.svelte';
|
||||
import Code from "$lib/animations/CodeWindow/Code.svelte";
|
||||
|
||||
let content = `
|
||||
const result = storage.createFile(
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import Box from './box.svelte';
|
||||
import Code from './code.svelte';
|
||||
import Phone from './phone.svelte';
|
||||
import Box from "./box.svelte";
|
||||
import Code from "./code.svelte";
|
||||
import Phone from "./phone.svelte";
|
||||
|
||||
import { safeAnimate, sleep } from '$lib/animations';
|
||||
import { createResettable } from '$lib/utils/resettable';
|
||||
import { getElSelector } from '../Products.svelte';
|
||||
import { safeAnimate, sleep } from "$lib/animations";
|
||||
import { createResettable } from "$lib/utils/resettable";
|
||||
import { getElSelector } from "../Products.svelte";
|
||||
|
||||
type File = {
|
||||
src: string;
|
||||
@@ -18,20 +18,20 @@ type State = {
|
||||
};
|
||||
|
||||
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();
|
||||
|
||||
@@ -39,7 +39,7 @@ const execute = async () => {
|
||||
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
|
||||
safeAnimate(uploadLoading, { opacity: 0 }, { duration: 0 })?.finished,
|
||||
]);
|
||||
|
||||
await safeAnimate(code, { zIndex: 20 }, { duration: 0 })?.finished;
|
||||
@@ -49,30 +49,34 @@ const execute = async () => {
|
||||
files: [
|
||||
...p.files,
|
||||
{
|
||||
src: '/images/animations/storage-1.png',
|
||||
filename: 'Profile.png',
|
||||
type: 'image/png',
|
||||
size: '362.6 KB'
|
||||
}
|
||||
]
|
||||
src: "/images/animations/storage-1.png",
|
||||
filename: "Profile.png",
|
||||
type: "image/png",
|
||||
size: "362.6 KB",
|
||||
},
|
||||
],
|
||||
}));
|
||||
|
||||
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
|
||||
safeAnimate(drawer, { y: [128, 0], opacity: 1 }, { duration: 0.5 })
|
||||
?.finished,
|
||||
]);
|
||||
|
||||
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 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
|
||||
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);
|
||||
@@ -80,9 +84,13 @@ const execute = async () => {
|
||||
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 })
|
||||
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,
|
||||
safeAnimate(box, { y: [300 - 16, 300], opacity: 1 }, { duration: 1 })?.finished
|
||||
]);
|
||||
|
||||
await sleep(250);
|
||||
@@ -90,7 +98,8 @@ const execute = async () => {
|
||||
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
|
||||
safeAnimate(uploadImg, { opacity: 0, y: 64 + 8 }, { duration: 0.5 })
|
||||
?.finished,
|
||||
]);
|
||||
await sleep(250);
|
||||
|
||||
@@ -101,12 +110,12 @@ const execute = async () => {
|
||||
files: [
|
||||
...p.files,
|
||||
{
|
||||
src: '/images/animations/storage-2.png',
|
||||
filename: 'Vector.svg',
|
||||
type: 'vector/svg',
|
||||
size: '1.5 KB'
|
||||
}
|
||||
]
|
||||
src: "/images/animations/storage-2.png",
|
||||
filename: "Vector.svg",
|
||||
type: "vector/svg",
|
||||
size: "1.5 KB",
|
||||
},
|
||||
],
|
||||
}));
|
||||
|
||||
await sleep(250);
|
||||
@@ -116,22 +125,22 @@ const execute = async () => {
|
||||
files: [
|
||||
...p.files,
|
||||
{
|
||||
src: '/images/animations/storage-3.png',
|
||||
filename: 'img2.webp',
|
||||
type: 'image/webp',
|
||||
size: '3.2 MB'
|
||||
}
|
||||
]
|
||||
src: "/images/animations/storage-3.png",
|
||||
filename: "img2.webp",
|
||||
type: "image/webp",
|
||||
size: "3.2 MB",
|
||||
},
|
||||
],
|
||||
}));
|
||||
};
|
||||
|
||||
export const storageController = {
|
||||
execute,
|
||||
state
|
||||
state,
|
||||
};
|
||||
|
||||
export const Storage = {
|
||||
Phone,
|
||||
Box,
|
||||
Code
|
||||
Code,
|
||||
};
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
<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;
|
||||
@@ -20,7 +20,11 @@
|
||||
<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 }}>
|
||||
<div
|
||||
class="task"
|
||||
data-checked={task.checked ? "" : undefined}
|
||||
in:fly={{ x: -16 }}
|
||||
>
|
||||
<TaskCheckbox bind:checked={task.checked} />
|
||||
<span class="title">{task.title}</span>
|
||||
</div>
|
||||
@@ -83,7 +87,7 @@
|
||||
letter-spacing: -0.014rem;
|
||||
}
|
||||
|
||||
[class*='icon-'] {
|
||||
[class*="icon-"] {
|
||||
font-size: 1.25rem;
|
||||
color: hsl(var(--web-color-greyscale-500));
|
||||
}
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
import type { Action } from 'svelte/action';
|
||||
import type { Action } from "svelte/action";
|
||||
import {
|
||||
animate as motionAnimate,
|
||||
type ElementOrSelector,
|
||||
type MotionKeyframesDefinition,
|
||||
type AnimationOptionsWithOverrides,
|
||||
animate
|
||||
} from 'motion';
|
||||
animate,
|
||||
} from "motion";
|
||||
|
||||
export function animation(
|
||||
elementOrSelector: ElementOrSelector,
|
||||
keyframes: MotionKeyframesDefinition,
|
||||
options?: AnimationOptionsWithOverrides
|
||||
options?: AnimationOptionsWithOverrides,
|
||||
) {
|
||||
const play = () => {
|
||||
const played = motionAnimate(elementOrSelector, keyframes, options);
|
||||
@@ -20,16 +20,23 @@ export function animation(
|
||||
const reverse = () => {
|
||||
const reversedKeyframes = Object.fromEntries(
|
||||
Object.entries(keyframes).map(([key, keyframe]) => {
|
||||
return [key, Array.isArray(keyframe) ? [...keyframe].reverse() : keyframe];
|
||||
})
|
||||
return [
|
||||
key,
|
||||
Array.isArray(keyframe) ? [...keyframe].reverse() : keyframe,
|
||||
];
|
||||
}),
|
||||
) as typeof keyframes;
|
||||
const reversed = motionAnimate(elementOrSelector, reversedKeyframes, options);
|
||||
const reversed = motionAnimate(
|
||||
elementOrSelector,
|
||||
reversedKeyframes,
|
||||
options,
|
||||
);
|
||||
return reversed;
|
||||
};
|
||||
|
||||
return {
|
||||
play,
|
||||
reverse
|
||||
reverse,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -38,7 +45,7 @@ export type Animation = ReturnType<typeof animation>;
|
||||
export const safeAnimate = (
|
||||
elementOrSelector: ElementOrSelector,
|
||||
keyframes: MotionKeyframesDefinition,
|
||||
options?: AnimationOptionsWithOverrides
|
||||
options?: AnimationOptionsWithOverrides,
|
||||
) => {
|
||||
try {
|
||||
return animate(elementOrSelector, keyframes, options);
|
||||
@@ -49,7 +56,7 @@ export const safeAnimate = (
|
||||
|
||||
type Unsubscriber = () => void;
|
||||
|
||||
type PreviousScroll = 'before' | 'after' | undefined;
|
||||
type PreviousScroll = "before" | "after" | undefined;
|
||||
|
||||
type ScrollCallbackState = {
|
||||
previous?: PreviousScroll;
|
||||
@@ -59,28 +66,33 @@ type ScrollCallbackState = {
|
||||
|
||||
export type ScrollCallback = {
|
||||
percentage: number;
|
||||
whenAfter?: (args: Omit<ScrollCallbackState, 'unsubscribe'>) => Unsubscriber | void;
|
||||
whenAfter?: (
|
||||
args: Omit<ScrollCallbackState, "unsubscribe">,
|
||||
) => Unsubscriber | void;
|
||||
};
|
||||
|
||||
export function createScrollHandler(callbacks: ScrollCallback[]) {
|
||||
const states: ScrollCallbackState[] = callbacks.map(() => ({ executedCount: 0 }));
|
||||
const states: ScrollCallbackState[] = callbacks.map(() => ({
|
||||
executedCount: 0,
|
||||
}));
|
||||
|
||||
const handler = function (scrollPercentage: number) {
|
||||
callbacks.forEach((callback, i) => {
|
||||
const { percentage, whenAfter } = callback;
|
||||
const { previous, unsubscribe, executedCount } = states[i];
|
||||
|
||||
if (scrollPercentage >= percentage && previous !== 'after') {
|
||||
if (scrollPercentage >= percentage && previous !== "after") {
|
||||
// Execute whenAfter
|
||||
states[i].unsubscribe = whenAfter?.({ previous, executedCount }) ?? undefined;
|
||||
states[i].previous = 'after';
|
||||
states[i].unsubscribe =
|
||||
whenAfter?.({ previous, executedCount }) ?? undefined;
|
||||
states[i].previous = "after";
|
||||
if (whenAfter) {
|
||||
states[i].executedCount++;
|
||||
}
|
||||
} else if (scrollPercentage < percentage && previous === 'after') {
|
||||
} else if (scrollPercentage < percentage && previous === "after") {
|
||||
unsubscribe?.();
|
||||
states[i].unsubscribe = undefined;
|
||||
states[i].previous = 'before';
|
||||
states[i].previous = "before";
|
||||
}
|
||||
});
|
||||
};
|
||||
@@ -107,8 +119,8 @@ export const scroll: Action<
|
||||
HTMLElement,
|
||||
undefined,
|
||||
{
|
||||
'on:web-scroll': (e: CustomEvent<ScrollInfo>) => void;
|
||||
'on:web-resize': (e: CustomEvent<ScrollInfo>) => void;
|
||||
"on:web-scroll": (e: CustomEvent<ScrollInfo>) => void;
|
||||
"on:web-resize": (e: CustomEvent<ScrollInfo>) => void;
|
||||
}
|
||||
> = (node) => {
|
||||
function getScrollInfo(): ScrollInfo {
|
||||
@@ -124,34 +136,34 @@ export const scroll: Action<
|
||||
return {
|
||||
percentage: scrollPercentage,
|
||||
traversed,
|
||||
remaning
|
||||
remaning,
|
||||
};
|
||||
}
|
||||
|
||||
const createHandler = (eventName: 'web-scroll' | 'web-resize') => {
|
||||
const createHandler = (eventName: "web-scroll" | "web-resize") => {
|
||||
return () => {
|
||||
node.dispatchEvent(
|
||||
new CustomEvent<ScrollInfo>(eventName, {
|
||||
detail: getScrollInfo()
|
||||
})
|
||||
detail: getScrollInfo(),
|
||||
}),
|
||||
);
|
||||
};
|
||||
};
|
||||
|
||||
const handleScroll = createHandler('web-scroll');
|
||||
const handleResize = createHandler('web-resize');
|
||||
const handleScroll = createHandler("web-scroll");
|
||||
const handleResize = createHandler("web-resize");
|
||||
|
||||
handleScroll();
|
||||
handleResize();
|
||||
|
||||
window.addEventListener('scroll', handleScroll);
|
||||
window.addEventListener('resize', handleResize);
|
||||
window.addEventListener("scroll", handleScroll);
|
||||
window.addEventListener("resize", handleResize);
|
||||
|
||||
return {
|
||||
destroy() {
|
||||
window.removeEventListener('scroll', handleScroll);
|
||||
window.removeEventListener('resize', handleResize);
|
||||
}
|
||||
window.removeEventListener("scroll", handleScroll);
|
||||
window.removeEventListener("resize", handleResize);
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
@@ -197,7 +209,9 @@ export function createProgressSequence(events: ProgressEvent[]) {
|
||||
let lastEventIdx = -1;
|
||||
|
||||
const handler = (percentage: number) => {
|
||||
const idx = sortedEvents.findIndex((event) => event.percentage <= percentage);
|
||||
const idx = sortedEvents.findIndex(
|
||||
(event) => event.percentage <= percentage,
|
||||
);
|
||||
if (idx === lastEventIdx) {
|
||||
return;
|
||||
}
|
||||
@@ -237,8 +251,8 @@ export function sleep(duration: number) {
|
||||
|
||||
export function getInitials(name: string) {
|
||||
return name
|
||||
.split(' ')
|
||||
.map((word) => word?.[0]?.toUpperCase() ?? '')
|
||||
.join('')
|
||||
.split(" ")
|
||||
.map((word) => word?.[0]?.toUpperCase() ?? "")
|
||||
.join("")
|
||||
.slice(0, 2);
|
||||
}
|
||||
|
||||
@@ -1,9 +1,14 @@
|
||||
import { PUBLIC_APPWRITE_ENDPOINT, PUBLIC_APPWRITE_PROJECT_ID } from '$env/static/public';
|
||||
import { Client, Databases, Functions } from '@appwrite.io/console';
|
||||
import {
|
||||
PUBLIC_APPWRITE_ENDPOINT,
|
||||
PUBLIC_APPWRITE_PROJECT_ID,
|
||||
} from "$env/static/public";
|
||||
import { Client, Databases, Functions } from "@appwrite.io/console";
|
||||
|
||||
export const client = new Client();
|
||||
|
||||
client.setEndpoint(PUBLIC_APPWRITE_ENDPOINT).setProject(PUBLIC_APPWRITE_PROJECT_ID);
|
||||
client
|
||||
.setEndpoint(PUBLIC_APPWRITE_ENDPOINT)
|
||||
.setProject(PUBLIC_APPWRITE_PROJECT_ID);
|
||||
|
||||
export const databases = new Databases(client);
|
||||
export const functions = new Functions(client);
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
import { APPWRITE_API_KEY_INIT } from '$env/static/private';
|
||||
import { PUBLIC_APPWRITE_ENDPOINT, PUBLIC_APPWRITE_PROJECT_INIT_ID } from '$env/static/public';
|
||||
import { Account, Client, Databases } from '@appwrite.io/console';
|
||||
import { APPWRITE_API_KEY_INIT } from "$env/static/private";
|
||||
import {
|
||||
PUBLIC_APPWRITE_ENDPOINT,
|
||||
PUBLIC_APPWRITE_PROJECT_INIT_ID,
|
||||
} from "$env/static/public";
|
||||
import { Account, Client, Databases } from "@appwrite.io/console";
|
||||
|
||||
const clientServer = new Client();
|
||||
clientServer
|
||||
@@ -10,5 +13,5 @@ clientServer
|
||||
|
||||
export const appwriteInitServer = {
|
||||
account: new Account(clientServer),
|
||||
databases: new Databases(clientServer)
|
||||
databases: new Databases(clientServer),
|
||||
};
|
||||
|
||||
@@ -1,10 +1,15 @@
|
||||
import { PUBLIC_APPWRITE_ENDPOINT, PUBLIC_APPWRITE_PROJECT_INIT_ID } from '$env/static/public';
|
||||
import { Client, Account } from '@appwrite.io/console';
|
||||
import {
|
||||
PUBLIC_APPWRITE_ENDPOINT,
|
||||
PUBLIC_APPWRITE_PROJECT_INIT_ID,
|
||||
} from "$env/static/public";
|
||||
import { Client, Account } from "@appwrite.io/console";
|
||||
|
||||
const client = new Client();
|
||||
client.setEndpoint(PUBLIC_APPWRITE_ENDPOINT).setProject(PUBLIC_APPWRITE_PROJECT_INIT_ID);
|
||||
client
|
||||
.setEndpoint(PUBLIC_APPWRITE_ENDPOINT)
|
||||
.setProject(PUBLIC_APPWRITE_PROJECT_INIT_ID);
|
||||
|
||||
export const appwriteInit = {
|
||||
client,
|
||||
account: new Account(client)
|
||||
account: new Account(client),
|
||||
};
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import Root from './Root.svelte';
|
||||
import Item from './Item.svelte';
|
||||
import Root from "./Root.svelte";
|
||||
import Item from "./Item.svelte";
|
||||
|
||||
export { Root as Accordion, Item as AccordionItem };
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
<script lang="ts">
|
||||
import { browser } from '$app/environment';
|
||||
import { BANNER_KEY } from '$lib/constants';
|
||||
import { browser } from "$app/environment";
|
||||
import { BANNER_KEY } from "$lib/constants";
|
||||
|
||||
const hideTopBanner = () => {
|
||||
document.body.dataset.bannerHidden = '';
|
||||
localStorage.setItem(BANNER_KEY, 'true');
|
||||
document.body.dataset.bannerHidden = "";
|
||||
localStorage.setItem(BANNER_KEY, "true");
|
||||
};
|
||||
</script>
|
||||
|
||||
|
||||
@@ -1,21 +1,21 @@
|
||||
<script lang="ts">
|
||||
import { DropdownCtx } from './DropdownMenu.svelte';
|
||||
import { DropdownCtx } from "./DropdownMenu.svelte";
|
||||
|
||||
export let checked = false;
|
||||
|
||||
const {
|
||||
builders: { createCheckboxItem }
|
||||
builders: { createCheckboxItem },
|
||||
} = DropdownCtx.get();
|
||||
|
||||
const {
|
||||
elements: { checkboxItem },
|
||||
states: { checked: localChecked }
|
||||
states: { checked: localChecked },
|
||||
} = createCheckboxItem({
|
||||
defaultChecked: checked,
|
||||
onCheckedChange({ next }) {
|
||||
checked = !!next;
|
||||
return next;
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
$: localChecked.set(checked);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script lang="ts" context="module">
|
||||
const ctxKey = Symbol('dropdown');
|
||||
const ctxKey = Symbol("dropdown");
|
||||
|
||||
export const DropdownCtx = {
|
||||
get() {
|
||||
@@ -7,26 +7,26 @@
|
||||
},
|
||||
set(ctx: DropdownMenu) {
|
||||
setContext(ctxKey, ctx);
|
||||
}
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<script lang="ts">
|
||||
import { createDropdownMenu, type DropdownMenu } from '@melt-ui/svelte';
|
||||
import { getContext, setContext } from 'svelte';
|
||||
import { createDropdownMenu, type DropdownMenu } from "@melt-ui/svelte";
|
||||
import { getContext, setContext } from "svelte";
|
||||
|
||||
const dropdown = createDropdownMenu({
|
||||
forceVisible: true,
|
||||
positioning: {
|
||||
placement: 'bottom-start'
|
||||
}
|
||||
placement: "bottom-start",
|
||||
},
|
||||
});
|
||||
|
||||
DropdownCtx.set(dropdown);
|
||||
|
||||
const {
|
||||
elements: { menu, trigger },
|
||||
states: { open }
|
||||
states: { open },
|
||||
} = dropdown;
|
||||
</script>
|
||||
|
||||
|
||||
@@ -1,18 +1,22 @@
|
||||
<script lang="ts">
|
||||
export let src: string;
|
||||
export let alt = '';
|
||||
export let alt = "";
|
||||
export let size: number;
|
||||
|
||||
let className = '';
|
||||
let className = "";
|
||||
export { className as class };
|
||||
</script>
|
||||
|
||||
<div class="head-wrapper {className}" style:width="{size}px" style:height="{size}px">
|
||||
<div
|
||||
class="head-wrapper {className}"
|
||||
style:width="{size}px"
|
||||
style:height="{size}px"
|
||||
>
|
||||
<img {src} {alt} />
|
||||
</div>
|
||||
|
||||
<style lang="scss">
|
||||
@use '$scss/abstract/mixins/border-gradient' as gradients;
|
||||
@use "$scss/abstract/mixins/border-gradient" as gradients;
|
||||
|
||||
.head-wrapper {
|
||||
@include gradients.border-gradient;
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
<script lang="ts">
|
||||
import { clamp } from '$lib/utils/clamp';
|
||||
import FloatingHead from './FloatingHead.svelte';
|
||||
import { clamp } from "$lib/utils/clamp";
|
||||
import FloatingHead from "./FloatingHead.svelte";
|
||||
|
||||
type Head = {
|
||||
src: string;
|
||||
display: [number, number, number];
|
||||
};
|
||||
|
||||
const headPositions: Array<Head['display']> = [
|
||||
const headPositions: Array<Head["display"]> = [
|
||||
[120, -25, 40],
|
||||
[120, 20, -40],
|
||||
[64, -40, 20],
|
||||
@@ -17,13 +17,13 @@
|
||||
[64, 40, -20],
|
||||
[64, 10, -55],
|
||||
[40, -45, 50],
|
||||
[40, -40, -40]
|
||||
[40, -40, -40],
|
||||
];
|
||||
|
||||
export let images: Array<string>;
|
||||
</script>
|
||||
|
||||
<div class="absolute web-u-hide-mobile root">
|
||||
<div class="web-u-hide-mobile root absolute">
|
||||
{#each headPositions as [size, top, left], i}
|
||||
{@const image = clamp(0, images.length - 1, i % images.length)}
|
||||
<FloatingHead
|
||||
|
||||
@@ -1,64 +1,66 @@
|
||||
<script lang="ts">
|
||||
import { createAccordion, melt } from '@melt-ui/svelte';
|
||||
import { slide } from 'svelte/transition';
|
||||
import { createAccordion, melt } from "@melt-ui/svelte";
|
||||
import { slide } from "svelte/transition";
|
||||
|
||||
export let noBorder = false;
|
||||
|
||||
const {
|
||||
elements: { content, heading, item, root, trigger },
|
||||
helpers: { isSelected }
|
||||
helpers: { isSelected },
|
||||
} = createAccordion({
|
||||
multiple: true,
|
||||
forceVisible: true
|
||||
forceVisible: true,
|
||||
});
|
||||
|
||||
const links: Record<string, { label: string; href: string; target?: string; rel?: string }[]> =
|
||||
{
|
||||
'Quick starts': [
|
||||
{ label: 'Web', href: '/docs/quick-starts/web' },
|
||||
{ label: 'Next.js', href: '/docs/quick-starts/nextjs' },
|
||||
{ label: 'React', href: '/docs/quick-starts/react' },
|
||||
{ label: 'Vue.js', href: '/docs/quick-starts/vue' },
|
||||
{ label: 'Nuxt', href: '/docs/quick-starts/nuxt' },
|
||||
{ label: 'SvelteKit', href: '/docs/quick-starts/sveltekit' },
|
||||
{ label: 'Refine', href: '/docs/quick-starts/refine' },
|
||||
{ label: 'Angular', href: '/docs/quick-starts/angular' },
|
||||
{ label: 'React Native', href: '/docs/quick-starts/react-native' },
|
||||
{ label: 'Flutter', href: '/docs/quick-starts/flutter' },
|
||||
{ label: 'Apple', href: '/docs/quick-starts/apple' },
|
||||
{ label: 'Android', href: '/docs/quick-starts/android' },
|
||||
{ label: 'Qwik', href: '/docs/quick-starts/qwik' },
|
||||
{ label: 'Astro', href: '/docs/quick-starts/astro' },
|
||||
{ label: 'Solid', href: '/docs/quick-starts/solid' }
|
||||
const links: Record<
|
||||
string,
|
||||
{ label: string; href: string; target?: string; rel?: string }[]
|
||||
> = {
|
||||
"Quick starts": [
|
||||
{ label: "Web", href: "/docs/quick-starts/web" },
|
||||
{ label: "Next.js", href: "/docs/quick-starts/nextjs" },
|
||||
{ label: "React", href: "/docs/quick-starts/react" },
|
||||
{ label: "Vue.js", href: "/docs/quick-starts/vue" },
|
||||
{ label: "Nuxt", href: "/docs/quick-starts/nuxt" },
|
||||
{ label: "SvelteKit", href: "/docs/quick-starts/sveltekit" },
|
||||
{ label: "Refine", href: "/docs/quick-starts/refine" },
|
||||
{ label: "Angular", href: "/docs/quick-starts/angular" },
|
||||
{ label: "React Native", href: "/docs/quick-starts/react-native" },
|
||||
{ label: "Flutter", href: "/docs/quick-starts/flutter" },
|
||||
{ label: "Apple", href: "/docs/quick-starts/apple" },
|
||||
{ label: "Android", href: "/docs/quick-starts/android" },
|
||||
{ label: "Qwik", href: "/docs/quick-starts/qwik" },
|
||||
{ label: "Astro", href: "/docs/quick-starts/astro" },
|
||||
{ label: "Solid", href: "/docs/quick-starts/solid" },
|
||||
],
|
||||
Products: [
|
||||
{ label: 'Auth', href: '/docs/products/auth' },
|
||||
{ label: 'Databases', href: '/docs/products/databases' },
|
||||
{ label: 'Functions', href: '/docs/products/functions' },
|
||||
{ label: 'Messaging', href: '/products/messaging' },
|
||||
{ label: 'Storage', href: '/docs/products/storage' },
|
||||
{ label: 'Realtime', href: '/docs/apis/realtime' }
|
||||
{ label: "Auth", href: "/docs/products/auth" },
|
||||
{ label: "Databases", href: "/docs/products/databases" },
|
||||
{ label: "Functions", href: "/docs/products/functions" },
|
||||
{ label: "Messaging", href: "/products/messaging" },
|
||||
{ label: "Storage", href: "/docs/products/storage" },
|
||||
{ label: "Realtime", href: "/docs/apis/realtime" },
|
||||
],
|
||||
Learn: [
|
||||
{ label: 'Docs', href: '/docs' },
|
||||
{ label: 'Integrations', href: '/integrations' },
|
||||
{ label: 'Community', href: '/community' },
|
||||
{ label: 'Init', href: '/init' },
|
||||
{ label: 'Threads', href: '/threads' },
|
||||
{ label: 'Blog', href: '/blog' },
|
||||
{ label: 'Changelog', href: '/changelog' },
|
||||
{ label: "Docs", href: "/docs" },
|
||||
{ label: "Integrations", href: "/integrations" },
|
||||
{ label: "Community", href: "/community" },
|
||||
{ label: "Init", href: "/init" },
|
||||
{ label: "Threads", href: "/threads" },
|
||||
{ label: "Blog", href: "/blog" },
|
||||
{ label: "Changelog", href: "/changelog" },
|
||||
{
|
||||
label: 'Roadmap',
|
||||
href: 'https://github.com/orgs/appwrite/projects',
|
||||
target: '_blank',
|
||||
rel: 'noopener noreferrer'
|
||||
label: "Roadmap",
|
||||
href: "https://github.com/orgs/appwrite/projects",
|
||||
target: "_blank",
|
||||
rel: "noopener noreferrer",
|
||||
},
|
||||
{
|
||||
label: 'Source code',
|
||||
href: 'https://github.com/appwrite',
|
||||
target: '_blank',
|
||||
rel: 'noopener noreferrer'
|
||||
}
|
||||
label: "Source code",
|
||||
href: "https://github.com/appwrite",
|
||||
target: "_blank",
|
||||
rel: "noopener noreferrer",
|
||||
},
|
||||
// {
|
||||
// label: 'Status',
|
||||
// href: 'https://appwrite.online',
|
||||
@@ -67,27 +69,27 @@
|
||||
// }
|
||||
],
|
||||
Programs: [
|
||||
{ label: 'Heroes', href: '/heroes' },
|
||||
{ label: 'Startups', href: '/startups' }
|
||||
{ label: "Heroes", href: "/heroes" },
|
||||
{ label: "Startups", href: "/startups" },
|
||||
],
|
||||
About: [
|
||||
{ label: 'Company', href: '/company' },
|
||||
{ label: 'Pricing', href: '/pricing' },
|
||||
{ label: "Company", href: "/company" },
|
||||
{ label: "Pricing", href: "/pricing" },
|
||||
{
|
||||
label: 'Careers',
|
||||
href: 'https://appwrite.careers',
|
||||
target: '_blank',
|
||||
rel: 'noopener noreferrer'
|
||||
label: "Careers",
|
||||
href: "https://appwrite.careers",
|
||||
target: "_blank",
|
||||
rel: "noopener noreferrer",
|
||||
},
|
||||
{
|
||||
label: 'Store',
|
||||
href: 'https://appwrite.store',
|
||||
target: '_blank',
|
||||
rel: 'noopener noreferrer'
|
||||
label: "Store",
|
||||
href: "https://appwrite.store",
|
||||
target: "_blank",
|
||||
rel: "noopener noreferrer",
|
||||
},
|
||||
{ label: 'Contact us', href: '/contact-us' },
|
||||
{ label: 'Assets', href: '/assets' }
|
||||
]
|
||||
{ label: "Contact us", href: "/contact-us" },
|
||||
{ label: "Assets", href: "/assets" },
|
||||
],
|
||||
};
|
||||
</script>
|
||||
|
||||
@@ -96,11 +98,19 @@
|
||||
class="web-footer-nav relative mt-24"
|
||||
class:web-u-sep-block-start={!noBorder}
|
||||
>
|
||||
<img class="web-logo" src="/images/logos/appwrite.svg" alt="appwrite" height="24" width="130" />
|
||||
<img
|
||||
class="web-logo"
|
||||
src="/images/logos/appwrite.svg"
|
||||
alt="appwrite"
|
||||
height="24"
|
||||
width="130"
|
||||
/>
|
||||
<ul class="web-footer-nav-main-list" use:melt={$root}>
|
||||
{#each Object.entries(links) as [title, items]}
|
||||
<li class="web-footer-nav-main-item web-is-not-mobile">
|
||||
<h2 class="web-footer-nav-main-title web-is-not-mobile web-caption-500 web-eyebrow">
|
||||
<h2
|
||||
class="web-footer-nav-main-title web-is-not-mobile web-caption-500 web-eyebrow"
|
||||
>
|
||||
{title}
|
||||
</h2>
|
||||
<ul class="web-footer-nav-secondary-list web-sub-body-400">
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script lang="ts">
|
||||
import { page } from '$app/stores';
|
||||
import { onMount } from 'svelte';
|
||||
import { page } from "$app/stores";
|
||||
import { onMount } from "svelte";
|
||||
|
||||
let mounted = false;
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
const randomDelay = () => Math.floor(Math.random() * 750);
|
||||
</script>
|
||||
|
||||
<div class="banner" class:hidden={$page.url.pathname.includes('init')}>
|
||||
<div class="banner" class:hidden={$page.url.pathname.includes("init")}>
|
||||
<div class="content web-u-color-text-primary">
|
||||
<div class="headings">
|
||||
<span style:font-weight="500"
|
||||
@@ -235,7 +235,7 @@
|
||||
}
|
||||
|
||||
&::after {
|
||||
content: '';
|
||||
content: "";
|
||||
display: block;
|
||||
position: absolute;
|
||||
transform-origin: left;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script lang="ts">
|
||||
import { buildOpenGraphImage } from '$lib/utils/metadata';
|
||||
import { buildOpenGraphImage } from "$lib/utils/metadata";
|
||||
|
||||
export let title: string;
|
||||
export let description: string;
|
||||
|
||||
@@ -1,63 +1,63 @@
|
||||
<script lang="ts">
|
||||
import Tooltip from '$lib/components/Tooltip.svelte';
|
||||
import { themeInUse } from '$routes/+layout.svelte';
|
||||
import Tooltip from "$lib/components/Tooltip.svelte";
|
||||
import { themeInUse } from "$routes/+layout.svelte";
|
||||
|
||||
$: platforms = [
|
||||
{
|
||||
name: 'Flutter',
|
||||
href: '/docs/quick-starts/flutter',
|
||||
image: `/images/platforms/${$themeInUse}/flutter.svg`
|
||||
name: "Flutter",
|
||||
href: "/docs/quick-starts/flutter",
|
||||
image: `/images/platforms/${$themeInUse}/flutter.svg`,
|
||||
},
|
||||
{
|
||||
name: 'Next',
|
||||
href: '/docs/quick-starts/nextjs',
|
||||
image: `/images/platforms/${$themeInUse}/nextjs.svg`
|
||||
name: "Next",
|
||||
href: "/docs/quick-starts/nextjs",
|
||||
image: `/images/platforms/${$themeInUse}/nextjs.svg`,
|
||||
},
|
||||
{
|
||||
name: 'React',
|
||||
href: '/docs/quick-starts/react',
|
||||
image: `/images/platforms/${$themeInUse}/react.svg`
|
||||
name: "React",
|
||||
href: "/docs/quick-starts/react",
|
||||
image: `/images/platforms/${$themeInUse}/react.svg`,
|
||||
},
|
||||
{
|
||||
name: 'Svelte',
|
||||
href: '/docs/quick-starts/sveltekit',
|
||||
image: `/images/platforms/${$themeInUse}/svelte.svg`
|
||||
name: "Svelte",
|
||||
href: "/docs/quick-starts/sveltekit",
|
||||
image: `/images/platforms/${$themeInUse}/svelte.svg`,
|
||||
},
|
||||
{
|
||||
name: 'Nuxt',
|
||||
href: '/docs/quick-starts/nuxt',
|
||||
image: `/images/platforms/${$themeInUse}/nuxt.svg`
|
||||
name: "Nuxt",
|
||||
href: "/docs/quick-starts/nuxt",
|
||||
image: `/images/platforms/${$themeInUse}/nuxt.svg`,
|
||||
},
|
||||
{
|
||||
name: 'Vue',
|
||||
href: '/docs/quick-starts/vue',
|
||||
image: `/images/platforms/${$themeInUse}/vue.svg`
|
||||
name: "Vue",
|
||||
href: "/docs/quick-starts/vue",
|
||||
image: `/images/platforms/${$themeInUse}/vue.svg`,
|
||||
},
|
||||
{
|
||||
name: 'Angular',
|
||||
href: '/docs/quick-starts/angular',
|
||||
image: `/images/platforms/${$themeInUse}/angular.svg`
|
||||
name: "Angular",
|
||||
href: "/docs/quick-starts/angular",
|
||||
image: `/images/platforms/${$themeInUse}/angular.svg`,
|
||||
},
|
||||
{
|
||||
name: 'Refine',
|
||||
href: '/docs/quick-starts/refine',
|
||||
image: `/images/platforms/${$themeInUse}/refine.svg`
|
||||
name: "Refine",
|
||||
href: "/docs/quick-starts/refine",
|
||||
image: `/images/platforms/${$themeInUse}/refine.svg`,
|
||||
},
|
||||
{
|
||||
name: 'Apple',
|
||||
href: '/docs/quick-starts/apple',
|
||||
image: `/images/platforms/${$themeInUse}/apple.svg`
|
||||
name: "Apple",
|
||||
href: "/docs/quick-starts/apple",
|
||||
image: `/images/platforms/${$themeInUse}/apple.svg`,
|
||||
},
|
||||
{
|
||||
name: 'Android',
|
||||
href: '/docs/quick-starts/android',
|
||||
image: `/images/platforms/${$themeInUse}/android.svg`
|
||||
name: "Android",
|
||||
href: "/docs/quick-starts/android",
|
||||
image: `/images/platforms/${$themeInUse}/android.svg`,
|
||||
},
|
||||
{
|
||||
name: 'React Native',
|
||||
href: '/docs/quick-starts/react-native',
|
||||
image: `/images/platforms/${$themeInUse}/react-native.svg`
|
||||
}
|
||||
name: "React Native",
|
||||
href: "/docs/quick-starts/react-native",
|
||||
image: `/images/platforms/${$themeInUse}/react-native.svg`,
|
||||
},
|
||||
] as Array<{
|
||||
name: string;
|
||||
href: string;
|
||||
@@ -65,11 +65,16 @@
|
||||
}>;
|
||||
</script>
|
||||
|
||||
<ul class="flex flex-wrap gap-4 web-u-margin-block-32-mobile web-u-margin-block-40-not-mobile">
|
||||
<ul
|
||||
class="web-u-margin-block-32-mobile web-u-margin-block-40-not-mobile flex flex-wrap gap-4"
|
||||
>
|
||||
{#each platforms as platform}
|
||||
<Tooltip>
|
||||
<li>
|
||||
<a href={platform.href} class="web-icon-button web-box-icon has-border-gradient">
|
||||
<a
|
||||
href={platform.href}
|
||||
class="web-icon-button web-box-icon has-border-gradient"
|
||||
>
|
||||
<img
|
||||
src={platform.image}
|
||||
alt="{platform.name} quick start"
|
||||
|
||||
@@ -1,24 +1,24 @@
|
||||
<script lang="ts">
|
||||
import { type Theme, currentTheme } from '$routes/+layout.svelte';
|
||||
import { type Theme, currentTheme } from "$routes/+layout.svelte";
|
||||
|
||||
import Select, { type SelectOption } from './Select.svelte';
|
||||
import Select, { type SelectOption } from "./Select.svelte";
|
||||
|
||||
const options: SelectOption<Theme>[] = [
|
||||
{
|
||||
value: 'dark',
|
||||
label: 'Dark',
|
||||
icon: 'web-icon-dark'
|
||||
value: "dark",
|
||||
label: "Dark",
|
||||
icon: "web-icon-dark",
|
||||
},
|
||||
{
|
||||
value: 'light',
|
||||
label: 'Light',
|
||||
icon: 'web-icon-light'
|
||||
value: "light",
|
||||
label: "Light",
|
||||
icon: "web-icon-light",
|
||||
},
|
||||
{
|
||||
value: 'system',
|
||||
label: 'System',
|
||||
icon: 'web-icon-system'
|
||||
}
|
||||
value: "system",
|
||||
label: "System",
|
||||
icon: "web-icon-system",
|
||||
},
|
||||
];
|
||||
</script>
|
||||
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
<script lang="ts">
|
||||
import { getTocCtx } from './TocRoot.svelte';
|
||||
import TocTree from './TocTree.svelte';
|
||||
import { getTocCtx } from "./TocRoot.svelte";
|
||||
import TocTree from "./TocTree.svelte";
|
||||
|
||||
export let showToc = true;
|
||||
|
||||
const {
|
||||
toc: {
|
||||
elements: { item },
|
||||
states: { activeHeadingIdxs, headingsTree }
|
||||
}
|
||||
states: { activeHeadingIdxs, headingsTree },
|
||||
},
|
||||
} = getTocCtx();
|
||||
|
||||
$: progress = Math.max(...$activeHeadingIdxs) / ($headingsTree.length - 1);
|
||||
@@ -100,6 +100,10 @@
|
||||
</svg>
|
||||
</span>
|
||||
</div>
|
||||
<TocTree tree={$headingsTree} activeHeadingIdxs={$activeHeadingIdxs} {item} />
|
||||
<TocTree
|
||||
tree={$headingsTree}
|
||||
activeHeadingIdxs={$activeHeadingIdxs}
|
||||
{item}
|
||||
/>
|
||||
</div>
|
||||
</aside>
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
import {
|
||||
createTableOfContents,
|
||||
type CreateTableOfContentsArgs,
|
||||
type TableOfContents
|
||||
} from '@melt-ui/svelte';
|
||||
import { getContext, setContext } from 'svelte';
|
||||
type TableOfContents,
|
||||
} from "@melt-ui/svelte";
|
||||
import { getContext, setContext } from "svelte";
|
||||
|
||||
const TOC_KEY = Symbol();
|
||||
export type TocContext = {
|
||||
@@ -21,16 +21,22 @@
|
||||
</script>
|
||||
|
||||
<script lang="ts">
|
||||
export let selector = '#main';
|
||||
export let exclude: CreateTableOfContentsArgs['exclude'] = ['h1', 'h3', 'h4', 'h5', 'h6'];
|
||||
export let activeType: CreateTableOfContentsArgs['activeType'] = 'highest';
|
||||
export let scrollOffset: CreateTableOfContentsArgs['scrollOffset'] = 0;
|
||||
export let selector = "#main";
|
||||
export let exclude: CreateTableOfContentsArgs["exclude"] = [
|
||||
"h1",
|
||||
"h3",
|
||||
"h4",
|
||||
"h5",
|
||||
"h6",
|
||||
];
|
||||
export let activeType: CreateTableOfContentsArgs["activeType"] = "highest";
|
||||
export let scrollOffset: CreateTableOfContentsArgs["scrollOffset"] = 0;
|
||||
|
||||
const toc = createTableOfContents({
|
||||
selector,
|
||||
exclude,
|
||||
activeType,
|
||||
scrollOffset
|
||||
scrollOffset,
|
||||
});
|
||||
|
||||
setCtx({ toc });
|
||||
|
||||
@@ -1,16 +1,20 @@
|
||||
<script lang="ts">
|
||||
import { type TableOfContentsItem, type TableOfContentsElements, melt } from '@melt-ui/svelte';
|
||||
import { getTocCtx } from './TocRoot.svelte';
|
||||
import {
|
||||
type TableOfContentsItem,
|
||||
type TableOfContentsElements,
|
||||
melt,
|
||||
} from "@melt-ui/svelte";
|
||||
import { getTocCtx } from "./TocRoot.svelte";
|
||||
|
||||
export let tree: TableOfContentsItem[] = [];
|
||||
export let activeHeadingIdxs: number[];
|
||||
export let item: TableOfContentsElements['item'];
|
||||
export let item: TableOfContentsElements["item"];
|
||||
export let level = 1;
|
||||
|
||||
const {
|
||||
toc: {
|
||||
helpers: { isActive }
|
||||
}
|
||||
helpers: { isActive },
|
||||
},
|
||||
} = getTocCtx();
|
||||
</script>
|
||||
|
||||
|
||||
@@ -1,51 +1,51 @@
|
||||
<script lang="ts">
|
||||
import { createTooltip, melt } from '@melt-ui/svelte';
|
||||
import type { FloatingConfig } from '@melt-ui/svelte/internal/actions';
|
||||
import { fly, type FlyParams } from 'svelte/transition';
|
||||
import { createTooltip, melt } from "@melt-ui/svelte";
|
||||
import type { FloatingConfig } from "@melt-ui/svelte/internal/actions";
|
||||
import { fly, type FlyParams } from "svelte/transition";
|
||||
|
||||
export let placement: NonNullable<FloatingConfig>['placement'] = 'top';
|
||||
export let placement: NonNullable<FloatingConfig>["placement"] = "top";
|
||||
export let disabled = false;
|
||||
export let closeOnPointerDown = false;
|
||||
export let disableHoverableContent = false;
|
||||
|
||||
const {
|
||||
elements: { trigger, content, arrow },
|
||||
states: { open }
|
||||
states: { open },
|
||||
} = createTooltip({
|
||||
positioning: {
|
||||
placement
|
||||
placement,
|
||||
},
|
||||
openDelay: 0,
|
||||
closeOnPointerDown,
|
||||
forceVisible: true,
|
||||
disableHoverableContent
|
||||
disableHoverableContent,
|
||||
});
|
||||
|
||||
$: flyParams = (function getFlyParams() {
|
||||
const params: FlyParams = {
|
||||
duration: 150
|
||||
duration: 150,
|
||||
};
|
||||
|
||||
switch (placement) {
|
||||
case 'top':
|
||||
case 'top-start':
|
||||
case 'top-end':
|
||||
case "top":
|
||||
case "top-start":
|
||||
case "top-end":
|
||||
params.y = 4;
|
||||
break;
|
||||
case 'bottom':
|
||||
case 'bottom-start':
|
||||
case 'bottom-end':
|
||||
case "bottom":
|
||||
case "bottom-start":
|
||||
case "bottom-end":
|
||||
params.y = -4;
|
||||
break;
|
||||
|
||||
case 'left':
|
||||
case 'left-start':
|
||||
case 'left-end':
|
||||
case "left":
|
||||
case "left-start":
|
||||
case "left-end":
|
||||
params.x = 4;
|
||||
break;
|
||||
case 'right':
|
||||
case 'right-start':
|
||||
case 'right-end':
|
||||
case "right":
|
||||
case "right-start":
|
||||
case "right-end":
|
||||
params.x = -4;
|
||||
break;
|
||||
}
|
||||
@@ -63,7 +63,11 @@
|
||||
{/if}
|
||||
|
||||
{#if $open && !disabled}
|
||||
<div use:melt={$content} class="web-tooltip web-sub-body-400" transition:fly={flyParams}>
|
||||
<div
|
||||
use:melt={$content}
|
||||
class="web-tooltip web-sub-body-400"
|
||||
transition:fly={flyParams}
|
||||
>
|
||||
<div use:melt={$arrow} />
|
||||
<slot name="tooltip" />
|
||||
</div>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
</li>
|
||||
|
||||
<style lang="scss">
|
||||
@use '$scss/abstract' as *;
|
||||
@use "$scss/abstract" as *;
|
||||
|
||||
.slide {
|
||||
cursor: grab;
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
export { default as Root } from './Carousel.svelte';
|
||||
export { default as Slide } from './CarouselSlide.svelte';
|
||||
export { default as Root } from "./Carousel.svelte";
|
||||
export { default as Slide } from "./CarouselSlide.svelte";
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
export const GITHUB_STARS = '42.8K';
|
||||
export const BANNER_KEY: Banners = 'discord-banner-01'; // Change key to force banner to show again
|
||||
export const GITHUB_STARS = "42.8K";
|
||||
export const BANNER_KEY: Banners = "discord-banner-01"; // Change key to force banner to show again
|
||||
export const SENTRY_DSN =
|
||||
'https://27d41dc8bb67b596f137924ab8599e59@o1063647.ingest.us.sentry.io/4507497727000576';
|
||||
"https://27d41dc8bb67b596f137924ab8599e59@o1063647.ingest.us.sentry.io/4507497727000576";
|
||||
|
||||
/**
|
||||
* History:
|
||||
@@ -9,8 +9,7 @@ export const SENTRY_DSN =
|
||||
* init-banner-02
|
||||
* pricing-banner-01
|
||||
*/
|
||||
type Banners = 'discord-banner-01' | 'init-banner-02' | 'pricing-banner-01'
|
||||
|
||||
type Banners = "discord-banner-01" | "init-banner-02" | "pricing-banner-01";
|
||||
|
||||
export type Social = {
|
||||
icon: string;
|
||||
@@ -22,60 +21,60 @@ export type SocialShareOption = {
|
||||
icon: string;
|
||||
label: string;
|
||||
link: string;
|
||||
type: 'link' | 'copy';
|
||||
type: "link" | "copy";
|
||||
};
|
||||
|
||||
export const socialSharingOptions: Array<SocialShareOption> = [
|
||||
{
|
||||
icon: 'web-icon-x',
|
||||
label: 'Twitter',
|
||||
link: 'https://x.com/intent/post?text={TITLE}\n&url={URL}',
|
||||
type: 'link'
|
||||
icon: "web-icon-x",
|
||||
label: "Twitter",
|
||||
link: "https://x.com/intent/post?text={TITLE}\n&url={URL}",
|
||||
type: "link",
|
||||
},
|
||||
{
|
||||
icon: 'web-icon-linkedin',
|
||||
label: 'LinkedIn',
|
||||
link: 'https://www.linkedin.com/sharing/share-offsite?text={TITLE}\n&url={URL}',
|
||||
type: 'link'
|
||||
icon: "web-icon-linkedin",
|
||||
label: "LinkedIn",
|
||||
link: "https://www.linkedin.com/sharing/share-offsite?text={TITLE}\n&url={URL}",
|
||||
type: "link",
|
||||
},
|
||||
{
|
||||
icon: 'web-icon-ycombinator',
|
||||
label: 'YCombinator',
|
||||
link: 'https://news.ycombinator.com/submitlink?t={TITLE}\n&u={URL}',
|
||||
type: 'link'
|
||||
icon: "web-icon-ycombinator",
|
||||
label: "YCombinator",
|
||||
link: "https://news.ycombinator.com/submitlink?t={TITLE}\n&u={URL}",
|
||||
type: "link",
|
||||
},
|
||||
{
|
||||
icon: 'web-icon-copy',
|
||||
label: 'Copy',
|
||||
link: '',
|
||||
type: 'copy'
|
||||
}
|
||||
]
|
||||
icon: "web-icon-copy",
|
||||
label: "Copy",
|
||||
link: "",
|
||||
type: "copy",
|
||||
},
|
||||
];
|
||||
|
||||
export const socials: Array<Social> = [
|
||||
{
|
||||
icon: 'web-icon-discord',
|
||||
label: 'Discord',
|
||||
link: 'https://appwrite.io/discord'
|
||||
icon: "web-icon-discord",
|
||||
label: "Discord",
|
||||
link: "https://appwrite.io/discord",
|
||||
},
|
||||
{
|
||||
icon: 'web-icon-github',
|
||||
label: 'Github',
|
||||
link: 'https://github.com/appwrite'
|
||||
icon: "web-icon-github",
|
||||
label: "Github",
|
||||
link: "https://github.com/appwrite",
|
||||
},
|
||||
{
|
||||
icon: 'web-icon-x',
|
||||
label: 'Twitter',
|
||||
link: 'https://twitter.com/intent/follow?screen_name=appwrite'
|
||||
icon: "web-icon-x",
|
||||
label: "Twitter",
|
||||
link: "https://twitter.com/intent/follow?screen_name=appwrite",
|
||||
},
|
||||
{
|
||||
icon: 'web-icon-linkedin',
|
||||
label: 'LinkedIn',
|
||||
link: 'https://www.linkedin.com/company/appwrite'
|
||||
icon: "web-icon-linkedin",
|
||||
label: "LinkedIn",
|
||||
link: "https://www.linkedin.com/company/appwrite",
|
||||
},
|
||||
{
|
||||
icon: 'web-icon-youtube',
|
||||
label: 'YouTube',
|
||||
link: 'https://www.youtube.com/c/appwrite?sub_confirmation=1'
|
||||
}
|
||||
icon: "web-icon-youtube",
|
||||
label: "YouTube",
|
||||
link: "https://www.youtube.com/c/appwrite?sub_confirmation=1",
|
||||
},
|
||||
];
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,5 @@
|
||||
<script lang="ts" generics="T">
|
||||
import Fuse, { type IFuseOptions, type FuseResult } from 'fuse.js';
|
||||
import Fuse, { type IFuseOptions, type FuseResult } from "fuse.js";
|
||||
|
||||
export let list: ReadonlyArray<T>;
|
||||
export let options: IFuseOptions<T>;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { FuseResult } from 'fuse.js';
|
||||
import type { FuseResult } from "fuse.js";
|
||||
|
||||
// Reexport your entry components here
|
||||
export { default as Fuse } from './Fuse.svelte';
|
||||
export { default as Fuse } from "./Fuse.svelte";
|
||||
|
||||
export type ResultType<T> = FuseResult<T>[];
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
export { default as Main } from './Main.svelte';
|
||||
export { default as Docs } from './Docs.svelte';
|
||||
export { default as DocsArticle } from './DocsArticle.svelte';
|
||||
export { default as DocsTutorial } from './DocsTutorial.svelte';
|
||||
export { default as Main } from "./Main.svelte";
|
||||
export { default as Docs } from "./Docs.svelte";
|
||||
export { default as DocsArticle } from "./DocsArticle.svelte";
|
||||
export { default as DocsTutorial } from "./DocsTutorial.svelte";
|
||||
|
||||
@@ -18,20 +18,20 @@ interface ChainFn {
|
||||
<A, B, C>(
|
||||
fn1: (args: Args<undefined>) => A,
|
||||
fn2: (args: Args<A>) => B,
|
||||
fn3: (args: Args<B>) => C
|
||||
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
|
||||
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
|
||||
fn5: (args: Args<D>) => E,
|
||||
): Chain;
|
||||
<A, B, C, D, E, F>(
|
||||
fn1: (args: Args<undefined>) => A,
|
||||
@@ -39,7 +39,7 @@ interface ChainFn {
|
||||
fn3: (args: Args<B>) => C,
|
||||
fn4: (args: Args<C>) => D,
|
||||
fn5: (args: Args<D>) => E,
|
||||
fn6: (args: Args<E>) => F
|
||||
fn6: (args: Args<E>) => F,
|
||||
): Chain;
|
||||
<A, B, C, D, E, F, G>(
|
||||
fn1: (args: Args<undefined>) => A,
|
||||
@@ -48,7 +48,7 @@ interface ChainFn {
|
||||
fn4: (args: Args<C>) => D,
|
||||
fn5: (args: Args<D>) => E,
|
||||
fn6: (args: Args<E>) => F,
|
||||
fn7: (args: Args<F>) => G
|
||||
fn7: (args: Args<F>) => G,
|
||||
): Chain;
|
||||
<A, B, C, D, E, F, G, H>(
|
||||
fn1: (args: Args<undefined>) => A,
|
||||
@@ -58,7 +58,7 @@ interface ChainFn {
|
||||
fn5: (args: Args<D>) => E,
|
||||
fn6: (args: Args<E>) => F,
|
||||
fn7: (args: Args<F>) => G,
|
||||
fn8: (args: Args<G>) => H
|
||||
fn8: (args: Args<G>) => H,
|
||||
): Chain;
|
||||
<A, B, C, D, E, F, G, H, I>(
|
||||
fn1: (args: Args<undefined>) => A,
|
||||
@@ -69,7 +69,7 @@ interface ChainFn {
|
||||
fn6: (args: Args<E>) => F,
|
||||
fn7: (args: Args<F>) => G,
|
||||
fn8: (args: Args<G>) => H,
|
||||
fn9: (args: Args<H>) => I
|
||||
fn9: (args: Args<H>) => I,
|
||||
): Chain;
|
||||
<A, B, C, D, E, F, G, H, I, J>(
|
||||
fn1: (args: Args<undefined>) => A,
|
||||
@@ -81,7 +81,7 @@ interface ChainFn {
|
||||
fn7: (args: Args<F>) => G,
|
||||
fn8: (args: Args<G>) => H,
|
||||
fn9: (args: Args<H>) => I,
|
||||
fn10: (args: Args<I>) => J
|
||||
fn10: (args: Args<I>) => J,
|
||||
): Chain;
|
||||
<A, B, C, D, E, F, G, H, I, J, K>(
|
||||
fn1: (args: Args<undefined>) => A,
|
||||
@@ -94,7 +94,7 @@ interface ChainFn {
|
||||
fn8: (args: Args<G>) => H,
|
||||
fn9: (args: Args<H>) => I,
|
||||
fn10: (args: Args<I>) => J,
|
||||
fn11: (args: Args<J>) => K
|
||||
fn11: (args: Args<J>) => K,
|
||||
): Chain;
|
||||
<A, B, C, D, E, F, G, H, I, J, K, L>(
|
||||
fn1: (args: Args<undefined>) => A,
|
||||
@@ -108,7 +108,7 @@ interface ChainFn {
|
||||
fn9: (args: Args<H>) => I,
|
||||
fn10: (args: Args<I>) => J,
|
||||
fn11: (args: Args<J>) => K,
|
||||
fn12: (args: Args<K>) => L
|
||||
fn12: (args: Args<K>) => L,
|
||||
): Chain;
|
||||
// So on...
|
||||
}
|
||||
|
||||
@@ -1,24 +1,24 @@
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import { describe, it, expect } from "vitest";
|
||||
|
||||
import { clamp } from './clamp';
|
||||
import type { TestCases } from './test';
|
||||
import { clamp } from "./clamp";
|
||||
import type { TestCases } from "./test";
|
||||
|
||||
const testCases: TestCases<typeof clamp> = [
|
||||
{
|
||||
args: [0, 5, 10],
|
||||
expected: 5
|
||||
expected: 5,
|
||||
},
|
||||
{
|
||||
args: [0, -5, 10],
|
||||
expected: 0
|
||||
expected: 0,
|
||||
},
|
||||
{
|
||||
args: [0, 15, 10],
|
||||
expected: 10
|
||||
}
|
||||
expected: 10,
|
||||
},
|
||||
];
|
||||
|
||||
describe('clamp', () => {
|
||||
describe("clamp", () => {
|
||||
testCases.forEach(({ args, expected }) => {
|
||||
it(`should return ${expected} when given ${JSON.stringify(args)}`, () => {
|
||||
expect(clamp(...args)).toBe(expected);
|
||||
|
||||
@@ -1,33 +1,33 @@
|
||||
import type { LanguageFn } from 'highlight.js';
|
||||
import hljs from 'highlight.js/lib/core';
|
||||
import go from 'highlight.js/lib/languages/go';
|
||||
import dart from 'highlight.js/lib/languages/dart';
|
||||
import javascript from 'highlight.js/lib/languages/javascript';
|
||||
import typescript from 'highlight.js/lib/languages/typescript';
|
||||
import xml from 'highlight.js/lib/languages/xml';
|
||||
import shell from 'highlight.js/lib/languages/shell';
|
||||
import markdown from 'highlight.js/lib/languages/markdown';
|
||||
import json from 'highlight.js/lib/languages/json';
|
||||
import swift from 'highlight.js/lib/languages/swift';
|
||||
import php from 'highlight.js/lib/languages/php';
|
||||
import python from 'highlight.js/lib/languages/python';
|
||||
import diff from 'highlight.js/lib/languages/diff';
|
||||
import ruby from 'highlight.js/lib/languages/ruby';
|
||||
import csharp from 'highlight.js/lib/languages/csharp';
|
||||
import kotlin from 'highlight.js/lib/languages/kotlin';
|
||||
import java from 'highlight.js/lib/languages/java';
|
||||
import cpp from 'highlight.js/lib/languages/cpp';
|
||||
import bash from 'highlight.js/lib/languages/bash';
|
||||
import powershell from 'highlight.js/lib/languages/powershell';
|
||||
import dos from 'highlight.js/lib/languages/dos';
|
||||
import yaml from 'highlight.js/lib/languages/yaml';
|
||||
import plaintext from 'highlight.js/lib/languages/plaintext';
|
||||
import graphql from 'highlight.js/lib/languages/graphql';
|
||||
import http from 'highlight.js/lib/languages/http';
|
||||
import css from 'highlight.js/lib/languages/css';
|
||||
import groovy from 'highlight.js/lib/languages/groovy';
|
||||
import ini from 'highlight.js/lib/languages/ini';
|
||||
import { Platform } from './references';
|
||||
import type { LanguageFn } from "highlight.js";
|
||||
import hljs from "highlight.js/lib/core";
|
||||
import go from "highlight.js/lib/languages/go";
|
||||
import dart from "highlight.js/lib/languages/dart";
|
||||
import javascript from "highlight.js/lib/languages/javascript";
|
||||
import typescript from "highlight.js/lib/languages/typescript";
|
||||
import xml from "highlight.js/lib/languages/xml";
|
||||
import shell from "highlight.js/lib/languages/shell";
|
||||
import markdown from "highlight.js/lib/languages/markdown";
|
||||
import json from "highlight.js/lib/languages/json";
|
||||
import swift from "highlight.js/lib/languages/swift";
|
||||
import php from "highlight.js/lib/languages/php";
|
||||
import python from "highlight.js/lib/languages/python";
|
||||
import diff from "highlight.js/lib/languages/diff";
|
||||
import ruby from "highlight.js/lib/languages/ruby";
|
||||
import csharp from "highlight.js/lib/languages/csharp";
|
||||
import kotlin from "highlight.js/lib/languages/kotlin";
|
||||
import java from "highlight.js/lib/languages/java";
|
||||
import cpp from "highlight.js/lib/languages/cpp";
|
||||
import bash from "highlight.js/lib/languages/bash";
|
||||
import powershell from "highlight.js/lib/languages/powershell";
|
||||
import dos from "highlight.js/lib/languages/dos";
|
||||
import yaml from "highlight.js/lib/languages/yaml";
|
||||
import plaintext from "highlight.js/lib/languages/plaintext";
|
||||
import graphql from "highlight.js/lib/languages/graphql";
|
||||
import http from "highlight.js/lib/languages/http";
|
||||
import css from "highlight.js/lib/languages/css";
|
||||
import groovy from "highlight.js/lib/languages/groovy";
|
||||
import ini from "highlight.js/lib/languages/ini";
|
||||
import { Platform } from "./references";
|
||||
|
||||
const languages = {
|
||||
js: javascript,
|
||||
@@ -64,33 +64,33 @@ const languages = {
|
||||
css: css,
|
||||
groovy: groovy,
|
||||
ini: ini,
|
||||
env: ini
|
||||
env: ini,
|
||||
} as const satisfies Record<string, LanguageFn>;
|
||||
|
||||
const platformAliases: Record<string, keyof typeof languages> = {
|
||||
[Platform.ClientWeb]: 'js',
|
||||
[Platform.ClientFlutter]: 'dart',
|
||||
[Platform.ClientApple]: 'swift',
|
||||
[Platform.ClientAndroidJava]: 'java',
|
||||
[Platform.ClientAndroidKotlin]: 'kotlin',
|
||||
[Platform.ClientReactNative]: 'js',
|
||||
[Platform.ClientGraphql]: 'graphql',
|
||||
[Platform.ClientRest]: 'http',
|
||||
[Platform.ServerDart]: 'dart',
|
||||
[Platform.ServerDeno]: 'ts',
|
||||
[Platform.ServerDotNet]: 'cs',
|
||||
[Platform.ServerNodeJs]: 'js',
|
||||
[Platform.ServerPhp]: 'php',
|
||||
[Platform.ServerPython]: 'py',
|
||||
[Platform.ServerRuby]: 'rb',
|
||||
[Platform.ServerSwift]: 'swift',
|
||||
[Platform.ServerJava]: 'java',
|
||||
[Platform.ServerKotlin]: 'kotlin',
|
||||
[Platform.ServerGraphql]: 'graphql',
|
||||
[Platform.ServerRest]: 'http',
|
||||
[Platform.ServerGo]: 'go',
|
||||
vue: 'html',
|
||||
svelte: 'html'
|
||||
[Platform.ClientWeb]: "js",
|
||||
[Platform.ClientFlutter]: "dart",
|
||||
[Platform.ClientApple]: "swift",
|
||||
[Platform.ClientAndroidJava]: "java",
|
||||
[Platform.ClientAndroidKotlin]: "kotlin",
|
||||
[Platform.ClientReactNative]: "js",
|
||||
[Platform.ClientGraphql]: "graphql",
|
||||
[Platform.ClientRest]: "http",
|
||||
[Platform.ServerDart]: "dart",
|
||||
[Platform.ServerDeno]: "ts",
|
||||
[Platform.ServerDotNet]: "cs",
|
||||
[Platform.ServerNodeJs]: "js",
|
||||
[Platform.ServerPhp]: "php",
|
||||
[Platform.ServerPython]: "py",
|
||||
[Platform.ServerRuby]: "rb",
|
||||
[Platform.ServerSwift]: "swift",
|
||||
[Platform.ServerJava]: "java",
|
||||
[Platform.ServerKotlin]: "kotlin",
|
||||
[Platform.ServerGraphql]: "graphql",
|
||||
[Platform.ServerRest]: "http",
|
||||
[Platform.ServerGo]: "go",
|
||||
vue: "html",
|
||||
svelte: "html",
|
||||
};
|
||||
|
||||
Object.entries(languages).forEach(([key, value]) => {
|
||||
@@ -99,7 +99,7 @@ Object.entries(languages).forEach(([key, value]) => {
|
||||
|
||||
Object.entries(platformAliases).forEach(([key, value]) => {
|
||||
hljs.registerAliases(key, {
|
||||
languageName: value
|
||||
languageName: value,
|
||||
});
|
||||
});
|
||||
|
||||
@@ -113,19 +113,19 @@ type Args = {
|
||||
|
||||
export const getCodeHtml = (args: Args) => {
|
||||
const { content, language, withLineNumbers } = args;
|
||||
const res = hljs.highlight(content, { language: language ?? 'sh' }).value;
|
||||
const res = hljs.highlight(content, { language: language ?? "sh" }).value;
|
||||
const lines = res.split(/\n/g);
|
||||
|
||||
while (lines.length > 0 && lines[lines.length - 1] === '') {
|
||||
while (lines.length > 0 && lines[lines.length - 1] === "") {
|
||||
lines.pop();
|
||||
}
|
||||
|
||||
const final = lines.reduce((carry, line) => {
|
||||
carry += `<span class="line">${line}</span>\n`;
|
||||
return carry;
|
||||
}, '');
|
||||
}, "");
|
||||
|
||||
return `<pre><code class="web-code language-${language} ${
|
||||
withLineNumbers ? 'line-numbers' : ''
|
||||
withLineNumbers ? "line-numbers" : ""
|
||||
}">${final}</code></pre>`;
|
||||
};
|
||||
|
||||
@@ -1,20 +1,20 @@
|
||||
import { derived, writable } from 'svelte/store';
|
||||
import { browser } from '$app/environment';
|
||||
import { Account, Client, Teams } from '@appwrite.io/console';
|
||||
import { Query, type Models } from '@appwrite.io/console';
|
||||
import { PUBLIC_APPWRITE_ENDPOINT } from '$env/static/public';
|
||||
import { derived, writable } from "svelte/store";
|
||||
import { browser } from "$app/environment";
|
||||
import { Account, Client, Teams } from "@appwrite.io/console";
|
||||
import { Query, type Models } from "@appwrite.io/console";
|
||||
import { PUBLIC_APPWRITE_ENDPOINT } from "$env/static/public";
|
||||
|
||||
const client = new Client();
|
||||
|
||||
client.setEndpoint(PUBLIC_APPWRITE_ENDPOINT).setProject('console');
|
||||
client.setEndpoint(PUBLIC_APPWRITE_ENDPOINT).setProject("console");
|
||||
|
||||
const account = new Account(client);
|
||||
const teams = new Teams(client);
|
||||
|
||||
enum BillingPlan {
|
||||
STARTER = 'tier-0',
|
||||
PRO = 'tier-1',
|
||||
SCALE = 'tier-2'
|
||||
STARTER = "tier-0",
|
||||
PRO = "tier-1",
|
||||
SCALE = "tier-2",
|
||||
}
|
||||
|
||||
export async function createSource(
|
||||
@@ -22,7 +22,7 @@ export async function createSource(
|
||||
referrer: string | null,
|
||||
utmSource: string | null,
|
||||
utmCampaign: string | null,
|
||||
utmMedium: string | null
|
||||
utmMedium: string | null,
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
): Promise<any> {
|
||||
const path = `/console/sources`;
|
||||
@@ -31,23 +31,25 @@ export async function createSource(
|
||||
referrer,
|
||||
utmSource,
|
||||
utmCampaign,
|
||||
utmMedium
|
||||
utmMedium,
|
||||
};
|
||||
|
||||
const uri = new URL(client.config.endpoint + path);
|
||||
return await client.call(
|
||||
'POST',
|
||||
"POST",
|
||||
uri,
|
||||
{
|
||||
'content-type': 'application/json'
|
||||
"content-type": "application/json",
|
||||
},
|
||||
params
|
||||
params,
|
||||
);
|
||||
}
|
||||
|
||||
export async function isProUser() {
|
||||
try {
|
||||
const orgs = await teams.list([Query.equal('billingPlan', BillingPlan.PRO)]);
|
||||
const orgs = await teams.list([
|
||||
Query.equal("billingPlan", BillingPlan.PRO),
|
||||
]);
|
||||
return orgs?.teams?.length > 1;
|
||||
} catch (e) {
|
||||
return false;
|
||||
@@ -58,7 +60,7 @@ export const sdk = { client, account };
|
||||
|
||||
export type AppwriteUser = Models.User<Models.Preferences>;
|
||||
function isAppwriteUser(user: unknown): user is AppwriteUser {
|
||||
return typeof user === 'object' && user !== null && '$id' in user;
|
||||
return typeof user === "object" && user !== null && "$id" in user;
|
||||
}
|
||||
|
||||
export function getAppwriteUser(): Promise<AppwriteUser | null> {
|
||||
@@ -73,15 +75,17 @@ function createAppwriteUser() {
|
||||
|
||||
function set(v: AppwriteUser | null) {
|
||||
if (v) {
|
||||
localStorage.setItem('appwrite:user', JSON.stringify(v));
|
||||
localStorage.setItem("appwrite:user", JSON.stringify(v));
|
||||
} else {
|
||||
localStorage.removeItem('appwrite:user');
|
||||
localStorage.removeItem("appwrite:user");
|
||||
}
|
||||
_set(v);
|
||||
}
|
||||
|
||||
if (browser) {
|
||||
const localUser = JSON.parse(localStorage.getItem('appwrite:user') ?? 'null');
|
||||
const localUser = JSON.parse(
|
||||
localStorage.getItem("appwrite:user") ?? "null",
|
||||
);
|
||||
if (isAppwriteUser(localUser)) _set(localUser);
|
||||
getAppwriteUser().then((res) => {
|
||||
set(res);
|
||||
@@ -89,7 +93,7 @@ function createAppwriteUser() {
|
||||
}
|
||||
|
||||
return {
|
||||
subscribe
|
||||
subscribe,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { writable } from 'svelte/store';
|
||||
import { writable } from "svelte/store";
|
||||
|
||||
async function securedCopy(value: string) {
|
||||
try {
|
||||
@@ -11,13 +11,13 @@ async function securedCopy(value: string) {
|
||||
}
|
||||
|
||||
function unsecuredCopy(value: string) {
|
||||
const textArea = document.createElement('textarea');
|
||||
const textArea = document.createElement("textarea");
|
||||
textArea.value = value;
|
||||
|
||||
// Avoid scrolling to bottom
|
||||
textArea.style.top = '0';
|
||||
textArea.style.left = '0';
|
||||
textArea.style.position = 'fixed';
|
||||
textArea.style.top = "0";
|
||||
textArea.style.left = "0";
|
||||
textArea.style.position = "fixed";
|
||||
|
||||
document.body.appendChild(textArea);
|
||||
textArea.focus();
|
||||
@@ -25,7 +25,7 @@ function unsecuredCopy(value: string) {
|
||||
|
||||
let success = true;
|
||||
try {
|
||||
document.execCommand('copy');
|
||||
document.execCommand("copy");
|
||||
} catch {
|
||||
success = false;
|
||||
} finally {
|
||||
@@ -56,6 +56,6 @@ export function createCopy(value: string) {
|
||||
|
||||
return {
|
||||
copied,
|
||||
copy: handleCopy
|
||||
copy: handleCopy,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
export const formatDate = (date: string | Date | number): string => {
|
||||
const dt = new Date(date);
|
||||
const month = dt.toLocaleString('en-US', { month: 'short' });
|
||||
const month = dt.toLocaleString("en-US", { month: "short" });
|
||||
const day = dt.getDate();
|
||||
const year = dt.getFullYear();
|
||||
return `${month} ${day}, ${year}`;
|
||||
@@ -11,9 +11,9 @@ export const addDays = (date: Date, days: number) => {
|
||||
};
|
||||
|
||||
export const toReleaseDate = (date: Date) => {
|
||||
return date.toLocaleDateString('en-US', {
|
||||
weekday: 'long',
|
||||
month: 'short',
|
||||
day: 'numeric'
|
||||
return date.toLocaleDateString("en-US", {
|
||||
weekday: "long",
|
||||
month: "short",
|
||||
day: "numeric",
|
||||
});
|
||||
};
|
||||
|
||||
@@ -9,6 +9,6 @@ export function createDebounce(delay = 500) {
|
||||
immediate: (callback: () => void) => {
|
||||
clearTimeout(timeout);
|
||||
callback();
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import type { AnimationConfig, FlipParams } from 'svelte/animate';
|
||||
import { cubicOut } from 'svelte/easing';
|
||||
import type { AnimationConfig, FlipParams } from "svelte/animate";
|
||||
import { cubicOut } from "svelte/easing";
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||
export function is_function(thing: unknown): thing is Function {
|
||||
return typeof thing === 'function';
|
||||
return typeof thing === "function";
|
||||
}
|
||||
|
||||
type Params = FlipParams & {
|
||||
@@ -19,11 +19,11 @@ type Params = FlipParams & {
|
||||
export function flip(
|
||||
node: HTMLElement,
|
||||
{ from, to }: { from: DOMRect; to: DOMRect },
|
||||
params: Params = {}
|
||||
params: Params = {},
|
||||
): AnimationConfig {
|
||||
const style = getComputedStyle(node);
|
||||
const transform = style.transform === 'none' ? '' : style.transform;
|
||||
const [ox, oy] = style.transformOrigin.split(' ').map(parseFloat);
|
||||
const transform = style.transform === "none" ? "" : style.transform;
|
||||
const [ox, oy] = style.transformOrigin.split(" ").map(parseFloat);
|
||||
const dx = from.left + (from.width * ox) / to.width - (to.left + ox);
|
||||
const dy = from.top + (from.height * oy) / to.height - (to.top + oy);
|
||||
|
||||
@@ -31,11 +31,13 @@ export function flip(
|
||||
delay = 0,
|
||||
duration = (d) => Math.sqrt(d) * 120,
|
||||
easing = cubicOut,
|
||||
scale = true
|
||||
scale = true,
|
||||
} = params;
|
||||
return {
|
||||
delay,
|
||||
duration: is_function(duration) ? duration(Math.sqrt(dx * dx + dy * dy)) : duration,
|
||||
duration: is_function(duration)
|
||||
? duration(Math.sqrt(dx * dx + dy * dy))
|
||||
: duration,
|
||||
easing,
|
||||
css: (t, u) => {
|
||||
const x = u * dx;
|
||||
@@ -52,8 +54,8 @@ export function flip(
|
||||
const inverse_sx = scale ? 1 / sx : 1;
|
||||
const inverse_sy = scale ? 1 / sy : 1;
|
||||
|
||||
node.style.setProperty('--inverse-sx', inverse_sx.toString());
|
||||
node.style.setProperty('--inverse-sy', inverse_sy.toString());
|
||||
}
|
||||
node.style.setProperty("--inverse-sx", inverse_sx.toString());
|
||||
node.style.setProperty("--inverse-sy", inverse_sy.toString());
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ let lastScrollPos = 0;
|
||||
|
||||
export function getScrollDir() {
|
||||
const scrollPos = window.scrollY;
|
||||
const scrollDir = scrollPos > lastScrollPos ? 'down' : 'up';
|
||||
const scrollDir = scrollPos > lastScrollPos ? "down" : "up";
|
||||
lastScrollPos = scrollPos;
|
||||
return scrollDir;
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
export function isNumeric(value: unknown): boolean {
|
||||
if (typeof value === 'number' && !isNaN(value)) {
|
||||
if (typeof value === "number" && !isNaN(value)) {
|
||||
return true;
|
||||
}
|
||||
if (typeof value === 'string' && value.trim() !== '') {
|
||||
if (typeof value === "string" && value.trim() !== "") {
|
||||
return !isNaN(Number(value));
|
||||
}
|
||||
return false;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
export function isVisible(
|
||||
element: Element,
|
||||
visRect: { left: number; right: number; top: number; bottom: number }
|
||||
visRect: { left: number; right: number; top: number; bottom: number },
|
||||
) {
|
||||
const rect = element.getBoundingClientRect();
|
||||
const vertInView = rect.top <= visRect.bottom && rect.bottom >= visRect.top;
|
||||
|
||||
@@ -1,35 +1,37 @@
|
||||
import MarkdownIt from 'markdown-it';
|
||||
import MarkdownIt from "markdown-it";
|
||||
|
||||
const md = new MarkdownIt('commonmark');
|
||||
const md = new MarkdownIt("commonmark");
|
||||
export function parse(content: string): string {
|
||||
const tokens = md.parse(content, null);
|
||||
return md.renderer.render(
|
||||
transform_tokens(tokens),
|
||||
{
|
||||
highlight: null
|
||||
highlight: null,
|
||||
},
|
||||
null
|
||||
null,
|
||||
);
|
||||
}
|
||||
|
||||
function transform_tokens(tokens: ReturnType<typeof md.parse>): ReturnType<typeof md.parse> {
|
||||
function transform_tokens(
|
||||
tokens: ReturnType<typeof md.parse>,
|
||||
): ReturnType<typeof md.parse> {
|
||||
return tokens.map((token) => {
|
||||
if (token.children) {
|
||||
token.children = transform_tokens(token.children);
|
||||
}
|
||||
switch (token.type) {
|
||||
case 'paragraph_open':
|
||||
token.attrPush(['class', 'web-paragraph']);
|
||||
case "paragraph_open":
|
||||
token.attrPush(["class", "web-paragraph"]);
|
||||
break;
|
||||
case 'link_open': {
|
||||
const href = token.attrGet('href');
|
||||
if (href?.startsWith('http')) {
|
||||
if (!href.startsWith('https://appwrite.io')) {
|
||||
token.attrPush(['rel', 'noopener noreferrer']);
|
||||
token.attrPush(['target', '_blank']);
|
||||
case "link_open": {
|
||||
const href = token.attrGet("href");
|
||||
if (href?.startsWith("http")) {
|
||||
if (!href.startsWith("https://appwrite.io")) {
|
||||
token.attrPush(["rel", "noopener noreferrer"]);
|
||||
token.attrPush(["target", "_blank"]);
|
||||
}
|
||||
}
|
||||
token.attrPush(['class', 'web-link']);
|
||||
token.attrPush(["class", "web-link"]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
export function toScale(value: number, from: [number, number], to: [number, number]) {
|
||||
export function toScale(
|
||||
value: number,
|
||||
from: [number, number],
|
||||
to: [number, number],
|
||||
) {
|
||||
const [fromMin, fromMax] = from;
|
||||
const [toMin, toMax] = to;
|
||||
|
||||
|
||||
@@ -1,35 +1,38 @@
|
||||
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_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 function buildOpenGraphImage(title: string, description: string): string {
|
||||
"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
|
||||
title,
|
||||
)}&subtitle=${encodeURIComponent(description)}`;
|
||||
}
|
||||
|
||||
export function createSchemaAuthor(author: AuthorData): string {
|
||||
return (
|
||||
`< script type="application/ld+json">${JSON.stringify({
|
||||
'@context': 'https://schema.org',
|
||||
'@type': 'Person',
|
||||
"@context": "https://schema.org",
|
||||
"@type": "Person",
|
||||
name: author.name,
|
||||
url: author.href,
|
||||
image: author.avatar
|
||||
})}</` + 'script>'
|
||||
image: author.avatar,
|
||||
})}</` + "script>"
|
||||
);
|
||||
}
|
||||
|
||||
export function createSchemaPost(post: PostsData): string {
|
||||
return (
|
||||
`< script type="application/ld+json">${JSON.stringify({
|
||||
'@context': 'https://schema.org',
|
||||
'@type': 'BlogPosting',
|
||||
"@context": "https://schema.org",
|
||||
"@type": "BlogPosting",
|
||||
headline: post.title,
|
||||
image: post.cover,
|
||||
datePublished: post.date,
|
||||
dateModified: post.date
|
||||
})}</` + 'script>'
|
||||
dateModified: post.date,
|
||||
})}</` + "script>"
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { writable } from 'svelte/store';
|
||||
import { writable } from "svelte/store";
|
||||
|
||||
type Adapter = {
|
||||
get: (key: string) => unknown;
|
||||
@@ -7,7 +7,7 @@ type Adapter = {
|
||||
|
||||
const localStorageAdapter: Adapter = {
|
||||
get: (key: string) => {
|
||||
if (typeof window === 'undefined') return undefined;
|
||||
if (typeof window === "undefined") return undefined;
|
||||
|
||||
const value = localStorage.getItem(key);
|
||||
|
||||
@@ -17,10 +17,10 @@ const localStorageAdapter: Adapter = {
|
||||
return JSON.parse(value);
|
||||
},
|
||||
set: (key, value) => {
|
||||
if (typeof window === 'undefined') return;
|
||||
if (typeof window === "undefined") return;
|
||||
|
||||
localStorage.setItem(key, JSON.stringify(value));
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
type Options<Value> = {
|
||||
@@ -31,7 +31,7 @@ type Options<Value> = {
|
||||
|
||||
export const persisted = <Value>(
|
||||
key: string,
|
||||
{ defaultValue, adapter = localStorageAdapter, validate }: Options<Value>
|
||||
{ defaultValue, adapter = localStorageAdapter, validate }: Options<Value>,
|
||||
) => {
|
||||
const localValue = adapter.get(key);
|
||||
let initialValue: Value | undefined = defaultValue;
|
||||
@@ -60,6 +60,6 @@ export const persisted = <Value>(
|
||||
return {
|
||||
...store,
|
||||
update,
|
||||
set
|
||||
set,
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
export const isDom = () => typeof window !== 'undefined';
|
||||
export const isDom = () => typeof window !== "undefined";
|
||||
export function getPlatform() {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const agent = (navigator as any).userAgentData;
|
||||
|
||||
@@ -1,147 +1,146 @@
|
||||
import { writable } from 'svelte/store';
|
||||
import type { Language } from './code';
|
||||
import { browser } from '$app/environment';
|
||||
import { writable } from "svelte/store";
|
||||
import type { Language } from "./code";
|
||||
import { browser } from "$app/environment";
|
||||
|
||||
const allVersions = [
|
||||
'1.6.x',
|
||||
'1.5.x',
|
||||
'1.4.x',
|
||||
'1.3.x',
|
||||
'1.2.x',
|
||||
'1.1.x',
|
||||
'1.0.x',
|
||||
'0.15.x',
|
||||
'cloud'
|
||||
"1.6.x",
|
||||
"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];
|
||||
|
||||
export const versions: Readonly<Array<Omit<Version, 'cloud'>>> = allVersions.filter(
|
||||
(v) => v !== 'cloud'
|
||||
);
|
||||
export const versions: Readonly<Array<Omit<Version, "cloud">>> =
|
||||
allVersions.filter((v) => v !== "cloud");
|
||||
|
||||
export enum Service {
|
||||
Account = 'account',
|
||||
Avatars = 'avatars',
|
||||
Databases = 'databases',
|
||||
Functions = 'functions',
|
||||
Messaging = 'messaging',
|
||||
Health = 'health',
|
||||
Locale = 'locale',
|
||||
Storage = 'storage',
|
||||
Teams = 'teams',
|
||||
Users = 'users',
|
||||
Account = "account",
|
||||
Avatars = "avatars",
|
||||
Databases = "databases",
|
||||
Functions = "functions",
|
||||
Messaging = "messaging",
|
||||
Health = "health",
|
||||
Locale = "locale",
|
||||
Storage = "storage",
|
||||
Teams = "teams",
|
||||
Users = "users",
|
||||
}
|
||||
|
||||
export enum Platform {
|
||||
ClientWeb = 'client-web',
|
||||
ClientFlutter = 'client-flutter',
|
||||
ClientReactNative = 'client-react-native',
|
||||
ClientApple = 'client-apple',
|
||||
ClientAndroidKotlin = 'client-android-kotlin',
|
||||
ClientAndroidJava = 'client-android-java',
|
||||
ClientGraphql = 'client-graphql',
|
||||
ClientRest = 'client-rest',
|
||||
ServerNodeJs = 'server-nodejs',
|
||||
ServerPython = 'server-python',
|
||||
ServerDart = 'server-dart',
|
||||
ServerPhp = 'server-php',
|
||||
ServerRuby = 'server-ruby',
|
||||
ServerDotNet = 'server-dotnet',
|
||||
ServerDeno = 'server-deno',
|
||||
ServerGo = 'server-go',
|
||||
ServerSwift = 'server-swift',
|
||||
ServerKotlin = 'server-kotlin',
|
||||
ServerJava = 'server-java',
|
||||
ServerGraphql = 'server-graphql',
|
||||
ServerRest = 'server-rest',
|
||||
ClientWeb = "client-web",
|
||||
ClientFlutter = "client-flutter",
|
||||
ClientReactNative = "client-react-native",
|
||||
ClientApple = "client-apple",
|
||||
ClientAndroidKotlin = "client-android-kotlin",
|
||||
ClientAndroidJava = "client-android-java",
|
||||
ClientGraphql = "client-graphql",
|
||||
ClientRest = "client-rest",
|
||||
ServerNodeJs = "server-nodejs",
|
||||
ServerPython = "server-python",
|
||||
ServerDart = "server-dart",
|
||||
ServerPhp = "server-php",
|
||||
ServerRuby = "server-ruby",
|
||||
ServerDotNet = "server-dotnet",
|
||||
ServerDeno = "server-deno",
|
||||
ServerGo = "server-go",
|
||||
ServerSwift = "server-swift",
|
||||
ServerKotlin = "server-kotlin",
|
||||
ServerJava = "server-java",
|
||||
ServerGraphql = "server-graphql",
|
||||
ServerRest = "server-rest",
|
||||
}
|
||||
|
||||
export const platformMap: Record<Language | string, string> = {
|
||||
[Platform.ClientApple]: 'Apple',
|
||||
[Platform.ClientFlutter]: 'Flutter',
|
||||
[Platform.ClientWeb]: 'Web',
|
||||
[Platform.ClientAndroidKotlin]: 'Android (Kotlin)',
|
||||
[Platform.ClientAndroidJava]: 'Android (Java)',
|
||||
[Platform.ClientReactNative]: 'React Native',
|
||||
[Platform.ClientGraphql]: 'GraphQL',
|
||||
[Platform.ClientRest]: 'REST',
|
||||
[Platform.ServerDart]: 'Dart',
|
||||
[Platform.ServerDeno]: 'Deno',
|
||||
[Platform.ServerDotNet]: '.NET',
|
||||
[Platform.ServerNodeJs]: 'Node.js',
|
||||
[Platform.ServerPhp]: 'PHP',
|
||||
[Platform.ServerPython]: 'Python',
|
||||
[Platform.ServerRuby]: 'Ruby',
|
||||
[Platform.ServerSwift]: 'Swift',
|
||||
[Platform.ServerKotlin]: 'Kotlin',
|
||||
[Platform.ServerJava]: 'Java',
|
||||
[Platform.ServerGraphql]: 'GraphQL',
|
||||
[Platform.ServerRest]: 'REST',
|
||||
[Platform.ServerGo]: 'Go',
|
||||
sh: 'Shell',
|
||||
js: 'JavaScript',
|
||||
ts: 'TypeScript',
|
||||
jsx: 'React',
|
||||
tsx: 'React',
|
||||
typescript: 'TypeScript',
|
||||
dart: 'Dart',
|
||||
java: 'Java',
|
||||
kotlin: 'Kotlin',
|
||||
cs: 'C#',
|
||||
py: 'Python',
|
||||
rb: 'Ruby',
|
||||
php: 'PHP',
|
||||
swift: 'Swift',
|
||||
xml: 'XML',
|
||||
html: 'HTML',
|
||||
md: 'Markdown',
|
||||
json: 'JSON',
|
||||
diff: 'Diff',
|
||||
http: 'HTTP',
|
||||
css: 'CSS',
|
||||
graphql: 'GraphQL',
|
||||
deno: 'Deno',
|
||||
python: 'Python',
|
||||
ruby: 'Ruby',
|
||||
csharp: 'C#',
|
||||
cpp: 'C++',
|
||||
bash: 'Bash',
|
||||
powershell: 'PowerShell',
|
||||
cmd: 'CMD',
|
||||
yaml: 'YAML',
|
||||
text: 'Text',
|
||||
vue: 'Vue',
|
||||
svelte: 'Svelte',
|
||||
groovy: 'Groovy',
|
||||
go: 'Go',
|
||||
[Platform.ClientApple]: "Apple",
|
||||
[Platform.ClientFlutter]: "Flutter",
|
||||
[Platform.ClientWeb]: "Web",
|
||||
[Platform.ClientAndroidKotlin]: "Android (Kotlin)",
|
||||
[Platform.ClientAndroidJava]: "Android (Java)",
|
||||
[Platform.ClientReactNative]: "React Native",
|
||||
[Platform.ClientGraphql]: "GraphQL",
|
||||
[Platform.ClientRest]: "REST",
|
||||
[Platform.ServerDart]: "Dart",
|
||||
[Platform.ServerDeno]: "Deno",
|
||||
[Platform.ServerDotNet]: ".NET",
|
||||
[Platform.ServerNodeJs]: "Node.js",
|
||||
[Platform.ServerPhp]: "PHP",
|
||||
[Platform.ServerPython]: "Python",
|
||||
[Platform.ServerRuby]: "Ruby",
|
||||
[Platform.ServerSwift]: "Swift",
|
||||
[Platform.ServerKotlin]: "Kotlin",
|
||||
[Platform.ServerJava]: "Java",
|
||||
[Platform.ServerGraphql]: "GraphQL",
|
||||
[Platform.ServerRest]: "REST",
|
||||
[Platform.ServerGo]: "Go",
|
||||
sh: "Shell",
|
||||
js: "JavaScript",
|
||||
ts: "TypeScript",
|
||||
jsx: "React",
|
||||
tsx: "React",
|
||||
typescript: "TypeScript",
|
||||
dart: "Dart",
|
||||
java: "Java",
|
||||
kotlin: "Kotlin",
|
||||
cs: "C#",
|
||||
py: "Python",
|
||||
rb: "Ruby",
|
||||
php: "PHP",
|
||||
swift: "Swift",
|
||||
xml: "XML",
|
||||
html: "HTML",
|
||||
md: "Markdown",
|
||||
json: "JSON",
|
||||
diff: "Diff",
|
||||
http: "HTTP",
|
||||
css: "CSS",
|
||||
graphql: "GraphQL",
|
||||
deno: "Deno",
|
||||
python: "Python",
|
||||
ruby: "Ruby",
|
||||
csharp: "C#",
|
||||
cpp: "C++",
|
||||
bash: "Bash",
|
||||
powershell: "PowerShell",
|
||||
cmd: "CMD",
|
||||
yaml: "YAML",
|
||||
text: "Text",
|
||||
vue: "Vue",
|
||||
svelte: "Svelte",
|
||||
groovy: "Groovy",
|
||||
go: "Go",
|
||||
};
|
||||
|
||||
export const serviceMap: Record<Service, string> = {
|
||||
[Service.Account]: 'Account',
|
||||
[Service.Avatars]: 'Avatars',
|
||||
[Service.Databases]: 'Databases',
|
||||
[Service.Functions]: 'Functions',
|
||||
[Service.Messaging]: 'Messaging',
|
||||
[Service.Health]: 'Health',
|
||||
[Service.Locale]: 'Locale',
|
||||
[Service.Storage]: 'Storage',
|
||||
[Service.Teams]: 'Teams',
|
||||
[Service.Users]: 'Users',
|
||||
[Service.Account]: "Account",
|
||||
[Service.Avatars]: "Avatars",
|
||||
[Service.Databases]: "Databases",
|
||||
[Service.Functions]: "Functions",
|
||||
[Service.Messaging]: "Messaging",
|
||||
[Service.Health]: "Health",
|
||||
[Service.Locale]: "Locale",
|
||||
[Service.Storage]: "Storage",
|
||||
[Service.Teams]: "Teams",
|
||||
[Service.Users]: "Users",
|
||||
};
|
||||
|
||||
export const preferredVersion = writable<Version | null>(
|
||||
globalThis?.localStorage?.getItem('preferredVersion') as Version
|
||||
globalThis?.localStorage?.getItem("preferredVersion") as Version,
|
||||
);
|
||||
export const preferredPlatform = writable<Platform | null>(
|
||||
globalThis?.localStorage?.getItem('preferredPlatform') as Platform
|
||||
globalThis?.localStorage?.getItem("preferredPlatform") as Platform,
|
||||
);
|
||||
|
||||
if (browser) {
|
||||
preferredVersion.subscribe((value) => {
|
||||
if (value) globalThis?.sessionStorage?.setItem('preferredVersion', value);
|
||||
if (value) globalThis?.sessionStorage?.setItem("preferredVersion", value);
|
||||
});
|
||||
preferredPlatform.subscribe((value) => {
|
||||
if (value) globalThis?.sessionStorage?.setItem('preferredPlatform', value);
|
||||
if (value) globalThis?.sessionStorage?.setItem("preferredPlatform", value);
|
||||
});
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user