feat: add hub

This commit is contained in:
2026-10-03 23:57:41 +02:00
parent 5452f72087
commit fb7b560696
52 changed files with 290 additions and 162 deletions
@@ -1,15 +1,15 @@
<script setup lang="ts">
// "New", bottom right.
// "Neu", bottom right.
// The list opens with NotesDrawer (mobile) and NotesSidebarHandle (desktop).
const { creating, createAndOpen } = useNewNote()
</script>
<template>
<div class="pointer-events-none fixed inset-x-0 bottom-0 z-40 flex justify-end px-4 pb-[max(1rem,env(safe-area-inset-bottom))] md:px-6 md:pb-6">
<UTooltip text="New note" :kbds="['meta', 'alt', 'n']">
<UTooltip text="Neue Notiz" :kbds="['meta', 'alt', 'n']">
<UButton
icon="i-lucide-square-pen"
label="New"
label="Neu"
size="lg"
class="pointer-events-auto rounded-full px-5 shadow-lg"
:loading="creating"
+6 -2
View File
@@ -24,7 +24,7 @@ function onTouchMove(event: TouchEvent) {
<div class="md:hidden">
<button
type="button"
aria-label="Show notes"
aria-label="Notizen anzeigen"
class="fixed inset-x-0 top-0 z-30 flex h-7 touch-none items-start justify-center pt-2"
@click="drawerOpen = true"
@touchstart.passive="onTouchStart"
@@ -33,7 +33,11 @@ function onTouchMove(event: TouchEvent) {
<span class="h-1.5 w-12 rounded-full bg-accented" />
</button>
<UDrawer v-model:open="drawerOpen" direction="top" title="Notes" :ui="{ content: 'max-h-[85dvh]', body: 'overflow-y-auto p-0 sm:p-0' }">
<UDrawer v-model:open="drawerOpen" direction="top" title="Notizen" :ui="{ content: 'max-h-[85dvh]', body: 'overflow-y-auto p-0 sm:p-0', header: 'px-2' }">
<!-- In the title row, right aligned; the header is inset like the list's search bar (px-2), so they line up -->
<template #actions>
<AppHeaderActions />
</template>
<template #body>
<NotesList />
</template>
+9 -8
View File
@@ -14,20 +14,21 @@ const route = useRoute()
<UInput
v-model="query"
icon="i-lucide-search"
placeholder="Search"
placeholder="Suchen"
:loading="searching"
class="w-full"
@keydown.esc="query = ''"
>
<template v-if="query" #trailing>
<UButton icon="i-lucide-x" color="neutral" variant="link" size="sm" aria-label="Clear search" @click="query = ''" />
<UButton icon="i-lucide-x" color="neutral" variant="link" size="sm" aria-label="Suche leeren" @click="query = ''" />
</template>
</UInput>
</div>
<p v-if="error" class="px-4 text-sm text-error">Couldn't load the notes: {{ errorMessage(error) }}</p>
<p v-if="error" class="px-2 text-sm text-error md:px-4">Notizen konnten nicht geladen werden: {{ errorMessage(error) }}</p>
<nav class="px-2 pb-4">
<!-- On mobile the titles and trash icons line up with the search bar's edges (the highlight reaches past them) -->
<nav class="pb-4 md:px-2">
<!-- The delete button shows on hover on desktop (instead of the date), always on mobile -->
<div v-for="doc in docs" :key="doc.id" class="group relative">
<NuxtLink
@@ -44,15 +45,15 @@ const route = useRoute()
color="neutral"
variant="ghost"
size="sm"
:aria-label="`Delete ${notesDocName(doc)}`"
title="Delete"
class="absolute inset-y-0 end-1 my-auto h-fit text-dimmed hover:text-error md:opacity-0 md:group-hover:opacity-100 md:focus-visible:opacity-100"
:aria-label="`${notesDocName(doc)} löschen`"
title="Löschen"
class="absolute inset-y-0 end-0.5 my-auto md:end-1 h-fit text-dimmed hover:text-error md:opacity-0 md:group-hover:opacity-100 md:focus-visible:opacity-100"
@click="deleteDoc(doc)"
/>
</div>
<p v-if="!docs.length && !error && !searching" class="px-2 py-4 text-sm text-muted">
{{ query.trim() ? 'No notes match.' : 'No notes yet.' }}
{{ query.trim() ? 'Keine Notiz passt.' : 'Noch keine Notizen.' }}
</p>
</nav>
</div>
+4 -1
View File
@@ -5,7 +5,10 @@ const { open } = useNotesSidebar()
<template>
<aside v-show="open" class="hidden w-72 shrink-0 flex-col border-e border-default md:flex">
<h1 class="px-4 py-4 text-lg font-semibold text-highlighted">Notes</h1>
<div class="flex items-center gap-1 px-4 py-4">
<h1 class="me-auto text-lg font-semibold text-highlighted">Notizen</h1>
<AppHeaderActions />
</div>
<NotesList class="flex-1 overflow-y-auto" />
</aside>
</template>
@@ -9,8 +9,8 @@ const { open, toggle } = useNotesSidebar()
delete buttons), as wide as the note's side padding (md:px-10), so it never covers the text either -->
<button
type="button"
:title="`${open ? 'Hide' : 'Show'} notes (⌘E)`"
:aria-label="open ? 'Hide notes' : 'Show notes'"
:title="`Notizen ${open ? 'ausblenden' : 'anzeigen'} (⌘E)`"
:aria-label="open ? 'Notizen ausblenden' : 'Notizen anzeigen'"
class="group fixed inset-y-0 z-20 hidden w-10 cursor-pointer items-center focus:outline-none md:flex"
:class="open ? 'left-72' : 'left-0'"
@click="toggle"