mobile task add better view handling and fixed dup templates
This commit is contained in:
@@ -262,32 +262,31 @@ export const QuickEntry: Component = () => {
|
|||||||
<div class="absolute inset-0 bg-background/80 backdrop-blur-sm" onClick={() => setIsOpen(false)} />
|
<div class="absolute inset-0 bg-background/80 backdrop-blur-sm" onClick={() => setIsOpen(false)} />
|
||||||
|
|
||||||
<div class="relative w-full max-w-xl max-h-[100vh] md:max-h-[80vh] bg-card border border-border rounded-t-2xl md:rounded-2xl shadow-2xl overflow-hidden animate-in fade-in slide-in-from-bottom-4 md:zoom-in-95 duration-200 flex flex-col">
|
<div class="relative w-full max-w-xl max-h-[100vh] md:max-h-[80vh] bg-card border border-border rounded-t-2xl md:rounded-2xl shadow-2xl overflow-hidden animate-in fade-in slide-in-from-bottom-4 md:zoom-in-95 duration-200 flex flex-col">
|
||||||
<div class="flex items-center px-4 py-3 border-b border-border shrink-0">
|
{/* Scrollable content area - includes header so entire card can scroll on mobile */}
|
||||||
<Search class="text-muted-foreground mr-3" size={20} />
|
|
||||||
<TextField class="flex-1">
|
|
||||||
<TextFieldInput
|
|
||||||
id="quick-entry-input"
|
|
||||||
name="task-title"
|
|
||||||
ref={inputRef}
|
|
||||||
value={input()}
|
|
||||||
onInput={(e) => setInput(e.currentTarget.value)}
|
|
||||||
onKeyDown={(e) => e.key === "Enter" && parseAndAdd()}
|
|
||||||
placeholder="Task title... type /p1-10 for priority and /u1-10 for urgency"
|
|
||||||
class="border-none shadow-none focus-visible:ring-0 text-lg"
|
|
||||||
/>
|
|
||||||
</TextField>
|
|
||||||
<Button
|
|
||||||
size="icon"
|
|
||||||
variant="ghost"
|
|
||||||
onClick={() => setIsOpen(false)}
|
|
||||||
class="ml-2 md:hidden h-9 w-9 rounded-full text-muted-foreground hover:text-foreground hover:bg-muted"
|
|
||||||
>
|
|
||||||
<X size={20} />
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Scrollable content area */}
|
|
||||||
<div class="flex-1 overflow-y-auto overscroll-contain">
|
<div class="flex-1 overflow-y-auto overscroll-contain">
|
||||||
|
<div class="flex items-center px-4 py-3 border-b border-border sticky top-0 bg-card z-10">
|
||||||
|
<Search class="text-muted-foreground mr-3" size={20} />
|
||||||
|
<TextField class="flex-1">
|
||||||
|
<TextFieldInput
|
||||||
|
id="quick-entry-input"
|
||||||
|
name="task-title"
|
||||||
|
ref={inputRef}
|
||||||
|
value={input()}
|
||||||
|
onInput={(e) => setInput(e.currentTarget.value)}
|
||||||
|
onKeyDown={(e) => e.key === "Enter" && parseAndAdd()}
|
||||||
|
placeholder="Task title... type /p1-10 for priority and /u1-10 for urgency"
|
||||||
|
class="border-none shadow-none focus-visible:ring-0 text-lg"
|
||||||
|
/>
|
||||||
|
</TextField>
|
||||||
|
<Button
|
||||||
|
size="icon"
|
||||||
|
variant="ghost"
|
||||||
|
onClick={() => setIsOpen(false)}
|
||||||
|
class="ml-2 md:hidden h-9 w-9 rounded-full text-muted-foreground hover:text-foreground hover:bg-muted"
|
||||||
|
>
|
||||||
|
<X size={20} />
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
{/* Row 1: Priority, Size, Urgency */}
|
{/* Row 1: Priority, Size, Urgency */}
|
||||||
<div class="flex flex-col md:flex-row flex-wrap items-stretch md:items-center p-4 gap-4 border-b border-border bg-muted/10">
|
<div class="flex flex-col md:flex-row flex-wrap items-stretch md:items-center p-4 gap-4 border-b border-border bg-muted/10">
|
||||||
<div class="flex-1 min-w-0 md:min-w-[140px] space-y-1.5">
|
<div class="flex-1 min-w-0 md:min-w-[140px] space-y-1.5">
|
||||||
|
|||||||
+9
-1
@@ -371,6 +371,10 @@ export const subscribeToRealtime = async () => {
|
|||||||
// Check if it's a template
|
// Check if it's a template
|
||||||
const isTemplate = e.record.tags?.includes("__template__");
|
const isTemplate = e.record.tags?.includes("__template__");
|
||||||
if (isTemplate) {
|
if (isTemplate) {
|
||||||
|
// Check if template already exists (from optimistic update)
|
||||||
|
const templateExists = store.templates?.some(t => t.id === e.record.id);
|
||||||
|
if (templateExists) return;
|
||||||
|
|
||||||
let meta: any = {};
|
let meta: any = {};
|
||||||
try { meta = JSON.parse(e.record.content || "{}"); } catch (e) { }
|
try { meta = JSON.parse(e.record.content || "{}"); } catch (e) { }
|
||||||
const newTemplate: TaskTemplate = {
|
const newTemplate: TaskTemplate = {
|
||||||
@@ -1070,7 +1074,11 @@ export const addTemplate = async (template: Omit<TaskTemplate, "id">) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const newTemplate = { ...template, id: record.id };
|
const newTemplate = { ...template, id: record.id };
|
||||||
setStore("templates", (prev) => [...(prev || []), newTemplate]);
|
// Check if already added by realtime subscription
|
||||||
|
setStore("templates", (prev) => {
|
||||||
|
if (prev?.some(t => t.id === record.id)) return prev;
|
||||||
|
return [...(prev || []), newTemplate];
|
||||||
|
});
|
||||||
return newTemplate;
|
return newTemplate;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error("Failed to add template:", err);
|
console.error("Failed to add template:", err);
|
||||||
|
|||||||
Reference in New Issue
Block a user