Skip to content

Instantly share code, notes, and snippets.

@bwindels
Last active April 11, 2022 08:11
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save bwindels/16930ddb0bc0f0e14009f8880793f7bf to your computer and use it in GitHub Desktop.
Save bwindels/16930ddb0bc0f0e14009f8880793f7bf to your computer and use it in GitHub Desktop.
class IconSerializer {
toURL(iconData: string, path: string): string {
// for build-time, we emit an asset with iconData and a name derived from path
// for run-time, we return a base64 data url of iconData
return "";
}
}
class Icon {
constructor(
// the variable name the postcss plugin came up with when it replaced the url() expression with var()
readonly urlVariable: string,
// the color names specified in ?colors=...,... in the url
private readonly colorNames: string[],
// the file contents of the icon
private readonly iconData: string,
// the icon path without the query parameter
private readonly path: string,
// how the icon should be serialized, based on whether we're running at build time or runtime
private readonly serializer: IconSerializer
) {}
createURLWithColors(colorValues: Map<string, string>): string {
const iconData = ;///
// parse svg in this.iconData, and look for colors in certain attributes,
// replacing hard-coded colors ([fushia, orange, ...]) with colors in colorValues
// of which we look up the name in this.colorNames
return this.serializer.toURL(iconData, this.path);
}
}
// during build time, this would be called from a postcss plugin to figure out what to pass as the "variables" options to the "postcss-css-variables" plugin
// during dev time, we would run this just before loading a css file where the css variables haven't been replaced yet, and we would
// set all the calculated variables on the document in a style argument.
export function expandDerivedVariables(
// all the derived variables used in the theme css (detected by a postcss plugin), same format as in theme definition file
derivedVariables: string[],
// the base color values provided by a JSON file
baseValues: Map<string, string>,
// icons detected by a postcss plugin, e.g. all usages of a url('icon.svg?colors=icon-color,...')
icons: Icon[]
): Map<string, string> {
const values = new Map(baseValues);
// calculate variable values from derivedVariables and add them to the values map
for (const icon of icons) {
values.set(icon.urlVariable, icon.createURLWithColors(values)); // in dev will turn to base64, prod to asset path
}
return values;
}
var postcss = require("postcss");
var cssvariables = require("postcss-css-variables");
var fs = require("fs");
var mycss = fs.readFileSync("input.css", "utf8");
/*
to support something like --avatar-color-darker-20 we will need
to write a plugin that takes the basic color set as an input and
first finds all the variables in the css AST.
Then it finds the ones that folow the --darker/fn pattern and parse
the names and calculate the derived color. Then once it has figured out
which variables need to be defined, it calls cssvariables as a nested plugin
with the variables option.
the plugin could also throw if it finds any variables that are not in the basic
color set
*/
// use off-color package to derive colors?
// good plugin api to find fn usages like url and var:
// https://github.com/devex-web-frontend/postcss-assets-rebase/blob/master/index.js
// Process your CSS with postcss-css-variables
var output = postcss([cssvariables({
variables: {
"icon-color": "red",
"avatar-color--darken-20": "blue",
"avatar-color--lighten-20": "lightblue",
}
})]).process(mycss).css;
console.log(output);
// a theme with it's own css file
// the source section is generated by the build system
{
"version": 1, //format version
"name": "Element",
"source": {
// this css file has the css variables replaced with literal values and is compatible with IE11
"built-asset": "element-theme-ac77c7b7.css",
// optional, the same style sheets with css variables not yet replaced.
// this is the style sheets that will be used when this theme or derived theme is loaded at runtime.
"runtime-asset": "element-theme-runtime-89er9w9e.css",
"derived-variables": [
"icon-color--darker-20",
"foo-color=icon-color--lighter-20", // include aliases so we can also derive colors from them
"foo-color--darker-10"
],
"icons": {
"icon-url-1": "chevron-38g9h89s.svg?colors=icon-color",
"icon-url-2": "add-7sd8s78d.svg",
},
},
"values": {
// this is the same format as font-faces in custom themes in element
"font-faces": [
{
"font-family": "Inter",
"src": [{"asset": "/fonts/Inter.ttf", "format": "ttf"}]
}
],
"variants": {
"light": {
"base": true,
"default": true, // can be specified for a dark and non-dark variant
"name": "Light",
"variables": {
// could also be logo urls, or fonts, not only colors
"icon-color": "#CCC",
"text-color": "#222",
"default-font": "Inter, sans", // only needs to be listed in the default variant, the other variants will expand on this one
"monospace-font" "'Courier new'"
}
},
"dark": {
"dark": true,
"default": true,
"name": "Dark",
"variables": {
"icon-color": "#111",
"text-color": "#DDD"
}
},
"dark-blue": {
"dark": true,
"name": "Dark Blue",
"variables": {
"icon-color": "#001",
"text-color": "#AAD"
}
}
}
}
}
// a derived theme
{
"name": "Customer",
"source": {
"extends": "element" // id listed in config file or url
},
"values": {
// branded font and colors and logo
}
}
@bwindels
Copy link
Author

bwindels commented Feb 24, 2022

supported themes will be listed in the config file, that way to add a (custom) theme you do need to control the hosting server but you don't need to build hydrogen

e.g.:

themes: {element: "element.json", customer: "https://some-other-server.org/customer-theme.json"},
theme_default: "element"

@bwindels
Copy link
Author

The above mapping is after the build system has run. Before the build is done it will be something like this:

{
  "themes": {"element": null},
  "theme_default": "element"
}

the theme location is left empty/null as it should always be

`${themeBaseDir}/${themeName}`

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment