Skip to content

Commit a3a9aa0

Browse files
Feat/metagram header (#133)
* feat: added metagram header primary linear gradient. * feat: added flash icon. * feat: added secondary state of header. * feat: added secondary state of header with menu. * chore: cleaned some code. * docs: updated component docs. --------- Co-authored-by: SoSweetHam <[email protected]>
1 parent e5a4770 commit a3a9aa0

File tree

4 files changed

+170
-29
lines changed

4 files changed

+170
-29
lines changed
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import type { ComponentProps } from "svelte";
2+
import Header from "./Header.svelte";
3+
4+
export default {
5+
title: "Fragments/Header",
6+
component: Header,
7+
tags: ["autodocs"],
8+
render: (args: {
9+
Component: Header;
10+
props: ComponentProps<typeof Header>;
11+
}) => ({
12+
Component: Header,
13+
props: args,
14+
}),
15+
};
16+
17+
export const Primary = {
18+
args: {
19+
variant: "primary",
20+
heading: "metagram",
21+
callback: () => alert("clicked"),
22+
},
23+
};
24+
25+
export const PrimaryWithNoFlash = {
26+
args: {
27+
variant: "primary",
28+
heading: "messages",
29+
},
30+
};
31+
32+
export const Secondary = {
33+
args: {
34+
variant: "secondary",
35+
heading: "Account",
36+
},
37+
};
38+
39+
export const SecondaryWithMenu = {
40+
args: {
41+
variant: "secondary",
42+
heading: "Account",
43+
callback: () => alert("menu clicked"),
44+
},
45+
};
46+
47+
export const Tertiary = {
48+
args: {
49+
variant: "tertiary",
50+
callback: () => alert("clicked"),
51+
},
52+
};
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
<script lang="ts">
2+
import { cn } from '$lib/utils';
3+
import {
4+
ArrowLeft01Icon,
5+
ArrowLeft02Icon,
6+
MoreVerticalIcon,
7+
ZapIcon
8+
} from '@hugeicons/core-free-icons';
9+
import { HugeiconsIcon } from '@hugeicons/svelte';
10+
import type { HTMLAttributes } from 'svelte/elements';
11+
12+
interface IHeaderProps extends HTMLAttributes<HTMLElement> {
13+
variant: 'primary' | 'secondary' | 'tertiary';
14+
heading?: string;
15+
callback?: () => void;
16+
}
17+
18+
const { variant, callback, heading, ...restProps }: IHeaderProps = $props();
19+
20+
const variantClasses = {
21+
primary: {
22+
text: 'text-transparent bg-clip-text bg-[image:var(--color-brand-gradient)]',
23+
background: ''
24+
},
25+
secondary: {
26+
text: '',
27+
background: ''
28+
},
29+
tertiary: {
30+
text: '',
31+
background: 'bg-white/60'
32+
}
33+
};
34+
35+
const backButton = {
36+
secondary: ArrowLeft01Icon,
37+
tertiary: ArrowLeft02Icon
38+
};
39+
40+
const menuButton = {
41+
primary: ZapIcon,
42+
secondary: MoreVerticalIcon,
43+
tertiary: MoreVerticalIcon
44+
};
45+
46+
const classes = $derived({
47+
common: cn('flex items-center justify-between p-4'),
48+
text: variantClasses[variant].text,
49+
background: variantClasses[variant].background
50+
});
51+
52+
const backButtonCallback = () => {
53+
window.history.back();
54+
};
55+
</script>
56+
57+
<header {...restProps} class={cn([classes.common, restProps.class])}>
58+
<span class="flex items-center gap-2">
59+
{#if variant !== 'primary'}
60+
<button
61+
class={cn([
62+
'cursor-pointer rounded-full p-2 hover:bg-gray-100',
63+
classes.background
64+
])}
65+
onclick={backButtonCallback}
66+
>
67+
<HugeiconsIcon
68+
icon={backButton[variant]}
69+
size={24}
70+
color="var(--color-black-500)"
71+
/>
72+
</button>
73+
{/if}
74+
{#if variant !== 'tertiary'}
75+
<h1 class={cn([classes.text])}>
76+
{heading}
77+
</h1>
78+
{/if}
79+
</span>
80+
{#if callback}
81+
<button
82+
class={cn(['cursor-pointer rounded-full p-2 hover:bg-gray-100', classes.background])}
83+
onclick={callback}
84+
>
85+
<HugeiconsIcon icon={menuButton[variant]} size={24} color="var(--color-black-500)" />
86+
</button>
87+
{/if}
88+
</header>
89+
90+
<!--
91+
@component
92+
@name Header
93+
@description Header fragment.
94+
@props
95+
- variant: Can be 'primary' for home screen header with a flash, 'secondary' without flash, or 'tertiary'.
96+
- heading: The main heading text.
97+
- callback: A function to be called when the header is clicked.
98+
@usage
99+
<script>
100+
import { Header } from "$lib/fragments";
101+
</script>
102+
103+
<Header variant="primary" heading="metagram" callback={() => alert("clicked")} />
104+
<Header variant="primary" heading="messages" />
105+
<Header variant="secondary" heading="Account" />
106+
<Header variant="secondary" heading="Account" callback={() => alert("clicked")} />
107+
<Header variant="tertiary" callback={() => alert("clicked")} />
108+
-->

platforms/metagram/src/lib/fragments/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
export { default as Header } from "./Header/Header.svelte";
12
export { default as BottomNav } from './BottomNav/BottomNav.svelte';
23
export { default as SettingsNavigationButton } from './SettingsNavigationButton/SettingsNavigationButton.svelte';
34
export { default as MessageInput } from './MessageInput/MessageInput.svelte';

platforms/metagram/src/lib/ui/Button/Button.svelte

Lines changed: 9 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import type { HTMLButtonAttributes } from 'svelte/elements';
44
55
interface IButtonProps extends HTMLButtonAttributes {
6-
variant?: 'primary' | 'secondary';
6+
variant?: 'primary' | 'danger';
77
isLoading?: boolean;
88
callback?: () => Promise<void> | void;
99
blockingClick?: boolean;
@@ -39,29 +39,13 @@
3939
};
4040
4141
const variantClasses = {
42-
primary: {
43-
background: 'bg-grey',
44-
text: 'text-black-800',
45-
border: 'border border-black-400'
46-
},
47-
secondary: {
48-
background: 'bg-brand-burnt-orange',
49-
text: 'text-white',
50-
border: 'border border-brand-burnt-orange-600'
51-
}
42+
primary: { background: 'bg-grey', text: 'text-black-800' },
43+
danger: { background: 'bg-red-500', text: 'text-white' }
5244
};
5345
5446
const disabledVariantClasses = {
55-
primary: {
56-
background: 'bg-grey/50',
57-
text: 'text-black-800/50',
58-
border: 'border border-black-400/50'
59-
},
60-
secondary: {
61-
background: 'bg-brand-burnt-orange/50',
62-
text: 'text-white/50',
63-
border: 'border border-brand-burnt-orange-600/50'
64-
}
47+
primary: { background: 'bg-grey/50', text: 'text-black-800/50' },
48+
danger: { background: 'bg-red-500/50', text: 'text-white/50' }
6549
};
6650
6751
const sizeVariant = {
@@ -80,9 +64,6 @@
8064
text: disabled
8165
? disabledVariantClasses[variant].text || variantClasses[variant].text
8266
: variantClasses[variant].text,
83-
border: disabled
84-
? disabledVariantClasses[variant].border || variantClasses[variant].border
85-
: variantClasses[variant].border,
8667
disabled: 'cursor-not-allowed'
8768
});
8869
</script>
@@ -94,7 +75,6 @@
9475
classes.common,
9576
classes.background,
9677
classes.text,
97-
classes.border,
9878
disabled && classes.disabled,
9979
restProps.class
10080
].join(' ')
@@ -118,12 +98,12 @@
11898
</div>
11999
</button>
120100

121-
<!--
101+
<!--
122102
@component
123103
export default Button
124104
@description
125105
This component is a button with a loading spinner that can be used to indicate that an action is being performed.
126-
106+
127107
@props
128108
- variant: The variant of the button. Default is `primary`.
129109
- size: The size of the button. Default is `md`.
@@ -132,13 +112,13 @@
132112
- blockingClick: A boolean to indicate if the button should block the click event while the callback function is being executed.
133113
- icon: A slot for an icon to be displayed inside the button.
134114
- ...restProps: Any other props that can be passed to a button element.
135-
115+
136116
@usage
137117
```html
138118
<script lang="ts">
139119
import * as Button from '$lib/ui/Button'
140120
</script>
141-
121+
142122
<Button.Action variant="primary" callback={() => console.log('clicked')}>
143123
Click me
144124
</Button.Action>

0 commit comments

Comments
 (0)