Some fixes

This commit is contained in:
2025-06-11 23:03:40 +09:00
parent 71d3f1912d
commit 6e2700fe3d
8 changed files with 423 additions and 193 deletions

View File

@ -1,5 +1,5 @@
import { Link, Route, Routes, useLocation } from "react-router-dom";
import { useEffect, useState } from "react";
import { Link, Route, Routes, useLocation } from "react-router-dom";
import EpisodeDetail from "./components/EpisodeDetail";
import EpisodeList from "./components/EpisodeList";
import FeedDetail from "./components/FeedDetail";
@ -10,13 +10,16 @@ import RSSEndpoints from "./components/RSSEndpoints";
function App() {
const location = useLocation();
const [isDarkMode, setIsDarkMode] = useState(() => {
const saved = localStorage.getItem('darkMode');
const saved = localStorage.getItem("darkMode");
return saved ? JSON.parse(saved) : false;
});
useEffect(() => {
document.documentElement.setAttribute('data-theme', isDarkMode ? 'dark' : 'light');
localStorage.setItem('darkMode', JSON.stringify(isDarkMode));
document.documentElement.setAttribute(
"data-theme",
isDarkMode ? "dark" : "light",
);
localStorage.setItem("darkMode", JSON.stringify(isDarkMode));
}, [isDarkMode]);
const toggleDarkMode = () => {
@ -41,12 +44,12 @@ function App() {
RSS
</div>
</div>
<button
<button
className="theme-toggle"
onClick={toggleDarkMode}
aria-label="テーマを切り替え"
>
{isDarkMode ? '☀️' : '🌙'}
{isDarkMode ? "☀️" : "🌙"}
</button>
</div>
</div>

View File

@ -63,7 +63,7 @@ function EpisodeList() {
filterEpisodesByCategory();
}
}, [episodes, selectedCategory, searchQuery]);
// Reset to page 1 when category changes (but don't trigger if already on page 1)
useEffect(() => {
if (currentPage !== 1) {
@ -85,28 +85,30 @@ function EpisodeList() {
page: currentPage.toString(),
limit: pageSize.toString(),
});
if (selectedCategory) {
searchParams.append("category", selectedCategory);
}
const response = await fetch(`/api/episodes-with-feed-info?${searchParams}`);
const response = await fetch(
`/api/episodes-with-feed-info?${searchParams}`,
);
if (!response.ok) {
throw new Error("データベースからの取得に失敗しました");
}
const data = await response.json();
// Handle paginated response
if (data.episodes !== undefined) {
const dbEpisodes = data.episodes || [];
if (dbEpisodes.length === 0 && data.total === 0) {
// Database is empty, fallback to XML
console.log("Database is empty, falling back to XML parsing...");
setUseDatabase(false);
return;
}
setEpisodes(dbEpisodes);
setTotalEpisodes(data.total || 0);
setTotalPages(data.totalPages || 1);
@ -402,9 +404,7 @@ function EpisodeList() {
))}
</select>
)}
{isSearching && (
<span className="episode-meta-text">...</span>
)}
{isSearching && <span className="episode-meta-text">...</span>}
</div>
</div>
@ -527,7 +527,7 @@ function EpisodeList() {
))}
</tbody>
</table>
{/* Pagination Controls - only show for database mode */}
{useDatabase && totalPages > 1 && (
<div className="pagination-container">
@ -538,7 +538,7 @@ function EpisodeList() {
>
</button>
{/* Page numbers */}
<div className="pagination-pages">
{/* First page */}
@ -553,13 +553,13 @@ function EpisodeList() {
{currentPage > 4 && <span>...</span>}
</>
)}
{/* Current page and nearby pages */}
{Array.from({ length: Math.min(5, totalPages) }, (_, i) => {
const pageNum = Math.max(1, currentPage - 2) + i;
if (pageNum > totalPages) return null;
if (pageNum < Math.max(1, currentPage - 2)) return null;
return (
<button
key={pageNum}
@ -570,7 +570,7 @@ function EpisodeList() {
</button>
);
})}
{/* Last page */}
{currentPage < totalPages - 2 && (
<>
@ -584,15 +584,17 @@ function EpisodeList() {
</>
)}
</div>
<button
className="btn btn-secondary"
onClick={() => setCurrentPage(Math.min(totalPages, currentPage + 1))}
onClick={() =>
setCurrentPage(Math.min(totalPages, currentPage + 1))
}
disabled={currentPage === totalPages}
>
</button>
{/* Page size selector */}
<div className="pagination-size-selector">
<span style={{ fontSize: "14px" }}>:</span>

View File

@ -222,7 +222,10 @@ function FeedDetail() {
<strong>
<Link
to={`/episode/${episode.id}`}
style={{ textDecoration: "none", color: "var(--accent-primary)" }}
style={{
textDecoration: "none",
color: "var(--accent-primary)",
}}
>
{episode.title}
</Link>
@ -242,7 +245,10 @@ function FeedDetail() {
href={episode.articleLink}
target="_blank"
rel="noopener noreferrer"
style={{ fontSize: "12px", color: "var(--text-secondary)" }}
style={{
fontSize: "12px",
color: "var(--text-secondary)",
}}
>
</a>

View File

@ -19,7 +19,7 @@ function FeedList() {
const [selectedCategory, setSelectedCategory] = useState<string>("");
const [loading, setLoading] = useState(true);
const [error, setError] = useState<string | null>(null);
// Pagination state
const [currentPage, setCurrentPage] = useState(1);
const [pageSize, setPageSize] = useState(15);
@ -46,7 +46,7 @@ function FeedList() {
try {
setLoading(true);
setError(null);
// Build query parameters
const params = new URLSearchParams();
params.append("page", currentPage.toString());
@ -54,17 +54,17 @@ function FeedList() {
if (selectedCategory) {
params.append("category", selectedCategory);
}
const response = await fetch(`/api/feeds?${params.toString()}`);
if (!response.ok) {
const errorData = await response.json();
throw new Error(errorData.error || "フィードの取得に失敗しました");
}
const data = await response.json();
// Handle paginated response
if (data.feeds && typeof data.total !== 'undefined') {
if (data.feeds && typeof data.total !== "undefined") {
setFeeds(data.feeds);
setFilteredFeeds(data.feeds);
setTotalFeeds(data.total);
@ -96,7 +96,6 @@ function FeedList() {
}
};
const formatDate = (dateString: string) => {
return new Date(dateString).toLocaleString("ja-JP");
};
@ -197,7 +196,11 @@ function FeedList() {
<option value={45}>45</option>
<option value={60}>60</option>
</select>
<button type="button" className="btn btn-secondary" onClick={fetchFeeds}>
<button
type="button"
className="btn btn-secondary"
onClick={fetchFeeds}
>
</button>
</div>
@ -268,7 +271,7 @@ function FeedList() {
>
</button>
{/* Page numbers */}
<div className="page-numbers">
{Array.from({ length: Math.min(5, totalPages) }, (_, i) => {
@ -282,12 +285,12 @@ function FeedList() {
} else {
pageNum = currentPage - 2 + i;
}
return (
<button
type="button"
key={pageNum}
className={`btn ${currentPage === pageNum ? 'btn-primary' : 'btn-secondary'}`}
className={`btn ${currentPage === pageNum ? "btn-primary" : "btn-secondary"}`}
onClick={() => setCurrentPage(pageNum)}
>
{pageNum}
@ -295,7 +298,7 @@ function FeedList() {
);
})}
</div>
<button
type="button"
className="btn btn-secondary"