prettier updates

This commit is contained in:
Jesse Winton
2024-07-23 16:08:38 -04:00
parent 79f84f74a0
commit 7cd6ca33d0
278 changed files with 6228 additions and 5966 deletions

View File

@@ -1,34 +1,34 @@
<script lang="ts">
import { rect } from '$lib/actions';
import { writable } from 'svelte/store';
import { rect } from '$lib/actions';
import { writable } from 'svelte/store';
const bodyRect = writable<DOMRect | null>(null);
const bodyRect = writable<DOMRect | null>(null);
</script>
<div class="relative">
<div
class="true-body"
style:width={`${$bodyRect?.width ?? 0}px`}
style:height={`${$bodyRect?.height ?? 0}px`}
/>
<div class="body" use:rect={bodyRect}>
<slot />
</div>
<div
class="true-body"
style:width={`${$bodyRect?.width ?? 0}px`}
style:height={`${$bodyRect?.height ?? 0}px`}
/>
<div class="body" use:rect={bodyRect}>
<slot />
</div>
</div>
<style lang="scss">
.relative {
position: relative;
overflow: hidden;
}
.relative {
position: relative;
overflow: hidden;
}
.body {
position: absolute;
left: 0;
top: 0;
}
.body {
position: absolute;
left: 0;
top: 0;
}
.true-body {
transition: 0.2s ease;
}
.true-body {
transition: 0.2s ease;
}
</style>

View File

@@ -1,10 +1,10 @@
<script lang="ts">
import '$scss/hljs.css';
import '$scss/hljs.css';
import { getCodeHtml } from '$lib/utils/code';
import { getCodeHtml } from '$lib/utils/code';
export let content: string;
$: codeHtml = getCodeHtml({ content, language: 'js' });
export let content: string;
$: codeHtml = getCodeHtml({ content, language: 'js' });
</script>
<!-- eslint-disable-next-line svelte/no-at-html-tags -->

View File

@@ -1,96 +1,96 @@
<script>
import AutoBox from '../AutoBox.svelte';
import Code from './Code.svelte';
import AutoBox from '../AutoBox.svelte';
import Code from './Code.svelte';
</script>
<div class="code-console">
<div class="header">
<div class="ellipse" />
<div class="ellipse-2" />
<div class="ellipse-3" />
</div>
<div class="block">
<AutoBox>
<slot {Code} />
</AutoBox>
</div>
<div id="code-bottom" />
<div class="header">
<div class="ellipse" />
<div class="ellipse-2" />
<div class="ellipse-3" />
</div>
<div class="block">
<AutoBox>
<slot {Code} />
</AutoBox>
</div>
<div id="code-bottom" />
</div>
<style lang="scss">
@use '$scss/abstract/mixins/border-gradient' as gradients;
.code-console {
@include gradients.border-gradient;
--p-radius: 16px;
.code-console {
@include gradients.border-gradient;
--p-radius: 16px;
display: flex;
flex-direction: column;
display: flex;
flex-direction: column;
background-color: hsl(var(--web-color-card));
border-radius: var(--p-radius);
--m-border-radius: var(--p-radius);
--m-border-gradient-before: linear-gradient(
180deg,
rgba(255, 255, 255, 0.12) 0%,
rgba(255, 255, 255, 0) 125.11%
);
backdrop-filter: blur(8px);
background-color: hsl(var(--web-color-card));
border-radius: var(--p-radius);
--m-border-radius: var(--p-radius);
--m-border-gradient-before: linear-gradient(
180deg,
rgba(255, 255, 255, 0.12) 0%,
rgba(255, 255, 255, 0) 125.11%
);
backdrop-filter: blur(8px);
min-width: 330px;
width: fit-content;
padding: 0 0.25rem 0.25rem;
}
min-width: 330px;
width: fit-content;
padding: 0 0.25rem 0.25rem;
}
.block {
width: 100%;
flex-grow: 1;
text-align: left;
.block {
width: 100%;
flex-grow: 1;
text-align: left;
border-radius: 12px;
background: linear-gradient(129deg, rgba(0, 0, 0, 0.48) 22.38%, rgba(0, 0, 0, 0) 136.5%);
padding: 20px;
border-radius: 12px;
background: linear-gradient(129deg, rgba(0, 0, 0, 0.48) 22.38%, rgba(0, 0, 0, 0) 136.5%);
padding: 20px;
position: relative;
}
position: relative;
}
.header {
position: relative;
display: flex;
align-items: center;
gap: 0.375rem;
padding: 0.75rem;
.header {
position: relative;
display: flex;
align-items: center;
gap: 0.375rem;
padding: 0.75rem;
.ellipse {
background-color: #ec6a5e;
.ellipse {
background-color: #ec6a5e;
width: 8px;
height: 8px;
top: 12px;
border-radius: 4px;
}
width: 8px;
height: 8px;
top: 12px;
border-radius: 4px;
}
.ellipse-2 {
background-color: #f5bf4f;
.ellipse-2 {
background-color: #f5bf4f;
width: 8px;
height: 8px;
top: 12px;
border-radius: 4px;
}
width: 8px;
height: 8px;
top: 12px;
border-radius: 4px;
}
.ellipse-3 {
background-color: #61c554;
.ellipse-3 {
background-color: #61c554;
width: 8px;
height: 8px;
top: 12px;
border-radius: 4px;
}
}
width: 8px;
height: 8px;
top: 12px;
border-radius: 4px;
}
}
.code-console :global(code) {
white-space: pre;
tab-size: 4;
}
.code-console :global(code) {
white-space: pre;
tab-size: 4;
}
</style>

View File

@@ -182,7 +182,7 @@
class="web-card is-white web-u-min-block-size-320 u-flex-vertical oss-card"
id="oss-discord"
>
<div class="u-flex-vertical u-main-space-between u-gap-32">
<div class="u-flex-vertical u-main-space-between gap-8">
<span
class="web-icon-discord web-u-font-size-40"
aria-hidden="true"
@@ -197,7 +197,7 @@
id="oss-github"
href="https://github.com/appwrite/appwrite"
>
<div class="u-flex-vertical u-main-space-between u-gap-32">
<div class="u-flex-vertical u-main-space-between gap-8">
<span
class="web-icon-github web-u-font-size-40"
aria-hidden="true"
@@ -212,7 +212,7 @@
class="web-card is-white web-u-min-block-size-320 u-flex-vertical oss-card"
id="oss-twitter"
>
<div class="u-flex-vertical u-main-space-between u-gap-32">
<div class="u-flex-vertical u-main-space-between gap-8">
<span
class="web-icon-x web-u-font-size-40"
aria-hidden="true"
@@ -227,7 +227,7 @@
class="web-card is-white web-u-min-block-size-320 u-flex-vertical oss-card"
id="oss-youtube"
>
<div class="u-flex-vertical u-main-space-between u-gap-32">
<div class="u-flex-vertical u-main-space-between gap-8">
<span
class="web-icon-youtube web-u-font-size-40"
aria-hidden="true"
@@ -242,7 +242,7 @@
id="oss-commits"
href="https://github.com/appwrite/appwrite"
>
<div class="u-flex-vertical u-main-space-between u-gap-32">
<div class="u-flex-vertical u-main-space-between gap-8">
<span
class="web-icon-github web-u-font-size-40"
aria-hidden="true"

View File

@@ -1,9 +1,9 @@
<script lang="ts">
export let id: string | undefined = undefined;
export let id: string | undefined = undefined;
</script>
<div class="phone" {id}>
<div class="inner">
<slot />
</div>
<div class="inner">
<slot />
</div>
</div>

View File

