Skip to content

Commit b53fc30

Browse files
authored
Merge pull request #36 from werther41/default-article-view
Default article view
2 parents 8c68125 + 5dcf14a commit b53fc30

File tree

21 files changed

+270
-52
lines changed

21 files changed

+270
-52
lines changed

app/admin/import/page.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -259,7 +259,7 @@ export default function ImportPage() {
259259
</div>
260260
) : (
261261
<div className="py-8 text-center text-muted-foreground">
262-
<AlertCircle className="mx-auto mb-4 size-12 opacity-50" />
262+
<AlertCircle className="size-12 mx-auto mb-4 opacity-50" />
263263
<p>Import results will appear here after running an import.</p>
264264
</div>
265265
)}

app/api/articles/route.ts

Lines changed: 58 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { NextRequest, NextResponse } from "next/server"
22

3-
import { getArticlesByTopics } from "@/lib/articles"
3+
import { getArticlesByTopics, getRecentArticles } from "@/lib/articles"
44

55
// Cache for 5 minutes
66
export const revalidate = 300
@@ -16,11 +16,65 @@ export async function GET(request: NextRequest) {
1616
const topicTypesParam = searchParams.get("topicTypes")
1717
const sortBy = searchParams.get("sortBy") || "score"
1818

19-
// Validate required parameters
19+
// If no topics provided, return recent articles
2020
if (!topicsParam) {
21+
// Validate timeFilter
22+
const validTimeFilters = ["24h", "7d", "30d", "all"]
23+
if (!validTimeFilters.includes(timeFilter)) {
24+
return NextResponse.json(
25+
{ error: "timeFilter must be one of: 24h, 7d, 30d, all" },
26+
{ status: 400 }
27+
)
28+
}
29+
30+
// Convert timeFilter to hours
31+
let timeWindow: number | null = null
32+
switch (timeFilter) {
33+
case "24h":
34+
timeWindow = 24
35+
break
36+
case "7d":
37+
timeWindow = 168
38+
break
39+
case "30d":
40+
timeWindow = 720
41+
break
42+
case "all":
43+
timeWindow = null
44+
break
45+
}
46+
47+
// Get recent articles
48+
const articles = await getRecentArticles({
49+
timeWindow,
50+
limit: 50,
51+
})
52+
53+
// Always sort by time for recent articles
54+
const sortedArticles = [...articles].sort(
55+
(a, b) =>
56+
new Date(b.published_at).getTime() -
57+
new Date(a.published_at).getTime()
58+
)
59+
2160
return NextResponse.json(
22-
{ error: "topics parameter is required" },
23-
{ status: 400 }
61+
{
62+
articles: sortedArticles,
63+
metadata: {
64+
totalResults: sortedArticles.length,
65+
timeFilter,
66+
searchType: "recent" as const,
67+
sortBy: "time",
68+
generatedAt: new Date().toISOString(),
69+
},
70+
},
71+
{
72+
headers: {
73+
"Cache-Control": "public, s-maxage=300, stale-while-revalidate=600",
74+
"CDN-Cache-Control": "public, s-maxage=300",
75+
"Vercel-CDN-Cache-Control": "public, s-maxage=300",
76+
},
77+
}
2478
)
2579
}
2680

app/api/topics/route.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,9 @@ export async function GET(request: NextRequest) {
2929
)
3030
}
3131

