mirror of
https://github.com/KivotosRailway/website.git
synced 2026-11-03 11:06:32 +09:00
修改新闻相关板块的图片比例
This commit is contained in:
+14
-8
@@ -39,7 +39,7 @@ a { color: inherit; text-decoration: none; }
|
|||||||
.news-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 28px; }
|
.news-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 28px; }
|
||||||
.news-card { min-width: 0; }
|
.news-card { min-width: 0; }
|
||||||
.news-card-link { display: block; }
|
.news-card-link { display: block; }
|
||||||
.news-visual { height: 420px; border-radius: 18px; background-size: cover; background-position: center; box-shadow: inset 0 0 0 1px rgba(15, 23, 42, 0.06); }
|
.news-visual { aspect-ratio: 29 / 13; border-radius: 18px; background-size: cover; background-position: center; box-shadow: inset 0 0 0 1px rgba(15, 23, 42, 0.06); }
|
||||||
.news-card h3 { margin: 18px 0 14px; font-size: clamp(20px, 1.7vw, 28px); line-height: 1.4; letter-spacing: -0.03em; }
|
.news-card h3 { margin: 18px 0 14px; font-size: clamp(20px, 1.7vw, 28px); line-height: 1.4; letter-spacing: -0.03em; }
|
||||||
.news-card time { color: var(--muted); font-size: 16px; }
|
.news-card time { color: var(--muted); font-size: 16px; }
|
||||||
|
|
||||||
@@ -53,14 +53,20 @@ a { color: inherit; text-decoration: none; }
|
|||||||
.news-filter-button.active { background: #0f73ff; border-color: #0f73ff; color: #fff; }
|
.news-filter-button.active { background: #0f73ff; border-color: #0f73ff; color: #fff; }
|
||||||
.news-toolbar-right { display: flex; align-items: center; gap: 8px; }
|
.news-toolbar-right { display: flex; align-items: center; gap: 8px; }
|
||||||
.news-view-toggle { width: 36px; height: 36px; border: 1px solid rgba(15, 23, 42, 0.16); border-radius: 50%; background: rgba(15, 23, 42, 0.03); color: #1b2430; cursor: pointer; }
|
.news-view-toggle { width: 36px; height: 36px; border: 1px solid rgba(15, 23, 42, 0.16); border-radius: 50%; background: rgba(15, 23, 42, 0.03); color: #1b2430; cursor: pointer; }
|
||||||
.news-list-grid { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 28px; padding-top: 28px; }
|
.news-list-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 32px; padding-top: 28px; padding-bottom: 48px; }
|
||||||
.news-list-card { min-width: 0; }
|
.news-list-card { min-width: 0; }
|
||||||
.news-list-link { display: block; }
|
.news-list-link { display: block; }
|
||||||
.news-list-cover { height: 250px; border-radius: 18px; background-size: cover; background-position: center; }
|
.news-list-cover { aspect-ratio: 29 / 13; border-radius: 18px; background-size: cover; background-position: center; }
|
||||||
.news-list-meta { padding-top: 14px; }
|
.news-list-meta { padding-top: 18px; }
|
||||||
.news-list-tag { display: inline-block; margin-bottom: 10px; font-size: 12px; color: #0f73ff; background: rgba(15, 115, 255, 0.08); padding: 5px 8px; border-radius: 999px; }
|
.news-list-tag { display: inline-block; margin-bottom: 12px; font-size: 12px; color: #0f73ff; background: rgba(15, 115, 255, 0.08); padding: 5px 8px; border-radius: 999px; }
|
||||||
.news-list-meta h3 { margin: 0 0 8px; font-size: clamp(20px, 1.5vw, 26px); line-height: 1.4; letter-spacing: -0.04em; }
|
.news-list-meta h3 { margin: 0 0 10px; font-size: clamp(18px, 2vw, 28px); line-height: 1.4; letter-spacing: -0.04em; }
|
||||||
.news-list-meta time { color: #697684; font-size: 14px; }
|
.news-list-meta time { color: #697684; font-size: 14px; }
|
||||||
|
.news-pagination { display: flex; align-items: center; justify-content: center; gap: 12px; padding: 20px 0 0; margin-top: 20px; }
|
||||||
|
.news-pagination-button { min-width: 40px; height: 40px; padding: 0 12px; border: 1px solid rgba(15, 23, 42, 0.16); border-radius: 8px; background: #fff; color: #1b2430; font-size: 14px; font-weight: 500; cursor: pointer; transition: all 0.2s ease; }
|
||||||
|
.news-pagination-button:hover:not(:disabled) { border-color: #0f73ff; color: #0f73ff; background: rgba(15, 115, 255, 0.04); }
|
||||||
|
.news-pagination-button.active { background: #0f73ff; border-color: #0f73ff; color: #fff; }
|
||||||
|
.news-pagination-button:disabled { opacity: 0.5; cursor: not-allowed; }
|
||||||
|
.news-pagination-info { color: #697684; font-size: 14px; margin: 0 8px; }
|
||||||
|
|
||||||
.news-detail-page { padding: 40px 0 80px; }
|
.news-detail-page { padding: 40px 0 80px; }
|
||||||
.news-detail-inner { max-width: 960px; margin: 0 auto; padding: 0 24px; }
|
.news-detail-inner { max-width: 960px; margin: 0 auto; padding: 0 24px; }
|
||||||
@@ -70,7 +76,7 @@ a { color: inherit; text-decoration: none; }
|
|||||||
.news-detail-card h1 { margin: 0 0 10px; font-size: clamp(38px, 4vw, 62px); line-height: 1.08; letter-spacing: -0.06em; }
|
.news-detail-card h1 { margin: 0 0 10px; font-size: clamp(38px, 4vw, 62px); line-height: 1.08; letter-spacing: -0.06em; }
|
||||||
.news-detail-card time { display: inline-block; margin-bottom: 20px; color: #697684; }
|
.news-detail-card time { display: inline-block; margin-bottom: 20px; color: #697684; }
|
||||||
.news-detail-ai-banner { display: flex; align-items: center; width: 100%; margin: 0 0 20px; padding: 12px 18px; border-radius: 999px; background: rgba(255, 179, 15, 0.08); color: #ff8f0f; font-size: 15px; line-height: 1.5; }
|
.news-detail-ai-banner { display: flex; align-items: center; width: 100%; margin: 0 0 20px; padding: 12px 18px; border-radius: 999px; background: rgba(255, 179, 15, 0.08); color: #ff8f0f; font-size: 15px; line-height: 1.5; }
|
||||||
.news-detail-cover { height: 360px; border-radius: 18px; background-size: cover; background-position: center; margin-bottom: 24px; }
|
.news-detail-cover { aspect-ratio: 29 / 13; border-radius: 18px; background-size: cover; background-position: center; margin-bottom: 24px; }
|
||||||
.news-detail-body { color: #1d2732; line-height: 1.9; font-size: 17px; }
|
.news-detail-body { color: #1d2732; line-height: 1.9; font-size: 17px; }
|
||||||
.news-detail-body h2, .news-detail-body h3 { margin-top: 28px; }
|
.news-detail-body h2, .news-detail-body h3 { margin-top: 28px; }
|
||||||
.news-detail-body p { margin: 0 0 18px; }
|
.news-detail-body p { margin: 0 0 18px; }
|
||||||
@@ -141,7 +147,7 @@ a { color: inherit; text-decoration: none; }
|
|||||||
.news-visual { height: 260px; }
|
.news-visual { height: 260px; }
|
||||||
.news-page-inner { padding: 0 16px; }
|
.news-page-inner { padding: 0 16px; }
|
||||||
.news-toolbar { padding-top: 12px; }
|
.news-toolbar { padding-top: 12px; }
|
||||||
.news-list-grid { grid-template-columns: 1fr; gap: 22px; }
|
.news-list-grid { grid-template-columns: 1fr; gap: 22px; padding-bottom: 32px; }
|
||||||
.news-detail-card { padding: 20px; }
|
.news-detail-card { padding: 20px; }
|
||||||
.news-detail-cover { height: 240px; }
|
.news-detail-cover { height: 240px; }
|
||||||
.page-bottom-nav { width: calc(100% - 40px); margin-top: 30px; padding: 24px 0; overflow-x: auto; }
|
.page-bottom-nav { width: calc(100% - 40px); margin-top: 30px; padding: 24px 0; overflow-x: auto; }
|
||||||
|
|||||||
@@ -5,9 +5,12 @@ import { useEffect, useState } from "react";
|
|||||||
import type { NewsItem } from "@/data/news";
|
import type { NewsItem } from "@/data/news";
|
||||||
import { getInitialLocale, getLocaleMessages, type Locale } from "@/lib/i18n";
|
import { getInitialLocale, getLocaleMessages, type Locale } from "@/lib/i18n";
|
||||||
|
|
||||||
|
const ITEMS_PER_PAGE = 12;
|
||||||
|
|
||||||
export function NewsList({ catalog }: { catalog: Record<Locale, NewsItem[]> }) {
|
export function NewsList({ catalog }: { catalog: Record<Locale, NewsItem[]> }) {
|
||||||
const [activeCategory, setActiveCategory] = useState<string | null>(null);
|
const [activeCategory, setActiveCategory] = useState<string | null>(null);
|
||||||
const [locale, setLocale] = useState<Locale>("zh-CN");
|
const [locale, setLocale] = useState<Locale>("zh-CN");
|
||||||
|
const [currentPage, setCurrentPage] = useState(1);
|
||||||
const messages = getLocaleMessages(locale);
|
const messages = getLocaleMessages(locale);
|
||||||
const news = catalog[locale];
|
const news = catalog[locale];
|
||||||
|
|
||||||
@@ -21,11 +24,40 @@ export function NewsList({ catalog }: { catalog: Record<Locale, NewsItem[]> }) {
|
|||||||
window.removeEventListener("storage", syncLocale);
|
window.removeEventListener("storage", syncLocale);
|
||||||
};
|
};
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setCurrentPage(1);
|
||||||
|
}, [activeCategory]);
|
||||||
|
|
||||||
const categories = Array.from(new Set(news.map((item) => item.category).filter(Boolean)));
|
const categories = Array.from(new Set(news.map((item) => item.category).filter(Boolean)));
|
||||||
const visibleNews = activeCategory
|
const visibleNews = activeCategory
|
||||||
? news.filter((item) => item.category === activeCategory)
|
? news.filter((item) => item.category === activeCategory)
|
||||||
: news;
|
: news;
|
||||||
|
|
||||||
|
const totalPages = Math.ceil(visibleNews.length / ITEMS_PER_PAGE);
|
||||||
|
const startIndex = (currentPage - 1) * ITEMS_PER_PAGE;
|
||||||
|
const endIndex = startIndex + ITEMS_PER_PAGE;
|
||||||
|
const paginatedNews = visibleNews.slice(startIndex, endIndex);
|
||||||
|
|
||||||
|
const handlePrevious = () => {
|
||||||
|
if (currentPage > 1) {
|
||||||
|
setCurrentPage(currentPage - 1);
|
||||||
|
window.scrollTo({ top: 0, behavior: "smooth" });
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleNext = () => {
|
||||||
|
if (currentPage < totalPages) {
|
||||||
|
setCurrentPage(currentPage + 1);
|
||||||
|
window.scrollTo({ top: 0, behavior: "smooth" });
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handlePageClick = (page: number) => {
|
||||||
|
setCurrentPage(page);
|
||||||
|
window.scrollTo({ top: 0, behavior: "smooth" });
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="news-toolbar" aria-label="新闻筛选和布局控制">
|
<div className="news-toolbar" aria-label="新闻筛选和布局控制">
|
||||||
@@ -54,7 +86,7 @@ export function NewsList({ catalog }: { catalog: Record<Locale, NewsItem[]> }) {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="news-list-grid">
|
<div className="news-list-grid">
|
||||||
{visibleNews.map((item) => (
|
{paginatedNews.map((item) => (
|
||||||
<article key={item.id} className="news-list-card">
|
<article key={item.id} className="news-list-card">
|
||||||
<Link href={item.href} className="news-list-link">
|
<Link href={item.href} className="news-list-link">
|
||||||
<div className="news-list-cover" style={{ backgroundImage: `url(${item.cover})` }} />
|
<div className="news-list-cover" style={{ backgroundImage: `url(${item.cover})` }} />
|
||||||
@@ -67,6 +99,44 @@ export function NewsList({ catalog }: { catalog: Record<Locale, NewsItem[]> }) {
|
|||||||
</article>
|
</article>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{totalPages > 1 && (
|
||||||
|
<div className="news-pagination">
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
className="news-pagination-button"
|
||||||
|
onClick={handlePrevious}
|
||||||
|
disabled={currentPage === 1}
|
||||||
|
aria-label="上一页"
|
||||||
|
>
|
||||||
|
←
|
||||||
|
</button>
|
||||||
|
|
||||||
|
{Array.from({ length: totalPages }, (_, i) => i + 1).map((page) => (
|
||||||
|
<button
|
||||||
|
key={page}
|
||||||
|
type="button"
|
||||||
|
className={`news-pagination-button${currentPage === page ? " active" : ""}`}
|
||||||
|
onClick={() => handlePageClick(page)}
|
||||||
|
aria-label={`第 ${page} 页`}
|
||||||
|
aria-current={currentPage === page ? "page" : undefined}
|
||||||
|
>
|
||||||
|
{page}
|
||||||
|
</button>
|
||||||
|
))}
|
||||||
|
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
className="news-pagination-button"
|
||||||
|
onClick={handleNext}
|
||||||
|
disabled={currentPage === totalPages}
|
||||||
|
aria-label="下一页"
|
||||||
|
>
|
||||||
|
→
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -62,12 +62,14 @@ function stripFrontmatter(markdown: string): string {
|
|||||||
return markdown.replace(/^---\r?\n[\s\S]*?\r?\n---\r?\n?/, "").trim();
|
return markdown.replace(/^---\r?\n[\s\S]*?\r?\n---\r?\n?/, "").trim();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const DEFAULT_NEWS_COVER = "https://r2-image.kivotosrailway.com/2025/05/01/681397ba4e763.png";
|
||||||
|
|
||||||
function normalizeNewsItem(fileName: string, raw: NewsFrontmatter, body: string): NewsItem | null {
|
function normalizeNewsItem(fileName: string, raw: NewsFrontmatter, body: string): NewsItem | null {
|
||||||
const title = raw.title?.trim();
|
const title = raw.title?.trim();
|
||||||
const date = raw.date?.trim() || "未注明日期";
|
const date = raw.date?.trim() || "未注明日期";
|
||||||
const category = (Array.isArray(raw.category) ? raw.category[0] : raw.category)?.trim() || "未分类";
|
const category = (Array.isArray(raw.category) ? raw.category[0] : raw.category)?.trim() || "未分类";
|
||||||
const tags = raw.tags ?? [];
|
const tags = raw.tags ?? [];
|
||||||
const cover = raw.cover?.trim() || "https://images.unsplash.com/photo-1497366754035-f200968a6e72?auto=format&fit=crop&w=1200&q=80";
|
const cover = raw.cover?.trim() || DEFAULT_NEWS_COVER;
|
||||||
const slug = raw.slug?.trim() || fileName.replace(/\.md$/i, "");
|
const slug = raw.slug?.trim() || fileName.replace(/\.md$/i, "");
|
||||||
|
|
||||||
if (!title) {
|
if (!title) {
|
||||||
|
|||||||
Reference in New Issue
Block a user