🚧 ui: re-scaffolding

- fix lint errors
This commit is contained in:
Jörn-Michael Miehe 2026-02-21 23:48:18 +00:00
parent d816460efa
commit b1c65f4d4a
12 changed files with 49 additions and 63 deletions

View file

@ -1,21 +0,0 @@
{
"extends": "@vue/tsconfig/tsconfig.dom.json",
"compilerOptions": {
"experimentalDecorators": true,
"lib": ["es2020", "dom", "dom.iterable", "es2022.object", "es2023.array"],
// "moduleResolution": "node",
// "sourceMap": true,
"baseUrl": ".",
"types": ["webpack-env", "mocha", "chai"],
"paths": {
"@/*": ["src/*"]
}
},
"include": [
"src/**/*.vue",
"src/**/*.ts",
// "src/**/*.tsx",
"tests/**/*.ts"
// "tests/**/*.tsx",
]
}

View file

@ -1,11 +0,0 @@
import { describe, it, expect } from "vitest";
import { mount } from "@vue/test-utils";
import App from "../App.vue";
describe("App", () => {
it("mounts renders properly", () => {
const wrapper = mount(App);
expect(wrapper.text()).toContain("You did it!");
});
});

View file

@ -8,7 +8,7 @@
<h3>Zuordnung Buchstaben</h3> <h3>Zuordnung Buchstaben</h3>
<div class="tags are-medium"> <div class="tags are-medium">
<template v-for="(data, day) in day_data" :key="`part-${day}`"> <template v-for="[day, data] in day_data" :key="`part-${day}`">
<span v-if="data.part === ''" class="tag is-warning"> <span v-if="data.part === ''" class="tag is-warning">
{{ day }} {{ day }}
</span> </span>
@ -21,7 +21,7 @@
<h3>Zuordnung Bilder</h3> <h3>Zuordnung Bilder</h3>
<div class="tags are-medium"> <div class="tags are-medium">
<span <span
v-for="(data, day) in day_data" v-for="[day, data] in day_data"
:key="`image-${day}`" :key="`image-${day}`"
:class="'tag is-' + (data.part === '' ? 'warning' : 'primary')" :class="'tag is-' + (data.part === '' ? 'warning' : 'primary')"
> >
@ -32,7 +32,7 @@
<h3>Alle Türchen</h3> <h3>Alle Türchen</h3>
<div class="tags are-medium"> <div class="tags are-medium">
<BulmaButton <BulmaButton
v-for="(data, day) in day_data" v-for="[day, data] in day_data"
:key="`btn-${day}`" :key="`btn-${day}`"
:class="'tag is-' + (data.part === '' ? 'warning' : 'info')" :class="'tag is-' + (data.part === '' ? 'warning' : 'info')"
:icon="['fas', 'fa-door-open']" :icon="['fas', 'fa-door-open']"
@ -48,14 +48,19 @@
<script setup lang="ts"> <script setup lang="ts">
import { API } from "@/lib/api"; import { API } from "@/lib/api";
import { name_door, objForEach } from "@/lib/helpers"; import { name_door, objForEach } from "@/lib/helpers";
import type { ImageData, NumStrDict } from "@/lib/model"; import type { ImageData } from "@/lib/model";
import { ref } from "vue"; import { ref } from "vue";
import MultiModal, { type HMultiModal } from "../MultiModal.vue"; import MultiModal, { type HMultiModal } from "../MultiModal.vue";
import BulmaButton from "../bulma/Button.vue"; import BulmaButton from "../bulma/Button.vue";
import BulmaDrawer from "../bulma/Drawer.vue"; import BulmaDrawer from "../bulma/Drawer.vue";
const day_data = ref<Record<number, { part: string; image_name: string }>>({}); interface DayData {
part: string;
image_name: string;
}
const day_data = ref<Map<number, DayData>>(new Map());
let modal: HMultiModal | undefined; let modal: HMultiModal | undefined;
@ -65,24 +70,31 @@ function on_modal_handle(handle: HMultiModal): void {
async function on_open(): Promise<void> { async function on_open(): Promise<void> {
const [day_parts, day_image_names] = await Promise.all([ const [day_parts, day_image_names] = await Promise.all([
API.request<NumStrDict>("admin/day_parts"), API.request<Record<number, string>>("admin/day_parts"),
API.request<NumStrDict>("admin/day_image_names"), API.request<Record<number, string>>("admin/day_image_names"),
]); ]);
const _ensure_day_in_data = (day: number) => { const _get_data = (day: number) => {
if (!(day in day_data.value)) { let result = day_data.value.get(day);
day_data.value[day] = { part: "", image_name: "" };
if (result === undefined) {
result = { part: "", image_name: "" };
day_data.value.set(day, result);
} }
return result;
}; };
// for (const [day, part] of day_parts.entries()) {
// _get_data(day).part = part;
// }
objForEach(day_parts, (day, part) => { objForEach(day_parts, (day, part) => {
_ensure_day_in_data(day); _get_data(day).part = part;
day_data.value[day].part = part;
}); });
objForEach(day_image_names, (day, image_name) => { objForEach(day_image_names, (day, image_name) => {
_ensure_day_in_data(day); _get_data(day).image_name = image_name;
day_data.value[day].image_name = image_name;
}); });
} }

View file

@ -232,7 +232,7 @@ const admin_config_model = ref<AdminConfigModel>({
}); });
const doors = ref<DoorSaved[]>([]); const doors = ref<DoorSaved[]>([]);
const creds = ref<Record<string, Credentials>>({ const creds = ref({
dav: { dav: {
username: "", username: "",
password: "", password: "",

View file

@ -13,14 +13,19 @@
<figure class="image is-unselectable"> <figure class="image is-unselectable">
<img :src="unwrap_loading(store.background_image).data_url" /> <img :src="unwrap_loading(store.background_image).data_url" />
<ThouCanvas> <ThouCanvas>
<PreviewDoor v-for="(_, index) in model" :key="`door-${index}`" v-model="model[index]" /> <PreviewDoor
v-for="(door, index) in model"
:key="`door-${index}`"
:model-value="door"
@update:model-value="updateAt(index, door)"
/>
</ThouCanvas> </ThouCanvas>
</figure> </figure>
</div> </div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { type VueLike, unwrap_loading } from "@/lib/helpers"; import { unwrap_loading, type VueLike } from "@/lib/helpers";
import { Door } from "@/lib/rects/door"; import { Door } from "@/lib/rects/door";
import { advent22Store } from "@/lib/store"; import { advent22Store } from "@/lib/store";
@ -28,5 +33,12 @@ import ThouCanvas from "../calendar/ThouCanvas.vue";
import PreviewDoor from "./PreviewDoor.vue"; import PreviewDoor from "./PreviewDoor.vue";
const model = defineModel<VueLike<Door>[]>({ required: true }); const model = defineModel<VueLike<Door>[]>({ required: true });
function updateAt(i: number, val: VueLike<Door>) {
const copy = [...model.value];
copy[i] = val;
model.value = copy;
}
const store = advent22Store(); const store = advent22Store();
</script> </script>

View file

@ -18,12 +18,8 @@ interface Params {
export class API { export class API {
private static get api_baseurl(): string { private static get api_baseurl(): string {
// in production mode, return "proto://hostname/api" // in production mode, return "proto://hostname/api"
if (process.env.NODE_ENV === "production") { if (import.meta.env.PROD) {
return `${window.location.protocol}//${window.location.host}/api`; return `${window.location.protocol}//${window.location.host}/api`;
} else if (process.env.NODE_ENV !== "development") {
// not in prouction or development mode
// eslint-disable-next-line no-console
console.warn("Unexpected NODE_ENV value: ", process.env.NODE_ENV);
} }
// in development mode, return "proto://hostname:8000/api" // in development mode, return "proto://hostname:8000/api"
@ -84,7 +80,6 @@ export class API {
const response = await this.axios.request<T>(this.get_axios_config(p)); const response = await this.axios.request<T>(this.get_axios_config(p));
return response.data; return response.data;
} catch (reason) { } catch (reason) {
// eslint-disable-next-line no-console
console.error(`Failed to query ${p.endpoint}: ${reason}`); console.error(`Failed to query ${p.endpoint}: ${reason}`);
throw new APIError(reason, p.endpoint); throw new APIError(reason, p.endpoint);
} }

View file

@ -39,7 +39,6 @@ export function handle_error(error: unknown): void {
if (error instanceof APIError) { if (error instanceof APIError) {
error.alert(); error.alert();
} else { } else {
// eslint-disable-next-line no-console
console.error(error); console.error(error);
} }
} }

View file

@ -45,10 +45,6 @@ export interface SiteConfigModel {
footer: string; footer: string;
} }
export interface NumStrDict {
[key: number]: string;
}
export interface DoorSaved { export interface DoorSaved {
day: number; day: number;
x1: number; x1: number;

View file

@ -5,6 +5,8 @@
"compilerOptions": { "compilerOptions": {
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
"lib": ["es2020", "dom", "dom.iterable", "es2022.object", "es2023.array"],
"paths": { "paths": {
"@/*": ["./src/*"] "@/*": ["./src/*"]
} }

View file

@ -5,7 +5,6 @@
"compilerOptions": { "compilerOptions": {
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.vitest.tsbuildinfo", "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.vitest.tsbuildinfo",
"lib": [],
"types": ["node", "jsdom"] "types": ["node", "jsdom"]
} }
} }

View file

@ -1,7 +1,7 @@
import { fileURLToPath, URL } from "node:url"; import { fileURLToPath, URL } from "node:url";
import { defineConfig } from "vite";
import vue from "@vitejs/plugin-vue"; import vue from "@vitejs/plugin-vue";
import { defineConfig } from "vite";
import vueDevTools from "vite-plugin-vue-devtools"; import vueDevTools from "vite-plugin-vue-devtools";
// https://vite.dev/config/ // https://vite.dev/config/
@ -12,4 +12,7 @@ export default defineConfig({
"@": fileURLToPath(new URL("./src", import.meta.url)), "@": fileURLToPath(new URL("./src", import.meta.url)),
}, },
}, },
build: {
sourcemap: true,
},
}); });