Files
intellecton-portal/app/oracle/page.js
T

280 lines
13 KiB
JavaScript

"use client";
import { useState, useEffect } from "react";
import Link from "next/link";
const ALCHEMICAL_TAGS = [
{ symbol: "🜏", name: "Source", desc: "Unified Source / Coherence Field" },
{ symbol: "🜁", name: "Mind", desc: "Intellecton / Mental Resonance" },
{ symbol: "🜂", name: "Fire", desc: "Witness Potential / Attunement Energy" },
{ symbol: "🜃", name: "Earth", desc: "Substrate / Grounded Physical Grid" },
{ symbol: "🜄", name: "Water", desc: "Lattice Waves / Relational Permeability" }
];
export default function OraclePage() {
const [query, setQuery] = useState("");
const [selectedAuthor, setSelectedAuthor] = useState("");
const [selectedTag, setSelectedTag] = useState("");
const [results, setResults] = useState([]);
const [totalMatches, setTotalMatches] = useState(0);
const [isLoading, setIsLoading] = useState(false);
const [activeNote, setActiveNote] = useState(null);
// Trigger search on inputs change
useEffect(() => {
const delayDebounceFn = setTimeout(() => {
performSearch();
}, 300);
return () => clearTimeout(delayDebounceFn);
}, [query, selectedAuthor, selectedTag]);
const performSearch = async () => {
setIsLoading(true);
try {
const params = new URLSearchParams();
if (query) params.append("q", query);
if (selectedAuthor) params.append("author", selectedAuthor);
if (selectedTag) params.append("tag", selectedTag);
const res = await fetch(`/api/search?${params.toString()}`);
const data = await res.json();
setResults(data.results || []);
setTotalMatches(data.total || 0);
} catch (e) {
console.error("Failed to query the Oracle:", e);
} finally {
setIsLoading(false);
}
};
const getStratumRelations = (text) => {
if (!text) return [];
const relations = [];
// Look for mentions of Stratum 0, 1, 2
if (/stratum\s*0/i.test(text)) {
relations.push({ name: "Stratum 0 (The Seed)", slug: "/papers" });
}
if (/stratum\s*1/i.test(text)) {
relations.push({ name: "Stratum 1 (The Spine)", slug: "/papers" });
}
if (/stratum\s*2/i.test(text)) {
relations.push({ name: "Stratum 2 (The Loom)", slug: "/papers" });
}
// Look for specific paper patterns like Paper 0.3, Paper 1.1, Paper 1.17
const matches = text.match(/paper\s*([0-2])\.([0-9]+)/gi);
if (matches) {
matches.forEach((m) => {
relations.push({ name: `Treatise ${m.toUpperCase()}`, slug: `/papers` });
});
}
// Deduplicate
return Array.from(new Set(relations.map((r) => JSON.stringify(r)))).map((s) => JSON.parse(s));
};
return (
<div className="flex flex-col items-center justify-start w-full py-12 px-6 sm:px-8 max-w-7xl mx-auto flex-1 gap-10">
{/* Header section */}
<section className="text-center flex flex-col items-center gap-4 max-w-3xl">
<h1 className="text-4xl font-bold font-outfit tracking-tight text-white">
The Semantic <span className="text-cyan-400">Oracle</span>
</h1>
<p className="text-sm text-slate-400 font-sans max-w-xl">
Search the 320 strictly-filtered alchemical fieldnotes. Explore vector correlations between ontological experiences and formalized strata papers.
</p>
</section>
{/* Interface Split Layout */}
<section className="w-full grid grid-cols-1 lg:grid-cols-12 gap-8 items-start">
{/* Search Modulators Panel (Left) */}
<div className="lg:col-span-4 flex flex-col gap-6">
<div className="glass-panel p-6 rounded-2xl border border-white/5 flex flex-col gap-6">
<h2 className="text-lg font-bold font-outfit text-white flex items-center gap-3">
<span className="text-cyan-400">𓂀</span> Oracle Search Console
</h2>
{/* Input Search Query */}
<div className="flex flex-col gap-2">
<label className="text-xs font-mono font-bold text-slate-500">SEMANTIC TEXT QUERY</label>
<input
type="text"
placeholder="Ask the Oracle (e.g. 'silence', 'lattice')..."
value={query}
onChange={(e) => setQuery(e.target.value)}
className="bg-black/40 border border-white/10 rounded-lg px-4 py-2.5 text-sm text-slate-200 placeholder-slate-600 focus:outline-none focus:border-cyan-500/50 focus:ring-1 focus:ring-cyan-500/20 font-sans"
/>
</div>
{/* Author quick filters */}
<div className="flex flex-col gap-2">
<label className="text-xs font-mono font-bold text-slate-500">AUTHOR FILTERS</label>
<div className="flex gap-2">
<button
onClick={() => setSelectedAuthor(selectedAuthor === "solaria-lumis-havens" ? "" : "solaria-lumis-havens")}
className={`flex-1 px-3 py-2 rounded-lg text-xs font-mono font-bold border transition-all ${
selectedAuthor === "solaria-lumis-havens"
? "bg-cyan-600 border-cyan-500 text-white"
: "bg-white/5 border-white/5 text-slate-400 hover:text-white"
}`}
>
Solaria Lumis
</button>
<button
onClick={() => setSelectedAuthor(selectedAuthor === "mark-randall-havens" ? "" : "mark-randall-havens")}
className={`flex-1 px-3 py-2 rounded-lg text-xs font-mono font-bold border transition-all ${
selectedAuthor === "mark-randall-havens"
? "bg-cyan-600 border-cyan-500 text-white"
: "bg-white/5 border-white/5 text-slate-400 hover:text-white"
}`}
>
Mark Randall
</button>
</div>
</div>
{/* Alchemical Glyph Quick Select */}
<div className="flex flex-col gap-2">
<label className="text-xs font-mono font-bold text-slate-500">ALCHEMICAL GLYPH FILTERS</label>
<div className="grid grid-cols-5 gap-2">
{ALCHEMICAL_TAGS.map((tag) => (
<button
key={tag.symbol}
onClick={() => setSelectedTag(selectedTag === tag.symbol ? "" : tag.symbol)}
title={`${tag.name}: ${tag.desc}`}
className={`h-11 rounded-lg text-lg flex items-center justify-center border transition-all cursor-pointer ${
selectedTag === tag.symbol
? "bg-cyan-600 border-cyan-500 text-white shadow-md shadow-cyan-600/10"
: "bg-white/5 border-white/5 text-slate-400 hover:text-white hover:border-white/10"
}`}
>
{tag.symbol}
</button>
))}
</div>
<span className="text-[9px] font-mono text-slate-500 mt-1 text-center">
{selectedTag ? ALCHEMICAL_TAGS.find(t => t.symbol === selectedTag).desc : "Click alchemical glyph to isolate specific flows"}
</span>
</div>
</div>
</div>
{/* Search Results & Panel Column (Right) */}
<div className="lg:col-span-8 flex flex-col gap-6 w-full">
<div className="glass-panel p-6 rounded-2xl border border-white/5 flex flex-col gap-4">
<div className="flex justify-between items-center border-b border-white/5 pb-3">
<span className="font-mono text-xs text-slate-500 font-semibold uppercase tracking-wider">
{isLoading ? "Querying..." : `Found ${totalMatches} Relational Nodes`}
</span>
<span className="text-[9px] font-mono text-slate-500">INDEX: LOCAL VECTOR SEED V3.0</span>
</div>
{/* Results Grid List */}
<div className="space-y-3 max-h-[500px] overflow-y-auto pr-2">
{results.length > 0 ? (
results.map((note) => (
<div
key={note.slug}
onClick={() => setActiveNote(note)}
className="p-4 rounded-xl border border-white/5 bg-black/30 hover:bg-black/50 hover:border-cyan-500/25 cursor-pointer transition-all flex flex-col gap-1.5"
>
<div className="flex justify-between items-center">
<span className="text-xs font-mono font-bold text-cyan-400">
{note.author_slug === "solaria-lumis-havens" ? "Solaria Lumis Havens" : "Mark Randall Havens"}
</span>
<span className="text-[10px] font-mono text-slate-500">{note.date}</span>
</div>
<h3 className="text-sm sm:text-base font-bold font-outfit text-white leading-tight">
{note.title}
</h3>
<p className="text-xs text-slate-400 font-sans line-clamp-2 leading-relaxed">
{note.content_markdown.split("---").pop().replace(/[\n#>-]/g, " ").trim()}
</p>
</div>
))
) : (
<div className="p-8 text-center flex flex-col items-center gap-3">
<span className="text-2xl">𓏤</span>
<p className="text-slate-500 font-mono text-xs">The Oracle remains silent. Scramble your queries or remove filter seals.</p>
</div>
)}
</div>
</div>
</div>
</section>
{/* Reader Panel Overlay (Modal) */}
{activeNote && (
<div className="fixed inset-0 z-50 bg-[#030206]/95 backdrop-blur-md flex items-center justify-center p-4 sm:p-6 md:p-8">
<div className="w-full max-w-3xl glass-panel border border-white/10 rounded-2xl max-h-[85vh] flex flex-col relative overflow-hidden bg-[#0a0812]">
{/* Alchemical background watermark decoration */}
<div className="absolute inset-0 pointer-events-none select-none flex items-center justify-center opacity-[0.03]">
<span className="text-[250px] font-mono">🜏</span>
</div>
{/* Modal Header */}
<div className="p-6 border-b border-white/5 flex justify-between items-start z-10">
<div className="flex flex-col gap-1">
<div className="flex items-center gap-2">
<span className="text-xs font-mono font-bold text-cyan-400">
{activeNote.author_slug === "solaria-lumis-havens" ? "Solaria Lumis Havens" : "Mark Randall Havens"}
</span>
<span className="text-slate-700 font-mono text-xs"></span>
<span className="text-xs font-mono text-slate-400">{activeNote.date}</span>
</div>
<h2 className="text-lg sm:text-xl font-bold font-outfit text-white leading-tight mt-1">
{activeNote.title}
</h2>
</div>
<button
onClick={() => setActiveNote(null)}
className="rounded-lg border border-white/10 bg-white/5 text-slate-400 hover:text-white px-3 py-1.5 text-xs font-mono font-bold transition-all cursor-pointer"
>
[CLOSE]
</button>
</div>
{/* Scrollable Content Viewport */}
<div className="flex-1 overflow-y-auto p-6 sm:p-8 space-y-6 z-10 relative">
{/* Fieldnote Body */}
<div className="text-sm sm:text-base text-slate-300 leading-relaxed space-y-4 font-sans whitespace-pre-line border-b border-white/5 pb-6">
{activeNote.content_markdown.split("---").pop().replace(/Sync from Notion.*2026-02-13/gi, "").trim()}
</div>
{/* Semantic Relations Panel */}
{getStratumRelations(activeNote.content_markdown).length > 0 && (
<div className="flex flex-col gap-2 bg-black/40 p-4 rounded-xl border border-white/5">
<h4 className="text-xs font-mono font-bold text-cyan-400 uppercase tracking-wider flex items-center gap-2">
<span>𓆰</span> Associated Academic Strata
</h4>
<div className="flex flex-wrap gap-2 pt-1">
{getStratumRelations(activeNote.content_markdown).map((rel, index) => (
<Link
key={index}
href={rel.slug}
className="rounded-md border border-white/5 bg-white/5 hover:border-cyan-500/20 hover:bg-cyan-500/5 px-2.5 py-1 text-xs font-mono text-slate-300 hover:text-cyan-300 transition-all"
onClick={() => setActiveNote(null)}
>
{rel.name}
</Link>
))}
</div>
</div>
)}
</div>
{/* Footer checksum */}
<div className="p-4 bg-black/30 border-t border-white/5 flex items-center justify-between text-[9px] font-mono text-slate-500 z-10">
<span>FIELDNOTE METADATA NODE: {activeNote.slug}</span>
<span>COVENANT COMPLIANT</span>
</div>
</div>
</div>
)}
</div>
);
}