mirror of
https://github.com/samsonjs/samhuri.net.git
synced 2026-04-05 10:45:45 +00:00
Fix detecting gemini:// links in JS and remove unused properties from site.toml
This commit is contained in:
parent
5255247823
commit
d2fc41fb1e
6 changed files with 122 additions and 65 deletions
|
|
@ -214,7 +214,9 @@ module Pressa
|
|||
remote_links = build_output_links(
|
||||
format_config["remote_links"],
|
||||
context: "site.toml outputs.html.remote_links",
|
||||
allow_icon: true
|
||||
allow_icon: true,
|
||||
allow_label_optional: false,
|
||||
allow_string_entries: false
|
||||
)
|
||||
|
||||
HTMLOutputOptions.new(
|
||||
|
|
@ -236,7 +238,9 @@ module Pressa
|
|||
home_links = build_output_links(
|
||||
format_config["home_links"],
|
||||
context: "site.toml outputs.gemini.home_links",
|
||||
allow_icon: false
|
||||
allow_icon: false,
|
||||
allow_label_optional: true,
|
||||
allow_string_entries: true
|
||||
)
|
||||
recent_posts_limit = build_recent_posts_limit(
|
||||
format_config["recent_posts_limit"],
|
||||
|
|
@ -339,11 +343,21 @@ module Pressa
|
|||
end
|
||||
end
|
||||
|
||||
def build_output_links(value, context:, allow_icon:)
|
||||
def build_output_links(value, context:, allow_icon:, allow_label_optional:, allow_string_entries:)
|
||||
entries = array_or_empty(value, context)
|
||||
entries.map.with_index do |entry, index|
|
||||
if allow_string_entries && entry.is_a?(String)
|
||||
href = entry
|
||||
unless !href.strip.empty?
|
||||
raise ValidationError, "Expected #{context}[#{index}] to be a non-empty String"
|
||||
end
|
||||
validate_link_href!(href.strip, context: "#{context}[#{index}]")
|
||||
|
||||
next OutputLink.new(label: nil, href: href.strip, icon: nil)
|
||||
end
|
||||
|
||||
unless entry.is_a?(Hash)
|
||||
raise ValidationError, "Expected #{context}[#{index}] to be a table"
|
||||
raise ValidationError, "Expected #{context}[#{index}] to be a String or table"
|
||||
end
|
||||
|
||||
allowed_keys = allow_icon ? %w[label href icon] : %w[label href]
|
||||
|
|
@ -353,16 +367,23 @@ module Pressa
|
|||
context: "#{context}[#{index}]"
|
||||
)
|
||||
|
||||
label = entry["label"]
|
||||
href = entry["href"]
|
||||
unless label.is_a?(String) && !label.strip.empty?
|
||||
raise ValidationError, "Expected #{context}[#{index}].label to be a non-empty String"
|
||||
end
|
||||
unless href.is_a?(String) && !href.strip.empty?
|
||||
raise ValidationError, "Expected #{context}[#{index}].href to be a non-empty String"
|
||||
end
|
||||
validate_link_href!(href.strip, context: "#{context}[#{index}].href")
|
||||
|
||||
label = entry["label"]
|
||||
if label.nil?
|
||||
unless allow_label_optional
|
||||
raise ValidationError, "Expected #{context}[#{index}].label to be a non-empty String"
|
||||
end
|
||||
else
|
||||
unless label.is_a?(String) && !label.strip.empty?
|
||||
raise ValidationError, "Expected #{context}[#{index}].label to be a non-empty String"
|
||||
end
|
||||
end
|
||||
|
||||
icon = entry["icon"]
|
||||
unless allow_icon
|
||||
if entry.key?("icon")
|
||||
|
|
@ -376,7 +397,7 @@ module Pressa
|
|||
raise ValidationError, "Expected #{context}[#{index}].icon to be a non-empty String"
|
||||
end
|
||||
|
||||
OutputLink.new(label: label.strip, href: href.strip, icon: icon&.strip)
|
||||
OutputLink.new(label: label&.strip, href: href.strip, icon: icon&.strip)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -20,7 +20,12 @@ module Pressa
|
|||
def write_recent_posts(target_path:, limit: RECENT_POSTS_LIMIT)
|
||||
rows = ["# #{@site.title}", ""]
|
||||
home_links.each do |link|
|
||||
rows << "=> #{link.href}"
|
||||
label = link.label&.strip
|
||||
rows << if label.nil? || label.empty?
|
||||
"=> #{link.href}"
|
||||
else
|
||||
"=> #{link.href} #{label}"
|
||||
end
|
||||
end
|
||||
rows << "" unless home_links.empty?
|
||||
rows << "## Recent posts"
|
||||
|
|
|
|||
|
|
@ -6,7 +6,8 @@ module Pressa
|
|||
end
|
||||
|
||||
class OutputLink < Dry::Struct
|
||||
attribute :label, Types::String
|
||||
# label is required for HTML remote links, but Gemini home_links may omit it.
|
||||
attribute :label, Types::String.optional.default(nil)
|
||||
attribute :href, Types::String
|
||||
attribute :icon, Types::String.optional.default(nil)
|
||||
end
|
||||
|
|
|
|||
|
|
@ -199,60 +199,64 @@ module Pressa
|
|||
}
|
||||
|
||||
function setupGeminiFallback() {
|
||||
var link = document.querySelector(
|
||||
'header.primary nav.remote li.gemini a[href^="gemini://"]'
|
||||
var links = document.querySelectorAll(
|
||||
'header.primary nav.remote a[href^="gemini://"]'
|
||||
);
|
||||
if (!link) return;
|
||||
if (!links || links.length === 0) return;
|
||||
|
||||
link.addEventListener("click", function (e) {
|
||||
if (!isPlainLeftClick(e)) return;
|
||||
for (var i = 0; i < links.length; i++) {
|
||||
(function (link) {
|
||||
link.addEventListener("click", function (e) {
|
||||
if (!isPlainLeftClick(e)) return;
|
||||
|
||||
e.preventDefault();
|
||||
e.preventDefault();
|
||||
|
||||
var geminiHref = link.getAttribute("href");
|
||||
var fallbackHref = "https://geminiprotocol.net";
|
||||
var geminiHref = link.getAttribute("href");
|
||||
var fallbackHref = "https://geminiprotocol.net";
|
||||
|
||||
var done = false;
|
||||
var fallbackTimer = null;
|
||||
var done = false;
|
||||
var fallbackTimer = null;
|
||||
|
||||
function cleanup() {
|
||||
if (fallbackTimer) window.clearTimeout(fallbackTimer);
|
||||
document.removeEventListener("visibilitychange", onVisibilityChange);
|
||||
window.removeEventListener("pagehide", onPageHide);
|
||||
window.removeEventListener("blur", onBlur);
|
||||
}
|
||||
function cleanup() {
|
||||
if (fallbackTimer) window.clearTimeout(fallbackTimer);
|
||||
document.removeEventListener("visibilitychange", onVisibilityChange);
|
||||
window.removeEventListener("pagehide", onPageHide);
|
||||
window.removeEventListener("blur", onBlur);
|
||||
}
|
||||
|
||||
function markDone() {
|
||||
done = true;
|
||||
cleanup();
|
||||
}
|
||||
function markDone() {
|
||||
done = true;
|
||||
cleanup();
|
||||
}
|
||||
|
||||
function onVisibilityChange() {
|
||||
// If a handler opens and the browser backgrounded, consider it "successful".
|
||||
if (document.visibilityState === "hidden") markDone();
|
||||
}
|
||||
function onVisibilityChange() {
|
||||
// If a handler opens and the browser backgrounded, consider it "successful".
|
||||
if (document.visibilityState === "hidden") markDone();
|
||||
}
|
||||
|
||||
function onPageHide() {
|
||||
markDone();
|
||||
}
|
||||
function onPageHide() {
|
||||
markDone();
|
||||
}
|
||||
|
||||
function onBlur() {
|
||||
// Some browsers blur the page when a protocol handler is invoked.
|
||||
markDone();
|
||||
}
|
||||
function onBlur() {
|
||||
// Some browsers blur the page when a protocol handler is invoked.
|
||||
markDone();
|
||||
}
|
||||
|
||||
document.addEventListener("visibilitychange", onVisibilityChange);
|
||||
window.addEventListener("pagehide", onPageHide, { once: true });
|
||||
window.addEventListener("blur", onBlur, { once: true });
|
||||
document.addEventListener("visibilitychange", onVisibilityChange);
|
||||
window.addEventListener("pagehide", onPageHide, { once: true });
|
||||
window.addEventListener("blur", onBlur, { once: true });
|
||||
|
||||
// If we're still here shortly after attempting navigation, assume it failed.
|
||||
fallbackTimer = window.setTimeout(function () {
|
||||
if (done) return;
|
||||
window.location.href = fallbackHref;
|
||||
}, 900);
|
||||
// If we're still here shortly after attempting navigation, assume it failed.
|
||||
fallbackTimer = window.setTimeout(function () {
|
||||
if (done) return;
|
||||
window.location.href = fallbackHref;
|
||||
}, 900);
|
||||
|
||||
window.location.href = geminiHref;
|
||||
});
|
||||
window.location.href = geminiHref;
|
||||
});
|
||||
})(links[i]);
|
||||
}
|
||||
}
|
||||
|
||||
if (document.readyState === "loading") {
|
||||
|
|
|
|||
16
site.toml
16
site.toml
|
|
@ -29,14 +29,14 @@ remote_links = [
|
|||
[outputs.gemini]
|
||||
recent_posts_limit = 20
|
||||
home_links = [
|
||||
{"label": "About", "href": "/about"},
|
||||
{"label": "Posts", "href": "/posts"},
|
||||
{"label": "Projects", "href": "/projects"},
|
||||
{"label": "Mastodon", "href": "https://techhub.social/@sjs"},
|
||||
{"label": "GitHub", "href": "https://github.com/samsonjs"},
|
||||
{"label": "RSS (Gemini)", "href": "/posts/feed.gmi"},
|
||||
{"label": "RSS (Web)", "href": "https://samhuri.net/feed.xml"},
|
||||
{"label": "Email", "href": "mailto:sami@samhuri.net"}
|
||||
"/about",
|
||||
"/posts",
|
||||
"/projects",
|
||||
"https://techhub.social/@sjs",
|
||||
"https://github.com/samsonjs",
|
||||
"/posts/feed.gmi",
|
||||
"https://samhuri.net/feed.xml",
|
||||
"mailto:sami@samhuri.net"
|
||||
]
|
||||
exclude_public = [
|
||||
"tweets/**",
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ class Pressa::Config::LoaderTest < Minitest::Test
|
|||
assert_equal(["Pressa::Utils::GeminiMarkdownRenderer"], site.renderers.map(&:class).map(&:name))
|
||||
assert_equal(["tweets/**"], site.public_excludes)
|
||||
assert_equal(20, site.gemini_output_options&.recent_posts_limit)
|
||||
assert_equal(["About", "GitHub"], site.gemini_output_options&.home_links&.map(&:label))
|
||||
assert_equal(["/about/", "https://github.com/samsonjs"], site.gemini_output_options&.home_links&.map(&:href))
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -561,6 +561,35 @@ class Pressa::Config::LoaderTest < Minitest::Test
|
|||
end
|
||||
end
|
||||
|
||||
def test_build_site_allows_string_home_links_and_optional_labels_for_gemini
|
||||
Dir.mktmpdir do |dir|
|
||||
File.write(File.join(dir, "site.toml"), <<~TOML)
|
||||
author = "Sami Samhuri"
|
||||
email = "sami@samhuri.net"
|
||||
title = "samhuri.net"
|
||||
description = "blog"
|
||||
url = "https://samhuri.net"
|
||||
|
||||
[outputs.gemini]
|
||||
home_links = [
|
||||
"/about/",
|
||||
{"href": "/posts/"},
|
||||
{"label": "GitHub", "href": "https://github.com/samsonjs"}
|
||||
]
|
||||
TOML
|
||||
File.write(File.join(dir, "projects.toml"), "projects = []\n")
|
||||
|
||||
loader = Pressa::Config::Loader.new(source_path: dir)
|
||||
site = loader.build_site(output_format: "gemini")
|
||||
|
||||
assert_equal("gemini", site.output_format)
|
||||
assert_equal(3, site.gemini_output_options&.home_links&.length)
|
||||
assert_nil(site.gemini_output_options&.home_links&.at(0)&.label)
|
||||
assert_nil(site.gemini_output_options&.home_links&.at(1)&.label)
|
||||
assert_equal("GitHub", site.gemini_output_options&.home_links&.at(2)&.label)
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def with_temp_config
|
||||
|
|
@ -588,10 +617,7 @@ class Pressa::Config::LoaderTest < Minitest::Test
|
|||
|
||||
[outputs.gemini]
|
||||
recent_posts_limit = 20
|
||||
home_links = [
|
||||
{"label": "About", "href": "/about/"},
|
||||
{"label": "GitHub", "href": "https://github.com/samsonjs"}
|
||||
]
|
||||
home_links = ["/about/", "https://github.com/samsonjs"]
|
||||
exclude_public = ["tweets/**"]
|
||||
TOML
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue