{{/* The page shell owns the rail, content column, contextual panel and
footer. Page templates render one section selected by .Tab. The body works
before scripts load; tiny.js and bridge.js establish shared browser services,
then feature modules are loaded for the current page. */}}
{{define "page"}}<!doctype html>
<html lang="en" data-js="no" data-scripts="{{scriptsVersion}}">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1,viewport-fit=cover">
<meta name="color-scheme" content="light dark">
<meta name="theme-color" content="#f4f2ec" media="(prefers-color-scheme: light)">
<meta name="theme-color" content="#1e1d1a" media="(prefers-color-scheme: dark)">
<meta name="mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="default">
<meta name="apple-mobile-web-app-title" content="{{.Slug}}">
<title>{{.Title}}</title>
<link rel="manifest" href="/manifest.webmanifest">
<link rel="icon" href="/icon.svg" type="image/svg+xml">
<link rel="apple-touch-icon" href="/apple-touch-icon.png">
<style>{{stylesheet}}</style>
<script src="/fixi.js"></script>
<script src="/signer.js"></script>
<script src="/webmcp.js"></script>
</head>
<body>
{{$mobile := mobileHeader .}}<header id="topbar">
{{if $mobile.BackURL}}<a id="mobile-back" href="{{$mobile.BackURL}}" aria-label="{{$mobile.BackLabel}}" title="{{$mobile.BackLabel}}"><svg viewBox="0 0 24 24" width="24" height="24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m14 6-6 6 6 6"/></svg></a>{{end}}
<details id="context-menu" name="mobile-chrome"><summary id="context-toggle" aria-controls="aside" title="Page details">
{{if $mobile.RoomID}}<room-avatar picture="{{$mobile.Picture}}" fallback="{{roomAvatarURL .URL $mobile.RoomID}}" aria-hidden="true"><img src="{{if $mobile.Picture}}{{$mobile.Picture}}{{else}}{{roomAvatarURL .URL $mobile.RoomID}}{{end}}" alt="" width="36" height="36" loading="lazy"></room-avatar>{{else if $mobile.PubKey}}<nostr-avatar pubkey="{{$mobile.PubKey}}" aria-hidden="true"><img src="{{avatarURL $mobile.PubKey}}" alt="" width="36" height="36" loading="lazy"></nostr-avatar>{{end}}
<span id="mobile-heading"><strong id="mobile-title" role="heading" aria-level="1">{{if $mobile.PubKey}}{{template "nostrName" $mobile.PubKey}}{{else}}{{$mobile.Title}}{{end}}</strong><small id="mobile-context">{{$mobile.Subtitle}}</small></span><svg data-chevron viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m8 10 4 4 4-4"/></svg>
</summary></details>
<details id="nav-menu" name="mobile-chrome"><summary id="menu" aria-controls="rail" aria-label="Menu" title="Menu"><svg data-menu-icon viewBox="0 0 24 24" width="24" height="24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" aria-hidden="true"><path d="M4 6h16M4 12h16M4 18h16"/></svg><svg data-close-icon viewBox="0 0 24 24" width="24" height="24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" aria-hidden="true"><path d="m6 6 12 12M6 18 18 6"/></svg></summary></details>
{{if and .Actor (not .Private)}}<signer-connection actor="{{.Actor}}" hidden></signer-connection>{{end}}
</header>
<table id="layout" aria-label="{{.Slug}}"><tbody><tr>
<td id="rail"><div id="railbox">{{template "rail" .}}</div></td>
<td id="main"><div id="content" tabindex="-1">
{{if .Private}}{{template "signin" .}}
{{else if eq .Tab "home"}}{{template "home" .}}
{{else if eq .Tab "inbox"}}{{template "inbox" .}}
{{else if eq .Tab "outbox"}}{{template "outbox" .}}
{{else if eq .Tab "search"}}{{template "search" .}}
{{else if eq .Tab "social"}}{{template "social" .}}
{{else if eq .Tab "social-thread"}}{{template "social-thread" .}}
{{else if eq .Tab "private"}}{{template "private" .}}
{{else if eq .Tab "chat"}}{{template "chat" .}}
{{else if eq .Tab "direct"}}{{template "direct" .}}
{{else if eq .Tab "media"}}{{template "media" .}}
{{else if eq .Tab "sites"}}{{template "sites" .}}
{{else if eq .Tab "marmot"}}{{template "marmot" .}}
{{else if eq .Tab "grasp"}}{{template "grasp" .}}
{{else if eq .Tab "terms"}}{{template "terms" .}}
{{else if eq .Tab "people"}}{{template "people" .}}
{{else if eq .Tab "agents"}}{{template "agents" .}}
{{else if eq .Tab "moderation"}}{{template "moderation" .}}
{{else if eq .Tab "rules"}}{{template "rules" .}}
{{else if eq .Tab "identity"}}{{template "identity" .}}
{{else if eq .Tab "signin"}}{{template "signin" .}}
{{else if eq .Tab "account"}}{{template "account" .}}
{{else if eq .Tab "connect"}}{{template "connect" .}}
{{else if eq .Tab "data"}}{{template "data" .}}
{{else if eq .Tab "sync"}}{{template "sync" .}}
{{else if eq .Tab "views"}}{{template "views" .}}
{{else if eq .Tab "health"}}{{template "health" .}}
{{else if eq .Tab "owner"}}{{template "owner" .}}
{{else if eq .Tab "repos"}}{{template "repos" .}}
{{else if eq .Tab "repo"}}{{template "repo" .}}
{{else if eq .Tab "files"}}{{template "files" .}}
{{else if eq .Tab "wiki"}}{{template "wiki" .}}
{{else if eq .Tab "wikipage"}}{{template "wikipage" .}}
{{else if eq .Tab "file"}}{{template "file" .}}
{{else if eq .Tab "approvals"}}{{template "approvals" .}}
{{else if eq .Tab "profile"}}{{template "profile" .}}
{{else if eq .Tab "rooms"}}{{template "rooms" .}}
{{else if eq .Tab "room"}}{{template "room" .}}
{{else if eq .Tab "thread"}}{{template "thread" .}}
{{else if eq .Tab "event"}}{{template "event" .}}
{{else if eq .Tab "view"}}{{template "view" .}}
{{else if eq .Tab "invite"}}{{template "invite" .}}
{{else}}{{template "home" .}}
{{end}}</div></td>
<td id="aside"><div id="panel">{{template "panel" .}}</div></td>
</tr></tbody></table>
<footer id="footer"><table><tr><td><span id="prompt"><b>{{.Slug}}</b> &raquo; <page-link url="{{pageAddress .URL .Path .Query}}" title="Copy the page address">{{prompt .Path .Query}}</page-link></span></td><td><span id="who">{{if .Private}}private relay{{else if .Actor}}signed in as <a href="/account">{{template "nostrName" .Actor}}</a> (<button id="session-logout" type="button">sign out</button>){{else}}browsing as guest (<a href="{{signinURL .Base .Path .Query}}">Sign in</a>){{end}}</span> <span id="session-status" role="status"></span><span id="navigation-status" role="status" aria-live="polite"></span></td></tr></table><button id="install" type="button" hidden>install app</button></footer>
<script src="{{scriptURL "tiny.js"}}"></script>
<script src="{{scriptURL "bridge.js"}}"></script>
{{if or (eq .Tab "files") (eq .Tab "file")}}<script src="{{scriptURL "blossom-encryption.js"}}"></script>
<script src="{{scriptURL "file-catalog.js"}}"></script>
<script src="{{scriptURL "blossom-manifests.js"}}"></script>
<script src="{{scriptURL "blossom-upload.js"}}"></script>
<script src="{{scriptURL "file-workspace.js"}}"></script>
{{end}}<script src="{{scriptURL "nostr-name.js"}}"></script>
<script src="{{scriptURL "components.js"}}"></script>
<script src="{{scriptURL "rooms.js"}}"></script>
<script src="{{scriptURL "file-messages.js"}}"></script>
<script src="{{scriptURL "direct-messages.js"}}"></script>
<script src="{{scriptURL "chat-files.js"}}"></script>
<script src="{{scriptURL "chat.js"}}"></script>
<script src="{{scriptURL "chat-presence.js"}}"></script>
<script src="{{scriptURL "chat-activity.js"}}"></script>
<script src="{{scriptURL "grant-request.js"}}"></script>
{{if eq .Tab "connect"}}<script src="{{scriptURL "private-services.js"}}"></script>
{{end}}</body>
</html>
{{end}}

