-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathdocumentation.html
More file actions
366 lines (331 loc) · 19.6 KB
/
Copy pathdocumentation.html
File metadata and controls
366 lines (331 loc) · 19.6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
<!DOCTYPE html>
<html lang="en" class="doc-page">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover">
<title>Restify — Documentation</title>
<meta name="description" content="Everything you need to run Restify: setup, library, playlists, offline listening, shortcuts and troubleshooting.">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Unbounded:wght@500;600;700;800&family=Plus+Jakarta+Sans:wght@400;500;600;700;800&family=JetBrains+Mono:wght@400;500;600&display=swap" rel="stylesheet">
<script src="https://unpkg.com/lucide@latest" defer></script>
<link rel="stylesheet" href="src/style.css">
</head>
<body class="doc-page">
<div class="drawer-backdrop" id="drawer-backdrop"></div>
<nav class="drawer" id="drawer" aria-label="Documentation sections" aria-hidden="true">
<div class="drawer-head">
<div class="brand"><span class="dot"></span> Restify Docs</div>
<button class="drawer-close" id="drawer-close" aria-label="Close menu"><i data-lucide="x"></i></button>
</div>
<div class="side-label">Side A — Getting started</div>
<div class="track-link" data-href="#welcome"><span class="n">01</span> Welcome to Restify</div>
<div class="track-link" data-href="#install"><span class="n">02</span> Install & set up</div>
<div class="track-link" data-href="#library"><span class="n">03</span> Your library, at a glance</div>
<div class="track-link" data-href="#playback"><span class="n">04</span> Playing & queueing</div>
<div class="side-label">Side B — Going deeper</div>
<div class="track-link" data-href="#playlists"><span class="n">05</span> Playlists & curation</div>
<div class="track-link" data-href="#offline"><span class="n">06</span> Offline listening</div>
<div class="track-link" data-href="#shortcuts"><span class="n">07</span> Keyboard shortcuts</div>
<div class="track-link" data-href="#account"><span class="n">08</span> Account & sync</div>
<div class="track-link" data-href="#faq"><span class="n">09</span> Troubleshooting & FAQ</div>
<div class="track-link" data-href="#changelog"><span class="n">10</span> Changelog & credits</div>
</nav>
<div class="doc-wrap" id="doc-root">
<a class="standalone-back" href="../index.html" id="standalone-back" data-standalone-only>
<i data-lucide="chevron-left"></i>Back to Restify
</a>
<header class="appbar">
<button class="appbar-btn" id="menu-open" aria-label="Open sections menu" aria-expanded="false"><i data-lucide="menu"></i></button>
</header>
<div class="progress-rail"><div class="progress-fill" id="progress-fill"></div></div>
<main>
<section class="hero">
<div class="vinyl" aria-hidden="true"></div>
<div class="eyebrow"><i data-lucide="headphones"></i> Restify · v2.4 docs</div>
<h1 class="hero-title">The full guide to your <em>ad-free</em> listening room.</h1>
<p class="hero-sub">Ten short tracks covering setup, your library, playlists, offline mode and every shortcut worth knowing.</p>
<div class="hero-actions">
<a class="btn btn-primary" href="#welcome"><i data-lucide="play"></i>Start reading</a>
<button class="btn btn-ghost" id="download-btn-hero"><i data-lucide="download"></i>Download .html</button>
</div>
<div class="stat-strip">
<div class="stat-chip"><div class="v">4</div><div class="l">Pages</div></div>
<div class="stat-chip"><div class="v">0</div><div class="l">Ads</div></div>
<div class="stat-chip"><div class="v">∞</div><div class="l">Songs</div></div>
</div>
</section>
<section class="toc">
<div class="toc-head"><h2>Tracklist</h2><span>10 sections</span></div>
<div class="toc-grid" id="toc-grid"></div>
</section>
<!-- 01 -->
<section class="doc-section" id="welcome">
<div class="sec-kicker"><div class="num">01</div><div class="side">Side A</div></div>
<h3 class="sec-title">Welcome to Restify</h3>
<p>Restify is a small, ad-free listening room built around four pages: <strong>Home</strong>, <strong>Search</strong>, <strong>Library</strong>, and <strong>About</strong>. No pre-roll, no mid-track breaks, no sponsored rows in your feed — just your music and the people you follow.</p>
<p>This guide walks through the app in the order most people actually use it: set up, build your library, press play, then the deeper stuff like offline mode and shortcuts.</p>
<div class="note"><i data-lucide="info"></i>Every section below is short on purpose. Jump around using the tracklist — you don't need to read this in order.</div>
</section>
<!-- 02 -->
<section class="doc-section" id="install">
<div class="sec-kicker"><div class="num">02</div><div class="side">Side A</div></div>
<h3 class="sec-title">Install & set up</h3>
<p>Restify runs as a lightweight app with no account wall to browse. Getting your own space running takes three steps:</p>
<ul class="doc-list">
<li><i data-lucide="check"></i><span><b>Open the app</b> and pick a display name — this is what shows on any playlist you share.</span></li>
<li><i data-lucide="check"></i><span><b>Add a profile photo</b> from the About page by tapping the ring around your avatar.</span></li>
<li><i data-lucide="check"></i><span><b>Pick your interests</b> — a few genre tags that shape what Home surfaces first.</span></li>
</ul>
<div class="track-card">
<div class="app-icon"><i data-lucide="user-round"></i></div>
<h4>Your profile is local-first</h4>
<p>Name, bio and photo are saved on-device until you connect an account, so you can try Restify fully before signing up for anything.</p>
</div>
</section>
<!-- 03 -->
<section class="doc-section" id="library">
<div class="sec-kicker"><div class="num">03</div><div class="side">Side A</div></div>
<h3 class="sec-title">Your library, at a glance</h3>
<p>The Library page collects everything you've saved: liked tracks, followed artists, and playlists — yours and ones you've saved from others.</p>
<ul class="doc-list">
<li><i data-lucide="heart"></i><span><b>Liked tracks</b> live in one running list, newest first.</span></li>
<li><i data-lucide="mic-2"></i><span><b>Followed artists</b> surface new releases on Home automatically.</span></li>
<li><i data-lucide="list-music"></i><span><b>Playlists</b> can be reordered by dragging the handle on the left of each row.</span></li>
</ul>
</section>
<!-- 04 -->
<section class="doc-section" id="playback">
<div class="sec-kicker"><div class="num">04</div><div class="side">Side A</div></div>
<h3 class="sec-title">Playing & queueing</h3>
<p>Tap any track to play it and start a queue from that point in the list. The mini-player pins to the bottom of the screen — swipe it up for full playback controls, or swipe a track sideways in a list to queue it next without interrupting what's playing.</p>
<div class="note"><i data-lucide="repeat"></i>Long-press the repeat icon to loop a single track instead of the full queue.</div>
</section>
<!-- 05 -->
<section class="doc-section" id="playlists">
<div class="sec-kicker"><div class="num">05</div><div class="side">Side B</div></div>
<h3 class="sec-title">Playlists & curation</h3>
<p>Playlists are how curation happens on Restify. Build one from scratch, or turn any listening session into a playlist with <strong>Save session as playlist</strong> from the queue menu.</p>
<ul class="doc-list">
<li><i data-lucide="lock"></i><span><b>Private by default</b> — nothing you make is visible to others until you share the link.</span></li>
<li><i data-lucide="share-2"></i><span><b>Share a playlist</b> from its menu; recipients can listen without an account.</span></li>
<li><i data-lucide="users"></i><span><b>Collaborative playlists</b> let anyone with the link add tracks, not just reorder them.</span></li>
</ul>
</section>
<!-- 06 -->
<section class="doc-section" id="offline">
<div class="sec-kicker"><div class="num">06</div><div class="side">Side B</div></div>
<h3 class="sec-title">Offline listening</h3>
<p>Download any track, album or playlist for offline playback from its overflow menu. Downloaded audio is stored on-device and plays even in airplane mode.</p>
<div class="note"><i data-lucide="wifi-off"></i>Downloads use your device's storage, not a Restify quota — remove any download at any time from Library → Downloads.</div>
</section>
<!-- 07 -->
<section class="doc-section" id="shortcuts">
<div class="sec-kicker"><div class="num">07</div><div class="side">Side B</div></div>
<h3 class="sec-title">Keyboard shortcuts</h3>
<p>On desktop, Restify responds to the same shortcuts almost every player uses:</p>
<div class="kbd-grid">
<div class="kbd-row"><span class="action">Play / pause</span><span class="kbd">Space</span></div>
<div class="kbd-row"><span class="action">Next track</span><span class="kbd">→</span></div>
<div class="kbd-row"><span class="action">Previous track</span><span class="kbd">←</span></div>
<div class="kbd-row"><span class="action">Volume up / down</span><span class="kbd">↑ / ↓</span></div>
<div class="kbd-row"><span class="action">Like current track</span><span class="kbd">L</span></div>
<div class="kbd-row"><span class="action">Search</span><span class="kbd">/</span></div>
</div>
</section>
<!-- 08 -->
<section class="doc-section" id="account">
<div class="sec-kicker"><div class="num">08</div><div class="side">Side B</div></div>
<h3 class="sec-title">Account & sync</h3>
<p>Connecting an account syncs your library, playlists and history across every device signed in. Until then, everything stays on the device you're using — which is why clearing browser data on the About page's photo picker only affects that one device.</p>
<ul class="doc-list">
<li><i data-lucide="smartphone"></i><span><b>Multiple devices</b> merge libraries the first time each one signs in.</span></li>
<li><i data-lucide="log-out"></i><span><b>Signing out</b> never deletes downloads already saved on that device.</span></li>
</ul>
</section>
<!-- 09 FAQ -->
<section class="doc-section" id="faq">
<div class="sec-kicker"><div class="num">09</div><div class="side">Side B</div></div>
<h3 class="sec-title">Troubleshooting & FAQ</h3>
<div class="faq-item">
<button class="faq-q" data-faq><span>A track shows but won't play</span><i data-lucide="plus"></i></button>
<div class="faq-a"><p>Usually a stalled queue. Skip forward one track and back — this forces the player to reload the source without losing your place.</p></div>
</div>
<div class="faq-item">
<button class="faq-q" data-faq><span>My downloads disappeared</span><i data-lucide="plus"></i></button>
<div class="faq-a"><p>Downloads live on-device. Reinstalling the app, clearing site data, or switching browsers clears them — re-download from Library once you're back.</p></div>
</div>
<div class="faq-item">
<button class="faq-q" data-faq><span>Can I use Restify without an account?</span><i data-lucide="plus"></i></button>
<div class="faq-a"><p>Yes. Browsing, playback and local playlists all work signed out — you'll just lose sync across devices.</p></div>
</div>
<div class="faq-item">
<button class="faq-q" data-faq><span>Why is a shared playlist empty for the person I sent it to?</span><i data-lucide="plus"></i></button>
<div class="faq-a"><p>Private playlists only unlock with the direct link. Check the visibility toggle in the playlist menu before sharing.</p></div>
</div>
</section>
<!-- 10 Changelog -->
<section class="doc-section" id="changelog">
<div class="sec-kicker"><div class="num">10</div><div class="side">Side B</div></div>
<h3 class="sec-title">Changelog & credits</h3>
<div class="changelog-item">
<span class="ver">v2.4</span>
<div class="cl-body"><b>Collaborative playlists</b><span>Anyone with the link can now add tracks, not just listen.</span></div>
</div>
<div class="changelog-item">
<span class="ver">v2.3</span>
<div class="cl-body"><b>Offline downloads</b><span>Tracks, albums and playlists can be saved for airplane-mode listening.</span></div>
</div>
<div class="changelog-item">
<span class="ver">v2.2</span>
<div class="cl-body"><b>Editable profile photo</b><span>Tap the ring on the About page to update your picture anytime.</span></div>
</div>
<div class="changelog-item">
<span class="ver">v2.0</span>
<div class="cl-body"><b>Four-page redesign</b><span>Home, Search, Library and About settled into the shape they are today.</span></div>
</div>
</section>
<footer class="doc-footer">
<div class="mark"><span class="dot"></span><span>RESTIFY</span></div>
<p>Documentation · built for local reading, no connection required.</p>
<button class="btn btn-primary foot-btn" id="download-btn-foot"><i data-lucide="download"></i>Download this page</button>
</footer>
</main>
</div>
<button class="disc-fab" id="disc-fab" aria-label="Back to top" title="Back to top">
<i data-lucide="arrow-up"></i>
</button>
<div class="toast" id="toast"><i data-lucide="check-circle"></i><span id="toast-text">Saved</span></div>
<script>
const SECTIONS = [
{id:'welcome', n:'01', side:'Side A — Getting started', title:'Welcome to Restify'},
{id:'install', n:'02', side:'Side A — Getting started', title:'Install & set up'},
{id:'library', n:'03', side:'Side A — Getting started', title:'Your library, at a glance'},
{id:'playback', n:'04', side:'Side A — Getting started', title:'Playing & queueing'},
{id:'playlists', n:'05', side:'Side B — Going deeper', title:'Playlists & curation'},
{id:'offline', n:'06', side:'Side B — Going deeper', title:'Offline listening'},
{id:'shortcuts', n:'07', side:'Side B — Going deeper', title:'Keyboard shortcuts'},
{id:'account', n:'08', side:'Side B — Going deeper', title:'Account & sync'},
{id:'faq', n:'09', side:'Side B — Going deeper', title:'Troubleshooting & FAQ'},
{id:'changelog', n:'10', side:'Side B — Going deeper', title:'Changelog & credits'}
];
function renderToc(){
let lastSide = '';
const html = SECTIONS.map(s => {
const label = s.side !== lastSide ? `<div class="side-label" style="margin:${lastSide?'16px':'0'} 4px 4px">${s.side}</div>` : '';
lastSide = s.side;
return `${label}<a class="track-link" href="#${s.id}" data-toc="${s.id}"><span class="n">${s.n}</span>${s.title}</a>`;
}).join('');
document.getElementById('toc-grid').innerHTML = html;
}
renderToc();
// Drawer open/close
// This page normally loads inside index.html's iframe (view-frame), which already
// shows its own back arrow + "Documentation" title above this content. When embedded,
// hide this page's own appbar too, so it doesn't stack a second header bar under
// index's — the appbar (and the standalone-back link below) only show up when this
// file is opened directly/standalone (e.g. while testing).
if (window.self === window.top) {
document.getElementById('standalone-back').style.display = 'flex';
} else {
document.body.classList.add('embedded');
}
const body = document.body;
const drawer = document.getElementById('drawer');
function openDrawer(){
body.classList.add('drawer-open');
drawer.setAttribute('aria-hidden','false');
document.getElementById('menu-open').setAttribute('aria-expanded','true');
}
function closeDrawer(){
body.classList.remove('drawer-open');
drawer.setAttribute('aria-hidden','true');
document.getElementById('menu-open').setAttribute('aria-expanded','false');
}
document.getElementById('menu-open').addEventListener('click', openDrawer);
document.getElementById('drawer-close').addEventListener('click', closeDrawer);
document.getElementById('drawer-backdrop').addEventListener('click', closeDrawer);
document.querySelectorAll('.drawer .track-link').forEach(el=>{
el.addEventListener('click', () => {
const target = document.querySelector(el.dataset.href);
closeDrawer();
if(target) setTimeout(()=>target.scrollIntoView({behavior:'smooth', block:'start'}), 180);
});
});
// Smooth scroll for toc + active state tracking
document.addEventListener('click', e=>{
const a = e.target.closest('a[href^="#"]');
if(!a) return;
const el = document.querySelector(a.getAttribute('href'));
if(el){ e.preventDefault(); el.scrollIntoView({behavior:'smooth', block:'start'}); }
});
const sectionEls = SECTIONS.map(s => document.getElementById(s.id));
const tocLinks = () => document.querySelectorAll('[data-toc], .drawer .track-link');
function setActive(id){
document.querySelectorAll('.track-link').forEach(l=>{
const match = (l.dataset.toc === id) || (l.dataset.href === '#'+id);
l.classList.toggle('active', !!match);
});
}
const observer = new IntersectionObserver((entries)=>{
entries.forEach(entry=>{
if(entry.isIntersecting){ setActive(entry.target.id); }
});
}, {rootMargin:'-30% 0px -60% 0px', threshold:0});
sectionEls.forEach(el => el && observer.observe(el));
// Scroll progress + disc rotation
const fill = document.getElementById('progress-fill');
const disc = document.getElementById('disc-fab');
function onScroll(){
const h = document.documentElement;
const scrolled = h.scrollTop;
const max = h.scrollHeight - h.clientHeight;
const pct = max > 0 ? Math.min(100, (scrolled / max) * 100) : 0;
fill.style.width = pct + '%';
disc.style.transform = `rotate(${pct * 3.6}deg)`;
}
document.addEventListener('scroll', onScroll, {passive:true});
onScroll();
disc.addEventListener('click', ()=> window.scrollTo({top:0, behavior:'smooth'}));
// FAQ accordion
document.querySelectorAll('[data-faq]').forEach(btn=>{
btn.addEventListener('click', ()=>{
btn.closest('.faq-item').classList.toggle('open');
});
});
// Toast
let toastTimer;
function showToast(text){
const t = document.getElementById('toast');
document.getElementById('toast-text').textContent = text;
t.classList.add('show');
clearTimeout(toastTimer);
toastTimer = setTimeout(()=> t.classList.remove('show'), 2600);
}
// Download this page for local/offline reading
function downloadDoc(){
try{
const html = '<!DOCTYPE html>\n' + document.documentElement.outerHTML;
const blob = new Blob([html], {type:'text/html'});
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'restify-documentation.html';
document.body.appendChild(a);
a.click();
a.remove();
URL.revokeObjectURL(url);
showToast('Downloaded — saved to your device');
}catch(err){
showToast('Download failed — try again');
}
}
['download-btn-hero','download-btn-foot'].forEach(id=>{
const el = document.getElementById(id);
if(el) el.addEventListener('click', downloadDoc);
});
document.addEventListener('DOMContentLoaded', () => { if (window.lucide) lucide.createIcons(); });
window.addEventListener('load', () => { if (window.lucide) lucide.createIcons(); });
</script>
</body>
</html>