org branding

This commit is contained in:
peintnermax
2024-04-01 10:00:31 +02:00
parent ddc33d2b9e
commit 8f836557c3
7 changed files with 175 additions and 158 deletions

View File

@@ -1,38 +0,0 @@
import { BrandingSettings } from "@zitadel/server";
import React from "react";
import { getBrandingSettings, server } from "#/lib/zitadel";
import { Logo } from "#/ui/Logo";
export default async function Layout({
children,
params,
}: {
children: React.ReactNode;
params: any;
}) {
const branding = await getBrandingSettings(server);
let partial: Partial<BrandingSettings> | undefined;
if (branding) {
partial = {
lightTheme: branding?.lightTheme,
darkTheme: branding?.darkTheme,
};
}
return (
<div className="mx-auto flex flex-col items-center space-y-4">
<div className="relative">
{branding && (
<Logo
lightSrc={branding.lightTheme?.logoUrl}
darkSrc={branding.darkTheme?.logoUrl}
height={150}
width={150}
/>
)}
</div>
<div className="w-full">{children}</div>
<div className="flex flex-row justify-between"></div>
</div>
);
}

View File

@@ -1,10 +1,14 @@
import {
getBrandingSettings,
getLegalAndSupportSettings,
getLoginSettings,
server,
} from "#/lib/zitadel";
import DynamicTheme from "#/ui/DynamicTheme";
import { SignInWithIDP } from "#/ui/SignInWithIDP";
import ThemeWrapper from "#/ui/ThemeWrapper";
import UsernameForm from "#/ui/UsernameForm";
import { BrandingSettings } from "@zitadel/server";
import {
GetActiveIdentityProvidersResponse,
IdentityProvider,
@@ -46,26 +50,30 @@ export default async function Page({
? `https://${process.env.VERCEL_URL}`
: "http://localhost:3000";
const branding = await getBrandingSettings(server, organization);
return (
<div className="flex flex-col items-center space-y-4">
<h1>Welcome back!</h1>
<p className="ztdl-p">Enter your login data.</p>
<DynamicTheme branding={branding}>
<div className="flex flex-col items-center space-y-4">
<h1>Welcome back!</h1>
<p className="ztdl-p">Enter your login data.</p>
<UsernameForm
loginSettings={loginSettings}
loginName={loginName}
authRequestId={authRequestId}
organization={organization}
submit={submit}
/>
{legal && identityProviders && process.env.ZITADEL_API_URL && (
<SignInWithIDP
host={host}
identityProviders={identityProviders}
<UsernameForm
loginSettings={loginSettings}
loginName={loginName}
authRequestId={authRequestId}
></SignInWithIDP>
)}
</div>
organization={organization}
submit={submit}
/>
{legal && identityProviders && process.env.ZITADEL_API_URL && (
<SignInWithIDP
host={host}
identityProviders={identityProviders}
authRequestId={authRequestId}
></SignInWithIDP>
)}
</div>
</DynamicTheme>
);
}

View File

@@ -1,5 +1,6 @@
import { getSession, server } from "#/lib/zitadel";
import { getBrandingSettings, getSession, server } from "#/lib/zitadel";
import Alert from "#/ui/Alert";
import DynamicTheme from "#/ui/DynamicTheme";
import LoginPasskey from "#/ui/LoginPasskey";
import UserAvatar from "#/ui/UserAvatar";
import { getMostRecentCookieWithLoginname } from "#/utils/cookies";
@@ -29,33 +30,37 @@ export default async function Page({
});
}
const branding = await getBrandingSettings(server, organization);
return (
<div className="flex flex-col items-center space-y-4">
<h1>{title}</h1>
<DynamicTheme branding={branding}>
<div className="flex flex-col items-center space-y-4">
<h1>{title}</h1>
{sessionFactors && (
<UserAvatar
loginName={loginName ?? sessionFactors.factors?.user?.loginName}
displayName={sessionFactors.factors?.user?.displayName}
showDropdown
></UserAvatar>
)}
<p className="ztdl-p mb-6 block">{description}</p>
{sessionFactors && (
<UserAvatar
loginName={loginName ?? sessionFactors.factors?.user?.loginName}
displayName={sessionFactors.factors?.user?.displayName}
showDropdown
></UserAvatar>
)}
<p className="ztdl-p mb-6 block">{description}</p>
{!sessionFactors && <div className="py-4"></div>}
{!sessionFactors && <div className="py-4"></div>}
{!loginName && (
<Alert>Provide your active session as loginName param</Alert>
)}
{!loginName && (
<Alert>Provide your active session as loginName param</Alert>
)}
{loginName && (
<LoginPasskey
loginName={loginName}
authRequestId={authRequestId}
altPassword={altPassword === "true"}
organization={organization}
/>
)}
</div>
{loginName && (
<LoginPasskey
loginName={loginName}
authRequestId={authRequestId}
altPassword={altPassword === "true"}
organization={organization}
/>
)}
</div>
</DynamicTheme>
);
}

