Some fixes
This commit is contained in:
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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"
|
||||
|
Reference in New Issue
Block a user