Monaco Editor Dark Mode (#32263)

* Initial go at light/dark mode compatability for the Monaco editor.

* Alphebetizing the imports.

* Using the color-convert package to convert rgb to hex values. Updating the monaco hover widget for dark mode.

* Changes to highlight and selection colors.

* Misspelled an EUI color variable name.

* Dark mode for the search results page.

* Prettifying code_result.tsx.

* Removing the monaco scroll decorator from the editor.

* Fixing some type errors for color-convert

* Markdown styling for dark mode.

* Changing the import location of 'chrome' in the monaco editor

* Adding a constant for the getTheme() method and adjusting blame view dark mode styles.
This commit is contained in:
Davey Holler 2019-03-06 13:56:51 -08:00 committed by Fuyao Zhao
parent 58585eef1b
commit 881bcc2729
14 changed files with 162 additions and 93 deletions

View file

@ -39,6 +39,7 @@
"@types/angular": "1.6.50",
"@types/boom": "^7.2.0",
"@types/cheerio": "^0.22.10",
"@types/color-convert": "^1.9.0",
"@types/d3-array": "^1.2.1",
"@types/d3-scale": "^2.0.0",
"@types/d3-shape": "^1.3.1",
@ -79,10 +80,10 @@
"@types/redux-actions": "^2.2.1",
"@types/rimraf": "^2.0.2",
"@types/sinon": "^7.0.0",
"@types/styled-components": "^3.0.1",
"@types/storybook__addon-actions": "^3.4.1",
"@types/storybook__addon-info": "^3.4.2",
"@types/storybook__react": "^4.0.0",
"@types/styled-components": "^3.0.1",
"@types/supertest": "^2.0.5",
"@types/tar-fs": "^1.16.1",
"@types/uuid": "^3.4.4",
@ -191,6 +192,7 @@
"brace": "0.11.1",
"chroma-js": "^1.3.6",
"classnames": "2.2.5",
"color-convert": "^2.0.0",
"concat-stream": "1.5.1",
"constate": "^0.9.0",
"constate-latest": "npm:constate@^1.0.0",

View file

@ -1,5 +1,8 @@
.code-search-highlight {
background-color: $euiColorHighlight !important;
background-color: $euiColorVis5;
color: black !important;
padding: $euiSizeXS / 2;
border-radius: $euiSizeXS / 2;
font-weight: bold;
font-style: oblique;
}

View file

@ -13,16 +13,14 @@
.expandButton {
position: absolute;
top: -16px;
right: 17px;
background: #ffffff;
border: 1px solid #d3dae6;
top: -1 * $euiSize;
right: $euiSize + 1px;
background: $euiColorLightestShade;
border: $euiBorderThin;
border-bottom: 0;
height: 0;
min-height: 16px;
min-height: $euiSize;
padding: 0;
box-shadow: 0px 0px 2px rgba(0, 0, 0, 0.05), 0px -4px 4px rgba(0, 0, 0, 0.03),
0px -6px 12px rgba(0, 0, 0, 0.05), 0px -12px 24px rgba(0, 0, 0, 0.05);
border-radius: 4px 4px 0px 0px;
border-radius: $euiSizeXS $euiSizeXS 0 0;
}

View file

@ -23,32 +23,31 @@ const Avatar = styled(EuiAvatar)`
margin: auto ${theme.euiSizeS} auto 0;
`;
const Root = styled(EuiFlexGroup)<{ isFirstLine: boolean }>`
padding: ${theme.paddingSizes.xs} ${theme.paddingSizes.s};
border-top: ${props => (props.isFirstLine ? 'none' : theme.euiBorderThick)};
`;
export class Blame extends React.PureComponent<{ blame: GitBlame; isFirstLine: boolean }> {
public render(): React.ReactNode {
const { blame, isFirstLine } = this.props;
return (
<Root gutterSize="none" justifyContent="spaceBetween" isFirstLine={isFirstLine}>
<EuiFlexGroup
className={isFirstLine ? 'codeBlame__item codeBlame__item--first ' : 'codeBlame__item'}
gutterSize="none"
justifyContent="spaceBetween"
>
<EuiFlexItem grow={false}>
<EuiFlexGroup gutterSize="none" alignItems="center">
<EuiFlexItem grow={false}>
<Avatar size="s" type="space" name={blame.committer.name} initialsLength={1} />
</EuiFlexItem>
<EuiFlexItem grow={false}>
<BlameMessage>{blame.commit.message}</BlameMessage>
<BlameMessage size="xs">{blame.commit.message}</BlameMessage>
</EuiFlexItem>
</EuiFlexGroup>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiText>
<EuiText size="xs">
<EuiTextColor color="subdued">{moment(blame.commit.date).fromNow()}</EuiTextColor>
</EuiText>
</EuiFlexItem>
</Root>
</EuiFlexGroup>
);
}
}

View file

@ -237,3 +237,11 @@
box-shadow: none;
}
}
.codeBlame__item {
padding: $euiSizeXS $euiSizeS;
border-top: $euiBorderThin;
&.codeBlame__item--first{
border-top: none;
}
}

