custom done

This commit is contained in:
Lone 2025-03-13 14:11:09 +00:00
parent c840f93df6
commit 0ba44f679d
11 changed files with 222 additions and 1312 deletions

1247
bun.lock

File diff suppressed because it is too large Load Diff

1
dist/assets/index-B-iQgq6W.css vendored Normal file

File diff suppressed because one or more lines are too long

58
dist/assets/index-BZYRh09w.js vendored Normal file

File diff suppressed because one or more lines are too long

1
dist/extension.svg vendored Normal file
View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="512" height="512" viewBox="0 0 512 512"><path fill="currentColor" d="M412.5 22.17c-.6 0-1.2.1-1.7.1c-9 .72-15.4 5.89-16.2 8.96c-2.1 7.02-3.6 16.36-2.2 22.82s3.4 10.34 14.2 12.22c16.6 2.88 35.4-.64 51.8-6.43c13-4.61 24.2-10.62 31.3-15.14c-.4-.67-.8-1.27-1.4-1.78c-1.5-1.26-4.3-2.53-8.6-3.31c-8.7-1.57-22.2-.88-36-1.57l-4.3-.22l-2.5-3.5c-6.2-8.57-14.6-11.93-22.7-12.14h-1.7zm-14 60.61c-3.9 10.17-4.5 20.22-2.8 29.52c2.2 12.2 9.5 22.1 13.6 32.9c14 36.6.8 45.4-20.8 51.1c22.3 20 33.3 44.4 35 68.3c30-45.7 35.3-86.2 1.3-128.6c-6.7-8.3-9.9-18.2-11.4-26.8c-1.5-7.9-.8-15.35 3.7-23.91c-4.5-.11-9-.51-13.5-1.29c-1.8-.31-3.4-.72-5.1-1.22M108.4 126.9c-29.04-.2-53.3 25.3-56.66 60c10.56-10.7 25.02-17.7 46.11-17.2c-20.2 13.7-33.69 29.2-44.34 45.3c1.77 8.2 4.64 16.5 8.8 24.9c38.09-52.5 60.99-29.6 72.69.1c10.8-20 27.4-36 47-48.1c-21.4-46.4-49.2-64.8-73.6-65m180.2 55c-3.4 0-6.9 0-10.4.2c-12.4.5-25 2.2-37.3 5.1c-46.3 11-86.3 38-97.9 81.1c22.2 7.6 40.7 16.4 56.7 25.4c31.6 4.7 63.8 3.2 91.4-2.5c38.5-8 67-25.4 73.3-39.7l16.4 7.2c-11 25.4-44.7 41.6-86 50.1c-19 4-39.9 6-61.3 5.7c4.3 2.8 8.4 5.5 12.4 8.1c27.1 17.6 48.4 29.7 82.6 28c35.6-2.9 62.6-25.9 72.9-54.6c10.2-28.7 4.4-62.5-28.7-89.5c-19.2-15.8-50.6-24.4-84.1-24.6m-92.5 130.4c-4.4 8.8-8.1 18-10.6 26.2c-18.6 8.8-25 12.1-34.8 33.2c-35.5 15.3-50.4 38.2-61.34 71.5c-22.48 6.1-40.85 5-63.06-9.9c-12.14 16.1 6.05 30.4 22.64 36.9c21.16 8.3 50.31 2.8 55.46-7.2c16.5-32.5 31.1-54.7 61.7-77c13.1-1.4 22.4-2.4 34.3-18c21.6 2.2 39.3-8 55-18.1c7.8 17.9 23.5 41.8 20.7 58.9c-11.8 9.5-8 21.3-8.3 24.1c6 17.9 66.2-5.8 108 18c22.4 12.8 27.9 44.9 69.4 37.9c6.8-1.1 5.3-7.2.6-8.9c-37.4-13.7-27.6-21-44.8-48.1c-32-.8-59.3-5.2-95.4-16.1c-10.4-3 3.2-24.8 13.3-47c-33.4-.9-57.8-14.7-82.9-31c-12.4-8.1-25.2-16.8-39.9-25.4"/></svg>

After

Width:  |  Height:  |  Size: 1.8 KiB

File diff suppressed because one or more lines are too long

1
dist/index-nip.js vendored
View File

@ -1 +0,0 @@
var c=void 0;export{c as default};

14
dist/index.html vendored Normal file
View File

@ -0,0 +1,14 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/extension.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Kunkun Nostr Open Specific NIP</title>
<script type="module" crossorigin src="/assets/index-BZYRh09w.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-B-iQgq6W.css">
</head>
<body>
<div id="root"></div>
</body>
</html>

View File

@ -14,10 +14,10 @@
"permission": "open:url",
"allow": [
{
"url": "https://github.com/nostr-protocol/nips"
"url": "https://github.com/**"
},
{
"url": "https://nips.nostr.com/"
"url": "https://nips.nostr.com/**"
}
]
}
@ -28,14 +28,14 @@
"value": "majesticons:open"
},
"customUiCmds": [
{
{
"main": "/index-nip.js",
"dist": "dist",
"devMain": "http://localhost:5173",
"name": "Nostr Open Specific NIP",
"cmds": []
}
],
],
"headlessCmds": [
{
"name": "Nostr Open NIP Repository (github.com)",
@ -56,11 +56,12 @@
"build:nip": "vite build"
},
"dependencies": {
"@iconify/react": "^5.2.0",
"@kksh/api": "0.1.5",
"@kksh/react": "0.1.1",
"@radix-ui/react-icons": "^1.3.0",
"preact": "^10.19.6",
"i18next": "^23.15.1"
"i18next": "^23.15.1",
"preact": "^10.19.6"
},
"devDependencies": {
"@types/bun": "latest",

View File

@ -1,10 +1,10 @@
import { expose, HeadlessCommand } from "@kksh/api/headless"
import { open } from "@kksh/api/headless";
class NostrOpenNipRepoNostrCom extends HeadlessCommand {
class NostrOpenNipRepoGithub extends HeadlessCommand {
async load() {
return open.url("https://nips.nostr.com/")
return open.url("https://github.com/nostr-protocol/nips")
}
}
expose(new NostrOpenNipRepoNostrCom())
expose(new NostrOpenNipRepoGithub())

View File

@ -1,44 +1,103 @@
import { render } from "preact"
import { render, Fragment } from "preact"
import { useEffect, useRef, useState } from "preact/hooks"
import { ui } from "@kksh/api/ui/custom"
import { ui, open } from "@kksh/api/ui/custom"
import { Button } from "@kksh/react"
import { Icon } from "@iconify/react";
import {
ActionPanel,
Button,
Command,
CommandEmpty,
CommandFooter,
CommandGroup,
CommandInput,
CommandItem,
CommandList,
CommandSeparator,
CommandShortcut,
ThemeProvider,
VertifcalSeparator
ThemeProvider
} from "@kksh/react"
import {
GearIcon
OpenInNewWindowIcon,
GitHubLogoIcon,
} from "@radix-ui/react-icons"
import "./index.css"
const App = () => {
const [value, setValue] = useState("linear")
const actionInputRef = useRef<HTMLInputElement | null>(null)
const [input, setInput] = useState("")
const listRef = useRef(null)
const seachInputEle = useRef<HTMLInputElement | null>(null)
// Function to fetch NIPs from GitHub
async function fetchNostrNips() {
try {
// Fetch the README.md file from the repository
const response = await fetch('https://api.github.com/repos/nostr-protocol/nips/contents/README.md');
const fileData = await response.json();
// Decode content from base64
const content = atob(fileData.content);
// Regular expression to match NIP entries in the list
// Format is like: - [NIP-01: Basic protocol flow description](01.md)
const nipRegex = /\- \[NIP-(\d+)\: (.*?)\]\((\d+\.md)\)/g;
const nips = [];
let match;
// Find all matches in the content
while ((match = nipRegex.exec(content)) !== null) {
const nipNumber = match[1].padStart(2, '0'); // Pad to ensure consistent format like "01"
const nipNumberNoPad = parseInt(nipNumber); // remove leading zeros
const title = <Fragment>{match[2].split(/`([^`]+)`/).map((part, i) =>
i % 2 === 0 ? part : <code className="bg-gray-100 dark:bg-gray-800 rounded px-1.5 py-0.5" key={i}>{part}</code>
)}</Fragment>;
useEffect(() => {
const filename = match[3];
nips.push({
nip: nipNumber,
title: title,
rawTitle: match[2],
urlGithub: `https://github.com/nostr-protocol/nips/blob/master/${filename}`,
urlNostrCom: `https://nips.nostr.com/${nipNumberNoPad}`,
// We're not fetching full content anymore, but we need to provide a placeholder
// for the filtering function that uses content
content: `NIP-${nipNumber}: ${title}`
});
}
// Sort NIPs by number
return nips.sort((a, b) => parseInt(a.nip) - parseInt(b.nip));
} catch (error) {
console.error('Error fetching NIPs:', error);
return [];
}
}
const App = () => {
const [input, setInput] = useState("")
const seachInputEle = useRef(null)
const [nips, setNips] = useState([])
const [loading, setLoading] = useState(false)
useEffect(() => {
ui.registerDragRegion()
ui.showMoveButton({
bottom: 0.2,
left: 0.2
})
// Fetch NIPs when component mounts
const loadNips = async () => {
setLoading(true)
try {
const fetchedNips = await fetchNostrNips()
setNips(fetchedNips)
} catch (error) {
console.error('Failed to load NIPs:', error)
} finally {
setLoading(false)
}
}
loadNips()
}, [])
function onKeyDown(e) {
function onKeyDown(e) {
if (e.key === "Escape") {
if (input.length === 0) {
ui.goBack()
@ -48,10 +107,19 @@ const App = () => {
}
}
return (
<ThemeProvider>
// Filter NIPs based on input
const filteredNips = input
? nips.filter(nip =>
nip.rawTitle.toLowerCase().includes(input.toLowerCase()) ||
nip.nip.includes(input) ||
nip.content.toLowerCase().includes(input.toLowerCase())
)
: nips
return (
<ThemeProvider>
<main className="h-screen">
<Command
<Command
onValueChange={(v) => {
setValue(v)
}}
@ -59,8 +127,8 @@ const App = () => {
<CommandInput
autoFocus
ref={seachInputEle}
placeholder="Type a command or search..."
className="h-12"
placeholder="Search NIPs by number or title..."
style={{height: '3.25rem'}}
onInput={(e) => {
setInput(e.target.value)
}}
@ -70,38 +138,53 @@ const App = () => {
<div className="h-8 w-8"></div>
</CommandInput>
<CommandList className="h-full">
<CommandEmpty>No results found.</CommandEmpty>
<CommandGroup heading="Suggestions">
<CommandItem>
<GearIcon className="mr-2 h-4 w-4" />
<span>Twitter</span>
</CommandItem>
<CommandItem>
<GearIcon className="mr-2 h-4 w-4" />
<span>Instagram</span>
</CommandItem>
<CommandItem>
<GearIcon className="mr-2 h-4 w-4" />
<span>LinkedIn</span>
</CommandItem>
<CommandItem>
<GearIcon className="mr-2 h-4 w-4" />
<span>Calendar</span>
</CommandItem>
<CommandItem>
<GearIcon className="mr-2 h-4 w-4" />
<span>Search Emoji</span>
</CommandItem>
<CommandItem>
<GearIcon className="mr-2 h-4 w-4" />
<span>Launch</span>
</CommandItem>
</CommandGroup>
{loading ? (
<div className="p-4 text-center">Loading NIPs...</div>
) : (
<Fragment>
<CommandEmpty>No NIPs found.</CommandEmpty>
<CommandGroup heading="Nostr Implementation Possibilities">
{filteredNips.map((nip) => (
<CommandItem
key={nip.nip}
>
<div className="flex items-center justify-between w-full">
<div className="truncate">
<span className="font-bold">NIP-{nip.nip}</span>: {nip.title}
</div>
<div className="flex space-x-2 ml-2">
<Button
style={{padding: '.1em .4em'}}
onClick={(e) => {
e.stopPropagation();
open.url(nip.urlNostrCom);
}}
title="Open on nips.nostr.com"
>
<Icon icon="game-icons:ostrich" width="20" height="20" />
</Button>
<Button
style={{padding: '.1em .4em'}}
onClick={(e) => {
e.stopPropagation();
open.url(nip.urlGithub);
}}
title="Open on GitHub"
>
<Icon icon="mdi:github" width="20" height="20" />
</Button>
</div>
</div>
</CommandItem>
))}
</CommandGroup>
</Fragment>
)}
</CommandList>
</Command>
</main>
</ThemeProvider>
)
</main>
</ThemeProvider>
)
}
render(<App />, document.getElementById("root"))

0
src/index-nip.ts Normal file
View File