Skip to content
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

40 Implemented dynamic global css variables #89

Merged
merged 17 commits into from
Nov 9, 2023
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
189 changes: 189 additions & 0 deletions src/lib/GlobalCssProperties.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
{
"default": {
"mediaFeature": "default",
"color": {
"--navigationbar-text-color": ["display-p3", 1, 1, 1, 0],
"--console-scrollbar-thumb-color": [
"display-p3",
0.22745098039,
0.27450980392,
0.30588235294
],
"--console-scrollbar-thumbhover-color": [
"display-p3",
0.2862745098,
0.34901960784,
0.38823529411
],
"--query-success-color": [
"display-p3",
0.31372549019,
0.54901960784,
0.27450980392
],
"--query-warning-color": [
"display-p3",
0.98431372549,
0.75294117647,
0.17647058823
],
"--query-error-color": [
"display-p3",
0.82745098039,
0.18431372549,
0.18431372549
]
},
"fontSize": {
"--sidebar-fontsize": [1, "rem"],
"--sidebar-navigationbar-fontsize": [1, "rem"]
},
"border": {
"--main-navigationbar-border": [
"solid",
[0.1, "em"],
["display-p3", 0.18823529411, 0.22745098039, 0.25098039215]
],
"--main-innernavigationbar-border": [
"none solid solid solid",
[0.1, "em"],
["display-p3", 0.18823529411, 0.22745098039, 0.25098039215]
]
}
},
"schemes": [
{
"mediaFeature": "prefers-color-scheme: light",
"color": {
"--main-navigationbar-color": [
"display-p3",
0.22745098039,
0.27450980392,
0.30588235294
],
"--canvas-topbar-color": [
"display-p3",
0.2862745098,
0.34901960784,
0.38823529411
],
"--canvas-text-color": ["display-p3", 0, 0, 0],
"--sidebar-text-color": ["display-p3", 0, 0, 0],
"--background-color": [
"display-p3",
0.95686274509,
0.95686274509,
0.95686274509
],
"--console-selectedtab-color": [
"display-p3",
0.2862745098,
0.34901960784,
0.38823529411
],
"--console-unselectedtab-color": [
"display-p3",
0.22745098039,
0.27450980392,
0.30588235294
],
"--console-topbar-background-color": [
"display-p3",
0.22745098039,
0.27450980392,
0.30588235294
],
"--console-text-color": ["display-p3", 0, 0, 0],
"--sidebar-element-color": [
"display-p3",
0.93333333333,
0.93333333333,
0.93333333333
],
"--sidebar-element-hover-color": [
"display-p3",
0.81176470588,
0.84705882352,
0.86274509803
],
"--queries-input-background-color": ["display-p3", 1, 1, 1],
"--canvas-action-color": ["display-p3", 0, 0, 0],
"--console-tab-hover-color": [
"display-p3",
0.3362745098,
0.39901960784,
0.43823529411
]
}
},
{
"mediaFeature": "prefers-color-scheme: dark",
"color": {
"--main-navigationbar-color": [
"display-p3",
0.0156862745,
0.02352941176,
0.03529411764
],
"--canvas-topbar-color": [
"display-p3",
0.05490196078,
0.06666666666,
0.09019607843
],
"--canvas-text-color": ["display-p3", 1, 1, 1],
"--sidebar-text-color": ["display-p3", 1, 1, 1],
"--background-color": [
"display-p3",
0.09019607843,
0.10196078431,
0.13333333333
],
"--console-selectedtab-color": [
"display-p3",
0.08490196078,
0.09666666666,
0.12019607843
],
"--console-unselectedtab-color": [
"display-p3",
0.0156862745,
0.02352941176,
0.03529411764
],
"--console-topbar-background-color": [
"display-p3",
0.0156862745,
0.02352941176,
0.03529411764
],
"--console-text-color": ["display-p3", 1, 1, 1],
"--sidebar-element-color": [
"display-p3",
0.19215686274,
0.21176470588,
0.23529411764
],
"--sidebar-element-hover-color": [
"display-p3",
0.12215686274,
0.23176470588,
0.25529411764
],
"--queries-input-background-color": [
"display-p3",
0.05490196078,
0.06666666666,
0.09019607843
],
"--canvas-action-color": ["display-p3", 1, 1, 1],
"--console-tab-hover-color": [
"display-p3",
0.13490196078,
0.14666666666,
0.17019607843
]
}
}
]
}
206 changes: 206 additions & 0 deletions src/lib/classes/styling/GlobalCssSchemesLoader.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,206 @@
import type ColorValue from "./ZodSchemas/AttributeSchemas/ColorAttribute";
import type MediaScheme from "./ZodSchemas/MediaScheme";

import MediaSchemes from "./ZodSchemas/MediaSchemes";
import GlobalCssProperties from "../../GlobalCssProperties.json";

import type { z } from "zod";

