Track HiveGrid Cloud planning reference

This commit is contained in:
david committed 2026-06-26 20:48:01 +02:00
1 parent b3d5ea6764
commit e341c5938a
5784 files changed
+1104929 -3

No files matched your search

@@ -0,0 +1,62 @@
import ButtonSecondary from "../buttons/ButtonSecondary";
import IconEmptyResults from "~/components/ui/icons/IconEmptyResults";
import clsx from "clsx";
import { PlusIcon, ReloadIcon } from "~/components/ui/icons/vendor";
interface Captions {
description?: string;
thereAreNo?: string;
new?: string;
}
interface Props {
className?: string;
captions: Captions;
to?: string;
icon?: string;
onClick?: () => void;
}
export default function EmptyState({ className, captions, to, icon, onClick }: Props) {
return (
// Subframe EmptyState layout: centered column, px-4 py-8, gap-6 stack, gap-4 text block, 48px icon, body-large title / body-default body
<div className={clsx(className, "border-border-default flex flex-col items-center gap-6 rounded-md border-2 border-dashed px-4 py-8 text-center")}>
<IconEmptyResults className="h-12 w-12" />
<div className="flex max-w-[384px] flex-col items-center gap-4">
<h3 className="text-body-large-0 font-body-large-0 text-text-neutral-primary">{captions.thereAreNo}</h3>
{captions.description && (
<p className="text-text-neutral-secondary text-body-default-regular-150 font-body-default-regular-150">{captions.description}</p>
)}
</div>
{captions.new && (
<div>
{(() => {
if (to) {
return (
<ButtonSecondary to={to}>
{(() => {
if (icon === "plus") {
return <PlusIcon className="h-4 w-4" />;
} else if (icon === "refresh") {
return <ReloadIcon className="h-4 w-4" />;
} else {
return null;
}
})()}
<div>{captions.new}</div>
</ButtonSecondary>
);
} else {
return (
<ButtonSecondary onClick={onClick} type="button">
{icon === "plus" && <PlusIcon className="h-4 w-4" />}
<div>{captions.new}</div>
</ButtonSecondary>
);
}
})()}
</div>
)}
</div>
);
}
@@ -0,0 +1,14 @@
import ButtonSecondary from "../buttons/ButtonSecondary";
import IconEmptyResults from "~/components/ui/icons/IconEmptyResults";
import clsx from "clsx";
import { cn } from "~/lib/utils";
export default function EmptyStateSimple({ children, className }: { children: React.ReactNode; className?: string }) {
return (
// Subframe EmptyState layout: centered, px-4 py-8, body-default typo
<div className={cn("border-border-default bg-surface-neutral-primary w-full rounded-md border-2 border-dashed px-4 py-8 text-center", className)}>
{/* <IconEmptyResults className="mx-auto w-10" /> */}
<div className="text-text-neutral-secondary text-body-default-regular-150 font-body-default-regular-150">{children}</div>
</div>
);
}
@@ -0,0 +1,32 @@
import { useLocation } from "react-router";
import { t as i18nT } from "i18next";
import EmptyState from "./EmptyState";
export default function PreviewEmptyStates() {
const currentRoute = useLocation().pathname;
return (
<div id="empty-states" className="space-y-1">
<div className="border-border bg-background border border-dashed p-6">
<div className="w-full space-y-2">
<EmptyState
onClick={() => alert(i18nT("components.emptyState.preview.clicked"))}
captions={{
new: i18nT("components.emptyState.preview.button"),
thereAreNo: i18nT("components.emptyState.preview.thereAreNo"),
description: i18nT("components.emptyState.preview.description"),
}}
icon="plus"
/>
<EmptyState
to={currentRoute}
captions={{
new: i18nT("components.emptyState.preview.link"),
thereAreNo: i18nT("components.emptyState.preview.thereAreNo"),
description: i18nT("components.emptyState.preview.description"),
}}
/>
</div>
</div>
</div>
);
}