AI podcast project

This commit is contained in:
ajaysi
2025-12-16 16:25:52 +05:30
parent eba5210577
commit 1d745c9bc8
50 changed files with 7637 additions and 2813 deletions

View File

@@ -1,6 +1,6 @@
import React, { useMemo } from "react";
import { Stack, Typography, Divider, Chip, Tooltip, IconButton, alpha } from "@mui/material";
import { OpenInNew as OpenInNewIcon, ContentCopy as ContentCopyIcon } from "@mui/icons-material";
import React, { useMemo, useState } from "react";
import { Stack, Typography, Divider, Chip, Tooltip, IconButton, alpha, Box } from "@mui/material";
import { OpenInNew as OpenInNewIcon, ContentCopy as ContentCopyIcon, ExpandMore as ExpandMoreIcon, ExpandLess as ExpandLessIcon } from "@mui/icons-material";
import { Fact } from "./types";
import { GlassyCard, glassyCardSx } from "./ui";
@@ -8,7 +8,10 @@ interface FactCardProps {
fact: Fact;
}
const MAX_PREVIEW_LENGTH = 200; // Characters to show before truncation
export const FactCard: React.FC<FactCardProps> = ({ fact }) => {
const [expanded, setExpanded] = useState(false);
const hostname = useMemo(() => {
try {
return new URL(fact.url).hostname;
@@ -21,30 +24,77 @@ export const FactCard: React.FC<FactCardProps> = ({ fact }) => {
navigator.clipboard.writeText(fact.quote);
};
const shouldTruncate = fact.quote.length > MAX_PREVIEW_LENGTH;
const previewText = shouldTruncate ? fact.quote.slice(0, MAX_PREVIEW_LENGTH).trim() + "..." : fact.quote;
const fullText = fact.quote;
return (
<GlassyCard
whileHover={{ y: -4 }}
whileHover={{ y: -2 }}
sx={{
...glassyCardSx,
p: 2,
p: 1.5,
cursor: "pointer",
transition: "all 0.2s",
height: "100%",
display: "flex",
flexDirection: "column",
"&:hover": {
borderColor: "rgba(102,126,234,0.25)",
boxShadow: "0 12px 28px rgba(15,23,42,0.08)",
boxShadow: "0 8px 20px rgba(15,23,42,0.08)",
},
background: "#ffffff",
border: "1px solid rgba(0,0,0,0.06)",
}}
>
<Stack spacing={1.5}>
<Typography variant="body2" sx={{ lineHeight: 1.6, color: "#0f172a" }}>
{fact.quote}
</Typography>
<Divider sx={{ borderColor: "rgba(0,0,0,0.06)" }} />
<Stack direction="row" spacing={1} alignItems="center" justifyContent="space-between">
<Stack direction="row" spacing={1} alignItems="center" flex={1}>
<OpenInNewIcon fontSize="small" sx={{ color: "rgba(15,23,42,0.6)" }} />
<Stack spacing={1} sx={{ flex: 1, minHeight: 0 }}>
{/* Quote Text - Truncated with expand option */}
<Box sx={{ flex: 1, minHeight: 0 }}>
<Typography
variant="body2"
sx={{
lineHeight: 1.5,
color: "#0f172a",
fontSize: "0.8125rem",
display: "-webkit-box",
WebkitLineClamp: expanded ? "none" : 4,
WebkitBoxOrient: "vertical",
overflow: "hidden",
textOverflow: "ellipsis",
mb: shouldTruncate ? 0.5 : 0,
}}
>
{expanded ? fullText : previewText}
</Typography>
{shouldTruncate && (
<IconButton
size="small"
onClick={(e) => {
e.stopPropagation();
setExpanded(!expanded);
}}
sx={{
p: 0.25,
mt: 0.25,
color: "#4f46e5",
"&:hover": { background: alpha("#4f46e5", 0.1) },
}}
>
{expanded ? (
<ExpandLessIcon fontSize="small" />
) : (
<ExpandMoreIcon fontSize="small" />
)}
</IconButton>
)}
</Box>
<Divider sx={{ borderColor: "rgba(0,0,0,0.06)", my: 0.5 }} />
{/* Source and Actions */}
<Stack direction="row" spacing={0.75} alignItems="center" justifyContent="space-between">
<Stack direction="row" spacing={0.5} alignItems="center" flex={1} minWidth={0}>
<OpenInNewIcon fontSize="small" sx={{ color: "rgba(15,23,42,0.5)", flexShrink: 0 }} />
<Typography
variant="caption"
component="a"
@@ -55,34 +105,49 @@ export const FactCard: React.FC<FactCardProps> = ({ fact }) => {
color: "#4f46e5",
textDecoration: "none",
"&:hover": { textDecoration: "underline" },
flex: 1,
overflow: "hidden",
textOverflow: "ellipsis",
whiteSpace: "nowrap",
fontSize: "0.7rem",
}}
>
{hostname || "source"}
</Typography>
</Stack>
<Tooltip title="Copy citation">
<IconButton size="small" onClick={handleCopy} sx={{ color: "rgba(15,23,42,0.65)" }}>
<IconButton
size="small"
onClick={(e) => {
e.stopPropagation();
handleCopy();
}}
sx={{
color: "rgba(15,23,42,0.6)",
p: 0.5,
"&:hover": { background: alpha("#4f46e5", 0.1) },
}}
>
<ContentCopyIcon fontSize="small" />
</IconButton>
</Tooltip>
</Stack>
<Stack direction="row" spacing={2}>
{/* Confidence and Date */}
<Stack direction="row" spacing={1} alignItems="center" justifyContent="space-between">
<Chip
label={`${(fact.confidence * 100).toFixed(0)}% confidence`}
label={`${(fact.confidence * 100).toFixed(0)}%`}
size="small"
sx={{
height: 20,
height: 18,
fontSize: "0.65rem",
background: alpha("#22c55e", 0.15),
color: "#15803d",
border: "1px solid rgba(34,197,94,0.35)",
fontWeight: 600,
}}
/>
<Typography variant="caption" sx={{ color: "#475569" }}>
{fact.date}
<Typography variant="caption" sx={{ color: "#64748b", fontSize: "0.7rem" }}>
{fact.date !== "Unknown" ? new Date(fact.date).toLocaleDateString("en-US", { month: "short", year: "numeric" }) : fact.date}
</Typography>
</Stack>
</Stack>