Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
bbf16a9
add light and dark mode toggle to home page
kruulik Feb 19, 2026
801c22b
closer match to chakra styles
kruulik Feb 19, 2026
73f564d
Merge branch 'main' into karolis-darkmode
kruulik Feb 19, 2026
ac2c5e6
update changelog
kruulik Feb 19, 2026
bb2f391
Update clients/fidesui/src/hooks/useThemeMode.tsx
kruulik Feb 19, 2026
f96124f
Update clients/admin-ui/src/home/HomeContainer.tsx
kruulik Feb 19, 2026
b82df1d
wrap localstore in try catch
kruulik Feb 19, 2026
0a87e0f
scope height constraints to admin-ui only
kruulik Feb 19, 2026
68bc0f5
lint
kruulik Feb 19, 2026
ff98584
cleanup unwanted change
kruulik Feb 19, 2026
20411fa
reduce changes
kruulik Feb 19, 2026
2316cb6
undo changelog
kruulik Feb 19, 2026
44cb409
add changelog
kruulik Feb 19, 2026
a98d963
Merge branch 'main' into karolis-darkmode
kruulik Feb 19, 2026
399dd0f
simplify useThemeMode
kruulik Feb 20, 2026
044267a
Merge branch 'karolis-darkmode' of https://github.com/ethyca/fides in…
kruulik Feb 20, 2026
09666a4
Merge branch 'main' into karolis-darkmode
kruulik Feb 20, 2026
dce89e0
lint fix
kruulik Feb 20, 2026
9714cac
Merge branch 'karolis-darkmode' of https://github.com/ethyca/fides in…
kruulik Feb 20, 2026
c1756c3
Merge branch 'main' into karolis-darkmode
kruulik Feb 20, 2026
999c068
update flex
kruulik Feb 20, 2026
1ac3f6a
remove redundant spreads
kruulik Feb 20, 2026
22c1f5b
remove orphaned code
kruulik Feb 20, 2026
4409ecc
clean up and simplify
kruulik Feb 20, 2026
809d01a
switch inline styles for tailwind
kruulik Feb 20, 2026
fded087
set to locked by default
kruulik Feb 23, 2026
6e71545
Merge branch 'main' into karolis-darkmode
kruulik Feb 23, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions changelog/ENG-2726-implement-dark-mode.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
type: Added
description: Adds an (alpha) light/dark mode capability to the Admin UI Home page
pr: 7430
labels: []
26 changes: 26 additions & 0 deletions clients/admin-ui/src/features/common/ThemeModeToggle.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import type { ThemeMode } from "fidesui";
import { Icons, Segmented, useThemeMode } from "fidesui";

// NOTE: This button is temporary, only for testing in dev.

export const ThemeModeSegmented = () => {
const { mode, setMode } = useThemeMode();

return (
<Segmented
size="small"
value={mode}
onChange={(value) => setMode(value as ThemeMode)}
options={[
{
label: <Icons.Light size={14} />,
value: "light",
},
{
label: <Icons.Asleep size={14} />,
value: "dark",
},
]}
/>
);
};
7 changes: 7 additions & 0 deletions clients/admin-ui/src/flags.json
Original file line number Diff line number Diff line change
Expand Up @@ -69,5 +69,12 @@
"development": true,
"test": false,
"production": false
},
"alphaDarkMode": {
"label": "Alpha light and dark theme",
"description": "Enable switching themes on Home page",
"development": true,
"test": false,
"production": false
}
}
32 changes: 19 additions & 13 deletions clients/admin-ui/src/home/HomeBanner.tsx
Original file line number Diff line number Diff line change
@@ -1,27 +1,35 @@
import { ChakraFlex as Flex, ChakraText as Text } from "fidesui";
import { Flex, Text, Title, useThemeMode } from "fidesui";
import palette from "fidesui/src/palette/palette.module.scss";
import * as React from "react";

import { useFeatures } from "~/features/common/features";

