auralynq-rag / web /components /IngestSources.tsx
asdfasdfqrqwer's picture
sync: bring the Space up to the current GitHub tree
656439d
Raw
History Blame Contribute Delete
3.79 kB
"use client";
import type { ReactNode } from "react";
import { Upload, Globe, FolderSync, Cloud, Mic, CheckCircle2 } from "lucide-react";
type Status = "available" | "planned";
interface SourceTile {
id: string;
label: string;
desc: string;
icon: ReactNode;
status: Status;
}
const TILES: SourceTile[] = [
{ id: "upload", label: "Upload files", desc: "PDF · DOCX · HTML · MD · TXT · audio", icon: <Upload className="h-4 w-4" />, status: "available" },
{ id: "voice", label: "Voice note", desc: "WAV · MP3 · M4A — transcribed + diarized", icon: <Mic className="h-4 w-4" />, status: "available" },
{ id: "url", label: "Web URL", desc: "Scrape + index a page", icon: <Globe className="h-4 w-4" />, status: "available" },
{ id: "folder", label: "Watch folder", desc: "Auto-reindex a local directory", icon: <FolderSync className="h-4 w-4" />, status: "available" },
{ id: "cloud", label: "Cloud connectors", desc: "Drive · Slack · Notion", icon: <Cloud className="h-4 w-4" />, status: "available" },
];
/**
* Ingest source tile-grid (Onyx pattern, adapted honestly to a local-first RAG):
* available sources are actionable; not-yet-built ones are shown as disabled
* "Planned" tiles — the same available/planned discipline the RAG strategy
* selector uses — rather than faking connectors that don't exist.
*/
export function IngestSources({ onUpload, onWebUrl }: { onUpload: () => void; onWebUrl?: () => void }) {
return (
<div>
<div className="mb-2 flex items-center justify-between">
<h3 className="text-sm font-semibold text-fg">Add a source</h3>
<span className="text-[10px] text-fg3">5 available</span>
</div>
<div className="grid grid-cols-2 gap-2">
{TILES.map((t) => {
const available = t.status === "available";
const Tag = available ? "button" : "div";
// folder → jump to the Watch Folder manager; url → open the URL input; others → upload.
const onClick =
t.id === "folder"
? () =>
document
.getElementById("watch-panel")
?.scrollIntoView({ behavior: "smooth", block: "start" })
: t.id === "url"
? onWebUrl ?? onUpload
: t.id === "cloud"
? () =>
document
.getElementById("connectors-panel")
?.scrollIntoView({ behavior: "smooth", block: "start" })
: onUpload;
return (
<Tag
key={t.id}
{...(available ? { type: "button" as const, onClick } : { "aria-disabled": true })}
className={`flex flex-col gap-1 rounded-xl border p-2.5 text-left transition ${
available
? "border-edge bg-panel2 hover:border-brand/50 hover:bg-panel"
: "cursor-not-allowed border-edge/60 bg-panel2/40 opacity-60"
}`}
>
<span className="flex items-center justify-between">
<span className={available ? "text-brand" : "text-fg3"}>{t.icon}</span>
{available ? (
<span className="inline-flex items-center gap-1 text-[10px] font-medium text-ok">
<CheckCircle2 className="h-3 w-3" aria-hidden /> Available
</span>
) : (
<span className="text-[10px] font-medium text-fg3">Planned</span>
)}
</span>
<span className="text-xs font-medium text-fg">{t.label}</span>
<span className="text-[10px] leading-snug text-fg3">{t.desc}</span>
</Tag>
);
})}
</div>
</div>
);
}