Files
thoughtsync/frontend/src/components/NoteChecklist.vue
T
bvandeusenandClaude Opus 5 f5837cd985
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
frontend: hover-revealed controls stay put where hovering is impossible (task 2697)
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>
2026-08-16 16:36:58 -04:00

76 lines
2.3 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<script setup lang="ts">
import { ref } from "vue";
import { useNotesStore, type ChecklistItem } from "../stores/notes";
const props = defineProps<{ noteId: string; items: ChecklistItem[]; editable?: boolean }>();
const notes = useNotesStore();
const newItem = ref("");
async function addItem() {
const text = newItem.value.trim();
if (!text) return;
await notes.addItem(props.noteId, text);
newItem.value = "";
}
function toggle(item: ChecklistItem) {
void notes.updateItem(props.noteId, item.id, { checked: !item.checked });
}
function editText(item: ChecklistItem, value: string) {
if (value !== item.text) void notes.updateItem(props.noteId, item.id, { text: value });
}
function remove(item: ChecklistItem) {
void notes.deleteItem(props.noteId, item.id);
}
</script>
<template>
<div class="flex flex-col gap-1">
<div v-for="item in items" :key="item.id" class="group/item flex items-center gap-2">
<input
type="checkbox"
class="h-4 w-4 shrink-0 accent-brand"
:checked="item.checked"
@change="toggle(item)"
@click.stop
/>
<input
v-if="editable"
:value="item.text"
class="min-w-0 flex-1 bg-transparent text-sm outline-none"
:class="item.checked ? 'text-neutral-400 line-through' : ''"
@change="editText(item, ($event.target as HTMLInputElement).value)"
/>
<span
v-else
class="min-w-0 flex-1 truncate text-sm"
:class="item.checked ? 'text-neutral-400 line-through' : 'text-neutral-700 dark:text-neutral-300'"
>{{ item.text }}</span
>
<button
v-if="editable"
type="button"
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)"
>
×
</button>
</div>
<form v-if="editable" class="mt-1 flex items-center gap-2" @submit.prevent="addItem">
<span class="h-4 w-4 shrink-0" />
<input
v-model="newItem"
type="text"
placeholder="+ List item"
class="min-w-0 flex-1 bg-transparent text-sm outline-none placeholder:text-neutral-400"
/>
</form>
<p v-if="!editable && items.length === 0" class="text-sm italic text-neutral-400">Empty checklist</p>
</div>
</template>