Files
dejanandClaude Opus 5 b8bf987d0e feat(dashboard): Analytics-Dashboard als Gestaltungsvorlage zur Übergabe
UI/UX-Prototyp der Analytics-Dashboards in HiveGrid, fachlich auf einen
SHK-/Handwerksbetrieb zugeschnitten. Ziel ist die Übergabe an die Entwicklung,
nicht der Produktivbetrieb.

Inhalt: sechs Seiten (Übersicht, Finanzen, Aufträge, Kunden, Team, Komponenten),
26 KPIs, neun Chart-Bausteine, Filtersystem mit seitenabhängiger Relevanz und ein
deterministischer Demo-Datensatz (420 Kunden, 1.900 Aufträge, Stichtag 30.07.2026).

Drei Quellen sind zusammengeführt: die fachliche Planung mit dem Branchenpartner
(Januar 2026), die Subframe-Komponentenbibliothek aus dem HiveGrid-Pitch und
IBM Carbon Data Visualization für die Diagrammregeln. Herkunft und bewusste
Abweichungen stehen in docs/HERKUNFT.md.

Dokumentation: README, HANDOVER (was echte Logik braucht), docs/DESIGN-SYSTEM,
KPI-KATALOG, DATENMODELL, NAVIGATION, HERKUNFT, ZIELSYSTEM (Einbauort in
HiveGrid Cloud) und LEITPLANKEN (welche Cloud-Screens als Vorbild taugen).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QPeZNwSeU7qG3RRCwaxEZX
2026-08-29 17:25:20 +02:00

152 lines
5.0 KiB
TypeScript

"use client";
/*
* Documentation:
* Progress — https://app.subframe.com/f023064a5ca0/library?component=Progress_60964db0-a1bf-428b-b9d5-f34cdf58ea77
* Toast — https://app.subframe.com/f023064a5ca0/library?component=Toast_2c7966c2-a95d-468a-83fe-bf196b95be7a
*/
import React from "react";
import { FeatherAlertCircle } from "@subframe/core";
import { FeatherAlertTriangle } from "@subframe/core";
import { FeatherCheckCircle } from "@subframe/core";
import { FeatherInbox } from "@subframe/core";
import { FeatherInfo } from "@subframe/core";
import { FeatherX } from "@subframe/core";
import * as SubframeUtils from "../../utils";
import { Progress } from "../Progress";
export interface ToastRootProps
extends Omit<React.HTMLAttributes<HTMLDivElement>, "title"> {
variant?: "information" | "success" | "warning" | "error" | "neutral";
dismissible?: boolean;
hideProgress?: boolean;
hideUndo?: boolean;
title?: React.ReactNode;
description?: React.ReactNode;
progress?: number;
undoLabel?: React.ReactNode;
className?: string;
}
const ToastRoot = React.forwardRef<HTMLDivElement, ToastRootProps>(
function ToastRoot(
{
variant = "information",
dismissible = false,
hideProgress = false,
hideUndo = false,
title,
description,
progress = 30,
undoLabel,
className,
...otherProps
}: ToastRootProps,
ref
) {
return (
<div
className={SubframeUtils.twClassNames(
"group/2c7966c2 flex min-w-[384px] max-w-[448px] flex-col items-start gap-3 rounded-md border border-solid border-border-default bg-surface-neutral-secondary px-5 py-5 shadow-lg",
{ "gap-4": hideUndo },
className
)}
ref={ref}
{...otherProps}
>
<div className="flex w-full items-start gap-3">
<FeatherInfo
className={SubframeUtils.twClassNames(
"text-heading-0 font-heading-0 text-icon-feedback-information",
{
hidden:
variant === "neutral" ||
variant === "error" ||
variant === "warning" ||
variant === "success",
}
)}
/>
<FeatherCheckCircle
className={SubframeUtils.twClassNames(
"hidden text-heading-0 font-heading-0 text-icon-feedback-positive",
{ "inline-flex": variant === "success" }
)}
/>
<FeatherAlertTriangle
className={SubframeUtils.twClassNames(
"hidden text-heading-0 font-heading-0 text-icon-feedback-warning",
{ "inline-flex": variant === "warning" }
)}
/>
<FeatherAlertCircle
className={SubframeUtils.twClassNames(
"hidden text-heading-0 font-heading-0 text-icon-feedback-negative",
{ "inline-flex": variant === "error" }
)}
/>
<FeatherInbox
className={SubframeUtils.twClassNames(
"hidden text-heading-0 font-heading-0 text-icon-neutral-secondary",
{ "inline-flex": variant === "neutral" }
)}
/>
<div className="flex grow shrink-0 basis-0 flex-col items-start gap-4">
{title ? (
<span className="text-body-default-medium-0 font-body-default-medium-0 text-text-neutral-primary">
{title}
</span>
) : null}
{description ? (
<span className="text-body-default-regular-0 font-body-default-regular-0 text-text-neutral-secondary">
{description}
</span>
) : null}
</div>
<div
className={SubframeUtils.twClassNames(
"hidden items-center justify-center",
{ flex: dismissible }
)}
>
<FeatherX className="text-body-default-regular-0 font-body-default-regular-0 text-icon-neutral-primary" />
</div>
</div>
<div
className={SubframeUtils.twClassNames(
"flex w-full items-center gap-6",
{ "justify-end": hideProgress }
)}
>
<div
className={SubframeUtils.twClassNames(
"flex grow shrink-0 basis-0 items-center",
{ hidden: hideProgress }
)}
>
<Progress
hideLabel={true}
value={progress}
label="Uploading file"
statusText="30%"
/>
</div>
<div
className={SubframeUtils.twClassNames("flex items-start", {
hidden: hideUndo,
})}
>
{undoLabel ? (
<span className="text-body-default-medium-0 font-body-default-medium-0 text-text-feedback-link-default hover:text-text-feedback-link-hover">
{undoLabel}
</span>
) : null}
</div>
</div>
</div>
);
}
);
export const Toast = ToastRoot;