1- import { Button , Heading } from '@digdir/designsystemet-react' ;
1+ import {
2+ Button ,
3+ Heading ,
4+ Paragraph ,
5+ Switch ,
6+ } from '@digdir/designsystemet-react' ;
27import { PlusIcon } from '@navikt/aksel-icons' ;
38import { useState } from 'react' ;
49import { ColorService , useColor } from 'react-color-palette' ;
510import { useTranslation } from 'react-i18next' ;
611import { useSearchParams } from 'react-router' ;
7- import type { ColorTheme } from '~/routes/themebuilder/_utils/use-themebuilder' ;
12+ import type {
13+ ColorTheme ,
14+ SeverityColorTheme ,
15+ } from '~/routes/themebuilder/_utils/use-themebuilder' ;
816import {
917 QUERY_SEPARATOR ,
1018 useThemebuilder ,
@@ -14,8 +22,8 @@ import { ColorPane } from '../color-pane/color-pane';
1422import classes from './color-page.module.css' ;
1523
1624type ColorEditorState = {
17- activePanel : 'add-color' | 'edit-color' | 'none' ;
18- colorType : 'main' | 'neutral' | 'support' ;
25+ activePanel : 'add-color' | 'edit-color' | 'edit-severity' | ' none';
26+ colorType : 'main' | 'neutral' | 'support' | 'severity' ;
1927 index : number ;
2028 name : string ;
2129 initialName : string ;
@@ -26,7 +34,7 @@ const DEFAULT_COLOR = '#0062ba';
2634
2735export const ColorPage = ( ) => {
2836 const { t } = useTranslation ( ) ;
29- const { colors } = useThemebuilder ( ) ;
37+ const { colors, severityColors , severityEnabled } = useThemebuilder ( ) ;
3038 const [ query , setQuery ] = useSearchParams ( ) ;
3139
3240 const [ editorState , setEditorState ] = useState < ColorEditorState > ( {
@@ -63,11 +71,42 @@ export const ColorPage = () => {
6371 updatedParams . set ( type , colorArray . join ( QUERY_SEPARATOR ) ) ;
6472 } else if ( type === 'neutral' ) {
6573 updatedParams . set ( 'neutral' , hex ) ;
74+ } else if ( type === 'severity' ) {
75+ updateSeverityColorInParams ( hex , name , updatedParams ) ;
6676 }
6777
6878 setQuery ( updatedParams , { replace : true , preventScrollReset : true } ) ;
6979 } ;
7080
81+ const updateSeverityColorInParams = (
82+ hex : string ,
83+ name : string ,
84+ params : URLSearchParams ,
85+ ) => {
86+ const severityParam = params . get ( 'severity' ) || '' ;
87+ const severityArray = severityParam . split ( QUERY_SEPARATOR ) . filter ( Boolean ) ;
88+
89+ // Find the severity color and check if it's the default
90+ const defaultColor = severityColors . find ( ( sc ) => sc . name === name ) ;
91+ if ( ! defaultColor ) return ;
92+
93+ const isDefault = hex . toLowerCase ( ) === defaultColor . hex . toLowerCase ( ) ;
94+
95+ // Remove existing entry for this severity color
96+ const filtered = severityArray . filter ( ( s ) => ! s . startsWith ( `${ name } :` ) ) ;
97+
98+ // Only add if it's not the default value
99+ if ( ! isDefault ) {
100+ filtered . push ( `${ name } :${ hex } ` ) ;
101+ }
102+
103+ if ( filtered . length > 0 ) {
104+ params . set ( 'severity' , filtered . join ( QUERY_SEPARATOR ) ) ;
105+ } else {
106+ params . delete ( 'severity' ) ;
107+ }
108+ } ;
109+
71110 const openColorEditor = (
72111 colorTheme : ColorTheme ,
73112 index : number ,
@@ -105,6 +144,24 @@ export const ColorPage = () => {
105144 updateColorInParams ( DEFAULT_COLOR , newColorName , type , colorCount ) ;
106145 } ;
107146
147+ const openSeverityColorEditor = (
148+ severityColor : SeverityColorTheme ,
149+ index : number ,
150+ ) => {
151+ const hexColor = severityColor . hex ;
152+
153+ setColor ( ColorService . convert ( 'hex' , hexColor ) ) ;
154+
155+ setEditorState ( {
156+ activePanel : 'edit-severity' ,
157+ colorType : 'severity' ,
158+ index : index ,
159+ name : severityColor . name ,
160+ initialName : severityColor . name ,
161+ initialHex : hexColor ,
162+ } ) ;
163+ } ;
164+
108165 const closeEditor = ( ) => {
109166 setEditorState ( ( prev ) => ( {
110167 ...prev ,
@@ -130,6 +187,17 @@ export const ColorPage = () => {
130187 }
131188 } ;
132189
190+ const toggleSeverityColors = ( enabled : boolean ) => {
191+ const updatedParams = new URLSearchParams ( query ) ;
192+ if ( enabled ) {
193+ updatedParams . set ( 'severity-enabled' , 'true' ) ;
194+ } else {
195+ updatedParams . delete ( 'severity-enabled' ) ;
196+ updatedParams . delete ( 'severity' ) ; // Also remove any severity color overrides
197+ }
198+ setQuery ( updatedParams , { replace : true , preventScrollReset : true } ) ;
199+ } ;
200+
133201 return (
134202 < div >
135203 { editorState . activePanel === 'none' && (
@@ -194,7 +262,9 @@ export const ColorPage = () => {
194262 </ Button >
195263 ) } { ' ' }
196264 { colors . support . length >= 40 && (
197- < div className = { classes . error } > Maximum 4 support colours</ div >
265+ < div className = { classes . error } >
266+ { t ( 'themeModal.max-X-colors' , { count : 4 } ) }
267+ </ div >
198268 ) }
199269 </ div >
200270 < div className = { classes . colors } >
@@ -208,6 +278,50 @@ export const ColorPage = () => {
208278 ) ) }
209279 </ div >
210280 </ div >
281+
282+ < div className = { classes . separator } > </ div >
283+ < div className = { classes . group } >
284+ < div className = { classes . groupHeader } >
285+ < Heading data-size = '2xs' id = 'severity-colors-heading' >
286+ { t ( 'themeModal.severity-colors' ) }
287+ </ Heading >
288+ < Switch
289+ name = 'severity-colors-switch'
290+ data-size = 'sm'
291+ checked = { severityEnabled }
292+ onChange = { ( e ) => toggleSeverityColors ( e . target . checked ) }
293+ aria-labelledby = 'severity-colors-heading'
294+ aria-describedby = 'severity-colors-description'
295+ />
296+ </ div >
297+ { ! severityEnabled && (
298+ < Paragraph
299+ id = 'severity-colors-description'
300+ data-size = 'sm'
301+ style = { {
302+ marginTop : '-4px' ,
303+ marginBottom : '8px' ,
304+ color : 'var(--ds-color-neutral-text-subtle)' ,
305+ } }
306+ >
307+ { t ( 'themeModal.severity-colors-switch' ) }
308+ </ Paragraph >
309+ ) }
310+ { severityEnabled && (
311+ < div className = { classes . colors } >
312+ { severityColors . map ( ( severityColor , index ) => (
313+ < ColorInput
314+ key = { severityColor . name }
315+ color = { severityColor . hex }
316+ name = { severityColor . name }
317+ onClick = { ( ) =>
318+ openSeverityColorEditor ( severityColor , index )
319+ }
320+ />
321+ ) ) }
322+ </ div >
323+ ) }
324+ </ div >
211325 </ >
212326 ) }
213327
@@ -218,7 +332,12 @@ export const ColorPage = () => {
218332 closeEditor ( ) ;
219333 } }
220334 onRemove = { ( ) => {
221- removeColor ( editorState . index , editorState . colorType ) ;
335+ if (
336+ editorState . colorType === 'main' ||
337+ editorState . colorType === 'support'
338+ ) {
339+ removeColor ( editorState . index , editorState . colorType ) ;
340+ }
222341 closeEditor ( ) ;
223342 } }
224343 onCancel = { ( ) => {
@@ -253,7 +372,58 @@ export const ColorPage = () => {
253372 editorState . index ,
254373 ) ;
255374 } }
256- colorType = { editorState . colorType }
375+ colorType = {
376+ editorState . colorType === 'severity'
377+ ? 'neutral'
378+ : editorState . colorType
379+ }
380+ />
381+ ) }
382+
383+ { editorState . activePanel === 'edit-severity' && (
384+ < ColorPane
385+ onClose = { ( ) => {
386+ closeEditor ( ) ;
387+ } }
388+ onRemove = { ( ) => {
389+ // Reset to default by removing from query params
390+ const updatedParams = new URLSearchParams ( query ) ;
391+ updateSeverityColorInParams (
392+ editorState . initialHex ,
393+ editorState . name ,
394+ updatedParams ,
395+ ) ;
396+ setQuery ( updatedParams , {
397+ replace : true ,
398+ preventScrollReset : true ,
399+ } ) ;
400+ closeEditor ( ) ;
401+ } }
402+ onCancel = { ( ) => {
403+ updateColorInParams (
404+ editorState . initialHex ,
405+ editorState . initialName ,
406+ editorState . colorType ,
407+ editorState . index ,
408+ ) ;
409+ closeEditor ( ) ;
410+ } }
411+ type = 'edit-color'
412+ color = { color }
413+ name = { editorState . name }
414+ setColor = { ( newColor ) => {
415+ setColor ( newColor ) ;
416+ updateColorInParams (
417+ newColor . hex ,
418+ editorState . name ,
419+ editorState . colorType ,
420+ editorState . index ,
421+ ) ;
422+ } }
423+ setName = { ( ) => {
424+ // Name changes not allowed for severity colors
425+ } }
426+ colorType = 'severity'
257427 />
258428 ) }
259429 </ div >
0 commit comments