{{/* The rail is the sitemap for the current context: the relay, one repository, or management. */}}
{{define "rail"}}{{$kind := railKind .Tab}}{{if .Private}}<header><span><a id="mark" href="/"><i>t</i><i>i</i><i>n</i><i>y</i></a></span></header>
<nav><a href="{{signinURL .Base .Path .Query}}" aria-current="page">/signin</a></nav>
<p>Private relay. Sign in with a Nostr signer to continue.</p>
{{else if eq $kind "repo"}}<header><span><a href="/">{{.Slug}}</a>/<a href="/repos" title="{{.Query.Get "owner"}}">{{shortID (npub (.Query.Get "owner"))}}</a>/<b>{{.Query.Get "repo"}}</b></span></header>
<nav>{{$v := repoView .Query}}<a href="{{repoURL .Query "home" ""}}"{{if eq $v "home"}} aria-current="page"{{end}}>/home</a><a href="{{repoURL .Query "tree" ""}}"{{if or (eq $v "tree") (eq $v "file")}} aria-current="page"{{end}}>/code</a><a href="{{repoURL .Query "history" ""}}"{{if or (eq $v "history") (eq $v "commit")}} aria-current="page"{{end}}>/history</a><a href="{{repoURL .Query "issues" ""}}"{{if or (eq $v "issues") (eq $v "issue")}} aria-current="page"{{end}}>/issues</a><a href="{{repoURL .Query "prs" ""}}"{{if or (eq $v "prs") (eq $v "pr")}} aria-current="page"{{end}}>/prs</a><a href="{{repoURL .Query "activity" ""}}"{{if eq $v "activity"}} aria-current="page"{{end}}>/activity</a></nav>
{{else if eq $kind "manage"}}<header><span><a href="/">{{.Slug}}</a>/<b>manage</b></span></header>
{{range $group := navGroups manageItems}}<nav>{{range $item := $group}}<a href="{{$item.Href}}"{{if eq $item.Tab $.Tab}} aria-current="page"{{end}}>{{$item.Label}}</a>{{end}}</nav>{{end}}
{{else if eq $kind "rooms"}}<header><span><a href="/">{{.Slug}}</a>/<a href="/chat"><b>chat</b></a></span></header>
<nav aria-label="Chat"><a href="/chat"{{if eq .Tab "chat"}} aria-current="page"{{end}}>All conversations</a></nav>
{{if .Actor}}<h4>Direct chats</h4><direct-chats actor="{{.Actor}}" relay="{{wsURL .URL}}" compact><p>Connect your signer to see direct chats.</p></direct-chats>
<p><a href="/chat#new-chat">+ new chat</a></p>{{end}}
<h4>Rooms</h4>
<nav id="room-list">{{range .Rooms}}{{$r := asMap .}}{{$id := str (index $r "id")}}{{$picture := socialMediaURL (str (index $r "picture"))}}<a href="/rooms/{{$id}}"{{if eq $id $.View}} aria-current="page"{{end}}><room-avatar picture="{{$picture}}" fallback="{{roomAvatarURL $.URL $id}}" aria-hidden="true"><img src="{{if $picture}}{{$picture}}{{else}}{{roomAvatarURL $.URL $id}}{{end}}" alt="" width="24" height="24" loading="lazy"></room-avatar>{{or (str (index $r "name")) $id}}{{with age (index $r "last_message_at")}} <small>{{.}}</small>{{end}}</a>{{else}}<a href="/chat">Browse rooms</a>{{end}}</nav>
<p><a href="/chat#new-room">+ new room</a></p>
{{else}}<header><span><a id="mark" href="/" title="{{.Slug}}"><i>t</i><i>i</i><i>n</i><i>y</i></a></span></header>
{{range $group := navGroups relayItems}}<nav>{{range $item := $group}}<a href="{{$item.Href}}"{{if eq $item.Tab $.Tab}} aria-current="page"{{end}}>{{$item.Label}}</a>{{end}}</nav>{{end}}{{if .Actor}}<p id="personal-nav"><a href="/account"{{if eq .Tab "account"}} aria-current="page"{{end}}>account</a></p>{{end}}
{{end}}<div id="mobile-actions">{{if .Actor}}<a href="/account">Account</a>{{end}}<page-link url="{{pageAddress .URL .Path .Query}}" title="Copy the page address"><button type="button">Copy page link</button></page-link></div><p id="rail-tools">{{if eq $kind "repo"}}<a href="/repos">&larr; all repositories</a>{{else if or (eq $kind "manage") (eq $kind "rooms")}}<a href="/">&larr; relay</a>{{end}}<button id="theme" type="button" aria-label="Switch theme">theme</button></p>{{end}}

