fix: global font size increase + button size increase
This commit is contained in:
@@ -32,26 +32,26 @@ export default function FilterCard({ filter, liked, onLike, onDownload }: Filter
|
||||
{/* 信息 */}
|
||||
<div className="p-2 space-y-1">
|
||||
<div className="flex items-center justify-between">
|
||||
<h3 className="text-[9px] font-semibold tracking-[0.1em] uppercase text-[#e0e0e0] truncate">
|
||||
<h3 className="text-[12px] font-semibold tracking-[0.1em] uppercase text-[#e0e0e0] truncate">
|
||||
{filter.title}
|
||||
</h3>
|
||||
</div>
|
||||
<p className="text-[8px] font-mono text-[#555] truncate">{filter.author}</p>
|
||||
<p className="text-[12px] font-mono text-[#555] truncate">{filter.author}</p>
|
||||
|
||||
<div className="flex items-center justify-between pt-1 border-t border-[#333]">
|
||||
<div className="flex items-center gap-2">
|
||||
<button
|
||||
onClick={() => onLike(filter.id)}
|
||||
className={`text-[8px] font-mono transition-colors duration-75
|
||||
className={`text-[12px] font-mono transition-colors duration-75
|
||||
${liked ? 'text-[#ff4500]' : 'text-[#555] hover:text-[#888]'}`}
|
||||
>
|
||||
♥ {filter.likes + (liked ? 1 : 0)}
|
||||
</button>
|
||||
<span className="text-[8px] font-mono text-[#555]">↓ {filter.downloads}</span>
|
||||
<span className="text-[12px] font-mono text-[#555]">↓ {filter.downloads}</span>
|
||||
</div>
|
||||
<button
|
||||
onClick={() => onDownload(filter.id)}
|
||||
className="text-[7px] font-semibold tracking-[0.1em] uppercase text-[#888] border border-[#333] px-1.5 py-0.5
|
||||
className="text-[12px] font-semibold tracking-[0.1em] uppercase text-[#888] border border-[#333] px-1.5 py-0.5
|
||||
hover:border-[#ff4500] hover:text-[#ff4500] transition-colors duration-75"
|
||||
>
|
||||
获取
|
||||
|
||||
@@ -32,7 +32,7 @@ function SliderControl({ label, value, min, max, step, unit, onChange }: {
|
||||
const pct = ((value - min) / (max - min)) * 100;
|
||||
return (
|
||||
<div className="flex items-center gap-2 py-1.5 border-b border-[#333] last:border-b-0">
|
||||
<span className="text-[8px] font-mono text-[#555] w-16 shrink-0 uppercase tracking-wider">{label}</span>
|
||||
<span className="text-[12px] font-mono text-[#555] w-16 shrink-0 uppercase tracking-wider">{label}</span>
|
||||
<div className="flex-1 relative h-2 border border-[#333] bg-[#111]">
|
||||
<div className="absolute left-0 top-0 h-full bg-[#ff4500]" style={{ width: `${pct}%` }} />
|
||||
<input
|
||||
@@ -45,7 +45,7 @@ function SliderControl({ label, value, min, max, step, unit, onChange }: {
|
||||
className="absolute inset-0 w-full h-full opacity-0 cursor-pointer"
|
||||
/>
|
||||
</div>
|
||||
<span className="text-[8px] font-mono text-[#888] w-12 text-right">{value.toFixed(step < 0.1 ? 2 : 1)}{unit}</span>
|
||||
<span className="text-[12px] font-mono text-[#888] w-12 text-right">{value.toFixed(step < 0.1 ? 2 : 1)}{unit}</span>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -75,14 +75,14 @@ export default function FilterEditor({ initialParams, onSave, onCancel }: Filter
|
||||
<div className="p-2.5 space-y-2">
|
||||
<div className="flex items-center gap-2 border-b border-[#333] pb-1.5">
|
||||
<span className="material-symbols-outlined text-[14px] text-[#ff4500]">tune</span>
|
||||
<h2 className="text-[9px] font-bold tracking-[0.15em] uppercase text-[#e0e0e0]">滤镜编辑器</h2>
|
||||
<h2 className="text-[12px] font-bold tracking-[0.15em] uppercase text-[#e0e0e0]">滤镜编辑器</h2>
|
||||
</div>
|
||||
|
||||
<input
|
||||
value={name}
|
||||
onChange={e => setName(e.target.value)}
|
||||
placeholder="滤镜名称"
|
||||
className="w-full border border-[#333] bg-[#111] text-[#e0e0e0] px-2 py-1.5 text-[9px] font-mono
|
||||
className="w-full border border-[#333] bg-[#111] text-[#e0e0e0] px-2 py-1.5 text-[12px] font-mono
|
||||
placeholder:text-[#444] outline-none focus:border-[#ff4500] transition-colors duration-75"
|
||||
/>
|
||||
</div>
|
||||
@@ -91,7 +91,7 @@ export default function FilterEditor({ initialParams, onSave, onCancel }: Filter
|
||||
{/* Tone controls */}
|
||||
<Card serial="FLT-TONE">
|
||||
<div className="p-2.5">
|
||||
<h3 className="text-[8px] font-bold tracking-[0.15em] uppercase text-[#888] mb-1">色调</h3>
|
||||
<h3 className="text-[12px] font-bold tracking-[0.15em] uppercase text-[#888] mb-1">色调</h3>
|
||||
<SliderControl label="亮度" value={params.brightness} min={-100} max={100} step={1} unit="" onChange={update('brightness')} />
|
||||
<SliderControl label="对比度" value={params.contrast} min={-100} max={100} step={1} unit="" onChange={update('contrast')} />
|
||||
<SliderControl label="饱和度" value={params.saturation} min={-100} max={100} step={1} unit="" onChange={update('saturation')} />
|
||||
@@ -103,7 +103,7 @@ export default function FilterEditor({ initialParams, onSave, onCancel }: Filter
|
||||
{/* Color balance */}
|
||||
<Card serial="FLT-RGB">
|
||||
<div className="p-2.5">
|
||||
<h3 className="text-[8px] font-bold tracking-[0.15em] uppercase text-[#888] mb-1">色彩平衡</h3>
|
||||
<h3 className="text-[12px] font-bold tracking-[0.15em] uppercase text-[#888] mb-1">色彩平衡</h3>
|
||||
<SliderControl label="R" value={params.rGain} min={0} max={2} step={0.01} unit="" onChange={update('rGain')} />
|
||||
<SliderControl label="G" value={params.gGain} min={0} max={2} step={0.01} unit="" onChange={update('gGain')} />
|
||||
<SliderControl label="B" value={params.bGain} min={0} max={2} step={0.01} unit="" onChange={update('bGain')} />
|
||||
@@ -114,7 +114,7 @@ export default function FilterEditor({ initialParams, onSave, onCancel }: Filter
|
||||
{/* Preview bar */}
|
||||
<Card serial="FLT-PREV">
|
||||
<div className="p-2.5 space-y-1">
|
||||
<h3 className="text-[8px] font-bold tracking-[0.15em] uppercase text-[#888]">预览</h3>
|
||||
<h3 className="text-[12px] font-bold tracking-[0.15em] uppercase text-[#888]">预览</h3>
|
||||
<div className="flex gap-1 h-16">
|
||||
{/* Color gradient preview affected by params */}
|
||||
<div
|
||||
@@ -143,9 +143,9 @@ export default function FilterEditor({ initialParams, onSave, onCancel }: Filter
|
||||
|
||||
{/* Actions */}
|
||||
<div className="flex gap-2">
|
||||
<Button variant="primary" size="sm" className="flex-1 text-[9px]" onClick={() => onSave?.(params)}>保存滤镜</Button>
|
||||
<Button variant="ghost" size="sm" className="text-[9px]" onClick={onCancel}>取消</Button>
|
||||
<Button variant="ghost" size="sm" className="text-[9px]" onClick={() => setParams({ ...DEFAULT_PARAMS })}>重置</Button>
|
||||
<Button variant="primary" size="sm" className="flex-1 text-[12px]" onClick={() => onSave?.(params)}>保存滤镜</Button>
|
||||
<Button variant="ghost" size="sm" className="text-[12px]" onClick={onCancel}>取消</Button>
|
||||
<Button variant="ghost" size="sm" className="text-[12px]" onClick={() => setParams({ ...DEFAULT_PARAMS })}>重置</Button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -17,45 +17,39 @@ export default function DesktopIcon({ icon, label, onClick, disabled, locked, vi
|
||||
<button
|
||||
onClick={onClick}
|
||||
disabled={disabled}
|
||||
className="relative flex flex-col items-center justify-center gap-1.5 py-5 border border-[#333]
|
||||
className="relative flex flex-col items-center justify-center gap-2 py-6 border border-[#333]
|
||||
transition-colors duration-75 cursor-pointer disabled:cursor-not-allowed
|
||||
hover:bg-[#222] hover:border-[#555] group"
|
||||
>
|
||||
{/* 坐标标记 */}
|
||||
<span className="tech-sn absolute top-1 left-1 opacity-0 group-hover:opacity-100 transition-opacity">
|
||||
<span className="tech-sn absolute top-1.5 left-1.5 opacity-0 group-hover:opacity-100 transition-opacity">
|
||||
X{index % 4}Y{Math.floor(index / 4)}
|
||||
</span>
|
||||
|
||||
{/* 锁定遮罩 */}
|
||||
{isBlocked && (
|
||||
<div className="absolute inset-0 bg-[#1a1a1a]/80 flex items-center justify-center z-10">
|
||||
<div className="flex flex-col items-center gap-1">
|
||||
<span className="text-[#555] text-[12px]">🔒</span>
|
||||
<span className="text-[7px] font-mono text-[#444] tracking-wider">
|
||||
<span className="text-[#555] text-[16px]">🔒</span>
|
||||
<span className="text-[9px] font-mono text-[#444] tracking-wider">
|
||||
{vip ? 'VIP ONLY' : '需登录'}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* 图标 */}
|
||||
<span className={`material-symbols-outlined text-[24px] transition-colors duration-75
|
||||
<span className={`material-symbols-outlined text-[28px] transition-colors duration-75
|
||||
${isBlocked ? 'text-[#444]' : 'text-[#888] group-hover:text-[#ff4500]'}`}>
|
||||
{icon}
|
||||
</span>
|
||||
|
||||
{/* 标签 */}
|
||||
<span className={`text-[9px] font-semibold tracking-[0.12em] uppercase transition-colors duration-75
|
||||
<span className={`text-[11px] font-semibold tracking-[0.12em] uppercase transition-colors duration-75
|
||||
${isBlocked ? 'text-[#444]' : 'text-[#555] group-hover:text-[#e0e0e0]'}`}>
|
||||
{label}
|
||||
</span>
|
||||
|
||||
{/* VIP 标记 */}
|
||||
{vip && !isBlocked && (
|
||||
<span className="absolute top-1.5 right-1.5 text-[7px] text-[#ff4500]">✦</span>
|
||||
<span className="absolute top-2 right-2 text-[9px] text-[#ff4500]">✦</span>
|
||||
)}
|
||||
|
||||
{/* 底部强调线 */}
|
||||
{!isBlocked && (
|
||||
<span className="absolute bottom-0 left-1/4 right-1/4 h-[1px] bg-[#ff4500] scale-x-0 group-hover:scale-x-100 transition-transform duration-75" />
|
||||
)}
|
||||
|
||||
@@ -1,12 +1,7 @@
|
||||
import React from 'react';
|
||||
import { useNavigate, useLocation } from 'react-router-dom';
|
||||
|
||||
interface DockItem {
|
||||
id: string;
|
||||
label: string;
|
||||
}
|
||||
|
||||
const NAV_ITEMS: DockItem[] = [
|
||||
const NAV_ITEMS = [
|
||||
{ id: 'optimization', label: '快速优化' },
|
||||
{ id: 'exposure', label: '画面滤镜' },
|
||||
{ id: 'filter-community', label: '滤镜社区' },
|
||||
@@ -31,7 +26,7 @@ export default function SubNavBar() {
|
||||
if (!currentPage || currentPage === 'home') return null;
|
||||
|
||||
return (
|
||||
<div className="fixed bottom-0 left-0 right-0 z-30 flex justify-center pb-1.5">
|
||||
<div className="fixed bottom-0 left-0 right-0 z-30 flex justify-center pb-2">
|
||||
<div className="flex border border-[#333] bg-[#1a1a1a] relative">
|
||||
{NAV_ITEMS.map(item => {
|
||||
const isActive = currentPage === item.id;
|
||||
@@ -39,7 +34,7 @@ export default function SubNavBar() {
|
||||
<button
|
||||
key={item.id}
|
||||
onClick={() => navigate('/' + item.id)}
|
||||
className={`relative px-3 py-1.5 text-[8px] font-semibold tracking-[0.1em] uppercase
|
||||
className={`relative px-4 py-2.5 text-[11px] font-semibold tracking-[0.1em] uppercase
|
||||
border-r border-[#333] last:border-r-0 transition-colors duration-75
|
||||
${isActive ? 'bg-[#ff4500]/10 text-[#ff4500]' : 'text-[#555] hover:text-[#888] hover:bg-[#222]'}`}
|
||||
>
|
||||
|
||||
@@ -13,55 +13,52 @@ function callElectron(method: string) {
|
||||
|
||||
export default function TopHud({ title = '码枪堂 2.0', subtitle, sections = [], onBack }: TopHudProps) {
|
||||
return (
|
||||
<div className="flex items-center justify-between border-b border-[#333] bg-[#1a1a1a] px-3 py-1 select-none">
|
||||
<div className="flex items-center gap-2">
|
||||
{/* Back button */}
|
||||
<div className="flex items-center justify-between border-b border-[#333] bg-[#1a1a1a] px-4 py-1.5 select-none">
|
||||
<div className="flex items-center gap-2.5">
|
||||
{onBack && (
|
||||
<button
|
||||
onClick={onBack}
|
||||
className="text-[#555] hover:text-[#e0e0e0] text-[10px] px-1 py-0.5 border border-[#333] hover:border-[#555] transition-colors duration-75"
|
||||
className="text-[#555] hover:text-[#e0e0e0] text-[14px] px-1.5 py-0.5 border border-[#333] hover:border-[#555] transition-colors duration-75"
|
||||
>
|
||||
←
|
||||
</button>
|
||||
)}
|
||||
<span className="text-[#ff4500] text-[8px]">◆</span>
|
||||
<h1 className="text-[9px] font-bold tracking-[0.15em] uppercase text-[#e0e0e0]">{title}</h1>
|
||||
<span className="text-[#ff4500] text-[10px]">◆</span>
|
||||
<h1 className="text-[13px] font-bold tracking-[0.15em] uppercase text-[#e0e0e0]">{title}</h1>
|
||||
{subtitle && (
|
||||
<>
|
||||
<span className="text-[#444] text-[8px]">|</span>
|
||||
<span className="text-[#444] text-[10px]">|</span>
|
||||
<span className="tech-sn">{subtitle}</span>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<div className="flex items-center gap-3">
|
||||
{sections.map((s, i) => (
|
||||
<span key={i} className="flex items-center gap-1">
|
||||
<span className="text-[7px] tracking-[0.15em] uppercase text-[#555]">{s.label}</span>
|
||||
<span className="text-[9px] font-mono text-[#e0e0e0]">{s.value}</span>
|
||||
<span className="text-[10px] tracking-[0.15em] uppercase text-[#555]">{s.label}</span>
|
||||
<span className="text-[11px] font-mono text-[#e0e0e0]">{s.value}</span>
|
||||
</span>
|
||||
))}
|
||||
<span className="w-[1px] h-3 bg-[#333]" />
|
||||
|
||||
{/* Window controls */}
|
||||
<span className="w-px h-4 bg-[#333]" />
|
||||
<button
|
||||
onClick={() => callElectron('minimizeWindow')}
|
||||
className="text-[#555] hover:text-[#e0e0e0] text-[14px] leading-none px-1 transition-colors duration-75"
|
||||
className="text-[#555] hover:text-[#e0e0e0] text-[18px] leading-none px-1 transition-colors duration-75"
|
||||
>
|
||||
─
|
||||
</button>
|
||||
<button
|
||||
onClick={() => callElectron('maximizeWindow')}
|
||||
className="text-[#555] hover:text-[#e0e0e0] text-[10px] leading-none px-1 transition-colors duration-75"
|
||||
className="text-[#555] hover:text-[#e0e0e0] text-[14px] leading-none px-1 transition-colors duration-75"
|
||||
>
|
||||
☐
|
||||
</button>
|
||||
<button
|
||||
onClick={() => callElectron('closeWindow')}
|
||||
className="text-[#555] hover:text-[#cc3300] text-[12px] leading-none px-1 transition-colors duration-75"
|
||||
className="text-[#555] hover:text-[#cc3300] text-[16px] leading-none px-1 transition-colors duration-75"
|
||||
>
|
||||
✕
|
||||
</button>
|
||||
<span className="text-[8px] font-mono text-[#444] ml-1">V0.2.1</span>
|
||||
<span className="text-[10px] font-mono text-[#444] ml-1">V0.2.1</span>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -40,29 +40,27 @@ export default function OptimizeItem({ item, onToggle, disabled }: OptimizeItemP
|
||||
const isOptimized = item.status === 'optimized';
|
||||
|
||||
return (
|
||||
<div
|
||||
className={`border transition-colors duration-75 bg-[#1a1a1a]/60 ${statusStyles[item.status]}`}
|
||||
>
|
||||
<div className="flex items-center gap-2 px-2 py-2">
|
||||
<div className={`w-1 h-1 shrink-0 rounded-full ${isOptimized ? 'bg-[#ff4500]' : 'bg-[#333]'}`} />
|
||||
<div className={`border transition-colors duration-75 bg-[#1a1a1a]/60 ${statusStyles[item.status]}`}>
|
||||
<div className="flex items-center gap-3 px-3 py-2.5">
|
||||
<div className={`w-1.5 h-1.5 shrink-0 rounded-full ${isOptimized ? 'bg-[#ff4500]' : 'bg-[#333]'}`} />
|
||||
|
||||
<div className="flex-1 min-w-0">
|
||||
<div className="flex items-center gap-1.5">
|
||||
<span className="material-symbols-outlined text-[12px] text-[#555]">{item.icon}</span>
|
||||
<span className="text-[9px] font-semibold tracking-[0.1em] uppercase text-[#e0e0e0] truncate">
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="material-symbols-outlined text-[14px] text-[#555]">{item.icon}</span>
|
||||
<span className="text-[13px] font-semibold tracking-[0.1em] uppercase text-[#e0e0e0] truncate">
|
||||
{item.label}
|
||||
</span>
|
||||
<span className={`text-[7px] font-mono tracking-wider px-1 py-[1px] border ${statusTextStyles[item.status]} border-current/30`}>
|
||||
<span className={`text-[12px] font-mono tracking-wider px-1.5 py-[1px] border ${statusTextStyles[item.status]} border-current/30`}>
|
||||
{statusLabels[item.status]}
|
||||
</span>
|
||||
</div>
|
||||
<p className="text-[8px] text-[#555] mt-0.5 truncate">{item.description}</p>
|
||||
<p className="text-[12px] text-[#555] mt-0.5 truncate">{item.description}</p>
|
||||
</div>
|
||||
|
||||
<button
|
||||
onClick={() => onToggle(item.id, isOptimized ? 'restore' : 'optimize')}
|
||||
disabled={disabled || item.status === 'error'}
|
||||
className={`w-[64px] shrink-0 py-1.5 text-[8px] font-semibold tracking-[0.1em] uppercase border transition-colors duration-75
|
||||
className={`w-[80px] shrink-0 py-2 text-[12px] font-semibold tracking-[0.1em] uppercase border transition-colors duration-75
|
||||
${isOptimized
|
||||
? 'border-[#555] text-[#555] hover:border-[#ff4500] hover:text-[#ff4500]'
|
||||
: 'border-[#555] text-[#888] hover:border-[#ff4500] hover:text-[#ff4500]'
|
||||
|
||||
@@ -15,20 +15,20 @@ export default function OptimizeResult({ success, message, details, onClose }: O
|
||||
{success ? '▸' : '✕'}
|
||||
</span>
|
||||
<div className="flex-1 min-w-0">
|
||||
<h3 className="text-[10px] font-bold tracking-[0.12em] uppercase text-[#e0e0e0]">
|
||||
<h3 className="text-[12px] font-bold tracking-[0.12em] uppercase text-[#e0e0e0]">
|
||||
{success ? '优化完成' : '优化失败'}
|
||||
</h3>
|
||||
<p className="text-[8px] font-mono text-[#888] mt-0.5">{message}</p>
|
||||
<p className="text-[12px] font-mono text-[#888] mt-0.5">{message}</p>
|
||||
{details && details.length > 0 && (
|
||||
<div className="mt-1.5 space-y-0.5">
|
||||
{details.map((d, i) => (
|
||||
<p key={i} className="text-[7px] font-mono text-[#555]">▸ {d}</p>
|
||||
<p key={i} className="text-[12px] font-mono text-[#555]">▸ {d}</p>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
{onClose && (
|
||||
<button onClick={onClose} className="text-[#555] hover:text-[#e0e0e0] text-[10px] leading-none transition-colors duration-75">
|
||||
<button onClick={onClose} className="text-[#555] hover:text-[#e0e0e0] text-[12px] leading-none transition-colors duration-75">
|
||||
✕
|
||||
</button>
|
||||
)}
|
||||
|
||||
@@ -20,14 +20,14 @@ export default function CategoryTabs({ categories, activeCode, onSelect, classNa
|
||||
<button
|
||||
key={cat.code}
|
||||
onClick={() => onSelect(cat.code)}
|
||||
className={`relative px-2.5 py-1.5 text-[8px] font-semibold tracking-[0.08em] uppercase border-r border-[#333] last:border-r-0 transition-colors duration-75
|
||||
className={`relative px-2.5 py-1.5 text-[12px] font-semibold tracking-[0.08em] uppercase border-r border-[#333] last:border-r-0 transition-colors duration-75
|
||||
${activeCode === cat.code
|
||||
? 'text-[#ff4500] bg-[#ff4500]/10'
|
||||
: 'text-[#555] hover:text-[#888] hover:bg-[#222]'
|
||||
}`}
|
||||
>
|
||||
{cat.name}
|
||||
<span className="ml-1 text-[7px] text-[#444]">{cat.code}</span>
|
||||
<span className="ml-1 text-[12px] text-[#444]">{cat.code}</span>
|
||||
{activeCode === cat.code && (
|
||||
<span className="absolute bottom-0 left-1 right-1 h-[1px] bg-[#ff4500]" />
|
||||
)}
|
||||
|
||||
@@ -36,13 +36,13 @@ export default function SchemeCard({ scheme, isFavorited, onFavorite, onUse, onC
|
||||
{/* 标题 */}
|
||||
<div className="flex items-start justify-between gap-2">
|
||||
<div className="min-w-0 flex-1">
|
||||
<h3 className="text-[10px] font-bold tracking-[0.08em] uppercase text-[#e0e0e0] truncate">
|
||||
<h3 className="text-[12px] font-bold tracking-[0.08em] uppercase text-[#e0e0e0] truncate">
|
||||
{scheme.title || '未命名方案'}
|
||||
</h3>
|
||||
<p className="text-[8px] font-mono text-[#555] mt-0.5">{scheme.weaponName || scheme.category || '通用'}</p>
|
||||
<p className="text-[12px] font-mono text-[#555] mt-0.5">{scheme.weaponName || scheme.category || '通用'}</p>
|
||||
</div>
|
||||
{scheme.isOfficial && (
|
||||
<span className="text-[7px] font-semibold tracking-[0.1em] uppercase text-[#ff4500] border border-[#ff4500]/30 px-1 py-0.5">
|
||||
<span className="text-[12px] font-semibold tracking-[0.1em] uppercase text-[#ff4500] border border-[#ff4500]/30 px-1 py-0.5">
|
||||
官方
|
||||
</span>
|
||||
)}
|
||||
@@ -50,19 +50,19 @@ export default function SchemeCard({ scheme, isFavorited, onFavorite, onUse, onC
|
||||
|
||||
{/* 作者 */}
|
||||
{scheme.user?.username && (
|
||||
<p className="text-[8px] font-mono text-[#555]">作者: {scheme.user.username}</p>
|
||||
<p className="text-[12px] font-mono text-[#555]">作者: {scheme.user.username}</p>
|
||||
)}
|
||||
|
||||
{/* 价格 */}
|
||||
{scheme.price > 0 && (
|
||||
<p className="text-[8px] font-mono text-[#555]">💰 {scheme.price}</p>
|
||||
<p className="text-[12px] font-mono text-[#555]">💰 {scheme.price}</p>
|
||||
)}
|
||||
|
||||
{/* 操作按钮 */}
|
||||
<div className="flex items-center gap-2 mt-auto pt-1 border-t border-[#333]">
|
||||
<button
|
||||
onClick={e => { e.stopPropagation(); onFavorite?.(scheme.id); }}
|
||||
className={`text-[8px] font-mono px-1.5 py-1 border transition-colors duration-75
|
||||
className={`text-[12px] font-mono px-1.5 py-1 border transition-colors duration-75
|
||||
${isFavorited
|
||||
? 'border-[#ff4500] text-[#ff4500]'
|
||||
: 'border-[#333] text-[#555] hover:border-[#555]'}`}
|
||||
@@ -71,7 +71,7 @@ export default function SchemeCard({ scheme, isFavorited, onFavorite, onUse, onC
|
||||
</button>
|
||||
<button
|
||||
onClick={e => { e.stopPropagation(); onUse?.(scheme.id); }}
|
||||
className="ml-auto text-[8px] font-semibold tracking-[0.1em] uppercase text-[#888] border border-[#333] px-1.5 py-1
|
||||
className="ml-auto text-[12px] font-semibold tracking-[0.1em] uppercase text-[#888] border border-[#333] px-1.5 py-1
|
||||
hover:border-[#ff4500] hover:text-[#ff4500] transition-colors duration-75"
|
||||
>
|
||||
使用
|
||||
@@ -79,7 +79,7 @@ export default function SchemeCard({ scheme, isFavorited, onFavorite, onUse, onC
|
||||
</div>
|
||||
|
||||
{/* 统计数据 */}
|
||||
<div className="flex items-center gap-3 text-[7px] font-mono text-[#555]">
|
||||
<div className="flex items-center gap-3 text-[12px] font-mono text-[#555]">
|
||||
<span>👁 {scheme.viewsCount}</span>
|
||||
<span>⬇ {scheme.downloadsCount}</span>
|
||||
<span>👍 {scheme.likesCount}</span>
|
||||
|
||||
@@ -38,7 +38,7 @@ export default function SchemeList({
|
||||
return (
|
||||
<div className="flex flex-col items-center justify-center py-12 gap-2 border border-[#333]">
|
||||
<span className="text-[24px] text-[#444]">📭</span>
|
||||
<p className="text-[10px] font-mono text-[#555]">暂无方案数据</p>
|
||||
<p className="text-[12px] font-mono text-[#555]">暂无方案数据</p>
|
||||
<span className="tech-sn">EMPTY / 404</span>
|
||||
</div>
|
||||
);
|
||||
@@ -65,7 +65,7 @@ export default function SchemeList({
|
||||
<button
|
||||
disabled={page <= 1}
|
||||
onClick={() => onPageChange(page - 1)}
|
||||
className="px-2 py-1 text-[8px] font-mono text-[#555] border border-[#333] disabled:opacity-30 hover:border-[#555]"
|
||||
className="px-2 py-1 text-[12px] font-mono text-[#555] border border-[#333] disabled:opacity-30 hover:border-[#555]"
|
||||
>
|
||||
◀
|
||||
</button>
|
||||
@@ -73,7 +73,7 @@ export default function SchemeList({
|
||||
<button
|
||||
key={i}
|
||||
onClick={() => onPageChange(i + 1)}
|
||||
className={`px-2 py-1 text-[8px] font-mono border transition-colors duration-75
|
||||
className={`px-2 py-1 text-[12px] font-mono border transition-colors duration-75
|
||||
${page === i + 1
|
||||
? 'border-[#ff4500] text-[#ff4500] bg-[#ff4500]/10'
|
||||
: 'border-[#333] text-[#555] hover:border-[#555]'}`}
|
||||
@@ -84,7 +84,7 @@ export default function SchemeList({
|
||||
<button
|
||||
disabled={page >= totalPages}
|
||||
onClick={() => onPageChange(page + 1)}
|
||||
className="px-2 py-1 text-[8px] font-mono text-[#555] border border-[#333] disabled:opacity-30 hover:border-[#555]"
|
||||
className="px-2 py-1 text-[12px] font-mono text-[#555] border border-[#333] disabled:opacity-30 hover:border-[#555]"
|
||||
>
|
||||
▶
|
||||
</button>
|
||||
|
||||
@@ -21,9 +21,9 @@ const variantStyles: Record<ButtonVariant, string> = {
|
||||
};
|
||||
|
||||
const sizeStyles: Record<ButtonSize, string> = {
|
||||
sm: 'px-3 py-1.5 text-[10px]',
|
||||
md: 'px-5 py-2.5 text-[11px]',
|
||||
lg: 'px-7 py-3 text-[13px]',
|
||||
sm: 'px-4 py-2 text-[12px]',
|
||||
md: 'px-6 py-3 text-[13px]',
|
||||
lg: 'px-8 py-4 text-[15px]',
|
||||
};
|
||||
|
||||
export default function Button({
|
||||
|
||||
@@ -25,12 +25,11 @@ export default function Card({
|
||||
${hoverable ? 'hover:border-[#ff4500] cursor-pointer' : ''}
|
||||
${className}`}
|
||||
>
|
||||
{/* Cut corner decorations */}
|
||||
<div className="absolute top-0 left-0 w-2 h-2 border-t border-l border-[#ff4500]/40 pointer-events-none" />
|
||||
<div className="absolute bottom-0 right-0 w-2 h-2 border-b border-r border-[#ff4500]/40 pointer-events-none" />
|
||||
|
||||
{serial && (
|
||||
<span className="tech-sn absolute top-1 right-1">{serial}</span>
|
||||
<span className="tech-sn absolute top-1.5 right-1.5">{serial}</span>
|
||||
)}
|
||||
|
||||
{children}
|
||||
|
||||
@@ -21,34 +21,31 @@ export default function Panel({
|
||||
|
||||
return (
|
||||
<div className={`border border-[#333] bg-[#1a1a1a] relative ${className}`}>
|
||||
{/* Cut corner */}
|
||||
<div className="absolute top-0 left-0 w-2 h-2 border-t border-l border-[#ff4500]/40 pointer-events-none z-10" />
|
||||
<div className="absolute bottom-0 right-0 w-2 h-2 border-b border-r border-[#ff4500]/40 pointer-events-none z-10" />
|
||||
|
||||
{/* Header */}
|
||||
<div
|
||||
className={`flex items-center justify-between px-3 py-2.5 border-b border-[#333] select-none
|
||||
className={`flex items-center justify-between px-3 py-3 border-b border-[#333] select-none
|
||||
${collapsible ? 'cursor-pointer hover:bg-[#222]' : ''}`}
|
||||
onClick={() => collapsible && setOpen(!open)}
|
||||
>
|
||||
<div className="flex items-center gap-2 min-w-0">
|
||||
<span className="text-[#555] text-[9px] font-mono">▌</span>
|
||||
<h3 className="text-[10px] font-semibold tracking-[0.12em] uppercase text-[#e0e0e0] truncate">
|
||||
<span className="text-[#555] text-[11px] font-mono">▌</span>
|
||||
<h3 className="text-[12px] font-semibold tracking-[0.12em] uppercase text-[#e0e0e0] truncate">
|
||||
{title}
|
||||
</h3>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
{serial && <span className="tech-sn">{serial}</span>}
|
||||
{collapsible && (
|
||||
<span className={`text-[#555] text-[8px] transition-transform duration-75 ${open ? 'rotate-180' : ''}`}>
|
||||
<span className={`text-[#555] text-[10px] transition-transform duration-75 ${open ? 'rotate-180' : ''}`}>
|
||||
▼
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Body */}
|
||||
{open && <div className="px-3 py-2.5">{children}</div>}
|
||||
{open && <div className="px-3 py-3">{children}</div>}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user