avatar component
asd
This commit is contained in:
parent
40bf33a9e5
commit
f374c3aa4d
5 changed files with 146 additions and 18 deletions
56
src/lib/components/Datadisplay/Avatar.stories.svelte
Normal file
56
src/lib/components/Datadisplay/Avatar.stories.svelte
Normal file
|
|
@ -0,0 +1,56 @@
|
||||||
|
<script module lang="ts">
|
||||||
|
import { defineMeta } from '@storybook/addon-svelte-csf';
|
||||||
|
import type { ComponentProps } from 'svelte';
|
||||||
|
import Avatar from './Avatar.svelte';
|
||||||
|
|
||||||
|
const { Story } = defineMeta({
|
||||||
|
title: 'Data display/Avatar',
|
||||||
|
component: Avatar,
|
||||||
|
argTypes: {
|
||||||
|
img: {
|
||||||
|
control: 'text',
|
||||||
|
},
|
||||||
|
placeholder: {
|
||||||
|
control: 'text',
|
||||||
|
},
|
||||||
|
presence: {
|
||||||
|
control: 'select',
|
||||||
|
options: [undefined, 'online', 'offline'],
|
||||||
|
},
|
||||||
|
ring: {
|
||||||
|
control: 'select',
|
||||||
|
options: [
|
||||||
|
undefined,
|
||||||
|
'neutral',
|
||||||
|
'primary',
|
||||||
|
'secondary',
|
||||||
|
'accent',
|
||||||
|
'info',
|
||||||
|
'success',
|
||||||
|
'warning',
|
||||||
|
'error',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
shape: {
|
||||||
|
control: 'select',
|
||||||
|
options: ['square', 'circle'],
|
||||||
|
},
|
||||||
|
size: {
|
||||||
|
control: 'select',
|
||||||
|
options: ['xs', 'sm', 'md', 'lg'],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{#snippet template(props: ComponentProps<typeof Avatar>)}
|
||||||
|
<Avatar {...props} />
|
||||||
|
{/snippet}
|
||||||
|
|
||||||
|
<Story
|
||||||
|
name="Default"
|
||||||
|
args={{
|
||||||
|
img: 'https://img.daisyui.com/images/stock/photo-1534528741775-53994a69daeb.webp',
|
||||||
|
}}
|
||||||
|
children={template}
|
||||||
|
/>
|
||||||
62
src/lib/components/Datadisplay/Avatar.svelte
Normal file
62
src/lib/components/Datadisplay/Avatar.svelte
Normal file
|
|
@ -0,0 +1,62 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import type { DaisyColor, DaisySize } from '$lib/types';
|
||||||
|
import clsx from 'clsx';
|
||||||
|
import type { SvelteHTMLElements } from 'svelte/elements';
|
||||||
|
import { twMerge } from 'tailwind-merge';
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
img?: string;
|
||||||
|
placeholder: string;
|
||||||
|
presence?: 'online' | 'offline';
|
||||||
|
ring?: Exclude<DaisyColor, 'ghost'>;
|
||||||
|
shape?: 'square' | 'circle';
|
||||||
|
size?: DaisySize | 'md';
|
||||||
|
} & Omit<SvelteHTMLElements['div'], 'children'>;
|
||||||
|
|
||||||
|
let {
|
||||||
|
class: className,
|
||||||
|
img,
|
||||||
|
placeholder,
|
||||||
|
presence,
|
||||||
|
ring,
|
||||||
|
shape = 'circle',
|
||||||
|
size = 'md',
|
||||||
|
...props
|
||||||
|
}: Props = $props();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div {...props} class={twMerge('avatar', presence, clsx(className))} class:placeholder>
|
||||||
|
<div
|
||||||
|
class={twMerge(
|
||||||
|
'rounded-xl',
|
||||||
|
clsx({
|
||||||
|
'rounded-xl': shape === 'square',
|
||||||
|
'rounded-full': shape === 'circle',
|
||||||
|
'w-12': size === 'xs',
|
||||||
|
'w-16': size === 'sm',
|
||||||
|
'w-20': size === 'md',
|
||||||
|
'w-32': size === 'lg',
|
||||||
|
'avatar-ring ring ring-offset-2 ring-offset-base-100': !!ring,
|
||||||
|
})
|
||||||
|
)}
|
||||||
|
class:bg-neutral={placeholder}
|
||||||
|
class:ring-neutral={ring === 'neutral'}
|
||||||
|
class:ring-primary={ring === 'primary'}
|
||||||
|
class:ring-secondary={ring === 'secondary'}
|
||||||
|
class:ring-accent={ring === 'accent'}
|
||||||
|
class:ring-info={ring === 'info'}
|
||||||
|
class:ring-success={ring === 'success'}
|
||||||
|
class:ring-warning={ring === 'warning'}
|
||||||
|
class:ring-error={ring === 'error'}
|
||||||
|
>
|
||||||
|
{#if img}
|
||||||
|
<img src={img} alt={placeholder} />
|
||||||
|
{:else}
|
||||||
|
<span
|
||||||
|
class:text-3xl={size === 'lg'}
|
||||||
|
class:text-xl={size === 'md'}
|
||||||
|
class:text-xs={size === 'xs'}>{placeholder}</span
|
||||||
|
>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
1
src/lib/components/Datadisplay/index.ts
Normal file
1
src/lib/components/Datadisplay/index.ts
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
export { default as Avatar } from './Avatar.svelte';
|
||||||
|
|
@ -5,17 +5,15 @@
|
||||||
import { messages } from '$lib/i18n';
|
import { messages } from '$lib/i18n';
|
||||||
import 'clerk-sveltekit/client';
|
import 'clerk-sveltekit/client';
|
||||||
import SignOutButton from 'clerk-sveltekit/client/SignOutButton.svelte';
|
import SignOutButton from 'clerk-sveltekit/client/SignOutButton.svelte';
|
||||||
import { Cog, LogOut, MessageCircleMore, UsersRound } from 'lucide-svelte';
|
import { Cog, LogOut, Menu, MessageCircleMore, UsersRound } from 'lucide-svelte';
|
||||||
import type { Snippet } from 'svelte';
|
import type { Snippet } from 'svelte';
|
||||||
import { onMount } from 'svelte';
|
import { onMount } from 'svelte';
|
||||||
import type { LayoutData } from './$types';
|
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
children: Snippet;
|
children: Snippet;
|
||||||
data: LayoutData;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let { children, data }: Props = $props();
|
let { children }: Props = $props();
|
||||||
|
|
||||||
let clerk;
|
let clerk;
|
||||||
|
|
||||||
|
|
@ -45,22 +43,17 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
let message = $derived(messages.nav_greeting({ name: data.user.name }));
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#snippet userMenu()}
|
{#snippet userMenu()}
|
||||||
<div class="dropdown dropdown-end">
|
<div class="dropdown dropdown-end">
|
||||||
<div tabindex="0" role="button" class="btn btn-circle btn-primary btn-sm ring">
|
<div
|
||||||
<div class="avatar placeholder online">
|
tabindex={0}
|
||||||
<div class="w-8 rounded-full">
|
role="button"
|
||||||
{#if data.user.hasImage}
|
class="btn btn-primary btn-md flex items-center gap-2 text-lg"
|
||||||
<img src={data.user.imageUrl} alt="Avatar" />
|
>
|
||||||
{:else}
|
<Menu />
|
||||||
<span>{data.user.name.at(0)}</span>
|
Menu
|
||||||
{/if}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<!-- svelte-ignore a11y_no_noninteractive_tabindex -->
|
<!-- svelte-ignore a11y_no_noninteractive_tabindex -->
|
||||||
<ul
|
<ul
|
||||||
|
|
@ -106,8 +99,7 @@
|
||||||
<h1 class="prose prose-2xl">Svelte</h1>
|
<h1 class="prose prose-2xl">Svelte</h1>
|
||||||
{/snippet}
|
{/snippet}
|
||||||
{#snippet end()}
|
{#snippet end()}
|
||||||
<div class="flex items-center gap-3">
|
<div class="flex items-center gap-4 pr-2">
|
||||||
<p class="prose prose-lg">{message}</p>
|
|
||||||
{@render userMenu()}
|
{@render userMenu()}
|
||||||
</div>
|
</div>
|
||||||
{/snippet}
|
{/snippet}
|
||||||
|
|
|
||||||
|
|
@ -1,2 +1,19 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
import { Avatar } from '$lib/components/Datadisplay';
|
||||||
|
import { messages } from '$lib/i18n';
|
||||||
|
import type { PageData } from './$types';
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
data: PageData;
|
||||||
|
};
|
||||||
|
|
||||||
|
let { data }: Props = $props();
|
||||||
|
|
||||||
|
let message = $derived(messages.nav_greeting({ name: data.user.name }));
|
||||||
|
let initials = $derived(data.user.name.split(' ').reduce((col, name) => col + name.at(0), ''));
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<div class="flex flex-col items-center gap-2">
|
||||||
|
<Avatar img={data.user.imageUrl} placeholder={initials} size="sm" ring="primary" />
|
||||||
|
<h1 class="prose prose-2xl">{message}</h1>
|
||||||
|
</div>
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue