Code-Schnipsel: Diff-History, Beschreibung sichtbar, Multi-Tag-Filter, Geteilt-von-mir Tab, nur genutzte Tags
This commit is contained in:
@@ -27,7 +27,16 @@ router.get('/', authenticate, (req, res) => {
|
|||||||
ORDER BY s.updated_at DESC
|
ORDER BY s.updated_at DESC
|
||||||
`).all(me).map(enrich);
|
`).all(me).map(enrich);
|
||||||
|
|
||||||
res.json({ own, shared });
|
const sharedByMe = db.prepare(`
|
||||||
|
SELECT s.*, u.username as shared_with_name
|
||||||
|
FROM snippets s
|
||||||
|
JOIN snippet_shares sh ON sh.snippet_id=s.id
|
||||||
|
JOIN users u ON u.id=sh.shared_with
|
||||||
|
WHERE s.user_id=?
|
||||||
|
ORDER BY s.title ASC
|
||||||
|
`).all(me).map(enrich);
|
||||||
|
|
||||||
|
res.json({ own, shared, sharedByMe });
|
||||||
});
|
});
|
||||||
|
|
||||||
// ── Einzelnes Snippet ────────────────────────────────────────────────────────
|
// ── Einzelnes Snippet ────────────────────────────────────────────────────────
|
||||||
|
|||||||
@@ -96,76 +96,123 @@ function SnippetShareModal({ snippet, onClose, toast }) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ── History Modal ─────────────────────────────────────────────────────────────
|
// ── Simple Diff ───────────────────────────────────────────────────────────────
|
||||||
|
function DiffView({ oldCode, newCode }) {
|
||||||
|
if (!oldCode) return (
|
||||||
|
<pre style={{margin:0,padding:'12px 14px',color:'#d0d0d0',fontFamily:"'Courier New',monospace",
|
||||||
|
fontSize:11,lineHeight:1.6,whiteSpace:'pre-wrap',wordBreak:'break-all',
|
||||||
|
background:'rgba(0,0,0,0.35)'}}>
|
||||||
|
{newCode}
|
||||||
|
</pre>
|
||||||
|
);
|
||||||
|
const oldLines = oldCode.split('\n');
|
||||||
|
const newLines = newCode.split('\n');
|
||||||
|
const maxLen = Math.max(oldLines.length, newLines.length);
|
||||||
|
const rows = [];
|
||||||
|
for (let i = 0; i < maxLen; i++) {
|
||||||
|
const o = oldLines[i];
|
||||||
|
const n = newLines[i];
|
||||||
|
if (o === n) {
|
||||||
|
rows.push({ type:'same', text: n ?? '' });
|
||||||
|
} else {
|
||||||
|
if (o !== undefined) rows.push({ type:'del', text: o });
|
||||||
|
if (n !== undefined) rows.push({ type:'add', text: n });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<div style={{background:'rgba(0,0,0,0.4)',border:'1px solid rgba(255,255,255,0.08)',
|
||||||
|
borderRadius:8,overflow:'auto',maxHeight:320,fontFamily:"'Courier New',monospace",fontSize:11,lineHeight:1.6}}>
|
||||||
|
{rows.map((r,i) => (
|
||||||
|
<div key={i} style={{
|
||||||
|
padding:'0 12px',whiteSpace:'pre-wrap',wordBreak:'break-all',
|
||||||
|
background: r.type==='add'?'rgba(78,205,196,0.12)':r.type==='del'?'rgba(255,107,157,0.12)':'transparent',
|
||||||
|
borderLeft:`2px solid ${r.type==='add'?'#4ecdc4':r.type==='del'?'#ff6b9d':'transparent'}`,
|
||||||
|
}}>
|
||||||
|
<span style={{color: r.type==='add'?'#4ecdc4':r.type==='del'?'rgba(255,107,157,0.7)':'rgba(255,255,255,0.2)',
|
||||||
|
marginRight:6,userSelect:'none',fontSize:10}}>
|
||||||
|
{r.type==='add'?'+':r.type==='del'?'−':' '}
|
||||||
|
</span>
|
||||||
|
<span style={{color: r.type==='same'?'#d0d0d0':'#fff'}}>{r.text}</span>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
function HistoryModal({ snippet, onClose, onRestore, toast }) {
|
function HistoryModal({ snippet, onClose, onRestore, toast }) {
|
||||||
const [history, setHistory] = useState([]);
|
const [history, setHistory] = useState([]);
|
||||||
const [selected, setSelected] = useState(null);
|
const [selected, setSelected] = useState(null);
|
||||||
|
const [showDiff, setShowDiff] = useState(true);
|
||||||
useEffect(()=>{
|
useEffect(()=>{
|
||||||
api(`/tools/snippets/${snippet.id}/history`).then(setHistory).catch(()=>{});
|
api(`/tools/snippets/${snippet.id}/history`).then(h=>{ setHistory(h); if(h.length) setSelected(h[0]); }).catch(()=>{});
|
||||||
},[]);
|
},[]);
|
||||||
const isMob = window.innerWidth < 768;
|
const isMob = window.innerWidth < 768;
|
||||||
|
const getOlderCode = (h) => {
|
||||||
|
const idx = history.indexOf(h);
|
||||||
|
return idx < history.length-1 ? history[idx+1].code : null;
|
||||||
|
};
|
||||||
return (
|
return (
|
||||||
<div style={{position:'fixed',inset:0,background:'rgba(0,0,0,0.85)',zIndex:7000,
|
<div style={{position:'fixed',inset:0,background:'rgba(0,0,0,0.85)',zIndex:7000,
|
||||||
display:'flex',alignItems:isMob?'flex-end':'center',justifyContent:'center',padding:isMob?0:24}}
|
display:'flex',alignItems:isMob?'flex-end':'center',justifyContent:'center',padding:isMob?0:24}}
|
||||||
onClick={e=>e.target===e.currentTarget&&onClose()}>
|
onClick={e=>e.target===e.currentTarget&&onClose()}>
|
||||||
<div style={{background:'#1a1a1e',borderRadius:isMob?'16px 16px 0 0':14,
|
<div style={{background:'#1a1a1e',borderRadius:isMob?'16px 16px 0 0':14,
|
||||||
width:'100%',maxWidth:640,border:'1px solid rgba(255,255,255,0.12)',
|
width:'100%',maxWidth:680,border:'1px solid rgba(255,255,255,0.12)',
|
||||||
display:'flex',flexDirection:'column',maxHeight:isMob?'88vh':'80vh',overflow:'hidden'}}>
|
display:'flex',flexDirection:'column',maxHeight:isMob?'88vh':'82vh',overflow:'hidden'}}>
|
||||||
<div style={{padding:'16px 20px',borderBottom:'1px solid rgba(255,255,255,0.08)',
|
<div style={{padding:'14px 20px',borderBottom:'1px solid rgba(255,255,255,0.08)',
|
||||||
display:'flex',justifyContent:'space-between',alignItems:'center',flexShrink:0}}>
|
display:'flex',justifyContent:'space-between',alignItems:'center',flexShrink:0,gap:10}}>
|
||||||
<div style={{color:'#fff',fontFamily:"'Space Mono',monospace",fontSize:14,fontWeight:700}}>
|
<div style={{color:'#fff',fontFamily:"'Space Mono',monospace",fontSize:13,fontWeight:700}}>📜 Versionshistorie</div>
|
||||||
📜 Versionshistorie
|
<div style={{display:'flex',gap:6,alignItems:'center'}}>
|
||||||
|
<button onClick={()=>setShowDiff(v=>!v)} style={{
|
||||||
|
background:showDiff?'rgba(78,205,196,0.12)':'rgba(255,255,255,0.05)',
|
||||||
|
border:`1px solid ${showDiff?'rgba(78,205,196,0.3)':'rgba(255,255,255,0.1)'}`,
|
||||||
|
borderRadius:6,color:showDiff?'#4ecdc4':'rgba(255,255,255,0.4)',
|
||||||
|
cursor:'pointer',fontSize:9,fontFamily:'monospace',padding:'3px 8px'}}>
|
||||||
|
{showDiff?'± Diff':'Code'}
|
||||||
|
</button>
|
||||||
|
<button onClick={onClose} style={{background:'transparent',border:'none',color:'rgba(255,255,255,0.4)',cursor:'pointer',fontSize:18}}>✕</button>
|
||||||
</div>
|
</div>
|
||||||
<button onClick={onClose} style={{background:'transparent',border:'none',color:'rgba(255,255,255,0.4)',cursor:'pointer',fontSize:18}}>✕</button>
|
|
||||||
</div>
|
</div>
|
||||||
{history.length===0 ? (
|
{history.length===0 ? (
|
||||||
<div style={{padding:32,textAlign:'center',color:'rgba(255,255,255,0.3)',fontFamily:'monospace',fontSize:11}}>
|
<div style={{padding:32,textAlign:'center',color:'rgba(255,255,255,0.3)',fontFamily:'monospace',fontSize:11}}>Keine älteren Versionen vorhanden.</div>
|
||||||
Keine älteren Versionen vorhanden.
|
|
||||||
</div>
|
|
||||||
) : (
|
) : (
|
||||||
<div style={{display:'flex',flex:1,overflow:'hidden'}}>
|
<div style={{display:'flex',flex:1,overflow:'hidden'}}>
|
||||||
{/* Liste */}
|
<div style={{width:150,borderRight:'1px solid rgba(255,255,255,0.07)',overflowY:'auto',flexShrink:0}}>
|
||||||
<div style={{width:160,borderRight:'1px solid rgba(255,255,255,0.07)',overflowY:'auto',flexShrink:0}}>
|
|
||||||
{history.map((h,i)=>(
|
{history.map((h,i)=>(
|
||||||
<button key={h.id} onClick={()=>setSelected(h)} style={{
|
<button key={h.id} onClick={()=>setSelected(h)} style={{
|
||||||
width:'100%',padding:'10px 12px',background: selected?.id===h.id?'rgba(78,205,196,0.1)':'transparent',
|
width:'100%',padding:'10px 12px',
|
||||||
|
background:selected?.id===h.id?'rgba(78,205,196,0.1)':'transparent',
|
||||||
borderLeft:`2px solid ${selected?.id===h.id?'#4ecdc4':'transparent'}`,
|
borderLeft:`2px solid ${selected?.id===h.id?'#4ecdc4':'transparent'}`,
|
||||||
border:'none',borderRight:'none',borderTop:'none',borderBottom:'1px solid rgba(255,255,255,0.05)',
|
border:'none',borderRight:'none',borderTop:'none',borderBottom:'1px solid rgba(255,255,255,0.05)',
|
||||||
cursor:'pointer',textAlign:'left',
|
cursor:'pointer',textAlign:'left'}}>
|
||||||
}}>
|
<div style={{color:'rgba(255,255,255,0.6)',fontFamily:'monospace',fontSize:9}}>v{history.length-i}</div>
|
||||||
<div style={{color:'rgba(255,255,255,0.6)',fontFamily:'monospace',fontSize:9}}>
|
<div style={{color:'rgba(255,255,255,0.3)',fontFamily:'monospace',fontSize:8,marginTop:2}}>{fmtDt(h.saved_at)}</div>
|
||||||
Version {history.length-i}
|
|
||||||
</div>
|
|
||||||
<div style={{color:'rgba(255,255,255,0.35)',fontFamily:'monospace',fontSize:8,marginTop:2}}>
|
|
||||||
{fmtDt(h.saved_at)}
|
|
||||||
</div>
|
|
||||||
</button>
|
</button>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
{/* Preview */}
|
|
||||||
<div style={{flex:1,overflow:'auto',padding:14,display:'flex',flexDirection:'column',gap:10}}>
|
<div style={{flex:1,overflow:'auto',padding:14,display:'flex',flexDirection:'column',gap:10}}>
|
||||||
{selected ? (
|
{selected && (
|
||||||
<>
|
<>
|
||||||
<div style={{display:'flex',alignItems:'center',justifyContent:'space-between'}}>
|
<div style={{display:'flex',alignItems:'center',justifyContent:'space-between',flexWrap:'wrap',gap:6}}>
|
||||||
<span style={{color:'rgba(255,255,255,0.4)',fontFamily:'monospace',fontSize:10}}>
|
<span style={{color:'rgba(255,255,255,0.35)',fontFamily:'monospace',fontSize:10}}>
|
||||||
{getLangLabel(selected.language)} · {fmtDt(selected.saved_at)}
|
{getLangLabel(selected.language)} · {fmtDt(selected.saved_at)}
|
||||||
|
{showDiff && getOlderCode(selected)===null && <span style={{color:'rgba(255,255,255,0.2)',marginLeft:6}}>(älteste Version)</span>}
|
||||||
</span>
|
</span>
|
||||||
{!snippet.is_shared && (
|
{!snippet.is_shared && (
|
||||||
<button onClick={()=>onRestore(selected)} style={{...S.btn('#ffe66d',true),fontSize:10}}>
|
<button onClick={()=>onRestore(selected)} style={{
|
||||||
|
background:'rgba(255,230,109,0.1)',border:'1px solid rgba(255,230,109,0.25)',
|
||||||
|
borderRadius:6,color:'#ffe66d',cursor:'pointer',fontSize:10,padding:'4px 10px'}}>
|
||||||
↩ Wiederherstellen
|
↩ Wiederherstellen
|
||||||
</button>
|
</button>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<pre style={{margin:0,background:'rgba(0,0,0,0.4)',border:'1px solid rgba(255,255,255,0.08)',
|
{showDiff
|
||||||
borderRadius:8,padding:12,color:'#d0d0d0',fontFamily:"'Courier New',monospace",
|
? <DiffView oldCode={getOlderCode(selected)} newCode={selected.code}/>
|
||||||
fontSize:11,lineHeight:1.6,overflowX:'auto',whiteSpace:'pre-wrap',wordBreak:'break-all'}}>
|
: <pre style={{margin:0,padding:'12px 14px',color:'#d0d0d0',fontFamily:"'Courier New',monospace",
|
||||||
{selected.code}
|
fontSize:11,lineHeight:1.6,background:'rgba(0,0,0,0.35)',border:'1px solid rgba(255,255,255,0.08)',
|
||||||
</pre>
|
borderRadius:8,overflowX:'auto',whiteSpace:'pre-wrap',wordBreak:'break-all',maxHeight:320,overflowY:'auto'}}>
|
||||||
|
{selected.code}
|
||||||
|
</pre>
|
||||||
|
}
|
||||||
</>
|
</>
|
||||||
) : (
|
|
||||||
<div style={{color:'rgba(255,255,255,0.25)',fontFamily:'monospace',fontSize:11,margin:'auto'}}>
|
|
||||||
Version auswählen
|
|
||||||
</div>
|
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -203,6 +250,12 @@ function SnippetCard({ snippet, onEdit, onDelete, onShare, onHistory, toast }) {
|
|||||||
borderRadius:4,padding:'1px 5px',flexShrink:0}}>von {snippet.owner}</span>
|
borderRadius:4,padding:'1px 5px',flexShrink:0}}>von {snippet.owner}</span>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
{snippet.description && (
|
||||||
|
<div style={{color:'rgba(255,255,255,0.38)',fontFamily:'monospace',fontSize:10,
|
||||||
|
marginTop:2,overflow:'hidden',textOverflow:'ellipsis',whiteSpace:'nowrap'}}>
|
||||||
|
{snippet.description}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
<div style={{display:'flex',alignItems:'center',gap:6,marginTop:2,flexWrap:'wrap'}}>
|
<div style={{display:'flex',alignItems:'center',gap:6,marginTop:2,flexWrap:'wrap'}}>
|
||||||
<span style={{fontSize:9,fontFamily:'monospace',color:langColor,opacity:0.8}}>
|
<span style={{fontSize:9,fontFamily:'monospace',color:langColor,opacity:0.8}}>
|
||||||
{getLangLabel(snippet.language)}
|
{getLangLabel(snippet.language)}
|
||||||
@@ -404,25 +457,30 @@ function SnippetForm({ initial, onSave, onCancel, toast, existingTags=[] }) {
|
|||||||
export default function CodeSchnipsel({ toast, mobile }) {
|
export default function CodeSchnipsel({ toast, mobile }) {
|
||||||
const [own, setOwn] = useState([]);
|
const [own, setOwn] = useState([]);
|
||||||
const [shared, setShared] = useState([]);
|
const [shared, setShared] = useState([]);
|
||||||
|
const [sharedByMe,setSharedByMe]= useState([]);
|
||||||
const [tab, setTab] = useState('own');
|
const [tab, setTab] = useState('own');
|
||||||
const [search, setSearch] = useState('');
|
const [search, setSearch] = useState('');
|
||||||
const [tagFilter, setTagFilter] = useState('');
|
const [tagFilters,setTagFilters]= useState([]); // multi-select array
|
||||||
const [showForm, setShowForm] = useState(false);
|
const [showForm, setShowForm] = useState(false);
|
||||||
const [editItem, setEditItem] = useState(null);
|
const [editItem, setEditItem] = useState(null);
|
||||||
const [shareItem, setShareItem] = useState(null);
|
const [shareItem, setShareItem] = useState(null);
|
||||||
const [histItem, setHistItem] = useState(null);
|
const [histItem, setHistItem] = useState(null);
|
||||||
|
|
||||||
const load = useCallback(()=>{
|
const load = useCallback(()=>{
|
||||||
api('/tools/snippets').then(d=>{ setOwn(d.own||[]); setShared(d.shared||[]); }).catch(()=>{});
|
api('/tools/snippets').then(d=>{ setOwn(d.own||[]); setShared(d.shared||[]); setSharedByMe(d.sharedByMe||[]); }).catch(()=>{});
|
||||||
},[]);
|
},[]);
|
||||||
|
|
||||||
useEffect(()=>{ load(); },[load]);
|
useEffect(()=>{ load(); },[load]);
|
||||||
|
|
||||||
const allTags = [...new Set([...own,...shared].flatMap(s=>s.tags||[]))].sort();
|
// Only tags that are currently in use
|
||||||
|
const allItems = [...own, ...shared];
|
||||||
|
const allTags = [...new Set(allItems.flatMap(s=>s.tags||[]))].sort();
|
||||||
|
|
||||||
|
const toggleTag = t => setTagFilters(p => p.includes(t) ? p.filter(x=>x!==t) : [...p, t]);
|
||||||
|
|
||||||
const filterItems = items => {
|
const filterItems = items => {
|
||||||
let res = items;
|
let res = items;
|
||||||
if (tagFilter) res = res.filter(s=>s.tags?.includes(tagFilter));
|
if (tagFilters.length) res = res.filter(s => tagFilters.every(t=>s.tags?.includes(t)));
|
||||||
if (search.trim()) {
|
if (search.trim()) {
|
||||||
const q = search.toLowerCase();
|
const q = search.toLowerCase();
|
||||||
res = res.filter(s =>
|
res = res.filter(s =>
|
||||||
@@ -436,7 +494,8 @@ export default function CodeSchnipsel({ toast, mobile }) {
|
|||||||
return res;
|
return res;
|
||||||
};
|
};
|
||||||
|
|
||||||
const items = filterItems(tab==='own' ? own : shared);
|
const curList = tab==='own' ? own : tab==='shared' ? shared : sharedByMe;
|
||||||
|
const items = filterItems(curList);
|
||||||
|
|
||||||
const handleSave = async form => {
|
const handleSave = async form => {
|
||||||
if (editItem?.id) {
|
if (editItem?.id) {
|
||||||
@@ -496,8 +555,8 @@ export default function CodeSchnipsel({ toast, mobile }) {
|
|||||||
|
|
||||||
{/* Tabs */}
|
{/* Tabs */}
|
||||||
<div style={{display:'flex',gap:6,marginBottom:12,flexWrap:'wrap'}}>
|
<div style={{display:'flex',gap:6,marginBottom:12,flexWrap:'wrap'}}>
|
||||||
{[['own','Meine',own.length],['shared','Geteilt mit mir',shared.length]].map(([k,l,cnt])=>(
|
{[['own','Meine',own.length],['shared','Geteilt mit mir',shared.length],['sharedByMe','Geteilt von mir',sharedByMe.length]].map(([k,l,cnt])=>(
|
||||||
<button key={k} onClick={()=>{setTab(k);setSearch('');setTagFilter('');}} style={{
|
<button key={k} onClick={()=>{setTab(k);setSearch('');setTagFilters([]);}} style={{
|
||||||
padding:'6px 14px',borderRadius:20,fontFamily:'monospace',fontSize:11,cursor:'pointer',
|
padding:'6px 14px',borderRadius:20,fontFamily:'monospace',fontSize:11,cursor:'pointer',
|
||||||
background:tab===k?'#4ecdc4':'rgba(255,255,255,0.05)',
|
background:tab===k?'#4ecdc4':'rgba(255,255,255,0.05)',
|
||||||
color:tab===k?'#0d0d0f':'rgba(255,255,255,0.55)',
|
color:tab===k?'#0d0d0f':'rgba(255,255,255,0.55)',
|
||||||
@@ -520,23 +579,32 @@ export default function CodeSchnipsel({ toast, mobile }) {
|
|||||||
color:'rgba(255,255,255,0.4)',cursor:'pointer',fontSize:16}}>✕</button>}
|
color:'rgba(255,255,255,0.4)',cursor:'pointer',fontSize:16}}>✕</button>}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Tag-Filter */}
|
{/* Tag-Filter (Mehrfachauswahl) */}
|
||||||
{allTags.length>0 && (
|
{allTags.length>0 && (
|
||||||
<div style={{display:'flex',gap:5,flexWrap:'wrap',marginBottom:14}}>
|
<div style={{display:'flex',gap:5,flexWrap:'wrap',marginBottom:14,alignItems:'center'}}>
|
||||||
<button onClick={()=>setTagFilter('')} style={{
|
<button onClick={()=>setTagFilters([])} style={{
|
||||||
fontSize:9,fontFamily:'monospace',padding:'3px 9px',borderRadius:20,cursor:'pointer',
|
fontSize:9,fontFamily:'monospace',padding:'3px 9px',borderRadius:20,cursor:'pointer',
|
||||||
background:!tagFilter?'rgba(78,205,196,0.15)':'rgba(255,255,255,0.04)',
|
background:!tagFilters.length?'rgba(78,205,196,0.15)':'rgba(255,255,255,0.04)',
|
||||||
border:`1px solid ${!tagFilter?'rgba(78,205,196,0.3)':'rgba(255,255,255,0.08)'}`,
|
border:`1px solid ${!tagFilters.length?'rgba(78,205,196,0.3)':'rgba(255,255,255,0.08)'}`,
|
||||||
color:!tagFilter?'#4ecdc4':'rgba(255,255,255,0.4)',
|
color:!tagFilters.length?'#4ecdc4':'rgba(255,255,255,0.4)',
|
||||||
}}>Alle</button>
|
}}>Alle</button>
|
||||||
{allTags.map(t=>(
|
{allTags.map(t=>{
|
||||||
<button key={t} onClick={()=>setTagFilter(t===tagFilter?'':t)} style={{
|
const active = tagFilters.includes(t);
|
||||||
fontSize:9,fontFamily:'monospace',padding:'3px 9px',borderRadius:20,cursor:'pointer',
|
const c = LANG_COLORS[t] || '#4ecdc4';
|
||||||
background:tagFilter===t?(LANG_COLORS[t]?LANG_COLORS[t]+'20':'rgba(78,205,196,0.15)'):'rgba(255,255,255,0.04)',
|
return (
|
||||||
border:`1px solid ${tagFilter===t?(LANG_COLORS[t]||'#4ecdc4')+'40':'rgba(255,255,255,0.08)'}`,
|
<button key={t} onClick={()=>toggleTag(t)} style={{
|
||||||
color:tagFilter===t?(LANG_COLORS[t]||'#4ecdc4'):'rgba(255,255,255,0.45)',
|
fontSize:9,fontFamily:'monospace',padding:'3px 9px',borderRadius:20,cursor:'pointer',
|
||||||
}}>{t}</button>
|
background:active?`${c}20`:'rgba(255,255,255,0.04)',
|
||||||
))}
|
border:`1px solid ${active?`${c}50`:'rgba(255,255,255,0.08)'}`,
|
||||||
|
color:active?c:'rgba(255,255,255,0.45)',
|
||||||
|
}}>{active?'✓ ':''}{t}</button>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
{tagFilters.length>0 && (
|
||||||
|
<span style={{color:'rgba(255,255,255,0.25)',fontFamily:'monospace',fontSize:9,marginLeft:2}}>
|
||||||
|
({tagFilters.length} aktiv)
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
@@ -545,7 +613,7 @@ export default function CodeSchnipsel({ toast, mobile }) {
|
|||||||
<div style={{...S.card,textAlign:'center',padding:40}}>
|
<div style={{...S.card,textAlign:'center',padding:40}}>
|
||||||
<div style={{fontSize:28,marginBottom:10}}>{'</>'}</div>
|
<div style={{fontSize:28,marginBottom:10}}>{'</>'}</div>
|
||||||
<div style={{color:'rgba(255,255,255,0.35)',fontFamily:'monospace',fontSize:12}}>
|
<div style={{color:'rgba(255,255,255,0.35)',fontFamily:'monospace',fontSize:12}}>
|
||||||
{search||tagFilter ? 'Keine Treffer.' : tab==='own' ? 'Noch keine Schnipsel – füge deinen ersten hinzu.' : 'Noch nichts geteilt.'}
|
{search||tagFilters.length ? 'Keine Treffer.' : tab==='own' ? 'Noch keine Schnipsel – füge deinen ersten hinzu.' : 'Noch nichts geteilt.'}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
) : items.map(s=>(
|
) : items.map(s=>(
|
||||||
|
|||||||
Reference in New Issue
Block a user