This commit is contained in:
Torsten Dittmann
2024-09-23 14:18:03 +02:00
parent 1ddf7de85a
commit 44fc0a06d8
14 changed files with 4685 additions and 3772 deletions
+1 -1
View File
@@ -23,7 +23,7 @@
"@appwrite.io/pink": "0.25.0",
"@appwrite.io/pink-icons": "0.25.0",
"@appwrite.io/pink-icons-svelte": "1.0.0-next.5",
"@appwrite.io/pink-svelte": "1.0.0-next.39",
"@appwrite.io/pink-svelte": "1.0.0-next.52",
"@popperjs/core": "^2.11.8",
"@sentry/sveltekit": "^8.28.0",
"@stripe/stripe-js": "^3.5.0",
+4549 -3597
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -18,7 +18,7 @@
</script>
{#if single}
<Card.Base padding="none" class="common-section">
<Card.Base padding="none">
<Empty
title={`Create your first ${target}`}
description="Need a hand? Learn more in our documentation.">
+1 -1
View File
@@ -7,7 +7,7 @@
export let search = '';
</script>
<Card.Base padding="none" class="common-section">
<Card.Base padding="none">
<Empty
title={`Sorry, we couldn't find ${search}`}
description={`There are no ${target} that match your search.`}
+5 -11
View File
@@ -3,6 +3,7 @@
import { page as pageStore } from '$app/stores';
import { InputSelect } from '$lib/elements/forms';
import { preferences } from '$lib/stores/preferences';
import { Layout } from '@appwrite.io/pink-svelte';
export let sum: number;
export let limit: number;
@@ -32,14 +33,7 @@
}
</script>
<div class="u-flex u-gap-12 u-cross-center">
<InputSelect
wrapperTag="div"
id="rows"
label={`${name} per page`}
showLabel={false}
{options}
bind:value={limit}
on:change={limitChange} />
<p class="text">{name} per page. Total results: {sum >= 5000 ? `${sum}+` : sum}</p>
</div>
<Layout.Stack direction="row" alignItems="center" inline>
<InputSelect id="rows" {options} bind:value={limit} on:change={limitChange} />
<p class="text" style:white-space="nowrap">{name} per page. Total results: {sum >= 5000 ? `${sum}+` : sum}</p>
</Layout.Stack>
@@ -1,6 +1,7 @@
<script lang="ts">
import Limit from './limit.svelte';
import Pagination from './pagination.svelte';
import { Layout } from '@appwrite.io/pink-svelte';
export let limit: number;
export let offset: number;
@@ -8,9 +9,7 @@
export let name: string;
</script>
<div class="u-flex u-margin-block-start-32 u-flex-wrap">
<Layout.Stack direction="row" alignItems="center" wrap="wrap" justifyContent="space-between">
<Limit {limit} sum={total} {name} />
<div class="u-margin-inline-start-auto">
<Pagination {limit} {offset} sum={total} />
</div>
</div>
<Pagination {limit} {offset} sum={total} />
</Layout.Stack>
+3 -3
View File
@@ -4,7 +4,7 @@
import { trackEvent } from '$lib/actions/analytics';
import { onMount } from 'svelte';
import { onDestroy } from 'svelte';
import { Input } from '@appwrite.io/pink-svelte';
import { Input, Layout } from '@appwrite.io/pink-svelte';
import { IconX } from '@appwrite.io/pink-icons-svelte';
export let search = '';
@@ -60,7 +60,7 @@
}
</script>
<div class="u-flex u-gap-12 common-section u-main-space-between">
<Layout.Stack direction="row" justifyContent="space-between">
<div class={fullWidth ? 'u-width-full-line' : 'u-flex-basis-50-percent'}>
<Input.Text {placeholder} {disabled} {required} type="search" bind:value={search}>
<svelte:fragment slot="end">
@@ -71,4 +71,4 @@
</Input.Text>
</div>
<slot />
</div>
</Layout.Stack>
+12 -38
View File
@@ -1,5 +1,5 @@
<script lang="ts">
import { FormItem, FormItemPart, Helper, Label } from '.';
import { Input } from '@appwrite.io/pink-svelte';
import type { FormItemTag } from './formItem.svelte';
export let id: string;
@@ -46,42 +46,16 @@
$: if (isNotEmpty(value)) {
error = null;
}
$: hasNullOption = options.some((option) => option.value === null);
$: wrapper = isMultiple ? FormItemPart : FormItem;
</script>
<svelte:component this={wrapper} {fullWidth} tag={wrapperTag}>
{#if label}
<Label {required} {hideRequired} {optionalText} hide={!showLabel} for={id}>
{label}
</Label>
{/if}
<div class="select">
<select
{id}
{required}
{disabled}
aria-label={ariaLabel}
bind:this={element}
bind:value
on:invalid={handleInvalid}
on:change>
{#if placeholder && !hasNullOption}
<option value={null} disabled selected hidden>{placeholder}</option>
{/if}
{#each options as option}
<option value={option.value} selected={option.value === value}>
{option.label}
</option>
{/each}
</select>
<span class="icon-cheveron-down" aria-hidden="true" />
</div>
{#if error}
<Helper type="warning">{error}</Helper>
{:else}
<slot name="helper" />
{/if}
</svelte:component>
<Input.Select
{label}
{options}
{placeholder}
{disabled}
helper={error}
state={error ? 'error' : 'default'}
on:invalid={handleInvalid}
on:input
on:change
bind:value />
+65 -66
View File
@@ -19,6 +19,7 @@
import { ContainerButton } from '.';
import { trackEvent } from '$lib/actions/analytics';
import { goto } from '$app/navigation';
import { Layout } from '@appwrite.io/pink-svelte';
export let isFlex = true;
export let title: string;
@@ -116,70 +117,68 @@
{/if}
{/if}
<header class:u-flex={isFlex} class="u-gap-12 common-section u-main-space-between u-flex-wrap">
<div class="u-flex u-cross-child-center u-cross-center u-gap-16 u-flex-wrap">
<Heading tag={titleTag} size={titleSize}>{title}</Heading>
{#if isCloud && isLimited}
<DropList bind:show={showDropdown} width="16">
{#if hasProjectLimitation}
<Pill button on:click={() => (showDropdown = !showDropdown)}>
<span class="icon-info" />{total}/{limit} created
</Pill>
{:else}
<Pill button on:click={() => (showDropdown = !showDropdown)}>
<span class="icon-info" />Limits applied
</Pill>
{/if}
<svelte:fragment slot="list">
<slot name="tooltip" {limit} {tier} {title} {upgradeMethod} {hasUsageFees}>
{#if hasProjectLimitation}
<p class="text">
You are limited to {limit}
{title.toLocaleLowerCase()} per project on the {tier} plan.
{#if $organization?.billingPlan === BillingPlan.FREE}<Button
link
href={$upgradeURL}
on:click={() =>
trackEvent('click_organization_upgrade', {
from: 'button',
source: 'resource_limit_tag'
})}>Upgrade</Button>
for additional {title.toLocaleLowerCase()}.
{/if}
</p>
{:else if hasUsageFees}
<p class="text">
You are limited to {limit}
{title.toLocaleLowerCase()} per organization on the {tier} plan.
<Button link on:click={() => ($showUsageRatesModal = true)}
>Excess usage fees will apply</Button
>.
</p>
{:else}
<p class="text">
You are limited to {limit}
{title.toLocaleLowerCase()} per organization on the {tier} plan.
{#if $organization?.billingPlan === BillingPlan.FREE}
<Button link href={$upgradeURL}>Upgrade</Button>
for additional {title.toLocaleLowerCase()}.
{/if}
</p>
{/if}
</slot>
</svelte:fragment>
</DropList>
{/if}
</div>
<Layout.Stack direction="row">
<Heading tag={titleTag} size={titleSize}>{title}</Heading>
{#if isCloud && isLimited}
<DropList bind:show={showDropdown} width="16">
{#if hasProjectLimitation}
<Pill button on:click={() => (showDropdown = !showDropdown)}>
<span class="icon-info" />{total}/{limit} created
</Pill>
{:else}
<Pill button on:click={() => (showDropdown = !showDropdown)}>
<span class="icon-info" />Limits applied
</Pill>
{/if}
<svelte:fragment slot="list">
<slot name="tooltip" {limit} {tier} {title} {upgradeMethod} {hasUsageFees}>
{#if hasProjectLimitation}
<p class="text">
You are limited to {limit}
{title.toLocaleLowerCase()} per project on the {tier} plan.
{#if $organization?.billingPlan === BillingPlan.FREE}<Button
link
href={$upgradeURL}
on:click={() =>
trackEvent('click_organization_upgrade', {
from: 'button',
source: 'resource_limit_tag'
})}>Upgrade</Button>
for additional {title.toLocaleLowerCase()}.
{/if}
</p>
{:else if hasUsageFees}
<p class="text">
You are limited to {limit}
{title.toLocaleLowerCase()} per organization on the {tier} plan.
<Button link on:click={() => ($showUsageRatesModal = true)}
>Excess usage fees will apply</Button
>.
</p>
{:else}
<p class="text">
You are limited to {limit}
{title.toLocaleLowerCase()} per organization on the {tier} plan.
{#if $organization?.billingPlan === BillingPlan.FREE}
<Button link href={$upgradeURL}>Upgrade</Button>
for additional {title.toLocaleLowerCase()}.
{/if}
</p>
{/if}
</slot>
</svelte:fragment>
</DropList>
{/if}
</Layout.Stack>
<slot {isButtonDisabled}>
{#if buttonText}
<ContainerButton
{title}
disabled={isButtonDisabled}
{buttonText}
{buttonEvent}
{buttonMethod}
{buttonHref} />
{/if}
</slot>
</header>
<slot {isButtonDisabled}>
{#if buttonText}
<ContainerButton
{title}
disabled={isButtonDisabled}
{buttonText}
{buttonEvent}
{buttonMethod}
{buttonHref} />
{/if}
</slot>
@@ -14,7 +14,6 @@
PaginationWithLimit,
SearchQuery
} from '$lib/components';
import { Pill } from '$lib/elements';
import { Button } from '$lib/elements/forms';
import { toLocaleDate, toLocaleDateTime } from '$lib/helpers/date';
import { Container, ContainerHeader } from '$lib/layout';
@@ -23,7 +22,7 @@
import type { PageData } from './$types';
import Create from './createUser.svelte';
import { tooltip } from '$lib/actions/tooltip';
import { Badge, Icon, Table } from '@appwrite.io/pink-svelte';
import { Badge, Icon, Table, Layout } from '@appwrite.io/pink-svelte';
import { Tag } from '@appwrite.io/pink-svelte';
import { IconDuplicate } from '@appwrite.io/pink-icons-svelte';
@@ -57,17 +56,17 @@
<Table.Root>
<svelte:fragment slot="header">
<Table.Header.Cell>Name</Table.Header.Cell>
<Table.Header.Cell onlyDesktop>Identifiers</Table.Header.Cell>
<Table.Header.Cell onlyDesktop width={130}>Status</Table.Header.Cell>
<Table.Header.Cell onlyDesktop width={100}>ID</Table.Header.Cell>
<Table.Header.Cell onlyDesktop width={100}>Labels</Table.Header.Cell>
<Table.Header.Cell onlyDesktop>Joined</Table.Header.Cell>
<Table.Header.Cell onlyDesktop>Last Activity</Table.Header.Cell>
<Table.Header.Cell>Identifiers</Table.Header.Cell>
<Table.Header.Cell width="130px">Status</Table.Header.Cell>
<Table.Header.Cell width="100px">ID</Table.Header.Cell>
<Table.Header.Cell width="100px">Labels</Table.Header.Cell>
<Table.Header.Cell>Joined</Table.Header.Cell>
<Table.Header.Cell>Last Activity</Table.Header.Cell>
</svelte:fragment>
{#each data.users.users as user}
<Table.Link href={`${base}/project-${projectId}/auth/user-${user.$id}`}>
<Table.Cell title="Name">
<div class="u-flex u-gap-12 u-cross-center">
<Table.Cell>
<Layout.Stack direction="row" alignItems="center">
{#if user.email || user.phone}
{#if user.name}
<AvatarInitials size={32} name={user.name} />
@@ -83,14 +82,14 @@
</div>
<span class="text u-trim">{user.name}</span>
{/if}
</div>
</Layout.Stack>
</Table.Cell>
<Table.Cell onlyDesktop title="Identifiers">
<Table.Cell>
{user.email && user.phone
? [user.email, user.phone].join(',')
: user.email || user.phone}
</Table.Cell>
<Table.Cell onlyDesktop title="Status">
<Table.Cell>
{#if user.status}
{@const success = user.emailVerification || user.phoneVerification}
<Badge
@@ -112,7 +111,7 @@
content="blocked" />
{/if}
</Table.Cell>
<Table.Cell onlyDesktop showOverflow title="ID">
<Table.Cell>
<Copy value={user.$id} event="user">
<Tag size="small">
<Icon size="small" icon={IconDuplicate} />
@@ -120,13 +119,13 @@
</Tag>
</Copy>
</Table.Cell>
<Table.Cell onlyDesktop title="Labels">
<Table.Cell>
{user.labels.join(', ')}
</Table.Cell>
<Table.Cell onlyDesktop title="Joined">
<Table.Cell>
{toLocaleDateTime(user.registration)}
</Table.Cell>
<Table.Cell onlyDesktop title="Last Activity">
<Table.Cell>
{user.accessedAt ? toLocaleDate(user.accessedAt) : 'never'}
</Table.Cell>
</Table.Link>
@@ -139,12 +138,8 @@
offset={data.offset}
total={data.users.total} />
{:else if data.search}
<EmptySearch>
<div class="u-text-center">
<b>Sorry, we couldn't find '{data.search}'</b>
<p>There are no users that match your search.</p>
</div>
<Button href={`${base}/project-${projectId}/auth`} secondary>Clear Search</Button>
<EmptySearch target="users" hidePagination>
<Button href={`${base}/project-${projectId}/auth`} size="small" secondary>Clear Search</Button>
</EmptySearch>
{:else}
<Empty
+7 -7
View File
@@ -84,16 +84,15 @@
"color-fgcolor-on-success-weak": "var(--web-green-200)",
"color-fgcolor-error": "var(--web-red-500)",
"color-fgcolor-on-error": "var(--neutral-0)",
"color-border-neutral": "var(--neutral-800)",
"color-fgcolor-on-error-weak": "var(--web-red-200)",
"color-border-neutral": "var(--neutral-800)",
"color-fgcolor-warning": "var(--web-orange-500)",
"color-fgcolor-on-warning": "var(--neutral-0)",
"color-border-neutral-strong": "var(--neutral-750)",
"color-border-neutral-stronger": "var(--neutral-600)",
"color-border-neutral-strongest": "var(--neutral-0)",
"color-fgcolor-on-warning-weak": "var(--web-orange-200)",
"color-border-focus": "var(--neutral-25)",
"color-border-focus-secondary": "var(--neutral-200)",
"color-border-neutral-strongest": "var(--neutral-0)",
"color-border-focus": "var(--neutral-600)",
"color-border-accent": "var(--neutral-0)",
"color-border-accent-secondary": "var(--neutral-0)",
"color-border-success": "var(--web-green-500)",
@@ -113,7 +112,7 @@
"gradient-border-button-secondary-bottom": "var(--color-border-neutral-strong)",
"gradient-border-button-secondary-top": "var(--color-border-neutral)",
"color-fgcolor-on-invert": "var(--neutral-800)",
"font-family-brand": "Aeonik Pro",
"font-family-brand": "Inter",
"font-family-sansserif": "Inter",
"font-family-monospace": "Aeonik Fono",
"font-family-code": "Fira Code",
@@ -176,8 +175,9 @@
"icon-size-l": "var(--base-24)",
"border-width-s": "1px",
"gap-none": "var(--base-0)",
"gap-xxs": "var(--base-2)",
"gap-xs": "var(--base-4)",
"gap-xxxs": "var(--base-2)",
"gap-xxs": "var(--base-4)",
"gap-xs": "var(--base-6)",
"gap-s": "var(--base-8)",
"gap-m": "var(--base-12)",
"gap-l": "var(--base-16)",
+6 -6
View File
@@ -84,16 +84,15 @@
"color-fgcolor-on-success-weak": "var(--web-green-200)",
"color-fgcolor-error": "var(--web-red-500)",
"color-fgcolor-on-error": "var(--neutral-0)",
"color-border-neutral": "var(--neutral-800)",
"color-fgcolor-on-error-weak": "var(--web-red-200)",
"color-border-neutral": "var(--neutral-800)",
"color-fgcolor-warning": "var(--web-orange-500)",
"color-fgcolor-on-warning": "var(--neutral-0)",
"color-border-neutral-strong": "var(--neutral-750)",
"color-border-neutral-stronger": "var(--neutral-600)",
"color-border-neutral-strongest": "var(--neutral-0)",
"color-fgcolor-on-warning-weak": "var(--web-orange-200)",
"color-border-focus": "var(--neutral-25)",
"color-border-focus-secondary": "var(--neutral-200)",
"color-border-neutral-strongest": "var(--neutral-0)",
"color-border-focus": "var(--neutral-600)",
"color-border-accent": "var(--neutral-0)",
"color-border-accent-secondary": "var(--neutral-0)",
"color-border-success": "var(--web-green-500)",
@@ -176,8 +175,9 @@
"icon-size-l": "var(--base-24)",
"border-width-s": "1px",
"gap-none": "var(--base-0)",
"gap-xxs": "var(--base-2)",
"gap-xs": "var(--base-4)",
"gap-xxxs": "var(--base-2)",
"gap-xxs": "var(--base-4)",
"gap-xs": "var(--base-6)",
"gap-s": "var(--base-8)",
"gap-m": "var(--base-12)",
"gap-l": "var(--base-16)",
+7 -7
View File
@@ -84,16 +84,15 @@
"color-fgcolor-on-success-weak": "var(--web-green-700)",
"color-fgcolor-error": "var(--web-red-700)",
"color-fgcolor-on-error": "var(--neutral-0)",
"color-border-neutral": "var(--neutral-50)",
"color-fgcolor-on-error-weak": "var(--web-red-700)",
"color-border-neutral": "var(--neutral-100)",
"color-fgcolor-warning": "var(--web-orange-700)",
"color-fgcolor-on-warning": "var(--neutral-0)",
"color-border-neutral-strong": "var(--neutral-200)",
"color-border-neutral-stronger": "var(--neutral-500)",
"color-border-neutral-strongest": "var(--neutral-900)",
"color-fgcolor-on-warning-weak": "var(--web-orange-700)",
"color-border-focus": "var(--neutral-600)",
"color-border-focus-secondary": "var(--neutral-500)",
"color-border-neutral-strongest": "var(--neutral-900)",
"color-border-focus": "var(--neutral-500)",
"color-border-accent": "var(--brand-pink-500)",
"color-border-accent-secondary": "var(--brand-pink-600)",
"color-border-success": "var(--web-green-500)",
@@ -113,7 +112,7 @@
"gradient-border-button-secondary-bottom": "var(--color-border-neutral)",
"gradient-border-button-secondary-top": "var(--color-border-neutral-strong)",
"color-fgcolor-on-invert": "var(--neutral-25)",
"font-family-brand": "Aeonik Pro",
"font-family-brand": "Inter",
"font-family-sansserif": "Inter",
"font-family-monospace": "Aeonik Fono",
"font-family-code": "Fira Code",
@@ -176,8 +175,9 @@
"icon-size-l": "var(--base-24)",
"border-width-s": "1px",
"gap-none": "var(--base-0)",
"gap-xxs": "var(--base-2)",
"gap-xs": "var(--base-4)",
"gap-xxxs": "var(--base-2)",
"gap-xxs": "var(--base-4)",
"gap-xs": "var(--base-6)",
"gap-s": "var(--base-8)",
"gap-m": "var(--base-12)",
"gap-l": "var(--base-16)",
+6 -6
View File
@@ -84,16 +84,15 @@
"color-fgcolor-on-success-weak": "var(--web-green-700)",
"color-fgcolor-error": "var(--web-red-700)",
"color-fgcolor-on-error": "var(--neutral-0)",
"color-border-neutral": "var(--neutral-50)",
"color-fgcolor-on-error-weak": "var(--web-red-700)",
"color-border-neutral": "var(--neutral-100)",
"color-fgcolor-warning": "var(--web-orange-700)",
"color-fgcolor-on-warning": "var(--neutral-0)",
"color-border-neutral-strong": "var(--neutral-200)",
"color-border-neutral-stronger": "var(--neutral-500)",
"color-border-neutral-strongest": "var(--neutral-900)",
"color-fgcolor-on-warning-weak": "var(--web-orange-700)",
"color-border-focus": "var(--neutral-600)",
"color-border-focus-secondary": "var(--neutral-500)",
"color-border-neutral-strongest": "var(--neutral-900)",
"color-border-focus": "var(--neutral-500)",
"color-border-accent": "var(--brand-pink-500)",
"color-border-accent-secondary": "var(--brand-pink-600)",
"color-border-success": "var(--web-green-500)",
@@ -176,8 +175,9 @@
"icon-size-l": "var(--base-24)",
"border-width-s": "1px",
"gap-none": "var(--base-0)",
"gap-xxs": "var(--base-2)",
"gap-xs": "var(--base-4)",
"gap-xxxs": "var(--base-2)",
"gap-xxs": "var(--base-4)",
"gap-xs": "var(--base-6)",
"gap-s": "var(--base-8)",
"gap-m": "var(--base-12)",
"gap-l": "var(--base-16)",