theme.tsx 24 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009
  1. import {css} from '@emotion/react';
  2. import color from 'color';
  3. import {DATA_CATEGORY_INFO} from 'sentry/constants';
  4. import {CHART_PALETTE} from 'sentry/constants/chartPalette';
  5. import {Outcome} from 'sentry/types';
  6. /**
  7. * Exporting for use in Storybook only. Do not import this
  8. * anywhere else! Instead, use the theme prop or import useTheme.
  9. */
  10. export const lightColors = {
  11. black: '#1D1127',
  12. white: '#FFFFFF',
  13. lightModeBlack: '#1D1127',
  14. lightModeWhite: '#FFFFFF',
  15. surface100: '#F5F3F7',
  16. surface200: '#FAF9FB',
  17. surface300: '#FFFFFF',
  18. surface400: '#FFFFFF',
  19. /**
  20. * Hover color. Deprecated – use <InteractionStateLayer /> instead for interaction
  21. * (hover/press) states.
  22. * @deprecated
  23. */
  24. surface500: '#F5F3F7',
  25. gray500: '#2B2233',
  26. gray400: '#3E3446',
  27. gray300: '#80708F',
  28. gray200: '#E0DCE5',
  29. gray100: '#F0ECF3',
  30. /**
  31. * Alternative version of gray200 that's translucent.
  32. * Useful for borders on tooltips, popovers, and dialogs.
  33. */
  34. translucentGray200: 'rgba(58, 17, 95, 0.14)',
  35. translucentGray100: 'rgba(45, 0, 85, 0.06)',
  36. purple400: '#584AC0',
  37. purple300: '#6C5FC7',
  38. purple200: 'rgba(108, 95, 199, 0.5)',
  39. purple100: 'rgba(108, 95, 199, 0.08)',
  40. blue400: '#2562D4',
  41. blue300: '#3C74DD',
  42. blue200: 'rgba(60, 116, 221, 0.5)',
  43. blue100: 'rgba(60, 116, 221, 0.09)',
  44. green400: '#268D75',
  45. green300: '#2BA185',
  46. green200: 'rgba(43, 161, 133, 0.55)',
  47. green100: 'rgba(43, 161, 133, 0.13)',
  48. yellow400: '#E5A500',
  49. yellow300: '#F5B000',
  50. yellow200: 'rgba(245, 176, 0, 0.55)',
  51. yellow100: 'rgba(245, 176, 0, 0.08)',
  52. red400: '#DF3338',
  53. red300: '#F55459',
  54. red200: 'rgba(245, 84, 89, 0.5)',
  55. red100: 'rgba(245, 84, 89, 0.09)',
  56. pink400: '#E50675',
  57. pink300: '#F14499',
  58. pink200: 'rgba(249, 26, 138, 0.5)',
  59. pink100: 'rgba(249, 26, 138, 0.1)',
  60. };
  61. /**
  62. * Exporting for use in Storybook only. Do not import this
  63. * anywhere else! Instead, use the theme prop or import useTheme.
  64. */
  65. export const darkColors = {
  66. black: '#1D1127',
  67. white: '#FFFFFF',
  68. lightModeBlack: '#FFFFFF',
  69. lightModeWhite: '#1D1127',
  70. surface100: '#18121C',
  71. surface200: '#1A141F',
  72. surface300: '#241D2A',
  73. surface400: '#2C2433',
  74. /**
  75. * Hover color. Deprecated – use <InteractionStateLayer /> instead for interaction
  76. * (hover/press) states.
  77. * @deprecated
  78. */
  79. surface500: '#362E3E',
  80. gray500: '#EBE6EF',
  81. gray400: '#D6D0DC',
  82. gray300: '#998DA5',
  83. gray200: '#393041',
  84. gray100: '#302735',
  85. /**
  86. * Alternative version of gray200 that's translucent.
  87. * Useful for borders on tooltips, popovers, and dialogs.
  88. */
  89. translucentGray200: 'rgba(218, 184, 245, 0.16)',
  90. translucentGray100: 'rgba(208, 168, 240, 0.07)',
  91. purple400: '#A397F7',
  92. purple300: '#7669D3',
  93. purple200: 'rgba(118, 105, 211, 0.27)',
  94. purple100: 'rgba(118, 105, 211, 0.12)',
  95. blue400: '#70A2FF',
  96. blue300: '#3070E8',
  97. blue200: 'rgba(48, 112, 232, 0.25)',
  98. blue100: 'rgba(48, 112, 232, 0.12)',
  99. green400: '#1AB792',
  100. green300: '#1D876E',
  101. green200: 'rgba(29, 135, 110, 0.3)',
  102. green100: 'rgba(29, 135, 110, 0.14)',
  103. yellow400: '#E5A500',
  104. yellow300: '#B28000',
  105. yellow200: 'rgba(178, 128, 0, 0.25)',
  106. yellow100: 'rgba(178, 128, 0, 0.1)',
  107. red400: '#F87277',
  108. red300: '#E12D33',
  109. red200: 'rgba(225, 45, 51, 0.25)',
  110. red100: 'rgba(225, 45, 51, 0.12)',
  111. pink400: '#E674AD',
  112. pink300: '#CE3B85',
  113. pink200: 'rgba(206, 59, 133, 0.25)',
  114. pink100: 'rgba(206, 59, 133, 0.1)',
  115. };
  116. const prismLight = {
  117. '--prism-base': '#332B3B',
  118. '--prism-selected': '#F5F3F7',
  119. '--prism-inline-code': '#332B3B',
  120. '--prism-inline-code-background': '#F5F3F7',
  121. '--prism-highlight-background': '#5C78A31C',
  122. '--prism-highlight-accent': '#5C78A344',
  123. '--prism-comment': '#80708F',
  124. '--prism-punctuation': '#332B3B',
  125. '--prism-property': '#18408B',
  126. '--prism-selector': '#177861',
  127. '--prism-operator': '#235CC8',
  128. '--prism-variable': '#332B3B',
  129. '--prism-function': '#235CC8',
  130. '--prism-keyword': '#BB3A3D',
  131. };
  132. const prismDark = {
  133. '--prism-base': '#D6D0DC',
  134. '--prism-selected': '#393041',
  135. '--prism-inline-code': '#D6D0DC',
  136. '--prism-inline-code-background': '#18121C',
  137. '--prism-highlight-background': '#A8A2C31C',
  138. '--prism-highlight-accent': '#A8A2C344',
  139. '--prism-comment': '#998DA5',
  140. '--prism-punctuation': '#D6D0DC',
  141. '--prism-property': '#70A2FF',
  142. '--prism-selector': '#1DCDA4',
  143. '--prism-operator': '#70A2FF',
  144. '--prism-variable': '#D6D0DC',
  145. '--prism-function': '#70A2FF',
  146. '--prism-keyword': '#F8777C',
  147. };
  148. const lightShadows = {
  149. dropShadowLight: '0 0 1px rgba(43, 34, 51, 0.04)',
  150. dropShadowMedium: '0 1px 2px rgba(43, 34, 51, 0.04)',
  151. dropShadowHeavy: '0 4px 24px rgba(43, 34, 51, 0.12)',
  152. };
  153. const darkShadows = {
  154. dropShadowLight: '0 0 1px rgba(10, 8, 12, 0.2)',
  155. dropShadowMedium: '0 1px 2px rgba(10, 8, 12, 0.2)',
  156. dropShadowHeavy: '0 4px 24px rgba(10, 8, 12, 0.36)',
  157. };
  158. /**
  159. * Background used in the theme-color meta tag
  160. * The colors below are an approximation of the colors used in the sidebar (sidebarGradient).
  161. * Unfortunately the exact colors cannot be used, as the theme-color tag does not support linear-gradient()
  162. */
  163. const sidebarBackground = {
  164. light: '#2f1937',
  165. dark: '#181622',
  166. };
  167. type BaseColors = typeof lightColors;
  168. const generateAliases = (colors: BaseColors) => ({
  169. /**
  170. * Heading text color
  171. */
  172. headingColor: colors.gray500,
  173. /**
  174. * Primary text color
  175. */
  176. textColor: colors.gray400,
  177. /**
  178. * Text that should not have as much emphasis
  179. */
  180. subText: colors.gray300,
  181. /**
  182. * Background for the main content area of a page?
  183. */
  184. bodyBackground: colors.surface200,
  185. /**
  186. * Primary background color
  187. */
  188. background: colors.surface300,
  189. /**
  190. * Elevated background color
  191. */
  192. backgroundElevated: colors.surface400,
  193. /**
  194. * Secondary background color used as a slight contrast against primary background
  195. */
  196. backgroundSecondary: colors.surface200,
  197. /**
  198. * Tertiary background color used as a stronger contrast against primary background
  199. */
  200. backgroundTertiary: colors.surface100,
  201. /**
  202. * Background for the header of a page
  203. */
  204. headerBackground: colors.surface300,
  205. /**
  206. * Primary border color
  207. */
  208. border: colors.gray200,
  209. translucentBorder: colors.translucentGray200,
  210. /**
  211. * Inner borders, e.g. borders inside of a grid
  212. */
  213. innerBorder: colors.gray100,
  214. translucentInnerBorder: colors.translucentGray100,
  215. /**
  216. * A color that denotes a "success", or something good
  217. */
  218. success: colors.green300,
  219. successText: colors.green400,
  220. successFocus: colors.green200,
  221. /**
  222. * A color that denotes an error, or something that is wrong
  223. */
  224. error: colors.red300,
  225. errorText: colors.red400,
  226. errorFocus: colors.red200,
  227. /**
  228. * A color that denotes danger, for dangerous actions like deletion
  229. */
  230. danger: colors.red300,
  231. dangerText: colors.red400,
  232. dangerFocus: colors.red200,
  233. /**
  234. * A color that denotes a warning
  235. */
  236. warning: colors.yellow300,
  237. warningText: colors.yellow400,
  238. warningFocus: colors.yellow200,
  239. /**
  240. * A color that indicates something is disabled where user can not interact or use
  241. * it in the usual manner (implies that there is an "enabled" state)
  242. */
  243. disabled: colors.gray300,
  244. disabledBorder: colors.gray200,
  245. /**
  246. * Indicates a "hover" state. Deprecated – use `InteractionStateLayer` instead for
  247. * interaction (hover/press) states.
  248. * @deprecated
  249. */
  250. hover: colors.surface500,
  251. /**
  252. * Indicates that something is "active" or "selected"
  253. */
  254. active: colors.purple300,
  255. activeHover: colors.purple400,
  256. activeText: colors.purple400,
  257. /**
  258. * Indicates that something has "focus", which is different than "active" state as it is more temporal
  259. * and should be a bit subtler than active
  260. */
  261. focus: colors.purple200,
  262. focusBorder: colors.purple300,
  263. /**
  264. * Inactive
  265. */
  266. inactive: colors.gray300,
  267. /**
  268. * Link color indicates that something is clickable
  269. */
  270. linkColor: colors.blue400,
  271. linkHoverColor: colors.blue400,
  272. linkUnderline: colors.blue200,
  273. linkFocus: colors.blue300,
  274. /**
  275. * Form placeholder text color
  276. */
  277. formPlaceholder: colors.gray300,
  278. /**
  279. * Default form text color
  280. */
  281. formText: colors.gray400,
  282. /**
  283. *
  284. */
  285. rowBackground: colors.surface400,
  286. /**
  287. * Color of lines that flow across the background of the chart to indicate axes levels
  288. * (This should only be used for yAxis)
  289. */
  290. chartLineColor: colors.gray100,
  291. /**
  292. * Color for chart label text
  293. */
  294. chartLabel: colors.gray300,
  295. /**
  296. * Color for the 'others' series in topEvent charts
  297. */
  298. chartOther: colors.gray200,
  299. /**
  300. * Default Progressbar color
  301. */
  302. progressBar: colors.purple300,
  303. /**
  304. * Default Progressbar color
  305. */
  306. progressBackground: colors.gray100,
  307. /**
  308. * Overlay for partial opacity
  309. */
  310. overlayBackgroundAlpha: color(colors.surface200).alpha(0.7).string(),
  311. /**
  312. * Tag progress bars
  313. */
  314. tagBarHover: colors.purple200,
  315. tagBar: colors.gray200,
  316. /**
  317. * Search filter "token" background
  318. */
  319. searchTokenBackground: {
  320. valid: colors.blue100,
  321. validActive: color(colors.blue100).opaquer(1.0).string(),
  322. invalid: colors.red100,
  323. invalidActive: color(colors.red100).opaquer(0.8).string(),
  324. warning: colors.yellow100,
  325. warningActive: color(colors.yellow100).opaquer(0.8).string(),
  326. },
  327. /**
  328. * Search filter "token" border
  329. */
  330. searchTokenBorder: {
  331. valid: colors.blue200,
  332. validActive: color(colors.blue200).opaquer(1).string(),
  333. invalid: colors.red200,
  334. invalidActive: color(colors.red200).opaquer(1).string(),
  335. warning: colors.yellow200,
  336. warningActive: color(colors.yellow200).opaquer(1).string(),
  337. },
  338. /**
  339. * Count on button when active
  340. */
  341. buttonCountActive: colors.white,
  342. /**
  343. * Count on button
  344. */
  345. buttonCount: colors.gray500,
  346. /**
  347. * Background of alert banners at the top
  348. */
  349. bannerBackground: colors.gray500,
  350. });
  351. const dataCategory = {
  352. [DATA_CATEGORY_INFO.error.plural]: CHART_PALETTE[4][3],
  353. [DATA_CATEGORY_INFO.transaction.plural]: CHART_PALETTE[4][2],
  354. [DATA_CATEGORY_INFO.attachment.plural]: CHART_PALETTE[4][1],
  355. [DATA_CATEGORY_INFO.replay.plural]: CHART_PALETTE[4][4],
  356. [DATA_CATEGORY_INFO.monitorSeat.plural]: CHART_PALETTE[4][5],
  357. };
  358. /**
  359. * Default colors for data usage outcomes
  360. */
  361. const outcome = {
  362. [Outcome.ACCEPTED]: CHART_PALETTE[0][0],
  363. [Outcome.FILTERED]: CHART_PALETTE[1][1],
  364. [Outcome.DROPPED]: CHART_PALETTE[5][3],
  365. };
  366. const generateAlertTheme = (colors: BaseColors, alias: Aliases) => ({
  367. muted: {
  368. background: colors.gray200,
  369. backgroundLight: alias.backgroundSecondary,
  370. border: alias.border,
  371. borderHover: alias.border,
  372. iconColor: 'inherit',
  373. iconHoverColor: 'inherit',
  374. },
  375. info: {
  376. background: colors.blue300,
  377. backgroundLight: colors.blue100,
  378. border: colors.blue200,
  379. borderHover: colors.blue300,
  380. iconColor: colors.blue400,
  381. iconHoverColor: colors.blue400,
  382. },
  383. warning: {
  384. background: colors.yellow300,
  385. backgroundLight: colors.yellow100,
  386. border: colors.yellow200,
  387. borderHover: colors.yellow300,
  388. iconColor: colors.yellow400,
  389. iconHoverColor: colors.yellow400,
  390. },
  391. success: {
  392. background: colors.green300,
  393. backgroundLight: colors.green100,
  394. border: colors.green200,
  395. borderHover: colors.green300,
  396. iconColor: colors.green400,
  397. iconHoverColor: colors.green400,
  398. },
  399. error: {
  400. background: colors.red300,
  401. backgroundLight: colors.red100,
  402. border: colors.red200,
  403. borderHover: colors.red300,
  404. iconColor: colors.red400,
  405. iconHoverColor: colors.red400,
  406. textLight: colors.red200,
  407. },
  408. });
  409. const generateBadgeTheme = (colors: BaseColors) => ({
  410. default: {
  411. background: colors.gray100,
  412. indicatorColor: colors.gray100,
  413. color: colors.gray500,
  414. },
  415. alpha: {
  416. background: `linear-gradient(90deg, ${colors.pink300}, ${colors.yellow300})`,
  417. indicatorColor: colors.pink300,
  418. color: colors.white,
  419. },
  420. beta: {
  421. background: `linear-gradient(90deg, ${colors.purple300}, ${colors.pink300})`,
  422. indicatorColor: colors.purple300,
  423. color: colors.white,
  424. },
  425. new: {
  426. background: `linear-gradient(90deg, ${colors.blue300}, ${colors.green300})`,
  427. indicatorColor: colors.green300,
  428. color: colors.white,
  429. },
  430. experimental: {
  431. background: colors.gray100,
  432. indicatorColor: colors.gray100,
  433. color: colors.gray500,
  434. },
  435. warning: {
  436. background: colors.yellow300,
  437. indicatorColor: colors.yellow300,
  438. color: colors.gray500,
  439. },
  440. });
  441. const generateTagTheme = (colors: BaseColors) => ({
  442. default: {
  443. background: colors.surface400,
  444. border: colors.gray200,
  445. iconColor: colors.gray300,
  446. },
  447. promotion: {
  448. background: colors.pink100,
  449. border: colors.pink200,
  450. iconColor: colors.pink400,
  451. },
  452. highlight: {
  453. background: colors.purple100,
  454. border: colors.purple200,
  455. iconColor: colors.purple400,
  456. },
  457. warning: {
  458. background: colors.yellow100,
  459. border: colors.yellow200,
  460. iconColor: colors.yellow400,
  461. },
  462. success: {
  463. background: colors.green100,
  464. border: colors.green200,
  465. iconColor: colors.green400,
  466. },
  467. error: {
  468. background: colors.red100,
  469. border: colors.red200,
  470. iconColor: colors.red400,
  471. },
  472. info: {
  473. background: colors.purple100,
  474. border: colors.purple200,
  475. iconColor: colors.purple400,
  476. },
  477. white: {
  478. background: colors.white,
  479. border: colors.white,
  480. iconColor: colors.black,
  481. },
  482. black: {
  483. background: colors.black,
  484. border: colors.black,
  485. iconColor: colors.white,
  486. },
  487. });
  488. const generateLevelTheme = (colors: BaseColors) => ({
  489. sample: colors.purple300,
  490. info: colors.blue300,
  491. warning: colors.yellow300,
  492. // Hardcoded legacy color (orange400). We no longer use orange anywhere
  493. // else in the app (except for the chart palette). This needs to be harcoded
  494. // here because existing users may still associate orange with the "error" level.
  495. error: '#FF7738',
  496. fatal: colors.red300,
  497. default: colors.gray300,
  498. unknown: colors.gray200,
  499. });
  500. const generateButtonTheme = (colors: BaseColors, alias: Aliases) => ({
  501. default: {
  502. color: alias.textColor,
  503. colorActive: alias.textColor,
  504. background: alias.background,
  505. backgroundActive: alias.hover,
  506. border: alias.border,
  507. borderActive: alias.border,
  508. borderTranslucent: alias.translucentBorder,
  509. focusBorder: alias.focusBorder,
  510. focusShadow: alias.focus,
  511. },
  512. primary: {
  513. color: colors.white,
  514. colorActive: colors.white,
  515. background: colors.purple300,
  516. backgroundActive: colors.purple400,
  517. border: colors.purple300,
  518. borderActive: colors.purple300,
  519. borderTranslucent: colors.purple300,
  520. focusBorder: alias.focusBorder,
  521. focusShadow: alias.focus,
  522. },
  523. danger: {
  524. color: colors.white,
  525. colorActive: colors.white,
  526. background: colors.red300,
  527. backgroundActive: colors.red400,
  528. border: colors.red300,
  529. borderActive: colors.red300,
  530. borderTranslucent: colors.red300,
  531. focusBorder: colors.red300,
  532. focusShadow: colors.red200,
  533. },
  534. link: {
  535. color: alias.linkColor,
  536. colorActive: alias.linkHoverColor,
  537. background: 'transparent',
  538. backgroundActive: 'transparent',
  539. border: 'transparent',
  540. borderActive: 'transparent',
  541. borderTranslucent: 'transparent',
  542. focusBorder: alias.focusBorder,
  543. focusShadow: alias.focus,
  544. },
  545. disabled: {
  546. color: alias.disabled,
  547. colorActive: alias.disabled,
  548. background: alias.background,
  549. backgroundActive: alias.background,
  550. border: alias.disabledBorder,
  551. borderActive: alias.disabledBorder,
  552. borderTranslucent: alias.translucentInnerBorder,
  553. focusBorder: 'transparent',
  554. focusShadow: 'transparent',
  555. },
  556. });
  557. const generateUtils = (colors: BaseColors, aliases: Aliases) => ({
  558. tooltipUnderline: (underlineColor: ColorOrAlias = 'gray300') => ({
  559. textDecoration: `underline dotted ${
  560. colors[underlineColor] ?? aliases[underlineColor]
  561. }`,
  562. textDecorationThickness: '0.75px',
  563. textUnderlineOffset: '1.25px',
  564. }),
  565. overflowEllipsis: css({
  566. display: 'block',
  567. width: '100%',
  568. whiteSpace: 'nowrap',
  569. overflow: 'hidden',
  570. textOverflow: 'ellipsis',
  571. }),
  572. });
  573. const generatePrismVariables = (
  574. prismColors: typeof prismLight,
  575. blockBackground: string
  576. ) =>
  577. css({
  578. // block background differs based on light/dark mode
  579. '--prism-block-background': blockBackground,
  580. ...prismColors,
  581. });
  582. const iconSizes = {
  583. xs: '12px',
  584. sm: '14px',
  585. md: '18px',
  586. lg: '24px',
  587. xl: '32px',
  588. xxl: '72px',
  589. };
  590. const commonTheme = {
  591. breakpoints: {
  592. small: '800px',
  593. medium: '992px',
  594. large: '1200px',
  595. xlarge: '1440px',
  596. xxlarge: '2560px',
  597. },
  598. ...lightColors,
  599. ...lightShadows,
  600. iconSizes,
  601. iconDirections: {
  602. up: '0',
  603. right: '90',
  604. down: '180',
  605. left: '270',
  606. },
  607. // Try to keep these ordered plz
  608. zIndex: {
  609. // Generic z-index when you hope your component is isolated and
  610. // does not need to battle others for z-index priority
  611. initial: 1,
  612. truncationFullValue: 10,
  613. traceView: {
  614. spanTreeToggler: 900,
  615. dividerLine: 909,
  616. rowInfoMessage: 910,
  617. minimapContainer: 999,
  618. },
  619. header: 1000,
  620. errorMessage: 1000,
  621. dropdown: 1001,
  622. dropdownAutocomplete: {
  623. // needs to be below actor but above other page elements (e.g. pagination)
  624. // (e.g. Issue Details "seen" dots on chart is 2)
  625. // stream header is 1000
  626. menu: 1007,
  627. // needs to be above menu
  628. actor: 1008,
  629. },
  630. globalSelectionHeader: 1009,
  631. settingsSidebarNavMask: 1017,
  632. settingsSidebarNav: 1018,
  633. sidebarPanel: 1019,
  634. sidebar: 1020,
  635. orgAndUserMenu: 1030,
  636. // Sentry user feedback modal
  637. sentryErrorEmbed: 1090,
  638. // If you change modal also update shared-components.less
  639. // as the z-index for bootstrap modals lives there.
  640. modal: 10000,
  641. toast: 10001,
  642. // tooltips and hovercards can be inside modals sometimes.
  643. hovercard: 10002,
  644. tooltip: 10003,
  645. // On mobile views issue list dropdowns overlap
  646. issuesList: {
  647. stickyHeader: 1,
  648. sortOptions: 2,
  649. displayOptions: 3,
  650. },
  651. },
  652. grid: 8,
  653. borderRadius: '6px',
  654. borderRadiusBottom: '0 0 6px 6px',
  655. borderRadiusTop: '6px 6px 0 0',
  656. borderRadiusLeft: '6px 0 0 6px',
  657. borderRadiusRight: '0 6px 6px 0',
  658. panelBorderRadius: '6px',
  659. modalBorderRadius: '8px',
  660. linkBorderRadius: '2px',
  661. headerSelectorRowHeight: 44,
  662. headerSelectorLabelHeight: 28,
  663. // Relative font sizes
  664. fontSizeRelativeSmall: '0.9em',
  665. fontSizeExtraSmall: '11px',
  666. fontSizeSmall: '12px',
  667. fontSizeMedium: '14px',
  668. fontSizeLarge: '16px',
  669. fontSizeExtraLarge: '18px',
  670. codeFontSize: '13px',
  671. headerFontSize: '22px',
  672. settings: {
  673. // Max-width for settings breadcrumbs
  674. // i.e. organization, project, or team
  675. maxCrumbWidth: '240px',
  676. containerWidth: '1440px',
  677. headerHeight: '61px',
  678. sidebarWidth: '220px',
  679. },
  680. sidebar: {
  681. boxShadow: '0 3px 3px #2f2936',
  682. color: '#9586a5',
  683. divider: '#493e54',
  684. badgeSize: '22px',
  685. smallBadgeSize: '11px',
  686. collapsedWidth: '70px',
  687. expandedWidth: '220px',
  688. mobileHeight: '54px',
  689. menuSpacing: '15px',
  690. },
  691. text: {
  692. family: "'Rubik', 'Avenir Next', sans-serif",
  693. familyMono: "'Roboto Mono', Monaco, Consolas, 'Courier New', monospace",
  694. lineHeightHeading: 1.2,
  695. lineHeightBody: 1.4,
  696. pageTitle: {
  697. fontSize: '1.625rem',
  698. fontWeight: 600,
  699. letterSpacing: '-0.01em',
  700. lineHeight: 1.2,
  701. },
  702. cardTitle: {
  703. fontSize: '1rem',
  704. fontWeight: 600,
  705. lineHeight: 1.2,
  706. },
  707. },
  708. /**
  709. * Common styles for form inputs & buttons, separated by size.
  710. * Should be used to ensure consistent sizing among form elements.
  711. */
  712. form: {
  713. md: {
  714. height: 38,
  715. minHeight: 38,
  716. fontSize: '0.875rem',
  717. lineHeight: '1rem',
  718. },
  719. sm: {
  720. height: 32,
  721. minHeight: 32,
  722. fontSize: '0.875rem',
  723. lineHeight: '1rem',
  724. },
  725. xs: {
  726. height: 26,
  727. minHeight: 26,
  728. fontSize: '0.75rem',
  729. lineHeight: '0.875rem',
  730. },
  731. },
  732. /**
  733. * Padding for buttons
  734. */
  735. buttonPadding: {
  736. md: {
  737. paddingLeft: 16,
  738. paddingRight: 16,
  739. paddingTop: 10,
  740. paddingBottom: 10,
  741. },
  742. sm: {
  743. paddingLeft: 12,
  744. paddingRight: 12,
  745. paddingTop: 8,
  746. paddingBottom: 8,
  747. },
  748. xs: {
  749. paddingLeft: 8,
  750. paddingRight: 8,
  751. paddingTop: 6,
  752. paddingBottom: 6,
  753. },
  754. },
  755. /**
  756. * Padding for form inputs
  757. */
  758. formPadding: {
  759. md: {
  760. paddingLeft: 16,
  761. paddingRight: 12,
  762. paddingTop: 10,
  763. paddingBottom: 10,
  764. },
  765. sm: {
  766. paddingLeft: 12,
  767. paddingRight: 10,
  768. paddingTop: 8,
  769. paddingBottom: 8,
  770. },
  771. xs: {
  772. paddingLeft: 8,
  773. paddingRight: 6,
  774. paddingTop: 6,
  775. paddingBottom: 6,
  776. },
  777. },
  778. dataCategory,
  779. outcome,
  780. tag: generateTagTheme(lightColors),
  781. level: generateLevelTheme(lightColors),
  782. charts: {
  783. colors: CHART_PALETTE[CHART_PALETTE.length - 1],
  784. // We have an array that maps `number + 1` --> list of `number` colors
  785. getColorPalette: (length: number) =>
  786. CHART_PALETTE[Math.min(CHART_PALETTE.length - 1, length + 1)] as string[],
  787. previousPeriod: lightColors.gray200,
  788. symbolSize: 6,
  789. },
  790. diff: {
  791. removedRow: 'hsl(358deg 89% 65% / 15%)',
  792. removed: 'hsl(358deg 89% 65% / 30%)',
  793. addedRow: 'hsl(100deg 100% 87% / 18%)',
  794. added: 'hsl(166deg 58% 47% / 32%)',
  795. },
  796. // Similarity spectrum used in "Similar Issues" in group details
  797. similarity: {
  798. empty: '#e2dee6',
  799. colors: ['#ec5e44', '#f38259', '#f9a66d', '#98b480', '#57be8c'],
  800. },
  801. // used as a gradient,
  802. businessIconColors: ['#EA5BC2', '#6148CE'],
  803. barBreakdownColors: ['#EAE2F8', '#BBA6DF', '#9A81C4', '#694D99', '#402A65'],
  804. barBreakdownFontColors: ['#564277', '#E8E2F1', '#E8E2F1', '#E8E2F1', '#E8E2F1'],
  805. demo: {
  806. headerSize: '70px',
  807. },
  808. };
  809. const lightAliases = generateAliases(lightColors);
  810. const darkAliases = generateAliases(darkColors);
  811. export const lightTheme = {
  812. ...commonTheme,
  813. ...lightColors,
  814. ...lightAliases,
  815. ...lightShadows,
  816. inverted: {
  817. ...darkColors,
  818. ...darkAliases,
  819. },
  820. ...generateUtils(lightColors, lightAliases),
  821. alert: generateAlertTheme(lightColors, lightAliases),
  822. badge: generateBadgeTheme(lightColors),
  823. button: generateButtonTheme(lightColors, lightAliases),
  824. tag: generateTagTheme(lightColors),
  825. level: generateLevelTheme(lightColors),
  826. stacktraceActiveBackground: lightColors.gray500,
  827. stacktraceActiveText: lightColors.white,
  828. prismVariables: generatePrismVariables(prismLight, lightAliases.backgroundSecondary),
  829. prismDarkVariables: generatePrismVariables(prismDark, darkAliases.backgroundElevated),
  830. sidebar: {
  831. ...commonTheme.sidebar,
  832. background: sidebarBackground.light,
  833. },
  834. sidebarGradient: `linear-gradient(294.17deg,${sidebarBackground.light} 35.57%,#452650 92.42%,#452650 92.42%)`,
  835. sidebarBorder: 'transparent',
  836. superuserSidebar: '#880808',
  837. };
  838. export const darkTheme: Theme = {
  839. ...commonTheme,
  840. ...darkColors,
  841. ...darkAliases,
  842. ...darkShadows,
  843. inverted: {
  844. ...lightColors,
  845. ...lightAliases,
  846. },
  847. ...generateUtils(darkColors, lightAliases),
  848. alert: generateAlertTheme(darkColors, darkAliases),
  849. badge: generateBadgeTheme(darkColors),
  850. button: generateButtonTheme(darkColors, darkAliases),
  851. tag: generateTagTheme(darkColors),
  852. level: generateLevelTheme(darkColors),
  853. prismVariables: generatePrismVariables(prismDark, darkAliases.backgroundSecondary),
  854. prismDarkVariables: generatePrismVariables(prismDark, darkAliases.backgroundSecondary),
  855. stacktraceActiveBackground: darkColors.gray200,
  856. stacktraceActiveText: darkColors.white,
  857. sidebar: {
  858. ...commonTheme.sidebar,
  859. background: sidebarBackground.dark,
  860. },
  861. sidebarGradient: `linear-gradient(180deg, ${sidebarBackground.dark} 0%, #1B1825 100%)`,
  862. sidebarBorder: darkAliases.border,
  863. superuserSidebar: '#620808',
  864. };
  865. type Theme = typeof lightTheme;
  866. export type Color = keyof typeof lightColors;
  867. export type Aliases = typeof lightAliases;
  868. export type ColorOrAlias = keyof Aliases | Color;
  869. export type IconSize = keyof typeof iconSizes;
  870. export type FormSize = keyof Theme['form'];
  871. export default commonTheme;
  872. // Be clear about what the [@emotion/React].THeme is extending
  873. type SentryTheme = Theme;
  874. /**
  875. * Configure Emotion to use our theme
  876. */
  877. declare module '@emotion/react' {
  878. // eslint-disable-next-line @typescript-eslint/no-shadow
  879. export interface Theme extends SentryTheme {}
  880. }
  881. // This should never be used directly (except in storybook)
  882. export {lightAliases as aliases};