Files
InfoGenie/InfoGenie-frontend/src/pages/ToolboxPage.js
2026-04-01 22:03:57 +08:00

118 lines
4.5 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import React, { useState } from 'react';
import { FiHardDrive, FiCloud } from 'react-icons/fi';
import clsx from 'clsx';
import { TOOLBOX_CATEGORIES } from '../config/Api60sConfig';
import FullscreenEmbed from '../components/FullscreenEmbed';
import {
PageWrapper,
PageHeader,
PageTitle,
FeatureGrid,
CatalogCard,
FeatureCardIcon,
FeatureCardTitle,
FeatureCardDesc,
FeatureCardUseCount,
} from '../styles/shared';
import { FEATURE_CARD_SECTION } from '../config/featureCardSections';
import { useFeatureCardClickStats } from '../hooks/useFeatureCardClickStats';
function headerColorForItem(item) {
if (!item) return '#4ade80';
for (const c of TOOLBOX_CATEGORIES) {
if (c.items.some((i) => i.id === item.id)) return c.color;
}
return '#4ade80';
}
const ToolboxPage = () => {
const [catId, setCatId] = useState(TOOLBOX_CATEGORIES[0].id);
const [embedItem, setEmbedItem] = useState(null);
const { counts, bump } = useFeatureCardClickStats(FEATURE_CARD_SECTION.TOOLBOX);
const cat = TOOLBOX_CATEGORIES.find((c) => c.id === catId) || TOOLBOX_CATEGORIES[0];
return (
<PageWrapper>
<PageHeader>
<PageTitle>工具箱</PageTitle>
</PageHeader>
{/* Tabs */}
<div className="flex gap-2.5 mx-auto mb-[18px] max-w-[1200px] px-5 overflow-x-auto justify-center sm:justify-start sm:px-4 sm:gap-2 [scrollbar-width:none] [&::-webkit-scrollbar]:hidden">
{TOOLBOX_CATEGORIES.map((c) => (
<button
key={c.id}
type="button"
onClick={() => setCatId(c.id)}
className={clsx(
'flex-shrink-0 flex items-center gap-1.5 px-5 py-2.5 rounded-xl text-sm font-semibold font-[inherit] cursor-pointer transition-all whitespace-nowrap border',
'sm:px-4 sm:py-[9px] sm:text-[13px] sm:rounded-[10px]',
catId === c.id
? 'border-transparent text-white [text-shadow:0_1px_2px_rgba(0,0,0,0.12)] shadow-[0_4px_16px_rgba(34,197,94,0.35)] hover:-translate-y-px'
: 'border-white/55 bg-white/92 text-[#166534] hover:-translate-y-px hover:border-[rgba(129,199,132,0.8)]',
)}
style={catId === c.id ? { background: `linear-gradient(135deg, ${c.color} 0%, #22c55e 100%)` } : {}}
>
{c.icon} {c.title}
</button>
))}
</div>
<FeatureGrid key={catId}>
{cat.items.map((item) => (
<CatalogCard
key={item.id}
$c={cat.color}
onClick={() => {
bump(item.id);
setEmbedItem(item);
}}
>
<FeatureCardUseCount>{Number(counts[item.id]) || 0}</FeatureCardUseCount>
<FeatureCardIcon>{item.icon}</FeatureCardIcon>
<FeatureCardTitle>{item.title}</FeatureCardTitle>
<FeatureCardDesc>{item.desc}</FeatureCardDesc>
{/* 右下角 离线/联网 标识 */}
<span
className={clsx(
'absolute right-[7px] bottom-[7px] w-[30px] h-[30px] rounded-[9px]',
'flex items-center justify-center pointer-events-none',
'border shadow-[0_1px_4px_rgba(15,80,40,0.06)]',
'sm:w-[26px] sm:h-[26px] sm:right-[5px] sm:bottom-[5px] sm:rounded-[8px]',
item.offlineOk
? 'bg-[rgba(236,253,245,0.98)] text-[#15803d] border-[rgba(34,197,94,0.28)]'
: 'bg-[rgba(255,251,235,0.98)] text-[#c2410c] border-[rgba(251,146,60,0.35)]',
)}
title={
item.offlineOk
? '可离线PWA 缓存后页面与脚本可本地加载(使用网络流/API 时仍需联网)'
: '需联网:依赖云端服务'
}
aria-label={item.offlineOk ? '可离线' : '需联网'}
>
{item.offlineOk ? (
<FiHardDrive className="w-4 h-4 sm:w-3.5 sm:h-3.5" strokeWidth={2.25} aria-hidden />
) : (
<FiCloud className="w-4 h-4 sm:w-3.5 sm:h-3.5" strokeWidth={2.25} aria-hidden />
)}
</span>
</CatalogCard>
))}
</FeatureGrid>
{embedItem && (
<FullscreenEmbed
title={embedItem.title}
url={embedItem.link}
headerColor={headerColorForItem(embedItem)}
onClose={() => setEmbedItem(null)}
/>
)}
</PageWrapper>
);
};
export default ToolboxPage;