Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 19 additions & 60 deletions Gemfile.lock
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
GIT
remote: https://github.com/html2rss/html2rss-configs.git
revision: 7f40e65325f33383a8bdabfc5261f8cff33a3a9e
revision: d9e3dc55b38514eb9cd4a17cb0285d9ef73bc9d5
specs:
html2rss-configs (0.2.0)
html2rss

GIT
remote: https://github.com/html2rss/html2rss.git
revision: 644c7f06ccd70f8ed231a26ffc9d8d3279a2617b
revision: aa974733c6e88a5c934f445516d9752dfa316067
specs:
html2rss (0.25.0)
addressable (~> 2.7)
Expand All @@ -17,50 +17,28 @@ GIT
faraday-follow_redirects
faraday-gzip (~> 3)
kramdown
mcp (~> 1.0)
mime-types (> 3.0)
nokogiri (>= 1.10, < 2.0)
puppeteer-ruby
rack (~> 3.0)
rackup (~> 2.0)
regexp_parser
reverse_markdown (~> 3.0)
rss
sanitize
thor
tzinfo
webrick (~> 1.9)
zeitwerk

GEM
remote: https://rubygems.org/
specs:
addressable (2.9.0)
public_suffix (>= 2.0.2, < 8.0)
async (2.44.1)
console (~> 1.29)
fiber-annotation
io-event (~> 1.11)
async-http (0.99.0)
async (>= 2.35.1)
async-pool (~> 0.11)
io-endpoint (~> 0.14)
io-stream (~> 0.14)
protocol-http (~> 0.66)
protocol-http1 (~> 0.39)
protocol-http2 (~> 0.26)
protocol-url (~> 0.2)
async-pool (0.11.2)
async (>= 2.0)
async-websocket (0.30.1)
async-http (~> 0.76)
protocol-http (~> 0.34)
protocol-rack (~> 0.7)
protocol-websocket (~> 0.17)
base64 (0.3.0)
bigdecimal (4.1.2)
brotli (0.8.0)
concurrent-ruby (1.3.8)
console (1.37.0)
fiber-annotation
fiber-local (~> 1.1)
json
crass (1.0.7)
dry-configurable (1.4.0)
dry-core (~> 1.0)
Expand Down Expand Up @@ -108,18 +86,18 @@ GEM
zlib (~> 3.0)
faraday-net_http (3.4.4)
net-http (~> 0.5)
fiber-annotation (0.2.0)
fiber-local (1.1.0)
fiber-storage
fiber-storage (1.0.1)
io-endpoint (0.17.2)
io-event (1.19.5)
io-stream (0.14.0)
openssl (>= 3.3)
hana (1.3.7)
json (2.21.2)
json_schemer (2.5.0)
bigdecimal
hana (~> 1.3)
regexp_parser (~> 2.0)
simpleidn (~> 0.2)
kramdown (2.5.2)
rexml (>= 3.4.4)
logger (1.7.0)
mcp (1.2.0)
json_schemer (>= 2.4)
mime-types (3.7.0)
logger
mime-types-data (~> 3.2025, >= 3.2025.0507)
Expand All @@ -130,31 +108,11 @@ GEM
racc (~> 1.4)
nokogiri (1.19.4-x86_64-linux-gnu)
racc (~> 1.4)
openssl (4.0.2)
protocol-hpack (1.5.1)
protocol-http (0.70.0)
protocol-http1 (0.40.2)
protocol-http (~> 0.68)
protocol-http2 (0.26.2)
protocol-hpack (~> 1.4)
protocol-http (~> 0.62)
protocol-rack (0.22.1)
io-stream (>= 0.10)
protocol-http (~> 0.58)
rack (>= 1.0)
protocol-url (0.18.0)
protocol-websocket (0.21.1)
protocol-http (~> 0.2)
public_suffix (7.0.5)
puppeteer-ruby (0.53.0)
async (>= 2.35.1, < 3.0)
async-http (>= 0.60, < 1.0)
async-websocket (>= 0.27, < 1.0)
base64
mime-types (>= 3.0)
urlpattern (~> 0.1.1)
racc (1.8.1)
rack (3.2.7)
rackup (2.3.1)
rack (>= 3)
regexp_parser (2.12.0)
reverse_markdown (3.0.2)
nokogiri
Expand All @@ -164,16 +122,17 @@ GEM
sanitize (7.0.0)
crass (~> 1.0.2)
nokogiri (>= 1.16.8)
simpleidn (0.2.3)
thor (1.5.0)
tzinfo (2.0.6)
concurrent-ruby (~> 1.0)
uri (1.1.1)
urlpattern (0.1.1-arm64-darwin)
urlpattern (0.1.1-x86_64-linux)
webrick (1.9.2)
zeitwerk (2.8.3)
zlib (3.2.3)

PLATFORMS
arm64-darwin-23
arm64-darwin-24
arm64-darwin-25
x86_64-linux
Expand Down
3 changes: 2 additions & 1 deletion bin/data-update
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,8 @@ output = file_names.map do |file_name|
'valid_channel_url' => valid_url(config['channel']['url']),
'url_parameters' => string_formatting_references(config['channel']['url']),
'default_parameters' => default_parameters,
'channel' => config['channel']
'channel' => config['channel'],
'directory' => config['directory']
}
end

Expand Down
139 changes: 137 additions & 2 deletions src/components/FeedDirectory.astro
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,18 @@ function formatDefaultParameters(defaultParameters: Record<string, string> = {})
.join(", ");
}

