Add core UI components and layout for media platform

Initializes the client-side application with fundamental UI components, including navigation, cards for articles and auctions, and various elements for user interaction and display.

Replit-Commit-Author: Agent
Replit-Commit-Session-Id: 069d4324-6c40-4355-955e-c714a50de1ea
Replit-Commit-Checkpoint-Type: intermediate_checkpoint
Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/3df548ff-50ae-432f-9be4-25d34eccc983/069d4324-6c40-4355-955e-c714a50de1ea/bVdKIaU
This commit is contained in:
kimjaehyeon0101
2025-09-29 14:35:50 +00:00
parent 4d252ca7a6
commit 2cbad88faa
89 changed files with 17584 additions and 0 deletions

View File

@ -0,0 +1,163 @@
import { useQuery } from "@tanstack/react-query";
import { useRoute } from "wouter";
import { Button } from "@/components/ui/button";
import { Badge } from "@/components/ui/badge";
import PredictionMarketCard from "@/components/PredictionMarketCard";
import type { Article, PredictionMarket } from "@shared/schema";
export default function Article() {
const [, params] = useRoute("/articles/:slug");
const { data: article, isLoading: articleLoading } = useQuery<Article>({
queryKey: ["/api/articles", params?.slug],
enabled: !!params?.slug
});
const { data: predictionMarkets = [], isLoading: marketsLoading } = useQuery<PredictionMarket[]>({
queryKey: ["/api/prediction-markets", { articleId: article?.id }],
enabled: !!article?.id
});
if (articleLoading) {
return (
<div className="min-h-screen bg-background">
<div className="max-w-4xl mx-auto px-6 py-8">
<div className="animate-pulse">
<div className="h-8 bg-muted rounded w-2/3 mb-4"></div>
<div className="h-64 bg-muted rounded mb-6"></div>
<div className="space-y-4">
{Array.from({ length: 5 }).map((_, i) => (
<div key={i} className="h-4 bg-muted rounded"></div>
))}
</div>
</div>
</div>
</div>
);
}
if (!article) {
return (
<div className="min-h-screen bg-background flex items-center justify-center">
<div className="text-center">
<h1 className="text-2xl font-bold mb-2">Article Not Found</h1>
<p className="text-muted-foreground mb-4">The article you're looking for doesn't exist.</p>
<Button onClick={() => window.history.back()}>Go Back</Button>
</div>
</div>
);
}
const formatDate = (date: string | Date) => {
const d = new Date(date);
const now = new Date();
const diffTime = Math.abs(now.getTime() - d.getTime());
const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24));
if (diffDays === 1) return "1 day ago";
if (diffDays < 7) return `${diffDays} days ago`;
return d.toLocaleDateString();
};
return (
<div className="min-h-screen bg-background">
{/* Header */}
<header className="bg-card border-b border-border sticky top-0 z-50">
<div className="max-w-7xl mx-auto px-6 py-4">
<div className="flex items-center justify-between">
<div className="flex items-center space-x-3">
<div className="w-10 h-10 bg-primary rounded-lg flex items-center justify-center text-primary-foreground font-bold text-lg">
S
</div>
<span className="text-2xl font-bold tracking-tight">SAPIENS</span>
</div>
<div className="flex items-center space-x-4">
<Button variant="ghost" onClick={() => window.history.back()}>
Back
</Button>
<Button variant="outline" onClick={() => window.location.href = "/"}>
Home
</Button>
</div>
</div>
</div>
</header>
<main className="max-w-4xl mx-auto px-6 py-8">
{/* Article Header */}
<div className="mb-8">
<div className="flex items-center space-x-4 mb-6">
<img
src="https://images.unsplash.com/photo-1560250097-0b93528c311a?ixlib=rb-4.0.3&w=48&h=48&fit=crop&crop=face"
alt="Author"
className="w-12 h-12 rounded-full object-cover"
/>
<div>
<h2 className="text-xl font-bold">Alex Karp</h2>
<p className="text-sm text-muted-foreground">CEO of Palantir</p>
</div>
</div>
</div>
{/* Article Content */}
<article>
{article.imageUrl && (
<img
src={article.imageUrl}
alt={article.title}
className="w-full h-64 object-cover rounded-lg mb-6"
/>
)}
<h1 className="text-3xl font-bold mb-4">{article.title}</h1>
<div className="flex items-center space-x-4 mb-6 text-sm text-muted-foreground">
<span>{formatDate(article.publishedAt!)}</span>
<span></span>
{article.tags?.map((tag) => (
<Badge key={tag} variant="secondary">
{tag}
</Badge>
))}
</div>
<div className="prose prose-lg max-w-none text-foreground mb-8">
{article.excerpt && (
<p className="text-lg text-muted-foreground mb-6 font-medium">
{article.excerpt}
</p>
)}
<div className="whitespace-pre-wrap">
{article.content}
</div>
</div>
</article>
{/* Related Prediction Markets */}
{predictionMarkets.length > 0 && (
<div className="mt-12 border-t border-border pt-8">
<h3 className="text-xl font-bold mb-6">Related Prediction Markets</h3>
<div className="space-y-4">
{predictionMarkets.slice(0, 3).map((market) => (
<PredictionMarketCard key={market.id} market={market} />
))}
</div>
{predictionMarkets.length > 3 && (
<Button
variant="outline"
className="w-full mt-6"
data-testid="button-view-all-predictions"
>
View All Related Predictions
</Button>
)}
</div>
)}
</main>
</div>
);
}