Compare commits
No commits in common. "d0d81510cca3466662643ab1273b79603629381f" and "109dec73d2b4afb6de868b6424413b3aa5802093" have entirely different histories.
d0d81510cc
...
109dec73d2
15 changed files with 409 additions and 236 deletions
|
@ -11,6 +11,7 @@
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@fortawesome/fontawesome-svg-core": "^6.6.0",
|
"@fortawesome/fontawesome-svg-core": "^6.6.0",
|
||||||
|
"@fortawesome/free-brands-svg-icons": "^6.6.0",
|
||||||
"@fortawesome/free-solid-svg-icons": "^6.6.0",
|
"@fortawesome/free-solid-svg-icons": "^6.6.0",
|
||||||
"@fortawesome/vue-fontawesome": "^3.0.8",
|
"@fortawesome/vue-fontawesome": "^3.0.8",
|
||||||
"@types/chai": "^4.3.17",
|
"@types/chai": "^4.3.17",
|
||||||
|
@ -25,9 +26,11 @@
|
||||||
"@vue/cli-service": "~5.0.0",
|
"@vue/cli-service": "~5.0.0",
|
||||||
"@vue/eslint-config-typescript": "^13.0.0",
|
"@vue/eslint-config-typescript": "^13.0.0",
|
||||||
"@vue/test-utils": "^2.4.6",
|
"@vue/test-utils": "^2.4.6",
|
||||||
|
"@vueuse/core": "^10.11.1",
|
||||||
"animate.css": "^4.1.1",
|
"animate.css": "^4.1.1",
|
||||||
"axios": "^1.7.3",
|
"axios": "^1.7.3",
|
||||||
"bulma": "^1.0.2",
|
"bulma": "^0.9.4",
|
||||||
|
"bulma-prefers-dark": "^0.1.0-beta.1",
|
||||||
"bulma-toast": "2.4.3",
|
"bulma-toast": "2.4.3",
|
||||||
"chai": "^5.1.1",
|
"chai": "^5.1.1",
|
||||||
"core-js": "^3.38.0",
|
"core-js": "^3.38.0",
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
@charset "utf-8";
|
@charset "utf-8";
|
||||||
|
@use "sass:map";
|
||||||
|
|
||||||
//=====================
|
//=====================
|
||||||
// custom color scheme
|
// custom color scheme
|
||||||
//=====================
|
//=====================
|
||||||
|
|
||||||
$colors: (
|
$advent22-colors: (
|
||||||
"primary": #945DE1,
|
"primary": #945DE1,
|
||||||
"link": #64B4BD,
|
"link": #64B4BD,
|
||||||
"info": #8C4E80,
|
"info": #8C4E80,
|
||||||
|
@ -12,3 +13,10 @@ $colors: (
|
||||||
"warning": #F6CA6B,
|
"warning": #F6CA6B,
|
||||||
"danger": #C5443B,
|
"danger": #C5443B,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
$primary: map.get($advent22-colors, "primary");
|
||||||
|
$link: map.get($advent22-colors, "link");
|
||||||
|
$info: map.get($advent22-colors, "info");
|
||||||
|
$success: map.get($advent22-colors, "success");
|
||||||
|
$warning: map.get($advent22-colors, "warning");
|
||||||
|
$danger: map.get($advent22-colors, "danger");
|
|
@ -78,14 +78,14 @@ export default class extends Vue {
|
||||||
|
|
||||||
private multi_modal?: MultiModal;
|
private multi_modal?: MultiModal;
|
||||||
|
|
||||||
public toast?: typeof BulmaToast;
|
public toast?: BulmaToast;
|
||||||
private toast_timeout?: number;
|
private toast_timeout?: number;
|
||||||
|
|
||||||
public modal_handle(modal: MultiModal) {
|
public modal_handle(modal: MultiModal) {
|
||||||
this.multi_modal = modal;
|
this.multi_modal = modal;
|
||||||
}
|
}
|
||||||
|
|
||||||
public toast_handle(toast: typeof BulmaToast) {
|
public toast_handle(toast: BulmaToast) {
|
||||||
this.toast = toast;
|
this.toast = toast;
|
||||||
|
|
||||||
if (this.store.is_touch_device) return;
|
if (this.store.is_touch_device) return;
|
||||||
|
|
|
@ -69,7 +69,6 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { Step } from "@/lib/helpers";
|
|
||||||
import { DoorSaved } from "@/lib/model";
|
import { DoorSaved } from "@/lib/model";
|
||||||
import { Door } from "@/lib/rects/door";
|
import { Door } from "@/lib/rects/door";
|
||||||
import { advent22Store } from "@/lib/store";
|
import { advent22Store } from "@/lib/store";
|
||||||
|
@ -79,7 +78,7 @@ import { API } from "@/lib/api";
|
||||||
import { APIError } from "@/lib/api_error";
|
import { APIError } from "@/lib/api_error";
|
||||||
import { toast } from "bulma-toast";
|
import { toast } from "bulma-toast";
|
||||||
import Calendar from "../Calendar.vue";
|
import Calendar from "../Calendar.vue";
|
||||||
import BulmaBreadcrumbs from "../bulma/Breadcrumbs.vue";
|
import BulmaBreadcrumbs, { Step } from "../bulma/Breadcrumbs.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";
|
||||||
import DoorChooser from "../editor/DoorChooser.vue";
|
import DoorChooser from "../editor/DoorChooser.vue";
|
||||||
|
|
|
@ -1,16 +1,15 @@
|
||||||
<!-- eslint-disable vue/multi-word-component-names -->
|
|
||||||
<template>
|
<template>
|
||||||
<nav class="breadcrumb has-succeeds-separator">
|
<nav class="breadcrumb has-succeeds-separator">
|
||||||
<ul>
|
<ul>
|
||||||
<li
|
<li
|
||||||
v-for="(step, index) in steps"
|
v-for="(step, index) in steps"
|
||||||
:key="index"
|
:key="`step-${index}`"
|
||||||
:class="modelValue === index ? 'is-active' : ''"
|
:class="modelValue === index ? 'is-active' : ''"
|
||||||
@click.left="change_step(index)"
|
@click.left="change_step(index)"
|
||||||
>
|
>
|
||||||
<a>
|
<a>
|
||||||
<span class="icon is-small">
|
<span class="icon is-small">
|
||||||
<FontAwesomeIcon :icon="step.icon" />
|
<font-awesome-icon :icon="step.icon" />
|
||||||
</span>
|
</span>
|
||||||
<span>{{ step.label }}</span>
|
<span>{{ step.label }}</span>
|
||||||
</a>
|
</a>
|
||||||
|
@ -19,21 +18,31 @@
|
||||||
</nav>
|
</nav>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script lang="ts">
|
||||||
import { Step } from "@/lib/helpers";
|
import { Options, Vue } from "vue-class-component";
|
||||||
|
|
||||||
const props = defineProps<{
|
export interface Step {
|
||||||
steps: Step[];
|
label: string;
|
||||||
modelValue: number;
|
icon: string;
|
||||||
}>();
|
}
|
||||||
|
|
||||||
const emit = defineEmits<{
|
@Options({
|
||||||
"update:modelValue": [number];
|
props: {
|
||||||
}>();
|
steps: Array,
|
||||||
|
modelValue: Number,
|
||||||
|
},
|
||||||
|
emits: ["update:modelValue"],
|
||||||
|
})
|
||||||
|
export default class extends Vue {
|
||||||
|
public steps!: Step[];
|
||||||
|
public modelValue!: number;
|
||||||
|
|
||||||
function change_step(next_step: number) {
|
public change_step(next_step: number) {
|
||||||
if (next_step === props.modelValue) return;
|
if (next_step === this.modelValue) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
emit("update:modelValue", next_step);
|
this.$emit("update:modelValue", next_step);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -1,28 +1,45 @@
|
||||||
<!-- eslint-disable vue/multi-word-component-names -->
|
|
||||||
<template>
|
<template>
|
||||||
<button class="button">
|
<button class="button">
|
||||||
<slot name="default">
|
<slot v-if="text === undefined" name="default">
|
||||||
<span v-if="icon !== undefined" class="icon">
|
<font-awesome-icon
|
||||||
<FontAwesomeIcon
|
|
||||||
v-if="icon !== undefined"
|
v-if="icon !== undefined"
|
||||||
:icon="icon"
|
:icon="icon"
|
||||||
:beat-fade="busy"
|
:beat-fade="busy"
|
||||||
/>
|
/>
|
||||||
</span>
|
|
||||||
</slot>
|
</slot>
|
||||||
<span v-if="text !== undefined">{{ text }}</span>
|
<template v-else>
|
||||||
|
<span v-if="icon !== undefined" class="icon">
|
||||||
|
<slot name="default">
|
||||||
|
<font-awesome-icon :icon="icon" :beat-fade="busy" />
|
||||||
|
</slot>
|
||||||
|
</span>
|
||||||
|
<span>{{ text }}</span>
|
||||||
|
</template>
|
||||||
</button>
|
</button>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script lang="ts">
|
||||||
withDefaults(
|
import { Options, Vue } from "vue-class-component";
|
||||||
defineProps<{
|
|
||||||
icon?: string | string[];
|
@Options({
|
||||||
text?: string;
|
props: {
|
||||||
busy?: boolean;
|
icon: {
|
||||||
}>(),
|
type: String,
|
||||||
{
|
required: false,
|
||||||
busy: false,
|
|
||||||
},
|
},
|
||||||
);
|
text: {
|
||||||
|
type: String,
|
||||||
|
required: false,
|
||||||
|
},
|
||||||
|
busy: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
export default class extends Vue {
|
||||||
|
public icon?: string;
|
||||||
|
public text?: string;
|
||||||
|
public busy!: boolean;
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -1,37 +1,36 @@
|
||||||
<!-- eslint-disable vue/multi-word-component-names -->
|
|
||||||
<template>
|
<template>
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<header class="card-header is-unselectable" style="cursor: pointer">
|
<header class="card-header is-unselectable" style="cursor: pointer">
|
||||||
<p class="card-header-title" @click="toggle">{{ header }}</p>
|
<p class="card-header-title" @click="toggle">{{ header }}</p>
|
||||||
|
|
||||||
<p v-if="refreshable" class="card-header-icon px-0">
|
<p v-if="refreshable" class="card-header-icon px-0">
|
||||||
<BulmaButton class="is-small is-primary" @click="refresh">
|
<BulmaButton class="tag icon is-primary" @click="refresh">
|
||||||
<FontAwesomeIcon
|
<font-awesome-icon
|
||||||
:icon="['fas', 'arrows-rotate']"
|
icon="fa-solid fa-arrows-rotate"
|
||||||
:spin="is_open && state === 'loading'"
|
:spin="is_open && loading"
|
||||||
/>
|
/>
|
||||||
</BulmaButton>
|
</BulmaButton>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<button class="card-header-icon" @click="toggle">
|
<button class="card-header-icon" @click="toggle">
|
||||||
<span class="icon">
|
<span class="icon">
|
||||||
<FontAwesomeIcon
|
<font-awesome-icon
|
||||||
:icon="['fas', is_open ? 'angle-down' : 'angle-right']"
|
:icon="'fa-solid fa-angle-' + (is_open ? 'down' : 'right')"
|
||||||
/>
|
/>
|
||||||
</span>
|
</span>
|
||||||
</button>
|
</button>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
<template v-if="is_open">
|
<template v-if="is_open">
|
||||||
<div v-if="state === 'loading'" class="card-content">
|
<div v-if="loading" class="card-content">
|
||||||
<progress class="progress is-primary" />
|
<progress class="progress is-primary" max="100" />
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
v-else-if="state === 'failed'"
|
v-else-if="failed"
|
||||||
class="card-content has-text-danger has-text-centered"
|
class="card-content has-text-danger has-text-centered"
|
||||||
>
|
>
|
||||||
<span class="icon is-large">
|
<span class="icon is-large">
|
||||||
<FontAwesomeIcon :icon="['fas', 'ban']" size="3x" />
|
<font-awesome-icon icon="fa-solid fa-ban" size="3x" />
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<slot v-else name="default" />
|
<slot v-else name="default" />
|
||||||
|
@ -39,46 +38,63 @@
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script lang="ts">
|
||||||
import { ref } from "vue";
|
import { Options, Vue } from "vue-class-component";
|
||||||
|
|
||||||
import BulmaButton from "./Button.vue";
|
import BulmaButton from "./Button.vue";
|
||||||
|
|
||||||
withDefaults(
|
enum DrawerState {
|
||||||
defineProps<{
|
Loading,
|
||||||
header: string;
|
Ready,
|
||||||
refreshable?: boolean;
|
Failed,
|
||||||
}>(),
|
}
|
||||||
{ refreshable: false },
|
|
||||||
);
|
|
||||||
|
|
||||||
const emit = defineEmits<{
|
@Options({
|
||||||
open: [
|
components: {
|
||||||
{
|
BulmaButton,
|
||||||
ready(): void;
|
|
||||||
fail(): void;
|
|
||||||
},
|
},
|
||||||
];
|
props: {
|
||||||
}>();
|
header: String,
|
||||||
|
refreshable: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
emits: ["open"],
|
||||||
|
})
|
||||||
|
export default class extends Vue {
|
||||||
|
public header!: string;
|
||||||
|
public refreshable!: boolean;
|
||||||
|
|
||||||
const is_open = ref(false);
|
public is_open = false;
|
||||||
const state = ref<"loading" | "ready" | "failed">("loading");
|
public state = DrawerState.Loading;
|
||||||
|
|
||||||
function toggle() {
|
public toggle() {
|
||||||
is_open.value = !is_open.value;
|
this.is_open = !this.is_open;
|
||||||
|
|
||||||
if (is_open.value) {
|
if (this.is_open) {
|
||||||
state.value = "loading";
|
this.state = DrawerState.Loading;
|
||||||
|
|
||||||
emit("open", {
|
this.$emit(
|
||||||
ready: () => (state.value = "ready"),
|
"open",
|
||||||
fail: () => (state.value = "failed"),
|
() => (this.state = DrawerState.Ready),
|
||||||
});
|
() => (this.state = DrawerState.Failed),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function refresh() {
|
public refresh() {
|
||||||
is_open.value = false;
|
this.is_open = false;
|
||||||
toggle();
|
this.toggle();
|
||||||
|
}
|
||||||
|
|
||||||
|
public get loading(): boolean {
|
||||||
|
return this.state === DrawerState.Loading;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get failed(): boolean {
|
||||||
|
return this.state === DrawerState.Failed;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
@ -1,47 +1,68 @@
|
||||||
<!-- eslint-disable vue/multi-word-component-names -->
|
|
||||||
<template>
|
<template>
|
||||||
<slot v-if="state === 'show'" name="default" />
|
<slot v-if="show" name="default" />
|
||||||
<span v-else>***</span>
|
<span v-else>***</span>
|
||||||
<BulmaButton
|
<BulmaButton
|
||||||
:class="`is-small is-${button_class} ml-2`"
|
:class="`tag icon is-${button_class} ml-2`"
|
||||||
:icon="['fas', `${button_icon}`]"
|
:icon="`fa-solid fa-${button_icon}`"
|
||||||
:busy="state === 'click'"
|
:busy="busy"
|
||||||
@click="on_click"
|
@click="on_click"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script lang="ts">
|
||||||
import { ref } from "vue";
|
import { Options, Vue } from "vue-class-component";
|
||||||
|
|
||||||
import BulmaButton from "./Button.vue";
|
import BulmaButton from "./Button.vue";
|
||||||
|
|
||||||
const emit = defineEmits<{
|
enum ClickState {
|
||||||
load: [];
|
Green = 0,
|
||||||
}>();
|
Yellow = 1,
|
||||||
|
Red = 2,
|
||||||
|
}
|
||||||
|
|
||||||
const state = ref<"start" | "click" | "show">("start");
|
@Options({
|
||||||
const button_class = ref<"primary" | "warning" | "danger">("primary");
|
components: {
|
||||||
const button_icon = ref<"eye-slash" | "eye">("eye-slash");
|
BulmaButton,
|
||||||
|
},
|
||||||
|
emits: ["load"],
|
||||||
|
})
|
||||||
|
export default class extends Vue {
|
||||||
|
public state = ClickState.Green;
|
||||||
|
|
||||||
function on_click(): void {
|
public on_click(): void {
|
||||||
switch (state.value) {
|
this.state++;
|
||||||
case "show":
|
this.state %= 3;
|
||||||
state.value = "start";
|
|
||||||
button_class.value = "primary";
|
|
||||||
button_icon.value = "eye-slash";
|
|
||||||
break;
|
|
||||||
|
|
||||||
case "start":
|
if (this.state === ClickState.Red) {
|
||||||
state.value = "click";
|
this.$emit("load");
|
||||||
button_class.value = "warning";
|
}
|
||||||
button_icon.value = "eye-slash";
|
}
|
||||||
break;
|
|
||||||
|
|
||||||
case "click":
|
public get show(): boolean {
|
||||||
state.value = "show";
|
return this.state === ClickState.Red;
|
||||||
button_class.value = "danger";
|
}
|
||||||
button_icon.value = "eye";
|
|
||||||
emit("load");
|
public get busy(): boolean {
|
||||||
break;
|
return this.state === ClickState.Yellow;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get button_class(): string {
|
||||||
|
switch (this.state) {
|
||||||
|
case ClickState.Red:
|
||||||
|
return "danger";
|
||||||
|
case ClickState.Yellow:
|
||||||
|
return "warning";
|
||||||
|
default:
|
||||||
|
return "primary";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public get button_icon(): string {
|
||||||
|
if (this.state === ClickState.Red) {
|
||||||
|
return "eye-slash";
|
||||||
|
} else {
|
||||||
|
return "eye";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
<!-- eslint-disable vue/multi-word-component-names -->
|
|
||||||
<template>
|
<template>
|
||||||
<div style="display: none">
|
<div style="display: none">
|
||||||
<div v-bind="$attrs" ref="message">
|
<div v-bind="$attrs" ref="message">
|
||||||
|
@ -7,43 +6,38 @@
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script lang="ts">
|
||||||
import * as bulmaToast from "bulma-toast";
|
import * as bulmaToast from "bulma-toast";
|
||||||
import { onMounted, ref } from "vue";
|
import { Options, Vue } from "vue-class-component";
|
||||||
|
|
||||||
const emit = defineEmits<{
|
@Options({
|
||||||
handle: [
|
emits: ["handle"],
|
||||||
{
|
})
|
||||||
show(options: bulmaToast.Options): void;
|
export default class extends Vue {
|
||||||
hide(): void;
|
public created(): void {
|
||||||
},
|
this.$emit("handle", this);
|
||||||
];
|
}
|
||||||
}>();
|
|
||||||
|
|
||||||
const message = ref<HTMLDivElement | null>(null);
|
public show(options: bulmaToast.Options = {}) {
|
||||||
|
if (!(this.$refs.message instanceof HTMLElement)) return;
|
||||||
onMounted(() =>
|
|
||||||
emit("handle", {
|
|
||||||
show(options: bulmaToast.Options = {}) {
|
|
||||||
if (!(message.value instanceof HTMLElement)) return;
|
|
||||||
|
|
||||||
bulmaToast.toast({
|
bulmaToast.toast({
|
||||||
...options,
|
...options,
|
||||||
single: true,
|
single: true,
|
||||||
message: message.value,
|
message: this.$refs.message,
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
hide() {
|
|
||||||
if (!(message.value instanceof HTMLElement)) return;
|
|
||||||
|
|
||||||
const toast_div = message.value.parentElement;
|
public hide() {
|
||||||
|
if (!(this.$refs.message instanceof HTMLElement)) return;
|
||||||
|
|
||||||
|
const toast_div = this.$refs.message.parentElement;
|
||||||
if (!(toast_div instanceof HTMLDivElement)) return;
|
if (!(toast_div instanceof HTMLDivElement)) return;
|
||||||
|
|
||||||
const dbutton = toast_div.querySelector("button.delete");
|
const dbutton = toast_div.querySelector("button.delete");
|
||||||
if (!(dbutton instanceof HTMLButtonElement)) return;
|
if (!(dbutton instanceof HTMLButtonElement)) return;
|
||||||
|
|
||||||
dbutton.click();
|
dbutton.click();
|
||||||
},
|
}
|
||||||
}),
|
}
|
||||||
);
|
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -1,30 +1,27 @@
|
||||||
<template>
|
<template>
|
||||||
<foreignObject
|
<foreignObject
|
||||||
:x="Math.round(get_bg_aspect_ratio() * rectangle.left)"
|
:x="Math.round(aspect_ratio * rectangle.left)"
|
||||||
:y="rectangle.top"
|
:y="rectangle.top"
|
||||||
:width="Math.round(get_bg_aspect_ratio() * rectangle.width)"
|
:width="Math.round(aspect_ratio * rectangle.width)"
|
||||||
:height="rectangle.height"
|
:height="rectangle.height"
|
||||||
:style="`transform: scaleX(${1 / get_bg_aspect_ratio()})`"
|
:style="`transform: scaleX(${1 / aspect_ratio})`"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
xmlns="http://www.w3.org/1999/xhtml"
|
xmlns="http://www.w3.org/1999/xhtml"
|
||||||
:class="`px-2 is-flex is-align-items-center is-justify-content-center is-size-2 has-text-weight-bold ${variant} ${
|
:class="`px-2 is-flex is-align-items-center is-justify-content-center is-size-2 has-text-weight-bold ${extra_classes}`"
|
||||||
visible ? 'visible' : ''
|
|
||||||
}`"
|
|
||||||
style="height: inherit"
|
style="height: inherit"
|
||||||
v-bind="$attrs"
|
:title="title"
|
||||||
>
|
>
|
||||||
<slot name="default" />
|
<slot name="default" />
|
||||||
</div>
|
</div>
|
||||||
</foreignObject>
|
</foreignObject>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script lang="ts">
|
||||||
import { loading_success } from "@/lib/helpers";
|
import { loading_success } from "@/lib/helpers";
|
||||||
import { Rectangle } from "@/lib/rects/rectangle";
|
import { Rectangle } from "@/lib/rects/rectangle";
|
||||||
import { advent22Store } from "@/lib/store";
|
import { advent22Store } from "@/lib/store";
|
||||||
|
import { Options, Vue } from "vue-class-component";
|
||||||
const store = advent22Store();
|
|
||||||
|
|
||||||
type BulmaVariant =
|
type BulmaVariant =
|
||||||
| "primary"
|
| "primary"
|
||||||
|
@ -34,26 +31,48 @@ type BulmaVariant =
|
||||||
| "warning"
|
| "warning"
|
||||||
| "danger";
|
| "danger";
|
||||||
|
|
||||||
withDefaults(
|
@Options({
|
||||||
defineProps<{
|
props: {
|
||||||
variant: BulmaVariant;
|
variant: String,
|
||||||
visible?: boolean;
|
visible: {
|
||||||
rectangle: Rectangle;
|
type: Boolean,
|
||||||
}>(),
|
default: false,
|
||||||
{
|
|
||||||
visible: true,
|
|
||||||
},
|
},
|
||||||
|
rectangle: Rectangle,
|
||||||
|
title: {
|
||||||
|
type: String,
|
||||||
|
required: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
export default class extends Vue {
|
||||||
|
public readonly store = advent22Store();
|
||||||
|
|
||||||
|
private variant!: BulmaVariant;
|
||||||
|
private visible!: boolean;
|
||||||
|
public rectangle!: Rectangle;
|
||||||
|
public title?: string;
|
||||||
|
|
||||||
|
public get extra_classes(): string {
|
||||||
|
let result = this.variant;
|
||||||
|
|
||||||
|
if (this.visible) result += " visible";
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get aspect_ratio(): number {
|
||||||
|
if (!loading_success(this.store.background_image)) return 1;
|
||||||
|
|
||||||
|
return (
|
||||||
|
this.store.background_image.height / this.store.background_image.width
|
||||||
);
|
);
|
||||||
|
}
|
||||||
function get_bg_aspect_ratio(): number {
|
|
||||||
if (!loading_success(store.background_image)) return 1;
|
|
||||||
|
|
||||||
return store.background_image.height / store.background_image.width;
|
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
@use "@/bulma-scheme" as scheme;
|
@import "@/bulma-scheme";
|
||||||
|
|
||||||
foreignObject > div {
|
foreignObject > div {
|
||||||
&:not(.visible, :hover):deep() > * {
|
&:not(.visible, :hover):deep() > * {
|
||||||
|
@ -65,7 +84,7 @@ foreignObject > div {
|
||||||
border-width: 2px;
|
border-width: 2px;
|
||||||
border-style: solid;
|
border-style: solid;
|
||||||
|
|
||||||
@each $name, $color in scheme.$colors {
|
@each $name, $color in $advent22-colors {
|
||||||
&.#{$name} {
|
&.#{$name} {
|
||||||
background-color: rgba($color, 0.3);
|
background-color: rgba($color, 0.3);
|
||||||
border-color: rgba($color, 0.9);
|
border-color: rgba($color, 0.9);
|
||||||
|
|
|
@ -15,8 +15,10 @@
|
||||||
</svg>
|
</svg>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script lang="ts">
|
||||||
import { Vector2D } from "@/lib/rects/vector2d";
|
import { Vector2D } from "@/lib/rects/vector2d";
|
||||||
|
import { advent22Store } from "@/lib/store";
|
||||||
|
import { Options, Vue } from "vue-class-component";
|
||||||
|
|
||||||
function get_event_thous(event: MouseEvent): Vector2D {
|
function get_event_thous(event: MouseEvent): Vector2D {
|
||||||
if (!(event.currentTarget instanceof SVGSVGElement)) {
|
if (!(event.currentTarget instanceof SVGSVGElement)) {
|
||||||
|
@ -29,22 +31,36 @@ function get_event_thous(event: MouseEvent): Vector2D {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
type TCMouseEvent = [MouseEvent, Vector2D];
|
function mouse_event_validator(event: object, point: object): boolean {
|
||||||
|
if (!(event instanceof MouseEvent)) {
|
||||||
|
console.warn(event, "is not a MouseEvent!");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
const emit = defineEmits<{
|
if (!(point instanceof Vector2D)) {
|
||||||
mousedown: TCMouseEvent;
|
console.warn(point, "is not a Vector2D!");
|
||||||
mouseup: TCMouseEvent;
|
return false;
|
||||||
mousemove: TCMouseEvent;
|
}
|
||||||
click: TCMouseEvent;
|
|
||||||
dblclick: TCMouseEvent;
|
|
||||||
}>();
|
|
||||||
|
|
||||||
function transform_mouse_event(event: MouseEvent) {
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Options({
|
||||||
|
emits: {
|
||||||
|
mousedown: mouse_event_validator,
|
||||||
|
mouseup: mouse_event_validator,
|
||||||
|
mousemove: mouse_event_validator,
|
||||||
|
click: mouse_event_validator,
|
||||||
|
dblclick: mouse_event_validator,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
export default class extends Vue {
|
||||||
|
public readonly store = advent22Store();
|
||||||
|
|
||||||
|
public transform_mouse_event(event: MouseEvent) {
|
||||||
const point = get_event_thous(event);
|
const point = get_event_thous(event);
|
||||||
|
this.$emit(event.type, event, point);
|
||||||
// mute a useless typescript error
|
}
|
||||||
const event_type = event.type as "mousedown";
|
|
||||||
emit(event_type, event, point);
|
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
@ -37,8 +37,3 @@ export function handle_error(error: unknown) {
|
||||||
export function name_door(day: number): string {
|
export function name_door(day: number): string {
|
||||||
return `Türchen ${day}`;
|
return `Türchen ${day}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Step {
|
|
||||||
label: string;
|
|
||||||
icon: string | string[];
|
|
||||||
}
|
|
||||||
|
|
|
@ -67,7 +67,6 @@ export const advent22Store = defineStore({
|
||||||
document.getElementsByTagName("head")[0].appendChild(link);
|
document.getElementsByTagName("head")[0].appendChild(link);
|
||||||
} catch {}
|
} catch {}
|
||||||
|
|
||||||
try {
|
|
||||||
const [is_admin, site_config, background_image, user_doors, next_door] =
|
const [is_admin, site_config, background_image, user_doors, next_door] =
|
||||||
await Promise.all([
|
await Promise.all([
|
||||||
this.update_is_admin(),
|
this.update_is_admin(),
|
||||||
|
@ -92,9 +91,6 @@ export const advent22Store = defineStore({
|
||||||
}
|
}
|
||||||
|
|
||||||
if (next_door !== null) this.next_door_target = Date.now() + next_door;
|
if (next_door !== null) this.next_door_target = Date.now() + next_door;
|
||||||
} catch {
|
|
||||||
this.background_image = "error";
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
when_initialized(callback: () => void): void {
|
when_initialized(callback: () => void): void {
|
||||||
|
|
|
@ -1,23 +1,64 @@
|
||||||
@charset "utf-8";
|
@charset "utf-8";
|
||||||
@use "sass:map";
|
|
||||||
|
|
||||||
//==============
|
//===========
|
||||||
// bulma
|
// variables
|
||||||
//==============
|
//===========
|
||||||
|
|
||||||
// custom color scheme
|
// custom color scheme
|
||||||
@use "bulma-scheme" as scheme;
|
@import "@/bulma-scheme";
|
||||||
@use "bulma/sass" with (
|
|
||||||
$primary: map.get(scheme.$colors, "primary"),
|
// Sass variables (bulma)
|
||||||
$link: map.get(scheme.$colors, "link"),
|
@import "~bulma/sass/utilities/initial-variables.sass";
|
||||||
$info: map.get(scheme.$colors, "info"),
|
@import "~bulma/sass/utilities/derived-variables.sass";
|
||||||
$success: map.get(scheme.$colors, "success"),
|
|
||||||
$warning: map.get(scheme.$colors, "warning"),
|
// Sass variables (bulma-prefers-dark)
|
||||||
$danger: map.get(scheme.$colors, "danger")
|
@import "~bulma-prefers-dark/sass/utilities/initial-variables.sass";
|
||||||
);
|
@import "~bulma-prefers-dark/sass/utilities/derived-variables.sass";
|
||||||
|
|
||||||
|
//=================
|
||||||
|
// variable tweaks
|
||||||
|
//=================
|
||||||
|
|
||||||
|
$modal-card-body-background-color-dark: $body-background-dark;
|
||||||
|
$card-background-color-dark: $background-dark;
|
||||||
|
|
||||||
//==============
|
//==============
|
||||||
// main imports
|
// main imports
|
||||||
//==============
|
//==============
|
||||||
|
|
||||||
@import "animate.css/animate";
|
@import "~animate.css/animate";
|
||||||
|
@import "~bulma/bulma";
|
||||||
|
@import "~bulma-prefers-dark/bulma-prefers-dark";
|
||||||
|
|
||||||
|
//==============
|
||||||
|
// style tweaks
|
||||||
|
//==============
|
||||||
|
|
||||||
|
.card-header {
|
||||||
|
background-color: $background;
|
||||||
|
|
||||||
|
@include prefers-scheme(dark) {
|
||||||
|
background-color: $card-header-background-color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-content {
|
||||||
|
@include prefers-scheme(dark) {
|
||||||
|
background-color: $body-background-dark;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.progress {
|
||||||
|
// &::-webkit-progress-bar {
|
||||||
|
// background-color: transparent !important;
|
||||||
|
// }
|
||||||
|
// &::-webkit-progress-value {
|
||||||
|
// background-color: transparent !important;
|
||||||
|
// }
|
||||||
|
&::-moz-progress-bar {
|
||||||
|
background-color: transparent !important;
|
||||||
|
}
|
||||||
|
// &::-ms-fill {
|
||||||
|
// background-color: transparent !important;
|
||||||
|
// }
|
||||||
|
}
|
49
ui/yarn.lock
49
ui/yarn.lock
|
@ -1084,6 +1084,13 @@
|
||||||
dependencies:
|
dependencies:
|
||||||
"@fortawesome/fontawesome-common-types" "6.6.0"
|
"@fortawesome/fontawesome-common-types" "6.6.0"
|
||||||
|
|
||||||
|
"@fortawesome/free-brands-svg-icons@^6.6.0":
|
||||||
|
version "6.6.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/@fortawesome/free-brands-svg-icons/-/free-brands-svg-icons-6.6.0.tgz#2797f2cc66d21e7e47fa64e680b8835e8d30e825"
|
||||||
|
integrity sha512-1MPD8lMNW/earme4OQi1IFHtmHUwAKgghXlNwWi9GO7QkTfD+IIaYpIai4m2YJEzqfEji3jFHX1DZI5pbY/biQ==
|
||||||
|
dependencies:
|
||||||
|
"@fortawesome/fontawesome-common-types" "6.6.0"
|
||||||
|
|
||||||
"@fortawesome/free-solid-svg-icons@^6.6.0":
|
"@fortawesome/free-solid-svg-icons@^6.6.0":
|
||||||
version "6.6.0"
|
version "6.6.0"
|
||||||
resolved "https://registry.yarnpkg.com/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-6.6.0.tgz#061751ca43be4c4d814f0adbda8f006164ec9f3b"
|
resolved "https://registry.yarnpkg.com/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-6.6.0.tgz#061751ca43be4c4d814f0adbda8f006164ec9f3b"
|
||||||
|
@ -1485,6 +1492,11 @@
|
||||||
dependencies:
|
dependencies:
|
||||||
"@types/node" "*"
|
"@types/node" "*"
|
||||||
|
|
||||||
|
"@types/web-bluetooth@^0.0.20":
|
||||||
|
version "0.0.20"
|
||||||
|
resolved "https://registry.yarnpkg.com/@types/web-bluetooth/-/web-bluetooth-0.0.20.tgz#f066abfcd1cbe66267cdbbf0de010d8a41b41597"
|
||||||
|
integrity sha512-g9gZnnXVq7gM7v3tJCWV/qw7w+KeOlSHAhgF9RytFyifW6AF61hdT2ucrYhPq9hLs5JIryeupHV3qGk95dH9ow==
|
||||||
|
|
||||||
"@types/webpack-env@^1.15.2":
|
"@types/webpack-env@^1.15.2":
|
||||||
version "1.18.4"
|
version "1.18.4"
|
||||||
resolved "https://registry.yarnpkg.com/@types/webpack-env/-/webpack-env-1.18.4.tgz#62879b0a9c653f9b1172d403b882f2045ecce032"
|
resolved "https://registry.yarnpkg.com/@types/webpack-env/-/webpack-env-1.18.4.tgz#62879b0a9c653f9b1172d403b882f2045ecce032"
|
||||||
|
@ -1994,6 +2006,28 @@
|
||||||
resolved "https://registry.yarnpkg.com/@vue/web-component-wrapper/-/web-component-wrapper-1.3.0.tgz#b6b40a7625429d2bd7c2281ddba601ed05dc7f1a"
|
resolved "https://registry.yarnpkg.com/@vue/web-component-wrapper/-/web-component-wrapper-1.3.0.tgz#b6b40a7625429d2bd7c2281ddba601ed05dc7f1a"
|
||||||
integrity sha512-Iu8Tbg3f+emIIMmI2ycSI8QcEuAUgPTgHwesDU1eKMLE4YC/c/sFbGc70QgMq31ijRftV0R7vCm9co6rldCeOA==
|
integrity sha512-Iu8Tbg3f+emIIMmI2ycSI8QcEuAUgPTgHwesDU1eKMLE4YC/c/sFbGc70QgMq31ijRftV0R7vCm9co6rldCeOA==
|
||||||
|
|
||||||
|
"@vueuse/core@^10.11.1":
|
||||||
|
version "10.11.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/@vueuse/core/-/core-10.11.1.tgz#15d2c0b6448d2212235b23a7ba29c27173e0c2c6"
|
||||||
|
integrity sha512-guoy26JQktXPcz+0n3GukWIy/JDNKti9v6VEMu6kV2sYBsWuGiTU8OWdg+ADfUbHg3/3DlqySDe7JmdHrktiww==
|
||||||
|
dependencies:
|
||||||
|
"@types/web-bluetooth" "^0.0.20"
|
||||||
|
"@vueuse/metadata" "10.11.1"
|
||||||
|
"@vueuse/shared" "10.11.1"
|
||||||
|
vue-demi ">=0.14.8"
|
||||||
|
|
||||||
|
"@vueuse/metadata@10.11.1":
|
||||||
|
version "10.11.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/@vueuse/metadata/-/metadata-10.11.1.tgz#209db7bb5915aa172a87510b6de2ca01cadbd2a7"
|
||||||
|
integrity sha512-IGa5FXd003Ug1qAZmyE8wF3sJ81xGLSqTqtQ6jaVfkeZ4i5kS2mwQF61yhVqojRnenVew5PldLyRgvdl4YYuSw==
|
||||||
|
|
||||||
|
"@vueuse/shared@10.11.1":
|
||||||
|
version "10.11.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/@vueuse/shared/-/shared-10.11.1.tgz#62b84e3118ae6e1f3ff38f4fbe71b0c5d0f10938"
|
||||||
|
integrity sha512-LHpC8711VFZlDaYUXEBbFBCQ7GS3dVU9mjOhhMhXP6txTV4EhYQg/KGnQuvt/sPAtoUKq7VVUnL6mVtFoL42sA==
|
||||||
|
dependencies:
|
||||||
|
vue-demi ">=0.14.8"
|
||||||
|
|
||||||
"@webassemblyjs/ast@1.11.6", "@webassemblyjs/ast@^1.11.5":
|
"@webassemblyjs/ast@1.11.6", "@webassemblyjs/ast@^1.11.5":
|
||||||
version "1.11.6"
|
version "1.11.6"
|
||||||
resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.11.6.tgz#db046555d3c413f8966ca50a95176a0e2c642e24"
|
resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.11.6.tgz#db046555d3c413f8966ca50a95176a0e2c642e24"
|
||||||
|
@ -2540,15 +2574,20 @@ buffer@^5.5.0:
|
||||||
base64-js "^1.3.1"
|
base64-js "^1.3.1"
|
||||||
ieee754 "^1.1.13"
|
ieee754 "^1.1.13"
|
||||||
|
|
||||||
|
bulma-prefers-dark@^0.1.0-beta.1:
|
||||||
|
version "0.1.0-beta.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/bulma-prefers-dark/-/bulma-prefers-dark-0.1.0-beta.1.tgz#074aa71899f389a0137dd3753f0d89e96ab1e59b"
|
||||||
|
integrity sha512-ti4sKxIIrTAvGtsYc9Rk66SUZSH/j63EU1hApQijQVlKFF0qBLGSb8E16HhI83KJaIeYP4aAHQv2tj0ara831A==
|
||||||
|
|
||||||
bulma-toast@2.4.3:
|
bulma-toast@2.4.3:
|
||||||
version "2.4.3"
|
version "2.4.3"
|
||||||
resolved "https://registry.yarnpkg.com/bulma-toast/-/bulma-toast-2.4.3.tgz#cd302ad5ed625f47d7426b48b741250950e1cbf9"
|
resolved "https://registry.yarnpkg.com/bulma-toast/-/bulma-toast-2.4.3.tgz#cd302ad5ed625f47d7426b48b741250950e1cbf9"
|
||||||
integrity sha512-OpNn3MUD27ne8RkQns3yS7HaltU5/s67ivbdxAb/gXjxmfZhIdoeUFPYkopEXwCpzc+VasYy1OAglGIFvjEvUQ==
|
integrity sha512-OpNn3MUD27ne8RkQns3yS7HaltU5/s67ivbdxAb/gXjxmfZhIdoeUFPYkopEXwCpzc+VasYy1OAglGIFvjEvUQ==
|
||||||
|
|
||||||
bulma@^1.0.2:
|
bulma@^0.9.4:
|
||||||
version "1.0.2"
|
version "0.9.4"
|
||||||
resolved "https://registry.yarnpkg.com/bulma/-/bulma-1.0.2.tgz#47395a660755c9566db3cf981fd4e3a2b637af19"
|
resolved "https://registry.yarnpkg.com/bulma/-/bulma-0.9.4.tgz#0ca8aeb1847a34264768dba26a064c8be72674a1"
|
||||||
integrity sha512-D7GnDuF6seb6HkcnRMM9E739QpEY9chDzzeFrHMyEns/EXyDJuQ0XA0KxbBl/B2NTsKSoDomW61jFGFaAxhK5A==
|
integrity sha512-86FlT5+1GrsgKbPLRRY7cGDg8fsJiP/jzTqXXVqiUZZ2aZT8uemEOHlU1CDU+TxklPEZ11HZNNWclRBBecP4CQ==
|
||||||
|
|
||||||
bytes@3.0.0:
|
bytes@3.0.0:
|
||||||
version "3.0.0"
|
version "3.0.0"
|
||||||
|
@ -7040,7 +7079,7 @@ vue-component-type-helpers@^2.0.0:
|
||||||
resolved "https://registry.yarnpkg.com/vue-component-type-helpers/-/vue-component-type-helpers-2.0.7.tgz#f142e82440da61fa81671ac2f35fd87146248897"
|
resolved "https://registry.yarnpkg.com/vue-component-type-helpers/-/vue-component-type-helpers-2.0.7.tgz#f142e82440da61fa81671ac2f35fd87146248897"
|
||||||
integrity sha512-7e12Evdll7JcTIocojgnCgwocX4WzIYStGClBQ+QuWPinZo/vQolv2EMq4a3lg16TKfwWafLimG77bxb56UauA==
|
integrity sha512-7e12Evdll7JcTIocojgnCgwocX4WzIYStGClBQ+QuWPinZo/vQolv2EMq4a3lg16TKfwWafLimG77bxb56UauA==
|
||||||
|
|
||||||
vue-demi@^0.14.10:
|
vue-demi@>=0.14.8, vue-demi@^0.14.10:
|
||||||
version "0.14.10"
|
version "0.14.10"
|
||||||
resolved "https://registry.yarnpkg.com/vue-demi/-/vue-demi-0.14.10.tgz#afc78de3d6f9e11bf78c55e8510ee12814522f04"
|
resolved "https://registry.yarnpkg.com/vue-demi/-/vue-demi-0.14.10.tgz#afc78de3d6f9e11bf78c55e8510ee12814522f04"
|
||||||
integrity sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==
|
integrity sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==
|
||||||
|
|
Loading…
Reference in a new issue