🔧 ui: BulmaDrawer state machine rework

This commit is contained in:
Jörn-Michael Miehe 2025-12-28 01:10:28 +00:00
parent d5c935ade7
commit eacd1da482
5 changed files with 54 additions and 80 deletions

View file

@ -2,7 +2,7 @@
<ConfigView />
<CalendarAssistant />
<DoorMapEditor />
<BulmaDrawer header="Vorschau" @open="(ready) => ready()">
<BulmaDrawer header="Vorschau">
<UserView />
</BulmaDrawer>
</template>

View file

@ -1,7 +1,7 @@
<template>
<MultiModal @handle="on_modal_handle" />
<BulmaDrawer header="Kalender-Assistent" @open="on_open" refreshable>
<BulmaDrawer header="Kalender-Assistent" :opening="on_open" refreshable>
<div class="card-content">
<div class="content">
<p>Hervorgehobenen Tagen wurde kein Buchstabe zugewiesen.</p>
@ -63,33 +63,27 @@ function on_modal_handle(handle: HMultiModal) {
modal = handle;
}
async function on_open(ready: () => void, fail: () => void) {
try {
const [day_parts, day_image_names] = await Promise.all([
API.request<NumStrDict>("admin/day_parts"),
API.request<NumStrDict>("admin/day_image_names"),
]);
async function on_open() {
const [day_parts, day_image_names] = await Promise.all([
API.request<NumStrDict>("admin/day_parts"),
API.request<NumStrDict>("admin/day_image_names"),
]);
const _ensure_day_in_data = (day: number) => {
if (!(day in day_data.value)) {
day_data.value[day] = { part: "", image_name: "" };
}
};
const _ensure_day_in_data = (day: number) => {
if (!(day in day_data.value)) {
day_data.value[day] = { part: "", image_name: "" };
}
};
objForEach(day_parts, (day, part) => {
_ensure_day_in_data(day);
day_data.value[day].part = part;
});
objForEach(day_parts, (day, part) => {
_ensure_day_in_data(day);
day_data.value[day].part = part;
});
objForEach(day_image_names, (day, image_name) => {
_ensure_day_in_data(day);
day_data.value[day].image_name = image_name;
});
ready();
} catch {
fail();
}
objForEach(day_image_names, (day, image_name) => {
_ensure_day_in_data(day);
day_data.value[day].image_name = image_name;
});
}
async function door_click(day: number) {

View file

@ -1,5 +1,5 @@
<template>
<BulmaDrawer header="Konfiguration" @open="on_open" refreshable>
<BulmaDrawer header="Konfiguration" :opening="on_open" refreshable>
<div class="card-content">
<div class="columns">
<div class="column is-one-third">
@ -247,24 +247,16 @@ function fmt_puzzle_date(name: keyof AdminConfigModel["puzzle"]): string {
return DateTime.fromISO(iso_date).toLocaleString(DateTime.DATE_SHORT);
}
async function on_open(ready: () => void, fail: () => void) {
try {
const [store_update, new_admin_config_model, new_doors] = await Promise.all(
[
store.update(),
API.request<AdminConfigModel>("admin/config_model"),
API.request<DoorSaved[]>("admin/doors"),
],
);
async function on_open() {
const [store_update, new_admin_config_model, new_doors] = await Promise.all([
store.update(),
API.request<AdminConfigModel>("admin/config_model"),
API.request<DoorSaved[]>("admin/doors"),
]);
void store_update;
admin_config_model.value = new_admin_config_model;
doors.value = new_doors;
ready();
} catch {
fail();
}
void store_update;
admin_config_model.value = new_admin_config_model;
doors.value = new_doors;
}
async function load_dav_credentials() {

View file

@ -1,5 +1,5 @@
<template>
<BulmaDrawer header="Türchen bearbeiten" @open="on_open">
<BulmaDrawer header="Türchen bearbeiten" :opening="load_doors">
<nav class="level is-mobile mb-0" style="overflow-x: auto">
<BulmaButton
:disabled="current_step === 0"
@ -128,15 +128,6 @@ async function save_doors() {
}
}
async function on_open(ready: () => void, fail: () => void) {
try {
load_doors();
ready();
} catch {
fail();
}
}
async function on_download() {
if (confirm("Aktuelle Änderungen verwerfen und Status vom Server laden?")) {
loading_doors.value = true;

View file

@ -4,11 +4,11 @@
<header class="card-header is-unselectable" style="cursor: pointer">
<p class="card-header-title" @click="toggle">{{ header }}</p>
<p v-if="refreshable" class="card-header-icon px-0">
<BulmaButton class="is-small is-primary" @click="refresh">
<p v-if="refreshable && is_open" class="card-header-icon px-0">
<BulmaButton class="is-small is-primary" @click="load">
<FontAwesomeIcon
:icon="['fas', 'arrows-rotate']"
:spin="is_open && state === 'loading'"
:spin="state === 'loading'"
/>
</BulmaButton>
</p>
@ -27,7 +27,7 @@
<progress class="progress is-primary" />
</div>
<div
v-else-if="state === 'failed'"
v-else-if="state === 'err'"
class="card-content has-text-danger has-text-centered"
>
<span class="icon is-large">
@ -40,42 +40,39 @@
</template>
<script setup lang="ts">
import { ref } from "vue";
import { computed, ref } from "vue";
import BulmaButton from "./Button.vue";
withDefaults(
const props = withDefaults(
defineProps<{
header: string;
opening?: () => Promise<void>;
refreshable?: boolean;
}>(),
{ refreshable: false },
{ opening: async () => {}, refreshable: false },
);
const emit = defineEmits<{
(event: "open", ready: () => void, fail: () => void): void;
}>();
const is_open = ref(false);
const state = ref<"loading" | "ready" | "failed">("loading");
function toggle() {
is_open.value = !is_open.value;
const state = ref<"closed" | "loading" | "ok" | "err">("closed");
const is_open = computed(() => state.value !== "closed");
async function toggle() {
if (is_open.value) {
state.value = "loading";
emit(
"open",
() => (state.value = "ready"),
() => (state.value = "failed"),
);
state.value = "closed";
} else {
await load();
}
}
function refresh() {
is_open.value = false;
toggle();
async function load() {
state.value = "loading";
try {
await props.opening();
state.value = "ok";
} catch {
state.value = "err";
}
}
</script>