Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/settings panel styling #2987

Open
wants to merge 16 commits into
base: next
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -39,5 +39,6 @@ packages/ui/core-components/coverage
sites/docs/.evidence/meta/query-cache/hashes.json

priority_support_users.csv
.aider*

evidence-*.tgz
106 changes: 80 additions & 26 deletions packages/ui/core-components/src/lib/atoms/button/Button.stories.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -10,38 +10,92 @@

<script>
import { Story } from '@storybook/addon-svelte-csf';
import { ServerCog } from '@evidence-dev/component-utilities/icons';

/** @type {import('./Button.svelte').ButtonVariant[]} */
const variants = ['primary', 'secondary', 'accent', 'info', 'positive', 'warning', 'negative'];
const variants = ['default', 'primary', 'destructive', 'muted', 'ghost', 'link'];

/** @type {import('./Button.svelte').ButtonSize[]} */
const sizes = ['sm', 'md', 'base', 'lg'];
const sizes = ['default', 'lg', 'xl'];
</script>

const outlines = [false, true];
<Story name="All Variants">
{#each variants as variant}
<div class="w-full bg-base-200 px-2 py-1 text-sm rounded border mt-4">
<span class="capitalize">{variant}</span>
</div>
<div class="flex flex-col gap-4 py-4">
{#each sizes as size}
<div class="flex justify-between">
<Button {variant} {size}>Save</Button>
<span class="capitalize text-secondary">
{size}
</span>
</div>
{/each}
</div>
{/each}
</Story>

const disableds = [false, true];
</script>
<Story name="Icon Left">
{#each variants as variant}
<div class="w-full bg-base-200 px-2 py-1 text-sm rounded border mt-4">
<span class="capitalize">{variant}</span>
</div>
<div class="flex flex-col gap-4 py-4">
{#each sizes as size}
<div class="flex justify-between">
<Button {variant} {size} icon={ServerCog} iconPosition="left">Configure</Button>
<span class="capitalize text-secondary">
{size}
</span>
</div>
{/each}
</div>
{/each}
</Story>

<Story name="All">
<div class="grid grid-cols-3 gap-2">
<span />
{#each outlines as outline}
<code>outline={outline}</code>
{/each}
{#each variants as variant}
{#each disableds as disabled}
<code>disabled={disabled}</code>
{#each outlines as outline}
<div class="flex flex-col gap-1 p-1 bg-base-100">
{#each sizes as size}
<span>
<Button {variant} {disabled} {outline} {size}>Click me</Button>
</span>
{/each}
</div>
{/each}
<Story name="Icon Right">
{#each variants as variant}
<div class="w-full bg-base-200 px-2 py-1 text-sm rounded border mt-4">
<span class="capitalize">{variant}</span>
</div>
<div class="flex flex-col gap-4 py-4">
{#each sizes as size}
<div class="flex justify-between">
<Button {variant} {size} icon={ServerCog}>Configure</Button>
<span class="capitalize text-secondary">
{size}
</span>
</div>
{/each}
{/each}
</div>
<div style="height:200px" />
</div>
{/each}
</Story>

<Story name="Disabled">
{#each variants as variant}
<div class="w-full bg-base-200 px-2 py-1 text-sm rounded border mt-4">
<span class="capitalize">{variant}</span>
</div>
<div class="flex flex-col gap-4 py-4">
{#each sizes as size}
<div class="flex justify-between">
<Button {variant} {size} disabled>Save</Button>
<span class="capitalize text-secondary">
{size}
</span>
</div>
{/each}
</div>
{/each}
</Story>

<Story name="Custom Classes">
<span class="font-mono text-xs bg-base-200 w-full rounded px-2 py-1 border">
class='w-full mt-6'
</span>
{#each variants as variant}
<Button {variant} class="w-full mt-6">Save</Button>
{/each}
</Story>
207 changes: 65 additions & 142 deletions packages/ui/core-components/src/lib/atoms/button/Button.svelte
Original file line number Diff line number Diff line change
@@ -1,47 +1,11 @@
<script context="module">
export const evidenceInclude = true;

/** @typedef {"sm" | "md" | "base" | "lg"} ButtonSize */
/** @typedef {"primary" | "secondary" | "accent" | "info" | "positive" | "warning" | "negative"} ButtonVariant */
/** @typedef {"default" | "sm" | "lg" | "xl"} ButtonSize */
/** @typedef {"default" | "primary" | "destructive" | "muted" | "ghost" | "link"} ButtonVariant */
/** @typedef {"left" | "right"} ButtonIconPosition */
/** @typedef {boolean} ButtonOutline */

/** @type {Record<ButtonSize, string>}*/
const sizes = {
base: 'px-2 py-1 mx-1 gap-2',
md: 'px-2 py-1 mx-1 gap-2 text-xs',
sm: 'px-1 py-0.5 mx-0.5 gap-1 text-xs',
lg: 'px-4 py-2 mx-2 gap-4'
};

/** @type {Record<ButtonSize, string>}*/
const iconSizes = {
base: 'w-4',
md: 'w-4',
sm: 'w-3',
lg: 'w-5'
};

const DEPRECATED_VARIANTS_MAP = /** @type {const} */ ({
success: 'positive',
warn: 'warning',
error: 'negative'
});

const isDeprecatedVariant = (variant) => DEPRECATED_VARIANTS_MAP[variant] !== undefined;

const checkDeprecatedVariant = (variant) => {
if (isDeprecatedVariant(variant)) {
console.warn(
`The variant "${variant}" is deprecated. Please use "${DEPRECATED_VARIANTS_MAP[variant]}" instead.`
);
return DEPRECATED_VARIANTS_MAP[variant];
}
return variant;
};
</script>

<script>
import { tv } from 'tailwind-variants';
import { Icon } from '@steeze-ui/svelte-icon';
/** @type {import("@steeze-ui/svelte-icon").IconSource | undefined} */
export let icon = undefined;
Expand All @@ -50,134 +14,93 @@
export let iconPosition = 'right';

/** @type {ButtonSize} */
export let size = 'base';

/** @type {ButtonSize} */
export let iconSize = size;
export let size = 'default';

/** @type {ButtonVariant} */
export let variant = 'info';
$: variant = checkDeprecatedVariant(variant);

/** @type {boolean} */
export let outline = false;
export let variant = 'default';

/** @type {boolean} */
export let disabled = false;

/** @type {string | undefined} */
export let formaction = undefined;

/** @type {string | undefined | null} */
let className = undefined;

export { className as class };

/** @type {HTMLButtonAttributes["type"]} */
let _type = 'button';
export { _type as type };

$: if (formaction) _type = 'submit';

const buttonVariants = tv({
base: 'inline-flex items-center justify-center rounded-md text-xs font-medium whitespace-nowrap transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-base-300 disabled:pointer-events-none disabled:opacity-50',
variants: {
variant: {
default: 'bg-base-100 border shadow-sm hover:bg-base-200 active:bg-base-300',
primary:
'bg-primary text-primary-content shadow-sm hover:bg-primary/90 active:bg-primary/80',
destructive:
'bg-negative text-negative-content shadow-sm hover:bg-negative/90 active:bg-negative/80',
muted: 'bg-base-200 text-base-content hover:bg-base-300 active:bg-base-300/80',
ghost: 'hover:bg-base-200 hover:text-base-content',
link: 'text-base-content underline-offset-4 hover:underline'
},
size: {
default: 'h-8 px-3',
lg: 'h-8 px-10',
xl: 'h-10 px-10 text-sm'
}
},
defaultVariants: {
variant: 'default',
size: 'default'
}
});

const iconVariants = tv({
variants: {
variant: {
default: 'stroke-base-content',
primary: 'stroke-primary-content',
destructive: 'stroke-negative-content',
muted: 'stroke-base-content',
ghost: 'stroke-base-content',
link: 'stroke-base-content'
},
size: {
default: 'h-4 w-4',
lg: 'h-4 w-4',
xl: 'h-5 w-5'
},
iconPosition: {
left: 'mr-2',
right: 'ml-2'
}
},
defaultVariants: {
variant: 'default',
size: 'default',
iconPosition: 'left'
}
});
</script>

<button
type={_type}
{disabled}
{formaction}
on:click|stopPropagation
class:outlined={outline}
class="flex items-center transition-colors rounded variant-{variant} {sizes[size]}"
class={buttonVariants({ variant, size, className })}
>
{#if iconPosition === 'left' && icon}
<Icon src={icon} class={iconSizes[iconSize]} />
<Icon src={icon} class={iconVariants({ variant, size, iconPosition })} />
{/if}
<slot />
{#if iconPosition === 'right' && icon}
<Icon src={icon} class={iconSizes[iconSize]} />
<Icon src={icon} class={iconVariants({ variant, size, iconPosition })} />
{/if}
</button>

<style lang="postcss">
button {
&.variant-primary {
--bg: theme(colors.primary);
--text: theme(colors.primary-content);
&.outlined {
--border: theme(colors.primary);
--text: theme(colors.primary);
--hover-bg: theme(colors.primary / 0.1);
}
}

&.variant-secondary {
--bg: theme(colors.base-300);
--text: theme(colors.base-content);
&.outlined {
--border: theme(colors.base-300);
--text: theme(colors.base-300);
--hover-bg: theme(colors.base-300 / 0.1);
}
}

&.variant-accent {
--bg: theme(colors.accent);
--text: theme(colors.accent-content);
&.outlined {
--border: theme(colors.accent);
--text: theme(colors.accent);
--hover-bg: theme(colors.accent / 0.1);
}
}

&.variant-info {
--bg: theme(colors.info);
--text: theme(colors.info-content);
&.outlined {
--border: theme(colors.info);
--text: theme(colors.info);
--hover-bg: theme(colors.info / 0.1);
}
}

&.variant-positive {
--bg: theme(colors.positive);
--text: theme(colors.positive-content);
&.outlined {
--border: theme(colors.positive);
--text: theme(colors.positive);
--hover-bg: theme(colors.positive / 0.1);
}
}

&.variant-warning {
--bg: theme(colors.warning);
--text: theme(colors.warning-content);
&.outlined {
--border: theme(colors.warning);
--text: theme(colors.warning);
--hover-bg: theme(colors.warning / 0.1);
}
}

&.variant-negative {
--bg: theme(colors.negative);
--text: theme(colors.negative-content);
&.outlined {
--border: theme(colors.negative);
--text: theme(colors.negative);
--hover-bg: theme(colors.negative / 0.1);
}
}

@apply bg-[var(--bg)] border-[var(--border)] text-[var(--text)];

&.outlined {
@apply bg-transparent border;
&:not(:disabled) {
@apply hover:bg-[var(--hover-bg)];
}
}

&:disabled {
@apply cursor-not-allowed saturate-50 opacity-50;
}
&:not(:disabled) {
@apply transition-all duration-150 hover:brightness-105 active:brightness-95;
}
}
</style>
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@
export { className as class };
</script>

<AccordionPrimitive.Item {value} class={cn('border-b border-base-300', className)} {...$$restProps}>
<AccordionPrimitive.Item
{value}
class={cn('border-b border-base-300 only-of-type:border-none', className)}
{...$$restProps}
>
<slot />
</AccordionPrimitive.Item>
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
<slot />
<Icon
src={ChevronDown}
class="h-4 w-4 shrink-0 text-base-300 transition-transform duration-200"
class="h-4 w-4 shrink-0 text-base-content-muted transition-transform duration-200"
/>
</AccordionPrimitive.Trigger>
</AccordionPrimitive.Header>
Loading
Loading