/**
* Class for handling the loading of different properties based on active media features
*/
class GlobalCssSchemesLoader {
private _window: Window;
private _mediaSchemes: z.infer<typeof MediaSchemes>;
BaBrixx marked this conversation as resolved.
Show resolved Hide resolved
private _propertyNames: string[] = [];

// SUPPORTED MEDIA FEATURES
private _supportedMediaFeatures: string[] = [
"prefers-color-scheme: dark",
"prefers-color-scheme: light",
"prefers-reduced-motion",
"prefers-reduced-transparency",
];
BaBrixx marked this conversation as resolved.
Show resolved Hide resolved

constructor(window: Window) {
this._window = window;
BaBrixx marked this conversation as resolved.
Show resolved Hide resolved

// Parse and apply the different properties
this._mediaSchemes = this.parseMediaFeatures();
this.applySchemes();

// Add event listeners to supported features
this.addEventListeners();
}

/**
* Method for applying the specified styles
*/
applySchemes() {
// Apply standard css variables
this.applyCssVariables(this._mediaSchemes.default);

// Apply each of the mediafeatures in the order in which they are specified in the .json file
this._mediaSchemes.schemes.forEach((scheme) => {
// Return early if the medie feature does not match
if (
this._supportedMediaFeatures.includes(scheme.mediaFeature) &&
this._window.matchMedia(`(${scheme.mediaFeature})`).matches
) {
this.applyCssVariables(scheme);
}
});
}

/**
* Method for applying CSS variabels for a specific mediafeature
* @param feature
*/
applyCssVariables(feature: z.infer<typeof MediaScheme>) {
// Apply color variables
if (feature.color) {
for (const [key, val] of Object.entries(feature.color)) {
this._window.document.documentElement.style.setProperty(
key,
this.createCssColor(val),
);
this._propertyNames.push(key);
}
}

// Apply font size variables
if (feature.fontSize) {
for (const [key, val] of Object.entries(feature.fontSize)) {
this._window.document.documentElement.style.setProperty(
key,
val[0] + val[1], //TODO: Check the font size number
);
this._propertyNames.push(key);
}
}

// Apply border variables
if (feature.border) {
for (const [key, val] of Object.entries(feature.border)) {
this._window.document.documentElement.style.setProperty(
key,
this.createCssColor(val[2]) /* Border color */ +
" " +
val[0] /* Border style */ +
" " +
val[1][0] /* Border size */ +
val[1][1] /* Border size unit */,
);
this._propertyNames.push(key);
}
}
}

/**
* Method for clearing the applied styles
*/
private clearAppliedProperties() {
this._propertyNames.forEach((attribute) => {
this._window.document.documentElement.style.removeProperty(
attribute,
);
});

this._propertyNames = [];
}

/**
* Method for re-applying the specified styles
*/
reapplyMediaFeatures() {
this.clearAppliedProperties();
this.applySchemes();
}

/**
* Method for loading the GlobalCssProperties.json file
*/
private parseMediaFeatures(): z.infer<typeof MediaSchemes> {
// Parsing media features
const parsedMediaFeatures = MediaSchemes.safeParse(GlobalCssProperties);

// Throwing error if the parsing failed
if (!parsedMediaFeatures.success) {
throw new Error(parsedMediaFeatures.error.message);
BaBrixx marked this conversation as resolved.
Show resolved Hide resolved
}

return parsedMediaFeatures.data;
}

/**
* Method for adding appropriate event listeners
*/
private addEventListeners() {
this._supportedMediaFeatures.forEach((feature) => {
this._window
.matchMedia(`(${feature})`)
.addEventListener("change", () => {
this.reapplyMediaFeatures();
});
});
}

/**
* Method for checking and creating CSS color string
* @param color
* @returns CSS color string
*/
private createCssColor(color: z.infer<typeof ColorValue>): string {
const supportedGamuts: string[] = [
"srgb",
"srgb-linear",
"display-p3",
"a98-rgb",
"prophoto-rgb",
"rec2020",
"xyz",
"xyz-d50",
"xyz-d65",
];
let cssColor: string;

// Check if color gamut is supported
if (!supportedGamuts.includes(color[0])) {
throw new Error(
`Color gamut "${color[0]}" specified in parsed global css styles, is not supported."`,
);
BaBrixx marked this conversation as resolved.
Show resolved Hide resolved
}

// Check if values are within range (0.0 - 1.0)
if (
this.outOfColorRange(color[1]) ||
this.outOfColorRange(color[2]) ||
this.outOfColorRange(color[3]) ||
(color[4] && this.outOfColorRange(color[4]))
) {
throw new Error(
"Color value in parsed global css styles out of range (0.0 - 1.0).",
);
}

// Create CSS color string
if (color[4]) {
cssColor = `color(${color[0]} ${color[1]} ${color[2]} ${color[3]} / ${color[4]})`;
} else {
cssColor = `color(${color[0]} ${color[1]} ${color[2]} ${color[3]})`;
}

return cssColor;
}

/**
* Support method for checking if color is within range
* @param value
* @returns Boolean value representing if value is out of range
*/
private outOfColorRange(value: number): boolean {
return value > 1 || value < 0;
}
}

export default GlobalCssSchemesLoader;
Loading