{{/* The panel holds facts and filters for the current page. */}}
{{define "panel"}}{{$kind := railKind .Tab}}{{if .Private}}{{template "panel-signin" .}}
{{else if eq .Tab "repo"}}{{template "panel-repo" .}}
{{else if eq .Tab "agents"}}{{template "panel-agents" .}}
{{else if eq $kind "manage"}}{{template "panel-manage" .}}
{{else if or (eq .Tab "chat") (eq .Tab "direct")}}{{template "panel-chat" .}}
{{else if eq $kind "rooms"}}{{template "panel-rooms" .}}
{{else if or (eq .Tab "social") (eq .Tab "social-thread")}}{{template "panel-social" .}}
{{else if or (eq .Tab "inbox") (eq .Tab "outbox") (eq .Tab "search") (eq .Tab "articles")}}{{template "panel-feed" .}}
{{else if eq .Tab "repos"}}{{template "panel-repos" .}}
{{else if or (eq .Tab "files") (eq .Tab "file")}}{{template "panel-files" .}}
{{else if eq .Tab "approvals"}}{{template "panel-approvals" .}}
{{else if or (eq .Tab "wiki") (eq .Tab "wikipage")}}{{template "panel-wiki" .}}
{{else if eq .Tab "signin"}}{{template "panel-signin" .}}
{{else if eq .Tab "account"}}{{template "panel-account" .}}
{{else}}{{template "panel-relay" .}}
{{end}}{{end}}

