Compare commits
4 commits
cca2c5ffd9
...
704de034b7
Author | SHA1 | Date | |
---|---|---|---|
704de034b7 | |||
fef618795d | |||
950d27b2cf | |||
7ddc2acb02 |
5 changed files with 107 additions and 4 deletions
38
app.vue
38
app.vue
|
@ -6,9 +6,47 @@
|
|||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ContextMenu } from '#components';
|
||||
import { render } from 'vue';
|
||||
|
||||
const banner = useState("banner", () => false);
|
||||
|
||||
onMounted(() => {
|
||||
document.removeEventListener("contextmenu", contextMenuHandler);
|
||||
document.addEventListener("contextmenu", (e) => {
|
||||
contextMenuHandler(e);
|
||||
});
|
||||
document.addEventListener("mousedown", (e) => {
|
||||
console.log("click");
|
||||
console.log("target:", e.target);
|
||||
console.log(e.target instanceof HTMLDivElement);
|
||||
if (e.target instanceof HTMLDivElement) {
|
||||
const classes = e.target.classList;
|
||||
console.log(classes);
|
||||
if (classes.contains("message-data") || classes.contains("message-metadata") || classes.contains("message-text")) {
|
||||
const closest = e.target.closest("div.message") as HTMLDivElement;
|
||||
console.log("message ID:", closest.dataset.messageId);
|
||||
}
|
||||
}
|
||||
const contextMenu = document.getElementById("context-menu");
|
||||
if (contextMenu) {
|
||||
contextMenu.remove();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
function contextMenuHandler(e: MouseEvent) {
|
||||
e.preventDefault();
|
||||
console.log("Opened context menu");
|
||||
console.log("Rendering new context menu");
|
||||
const menuContainer = document.createElement("div");
|
||||
menuContainer.id = "context-menu";
|
||||
document.body.appendChild(menuContainer);
|
||||
const contextMenu = h(ContextMenu, { cursorX: e.clientX, cursorY: e.clientY });
|
||||
render(contextMenu, menuContainer);
|
||||
console.log("Rendered");
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<style>
|
||||
|
|
52
components/ContextMenu.vue
Normal file
52
components/ContextMenu.vue
Normal file
|
@ -0,0 +1,52 @@
|
|||
<template>
|
||||
<div v-for="item of menuItems" class="context-menu-item">
|
||||
{{ item.name }}
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
const props = defineProps<{ cursorX: number, cursorY: number }>();
|
||||
|
||||
|
||||
|
||||
const menuItems = [
|
||||
{ name: "Edit", callback: editMessage },
|
||||
{ name: "Reply", callback: replyMessage }
|
||||
];
|
||||
|
||||
onMounted(() => {
|
||||
const contextMenu = document.getElementById("context-menu");
|
||||
if (contextMenu) {
|
||||
contextMenu.style.left = props.cursorX.toString() + "px";
|
||||
contextMenu.style.top = props.cursorY.toString() + "px";
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
function editMessage() {
|
||||
//
|
||||
}
|
||||
|
||||
function replyMessage(id: string) {
|
||||
//
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<style>
|
||||
|
||||
#context-menu {
|
||||
position: absolute;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 10dvw;
|
||||
border: .15rem solid cyan;
|
||||
background-color: var(--background-color);
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.context-menu-item:hover {
|
||||
background-color: rgb(50, 50, 50);
|
||||
}
|
||||
|
||||
</style>
|
|
@ -1,5 +1,5 @@
|
|||
<template>
|
||||
<div v-if="props.type == 'normal'" :id="props.last ? 'last-message' : undefined" class="message normal-message">
|
||||
<div @click="emitId" v-if="props.type == 'normal'" :id="props.last ? 'last-message' : undefined" class="message normal-message" :data-message-id="props.messageId">
|
||||
<div class="left-column">
|
||||
<img v-if="props.img" class="message-author-avatar" :src="props.img" :alt="username" />
|
||||
<Icon v-else name="lucide:user" class="message-author-avatar" />
|
||||
|
@ -16,7 +16,7 @@
|
|||
<div class="message-text" v-html="sanitized" tabindex="0"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else ref="messageElement" :id="props.last ? 'last-message' : undefined" class="message grouped-message" :class="{ 'message-margin-bottom': props.marginBottom }">
|
||||
<div v-else ref="messageElement" :id="props.last ? 'last-message' : undefined" class="message grouped-message" :class="{ 'message-margin-bottom': props.marginBottom }" :data-message-id="props.messageId">
|
||||
<div class="left-column">
|
||||
<span :class="{ 'invisible': dateHidden }" class="message-date side-message-date" :title="date.toString()">
|
||||
{{ date.toLocaleTimeString(undefined, { timeStyle: "short" }) }}
|
||||
|
@ -41,7 +41,8 @@ const props = defineProps<{
|
|||
format: "12" | "24",
|
||||
type: "normal" | "grouped",
|
||||
marginBottom: boolean,
|
||||
last: boolean
|
||||
last: boolean,
|
||||
messageId: string
|
||||
}>();
|
||||
|
||||
const messageElement = ref<HTMLDivElement>();
|
||||
|
@ -74,6 +75,11 @@ onMounted(async () => {
|
|||
// showHover.value = !showHover.value;
|
||||
//}
|
||||
|
||||
const nuxtApp = useNuxtApp();
|
||||
function emitId() {
|
||||
// nuxtApp.callHook()
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
:text="message.message" :timestamp="messageTimestamps[message.uuid]" :img="message.user.avatar"
|
||||
format="12" :type="messagesType[message.uuid]"
|
||||
:margin-bottom="(messages[i + 1] && messagesType[messages[i + 1].uuid] == 'normal') ?? false"
|
||||
:last="i == messages.length - 1" />
|
||||
:last="i == messages.length - 1" :message-id="message.uuid" />
|
||||
</div>
|
||||
<div id="message-box" class="rounded-corners">
|
||||
<form id="message-form" @submit="sendMessage">
|
||||
|
|
7
types/hooks.ts
Normal file
7
types/hooks.ts
Normal file
|
@ -0,0 +1,7 @@
|
|||
import type { RuntimeNuxtHooks } from 'nuxt/schema';
|
||||
|
||||
declare module "nuxt/schema" {
|
||||
interface RuntimeNuxtHooks {
|
||||
"app:message:right-clicked": (payload: { messageId: string }) => void
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue