Skip to content

Commit 45f3daa

Browse files
committed
feat: subscribe dropdown with RSS + Atom options on homepage and article pages
- Homepage: orange RSS icon opens dropdown with RSS and Atom links - Article page: "Subscribe" button opens dropdown with RSS and Atom - Regenerated lock file for Node 22 compatibility
1 parent cb66b48 commit 45f3daa

2 files changed

Lines changed: 57 additions & 14 deletions

File tree

src/routes/+page.svelte

Lines changed: 32 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
<script lang="ts">
22
let { data } = $props();
33
let expandedArticles = $state(new Set<number>());
4+
let subscribeOpen = $state(false);
45
56
// Stable color per feed name — hashes the name to pick a hue
67
function feedColor(name: string): string {
@@ -45,15 +46,22 @@
4546
style={data.feedFilter === String(feed.id) ? `background: ${feedColor(feed.name)};` : `border: 1px solid ${feedColor(feed.name)}; color: ${feedColor(feed.name)}; background: transparent;`}
4647
>{feed.name}</a>
4748
{/each}
48-
<a href={data.feedFilter ? `/feed/${data.feedFilter}/rss.xml` : '/rss.xml'}
49-
class="rss-icon" title="Subscribe to this feed (RSS)">
50-
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 256 256">
51-
<rect width="256" height="256" rx="55" ry="55" fill="#f26522"/>
52-
<circle cx="68" cy="189" r="28" fill="#fff"/>
53-
<path d="M160 213h-34a82 82 0 0 0-82-82V97a116 116 0 0 1 116 116z" fill="#fff"/>
54-
<path d="M224 213h-34a148 148 0 0 0-148-148V31a182 182 0 0 1 182 182z" fill="#fff"/>
55-
</svg>
56-
</a>
49+
<div class="subscribe-dropdown">
50+
<button type="button" class="rss-icon" onclick={() => subscribeOpen = !subscribeOpen} title="Subscribe to this feed">
51+
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 256 256">
52+
<rect width="256" height="256" rx="55" ry="55" fill="#f26522"/>
53+
<circle cx="68" cy="189" r="28" fill="#fff"/>
54+
<path d="M160 213h-34a82 82 0 0 0-82-82V97a116 116 0 0 1 116 116z" fill="#fff"/>
55+
<path d="M224 213h-34a148 148 0 0 0-148-148V31a182 182 0 0 1 182 182z" fill="#fff"/>
56+
</svg>
57+
</button>
58+
{#if subscribeOpen}
59+
<div class="subscribe-menu">
60+
<a href={data.feedFilter ? `/feed/${data.feedFilter}/rss.xml` : '/rss.xml'}>RSS</a>
61+
<a href={data.feedFilter ? `/feed/${data.feedFilter}/atom.xml` : '/atom.xml'}>Atom</a>
62+
</div>
63+
{/if}
64+
</div>
5765
</div>
5866
<label>
5967
<input type="checkbox" checked={data.showBoring}
@@ -148,8 +156,21 @@
148156
.feed-tabs a { padding: 0.2rem 0.6rem; border-radius: 1rem; text-decoration: none; background: var(--color-border); color: var(--color-text); font-size: 0.8rem; transition: background 0.15s; }
149157
.feed-tabs a:hover { background: var(--color-primary); color: white; }
150158
.feed-tabs a.active { background: var(--color-primary); color: white; }
151-
.rss-icon { display: inline-flex; align-items: center; background: none !important; padding: 0.2rem !important; }
152-
.rss-icon:hover { background: none !important; opacity: 0.8; }
159+
.subscribe-dropdown { position: relative; display: inline-flex; }
160+
.rss-icon { display: inline-flex; align-items: center; background: none !important; padding: 0.2rem !important; border: none; cursor: pointer; }
161+
.rss-icon:hover { opacity: 0.8; }
162+
.subscribe-menu {
163+
position: absolute; top: 100%; right: 0; margin-top: 0.25rem;
164+
background: white; border: 1px solid var(--color-border); border-radius: 0.375rem;
165+
box-shadow: 0 4px 12px rgba(0,0,0,0.1); z-index: 10; min-width: 80px;
166+
display: flex; flex-direction: column;
167+
}
168+
.subscribe-menu a {
169+
display: block; padding: 0.4rem 0.75rem; text-decoration: none;
170+
font-size: 0.8rem; color: var(--color-text);
171+
}
172+
.subscribe-menu a:hover { background: #f0f4ff; color: var(--color-primary); }
173+
.subscribe-menu a:not(:last-child) { border-bottom: 1px solid var(--color-border); }
153174
label { font-size: 0.8rem; white-space: nowrap; color: var(--color-muted); }
154175
155176
.diff-list { display: flex; flex-direction: column; gap: 1rem; }

src/routes/article/[id]/+page.svelte

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
<script lang="ts">
22
let { data } = $props();
33
const { article } = data;
4+
let subscribeOpen = $state(false);
45
</script>
56

67
<svelte:head><title>{article.versions[0]?.title || 'Article'} — NewsDiff</title></svelte:head>
@@ -10,8 +11,15 @@
1011
<a href={article.url} target="_blank" rel="noopener">{article.url}</a>
1112
<span>{article.feed.name}</span>
1213
<span>{article.versions.length} version{article.versions.length !== 1 ? 's' : ''}</span>
13-
<a href="/article/{article.id}/atom.xml" class="feed-link">Atom</a>
14-
<a href="/article/{article.id}/rss.xml" class="feed-link">RSS</a>
14+
<div class="subscribe-dropdown">
15+
<button type="button" class="feed-link subscribe-btn" onclick={() => subscribeOpen = !subscribeOpen}>Subscribe</button>
16+
{#if subscribeOpen}
17+
<div class="subscribe-menu">
18+
<a href="/article/{article.id}/rss.xml">RSS</a>
19+
<a href="/article/{article.id}/atom.xml">Atom</a>
20+
</div>
21+
{/if}
22+
</div>
1523
</div>
1624

1725
{#if article.diffs.length > 0}
@@ -37,7 +45,21 @@
3745
<style>
3846
.meta { display: flex; gap: 1rem; font-size: 0.85rem; color: var(--color-muted); margin-bottom: 2rem; flex-wrap: wrap; }
3947
.meta a { color: var(--color-primary); word-break: break-all; }
40-
.feed-link { word-break: normal; }
48+
.subscribe-dropdown { position: relative; display: inline-flex; }
49+
.subscribe-btn { border: none; background: none; cursor: pointer; font-size: 0.85rem; color: var(--color-primary); padding: 0; }
50+
.subscribe-btn:hover { text-decoration: underline; }
51+
.subscribe-menu {
52+
position: absolute; top: 100%; left: 0; margin-top: 0.25rem;
53+
background: white; border: 1px solid var(--color-border); border-radius: 0.375rem;
54+
box-shadow: 0 4px 12px rgba(0,0,0,0.1); z-index: 10; min-width: 80px;
55+
display: flex; flex-direction: column;
56+
}
57+
.subscribe-menu a {
58+
display: block; padding: 0.4rem 0.75rem; text-decoration: none;
59+
font-size: 0.8rem; color: var(--color-text);
60+
}
61+
.subscribe-menu a:hover { background: #f0f4ff; color: var(--color-primary); }
62+
.subscribe-menu a:not(:last-child) { border-bottom: 1px solid var(--color-border); }
4163
h2 { font-size: 1.1rem; margin-bottom: 1rem; }
4264
.diff-list { display: flex; flex-direction: column; gap: 0.5rem; }
4365
.diff-card { display: flex; align-items: center; gap: 1rem; padding: 0.75rem; border: 1px solid var(--color-border); border-radius: 0.25rem; text-decoration: none; color: var(--color-text); background: white; }

0 commit comments

Comments
 (0)