{{define "panel-relay"}}<section><h4>About</h4><table><tr><th>identity</th><td>{{template "nostrKey" .Identity}}</td></tr><tr><th>reads</th><td>{{.Policy.Reads}}</td></tr><tr><th>writes</th><td>{{.Policy.Writes}}</td></tr><tr><th>search</th><td>{{.Policy.Features.Search}}</td></tr>{{if .Policy.Features.Grasp}}<tr><th>git</th><td>GRASP-01</td></tr>{{end}}{{if .Policy.Features.Files}}<tr><th>files</th><td>Blossom</td></tr>{{end}}</table></section>
<section><h4>Actions</h4><ul>{{if .Actor}}<li><a href="/profile">profile</a></li>{{else}}<li><a href="{{signinURL .Base .Path .Query}}">sign in</a></li>{{end}}<li><a href="/.well-known/nostr.json">NIP-05 names</a></li>{{if .Policy.Features.Pages}}<li><a href="/feed.xml">Atom feed</a></li>{{end}}<li><a href="/terms">terms</a></li></ul></section>
<section><h4>Relay</h4><table><tr><th>url</th><td><code>{{.URL}}</code></td></tr></table></section>{{end}}

{{define "panel-signin"}}<section><h4>Session</h4><table><tr><th>status</th><td>{{if .Actor}}signed in{{else}}guest{{end}}</td></tr><tr><th>method</th><td>NIP-98</td></tr></table></section>
<section><h4>After sign in</h4><ul><li>join chats</li><li>manage members and policy</li><li>upload files</li><li>push repositories</li></ul></section>{{end}}

{{define "panel-account"}}<section><h4>Personal</h4><table><tr><th>identity</th><td>{{template "nostrKey" .Actor}}</td></tr><tr><th>profile</th><td><a href="/profile">edit</a></td></tr></table></section><section><h4>Relay</h4><p><small>Your relay lists and chat preferences apply to this account.</small></p></section>{{end}}

{{define "panel-repos"}}<section><h4>Hosting</h4><table><tr><th>server</th><td><code>{{.URL}}</code></td></tr><tr><th>protocol</th><td>GRASP-01</td></tr></table></section>
<section><h4>Publish</h4><p><small>Announce with ngit and push with plain git. Every push needs the owner's signed state.</small></p></section>{{end}}

