feat: Kanban touch drag, admins delete backups, bigger share message
MindSift CI & Docker Release / Build, Test in Container & Push (push) Successful in 2m5s
MindSift CI & Docker Release / Build, Test in Container & Push (push) Successful in 2m5s
- Kanban on phones/tablets: hold a card, drag it onto a card or column, release; the page scrolls at the edges
- Admin settings: database backups can be deleted (DELETE /api/v1/admin/backups/{name})
- Share message: large Liste/Aufgabe buttons, close button, tap outside closes
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
da258fdce2
commit
f76b0f34ff
14 files changed
+371
-57
No files matched your search
@@ -49,52 +49,68 @@ export const SharedImportToast: React.FC<SharedImportToastProps> = ({ thoughtIds
|
||||
else setChoosingList(true);
|
||||
};
|
||||
|
||||
const chip =
|
||||
'h-9 px-3 inline-flex items-center gap-1.5 rounded-btn border border-border bg-canvas text-main text-xs font-medium active:bg-panel-elevated disabled:opacity-50 touch-manipulation';
|
||||
const big =
|
||||
'min-h-[52px] px-3 py-2 rounded-xl text-sm font-semibold flex items-center justify-center gap-2 touch-manipulation cursor-pointer active:scale-98 disabled:opacity-50';
|
||||
|
||||
return (
|
||||
<div
|
||||
role="status"
|
||||
className="fixed left-1/2 -translate-x-1/2 bottom-[calc(5.5rem+env(safe-area-inset-bottom))] sm:bottom-4 z-[60] w-[calc(100vw-1.5rem)] max-w-sm panel-surface shadow-panel overflow-hidden p-3 space-y-2.5 animate-in fade-in slide-in-from-bottom-2 duration-200"
|
||||
>
|
||||
<div className="flex items-center gap-2 text-sm text-main">
|
||||
<Inbox className="w-4 h-4 text-accent shrink-0" />
|
||||
<span className="flex-1 font-medium">
|
||||
{count === 1 ? 'Im Quick Dump abgelegt' : `${count} Einträge im Quick Dump abgelegt`}
|
||||
</span>
|
||||
<button type="button" onClick={onClose} aria-label="Schließen" className="h-7 w-7 -mr-1 flex items-center justify-center text-faint">
|
||||
<>
|
||||
{/* Tapping anywhere else closes it (transparent, the page stays visible) */}
|
||||
<div className="fixed inset-0 z-[59]" onClick={onClose} aria-hidden />
|
||||
<div
|
||||
role="status"
|
||||
className="fixed left-1/2 -translate-x-1/2 bottom-[calc(5.5rem+env(safe-area-inset-bottom))] sm:bottom-4 z-[60] w-[calc(100vw-1.5rem)] max-w-md panel-surface shadow-panel overflow-hidden p-4 space-y-3 animate-in fade-in slide-in-from-bottom-2 duration-200"
|
||||
>
|
||||
<button
|
||||
type="button"
|
||||
onClick={onClose}
|
||||
aria-label="Schließen"
|
||||
className="absolute top-2 right-2 h-8 w-8 flex items-center justify-center rounded-btn text-faint hover:text-main"
|
||||
>
|
||||
<X className="w-4 h-4" />
|
||||
</button>
|
||||
<div className="pr-8">
|
||||
<p className="flex items-center gap-2 text-base font-semibold text-main">
|
||||
<Inbox className="w-5 h-5 text-accent shrink-0" />
|
||||
{count === 1 ? 'Im Quick Dump abgelegt' : `${count} Einträge im Quick Dump abgelegt`}
|
||||
</p>
|
||||
<p className="text-xs text-muted mt-1">
|
||||
{choosingList ? 'Auf welche Liste?' : 'Oder gleich woanders hin:'}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{failed && <p className="text-xs text-status-err">Umwandeln hat nicht geklappt – der Eintrag bleibt im Quick Dump.</p>}
|
||||
|
||||
{!choosingList ? (
|
||||
<div className={`grid gap-2 ${writableLists.length > 0 ? 'grid-cols-2' : 'grid-cols-1'}`}>
|
||||
{writableLists.length > 0 && (
|
||||
<button type="button" disabled={busy} onClick={toList} className={`${big} bg-canvas border border-border text-main`}>
|
||||
<ShoppingCart className="w-4 h-4 text-accent" />
|
||||
<span>Liste</span>
|
||||
</button>
|
||||
)}
|
||||
<button type="button" disabled={busy} onClick={() => convert('task')} className={`${big} bg-accent text-on-accent`}>
|
||||
<CheckSquare className="w-4 h-4" />
|
||||
<span>Aufgabe</span>
|
||||
<ArrowRight className="w-4 h-4" />
|
||||
</button>
|
||||
</div>
|
||||
) : (
|
||||
<div className="grid grid-cols-2 gap-2">
|
||||
{writableLists.map((l) => (
|
||||
<button
|
||||
key={l.id}
|
||||
type="button"
|
||||
disabled={busy}
|
||||
onClick={() => convert('list_item', l)}
|
||||
className={`${big} bg-canvas border border-border text-main`}
|
||||
>
|
||||
<span>{l.icon}</span>
|
||||
<span className="truncate">{l.title}</span>
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{failed && <p className="text-xs text-status-err">Umwandeln hat nicht geklappt – der Eintrag bleibt im Quick Dump.</p>}
|
||||
|
||||
{!choosingList ? (
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="text-xs text-muted">Stattdessen</span>
|
||||
<button type="button" className={chip} disabled={busy} onClick={() => convert('task')}>
|
||||
<ArrowRight className="w-3.5 h-3.5 text-faint" />
|
||||
<CheckSquare className="w-3.5 h-3.5 text-accent" />
|
||||
Aufgabe
|
||||
</button>
|
||||
{writableLists.length > 0 && (
|
||||
<button type="button" className={chip} disabled={busy} onClick={toList}>
|
||||
<ArrowRight className="w-3.5 h-3.5 text-faint" />
|
||||
<ShoppingCart className="w-3.5 h-3.5 text-accent" />
|
||||
Liste
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
) : (
|
||||
<div className="flex flex-wrap items-center gap-2">
|
||||
{writableLists.map((l) => (
|
||||
<button key={l.id} type="button" className={chip} disabled={busy} onClick={() => convert('list_item', l)}>
|
||||
<span>{l.icon}</span>
|
||||
{l.title}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
Reference in new issue
Block a user