feat(dashboard): Platzhalterseite statt Hinweis-Toast

Der Menüpunkt 'Dashboard' löste bisher nur einen Toast aus. Ein
Navigationseintrag, der nirgendwohin führt, lässt den Leser im Unklaren, ob
etwas fehlt oder etwas kaputt ist.

Jetzt führt er auf /dashboard: ein Leerzustand nach dem Hausmuster
(ui/components/EmptyState), der benennt, warum hier nichts steht, was später
hinkommt (drei Rollen-Layouts, Widgets teils aus Analytics, teils nicht — offene
HR-Anträge, Aufgaben, Termine) und wo der Zuschnitt dokumentiert ist. Mit einem
Weg zurück nach Analytics.

Dabei:
- EmptyState aus der Cloud-Fassung nachgezogen; unsere Kopie hatte den
  action-Slot noch nicht.
- PageHeader bekommt 'standardAktionen': Auf einer leeren Seite gibt es nichts
  zu aktualisieren oder zu exportieren, also stehen dort auch keine
  Schaltflächen dafür.
- Die Variante 'software' in NavZiel entfällt — jeder Eintrag führt jetzt auf
  eine echte Seite, der Toast-Zweig in der AppShell war damit toter Code.
- verify-layout deckt /dashboard mit ab (jetzt 7 Seiten x 7 Breiten).

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 20:56:35 +02:00
1 parent 466c079644
commit 7183fad27a
9 files changed
+182 -140

No files matched your search

