diff --git a/web/ai-extraction-review/app/page.tsx b/web/ai-extraction-review/app/page.tsx index 4705752c..517bde9b 100644 --- a/web/ai-extraction-review/app/page.tsx +++ b/web/ai-extraction-review/app/page.tsx @@ -3,10 +3,11 @@ import { ExtractionReviewCard } from "./ExtractionReviewCard"; import { getInvoiceExtraction } from "../lib/api"; import { EXAMPLE_INVOICE } from "../lib/examples"; +import { PageContainer } from "@nexarch/shl"; export default function ExtractionReviewPage() { return ( -
+

Extraktions-Korrektur

-
+ ); } diff --git a/web/ai-search-chat/app/page.tsx b/web/ai-search-chat/app/page.tsx index 82abfffe..cd356a6e 100644 --- a/web/ai-search-chat/app/page.tsx +++ b/web/ai-search-chat/app/page.tsx @@ -4,6 +4,7 @@ import { useState } from "react"; import { SearchPanel } from "./SearchPanel"; import { ChatPanel, ChatTurn } from "./ChatPanel"; import { Hit } from "../lib/api"; +import { PageContainer } from "@nexarch/shl"; type Tab = "search" | "chat"; @@ -17,7 +18,7 @@ export default function SearchChatPage() { const [chatHistory, setChatHistory] = useState([]); return ( -
+

Suche und Chat

@@ -59,6 +60,6 @@ export default function SearchChatPage() { onHistoryChange={setChatHistory} />
-
+ ); } diff --git a/web/ai-summaries/app/page.tsx b/web/ai-summaries/app/page.tsx index 6cef1dec..28b78c5a 100644 --- a/web/ai-summaries/app/page.tsx +++ b/web/ai-summaries/app/page.tsx @@ -3,10 +3,11 @@ import { SummaryCard } from "./SummaryCard"; import { getDocumentSummary, getThreadSummary } from "../lib/api"; import { EXAMPLE_DOCUMENT, EXAMPLE_THREAD } from "../lib/examples"; +import { PageContainer } from "@nexarch/shl"; export default function SummariesPage() { return ( -
+

Zusammenfassungen

(await getThreadSummary(EXAMPLE_THREAD.id)).summary} /> -
+ ); } diff --git a/web/audit-log/app/page.tsx b/web/audit-log/app/page.tsx index 7561a936..81da05c8 100644 --- a/web/audit-log/app/page.tsx +++ b/web/audit-log/app/page.tsx @@ -2,6 +2,7 @@ import { useState } from "react"; import { fetchRecords, downloadExport, type AuditRecord, type AuditFilter } from "@/lib/api"; +import { PageContainer } from "@nexarch/shl"; const EMPTY_FILTER: AuditFilter = { tenant: "", actor: "", action: "", from: "", to: "" }; @@ -37,7 +38,7 @@ export default function Page() { } return ( -
+

Audit-Log

@@ -163,6 +164,6 @@ export default function Page() { )} -
+ ); } diff --git a/web/core-control/app/page.tsx b/web/core-control/app/page.tsx index eea20562..709e1069 100644 --- a/web/core-control/app/page.tsx +++ b/web/core-control/app/page.tsx @@ -1,10 +1,11 @@ import { ControlSections } from "./ControlSections"; +import { PageContainer } from "@nexarch/shl"; export default function Page() { return ( -
+

NEXARCH Core-Steuerung

-
+ ); } diff --git a/web/dms-upload/app/page.tsx b/web/dms-upload/app/page.tsx index 56928d49..47816d92 100644 --- a/web/dms-upload/app/page.tsx +++ b/web/dms-upload/app/page.tsx @@ -1,10 +1,11 @@ import { UploadManager } from "../components/UploadManager"; +import { PageContainer } from "@nexarch/shl"; export default function IndexPage() { return ( -
+

Dokumente hochladen

-
+ ); } diff --git a/web/dms2-import/app/page.tsx b/web/dms2-import/app/page.tsx index b26fcd1a..4dd1e945 100644 --- a/web/dms2-import/app/page.tsx +++ b/web/dms2-import/app/page.tsx @@ -2,7 +2,7 @@ import { Suspense } from "react"; import { useSearchParams } from "next/navigation"; -import { TextField } from "@nexarch/shl"; +import { TextField, PageContainer } from "@nexarch/shl"; import { ImportAssistant } from "./ImportAssistant"; function ImportPage() { @@ -11,7 +11,7 @@ function ImportPage() { const tenant = params.get("tenant") ?? ""; return ( -
+

Import-Assistent fuer Drittsystem-Exporte

{userId === "" || tenant === "" ? (
)} -
+ ); } diff --git a/web/lic-admin/app/page.tsx b/web/lic-admin/app/page.tsx index 8f8d056d..2111f892 100644 --- a/web/lic-admin/app/page.tsx +++ b/web/lic-admin/app/page.tsx @@ -2,6 +2,7 @@ import { useState } from "react"; import { fetchOverview, toggleFlag, type Overview } from "@/lib/api"; +import { PageContainer } from "@nexarch/shl"; const STATUS_LABEL: Record = { ok: "In Ordnung", @@ -48,7 +49,7 @@ export default function Page() { } return ( -
+

Lizenz- und Modulverwaltung

@@ -169,6 +170,6 @@ export default function Page() { )} -
+ ); } diff --git a/web/mail-search/app/page.tsx b/web/mail-search/app/page.tsx index 7ffb91df..8e7f2641 100644 --- a/web/mail-search/app/page.tsx +++ b/web/mail-search/app/page.tsx @@ -2,7 +2,7 @@ import { useState, useEffect, useCallback, useRef, type FormEvent } from "react"; import Link from "next/link"; -import { TextField, useToast } from "@nexarch/shl"; +import { TextField, useToast, PageContainer } from "@nexarch/shl"; import { search, facets, ApiError, type SearchHit, type AppliedFilter, type FacetsResponse } from "../lib/api"; import { splitHighlighted } from "../lib/highlight"; import { HIGHLIGHT_BG_LIGHT, HIGHLIGHT_FG_LIGHT } from "../lib/highlightColors"; @@ -185,7 +185,7 @@ export default function SearchPage() { }, [hits, focusedIndex, focusResult, archiveFocused]); return ( -
+

Mail-Suche

Tastenkürzel: / Suche fokussieren, j/k nächste/vorherige Nachricht,{" "} @@ -255,6 +255,6 @@ export default function SearchPage() { ))} )} -

