Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 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
2 changes: 1 addition & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
}
},
"[svelte]": {
"editor.defaultFormatter": "biomejs.biome",
"editor.defaultFormatter": "svelte.svelte-vscode",
"editor.codeActionsOnSave": {
"source.organizeImports.biome": "explicit",
"source.fixAll.biome": "explicit"
Expand Down
52 changes: 52 additions & 0 deletions platforms/metagram/src/lib/fragments/Header/Header.stories.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import type { ComponentProps } from "svelte";
import Header from "./Header.svelte";

export default {
title: "Fragments/Header",
component: Header,
tags: ["autodocs"],
render: (args: {
Component: Header;
props: ComponentProps<typeof Header>;
}) => ({
Component: Header,
props: args,
}),
};

export const Primary = {
args: {
variant: "primary",
heading: "metagram",
callback: () => alert("clicked"),
},
};

export const PrimaryWithNoFlash = {
args: {
variant: "primary",
heading: "messages",
},
};

export const Secondary = {
args: {
variant: "secondary",
heading: "Account",
},
};

export const SecondaryWithMenu = {
args: {
variant: "secondary",
heading: "Account",
callback: () => alert("menu clicked"),
},
};

export const Tertiary = {
args: {
variant: "tertiary",
callback: () => alert("clicked"),
},
};
108 changes: 108 additions & 0 deletions platforms/metagram/src/lib/fragments/Header/Header.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
<script lang="ts">
import { cn } from '$lib/utils';
import {
ArrowLeft01Icon,
ArrowLeft02Icon,
MoreVerticalIcon,
ZapIcon
} from '@hugeicons/core-free-icons';
import { HugeiconsIcon } from '@hugeicons/svelte';
import type { HTMLAttributes } from 'svelte/elements';

interface IHeaderProps extends HTMLAttributes<HTMLElement> {
variant: 'primary' | 'secondary' | 'tertiary';
heading?: string;
callback?: () => void;
}

const { variant, callback, heading, ...restProps }: IHeaderProps = $props();

const variantClasses = {
primary: {
text: 'text-transparent bg-clip-text bg-[image:var(--color-brand-gradient)]',
background: ''
},
secondary: {
text: '',
background: ''
},
tertiary: {
text: '',
background: 'bg-white/60'
}
};

const backButton = {
secondary: ArrowLeft01Icon,
tertiary: ArrowLeft02Icon
};

const menuButton = {
primary: ZapIcon,
secondary: MoreVerticalIcon,
tertiary: MoreVerticalIcon
};

const classes = $derived({
common: cn('flex items-center justify-between p-4'),
text: variantClasses[variant].text,
background: variantClasses[variant].background
});

const backButtonCallback = () => {
window.history.back();
};
</script>

<header {...restProps} class={cn([classes.common, restProps.class])}>
<span class="flex items-center gap-2">
{#if variant !== 'primary'}
<button
class={cn([
'cursor-pointer rounded-full p-2 hover:bg-gray-100',
classes.background
])}
onclick={backButtonCallback}
>
<HugeiconsIcon
icon={backButton[variant]}
size={24}
color="var(--color-black-500)"
/>
</button>
{/if}
{#if variant !== 'tertiary'}
<h1 class={cn([classes.text])}>
{heading}
</h1>
{/if}
</span>
{#if callback}
<button
class={cn(['cursor-pointer rounded-full p-2 hover:bg-gray-100', classes.background])}
onclick={callback}
>
<HugeiconsIcon icon={menuButton[variant]} size={24} color="var(--color-black-500)" />
</button>
{/if}
Comment on lines +80 to +87
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Use Svelte event handlers and add accessibility attributes.

Replace onclick with Svelte's on:click directive and add appropriate aria attributes for better accessibility.

 <button
   class={cn(['cursor-pointer rounded-full p-2 hover:bg-gray-100', classes.background])}
-  onclick={callback}
+  on:click={callback}
+  aria-label="Menu"
 >
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
{#if callback}
<button
class={cn(['cursor-pointer rounded-full p-2 hover:bg-gray-100', classes.background])}
onclick={callback}
>
<HugeiconsIcon icon={menuButton[variant]} size={24} color="var(--color-black-500)" />
</button>
{/if}
{#if callback}
<button
class={cn(['cursor-pointer rounded-full p-2 hover:bg-gray-100', classes.background])}
on:click={callback}
aria-label="Menu"
>
<HugeiconsIcon icon={menuButton[variant]} size={24} color="var(--color-black-500)" />
</button>
{/if}

</header>

<!--
@component
@name Header
@description Header fragment.
@props
- variant: Can be 'primary' for home screen header with a flash, 'secondary' without flash, or 'tertiary'.
- heading: The main heading text.
- callback: A function to be called when the header is clicked.
@usage
<script>
import { Header } from "$lib/fragments";
</script>

<Header variant="primary" heading="metagram" callback={() => alert("clicked")} />
<Header variant="primary" heading="messages" />
<Header variant="secondary" heading="Account" />
<Header variant="secondary" heading="Account" callback={() => alert("clicked")} />
<Header variant="tertiary" callback={() => alert("clicked")} />
-->
1 change: 1 addition & 0 deletions platforms/metagram/src/lib/fragments/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default as Header } from "./Header/Header.svelte";
38 changes: 9 additions & 29 deletions platforms/metagram/src/lib/ui/Button/Button.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import type { HTMLButtonAttributes } from 'svelte/elements';

interface IButtonProps extends HTMLButtonAttributes {
variant?: 'primary' | 'secondary';
variant?: 'primary' | 'danger';
isLoading?: boolean;
callback?: () => Promise<void> | void;
blockingClick?: boolean;
Expand Down Expand Up @@ -39,29 +39,13 @@
};

const variantClasses = {
primary: {
background: 'bg-grey',
text: 'text-black-800',
border: 'border border-black-400'
},
secondary: {
background: 'bg-brand-burnt-orange',
text: 'text-white',
border: 'border border-brand-burnt-orange-600'
}
primary: { background: 'bg-grey', text: 'text-black-800' },
danger: { background: 'bg-red-500', text: 'text-white' }
};

const disabledVariantClasses = {
primary: {
background: 'bg-grey/50',
text: 'text-black-800/50',
border: 'border border-black-400/50'
},
secondary: {
background: 'bg-brand-burnt-orange/50',
text: 'text-white/50',
border: 'border border-brand-burnt-orange-600/50'
}
primary: { background: 'bg-grey/50', text: 'text-black-800/50' },
danger: { background: 'bg-red-500/50', text: 'text-white/50' }
};

const sizeVariant = {
Expand All @@ -80,9 +64,6 @@
text: disabled
? disabledVariantClasses[variant].text || variantClasses[variant].text
: variantClasses[variant].text,
border: disabled
? disabledVariantClasses[variant].border || variantClasses[variant].border
: variantClasses[variant].border,
disabled: 'cursor-not-allowed'
});
</script>
Expand All @@ -94,7 +75,6 @@
classes.common,
classes.background,
classes.text,
classes.border,
disabled && classes.disabled,
restProps.class
].join(' ')
Expand All @@ -118,12 +98,12 @@
</div>
</button>

<!--
<!--
@component
export default Button
@description
This component is a button with a loading spinner that can be used to indicate that an action is being performed.

@props
- variant: The variant of the button. Default is `primary`.
- size: The size of the button. Default is `md`.
Expand All @@ -132,13 +112,13 @@
- blockingClick: A boolean to indicate if the button should block the click event while the callback function is being executed.
- icon: A slot for an icon to be displayed inside the button.
- ...restProps: Any other props that can be passed to a button element.

@usage
```html
<script lang="ts">
import * as Button from '$lib/ui/Button'
</script>

<Button.Action variant="primary" callback={() => console.log('clicked')}>
Click me
</Button.Action>
Expand Down
Loading