frontend: hover-revealed controls stay put where hovering is impossible (task 2697)
CI & Build / Python lint (push) Successful in 2s
CI & Build / TypeScript typecheck (push) Successful in 6s
CI & Build / Python tests (push) Successful in 10s
CI & Build / Build & push image (push) Successful in 29s
Desktop (Tauri) / Tauri desktop (Linux) (push) Canceled after 2m36s
Desktop (Tauri) / Windows installer (cross-compiled) (push) Canceled after 2m36s
Desktop (Tauri) / Update manifest (push) Canceled after 0s
CI & Build / Python lint (push) Successful in 2s
CI & Build / TypeScript typecheck (push) Successful in 6s
CI & Build / Python tests (push) Successful in 10s
CI & Build / Build & push image (push) Successful in 29s
Desktop (Tauri) / Tauri desktop (Linux) (push) Canceled after 2m36s
Desktop (Tauri) / Windows installer (cross-compiled) (push) Canceled after 2m36s
Desktop (Tauri) / Update manifest (push) Canceled after 0s
A finger cannot hover, and on a note card the hover toolbar is the only way to pin, colour or archive — so on a phone those notes could not be acted on at all. Same for deleting a checklist item, a saved view, an attachment or a preview. Marked rather than rewritten inline: one `.hover-reveal` class on the five elements and a single rule that says what it is for. The `group-hover:` reveal stays in the markup because the trigger differs per component (named groups); only the fallback is shared. `@media (hover: none)` asks the device directly, which is more honest than inferring from viewport width — a narrow window on a laptop still hovers, and a large tablet still doesn't. It sits after the Tailwind directives so it beats the opacity-0/pointer-events-none utilities on source order without !important. Tap targets follow the same shape: p-1.5 around an 18px icon lands near 30px, which is fine for a cursor and too small for a thumb. Bumped to 44px on coarse pointers only, so desktop chrome doesn't inflate. The drag grip is deliberately NOT revealed yet. Reordering still uses HTML5 drag-and-drop, which never fires from touch, so showing the handle would only promise something that does nothing. It comes with the pointer-events rewrite. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -388,7 +388,7 @@ async function signOut() {
|
||||
<span class="flex-1 truncate">{{ f.name }}</span>
|
||||
<button
|
||||
type="button"
|
||||
class="text-neutral-400 opacity-0 hover:text-red-500 group-hover/view:opacity-100"
|
||||
class="hover-reveal text-neutral-400 opacity-0 hover:text-red-500 group-hover/view:opacity-100"
|
||||
:aria-label="`Delete view ${f.name}`"
|
||||
@click.prevent.stop="removeView(f)"
|
||||
>
|
||||
|
||||
@@ -36,7 +36,7 @@ defineEmits<{ (e: "remove"): void }>();
|
||||
<button
|
||||
v-if="removable"
|
||||
type="button"
|
||||
class="absolute right-1 top-1 rounded-full bg-black/50 px-1.5 text-white opacity-0 transition group-hover/lp:opacity-100"
|
||||
class="hover-reveal absolute right-1 top-1 rounded-full bg-black/50 px-1.5 text-white opacity-0 transition group-hover/lp:opacity-100"
|
||||
aria-label="Remove preview"
|
||||
@click="$emit('remove')"
|
||||
>
|
||||
|
||||
@@ -277,9 +277,11 @@ onBeforeUnmount(() => document.removeEventListener("mousedown", onDocMousedown))
|
||||
<!-- Toolbar overlays the card's top-right on hover/focus as a floating pill
|
||||
(window-control style) instead of reserving a permanent row — so at rest
|
||||
the card is content-sized with even padding, not text pinned to the top
|
||||
above an empty strip. -->
|
||||
above an empty strip.
|
||||
`hover-reveal`: on a device that can't hover this is the ONLY way to pin,
|
||||
colour or archive a note, so there it stays visible (see style.css). -->
|
||||
<div
|
||||
class="pointer-events-none absolute right-1.5 top-1.5 flex items-center gap-0.5 rounded-full bg-white/85 p-0.5 opacity-0 shadow-sm ring-1 ring-black/5 backdrop-blur-sm transition focus-within:pointer-events-auto focus-within:opacity-100 group-hover:pointer-events-auto group-hover:opacity-100 dark:bg-neutral-900/85 dark:ring-white/10"
|
||||
class="hover-reveal pointer-events-none absolute right-1.5 top-1.5 flex items-center gap-0.5 rounded-full bg-white/85 p-0.5 opacity-0 shadow-sm ring-1 ring-black/5 backdrop-blur-sm transition focus-within:pointer-events-auto focus-within:opacity-100 group-hover:pointer-events-auto group-hover:opacity-100 dark:bg-neutral-900/85 dark:ring-white/10"
|
||||
>
|
||||
<template v-if="note.trashed">
|
||||
<button type="button" class="icon-btn" title="Restore" aria-label="Restore" @click="notes.restore(note.id)">
|
||||
|
||||
@@ -52,7 +52,7 @@ function remove(item: ChecklistItem) {
|
||||
<button
|
||||
v-if="editable"
|
||||
type="button"
|
||||
class="text-neutral-300 opacity-0 hover:text-neutral-600 group-hover/item:opacity-100 dark:hover:text-neutral-200"
|
||||
class="hover-reveal text-neutral-300 opacity-0 hover:text-neutral-600 group-hover/item:opacity-100 dark:hover:text-neutral-200"
|
||||
aria-label="Delete item"
|
||||
@click="remove(item)"
|
||||
>
|
||||
|
||||
@@ -558,7 +558,7 @@ function revPreview(rev: NoteRevision): string {
|
||||
<img :src="att.url" alt="" loading="lazy" decoding="async" class="h-24 w-24 rounded-lg object-cover" />
|
||||
<button
|
||||
type="button"
|
||||
class="absolute right-1 top-1 rounded-full bg-black/50 px-1.5 text-white opacity-0 transition group-hover/att:opacity-100"
|
||||
class="hover-reveal absolute right-1 top-1 rounded-full bg-black/50 px-1.5 text-white opacity-0 transition group-hover/att:opacity-100"
|
||||
aria-label="Remove attachment"
|
||||
@click="notes.deleteAttachment(liveNote.id, att.id)"
|
||||
>
|
||||
|
||||
Reference in New Issue
Block a user