Compare commits

...

2 Commits

Author SHA1 Message Date
grimhilt
1ab74d67ca close on escape 2023-04-11 19:15:35 +02:00
grimhilt
9842ebeb12 show mail content in modal on double click 2023-04-11 18:59:10 +02:00
7 changed files with 135 additions and 65 deletions

View File

@ -53,7 +53,7 @@ export async function getRooms(mailboxId) {
INNER JOIN flag ON flag.flag_id = flag_name.flag_id AND flag.message_id = app_room_message.message_id INNER JOIN flag ON flag.flag_id = flag_name.flag_id AND flag.message_id = app_room_message.message_id
WHERE flag_name.flag_id = flag.flag_id WHERE flag_name.flag_id = flag.flag_id
) )
) notSeenRoom ON notSeenThreads.room_id = room.room_id ) notSeenRoom ON notSeenRoom.room_id = room.room_id
LEFT JOIN ( LEFT JOIN (
SELECT app_room_message.message_id, app_thread.parent_id SELECT app_room_message.message_id, app_thread.parent_id

View File

@ -1,6 +1,7 @@
<script setup lang="ts"> <script setup lang="ts">
import { Message } from "@/store/models/model"; import { Message } from "@/store/models/model";
import { ref, watch, defineProps, PropType } from "vue"; import { ref, watch, defineProps, PropType } from "vue";
import Content from "../structure/message/Content.vue";
import Modal from "./Modal.vue"; import Modal from "./Modal.vue";
const props = defineProps({ messageId: { type: Number, require: true }, message: Object as PropType<Message> }); const props = defineProps({ messageId: { type: Number, require: true }, message: Object as PropType<Message> });
@ -16,11 +17,23 @@ watch(
</script> </script>
<template> <template>
<div> <div class="main">
<Modal v-if="messageId != -1" :title="props.message?.subject" @close-modal="() => $emit('close')"> <Modal v-if="messageId != -1" @close-modal="() => $emit('close')">
<template v-slot:body> yep </template> <template v-slot:body>
<div>{{ props.message?.subject ?? "No Object" }}</div>
<Content type="large" :content="props.message?.content" class="content" />
</template>
</Modal> </Modal>
</div> </div>
</template> </template>
<style></style> <style scoped>
.main {
min-width: 700px;
}
/* todo */
.content {
width: 700px;
height: 700px;
}
</style>

View File

@ -1,14 +1,25 @@
<script setup> <script setup>
import { vOnClickOutside } from "@vueuse/components"; import { vOnClickOutside } from "@vueuse/components";
import { defineEmits, defineProps } from "vue"; import { defineEmits, defineProps, onMounted, onUnmounted } from "vue";
const emit = defineEmits(["close-modal"]); const emit = defineEmits(["close-modal"]);
const props = defineProps({ title: String }); const props = defineProps({ title: String });
// todo close on escape
function close() { function close() {
emit("close-modal"); emit("close-modal");
} }
function keyUpHandler(e) {
if (e.key == "Escape") close();
}
onMounted(() => {
window.addEventListener("keyup", keyUpHandler);
});
onUnmounted(() => {
window.removeEventListener("keyup", keyUpHandler);
});
</script> </script>
<template> <template>

View File

@ -0,0 +1,70 @@
<script setup lang="ts">
import { defineProps, onMounted, ref, watch } from "vue";
import DOMPurify from "dompurify";
const props = defineProps({
content: String,
type: String,
});
const iframe = ref<HTMLIFrameElement>();
// todo dompurify
// background vs color
const htmlDefault = (html: string) => {
return `
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body style="margin: 0;">
${html}
</body>
</html>
`;
};
function setIframeContent(content: string | undefined) {
if (!iframe.value) return;
if (!content) return;
const doc = iframe.value.contentDocument || iframe.value.contentWindow?.document;
if (!doc) return;
const html = DOMPurify.sanitize(content);
doc.open();
doc.write(htmlDefault(html));
doc.close();
}
watch(
() => props.content,
(content: string | undefined) => {
setIframeContent(content);
},
);
onMounted(() => {
setIframeContent(props.content);
});
</script>
<template>
<iframe :class="type" ref="iframe"></iframe>
</template>
<style scoped>
iframe {
overflow-y: auto;
max-height: 300px;
flex-basis: 100%;
border: none;
max-width: 640px; /* template width being 600px to 640px up to 750px (experiment and test) */
background-color: rgb(234, 234, 234);
}
.large {
max-height: 700px;
}
</style>

View File

@ -1,57 +1,14 @@
<script setup lang="ts"> <script setup lang="ts">
import { defineProps, onMounted, ref, watch, PropType } from "vue"; import { defineProps, ref, PropType } from "vue";
import { decodeEmojis } from "../../utils/string"; import { decodeEmojis } from "../../../utils/string";
import { removeDuplicates } from "../../utils/array"; import { removeDuplicates } from "../../../utils/array";
import DOMPurify from "dompurify";
import { Address, Message } from "@/store/models/model"; import { Address, Message } from "@/store/models/model";
import Content from "./Content.vue";
const props = defineProps({ const props = defineProps({
msg: Object as PropType<Message>, msg: Object as PropType<Message>,
members: Array as PropType<Address[]>, members: Array as PropType<Address[]>,
}); });
console.log(props.msg);
const iframe = ref<HTMLIFrameElement>();
// todo dompurify
// background vs color
const htmlDefault = (html: string) => {
return `
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body style="margin: 0;">
${html}
</body>
</html>
`;
};
function setIframeContent(content: string | undefined) {
if (!iframe.value) return;
if (!content) return;
const doc = iframe.value.contentDocument || iframe.value.contentWindow?.document;
if (!doc) return;
const html = DOMPurify.sanitize(content);
doc.open();
doc.write(htmlDefault(html));
doc.close();
}
watch(
() => props.msg,
(newData: Message | undefined) => {
setIframeContent(newData?.content);
},
);
onMounted(() => {
setIframeContent(props.msg?.content);
});
const displayAddresses = (addressIds: string[] | undefined): string => { const displayAddresses = (addressIds: string[] | undefined): string => {
if (!addressIds) return ""; if (!addressIds) return "";
@ -106,7 +63,7 @@ const classes = (): string => {
</div> </div>
</div> </div>
<div class="content" :class="[classes()]"> <div class="content" :class="[classes()]">
<iframe ref="iframe"></iframe> <Content :content="props.msg?.content" />
<div class="options">options {{ props?.msg?.flags }}</div> <div class="options">options {{ props?.msg?.flags }}</div>
</div> </div>
</div> </div>
@ -156,15 +113,6 @@ const classes = (): string => {
background-color: var(--tertiary-background); background-color: var(--tertiary-background);
} }
iframe {
overflow-y: auto;
max-height: 300px;
flex-basis: 100%;
border: none;
max-width: 640px; /* template width being 600px to 640px up to 750px (experiment and test) */
background-color: rgb(234, 234, 234);
}
.options { .options {
flex: 1; flex: 1;
text-align: center; text-align: center;

View File

@ -0,0 +1,28 @@
<script setup lang="ts">
import { defineProps, onMounted, ref, watch, PropType } from "vue";
import { decodeEmojis } from "../../../utils/string";
import { removeDuplicates } from "../../../utils/array";
import DOMPurify from "dompurify";
import { Address, Message } from "@/store/models/model";
const props = defineProps({
msg: Object as PropType<Message>,
});
</script>
<template>
<div>
<div>mark as not read</div>
<div>flag favorite</div>
<div>reply</div>
<div>delete from all</div>
<div>delete from remote</div>
<div>transfer</div>
<div>see source</div>
</div>
</template>
<style scoped>
div {
text-align: center;
}
</style>

View File

@ -3,7 +3,7 @@ import { useStore } from "vuex";
import { useRoute, onBeforeRouteUpdate } from "vue-router"; import { useRoute, onBeforeRouteUpdate } from "vue-router";
import { onBeforeMount, ref } from "vue"; import { onBeforeMount, ref } from "vue";
import Header from "./Header.vue"; import Header from "./Header.vue";
import Message from "./Message.vue"; import Message from "../../components/structure/message/Message.vue";
import { Room, RoomType } from "@/store/models/model"; import { Room, RoomType } from "@/store/models/model";
import MessageViewModal from "@/components/modals/MessageViewModal.vue"; import MessageViewModal from "@/components/modals/MessageViewModal.vue";