| 1 | {{define "home" }}<section id="identity" > |
| 2 | <header>{{if .Policy.Icon}}<img alt="" src="{{.Policy.Icon}}" >{{end}}<h1>{{or .Policy.Name .Slug}}</h1><small><code>{{.URL}}</code> | {{template "nostrKey" .Identity}}</small></header> |
| 3 | <table id="facts" > |
| 4 | {{if .Policy.Contact}}<tr><th>contact</th><td>{{.Policy.Contact}}</td></tr>{{end}} |
| 5 | {{if .Policy.Tags}}<tr><th>tags</th><td id="tags" >{{range .Policy.Tags}}<a href="/search?q={{urlquery .}}" >#{{.}}</a>{{end}}</td></tr>{{end}} |
| 6 | {{if .Policy.LanguageTags}}<tr><th>languages</th><td>{{join .Policy.LanguageTags ", " }}</td></tr>{{end}} |
| 7 | {{if .Policy.RelayCountries}}<tr><th>countries</th><td>{{join .Policy.RelayCountries ", " }}</td></tr>{{end}} |
| 8 | <tr><th>policies</th><td>{{if .Policy.PostingPolicy}}<a href="{{.Policy.PostingPolicy}}" >posting</a> | {{end}}{{if .Policy.PrivacyPolicy}}<a href="{{.Policy.PrivacyPolicy}}" >privacy</a> | {{end}}<a href="/terms" >terms</a></td></tr> |
| 9 | <tr><th>reads</th><td>{{.Policy.Reads}}</td></tr> |
| 10 | <tr><th>writes</th><td>{{.Policy.Writes}}</td></tr> |
| 11 | </table> |
| 12 | {{if .Policy.Description}}<h2>About</h2> |
| 13 | {{markdown .Policy.Description}} |
| 14 | {{end}}{{if .Connections}}<h2>Connect</h2> |
| 15 | <p>Open this relay in an app. Each card is a way in; sign in to see the ones made for members.</p> |
| 16 | {{range .Connections}}{{$c := asMap .}}<connect-card> |
| 17 | <h3>{{str (index $c "title" )}} <small>{{str (index $c "app" )}}{{with str (index $c "where" )}}, {{.}}{{end}}{{if ne (str (index $c "visibility" )) "public" }} | {{str (index $c "visibility" )}}{{end}}</small></h3> |
| 18 | <p>{{str (index $c "about" )}}</p> |
| 19 | {{range index $c "inputs" }}{{$i := asMap .}}<label>{{str (index $i "Label" )}} <input name="{{str (index $i " Name")}}" placeholder="{{str (index $i " Placeholder")}}" pattern="{{str (index $i " Pattern")}}" ></label> |
| 20 | {{end}}<p>{{range index $c "links" }}{{$l := asMap .}}{{if str (index $l "href" )}}<a href="{{str (index $l " href")}}" >{{str (index $l "label" )}}</a> {{else}}<button type="button" data-copy="{{str (index $l " copy")}}" >{{str (index $l "label" )}}</button> {{end}}{{end}}{{if index $c "hidden" }}<small>sign in for {{str (index $c "hidden" )}} more</small>{{end}}<output role="status" ></output></p> |
| 21 | {{with str (index $c "qr" )}}<details><summary>QR code</summary><img src="/qr.svg?text={{urlquery .}}" alt="QR code" width="200" height="200" ></details>{{end}} |
| 22 | </connect-card> |
| 23 | {{end}}{{end}} |
| 24 | </section> |
| 25 | {{end}} |
| 26 | |
| 27 | {{define "signin" }}<section id="signin" > |
| 28 | <h1>{{if and .Actor (.Query.Get "connect" )}}Connect your signer{{else if .Actor}}Your account{{else}}Sign in{{end}}</h1> |
| 29 | {{if .Notice}}<p role="status" >{{.Notice}}</p>{{end}} |
| 30 | {{if .Actor}}<p>Signed in as {{template "nostrKey" .Actor}}.</p> |
| 31 | <p><a href="/account" >Open your account</a> | <a href="/chat" >Chat</a></p> |
| 32 | {{if not (.Query.Get "connect" )}}<p><a href="/signin?connect=1{{with .Query.Get " next"}}&next={{urlquery .}}{{end}}" >Connect a signer</a> to restore signing without signing out.</p>{{end}} |
| 33 | {{if .Query.Get "connect" }}<p>Connect the signer for this account. Your sign-in session stays active.</p>{{template "signerControls" .}}{{else}}<p>Open Menu on a phone, or use the desktop footer, to sign out.</p>{{end}} |
| 34 | {{else}}<p>Use a browser extension, or connect Amber on your phone. The relay never sees a private key.</p> |
| 35 | {{template "signerControls" .}} |
| 36 | {{end}}</section> |
| 37 | {{end}} |
| 38 | |
| 39 | {{define "account" }}<section id="account" > |
| 40 | <h1>Account</h1> |
| 41 | <p>Manage your profile, chat preferences and relay lists.</p> |
| 42 | <table id="account-identity" ><tbody><tr><th>signed in as</th><td>{{template "nostrName" .Actor}}</td></tr><tr><th>profile</th><td><a href="/profile" >Edit your profile</a></td></tr></tbody></table> |
| 43 | <h2>Chat preferences</h2> |
| 44 | <chat-preferences actor="{{.Actor}}" ><label><input type="checkbox" name="share_presence" {{if .SharePresence}} checked{{end}} disabled> Share presence and typing</label><p>Show when you are online or typing in chat.</p><output role="status" ></output></chat-preferences><noscript><p>Changing preferences requires JavaScript and a connected signer.</p></noscript> |
| 45 | <h2>Your relay lists</h2> |
| 46 | <p>Choose where other Nostr clients find your notes, messages and files. Existing entries stay.</p> |
| 47 | <relay-lists relay="{{wsURL .URL}}" server="{{.URL}}" pubkey="{{.Actor}}" > |
| 48 | <table id="rows" ><tbody> |
| 49 | <tr data-kind="10002" data-tag="r" ><td>Relay list <small>NIP-65</small></td><td>where clients read your notes and send you mentions</td><td><button type="button" name="check" >check</button> <button type="button" name="add" >add this relay</button></td></tr> |
| 50 | <tr data-kind="10050" data-tag="relay" ><td>DM inbox <small>NIP-17</small></td><td>where people send you private messages</td><td><button type="button" name="check" >check</button> <button type="button" name="add" >add this relay</button></td></tr> |
| 51 | <tr data-kind="10007" data-tag="relay" ><td>Search relays <small>NIP-51</small></td><td>where clients run your searches</td><td><button type="button" name="check" >check</button> <button type="button" name="add" >add this relay</button></td></tr> |
| 52 | <tr data-kind="10063" data-tag="server" data-value="server" ><td>Blossom servers <small>BUD-03</small></td><td>where clients upload and look for your files</td><td><button type="button" name="check" >check</button> <button type="button" name="add" >add this relay</button></td></tr> |
| 53 | </tbody></table><output role="status" ></output></relay-lists> |
| 54 | </section>{{end}} |
| 55 | |
| 56 | {{define "signerControls" }}<p><button id="session-login" type="button" >{{if .Actor}}Use connected signer{{else}}Sign in with connected signer{{end}}</button></p> |
| 57 | <h2>Phone signer</h2> |
| 58 | <p>Scan the QR code with Amber and approve the connection and sign-in request. You will return to the page you opened.</p> |
| 59 | <p><label><input type="checkbox" id="remember-signer" > Remember this device</label> <small>Keeps the phone signer connected after the app closes. Sign out to forget it.</small></p> |
| 60 | <p><button id="nostrconnect" type="button" >Generate QR code</button> <a id="nostrconnect-open" hidden>Open in signer</a></p> |
| 61 | <img id="signer-qr" alt="Nostr Connect QR code" hidden width="240" height="240" > |
| 62 | <p id="signer-status" role="status" ></p> |
| 63 | <h2>Bunker URL</h2> |
| 64 | <form id="bunker" > |
| 65 | <label>Paste from your signer <input id="bunker-url" type="url" placeholder="bunker://…" required></label> |
| 66 | <button>Connect remote signer</button> |
| 67 | </form> |
| 68 | {{end}} |
| 69 | |
| 70 | {{define "inbox" }}<section> |
| 71 | <h1>Inbox</h1> |
| 72 | <p>Events addressed to this signed-in key, subject to the same private-event gates as websocket queries.</p> |
| 73 | {{if .Error}}{{template "alert" .Error}}{{else}}{{template "eventList" .}}{{end}} |
| 74 | </section> |
| 75 | {{end}} |
| 76 | |
| 77 | {{define "outbox" }}<section> |
| 78 | <h1>Outbox</h1> |
| 79 | <p>Events authored by this signed-in key.</p> |
| 80 | {{if .Error}}{{template "alert" .Error}}{{else}}{{template "eventList" .}}{{end}} |
| 81 | </section> |
| 82 | {{end}} |
| 83 | |
| 84 | {{define "search" }}<section> |
| 85 | <h1>Search</h1> |
| 86 | <form id="search" action="/search" method="get" > |
| 87 | <label>Terms <input name="q" type="search" value="{{.Query.Get " q"}}" required></label> |
| 88 | <input type="hidden" name="kinds" value="{{.Query.Get " kinds"}}" ><input type="hidden" name="author" value="{{.Query.Get " author"}}" ><input type="hidden" name="since" value="{{.Query.Get " since"}}" > |
| 89 | <button>Search</button> |
| 90 | </form> |
| 91 | {{if .Error}}{{template "alert" .Error}} |
| 92 | {{else if .Feed}}<h2>Results</h2> |
| 93 | {{template "eventList" .}} |
| 94 | {{else if .Query.Get "q" }}<p>No matching events.</p> |
| 95 | {{end}}</section> |
| 96 | {{end}} |
| 97 | |
| 98 | {{define "articles" }}<section> |
| 99 | <h1>Articles</h1> |
| 100 | <p>Long-form NIP-23 events published on this relay.</p> |
| 101 | {{if .Error}}{{template "alert" .Error}}{{else}}{{template "eventList" .}}{{end}} |
| 102 | <p><a href="/feed.xml" >Atom feed</a> | <a href="/articles.json" >JSON feed</a></p> |
| 103 | </section> |
| 104 | {{end}} |
| 105 | |
| 106 | {{define "event" }}<section> |
| 107 | <h1>Event</h1> |
| 108 | {{if .Feed}}{{template "eventList" .}}{{else}}{{template "nostrEvent" .Event}}<share-link></share-link>{{end}} |
| 109 | <p><a href="/feed.xml" >Atom feed</a> | <a href="/articles.json" >JSON feed</a></p> |
| 110 | </section> |
| 111 | {{end}} |
| 112 | |
| 113 | {{define "view" }}<section> |
| 114 | <h1>View: {{.View}}</h1> |
| 115 | {{template "jsonView" .Event}} |
| 116 | </section> |
| 117 | {{end}} |
| 118 | |
| 119 | {{define "invite" }}<section> |
| 120 | <h1>Join this relay</h1> |
| 121 | <p>This invite is claimed with one signature from your Nostr signer. The relay never receives a private key.</p> |
| 122 | {{if .Policy.JoinTerms}}<h2>Before you join</h2> |
| 123 | <pre>{{.Policy.JoinTerms}}</pre> |
| 124 | {{end}}<rpc-form method="claiminvite" action="/api/invites/claim" terms="{{.Policy.JoinTerms}}" > |
| 125 | <input type="hidden" name="param" value="{{.Invite}}" > |
| 126 | {{if .Policy.JoinTerms}}<label><input type="checkbox" name="termsAgreement" required> I agree to these relay terms.</label> |
| 127 | {{end}}<button>Join relay</button> |
| 128 | </rpc-form> |
| 129 | </section> |
| 130 | {{end}} |
| 131 | |
| 132 | {{define "terms" }}<section> |
| 133 | <h1>Terms</h1> |
| 134 | {{if .Policy.JoinTerms}}{{markdown .Policy.JoinTerms}}{{else}}<p>This relay has not published terms.</p>{{end}} |
| 135 | </section> |
| 136 | {{end}} |
| 137 | |
| 138 | {{define "private" }}<section> |
| 139 | <h1>Private messages</h1> |
| 140 | <p>Sign in with a Nostr client to view addressed private events.</p> |
| 141 | </section> |
| 142 | {{end}} |
| 143 | |
| 144 | {{define "media" }}<section> |
| 145 | <h1>Media</h1> |
| 146 | <p>Blossom uploads and NIP-96 metadata are available from compatible clients.</p> |
| 147 | </section> |
| 148 | {{end}} |
| 149 | |
| 150 | {{define "marmot" }}<section> |
| 151 | <h1>Marmot</h1> |
| 152 | <p>Marmot group state is served when the feature is enabled.</p> |
| 153 | </section> |
| 154 | {{end}} |
| 155 | |
| 156 | {{define "grasp" }}<section> |
| 157 | <h1>GRASP</h1> |
| 158 | <p>Repository state and relay capabilities are served through the GRASP endpoints.</p> |
| 159 | </section> |
| 160 | {{end}} |