Added 'edited today' filter and task description previews
This commit is contained in:
@@ -15,7 +15,7 @@ export const FilterBar: Component = () => {
|
||||
|
||||
const hasActiveFilters = () => {
|
||||
const f = store.filter;
|
||||
return f.query !== "" || f.tags.length > 0 || f.priorityMin !== 1 || f.priorityMax !== 10 || f.urgencyMin !== 1 || f.urgencyMax !== 10;
|
||||
return f.query !== "" || f.tags.length > 0 || f.priorityMin !== 1 || f.priorityMax !== 10 || f.urgencyMin !== 1 || f.urgencyMax !== 10 || f.editedToday;
|
||||
};
|
||||
|
||||
const allTags = () => store.tagDefinitions.map(d => d.name).sort();
|
||||
@@ -44,10 +44,25 @@ export const FilterBar: Component = () => {
|
||||
<PopoverContent class="w-[calc(100vw-2rem)] sm:w-[480px] p-0 overflow-hidden bg-card border-border shadow-2xl rounded-2xl animate-in fade-in zoom-in-95 duration-200">
|
||||
{/* Header */}
|
||||
<div class="px-4 py-3 border-b border-border/50 bg-muted/20 flex items-center justify-between">
|
||||
<h3 class="text-xs font-bold uppercase tracking-widest text-muted-foreground flex items-center gap-2">
|
||||
<Search size={12} />
|
||||
Filters & Search
|
||||
</h3>
|
||||
<div class="flex items-center gap-4">
|
||||
<h3 class="text-xs font-bold uppercase tracking-widest text-muted-foreground flex items-center gap-2">
|
||||
<Search size={12} />
|
||||
Filters
|
||||
</h3>
|
||||
<div class="h-4 w-px bg-border/50" />
|
||||
<button
|
||||
onClick={() => setFilter({ editedToday: !store.filter.editedToday })}
|
||||
class={cn(
|
||||
"flex items-center gap-1.5 px-2 py-0.5 rounded-full text-[9px] font-black uppercase tracking-tight transition-all border",
|
||||
store.filter.editedToday
|
||||
? "bg-primary/10 text-primary border-primary/20"
|
||||
: "bg-muted/50 text-muted-foreground border-transparent hover:bg-muted"
|
||||
)}
|
||||
>
|
||||
<div class={cn("w-1.5 h-1.5 rounded-full", store.filter.editedToday ? "bg-primary" : "bg-muted-foreground/30")} />
|
||||
Edited Today
|
||||
</button>
|
||||
</div>
|
||||
<div class="flex items-center gap-2">
|
||||
<Show when={hasActiveFilters()}>
|
||||
<Button
|
||||
@@ -56,7 +71,7 @@ export const FilterBar: Component = () => {
|
||||
class="h-7 px-2 text-[10px] font-bold uppercase tracking-wider text-muted-foreground hover:text-destructive"
|
||||
onClick={clearFilter}
|
||||
>
|
||||
Clear All
|
||||
Clear
|
||||
</Button>
|
||||
</Show>
|
||||
<Button
|
||||
@@ -70,7 +85,7 @@ export const FilterBar: Component = () => {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Controls Grid */}
|
||||
{/* Controls */}
|
||||
<div class="p-4 space-y-6">
|
||||
{/* Search Input */}
|
||||
<div class="space-y-2">
|
||||
|
||||
@@ -50,6 +50,27 @@ export const TaskCard: Component<{ task: Task }> = (props) => {
|
||||
)}>
|
||||
{props.task.title}
|
||||
</h3>
|
||||
{props.task.content && (
|
||||
<div class="text-[11px] sm:text-xs text-muted-foreground/60 line-clamp-1 mt-1 leading-tight whitespace-pre">
|
||||
{(() => {
|
||||
let html = props.task.content || "";
|
||||
// Replace block tags with newlines first to preserve structure
|
||||
html = html.replace(/<\/p>/gi, '\n')
|
||||
.replace(/<\/div>/gi, '\n')
|
||||
.replace(/<br\s*\/?>/gi, '\n')
|
||||
.replace(/<\/li>/gi, '\n')
|
||||
.replace(/<\/h[1-6]>/gi, '\n');
|
||||
|
||||
const tmp = document.createElement("DIV");
|
||||
tmp.innerHTML = html;
|
||||
const text = tmp.textContent || tmp.innerText || "";
|
||||
|
||||
// Replace newlines (and surrounding whitespace) with a wide gap
|
||||
// Using 5 non-breaking spaces worth of visual space
|
||||
return text.trim().replace(/\s*[\r\n]+\s*/g, ' ');
|
||||
})()}
|
||||
</div>
|
||||
)}
|
||||
<div class="flex flex-wrap items-center gap-x-3 gap-y-1.5 mt-1 min-w-0">
|
||||
{/* Priority */}
|
||||
<div class="flex items-center gap-1.5 shrink-0">
|
||||
|
||||
@@ -92,7 +92,7 @@ export const TaskEditor: Component<TaskEditorProps> = (props) => {
|
||||
return (
|
||||
<div
|
||||
ref={editorRef}
|
||||
class="w-full h-full cursor-text"
|
||||
class="w-full cursor-text"
|
||||
onClick={() => editor()?.chain().focus().run()}
|
||||
/>
|
||||
);
|
||||
|
||||
+12
-2
@@ -58,6 +58,7 @@ export interface Filter {
|
||||
priorityMax: number;
|
||||
urgencyMin: number;
|
||||
urgencyMax: number;
|
||||
editedToday: boolean;
|
||||
}
|
||||
|
||||
interface TaskStore {
|
||||
@@ -85,7 +86,8 @@ export const [store, setStore] = createStore<TaskStore>({
|
||||
priorityMin: 1,
|
||||
priorityMax: 10,
|
||||
urgencyMin: 1,
|
||||
urgencyMax: 10
|
||||
urgencyMax: 10,
|
||||
editedToday: false
|
||||
}
|
||||
});
|
||||
|
||||
@@ -128,6 +130,13 @@ export const matchesFilter = (task: Task) => {
|
||||
const urgency = calculateUrgencyFromDate(task.dueDate);
|
||||
if (urgency < f.urgencyMin || urgency > f.urgencyMax) return false;
|
||||
|
||||
// Edited Today
|
||||
if (f.editedToday) {
|
||||
const today = new Date().toISOString().split('T')[0];
|
||||
const updated = new Date(task.updated).toISOString().split('T')[0];
|
||||
if (today !== updated) return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
@@ -732,7 +741,8 @@ export const clearFilter = () => {
|
||||
priorityMin: 1,
|
||||
priorityMax: 10,
|
||||
urgencyMin: 1,
|
||||
urgencyMax: 10
|
||||
urgencyMax: 10,
|
||||
editedToday: false
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user