-
-
Notifications
You must be signed in to change notification settings - Fork 359
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
Suggested implementation of themes refactoring #1340
base: main
Are you sure you want to change the base?
Suggested implementation of themes refactoring #1340
Conversation
e65a3f0
to
f9027ce
Compare
Approach makes sense to me. Thank you.
Making all the tokens required in |
Great :)
So to be 100% clear, you mean at least this?
But do you also mean this?
I'd argue if we think those component-specific variables are kinda legacy and we eventually want to remove them, I'd say making them required in a theme object is maybe too much trouble? Since the idea is themes would not want to change those, as Here are a few thoughts:
Yeah I guess this way of doing was more to show the structure, indeed "grist-tokens" is not necessary. I'd argue if *everything* is listed in a theme object, the concept of "grist-base" variables is also debatable: every design token variable is tied to the theme, and then there is the custom css layer that comes on top. |
Only the variables we'd like to change from theme to theme. So yes to colors, but no to z-indexes. Padding and font size are more interesting; I can see an argument that making them required would be more of a nuisance, as they won't always change across themes. A compromise might be to make the vars (e.g. fonts, padding, etc.) optional, and the colors required, with the vars being inherited from the base layer.
No, I agree that it's too much trouble to make those required.
I had a similar thing in mind. A base theme defining the default, non-color variables makes a lot of sense to me. The current system is awkward because things live in two places, as you said. If we can narrow that down to one, that'd be great! |
Hey @georgegevoian, Here is an update to move things forward. SummaryThe idea is:
Feedback neededVariable namings and impact on widget's stylingI made the choice to abstract the css variable names as much as possible. The goal is that we don't have to regularly switch in our heads between the consumed in the codebase name ( So there is some code to map some js object keys to existing css var names. Unfortunately I only figured out later that theme variables in widget iframes was loaded differently. And from what I understand I can't import common files in the plugin-related code? Which means for now I can't go find the css variable name matching the theme key in the plugin code, like I do in the default Any advice on what I could do there? My intuition would be to actually remove the js object key <> css var name manual mapping and just generate css variable names based on the JS keys. So that TS checkersI had trouble with the ts-interface-checker related code, because it doesn't handle generics. I ended up just… removing the I'm not against a little bit of explanation here if what I did is not ok, I assume I missed something :) Next stepsIf what you see seems globally find for you, here what I wanted to continue on:
What do you think? Thanks a lot. |
Sounds good. One small suggestion - and only if it's simple to implement - would be to split the exported import {colors, fontSizes, legacyVariables} from 'app/common/ThemePrefs';
export const button = styled('button', `
font-size: ${fontSizes.medium};
color: ${colors.slate};
background-color: ${legacyVariables.controlPrimaryBg};
`); How does that look to you? I like it a bit better, but I'm also fine with how you've done it now.
Ok to remove and not worry about, for now. It was done very early on for the (ambitious) goal of supporting custom themes (where users could specify the values of individual variables). The checkers alone aren't sufficient for validation anyway (they don't actually check the values are valid CSS colors).
For preserving backward compatibility, it's really just the properties in The easiest fix for the plugin theme handling would be to move whatever theme-related code you need to
Actually, one big commit may be problematic because this repo doesn't contain all the UI code bundled in the SaaS build of Grist. Let's plan on having 2 ways of consuming tokens, with the aim of getting all the code using the old way migrated over fairly quickly in follow-up PRs. That'll give us some time to update any SaaS-only code to use the new variables. Besides that, I think your plan for next steps sounds good. Thanks @manuhabitela. |
Thanks for the quick feedback :)
Sure. I can also make theme files have the tokens listed with this structure so that everything is consistent.
Sorry I'm not sure I understood correctly. You mean keep the current mapping for old
Okay, will try to see about the webpack imports and fallback to just moving code if I struggle too much, good to know thanks.
Good to know, thanks. If I can allow myself to change the css variable names of legacyVariables right now though (like I understood in one [1]), is there not a risk of breaking external code using those variables then? Not talking about the |
Yes. In other words, anything in
You're correct that it can break external code referencing those variable names. The |
Okay well I'll leave current js name <> css names mappings as is. It's "just" one file having a couple big mappings after all, and it will prevent any surprises.
So actually I started changing things as you suggested but quickly stumbled upon cases where I started questioning what the categorization should be (like In the end I'd rather leave everything as is for now, it makes for a simpler switch (keep the same naming of previous colors+vars namings in the new tokens object). We could think about better names later maybe? I feel like this adds another layer of things to solve. |
Ok with me! |
c54bcde
to
f02621e
Compare
Ok, big update, hopefully you don't hate me too much 😬 I basically wrote a novel to explain everything in the latest commit but here is the gist of it since last time:
Questions/thoughts
|
In practice we've done this by trying not to make breaking changes to that file. For theming, @georgegevoian is the expert, but as I understood it the logical involvement that file had in theming was to inject a bunch of material sent to it from the surrounding app. Is it at all possible that you can move some of your changes into the material the surrounding app sends to |
Okay thanks to your help guys I think I managed to understand better and find a better solution for the grist-plugin-api thing :) Will keep you posted. |
Alright! Latest commit (that I'd fixup before merging) should make the grist-plugin-api issue go away. The final idea is:
To make this work I had to adapt the new format to the old way of attaching variables, so I added a few tests to make sure we don't make mistakes when writing new theme tokens. I think this is good to review @georgegevoian. One thing I noticed when searching for code sending "theme messages", as in the grist-plugin-api, is code in If any of you guys want to review @hexaltation @fflorent we can take some time in a call for context, I know this is a big chunk to swallow 🙈 |
0e6a992
to
dcf06c8
Compare
Deployed commit |
Deployed commit |
- 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.
Until now themes described each component variable. This made creating a theme difficult: we had to override a bunch of hard-coded component variables (around 435 total) if we wanted to change one color shade used globally. Some CSS variables were not defined in a theme, but as theme-agnostic tokens, in cssVars.ts. But those tokens applied values related to the light theme, and couldn't be overriden easily in the dark theme. Also, the theme-related css variables were defined in cssVars, with default values, matching the ones in the light theme. This lead to some confusion because sometimes the fallback value described in cssVar wasn't in sync with the actual value in theme. The idea of this commit is to make it easier to write theme and update theme files: - a theme file now describes around 20 main design tokens, defining the main text color, backgrounds, primary colors, etc. The hundreds of variables it defined previously are now inside a `components` key to explicitely show they are more specific. Most of those variables target one of the main design tokens to help with updating the styles globally. - a new Base.ts theme file was added, that the actual theme files use as a… base. It contains the design tokens we assume won't change 99% of the time. - to prevent too much context switching in our dev heads, now theme tokens are defined with js object keys styled names, instead of css var names (ie bgSecondary instead of 'bg-secondary'). - a new theme `tokens` object exposes all the CSS variables related to the current theme, that the codebase can consume. They are meant to be used just like cssVars `colors` and ` vars` are used today, and actually the idea would be to eventually remove those cssVars exports so that `tokens` is the only one used. Some `vars` were not migrated to a matching `token` because they were not used in the codebase, but we kept it to not break custom css/custom widget that may use the variables. - a new theme `components` object exposes all the previous cssVars `theme` variables. The current cssVars `theme` object just consumes this new object, but we could also imagine removing it altogether in the future. - for all of this to work, now a theme is always loaded, even when custom CSS is enabled, or when theme choice is actually unsupported (forms). In this latter cases, the light theme is loaded. Limitations: - I tried to have more "theme-agnostic" variable names for the gray shades and the primary color (green). The tricky part is, in the light theme there are way less dark-shades and green shades used than in the dark theme (colors are not a 1:1 match) so it's a bit hard to come up with generic, theme-agnostic tokens. This can certainly be improved but my guess is now is a good middle ground. - The switch to js object keys names made me create big mapping objects between js key and css variables, resulting in 500+ lines of code added to the app bundle and the grist-plugin-api.js file. I'm really not happy with this and would like to find a better solution. Before/after stats for the theme "components" variables: - a theme had around 435 variables set before, all hard-coded strings - now a Base theme, common to dark and light, defines around 290 values, and around 10 of those are hard-coded, the other target the more generic tokens, making it easier to update - a specific theme (dark or light) defines around 150 variables. In each theme, around 60 of those are hard-coded. That means while there is still a big room for improvement, themes should be noticeably easier to maintain, as most values come from generic tokens.
plotly doesn't handle values that are not actual color strings. So the plotly theme broke because chart related variables now target generic tokens. Adding a way to force a css token to return the actual value instead of returning the css variable.
In order to prevent "context switching" when dealing with theme variables, choice was made to now stick with js-like keys in theme files. So that consuming tokens in the app, and writing tokens in themes, would be with the same keys (like 'bgSecondary' everywhere instead of 'bgSecondary' in one part and 'bg-secondary' in another). This initialy changed how theme css vars were attached to the DOM. However it implied modifying how external plugins load the theme variables. This is actually something we want to avoid, because writing breaking changes in the grist-plugin-api file is rather annoying to support. This commit rollbacks the way theme vars were attached so that it works as before, meaning, the theme loading function gets a list of "css like" names instead of "js like" names.
Make sure the root css vars are appended in the dom before any style, so that @layers definition is not done too late. Before that, layers were not understood correctly by custom css, resulting in having to mark as "!important" all variable definition. Now you don't need to.
62d0a68
to
62d3047
Compare
Deployed commit |
Context
Here is an example of implementation following discussions in #1295 (up until George's comment).
Proposed solution
Everything is detailed in comments and commit messages, here is a summary of it:
cssVars.colors
andcssVars.vars
, have one big unique object that holds all the design tokens (cssVars.designTokens
), that can all be overriden by a theme. Contrary to before where default colors could not be changed. The idea would be that the new object replaces the 2 others.cssVars.theme
, make the specific component variables target the new design tokens. In the end, in each Theme, specific component variables can be removed, and we can decide to define only the more global design token values (see GristDark).Questions that popped up:
cssVars
being used for the undefined variables. I'm not sure this is a great idea as it could lead to oversights when implementing new themes or updating current ones. I'm not sure it's actually an issue either. As we can easily create a new Theme by extending an existing one anyway. What do you think?Related issues
#1295
Has this been tested?
ping @dsagal @georgegevoian