mirror of
https://github.com/appwrite/console.git
synced 2026-06-06 19:27:48 +00:00
feat: new org creation
This commit is contained in:
Generated
+9
-9
@@ -7,8 +7,8 @@
|
||||
"name": "@appwrite/console",
|
||||
"dependencies": {
|
||||
"@appwrite.io/console": "^0.5.0",
|
||||
"@appwrite.io/pink": "0.11.0",
|
||||
"@appwrite.io/pink-icons": "0.11.0",
|
||||
"@appwrite.io/pink": "0.16.0",
|
||||
"@appwrite.io/pink-icons": "0.16.0",
|
||||
"@popperjs/core": "^2.11.8",
|
||||
"@sentry/svelte": "^7.66.0",
|
||||
"@sentry/tracing": "^7.66.0",
|
||||
@@ -167,19 +167,19 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@appwrite.io/pink": {
|
||||
"version": "0.11.0",
|
||||
"resolved": "https://registry.npmjs.org/@appwrite.io/pink/-/pink-0.11.0.tgz",
|
||||
"integrity": "sha512-0/ztJxeV6Cy1FnXy2ClLELzDnR4eRtGAhQ24napCg0VwOFevSIc0S7jcRrWVyA6WRuwex4eGiEn2JeYMTq70Xg==",
|
||||
"version": "0.16.0",
|
||||
"resolved": "https://registry.npmjs.org/@appwrite.io/pink/-/pink-0.16.0.tgz",
|
||||
"integrity": "sha512-KprOd+36I0w6PC0x6NJclvyJNpCsjAPcrCHL3QixSX0dZ66wqFE6NitF/KiVVCxbuBaNgjrm7oQ0hr7dt1Sm5Q==",
|
||||
"dependencies": {
|
||||
"@appwrite.io/pink-icons": "0.11.0",
|
||||
"@appwrite.io/pink-icons": "0.16.0",
|
||||
"normalize.css": "^8.0.1",
|
||||
"the-new-css-reset": "^1.11.2"
|
||||
}
|
||||
},
|
||||
"node_modules/@appwrite.io/pink-icons": {
|
||||
"version": "0.11.0",
|
||||
"resolved": "https://registry.npmjs.org/@appwrite.io/pink-icons/-/pink-icons-0.11.0.tgz",
|
||||
"integrity": "sha512-FOvP87m4S17QRQPrLzsSlwrbIeJNJi5RliGUQYONIhmI0PiwE4Xm5LXFE+NqFYsR56w2X3jYdJIHdIdZlH3XjA=="
|
||||
"version": "0.16.0",
|
||||
"resolved": "https://registry.npmjs.org/@appwrite.io/pink-icons/-/pink-icons-0.16.0.tgz",
|
||||
"integrity": "sha512-tWaG5lFXnKzbFbGf4SlxoFYj2yH7kQDejFq+UHdfzBrqteSfZpxIxdNmKHIea1ztcmsat4y+R0ZbVX9iOv+oPw=="
|
||||
},
|
||||
"node_modules/@babel/code-frame": {
|
||||
"version": "7.23.5",
|
||||
|
||||
+2
-2
@@ -19,8 +19,8 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@appwrite.io/console": "^0.5.0",
|
||||
"@appwrite.io/pink": "0.11.0",
|
||||
"@appwrite.io/pink-icons": "0.11.0",
|
||||
"@appwrite.io/pink": "0.16.0",
|
||||
"@appwrite.io/pink-icons": "0.16.0",
|
||||
"@popperjs/core": "^2.11.8",
|
||||
"@sentry/svelte": "^7.66.0",
|
||||
"@sentry/tracing": "^7.66.0",
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
hide?: boolean;
|
||||
tooltip?: string;
|
||||
for?: string;
|
||||
class?: string;
|
||||
}
|
||||
|
||||
export let required: $$Props['required'] = false;
|
||||
@@ -13,12 +14,14 @@
|
||||
export let optionalText: $$Props['optionalText'] = undefined;
|
||||
export let hide: $$Props['hide'] = false;
|
||||
export let tooltip: $$Props['tooltip'] = null;
|
||||
let classes: string = undefined;
|
||||
export { classes as class };
|
||||
</script>
|
||||
|
||||
<label
|
||||
class:is-required={required && !hideRequired}
|
||||
class:u-hide={hide}
|
||||
class="label"
|
||||
class="label {classes}"
|
||||
{...$$restProps}>
|
||||
<slot />
|
||||
</label>
|
||||
|
||||
@@ -19,3 +19,7 @@ export { default as GridHeader } from './gridHeader.svelte';
|
||||
export { default as ContainerHeader } from './containerHeader.svelte';
|
||||
export { default as HeaderAlert } from './headerAlert.svelte';
|
||||
export { default as ContainerButton } from './containerButton.svelte';
|
||||
export { default as WizardSecondaryContainer } from './wizardSecondaryContainer.svelte';
|
||||
export { default as WizardSecondaryContent } from './wizardSecondaryContent.svelte';
|
||||
export { default as WizardSecondaryHeader } from './wizardSecondaryHeader.svelte';
|
||||
export { default as WizardSecondaryFooter } from './wizardSecondaryFooter.svelte';
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
<section class="wizard-secondary c-wizard-position">
|
||||
<div class="wizard-secondary-container">
|
||||
<slot />
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<style lang="scss">
|
||||
.c-wizard-position {
|
||||
background-color: hsl(var(--p-body-bg-color));
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
z-index: 30;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
max-height: 100vh;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,11 @@
|
||||
<div class="wizard-secondary-content">
|
||||
<div class="wizard-secondary-content-1">
|
||||
<slot />
|
||||
</div>
|
||||
<div class="wizard-secondary-content-sep"></div>
|
||||
<div class="wizard-secondary-content-2">
|
||||
<div class="wizard-secondary-content-sticky">
|
||||
<slot name="aside" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,8 @@
|
||||
<div class="wizard-secondary-options">
|
||||
<div class="wizard-secondary-options-start">
|
||||
<slot name="start" />
|
||||
</div>
|
||||
<div class="wizard-secondary-options-end">
|
||||
<slot />
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,17 @@
|
||||
<script lang="ts">
|
||||
import { Heading } from '$lib/components';
|
||||
import { Button } from '$lib/elements/forms';
|
||||
export let href: string;
|
||||
</script>
|
||||
|
||||
<header class="wizard-secondary-header">
|
||||
<div class="u-flex u-main-space-between u-gap-32">
|
||||
<Heading size={1} tag="h1"><slot /></Heading>
|
||||
<Button text round class="u-margin-block-start-8" ariaLabel="close modal" {href}>
|
||||
<span class="icon-x u-font-size-20" aria-hidden="true"></span>
|
||||
</Button>
|
||||
</div>
|
||||
{#if $$slots.description}
|
||||
<p class="body-text-2"><slot name="description" /></p>
|
||||
{/if}
|
||||
</header>
|
||||
@@ -114,7 +114,7 @@ export type TierData = {
|
||||
|
||||
export const tierFree: TierData = {
|
||||
name: 'Starter',
|
||||
description: 'For personal, passion projects.'
|
||||
description: 'For personal hobby projects of small scale and students.'
|
||||
};
|
||||
|
||||
export const tierPro: TierData = {
|
||||
|
||||
@@ -0,0 +1,93 @@
|
||||
<script lang="ts">
|
||||
import { base } from '$app/paths';
|
||||
import { LabelCard } from '$lib/components';
|
||||
import { BillingPlan } from '$lib/constants';
|
||||
import { Button, Form, FormList, InputText, Label } from '$lib/elements/forms';
|
||||
import { formatCurrency } from '$lib/helpers/numbers';
|
||||
import {
|
||||
WizardSecondaryContainer,
|
||||
WizardSecondaryContent,
|
||||
WizardSecondaryFooter,
|
||||
WizardSecondaryHeader
|
||||
} from '$lib/layout';
|
||||
import { plansInfo, tierFree, tierPro } from '$lib/stores/billing';
|
||||
import { organizationList, type Organization } from '$lib/stores/organization';
|
||||
import { createOrganization } from './store';
|
||||
|
||||
$: anyOrgFree = $organizationList.teams?.find(
|
||||
(org) => (org as Organization)?.billingPlan === BillingPlan.STARTER
|
||||
);
|
||||
|
||||
$: freePlan = $plansInfo.get(BillingPlan.STARTER);
|
||||
$: proPlan = $plansInfo.get(BillingPlan.PRO);
|
||||
</script>
|
||||
|
||||
<WizardSecondaryContainer>
|
||||
<WizardSecondaryHeader href={`${base}/console`}>Create organization</WizardSecondaryHeader>
|
||||
<WizardSecondaryContent>
|
||||
<Form onSubmit={() => console.log('test')}>
|
||||
<FormList>
|
||||
<InputText label="Name" placeholder="Enter name" id="name" />
|
||||
</FormList>
|
||||
<Label class="u-margin-block-start-16">Select plan</Label>
|
||||
<ul
|
||||
class="u-flex u-gap-16 u-margin-block-start-8"
|
||||
style="--p-grid-item-size:16em; --p-grid-item-size-small-screens:16rem; --grid-gap: 1rem;">
|
||||
<li class="u-flex-basis-50-percent">
|
||||
<LabelCard
|
||||
name="plan"
|
||||
bind:group={$createOrganization.billingPlan}
|
||||
value="tier-0"
|
||||
disabled={!!anyOrgFree}
|
||||
tooltipShow={!!anyOrgFree}
|
||||
tooltipText="You are limited to 1 Free organization per account.">
|
||||
<svelte:fragment slot="custom" let:disabled>
|
||||
<div
|
||||
class="u-flex u-flex-vertical u-gap-4 u-width-full-line"
|
||||
class:u-opacity-50={disabled}>
|
||||
<h4 class="body-text-2 u-bold">
|
||||
{tierFree.name}
|
||||
</h4>
|
||||
<p class="u-color-text-gray u-small">{tierFree.description}</p>
|
||||
<p>
|
||||
{formatCurrency(freePlan?.price ?? 0)}
|
||||
</p>
|
||||
</div>
|
||||
</svelte:fragment>
|
||||
</LabelCard>
|
||||
</li>
|
||||
|
||||
<li class="u-flex-basis-50-percent">
|
||||
<LabelCard
|
||||
name="plan"
|
||||
bind:group={$createOrganization.billingPlan}
|
||||
value="tier-1">
|
||||
<svelte:fragment slot="custom">
|
||||
<div class="u-flex u-flex-vertical u-gap-4 u-width-full-line">
|
||||
<h4 class="body-text-2 u-bold">
|
||||
{tierPro.name}
|
||||
</h4>
|
||||
<p class="u-color-text-gray u-small">
|
||||
{tierPro.description}
|
||||
</p>
|
||||
<p>
|
||||
{formatCurrency(proPlan?.price ?? 0)} per member/month + usage
|
||||
</p>
|
||||
</div>
|
||||
</svelte:fragment>
|
||||
</LabelCard>
|
||||
</li>
|
||||
</ul>
|
||||
</Form>
|
||||
<svelte:fragment slot="aside">
|
||||
<div class="card">
|
||||
Lorem ipsum dolor sit amet consectetur adipisicing elit. Recusandae, incidunt!
|
||||
</div>
|
||||
</svelte:fragment>
|
||||
</WizardSecondaryContent>
|
||||
|
||||
<WizardSecondaryFooter>
|
||||
<Button href={`${base}/console`} secondary>Cancel</Button>
|
||||
<Button on:click>Create organization</Button>
|
||||
</WizardSecondaryFooter>
|
||||
</WizardSecondaryContainer>
|
||||
@@ -0,0 +1,28 @@
|
||||
import { BillingPlan } from '$lib/constants';
|
||||
import type { WizardStepsType } from '$lib/layout/wizard.svelte';
|
||||
import type { Tier } from '$lib/stores/billing';
|
||||
import { writable } from 'svelte/store';
|
||||
|
||||
export const createOrgSteps = writable<WizardStepsType>(new Map());
|
||||
export const createOrganizationFinalAction = writable<string>('Start trial');
|
||||
|
||||
export const createOrganization = writable<{
|
||||
id?: string;
|
||||
name: string;
|
||||
billingPlan: Tier;
|
||||
paymentMethodId: string;
|
||||
billingAddressId: string;
|
||||
collaborators?: string[];
|
||||
billingBudget?: number;
|
||||
taxId?: string;
|
||||
couponCode?: string;
|
||||
}>({
|
||||
id: null,
|
||||
name: null,
|
||||
billingPlan: BillingPlan.PRO,
|
||||
paymentMethodId: null,
|
||||
collaborators: [],
|
||||
billingAddressId: null,
|
||||
taxId: null,
|
||||
couponCode: null
|
||||
});
|
||||
Reference in New Issue
Block a user