diff --git a/app/admin/layout.tsx b/app/admin/layout.tsx index 889c695..f556ce0 100644 --- a/app/admin/layout.tsx +++ b/app/admin/layout.tsx @@ -1,7 +1,8 @@ import { cookies } from "next/headers"; -import { SidebarProvider, SidebarTrigger } from "@/components/ui/sidebar"; +import { SidebarProvider } from "@/components/ui/sidebar"; import { verifySession } from "@/lib/supabase/dal"; import { AppSidebar } from "@/modules/shared/ui/components/app-sidebar"; +import { MobileHeader } from "@/modules/shared/ui/components/mobile-header"; import { TermsDialog } from "@/modules/shared/ui/components/terms-dialog"; @@ -14,11 +15,9 @@ export default async function AdminLayout({ children }: { children: React.ReactN {!session.isAdmin && !session.hasAcceptedTerms && } -
-
- -
-
{children}
+
+ +
{children}
) diff --git a/app/client/layout.tsx b/app/client/layout.tsx index bf5d0b6..ab5e0d8 100644 --- a/app/client/layout.tsx +++ b/app/client/layout.tsx @@ -1,7 +1,8 @@ import { cookies } from "next/headers"; -import { SidebarProvider, SidebarTrigger } from "@/components/ui/sidebar"; +import { SidebarProvider } from "@/components/ui/sidebar"; import { verifySession } from "@/lib/supabase/dal"; import { AppSidebar } from "@/modules/shared/ui/components/app-sidebar"; +import { MobileHeader } from "@/modules/shared/ui/components/mobile-header"; import { TermsDialog } from "@/modules/shared/ui/components/terms-dialog"; @@ -17,11 +18,9 @@ export default async function ClientLayout({ children }: { children: React.React return ( -
-
- -
-
{children}
+
+ +
{children}
) diff --git a/app/globals.css b/app/globals.css index f278a06..ccb8a67 100644 --- a/app/globals.css +++ b/app/globals.css @@ -212,4 +212,10 @@ animation-duration: 0.01ms !important; transition-duration: 0.01ms !important; } -} \ No newline at end of file +} +/* iOS zoomt beim Fokussieren in Felder mit < 16px Schrift. Auf Touch-Geräten daher mindestens 16px. */ +@media (pointer: coarse) { + input:not([type="checkbox"], [type="radio"], [type="file"]), select, textarea { + font-size: max(16px, 1em); + } +} diff --git a/app/layout.tsx b/app/layout.tsx index f44301c..e79cabb 100644 --- a/app/layout.tsx +++ b/app/layout.tsx @@ -1,4 +1,4 @@ -import type { Metadata } from "next"; +import type { Metadata, Viewport } from "next"; import { Inter, JetBrains_Mono } from "next/font/google"; import { ThemeProvider } from "@/components/theme-provider"; import "./globals.css"; @@ -15,13 +15,29 @@ const jetbrainsMono = JetBrains_Mono({ export const metadata: Metadata = { title: "Since3 Portal", - description: "Generated by create next app", + description: "Kundenportal von Since3: Status, Rechnungen, Dokumente und Zugangsdaten.", + applicationName: "Since3 Portal", + appleWebApp: { + capable: true, + title: "Since3", + statusBarStyle: "default", + }, + formatDetection: { + telephone: false, + }, +}; + +export const viewport: Viewport = { + themeColor: [ + { media: "(prefers-color-scheme: light)", color: "#fcfcfc" }, + { media: "(prefers-color-scheme: dark)", color: "#020202" }, + ], }; export default function RootLayout({ children }: LayoutProps<"/">) { return ( diff --git a/app/manifest.ts b/app/manifest.ts new file mode 100644 index 0000000..2afbb7b --- /dev/null +++ b/app/manifest.ts @@ -0,0 +1,36 @@ +import type { MetadataRoute } from "next"; + +export default function manifest(): MetadataRoute.Manifest { + return { + id: "/", + name: "Since3 Portal", + short_name: "Since3", + description: "Kundenportal von Since3: Status, Rechnungen, Dokumente und Zugangsdaten.", + lang: "de", + start_url: "/", + scope: "/", + display: "standalone", + background_color: "#020202", + theme_color: "#020202", + icons: [ + { + src: "/icons/icon-192.png", + sizes: "192x192", + type: "image/png", + purpose: "any", + }, + { + src: "/icons/icon-512.png", + sizes: "512x512", + type: "image/png", + purpose: "any", + }, + { + src: "/icons/icon-maskable-512.png", + sizes: "512x512", + type: "image/png", + purpose: "maskable", + }, + ], + }; +} diff --git a/app/page.tsx b/app/page.tsx index 5dc0188..6959a2a 100644 --- a/app/page.tsx +++ b/app/page.tsx @@ -1,5 +1,11 @@ +import { redirect } from "next/navigation"; +import { getProfile } from "@/lib/supabase/dal"; import LoginPageView from "@/modules/loginPage/ui/views/login-view"; -export default function Home() { +export default async function Home() { + // Installierte App startet auf "/": mit gültiger Session direkt ins Dashboard. + const profile = await getProfile(); + if (profile) redirect(profile.role === "admin" ? "/admin/dashboard" : "/client/dashboard"); + return ; } diff --git a/app/terms/page.tsx b/app/terms/page.tsx index a2711f2..ce247dc 100644 --- a/app/terms/page.tsx +++ b/app/terms/page.tsx @@ -1,6 +1,6 @@ const TermsPage = () => { return ( -
+

Nutzungsbedingungen

TODO: Nutzungsbedingungen einfügen. diff --git a/components/ui/dialog.tsx b/components/ui/dialog.tsx index 5cadf3f..03c0a8a 100644 --- a/components/ui/dialog.tsx +++ b/components/ui/dialog.tsx @@ -53,7 +53,7 @@ function DialogContent({ -

+
{(["generate", "manual"] as const).map((value) => (