mirror of
https://github.com/Unleash/unleash.git
synced 2025-09-15 17:50:48 +02:00
Feat/dark mode exp (#1137)
* feat: add dark mode theme * fix: feature metrics * fix: add color * styling * fix: add switch * fix: form sidebar * fix: remove console log * fix: add properties * fix: strategy container * feat: feature flag * fix: tests * fix: build * fix: logo * fix: icon * fix: update snapshots * fix: CES operator * fix: typography * fix: input styling * fix: remove initial load * fix: change flag name * fix: refactor to custom hook * fix: remove unused import * fix: dialog headers * fix: use uiConfig flags instead of flags
This commit is contained in:
parent
e6b72ff4a0
commit
6818a82cd1
@ -39,6 +39,7 @@
|
|||||||
"isready": "yarn lint && yarn fmt && yarn prepare"
|
"isready": "yarn lint && yarn fmt && yarn prepare"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@codemirror/lang-json": "6.0.0",
|
||||||
"@emotion/react": "11.9.3",
|
"@emotion/react": "11.9.3",
|
||||||
"@emotion/styled": "11.9.3",
|
"@emotion/styled": "11.9.3",
|
||||||
"@mui/icons-material": "5.8.4",
|
"@mui/icons-material": "5.8.4",
|
||||||
@ -62,6 +63,7 @@
|
|||||||
"@types/react-test-renderer": "17.0.2",
|
"@types/react-test-renderer": "17.0.2",
|
||||||
"@types/react-timeago": "4.1.3",
|
"@types/react-timeago": "4.1.3",
|
||||||
"@types/semver": "7.3.12",
|
"@types/semver": "7.3.12",
|
||||||
|
"@uiw/react-codemirror": "4.11.4",
|
||||||
"@vitejs/plugin-react": "1.3.2",
|
"@vitejs/plugin-react": "1.3.2",
|
||||||
"chart.js": "3.9.1",
|
"chart.js": "3.9.1",
|
||||||
"chartjs-adapter-date-fns": "2.0.0",
|
"chartjs-adapter-date-fns": "2.0.0",
|
||||||
@ -102,8 +104,7 @@
|
|||||||
"vite-tsconfig-paths": "3.5.0",
|
"vite-tsconfig-paths": "3.5.0",
|
||||||
"vitest": "0.22.1",
|
"vitest": "0.22.1",
|
||||||
"whatwg-fetch": "3.6.2",
|
"whatwg-fetch": "3.6.2",
|
||||||
"@codemirror/lang-json": "6.0.0",
|
"@uiw/codemirror-theme-duotone": "^4.11.5"
|
||||||
"@uiw/react-codemirror": "4.11.4"
|
|
||||||
},
|
},
|
||||||
"jest": {
|
"jest": {
|
||||||
"moduleNameMapper": {
|
"moduleNameMapper": {
|
||||||
|
1
frontend/src/assets/img/logoWithWhiteText.svg
Normal file
1
frontend/src/assets/img/logoWithWhiteText.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg id="bg" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 653.4 251.24"><defs><style>.cls-1{fill:#fff;}.cls-2{fill:#1a4049;}.cls-3{fill:#817afe;}</style></defs><circle class="cls-1" cx="125.62" cy="125.62" r="80"/><polygon class="cls-1" points="137.05 91.33 137.05 114.19 137.05 137.05 159.9 137.05 159.9 114.19 159.9 91.33 137.05 91.33"/><polygon class="cls-1" points="114.19 114.19 114.19 91.33 91.33 91.33 91.33 114.19 91.33 137.05 91.33 159.9 114.19 159.9 137.05 159.9 137.05 137.05 114.19 137.05 114.19 114.19"/><polygon class="cls-2" points="137.05 91.33 137.05 114.19 137.05 137.05 159.9 137.05 159.9 114.19 159.9 91.33 137.05 91.33"/><polygon class="cls-2" points="114.19 114.19 114.19 91.33 91.33 91.33 91.33 114.19 91.33 137.05 91.33 159.9 114.19 159.9 137.05 159.9 137.05 137.05 114.19 137.05 114.19 114.19"/><rect class="cls-3" x="137.05" y="137.05" width="22.86" height="22.86"/><path class="cls-1" d="M251.58,139.13V112.77h11.93v25.06c0,7.36,3.91,12.2,11.27,12.2s11.27-4.84,11.27-12.2V112.77h12v26.36c0,12.67-8.48,21.8-23.1,21.8C260.06,160.93,251.58,151.8,251.58,139.13Z"/><path class="cls-1" d="M321.91,159.9H310.08V112.77h11.83v7.92a17.93,17.93,0,0,1,15.65-9c11.83,0,19.66,8.67,19.66,20.68V159.9h-12V134.75c0-7.45-4.38-12.39-11.46-12.39s-11.83,5-11.83,12.39Z"/><path class="cls-1" d="M369.42,91.34h11.92V159.9H369.42Z"/><path class="cls-1" d="M441.24,137v1.3H403.79c.47,7.36,5.87,13,13.69,13,7.55,0,10.62-3.82,11.46-5.12h11.74c-.75,4.84-7.17,15-23.2,15-15.27,0-25.61-10.61-25.61-24.77,0-14.63,10.24-24.78,24.68-24.78S441.24,121.62,441.24,137Zm-37.08-6.9h24.6c-1.77-6-6.15-9.31-12.21-9.31C410.12,120.78,405.65,124.23,404.16,130.09Z"/><path class="cls-1" d="M467.78,130.37h15.47c0-5.68-4.29-9.31-11.27-9.31-6.62,0-9,3.54-9.78,4.75h-12c1-4.94,6.89-14.25,21.8-14.25,14.62,0,22.73,7.64,22.73,18.81V146.3c0,2.89,1,4,3.72,4.29v9.59h-3.72c-6.06-.09-9.69-2.33-11-6.52-2.23,3.45-7.26,7.27-15.27,7.27-11.09,0-19.47-6.24-19.47-15.93S456.14,130.37,467.78,130.37Zm15.47,12.11v-4H469.74c-5.59,0-9,2-9,6.33,0,4.57,4.29,7.27,10.25,7.27C477.66,152.08,483.25,148.82,483.25,142.48Z"/><path class="cls-1" d="M523.12,140.62c-10.34-.74-17.33-5.59-17.33-14.72,0-8.85,8.1-14.44,20.77-14.44,17,0,21.8,8.76,23.1,13.32H537.09c-.84-1-3.54-4.28-10.62-4.28-5.68,0-8.66,1.86-8.66,4.75,0,2.61,2,4.29,6.7,4.94l8,.84c12.77,1.11,18,6,18,15.27,0,8.85-7.36,14.91-21.8,14.91-17.51,0-23.19-10.16-24.12-14.53h12.76c.47,1.11,3.35,5.31,11.36,5.31,6.62,0,9.69-2.24,9.69-5.22s-1.67-4.66-7-5.31C528.05,141.18,526.38,141,523.12,140.62Z"/><path class="cls-1" d="M571.55,159.9H559.72V91.34h11.83v29.35a17.93,17.93,0,0,1,15.65-9c11.83,0,19.66,8.67,19.66,20.68V159.9h-12V134.75c0-7.45-4.38-12.39-11.46-12.39s-11.83,5-11.83,12.39Z"/></svg>
|
After Width: | Height: | Size: 2.6 KiB |
@ -17,7 +17,7 @@ export const useStyles = makeStyles()(theme => ({
|
|||||||
margin: '0 auto',
|
margin: '0 auto',
|
||||||
flex: 1,
|
flex: 1,
|
||||||
width: '100%',
|
width: '100%',
|
||||||
backgroundColor: theme.palette.grey[300],
|
backgroundColor: theme.palette.contentWrapper,
|
||||||
},
|
},
|
||||||
content: {
|
content: {
|
||||||
width: '1250px',
|
width: '1250px',
|
||||||
|
@ -10,7 +10,7 @@ export const useStyles = makeStyles()(theme => ({
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
icon: {
|
icon: {
|
||||||
background: theme.palette.primary.main,
|
background: theme.palette.featureSegmentSearchBackground,
|
||||||
height: 48,
|
height: 48,
|
||||||
width: 48,
|
width: 48,
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
|
@ -2,7 +2,7 @@ import { makeStyles } from 'tss-react/mui';
|
|||||||
|
|
||||||
export const useStyles = makeStyles()(theme => ({
|
export const useStyles = makeStyles()(theme => ({
|
||||||
badge: {
|
badge: {
|
||||||
backgroundColor: theme.palette.primary.main,
|
backgroundColor: theme.palette.checkmarkBadge,
|
||||||
width: '75px',
|
width: '75px',
|
||||||
height: '75px',
|
height: '75px',
|
||||||
borderRadius: '50px',
|
borderRadius: '50px',
|
||||||
|
@ -2,7 +2,7 @@ import { makeStyles } from 'tss-react/mui';
|
|||||||
|
|
||||||
export const useStyles = makeStyles()(theme => ({
|
export const useStyles = makeStyles()(theme => ({
|
||||||
container: {
|
container: {
|
||||||
backgroundColor: theme.palette.sidebarContainer,
|
backgroundColor: theme.palette.codebox,
|
||||||
padding: '1rem',
|
padding: '1rem',
|
||||||
borderRadius: theme.shape.borderRadiusMedium,
|
borderRadius: theme.shape.borderRadiusMedium,
|
||||||
position: 'relative',
|
position: 'relative',
|
||||||
@ -13,7 +13,7 @@ export const useStyles = makeStyles()(theme => ({
|
|||||||
margin: 0,
|
margin: 0,
|
||||||
wordBreak: 'break-all',
|
wordBreak: 'break-all',
|
||||||
whiteSpace: 'pre-wrap',
|
whiteSpace: 'pre-wrap',
|
||||||
color: '#fff',
|
color: theme.palette.formSidebarTextColor,
|
||||||
fontSize: 14,
|
fontSize: 14,
|
||||||
},
|
},
|
||||||
icon: {
|
icon: {
|
||||||
|
@ -1,10 +1,25 @@
|
|||||||
import { makeStyles } from 'tss-react/mui';
|
import { makeStyles } from 'tss-react/mui';
|
||||||
|
|
||||||
export const useStyles = makeStyles()(theme => ({
|
export const useStyles = makeStyles()(theme => ({
|
||||||
|
constraintIconContainer: {
|
||||||
|
backgroundColor: theme.palette.background.paper,
|
||||||
|
borderRadius: '50%',
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center',
|
||||||
|
marginRight: theme.spacing(1),
|
||||||
|
[theme.breakpoints.down(650)]: {
|
||||||
|
marginBottom: '1rem',
|
||||||
|
marginRight: 0,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
constraintIcon: {
|
||||||
|
fill: '#fff',
|
||||||
|
},
|
||||||
accordion: {
|
accordion: {
|
||||||
border: `1px solid ${theme.palette.dividerAlternative}`,
|
border: `1px solid ${theme.palette.dividerAlternative}`,
|
||||||
borderRadius: theme.shape.borderRadiusMedium,
|
borderRadius: theme.shape.borderRadiusMedium,
|
||||||
backgroundColor: '#fff',
|
backgroundColor: theme.palette.constraintAccordion.background,
|
||||||
boxShadow: 'none',
|
boxShadow: 'none',
|
||||||
margin: 0,
|
margin: 0,
|
||||||
},
|
},
|
||||||
@ -14,7 +29,7 @@ export const useStyles = makeStyles()(theme => ({
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
accordionEdit: {
|
accordionEdit: {
|
||||||
backgroundColor: '#F6F6FA',
|
backgroundColor: theme.palette.constraintAccordion.editBackground,
|
||||||
},
|
},
|
||||||
headerMetaInfo: {
|
headerMetaInfo: {
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { Box, Tooltip } from '@mui/material';
|
import { Box, Tooltip, useTheme } from '@mui/material';
|
||||||
import { ReactComponent as NegatedIcon } from 'assets/icons/24_Negator.svg';
|
import { ReactComponent as NegatedIcon } from 'assets/icons/24_Negator.svg';
|
||||||
import { ReactComponent as NegatedIconOff } from 'assets/icons/24_Negator off.svg';
|
import { ReactComponent as NegatedIconOff } from 'assets/icons/24_Negator off.svg';
|
||||||
import { IConstraint } from 'interfaces/strategy';
|
import { IConstraint } from 'interfaces/strategy';
|
||||||
@ -7,6 +7,7 @@ import {
|
|||||||
StyledToggleButtonOn,
|
StyledToggleButtonOn,
|
||||||
} from '../StyledToggleButton';
|
} from '../StyledToggleButton';
|
||||||
import { ConditionallyRender } from '../../../../ConditionallyRender/ConditionallyRender';
|
import { ConditionallyRender } from '../../../../ConditionallyRender/ConditionallyRender';
|
||||||
|
import { ThemeMode } from 'component/common/ThemeMode/ThemeMode';
|
||||||
|
|
||||||
interface InvertedOperatorButtonProps {
|
interface InvertedOperatorButtonProps {
|
||||||
localConstraint: IConstraint;
|
localConstraint: IConstraint;
|
||||||
@ -16,35 +17,59 @@ interface InvertedOperatorButtonProps {
|
|||||||
export const InvertedOperatorButton = ({
|
export const InvertedOperatorButton = ({
|
||||||
localConstraint,
|
localConstraint,
|
||||||
setInvertedOperator,
|
setInvertedOperator,
|
||||||
}: InvertedOperatorButtonProps) => (
|
}: InvertedOperatorButtonProps) => {
|
||||||
<Tooltip
|
const theme = useTheme();
|
||||||
title={
|
|
||||||
Boolean(localConstraint.inverted)
|
return (
|
||||||
? 'Remove negation'
|
<Tooltip
|
||||||
: 'Negate operator'
|
title={
|
||||||
}
|
Boolean(localConstraint.inverted)
|
||||||
arrow
|
? 'Remove negation'
|
||||||
>
|
: 'Negate operator'
|
||||||
<Box sx={{ display: 'flex', alignItems: 'stretch' }}>
|
}
|
||||||
<ConditionallyRender
|
arrow
|
||||||
condition={Boolean(localConstraint.inverted)}
|
>
|
||||||
show={
|
<Box sx={{ display: 'flex', alignItems: 'stretch' }}>
|
||||||
<StyledToggleButtonOn
|
<ConditionallyRender
|
||||||
onClick={setInvertedOperator}
|
condition={Boolean(localConstraint.inverted)}
|
||||||
disableRipple
|
show={
|
||||||
>
|
<StyledToggleButtonOn
|
||||||
<NegatedIcon />
|
onClick={setInvertedOperator}
|
||||||
</StyledToggleButtonOn>
|
disableRipple
|
||||||
}
|
>
|
||||||
elseShow={
|
<ThemeMode
|
||||||
<StyledToggleButtonOff
|
darkmode={
|
||||||
onClick={setInvertedOperator}
|
<NegatedIcon
|
||||||
disableRipple
|
style={{
|
||||||
>
|
fill: theme.palette.background
|
||||||
<NegatedIconOff />
|
.paper,
|
||||||
</StyledToggleButtonOff>
|
}}
|
||||||
}
|
/>
|
||||||
/>
|
}
|
||||||
</Box>
|
lightmode={<NegatedIcon />}
|
||||||
</Tooltip>
|
/>
|
||||||
);
|
</StyledToggleButtonOn>
|
||||||
|
}
|
||||||
|
elseShow={
|
||||||
|
<StyledToggleButtonOff
|
||||||
|
onClick={setInvertedOperator}
|
||||||
|
disableRipple
|
||||||
|
>
|
||||||
|
<ThemeMode
|
||||||
|
darkmode={
|
||||||
|
<NegatedIconOff
|
||||||
|
style={{
|
||||||
|
fill: theme.palette.background
|
||||||
|
.paper,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
lightmode={<NegatedIconOff />}
|
||||||
|
/>
|
||||||
|
</StyledToggleButtonOff>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
</Tooltip>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
@ -14,6 +14,7 @@ export const ConstraintIcon: VFC<IConstraintIconProps> = ({ compact }) => (
|
|||||||
borderRadius: '50%',
|
borderRadius: '50%',
|
||||||
width: compact ? '18px' : '24px',
|
width: compact ? '18px' : '24px',
|
||||||
height: compact ? '18px' : '24px',
|
height: compact ? '18px' : '24px',
|
||||||
|
marginRight: '13px',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<TrackChanges
|
<TrackChanges
|
||||||
|
@ -4,7 +4,7 @@ export const useStyles = makeStyles()(theme => ({
|
|||||||
container: {
|
container: {
|
||||||
padding: theme.spacing(0.5, 1.5),
|
padding: theme.spacing(0.5, 1.5),
|
||||||
borderRadius: theme.shape.borderRadius,
|
borderRadius: theme.shape.borderRadius,
|
||||||
backgroundColor: theme.palette.grey[200],
|
backgroundColor: theme.palette.constraintAccordion.operatorBackground,
|
||||||
lineHeight: 1.25,
|
lineHeight: 1.25,
|
||||||
},
|
},
|
||||||
name: {
|
name: {
|
||||||
|
@ -2,8 +2,8 @@ import { makeStyles } from 'tss-react/mui';
|
|||||||
|
|
||||||
export const useStyles = makeStyles()(theme => ({
|
export const useStyles = makeStyles()(theme => ({
|
||||||
dialogTitle: {
|
dialogTitle: {
|
||||||
backgroundColor: theme.palette.primary.main,
|
backgroundColor: theme.palette.dialogHeaderBackground,
|
||||||
color: '#fff',
|
color: theme.palette.dialogHeaderText,
|
||||||
height: '150px',
|
height: '150px',
|
||||||
padding: '2rem 3rem',
|
padding: '2rem 3rem',
|
||||||
clipPath: ' ellipse(130% 115px at 120% 20%)',
|
clipPath: ' ellipse(130% 115px at 120% 20%)',
|
||||||
|
@ -20,7 +20,7 @@ export const useStyles = makeStyles()(theme => ({
|
|||||||
borderRadius: 0,
|
borderRadius: 0,
|
||||||
},
|
},
|
||||||
sidebar: {
|
sidebar: {
|
||||||
backgroundColor: theme.palette.primary.main,
|
backgroundColor: theme.palette.formSidebar,
|
||||||
padding: '2rem',
|
padding: '2rem',
|
||||||
flexGrow: 0,
|
flexGrow: 0,
|
||||||
flexShrink: 0,
|
flexShrink: 0,
|
||||||
@ -42,7 +42,7 @@ export const useStyles = makeStyles()(theme => ({
|
|||||||
fontWeight: 'normal',
|
fontWeight: 'normal',
|
||||||
},
|
},
|
||||||
subtitle: {
|
subtitle: {
|
||||||
color: '#fff',
|
color: theme.palette.formSidebarTextColor,
|
||||||
marginBottom: '1rem',
|
marginBottom: '1rem',
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
justifyContent: 'space-between',
|
justifyContent: 'space-between',
|
||||||
@ -51,7 +51,7 @@ export const useStyles = makeStyles()(theme => ({
|
|||||||
fontSize: theme.fontSizes.bodySize,
|
fontSize: theme.fontSizes.bodySize,
|
||||||
},
|
},
|
||||||
description: {
|
description: {
|
||||||
color: '#fff',
|
color: theme.palette.formSidebarTextColor,
|
||||||
zIndex: 1,
|
zIndex: 1,
|
||||||
position: 'relative',
|
position: 'relative',
|
||||||
},
|
},
|
||||||
@ -72,7 +72,7 @@ export const useStyles = makeStyles()(theme => ({
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
formContent: {
|
formContent: {
|
||||||
backgroundColor: '#fff',
|
backgroundColor: theme.palette.formBackground,
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
flexDirection: 'column',
|
flexDirection: 'column',
|
||||||
padding: '3rem',
|
padding: '3rem',
|
||||||
|
@ -3,7 +3,7 @@ import React, { FC, VFC, useEffect, useState, useContext } from 'react';
|
|||||||
import { InstanceStatusBar } from 'component/common/InstanceStatus/InstanceStatusBar';
|
import { InstanceStatusBar } from 'component/common/InstanceStatus/InstanceStatusBar';
|
||||||
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
|
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
|
||||||
import { Dialogue } from 'component/common/Dialogue/Dialogue';
|
import { Dialogue } from 'component/common/Dialogue/Dialogue';
|
||||||
import { Typography } from '@mui/material';
|
import { Typography, useTheme } from '@mui/material';
|
||||||
import { useNavigate } from 'react-router-dom';
|
import { useNavigate } from 'react-router-dom';
|
||||||
import { IInstanceStatus } from 'interfaces/instance';
|
import { IInstanceStatus } from 'interfaces/instance';
|
||||||
import { ADMIN } from 'component/providers/AccessProvider/permissions';
|
import { ADMIN } from 'component/providers/AccessProvider/permissions';
|
||||||
@ -91,6 +91,7 @@ export const InstanceStatus: FC = ({ children }) => {
|
|||||||
useInstanceStatus();
|
useInstanceStatus();
|
||||||
const { extendTrial } = useInstanceStatusApi();
|
const { extendTrial } = useInstanceStatusApi();
|
||||||
const { setToastApiError } = useToast();
|
const { setToastApiError } = useToast();
|
||||||
|
const theme = useTheme();
|
||||||
|
|
||||||
const onExtendTrial = async () => {
|
const onExtendTrial = async () => {
|
||||||
try {
|
try {
|
||||||
@ -102,7 +103,12 @@ export const InstanceStatus: FC = ({ children }) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div style={{ height: '100%' }}>
|
<div
|
||||||
|
style={{
|
||||||
|
height: '100%',
|
||||||
|
backgroundColor: theme.palette.background.paper,
|
||||||
|
}}
|
||||||
|
>
|
||||||
<ConditionallyRender
|
<ConditionallyRender
|
||||||
condition={isBilling && Boolean(instanceStatus)}
|
condition={isBilling && Boolean(instanceStatus)}
|
||||||
show={() => (
|
show={() => (
|
||||||
|
@ -6,6 +6,7 @@ export const useStyles = makeStyles()(theme => ({
|
|||||||
justifyContent: 'center',
|
justifyContent: 'center',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
height: '100%',
|
height: '100%',
|
||||||
|
backgroundColor: theme.palette.background.paper,
|
||||||
},
|
},
|
||||||
img: {
|
img: {
|
||||||
width: '100px',
|
width: '100px',
|
||||||
|
@ -6,6 +6,7 @@ export const useStyles = makeStyles()(theme => ({
|
|||||||
flexGrow: 1,
|
flexGrow: 1,
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
position: 'relative',
|
position: 'relative',
|
||||||
|
backgroundColor: theme.palette.background.paper,
|
||||||
maxWidth: '400px',
|
maxWidth: '400px',
|
||||||
[theme.breakpoints.down('md')]: {
|
[theme.breakpoints.down('md')]: {
|
||||||
marginTop: theme.spacing(1),
|
marginTop: theme.spacing(1),
|
||||||
|
@ -7,7 +7,7 @@ export const useStyles = makeStyles()(theme => ({
|
|||||||
'& + &': {
|
'& + &': {
|
||||||
marginTop: theme.spacing(2),
|
marginTop: theme.spacing(2),
|
||||||
},
|
},
|
||||||
background: theme.palette.background.default,
|
background: theme.palette.background.paper,
|
||||||
},
|
},
|
||||||
header: {
|
header: {
|
||||||
padding: theme.spacing(0.5, 2),
|
padding: theme.spacing(0.5, 2),
|
||||||
|
@ -5,7 +5,8 @@ export const useStyles = makeStyles()(theme => ({
|
|||||||
'& > th': {
|
'& > th': {
|
||||||
height: theme.shape.tableRowHeightCompact,
|
height: theme.shape.tableRowHeightCompact,
|
||||||
border: 0,
|
border: 0,
|
||||||
|
backgroundColor: theme.palette.tableHeaderBackground,
|
||||||
|
color: theme.palette.tableHeaderColor,
|
||||||
'&:first-of-type': {
|
'&:first-of-type': {
|
||||||
borderTopLeftRadius: theme.shape.borderRadiusMedium,
|
borderTopLeftRadius: theme.shape.borderRadiusMedium,
|
||||||
borderBottomLeftRadius: theme.shape.borderRadiusMedium,
|
borderBottomLeftRadius: theme.shape.borderRadiusMedium,
|
||||||
|
20
frontend/src/component/common/ThemeMode/ThemeMode.tsx
Normal file
20
frontend/src/component/common/ThemeMode/ThemeMode.tsx
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
import UIContext from 'contexts/UIContext';
|
||||||
|
import { useContext } from 'react';
|
||||||
|
import { ConditionallyRender } from '../ConditionallyRender/ConditionallyRender';
|
||||||
|
|
||||||
|
interface IThemeModeProps {
|
||||||
|
darkmode: JSX.Element;
|
||||||
|
lightmode: JSX.Element;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const ThemeMode = ({ darkmode, lightmode }: IThemeModeProps) => {
|
||||||
|
const { themeMode } = useContext(UIContext);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ConditionallyRender
|
||||||
|
condition={themeMode === 'dark'}
|
||||||
|
show={darkmode}
|
||||||
|
elseShow={lightmode}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
@ -3,7 +3,7 @@ import { makeStyles } from 'tss-react/mui';
|
|||||||
export const useStyles = makeStyles()(theme => ({
|
export const useStyles = makeStyles()(theme => ({
|
||||||
container: {
|
container: {
|
||||||
maxWidth: '450px',
|
maxWidth: '450px',
|
||||||
background: '#fff',
|
background: theme.palette.background.paper,
|
||||||
boxShadow: '2px 2px 4px rgba(0,0,0,0.4)',
|
boxShadow: '2px 2px 4px rgba(0,0,0,0.4)',
|
||||||
zIndex: 500,
|
zIndex: 500,
|
||||||
margin: '0 0.8rem',
|
margin: '0 0.8rem',
|
||||||
|
@ -10,7 +10,7 @@ export const useStyles = makeStyles()(theme => ({
|
|||||||
paddingBlockStart: 4,
|
paddingBlockStart: 4,
|
||||||
paddingBlockEnd: 4,
|
paddingBlockEnd: 4,
|
||||||
borderRadius: '100rem',
|
borderRadius: '100rem',
|
||||||
background: theme.palette.primary.main,
|
background: theme.palette.featureStrategySegmentChipBackground,
|
||||||
color: 'white',
|
color: 'white',
|
||||||
},
|
},
|
||||||
link: {
|
link: {
|
||||||
|
@ -3,7 +3,7 @@ import { makeStyles } from 'tss-react/mui';
|
|||||||
export const useStyles = makeStyles()(theme => ({
|
export const useStyles = makeStyles()(theme => ({
|
||||||
container: {
|
container: {
|
||||||
borderRadius: '12.5px',
|
borderRadius: '12.5px',
|
||||||
backgroundColor: '#fff',
|
backgroundColor: theme.palette.background.paper,
|
||||||
padding: '2rem',
|
padding: '2rem',
|
||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
|
@ -3,7 +3,7 @@ import { makeStyles } from 'tss-react/mui';
|
|||||||
export const useStyles = makeStyles()(theme => ({
|
export const useStyles = makeStyles()(theme => ({
|
||||||
item: {
|
item: {
|
||||||
padding: theme.spacing(2),
|
padding: theme.spacing(2),
|
||||||
background: theme.palette.secondaryContainer,
|
background: theme.palette.featureMetricsBackground,
|
||||||
borderRadius: theme.spacing(2),
|
borderRadius: theme.spacing(2),
|
||||||
textAlign: 'center',
|
textAlign: 'center',
|
||||||
[theme.breakpoints.up('md')]: {
|
[theme.breakpoints.up('md')]: {
|
||||||
|
@ -9,7 +9,7 @@ import { styled } from '@mui/material';
|
|||||||
|
|
||||||
const StyledContainer = styled('div')(({ theme }) => ({
|
const StyledContainer = styled('div')(({ theme }) => ({
|
||||||
borderRadius: theme.shape.borderRadiusLarge,
|
borderRadius: theme.shape.borderRadiusLarge,
|
||||||
backgroundColor: '#fff',
|
backgroundColor: theme.palette.background.paper,
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
flexDirection: 'column',
|
flexDirection: 'column',
|
||||||
padding: '1.5rem',
|
padding: '1.5rem',
|
||||||
|
@ -4,7 +4,8 @@ export const useStyles = makeStyles()(theme => ({
|
|||||||
featureOverviewEnvironment: {
|
featureOverviewEnvironment: {
|
||||||
borderRadius: theme.shape.borderRadiusLarge,
|
borderRadius: theme.shape.borderRadiusLarge,
|
||||||
marginBottom: theme.spacing(2),
|
marginBottom: theme.spacing(2),
|
||||||
background: theme.palette.background.default,
|
padding: '0.2rem',
|
||||||
|
backgroundColor: theme.palette.background.paper,
|
||||||
},
|
},
|
||||||
accordion: {
|
accordion: {
|
||||||
boxShadow: 'none',
|
boxShadow: 'none',
|
||||||
|
@ -53,7 +53,7 @@ const FeatureOverviewEnvironment = ({
|
|||||||
style={{
|
style={{
|
||||||
background: !env.enabled
|
background: !env.enabled
|
||||||
? theme.palette.neutral.light
|
? theme.palette.neutral.light
|
||||||
: theme.palette.background.default,
|
: theme.palette.background.paper,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Accordion
|
<Accordion
|
||||||
|
@ -4,7 +4,7 @@ export const useStyles = makeStyles()(theme => ({
|
|||||||
container: {
|
container: {
|
||||||
borderRadius: theme.shape.borderRadiusLarge,
|
borderRadius: theme.shape.borderRadiusLarge,
|
||||||
color: '#fff',
|
color: '#fff',
|
||||||
backgroundColor: theme.palette.primary.main,
|
backgroundColor: theme.palette.featureMetaData,
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
flexDirection: 'column',
|
flexDirection: 'column',
|
||||||
maxWidth: '350px',
|
maxWidth: '350px',
|
||||||
|
@ -7,7 +7,7 @@ export const useStyles = makeStyles()(theme => ({
|
|||||||
display: 'flex',
|
display: 'flex',
|
||||||
},
|
},
|
||||||
header: {
|
header: {
|
||||||
backgroundColor: '#fff',
|
backgroundColor: theme.palette.background.paper,
|
||||||
borderRadius: theme.shape.borderRadiusLarge,
|
borderRadius: theme.shape.borderRadiusLarge,
|
||||||
marginBottom: '1rem',
|
marginBottom: '1rem',
|
||||||
},
|
},
|
||||||
|
@ -15,7 +15,7 @@ export const useStyles = makeStyles()(theme => ({
|
|||||||
pointerEvents: 'auto',
|
pointerEvents: 'auto',
|
||||||
position: 'relative',
|
position: 'relative',
|
||||||
padding: '4rem',
|
padding: '4rem',
|
||||||
background: 'white',
|
background: theme.palette.background.paper,
|
||||||
boxShadow: '0 0 1rem rgba(0, 0, 0, 0.25)',
|
boxShadow: '0 0 1rem rgba(0, 0, 0, 0.25)',
|
||||||
borderRadius: '1rem',
|
borderRadius: '1rem',
|
||||||
[theme.breakpoints.down('md')]: {
|
[theme.breakpoints.down('md')]: {
|
||||||
|
@ -131,18 +131,18 @@ exports[`FeedbackCESForm 1`] = `
|
|||||||
class="MuiFormControl-root MuiFormControl-fullWidth MuiTextField-root mui-wb57ya-MuiFormControl-root-MuiTextField-root"
|
class="MuiFormControl-root MuiFormControl-fullWidth MuiTextField-root mui-wb57ya-MuiFormControl-root-MuiTextField-root"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="MuiInputBase-root MuiOutlinedInput-root MuiInputBase-colorPrimary MuiInputBase-fullWidth MuiInputBase-formControl MuiInputBase-multiline mui-181wpo2-MuiInputBase-root-MuiOutlinedInput-root"
|
class="MuiInputBase-root MuiOutlinedInput-root MuiInputBase-colorPrimary MuiInputBase-fullWidth MuiInputBase-formControl MuiInputBase-multiline mui-1qvtpcv-MuiInputBase-root-MuiOutlinedInput-root"
|
||||||
>
|
>
|
||||||
<textarea
|
<textarea
|
||||||
aria-invalid="false"
|
aria-invalid="false"
|
||||||
class="MuiInputBase-input MuiOutlinedInput-input MuiInputBase-inputMultiline mui-1632cvv-MuiInputBase-input-MuiOutlinedInput-input"
|
class="MuiInputBase-input MuiOutlinedInput-input MuiInputBase-inputMultiline mui-1wvz5kg-MuiInputBase-input-MuiOutlinedInput-input"
|
||||||
id="mui-1"
|
id="mui-1"
|
||||||
rows="3"
|
rows="3"
|
||||||
style="height: 0px; overflow: hidden;"
|
style="height: 0px; overflow: hidden;"
|
||||||
/>
|
/>
|
||||||
<textarea
|
<textarea
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
class="MuiInputBase-input MuiOutlinedInput-input MuiInputBase-inputMultiline mui-1632cvv-MuiInputBase-input-MuiOutlinedInput-input"
|
class="MuiInputBase-input MuiOutlinedInput-input MuiInputBase-inputMultiline mui-1wvz5kg-MuiInputBase-input-MuiOutlinedInput-input"
|
||||||
readonly=""
|
readonly=""
|
||||||
style="visibility: hidden; position: absolute; overflow: hidden; height: 0px; top: 0px; left: 0px; transform: translateZ(0); padding: 0px; width: 100%;"
|
style="visibility: hidden; position: absolute; overflow: hidden; height: 0px; top: 0px; left: 0px; transform: translateZ(0); padding: 0px; width: 100%;"
|
||||||
tabindex="-1"
|
tabindex="-1"
|
||||||
|
@ -3,7 +3,7 @@ import { makeStyles } from 'tss-react/mui';
|
|||||||
export const useStyles = makeStyles()(theme => ({
|
export const useStyles = makeStyles()(theme => ({
|
||||||
feedback: {
|
feedback: {
|
||||||
borderRadius: '12.5px',
|
borderRadius: '12.5px',
|
||||||
backgroundColor: '#fff',
|
backgroundColor: theme.palette.background.paper,
|
||||||
zIndex: 9999,
|
zIndex: 9999,
|
||||||
boxShadow: '2px 2px 4px 4px rgba(143,143,143, 0.25)',
|
boxShadow: '2px 2px 4px 4px rgba(143,143,143, 0.25)',
|
||||||
padding: '1.5rem',
|
padding: '1.5rem',
|
||||||
@ -21,7 +21,7 @@ export const useStyles = makeStyles()(theme => ({
|
|||||||
position: 'absolute',
|
position: 'absolute',
|
||||||
right: '-38px',
|
right: '-38px',
|
||||||
top: '-47px',
|
top: '-47px',
|
||||||
backgroundColor: '#fff',
|
backgroundColor: theme.palette.background.paper,
|
||||||
boxShadow: '2px 2px 4px 4px rgba(143,143,143, 0.25)',
|
boxShadow: '2px 2px 4px 4px rgba(143,143,143, 0.25)',
|
||||||
['&:hover']: {
|
['&:hover']: {
|
||||||
backgroundColor: '#fff',
|
backgroundColor: '#fff',
|
||||||
|
@ -6,6 +6,7 @@ export const useStyles = makeStyles()(theme => ({
|
|||||||
width: '100%',
|
width: '100%',
|
||||||
flexGrow: 1,
|
flexGrow: 1,
|
||||||
zIndex: 100,
|
zIndex: 100,
|
||||||
|
backgroundColor: theme.palette.footerBackground,
|
||||||
},
|
},
|
||||||
list: {
|
list: {
|
||||||
padding: 0,
|
padding: 0,
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
exports[`should render DrawerMenu 1`] = `
|
exports[`should render DrawerMenu 1`] = `
|
||||||
[
|
[
|
||||||
<footer
|
<footer
|
||||||
className="tss-wd65c0-footer"
|
className="tss-16d7ppb-footer"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
className="MuiGrid-root MuiGrid-container MuiGrid-spacing-xs-10 mui-16chest-MuiGrid-root"
|
className="MuiGrid-root MuiGrid-container MuiGrid-spacing-xs-10 mui-16chest-MuiGrid-root"
|
||||||
@ -448,7 +448,7 @@ exports[`should render DrawerMenu 1`] = `
|
|||||||
exports[`should render DrawerMenu with "features" selected 1`] = `
|
exports[`should render DrawerMenu with "features" selected 1`] = `
|
||||||
[
|
[
|
||||||
<footer
|
<footer
|
||||||
className="tss-wd65c0-footer"
|
className="tss-16d7ppb-footer"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
className="MuiGrid-root MuiGrid-container MuiGrid-spacing-xs-10 mui-16chest-MuiGrid-root"
|
className="MuiGrid-root MuiGrid-container MuiGrid-spacing-xs-10 mui-16chest-MuiGrid-root"
|
||||||
|
@ -2,8 +2,7 @@ import { makeStyles } from 'tss-react/mui';
|
|||||||
|
|
||||||
export const useStyles = makeStyles()(theme => ({
|
export const useStyles = makeStyles()(theme => ({
|
||||||
header: {
|
header: {
|
||||||
backgroundColor: '#fff',
|
backgroundColor: theme.palette.headerBackground,
|
||||||
color: '#000',
|
|
||||||
padding: '0.5rem',
|
padding: '0.5rem',
|
||||||
boxShadow: 'none',
|
boxShadow: 'none',
|
||||||
position: 'relative',
|
position: 'relative',
|
||||||
@ -80,7 +79,6 @@ export const useStyles = makeStyles()(theme => ({
|
|||||||
textDecoration: 'none',
|
textDecoration: 'none',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
color: '#000',
|
|
||||||
},
|
},
|
||||||
icon: {
|
icon: {
|
||||||
color: theme.palette.grey[700],
|
color: theme.palette.grey[700],
|
||||||
|
@ -2,13 +2,21 @@ import { useEffect, useState, VFC } from 'react';
|
|||||||
import useMediaQuery from '@mui/material/useMediaQuery';
|
import useMediaQuery from '@mui/material/useMediaQuery';
|
||||||
import { useTheme } from '@mui/material/styles';
|
import { useTheme } from '@mui/material/styles';
|
||||||
import { Link } from 'react-router-dom';
|
import { Link } from 'react-router-dom';
|
||||||
import { AppBar, Container, IconButton, Tooltip } from '@mui/material';
|
import {
|
||||||
|
AppBar,
|
||||||
|
Container,
|
||||||
|
FormControlLabel,
|
||||||
|
IconButton,
|
||||||
|
Tooltip,
|
||||||
|
Switch,
|
||||||
|
} from '@mui/material';
|
||||||
import MenuIcon from '@mui/icons-material/Menu';
|
import MenuIcon from '@mui/icons-material/Menu';
|
||||||
import SettingsIcon from '@mui/icons-material/Settings';
|
import SettingsIcon from '@mui/icons-material/Settings';
|
||||||
import UserProfile from 'component/user/UserProfile';
|
import UserProfile from 'component/user/UserProfile';
|
||||||
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
|
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
|
||||||
import MenuBookIcon from '@mui/icons-material/MenuBook';
|
import MenuBookIcon from '@mui/icons-material/MenuBook';
|
||||||
import { ReactComponent as UnleashLogo } from 'assets/img/logoDarkWithText.svg';
|
import { ReactComponent as UnleashLogo } from 'assets/img/logoDarkWithText.svg';
|
||||||
|
import { ReactComponent as UnleashLogoWhite } from 'assets/img/logoWithWhiteText.svg';
|
||||||
|
|
||||||
import { DrawerMenu } from './DrawerMenu/DrawerMenu';
|
import { DrawerMenu } from './DrawerMenu/DrawerMenu';
|
||||||
import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig';
|
import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig';
|
||||||
@ -24,8 +32,11 @@ import { useStyles } from './Header.styles';
|
|||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import { useId } from 'hooks/useId';
|
import { useId } from 'hooks/useId';
|
||||||
import { IRoute } from 'interfaces/route';
|
import { IRoute } from 'interfaces/route';
|
||||||
|
import { ThemeMode } from 'component/common/ThemeMode/ThemeMode';
|
||||||
|
import { useThemeMode } from 'hooks/useThemeMode';
|
||||||
|
|
||||||
const Header: VFC = () => {
|
const Header: VFC = () => {
|
||||||
|
const { onSetThemeMode, themeMode } = useThemeMode();
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const adminId = useId();
|
const adminId = useId();
|
||||||
const configId = useId();
|
const configId = useId();
|
||||||
@ -111,9 +122,19 @@ const Header: VFC = () => {
|
|||||||
)}
|
)}
|
||||||
aria-label="Home"
|
aria-label="Home"
|
||||||
>
|
>
|
||||||
<UnleashLogo
|
<ThemeMode
|
||||||
className={styles.logo}
|
darkmode={
|
||||||
aria-label="Unleash logo"
|
<UnleashLogoWhite
|
||||||
|
className={styles.logo}
|
||||||
|
aria-label="Unleash logo"
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
lightmode={
|
||||||
|
<UnleashLogo
|
||||||
|
className={styles.logo}
|
||||||
|
aria-label="Unleash logo"
|
||||||
|
/>
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
</Link>
|
</Link>
|
||||||
<nav className={styles.nav}>
|
<nav className={styles.nav}>
|
||||||
@ -148,6 +169,22 @@ const Header: VFC = () => {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className={styles.userContainer}>
|
<div className={styles.userContainer}>
|
||||||
|
<ConditionallyRender
|
||||||
|
condition={Boolean(
|
||||||
|
uiConfig.flags.ENABLE_DARK_MODE_SUPPORT
|
||||||
|
)}
|
||||||
|
show={
|
||||||
|
<FormControlLabel
|
||||||
|
control={
|
||||||
|
<Switch
|
||||||
|
onChange={onSetThemeMode}
|
||||||
|
checked={themeMode === 'dark'}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
label="darkmode"
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
/>
|
||||||
<Tooltip title="Documentation" arrow>
|
<Tooltip title="Documentation" arrow>
|
||||||
<IconButton
|
<IconButton
|
||||||
href="https://docs.getunleash.io/"
|
href="https://docs.getunleash.io/"
|
||||||
|
@ -20,7 +20,7 @@ export const useStyles = makeStyles()(theme => ({
|
|||||||
textDecoration: 'none',
|
textDecoration: 'none',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
color: '#000',
|
color: 'inherit',
|
||||||
height: '100%',
|
height: '100%',
|
||||||
width: '100%',
|
width: '100%',
|
||||||
'&&': {
|
'&&': {
|
||||||
|
@ -159,7 +159,7 @@ export const Playground: VFC<{}> = () => {
|
|||||||
>
|
>
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
background: theme.palette.grey[200],
|
background: theme.palette.playgroundBackground,
|
||||||
borderBottomLeftRadius: theme.shape.borderRadiusMedium,
|
borderBottomLeftRadius: theme.shape.borderRadiusMedium,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
@ -170,7 +170,7 @@ export const Playground: VFC<{}> = () => {
|
|||||||
py: 3,
|
py: 3,
|
||||||
mb: 4,
|
mb: 4,
|
||||||
mt: 2,
|
mt: 2,
|
||||||
background: theme.palette.grey[200],
|
background: theme.palette.playgroundBackground,
|
||||||
transition: 'width 0.4s ease',
|
transition: 'width 0.4s ease',
|
||||||
minWidth: matches ? 'auto' : '500px',
|
minWidth: matches ? 'auto' : '500px',
|
||||||
width: formWidth,
|
width: formWidth,
|
||||||
|
@ -1,10 +1,13 @@
|
|||||||
import CodeMirror from '@uiw/react-codemirror';
|
import CodeMirror from '@uiw/react-codemirror';
|
||||||
|
import { useContext } from 'react';
|
||||||
import { json } from '@codemirror/lang-json';
|
import { json } from '@codemirror/lang-json';
|
||||||
import { Dispatch, SetStateAction, VFC, useCallback } from 'react';
|
import { Dispatch, SetStateAction, VFC, useCallback } from 'react';
|
||||||
import { styled, useTheme, Box } from '@mui/material';
|
import { styled, useTheme, Box } from '@mui/material';
|
||||||
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
|
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
|
||||||
|
import { duotoneDark, duotoneLight } from '@uiw/codemirror-theme-duotone';
|
||||||
import Check from '@mui/icons-material/Check';
|
import Check from '@mui/icons-material/Check';
|
||||||
import { Error } from '@mui/icons-material';
|
import { Error } from '@mui/icons-material';
|
||||||
|
import UIContext from 'contexts/UIContext';
|
||||||
|
|
||||||
interface IPlaygroundEditorProps {
|
interface IPlaygroundEditorProps {
|
||||||
context: string | undefined;
|
context: string | undefined;
|
||||||
@ -78,6 +81,7 @@ export const PlaygroundEditor: VFC<IPlaygroundEditorProps> = ({
|
|||||||
setContext,
|
setContext,
|
||||||
error,
|
error,
|
||||||
}) => {
|
}) => {
|
||||||
|
const { themeMode } = useContext(UIContext);
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const onCodeFieldChange = useCallback(
|
const onCodeFieldChange = useCallback(
|
||||||
context => {
|
context => {
|
||||||
@ -109,6 +113,7 @@ export const PlaygroundEditor: VFC<IPlaygroundEditorProps> = ({
|
|||||||
<CodeMirror
|
<CodeMirror
|
||||||
value={context}
|
value={context}
|
||||||
height="200px"
|
height="200px"
|
||||||
|
theme={themeMode === 'dark' ? duotoneDark : duotoneLight}
|
||||||
extensions={[json()]}
|
extensions={[json()]}
|
||||||
onChange={onCodeFieldChange}
|
onChange={onCodeFieldChange}
|
||||||
style={{
|
style={{
|
||||||
|
@ -13,7 +13,7 @@ export const useStyles = makeStyles()(theme => ({
|
|||||||
minWidth: 0,
|
minWidth: 0,
|
||||||
},
|
},
|
||||||
header: {
|
header: {
|
||||||
backgroundColor: '#fff',
|
backgroundColor: theme.palette.background.paper,
|
||||||
borderRadius: theme.shape.borderRadiusLarge,
|
borderRadius: theme.shape.borderRadiusLarge,
|
||||||
marginBottom: '1rem',
|
marginBottom: '1rem',
|
||||||
},
|
},
|
||||||
|
@ -55,7 +55,7 @@ export const useStyles = makeStyles()(theme => ({
|
|||||||
margin: '0',
|
margin: '0',
|
||||||
textAlign: 'center',
|
textAlign: 'center',
|
||||||
marginBottom: '1rem',
|
marginBottom: '1rem',
|
||||||
backgroundColor: '#fff',
|
backgroundColor: theme.palette.background.paper,
|
||||||
borderRadius: theme.shape.borderRadiusLarge,
|
borderRadius: theme.shape.borderRadiusLarge,
|
||||||
width: '100%',
|
width: '100%',
|
||||||
padding: '1.5rem 1rem 1.5rem 1rem',
|
padding: '1.5rem 1rem 1.5rem 1rem',
|
||||||
|
@ -16,7 +16,7 @@ export const useStyles = makeStyles()(theme => ({
|
|||||||
},
|
},
|
||||||
'&:hover': {
|
'&:hover': {
|
||||||
transition: 'background-color 0.2s ease-in-out',
|
transition: 'background-color 0.2s ease-in-out',
|
||||||
backgroundColor: theme.palette.neutral.light,
|
backgroundColor: theme.palette.projectCard.hover,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
header: {
|
header: {
|
||||||
@ -49,7 +49,7 @@ export const useStyles = makeStyles()(theme => ({
|
|||||||
textAlign: 'center',
|
textAlign: 'center',
|
||||||
},
|
},
|
||||||
infoStats: {
|
infoStats: {
|
||||||
color: '#4A4599',
|
color: theme.palette.projectCard.textColor,
|
||||||
fontWeight: 'bold',
|
fontWeight: 'bold',
|
||||||
},
|
},
|
||||||
actionsBtn: {
|
actionsBtn: {
|
||||||
|
@ -1,10 +1,36 @@
|
|||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
import UIContext, { createEmptyToast } from 'contexts/UIContext';
|
import UIContext, { createEmptyToast, themeMode } from 'contexts/UIContext';
|
||||||
import { IToast } from 'interfaces/toast';
|
import { IToast } from 'interfaces/toast';
|
||||||
|
import { getLocalStorageItem } from 'utils/storage';
|
||||||
|
|
||||||
const UIProvider: React.FC = ({ children }) => {
|
const resolveMode = (darkmode: boolean): themeMode => {
|
||||||
|
const value = getLocalStorageItem('unleash-theme');
|
||||||
|
if (value) {
|
||||||
|
return value as themeMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
let osDark;
|
||||||
|
if (darkmode) {
|
||||||
|
osDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (osDark) {
|
||||||
|
return 'dark';
|
||||||
|
}
|
||||||
|
return 'light';
|
||||||
|
};
|
||||||
|
|
||||||
|
interface IUiProviderProps {
|
||||||
|
darkmode: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
const UIProvider: React.FC<IUiProviderProps> = ({
|
||||||
|
children,
|
||||||
|
darkmode = false,
|
||||||
|
}) => {
|
||||||
const [toastData, setToast] = useState<IToast>(createEmptyToast());
|
const [toastData, setToast] = useState<IToast>(createEmptyToast());
|
||||||
const [showFeedback, setShowFeedback] = useState(false);
|
const [showFeedback, setShowFeedback] = useState(false);
|
||||||
|
const [themeMode, setThemeMode] = useState(resolveMode(darkmode));
|
||||||
|
|
||||||
const context = React.useMemo(
|
const context = React.useMemo(
|
||||||
() => ({
|
() => ({
|
||||||
@ -12,8 +38,10 @@ const UIProvider: React.FC = ({ children }) => {
|
|||||||
toastData,
|
toastData,
|
||||||
showFeedback,
|
showFeedback,
|
||||||
setShowFeedback,
|
setShowFeedback,
|
||||||
|
themeMode,
|
||||||
|
setThemeMode,
|
||||||
}),
|
}),
|
||||||
[toastData, showFeedback]
|
[toastData, showFeedback, themeMode]
|
||||||
);
|
);
|
||||||
|
|
||||||
return <UIContext.Provider value={context}>{children}</UIContext.Provider>;
|
return <UIContext.Provider value={context}>{children}</UIContext.Provider>;
|
||||||
|
@ -0,0 +1,16 @@
|
|||||||
|
import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig';
|
||||||
|
import UIProvider from './UIProvider';
|
||||||
|
|
||||||
|
export const UIProviderContainer: React.FC = ({ children }) => {
|
||||||
|
const { uiConfig } = useUiConfig();
|
||||||
|
|
||||||
|
if (!uiConfig.flags) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<UIProvider darkmode={uiConfig.flags.ENABLE_DARK_MODE_SUPPORT || false}>
|
||||||
|
{children}
|
||||||
|
</UIProvider>
|
||||||
|
);
|
||||||
|
};
|
@ -17,7 +17,7 @@ export const useStyles = makeStyles()(theme => ({
|
|||||||
steps: {
|
steps: {
|
||||||
position: 'relative',
|
position: 'relative',
|
||||||
borderRadius: 10,
|
borderRadius: 10,
|
||||||
background: '#fff',
|
background: theme.palette.background.paper,
|
||||||
padding: '0.6rem 1.5rem',
|
padding: '0.6rem 1.5rem',
|
||||||
margin: 'auto',
|
margin: 'auto',
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
|
@ -13,7 +13,7 @@ test('renders an empty list correctly', () => {
|
|||||||
<MemoryRouter>
|
<MemoryRouter>
|
||||||
<ThemeProvider>
|
<ThemeProvider>
|
||||||
<AnnouncerProvider>
|
<AnnouncerProvider>
|
||||||
<UIProvider>
|
<UIProvider darkmode={false}>
|
||||||
<AccessProviderMock
|
<AccessProviderMock
|
||||||
permissions={[{ permission: ADMIN }]}
|
permissions={[{ permission: ADMIN }]}
|
||||||
>
|
>
|
||||||
|
@ -7,7 +7,7 @@ exports[`renders an empty list correctly 1`] = `
|
|||||||
aria-live="polite"
|
aria-live="polite"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
className="MuiPaper-root MuiPaper-elevation MuiPaper-rounded MuiPaper-elevation1 tss-15wj2kz-container mui-177gdp-MuiPaper-root"
|
className="MuiPaper-root MuiPaper-elevation MuiPaper-rounded MuiPaper-elevation1 tss-15wj2kz-container mui-lorrhs-MuiPaper-root"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
className="header tss-1ywhhai-headerContainer"
|
className="header tss-1ywhhai-headerContainer"
|
||||||
@ -32,7 +32,7 @@ exports[`renders an empty list correctly 1`] = `
|
|||||||
className="tss-u5t8ea-headerActions"
|
className="tss-u5t8ea-headerActions"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
className="tss-119iiqp-container"
|
className="tss-1oozr04-container"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
className="tss-1xjrf9m-search search-container"
|
className="tss-1xjrf9m-search search-container"
|
||||||
@ -49,12 +49,12 @@ exports[`renders an empty list correctly 1`] = `
|
|||||||
/>
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
<div
|
<div
|
||||||
className="MuiInputBase-root tss-11gf6cf-inputRoot input-container MuiInputBase-colorPrimary mui-1v3pvzz-MuiInputBase-root"
|
className="MuiInputBase-root tss-11gf6cf-inputRoot input-container MuiInputBase-colorPrimary mui-qtv7d9-MuiInputBase-root"
|
||||||
onClick={[Function]}
|
onClick={[Function]}
|
||||||
>
|
>
|
||||||
<input
|
<input
|
||||||
aria-label="Search (Ctrl+K)"
|
aria-label="Search (Ctrl+K)"
|
||||||
className="MuiInputBase-input mui-j79lc6-MuiInputBase-input"
|
className="MuiInputBase-input mui-mfsqjb-MuiInputBase-input"
|
||||||
onAnimationStart={[Function]}
|
onAnimationStart={[Function]}
|
||||||
onBlur={[Function]}
|
onBlur={[Function]}
|
||||||
onChange={[Function]}
|
onChange={[Function]}
|
||||||
@ -120,7 +120,7 @@ exports[`renders an empty list correctly 1`] = `
|
|||||||
role={null}
|
role={null}
|
||||||
>
|
>
|
||||||
<tr
|
<tr
|
||||||
className="MuiTableRow-root MuiTableRow-head tss-1sk7xq7-tableHeader mui-cn4v9y-MuiTableRow-root"
|
className="MuiTableRow-root MuiTableRow-head tss-1u2w2tj-tableHeader mui-cn4v9y-MuiTableRow-root"
|
||||||
role="row"
|
role="row"
|
||||||
>
|
>
|
||||||
<th
|
<th
|
||||||
|
@ -17,8 +17,8 @@ const StandaloneBanner: FC<IStandaloneBannerProps> = ({ title, children }) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Gradient
|
<Gradient
|
||||||
from={theme.palette.primary.main}
|
from={theme.palette.standaloneBannerGradient.from}
|
||||||
to="#173341"
|
to={theme.palette.standaloneBannerGradient.to}
|
||||||
className={styles.gradient}
|
className={styles.gradient}
|
||||||
>
|
>
|
||||||
<div className={styles.container}>
|
<div className={styles.container}>
|
||||||
|
@ -75,6 +75,7 @@ const UserProfile = ({
|
|||||||
disableRipple
|
disableRipple
|
||||||
>
|
>
|
||||||
<Avatar
|
<Avatar
|
||||||
|
style={{ backgroundColor: '#fff', padding: '0.15rem' }}
|
||||||
alt="Your Gravatar"
|
alt="Your Gravatar"
|
||||||
src={imageUrl}
|
src={imageUrl}
|
||||||
data-testid={HEADER_USER_AVATAR}
|
data-testid={HEADER_USER_AVATAR}
|
||||||
|
@ -20,6 +20,7 @@ import { basePath } from 'utils/formatPath';
|
|||||||
import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig';
|
import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig';
|
||||||
import { IUser } from 'interfaces/user';
|
import { IUser } from 'interfaces/user';
|
||||||
import { ILocationSettings } from 'hooks/useLocationSettings';
|
import { ILocationSettings } from 'hooks/useLocationSettings';
|
||||||
|
import { useTheme } from '@mui/material/styles';
|
||||||
|
|
||||||
interface IUserProfileContentProps {
|
interface IUserProfileContentProps {
|
||||||
id: string;
|
id: string;
|
||||||
@ -45,6 +46,8 @@ const UserProfileContent = ({
|
|||||||
setLocationSettings,
|
setLocationSettings,
|
||||||
}: IUserProfileContentProps) => {
|
}: IUserProfileContentProps) => {
|
||||||
const { classes: themeStyles } = useThemeStyles();
|
const { classes: themeStyles } = useThemeStyles();
|
||||||
|
const theme = useTheme();
|
||||||
|
|
||||||
const { uiConfig } = useUiConfig();
|
const { uiConfig } = useUiConfig();
|
||||||
const [updatedPassword, setUpdatedPassword] = useState(false);
|
const [updatedPassword, setUpdatedPassword] = useState(false);
|
||||||
const [editingProfile, setEditingProfile] = useState(false);
|
const [editingProfile, setEditingProfile] = useState(false);
|
||||||
@ -121,7 +124,11 @@ const UserProfileContent = ({
|
|||||||
>
|
>
|
||||||
<InputLabel
|
<InputLabel
|
||||||
htmlFor="locale-select"
|
htmlFor="locale-select"
|
||||||
style={{ backgroundColor: '#fff' }}
|
style={{
|
||||||
|
backgroundColor:
|
||||||
|
theme.palette
|
||||||
|
.inputLabelBackground,
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
Date/Time formatting
|
Date/Time formatting
|
||||||
</InputLabel>
|
</InputLabel>
|
||||||
|
@ -3,7 +3,7 @@ import { makeStyles } from 'tss-react/mui';
|
|||||||
export const useStyles = makeStyles()(theme => ({
|
export const useStyles = makeStyles()(theme => ({
|
||||||
container: {
|
container: {
|
||||||
padding: '5.5rem',
|
padding: '5.5rem',
|
||||||
background: '#EFF2F2',
|
background: theme.palette.standaloneBackground,
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
[theme.breakpoints.down('md')]: {
|
[theme.breakpoints.down('md')]: {
|
||||||
flexDirection: 'column',
|
flexDirection: 'column',
|
||||||
@ -27,7 +27,7 @@ export const useStyles = makeStyles()(theme => ({
|
|||||||
flex: '1',
|
flex: '1',
|
||||||
borderTopRightRadius: '3px',
|
borderTopRightRadius: '3px',
|
||||||
borderBottomRightRadius: '3px',
|
borderBottomRightRadius: '3px',
|
||||||
backgroundColor: '#fff',
|
backgroundColor: theme.palette.background.paper,
|
||||||
position: 'relative',
|
position: 'relative',
|
||||||
[theme.breakpoints.down('md')]: {
|
[theme.breakpoints.down('md')]: {
|
||||||
borderRadius: '0',
|
borderRadius: '0',
|
||||||
|
@ -6,8 +6,12 @@ interface IUIContext {
|
|||||||
setToast: React.Dispatch<React.SetStateAction<IToast>>;
|
setToast: React.Dispatch<React.SetStateAction<IToast>>;
|
||||||
showFeedback: boolean;
|
showFeedback: boolean;
|
||||||
setShowFeedback: React.Dispatch<React.SetStateAction<boolean>>;
|
setShowFeedback: React.Dispatch<React.SetStateAction<boolean>>;
|
||||||
|
setThemeMode: React.Dispatch<React.SetStateAction<themeMode>>;
|
||||||
|
themeMode: themeMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type themeMode = 'light' | 'dark';
|
||||||
|
|
||||||
export const createEmptyToast = (): IToast => {
|
export const createEmptyToast = (): IToast => {
|
||||||
return {
|
return {
|
||||||
type: 'success',
|
type: 'success',
|
||||||
@ -27,11 +31,17 @@ const setShowFeedbackPlaceholder = () => {
|
|||||||
throw new Error('setShowFeedback called outside UIContext');
|
throw new Error('setShowFeedback called outside UIContext');
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const setThemeModePlaceholder = () => {
|
||||||
|
throw new Error('setMode called outside UIContext');
|
||||||
|
};
|
||||||
|
|
||||||
const UIContext = React.createContext<IUIContext>({
|
const UIContext = React.createContext<IUIContext>({
|
||||||
toastData: createEmptyToast(),
|
toastData: createEmptyToast(),
|
||||||
setToast: setToastPlaceholder,
|
setToast: setToastPlaceholder,
|
||||||
showFeedback: false,
|
showFeedback: false,
|
||||||
setShowFeedback: setShowFeedbackPlaceholder,
|
setShowFeedback: setShowFeedbackPlaceholder,
|
||||||
|
themeMode: 'light',
|
||||||
|
setThemeMode: setThemeModePlaceholder,
|
||||||
});
|
});
|
||||||
|
|
||||||
export default UIContext;
|
export default UIContext;
|
||||||
|
37
frontend/src/hooks/useThemeMode.ts
Normal file
37
frontend/src/hooks/useThemeMode.ts
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
import UIContext, { themeMode } from 'contexts/UIContext';
|
||||||
|
import { useContext } from 'react';
|
||||||
|
import { setLocalStorageItem } from 'utils/storage';
|
||||||
|
import mainTheme from 'themes/theme';
|
||||||
|
import darkTheme from 'themes/dark-theme';
|
||||||
|
import { Theme } from '@emotion/react';
|
||||||
|
|
||||||
|
interface IUseThemeModeOutput {
|
||||||
|
resolveTheme: () => Theme;
|
||||||
|
onSetThemeMode: () => void;
|
||||||
|
themeMode: themeMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useThemeMode = (): IUseThemeModeOutput => {
|
||||||
|
const { themeMode, setThemeMode } = useContext(UIContext);
|
||||||
|
|
||||||
|
const resolveTheme = () => {
|
||||||
|
if (themeMode === 'light') {
|
||||||
|
return mainTheme;
|
||||||
|
}
|
||||||
|
|
||||||
|
return darkTheme;
|
||||||
|
};
|
||||||
|
|
||||||
|
const onSetThemeMode = () => {
|
||||||
|
setThemeMode((prev: themeMode) => {
|
||||||
|
if (prev === 'light') {
|
||||||
|
setLocalStorageItem('unleash-theme', 'dark');
|
||||||
|
return 'dark';
|
||||||
|
}
|
||||||
|
setLocalStorageItem('unleash-theme', 'light');
|
||||||
|
return 'light';
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
return { resolveTheme, onSetThemeMode, themeMode };
|
||||||
|
};
|
@ -10,12 +10,12 @@ import { ScrollTop } from 'component/common/ScrollTop/ScrollTop';
|
|||||||
import { AccessProvider } from 'component/providers/AccessProvider/AccessProvider';
|
import { AccessProvider } from 'component/providers/AccessProvider/AccessProvider';
|
||||||
import { basePath } from 'utils/formatPath';
|
import { basePath } from 'utils/formatPath';
|
||||||
import { FeedbackCESProvider } from 'component/feedback/FeedbackCESContext/FeedbackCESProvider';
|
import { FeedbackCESProvider } from 'component/feedback/FeedbackCESContext/FeedbackCESProvider';
|
||||||
import UIProvider from 'component/providers/UIProvider/UIProvider';
|
|
||||||
import { AnnouncerProvider } from 'component/common/Announcer/AnnouncerProvider/AnnouncerProvider';
|
import { AnnouncerProvider } from 'component/common/Announcer/AnnouncerProvider/AnnouncerProvider';
|
||||||
import { InstanceStatus } from 'component/common/InstanceStatus/InstanceStatus';
|
import { InstanceStatus } from 'component/common/InstanceStatus/InstanceStatus';
|
||||||
|
import { UIProviderContainer } from 'component/providers/UIProvider/UIProviderContainer';
|
||||||
|
|
||||||
ReactDOM.render(
|
ReactDOM.render(
|
||||||
<UIProvider>
|
<UIProviderContainer>
|
||||||
<AccessProvider>
|
<AccessProvider>
|
||||||
<BrowserRouter basename={basePath}>
|
<BrowserRouter basename={basePath}>
|
||||||
<ThemeProvider>
|
<ThemeProvider>
|
||||||
@ -30,6 +30,6 @@ ReactDOM.render(
|
|||||||
</ThemeProvider>
|
</ThemeProvider>
|
||||||
</BrowserRouter>
|
</BrowserRouter>
|
||||||
</AccessProvider>
|
</AccessProvider>
|
||||||
</UIProvider>,
|
</UIProviderContainer>,
|
||||||
document.getElementById('app')
|
document.getElementById('app')
|
||||||
);
|
);
|
||||||
|
@ -39,6 +39,7 @@ export interface IFlags {
|
|||||||
T?: boolean;
|
T?: boolean;
|
||||||
UNLEASH_CLOUD?: boolean;
|
UNLEASH_CLOUD?: boolean;
|
||||||
UG?: boolean;
|
UG?: boolean;
|
||||||
|
ENABLE_DARK_MODE_SUPPORT?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IVersionInfo {
|
export interface IVersionInfo {
|
||||||
|
@ -1,19 +1,24 @@
|
|||||||
import React, { FC } from 'react';
|
import React, { FC } from 'react';
|
||||||
import { CssBaseline, ThemeProvider as MuiThemeProvider } from '@mui/material';
|
import { CssBaseline, ThemeProvider as MuiThemeProvider } from '@mui/material';
|
||||||
import mainTheme from 'themes/theme';
|
|
||||||
import createCache from '@emotion/cache';
|
import createCache from '@emotion/cache';
|
||||||
import { CacheProvider } from '@emotion/react';
|
import { CacheProvider } from '@emotion/react';
|
||||||
|
import { useThemeMode } from 'hooks/useThemeMode';
|
||||||
|
|
||||||
export const muiCache = createCache({
|
export const muiCache = createCache({
|
||||||
key: 'mui',
|
key: 'mui',
|
||||||
prepend: true,
|
prepend: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
export const ThemeProvider: FC = ({ children }) => (
|
export const ThemeProvider: FC = ({ children }) => {
|
||||||
<CacheProvider value={muiCache}>
|
const { resolveTheme } = useThemeMode();
|
||||||
<MuiThemeProvider theme={mainTheme}>
|
|
||||||
<CssBaseline />
|
return (
|
||||||
{children}
|
<CacheProvider value={muiCache}>
|
||||||
</MuiThemeProvider>
|
<MuiThemeProvider theme={resolveTheme()}>
|
||||||
</CacheProvider>
|
<CssBaseline />
|
||||||
);
|
{children}
|
||||||
|
</MuiThemeProvider>
|
||||||
|
</CacheProvider>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
@ -17,10 +17,6 @@ button {
|
|||||||
font-family: 'Sen', sans-serif;
|
font-family: 'Sen', sans-serif;
|
||||||
}
|
}
|
||||||
|
|
||||||
.MuiInputBase-root {
|
|
||||||
background-color: #fff;
|
|
||||||
}
|
|
||||||
|
|
||||||
.MuiAccordion-root.Mui-expanded {
|
.MuiAccordion-root.Mui-expanded {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
|
@ -78,4 +78,12 @@ export const colors = {
|
|||||||
100: '#DCEEFA',
|
100: '#DCEEFA',
|
||||||
50: '#EBF7FF',
|
50: '#EBF7FF',
|
||||||
},
|
},
|
||||||
|
darkblue: {
|
||||||
|
1000: '#091826',
|
||||||
|
900: '#041c32',
|
||||||
|
800: '#1d3247',
|
||||||
|
700: '#28415c',
|
||||||
|
600: '#1f3751',
|
||||||
|
500: '#0e2840',
|
||||||
|
},
|
||||||
} as const;
|
} as const;
|
||||||
|
418
frontend/src/themes/dark-theme.ts
Normal file
418
frontend/src/themes/dark-theme.ts
Normal file
@ -0,0 +1,418 @@
|
|||||||
|
import { createTheme } from '@mui/material/styles';
|
||||||
|
import { colors } from './colors';
|
||||||
|
|
||||||
|
const themeColors = {
|
||||||
|
main: colors.darkblue[900],
|
||||||
|
secondary: colors.darkblue[800],
|
||||||
|
textColor: '#ffffffe6',
|
||||||
|
hover: 'rgb(255, 255, 255, 0.7)',
|
||||||
|
};
|
||||||
|
|
||||||
|
export default createTheme({
|
||||||
|
breakpoints: {
|
||||||
|
values: {
|
||||||
|
xs: 0,
|
||||||
|
sm: 600,
|
||||||
|
md: 960,
|
||||||
|
lg: 1260,
|
||||||
|
xl: 1536,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
boxShadows: {
|
||||||
|
main: '0px 2px 4px rgba(129, 122, 254, 0.2)',
|
||||||
|
card: '0px 2px 10px rgba(28, 25, 78, 0.12)',
|
||||||
|
elevated: '0px 1px 20px rgba(45, 42, 89, 0.1)',
|
||||||
|
},
|
||||||
|
typography: {
|
||||||
|
fontFamily: 'Sen, Roboto, sans-serif',
|
||||||
|
fontWeightBold: '700',
|
||||||
|
fontWeightMedium: '700',
|
||||||
|
allVariants: { lineHeight: 1.4 },
|
||||||
|
button: { lineHeight: 1.75 },
|
||||||
|
h1: {
|
||||||
|
fontSize: '1.5rem',
|
||||||
|
lineHeight: 1.875,
|
||||||
|
},
|
||||||
|
h3: {
|
||||||
|
fontSize: '1rem',
|
||||||
|
fontWeight: '700',
|
||||||
|
},
|
||||||
|
caption: {
|
||||||
|
fontSize: `${12 / 16}rem`,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
fontSizes: {
|
||||||
|
mainHeader: '1.25rem',
|
||||||
|
bodySize: '1rem',
|
||||||
|
smallBody: `${14 / 16}rem`,
|
||||||
|
smallerBody: `${12 / 16}rem`,
|
||||||
|
},
|
||||||
|
fontWeight: {
|
||||||
|
thin: 300,
|
||||||
|
medium: 400,
|
||||||
|
semi: 700,
|
||||||
|
bold: 700,
|
||||||
|
},
|
||||||
|
shape: {
|
||||||
|
borderRadius: 4,
|
||||||
|
borderRadiusMedium: 8,
|
||||||
|
borderRadiusLarge: 12,
|
||||||
|
borderRadiusExtraLarge: 20,
|
||||||
|
tableRowHeight: 64,
|
||||||
|
tableRowHeightCompact: 56,
|
||||||
|
tableRowHeightDense: 48,
|
||||||
|
},
|
||||||
|
palette: {
|
||||||
|
primary: {
|
||||||
|
main: themeColors.textColor,
|
||||||
|
light: colors.purple[700],
|
||||||
|
dark: colors.purple[900],
|
||||||
|
},
|
||||||
|
secondary: {
|
||||||
|
main: colors.purple[800],
|
||||||
|
light: colors.purple[700],
|
||||||
|
dark: colors.purple[900],
|
||||||
|
},
|
||||||
|
info: {
|
||||||
|
light: colors.blue[50],
|
||||||
|
main: colors.blue[500],
|
||||||
|
dark: colors.blue[700],
|
||||||
|
border: colors.blue[200],
|
||||||
|
},
|
||||||
|
success: {
|
||||||
|
light: colors.green[50],
|
||||||
|
main: colors.green[600],
|
||||||
|
dark: themeColors.main,
|
||||||
|
border: colors.green[300],
|
||||||
|
},
|
||||||
|
warning: {
|
||||||
|
light: colors.orange[100],
|
||||||
|
main: colors.orange[800],
|
||||||
|
dark: colors.orange[900],
|
||||||
|
border: colors.orange[500],
|
||||||
|
},
|
||||||
|
error: {
|
||||||
|
light: colors.red[50],
|
||||||
|
main: colors.red[700],
|
||||||
|
dark: colors.red[800],
|
||||||
|
border: colors.red[300],
|
||||||
|
},
|
||||||
|
background: {
|
||||||
|
paper: themeColors.main,
|
||||||
|
},
|
||||||
|
divider: themeColors.secondary,
|
||||||
|
dividerAlternative: colors.grey[400],
|
||||||
|
tableHeaderHover: colors.darkblue[700],
|
||||||
|
tableHeaderBackground: themeColors.secondary,
|
||||||
|
tableHeaderColor: themeColors.textColor,
|
||||||
|
highlight: '#FFEACC',
|
||||||
|
secondaryContainer: themeColors.secondary,
|
||||||
|
contentWrapper: colors.darkblue[800],
|
||||||
|
formBackground: themeColors.main,
|
||||||
|
formSidebar: colors.darkblue[1000],
|
||||||
|
headerBackground: themeColors.main,
|
||||||
|
footerBackground: themeColors.main,
|
||||||
|
sidebarContainer: 'rgba(32,32,33, 0.2)',
|
||||||
|
codebox: colors.darkblue[600],
|
||||||
|
featureMetaData: colors.darkblue[1000],
|
||||||
|
playgroundBackground: colors.darkblue[600],
|
||||||
|
playgroundFormBackground: themeColors.secondary,
|
||||||
|
standaloneBackground: colors.black,
|
||||||
|
featureStrategySegmentChipBackground: themeColors.secondary,
|
||||||
|
featureSegmentSearchBackground: themeColors.secondary,
|
||||||
|
dialogHeaderBackground: themeColors.secondary,
|
||||||
|
dialogHeaderText: themeColors.textColor,
|
||||||
|
lightBorder: colors.darkblue[500],
|
||||||
|
constraintAccordion: {
|
||||||
|
editBackground: colors.darkblue[600],
|
||||||
|
background: themeColors.secondary,
|
||||||
|
operatorBackground: themeColors.main,
|
||||||
|
},
|
||||||
|
standaloneBannerGradient: {
|
||||||
|
from: colors.darkblue[1000],
|
||||||
|
to: colors.black,
|
||||||
|
},
|
||||||
|
projectCard: {
|
||||||
|
hover: themeColors.secondary,
|
||||||
|
textColor: themeColors.textColor,
|
||||||
|
},
|
||||||
|
formSidebarTextColor: themeColors.textColor,
|
||||||
|
checkmarkBadge: themeColors.secondary,
|
||||||
|
inputLabelBackground: 'transparent',
|
||||||
|
featureMetricsBackground: themeColors.secondary,
|
||||||
|
grey: colors.grey,
|
||||||
|
text: {
|
||||||
|
primary: themeColors.textColor,
|
||||||
|
secondary: colors.grey[800],
|
||||||
|
disabled: colors.grey[600],
|
||||||
|
},
|
||||||
|
code: {
|
||||||
|
main: '#0b8c8f',
|
||||||
|
diffAdd: 'green',
|
||||||
|
diffSub: 'red',
|
||||||
|
diffNeutral: 'black',
|
||||||
|
edited: 'blue',
|
||||||
|
},
|
||||||
|
neutral: {
|
||||||
|
light: colors.darkblue[500],
|
||||||
|
main: colors.grey[700],
|
||||||
|
dark: colors.grey[800],
|
||||||
|
border: colors.grey[500],
|
||||||
|
},
|
||||||
|
activityIndicators: {
|
||||||
|
primary: themeColors.secondary,
|
||||||
|
unknown: themeColors.secondary,
|
||||||
|
recent: themeColors.secondary,
|
||||||
|
inactive: themeColors.secondary,
|
||||||
|
abandoned: themeColors.secondary,
|
||||||
|
},
|
||||||
|
tertiary: {
|
||||||
|
light: themeColors.secondary,
|
||||||
|
main: colors.grey[400],
|
||||||
|
dark: colors.grey[600],
|
||||||
|
background: 'white',
|
||||||
|
contrast: colors.grey[300],
|
||||||
|
},
|
||||||
|
inactiveIcon: colors.grey[600],
|
||||||
|
},
|
||||||
|
components: {
|
||||||
|
MuiAppBar: {
|
||||||
|
styleOverrides: {
|
||||||
|
root: {
|
||||||
|
color: themeColors.textColor,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
MuiInputLabel: {
|
||||||
|
styleOverrides: {
|
||||||
|
root: {
|
||||||
|
color: themeColors.textColor,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
MuiIconButton: {
|
||||||
|
styleOverrides: {
|
||||||
|
root: {
|
||||||
|
color: colors.white,
|
||||||
|
'&:hover': {
|
||||||
|
backgroundColor: themeColors.hover,
|
||||||
|
},
|
||||||
|
'&.Mui-disabled': {
|
||||||
|
'& .MuiSvgIcon-root': {
|
||||||
|
color: colors.grey[700],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
MuiLink: {
|
||||||
|
styleOverrides: {
|
||||||
|
root: {
|
||||||
|
color: colors.white,
|
||||||
|
'&:hover': {
|
||||||
|
textDecoration: 'none',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
MuiBreadcrumbs: {
|
||||||
|
styleOverrides: {
|
||||||
|
root: {
|
||||||
|
color: themeColors.textColor,
|
||||||
|
fontSize: '0.875rem',
|
||||||
|
'& a': {
|
||||||
|
color: themeColors.textColor,
|
||||||
|
textDecoration: 'underline',
|
||||||
|
'&:hover': {
|
||||||
|
textDecoration: 'none',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
MuiTableHead: {
|
||||||
|
styleOverrides: {
|
||||||
|
root: {
|
||||||
|
background: 'transparent',
|
||||||
|
'& th': {
|
||||||
|
background: colors.grey[200],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
MuiTableRow: {
|
||||||
|
styleOverrides: {
|
||||||
|
root: {
|
||||||
|
'&.MuiTableRow-hover:hover': {
|
||||||
|
background: themeColors.secondary,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
MuiTableCell: {
|
||||||
|
styleOverrides: {
|
||||||
|
root: {
|
||||||
|
borderBottomColor: themeColors.main,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
MuiAlert: {
|
||||||
|
styleOverrides: {
|
||||||
|
root: {
|
||||||
|
borderRadius: '8px',
|
||||||
|
a: {
|
||||||
|
color: 'inherit',
|
||||||
|
},
|
||||||
|
'&.MuiAlert-standardInfo': {
|
||||||
|
backgroundColor: colors.blue[50],
|
||||||
|
color: colors.blue[700],
|
||||||
|
border: `1px solid ${colors.blue[200]}`,
|
||||||
|
'& .MuiAlert-icon .MuiSvgIcon-root': {
|
||||||
|
color: colors.blue[500],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'&.MuiAlert-standardSuccess': {
|
||||||
|
backgroundColor: colors.green[50],
|
||||||
|
color: colors.green[800],
|
||||||
|
border: `1px solid ${colors.green[300]}`,
|
||||||
|
'& .MuiAlert-icon .MuiSvgIcon-root': {
|
||||||
|
color: colors.green[500],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'&.MuiAlert-standardWarning': {
|
||||||
|
backgroundColor: colors.orange[100],
|
||||||
|
color: colors.orange[900],
|
||||||
|
border: `1px solid ${colors.orange[500]}`,
|
||||||
|
'& .MuiAlert-icon .MuiSvgIcon-root': {
|
||||||
|
color: colors.orange[800],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'&.MuiAlert-standardError': {
|
||||||
|
backgroundColor: colors.red[50],
|
||||||
|
color: colors.red[800],
|
||||||
|
border: `1px solid ${colors.red[300]}`,
|
||||||
|
'& .MuiAlert-icon .MuiSvgIcon-root': {
|
||||||
|
color: colors.red[700],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
MuiButton: {
|
||||||
|
styleOverrides: {
|
||||||
|
root: {
|
||||||
|
'&.Mui-disabled': {
|
||||||
|
backgroundColor: colors.grey[400],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
MuiSvgIcon: {
|
||||||
|
styleOverrides: {
|
||||||
|
root: {
|
||||||
|
color: themeColors.textColor,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
MuiTabs: {
|
||||||
|
styleOverrides: {
|
||||||
|
root: {
|
||||||
|
backgroundColor: themeColors.main,
|
||||||
|
color: themeColors.textColor,
|
||||||
|
'& .MuiTabs-indicator': {
|
||||||
|
height: '4px',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
MuiTab: {
|
||||||
|
styleOverrides: {
|
||||||
|
root: {
|
||||||
|
color: themeColors.textColor,
|
||||||
|
fontSize: '1rem',
|
||||||
|
textTransform: 'none',
|
||||||
|
fontWeight: 400,
|
||||||
|
minHeight: '62px',
|
||||||
|
'&:hover': {
|
||||||
|
backgroundColor: themeColors.secondary,
|
||||||
|
},
|
||||||
|
'&.Mui-selected': {
|
||||||
|
color: themeColors.textColor,
|
||||||
|
fontWeight: 700,
|
||||||
|
},
|
||||||
|
'& > span': {
|
||||||
|
color: colors.purple[900],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
MuiAccordionSummary: {
|
||||||
|
styleOverrides: {
|
||||||
|
root: {
|
||||||
|
'& > .MuiAccordionSummary-content.Mui-expanded': {
|
||||||
|
margin: '12px 0',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
MuiSwitch: {
|
||||||
|
styleOverrides: {
|
||||||
|
switchBase: {
|
||||||
|
zIndex: 1,
|
||||||
|
'&:not(.Mui-checked) .MuiTouchRipple-child': {
|
||||||
|
color: colors.grey['500'],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
MuiIcon: {
|
||||||
|
styleOverrides: {
|
||||||
|
root: {
|
||||||
|
color: colors.white,
|
||||||
|
},
|
||||||
|
colorDisabled: {
|
||||||
|
color: colors.white[600],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
MuiMenu: {
|
||||||
|
styleOverrides: {
|
||||||
|
root: {
|
||||||
|
'.MuiMenu-list': {
|
||||||
|
backgroundColor: colors.darkblue[600],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
MuiMenuItem: {
|
||||||
|
styleOverrides: {
|
||||||
|
root: {
|
||||||
|
'&.Mui-disabled': {
|
||||||
|
opacity: 0.66,
|
||||||
|
},
|
||||||
|
'&:hover': {
|
||||||
|
backgroundColor: themeColors.secondary,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
MuiInputBase: {
|
||||||
|
styleOverrides: {
|
||||||
|
root: {
|
||||||
|
backgroundColor: colors.darkblue[1000],
|
||||||
|
'.MuiSvgIcon-root': {
|
||||||
|
color: '#fff',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
MuiPaper: {
|
||||||
|
styleOverrides: {
|
||||||
|
root: {
|
||||||
|
backgroundColor: themeColors.main,
|
||||||
|
color: themeColors.textColor,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
@ -107,9 +107,42 @@ export default createTheme({
|
|||||||
divider: colors.grey[300],
|
divider: colors.grey[300],
|
||||||
dividerAlternative: colors.grey[400],
|
dividerAlternative: colors.grey[400],
|
||||||
tableHeaderHover: colors.grey[400],
|
tableHeaderHover: colors.grey[400],
|
||||||
|
tableHeaderBackground: colors.grey[200],
|
||||||
|
tableHeaderColor: colors.grey[900],
|
||||||
|
formSidebarTextColor: colors.white,
|
||||||
highlight: '#FFEACC',
|
highlight: '#FFEACC',
|
||||||
secondaryContainer: colors.grey[200],
|
secondaryContainer: colors.grey[200],
|
||||||
|
contentWrapper: colors.grey[300],
|
||||||
|
headerBackground: colors.white,
|
||||||
|
footerBackground: colors.white,
|
||||||
|
formBackground: colors.white,
|
||||||
|
formSidebar: colors.purple[800],
|
||||||
|
featureMetaData: colors.purple[800],
|
||||||
|
codebox: 'rgba(32,32,33, 0.2)',
|
||||||
sidebarContainer: 'rgba(32,32,33, 0.2)',
|
sidebarContainer: 'rgba(32,32,33, 0.2)',
|
||||||
|
playgroundBackground: colors.grey[200],
|
||||||
|
playgroundFormBackground: colors.grey[200],
|
||||||
|
standaloneBackground: colors.grey[300],
|
||||||
|
constraintAccordion: {
|
||||||
|
editBackground: '#F6F6FA',
|
||||||
|
background: colors.white,
|
||||||
|
operatorBackground: colors.grey[200],
|
||||||
|
},
|
||||||
|
projectCard: {
|
||||||
|
hover: colors.grey[100],
|
||||||
|
textColor: '#4A4599',
|
||||||
|
},
|
||||||
|
standaloneBannerGradient: {
|
||||||
|
from: colors.purple[900],
|
||||||
|
to: '#173341',
|
||||||
|
},
|
||||||
|
checkmarkBadge: colors.purple[800],
|
||||||
|
inputLabelBackground: colors.white,
|
||||||
|
featureMetricsBackground: colors.grey[100],
|
||||||
|
featureStrategySegmentChipBackground: colors.purple[800],
|
||||||
|
featureSegmentSearchBackground: colors.purple[800],
|
||||||
|
dialogHeaderBackground: colors.purple[800],
|
||||||
|
dialogHeaderText: '#ffffffe6',
|
||||||
grey: colors.grey,
|
grey: colors.grey,
|
||||||
lightBorder: colors.grey[400],
|
lightBorder: colors.grey[400],
|
||||||
text: {
|
text: {
|
||||||
@ -333,5 +366,26 @@ export default createTheme({
|
|||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
MuiInputBase: {
|
||||||
|
styleOverrides: {
|
||||||
|
root: {
|
||||||
|
backgroundColor: '#fff',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
MuiPaper: {
|
||||||
|
styleOverrides: {
|
||||||
|
root: {
|
||||||
|
backgroundColor: '#fff',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
MuiAppBar: {
|
||||||
|
styleOverrides: {
|
||||||
|
root: {
|
||||||
|
color: colors.black,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
@ -54,10 +54,44 @@ declare module '@mui/material/styles' {
|
|||||||
primary: string;
|
primary: string;
|
||||||
};
|
};
|
||||||
dividerAlternative: string;
|
dividerAlternative: string;
|
||||||
|
contentWrapper: string;
|
||||||
|
headerBackground: string;
|
||||||
|
footerBackground: string;
|
||||||
|
codebox: string;
|
||||||
|
featureMetaData: string;
|
||||||
|
playgroundBackground: string;
|
||||||
|
playgroundFormBackground: string;
|
||||||
|
standaloneBackground: string;
|
||||||
|
standaloneBannerGradient: {
|
||||||
|
from: string;
|
||||||
|
to: string;
|
||||||
|
};
|
||||||
|
featureMetricsBackground: string;
|
||||||
|
constraintAccordion: {
|
||||||
|
editBackground: string;
|
||||||
|
background: string;
|
||||||
|
operatorBackground: string;
|
||||||
|
};
|
||||||
|
projectCard: {
|
||||||
|
hover: string;
|
||||||
|
textColor: string;
|
||||||
|
};
|
||||||
|
checkmarkBadge: string;
|
||||||
|
inputLabelBackground: string;
|
||||||
|
featureStrategySegmentChipBackground: string;
|
||||||
|
featureSegmentSearchBackground: string;
|
||||||
|
dialogHeaderBackground: string;
|
||||||
|
dialogHeaderText: string;
|
||||||
|
formSidebarTextColor: string;
|
||||||
/**
|
/**
|
||||||
* For table header hover effect.
|
* For table header hover effect.
|
||||||
*/
|
*/
|
||||||
|
tableHeaderBackground: string;
|
||||||
tableHeaderHover: string;
|
tableHeaderHover: string;
|
||||||
|
tableHeaderColor: string;
|
||||||
|
|
||||||
|
formBackground: string;
|
||||||
|
formSidebar: string;
|
||||||
/**
|
/**
|
||||||
* Text highlight effect color. Used when filtering/searching over content.
|
* Text highlight effect color. Used when filtering/searching over content.
|
||||||
*/
|
*/
|
||||||
|
@ -2447,6 +2447,22 @@
|
|||||||
"@codemirror/state" "^6.0.0"
|
"@codemirror/state" "^6.0.0"
|
||||||
"@codemirror/view" "^6.0.0"
|
"@codemirror/view" "^6.0.0"
|
||||||
|
|
||||||
|
"@uiw/codemirror-theme-duotone@^4.11.5":
|
||||||
|
version "4.11.5"
|
||||||
|
resolved "https://registry.yarnpkg.com/@uiw/codemirror-theme-duotone/-/codemirror-theme-duotone-4.11.5.tgz#12df3666337f757253f810fc4e61c8bc887e40c6"
|
||||||
|
integrity sha512-5Ea9naIp/KM6jZjog7tChdOjEPQgeKwSDuCh+TY1lQyt5YJS5P3eZSZq68KNZlwuBHj2c53h069brMnhguTFag==
|
||||||
|
dependencies:
|
||||||
|
"@uiw/codemirror-themes" "4.11.5"
|
||||||
|
|
||||||
|
"@uiw/codemirror-themes@4.11.5":
|
||||||
|
version "4.11.5"
|
||||||
|
resolved "https://registry.yarnpkg.com/@uiw/codemirror-themes/-/codemirror-themes-4.11.5.tgz#15926e65129b41c9ec607065416fc829970e122a"
|
||||||
|
integrity sha512-f2i3yGPzxmCsvx4t6HHykcEhAxbI4GDAMzdFtQfFYMuu1F5sQP43JQvBC8ESflYk05QmE9rCWWZZpvOathLzVw==
|
||||||
|
dependencies:
|
||||||
|
"@codemirror/language" "^6.0.0"
|
||||||
|
"@codemirror/state" "^6.0.0"
|
||||||
|
"@codemirror/view" "^6.0.0"
|
||||||
|
|
||||||
"@uiw/react-codemirror@4.11.4":
|
"@uiw/react-codemirror@4.11.4":
|
||||||
version "4.11.4"
|
version "4.11.4"
|
||||||
resolved "https://registry.yarnpkg.com/@uiw/react-codemirror/-/react-codemirror-4.11.4.tgz#76adc757baa0b8b1a9bd30d7081f5622b896d607"
|
resolved "https://registry.yarnpkg.com/@uiw/react-codemirror/-/react-codemirror-4.11.4.tgz#76adc757baa0b8b1a9bd30d7081f5622b896d607"
|
||||||
|
Loading…
Reference in New Issue
Block a user