Compare commits
5 Commits
28520c59b9
...
3295c6b2cf
| Author | SHA1 | Date | |
|---|---|---|---|
|
3295c6b2cf
|
|||
|
c0a02295c1
|
|||
|
fdb13bc65d
|
|||
|
a0f0b06ad2
|
|||
|
ce469bc37f
|
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1 +1,2 @@
|
||||
.env
|
||||
users.yaml
|
||||
|
||||
@@ -48,6 +48,12 @@ code {
|
||||
padding: 0.1em 0.3em;
|
||||
}
|
||||
|
||||
pre {
|
||||
overflow-x: auto;
|
||||
white-space: pre;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
pre code {
|
||||
display: block;
|
||||
padding: 0.6rem 1rem;
|
||||
@@ -74,6 +80,14 @@ main header {
|
||||
margin-bottom: 3rem;
|
||||
}
|
||||
|
||||
main header .draft-label {
|
||||
display: inline-block;
|
||||
padding: 0.5rem 1rem;
|
||||
border: 1px solid;
|
||||
border-radius: 5px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
main header h1 {
|
||||
margin-bottom: 1.6rem;
|
||||
}
|
||||
@@ -99,7 +113,11 @@ main .article-list .item {
|
||||
}
|
||||
|
||||
main .article-list .item h3 {
|
||||
margin-bottom: 1rem;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
main .article-list p {
|
||||
margin-top: 0.5rem;
|
||||
}
|
||||
|
||||
main article footer {
|
||||
|
||||
@@ -20,6 +20,11 @@ code {
|
||||
color: #027739;
|
||||
}
|
||||
|
||||
pre {
|
||||
background-color: #333;
|
||||
color: #ccc;
|
||||
}
|
||||
|
||||
pre code {
|
||||
background-color: #333;
|
||||
color: #ccc;
|
||||
@@ -29,6 +34,11 @@ dl dt {
|
||||
color: #888;
|
||||
}
|
||||
|
||||
main header .draft-label {
|
||||
color: #770202;
|
||||
border-color: #770202;
|
||||
}
|
||||
|
||||
main header .meta .date {
|
||||
color: #888;
|
||||
}
|
||||
|
||||
11
html.ts
11
html.ts
@@ -40,10 +40,16 @@ export function errorPageHtml(statusCode: number, title: string): string {
|
||||
|
||||
export function articleHtml(article: Article, profile: Profile): string {
|
||||
const publishedAtFormatted = localizeDate(article.publishedAt);
|
||||
const pageTitle = article.isDraft ? `Draft: ${article.title}` : article.title;
|
||||
let draftLabel = ``;
|
||||
if (article.isDraft) {
|
||||
draftLabel = `<p class="draft-label">Draft version</p>`;
|
||||
}
|
||||
|
||||
const body = `
|
||||
<main>
|
||||
<header>
|
||||
${draftLabel}
|
||||
<h1>${article.title}</h1>
|
||||
<div class="meta">
|
||||
<img class="avatar" src="${profile.picture}" alt="User Avatar" />
|
||||
@@ -62,7 +68,7 @@ export function articleHtml(article: Article, profile: Profile): string {
|
||||
</main>
|
||||
`;
|
||||
|
||||
return htmlLayout(article.title, body, profile);
|
||||
return htmlLayout(pageTitle, body, profile);
|
||||
}
|
||||
|
||||
function articleListItemHtml(article: Article): string {
|
||||
@@ -78,9 +84,10 @@ function articleListItemHtml(article: Article): string {
|
||||
|
||||
export function articleListHtml(articles: Article[]): string {
|
||||
if (articles.length === 0) return "";
|
||||
const sortedArticles = articles.sort((a, b) => b.publishedAt - a.publishedAt);
|
||||
let html = "";
|
||||
|
||||
for (const article of articles) {
|
||||
for (const article of sortedArticles) {
|
||||
html += articleListItemHtml(article);
|
||||
}
|
||||
|
||||
|
||||
@@ -15,6 +15,10 @@ export default class Article {
|
||||
return tag ? tag[1] : "";
|
||||
}
|
||||
|
||||
get isDraft(): boolean {
|
||||
return this.event.kind === 30024;
|
||||
}
|
||||
|
||||
get url(): string {
|
||||
return `${config.base_url}/${this.naddr}`;
|
||||
}
|
||||
@@ -47,6 +51,7 @@ export default class Article {
|
||||
identifier: this.identifier,
|
||||
pubkey: this.event.pubkey,
|
||||
kind: this.event.kind,
|
||||
relays: [config.home_relay_url],
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,9 @@ import { nip19 } from "@nostr/tools";
|
||||
import { NEvent } from "../nostr.ts";
|
||||
|
||||
export interface ProfileData {
|
||||
name: string;
|
||||
name?: string;
|
||||
display_name?: string;
|
||||
displayName?: string;
|
||||
about?: string;
|
||||
picture?: string;
|
||||
nip05?: string;
|
||||
|
||||
15
nostr.ts
15
nostr.ts
@@ -17,14 +17,25 @@ export async function fetchReplaceableEvent(
|
||||
pubkey: string,
|
||||
identifier: string,
|
||||
) {
|
||||
const events = await relay.query([{
|
||||
let events = await relay.query([{
|
||||
authors: [pubkey],
|
||||
kinds: [30023],
|
||||
"#d": [identifier],
|
||||
limit: 1,
|
||||
}]);
|
||||
|
||||
return events.length > 0 ? events[0] : null;
|
||||
if (events.length > 0) {
|
||||
return events[0];
|
||||
} else {
|
||||
events = await relay.query([{
|
||||
authors: [pubkey],
|
||||
kinds: [30024],
|
||||
"#d": [identifier],
|
||||
limit: 1,
|
||||
}]);
|
||||
|
||||
return events.length > 0 ? events[0] : null;
|
||||
}
|
||||
}
|
||||
|
||||
export async function fetchArticlesByAuthor(pubkey: string) {
|
||||
|
||||
@@ -20,6 +20,18 @@ describe("Article", () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe("#isDraft", () => {
|
||||
it("is false when kind is 30023", () => {
|
||||
expect(article.isDraft).toBe(false);
|
||||
});
|
||||
|
||||
it("is true when kind is 30024", () => {
|
||||
article.event.kind = 30024;
|
||||
expect(article.isDraft).toBe(true);
|
||||
article.event.kind = 30023;
|
||||
});
|
||||
});
|
||||
|
||||
describe("#title", () => {
|
||||
it("returns the content of the 'title' tag", () => {
|
||||
expect(article.title).toMatch(
|
||||
@@ -53,9 +65,9 @@ describe("Article", () => {
|
||||
});
|
||||
|
||||
describe("#naddr", () => {
|
||||
it("returns bech32 addressable event ID", () => {
|
||||
expect(article.naddr).toEqual(
|
||||
"naddr1qvzqqqr4gupzq8meqkx80g3yuklzymy0qfx2ekk56aqc2ht4ak03z3em4r4cdcwtqqxnzdejxcenjd3hx5urgwp4676hkz",
|
||||
it("returns a bech32 addressable event ID", () => {
|
||||
expect(article.naddr).toMatch(
|
||||
/naddr1qvzqqqr4gupzq8meqkx80g3yuklzymy0qf/,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
_: b3e1b7c0ef48294bd856203bfd460625de95d3afb894e5f09b14cd1f0e7097cf
|
||||
accounts: b3e1b7c1660b7db0ecb93ec55c09e67961171a5c4e9e2602f1b47477ea61c50a
|
||||
4
users.yaml.sample
Normal file
4
users.yaml.sample
Normal file
@@ -0,0 +1,4 @@
|
||||
_: b3e1b7c0ef48294bd856203bfd460625de95d3afb894e5f09b14cd1f0e7097cf
|
||||
accounts: b3e1b7c1660b7db0ecb93ec55c09e67961171a5c4e9e2602f1b47477ea61c50a
|
||||
bitcoincore: 47750177bb6bb113784e4973f6b2e3dd27ef1eff227d6e38d0046d618969e41a
|
||||
# jeffg: 1739d937dc8c0c7370aa27585938c119e25c41f6c441a5d34c6d38503e3136ef
|
||||
Reference in New Issue
Block a user