13 changed files with 440 additions and 82 deletions
@ -0,0 +1,44 @@
@@ -0,0 +1,44 @@
|
||||
package nostr |
||||
|
||||
// Standard Nostr event kinds
|
||||
// These are protocol-level constants and should not be configurable
|
||||
const ( |
||||
// KindProfile is kind 0 - user profile/metadata
|
||||
KindProfile = 0 |
||||
|
||||
// KindNote is kind 1 - regular notes/text posts
|
||||
KindNote = 1 |
||||
|
||||
// KindWiki is kind 30818 - wiki pages (NIP-54)
|
||||
KindWiki = 30818 |
||||
|
||||
// KindBlog is kind 30041 - blog articles
|
||||
KindBlog = 30041 |
||||
|
||||
// KindLongform is kind 30023 - longform markdown articles
|
||||
KindLongform = 30023 |
||||
|
||||
// KindIndex is kind 30040 - publication index events (NKBIP-01)
|
||||
KindIndex = 30040 |
||||
|
||||
// KindIssue is kind 1621 - issue events
|
||||
KindIssue = 1621 |
||||
|
||||
// KindRepoAnnouncement is kind 30617 - repository announcement events
|
||||
KindRepoAnnouncement = 30617 |
||||
) |
||||
|
||||
// SupportedWikiKinds returns the list of supported wiki kinds
|
||||
func SupportedWikiKinds() []int { |
||||
return []int{KindWiki} |
||||
} |
||||
|
||||
// SupportedBlogKinds returns the list of supported blog kinds
|
||||
func SupportedBlogKinds() []int { |
||||
return []int{KindBlog} |
||||
} |
||||
|
||||
// SupportedArticleKinds returns all supported article kinds (wiki + blog)
|
||||
func SupportedArticleKinds() []int { |
||||
return []int{KindWiki, KindBlog} |
||||
} |
||||
@ -1,8 +1,6 @@
@@ -1,8 +1,6 @@
|
||||
{ |
||||
"dependencies": { |
||||
"@asciidoctor/core": "^3.0.4" |
||||
}, |
||||
"devDependencies": { |
||||
"lucide": "^0.564.0" |
||||
"@asciidoctor/core": "^3.0.4", |
||||
"marked": "^12.0.0" |
||||
} |
||||
} |
||||
|
||||
@ -0,0 +1,130 @@
@@ -0,0 +1,130 @@
|
||||
{{define "content"}} |
||||
<div class="blog-layout"> |
||||
<!-- Left Sidebar --> |
||||
<aside class="blog-sidebar"> |
||||
<div class="blog-header"> |
||||
<h1 class="blog-title">Articles</h1> |
||||
<p class="blog-description">Longform markdown articles</p> |
||||
<div class="blog-tags"> |
||||
<span class="tag">#articles</span> |
||||
<span class="tag">#longform</span> |
||||
</div> |
||||
</div> |
||||
|
||||
<nav class="blog-nav" aria-label="Articles"> |
||||
<ul class="article-menu"> |
||||
{{range $index, $item := .ArticleItems}} |
||||
<li> |
||||
<a href="#" class="article-link" data-dtag="{{$item.DTag}}" data-index="{{$index}}"{{if eq $index 0}} data-active="true"{{end}}> |
||||
<div class="article-link-title"><span class="icon-inline">{{icon "file-text"}}</span> {{$item.Title}}</div> |
||||
{{if $item.Time}} |
||||
<div class="article-link-meta"> |
||||
<span class="article-date"><span class="icon-inline">{{icon "clock"}}</span> {{$item.Time}}</span> |
||||
{{if $item.Author}} |
||||
<span class="article-author">{{template "user-badge-simple" (dict "Pubkey" $item.Author "Profiles" $.Profiles)}}</span> |
||||
{{end}} |
||||
</div> |
||||
{{end}} |
||||
</a> |
||||
</li> |
||||
{{end}} |
||||
</ul> |
||||
</nav> |
||||
</aside> |
||||
|
||||
<!-- Right Content Pane --> |
||||
<main class="blog-content"> |
||||
{{range $index, $item := .ArticleItems}} |
||||
<article class="blog-article{{if eq $index 0}} active{{end}}" data-dtag="{{$item.DTag}}" id="article-{{$item.DTag}}"> |
||||
<header class="article-header"> |
||||
<h1 class="article-title">{{$item.Title}}</h1> |
||||
<p class="article-subtitle">Longform article</p> |
||||
</header> |
||||
{{if $item.Summary}}<p class="article-summary">{{$item.Summary}}</p>{{end}} |
||||
<div class="article-content"> |
||||
{{$item.Content}} |
||||
</div> |
||||
</article> |
||||
{{else}} |
||||
<article class="blog-article active"> |
||||
<header class="article-header"> |
||||
<h1 class="article-title"><span class="icon-inline">{{icon "file-x"}}</span> No Articles</h1> |
||||
</header> |
||||
<div class="article-content"> |
||||
<p><span class="icon-inline">{{icon "inbox"}}</span> No articles available yet.</p> |
||||
</div> |
||||
</article> |
||||
{{end}} |
||||
</main> |
||||
</div> |
||||
|
||||
<script> |
||||
(function() { |
||||
const articleLinks = document.querySelectorAll('.article-link'); |
||||
const articles = document.querySelectorAll('.blog-article'); |
||||
|
||||
function showArticle(dtag) { |
||||
// Hide all articles |
||||
articles.forEach(article => { |
||||
article.classList.remove('active'); |
||||
}); |
||||
|
||||
// Show selected article |
||||
const targetArticle = document.querySelector(`.blog-article[data-dtag="${dtag}"]`); |
||||
if (targetArticle) { |
||||
targetArticle.classList.add('active'); |
||||
} |
||||
|
||||
// Update active link |
||||
articleLinks.forEach(link => { |
||||
if (link.dataset.dtag === dtag) { |
||||
link.setAttribute('data-active', 'true'); |
||||
} else { |
||||
link.removeAttribute('data-active'); |
||||
} |
||||
}); |
||||
|
||||
// Update URL hash without scrolling |
||||
if (history.pushState) { |
||||
history.pushState(null, null, `#${dtag}`); |
||||
} else { |
||||
window.location.hash = dtag; |
||||
} |
||||
} |
||||
|
||||
// Handle link clicks |
||||
articleLinks.forEach(link => { |
||||
link.addEventListener('click', function(e) { |
||||
e.preventDefault(); |
||||
const dtag = this.dataset.dtag; |
||||
showArticle(dtag); |
||||
}); |
||||
}); |
||||
|
||||
// Handle initial hash on page load |
||||
if (window.location.hash) { |
||||
const hash = window.location.hash.substring(1); |
||||
const targetLink = document.querySelector(`.article-link[data-dtag="${hash}"]`); |
||||
if (targetLink) { |
||||
showArticle(hash); |
||||
} |
||||
} |
||||
|
||||
// Handle browser back/forward |
||||
window.addEventListener('popstate', function() { |
||||
const hash = window.location.hash.substring(1); |
||||
if (hash) { |
||||
showArticle(hash); |
||||
} else { |
||||
// Show first article if no hash |
||||
const firstLink = document.querySelector('.article-link'); |
||||
if (firstLink) { |
||||
showArticle(firstLink.dataset.dtag); |
||||
} |
||||
} |
||||
}); |
||||
})(); |
||||
</script> |
||||
{{end}} |
||||
|
||||
{{/* Feed is defined in components.html */}} |
||||
Loading…
Reference in new issue