From 6f3a0cc3d2a7b3bbe00424218240ffef0b19d4fa Mon Sep 17 00:00:00 2001 From: jlightner Date: Sat, 4 Apr 2026 13:58:33 +0000 Subject: [PATCH] =?UTF-8?q?feat:=20Built=20CreatorTransparency=20page=20wi?= =?UTF-8?q?th=20four=20collapsible=20sections,=20AP=E2=80=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - "frontend/src/api/creator-transparency.ts" - "frontend/src/pages/CreatorTransparency.tsx" - "frontend/src/pages/CreatorTransparency.module.css" - "frontend/src/App.tsx" - "frontend/src/pages/CreatorDashboard.tsx" GSD-Task: S05/T02 --- .gsd/milestones/M025/slices/S05/S05-PLAN.md | 2 +- .../M025/slices/S05/tasks/T01-VERIFY.json | 16 + .../M025/slices/S05/tasks/T02-SUMMARY.md | 85 ++++ frontend/src/App.tsx | 2 + frontend/src/api/creator-transparency.ts | 51 +++ frontend/src/pages/CreatorDashboard.tsx | 7 + .../src/pages/CreatorTransparency.module.css | 332 +++++++++++++++ frontend/src/pages/CreatorTransparency.tsx | 399 ++++++++++++++++++ frontend/tsconfig.app.tsbuildinfo | 2 +- 9 files changed, 894 insertions(+), 2 deletions(-) create mode 100644 .gsd/milestones/M025/slices/S05/tasks/T01-VERIFY.json create mode 100644 .gsd/milestones/M025/slices/S05/tasks/T02-SUMMARY.md create mode 100644 frontend/src/api/creator-transparency.ts create mode 100644 frontend/src/pages/CreatorTransparency.module.css create mode 100644 frontend/src/pages/CreatorTransparency.tsx diff --git a/.gsd/milestones/M025/slices/S05/S05-PLAN.md b/.gsd/milestones/M025/slices/S05/S05-PLAN.md index 38a3114..8b93d2e 100644 --- a/.gsd/milestones/M025/slices/S05/S05-PLAN.md +++ b/.gsd/milestones/M025/slices/S05/S05-PLAN.md @@ -37,7 +37,7 @@ - Estimate: 45m - Files: backend/schemas.py, backend/routers/creator_dashboard.py - Verify: docker exec chrysopedia-api python -c "from routers.creator_dashboard import router; from schemas import CreatorTransparencyResponse" && echo 'OK' -- [ ] **T02: Build transparency page with collapsible sections and wire into creator dashboard** — Create the CreatorTransparency page component with four collapsible sections (Technique Pages, Key Moments, Cross-References, Source Videos), an API client function, route registration in App.tsx, and a sidebar nav link. +- [x] **T02: Built CreatorTransparency page with four collapsible sections, API client, route, and sidebar nav link** — Create the CreatorTransparency page component with four collapsible sections (Technique Pages, Key Moments, Cross-References, Source Videos), an API client function, route registration in App.tsx, and a sidebar nav link. ## Steps diff --git a/.gsd/milestones/M025/slices/S05/tasks/T01-VERIFY.json b/.gsd/milestones/M025/slices/S05/tasks/T01-VERIFY.json new file mode 100644 index 0000000..c503b8b --- /dev/null +++ b/.gsd/milestones/M025/slices/S05/tasks/T01-VERIFY.json @@ -0,0 +1,16 @@ +{ + "schemaVersion": 1, + "taskId": "T01", + "unitId": "M025/S05/T01", + "timestamp": 1775310913898, + "passed": true, + "discoverySource": "task-plan", + "checks": [ + { + "command": "echo 'OK'", + "exitCode": 0, + "durationMs": 9, + "verdict": "pass" + } + ] +} diff --git a/.gsd/milestones/M025/slices/S05/tasks/T02-SUMMARY.md b/.gsd/milestones/M025/slices/S05/tasks/T02-SUMMARY.md new file mode 100644 index 0000000..1d896c9 --- /dev/null +++ b/.gsd/milestones/M025/slices/S05/tasks/T02-SUMMARY.md @@ -0,0 +1,85 @@ +--- +id: T02 +parent: S05 +milestone: M025 +provides: [] +requires: [] +affects: [] +key_files: ["frontend/src/api/creator-transparency.ts", "frontend/src/pages/CreatorTransparency.tsx", "frontend/src/pages/CreatorTransparency.module.css", "frontend/src/App.tsx", "frontend/src/pages/CreatorDashboard.tsx"] +key_decisions: ["Used CSS grid-template-rows 0fr/1fr for smooth collapsible section animation", "Grouped key moments by source video filename for scannability"] +patterns_established: [] +drill_down_paths: [] +observability_surfaces: [] +duration: "" +verification_result: "Frontend build passes with zero TypeScript errors. grep confirms route registered in App.tsx and sidebar link added in CreatorDashboard.tsx." +completed_at: 2026-04-04T13:58:28.416Z +blocker_discovered: false +--- + +# T02: Built CreatorTransparency page with four collapsible sections, API client, route, and sidebar nav link + +> Built CreatorTransparency page with four collapsible sections, API client, route, and sidebar nav link + +## What Happened +--- +id: T02 +parent: S05 +milestone: M025 +key_files: + - frontend/src/api/creator-transparency.ts + - frontend/src/pages/CreatorTransparency.tsx + - frontend/src/pages/CreatorTransparency.module.css + - frontend/src/App.tsx + - frontend/src/pages/CreatorDashboard.tsx +key_decisions: + - Used CSS grid-template-rows 0fr/1fr for smooth collapsible section animation + - Grouped key moments by source video filename for scannability +duration: "" +verification_result: passed +completed_at: 2026-04-04T13:58:28.416Z +blocker_discovered: false +--- + +# T02: Built CreatorTransparency page with four collapsible sections, API client, route, and sidebar nav link + +**Built CreatorTransparency page with four collapsible sections, API client, route, and sidebar nav link** + +## What Happened + +Created the API client with TypeScript interfaces matching all backend Transparency schemas. Built the CreatorTransparency page with tag summary bar, four collapsible sections (Technique Pages, Key Moments grouped by video, Cross-References, Source Videos) using CSS grid-template-rows animation. Added route at /creator/transparency with ProtectedRoute wrapper and Transparency NavLink in the sidebar between Tiers and Posts. + +## Verification + +Frontend build passes with zero TypeScript errors. grep confirms route registered in App.tsx and sidebar link added in CreatorDashboard.tsx. + +## Verification Evidence + +| # | Command | Exit Code | Verdict | Duration | +|---|---------|-----------|---------|----------| +| 1 | `cd frontend && npm run build` | 0 | ✅ pass | 7100ms | +| 2 | `grep -q 'transparency' frontend/src/App.tsx` | 0 | ✅ pass | 10ms | +| 3 | `grep -q 'Transparency' frontend/src/pages/CreatorDashboard.tsx` | 0 | ✅ pass | 10ms | + + +## Deviations + +None. + +## Known Issues + +None. + +## Files Created/Modified + +- `frontend/src/api/creator-transparency.ts` +- `frontend/src/pages/CreatorTransparency.tsx` +- `frontend/src/pages/CreatorTransparency.module.css` +- `frontend/src/App.tsx` +- `frontend/src/pages/CreatorDashboard.tsx` + + +## Deviations +None. + +## Known Issues +None. diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index 4b5b3bc..9205b29 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -31,6 +31,7 @@ const PostsList = React.lazy(() => import("./pages/PostsList")); const ShortPlayer = React.lazy(() => import("./pages/ShortPlayer")); const EmbedPlayer = React.lazy(() => import("./pages/EmbedPlayer")); const CreatorOnboarding = React.lazy(() => import("./pages/CreatorOnboarding")); +const CreatorTransparency = React.lazy(() => import("./pages/CreatorTransparency")); import AdminDropdown from "./components/AdminDropdown"; import ImpersonationBanner from "./components/ImpersonationBanner"; import AppFooter from "./components/AppFooter"; @@ -216,6 +217,7 @@ function AppShell() { }>} /> }>} /> }>} /> + }>} /> }>} /> }>} /> }>} /> diff --git a/frontend/src/api/creator-transparency.ts b/frontend/src/api/creator-transparency.ts new file mode 100644 index 0000000..15fa6ef --- /dev/null +++ b/frontend/src/api/creator-transparency.ts @@ -0,0 +1,51 @@ +import { request, BASE } from "./client"; + +// ── Types ──────────────────────────────────────────────────────────────────── + +export interface TransparencyTechnique { + title: string; + slug: string; + topic_category: string; + topic_tags: string[]; + summary: string; + created_at: string; + key_moment_count: number; +} + +export interface TransparencyKeyMoment { + title: string; + summary: string; + content_type: string; + start_time: number; + end_time: number; + source_video_filename: string; + technique_page_title: string | null; +} + +export interface TransparencyRelationship { + relationship_type: string; + source_page_title: string; + source_page_slug: string; + target_page_title: string; + target_page_slug: string; +} + +export interface TransparencySourceVideo { + filename: string; + processing_status: string; + created_at: string; +} + +export interface CreatorTransparencyResponse { + techniques: TransparencyTechnique[]; + key_moments: TransparencyKeyMoment[]; + relationships: TransparencyRelationship[]; + source_videos: TransparencySourceVideo[]; + tags: string[]; +} + +// ── Functions ──────────────────────────────────────────────────────────────── + +export async function fetchCreatorTransparency(): Promise { + return request(`${BASE}/creator/transparency`); +} diff --git a/frontend/src/pages/CreatorDashboard.tsx b/frontend/src/pages/CreatorDashboard.tsx index a041f6b..54586b6 100644 --- a/frontend/src/pages/CreatorDashboard.tsx +++ b/frontend/src/pages/CreatorDashboard.tsx @@ -59,6 +59,13 @@ function SidebarNav() { Tiers + + + + + + Transparency + diff --git a/frontend/src/pages/CreatorTransparency.module.css b/frontend/src/pages/CreatorTransparency.module.css new file mode 100644 index 0000000..9df93e7 --- /dev/null +++ b/frontend/src/pages/CreatorTransparency.module.css @@ -0,0 +1,332 @@ +/* ── Page layout (reuses sidebar from CreatorDashboard) ─────────────────── */ + +.layout { + display: flex; + gap: 0; + min-height: 60vh; +} + +.content { + flex: 1; + min-width: 0; + padding: 2rem; +} + +.pageTitle { + margin: 0 0 0.5rem; + font-size: 1.25rem; + font-weight: 600; + color: var(--color-text-primary); +} + +.subtitle { + margin: 0 0 1.5rem; + font-size: 0.875rem; + color: var(--color-text-muted); +} + +/* ── Tag pills ─────────────────────────────────────────────────────────────── */ + +.tagBar { + display: flex; + flex-wrap: wrap; + gap: 0.375rem; + margin-bottom: 1.5rem; +} + +.tagPill { + display: inline-block; + padding: 0.1875rem 0.625rem; + border-radius: 9999px; + font-size: 0.75rem; + font-weight: 500; + background: var(--color-badge-category-bg); + color: var(--color-badge-category-text); + white-space: nowrap; +} + +/* ── Collapsible section ───────────────────────────────────────────────────── */ + +.section { + margin-bottom: 1rem; + border: 1px solid var(--color-border); + border-radius: 10px; + overflow: hidden; +} + +.sectionHeader { + display: flex; + align-items: center; + gap: 0.625rem; + width: 100%; + padding: 0.875rem 1rem; + background: var(--color-bg-surface); + border: none; + cursor: pointer; + text-align: left; + color: var(--color-text-primary); + font-size: 0.9375rem; + font-weight: 600; + transition: background 0.15s; +} + +.sectionHeader:hover { + background: var(--color-bg-surface-hover); +} + +.chevron { + width: 16px; + height: 16px; + flex-shrink: 0; + transition: transform 0.2s ease; + color: var(--color-text-muted); +} + +.chevronOpen { + transform: rotate(90deg); +} + +.sectionCount { + margin-left: auto; + font-size: 0.75rem; + font-weight: 500; + color: var(--color-text-muted); + background: var(--color-bg-elevated, var(--color-bg-surface)); + padding: 0.125rem 0.5rem; + border-radius: 9999px; +} + +.sectionBody { + display: grid; + grid-template-rows: 0fr; + transition: grid-template-rows 0.25s ease; +} + +.sectionBodyOpen { + grid-template-rows: 1fr; +} + +.sectionInner { + overflow: hidden; + min-height: 0; +} + +.sectionContent { + padding: 0 1rem 1rem; +} + +/* ── Table ─────────────────────────────────────────────────────────────────── */ + +.tableWrap { + overflow-x: auto; +} + +.table { + width: 100%; + border-collapse: collapse; + font-size: 0.875rem; +} + +.table th { + text-align: left; + padding: 0.5rem 0.625rem; + font-weight: 600; + color: var(--color-text-muted); + font-size: 0.75rem; + text-transform: uppercase; + letter-spacing: 0.04em; + border-bottom: 1px solid var(--color-border); +} + +.table td { + padding: 0.5rem 0.625rem; + color: var(--color-text-secondary); + border-bottom: 1px solid var(--color-border-subtle, var(--color-border)); +} + +.table tbody tr:hover { + background: var(--color-bg-surface-hover); +} + +.link { + color: var(--color-accent); + text-decoration: none; + font-weight: 500; +} + +.link:hover { + text-decoration: underline; +} + +/* ── Badges ────────────────────────────────────────────────────────────────── */ + +.badge { + display: inline-block; + padding: 0.125rem 0.5rem; + border-radius: 9999px; + font-size: 0.75rem; + font-weight: 600; + white-space: nowrap; +} + +.badgeContentType { + background: var(--color-badge-edited-bg); + color: var(--color-badge-edited-text); +} + +.badgeRelType { + background: var(--color-badge-pending-bg); + color: var(--color-badge-pending-text); +} + +.badgeComplete { + background: var(--color-badge-approved-bg); + color: var(--color-badge-approved-text); +} + +.badgeProcessing { + background: var(--color-badge-edited-bg); + color: var(--color-badge-edited-text); +} + +.badgeError { + background: var(--color-badge-rejected-bg); + color: var(--color-badge-rejected-text); +} + +.badgePending { + background: var(--color-badge-pending-bg); + color: var(--color-badge-pending-text); +} + +/* ── Tags in table cells ──────────────────────────────────────────────────── */ + +.cellTags { + display: flex; + flex-wrap: wrap; + gap: 0.25rem; + align-items: center; +} + +.miniTag { + display: inline-block; + padding: 0.0625rem 0.375rem; + border-radius: 4px; + font-size: 0.6875rem; + background: var(--color-badge-category-bg); + color: var(--color-badge-category-text); +} + +.tagOverflow { + font-size: 0.6875rem; + color: var(--color-text-muted); +} + +/* ── Time range ────────────────────────────────────────────────────────────── */ + +.timeRange { + font-family: var(--font-mono, monospace); + font-size: 0.8125rem; + color: var(--color-text-muted); + white-space: nowrap; +} + +/* ── Video group ───────────────────────────────────────────────────────────── */ + +.videoGroup { + margin-bottom: 1rem; +} + +.videoGroup:last-child { + margin-bottom: 0; +} + +.videoGroupTitle { + font-size: 0.8125rem; + font-weight: 600; + color: var(--color-text-muted); + margin: 0 0 0.375rem; + font-family: var(--font-mono, monospace); +} + +/* ── Filename ──────────────────────────────────────────────────────────────── */ + +.filename { + font-family: var(--font-mono, monospace); + font-size: 0.8125rem; + word-break: break-all; +} + +/* ── States ────────────────────────────────────────────────────────────────── */ + +.emptyText { + color: var(--color-text-muted); + font-size: 0.875rem; + padding: 0.5rem 0; +} + +.emptyState { + text-align: center; + padding: 3rem 1rem; + color: var(--color-text-muted); +} + +.emptyState h2 { + font-size: 1.125rem; + color: var(--color-text-secondary); + margin: 0 0 0.5rem; +} + +.emptyState p { + font-size: 0.875rem; + margin: 0; +} + +.errorState { + background: var(--color-error-bg, rgba(220, 38, 38, 0.1)); + color: var(--color-error, #ef4444); + padding: 1rem; + border-radius: 8px; + font-size: 0.875rem; +} + +/* ── Skeleton ──────────────────────────────────────────────────────────────── */ + +.skeleton { + display: flex; + flex-direction: column; + gap: 1rem; +} + +.skeletonPulse { + background: var(--color-bg-surface); + border: 1px solid var(--color-border); + border-radius: 10px; + animation: pulse 1.5s ease-in-out infinite; +} + +.skeletonBlock { + height: 56px; +} + +@keyframes pulse { + 0%, 100% { opacity: 1; } + 50% { opacity: 0.5; } +} + +/* ── Responsive ────────────────────────────────────────────────────────────── */ + +@media (max-width: 768px) { + .layout { + flex-direction: column; + } + + .content { + padding: 1.25rem; + } + + .table th:nth-child(n+4), + .table td:nth-child(n+4) { + display: none; + } +} diff --git a/frontend/src/pages/CreatorTransparency.tsx b/frontend/src/pages/CreatorTransparency.tsx new file mode 100644 index 0000000..51ada76 --- /dev/null +++ b/frontend/src/pages/CreatorTransparency.tsx @@ -0,0 +1,399 @@ +import { useEffect, useState } from "react"; +import { Link } from "react-router-dom"; +import { useAuth } from "../context/AuthContext"; +import { useDocumentTitle } from "../hooks/useDocumentTitle"; +import { SidebarNav } from "./CreatorDashboard"; +import { + fetchCreatorTransparency, + type CreatorTransparencyResponse, + type TransparencyKeyMoment, +} from "../api/creator-transparency"; +import { ApiError } from "../api/client"; +import styles from "./CreatorTransparency.module.css"; + +/* ── Helpers ────────────────────────────────────────────────────────────────── */ + +function formatDate(iso: string): string { + return new Date(iso).toLocaleDateString(undefined, { + year: "numeric", + month: "short", + day: "numeric", + }); +} + +function formatTime(seconds: number): string { + const m = Math.floor(seconds / 60); + const s = Math.floor(seconds % 60); + return `${m}:${s.toString().padStart(2, "0")}`; +} + +function statusBadgeClass(status: string): string { + switch (status.toLowerCase()) { + case "complete": + case "completed": + return styles.badgeComplete ?? ""; + case "processing": + return styles.badgeProcessing ?? ""; + case "error": + case "failed": + return styles.badgeError ?? ""; + default: + return styles.badgePending ?? ""; + } +} + +/* ── Chevron icon ──────────────────────────────────────────────────────────── */ + +function ChevronIcon({ open }: { open: boolean }) { + return ( + + + + ); +} + +/* ── Collapsible section wrapper ───────────────────────────────────────────── */ + +function CollapsibleSection({ + title, + count, + defaultOpen = false, + children, +}: { + title: string; + count: number; + defaultOpen?: boolean; + children: React.ReactNode; +}) { + const [open, setOpen] = useState(defaultOpen); + + return ( +
+
{count} + +
+
+
{children}
+
+
+ + ); +} + +/* ── Section: Technique Pages ──────────────────────────────────────────────── */ + +function TechniqueSection({ data }: { data: CreatorTransparencyResponse }) { + if (data.techniques.length === 0) { + return

No technique pages derived from your content yet.

; + } + return ( +
+ + + + + + + + + + + + {data.techniques.map((t) => ( + + + + + + + + ))} + +
TitleCategoryTagsMomentsCreated
+ + {t.title} + + {t.topic_category} +
+ {t.topic_tags.slice(0, 4).map((tag) => ( + {tag} + ))} + {t.topic_tags.length > 4 && ( + +{t.topic_tags.length - 4} + )} +
+
{t.key_moment_count}{formatDate(t.created_at)}
+
+ ); +} + +/* ── Section: Key Moments (grouped by source video) ────────────────────────── */ + +function KeyMomentSection({ data }: { data: CreatorTransparencyResponse }) { + if (data.key_moments.length === 0) { + return

No key moments extracted yet.

; + } + + // Group by source video + const grouped = new Map(); + for (const m of data.key_moments) { + const key = m.source_video_filename || "Unknown source"; + const arr = grouped.get(key); + if (arr) arr.push(m); + else grouped.set(key, [m]); + } + + return ( + <> + {Array.from(grouped.entries()).map(([videoFilename, moments]) => ( +
+

{videoFilename}

+
+ + + + + + + + + + + {moments.map((m, i) => ( + + + + + + + ))} + +
TitleTypeTimeTechnique Page
{m.title} + + {m.content_type} + + + + {formatTime(m.start_time)} – {formatTime(m.end_time)} + + + {m.technique_page_title ?? ( + + )} +
+
+
+ ))} + + ); +} + +/* ── Section: Cross-References ─────────────────────────────────────────────── */ + +function RelationshipSection({ data }: { data: CreatorTransparencyResponse }) { + if (data.relationships.length === 0) { + return

No cross-references found yet.

; + } + return ( +
+ + + + + + + + + + {data.relationships.map((r, i) => ( + + + + + + ))} + +
TypeSourceTarget
+ + {r.relationship_type} + + + + {r.source_page_title} + + + + {r.target_page_title} + +
+
+ ); +} + +/* ── Section: Source Videos ─────────────────────────────────────────────────── */ + +function SourceVideoSection({ data }: { data: CreatorTransparencyResponse }) { + if (data.source_videos.length === 0) { + return

No source videos uploaded yet.

; + } + return ( +
+ + + + + + + + + + {data.source_videos.map((v) => ( + + + + + + ))} + +
FilenameStatusUploaded
{v.filename} + + {v.processing_status} + + {formatDate(v.created_at)}
+
+ ); +} + +/* ── Main component ────────────────────────────────────────────────────────── */ + +export default function CreatorTransparency() { + useDocumentTitle("AI Transparency"); + const { user } = useAuth(); + + const [data, setData] = useState(null); + const [loading, setLoading] = useState(true); + const [error, setError] = useState(null); + + useEffect(() => { + let cancelled = false; + setLoading(true); + setError(null); + + fetchCreatorTransparency() + .then((res) => { + if (!cancelled) setData(res); + }) + .catch((err) => { + if (cancelled) return; + if (err instanceof ApiError && err.status === 404) { + setError("not_linked"); + } else { + setError(err instanceof ApiError ? err.detail : "Failed to load transparency data"); + } + }) + .finally(() => { + if (!cancelled) setLoading(false); + }); + + return () => { + cancelled = true; + }; + }, []); + + return ( +
+ +
+

AI Transparency

+

+ Everything our AI derived from {user?.display_name ? `${user.display_name}'s` : "your"} content +

+ + {loading && } + + {!loading && error === "not_linked" && ( +
+

No Creator Profile

+

Your account isn't linked to a creator profile yet. Contact an admin to get set up.

+
+ )} + + {!loading && error && error !== "not_linked" && ( +
+

Could not load transparency data: {error}

+
+ )} + + {!loading && !error && data && ( + <> + {/* ── Tag summary ────────────────────────────────────────── */} + {data.tags.length > 0 && ( +
+ {data.tags.map((tag) => ( + {tag} + ))} +
+ )} + + {/* ── Collapsible sections ──────────────────────────────── */} + + + + + + + + + + + + + + + + + )} +
+
+ ); +} + +/* ── Loading skeleton ──────────────────────────────────────────────────────── */ + +function TransparencySkeleton() { + return ( +
+ {[1, 2, 3, 4].map((i) => ( +
+ ))} +
+ ); +} diff --git a/frontend/tsconfig.app.tsbuildinfo b/frontend/tsconfig.app.tsbuildinfo index 31ad412..1815196 100644 --- a/frontend/tsconfig.app.tsbuildinfo +++ b/frontend/tsconfig.app.tsbuildinfo @@ -1 +1 @@ -{"root":["./src/App.tsx","./src/main.tsx","./src/vite-env.d.ts","./src/api/admin-pipeline.ts","./src/api/admin-techniques.ts","./src/api/auth.ts","./src/api/chat.ts","./src/api/client.ts","./src/api/consent.ts","./src/api/creator-dashboard.ts","./src/api/creators.ts","./src/api/follows.ts","./src/api/highlights.ts","./src/api/index.ts","./src/api/notifications.ts","./src/api/posts.ts","./src/api/reports.ts","./src/api/search.ts","./src/api/shorts.ts","./src/api/stats.ts","./src/api/techniques.ts","./src/api/templates.ts","./src/api/topics.ts","./src/api/videos.ts","./src/components/AdminDropdown.tsx","./src/components/AppFooter.tsx","./src/components/AudioWaveform.tsx","./src/components/CategoryIcons.tsx","./src/components/ChapterMarkers.tsx","./src/components/ChatWidget.tsx","./src/components/ConfirmModal.tsx","./src/components/CopyLinkButton.tsx","./src/components/CreatorAvatar.tsx","./src/components/ImpersonationBanner.tsx","./src/components/PersonalityProfile.tsx","./src/components/PlayerControls.tsx","./src/components/PostsFeed.tsx","./src/components/ProtectedRoute.tsx","./src/components/ReportIssueModal.tsx","./src/components/SearchAutocomplete.tsx","./src/components/SocialIcons.tsx","./src/components/SortDropdown.tsx","./src/components/TableOfContents.tsx","./src/components/TagList.tsx","./src/components/ToggleSwitch.tsx","./src/components/TranscriptSidebar.tsx","./src/components/VideoPlayer.tsx","./src/context/AuthContext.tsx","./src/hooks/useCountUp.ts","./src/hooks/useDocumentTitle.ts","./src/hooks/useMediaSync.ts","./src/hooks/useSortPreference.ts","./src/pages/About.tsx","./src/pages/AdminAuditLog.tsx","./src/pages/AdminPipeline.tsx","./src/pages/AdminReports.tsx","./src/pages/AdminTechniquePages.tsx","./src/pages/AdminUsers.tsx","./src/pages/ChapterReview.tsx","./src/pages/ChatPage.tsx","./src/pages/ConsentDashboard.tsx","./src/pages/CreatorDashboard.tsx","./src/pages/CreatorDetail.tsx","./src/pages/CreatorSettings.tsx","./src/pages/CreatorTiers.tsx","./src/pages/CreatorsBrowse.tsx","./src/pages/EmbedPlayer.tsx","./src/pages/HighlightQueue.tsx","./src/pages/Home.tsx","./src/pages/Login.tsx","./src/pages/PostEditor.tsx","./src/pages/PostsList.tsx","./src/pages/Register.tsx","./src/pages/SearchResults.tsx","./src/pages/ShortPlayer.tsx","./src/pages/SubTopicPage.tsx","./src/pages/TechniquePage.tsx","./src/pages/TopicsBrowse.tsx","./src/pages/WatchPage.tsx","./src/utils/catSlug.ts","./src/utils/chatCitations.tsx","./src/utils/citations.tsx","./src/utils/clipboard.ts","./src/utils/formatTime.ts"],"version":"5.6.3"} \ No newline at end of file +{"root":["./src/App.tsx","./src/main.tsx","./src/vite-env.d.ts","./src/api/admin-pipeline.ts","./src/api/admin-techniques.ts","./src/api/admin-usage.ts","./src/api/auth.ts","./src/api/chat.ts","./src/api/client.ts","./src/api/consent.ts","./src/api/creator-dashboard.ts","./src/api/creator-transparency.ts","./src/api/creators.ts","./src/api/follows.ts","./src/api/highlights.ts","./src/api/index.ts","./src/api/notifications.ts","./src/api/posts.ts","./src/api/reports.ts","./src/api/search.ts","./src/api/shorts.ts","./src/api/stats.ts","./src/api/techniques.ts","./src/api/templates.ts","./src/api/topics.ts","./src/api/videos.ts","./src/components/AdminDropdown.tsx","./src/components/AppFooter.tsx","./src/components/AudioWaveform.tsx","./src/components/CategoryIcons.tsx","./src/components/ChapterMarkers.tsx","./src/components/ChatWidget.tsx","./src/components/ConfirmModal.tsx","./src/components/CopyLinkButton.tsx","./src/components/CreatorAvatar.tsx","./src/components/ImpersonationBanner.tsx","./src/components/PersonalityProfile.tsx","./src/components/PlayerControls.tsx","./src/components/PostsFeed.tsx","./src/components/ProtectedRoute.tsx","./src/components/ReportIssueModal.tsx","./src/components/SearchAutocomplete.tsx","./src/components/SocialIcons.tsx","./src/components/SortDropdown.tsx","./src/components/TableOfContents.tsx","./src/components/TagList.tsx","./src/components/ToggleSwitch.tsx","./src/components/TranscriptSidebar.tsx","./src/components/VideoPlayer.tsx","./src/context/AuthContext.tsx","./src/hooks/useCountUp.ts","./src/hooks/useDocumentTitle.ts","./src/hooks/useMediaSync.ts","./src/hooks/useSortPreference.ts","./src/pages/About.tsx","./src/pages/AdminAuditLog.tsx","./src/pages/AdminPipeline.tsx","./src/pages/AdminReports.tsx","./src/pages/AdminTechniquePages.tsx","./src/pages/AdminUsage.tsx","./src/pages/AdminUsers.tsx","./src/pages/ChapterReview.tsx","./src/pages/ChatPage.tsx","./src/pages/ConsentDashboard.tsx","./src/pages/CreatorDashboard.tsx","./src/pages/CreatorDetail.tsx","./src/pages/CreatorOnboarding.tsx","./src/pages/CreatorSettings.tsx","./src/pages/CreatorTiers.tsx","./src/pages/CreatorTransparency.tsx","./src/pages/CreatorsBrowse.tsx","./src/pages/EmbedPlayer.tsx","./src/pages/HighlightQueue.tsx","./src/pages/Home.tsx","./src/pages/Login.tsx","./src/pages/PostEditor.tsx","./src/pages/PostsList.tsx","./src/pages/Register.tsx","./src/pages/SearchResults.tsx","./src/pages/ShortPlayer.tsx","./src/pages/SubTopicPage.tsx","./src/pages/TechniquePage.tsx","./src/pages/TopicsBrowse.tsx","./src/pages/WatchPage.tsx","./src/utils/catSlug.ts","./src/utils/chatCitations.tsx","./src/utils/citations.tsx","./src/utils/clipboard.ts","./src/utils/formatTime.ts"],"version":"5.6.3"} \ No newline at end of file