View file

@ -4,26 +4,15 @@
* you may not use this file except in compliance with the Elastic License.
*/
import { EuiBadge, EuiFlexGroup, EuiFlexItem } from '@elastic/eui';
import theme from '@elastic/eui/dist/eui_theme_light.json';
import { EuiBadge, EuiFlexGroup, EuiFlexItem, EuiText } from '@elastic/eui';
import { IPosition } from 'monaco-editor';
import React from 'react';
import { Link } from 'react-router-dom';
import styled from 'styled-components';
import { RepositoryUtils } from '../../../common/repository_utils';
import { history } from '../../utils/url';
import { CodeBlock } from '../codeblock/codeblock';
const OrgName = styled.span`
color: ${theme.euiTextColor};
`;
const RepoName = styled.span`
color: ${theme.euiTextColor};
font-weight: bold;
`;
interface Props {
results: any[];
}
@ -43,8 +32,23 @@ export class CodeResult extends React.PureComponent<Props> {
<div key={`resultitem${key}`} data-test-subj="codeSearchResultList">
<p style={{ marginBottom: '.5rem' }}>
<Link to={repoLinkUrl}>
<OrgName>{RepositoryUtils.orgNameFromUri(uri)}</OrgName>/
<RepoName>{RepositoryUtils.repoNameFromUri(uri)}</RepoName>
<EuiFlexGroup
direction="row"
alignItems="center"
justifyContent="flexStart"
gutterSize="none"
>
<EuiFlexItem grow={false}>
<EuiText size="s" color="subdued">
{RepositoryUtils.orgNameFromUri(uri)}/
</EuiText>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiText size="s" color="default">
<strong>{RepositoryUtils.repoNameFromUri(uri)}</strong>
</EuiText>
</EuiFlexItem>
</EuiFlexGroup>
</Link>
</p>
<EuiFlexGroup
@ -56,10 +60,12 @@ export class CodeResult extends React.PureComponent<Props> {
<EuiFlexItem grow={false}>
<EuiBadge color="default">{hits}</EuiBadge>
</EuiFlexItem>
<EuiFlexItem grow={false}>hits from</EuiFlexItem>
<EuiFlexItem grow={false} data-test-subj="codeSearchResultFileItem">
<Link to={fileLinkUrl}>{filePath}</Link>
</EuiFlexItem>
<EuiText size="s">
&nbsp;hits from
<Link to={fileLinkUrl} data-test-subj="codeSearchResultFileItem">
&nbsp;{filePath}
</Link>
</EuiText>
</EuiFlexGroup>
<CodeBlock
key={`code${key}`}

View file

@ -14,7 +14,6 @@ import { SearchScope } from '../../../model';
import { history } from '../../utils/url';
const ScopeTabContainer = styled.div`
background-color: #ffffff;
height: 56px;
`;

View file

@ -0,0 +1,7 @@
.codeSidebar__container {
background-color: $euiColorLightestShade;
border-right: solid 1px $euiBorderColor;
flex-grow: 1;
flex-shrink: 1;
overflow: auto;
}

View file

@ -23,14 +23,6 @@ import { RepositoryUtils } from '../../../common/repository_utils';
import { SearchScope } from '../../../model';
import { ScopeTabs } from './scope_tabs';
const SideBarContainer = styled.div`
background-color: ${theme.euiColorLightestShade};
border-right: ${theme.euiBorderWidthThin} solid ${theme.euiBorderColor};
flex-grow: 1;
flex-shrink: 1;
overflow: auto;
`;
const FacetContainer = styled.div`
padding: 0 1rem;
`;
@ -110,7 +102,7 @@ export class SideBar extends React.PureComponent<Props> {
});
return (
<SideBarContainer>
<div className="codeSidebar__container">
<ScopeTabs query={this.props.query} scope={this.props.scope} />
<FacetContainer>
<FacetTitle gutterSize="s" alignItems="center" style={{ marginBottom: '.5rem' }}>
@ -142,7 +134,7 @@ export class SideBar extends React.PureComponent<Props> {
{langStatsComp}
</EuiFacetGroup>
</FacetContainer>
</SideBarContainer>
</div>
);
}
}

