From 1065e30c8d2075da928056945eeb4c065e3d3702 Mon Sep 17 00:00:00 2001 From: Thomas Camlong Date: Thu, 28 May 2026 12:15:44 +0200 Subject: [PATCH] feat(init): unify onboarding step widths with shared layout Replace per-step hardcoded Card widths (384px, 776px, 1024px) with a consistent 1024px shell defined in _constants.ts. All steps now use an InitStepCard wrapper set to w=100%, inheriting width from the page shell. Also updates old-import cards to w=100% for proper width propagation. --- .../[locale]/init/_components/init-step-card.tsx | 12 ++++++++++++ apps/nextjs/src/app/[locale]/init/_constants.ts | 2 ++ .../[locale]/init/_steps/finish/init-finish.tsx | 8 +++++--- .../app/[locale]/init/_steps/group/init-group.tsx | 8 +++++--- .../[locale]/init/_steps/import/file-info-card.tsx | 8 +++++--- .../[locale]/init/_steps/import/init-import.tsx | 9 +++++---- .../init/_steps/settings/init-settings.tsx | 14 ++++++++------ .../app/[locale]/init/_steps/start/init-start.tsx | 7 ++++--- .../app/[locale]/init/_steps/user/init-user.tsx | 7 +++---- apps/nextjs/src/app/[locale]/init/page.tsx | 3 ++- .../src/components/initial-oldmarr-import.tsx | 2 +- .../components/initial/board-selection-card.tsx | 2 +- .../components/initial/import-settings-card.tsx | 2 +- .../src/components/initial/import-summary-card.tsx | 2 +- 14 files changed, 55 insertions(+), 31 deletions(-) create mode 100644 apps/nextjs/src/app/[locale]/init/_components/init-step-card.tsx create mode 100644 apps/nextjs/src/app/[locale]/init/_constants.ts diff --git a/apps/nextjs/src/app/[locale]/init/_components/init-step-card.tsx b/apps/nextjs/src/app/[locale]/init/_components/init-step-card.tsx new file mode 100644 index 000000000..e51149147 --- /dev/null +++ b/apps/nextjs/src/app/[locale]/init/_components/init-step-card.tsx @@ -0,0 +1,12 @@ +import type { PropsWithChildren } from "react"; +import { Card } from "@mantine/core"; + +interface InitStepCardProps { + withBorder?: boolean; +} + +export const InitStepCard = ({ children, withBorder = true }: PropsWithChildren) => ( + + {children} + +); diff --git a/apps/nextjs/src/app/[locale]/init/_constants.ts b/apps/nextjs/src/app/[locale]/init/_constants.ts new file mode 100644 index 000000000..870cbdc21 --- /dev/null +++ b/apps/nextjs/src/app/[locale]/init/_constants.ts @@ -0,0 +1,2 @@ +export const onboardingContentWidth = 64 * 16; +export const onboardingMaxWidth = "90vw"; diff --git a/apps/nextjs/src/app/[locale]/init/_steps/finish/init-finish.tsx b/apps/nextjs/src/app/[locale]/init/_steps/finish/init-finish.tsx index 477cf6d46..ff7c2042a 100644 --- a/apps/nextjs/src/app/[locale]/init/_steps/finish/init-finish.tsx +++ b/apps/nextjs/src/app/[locale]/init/_steps/finish/init-finish.tsx @@ -1,5 +1,5 @@ import type { MantineColor } from "@mantine/core"; -import { Button, Card, Stack, Text } from "@mantine/core"; +import { Button, Stack, Text } from "@mantine/core"; import { IconBook2, IconLayoutDashboard, IconMailForward } from "@tabler/icons-react"; import { isProviderEnabled } from "@homarr/auth/server"; @@ -9,11 +9,13 @@ import { getScopedI18n } from "@homarr/translation/server"; import { Link } from "@homarr/ui"; import type { TablerIcon } from "@homarr/ui"; +import { InitStepCard } from "../../_components/init-step-card"; + export const InitFinish = async () => { const tFinish = await getScopedI18n("init.step.finish"); return ( - + {tFinish("description")} @@ -37,7 +39,7 @@ export const InitFinish = async () => { {tFinish("action.docs")} - + ); }; diff --git a/apps/nextjs/src/app/[locale]/init/_steps/group/init-group.tsx b/apps/nextjs/src/app/[locale]/init/_steps/group/init-group.tsx index 94424ef7d..98602de73 100644 --- a/apps/nextjs/src/app/[locale]/init/_steps/group/init-group.tsx +++ b/apps/nextjs/src/app/[locale]/init/_steps/group/init-group.tsx @@ -1,6 +1,6 @@ "use client"; -import { Button, Card, Stack, TextInput } from "@mantine/core"; +import { Button, Stack, TextInput } from "@mantine/core"; import { IconArrowRight } from "@tabler/icons-react"; import type { z } from "zod/v4"; @@ -10,6 +10,8 @@ import { useZodForm } from "@homarr/form"; import { useI18n } from "@homarr/translation/client"; import { groupCreateSchema } from "@homarr/validation/group"; +import { InitStepCard } from "../../_components/init-step-card"; + export const InitGroup = () => { const t = useI18n(); const { mutateAsync } = clientApi.group.createInitialExternalGroup.useMutation({ @@ -34,7 +36,7 @@ export const InitGroup = () => { }; return ( - +
{
-
+ ); }; diff --git a/apps/nextjs/src/app/[locale]/init/_steps/import/file-info-card.tsx b/apps/nextjs/src/app/[locale]/init/_steps/import/file-info-card.tsx index 3acbe646b..8a3a14fb4 100644 --- a/apps/nextjs/src/app/[locale]/init/_steps/import/file-info-card.tsx +++ b/apps/nextjs/src/app/[locale]/init/_steps/import/file-info-card.tsx @@ -1,10 +1,12 @@ -import { ActionIcon, Button, Card, Group, Text } from "@mantine/core"; +import { ActionIcon, Button, Group, Text } from "@mantine/core"; import type { FileWithPath } from "@mantine/dropzone"; import { IconPencil } from "@tabler/icons-react"; import { humanFileSize } from "@homarr/common"; import { useScopedI18n } from "@homarr/translation/client"; +import { InitStepCard } from "../../_components/init-step-card"; + interface FileInfoCardProps { file: FileWithPath; onRemove: () => void; @@ -13,7 +15,7 @@ interface FileInfoCardProps { export const FileInfoCard = ({ file, onRemove }: FileInfoCardProps) => { const tFileInfo = useScopedI18n("init.step.import.fileInfo"); return ( - + @@ -36,6 +38,6 @@ export const FileInfoCard = ({ file, onRemove }: FileInfoCardProps) => { - + ); }; diff --git a/apps/nextjs/src/app/[locale]/init/_steps/import/init-import.tsx b/apps/nextjs/src/app/[locale]/init/_steps/import/init-import.tsx index cdb3faf50..c7113b66b 100644 --- a/apps/nextjs/src/app/[locale]/init/_steps/import/init-import.tsx +++ b/apps/nextjs/src/app/[locale]/init/_steps/import/init-import.tsx @@ -1,13 +1,14 @@ "use client"; import { startTransition, useState } from "react"; -import { Card, Stack } from "@mantine/core"; +import { Stack } from "@mantine/core"; import type { FileWithPath } from "@mantine/dropzone"; import type { RouterOutputs } from "@homarr/api"; import { clientApi } from "@homarr/api/client"; import { InitialOldmarrImport } from "@homarr/old-import/components"; +import { InitStepCard } from "../../_components/init-step-card"; import { FileInfoCard } from "./file-info-card"; import { ImportDropZone } from "./import-dropzone"; @@ -20,7 +21,7 @@ export const InitImport = () => { if (!file) { return ( - + { @@ -40,12 +41,12 @@ export const InitImport = () => { }); }} /> - + ); } return ( - + setFile(null)} /> {analyseResult !== null && } diff --git a/apps/nextjs/src/app/[locale]/init/_steps/settings/init-settings.tsx b/apps/nextjs/src/app/[locale]/init/_steps/settings/init-settings.tsx index cb024fc2f..5c99d651c 100644 --- a/apps/nextjs/src/app/[locale]/init/_steps/settings/init-settings.tsx +++ b/apps/nextjs/src/app/[locale]/init/_steps/settings/init-settings.tsx @@ -1,6 +1,6 @@ "use client"; -import { Button, Card, Group, Stack, Switch, Text } from "@mantine/core"; +import { Button, Group, Stack, Switch, Text } from "@mantine/core"; import { IconArrowRight } from "@tabler/icons-react"; import type { z } from "zod/v4"; @@ -13,6 +13,8 @@ import type { TranslationObject } from "@homarr/translation"; import { useI18n, useScopedI18n } from "@homarr/translation/client"; import { settingsInitSchema } from "@homarr/validation/settings"; +import { InitStepCard } from "../../_components/init-step-card"; + export const InitSettings = () => { const tSection = useScopedI18n("management.page.settings.section"); const t = useI18n(); @@ -29,8 +31,8 @@ export const InitSettings = () => { return (
- - + + {tSection("analytics.title")} @@ -38,8 +40,8 @@ export const InitSettings = () => { - - + + {tSection("crawlingAndIndexing.title")} @@ -62,7 +64,7 @@ export const InitSettings = () => { /> - +