diff --git a/apps/theme/app/contrast-charts/page.module.css b/apps/theme/app/contrast-charts/page.module.css
new file mode 100644
index 0000000000..059bbeb235
--- /dev/null
+++ b/apps/theme/app/contrast-charts/page.module.css
@@ -0,0 +1,4 @@
+.subHeading {
+ margin-bottom: 12px !important;
+ margin-top: 32px !important;
+}
diff --git a/apps/theme/app/contrast-charts/page.tsx b/apps/theme/app/contrast-charts/page.tsx
new file mode 100644
index 0000000000..b00c31c3ce
--- /dev/null
+++ b/apps/theme/app/contrast-charts/page.tsx
@@ -0,0 +1,27 @@
+'use client';
+import { Heading } from '@digdir/designsystemet-react';
+import { Container } from '@repo/components';
+import { ContrastChart } from '../../components/ContrastChart/ContrastChart';
+import classes from './page.module.css';
+
+export default function ContrastCharts() {
+ return (
+
+
+
+
+ Kontrastoversikt
+
+ Light mode
+
+
+
+ Dark mode
+
+
+
+
+
+
+ );
+}
diff --git a/apps/theme/components/ContrastChart/ContrastChart.module.css b/apps/theme/components/ContrastChart/ContrastChart.module.css
new file mode 100644
index 0000000000..9de6862c30
--- /dev/null
+++ b/apps/theme/components/ContrastChart/ContrastChart.module.css
@@ -0,0 +1,103 @@
+.color {
+ height: 36px;
+ display: block;
+ flex: 1 1;
+ box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.1);
+ border-radius: 2px;
+}
+
+.colors {
+ display: flex;
+ gap: 12px;
+}
+
+.table {
+ background-color: #e2e2e2;
+ margin-bottom: 100px;
+}
+
+.cell {
+ padding: 14px;
+ display: flex;
+ flex-direction: column;
+ justify-content: space-between;
+ height: 100%;
+}
+
+.tag {
+ background-color: #d23e3e;
+ color: white;
+ border-radius: 400px;
+ font-size: 13px;
+ font-weight: 500;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ padding: 3px 9px;
+}
+
+.AA {
+ background-color: green;
+ margin-left: 4px;
+}
+
+.AAA {
+ background-color: #407be9;
+}
+
+.AA18 {
+ background-color: #fbb025;
+ color: black;
+}
+
+.meta {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+}
+
+.contrast {
+ font-size: 16px;
+ font-weight: 500;
+ width: 48px;
+ text-align: center;
+}
+
+.table,
+.td,
+.th {
+ border: 4px solid var(--ds-color-neutral-background-default);
+ border-collapse: collapse;
+ background-color: var(--ds-color-neutral-surface-default);
+}
+
+.th {
+ height: 90px;
+ width: 140px;
+ padding: 16px;
+}
+
+.td {
+ height: 90px;
+ width: 140px;
+ vertical-align: top;
+}
+
+.header {
+ font-size: 16px;
+ width: 30px;
+ text-align: left;
+ display: flex;
+ flex-direction: column;
+ gap: 2px;
+ font-weight: 500;
+}
+
+.headerHex {
+ color: var(--ds-color-neutral-text-subtle);
+ font-weight: 400;
+}
+
+.contrastChart {
+ background-color: transparent;
+}
diff --git a/apps/theme/components/ContrastChart/ContrastChart.tsx b/apps/theme/components/ContrastChart/ContrastChart.tsx
new file mode 100644
index 0000000000..bf62f573ff
--- /dev/null
+++ b/apps/theme/components/ContrastChart/ContrastChart.tsx
@@ -0,0 +1,107 @@
+import {
+ type ColorInfo,
+ generateThemeForColor,
+ getColorNameFromNumber,
+ getContrastFromHex,
+} from '@/packages/cli/dist/src';
+
+import cl from 'clsx/lite';
+import classes from './ContrastChart.module.css';
+
+type ContrastChartProps = {
+ type?: 'light' | 'dark';
+};
+
+export const ContrastChart = ({ type = 'light' }: ContrastChartProps) => {
+ const theme = generateThemeForColor('#0062BA');
+ const includedColorIndexes = [1, 2, 3, 4, 5, 6, 7, 8, 12, 13];
+ const reducedLight = theme.light.filter((color) =>
+ includedColorIndexes.includes(color.number),
+ );
+ const reducedDark = theme.dark.filter((color) =>
+ includedColorIndexes.includes(color.number),
+ );
+
+ const Tag = ({
+ color1,
+ color2,
+ }: { color1: ColorInfo; color2: ColorInfo }) => {
+ const contrast = getContrastFromHex(color1.hex, color2.hex);
+ let type = 'AAA';
+
+ if (contrast < 3) {
+ type = 'FAIL';
+ } else if (contrast < 4.5) {
+ type = 'AA18';
+ } else if (contrast < 7) {
+ type = 'AA';
+ }
+
+ return {type}
;
+ };
+
+ const TdCell = ({
+ color1,
+ color2,
+ }: { color1: ColorInfo; color2: ColorInfo }) => {
+ return (
+
+
+
+
+
+ {Math.floor(getContrastFromHex(color1.hex, color2.hex) * 10) / 10}
+ :1
+
+
+
+ );
+ };
+
+ const ThCell = ({ color }: { color: ColorInfo }) => {
+ return (
+
+
+ {getColorNameFromNumber(color.number)}
+ {color.hex}
+
+ |
+ );
+ };
+
+ const reducedColors = type === 'light' ? reducedLight : reducedDark;
+ const themeColors = type === 'light' ? theme.light : theme.dark;
+
+ return (
+
+
+
+ |
+ {reducedColors.map((color, index) => (
+
+ ))}
+
+
+ {includedColorIndexes.map((number, index) => (
+
+
+ {reducedColors.map((color, index) => (
+
+
+ |
+ ))}
+
+ ))}
+
+
+ );
+};
diff --git a/packages/cli/src/colors/theme.ts b/packages/cli/src/colors/theme.ts
index 9a55e87e8e..4576fee6be 100644
--- a/packages/cli/src/colors/theme.ts
+++ b/packages/cli/src/colors/theme.ts
@@ -68,18 +68,18 @@ const generateThemeColor = (color: CssColor, colorScheme: ColorMode, contrastMod
leoBackgroundColor.colorKeys[0],
);
- const textSubLightLightness = contrastMode === 'aa' ? 42 : 30;
+ const textSubLightLightness = contrastMode === 'aa' ? 41 : 30;
const textDefLightLightness = contrastMode === 'aa' ? 18 : 12;
- const textSubDarkLightness = contrastMode === 'aa' ? 67 : 80;
+ const textSubDarkLightness = contrastMode === 'aa' ? 66 : 80;
const textDefDarkLightness = contrastMode === 'aa' ? 90 : 94;
let lightnessScale: number[] = [];
if (colorScheme === 'light') {
- lightnessScale = [100, 96, 90, 84, 78, 76, 54, 33, textSubLightLightness, textDefLightLightness];
+ lightnessScale = [100, 96, 90, 84, 78, 76, 53, 41, textSubLightLightness, textDefLightLightness];
} else if (colorScheme === 'dark') {
- lightnessScale = [10, 14, 20, 26, 32, 35, 47, 77, textSubDarkLightness, textDefDarkLightness];
+ lightnessScale = [10, 14, 20, 26, 32, 35, 52, 66, textSubDarkLightness, textDefDarkLightness];
} else {
lightnessScale = [1, 6, 14, 20, 26, 58, 70, 82, 80, 95];
}