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</table>10{{if .Policy.Description}}<h2>About</h2>11{{markdown .Policy.Description}}12{{end}}{{if .Connections}}<h2>Connect</h2>13<p>Open this relay in an app.</p>14{{range .Connections}}{{$c := asMap .}}<connect-card>15<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>16<p>{{str (index $c "about")}}</p>17{{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>18{{end}}<p>{{range index $c "links"}}{{$l := asMap .}}{{if str (index $l "href")}}<a href="{{safeURL (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>19{{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}}20</connect-card>21{{end}}{{end}}22</section>23{{end}}2425{{define "signin"}}<section id="signin">26<h1>{{if and .Actor (.Query.Get "connect")}}Connect your signer{{else if .Actor}}Your account{{else}}Sign in{{end}}</h1>27{{if .Notice}}<p role="status">{{.Notice}}</p>{{end}}28{{if .Actor}}<p>Signed in as {{template "nostrKey" .Actor}}.</p>29<p><a href="/account">Open your account</a> | <a href="/chat">Chat</a></p>30{{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}}31{{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}}32{{else}}<p>Use a browser extension, or connect Amber on your phone. The relay never sees a private key.</p>33{{template "signerControls" .}}34{{end}}</section>35{{end}}3637{{define "account"}}<section id="account">38<h1>Account</h1>39<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>40<h2>Chat preferences</h2>41<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>42<h2>Your relay lists</h2>43<p>Where other clients find your notes, messages and files.</p>44<relay-lists relay="{{wsURL .URL}}" server="{{.URL}}" pubkey="{{.Actor}}">45<table id="rows"><tbody>46<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>47<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>48<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>49<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>50</tbody></table><output role="status"></output></relay-lists>51</section>{{end}}5253{{define "signerControls"}}<p><button id="session-login" type="button" data-primary>{{if .Actor}}Use connected signer{{else}}Sign in with connected signer{{end}}</button></p>54<h2>Phone signer</h2>55<p>Scan the QR code with Amber and approve the connection and sign-in request. You will return to the page you opened.</p>56<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>57<p><button id="nostrconnect" type="button">Generate QR code</button> <a id="nostrconnect-open" hidden>Open in signer</a></p>58<img id="signer-qr" alt="Nostr Connect QR code" hidden width="240" height="240">59<p id="signer-status" role="status"></p>60<h2>Bunker URL</h2>61<form id="bunker">62<label>Paste from your signer <input id="bunker-url" type="url" placeholder="bunker://…" required></label>63<button>Connect remote signer</button>64</form>65{{end}}6667{{define "inbox"}}<section>68<h1>Inbox</h1>69{{if .Error}}{{template "alert" .Error}}{{else}}{{template "eventList" .}}{{end}}70</section>71{{end}}7273{{define "outbox"}}<section>74<h1>Outbox</h1>75{{if .Error}}{{template "alert" .Error}}{{else}}{{template "eventList" .}}{{end}}76</section>77{{end}}7879{{define "search"}}<section>80<h1>Search</h1>81<form id="search" action="/search" method="get">82<label>Terms <input name="q" type="search" value="{{.Query.Get "q"}}" required></label>83<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"}}">84<button>Search</button>85</form>86{{if .Error}}{{template "alert" .Error}}87{{else if .Feed}}<h2>Results</h2>88{{template "eventList" .}}89{{else if .Query.Get "q"}}<p data-empty>No matching events.</p>90{{end}}</section>91{{end}}9293{{define "articles"}}<section>94<h1>Articles</h1>95{{if .Error}}{{template "alert" .Error}}{{else}}{{template "eventList" .}}{{end}}96<p><a href="/feed.xml">Atom feed</a> | <a href="/articles.json">JSON feed</a></p>97</section>98{{end}}99100{{define "event"}}<section>101<h1>Event</h1>102{{if .Feed}}{{template "eventList" .}}{{else}}{{template "nostrEvent" .Event}}<share-link></share-link>{{end}}103<p><a href="/feed.xml">Atom feed</a> | <a href="/articles.json">JSON feed</a></p>104</section>105{{end}}106107{{define "view"}}<section>108<h1>View: {{.View}}</h1>109{{template "jsonView" .Event}}110</section>111{{end}}112113{{define "invite"}}<section>114<h1>Join {{or .Policy.Name .Slug}}</h1>115<p>This invite is claimed with one signature from your Nostr signer. The relay never receives a private key.</p>116{{if .Policy.JoinTerms}}<h2>Before you join</h2>117<pre>{{.Policy.JoinTerms}}</pre>118{{end}}<rpc-form method="claiminvite" action="/api/invites/claim" terms="{{.Policy.JoinTerms}}">119<input type="hidden" name="param" value="{{.Invite}}">120{{if .Policy.JoinTerms}}<label><input type="checkbox" name="termsAgreement" required> I agree to these relay terms.</label>121{{end}}<button data-primary>Join relay</button>122</rpc-form>123</section>124{{end}}125126{{define "terms"}}<section>127<h1>Terms</h1>128{{if .Policy.JoinTerms}}{{markdown .Policy.JoinTerms}}{{else}}<p>This relay has not published terms.</p>{{end}}129</section>130{{end}}131132{{define "private"}}<section>133<h1>Private messages</h1>134<p>Sign in with a Nostr client to view addressed private events.</p>135</section>136{{end}}137138{{define "media"}}<section>139<h1>Media</h1>140<p>Blossom uploads and NIP-96 metadata are available from compatible clients.</p>141</section>142{{end}}143144{{define "marmot"}}<section>145<h1>Marmot</h1>146<p>Marmot group state is served when the feature is enabled.</p>147</section>148{{end}}149150{{define "grasp"}}<section>151<h1>GRASP</h1>152<p>Repository state and relay capabilities are served through the GRASP endpoints.</p>153</section>154{{end}}