fix: ebook reader UI - bookmark overlay, search panel, sidebar tabs

This commit is contained in:
neon
2026-04-13 23:01:55 -06:00
parent 9488e6c633
commit a94bfd21ea
3 changed files with 46 additions and 36 deletions
+17
View File
@@ -315,6 +315,12 @@ function closeSearch() {
</template>
</ReaderHeader>
<Transition name="bookmark-fade">
<div v-if="bookmarks.isCurrentCfiBookmarked.value" class="absolute left-8 z-30 pointer-events-none" aria-hidden="true">
<div class="w-7 h-14 bg-primary" style="clip-path: polygon(0 0, 100% 0, 100% 100%, 50% 80%, 0 100%)" />
</div>
</Transition>
<div class="absolute inset-0">
<div v-if="loading" class="absolute inset-0 flex items-center justify-center z-10 bg-background">
<div class="flex flex-col items-center gap-3">
@@ -401,3 +407,14 @@ function closeSearch() {
/>
</div>
</template>
<style scoped>
.bookmark-fade-enter-active,
.bookmark-fade-leave-active {
transition: opacity 0.2s ease;
}
.bookmark-fade-enter-from,
.bookmark-fade-leave-to {
opacity: 0;
}
</style>
@@ -1,6 +1,6 @@
<script setup lang="ts">
import { ref, watch } from 'vue'
import { Loader2, Search, X } from 'lucide-vue-next'
import { ChevronLeft, Loader2, Search, X } from 'lucide-vue-next'
import type { SearchResult } from '../composables/useSearch'
import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip'
@@ -40,8 +40,19 @@ function onClear() {
<template>
<div class="fixed inset-0 z-50 flex">
<div class="search-panel w-80 h-full bg-card text-card-foreground flex flex-col shadow-2xl border-r border-border" @click.stop>
<div class="flex items-center gap-2 px-4 py-3 border-b border-border shrink-0">
<Search :size="16" class="text-muted-foreground shrink-0" />
<div class="flex items-center gap-2 px-3 py-2.5 border-b border-border shrink-0">
<Tooltip>
<TooltipTrigger as-child>
<button
class="flex items-center justify-center w-7 h-7 rounded-md text-muted-foreground hover:text-foreground hover:bg-muted transition-colors shrink-0"
@click="emit('close')"
>
<ChevronLeft :size="18" />
</button>
</TooltipTrigger>
<TooltipContent>Close</TooltipContent>
</Tooltip>
<Search :size="15" class="text-muted-foreground shrink-0" />
<input
v-model="inputValue"
type="text"
@@ -56,17 +67,6 @@ function onClear() {
>
<X :size="14" />
</button>
<Tooltip>
<TooltipTrigger as-child>
<button
class="flex items-center justify-center w-7 h-7 rounded-md text-muted-foreground hover:text-foreground hover:bg-muted transition-colors shrink-0"
@click="emit('close')"
>
<X :size="16" />
</button>
</TooltipTrigger>
<TooltipContent>Close</TooltipContent>
</Tooltip>
</div>
<div class="flex-1 overflow-y-auto">
@@ -1,6 +1,6 @@
<script setup lang="ts">
import { ref } from 'vue'
import { Bookmark, BookOpen, Highlighter, Trash2, X } from 'lucide-vue-next'
import { Bookmark, BookOpen, Highlighter, Trash2 } from 'lucide-vue-next'
import type { TocItem } from '../composables/useToc'
import type { Bookmark as BookmarkType } from '../composables/useBookmarks'
import type { Annotation } from '../composables/useAnnotations'
@@ -31,28 +31,21 @@ const activeTab = ref<Tab>('chapters')
<template>
<div class="fixed inset-0 z-50 flex">
<div class="sidebar-panel w-80 h-full bg-card text-card-foreground flex flex-col shadow-2xl border-r border-border" @click.stop>
<div class="flex items-center justify-between px-4 py-3 border-b border-border shrink-0">
<div class="flex gap-1">
<button
v-for="tab in [
{ id: 'chapters', icon: BookOpen, label: 'Chapters' },
{ id: 'bookmarks', icon: Bookmark, label: 'Bookmarks' },
{ id: 'highlights', icon: Highlighter, label: 'Highlights' },
] as const"
:key="tab.id"
class="flex items-center gap-1.5 px-2.5 py-1.5 rounded-md text-xs font-medium transition-colors"
:class="activeTab === tab.id ? 'bg-primary text-primary-foreground' : 'text-muted-foreground hover:text-foreground hover:bg-muted'"
@click="activeTab = tab.id"
>
<component :is="tab.icon" :size="13" />
{{ tab.label }}
</button>
</div>
<div class="flex items-stretch border-b border-border shrink-0">
<button
class="flex items-center justify-center w-7 h-7 rounded-md text-muted-foreground hover:text-foreground hover:bg-muted transition-colors"
@click="emit('close')"
v-for="tab in [
{ id: 'chapters', icon: BookOpen, label: 'Chapters' },
{ id: 'bookmarks', icon: Bookmark, label: 'Bookmarks' },
{ id: 'highlights', icon: Highlighter, label: 'Highlights' },
] as const"
:key="tab.id"
class="flex-1 flex items-center justify-center gap-1.5 py-3 text-[13.5px] relative transition-colors"
:class="activeTab === tab.id ? 'text-primary' : 'text-muted-foreground hover:text-foreground'"
@click="activeTab = tab.id"
>
<X :size="16" />
<component :is="tab.icon" :size="16" />
{{ tab.label }}
<span v-if="activeTab === tab.id" class="absolute bottom-0 inset-x-0 h-0.5 bg-primary rounded-t-full" />
</button>
</div>
@@ -180,7 +173,7 @@ const TocList = defineComponent({
emit('toggleExpand', item.href)
},
},
[expanded ? h(ChevronDown as Component, { size: 14 }) : h(ChevronRight as Component, { size: 14 })],
[expanded ? h(ChevronDown as Component, { size: 14 }) : h(ChevronRight as Component, { size: 12 })],
)
: h('span', { class: 'w-3.5 shrink-0' }),
h('span', { class: 'truncate' }, item.label),