Compare commits

...

3 Commits

Author SHA1 Message Date
grimhilt
e44584df0a simplify and composer design 2023-04-15 00:39:24 +02:00
grimhilt
956bc35158 fix duplication of threads on account change 2023-04-14 23:04:09 +02:00
grimhilt
79e17ad24f fix mail view in modal 2023-04-14 21:00:23 +02:00
4 changed files with 98 additions and 148 deletions

View File

@ -27,7 +27,7 @@ export async function getAccounts() {
return await execQueryAsync(query, values);
}
export async function getRooms(mailboxId) {
export async function getRooms(mailboxId: number) {
const query = `
SELECT
room.room_id AS id,

View File

@ -3,7 +3,7 @@ import imapAPI from "@/services/imapAPI";
import store from "@/store/store";
import StarterKit from "@tiptap/starter-kit";
import { BubbleMenu, useEditor, EditorContent, FloatingMenu } from "@tiptap/vue-3";
import { inject, onBeforeUnmount } from "vue";
import { inject } from "vue";
const editor = useEditor({
extensions: [StarterKit],
@ -35,120 +35,75 @@ const send = () => {
</script>
<template>
<div v-if="editor">
<bubble-menu class="bubble-menu" :tippy-options="{ duration: 100 }" :editor="editor">
<button
@click="editor.chain().focus().toggleBold().run()"
:class="{ 'is-active': editor.isActive('bold') }"
>
Bold
</button>
<button
@click="editor.chain().focus().toggleItalic().run()"
:class="{ 'is-active': editor.isActive('italic') }"
>
Italic
</button>
<button
@click="editor.chain().focus().toggleStrike().run()"
:class="{ 'is-active': editor.isActive('strike') }"
>
Strike
</button>
</bubble-menu>
<div class="main">
<div v-if="editor">
<bubble-menu class="bubble-menu" :tippy-options="{ duration: 100 }" :editor="editor">
<button
@click="editor.chain().focus().toggleBold().run()"
:class="{ 'is-active': editor.isActive('bold') }"
>
Bold
</button>
<button
@click="editor.chain().focus().toggleItalic().run()"
:class="{ 'is-active': editor.isActive('italic') }"
>
Italic
</button>
<button
@click="editor.chain().focus().toggleStrike().run()"
:class="{ 'is-active': editor.isActive('strike') }"
>
Strike
</button>
</bubble-menu>
<floating-menu class="floating-menu" :tippy-options="{ duration: 100 }" :editor="editor">
<button
@click="editor.chain().focus().toggleHeading({ level: 1 }).run()"
:class="{ 'is-active': editor.isActive('heading', { level: 1 }) }"
>
H1
</button>
<button
@click="editor.chain().focus().toggleHeading({ level: 2 }).run()"
:class="{ 'is-active': editor.isActive('heading', { level: 2 }) }"
>
H2
</button>
<button
@click="editor.chain().focus().toggleBulletList().run()"
:class="{ 'is-active': editor.isActive('bulletList') }"
>
Bullet List
</button>
</floating-menu>
<floating-menu class="floating-menu" :tippy-options="{ duration: 100 }" :editor="editor">
<button
@click="editor.chain().focus().toggleHeading({ level: 1 }).run()"
:class="{ 'is-active': editor.isActive('heading', { level: 1 }) }"
>
H1
</button>
<button
@click="editor.chain().focus().toggleHeading({ level: 2 }).run()"
:class="{ 'is-active': editor.isActive('heading', { level: 2 }) }"
>
H2
</button>
<button
@click="editor.chain().focus().toggleBulletList().run()"
:class="{ 'is-active': editor.isActive('bulletList') }"
>
Bullet List
</button>
</floating-menu>
</div>
<editor-content class="editor" :editor="editor" aria-expanded="false" />
<button @click="send()">SEND</button>
</div>
<editor-content class="editor" :editor="editor" />
<div class="send" @click="send()">SEND</div>
</template>
<style lang="scss">
.send:hover {
background-color: var(--selected);
}
/* Basic editor styles */
.editor {
background-color: var(--secondary-background);
}
.ProseMirror {
> * + * {
margin-top: 0.75em;
}
ul,
ol {
padding: 0 1rem;
}
blockquote {
padding-left: 1rem;
border-left: 2px solid rgba(#0d0d0d, 0.1);
}
}
.bubble-menu {
display: flex;
background-color: #0d0d0d;
padding: 0.2rem;
border-radius: 0.5rem;
button {
border: none;
background: none;
color: #fff;
font-size: 0.85rem;
font-weight: 500;
padding: 0 0.2rem;
opacity: 0.6;
&:hover,
&.is-active {
opacity: 1;
}
}
}
.floating-menu {
display: flex;
background-color: #0d0d0d10;
padding: 0.2rem;
border-radius: 0.5rem;
button {
border: none;
background: none;
font-size: 0.85rem;
font-weight: 500;
padding: 0 0.2rem;
opacity: 0.6;
&:hover,
&.is-active {
opacity: 1;
}
}
<style>
.ProseMirror:focus {
outline: none;
}
</style>
<style lang="scss" scoped>
.main {
display: flex;
flex-direction: row;
padding: 10px;
}
.editor {
background-color: var(--secondary-background);
flex: 1;
margin-right: 10px;
border-radius: 10px;
padding: 0 10px;
line-height: 0.6rem;
}
</style>

View File

@ -21,8 +21,6 @@ interface AccountFromBack {
email: string;
}
const buffer: RoomFromBack[] = [];
function createRoom(options: RoomFromBack): Room {
return {
id: options.id,
@ -117,6 +115,7 @@ const store = createStore<State>({
},
addRooms(state, payload) {
// todo add if not exist
const buffer: RoomFromBack[] = [];
payload.rooms.forEach((room: RoomFromBack) => {
if (room.roomType == RoomType.THREAD) {
buffer.push(room);
@ -174,7 +173,7 @@ const store = createStore<State>({
},
getters: {
rooms: (state) => (): Room[] => {
if (state.activeAccount === 0) return state.rooms;
if (state.activeAccount === 0) return state.rooms.filter((room) => room.roomType != RoomType.THREAD);
return state.rooms.filter(
(room) => room.mailboxId == state.activeAccount && room.roomType != RoomType.THREAD,
);
@ -200,6 +199,13 @@ const store = createStore<State>({
store.dispatch("fetchMessages", { roomId: roomId, obj: msgOnRoomId(state, roomId) });
return msgOnRoomId(state, roomId)?.messages ?? [];
},
message:
(state) =>
(roomId: number, messageId: number): Message | undefined => {
const roomMessage = msgOnRoomId(state, roomId);
if (!roomMessage) return;
return roomMessage.messages.find((msg) => msg.id === messageId);
},
accountOfRoom:
(state) =>
(roomId: number): string | undefined => {

View File

@ -39,59 +39,48 @@ const shouldDisplayComposer = () => {
);
};
function openMessageView(id) {
messageIdView.value = id;
message.value = room.value?.messages.find((message) => message.id == id);
function openMessageView(messageId) {
messageIdView.value = messageId;
if (messageId === -1) return;
message.value = store.getters.message(room.value.id, messageId);
}
provide("room", room);
</script>
<template>
<div id="main">
<div class="container">
<Header :id="id" :room="room"></Header>
<div id="RoomViewBody">
<div class="content">
<Message
v-for="(message, index) in store.getters.messages(room?.id)"
:key="index"
:msg="message"
:members="room?.members"
@open-message-view="(id) => openMessageView(id)"
/>
</div>
<Composer class="composer" v-if="shouldDisplayComposer()" />
<div class="messages">
<Message
v-for="(message, index) in store.getters.messages(room?.id)"
:key="index"
:msg="message"
:members="room?.members"
@open-message-view="(id) => openMessageView(id)"
/>
</div>
<Composer class="composer" v-if="shouldDisplayComposer()" />
<MessageViewModal :message="message" :messageId="messageIdView" @close="() => openMessageView(-1)" />
</div>
</template>
<style scoped>
#main {
.container {
display: flex;
flex-direction: column;
background-color: var(--primary-background);
color: var(--primary-text);
height: 100vh;
width: 100%;
}
#RoomViewBody {
display: flex;
flex-direction: column;
height: 100%;
.messages {
flex-grow: 1;
}
.composer {
position: absolute;
bottom: 0;
width: 100%;
padding-top: 10px;
height: 35px;
}
.content {
display: flex;
flex-direction: column-reverse;
overflow: auto;
margin-bottom: 60px;
align-items: center;
}
</style>