Skip to content

Commit

Permalink
component: error state (#12)
Browse files Browse the repository at this point in the history
* component: error state

* link

* explicit

---------

Co-authored-by: Davis SHYAKA <87414827+davis-shyaka@users.noreply.github.com>
  • Loading branch information
shyakadavis and shyakadavis authored Jul 19, 2024
1 parent 11c72e1 commit 49c51d1
Show file tree
Hide file tree
Showing 22 changed files with 1,005 additions and 16 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
"shiki": "^1.10.3",
"svelte": "^4.2.18",
"svelte-check": "^3.8.4",
"svelte-exmarkdown": "^3.0.5",
"svelte-meta-tags": "^3.1.2",
"tailwindcss": "^3.4.6",
"tslib": "^2.6.3",
Expand Down
651 changes: 651 additions & 0 deletions pnpm-lock.yaml

Large diffs are not rendered by default.

25 changes: 25 additions & 0 deletions src/app.css
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,15 @@
--gray-alpha-900: rgba(0, 0, 0, 0.61);
--gray-alpha-1000: rgba(0, 0, 0, 0.91);

--accents-1: #fafafa;
--accents-2: #eaeaea;
--accents-3: #999;
--accents-4: #888;
--accents-5: #666;
--accents-6: #444;
--accents-7: #333;
--accents-8: #111;

--contrast-fg: hsl(0 0% 100%);
--focus-color: var(--blue-700);

Expand Down Expand Up @@ -225,6 +234,15 @@
--gray-alpha-900: hsla(0, 0%, 100%, 0.61);
--gray-alpha-1000: hsla(0, 0%, 100%, 0.92);

--accents-1: #111;
--accents-2: #333;
--accents-3: #444;
--accents-4: #666;
--accents-5: #888;
--accents-6: #999;
--accents-7: #eaeaea;
--accents-8: #fafafa;

--focus-color: var(--blue-900);

/* Shadows */
Expand Down Expand Up @@ -258,3 +276,10 @@ html.dark .shiki span {
font-weight: var(--shiki-dark-font-weight) !important;
text-decoration: var(--shiki-dark-text-decoration) !important;
}

/*
The styles for ``
*/
.prose code:not(pre > code) {
@apply rounded-md border border-gray-300 bg-gray-100 px-[3.6px] py-0.5 font-mono text-sm before:content-[''] after:content-[''];
}
3 changes: 3 additions & 0 deletions src/lib/assets/icons/chart-bar-peak.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
67 changes: 67 additions & 0 deletions src/lib/assets/icons/error-states.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions src/lib/assets/icons/external-small.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 6 additions & 0 deletions src/lib/assets/icons/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import Bell from './bell.svg?component';
import Box from './box.svg?component';
import BrandAssets from './brand-assets.svg?component';
import CharBarMiddle from './chart-bar-middle.svg?component';
import ChartBarPeak from './chart-bar-peak.svg?component';
import CharTrendingDown from './chart-trending-down.svg?component';
import Check from './check.svg?component';
import ChevronLeft from './chevron-left.svg?component';
Expand All @@ -15,6 +16,8 @@ import CodeBracket from './code-bracket.svg?component';
import Command from './command.svg?component';
import Copy from './copy.svg?component';
import Database from './database.svg?component';
import ErrorStates from './error-states.svg?component';
import ExternalSmall from './external-small.svg?component';
import External from './external.svg?component';
import FileText from './file-text.svg?component';
import Flag from './flag.svg?component';
Expand Down Expand Up @@ -56,6 +59,7 @@ export const Icons = {
Box,
BrandAssets,
CharBarMiddle,
ChartBarPeak,
CharTrendingDown,
Check,
ChevronLeft,
Expand All @@ -66,6 +70,8 @@ export const Icons = {
Command,
Copy,
Database,
ErrorStates,
ExternalSmall,
External,
FileText,
Flag,
Expand Down
9 changes: 0 additions & 9 deletions src/lib/components/shared/demo-utils.ts

This file was deleted.

12 changes: 9 additions & 3 deletions src/lib/components/shared/demo.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@
import { Icons } from '$lib/assets/icons';
import { cn } from '$lib/utils';
import { onMount } from 'svelte';
import Markdown from 'svelte-exmarkdown';
import { scale } from 'svelte/transition';
import Accordion from './accordion-animation';
import { format_string, parse_back_ticks } from './demo-utils';
import { get_highlighted_code } from './shiki';
let class_name: string | undefined = undefined;
Expand All @@ -13,6 +13,11 @@
export let subtitle: string | undefined = undefined;
export { class_name as class };
// e.g. "with-icons" -> "With Icons"
function format_string(str: string) {
return str.replace(/-/g, ' ').replace(/\b\w/g, (char) => char.toUpperCase());
}
// Show/hide code details animation
const accordions: Accordion[] = [];
onMount(() => {
Expand Down Expand Up @@ -58,9 +63,10 @@
</a>
{#if subtitle}
<p
class="mt-2 leading-6 text-gray-900 xl:mt-4 [&>code]:rounded-md [&>code]:border [&>code]:border-gray-300 [&>code]:bg-gray-100 [&>code]:px-[3.6px] [&>code]:py-0.5 [&>code]:font-mono [&>code]:text-sm"
class="prose prose-neutral mt-2 max-w-none text-gray-900 dark:prose-invert marker:content-['-'] prose-strong:font-normal prose-strong:text-gray-1000 xl:mt-4"
>
{@html parse_back_ticks(subtitle)}
<Markdown md={subtitle} />
<slot name="image"></slot>
</p>
{/if}
<div
Expand Down
2 changes: 1 addition & 1 deletion src/lib/components/ui/badge/badge.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
{...$$restProps}
>
{#if icon}
<svelte:component this={icon} class="size-4" />
<svelte:component this={icon} aria-hidden="true" class="size-4" />
{/if}
<slot />
</svelte:element>
3 changes: 2 additions & 1 deletion src/lib/components/ui/button/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ const button_variants = tv({
variants: {
variant: {
default: 'bg-gray-1000 text-background-100',
secondary: 'border border-gray-alpha-400 bg-background-100 hover:bg-gray-alpha-100',
secondary:
'border border-gray-alpha-400 bg-background-100 text-gray-1000 hover:bg-gray-alpha-100',
tertiary: 'bg-transparent hover:bg-gray-alpha-200',
error: 'bg-red-800 text-contrast-fg hover:bg-red-900',
warning: 'active:bg-[#a35200; bg-amber-800 text-[#0a0a0a] hover:bg-[#d27504]'
Expand Down
32 changes: 32 additions & 0 deletions src/lib/components/ui/empty-state/empty-state.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<script lang="ts">
import { cn } from '$lib/utils.js';
import { type Props, badge_variants } from './index.js';
type $$Props = Props;
let class_name: string | undefined | null = undefined;
export let variant: $$Props['variant'] = undefined;
export let title: $$Props['title'];
export let description: $$Props['description'];
export let icon_size: $$Props['icon_size'] = 32;
export { class_name as class };
export let icon: $$Props['icon'] = undefined;
$: icon_parent_size = icon_size ? icon_size + 28 : 32;
</script>

<div class={cn(badge_variants({ variant, className: class_name }))} {...$$restProps}>
{#if icon}
<span
class="grid place-items-center rounded-lg border border-gray-alpha-400 bg-background-100 p-[14px]"
style="width: {icon_parent_size}px; height: {icon_parent_size}px;"
>
<svelte:component this={icon} aria-hidden="true" width={icon_size} height={icon_size} />
</span>
{/if}
<div class="grid place-items-center gap-2">
<p class="text-lg font-medium text-gray-1000">{title}</p>
<p class="text-balance text-sm">{description}</p>
</div>
<slot></slot>
</div>
22 changes: 22 additions & 0 deletions src/lib/components/ui/empty-state/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import type { Icons } from '$lib/assets/icons';
import { type VariantProps, tv } from 'tailwind-variants';

export { default as EmptyState } from './empty-state.svelte';

export const badge_variants = tv({
base: 'grid place-items-center gap-4 text-gray-900',
variants: {
variant: {}
},
defaultVariants: {}
});

type Variant = VariantProps<typeof badge_variants>['variant'];

export type Props = {
variant?: Variant;
icon?: typeof Icons.Shield;
title: string;
description: string;
icon_size?: number;
};
38 changes: 38 additions & 0 deletions src/lib/components/ui/link/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import type { Button as LinkPrimitive } from 'bits-ui';
import { type VariantProps, tv } from 'tailwind-variants';
import Link from './link.svelte';

const link_variants = tv({
base: 'inline-flex select-none items-center justify-center gap-x-1 whitespace-nowrap rounded-md text-sm font-medium ring-offset-background-200 transition-[background,color,transform,box-shadow] ease-in-out focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-focus-color focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:text-gray-700 [&>svg]:size-3',
variants: {
variant: {
default: '',
secondary: 'text-accents-5 hover:text-gray-1000',
tertiary: '',
error: '',
warning: ''
}
},
defaultVariants: {
variant: 'default'
}
});

type Variant = VariantProps<typeof link_variants>['variant'];

type Props = LinkPrimitive.Props & {
variant?: Variant;
external?: boolean;
href: string;
};

type Events = LinkPrimitive.Events;

export {
Link,
link_variants,
type Events as ButtonEvents,
type Props as ButtonProps,
type Events,
type Props
};
32 changes: 32 additions & 0 deletions src/lib/components/ui/link/link.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<script lang="ts">
import { Icons } from '$lib/assets/icons/index.js';
import { cn } from '$lib/utils.js';
import { Button as LinkPrimitive } from 'bits-ui';
import { type Events, type Props, link_variants } from './index.js';
type $$Props = Props;
type $$Events = Events;
let class_name: $$Props['class'] = undefined;
export let variant: $$Props['variant'] = 'default';
export let href: $$Props['href'];
export let builders: $$Props['builders'] = [];
export let external: $$Props['external'] = false;
export { class_name as class };
</script>

<LinkPrimitive.Root
{builders}
class={cn(link_variants({ variant, className: class_name }))}
{href}
target={external ? '_blank' : undefined}
rel={external ? 'noopener noreferrer' : undefined}
{...$$restProps}
on:click
on:keydown
>
<slot />
{#if external}
<Icons.External aria-hidden="true" />
{/if}
</LinkPrimitive.Root>
2 changes: 1 addition & 1 deletion src/lib/config/sitemap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ export const aside_items: Aside = {
{
title: 'Empty State',
href: '/empty-state',
status: 'soon'
status: 'draft'
},
{
title: 'Error',
Expand Down
43 changes: 42 additions & 1 deletion src/routes/empty-state/+page.svelte
Original file line number Diff line number Diff line change
@@ -1 +1,42 @@
<h1>empty-state</h1>
<script lang="ts">
import { Icons } from '$lib/assets/icons';
import Demo from '$lib/components/shared/demo.svelte';
import PageWrapper from '$lib/components/shared/page-wrapper.svelte';
import BlankSlate from './blank-slate.svelte';
import blank_slate_code from './blank-slate.svelte?raw';
import EmptyStateDesignFramework from './empty-state-design-framework.svelte';
import empty_state_design_framework_code from './empty-state-design-framework.svelte?raw';
import Informational from './informational.svelte';
import informational_code from './informational.svelte?raw';
export let data;
const empty_state_design_framework_subtitle =
'When designed thoughtfully, empty states become an essential part of a smooth user experience, providing enough context to keep users working in a productive way. There are several approaches to explore that will match the needs a developer in different situations:\n- __Blank Slate__ - Basic empty state for first run experience\n- __Informational__ - Alternative for first use empty state, including in-line CTAs and supplemental documentation links\n- __Educational__ - Launch a contextual onboarding flow to gain deeper understanding about that area of the app\n- __Guide__ - Starter content that allows users to interact with data and learn the system by tinkering or setting up their environment';
const informational_subtitle =
'Help users by clearly explaining the benefit and utility of a product or feature, with a call to action and link to more information to help users progress.\n\nDefault to showing rather than telling the value of a feature. Certain entry points to a product may call for a unique empty state and a call to upgrade. Informational empty states will include a call to action.';
</script>

<PageWrapper title={data.title} description={data.description}>
<Demo
id="empty-state-design-framework"
subtitle={empty_state_design_framework_subtitle}
code={empty_state_design_framework_code}
>
<Icons.ErrorStates aria-hidden="true" slot="image" />
<EmptyStateDesignFramework />
</Demo>

<Demo
id="blank-slate"
subtitle="The most basic empty state should convey the state of the view."
code={blank_slate_code}
>
<BlankSlate />
</Demo>

<Demo id="informational" subtitle={informational_subtitle} code={informational_code}>
<Informational />
</Demo>
</PageWrapper>
22 changes: 22 additions & 0 deletions src/routes/empty-state/+page.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import type { MetaTagsProps } from 'svelte-meta-tags';

export function load() {
const title = 'Empty State';
const description =
'Fill spaces when no content has been added yet, or is temporarily empty due to the nature of the feature and should be designed to prevent confusion.';

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

return {
pageMetaTags,
title,
description
};
}
11 changes: 11 additions & 0 deletions src/routes/empty-state/blank-slate.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<script lang="ts">
import { Icons } from '$lib/assets/icons';
import { EmptyState } from '$lib/components/ui/empty-state';
</script>

<EmptyState
title="Title"
description="A message conveying the state of the product."
icon={Icons.ChartBarPeak}
icon_size={32}
/>
11 changes: 11 additions & 0 deletions src/routes/empty-state/empty-state-design-framework.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<script lang="ts">
import { Icons } from '$lib/assets/icons';
import { EmptyState } from '$lib/components/ui/empty-state';
</script>

<EmptyState
title="Title"
description="A message conveying the state of the product."
icon={Icons.ChartBarPeak}
icon_size={32}
/>
Loading

0 comments on commit 49c51d1

Please sign in to comment.