32-
if (limit < 1 || limit > 50) {
32+
if (limit < 1 || limit > 200) {
3333
return NextResponse.json(
34-
{ error: "limit must be between 1 and 50" },
34+
{ error: "limit must be between 1 and 200" },
3535
{ status: 400 }
3636
)
3737
}

app/deep-dive/burger-infographic/page.tsx

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -419,31 +419,31 @@ export default function BurgerInfographic() {
419419
your best burger yet.
420420
</p>
421421
<div className="flex flex-col items-center justify-center space-y-4 md:flex-row md:space-x-4 md:space-y-0">
422-
<div className="flex size-24 shrink-0 items-center justify-center rounded-full bg-[#00CECB] text-center font-bold text-[#FFFFEA]">
422+
<div className="size-24 flex shrink-0 items-center justify-center rounded-full bg-[#00CECB] text-center font-bold text-[#FFFFEA]">
423423
<span>1. Preheat Pan</span>
424424
</div>
425425
<div className="mx-4 rotate-90 text-4xl text-[#00796B] md:rotate-0">
426426
&rarr;
427427
</div>
428-
<div className="flex size-24 shrink-0 items-center justify-center rounded-full bg-[#00CECB] text-center font-bold text-[#FFFFEA]">
428+
<div className="size-24 flex shrink-0 items-center justify-center rounded-full bg-[#00CECB] text-center font-bold text-[#FFFFEA]">
429429
<span>2. Add Patty</span>
430430
</div>
431431
<div className="mx-4 rotate-90 text-4xl text-[#00796B] md:rotate-0">
432432
&rarr;
433433
</div>
434-
<div className="flex size-24 shrink-0 items-center justify-center rounded-full bg-[#FF5E5B] text-center font-bold text-[#FFFFEA]">
434+
<div className="size-24 flex shrink-0 items-center justify-center rounded-full bg-[#FF5E5B] text-center font-bold text-[#FFFFEA]">
435435
<span>3. Flip every 30s</span>
436436
</div>
437437
<div className="mx-4 rotate-90 text-4xl text-[#00796B] md:rotate-0">
438438
&rarr;
439439
</div>
440-
<div className="flex size-24 shrink-0 items-center justify-center rounded-full bg-[#00CECB] text-center font-bold text-[#FFFFEA]">
440+
<div className="size-24 flex shrink-0 items-center justify-center rounded-full bg-[#00CECB] text-center font-bold text-[#FFFFEA]">
441441
<span>4. Add Cheese</span>
442442
</div>
443443
<div className="mx-4 rotate-90 text-4xl text-[#00796B] md:rotate-0">
444444
&rarr;
445445
</div>
446-
<div className="flex size-24 shrink-0 items-center justify-center rounded-full bg-[#00CECB] text-center font-bold text-[#FFFFEA]">
446+
<div className="size-24 flex shrink-0 items-center justify-center rounded-full bg-[#00CECB] text-center font-bold text-[#FFFFEA]">
447447
<span>5. Rest & Serve</span>
448448
</div>
449449
</div>

app/deep-dive/page.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ export default function DeepDivePage() {
1414
<section className="px-4 py-8">
1515
<div className="container mx-auto max-w-4xl text-center">
1616
<h1 className="mb-6 text-4xl font-bold text-foreground">Deep Dive</h1>
17-
<p className="mb-12 text-pretty text-xl text-muted-foreground">
17+
<p className="text-pretty mb-12 text-xl text-muted-foreground">
1818
Immerse yourself in comprehensive explorations of the most
1919
wonderfully pointless topics. From detailed infographics to in-depth
2020
articles, discover the hidden depths of useless knowledge.

app/discover/page.tsx

Lines changed: 112 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,8 @@ export default function DiscoverPage() {
4444
const [searchState, setSearchState] = useState<SearchState>({
4545
mode: "topic",
4646
topics: [],
47-
timeFilter: "7d",
48-
sortBy: "score",
47+
timeFilter: "24h",
48+
sortBy: "time",
4949
textQuery: "",
5050
articles: [],
5151
isLoading: false,
@@ -80,6 +80,78 @@ export default function DiscoverPage() {
8080
fetchStats()
8181
}, [])
8282

83+
// Function to fetch recent articles
84+
const fetchRecentArticles = useCallback(async () => {
85+
setSearchState((prev) => {
86+
// Only fetch if no topics selected and no text query
87+
if (prev.topics.length === 0 && !prev.textQuery) {
88+
// Start loading
89+
const loadingState = { ...prev, isLoading: true, error: null }
90+
91+
// Fetch articles asynchronously
92+
const params = new URLSearchParams({
93+
timeFilter: prev.timeFilter,
94+
sortBy: "time",
95+
})
96+
97+
fetch(`/api/articles?${params}`)
98+
.then((response) => {
99+
if (!response.ok) {
100+
return response.json().then((errorData) => {
101+
throw new Error(errorData.error || "Failed to fetch articles")
102+
})
103+
}
104+
return response.json()
105+
})
106+
.then((data) => {
107+
setSearchState((current) => ({
108+
...current,
109+
articles: data.articles,
110+
isLoading: false,
111+
error: null,
112+
}))
113+
})
114+
.catch((error) => {
115+
console.error("Error fetching recent articles:", error)
116+
setSearchState((current) => ({
117+
...current,
118+
isLoading: false,
119+
error:
120+
error instanceof Error
121+
? error.message
122+
: "Failed to fetch recent articles",
123+
}))
124+
})
125+
126+
return loadingState
127+
}
128+
return prev
129+
})
130+
}, [])
131+
132+
// Fetch recent articles on mount when no search is active
133+
useEffect(() => {
134+
fetchRecentArticles()
135+
// eslint-disable-next-line react-hooks/exhaustive-deps
136+
}, []) // Only run on mount
137+
138+
// Refetch recent articles when time filter changes (if no active search)
139+
useEffect(() => {
140+
if (
141+
shouldTriggerSearch.current &&
142+
searchState.topics.length === 0 &&
143+
!searchState.textQuery
144+
) {
145+
shouldTriggerSearch.current = false
146+
fetchRecentArticles()
147+
}
148+
}, [
149+
searchState.timeFilter,
150+
searchState.topics.length,
151+
searchState.textQuery,
152+
fetchRecentArticles,
153+
])
154+
83155
const performTextSearch = useCallback(
84156
async (query: string) => {
85157
setSearchState((prev) => ({ ...prev, isLoading: true, error: null }))
@@ -184,6 +256,10 @@ export default function DiscoverPage() {
184256
articles: [],
185257
error: null,
186258
}))
259+
// If switching away from search with no active search, fetch recent articles
260+
if (searchState.topics.length === 0 && !searchState.textQuery) {
261+
shouldTriggerSearch.current = true
262+
}
187263
}
188264

189265
const handleTopicsChange = (topics: string[]) => {
@@ -192,6 +268,10 @@ export default function DiscoverPage() {
192268

193269
const handleTimeFilterChange = (timeFilter: TimeFilter) => {
194270
setSearchState((prev) => ({ ...prev, timeFilter }))
271+
// If no active search, refetch recent articles with new time filter
272+
if (searchState.topics.length === 0 && !searchState.textQuery) {
273+
shouldTriggerSearch.current = true
274+
}
195275
}
196276

197277
const handleSortChange = (sortBy: SortBy) => {
@@ -210,6 +290,9 @@ export default function DiscoverPage() {
210290
searchState.textQuery.length >= 3
211291
) {
212292
performTextSearch(searchState.textQuery)
293+
} else if (searchState.topics.length === 0 && !searchState.textQuery) {
294+
// Refetch recent articles if no active search
295+
fetchRecentArticles()
213296
}
214297
}
215298
}, [
@@ -219,6 +302,7 @@ export default function DiscoverPage() {
219302
searchState.textQuery,
220303
performTopicSearch,
221304
performTextSearch,
305+
fetchRecentArticles,
222306
])
223307

224308
const handleTextQueryChange = (textQuery: string) => {
@@ -275,7 +359,7 @@ export default function DiscoverPage() {
275359
: "text-foreground opacity-50"
276360
}`}
277361
>
278-
<TrendingUp className="h-4 w-4 text-primary sm:size-6" />
362+
<TrendingUp className="sm:size-6 h-4 w-4 text-primary" />
279363
<span className="whitespace-nowrap">By Topics</span>
280364
</Button>
281365
<Button
@@ -288,7 +372,7 @@ export default function DiscoverPage() {
288372
: "text-foreground opacity-50"
289373
}`}
290374
>
291-
<Search className="h-4 w-4 text-primary sm:size-6" />
375+
<Search className="sm:size-6 h-4 w-4 text-primary" />
292376
<span className="whitespace-nowrap">Vector Search</span>
293377
</Button>
294378
</div>
@@ -406,6 +490,28 @@ export default function DiscoverPage() {
406490
</Card>
407491
)}
408492

493+
{/* Default View Message */}
494+
{searchState.topics.length === 0 &&
495+
!searchState.textQuery &&
496+
!searchState.isLoading &&
497+
searchState.articles.length > 0 && (
498+
<Card className="mb-6 border-blue-200 bg-blue-50 dark:border-blue-800 dark:bg-blue-900/20">
499+
<CardContent className="p-4">
500+
<p className="text-sm text-blue-800 dark:text-blue-200">
501+
<span className="font-medium">
502+
Displaying most recent news from{" "}
503+
{TIME_FILTER_OPTIONS.find(
504+
(opt) => opt.value === searchState.timeFilter
505+
)?.label.toLowerCase()}
506+
.
507+
</span>{" "}
508+
Select topics and search articles, or adjust the time filter
509+
to explore more content.
510+
</p>
511+
</CardContent>
512+
</Card>
513+
)}
514+
409515
{/* Active Filters Display */}
410516
{(searchState.topics.length > 0 || searchState.textQuery) && (
411517
<Card className="mb-6">
@@ -429,7 +535,7 @@ export default function DiscoverPage() {
429535
)}
430536

431537
<Badge variant="outline">
432-
<Clock className="mr-1 w-3 h-3" />
538+
<Clock className="mr-1 h-3 w-3" />
433539
{
434540
TIME_FILTER_OPTIONS.find(
435541
(opt) => opt.value === searchState.timeFilter
@@ -438,7 +544,7 @@ export default function DiscoverPage() {
438544
</Badge>
439545

440546
<Badge variant="outline">
441-
<Filter className="mr-1 w-3 h-3" />
547+
<Filter className="mr-1 h-3 w-3" />
442548
{searchState.sortBy === "score"
443549
? "Most Relevant"
444550
: "Most Recent"}

app/not-found.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ export default function NotFound() {
1010
<div className="container mx-auto max-w-2xl text-center">
1111
<Card className="border-primary/20 from-primary/5 to-secondary/5 bg-gradient-to-br">
1212
<CardHeader className="text-center">
13-
<div className="from-primary/20 to-secondary/20 mx-auto mb-4 flex size-20 items-center justify-center rounded-full bg-gradient-to-br">
13+
<div className="from-primary/20 to-secondary/20 size-20 mx-auto mb-4 flex items-center justify-center rounded-full bg-gradient-to-br">
1414
<div className="text-4xl">🤔</div>
1515
</div>
1616
<CardTitle className="text-4xl font-bold text-foreground">

app/page.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,10 @@ export default function UselessFactsHome() {
1212
{/* Hero Section */}
1313
<section className="px-4 py-8">
1414
<div className="container mx-auto max-w-4xl text-center">
15-
<h2 className="mb-6 text-balance text-3xl font-semibold text-foreground">
15+
<h2 className="text-balance mb-6 text-3xl font-semibold text-foreground">
1616
Discover Facts You&apos;ll Never Need
1717
</h2>
18-
<p className="mb-6 text-pretty text-xl text-muted-foreground">
18+
<p className="text-pretty mb-6 text-xl text-muted-foreground">
1919
Expand your mind with wonderfully pointless information that&apos;s
2020
guaranteed to impress absolutely no one.
2121
</p>
@@ -38,7 +38,7 @@ export default function UselessFactsHome() {
3838
</Link>{" "}
3939
to discover the most loved and hated facts in our collection.
4040
</p>
41-
<p className="mt-6 text-pretty text-lg text-muted-foreground">
41+
<p className="text-pretty mt-6 text-lg text-muted-foreground">
4242
Prefer to browse everything yourself? Explore our full catalog on
4343
the{" "}
4444
<Link

components/article-list.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,7 @@ export function ArticleList({
152152
<Card className="border-muted">
153153
<CardContent className="p-8">
154154
<div className="text-center">
155-
<div className="bg-muted/50 mx-auto mb-4 flex size-12 items-center justify-center rounded-full">
155+
<div className="bg-muted/50 size-12 mx-auto mb-4 flex items-center justify-center rounded-full">
156156
<TrendingUp className="size-6 text-muted-foreground" />
157157
</div>
158158
<h3 className="mb-2 text-lg font-semibold">No articles found</h3>
@@ -265,7 +265,7 @@ export function ArticleList({
265265
variant="outline"
266266
className="border-blue-200 bg-blue-100 text-xs text-blue-800 hover:bg-blue-200 dark:border-blue-800 dark:bg-blue-900/20 dark:text-blue-300 dark:hover:bg-blue-900/30"
267267
>
268-
<Hash className="mr-1 w-3 h-3" />
268+
<Hash className="mr-1 h-3 w-3" />
269269
{topic}
270270
</Badge>
271271
))}

0 commit comments

Comments
 (0)