Skip to content

Commit 0d65e12

Browse files
authored
fix(web): notification styles & alignment (#968)
* fix(web): notification icon & indicator colors * fix(web): notification item text size & weights * fix(web): notification button styles * fix(web): notification filter styles * fix(web): Tab List styles * fix(web): link button styles * fix(web): vertical spacing in notifications sidebar * fix(web): notification sidebar link styles * refactor(web): change default button border radius to rounded instead of rounded-md * fix(web): Notification Item alignment with other elements * refactor(web): add tw color palettes for unraid-green & unraid-red
1 parent b2acde3 commit 0d65e12

File tree

9 files changed

+88
-68
lines changed

9 files changed

+88
-68
lines changed

web/components/Notifications/Indicator.vue

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ const icon = computed<{ component: Component; color: string } | null>(() => {
4343
case Importance.Alert:
4444
return {
4545
component: ShieldExclamationIcon,
46-
color: 'text-red-500',
46+
color: 'text-unraid-red',
4747
};
4848
}
4949
return null;
@@ -73,10 +73,10 @@ watch(overview, (newVal, oldVal) => {
7373
<div
7474
v-if="indicatorLevel"
7575
:class="
76-
cn('absolute top-0 right-0 size-2.5 rounded-full', {
76+
cn('absolute top-0 right-0 size-2.5 rounded-full border border-neutral-800', {
7777
'bg-unraid-red': indicatorLevel === Importance.Alert,
78-
'bg-yellow-500': indicatorLevel === Importance.Warning,
79-
'bg-green-500': indicatorLevel === 'UNREAD',
78+
'bg-yellow-accent': indicatorLevel === Importance.Warning,
79+
'bg-unraid-green': indicatorLevel === 'UNREAD',
8080
})
8181
"
8282
/>

web/components/Notifications/Item.vue

Lines changed: 22 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
<script setup lang="ts">
2+
import { Markdown } from '@/helpers/markdown';
23
import {
34
ArchiveBoxIcon,
45
CheckBadgeIcon,
@@ -14,15 +15,14 @@ import {
1415
archiveNotification as archiveMutation,
1516
deleteNotification as deleteMutation,
1617
} from './graphql/notification.query';
17-
import { Markdown } from '@/helpers/markdown';
1818
1919
const props = defineProps<NotificationFragmentFragment>();
2020
2121
const descriptionMarkup = computedAsync(async () => {
2222
try {
2323
return await Markdown.parse(props.description);
2424
} catch (e) {
25-
console.error(e)
25+
console.error(e);
2626
return props.description;
2727
}
2828
}, '');
@@ -32,17 +32,17 @@ const icon = computed<{ component: Component; color: string } | null>(() => {
3232
case 'INFO':
3333
return {
3434
component: CheckBadgeIcon,
35-
color: 'text-green-500',
35+
color: 'text-unraid-green',
3636
};
3737
case 'WARNING':
3838
return {
3939
component: ExclamationTriangleIcon,
40-
color: 'text-yellow-500',
40+
color: 'text-yellow-accent',
4141
};
4242
case 'ALERT':
4343
return {
4444
component: ShieldExclamationIcon,
45-
color: 'text-red-500',
45+
color: 'text-unraid-red',
4646
};
4747
}
4848
return null;
@@ -66,66 +66,57 @@ const mutationError = computed(() => {
6666
</script>
6767

6868
<template>
69-
<div class="group/item relative w-full py-4 pl-1 flex flex-col gap-2">
70-
<header
71-
class="w-full flex flex-row items-baseline justify-between gap-2 -translate-y-1 group-hover/item:font-medium group-focus/item:font-medium"
72-
>
73-
<h3
74-
class="text-muted-foreground text-[0.875rem] tracking-wide flex flex-row items-baseline gap-2 uppercase"
75-
>
69+
<!-- fixed width hack ensures alignment with other elements regardless of scrollbar presence or width -->
70+
<div class="group/item relative py-5 flex flex-col gap-2 text-base w-[487px]">
71+
<header class="w-full flex flex-row items-baseline justify-between gap-2 -translate-y-1">
72+
<h3 class="tracking-normal flex flex-row items-baseline gap-2 uppercase font-bold">
7673
<!-- the `translate` compensates for extra space added by the `svg` element when rendered -->
7774
<component
7875
:is="icon.component"
7976
v-if="icon"
80-
class="size-5 shrink-0 translate-y-1.5"
77+
class="size-5 shrink-0 translate-y-1"
8178
:class="icon.color"
8279
/>
8380
<span>{{ title }}</span>
8481
</h3>
8582

8683
<div class="shrink-0 flex flex-row items-baseline justify-end gap-2 mt-1">
87-
<p class="text-12px opacity-75">{{ formattedTimestamp }}</p>
84+
<p class="text-gray-500 text-sm">{{ formattedTimestamp }}</p>
8885
</div>
8986
</header>
9087

91-
<h4 class="group-hover/item:font-medium group-focus/item:font-medium">
88+
<h4 class="font-bold">
9289
{{ subject }}
9390
</h4>
9491

95-
<div
96-
class="w-full flex flex-row items-center justify-between gap-2 opacity-75 group-hover/item:opacity-100 group-focus/item:opacity-100"
97-
>
98-
<div class="text-secondary-foreground" v-html="descriptionMarkup" />
92+
<div class="w-full flex flex-row items-center justify-between gap-2">
93+
<div class="" v-html="descriptionMarkup" />
9994
</div>
10095

10196
<p v-if="mutationError" class="text-red-600">Error: {{ mutationError }}</p>
10297

103-
<div class="flex justify-end items-baseline gap-2">
98+
<div class="flex justify-end items-baseline gap-4">
10499
<a v-if="link" :href="link">
105-
<Button type="button" variant="outline" size="xs">
106-
<LinkIcon class="size-3 mr-1 text-muted-foreground/80" />
107-
<span class="text-sm text-muted-foreground mt-0.5">View</span>
100+
<Button type="button" variant="outline">
101+
<LinkIcon class="size-4 mr-2" />
102+
<span class="text-sm">View</span>
108103
</Button>
109104
</a>
110105
<Button
111106
v-if="type === NotificationType.Unread"
112107
:disabled="archive.loading"
113-
class="relative z-20 rounded"
114-
size="xs"
115108
@click="archive.mutate"
116109
>
117-
<ArchiveBoxIcon class="size-3 mr-1" />
118-
<span class="text-sm mt-0.5">Archive</span>
110+
<ArchiveBoxIcon class="size-4 mr-2" />
111+
<span class="text-sm">Archive</span>
119112
</Button>
120113
<Button
121114
v-if="type === NotificationType.Archive"
122115
:disabled="deleteNotification.loading"
123-
class="relative z-20 rounded"
124-
size="xs"
125116
@click="deleteNotification.mutate"
126117
>
127-
<TrashIcon class="size-3 mr-1" />
128-
<span class="text-sm mt-0.5">Delete</span>
118+
<TrashIcon class="size-4 mr-2" />
119+
<span class="text-sm">Delete</span>
129120
</Button>
130121
</div>
131122
</div>

web/components/Notifications/List.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ async function onLoadMore() {
7777
<div
7878
v-if="notifications?.length > 0"
7979
v-infinite-scroll="[onLoadMore, { canLoadMore: () => canLoadMore }]"
80-
class="divide-y divide-gray-200 overflow-y-auto pl-7 pr-4 h-full"
80+
class="divide-y divide-gray-200 overflow-y-auto h-full pl-7"
8181
>
8282
<NotificationsItem
8383
v-for="notification in notifications"

web/components/Notifications/Sidebar.vue

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -33,22 +33,23 @@ const confirmAndDeleteAll = async () => {
3333
</SheetTrigger>
3434

3535
<!-- We remove the horizontal padding from the container to keep the NotificationList's scrollbar in the right place -->
36-
<SheetContent :to="teleportTarget" class="w-full sm:max-w-[540px] h-screen px-0">
37-
<div class="flex flex-col h-full gap-3">
38-
<SheetHeader class="ml-1 px-6 flex items-baseline gap-0">
36+
<SheetContent
37+
:to="teleportTarget"
38+
class="w-full max-w-[100vw] sm:max-w-[540px] h-screen px-0 bg-[#f2f2f2]"
39+
>
40+
<div class="flex flex-col h-full gap-5">
41+
<SheetHeader class="ml-1 px-6 flex items-baseline gap-1">
3942
<SheetTitle class="text-2xl">Notifications</SheetTitle>
4043
<a href="/Settings/Notifications">
41-
<Button variant="link" size="sm" class="text-muted-foreground text-base p-0">
42-
Edit Settings
43-
</Button>
44+
<Button variant="link" size="sm" class="p-0 h-auto"> Edit Settings </Button>
4445
</a>
4546
</SheetHeader>
4647

4748
<!-- min-h-0 prevents the flex container from expanding beyond its containing bounds. -->
4849
<!-- this is necessary because flex items have a default min-height: auto, -->
4950
<!-- which means they won't shrink below the height of their content, even if you use flex-1 or other flex properties. -->
5051
<Tabs default-value="unread" class="flex-1 flex flex-col min-h-0" activation-mode="manual">
51-
<div class="flex flex-row justify-between items-center flex-wrap gap-2 px-6">
52+
<div class="flex flex-row justify-between items-center flex-wrap gap-5 px-6">
5253
<TabsList class="ml-[1px]">
5354
<TabsTrigger value="unread"> Unread </TabsTrigger>
5455
<TabsTrigger value="archived"> Archived </TabsTrigger>
@@ -58,7 +59,7 @@ const confirmAndDeleteAll = async () => {
5859
:disabled="loadingArchiveAll"
5960
variant="link"
6061
size="sm"
61-
class="text-muted-foreground text-base p-0"
62+
class="text-foreground hover:text-destructive transition-none"
6263
@click="confirmAndArchiveAll"
6364
>
6465
Archive All
@@ -69,7 +70,7 @@ const confirmAndDeleteAll = async () => {
6970
:disabled="loadingDeleteAll"
7071
variant="link"
7172
size="sm"
72-
class="text-muted-foreground text-base p-0"
73+
class="text-foreground hover:text-destructive transition-none"
7374
@click="confirmAndDeleteAll"
7475
>
7576
Delete All
@@ -83,8 +84,8 @@ const confirmAndDeleteAll = async () => {
8384
}
8485
"
8586
>
86-
<SelectTrigger class="bg-secondary border-0 h-auto">
87-
<SelectValue class="text-muted-foreground" placeholder="Filter" />
87+
<SelectTrigger class="h-auto">
88+
<SelectValue class="text-gray-400 leading-6" placeholder="Filter By" />
8889
</SelectTrigger>
8990
<SelectContent :to="teleportTarget">
9091
<SelectGroup>
@@ -98,11 +99,11 @@ const confirmAndDeleteAll = async () => {
9899
</Select>
99100
</div>
100101

101-
<TabsContent value="unread" class="flex-1 min-h-0 mt-3">
102+
<TabsContent value="unread" class="flex-1 min-h-0 mt-5">
102103
<NotificationsList :importance="importance" :type="NotificationType.Unread" />
103104
</TabsContent>
104105

105-
<TabsContent value="archived" class="flex-1 min-h-0 mt-3">
106+
<TabsContent value="archived" class="flex-1 min-h-0 mt-5">
106107
<NotificationsList :importance="importance" :type="NotificationType.Archive" />
107108
</TabsContent>
108109
</Tabs>
Lines changed: 11 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,22 @@
1-
import { type VariantProps, cva } from 'class-variance-authority'
1+
import { cva, type VariantProps } from 'class-variance-authority';
22

3-
export { default as Button } from './Button.vue'
3+
export { default as Button } from './Button.vue';
44

55
export const buttonVariants = cva(
6-
'inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50',
6+
'inline-flex items-center justify-center whitespace-nowrap rounded text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50',
77
{
88
variants: {
99
variant: {
1010
default: 'bg-primary text-primary-foreground hover:bg-primary/90',
11-
destructive:
12-
'bg-destructive text-destructive-foreground hover:bg-destructive/90',
13-
outline:
14-
'border border-input bg-background hover:bg-accent hover:text-accent-foreground',
15-
secondary:
16-
'bg-secondary text-secondary-foreground hover:bg-secondary/80',
11+
destructive: 'bg-destructive text-destructive-foreground hover:bg-destructive/90',
12+
outline: 'border border-input bg-background hover:bg-accent hover:text-accent-foreground',
13+
secondary: 'bg-secondary text-secondary-foreground hover:bg-secondary/80',
1714
ghost: 'hover:bg-accent hover:text-accent-foreground',
1815
link: 'text-primary underline-offset-4 hover:underline',
1916
},
2017
size: {
21-
default: 'h-10 px-4 py-2',
22-
xs: 'h-7 rounded px-2',
18+
default: 'px-4 py-2',
19+
xs: 'h-7 px-2',
2320
sm: 'h-9 rounded-md px-3',
2421
lg: 'h-11 rounded-md px-8',
2522
icon: 'h-10 w-10',
@@ -29,7 +26,7 @@ export const buttonVariants = cva(
2926
variant: 'default',
3027
size: 'default',
3128
},
32-
},
33-
)
29+
}
30+
);
3431

35-
export type ButtonVariants = VariantProps<typeof buttonVariants>
32+
export type ButtonVariants = VariantProps<typeof buttonVariants>;

web/components/shadcn/select/SelectTrigger.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ const forwardedProps = useForwardProps(delegatedProps)
1919
<SelectTrigger
2020
v-bind="forwardedProps"
2121
:class="cn(
22-
'flex h-10 w-full items-center justify-between rounded-md border border-input bg-background px-3 py-2 text-base ring-offset-background placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 [&>span]:truncate text-start',
22+
'flex h-10 w-full items-center justify-between rounded-md border border-input bg-background px-4.5 py-3 text-base ring-offset-background placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 [&>span]:truncate text-start',
2323
props.class,
2424
)"
2525
>

web/components/shadcn/tabs/TabsList.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ const delegatedProps = computed(() => {
1616
<TabsList
1717
v-bind="delegatedProps"
1818
:class="cn(
19-
'inline-flex items-center justify-center rounded-md bg-muted p-1 text-muted-foreground',
19+
'inline-flex items-center justify-center rounded-md bg-input p-1.5 text-foreground',
2020
props.class,
2121
)"
2222
>

web/components/shadcn/tabs/TabsTrigger.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ const forwardedProps = useForwardProps(delegatedProps)
1818
<TabsTrigger
1919
v-bind="forwardedProps"
2020
:class="cn(
21-
'inline-flex items-center justify-center whitespace-nowrap rounded-sm px-3 py-1.5 text-base font-medium ring-offset-background transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:bg-background data-[state=active]:text-foreground data-[state=active]:shadow-sm',
21+
'inline-flex items-center justify-center whitespace-nowrap rounded px-4.5 py-2.5 text-sm font-medium ring-offset-background transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:bg-background data-[state=active]:text-foreground data-[state=active]:shadow-sm',
2222
props.class,
2323
)"
2424
>

web/tailwind.config.ts

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ import 'dotenv/config';
22
import type { Config } from 'tailwindcss';
33
import type { PluginAPI } from 'tailwindcss/types/config';
44

5-
65
// @ts-expect-error - just trying to get this to build @fixme
76
export default <Partial<Config>>{
87
darkMode: ['class'],
@@ -45,9 +44,40 @@ export default <Partial<Config>>{
4544
'grey-lightest': '#f2f2f2',
4645
white: '#ffffff',
4746

47+
// unraid colors
48+
'yellow-accent': '#E9BF41',
4849
'orange-dark': '#f15a2c',
4950
orange: '#ff8c2f',
50-
'unraid-red': '#E22828',
51+
// palettes generated from https://uicolors.app/create
52+
'unraid-red': {
53+
DEFAULT: '#E22828',
54+
'50': '#fef2f2',
55+
'100': '#ffe1e1',
56+
'200': '#ffc9c9',
57+
'300': '#fea3a3',
58+
'400': '#fc6d6d',
59+
'500': '#f43f3f',
60+
'600': '#e22828',
61+
'700': '#bd1818',
62+
'800': '#9c1818',
63+
'900': '#821a1a',
64+
'950': '#470808',
65+
},
66+
67+
'unraid-green': {
68+
DEFAULT: '#63A659',
69+
'50': '#f5f9f4',
70+
'100': '#e7f3e5',
71+
'200': '#d0e6cc',
72+
'300': '#aad1a4',
73+
'400': '#7db474',
74+
'500': '#63a659',
75+
'600': '#457b3e',
76+
'700': '#396134',
77+
'800': '#314e2d',
78+
'900': '#284126',
79+
'950': '#122211',
80+
},
5181

5282
alpha: 'var(--color-alpha)',
5383
beta: 'var(--color-beta)',
@@ -101,6 +131,7 @@ export default <Partial<Config>>{
101131
'30px': '30px',
102132
},
103133
spacing: {
134+
'4.5': '1.125rem',
104135
'-8px': '-8px',
105136
'2px': '2px',
106137
'4px': '4px',

0 commit comments

Comments
 (0)