webmail - dark / light mode - UI refinements
Some checks are pending
Docker Image - Webmail / build_self_hosted (push) Waiting to run
Docker Image - Webmail / build_github_hosted_fallback (push) Blocked by required conditions

This commit is contained in:
ChrispyBacon-dev 2026-04-25 23:26:43 +02:00
parent 652e110d2e
commit 1f31021ae8
27 changed files with 1512 additions and 946 deletions

BIN
webmail/public/logo.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 MiB

View file

@ -541,7 +541,8 @@ if (__VLS_ctx.store.isComposeOpen && (__VLS_ctx.effectivePanelMode || !__VLS_ctx
...{ onBlur: (__VLS_ctx.toHandlers.onBlur) },
...{ onPaste: (__VLS_ctx.toHandlers.onPaste) },
placeholder: "Add recipient…",
...{ class: "flex-1 min-w-[120px] bg-transparent text-sm text-foreground placeholder:text-muted-foreground focus:outline-none py-0.5" },
...{ class: "flex-1 min-w-[120px] bg-transparent text-foreground placeholder:text-muted-foreground focus:outline-none py-0.5" },
...{ style: {} },
});
(__VLS_ctx.toInput);
__VLS_asFunctionalElement(__VLS_intrinsicElements.div, __VLS_intrinsicElements.div)({
@ -674,7 +675,8 @@ if (__VLS_ctx.store.isComposeOpen && (__VLS_ctx.effectivePanelMode || !__VLS_ctx
});
__VLS_asFunctionalElement(__VLS_intrinsicElements.select, __VLS_intrinsicElements.select)({
value: (__VLS_ctx.fromAddress),
...{ class: "flex-1 px-2 py-2 text-sm bg-background text-foreground focus:outline-none" },
...{ class: "flex-1 px-2 py-2 bg-transparent text-foreground focus:outline-none" },
...{ style: {} },
});
__VLS_asFunctionalElement(__VLS_intrinsicElements.option, __VLS_intrinsicElements.option)({
value: (__VLS_ctx.store.currentMailbox),
@ -690,7 +692,8 @@ if (__VLS_ctx.store.isComposeOpen && (__VLS_ctx.effectivePanelMode || !__VLS_ctx
}
__VLS_asFunctionalElement(__VLS_intrinsicElements.input)({
placeholder: "Subject",
...{ class: "w-full px-4 py-2 text-sm bg-background text-foreground placeholder:text-muted-foreground focus:outline-none" },
...{ class: "w-full px-4 py-2 bg-transparent text-foreground placeholder:text-muted-foreground focus:outline-none" },
...{ style: {} },
});
(__VLS_ctx.subject);
const __VLS_32 = {}.EditorContent;
@ -1332,7 +1335,6 @@ if (__VLS_ctx.store.isComposeOpen && (__VLS_ctx.effectivePanelMode || !__VLS_ctx
/** @type {__VLS_StyleScopedClasses['flex-1']} */ ;
/** @type {__VLS_StyleScopedClasses['min-w-[120px]']} */ ;
/** @type {__VLS_StyleScopedClasses['bg-transparent']} */ ;
/** @type {__VLS_StyleScopedClasses['text-sm']} */ ;
/** @type {__VLS_StyleScopedClasses['text-foreground']} */ ;
/** @type {__VLS_StyleScopedClasses['placeholder:text-muted-foreground']} */ ;
/** @type {__VLS_StyleScopedClasses['focus:outline-none']} */ ;
@ -1443,15 +1445,13 @@ if (__VLS_ctx.store.isComposeOpen && (__VLS_ctx.effectivePanelMode || !__VLS_ctx
/** @type {__VLS_StyleScopedClasses['flex-1']} */ ;
/** @type {__VLS_StyleScopedClasses['px-2']} */ ;
/** @type {__VLS_StyleScopedClasses['py-2']} */ ;
/** @type {__VLS_StyleScopedClasses['text-sm']} */ ;
/** @type {__VLS_StyleScopedClasses['bg-background']} */ ;
/** @type {__VLS_StyleScopedClasses['bg-transparent']} */ ;
/** @type {__VLS_StyleScopedClasses['text-foreground']} */ ;
/** @type {__VLS_StyleScopedClasses['focus:outline-none']} */ ;
/** @type {__VLS_StyleScopedClasses['w-full']} */ ;
/** @type {__VLS_StyleScopedClasses['px-4']} */ ;
/** @type {__VLS_StyleScopedClasses['py-2']} */ ;
/** @type {__VLS_StyleScopedClasses['text-sm']} */ ;
/** @type {__VLS_StyleScopedClasses['bg-background']} */ ;
/** @type {__VLS_StyleScopedClasses['bg-transparent']} */ ;
/** @type {__VLS_StyleScopedClasses['text-foreground']} */ ;
/** @type {__VLS_StyleScopedClasses['placeholder:text-muted-foreground']} */ ;
/** @type {__VLS_StyleScopedClasses['focus:outline-none']} */ ;

File diff suppressed because one or more lines are too long

View file

@ -1,7 +1,7 @@
<script setup lang="ts">
import { computed, ref, type Component } from 'vue'
import {
Inbox, FileText, Send, Trash2, AlertCircle, Archive, Folder,
Inbox, FileText, Send, Trash2, AlertCircle, Archive, Folder, FolderOpen,
FolderPlus, X,
} from 'lucide-vue-next'
import { TooltipRoot, TooltipTrigger, TooltipContent, TooltipPortal } from 'radix-vue'
@ -26,7 +26,7 @@ const PALETTE = [
'#3b82f6', '#8b5cf6', '#ec4899', '#14b8a6',
]
const getIcon = (name: string): Component => iconMap[name] || Folder
const getIcon = (name: string, active = false): Component => iconMap[name] || (active ? FolderOpen : Folder)
const systemFolders = computed(() => store.folders.filter((f: any) => f.system_folder))
const customFolders = computed(() => store.folders.filter((f: any) => !f.system_folder))
@ -142,7 +142,7 @@ const confirmEdit = async () => {
)"
@click="selectFolder(f.name)"
>
<component :is="getIcon(f.name)" class="size-4" :style="f.color && store.currentFolder !== f.name ? `color:${f.color}` : ''" />
<component :is="getIcon(f.name, store.currentFolder === f.name)" class="size-4" :style="f.color && store.currentFolder !== f.name ? `color:${f.color}` : ''" />
<span class="sr-only">{{ f.name }}</span>
</button>
</TooltipTrigger>
@ -203,7 +203,7 @@ const confirmEdit = async () => {
class="flex flex-1 items-center gap-3 px-3 py-2 text-left min-w-0"
@click="selectFolder(f.name)"
>
<component :is="getIcon(f.name)" class="size-4 flex-shrink-0" :style="f.color ? `color:${f.color}` : ''" />
<component :is="getIcon(f.name, store.currentFolder === f.name)" class="size-4 flex-shrink-0" :style="f.color && store.currentFolder !== f.name ? `color:${f.color}` : ''" />
<span class="truncate">{{ f.name }}</span>
<span
v-if="f.total_count > 0"
@ -246,9 +246,8 @@ const confirmEdit = async () => {
</div>
</template>
<!-- Section label: Custom (expanded only) -->
<!-- Custom folders (expanded only) -->
<template v-if="!isCollapsed && customFolders.length">
<p class="px-3 pt-3 pb-1 text-[10px] font-semibold uppercase tracking-widest text-muted-foreground/60 select-none">Custom</p>
<template v-for="f in customFolders" :key="f.name + '-custom'">
<!-- Expanded row inline edit mode -->
<div v-if="editingFolder?.id === f.id" class="rounded-md border bg-muted p-2 flex flex-col gap-2">
@ -271,7 +270,7 @@ const confirmEdit = async () => {
)"
>
<button class="flex flex-1 items-center gap-3 px-3 py-2 text-left min-w-0" @click="selectFolder(f.name)">
<component :is="getIcon(f.name)" class="size-4 flex-shrink-0" :style="f.color ? `color:${f.color}` : ''" />
<component :is="getIcon(f.name, store.currentFolder === f.name)" class="size-4 flex-shrink-0" :style="f.color && store.currentFolder !== f.name ? `color:${f.color}` : ''" />
<span class="truncate">{{ f.name }}</span>
<span v-if="f.total_count > 0" :class="cn('ml-auto text-xs flex-shrink-0 flex gap-1', store.currentFolder === f.name ? 'opacity-90' : 'text-muted-foreground')">
<span v-if="f.unread_count" class="rounded-full px-1.5 py-0.5 text-[10.5px] font-bold leading-none flex items-center" style="background: rgba(251,166,18,0.12); color: #FBA612;">{{ f.unread_count }}</span>

View file

@ -1,6 +1,6 @@
/// <reference types="../../../node_modules/.vue-global-types/vue_3.5_0_0_0.d.ts" />
import { computed, ref } from 'vue';
import { Inbox, FileText, Send, Trash2, AlertCircle, Archive, Folder, FolderPlus, } from 'lucide-vue-next';
import { Inbox, FileText, Send, Trash2, AlertCircle, Archive, Folder, FolderOpen, FolderPlus, } from 'lucide-vue-next';
import { TooltipRoot, TooltipTrigger, TooltipContent, TooltipPortal } from 'radix-vue';
import { cn } from '../../lib/utils';
import { useMailStore } from '../../stores/mail';
@ -18,7 +18,7 @@ const PALETTE = [
'#ef4444', '#f97316', '#eab308', '#22c55e',
'#3b82f6', '#8b5cf6', '#ec4899', '#14b8a6',
];
const getIcon = (name) => iconMap[name] || Folder;
const getIcon = (name, active = false) => iconMap[name] || (active ? FolderOpen : Folder);
const systemFolders = computed(() => store.folders.filter((f) => f.system_folder));
const customFolders = computed(() => store.folders.filter((f) => !f.system_folder));
const selectFolder = (name) => {
@ -155,7 +155,7 @@ for (const [f] of __VLS_getVForSourceType(((__VLS_ctx.isCollapsed ? __VLS_ctx.st
? 'df-folder-active'
: 'text-muted-foreground')) },
});
const __VLS_8 = ((__VLS_ctx.getIcon(f.name)));
const __VLS_8 = ((__VLS_ctx.getIcon(f.name, __VLS_ctx.store.currentFolder === f.name)));
// @ts-ignore
const __VLS_9 = __VLS_asFunctionalComponent(__VLS_8, new __VLS_8({
...{ class: "size-4" },
@ -274,15 +274,15 @@ for (const [f] of __VLS_getVForSourceType(((__VLS_ctx.isCollapsed ? __VLS_ctx.st
} },
...{ class: "flex flex-1 items-center gap-3 px-3 py-2 text-left min-w-0" },
});
const __VLS_20 = ((__VLS_ctx.getIcon(f.name)));
const __VLS_20 = ((__VLS_ctx.getIcon(f.name, __VLS_ctx.store.currentFolder === f.name)));
// @ts-ignore
const __VLS_21 = __VLS_asFunctionalComponent(__VLS_20, new __VLS_20({
...{ class: "size-4 flex-shrink-0" },
...{ style: (f.color ? `color:${f.color}` : '') },
...{ style: (f.color && __VLS_ctx.store.currentFolder !== f.name ? `color:${f.color}` : '') },
}));
const __VLS_22 = __VLS_21({
...{ class: "size-4 flex-shrink-0" },
...{ style: (f.color ? `color:${f.color}` : '') },
...{ style: (f.color && __VLS_ctx.store.currentFolder !== f.name ? `color:${f.color}` : '') },
}, ...__VLS_functionalComponentArgsRest(__VLS_21));
__VLS_asFunctionalElement(__VLS_intrinsicElements.span, __VLS_intrinsicElements.span)({
...{ class: "truncate" },
@ -306,7 +306,7 @@ for (const [f] of __VLS_getVForSourceType(((__VLS_ctx.isCollapsed ? __VLS_ctx.st
}
if (!f.system_folder) {
__VLS_asFunctionalElement(__VLS_intrinsicElements.div, __VLS_intrinsicElements.div)({
...{ class: (__VLS_ctx.cn('absolute right-1 flex gap-0.5 opacity-0 group-hover/row:opacity-100 transition-opacity rounded px-0.5', __VLS_ctx.store.currentFolder === f.name ? 'bg-primary' : 'bg-accent')) },
...{ class: (__VLS_ctx.cn('absolute right-1 flex gap-0.5 opacity-0 group-hover/row:opacity-100 [@media(hover:none)]:opacity-100 transition-opacity rounded px-0.5', __VLS_ctx.store.currentFolder === f.name ? 'bg-primary' : 'bg-accent')) },
});
__VLS_asFunctionalElement(__VLS_intrinsicElements.button, __VLS_intrinsicElements.button)({
...{ onClick: (...[$event]) => {
@ -360,9 +360,6 @@ for (const [f] of __VLS_getVForSourceType(((__VLS_ctx.isCollapsed ? __VLS_ctx.st
}
}
if (!__VLS_ctx.isCollapsed && __VLS_ctx.customFolders.length) {
__VLS_asFunctionalElement(__VLS_intrinsicElements.p, __VLS_intrinsicElements.p)({
...{ class: "px-3 pt-3 pb-1 text-[10px] font-semibold uppercase tracking-widest text-muted-foreground/60 select-none" },
});
for (const [f] of __VLS_getVForSourceType((__VLS_ctx.customFolders))) {
(f.name + '-custom');
if (__VLS_ctx.editingFolder?.id === f.id) {
@ -431,15 +428,15 @@ if (!__VLS_ctx.isCollapsed && __VLS_ctx.customFolders.length) {
} },
...{ class: "flex flex-1 items-center gap-3 px-3 py-2 text-left min-w-0" },
});
const __VLS_28 = ((__VLS_ctx.getIcon(f.name)));
const __VLS_28 = ((__VLS_ctx.getIcon(f.name, __VLS_ctx.store.currentFolder === f.name)));
// @ts-ignore
const __VLS_29 = __VLS_asFunctionalComponent(__VLS_28, new __VLS_28({
...{ class: "size-4 flex-shrink-0" },
...{ style: (f.color ? `color:${f.color}` : '') },
...{ style: (f.color && __VLS_ctx.store.currentFolder !== f.name ? `color:${f.color}` : '') },
}));
const __VLS_30 = __VLS_29({
...{ class: "size-4 flex-shrink-0" },
...{ style: (f.color ? `color:${f.color}` : '') },
...{ style: (f.color && __VLS_ctx.store.currentFolder !== f.name ? `color:${f.color}` : '') },
}, ...__VLS_functionalComponentArgsRest(__VLS_29));
__VLS_asFunctionalElement(__VLS_intrinsicElements.span, __VLS_intrinsicElements.span)({
...{ class: "truncate" },
@ -696,15 +693,6 @@ if (!__VLS_ctx.isCollapsed) {
/** @type {__VLS_StyleScopedClasses['rounded']} */ ;
/** @type {__VLS_StyleScopedClasses['hover:text-destructive']} */ ;
/** @type {__VLS_StyleScopedClasses['size-3']} */ ;
/** @type {__VLS_StyleScopedClasses['px-3']} */ ;
/** @type {__VLS_StyleScopedClasses['pt-3']} */ ;
/** @type {__VLS_StyleScopedClasses['pb-1']} */ ;
/** @type {__VLS_StyleScopedClasses['text-[10px]']} */ ;
/** @type {__VLS_StyleScopedClasses['font-semibold']} */ ;
/** @type {__VLS_StyleScopedClasses['uppercase']} */ ;
/** @type {__VLS_StyleScopedClasses['tracking-widest']} */ ;
/** @type {__VLS_StyleScopedClasses['text-muted-foreground/60']} */ ;
/** @type {__VLS_StyleScopedClasses['select-none']} */ ;
/** @type {__VLS_StyleScopedClasses['rounded-md']} */ ;
/** @type {__VLS_StyleScopedClasses['border']} */ ;
/** @type {__VLS_StyleScopedClasses['bg-muted']} */ ;

File diff suppressed because one or more lines are too long

View file

@ -183,36 +183,9 @@ const mobileTitle = computed(() => {
<div class="absolute top-0 left-0 right-0 h-px pointer-events-none z-10" style="background: rgba(255,255,255,0.62)" />
<!-- Header: wordmark + collapse toggle -->
<div class="h-[54px] flex items-center px-[14px] flex-shrink-0">
<div class="h-[54px] flex items-center justify-center px-[14px] flex-shrink-0">
<template v-if="!store.isCollapsed">
<span class="font-['Outfit'] font-extrabold text-[17px] tracking-[-0.01em] leading-none select-none whitespace-nowrap">
<span class="text-[#194466] dark:text-[#5EB1E5]">Dock</span><span class="text-[#FBA612]">Flare</span>
</span>
<div class="ml-auto flex items-center gap-1">
<TooltipRoot :delay-duration="0">
<TooltipTrigger as-child>
<button class="inline-flex h-7 w-7 items-center justify-center rounded-md text-muted-foreground hover:bg-accent/60 transition-colors" @click="store.toggleViewMode()">
<Columns2 v-if="store.viewMode === 'full'" class="size-3.5" />
<Maximize2 v-else class="size-3.5" />
</button>
</TooltipTrigger>
<TooltipPortal>
<TooltipContent side="bottom" class="z-50 rounded-md border bg-popover px-3 py-1.5 text-sm text-popover-foreground shadow-md">
{{ store.viewMode === 'full' ? 'Split view' : 'Full view' }}
</TooltipContent>
</TooltipPortal>
</TooltipRoot>
<TooltipRoot :delay-duration="0">
<TooltipTrigger as-child>
<button class="inline-flex h-7 w-7 items-center justify-center rounded-md text-muted-foreground hover:bg-accent/60 transition-colors" @click="store.isCollapsed = true">
<PanelLeftClose class="size-3.5" />
</button>
</TooltipTrigger>
<TooltipPortal>
<TooltipContent side="bottom" class="z-50 rounded-md border bg-popover px-3 py-1.5 text-sm text-popover-foreground shadow-md">Collapse sidebar</TooltipContent>
</TooltipPortal>
</TooltipRoot>
</div>
<img src="/logo.gif" alt="DockFlare" class="h-7 w-auto select-none" draggable="false" />
</template>
<template v-else>
<span class="font-['Outfit'] font-extrabold text-[15px] leading-none select-none mx-auto">
@ -221,20 +194,6 @@ const mobileTitle = computed(() => {
</template>
</div>
<!-- Expand button only when collapsed, below DF logo -->
<div v-if="store.isCollapsed" class="flex justify-center pb-1 flex-shrink-0">
<TooltipRoot :delay-duration="0">
<TooltipTrigger as-child>
<button class="inline-flex h-7 w-7 items-center justify-center rounded-md text-muted-foreground hover:bg-accent/60 transition-colors" @click="store.isCollapsed = false">
<PanelLeftOpen class="size-3.5" />
</button>
</TooltipTrigger>
<TooltipPortal>
<TooltipContent side="right" class="z-50 rounded-md border bg-popover px-3 py-1.5 text-sm text-popover-foreground shadow-md">Expand sidebar</TooltipContent>
</TooltipPortal>
</TooltipRoot>
</div>
<!-- Mailbox selector only when multiple mailboxes -->
<div v-if="store.mailboxes.length > 1 && !store.isCollapsed" class="px-3 pb-2 flex-shrink-0">
<MailboxSelector :is-collapsed="false" />
@ -273,9 +232,15 @@ const mobileTitle = computed(() => {
:class="store.isCollapsed
? 'flex flex-col items-center gap-1 px-2 py-3 flex-shrink-0'
: 'px-3 py-3 flex-shrink-0 space-y-0.5'"
style="border-top: 1px solid rgba(128,128,128,0.1);"
>
<template v-if="!store.isCollapsed">
<button
class="flex items-center gap-3 w-full px-3 py-2 rounded-lg text-sm text-muted-foreground hover:bg-accent/60 hover:text-foreground transition-colors"
@click="store.isCollapsed = true"
>
<PanelLeftClose class="size-4" />
Collapse sidebar
</button>
<button
class="flex items-center gap-3 w-full px-3 py-2 rounded-lg text-sm text-muted-foreground hover:bg-accent/60 hover:text-foreground transition-colors"
@click="store.toggleTheme()"
@ -300,6 +265,16 @@ const mobileTitle = computed(() => {
</button>
</template>
<template v-else>
<TooltipRoot :delay-duration="0">
<TooltipTrigger as-child>
<button class="inline-flex h-8 w-8 items-center justify-center rounded-md text-muted-foreground hover:bg-accent transition-colors" @click="store.isCollapsed = false">
<PanelLeftOpen class="size-4" />
</button>
</TooltipTrigger>
<TooltipPortal>
<TooltipContent side="right" class="z-50 rounded-md border bg-popover px-3 py-1.5 text-sm text-popover-foreground shadow-md">Expand sidebar</TooltipContent>
</TooltipPortal>
</TooltipRoot>
<TooltipRoot :delay-duration="0">
<TooltipTrigger as-child>
<button class="inline-flex h-8 w-8 items-center justify-center rounded-md text-muted-foreground hover:bg-accent transition-colors" @click="store.toggleTheme()">
@ -347,7 +322,7 @@ const mobileTitle = computed(() => {
:default-size="35"
:min-size="25"
class="flex flex-col overflow-hidden"
style="background: var(--df-list-bg); backdrop-filter: var(--df-list-blur); box-shadow: 2px 0 10px rgba(0,0,0,0.035);"
style="background: var(--df-list-bg); backdrop-filter: var(--df-list-blur);"
>
<MessageList />
</SplitterPanel>

File diff suppressed because it is too large Load diff

File diff suppressed because one or more lines are too long

View file

@ -541,7 +541,6 @@ const sendInlineReply = async () => {
<AttachmentBar :attachments="message.attachments" />
<Separator class="mt-auto print-hide" />
<div class="p-4 print-hide">
<form @submit.prevent="sendInlineReply">
@ -586,12 +585,16 @@ const sendInlineReply = async () => {
.df-reply-wrapper :deep(textarea) {
background: transparent !important;
}
:global(.dark) .df-reply-wrapper {
.dark .df-reply-wrapper {
background: rgba(255, 255, 255, 0.09);
border: 1px solid rgba(255, 255, 255, 0.13);
}
:global(.dark) .df-reply-wrapper :deep(textarea) {
.dark .df-reply-wrapper :deep(textarea) {
color: hsl(210 40% 92%);
caret-color: hsl(210 40% 92%);
}
.dark .df-reply-wrapper :deep(textarea)::placeholder {
color: hsl(210 30% 70%);
opacity: 1;
}
</style>

View file

@ -334,6 +334,11 @@ let __VLS_components;
let __VLS_directives;
/** @type {__VLS_StyleScopedClasses['df-reply-wrapper']} */ ;
/** @type {__VLS_StyleScopedClasses['df-reply-wrapper']} */ ;
/** @type {__VLS_StyleScopedClasses['df-reply-wrapper']} */ ;
/** @type {__VLS_StyleScopedClasses['dark']} */ ;
/** @type {__VLS_StyleScopedClasses['df-reply-wrapper']} */ ;
/** @type {__VLS_StyleScopedClasses['dark']} */ ;
/** @type {__VLS_StyleScopedClasses['df-reply-wrapper']} */ ;
// CSS variable injection
// CSS variable injection end
__VLS_asFunctionalElement(__VLS_intrinsicElements.div, __VLS_intrinsicElements.div)({
@ -1231,14 +1236,6 @@ if (__VLS_ctx.message) {
const __VLS_300 = __VLS_299({
attachments: (__VLS_ctx.message.attachments),
}, ...__VLS_functionalComponentArgsRest(__VLS_299));
/** @type {[typeof Separator, ]} */ ;
// @ts-ignore
const __VLS_302 = __VLS_asFunctionalComponent(Separator, new Separator({
...{ class: "mt-auto print-hide" },
}));
const __VLS_303 = __VLS_302({
...{ class: "mt-auto print-hide" },
}, ...__VLS_functionalComponentArgsRest(__VLS_302));
__VLS_asFunctionalElement(__VLS_intrinsicElements.div, __VLS_intrinsicElements.div)({
...{ class: "p-4 print-hide" },
});
@ -1253,36 +1250,36 @@ if (__VLS_ctx.message) {
});
/** @type {[typeof Textarea, ]} */ ;
// @ts-ignore
const __VLS_305 = __VLS_asFunctionalComponent(Textarea, new Textarea({
const __VLS_302 = __VLS_asFunctionalComponent(Textarea, new Textarea({
modelValue: (__VLS_ctx.replyText),
...{ class: "p-2 min-h-[80px] bg-transparent border-0 shadow-none focus-visible:ring-0" },
placeholder: (`Reply ${__VLS_ctx.message.from_name || __VLS_ctx.message.from_address}...`),
}));
const __VLS_306 = __VLS_305({
const __VLS_303 = __VLS_302({
modelValue: (__VLS_ctx.replyText),
...{ class: "p-2 min-h-[80px] bg-transparent border-0 shadow-none focus-visible:ring-0" },
placeholder: (`Reply ${__VLS_ctx.message.from_name || __VLS_ctx.message.from_address}...`),
}, ...__VLS_functionalComponentArgsRest(__VLS_305));
}, ...__VLS_functionalComponentArgsRest(__VLS_302));
__VLS_asFunctionalElement(__VLS_intrinsicElements.div, __VLS_intrinsicElements.div)({
...{ class: "flex items-center" },
});
/** @type {[typeof Button, typeof Button, ]} */ ;
// @ts-ignore
const __VLS_308 = __VLS_asFunctionalComponent(Button, new Button({
const __VLS_305 = __VLS_asFunctionalComponent(Button, new Button({
type: "submit",
size: "sm",
...{ class: "ml-auto" },
disabled: (__VLS_ctx.sendingReply || !__VLS_ctx.replyText.trim()),
}));
const __VLS_309 = __VLS_308({
const __VLS_306 = __VLS_305({
type: "submit",
size: "sm",
...{ class: "ml-auto" },
disabled: (__VLS_ctx.sendingReply || !__VLS_ctx.replyText.trim()),
}, ...__VLS_functionalComponentArgsRest(__VLS_308));
__VLS_310.slots.default;
}, ...__VLS_functionalComponentArgsRest(__VLS_305));
__VLS_307.slots.default;
(__VLS_ctx.sendingReply ? 'Sending...' : 'Send');
var __VLS_310;
var __VLS_307;
}
else {
__VLS_asFunctionalElement(__VLS_intrinsicElements.div, __VLS_intrinsicElements.div)({
@ -1515,8 +1512,6 @@ else {
/** @type {__VLS_StyleScopedClasses['p-4']} */ ;
/** @type {__VLS_StyleScopedClasses['text-sm']} */ ;
/** @type {__VLS_StyleScopedClasses['whitespace-pre-wrap']} */ ;
/** @type {__VLS_StyleScopedClasses['mt-auto']} */ ;
/** @type {__VLS_StyleScopedClasses['print-hide']} */ ;
/** @type {__VLS_StyleScopedClasses['p-4']} */ ;
/** @type {__VLS_StyleScopedClasses['print-hide']} */ ;
/** @type {__VLS_StyleScopedClasses['grid']} */ ;

File diff suppressed because one or more lines are too long

View file

@ -1,16 +1,16 @@
<script setup lang="ts">
import { ref, computed } from 'vue'
import { ArrowDownUp, Trash2 } from 'lucide-vue-next'
const props = defineProps({
hideTitle: { type: Boolean, default: false },
})
import { ref, computed, watch } from 'vue'
import { ArrowDownUp, Trash2, Square, CheckSquare, FolderInput } from 'lucide-vue-next'
import {
TabsRoot, TabsList, TabsTrigger, TabsContent,
} from 'radix-vue'
import {
ScrollAreaRoot, ScrollAreaViewport, ScrollAreaScrollbar, ScrollAreaThumb,
} from 'radix-vue'
import {
DropdownMenuRoot, DropdownMenuTrigger, DropdownMenuContent,
DropdownMenuItem, DropdownMenuPortal,
} from 'radix-vue'
import { useMailStore } from '../../stores/mail'
import { mailApi } from '../../api/mail'
import MessageListItem from './MessageListItem.vue'
@ -18,9 +18,17 @@ import SearchBar from './SearchBar.vue'
import Dialog from '../ui/Dialog.vue'
import Button from '../ui/Button.vue'
const props = defineProps({
hideTitle: { type: Boolean, default: false },
})
const store = useMailStore()
const showTrashConfirm = ref(false)
const bulkSelectMode = ref(false)
const selectedIds = ref<Set<string>>(new Set())
const isBulkLoading = ref(false)
const folderColor = computed(() => store.currentFolderObj?.color || '')
const unreadMessages = computed(() =>
@ -43,11 +51,48 @@ const displayMessages = computed(() => {
})
})
const trashFolder = computed(() => store.folders.find((f: any) => f.name === 'Trash'))
const otherFolders = computed(() => store.folders.filter((f: any) => f.name !== store.currentFolder))
const hasSelection = computed(() => selectedIds.value.size > 0)
const allSelected = computed(() =>
displayMessages.value.length > 0 && selectedIds.value.size === displayMessages.value.length
)
watch(() => store.activeTab, () => {
selectedIds.value = new Set()
})
const toggleSort = () => {
store.sortOrder = store.sortOrder === 'desc' ? 'asc' : 'desc'
}
function toggleBulkSelect() {
bulkSelectMode.value = !bulkSelectMode.value
if (!bulkSelectMode.value) {
selectedIds.value = new Set()
}
}
function toggleSelectAll() {
if (allSelected.value) {
selectedIds.value = new Set()
} else {
selectedIds.value = new Set(displayMessages.value.map((m: any) => m.id))
}
}
function toggleMessageSelection(id: string) {
const next = new Set(selectedIds.value)
if (next.has(id)) next.delete(id)
else next.add(id)
selectedIds.value = next
}
const selectMessage = (msg: any) => {
if (bulkSelectMode.value) {
toggleMessageSelection(msg.id)
return
}
if (msg.is_draft) {
let parsed = msg.to_addresses
if (typeof parsed === 'string') {
@ -86,6 +131,46 @@ const performEmptyTrash = async () => {
showTrashConfirm.value = false
}
}
async function bulkMoveToTrash() {
if (!hasSelection.value || !trashFolder.value) return
isBulkLoading.value = true
try {
await mailApi.moveMessages(store.currentMailbox, {
message_ids: [...selectedIds.value],
folder_id: trashFolder.value.id,
})
store.messages = (store.messages as any[]).filter((m: any) => !selectedIds.value.has(m.id)) as any
selectedIds.value = new Set()
const fRes = await mailApi.getFolders(store.currentMailbox)
store.folders = fRes.data
store.showToast('Messages moved to Trash', 'success')
} catch {
store.showToast('Failed to move messages to Trash')
} finally {
isBulkLoading.value = false
}
}
async function bulkMoveToFolder(folderId: number, folderName: string) {
if (!hasSelection.value) return
isBulkLoading.value = true
try {
await mailApi.moveMessages(store.currentMailbox, {
message_ids: [...selectedIds.value],
folder_id: folderId,
})
store.messages = (store.messages as any[]).filter((m: any) => !selectedIds.value.has(m.id)) as any
selectedIds.value = new Set()
const fRes = await mailApi.getFolders(store.currentMailbox)
store.folders = fRes.data
store.showToast(`Messages moved to ${folderName}`, 'success')
} catch {
store.showToast('Failed to move messages')
} finally {
isBulkLoading.value = false
}
}
</script>
<template>
@ -93,14 +178,95 @@ const performEmptyTrash = async () => {
<div class="flex items-center px-4 flex-shrink-0" :class="hideTitle ? 'h-[44px]' : 'h-[52px]'">
<h1 v-if="!hideTitle" class="text-xl font-bold">{{ store.currentFolder || 'Inbox' }}</h1>
<div class="flex items-center gap-1" :class="hideTitle ? 'w-full justify-between' : 'ml-auto'">
<!-- Bulk action controls (visible when bulkSelectMode active) -->
<template v-if="bulkSelectMode">
<!-- Select all -->
<button
class="inline-flex h-9 w-9 items-center justify-center rounded-md text-muted-foreground hover:bg-accent hover:text-accent-foreground transition-colors"
:title="allSelected ? 'Deselect all' : 'Select all'"
@click="toggleSelectAll"
>
<CheckSquare v-if="allSelected" class="size-4" />
<Square v-else class="size-4" />
</button>
<!-- Move to trash (hidden when already in Trash) -->
<button
v-if="store.currentFolder !== 'Trash'"
class="inline-flex h-9 w-9 items-center justify-center rounded-md transition-colors"
:class="hasSelection && !isBulkLoading
? 'text-muted-foreground hover:bg-destructive hover:text-destructive-foreground'
: 'text-muted-foreground/30 cursor-not-allowed'"
:disabled="!hasSelection || isBulkLoading"
title="Move to Trash"
@click="bulkMoveToTrash"
>
<Trash2 class="size-4" />
</button>
<!-- Move to folder dropdown -->
<DropdownMenuRoot>
<DropdownMenuTrigger as-child>
<button
class="inline-flex h-9 w-9 items-center justify-center rounded-md transition-colors"
:class="hasSelection && !isBulkLoading
? 'text-muted-foreground hover:bg-accent hover:text-accent-foreground'
: 'text-muted-foreground/30 cursor-not-allowed'"
:disabled="!hasSelection || isBulkLoading"
title="Move to folder"
>
<FolderInput class="size-4" />
</button>
</DropdownMenuTrigger>
<DropdownMenuPortal>
<DropdownMenuContent
align="end"
:side-offset="4"
class="z-50 min-w-[160px] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md"
>
<DropdownMenuItem
v-for="folder in otherFolders"
:key="folder.id"
class="relative flex cursor-pointer select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none hover:bg-accent hover:text-accent-foreground"
@click="bulkMoveToFolder(folder.id, folder.name)"
>
<span
v-if="folder.color"
class="h-2 w-2 rounded-full flex-shrink-0"
:style="`background: ${folder.color}`"
/>
{{ folder.name }}
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenuPortal>
</DropdownMenuRoot>
</template>
<!-- Empty trash (only outside bulk mode) -->
<button
v-if="store.currentFolder === 'Trash' && store.messages.length > 0"
v-if="store.currentFolder === 'Trash' && store.messages.length > 0 && !bulkSelectMode"
class="inline-flex h-9 w-9 items-center justify-center rounded-md text-muted-foreground hover:bg-destructive hover:text-destructive-foreground transition-colors"
title="Empty Trash"
@click="emptyTrash"
>
<Trash2 class="size-4" />
</button>
<!-- Checkbox toggle (always visible) -->
<button
class="inline-flex h-9 w-9 items-center justify-center rounded-md transition-colors"
:class="bulkSelectMode
? 'bg-accent text-[#FBA612]'
: 'text-muted-foreground hover:bg-accent hover:text-accent-foreground'"
title="Select messages"
@click="toggleBulkSelect"
>
<CheckSquare v-if="bulkSelectMode" class="size-4" />
<Square v-else class="size-4" />
</button>
<!-- Sort -->
<button
class="inline-flex h-9 w-9 items-center justify-center rounded-md text-muted-foreground hover:bg-accent hover:text-accent-foreground transition-colors"
:title="store.sortOrder === 'desc' ? 'Oldest first' : 'Newest first'"
@ -108,6 +274,7 @@ const performEmptyTrash = async () => {
>
<ArrowDownUp class="size-4" :class="store.sortOrder === 'asc' ? 'rotate-180' : ''" />
</button>
<TabsList class="inline-flex h-9 items-center gap-1 bg-transparent">
<TabsTrigger
value="all"
@ -146,6 +313,8 @@ const performEmptyTrash = async () => {
:message="msg"
:selected="store.currentMessage?.id === msg.id"
:folder-color="folderColor"
:bulk-select-mode="bulkSelectMode"
:is-checked="selectedIds.has(msg.id)"
@click="selectMessage(msg)"
/>
</TransitionGroup>
@ -184,6 +353,8 @@ const performEmptyTrash = async () => {
:message="msg"
:selected="store.currentMessage?.id === msg.id"
:folder-color="folderColor"
:bulk-select-mode="bulkSelectMode"
:is-checked="selectedIds.has(msg.id)"
@click="selectMessage(msg)"
/>
</TransitionGroup>
@ -222,6 +393,8 @@ const performEmptyTrash = async () => {
:message="msg"
:selected="store.currentMessage?.id === msg.id"
:folder-color="folderColor"
:bulk-select-mode="bulkSelectMode"
:is-checked="selectedIds.has(msg.id)"
@click="selectMessage(msg)"
/>
</TransitionGroup>

File diff suppressed because it is too large Load diff

File diff suppressed because one or more lines are too long

View file

@ -1,7 +1,7 @@
<script setup lang="ts">
import { computed } from 'vue'
import { formatDistanceToNow, format } from 'date-fns'
import { Paperclip, Star } from 'lucide-vue-next'
import { Paperclip, Star, Check } from 'lucide-vue-next'
import { TooltipRoot, TooltipTrigger, TooltipContent, TooltipPortal } from 'radix-vue'
import { cn } from '../../lib/utils'
import Badge from '../ui/Badge.vue'
@ -11,6 +11,8 @@ const props = defineProps({
message: { type: Object, required: true },
selected: { type: Boolean, default: false },
folderColor: { type: String, default: '' },
bulkSelectMode: { type: Boolean, default: false },
isChecked: { type: Boolean, default: false },
})
const initials = computed(() => {
@ -53,6 +55,15 @@ const recipientLabel = computed(() => {
)"
:style="folderColor ? `border-left: 3px solid ${folderColor}; border-radius: 12px 0 0 12px;` : ''"
>
<!-- Bulk select checkbox -->
<div
v-if="bulkSelectMode"
class="flex-shrink-0 h-5 w-5 rounded border-2 flex items-center justify-center mt-2 transition-all"
:class="isChecked ? 'bg-[#FBA612] border-[#FBA612]' : 'border-muted-foreground/50'"
>
<Check v-if="isChecked" class="size-3 text-white" />
</div>
<!-- Avatar -->
<div
class="flex-shrink-0 h-9 w-9 rounded-full flex items-center justify-center text-[13px] font-semibold text-white select-none mt-0.5"

View file

@ -1,7 +1,7 @@
/// <reference types="../../../node_modules/.vue-global-types/vue_3.5_0_0_0.d.ts" />
import { computed } from 'vue';
import { formatDistanceToNow, format } from 'date-fns';
import { Paperclip, Star } from 'lucide-vue-next';
import { Paperclip, Star, Check } from 'lucide-vue-next';
import { TooltipRoot, TooltipTrigger, TooltipContent, TooltipPortal } from 'radix-vue';
import { cn } from '../../lib/utils';
import Badge from '../ui/Badge.vue';
@ -10,6 +10,8 @@ const props = defineProps({
message: { type: Object, required: true },
selected: { type: Boolean, default: false },
folderColor: { type: String, default: '' },
bulkSelectMode: { type: Boolean, default: false },
isChecked: { type: Boolean, default: false },
});
const initials = computed(() => {
const name = props.message.from_name || props.message.from_address || '?';
@ -54,6 +56,23 @@ __VLS_asFunctionalElement(__VLS_intrinsicElements.button, __VLS_intrinsicElement
...{ class: (__VLS_ctx.cn('df-msg-item flex items-start gap-3 rounded-xl p-3 text-left text-sm w-full', __VLS_ctx.selected && 'df-msg-selected')) },
...{ style: (__VLS_ctx.folderColor ? `border-left: 3px solid ${__VLS_ctx.folderColor}; border-radius: 12px 0 0 12px;` : '') },
});
if (__VLS_ctx.bulkSelectMode) {
__VLS_asFunctionalElement(__VLS_intrinsicElements.div, __VLS_intrinsicElements.div)({
...{ class: "flex-shrink-0 h-5 w-5 rounded border-2 flex items-center justify-center mt-2 transition-all" },
...{ class: (__VLS_ctx.isChecked ? 'bg-[#FBA612] border-[#FBA612]' : 'border-muted-foreground/50') },
});
if (__VLS_ctx.isChecked) {
const __VLS_0 = {}.Check;
/** @type {[typeof __VLS_components.Check, ]} */ ;
// @ts-ignore
const __VLS_1 = __VLS_asFunctionalComponent(__VLS_0, new __VLS_0({
...{ class: "size-3 text-white" },
}));
const __VLS_2 = __VLS_1({
...{ class: "size-3 text-white" },
}, ...__VLS_functionalComponentArgsRest(__VLS_1));
}
}
__VLS_asFunctionalElement(__VLS_intrinsicElements.div, __VLS_intrinsicElements.div)({
...{ class: "flex-shrink-0 h-9 w-9 rounded-full flex items-center justify-center text-[13px] font-semibold text-white select-none mt-0.5" },
...{ style: {} },
@ -75,62 +94,62 @@ if (!__VLS_ctx.message.is_read) {
});
}
if (__VLS_ctx.message.is_starred) {
const __VLS_0 = {}.Star;
const __VLS_4 = {}.Star;
/** @type {[typeof __VLS_components.Star, ]} */ ;
// @ts-ignore
const __VLS_1 = __VLS_asFunctionalComponent(__VLS_0, new __VLS_0({
...{ class: "flex-shrink-0 size-3 fill-yellow-400 text-yellow-400" },
}));
const __VLS_2 = __VLS_1({
...{ class: "flex-shrink-0 size-3 fill-yellow-400 text-yellow-400" },
}, ...__VLS_functionalComponentArgsRest(__VLS_1));
}
if (__VLS_ctx.timestamp) {
const __VLS_4 = {}.TooltipRoot;
/** @type {[typeof __VLS_components.TooltipRoot, typeof __VLS_components.TooltipRoot, ]} */ ;
// @ts-ignore
const __VLS_5 = __VLS_asFunctionalComponent(__VLS_4, new __VLS_4({
delayDuration: (300),
...{ class: "flex-shrink-0 size-3 fill-yellow-400 text-yellow-400" },
}));
const __VLS_6 = __VLS_5({
delayDuration: (300),
...{ class: "flex-shrink-0 size-3 fill-yellow-400 text-yellow-400" },
}, ...__VLS_functionalComponentArgsRest(__VLS_5));
__VLS_7.slots.default;
const __VLS_8 = {}.TooltipTrigger;
/** @type {[typeof __VLS_components.TooltipTrigger, typeof __VLS_components.TooltipTrigger, ]} */ ;
}
if (__VLS_ctx.timestamp) {
const __VLS_8 = {}.TooltipRoot;
/** @type {[typeof __VLS_components.TooltipRoot, typeof __VLS_components.TooltipRoot, ]} */ ;
// @ts-ignore
const __VLS_9 = __VLS_asFunctionalComponent(__VLS_8, new __VLS_8({
asChild: true,
delayDuration: (300),
}));
const __VLS_10 = __VLS_9({
asChild: true,
delayDuration: (300),
}, ...__VLS_functionalComponentArgsRest(__VLS_9));
__VLS_11.slots.default;
const __VLS_12 = {}.TooltipTrigger;
/** @type {[typeof __VLS_components.TooltipTrigger, typeof __VLS_components.TooltipTrigger, ]} */ ;
// @ts-ignore
const __VLS_13 = __VLS_asFunctionalComponent(__VLS_12, new __VLS_12({
asChild: true,
}));
const __VLS_14 = __VLS_13({
asChild: true,
}, ...__VLS_functionalComponentArgsRest(__VLS_13));
__VLS_15.slots.default;
__VLS_asFunctionalElement(__VLS_intrinsicElements.div, __VLS_intrinsicElements.div)({
...{ class: (__VLS_ctx.cn('flex-shrink-0 text-xs cursor-default', __VLS_ctx.selected ? 'text-foreground' : 'text-muted-foreground')) },
});
(__VLS_ctx.relativeTime);
var __VLS_11;
const __VLS_12 = {}.TooltipPortal;
var __VLS_15;
const __VLS_16 = {}.TooltipPortal;
/** @type {[typeof __VLS_components.TooltipPortal, typeof __VLS_components.TooltipPortal, ]} */ ;
// @ts-ignore
const __VLS_13 = __VLS_asFunctionalComponent(__VLS_12, new __VLS_12({}));
const __VLS_14 = __VLS_13({}, ...__VLS_functionalComponentArgsRest(__VLS_13));
__VLS_15.slots.default;
const __VLS_16 = {}.TooltipContent;
const __VLS_17 = __VLS_asFunctionalComponent(__VLS_16, new __VLS_16({}));
const __VLS_18 = __VLS_17({}, ...__VLS_functionalComponentArgsRest(__VLS_17));
__VLS_19.slots.default;
const __VLS_20 = {}.TooltipContent;
/** @type {[typeof __VLS_components.TooltipContent, typeof __VLS_components.TooltipContent, ]} */ ;
// @ts-ignore
const __VLS_17 = __VLS_asFunctionalComponent(__VLS_16, new __VLS_16({
const __VLS_21 = __VLS_asFunctionalComponent(__VLS_20, new __VLS_20({
...{ class: "z-50 rounded-md border bg-popover px-3 py-1.5 text-xs text-popover-foreground shadow-md" },
}));
const __VLS_18 = __VLS_17({
const __VLS_22 = __VLS_21({
...{ class: "z-50 rounded-md border bg-popover px-3 py-1.5 text-xs text-popover-foreground shadow-md" },
}, ...__VLS_functionalComponentArgsRest(__VLS_17));
__VLS_19.slots.default;
}, ...__VLS_functionalComponentArgsRest(__VLS_21));
__VLS_23.slots.default;
(__VLS_ctx.exactTime);
var __VLS_23;
var __VLS_19;
var __VLS_15;
var __VLS_7;
var __VLS_11;
}
__VLS_asFunctionalElement(__VLS_intrinsicElements.div, __VLS_intrinsicElements.div)({
...{ class: "text-xs font-medium truncate" },
@ -146,27 +165,39 @@ if (__VLS_ctx.message.has_attachments) {
});
/** @type {[typeof Badge, typeof Badge, ]} */ ;
// @ts-ignore
const __VLS_20 = __VLS_asFunctionalComponent(Badge, new Badge({
const __VLS_24 = __VLS_asFunctionalComponent(Badge, new Badge({
variant: "secondary",
...{ class: "gap-1" },
}));
const __VLS_21 = __VLS_20({
variant: "secondary",
...{ class: "gap-1" },
}, ...__VLS_functionalComponentArgsRest(__VLS_20));
__VLS_22.slots.default;
const __VLS_23 = {}.Paperclip;
/** @type {[typeof __VLS_components.Paperclip, ]} */ ;
// @ts-ignore
const __VLS_24 = __VLS_asFunctionalComponent(__VLS_23, new __VLS_23({
...{ class: "size-3" },
}));
const __VLS_25 = __VLS_24({
...{ class: "size-3" },
variant: "secondary",
...{ class: "gap-1" },
}, ...__VLS_functionalComponentArgsRest(__VLS_24));
var __VLS_22;
__VLS_26.slots.default;
const __VLS_27 = {}.Paperclip;
/** @type {[typeof __VLS_components.Paperclip, ]} */ ;
// @ts-ignore
const __VLS_28 = __VLS_asFunctionalComponent(__VLS_27, new __VLS_27({
...{ class: "size-3" },
}));
const __VLS_29 = __VLS_28({
...{ class: "size-3" },
}, ...__VLS_functionalComponentArgsRest(__VLS_28));
var __VLS_26;
}
/** @type {__VLS_StyleScopedClasses['flex-shrink-0']} */ ;
/** @type {__VLS_StyleScopedClasses['h-5']} */ ;
/** @type {__VLS_StyleScopedClasses['w-5']} */ ;
/** @type {__VLS_StyleScopedClasses['rounded']} */ ;
/** @type {__VLS_StyleScopedClasses['border-2']} */ ;
/** @type {__VLS_StyleScopedClasses['flex']} */ ;
/** @type {__VLS_StyleScopedClasses['items-center']} */ ;
/** @type {__VLS_StyleScopedClasses['justify-center']} */ ;
/** @type {__VLS_StyleScopedClasses['mt-2']} */ ;
/** @type {__VLS_StyleScopedClasses['transition-all']} */ ;
/** @type {__VLS_StyleScopedClasses['size-3']} */ ;
/** @type {__VLS_StyleScopedClasses['text-white']} */ ;
/** @type {__VLS_StyleScopedClasses['flex-shrink-0']} */ ;
/** @type {__VLS_StyleScopedClasses['h-9']} */ ;
/** @type {__VLS_StyleScopedClasses['w-9']} */ ;
/** @type {__VLS_StyleScopedClasses['rounded-full']} */ ;
@ -224,6 +255,7 @@ const __VLS_self = (await import('vue')).defineComponent({
return {
Paperclip: Paperclip,
Star: Star,
Check: Check,
TooltipRoot: TooltipRoot,
TooltipTrigger: TooltipTrigger,
TooltipContent: TooltipContent,
@ -241,6 +273,8 @@ const __VLS_self = (await import('vue')).defineComponent({
message: { type: Object, required: true },
selected: { type: Boolean, default: false },
folderColor: { type: String, default: '' },
bulkSelectMode: { type: Boolean, default: false },
isChecked: { type: Boolean, default: false },
},
});
export default (await import('vue')).defineComponent({
@ -251,6 +285,8 @@ export default (await import('vue')).defineComponent({
message: { type: Object, required: true },
selected: { type: Boolean, default: false },
folderColor: { type: String, default: '' },
bulkSelectMode: { type: Boolean, default: false },
isChecked: { type: Boolean, default: false },
},
});
; /* PartiallyEnd: #4569/main.vue */

File diff suppressed because one or more lines are too long

View file

@ -23,7 +23,7 @@ const selectResult = (msg: any) => {
</script>
<template>
<div class="relative w-full px-4 py-2 border-b">
<div class="relative w-full px-4 py-2">
<input v-model="searchVal" type="search" placeholder="Search..." class="w-full rounded-md border border-input bg-background px-3 py-2 text-base focus:outline-none focus:ring-2 focus:ring-ring" style="font-size: 16px;" />
<div v-if="searchVal && results.length > 0" class="absolute left-0 right-0 top-full z-10 mt-1 max-h-[300px] overflow-y-auto rounded-md border bg-background p-1 shadow-md">
<div v-for="res in results" :key="res.id" @click="selectResult(res)" class="cursor-pointer rounded-sm px-2 py-1 text-sm hover:bg-accent">

View file

@ -22,12 +22,13 @@ const __VLS_ctx = {};
let __VLS_components;
let __VLS_directives;
__VLS_asFunctionalElement(__VLS_intrinsicElements.div, __VLS_intrinsicElements.div)({
...{ class: "relative w-full px-4 py-2 border-b" },
...{ class: "relative w-full px-4 py-2" },
});
__VLS_asFunctionalElement(__VLS_intrinsicElements.input)({
type: "search",
placeholder: "Search...",
...{ class: "w-full rounded-md border border-input bg-background px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-ring" },
...{ class: "w-full rounded-md border border-input bg-background px-3 py-2 text-base focus:outline-none focus:ring-2 focus:ring-ring" },
...{ style: {} },
});
(__VLS_ctx.searchVal);
if (__VLS_ctx.searchVal && __VLS_ctx.results.length > 0) {
@ -63,7 +64,6 @@ else if (__VLS_ctx.searchVal && !__VLS_ctx.loading) {
/** @type {__VLS_StyleScopedClasses['w-full']} */ ;
/** @type {__VLS_StyleScopedClasses['px-4']} */ ;
/** @type {__VLS_StyleScopedClasses['py-2']} */ ;
/** @type {__VLS_StyleScopedClasses['border-b']} */ ;
/** @type {__VLS_StyleScopedClasses['w-full']} */ ;
/** @type {__VLS_StyleScopedClasses['rounded-md']} */ ;
/** @type {__VLS_StyleScopedClasses['border']} */ ;
@ -71,7 +71,7 @@ else if (__VLS_ctx.searchVal && !__VLS_ctx.loading) {
/** @type {__VLS_StyleScopedClasses['bg-background']} */ ;
/** @type {__VLS_StyleScopedClasses['px-3']} */ ;
/** @type {__VLS_StyleScopedClasses['py-2']} */ ;
/** @type {__VLS_StyleScopedClasses['text-sm']} */ ;
/** @type {__VLS_StyleScopedClasses['text-base']} */ ;
/** @type {__VLS_StyleScopedClasses['focus:outline-none']} */ ;
/** @type {__VLS_StyleScopedClasses['focus:ring-2']} */ ;
/** @type {__VLS_StyleScopedClasses['focus:ring-ring']} */ ;

View file

@ -1 +1 @@
{"version":3,"file":"SearchBar.vue.js","sourceRoot":"","sources":["SearchBar.vue"],"names":[],"mappings":"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"}
{"version":3,"file":"SearchBar.vue.js","sourceRoot":"","sources":["SearchBar.vue"],"names":[],"mappings":"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"}

View file

@ -38,7 +38,7 @@ const store = useMailStore()
.fade-leave-to {
opacity: 0;
}
:global(.dark) .df-settings-dialog {
.dark .df-settings-dialog {
background: rgba(10, 20, 44, 0.90) !important;
border-color: rgba(255,255,255,0.08) !important;
}

View file

@ -611,3 +611,17 @@ function formatDate(iso: string | null) {
<p class="text-sm text-muted-foreground">Additional settings are managed in DockFlare Master.</p>
</div>
</template>
<style scoped>
.dark input,
.dark textarea,
.dark select {
background-color: hsl(var(--muted)) !important;
color: hsl(var(--foreground));
}
.dark input::placeholder,
.dark textarea::placeholder {
color: hsl(var(--muted-foreground));
opacity: 1;
}
</style>

View file

@ -268,6 +268,12 @@ debugger; /* PartiallyEnd: #3632/scriptSetup.vue */
const __VLS_ctx = {};
let __VLS_components;
let __VLS_directives;
/** @type {__VLS_StyleScopedClasses['dark']} */ ;
/** @type {__VLS_StyleScopedClasses['dark']} */ ;
/** @type {__VLS_StyleScopedClasses['dark']} */ ;
/** @type {__VLS_StyleScopedClasses['dark']} */ ;
// CSS variable injection
// CSS variable injection end
__VLS_asFunctionalElement(__VLS_intrinsicElements.div, __VLS_intrinsicElements.div)({
...{ class: "p-6" },
});

File diff suppressed because one or more lines are too long

View file

@ -3,7 +3,6 @@ import { ref, onMounted } from 'vue';
import { useRoute } from 'vue-router';
import { useAuth } from '../composables/useAuth';
import { authApi } from '../api/auth';
import Button from '../components/ui/Button.vue';
const route = useRoute();
const { login } = useAuth();
const email = ref('');
@ -54,12 +53,22 @@ debugger; /* PartiallyEnd: #3632/scriptSetup.vue */
const __VLS_ctx = {};
let __VLS_components;
let __VLS_directives;
/** @type {__VLS_StyleScopedClasses['df-login-card']} */ ;
/** @type {__VLS_StyleScopedClasses['dark']} */ ;
/** @type {__VLS_StyleScopedClasses['df-login-input']} */ ;
/** @type {__VLS_StyleScopedClasses['df-login-submit']} */ ;
/** @type {__VLS_StyleScopedClasses['df-login-sso']} */ ;
/** @type {__VLS_StyleScopedClasses['dark']} */ ;
/** @type {__VLS_StyleScopedClasses['df-login-sso']} */ ;
/** @type {__VLS_StyleScopedClasses['dark']} */ ;
/** @type {__VLS_StyleScopedClasses['df-login-sso']} */ ;
// CSS variable injection
// CSS variable injection end
__VLS_asFunctionalElement(__VLS_intrinsicElements.div, __VLS_intrinsicElements.div)({
...{ class: "flex h-screen w-screen items-center justify-center" },
});
__VLS_asFunctionalElement(__VLS_intrinsicElements.div, __VLS_intrinsicElements.div)({
...{ class: "w-full max-w-sm space-y-6 p-8" },
...{ style: {} },
...{ class: "df-login-card w-full max-w-sm space-y-6 p-8" },
});
__VLS_asFunctionalElement(__VLS_intrinsicElements.div, __VLS_intrinsicElements.div)({
...{ class: "flex flex-col space-y-1 text-center" },
@ -84,16 +93,14 @@ __VLS_asFunctionalElement(__VLS_intrinsicElements.input)({
type: "email",
placeholder: "you@example.com",
required: true,
...{ class: "w-full rounded-xl px-3 py-2 text-sm text-foreground placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-[rgba(251,166,18,0.4)]" },
...{ style: {} },
...{ class: "df-login-input w-full rounded-xl px-3 py-2 text-sm text-foreground placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-[rgba(251,166,18,0.4)]" },
});
(__VLS_ctx.email);
__VLS_asFunctionalElement(__VLS_intrinsicElements.input)({
type: "password",
placeholder: "Password",
required: true,
...{ class: "w-full rounded-xl px-3 py-2 text-sm text-foreground placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-[rgba(251,166,18,0.4)]" },
...{ style: {} },
...{ class: "df-login-input w-full rounded-xl px-3 py-2 text-sm text-foreground placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-[rgba(251,166,18,0.4)]" },
});
(__VLS_ctx.password);
if (__VLS_ctx.error) {
@ -102,58 +109,34 @@ if (__VLS_ctx.error) {
});
(__VLS_ctx.error);
}
/** @type {[typeof Button, typeof Button, ]} */ ;
// @ts-ignore
const __VLS_0 = __VLS_asFunctionalComponent(Button, new Button({
__VLS_asFunctionalElement(__VLS_intrinsicElements.button, __VLS_intrinsicElements.button)({
type: "submit",
...{ class: "w-full" },
...{ class: "df-login-submit w-full h-10 rounded-md text-sm font-semibold transition-all disabled:opacity-50" },
disabled: (__VLS_ctx.loading),
}));
const __VLS_1 = __VLS_0({
type: "submit",
...{ class: "w-full" },
disabled: (__VLS_ctx.loading),
}, ...__VLS_functionalComponentArgsRest(__VLS_0));
__VLS_2.slots.default;
});
(__VLS_ctx.loading ? 'Signing in…' : 'Sign in');
var __VLS_2;
__VLS_asFunctionalElement(__VLS_intrinsicElements.div, __VLS_intrinsicElements.div)({
...{ class: "flex items-center gap-2" },
});
__VLS_asFunctionalElement(__VLS_intrinsicElements.div)({
...{ class: "flex-1 border-t" },
...{ class: "flex-1 border-t border-border" },
});
__VLS_asFunctionalElement(__VLS_intrinsicElements.span, __VLS_intrinsicElements.span)({
...{ class: "text-xs text-muted-foreground" },
});
__VLS_asFunctionalElement(__VLS_intrinsicElements.div)({
...{ class: "flex-1 border-t" },
...{ class: "flex-1 border-t border-border" },
});
__VLS_asFunctionalElement(__VLS_intrinsicElements.button, __VLS_intrinsicElements.button)({
...{ onClick: (__VLS_ctx.redirectToMaster) },
...{ class: "df-login-sso w-full h-10 rounded-md text-sm font-medium transition-all" },
});
/** @type {[typeof Button, typeof Button, ]} */ ;
// @ts-ignore
const __VLS_3 = __VLS_asFunctionalComponent(Button, new Button({
...{ 'onClick': {} },
variant: "outline",
...{ class: "w-full" },
}));
const __VLS_4 = __VLS_3({
...{ 'onClick': {} },
variant: "outline",
...{ class: "w-full" },
}, ...__VLS_functionalComponentArgsRest(__VLS_3));
let __VLS_6;
let __VLS_7;
let __VLS_8;
const __VLS_9 = {
onClick: (__VLS_ctx.redirectToMaster)
};
__VLS_5.slots.default;
var __VLS_5;
/** @type {__VLS_StyleScopedClasses['flex']} */ ;
/** @type {__VLS_StyleScopedClasses['h-screen']} */ ;
/** @type {__VLS_StyleScopedClasses['w-screen']} */ ;
/** @type {__VLS_StyleScopedClasses['items-center']} */ ;
/** @type {__VLS_StyleScopedClasses['justify-center']} */ ;
/** @type {__VLS_StyleScopedClasses['df-login-card']} */ ;
/** @type {__VLS_StyleScopedClasses['w-full']} */ ;
/** @type {__VLS_StyleScopedClasses['max-w-sm']} */ ;
/** @type {__VLS_StyleScopedClasses['space-y-6']} */ ;
@ -174,6 +157,7 @@ var __VLS_5;
/** @type {__VLS_StyleScopedClasses['text-muted-foreground']} */ ;
/** @type {__VLS_StyleScopedClasses['mt-1']} */ ;
/** @type {__VLS_StyleScopedClasses['space-y-3']} */ ;
/** @type {__VLS_StyleScopedClasses['df-login-input']} */ ;
/** @type {__VLS_StyleScopedClasses['w-full']} */ ;
/** @type {__VLS_StyleScopedClasses['rounded-xl']} */ ;
/** @type {__VLS_StyleScopedClasses['px-3']} */ ;
@ -184,6 +168,7 @@ var __VLS_5;
/** @type {__VLS_StyleScopedClasses['focus:outline-none']} */ ;
/** @type {__VLS_StyleScopedClasses['focus:ring-2']} */ ;
/** @type {__VLS_StyleScopedClasses['focus:ring-[rgba(251,166,18,0.4)]']} */ ;
/** @type {__VLS_StyleScopedClasses['df-login-input']} */ ;
/** @type {__VLS_StyleScopedClasses['w-full']} */ ;
/** @type {__VLS_StyleScopedClasses['rounded-xl']} */ ;
/** @type {__VLS_StyleScopedClasses['px-3']} */ ;
@ -196,22 +181,36 @@ var __VLS_5;
/** @type {__VLS_StyleScopedClasses['focus:ring-[rgba(251,166,18,0.4)]']} */ ;
/** @type {__VLS_StyleScopedClasses['text-sm']} */ ;
/** @type {__VLS_StyleScopedClasses['text-destructive']} */ ;
/** @type {__VLS_StyleScopedClasses['df-login-submit']} */ ;
/** @type {__VLS_StyleScopedClasses['w-full']} */ ;
/** @type {__VLS_StyleScopedClasses['h-10']} */ ;
/** @type {__VLS_StyleScopedClasses['rounded-md']} */ ;
/** @type {__VLS_StyleScopedClasses['text-sm']} */ ;
/** @type {__VLS_StyleScopedClasses['font-semibold']} */ ;
/** @type {__VLS_StyleScopedClasses['transition-all']} */ ;
/** @type {__VLS_StyleScopedClasses['disabled:opacity-50']} */ ;
/** @type {__VLS_StyleScopedClasses['flex']} */ ;
/** @type {__VLS_StyleScopedClasses['items-center']} */ ;
/** @type {__VLS_StyleScopedClasses['gap-2']} */ ;
/** @type {__VLS_StyleScopedClasses['flex-1']} */ ;
/** @type {__VLS_StyleScopedClasses['border-t']} */ ;
/** @type {__VLS_StyleScopedClasses['border-border']} */ ;
/** @type {__VLS_StyleScopedClasses['text-xs']} */ ;
/** @type {__VLS_StyleScopedClasses['text-muted-foreground']} */ ;
/** @type {__VLS_StyleScopedClasses['flex-1']} */ ;
/** @type {__VLS_StyleScopedClasses['border-t']} */ ;
/** @type {__VLS_StyleScopedClasses['border-border']} */ ;
/** @type {__VLS_StyleScopedClasses['df-login-sso']} */ ;
/** @type {__VLS_StyleScopedClasses['w-full']} */ ;
/** @type {__VLS_StyleScopedClasses['h-10']} */ ;
/** @type {__VLS_StyleScopedClasses['rounded-md']} */ ;
/** @type {__VLS_StyleScopedClasses['text-sm']} */ ;
/** @type {__VLS_StyleScopedClasses['font-medium']} */ ;
/** @type {__VLS_StyleScopedClasses['transition-all']} */ ;
var __VLS_dollars;
const __VLS_self = (await import('vue')).defineComponent({
setup() {
return {
Button: Button,
email: email,
password: password,
error: error,

File diff suppressed because one or more lines are too long