118 lines
4.5 KiB
JavaScript
118 lines
4.5 KiB
JavaScript
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;
|