View File

@@ -1,5 +1,6 @@
import { getSession, server } from "#/lib/zitadel";
import { getBrandingSettings, getSession, server } from "#/lib/zitadel";
import Alert from "#/ui/Alert";
import DynamicTheme from "#/ui/DynamicTheme";
import PasswordForm from "#/ui/PasswordForm";
import UserAvatar from "#/ui/UserAvatar";
import { getMostRecentCookieWithLoginname } from "#/utils/cookies";
@@ -26,35 +27,39 @@ export default async function Page({
});
}
const branding = await getBrandingSettings(server, organization);
return (
<div className="flex flex-col items-center space-y-4">
<h1>{sessionFactors?.factors?.user?.displayName ?? "Password"}</h1>
<p className="ztdl-p mb-6 block">Enter your password.</p>
<DynamicTheme branding={branding}>
<div className="flex flex-col items-center space-y-4">
<h1>{sessionFactors?.factors?.user?.displayName ?? "Password"}</h1>
<p className="ztdl-p mb-6 block">Enter your password.</p>
{!sessionFactors && (
<div className="py-4">
<Alert>
Could not get the context of the user. Make sure to enter the
username first or provide a loginName as searchParam.
</Alert>
</div>
)}
{!sessionFactors && (
<div className="py-4">
<Alert>
Could not get the context of the user. Make sure to enter the
username first or provide a loginName as searchParam.
</Alert>
</div>
)}
{sessionFactors && (
<UserAvatar
loginName={loginName ?? sessionFactors.factors?.user?.loginName}
displayName={sessionFactors.factors?.user?.displayName}
showDropdown
></UserAvatar>
)}
{sessionFactors && (
<UserAvatar
loginName={loginName ?? sessionFactors.factors?.user?.loginName}
displayName={sessionFactors.factors?.user?.displayName}
showDropdown
></UserAvatar>
)}
<PasswordForm
loginName={loginName}
authRequestId={authRequestId}
organization={organization}
promptPasswordless={promptPasswordless === "true"}
isAlternative={alt === "true"}
/>
</div>
<PasswordForm
loginName={loginName}
authRequestId={authRequestId}
organization={organization}
promptPasswordless={promptPasswordless === "true"}
isAlternative={alt === "true"}
/>
</div>
</DynamicTheme>
);
}

View File

