frontend/app.vue
Temmie 37ebcb74aa
All checks were successful
ci/woodpecker/push/build-and-publish Pipeline was successful
feat: implement layout switching and saving
2025-08-05 02:22:57 +02:00

112 lines
2.8 KiB
Vue

<template>
<div>
<Banner v-if="banner" />
<ContextMenu v-if="contextMenu && contextMenu.show" :pointer-x="contextMenu.pointerX" :pointer-y="contextMenu.pointerY" :menu-items="contextMenu.items" />
<NuxtPage :keepalive="true" />
</div>
</template>
<script lang="ts" setup>
import ContextMenu from '~/components/UserInterface/ContextMenu.vue';
import type { ContextMenuInterface } from './types/interfaces';
const banner = useState("banner", () => false);
const contextMenu = useState<ContextMenuInterface>("contextMenu");
onMounted(() => {
loadPreferredThemes()
document.removeEventListener("contextmenu", contextMenuHandler);
document.addEventListener("contextmenu", (e) => {
if (e.target instanceof Element && e.target.classList.contains("default-contextmenu")) return;
contextMenuHandler(e);
});
document.addEventListener("mousedown", (e) => {
if (e.target instanceof HTMLElement && e.target.closest("#context-menu")) return;
console.log("click");
console.log("target:", e.target);
console.log(e.target instanceof HTMLDivElement);
removeContextMenu(contextMenu);
if (e.target instanceof HTMLElement && e.target.classList.contains("message-text") && e.target.contentEditable) {
e.target.contentEditable = "false";
}
const destroyOnClick = document.getElementsByClassName("destroy-on-click");
for (const element of destroyOnClick) {
const closest = (e.target as HTMLElement).closest(".destroy-on-click");
if (element != closest) {
unrender(element);
}
}
});
document.addEventListener("keyup", (e) => {
const messageReply = document.getElementById("message-reply") as HTMLDivElement;
if (e.key == "Escape" && messageReply) {
e.preventDefault();
messageReply.remove();
const replyToMessage = document.querySelector(`.message[data-message-id='${messageReply.dataset.messageId}']`);
if (replyToMessage) {
replyToMessage.classList.remove("replying-to");
}
}
});
});
function contextMenuHandler(e: MouseEvent) {
e.preventDefault();
//console.log("Opened context menu");
//createContextMenu(e, [
// { name: "Wah", callback: () => { return } }
//]);
}
</script>
<style>
html {
background-color: #1f1e1d;
}
body {
font-family: var(--preferred-font), Arial, Helvetica, sans-serif;
box-sizing: border-box;
color: var(--text-color);
background: var(--optional-body-background);
background-color: var(--chat-background-color);
margin: 0;
}
*:focus-visible {
outline: var(--outline-border);
}
a {
color: aquamarine;
}
.white {
color: white;
}
.bottom-border {
border-bottom: 1px solid var(--padding-color);
}
.left-border {
border-left: 1px solid var(--padding-color);
}
.right-border {
border-right: 1px solid var(--padding-color);
}
.rounded-corners {
border-radius: .3rem;
}
.invisible {
visibility: hidden;
}
</style>