1
0
mirror of https://github.com/lensapp/lens.git synced 2025-05-20 05:10:56 +00:00

Switching color theme globally (#728)

* Adding cluster menu colors

Signed-off-by: Alex Andreev <alex.andreev.email@gmail.com>

* Adding theme class name flag into #app

Signed-off-by: Alex Andreev <alex.andreev.email@gmail.com>

* Cleaning up mixins

Signed-off-by: Alex Andreev <alex.andreev.email@gmail.com>

* Tuning up Wizard Layout styles

Signed-off-by: Alex Andreev <alex.andreev.email@gmail.com>

* Using theme-light global flag

Signed-off-by: Alex Andreev <alex.andreev.email@gmail.com>

* Minor style fixes

Signed-off-by: Alex Andreev <alex.andreev.email@gmail.com>

* Using .theme-light flag across components

Signed-off-by: Alex Andreev <alex.andreev.email@gmail.com>

* Set theme as @computed value

Signed-off-by: Alex Andreev <alex.andreev.email@gmail.com>

* Preventing Drawer slide-in scroll flickering

Signed-off-by: Alex Andreev <alex.andreev.email@gmail.com>

* Setting background for settings views

Signed-off-by: Alex Andreev <alex.andreev.email@gmail.com>

* Minor layout fixes

Signed-off-by: Alex Andreev <alex.andreev.email@gmail.com>

* Switching AceEditor theme reactively

Signed-off-by: Alex Andreev <alex.andreev.email@gmail.com>

* Cleaning up

Signed-off-by: Alex Andreev <alex.andreev.email@gmail.com>
This commit is contained in:
Alex Andreev 2020-08-24 10:24:05 +03:00 committed by GitHub
parent c7b11f86af
commit 0f11b03692
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
26 changed files with 85 additions and 87 deletions

View File

@ -1,13 +1,6 @@
@import "release.mixins"; @import "release.mixins";
.ReleaseDetails { .ReleaseDetails {
&.light {
.AceEditor {
border: 1px solid gainsboro;
border-radius: $radius;
}
}
.DrawerItem { .DrawerItem {
align-items: center; align-items: center;
} }

View File

@ -15,7 +15,7 @@
.content-col { .content-col {
margin: 0; margin: 0;
padding-top: $padding * 3; padding-top: $padding * 3;
background-color: transparent; background-color: $clusterSettingsBackground;
.SubTitle { .SubTitle {
text-transform: none; text-transform: none;

View File

@ -8,8 +8,8 @@
padding: 0; padding: 0;
.content-col { .content-col {
background-color: transparent;
padding: $padding * 8 0; padding: $padding * 8 0;
background-color: $clusterSettingsBackground;
h2 { h2 {
margin-bottom: $margin * 2; margin-bottom: $margin * 2;
@ -40,6 +40,10 @@
.WizardLayout .head-col { .WizardLayout .head-col {
padding-top: 32px; padding-top: 32px;
overflow: hidden; overflow: hidden;
.Icon {
margin-top: -$margin * 2;
}
} }
} }

View File

@ -5,13 +5,12 @@
flex: 1; flex: 1;
z-index: 10; z-index: 10;
&.hidden { .theme-light & {
visibility: hidden; border: 1px solid gainsboro;
} border-radius: $radius;
&.light {
.ace_scrollbar { .ace_scrollbar {
@include custom-scrollbar($theme: dark); @include custom-scrollbar(dark);
} }
} }

View File

@ -3,10 +3,11 @@
import "./ace-editor.scss" import "./ace-editor.scss"
import React from "react" import React from "react"
import { observer } from "mobx-react"; import { observer, disposeOnUnmount } from "mobx-react";
import AceBuild, { Ace } from "ace-builds" import AceBuild, { Ace } from "ace-builds"
import { autobind, cssNames } from "../../utils"; import { autobind, cssNames } from "../../utils";
import { themeStore } from "../../theme.store"; import { themeStore } from "../../theme.store";
import { reaction } from "mobx";
interface Props extends Partial<Ace.EditorOptions> { interface Props extends Partial<Ace.EditorOptions> {
className?: string; className?: string;
@ -46,6 +47,11 @@ export class AceEditor extends React.Component<Props, State> {
require("ace-builds/src-noconflict/ext-searchbox") require("ace-builds/src-noconflict/ext-searchbox")
} }
@disposeOnUnmount
themeSwitcher = reaction(() => themeStore.activeTheme, () => {
this.setTheme(this.theme);
});
get theme() { get theme() {
switch (themeStore.activeTheme.type) { switch (themeStore.activeTheme.type) {
case "light": case "light":
@ -148,9 +154,8 @@ export class AceEditor extends React.Component<Props, State> {
render() { render() {
const { className, hidden } = this.props; const { className, hidden } = this.props;
const themeType = themeStore.activeTheme.type;
return ( return (
<div className={cssNames("AceEditor", className, { hidden }, themeType)}> <div className={cssNames("AceEditor", className, { hidden })}>
<div className="editor" ref={e => this.elem = e}/> <div className="editor" ref={e => this.elem = e}/>
</div> </div>
) )

View File

@ -12,8 +12,6 @@
:root { :root {
--mainBackground: #1e2124; --mainBackground: #1e2124;
--textColorPrimary: #87909c;
--clusters-menu-bgc: #252729;
--main-layout-header: 40px; --main-layout-header: 40px;
} }
@ -31,6 +29,7 @@ html {
html, body { html, body {
height: 100%; height: 100%;
overflow: hidden;
} }
#app { #app {
@ -79,7 +78,7 @@ hr {
} }
h1 { h1 {
color: white; color: $textColorPrimary;
font-size: 28px; font-size: 28px;
font-weight: normal; font-weight: normal;
letter-spacing: -.010em; letter-spacing: -.010em;
@ -142,10 +141,6 @@ a {
text-decoration: underline; text-decoration: underline;
} }
&:focus {
color: white;
}
&:not([href]) { &:not([href]) {
border-bottom: 1px dotted; border-bottom: 1px dotted;
text-decoration: none; text-decoration: none;

View File

@ -5,7 +5,8 @@
position: relative; position: relative;
text-align: center; text-align: center;
padding: $spacing; padding: $spacing;
background: var(--clusters-menu-bgc); background: $clusterMenuBackground;
border-right: 1px solid $clusterMenuBorderColor;
.is-mac & { .is-mac & {
padding-top: $spacing * 2; padding-top: $spacing * 2;
@ -47,11 +48,9 @@
.Icon { .Icon {
border-radius: $radius; border-radius: $radius;
padding: $padding / 3; padding: $padding / 3;
color: var(--clusters-menu-bgc) !important; color: $addClusterIconColor;
background: white !important; background: #ffffff66;
font-weight: bold;
cursor: pointer; cursor: pointer;
opacity: 0.4;
&.active { &.active {
opacity: 1; opacity: 1;
@ -59,7 +58,7 @@
&:hover { &:hover {
box-shadow: none; box-shadow: none;
opacity: .75; background: #ffffff;
} }
} }

View File

@ -15,4 +15,8 @@
&.modal { &.modal {
background: transparentize(#222, .5); background: transparentize(#222, .5);
} }
h5 {
color: white;
}
} }

View File

@ -77,4 +77,8 @@
pointer-events: none; pointer-events: none;
} }
} }
.AceEditor {
border: none;
}
} }

View File

@ -5,7 +5,7 @@
margin-left: $padding * 2; margin-left: $padding * 2;
margin-top: $padding * 2; margin-top: $padding * 2;
&.light { .theme-light & {
.xterm-viewport { .xterm-viewport {
@include custom-scrollbar(dark); @include custom-scrollbar(dark);
} }

View File

@ -9,7 +9,7 @@
box-shadow: 0 0 $unit * 2 $boxShadow; box-shadow: 0 0 $unit * 2 $boxShadow;
z-index: $zIndex-drawer; z-index: $zIndex-drawer;
&.light { .theme-light & {
.drawer-content { .drawer-content {
@include custom-scrollbar(dark); @include custom-scrollbar(dark);
} }

View File

@ -6,7 +6,6 @@ import { cssNames, noop } from "../../utils";
import { Icon } from "../icon"; import { Icon } from "../icon";
import { Animate, AnimateName } from "../animate"; import { Animate, AnimateName } from "../animate";
import { history } from "../../navigation"; import { history } from "../../navigation";
import { themeStore } from "../../theme.store";
export interface DrawerProps { export interface DrawerProps {
open: boolean; open: boolean;
@ -101,7 +100,7 @@ export class Drawer extends React.Component<DrawerProps> {
render() { render() {
const { open, position, title, animation, children, toolbar, size, usePortal } = this.props const { open, position, title, animation, children, toolbar, size, usePortal } = this.props
let { className, contentClass } = this.props; let { className, contentClass } = this.props;
className = cssNames("Drawer", className, position, themeStore.activeTheme.type); className = cssNames("Drawer", className, position);
contentClass = cssNames("drawer-content flex column box grow", contentClass); contentClass = cssNames("drawer-content flex column box grow", contentClass);
const style = size ? { "--size": size } as React.CSSProperties : undefined; const style = size ? { "--size": size } as React.CSSProperties : undefined;
const drawer = ( const drawer = (

View File

@ -1,5 +1,5 @@
.KubeConfigDialog { .KubeConfigDialog {
&.light { .theme-light & {
.AceEditor { .AceEditor {
border: 1px solid gainsboro; border: 1px solid gainsboro;
border-radius: $radius; border-radius: $radius;

View File

@ -13,7 +13,6 @@ import { Dialog, DialogProps } from "../dialog";
import { Icon } from "../icon"; import { Icon } from "../icon";
import { Notifications } from "../notifications"; import { Notifications } from "../notifications";
import { Wizard, WizardStep } from "../wizard"; import { Wizard, WizardStep } from "../wizard";
import { themeStore } from "../../theme.store";
import { apiBase } from "../../api"; import { apiBase } from "../../api";
interface IKubeconfigDialogData { interface IKubeconfigDialogData {
@ -92,7 +91,7 @@ export class KubeConfigDialog extends React.Component<Props> {
return ( return (
<Dialog <Dialog
{...dialogProps} {...dialogProps}
className={cssNames("KubeConfigDialog", themeStore.activeTheme.type)} className={cssNames("KubeConfigDialog")}
isOpen={isOpen} isOpen={isOpen}
onOpen={this.onOpen} onOpen={this.onOpen}
close={this.close} close={this.close}

View File

@ -8,13 +8,6 @@
grid-template-columns: [sidebar] minmax(var(--main-layout-header), min-content) [main] 1fr; grid-template-columns: [sidebar] minmax(var(--main-layout-header), min-content) [main] 1fr;
height: 100%; height: 100%;
&.light {
main {
@include custom-scrollbar(dark);
overflow-y: scroll;
}
}
> .Tabs { > .Tabs {
grid-area: tabs; grid-area: tabs;
background: $layoutTabsBackground; background: $layoutTabsBackground;
@ -69,6 +62,10 @@
@include custom-scrollbar; @include custom-scrollbar;
$spacing: $margin * 2; $spacing: $margin * 2;
.theme-light & {
@include custom-scrollbar(dark);
}
grid-area: main; grid-area: main;
overflow-y: scroll; // always reserve space for scrollbar (17px) overflow-y: scroll; // always reserve space for scrollbar (17px)
overflow-x: auto; overflow-x: auto;

View File

@ -11,7 +11,6 @@ import { ErrorBoundary } from "../error-boundary";
import { Dock } from "../dock"; import { Dock } from "../dock";
import { navigate, navigation } from "../../navigation"; import { navigate, navigation } from "../../navigation";
import { getHostedCluster } from "../../../common/cluster-store"; import { getHostedCluster } from "../../../common/cluster-store";
import { themeStore } from "../../theme.store";
export interface TabRoute extends RouteProps { export interface TabRoute extends RouteProps {
title: React.ReactNode; title: React.ReactNode;
@ -50,7 +49,7 @@ export class MainLayout extends React.Component<Props> {
const routePath = navigation.location.pathname; const routePath = navigation.location.pathname;
const cluster = getHostedCluster(); const cluster = getHostedCluster();
return ( return (
<div className={cssNames("MainLayout", className, themeStore.activeTheme.type)}> <div className={cssNames("MainLayout", className)}>
<header className={cssNames("flex gaps align-center", headerClass)}> <header className={cssNames("flex gaps align-center", headerClass)}>
<span className="cluster"> <span className="cluster">
{cluster.preferences?.clusterName || cluster.contextName} {cluster.preferences?.clusterName || cluster.contextName}

View File

@ -20,6 +20,10 @@
&.pinned { &.pinned {
.sidebar-nav { .sidebar-nav {
@include custom-scrollbar; @include custom-scrollbar;
.theme-light & {
@include custom-scrollbar(dark);
}
} }
} }

View File

@ -2,7 +2,7 @@
$spacing: $padding * 2; $spacing: $padding * 2;
position: relative; position: relative;
padding: $padding * 3; padding: $padding * 2;
height: 100%; height: 100%;
display: grid; display: grid;
grid-template-columns: 1fr 40%; grid-template-columns: 1fr 40%;
@ -11,17 +11,21 @@
@include custom-scrollbar; @include custom-scrollbar;
--flex-gap: #{$spacing}; --flex-gap: #{$spacing};
padding: $spacing; padding: $spacing;
.theme-light & {
@include custom-scrollbar(dark);
}
} }
> .head-col { > .head-col {
position: sticky; position: sticky;
border-bottom: 1px solid $grey-800;
justify-content: space-between; justify-content: space-between;
background-color: $clusterMenuBackground;
} }
> .content-col { > .content-col {
margin-right: $spacing; margin-right: $spacing;
background-color: var(--clusters-menu-bgc); background-color: $contentColor;
border-radius: $radius; border-radius: $radius;
> div { > div {
@ -36,7 +40,7 @@
} }
> .info-col { > .info-col {
border-left: 1px solid #353a3e; background-color: $contentColor;
} }
p { p {

View File

@ -8,8 +8,8 @@
@mixin custom-scrollbar($theme: light, $size: 7px, $borderSpacing: 5px) { @mixin custom-scrollbar($theme: light, $size: 7px, $borderSpacing: 5px) {
$themes: ( $themes: (
light: rgba(255, 255, 255, .25), light: #5f6064,
dark: rgba(0, 0, 0, .25), dark: #bbb,
); );
$scrollBarColor: if(map_has_key($themes, $theme), map_get($themes, $theme), none); $scrollBarColor: if(map_has_key($themes, $theme), map_get($themes, $theme), none);
@ -34,10 +34,6 @@
&::-webkit-scrollbar-corner { &::-webkit-scrollbar-corner {
background-color: transparent; background-color: transparent;
} }
// Firefox
scrollbar-color: $scrollBarColor transparent;
//scrollbar-width: thin;
} }
// Hide scrollbar but keep the element scrollable // Hide scrollbar but keep the element scrollable
@ -49,27 +45,6 @@
height: 0; height: 0;
background: transparent; background: transparent;
} }
scrollbar-width: none; // Firefox 65+
-ms-overflow-style: none; // IE (10,11?), Edge(?)
}
// Cross-browser hacks
@mixin safariOnly {
@media not all and (min-resolution: .001dpcm) {
@content;
}
}
@mixin firefoxOnly {
@-moz-document url-prefix() {
@content;
}
}
@mixin edgeOnly {
@supports (-ms-accelerator: true) {
@content;
}
} }
@mixin stripeLinesAnimation($color1: #ccc, $color2: transparent, $spacing: 1rem) { @mixin stripeLinesAnimation($color1: #ccc, $color2: transparent, $spacing: 1rem) {

View File

@ -38,7 +38,9 @@ export class Select extends React.Component<SelectProps> {
menuPortalTarget: document.body, menuPortalTarget: document.body,
} }
private theme = this.props.themeName || themeStore.activeTheme.type; @computed get theme() {
return this.props.themeName || themeStore.activeTheme.type;
}
private styles: Styles = { private styles: Styles = {
menuPortal: styles => ({ menuPortal: styles => ({

View File

@ -1,9 +1,9 @@
.Table { .Table {
&.scrollable { &.scrollable {
&.light { .theme-light & {
@include custom-scrollbar(dark); @include custom-scrollbar(dark);
} }
@include custom-scrollbar(); @include custom-scrollbar();
flex: 1 0 0; // hackfix: flex-basis must be "0" for proper work in firefox flex: 1 0 0; // hackfix: flex-basis must be "0" for proper work in firefox
} }

View File

@ -1,14 +1,13 @@
.VirtualList { .VirtualList {
overflow: hidden; overflow: hidden;
&.light {
.list {
@include custom-scrollbar(dark);
}
}
> .list { > .list {
@include custom-scrollbar; @include custom-scrollbar;
.theme-light & {
@include custom-scrollbar(dark);
}
overflow-y: overlay !important; overflow-y: overlay !important;
overflow-x: hidden !important; overflow-x: hidden !important;
} }

View File

@ -93,6 +93,9 @@ export class ThemeStore {
return `--${cssName}: ${color} !important;` return `--${cssName}: ${color} !important;`
}); });
this.styles.textContent = `:root {\n${cssVars.join("\n")}}`; this.styles.textContent = `:root {\n${cssVars.join("\n")}}`;
// Adding universal theme flag which can be used in component styles
const body = document.querySelector("body");
body.classList.toggle("theme-light", theme.type === ThemeType.LIGHT);
} }
} }

View File

@ -90,6 +90,10 @@
"drawerSubtitleBackground": "#373a3e", "drawerSubtitleBackground": "#373a3e",
"drawerItemNameColor": "#87909c", "drawerItemNameColor": "#87909c",
"drawerItemValueColor": "#a0a0a0", "drawerItemValueColor": "#a0a0a0",
"clusterMenuBackground": "#252729",
"clusterMenuBorderColor": "#252729",
"clusterSettingsBackground": "#1e2124",
"addClusterIconColor": "#252729",
"boxShadow": "#0000003a", "boxShadow": "#0000003a",
"iconActiveColor": "#ffffff", "iconActiveColor": "#ffffff",
"iconActiveBackground": "#ffffff22", "iconActiveBackground": "#ffffff22",

View File

@ -26,7 +26,7 @@
"sidebarBackground": "#e8e8e8", "sidebarBackground": "#e8e8e8",
"buttonPrimaryBackground": "#3d90ce", "buttonPrimaryBackground": "#3d90ce",
"buttonDefaultBackground": "#414448", "buttonDefaultBackground": "#414448",
"buttonAccentBackground": "#3b4148", "buttonAccentBackground": "#e85555",
"buttonDisabledBackground": "#808080", "buttonDisabledBackground": "#808080",
"tableBgcStripe": "#f8f8f8", "tableBgcStripe": "#f8f8f8",
"tableBgcSelected": "#f4f5f5", "tableBgcSelected": "#f4f5f5",
@ -91,6 +91,10 @@
"drawerSubtitleBackground": "#f1f1f1", "drawerSubtitleBackground": "#f1f1f1",
"drawerItemNameColor": "#727272", "drawerItemNameColor": "#727272",
"drawerItemValueColor": "#555555", "drawerItemValueColor": "#555555",
"clusterMenuBackground": "#e8e8e8",
"clusterMenuBorderColor": "#c9cfd3",
"clusterSettingsBackground": "#ffffff",
"addClusterIconColor": "#8d8d8d",
"boxShadow": "#0000003a", "boxShadow": "#0000003a",
"iconActiveColor": "#ffffff", "iconActiveColor": "#ffffff",
"iconActiveBackground": "#a6a6a694", "iconActiveBackground": "#a6a6a694",

View File

@ -110,6 +110,12 @@ $chartStripesColor: var(--chartStripesColor);
$chartCapacityColor: var(--chartCapacityColor); $chartCapacityColor: var(--chartCapacityColor);
$pieChartDefaultColor: var(--pieChartDefaultColor); $pieChartDefaultColor: var(--pieChartDefaultColor);
// Cluster Menu
$clusterMenuBackground: var(--clusterMenuBackground);
$clusterMenuBorderColor: var(--clusterMenuBorderColor);
$clusterSettingsBackground: var(--clusterSettingsBackground);
$addClusterIconColor: var(--addClusterIconColor);
// Misc // Misc
$boxShadow: var(--boxShadow); $boxShadow: var(--boxShadow);
$iconActiveColor: var(--iconActiveColor); $iconActiveColor: var(--iconActiveColor);