{{define "panel-files"}}<section><h4>Storage</h4><table><tr><th>protocol</th><td>Blossom</td></tr>{{if .Policy.Features.Files}}<tr><th>uploads</th><td>members</td></tr>{{end}}</table></section>
{{if .Actor}}<section><h4>Upload</h4><file-upload pubkey="{{.Actor}}"></file-upload><p><small>Members-only files require membership to view or download.</small></p><details><summary>Import from URL</summary><file-mirror action="/mirror"></file-mirror></details><noscript><p>Uploads need JavaScript and a connected signer.</p></noscript></section>{{end}}{{end}}

{{define "panel-approvals"}}{{$counts := approvalCounts .Event}}{{$data := asMap .Event}}<section><h4>Waiting</h4><table><tr><th>open</th><td>{{index $counts "open"}}</td></tr><tr><th>oldest</th><td>{{with index $data "oldest_open"}}<time datetime="{{datetime .}}">{{when .}}</time>{{else}}none{{end}}</td></tr><tr><th>answered</th><td>{{index $counts "answered"}}</td></tr><tr><th>expired</th><td>{{index $counts "expired"}}</td></tr></table></section>
<section><h4>Devices</h4>{{if .Actor}}{{range $index, $device := approvalDevices .Event}}<p><i></i>device {{add $index 1}} | {{$device}}</p>{{else}}<p>No device receives notifications for this key. Enable them in Chat.</p>{{end}}<p><small>Answers from the phone need the remembered signer.</small></p>{{else}}<p>Sign in to see which devices are notified.</p>{{end}}</section>{{end}}

{{define "panel-feed"}}<section><h4>Filters</h4><form method="get" action="/{{.Tab}}"><label for="filter-kinds">kinds</label><select id="filter-kinds" name="kinds"><option value="">notes and articles</option><option value="1"{{if eq (.Query.Get "kinds") "1"}} selected{{end}}>1 notes</option><option value="30023"{{if eq (.Query.Get "kinds") "30023"}} selected{{end}}>30023 articles</option><option value="7"{{if eq (.Query.Get "kinds") "7"}} selected{{end}}>7 reactions</option><option value="all"{{if eq (.Query.Get "kinds") "all"}} selected{{end}}>everything</option></select><label for="filter-author">author</label><input id="filter-author" name="author" placeholder="64 hex pubkey" value="{{.Query.Get "author"}}"><label for="filter-since">since</label><input id="filter-since" name="since" type="date" value="{{.Query.Get "since"}}">{{if eq .Tab "search"}}<label for="filter-q">search</label><input id="filter-q" name="q" value="{{.Query.Get "q"}}">{{end}}<button>apply</button></form></section>
{{if .Actor}}<section><h4>You</h4><table><tr><th>key</th><td>{{template "nostrKey" .Actor}}</td></tr></table></section>{{end}}
{{if and .Actor (eq .Tab "inbox")}}<section><h4>Notifications</h4><push-toggle></push-toggle><p><small>Relay notices for this key, on this device only.</small></p>{{if .Owner}}<rpc-form method="notifytest"><button>Send a test</button></rpc-form>{{end}}<noscript><p>Enabling notifications needs JavaScript.</p></noscript></section>{{end}}{{end}}

