s
This commit is contained in:
@@ -3,18 +3,26 @@
|
||||
import { useState, useMemo, useSyncExternalStore } from "react";
|
||||
import { useTranslation } from "@/app/digital/i18n/navigation";
|
||||
import type { ResourceData } from "@/app/digital/lib/theme-data";
|
||||
import DigitalThemeIcon, { type IconName } from "./DigitalThemeIcon";
|
||||
|
||||
const PER_PAGE_MOBILE = 4;
|
||||
const PER_PAGE_PC = 8;
|
||||
const BREAKPOINT = 768;
|
||||
|
||||
const panCategoryIconNames: Record<string, IconName> = {
|
||||
docs: "file",
|
||||
templates: "check",
|
||||
firmware: "spark",
|
||||
storage: "cloud",
|
||||
};
|
||||
|
||||
function useIsPC() {
|
||||
return useSyncExternalStore(
|
||||
(callback) => {
|
||||
if (typeof window === "undefined") return () => {};
|
||||
const mq = window.matchMedia(`(min-width: ${BREAKPOINT}px)`);
|
||||
const mq = window.matchMedia(`(min-width: ${BREAKPOINT}px)`);
|
||||
const fn = () => callback();
|
||||
mq.addEventListener("change", fn);
|
||||
mq.addEventListener("change", fn);
|
||||
return () => mq.removeEventListener("change", fn);
|
||||
},
|
||||
() =>
|
||||
@@ -68,11 +76,11 @@ export default function ResourceNavigation({ data }: ResourceNavigationProps) {
|
||||
}, [data.products, safeProductsPage, productsPerPage]);
|
||||
|
||||
return (
|
||||
<div className="mt-12 space-y-16">
|
||||
<div className="dn-resources mt-12 space-y-16">
|
||||
{/* 图书 - 封面+书名,数量少则大封面,多则分页 */}
|
||||
<div>
|
||||
<h3 className="mb-4 flex items-center gap-2 text-xl font-bold text-slate-900 dark:text-slate-100">
|
||||
<span>📚</span>
|
||||
<h3 className="dn-subsection-title mb-4 flex items-center gap-2 text-xl font-bold text-slate-900 dark:text-slate-100">
|
||||
<DigitalThemeIcon name="book" emoji="📚" className="h-5 w-5" />
|
||||
{t("resourceSections.books")}
|
||||
{data.books.length > 0 && (
|
||||
<span className="text-sm font-normal text-slate-500 dark:text-slate-400">
|
||||
@@ -88,7 +96,7 @@ export default function ResourceNavigation({ data }: ResourceNavigationProps) {
|
||||
key={`book-${booksPage}-${i}`}
|
||||
type="button"
|
||||
onClick={showUpdating}
|
||||
className="group flex cursor-not-allowed flex-col text-left"
|
||||
className="dn-resource-tile group flex cursor-not-allowed flex-col text-left"
|
||||
>
|
||||
<div
|
||||
className="overflow-hidden rounded-lg border border-slate-200 bg-slate-100 shadow-sm transition-all group-hover:shadow-md dark:border-slate-700 dark:bg-slate-800"
|
||||
@@ -107,12 +115,12 @@ export default function ResourceNavigation({ data }: ResourceNavigationProps) {
|
||||
))}
|
||||
</div>
|
||||
{booksTotalPages > 1 && (
|
||||
<div className="mt-6 flex items-center justify-center gap-2">
|
||||
<div className="dn-pagination mt-6 flex items-center justify-center gap-2">
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setBooksPage((p) => Math.max(0, p - 1))}
|
||||
disabled={safeBooksPage === 0}
|
||||
className="flex h-10 w-10 items-center justify-center rounded-lg border border-slate-200 bg-white text-slate-600 transition-colors hover:bg-slate-50 disabled:opacity-40 disabled:cursor-not-allowed dark:border-slate-700 dark:bg-slate-800 dark:text-slate-400 dark:hover:bg-slate-700"
|
||||
className="dn-icon-button flex h-10 w-10 items-center justify-center rounded-lg border border-slate-200 bg-white text-slate-600 transition-colors hover:bg-slate-50 disabled:opacity-40 disabled:cursor-not-allowed dark:border-slate-700 dark:bg-slate-800 dark:text-slate-400 dark:hover:bg-slate-700"
|
||||
aria-label="上一页"
|
||||
>
|
||||
<svg className="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
@@ -126,7 +134,7 @@ export default function ResourceNavigation({ data }: ResourceNavigationProps) {
|
||||
type="button"
|
||||
onClick={() => setBooksPage((p) => Math.min(booksTotalPages - 1, p + 1))}
|
||||
disabled={safeBooksPage === booksTotalPages - 1}
|
||||
className="flex h-10 w-10 items-center justify-center rounded-lg border border-slate-200 bg-white text-slate-600 transition-colors hover:bg-slate-50 disabled:opacity-40 disabled:cursor-not-allowed dark:border-slate-700 dark:bg-slate-800 dark:text-slate-400 dark:hover:bg-slate-700"
|
||||
className="dn-icon-button flex h-10 w-10 items-center justify-center rounded-lg border border-slate-200 bg-white text-slate-600 transition-colors hover:bg-slate-50 disabled:opacity-40 disabled:cursor-not-allowed dark:border-slate-700 dark:bg-slate-800 dark:text-slate-400 dark:hover:bg-slate-700"
|
||||
aria-label="下一页"
|
||||
>
|
||||
<svg className="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
@@ -139,8 +147,8 @@ export default function ResourceNavigation({ data }: ResourceNavigationProps) {
|
||||
|
||||
{/* 商业数码 - 商品图+跳转电商 */}
|
||||
<div>
|
||||
<h3 className="mb-4 flex items-center gap-2 text-xl font-bold text-slate-900 dark:text-slate-100">
|
||||
<span>🛒</span>
|
||||
<h3 className="dn-subsection-title mb-4 flex items-center gap-2 text-xl font-bold text-slate-900 dark:text-slate-100">
|
||||
<DigitalThemeIcon name="shopping" emoji="🛒" className="h-5 w-5" />
|
||||
{t("resourceSections.products")}
|
||||
{data.products.length > 0 && (
|
||||
<span className="text-sm font-normal text-slate-500 dark:text-slate-400">
|
||||
@@ -156,7 +164,7 @@ export default function ResourceNavigation({ data }: ResourceNavigationProps) {
|
||||
key={`product-${productsPage}-${i}`}
|
||||
type="button"
|
||||
onClick={showUpdating}
|
||||
className="group flex cursor-not-allowed flex-col text-left"
|
||||
className="dn-resource-tile group flex cursor-not-allowed flex-col text-left"
|
||||
>
|
||||
<div
|
||||
className="overflow-hidden rounded-xl border border-slate-200 bg-white p-3 shadow-sm transition-all group-hover:shadow-md dark:border-slate-700 dark:bg-slate-900"
|
||||
@@ -175,12 +183,12 @@ export default function ResourceNavigation({ data }: ResourceNavigationProps) {
|
||||
))}
|
||||
</div>
|
||||
{productsTotalPages > 1 && (
|
||||
<div className="mt-6 flex items-center justify-center gap-2">
|
||||
<div className="dn-pagination mt-6 flex items-center justify-center gap-2">
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setProductsPage((p) => Math.max(0, p - 1))}
|
||||
disabled={safeProductsPage === 0}
|
||||
className="flex h-10 w-10 items-center justify-center rounded-lg border border-slate-200 bg-white text-slate-600 transition-colors hover:bg-slate-50 disabled:opacity-40 disabled:cursor-not-allowed dark:border-slate-700 dark:bg-slate-800 dark:text-slate-400 dark:hover:bg-slate-700"
|
||||
className="dn-icon-button flex h-10 w-10 items-center justify-center rounded-lg border border-slate-200 bg-white text-slate-600 transition-colors hover:bg-slate-50 disabled:opacity-40 disabled:cursor-not-allowed dark:border-slate-700 dark:bg-slate-800 dark:text-slate-400 dark:hover:bg-slate-700"
|
||||
aria-label="上一页"
|
||||
>
|
||||
<svg className="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
@@ -194,7 +202,7 @@ export default function ResourceNavigation({ data }: ResourceNavigationProps) {
|
||||
type="button"
|
||||
onClick={() => setProductsPage((p) => Math.min(productsTotalPages - 1, p + 1))}
|
||||
disabled={safeProductsPage === productsTotalPages - 1}
|
||||
className="flex h-10 w-10 items-center justify-center rounded-lg border border-slate-200 bg-white text-slate-600 transition-colors hover:bg-slate-50 disabled:opacity-40 disabled:cursor-not-allowed dark:border-slate-700 dark:bg-slate-800 dark:text-slate-400 dark:hover:bg-slate-700"
|
||||
className="dn-icon-button flex h-10 w-10 items-center justify-center rounded-lg border border-slate-200 bg-white text-slate-600 transition-colors hover:bg-slate-50 disabled:opacity-40 disabled:cursor-not-allowed dark:border-slate-700 dark:bg-slate-800 dark:text-slate-400 dark:hover:bg-slate-700"
|
||||
aria-label="下一页"
|
||||
>
|
||||
<svg className="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
@@ -207,24 +215,28 @@ export default function ResourceNavigation({ data }: ResourceNavigationProps) {
|
||||
|
||||
{/* 网盘 - 分类 Tab */}
|
||||
<div>
|
||||
<h3 className="mb-4 flex items-center gap-2 text-xl font-bold text-slate-900 dark:text-slate-100">
|
||||
<span>☁️</span>
|
||||
<h3 className="dn-subsection-title mb-4 flex items-center gap-2 text-xl font-bold text-slate-900 dark:text-slate-100">
|
||||
<DigitalThemeIcon name="cloud" emoji="☁️" className="h-5 w-5" />
|
||||
{t("resourceSections.pan")}
|
||||
</h3>
|
||||
<div className="rounded-2xl border border-slate-200 bg-white dark:border-slate-700 dark:bg-slate-900">
|
||||
<div className="flex flex-wrap gap-1 border-b border-slate-200 p-2 dark:border-slate-700">
|
||||
<div className="dn-card dn-pan rounded-2xl border border-slate-200 bg-white dark:border-slate-700 dark:bg-slate-900">
|
||||
<div className="dn-tabs flex flex-wrap gap-1 border-b border-slate-200 p-2 dark:border-slate-700">
|
||||
{data.pan.categories.map((cat) => (
|
||||
<button
|
||||
key={cat.id}
|
||||
type="button"
|
||||
onClick={() => setActivePanCategory(cat.id)}
|
||||
className={`rounded-lg px-4 py-2 text-sm font-medium transition-colors ${
|
||||
className={`dn-tab rounded-lg px-4 py-2 text-sm font-medium transition-colors ${
|
||||
activePanCategory === cat.id
|
||||
? "bg-sky-100 text-sky-700 dark:bg-sky-900/50 dark:text-sky-300"
|
||||
? "dn-tab-active bg-sky-100 text-sky-700 dark:bg-sky-900/50 dark:text-sky-300"
|
||||
: "text-slate-600 hover:bg-slate-100 dark:text-slate-400 dark:hover:bg-slate-800"
|
||||
}`}
|
||||
>
|
||||
<span className="mr-1.5">{cat.icon}</span>
|
||||
<DigitalThemeIcon
|
||||
name={panCategoryIconNames[cat.id] ?? "file"}
|
||||
emoji={cat.icon}
|
||||
className="mr-1.5 inline h-4 w-4"
|
||||
/>
|
||||
{cat.title}
|
||||
</button>
|
||||
))}
|
||||
@@ -243,10 +255,14 @@ export default function ResourceNavigation({ data }: ResourceNavigationProps) {
|
||||
href={item.href}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer sponsored"
|
||||
className="flex items-center gap-3 rounded-xl border border-slate-100 p-3 transition-colors hover:border-sky-200 hover:bg-sky-50/50 dark:border-slate-700 dark:hover:border-sky-800 dark:hover:bg-sky-900/20"
|
||||
className="dn-resource-link flex items-center gap-3 rounded-xl border border-slate-100 p-3 transition-colors hover:border-sky-200 hover:bg-sky-50/50 dark:border-slate-700 dark:hover:border-sky-800 dark:hover:bg-sky-900/20"
|
||||
>
|
||||
<div className="flex h-10 w-10 shrink-0 items-center justify-center rounded-lg bg-slate-100 text-lg dark:bg-slate-800">
|
||||
{activeCategory.icon}
|
||||
<div className="dn-icon-box flex h-10 w-10 shrink-0 items-center justify-center rounded-lg bg-slate-100 text-lg dark:bg-slate-800">
|
||||
<DigitalThemeIcon
|
||||
name={panCategoryIconNames[activeCategory.id] ?? "file"}
|
||||
emoji={activeCategory.icon}
|
||||
className="h-5 w-5"
|
||||
/>
|
||||
</div>
|
||||
<div className="min-w-0 flex-1">
|
||||
<div className="font-medium text-slate-900 dark:text-slate-100">{item.name}</div>
|
||||
|
||||
Reference in New Issue
Block a user