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
This commit is contained in:
commit
b8bf987d0e
250 files changed
+33153
No files matched your search
@@ -0,0 +1,28 @@
|
||||
## Wann verwenden
|
||||
|
||||
Überall, wo eine postalische Adresse erfasst oder bearbeitet wird (Kontakt, Projekt, Lieferadresse, Baustelle, Rechnungsadresse). Immer diese Komponente statt eines eigenen Adressformulars — nur so bleibt Feldreihenfolge und Beschriftung im ganzen Produkt identisch.
|
||||
|
||||
## Feldreihenfolge ist nicht verhandelbar
|
||||
|
||||
Die Reihenfolge folgt DIN 5008 / DHL-Adresslogik, also der Reihenfolge, in der eine Adresse auf ein Label gedruckt wird: Firma → Name → Straße + Nr. → Adresszusatz → PLZ + Ort → Land. Nutzer tippen Adressen als zusammenhängenden Block ab; jede Umsortierung erzeugt Lesefehler und Zahlendreher. **Land steht immer zuletzt**, nie oben.
|
||||
|
||||
PLZ steht links vor dem Ort (DE/AT/CH-Konvention), Hausnummer rechts nach der Straße. Beide Paare bleiben in einer Zeile, damit sie als eine Information gelesen werden.
|
||||
|
||||
## Pflicht vs. optional
|
||||
|
||||
- Fachlich nötig für Versand und Routing: Name (oder Firma), Straße, Nr., PLZ, Ort, Land.
|
||||
- Optional und im Platzhalter als „(optional)" markiert: Firma, Adresszusatz. Adresszusatz nie für Straßendaten missbrauchen — er ist für Etage, Gebäude, c/o.
|
||||
|
||||
## Notiz zur Adresse
|
||||
|
||||
Interne Zustellinformation, kein Adressbestandteil: Zufahrt, Schlüsselübergabe, Parksituation, Torcode. Deshalb sitzt sie **unter der Trennlinie**, außerhalb des Adressblocks, und der Hilfetext sagt explizit, dass sie nicht auf Versandlabels gedruckt wird. Diese Trennung nicht auflösen und die Notiz nicht nach oben ziehen.
|
||||
|
||||
## Props im Einsatz
|
||||
|
||||
- `hideAddressType`: einschalten, wenn der Kontext den Typ schon festlegt (z. B. Dialog heißt „Rechnungsadresse ändern"). Doppelte Angabe derselben Information vermeiden.
|
||||
- `hideNote`: nur einschalten, wo keine Zustellung stattfindet (z. B. reine Rechnungsadresse).
|
||||
- `title` / `subtitle`: Titel benennt die Aktion („Adresse hinzufügen", „Lieferadresse bearbeiten"), der Untertitel sagt, wofür die Daten verwendet werden — nicht mit Bedienhinweisen füllen.
|
||||
|
||||
## Beschriftung
|
||||
|
||||
Labels bleiben kurz und in Nutzersprache („Nr.", nicht „Hausnummer/Zusatz"), Platzhalter zeigen ein echtes Beispiel („10115", „12a") statt einer Formatanweisung. Keine Sternchen für Pflichtfelder — optionale Felder werden markiert, nicht umgekehrt.
|
||||
@@ -0,0 +1,478 @@
|
||||
// @subframe/sync-disable
|
||||
// @ts-nocheck
|
||||
"use client";
|
||||
/*
|
||||
* Documentation:
|
||||
* Address Dialog — https://app.subframe.com/f023064a5ca0/library?component=Address+Dialog_b3a6c4d9-a908-4acc-881c-132a867b5ef6
|
||||
* Avatar — https://app.subframe.com/f023064a5ca0/library?component=Avatar_bec25ae6-5010-4485-b46b-cf79e3943ab2
|
||||
* Button — https://app.subframe.com/f023064a5ca0/library?component=Button_3b777358-b86b-40af-9327-891efc6826fe
|
||||
* Checkbox — https://app.subframe.com/f023064a5ca0/library?component=Checkbox_3816e3b5-c48c-499b-b45e-0777c6972523
|
||||
* Dialog — https://app.subframe.com/f023064a5ca0/library?component=Dialog_ca59db17-43fb-4247-8094-3c55162e902d
|
||||
* Icon Button — https://app.subframe.com/f023064a5ca0/library?component=Icon+Button_af9405b1-8c54-4e01-9786-5aad308224f6
|
||||
* Icon with Background — https://app.subframe.com/f023064a5ca0/library?component=Icon+with+Background_4a18e9fc-cea3-46ca-8c53-2412462342ad
|
||||
* Search Input — https://app.subframe.com/f023064a5ca0/library?component=Search+Input_75a35ed3-52c0-4435-8586-e390eb77d723
|
||||
* Select — https://app.subframe.com/f023064a5ca0/library?component=Select_bb88f90b-8c43-4b73-9c2f-3558ce7838f3
|
||||
* Text Area — https://app.subframe.com/f023064a5ca0/library?component=Text+Area_4ec05ee8-8f1c-46b2-b863-5419aa7f5cce
|
||||
* Text Input — https://app.subframe.com/f023064a5ca0/library?component=Text+Input_be48ca43-f8e7-4c0e-8870-d219ea11abfe
|
||||
*/
|
||||
|
||||
import React from "react";
|
||||
import { FeatherArrowRight } from "@subframe/core";
|
||||
import { FeatherCheck } from "@subframe/core";
|
||||
import { FeatherChevronDown } from "@subframe/core";
|
||||
import { FeatherMapPin } from "@subframe/core";
|
||||
import { FeatherUserSearch } from "@subframe/core";
|
||||
import { FeatherX } from "@subframe/core";
|
||||
import * as SubframeCore from "@subframe/core";
|
||||
import * as SubframeUtils from "../../utils";
|
||||
import { Avatar } from "../Avatar";
|
||||
import { Button } from "../Button";
|
||||
import { Checkbox } from "../Checkbox";
|
||||
import { Dialog } from "../Dialog";
|
||||
import { IconButton } from "../IconButton";
|
||||
import { IconWithBackground } from "../IconWithBackground";
|
||||
import { SearchInput } from "../SearchInput";
|
||||
import { Select } from "../Select";
|
||||
import { TextArea } from "../TextArea";
|
||||
import { TextInput } from "../TextInput";
|
||||
|
||||
export interface AddressDialogRootProps
|
||||
extends React.ComponentProps<typeof Dialog> {
|
||||
hideAddressType?: boolean;
|
||||
hideNote?: boolean;
|
||||
hideCompany?: boolean;
|
||||
hideDefaultAddress?: boolean;
|
||||
hideImport?: boolean;
|
||||
title?: React.ReactNode;
|
||||
subtitle?: React.ReactNode;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
const AddressDialogRoot = React.forwardRef<
|
||||
React.ElementRef<typeof Dialog>,
|
||||
AddressDialogRootProps
|
||||
>(function AddressDialogRoot(
|
||||
{
|
||||
hideAddressType = false,
|
||||
hideNote = false,
|
||||
hideCompany = false,
|
||||
hideDefaultAddress = false,
|
||||
hideImport = false,
|
||||
title,
|
||||
subtitle,
|
||||
className,
|
||||
...otherProps
|
||||
}: AddressDialogRootProps,
|
||||
ref
|
||||
) {
|
||||
return (
|
||||
<Dialog
|
||||
className={SubframeUtils.twClassNames("group/b3a6c4d9", className)}
|
||||
ref={ref}
|
||||
{...otherProps}
|
||||
>
|
||||
<Dialog.Content
|
||||
className="mobile:w-full mobile:max-w-[calc(100vw-32px)]"
|
||||
size="medium"
|
||||
hideCloseIcon={true}
|
||||
>
|
||||
<div className="flex w-full flex-col items-start gap-4">
|
||||
<div className="flex w-full items-start justify-between gap-3">
|
||||
<div className="flex items-start gap-3">
|
||||
<IconWithBackground
|
||||
variant="primary"
|
||||
size="medium"
|
||||
icon={<FeatherMapPin />}
|
||||
/>
|
||||
<div className="flex flex-col items-start gap-1">
|
||||
{title ? (
|
||||
<span className="text-heading-0 font-heading-0 text-text-neutral-primary">
|
||||
{title}
|
||||
</span>
|
||||
) : null}
|
||||
{subtitle ? (
|
||||
<span className="text-body-small-regular-150 font-body-small-regular-150 text-text-neutral-tertiary">
|
||||
{subtitle}
|
||||
</span>
|
||||
) : null}
|
||||
</div>
|
||||
</div>
|
||||
<IconButton variant="tertiary" size="small" icon={<FeatherX />} />
|
||||
</div>
|
||||
<div className="flex w-full flex-col items-start gap-3">
|
||||
<div
|
||||
className={SubframeUtils.twClassNames(
|
||||
"flex w-full flex-col items-start gap-3",
|
||||
{ hidden: hideImport }
|
||||
)}
|
||||
>
|
||||
<div className="flex w-full items-center justify-between rounded-md border border-solid border-border-default bg-surface-neutral-secondary px-3 py-3 gap-3 mobile:flex-wrap">
|
||||
<div className="flex flex-col items-start gap-1">
|
||||
<span className="text-body-default-medium-0 font-body-default-medium-0 text-text-neutral-primary">
|
||||
Aus Kontakt übernehmen
|
||||
</span>
|
||||
<span className="text-body-small-regular-150 font-body-small-regular-150 text-text-neutral-tertiary">
|
||||
Adressdaten aus einem bestehenden Kontakt vorbefüllen
|
||||
</span>
|
||||
</div>
|
||||
<SubframeCore.DropdownMenu.Root>
|
||||
<SubframeCore.DropdownMenu.Trigger asChild={true}>
|
||||
<Button
|
||||
variant="secondary"
|
||||
size="small"
|
||||
icon={<FeatherUserSearch />}
|
||||
iconRight={<FeatherChevronDown />}
|
||||
>
|
||||
Kontakt suchen
|
||||
</Button>
|
||||
</SubframeCore.DropdownMenu.Trigger>
|
||||
<SubframeCore.DropdownMenu.Portal>
|
||||
<SubframeCore.DropdownMenu.Content
|
||||
side="bottom"
|
||||
align="end"
|
||||
sideOffset={4}
|
||||
asChild={true}
|
||||
>
|
||||
<div className="flex w-80 flex-none flex-col items-start overflow-hidden rounded-md border border-solid border-border-default bg-surface-neutral-secondary shadow-lg">
|
||||
<div className="flex w-full flex-col items-start px-2 py-2">
|
||||
<SearchInput
|
||||
className="h-9 w-full flex-none"
|
||||
size="small"
|
||||
fillContainer={true}
|
||||
label="Label"
|
||||
helpText="Help text"
|
||||
message="Hilfetext"
|
||||
hideShortcut={true}
|
||||
>
|
||||
<SearchInput.Input placeholder="Kontakt oder Firma suchen" />
|
||||
</SearchInput>
|
||||
</div>
|
||||
<div className="flex h-px w-full flex-none flex-col items-start bg-border-default" />
|
||||
<div className="flex w-full flex-col items-start px-1 py-1">
|
||||
<div className="flex w-full items-center gap-3 rounded-md px-2 py-2 cursor-pointer hover:bg-surface-neutral-tertiary">
|
||||
<Avatar size="small">MB</Avatar>
|
||||
<div className="flex grow shrink-0 basis-0 flex-col items-start">
|
||||
<span className="line-clamp-1 w-full text-body-small-medium-150 font-body-small-medium-150 text-text-neutral-primary">
|
||||
Markus Bauer
|
||||
</span>
|
||||
<span className="line-clamp-1 w-full text-body-small-regular-150 font-body-small-regular-150 text-text-neutral-tertiary">
|
||||
Bauer Elektrotechnik GmbH · Berlin
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex w-full items-center gap-3 rounded-md px-2 py-2 cursor-pointer hover:bg-surface-neutral-tertiary">
|
||||
<Avatar size="small">SK</Avatar>
|
||||
<div className="flex grow shrink-0 basis-0 flex-col items-start">
|
||||
<span className="line-clamp-1 w-full text-body-small-medium-150 font-body-small-medium-150 text-text-neutral-primary">
|
||||
Sandra Keller
|
||||
</span>
|
||||
<span className="line-clamp-1 w-full text-body-small-regular-150 font-body-small-regular-150 text-text-neutral-tertiary">
|
||||
Keller Immobilien · Potsdam
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex w-full items-center gap-3 rounded-md px-2 py-2 cursor-pointer hover:bg-surface-neutral-tertiary">
|
||||
<Avatar size="small">JR</Avatar>
|
||||
<div className="flex grow shrink-0 basis-0 flex-col items-start">
|
||||
<span className="line-clamp-1 w-full text-body-small-medium-150 font-body-small-medium-150 text-text-neutral-primary">
|
||||
Jonas Richter
|
||||
</span>
|
||||
<span className="line-clamp-1 w-full text-body-small-regular-150 font-body-small-regular-150 text-text-neutral-tertiary">
|
||||
Richter Bau AG · Hamburg
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex w-full items-center gap-3 rounded-md px-2 py-2 cursor-pointer hover:bg-surface-neutral-tertiary">
|
||||
<Avatar size="small">EV</Avatar>
|
||||
<div className="flex grow shrink-0 basis-0 flex-col items-start">
|
||||
<span className="line-clamp-1 w-full text-body-small-medium-150 font-body-small-medium-150 text-text-neutral-primary">
|
||||
Elena Vogt
|
||||
</span>
|
||||
<span className="line-clamp-1 w-full text-body-small-regular-150 font-body-small-regular-150 text-text-neutral-tertiary">
|
||||
— · München
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex h-px w-full flex-none flex-col items-start bg-border-default" />
|
||||
<div className="flex w-full items-center gap-2 px-3 py-2.5 cursor-pointer hover:bg-surface-neutral-tertiary">
|
||||
<span className="grow shrink-0 basis-0 text-body-small-medium-150 font-body-small-medium-150 text-text-neutral-secondary">
|
||||
Alle Kontakte durchsuchen
|
||||
</span>
|
||||
<FeatherArrowRight className="text-body-small-regular-150 font-body-small-regular-150 text-icon-neutral-tertiary" />
|
||||
</div>
|
||||
</div>
|
||||
</SubframeCore.DropdownMenu.Content>
|
||||
</SubframeCore.DropdownMenu.Portal>
|
||||
</SubframeCore.DropdownMenu.Root>
|
||||
</div>
|
||||
<div className="flex h-px w-full flex-none flex-col items-start bg-border-default" />
|
||||
</div>
|
||||
<Select
|
||||
className={SubframeUtils.twClassNames({
|
||||
hidden: hideAddressType,
|
||||
})}
|
||||
variant="outline"
|
||||
fillContainer={true}
|
||||
showLabel={true}
|
||||
label="Adresstyp"
|
||||
placeholder="Lieferadresse"
|
||||
helpText=""
|
||||
errorText=""
|
||||
message=""
|
||||
>
|
||||
<Select.Item
|
||||
value="Lieferadresse"
|
||||
showItemText={true}
|
||||
content={
|
||||
<span className="grow shrink-0 basis-0 text-body-default-regular-0 font-body-default-regular-0 text-text-neutral-tertiary">
|
||||
Option
|
||||
</span>
|
||||
}
|
||||
>
|
||||
Lieferadresse
|
||||
</Select.Item>
|
||||
<Select.Item
|
||||
value="Baustelle"
|
||||
showItemText={true}
|
||||
content={
|
||||
<span className="grow shrink-0 basis-0 text-body-default-regular-0 font-body-default-regular-0 text-text-neutral-tertiary">
|
||||
Option
|
||||
</span>
|
||||
}
|
||||
>
|
||||
Baustelle
|
||||
</Select.Item>
|
||||
<Select.Item
|
||||
value="Rechnungsadresse"
|
||||
showItemText={true}
|
||||
content={
|
||||
<span className="grow shrink-0 basis-0 text-body-default-regular-0 font-body-default-regular-0 text-text-neutral-tertiary">
|
||||
Option
|
||||
</span>
|
||||
}
|
||||
>
|
||||
Rechnungsadresse
|
||||
</Select.Item>
|
||||
<Select.Item
|
||||
value="Büro"
|
||||
showItemText={true}
|
||||
content={
|
||||
<span className="grow shrink-0 basis-0 text-body-default-regular-0 font-body-default-regular-0 text-text-neutral-tertiary">
|
||||
Option
|
||||
</span>
|
||||
}
|
||||
>
|
||||
Büro
|
||||
</Select.Item>
|
||||
<Select.Item
|
||||
value="Privat"
|
||||
showItemText={true}
|
||||
content={
|
||||
<span className="grow shrink-0 basis-0 text-body-default-regular-0 font-body-default-regular-0 text-text-neutral-tertiary">
|
||||
Option
|
||||
</span>
|
||||
}
|
||||
>
|
||||
Privat
|
||||
</Select.Item>
|
||||
</Select>
|
||||
<TextInput
|
||||
className={SubframeUtils.twClassNames("h-auto w-full flex-none", {
|
||||
hidden: hideCompany,
|
||||
})}
|
||||
fillContainer={true}
|
||||
showLabel={true}
|
||||
label="Firma"
|
||||
helpText=""
|
||||
message=""
|
||||
>
|
||||
<TextInput.Input placeholder="Firmenname (optional)" value="" />
|
||||
</TextInput>
|
||||
<TextInput
|
||||
className="h-auto w-full flex-none"
|
||||
fillContainer={true}
|
||||
showLabel={true}
|
||||
label="Name / Ansprechpartner"
|
||||
helpText=""
|
||||
message=""
|
||||
>
|
||||
<TextInput.Input placeholder="Vor- und Nachname" value="" />
|
||||
</TextInput>
|
||||
<div className="flex w-full items-end gap-3 mobile:flex-wrap">
|
||||
<div className="flex grow shrink-0 basis-0 flex-col items-start">
|
||||
<TextInput
|
||||
className="h-auto w-full flex-none"
|
||||
fillContainer={true}
|
||||
showLabel={true}
|
||||
label="Straße"
|
||||
helpText=""
|
||||
message=""
|
||||
>
|
||||
<TextInput.Input placeholder="Straßenname" value="" />
|
||||
</TextInput>
|
||||
</div>
|
||||
<div className="flex w-48 flex-none flex-col items-start">
|
||||
<TextInput
|
||||
className="h-auto w-full flex-none"
|
||||
fillContainer={true}
|
||||
showLabel={true}
|
||||
label="Nr."
|
||||
helpText=""
|
||||
message=""
|
||||
>
|
||||
<TextInput.Input placeholder="12a" value="" />
|
||||
</TextInput>
|
||||
</div>
|
||||
</div>
|
||||
<TextInput
|
||||
className="h-auto w-full flex-none"
|
||||
fillContainer={true}
|
||||
showLabel={true}
|
||||
label="Adresszusatz"
|
||||
helpText=""
|
||||
message=""
|
||||
>
|
||||
<TextInput.Input
|
||||
placeholder="Etage, Gebäude, c/o (optional)"
|
||||
value=""
|
||||
/>
|
||||
</TextInput>
|
||||
<div className="flex w-full items-end gap-3 mobile:flex-wrap">
|
||||
<div className="flex w-48 flex-none flex-col items-start">
|
||||
<TextInput
|
||||
className="h-auto w-full flex-none"
|
||||
fillContainer={true}
|
||||
showLabel={true}
|
||||
label="PLZ"
|
||||
helpText=""
|
||||
message=""
|
||||
>
|
||||
<TextInput.Input placeholder="10115" value="" />
|
||||
</TextInput>
|
||||
</div>
|
||||
<div className="flex grow shrink-0 basis-0 flex-col items-start">
|
||||
<TextInput
|
||||
className="h-auto w-full flex-none"
|
||||
fillContainer={true}
|
||||
showLabel={true}
|
||||
label="Ort"
|
||||
helpText=""
|
||||
message=""
|
||||
>
|
||||
<TextInput.Input placeholder="Berlin" value="" />
|
||||
</TextInput>
|
||||
</div>
|
||||
</div>
|
||||
<Select
|
||||
variant="outline"
|
||||
fillContainer={true}
|
||||
showLabel={true}
|
||||
label="Land"
|
||||
placeholder="Deutschland"
|
||||
helpText=""
|
||||
errorText=""
|
||||
message=""
|
||||
>
|
||||
<Select.Item
|
||||
value="Deutschland"
|
||||
showItemText={true}
|
||||
content={
|
||||
<span className="grow shrink-0 basis-0 text-body-default-regular-0 font-body-default-regular-0 text-text-neutral-tertiary">
|
||||
Option
|
||||
</span>
|
||||
}
|
||||
>
|
||||
Deutschland
|
||||
</Select.Item>
|
||||
<Select.Item
|
||||
value="Österreich"
|
||||
showItemText={true}
|
||||
content={
|
||||
<span className="grow shrink-0 basis-0 text-body-default-regular-0 font-body-default-regular-0 text-text-neutral-tertiary">
|
||||
Option
|
||||
</span>
|
||||
}
|
||||
>
|
||||
Österreich
|
||||
</Select.Item>
|
||||
<Select.Item
|
||||
value="Schweiz"
|
||||
showItemText={true}
|
||||
content={
|
||||
<span className="grow shrink-0 basis-0 text-body-default-regular-0 font-body-default-regular-0 text-text-neutral-tertiary">
|
||||
Option
|
||||
</span>
|
||||
}
|
||||
>
|
||||
Schweiz
|
||||
</Select.Item>
|
||||
<Select.Item
|
||||
value="Niederlande"
|
||||
showItemText={true}
|
||||
content={
|
||||
<span className="grow shrink-0 basis-0 text-body-default-regular-0 font-body-default-regular-0 text-text-neutral-tertiary">
|
||||
Option
|
||||
</span>
|
||||
}
|
||||
>
|
||||
Niederlande
|
||||
</Select.Item>
|
||||
<Select.Item
|
||||
value="Polen"
|
||||
showItemText={true}
|
||||
content={
|
||||
<span className="grow shrink-0 basis-0 text-body-default-regular-0 font-body-default-regular-0 text-text-neutral-tertiary">
|
||||
Option
|
||||
</span>
|
||||
}
|
||||
>
|
||||
Polen
|
||||
</Select.Item>
|
||||
</Select>
|
||||
<div
|
||||
className={SubframeUtils.twClassNames(
|
||||
"flex w-full flex-col items-start gap-3",
|
||||
{ hidden: hideNote }
|
||||
)}
|
||||
>
|
||||
<div className="flex h-px w-full flex-none flex-col items-start bg-border-default" />
|
||||
<TextArea
|
||||
className="h-auto w-full flex-none max-w-[9999px]"
|
||||
error={false}
|
||||
fillContainer={false}
|
||||
showLabel={true}
|
||||
label="Notiz zur Adresse"
|
||||
helpText="Nur intern sichtbar, wird nicht auf Versandlabels gedruckt"
|
||||
errorText=""
|
||||
message=""
|
||||
>
|
||||
<TextArea.Input
|
||||
className="h-16 w-full flex-none min-h-[64px]"
|
||||
placeholder="z. B. Zufahrt über den Hinterhof, Schlüssel beim Nachbarn, Parkmöglichkeit"
|
||||
value=""
|
||||
/>
|
||||
</TextArea>
|
||||
</div>
|
||||
<Checkbox
|
||||
className={SubframeUtils.twClassNames({
|
||||
hidden: hideDefaultAddress,
|
||||
})}
|
||||
label="Als Standardadresse verwenden"
|
||||
description=""
|
||||
helpText=""
|
||||
/>
|
||||
</div>
|
||||
<div className="flex w-full items-center justify-end gap-2 bg-surface-neutral-secondary pt-2 sticky bottom-0">
|
||||
<Button variant="tertiary">Abbrechen</Button>
|
||||
<Button variant="primary" icon={<FeatherCheck />}>
|
||||
Adresse speichern
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</Dialog.Content>
|
||||
</Dialog>
|
||||
);
|
||||
});
|
||||
|
||||
export const AddressDialog = AddressDialogRoot;
|
||||
@@ -0,0 +1,10 @@
|
||||
"use client";
|
||||
import { AddressDialog as AddressDialogComponent } from "./AddressDialog";
|
||||
|
||||
/**
|
||||
* Add wrapper components and business logic here.
|
||||
* If you modify this file, disable Subframe sync for it to prevent overwrites.
|
||||
* Learn more: https://docs.subframe.com/concepts/syncing-components#wrapping-components
|
||||
*/
|
||||
|
||||
export const AddressDialog = AddressDialogComponent;
|
||||
Reference in new issue
Block a user