View file

@ -9,7 +9,8 @@
@import "./monaco/override_monaco_styles.scss";
@import "./components/diff_page/diff.scss";
@import "./components/main/main.scss";
@import "./components/search_page/search.scss";
@import "./components/admin_page/sidebar.scss";
@import "./components/symbol_tree/symbol_tree.scss";
@import "./style/markdown.scss";
@import "./components/symbol_tree/symbol_tree.scss";

View file

@ -17,7 +17,7 @@
.monaco-editor-hover {
min-width: 350px;
border: 1px solid #c8c8c8;
border: $euiBorderThin;
cursor: default;
position: absolute;
overflow-y: auto;
@ -30,10 +30,9 @@
box-sizing: initial;
animation: fadein .1s linear;
line-height: 1.5em;
background: #FFFFFF;
background: $euiColorLightestShade;
border-radius: 4px 4px 4px 4px;
box-shadow: 0 4px 8px 0 rgba(153,153,153,0.15),
0 2px 3px -1px rgba(153,153,153,0.30);
@include euiBottomShadow;
}
.monaco-editor-hover .hover-row {
@ -41,14 +40,14 @@
}
.monaco-editor-hover .button-group {
background: linear-gradient(-180deg, #FAFAFA 0%, #F8F8F8 100%);
background: linear-gradient(-180deg, $euiColorLightestShade 0%, $euiColorEmptyShade 100%);
border-radius: 0 0 4px 4px;
box-shadow: 0 -1px 0 0 #D9D9D9;
box-shadow: 0 -1px 0 0 $euiBorderColor;
height: 32px;
}
.monaco-editor-hover .button-group button:not(:first-child) {
border-left: 1px solid #D8D8D8;
border-left: 1px solid $euiBorderColor;
}
.monaco-editor-hover .button-group button{
@ -59,6 +58,14 @@
flex: 1;
}
.monaco-editor .scroll-decoration {
display: none;
}
.code-mark-line-number, .code-monaco-highlight-line {
background-color: $euiColorLightShade;
}
.text-placeholder {
width: 100%;
height: 18px;
@ -71,8 +78,8 @@
animation-iteration-count: infinite;
animation-name: placeHolderShimmer;
animation-timing-function: linear;
background: #f6f7f8;
background: linear-gradient(to right, #eaeaea 8%, #f8f8f8 38%, #eaeaea 54%);
background: $euiColorLightestShade;
background: linear-gradient(to right, $euiColorLightShade 8%, $euiColorLightestShade 38%, $euiColorLightShade 54%);
background-size: 1000px 640px;
position: relative;

View file

@ -3,7 +3,7 @@
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import convert from 'color-convert';
// (1) Desired editor features:
import 'monaco-editor/esm/vs/editor/browser/controller/coreCommands.js';
import 'monaco-editor/esm/vs/editor/browser/widget/codeEditorWidget.js';
@ -49,6 +49,8 @@ import 'monaco-editor/esm/vs/editor/contrib/goToDefinition/goToDefinitionMouse';
// import 'monaco-editor/esm/vs/editor/standalone/browser/toggleHighContrast/toggleHighContrast.js';
import * as monaco from 'monaco-editor/esm/vs/editor/editor.api.js';
import darkTheme from '@elastic/eui/dist/eui_theme_dark.json';
import lightTheme from '@elastic/eui/dist/eui_theme_light.json';
// (2) Desired languages:
// import 'monaco-editor/esm/vs/language/typescript/monaco.contribution';
// import 'monaco-editor/esm/vs/language/css/monaco.contribution';
@ -94,6 +96,9 @@ import 'monaco-editor/esm/vs/basic-languages/javascript/javascript.contribution'
// import 'monaco-editor/esm/vs/basic-languages/pug/pug.contribution.js';
// import 'monaco-editor/esm/vs/basic-languages/python/python.contribution.js';
import 'monaco-editor/esm/vs/basic-languages/typescript/typescript.contribution';
import chrome from 'ui/chrome';
const IS_DARK_THEME = chrome.getUiSettingsClient().get('theme:darkMode');
// @ts-ignore
/*self.MonacoEnvironment = {
@ -114,46 +119,74 @@ import 'monaco-editor/esm/vs/basic-languages/typescript/typescript.contribution'
},
};*/
const elasticLight = {
keyword: '#DD0A73',
comment: '#90A4AE',
delimeter: '#017F75',
string: '#0079A5',
number: '#E5830E',
regexp: '#0079A5',
types: '#909AA1',
annotation: '#D9D9D9',
tag: '#DD0A73',
symbol: '#A30000',
foreground: '#3F3F3F',
editorBackground: '#FFFFFF',
lineNumbers: '#D9D9D9',
function getTheme() {
if (IS_DARK_THEME) {
return darkTheme;
} else {
return lightTheme;
}
}
const themeName = getTheme();
function getHex(rgbString: string) {
const colorValues = rgbString.slice(4, -1);
const colorArray = colorValues.split(', ');
// @ts-ignore
return '#' + convert.rgb.hex(Number(colorArray[0]), Number(colorArray[1]), Number(colorArray[2]));
}
const syntaxTheme = {
keyword: getHex(themeName.euiColorAccent),
comment: getHex(themeName.euiColorMediumShade),
delimiter: getHex(themeName.euiColorSecondary),
string: getHex(themeName.euiColorPrimary),
number: getHex(themeName.euiColorWarning),
regexp: getHex(themeName.euiColorPrimary),
types: `${IS_DARK_THEME ? getHex(themeName.euiColorVis5) : getHex(themeName.euiColorVis9)}`,
annotation: getHex(themeName.euiColorLightShade),
tag: getHex(themeName.euiColorAccent),
symbol: getHex(themeName.euiColorDanger),
foreground: getHex(themeName.euiColorDarkestShade),
editorBackground: getHex(themeName.euiColorLightestShade),
lineNumbers: getHex(themeName.euiColorDarkShade),
editorIndentGuide: getHex(themeName.euiColorLightShade),
selectionBackground: getHex(themeName.euiColorLightShade),
editorWidgetBackground: getHex(themeName.euiColorLightestShade),
editorWidgetBorder: getHex(themeName.euiColorLightShade),
findMatchBackground: getHex(themeName.euiColorWarning),
findMatchHighlightBackground: getHex(themeName.euiColorWarning),
};
monaco.editor.defineTheme('k6-colors-light', {
monaco.editor.defineTheme('euiColors', {
base: 'vs',
inherit: true,
rules: [
{ token: 'keyword', foreground: elasticLight.keyword, fontStyle: 'bold' },
{ token: 'comment', foreground: elasticLight.comment },
{ token: 'delimiter', foreground: elasticLight.delimeter },
{ token: 'string', foreground: elasticLight.string },
{ token: 'number', foreground: elasticLight.number },
{ token: 'regexp', foreground: elasticLight.regexp },
{ token: 'type', foreground: elasticLight.types },
{ token: 'annotation', foreground: elasticLight.annotation },
{ token: 'tag', foreground: elasticLight.tag },
{ token: 'symbol', foreground: elasticLight.symbol },
{ token: 'keyword', foreground: syntaxTheme.keyword, fontStyle: 'bold' },
{ token: 'comment', foreground: syntaxTheme.comment },
{ token: 'delimiter', foreground: syntaxTheme.delimiter },
{ token: 'string', foreground: syntaxTheme.string },
{ token: 'number', foreground: syntaxTheme.number },
{ token: 'regexp', foreground: syntaxTheme.regexp },
{ token: 'type', foreground: syntaxTheme.types },
{ token: 'annotation', foreground: syntaxTheme.annotation },
{ token: 'tag', foreground: syntaxTheme.tag },
{ token: 'symbol', foreground: syntaxTheme.symbol },
// We provide an empty string fallback
{ token: '', foreground: elasticLight.foreground },
{ token: '', foreground: syntaxTheme.foreground },
],
colors: {
'editor.foreground': elasticLight.foreground,
'editor.background': elasticLight.editorBackground,
'editorLineNumber.foreground': elasticLight.lineNumbers,
'editorLineNumber.activeForeground': elasticLight.lineNumbers,
'editor.foreground': syntaxTheme.foreground,
'editor.background': syntaxTheme.editorBackground,
'editorLineNumber.foreground': syntaxTheme.lineNumbers,
'editorLineNumber.activeForeground': syntaxTheme.lineNumbers,
'editorIndentGuide.background': syntaxTheme.editorIndentGuide,
'editor.selectionBackground': syntaxTheme.selectionBackground,
'editorWidget.border': syntaxTheme.editorWidgetBorder,
'editorWidget.background': syntaxTheme.editorWidgetBackground,
},
});
monaco.editor.setTheme('k6-colors-light');
monaco.editor.setTheme('euiColors');
export { monaco };

View file

@ -0,0 +1,7 @@
.markdown-body {
color: $euiColorDarkestShade;
a, a:visited {
color: $euiColorPrimary;
text-decoration: underline;
}
}

View file

@ -1692,7 +1692,7 @@
resolved "https://registry.yarnpkg.com/@types/cmd-shim/-/cmd-shim-2.0.0.tgz#c3d81d3c2a51af3c65c19b4f1d493a75abf07a5c"
integrity sha512-WuV5bOQTGxqzewPnJbrDe51I5mnX2wTRYy+PduRuIvSuBWZlxDYD6Qt/f1m5sezxx1yyE9+1wHJ/0sRuNIoFaQ==
"@types/color-convert@*":
"@types/color-convert@*", "@types/color-convert@^1.9.0":
version "1.9.0"
resolved "https://registry.yarnpkg.com/@types/color-convert/-/color-convert-1.9.0.tgz#bfa8203e41e7c65471e9841d7e306a7cd8b5172d"
integrity sha512-OKGEfULrvSL2VRbkl/gnjjgbbF7ycIlpSsX7Nkab4MOWi5XxmgBYvuiQ7lcCFY5cPDz7MUNaKgxte2VRmtr4Fg==
@ -6743,12 +6743,19 @@ color-convert@^1.9.1:
dependencies:
color-name "1.1.3"
color-convert@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.0.tgz#9851ac61cc0d3898a8a3088650d5bf447bf69d97"
integrity sha512-hzTicsCJIHdxih9+2aLR1tNGZX5qSJGRHDPVwSY26tVrEf55XNajLOBWz2UuWSIergszA09/bqnOiHyqx9fxQg==
dependencies:
color-name "~1.1.4"
color-name@1.1.3:
version "1.1.3"
resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25"
integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=
color-name@^1.0.0, color-name@^1.1.1:
color-name@^1.0.0, color-name@^1.1.1, color-name@~1.1.4:
version "1.1.4"
resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2"
integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==