// ========================================================= // FBIF 资讯订阅 · 标签管理 (Tag manager) // Tags are user-defined labels applied to SOURCES. Here you // create/delete tags, toggle their visibility in the sidebar, // and manage which sources carry each tag. // ========================================================= const SWATCHES = ['#E8542E', '#8A5A2B', '#1F8A5B', '#3DA35D', '#2A6FDB', '#7A4FBB', '#C0392B', '#0F8B8D', '#B45F00', '#555E6B', '#1456F0', '#646A73']; // popover: pick which sources carry this tag (checkboxes + search + count) const SourcePickPopover = ({ tag, sources, anchorRef, onToggleSourceTag, onClose }) => { const [q, setQ] = React.useState(''); const list = sources.filter(s => s.name.includes(q)); const count = sources.filter(s => s.tags.includes(tag.id)).length; return (
哪些来源属于「{tag.name}」已选 {count}
setQ(e.target.value)} width="100%" height={30} />
{list.map(s => { const on = s.tags.includes(tag.id); return ( onToggleSourceTag(s.id, tag.id)} label={{s.name}} right={{on && }} /> ); })} {list.length === 0 &&
无匹配来源
}
); }; const TagRow = ({ tag, data, onToggleSub, onDelete, onToggleSourceTag }) => { const [hover, setHover] = React.useState(false); const [pickOpen, setPickOpen] = React.useState(false); const pickBtnRef = React.useRef(null); const used = data.SOURCES.filter(s => s.tags.includes(tag.id)); const articleCount = used.filter(s => s.subscribed).reduce((a, s) => a + (s.article_count || 0), 0); return (
setHover(true)} onMouseLeave={() => setHover(false)} style={{ display: 'flex', alignItems: 'center', gap: 12, padding: '0 16px', height: 56, borderBottom: '1px solid #EDEFF2', background: hover ? '#F7F8FA' : '#fff' }}>
{tag.name}
{used.length} 个来源
{articleCount} 条资讯
{pickOpen && setPickOpen(false)} />}
侧栏显示 onToggleSub(tag)} />
); }; const TagManager = ({ data, onCreateTag, onDeleteTag, onToggleTagSub, onToggleSourceTag, onClose }) => { useLucide(); const [name, setName] = React.useState(''); const [color, setColor] = React.useState(SWATCHES[0]); const create = () => { const v = name.trim(); if (!v) return; onCreateTag(v, color); setName(''); }; return (

标签管理

标签是你给「来源」打的组织标签。一个来源可有多个标签,时间线可按标签筛选。

{/* 新建标签 */}
新建标签
setName(e.target.value)} onKeyDown={e => e.key === 'Enter' && create()} width={240} height={36} />
颜色 {SWATCHES.slice(0, 8).map(c => (
{!name.trim() &&
输入标签名称后即可创建(同名标签会被拦截)。
}
{/* tag list */}
全部标签 {data.TAGS.length}
标签 关联来源 资讯数 侧栏
{data.TAGS.map(t => ( ))} {data.TAGS.length === 0 &&
暂无标签,先创建一个
}
); }; Object.assign(window, { TagManager });