mirror of
https://github.com/Tony0410/quietthanks.git
synced 2026-05-24 21:31:41 +08:00
- Remove redundant Save button, keep only Save & New - Add calendar view to timeline showing days with entries - Add search functionality with highlighted matches - Add date filtering by clicking calendar days - Show results count when filtering Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
70 lines
2.0 KiB
TypeScript
70 lines
2.0 KiB
TypeScript
"use client";
|
|
|
|
import Link from "next/link";
|
|
import { formatDate, isToday } from "@/lib/utils/date";
|
|
import { MoodIcon } from "./MoodSelector";
|
|
import { TagChips } from "./TagInput";
|
|
import type { EntryWithTags } from "@/lib/types";
|
|
|
|
interface EntryRowProps {
|
|
entry: EntryWithTags;
|
|
searchQuery?: string;
|
|
}
|
|
|
|
function highlightText(text: string, query: string): React.ReactNode {
|
|
if (!query.trim()) return text;
|
|
|
|
const regex = new RegExp(`(${query.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")})`, "gi");
|
|
const parts = text.split(regex);
|
|
|
|
return parts.map((part, i) =>
|
|
regex.test(part) ? (
|
|
<mark key={i} className="bg-accent/30 text-foreground rounded px-0.5">
|
|
{part}
|
|
</mark>
|
|
) : (
|
|
part
|
|
)
|
|
);
|
|
}
|
|
|
|
export function EntryRow({ entry, searchQuery = "" }: EntryRowProps) {
|
|
// Truncate text to one line preview
|
|
const preview = entry.text.length > 80 ? entry.text.slice(0, 80) + "..." : entry.text;
|
|
|
|
return (
|
|
<Link
|
|
href={`/entry/${entry.id}`}
|
|
className="block p-4 bg-surface border border-border rounded-xl hover:border-muted transition-colors"
|
|
>
|
|
<div className="flex items-start justify-between gap-3">
|
|
<div className="flex-1 min-w-0">
|
|
<div className="flex items-center gap-2 mb-1">
|
|
<span className="text-sm text-muted">
|
|
{isToday(entry.date) ? "Today" : formatDate(entry.date)}
|
|
</span>
|
|
{entry.roughDay ? (
|
|
<span className="text-xs px-2 py-0.5 bg-red-500/20 text-red-400 rounded">
|
|
rough day
|
|
</span>
|
|
) : null}
|
|
</div>
|
|
<p className="text-foreground truncate">
|
|
{highlightText(preview, searchQuery)}
|
|
</p>
|
|
{entry.tags.length > 0 && (
|
|
<div className="mt-2">
|
|
<TagChips tags={entry.tags} highlightQuery={searchQuery} />
|
|
</div>
|
|
)}
|
|
</div>
|
|
{entry.mood && (
|
|
<div className="text-xl">
|
|
<MoodIcon mood={entry.mood} />
|
|
</div>
|
|
)}
|
|
</div>
|
|
</Link>
|
|
);
|
|
}
|