forked from mirrors/homebox
feat: new dashboard implementation (#168)
* wip: charts.js experimental work * update lock file * wip: frontend redesign * wip: more UI fixes for consistency across themes * cleanup * improve UI log * style updates * fix lint errors
This commit is contained in:
parent
a3954dab0f
commit
6a8a25e3f8
42 changed files with 1690 additions and 296 deletions
126
frontend/composables/use-css-var.ts
Normal file
126
frontend/composables/use-css-var.ts
Normal file
|
@ -0,0 +1,126 @@
|
|||
type ColorType = "hsla";
|
||||
|
||||
export type VarOptions = {
|
||||
type: ColorType;
|
||||
transparency?: number;
|
||||
apply?: (value: string) => string;
|
||||
};
|
||||
|
||||
export type Breakpoints = {
|
||||
sm: boolean;
|
||||
md: boolean;
|
||||
lg: boolean;
|
||||
xl: boolean;
|
||||
xxl: boolean;
|
||||
};
|
||||
|
||||
export function useBreakpoints(): Breakpoints {
|
||||
const breakpoints: Breakpoints = reactive({
|
||||
sm: false,
|
||||
md: false,
|
||||
lg: false,
|
||||
xl: false,
|
||||
xxl: false,
|
||||
});
|
||||
|
||||
const updateBreakpoints = () => {
|
||||
breakpoints.sm = window.innerWidth < 640;
|
||||
breakpoints.md = window.innerWidth >= 640;
|
||||
breakpoints.lg = window.innerWidth >= 768;
|
||||
breakpoints.xl = window.innerWidth >= 1024;
|
||||
breakpoints.xxl = window.innerWidth >= 1280;
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
updateBreakpoints();
|
||||
window.addEventListener("resize", updateBreakpoints);
|
||||
});
|
||||
|
||||
onUnmounted(() => {
|
||||
window.removeEventListener("resize", updateBreakpoints);
|
||||
});
|
||||
|
||||
return breakpoints;
|
||||
}
|
||||
|
||||
class ThemeObserver {
|
||||
// eslint-disable-next-line no-use-before-define
|
||||
private static instance?: ThemeObserver;
|
||||
private readonly observer: MutationObserver;
|
||||
|
||||
private fns: (() => void)[] = [];
|
||||
|
||||
private constructor() {
|
||||
this.observer = new MutationObserver(mutations => {
|
||||
mutations.forEach(mutation => {
|
||||
if (mutation.attributeName === "data-theme") {
|
||||
this.fire();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
const html = document.querySelector("html");
|
||||
if (!html) {
|
||||
throw new Error("No html element found");
|
||||
}
|
||||
|
||||
this.observer.observe(html, { attributes: true });
|
||||
}
|
||||
|
||||
public static getInstance() {
|
||||
if (!ThemeObserver.instance) {
|
||||
ThemeObserver.instance = new ThemeObserver();
|
||||
}
|
||||
|
||||
return ThemeObserver.instance;
|
||||
}
|
||||
|
||||
private fire() {
|
||||
this.fns.forEach(fn => fn());
|
||||
}
|
||||
|
||||
public add(fn: () => void) {
|
||||
this.fns.push(fn);
|
||||
}
|
||||
|
||||
public remove(fn: () => void) {
|
||||
this.fns = this.fns.filter(f => f !== fn);
|
||||
}
|
||||
}
|
||||
|
||||
export function useCssVar(name: string, options?: VarOptions) {
|
||||
if (!options) {
|
||||
options = {
|
||||
type: "hsla",
|
||||
transparency: 1,
|
||||
apply: undefined,
|
||||
};
|
||||
}
|
||||
|
||||
const cssVal = ref(getComputedStyle(document.documentElement).getPropertyValue(name).trim());
|
||||
const update = () => {
|
||||
cssVal.value = getComputedStyle(document.documentElement).getPropertyValue(name).trim();
|
||||
};
|
||||
|
||||
ThemeObserver.getInstance().add(update);
|
||||
onUnmounted(() => {
|
||||
ThemeObserver.getInstance().remove(update);
|
||||
});
|
||||
|
||||
switch (options.type) {
|
||||
case "hsla": {
|
||||
return computed(() => {
|
||||
if (!document) {
|
||||
return "";
|
||||
}
|
||||
|
||||
let val = cssVal.value.trim().split(" ").join(", ");
|
||||
if (options?.transparency) {
|
||||
val += `, ${options.transparency}`;
|
||||
}
|
||||
|
||||
return `hsla(${val})`;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue