nostr-blog-widget 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +223 -0
- package/dist/537.nostr-blog.js +2 -0
- package/dist/537.nostr-blog.js.map +1 -0
- package/dist/nostr-blog.css +1156 -0
- package/dist/nostr-blog.css.map +1 -0
- package/dist/nostr-blog.js +3 -0
- package/dist/nostr-blog.js.LICENSE.txt +3 -0
- package/dist/nostr-blog.js.map +1 -0
- package/package.json +54 -0
package/README.md
ADDED
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
# Nostr Blog Widget
|
|
2
|
+
|
|
3
|
+
A drop-in JavaScript widget that transforms any webpage into a Nostr-powered blog. Display long-form articles (kind 30023) and short notes (kind 1) from Nostr with zero backend required.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- 📝 **Dual Content Support**: Display both long-form articles (kind 30023) and short notes (kind 1)
|
|
8
|
+
- 👥 **Multi-Author Support**: Aggregate posts from multiple Nostr authors
|
|
9
|
+
- 🎨 **Three View Modes**: Grid, List, and Compact layouts
|
|
10
|
+
- 🖼️ **Rich Media**: Automatic image and video embedding
|
|
11
|
+
- 🔗 **Nostr Reference Embedding**: Embedded preview cards for referenced Nostr posts (nevent, naddr, note)
|
|
12
|
+
- 🎛️ **Built-in Controls**: Filter by author, content type, date range, and layout
|
|
13
|
+
- 🌓 **Theme Support**: Light, dark, and auto modes
|
|
14
|
+
- 📱 **Responsive Design**: Works on all devices
|
|
15
|
+
- ⚡ **No Backend Required**: Connects directly to Nostr relays
|
|
16
|
+
|
|
17
|
+
## Installation
|
|
18
|
+
|
|
19
|
+
### Via NPM
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
npm install nostr-blog-widget
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Then include in your HTML:
|
|
26
|
+
|
|
27
|
+
```html
|
|
28
|
+
<script src="node_modules/nostr-blog-widget/dist/nostr-blog.js"></script>
|
|
29
|
+
<link rel="stylesheet" href="node_modules/nostr-blog-widget/dist/nostr-blog.css">
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
### Via CDN
|
|
33
|
+
|
|
34
|
+
```html
|
|
35
|
+
<script src="https://unpkg.com/nostr-blog-widget@latest/dist/nostr-blog.js"></script>
|
|
36
|
+
<link rel="stylesheet" href="https://unpkg.com/nostr-blog-widget@latest/dist/nostr-blog.css">
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Quick Start
|
|
40
|
+
|
|
41
|
+
Add this to your HTML:
|
|
42
|
+
|
|
43
|
+
```html
|
|
44
|
+
<!DOCTYPE html>
|
|
45
|
+
<html>
|
|
46
|
+
<head>
|
|
47
|
+
<link rel="stylesheet" href="https://unpkg.com/nostr-blog-widget@latest/dist/nostr-blog.css">
|
|
48
|
+
</head>
|
|
49
|
+
<body>
|
|
50
|
+
<div
|
|
51
|
+
id="nostr-blog"
|
|
52
|
+
data-pubkey='["3bf0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefa459d", "npub1j8y6tcdfw3q3f3h794s6un0gyc5742s0k5h5s2yqj0r70cpklqeqjavrvg", "npub1k7cnst4fh4ajgg8w6ndcmqen4fnyc7ahhm3zpp255vdxqarrtekq5rrg96"]'
|
|
53
|
+
data-relays='["wss://relay.damus.io", "wss://nos.lol"]'
|
|
54
|
+
></div>
|
|
55
|
+
|
|
56
|
+
<script src="https://unpkg.com/nostr-blog-widget@latest/dist/nostr-blog.js"></script>
|
|
57
|
+
</body>
|
|
58
|
+
</html>
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
That's it! Your Nostr blog is live.
|
|
62
|
+
|
|
63
|
+
## Configuration
|
|
64
|
+
|
|
65
|
+
Configure the widget using data attributes:
|
|
66
|
+
|
|
67
|
+
```html
|
|
68
|
+
<div
|
|
69
|
+
id="nostr-blog"
|
|
70
|
+
data-pubkey='["npub1..."]'
|
|
71
|
+
data-relays='["wss://relay.damus.io", "wss://nos.lol"]'
|
|
72
|
+
data-layout="grid"
|
|
73
|
+
data-theme="light"
|
|
74
|
+
data-posts-per-page="10"
|
|
75
|
+
data-show-images="true"
|
|
76
|
+
data-date-format="relative"
|
|
77
|
+
data-content-type="all"
|
|
78
|
+
data-show-controls="true"
|
|
79
|
+
data-pagination="load-more"
|
|
80
|
+
></div>
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
### Available Options
|
|
84
|
+
|
|
85
|
+
| Attribute | Type | Default | Description |
|
|
86
|
+
|-----------|------|---------|-------------|
|
|
87
|
+
| `data-pubkey` | string or array | *required* | Nostr pubkey(s) in hex or npub format |
|
|
88
|
+
| `data-relays` | array | *required* | Array of Nostr relay URLs |
|
|
89
|
+
| `data-layout` | `grid` \| `list` \| `compact` | `grid` | Display layout |
|
|
90
|
+
| `data-theme` | `light` \| `dark` \| `auto` | `light` | Color theme |
|
|
91
|
+
| `data-posts-per-page` | number | `10` | Number of posts to load |
|
|
92
|
+
| `data-show-images` | boolean | `true` | Show post images |
|
|
93
|
+
| `data-date-format` | `short` \| `long` \| `relative` | `relative` | Date display format |
|
|
94
|
+
| `data-content-type` | `all` \| `long-form` \| `short-form` | `all` | Filter by content type |
|
|
95
|
+
| `data-show-controls` | boolean | `true` | Show control panel |
|
|
96
|
+
| `data-pagination` | `infinite-scroll` \| `load-more` \| `none` | `load-more` | Pagination style |
|
|
97
|
+
|
|
98
|
+
## View Modes
|
|
99
|
+
|
|
100
|
+
### Grid View
|
|
101
|
+
Cards displayed in a responsive grid with images, titles, and summaries.
|
|
102
|
+
|
|
103
|
+
### List View
|
|
104
|
+
Full-width cards with complete content preview.
|
|
105
|
+
|
|
106
|
+
### Compact View
|
|
107
|
+
Minimal single-line entries with just date and title - perfect for blog archives.
|
|
108
|
+
|
|
109
|
+
## Content Types
|
|
110
|
+
|
|
111
|
+
### Long-form Articles (kind 30023)
|
|
112
|
+
- Displays title, summary, author, date, and feature image
|
|
113
|
+
- "Read more" button to view full article
|
|
114
|
+
- Full markdown support in article view
|
|
115
|
+
|
|
116
|
+
### Short Notes (kind 1)
|
|
117
|
+
- Shows complete content in grid/list view
|
|
118
|
+
- Automatic media embedding (images and videos)
|
|
119
|
+
- Embedded preview cards for Nostr references
|
|
120
|
+
- No "Read more" button needed
|
|
121
|
+
|
|
122
|
+
## Advanced Usage
|
|
123
|
+
|
|
124
|
+
### Multiple Authors
|
|
125
|
+
|
|
126
|
+
```html
|
|
127
|
+
data-pubkey='["npub1abc...", "npub1def...", "hex-pubkey-123"]'
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
The widget automatically:
|
|
131
|
+
- Fetches posts from all authors
|
|
132
|
+
- Shows author filter dropdown
|
|
133
|
+
- Displays author avatars and names
|
|
134
|
+
|
|
135
|
+
### Custom Styling
|
|
136
|
+
|
|
137
|
+
Override default styles with CSS:
|
|
138
|
+
|
|
139
|
+
```css
|
|
140
|
+
/* Customize colors */
|
|
141
|
+
.nbw-bg-white { background: #f5f5f5 !important; }
|
|
142
|
+
.nbw-text-blue-600 { color: #0066cc !important; }
|
|
143
|
+
|
|
144
|
+
/* Customize card appearance */
|
|
145
|
+
.nbw-rounded-lg { border-radius: 8px !important; }
|
|
146
|
+
.nbw-shadow-md { box-shadow: 0 4px 6px rgba(0,0,0,0.1) !important; }
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
All widget classes are prefixed with `nbw-` to avoid conflicts.
|
|
150
|
+
|
|
151
|
+
### Embedding Options
|
|
152
|
+
|
|
153
|
+
The widget automatically handles:
|
|
154
|
+
- Image URLs (jpg, png, gif, webp, svg)
|
|
155
|
+
- Video URLs (mp4, webm, mov, avi)
|
|
156
|
+
- Nostr references (nevent1, naddr1, note1) - shows embedded post cards
|
|
157
|
+
- Nostr profiles (npub1, nprofile1) - shows clickable links
|
|
158
|
+
|
|
159
|
+
## Examples
|
|
160
|
+
|
|
161
|
+
### Personal Blog
|
|
162
|
+
```html
|
|
163
|
+
<div
|
|
164
|
+
id="nostr-blog"
|
|
165
|
+
data-pubkey="npub1yourpubkey..."
|
|
166
|
+
data-relays='["wss://relay.damus.io"]'
|
|
167
|
+
data-layout="list"
|
|
168
|
+
data-content-type="long-form"
|
|
169
|
+
></div>
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
### Multi-Author Publication
|
|
173
|
+
```html
|
|
174
|
+
<div
|
|
175
|
+
id="nostr-blog"
|
|
176
|
+
data-pubkey='["npub1author1...", "npub1author2..."]'
|
|
177
|
+
data-relays='["wss://relay.damus.io", "wss://nos.lol"]'
|
|
178
|
+
data-layout="grid"
|
|
179
|
+
data-show-controls="true"
|
|
180
|
+
></div>
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
### Compact Archive
|
|
184
|
+
```html
|
|
185
|
+
<div
|
|
186
|
+
id="nostr-blog"
|
|
187
|
+
data-pubkey="npub1yourpubkey..."
|
|
188
|
+
data-relays='["wss://relay.damus.io"]'
|
|
189
|
+
data-layout="compact"
|
|
190
|
+
data-show-controls="false"
|
|
191
|
+
data-posts-per-page="50"
|
|
192
|
+
></div>
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
## Browser Support
|
|
196
|
+
|
|
197
|
+
- Chrome/Edge: ✅
|
|
198
|
+
- Firefox: ✅
|
|
199
|
+
- Safari: ✅
|
|
200
|
+
- Mobile browsers: ✅
|
|
201
|
+
|
|
202
|
+
## Technical Details
|
|
203
|
+
|
|
204
|
+
- Built with [SolidJS](https://www.solidjs.com/) for reactive UI
|
|
205
|
+
- Uses [nostr-tools](https://github.com/nbd-wtf/nostr-tools) for Nostr protocol
|
|
206
|
+
- Styled with [TailwindCSS](https://tailwindcss.com/)
|
|
207
|
+
- Markdown rendering via [marked](https://marked.js.org/)
|
|
208
|
+
|
|
209
|
+
## License
|
|
210
|
+
|
|
211
|
+
MIT
|
|
212
|
+
|
|
213
|
+
## Contributing
|
|
214
|
+
|
|
215
|
+
Issues and pull requests welcome at [github.com/bigmarh/nostr-blog-widget](https://github.com/bigmarh/nostr-blog-widget)
|
|
216
|
+
|
|
217
|
+
## Author
|
|
218
|
+
|
|
219
|
+
Created by [Lamar Wilson](https://lamarwilson.com)
|
|
220
|
+
|
|
221
|
+
## Support
|
|
222
|
+
|
|
223
|
+
- GitHub Issues: [Report bugs](https://github.com/bigmarh/nostr-blog-widget/issues)
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use strict";(this.webpackChunkNostrBlog=this.webpackChunkNostrBlog||[]).push([[537],{537(n,r,e){e.d(r,{Navigation:()=>s});var t=e(35),b=e(701),o=(0,t.vs)('<nav class=nbw-space-y-2><a href=#/ class="nbw-block nbw-px-4 nbw-py-2 nbw-rounded nbw-transition-colors hover:nbw-bg-gray-100 nbw-text-gray-900 nbw-no-underline">Home</a><div class="nbw-border-t nbw-border-gray-200 nbw-my-2">'),a=(0,t.vs)('<a class="nbw-block nbw-px-4 nbw-py-2 nbw-rounded nbw-transition-colors hover:nbw-bg-gray-100 nbw-text-gray-700 nbw-no-underline nbw-text-sm">');const s=n=>{return r=o(),(e=r.firstChild).nextSibling,e.$$click=r=>{r.preventDefault(),n.onHome()},(0,t.Yr)(r,(0,b.a0)(b.a,{get each(){return n.posts},children:r=>{return(e=a()).$$click=e=>{e.preventDefault(),n.onNavigate(r.id)},(0,t.Yr)(e,()=>r.title),(0,b.gb)(b=>{var o=`#/post/${r.id}`,a={"nbw-bg-gray-200 nbw-font-semibold":n.currentPostId===r.id};return o!==b.e&&(0,t.Bq)(e,"href",b.e=o),b.t=(0,t.pP)(e,a,b.t),b},{e:void 0,t:void 0}),e;var e}}),null),(0,b.gb)(r=>(0,t.pP)(e,{"nbw-bg-gray-200 nbw-font-semibold":!n.currentPostId},r)),r;var r,e};(0,t.z_)(["click"])}}]);
|
|
2
|
+
//# sourceMappingURL=537.nostr-blog.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"537.nostr-blog.js","mappings":"8hBAUO,MAAMA,EAA0CC,IACrD,oDAMgBC,IACRA,EAAEC,iBACFF,EAAMG,WACP,mBAKF,IAAG,SAACC,GAAI,OAAEJ,EAAMK,KAAK,WAClBC,IAAI,sBAKQL,IACRA,EAAEC,iBACFF,EAAMO,WAAWD,EAAKE,MACvB,cAEAF,EAAKG,QAAK,kBARL,UAAUH,EAAKE,KAAI,EAEd,CAAE,oCAAqCR,EAAMU,gBAAkBJ,EAAKE,IAAI,yFAJjF,SAYL,6BAtBU,CAAE,qCAAsCR,EAAMU,eAAe,MALvE,IAAP,MA+BA,kB","sources":["webpack://NostrBlog/./src/components/Navigation.tsx"],"sourcesContent":["import { Component, For } from 'solid-js';\nimport { BlogPost } from '../types/config';\n\ninterface NavigationProps {\n posts: BlogPost[];\n currentPostId?: string;\n onNavigate: (postId: string) => void;\n onHome: () => void;\n}\n\nexport const Navigation: Component<NavigationProps> = (props) => {\n return (\n <nav class=\"nbw-space-y-2\">\n <a\n href=\"#/\"\n class=\"nbw-block nbw-px-4 nbw-py-2 nbw-rounded nbw-transition-colors hover:nbw-bg-gray-100 nbw-text-gray-900 nbw-no-underline\"\n classList={{ 'nbw-bg-gray-200 nbw-font-semibold': !props.currentPostId }}\n onClick={(e) => {\n e.preventDefault();\n props.onHome();\n }}\n >\n Home\n </a>\n <div class=\"nbw-border-t nbw-border-gray-200 nbw-my-2\"></div>\n <For each={props.posts}>\n {(post) => (\n <a\n href={`#/post/${post.id}`}\n class=\"nbw-block nbw-px-4 nbw-py-2 nbw-rounded nbw-transition-colors hover:nbw-bg-gray-100 nbw-text-gray-700 nbw-no-underline nbw-text-sm\"\n classList={{ 'nbw-bg-gray-200 nbw-font-semibold': props.currentPostId === post.id }}\n onClick={(e) => {\n e.preventDefault();\n props.onNavigate(post.id);\n }}\n >\n {post.title}\n </a>\n )}\n </For>\n </nav>\n );\n};\n"],"names":["Navigation","props","e","preventDefault","onHome","each","posts","post","onNavigate","id","title","currentPostId"],"ignoreList":[],"sourceRoot":""}
|