diff --git a/src/components/admin/CardList.tsx b/src/components/admin/CardList.tsx new file mode 100644 index 0000000..6484236 --- /dev/null +++ b/src/components/admin/CardList.tsx @@ -0,0 +1,61 @@ +import { ReactNode } from "react"; + +interface CardListProps { + children: ReactNode; + ariaLabel?: string; +} + +export function CardList({ children, ariaLabel }: CardListProps) { + return ( + + ); +} + +interface CardListItemProps { + onClick?: () => void; + href?: string; + children: ReactNode; + as?: "li" | "div"; +} + +export function CardListItem({ onClick, href, children, as = "li" }: CardListItemProps) { + const content = ( +
+ {children} +
+ ); + + if (href) { + return ( +
  • + + {content} + +
  • + ); + } + if (onClick) { + return ( +
  • + +
  • + ); + } + return
  • {content}
  • ; +} diff --git a/src/components/admin/PageHeader.tsx b/src/components/admin/PageHeader.tsx new file mode 100644 index 0000000..086e149 --- /dev/null +++ b/src/components/admin/PageHeader.tsx @@ -0,0 +1,25 @@ +import { ReactNode } from "react"; + +interface PageHeaderProps { + title: string; + subtitle?: string; + actions?: ReactNode; +} + +export function PageHeader({ title, subtitle, actions }: PageHeaderProps) { + return ( +
    +
    +

    + {title} +

    + {subtitle && ( +

    {subtitle}

    + )} +
    + {actions &&
    {actions}
    } +
    + ); +} + +export default PageHeader; diff --git a/src/components/admin/StatusPill.tsx b/src/components/admin/StatusPill.tsx new file mode 100644 index 0000000..0e00b48 --- /dev/null +++ b/src/components/admin/StatusPill.tsx @@ -0,0 +1,35 @@ +export type StatusKind = "placed" | "ready" | "picked-up" | "cancelled" | "scheduled" | "in-transit" | "completed" | "low" | "out" | "in-stock" | "hidden"; + +const STATUS_MAP: Record = { + placed: { bg: "var(--color-info-soft)", fg: "var(--color-info)", label: "Placed" }, + ready: { bg: "var(--color-warning-soft)", fg: "var(--color-warning)", label: "Ready" }, + "picked-up": { bg: "var(--color-success-soft)", fg: "var(--color-success)", label: "Picked up" }, + cancelled: { bg: "var(--color-surface-2)", fg: "var(--color-text-muted)", label: "Cancelled" }, + scheduled: { bg: "var(--color-info-soft)", fg: "var(--color-info)", label: "Scheduled" }, + "in-transit": { bg: "var(--color-warning-soft)", fg: "var(--color-warning)", label: "In transit" }, + completed: { bg: "var(--color-success-soft)", fg: "var(--color-success)", label: "Completed" }, + low: { bg: "var(--color-warning-soft)", fg: "var(--color-warning)", label: "Low stock" }, + out: { bg: "var(--color-danger-soft)", fg: "var(--color-danger)", label: "Out" }, + "in-stock": { bg: "var(--color-success-soft)", fg: "var(--color-success)", label: "In stock" }, + hidden: { bg: "var(--color-surface-2)", fg: "var(--color-text-muted)", label: "Hidden" }, +}; + +interface StatusPillProps { + status: StatusKind; + label?: string; +} + +export function StatusPill({ status, label }: StatusPillProps) { + const cfg = STATUS_MAP[status]; + return ( + + {label ?? cfg.label} + + ); +} + +export default StatusPill; diff --git a/src/components/admin/StickyActionBar.tsx b/src/components/admin/StickyActionBar.tsx new file mode 100644 index 0000000..d4cc3cc --- /dev/null +++ b/src/components/admin/StickyActionBar.tsx @@ -0,0 +1,30 @@ +import { ReactNode } from "react"; + +interface StickyActionBarProps { + children: ReactNode; + pendingSync?: boolean; +} + +export function StickyActionBar({ children, pendingSync = false }: StickyActionBarProps) { + return ( +
    + {pendingSync && ( +
    + + Pending sync +
    + )} + {children} +
    + ); +} + +export default StickyActionBar;