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:
dejanandClaude Opus 5 committed 2026-08-29 17:25:20 +02:00
commit b8bf987d0e
250 files changed
+33153

No files matched your search

+157
View File
@@ -0,0 +1,157 @@
"use client";
/*
* Documentation:
* Accordion — https://app.subframe.com/f023064a5ca0/library?component=Accordion_d2e81e20-863a-4027-826a-991d8910efd9
*/
import React from "react";
import { FeatherChevronRight } from "@subframe/core";
import * as SubframeCore from "@subframe/core";
import * as SubframeUtils from "../../utils";
export interface ChevronProps
extends React.ComponentProps<typeof SubframeCore.Collapsible.Chevron> {
className?: string;
}
const Chevron = React.forwardRef<
React.ElementRef<typeof FeatherChevronRight>,
ChevronProps
>(function Chevron({ className, ...otherProps }: ChevronProps, ref) {
return (
<SubframeCore.Collapsible.Chevron {...otherProps}>
<FeatherChevronRight
className={SubframeUtils.twClassNames(
"text-body-default-regular-150 font-body-default-regular-150 text-icon-neutral-primary group-data-[state=open]/d2e81e20:-rotate-90 group-aria-[invalid=true]/d2e81e20:text-icon-feedback-negative group-aria-[disabled=true]/d2e81e20:text-icon-neutral-disabled",
className
)}
ref={ref}
/>
</SubframeCore.Collapsible.Chevron>
);
});
export interface ContentProps
extends React.ComponentProps<typeof SubframeCore.Collapsible.Content> {
children?: React.ReactNode;
className?: string;
}
const Content = React.forwardRef<HTMLDivElement, ContentProps>(function Content(
{ children, className, ...otherProps }: ContentProps,
ref
) {
return children ? (
<SubframeCore.Collapsible.Content asChild={true} {...otherProps}>
<div
className={SubframeUtils.twClassNames(
"flex w-full flex-col items-start gap-2",
className
)}
ref={ref}
>
{children}
</div>
</SubframeCore.Collapsible.Content>
) : null;
});
export interface TriggerProps
extends React.ComponentProps<typeof SubframeCore.Collapsible.Trigger> {
children?: React.ReactNode;
className?: string;
}
const Trigger = React.forwardRef<HTMLDivElement, TriggerProps>(function Trigger(
{ children, className, ...otherProps }: TriggerProps,
ref
) {
return children ? (
<SubframeCore.Collapsible.Trigger asChild={true} {...otherProps}>
<div
className={SubframeUtils.twClassNames(
"flex w-full cursor-pointer flex-col items-start gap-2",
className
)}
ref={ref}
>
{children}
</div>
</SubframeCore.Collapsible.Trigger>
) : null;
});
export interface AccordionRootProps
extends React.ComponentProps<typeof SubframeCore.Collapsible.Root> {
disabled?: boolean;
error?: boolean;
open?: boolean;
variant?: "card" | "ghost";
trigger?: React.ReactNode;
children?: React.ReactNode;
className?: string;
}
const AccordionRoot = React.forwardRef<HTMLDivElement, AccordionRootProps>(
function AccordionRoot(
{
disabled = false,
error = false,
open,
variant = "card",
trigger,
children,
className,
defaultOpen = false,
...otherProps
}: AccordionRootProps,
ref
) {
return (
<SubframeCore.Collapsible.Root
open={open}
defaultOpen={defaultOpen}
asChild={true}
disabled={disabled}
{...otherProps}
>
<div
className={SubframeUtils.twClassNames(
"group/d2e81e20 flex w-full cursor-pointer flex-col items-start rounded-md border border-solid border-border-default bg-surface-neutral-secondary hover:bg-surface-neutral-tertiary",
{
"border-none bg-transparent hover:bg-transparent":
variant === "ghost",
"border-2 border-solid border-border-negative-solid hover:border-border-negative-solid":
error,
"border border-solid border-border-disabled bg-surface-neutral-disabled opacity-40 pointer-events-none hover:bg-surface-neutral-disabled hover:border-border-disabled":
disabled,
},
className
)}
ref={ref}
>
<Trigger>
{trigger ? (
<div className="flex w-full grow shrink-0 basis-0 flex-col items-start group-data-[state=open]/d2e81e20:flex-none">
{trigger}
</div>
) : null}
</Trigger>
<Content>
{children ? (
<div className="flex w-full grow shrink-0 basis-0 flex-col items-start">
{children}
</div>
) : null}
</Content>
</div>
</SubframeCore.Collapsible.Root>
);
}
);
export const Accordion = Object.assign(AccordionRoot, {
Chevron,
Content,
Trigger,
});
+10
View File
@@ -0,0 +1,10 @@
"use client";
import { Accordion as AccordionComponent } from "./Accordion";
/**
* 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 Accordion = AccordionComponent;
@@ -0,0 +1,158 @@
"use client";
/*
* Documentation:
* Accordion Nested — https://app.subframe.com/f023064a5ca0/library?component=Accordion+Nested_91a645f4-5a9c-4c61-be00-d85b9d554e91
*/
import React from "react";
import { FeatherChevronRight } from "@subframe/core";
import * as SubframeCore from "@subframe/core";
import * as SubframeUtils from "../../utils";
export interface ChevronProps
extends React.ComponentProps<typeof SubframeCore.Collapsible.Chevron> {
className?: string;
}
const Chevron = React.forwardRef<
React.ElementRef<typeof FeatherChevronRight>,
ChevronProps
>(function Chevron({ className, ...otherProps }: ChevronProps, ref) {
return (
<SubframeCore.Collapsible.Chevron {...otherProps}>
<FeatherChevronRight
className={SubframeUtils.twClassNames(
"text-body-default-regular-150 font-body-default-regular-150 text-icon-neutral-primary transition-transform group-data-[state=open]/91a645f4:-rotate-90 group-aria-[invalid=true]/91a645f4:text-icon-feedback-negative group-aria-[disabled=true]/91a645f4:text-icon-neutral-disabled",
className
)}
ref={ref}
/>
</SubframeCore.Collapsible.Chevron>
);
});
export interface ContentProps
extends React.ComponentProps<typeof SubframeCore.Collapsible.Content> {
children?: React.ReactNode;
className?: string;
}
const Content = React.forwardRef<HTMLDivElement, ContentProps>(function Content(
{ children, className, ...otherProps }: ContentProps,
ref
) {
return children ? (
<SubframeCore.Collapsible.Content asChild={true} {...otherProps}>
<div
className={SubframeUtils.twClassNames(
"flex w-full flex-col items-start gap-2",
className
)}
ref={ref}
>
{children}
</div>
</SubframeCore.Collapsible.Content>
) : null;
});
export interface TriggerProps
extends React.ComponentProps<typeof SubframeCore.Collapsible.Trigger> {
children?: React.ReactNode;
className?: string;
}
const Trigger = React.forwardRef<HTMLDivElement, TriggerProps>(function Trigger(
{ children, className, ...otherProps }: TriggerProps,
ref
) {
return children ? (
<SubframeCore.Collapsible.Trigger asChild={true} {...otherProps}>
<div
className={SubframeUtils.twClassNames(
"flex w-full cursor-pointer flex-col items-start gap-2",
className
)}
ref={ref}
>
{children}
</div>
</SubframeCore.Collapsible.Trigger>
) : null;
});
export interface AccordionNestedRootProps
extends React.ComponentProps<typeof SubframeCore.Collapsible.Root> {
disabled?: boolean;
error?: boolean;
open?: boolean;
variant?: "card" | "ghost";
trigger?: React.ReactNode;
children?: React.ReactNode;
className?: string;
}
const AccordionNestedRoot = React.forwardRef<
HTMLDivElement,
AccordionNestedRootProps
>(function AccordionNestedRoot(
{
disabled = false,
error = false,
open,
variant = "card",
trigger,
children,
className,
defaultOpen = false,
...otherProps
}: AccordionNestedRootProps,
ref
) {
return (
<SubframeCore.Collapsible.Root
open={open}
defaultOpen={defaultOpen}
asChild={true}
disabled={disabled}
{...otherProps}
>
<div
className={SubframeUtils.twClassNames(
"group/91a645f4 flex w-full cursor-pointer flex-col items-start rounded-md border border-solid border-border-default bg-surface-neutral-secondary hover:bg-surface-neutral-tertiary",
{
"border-none bg-transparent hover:bg-transparent":
variant === "ghost",
"border-2 border-solid border-border-negative-solid hover:border-border-negative-solid":
error,
"border border-solid border-border-disabled bg-surface-neutral-disabled opacity-40 pointer-events-none hover:bg-surface-neutral-disabled hover:border-border-disabled":
disabled,
},
className
)}
ref={ref}
>
<Trigger>
{trigger ? (
<div className="flex w-full grow shrink-0 basis-0 flex-col items-start group-data-[state=open]/91a645f4:flex-none">
{trigger}
</div>
) : null}
</Trigger>
<Content>
{children ? (
<div className="flex w-full grow shrink-0 basis-0 flex-col items-start">
{children}
</div>
) : null}
</Content>
</div>
</SubframeCore.Collapsible.Root>
);
});
export const AccordionNested = Object.assign(AccordionNestedRoot, {
Chevron,
Content,
Trigger,
});
+10
View File
@@ -0,0 +1,10 @@
"use client";
import { AccordionNested as AccordionNestedComponent } from "./AccordionNested";
/**
* 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 AccordionNested = AccordionNestedComponent;
@@ -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;
+10
View File
@@ -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;
+153
View File
@@ -0,0 +1,153 @@
"use client";
/*
* Documentation:
* Alert — https://app.subframe.com/f023064a5ca0/library?component=Alert_3a65613d-d546-467c-80f4-aaba6a7edcd5
* Icon Button — https://app.subframe.com/f023064a5ca0/library?component=Icon+Button_af9405b1-8c54-4e01-9786-5aad308224f6
*/
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 { IconButton } from "../IconButton";
export interface AlertRootProps
extends Omit<React.HTMLAttributes<HTMLDivElement>, "title"> {
variant?: "information" | "success" | "warning" | "error" | "neutral";
notDismissible?: boolean;
title?: React.ReactNode;
description?: React.ReactNode;
textSize?: "small" | "medium";
className?: string;
}
const AlertRoot = React.forwardRef<HTMLDivElement, AlertRootProps>(
function AlertRoot(
{
variant = "information",
notDismissible = false,
title,
description,
textSize = "medium",
className,
...otherProps
}: AlertRootProps,
ref
) {
return (
<div
className={SubframeUtils.twClassNames(
"group/3a65613d flex w-full flex-col items-start gap-2 rounded-md border border-solid border-border-information-subtle bg-surface-feedback-subtle-information px-4 py-5 relative",
{
"px-3 py-3.5": textSize === "small",
"border border-solid border-border-default bg-surface-feedback-subtle-neutral":
variant === "neutral",
"border border-solid border-border-negative-subtle bg-surface-feedback-subtle-negative":
variant === "error",
"border border-solid border-border-warning-subtle bg-surface-feedback-subtle-warning":
variant === "warning",
"border border-solid border-border-positive-subtle bg-surface-feedback-subtle-positive":
variant === "success",
},
className
)}
ref={ref}
{...otherProps}
>
<div
className={SubframeUtils.twClassNames(
"flex w-full items-start gap-3",
{ "gap-2.5": textSize === "small" }
)}
>
<FeatherInfo
className={SubframeUtils.twClassNames(
"text-heading-0 font-heading-0 text-icon-feedback-information",
{
"text-body-large font-body-large": textSize === "small",
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-2">
{title ? (
<span
className={SubframeUtils.twClassNames(
"w-full whitespace-pre-wrap text-body-default-medium-0 font-body-default-medium-0 text-text-feedback-information",
{
"text-body-small-medium-0 font-body-small-medium-0":
textSize === "small",
"text-text-neutral-primary": variant === "neutral",
"text-text-feedback-negative": variant === "error",
"text-text-feedback-warning": variant === "warning",
"text-text-feedback-positive": variant === "success",
}
)}
>
{title}
</span>
) : null}
{description ? (
<span
className={SubframeUtils.twClassNames(
"w-full whitespace-pre-wrap text-body-default-regular-150 font-body-default-regular-150 text-text-neutral-secondary",
{
"text-body-small-regular-150 font-body-small-regular-150":
textSize === "small",
}
)}
>
{description}
</span>
) : null}
</div>
<div
className={SubframeUtils.twClassNames(
"flex items-center justify-end gap-1 px-1 py-1",
{ hidden: notDismissible }
)}
>
<IconButton variant="ghost" square={true} icon={<FeatherX />} />
</div>
</div>
<div className="hidden items-start justify-center absolute top-3 right-3">
<FeatherX className="text-body-default-regular-0 font-body-default-regular-0 text-icon-neutral-secondary" />
</div>
</div>
);
}
);
export const Alert = AlertRoot;
+10
View File
@@ -0,0 +1,10 @@
"use client";
import { Alert as AlertComponent } from "./Alert";
/**
* 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 Alert = AlertComponent;
+42
View File
@@ -0,0 +1,42 @@
"use client";
/*
* Documentation:
* Area Chart — https://app.subframe.com/f023064a5ca0/library?component=Area+Chart_8aa1e7b3-5db6-4a62-aa49-137ced21a231
*/
import React from "react";
import * as SubframeCore from "@subframe/core";
import * as SubframeUtils from "../../utils";
export interface AreaChartRootProps
extends React.ComponentProps<typeof SubframeCore.AreaChart> {
stacked?: boolean;
className?: string;
}
const AreaChartRoot = React.forwardRef<
React.ElementRef<typeof SubframeCore.AreaChart>,
AreaChartRootProps
>(function AreaChartRoot(
{ stacked = false, className, ...otherProps }: AreaChartRootProps,
ref
) {
return (
<SubframeCore.AreaChart
className={SubframeUtils.twClassNames("h-80 w-full", className)}
ref={ref}
stacked={stacked}
colors={[
"#3b82f6",
"#bfdbfe",
"#2563eb",
"#93c5fd",
"#1d4ed8",
"#60a5fa",
]}
{...otherProps}
/>
);
});
export const AreaChart = AreaChartRoot;
+10
View File
@@ -0,0 +1,10 @@
"use client";
import { AreaChart as AreaChartComponent } from "./AreaChart";
/**
* 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 AreaChart = AreaChartComponent;
+108
View File
@@ -0,0 +1,108 @@
"use client";
/*
* Documentation:
* Avatar — https://app.subframe.com/f023064a5ca0/library?component=Avatar_bec25ae6-5010-4485-b46b-cf79e3943ab2
*/
import React from "react";
import * as SubframeUtils from "../../utils";
export interface AvatarRootProps
extends Omit<React.HTMLAttributes<HTMLDivElement>, "color"> {
color?: "neutral" | "blue" | "green" | "red" | "yellow" | "purple";
size?:
| "extra-small"
| "small"
| "medium"
| "large"
| "extra-large"
| "2-x-large"
| "3-x-large";
border?: boolean;
children?: React.ReactNode;
image?: string;
className?: string;
}
const AvatarRoot = React.forwardRef<HTMLDivElement, AvatarRootProps>(
function AvatarRoot(
{
color = "neutral",
size = "medium",
border = false,
children,
image,
className,
...otherProps
}: AvatarRootProps,
ref
) {
return (
<div
className={SubframeUtils.twClassNames(
"group/bec25ae6 flex h-10 w-10 flex-col items-center justify-center gap-2 overflow-hidden rounded-round bg-surface-neutral-tertiary relative",
{
"border border-solid border-border-on-primary": border,
"h-32 w-32": size === "3-x-large",
"h-20 w-20": size === "2-x-large",
"h-16 w-16": size === "extra-large",
"h-12 w-12": size === "large",
"h-8 w-8": size === "small",
"h-6 w-6": size === "extra-small",
"bg-surface-ui-subtle-purple-default": color === "purple",
"bg-surface-ui-subtle-yellow-default": color === "yellow",
"bg-surface-ui-subtle-red-default": color === "red",
"bg-surface-ui-subtle-green-default": color === "green",
"bg-surface-ui-subtle-blue-default": color === "blue",
},
className
)}
ref={ref}
{...otherProps}
>
{children ? (
<span
className={SubframeUtils.twClassNames(
"line-clamp-1 w-full text-body-default-medium-150 font-body-default-medium-150 text-text-neutral-secondary text-center absolute",
{
"text-title-hero font-title-hero": size === "3-x-large",
"text-title-page font-title-page": size === "2-x-large",
"text-subtitle font-subtitle": size === "extra-large",
"text-heading-0 font-heading-0": size === "large",
"text-body-small-medium-150 font-body-small-medium-150":
size === "small",
"text-body-extra-small-medium-150 font-body-extra-small-medium-150":
size === "extra-small",
"text-text-ui-purple": color === "purple",
"text-text-ui-yellow": color === "yellow",
"text-text-ui-red": color === "red",
"text-text-ui-green": color === "green",
"text-text-ui-blue": color === "blue",
}
)}
>
{children}
</span>
) : null}
{image ? (
<img
className={SubframeUtils.twClassNames(
"h-10 w-10 flex-none object-cover absolute",
{
"h-24 w-24": size === "3-x-large",
"h-20 w-20": size === "2-x-large",
"h-16 w-16": size === "extra-large",
"h-12 w-12": size === "large",
"h-8 w-8": size === "small",
"h-6 w-6": size === "extra-small",
}
)}
src={image}
/>
) : null}
</div>
);
}
);
export const Avatar = AvatarRoot;
+10
View File
@@ -0,0 +1,10 @@
"use client";
import { Avatar as AvatarComponent } from "./Avatar";
/**
* 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 Avatar = AvatarComponent;
+110
View File
@@ -0,0 +1,110 @@
"use client";
/*
* Documentation:
* Avatar Group — https://app.subframe.com/f023064a5ca0/library?component=Avatar+Group_6e7444ab-1d67-47f5-af23-1a2d3ecf1016
*/
import React from "react";
import * as SubframeUtils from "../../utils";
export interface AvatarOverflowProps
extends React.HTMLAttributes<HTMLDivElement> {
border?: boolean;
overflowLabel?: React.ReactNode;
className?: string;
}
const AvatarOverflow = React.forwardRef<HTMLDivElement, AvatarOverflowProps>(
function AvatarOverflow(
{
border = false,
overflowLabel,
className,
...otherProps
}: AvatarOverflowProps,
ref
) {
return (
<div
className={SubframeUtils.twClassNames(
"group/dbd63208 flex h-10 w-10 cursor-pointer items-center justify-center overflow-hidden rounded-round bg-surface-neutral-tertiary group/avataroverflow shrink-0 relative",
{ "border border-solid border-border-on-primary": border },
className
)}
ref={ref}
{...otherProps}
>
{overflowLabel ? (
<span className="text-body-small-medium-150 font-body-small-medium-150 text-text-neutral-secondary">
{overflowLabel}
</span>
) : null}
</div>
);
}
);
export interface AvatarGroupRootProps
extends React.HTMLAttributes<HTMLDivElement> {
hoverEffect?: "on" | "off";
border?: boolean;
showOverflow?: boolean;
children?: React.ReactNode;
overflowLabel?: React.ReactNode;
className?: string;
}
const AvatarGroupRoot = React.forwardRef<HTMLDivElement, AvatarGroupRootProps>(
function AvatarGroupRoot(
{
hoverEffect = "off",
border = false,
showOverflow = false,
children,
overflowLabel,
className,
...otherProps
}: AvatarGroupRootProps,
ref
) {
return (
<div
className={SubframeUtils.twClassNames(
"group/6e7444ab items-center group/mtavatargroup inline-flex [&>*:not(:first-child)]:-ml-2",
className
)}
ref={ref}
{...otherProps}
>
{children ? (
<div
className={SubframeUtils.twClassNames(
"items-center inline-flex [&>*:not(:first-child)]:-ml-2 [&>*]:relative relative [&>*]:z-0 z-0 [&>*:nth-child(1)]:z-[1] [&>*:nth-child(2)]:z-[2] [&>*:nth-child(3)]:z-[3] [&>*:nth-child(4)]:z-[4] [&>*:nth-child(5)]:z-[5]",
{
"[&>*]:border [&>*]:border-solid [&>*]:border-border-on-primary":
border,
"[&>*]:transition-transform [&>*]:duration-200 [&>*:hover]:scale-110 [&>*:hover]:rotate-6 [&>*:hover]:z-20":
hoverEffect === "on",
}
)}
>
{children}
</div>
) : null}
<AvatarOverflow
className={SubframeUtils.twClassNames("hidden relative z-10", {
flex: showOverflow,
"border border-solid border-border-on-primary": border,
"transition-transform duration-200 hover:scale-110 hover:rotate-6":
hoverEffect === "on",
})}
overflowLabel={overflowLabel}
/>
</div>
);
}
);
export const AvatarGroup = Object.assign(AvatarGroupRoot, {
AvatarOverflow,
});
+10
View File
@@ -0,0 +1,10 @@
"use client";
import { AvatarGroup as AvatarGroupComponent } from "./AvatarGroup";
/**
* 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 AvatarGroup = AvatarGroupComponent;
+317
View File
@@ -0,0 +1,317 @@
"use client";
/*
* Documentation:
* Badge — https://app.subframe.com/f023064a5ca0/library?component=Badge_7d75e221-355a-4695-acb7-3902a9f6ffde
*/
import React from "react";
import * as SubframeUtils from "../../utils";
export interface BadgeRootProps extends React.HTMLAttributes<HTMLDivElement> {
tone?:
| "red-subtle"
| "orange-subtle"
| "yellow-subtle"
| "pear-subtle"
| "lime-subtle"
| "green-subtle"
| "teal-subtle"
| "ocean-subtle"
| "sky-subtle"
| "blue-subtle"
| "indigo-subtle"
| "violet-subtle"
| "fuchsia-subtle"
| "pink-subtle"
| "sand-subtle"
| "brown-subtle"
| "red-solid"
| "orange-solid"
| "yellow-solid"
| "pear-solid"
| "lime-solid"
| "green-solid"
| "teal-solid"
| "ocean-solid"
| "sky-solid"
| "blue-solid"
| "indigo-solid"
| "violet-solid"
| "fuchsia-solid"
| "pink-solid"
| "sand-solid"
| "brown-solid"
| "red-outline"
| "orange-outline"
| "yellow-outline"
| "pear-outline"
| "lime-outline"
| "green-outline"
| "teal-outline"
| "ocean-outline"
| "sky-outline"
| "blue-outline"
| "indigo-outline"
| "violet-outline"
| "fuchsia-outline"
| "pink-outline"
| "sand-outline"
| "brown-outline"
| "brand-primary-solid"
| "brand-secondary-solid"
| "neutral-solid"
| "brand-primary-subtle"
| "brand-secondary-subtle"
| "neutral-subtle"
| "white";
children?: React.ReactNode;
size?: "small" | "medium" | "large";
hideDot?: boolean;
className?: string;
}
const BadgeRoot = React.forwardRef<HTMLDivElement, BadgeRootProps>(
function BadgeRoot(
{
tone = "neutral-subtle",
children,
size = "medium",
hideDot = false,
className,
...otherProps
}: BadgeRootProps,
ref
) {
return (
<div
className={SubframeUtils.twClassNames(
"group/7d75e221 flex h-6 items-center gap-2 rounded-round border border-solid border-border-default bg-surface-feedback-subtle-neutral px-2.5 py-1",
{
"h-8 py-2": size === "large",
"h-5 py-0.5": size === "small",
"bg-surface-neutral-secondary": tone === "white",
"border border-solid border-brand-brand-secondary-surface-subtle-default bg-brand-brand-secondary-surface-subtle-default":
tone === "brand-secondary-subtle",
"border border-solid border-brand-brand-surface-subtle-default bg-brand-brand-surface-subtle-default":
tone === "brand-primary-subtle",
"border border-solid border-surface-feedback-solid-neutral bg-surface-feedback-solid-neutral":
tone === "neutral-solid",
"border border-solid border-brand-brand-secondary-surface-solid-default bg-brand-brand-secondary-surface-solid-default":
tone === "brand-secondary-solid",
"border border-solid border-brand-brand-surface-solid-default bg-brand-brand-surface-solid-default":
tone === "brand-primary-solid",
"border-2 border-solid border-[#c2a682] bg-[#fafafa]":
tone === "brown-outline",
"border-2 border-solid border-[#c8baa9] bg-[#fafafa]":
tone === "sand-outline",
"border-2 border-solid border-[#f9a8d4] bg-[#fafafa]":
tone === "pink-outline",
"border-2 border-solid border-[#f0abfc] bg-[#fafafa]":
tone === "fuchsia-outline",
"border-2 border-solid border-[#cfb2ff] bg-[#fafafa]":
tone === "violet-outline",
"border-2 border-solid border-[#b3b8ff] bg-[#fafafa]":
tone === "indigo-outline",
"border-2 border-solid border-[#85c7ff] bg-[#fafafa]":
tone === "blue-outline",
"border-2 border-solid border-[#79c7ff] bg-[#fafafa]":
tone === "sky-outline",
"border-2 border-solid border-[#81dbf8] bg-[#fafafa]":
tone === "ocean-outline",
"border-2 border-solid border-[#51f7e5] bg-[#fafafa]":
tone === "teal-outline",
"border-2 border-solid border-[#85f0a3] bg-[#fafafa]":
tone === "green-outline",
"border-2 border-solid border-[#bef264] bg-[#fafafa]":
tone === "lime-outline",
"border-2 border-solid border-[#e0eb6b] bg-[#fafafa]":
tone === "pear-outline",
"border-2 border-solid border-[#f6d84e] bg-[#fafafa]":
tone === "yellow-outline",
"border-2 border-solid border-[#ffa570] bg-[#fafafa]":
tone === "orange-outline",
"border-2 border-solid border-[#fba6a6] bg-[#fafafa]":
tone === "red-outline",
"border border-solid border-[#8a5f44] bg-[#8a5f44]":
tone === "brown-solid",
"border border-solid border-[#947562] bg-[#947562]":
tone === "sand-solid",
"border border-solid border-[#db2777] bg-[#db2777]":
tone === "pink-solid",
"border border-solid border-[#c026d3] bg-[#c026d3]":
tone === "fuchsia-solid",
"border border-solid border-[#7c2df0] bg-[#7c2df0]":
tone === "violet-solid",
"border border-solid border-[#4835f2] bg-[#4835f2]":
tone === "indigo-solid",
"border border-solid border-[#0c4bff] bg-[#0c4bff]":
tone === "blue-solid",
"border border-solid border-[#0071ce] bg-[#0071ce]":
tone === "sky-solid",
"border border-solid border-[#0890c1] bg-[#0890c1]":
tone === "ocean-solid",
"border border-solid border-[#05807c] bg-[#05807c]":
tone === "teal-solid",
"border border-solid border-[#15a43e] bg-[#15a43e]":
tone === "green-solid",
"border border-solid border-[#4d7c0f] bg-[#4d7c0f]":
tone === "lime-solid",
"border border-solid border-[#677615] bg-[#677615]":
tone === "pear-solid",
"border border-solid border-[#e0c200] bg-[#e0c200]":
tone === "yellow-solid",
"border border-solid border-[#ea580c] bg-[#ea580c]":
tone === "orange-solid",
"border border-solid border-[#da2828] bg-[#da2828]":
tone === "red-solid",
"border border-solid border-[#d9c8af] bg-[#ebe3d6]":
tone === "brown-subtle",
"border border-solid border-[#ded6ca] bg-[#ede9e3]":
tone === "sand-subtle",
"border border-solid border-[#fbcfe8] bg-[#fce7f3]":
tone === "pink-subtle",
"border border-solid border-[#f5d0fe] bg-[#fae8ff]":
tone === "fuchsia-subtle",
"border border-solid border-[#e4d4ff] bg-[#f0e7ff]":
tone === "violet-subtle",
"border border-solid border-[#d5d9ff] bg-[#e8e9ff]":
tone === "indigo-subtle",
"border border-solid border-[#b3dfff] bg-[#d5efff]":
tone === "blue-subtle",
"border border-solid border-border-information-subtle bg-surface-feedback-subtle-information":
tone === "sky-subtle",
"border border-solid border-[#bceafb] bg-[#e1f4fd]":
tone === "ocean-subtle",
"border border-solid border-[#90ffee] bg-[#c8fff7]":
tone === "teal-subtle",
"border border-solid border-[#baf8cb] bg-[#dcfce4]":
tone === "green-subtle",
"border border-solid border-[#d9f99d] bg-[#ecfccb]":
tone === "lime-subtle",
"border border-solid border-[#eff4a2] bg-[#f8facd]":
tone === "pear-subtle",
"border border-solid border-[#faeb8e] bg-[#fcf6c5]":
tone === "yellow-subtle",
"border border-solid border-[#ffcaa8] bg-[#ffe7d4]":
tone === "orange-subtle",
"border border-solid border-[#fdcbcb] bg-[#fee2e2]":
tone === "red-subtle",
},
className
)}
ref={ref}
{...otherProps}
>
<div
className={SubframeUtils.twClassNames(
"flex h-1 w-1 flex-none flex-col items-start rounded-round bg-icon-neutral-on-subtle",
{
hidden: hideDot,
"bg-brand-brand-secondary-surface-solid-default":
tone === "brand-secondary-subtle",
"bg-brand-brand-surface-solid-default":
tone === "brand-primary-subtle",
"bg-icon-neutral-on-solid":
tone === "neutral-solid" ||
tone === "brand-secondary-solid" ||
tone === "brand-primary-solid" ||
tone === "brown-solid" ||
tone === "sand-solid" ||
tone === "pink-solid" ||
tone === "fuchsia-solid" ||
tone === "violet-solid" ||
tone === "indigo-solid" ||
tone === "blue-solid" ||
tone === "sky-solid" ||
tone === "ocean-solid" ||
tone === "teal-solid" ||
tone === "green-solid" ||
tone === "lime-solid" ||
tone === "pear-solid" ||
tone === "yellow-solid" ||
tone === "orange-solid" ||
tone === "red-solid",
"bg-[#6f4a39]": tone === "brown-outline",
"bg-[#7c6052]": tone === "sand-outline",
"bg-[#be185d]": tone === "pink-outline",
"bg-[#a21caf]": tone === "fuchsia-outline",
"bg-[#691cd4]": tone === "violet-outline",
"bg-[#3923de]": tone === "indigo-outline",
"bg-[#003beb]": tone === "blue-outline",
"bg-[#0071ce]": tone === "sky-outline" || tone === "sky-subtle",
"bg-[#08739c]": tone === "ocean-outline",
"bg-[#05807c]": tone === "teal-outline" || tone === "teal-subtle",
"bg-[#148134]": tone === "green-outline",
"bg-[#4d7c0f]": tone === "lime-outline" || tone === "lime-subtle",
"bg-[#677615]": tone === "pear-outline" || tone === "pear-subtle",
"bg-[#9b5e0d]": tone === "yellow-outline",
"bg-[#c72307]": tone === "orange-outline",
"bg-[#c52020]": tone === "red-outline",
"bg-[#8a5f44]": tone === "brown-subtle",
"bg-[#947562]": tone === "sand-subtle",
"bg-[#db2777]": tone === "pink-subtle",
"bg-[#c026d3]": tone === "fuchsia-subtle",
"bg-[#7c2df0]": tone === "violet-subtle",
"bg-[#4835f2]": tone === "indigo-subtle",
"bg-[#0c4bff]": tone === "blue-subtle",
"bg-[#0890c1]": tone === "ocean-subtle",
"bg-[#15a43e]": tone === "green-subtle",
"bg-[#e0c200]": tone === "yellow-subtle",
"bg-[#ea580c]": tone === "orange-subtle",
"bg-[#da2828]": tone === "red-subtle",
}
)}
/>
{children ? (
<span
className={SubframeUtils.twClassNames(
"whitespace-nowrap text-body-small-medium-0 font-body-small-medium-0 text-text-neutral-on-subtle",
{
"text-text-neutral-on-solid":
tone === "neutral-solid" ||
tone === "brand-secondary-solid" ||
tone === "brand-primary-solid" ||
tone === "brown-solid" ||
tone === "sand-solid" ||
tone === "pink-solid" ||
tone === "fuchsia-solid" ||
tone === "violet-solid" ||
tone === "indigo-solid" ||
tone === "blue-solid" ||
tone === "sky-solid" ||
tone === "ocean-solid" ||
tone === "teal-solid" ||
tone === "green-solid" ||
tone === "lime-solid" ||
tone === "pear-solid" ||
tone === "yellow-solid" ||
tone === "orange-solid" ||
tone === "red-solid",
"text-[#6f4a39]": tone === "brown-outline",
"text-[#7c6052]": tone === "sand-outline",
"text-[#be185d]": tone === "pink-outline",
"text-[#a21caf]": tone === "fuchsia-outline",
"text-[#691cd4]": tone === "violet-outline",
"text-[#3923de]": tone === "indigo-outline",
"text-[#003beb]": tone === "blue-outline",
"text-[#0071ce]": tone === "sky-outline",
"text-[#08739c]": tone === "ocean-outline",
"text-[#05807c]": tone === "teal-outline",
"text-[#148134]": tone === "green-outline",
"text-[#4d7c0f]": tone === "lime-outline",
"text-[#677615]": tone === "pear-outline",
"text-[#9b5e0d]": tone === "yellow-outline",
"text-[#c72307]": tone === "orange-outline",
"text-[#c52020]": tone === "red-outline",
}
)}
>
{children}
</span>
) : null}
</div>
);
}
);
export const Badge = BadgeRoot;
+10
View File
@@ -0,0 +1,10 @@
"use client";
import { Badge as BadgeComponent } from "./Badge";
/**
* 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 Badge = BadgeComponent;
@@ -0,0 +1,169 @@
"use client";
/*
* Documentation:
* Badge Feedback — https://app.subframe.com/f023064a5ca0/library?component=Badge+Feedback_896531e4-54ea-4e5a-8710-c30fc2ce10fb
*/
import React from "react";
import * as SubframeUtils from "../../utils";
export interface BadgeFeedbackRootProps
extends React.HTMLAttributes<HTMLDivElement> {
farbe?:
| "solid-neutral"
| "solid-positive"
| "solid-negative"
| "solid-warning"
| "solid-information"
| "solid-purple"
| "solid-blue"
| "solid-brand-primary"
| "solid-brand-secondary"
| "subtle-neutral"
| "subtle-positive"
| "subtle-negative"
| "subtle-warning"
| "subtle-information"
| "subtle-purple"
| "subtle-blue"
| "subtle-brand-primary"
| "subtle-brand-secondary"
| "ghost-neutral"
| "ghost-positive"
| "ghost-negative"
| "ghost-warning"
| "ghost-information"
| "ghost-purple"
| "ghost-blue"
| "ghost-brand-primary"
| "ghost-brand-secondary";
children?: React.ReactNode;
size?: "medium" | "small" | "large";
className?: string;
}
const BadgeFeedbackRoot = React.forwardRef<
HTMLDivElement,
BadgeFeedbackRootProps
>(function BadgeFeedbackRoot(
{
farbe = "solid-neutral",
children,
size = "medium",
className,
...otherProps
}: BadgeFeedbackRootProps,
ref
) {
return (
<div
className={SubframeUtils.twClassNames(
"group/896531e4 flex h-6 items-center gap-2 rounded-round bg-surface-feedback-solid-neutral px-2.5 py-1",
{
"h-8 py-2": size === "large",
"h-5 py-0.5": size === "small",
"bg-transparent px-0 py-0":
farbe === "ghost-brand-secondary" ||
farbe === "ghost-brand-primary" ||
farbe === "ghost-blue" ||
farbe === "ghost-purple" ||
farbe === "ghost-information" ||
farbe === "ghost-warning" ||
farbe === "ghost-negative" ||
farbe === "ghost-positive" ||
farbe === "ghost-neutral",
"bg-brand-brand-secondary-surface-subtle-default":
farbe === "subtle-brand-secondary",
"bg-brand-brand-surface-subtle-default":
farbe === "subtle-brand-primary",
"bg-surface-ui-subtle-blue-default": farbe === "subtle-blue",
"bg-surface-ui-subtle-purple-default": farbe === "subtle-purple",
"bg-surface-feedback-subtle-information":
farbe === "subtle-information",
"bg-surface-feedback-subtle-warning": farbe === "subtle-warning",
"bg-surface-feedback-subtle-negative": farbe === "subtle-negative",
"bg-surface-feedback-subtle-positive": farbe === "subtle-positive",
"bg-surface-feedback-subtle-neutral": farbe === "subtle-neutral",
"bg-brand-brand-secondary-surface-solid-default":
farbe === "solid-brand-secondary",
"bg-brand-brand-surface-solid-default":
farbe === "solid-brand-primary",
"bg-surface-ui-solid-blue-default": farbe === "solid-blue",
"bg-surface-ui-solid-purple-default": farbe === "solid-purple",
"bg-surface-feedback-solid-information":
farbe === "solid-information",
"bg-surface-feedback-solid-warning": farbe === "solid-warning",
"bg-surface-feedback-solid-negative-default":
farbe === "solid-negative",
"bg-surface-feedback-solid-positive-default":
farbe === "solid-positive",
},
className
)}
ref={ref}
{...otherProps}
>
<div
className={SubframeUtils.twClassNames(
"flex h-1 w-1 flex-none flex-col items-start gap-2 rounded-round bg-icon-neutral-on-solid",
{
"bg-brand-brand-secondary-surface-solid-default":
farbe === "ghost-brand-secondary" ||
farbe === "subtle-brand-secondary",
"bg-brand-brand-surface-solid-default":
farbe === "ghost-brand-primary" ||
farbe === "subtle-brand-primary",
"bg-icon-ui-blue":
farbe === "ghost-blue" || farbe === "subtle-blue",
"bg-icon-ui-purple":
farbe === "ghost-purple" || farbe === "subtle-purple",
"bg-icon-feedback-information":
farbe === "ghost-information" || farbe === "subtle-information",
"bg-icon-feedback-warning":
farbe === "ghost-warning" || farbe === "subtle-warning",
"bg-icon-feedback-negative":
farbe === "ghost-negative" || farbe === "subtle-negative",
"bg-icon-feedback-positive":
farbe === "ghost-positive" || farbe === "subtle-positive",
"bg-icon-neutral-on-subtle":
farbe === "ghost-neutral" || farbe === "subtle-neutral",
}
)}
/>
{children ? (
<span
className={SubframeUtils.twClassNames(
"whitespace-nowrap text-body-small-medium-0 font-body-small-medium-0 text-text-neutral-on-solid",
{
"text-brand-brand-secondary-surface-solid-default":
farbe === "ghost-brand-secondary",
"text-brand-brand-surface-solid-default":
farbe === "ghost-brand-primary",
"text-text-ui-blue": farbe === "ghost-blue",
"text-text-ui-purple": farbe === "ghost-purple",
"text-text-feedback-information": farbe === "ghost-information",
"text-text-feedback-warning": farbe === "ghost-warning",
"text-text-feedback-negative":
farbe === "ghost-negative" || farbe === "subtle-negative",
"text-text-feedback-positive":
farbe === "ghost-positive" || farbe === "subtle-positive",
"text-text-neutral-on-subtle":
farbe === "ghost-neutral" ||
farbe === "subtle-brand-secondary" ||
farbe === "subtle-brand-primary" ||
farbe === "subtle-blue" ||
farbe === "subtle-purple" ||
farbe === "subtle-information" ||
farbe === "subtle-warning" ||
farbe === "subtle-neutral",
}
)}
>
{children}
</span>
) : null}
</div>
);
});
export const BadgeFeedback = BadgeFeedbackRoot;
+10
View File
@@ -0,0 +1,10 @@
"use client";
import { BadgeFeedback as BadgeFeedbackComponent } from "./BadgeFeedback";
/**
* 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 BadgeFeedback = BadgeFeedbackComponent;
@@ -0,0 +1,121 @@
"use client";
/*
* Documentation:
* Badge Shortcut — https://app.subframe.com/f023064a5ca0/library?component=Badge+Shortcut_97bdb082-1124-4dd7-a335-b14b822d0157
*/
import React from "react";
import { FeatherCommand } from "@subframe/core";
import * as SubframeCore from "@subframe/core";
import * as SubframeUtils from "../../utils";
export interface BadgeShortcutRootProps
extends React.HTMLAttributes<HTMLDivElement> {
variant?:
| "neutral"
| "brand-primary"
| "brand-secondary"
| "error"
| "warning"
| "success";
iconLeft1?: React.ReactNode;
iconLeft2?: React.ReactNode;
children?: React.ReactNode;
iconRight?: React.ReactNode;
size?: "small" | "medium" | "large";
className?: string;
}
const BadgeShortcutRoot = React.forwardRef<
HTMLDivElement,
BadgeShortcutRootProps
>(function BadgeShortcutRoot(
{
variant = "neutral",
iconLeft1 = <FeatherCommand />,
iconLeft2 = null,
children,
iconRight = null,
size = "medium",
className,
...otherProps
}: BadgeShortcutRootProps,
ref
) {
return (
<div
className={SubframeUtils.twClassNames(
"group/97bdb082 flex min-h-[20px] items-center justify-center rounded-sm border border-solid border-surface-feedback-subtle-neutral bg-surface-feedback-subtle-neutral px-1 py-0.5",
{
"min-h-[24px] px-1.5 py-1": size === "large",
"min-h-[14px] px-px py-px": size === "small",
"border border-solid border-surface-feedback-subtle-positive bg-surface-feedback-subtle-positive":
variant === "success",
"border border-solid border-surface-feedback-subtle-warning bg-surface-feedback-subtle-warning":
variant === "warning",
"border border-solid border-surface-feedback-subtle-negative bg-surface-feedback-subtle-negative":
variant === "error",
"border border-solid border-brand-brand-secondary-surface-subtle-default bg-brand-brand-secondary-surface-subtle-default":
variant === "brand-secondary",
"border border-solid border-brand-brand-surface-subtle-default bg-brand-brand-surface-subtle-default":
variant === "brand-primary",
},
className
)}
ref={ref}
{...otherProps}
>
{iconLeft1 ? (
<SubframeCore.IconWrapper
className={SubframeUtils.twClassNames(
"font-['Instrument_Sans'] text-[14px] font-[400] leading-[13px] text-icon-neutral-on-subtle",
{
"text-brand-brand-surface-solid-default":
variant === "brand-primary",
}
)}
>
{iconLeft1}
</SubframeCore.IconWrapper>
) : null}
{iconLeft2 ? (
<SubframeCore.IconWrapper
className={SubframeUtils.twClassNames(
"font-['Instrument_Sans'] text-[14px] font-[400] leading-[13px] text-icon-neutral-on-subtle",
{
"text-brand-brand-surface-solid-default":
variant === "brand-primary",
}
)}
>
{iconLeft2}
</SubframeCore.IconWrapper>
) : null}
{children ? (
<span className="whitespace-nowrap font-['Instrument_Sans'] text-[14px] font-[400] leading-[14px] text-text-neutral-on-subtle">
{children}
</span>
) : null}
{iconRight ? (
<SubframeCore.IconWrapper
className={SubframeUtils.twClassNames(
"font-['Inter'] text-[12px] font-[400] leading-[16px] text-icon-neutral-on-subtle",
{
"text-icon-feedback-positive": variant === "success",
"text-icon-feedback-warning": variant === "warning",
"text-icon-feedback-negative": variant === "error",
"text-brand-brand-secondary-surface-solid-default":
variant === "brand-secondary",
"text-brand-brand-surface-solid-default":
variant === "brand-primary",
}
)}
>
{iconRight}
</SubframeCore.IconWrapper>
) : null}
</div>
);
});
export const BadgeShortcut = BadgeShortcutRoot;
+10
View File
@@ -0,0 +1,10 @@
"use client";
import { BadgeShortcut as BadgeShortcutComponent } from "./BadgeShortcut";
/**
* 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 BadgeShortcut = BadgeShortcutComponent;
+129
View File
@@ -0,0 +1,129 @@
"use client";
/*
* Documentation:
* Banner Alert — https://app.subframe.com/f023064a5ca0/library?component=Banner+Alert_a3e8dcff-3c57-42da-880f-432bb8ce4100
* Link Button — https://app.subframe.com/f023064a5ca0/library?component=Link+Button_a4ee726a-774c-4091-8c49-55b659356024
*/
import React from "react";
import { FeatherAlertCircle } from "@subframe/core";
import { FeatherAlertTriangle } from "@subframe/core";
import { FeatherCheckCircle } from "@subframe/core";
import { FeatherInfo } from "@subframe/core";
import { FeatherX } from "@subframe/core";
import * as SubframeUtils from "../../utils";
import { LinkButton } from "../LinkButton";
export interface BannerAlertRootProps
extends React.HTMLAttributes<HTMLDivElement> {
dismissing?: boolean;
type?: "information" | "success" | "warning" | "error";
fillContainer?: boolean;
hideAction?: boolean;
dismissible?: boolean;
children?: React.ReactNode;
actionLabel?: React.ReactNode;
className?: string;
}
const BannerAlertRoot = React.forwardRef<HTMLDivElement, BannerAlertRootProps>(
function BannerAlertRoot(
{
dismissing = false,
type = "information",
fillContainer = false,
hideAction = false,
dismissible = false,
children,
actionLabel,
className,
...otherProps
}: BannerAlertRootProps,
ref
) {
return (
<div
className={SubframeUtils.twClassNames(
"group/a3e8dcff flex w-256 items-center gap-2 border-b border-solid border-border-information-solid bg-surface-feedback-subtle-information px-4 py-3",
{
"w-full": fillContainer,
"border-b border-x-0 border-t-0 border-solid border-border-negative-solid bg-surface-feedback-subtle-negative":
type === "error",
"border-b border-x-0 border-t-0 border-solid border-border-warning-solid bg-surface-feedback-subtle-warning":
type === "warning",
"border-b border-x-0 border-t-0 border-solid border-border-positive-solid bg-surface-feedback-subtle-positive":
type === "success",
hidden: dismissing,
},
className
)}
ref={ref}
{...otherProps}
>
<FeatherInfo
className={SubframeUtils.twClassNames(
"text-body-large-0 font-body-large-0 text-icon-feedback-information",
{
hidden:
type === "error" || type === "warning" || type === "success",
}
)}
/>
<FeatherCheckCircle
className={SubframeUtils.twClassNames(
"hidden text-body-large-0 font-body-large-0 text-icon-feedback-positive",
{ "inline-flex": type === "success" }
)}
/>
<FeatherAlertTriangle
className={SubframeUtils.twClassNames(
"hidden text-body-large-0 font-body-large-0 text-icon-feedback-warning",
{ "inline-flex": type === "warning" }
)}
/>
<FeatherAlertCircle
className={SubframeUtils.twClassNames(
"hidden text-body-large-0 font-body-large-0 text-icon-feedback-negative",
{ "inline-flex": type === "error" }
)}
/>
{children ? (
<span
className={SubframeUtils.twClassNames(
"grow shrink-0 basis-0 whitespace-pre-wrap text-body-default-regular-0 font-body-default-regular-0 text-text-feedback-information",
{
"text-text-feedback-negative": type === "error",
"text-text-feedback-warning": type === "warning",
"text-text-feedback-positive": type === "success",
}
)}
>
{children}
</span>
) : null}
<LinkButton iconRight={null} underline={true}>
Aktion
</LinkButton>
<div
className={SubframeUtils.twClassNames(
"hidden items-center justify-center rounded-md px-1 py-1 cursor-pointer hover:bg-black-100",
{ "inline-flex": dismissible }
)}
>
<FeatherX
className={SubframeUtils.twClassNames(
"text-body-large-0 font-body-large-0 text-icon-feedback-information",
{
"text-icon-feedback-negative": type === "error",
"text-icon-feedback-warning": type === "warning",
"text-icon-feedback-positive": type === "success",
}
)}
/>
</div>
</div>
);
}
);
export const BannerAlert = BannerAlertRoot;
+10
View File
@@ -0,0 +1,10 @@
"use client";
import { BannerAlert as BannerAlertComponent } from "./BannerAlert";
/**
* 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 BannerAlert = BannerAlertComponent;
@@ -0,0 +1,51 @@
"use client";
/*
* Documentation:
* Banner Offline — https://app.subframe.com/f023064a5ca0/library?component=Banner+Offline_2582cb6e-0176-4a5c-b70f-c3bef3c7001d
*/
import React from "react";
import * as SubframeUtils from "../../utils";
export interface BannerOfflineRootProps
extends React.HTMLAttributes<HTMLDivElement> {
variant?: "default";
text?: React.ReactNode;
className?: string;
}
const BannerOfflineRoot = React.forwardRef<
HTMLDivElement,
BannerOfflineRootProps
>(function BannerOfflineRoot(
{
variant = "default",
text,
className,
...otherProps
}: BannerOfflineRootProps,
ref
) {
return (
<div
className={SubframeUtils.twClassNames(
"flex w-full items-center gap-2 border-b border-solid border-border-warning-solid bg-surface-feedback-subtle-warning px-4 py-3",
className
)}
ref={ref}
{...otherProps}
>
<img
className="h-1 w-1 flex-none object-cover"
src="data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNCIgaGVpZ2h0PSI0IiB2aWV3Qm94PSIwIDAgNCA0IiBmaWxsPSJub25lIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjxjaXJjbGUgY3g9IjIiIGN5PSIyIiByPSIyIiBmaWxsPSIjOUI1RTBEIi8+PC9zdmc+"
/>
{text ? (
<span className="grow shrink-0 basis-0 whitespace-pre-wrap text-body-default-regular-0 font-body-default-regular-0 text-text-feedback-warning">
{text}
</span>
) : null}
</div>
);
});
export const BannerOffline = BannerOfflineRoot;
+10
View File
@@ -0,0 +1,10 @@
"use client";
import { BannerOffline as BannerOfflineComponent } from "./BannerOffline";
/**
* 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 BannerOffline = BannerOfflineComponent;
+42
View File
@@ -0,0 +1,42 @@
"use client";
/*
* Documentation:
* Bar Chart — https://app.subframe.com/f023064a5ca0/library?component=Bar+Chart_4d4f30e7-1869-4980-8b96-617df3b37912
*/
import React from "react";
import * as SubframeCore from "@subframe/core";
import * as SubframeUtils from "../../utils";
export interface BarChartRootProps
extends React.ComponentProps<typeof SubframeCore.BarChart> {
stacked?: boolean;
className?: string;
}
const BarChartRoot = React.forwardRef<
React.ElementRef<typeof SubframeCore.BarChart>,
BarChartRootProps
>(function BarChartRoot(
{ stacked = false, className, ...otherProps }: BarChartRootProps,
ref
) {
return (
<SubframeCore.BarChart
className={SubframeUtils.twClassNames("h-80 w-full", className)}
ref={ref}
stacked={stacked}
colors={[
"#3b82f6",
"#bfdbfe",
"#2563eb",
"#93c5fd",
"#1d4ed8",
"#60a5fa",
]}
{...otherProps}
/>
);
});
export const BarChart = BarChartRoot;
+10
View File
@@ -0,0 +1,10 @@
"use client";
import { BarChart as BarChartComponent } from "./BarChart";
/**
* 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 BarChart = BarChartComponent;
+86
View File
@@ -0,0 +1,86 @@
"use client";
/*
* Documentation:
* Breadcrumbs — https://app.subframe.com/f023064a5ca0/library?component=Breadcrumbs_8898334b-a66f-4ee8-8bd1-afcfa8e37cc0
*/
import React from "react";
import { FeatherChevronRight } from "@subframe/core";
import * as SubframeUtils from "../../utils";
export interface ItemProps extends React.HTMLAttributes<HTMLSpanElement> {
children?: React.ReactNode;
active?: boolean;
className?: string;
}
const Item = React.forwardRef<HTMLSpanElement, ItemProps>(function Item(
{ children, active = false, className, ...otherProps }: ItemProps,
ref
) {
return children ? (
<span
className={SubframeUtils.twClassNames(
"group/bbdc1640 line-clamp-1 cursor-pointer break-words text-body-small-regular-0 font-body-small-regular-0 text-text-neutral-tertiary hover:text-text-neutral-primary",
{ "text-text-neutral-primary": active },
className
)}
ref={ref}
{...otherProps}
>
{children}
</span>
) : null;
});
export interface DividerProps
extends React.ComponentProps<typeof FeatherChevronRight> {
className?: string;
}
const Divider = React.forwardRef<
React.ElementRef<typeof FeatherChevronRight>,
DividerProps
>(function Divider({ className, ...otherProps }: DividerProps, ref) {
return (
<FeatherChevronRight
className={SubframeUtils.twClassNames(
"text-body-small-regular-0 font-body-small-regular-0 text-icon-neutral-tertiary",
className
)}
ref={ref}
{...otherProps}
/>
);
});
export interface BreadcrumbsRootProps
extends React.HTMLAttributes<HTMLDivElement> {
children?: React.ReactNode;
className?: string;
}
const BreadcrumbsRoot = React.forwardRef<HTMLDivElement, BreadcrumbsRootProps>(
function BreadcrumbsRoot(
{ children, className, ...otherProps }: BreadcrumbsRootProps,
ref
) {
return children ? (
<div
className={SubframeUtils.twClassNames(
"flex items-center gap-2",
className
)}
ref={ref}
{...otherProps}
>
{children}
</div>
) : null;
}
);
export const Breadcrumbs = Object.assign(BreadcrumbsRoot, {
Item,
Divider,
});
+10
View File
@@ -0,0 +1,10 @@
"use client";
import { Breadcrumbs as BreadcrumbsComponent } from "./Breadcrumbs";
/**
* 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 Breadcrumbs = BreadcrumbsComponent;
+152
View File
@@ -0,0 +1,152 @@
"use client";
/*
* Documentation:
* Button — https://app.subframe.com/f023064a5ca0/library?component=Button_3b777358-b86b-40af-9327-891efc6826fe
*/
import React from "react";
import * as SubframeCore from "@subframe/core";
import * as SubframeUtils from "../../utils";
export interface ButtonRootProps
extends React.ButtonHTMLAttributes<HTMLButtonElement> {
disabled?: boolean;
loading?: boolean;
variant?:
| "primary"
| "secondary"
| "tertiary"
| "ghost"
| "destructive"
| "neutral"
| "success"
| "warning"
| "information";
size?: "large" | "medium" | "small";
children?: React.ReactNode;
icon?: React.ReactNode;
iconRight?: React.ReactNode;
onClick?: (event: React.MouseEvent<HTMLButtonElement>) => void;
className?: string;
}
const ButtonRoot = React.forwardRef<HTMLButtonElement, ButtonRootProps>(
function ButtonRoot(
{
disabled = false,
loading = false,
variant = "primary",
size = "medium",
children,
icon = null,
iconRight = null,
className,
type = "button",
...otherProps
}: ButtonRootProps,
ref
) {
return (
<button
className={SubframeUtils.twClassNames(
"group/3b777358 flex h-9 cursor-pointer items-center justify-center gap-3 rounded-md border-none bg-brand-brand-surface-solid-default px-4 py-2.5 text-left hover:bg-brand-brand-surface-solid-hover active:bg-brand-brand-surface-solid-active focus-within:shadow-focus disabled:cursor-default disabled:bg-surface-neutral-disabled disabled:pointer-events-none hover:disabled:cursor-default hover:disabled:bg-surface-neutral-disabled active:disabled:cursor-default active:disabled:bg-surface-neutral-disabled",
{
"h-8 gap-2 px-3 py-2": size === "small",
"h-12 gap-2.5 px-5 py-3.5": size === "large",
"bg-surface-feedback-solid-information hover:bg-surface-feedback-solid-information-hover active:bg-surface-feedback-solid-information-active":
variant === "information",
"bg-surface-feedback-solid-warning hover:bg-surface-feedback-solid-warning-hover active:bg-surface-feedback-solid-warning-active":
variant === "warning",
"bg-surface-feedback-solid-positive-default hover:bg-surface-feedback-solid-positive-hover active:bg-surface-feedback-solid-positive-active":
variant === "success",
"bg-surface-feedback-solid-neutral hover:bg-surface-feedback-solid-neutral-hover active:bg-surface-feedback-solid-neutral-active":
variant === "neutral",
"bg-surface-feedback-solid-negative-default hover:bg-surface-feedback-solid-negative-hover active:bg-surface-feedback-solid-negative-active":
variant === "destructive",
"bg-transparent hover:border hover:border-solid hover:border-border-strong hover:bg-surface-neutral-secondary active:bg-surface-neutral-tertiary focus-within:border focus-within:border-solid focus-within:border-border-default focus-within:bg-surface-neutral-secondary":
variant === "ghost",
"border border-solid border-border-default bg-surface-neutral-primary hover:border hover:border-solid hover:border-border-strong hover:bg-surface-neutral-secondary active:bg-surface-neutral-tertiary":
variant === "tertiary",
"bg-brand-brand-secondary-surface-subtle-default hover:bg-brand-brand-secondary-surface-subtle-hover active:bg-brand-brand-secondary-surface-subtle-active":
variant === "secondary",
},
className
)}
ref={ref}
type={type}
disabled={disabled}
{...otherProps}
>
{icon ? (
<SubframeCore.IconWrapper
className={SubframeUtils.twClassNames(
"text-body-default-regular-0 font-body-default-regular-0 text-icon-neutral-on-solid group-disabled/3b777358:text-icon-neutral-disabled",
{
"text-body-large-0 font-body-large-0": size === "large",
"text-icon-neutral-secondary": variant === "ghost",
"text-icon-neutral-on-subtle": variant === "tertiary",
"text-icon-neutral-primary": variant === "secondary",
hidden: loading,
}
)}
>
{icon}
</SubframeCore.IconWrapper>
) : null}
<div
className={SubframeUtils.twClassNames(
"hidden h-4 w-4 flex-none items-center justify-center gap-2",
{ "h-5 w-5": size === "large", flex: loading }
)}
>
<SubframeCore.Loader
className={SubframeUtils.twClassNames(
"text-body-extra-small-regular-150 font-body-extra-small-regular-150 text-icon-neutral-on-solid group-disabled/3b777358:text-icon-neutral-disabled group-hover/3b777358:group-disabled/3b777358:text-icon-neutral-on-solid group-active/3b777358:group-disabled/3b777358:text-icon-neutral-disabled",
{
"text-icon-neutral-secondary": variant === "ghost",
"text-icon-neutral-on-subtle": variant === "tertiary",
"text-icon-neutral-primary": variant === "secondary",
}
)}
/>
</div>
{children ? (
<span
className={SubframeUtils.twClassNames(
"whitespace-nowrap text-body-default-regular-0 font-body-default-regular-0 text-text-neutral-on-solid group-disabled/3b777358:text-text-neutral-disabled",
{
"text-body-large-0 font-body-large-0": size === "large",
"text-text-neutral-primary":
variant === "ghost" ||
variant === "tertiary" ||
variant === "secondary",
"hidden text-body-small-medium-150 font-body-small-medium-150":
loading,
}
)}
>
{children}
</span>
) : null}
{iconRight ? (
<SubframeCore.IconWrapper
className={SubframeUtils.twClassNames(
"text-body-default-regular-150 font-body-default-regular-150 text-icon-neutral-on-solid group-disabled/3b777358:text-icon-neutral-disabled",
{
"text-body-large font-body-large": size === "large",
"text-icon-neutral-secondary": variant === "ghost",
"text-icon-neutral-on-subtle": variant === "tertiary",
"text-icon-neutral-primary": variant === "secondary",
hidden: loading,
}
)}
>
{iconRight}
</SubframeCore.IconWrapper>
) : null}
</button>
);
}
);
export const Button = ButtonRoot;
+10
View File
@@ -0,0 +1,10 @@
"use client";
import { Button as ButtonComponent } from "./Button";
/**
* 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 Button = ButtonComponent;
+51
View File
@@ -0,0 +1,51 @@
"use client";
/*
* Documentation:
* Button Group — https://app.subframe.com/f023064a5ca0/library?component=Button+Group_e0379327-50f0-4852-9ae1-ad09b4bf01d3
*/
import React from "react";
import * as SubframeUtils from "../../utils";
export interface ButtonGroupRootProps
extends React.HTMLAttributes<HTMLDivElement> {
vertical?: boolean;
align?: "start" | "center" | "end" | "stretch";
children?: React.ReactNode;
className?: string;
}
const ButtonGroupRoot = React.forwardRef<HTMLDivElement, ButtonGroupRootProps>(
function ButtonGroupRoot(
{
vertical = false,
align = "start",
children,
className,
...otherProps
}: ButtonGroupRootProps,
ref
) {
return children ? (
<div
className={SubframeUtils.twClassNames(
"group/e0379327 flex w-full items-center gap-2",
{
"justify-start items-stretch [&>*]:grow [&>*]:basis-0":
align === "stretch",
"justify-end": align === "end",
"justify-center": align === "center",
"flex-col items-start": vertical,
},
className
)}
ref={ref}
{...otherProps}
>
{children}
</div>
) : null;
}
);
export const ButtonGroup = ButtonGroupRoot;
+10
View File
@@ -0,0 +1,10 @@
"use client";
import { ButtonGroup as ButtonGroupComponent } from "./ButtonGroup";
/**
* 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 ButtonGroup = ButtonGroupComponent;
+53
View File
@@ -0,0 +1,53 @@
"use client";
/*
* Documentation:
* Calendar — https://app.subframe.com/f023064a5ca0/library?component=Calendar_5a87e517-ace2-49af-adcf-076c97ec3921
*/
import React from "react";
import * as SubframeCore from "@subframe/core";
import * as SubframeUtils from "../../utils";
export type CalendarRootProps = React.ComponentProps<
typeof SubframeCore.Calendar
> & { className?: string };
const CalendarRoot = React.forwardRef<
React.ElementRef<typeof SubframeCore.Calendar>,
CalendarRootProps
>(function CalendarRoot({ className, ...otherProps }: CalendarRootProps, ref) {
return (
<SubframeCore.Calendar
className={className}
ref={ref}
classNames={{
root: "relative border-box",
month: "flex flex-col gap-4",
months: "relative flex flex-wrap max-w-fit gap-4",
nav: "absolute flex items-center justify-between h-8 w-full p-0.5",
month_caption: "flex items-center justify-center h-8",
caption_label: "text-body-bold font-body-bold text-default-font",
button_previous:
"inline-flex items-center justify-center h-8 w-8 bg-transparent rounded-md border-none bg-transparent hover:bg-neutral-50 active:bg-neutral-100 border-none",
button_next:
"inline-flex items-center justify-center h-8 w-8 bg-transparent rounded-md border-none bg-transparent hover:bg-neutral-50 active:bg-neutral-100 border-none",
chevron: "text-[18px] font-[500] leading-[18px] text-neutral-600",
weeks: "flex flex-col gap-2",
weekdays: "flex pb-4",
weekday: "w-8 text-caption-bold font-caption-bold text-subtext-color",
week: "flex rounded-lg overflow-hidden",
day: "group flex p-0 cursor-pointer items-center justify-center text-body font-body text-default-font h-8 w-8",
day_button:
"flex h-8 w-8 cursor-pointer items-center justify-center gap-2 rounded-lg border-none hover:bg-neutral-100 group-[.selected]:bg-brand-600 group-[.selected]:text-white group-[.outside]:bg-transparent group-[.outside.selected]:bg-neutral-100 group-[.outside.range-start]:bg-neutral-100 group-[.outside.range-end]:bg-neutral-100 group-[.outside.range-start]:rounded-l-lg group-[.outside.range-start]:rounded-r-none group-[.outside.range-end]:rounded-l-none group-[.outside.range-end]:rounded-r-lg group-[.outside]:!text-neutral-400 group-[.outside]:hover:bg-neutral-100 group-[.range-middle.selected]:bg-neutral-100 group-[.range-middle.selected]:text-default-font group-[.range-middle.selected]:hover:bg-neutral-100 group-[.range-middle.selected]:rounded-none",
selected: "selected",
outside: "outside",
range_start: "range-start bg-neutral-100 rounded-l-lg",
range_middle: "range-middle",
range_end: "range-end bg-neutral-100 rounded-r-lg",
}}
{...otherProps}
/>
);
});
export const Calendar = CalendarRoot;
+10
View File
@@ -0,0 +1,10 @@
"use client";
import { Calendar as CalendarComponent } from "./Calendar";
/**
* 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 Calendar = CalendarComponent;
+65
View File
@@ -0,0 +1,65 @@
"use client";
/*
* Documentation:
* Card — https://app.subframe.com/f023064a5ca0/library?component=Card_56067c50-02ce-4c7c-8866-9db30e23ecc0
*/
import React from "react";
import * as SubframeUtils from "../../utils";
export interface CardRootProps extends React.HTMLAttributes<HTMLDivElement> {
children?: React.ReactNode;
size?: "extra-small" | "small" | "medium" | "large" | "extra-large";
variant?:
| "default"
| "neutral"
| "information"
| "positive"
| "warning"
| "negative";
className?: string;
}
const CardRoot = React.forwardRef<HTMLDivElement, CardRootProps>(
function CardRoot(
{
children,
size = "medium",
variant = "default",
className,
...otherProps
}: CardRootProps,
ref
) {
return children ? (
<div
className={SubframeUtils.twClassNames(
"group/56067c50 flex min-w-[384px] max-w-[448px] flex-col items-start gap-4 rounded-md border border-solid border-border-default bg-surface-neutral-secondary px-4 py-4 shadow-sm",
{
"border border-solid border-border-negative-subtle bg-surface-feedback-subtle-negative":
variant === "negative",
"border border-solid border-border-warning-subtle bg-surface-feedback-subtle-warning":
variant === "warning",
"border border-solid border-border-positive-subtle bg-surface-feedback-subtle-positive":
variant === "positive",
"border border-solid border-border-information-subtle bg-surface-feedback-subtle-information":
variant === "information",
"border border-solid border-surface-feedback-subtle-neutral bg-surface-feedback-subtle-neutral":
variant === "neutral",
"px-8 py-8": size === "extra-large",
"px-6 py-6": size === "large",
"px-2 py-2": size === "small",
"px-1 py-1": size === "extra-small",
},
className
)}
ref={ref}
{...otherProps}
>
{children}
</div>
) : null;
}
);
export const Card = CardRoot;
+10
View File
@@ -0,0 +1,10 @@
"use client";
import { Card as CardComponent } from "./Card";
/**
* 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 Card = CardComponent;
+84
View File
@@ -0,0 +1,84 @@
"use client";
/*
* Documentation:
* Button — https://app.subframe.com/f023064a5ca0/library?component=Button_3b777358-b86b-40af-9327-891efc6826fe
* Card Icon — https://app.subframe.com/f023064a5ca0/library?component=Card+Icon_41867f0d-7a6a-4e51-9b08-6cce5a3070b1
*/
import React from "react";
import { FeatherInfo } from "@subframe/core";
import * as SubframeUtils from "../../utils";
import { Button } from "../Button";
export interface CardIconRootProps
extends Omit<React.HTMLAttributes<HTMLDivElement>, "title"> {
outlined?: boolean;
layout?: "horizontal" | "vertical";
hideIcon?: boolean;
title?: React.ReactNode;
body?: React.ReactNode;
className?: string;
}
const CardIconRoot = React.forwardRef<HTMLDivElement, CardIconRootProps>(
function CardIconRoot(
{
outlined = false,
layout = "horizontal",
hideIcon = false,
title,
body,
className,
...otherProps
}: CardIconRootProps,
ref
) {
return (
<div
className={SubframeUtils.twClassNames(
"group/41867f0d flex min-w-[448px] max-w-[448px] items-start gap-6 px-6 py-6",
{
"flex-col": layout === "vertical",
"rounded-md border border-solid border-border-default bg-surface-neutral-primary":
outlined,
},
className
)}
ref={ref}
{...otherProps}
>
<div
className={SubframeUtils.twClassNames("flex items-start gap-4", {
hidden: hideIcon,
})}
>
<FeatherInfo className="font-['Inter'] text-[24px] font-[400] leading-[24px] text-icon-neutral-primary" />
</div>
<div className="flex flex-col items-start gap-6">
<div
className={SubframeUtils.twClassNames(
"flex w-full flex-col items-start gap-3 pr-6",
{ "gap-6": layout === "vertical" }
)}
>
{title ? (
<span className="w-full text-body-large-0 font-body-large-0 text-text-neutral-primary">
{title}
</span>
) : null}
<div className="flex w-full flex-col items-start gap-5">
{body ? (
<span className="w-full break-words text-body-default-regular-150 font-body-default-regular-150 text-text-neutral-secondary">
{body}
</span>
) : null}
<Button>Button</Button>
</div>
</div>
</div>
</div>
);
}
);
export const CardIcon = CardIconRoot;
+10
View File
@@ -0,0 +1,10 @@
"use client";
import { CardIcon as CardIconComponent } from "./CardIcon";
/**
* 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 CardIcon = CardIconComponent;
+83
View File
@@ -0,0 +1,83 @@
"use client";
/*
* Documentation:
* Button — https://app.subframe.com/f023064a5ca0/library?component=Button_3b777358-b86b-40af-9327-891efc6826fe
* Card Image — https://app.subframe.com/f023064a5ca0/library?component=Card+Image_1f735087-2381-42e1-8ceb-491a8bc63948
*/
import React from "react";
import * as SubframeUtils from "../../utils";
import { Button } from "../Button";
export interface CardImageRootProps
extends Omit<React.HTMLAttributes<HTMLDivElement>, "title"> {
outlined?: boolean;
layout?: "horizontal" | "vertical";
hideImage?: boolean;
title?: React.ReactNode;
body?: React.ReactNode;
className?: string;
}
const CardImageRoot = React.forwardRef<HTMLDivElement, CardImageRootProps>(
function CardImageRoot(
{
outlined = false,
layout = "horizontal",
hideImage = false,
title,
body,
className,
...otherProps
}: CardImageRootProps,
ref
) {
return (
<div
className={SubframeUtils.twClassNames(
"group/1f735087 flex min-w-[448px] max-w-[448px] items-start gap-6 px-6 py-6",
{
"flex-col": layout === "vertical",
"rounded-md border border-solid border-border-default bg-surface-neutral-primary":
outlined,
},
className
)}
ref={ref}
{...otherProps}
>
<img
className={SubframeUtils.twClassNames(
"h-40 w-40 flex-none object-cover",
{ hidden: hideImage }
)}
src="https://res.cloudinary.com/subframe/image/upload/v1711417507/shared/y2rsnhq3mex4auk54aye.png"
/>
<div className="flex flex-col items-start gap-6">
<div
className={SubframeUtils.twClassNames(
"flex w-full flex-col items-start gap-3 pr-6",
{ "gap-6": layout === "vertical" }
)}
>
{title ? (
<span className="w-full text-body-large-0 font-body-large-0 text-icon-neutral-primary">
{title}
</span>
) : null}
<div className="flex w-full flex-col items-start gap-5">
{body ? (
<span className="w-full break-words text-body-default-regular-150 font-body-default-regular-150 text-icon-neutral-primary">
{body}
</span>
) : null}
<Button>Button</Button>
</div>
</div>
</div>
</div>
);
}
);
export const CardImage = CardImageRoot;
+10
View File
@@ -0,0 +1,10 @@
"use client";
import { CardImage as CardImageComponent } from "./CardImage";
/**
* 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 CardImage = CardImageComponent;
+145
View File
@@ -0,0 +1,145 @@
"use client";
/*
* Documentation:
* Checkbox — https://app.subframe.com/f023064a5ca0/library?component=Checkbox_3816e3b5-c48c-499b-b45e-0777c6972523
*/
import React from "react";
import { FeatherCheck } from "@subframe/core";
import { FeatherMinus } from "@subframe/core";
import * as SubframeCore from "@subframe/core";
import * as SubframeUtils from "../../utils";
export interface CheckboxRootProps
extends React.ComponentProps<typeof SubframeCore.Checkbox.Root> {
label?: React.ReactNode;
disabled?: boolean;
checked?: boolean;
error?: boolean;
description?: React.ReactNode;
helpText?: React.ReactNode;
indeterminate?: boolean;
hideLabel?: boolean;
onCheckedChange?: (checked: boolean) => void;
className?: string;
}
const CheckboxRoot = React.forwardRef<HTMLButtonElement, CheckboxRootProps>(
function CheckboxRoot(
{
label,
disabled = false,
checked = false,
error = false,
description,
helpText,
indeterminate = false,
hideLabel = false,
className,
...otherProps
}: CheckboxRootProps,
ref
) {
return (
<SubframeCore.Checkbox.Root
checked={checked}
disabled={disabled}
asChild={true}
{...otherProps}
>
<button
className={SubframeUtils.twClassNames(
"group/3816e3b5 flex cursor-pointer items-start justify-between text-left",
className
)}
ref={ref}
>
<div
className={SubframeUtils.twClassNames("flex items-center pt-0.5", {
"px-0 py-0": hideLabel,
})}
>
<div
className={SubframeUtils.twClassNames(
"flex h-4 w-4 flex-none flex-col items-center justify-center gap-2 rounded-sm border-2 border-solid border-border-strong bg-surface-neutral-secondary group-hover/3816e3b5:border-2 group-hover/3816e3b5:border-solid group-hover/3816e3b5:border-brand-brand-border-solid-hover group-focus-within/3816e3b5:shadow-focus group-aria-[checked=true]/3816e3b5:border-2 group-aria-[checked=true]/3816e3b5:border-solid group-aria-[checked=true]/3816e3b5:border-brand-brand-border-solid-default group-aria-[checked=true]/3816e3b5:bg-brand-brand-surface-solid-default group-hover/3816e3b5:group-aria-[checked=true]/3816e3b5:bg-brand-brand-surface-solid-hover group-disabled/3816e3b5:border group-disabled/3816e3b5:border-solid group-disabled/3816e3b5:border-border-disabled group-disabled/3816e3b5:bg-surface-neutral-disabled",
{
"border-2 border-solid border-border-negative-solid group-hover/3816e3b5:border-2 group-hover/3816e3b5:border-solid group-hover/3816e3b5:border-border-negative-solid":
error,
}
)}
>
{indeterminate ? (
<FeatherMinus
className={SubframeUtils.twClassNames(
"hidden text-body-extra-small-semibold-150 font-body-extra-small-semibold-150 text-icon-neutral-on-solid group-aria-[checked=true]/3816e3b5:inline-flex group-disabled/3816e3b5:text-icon-neutral-disabled",
{ "inline-flex": indeterminate }
)}
/>
) : (
<FeatherCheck
className={SubframeUtils.twClassNames(
"hidden text-body-extra-small-semibold-150 font-body-extra-small-semibold-150 text-icon-neutral-on-solid group-aria-[checked=true]/3816e3b5:inline-flex group-disabled/3816e3b5:text-icon-neutral-disabled",
{ "inline-flex": indeterminate }
)}
/>
)}
</div>
<div
className={SubframeUtils.twClassNames(
"hidden h-4 w-4 flex-none flex-col items-center justify-center gap-2 rounded-round border-2 border-solid border-border-strong bg-surface-neutral-secondary group-hover/3816e3b5:border-brand-brand-border-solid-hover group-focus-within/3816e3b5:shadow-focus group-aria-[checked=true]/3816e3b5:border-2 group-aria-[checked=true]/3816e3b5:border-solid group-aria-[checked=true]/3816e3b5:border-brand-brand-border-solid-default group-disabled/3816e3b5:border-2 group-disabled/3816e3b5:border-solid group-disabled/3816e3b5:border-border-disabled group-disabled/3816e3b5:bg-surface-neutral-disabled",
{
"border-2 border-solid border-border-negative-solid group-hover/3816e3b5:border-border-negative-solid":
error,
}
)}
>
<div
className={SubframeUtils.twClassNames(
"hidden h-2 w-2 flex-none items-start rounded-round bg-brand-brand-surface-solid-default group-hover/3816e3b5:bg-brand-brand-surface-solid-hover group-aria-[checked=true]/3816e3b5:flex group-disabled/3816e3b5:bg-icon-neutral-disabled",
{
"bg-surface-feedback-solid-negative-default group-hover/3816e3b5:bg-surface-feedback-solid-negative-hover":
error,
}
)}
/>
</div>
</div>
<div
className={SubframeUtils.twClassNames(
"flex flex-col items-start pl-2 group-hover/3816e3b5:grow group-hover/3816e3b5:shrink-0 group-hover/3816e3b5:basis-0",
{ hidden: hideLabel }
)}
>
{label ? (
<span
className={SubframeUtils.twClassNames(
"text-body-small-medium-150 font-body-small-medium-150 text-text-neutral-primary group-disabled/3816e3b5:text-text-neutral-disabled",
{ "text-text-feedback-negative": error }
)}
>
{label}
</span>
) : null}
{description ? (
<span className="text-body-extra-small-regular-150 font-body-extra-small-regular-150 text-text-neutral-tertiary group-disabled/3816e3b5:text-text-neutral-disabled">
{description}
</span>
) : null}
{helpText ? (
<span
className={SubframeUtils.twClassNames(
"text-body-extra-small-regular-150 font-body-extra-small-regular-150 text-text-neutral-tertiary",
{ "text-text-feedback-negative": error }
)}
>
{helpText}
</span>
) : null}
</div>
</button>
</SubframeCore.Checkbox.Root>
);
}
);
export const Checkbox = CheckboxRoot;
+10
View File
@@ -0,0 +1,10 @@
"use client";
import { Checkbox as CheckboxComponent } from "./Checkbox";
/**
* 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 Checkbox = CheckboxComponent;
@@ -0,0 +1,68 @@
"use client";
/*
* Documentation:
* Checkbox Card — https://app.subframe.com/f023064a5ca0/library?component=Checkbox+Card_de0b4dfb-3946-4702-be52-5678dd71925a
*/
import React from "react";
import { FeatherCheck } from "@subframe/core";
import * as SubframeCore from "@subframe/core";
import * as SubframeUtils from "../../utils";
export interface CheckboxCardRootProps
extends React.ComponentProps<typeof SubframeCore.Checkbox.Root> {
disabled?: boolean;
checked?: boolean;
showCheckbox?: boolean;
children?: React.ReactNode;
onCheckedChange?: (checked: boolean) => void;
className?: string;
}
const CheckboxCardRoot = React.forwardRef<
HTMLButtonElement,
CheckboxCardRootProps
>(function CheckboxCardRoot(
{
disabled = false,
checked = false,
showCheckbox = false,
children,
className,
...otherProps
}: CheckboxCardRootProps,
ref
) {
return (
<SubframeCore.Checkbox.Root
checked={checked}
disabled={disabled}
asChild={true}
{...otherProps}
>
<button
className={SubframeUtils.twClassNames(
"group/de0b4dfb flex cursor-pointer items-center gap-4 rounded-md border border-solid border-border-default bg-surface-neutral-secondary px-2 py-2 text-left hover:bg-surface-neutral-tertiary aria-[checked=true]:border aria-[checked=true]:border-solid aria-[checked=true]:border-brand-brand-secondary-border-subtle-default aria-[checked=true]:bg-surface-ui-subtle-blue-default hover:aria-[checked=true]:bg-surface-ui-subtle-blue-hover disabled:cursor-default disabled:border disabled:border-solid disabled:border-border-disabled disabled:bg-surface-neutral-disabled hover:disabled:cursor-default hover:disabled:bg-surface-neutral-disabled",
className
)}
ref={ref}
>
<div
className={SubframeUtils.twClassNames(
"hidden h-4 w-4 flex-none flex-col items-center justify-center rounded-sm border-2 border-solid border-border-strong bg-surface-neutral-secondary group-aria-[checked=true]/de0b4dfb:border-2 group-aria-[checked=true]/de0b4dfb:border-solid group-aria-[checked=true]/de0b4dfb:border-brand-brand-border-solid-default group-aria-[checked=true]/de0b4dfb:bg-brand-brand-surface-solid-default group-disabled/de0b4dfb:border-2 group-disabled/de0b4dfb:border-solid group-disabled/de0b4dfb:border-border-disabled group-disabled/de0b4dfb:bg-surface-neutral-disabled",
{ flex: showCheckbox }
)}
>
<FeatherCheck className="hidden text-body-extra-small-semibold-150 font-body-extra-small-semibold-150 text-icon-neutral-on-solid group-aria-[checked=true]/de0b4dfb:inline-flex group-disabled/de0b4dfb:text-icon-neutral-disabled" />
</div>
{children ? (
<div className="flex grow shrink-0 basis-0 items-center gap-4">
{children}
</div>
) : null}
</button>
</SubframeCore.Checkbox.Root>
);
});
export const CheckboxCard = CheckboxCardRoot;
+10
View File
@@ -0,0 +1,10 @@
"use client";
import { CheckboxCard as CheckboxCardComponent } from "./CheckboxCard";
/**
* 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 CheckboxCard = CheckboxCardComponent;
@@ -0,0 +1,73 @@
"use client";
/*
* Documentation:
* Checkbox Group — https://app.subframe.com/f023064a5ca0/library?component=Checkbox+Group_f9f1b596-c6b3-4d60-aa9a-f34b353f8aa5
*/
import React from "react";
import * as SubframeUtils from "../../utils";
export interface CheckboxGroupRootProps
extends React.HTMLAttributes<HTMLDivElement> {
label?: React.ReactNode;
helpText?: React.ReactNode;
error?: boolean;
horizontal?: boolean;
children?: React.ReactNode;
className?: string;
}
const CheckboxGroupRoot = React.forwardRef<
HTMLDivElement,
CheckboxGroupRootProps
>(function CheckboxGroupRoot(
{
label,
helpText,
error = false,
horizontal = false,
children,
className,
...otherProps
}: CheckboxGroupRootProps,
ref
) {
return (
<div
className={SubframeUtils.twClassNames(
"group/f9f1b596 flex flex-col items-start gap-2",
className
)}
ref={ref}
{...otherProps}
>
{label ? (
<span className="text-body-small-medium-150 font-body-small-medium-150 text-text-neutral-primary">
{label}
</span>
) : null}
{children ? (
<div
className={SubframeUtils.twClassNames(
"flex flex-col items-start gap-2",
{ "flex-row gap-6": horizontal }
)}
>
{children}
</div>
) : null}
{helpText ? (
<span
className={SubframeUtils.twClassNames(
"text-body-extra-small-regular-150 font-body-extra-small-regular-150 text-text-neutral-tertiary",
{ "text-text-feedback-negative": error }
)}
>
{helpText}
</span>
) : null}
</div>
);
});
export const CheckboxGroup = CheckboxGroupRoot;
+10
View File
@@ -0,0 +1,10 @@
"use client";
import { CheckboxGroup as CheckboxGroupComponent } from "./CheckboxGroup";
/**
* 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 CheckboxGroup = CheckboxGroupComponent;
+386
View File
@@ -0,0 +1,386 @@
// @subframe/sync-disable
// @ts-nocheck
"use client";
/*
* Documentation:
* Combobox — https://app.subframe.com/f023064a5ca0/library?component=Combobox_8a1be2ee-c1b7-4407-9c21-6448306d2700
* Loader — https://app.subframe.com/f023064a5ca0/library?component=Loader_f2e570c8-e463-45c2-aae9-a960146bc5d5
*/
import React from "react";
import { FeatherCheck } from "@subframe/core";
import { FeatherChevronDown } from "@subframe/core";
import { FeatherLoader } from "@subframe/core";
import { FeatherPlus } from "@subframe/core";
import { FeatherSearch } from "@subframe/core";
import { FeatherSearchX } from "@subframe/core";
import { FeatherX } from "@subframe/core";
import * as SubframeCore from "@subframe/core";
import * as SubframeUtils from "../../utils";
import { Loader } from "../Loader";
export interface ChipProps extends React.HTMLAttributes<HTMLDivElement> {
children?: React.ReactNode;
className?: string;
}
const Chip = React.forwardRef<HTMLDivElement, ChipProps>(function Chip(
{ children, className, ...otherProps }: ChipProps,
ref
) {
return (
<div
className={SubframeUtils.twClassNames(
"flex items-center gap-1 rounded-sm border border-solid border-border-default bg-surface-feedback-subtle-neutral pl-2 pr-1 py-0.5",
className
)}
ref={ref}
{...otherProps}
>
{children ? (
<span className="whitespace-nowrap text-body-small-medium-0 font-body-small-medium-0 text-text-neutral-on-subtle">
{children}
</span>
) : null}
<div className="flex h-4 w-4 flex-none flex-col items-center justify-center rounded-sm cursor-pointer hover:bg-surface-feedback-subtle-neutral-hover active:bg-surface-feedback-subtle-neutral-active">
<FeatherX className="text-body-small-medium-0 font-body-small-medium-0 text-icon-neutral-tertiary" />
</div>
</div>
);
});
export interface ItemProps extends React.HTMLAttributes<HTMLDivElement> {
children?: React.ReactNode;
selected?: boolean;
showCheckbox?: boolean;
className?: string;
}
const Item = React.forwardRef<HTMLDivElement, ItemProps>(function Item(
{
children,
selected = false,
showCheckbox = false,
className,
...otherProps
}: ItemProps,
ref
) {
return (
<div
className={SubframeUtils.twClassNames(
"group/7b9d6745 flex w-full cursor-pointer items-center gap-2 rounded-sm px-2 py-2 hover:bg-surface-neutral-tertiary active:bg-surface-neutral-secondary",
{
"bg-surface-ui-subtle-blue-default hover:bg-surface-ui-subtle-blue-hover active:bg-surface-ui-subtle-blue-active":
selected,
},
className
)}
ref={ref}
{...otherProps}
>
<div
className={SubframeUtils.twClassNames(
"hidden h-4 w-4 flex-none flex-col items-center justify-center rounded-sm border-2 border-solid border-border-strong bg-surface-neutral-secondary",
{
flex: showCheckbox,
"border-2 border-solid border-brand-brand-border-solid-default bg-brand-brand-surface-solid-default":
selected,
}
)}
>
<FeatherCheck
className={SubframeUtils.twClassNames(
"hidden text-body-extra-small-semibold-0 font-body-extra-small-semibold-0 text-icon-neutral-on-solid",
{ "inline-flex": selected }
)}
/>
</div>
{children ? (
<span
className={SubframeUtils.twClassNames(
"grow shrink-0 basis-0 text-body-default-regular-0 font-body-default-regular-0 text-text-neutral-tertiary",
{ "text-text-neutral-primary": selected }
)}
>
{children}
</span>
) : null}
<FeatherCheck
className={SubframeUtils.twClassNames(
"hidden text-body-default-regular-0 font-body-default-regular-0 text-icon-neutral-primary",
{ "inline-flex": selected }
)}
/>
</div>
);
});
export interface AddItemProps extends React.HTMLAttributes<HTMLDivElement> {
children?: React.ReactNode;
className?: string;
}
const AddItem = React.forwardRef<HTMLDivElement, AddItemProps>(function AddItem(
{ children, className, ...otherProps }: AddItemProps,
ref
) {
return (
<div
className={SubframeUtils.twClassNames(
"group/4458d273 flex w-full cursor-pointer items-center gap-2 rounded-sm px-2 py-2 group/add-item hover:bg-surface-neutral-tertiary active:bg-surface-neutral-secondary",
className
)}
ref={ref}
{...otherProps}
>
<FeatherPlus className="text-body-default-regular-0 font-body-default-regular-0 text-icon-feedback-information" />
{children ? (
<span className="grow shrink-0 basis-0 text-body-default-medium-0 font-body-default-medium-0 text-text-feedback-information">
{children}
</span>
) : null}
</div>
);
});
export interface ComboboxRootProps
extends Omit<React.HTMLAttributes<HTMLDivElement>, "placeholder"> {
disabled?: boolean;
error?: boolean;
state?: "default" | "typing" | "no-results" | "loading" | "create-new";
hasValue?: boolean;
open?: boolean;
showLabel?: boolean;
label?: React.ReactNode;
helpText?: React.ReactNode;
searchValue?: React.ReactNode;
placeholder?: React.ReactNode;
createLabel?: React.ReactNode;
emptyText?: React.ReactNode;
loadingText?: React.ReactNode;
message?: React.ReactNode;
icon?: React.ReactNode;
chipChildren?: React.ReactNode;
children?: React.ReactNode;
size?: "small" | "medium" | "large";
className?: string;
}
const ComboboxRoot = React.forwardRef<HTMLDivElement, ComboboxRootProps>(
function ComboboxRoot(
{
disabled = false,
error = false,
state = "default",
hasValue = false,
open = false,
showLabel = false,
label,
helpText,
searchValue,
placeholder,
createLabel,
emptyText,
loadingText,
message,
icon = <FeatherSearch />,
chipChildren,
children,
size = "medium",
className,
...otherProps
}: ComboboxRootProps,
ref
) {
return (
<div
className={SubframeUtils.twClassNames(
"group/8a1be2ee flex min-w-[192px] max-w-[576px] cursor-pointer flex-col items-start gap-3",
{ "gap-0": showLabel },
className
)}
ref={ref}
{...otherProps}
>
<div
className={SubframeUtils.twClassNames(
"hidden w-full flex-col items-start",
{ flex: showLabel }
)}
>
{label ? (
<span
className={SubframeUtils.twClassNames(
"text-body-default-medium-0 font-body-default-medium-0 text-text-neutral-primary",
{ "text-text-feedback-negative": error }
)}
>
{label}
</span>
) : null}
{helpText ? (
<span
className={SubframeUtils.twClassNames(
"text-body-small-regular-0 font-body-small-regular-0 text-text-neutral-tertiary mt-2",
{ "text-text-feedback-negative": error }
)}
>
{helpText}
</span>
) : null}
</div>
<div
className={SubframeUtils.twClassNames(
"flex w-full grow shrink-0 basis-0 flex-col items-start gap-1 rounded-sm relative",
{ "mt-2": showLabel }
)}
>
<div
className={SubframeUtils.twClassNames(
"flex h-9 w-full flex-none flex-col items-start rounded-sm border border-solid border-border-strong bg-surface-neutral-primary group-hover/8a1be2ee:border group-hover/8a1be2ee:border-solid group-hover/8a1be2ee:border-brand-brand-border-solid-hover group-hover/8a1be2ee:bg-surface-neutral-secondary group-focus-within/8a1be2ee:bg-surface-neutral-secondary group-focus-within/8a1be2ee:shadow-focus",
{
"h-12": size === "large",
"h-8": size === "small",
"border border-solid border-border-negative-solid group-hover/8a1be2ee:border group-hover/8a1be2ee:border-solid group-hover/8a1be2ee:border-border-negative-solid group-focus-within/8a1be2ee:border-2 group-focus-within/8a1be2ee:border-solid group-focus-within/8a1be2ee:border-border-negative-solid group-focus-within/8a1be2ee:shadow-none":
error,
"border border-solid border-border-disabled bg-surface-neutral-disabled group-hover/8a1be2ee:border group-hover/8a1be2ee:border-solid group-hover/8a1be2ee:border-border-disabled group-hover/8a1be2ee:bg-surface-neutral-disabled group-focus-within/8a1be2ee:bg-surface-neutral-disabled group-focus-within/8a1be2ee:shadow-none":
disabled,
}
)}
>
<div className="flex w-full grow shrink-0 basis-0 flex-wrap items-center gap-2 px-3">
{icon ? (
<SubframeCore.IconWrapper
className={SubframeUtils.twClassNames(
"text-body-default-regular-0 font-body-default-regular-0 text-icon-neutral-subtle",
{ "text-icon-feedback-negative": error }
)}
>
{icon}
</SubframeCore.IconWrapper>
) : null}
{chipChildren ? (
<div
className={SubframeUtils.twClassNames(
"hidden flex-wrap items-center gap-1.5",
{ flex: hasValue }
)}
>
{chipChildren}
</div>
) : null}
<div
className={SubframeUtils.twClassNames(
"flex grow shrink-0 basis-0 items-center gap-1",
{ hidden: hasValue }
)}
>
<input
className={SubframeUtils.twClassNames(
"h-6 min-w-[64px] grow shrink-0 basis-0 text-body-default-regular-0 font-body-default-regular-0 text-text-neutral-secondary outline-none placeholder:text-text-neutral-subtle",
{ hidden: hasValue, "text-text-neutral-disabled": disabled }
)}
placeholder={placeholder}
value=""
type="text"
/>
</div>
<FeatherChevronDown
className={SubframeUtils.twClassNames(
"text-body-default-medium-0 font-body-default-medium-0 text-icon-neutral-tertiary",
{
"text-icon-feedback-negative": error,
"hidden text-icon-neutral-disabled": disabled,
}
)}
/>
<Loader
className={SubframeUtils.twClassNames("hidden", {
flex: state === "loading",
})}
/>
</div>
</div>
{message ? (
<span
className={SubframeUtils.twClassNames(
"hidden text-body-extra-small-regular-0 font-body-extra-small-regular-0 text-text-feedback-negative mt-1",
{ inline: error }
)}
>
{message}
</span>
) : null}
<div
className={SubframeUtils.twClassNames(
"hidden w-full flex-col items-start gap-0.5 overflow-hidden rounded-sm border border-solid border-border-default bg-surface-neutral-primary px-1 py-1 shadow-md absolute left-0 right-0 top-full z-50 mt-1",
{ flex: open }
)}
>
{children ? (
<div
className={SubframeUtils.twClassNames(
"flex w-full flex-col items-start gap-0.5",
{
hidden:
state === "create-new" ||
state === "loading" ||
state === "no-results",
}
)}
>
{children}
</div>
) : null}
<div
className={SubframeUtils.twClassNames(
"hidden w-full items-center gap-2 px-2 py-3",
{ flex: state === "no-results" }
)}
>
<FeatherSearchX className="text-body-default-regular-0 font-body-default-regular-0 text-icon-neutral-tertiary" />
{emptyText ? (
<span className="text-body-default-regular-0 font-body-default-regular-0 text-text-neutral-tertiary">
{emptyText}
</span>
) : null}
</div>
<div
className={SubframeUtils.twClassNames(
"hidden w-full items-center gap-2 px-2 py-3",
{ flex: state === "loading" }
)}
>
<FeatherLoader className="text-body-default-regular-0 font-body-default-regular-0 text-icon-neutral-tertiary animate-spin" />
{loadingText ? (
<span className="text-body-default-regular-0 font-body-default-regular-0 text-text-neutral-tertiary">
{loadingText}
</span>
) : null}
</div>
<div
className={SubframeUtils.twClassNames(
"hidden w-full items-center gap-2 rounded-sm px-2 py-2 cursor-pointer hover:bg-surface-neutral-tertiary active:bg-surface-neutral-secondary",
{ flex: state === "create-new" }
)}
>
<FeatherPlus className="text-body-default-regular-0 font-body-default-regular-0 text-icon-feedback-information" />
{createLabel ? (
<span className="grow shrink-0 basis-0 text-body-default-medium-0 font-body-default-medium-0 text-text-feedback-information">
{createLabel}
</span>
) : null}
</div>
</div>
</div>
</div>
);
}
);
export const Combobox = Object.assign(ComboboxRoot, {
Chip,
Item,
AddItem,
});
+10
View File
@@ -0,0 +1,10 @@
"use client";
import { Combobox as ComboboxComponent } from "./Combobox";
/**
* 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 Combobox = ComboboxComponent;
+117
View File
@@ -0,0 +1,117 @@
"use client";
/*
* Documentation:
* Context Menu — https://app.subframe.com/f023064a5ca0/library?component=Context+Menu_f8a49f07-fa5b-46c8-9399-cbbf0930cc62
*/
import React from "react";
import { FeatherStar } from "@subframe/core";
import * as SubframeCore from "@subframe/core";
import * as SubframeUtils from "../../utils";
export interface ContextDividerProps
extends React.HTMLAttributes<HTMLDivElement> {
className?: string;
}
const ContextDivider = React.forwardRef<HTMLDivElement, ContextDividerProps>(
function ContextDivider(
{ className, ...otherProps }: ContextDividerProps,
ref
) {
return (
<div
className={SubframeUtils.twClassNames(
"flex w-full items-start gap-2 px-1 py-1",
className
)}
ref={ref}
{...otherProps}
>
<div className="flex h-px grow shrink-0 basis-0 flex-col items-center gap-2 bg-border-default" />
</div>
);
}
);
export interface ContextItemProps
extends React.ComponentProps<typeof SubframeCore.ContextMenu.Item> {
children?: React.ReactNode;
icon?: React.ReactNode;
rightSlot?: React.ReactNode;
className?: string;
}
const ContextItem = React.forwardRef<HTMLDivElement, ContextItemProps>(
function ContextItem(
{
children,
icon = <FeatherStar />,
rightSlot,
className,
...otherProps
}: ContextItemProps,
ref
) {
return (
<SubframeCore.ContextMenu.Item asChild={true} {...otherProps}>
<div
className={SubframeUtils.twClassNames(
"group/9358ee78 flex h-8 w-full cursor-pointer items-center gap-2 rounded-md px-2 hover:bg-surface-neutral-tertiary active:bg-surface-neutral-primary data-[highlighted]:bg-surface-neutral-tertiary",
className
)}
ref={ref}
>
<div className="flex h-4 w-4 flex-none items-center justify-center gap-2">
{icon ? (
<SubframeCore.IconWrapper className="text-body-default-regular-0 font-body-default-regular-0 text-icon-neutral-primary">
{icon}
</SubframeCore.IconWrapper>
) : null}
</div>
{children ? (
<span className="line-clamp-1 grow shrink-0 basis-0 text-body-small-medium-150 font-body-small-medium-150 text-text-neutral-primary">
{children}
</span>
) : null}
{rightSlot ? (
<div className="flex flex-col items-end justify-center gap-2">
{rightSlot}
</div>
) : null}
</div>
</SubframeCore.ContextMenu.Item>
);
}
);
export interface ContextMenuRootProps
extends React.HTMLAttributes<HTMLDivElement> {
children?: React.ReactNode;
className?: string;
}
const ContextMenuRoot = React.forwardRef<HTMLDivElement, ContextMenuRootProps>(
function ContextMenuRoot(
{ children, className, ...otherProps }: ContextMenuRootProps,
ref
) {
return children ? (
<div
className={SubframeUtils.twClassNames(
"flex min-w-[192px] flex-col items-start rounded-md border border-solid border-border-default bg-surface-neutral-secondary px-1 py-1 shadow-lg",
className
)}
ref={ref}
{...otherProps}
>
{children}
</div>
) : null;
}
);
export const ContextMenu = Object.assign(ContextMenuRoot, {
ContextDivider,
ContextItem,
});
+10
View File
@@ -0,0 +1,10 @@
"use client";
import { ContextMenu as ContextMenuComponent } from "./ContextMenu";
/**
* 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 ContextMenu = ContextMenuComponent;
@@ -0,0 +1,77 @@
"use client";
/*
* Documentation:
* Copy to clipboard button — https://app.subframe.com/f023064a5ca0/library?component=Copy+to+clipboard+button_e8c76626-6462-4f2f-b595-38d530d427e8
* Tooltip — https://app.subframe.com/f023064a5ca0/library?component=Tooltip_ccebd1e9-f6ac-4737-8376-0dfacd90c9f3
*/
import React from "react";
import { FeatherClipboard } from "@subframe/core";
import * as SubframeCore from "@subframe/core";
import * as SubframeUtils from "../../utils";
import { Tooltip } from "../Tooltip";
export interface CopyToClipboardButtonRootProps
extends Omit<
React.ComponentProps<typeof SubframeCore.CopyToClipboard.Root>,
"clipboardText"
> {
clipboardText?: React.ReactNode;
tooltipText?: React.ReactNode;
icon?: React.ReactNode;
onCopy?: () => void;
className?: string;
}
const CopyToClipboardButtonRoot = React.forwardRef<
HTMLDivElement,
CopyToClipboardButtonRootProps
>(function CopyToClipboardButtonRoot(
{
clipboardText,
tooltipText,
icon = <FeatherClipboard />,
className,
...otherProps
}: CopyToClipboardButtonRootProps,
ref
) {
return (
<SubframeCore.Tooltip.Provider>
<SubframeCore.Tooltip.Root>
<SubframeCore.Tooltip.Trigger asChild={true}>
<SubframeCore.CopyToClipboard.Root
clipboardText={clipboardText as string}
{...otherProps}
>
<div
className={SubframeUtils.twClassNames(
"group/e8c76626 flex h-6 w-6 cursor-pointer flex-col items-center justify-center gap-2 rounded-md hover:bg-surface-neutral-tertiary",
className
)}
ref={ref}
>
{icon ? (
<SubframeCore.IconWrapper className="text-body-default-regular-0 font-body-default-regular-0 text-icon-neutral-secondary group-hover/e8c76626:text-icon-neutral-primary">
{icon}
</SubframeCore.IconWrapper>
) : null}
</div>
</SubframeCore.CopyToClipboard.Root>
</SubframeCore.Tooltip.Trigger>
<SubframeCore.Tooltip.Portal>
<SubframeCore.Tooltip.Content
side="bottom"
align="center"
sideOffset={8}
asChild={true}
>
<Tooltip>{tooltipText}</Tooltip>
</SubframeCore.Tooltip.Content>
</SubframeCore.Tooltip.Portal>
</SubframeCore.Tooltip.Root>
</SubframeCore.Tooltip.Provider>
);
});
export const CopyToClipboardButton = CopyToClipboardButtonRoot;
@@ -0,0 +1,10 @@
"use client";
import { CopyToClipboardButton as CopyToClipboardButtonComponent } from "./CopyToClipboardButton";
/**
* 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 CopyToClipboardButton = CopyToClipboardButtonComponent;
+679
View File
@@ -0,0 +1,679 @@
// @subframe/sync-disable
// @ts-nocheck
"use client";
/*
* Documentation:
* Date Picker — https://app.subframe.com/f023064a5ca0/library?component=Date+Picker_e0461776-caeb-4bb3-a9a1-7df3bcfe9afe
* Dropdown Menu select — https://app.subframe.com/f023064a5ca0/library?component=Dropdown+Menu+select_99951515-459b-4286-919e-a89e7549b43b
* Icon Button — https://app.subframe.com/f023064a5ca0/library?component=Icon+Button_af9405b1-8c54-4e01-9786-5aad308224f6
*/
import React from "react";
import { FeatherCalendar } from "@subframe/core";
import { FeatherChevronDown } from "@subframe/core";
import { FeatherChevronLeft } from "@subframe/core";
import { FeatherChevronRight } from "@subframe/core";
import * as SubframeCore from "@subframe/core";
import * as SubframeUtils from "../../utils";
import { DropdownMenuSelect } from "../DropdownMenuSelect";
import { IconButton } from "../IconButton";
export interface WeekdayProps extends React.HTMLAttributes<HTMLDivElement> {
children?: React.ReactNode;
className?: string;
}
const Weekday = React.forwardRef<HTMLDivElement, WeekdayProps>(function Weekday(
{ children, className, ...otherProps }: WeekdayProps,
ref
) {
return (
<div
className={SubframeUtils.twClassNames(
"flex h-8 w-9 items-center justify-center",
className
)}
ref={ref}
{...otherProps}
>
{children ? (
<span className="text-body-extra-small-medium-0 font-body-extra-small-medium-0 text-text-neutral-tertiary">
{children}
</span>
) : null}
</div>
);
});
export interface SelectProps extends React.HTMLAttributes<HTMLDivElement> {
children?: React.ReactNode;
grow?: boolean;
className?: string;
}
const Select = React.forwardRef<HTMLDivElement, SelectProps>(function Select(
{ children, grow = false, className, ...otherProps }: SelectProps,
ref
) {
return (
<div
className={SubframeUtils.twClassNames(
"group/f2c7e363 flex cursor-pointer items-center justify-between rounded-sm border border-solid border-border-default bg-surface-neutral-secondary px-2 py-1.5 hover:bg-surface-neutral-tertiary",
{ "w-full": grow },
className
)}
ref={ref}
{...otherProps}
>
<div className="flex items-center gap-2 pr-2">
{children ? (
<span className="text-body-small-medium-0 font-body-small-medium-0 text-text-neutral-primary">
{children}
</span>
) : null}
</div>
<FeatherChevronDown className="text-body-small-medium-0 font-body-small-medium-0 text-icon-neutral-tertiary" />
</div>
);
});
export interface CalendarPanelProps
extends React.HTMLAttributes<HTMLDivElement> {
month?: React.ReactNode;
year?: React.ReactNode;
className?: string;
}
const CalendarPanel = React.forwardRef<HTMLDivElement, CalendarPanelProps>(
function CalendarPanel(
{ month, year, className, ...otherProps }: CalendarPanelProps,
ref
) {
return (
<div
className={SubframeUtils.twClassNames(
"flex flex-col items-start gap-2",
className
)}
ref={ref}
{...otherProps}
>
<div className="flex w-80 flex-col items-start overflow-hidden rounded-md border border-solid border-border-default shadow-md">
<div className="flex w-full flex-col items-start bg-surface-neutral-tertiary">
<div className="flex w-full items-center justify-center px-3 py-3">
<div className="flex grow shrink-0 basis-0 items-center justify-center gap-1">
<IconButton
variant="ghost"
size="extra-small"
square={true}
icon={<FeatherChevronLeft />}
/>
<DatePicker.MonthSelect />
<IconButton
variant="ghost"
size="extra-small"
square={true}
icon={<FeatherChevronRight />}
/>
<IconButton
variant="ghost"
size="extra-small"
square={true}
icon={<FeatherChevronLeft />}
/>
<DatePicker.YearSelect />
<IconButton
variant="ghost"
size="extra-small"
square={true}
icon={<FeatherChevronRight />}
/>
</div>
</div>
<div className="flex w-full items-center justify-between px-3">
<DatePicker.Weekday>Mo</DatePicker.Weekday>
<DatePicker.Weekday>Di</DatePicker.Weekday>
<DatePicker.Weekday>Mi</DatePicker.Weekday>
<DatePicker.Weekday>Do</DatePicker.Weekday>
<DatePicker.Weekday>Fr</DatePicker.Weekday>
<DatePicker.Weekday>Sa</DatePicker.Weekday>
<DatePicker.Weekday>So</DatePicker.Weekday>
</div>
</div>
<div className="flex h-px w-full flex-none flex-col items-center gap-2 bg-[#e5e5e5]" />
<div className="flex w-full flex-col items-center gap-1 bg-surface-neutral-secondary px-3 py-3">
<div className="flex w-full items-center justify-between">
<DatePicker.Day outside={true}>27</DatePicker.Day>
<DatePicker.Day outside={true}>28</DatePicker.Day>
<DatePicker.Day outside={true}>29</DatePicker.Day>
<DatePicker.Day outside={true}>30</DatePicker.Day>
<DatePicker.Day outside={true}>31</DatePicker.Day>
<DatePicker.Day>1</DatePicker.Day>
<DatePicker.Day>2</DatePicker.Day>
</div>
<div className="flex w-full items-center justify-between">
<DatePicker.Day>3</DatePicker.Day>
<DatePicker.Day>4</DatePicker.Day>
<DatePicker.Day>5</DatePicker.Day>
<DatePicker.Day>6</DatePicker.Day>
<DatePicker.Day>7</DatePicker.Day>
<DatePicker.Day>8</DatePicker.Day>
<DatePicker.Day>9</DatePicker.Day>
</div>
<div className="flex w-full items-center justify-between">
<DatePicker.Day>10</DatePicker.Day>
<DatePicker.Day>11</DatePicker.Day>
<DatePicker.Day>12</DatePicker.Day>
<DatePicker.Day>13</DatePicker.Day>
<DatePicker.Day selected={true}>14</DatePicker.Day>
<DatePicker.Day>15</DatePicker.Day>
<DatePicker.Day>16</DatePicker.Day>
</div>
<div className="flex w-full items-center justify-between">
<DatePicker.Day>17</DatePicker.Day>
<DatePicker.Day>18</DatePicker.Day>
<DatePicker.Day today={true}>19</DatePicker.Day>
<DatePicker.Day>20</DatePicker.Day>
<DatePicker.Day>21</DatePicker.Day>
<DatePicker.Day>22</DatePicker.Day>
<DatePicker.Day>23</DatePicker.Day>
</div>
<div className="flex w-full items-center justify-between">
<DatePicker.Day>24</DatePicker.Day>
<DatePicker.Day>25</DatePicker.Day>
<DatePicker.Day>26</DatePicker.Day>
<DatePicker.Day>27</DatePicker.Day>
<DatePicker.Day>28</DatePicker.Day>
<DatePicker.Day outside={true}>1</DatePicker.Day>
<DatePicker.Day outside={true}>2</DatePicker.Day>
</div>
</div>
</div>
<div className="hidden w-80 flex-col items-start overflow-hidden rounded-md border border-solid border-border-default shadow-md">
<div className="flex w-full flex-col items-start bg-surface-neutral-tertiary">
<div className="flex w-full items-center justify-center px-3 py-3">
<div className="flex grow shrink-0 basis-0 items-center justify-center gap-1">
<IconButton
variant="ghost"
size="extra-small"
square={true}
icon={<FeatherChevronLeft />}
/>
<DatePicker.MonthSelect />
<IconButton
variant="ghost"
size="extra-small"
square={true}
icon={<FeatherChevronRight />}
/>
<IconButton
variant="ghost"
size="extra-small"
square={true}
icon={<FeatherChevronLeft />}
/>
<DatePicker.YearSelect />
<IconButton
variant="ghost"
size="extra-small"
square={true}
icon={<FeatherChevronRight />}
/>
</div>
</div>
<div className="flex w-full items-center justify-between px-3">
<DatePicker.Weekday>Mo</DatePicker.Weekday>
<DatePicker.Weekday>Di</DatePicker.Weekday>
<DatePicker.Weekday>Mi</DatePicker.Weekday>
<DatePicker.Weekday>Do</DatePicker.Weekday>
<DatePicker.Weekday>Fr</DatePicker.Weekday>
<DatePicker.Weekday>Sa</DatePicker.Weekday>
<DatePicker.Weekday>So</DatePicker.Weekday>
</div>
</div>
<div className="flex h-px w-full flex-none flex-col items-center gap-2 bg-[#e5e5e5]" />
<div className="flex w-full flex-col items-center gap-1 bg-surface-neutral-secondary px-3 py-3">
<div className="flex w-full items-center justify-between">
<DatePicker.Day outside={true}>27</DatePicker.Day>
<DatePicker.Day outside={true}>28</DatePicker.Day>
<DatePicker.Day outside={true}>29</DatePicker.Day>
<DatePicker.Day outside={true}>30</DatePicker.Day>
<DatePicker.Day outside={true}>31</DatePicker.Day>
<DatePicker.Day>1</DatePicker.Day>
<DatePicker.Day>2</DatePicker.Day>
</div>
<div className="flex w-full items-center justify-between">
<DatePicker.Day>3</DatePicker.Day>
<DatePicker.Day>4</DatePicker.Day>
<DatePicker.Day>5</DatePicker.Day>
<DatePicker.Day>6</DatePicker.Day>
<DatePicker.Day>7</DatePicker.Day>
<DatePicker.Day>8</DatePicker.Day>
<DatePicker.Day>9</DatePicker.Day>
</div>
<div className="flex w-full items-center justify-between">
<DatePicker.Day>10</DatePicker.Day>
<DatePicker.Day>11</DatePicker.Day>
<DatePicker.Day>12</DatePicker.Day>
<DatePicker.Day>13</DatePicker.Day>
<DatePicker.Day selected={true}>14</DatePicker.Day>
<DatePicker.Day>15</DatePicker.Day>
<DatePicker.Day>16</DatePicker.Day>
</div>
<div className="flex w-full items-center justify-between">
<DatePicker.Day>17</DatePicker.Day>
<DatePicker.Day>18</DatePicker.Day>
<DatePicker.Day today={true}>19</DatePicker.Day>
<DatePicker.Day>20</DatePicker.Day>
<DatePicker.Day>21</DatePicker.Day>
<DatePicker.Day>22</DatePicker.Day>
<DatePicker.Day>23</DatePicker.Day>
</div>
<div className="flex w-full items-center justify-between">
<DatePicker.Day>24</DatePicker.Day>
<DatePicker.Day>25</DatePicker.Day>
<DatePicker.Day>26</DatePicker.Day>
<DatePicker.Day>27</DatePicker.Day>
<DatePicker.Day>28</DatePicker.Day>
<DatePicker.Day outside={true}>1</DatePicker.Day>
<DatePicker.Day outside={true}>2</DatePicker.Day>
</div>
</div>
</div>
</div>
);
}
);
export interface MonthSelectProps extends React.HTMLAttributes<HTMLDivElement> {
className?: string;
}
const MonthSelect = React.forwardRef<HTMLDivElement, MonthSelectProps>(
function MonthSelect({ className, ...otherProps }: MonthSelectProps, ref) {
return (
<SubframeCore.DropdownMenu.Root>
<SubframeCore.DropdownMenu.Trigger asChild={true}>
<div
className={SubframeUtils.twClassNames(
"flex flex-col items-start gap-2",
className
)}
ref={ref}
{...otherProps}
>
<DatePicker.Select>September</DatePicker.Select>
</div>
</SubframeCore.DropdownMenu.Trigger>
<SubframeCore.DropdownMenu.Portal>
<SubframeCore.DropdownMenu.Content
side="bottom"
align="start"
sideOffset={4}
asChild={true}
>
<DropdownMenuSelect className="min-w-0">
<div className="flex w-full flex-col items-start gap-0.5">
<DatePicker.YearCell>Januar</DatePicker.YearCell>
<DatePicker.YearCell selected={true}>
Februar
</DatePicker.YearCell>
<DatePicker.YearCell>März</DatePicker.YearCell>
<DatePicker.YearCell>April</DatePicker.YearCell>
<DatePicker.YearCell>Mai</DatePicker.YearCell>
<DatePicker.YearCell>Juni</DatePicker.YearCell>
<DatePicker.YearCell>Juli</DatePicker.YearCell>
<DatePicker.YearCell>August</DatePicker.YearCell>
<DatePicker.YearCell>September</DatePicker.YearCell>
<DatePicker.YearCell>Oktober</DatePicker.YearCell>
<DatePicker.YearCell>November</DatePicker.YearCell>
<DatePicker.YearCell>Dezember</DatePicker.YearCell>
</div>
</DropdownMenuSelect>
</SubframeCore.DropdownMenu.Content>
</SubframeCore.DropdownMenu.Portal>
</SubframeCore.DropdownMenu.Root>
);
}
);
export interface YearSelectProps
extends React.ComponentProps<typeof DatePicker.Select> {
className?: string;
}
const YearSelect = React.forwardRef<
React.ElementRef<typeof DatePicker.Select>,
YearSelectProps
>(function YearSelect({ className, ...otherProps }: YearSelectProps, ref) {
return (
<SubframeCore.DropdownMenu.Root>
<SubframeCore.DropdownMenu.Trigger asChild={true}>
<DatePicker.Select className={className} ref={ref} {...otherProps}>
2026
</DatePicker.Select>
</SubframeCore.DropdownMenu.Trigger>
<SubframeCore.DropdownMenu.Portal>
<SubframeCore.DropdownMenu.Content
side="bottom"
align="start"
sideOffset={4}
asChild={true}
>
<DropdownMenuSelect className="min-w-0">
<div className="flex w-full flex-col items-start gap-0.5">
<DatePicker.YearCell>2021</DatePicker.YearCell>
<DatePicker.YearCell>2022</DatePicker.YearCell>
<DatePicker.YearCell>2023</DatePicker.YearCell>
<DatePicker.YearCell>2024</DatePicker.YearCell>
<DatePicker.YearCell>2025</DatePicker.YearCell>
<DatePicker.YearCell selected={true}>2026</DatePicker.YearCell>
<DatePicker.YearCell>2027</DatePicker.YearCell>
<DatePicker.YearCell>2028</DatePicker.YearCell>
<DatePicker.YearCell>2029</DatePicker.YearCell>
<DatePicker.YearCell>2030</DatePicker.YearCell>
<DatePicker.YearCell>2031</DatePicker.YearCell>
</div>
</DropdownMenuSelect>
</SubframeCore.DropdownMenu.Content>
</SubframeCore.DropdownMenu.Portal>
</SubframeCore.DropdownMenu.Root>
);
});
export interface DayProps extends React.HTMLAttributes<HTMLDivElement> {
children?: React.ReactNode;
selected?: boolean;
today?: boolean;
outside?: boolean;
className?: string;
}
const Day = React.forwardRef<HTMLDivElement, DayProps>(function Day(
{
children,
selected = false,
today = false,
outside = false,
className,
...otherProps
}: DayProps,
ref
) {
return (
<div
className={SubframeUtils.twClassNames(
"group/3262f2d3 flex h-full max-h-[36px] min-h-[36px] w-full min-w-[36px] max-w-[36px] cursor-pointer items-center justify-center rounded-round hover:bg-surface-neutral-tertiary",
{
"border border-solid border-border-strong": today,
"bg-brand-brand-surface-solid-default": selected,
},
className
)}
ref={ref}
{...otherProps}
>
{children ? (
<span
className={SubframeUtils.twClassNames(
"text-body-small-regular-0 font-body-small-regular-0 text-text-neutral-primary",
{
"text-text-neutral-subtle": outside,
"text-text-neutral-on-solid": selected,
}
)}
>
{children}
</span>
) : null}
</div>
);
});
export interface YearCellProps extends React.HTMLAttributes<HTMLDivElement> {
children?: React.ReactNode;
selected?: boolean;
className?: string;
}
const YearCell = React.forwardRef<HTMLDivElement, YearCellProps>(
function YearCell(
{ children, selected = false, className, ...otherProps }: YearCellProps,
ref
) {
return (
<div
className={SubframeUtils.twClassNames(
"group/5db54e28 flex h-7 w-full cursor-pointer items-center rounded-sm px-2 group/yearcell hover:bg-surface-feedback-subtle-information-hover",
{ "bg-brand-brand-surface-solid-default": selected },
className
)}
ref={ref}
{...otherProps}
>
{children ? (
<span
className={SubframeUtils.twClassNames(
"text-body-small-medium-0 font-body-small-medium-0 text-text-neutral-primary",
{
"text-text-neutral-on-solid group-hover/5db54e28:text-text-neutral-primary":
selected,
}
)}
>
{children}
</span>
) : null}
</div>
);
}
);
export interface DatePickerRootProps
extends Omit<React.HTMLAttributes<HTMLDivElement>, "placeholder"> {
disabled?: boolean;
error?: boolean;
hasValue?: boolean;
size?: "small" | "medium" | "large";
fillContainer?: boolean;
borderless?: boolean;
noPadding?: boolean;
showLabel?: boolean;
label?: React.ReactNode;
helpText?: React.ReactNode;
message?: React.ReactNode;
placeholder?: React.ReactNode;
value?: React.ReactNode;
month?: React.ReactNode;
year?: React.ReactNode;
boolean?: boolean;
className?: string;
}
const DatePickerRoot = React.forwardRef<HTMLDivElement, DatePickerRootProps>(
function DatePickerRoot(
{
disabled = false,
error = false,
hasValue = false,
size = "medium",
fillContainer = false,
borderless = false,
noPadding = false,
showLabel = false,
label,
helpText,
message,
placeholder,
value,
month,
year,
boolean = false,
className,
...otherProps
}: DatePickerRootProps,
ref
) {
return (
<SubframeCore.DropdownMenu.Root>
<SubframeCore.DropdownMenu.Trigger asChild={true}>
<div
className={SubframeUtils.twClassNames(
"group/e0461776 flex min-w-[144px] cursor-pointer flex-col items-start gap-3",
{
"gap-0": showLabel,
"w-full min-w-[240px]": fillContainer,
"cursor-not-allowed": disabled,
},
className
)}
ref={ref}
{...otherProps}
>
<div
className={SubframeUtils.twClassNames(
"hidden flex-col items-start gap-2",
{ flex: showLabel }
)}
>
{label ? (
<span
className={SubframeUtils.twClassNames(
"text-body-default-medium-0 font-body-default-medium-0 text-text-neutral-primary",
{
"text-text-feedback-negative": error,
"text-text-neutral-disabled": disabled,
}
)}
>
{label}
</span>
) : null}
{helpText ? (
<span
className={SubframeUtils.twClassNames(
"text-body-small-regular-0 font-body-small-regular-0 text-text-neutral-tertiary",
{
"text-text-feedback-negative": error,
"text-text-neutral-disabled": disabled,
}
)}
>
{helpText}
</span>
) : null}
</div>
<div
className={SubframeUtils.twClassNames(
"flex w-full flex-col items-start gap-3",
{ "gap-1": showLabel }
)}
>
<div
className={SubframeUtils.twClassNames(
"flex w-full flex-col items-start gap-1 relative",
{ "px-0 pt-1.5 pb-0": showLabel }
)}
>
<div
className={SubframeUtils.twClassNames(
"flex h-9 w-full flex-none items-center gap-2 rounded-sm border border-solid border-border-strong bg-surface-neutral-primary px-3 group-hover/e0461776:bg-surface-neutral-secondary group-focus-within/e0461776:bg-surface-neutral-secondary group-focus-within/e0461776:shadow-focus",
{
"border border-solid border-border-default": showLabel,
"h-auto px-0 py-0": noPadding,
"border-none": borderless,
"h-12": size === "large",
"h-8": size === "small",
"border border-solid border-border-negative-solid group-focus-within/e0461776:border-2 group-focus-within/e0461776:border-solid group-focus-within/e0461776:border-border-negative-solid group-focus-within/e0461776:shadow-none":
error,
"border border-solid border-border-disabled bg-surface-neutral-disabled cursor-not-allowed group-hover/e0461776:bg-surface-neutral-disabled group-focus-within/e0461776:bg-surface-neutral-disabled group-focus-within/e0461776:shadow-none":
disabled,
}
)}
>
{value ? (
<span
className={SubframeUtils.twClassNames(
"hidden grow shrink-0 basis-0 text-body-default-regular-0 font-body-default-regular-0 text-text-neutral-secondary",
{
"text-body-small-regular-0 font-body-small-regular-0":
size === "small",
inline: hasValue,
"text-text-neutral-disabled": disabled,
}
)}
>
{value}
</span>
) : null}
{placeholder ? (
<span
className={SubframeUtils.twClassNames(
"grow shrink-0 basis-0 text-body-default-regular-0 font-body-default-regular-0 text-text-neutral-subtle",
{
"text-body-small-regular-0 font-body-small-regular-0":
size === "small",
hidden: hasValue,
"text-text-neutral-disabled": disabled,
}
)}
>
{placeholder}
</span>
) : null}
<FeatherCalendar
className={SubframeUtils.twClassNames(
"text-body-default-regular-0 font-body-default-regular-0 text-icon-neutral-tertiary",
{
"text-body-small-regular-0 font-body-small-regular-0":
size === "small",
"text-icon-feedback-negative": error,
"text-icon-neutral-disabled": disabled,
}
)}
/>
</div>
</div>
{message ? (
<span
className={SubframeUtils.twClassNames(
"hidden text-body-extra-small-regular-0 font-body-extra-small-regular-0 text-text-neutral-tertiary",
{
inline: showLabel,
"text-text-feedback-negative": error,
"text-text-neutral-disabled": disabled,
}
)}
>
{message}
</span>
) : null}
</div>
</div>
</SubframeCore.DropdownMenu.Trigger>
<SubframeCore.DropdownMenu.Portal>
<SubframeCore.DropdownMenu.Content
side="bottom"
align="start"
sideOffset={4}
asChild={true}
>
<DropdownMenuSelect className="h-auto w-auto flex-none">
<CalendarPanel month="Februar" year="2025" />
</DropdownMenuSelect>
</SubframeCore.DropdownMenu.Content>
</SubframeCore.DropdownMenu.Portal>
</SubframeCore.DropdownMenu.Root>
);
}
);
export const DatePicker = Object.assign(DatePickerRoot, {
Weekday,
Select,
CalendarPanel,
MonthSelect,
YearSelect,
Day,
YearCell,
});
+10
View File
@@ -0,0 +1,10 @@
"use client";
import { DatePicker as DatePickerComponent } from "./DatePicker";
/**
* 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 DatePicker = DatePickerComponent;
+85
View File
@@ -0,0 +1,85 @@
"use client";
/*
* Documentation:
* Dialog — https://app.subframe.com/f023064a5ca0/library?component=Dialog_ca59db17-43fb-4247-8094-3c55162e902d
*/
import React from "react";
import * as SubframeCore from "@subframe/core";
import * as SubframeUtils from "../../utils";
export interface ContentProps
extends React.ComponentProps<typeof SubframeCore.Dialog.Content> {
children?: React.ReactNode;
size?: "xs" | "small" | "medium" | "large" | "media";
padding?: "default" | "spacious";
hideCloseIcon?: boolean;
className?: string;
}
const Content = React.forwardRef<HTMLDivElement, ContentProps>(function Content(
{
children,
size = "small",
padding = "default",
hideCloseIcon = false,
className,
...otherProps
}: ContentProps,
ref
) {
return children ? (
<SubframeCore.Dialog.Content asChild={true} {...otherProps}>
<div
className={SubframeUtils.twClassNames(
"group/04ea6d47 flex w-full flex-col items-start gap-6 rounded-md border border-solid border-border-default bg-surface-neutral-secondary px-4 py-4 shadow-lg overflow-auto max-w-[560px] mobile:overflow-auto mobile:max-h-[90vh] mobile:max-w-[calc(100vw-32px)]",
{
"hide-close-icon": hideCloseIcon,
"px-8 py-8": padding === "spacious",
"h-192 w-320 max-w-320": size === "media",
"max-w-[1200px]": size === "large",
"max-w-[720px]": size === "medium",
"max-w-[420px]": size === "xs",
},
className
)}
ref={ref}
>
{children}
</div>
</SubframeCore.Dialog.Content>
) : null;
});
export interface DialogRootProps
extends React.ComponentProps<typeof SubframeCore.Dialog.Root> {
children?: React.ReactNode;
open?: boolean;
onOpenChange?: (open: boolean) => void;
className?: string;
}
const DialogRoot = React.forwardRef<HTMLDivElement, DialogRootProps>(
function DialogRoot(
{ children, className, ...otherProps }: DialogRootProps,
ref
) {
return children ? (
<SubframeCore.Dialog.Root asChild={true} {...otherProps}>
<div
className={SubframeUtils.twClassNames(
"flex h-full w-full flex-col items-center justify-center gap-2 bg-surface-neutral-overlay",
className
)}
ref={ref}
>
{children}
</div>
</SubframeCore.Dialog.Root>
) : null;
}
);
export const Dialog = Object.assign(DialogRoot, {
Content,
});
+10
View File
@@ -0,0 +1,10 @@
"use client";
import { Dialog as DialogComponent } from "./Dialog";
/**
* 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 Dialog = DialogComponent;
@@ -0,0 +1,74 @@
"use client";
/*
* Documentation:
* Dialog Fullscreen — https://app.subframe.com/f023064a5ca0/library?component=Dialog+Fullscreen_3f094173-71de-4378-a09a-05c482f7a137
* Icon Button — https://app.subframe.com/f023064a5ca0/library?component=Icon+Button_af9405b1-8c54-4e01-9786-5aad308224f6
*/
import React from "react";
import { FeatherX } from "@subframe/core";
import * as SubframeCore from "@subframe/core";
import * as SubframeUtils from "../../utils";
import { IconButton } from "../IconButton";
export interface DialogFullscreenRootProps
extends React.ComponentProps<typeof SubframeCore.FullScreenDialog.Root> {
children?: React.ReactNode;
padding?: "default" | "spacious";
hideCloseIcon?: boolean;
open?: boolean;
onOpenChange?: (open: boolean) => void;
className?: string;
}
const DialogFullscreenRoot = React.forwardRef<
HTMLDivElement,
DialogFullscreenRootProps
>(function DialogFullscreenRoot(
{
children,
padding = "default",
hideCloseIcon = false,
className,
...otherProps
}: DialogFullscreenRootProps,
ref
) {
return (
<SubframeCore.FullScreenDialog.Root asChild={true} {...otherProps}>
<div
className={SubframeUtils.twClassNames(
"group/3f094173 flex h-full w-full flex-col items-center justify-center bg-surface-neutral-overlay px-6 py-6 mobile:px-4 mobile:py-4",
className
)}
ref={ref}
>
<div
className={SubframeUtils.twClassNames(
"flex w-full grow shrink-0 basis-0 flex-col items-start overflow-hidden rounded-lg border border-solid border-border-default bg-surface-neutral-secondary shadow-lg group/dialogfs max-w-[2512px] relative",
{ "hide-close-icon": hideCloseIcon }
)}
>
{children ? (
<div
className={SubframeUtils.twClassNames(
"flex w-full grow shrink-0 basis-0 flex-col items-start gap-4 px-4 py-4 overflow-auto",
{ "px-8 py-8": padding === "spacious" }
)}
>
{children}
</div>
) : null}
<IconButton
className="group-[.hide-close-icon]/dialogfs:hidden absolute right-4 top-4"
variant="ghost"
size="small"
icon={<FeatherX />}
/>
</div>
</div>
</SubframeCore.FullScreenDialog.Root>
);
});
export const DialogFullscreen = DialogFullscreenRoot;
+10
View File
@@ -0,0 +1,10 @@
"use client";
import { DialogFullscreen as DialogFullscreenComponent } from "./DialogFullscreen";
/**
* 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 DialogFullscreen = DialogFullscreenComponent;
+67
View File
@@ -0,0 +1,67 @@
"use client";
/*
* Documentation:
* Drawer Right — https://app.subframe.com/f023064a5ca0/library?component=Drawer+Right_1e71b2cb-8d72-4e67-b368-8805179e9444
*/
import React from "react";
import * as SubframeCore from "@subframe/core";
import * as SubframeUtils from "../../utils";
export interface ContentProps
extends React.ComponentProps<typeof SubframeCore.Drawer.Content> {
children?: React.ReactNode;
className?: string;
}
const Content = React.forwardRef<HTMLDivElement, ContentProps>(function Content(
{ children, className, ...otherProps }: ContentProps,
ref
) {
return children ? (
<SubframeCore.Drawer.Content asChild={true} {...otherProps}>
<div
className={SubframeUtils.twClassNames(
"flex h-full min-w-[320px] flex-col items-start gap-2 border-l border-solid border-[#e5e5e5] bg-[#ffffff]",
className
)}
ref={ref}
>
{children}
</div>
</SubframeCore.Drawer.Content>
) : null;
});
export interface DrawerRightRootProps
extends React.ComponentProps<typeof SubframeCore.Drawer.Root> {
children?: React.ReactNode;
open?: boolean;
onOpenChange?: (open: boolean) => void;
className?: string;
}
const DrawerRightRoot = React.forwardRef<HTMLDivElement, DrawerRightRootProps>(
function DrawerRightRoot(
{ children, className, ...otherProps }: DrawerRightRootProps,
ref
) {
return children ? (
<SubframeCore.Drawer.Root asChild={true} {...otherProps}>
<div
className={SubframeUtils.twClassNames(
"flex h-full w-full flex-col items-end justify-center gap-2 bg-[#00000066]",
className
)}
ref={ref}
>
{children}
</div>
</SubframeCore.Drawer.Root>
) : null;
}
);
export const DrawerRight = Object.assign(DrawerRightRoot, {
Content,
});
+10
View File
@@ -0,0 +1,10 @@
"use client";
import { DrawerRight as DrawerRightComponent } from "./DrawerRight";
/**
* 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 DrawerRight = DrawerRightComponent;
@@ -0,0 +1,379 @@
// @subframe/sync-disable
"use client";
/*
* Documentation:
* Accordion — https://app.subframe.com/f023064a5ca0/library?component=Accordion_d2e81e20-863a-4027-826a-991d8910efd9
* Avatar — https://app.subframe.com/f023064a5ca0/library?component=Avatar_bec25ae6-5010-4485-b46b-cf79e3943ab2
* Checkbox — https://app.subframe.com/f023064a5ca0/library?component=Checkbox_3816e3b5-c48c-499b-b45e-0777c6972523
* Dropdown Menu multi select — https://app.subframe.com/f023064a5ca0/library?component=Dropdown+Menu+multi+select_8c9fd450-3912-4c8a-abae-4f24e3022a64
*/
import React from "react";
import { FeatherLayers } from "@subframe/core";
import { FeatherSearch } from "@subframe/core";
import * as SubframeCore from "@subframe/core";
import * as SubframeUtils from "../../utils";
import { Accordion } from "../Accordion";
import { Avatar } from "../Avatar";
import { Checkbox } from "../Checkbox";
export interface DropdownDividerProps
extends React.HTMLAttributes<HTMLDivElement> {
className?: string;
}
const DropdownDivider = React.forwardRef<HTMLDivElement, DropdownDividerProps>(
function DropdownDivider(
{ className, ...otherProps }: DropdownDividerProps,
ref
) {
return (
<div
className={SubframeUtils.twClassNames(
"flex w-full items-start gap-2 px-1 py-1",
className
)}
ref={ref}
{...otherProps}
>
<div className="flex h-px grow shrink-0 basis-0 flex-col items-center gap-2 bg-border-default" />
</div>
);
}
);
export interface DropdownItemProps
extends React.ComponentProps<typeof SubframeCore.DropdownMenu.Item> {
children?: React.ReactNode;
icon?: React.ReactNode;
iconRight?: React.ReactNode;
image?: string;
selected?: boolean;
showCheckbox?: boolean;
className?: string;
}
const DropdownItem = React.forwardRef<HTMLDivElement, DropdownItemProps>(
function DropdownItem(
{
children,
icon = null,
iconRight = null,
image,
selected = false,
showCheckbox = false,
className,
...otherProps
}: DropdownItemProps,
ref
) {
return (
<SubframeCore.DropdownMenu.Item asChild={true} {...otherProps}>
<div
className={SubframeUtils.twClassNames(
"group/744235d7 flex w-full cursor-pointer items-center gap-2 rounded-md px-2 py-2.5 group/dropdown-item hover:bg-surface-neutral-tertiary active:bg-surface-neutral-secondary",
{
"bg-surface-ui-subtle-blue-default hover:bg-surface-ui-subtle-blue-hover active:bg-surface-ui-subtle-blue-active":
selected,
},
className
)}
ref={ref}
>
<div
className={SubframeUtils.twClassNames("hidden items-start", {
flex: showCheckbox,
})}
>
<Checkbox
checked={selected}
className="h-auto w-auto flex-none self-stretch"
label="label"
description="Description"
helpText=""
hideLabel={true}
/>
</div>
{image ? (
<img
className="h-6 w-6 flex-none rounded-round object-cover"
src={image}
/>
) : null}
{icon ? (
<SubframeCore.IconWrapper
className={SubframeUtils.twClassNames(
"text-body-small-regular-150 font-body-small-regular-150 text-icon-neutral-tertiary",
{ "text-icon-neutral-primary": selected }
)}
>
{icon}
</SubframeCore.IconWrapper>
) : null}
{children ? (
<span
className={SubframeUtils.twClassNames(
"line-clamp-1 grow shrink-0 basis-0 text-body-small-regular-0 font-body-small-regular-0 text-text-neutral-tertiary",
{ "text-text-neutral-primary": selected }
)}
>
{children}
</span>
) : null}
{iconRight ? (
<SubframeCore.IconWrapper
className={SubframeUtils.twClassNames(
"text-body-small-regular-150 font-body-small-regular-150 text-icon-neutral-tertiary",
{ "text-icon-neutral-primary": selected }
)}
>
{iconRight}
</SubframeCore.IconWrapper>
) : null}
</div>
</SubframeCore.DropdownMenu.Item>
);
}
);
export interface DropdownUserItemProps
extends Omit<React.HTMLAttributes<HTMLDivElement>, "title"> {
title?: React.ReactNode;
subtitle?: React.ReactNode;
image?: string;
selected?: boolean;
showCheckbox?: boolean;
className?: string;
}
const DropdownUserItem = React.forwardRef<
HTMLDivElement,
DropdownUserItemProps
>(function DropdownUserItem(
{
title,
subtitle,
image,
selected = false,
showCheckbox = false,
className,
...otherProps
}: DropdownUserItemProps,
ref
) {
return (
<div
className={SubframeUtils.twClassNames(
"group/ad6eaaaf flex w-full cursor-pointer items-center gap-2 rounded-md px-2 py-2 group/user-item hover:bg-surface-neutral-tertiary active:bg-surface-neutral-secondary",
{
"bg-surface-ui-subtle-blue-default hover:bg-surface-ui-subtle-blue-hover active:bg-surface-ui-subtle-blue-active":
selected,
},
className
)}
ref={ref}
{...otherProps}
>
<div
className={SubframeUtils.twClassNames("hidden items-start", {
flex: showCheckbox,
})}
>
<Checkbox
checked={selected}
label="label"
description="Description"
helpText=""
hideLabel={true}
/>
</div>
<Avatar size="small" image={image}>
OR
</Avatar>
<div className="flex grow shrink-0 basis-0 flex-col items-start">
{title ? (
<span className="line-clamp-1 w-full text-body-small-medium-150 font-body-small-medium-150 text-text-neutral-primary">
{title}
</span>
) : null}
{subtitle ? (
<span className="line-clamp-1 w-full text-body-extra-small-regular-150 font-body-extra-small-regular-150 text-text-neutral-tertiary">
{subtitle}
</span>
) : null}
</div>
</div>
);
});
export interface DropdownCustomItemProps
extends React.HTMLAttributes<HTMLDivElement> {
children?: React.ReactNode;
selected?: boolean;
showCheckbox?: boolean;
size?: "medium" | "small" | "large";
className?: string;
}
const DropdownCustomItem = React.forwardRef<
HTMLDivElement,
DropdownCustomItemProps
>(function DropdownCustomItem(
{
children,
selected = false,
showCheckbox = false,
size = "medium",
className,
...otherProps
}: DropdownCustomItemProps,
ref
) {
return (
<div
className={SubframeUtils.twClassNames(
"group/e2891f3f flex w-full cursor-pointer items-center gap-2 rounded-md px-2 py-2.5 hover:bg-surface-neutral-tertiary active:bg-surface-neutral-secondary",
{
"px-2.5 py-3": size === "large",
"px-1 py-1": size === "small",
"bg-surface-ui-subtle-blue-default hover:bg-surface-ui-subtle-blue-hover active:bg-surface-ui-subtle-blue-active":
selected,
},
className
)}
ref={ref}
{...otherProps}
>
<Checkbox
className={SubframeUtils.twClassNames("hidden", { flex: showCheckbox })}
label="label"
description="Description"
helpText=""
hideLabel={true}
/>
{children ? (
<div className="flex grow shrink-0 basis-0 flex-col items-start">
{children}
</div>
) : null}
</div>
);
});
export interface DropdownNestedItemProps
extends React.ComponentProps<typeof Accordion> {
children?: React.ReactNode;
label?: React.ReactNode;
icon?: React.ReactNode;
className?: string;
}
const DropdownNestedItem = React.forwardRef<
React.ElementRef<typeof Accordion>,
DropdownNestedItemProps
>(function DropdownNestedItem(
{
children,
label,
icon = <FeatherLayers />,
className,
...otherProps
}: DropdownNestedItemProps,
ref
) {
return (
<Accordion
className={SubframeUtils.twClassNames(
"group/e3a3cd0a cursor-pointer group/nested-item",
className
)}
variant="ghost"
trigger={
<div className="flex h-8 w-full flex-none items-center gap-2 rounded-md px-3 group-hover/e3a3cd0a:bg-surface-neutral-tertiary">
{icon ? (
<SubframeCore.IconWrapper className="text-body-small-regular-150 font-body-small-regular-150 text-icon-neutral-primary">
{icon}
</SubframeCore.IconWrapper>
) : null}
{label ? (
<span className="line-clamp-1 grow shrink-0 basis-0 text-body-small-medium-150 font-body-small-medium-150 text-text-neutral-primary">
{label}
</span>
) : null}
<Accordion.Chevron />
</div>
}
ref={ref}
{...otherProps}
>
{children ? (
<div className="flex w-full flex-col items-start gap-1">{children}</div>
) : null}
</Accordion>
);
});
export interface DropdownMenuMultiSelectRootProps
extends React.HTMLAttributes<HTMLDivElement> {
children?: React.ReactNode;
showSearch?: boolean;
className?: string;
}
const DropdownMenuMultiSelectRoot = React.forwardRef<
HTMLDivElement,
DropdownMenuMultiSelectRootProps
>(function DropdownMenuMultiSelectRoot(
{
children,
showSearch = false,
className,
...otherProps
}: DropdownMenuMultiSelectRootProps,
ref
) {
return (
<div
className={SubframeUtils.twClassNames(
"group/8c9fd450 flex min-w-[192px] flex-col items-start rounded-md border border-solid border-border-default bg-surface-neutral-secondary px-1 py-1 shadow-lg",
className
)}
ref={ref}
{...otherProps}
>
<div
className={SubframeUtils.twClassNames(
"hidden w-full flex-col items-start gap-1 pb-1",
{ flex: showSearch }
)}
>
<div className="flex w-full items-center gap-2 rounded-sm bg-surface-neutral-tertiary px-2 py-1.5">
<FeatherSearch className="text-body-small-regular-150 font-body-small-regular-150 text-icon-neutral-tertiary" />
<input
className="min-w-[0px] grow shrink-0 basis-0 self-stretch text-body-small-regular-150 font-body-small-regular-150 text-text-neutral-secondary outline-none placeholder:text-text-neutral-subtle"
placeholder="Suchen…"
value=""
type="search"
/>
</div>
<div className="flex h-px w-full flex-none flex-col items-center gap-2 bg-border-default" />
</div>
{children ? (
<div className="flex w-full flex-col items-start gap-0.5">
{children}
</div>
) : null}
</div>
);
});
export const DropdownMenuMultiSelect = Object.assign(
DropdownMenuMultiSelectRoot,
{
DropdownDivider,
DropdownItem,
DropdownUserItem,
DropdownCustomItem,
DropdownNestedItem,
}
);
@@ -0,0 +1,10 @@
"use client";
import { DropdownMenuMultiSelect as DropdownMenuMultiSelectComponent } from "./DropdownMenuMultiSelect";
/**
* 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 DropdownMenuMultiSelect = DropdownMenuMultiSelectComponent;
@@ -0,0 +1,373 @@
"use client";
/*
* Documentation:
* Accordion — https://app.subframe.com/f023064a5ca0/library?component=Accordion_d2e81e20-863a-4027-826a-991d8910efd9
* Avatar — https://app.subframe.com/f023064a5ca0/library?component=Avatar_bec25ae6-5010-4485-b46b-cf79e3943ab2
* Checkbox — https://app.subframe.com/f023064a5ca0/library?component=Checkbox_3816e3b5-c48c-499b-b45e-0777c6972523
* Dropdown Menu select — https://app.subframe.com/f023064a5ca0/library?component=Dropdown+Menu+select_99951515-459b-4286-919e-a89e7549b43b
*/
import React from "react";
import { FeatherLayers } from "@subframe/core";
import { FeatherSearch } from "@subframe/core";
import * as SubframeCore from "@subframe/core";
import * as SubframeUtils from "../../utils";
import { Accordion } from "../Accordion";
import { Avatar } from "../Avatar";
import { Checkbox } from "../Checkbox";
export interface DropdownDividerProps
extends React.HTMLAttributes<HTMLDivElement> {
className?: string;
}
const DropdownDivider = React.forwardRef<HTMLDivElement, DropdownDividerProps>(
function DropdownDivider(
{ className, ...otherProps }: DropdownDividerProps,
ref
) {
return (
<div
className={SubframeUtils.twClassNames(
"flex w-full items-start gap-2 px-1 py-1",
className
)}
ref={ref}
{...otherProps}
>
<div className="flex h-px grow shrink-0 basis-0 flex-col items-center gap-2 bg-border-default" />
</div>
);
}
);
export interface DropdownItemProps
extends React.ComponentProps<typeof SubframeCore.DropdownMenu.Item> {
children?: React.ReactNode;
icon?: React.ReactNode;
iconRight?: React.ReactNode;
image?: string;
selected?: boolean;
showCheckbox?: boolean;
className?: string;
}
const DropdownItem = React.forwardRef<HTMLDivElement, DropdownItemProps>(
function DropdownItem(
{
children,
icon = null,
iconRight = null,
image,
selected = false,
showCheckbox = false,
className,
...otherProps
}: DropdownItemProps,
ref
) {
return (
<SubframeCore.DropdownMenu.Item asChild={true} {...otherProps}>
<div
className={SubframeUtils.twClassNames(
"group/adcae8d6 flex w-full cursor-pointer items-center gap-2 rounded-md px-2 py-2.5 group/dropdown-item hover:bg-surface-neutral-tertiary active:bg-surface-neutral-secondary",
{
"bg-surface-ui-subtle-blue-default hover:bg-surface-ui-subtle-blue-hover active:bg-surface-ui-subtle-blue-active":
selected,
},
className
)}
ref={ref}
>
<div
className={SubframeUtils.twClassNames("hidden items-start", {
flex: showCheckbox,
})}
>
<Checkbox
className="h-auto w-auto flex-none self-stretch"
label="label"
description="Description"
helpText=""
hideLabel={true}
/>
</div>
{image ? (
<img
className="h-6 w-6 flex-none rounded-round object-cover"
src={image}
/>
) : null}
{icon ? (
<SubframeCore.IconWrapper
className={SubframeUtils.twClassNames(
"text-body-small-regular-150 font-body-small-regular-150 text-icon-neutral-tertiary",
{ "text-icon-neutral-primary": selected }
)}
>
{icon}
</SubframeCore.IconWrapper>
) : null}
{children ? (
<span
className={SubframeUtils.twClassNames(
"line-clamp-1 grow shrink-0 basis-0 text-body-small-regular-0 font-body-small-regular-0 text-text-neutral-tertiary",
{ "text-text-neutral-primary": selected }
)}
>
{children}
</span>
) : null}
{iconRight ? (
<SubframeCore.IconWrapper
className={SubframeUtils.twClassNames(
"text-body-small-regular-150 font-body-small-regular-150 text-icon-neutral-tertiary",
{ "text-icon-neutral-primary": selected }
)}
>
{iconRight}
</SubframeCore.IconWrapper>
) : null}
</div>
</SubframeCore.DropdownMenu.Item>
);
}
);
export interface DropdownUserItemProps
extends Omit<React.HTMLAttributes<HTMLDivElement>, "title"> {
title?: React.ReactNode;
subtitle?: React.ReactNode;
image?: string;
selected?: boolean;
showCheckbox?: boolean;
className?: string;
}
const DropdownUserItem = React.forwardRef<
HTMLDivElement,
DropdownUserItemProps
>(function DropdownUserItem(
{
title,
subtitle,
image,
selected = false,
showCheckbox = false,
className,
...otherProps
}: DropdownUserItemProps,
ref
) {
return (
<div
className={SubframeUtils.twClassNames(
"group/0d3c57ad flex w-full cursor-pointer items-center gap-2 rounded-md px-2 py-2 group/user-item hover:bg-surface-neutral-tertiary active:bg-surface-neutral-secondary",
{
"bg-surface-ui-subtle-blue-default hover:bg-surface-ui-subtle-blue-hover active:bg-surface-ui-subtle-blue-active":
selected,
},
className
)}
ref={ref}
{...otherProps}
>
<div
className={SubframeUtils.twClassNames("hidden items-start", {
flex: showCheckbox,
})}
>
<Checkbox
label="label"
description="Description"
helpText=""
hideLabel={true}
/>
</div>
<Avatar size="small" image={image}>
OR
</Avatar>
<div className="flex grow shrink-0 basis-0 flex-col items-start">
{title ? (
<span className="line-clamp-1 w-full text-body-small-medium-150 font-body-small-medium-150 text-text-neutral-primary">
{title}
</span>
) : null}
{subtitle ? (
<span className="line-clamp-1 w-full text-body-extra-small-regular-150 font-body-extra-small-regular-150 text-text-neutral-tertiary">
{subtitle}
</span>
) : null}
</div>
</div>
);
});
export interface DropdownCustomItemProps
extends React.HTMLAttributes<HTMLDivElement> {
children?: React.ReactNode;
selected?: boolean;
showCheckbox?: boolean;
size?: "medium" | "small" | "large";
className?: string;
}
const DropdownCustomItem = React.forwardRef<
HTMLDivElement,
DropdownCustomItemProps
>(function DropdownCustomItem(
{
children,
selected = false,
showCheckbox = false,
size = "medium",
className,
...otherProps
}: DropdownCustomItemProps,
ref
) {
return (
<div
className={SubframeUtils.twClassNames(
"group/4abe03f9 flex w-full cursor-pointer items-center gap-2 rounded-md px-2 py-2.5 hover:bg-surface-neutral-tertiary active:bg-surface-neutral-secondary",
{
"px-2.5 py-3": size === "large",
"px-1 py-1": size === "small",
"bg-surface-ui-subtle-blue-default hover:bg-surface-ui-subtle-blue-hover active:bg-surface-ui-subtle-blue-active":
selected,
},
className
)}
ref={ref}
{...otherProps}
>
<Checkbox
className={SubframeUtils.twClassNames("hidden", { flex: showCheckbox })}
label="label"
description="Description"
helpText=""
hideLabel={true}
/>
{children ? (
<div className="flex grow shrink-0 basis-0 flex-col items-start">
{children}
</div>
) : null}
</div>
);
});
export interface DropdownNestedItemProps
extends React.ComponentProps<typeof Accordion> {
children?: React.ReactNode;
label?: React.ReactNode;
icon?: React.ReactNode;
className?: string;
}
const DropdownNestedItem = React.forwardRef<
React.ElementRef<typeof Accordion>,
DropdownNestedItemProps
>(function DropdownNestedItem(
{
children,
label,
icon = <FeatherLayers />,
className,
...otherProps
}: DropdownNestedItemProps,
ref
) {
return (
<Accordion
className={SubframeUtils.twClassNames(
"group/ca3b20a3 cursor-pointer group/nested-item",
className
)}
variant="ghost"
trigger={
<div className="flex h-8 w-full flex-none items-center gap-2 rounded-md px-3 group-hover/ca3b20a3:bg-surface-neutral-tertiary">
{icon ? (
<SubframeCore.IconWrapper className="text-body-small-regular-150 font-body-small-regular-150 text-icon-neutral-primary">
{icon}
</SubframeCore.IconWrapper>
) : null}
{label ? (
<span className="line-clamp-1 grow shrink-0 basis-0 text-body-small-medium-150 font-body-small-medium-150 text-text-neutral-primary">
{label}
</span>
) : null}
<Accordion.Chevron />
</div>
}
ref={ref}
{...otherProps}
>
{children ? (
<div className="flex w-full flex-col items-start gap-1">{children}</div>
) : null}
</Accordion>
);
});
export interface DropdownMenuSelectRootProps
extends React.HTMLAttributes<HTMLDivElement> {
children?: React.ReactNode;
showSearch?: boolean;
className?: string;
}
const DropdownMenuSelectRoot = React.forwardRef<
HTMLDivElement,
DropdownMenuSelectRootProps
>(function DropdownMenuSelectRoot(
{
children,
showSearch = false,
className,
...otherProps
}: DropdownMenuSelectRootProps,
ref
) {
return (
<div
className={SubframeUtils.twClassNames(
"group/99951515 flex min-w-[192px] flex-col items-start rounded-md border border-solid border-border-default bg-surface-neutral-secondary px-1 py-1 shadow-lg",
className
)}
ref={ref}
{...otherProps}
>
<div
className={SubframeUtils.twClassNames(
"hidden w-full flex-col items-start gap-1 pb-1",
{ flex: showSearch }
)}
>
<div className="flex w-full items-center gap-2 rounded-sm bg-surface-neutral-tertiary px-2 py-1.5">
<FeatherSearch className="text-body-small-regular-150 font-body-small-regular-150 text-icon-neutral-tertiary" />
<input
className="min-w-[0px] grow shrink-0 basis-0 self-stretch text-body-small-regular-150 font-body-small-regular-150 text-text-neutral-secondary outline-none placeholder:text-text-neutral-subtle"
placeholder="Suchen…"
value=""
type="search"
/>
</div>
<div className="flex h-px w-full flex-none flex-col items-center gap-2 bg-border-default" />
</div>
{children ? (
<div className="flex w-full flex-col items-start gap-0.5">
{children}
</div>
) : null}
</div>
);
});
export const DropdownMenuSelect = Object.assign(DropdownMenuSelectRoot, {
DropdownDivider,
DropdownItem,
DropdownUserItem,
DropdownCustomItem,
DropdownNestedItem,
});
@@ -0,0 +1,10 @@
"use client";
import { DropdownMenuSelect as DropdownMenuSelectComponent } from "./DropdownMenuSelect";
/**
* 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 DropdownMenuSelect = DropdownMenuSelectComponent;
+109
View File
@@ -0,0 +1,109 @@
"use client";
/*
* Documentation:
* Button — https://app.subframe.com/f023064a5ca0/library?component=Button_3b777358-b86b-40af-9327-891efc6826fe
* Empty State — https://app.subframe.com/f023064a5ca0/library?component=Empty+State_9fcf03a9-ada9-4a3d-80bc-87ff6ce78023
*/
import React from "react";
import * as SubframeUtils from "../../utils";
import { Button } from "../Button";
export interface EmptyStateRootProps
extends Omit<React.HTMLAttributes<HTMLDivElement>, "title"> {
variant?: "default" | "no-results" | "error";
outlined?: boolean;
fillContainer?: boolean;
title?: React.ReactNode;
body?: React.ReactNode;
className?: string;
}
const EmptyStateRoot = React.forwardRef<HTMLDivElement, EmptyStateRootProps>(
function EmptyStateRoot(
{
variant = "default",
outlined = false,
fillContainer = false,
title,
body,
className,
...otherProps
}: EmptyStateRootProps,
ref
) {
return (
<div
className={SubframeUtils.twClassNames(
"group/9fcf03a9 flex max-w-[384px] items-center gap-4 px-4 py-8",
{
"max-w-none": fillContainer,
"rounded-md border border-solid border-border-default bg-surface-neutral-primary":
outlined,
},
className
)}
ref={ref}
{...otherProps}
>
<div className="flex flex-col items-center gap-6">
<div className="flex flex-col items-center gap-7">
<img
className={SubframeUtils.twClassNames(
"h-12 w-12 flex-none object-cover",
{ hidden: variant === "error" || variant === "no-results" }
)}
src="data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNDgiIGhlaWdodD0iNDgiIHZpZXdCb3g9IjAgMCA0OCA0OCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiBjbGFzcz0iZmxleC1ub25lIiBkYXRhLW5vZGUtaWQ9IjM3YmE4ZTQ2Ij48cGF0aCBkPSJNMzcuNSAyMVYzNy42NjY3QzM3LjUgMzguMDIwMyAzNy4zNTk1IDM4LjM1OTQgMzcuMTA5NSAzOC42MDk1QzM2Ljg1OTQgMzguODU5NSAzNi41MjAzIDM5IDM2LjE2NjcgMzlINy41QzcuMTAyMTggMzkgNi43MjA2NCAzOC44NDIgNi40MzkzNCAzOC41NjA3QzYuMTU4MDQgMzguMjc5NCA2IDM3Ljg5NzggNiAzNy41VjE2LjVDNiAxNi4xMDIyIDYuMTU4MDQgMTUuNzIwNiA2LjQzOTM0IDE1LjQzOTNDNi43MjA2NCAxNS4xNTggNy4xMDIxOCAxNSA3LjUgMTVIMTZDMTYuMzI0NiAxNSAxNi42NDA0IDE1LjEwNTMgMTYuOSAxNS4zTDIyLjEgMTkuMkMyMi4zNTk2IDE5LjM5NDcgMjIuNjc1NCAxOS41IDIzIDE5LjVIMzZDMzYuMzk3OCAxOS41IDM2Ljc3OTQgMTkuNjU4IDM3LjA2MDcgMTkuOTM5M0MzNy4zNDIgMjAuMjIwNiAzNy41IDIwLjYwMjIgMzcuNSAyMVoiIHN0cm9rZT0iIzg1ODU4OSIgc3Ryb2tlLXdpZHRoPSIxLjUiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCIgZGF0YS1ub2RlLWlkPSI4MzBkNDBlZi05N2E3LTRjMjYtODQwZi0yNDQzMTEwNjYwMjgiPjwvcGF0aD48cGF0aCBkPSJNMTIgMTVWMTAuNUMxMiAxMC4xMDIyIDEyLjE1OCA5LjcyMDY0IDEyLjQzOTMgOS40MzkzNEMxMi43MjA2IDkuMTU4MDQgMTMuMTAyMiA5IDEzLjUgOUgyMkMyMi4zMjQ2IDkgMjIuNjQwNCA5LjEwNTI3IDIyLjkgOS4zTDI4LjEgMTMuMkMyOC4zNTk2IDEzLjM5NDcgMjguNjc1NCAxMy41IDI5IDEzLjVINDJDNDIuMzk3OCAxMy41IDQyLjc3OTQgMTMuNjU4IDQzLjA2MDcgMTMuOTM5M0M0My4zNDIgMTQuMjIwNiA0My41IDE0LjYwMjIgNDMuNSAxNVYzMS42NjY3QzQzLjUgMzEuODQxOCA0My40NjU1IDMyLjAxNTEgNDMuMzk4NSAzMi4xNzY5QzQzLjMzMTUgMzIuMzM4NyA0My4yMzMzIDMyLjQ4NTcgNDMuMTA5NSAzMi42MDk1QzQyLjk4NTcgMzIuNzMzMyA0Mi44Mzg3IDMyLjgzMTUgNDIuNjc2OSAzMi44OTg1QzQyLjUxNTEgMzIuOTY1NSA0Mi4zNDE4IDMzIDQyLjE2NjcgMzNIMzcuNSIgc3Ryb2tlPSIjODU4NTg5IiBzdHJva2Utd2lkdGg9IjEuNSIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2UtbGluZWpvaW49InJvdW5kIiBkYXRhLW5vZGUtaWQ9IjJiZDUxMmE0LWI3YzQtNDg5MS05N2NmLTliNjkyZTc1MTNkMSI+PC9wYXRoPjwvc3ZnPg=="
/>
<img
className={SubframeUtils.twClassNames(
"hidden h-12 w-12 flex-none object-cover",
{ block: variant === "no-results" }
)}
src="data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNDgiIGhlaWdodD0iNDgiIHZpZXdCb3g9IjAgMCA0OCA0OCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJNMjEuNzUgMzcuNUMzMC40NDg1IDM3LjUgMzcuNSAzMC40NDg1IDM3LjUgMjEuNzVDMzcuNSAxMy4wNTE1IDMwLjQ0ODUgNiAyMS43NSA2QzEzLjA1MTUgNiA2IDEzLjA1MTUgNiAyMS43NUM2IDMwLjQ0ODUgMTMuMDUxNSAzNy41IDIxLjc1IDM3LjVaIiBzdHJva2U9IiM4NTg1ODkiIHN0cm9rZS13aWR0aD0iMiIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2UtbGluZWpvaW49InJvdW5kIi8+PHBhdGggZD0iTTMyLjg4NjMgMzIuODg2N0w0MS45OTg5IDQxLjk5OTMiIHN0cm9rZT0iIzg1ODU4OSIgc3Ryb2tlLXdpZHRoPSIyIiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiLz48L3N2Zz4="
/>
<img
className={SubframeUtils.twClassNames(
"hidden h-12 w-12 flex-none object-cover",
{ block: variant === "error" }
)}
src="data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNDgiIGhlaWdodD0iNDgiIHZpZXdCb3g9IjAgMCA0OCA0OCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJNMjQgMTkuNVYyNyIgc3Ryb2tlPSIjQzUyMDIwIiBzdHJva2Utd2lkdGg9IjIiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCIvPjxwYXRoIGQ9Ik0yMS40MDM2IDcuNDk3MTNMNC45MDgwNCAzNS45OTU3QzQuNjQ0MDkgMzYuNDUxNyA0LjUwNDg5IDM2Ljk2OTIgNC41MDQ0NiAzNy40OTYxQzQuNTA0MDIgMzguMDIzIDQuNjQyMzYgMzguNTQwNyA0LjkwNTU1IDM4Ljk5NzFDNS4xNjg3NSAzOS40NTM2IDUuNTQ3NTEgMzkuODMyNyA2LjAwMzc0IDQwLjA5NjJDNi40NTk5NyA0MC4zNTk4IDYuOTc3NTcgNDAuNDk4NiA3LjUwNDQ3IDQwLjQ5ODZINDAuNDk1NkM0MS4wMjI0IDQwLjQ5ODYgNDEuNTQgNDAuMzU5OCA0MS45OTYzIDQwLjA5NjJDNDIuNDUyNSAzOS44MzI3IDQyLjgzMTMgMzkuNDUzNiA0My4wOTQ1IDM4Ljk5NzFDNDMuMzU3NyAzOC41NDA3IDQzLjQ5NiAzOC4wMjMgNDMuNDk1NiAzNy40OTYxQzQzLjQ5NTEgMzYuOTY5MiA0My4zNTU5IDM2LjQ1MTcgNDMuMDkyIDM1Ljk5NTdMMjYuNTk2NCA3LjQ5NzEzQzI2LjMzMjkgNy4wNDE4NSAyNS45NTQzIDYuNjYzODcgMjUuNDk4NiA2LjQwMTFDMjUuMDQyOSA2LjEzODMyIDI0LjUyNjEgNiAyNCA2QzIzLjQ3NCA2IDIyLjk1NzIgNi4xMzgzMiAyMi41MDE0IDYuNDAxMUMyMi4wNDU3IDYuNjYzODcgMjEuNjY3MSA3LjA0MTg1IDIxLjQwMzYgNy40OTcxM1Y3LjQ5NzEzWiIgc3Ryb2tlPSIjQzUyMDIwIiBzdHJva2Utd2lkdGg9IjIiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCIvPjxwYXRoIGQ9Ik0yNCAzNS42MjVDMjUuMDM1NSAzNS42MjUgMjUuODc1IDM0Ljc4NTUgMjUuODc1IDMzLjc1QzI1Ljg3NSAzMi43MTQ1IDI1LjAzNTUgMzEuODc1IDI0IDMxLjg3NUMyMi45NjQ1IDMxLjg3NSAyMi4xMjUgMzIuNzE0NSAyMi4xMjUgMzMuNzVDMjIuMTI1IDM0Ljc4NTUgMjIuOTY0NSAzNS42MjUgMjQgMzUuNjI1WiIgZmlsbD0iI0M1MjAyMCIvPjwvc3ZnPg=="
/>
<div className="flex w-full flex-col items-center gap-4 px-4">
{title ? (
<span className="w-full text-body-large-0 font-body-large-0 text-text-neutral-primary text-center">
{title}
</span>
) : null}
{body ? (
<span className="break-words text-body-default-regular-150 font-body-default-regular-150 text-text-neutral-secondary text-center">
{body}
</span>
) : null}
</div>
<Button
className={SubframeUtils.twClassNames("h-9 w-36 flex-none", {
"w-28": variant === "error" || variant === "no-results",
})}
variant={
variant === "error"
? "tertiary"
: variant === "no-results"
? "tertiary"
: undefined
}
>
{variant === "error"
? "Try again"
: variant === "no-results"
? "Clear filters"
: "Create project"}
</Button>
</div>
</div>
</div>
);
}
);
export const EmptyState = EmptyStateRoot;
+10
View File
@@ -0,0 +1,10 @@
"use client";
import { EmptyState as EmptyStateComponent } from "./EmptyState";
/**
* 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 EmptyState = EmptyStateComponent;
+81
View File
@@ -0,0 +1,81 @@
"use client";
/*
* Documentation:
* Button — https://app.subframe.com/f023064a5ca0/library?component=Button_3b777358-b86b-40af-9327-891efc6826fe
* Error State — https://app.subframe.com/f023064a5ca0/library?component=Error+State_07f75db5-d9ee-406e-8c83-cb9e3bf687ee
*/
import React from "react";
import * as SubframeUtils from "../../utils";
import { Button } from "../Button";
export interface ErrorStateRootProps
extends Omit<React.HTMLAttributes<HTMLDivElement>, "title"> {
variant?: "inline" | "full-width";
hideCancel?: boolean;
title?: React.ReactNode;
description?: React.ReactNode;
retryLabel?: React.ReactNode;
cancelLabel?: React.ReactNode;
className?: string;
}
const ErrorStateRoot = React.forwardRef<HTMLDivElement, ErrorStateRootProps>(
function ErrorStateRoot(
{
variant = "inline",
hideCancel = false,
title,
description,
retryLabel,
cancelLabel,
className,
...otherProps
}: ErrorStateRootProps,
ref
) {
return (
<div
className={SubframeUtils.twClassNames(
"group/07f75db5 flex min-w-[192px] max-w-[576px] flex-col items-start gap-2 rounded-md border-2 border-solid border-border-negative-solid bg-surface-feedback-subtle-negative px-4 py-4 shadow-sm group/error-state",
{ "w-full min-w-0 max-w-none": variant === "full-width" },
className
)}
ref={ref}
{...otherProps}
>
<div className="flex w-full flex-col items-start gap-6">
<div className="flex w-full items-center gap-2">
<img
className="h-1 w-1 flex-none object-cover"
src="data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNCIgaGVpZ2h0PSI0IiB2aWV3Qm94PSIwIDAgNCA0IiBmaWxsPSJub25lIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGNsYXNzPSJoLTEgdy0xIGZsZXgtbm9uZSIgZGF0YS1ub2RlLWlkPSJjNWJhMzRjMCI+PGNpcmNsZSBjeD0iMiIgY3k9IjIiIHI9IjIiIGZpbGw9IiNDNTIwMjAiPjwvY2lyY2xlPjwvc3ZnPg=="
/>
{title ? (
<span className="grow shrink-0 basis-0 whitespace-pre-wrap text-body-default-medium-0 font-body-default-medium-0 text-text-feedback-negative">
{title}
</span>
) : null}
</div>
<div className="flex flex-col items-start gap-6 pl-3">
{description ? (
<span className="text-body-default-regular-0 font-body-default-regular-0 text-text-neutral-secondary">
{description}
</span>
) : null}
<div className="flex items-center gap-2">
<Button variant="tertiary">{retryLabel}</Button>
<Button
className={SubframeUtils.twClassNames({ hidden: hideCancel })}
variant="ghost"
>
{cancelLabel}
</Button>
</div>
</div>
</div>
</div>
);
}
);
export const ErrorState = ErrorStateRoot;
+10
View File
@@ -0,0 +1,10 @@
"use client";
import { ErrorState as ErrorStateComponent } from "./ErrorState";
/**
* 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 ErrorState = ErrorStateComponent;
+200
View File
@@ -0,0 +1,200 @@
"use client";
/*
* Documentation:
* Button — https://app.subframe.com/f023064a5ca0/library?component=Button_3b777358-b86b-40af-9327-891efc6826fe
* File Upload — https://app.subframe.com/f023064a5ca0/library?component=File+Upload_28a3336a-2bdd-4d1c-8dc1-75c9d6eef452
* Progress — https://app.subframe.com/f023064a5ca0/library?component=Progress_60964db0-a1bf-428b-b9d5-f34cdf58ea77
*/
import React from "react";
import { FeatherFile } from "@subframe/core";
import { FeatherUpload } from "@subframe/core";
import { FeatherX } from "@subframe/core";
import * as SubframeUtils from "../../utils";
import { Button } from "../Button";
import { Progress } from "../Progress";
export interface FileUploadRootProps
extends React.HTMLAttributes<HTMLDivElement> {
fullwith?: boolean;
state?: "default" | "hover" | "uploading" | "error" | "uploaded";
filename?: React.ReactNode;
fileSize?: React.ReactNode;
uploadProgress?: number;
progressText?: React.ReactNode;
errorMessage?: React.ReactNode;
browseLabel?: React.ReactNode;
cancelLabel?: React.ReactNode;
className?: string;
}
const FileUploadRoot = React.forwardRef<HTMLDivElement, FileUploadRootProps>(
function FileUploadRoot(
{
fullwith = false,
state = "default",
filename,
fileSize,
uploadProgress = 60,
progressText,
errorMessage,
browseLabel,
cancelLabel,
className,
...otherProps
}: FileUploadRootProps,
ref
) {
return (
<div
className={SubframeUtils.twClassNames(
"group/28a3336a flex flex-col items-start gap-2",
{ "w-full": fullwith },
className
)}
ref={ref}
{...otherProps}
>
<div
className={SubframeUtils.twClassNames(
"flex h-52 w-80 flex-none flex-col items-center justify-center gap-5 rounded-lg border border-dashed border-border-strong bg-surface-neutral-primary px-6 py-8",
{
hidden: state === "uploaded" || state === "uploading",
"h-auto border border-dashed border-border-negative-solid":
state === "error",
"border-2 border-dashed border-border-information-solid bg-surface-feedback-subtle-information":
state === "hover",
"h-auto w-full": fullwith,
}
)}
>
<div
className={SubframeUtils.twClassNames(
"flex flex-col items-center justify-center gap-8",
{ "gap-6": state === "error" }
)}
>
<div
className={SubframeUtils.twClassNames(
"flex flex-col items-center justify-center gap-8",
{ "gap-6": state === "hover" }
)}
>
<FeatherUpload className="text-subtitle font-subtitle text-icon-neutral-secondary" />
<span
className={SubframeUtils.twClassNames(
"hidden text-body-small-medium-0 font-body-small-medium-0 text-text-feedback-link-default",
{
"text-text-neutral-primary": state === "error",
"text-text-neutral-primary inline-flex": state === "hover",
}
)}
>
Drop your invoice file here
</span>
</div>
<span
className={SubframeUtils.twClassNames(
"text-body-default-regular-0 font-body-default-regular-0 text-text-neutral-secondary",
{ hidden: state === "hover" }
)}
>
Drop your invoice file here or
</span>
</div>
<div
className={SubframeUtils.twClassNames(
"flex flex-col items-center justify-center gap-5",
{ "gap-6": state === "error", hidden: state === "hover" }
)}
>
<div
className={SubframeUtils.twClassNames(
"flex flex-col items-center justify-center gap-3",
{ hidden: state === "hover" }
)}
>
<Button variant="tertiary">Click here to browse</Button>
</div>
{errorMessage ? (
<span
className={SubframeUtils.twClassNames(
"hidden text-body-small-regular-0 font-body-small-regular-0 text-text-feedback-negative",
{ "inline-flex": state === "error" }
)}
>
{errorMessage}
</span>
) : null}
</div>
</div>
<div
className={SubframeUtils.twClassNames(
"hidden w-80 flex-col items-start gap-4 rounded-lg border border-dashed border-border-strong bg-surface-neutral-primary px-6 py-8",
{ flex: state === "uploading", "w-full flex-none": fullwith }
)}
>
{filename ? (
<span className="text-body-default-medium-0 font-body-default-medium-0 text-text-neutral-primary">
{filename}
</span>
) : null}
<Progress
hideLabel={state === "uploading" ? true : undefined}
label="Uploading file"
statusText="30%"
/>
<div
className={SubframeUtils.twClassNames(
"hidden flex-col items-start gap-6",
{ flex: state === "uploading" }
)}
>
{progressText ? (
<span className="text-body-small-regular-0 font-body-small-regular-0 text-text-neutral-tertiary">
{progressText}
</span>
) : null}
<div
className={SubframeUtils.twClassNames(
"hidden items-center gap-2",
{ flex: state === "uploading" }
)}
>
<Button
variant={state === "uploading" ? "destructive" : undefined}
>
{state === "uploading" ? "Cancel" : "Button"}
</Button>
</div>
</div>
</div>
<div
className={SubframeUtils.twClassNames(
"hidden w-72 items-center gap-3 rounded-md border border-solid border-border-default bg-surface-neutral-primary px-3 py-4",
{ flex: state === "uploaded", "w-full flex-none": fullwith }
)}
>
<FeatherFile className="text-body-large font-body-large text-icon-neutral-secondary" />
<div className="flex grow shrink-0 basis-0 flex-col items-start gap-2 self-stretch">
{filename ? (
<span className="text-body-small-medium-0 font-body-small-medium-0 text-text-neutral-primary">
{filename}
</span>
) : null}
{fileSize ? (
<span className="text-body-small-regular-0 font-body-small-regular-0 text-text-neutral-tertiary">
{fileSize}
</span>
) : null}
</div>
<div className="flex items-start">
<FeatherX className="text-body-default-regular-0 font-body-default-regular-0 text-icon-neutral-subtle" />
</div>
</div>
</div>
);
}
);
export const FileUpload = FileUploadRoot;
+10
View File
@@ -0,0 +1,10 @@
"use client";
import { FileUpload as FileUploadComponent } from "./FileUpload";
/**
* 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 FileUpload = FileUploadComponent;
+212
View File
@@ -0,0 +1,212 @@
// @subframe/sync-disable
"use client";
/*
* Documentation:
* Filter Bar — https://app.subframe.com/f023064a5ca0/library?component=Filter+Bar_f2cf6974-3297-4da8-8613-cd00dc1c228e
*/
import React from "react";
import { FeatherBriefcase } from "@subframe/core";
import { FeatherChevronDown } from "@subframe/core";
import { FeatherRotateCcw } from "@subframe/core";
import { FeatherSearch } from "@subframe/core";
import * as SubframeCore from "@subframe/core";
import * as SubframeUtils from "../../utils";
export interface StatusFilterButtonProps
extends React.HTMLAttributes<HTMLDivElement> {
icon?: React.ReactNode;
label?: React.ReactNode;
showCount?: boolean;
count?: React.ReactNode;
dropdown?: React.ReactNode;
className?: string;
}
const StatusFilterButton = React.forwardRef<
HTMLDivElement,
StatusFilterButtonProps
>(function StatusFilterButton(
{
icon = <FeatherBriefcase />,
label,
showCount = false,
count,
dropdown,
className,
...otherProps
}: StatusFilterButtonProps,
ref
) {
return (
<SubframeCore.DropdownMenu.Root>
<SubframeCore.DropdownMenu.Trigger asChild={true}>
<div
className={SubframeUtils.twClassNames(
"group/4ad576dd flex h-6 cursor-pointer items-center gap-0.5 rounded-md border border-solid border-border-default pl-1 pr-0.5 py-1 hover:bg-surface-neutral-tertiary focus-within:shadow-focus",
{
"border border-solid border-brand-brand-secondary-border-subtle-default bg-surface-feedback-subtle-information-hover pl-px hover:border hover:border-solid hover:border-brand-brand-secondary-border-subtle-hover hover:bg-surface-feedback-subtle-information-hover active:border active:border-solid active:border-brand-brand-secondary-border-subtle-active active:bg-surface-feedback-subtle-information-active focus-within:border focus-within:border-solid focus-within:border-brand-brand-secondary-border-subtle-hover":
showCount,
},
className
)}
ref={ref}
{...otherProps}
>
<div className="flex items-center gap-1">
<div
className={SubframeUtils.twClassNames(
"hidden h-5 grow shrink-0 basis-0 items-center gap-1 rounded-sm bg-surface-neutral-secondary px-1.5 py-0.5",
{ flex: showCount }
)}
>
<div className="flex h-1 w-1 flex-none flex-col items-start gap-2 rounded-round bg-icon-neutral-primary" />
{count ? (
<span className="text-body-small-medium-0 font-body-small-medium-0 text-text-neutral-primary">
{count}
</span>
) : null}
</div>
{icon ? (
<SubframeCore.IconWrapper
className={SubframeUtils.twClassNames(
"text-body-default-regular-150 font-body-default-regular-150 text-icon-neutral-tertiary",
{ "text-icon-neutral-primary": showCount }
)}
>
{icon}
</SubframeCore.IconWrapper>
) : null}
{label ? (
<span
className={SubframeUtils.twClassNames(
"text-body-small-regular-0 font-body-small-regular-0 text-text-neutral-tertiary",
{ "text-text-neutral-primary": showCount }
)}
>
{label}
</span>
) : null}
</div>
<div className="flex items-center pt-px">
<FeatherChevronDown
className={SubframeUtils.twClassNames(
"text-body-small-regular-150 font-body-small-regular-150 text-icon-neutral-tertiary",
{ "text-icon-neutral-primary": showCount }
)}
/>
</div>
</div>
</SubframeCore.DropdownMenu.Trigger>
<SubframeCore.DropdownMenu.Portal>
<SubframeCore.DropdownMenu.Content
side="bottom"
align="start"
sideOffset={4}
asChild={true}
>
{dropdown ? (
<div className="items-start contents">{dropdown}</div>
) : null}
</SubframeCore.DropdownMenu.Content>
</SubframeCore.DropdownMenu.Portal>
</SubframeCore.DropdownMenu.Root>
);
});
export interface FilterBarRootProps
extends React.HTMLAttributes<HTMLDivElement> {
hideSearch?: boolean;
showActiveFilters?: boolean;
searchValue?: string;
onSearchChange?: (value: string) => void;
onClearFilters?: () => void;
children?: React.ReactNode;
activeFilters?: React.ReactNode;
className?: string;
}
const FilterBarRoot = React.forwardRef<HTMLDivElement, FilterBarRootProps>(
function FilterBarRoot(
{
hideSearch = false,
showActiveFilters = false,
searchValue,
onSearchChange = () => {},
onClearFilters = () => {},
children,
activeFilters,
className,
...otherProps
}: FilterBarRootProps,
ref
) {
return (
<div
className={SubframeUtils.twClassNames(
"group/f2cf6974 flex w-full flex-col items-start gap-2 rounded-md bg-surface-neutral-secondary px-3 py-2",
className
)}
ref={ref}
{...otherProps}
>
<div className="flex w-full flex-wrap items-center gap-1">
<div
className={SubframeUtils.twClassNames("flex items-center gap-1.5", {
hidden: hideSearch,
})}
>
<FeatherSearch className="text-body-small-regular-150 font-body-small-regular-150 text-icon-neutral-tertiary" />
<input
className="w-40 flex-none text-body-small-regular-150 font-body-small-regular-150 text-text-neutral-secondary outline-none placeholder:text-text-neutral-subtle"
placeholder="Freitext suchen..."
value={searchValue}
onChange={(event) => onSearchChange(event.target.value)}
type="text"
/>
</div>
<div
className={SubframeUtils.twClassNames(
"flex h-5 w-px flex-none items-start bg-border-default",
{ hidden: hideSearch }
)}
/>
{children ? (
<div className="items-start contents">{children}</div>
) : null}
</div>
<div
className={SubframeUtils.twClassNames(
"hidden w-full flex-wrap items-center gap-1.5 border-t border-solid border-border-default pt-2",
{ flex: showActiveFilters }
)}
>
{activeFilters ? (
<div className="items-start contents">{activeFilters}</div>
) : null}
<div
className="flex h-6 items-center gap-1 rounded-md border border-solid border-border-negative-subtle bg-surface-feedback-subtle-negative px-1.5 py-1 cursor-pointer hover:bg-surface-feedback-subtle-negative-hover active:bg-surface-feedback-subtle-negative-active focus-within:shadow-focus"
role="button"
tabIndex={0}
onClick={onClearFilters}
onKeyDown={(event) => {
if (event.key === "Enter" || event.key === " ") {
event.preventDefault();
onClearFilters();
}
}}
>
<FeatherRotateCcw className="text-body-small-regular-150 font-body-small-regular-150 text-icon-feedback-negative" />
<span className="whitespace-nowrap text-body-small-regular-0 font-body-small-regular-0 text-text-feedback-negative">
Zurücksetzen
</span>
</div>
</div>
</div>
);
}
);
export const FilterBar = Object.assign(FilterBarRoot, {
StatusFilterButton,
});
+10
View File
@@ -0,0 +1,10 @@
"use client";
import { FilterBar as FilterBarComponent } from "./FilterBar";
/**
* 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 FilterBar = FilterBarComponent;
@@ -0,0 +1,55 @@
"use client";
/*
* Documentation:
* Form save Retry — https://app.subframe.com/f023064a5ca0/library?component=Form+save+Retry_db7627dd-19cb-457b-bbfd-6fe16d620fe0
*/
import React from "react";
import * as SubframeUtils from "../../utils";
export interface FormSaveRetryRootProps
extends Omit<React.HTMLAttributes<HTMLDivElement>, "title"> {
variant?: "default";
title?: React.ReactNode;
children?: React.ReactNode;
className?: string;
}
const FormSaveRetryRoot = React.forwardRef<
HTMLDivElement,
FormSaveRetryRootProps
>(function FormSaveRetryRoot(
{
variant = "default",
title,
children,
className,
...otherProps
}: FormSaveRetryRootProps,
ref
) {
return (
<div
className={SubframeUtils.twClassNames(
"flex max-w-[576px] flex-col items-start gap-2 px-4 py-4",
className
)}
ref={ref}
{...otherProps}
>
<div className="flex w-full items-center gap-2">
<img
className="h-1 w-1 flex-none object-cover"
src="data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNCIgaGVpZ2h0PSI0IiB2aWV3Qm94PSIwIDAgNCA0IiBmaWxsPSJub25lIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGNsYXNzPSJoLTEgdy0xIGZsZXgtbm9uZSIgZGF0YS1ub2RlLWlkPSJjNWJhMzRjMCI+PGNpcmNsZSBjeD0iMiIgY3k9IjIiIHI9IjIiIGZpbGw9IiNDNTIwMjAiPjwvY2lyY2xlPjwvc3ZnPg=="
/>
{children ? (
<div className="flex grow shrink-0 basis-0 items-center gap-2">
{children}
</div>
) : null}
</div>
</div>
);
});
export const FormSaveRetry = FormSaveRetryRoot;
+10
View File
@@ -0,0 +1,10 @@
"use client";
import { FormSaveRetry as FormSaveRetryComponent } from "./FormSaveRetry";
/**
* 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 FormSaveRetry = FormSaveRetryComponent;
@@ -0,0 +1,134 @@
"use client";
/*
* Documentation:
* Breadcrumbs — https://app.subframe.com/f023064a5ca0/library?component=Breadcrumbs_8898334b-a66f-4ee8-8bd1-afcfa8e37cc0
* Header Navigation — https://app.subframe.com/f023064a5ca0/library?component=Header+Navigation_9abee202-1896-4bb8-b899-63d76af2825e
* Icon Button — https://app.subframe.com/f023064a5ca0/library?component=Icon+Button_af9405b1-8c54-4e01-9786-5aad308224f6
* Search Input — https://app.subframe.com/f023064a5ca0/library?component=Search+Input_75a35ed3-52c0-4435-8586-e390eb77d723
*/
import React from "react";
import { FeatherBell } from "@subframe/core";
import * as SubframeCore from "@subframe/core";
import * as SubframeUtils from "../../utils";
import { Breadcrumbs } from "../Breadcrumbs";
import { IconButton } from "../IconButton";
import { SearchInput } from "../SearchInput";
export interface NavItemProps extends React.HTMLAttributes<HTMLDivElement> {
selected?: boolean;
children?: React.ReactNode;
icon?: React.ReactNode;
className?: string;
}
const NavItem = React.forwardRef<HTMLDivElement, NavItemProps>(function NavItem(
{
selected = false,
children,
icon = null,
className,
...otherProps
}: NavItemProps,
ref
) {
return (
<div
className={SubframeUtils.twClassNames(
"group/448f9541 flex cursor-pointer items-center justify-center gap-2 rounded-sm px-3 py-1.5 hover:bg-surface-neutral-tertiary",
{ "bg-surface-neutral-tertiary py-2": selected },
className
)}
ref={ref}
{...otherProps}
>
{icon ? (
<SubframeCore.IconWrapper
className={SubframeUtils.twClassNames(
"text-body-small-medium-0 font-body-small-medium-0 text-icon-neutral-secondary",
{ "text-icon-neutral-primary": selected }
)}
>
{icon}
</SubframeCore.IconWrapper>
) : null}
{children ? (
<span
className={SubframeUtils.twClassNames(
"whitespace-nowrap text-body-small-medium-0 font-body-small-medium-0 text-text-neutral-secondary",
{ "text-text-neutral-primary": selected }
)}
>
{children}
</span>
) : null}
</div>
);
});
export interface HeaderNavigationRootProps
extends React.HTMLAttributes<HTMLDivElement> {
leftSlot?: React.ReactNode;
breadcrumbs?: React.ReactNode[];
className?: string;
}
const HeaderNavigationRoot = React.forwardRef<
HTMLDivElement,
HeaderNavigationRootProps
>(function HeaderNavigationRoot(
{
leftSlot,
breadcrumbs = ["Übersicht"],
className,
...otherProps
}: HeaderNavigationRootProps,
ref
) {
return (
<div
className={SubframeUtils.twClassNames(
"flex h-14 w-full items-center justify-between border-b border-solid border-border-default bg-surface-neutral-secondary pl-6 pr-3 py-3 mobile:px-4",
className
)}
ref={ref}
{...otherProps}
>
<div className="flex grow shrink-0 basis-0 items-center justify-between">
<div className="flex items-center gap-6 pr-1">
<Breadcrumbs>
{breadcrumbs.map((breadcrumb, index) => (
<React.Fragment key={`${index}-${String(breadcrumb)}`}>
{index > 0 ? <Breadcrumbs.Divider /> : null}
<Breadcrumbs.Item active={index === breadcrumbs.length - 1}>
{breadcrumb}
</Breadcrumbs.Item>
</React.Fragment>
))}
</Breadcrumbs>
</div>
{leftSlot ? (
<div className="flex grow shrink-0 basis-0 items-center gap-6 mobile:gap-2">
{leftSlot}
</div>
) : null}
<div className="flex items-center gap-2 self-stretch pl-1">
<SearchInput
className="h-auto grow shrink-0 basis-0"
size="small"
label="Label"
helpText="Help text"
message="Hilfetext"
>
<SearchInput.Input placeholder="Suche" />
</SearchInput>
<IconButton variant="ghost" size="small" icon={<FeatherBell />} />
</div>
</div>
</div>
);
});
export const HeaderNavigation = Object.assign(HeaderNavigationRoot, {
NavItem,
});
+10
View File
@@ -0,0 +1,10 @@
"use client";
import { HeaderNavigation as HeaderNavigationComponent } from "./HeaderNavigation";
/**
* 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 HeaderNavigation = HeaderNavigationComponent;
+87
View File
@@ -0,0 +1,87 @@
"use client";
/*
* Documentation:
* Help Circle — https://app.subframe.com/f023064a5ca0/library?component=Help+Circle_bdf8292f-ad00-49d7-9ca6-98c24f58f842
*/
import React from "react";
import { FeatherHelpCircle } from "@subframe/core";
import * as SubframeCore from "@subframe/core";
import * as SubframeUtils from "../../utils";
export interface HelpCircleRootProps
extends React.HTMLAttributes<HTMLDivElement> {
icon?: React.ReactNode;
size?: "small" | "medium" | "large";
shape?: "default" | "background";
tooltipText?: React.ReactNode;
className?: string;
}
const HelpCircleRoot = React.forwardRef<HTMLDivElement, HelpCircleRootProps>(
function HelpCircleRoot(
{
icon = <FeatherHelpCircle />,
size = "medium",
shape = "default",
tooltipText,
className,
...otherProps
}: HelpCircleRootProps,
ref
) {
return (
<SubframeCore.Tooltip.Provider>
<SubframeCore.Tooltip.Root>
<SubframeCore.Tooltip.Trigger asChild={true}>
<div
className={SubframeUtils.twClassNames(
"group/bdf8292f flex cursor-pointer items-center justify-center rounded-md px-1 py-1",
{
"bg-surface-feedback-subtle-neutral hover:bg-surface-feedback-subtle-neutral-hover":
shape === "background",
},
className
)}
ref={ref}
{...otherProps}
>
{icon ? (
<SubframeCore.IconWrapper
className={SubframeUtils.twClassNames(
"text-body-default-medium-0 font-body-default-medium-0 text-icon-neutral-tertiary group-hover/bdf8292f:text-icon-neutral-secondary",
{
"text-body-large-0 font-body-large-0": size === "large",
"text-body-small-regular-0 font-body-small-regular-0":
size === "small",
}
)}
>
{icon}
</SubframeCore.IconWrapper>
) : null}
</div>
</SubframeCore.Tooltip.Trigger>
<SubframeCore.Tooltip.Portal>
<SubframeCore.Tooltip.Content
side="top"
align="center"
sideOffset={4}
asChild={true}
>
<div className="flex max-w-[384px] flex-col items-start gap-2 rounded-sm bg-surface-feedback-solid-neutral-active px-1.5 py-0.5 shadow-lg">
{tooltipText ? (
<span className="text-body-extra-small-medium-150 font-body-extra-small-medium-150 text-text-neutral-on-solid">
{tooltipText}
</span>
) : null}
</div>
</SubframeCore.Tooltip.Content>
</SubframeCore.Tooltip.Portal>
</SubframeCore.Tooltip.Root>
</SubframeCore.Tooltip.Provider>
);
}
);
export const HelpCircle = HelpCircleRoot;
+10
View File
@@ -0,0 +1,10 @@
"use client";
import { HelpCircle as HelpCircleComponent } from "./HelpCircle";
/**
* 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 HelpCircle = HelpCircleComponent;
+132
View File
@@ -0,0 +1,132 @@
"use client";
/*
* Documentation:
* Icon — https://app.subframe.com/f023064a5ca0/library?component=Icon_e24ec5dc-9821-430d-8254-1d72a7d46218
*/
import React from "react";
import { FeatherCircle } from "@subframe/core";
import { FeatherCircleDashed } from "@subframe/core";
import * as SubframeCore from "@subframe/core";
import * as SubframeUtils from "../../utils";
export interface IconFeedbackIconProps
extends React.ComponentProps<typeof SubframeCore.IconWrapper> {
variant?:
| "primary"
| "secondary"
| "tertiary"
| "destructive"
| "neutral"
| "success"
| "warning"
| "information";
size?: "medium" | "small" | "large";
icon?: React.ReactNode;
className?: string;
}
const IconFeedbackIcon = React.forwardRef<
React.ElementRef<typeof SubframeCore.IconWrapper>,
IconFeedbackIconProps
>(function IconFeedbackIcon(
{
variant = "primary",
size = "medium",
icon = <FeatherCircle />,
className,
...otherProps
}: IconFeedbackIconProps,
ref
) {
return icon ? (
<SubframeCore.IconWrapper
className={SubframeUtils.twClassNames(
"group/dc696813 text-body-large-0 font-body-large-0 text-icon-neutral-primary relative",
{
"text-heading-0 font-heading-0": size === "large",
"text-body-default-regular-0 font-body-default-regular-0":
size === "small",
"text-icon-feedback-information": variant === "information",
"text-icon-feedback-warning": variant === "warning",
"text-icon-feedback-positive": variant === "success",
"text-icon-feedback-negative": variant === "destructive",
"text-icon-neutral-tertiary": variant === "tertiary",
"text-icon-neutral-secondary": variant === "secondary",
},
className
)}
ref={ref}
{...otherProps}
>
{icon}
</SubframeCore.IconWrapper>
) : null;
});
export interface IconRootProps extends React.HTMLAttributes<HTMLDivElement> {
variant?:
| "primary"
| "secondary"
| "tertiary"
| "destructive"
| "neutral"
| "success"
| "warning"
| "information";
size?: "extra-small" | "small" | "medium" | "large" | "extra-large";
icon?: React.ReactNode;
className?: string;
}
const IconRoot = React.forwardRef<HTMLDivElement, IconRootProps>(
function IconRoot(
{
variant = "primary",
size = "medium",
icon = <FeatherCircleDashed />,
className,
...otherProps
}: IconRootProps,
ref
) {
return (
<div
className={SubframeUtils.twClassNames(
"group/e24ec5dc flex flex-col items-center justify-center rounded-sm",
className
)}
ref={ref}
{...otherProps}
>
{icon ? (
<SubframeCore.IconWrapper
className={SubframeUtils.twClassNames(
"text-body-large-0 font-body-large-0 text-icon-neutral-primary",
{
"text-subtitle-0 font-subtitle-0": size === "extra-large",
"text-heading-0 font-heading-0": size === "large",
"text-body-default-regular-0 font-body-default-regular-0":
size === "small",
"text-body-small-regular-0 font-body-small-regular-0":
size === "extra-small",
"text-icon-feedback-information": variant === "information",
"text-icon-feedback-warning": variant === "warning",
"text-icon-feedback-positive": variant === "success",
"text-icon-feedback-negative": variant === "destructive",
"text-icon-neutral-tertiary": variant === "tertiary",
"text-icon-neutral-secondary": variant === "secondary",
}
)}
>
{icon}
</SubframeCore.IconWrapper>
) : null}
</div>
);
}
);
export const Icon = Object.assign(IconRoot, {
IconFeedbackIcon,
});
+10
View File
@@ -0,0 +1,10 @@
"use client";
import { Icon as IconComponent } from "./Icon";
/**
* 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 Icon = IconComponent;
+124
View File
@@ -0,0 +1,124 @@
"use client";
/*
* Documentation:
* Icon Button — https://app.subframe.com/f023064a5ca0/library?component=Icon+Button_af9405b1-8c54-4e01-9786-5aad308224f6
*/
import React from "react";
import { FeatherPlus } from "@subframe/core";
import * as SubframeCore from "@subframe/core";
import * as SubframeUtils from "../../utils";
export interface IconButtonRootProps
extends React.ButtonHTMLAttributes<HTMLButtonElement> {
disabled?: boolean;
loading?: boolean;
variant?:
| "primary"
| "secondary"
| "tertiary"
| "ghost"
| "neutral"
| "destructive"
| "success"
| "warning"
| "information";
size?: "large" | "medium" | "small" | "extra-small" | "2-x-small";
square?: boolean;
icon?: React.ReactNode;
onClick?: (event: React.MouseEvent<HTMLButtonElement>) => void;
className?: string;
}
const IconButtonRoot = React.forwardRef<HTMLButtonElement, IconButtonRootProps>(
function IconButtonRoot(
{
disabled = false,
loading = false,
variant = "primary",
size = "medium",
square = false,
icon = <FeatherPlus />,
className,
type = "button",
...otherProps
}: IconButtonRootProps,
ref
) {
return (
<button
className={SubframeUtils.twClassNames(
"group/af9405b1 flex h-9 w-9 cursor-pointer items-center justify-center gap-2 rounded-round border-none bg-brand-brand-surface-solid-default text-left hover:bg-brand-brand-surface-solid-hover active:bg-brand-brand-surface-solid-active focus-within:shadow-focus disabled:cursor-default disabled:bg-surface-neutral-disabled disabled:pointer-events-none hover:disabled:cursor-default hover:disabled:bg-surface-neutral-disabled active:disabled:cursor-default active:disabled:bg-surface-neutral-disabled",
{
"rounded-md": square,
"h-4 w-4": size === "2-x-small",
"h-6 w-6": size === "extra-small",
"h-8 w-8": size === "small",
"h-12 w-12": size === "large",
"bg-surface-feedback-solid-information hover:bg-surface-feedback-solid-information-hover active:bg-surface-feedback-solid-information-active":
variant === "information",
"bg-surface-feedback-solid-warning hover:bg-surface-feedback-solid-warning-hover active:bg-surface-feedback-solid-warning-active":
variant === "warning",
"bg-surface-feedback-solid-positive-default hover:bg-surface-feedback-solid-positive-hover active:bg-surface-feedback-solid-positive-active":
variant === "success",
"bg-surface-feedback-solid-negative-default hover:bg-surface-feedback-solid-negative-hover active:bg-surface-feedback-solid-negative-active":
variant === "destructive",
"bg-surface-feedback-solid-neutral hover:bg-surface-feedback-solid-neutral-hover active:bg-surface-feedback-solid-neutral-active":
variant === "neutral",
"bg-transparent hover:bg-surface-neutral-tertiary active:bg-surface-neutral-tertiary":
variant === "ghost",
"border border-solid border-border-default bg-surface-neutral-primary hover:border hover:border-solid hover:border-border-strong hover:bg-surface-neutral-secondary active:bg-surface-neutral-tertiary":
variant === "tertiary",
"bg-brand-brand-secondary-surface-subtle-default hover:bg-brand-brand-secondary-surface-subtle-hover active:bg-brand-brand-secondary-surface-subtle-active":
variant === "secondary",
},
className
)}
ref={ref}
type={type}
disabled={disabled}
{...otherProps}
>
{icon ? (
<SubframeCore.IconWrapper
className={SubframeUtils.twClassNames(
"text-body-large-0 font-body-large-0 text-icon-neutral-on-solid group-disabled/af9405b1:text-icon-neutral-disabled",
{
"text-body-small-semibold-0 font-body-small-semibold-0":
size === "2-x-small",
"text-body-default-semibold-0 font-body-default-semibold-0":
size === "extra-small",
"text-heading-0 font-heading-0": size === "large",
"text-icon-neutral-secondary": variant === "ghost",
"text-icon-neutral-on-subtle": variant === "tertiary",
"text-icon-neutral-primary": variant === "secondary",
hidden: loading,
}
)}
>
{icon}
</SubframeCore.IconWrapper>
) : null}
<div
className={SubframeUtils.twClassNames(
"hidden h-4 w-4 flex-none items-center justify-center gap-2",
{ "h-5 w-5": size === "large", flex: loading }
)}
>
<SubframeCore.Loader
className={SubframeUtils.twClassNames(
"text-body-extra-small-regular-150 font-body-extra-small-regular-150 text-icon-neutral-on-solid group-disabled/af9405b1:text-icon-neutral-disabled group-hover/af9405b1:group-disabled/af9405b1:text-icon-neutral-on-solid group-active/af9405b1:group-disabled/af9405b1:text-icon-neutral-disabled",
{
"text-icon-neutral-secondary": variant === "ghost",
"text-icon-neutral-on-subtle": variant === "tertiary",
"text-icon-neutral-primary": variant === "secondary",
}
)}
/>
</div>
</button>
);
}
);
export const IconButton = IconButtonRoot;
+10
View File
@@ -0,0 +1,10 @@
"use client";
import { IconButton as IconButtonComponent } from "./IconButton";
/**
* 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 IconButton = IconButtonComponent;
@@ -0,0 +1,160 @@
"use client";
/*
* Documentation:
* Icon with Background — https://app.subframe.com/f023064a5ca0/library?component=Icon+with+Background_4a18e9fc-cea3-46ca-8c53-2412462342ad
*/
import React from "react";
import { FeatherFlag } from "@subframe/core";
import { FeatherMail } from "@subframe/core";
import * as SubframeCore from "@subframe/core";
import * as SubframeUtils from "../../utils";
export interface IconFeedbackIconProps
extends React.ComponentProps<typeof SubframeCore.IconWrapper> {
variant?:
| "primary"
| "secondary"
| "tertiary"
| "destructive"
| "neutral"
| "success"
| "warning"
| "information";
size?: "medium" | "small" | "large";
icon?: React.ReactNode;
className?: string;
}
const IconFeedbackIcon = React.forwardRef<
React.ElementRef<typeof SubframeCore.IconWrapper>,
IconFeedbackIconProps
>(function IconFeedbackIcon(
{
variant = "primary",
size = "medium",
icon = <FeatherFlag />,
className,
...otherProps
}: IconFeedbackIconProps,
ref
) {
return icon ? (
<SubframeCore.IconWrapper
className={SubframeUtils.twClassNames(
"group/8e5c09be text-body-large-0 font-body-large-0 text-icon-neutral-primary relative",
{
"text-heading-0 font-heading-0": size === "large",
"text-body-default-regular-0 font-body-default-regular-0":
size === "small",
"text-icon-feedback-information": variant === "information",
"text-icon-feedback-warning": variant === "warning",
"text-icon-feedback-positive": variant === "success",
"text-icon-feedback-negative": variant === "destructive",
"text-icon-neutral-tertiary": variant === "tertiary",
"text-icon-neutral-secondary": variant === "secondary",
},
className
)}
ref={ref}
{...otherProps}
>
{icon}
</SubframeCore.IconWrapper>
) : null;
});
export interface IconWithBackgroundRootProps
extends React.HTMLAttributes<HTMLDivElement> {
variant?:
| "primary"
| "secondary"
| "tertiary"
| "destructive"
| "neutral"
| "success"
| "warning"
| "information";
size?:
| "extra-small"
| "small"
| "medium"
| "large"
| "extra-large"
| "2-x-large"
| "3-x-large";
round?: boolean;
icon?: React.ReactNode;
className?: string;
}
const IconWithBackgroundRoot = React.forwardRef<
HTMLDivElement,
IconWithBackgroundRootProps
>(function IconWithBackgroundRoot(
{
variant = "primary",
size = "medium",
round = false,
icon = <FeatherMail />,
className,
...otherProps
}: IconWithBackgroundRootProps,
ref
) {
return (
<div
className={SubframeUtils.twClassNames(
"group/4a18e9fc flex flex-col items-center justify-center gap-2 rounded-sm bg-brand-brand-surface-subtle-default px-1.5 py-1.5",
{
"rounded-round": round,
"px-4 py-4":
size === "3-x-large" ||
size === "2-x-large" ||
size === "extra-large",
"px-2.5 py-2.5": size === "large",
"bg-surface-feedback-subtle-information": variant === "information",
"bg-surface-feedback-subtle-warning": variant === "warning",
"bg-surface-feedback-subtle-positive": variant === "success",
"bg-surface-feedback-subtle-neutral": variant === "neutral",
"bg-surface-feedback-subtle-negative": variant === "destructive",
"bg-surface-neutral-tertiary": variant === "tertiary",
"bg-surface-neutral-secondary": variant === "secondary",
},
className
)}
ref={ref}
{...otherProps}
>
{icon ? (
<SubframeCore.IconWrapper
className={SubframeUtils.twClassNames(
"text-body-large-0 font-body-large-0 text-icon-neutral-primary relative",
{
"text-title-hero font-title-hero": size === "3-x-large",
"text-title-page font-title-page": size === "2-x-large",
"text-subtitle-0 font-subtitle-0": size === "extra-large",
"text-heading-0 font-heading-0": size === "large",
"text-body-default-regular-0 font-body-default-regular-0":
size === "small",
"text-body-small-semibold-0 font-body-small-semibold-0":
size === "extra-small",
"text-icon-feedback-information": variant === "information",
"text-icon-feedback-warning": variant === "warning",
"text-icon-feedback-positive": variant === "success",
"text-icon-feedback-negative": variant === "destructive",
"text-icon-neutral-tertiary": variant === "tertiary",
"text-icon-neutral-secondary": variant === "secondary",
}
)}
>
{icon}
</SubframeCore.IconWrapper>
) : null}
</div>
);
});
export const IconWithBackground = Object.assign(IconWithBackgroundRoot, {
IconFeedbackIcon,
});
@@ -0,0 +1,10 @@
"use client";
import { IconWithBackground as IconWithBackgroundComponent } from "./IconWithBackground";
/**
* 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 IconWithBackground = IconWithBackgroundComponent;
+139
View File
@@ -0,0 +1,139 @@
"use client";
/*
* Documentation:
* Input OTP — https://app.subframe.com/f023064a5ca0/library?component=Input+OTP_1a223fbe-dca0-4e44-a383-44bbc7db975d
*/
import React from "react";
import * as SubframeUtils from "../../utils";
export interface InputProps
extends Omit<React.InputHTMLAttributes<HTMLInputElement>, "placeholder"> {
placeholder?: React.ReactNode;
className?: string;
}
const Input = React.forwardRef<HTMLInputElement, InputProps>(function Input(
{ placeholder, className, ...otherProps }: InputProps,
ref
) {
return (
<input
className={SubframeUtils.twClassNames(
"h-full w-full text-body-large-0 font-body-large-0 text-text-neutral-primary outline-none placeholder:text-text-neutral-subtle text-center",
className
)}
placeholder={placeholder as string}
value=""
ref={ref}
type="text"
{...otherProps}
/>
);
});
export interface OtpInputItemProps
extends React.HTMLAttributes<HTMLDivElement> {
success?: boolean;
error?: boolean;
disabled?: boolean;
children?: React.ReactNode;
className?: string;
}
const OtpInputItem = React.forwardRef<HTMLDivElement, OtpInputItemProps>(
function OtpInputItem(
{
success = false,
error = false,
disabled = false,
children,
className,
...otherProps
}: OtpInputItemProps,
ref
) {
return (
<div
className={SubframeUtils.twClassNames(
"group/7a2f2337 flex h-14 w-12 cursor-pointer items-center justify-center gap-2 rounded-md border border-solid border-border-default bg-surface-neutral-primary px-2 py-2 hover:border hover:border-solid hover:border-border-strong focus-within:shadow-focus",
{
"border-none bg-surface-neutral-disabled hover:border-none focus-within:shadow-none":
disabled,
"border border-solid border-border-negative-solid hover:border hover:border-solid hover:border-border-negative-solid":
error,
"border-none bg-surface-feedback-subtle-positive hover:border-none":
success,
},
className
)}
ref={ref}
{...otherProps}
>
{children ? (
<div className="flex grow shrink-0 basis-0 items-center justify-center self-stretch">
{children}
</div>
) : null}
</div>
);
}
);
export interface InputOtpRootProps
extends Omit<React.HTMLAttributes<HTMLDivElement>, "title"> {
state?: "default" | "error" | "disabled";
title?: React.ReactNode;
helperText?: React.ReactNode;
children?: React.ReactNode;
className?: string;
}
const InputOtpRoot = React.forwardRef<HTMLDivElement, InputOtpRootProps>(
function InputOtpRoot(
{
state = "default",
title,
helperText,
children,
className,
...otherProps
}: InputOtpRootProps,
ref
) {
return (
<div
className={SubframeUtils.twClassNames(
"group/1a223fbe flex flex-col items-center gap-4",
className
)}
ref={ref}
{...otherProps}
>
{title ? (
<span className="text-body-large-0 font-body-large-0 text-text-neutral-primary">
{title}
</span>
) : null}
{children ? (
<div className="flex items-center gap-2">{children}</div>
) : null}
{helperText ? (
<span
className={SubframeUtils.twClassNames(
"text-body-small-regular-0 font-body-small-regular-0 text-text-neutral-secondary",
{ "text-text-feedback-negative": state === "error" }
)}
>
{helperText}
</span>
) : null}
</div>
);
}
);
export const InputOtp = Object.assign(InputOtpRoot, {
Input,
OtpInputItem,
});
+10
View File
@@ -0,0 +1,10 @@
"use client";
import { InputOtp as InputOtpComponent } from "./InputOtp";
/**
* 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 InputOtp = InputOtpComponent;
+143
View File
@@ -0,0 +1,143 @@
"use client";
/*
* Documentation:
* Icon — https://app.subframe.com/f023064a5ca0/library?component=Icon_e24ec5dc-9821-430d-8254-1d72a7d46218
* KanbanCard — https://app.subframe.com/f023064a5ca0/library?component=KanbanCard_27235bcb-e61b-4880-9ae6-3f12d290a434
*/
import React from "react";
import { FeatherFlag } from "@subframe/core";
import { FeatherLock } from "@subframe/core";
import * as SubframeUtils from "../../utils";
import { Icon } from "../Icon";
export interface KanbanCardRootProps
extends React.HTMLAttributes<HTMLDivElement> {
tagsSlot?: React.ReactNode;
hideTags?: boolean;
titleSlot?: React.ReactNode;
valueSlot?: React.ReactNode;
priceLocked?: boolean;
footerLeftSlot?: React.ReactNode;
footerRightSlot?: React.ReactNode;
flagVariant?:
| "primary"
| "secondary"
| "tertiary"
| "destructive"
| "neutral"
| "success"
| "warning"
| "information";
keepTagRowSpace?: boolean;
className?: string;
}
const KanbanCardRoot = React.forwardRef<HTMLDivElement, KanbanCardRootProps>(
function KanbanCardRoot(
{
tagsSlot,
hideTags = false,
titleSlot,
valueSlot,
priceLocked = false,
footerLeftSlot,
footerRightSlot,
flagVariant = "primary",
keepTagRowSpace = false,
className,
...otherProps
}: KanbanCardRootProps,
ref
) {
return (
<div
className={SubframeUtils.twClassNames(
"group/27235bcb flex w-full min-w-[0px] flex-col items-start gap-3 max-w-full",
className
)}
ref={ref}
{...otherProps}
>
<div className="flex w-full min-w-[0px] flex-col items-start gap-4 rounded-lg border border-solid border-border-default bg-surface-neutral-secondary px-3 py-3 shadow-sm relative max-w-full">
<Icon
className="absolute top-3 right-3"
variant={
flagVariant === "information"
? "information"
: flagVariant === "warning"
? "warning"
: flagVariant === "success"
? "success"
: flagVariant === "neutral"
? "neutral"
: flagVariant === "destructive"
? "destructive"
: flagVariant === "tertiary"
? "tertiary"
: flagVariant === "secondary"
? "secondary"
: "primary"
}
icon={<FeatherFlag />}
/>
{tagsSlot ? (
<div
className={SubframeUtils.twClassNames(
"flex w-full min-w-[0px] flex-wrap items-center gap-1.5 pr-7 grow",
{ hidden: hideTags }
)}
>
{tagsSlot}
</div>
) : null}
<div
className={SubframeUtils.twClassNames(
"hidden h-5 w-full min-w-[0px] flex-none flex-wrap items-center gap-1.5 pr-7",
{ flex: keepTagRowSpace }
)}
/>
{titleSlot ? (
<div className="flex w-full min-w-[0px] flex-col items-start justify-center gap-2 pr-7">
{titleSlot}
</div>
) : null}
<div className="flex w-full min-w-[0px] flex-wrap items-center gap-2">
{valueSlot ? (
<div
className={SubframeUtils.twClassNames(
"flex min-w-[0px] flex-col items-start gap-2",
{ hidden: priceLocked }
)}
>
{valueSlot}
</div>
) : null}
<div
className={SubframeUtils.twClassNames(
"hidden min-w-[0px] items-center gap-1.5",
{ flex: priceLocked }
)}
>
<FeatherLock className="text-body-small-medium-0 font-body-small-medium-0 text-icon-neutral-tertiary" />
<span className="break-words text-body-small-regular-0 font-body-small-regular-0 text-text-neutral-tertiary">
Umsatz gesperrt
</span>
</div>
</div>
<div className="flex h-px w-full flex-none flex-col items-center gap-2 bg-border-default" />
<div className="flex w-full min-w-[0px] flex-wrap items-center justify-between gap-x-2 gap-y-2">
{footerLeftSlot ? (
<div className="flex items-center">{footerLeftSlot}</div>
) : null}
{footerRightSlot ? (
<div className="flex items-center">{footerRightSlot}</div>
) : null}
</div>
</div>
</div>
);
}
);
export const KanbanCard = KanbanCardRoot;
+10
View File
@@ -0,0 +1,10 @@
"use client";
import { KanbanCard as KanbanCardComponent } from "./KanbanCard";
/**
* 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 KanbanCard = KanbanCardComponent;
+171
View File
@@ -0,0 +1,171 @@
"use client";
/*
* Documentation:
* KanbanColumn — https://app.subframe.com/f023064a5ca0/library?component=KanbanColumn_bbc08458-14aa-4512-a807-e673a64315ab
*/
import React from "react";
import { FeatherChevronsLeft } from "@subframe/core";
import { FeatherChevronsRight } from "@subframe/core";
import { FeatherLock } from "@subframe/core";
import * as SubframeCore from "@subframe/core";
import * as SubframeUtils from "../../utils";
export interface KanbanColumnRootProps
extends React.HTMLAttributes<HTMLDivElement> {
collapsed?: boolean;
name?: React.ReactNode;
price?: React.ReactNode;
icon?: React.ReactNode;
badge?: React.ReactNode;
cards?: React.ReactNode;
sumLocked?: boolean;
className?: string;
}
const KanbanColumnRoot = React.forwardRef<
HTMLDivElement,
KanbanColumnRootProps
>(function KanbanColumnRoot(
{
collapsed = false,
name,
price,
icon = <FeatherChevronsLeft />,
badge,
cards,
sumLocked = false,
className,
...otherProps
}: KanbanColumnRootProps,
ref
) {
return (
<div
className={SubframeUtils.twClassNames(
"group/bbc08458 flex w-80 flex-col items-center gap-2 rounded-md border-2 border-solid border-border-default bg-surface-neutral-tertiary px-1.5 py-1.5 shrink-0 min-w-80 self-start",
{ "h-full w-12 px-0 min-w-12": collapsed },
className
)}
ref={ref}
{...otherProps}
>
<div
className={SubframeUtils.twClassNames(
"flex w-full flex-col items-center",
{ "grow shrink-0 basis-0 bg-surface-neutral-tertiary": collapsed }
)}
>
<div
className={SubframeUtils.twClassNames(
"flex w-full items-center justify-between px-1 pt-1.5 pb-1 gap-2",
{ "flex-col rounded-md py-3 cursor-pointer": collapsed }
)}
>
<FeatherChevronsRight
className={SubframeUtils.twClassNames(
"hidden text-body-small-semibold-0 font-body-small-semibold-0 text-icon-neutral-tertiary",
{ "inline-flex": collapsed }
)}
/>
<div
className={SubframeUtils.twClassNames(
"hidden grow shrink-0 basis-0 flex-col items-center gap-2 self-stretch py-3",
{ flex: collapsed }
)}
>
<div className="flex h-0.5 w-full flex-none flex-col items-center gap-2 bg-border-default" />
</div>
{name ? (
<span
className={SubframeUtils.twClassNames(
"hidden break-words text-body-small-semibold-150 font-body-small-semibold-150 text-text-neutral-primary [writing-mode:vertical-rl] rotate-180",
{ inline: collapsed }
)}
>
{name}
</span>
) : null}
<div
className={SubframeUtils.twClassNames(
"flex min-w-[0px] items-center gap-2.5 grow shrink",
{ "flex-col px-1 py-1": collapsed }
)}
>
{name ? (
<span
className={SubframeUtils.twClassNames(
"min-w-[0px] break-words text-body-small-semibold-150 font-body-small-semibold-150 text-text-neutral-primary",
{ hidden: collapsed }
)}
>
{name}
</span>
) : null}
{badge ? (
<div
className={SubframeUtils.twClassNames(
"flex items-center gap-2.5 shrink-0",
{ "px-1 py-2": collapsed }
)}
>
{badge}
</div>
) : null}
</div>
<div
className={SubframeUtils.twClassNames(
"flex min-w-[0px] items-center gap-2 shrink-0",
{ hidden: collapsed }
)}
>
<div
className={SubframeUtils.twClassNames(
"hidden items-center gap-1 shrink-0",
{ flex: sumLocked }
)}
>
<FeatherLock className="text-body-extra-small-regular-0 font-body-extra-small-regular-0 text-icon-neutral-subtle" />
<span className="whitespace-nowrap text-body-extra-small-regular-150 font-body-extra-small-regular-150 text-text-neutral-subtle">
Summe gesperrt
</span>
</div>
{price ? (
<span
className={SubframeUtils.twClassNames(
"break-words text-body-small-regular-0 font-body-small-regular-0 text-text-neutral-tertiary",
{ hidden: sumLocked }
)}
>
{price}
</span>
) : null}
{icon ? (
<SubframeCore.IconWrapper className="text-body-small-semibold-0 font-body-small-semibold-0 text-icon-neutral-tertiary">
{icon}
</SubframeCore.IconWrapper>
) : null}
</div>
</div>
</div>
<div
className={SubframeUtils.twClassNames(
"flex h-0.5 w-full flex-none flex-col items-center gap-2 bg-border-default",
{ hidden: collapsed }
)}
/>
{cards ? (
<div
className={SubframeUtils.twClassNames(
"flex w-full flex-col items-center gap-3 pb-2",
{ hidden: collapsed }
)}
>
{cards}
</div>
) : null}
</div>
);
});
export const KanbanColumn = KanbanColumnRoot;
+10
View File
@@ -0,0 +1,10 @@
"use client";
import { KanbanColumn as KanbanColumnComponent } from "./KanbanColumn";
/**
* 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 KanbanColumn = KanbanColumnComponent;
@@ -0,0 +1,49 @@
"use client";
/*
* Documentation:
* Kanban Subbar — https://app.subframe.com/f023064a5ca0/library?component=Kanban+Subbar_75a855a6-3419-4c84-97bd-540dd2f180a4
*/
import React from "react";
import * as SubframeUtils from "../../utils";
export interface KanbanSubbarRootProps
extends React.HTMLAttributes<HTMLDivElement> {
header?: React.ReactNode;
badge?: React.ReactNode;
children?: React.ReactNode;
className?: string;
}
const KanbanSubbarRoot = React.forwardRef<
HTMLDivElement,
KanbanSubbarRootProps
>(function KanbanSubbarRoot(
{ header, badge, children, className, ...otherProps }: KanbanSubbarRootProps,
ref
) {
return (
<div
className={SubframeUtils.twClassNames(
"flex w-full flex-col items-start gap-4 bg-surface-neutral-secondary px-4 py-4",
className
)}
ref={ref}
{...otherProps}
>
<div className="flex items-center gap-4 px-2 py-1">
{header ? (
<span className="text-body-large-0 font-body-large-0 text-text-neutral-primary">
{header}
</span>
) : null}
{badge ? <div className="flex items-center gap-4">{badge}</div> : null}
</div>
{children ? (
<div className="flex w-full flex-col items-start gap-2">{children}</div>
) : null}
</div>
);
});
export const KanbanSubbar = KanbanSubbarRoot;
+10
View File
@@ -0,0 +1,10 @@
"use client";
import { KanbanSubbar as KanbanSubbarComponent } from "./KanbanSubbar";
/**
* 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 KanbanSubbar = KanbanSubbarComponent;
+40
View File
@@ -0,0 +1,40 @@
"use client";
/*
* Documentation:
* Line Chart — https://app.subframe.com/f023064a5ca0/library?component=Line+Chart_22944dd2-3cdd-42fd-913a-1b11a3c1d16d
*/
import React from "react";
import * as SubframeCore from "@subframe/core";
import * as SubframeUtils from "../../utils";
export interface LineChartRootProps
extends React.ComponentProps<typeof SubframeCore.LineChart> {
className?: string;
}
const LineChartRoot = React.forwardRef<
React.ElementRef<typeof SubframeCore.LineChart>,
LineChartRootProps
>(function LineChartRoot(
{ className, ...otherProps }: LineChartRootProps,
ref
) {
return (
<SubframeCore.LineChart
className={SubframeUtils.twClassNames("h-80 w-full", className)}
ref={ref}
colors={[
"#3b82f6",
"#bfdbfe",
"#2563eb",
"#93c5fd",
"#1d4ed8",
"#60a5fa",
]}
{...otherProps}
/>
);
});
export const LineChart = LineChartRoot;
+10
View File
@@ -0,0 +1,10 @@
"use client";
import { LineChart as LineChartComponent } from "./LineChart";
/**
* 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 LineChart = LineChartComponent;
+107
View File
@@ -0,0 +1,107 @@
"use client";
/*
* Documentation:
* Link Button — https://app.subframe.com/f023064a5ca0/library?component=Link+Button_a4ee726a-774c-4091-8c49-55b659356024
*/
import React from "react";
import { FeatherArrowRight } from "@subframe/core";
import * as SubframeCore from "@subframe/core";
import * as SubframeUtils from "../../utils";
export interface LinkButtonRootProps
extends React.ButtonHTMLAttributes<HTMLButtonElement> {
disabled?: boolean;
variant?: "primary" | "subtle";
size?: "large" | "medium" | "small";
icon?: React.ReactNode;
children?: React.ReactNode;
iconRight?: React.ReactNode;
hideIcon?: boolean;
underline?: boolean;
onClick?: (event: React.MouseEvent<HTMLButtonElement>) => void;
className?: string;
}
const LinkButtonRoot = React.forwardRef<HTMLButtonElement, LinkButtonRootProps>(
function LinkButtonRoot(
{
disabled = false,
variant = "primary",
size = "medium",
icon = null,
children,
iconRight = <FeatherArrowRight />,
hideIcon = false,
underline = false,
className,
type = "button",
...otherProps
}: LinkButtonRootProps,
ref
) {
return (
<button
className={SubframeUtils.twClassNames(
"group/a4ee726a flex cursor-pointer items-start gap-2 border-none bg-transparent text-left",
className
)}
ref={ref}
type={type}
disabled={disabled}
{...otherProps}
>
{icon ? (
<SubframeCore.IconWrapper
className={SubframeUtils.twClassNames(
"text-body-default-regular-150 font-body-default-regular-150 text-icon-feedback-link-default group-hover/a4ee726a:text-icon-feedback-link-hover group-active/a4ee726a:text-icon-feedback-link-active group-disabled/a4ee726a:text-icon-neutral-disabled",
{
hidden: hideIcon,
"text-body-small-regular-150 font-body-small-regular-150":
size === "small",
"text-body-large font-body-large": size === "large",
"text-icon-neutral-primary": variant === "subtle",
}
)}
>
{icon}
</SubframeCore.IconWrapper>
) : null}
{children ? (
<span
className={SubframeUtils.twClassNames(
"min-w-[0px] break-words text-body-default-regular-0 font-body-default-regular-0 text-text-feedback-link-default group-hover/a4ee726a:text-text-feedback-link-hover group-active/a4ee726a:text-text-feedback-link-active group-disabled/a4ee726a:text-text-neutral-disabled group-hover/a4ee726a:group-disabled/a4ee726a:text-text-neutral-disabled group-active/a4ee726a:group-disabled/a4ee726a:text-text-neutral-disabled",
{
underline: underline,
"text-body-small-regular-0 font-body-small-regular-0":
size === "small",
"text-body-large-0 font-body-large-0": size === "large",
"text-text-neutral-primary": variant === "subtle",
}
)}
>
{children}
</span>
) : null}
{iconRight ? (
<SubframeCore.IconWrapper
className={SubframeUtils.twClassNames(
"text-body-default-regular-0 font-body-default-regular-0 text-icon-feedback-link-default group-hover/a4ee726a:text-icon-feedback-link-hover group-active/a4ee726a:text-icon-feedback-link-active group-disabled/a4ee726a:text-icon-neutral-disabled group-hover/a4ee726a:group-disabled/a4ee726a:text-icon-neutral-disabled group-active/a4ee726a:group-disabled/a4ee726a:text-text-neutral-disabled",
{
hidden: hideIcon,
"text-body-small-regular-150 font-body-small-regular-150":
size === "small",
"text-body-large font-body-large": size === "large",
"text-icon-neutral-primary": variant === "subtle",
}
)}
>
{iconRight}
</SubframeCore.IconWrapper>
) : null}
</button>
);
}
);
export const LinkButton = LinkButtonRoot;
+10
View File
@@ -0,0 +1,10 @@
"use client";
import { LinkButton as LinkButtonComponent } from "./LinkButton";
/**
* 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 LinkButton = LinkButtonComponent;
+41
View File
@@ -0,0 +1,41 @@
"use client";
/*
* Documentation:
* Loader — https://app.subframe.com/f023064a5ca0/library?component=Loader_f2e570c8-e463-45c2-aae9-a960146bc5d5
*/
import React from "react";
import * as SubframeCore from "@subframe/core";
import * as SubframeUtils from "../../utils";
export interface LoaderRootProps
extends React.ComponentProps<typeof SubframeCore.Loader> {
size?: "small" | "medium" | "large";
className?: string;
}
const LoaderRoot = React.forwardRef<
React.ElementRef<typeof SubframeCore.Loader>,
LoaderRootProps
>(function LoaderRoot(
{ size = "medium", className, ...otherProps }: LoaderRootProps,
ref
) {
return (
<SubframeCore.Loader
className={SubframeUtils.twClassNames(
"group/f2e570c8 font-['Inter'] text-[14px] font-[400] leading-[20px] text-[#2563eb]",
{
"text-[20px] font-[600] leading-[24px] tracking-normal":
size === "large",
"text-[12px] leading-[16px] tracking-normal": size === "small",
},
className
)}
ref={ref}
{...otherProps}
/>
);
});
export const Loader = LoaderRoot;
+10
View File
@@ -0,0 +1,10 @@
"use client";
import { Loader as LoaderComponent } from "./Loader";
/**
* 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 Loader = LoaderComponent;
@@ -0,0 +1,79 @@
"use client";
/*
* Documentation:
* Loading Indicator Skeleton — https://app.subframe.com/f023064a5ca0/library?component=Loading+Indicator+Skeleton_08dee637-2ba5-4c5d-86d4-a531fd11481f
*/
import React from "react";
import * as SubframeUtils from "../../utils";
export interface LoadingIndicatorSkeletonRootProps
extends React.HTMLAttributes<HTMLDivElement> {
variant?: "card" | "list";
className?: string;
}
const LoadingIndicatorSkeletonRoot = React.forwardRef<
HTMLDivElement,
LoadingIndicatorSkeletonRootProps
>(function LoadingIndicatorSkeletonRoot(
{
variant = "card",
className,
...otherProps
}: LoadingIndicatorSkeletonRootProps,
ref
) {
return (
<div
className={SubframeUtils.twClassNames(
"group/08dee637 flex w-full items-start rounded-[8px] border border-solid border-[#e7e7e7] bg-surface-neutral-primary px-6 py-6 group/mtskeleton",
{ "border border-solid border-border-default": variant === "list" },
className
)}
ref={ref}
{...otherProps}
>
<div
className={SubframeUtils.twClassNames(
"flex grow shrink-0 basis-0 flex-col items-start gap-4",
{ hidden: variant === "list" }
)}
>
<div className="flex items-center gap-3">
<div className="flex h-10 w-10 flex-none items-start rounded-[9999px] bg-surface-neutral-tertiary animate-pulse" />
<div className="flex min-w-[0px] flex-col items-start gap-2 flex-1">
<div className="flex h-3 flex-none items-start rounded-[4px] bg-[#e7e7e7] w-1/2 animate-pulse" />
<div className="flex h-3 flex-none items-start rounded-[4px] bg-[#e7e7e7] w-1/3 animate-pulse" />
</div>
</div>
<div className="flex h-32 w-full flex-none items-start rounded-[4px] bg-surface-neutral-tertiary animate-pulse" />
<div className="flex h-3 flex-none items-start rounded-[4px] bg-surface-neutral-tertiary w-1/3 animate-pulse" />
</div>
<div
className={SubframeUtils.twClassNames(
"hidden min-w-[0px] grow shrink-0 basis-0 flex-col items-start",
{ flex: variant === "list" }
)}
>
<div className="flex w-full items-start gap-3 pb-4">
<div className="flex h-8 w-8 flex-none items-start rounded-[4px] bg-surface-neutral-tertiary animate-pulse" />
<div className="flex min-w-[0px] flex-col items-start gap-2 flex-1">
<div className="flex h-20 w-full flex-none items-start rounded-[4px] bg-surface-neutral-tertiary animate-pulse" />
<div className="flex h-3 flex-none items-start rounded-[4px] bg-surface-neutral-tertiary w-1/2 animate-pulse" />
</div>
</div>
<div className="flex w-full items-center gap-3 border-t border-solid border-[#e7e7e7] py-4">
<div className="flex h-8 w-8 flex-none items-start rounded-[4px] bg-surface-neutral-tertiary animate-pulse" />
<div className="flex h-3 min-w-[0px] items-start rounded-[4px] bg-surface-neutral-tertiary flex-1 animate-pulse" />
</div>
<div className="flex w-full items-center gap-3 border-t border-solid border-[#e7e7e7] py-4">
<div className="flex h-8 w-8 flex-none items-start rounded-[4px] bg-surface-neutral-disabled animate-pulse" />
<div className="flex h-3 min-w-[0px] items-start rounded-[4px] bg-surface-neutral-tertiary flex-1 animate-pulse" />
</div>
</div>
</div>
);
});
export const LoadingIndicatorSkeleton = LoadingIndicatorSkeletonRoot;
Loaded 100 of 250 files, more files were not shown because too many files have changed in this diff. Show more