WIP: major refactoring

This commit is contained in:
Jörn-Michael Miehe 2024-08-23 18:21:32 +00:00
parent 55081b24d8
commit 15b957791f
7 changed files with 79 additions and 99 deletions

View file

@ -2,33 +2,34 @@ module.exports = {
root: true,
env: {
node: true
node: true,
},
'extends': [
'plugin:vue/vue3-essential',
'eslint:recommended',
'@vue/typescript/recommended'
extends: [
"plugin:vue/vue3-essential",
"eslint:recommended",
"@vue/typescript/recommended",
],
parserOptions: {
ecmaVersion: 2020
ecmaVersion: 2020,
},
rules: {
'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off'
"no-empty": "off",
"no-console": process.env.NODE_ENV === "production" ? "warn" : "off",
"no-debugger": process.env.NODE_ENV === "production" ? "warn" : "off",
},
overrides: [
{
files: [
'**/__tests__/*.{j,t}s?(x)',
'**/tests/unit/**/*.spec.{j,t}s?(x)'
"**/__tests__/*.{j,t}s?(x)",
"**/tests/unit/**/*.spec.{j,t}s?(x)",
],
env: {
mocha: true
}
}
]
}
mocha: true,
},
},
],
};

View file

@ -29,7 +29,7 @@
<figure>
<div class="image is-unselectable">
<img :src="store.calendar_background_image" />
<img :src="store.background_image" />
<ThouCanvas>
<CalendarDoor
v-for="(door, index) in doors"

View file

@ -11,7 +11,7 @@
</ul>
</div>
<figure class="image is-unselectable">
<img :src="store.calendar_background_image" />
<img :src="store.background_image" />
<ThouCanvas>
<PreviewDoor
v-for="(door, index) in doors"

View file

@ -9,7 +9,7 @@
</ul>
</div>
<figure class="image is-unselectable">
<img :src="store.calendar_background_image" />
<img :src="store.background_image" />
<DoorCanvas :doors="doors" />
</figure>
</div>

View file

@ -1,3 +1,5 @@
import { APIError } from "./api_error";
export function objForEach<T>(
obj: T,
f: (k: keyof T, v: T[keyof T]) => void,
@ -8,3 +10,20 @@ export function objForEach<T>(
}
}
}
export type Loading<T> = T | "loading" | "error";
export function loading_success<T>(o: Loading<T>): o is T {
if (o === "loading") return false;
if (o === "error") return false;
return true;
}
export function handle_error(error: unknown) {
if (error instanceof APIError) {
error.alert();
} else {
console.error(error);
}
}

View file

@ -60,7 +60,6 @@ export interface DoorSaved {
export interface ImageData {
height: number;
width: number;
aspect_ratio: number;
data_url: string;
}

View file

@ -1,6 +1,7 @@
import { acceptHMRUpdate, defineStore } from "pinia";
import { API } from "./api";
import { Credentials, DoorSaved, SiteConfigModel } from "./model";
import { Loading, loading_success } from "./helpers";
import { Credentials, DoorSaved, ImageData, SiteConfigModel } from "./model";
import { Door } from "./rects/door";
declare global {
@ -13,9 +14,8 @@ type State = {
on_initialized: (() => void)[];
is_touch_device: boolean;
is_admin: boolean;
site_config: SiteConfigModel;
calendar_background_image: string | undefined;
calendar_aspect_ratio: number;
site_config: Loading<SiteConfigModel>;
background_image: Loading<ImageData>;
user_doors: Door[];
next_door_target: number | null;
};
@ -31,14 +31,8 @@ export const advent22Store = defineStore({
navigator.maxTouchPoints > 0 ||
navigator.msMaxTouchPoints > 0,
is_admin: false,
site_config: {
title: document.title,
subtitle: "",
content: "",
footer: "",
},
calendar_background_image: undefined,
calendar_aspect_ratio: 1,
site_config: "loading",
background_image: "loading",
user_doors: [],
next_door_target: null,
}),
@ -48,39 +42,29 @@ export const advent22Store = defineStore({
this.update().then(() => this.on_initialized.forEach((fn) => fn()));
},
update(): Promise<void> {
return new Promise((resolve, reject) => {
API.request("user/favicon");
this.advent22
.api_get_blob("user/favicon")
.then((favicon_src) => {
async update(): Promise<void> {
try {
const favicon = await API.request<ImageData>("user/favicon");
const link: HTMLLinkElement =
document.querySelector("link[rel*='icon']") ||
document.createElement("link");
link.rel = "shortcut icon";
link.type = "image/x-icon";
link.href = favicon_src;
link.href = favicon.data_url;
if (link.parentElement === null)
document.getElementsByTagName("head")[0].appendChild(link);
})
.catch(() => {});
} catch {}
Promise.all([
const [is_admin, site_config, background_image, user_doors, next_door] =
await Promise.all([
this.update_is_admin(),
this.advent22.api_get<SiteConfigModel>("user/site_config"),
this.advent22.api_get_blob("user/background_image"),
this.advent22.api_get<DoorSaved[]>("user/doors"),
this.advent22.api_get<number | null>("user/next_door"),
])
.then(
([
is_admin,
site_config,
background_image,
user_doors,
next_door,
]) => {
API.request<SiteConfigModel>("user/site_config"),
API.request<ImageData>("user/background_image"),
API.request<DoorSaved[]>("user/doors"),
API.request<number | null>("user/next_door"),
]);
is_admin; // discard value
document.title = site_config.title;
@ -89,42 +73,27 @@ export const advent22Store = defineStore({
document.title += " " + site_config.subtitle;
this.site_config = site_config;
this.calendar_background_image = background_image;
this.background_image = background_image;
this.user_doors.length = 0;
for (const door_saved of user_doors) {
this.user_doors.push(Door.load(door_saved));
}
if (next_door !== null)
this.next_door_target = Date.now() + next_door;
resolve();
},
)
.catch(reject);
});
if (next_door !== null) this.next_door_target = Date.now() + next_door;
},
when_initialized(callback: () => void): void {
if (this.is_initialized) {
if (loading_success(this.site_config)) {
callback();
} else {
this.on_initialized.push(callback);
}
},
update_is_admin(): Promise<boolean> {
return new Promise((resolve, reject) => {
this.advent22
.api_get<boolean>("admin/is_admin")
.then((is_admin) => {
this.is_admin = is_admin;
resolve(is_admin);
})
.catch(reject);
});
async update_is_admin(): Promise<boolean> {
this.is_admin = await API.request<boolean>("admin/is_admin");
return this.is_admin;
},
login(creds: Credentials): Promise<boolean> {
@ -139,14 +108,6 @@ export const advent22Store = defineStore({
toggle_touch_device(): void {
this.is_touch_device = !this.is_touch_device;
},
set_calendar_aspect_ratio(rect: DOMRectReadOnly): void {
const result = rect.width / rect.height;
// filter suspicious results
if (result !== 0 && isFinite(result) && !isNaN(result))
this.calendar_aspect_ratio = result;
},
},
});