mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-29 14:08:11 +00:00
style: ui improvement to the notification cards.
This commit is contained in:
@@ -9,11 +9,13 @@ import {
|
||||
ScrollArea,
|
||||
Stack,
|
||||
Text,
|
||||
ThemeIcon,
|
||||
} from "@mantine/core";
|
||||
import { CheckCheck, Inbox, X } from "lucide-react";
|
||||
import { Bell, CheckCheck, Inbox, X } from "lucide-react";
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
|
||||
import { NotificationItem } from "./NotificationItem";
|
||||
import { edr } from "./PriorityTag";
|
||||
import type {
|
||||
NotificationItemData,
|
||||
ResolveNotificationVisual,
|
||||
@@ -73,36 +75,39 @@ function Sentinel({
|
||||
}
|
||||
|
||||
function SectionLabel({
|
||||
children,
|
||||
right,
|
||||
label,
|
||||
count,
|
||||
}: {
|
||||
children: React.ReactNode;
|
||||
right?: React.ReactNode;
|
||||
label: string;
|
||||
count?: number;
|
||||
}) {
|
||||
return (
|
||||
<Group
|
||||
justify="space-between"
|
||||
gap={8}
|
||||
px="md"
|
||||
py={6}
|
||||
py={8}
|
||||
wrap="nowrap"
|
||||
style={{
|
||||
position: "sticky",
|
||||
top: 0,
|
||||
zIndex: 1,
|
||||
background: "var(--mantine-color-body)",
|
||||
backdropFilter: "blur(6px)",
|
||||
background: edr.card,
|
||||
borderBottom: `1px solid ${edr.border}`,
|
||||
}}
|
||||
>
|
||||
<Text
|
||||
size="xs"
|
||||
fw={700}
|
||||
tt="uppercase"
|
||||
c="dimmed"
|
||||
style={{ letterSpacing: 0.6 }}
|
||||
style={{ color: edr.muted, letterSpacing: 0.6 }}
|
||||
>
|
||||
{children}
|
||||
{label}
|
||||
</Text>
|
||||
{right}
|
||||
{typeof count === "number" && count > 0 && (
|
||||
<Text size="xs" fw={600} style={{ color: edr.muted }}>
|
||||
{count}
|
||||
</Text>
|
||||
)}
|
||||
</Group>
|
||||
);
|
||||
}
|
||||
@@ -110,15 +115,16 @@ function SectionLabel({
|
||||
function LoadingRow() {
|
||||
return (
|
||||
<Group justify="center" py="md">
|
||||
<Loader size="xs" />
|
||||
<Loader size="xs" color="edr-green" />
|
||||
</Group>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Right slide-in notification center: an "Unread" section over an "Earlier"
|
||||
* (read) section, each with its own infinite-scroll trigger, in one scroll
|
||||
* surface. Presentational — the host wires data, paging, and the visual registry.
|
||||
* Right slide-in notification center, styled to the EDR design system: a
|
||||
* branded header, an "Unread" section over an "Earlier" (read) section, each
|
||||
* with its own infinite-scroll trigger in one scroll surface. Presentational —
|
||||
* the host wires data, paging, and the visual registry.
|
||||
*/
|
||||
export function NotificationDrawer({
|
||||
opened,
|
||||
@@ -138,7 +144,7 @@ export function NotificationDrawer({
|
||||
resolveVisual,
|
||||
emptyLabel = "You're all caught up",
|
||||
title = "Notifications",
|
||||
width = 420,
|
||||
width = 424,
|
||||
}: NotificationDrawerProps) {
|
||||
const [viewport, setViewport] = useState<HTMLElement | null>(null);
|
||||
const viewportRef = useRef<HTMLDivElement>(null);
|
||||
@@ -168,10 +174,14 @@ export function NotificationDrawer({
|
||||
size={width}
|
||||
padding={0}
|
||||
withCloseButton={false}
|
||||
overlayProps={{ backgroundOpacity: 0.35, blur: 2 }}
|
||||
transitionProps={{ transition: "slide-left" }}
|
||||
overlayProps={{ backgroundOpacity: 0.45, blur: 3 }}
|
||||
transitionProps={{ transition: "slide-left", duration: 220 }}
|
||||
styles={{
|
||||
content: { display: "flex", flexDirection: "column" },
|
||||
content: {
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
background: edr.card,
|
||||
},
|
||||
body: {
|
||||
flex: 1,
|
||||
minHeight: 0,
|
||||
@@ -184,18 +194,24 @@ export function NotificationDrawer({
|
||||
<Group
|
||||
justify="space-between"
|
||||
px="md"
|
||||
py="sm"
|
||||
py="md"
|
||||
wrap="nowrap"
|
||||
style={{
|
||||
borderBottom: "1px solid var(--mantine-color-default-border)",
|
||||
}}
|
||||
style={{ borderBottom: `1px solid ${edr.border}` }}
|
||||
>
|
||||
<Group gap="xs" wrap="nowrap">
|
||||
<Text fw={700} size="md">
|
||||
{title}
|
||||
</Text>
|
||||
<Group gap="sm" wrap="nowrap">
|
||||
<ThemeIcon variant="light" color="edr-green" radius="md" size={36}>
|
||||
<Bell size={18} strokeWidth={2} />
|
||||
</ThemeIcon>
|
||||
<Box>
|
||||
<Text fw={700} size="md" style={{ color: edr.text, lineHeight: 1.2 }}>
|
||||
{title}
|
||||
</Text>
|
||||
<Text size="xs" style={{ color: edr.muted }}>
|
||||
{totalUnread > 0 ? `${totalUnread} unread` : "All caught up"}
|
||||
</Text>
|
||||
</Box>
|
||||
{totalUnread > 0 && (
|
||||
<Badge color="red" variant="filled" size="sm" radius="sm">
|
||||
<Badge color="red" variant="filled" size="sm" radius="xl">
|
||||
{totalUnread > 99 ? "99+" : totalUnread}
|
||||
</Badge>
|
||||
)}
|
||||
@@ -205,7 +221,7 @@ export function NotificationDrawer({
|
||||
<Button
|
||||
variant="subtle"
|
||||
size="compact-xs"
|
||||
color="gray"
|
||||
color="edr-green"
|
||||
leftSection={<CheckCheck size={13} />}
|
||||
onClick={onMarkAllRead}
|
||||
>
|
||||
@@ -233,21 +249,23 @@ export function NotificationDrawer({
|
||||
{loading && unread.length === 0 && read.length === 0 ? (
|
||||
<LoadingRow />
|
||||
) : isEmpty ? (
|
||||
<Stack align="center" gap="xs" py={64} px="lg">
|
||||
<Inbox
|
||||
size={40}
|
||||
strokeWidth={1.4}
|
||||
color="var(--mantine-color-dimmed)"
|
||||
/>
|
||||
<Text c="dimmed" size="sm" ta="center">
|
||||
<Stack align="center" gap="sm" py={72} px="lg">
|
||||
<ThemeIcon variant="light" color="edr-green" radius="xl" size={56}>
|
||||
<Inbox size={26} strokeWidth={1.6} />
|
||||
</ThemeIcon>
|
||||
<Text size="sm" fw={600} style={{ color: edr.text }}>
|
||||
{emptyLabel}
|
||||
</Text>
|
||||
<Text size="xs" ta="center" style={{ color: edr.muted, maxWidth: 240 }}>
|
||||
New notifications about your bookings, clearances and invoices will
|
||||
show up here.
|
||||
</Text>
|
||||
</Stack>
|
||||
) : (
|
||||
<Box pb="md">
|
||||
{unread.length > 0 && (
|
||||
<>
|
||||
<SectionLabel>Unread</SectionLabel>
|
||||
<SectionLabel label="Unread" count={totalUnread} />
|
||||
<Stack gap={0}>{unread.map(renderItem)}</Stack>
|
||||
{hasMoreUnread && (
|
||||
<Sentinel
|
||||
@@ -261,7 +279,7 @@ export function NotificationDrawer({
|
||||
|
||||
{read.length > 0 && (
|
||||
<>
|
||||
<SectionLabel>Earlier</SectionLabel>
|
||||
<SectionLabel label="Earlier" />
|
||||
<Stack gap={0}>{read.map(renderItem)}</Stack>
|
||||
{hasMoreRead && (
|
||||
<Sentinel
|
||||
|
||||
Reference in New Issue
Block a user