@@ -1,55 +1,55 @@
<script lang="ts">
import AutoHeight from '../AutoBox.svelte';
import AutoHeight from '../AutoBox.svelte';
</script>
<div class="anim-box">
<div class="top"><slot name="top" /></div>
<div class="content">
<AutoHeight>
<slot />
</AutoHeight>
</div>
<div class="top"><slot name="top" /></div>
<div class="content">
<AutoHeight>
<slot />
</AutoHeight>
</div>
</div>
<style lang="scss">
@use '$scss/abstract/mixins/border-gradient' as gradients;
.anim-box {
@include gradients.border-gradient;
--m-border-radius: 1rem;
--m-border-gradient-before: linear-gradient(
180deg,
rgba(255, 255, 255, 0.12) 0%,
rgba(255, 255, 255, 0) 125.11%
);
border-radius: var(--m-border-radius);
background: hsl(var(--web-color-card));
backdrop-filter: blur(8px);
.anim-box {
@include gradients.border-gradient;
--m-border-radius: 1rem;
--m-border-gradient-before: linear-gradient(
180deg,
rgba(255, 255, 255, 0.12) 0%,
rgba(255, 255, 255, 0) 125.11%
);
border-radius: var(--m-border-radius);
background: hsl(var(--web-color-card));
backdrop-filter: blur(8px);
padding: 0.5rem;
padding-block-start: 0;
padding: 0.5rem;
padding-block-start: 0;
text-align: left;
text-align: left;
.top {
color: var(--greyscale-50, #ededf0);
font-family: Aeonik Pro;
font-size: 1.25rem;
font-style: normal;
font-weight: 400;
line-height: 2rem; /* 160% */
letter-spacing: -0.0125rem;
.top {
color: var(--greyscale-50, #ededf0);
font-family: Aeonik Pro;
font-size: 1.25rem;
font-style: normal;
font-weight: 400;
line-height: 2rem; /* 160% */
letter-spacing: -0.0125rem;
padding: 1rem;
text-align: left;
}
padding: 1rem;
text-align: left;
}
.content {
border-radius: 0.75rem;
background: rgba(255, 255, 255, 0.04);
backdrop-filter: blur(30px);
.content {
border-radius: 0.75rem;
background: rgba(255, 255, 255, 0.04);
backdrop-filter: blur(30px);
position: relative;
}
}
position: relative;
}
}
</style>

View File

@@ -247,7 +247,7 @@
Your backend, minus the hassle
</h2>
<p
class="web-description web-u-max-width-700 u-margin-inline-auto"
class="web-description web-u-max-width-700 mx-auto"
transition:fly={{
y: 16,
delay: 400

View File

@@ -1,61 +1,61 @@
<script lang="ts">
import { createCheckbox, melt } from '@melt-ui/svelte';
import { createCheckbox, melt } from '@melt-ui/svelte';
export let checked = false;
export let checked = false;
const {
elements: { root },
states: { checked: localChecked },
helpers: { isChecked }
} = createCheckbox({
onCheckedChange({ next }) {
if (typeof next === 'boolean') {
checked = next;
}
return next;
}
});
const {
elements: { root },
states: { checked: localChecked },
helpers: { isChecked }
} = createCheckbox({
onCheckedChange({ next }) {
if (typeof next === 'boolean') {
checked = next;
}
return next;
}
});
$: localChecked.set(checked);
$: localChecked.set(checked);
</script>
<div class="wrapper">
<button use:melt={$root} class="anim-checkbox">
{#if $isChecked}
<span class="web-icon-check" />
{/if}
</button>
<button use:melt={$root} class="anim-checkbox">
{#if $isChecked}
<span class="web-icon-check" />
{/if}
</button>
</div>
<style lang="scss">
.wrapper {
display: grid;
place-items: center;
}
.wrapper {
display: grid;
place-items: center;
}
.anim-checkbox {
width: 1rem;
height: 1rem;
flex-shrink: 0;
.anim-checkbox {
width: 1rem;
height: 1rem;
flex-shrink: 0;
border-radius: 0.125rem;
border: 1.5px solid var(--greyscale-500, #818186);
border-radius: 0.125rem;
border: 1.5px solid var(--greyscale-500, #818186);
position: relative;
position: relative;
&:global(.anim-checkbox[data-state='checked']) {
background-color: #7c67fe;
border-color: #7c67fe;
}
}
&:global(.anim-checkbox[data-state='checked']) {
background-color: #7c67fe;
border-color: #7c67fe;
}
}
[class*='icon-'] {
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
[class*='icon-'] {
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
color: white;
font-size: 1rem;
}
color: white;
font-size: 1rem;
}
</style>

View File

@@ -1,64 +1,64 @@
<script lang="ts">
import { getInitials } from '$lib/animations';
import { fly } from 'svelte/transition';
import { authController } from '.';
import { flip } from '$lib/utils/flip';
import { getInitials } from '$lib/animations';
import { fly } from 'svelte/transition';
import { authController } from '.';
import { flip } from '$lib/utils/flip';
const { state } = authController;
const { state } = authController;
type AuthEntry = {
avatar: string;
name: string;
email: string;
id: number;
};
$: authData = [
$state.submitted
? {
avatar: getInitials($state.name),
name: $state.name,
email: $state.email,
id: 0
}
: undefined,
{
avatar: 'BD',
name: 'Benjamin Davis',
email: 'benjamin.davis@example.com',
id: 1
},
{
avatar: 'OS',
name: 'Olivia Smith',
email: 'olivia.smith@example.com',
id: 2
},
{
avatar: 'EW',
name: 'Ethan Wilson',
email: 'ethan.wilson@example.com',
id: 3
}
].filter(Boolean) as AuthEntry[];
type AuthEntry = {
avatar: string;
name: string;
email: string;
id: number;
};
$: authData = [
$state.submitted
? {
avatar: getInitials($state.name),
name: $state.name,
email: $state.email,
id: 0
}
: undefined,
{
avatar: 'BD',
name: 'Benjamin Davis',
email: 'benjamin.davis@example.com',
id: 1
},
{
avatar: 'OS',
name: 'Olivia Smith',
email: 'olivia.smith@example.com',
id: 2
},
{
avatar: 'EW',
name: 'Ethan Wilson',
email: 'ethan.wilson@example.com',
id: 3
}
].filter(Boolean) as AuthEntry[];
</script>
<div class="pseudo-table">
<div class="header">
<span class="web-eyebrow">Name</span>
<span class="web-eyebrow">Identifier</span>
</div>
{#each authData as user (user.id)}
<div
class="row"
in:fly={{ duration: 100, x: -16, delay: 100 }}
out:fly={{ duration: 100, x: -16 }}
animate:flip={{ duration: 150 }}
>
<div class="u-flex u-cross-center u-gap-12">
<div class="avatar is-size-small">{user.avatar}</div>
<span class="truncated">{user.name}</span>
</div>
<span class="truncated">{user.email}</span>
</div>
{/each}
<div class="header">
<span class="web-eyebrow">Name</span>
<span class="web-eyebrow">Identifier</span>
</div>
{#each authData as user (user.id)}
<div
class="row"
in:fly={{ duration: 100, x: -16, delay: 100 }}
out:fly={{ duration: 100, x: -16 }}
animate:flip={{ duration: 150 }}
>
<div class="flex u-cross-center gap-3">
<div class="avatar is-size-small">{user.avatar}</div>
<span class="truncated">{user.name}</span>
</div>
<span class="truncated">{user.email}</span>
</div>
{/each}
</div>

View File

@@ -1,211 +1,220 @@
<script lang="ts">
import { fade } from 'svelte/transition';
import { authController } from '.';
import { objectKeys } from '$lib/utils/object';
import { flip } from '$lib/utils/flip';
import { fade } from 'svelte/transition';
import { authController } from '.';
import { objectKeys } from '$lib/utils/object';
import { flip } from '$lib/utils/flip';
const { state } = authController;
const { state } = authController;
$: controlsEnabled = $state.showControls && Object.values($state.controls).some(Boolean);
$: controlsEnabled = $state.showControls && Object.values($state.controls).some(Boolean);
</script>
<div data-theme-ignore class="inner-phone theme-light">
<p class="title">Create an Account</p>
<p class="subtitle">Please enter your details</p>
<div class="inputs">
<fieldset>
<label for="name">Your Name</label>
<input type="name" id="name" placeholder="Enter your name" bind:value={$state.name} />
</fieldset>
<fieldset>
<label for="email">Your Email</label>
<input type="email" id="email" placeholder="Enter your email" bind:value={$state.email} />
</fieldset>
<fieldset>
<label for="password">Create Password</label>
<input
type="password"
id="password"
placeholder="Enter Password"
bind:value={$state.password}
/>
</fieldset>
</div>
<button class="sign-up">Sign Up</button>
{#if controlsEnabled}
<span class="with-sep" transition:fade={{ duration: 100 }}>or sign up with</span>
<div class="oauth-btns" transition:fade={{ duration: 100 }}>
{#each objectKeys($state.controls).filter((p) => $state.controls[p]) as provider (provider)}
<button class="oauth" transition:fade={{ duration: 100 }} animate:flip={{ duration: 250 }}>
<div class="inner">
<span class="web-icon-{provider.toLowerCase()}" />
<span>{provider}</span>
</div>
</button>
{/each}
</div>
{/if}
<div data-theme-ignore class="inner-phone light">
<p class="title">Create an Account</p>
<p class="subtitle">Please enter your details</p>
<div class="inputs">
<fieldset>
<label for="name">Your Name</label>
<input type="name" id="name" placeholder="Enter your name" bind:value={$state.name} />
</fieldset>
<fieldset>
<label for="email">Your Email</label>
<input
type="email"
id="email"
placeholder="Enter your email"
bind:value={$state.email}
/>
</fieldset>
<fieldset>
<label for="password">Create Password</label>
<input
type="password"
id="password"
placeholder="Enter Password"
bind:value={$state.password}
/>
</fieldset>
</div>
<button class="sign-up">Sign Up</button>
{#if controlsEnabled}
<span class="with-sep" transition:fade={{ duration: 100 }}>or sign up with</span>
<div class="oauth-btns" transition:fade={{ duration: 100 }}>
{#each objectKeys($state.controls).filter((p) => $state.controls[p]) as provider (provider)}
<button
class="oauth"
transition:fade={{ duration: 100 }}
animate:flip={{ duration: 250 }}
>
<div class="inner">
<span class="web-icon-{provider.toLowerCase()}" />
<span>{provider}</span>
</div>
</button>
{/each}
</div>
{/if}
</div>
<style lang="scss">
.inner-phone {
padding-block: 3rem;
padding-inline: 1rem;
.inner-phone {
padding-block: 3rem;
padding-inline: 1rem;
color: rgba(67, 67, 71, 1);
text-align: left;
color: rgba(67, 67, 71, 1);
text-align: left;
.title {
color: #434347;
font-family: Inter;
font-size: 16px;
font-style: normal;
font-weight: 600;
line-height: 22px; /* 137.5% */
letter-spacing: -0.224px;
}
.title {
color: #434347;
font-family: Inter;
font-size: 16px;
font-style: normal;
font-weight: 600;
line-height: 22px; /* 137.5% */
letter-spacing: -0.224px;
}
.subtitle {
color: var(--greyscale-700, var(--color-greyscale-700, #56565c));
font-family: Inter;
font-size: 14px;
font-style: normal;
font-weight: 400;
line-height: 20px; /* 142.857% */
letter-spacing: -0.196px;
}
.subtitle {
color: var(--greyscale-700, var(--color-greyscale-700, #56565c));
font-family: Inter;
font-size: 14px;
font-style: normal;
font-weight: 400;
line-height: 20px; /* 142.857% */
letter-spacing: -0.196px;
}
.inputs {
display: flex;
flex-direction: column;
gap: 0.75rem;
margin-block-start: 1.5rem;
.inputs {
display: flex;
flex-direction: column;
gap: 0.75rem;
margin-block-start: 1.5rem;
fieldset {
display: flex;
flex-direction: column;
gap: 0.3125rem;
width: 100%;
fieldset {
display: flex;
flex-direction: column;
gap: 0.3125rem;
width: 100%;
label {
color: var(--color-greyscale-700, #56565c);
font-family: Inter;
font-size: 12px;
font-style: normal;
font-weight: 400;
line-height: 16px; /* 133.333% */
letter-spacing: -0.168px;
}
label {
color: var(--color-greyscale-700, #56565c);
font-family: Inter;
font-size: 12px;
font-style: normal;
font-weight: 400;
line-height: 16px; /* 133.333% */
letter-spacing: -0.168px;
}
input {
all: unset;
display: flex;
padding: 8px 12px;
align-items: flex-start;
align-self: stretch;
border-radius: 8px;
border: 1px solid #d8d8db;
input {
all: unset;
display: flex;
padding: 8px 12px;
align-items: flex-start;
align-self: stretch;
border-radius: 8px;
border: 1px solid #d8d8db;
color: #434347;
font-family: Inter;
font-size: 12px;
font-style: normal;
font-weight: 400;
line-height: 16px; /* 133.333% */
letter-spacing: -0.168px;
}
}
}
color: #434347;
font-family: Inter;
font-size: 12px;
font-style: normal;
font-weight: 400;
line-height: 16px; /* 133.333% */
letter-spacing: -0.168px;
}
}
}
.sign-up {
padding: 0.375rem 0.75rem;
text-align: center;
width: 100%;
margin-block-start: 1.25rem;
.sign-up {
padding: 0.375rem 0.75rem;
text-align: center;
width: 100%;
margin-block-start: 1.25rem;
border-radius: 0.5rem;
background: var(--appwrite-purple, #7c67fe);
box-shadow: 0px 4px 8px 0px rgba(0, 0, 0, 0.06);
border-radius: 0.5rem;
background: var(--appwrite-purple, #7c67fe);
box-shadow: 0px 4px 8px 0px rgba(0, 0, 0, 0.06);
color: var(--color-bw-white, #fff);
text-align: center;
color: var(--color-bw-white, #fff);
text-align: center;
/* Responsive/SubBody-500 */
font-family: Inter;
font-size: 14px;
font-style: normal;
font-weight: 500;
line-height: 22px; /* 157.143% */
letter-spacing: -0.07px;
}
/* Responsive/SubBody-500 */
font-family: Inter;
font-size: 14px;
font-style: normal;
font-weight: 500;
line-height: 22px; /* 157.143% */
letter-spacing: -0.07px;
}
.with-sep {
display: flex;
align-items: center;
justify-content: space-between;
gap: 1rem;
.with-sep {
display: flex;
align-items: center;
justify-content: space-between;
gap: 1rem;
font-family: Inter;
font-size: 0.75rem;
font-style: normal;
font-weight: 400;
line-height: 1.25rem; /* 166.667% */
letter-spacing: -0.0105rem;
color: hsl(var(--web-color-greyscale-500));
font-family: Inter;
font-size: 0.75rem;
font-style: normal;
font-weight: 400;
line-height: 1.25rem; /* 166.667% */
letter-spacing: -0.0105rem;
color: hsl(var(--web-color-greyscale-500));
margin-block-start: 0.75rem;
margin-block-start: 0.75rem;
&::before,
&::after {
content: '';
height: 1px;
flex-grow: 1;
background-color: hsl(var(--web-color-greyscale-200));
}
}
&::before,
&::after {
content: '';
height: 1px;
flex-grow: 1;
background-color: hsl(var(--web-color-greyscale-200));
}
}
.oauth-btns {
--gap: 0.5rem;
display: flex;
flex-wrap: wrap;
gap: var(--gap);
margin-block-start: 0.75rem;
}
.oauth-btns {
--gap: 0.5rem;
display: flex;
flex-wrap: wrap;
gap: var(--gap);
margin-block-start: 0.75rem;
}
.oauth {
display: flex;
justify-content: center;
align-items: center;
.oauth {
display: flex;
justify-content: center;
align-items: center;
border-radius: 0.5rem;
border: 1px solid #d9d9d9;
color: hsl(var(--web-color-greyscale-750));
text-align: center;
border-radius: 0.5rem;
border: 1px solid #d9d9d9;
color: hsl(var(--web-color-greyscale-750));
text-align: center;
/* Responsive/Caption-500 */
font-family: Inter;
font-size: 0.875rem;
font-style: normal;
font-weight: 500;
line-height: 1.375rem; /* 157.143% */
letter-spacing: -0.01575rem;
/* Responsive/Caption-500 */
font-family: Inter;
font-size: 0.875rem;
font-style: normal;
font-weight: 500;
line-height: 1.375rem; /* 157.143% */
letter-spacing: -0.01575rem;
flex: 1 1 calc(50% - var(--gap));
padding-block: 0.375rem;
position: relative;
height: 2.125rem;
flex: 1 1 calc(50% - var(--gap));
padding-block: 0.375rem;
position: relative;
height: 2.125rem;
.inner {
position: absolute;
left: 50%;
top: 50%;
.inner {
position: absolute;
left: 50%;
top: 50%;
display: flex;
justify-content: center;
align-items: center;
gap: 0.5rem;
transform: translate(-50%, -50%) scale(var(--inverse-sx, 1), var(--inverse-sy, 1));
}
}
}
display: flex;
justify-content: center;
align-items: center;
gap: 0.5rem;
transform: translate(-50%, -50%) scale(var(--inverse-sx, 1), var(--inverse-sy, 1));
}
}
}
</style>

View File

@@ -1,54 +1,54 @@
<script lang="ts">
import { slide } from 'svelte/transition';
import { databasesController } from '.';
import { flip } from '$lib/utils/flip';
import { slide } from 'svelte/transition';
import { databasesController } from '.';
import { flip } from '$lib/utils/flip';
const { state } = databasesController;
const { state } = databasesController;
</script>
<div class="pseudo-table">
<div class="header">
<span class="web-eyebrow">Document ID</span>
<span class="web-eyebrow">Task</span>
</div>
{#each $state.tasks.slice(0, $state.tableSlice) as task (task.id)}
<div class="row" transition:slide={{ duration: 150 }} animate:flip={{ duration: 150 }}>
<div class="copy-button">
<span class="web-icon-copy" />
<span>{task.id}</span>
</div>
<span class="truncated">{task.title}</span>
</div>
{/each}
<div class="header">
<span class="web-eyebrow">Document ID</span>
<span class="web-eyebrow">Task</span>
</div>
{#each $state.tasks.slice(0, $state.tableSlice) as task (task.id)}
<div class="row" transition:slide={{ duration: 150 }} animate:flip={{ duration: 150 }}>
<div class="copy-button">
<span class="web-icon-copy" />
<span>{task.id}</span>
</div>
<span class="truncated">{task.title}</span>
</div>
{/each}
</div>
<style lang="scss">
.copy-button {
display: flex;
padding: 0.25rem 0.5rem;
align-items: center;
gap: 0.375rem;
.copy-button {
display: flex;
padding: 0.25rem 0.5rem;
align-items: center;
gap: 0.375rem;
border-radius: 62.4375rem;
border: 1px solid rgba(255, 255, 255, 0.08);
background: rgba(255, 255, 255, 0.04);
backdrop-filter: blur(2.6666667461395264px);
border-radius: 62.4375rem;
border: 1px solid rgba(255, 255, 255, 0.08);
background: rgba(255, 255, 255, 0.04);
backdrop-filter: blur(2.6666667461395264px);
[class*='icon-'] {
font-size: 1.25rem;
color: hsl(var(--web-color-greyscale-600));
}
[class*='icon-'] {
font-size: 1.25rem;
color: hsl(var(--web-color-greyscale-600));
}
span:not([class*='icon-']) {
color: var(--greyscale-400, #adadb1);
font-family: Inter;
font-size: 0.875rem;
font-style: normal;
font-weight: 400;
line-height: 1.25rem; /* 142.857% */
span:not([class*='icon-']) {
color: var(--greyscale-400, #adadb1);
font-family: Inter;
font-size: 0.875rem;
font-style: normal;
font-weight: 400;
line-height: 1.25rem; /* 142.857% */
overflow: hidden;
text-overflow: ellipsis;
}
}
overflow: hidden;
text-overflow: ellipsis;
}
}
</style>

View File

@@ -1,7 +1,7 @@
<script lang="ts">
import Code from '$lib/animations/CodeWindow/Code.svelte';
import Code from '$lib/animations/CodeWindow/Code.svelte';
let content = `
let content = `
const result = databases.createDocument(
'Your-tasks',
tasks,

View File

@@ -7,88 +7,88 @@ import { createResettable } from '$lib/utils/resettable';
import { getElSelector } from '../Products.svelte';
type Task = {
id: string;
title: string;
checked: boolean;
id: string;
title: string;
checked: boolean;
};
type State = {
tasks: Task[];
tableSlice: number;
tasks: Task[];
tableSlice: number;
};
const state = createResettable<State>({
tasks: [
{
id: '3397fecdedb13397fecdedb1',
title: 'Research user needs',
checked: true
}
],
tableSlice: 1
tasks: [
{
id: '3397fecdedb13397fecdedb1',
title: 'Research user needs',
checked: true
}
],
tableSlice: 1
});
const execute = async () => {
const phone = getElSelector('phone');
const box = getElSelector('box');
const code = getElSelector('code');
const { update } = state.reset();
const phone = getElSelector('phone');
const box = getElSelector('box');
const code = getElSelector('code');
const { update } = state.reset();
await Promise.all([
safeAnimate(phone, { x: 390, y: 0 }, { duration: 0.5 })?.finished,
safeAnimate(box, { x: 0, y: 32, opacity: 1 }, { duration: 0.5 })?.finished,
safeAnimate(code, { x: 80, y: 320, opacity: 1 }, { duration: 0.5 })?.finished
]);
await Promise.all([
safeAnimate(phone, { x: 390, y: 0 }, { duration: 0.5 })?.finished,
safeAnimate(box, { x: 0, y: 32, opacity: 1 }, { duration: 0.5 })?.finished,
safeAnimate(code, { x: 80, y: 320, opacity: 1 }, { duration: 0.5 })?.finished
]);
await sleep(250);
await sleep(250);
update((p) => ({
...p,
tasks: [
...p.tasks,
{
id: '3397fecdedb13397fecdedb2',
title: 'Create wireframes',
checked: false
}
]
}));
await sleep(250);
update((p) => ({
...p,
tasks: [
...p.tasks,
{
id: '3397fecdedb13397fecdedb2',
title: 'Create wireframes',
checked: false
}
]
}));
await sleep(250);
update((p) => ({
...p,
tableSlice: p.tableSlice + 1
}));
update((p) => ({
...p,
tableSlice: p.tableSlice + 1
}));
await sleep(250);
await sleep(250);
update((p) => ({
...p,
tasks: [
...p.tasks,
{
id: '3397fecdedb13397fecdedb3',
title: 'Create visual design',
checked: false
}
]
}));
update((p) => ({
...p,
tasks: [
...p.tasks,
{
id: '3397fecdedb13397fecdedb3',
title: 'Create visual design',
checked: false
}
]
}));
await sleep(250);
await sleep(250);
update((p) => ({
...p,
tableSlice: p.tableSlice + 1
}));
update((p) => ({
...p,
tableSlice: p.tableSlice + 1
}));
};
export const databasesController = {
execute,
state
execute,
state
};
export const Databases = {
Phone,
Box,
Code
Phone,
Box,
Code
};

View File

@@ -1,127 +1,127 @@
<script lang="ts">
import { fly } from 'svelte/transition';
import { databasesController } from '.';
import TaskCheckbox from '../TaskCheckbox.svelte';
import { fly } from 'svelte/transition';
import { databasesController } from '.';
import TaskCheckbox from '../TaskCheckbox.svelte';
const { state } = databasesController;
const { state } = databasesController;
</script>
<div data-theme-ignore class="inner-phone theme-light">
<div class="header">
<p class="title">Your tasks</p>
<span class="icon-menu" aria-label="menu" />
</div>
<div data-theme-ignore class="inner-phone light">
<div class="header">
<p class="title">Your tasks</p>
<span class="icon-menu" aria-label="menu" />
</div>
<div class="date">Today</div>
<div class="tasks">
{#each $state.tasks as task (task.id)}
<div class="task" data-checked={task.checked ? '' : undefined} in:fly={{ x: -16 }}>
<TaskCheckbox bind:checked={task.checked} />
<span class="title">{task.title}</span>
</div>
{/each}
</div>
<div class="date">Today</div>
<div class="tasks">
{#each $state.tasks as task (task.id)}
<div class="task" data-checked={task.checked ? '' : undefined} in:fly={{ x: -16 }}>
<TaskCheckbox bind:checked={task.checked} />
<span class="title">{task.title}</span>
</div>
{/each}
</div>
<button class="add-btn">
<span class="web-icon-plus" />
</button>
<button class="add-btn">
<span class="web-icon-plus" />
</button>
</div>
<style lang="scss">
.inner-phone {
padding-block: 3rem;
padding-inline: 1rem;
.inner-phone {
padding-block: 3rem;
padding-inline: 1rem;
color: rgba(67, 67, 71, 1);
text-align: left;
color: rgba(67, 67, 71, 1);
text-align: left;
position: relative;
height: 100%;
position: relative;
height: 100%;
.header {
display: flex;
justify-content: space-between;
align-items: center;
.header {
display: flex;
justify-content: space-between;
align-items: center;
.title {
color: var(--color-greyscale-800, #2d2d31);
font-family: Inter;
font-size: 1rem;
font-style: normal;
font-weight: 600;
line-height: 1.375rem; /* 137.5% */
letter-spacing: -0.014rem;
}
.title {
color: var(--color-greyscale-800, #2d2d31);
font-family: Inter;
font-size: 1rem;
font-style: normal;
font-weight: 600;
line-height: 1.375rem; /* 137.5% */
letter-spacing: -0.014rem;
}
[class*='icon-'] {
font-size: 1.25rem;
color: hsl(var(--web-color-greyscale-500));
}
}
[class*='icon-'] {
font-size: 1.25rem;
color: hsl(var(--web-color-greyscale-500));
}
}
.date {
margin-block-start: 3rem;
.date {
margin-block-start: 3rem;
color: hsl(var(--web-color-greyscale-600));
font-family: Inter;
font-size: 0.75rem;
font-style: normal;
font-weight: 500;
line-height: 1.25rem; /* 166.667% */
}
color: hsl(var(--web-color-greyscale-600));
font-family: Inter;
font-size: 0.75rem;
font-style: normal;
font-weight: 500;
line-height: 1.25rem; /* 166.667% */
}
.tasks {
margin-block-start: 0.5rem;
.tasks {
margin-block-start: 0.5rem;
display: flex;
flex-direction: column;
gap: 0.5rem;
display: flex;
flex-direction: column;
gap: 0.5rem;
.task {
display: flex;
align-items: center;
gap: 0.75rem;
.task {
display: flex;
align-items: center;
gap: 0.75rem;
border-radius: 0.5rem;
border: 1px solid hsl(var(--web-color-greyscale-50));
background: hsl(var(--web-color-white));
color: var(--greyscale-700, var(--color-greyscale-700, #56565c));
border-radius: 0.5rem;
border: 1px solid hsl(var(--web-color-greyscale-50));
background: hsl(var(--web-color-white));
color: var(--greyscale-700, var(--color-greyscale-700, #56565c));
padding-block: 0.55rem;
padding-inline: 0.88rem;
padding-block: 0.55rem;
padding-inline: 0.88rem;
/* Responsive/SubBody-400 */
font-family: Inter;
font-size: 0.875rem;
font-style: normal;
font-weight: 400;
line-height: 1.375rem; /* 157.143% */
letter-spacing: -0.00394rem;
/* Responsive/SubBody-400 */
font-family: Inter;
font-size: 0.875rem;
font-style: normal;
font-weight: 400;
line-height: 1.375rem; /* 157.143% */
letter-spacing: -0.00394rem;
transition: opacity 200ms ease;
transition: opacity 200ms ease;
&[data-checked] {
opacity: 0.6;
}
}
}
&[data-checked] {
opacity: 0.6;
}
}
}
.add-btn {
position: absolute;
right: 1rem;
bottom: 2.5rem;
.add-btn {
position: absolute;
right: 1rem;
bottom: 2.5rem;
width: 2.5rem;
height: 2.5rem;
flex-shrink: 0;
box-shadow: 0px 2px 6px 0px rgba(0, 0, 0, 0.12);
background-color: rgba(124, 103, 254, 1);
color: rgba(237, 237, 240, 1);
font-size: 1.5rem;
width: 2.5rem;
height: 2.5rem;
flex-shrink: 0;
box-shadow: 0px 2px 6px 0px rgba(0, 0, 0, 0.12);
background-color: rgba(124, 103, 254, 1);
color: rgba(237, 237, 240, 1);
font-size: 1.5rem;
display: grid;
place-items: center;
border-radius: 100%;
}
}
display: grid;
place-items: center;
border-radius: 100%;
}
}
</style>

View File

@@ -1,10 +1,10 @@
<script lang="ts">
import { portal } from '$lib/actions';
import Code from '$lib/animations/CodeWindow/Code.svelte';
import { fade } from 'svelte/transition';
import { functionsController } from '.';
import { portal } from '$lib/actions';
import Code from '$lib/animations/CodeWindow/Code.svelte';
import { fade } from 'svelte/transition';
import { functionsController } from '.';
let content = `
let content = `
const userId = req.headers['user-id'];
if (req.path === '/subscribe') {
@@ -18,39 +18,39 @@ if (req.path === '/webhook') {
return res.json({ success: true });`.trim();
const { state } = functionsController;
const { state } = functionsController;
</script>
<Code {content} />
<div use:portal={{ target: '#code-bottom' }} class="bottom">
{#if $state.submit !== 'idle'}
<span class="web-icon-github" in:fade />
{/if}
{#if $state.submit === 'loading'}
<span in:fade>Pushing to GitHub...</span>
<div class="loader is-small" in:fade />
{:else if $state.submit === 'success'}
<span>Deployed to Appwrite Cloud</span>
<span class="web-icon-check" />
{/if}
{#if $state.submit !== 'idle'}
<span class="web-icon-github" in:fade />
{/if}
{#if $state.submit === 'loading'}
<span in:fade>Pushing to GitHub...</span>
<div class="loader is-small" in:fade />
{:else if $state.submit === 'success'}
<span>Deployed to Appwrite Cloud</span>
<span class="web-icon-check" />
{/if}
</div>
<style lang="scss">
.bottom {
display: flex;
align-items: center;
gap: 0.5rem;
.bottom {
display: flex;
align-items: center;
gap: 0.5rem;
height: 3rem;
padding-inline: 1rem;
height: 3rem;
padding-inline: 1rem;
color: var(--color-bw-white, #fff);
font-family: Inter;
font-size: 0.875rem;
font-style: normal;
font-weight: 400;
line-height: 150%; /* 1.3125rem */
letter-spacing: -0.00875rem;
}
color: var(--color-bw-white, #fff);
font-family: Inter;
font-size: 0.875rem;
font-style: normal;
font-weight: 400;
line-height: 150%; /* 1.3125rem */
letter-spacing: -0.00875rem;
}
</style>

View File

@@ -6,53 +6,53 @@ import { createResettable } from '$lib/utils/resettable';
import { getElSelector } from '../Products.svelte';
type State = {
submit: 'idle' | 'loading' | 'success';
submit: 'idle' | 'loading' | 'success';
};
const state = createResettable<State>({
submit: 'idle'
submit: 'idle'
});
const execute = async () => {
const phone = getElSelector('phone');
const box = getElSelector('box');
const code = getElSelector('code');
const phone = getElSelector('phone');
const box = getElSelector('box');
const code = getElSelector('code');
const { update } = state.reset();
const { update } = state.reset();
await Promise.all([
safeAnimate(phone, { x: 430, y: 0, width: '275px' }, { duration: 0.5 })?.finished,
safeAnimate(code, { x: 0, y: 200, opacity: 0 }, { duration: 0.5 })?.finished,
safeAnimate(box, { opacity: 0 }, { duration: 0.5 })?.finished
]);
await Promise.all([
safeAnimate(phone, { x: 430, y: 0, width: '275px' }, { duration: 0.5 })?.finished,
safeAnimate(code, { x: 0, y: 200, opacity: 0 }, { duration: 0.5 })?.finished,
safeAnimate(box, { opacity: 0 }, { duration: 0.5 })?.finished
]);
await sleep(250);
await sleep(250);
await safeAnimate(code, { zIndex: 0 }, { duration: 0 })?.finished;
await safeAnimate(code, { y: [200 - 16, 200], opacity: 1 }, { duration: 0.5 })?.finished;
await safeAnimate(code, { zIndex: 0 }, { duration: 0 })?.finished;
await safeAnimate(code, { y: [200 - 16, 200], opacity: 1 }, { duration: 0.5 })?.finished;
await sleep(250);
await sleep(250);
update((p) => ({
...p,
submit: 'loading'
}));
update((p) => ({
...p,
submit: 'loading'
}));
await sleep(1500);
await sleep(1500);
update((p) => ({
...p,
submit: 'success'
}));
update((p) => ({
...p,
submit: 'success'
}));
};
export const functionsController = {
execute,
state
execute,
state
};
export const Functions = {
Phone,
Phone,
Code
Code
};

View File

@@ -1,325 +1,325 @@
<script lang="ts">
import { flip } from '$lib/utils/flip';
import { crossfade, scale, slide } from 'svelte/transition';
import { functionsController } from '.';
import { flip } from '$lib/utils/flip';
import { crossfade, scale, slide } from 'svelte/transition';
import { functionsController } from '.';
const { state } = functionsController;
const { state } = functionsController;
type Method = {
icon: string;
label: string;
};
type Method = {
icon: string;
label: string;
};
$: methods = [
$state.submit === 'success' && {
icon: '/images/animations/stripe.png',
label: 'Stripe'
},
{
icon: '/images/animations/credit-card.svg',
label: 'Card'
},
{
icon: '/images/animations/paypal.svg',
label: 'PayPal'
},
{
icon: '/images/animations/apple.svg',
label: 'Apple'
}
].filter(Boolean) as Method[];
$: methods = [
$state.submit === 'success' && {
icon: '/images/animations/stripe.png',
label: 'Stripe'
},
{
icon: '/images/animations/credit-card.svg',
label: 'Card'
},
{
icon: '/images/animations/paypal.svg',
label: 'PayPal'
},
{
icon: '/images/animations/apple.svg',
label: 'Apple'
}
].filter(Boolean) as Method[];
</script>
<div data-theme-ignore class="inner-phone theme-light">
<div class="header">
<p class="title">Upgrade plan</p>
<span class="icon-menu" aria-label="menu" />
</div>
<div data-theme-ignore class="inner-phone light">
<div class="header">
<p class="title">Upgrade plan</p>
<span class="icon-menu" aria-label="menu" />
</div>
<div class="plan">
<p class="title">Premium plan</p>
<div class="subscription">
<p class="price">$20</p>
<p class="period">/month</p>
</div>
<ul>
<li>Premium plan</li>
<li>Premium plan</li>
<li>Premium plan</li>
</ul>
</div>
<div class="plan">
<p class="title">Premium plan</p>
<div class="subscription">
<p class="price">$20</p>
<p class="period">/month</p>
</div>
<ul>
<li>Premium plan</li>
<li>Premium plan</li>
<li>Premium plan</li>
</ul>
</div>
<ul class="methods">
{#each methods as method, i (method.label)}
<li
in:scale={{ delay: 150 }}
animate:flip={{ duration: 500 }}
data-active={i == 0 ? '' : undefined}
>
<img src={method.icon} alt="" />
<p>{method.label}</p>
</li>
{/each}
</ul>
<ul class="methods">
{#each methods as method, i (method.label)}
<li
in:scale={{ delay: 150 }}
animate:flip={{ duration: 500 }}
data-active={i == 0 ? '' : undefined}
>
<img src={method.icon} alt="" />
<p>{method.label}</p>
</li>
{/each}
</ul>
{#if $state.submit !== 'success'}
<div class="form">
<p>Card information</p>
<div class="bordered">
<div>
<p>placeholder</p>
<img src="/images/animations/visa.png" alt="" />
<img src="/images/animations/mastercard.png" alt="" />
</div>
<div>
<p>MM/YY</p>
<p>CVV</p>
</div>
</div>
</div>
{/if}
{#if $state.submit !== 'success'}
<div class="form">
<p>Card information</p>
<div class="bordered">
<div>
<p>placeholder</p>
<img src="/images/animations/visa.png" alt="" />
<img src="/images/animations/mastercard.png" alt="" />
</div>
<div>
<p>MM/YY</p>
<p>CVV</p>
</div>
</div>
</div>
{/if}
<button>
Pay $20.00
{#if $state.submit === 'success'}
<span in:slide={{ axis: 'x' }}>on Stripe</span>
{/if}
</button>
<button>
Pay $20.00
{#if $state.submit === 'success'}
<span in:slide={{ axis: 'x' }}>on Stripe</span>
{/if}
</button>
</div>
<style lang="scss">
.inner-phone {
padding-block: 3rem 1.5rem;
padding-inline: 1rem;
.inner-phone {
padding-block: 3rem 1.5rem;
padding-inline: 1rem;
color: rgba(67, 67, 71, 1);
text-align: left;
color: rgba(67, 67, 71, 1);
text-align: left;
position: relative;
height: 100%;
overflow: visible;
position: relative;
height: 100%;
overflow: visible;
display: flex;
flex-direction: column;
display: flex;
flex-direction: column;
.header {
display: flex;
justify-content: space-between;
align-items: center;
.header {
display: flex;
justify-content: space-between;
align-items: center;
.title {
color: #434347;
font-family: Inter;
font-size: 1rem;
font-style: normal;
font-weight: 600;
line-height: 1.375rem; /* 137.5% */
letter-spacing: -0.014rem;
}
.title {
color: #434347;
font-family: Inter;
font-size: 1rem;
font-style: normal;
font-weight: 600;
line-height: 1.375rem; /* 137.5% */
letter-spacing: -0.014rem;
}
[class*='icon-'] {
font-size: 1.25rem;
color: hsl(var(--web-color-greyscale-500));
}
}
[class*='icon-'] {
font-size: 1.25rem;
color: hsl(var(--web-color-greyscale-500));
}
}
.plan {
display: flex;
padding: 0.75rem 1rem;
flex-direction: column;
justify-content: center;
align-items: flex-start;
.plan {
display: flex;
padding: 0.75rem 1rem;
flex-direction: column;
justify-content: center;
align-items: flex-start;
border-radius: 0.75rem;
background: rgba(237, 237, 240, 0.5);
border-radius: 0.75rem;
background: rgba(237, 237, 240, 0.5);
margin-block-start: 1rem;
margin-block-start: 1rem;
.title {
color: var(--color-greyscale-700, #56565c);
font-family: Inter;
font-size: 0.75rem;
font-style: normal;
font-weight: 700;
line-height: 1.25rem; /* 166.667% */
}
.title {
color: var(--color-greyscale-700, #56565c);
font-family: Inter;
font-size: 0.75rem;
font-style: normal;
font-weight: 700;
line-height: 1.25rem; /* 166.667% */
}
.subscription {
display: flex;
align-items: baseline;
margin-block-start: 0.15rem;
.subscription {
display: flex;
align-items: baseline;
margin-block-start: 0.15rem;
.price {
color: var(--greyscale-700, var(--color-greyscale-700, #56565c));
font-family: Inter;
font-size: 1.125rem;
font-style: normal;
font-weight: 700;
line-height: 1.25rem; /* 111.111% */
}
.price {
color: var(--greyscale-700, var(--color-greyscale-700, #56565c));
font-family: Inter;
font-size: 1.125rem;
font-style: normal;
font-weight: 700;
line-height: 1.25rem; /* 111.111% */
}
.period {
color: var(--greyscale-700, var(--color-greyscale-700, #56565c));
font-family: Inter;
font-size: 0.75rem;
font-style: normal;
font-weight: 400;
line-height: 1.25rem;
}
}
.period {
color: var(--greyscale-700, var(--color-greyscale-700, #56565c));
font-family: Inter;
font-size: 0.75rem;
font-style: normal;
font-weight: 400;
line-height: 1.25rem;
}
}
ul {
display: flex;
flex-direction: column;
gap: 0.125rem;
margin-block-start: 0.75rem;
ul {
display: flex;
flex-direction: column;
gap: 0.125rem;
margin-block-start: 0.75rem;
li {
color: var(--color-greyscale-500, #818186);
font-family: Inter;
font-size: 0.75rem;
font-style: normal;
font-weight: 400;
line-height: 1.25rem; /* 166.667% */
li {
color: var(--color-greyscale-500, #818186);
font-family: Inter;
font-size: 0.75rem;
font-style: normal;
font-weight: 400;
line-height: 1.25rem; /* 166.667% */
padding-inline-start: 1.5rem;
padding-inline-start: 1.5rem;
position: relative;
position: relative;
&::before {
content: '';
display: block;
position: absolute;
left: 0;
width: 1rem;
height: 1rem;
top: 50%;
transform: translateY(-50%);
&::before {
content: '';
display: block;
position: absolute;
left: 0;
width: 1rem;
height: 1rem;
top: 50%;
transform: translateY(-50%);
background-image: url('/images/animations/check-circle.svg');
}
}
}
}
background-image: url('/images/animations/check-circle.svg');
}
}
}
}
.methods {
margin-block-start: 1.25rem;
.methods {
margin-block-start: 1.25rem;
display: flex;
gap: 0.75rem;
overflow: hidden;
margin-inline: -1rem;
padding-inline: 1rem;
display: flex;
gap: 0.75rem;
overflow: hidden;
margin-inline: -1rem;
padding-inline: 1rem;
li {
flex-shrink: 0;
li {
flex-shrink: 0;
display: flex;
width: 5.5rem;
padding: 0.75rem 0.75rem 0.625rem 0.75rem;
flex-direction: column;
justify-content: center;
align-items: flex-start;
gap: 0.125rem;
display: flex;
width: 5.5rem;
padding: 0.75rem 0.75rem 0.625rem 0.75rem;
flex-direction: column;
justify-content: center;
align-items: flex-start;
gap: 0.125rem;
border-radius: 0.75rem;
border: 1px solid var(--greyscale-50, #ededf0);
border-radius: 0.75rem;
border: 1px solid var(--greyscale-50, #ededf0);
color: var(--greyscale-700, var(--color-greyscale-700, #56565c));
font-family: Inter;
font-size: 0.75rem;
font-style: normal;
font-weight: 400;
line-height: 1.25rem; /* 166.667% */
color: var(--greyscale-700, var(--color-greyscale-700, #56565c));
font-family: Inter;
font-size: 0.75rem;
font-style: normal;
font-weight: 400;
line-height: 1.25rem; /* 166.667% */
&[data-active] {
border-color: var(--appwrite-purple, #7c67fe);
}
}
}
&[data-active] {
border-color: var(--appwrite-purple, #7c67fe);
}
}
}
.form {
margin-block-start: 1.25rem;
.form {
margin-block-start: 1.25rem;
> p {
color: var(--dark-neutrals-150, #373b4d);
font-family: Inter;
font-size: 0.75rem;
font-style: normal;
font-weight: 400;
line-height: 150%; /* 1.125rem */
}
> p {
color: var(--dark-neutrals-150, #373b4d);
font-family: Inter;
font-size: 0.75rem;
font-style: normal;
font-weight: 400;
line-height: 150%; /* 1.125rem */
}
.bordered {
margin-block-start: 0.25rem;
.bordered {
margin-block-start: 0.25rem;
border-radius: 0.5rem;
border: 1px solid #ededf0;
background: var(--color-bw-white, #fff);
border-radius: 0.5rem;
border: 1px solid #ededf0;
background: var(--color-bw-white, #fff);
> div:first-child {
display: flex;
gap: 0.25rem;
padding: 0.65rem 0.75rem;
border-bottom: 1px solid #ededf0;
> div:first-child {
display: flex;
gap: 0.25rem;
padding: 0.65rem 0.75rem;
border-bottom: 1px solid #ededf0;
> :nth-child(2) {
margin-inline-start: auto;
}
}
> :nth-child(2) {
margin-inline-start: auto;
}
}
> div:nth-child(2) {
display: flex;
> div:nth-child(2) {
display: flex;
> p {
padding: 0.65rem 0.75rem;
}
> p {
padding: 0.65rem 0.75rem;
}
> p:first-child {
flex-grow: 3;
}
> p:first-child {
flex-grow: 3;
}
> p:last-child {
flex-grow: 1;
border-inline-start: 1px solid #ededf0;
}
}
> p:last-child {
flex-grow: 1;
border-inline-start: 1px solid #ededf0;
}
}
p {
color: var(--light-neutrals-50, #c4c6d7);
font-family: Inter;
font-size: 0.75rem;
font-style: normal;
font-weight: 400;
line-height: 150%; /* 1.125rem */
}
}
}
p {
color: var(--light-neutrals-50, #c4c6d7);
font-family: Inter;
font-size: 0.75rem;
font-style: normal;
font-weight: 400;
line-height: 150%; /* 1.125rem */
}
}
}
> button {
display: flex;
text-align: center;
padding: 0.5rem 1rem;
justify-content: center;
align-items: center;
gap: 0.25rem;
> button {
display: flex;
text-align: center;
padding: 0.5rem 1rem;
justify-content: center;
align-items: center;
gap: 0.25rem;
border-radius: 0.5rem;
background: var(--appwrite-purple, #7c67fe);
box-shadow: 0px 4px 8px 0px rgba(0, 0, 0, 0.06);
border-radius: 0.5rem;
background: var(--appwrite-purple, #7c67fe);
box-shadow: 0px 4px 8px 0px rgba(0, 0, 0, 0.06);
color: var(--color-bw-white, #fff);
text-align: center;
font-family: Inter;
font-size: 0.875rem;
font-style: normal;
font-weight: 500;
line-height: 1.375rem; /* 157.143% */
letter-spacing: -0.01225rem;
color: var(--color-bw-white, #fff);
text-align: center;
font-family: Inter;
font-size: 0.875rem;
font-style: normal;
font-weight: 500;
line-height: 1.375rem; /* 157.143% */
letter-spacing: -0.01225rem;
margin-block-start: auto;
margin-block-start: auto;
white-space: nowrap;
}
}
white-space: nowrap;
}
}
</style>

View File

@@ -19,7 +19,7 @@
</div>
{/if}
<div data-theme-ignore class="inner-phone theme-light">
<div data-theme-ignore class="inner-phone light">
<div class="header">
<p class="title">Your tasks</p>
<span class="icon-menu" aria-label="menu" />

View File

@@ -12,42 +12,42 @@ const executions = createResettable(0);
const realtime = createResettable(0);
const execute = async () => {
const phone = getElSelector('phone');
const pd = getElSelector('pd');
const phone = getElSelector('phone');
const pd = getElSelector('pd');
const graphBox = getElSelector('graph-box');
const graphBox = getElSelector('graph-box');
const boxesAndStates = [
{ box: getElSelector('post-auth'), state: authentication.reset() },
{ box: getElSelector('post-storage'), state: storage.reset() },
{ box: getElSelector('post-bandwidth'), state: bandwidth.reset() },
{ box: getElSelector('post-functions'), state: executions.reset() },
{ box: getElSelector('post-databases'), state: databases.reset() },
{ box: getElSelector('post-realtime'), state: realtime.reset() },
{ box: getElSelector('post-requests'), state: requests.reset() }
];
const boxesAndStates = [
{ box: getElSelector('post-auth'), state: authentication.reset() },
{ box: getElSelector('post-storage'), state: storage.reset() },
{ box: getElSelector('post-bandwidth'), state: bandwidth.reset() },
{ box: getElSelector('post-functions'), state: executions.reset() },
{ box: getElSelector('post-databases'), state: databases.reset() },
{ box: getElSelector('post-realtime'), state: realtime.reset() },
{ box: getElSelector('post-requests'), state: requests.reset() }
];
await Promise.all([
safeAnimate(pd, { opacity: 0, y: -16 }, { duration: 0.5 })?.finished,
safeAnimate(graphBox, { opacity: 0, visibility: 'hidden' }, { duration: 0.5 })?.finished,
safeAnimate(phone, { x: '-50%', width: '660px' }, { duration: 1, delay: 0.5 })?.finished
]);
await Promise.all([
safeAnimate(pd, { opacity: 0, y: -16 }, { duration: 0.5 })?.finished,
safeAnimate(graphBox, { opacity: 0, visibility: 'hidden' }, { duration: 0.5 })?.finished,
safeAnimate(phone, { x: '-50%', width: '660px' }, { duration: 1, delay: 0.5 })?.finished
]);
boxesAndStates.forEach(({ box, state }, i) => {
safeAnimate(box, { opacity: 1, y: [1200, 0] }, { duration: 0.5, delay: i * 0.1 })?.finished;
animate(state.set, { duration: 2, delay: (i + 1) * 0.25 });
});
boxesAndStates.forEach(({ box, state }, i) => {
safeAnimate(box, { opacity: 1, y: [1200, 0] }, { duration: 0.5, delay: i * 0.1 })?.finished;
animate(state.set, { duration: 2, delay: (i + 1) * 0.25 });
});
};
export const postController = {
execute,
state: {
requests,
databases,
authentication,
storage,
bandwidth,
executions,
realtime
}
execute,
state: {
requests,
databases,
authentication,
storage,
bandwidth,
executions,
realtime
}
};

View File

@@ -1,297 +1,300 @@
<script lang="ts">
import { toScale } from '$lib/utils/toScale';
import { postController } from '.';
import { elId } from '../Products.svelte';
import { toScale } from '$lib/utils/toScale';
import { postController } from '.';
import { elId } from '../Products.svelte';
const {
state: { authentication, bandwidth, databases, executions, requests, storage, realtime }
} = postController;
const {
state: { authentication, bandwidth, databases, executions, requests, storage, realtime }
} = postController;
const formatK = (num: number) => {
if (num > 999) {
return `${(num / 1000).toFixed(1)}K`;
}
return Math.floor(num);
};
const formatK = (num: number) => {
if (num > 999) {
return `${(num / 1000).toFixed(1)}K`;
}
return Math.floor(num);
};
</script>
<div class="gradient-box auth" id="post-auth-{$elId}">
<div class="u-flex u-cross-center u-gap-8">
<p class="icon-user-group" />
<p class="f-eyebrow">Authentication</p>
</div>
<p class="f-display mbs-16">{formatK(toScale($authentication, [0, 1], [0, 4000]))}</p>
<div class="u-flex u-cross-center justify-between mbs-4">
<p class="f-sub">Users</p>
<p class="f-idk">Sessions: 20K</p>
</div>
<div class="flex u-cross-center gap-2">
<p class="icon-user-group" />
<p class="f-eyebrow">Authentication</p>
</div>
<p class="f-display mbs-16">{formatK(toScale($authentication, [0, 1], [0, 4000]))}</p>
<div class="flex u-cross-center justify-between mbs-4">
<p class="f-sub">Users</p>
<p class="f-idk">Sessions: 20K</p>
</div>
</div>
<div class="gradient-box storage" id="post-storage-{$elId}">
<div class="u-flex u-cross-center u-gap-8">
<p class="icon-folder" />
<p class="f-eyebrow">Storage</p>
</div>
<p class="f-display mbs-16">
{toScale($storage, [0, 1], [0, 8]).toFixed(1)} <span class="f-tiny-display">GB</span>
</p>
<div class="u-flex u-cross-center justify-between mbs-4">
<p class="f-sub">Storage</p>
<p class="f-idk">Buckets: 44</p>
</div>
<div class="flex u-cross-center gap-2">
<p class="icon-folder" />
<p class="f-eyebrow">Storage</p>
</div>
<p class="f-display mbs-16">
{toScale($storage, [0, 1], [0, 8]).toFixed(1)} <span class="f-tiny-display">GB</span>
</p>
<div class="flex u-cross-center justify-between mbs-4">
<p class="f-sub">Storage</p>
<p class="f-idk">Buckets: 44</p>
</div>
</div>
<div class="gradient-box bandwidth" id="post-bandwidth-{$elId}">
<p class="f-display">
{toScale($bandwidth, [0, 1], [0, 1.2]).toFixed(2)} <span class="f-tiny-display">GB</span>
</p>
<p class="f-sub">Bandwidth</p>
<img class="mbs-16" src="./images/animations/bandwidth-graph.svg" alt="" />
<p class="f-display">
{toScale($bandwidth, [0, 1], [0, 1.2]).toFixed(2)} <span class="f-tiny-display">GB</span>
</p>
<p class="f-sub">Bandwidth</p>
<img class="mbs-16" src="./images/animations/bandwidth-graph.svg" alt="" />
</div>
<div class="gradient-box functions" id="post-functions-{$elId}">
<div class="u-flex u-cross-center u-gap-8">
<p class="icon-lightning-bolt" />
<p class="f-eyebrow">Functions</p>
</div>
<p class="f-display mbs-16">{toScale($executions, [0, 1], [0, 846]).toFixed(0)}</p>
<div class="u-flex u-cross-center justify-between mbs-4">
<p class="f-sub">Executions</p>
</div>
<div class="flex u-cross-center gap-2">
<p class="icon-lightning-bolt" />
<p class="f-eyebrow">Functions</p>
</div>
<p class="f-display mbs-16">{toScale($executions, [0, 1], [0, 846]).toFixed(0)}</p>
<div class="flex u-cross-center justify-between mbs-4">
<p class="f-sub">Executions</p>
</div>
</div>
<div class="gradient-box databases" id="post-databases-{$elId}">
<div class="u-flex u-cross-center u-gap-8">
<p class="icon-database" />
<p class="f-eyebrow">Databases</p>
</div>
<p class="f-display mbs-16">{toScale($databases, [0, 1], [0, 8]).toFixed(0)}</p>
<div class="u-flex u-cross-center justify-between mbs-4">
<p class="f-sub">Databases</p>
<p class="f-idk">Documents: 20</p>
</div>
<div class="flex u-cross-center gap-2">
<p class="icon-database" />
<p class="f-eyebrow">Databases</p>
</div>
<p class="f-display mbs-16">{toScale($databases, [0, 1], [0, 8]).toFixed(0)}</p>
<div class="flex u-cross-center justify-between mbs-4">
<p class="f-sub">Databases</p>
<p class="f-idk">Documents: 20</p>
</div>
</div>
<div class="gradient-box requests" id="post-requests-{$elId}">
<p class="f-display">{formatK(toScale($requests, [0, 1], [0, 6849]))}</p>
<p class="f-sub">Requests</p>
<img class="mbs-16" src="./images/animations/requests-graph.svg" alt="" />
<p class="f-display">{formatK(toScale($requests, [0, 1], [0, 6849]))}</p>
<p class="f-sub">Requests</p>
<img class="mbs-16" src="./images/animations/requests-graph.svg" alt="" />
</div>
<div class="gradient-box realtime" id="post-realtime-{$elId}">
<p class="f-display">{formatK(toScale($realtime, [0, 1], [0, 100000]))}</p>
<p class="f-sub">Realtime connections</p>
<img class="mbs-16" src="./images/animations/realtime-graph.svg" alt="" />
<p class="f-display">{formatK(toScale($realtime, [0, 1], [0, 100000]))}</p>
<p class="f-sub">Realtime connections</p>
<img class="mbs-16" src="./images/animations/realtime-graph.svg" alt="" />
</div>
<div class="gradient-overlay u-flex u-flex-vertical">
<h3>See your products grow</h3>
<p>
Keep track of your projects progress on the Appwrite Console and see them grow into products
users love and use every day.
</p>
<div class="gradient-overlay flex u-flex-vertical">
<h3>See your products grow</h3>
<p>
Keep track of your projects progress on the Appwrite Console and see them grow into products
users love and use every day.
</p>
</div>
<style lang="scss">
@use '$scss/abstract/mixins/border-gradient' as gradients;
// Utilities
.f-eyebrow {
color: #adadb0;
/* Eyebrow headings/level 3 */
font-family: Inter;
font-size: 0.75rem;
font-style: normal;
font-weight: 500;
line-height: 150%; /* 1.125rem */
letter-spacing: 0.09rem;
text-transform: uppercase;
}
// Utilities
.f-eyebrow {
color: #adadb0;
/* Eyebrow headings/level 3 */
font-family: Inter;
font-size: 0.75rem;
font-style: normal;
font-weight: 500;
line-height: 150%; /* 1.125rem */
letter-spacing: 0.09rem;
text-transform: uppercase;
}
.f-display {
color: #ededf0;
font-family: Aeonik Pro;
font-size: 2rem;
font-style: normal;
font-weight: 500;
line-height: 2.25rem; /* 112.5% */
}
.f-display {
color: #ededf0;
font-family: Aeonik Pro;
font-size: 2rem;
font-style: normal;
font-weight: 500;
line-height: 2.25rem; /* 112.5% */
}
.f-tiny-display {
color: var(--greyscale-50, #ededf0);
text-align: center;
font-family: Inter;
font-size: 0.875rem;
font-style: normal;
font-weight: 500;
line-height: 1rem; /* 114.286% */
}
.f-tiny-display {
color: var(--greyscale-50, #ededf0);
text-align: center;
font-family: Inter;
font-size: 0.875rem;
font-style: normal;
font-weight: 500;
line-height: 1rem; /* 114.286% */
}
.f-sub {
color: #97979b;
font-family: Inter;
font-size: 0.875rem;
font-style: normal;
font-weight: 400;
line-height: 1.125rem; /* 128.571% */
}
.f-sub {
color: #97979b;
font-family: Inter;
font-size: 0.875rem;
font-style: normal;
font-weight: 400;
line-height: 1.125rem; /* 128.571% */
}
.f-idk {
color: var(--primary, #e4e4e7);
text-align: right;
font-family: Inter;
font-size: 0.875rem;
font-style: normal;
font-weight: 400;
line-height: 150%; /* 1.3125rem */
opacity: 40%;
}
.f-idk {
color: var(--primary, #e4e4e7);
text-align: right;
font-family: Inter;
font-size: 0.875rem;
font-style: normal;
font-weight: 400;
line-height: 150%; /* 1.3125rem */
opacity: 40%;
}
.mbs-16 {
margin-block-start: 1rem;
}
.mbs-16 {
margin-block-start: 1rem;
}
.mbs-4 {
margin-block-start: 0.25rem;
}
.mbs-4 {
margin-block-start: 0.25rem;
}
.justify-between {
justify-content: space-between;
}
.justify-between {
justify-content: space-between;
}
// Components
.gradient-box {
@include gradients.border-gradient;
--m-border-gradient-before: linear-gradient(
180deg,
rgba(255, 255, 255, 0.12) 0%,
rgba(255, 255, 255, 0) 125.11%
);
--m-border-radius: 1rem;
// Components
.gradient-box {
@include gradients.border-gradient;
--m-border-gradient-before: linear-gradient(
180deg,
rgba(255, 255, 255, 0.12) 0%,
rgba(255, 255, 255, 0) 125.11%
);
--m-border-radius: 1rem;
position: absolute;
background: var(--card, rgba(35, 35, 37, 0.9));
box-shadow: 0px 0px 0px 0px rgba(0, 0, 0, 0.06), -2px 4px 9px 0px rgba(0, 0, 0, 0.06),
-8px 15px 17px 0px rgba(0, 0, 0, 0.05), -19px 34px 23px 0px rgba(0, 0, 0, 0.03),
-33px 60px 27px 0px rgba(0, 0, 0, 0.01), -52px 94px 30px 0px rgba(0, 0, 0, 0);
backdrop-filter: blur(8px);
position: absolute;
background: var(--card, rgba(35, 35, 37, 0.9));
box-shadow:
0px 0px 0px 0px rgba(0, 0, 0, 0.06),
-2px 4px 9px 0px rgba(0, 0, 0, 0.06),
-8px 15px 17px 0px rgba(0, 0, 0, 0.05),
-19px 34px 23px 0px rgba(0, 0, 0, 0.03),
-33px 60px 27px 0px rgba(0, 0, 0, 0.01),
-52px 94px 30px 0px rgba(0, 0, 0, 0);
backdrop-filter: blur(8px);
padding: 1.5rem;
padding: 1.5rem;
z-index: 9999;
z-index: 9999;
min-width: 20rem;
}
min-width: 20rem;
}
@keyframes fadeIn {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
@keyframes fadeIn {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
.gradient-overlay {
position: absolute;
z-index: 100;
bottom: -7.5rem;
width: 100%;
height: 30rem;
.gradient-overlay {
position: absolute;
z-index: 100;
bottom: -7.5rem;
width: 100%;
height: 30rem;
display: flex;
flex-direction: column;
align-items: center;
gap: 1.25rem;
display: flex;
flex-direction: column;
align-items: center;
gap: 1.25rem;
padding-block-start: 15rem;
padding-block-start: 15rem;
opacity: 0;
animation: fadeIn 0.75s ease-in-out 1.5s forwards;
opacity: 0;
animation: fadeIn 0.75s ease-in-out 1.5s forwards;
&::before {
content: '';
inset: 0;
position: absolute;
//background: #19191d; // old bg
//filter: blur(125px); // break Safari
background: #19191dcc;
filter: blur(67px);
&::before {
content: '';
inset: 0;
position: absolute;
//background: #19191d; // old bg
//filter: blur(125px); // break Safari
background: #19191dcc;
filter: blur(67px);
}
}
h3 {
position: relative;
color: var(--primary, #e4e4e7);
text-align: center;
h3 {
position: relative;
color: var(--primary, #e4e4e7);
text-align: center;
/* Desktop/Display */
font-family: Aeonik Pro;
font-size: 4rem;
font-style: normal;
font-weight: 400;
line-height: 4.25rem; /* 106.25% */
letter-spacing: -0.04rem;
}
/* Desktop/Display */
font-family: Aeonik Pro;
font-size: 4rem;
font-style: normal;
font-weight: 400;
line-height: 4.25rem; /* 106.25% */
letter-spacing: -0.04rem;
}
p {
position: relative;
p {
position: relative;
color: var(--secondary, #adadb0);
text-align: center;
color: var(--secondary, #adadb0);
text-align: center;
/* Desktop/Description */
font-family: Inter;
font-size: 1.25rem;
font-style: normal;
font-weight: 500;
line-height: 1.75rem; /* 140% */
letter-spacing: -0.0175rem;
max-width: 40rem;
text-align: center;
}
}
/* Desktop/Description */
font-family: Inter;
font-size: 1.25rem;
font-style: normal;
font-weight: 500;
line-height: 1.75rem; /* 140% */
letter-spacing: -0.0175rem;
max-width: 40rem;
text-align: center;
}
}
// Specifics
.auth {
opacity: 0;
left: 4rem;
top: -11rem;
}
// Specifics
.auth {
opacity: 0;
left: 4rem;
top: -11rem;
}
.storage {
opacity: 0;
left: -10rem;
top: -2rem;
}
.storage {
opacity: 0;
left: -10rem;
top: -2rem;
}
.bandwidth {
opacity: 0;
left: -4rem;
top: 11rem;
}
.bandwidth {
opacity: 0;
left: -4rem;
top: 11rem;
}
.functions {
opacity: 0;
left: -6rem;
top: 35rem;
}
.functions {
opacity: 0;
left: -6rem;
top: 35rem;
}
.databases {
opacity: 0;
top: -13rem;
right: 10rem;
}
.databases {
opacity: 0;
top: -13rem;
right: 10rem;
}
.requests {
opacity: 0;
top: 17rem;
right: -18rem;
}
.requests {
opacity: 0;
top: 17rem;
right: -18rem;
}
.realtime {
opacity: 0;
top: -1rem;
right: -7rem;
}
.realtime {
opacity: 0;
top: -1rem;
right: -7rem;
}
</style>

File diff suppressed because it is too large Load Diff

View File

@@ -1,39 +1,39 @@
<script lang="ts">
import { slide } from 'svelte/transition';
import { storageController } from '.';
import { flip } from '$lib/utils/flip';
import { slide } from 'svelte/transition';
import { storageController } from '.';
import { flip } from '$lib/utils/flip';
const { state } = storageController;
const { state } = storageController;
</script>
<div class="pseudo-table">
<div class="header">
<span class="web-eyebrow">Filename</span>
<span class="web-eyebrow">Type</span>
<span class="web-eyebrow">Size</span>
</div>
{#each $state.files as file (file.src)}
<div class="row" in:slide={{ duration: 150 }} animate:flip={{ duration: 150 }}>
<div class="img-wrapper">
<img src={file.src} alt="" />
<span>{file.filename}</span>
</div>
<span class="truncated">{file.type}</span>
<span class="truncated">{file.size}</span>
</div>
{/each}
<div class="header">
<span class="web-eyebrow">Filename</span>
<span class="web-eyebrow">Type</span>
<span class="web-eyebrow">Size</span>
</div>
{#each $state.files as file (file.src)}
<div class="row" in:slide={{ duration: 150 }} animate:flip={{ duration: 150 }}>
<div class="img-wrapper">
<img src={file.src} alt="" />
<span>{file.filename}</span>
</div>
<span class="truncated">{file.type}</span>
<span class="truncated">{file.size}</span>
</div>
{/each}
</div>
<style lang="scss">
.header,
.row {
grid-template-columns: 7rem 1fr 1fr !important;
gap: 1.5rem 3rem;
}
.header,
.row {
grid-template-columns: 7rem 1fr 1fr !important;
gap: 1.5rem 3rem;
}
.img-wrapper {
display: flex;
align-items: center;
gap: 0.5rem;
}
.img-wrapper {
display: flex;
align-items: center;
gap: 0.5rem;
}
</style>

View File

@@ -1,7 +1,7 @@
<script lang="ts">
import Code from '$lib/animations/CodeWindow/Code.svelte';
import Code from '$lib/animations/CodeWindow/Code.svelte';
let content = `
let content = `
const result = storage.createFile(
'my-bucket',
ID.unique(),

View File

@@ -7,130 +7,131 @@ import { createResettable } from '$lib/utils/resettable';
import { getElSelector } from '../Products.svelte';
type File = {
src: string;
filename: string;
type: string;
size: string;
src: string;
filename: string;
type: string;
size: string;
};
type State = {
files: File[];
files: File[];
};
const state = createResettable<State>({
files: []
files: []
});
const execute = async () => {
const phone = getElSelector('phone');
const box = getElSelector('box');
const code = getElSelector('code');
const overlay = getElSelector('overlay');
const drawer = getElSelector('drawer');
const upload = getElSelector('upload');
const uploadBtn = getElSelector('upload-btn');
const uploadImg = getElSelector('upload-img');
const uploadLoading = getElSelector('upload-loading');
const uploadText = getElSelector('upload-text');
const phone = getElSelector('phone');
const box = getElSelector('box');
const code = getElSelector('code');
const overlay = getElSelector('overlay');
const drawer = getElSelector('drawer');
const upload = getElSelector('upload');
const uploadBtn = getElSelector('upload-btn');
const uploadImg = getElSelector('upload-img');
const uploadLoading = getElSelector('upload-loading');
const uploadText = getElSelector('upload-text');
const { update } = state.reset();
const { update } = state.reset();
await Promise.all([
safeAnimate(phone, { x: 0, y: 0 }, { duration: 0.5 })?.finished,
safeAnimate(box, { opacity: 0 }, { duration: 0.5 })?.finished,
safeAnimate(code, { opacity: 0 }, { duration: 0.5 })?.finished,
safeAnimate(uploadLoading, { opacity: 0 }, { duration: 0 })?.finished
]);
await Promise.all([
safeAnimate(phone, { x: 0, y: 0 }, { duration: 0.5 })?.finished,
safeAnimate(box, { opacity: 0 }, { duration: 0.5 })?.finished,
safeAnimate(code, { opacity: 0 }, { duration: 0.5 })?.finished,
safeAnimate(uploadLoading, { opacity: 0 }, { duration: 0 })?.finished
]);
await safeAnimate(code, { zIndex: 20 }, { duration: 0 })?.finished;
await safeAnimate(code, { zIndex: 20 }, { duration: 0 })?.finished;
update((p) => ({
...p,
files: [
...p.files,
{
src: '/images/animations/storage-1.png',
filename: 'Profile.png',
type: 'image/png',
size: '362.6 KB'
}
]
}));
update((p) => ({
...p,
files: [
...p.files,
{
src: '/images/animations/storage-1.png',
filename: 'Profile.png',
type: 'image/png',
size: '362.6 KB'
}
]
}));
await sleep(250);
await sleep(250);
await Promise.all([
safeAnimate(overlay, { opacity: 1 }, { duration: 0.25 })?.finished,
safeAnimate(drawer, { y: [128, 0], opacity: 1 }, { duration: 0.5 })?.finished
]);
await Promise.all([
safeAnimate(overlay, { opacity: 1 }, { duration: 0.25 })?.finished,
safeAnimate(drawer, { y: [128, 0], opacity: 1 }, { duration: 0.5 })?.finished
]);
await sleep(250);
await sleep(250);
await safeAnimate(uploadBtn, { scale: [1, 0.9, 1] }, { duration: 0.25 })?.finished;
await safeAnimate(uploadBtn, { scale: [1, 0.9, 1] }, { duration: 0.25 })?.finished;
await safeAnimate(code, { x: 300, y: 32 }, { duration: 0 })?.finished;
await safeAnimate(code, { x: 300, y: 32 }, { duration: 0 })?.finished;
await Promise.all([
safeAnimate(code, { y: [32 - 16, 32], opacity: 1 }, { duration: 0.5 })?.finished,
safeAnimate(upload, { y: [-16, 0], opacity: 1 }, { duration: 0.5 })?.finished
]);
await Promise.all([
safeAnimate(code, { y: [32 - 16, 32], opacity: 1 }, { duration: 0.5 })?.finished,
safeAnimate(upload, { y: [-16, 0], opacity: 1 }, { duration: 0.5 })?.finished
]);
await sleep(250);
await sleep(250);
await safeAnimate(box, { x: 300, y: 300 }, { duration: 0 })?.finished;
await safeAnimate(box, { x: 300, y: 300 }, { duration: 0 })?.finished;
await Promise.all([
safeAnimate(uploadImg, { x: [64, 48], y: [80, 64], opacity: 1 }, { duration: 0.5 })?.finished,
safeAnimate(box, { y: [300 - 16, 300], opacity: 1 }, { duration: 1 })?.finished
]);
await Promise.all([
safeAnimate(uploadImg, { x: [64, 48], y: [80, 64], opacity: 1 }, { duration: 0.5 })
?.finished,
safeAnimate(box, { y: [300 - 16, 300], opacity: 1 }, { duration: 1 })?.finished
]);
await sleep(250);
await sleep(250);
await Promise.all([
safeAnimate(uploadText, { opacity: 0 }, { duration: 0.5 })?.finished,
safeAnimate(uploadLoading, { opacity: 1 }, { duration: 0.5 })?.finished,
safeAnimate(uploadImg, { opacity: 0, y: 64 + 8 }, { duration: 0.5 })?.finished
]);
await sleep(250);
await Promise.all([
safeAnimate(uploadText, { opacity: 0 }, { duration: 0.5 })?.finished,
safeAnimate(uploadLoading, { opacity: 1 }, { duration: 0.5 })?.finished,
safeAnimate(uploadImg, { opacity: 0, y: 64 + 8 }, { duration: 0.5 })?.finished
]);
await sleep(250);
await safeAnimate(upload, { opacity: 0, y: 48 }, { duration: 0.5 })?.finished;
await safeAnimate(upload, { opacity: 0, y: 48 }, { duration: 0.5 })?.finished;
update((p) => ({
...p,
files: [
...p.files,
{
src: '/images/animations/storage-2.png',
filename: 'Vector.svg',
type: 'vector/svg',
size: '1.5 KB'
}
]
}));
update((p) => ({
...p,
files: [
...p.files,
{
src: '/images/animations/storage-2.png',
filename: 'Vector.svg',
type: 'vector/svg',
size: '1.5 KB'
}
]
}));
await sleep(250);
await sleep(250);
update((p) => ({
...p,
files: [
...p.files,
{
src: '/images/animations/storage-3.png',
filename: 'img2.webp',
type: 'image/webp',
size: '3.2 MB'
}
]
}));
update((p) => ({
...p,
files: [
...p.files,
{
src: '/images/animations/storage-3.png',
filename: 'img2.webp',
type: 'image/webp',
size: '3.2 MB'
}
]
}));
};
export const storageController = {
execute,
state
execute,
state
};
export const Storage = {
Phone,
Box,
Code
Phone,
Box,
Code
};

View File

@@ -1,284 +1,284 @@
<script lang="ts">
import { fly } from 'svelte/transition';
import { storageController } from '.';
import { elId } from '../Products.svelte';
import TaskCheckbox from '../TaskCheckbox.svelte';
import { databasesController } from '../databases';
import { fly } from 'svelte/transition';
import { storageController } from '.';
import { elId } from '../Products.svelte';
import TaskCheckbox from '../TaskCheckbox.svelte';
import { databasesController } from '../databases';
const { state: dbState } = databasesController;
const fixedTasks = $dbState.tasks;
const { state: dbState } = databasesController;
const fixedTasks = $dbState.tasks;
const { state } = storageController;
const { state } = storageController;
</script>
<div data-theme-ignore class="inner-phone theme-light">
<div class="header">
<p class="title">Your tasks</p>
<span class="icon-menu" aria-label="menu" />
</div>
<div data-theme-ignore class="inner-phone light">
<div class="header">
<p class="title">Your tasks</p>
<span class="icon-menu" aria-label="menu" />
</div>
<div class="date">Today</div>
<div class="tasks">
{#each fixedTasks as task (task.id)}
<div class="task" data-checked={task.checked ? '' : undefined} in:fly={{ x: -16 }}>
<TaskCheckbox bind:checked={task.checked} />
<span class="title">{task.title}</span>
</div>
{/each}
</div>
<div class="date">Today</div>
<div class="tasks">
{#each fixedTasks as task (task.id)}
<div class="task" data-checked={task.checked ? '' : undefined} in:fly={{ x: -16 }}>
<TaskCheckbox bind:checked={task.checked} />
<span class="title">{task.title}</span>
</div>
{/each}
</div>
<button class="add-btn">
<span class="web-icon-plus" />
</button>
<button class="add-btn">
<span class="web-icon-plus" />
</button>
<div class="overlay" id="overlay-{$elId}">
<div class="drawer" id="drawer-{$elId}">
<p class="title">Edit images for website</p>
<p class="subtitle">Edit the attached images to use in the website</p>
<div class="overlay" id="overlay-{$elId}">
<div class="drawer" id="drawer-{$elId}">
<p class="title">Edit images for website</p>
<p class="subtitle">Edit the attached images to use in the website</p>
<div class="upload" id="upload-btn-{$elId}">Upload media...</div>
<div class="images">
{#each $state.files.slice(1) as file}
<img src={file.src} alt="" transition:fly={{ x: 16 }} />
{/each}
</div>
</div>
</div>
<div class="upload" id="upload-btn-{$elId}">Upload media...</div>
<div class="images">
{#each $state.files.slice(1) as file}
<img src={file.src} alt="" transition:fly={{ x: 16 }} />
{/each}
</div>
</div>
</div>
</div>
<div class="upload-media" id="upload-{$elId}">
<p class="title">Upload media</p>
<div class="drop-zone">
<span id="upload-text-{$elId}"> Drop media here </span>
<div class="loading-overlay" id="upload-loading-{$elId}">
<div class="loader" />
</div>
</div>
<img id="upload-img-{$elId}" src="/images/animations/storage-2.png" alt="" />
<p class="title">Upload media</p>
<div class="drop-zone">
<span id="upload-text-{$elId}"> Drop media here </span>
<div class="loading-overlay" id="upload-loading-{$elId}">
<div class="loader" />
</div>
</div>
<img id="upload-img-{$elId}" src="/images/animations/storage-2.png" alt="" />
</div>
<style lang="scss">
.inner-phone {
padding-block: 3rem;
padding-inline: 1rem;
.inner-phone {
padding-block: 3rem;
padding-inline: 1rem;
color: rgba(67, 67, 71, 1);
text-align: left;
color: rgba(67, 67, 71, 1);
text-align: left;
position: relative;
height: 100%;
overflow: visible;
position: relative;
height: 100%;
overflow: visible;
.header {
display: flex;
justify-content: space-between;
align-items: center;
.header {
display: flex;
justify-content: space-between;
align-items: center;
.title {
color: var(--color-greyscale-800, #2d2d31);
font-family: Inter;
font-size: 1rem;
font-style: normal;
font-weight: 600;
line-height: 1.375rem; /* 137.5% */
letter-spacing: -0.014rem;
}
.title {
color: var(--color-greyscale-800, #2d2d31);
font-family: Inter;
font-size: 1rem;
font-style: normal;
font-weight: 600;
line-height: 1.375rem; /* 137.5% */
letter-spacing: -0.014rem;
}
[class*='icon-'] {
font-size: 1.25rem;
color: hsl(var(--web-color-greyscale-500));
}
}
[class*='icon-'] {
font-size: 1.25rem;
color: hsl(var(--web-color-greyscale-500));
}
}
.date {
margin-block-start: 3rem;
.date {
margin-block-start: 3rem;
color: hsl(var(--web-color-greyscale-600));
font-family: Inter;
font-size: 0.75rem;
font-style: normal;
font-weight: 500;
line-height: 1.25rem; /* 166.667% */
}
color: hsl(var(--web-color-greyscale-600));
font-family: Inter;
font-size: 0.75rem;
font-style: normal;
font-weight: 500;
line-height: 1.25rem; /* 166.667% */
}
.tasks {
margin-block-start: 0.5rem;
.tasks {
margin-block-start: 0.5rem;
display: flex;
flex-direction: column;
gap: 0.5rem;
display: flex;
flex-direction: column;
gap: 0.5rem;
.task {
display: flex;
align-items: center;
gap: 0.75rem;
.task {
display: flex;
align-items: center;
gap: 0.75rem;
border-radius: 0.5rem;
border: 1px solid hsl(var(--web-color-greyscale-50));
background: hsl(var(--web-color-white));
color: var(--greyscale-700, var(--color-greyscale-700, #56565c));
border-radius: 0.5rem;
border: 1px solid hsl(var(--web-color-greyscale-50));
background: hsl(var(--web-color-white));
color: var(--greyscale-700, var(--color-greyscale-700, #56565c));
padding-block: 0.55rem;
padding-inline: 0.88rem;
padding-block: 0.55rem;
padding-inline: 0.88rem;
/* Responsive/SubBody-400 */
font-family: Inter;
font-size: 0.875rem;
font-style: normal;
font-weight: 400;
line-height: 1.375rem; /* 157.143% */
letter-spacing: -0.00394rem;
/* Responsive/SubBody-400 */
font-family: Inter;
font-size: 0.875rem;
font-style: normal;
font-weight: 400;
line-height: 1.375rem; /* 157.143% */
letter-spacing: -0.00394rem;
transition: opacity 200ms ease;
transition: opacity 200ms ease;
&[data-checked] {
opacity: 0.6;
}
}
}
&[data-checked] {
opacity: 0.6;
}
}
}
.add-btn {
position: absolute;
right: 1rem;
bottom: 2.5rem;
.add-btn {
position: absolute;
right: 1rem;
bottom: 2.5rem;
width: 2.5rem;
height: 2.5rem;
flex-shrink: 0;
box-shadow: 0px 2px 6px 0px rgba(0, 0, 0, 0.12);
background-color: rgba(124, 103, 254, 1);
color: rgba(237, 237, 240, 1);
font-size: 1.5rem;
width: 2.5rem;
height: 2.5rem;
flex-shrink: 0;
box-shadow: 0px 2px 6px 0px rgba(0, 0, 0, 0.12);
background-color: rgba(124, 103, 254, 1);
color: rgba(237, 237, 240, 1);
font-size: 1.5rem;
display: grid;
place-items: center;
border-radius: 100%;
}
}
display: grid;
place-items: center;
border-radius: 100%;
}
}
.overlay {
opacity: 0;
.overlay {
opacity: 0;
position: absolute;
inset: 0;
overflow: hidden;
position: absolute;
inset: 0;
overflow: hidden;
background: rgba(0, 0, 0, 0.32);
border-radius: 2rem;
background: rgba(0, 0, 0, 0.32);
border-radius: 2rem;
.drawer {
position: absolute;
bottom: 0;
height: 60%;
opacity: 0;
.drawer {
position: absolute;
bottom: 0;
height: 60%;
opacity: 0;
background-color: white;
border-radius: 0.88463rem 0.88463rem 2rem 2rem;
background-color: white;
border-radius: 0.88463rem 0.88463rem 2rem 2rem;
padding: 1rem;
padding: 1rem;
.title {
color: #434347;
font-family: Inter;
font-size: 0.88463rem;
font-style: normal;
font-weight: 600;
line-height: 1.21638rem; /* 137.5% */
letter-spacing: -0.01238rem;
}
.title {
color: #434347;
font-family: Inter;
font-size: 0.88463rem;
font-style: normal;
font-weight: 600;
line-height: 1.21638rem; /* 137.5% */
letter-spacing: -0.01238rem;
}
.subtitle {
color: var(--greyscale-500, var(--color-greyscale-500, #818186));
font-family: Inter;
font-size: 0.77406rem;
font-style: normal;
font-weight: 400;
line-height: 1.10575rem; /* 142.857% */
letter-spacing: -0.01081rem;
.subtitle {
color: var(--greyscale-500, var(--color-greyscale-500, #818186));
font-family: Inter;
font-size: 0.77406rem;
font-style: normal;
font-weight: 400;
line-height: 1.10575rem; /* 142.857% */
letter-spacing: -0.01081rem;
margin-block-start: 0.2rem;
}
margin-block-start: 0.2rem;
}
.upload {
display: flex;
padding: 0.44231rem 0.66344rem;
justify-content: center;
align-items: center;
align-self: stretch;
.upload {
display: flex;
padding: 0.44231rem 0.66344rem;
justify-content: center;
align-items: center;
align-self: stretch;
border-radius: 0.66344rem;
border: 1px dashed #d9d9d9;
border-radius: 0.66344rem;
border: 1px dashed #d9d9d9;
color: var(--greyscale-500, var(--color-greyscale-500, #818186));
font-family: Inter;
font-size: 0.77406rem;
font-style: normal;
font-weight: 400;
line-height: 1.10575rem; /* 142.857% */
letter-spacing: -0.01081rem;
color: var(--greyscale-500, var(--color-greyscale-500, #818186));
font-family: Inter;
font-size: 0.77406rem;
font-style: normal;
font-weight: 400;
line-height: 1.10575rem; /* 142.857% */
letter-spacing: -0.01081rem;
margin-block-start: 2rem;
}
}
}
margin-block-start: 2rem;
}
}
}
.upload-media {
position: absolute;
right: calc(0% - 24px);
bottom: 8rem;
background-color: white;
box-shadow: 0px 4px 24px 0px rgba(0, 0, 0, 0.05);
border-radius: 1rem;
padding: 0.75rem;
.upload-media {
position: absolute;
right: calc(0% - 24px);
bottom: 8rem;
background-color: white;
box-shadow: 0px 4px 24px 0px rgba(0, 0, 0, 0.05);
border-radius: 1rem;
padding: 0.75rem;
opacity: 0;
opacity: 0;
.title {
color: var(--color-greyscale-800, #2d2d31);
font-family: Inter;
font-size: 0.85rem;
font-style: normal;
font-weight: 600;
line-height: 1.375rem; /* 137.5% */
letter-spacing: -0.014rem;
}
.title {
color: var(--color-greyscale-800, #2d2d31);
font-family: Inter;
font-size: 0.85rem;
font-style: normal;
font-weight: 600;
line-height: 1.375rem; /* 137.5% */
letter-spacing: -0.014rem;
}
.drop-zone {
display: grid;
place-items: center;
border: 0.885px dashed #d9d9d9;
border-radius: 0.5rem;
.drop-zone {
display: grid;
place-items: center;
border: 0.885px dashed #d9d9d9;
border-radius: 0.5rem;
color: var(--greyscale-500, var(--color-greyscale-500, #818186));
padding: 2rem 1.25rem;
margin-block-start: 0.5rem;
font-size: 0.65rem;
font-family: Inter;
color: var(--greyscale-500, var(--color-greyscale-500, #818186));
padding: 2rem 1.25rem;
margin-block-start: 0.5rem;
font-size: 0.65rem;
font-family: Inter;
position: relative;
overflow: hidden;
position: relative;
overflow: hidden;
.loading-overlay {
position: absolute;
inset: 0;
opacity: 0;
z-index: 100;
.loading-overlay {
position: absolute;
inset: 0;
opacity: 0;
z-index: 100;
display: grid;
place-items: center;
}
}
display: grid;
place-items: center;
}
}
img {
position: absolute;
left: 0;
top: 0;
opacity: 0;
}
}
img {
position: absolute;
left: 0;
top: 0;
opacity: 0;
}
}
.images {
display: flex;
margin-block-start: 0.5rem;
gap: 0.5rem;
}
.images {
display: flex;
margin-block-start: 0.5rem;
gap: 0.5rem;
}
</style>

View File

@@ -25,34 +25,21 @@
</script>
<div
class="scroll-indicator"
class="scroll-indicator relative h-full w-px shrink-0 rounded-full"
use:rect={elRect}
style:--y={`${y}px`}
style:--percentage={`${easedPercentage * 100}%`}
>
<div class="web-dot" />
<div class="0)] absolute -top-[8px] left-1/2 translate-[-50%_var(--y," />
</div>
<style lang="scss">
.scroll-indicator {
position: relative;
width: 1px;
flex-shrink: 0;
height: 100%;
background: linear-gradient(
to bottom,
hsl(var(--web-color-accent)) 0%,
hsl(var(--web-color-greyscale-700)) var(--percentage),
hsl(var(--web-color-greyscale-700)) 100%
);
border-radius: 100%;
}
.web-dot {
position: absolute;
left: 50%;
translate: -50% var(--y, 0);
top: -8px;
}
</style>