+ ); } diff --git a/web/pdf-viewer/app/page.tsx b/web/pdf-viewer/app/page.tsx index 077576ac..8fd4bd2f 100644 --- a/web/pdf-viewer/app/page.tsx +++ b/web/pdf-viewer/app/page.tsx @@ -1,14 +1,14 @@ "use client"; -import { useI18n } from "@nexarch/shl"; +import { useI18n, PageContainer } from "@nexarch/shl"; import "../lib/messages"; export default function IndexPage() { const { t } = useI18n(); return ( -
+

{t("pdf.index.title", "NEXARCH Dokumentbetrachter")}

{t("pdf.index.hint", "Diese Anwendung wird über /viewer/ aufgerufen.")}

-
+ ); } diff --git a/web/routing-rules/app/page.tsx b/web/routing-rules/app/page.tsx index 27e1620b..22a44181 100644 --- a/web/routing-rules/app/page.tsx +++ b/web/routing-rules/app/page.tsx @@ -2,7 +2,7 @@ import { Suspense } from "react"; import { useSearchParams } from "next/navigation"; -import { TextField } from "@nexarch/shl"; +import { TextField, PageContainer } from "@nexarch/shl"; import { RuleEditor } from "./RuleEditor"; function RulesPage() { @@ -10,7 +10,7 @@ function RulesPage() { const userId = params.get("user") ?? ""; return ( -
+

Routing-Regel-Editor

{userId === "" ? ( )} -
+ ); } diff --git a/web/shl/components/PageContainer.tsx b/web/shl/components/PageContainer.tsx new file mode 100644 index 00000000..9a4592ae --- /dev/null +++ b/web/shl/components/PageContainer.tsx @@ -0,0 +1,17 @@ +import type { CSSProperties, ReactNode } from "react"; + +export interface PageContainerProps { + maxWidth?: CSSProperties["maxWidth"]; + margin?: CSSProperties["margin"]; + padding?: CSSProperties["padding"]; + children: ReactNode; +} + +// Ersetzt den in 17 Seiten unabhaengig kopierten +// `
`-Container (Fable-Review +// auf Code-Dopplung). margin/padding bleiben als Props einstellbar, da +// die kopierten Varianten sich darin unterschieden (z. B. "0 auto" vs. +// "40px auto", "24px" vs. "2rem 1rem"). +export function PageContainer({ maxWidth = 960, margin = "0 auto", padding = 24, children }: PageContainerProps) { + return
{children}
; +} diff --git a/web/shl/index.ts b/web/shl/index.ts index f1e46790..46791370 100644 --- a/web/shl/index.ts +++ b/web/shl/index.ts @@ -17,6 +17,9 @@ export type { ShellProps, ModuleLink } from "./components/Shell"; export { ModuleNavShell, MODULE_REGISTRY, resolveModuleHref } from "./components/ModuleNavShell"; export type { ModuleNavShellProps, ModuleRegistryEntry } from "./components/ModuleNavShell"; +export { PageContainer } from "./components/PageContainer"; +export type { PageContainerProps } from "./components/PageContainer"; + export { Dialog } from "./components/Dialog"; export type { DialogProps } from "./components/Dialog"; diff --git a/web/status-page/app/page.tsx b/web/status-page/app/page.tsx index 47c0fcb9..c921a452 100644 --- a/web/status-page/app/page.tsx +++ b/web/status-page/app/page.tsx @@ -2,6 +2,7 @@ import { useEffect, useState } from "react"; import { fetchOverview, fetchHistory, type ModuleStatus, type HistoryEntry } from "@/lib/api"; +import { PageContainer } from "@nexarch/shl"; const POLL_INTERVAL_MS = 5000; @@ -56,7 +57,7 @@ export default function Page() { const anyDown = modules.some((m) => m.status === "down"); return ( -
+

Systemstatus

{error && ( @@ -120,6 +121,6 @@ export default function Page() { )} -
+ ); } diff --git a/web/tenant-admin/app/page.tsx b/web/tenant-admin/app/page.tsx index c1191acd..15593ce6 100644 --- a/web/tenant-admin/app/page.tsx +++ b/web/tenant-admin/app/page.tsx @@ -1,6 +1,7 @@ "use client"; import { useState } from "react"; +import { PageContainer } from "@nexarch/shl"; import { fetchTenants, fetchTenantDetail, @@ -97,7 +98,7 @@ export default function Page() { } return ( -
+

Mandantenverwaltung

@@ -222,6 +223,6 @@ export default function Page() {
)} -
+ ); } diff --git a/web/workflow-approvals/app/page.tsx b/web/workflow-approvals/app/page.tsx index 28acbeaf..a877db0b 100644 --- a/web/workflow-approvals/app/page.tsx +++ b/web/workflow-approvals/app/page.tsx @@ -2,7 +2,7 @@ import { Suspense } from "react"; import { useSearchParams } from "next/navigation"; -import { TextField } from "@nexarch/shl"; +import { TextField, PageContainer } from "@nexarch/shl"; import { ApprovalList } from "./ApprovalList"; function ApprovalsPage() { @@ -10,7 +10,7 @@ function ApprovalsPage() { const userId = params.get("user") ?? ""; return ( -
+

Meine Freigaben

{userId === "" ? ( )} -
+ ); } diff --git a/web/workflow-cases/app/page.tsx b/web/workflow-cases/app/page.tsx index 4fffe95b..c9c5ae78 100644 --- a/web/workflow-cases/app/page.tsx +++ b/web/workflow-cases/app/page.tsx @@ -2,7 +2,7 @@ import { Suspense, useState } from "react"; import { useSearchParams } from "next/navigation"; -import { TextField } from "@nexarch/shl"; +import { TextField, PageContainer } from "@nexarch/shl"; import { CaseOverview } from "./CaseOverview"; import { ReminderKanban } from "./ReminderKanban"; @@ -14,7 +14,7 @@ function CasesPage() { const [tab, setTab] = useState("cases"); return ( -
+

Akten & Wiedervorlagen

{userId === "" ? ( : } )} -
+ ); } diff --git a/web/workflow-tasks/app/page.tsx b/web/workflow-tasks/app/page.tsx index b398cbdb..c8e706dc 100644 --- a/web/workflow-tasks/app/page.tsx +++ b/web/workflow-tasks/app/page.tsx @@ -2,7 +2,7 @@ import { Suspense } from "react"; import { useSearchParams } from "next/navigation"; -import { TextField } from "@nexarch/shl"; +import { TextField, PageContainer } from "@nexarch/shl"; import { TaskBoard } from "./TaskBoard"; function TasksPage() { @@ -11,7 +11,7 @@ function TasksPage() { const tenantSlug = params.get("tenant") ?? ""; return ( -
+

Aufgaben

{userId === "" || tenantSlug === "" ? ( )} -
+ ); }