feat: feed UI, in-app player, offline mode, settings

Adds an end-to-end integration test that runs the real pipeline against
live YouTube Atom feeds, verifying the merged feed is newest-first
across channels.
This commit is contained in:
vincent
2026-08-29 02:34:14 +02:00
parent a30423e4b5
commit e75d896933
16 changed files with 1059 additions and 2 deletions
+52
View File
@@ -0,0 +1,52 @@
import { fileUrl } from "../api";
import type { FeedItem } from "../types";
import { compactViews, relativeTime } from "./format";
interface Props {
item: FeedItem;
path: string;
onClose: () => void;
onDelete: () => void;
}
/**
* Plays the local file through Tauri's asset protocol. Every download is
* H.264/AAC in MP4 precisely so WKWebView can decode it natively.
*/
export default function Player({ item, path, onClose, onDelete }: Props) {
return (
<div className="fixed inset-0 z-50 bg-ink/97 flex flex-col">
<div className="flex items-center gap-3 px-5 py-3 border-b border-edge">
<button onClick={onClose}
className="rounded-full px-3 py-1.5 text-xs font-medium bg-surface hover:bg-raised cursor-pointer">
Back
</button>
<span className="text-sm text-muted truncate flex-1">{item.channel_title}</span>
<button onClick={onDelete}
className="rounded-full px-3 py-1.5 text-xs font-medium bg-surface text-muted
hover:bg-red-500/20 hover:text-red-300 cursor-pointer">
Delete download
</button>
</div>
<div className="flex-1 min-h-0 bg-black grid place-items-center">
<video key={path} src={fileUrl(path)} controls autoPlay
className="max-h-full max-w-full" />
</div>
<div className="px-5 py-4 max-h-56 overflow-y-auto border-t border-edge">
<h2 className="font-semibold text-lg leading-snug">{item.title}</h2>
<div className="mt-1 text-xs text-muted">
{[compactViews(item.views), relativeTime(item.published)]
.filter(Boolean)
.join(" · ")}
</div>
{item.description && (
<p className="mt-3 text-sm text-muted whitespace-pre-wrap leading-relaxed">
{item.description}
</p>
)}
</div>
</div>
);
}