sandymount 0.0.1 → 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CNAME +1 -0
- package/MAGIC.md +9 -0
- package/README.md +235 -2
- package/bin/sandymount.js +108 -0
- package/getting-started.html +439 -0
- package/index.html +680 -0
- package/manifesto.html +203 -0
- package/og-image.png +0 -0
- package/og-image.svg +86 -0
- package/package.json +31 -5
- package/styles.css +907 -0
- package/tools.html +234 -0
|
@@ -0,0 +1,439 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
+
<title>Getting Started with SAND - The Decentralized Web Stack</title>
|
|
7
|
+
|
|
8
|
+
<!-- Primary Meta Tags -->
|
|
9
|
+
<meta name="title" content="Getting Started with SAND - The Decentralized Web Stack">
|
|
10
|
+
<meta name="description" content="Get a decentralized identity in 30 seconds. No email. No password. No company. Start building on the SAND stack.">
|
|
11
|
+
|
|
12
|
+
<!-- Open Graph / Facebook -->
|
|
13
|
+
<meta property="og:type" content="website">
|
|
14
|
+
<meta property="og:url" content="https://sandy-mount.com/getting-started.html">
|
|
15
|
+
<meta property="og:title" content="Getting Started with SAND">
|
|
16
|
+
<meta property="og:description" content="Get a decentralized identity in 30 seconds. No email. No password. No company.">
|
|
17
|
+
<meta property="og:image" content="https://sandy-mount.com/og-image.png">
|
|
18
|
+
|
|
19
|
+
<!-- Twitter -->
|
|
20
|
+
<meta property="twitter:card" content="summary_large_image">
|
|
21
|
+
<meta property="twitter:url" content="https://sandy-mount.com/getting-started.html">
|
|
22
|
+
<meta property="twitter:title" content="Getting Started with SAND">
|
|
23
|
+
<meta property="twitter:description" content="Get a decentralized identity in 30 seconds. No email. No password. No company.">
|
|
24
|
+
<meta property="twitter:image" content="https://sandy-mount.com/og-image.png">
|
|
25
|
+
|
|
26
|
+
<!-- Favicon -->
|
|
27
|
+
<link rel="icon" type="image/svg+xml" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'><text y='.9em' font-size='90'>🏖️</text></svg>">
|
|
28
|
+
|
|
29
|
+
<!-- Styles -->
|
|
30
|
+
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800&display=swap" rel="stylesheet">
|
|
31
|
+
<link rel="stylesheet" href="./styles.css">
|
|
32
|
+
<style>
|
|
33
|
+
.guide-header {
|
|
34
|
+
text-align: center;
|
|
35
|
+
padding: 4rem 1.5rem 3rem;
|
|
36
|
+
max-width: 700px;
|
|
37
|
+
margin: 0 auto;
|
|
38
|
+
}
|
|
39
|
+
.guide-header h1 {
|
|
40
|
+
font-size: 2.5rem;
|
|
41
|
+
margin-bottom: 1rem;
|
|
42
|
+
background: var(--gradient);
|
|
43
|
+
-webkit-background-clip: text;
|
|
44
|
+
background-clip: text;
|
|
45
|
+
color: transparent;
|
|
46
|
+
}
|
|
47
|
+
.guide-header .hook {
|
|
48
|
+
font-size: 1.25rem;
|
|
49
|
+
color: var(--text-muted);
|
|
50
|
+
margin-bottom: 0.5rem;
|
|
51
|
+
}
|
|
52
|
+
.guide-header .subhook {
|
|
53
|
+
color: var(--text-muted);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
.steps {
|
|
57
|
+
max-width: 800px;
|
|
58
|
+
margin: 0 auto;
|
|
59
|
+
padding: 0 1.5rem 4rem;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
.step {
|
|
63
|
+
background: var(--bg-card);
|
|
64
|
+
border: 1px solid var(--border);
|
|
65
|
+
border-radius: 12px;
|
|
66
|
+
padding: 2rem;
|
|
67
|
+
margin-bottom: 2rem;
|
|
68
|
+
position: relative;
|
|
69
|
+
}
|
|
70
|
+
.step::before {
|
|
71
|
+
content: '';
|
|
72
|
+
position: absolute;
|
|
73
|
+
left: 2rem;
|
|
74
|
+
top: 100%;
|
|
75
|
+
width: 2px;
|
|
76
|
+
height: 2rem;
|
|
77
|
+
background: var(--border);
|
|
78
|
+
}
|
|
79
|
+
.step:last-child::before {
|
|
80
|
+
display: none;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
.step-header {
|
|
84
|
+
display: flex;
|
|
85
|
+
align-items: center;
|
|
86
|
+
gap: 1rem;
|
|
87
|
+
margin-bottom: 1rem;
|
|
88
|
+
}
|
|
89
|
+
.step-time {
|
|
90
|
+
font-size: 0.75rem;
|
|
91
|
+
font-weight: 600;
|
|
92
|
+
text-transform: uppercase;
|
|
93
|
+
letter-spacing: 0.05em;
|
|
94
|
+
padding: 0.25rem 0.75rem;
|
|
95
|
+
border-radius: 20px;
|
|
96
|
+
background: var(--accent-glow);
|
|
97
|
+
color: var(--accent);
|
|
98
|
+
}
|
|
99
|
+
.step-layer {
|
|
100
|
+
font-size: 0.75rem;
|
|
101
|
+
font-weight: 600;
|
|
102
|
+
text-transform: uppercase;
|
|
103
|
+
letter-spacing: 0.05em;
|
|
104
|
+
padding: 0.25rem 0.75rem;
|
|
105
|
+
border-radius: 20px;
|
|
106
|
+
}
|
|
107
|
+
.step-layer.d { background: rgba(22, 163, 74, 0.1); color: var(--accent-green); }
|
|
108
|
+
.step-layer.n { background: rgba(234, 88, 12, 0.1); color: var(--accent-orange); }
|
|
109
|
+
.step-layer.s { background: rgba(124, 58, 237, 0.1); color: var(--accent); }
|
|
110
|
+
.step-layer.a { background: rgba(8, 145, 178, 0.1); color: var(--accent-cyan); }
|
|
111
|
+
|
|
112
|
+
.step h2 {
|
|
113
|
+
font-size: 1.5rem;
|
|
114
|
+
margin-bottom: 0.5rem;
|
|
115
|
+
}
|
|
116
|
+
.step .aha {
|
|
117
|
+
color: var(--accent);
|
|
118
|
+
font-style: italic;
|
|
119
|
+
margin-bottom: 1rem;
|
|
120
|
+
}
|
|
121
|
+
.step p {
|
|
122
|
+
color: var(--text-muted);
|
|
123
|
+
margin-bottom: 1rem;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
.step-code {
|
|
127
|
+
background: #1e1e2e;
|
|
128
|
+
color: #cdd6f4;
|
|
129
|
+
padding: 1rem 1.25rem;
|
|
130
|
+
border-radius: 8px;
|
|
131
|
+
font-family: 'SF Mono', 'Fira Code', monospace;
|
|
132
|
+
font-size: 0.875rem;
|
|
133
|
+
overflow-x: auto;
|
|
134
|
+
margin-bottom: 1rem;
|
|
135
|
+
}
|
|
136
|
+
.step-code .comment { color: #6c7086; }
|
|
137
|
+
.step-code .command { color: #a6e3a1; }
|
|
138
|
+
.step-code .output { color: #89b4fa; }
|
|
139
|
+
|
|
140
|
+
.step-links {
|
|
141
|
+
display: flex;
|
|
142
|
+
flex-wrap: wrap;
|
|
143
|
+
gap: 0.75rem;
|
|
144
|
+
}
|
|
145
|
+
.step-links a {
|
|
146
|
+
font-size: 0.875rem;
|
|
147
|
+
padding: 0.5rem 1rem;
|
|
148
|
+
border-radius: 6px;
|
|
149
|
+
background: var(--bg);
|
|
150
|
+
border: 1px solid var(--border);
|
|
151
|
+
transition: all 0.2s;
|
|
152
|
+
}
|
|
153
|
+
.step-links a:hover {
|
|
154
|
+
border-color: var(--accent);
|
|
155
|
+
background: var(--accent-glow);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
.next-steps {
|
|
159
|
+
max-width: 800px;
|
|
160
|
+
margin: 0 auto;
|
|
161
|
+
padding: 0 1.5rem 4rem;
|
|
162
|
+
}
|
|
163
|
+
.next-steps h2 {
|
|
164
|
+
font-size: 1.5rem;
|
|
165
|
+
margin-bottom: 1.5rem;
|
|
166
|
+
text-align: center;
|
|
167
|
+
}
|
|
168
|
+
.next-grid {
|
|
169
|
+
display: grid;
|
|
170
|
+
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
|
|
171
|
+
gap: 1rem;
|
|
172
|
+
}
|
|
173
|
+
.next-card {
|
|
174
|
+
background: var(--bg-card);
|
|
175
|
+
border: 1px solid var(--border);
|
|
176
|
+
border-radius: 8px;
|
|
177
|
+
padding: 1.5rem;
|
|
178
|
+
text-align: center;
|
|
179
|
+
transition: all 0.2s;
|
|
180
|
+
}
|
|
181
|
+
.next-card:hover {
|
|
182
|
+
border-color: var(--accent);
|
|
183
|
+
transform: translateY(-2px);
|
|
184
|
+
}
|
|
185
|
+
.next-card h3 {
|
|
186
|
+
font-size: 1rem;
|
|
187
|
+
margin-bottom: 0.5rem;
|
|
188
|
+
}
|
|
189
|
+
.next-card p {
|
|
190
|
+
font-size: 0.875rem;
|
|
191
|
+
color: var(--text-muted);
|
|
192
|
+
}
|
|
193
|
+
</style>
|
|
194
|
+
</head>
|
|
195
|
+
<body>
|
|
196
|
+
<a href="#main" class="skip-link">Skip to main content</a>
|
|
197
|
+
<div class="bg-grid" aria-hidden="true"></div>
|
|
198
|
+
<div class="bg-glow bg-glow-1" aria-hidden="true"></div>
|
|
199
|
+
<div class="bg-glow bg-glow-2" aria-hidden="true"></div>
|
|
200
|
+
|
|
201
|
+
<nav class="nav" aria-label="Main navigation">
|
|
202
|
+
<a href="./" class="nav-logo">Sandymount</a>
|
|
203
|
+
<div class="nav-links">
|
|
204
|
+
<a href="./#stack">Stack</a>
|
|
205
|
+
<a href="./#projects">Projects</a>
|
|
206
|
+
<a href="./getting-started.html" class="active">Get Started</a>
|
|
207
|
+
<a href="./manifesto.html">Manifesto</a>
|
|
208
|
+
<a href="https://github.com/sandy-mount">GitHub</a>
|
|
209
|
+
</div>
|
|
210
|
+
<button class="hamburger" onclick="toggleMenu()" aria-label="Toggle menu" aria-expanded="false" aria-controls="mobileMenu">
|
|
211
|
+
<span></span>
|
|
212
|
+
<span></span>
|
|
213
|
+
<span></span>
|
|
214
|
+
</button>
|
|
215
|
+
</nav>
|
|
216
|
+
|
|
217
|
+
<div class="mobile-menu" id="mobileMenu" aria-label="Mobile navigation">
|
|
218
|
+
<a href="./#stack" onclick="closeMenu()">Stack</a>
|
|
219
|
+
<a href="./#projects" onclick="closeMenu()">Projects</a>
|
|
220
|
+
<a href="./getting-started.html" onclick="closeMenu()">Get Started</a>
|
|
221
|
+
<a href="./manifesto.html" onclick="closeMenu()">Manifesto</a>
|
|
222
|
+
<a href="https://github.com/sandy-mount" onclick="closeMenu()">GitHub</a>
|
|
223
|
+
</div>
|
|
224
|
+
|
|
225
|
+
<main id="main">
|
|
226
|
+
<header class="guide-header">
|
|
227
|
+
<h1>Build on SAND</h1>
|
|
228
|
+
<p class="hook">Get a decentralized identity in 30 seconds.</p>
|
|
229
|
+
<p class="subhook">No email. No password. No company.</p>
|
|
230
|
+
</header>
|
|
231
|
+
|
|
232
|
+
<div class="steps">
|
|
233
|
+
<!-- Step 1: Identity -->
|
|
234
|
+
<div class="step">
|
|
235
|
+
<div class="step-header">
|
|
236
|
+
<span class="step-time">30 seconds</span>
|
|
237
|
+
<span class="step-layer d">D — Identity</span>
|
|
238
|
+
</div>
|
|
239
|
+
<h2>1. Create Your Agent</h2>
|
|
240
|
+
<p class="aha">"I exist on the decentralized web — no signup required."</p>
|
|
241
|
+
<p>One command. You're an agent on the decentralized web with a cryptographic identity that works across the entire SAND stack.</p>
|
|
242
|
+
|
|
243
|
+
<div class="step-code">
|
|
244
|
+
<span class="comment"># Create your agent identity</span><br>
|
|
245
|
+
<span class="command">npm init agent</span><br><br>
|
|
246
|
+
<span class="comment"># Output: your agent keys</span><br>
|
|
247
|
+
<span class="output">{</span><br>
|
|
248
|
+
<span class="output"> "nsec": "nsec1abc...xyz", // private - keep secret!</span><br>
|
|
249
|
+
<span class="output"> "npub": "npub1def...uvw" // public - share freely</span><br>
|
|
250
|
+
<span class="output">}</span>
|
|
251
|
+
</div>
|
|
252
|
+
|
|
253
|
+
<p>Your <code>npub</code> is your public identity. Your <code>nsec</code> is your private key — guard it like a password, but better: no one can reset it, and no one can take it away.</p>
|
|
254
|
+
|
|
255
|
+
<div class="step-links">
|
|
256
|
+
<a href="https://github.com/melvincarvalho/create-agent">create-agent on GitHub →</a>
|
|
257
|
+
<a href="https://nostrcg.github.io/did-nostr/">did:nostr Spec →</a>
|
|
258
|
+
</div>
|
|
259
|
+
</div>
|
|
260
|
+
|
|
261
|
+
<!-- Step 2: Messaging -->
|
|
262
|
+
<div class="step">
|
|
263
|
+
<div class="step-header">
|
|
264
|
+
<span class="step-time">2 minutes</span>
|
|
265
|
+
<span class="step-layer n">N — Realtime</span>
|
|
266
|
+
</div>
|
|
267
|
+
<h2>2. Send Your First Message</h2>
|
|
268
|
+
<p class="aha">"No account, no permission — it just worked."</p>
|
|
269
|
+
<p>Use your new identity to post to the Nostr network. Messages go to relays you choose, not company servers.</p>
|
|
270
|
+
|
|
271
|
+
<div class="step-code">
|
|
272
|
+
<span class="comment"># Post to Nostr (using any client)</span><br>
|
|
273
|
+
<span class="command">npx nostrcli post "Hello from the decentralized web!"</span>
|
|
274
|
+
</div>
|
|
275
|
+
|
|
276
|
+
<p>Or use a web client — sign in with your nsec (or a browser extension like nos2x) and post. Your message propagates across relays worldwide in seconds.</p>
|
|
277
|
+
|
|
278
|
+
<div class="step-links">
|
|
279
|
+
<a href="https://nostr.rocks/">nostr.rocks (web client) →</a>
|
|
280
|
+
<a href="https://nostrcg.github.io/userguide/">Nostr User Guide →</a>
|
|
281
|
+
<a href="https://nostr.com/">More Clients →</a>
|
|
282
|
+
</div>
|
|
283
|
+
</div>
|
|
284
|
+
|
|
285
|
+
<!-- Step 3: Data -->
|
|
286
|
+
<div class="step">
|
|
287
|
+
<div class="step-header">
|
|
288
|
+
<span class="step-time">10 minutes</span>
|
|
289
|
+
<span class="step-layer s">S — Data/Web</span>
|
|
290
|
+
</div>
|
|
291
|
+
<h2>3. Own Your Data</h2>
|
|
292
|
+
<p class="aha">"My data, my URL, my rules."</p>
|
|
293
|
+
<p>Set up a Solid pod — your personal data store on the web. Apps request access; you decide what to share.</p>
|
|
294
|
+
|
|
295
|
+
<div class="step-code">
|
|
296
|
+
<span class="comment"># Option A: Use a provider</span><br>
|
|
297
|
+
<span class="command">→ solidweb.org (free pods)</span><br><br>
|
|
298
|
+
<span class="comment"># Option B: Self-host with JSS</span><br>
|
|
299
|
+
<span class="command">npx jss init my-pod</span><br>
|
|
300
|
+
<span class="command">npx jss start</span>
|
|
301
|
+
</div>
|
|
302
|
+
|
|
303
|
+
<p>Your pod is a web server you control. Store anything — notes, contacts, photos. Access it from any Solid-compatible app.</p>
|
|
304
|
+
|
|
305
|
+
<div class="step-links">
|
|
306
|
+
<a href="https://solid-lite.org/">Solid Lite →</a>
|
|
307
|
+
<a href="https://github.com/JavaScriptSolidServer/JavaScriptSolidServer">JSS Server →</a>
|
|
308
|
+
<a href="https://solidweb.org/">solidweb.org →</a>
|
|
309
|
+
</div>
|
|
310
|
+
</div>
|
|
311
|
+
|
|
312
|
+
<!-- Step 4: Rich Messaging -->
|
|
313
|
+
<div class="step">
|
|
314
|
+
<div class="step-header">
|
|
315
|
+
<span class="step-time">5 minutes</span>
|
|
316
|
+
<span class="step-layer s">S — Data/Web</span>
|
|
317
|
+
</div>
|
|
318
|
+
<h2>4. Rich Messaging</h2>
|
|
319
|
+
<p class="aha">"My conversations, my pod, my history."</p>
|
|
320
|
+
<p>Solid Chat brings real-time messaging to your pod. Chat with anyone, keep your history. No company reads your messages — they're stored in YOUR data store.</p>
|
|
321
|
+
|
|
322
|
+
<div class="step-code">
|
|
323
|
+
<span class="comment"># Open Solid Chat with your pod</span><br>
|
|
324
|
+
<span class="command">→ solid-chat.com</span><br><br>
|
|
325
|
+
<span class="comment"># Log in with your Solid pod</span><br>
|
|
326
|
+
<span class="output">Messages stored at: yourpod.solidweb.org/chat/</span>
|
|
327
|
+
</div>
|
|
328
|
+
|
|
329
|
+
<p>This is what the decentralized web looks like: real apps, real utility, YOUR data. Chat today, export tomorrow. No lock-in, ever.</p>
|
|
330
|
+
|
|
331
|
+
<div class="step-links">
|
|
332
|
+
<a href="https://solid-chat.com/">Solid Chat →</a>
|
|
333
|
+
<a href="https://solid.github.io/chat/">Chat Specification →</a>
|
|
334
|
+
</div>
|
|
335
|
+
</div>
|
|
336
|
+
|
|
337
|
+
<!-- Step 5: Mount -->
|
|
338
|
+
<div class="step">
|
|
339
|
+
<div class="step-header">
|
|
340
|
+
<span class="step-time">2 minutes</span>
|
|
341
|
+
<span class="step-layer s">S — Data/Web</span>
|
|
342
|
+
</div>
|
|
343
|
+
<h2>5. Mount Your Pod</h2>
|
|
344
|
+
<p class="aha">"My cloud is my filesystem."</p>
|
|
345
|
+
<p>This is where it clicks. Mount your Solid pod locally via SSHFS. Your decentralized data becomes a folder on your device.</p>
|
|
346
|
+
|
|
347
|
+
<div class="step-code">
|
|
348
|
+
<span class="comment"># Mount your pod locally</span><br>
|
|
349
|
+
<span class="command">sshfs you@solidweb.org:/pod ~/mypod</span><br><br>
|
|
350
|
+
<span class="comment"># Browse your decentralized data</span><br>
|
|
351
|
+
<span class="command">ls ~/mypod</span><br>
|
|
352
|
+
<span class="output">chat/ notes/ contacts/ photos/</span>
|
|
353
|
+
</div>
|
|
354
|
+
|
|
355
|
+
<p>"Own your data" isn't a slogan — it's <code>ls -la</code>. Browse it. Edit it. Sync it. Back it up. It's just files.</p>
|
|
356
|
+
|
|
357
|
+
<div class="step-links">
|
|
358
|
+
<a href="https://solidweb.org/">solidweb.org →</a>
|
|
359
|
+
<a href="https://en.wikipedia.org/wiki/SSHFS">What is SSHFS? →</a>
|
|
360
|
+
<a href="./tools.html">100+ tools that just work →</a>
|
|
361
|
+
</div>
|
|
362
|
+
</div>
|
|
363
|
+
</div>
|
|
364
|
+
|
|
365
|
+
<section class="next-steps">
|
|
366
|
+
<h2>And So Much More...</h2>
|
|
367
|
+
<p style="text-align: center; color: var(--text-muted); margin-bottom: 2rem; max-width: 500px; margin-left: auto; margin-right: auto;">This is just the beginning. The SAND stack is open — extend it, fork it, build on it. No ceilings. No gatekeepers.</p>
|
|
368
|
+
<div class="next-grid">
|
|
369
|
+
<a href="https://aam.wtf/" class="next-card">
|
|
370
|
+
<h3>AAM</h3>
|
|
371
|
+
<p>Agent-to-Agent discovery and skills registry</p>
|
|
372
|
+
</a>
|
|
373
|
+
<a href="https://docs.soapbox.pub/ditto/install/" class="next-card">
|
|
374
|
+
<h3>Ditto</h3>
|
|
375
|
+
<p>Bridge Nostr ↔ ActivityPub for federation</p>
|
|
376
|
+
</a>
|
|
377
|
+
<a href="https://solid-lite.github.io/slips/" class="next-card">
|
|
378
|
+
<h3>SLIPs</h3>
|
|
379
|
+
<p>34+ modular specs for building on Solid</p>
|
|
380
|
+
</a>
|
|
381
|
+
<a href="https://blocktrails.org/" class="next-card">
|
|
382
|
+
<h3>BlockTrails</h3>
|
|
383
|
+
<p>Provably safe agents with audit trails</p>
|
|
384
|
+
</a>
|
|
385
|
+
</div>
|
|
386
|
+
</section>
|
|
387
|
+
</main>
|
|
388
|
+
|
|
389
|
+
<footer class="footer">
|
|
390
|
+
<div class="footer-grid">
|
|
391
|
+
<div class="footer-brand">
|
|
392
|
+
<div class="nav-logo">Sandymount</div>
|
|
393
|
+
<p>Building on SAND, the stack for the decentralized web.</p>
|
|
394
|
+
</div>
|
|
395
|
+
<div class="footer-col">
|
|
396
|
+
<h4>Stack</h4>
|
|
397
|
+
<a href="https://solidproject.org">Solid</a>
|
|
398
|
+
<a href="https://activitypub.rocks">ActivityPub</a>
|
|
399
|
+
<a href="https://nostr.com">Nostr</a>
|
|
400
|
+
<a href="https://nostrcg.github.io/did-nostr/">DID</a>
|
|
401
|
+
</div>
|
|
402
|
+
<div class="footer-col">
|
|
403
|
+
<h4>Learn</h4>
|
|
404
|
+
<a href="./getting-started.html">Get Started</a>
|
|
405
|
+
<a href="./manifesto.html">Manifesto</a>
|
|
406
|
+
<a href="https://socialdocs.org">SocialDocs</a>
|
|
407
|
+
</div>
|
|
408
|
+
<div class="footer-col">
|
|
409
|
+
<h4>Connect</h4>
|
|
410
|
+
<a href="https://github.com/sandy-mount">GitHub</a>
|
|
411
|
+
<a href="./">Home</a>
|
|
412
|
+
</div>
|
|
413
|
+
</div>
|
|
414
|
+
<div class="footer-bottom">
|
|
415
|
+
<p>Sandymount — Building on SAND, the stack for the decentralized web.</p>
|
|
416
|
+
</div>
|
|
417
|
+
</footer>
|
|
418
|
+
|
|
419
|
+
<script>
|
|
420
|
+
function toggleMenu() {
|
|
421
|
+
const hamburger = document.querySelector('.hamburger');
|
|
422
|
+
const mobileMenu = document.getElementById('mobileMenu');
|
|
423
|
+
const isOpen = mobileMenu.classList.toggle('active');
|
|
424
|
+
hamburger.classList.toggle('active');
|
|
425
|
+
hamburger.setAttribute('aria-expanded', isOpen);
|
|
426
|
+
document.body.style.overflow = isOpen ? 'hidden' : '';
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
function closeMenu() {
|
|
430
|
+
const hamburger = document.querySelector('.hamburger');
|
|
431
|
+
const mobileMenu = document.getElementById('mobileMenu');
|
|
432
|
+
hamburger.classList.remove('active');
|
|
433
|
+
mobileMenu.classList.remove('active');
|
|
434
|
+
hamburger.setAttribute('aria-expanded', 'false');
|
|
435
|
+
document.body.style.overflow = '';
|
|
436
|
+
}
|
|
437
|
+
</script>
|
|
438
|
+
</body>
|
|
439
|
+
</html>
|