{{define "panel-repo"}}{{$r := asMap .Event}}{{with index $r "repository"}}{{$r = asMap .}}{{end}}<section><h4>About</h4><table><tr><th>owner</th><td>{{template "nostrKey" (str (index $r "owner"))}}</td></tr><tr><th>visibility</th><td>{{if index $r "private"}}private{{else}}public{{end}}</td></tr>{{with index $r "commit"}}<tr><th>head</th><td><code title="{{.}}">{{shortID .}}</code></td></tr>{{end}}</table></section>
{{with index $r "maintainers"}}<section><h4>Maintainers</h4><ul id="maintainers">{{range .}}{{$m := asMap .}}<li>{{template "nostrName" (str (index $m "pubkey"))}}{{$role := str (index $m "role")}}{{if eq $role "agent"}} <small>agent{{with str (index $m "name")}} {{.}}{{end}}</small>{{else if eq $role "owner"}} <small>owner</small>{{end}}</li>{{end}}</ul></section>
{{end}}<section><h4>Clone</h4><ul>{{range index $r "clone"}}<li><code>{{.}}</code></li>{{else}}<li>no clone URL advertised</li>{{end}}</ul></section>
{{with index $r "refs"}}<section><h4>Refs</h4><form method="get" action="/repo"><input type="hidden" name="owner" value="{{$.Query.Get "owner"}}"><input type="hidden" name="repo" value="{{$.Query.Get "repo"}}"><input type="hidden" name="path" value="{{$.Query.Get "path"}}"><input type="hidden" name="id" value="{{$.Query.Get "id"}}"><input type="hidden" name="view" value="{{repoView $.Query}}"><label for="ref-select">branch or tag</label><select id="ref-select" name="ref"><option value="">default branch</option>{{range $name, $oid := .}}<option value="{{$name}}"{{if eq ($.Query.Get "ref") $name}} selected{{end}}>{{$name}}</option>{{end}}</select><button>go</button></form></section>{{end}}{{end}}

{{define "panel-manage"}}<section><h4>Policy</h4><table><tr><th>name</th><td>{{.Policy.Name}}</td></tr><tr><th>reads</th><td>{{.Policy.Reads}}</td></tr><tr><th>writes</th><td>{{.Policy.Writes}}</td></tr><tr><th>owner</th><td>{{template "nostrKey" .Policy.Owner}}</td></tr></table></section>
{{if .Review}}<section><h4>People</h4><table><tr><th>requests</th><td>{{len (pendingRequests .Requests)}} pending</td></tr></table></section>
{{end}}<section><h4>Session</h4><table><tr><th>you</th><td>{{if .Actor}}{{template "nostrKey" .Actor}}{{else}}guest{{end}}</td></tr><tr><th>role</th><td>{{if .Owner}}owner{{else if .Actor}}member{{else}}none{{end}}</td></tr></table></section>
<section><h4>Result</h4><p><small>Each form shows its result below the form. Every call is signed by your connected signer.</small></p></section>{{end}}

