import { useState, useEffect } from 'react'; import { config as configApi } from '../api'; export default function Output() { const [preview, setPreview] = useState(''); const [loading, setLoading] = useState(false); const [copiedSurge, setCopiedSurge] = useState(false); const [copiedClash, setCopiedClash] = useState(false); const [copiedSsr, setCopiedSsr] = useState(false); const [surgeToken, setSurgeToken] = useState(''); const surgeUrl = surgeToken ? `${window.location.origin}/surge/${surgeToken}` : ''; const clashUrl = surgeToken ? `${window.location.origin}/clash/${surgeToken}` : ''; const ssrUrl = surgeToken ? `${window.location.origin}/ssr/${surgeToken}` : ''; const loadToken = async () => { try { const data = await configApi.getSurgeToken(); setSurgeToken(data.token || ''); } catch {} }; const handleRegenerate = async () => { if (!confirm('重新生成后,旧的订阅链接将失效(Surge / Clash / SSR 三条链接同时更新)。确定继续?')) return; try { const data = await configApi.regenerateSurgeToken(); setSurgeToken(data.token); loadPreview(); } catch {} }; const loadPreview = async () => { setLoading(true); try { const data = await configApi.preview(); setPreview(data.config); } catch (err: any) { setPreview(`# Error: ${err.message}`); } finally { setLoading(false); } }; useEffect(() => { loadToken(); loadPreview(); }, []); const makeCopyHandler = (url: string, setter: (v: boolean) => void) => () => { navigator.clipboard.writeText(url); setter(true); setTimeout(() => setter(false), 2000); }; return (

输出配置

Surge / Clash / SSR 订阅链接和配置预览

{/* Surge URL */} {/* Clash URL */} {/* SSR URL */} {/* Preview */}
SURGE 配置预览
        {preview || '(empty)'}
      
); } function UrlCard({ label, url, copied, onCopy, onRegenerate, }: { label: string; url: string; copied: boolean; onCopy: () => void; onRegenerate?: () => void; }) { return (
{label}
{url || '加载中...'} {onRegenerate && ( )}
); } const styles = { title: { fontFamily: 'var(--font-mono)' as const, fontSize: 16, fontWeight: 600 as const, color: 'var(--text-primary)', marginBottom: 4, }, subtitle: { fontSize: 12, color: 'var(--text-secondary)', marginBottom: 20, }, card: { background: 'var(--bg-input)', border: '1px solid var(--border)', borderRadius: 'var(--radius)', padding: 16, marginBottom: 12, }, cardLabel: { fontSize: 10, fontFamily: 'var(--font-mono)' as const, color: 'var(--text-muted)', textTransform: 'uppercase' as const, letterSpacing: '0.1em', marginBottom: 8, }, urlCode: { flex: 1, fontFamily: 'var(--font-mono)' as const, fontSize: 13, color: 'var(--accent)', userSelect: 'all' as const, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' as const, }, sectionLabel: { fontSize: 10, fontFamily: 'var(--font-mono)' as const, color: 'var(--text-muted)', textTransform: 'uppercase' as const, letterSpacing: '0.1em', }, pre: { background: 'var(--bg-input)', border: '1px solid var(--border)', borderRadius: 'var(--radius)', padding: 16, fontFamily: 'var(--font-mono)' as const, fontSize: 11, lineHeight: 1.6, color: 'var(--text-secondary)', overflow: 'auto', maxHeight: 'calc(100vh - 480px)', whiteSpace: 'pre-wrap' as const, wordBreak: 'break-all' as const, }, };