+51 -86
View File
@@ -7,103 +7,68 @@
import React from "react";
import * as SubframeUtils from "../../utils";
import { Button } from "../Button";
export interface EmptyStateRootProps
extends Omit<React.HTMLAttributes<HTMLDivElement>, "title"> {
export interface EmptyStateRootProps extends Omit<React.HTMLAttributes<HTMLDivElement>, "title"> {
variant?: "default" | "no-results" | "error";
outlined?: boolean;
fillContainer?: boolean;
title?: React.ReactNode;
body?: React.ReactNode;
// Optional call-to-action rendered below the text. When omitted (the default),
// no button is shown. Replaces the previous hard-coded "Create project" button.
action?: 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>
const EmptyStateRoot = React.forwardRef<HTMLDivElement, EmptyStateRootProps>(function EmptyStateRoot(
{ variant = "default", outlined = false, fillContainer = false, title, body, action, className, ...otherProps }: EmptyStateRootProps,
ref
) {
return (
<div
className={SubframeUtils.twClassNames(
// Local mod (HiveGrid): center the empty state within its container by
// default. The root was max-w-[384px] with the flex default justify-start,
// so the box hugged the left edge of the content area. Now the root spans
// the width and centers; the 384px reading width moves onto the inner
// column so body text still wraps. Re-check this on the next ~/ui sync.
"group/9fcf03a9 flex w-full items-center justify-center gap-4 px-4 py-8",
{
"border-border-default bg-surface-neutral-primary rounded-md border border-solid": outlined,
},
className
)}
ref={ref}
{...otherProps}
>
<div className={SubframeUtils.twClassNames("flex w-full max-w-[384px] flex-col items-center gap-6", { "max-w-none": fillContainer })}>
<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=="
alt=""
/>
<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="
alt=""
/>
<img
className={SubframeUtils.twClassNames("hidden h-12 w-12 flex-none object-cover", { block: variant === "error" })}
src="data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNDgiIGhlaWdodD0iNDgiIHZpZXdCb3g9IjAgMCA0OCA0OCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJNMjQgMTkuNVYyNyIgc3Ryb2tlPSIjQzUyMDIwIiBzdHJva2Utd2lkdGg9IjIiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCIvPjxwYXRoIGQ9Ik0yMS40MDM2IDcuNDk3MTNMNC45MDgwNCAzNS45OTU3QzQuNjQ0MDkgMzYuNDUxNyA0LjUwNDg5IDM2Ljk2OTIgNC41MDQ0NiAzNy40OTYxQzQuNTA0MDIgMzguMDIzIDQuNjQyMzYgMzguNTQwNyA0LjkwNTU1IDM4Ljk5NzFDNS4xNjg3NSAzOS40NTM2IDUuNTQ3NTEgMzkuODMyNyA2LjAwMzc0IDQwLjA5NjJDNi40NTk5NyA0MC4zNTk4IDYuOTc3NTcgNDAuNDk4NiA3LjUwNDQ3IDQwLjQ5ODZINDAuNDk1NkM0MS4wMjI0IDQwLjQ5ODYgNDEuNTQgNDAuMzU5OCA0MS45OTYzIDQwLjA5NjJDNDIuNDUyNSAzOS44MzI3IDQyLjgzMTMgMzkuNDUzNiA0My4wOTQ1IDM4Ljk5NzFDNDMuMzU3NyAzOC41NDA3IDQzLjQ5NiAzOC4wMjMgNDMuNDk1NiAzNy40OTYxQzQzLjQ5NTEgMzYuOTY5MiA0My4zNTU5IDM2LjQ1MTcgNDMuMDkyIDM1Ljk5NTdMMjYuNTk2NCA3LjQ5NzEzQzI2LjMzMjkgNy4wNDE4NSAyNS45NTQzIDYuNjYzODcgMjUuNDk4NiA2LjQwMTFDMjUuMDQyOSA2LjEzODMyIDI0LjUyNjEgNiAyNCA2QzIzLjQ3NCA2IDIyLjk1NzIgNi4xMzgzMiAyMi41MDE0IDYuNDAxMUMyMi4wNDU3IDYuNjYzODcgMjEuNjY3MSA3LjA0MTg1IDIxLjQwMzYgNy40OTcxM1Y3LjQ5NzEzWiIgc3Ryb2tlPSIjQzUyMDIwIiBzdHJva2Utd2lkdGg9IjIiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCIvPjxwYXRoIGQ9Ik0yNCAzNS42MjVDMjUuMDM1NSAzNS42MjUgMjUuODc1IDM0Ljc4NTUgMjUuODc1IDMzLjc1QzI1Ljg3NSAzMi43MTQ1IDI1LjAzNTUgMzEuODc1IDI0IDMxLjg3NUMyMi45NjQ1IDMxLjg3NSAyMi4xMjUgMzIuNzE0NSAyMi4xMjUgMzMuNzVDMjIuMTI1IDM0Ljc4NTUgMjIuOTY0NSAzNS42MjUgMjQgMzUuNjI1WiIgZmlsbD0iI0M1MjAyMCIvPjwvc3ZnPg=="
alt=""
/>
<div className="flex w-full flex-col items-center gap-4 px-4">
{title ? <span className="text-body-large-0 font-body-large-0 text-text-neutral-primary w-full text-center">{title}</span> : null}
{body ? (
<span className="text-body-default-regular-150 font-body-default-regular-150 text-text-neutral-secondary text-center break-words">{body}</span>
) : null}
</div>
{action ? <div className="flex flex-none items-center gap-2">{action}</div> : null}
</div>
</div>
);
}
);
</div>
);
});
export const EmptyState = EmptyStateRoot;
+11 -3
View File
@@ -1,10 +1,18 @@
"use client";
import { EmptyState as EmptyStateComponent } from "./EmptyState";
import React from "react";
import { EmptyState as EmptyStateComponent, type EmptyStateRootProps } 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
*
* History: this wrapper used to add `[&_button]:hidden` to suppress the synced
* component's hardcoded, non-wired english CTA ("Create project"). The synced
* component has since gained a proper `action` slot and no hardcoded button,
* so the class only hid the real action buttons screens pass in (create/retry
* CTAs). Do not re-add a blanket button-hiding class here.
*/
export const EmptyState = EmptyStateComponent;
export const EmptyState = React.forwardRef<HTMLDivElement, EmptyStateRootProps>(function EmptyState(props, ref) {
return <EmptyStateComponent ref={ref} {...props} />;
});