This commit is contained in:
Râu Cao 2025-04-23 12:43:41 +04:00
commit 44d5b62b3c
Signed by: raucao
GPG Key ID: 37036C356E56CC51
9 changed files with 173 additions and 0 deletions

28
background.js Normal file
View File

@ -0,0 +1,28 @@
browser.tabs.onUpdated.addListener(async (tabId, changeInfo, tab) => {
if (changeInfo.status !== 'complete') {
browser.pageAction.hide(tabId);
await browser.storage.local.remove(`nl_tab_${sender.tab.id}`);
return;
}
}, { properties: ["status"] });
browser.runtime.onMessage.addListener((message, sender, sendResponse) => {
if (message.action === "showNostrLinksPageAction" && sender.tab?.id) {
const tabLinks = { [`nl_tab_${sender.tab.id}`]: message.links };
browser.storage.local.set(tabLinks, () => {
browser.pageAction.show(sender.tab.id);
});
}
if (message.action === "getNostrLinks" && message.tabId) {
browser.storage.local.get(`nl_tab_${message.tabId}`, (result) => {
sendResponse({ links: result[`nl_tab_${message.tabId}`] || [] });
});
return true; // Keep message channel open for async response
}
});
browser.tabs.onRemoved.addListener((tabId) => {
browser.storage.local.remove(`nl_tab_${tabId}`);
});

20
content.js Normal file
View File

@ -0,0 +1,20 @@
document.addEventListener('DOMContentLoaded', function() {
const alternateLinks = document.querySelectorAll('link[rel="alternate"][type="application/nostr+json"]');
if (alternateLinks.length > 0) {
console.debug("[nostr-links] Found:", alternateLinks);
const links = Array.from(alternateLinks).map((link, index) => ({
uri: link.href.replace(/^(nostr|web+nostr):/, ""),
text: link.title.trim()
// icon: "icon.png"
}));
browser.runtime.sendMessage({
action: "showNostrLinksPageAction",
links: links
});
} else {
console.debug("[nostr-links] No nostr links found");
}
});

BIN
icons/nostr-48.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

BIN
icons/nostr-96.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

9
icons/nostr.svg Normal file
View File

@ -0,0 +1,9 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<style>
path { fill: #8e30eb; }
</style>
<path d="M3.03377 4.84648C2.38935 5.60878 1.88639 6.49681 1.5799 7.4713C3.32454 7.07836 5.64286 6.98406 6.95527 6.88189C7.36392 5.20013 8.52701 3.91915 10.476 4.0056C11.3169 4.04489 12.0556 4.58714 12.5664 5.42017C12.9436 5.01937 13.4466 4.75218 14.1146 4.65787C14.1617 4.65787 14.2639 4.65001 14.3425 4.65001C12.9593 3.14114 10.9868 2.18237 8.77849 2.18237C8.3777 2.18237 7.98476 2.22167 7.59183 2.28454C7.51324 2.28454 7.41108 2.30026 7.27748 2.33169C7.26962 2.33169 7.2539 2.33169 7.24604 2.33169C7.23818 2.33169 7.23032 2.33169 7.21461 2.33169C5.69001 2.70105 4.54264 2.40242 3.89037 1.51438C3.81964 1.42008 3.54458 1.00357 3.45814 0.272705C2.97876 0.767805 2.66441 1.58511 2.9316 2.45743C3.14379 3.149 3.54458 3.51836 3.97681 3.73054C3.31668 3.76984 2.76657 3.6441 2.21646 3.22759C1.89425 2.98396 1.68992 2.71677 1.352 2.01734C1.03765 2.51244 1.06909 3.06255 1.13195 3.34547C1.21054 3.72268 1.40701 4.14706 1.65849 4.39068C2.04357 4.76789 2.59368 4.85434 3.04162 4.84648H3.03377Z" />
<path d="M10.4837 11.3458C11.4602 11.3458 12.2519 9.99116 12.2519 8.32016C12.2519 6.64917 11.4602 5.29456 10.4837 5.29456C9.50711 5.29456 8.71545 6.64917 8.71545 8.32016C8.71545 9.99116 9.50711 11.3458 10.4837 11.3458Z" />
<path d="M14.3737 10.615C15.1376 10.615 15.7569 9.53831 15.7569 8.21019C15.7569 6.88207 15.1376 5.80542 14.3737 5.80542C13.6099 5.80542 12.9906 6.88207 12.9906 8.21019C12.9906 9.53831 13.6099 10.615 14.3737 10.615Z" />
<path fill-rule="evenodd" clip-rule="evenodd" d="M7.52542 23.9833C7.53337 23.6314 7.66454 22.5232 8.7864 20.3047C9.2815 19.3381 10.4053 18.0021 11.2462 17.2791C11.6941 16.8862 12.1421 16.5561 12.5822 16.2496C12.8101 16.116 13.0222 15.9745 13.2266 15.8252C16.9076 13.5684 20.157 14.0396 22.8528 14.4306L22.9321 14.4421C22.9321 14.4421 23.5765 12.5246 20.9203 11.5344C19.4743 11 17.7689 10.5677 16.3465 10.2691C16.1422 10.6385 15.8828 10.9528 15.5763 11.1886C15.5721 11.1917 15.5678 11.195 15.5634 11.1983C15.3354 11.3696 14.795 11.7757 13.816 11.6601C13.313 11.5972 12.9279 11.3929 12.6215 11.0943C12.1028 11.9509 11.3562 12.5088 10.4917 12.5874C8.09483 12.7918 6.88458 10.7799 6.806 8.55591C5.00635 8.7288 2.55443 9.83688 1.24988 10.4813L1.25662 22.0396C2.92115 22.6846 5.41819 23.4807 7.52542 23.9833Z" />
</svg>

After

Width:  |  Height:  |  Size: 2.3 KiB

34
manifest.json Normal file
View File

@ -0,0 +1,34 @@
{
"manifest_version": 3,
"name": "Nostr Links",
"version": "1.0.0",
"description": "A web extension to discover Nostr links",
"author": "Râu Cao",
"homepage_url": "https://gitea.kosmos.org/raucao/nostr-links",
"icons": {
"48": "icons/nostr-48.png",
"96": "icons/nostr-96.png"
},
"permissions": [
"storage",
"tabs",
"activeTab"
],
"background": {
"scripts": [
"background.js"
]
},
"content_scripts": [
{
"matches": [ "http://*/*", "https://*/*", "file:///*" ],
"js": ["content.js"],
"run_at": "document_end"
}
],
"page_action": {
"default_icon": "icons/nostr.svg",
"default_title": "Nostr",
"default_popup": "popup/nostr-links.html"
}
}

49
popup/nostr-links.css Normal file
View File

@ -0,0 +1,49 @@
body {
margin: 0;
padding: 0;
font-family: -apple-system, BlinkMacSystemFont, sans-serif;
background-color: #fff;
min-width: 200px;
border: 1px solid #ccc;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
}
.dropdown-menu {
list-style: none;
margin: 0;
padding: 4px 0;
}
.dropdown-menu li {
margin: 0;
padding: 0;
}
.dropdown-menu a {
display: flex;
align-items: center;
padding: 8px 12px;
color: #333;
text-decoration: none;
white-space: nowrap;
transition: background-color 0.1s ease;
}
.dropdown-menu a:hover {
background-color: #f0f0f0;
color: #000;
}
.dropdown-menu a.disabled {
color: #999;
pointer-events: none;
cursor: default;
}
.menu-icon {
display: none;
width: 16px;
height: 16px;
margin-right: 8px;
vertical-align: middle;
}

13
popup/nostr-links.html Normal file
View File

@ -0,0 +1,13 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Nostr Links</title>
<link rel="stylesheet" href="nostr-links.css">
</head>
<body>
<ul class="dropdown-menu" id="link-menu"></ul>
<script src="nostr-links.js"></script>
</body>
</html>

20
popup/nostr-links.js Normal file
View File

@ -0,0 +1,20 @@
browser.tabs.query({ active: true, currentWindow: true }, (tabs) => {
const tabId = tabs[0].id;
browser.runtime.sendMessage({ action: "getNostrLinks", tabId }, (response) => {
const menu = document.getElementById("link-menu");
if (response.links && response.links.length > 0) {
menu.innerHTML = response.links
.map(
(link) => `
<li>
<a href="web+nostr:${link.uri}" target="_blank">
${link.text || "Open on Nostr"}
</a>
</li>
`
)
.join("");
}
});
});