Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

VS Code like theming (colors and icons) #6475

Merged
merged 65 commits into from
Dec 27, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
65 commits
Select commit Hold shift + click to select a range
1fe99da
[plugin/theming] #4831: load themes from json files
akosyakov Oct 31, 2019
6a11491
[monaco] preserve color themes
akosyakov Nov 1, 2019
27a5242
[plugin]: handle colors contribution point
akosyakov Nov 1, 2019
396c02f
[monaco] load themes from tmTheme files
akosyakov Nov 1, 2019
04896a9
[vscode] icon theming
akosyakov Nov 25, 2019
940f8a8
apply base and activity bar vscode colors
jbicker Dec 9, 2019
038e9a7
Added color variables for sidebars
jbicker Dec 9, 2019
77f66f6
[git] apply vscode colors
akosyakov Dec 9, 2019
7212ec8
Added color variables for trees
jbicker Dec 9, 2019
367820d
apply welcome page vscode colors
akosyakov Dec 9, 2019
5111c89
apply debug vscode colors
akosyakov Dec 9, 2019
11a389a
apply panel vscode colors
akosyakov Dec 10, 2019
94370db
apply terminal vscode colors
akosyakov Dec 10, 2019
377d1a3
Apply colors for sidepanel and trees/lists
jbicker Dec 10, 2019
8a4c5c6
apply editor Groups & tabs vscode colors
akosyakov Dec 11, 2019
c6d6c0d
apply minimap vscode colors
akosyakov Dec 11, 2019
5bdc34e
apply merge conflicts vscode colors
akosyakov Dec 11, 2019
1acc15c
Aplied color for statusbar, adapted colors of searchbox in trees
jbicker Dec 11, 2019
5a01783
apply diff editor vscode colors
akosyakov Dec 11, 2019
06153bd
apply editor hover widget vscode colors
akosyakov Dec 11, 2019
492f669
apply progress bar vscode colors
akosyakov Dec 11, 2019
48c12fc
apply badge vscode colors
akosyakov Dec 11, 2019
04f1bd4
[color] add more color functions
akosyakov Dec 12, 2019
77053a0
Applied colors for buttons and quickInput
jbicker Dec 12, 2019
042a780
apply notification vscode colors
akosyakov Dec 12, 2019
93b2c27
Fix for icon variables in debug view
jbicker Dec 12, 2019
7b71aba
apply title bar and menu vscode colors
akosyakov Dec 12, 2019
52e0a1e
apply vscode colors to dialogs
akosyakov Dec 12, 2019
3bf626b
Applied Text colors
jbicker Dec 12, 2019
a4ca550
Improved look of navigator search-box
jbicker Dec 12, 2019
dee8777
apply window border vscode colors
akosyakov Dec 12, 2019
e09a6cb
[theming] remove usage of deprecated styles for box-shadow attributes
akosyakov Dec 12, 2019
305ff32
[console] remove usage of deprecated css variables
akosyakov Dec 12, 2019
3bfcdaa
[getting-started] remove usage of old css colors
akosyakov Dec 12, 2019
492e1dc
Applied input control colors and adapted respective styles
jbicker Dec 12, 2019
085bb51
[git] remove usage of old css colors
akosyakov Dec 12, 2019
a25c8c3
Applied color variables to scrollbars
jbicker Dec 13, 2019
feecb3a
Additional changes regarding Input control colors
jbicker Dec 13, 2019
5cf0ef2
Fixed Activity Bar: borders are now applied to full height
jbicker Dec 13, 2019
eadc8b2
Introduced border to left and right side content panels.
jbicker Dec 13, 2019
ed91099
Got rid of '--theia-ui-button-*'-Variables
jbicker Dec 13, 2019
8ac04cb
Removed old color keys for output, dialogs, statusbar, menu, scrollbar
jbicker Dec 13, 2019
2f0c599
[theming] remove --theia-ui-font-color1 css color
akosyakov Dec 13, 2019
abdc152
Removed old color variables for highlighted words
jbicker Dec 13, 2019
570a555
[theming] remove old font and icon colors
akosyakov Dec 13, 2019
b4f8c75
Removed State colors (warn, error, success, info)
jbicker Dec 13, 2019
37608f6
[theming] remove old layout, branding and accent colors
akosyakov Dec 13, 2019
c5735ee
Replaced old color variables for States with VSCode Theme colors
jbicker Dec 16, 2019
54e321f
Fixed tab highlighting in right activity bar.
jbicker Dec 16, 2019
283226b
(theming) Use css classes to style HTML elements.
akosyakov Dec 16, 2019
ce5e8a4
Improved offline behaviour of status bar.
akosyakov Dec 18, 2019
4d573c9
align select color theme command/menu aciton with vscode
akosyakov Dec 17, 2019
d42110e
replace old ansicolor variables with vscode terminal variables
akosyakov Dec 17, 2019
8671207
reflect icon theme changes in tab bar titles
akosyakov Dec 17, 2019
39b134d
[debug] coloring status bar while debugging a program
akosyakov Dec 18, 2019
4e77a54
[monaco] store themes in the indexeddb
akosyakov Dec 18, 2019
3e72fba
[vscode] support color and icon theme preferences
akosyakov Dec 18, 2019
55227b4
update default Theia themes
akosyakov Dec 18, 2019
19d29fa
[theming] update CHANGELOG
akosyakov Dec 19, 2019
785757f
[plugin] remove patching of VS Code extension configurations
akosyakov Dec 20, 2019
58a1d7d
[keybinding] fix #6781: highlight search input on light themes
akosyakov Dec 26, 2019
269909c
[theming] fix #6783: don't render an icon element if an icon is not set
akosyakov Dec 26, 2019
ea270ba
[theming] fix #6785: align monaco list and scrollbar colors
akosyakov Dec 26, 2019
7b42a8e
[theming] fix #6788: introduce URIIconReference
akosyakov Dec 26, 2019
872e810
[theming] fix activity bar icon colors
akosyakov Dec 27, 2019
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 54 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,60 @@ Breaking changes:

- [task] renamed method `getStrigifiedTaskSchema()` has been renamed to `getStringifiedTaskSchema()` [#6780](https://github.com/eclipse-theia/theia/pull/6780)
- [task] renamed method `reorgnizeTasks()` has been renamed to `reorganizeTasks()` [#6780](https://github.com/eclipse-theia/theia/pull/6780)
- Support VS Code icon and color theming. [#6475](https://github.com/eclipse-theia/theia/pull/6475)
vince-fugnitto marked this conversation as resolved.
Show resolved Hide resolved
- Theming: Before `input`, `textarea`, `select` and `button` elements were styled in an ad-hoc manner, i.e.
some were styled globally for a tag, other per a component and third with a dedicated css class name.
Now Theia does not style these elements by default, but an extension developer should decide.
Theia comes though with predefined css class names: `theia-input`, `theia-select` and `theia-button`
to style input/textarea, select and button elements correspondingly. Existing components were refactored to use them.
- Theming: Theia css colors are replaced with [VS Code colors](https://code.visualstudio.com/api/references/theme-color).
- One can reference VS Code color in css by prefixing them with `--theia` and replacing all dots with dashes.
For example `widget.shadow` color can be referenced in css with `var(--theia-widget-shadow)`.
- One can resolve a current color value programmatically with `ColorRegistry.getCurrentColor`.
- One can load a new color theme:
- in the frontend module to enable it on startup
```ts
MonacoThemingService.register({
id: 'myDarkTheme',
label: 'My Dark Theme',
uiTheme: 'vs-dark',
json: require('./relative/path/to/my_theme.json'),
includes: {
'./included_theme.json': require('./relative/path/to/included_theme.json')
}
});
```
- later from a file:
```ts
@inject(MonacoThemingService)
protected readonly monacoThemeService: MonacoThemingService;

this.monacoThemeService.register({
id: 'myDarkTheme',
label: 'My Dark Theme',
uiTheme: 'vs-dark',
uri: 'file:///absolute/path/to/my_theme.json'
});
```
- or install from a VS Code extension.
- One should not introduce css color variables anymore or hardcode colors in css.
- One can contribute new colors by implementing `ColorContribution` contribution point and calling `ColorRegistry.register`.
It's important that new colors are derived from existing VS Code colors if one plans to allow installation of VS Code extension contributing color themes.
Otherwise, there is no guarantee that new colors don't look alien for a random VS Code color theme.
One can derive from an existing color, just by plainly referencing it, e.g. `dark: 'widget.shadow'`,
or applying transformations, e.g. `dark: Color.lighten('widget.shadow', 0.4)`.
- One can though specify values, without deriving from VS Code colors, for new colors in their own theme.
See for example, how [Light (Theia)](packages/monaco/data/monaco-themes/vscode/light_theia.json) theme overrides colors for the activity bar.
- Labeling: `LabelProvider.getIcon` should be sync and fast to avoid blocking rendering and icon caching.
One has to pass more specific elements to get a more specific icon. For example, one cannot answer precisely from a URI
whether a folder or a file icon should be used. If a client wants to get a proper result then it should pass `FileStat` for example or
provide own `LabelProviderContribution` which derives `FileStat` from a custom data structure and then calls `LabelProvider.getIcon` again.
- Labeling: `LabelProviderContribution` methods can return `undefined` meaning that the next contribution should be tried.
- Tree: `TreeNode.name`, `TreeNode.description` and `TreeNode.icon` are deprecated and will be removed later.
One has to provide `LabelProviderContribution` implementation for a custom tree node structure.
Before these attributes have to be computed for all nodes and stored as a part of the layout.
From now on they will be computed only on demand for visible nodes.
It decreases requirements to the local storage and allows to invalidate node appearance by simply rerendering a tree.

## v0.14.0

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
********************************************************************************/

import { DefaultUriLabelProviderContribution, DidChangeLabelEvent, FILE_ICON } from '@theia/core/lib/browser/label-provider';
import { DefaultUriLabelProviderContribution, DidChangeLabelEvent } from '@theia/core/lib/browser/label-provider';
import URI from '@theia/core/lib/common/uri';
import { injectable } from 'inversify';
import { Emitter, Event } from '@theia/core';
Expand Down Expand Up @@ -54,23 +54,23 @@ export class SampleDynamicLabelProviderContribution extends DefaultUriLabelProvi
});
}

private getUri(element: URI): URI {
protected getUri(element: URI): URI {
return new URI(element.toString());
}

async getIcon(element: URI): Promise<string> {
getIcon(element: URI): string {
akosyakov marked this conversation as resolved.
Show resolved Hide resolved
const uri = this.getUri(element);
const icon = super.getFileIcon(uri);
if (!icon) {
return FILE_ICON;
return this.defaultFileIcon;
}
return icon;
}

protected readonly onDidChangeEmitter = new Emitter<DidChangeLabelEvent>();
private x: number = 0;

getName(element: URI): string {
getName(element: URI): string | undefined {
const uri = this.getUri(element);
if (this.isActive && uri.toString().includes('test')) {
return super.getName(uri) + '-' + this.x.toString(10);
Expand All @@ -79,7 +79,7 @@ export class SampleDynamicLabelProviderContribution extends DefaultUriLabelProvi
}
}

getLongName(element: URI): string {
getLongName(element: URI): string | undefined {
const uri = this.getUri(element);
return super.getLongName(uri);
}
Expand Down
5 changes: 2 additions & 3 deletions packages/callhierarchy/src/browser/style/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@

.theia-CallHierarchyTree {
font-size: var(--theia-ui-font-size1);
color: var(--theia-ui-font-color1);
}

.theia-CallHierarchyTree .theia-TreeNode {
Expand Down Expand Up @@ -45,11 +44,11 @@
}

.theia-CallHierarchyTree .definitionNode .referenceCount {
color: var(--theia-ui-font-color3);
color: var(--theia-badge-background);
}

.theia-CallHierarchyTree .definitionNode .container {
color: var(--theia-ui-font-color2);
color: var(--theia-descriptionForeground);
}

.call-hierarchy-tab-icon::before {
Expand Down
8 changes: 3 additions & 5 deletions packages/console/src/browser/style/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -15,31 +15,29 @@
********************************************************************************/

.theia-console-content {
color: var(--theia-content-font-color0);
font-size: var(--theia-code-font-size);
line-height: var(--theia-code-line-height);
font-family: var(--theia-code-font-family);
}

.theia-console-input {
padding-left: 20px;
border-top: var(--theia-panel-border-width) solid var(--theia-border-color1);
border-top: var(--theia-panel-border-width) solid var(--theia-panel-border);
}

.theia-console-input:before {
left: 8px;
position: absolute;
content: '\276f';
line-height: 18px;
color: var(--theia-ui-font-color1);
}

.theia-console-error {
color: var(--theia-error-color2);
color: var(--theia-errorForeground);
}

.theia-console-warning {
color: var(--theia-warn-color2);
color: var(--theia-editorWarning-foreground);
}

.theia-console-ansi-console-item {
Expand Down
31 changes: 26 additions & 5 deletions packages/core/src/browser/color-application-contribution.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,13 +39,19 @@ export class ColorApplicationContribution implements FrontendApplicationContribu
@inject(ContributionProvider) @named(ColorContribution)
protected readonly colorContributions: ContributionProvider<ColorContribution>;

private static themeBackgroundId = 'theme.background';

onStart(): void {
for (const contribution of this.colorContributions.getContributions()) {
contribution.registerColors(this.colors);
}

this.updateThemeBackground();
ThemeService.get().onThemeChange(() => this.updateThemeBackground());

this.update();
ThemeService.get().onThemeChange(() => this.update());
this.colors.onDidChange(() => this.update());
}

protected readonly toUpdate = new DisposableCollection();
Expand All @@ -61,15 +67,30 @@ export class ColorApplicationContribution implements FrontendApplicationContribu
const documentElement = document.documentElement;
if (documentElement) {
for (const id of this.colors.getColors()) {
const color = this.colors.getCurrentColor(id);
if (color) {
const propertyName = `--theia-${id.replace('.', '-')}`;
documentElement.style.setProperty(propertyName, color);
this.toUpdate.push(Disposable.create(() => documentElement.style.removeProperty(propertyName)));
const variable = this.colors.getCurrentCssVariable(id);
if (variable) {
const { name, value } = variable;
documentElement.style.setProperty(name, value);
this.toUpdate.push(Disposable.create(() => documentElement.style.removeProperty(name)));
}
}
}
this.onDidChangeEmitter.fire(undefined);
}

protected updateThemeBackground(): void {
const color = this.colors.getCurrentColor('editor.background');
if (color) {
window.localStorage.setItem(ColorApplicationContribution.themeBackgroundId, color);
} else {
window.localStorage.removeItem(ColorApplicationContribution.themeBackgroundId);
}
}

static initBackground(): void {
const value = window.localStorage.getItem(this.themeBackgroundId) || '#1d1d1d';
const documentElement = document.documentElement;
documentElement.style.setProperty('--theia-editor-background', value);
}

}
112 changes: 106 additions & 6 deletions packages/core/src/browser/color-registry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,32 +15,132 @@
********************************************************************************/

import { injectable } from 'inversify';
import { Disposable } from '../common/disposable';
import { DisposableCollection, Disposable } from '../common/disposable';
import { Emitter } from '../common/event';

/**
* Either be a reference to an existing color or a color value as a hex string, rgba, or hsla.
*/
export type Color = string | RGBA | HSLA | ColorTransformation;
export namespace Color {
export function rgba(r: number, g: number, b: number, a: number = 1): Color {
return { r, g, b, a };
}
export function hsla(h: number, s: number, l: number, a: number = 1): Color {
return { h, s, l, a };
}
export const white = rgba(255, 255, 255, 1);
export const black = rgba(0, 0, 0, 1);
export function transparent(v: string, f: number): ColorTransformation {
return { v, f, kind: 'transparent' };
}
export function lighten(v: string, f: number): ColorTransformation {
return { v, f, kind: 'lighten' };
}
export function darken(v: string, f: number): ColorTransformation {
return { v, f, kind: 'darken' };
}
}
export interface ColorTransformation {
kind: 'transparent' | 'lighten' | 'darken'
v: string
f: number
}
export interface RGBA {
/**
* Red: integer in [0-255]
*/
readonly r: number;

/**
* Green: integer in [0-255]
*/
readonly g: number;

/**
* Blue: integer in [0-255]
*/
readonly b: number;

/**
* Alpha: float in [0-1]
*/
readonly a: number;
}
export interface HSLA {
/**
* Hue: integer in [0, 360]
*/
readonly h: number;
/**
* Saturation: float in [0, 1]
*/
readonly s: number;
/**
* Luminosity: float in [0, 1]
*/
readonly l: number;
/**
* Alpha: float in [0, 1]
*/
readonly a: number;
}

export interface ColorDefaults {
light?: string
dark?: string
hc?: string
light?: Color
dark?: Color
hc?: Color
}

export interface ColorOptions {
export interface ColorDefinition {
id: string
defaults?: ColorDefaults
description: string
}

export interface ColorCssVariable {
name: string
value: string
}

/**
* It should be implemented by an extension, e.g. by the monaco extension.
*/
@injectable()
export class ColorRegistry {

protected readonly onDidChangeEmitter = new Emitter<void>();
readonly onDidChange = this.onDidChangeEmitter.event;
protected fireDidChange(): void {
this.onDidChangeEmitter.fire(undefined);
}

*getColors(): IterableIterator<string> { }

getCurrentCssVariable(id: string): ColorCssVariable | undefined {
const value = this.getCurrentColor(id);
if (!value) {
return undefined;
}
const name = this.toCssVariableName(id);
return { name, value };
}

toCssVariableName(id: string, prefix = 'theia'): string {
return `--${prefix}-${id.replace(/\./g, '-')}`;
}

getCurrentColor(id: string): string | undefined {
return undefined;
}

register(id: string, options: ColorOptions): Disposable {
register(...definitions: ColorDefinition[]): Disposable {
const result = new DisposableCollection(...definitions.map(definition => this.doRegister(definition)));
this.fireDidChange();
return result;
}

protected doRegister(definition: ColorDefinition): Disposable {
return Disposable.NULL;
}

Expand Down
Loading