const availableTopics = [...new Set(configs.flatMap((config) => config.directory?.topics || []))].sort(
(a, b) => a.localeCompare(b),
);

const availableLanguages = [
...new Set(
configs
.map((config) => config.channel?.language)
.filter((language): language is string => Boolean(language)),
),
].sort((a, b) => a.localeCompare(b));

const staticFeedUrls = configs.map((config) => ({
...config,
staticFeedUrl: "#",
Expand All @@ -19,6 +31,8 @@ const staticFeedUrls = configs.map((config) => ({
?.replace(/^https?:\/\//, "")
.replace(/^www\./, "")
.replace(/\/$/, ""),
topics: config.directory?.topics || [],
language: config.channel?.language || "",
}));
---

Expand Down Expand Up @@ -47,6 +61,38 @@ const staticFeedUrls = configs.map((config) => ({
</p>
</div>

<div class="filter-block">
<div class="filter-group">
<p class="filter-label" id="topic-filter-label">Topics</p>
<div class="topic-chips" role="group" aria-labelledby="topic-filter-label">
{
availableTopics.map((topic) => (
<button type="button" class="topic-chip" data-topic-filter={topic} aria-pressed="false">
{topic}
</button>
))
}
</div>
</div>

<div class="filter-actions">
<div class="language-filter">
<label class="filter-label" for="language-filter">Language</label>
<select
id="language-filter"
class="language-select"
data-language-filter
aria-label="Filter by language"
>
<option value="">All languages</option>
{availableLanguages.map((language) => <option value={language}>{language}</option>)}
</select>
</div>

<button type="button" class="export-opml" data-export-opml> Export OPML </button>
</div>
</div>

<div class="instance-block">
<div class="instance-line">
<span class="instance-label">Using instance:</span>
Expand Down Expand Up @@ -114,7 +160,9 @@ const staticFeedUrls = configs.map((config) => ({
class="feed-row"
data-domain={config.domain}
data-name={config.name}
data-searchable={`${config.domain}/${config.name} ${config.channel?.url || ""}`}
data-topics={config.topics.join(" ")}
data-language={config.language}
data-searchable={`${config.domain}/${config.name} ${config.channel?.url || ""} ${config.topics.join(" ")} ${config.language}`}
>
<div class="feed-info">
<div class="feed-mainline">
Expand Down Expand Up @@ -272,14 +320,16 @@ const staticFeedUrls = configs.map((config) => ({
}

.search-block,
.filter-block,
.instance-block,
.empty-state,
.feed-row,
.parameter-form {
padding: var(--fd-padding);
}

.search-block {
.search-block,
.filter-block {
display: grid;
gap: var(--fd-gap);
border-bottom: 1px solid var(--fd-border);
Expand Down Expand Up @@ -325,6 +375,81 @@ const staticFeedUrls = configs.map((config) => ({
outline: none;
}

.filter-group {
display: grid;
gap: 0.375rem;
}

.filter-label {
margin: 0;
color: var(--fd-muted);
font-size: var(--sl-text-xs);
}

.topic-chips {
display: flex;
flex-wrap: wrap;
gap: 0.375rem;
}

.topic-chip {
appearance: none;
padding: 0.25rem 0.625rem;
border: 1px solid var(--fd-border);
border-radius: calc(var(--fd-radius) - 0.125rem);
background: transparent;
color: var(--fd-muted);
font: inherit;
font-size: var(--sl-text-xs);
cursor: pointer;
}

.topic-chip[aria-pressed="true"] {
border-color: var(--sl-color-accent);
background: var(--sl-color-accent-low);
color: var(--sl-color-white);
}

.filter-actions {
display: flex;
flex-wrap: wrap;
gap: var(--fd-gap);
align-items: end;
justify-content: space-between;
}

.language-filter {
display: grid;
gap: 0.375rem;
min-width: 10rem;
}

.language-select {
min-width: 0;
padding: 0.5rem 0.75rem;
border: 1px solid var(--fd-border);
border-radius: calc(var(--fd-radius) - 0.125rem);
background: var(--fd-surface-alt);
color: var(--sl-color-white);
font: inherit;
font-size: var(--sl-text-sm);
}

.export-opml {
appearance: none;
display: inline-flex;
align-items: center;
justify-content: center;
padding: 0.5rem 0.75rem;
border: 1px solid var(--fd-border);
border-radius: calc(var(--fd-radius) - 0.125rem);
background: transparent;
color: var(--sl-color-white);
font: inherit;
font-size: var(--sl-text-sm);
cursor: pointer;
}

.result-summary,
.instance-feedback,
.empty-title,
Expand Down Expand Up @@ -551,6 +676,11 @@ const staticFeedUrls = configs.map((config) => ({
.instance-apply:focus-visible,
.done-button:hover,
.done-button:focus-visible,
.topic-chip:hover,
.topic-chip:focus-visible,
.export-opml:hover,
.export-opml:focus-visible,
.language-select:focus-visible,
.instance-input:focus-visible,
.form-input:focus-visible {
border-color: var(--sl-color-accent);
Expand Down Expand Up @@ -651,5 +781,10 @@ const staticFeedUrls = configs.map((config) => ({
.feed-meta {
justify-content: flex-start;
}

.filter-actions {
flex-direction: column;
align-items: stretch;
}
}
</style>
Loading
Loading