const HomeBanner = () => {
const { systemsCount } = useFeatures();
const { resolvedMode } = useThemeMode();

// Read the background color directly from the theme config so it always
// matches the applied theme regardless of how Ant resolves CSS variables.
// Once we're using ant Layout globally, we won't need to hard-code the colors.
const bgColor =
resolvedMode === "dark"
? palette.FIDESUI_BG_MINOS
: palette.FIDESUI_CORINTH;

const hasSystems = systemsCount > 0;

return (
<Flex background={palette.FIDESUI_CORINTH}>
<Flex flexDir="column" maxWidth="600px" padding="10" paddingBottom="16">
<Flex style={{ background: bgColor }}>
<Flex vertical className="max-w-[600px] p-10 pb-16">
{hasSystems && (
<>
<Text fontSize="3xl" fontWeight="semibold">
Welcome back!
</Text>
<Text marginTop="1" fontSize="lg" fontWeight="semibold">
<Title level={1}>Welcome back!</Title>
<Text strong size="lg" className="mt-1 block">
{`${systemsCount} system${
systemsCount > 1 ? "s" : ""
} currently under management`}
</Text>
<Text marginTop="1" fontSize="sm">
<Text className="mt-1 block">
{`Fides is currently managing privacy for ${systemsCount} system${
systemsCount > 1 ? "s" : ""
}. From here you can continue adding and managing systems, process privacy requests or generate reports for your privacy compliance requirements.`}
Expand All @@ -30,13 +38,11 @@ const HomeBanner = () => {
)}
{!hasSystems && (
<>
<Text fontSize="3xl" fontWeight="semibold">
Welcome to Fides!
</Text>
<Text marginTop="1" fontSize="lg" fontWeight="semibold">
<Title level={1}>Welcome to Fides!</Title>
<Text strong size="lg" className="mt-1 block">
Start your privacy engineering journey today
</Text>
<Text marginTop="1" fontSize="sm">
<Text className="mt-1 block">
Step one in setting up your privacy engineering platform is adding
the systems you need to manage. Use the links below to add and
configure systems within Fides for data mapping and privacy
Expand Down
68 changes: 59 additions & 9 deletions clients/admin-ui/src/home/HomeContainer.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,68 @@
import { ChakraFlex as Flex } from "fidesui";
import {
ConfigProvider,
darkAntTheme,
defaultAntTheme,
Flex,
ThemeModeProvider,
useThemeMode,
} from "fidesui";
import palette from "fidesui/src/palette/palette.module.scss";
import * as React from "react";

import { useFlags } from "~/features/common/features";
import Layout from "~/features/common/Layout";
import { ThemeModeSegmented } from "~/features/common/ThemeModeToggle";

import HomeBanner from "./HomeBanner";
import HomeContent from "./HomeContent";

const HomeContainer = () => (
<Layout title="Home" padded={false}>
<Flex direction="column" gap={10} pb={6}>
<HomeBanner />
<HomeContent />
</Flex>
</Layout>
);
const HomeContainerInner = () => {
const { resolvedMode } = useThemeMode();
const {
flags: { alphaDarkMode },
} = useFlags();

const activeTheme = resolvedMode === "dark" ? darkAntTheme : defaultAntTheme;
const bgColor =
resolvedMode === "dark"
? palette.FIDESUI_BG_MINOS
: palette.FIDESUI_FULL_WHITE;

return (
<ConfigProvider theme={activeTheme}>
{/* this wrapping div can be removed once global theming is applied */}
<div className="min-h-full w-full" style={{ backgroundColor: bgColor }}>
<Layout title="Home" padded={false}>
<Flex vertical gap={40} className="pb-6">
{/* NOTE: temporary button placement for testing */}
{alphaDarkMode && (
<Flex className="absolute pl-2 pt-2">
<ThemeModeSegmented />
</Flex>
)}

<HomeBanner />
<HomeContent />
</Flex>
</Layout>
</div>
</ConfigProvider>
);
};

const HomeContainer = () => {
const {
flags: { alphaDarkMode },
} = useFlags();
return (
<ThemeModeProvider
defaultMode="light"
locked={!alphaDarkMode}
wrapperStyle={{ width: "100%" }}
>
<HomeContainerInner />
</ThemeModeProvider>
Comment on lines +58 to +64
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The theme will only ever be applied to the child contents of this wrapper. This is a pattern we could use elsewhere to start adding theming in sections, without being blocked by a global migration from Chakra to Ant.

);
};

export default HomeContainer;
24 changes: 13 additions & 11 deletions clients/admin-ui/src/home/HomeContent.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { ChakraFlex as Flex, ChakraSimpleGrid as SimpleGrid } from "fidesui";
import { Col, Flex, Row } from "fidesui";
import NextLink from "next/link";
import * as React from "react";
import { useMemo } from "react";
Expand Down Expand Up @@ -27,20 +27,22 @@ const HomeContent = () => {
);

return (
<Flex paddingX={10} data-testid="home-content">
<SimpleGrid columns={{ md: 2, xl: 3 }} spacing="24px">
<Flex className="px-10" data-testid="home-content">
<Row gutter={[24, 24]} className="w-full">
{list
.sort((a, b) => (a.sortOrder > b.sortOrder ? 1 : -1))
.map((item) => (
<NextLink href={item.href} key={item.key} className="flex">
<CalloutNavCard
title={item.name}
description={item.description}
color={item.color}
/>
</NextLink>
<Col key={item.key} xs={24} md={12} xl={8}>
<NextLink href={item.href} className="flex h-full">
<CalloutNavCard
title={item.name}
description={item.description}
color={item.color}
/>
</NextLink>
</Col>
))}
</SimpleGrid>
</Row>
</Flex>
);
};
Expand Down
6 changes: 3 additions & 3 deletions clients/admin-ui/src/home/HomeLayout.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { ChakraFlex as Flex } from "fidesui";
import { Flex } from "fidesui";
import Head from "next/head";
import * as React from "react";
import { ReactNode } from "react";
Expand All @@ -9,13 +9,13 @@ type HomeLayoutProps = {
};

const HomeLayout = ({ children, title }: HomeLayoutProps) => (
<Flex data-testid={title} direction="column" height="100%">
<Flex vertical data-testid={title} className="h-full">
<Head>
<title>Fides Admin UI - {title}</title>
<meta name="description" content="Privacy Engineering Platform" />
<link rel="icon" href="/favicon.ico" />
</Head>
<Flex as="main" flexDirection="column" gap={10}>
<Flex vertical gap={40} component="main">
{children}
</Flex>
</Flex>
Expand Down
1 change: 1 addition & 0 deletions clients/admin-ui/tailwind.config.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/** @type {import('tailwindcss').Config} */
module.exports = {
darkMode: ["selector", '[data-theme="dark"]'],
content: [
"./src/**/*.{js,ts,jsx,tsx,mdx}",
"../fidesui/src/components/**/*.{js,ts,jsx,tsx,mdx}",
Expand Down
31 changes: 31 additions & 0 deletions clients/fidesui/src/ant-theme/dark-theme.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { theme, ThemeConfig } from "antd";

import palette from "../palette/palette.module.scss";
import { defaultAntTheme } from "./default-theme";

/**
* Dark mode theme for Ant Design components.
* Uses Ant Design's built-in darkAlgorithm for automatic dark color generation,
* with custom overrides to match the Fides brand palette.
*/
export const darkAntTheme: ThemeConfig = {
...defaultAntTheme,
algorithm: theme.darkAlgorithm,
cssVar: true,
token: {
...defaultAntTheme.token,
colorBgBase: palette.FIDESUI_BG_MINOS,
colorTextBase: palette.FIDESUI_CORINTH,
colorText: palette.FIDESUI_CORINTH,
colorTextHeading: palette.FIDESUI_CORINTH,
colorPrimary: palette.FIDESUI_CORINTH,
colorBgContainer: palette.FIDESUI_BG_MINOS,
colorBorder: "#3a3a3a",
},
components: {
...defaultAntTheme.components,
Layout: {
bodyBg: palette.FIDESUI_BG_MINOS,
},
},
};
1 change: 1 addition & 0 deletions clients/fidesui/src/ant-theme/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// Main exports for Ant Design theme system
export { darkAntTheme } from "./dark-theme";
export { createDefaultAntTheme, defaultAntTheme } from "./default-theme";
export type { ThemeConfig } from "antd/es";
2 changes: 2 additions & 0 deletions clients/fidesui/src/hooks/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
export type { UseFormModalOptions } from "./useFormModal";
export { useFormModal } from "./useFormModal";
export type { ThemeMode, ThemeModeProviderProps } from "./useThemeMode";
export { ThemeModeProvider, useThemeMode } from "./useThemeMode";
Loading
Loading