Browse Source

feat(theme): Add in-app Prism colors (#43761)

https://github.com/getsentry/sentry/issues/43765

Add Prism (code highlighting) colors as global styles. Rather than
importing `prism-sentry` wherever we have code, the styles will
automatically be available without additional work (besides calling
`Prism.highlight`).

The new styles have both a light and dark theme, so code snippets can
fit in better with the rest of the UI.

**Before:**
<img width="797" alt="Screenshot 2023-01-26 at 1 54 57 PM"
src="https://user-images.githubusercontent.com/44172267/214959344-419be2be-04af-4cbc-9b16-17f72ec7528e.png">
<img width="797" alt="Screenshot 2023-01-26 at 1 55 11 PM"
src="https://user-images.githubusercontent.com/44172267/214959384-dacdb61d-3f5d-4e0b-8e9e-ca22ffb271f0.png">

**After:**
<img width="797" alt="Screenshot 2023-01-26 at 1 55 24 PM"
src="https://user-images.githubusercontent.com/44172267/214959409-c2bacab3-8760-4b30-9cf8-ae0dd9e5c559.png">
<img width="797" alt="Screenshot 2023-01-26 at 1 55 32 PM"
src="https://user-images.githubusercontent.com/44172267/214959433-42634556-608f-42fb-9282-9f85d35b98d6.png">

More screenshots below…
Vu Luong 2 years ago
parent
commit
ddff7049b3

+ 0 - 1
package.json

@@ -124,7 +124,6 @@
     "platformicons": "^5.4.0",
     "po-catalog-loader": "2.0.0",
     "prettier": "2.7.1",
-    "prism-sentry": "^1.0.2",
     "prismjs": "^1.27.0",
     "process": "^0.11.10",
     "prop-types": "^15.8.1",

+ 0 - 10
static/app/components/codeSnippet.tsx

@@ -1,5 +1,3 @@
-import 'prism-sentry/index.css';
-
 import {Fragment, useEffect, useRef, useState} from 'react';
 import styled from '@emotion/styled';
 import Prism from 'prismjs';
@@ -74,7 +72,6 @@ export function CodeSnippet({
 }
 
 const PreContainer = styled('pre')<{unsetBorderRadiusTop?: boolean}>`
-  overflow-x: scroll;
   ${p =>
     p.unsetBorderRadiusTop
       ? `
@@ -82,13 +79,6 @@ const PreContainer = styled('pre')<{unsetBorderRadiusTop?: boolean}>`
   border-top-right-radius: 0px;
   `
       : null}
-
-  word-break: break-all;
-  white-space: pre-wrap;
-
-  code {
-    white-space: pre;
-  }
 `;
 
 const UnstyledButton = styled('button')`

+ 0 - 6
static/app/components/events/interfaces/spans/inlineDocs.tsx

@@ -1,5 +1,3 @@
-import 'prism-sentry/index.css';
-
 import {Component} from 'react';
 import styled from '@emotion/styled';
 import * as Sentry from '@sentry/react';
@@ -131,10 +129,6 @@ const DocumentationWrapper = styled('div')`
   p {
     line-height: 1.5;
   }
-  pre {
-    word-break: break-all;
-    white-space: pre-wrap;
-  }
 `;
 
 export default withApi(InlineDocs);

+ 0 - 2
static/app/components/htmlCode.tsx

@@ -1,5 +1,3 @@
-import 'prism-sentry/index.css';
-
 import {useEffect, useRef} from 'react';
 import styled from '@emotion/styled';
 import beautify from 'js-beautify';

+ 0 - 7
static/app/components/sidebar/onboardingStep.tsx

@@ -1,5 +1,3 @@
-import 'prism-sentry/index.css';
-
 import {useState} from 'react';
 import styled from '@emotion/styled';
 
@@ -81,11 +79,6 @@ export const DocumentationWrapper = styled('div')`
     border-radius: ${p => p.theme.borderRadius};
   }
 
-  pre {
-    word-break: break-all;
-    white-space: pre-wrap;
-  }
-
   blockquote {
     padding: ${space(1)};
     margin-left: 0;

+ 7 - 0
static/app/styles/global.tsx

@@ -1,6 +1,7 @@
 import {css, Global, Theme} from '@emotion/react';
 
 import {IS_ACCEPTANCE_TEST} from 'sentry/constants';
+import {prismStyles} from 'sentry/styles/prism';
 
 const styles = (theme: Theme, isDark: boolean) => css`
   body {
@@ -38,12 +39,18 @@ const styles = (theme: Theme, isDark: boolean) => css`
 
   pre {
     background-color: ${theme.backgroundSecondary};
+    word-break: break-all;
+    white-space: pre-wrap;
+    overflow-x: auto;
   }
 
   code {
     background-color: transparent;
+    white-space: pre;
   }
 
+  ${prismStyles(theme)}
+
   /**
    * See https://web.dev/prefers-reduced-motion/
    */

+ 135 - 0
static/app/styles/prism.tsx

@@ -0,0 +1,135 @@
+import {css, Theme} from '@emotion/react';
+
+import space from 'sentry/styles/space';
+
+/**
+ * Prism (code highlighting) styles. Added to <GlobalStyles />, so no need to import
+ * this into any component.
+ */
+export const prismStyles = (theme: Theme) => css`
+  :root {
+    ${theme.prismVariables};
+  }
+
+  /* Use dark Prism theme for code snippets imported from Sentry Docs */
+  .gatsby-highlight {
+    ${theme.prismDarkVariables};
+  }
+
+  pre[class*='language-'] {
+    overflow-x: scroll;
+    padding: ${space(1)} ${space(2)};
+    border-radius: ${theme.borderRadius};
+    box-shadow: none;
+  }
+
+  pre[class*='language-'],
+  code[class*='language-'] {
+    color: var(--prism-base);
+    background: var(--prism-block-background);
+    font-size: ${theme.codeFontSize};
+    text-shadow: none;
+    font-family: ${theme.text.familyMono};
+    direction: ltr;
+    text-align: left;
+    white-space: pre;
+    word-spacing: normal;
+    word-break: normal;
+    -moz-tab-size: 4;
+    -o-tab-size: 4;
+    tab-size: 4;
+    -webkit-hyphens: none;
+    -moz-hyphens: none;
+    -ms-hyphens: none;
+    hyphens: none;
+
+    .namespace {
+      opacity: 0.7;
+    }
+    .token.comment,
+    .token.prolog,
+    .token.doctype,
+    .token.cdata {
+      color: var(--prism-comment);
+    }
+    .token.punctuation {
+      color: var(--prism-punctuation);
+    }
+    .token.property,
+    .token.tag,
+    .token.boolean,
+    .token.number,
+    .token.constant,
+    .token.symbol,
+    .token.deleted {
+      color: var(--prism-property);
+    }
+    .token.selector,
+    .token.attr-name,
+    .token.string,
+    .token.char,
+    .token.builtin,
+    .token.inserted {
+      color: var(--prism-selector);
+    }
+    .token.operator,
+    .token.entity,
+    .token.url,
+    .language-css .token.string,
+    .style .token.string {
+      color: var(--prism-operator);
+      background: none;
+    }
+    .token.atrule,
+    .token.attr-value,
+    .token.keyword {
+      color: var(--prism-keyword);
+    }
+    .token.function {
+      color: var(--prism-function);
+    }
+    .token.regex,
+    .token.important,
+    .token.variable {
+      color: var(--prism-variable);
+    }
+    .token.important,
+    .token.bold {
+      font-weight: bold;
+    }
+    .token.italic {
+      font-style: italic;
+    }
+    .token.entity {
+      cursor: help;
+    }
+    .line-highlight {
+      position: absolute;
+      left: 0;
+      right: 0;
+      padding: inherit 0;
+      margin-top: 1em;
+      background: var(--prism-highlight-background);
+      box-shadow: inset 5px 0 0 var(--prism-highlight-accent);
+      z-index: 0;
+      pointer-events: none;
+      line-height: inherit;
+      white-space: pre;
+    }
+  }
+
+  pre[class*='language-']::selection,
+  code[class*='language-']::selection {
+    text-shadow: none;
+    background: var(--prism-selected);
+  }
+
+  pre[data-line] {
+    position: relative;
+  }
+
+  pre[class*='language-'] > code[class*='language-'] {
+    position: relative;
+    z-index: 1;
+  }
+`;

+ 49 - 0
static/app/utils/theme.tsx

@@ -118,6 +118,40 @@ export const darkColors = {
   pink100: 'rgba(206, 59, 133, 0.1)',
 };
 
+const prismLight = {
+  '--prism-base': '#332B3B',
+  '--prism-selected': '#E9E0EB',
+  '--prism-inline-code': '#D25F7C',
+  '--prism-inline-code-background': '#F8F9FB',
+  '--prism-highlight-background': '#E8ECF2',
+  '--prism-highlight-accent': '#C7CBD1',
+  '--prism-comment': '#72697C',
+  '--prism-punctuation': '#70697C',
+  '--prism-property': '#7A6229',
+  '--prism-selector': '#3C774A',
+  '--prism-operator': '#635D6F',
+  '--prism-variable': '#A8491A',
+  '--prism-function': '#106A9E',
+  '--prism-keyword': '#A7114A',
+};
+
+const prismDark = {
+  '--prism-base': '#F2EDF6',
+  '--prism-selected': '#865891',
+  '--prism-inline-code': '#D25F7C',
+  '--prism-inline-code-background': '#F8F9FB',
+  '--prism-highlight-background': '#382F5C',
+  '--prism-highlight-accent': '#D25F7C',
+  '--prism-comment': '#8B7A9E',
+  '--prism-punctuation': '#B3ACC1',
+  '--prism-property': '#EAB944',
+  '--prism-selector': '#7EBE8E',
+  '--prism-operator': '#A470A7',
+  '--prism-variable': '#E58759',
+  '--prism-function': '#6CC5F9',
+  '--prism-keyword': '#E386AA',
+};
+
 const lightShadows = {
   dropShadowLight: '0 0 1px rgba(43, 34, 51, 0.04)',
   dropShadowMedium: '0 1px 2px rgba(43, 34, 51, 0.04)',
@@ -575,6 +609,16 @@ const generateUtils = (colors: BaseColors, aliases: Aliases) => ({
   }),
 });
 
+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: '16px',
@@ -685,6 +729,7 @@ const commonTheme = {
   fontSizeMedium: '14px',
   fontSizeLarge: '16px',
   fontSizeExtraLarge: '18px',
+  codeFontSize: '13px',
   headerFontSize: '22px',
 
   settings: {
@@ -857,6 +902,8 @@ export const lightTheme = {
   button: generateButtonTheme(lightColors, lightAliases),
   tag: generateTagTheme(lightColors),
   level: generateLevelTheme(lightColors),
+  prismVariables: generatePrismVariables(prismLight, lightAliases.backgroundSecondary),
+  prismDarkVariables: generatePrismVariables(prismDark, darkAliases.backgroundElevated),
   sidebar: {
     ...commonTheme.sidebar,
     background: sidebarBackground.light,
@@ -880,6 +927,8 @@ export const darkTheme: Theme = {
   button: generateButtonTheme(darkColors, darkAliases),
   tag: generateTagTheme(darkColors),
   level: generateLevelTheme(darkColors),
+  prismVariables: generatePrismVariables(prismDark, darkAliases.backgroundSecondary),
+  prismDarkVariables: generatePrismVariables(prismDark, darkAliases.backgroundSecondary),
   sidebar: {
     ...commonTheme.sidebar,
     background: sidebarBackground.dark,

+ 0 - 2
static/app/views/onboarding/integrationSetup.tsx

@@ -1,5 +1,3 @@
-import 'prism-sentry/index.css';
-
 import {Fragment, useCallback, useEffect, useState} from 'react';
 import styled from '@emotion/styled';
 import {motion} from 'framer-motion';

+ 0 - 9
static/app/views/onboarding/setupDocs.tsx

@@ -1,5 +1,3 @@
-import 'prism-sentry/index.css';
-
 import {Fragment, useCallback, useEffect, useState} from 'react';
 import {browserHistory} from 'react-router';
 import {css, Theme} from '@emotion/react';
@@ -371,16 +369,9 @@ const Content = styled(motion.div)`
   }
 
   code {
-    font-size: 87.5%;
     color: ${p => p.theme.pink400};
   }
 
-  pre code {
-    color: inherit;
-    font-size: inherit;
-    white-space: pre;
-  }
-
   h2 {
     font-size: 1.4em;
   }

Some files were not shown because too many files changed in this diff