Skip to content

Commit

Permalink
(themes) Add CSS layers to ease up variables handling
Browse files Browse the repository at this point in the history
- 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.
  • Loading branch information
manuhabitela committed Dec 12, 2024
1 parent d107464 commit b77bbf7
Show file tree
Hide file tree
Showing 6 changed files with 81 additions and 72 deletions.
1 change: 1 addition & 0 deletions app/client/app.css
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
/* global variables */
@layer grist-base, grist-theme, grist-custom;
:root {
--color-logo-row: #F9AE41;
--color-logo-col: #2CB0AF;
Expand Down
14 changes: 14 additions & 0 deletions app/client/lib/getOrCreateStyleElement.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/**
* Gets or creates a style element in the head of the document with the given `id`.
*
* Useful for grouping CSS values such as theme custom properties without needing to
* pollute the document with in-line styles.
*/
export function getOrCreateStyleElement(id: string) {
let style = document.head.querySelector(`#${id}`);
if (style) { return style; }
style = document.createElement('style');
style.setAttribute('id', id);
document.head.append(style);
return style;
}
3 changes: 0 additions & 3 deletions app/client/ui/PagePanels.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@
/**
* Note that it assumes the presence of cssVars.cssRootVars on <body>.
*/
import {makeT} from 'app/client/lib/localization';
import * as commands from 'app/client/components/commands';
import {watchElementForBlur} from 'app/client/lib/FocusLayer';
Expand Down
29 changes: 17 additions & 12 deletions app/client/ui2018/cssVars.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@
*/
import {urlState} from 'app/client/models/gristUrlState';
import {getTheme, ProductFlavor} from 'app/client/ui/CustomThemes';
import {dom, DomElementMethod, makeTestId, Observable, styled, TestId} from 'grainjs';
import {getOrCreateStyleElement} from 'app/client/lib/getOrCreateStyleElement';
import {DomElementMethod, makeTestId, Observable, styled, TestId} from 'grainjs';
import debounce = require('lodash/debounce');
import values = require('lodash/values');

Expand Down Expand Up @@ -922,12 +923,6 @@ export const theme = {

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

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

const cssVarsOnly = styled('div', cssColors + cssVars);
const cssBodyVars = styled('div', cssFontParams + cssColors + cssVars + cssBorderBox + cssInputFonts + cssFontStyles);
const cssRootVars = cssColors + cssVars;
const cssReset = cssBorderBox + cssInputFonts + cssFontStyles;

const cssBody = styled('body', `
margin: 0;
Expand All @@ -980,10 +975,12 @@ const cssBody = styled('body', `
const cssRoot = styled('html', `
height: 100%;
overflow: hidden;
font-family: ${vars.fontFamily};
font-size: ${vars.mediumFontSize};
-moz-osx-font-smoothing: grayscale;
-webkit-font-smoothing: antialiased;
`);

export const cssRootVars = cssBodyVars.className;

// Also make a globally available testId, with a simple "test-" prefix (i.e. in tests, query css
// class ".test-{name}". Ideally, we'd use noTestId() instead in production.
export const testId: TestId = makeTestId('test-');
Expand Down Expand Up @@ -1060,7 +1057,15 @@ export function isScreenResizing(): Observable<boolean> {
* Attaches the global css properties to the document's root to make them available in the page.
*/
export function attachCssRootVars(productFlavor: ProductFlavor, varsOnly: boolean = false) {
dom.update(document.documentElement, varsOnly ? dom.cls(cssVarsOnly.className) : dom.cls(cssRootVars));
/* apply each group of rules and variables in the correct css layer
* see app/client/app.css for layers order */
getOrCreateStyleElement('grist-root-css').textContent = `
@layer grist-base {
:root {
${cssRootVars}
}
${!varsOnly && cssReset}
}`;
document.documentElement.classList.add(cssRoot.className);
document.body.classList.add(cssBody.className);
const customTheme = getTheme(productFlavor);
Expand Down
24 changes: 7 additions & 17 deletions app/client/ui2018/theme.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { createPausableObs, PausableObservable } from 'app/client/lib/pausableObs';
import { getStorage } from 'app/client/lib/storage';
import { getOrCreateStyleElement } from 'app/client/lib/getOrCreateStyleElement';
import { urlState } from 'app/client/models/gristUrlState';
import { Theme, ThemeAppearance, ThemeColors, ThemePrefs } from 'app/common/ThemePrefs';
import { getThemeColors } from 'app/common/Themes';
Expand Down Expand Up @@ -130,9 +131,13 @@ function attachCssThemeVars({appearance, colors: themeColors}: Theme) {
properties.push(...getCssThemeBackgroundProperties(appearance));

// Apply the properties to the theme style element.
getOrCreateStyleElement('grist-theme').textContent = `:root {
// The 'grist-theme' layer takes precedence over the 'grist-base' layer where
// default CSS variables are defined.
getOrCreateStyleElement('grist-theme').textContent = `@layer grist-theme {
:root {
${properties.join('\n')}
}`;
}
}`;

// Make the browser aware of the color scheme.
document.documentElement.style.setProperty(`color-scheme`, appearance);
Expand Down Expand Up @@ -174,18 +179,3 @@ function getCssThemeBackgroundProperties(appearance: ThemeAppearance) {
: 'url("img/gplaypattern.png")';
return [`--grist-theme-bg: ${value};`];
}

/**
* Gets or creates a style element in the head of the document with the given `id`.
*
* Useful for grouping CSS values such as theme custom properties without needing to
* pollute the document with in-line styles.
*/
function getOrCreateStyleElement(id: string) {
let style = document.head.querySelector(`#${id}`);
if (style) { return style; }
style = document.createElement('style');
style.setAttribute('id', id);
document.head.append(style);
return style;
}
82 changes: 42 additions & 40 deletions static/custom.css
Original file line number Diff line number Diff line change
@@ -1,42 +1,44 @@
:root {
/* logo */
--icon-GristLogo: url("ui-icons/Logo/GristLogo.svg") !important;
--grist-logo-bg: #040404 !important;
--grist-logo-size: 22px 22px !important;
@layer grist-custom {
:root {
/* logo */
--icon-GristLogo: url("ui-icons/Logo/GristLogo.svg") !important;
--grist-logo-bg: #040404 !important;
--grist-logo-size: 22px 22px !important;

/* colors */
--grist-color-light-grey: #F7F7F7 !important;
--grist-color-medium-grey: rgba(217,217,217,0.6) !important;
--grist-color-medium-grey-opaque: #E8E8E8 !important;
--grist-color-dark-grey: #D9D9D9 !important;
--grist-color-light: #FFFFFF !important;
--grist-color-dark: #262633 !important;
--grist-color-dark-bg: #262633 !important;
--grist-color-slate: #929299 !important;
--grist-color-light-green: #16B378 !important;
--grist-color-dark-green: #009058 !important;
--grist-color-darker-green: #007548 !important;
--grist-color-lighter-green: #b1ffe2 !important;
--grist-color-lighter-blue: #87b2f9 !important;
--grist-color-light-blue: #3B82F6 !important;
--grist-color-cursor: #16B378 !important;
--grist-color-selection: rgba(22,179,120,0.15) !important;
--grist-color-selection-opaque: #DCF4EB !important;
--grist-color-selection-darker-opaque: #d6eee5 !important;
--grist-color-inactive-cursor: #A2E1C9 !important;
--grist-color-hover: #bfbfbf !important;
--grist-color-error: #D0021B !important;
--grist-color-warning: #F9AE41 !important;
--grist-color-warning-bg: #dd962c !important;
--grist-color-backdrop: rgba(38,38,51,0.9) !important;
--grist-label-text-bg: #FFFFFF !important;
--grist-label-active-bg: #F0F0F0 !important;
--grist-primary-fg: #16B378 !important;
--grist-primary-fg-hover: #009058 !important;
--grist-primary-bg: #ffffff !important;
--grist-control-bg: #ffffff !important;
--grist-control-fg: #16B378 !important;
--grist-primary-fg-hover: #009058 !important;
--grist-control-border: 1px solid #11B683 !important;
--grist-toast-bg: #040404 !important;
/* colors */
--grist-color-light-grey: #F7F7F7 !important;
--grist-color-medium-grey: rgba(217,217,217,0.6) !important;
--grist-color-medium-grey-opaque: #E8E8E8 !important;
--grist-color-dark-grey: #D9D9D9 !important;
--grist-color-light: #FFFFFF !important;
--grist-color-dark: #262633 !important;
--grist-color-dark-bg: #262633 !important;
--grist-color-slate: #929299 !important;
--grist-color-light-green: #16B378 !important;
--grist-color-dark-green: #009058 !important;
--grist-color-darker-green: #007548 !important;
--grist-color-lighter-green: #b1ffe2 !important;
--grist-color-lighter-blue: #87b2f9 !important;
--grist-color-light-blue: #3B82F6 !important;
--grist-color-cursor: #16B378 !important;
--grist-color-selection: rgba(22,179,120,0.15) !important;
--grist-color-selection-opaque: #DCF4EB !important;
--grist-color-selection-darker-opaque: #d6eee5 !important;
--grist-color-inactive-cursor: #A2E1C9 !important;
--grist-color-hover: #bfbfbf !important;
--grist-color-error: #D0021B !important;
--grist-color-warning: #F9AE41 !important;
--grist-color-warning-bg: #dd962c !important;
--grist-color-backdrop: rgba(38,38,51,0.9) !important;
--grist-label-text-bg: #FFFFFF !important;
--grist-label-active-bg: #F0F0F0 !important;
--grist-primary-fg: #16B378 !important;
--grist-primary-fg-hover: #009058 !important;
--grist-primary-bg: #ffffff !important;
--grist-control-bg: #ffffff !important;
--grist-control-fg: #16B378 !important;
--grist-primary-fg-hover: #009058 !important;
--grist-control-border: 1px solid #11B683 !important;
--grist-toast-bg: #040404 !important;
}
}

0 comments on commit b77bbf7

Please sign in to comment.