Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
106 changes: 69 additions & 37 deletions src/Core.Assets/src/Design/ThemeStorage.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,25 @@
import { DesignTheme } from "../DesignTheme";

type ThemeStorageValue = { mode: string | null, primaryColor: string | null, neutralColor: string | null };

type StorageLike = Pick<Storage, "getItem" | "setItem" | "removeItem">;

const memoryStorage = (() => {
const values: Record<string, string> = {};

return {
getItem(key: string): string | null {
return Object.prototype.hasOwnProperty.call(values, key) ? values[key] : null;
},
setItem(key: string, value: string): void {
values[key] = value;
},
Comment thread
vnbaaij marked this conversation as resolved.
removeItem(key: string): void {
delete values[key];
},
} satisfies StorageLike;
})();

class ThemeStorage {

private _designTheme: DesignTheme
Expand All @@ -19,13 +39,21 @@ class ThemeStorage {
return this._designTheme.storageName;
}

private static getStorage(): StorageLike {
try {
const storage = window.localStorage;
if (storage == null) {
return memoryStorage;
}

public updateLocalStorage(mode: string | null, primaryColor: string | null, neutralColor: string | null): void {

// If LocalStorage is not available, do nothing.
if (localStorage == null) {
return;
return storage;
} catch {
return memoryStorage;
}
}

public updateLocalStorage(mode: string | null, primaryColor: string | null, neutralColor: string | null): void {
const storage = ThemeStorage.getStorage();

// Wait the component to be initialized
if (!this._designTheme._isInitialized) {
Expand All @@ -37,56 +65,60 @@ class ThemeStorage {
return;
}

// Save to the localstorage
localStorage.setItem(this.storageName, JSON.stringify({
const theme: ThemeStorageValue = {
mode: ThemeStorage.getValueOrNull(mode),
primaryColor: ThemeStorage.getValueOrNull(primaryColor),
neutralColor: ThemeStorage.getValueOrNull(neutralColor),
}));
}

public readLocalStorage(): { mode: string | null, primaryColor: string | null, neutralColor: string | null } | null {
};

// If LocalStorage is not available, do nothing.
if (localStorage == null) {
return null;
try {
storage.setItem(this.storageName, JSON.stringify(theme));
} catch {
// Ignore storage write failures and continue with in-memory theme state.
}
}

public readLocalStorage(): ThemeStorageValue | null {
const storage = ThemeStorage.getStorage();

// Check if storageName attribute is defined
if (this.storageName == null) {
return null;
}

// Check if localstorage exists
const storageJson = localStorage.getItem(this.storageName);
try {
const storageJson = storage.getItem(this.storageName);
if (storageJson == null) {
return null;
}

// Read the localstorage
const storageItems = JSON.parse(storageJson);

if (storageJson == null) {
return {
mode: ThemeStorage.getValueOrNull(storageItems?.mode),
primaryColor: ThemeStorage.getValueOrNull(storageItems?.primaryColor),
neutralColor: ThemeStorage.getValueOrNull(storageItems?.neutralColor),
};
} catch {
this.clearLocalStorage();
return null;
}
}

// Read the localstorage
const storageItems = JSON.parse(storageJson);
public clearLocalStorage(): void {
const storage = ThemeStorage.getStorage();

return {
mode: ThemeStorage.getValueOrNull(storageItems?.mode),
primaryColor: ThemeStorage.getValueOrNull(storageItems?.primaryColor),
neutralColor: ThemeStorage.getValueOrNull(storageItems?.neutralColor),
// Check if storageName attribute is defined
if (this.storageName == null) {
return;
}
}

public clearLocalStorage(): void {
// If LocalStorage is not available, do nothing.
if (localStorage == null) {
return;
}

// Check if storageName attribute is defined
if (this.storageName == null) {
return;
}

// Clear the localstorage
localStorage.removeItem(this.storageName);
try {
storage.removeItem(this.storageName);
} catch {
// Ignore storage clear failures and continue with in-memory theme state.
}
}

/**
Expand Down
62 changes: 53 additions & 9 deletions src/Core/wwwroot/js/loading-theme.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,55 @@
// Here we'll find the first web component and wait for it to be upgraded.
// When it is, we'll remove this invisibility from the body.

const memoryStorage = (() => {
const values = {};

return {
getItem(key) {
return Object.prototype.hasOwnProperty.call(values, key) ? values[key] : null;
},
setItem(key, value) {
values[key] = String(value);
},
Comment thread
vnbaaij marked this conversation as resolved.
removeItem(key) {
delete values[key];
}
};
})();

function getThemeStorage() {
try {
const storage = window.localStorage;
if (storage == null) {
return memoryStorage;
}

return storage;
} catch {
return memoryStorage;
}
}

function readStoredTheme(storageName) {
if (!storageName) {
return null;
}

const storage = getThemeStorage();

try {
const theme = storage.getItem(storageName);
return theme ? JSON.parse(theme) : null;
} catch {
try {
storage.removeItem(storageName);
} catch {
}

return null;
}
}

class LoadingTheme extends HTMLElement {

className = "hidden-body";
Expand All @@ -17,17 +66,12 @@ class LoadingTheme extends HTMLElement {

// Custom element added to page.
connectedCallback() {

// If LocalStorage is not available, do nothing.
if (localStorage == null) {
return;
}

// Attributes
const storageName = this.getAttribute("storage-name");
const mode = this.getAttribute("mode");
const primaryColor = this.getAttribute("primary-color");
const neutralColor = this.getAttribute("neutral-color");
const storedTheme = readStoredTheme(storageName);

const isDark = (modeSaved, isSystemDark) => {
switch (modeSaved) {
Expand All @@ -41,9 +85,9 @@ class LoadingTheme extends HTMLElement {
};

// Compute the saved or the system theme (dark/light).
const modeSaved = mode ?? JSON.parse(localStorage.getItem(storageName))?.mode;
const primaryColorSaved = primaryColor ?? JSON.parse(localStorage.getItem(storageName))?.primaryColor;
const neutralColorSaved = neutralColor ?? JSON.parse(localStorage.getItem(storageName))?.neutralColor;
const modeSaved = mode ?? storedTheme?.mode;
const primaryColorSaved = primaryColor ?? storedTheme?.primaryColor;
const neutralColorSaved = neutralColor ?? storedTheme?.neutralColor;
const isSystemDark = window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches;
const bgColor = isDark(modeSaved, isSystemDark) ? this.defaultDarkColor : this.defaultLightColor;

Expand Down
Loading