Support dark mode in the frontend
This commit is contained in:
		@@ -1,4 +1,5 @@
 | 
				
			|||||||
import { Link, Route, Routes, useLocation } from "react-router-dom";
 | 
					import { Link, Route, Routes, useLocation } from "react-router-dom";
 | 
				
			||||||
 | 
					import { useEffect, useState } from "react";
 | 
				
			||||||
import EpisodeDetail from "./components/EpisodeDetail";
 | 
					import EpisodeDetail from "./components/EpisodeDetail";
 | 
				
			||||||
import EpisodeList from "./components/EpisodeList";
 | 
					import EpisodeList from "./components/EpisodeList";
 | 
				
			||||||
import FeedDetail from "./components/FeedDetail";
 | 
					import FeedDetail from "./components/FeedDetail";
 | 
				
			||||||
@@ -8,6 +9,19 @@ import RSSEndpoints from "./components/RSSEndpoints";
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
function App() {
 | 
					function App() {
 | 
				
			||||||
  const location = useLocation();
 | 
					  const location = useLocation();
 | 
				
			||||||
 | 
					  const [isDarkMode, setIsDarkMode] = useState(() => {
 | 
				
			||||||
 | 
					    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));
 | 
				
			||||||
 | 
					  }, [isDarkMode]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const toggleDarkMode = () => {
 | 
				
			||||||
 | 
					    setIsDarkMode(!isDarkMode);
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
  const isMainPage = [
 | 
					  const isMainPage = [
 | 
				
			||||||
    "/",
 | 
					    "/",
 | 
				
			||||||
    "/feeds",
 | 
					    "/feeds",
 | 
				
			||||||
@@ -20,9 +34,20 @@ function App() {
 | 
				
			|||||||
      {isMainPage && (
 | 
					      {isMainPage && (
 | 
				
			||||||
        <>
 | 
					        <>
 | 
				
			||||||
          <div className="header">
 | 
					          <div className="header">
 | 
				
			||||||
            <div className="title">Voice RSS Summary</div>
 | 
					            <div className="header-content">
 | 
				
			||||||
            <div className="subtitle">
 | 
					              <div className="header-text">
 | 
				
			||||||
              RSS フィードから自動生成された音声ポッドキャスト
 | 
					                <div className="title">Voice RSS Summary</div>
 | 
				
			||||||
 | 
					                <div className="subtitle">
 | 
				
			||||||
 | 
					                  RSS フィードから自動生成された音声ポッドキャスト
 | 
				
			||||||
 | 
					                </div>
 | 
				
			||||||
 | 
					              </div>
 | 
				
			||||||
 | 
					              <button 
 | 
				
			||||||
 | 
					                className="theme-toggle"
 | 
				
			||||||
 | 
					                onClick={toggleDarkMode}
 | 
				
			||||||
 | 
					                aria-label="テーマを切り替え"
 | 
				
			||||||
 | 
					              >
 | 
				
			||||||
 | 
					                {isDarkMode ? '☀️' : '🌙'}
 | 
				
			||||||
 | 
					              </button>
 | 
				
			||||||
            </div>
 | 
					            </div>
 | 
				
			||||||
          </div>
 | 
					          </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -345,20 +345,9 @@ function EpisodeList() {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  return (
 | 
					  return (
 | 
				
			||||||
    <div>
 | 
					    <div>
 | 
				
			||||||
      <div
 | 
					      <div style={{ marginBottom: "20px" }}>
 | 
				
			||||||
        style={{
 | 
					        <div className="episode-header">
 | 
				
			||||||
          marginBottom: "20px",
 | 
					          <h2 className="episode-title">
 | 
				
			||||||
        }}
 | 
					 | 
				
			||||||
      >
 | 
					 | 
				
			||||||
        <div
 | 
					 | 
				
			||||||
          style={{
 | 
					 | 
				
			||||||
            display: "flex",
 | 
					 | 
				
			||||||
            justifyContent: "space-between",
 | 
					 | 
				
			||||||
            alignItems: "center",
 | 
					 | 
				
			||||||
            marginBottom: "15px",
 | 
					 | 
				
			||||||
          }}
 | 
					 | 
				
			||||||
        >
 | 
					 | 
				
			||||||
          <h2>
 | 
					 | 
				
			||||||
            エピソード一覧 (
 | 
					            エピソード一覧 (
 | 
				
			||||||
            {searchQuery
 | 
					            {searchQuery
 | 
				
			||||||
              ? `検索結果: ${filteredEpisodes.length}件`
 | 
					              ? `検索結果: ${filteredEpisodes.length}件`
 | 
				
			||||||
@@ -369,8 +358,8 @@ function EpisodeList() {
 | 
				
			|||||||
                  : `${episodes.length}件`}
 | 
					                  : `${episodes.length}件`}
 | 
				
			||||||
            )
 | 
					            )
 | 
				
			||||||
          </h2>
 | 
					          </h2>
 | 
				
			||||||
          <div style={{ display: "flex", gap: "10px", alignItems: "center" }}>
 | 
					          <div className="episode-meta">
 | 
				
			||||||
            <span style={{ fontSize: "12px", color: "#666" }}>
 | 
					            <span className="episode-meta-text">
 | 
				
			||||||
              データソース: {useDatabase ? "データベース" : "XML"}
 | 
					              データソース: {useDatabase ? "データベース" : "XML"}
 | 
				
			||||||
            </span>
 | 
					            </span>
 | 
				
			||||||
            <button className="btn btn-secondary" onClick={fetchEpisodes}>
 | 
					            <button className="btn btn-secondary" onClick={fetchEpisodes}>
 | 
				
			||||||
@@ -379,27 +368,13 @@ function EpisodeList() {
 | 
				
			|||||||
          </div>
 | 
					          </div>
 | 
				
			||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        <div
 | 
					        <div className="episode-search-bar">
 | 
				
			||||||
          style={{
 | 
					 | 
				
			||||||
            display: "flex",
 | 
					 | 
				
			||||||
            gap: "10px",
 | 
					 | 
				
			||||||
            alignItems: "center",
 | 
					 | 
				
			||||||
            flexWrap: "wrap",
 | 
					 | 
				
			||||||
          }}
 | 
					 | 
				
			||||||
        >
 | 
					 | 
				
			||||||
          <input
 | 
					          <input
 | 
				
			||||||
            type="text"
 | 
					            type="text"
 | 
				
			||||||
            placeholder="エピソードを検索..."
 | 
					            placeholder="エピソードを検索..."
 | 
				
			||||||
            value={searchQuery}
 | 
					            value={searchQuery}
 | 
				
			||||||
            onChange={(e) => setSearchQuery(e.target.value)}
 | 
					            onChange={(e) => setSearchQuery(e.target.value)}
 | 
				
			||||||
            style={{
 | 
					            className="episode-search-input"
 | 
				
			||||||
              flex: "1",
 | 
					 | 
				
			||||||
              minWidth: "200px",
 | 
					 | 
				
			||||||
              padding: "8px 12px",
 | 
					 | 
				
			||||||
              fontSize: "14px",
 | 
					 | 
				
			||||||
              border: "1px solid #ccc",
 | 
					 | 
				
			||||||
              borderRadius: "4px",
 | 
					 | 
				
			||||||
            }}
 | 
					 | 
				
			||||||
          />
 | 
					          />
 | 
				
			||||||
          {searchQuery && (
 | 
					          {searchQuery && (
 | 
				
			||||||
            <button
 | 
					            <button
 | 
				
			||||||
@@ -417,13 +392,7 @@ function EpisodeList() {
 | 
				
			|||||||
            <select
 | 
					            <select
 | 
				
			||||||
              value={selectedCategory}
 | 
					              value={selectedCategory}
 | 
				
			||||||
              onChange={(e) => setSelectedCategory(e.target.value)}
 | 
					              onChange={(e) => setSelectedCategory(e.target.value)}
 | 
				
			||||||
              style={{
 | 
					              className="episode-category-select"
 | 
				
			||||||
                padding: "8px 12px",
 | 
					 | 
				
			||||||
                fontSize: "14px",
 | 
					 | 
				
			||||||
                border: "1px solid #ccc",
 | 
					 | 
				
			||||||
                borderRadius: "4px",
 | 
					 | 
				
			||||||
                minWidth: "120px",
 | 
					 | 
				
			||||||
              }}
 | 
					 | 
				
			||||||
            >
 | 
					            >
 | 
				
			||||||
              <option value="">全カテゴリ</option>
 | 
					              <option value="">全カテゴリ</option>
 | 
				
			||||||
              {categories.map((category) => (
 | 
					              {categories.map((category) => (
 | 
				
			||||||
@@ -434,7 +403,7 @@ function EpisodeList() {
 | 
				
			|||||||
            </select>
 | 
					            </select>
 | 
				
			||||||
          )}
 | 
					          )}
 | 
				
			||||||
          {isSearching && (
 | 
					          {isSearching && (
 | 
				
			||||||
            <span style={{ fontSize: "14px", color: "#666" }}>検索中...</span>
 | 
					            <span className="episode-meta-text">検索中...</span>
 | 
				
			||||||
          )}
 | 
					          )}
 | 
				
			||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
      </div>
 | 
					      </div>
 | 
				
			||||||
@@ -456,24 +425,18 @@ function EpisodeList() {
 | 
				
			|||||||
                  <strong>
 | 
					                  <strong>
 | 
				
			||||||
                    <Link
 | 
					                    <Link
 | 
				
			||||||
                      to={`/episode/${episode.id}`}
 | 
					                      to={`/episode/${episode.id}`}
 | 
				
			||||||
                      style={{ textDecoration: "none", color: "#007bff" }}
 | 
					                      className="episode-link"
 | 
				
			||||||
                    >
 | 
					                    >
 | 
				
			||||||
                      {episode.title}
 | 
					                      {episode.title}
 | 
				
			||||||
                    </Link>
 | 
					                    </Link>
 | 
				
			||||||
                  </strong>
 | 
					                  </strong>
 | 
				
			||||||
                </div>
 | 
					                </div>
 | 
				
			||||||
                {episode.feedTitle && (
 | 
					                {episode.feedTitle && (
 | 
				
			||||||
                  <div
 | 
					                  <div className="episode-feed-info">
 | 
				
			||||||
                    style={{
 | 
					 | 
				
			||||||
                      fontSize: "12px",
 | 
					 | 
				
			||||||
                      color: "#666",
 | 
					 | 
				
			||||||
                      marginBottom: "4px",
 | 
					 | 
				
			||||||
                    }}
 | 
					 | 
				
			||||||
                  >
 | 
					 | 
				
			||||||
                    フィード:{" "}
 | 
					                    フィード:{" "}
 | 
				
			||||||
                    <Link
 | 
					                    <Link
 | 
				
			||||||
                      to={`/feeds/${episode.feedId}`}
 | 
					                      to={`/feeds/${episode.feedId}`}
 | 
				
			||||||
                      style={{ color: "#007bff" }}
 | 
					                      className="episode-link"
 | 
				
			||||||
                    >
 | 
					                    >
 | 
				
			||||||
                      {episode.feedTitle}
 | 
					                      {episode.feedTitle}
 | 
				
			||||||
                    </Link>
 | 
					                    </Link>
 | 
				
			||||||
@@ -481,7 +444,7 @@ function EpisodeList() {
 | 
				
			|||||||
                      <span
 | 
					                      <span
 | 
				
			||||||
                        style={{
 | 
					                        style={{
 | 
				
			||||||
                          marginLeft: "8px",
 | 
					                          marginLeft: "8px",
 | 
				
			||||||
                          color: "#999",
 | 
					                          color: "var(--text-muted)",
 | 
				
			||||||
                          fontSize: "11px",
 | 
					                          fontSize: "11px",
 | 
				
			||||||
                        }}
 | 
					                        }}
 | 
				
			||||||
                      >
 | 
					                      >
 | 
				
			||||||
@@ -492,13 +455,7 @@ function EpisodeList() {
 | 
				
			|||||||
                )}
 | 
					                )}
 | 
				
			||||||
                {episode.articleTitle &&
 | 
					                {episode.articleTitle &&
 | 
				
			||||||
                  episode.articleTitle !== episode.title && (
 | 
					                  episode.articleTitle !== episode.title && (
 | 
				
			||||||
                    <div
 | 
					                    <div className="episode-article-info">
 | 
				
			||||||
                      style={{
 | 
					 | 
				
			||||||
                        fontSize: "12px",
 | 
					 | 
				
			||||||
                        color: "#666",
 | 
					 | 
				
			||||||
                        marginBottom: "4px",
 | 
					 | 
				
			||||||
                      }}
 | 
					 | 
				
			||||||
                    >
 | 
					 | 
				
			||||||
                      元記事: <strong>{episode.articleTitle}</strong>
 | 
					                      元記事: <strong>{episode.articleTitle}</strong>
 | 
				
			||||||
                    </div>
 | 
					                    </div>
 | 
				
			||||||
                  )}
 | 
					                  )}
 | 
				
			||||||
@@ -507,46 +464,26 @@ function EpisodeList() {
 | 
				
			|||||||
                    href={episode.articleLink}
 | 
					                    href={episode.articleLink}
 | 
				
			||||||
                    target="_blank"
 | 
					                    target="_blank"
 | 
				
			||||||
                    rel="noopener noreferrer"
 | 
					                    rel="noopener noreferrer"
 | 
				
			||||||
                    style={{ fontSize: "12px", color: "#666" }}
 | 
					                    className="episode-article-link"
 | 
				
			||||||
                  >
 | 
					                  >
 | 
				
			||||||
                    元記事を見る
 | 
					                    元記事を見る
 | 
				
			||||||
                  </a>
 | 
					                  </a>
 | 
				
			||||||
                )}
 | 
					                )}
 | 
				
			||||||
              </td>
 | 
					              </td>
 | 
				
			||||||
              <td>
 | 
					              <td>
 | 
				
			||||||
                <div
 | 
					                <div className="episode-description">
 | 
				
			||||||
                  style={{
 | 
					 | 
				
			||||||
                    fontSize: "14px",
 | 
					 | 
				
			||||||
                    maxWidth: "200px",
 | 
					 | 
				
			||||||
                    overflow: "hidden",
 | 
					 | 
				
			||||||
                    textOverflow: "ellipsis",
 | 
					 | 
				
			||||||
                    whiteSpace: "nowrap",
 | 
					 | 
				
			||||||
                  }}
 | 
					 | 
				
			||||||
                >
 | 
					 | 
				
			||||||
                  {episode.description || "No description"}
 | 
					                  {episode.description || "No description"}
 | 
				
			||||||
                </div>
 | 
					                </div>
 | 
				
			||||||
                {episode.fileSize && (
 | 
					                {episode.fileSize && (
 | 
				
			||||||
                  <div
 | 
					                  <div className="episode-file-size">
 | 
				
			||||||
                    style={{
 | 
					 | 
				
			||||||
                      fontSize: "12px",
 | 
					 | 
				
			||||||
                      color: "#666",
 | 
					 | 
				
			||||||
                      marginTop: "4px",
 | 
					 | 
				
			||||||
                    }}
 | 
					 | 
				
			||||||
                  >
 | 
					 | 
				
			||||||
                    {formatFileSize(episode.fileSize)}
 | 
					                    {formatFileSize(episode.fileSize)}
 | 
				
			||||||
                  </div>
 | 
					                  </div>
 | 
				
			||||||
                )}
 | 
					                )}
 | 
				
			||||||
              </td>
 | 
					              </td>
 | 
				
			||||||
              <td>{formatDate(episode.createdAt)}</td>
 | 
					              <td>{formatDate(episode.createdAt)}</td>
 | 
				
			||||||
              <td>
 | 
					              <td>
 | 
				
			||||||
                <div
 | 
					                <div className="episode-actions">
 | 
				
			||||||
                  style={{
 | 
					                  <div className="episode-action-buttons">
 | 
				
			||||||
                    display: "flex",
 | 
					 | 
				
			||||||
                    gap: "8px",
 | 
					 | 
				
			||||||
                    flexDirection: "column",
 | 
					 | 
				
			||||||
                  }}
 | 
					 | 
				
			||||||
                >
 | 
					 | 
				
			||||||
                  <div style={{ display: "flex", gap: "8px" }}>
 | 
					 | 
				
			||||||
                    <button
 | 
					                    <button
 | 
				
			||||||
                      className="btn btn-primary"
 | 
					                      className="btn btn-primary"
 | 
				
			||||||
                      onClick={() =>
 | 
					                      onClick={() =>
 | 
				
			||||||
@@ -593,16 +530,7 @@ function EpisodeList() {
 | 
				
			|||||||
      
 | 
					      
 | 
				
			||||||
      {/* Pagination Controls - only show for database mode */}
 | 
					      {/* Pagination Controls - only show for database mode */}
 | 
				
			||||||
      {useDatabase && totalPages > 1 && (
 | 
					      {useDatabase && totalPages > 1 && (
 | 
				
			||||||
        <div
 | 
					        <div className="pagination-container">
 | 
				
			||||||
          style={{
 | 
					 | 
				
			||||||
            marginTop: "20px",
 | 
					 | 
				
			||||||
            display: "flex",
 | 
					 | 
				
			||||||
            justifyContent: "center",
 | 
					 | 
				
			||||||
            alignItems: "center",
 | 
					 | 
				
			||||||
            gap: "10px",
 | 
					 | 
				
			||||||
            flexWrap: "wrap",
 | 
					 | 
				
			||||||
          }}
 | 
					 | 
				
			||||||
        >
 | 
					 | 
				
			||||||
          <button
 | 
					          <button
 | 
				
			||||||
            className="btn btn-secondary"
 | 
					            className="btn btn-secondary"
 | 
				
			||||||
            onClick={() => setCurrentPage(Math.max(1, currentPage - 1))}
 | 
					            onClick={() => setCurrentPage(Math.max(1, currentPage - 1))}
 | 
				
			||||||
@@ -612,7 +540,7 @@ function EpisodeList() {
 | 
				
			|||||||
          </button>
 | 
					          </button>
 | 
				
			||||||
          
 | 
					          
 | 
				
			||||||
          {/* Page numbers */}
 | 
					          {/* Page numbers */}
 | 
				
			||||||
          <div style={{ display: "flex", gap: "5px", alignItems: "center" }}>
 | 
					          <div className="pagination-pages">
 | 
				
			||||||
            {/* First page */}
 | 
					            {/* First page */}
 | 
				
			||||||
            {currentPage > 3 && (
 | 
					            {currentPage > 3 && (
 | 
				
			||||||
              <>
 | 
					              <>
 | 
				
			||||||
@@ -635,11 +563,8 @@ function EpisodeList() {
 | 
				
			|||||||
              return (
 | 
					              return (
 | 
				
			||||||
                <button
 | 
					                <button
 | 
				
			||||||
                  key={pageNum}
 | 
					                  key={pageNum}
 | 
				
			||||||
                  className={`btn ${currentPage === pageNum ? "btn-primary" : "btn-secondary"}`}
 | 
					                  className={`btn pagination-page-btn ${currentPage === pageNum ? "btn-primary" : "btn-secondary"}`}
 | 
				
			||||||
                  onClick={() => setCurrentPage(pageNum)}
 | 
					                  onClick={() => setCurrentPage(pageNum)}
 | 
				
			||||||
                  style={{
 | 
					 | 
				
			||||||
                    minWidth: "40px",
 | 
					 | 
				
			||||||
                  }}
 | 
					 | 
				
			||||||
                >
 | 
					                >
 | 
				
			||||||
                  {pageNum}
 | 
					                  {pageNum}
 | 
				
			||||||
                </button>
 | 
					                </button>
 | 
				
			||||||
@@ -669,7 +594,7 @@ function EpisodeList() {
 | 
				
			|||||||
          </button>
 | 
					          </button>
 | 
				
			||||||
          
 | 
					          
 | 
				
			||||||
          {/* Page size selector */}
 | 
					          {/* Page size selector */}
 | 
				
			||||||
          <div style={{ marginLeft: "20px", display: "flex", alignItems: "center", gap: "5px" }}>
 | 
					          <div className="pagination-size-selector">
 | 
				
			||||||
            <span style={{ fontSize: "14px" }}>表示件数:</span>
 | 
					            <span style={{ fontSize: "14px" }}>表示件数:</span>
 | 
				
			||||||
            <select
 | 
					            <select
 | 
				
			||||||
              value={pageSize}
 | 
					              value={pageSize}
 | 
				
			||||||
@@ -677,12 +602,7 @@ function EpisodeList() {
 | 
				
			|||||||
                setPageSize(Number.parseInt(e.target.value, 10));
 | 
					                setPageSize(Number.parseInt(e.target.value, 10));
 | 
				
			||||||
                setCurrentPage(1); // Reset to first page when changing page size
 | 
					                setCurrentPage(1); // Reset to first page when changing page size
 | 
				
			||||||
              }}
 | 
					              }}
 | 
				
			||||||
              style={{
 | 
					              className="pagination-size-select"
 | 
				
			||||||
                padding: "4px 8px",
 | 
					 | 
				
			||||||
                fontSize: "14px",
 | 
					 | 
				
			||||||
                border: "1px solid #ccc",
 | 
					 | 
				
			||||||
                borderRadius: "4px",
 | 
					 | 
				
			||||||
              }}
 | 
					 | 
				
			||||||
            >
 | 
					            >
 | 
				
			||||||
              <option value={10}>10</option>
 | 
					              <option value={10}>10</option>
 | 
				
			||||||
              <option value={20}>20</option>
 | 
					              <option value={20}>20</option>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,3 +1,49 @@
 | 
				
			|||||||
 | 
					:root {
 | 
				
			||||||
 | 
					  /* Light theme colors */
 | 
				
			||||||
 | 
					  --bg-primary: #f5f5f5;
 | 
				
			||||||
 | 
					  --bg-secondary: #fff;
 | 
				
			||||||
 | 
					  --bg-tertiary: #f8f9fa;
 | 
				
			||||||
 | 
					  --text-primary: #333;
 | 
				
			||||||
 | 
					  --text-secondary: #666;
 | 
				
			||||||
 | 
					  --text-muted: #999;
 | 
				
			||||||
 | 
					  --border-color: #e9ecef;
 | 
				
			||||||
 | 
					  --border-light: #ddd;
 | 
				
			||||||
 | 
					  --shadow: rgba(0, 0, 0, 0.1);
 | 
				
			||||||
 | 
					  --accent-primary: #007bff;
 | 
				
			||||||
 | 
					  --accent-primary-hover: #0056b3;
 | 
				
			||||||
 | 
					  --accent-danger: #dc3545;
 | 
				
			||||||
 | 
					  --accent-danger-hover: #c82333;
 | 
				
			||||||
 | 
					  --accent-secondary: #6c757d;
 | 
				
			||||||
 | 
					  --accent-secondary-hover: #545b62;
 | 
				
			||||||
 | 
					  --success-bg: #d4edda;
 | 
				
			||||||
 | 
					  --success-text: #155724;
 | 
				
			||||||
 | 
					  --error-bg: #f8d7da;
 | 
				
			||||||
 | 
					  --error-text: #721c24;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[data-theme="dark"] {
 | 
				
			||||||
 | 
					  /* Dark theme colors */
 | 
				
			||||||
 | 
					  --bg-primary: #1a1a1a;
 | 
				
			||||||
 | 
					  --bg-secondary: #2d2d2d;
 | 
				
			||||||
 | 
					  --bg-tertiary: #3a3a3a;
 | 
				
			||||||
 | 
					  --text-primary: #e0e0e0;
 | 
				
			||||||
 | 
					  --text-secondary: #b0b0b0;
 | 
				
			||||||
 | 
					  --text-muted: #888;
 | 
				
			||||||
 | 
					  --border-color: #444;
 | 
				
			||||||
 | 
					  --border-light: #555;
 | 
				
			||||||
 | 
					  --shadow: rgba(0, 0, 0, 0.3);
 | 
				
			||||||
 | 
					  --accent-primary: #4dabf7;
 | 
				
			||||||
 | 
					  --accent-primary-hover: #339af0;
 | 
				
			||||||
 | 
					  --accent-danger: #f03e3e;
 | 
				
			||||||
 | 
					  --accent-danger-hover: #e03131;
 | 
				
			||||||
 | 
					  --accent-secondary: #868e96;
 | 
				
			||||||
 | 
					  --accent-secondary-hover: #adb5bd;
 | 
				
			||||||
 | 
					  --success-bg: #2b5a3b;
 | 
				
			||||||
 | 
					  --success-text: #a3d9a5;
 | 
				
			||||||
 | 
					  --error-bg: #5a2b2b;
 | 
				
			||||||
 | 
					  --error-text: #f1aeb5;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
* {
 | 
					* {
 | 
				
			||||||
  margin: 0;
 | 
					  margin: 0;
 | 
				
			||||||
  padding: 0;
 | 
					  padding: 0;
 | 
				
			||||||
@@ -6,9 +52,10 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
body {
 | 
					body {
 | 
				
			||||||
  font-family: system-ui, -apple-system, sans-serif;
 | 
					  font-family: system-ui, -apple-system, sans-serif;
 | 
				
			||||||
  background-color: #f5f5f5;
 | 
					  background-color: var(--bg-primary);
 | 
				
			||||||
  color: #333;
 | 
					  color: var(--text-primary);
 | 
				
			||||||
  line-height: 1.6;
 | 
					  line-height: 1.6;
 | 
				
			||||||
 | 
					  transition: background-color 0.3s ease, color 0.3s ease;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.container {
 | 
					.container {
 | 
				
			||||||
@@ -18,30 +65,65 @@ body {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.header {
 | 
					.header {
 | 
				
			||||||
  background-color: #fff;
 | 
					  background-color: var(--bg-secondary);
 | 
				
			||||||
  border-radius: 8px;
 | 
					  border-radius: 8px;
 | 
				
			||||||
  padding: 20px;
 | 
					  padding: 20px;
 | 
				
			||||||
  margin-bottom: 20px;
 | 
					  margin-bottom: 20px;
 | 
				
			||||||
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
 | 
					  box-shadow: 0 2px 4px var(--shadow);
 | 
				
			||||||
 | 
					  transition: background-color 0.3s ease, box-shadow 0.3s ease;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.header-content {
 | 
				
			||||||
 | 
					  display: flex;
 | 
				
			||||||
 | 
					  justify-content: space-between;
 | 
				
			||||||
 | 
					  align-items: center;
 | 
				
			||||||
 | 
					  gap: 20px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.header-text {
 | 
				
			||||||
 | 
					  flex: 1;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.title {
 | 
					.title {
 | 
				
			||||||
  font-size: 24px;
 | 
					  font-size: 24px;
 | 
				
			||||||
  font-weight: bold;
 | 
					  font-weight: bold;
 | 
				
			||||||
  margin-bottom: 8px;
 | 
					  margin-bottom: 8px;
 | 
				
			||||||
 | 
					  color: var(--text-primary);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.subtitle {
 | 
					.subtitle {
 | 
				
			||||||
  color: #666;
 | 
					  color: var(--text-secondary);
 | 
				
			||||||
  font-size: 14px;
 | 
					  font-size: 14px;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.theme-toggle {
 | 
				
			||||||
 | 
					  background: var(--bg-tertiary);
 | 
				
			||||||
 | 
					  border: 1px solid var(--border-color);
 | 
				
			||||||
 | 
					  border-radius: 50%;
 | 
				
			||||||
 | 
					  width: 50px;
 | 
				
			||||||
 | 
					  height: 50px;
 | 
				
			||||||
 | 
					  display: flex;
 | 
				
			||||||
 | 
					  align-items: center;
 | 
				
			||||||
 | 
					  justify-content: center;
 | 
				
			||||||
 | 
					  cursor: pointer;
 | 
				
			||||||
 | 
					  font-size: 20px;
 | 
				
			||||||
 | 
					  transition: all 0.3s ease;
 | 
				
			||||||
 | 
					  flex-shrink: 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.theme-toggle:hover {
 | 
				
			||||||
 | 
					  transform: scale(1.1);
 | 
				
			||||||
 | 
					  background: var(--accent-primary);
 | 
				
			||||||
 | 
					  color: white;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.tabs {
 | 
					.tabs {
 | 
				
			||||||
  display: flex;
 | 
					  display: flex;
 | 
				
			||||||
  background-color: #fff;
 | 
					  background-color: var(--bg-secondary);
 | 
				
			||||||
  border-radius: 8px;
 | 
					  border-radius: 8px;
 | 
				
			||||||
  margin-bottom: 20px;
 | 
					  margin-bottom: 20px;
 | 
				
			||||||
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
 | 
					  box-shadow: 0 2px 4px var(--shadow);
 | 
				
			||||||
 | 
					  transition: background-color 0.3s ease, box-shadow 0.3s ease;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.tab {
 | 
					.tab {
 | 
				
			||||||
@@ -63,19 +145,20 @@ body {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.tab.active {
 | 
					.tab.active {
 | 
				
			||||||
  background-color: #007bff;
 | 
					  background-color: var(--accent-primary);
 | 
				
			||||||
  color: white;
 | 
					  color: white;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.tab:hover:not(.active) {
 | 
					.tab:hover:not(.active) {
 | 
				
			||||||
  background-color: #f8f9fa;
 | 
					  background-color: var(--bg-tertiary);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.content {
 | 
					.content {
 | 
				
			||||||
  background-color: #fff;
 | 
					  background-color: var(--bg-secondary);
 | 
				
			||||||
  border-radius: 8px;
 | 
					  border-radius: 8px;
 | 
				
			||||||
  padding: 20px;
 | 
					  padding: 20px;
 | 
				
			||||||
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
 | 
					  box-shadow: 0 2px 4px var(--shadow);
 | 
				
			||||||
 | 
					  transition: background-color 0.3s ease, box-shadow 0.3s ease;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.table {
 | 
					.table {
 | 
				
			||||||
@@ -88,16 +171,20 @@ body {
 | 
				
			|||||||
.table td {
 | 
					.table td {
 | 
				
			||||||
  padding: 12px;
 | 
					  padding: 12px;
 | 
				
			||||||
  text-align: left;
 | 
					  text-align: left;
 | 
				
			||||||
  border-bottom: 1px solid #e9ecef;
 | 
					  border-bottom: 1px solid var(--border-color);
 | 
				
			||||||
 | 
					  transition: border-color 0.3s ease;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.table th {
 | 
					.table th {
 | 
				
			||||||
  background-color: #f8f9fa;
 | 
					  background-color: var(--bg-tertiary);
 | 
				
			||||||
  font-weight: 600;
 | 
					  font-weight: 600;
 | 
				
			||||||
 | 
					  color: var(--text-primary);
 | 
				
			||||||
 | 
					  transition: background-color 0.3s ease;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.table tr:hover {
 | 
					.table tr:hover {
 | 
				
			||||||
  background-color: #f8f9fa;
 | 
					  background-color: var(--bg-tertiary);
 | 
				
			||||||
 | 
					  transition: background-color 0.3s ease;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.btn {
 | 
					.btn {
 | 
				
			||||||
@@ -112,30 +199,30 @@ body {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.btn-primary {
 | 
					.btn-primary {
 | 
				
			||||||
  background-color: #007bff;
 | 
					  background-color: var(--accent-primary);
 | 
				
			||||||
  color: white;
 | 
					  color: white;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.btn-primary:hover {
 | 
					.btn-primary:hover {
 | 
				
			||||||
  background-color: #0056b3;
 | 
					  background-color: var(--accent-primary-hover);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.btn-danger {
 | 
					.btn-danger {
 | 
				
			||||||
  background-color: #dc3545;
 | 
					  background-color: var(--accent-danger);
 | 
				
			||||||
  color: white;
 | 
					  color: white;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.btn-danger:hover {
 | 
					.btn-danger:hover {
 | 
				
			||||||
  background-color: #c82333;
 | 
					  background-color: var(--accent-danger-hover);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.btn-secondary {
 | 
					.btn-secondary {
 | 
				
			||||||
  background-color: #6c757d;
 | 
					  background-color: var(--accent-secondary);
 | 
				
			||||||
  color: white;
 | 
					  color: white;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.btn-secondary:hover {
 | 
					.btn-secondary:hover {
 | 
				
			||||||
  background-color: #545b62;
 | 
					  background-color: var(--accent-secondary-hover);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.form-group {
 | 
					.form-group {
 | 
				
			||||||
@@ -151,15 +238,18 @@ body {
 | 
				
			|||||||
.form-input {
 | 
					.form-input {
 | 
				
			||||||
  width: 100%;
 | 
					  width: 100%;
 | 
				
			||||||
  padding: 10px;
 | 
					  padding: 10px;
 | 
				
			||||||
  border: 1px solid #ddd;
 | 
					  border: 1px solid var(--border-light);
 | 
				
			||||||
  border-radius: 4px;
 | 
					  border-radius: 4px;
 | 
				
			||||||
  font-size: 14px;
 | 
					  font-size: 14px;
 | 
				
			||||||
 | 
					  background-color: var(--bg-secondary);
 | 
				
			||||||
 | 
					  color: var(--text-primary);
 | 
				
			||||||
 | 
					  transition: all 0.3s ease;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.form-input:focus {
 | 
					.form-input:focus {
 | 
				
			||||||
  outline: none;
 | 
					  outline: none;
 | 
				
			||||||
  border-color: #007bff;
 | 
					  border-color: var(--accent-primary);
 | 
				
			||||||
  box-shadow: 0 0 0 2px rgba(0, 123, 255, 0.25);
 | 
					  box-shadow: 0 0 0 2px rgba(77, 171, 247, 0.25);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.audio-player {
 | 
					.audio-player {
 | 
				
			||||||
@@ -170,29 +260,31 @@ body {
 | 
				
			|||||||
.loading {
 | 
					.loading {
 | 
				
			||||||
  text-align: center;
 | 
					  text-align: center;
 | 
				
			||||||
  padding: 40px;
 | 
					  padding: 40px;
 | 
				
			||||||
  color: #666;
 | 
					  color: var(--text-secondary);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.error {
 | 
					.error {
 | 
				
			||||||
  background-color: #f8d7da;
 | 
					  background-color: var(--error-bg);
 | 
				
			||||||
  color: #721c24;
 | 
					  color: var(--error-text);
 | 
				
			||||||
  padding: 10px;
 | 
					  padding: 10px;
 | 
				
			||||||
  border-radius: 4px;
 | 
					  border-radius: 4px;
 | 
				
			||||||
  margin-bottom: 20px;
 | 
					  margin-bottom: 20px;
 | 
				
			||||||
 | 
					  transition: all 0.3s ease;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.success {
 | 
					.success {
 | 
				
			||||||
  background-color: #d4edda;
 | 
					  background-color: var(--success-bg);
 | 
				
			||||||
  color: #155724;
 | 
					  color: var(--success-text);
 | 
				
			||||||
  padding: 10px;
 | 
					  padding: 10px;
 | 
				
			||||||
  border-radius: 4px;
 | 
					  border-radius: 4px;
 | 
				
			||||||
  margin-bottom: 20px;
 | 
					  margin-bottom: 20px;
 | 
				
			||||||
 | 
					  transition: all 0.3s ease;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.empty-state {
 | 
					.empty-state {
 | 
				
			||||||
  text-align: center;
 | 
					  text-align: center;
 | 
				
			||||||
  padding: 40px;
 | 
					  padding: 40px;
 | 
				
			||||||
  color: #666;
 | 
					  color: var(--text-secondary);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.feed-item {
 | 
					.feed-item {
 | 
				
			||||||
@@ -200,9 +292,11 @@ body {
 | 
				
			|||||||
  align-items: center;
 | 
					  align-items: center;
 | 
				
			||||||
  justify-content: space-between;
 | 
					  justify-content: space-between;
 | 
				
			||||||
  padding: 15px;
 | 
					  padding: 15px;
 | 
				
			||||||
  border: 1px solid #e9ecef;
 | 
					  border: 1px solid var(--border-color);
 | 
				
			||||||
  border-radius: 4px;
 | 
					  border-radius: 4px;
 | 
				
			||||||
  margin-bottom: 10px;
 | 
					  margin-bottom: 10px;
 | 
				
			||||||
 | 
					  background-color: var(--bg-secondary);
 | 
				
			||||||
 | 
					  transition: all 0.3s ease;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.feed-info {
 | 
					.feed-info {
 | 
				
			||||||
@@ -215,7 +309,7 @@ body {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.feed-url {
 | 
					.feed-url {
 | 
				
			||||||
  color: #666;
 | 
					  color: var(--text-secondary);
 | 
				
			||||||
  font-size: 14px;
 | 
					  font-size: 14px;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -233,14 +327,15 @@ body {
 | 
				
			|||||||
.feed-section {
 | 
					.feed-section {
 | 
				
			||||||
  margin-bottom: 2rem;
 | 
					  margin-bottom: 2rem;
 | 
				
			||||||
  padding: 1.5rem;
 | 
					  padding: 1.5rem;
 | 
				
			||||||
  background: #f8f9fa;
 | 
					  background: var(--bg-tertiary);
 | 
				
			||||||
  border-radius: 8px;
 | 
					  border-radius: 8px;
 | 
				
			||||||
  border: 1px solid #e9ecef;
 | 
					  border: 1px solid var(--border-color);
 | 
				
			||||||
 | 
					  transition: all 0.3s ease;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.feed-section h2 {
 | 
					.feed-section h2 {
 | 
				
			||||||
  margin: 0 0 1rem 0;
 | 
					  margin: 0 0 1rem 0;
 | 
				
			||||||
  color: #495057;
 | 
					  color: var(--text-primary);
 | 
				
			||||||
  font-size: 1.5rem;
 | 
					  font-size: 1.5rem;
 | 
				
			||||||
  font-weight: 600;
 | 
					  font-weight: 600;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -279,10 +374,10 @@ body {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
.rss-section h2 {
 | 
					.rss-section h2 {
 | 
				
			||||||
  margin: 0 0 1.5rem 0;
 | 
					  margin: 0 0 1.5rem 0;
 | 
				
			||||||
  color: #2c3e50;
 | 
					  color: var(--text-primary);
 | 
				
			||||||
  font-size: 1.5rem;
 | 
					  font-size: 1.5rem;
 | 
				
			||||||
  font-weight: 600;
 | 
					  font-weight: 600;
 | 
				
			||||||
  border-bottom: 2px solid #3498db;
 | 
					  border-bottom: 2px solid var(--accent-primary);
 | 
				
			||||||
  padding-bottom: 0.5rem;
 | 
					  padding-bottom: 0.5rem;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -293,17 +388,17 @@ body {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.rss-endpoint-card {
 | 
					.rss-endpoint-card {
 | 
				
			||||||
  background: white;
 | 
					  background: var(--bg-secondary);
 | 
				
			||||||
  border: 1px solid #e1e8ed;
 | 
					  border: 1px solid var(--border-color);
 | 
				
			||||||
  border-radius: 12px;
 | 
					  border-radius: 12px;
 | 
				
			||||||
  padding: 1.5rem;
 | 
					  padding: 1.5rem;
 | 
				
			||||||
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
 | 
					  box-shadow: 0 2px 8px var(--shadow);
 | 
				
			||||||
  transition: all 0.2s ease;
 | 
					  transition: all 0.2s ease;
 | 
				
			||||||
  position: relative;
 | 
					  position: relative;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.rss-endpoint-card:hover {
 | 
					.rss-endpoint-card:hover {
 | 
				
			||||||
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.15);
 | 
					  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.2);
 | 
				
			||||||
  transform: translateY(-2px);
 | 
					  transform: translateY(-2px);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -333,7 +428,7 @@ body {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
.endpoint-header h3 {
 | 
					.endpoint-header h3 {
 | 
				
			||||||
  margin: 0;
 | 
					  margin: 0;
 | 
				
			||||||
  color: #2c3e50;
 | 
					  color: var(--text-primary);
 | 
				
			||||||
  font-size: 1.2rem;
 | 
					  font-size: 1.2rem;
 | 
				
			||||||
  font-weight: 600;
 | 
					  font-weight: 600;
 | 
				
			||||||
  flex: 1;
 | 
					  flex: 1;
 | 
				
			||||||
@@ -376,14 +471,14 @@ body {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.endpoint-description {
 | 
					.endpoint-description {
 | 
				
			||||||
  color: #666;
 | 
					  color: var(--text-secondary);
 | 
				
			||||||
  margin-bottom: 1rem;
 | 
					  margin-bottom: 1rem;
 | 
				
			||||||
  line-height: 1.5;
 | 
					  line-height: 1.5;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.endpoint-url {
 | 
					.endpoint-url {
 | 
				
			||||||
  background: #f8f9fa;
 | 
					  background: var(--bg-tertiary);
 | 
				
			||||||
  border: 1px solid #e9ecef;
 | 
					  border: 1px solid var(--border-color);
 | 
				
			||||||
  border-radius: 8px;
 | 
					  border-radius: 8px;
 | 
				
			||||||
  padding: 1rem;
 | 
					  padding: 1rem;
 | 
				
			||||||
  display: flex;
 | 
					  display: flex;
 | 
				
			||||||
@@ -391,6 +486,7 @@ body {
 | 
				
			|||||||
  align-items: center;
 | 
					  align-items: center;
 | 
				
			||||||
  gap: 1rem;
 | 
					  gap: 1rem;
 | 
				
			||||||
  flex-wrap: wrap;
 | 
					  flex-wrap: wrap;
 | 
				
			||||||
 | 
					  transition: all 0.3s ease;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.rss-endpoint-card.main-feed .endpoint-url {
 | 
					.rss-endpoint-card.main-feed .endpoint-url {
 | 
				
			||||||
@@ -401,7 +497,7 @@ body {
 | 
				
			|||||||
.endpoint-url code {
 | 
					.endpoint-url code {
 | 
				
			||||||
  background: none;
 | 
					  background: none;
 | 
				
			||||||
  border: none;
 | 
					  border: none;
 | 
				
			||||||
  color: #495057;
 | 
					  color: var(--text-primary);
 | 
				
			||||||
  font-family: "Monaco", "Menlo", "Ubuntu Mono", monospace;
 | 
					  font-family: "Monaco", "Menlo", "Ubuntu Mono", monospace;
 | 
				
			||||||
  font-size: 0.9rem;
 | 
					  font-size: 0.9rem;
 | 
				
			||||||
  word-break: break-all;
 | 
					  word-break: break-all;
 | 
				
			||||||
@@ -421,7 +517,7 @@ body {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
.copy-btn,
 | 
					.copy-btn,
 | 
				
			||||||
.open-btn {
 | 
					.open-btn {
 | 
				
			||||||
  background: #3498db;
 | 
					  background: var(--accent-primary);
 | 
				
			||||||
  color: white;
 | 
					  color: white;
 | 
				
			||||||
  border: none;
 | 
					  border: none;
 | 
				
			||||||
  border-radius: 6px;
 | 
					  border-radius: 6px;
 | 
				
			||||||
@@ -438,7 +534,7 @@ body {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
.copy-btn:hover,
 | 
					.copy-btn:hover,
 | 
				
			||||||
.open-btn:hover {
 | 
					.open-btn:hover {
 | 
				
			||||||
  background: #2980b9;
 | 
					  background: var(--accent-primary-hover);
 | 
				
			||||||
  transform: scale(1.05);
 | 
					  transform: scale(1.05);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -462,10 +558,11 @@ body {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.usage-info {
 | 
					.usage-info {
 | 
				
			||||||
  background: #f8f9fa;
 | 
					  background: var(--bg-tertiary);
 | 
				
			||||||
  border-radius: 12px;
 | 
					  border-radius: 12px;
 | 
				
			||||||
  padding: 2rem;
 | 
					  padding: 2rem;
 | 
				
			||||||
  margin-top: 3rem;
 | 
					  margin-top: 3rem;
 | 
				
			||||||
 | 
					  transition: background-color 0.3s ease;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.usage-cards {
 | 
					.usage-cards {
 | 
				
			||||||
@@ -476,22 +573,23 @@ body {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.usage-card {
 | 
					.usage-card {
 | 
				
			||||||
  background: white;
 | 
					  background: var(--bg-secondary);
 | 
				
			||||||
  border-radius: 8px;
 | 
					  border-radius: 8px;
 | 
				
			||||||
  padding: 1.5rem;
 | 
					  padding: 1.5rem;
 | 
				
			||||||
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
 | 
					  box-shadow: 0 2px 4px var(--shadow);
 | 
				
			||||||
 | 
					  transition: all 0.3s ease;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.usage-card h3 {
 | 
					.usage-card h3 {
 | 
				
			||||||
  margin: 0 0 1rem 0;
 | 
					  margin: 0 0 1rem 0;
 | 
				
			||||||
  color: #2c3e50;
 | 
					  color: var(--text-primary);
 | 
				
			||||||
  font-size: 1.1rem;
 | 
					  font-size: 1.1rem;
 | 
				
			||||||
  font-weight: 600;
 | 
					  font-weight: 600;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.usage-card p {
 | 
					.usage-card p {
 | 
				
			||||||
  margin: 0;
 | 
					  margin: 0;
 | 
				
			||||||
  color: #666;
 | 
					  color: var(--text-secondary);
 | 
				
			||||||
  line-height: 1.6;
 | 
					  line-height: 1.6;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -523,3 +621,193 @@ body {
 | 
				
			|||||||
    grid-template-columns: 1fr;
 | 
					    grid-template-columns: 1fr;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Additional form elements */
 | 
				
			||||||
 | 
					select {
 | 
				
			||||||
 | 
					  background-color: var(--bg-secondary);
 | 
				
			||||||
 | 
					  color: var(--text-primary);
 | 
				
			||||||
 | 
					  border: 1px solid var(--border-light);
 | 
				
			||||||
 | 
					  border-radius: 4px;
 | 
				
			||||||
 | 
					  transition: all 0.3s ease;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					select:focus {
 | 
				
			||||||
 | 
					  outline: none;
 | 
				
			||||||
 | 
					  border-color: var(--accent-primary);
 | 
				
			||||||
 | 
					  box-shadow: 0 0 0 2px rgba(77, 171, 247, 0.25);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Links */
 | 
				
			||||||
 | 
					a {
 | 
				
			||||||
 | 
					  color: var(--accent-primary);
 | 
				
			||||||
 | 
					  transition: color 0.3s ease;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					a:hover {
 | 
				
			||||||
 | 
					  color: var(--accent-primary-hover);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Form labels */
 | 
				
			||||||
 | 
					.form-label {
 | 
				
			||||||
 | 
					  color: var(--text-primary);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Tab text color for better readability */
 | 
				
			||||||
 | 
					.tab {
 | 
				
			||||||
 | 
					  color: var(--text-primary);
 | 
				
			||||||
 | 
					  transition: all 0.3s ease;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Component-specific styles for better dark theme support */
 | 
				
			||||||
 | 
					.episode-header {
 | 
				
			||||||
 | 
					  display: flex;
 | 
				
			||||||
 | 
					  justify-content: space-between;
 | 
				
			||||||
 | 
					  align-items: center;
 | 
				
			||||||
 | 
					  margin-bottom: 15px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.episode-title {
 | 
				
			||||||
 | 
					  color: var(--text-primary);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.episode-meta {
 | 
				
			||||||
 | 
					  display: flex;
 | 
				
			||||||
 | 
					  gap: 10px;
 | 
				
			||||||
 | 
					  align-items: center;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.episode-meta-text {
 | 
				
			||||||
 | 
					  font-size: 12px;
 | 
				
			||||||
 | 
					  color: var(--text-secondary);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.episode-search-bar {
 | 
				
			||||||
 | 
					  display: flex;
 | 
				
			||||||
 | 
					  gap: 10px;
 | 
				
			||||||
 | 
					  align-items: center;
 | 
				
			||||||
 | 
					  flex-wrap: wrap;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.episode-search-input {
 | 
				
			||||||
 | 
					  flex: 1;
 | 
				
			||||||
 | 
					  min-width: 200px;
 | 
				
			||||||
 | 
					  padding: 8px 12px;
 | 
				
			||||||
 | 
					  font-size: 14px;
 | 
				
			||||||
 | 
					  border: 1px solid var(--border-light);
 | 
				
			||||||
 | 
					  border-radius: 4px;
 | 
				
			||||||
 | 
					  background-color: var(--bg-secondary);
 | 
				
			||||||
 | 
					  color: var(--text-primary);
 | 
				
			||||||
 | 
					  transition: all 0.3s ease;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.episode-search-input:focus {
 | 
				
			||||||
 | 
					  outline: none;
 | 
				
			||||||
 | 
					  border-color: var(--accent-primary);
 | 
				
			||||||
 | 
					  box-shadow: 0 0 0 2px rgba(77, 171, 247, 0.25);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.episode-category-select {
 | 
				
			||||||
 | 
					  padding: 8px 12px;
 | 
				
			||||||
 | 
					  font-size: 14px;
 | 
				
			||||||
 | 
					  border: 1px solid var(--border-light);
 | 
				
			||||||
 | 
					  border-radius: 4px;
 | 
				
			||||||
 | 
					  min-width: 120px;
 | 
				
			||||||
 | 
					  background-color: var(--bg-secondary);
 | 
				
			||||||
 | 
					  color: var(--text-primary);
 | 
				
			||||||
 | 
					  transition: all 0.3s ease;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.episode-category-select:focus {
 | 
				
			||||||
 | 
					  outline: none;
 | 
				
			||||||
 | 
					  border-color: var(--accent-primary);
 | 
				
			||||||
 | 
					  box-shadow: 0 0 0 2px rgba(77, 171, 247, 0.25);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.episode-actions {
 | 
				
			||||||
 | 
					  display: flex;
 | 
				
			||||||
 | 
					  gap: 8px;
 | 
				
			||||||
 | 
					  flex-direction: column;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.episode-action-buttons {
 | 
				
			||||||
 | 
					  display: flex;
 | 
				
			||||||
 | 
					  gap: 8px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.episode-link {
 | 
				
			||||||
 | 
					  text-decoration: none;
 | 
				
			||||||
 | 
					  color: var(--accent-primary);
 | 
				
			||||||
 | 
					  transition: color 0.3s ease;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.episode-link:hover {
 | 
				
			||||||
 | 
					  color: var(--accent-primary-hover);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.episode-feed-info {
 | 
				
			||||||
 | 
					  font-size: 12px;
 | 
				
			||||||
 | 
					  color: var(--text-secondary);
 | 
				
			||||||
 | 
					  margin-bottom: 4px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.episode-article-info {
 | 
				
			||||||
 | 
					  font-size: 12px;
 | 
				
			||||||
 | 
					  color: var(--text-secondary);
 | 
				
			||||||
 | 
					  margin-bottom: 4px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.episode-article-link {
 | 
				
			||||||
 | 
					  font-size: 12px;
 | 
				
			||||||
 | 
					  color: var(--text-secondary);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.episode-description {
 | 
				
			||||||
 | 
					  font-size: 14px;
 | 
				
			||||||
 | 
					  max-width: 200px;
 | 
				
			||||||
 | 
					  overflow: hidden;
 | 
				
			||||||
 | 
					  text-overflow: ellipsis;
 | 
				
			||||||
 | 
					  white-space: nowrap;
 | 
				
			||||||
 | 
					  color: var(--text-primary);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.episode-file-size {
 | 
				
			||||||
 | 
					  font-size: 12px;
 | 
				
			||||||
 | 
					  color: var(--text-secondary);
 | 
				
			||||||
 | 
					  margin-top: 4px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.pagination-container {
 | 
				
			||||||
 | 
					  margin-top: 20px;
 | 
				
			||||||
 | 
					  display: flex;
 | 
				
			||||||
 | 
					  justify-content: center;
 | 
				
			||||||
 | 
					  align-items: center;
 | 
				
			||||||
 | 
					  gap: 10px;
 | 
				
			||||||
 | 
					  flex-wrap: wrap;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.pagination-pages {
 | 
				
			||||||
 | 
					  display: flex;
 | 
				
			||||||
 | 
					  gap: 5px;
 | 
				
			||||||
 | 
					  align-items: center;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.pagination-page-btn {
 | 
				
			||||||
 | 
					  min-width: 40px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.pagination-size-selector {
 | 
				
			||||||
 | 
					  margin-left: 20px;
 | 
				
			||||||
 | 
					  display: flex;
 | 
				
			||||||
 | 
					  align-items: center;
 | 
				
			||||||
 | 
					  gap: 5px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.pagination-size-select {
 | 
				
			||||||
 | 
					  padding: 4px 8px;
 | 
				
			||||||
 | 
					  font-size: 14px;
 | 
				
			||||||
 | 
					  border: 1px solid var(--border-light);
 | 
				
			||||||
 | 
					  border-radius: 4px;
 | 
				
			||||||
 | 
					  background-color: var(--bg-secondary);
 | 
				
			||||||
 | 
					  color: var(--text-primary);
 | 
				
			||||||
 | 
					  transition: all 0.3s ease;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user