feat: redo settings and all org pages. (#601)

* feat: new components, deploy storybook

* refactor: simplify component field definitions and enhance button loading state

- Removed unnecessary type imports and simplified the FIELDS array definitions across multiple components in Storybook.
- Updated button component to use a loading state instead of isLoading, improving clarity and consistency in props.
- Adjusted button stories to reflect the new loading prop and enhanced the button's loading visual feedback.
- Minor CSS adjustments for better layout and styling consistency.

* chore: add field, card, password components

* feat: improve page component & update AuthUI path

* chore: update bits-ui to version 2.14.4 and all org related UI's

- Updated bits-ui dependency in pnpm-lock.yaml and package.json to version 2.14.4.
- Refactored imports for RoleBasedSecurity and UpgradeBanner components to use the new ui feature directory.
- Removed unused Course components and related files to clean up the codebase.
- Enhanced various components to improve consistency and maintainability.

* chore: move all setting buttons to the top and update auth ui styles

* chore: remove svelte-loading-spinners and replace with @cio/ui/base/spinner

- Removed all instances of svelte-loading-spinners from the project.
- Updated components to use the new Spinner from @cio/ui/base/spinner.
- Cleaned up pnpm-lock.yaml and package.json to reflect the removal of svelte-loading-spinners.
- Added new CSS animations for rocket launch effects in app.css.
- Enhanced email change flow with updated verification messages in translations.

* chore: remove supabase file upload from dashboard and move to r2

* chore: update organization API and UI components

- Added new API methods for organization plan operations and team management.
- Introduced middleware for API key authentication and organization admin checks.
- Refactored organization-related components to utilize the new API structure.
- Updated various UI components to improve consistency and maintainability.
- Enhanced error handling and validation for organization-related actions.
- Removed deprecated services and streamlined the codebase.
This commit is contained in:
Rotimi Best
2025-12-02 09:54:38 +01:00
committed by GitHub
parent 531516a8f7
commit c7854efae3
350 changed files with 13928 additions and 3895 deletions
@@ -0,0 +1,411 @@
<script module>
import { defineMeta } from '@storybook/addon-svelte-csf';
import SearchIcon from '@lucide/svelte/icons/search';
import MailIcon from '@lucide/svelte/icons/mail';
import LockIcon from '@lucide/svelte/icons/lock';
import CreditCardIcon from '@lucide/svelte/icons/credit-card';
import UserIcon from '@lucide/svelte/icons/user';
import MessageSquareIcon from '@lucide/svelte/icons/message-square';
import GlobeIcon from '@lucide/svelte/icons/globe';
import LoaderCircleIcon from '@lucide/svelte/icons/loader-circle';
import EyeIcon from '@lucide/svelte/icons/eye';
import EyeOffIcon from '@lucide/svelte/icons/eye-off';
import KeyIcon from '@lucide/svelte/icons/key';
import FileTextIcon from '@lucide/svelte/icons/file-text';
import ChevronDownIcon from '@lucide/svelte/icons/chevron-down';
import PlusIcon from '@lucide/svelte/icons/plus';
import CopyIcon from '@lucide/svelte/icons/copy';
import MoreHorizontalIcon from '@lucide/svelte/icons/more-horizontal';
import StarIcon from '@lucide/svelte/icons/star';
import InfoIcon from '@lucide/svelte/icons/info';
import LoaderIcon from '@lucide/svelte/icons/loader';
import Link2Icon from '@lucide/svelte/icons/link-2';
import { CopyButton } from '@cio/ui/base/copy-button';
import * as InputGroup from '@cio/ui/base/input-group';
import { Input } from '@cio/ui/base/input';
import { Textarea } from '@cio/ui/base/textarea';
import { Label } from '@cio/ui/base/label';
import { Button } from '@cio/ui/base/button';
import { Spinner } from '@cio/ui/base/spinner';
import * as Tooltip from '@cio/ui/base/tooltip';
import * as DropdownMenu from '@cio/ui/base/dropdown-menu';
import * as ButtonGroup from '@cio/ui/base/button-group';
import { Kbd } from '@cio/ui/base/kbd';
import { FIELDS } from './fields';
const { Story } = defineMeta({
title: 'Molecules/InputGroup',
component: InputGroup.Root,
parameters: {
layout: 'centered',
controls: {
include: FIELDS
}
},
tags: ['autodocs']
});
let email = $state('');
let password = $state('');
let showPassword = $state(false);
let apiKey = $state('');
let searchQuery = $state('');
let fileName = $state('');
let username = $state('');
let message = $state('');
let code = $state("console.log('Hello, world!');");
let customInput = $state('Autoresize textarea...');
let domain = $state('example.com');
let amount = $state('0.00');
let cardNumber = $state('');
let fileType = $state('txt');
</script>
<Story name="Icon">
{#snippet template()}
<div class="grid w-full max-w-sm gap-6">
<InputGroup.Root>
<InputGroup.Addon align="inline-start">
<SearchIcon />
</InputGroup.Addon>
<InputGroup.Input placeholder="Search..." />
</InputGroup.Root>
<InputGroup.Root>
<InputGroup.Addon align="inline-start">
<MailIcon />
</InputGroup.Addon>
<InputGroup.Input type="email" placeholder="Enter your email" />
</InputGroup.Root>
<InputGroup.Root>
<InputGroup.Addon align="inline-start">
<CreditCardIcon />
</InputGroup.Addon>
<InputGroup.Input placeholder="Card number" />
</InputGroup.Root>
<InputGroup.Root>
<InputGroup.Input placeholder="Card number" />
<InputGroup.Addon align="inline-end">
<StarIcon />
<InfoIcon />
</InputGroup.Addon>
</InputGroup.Root>
</div>
{/snippet}
</Story>
<Story name="Text">
{#snippet template()}
<div class="ui:flex ui:flex-col ui:gap-4 ui:w-96">
<InputGroup.Root>
<InputGroup.Addon align="inline-start">
<InputGroup.Text>https://</InputGroup.Text>
</InputGroup.Addon>
<InputGroup.Input placeholder="example.com" />
</InputGroup.Root>
<InputGroup.Root>
<InputGroup.Addon align="inline-start">
<InputGroup.Text>$</InputGroup.Text>
</InputGroup.Addon>
<InputGroup.Input type="number" placeholder="0.00" />
</InputGroup.Root>
<InputGroup.Root>
<InputGroup.Addon align="inline-start">
<InputGroup.Text>@</InputGroup.Text>
</InputGroup.Addon>
<InputGroup.Input placeholder="Enter your username" />
</InputGroup.Root>
<InputGroup.Root>
<InputGroup.Addon align="block-start">
<InputGroup.Text>Note</InputGroup.Text>
</InputGroup.Addon>
<InputGroup.Textarea placeholder="Enter your message" />
</InputGroup.Root>
</div>
{/snippet}
</Story>
<Story name="Button">
{#snippet template()}
<div class="ui:flex ui:flex-col ui:gap-4 ui:w-96">
<InputGroup.Root>
<InputGroup.Input placeholder="https://x.com/shadcn" />
<InputGroup.Addon align="inline-end">
<InputGroup.Button>
<CopyIcon />
</InputGroup.Button>
</InputGroup.Addon>
</InputGroup.Root>
<InputGroup.Root>
<InputGroup.Input placeholder="Type to search..." />
<InputGroup.Addon align="inline-end">
<InputGroup.Button>
<SearchIcon />
</InputGroup.Button>
</InputGroup.Addon>
</InputGroup.Root>
</div>
{/snippet}
</Story>
<Story name="Tooltip">
{#snippet template()}
<div class="ui:flex ui:flex-col ui:gap-4 ui:w-96">
<InputGroup.Root>
<InputGroup.Addon align="inline-start">
<LockIcon />
</InputGroup.Addon>
<InputGroup.Input type={showPassword ? 'text' : 'password'} placeholder="Enter password" />
<InputGroup.Addon align="inline-end">
<Tooltip.Provider>
<Tooltip.Root>
<Tooltip.Trigger>
{#snippet child({ props })}
<InputGroup.Button
{...props}
onclick={() => (showPassword = !showPassword)}
aria-label={showPassword ? 'Hide password' : 'Show password'}
>
{#if showPassword}
<EyeOffIcon />
{:else}
<EyeIcon />
{/if}
</InputGroup.Button>
{/snippet}
</Tooltip.Trigger>
<Tooltip.Content>{showPassword ? 'Hide password' : 'Show password'}</Tooltip.Content>
</Tooltip.Root>
</Tooltip.Provider>
</InputGroup.Addon>
</InputGroup.Root>
<InputGroup.Root>
<InputGroup.Addon align="inline-start">
<MailIcon />
</InputGroup.Addon>
<InputGroup.Input type="email" placeholder="Your email address" />
<InputGroup.Addon align="inline-end">
<Tooltip.Provider>
<Tooltip.Root>
<Tooltip.Trigger>
{#snippet child({ props })}
<InputGroup.Button {...props} aria-label="Help">
<MessageSquareIcon />
</InputGroup.Button>
{/snippet}
</Tooltip.Trigger>
<Tooltip.Content>We'll never share your email</Tooltip.Content>
</Tooltip.Root>
</Tooltip.Provider>
</InputGroup.Addon>
</InputGroup.Root>
<InputGroup.Root>
<InputGroup.Addon align="inline-start">
<KeyIcon />
</InputGroup.Addon>
<InputGroup.Input type="password" placeholder="Enter API key" />
<InputGroup.Addon align="inline-end">
<Tooltip.Provider>
<Tooltip.Root>
<Tooltip.Trigger>
{#snippet child({ props })}
<InputGroup.Button {...props} aria-label="Generate API key">
<KeyIcon />
</InputGroup.Button>
{/snippet}
</Tooltip.Trigger>
<Tooltip.Content>Generate a new API key</Tooltip.Content>
</Tooltip.Root>
</Tooltip.Provider>
</InputGroup.Addon>
</InputGroup.Root>
</div>
{/snippet}
</Story>
<Story name="Textarea">
{#snippet template()}
<div class="ui:flex ui:flex-col ui:gap-4 ui:w-96">
<InputGroup.Root>
<InputGroup.Addon align="block-start">
<InputGroup.Text>Code</InputGroup.Text>
</InputGroup.Addon>
<InputGroup.Textarea placeholder="console.log('Hello, world!');" />
</InputGroup.Root>
<InputGroup.Root>
<InputGroup.Addon align="block-end">
<InputGroup.Text>Note</InputGroup.Text>
</InputGroup.Addon>
<InputGroup.Textarea placeholder="Enter your message" />
</InputGroup.Root>
</div>
{/snippet}
</Story>
<Story name="Spinner">
{#snippet template()}
<div class="grid w-full max-w-sm gap-4">
<InputGroup.Root data-disabled>
<InputGroup.Input placeholder="Searching..." disabled />
<InputGroup.Addon align="inline-end">
<Spinner />
</InputGroup.Addon>
</InputGroup.Root>
<InputGroup.Root data-disabled>
<InputGroup.Input placeholder="Processing..." disabled />
<InputGroup.Addon>
<Spinner />
</InputGroup.Addon>
</InputGroup.Root>
<InputGroup.Root data-disabled>
<InputGroup.Input placeholder="Saving changes..." disabled />
<InputGroup.Addon align="inline-end">
<InputGroup.Text>Saving...</InputGroup.Text>
<Spinner />
</InputGroup.Addon>
</InputGroup.Root>
<InputGroup.Root data-disabled>
<InputGroup.Input placeholder="Refreshing data..." disabled />
<InputGroup.Addon>
<LoaderIcon class="animate-spin" />
</InputGroup.Addon>
<InputGroup.Addon align="inline-end">
<InputGroup.Text class="text-muted-foreground">Please wait...</InputGroup.Text>
</InputGroup.Addon>
</InputGroup.Root>
</div>
{/snippet}
</Story>
<Story name="Label">
{#snippet template()}
<div class="grid w-full max-w-sm gap-4">
<InputGroup.Root>
<InputGroup.Input id="email" placeholder="shadcn" />
<InputGroup.Addon>
<Label for="email">@</Label>
</InputGroup.Addon>
</InputGroup.Root>
<InputGroup.Root>
<InputGroup.Input id="email-2" placeholder="shadcn@vercel.com" />
<InputGroup.Addon align="block-start">
<Label for="email-2" class="ui:text-foreground">Email</Label>
<Tooltip.Provider>
<Tooltip.Root>
<Tooltip.Trigger>
{#snippet child({ props })}
<InputGroup.Button
{...props}
variant="ghost"
aria-label="Help"
class="ms-auto rounded-full"
size="icon-xs"
>
<InfoIcon />
</InputGroup.Button>
{/snippet}
</Tooltip.Trigger>
<Tooltip.Content>
<p>We'll use this to send you notifications</p>
</Tooltip.Content>
</Tooltip.Root>
</Tooltip.Provider>
</InputGroup.Addon>
</InputGroup.Root>
</div>
{/snippet}
</Story>
<Story name="Dropdown">
{#snippet template()}
<div class="grid w-full max-w-sm gap-4">
<InputGroup.Root>
<InputGroup.Input placeholder="Enter file name" />
<InputGroup.Addon align="inline-end">
<DropdownMenu.Root>
<DropdownMenu.Trigger>
{#snippet child({ props })}
<InputGroup.Button {...props} variant="ghost" aria-label="More" size="icon-xs">
<MoreHorizontalIcon />
</InputGroup.Button>
{/snippet}
</DropdownMenu.Trigger>
<DropdownMenu.Content align="end">
<DropdownMenu.Item>Settings</DropdownMenu.Item>
<DropdownMenu.Item>Copy path</DropdownMenu.Item>
<DropdownMenu.Item>Open location</DropdownMenu.Item>
</DropdownMenu.Content>
</DropdownMenu.Root>
</InputGroup.Addon>
</InputGroup.Root>
<InputGroup.Root class="[--radius:1rem]">
<InputGroup.Input placeholder="Enter search query" />
<InputGroup.Addon align="inline-end">
<DropdownMenu.Root>
<DropdownMenu.Trigger>
{#snippet child({ props })}
<InputGroup.Button {...props} variant="ghost" class="!pe-1.5 text-xs">
Search In... <ChevronDownIcon class="size-3" />
</InputGroup.Button>
{/snippet}
</DropdownMenu.Trigger>
<DropdownMenu.Content align="end" class="[--radius:0.95rem]">
<DropdownMenu.Item>Documentation</DropdownMenu.Item>
<DropdownMenu.Item>Blog Posts</DropdownMenu.Item>
<DropdownMenu.Item>Changelog</DropdownMenu.Item>
</DropdownMenu.Content>
</DropdownMenu.Root>
</InputGroup.Addon>
</InputGroup.Root>
</div>
{/snippet}
</Story>
<Story name="Button Group">
{#snippet template()}
<div class="grid w-full max-w-sm gap-6">
<ButtonGroup.Root>
<ButtonGroup.Text>
<Label for="url">https://</Label>
</ButtonGroup.Text>
<InputGroup.Root>
<InputGroup.Input id="url" />
<InputGroup.Addon align="inline-end">
<Link2Icon />
</InputGroup.Addon>
</InputGroup.Root>
<ButtonGroup.Text>.com</ButtonGroup.Text>
</ButtonGroup.Root>
</div>
{/snippet}
</Story>
<Story name="Custom Input">
{#snippet template()}
<div class="w-lg grid gap-6">
<InputGroup.Root>
<textarea
data-slot="input-group-control"
class="field-sizing-content flex min-h-16 w-full resize-none rounded-md bg-transparent px-3 py-2.5 text-base outline-none transition-[color,box-shadow] md:text-sm"
placeholder="Autoresize textarea..."
></textarea>
<InputGroup.Addon align="block-end">
<InputGroup.Button class="ms-auto" size="sm" variant="default">Submit</InputGroup.Button>
</InputGroup.Addon>
</InputGroup.Root>
</div>
{/snippet}
</Story>