a love letter to tangled (android, iOS, and a search API)
1{{define "title"}}Twister — Search Tangled{{end}}
2{{define "head"}}
3<script defer src="https://cdn.jsdelivr.net/npm/alpinejs@3.x.x/dist/cdn.min.js"></script>
4{{end}}
5{{define "content"}}
6<div x-data="searchApp()" x-init="initFromURL()">
7 <section class="search-hero">
8 <h1>Search Tangled</h1>
9 <form class="search-form" @submit.prevent="doSearch(true)">
10 <input type="text" x-model="query" placeholder="Search repos, issues, PRs, profiles…" class="search-input" autofocus>
11 <button type="submit" class="btn btn-primary">Search</button>
12 </form>
13 <div class="filter-bar">
14 <select x-model="filters.type" @change="doSearch(true)">
15 <option value="">All types</option>
16 <option value="repo">Repos</option>
17 <option value="issue">Issues</option>
18 <option value="pull">Pull Requests</option>
19 <option value="profile">Profiles</option>
20 <option value="string">Strings</option>
21 <option value="star">Stars</option>
22 </select>
23 <input type="text" x-model="filters.author" placeholder="Author" @keydown.enter="doSearch(true)" class="filter-input">
24 <input type="text" x-model="filters.language" placeholder="Language" @keydown.enter="doSearch(true)" class="filter-input">
25 <select x-model="filters.state" @change="doSearch(true)">
26 <option value="">Any state</option>
27 <option value="open">Open</option>
28 <option value="closed">Closed</option>
29 <option value="merged">Merged</option>
30 </select>
31 </div>
32 </section>
33
34 <section class="results">
35 <template x-if="error">
36 <div class="msg msg-error" x-text="error"></div>
37 </template>
38 <template x-if="!error && !searched && !loading">
39 <div class="msg msg-empty">
40 <p>Search indexed Tangled records.</p>
41 <p>
42 If a record is missing, fetch it through the API to index it for search.
43 Try
44 <a href="/actors/desertthunder.dev" target="_blank" rel="noopener">
45 <code>GET /actors/desertthunder.dev</code>
46 </a>.
47 </p>
48 </div>
49 </template>
50 <template x-if="!error && searched && results.length === 0">
51 <div class="msg msg-empty">
52 <p>No results found.</p>
53 <p>
54 Fetching a resource through the API will index it for search.
55 Try
56 <a href="/actors/desertthunder.dev" target="_blank" rel="noopener">
57 <code>GET /actors/desertthunder.dev</code>
58 </a>
59 and search again.
60 </p>
61 </div>
62 </template>
63 <template x-for="r in results" :key="r.id">
64 <div class="result-shell">
65 <article class="card">
66 <div class="card-head">
67 <span class="badge" x-text="r.record_type"></span>
68 <span class="card-title" x-text="r.title || r.id"></span>
69 </div>
70 <div class="card-snippet" x-show="r.body_snippet" x-html="r.body_snippet"></div>
71 <div class="card-snippet" x-show="!r.body_snippet && r.summary" x-text="r.summary"></div>
72 <div class="card-meta">
73 <span x-show="r.author_handle" x-text="r.author_handle"></span>
74 <span x-show="r.repo_name" class="meta-sep" x-text="r.repo_name"></span>
75 <span x-show="r.updated_at" class="meta-sep" x-text="relTime(r.updated_at)"></span>
76 </div>
77 <div class="card-actions">
78 <a
79 x-show="resultURL(r)"
80 :href="resultURL(r)"
81 target="_blank"
82 rel="noopener"
83 class="btn btn-card"
84 >Open on Tangled</a>
85 <button
86 x-show="r.at_uri"
87 type="button"
88 class="btn btn-card"
89 @click="copyATURI(r)"
90 >Copy AT URI</button>
91 <a
92 x-show="r.at_uri"
93 :href="pdsURL(r)"
94 target="_blank"
95 rel="noopener"
96 class="btn btn-card"
97 >Open in pds.ls</a>
98 <a
99 :href="jsonURL(r)"
100 target="_blank"
101 rel="noopener"
102 class="btn btn-card"
103 >View JSON</a>
104 </div>
105 <div x-show="warningMessage(r)" class="card-warning" role="note">
106 <strong class="warning-title" x-text="warningMessage(r)"></strong>
107 <code x-show="r.at_uri" class="warning-uri" x-text="r.at_uri"></code>
108 </div>
109 </article>
110 </div>
111 </template>
112 <template x-if="hasMore">
113 <button class="btn btn-more" @click="loadMore()" x-text="loading ? 'Loading\u2026' : 'Load more'" :disabled="loading"></button>
114 </template>
115 </section>
116 <div class="toast" :class="{ 'toast-visible': toastVisible }" x-show="toastVisible" x-transition.opacity.duration.150ms>
117 <span x-text="toastMessage"></span>
118 </div>
119</div>
120{{end}}
121{{define "scripts"}}
122<script src="/static/search.js"></script>
123{{end}}
124{{template "layout" .}}