Skip to content

Commit b77bbf7

Browse files
committed
(themes) Add CSS layers to ease up variables handling
- introduce "grist-base", "grist-theme" and "grist-custom" css layers in order to easily handle priority of css variables and base css rules - apply css default variables and css reset on the "grist-base" layer. Note that the way default html/body css is loaded has been changed to be simpler, but maybe I assumed too much here, I didn't dig too deep to get the whole context - apply custom theme css variables on the "grist-theme" layer - a potential custom.css file should wrap its code in the "grist-custom" layer, as the updated example file suggests This will allow base/theme/custom CSS to generate the same variable names while being sure custom css takes precedence theme variables, and theme variables take precedence over default variables.
1 parent d107464 commit b77bbf7

File tree

6 files changed

+81
-72
lines changed

6 files changed

+81
-72
lines changed

app/client/app.css

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
/* global variables */
2+
@layer grist-base, grist-theme, grist-custom;
23
:root {
34
--color-logo-row: #F9AE41;
45
--color-logo-col: #2CB0AF;
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
/**
2+
* Gets or creates a style element in the head of the document with the given `id`.
3+
*
4+
* Useful for grouping CSS values such as theme custom properties without needing to
5+
* pollute the document with in-line styles.
6+
*/
7+
export function getOrCreateStyleElement(id: string) {
8+
let style = document.head.querySelector(`#${id}`);
9+
if (style) { return style; }
10+
style = document.createElement('style');
11+
style.setAttribute('id', id);
12+
document.head.append(style);
13+
return style;
14+
}

app/client/ui/PagePanels.ts

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,3 @@
1-
/**
2-
* Note that it assumes the presence of cssVars.cssRootVars on <body>.
3-
*/
41
import {makeT} from 'app/client/lib/localization';
52
import * as commands from 'app/client/components/commands';
63
import {watchElementForBlur} from 'app/client/lib/FocusLayer';

app/client/ui2018/cssVars.ts

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@
88
*/
99
import {urlState} from 'app/client/models/gristUrlState';
1010
import {getTheme, ProductFlavor} from 'app/client/ui/CustomThemes';
11-
import {dom, DomElementMethod, makeTestId, Observable, styled, TestId} from 'grainjs';
11+
import {getOrCreateStyleElement} from 'app/client/lib/getOrCreateStyleElement';
12+
import {DomElementMethod, makeTestId, Observable, styled, TestId} from 'grainjs';
1213
import debounce = require('lodash/debounce');
1314
import values = require('lodash/values');
1415

@@ -922,12 +923,6 @@ export const theme = {
922923

923924
const cssColors = values(colors).map(v => v.decl()).join('\n');
924925
const cssVars = values(vars).map(v => v.decl()).join('\n');
925-
const cssFontParams = `
926-
font-family: ${vars.fontFamily};
927-
font-size: ${vars.mediumFontSize};
928-
-moz-osx-font-smoothing: grayscale;
929-
-webkit-font-smoothing: antialiased;
930-
`;
931926

932927
// We set box-sizing globally to match bootstrap's setting of border-box, since we are integrating
933928
// into an app which already has it set, and it's impossible to make things look consistently with
@@ -969,8 +964,8 @@ const cssFontStyles = `
969964
}
970965
`;
971966

972-
const cssVarsOnly = styled('div', cssColors + cssVars);
973-
const cssBodyVars = styled('div', cssFontParams + cssColors + cssVars + cssBorderBox + cssInputFonts + cssFontStyles);
967+
const cssRootVars = cssColors + cssVars;
968+
const cssReset = cssBorderBox + cssInputFonts + cssFontStyles;
974969

975970
const cssBody = styled('body', `
976971
margin: 0;
@@ -980,10 +975,12 @@ const cssBody = styled('body', `
980975
const cssRoot = styled('html', `
981976
height: 100%;
982977
overflow: hidden;
978+
font-family: ${vars.fontFamily};
979+
font-size: ${vars.mediumFontSize};
980+
-moz-osx-font-smoothing: grayscale;
981+
-webkit-font-smoothing: antialiased;
983982
`);
984983

985-
export const cssRootVars = cssBodyVars.className;
986-
987984
// Also make a globally available testId, with a simple "test-" prefix (i.e. in tests, query css
988985
// class ".test-{name}". Ideally, we'd use noTestId() instead in production.
989986
export const testId: TestId = makeTestId('test-');
@@ -1060,7 +1057,15 @@ export function isScreenResizing(): Observable<boolean> {
10601057
* Attaches the global css properties to the document's root to make them available in the page.
10611058
*/
10621059
export function attachCssRootVars(productFlavor: ProductFlavor, varsOnly: boolean = false) {
1063-
dom.update(document.documentElement, varsOnly ? dom.cls(cssVarsOnly.className) : dom.cls(cssRootVars));
1060+
/* apply each group of rules and variables in the correct css layer
1061+
* see app/client/app.css for layers order */
1062+
getOrCreateStyleElement('grist-root-css').textContent = `
1063+
@layer grist-base {
1064+
:root {
1065+
${cssRootVars}
1066+
}
1067+
${!varsOnly && cssReset}
1068+
}`;
10641069
document.documentElement.classList.add(cssRoot.className);
10651070
document.body.classList.add(cssBody.className);
10661071
const customTheme = getTheme(productFlavor);

app/client/ui2018/theme.ts

Lines changed: 7 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { createPausableObs, PausableObservable } from 'app/client/lib/pausableObs';
22
import { getStorage } from 'app/client/lib/storage';
3+
import { getOrCreateStyleElement } from 'app/client/lib/getOrCreateStyleElement';
34
import { urlState } from 'app/client/models/gristUrlState';
45
import { Theme, ThemeAppearance, ThemeColors, ThemePrefs } from 'app/common/ThemePrefs';
56
import { getThemeColors } from 'app/common/Themes';
@@ -130,9 +131,13 @@ function attachCssThemeVars({appearance, colors: themeColors}: Theme) {
130131
properties.push(...getCssThemeBackgroundProperties(appearance));
131132

132133
// Apply the properties to the theme style element.
133-
getOrCreateStyleElement('grist-theme').textContent = `:root {
134+
// The 'grist-theme' layer takes precedence over the 'grist-base' layer where
135+
// default CSS variables are defined.
136+
getOrCreateStyleElement('grist-theme').textContent = `@layer grist-theme {
137+
:root {
134138
${properties.join('\n')}
135-
}`;
139+
}
140+
}`;
136141

137142
// Make the browser aware of the color scheme.
138143
document.documentElement.style.setProperty(`color-scheme`, appearance);
@@ -174,18 +179,3 @@ function getCssThemeBackgroundProperties(appearance: ThemeAppearance) {
174179
: 'url("img/gplaypattern.png")';
175180
return [`--grist-theme-bg: ${value};`];
176181
}
177-
178-
/**
179-
* Gets or creates a style element in the head of the document with the given `id`.
180-
*
181-
* Useful for grouping CSS values such as theme custom properties without needing to
182-
* pollute the document with in-line styles.
183-
*/
184-
function getOrCreateStyleElement(id: string) {
185-
let style = document.head.querySelector(`#${id}`);
186-
if (style) { return style; }
187-
style = document.createElement('style');
188-
style.setAttribute('id', id);
189-
document.head.append(style);
190-
return style;
191-
}

static/custom.css

Lines changed: 42 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,42 +1,44 @@
1-
:root {
2-
/* logo */
3-
--icon-GristLogo: url("ui-icons/Logo/GristLogo.svg") !important;
4-
--grist-logo-bg: #040404 !important;
5-
--grist-logo-size: 22px 22px !important;
1+
@layer grist-custom {
2+
:root {
3+
/* logo */
4+
--icon-GristLogo: url("ui-icons/Logo/GristLogo.svg") !important;
5+
--grist-logo-bg: #040404 !important;
6+
--grist-logo-size: 22px 22px !important;
67

7-
/* colors */
8-
--grist-color-light-grey: #F7F7F7 !important;
9-
--grist-color-medium-grey: rgba(217,217,217,0.6) !important;
10-
--grist-color-medium-grey-opaque: #E8E8E8 !important;
11-
--grist-color-dark-grey: #D9D9D9 !important;
12-
--grist-color-light: #FFFFFF !important;
13-
--grist-color-dark: #262633 !important;
14-
--grist-color-dark-bg: #262633 !important;
15-
--grist-color-slate: #929299 !important;
16-
--grist-color-light-green: #16B378 !important;
17-
--grist-color-dark-green: #009058 !important;
18-
--grist-color-darker-green: #007548 !important;
19-
--grist-color-lighter-green: #b1ffe2 !important;
20-
--grist-color-lighter-blue: #87b2f9 !important;
21-
--grist-color-light-blue: #3B82F6 !important;
22-
--grist-color-cursor: #16B378 !important;
23-
--grist-color-selection: rgba(22,179,120,0.15) !important;
24-
--grist-color-selection-opaque: #DCF4EB !important;
25-
--grist-color-selection-darker-opaque: #d6eee5 !important;
26-
--grist-color-inactive-cursor: #A2E1C9 !important;
27-
--grist-color-hover: #bfbfbf !important;
28-
--grist-color-error: #D0021B !important;
29-
--grist-color-warning: #F9AE41 !important;
30-
--grist-color-warning-bg: #dd962c !important;
31-
--grist-color-backdrop: rgba(38,38,51,0.9) !important;
32-
--grist-label-text-bg: #FFFFFF !important;
33-
--grist-label-active-bg: #F0F0F0 !important;
34-
--grist-primary-fg: #16B378 !important;
35-
--grist-primary-fg-hover: #009058 !important;
36-
--grist-primary-bg: #ffffff !important;
37-
--grist-control-bg: #ffffff !important;
38-
--grist-control-fg: #16B378 !important;
39-
--grist-primary-fg-hover: #009058 !important;
40-
--grist-control-border: 1px solid #11B683 !important;
41-
--grist-toast-bg: #040404 !important;
8+
/* colors */
9+
--grist-color-light-grey: #F7F7F7 !important;
10+
--grist-color-medium-grey: rgba(217,217,217,0.6) !important;
11+
--grist-color-medium-grey-opaque: #E8E8E8 !important;
12+
--grist-color-dark-grey: #D9D9D9 !important;
13+
--grist-color-light: #FFFFFF !important;
14+
--grist-color-dark: #262633 !important;
15+
--grist-color-dark-bg: #262633 !important;
16+
--grist-color-slate: #929299 !important;
17+
--grist-color-light-green: #16B378 !important;
18+
--grist-color-dark-green: #009058 !important;
19+
--grist-color-darker-green: #007548 !important;
20+
--grist-color-lighter-green: #b1ffe2 !important;
21+
--grist-color-lighter-blue: #87b2f9 !important;
22+
--grist-color-light-blue: #3B82F6 !important;
23+
--grist-color-cursor: #16B378 !important;
24+
--grist-color-selection: rgba(22,179,120,0.15) !important;
25+
--grist-color-selection-opaque: #DCF4EB !important;
26+
--grist-color-selection-darker-opaque: #d6eee5 !important;
27+
--grist-color-inactive-cursor: #A2E1C9 !important;
28+
--grist-color-hover: #bfbfbf !important;
29+
--grist-color-error: #D0021B !important;
30+
--grist-color-warning: #F9AE41 !important;
31+
--grist-color-warning-bg: #dd962c !important;
32+
--grist-color-backdrop: rgba(38,38,51,0.9) !important;
33+
--grist-label-text-bg: #FFFFFF !important;
34+
--grist-label-active-bg: #F0F0F0 !important;
35+
--grist-primary-fg: #16B378 !important;
36+
--grist-primary-fg-hover: #009058 !important;
37+
--grist-primary-bg: #ffffff !important;
38+
--grist-control-bg: #ffffff !important;
39+
--grist-control-fg: #16B378 !important;
40+
--grist-primary-fg-hover: #009058 !important;
41+
--grist-control-border: 1px solid #11B683 !important;
42+
--grist-toast-bg: #040404 !important;
43+
}
4244
}

0 commit comments

Comments
 (0)