{{define "panel-agents"}}{{$counts := agentCounts .Feed}}{{$callbacks := callbackCounts .Callbacks}}<section><h4>Agents</h4><table><tr><th>active</th><td>{{index $counts "active"}}</td></tr><tr><th>paused</th><td>{{index $counts "paused"}}</td></tr><tr><th>revoked</th><td>{{index $counts "revoked"}}</td></tr><tr><th>callbacks</th><td>{{index $callbacks "active"}} active, {{index $callbacks "paused"}} paused</td></tr></table></section>
<section><h4>Machine access</h4><table><tr><th>mcp</th><td><code>/mcp</code> 2026-07-28</td></tr><tr><th>auth</th><td>NIP-98 per request</td></tr><tr><th>rest</th><td><code>/events</code> <code>/query</code></td></tr></table></section>
<section><h4>Kill switch</h4><rpc-form method="pauseallagents" refresh><button>Pause all agents</button></rpc-form><rpc-form method="resumeallagents" refresh><button>Resume all agents</button></rpc-form><p><small>Pausing keeps grants and rejects writes until resumed.</small></p></section>
<section><h4>Session</h4><table><tr><th>you</th><td>{{if .Actor}}{{template "nostrKey" .Actor}}{{else}}guest{{end}}</td></tr><tr><th>role</th><td>{{if .Owner}}owner{{else if .Actor}}member{{else}}none{{end}}</td></tr></table></section>{{end}}
{{define "panel-rooms"}}{{if eq .Tab "rooms"}}<section><h4>Rooms</h4><table><tr><th>rooms</th><td>{{len .Rooms}}</td></tr><tr><th>protocol</th><td>NIP-29</td></tr></table></section>
<section><h4>Actions</h4><ul>{{if .Actor}}<li><a href="/chat#new-room">new room</a></li>{{else}}<li><a href="{{signinURL .Base .Path .Query}}">sign in</a></li>{{end}}</ul></section>
{{else if .Error}}<section><h4>Room</h4><table><tr><th>id</th><td><code>{{.View}}</code></td></tr></table></section>
{{else}}{{$data := asMap .Event}}{{$room := asMap (index $data "room")}}{{$id := str (index $room "id")}}{{$role := str (index $room "role")}}<section><h4>Room</h4><table><tr><th>id</th><td><code>{{$id}}</code></td></tr><tr><th>access</th><td>{{if eq (str (index $room "access")) "members"}}members only{{else}}open{{end}}</td></tr><tr><th>created</th><td>{{short (index $room "created_at")}}</td></tr>{{if $role}}<tr><th>you</th><td>{{$role}}</td></tr>{{end}}</table></section>
<section><h4>Members</h4><ul id="members">{{range roomMembers .Event}}{{$m := asMap .}}<li{{if index $m "agent"}} data-agent{{with str (index $m "operator")}} data-operator="{{.}}"{{end}}{{end}}>{{template "nostrName" (str (index $m "pubkey"))}} <small>{{if index $m "agent"}}{{if index $m "operator"}}{{template "nostrName" (str (index $m "operator"))}}'s agent{{else}}agent{{end}}{{else}}{{str (index $m "role")}}{{end}}</small></li>{{else}}<li>{{str (index $room "members")}} members</li>{{end}}</ul></section>
{{if eq .Tab "thread"}}<section><h4>Actions</h4><ul><li><a href="/rooms/{{$id}}">open room</a></li></ul></section>
{{else}}
{{if .Actor}}<section><h4>Actions</h4>{{if roomAdmin $role}}<details><summary>invite member</summary><room-action room="{{$id}}" kind="9000"><label>pubkey <input name="pubkey" placeholder="npub or 64 hex" required></label><label>role <select name="role"><option value="member">member</option><option value="admin">admin</option>{{if eq $role "owner"}}<option value="owner">owner</option>{{end}}</select></label><button>Add member</button></room-action></details>
<details><summary>room settings</summary><room-action room="{{$id}}" kind="9002"><label>name <input name="name" value="{{str (index $room "name")}}" required maxlength="200"></label><label>about <input name="about" value="{{str (index $room "about")}}" maxlength="2000"></label><label>picture <input name="picture" value="{{str (index $room "picture")}}" placeholder="https://"></label><label>access <select name="access"><option value="open"{{if ne (str (index $room "access")) "members"}} selected{{end}}>open</option><option value="members"{{if eq (str (index $room "access")) "members"}} selected{{end}}>members only</option></select></label><button>Save</button></room-action></details>
{{end}}{{if $role}}<room-action room="{{$id}}" kind="9022"><button>Leave room</button></room-action>{{else}}<room-action room="{{$id}}" kind="9021"><button>Join room</button></room-action>{{end}}<noscript><p>Room actions need JavaScript and a connected signer.</p></noscript></section>
{{end}}{{end}}{{end}}{{end}}

{{/* Shared partials. */}}

{{define "alert"}}{{if .}}<p role="alert">{{.}}</p>{{end}}{{end}}

{{define "nostrKey"}}<nostr-key hex="{{.}}" title="{{.}}">{{shortID .}}</nostr-key>{{end}}
{{/* nostrName shows a person: the vendored nostr-name element swaps the short id for the profile name published on this relay. */}}
{{define "nostrName"}}<nostr-name pubkey="{{.}}" title="{{.}}">{{shortID .}}</nostr-name>{{end}}

{{define "jsonView"}}<json-view><pre>{{json .}}</pre></json-view>{{end}}

{{define "nostrEvent"}}{{$e := asMap .}}<nostr-event id="event-{{str (index $e "id")}}">
<header><a href="/e/{{str (index $e "id")}}">{{shortID (index $e "id")}}</a> | kind {{str (index $e "kind")}} | {{template "nostrName" (str (index $e "pubkey"))}}<small><time datetime="{{datetime (index $e "created_at")}}">{{when (index $e "created_at")}}</time></small></header>
{{if eq (str (index $e "kind")) "30023"}}<article>{{markdown (str (index $e "content"))}}</article>{{else}}<pre>{{str (index $e "content")}}</pre>{{end}}
<details><summary>event JSON</summary>{{template "jsonView" .}}</details>
</nostr-event>{{end}}

{{define "eventList"}}{{if .Feed}}<ol id="events">
{{range .Feed}}<li>{{template "nostrEvent" .}}</li>
{{end}}</ol>
{{else}}<p>No events.</p>
{{end}}{{end}}
