Skip to content

Commit

Permalink
component: Skeleton (#58)
Browse files Browse the repository at this point in the history
* component: Skeleton

* imo, good to go

* .

* lint

* enforce no animation

---------

Co-authored-by: Davis SHYAKA <[email protected]>
  • Loading branch information
shyakadavis and shyakadavis authored Aug 22, 2024
1 parent f28080b commit ce7353d
Show file tree
Hide file tree
Showing 14 changed files with 205 additions and 2 deletions.
3 changes: 3 additions & 0 deletions src/lib/components/ui/skeleton/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import Root from './skeleton.svelte';

export { Root, Root as Skeleton };
52 changes: 52 additions & 0 deletions src/lib/components/ui/skeleton/skeleton.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
<script lang="ts">
import { cn } from '$lib/utils.js';
import type { HTMLAttributes } from 'svelte/elements';
type $$Props = HTMLAttributes<HTMLDivElement> & {
width?: number | string;
height?: number | string;
box_height?: number;
show?: boolean;
pill?: boolean;
rounded?: boolean;
squared?: boolean;
animated?: boolean;
};
let class_name: $$Props['class'] = undefined;
export { class_name as class };
export let width: $$Props['width'] = undefined;
export let height: $$Props['height'] = 24;
export let box_height: $$Props['box_height'] = undefined;
export let show: $$Props['show'] = true;
export let pill: $$Props['pill'] = false;
export let rounded: $$Props['rounded'] = false;
export let squared: $$Props['squared'] = false;
export let animated: $$Props['animated'] = true;
</script>

<span
style:--width={typeof width === 'number' ? `${width}px` : width}
style:--height={typeof height === 'number' ? `${height}px` : height}
style:--box-height="{box_height}px"
class={cn(
'block rounded-md motion-reduce:animate-none',
'animate-skeleton-loading bg-gradient-to-r from-accents-1 via-accents-2 to-accents-1 bg-[length:400%_100%]',
'mb-[calc(var(--box-height)-var(--height))] min-h-[var(--height)] w-[var(--width)]',
// TODO: If there is a way to apply class names to slots, it would save us the trouble of `[&>*]:after:` selectors
{
"relative [&>*]:pointer-events-none [&>*]:after:absolute [&>*]:after:inset-0 [&>*]:after:animate-skeleton-loading [&>*]:after:rounded-[4px] [&>*]:after:bg-gradient-to-r [&>*]:after:from-accents-1 [&>*]:after:via-accents-2 [&>*]:after:to-accents-1 [&>*]:after:bg-[length:400%_100%] [&>*]:after:content-['']":
show
},
{
'rounded-full': pill,
'rounded-[50%]': rounded,
'rounded-none': squared,
'!animate-none [&>*]:after:!animate-none': !animated
},
class_name
)}
{...$$restProps}
>
<slot></slot>
</span>
2 changes: 1 addition & 1 deletion src/lib/config/sitemap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@ export const aside_items: Aside = {
{
title: 'Skeleton',
href: '/skeleton',
status: 'soon'
status: 'draft'
},
{
title: 'Snippet',
Expand Down
65 changes: 64 additions & 1 deletion src/routes/skeleton/+page.svelte
Original file line number Diff line number Diff line change
@@ -1 +1,64 @@
<h1>skeleton</h1>
<script lang="ts">
import Demo from '$lib/components/shared/demo.svelte';
import PageWrapper from '$lib/components/shared/page-wrapper.svelte';
import DefaultWithBoxHeight from './default-with-box-height.svelte';
import default_with_box_height_code from './default-with-box-height.svelte?raw';
import DefaultWithSetWidth from './default-with-set-width.svelte';
import default_with_set_width_code from './default-with-set-width.svelte?raw';
import NoAnimation from './no-animation.svelte';
import no_animation_code from './no-animation.svelte?raw';
import Pill from './pill.svelte';
import pill_code from './pill.svelte?raw';
import Rounded from './rounded.svelte';
import rounded_code from './rounded.svelte?raw';
import Squared from './squared.svelte';
import squared_code from './squared.svelte?raw';
import WrappingChildrenWithFixedSize from './wrapping-children-with-fixed-size.svelte';
import wrapping_children_with_fixed_size_code from './wrapping-children-with-fixed-size.svelte?raw';
import WrappingChildren from './wrapping-children.svelte';
import wrapping_children_code from './wrapping-children.svelte?raw';
export let data;
</script>

<PageWrapper title={data.title} description={data.description}>
<Demo id="default-with-set-width" code={default_with_set_width_code}>
<DefaultWithSetWidth />
</Demo>

<Demo id="default-with-box-height" code={default_with_box_height_code}>
<DefaultWithBoxHeight />
</Demo>

<Demo
id="wrapping-children"
subtitle="If you do not pass a fixed size, it will be calculated automatically."
code={wrapping_children_code}
>
<WrappingChildren />
</Demo>

<Demo
id="wrapping-children-with-fixed-size"
subtitle="The skeleton will hide when children are not null, but the size is retained."
code={wrapping_children_with_fixed_size_code}
>
<WrappingChildrenWithFixedSize />
</Demo>

<Demo id="pill" code={pill_code}>
<Pill />
</Demo>

<Demo id="rounded" code={rounded_code}>
<Rounded />
</Demo>

<Demo id="squared" code={squared_code}>
<Squared />
</Demo>

<Demo id="no-animation" code={no_animation_code}>
<NoAnimation />
</Demo>
</PageWrapper>
21 changes: 21 additions & 0 deletions src/routes/skeleton/+page.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import type { MetaTagsProps } from 'svelte-meta-tags';

export function load() {
const title = 'Skeleton';
const description = 'Display a skeleton whilst another component is loading.';

const pageMetaTags = Object.freeze({
title,
description,
openGraph: {
title,
description
}
}) satisfies MetaTagsProps;

return {
pageMetaTags,
title,
description
};
}
5 changes: 5 additions & 0 deletions src/routes/skeleton/default-with-box-height.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<script lang="ts">
import { Skeleton } from '$lib/components/ui/skeleton';
</script>

<Skeleton width={160} box_height={42} />
5 changes: 5 additions & 0 deletions src/routes/skeleton/default-with-set-width.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<script lang="ts">
import { Skeleton } from '$lib/components/ui/skeleton';
</script>

<Skeleton width={160} />
5 changes: 5 additions & 0 deletions src/routes/skeleton/no-animation.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<script lang="ts">
import { Skeleton } from '$lib/components/ui/skeleton';
</script>

<Skeleton animated={false} height={100} width="100%" />
5 changes: 5 additions & 0 deletions src/routes/skeleton/pill.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<script lang="ts">
import { Skeleton } from '$lib/components/ui/skeleton';
</script>

<Skeleton pill width={48} />
5 changes: 5 additions & 0 deletions src/routes/skeleton/rounded.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<script lang="ts">
import { Skeleton } from '$lib/components/ui/skeleton';
</script>

<Skeleton rounded box_height={48} height={48} width={48} />
5 changes: 5 additions & 0 deletions src/routes/skeleton/squared.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<script lang="ts">
import { Skeleton } from '$lib/components/ui/skeleton';
</script>

<Skeleton squared box_height={48} height={48} width={48} />
11 changes: 11 additions & 0 deletions src/routes/skeleton/wrapping-children-with-fixed-size.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<script lang="ts">
import { Skeleton } from '$lib/components/ui/skeleton';
</script>

<div class="flex flex-col items-start gap-4">
<Skeleton height={100} width="100%" />

<!-- <Skeleton height={100} width="100%">
<Button>Not hidden by skeleton</Button>
</Skeleton> -->
</div>
14 changes: 14 additions & 0 deletions src/routes/skeleton/wrapping-children.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<script lang="ts">
import { Button } from '$lib/components/ui/button';
import { Skeleton } from '$lib/components/ui/skeleton';
</script>

<div class="flex flex-col items-start gap-4">
<Skeleton>
<Button>Hidden by skeleton</Button>
</Skeleton>

<Skeleton show={false}>
<Button>Not hidden by skeleton</Button>
</Skeleton>
</div>
9 changes: 9 additions & 0 deletions tailwind.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,15 @@ const config: Config = {
fontFamily: {
sans: ['Geist Sans, sans-serif', ...fontFamily.sans],
mono: ['Geist Mono, monospace', ...fontFamily.mono]
},
animation: {
'skeleton-loading': 'skeleton_loading 8s ease-in-out infinite'
},
keyframes: {
skeleton_loading: {
'0%': { backgroundPosition: '200% 0;' },
to: { backgroundPosition: '-200% 0;' }
}
}
}
},
Expand Down

0 comments on commit ce7353d

Please sign in to comment.