diff options
| author | Adam Soltys <[email protected]> | 2026-10-02 10:20:57 -0700 |
|---|---|---|
| committer | Adam Soltys <[email protected]> | 2026-10-02 10:20:57 -0700 |
| commit | af19e72e54b1b3bac210d8c9d74317f662160c18 (patch) | |
| tree | 4899e195ab1f9d2850d51b30e6b5f89ba88a6412 /src | |
| parent | ef6729ceaf49d2d85bc8920c2c7756086ee7450d (diff) | |
| download | coinosv3-af19e72e54b1b3bac210d8c9d74317f662160c18.tar.gz coinosv3-af19e72e54b1b3bac210d8c9d74317f662160c18.zip | |
Feed form: relays and an every-post firehose; its Back works; a stronger new-post tint
- The new/edit feed form gets a Relays field (read this feed from these
relays only) and "Every post on these relays", which saves a firehose
feed (optionally curated) named after its relay and hides the people,
packs and topics it doesn't need. It used to take a hand-typed
/feed/all?r= link.
- The form's Back did nothing visible: opening it made no history entry,
so Back went to the page behind the feed and left the form up. The
editor (and the gear page's Spending/Savings view) are now part of the
navigation state.
- New-post tint 9% -> 16% green in light mode; dark mode unchanged.
- tools/feed-editor-relays-test.js.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Dmcrt9KyNDKVWFKnb8BREo
Diffstat (limited to 'src')
| -rw-r--r-- | src/app.js | 9 | ||||
| -rw-r--r-- | src/features/messages.js | 40 | ||||
| -rw-r--r-- | src/i18n.js | 4 | ||||
| -rw-r--r-- | src/locales/ar.json | 6 | ||||
| -rw-r--r-- | src/locales/bn.json | 6 | ||||
| -rw-r--r-- | src/locales/de.json | 6 | ||||
| -rw-r--r-- | src/locales/es.json | 6 | ||||
| -rw-r--r-- | src/locales/fr.json | 6 | ||||
| -rw-r--r-- | src/locales/hi.json | 6 | ||||
| -rw-r--r-- | src/locales/id.json | 6 | ||||
| -rw-r--r-- | src/locales/ja.json | 6 | ||||
| -rw-r--r-- | src/locales/ko.json | 6 | ||||
| -rw-r--r-- | src/locales/mr.json | 6 | ||||
| -rw-r--r-- | src/locales/pt.json | 6 | ||||
| -rw-r--r-- | src/locales/ru.json | 6 | ||||
| -rw-r--r-- | src/locales/sw.json | 6 | ||||
| -rw-r--r-- | src/locales/ta.json | 6 | ||||
| -rw-r--r-- | src/locales/te.json | 6 | ||||
| -rw-r--r-- | src/locales/tr.json | 6 | ||||
| -rw-r--r-- | src/locales/ur.json | 6 | ||||
| -rw-r--r-- | src/locales/vi.json | 6 | ||||
| -rw-r--r-- | src/locales/zh.json | 6 | ||||
| -rw-r--r-- | src/style.css | 5 |
23 files changed, 139 insertions, 33 deletions
@@ -795,7 +795,7 @@ function renderInner() { // ui field that decides which page is on screen. const navKey = [ui.screen, ui.tab === 'settings', ui.chatOpen, ui.msgView, ui.msgPeer, ui.msgCommunity, ui.profilePk, ui.settingsPage, ui.addrScan, ui.arkExitPage, ui.txDetail, ui.giftMode, ui.claimStep, ui.nameEditOpen, - ui.noteThread && ui.noteThread.focusId, !!ui.userSearch, !!ui.zapSetup, !!ui.hatShop].join('|'); + ui.noteThread && ui.noteThread.focusId, !!ui.userSearch, !!ui.zapSetup, !!ui.hatShop, !!ui.feedEdit, ui.settingsView].join('|'); // A deep-linked profile landing is ONE page settling, not a chain of // navigations: boot screens shuffle beneath the shell (unlock → restored // wallet), then the resolved profile replaces the shell in place. The key @@ -868,7 +868,7 @@ wallet.subscribe(scheduleRender); // lightbox: a full-screen photo is a place too — the phone's Back must close // it, not pop the screen under it (which once walked a viewer straight back // to the start page, so the photo's × then looked like a logout). -const NAV_FIELDS = ['screen', 'tab', 'txDetail', 'arkMoveDetail', 'arkReconDetail', 'arkExitDetail', 'giftDetail', 'bump', 'giftMode', 'claimStep', 'chatOpen', 'msgView', 'feedId', 'pubProf', 'arkCoinsPage', 'arkExitPage', 'msgCommunity', 'msgPeer', 'profilePk', 'profEdit', 'profEditFilled', 'profOverThread', 'settingsPage', 'nameEditOpen', 'noteThread', 'userSearch', 'zapSetup', 'hatShop', 'lightbox']; +const NAV_FIELDS = ['screen', 'tab', 'txDetail', 'arkMoveDetail', 'arkReconDetail', 'arkExitDetail', 'giftDetail', 'bump', 'giftMode', 'claimStep', 'chatOpen', 'msgView', 'feedId', 'pubProf', 'arkCoinsPage', 'arkExitPage', 'msgCommunity', 'msgPeer', 'profilePk', 'profEdit', 'profEditFilled', 'profOverThread', 'settingsPage', 'nameEditOpen', 'noteThread', 'userSearch', 'zapSetup', 'hatShop', 'lightbox', 'feedEdit', 'settingsView']; function navSnapshot() { const s = {}; for (const f of NAV_FIELDS) s[f] = ui[f] ?? null; @@ -877,6 +877,7 @@ function navSnapshot() { // keystroke must never mint a history entry. if (ui.noteThread) s.noteThread = { rootId: ui.noteThread.rootId, focusId: ui.noteThread.focusId, seed: ui.noteThread.seed }; if (ui.userSearch) s.userSearch = { q: '', rows: null }; + if (ui.feedEdit) s.feedEdit = { ...ui.feedEdit, q: '', rows: null, pq: '', packRows: null, pt: null }; if (ui.zapSetup) s.zapSetup = { pk: ui.zapSetup.pk, npub: ui.zapSetup.npub, eventId: ui.zapSetup.eventId, amount: '21' }; // Keep the editable fields in this history entry so a refresh restores the // draft. Copy them: later keystrokes must not mutate earlier snapshots. @@ -970,7 +971,7 @@ function restoreNavFromHistory(renderNow = true) { // the vault prompt); with an account open now, those screens are stale. // Restoring one painted the start page over a perfectly good wallet. if (['unlock', 'vault'].includes(nav.screen) && activeAccount()) nav.screen = 'wallet'; - for (const f of NAV_FIELDS) if (f in nav) ui[f] = f === 'profEdit' && nav[f] ? structuredClone(nav[f]) : nav[f]; + for (const f of NAV_FIELDS) if (f in nav) ui[f] = (f === 'profEdit' || f === 'feedEdit') && nav[f] ? structuredClone(nav[f]) : nav[f]; ui.lightbox = null; nav.lightbox = null; // an object URL doesn't survive a reload navStack = [nav]; navIndex = 0; @@ -997,7 +998,7 @@ window.addEventListener('popstate', (e) => { } restoringHistory = true; try { - for (const f of NAV_FIELDS) ui[f] = f === 'profEdit' && snap[f] ? structuredClone(snap[f]) : f in snap ? snap[f] : null; + for (const f of NAV_FIELDS) ui[f] = (f === 'profEdit' || f === 'feedEdit') && snap[f] ? structuredClone(snap[f]) : f in snap ? snap[f] : null; if (st && typeof st.i === 'number') navIndex = st.i; else { const i = navStack.findIndex((s) => navSig(s) === navSig(snap)); if (i >= 0) navIndex = i; } render(); diff --git a/src/features/messages.js b/src/features/messages.js index 176c779..68eefda 100644 --- a/src/features/messages.js +++ b/src/features/messages.js @@ -8894,8 +8894,10 @@ export function messagesFeature(ctx) { const isNew = !def || adhocFeeds.has(def.id); ui.feedEdit = def ? { id: def.id, name: def.name || '', follows: !!def.follows, authors: [...(def.authors || [])], priv: [...(def.priv || [])], packs: [...(def.packs || [])], - topics: feedTopics(def).map((x) => '#' + x).join(' '), q: '', rows: null, pq: '', packRows: null, isNew, d: def.d || null, publish: isNew || !!def.d } - : { id: null, name: '', follows: false, authors: [], priv: [], packs: [], topics: '', q: '', rows: null, pq: '', packRows: null, isNew: true, d: null, publish: true }; + topics: feedTopics(def).map((x) => '#' + x).join(' '), q: '', rows: null, pq: '', packRows: null, isNew, d: def.d || null, publish: isNew || !!def.d, + relays: (def.relays || []).map((r) => r.replace(/^wss:\/\//, '')).join(' '), all: !!def.all && !def.builtin, curated: !!def.curated } + : { id: null, name: '', follows: false, authors: [], priv: [], packs: [], topics: '', q: '', rows: null, pq: '', packRows: null, isNew: true, d: null, publish: true, + relays: '', all: false, curated: false }; render(); } const feedPeopleSearcher = makeSearcher((q, rows) => { @@ -8907,12 +8909,20 @@ export function messagesFeature(ctx) { const e = ui.feedEdit; if (!e) return; const topics = [...new Set(e.topics.split(/[\s,]+/).map(normTopic).filter(Boolean))].slice(0, 20); - if (!e.follows && !e.authors.length && !e.packs.length && !topics.length) { toast(t('feedNoQuery')); return; } - const name = e.name.trim().slice(0, 40) || (topics.length ? '#' + topics[0] : t('feedNewName')); + const words = String(e.relays || '').split(/[\s,]+/).filter(Boolean); + const relays = [...new Set(words.map(normRelay).filter(Boolean))].slice(0, 12); + if (relays.length < words.length) { toast(t('feedRelayBad')); return; } + // every post on its relays: a firehose needs the relays, nothing else + if (e.all && !relays.length) { toast(t('feedAllNeedsRelays')); return; } + if (!e.all && !e.follows && !e.authors.length && !e.packs.length && !topics.length) { toast(t('feedNoQuery')); return; } + const name = e.name.trim().slice(0, 40) || (e.all ? relays[0].replace(/^wss:\/\//, '') : topics.length ? '#' + topics[0] : t('feedNewName')); const s = st(); const keep = e.id && !adhocFeeds.has(e.id) && s.feeds.some((f) => f.id === e.id); const id = keep ? e.id : 'f' + Date.now().toString(36) + Math.random().toString(36).slice(2, 6); - const def = { id, name, follows: e.follows, authors: e.authors.slice(0, FEED_AUTHORS_MAX), packs: e.packs.slice(0, 20), topics, at: Date.now() }; + const def = e.all + ? { id, name, follows: false, authors: [], packs: [], topics: [], all: true, curated: !!e.curated, relays, at: Date.now() } + : { id, name, follows: e.follows, authors: e.authors.slice(0, FEED_AUTHORS_MAX), packs: e.packs.slice(0, 20), topics, relays, all: false, curated: false, at: Date.now() }; + if (!relays.length) delete def.relays; const prev = keep ? s.feeds.find((f) => f.id === id) : null; // d, listAt, listContent and priv ride along from the previous copy if (keep) s.feeds = s.feeds.map((f) => (f.id === id ? { ...f, ...def } : f)); else s.feeds.push(def); @@ -9008,7 +9018,19 @@ export function messagesFeature(ctx) { h('label', { class: 'col', style: 'gap:4px' }, h('span', { class: 'small muted' }, t('feedName')), h('input', { type: 'text', value: e.name, placeholder: t('feedNameHint'), maxlength: '40', onInput: (ev) => { e.name = ev.target.value; } })), - h('div', { class: 'col', style: 'gap:8px' }, + // where the feed reads, and whether it takes everything there + h('div', { class: 'col', style: 'gap:6px' }, + h('span', { class: 'small muted' }, t('feedRelays')), + h('input', { type: 'text', class: 'feed-relays-input', value: e.relays || '', placeholder: 'nos.lol relay.damus.io', + autocapitalize: 'none', autocomplete: 'off', spellcheck: 'false', onInput: (ev) => { e.relays = ev.target.value; } }), + h('div', { class: 'small faint' }, t('feedRelaysFormHelp')), + h('label', { class: 'row gap6', style: 'align-items:center;cursor:pointer' }, + h('input', { type: 'checkbox', class: 'feed-all-toggle', checked: !!e.all, style: 'width:18px;height:18px;accent-color:var(--accent);margin:0', onChange: (ev) => { e.all = ev.target.checked; render(); } }), + h('span', {}, t('feedAllToggle'))), + e.all ? h('label', { class: 'row gap6', style: 'align-items:center;cursor:pointer;margin-left:26px' }, + h('input', { type: 'checkbox', checked: !!e.curated, style: 'width:18px;height:18px;accent-color:var(--accent);margin:0', onChange: (ev) => { e.curated = ev.target.checked; } }), + h('span', { class: 'small' }, t('feedAllCurated'))) : null), + e.all ? null : h('div', { class: 'col', style: 'gap:8px' }, h('span', { class: 'small muted' }, t('feedPeople')), h('label', { class: 'row gap6', style: 'align-items:center;cursor:pointer' }, h('input', { type: 'checkbox', checked: e.follows, style: 'width:18px;height:18px;accent-color:var(--accent);margin:0', onChange: (ev) => { e.follows = ev.target.checked; render(); } }), @@ -9030,7 +9052,7 @@ export function messagesFeature(ctx) { e.authors.push(r.pk); e.q = ''; e.rows = null; render(); }, (pk, node) => hook('wrapAvatar', pk, node))) : null), - h('div', { class: 'col', style: 'gap:8px' }, + e.all ? null : h('div', { class: 'col', style: 'gap:8px' }, h('span', { class: 'small muted' }, t('feedPacks')), ...e.packs.map((p) => packRow(p, null, h('button', { class: 'btn-sm', type: 'button', 'aria-label': t('remove'), onClick: () => { e.packs = e.packs.filter((x) => packKey(x) !== packKey(p)); render(); } }, '\u00d7'))), @@ -9045,12 +9067,12 @@ export function messagesFeature(ctx) { e.pq = ''; e.packRows = null; render(); })), e.packRows && !e.packRows.length ? h('div', { class: 'small faint' }, t('searchNoResults')) : null), - h('label', { class: 'col', style: 'gap:4px' }, + e.all ? null : h('label', { class: 'col', style: 'gap:4px' }, h('span', { class: 'small muted' }, t('feedTopics')), h('input', { type: 'text', value: e.topics, placeholder: t('feedTopicsHint'), autocapitalize: 'none', autocomplete: 'off', onInput: (ev) => { e.topics = ev.target.value; } }), h('div', { class: 'small faint' }, t('feedTopicsHelp'))), // a feed of people is a nostr list (NIP-51 follow set) unless told not to be - e.authors.length || (e.priv || []).length || e.d + !e.all && (e.authors.length || (e.priv || []).length || e.d) ? h('div', { class: 'col', style: 'gap:4px' }, h('label', { class: 'row gap6', style: 'align-items:center;cursor:pointer' }, h('input', { type: 'checkbox', class: 'feed-list-toggle', checked: !!e.publish, style: 'width:18px;height:18px;accent-color:var(--accent);margin:0', onChange: (ev) => { e.publish = ev.target.checked; } }), diff --git a/src/i18n.js b/src/i18n.js index ac538ed..906ff51 100644 --- a/src/i18n.js +++ b/src/i18n.js @@ -282,6 +282,10 @@ const STR = { askNotNow: 'Not now', feedLangLabel: 'Language', feedRelays: 'Relays', + feedRelaysFormHelp: 'Read this feed from these relays only. Leave empty for the usual ones.', + feedAllToggle: 'Every post on these relays (a firehose)', + feedAllCurated: 'Only popular posts: hide bots and posts nobody reacted to', + feedAllNeedsRelays: 'Name the relays to read everything from.', feedRelaysHint: 'Posts are read from these relays. What the feed asks for stays the same.', feedRelayUsual: 'usual', feedRelaysOutbox: 'Right now each person is read from the relays they publish to.', diff --git a/src/locales/ar.json b/src/locales/ar.json index 75971cf..dd81a34 100644 --- a/src/locales/ar.json +++ b/src/locales/ar.json @@ -881,5 +881,9 @@ "followHistRestored": "تمت استعادة {n} متابَعًا.", "securityTitle": "الأمان", "arkCoinsNone": "لا توجد عملات في الإنفاق بعد.", - "profKeyLink": "المفتاح العام" + "profKeyLink": "المفتاح العام", + "feedRelaysFormHelp": "اقرأ هذه الخلاصة من هذه المرحّلات فقط. اتركها فارغة لاستخدام المعتاد.", + "feedAllToggle": "كل منشور على هذه المرحّلات (تدفق كامل)", + "feedAllCurated": "المنشورات الرائجة فقط: إخفاء الروبوتات والمنشورات بلا تفاعل", + "feedAllNeedsRelays": "اذكر المرحّلات التي تقرأ منها كل شيء." } diff --git a/src/locales/bn.json b/src/locales/bn.json index 98bb71c..d93622d 100644 --- a/src/locales/bn.json +++ b/src/locales/bn.json @@ -881,5 +881,9 @@ "followHistRestored": "{n} জনকে আবার ফলো করা হয়েছে।", "securityTitle": "নিরাপত্তা", "arkCoinsNone": "স্পেন্ডিং-এ এখনও কোনো কয়েন নেই।", - "profKeyLink": "পাবলিক কী" + "profKeyLink": "পাবলিক কী", + "feedRelaysFormHelp": "শুধু এই রিলেগুলো থেকে এই ফিড পড়ুন। সাধারণগুলোর জন্য খালি রাখুন।", + "feedAllToggle": "এই রিলেগুলোর প্রতিটি পোস্ট (ফায়ারহোস)", + "feedAllCurated": "শুধু জনপ্রিয় পোস্ট: বট ও প্রতিক্রিয়াহীন পোস্ট লুকান", + "feedAllNeedsRelays": "কোন রিলে থেকে সব পড়বেন তা লিখুন।" } diff --git a/src/locales/de.json b/src/locales/de.json index ce61392..33e1f56 100644 --- a/src/locales/de.json +++ b/src/locales/de.json @@ -881,5 +881,9 @@ "followHistRestored": "{n} Follows wiederhergestellt.", "securityTitle": "Sicherheit", "arkCoinsNone": "Noch keine Coins in Ausgaben.", - "profKeyLink": "Öffentlicher Schlüssel" + "profKeyLink": "Öffentlicher Schlüssel", + "feedRelaysFormHelp": "Diesen Feed nur von diesen Relays lesen. Leer lassen für die üblichen.", + "feedAllToggle": "Jeder Beitrag auf diesen Relays (Firehose)", + "feedAllCurated": "Nur beliebte Beiträge: Bots und Beiträge ohne Reaktionen ausblenden", + "feedAllNeedsRelays": "Nenne die Relays, von denen alles gelesen werden soll." } diff --git a/src/locales/es.json b/src/locales/es.json index c66feac..291da3d 100644 --- a/src/locales/es.json +++ b/src/locales/es.json @@ -881,5 +881,9 @@ "followHistRestored": "Se restauraron {n} seguidos.", "securityTitle": "Seguridad", "arkCoinsNone": "Aún no hay monedas en Gastos.", - "profKeyLink": "Clave pública" + "profKeyLink": "Clave pública", + "feedRelaysFormHelp": "Lee este feed solo de estos relays. Déjalo vacío para usar los habituales.", + "feedAllToggle": "Todas las publicaciones de estos relays (firehose)", + "feedAllCurated": "Solo publicaciones populares: oculta bots y publicaciones sin reacciones", + "feedAllNeedsRelays": "Indica los relays de los que leerlo todo." } diff --git a/src/locales/fr.json b/src/locales/fr.json index 970004e..31d07ba 100644 --- a/src/locales/fr.json +++ b/src/locales/fr.json @@ -881,5 +881,9 @@ "followHistRestored": "{n} abonnements restaurés.", "securityTitle": "Sécurité", "arkCoinsNone": "Aucune pièce dans Dépenses pour l’instant.", - "profKeyLink": "Clé publique" + "profKeyLink": "Clé publique", + "feedRelaysFormHelp": "Lire ce fil uniquement depuis ces relais. Laisser vide pour les relais habituels.", + "feedAllToggle": "Toutes les publications de ces relais (firehose)", + "feedAllCurated": "Seulement les publications populaires : masquer les bots et les publications sans réaction", + "feedAllNeedsRelays": "Indiquez les relais dont tout lire." } diff --git a/src/locales/hi.json b/src/locales/hi.json index 686bd6b..0d410e4 100644 --- a/src/locales/hi.json +++ b/src/locales/hi.json @@ -881,5 +881,9 @@ "followHistRestored": "{n} फ़ॉलो बहाल किए गए।", "securityTitle": "सुरक्षा", "arkCoinsNone": "स्पेंडिंग में अभी कोई कॉइन नहीं।", - "profKeyLink": "पब्लिक की" + "profKeyLink": "पब्लिक की", + "feedRelaysFormHelp": "यह फ़ीड सिर्फ़ इन रिले से पढ़ें। सामान्य रिले के लिए खाली छोड़ें।", + "feedAllToggle": "इन रिले की हर पोस्ट (फ़ायरहोज़)", + "feedAllCurated": "सिर्फ़ लोकप्रिय पोस्ट: बॉट और बिना प्रतिक्रिया वाली पोस्ट छिपाएँ", + "feedAllNeedsRelays": "वे रिले बताएँ जिनसे सब कुछ पढ़ना है।" } diff --git a/src/locales/id.json b/src/locales/id.json index a5b4f32..82c8e30 100644 --- a/src/locales/id.json +++ b/src/locales/id.json @@ -217,5 +217,9 @@ "followHistRestored": "{n} ikutan dipulihkan.", "securityTitle": "Keamanan", "arkCoinsNone": "Belum ada koin di Belanja.", - "profKeyLink": "Kunci publik" + "profKeyLink": "Kunci publik", + "feedRelaysFormHelp": "Baca feed ini hanya dari relay ini. Kosongkan untuk relay biasa.", + "feedAllToggle": "Setiap postingan di relay ini (firehose)", + "feedAllCurated": "Hanya postingan populer: sembunyikan bot dan postingan tanpa reaksi", + "feedAllNeedsRelays": "Sebutkan relay untuk membaca semuanya." } diff --git a/src/locales/ja.json b/src/locales/ja.json index b809144..c95f5d0 100644 --- a/src/locales/ja.json +++ b/src/locales/ja.json @@ -881,5 +881,9 @@ "followHistRestored": "{n}人のフォローを復元しました。", "securityTitle": "セキュリティ", "arkCoinsNone": "支出にはまだコインがありません。", - "profKeyLink": "公開鍵" + "profKeyLink": "公開鍵", + "feedRelaysFormHelp": "このフィードはこれらのリレーからだけ読み込みます。空欄ならいつものリレーです。", + "feedAllToggle": "これらのリレーのすべての投稿(ファイアホース)", + "feedAllCurated": "人気の投稿のみ:ボットと反応のない投稿を隠す", + "feedAllNeedsRelays": "すべてを読み込むリレーを指定してください。" } diff --git a/src/locales/ko.json b/src/locales/ko.json index e2e2500..40a9a40 100644 --- a/src/locales/ko.json +++ b/src/locales/ko.json @@ -880,5 +880,9 @@ "followHistRestored": "팔로우 {n}명을 복원했습니다.", "securityTitle": "보안", "arkCoinsNone": "지출에 아직 코인이 없습니다.", - "profKeyLink": "공개 키" + "profKeyLink": "공개 키", + "feedRelaysFormHelp": "이 피드를 이 릴레이에서만 읽습니다. 비워 두면 평소 릴레이를 씁니다.", + "feedAllToggle": "이 릴레이의 모든 게시물 (파이어호스)", + "feedAllCurated": "인기 게시물만: 봇과 반응 없는 게시물 숨기기", + "feedAllNeedsRelays": "모두 읽어 올 릴레이를 지정하세요." } diff --git a/src/locales/mr.json b/src/locales/mr.json index 6d443bb..8fdb6db 100644 --- a/src/locales/mr.json +++ b/src/locales/mr.json @@ -217,5 +217,9 @@ "followHistRestored": "{n} फॉलो पुनर्संचयित केले.", "securityTitle": "सुरक्षा", "arkCoinsNone": "स्पेंडिंगमध्ये अद्याप कोणतेही कॉइन नाहीत.", - "profKeyLink": "सार्वजनिक की" + "profKeyLink": "सार्वजनिक की", + "feedRelaysFormHelp": "ही फीड फक्त या रिलेवरून वाचा. नेहमीच्या रिलेसाठी रिकामे ठेवा.", + "feedAllToggle": "या रिलेवरील प्रत्येक पोस्ट (फायरहोज)", + "feedAllCurated": "फक्त लोकप्रिय पोस्ट: बॉट्स आणि प्रतिसाद नसलेल्या पोस्ट लपवा", + "feedAllNeedsRelays": "सर्व काही कोणत्या रिलेवरून वाचायचे ते सांगा." } diff --git a/src/locales/pt.json b/src/locales/pt.json index 63d15cf..3c832a2 100644 --- a/src/locales/pt.json +++ b/src/locales/pt.json @@ -881,5 +881,9 @@ "followHistRestored": "{n} seguidos restaurados.", "securityTitle": "Segurança", "arkCoinsNone": "Ainda não há moedas em Gastos.", - "profKeyLink": "Chave pública" + "profKeyLink": "Chave pública", + "feedRelaysFormHelp": "Ler este feed só destes relays. Deixe em branco para os habituais.", + "feedAllToggle": "Todas as publicações destes relays (firehose)", + "feedAllCurated": "Só publicações populares: ocultar bots e publicações sem reações", + "feedAllNeedsRelays": "Indique os relays de onde ler tudo." } diff --git a/src/locales/ru.json b/src/locales/ru.json index 98da4e2..6766b0e 100644 --- a/src/locales/ru.json +++ b/src/locales/ru.json @@ -881,5 +881,9 @@ "followHistRestored": "Восстановлено подписок: {n}.", "securityTitle": "Безопасность", "arkCoinsNone": "В расходах пока нет монет.", - "profKeyLink": "Открытый ключ" + "profKeyLink": "Открытый ключ", + "feedRelaysFormHelp": "Читать эту ленту только с этих реле. Оставьте пустым для обычных.", + "feedAllToggle": "Все посты на этих реле (поток)", + "feedAllCurated": "Только популярные: скрыть ботов и посты без реакций", + "feedAllNeedsRelays": "Укажите реле, с которых читать всё." } diff --git a/src/locales/sw.json b/src/locales/sw.json index efaad77..57ff264 100644 --- a/src/locales/sw.json +++ b/src/locales/sw.json @@ -217,5 +217,9 @@ "followHistRestored": "Umerejesha unaowafuata {n}.", "securityTitle": "Usalama", "arkCoinsNone": "Bado hakuna sarafu kwenye Matumizi.", - "profKeyLink": "Ufunguo wa umma" + "profKeyLink": "Ufunguo wa umma", + "feedRelaysFormHelp": "Soma mlisho huu kutoka relay hizi tu. Acha tupu kwa zile za kawaida.", + "feedAllToggle": "Kila chapisho kwenye relay hizi (firehose)", + "feedAllCurated": "Machapisho maarufu tu: ficha boti na machapisho yasiyo na majibu", + "feedAllNeedsRelays": "Taja relay za kusoma kila kitu." } diff --git a/src/locales/ta.json b/src/locales/ta.json index bc210a3..0cb5244 100644 --- a/src/locales/ta.json +++ b/src/locales/ta.json @@ -217,5 +217,9 @@ "followHistRestored": "{n} பின்தொடர்வுகள் மீட்டெடுக்கப்பட்டன.", "securityTitle": "பாதுகாப்பு", "arkCoinsNone": "செலவுக் கணக்கில் இன்னும் நாணயங்கள் இல்லை.", - "profKeyLink": "பொது விசை" + "profKeyLink": "பொது விசை", + "feedRelaysFormHelp": "இந்த ஊட்டத்தை இந்த ரிலேக்களிலிருந்து மட்டும் படிக்கவும். வழக்கமானவற்றுக்கு காலியாக விடவும்.", + "feedAllToggle": "இந்த ரிலேக்களில் உள்ள ஒவ்வொரு பதிவும் (ஃபயர்ஹோஸ்)", + "feedAllCurated": "பிரபல பதிவுகள் மட்டும்: பாட்களையும் எதிர்வினையற்ற பதிவுகளையும் மறை", + "feedAllNeedsRelays": "அனைத்தையும் படிக்க வேண்டிய ரிலேக்களைக் குறிப்பிடவும்." } diff --git a/src/locales/te.json b/src/locales/te.json index 44d7017..9f468e6 100644 --- a/src/locales/te.json +++ b/src/locales/te.json @@ -215,5 +215,9 @@ "followHistRestored": "{n} ఫాలోలు పునరుద్ధరించబడ్డాయి.", "securityTitle": "భద్రత", "arkCoinsNone": "ఖర్చు ఖాతాలో ఇంకా నాణేలు లేవు.", - "profKeyLink": "పబ్లిక్ కీ" + "profKeyLink": "పబ్లిక్ కీ", + "feedRelaysFormHelp": "ఈ ఫీడ్ను ఈ రిలేల నుంచి మాత్రమే చదవండి. సాధారణ వాటికి ఖాళీగా ఉంచండి.", + "feedAllToggle": "ఈ రిలేలలోని ప్రతి పోస్ట్ (ఫైర్హోస్)", + "feedAllCurated": "జనాదరణ పొందిన పోస్ట్లు మాత్రమే: బాట్లు, స్పందన లేని పోస్ట్లను దాచు", + "feedAllNeedsRelays": "అన్నీ చదవాల్సిన రిలేలను పేర్కొనండి." } diff --git a/src/locales/tr.json b/src/locales/tr.json index f22cb0e..6c441b2 100644 --- a/src/locales/tr.json +++ b/src/locales/tr.json @@ -880,5 +880,9 @@ "followHistRestored": "{n} takip geri yüklendi.", "securityTitle": "Güvenlik", "arkCoinsNone": "Harcama’da henüz coin yok.", - "profKeyLink": "Açık anahtar" + "profKeyLink": "Açık anahtar", + "feedRelaysFormHelp": "Bu akışı yalnızca bu rölelerden oku. Her zamankiler için boş bırak.", + "feedAllToggle": "Bu rölelerdeki her gönderi (firehose)", + "feedAllCurated": "Yalnızca popüler gönderiler: botları ve tepki almamış gönderileri gizle", + "feedAllNeedsRelays": "Her şeyin okunacağı röleleri yaz." } diff --git a/src/locales/ur.json b/src/locales/ur.json index a018085..c6a6fe4 100644 --- a/src/locales/ur.json +++ b/src/locales/ur.json @@ -217,5 +217,9 @@ "followHistRestored": "{n} فالو بحال ہو گئے۔", "securityTitle": "سیکیورٹی", "arkCoinsNone": "خرچ میں ابھی کوئی کوائن نہیں۔", - "profKeyLink": "پبلک کی" + "profKeyLink": "پبلک کی", + "feedRelaysFormHelp": "یہ فیڈ صرف ان ریلے سے پڑھیں۔ معمول کے ریلے کے لیے خالی چھوڑ دیں۔", + "feedAllToggle": "ان ریلے پر ہر پوسٹ (فائر ہوز)", + "feedAllCurated": "صرف مقبول پوسٹس: بوٹس اور بغیر ردعمل والی پوسٹس چھپائیں", + "feedAllNeedsRelays": "وہ ریلے بتائیں جن سے سب کچھ پڑھنا ہے۔" } diff --git a/src/locales/vi.json b/src/locales/vi.json index fefac38..963aa21 100644 --- a/src/locales/vi.json +++ b/src/locales/vi.json @@ -217,5 +217,9 @@ "followHistRestored": "Đã khôi phục {n} người theo dõi.", "securityTitle": "Bảo mật", "arkCoinsNone": "Chưa có coin nào trong Chi tiêu.", - "profKeyLink": "Khóa công khai" + "profKeyLink": "Khóa công khai", + "feedRelaysFormHelp": "Chỉ đọc bảng tin này từ các relay này. Để trống để dùng relay thường dùng.", + "feedAllToggle": "Mọi bài đăng trên các relay này (firehose)", + "feedAllCurated": "Chỉ bài phổ biến: ẩn bot và bài không ai tương tác", + "feedAllNeedsRelays": "Hãy nêu các relay để đọc mọi thứ." } diff --git a/src/locales/zh.json b/src/locales/zh.json index e09b385..c73d88e 100644 --- a/src/locales/zh.json +++ b/src/locales/zh.json @@ -881,5 +881,9 @@ "followHistRestored": "已恢复 {n} 个关注。", "securityTitle": "安全", "arkCoinsNone": "支出账户中还没有币。", - "profKeyLink": "公钥" + "profKeyLink": "公钥", + "feedRelaysFormHelp": "仅从这些中继读取此动态。留空则使用常用中继。", + "feedAllToggle": "这些中继上的每一条帖子(全量流)", + "feedAllCurated": "仅热门帖子:隐藏机器人和无人互动的帖子", + "feedAllNeedsRelays": "请填写要读取全部内容的中继。" } diff --git a/src/style.css b/src/style.css index 7ef428c..5bb171a 100644 --- a/src/style.css +++ b/src/style.css @@ -964,12 +964,15 @@ html.no-scroll { overflow: hidden; scrollbar-gutter: auto; } side shadows carry the tint through the list's padding to its edges. */ .notes-feed > .row { transition: background-color 3s ease-out, box-shadow 3s ease-out; } .notes-feed > .row.note-fresh { - --fresh-bg: color-mix(in srgb, var(--green) 9%, var(--paper)); + /* 9% was a whisper on white; dark mode keeps it (the green carries more there) */ + --fresh-bg: color-mix(in srgb, var(--green) 16%, var(--paper)); background-color: var(--fresh-bg); box-shadow: -14px 0 0 var(--fresh-bg), 14px 0 0 var(--fresh-bg); } +:root[data-theme="dark"] .notes-feed > .row.note-fresh { --fresh-bg: color-mix(in srgb, var(--green) 9%, var(--paper)); } + /* Inline move-money panel on the balance card. */ .balance-move { gap: 10px; margin-top: 12px; padding-top: 12px; border-top: 1px solid var(--line); text-align: left; } /* balance carousel: the other face peeks at the card's edge and drags into |