@@ -26,15 +26,6 @@ export default async function RootLayout({
// later only shown with dev mode enabled
const showNav = process.env.DEBUG === "true";
const branding = await getBrandingSettings(server);
let partial: Partial<BrandingSettings> | undefined;
if (branding) {
partial = {
lightTheme: branding?.lightTheme,
darkTheme: branding?.darkTheme,
};
}
let domain = process.env.ZITADEL_API_URL;
domain = domain ? domain.replace("https://", "") : "acme.com";
@@ -42,49 +33,40 @@ export default async function RootLayout({
<html lang="en" className={`${lato.className}`} suppressHydrationWarning>
<head />
<body>
<ThemeWrapper branding={partial}>
<ThemeProvider>
<LayoutProviders>
<div
className={`h-screen overflow-y-scroll bg-background-light-600 dark:bg-background-dark-600 ${
showNav
? "bg-[url('/grid-light.svg')] dark:bg-[url('/grid-dark.svg')]"
: ""
}`}
>
{showNav ? (
<GlobalNav />
) : (
<div className="absolute bottom-0 right-0 flex flex-row p-4">
<Theme />
</div>
)}
<div
className={`h-screen overflow-y-scroll bg-background-light-600 dark:bg-background-dark-600 ${
showNav
? "bg-[url('/grid-light.svg')] dark:bg-[url('/grid-dark.svg')]"
: ""
}`}
>
{showNav ? (
<GlobalNav />
) : (
<div className="absolute bottom-0 right-0 flex flex-row p-4">
<Theme />
</div>
)}
<div
className={`${
showNav ? "lg:pl-72" : ""
} pb-4 flex flex-col justify-center h-full`}
>
<div className="mx-auto max-w-[440px] space-y-8 pt-20 lg:py-8 w-full">
{showNav && (
<div className="rounded-lg bg-vc-border-gradient dark:bg-dark-vc-border-gradient p-px shadow-lg shadow-black/5 dark:shadow-black/20">
<div className="rounded-lg bg-background-light-400 dark:bg-background-dark-500">
<AddressBar domain={domain} />
</div>
</div>
)}
<div className="rounded-lg bg-vc-border-gradient dark:bg-dark-vc-border-gradient p-px shadow-lg shadow-black/5 dark:shadow-black/20 mb-10">
<div className="rounded-lg bg-background-light-400 dark:bg-background-dark-500 px-8 py-12">
{children}
</div>
</div>
<div
className={`${
showNav ? "lg:pl-72" : ""
} pb-4 flex flex-col justify-center h-full`}
>
<div className="mx-auto max-w-[440px] space-y-8 pt-20 lg:py-8 w-full">
{showNav && (
<div className="rounded-lg bg-vc-border-gradient dark:bg-dark-vc-border-gradient p-px shadow-lg shadow-black/5 dark:shadow-black/20">
<div className="rounded-lg bg-background-light-400 dark:bg-background-dark-500">
<AddressBar domain={domain} />
</div>
</div>
</div>
</LayoutProviders>
</ThemeProvider>
</ThemeWrapper>
)}
{children}
</div>
</div>
</div>
<Analytics />
</body>
</html>

View File

@@ -55,11 +55,15 @@ if (!getServers().length) {
}
export async function getBrandingSettings(
server: ZitadelServer
server: ZitadelServer,
organization?: string
): Promise<BrandingSettings | undefined> {
const settingsService = settings.getSettings(server);
return settingsService
.getBrandingSettings({}, {})
.getBrandingSettings(
{ ctx: organization ? { orgId: organization } : { instance: true } },
{}
)
.then((resp: GetBrandingSettingsResponse) => resp.settings);
}

View File

@@ -0,0 +1,51 @@
"use client";
import { BrandingSettings } from "@zitadel/server";
import React from "react";
import { Logo } from "#/ui/Logo";
import ThemeWrapper from "./ThemeWrapper";
import { LayoutProviders } from "./LayoutProviders";
import ThemeProvider from "./ThemeProvider";
export default async function DynamicTheme({
branding,
children,
}: {
children: React.ReactNode;
branding?: BrandingSettings;
}) {
let partial: Partial<BrandingSettings> | undefined;
if (branding) {
partial = {
lightTheme: branding?.lightTheme,
darkTheme: branding?.darkTheme,
};
}
return (
<ThemeWrapper branding={partial}>
<ThemeProvider>
<LayoutProviders>
<div className="rounded-lg bg-vc-border-gradient dark:bg-dark-vc-border-gradient p-px shadow-lg shadow-black/5 dark:shadow-black/20 mb-10">
<div className="rounded-lg bg-background-light-400 dark:bg-background-dark-500 px-8 py-12">
<div className="mx-auto flex flex-col items-center space-y-4">
<div className="relative">
{branding && (
<Logo
lightSrc={branding.lightTheme?.logoUrl}
darkSrc={branding.darkTheme?.logoUrl}
height={150}
width={150}
/>
)}
</div>
<div className="w-full">{children}</div>
<div className="flex flex-row justify-between"></div>
</div>
</div>
</div>
</LayoutProviders>
</ThemeProvider>
</ThemeWrapper>
);
}