diff --git a/apps/trust/index.html b/apps/trust/index.html
index 0a1c5e715..743056332 100644
--- a/apps/trust/index.html
+++ b/apps/trust/index.html
@@ -4,7 +4,7 @@
-
+
+
+
diff --git a/apps/trust/src/components/OrganizationSidebar.tsx b/apps/trust/src/components/OrganizationSidebar.tsx
index 105d7577c..898142826 100644
--- a/apps/trust/src/components/OrganizationSidebar.tsx
+++ b/apps/trust/src/components/OrganizationSidebar.tsx
@@ -1,4 +1,5 @@
import { formatError } from "@probo/helpers";
+import { useSystemTheme } from "@probo/hooks";
import { useTranslate } from "@probo/i18n";
import {
Button,
@@ -36,6 +37,9 @@ export function OrganizationSidebar({
const { __ } = useTranslate();
const isAuthenticated = !!use(Viewer);
const { toast } = useToast();
+ const theme = useSystemTheme();
+
+ const logoFileUrl = theme === "dark" ? (trustCenter?.darkLogoFileUrl ?? trustCenter?.logoFileUrl) : trustCenter?.logoFileUrl;
const [requestAllAccesses, isRequestingAccess]
= useMutation(
@@ -77,11 +81,11 @@ export function OrganizationSidebar({
return (
- {trustCenter.logoFileUrl
+ {logoFileUrl
? (
)
diff --git a/apps/trust/src/layouts/MainLayout.tsx b/apps/trust/src/layouts/MainLayout.tsx
index fbef01eda..e0d89d1d9 100644
--- a/apps/trust/src/layouts/MainLayout.tsx
+++ b/apps/trust/src/layouts/MainLayout.tsx
@@ -1,3 +1,4 @@
+import { useFavicon, useSystemTheme } from "@probo/hooks";
import { useTranslate } from "@probo/i18n";
import { Logo, TabLink, Tabs } from "@probo/ui";
import { type PreloadedQuery, usePreloadedQuery } from "react-relay";
@@ -19,9 +20,14 @@ export function MainLayout(props: Props) {
const data = usePreloadedQuery(currentTrustGraphQuery, props.queryRef);
const trustCenter = data.currentTrustCenter;
+ const theme = useSystemTheme();
+
+ useFavicon(theme === "dark" ? (trustCenter?.darkLogoFileUrl ?? trustCenter?.logoFileUrl) : trustCenter?.logoFileUrl);
+
if (!trustCenter) {
return null;
}
+
const showNDADialog
= trustCenter.isViewerMember
&& !trustCenter.hasAcceptedNonDisclosureAgreement
diff --git a/packages/hooks/src/index.ts b/packages/hooks/src/index.ts
index 61af4f0f3..7207bbc14 100644
--- a/packages/hooks/src/index.ts
+++ b/packages/hooks/src/index.ts
@@ -5,3 +5,5 @@ export { useList } from "./useList";
export { useStateWithRef } from "./useStateWithRef";
export { useCleanup } from "./useCleanup";
export { useCopy } from "./useCopy";
+export { useFavicon } from "./useFavicon";
+export { useSystemTheme } from "./useSystemTheme";
diff --git a/packages/hooks/src/useFavicon.ts b/packages/hooks/src/useFavicon.ts
new file mode 100644
index 000000000..584466a12
--- /dev/null
+++ b/packages/hooks/src/useFavicon.ts
@@ -0,0 +1,25 @@
+import { useEffect } from "react";
+
+export function useFavicon(faviconUrl?: string | null) {
+ useEffect(() => {
+ if (!faviconUrl) return;
+
+ let favicon: HTMLLinkElement;
+ const existingFavicon = document.getElementById("favicon") as (HTMLLinkElement | null);
+
+ if (existingFavicon) {
+ favicon = existingFavicon
+ favicon.href = faviconUrl;
+ } else {
+ favicon = document.createElement("link");
+ favicon.id = "favicon";
+ favicon.rel = "icon";
+ favicon.href = faviconUrl;
+ document.head.appendChild(favicon);
+ }
+
+ return () => {
+ favicon.href = "/favicons/favicon.ico";
+ }
+ });
+}
\ No newline at end of file
diff --git a/packages/hooks/src/useSystemTheme.ts b/packages/hooks/src/useSystemTheme.ts
new file mode 100644
index 000000000..0c478ae63
--- /dev/null
+++ b/packages/hooks/src/useSystemTheme.ts
@@ -0,0 +1,31 @@
+import { useEffect, useState } from "react";
+
+export function useSystemTheme(): "light" | "dark" {
+ const getSystemTheme = () => {
+ if (typeof window !== "undefined" && window.matchMedia) {
+ return window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light" as const;
+ }
+ return "light" as const;
+ };
+
+ const [theme, setTheme] = useState<"light" | "dark">(getSystemTheme());
+
+ useEffect(() => {
+ if (typeof window === "undefined" || !window.matchMedia) {
+ return;
+ }
+
+ const mediaQuery = window.matchMedia("(prefers-color-scheme: dark)");
+ const handleChange = (event: MediaQueryListEvent) => {
+ setTheme(event.matches ? "dark" : "light");
+ };
+
+ mediaQuery.addEventListener("change", handleChange);
+
+ return () => {
+ mediaQuery.removeEventListener("change", handleChange);
+ };
+ }, []);
+
+ return theme;
+};
diff --git a/pkg/server/api/trust/v1/v1_resolver.go b/pkg/server/api/trust/v1/v1_resolver.go
index e769d4efb..e8c3eb493 100644
--- a/pkg/server/api/trust/v1/v1_resolver.go
+++ b/pkg/server/api/trust/v1/v1_resolver.go
@@ -882,7 +882,7 @@ func (r *trustCenterResolver) LogoFileURL(ctx context.Context, obj *types.TrustC
func (r *trustCenterResolver) DarkLogoFileURL(ctx context.Context, obj *types.TrustCenter) (*string, error) {
trustService := r.TrustService(ctx, obj.ID.TenantID())
- return trustService.TrustCenters.GenerateLogoURL(ctx, obj.ID, 1*time.Hour)
+ return trustService.TrustCenters.GenerateDarkLogoURL(ctx, obj.ID, 1*time.Hour)
}
// NdaFileURL is the resolver for the ndaFileUrl field.
diff --git a/pkg/trust/trust_center_service.go b/pkg/trust/trust_center_service.go
index 1c5f3871a..e421335dc 100644
--- a/pkg/trust/trust_center_service.go
+++ b/pkg/trust/trust_center_service.go
@@ -201,7 +201,7 @@ func (s TrustCenterService) GenerateDarkLogoURL(
return nil, err
}
- if compliancePage.LogoFileID == nil {
+ if compliancePage.DarkLogoFileID == nil {
return nil, nil
}