add branding logo component

This commit is contained in:
miloschwartz 2025-07-15 16:24:16 -07:00
parent e99905e3c9
commit 19d54778f5
No known key found for this signature in database
5 changed files with 97 additions and 61 deletions

View file

@ -69,7 +69,13 @@ async function copyInDomains() {
} else { } else {
await trx await trx
.insert(domains) .insert(domains)
.values({ domainId, baseDomain, configManaged: true, type: "wildcard" }) .values({
domainId,
baseDomain,
configManaged: true,
type: "wildcard",
verified: true
})
.execute(); .execute();
} }
} }

View file

@ -210,18 +210,17 @@ export default function DomainsTable({ domains }: Props) {
: t("restart", { fallback: "Restart" })} : t("restart", { fallback: "Restart" })}
</Button> </Button>
)} )}
{!domain.configManaged && ( <Button
<Button variant="secondary"
variant="secondary" size="sm"
size="sm" disabled={domain.configManaged}
onClick={() => { onClick={() => {
setSelectedDomain(domain); setSelectedDomain(domain);
setIsDeleteModalOpen(true); setIsDeleteModalOpen(true);
}} }}
> >
{t("delete")} {t("delete")}
</Button> </Button>
)}
</div> </div>
); );
} }

View file

@ -14,6 +14,7 @@ import { useRouter } from "next/navigation";
import { useEffect } from "react"; import { useEffect } from "react";
import Image from "next/image"; import Image from "next/image";
import { cleanRedirect } from "@app/lib/cleanRedirect"; import { cleanRedirect } from "@app/lib/cleanRedirect";
import BrandingLogo from "@app/components/BrandingLogo";
import { useTranslations } from "next-intl"; import { useTranslations } from "next-intl";
type DashboardLoginFormProps = { type DashboardLoginFormProps = {
@ -26,42 +27,24 @@ export default function DashboardLoginForm({
idps idps
}: DashboardLoginFormProps) { }: DashboardLoginFormProps) {
const router = useRouter(); const router = useRouter();
// const api = createApiClient(useEnvContext()); const { env } = useEnvContext();
//
// useEffect(() => {
// const logout = async () => {
// try {
// await api.post("/auth/logout");
// console.log("user logged out");
// } catch (e) {}
// };
//
// logout();
// });
const t = useTranslations(); const t = useTranslations();
function getSubtitle() {
return t("loginStart");
}
return ( return (
<Card className="w-full max-w-md"> <Card className="shadow-md w-full max-w-md">
<CardHeader> <CardHeader className="border-b">
<div className="flex flex-row items-center justify-center"> <div className="flex flex-row items-center justify-center">
<Image <BrandingLogo height={58} width={175} />
src={`/logo/pangolin_orange.svg`}
alt={t('pangolinLogoAlt')}
width={100}
height={100}
/>
</div> </div>
<div className="text-center space-y-1"> <div className="text-center space-y-1 pt-3">
<h1 className="text-2xl font-bold mt-1"> <p className="text-muted-foreground">{getSubtitle()}</p>
{t('welcome')}
</h1>
<p className="text-sm text-muted-foreground">
{t('loginStart')}
</p>
</div> </div>
</CardHeader> </CardHeader>
<CardContent> <CardContent className="pt-6">
<LoginForm <LoginForm
redirect={redirect} redirect={redirect}
idps={idps} idps={idps}

View file

@ -32,6 +32,7 @@ import { useEnvContext } from "@app/hooks/useEnvContext";
import Image from "next/image"; import Image from "next/image";
import { cleanRedirect } from "@app/lib/cleanRedirect"; import { cleanRedirect } from "@app/lib/cleanRedirect";
import { useTranslations } from "next-intl"; import { useTranslations } from "next-intl";
import BrandingLogo from "@app/components/BrandingLogo";
type SignupFormProps = { type SignupFormProps = {
redirect?: string; redirect?: string;
@ -88,9 +89,7 @@ export default function SignupForm({
}) })
.catch((e) => { .catch((e) => {
console.error(e); console.error(e);
setError( setError(formatAxiosError(e, t("signupError")));
formatAxiosError(e, t('signupError'))
);
}); });
if (res && res.status === 200) { if (res && res.status === 200) {
@ -117,24 +116,21 @@ export default function SignupForm({
setLoading(false); setLoading(false);
} }
function getSubtitle() {
return t("authCreateAccount");
}
return ( return (
<Card className="w-full max-w-md shadow-md"> <Card className="w-full max-w-md shadow-md">
<CardHeader className="border-b"> <CardHeader className="border-b">
<div className="flex flex-row items-center justify-center"> <div className="flex flex-row items-center justify-center">
<Image <BrandingLogo
src={`/logo/pangolin_orange.svg`} height={58}
alt={t('pangolinLogoAlt')} width={175}
width="100"
height="100"
/> />
</div> </div>
<div className="text-center space-y-1"> <div className="text-center space-y-1 pt-3">
<h1 className="text-2xl font-bold mt-1"> <p className="text-muted-foreground">{getSubtitle()}</p>
{t('welcome')}
</h1>
<p className="text-sm text-muted-foreground">
{t('authCreateAccount')}
</p>
</div> </div>
</CardHeader> </CardHeader>
<CardContent className="pt-6"> <CardContent className="pt-6">
@ -148,7 +144,7 @@ export default function SignupForm({
name="email" name="email"
render={({ field }) => ( render={({ field }) => (
<FormItem> <FormItem>
<FormLabel>{t('email')}</FormLabel> <FormLabel>{t("email")}</FormLabel>
<FormControl> <FormControl>
<Input {...field} /> <Input {...field} />
</FormControl> </FormControl>
@ -161,7 +157,7 @@ export default function SignupForm({
name="password" name="password"
render={({ field }) => ( render={({ field }) => (
<FormItem> <FormItem>
<FormLabel>{t('password')}</FormLabel> <FormLabel>{t("password")}</FormLabel>
<FormControl> <FormControl>
<Input type="password" {...field} /> <Input type="password" {...field} />
</FormControl> </FormControl>
@ -174,7 +170,9 @@ export default function SignupForm({
name="confirmPassword" name="confirmPassword"
render={({ field }) => ( render={({ field }) => (
<FormItem> <FormItem>
<FormLabel>{t('confirmPassword')}</FormLabel> <FormLabel>
{t("confirmPassword")}
</FormLabel>
<FormControl> <FormControl>
<Input type="password" {...field} /> <Input type="password" {...field} />
</FormControl> </FormControl>
@ -190,7 +188,7 @@ export default function SignupForm({
)} )}
<Button type="submit" className="w-full"> <Button type="submit" className="w-full">
{t('createAccount')} {t("createAccount")}
</Button> </Button>
</form> </form>
</Form> </Form>

View file

@ -0,0 +1,50 @@
"use client";
import { useEnvContext } from "@app/hooks/useEnvContext";
import { useTheme } from "next-themes";
import Image from "next/image";
import { useEffect, useState } from "react";
type BrandingLogoProps = {
width: number;
height: number;
};
export default function BrandingLogo(props: BrandingLogoProps) {
const { env } = useEnvContext();
const { theme } = useTheme();
const [path, setPath] = useState<string>(""); // Default logo path
useEffect(() => {
function getPath() {
let lightOrDark = theme;
if (theme === "system" || !theme) {
lightOrDark = window.matchMedia("(prefers-color-scheme: dark)")
.matches
? "dark"
: "light";
}
if (lightOrDark === "light") {
return "/logo/word_mark_black.png";
}
return "/logo/word_mark_white.png";
}
const path = getPath();
setPath(path);
}, [theme, env]);
return (
path && (
<Image
src={path}
alt="Logo"
width={props.width}
height={props.height}
/>
)
);
}