mirror of
https://github.com/hanzoai/sentinel.git
synced 2026-09-29 22:34:33 +00:00
1010 lines
24 KiB
TypeScript
1010 lines
24 KiB
TypeScript
import {css} from '@emotion/react';
|
||
import color from 'color';
|
||
|
||
import {DATA_CATEGORY_INFO} from 'sentry/constants';
|
||
import {CHART_PALETTE} from 'sentry/constants/chartPalette';
|
||
import {Outcome} from 'sentry/types';
|
||
|
||
/**
|
||
* Exporting for use in Storybook only. Do not import this
|
||
* anywhere else! Instead, use the theme prop or import useTheme.
|
||
*/
|
||
export const lightColors = {
|
||
black: '#1D1127',
|
||
white: '#FFFFFF',
|
||
|
||
lightModeBlack: '#1D1127',
|
||
lightModeWhite: '#FFFFFF',
|
||
|
||
surface100: '#F5F3F7',
|
||
surface200: '#FAF9FB',
|
||
surface300: '#FFFFFF',
|
||
surface400: '#FFFFFF',
|
||
|
||
/**
|
||
* Hover color. Deprecated – use <InteractionStateLayer /> instead for interaction
|
||
* (hover/press) states.
|
||
* @deprecated
|
||
*/
|
||
surface500: '#F5F3F7',
|
||
|
||
gray500: '#2B2233',
|
||
gray400: '#3E3446',
|
||
gray300: '#80708F',
|
||
gray200: '#E0DCE5',
|
||
gray100: '#F0ECF3',
|
||
|
||
/**
|
||
* Alternative version of gray200 that's translucent.
|
||
* Useful for borders on tooltips, popovers, and dialogs.
|
||
*/
|
||
translucentGray200: 'rgba(58, 17, 95, 0.14)',
|
||
translucentGray100: 'rgba(45, 0, 85, 0.06)',
|
||
|
||
purple400: '#584AC0',
|
||
purple300: '#6C5FC7',
|
||
purple200: 'rgba(108, 95, 199, 0.5)',
|
||
purple100: 'rgba(108, 95, 199, 0.08)',
|
||
|
||
blue400: '#2562D4',
|
||
blue300: '#3C74DD',
|
||
blue200: 'rgba(60, 116, 221, 0.5)',
|
||
blue100: 'rgba(60, 116, 221, 0.09)',
|
||
|
||
green400: '#268D75',
|
||
green300: '#2BA185',
|
||
green200: 'rgba(43, 161, 133, 0.55)',
|
||
green100: 'rgba(43, 161, 133, 0.13)',
|
||
|
||
yellow400: '#E5A500',
|
||
yellow300: '#F5B000',
|
||
yellow200: 'rgba(245, 176, 0, 0.55)',
|
||
yellow100: 'rgba(245, 176, 0, 0.08)',
|
||
|
||
red400: '#DF3338',
|
||
red300: '#F55459',
|
||
red200: 'rgba(245, 84, 89, 0.5)',
|
||
red100: 'rgba(245, 84, 89, 0.09)',
|
||
|
||
pink400: '#E50675',
|
||
pink300: '#F14499',
|
||
pink200: 'rgba(249, 26, 138, 0.5)',
|
||
pink100: 'rgba(249, 26, 138, 0.1)',
|
||
};
|
||
|
||
/**
|
||
* Exporting for use in Storybook only. Do not import this
|
||
* anywhere else! Instead, use the theme prop or import useTheme.
|
||
*/
|
||
export const darkColors = {
|
||
black: '#1D1127',
|
||
white: '#FFFFFF',
|
||
|
||
lightModeBlack: '#FFFFFF',
|
||
lightModeWhite: '#1D1127',
|
||
|
||
surface100: '#18121C',
|
||
surface200: '#1A141F',
|
||
surface300: '#241D2A',
|
||
surface400: '#2C2433',
|
||
|
||
/**
|
||
* Hover color. Deprecated – use <InteractionStateLayer /> instead for interaction
|
||
* (hover/press) states.
|
||
* @deprecated
|
||
*/
|
||
surface500: '#362E3E',
|
||
|
||
gray500: '#EBE6EF',
|
||
gray400: '#D6D0DC',
|
||
gray300: '#998DA5',
|
||
gray200: '#393041',
|
||
gray100: '#302735',
|
||
|
||
/**
|
||
* Alternative version of gray200 that's translucent.
|
||
* Useful for borders on tooltips, popovers, and dialogs.
|
||
*/
|
||
translucentGray200: 'rgba(218, 184, 245, 0.16)',
|
||
translucentGray100: 'rgba(208, 168, 240, 0.07)',
|
||
|
||
purple400: '#A397F7',
|
||
purple300: '#7669D3',
|
||
purple200: 'rgba(118, 105, 211, 0.27)',
|
||
purple100: 'rgba(118, 105, 211, 0.12)',
|
||
|
||
blue400: '#70A2FF',
|
||
blue300: '#3070E8',
|
||
blue200: 'rgba(48, 112, 232, 0.25)',
|
||
blue100: 'rgba(48, 112, 232, 0.12)',
|
||
|
||
green400: '#1AB792',
|
||
green300: '#1D876E',
|
||
green200: 'rgba(29, 135, 110, 0.3)',
|
||
green100: 'rgba(29, 135, 110, 0.14)',
|
||
|
||
yellow400: '#E5A500',
|
||
yellow300: '#B28000',
|
||
yellow200: 'rgba(178, 128, 0, 0.25)',
|
||
yellow100: 'rgba(178, 128, 0, 0.1)',
|
||
|
||
red400: '#F87277',
|
||
red300: '#E12D33',
|
||
red200: 'rgba(225, 45, 51, 0.25)',
|
||
red100: 'rgba(225, 45, 51, 0.12)',
|
||
|
||
pink400: '#E674AD',
|
||
pink300: '#CE3B85',
|
||
pink200: 'rgba(206, 59, 133, 0.25)',
|
||
pink100: 'rgba(206, 59, 133, 0.1)',
|
||
};
|
||
|
||
const prismLight = {
|
||
'--prism-base': '#332B3B',
|
||
'--prism-selected': '#F5F3F7',
|
||
'--prism-inline-code': '#332B3B',
|
||
'--prism-inline-code-background': '#F5F3F7',
|
||
'--prism-highlight-background': '#5C78A31C',
|
||
'--prism-highlight-accent': '#5C78A344',
|
||
'--prism-comment': '#80708F',
|
||
'--prism-punctuation': '#332B3B',
|
||
'--prism-property': '#18408B',
|
||
'--prism-selector': '#177861',
|
||
'--prism-operator': '#235CC8',
|
||
'--prism-variable': '#332B3B',
|
||
'--prism-function': '#235CC8',
|
||
'--prism-keyword': '#BB3A3D',
|
||
};
|
||
|
||
const prismDark = {
|
||
'--prism-base': '#D6D0DC',
|
||
'--prism-selected': '#393041',
|
||
'--prism-inline-code': '#D6D0DC',
|
||
'--prism-inline-code-background': '#18121C',
|
||
'--prism-highlight-background': '#A8A2C31C',
|
||
'--prism-highlight-accent': '#A8A2C344',
|
||
'--prism-comment': '#998DA5',
|
||
'--prism-punctuation': '#D6D0DC',
|
||
'--prism-property': '#70A2FF',
|
||
'--prism-selector': '#1DCDA4',
|
||
'--prism-operator': '#70A2FF',
|
||
'--prism-variable': '#D6D0DC',
|
||
'--prism-function': '#70A2FF',
|
||
'--prism-keyword': '#F8777C',
|
||
};
|
||
|
||
const lightShadows = {
|
||
dropShadowLight: '0 0 1px rgba(43, 34, 51, 0.04)',
|
||
dropShadowMedium: '0 1px 2px rgba(43, 34, 51, 0.04)',
|
||
dropShadowHeavy: '0 4px 24px rgba(43, 34, 51, 0.12)',
|
||
};
|
||
|
||
const darkShadows = {
|
||
dropShadowLight: '0 0 1px rgba(10, 8, 12, 0.2)',
|
||
dropShadowMedium: '0 1px 2px rgba(10, 8, 12, 0.2)',
|
||
dropShadowHeavy: '0 4px 24px rgba(10, 8, 12, 0.36)',
|
||
};
|
||
|
||
/**
|
||
* Background used in the theme-color meta tag
|
||
* The colors below are an approximation of the colors used in the sidebar (sidebarGradient).
|
||
* Unfortunately the exact colors cannot be used, as the theme-color tag does not support linear-gradient()
|
||
*/
|
||
const sidebarBackground = {
|
||
light: '#2f1937',
|
||
dark: '#181622',
|
||
};
|
||
|
||
type BaseColors = typeof lightColors;
|
||
|
||
const generateAliases = (colors: BaseColors) => ({
|
||
/**
|
||
* Heading text color
|
||
*/
|
||
headingColor: colors.gray500,
|
||
|
||
/**
|
||
* Primary text color
|
||
*/
|
||
textColor: colors.gray400,
|
||
|
||
/**
|
||
* Text that should not have as much emphasis
|
||
*/
|
||
subText: colors.gray300,
|
||
|
||
/**
|
||
* Background for the main content area of a page?
|
||
*/
|
||
bodyBackground: colors.surface200,
|
||
|
||
/**
|
||
* Primary background color
|
||
*/
|
||
background: colors.surface300,
|
||
|
||
/**
|
||
* Elevated background color
|
||
*/
|
||
backgroundElevated: colors.surface400,
|
||
|
||
/**
|
||
* Secondary background color used as a slight contrast against primary background
|
||
*/
|
||
backgroundSecondary: colors.surface200,
|
||
|
||
/**
|
||
* Tertiary background color used as a stronger contrast against primary background
|
||
*/
|
||
backgroundTertiary: colors.surface100,
|
||
|
||
/**
|
||
* Background for the header of a page
|
||
*/
|
||
headerBackground: colors.surface300,
|
||
|
||
/**
|
||
* Primary border color
|
||
*/
|
||
border: colors.gray200,
|
||
translucentBorder: colors.translucentGray200,
|
||
|
||
/**
|
||
* Inner borders, e.g. borders inside of a grid
|
||
*/
|
||
innerBorder: colors.gray100,
|
||
translucentInnerBorder: colors.translucentGray100,
|
||
|
||
/**
|
||
* A color that denotes a "success", or something good
|
||
*/
|
||
success: colors.green300,
|
||
successText: colors.green400,
|
||
successFocus: colors.green200,
|
||
|
||
/**
|
||
* A color that denotes an error, or something that is wrong
|
||
*/
|
||
error: colors.red300,
|
||
errorText: colors.red400,
|
||
errorFocus: colors.red200,
|
||
|
||
/**
|
||
* A color that denotes danger, for dangerous actions like deletion
|
||
*/
|
||
danger: colors.red300,
|
||
dangerText: colors.red400,
|
||
dangerFocus: colors.red200,
|
||
|
||
/**
|
||
* A color that denotes a warning
|
||
*/
|
||
warning: colors.yellow300,
|
||
warningText: colors.yellow400,
|
||
warningFocus: colors.yellow200,
|
||
|
||
/**
|
||
* A color that indicates something is disabled where user can not interact or use
|
||
* it in the usual manner (implies that there is an "enabled" state)
|
||
*/
|
||
disabled: colors.gray300,
|
||
disabledBorder: colors.gray200,
|
||
|
||
/**
|
||
* Indicates a "hover" state. Deprecated – use `InteractionStateLayer` instead for
|
||
* interaction (hover/press) states.
|
||
* @deprecated
|
||
*/
|
||
hover: colors.surface500,
|
||
|
||
/**
|
||
* Indicates that something is "active" or "selected"
|
||
*/
|
||
active: colors.purple300,
|
||
activeHover: colors.purple400,
|
||
activeText: colors.purple400,
|
||
|
||
/**
|
||
* Indicates that something has "focus", which is different than "active" state as it is more temporal
|
||
* and should be a bit subtler than active
|
||
*/
|
||
focus: colors.purple200,
|
||
focusBorder: colors.purple300,
|
||
|
||
/**
|
||
* Inactive
|
||
*/
|
||
inactive: colors.gray300,
|
||
|
||
/**
|
||
* Link color indicates that something is clickable
|
||
*/
|
||
linkColor: colors.blue400,
|
||
linkHoverColor: colors.blue400,
|
||
linkUnderline: colors.blue200,
|
||
linkFocus: colors.blue300,
|
||
|
||
/**
|
||
* Form placeholder text color
|
||
*/
|
||
formPlaceholder: colors.gray300,
|
||
|
||
/**
|
||
* Default form text color
|
||
*/
|
||
formText: colors.gray400,
|
||
|
||
/**
|
||
*
|
||
*/
|
||
rowBackground: colors.surface400,
|
||
|
||
/**
|
||
* Color of lines that flow across the background of the chart to indicate axes levels
|
||
* (This should only be used for yAxis)
|
||
*/
|
||
chartLineColor: colors.gray100,
|
||
|
||
/**
|
||
* Color for chart label text
|
||
*/
|
||
chartLabel: colors.gray300,
|
||
|
||
/**
|
||
* Color for the 'others' series in topEvent charts
|
||
*/
|
||
chartOther: colors.gray200,
|
||
|
||
/**
|
||
* Default Progressbar color
|
||
*/
|
||
progressBar: colors.purple300,
|
||
|
||
/**
|
||
* Default Progressbar color
|
||
*/
|
||
progressBackground: colors.gray100,
|
||
|
||
/**
|
||
* Overlay for partial opacity
|
||
*/
|
||
overlayBackgroundAlpha: color(colors.surface200).alpha(0.7).string(),
|
||
|
||
/**
|
||
* Tag progress bars
|
||
*/
|
||
tagBarHover: colors.purple200,
|
||
tagBar: colors.gray200,
|
||
|
||
/**
|
||
* Search filter "token" background
|
||
*/
|
||
searchTokenBackground: {
|
||
valid: colors.blue100,
|
||
validActive: color(colors.blue100).opaquer(1.0).string(),
|
||
invalid: colors.red100,
|
||
invalidActive: color(colors.red100).opaquer(0.8).string(),
|
||
warning: colors.yellow100,
|
||
warningActive: color(colors.yellow100).opaquer(0.8).string(),
|
||
},
|
||
|
||
/**
|
||
* Search filter "token" border
|
||
*/
|
||
searchTokenBorder: {
|
||
valid: colors.blue200,
|
||
validActive: color(colors.blue200).opaquer(1).string(),
|
||
invalid: colors.red200,
|
||
invalidActive: color(colors.red200).opaquer(1).string(),
|
||
warning: colors.yellow200,
|
||
warningActive: color(colors.yellow200).opaquer(1).string(),
|
||
},
|
||
|
||
/**
|
||
* Count on button when active
|
||
*/
|
||
buttonCountActive: colors.white,
|
||
|
||
/**
|
||
* Count on button
|
||
*/
|
||
buttonCount: colors.gray500,
|
||
|
||
/**
|
||
* Background of alert banners at the top
|
||
*/
|
||
bannerBackground: colors.gray500,
|
||
});
|
||
|
||
const dataCategory = {
|
||
[DATA_CATEGORY_INFO.error.plural]: CHART_PALETTE[4][3],
|
||
[DATA_CATEGORY_INFO.transaction.plural]: CHART_PALETTE[4][2],
|
||
[DATA_CATEGORY_INFO.attachment.plural]: CHART_PALETTE[4][1],
|
||
[DATA_CATEGORY_INFO.replay.plural]: CHART_PALETTE[4][4],
|
||
[DATA_CATEGORY_INFO.monitorSeat.plural]: CHART_PALETTE[4][5],
|
||
};
|
||
|
||
/**
|
||
* Default colors for data usage outcomes
|
||
*/
|
||
const outcome = {
|
||
[Outcome.ACCEPTED]: CHART_PALETTE[0][0],
|
||
[Outcome.FILTERED]: CHART_PALETTE[1][1],
|
||
[Outcome.DROPPED]: CHART_PALETTE[5][3],
|
||
};
|
||
|
||
const generateAlertTheme = (colors: BaseColors, alias: Aliases) => ({
|
||
muted: {
|
||
background: colors.gray200,
|
||
backgroundLight: alias.backgroundSecondary,
|
||
border: alias.border,
|
||
borderHover: alias.border,
|
||
iconColor: 'inherit',
|
||
iconHoverColor: 'inherit',
|
||
},
|
||
info: {
|
||
background: colors.blue300,
|
||
backgroundLight: colors.blue100,
|
||
border: colors.blue200,
|
||
borderHover: colors.blue300,
|
||
iconColor: colors.blue400,
|
||
iconHoverColor: colors.blue400,
|
||
},
|
||
warning: {
|
||
background: colors.yellow300,
|
||
backgroundLight: colors.yellow100,
|
||
border: colors.yellow200,
|
||
borderHover: colors.yellow300,
|
||
iconColor: colors.yellow400,
|
||
iconHoverColor: colors.yellow400,
|
||
},
|
||
success: {
|
||
background: colors.green300,
|
||
backgroundLight: colors.green100,
|
||
border: colors.green200,
|
||
borderHover: colors.green300,
|
||
iconColor: colors.green400,
|
||
iconHoverColor: colors.green400,
|
||
},
|
||
error: {
|
||
background: colors.red300,
|
||
backgroundLight: colors.red100,
|
||
border: colors.red200,
|
||
borderHover: colors.red300,
|
||
iconColor: colors.red400,
|
||
iconHoverColor: colors.red400,
|
||
textLight: colors.red200,
|
||
},
|
||
});
|
||
|
||
const generateBadgeTheme = (colors: BaseColors) => ({
|
||
default: {
|
||
background: colors.gray100,
|
||
indicatorColor: colors.gray100,
|
||
color: colors.gray500,
|
||
},
|
||
alpha: {
|
||
background: `linear-gradient(90deg, ${colors.pink300}, ${colors.yellow300})`,
|
||
indicatorColor: colors.pink300,
|
||
color: colors.white,
|
||
},
|
||
beta: {
|
||
background: `linear-gradient(90deg, ${colors.purple300}, ${colors.pink300})`,
|
||
indicatorColor: colors.purple300,
|
||
color: colors.white,
|
||
},
|
||
new: {
|
||
background: `linear-gradient(90deg, ${colors.blue300}, ${colors.green300})`,
|
||
indicatorColor: colors.green300,
|
||
color: colors.white,
|
||
},
|
||
experimental: {
|
||
background: colors.gray100,
|
||
indicatorColor: colors.gray100,
|
||
color: colors.gray500,
|
||
},
|
||
warning: {
|
||
background: colors.yellow300,
|
||
indicatorColor: colors.yellow300,
|
||
color: colors.gray500,
|
||
},
|
||
});
|
||
|
||
const generateTagTheme = (colors: BaseColors) => ({
|
||
default: {
|
||
background: colors.surface400,
|
||
border: colors.gray200,
|
||
iconColor: colors.gray300,
|
||
},
|
||
promotion: {
|
||
background: colors.pink100,
|
||
border: colors.pink200,
|
||
iconColor: colors.pink400,
|
||
},
|
||
highlight: {
|
||
background: colors.purple100,
|
||
border: colors.purple200,
|
||
iconColor: colors.purple400,
|
||
},
|
||
warning: {
|
||
background: colors.yellow100,
|
||
border: colors.yellow200,
|
||
iconColor: colors.yellow400,
|
||
},
|
||
success: {
|
||
background: colors.green100,
|
||
border: colors.green200,
|
||
iconColor: colors.green400,
|
||
},
|
||
error: {
|
||
background: colors.red100,
|
||
border: colors.red200,
|
||
iconColor: colors.red400,
|
||
},
|
||
info: {
|
||
background: colors.purple100,
|
||
border: colors.purple200,
|
||
iconColor: colors.purple400,
|
||
},
|
||
white: {
|
||
background: colors.white,
|
||
border: colors.white,
|
||
iconColor: colors.black,
|
||
},
|
||
black: {
|
||
background: colors.black,
|
||
border: colors.black,
|
||
iconColor: colors.white,
|
||
},
|
||
});
|
||
|
||
const generateLevelTheme = (colors: BaseColors) => ({
|
||
sample: colors.purple300,
|
||
info: colors.blue300,
|
||
warning: colors.yellow300,
|
||
// Hardcoded legacy color (orange400). We no longer use orange anywhere
|
||
// else in the app (except for the chart palette). This needs to be harcoded
|
||
// here because existing users may still associate orange with the "error" level.
|
||
error: '#FF7738',
|
||
fatal: colors.red300,
|
||
default: colors.gray300,
|
||
unknown: colors.gray200,
|
||
});
|
||
|
||
const generateButtonTheme = (colors: BaseColors, alias: Aliases) => ({
|
||
default: {
|
||
color: alias.textColor,
|
||
colorActive: alias.textColor,
|
||
background: alias.background,
|
||
backgroundActive: alias.hover,
|
||
border: alias.border,
|
||
borderActive: alias.border,
|
||
borderTranslucent: alias.translucentBorder,
|
||
focusBorder: alias.focusBorder,
|
||
focusShadow: alias.focus,
|
||
},
|
||
primary: {
|
||
color: colors.white,
|
||
colorActive: colors.white,
|
||
background: colors.purple300,
|
||
backgroundActive: colors.purple400,
|
||
border: colors.purple300,
|
||
borderActive: colors.purple300,
|
||
borderTranslucent: colors.purple300,
|
||
focusBorder: alias.focusBorder,
|
||
focusShadow: alias.focus,
|
||
},
|
||
danger: {
|
||
color: colors.white,
|
||
colorActive: colors.white,
|
||
background: colors.red300,
|
||
backgroundActive: colors.red400,
|
||
border: colors.red300,
|
||
borderActive: colors.red300,
|
||
borderTranslucent: colors.red300,
|
||
focusBorder: colors.red300,
|
||
focusShadow: colors.red200,
|
||
},
|
||
link: {
|
||
color: alias.linkColor,
|
||
colorActive: alias.linkHoverColor,
|
||
background: 'transparent',
|
||
backgroundActive: 'transparent',
|
||
border: 'transparent',
|
||
borderActive: 'transparent',
|
||
borderTranslucent: 'transparent',
|
||
focusBorder: alias.focusBorder,
|
||
focusShadow: alias.focus,
|
||
},
|
||
disabled: {
|
||
color: alias.disabled,
|
||
colorActive: alias.disabled,
|
||
background: alias.background,
|
||
backgroundActive: alias.background,
|
||
border: alias.disabledBorder,
|
||
borderActive: alias.disabledBorder,
|
||
borderTranslucent: alias.translucentInnerBorder,
|
||
focusBorder: 'transparent',
|
||
focusShadow: 'transparent',
|
||
},
|
||
});
|
||
|
||
const generateUtils = (colors: BaseColors, aliases: Aliases) => ({
|
||
tooltipUnderline: (underlineColor: ColorOrAlias = 'gray300') => ({
|
||
textDecoration: `underline dotted ${
|
||
colors[underlineColor] ?? aliases[underlineColor]
|
||
}`,
|
||
textDecorationThickness: '0.75px',
|
||
textUnderlineOffset: '1.25px',
|
||
}),
|
||
overflowEllipsis: css({
|
||
display: 'block',
|
||
width: '100%',
|
||
whiteSpace: 'nowrap',
|
||
overflow: 'hidden',
|
||
textOverflow: 'ellipsis',
|
||
}),
|
||
});
|
||
|
||
const generatePrismVariables = (
|
||
prismColors: typeof prismLight,
|
||
blockBackground: string
|
||
) =>
|
||
css({
|
||
// block background differs based on light/dark mode
|
||
'--prism-block-background': blockBackground,
|
||
...prismColors,
|
||
});
|
||
|
||
const iconSizes = {
|
||
xs: '12px',
|
||
sm: '14px',
|
||
md: '18px',
|
||
lg: '24px',
|
||
xl: '32px',
|
||
xxl: '72px',
|
||
};
|
||
|
||
const commonTheme = {
|
||
breakpoints: {
|
||
small: '800px',
|
||
medium: '992px',
|
||
large: '1200px',
|
||
xlarge: '1440px',
|
||
xxlarge: '2560px',
|
||
},
|
||
|
||
...lightColors,
|
||
|
||
...lightShadows,
|
||
|
||
iconSizes,
|
||
|
||
iconDirections: {
|
||
up: '0',
|
||
right: '90',
|
||
down: '180',
|
||
left: '270',
|
||
},
|
||
|
||
// Try to keep these ordered plz
|
||
zIndex: {
|
||
// Generic z-index when you hope your component is isolated and
|
||
// does not need to battle others for z-index priority
|
||
initial: 1,
|
||
|
||
truncationFullValue: 10,
|
||
|
||
traceView: {
|
||
spanTreeToggler: 900,
|
||
dividerLine: 909,
|
||
rowInfoMessage: 910,
|
||
minimapContainer: 999,
|
||
},
|
||
|
||
header: 1000,
|
||
errorMessage: 1000,
|
||
dropdown: 1001,
|
||
|
||
dropdownAutocomplete: {
|
||
// needs to be below actor but above other page elements (e.g. pagination)
|
||
// (e.g. Issue Details "seen" dots on chart is 2)
|
||
// stream header is 1000
|
||
menu: 1007,
|
||
|
||
// needs to be above menu
|
||
actor: 1008,
|
||
},
|
||
|
||
globalSelectionHeader: 1009,
|
||
|
||
settingsSidebarNavMask: 1017,
|
||
settingsSidebarNav: 1018,
|
||
sidebarPanel: 1019,
|
||
sidebar: 1020,
|
||
orgAndUserMenu: 1030,
|
||
|
||
// Sentry user feedback modal
|
||
sentryErrorEmbed: 1090,
|
||
|
||
// If you change modal also update shared-components.less
|
||
// as the z-index for bootstrap modals lives there.
|
||
modal: 10000,
|
||
toast: 10001,
|
||
|
||
// tooltips and hovercards can be inside modals sometimes.
|
||
hovercard: 10002,
|
||
tooltip: 10003,
|
||
|
||
// On mobile views issue list dropdowns overlap
|
||
issuesList: {
|
||
stickyHeader: 1,
|
||
sortOptions: 2,
|
||
displayOptions: 3,
|
||
},
|
||
},
|
||
|
||
grid: 8,
|
||
|
||
borderRadius: '6px',
|
||
borderRadiusBottom: '0 0 6px 6px',
|
||
borderRadiusTop: '6px 6px 0 0',
|
||
borderRadiusLeft: '6px 0 0 6px',
|
||
borderRadiusRight: '0 6px 6px 0',
|
||
|
||
panelBorderRadius: '6px',
|
||
modalBorderRadius: '8px',
|
||
linkBorderRadius: '2px',
|
||
|
||
headerSelectorRowHeight: 44,
|
||
headerSelectorLabelHeight: 28,
|
||
|
||
// Relative font sizes
|
||
fontSizeRelativeSmall: '0.9em',
|
||
|
||
fontSizeExtraSmall: '11px',
|
||
fontSizeSmall: '12px',
|
||
fontSizeMedium: '14px',
|
||
fontSizeLarge: '16px',
|
||
fontSizeExtraLarge: '18px',
|
||
codeFontSize: '13px',
|
||
headerFontSize: '22px',
|
||
|
||
settings: {
|
||
// Max-width for settings breadcrumbs
|
||
// i.e. organization, project, or team
|
||
maxCrumbWidth: '240px',
|
||
|
||
containerWidth: '1440px',
|
||
headerHeight: '61px',
|
||
sidebarWidth: '220px',
|
||
},
|
||
|
||
sidebar: {
|
||
boxShadow: '0 3px 3px #2f2936',
|
||
color: '#9586a5',
|
||
divider: '#493e54',
|
||
badgeSize: '22px',
|
||
smallBadgeSize: '11px',
|
||
collapsedWidth: '70px',
|
||
expandedWidth: '220px',
|
||
mobileHeight: '54px',
|
||
menuSpacing: '15px',
|
||
},
|
||
|
||
text: {
|
||
family: "'Rubik', 'Avenir Next', sans-serif",
|
||
familyMono: "'Roboto Mono', Monaco, Consolas, 'Courier New', monospace",
|
||
lineHeightHeading: 1.2,
|
||
lineHeightBody: 1.4,
|
||
pageTitle: {
|
||
fontSize: '1.625rem',
|
||
fontWeight: 600,
|
||
letterSpacing: '-0.01em',
|
||
lineHeight: 1.2,
|
||
},
|
||
cardTitle: {
|
||
fontSize: '1rem',
|
||
fontWeight: 600,
|
||
lineHeight: 1.2,
|
||
},
|
||
},
|
||
|
||
/**
|
||
* Common styles for form inputs & buttons, separated by size.
|
||
* Should be used to ensure consistent sizing among form elements.
|
||
*/
|
||
form: {
|
||
md: {
|
||
height: 38,
|
||
minHeight: 38,
|
||
fontSize: '0.875rem',
|
||
lineHeight: '1rem',
|
||
},
|
||
sm: {
|
||
height: 32,
|
||
minHeight: 32,
|
||
fontSize: '0.875rem',
|
||
lineHeight: '1rem',
|
||
},
|
||
xs: {
|
||
height: 26,
|
||
minHeight: 26,
|
||
fontSize: '0.75rem',
|
||
lineHeight: '0.875rem',
|
||
},
|
||
},
|
||
|
||
/**
|
||
* Padding for buttons
|
||
*/
|
||
buttonPadding: {
|
||
md: {
|
||
paddingLeft: 16,
|
||
paddingRight: 16,
|
||
paddingTop: 10,
|
||
paddingBottom: 10,
|
||
},
|
||
sm: {
|
||
paddingLeft: 12,
|
||
paddingRight: 12,
|
||
paddingTop: 8,
|
||
paddingBottom: 8,
|
||
},
|
||
xs: {
|
||
paddingLeft: 8,
|
||
paddingRight: 8,
|
||
paddingTop: 6,
|
||
paddingBottom: 6,
|
||
},
|
||
},
|
||
|
||
/**
|
||
* Padding for form inputs
|
||
*/
|
||
formPadding: {
|
||
md: {
|
||
paddingLeft: 16,
|
||
paddingRight: 12,
|
||
paddingTop: 10,
|
||
paddingBottom: 10,
|
||
},
|
||
sm: {
|
||
paddingLeft: 12,
|
||
paddingRight: 10,
|
||
paddingTop: 8,
|
||
paddingBottom: 8,
|
||
},
|
||
xs: {
|
||
paddingLeft: 8,
|
||
paddingRight: 6,
|
||
paddingTop: 6,
|
||
paddingBottom: 6,
|
||
},
|
||
},
|
||
|
||
dataCategory,
|
||
outcome,
|
||
|
||
tag: generateTagTheme(lightColors),
|
||
|
||
level: generateLevelTheme(lightColors),
|
||
|
||
charts: {
|
||
colors: CHART_PALETTE[CHART_PALETTE.length - 1],
|
||
|
||
// We have an array that maps `number + 1` --> list of `number` colors
|
||
getColorPalette: (length: number) =>
|
||
CHART_PALETTE[Math.min(CHART_PALETTE.length - 1, length + 1)] as string[],
|
||
|
||
previousPeriod: lightColors.gray200,
|
||
symbolSize: 6,
|
||
},
|
||
|
||
diff: {
|
||
removedRow: 'hsl(358deg 89% 65% / 15%)',
|
||
removed: 'hsl(358deg 89% 65% / 30%)',
|
||
addedRow: 'hsl(100deg 100% 87% / 18%)',
|
||
added: 'hsl(166deg 58% 47% / 32%)',
|
||
},
|
||
|
||
// Similarity spectrum used in "Similar Issues" in group details
|
||
similarity: {
|
||
empty: '#e2dee6',
|
||
colors: ['#ec5e44', '#f38259', '#f9a66d', '#98b480', '#57be8c'],
|
||
},
|
||
|
||
// used as a gradient,
|
||
businessIconColors: ['#EA5BC2', '#6148CE'],
|
||
|
||
barBreakdownColors: ['#EAE2F8', '#BBA6DF', '#9A81C4', '#694D99', '#402A65'],
|
||
barBreakdownFontColors: ['#564277', '#E8E2F1', '#E8E2F1', '#E8E2F1', '#E8E2F1'],
|
||
|
||
demo: {
|
||
headerSize: '70px',
|
||
},
|
||
};
|
||
|
||
const lightAliases = generateAliases(lightColors);
|
||
const darkAliases = generateAliases(darkColors);
|
||
|
||
export const lightTheme = {
|
||
...commonTheme,
|
||
...lightColors,
|
||
...lightAliases,
|
||
...lightShadows,
|
||
inverted: {
|
||
...darkColors,
|
||
...darkAliases,
|
||
},
|
||
...generateUtils(lightColors, lightAliases),
|
||
alert: generateAlertTheme(lightColors, lightAliases),
|
||
badge: generateBadgeTheme(lightColors),
|
||
button: generateButtonTheme(lightColors, lightAliases),
|
||
tag: generateTagTheme(lightColors),
|
||
level: generateLevelTheme(lightColors),
|
||
stacktraceActiveBackground: lightColors.gray500,
|
||
stacktraceActiveText: lightColors.white,
|
||
prismVariables: generatePrismVariables(prismLight, lightAliases.backgroundSecondary),
|
||
prismDarkVariables: generatePrismVariables(prismDark, darkAliases.backgroundElevated),
|
||
sidebar: {
|
||
...commonTheme.sidebar,
|
||
background: sidebarBackground.light,
|
||
},
|
||
sidebarGradient: `linear-gradient(294.17deg,${sidebarBackground.light} 35.57%,#452650 92.42%,#452650 92.42%)`,
|
||
sidebarBorder: 'transparent',
|
||
superuserSidebar: '#880808',
|
||
};
|
||
|
||
export const darkTheme: Theme = {
|
||
...commonTheme,
|
||
...darkColors,
|
||
...darkAliases,
|
||
...darkShadows,
|
||
inverted: {
|
||
...lightColors,
|
||
...lightAliases,
|
||
},
|
||
...generateUtils(darkColors, lightAliases),
|
||
alert: generateAlertTheme(darkColors, darkAliases),
|
||
badge: generateBadgeTheme(darkColors),
|
||
button: generateButtonTheme(darkColors, darkAliases),
|
||
tag: generateTagTheme(darkColors),
|
||
level: generateLevelTheme(darkColors),
|
||
prismVariables: generatePrismVariables(prismDark, darkAliases.backgroundSecondary),
|
||
prismDarkVariables: generatePrismVariables(prismDark, darkAliases.backgroundSecondary),
|
||
stacktraceActiveBackground: darkColors.gray200,
|
||
stacktraceActiveText: darkColors.white,
|
||
sidebar: {
|
||
...commonTheme.sidebar,
|
||
background: sidebarBackground.dark,
|
||
},
|
||
sidebarGradient: `linear-gradient(180deg, ${sidebarBackground.dark} 0%, #1B1825 100%)`,
|
||
sidebarBorder: darkAliases.border,
|
||
superuserSidebar: '#620808',
|
||
};
|
||
|
||
type Theme = typeof lightTheme;
|
||
|
||
export type Color = keyof typeof lightColors;
|
||
export type Aliases = typeof lightAliases;
|
||
export type ColorOrAlias = keyof Aliases | Color;
|
||
export type IconSize = keyof typeof iconSizes;
|
||
export type FormSize = keyof Theme['form'];
|
||
|
||
export default commonTheme;
|
||
|
||
// Be clear about what the [@emotion/React].THeme is extending
|
||
type SentryTheme = Theme;
|
||
|
||
/**
|
||
* Configure Emotion to use our theme
|
||
*/
|
||
declare module '@emotion/react' {
|
||
// eslint-disable-next-line @typescript-eslint/no-shadow
|
||
export interface Theme extends SentryTheme {}
|
||
}
|
||
|
||
// This should never be used directly (except in storybook)
|
||
export {lightAliases as aliases};
|