A vibe coded tangled fork which supports pijul.
1{{ define "title" }}tangled · tightly-knit social coding{{ end }}
2
3{{ define "extrameta" }}
4 <!-- Open Graph Meta Tags -->
5 <meta property="og:title" content="tangled · tightly-knit social coding" />
6 <meta property="og:type" content="website" />
7 <meta property="og:url" content="https://tangled.org" />
8 <meta property="og:description" content="The next-generation social coding platform." />
9 <meta property="og:image" content="https://assets.tangled.network/tangled_og.png" />
10 <meta property="og:image:width" content="1200" />
11 <meta property="og:image:height" content="630" />
12
13 <!-- Twitter Card Meta Tags -->
14 <meta name="twitter:card" content="summary_large_image" />
15 <meta name="twitter:title" content="Tangled" />
16 <meta name="twitter:description" content="The next-generation social coding platform." />
17 <meta name="twitter:image" content="https://assets.tangled.network/tangled_og.png" />
18
19 <!-- Additional SEO -->
20 <meta name="description" content="The next-generation social coding platform. Host repos on your infrastructure with knots, use stacked pull requests, and run CI with spindles." />
21 <link rel="canonical" href="https://tangled.org" />
22{{ end }}
23
24
25{{ define "content" }}
26 <div class="flex flex-col gap-20 md:gap-40 my-20 md:my-32">
27 {{ template "timeline/fragments/hero" . }}
28 {{ template "timeline/fragments/preview" . }}
29 {{ template "features1" . }}
30 {{ template "features2" . }}
31 {{ template "recentUpdates" . }}
32 {{ template "community" . }}
33 </div>
34{{ end }}
35
36{{ block "topbarLayout" . }}
37 <header class="max-w-screen-xl mx-auto w-full col-span-full md:col-span-1 md:col-start-2" style="z-index: 20;">
38 {{ if .LoggedInUser }}
39 <div id="upgrade-banner"
40 hx-get="/upgradeBanner"
41 hx-trigger="load"
42 hx-swap="innerHTML">
43 </div>
44 {{ end }}
45 {{ template "layouts/fragments/topbar" . }}
46 </header>
47{{ end }}
48
49{{ block "footerLayout" . }}
50 <footer class="z-10">
51 {{ template "layouts/fragments/footer" . }}
52 </footer>
53{{ end }}
54
55{{ block "bodyClasses" . }}
56 bg-transparent bg-gradient-to-b from-white to-slate-100 dark:bg-none dark:bg-gray-900
57{{ end }}
58
59{{ block "mainLayout" . }}
60 <div class="flex-grow relative">
61 <div
62 class="absolute opacity-50 dark:opacity-5 inset-x-0 top-0 bottom-[-50px] md:bottom-[-150px] pointer-events-none bg-[url('https://assets.tangled.network/yarn_ball.svg')] bg-no-repeat bg-right-bottom bg-[length:500px] md:bg-[length:1000px] w-full">
63 </div>
64 <div class="max-w-screen-xl mx-auto flex flex-col gap-4 relative z-10">
65 {{ block "contentLayout" . }}
66 <main>
67 {{ block "content" . }}{{ end }}
68 </main>
69 {{ end }}
70
71 {{ block "contentAfterLayout" . }}
72 <main>
73 {{ block "contentAfter" . }}{{ end }}
74 </main>
75 {{ end }}
76 </div>
77 </div>
78{{ end }}
79
80{{ define "features1" }}
81 {{ $labelStyle := "normal-case cursor-pointer w-auto md:w-full p-4 md:px-6 rounded bg-white dark:bg-gray-800 font-medium text-base md:text-lg opacity-50 border border-gray-200 dark:border-gray-700 relative overflow-hidden" }}
82 {{ $spanStyle := "z-10 items-center justify-between gap-2 w-full" }}
83 {{ $connectorStyle := "w-0.5 h-6 bg-gray-300 dark:bg-gray-600 opacity-0 mx-auto" }}
84 {{ $contentStyle := "hidden bg-white dark:bg-gray-800 rounded shadow-sm border border-gray-200 dark:border-gray-700 grid-cols-1 animate-fadein" }}
85 {{ $progressOverlayStyle := "absolute inset-0 bg-gray-600/10 dark:bg-gray-100/10 w-0 transition-none" }}
86
87 <style>
88 @media (max-width: 768px) {
89 .features-grid:has(#feature-prs:checked) {
90 grid-template-columns: 1fr auto auto;
91 }
92
93 .features-grid:has(#feature-knots:checked) {
94 grid-template-columns: auto 1fr auto;
95 }
96
97 .features-grid:has(#feature-spindles:checked) {
98 grid-template-columns: auto auto 1fr;
99 }
100
101 #feature-prs:checked ~ label[for="feature-prs"] .label-text,
102 #feature-knots:checked ~ label[for="feature-knots"] .label-text,
103 #feature-spindles:checked ~ label[for="feature-spindles"] .label-text {
104 display: inline-flex !important;
105 }
106 #feature-prs:checked ~ label[for="feature-prs"] .icon-only,
107 #feature-knots:checked ~ label[for="feature-knots"] .icon-only,
108 #feature-spindles:checked ~ label[for="feature-spindles"] .icon-only {
109 display: none !important;
110 }
111 }
112 </style>
113
114 <div class="features-grid w-full grid grid-cols-3 gap-x-6 px-2">
115 <input type="radio" id="feature-prs" name="feature" class="peer/prs hidden" checked />
116 <input type="radio" id="feature-knots" name="feature" class="peer/knots hidden" />
117 <input type="radio" id="feature-spindles" name="feature" class="peer/spindles hidden" />
118
119 <label for="feature-prs" class="{{ $labelStyle }} peer-checked/prs:opacity-100 peer-checked/prs:shadow-sm">
120 <span class="label-text hidden md:inline-flex {{ $spanStyle }}">A better way to review {{ i "git-pull-request" "size-5" }}</span>
121 <span class="icon-only inline-flex md:hidden {{ $spanStyle }}">{{ i "git-pull-request" "size-5" }}</span>
122 <div class="{{ $progressOverlayStyle }}" data-progress="prs"></div>
123 </label>
124
125 <label for="feature-knots" class="{{ $labelStyle }} peer-checked/knots:opacity-100 peer-checked/knots:shadow-sm">
126 <span class="label-text hidden md:inline-flex {{ $spanStyle }}">Completely self-hostable {{ i "hard-drive" "size-5" }}</span>
127 <span class="icon-only inline-flex md:hidden {{ $spanStyle }}">{{ i "hard-drive" "size-5" }}</span>
128 <div class="{{ $progressOverlayStyle }}" data-progress="knots"></div>
129 </label>
130
131 <label for="feature-spindles" class="{{ $labelStyle }} peer-checked/spindles:opacity-100 peer-checked/spindles:shadow-sm">
132 <span class="label-text hidden md:inline-flex {{ $spanStyle }}">Quick and easy CI {{ i "layers-2" "size-5" }}</span>
133 <span class="icon-only inline-flex md:hidden {{ $spanStyle }}">{{ i "layers-2" "size-5" }}</span>
134 <div class="{{ $progressOverlayStyle }}" data-progress="spindles"></div>
135 </label>
136
137 <div class="{{ $connectorStyle }} peer-checked/prs:opacity-100"></div>
138 <div class="{{ $connectorStyle }} peer-checked/knots:opacity-100"></div>
139 <div class="{{ $connectorStyle }} peer-checked/spindles:opacity-100"></div>
140
141 {{ $titleStyle := "text-2xl md:text-6xl my-2 md:mb-4 text-black dark:text-white font-medium" }}
142 {{ $textContentStyle := "p-4 md:p-6 md:text-xl" }}
143 {{ $imgContentStyle := "w-full overflow-hidden place-content-center bg-gradient-to-b from-slate-50 to-slate-100 dark:from-gray-800 dark:to-gray-900 border-t border-gray-200 dark:border-gray-700" }}
144 {{ $linkDesktopStyle := "hover:no-underline items-center gap-2 p-3 text-base btn" }}
145
146 <div class="col-span-3 {{ $contentStyle }} peer-checked/prs:grid relative">
147 <div class="{{ $textContentStyle }} flex gap-4 md:gap-8">
148 <section class="space-y-4">
149 <h1 class="{{ $titleStyle }}">Pull requests, reimagined</h1>
150 <p class="text-gray-600 dark:text-gray-400">
151 Break down large features into small, reviewable chunks. Stack pull
152 requests on top of each other and ship faster with round-based code
153 reviews. Tangled natively supports stacking using Jujutsu.
154 </p>
155 <a href="https://blog.tangled.org/stacking" class="hover:no-underline inline-flex md:hidden items-center gap-2 text-sm text-black dark:text-white font-medium">
156 Learn more
157 {{ i "arrow-right" "size-4" }}
158 </a>
159 </section>
160 <div class="w-fit hidden md:flex items-center">
161 <div class="size-32 rounded-full flex items-center justify-center bg-yellow-100 dark:bg-yellow-900 -mr-4" >
162 {{ i "wand-sparkles" "size-16 text-yellow-500 dark:text-yellow-500" }}
163 </div>
164 <div class="size-40 rounded-full flex items-center justify-center bg-green-100 dark:bg-green-900 z-10">
165 {{ i "git-pull-request-arrow" "size-24 text-green-500 dark:text-green-500 rotate-12" }}
166 </div>
167 </div>
168 </div>
169 <div class="{{ $imgContentStyle }} relative overflow-hidden flex items-center justify-center">
170 <div class="w-[120%] md:w-full flex">
171 <picture class="w-full">
172 <source srcset="https://assets.tangled.network/home-page-prs-dark.svg" media="(prefers-color-scheme: dark)" />
173 <img src="https://assets.tangled.network/home-page-prs-light.svg" class="w-full block" />
174 </picture>
175 </div>
176 </div>
177 <a href="https://blog.tangled.org/stacking" class="hover:no-underline hidden md:inline-flex absolute -bottom-6 -right-12 items-center gap-2 p-3 text-base btn">
178 Learn more
179 {{ i "arrow-right" "size-4" }}
180 </a>
181 </div>
182
183 <div class="col-span-3 {{ $contentStyle }} peer-checked/knots:grid relative">
184 <div class="{{ $textContentStyle }} flex place-content-between gap-4 md:gap-8">
185 <section class="space-y-4">
186 <h1 class="{{ $titleStyle }}">Run it at home</h1>
187 <p class="text-gray-600 dark:text-gray-400">
188 Host your repositories on your own infrastructure with <a href="https://docs.tangled.org/knot-self-hosting-guide.html#knot-self-hosting-guide" class="no-underline">knots</a>.
189 Run CI on your own machines with <a href="https://docs.tangled.org/spindles.html#self-hosting-guide" class="no-underline">spindles</a>.
190 <br>
191 Don't want to self-host? All are welcome on our hosted instances.
192 </p>
193 <a href="https://docs.tangled.org/knot-self-hosting-guide.html#knot-self-hosting-guide" class="hover:no-underline inline-flex md:hidden items-center gap-2 text-sm text-black dark:text-white font-medium">
194 Learn more
195 {{ i "arrow-right" "size-4" }}
196 </a>
197 </section>
198 <div class="w-fit hidden md:flex items-center">
199 <div class="size-32 rounded-full flex items-center justify-center bg-blue-100 dark:bg-blue-900 -mr-4" >
200 {{ i "workflow" "size-16 text-blue-500 dark:text-blue-500" }}
201 </div>
202 <div class="size-40 rounded-full flex items-center justify-center bg-yellow-100 dark:bg-yellow-900 z-10">
203 {{ i "server" "size-24 text-yellow-500 dark:text-yellow-500" }}
204 </div>
205 </div>
206 </div>
207 <div class="{{ $imgContentStyle }} relative overflow-hidden flex items-center justify-center">
208 <div class="w-[120%] md:w-full flex">
209 <picture class="w-full">
210 <source srcset="https://assets.tangled.network/home-page-self-host-dark.svg" media="(prefers-color-scheme: dark)" />
211 <img src="https://assets.tangled.network/home-page-self-host-light.svg" class="w-full block" />
212 </picture>
213 </div>
214 </div>
215 <a href="https://docs.tangled.org/knot-self-hosting-guide.html#knot-self-hosting-guide" class="hover:no-underline hidden md:inline-flex absolute -bottom-6 -right-12 items-center gap-2 p-3 text-base btn">
216 Learn more
217 {{ i "arrow-right" "size-4" }}
218 </a>
219 </div>
220
221 <div class="col-span-3 {{ $contentStyle }} peer-checked/spindles:grid relative">
222 <div class="{{ $textContentStyle }} flex place-content-between gap-4 md:gap-8">
223 <section class="space-y-4">
224 <h1 class="{{ $titleStyle }}">Nix-powered CI</h1>
225 <p class="text-gray-600 dark:text-gray-400">
226 Pick and choose dependencies for your CI pipelines from <a
227 href="https://docs.tangled.org/spindles.html#dependencies"
228 class="no-underline"><code>nixpkgs</code></a>, one of the biggest
229 package repositories.
230 <br>
231 Support for Docker and MicroVM based runners coming soon!
232 </p>
233 <a href="https://docs.tangled.org/spindles.html#pipelines" class="hover:no-underline inline-flex md:hidden items-center gap-2 text-sm text-black dark:text-white font-medium">
234 Learn more
235 {{ i "arrow-right" "size-4" }}
236 </a>
237 </section>
238 <div class="w-fit hidden md:flex items-center">
239 <div class="size-32 rounded-full flex items-center justify-center bg-green-100 dark:bg-green-900 -mr-4" >
240 {{ i "package" "size-16 text-green-500 dark:text-green-500" }}
241 </div>
242 <div class="size-40 rounded-full flex items-center justify-center bg-indigo-100 dark:bg-indigo-900 z-10">
243 {{ i "snowflake" "size-24 text-indigo-500 dark:text-indigo-500 rotate-12" }}
244 </div>
245 </div>
246 </div>
247 <div class="{{ $imgContentStyle }} flex items-end justify-center pb-0 overflow-hidden">
248 <div class="w-[120%] md:w-full flex">
249 <picture class="w-full">
250 <source srcset="https://assets.tangled.network/home-page-ci-dark.svg" media="(prefers-color-scheme: dark)" />
251 <img src="https://assets.tangled.network/home-page-ci-light.svg" class="w-full block" />
252 </picture>
253 </div>
254 </div>
255 <a href="https://docs.tangled.org/spindles.html#pipelines" class="hover:no-underline hidden md:inline-flex absolute -bottom-6 -right-12 items-center gap-2 p-3 text-base btn">
256 Learn more
257 {{ i "arrow-right" "size-4" }}
258 </a>
259 </div>
260 </div>
261
262 <script>
263 document.addEventListener('DOMContentLoaded', function() {
264 const featureIds = ['feature-prs', 'feature-knots', 'feature-spindles'];
265 const progressNames = ['prs', 'knots', 'spindles'];
266 let currentIndex = 0;
267 let timerInterval = null;
268
269 function stopTimer() {
270 if (timerInterval) {
271 clearInterval(timerInterval);
272 timerInterval = null;
273 }
274 document.querySelectorAll('[data-progress]').forEach(el => {
275 el.classList.remove('animate-progress');
276 });
277 }
278
279 const firstProgress = document.querySelector('[data-progress="prs"]');
280 if (firstProgress) {
281 firstProgress.classList.add('animate-progress');
282 }
283
284 document.querySelectorAll('label[for^="feature-"]').forEach(label => {
285 label.addEventListener('click', stopTimer);
286 });
287
288 timerInterval = setInterval(function() {
289 document.querySelectorAll('[data-progress]').forEach(el => {
290 el.classList.remove('animate-progress');
291 void el.offsetWidth; // force reflow
292 });
293
294 currentIndex = (currentIndex + 1) % featureIds.length;
295 document.getElementById(featureIds[currentIndex]).checked = true;
296
297 const activeProgress = document.querySelector('[data-progress="' + progressNames[currentIndex] + '"]');
298 if (activeProgress) {
299 activeProgress.classList.add('animate-progress');
300 }
301 }, 10000);
302 });
303 </script>
304{{ end }}
305
306{{ define "features2" }}
307 {{ $cardStyle := "bg-white dark:bg-gray-800 rounded shadow-sm border border-gray-200 dark:border-gray-700" }}
308 {{ $cardInnerStyle := "flex flex-row items-center gap-4 md:gap-6 p-4 md:p-6 md:pt-8 relative" }}
309 {{ $contentStyle := "flex-1 flex flex-col" }}
310 {{ $titleStyle := "text-xl md:text-2xl font-bold mb-2 md:mb-3 text-gray-900 dark:text-gray-100" }}
311 {{ $descriptionStyle := "text-gray-600 dark:text-gray-300 text-sm md:text-base leading-relaxed mb-5 md:mb-0" }}
312 {{ $linkMobileStyle := "hover:no-underline inline-flex md:hidden items-center gap-2 text-sm text-black dark:text-white font-medium" }}
313 {{ $iconContainerStyle := "relative shrink-0 w-24 h-24 md:w-48 md:h-48" }}
314 {{ $iconCircleStyle := "rounded-full flex items-center justify-center border border-gray-200 dark:border-gray-700" }}
315 {{ $linkDesktopStyle := "hover:no-underline hidden md:inline-flex absolute -bottom-10 -right-14 items-center gap-2 p-3 text-base btn" }}
316
317 <div class="w-full flex flex-col gap-6 md:gap-40 max-w-5xl mx-auto px-2">
318 <div class="{{ $cardStyle }} md:mr-32">
319 <div class="{{ $cardInnerStyle }}">
320 {{ $moreLink := "https://docs.tangled.org/quick-start-guide.html#login-or-sign-up" }}
321 <div class="{{ $contentStyle }}">
322 <h3 class="{{ $titleStyle }}">Built on AT Protocol</h3>
323 <p class="{{ $descriptionStyle }}">
324 <a class="underline" href="https://atproto.com/">AT Protocol</a> enables federated code-collaboration. Submit
325 pull-requests or bug-reports to any repository hosted on any
326 server.
327 <br>
328 <br>
329 Bring an existing AT Protocol account (such as your Bluesky
330 account), or signup for one with us.
331 </p>
332 <a href="{{ $moreLink }}" class="{{ $linkMobileStyle }}">
333 Learn more
334 {{ i "arrow-right" "size-4" }}
335 </a>
336 </div>
337 <div class="{{ $iconContainerStyle }}">
338 <div class="{{ $iconCircleStyle }} w-full h-full bg-blue-100 dark:bg-blue-900/50">
339 {{ i "at-sign" "size-12 md:size-24" "text-blue-500 dark:text-blue-500" "rotate-12" }}
340 </div>
341 <div class="{{ $iconCircleStyle }} absolute -top-2 -left-2 w-10 h-10 md:w-16 md:h-16 rounded-full bg-white dark:bg-gray-800 -rotate-12">
342 {{ i "globe" "size-4 md:size-8" "text-blue-500 dark:text-blue-500" }}
343 </div>
344 <a href="{{ $moreLink }}" class="{{ $linkDesktopStyle }}">
345 Learn more
346 {{ i "arrow-right" "size-4" }}
347 </a>
348 </div>
349 </div>
350 </div>
351
352 <div class="{{ $cardStyle }} md:ml-32">
353 <div class="{{ $cardInnerStyle }}">
354 {{ $moreLink := "https://tangled.org/core" }}
355 <div class="{{ $contentStyle }}">
356 <h3 class="{{ $titleStyle }}">Free and open source</h3>
357 <p class="{{ $descriptionStyle }}">
358 All of Tangled is open source and built with the community!
359 Check out the <a class="underline" href="https://tangled.org/core">monorepo</a> and join in on the fun.
360 <br>
361 <br>
362 We welcome contributions however big or small. You can start contributing by picking up a
363 <a class="underline" href="https://tangled.org/tangled.org/core/issues">good-first-issue</a>.
364 </p>
365 <a href="{{ $moreLink }}" class="{{ $linkMobileStyle }}">
366 View source
367 {{ i "arrow-right" "size-4" }}
368 </a>
369 </div>
370 <div class="{{ $iconContainerStyle }}">
371 <div class="{{ $iconCircleStyle }} w-full h-full bg-green-100 dark:bg-green-900/50">
372 {{ i "package-open" "size-12 md:size-24" "text-green-500 dark:text-green-500" "-rotate-12" }}
373 </div>
374 <div class="absolute -top-2 -left-2 w-10 h-10 md:w-16 md:h-16 rounded-full bg-white dark:bg-gray-800 flex items-center justify-center border border-gray-200 dark:border-gray-700 rotate-12">
375 {{ i "heart" "size-4 md:size-8" "text-green-500 dark:text-green-500" }}
376 </div>
377 <a href="{{ $moreLink }}" class="{{ $linkDesktopStyle }}">
378 View source
379 {{ i "arrow-right" "size-4" }}
380 </a>
381 </div>
382 </div>
383 </div>
384
385 <div class="{{ $cardStyle }} md:mr-32">
386 <div class="{{ $cardInnerStyle }}">
387 {{ $moreLink := "/timeline" }}
388 <div class="{{ $contentStyle }}">
389 <h3 class="{{ $titleStyle }}">Social coding is back</h3>
390 <p class="{{ $descriptionStyle }}">
391 Discover trending projects, follow your friends and star your favourite repositories. Coding is better together!
392 </p>
393 <a href="{{ $moreLink }}" class="{{ $linkMobileStyle }}">
394 Explore timeline
395 {{ i "arrow-right" "size-4" }}
396 </a>
397 </div>
398 <div class="{{ $iconContainerStyle }}">
399 <div class="{{ $iconCircleStyle }} w-full h-full bg-amber-100 dark:bg-amber-900/50">
400 {{ i "message-circle-heart" "size-12 md:size-24" "text-amber-500 dark:text-amber-500" "rotate-12" }}
401 </div>
402 <div class="absolute -top-2 -left-2 w-10 h-10 md:w-16 md:h-16 rounded-full bg-white dark:bg-gray-800 flex items-center justify-center border border-gray-200 dark:border-gray-700 -rotate-12">
403 {{ i "users" "size-4 md:size-8" "text-amber-500 dark:text-amber-500" }}
404 </div>
405 <a href="{{ $moreLink }}" class="{{ $linkDesktopStyle }}">
406 Explore timeline
407 {{ i "arrow-right" "size-4" }}
408 </a>
409 </div>
410 </div>
411 </div>
412 </div>
413{{ end }}
414
415{{ define "changelog" }}
416 <div class="w-full px-2 py-16 md:py-24">
417 <h2 class="text-3xl md:text-4xl font-bold mb-8 text-gray-900 dark:text-gray-100">Changelog</h2>
418
419 <div class="grid grid-cols-1 gap-6 mb-6">
420 {{ range $index := list 0 1 2 3 }}
421 <div class="bg-white dark:bg-gray-800 rounded shadow-sm border border-gray-200 dark:border-gray-700 p-6">
422 <div class="flex items-center gap-2 mb-3">
423 <span class="text-xs font-medium text-gray-500 dark:text-gray-400">v1.{{ sub 3 $index }}.0</span>
424 <span class="text-xs text-gray-400 dark:text-gray-500">•</span>
425 <span class="text-xs text-gray-500 dark:text-gray-400">Feb {{ sub 16 $index }}, 2026</span>
426 </div>
427 <h3 class="text-lg font-semibold mb-2 text-gray-900 dark:text-gray-100">Feature Update {{ sub 4 $index }}</h3>
428 <p class="text-sm text-gray-600 dark:text-gray-300 leading-relaxed">
429 Improvements to the platform including bug fixes, performance enhancements, and new features.
430 </p>
431 </div>
432 {{ end }}
433 </div>
434
435 <div class="flex justify-end">
436 <a href="/changelog" class="hover:no-underline inline-flex items-center gap-2 px-4 py-2 text-base btn">
437 View full changelog
438 {{ i "arrow-right" "size-4" }}
439 </a>
440 </div>
441 </div>
442{{ end }}
443
444{{ define "recentUpdates" }}
445 <div class="w-full px-2 py-16 md:py-24">
446 <h2 class="px-4 text-3xl md:text-4xl font-bold text-gray-900 dark:text-gray-100 mb-2">Recent updates</h2>
447 <p class="px-4 mb-8 text-gray-500 dark:text-gray-400">
448 Follow <a href="https://bsky.app/profile/tangled.org">@tangled.org</a> on Bluesky for more!
449 </p>
450 <div class="columns-1 md:columns-2 lg:columns-3 gap-6">
451 {{ range $index, $post := .BlueskyPosts }}
452 <div class="{{ if ge $index 3 }}hidden md:block{{ end }}">
453 {{ template "post" $post }}
454 </div>
455 {{ end }}
456 </div>
457 </div>
458{{ end }}
459
460{{ define "post" }}
461 <div class="bg-white dark:bg-gray-800 rounded shadow-sm border border-gray-200 dark:border-gray-700 px-6 py-4 flex flex-col gap-2 break-inside-avoid mb-6">
462 <div class="flex items-center justify-between text-sm text-gray-500 dark:text-gray-400">
463 <span class="flex items-center gap-2">
464 {{ template "user/fragments/picHandle" "tangled.org" }}
465 </span>
466 <span>{{ template "repo/fragments/shortTimeAgo" .CreatedAt }}</span>
467 </div>
468 <p class="text-gray-900 dark:text-gray-100 text-base leading-relaxed whitespace-pre-wrap">{{ .Text }}</p>
469
470 {{ if .Embed }}
471 {{ if .Embed.EmbedImages_View }}
472 <div class="grid {{ if eq (len .Embed.EmbedImages_View.Images) 1 }}grid-cols-1{{ else if eq (len .Embed.EmbedImages_View.Images) 2 }}grid-cols-2{{ else }}grid-cols-2{{ end }} gap-2">
473 {{ range .Embed.EmbedImages_View.Images }}
474 <img src="{{ .Fullsize }}" alt="{{ .Alt }}" class="rounded w-full h-auto object-cover border border-gray-200 dark:border-gray-700" loading="lazy" />
475 {{ end }}
476 </div>
477 {{ else if .Embed.EmbedExternal_View }}
478 <a href="{{ .Embed.EmbedExternal_View.External.Uri }}" target="_blank" rel="noopener noreferrer" class="hover:no-underline block border border-gray-200 dark:border-gray-700 rounded overflow-hidden hover:bg-gray-50 dark:hover:bg-gray-700 transition-colors">
479 {{ if .Embed.EmbedExternal_View.External.Thumb }}
480 <img src="{{ .Embed.EmbedExternal_View.External.Thumb }}" alt="" class="w-full h-48 object-cover" loading="lazy" />
481 {{ end }}
482 <div class="p-3">
483 <div class="font-medium text-gray-900 dark:text-gray-100 text-sm mb-1">{{ .Embed.EmbedExternal_View.External.Title }}</div>
484 <div class="text-xs text-gray-600 dark:text-gray-400 line-clamp-2">{{ .Embed.EmbedExternal_View.External.Description }}</div>
485 <div class="text-xs text-gray-500 dark:text-gray-500 mt-1">{{ .Embed.EmbedExternal_View.External.Uri }}</div>
486 </div>
487 </a>
488 {{ else if .Embed.EmbedVideo_View }}
489 <div class="rounded overflow-hidden bg-gray-100 dark:bg-gray-700 aspect-video flex items-center justify-center">
490 <span class="text-gray-500 dark:text-gray-400 text-sm">Video embed</span>
491 </div>
492 {{ end }}
493 {{ end }}
494
495 <a href="https://bsky.app/profile/tangled.org/post/{{ .Rkey }}"
496 target="_blank"
497 rel="noopener noreferrer"
498 class="flex items-center justify-between gap-4 text-sm text-gray-500 dark:text-gray-400 pt-2 no-underline hover:no-underline">
499 <div class="flex items-center gap-4">
500 <div class="flex items-center gap-1">
501 {{ i "heart" "size-4" }}
502 <span>{{ .LikeCount }}</span>
503 </div>
504 <div class="flex items-center gap-1">
505 {{ i "repeat-2" "size-4" }}
506 <span>{{ .RepostCount }}</span>
507 </div>
508 <div class="flex items-center gap-1">
509 {{ i "message-square" "size-4 -scale-x-1" }}
510 <span>{{ add64 .ReplyCount .QuoteCount }}</span>
511 </div>
512 </div>
513 {{ i "arrow-up-right" "size-4" }}
514 </a>
515 </div>
516{{ end }}
517
518{{ define "community" }}
519 <div class="w-full px-2 py-16 md:py-24">
520 <div class="max-w-2xl mx-auto text-center space-y-6">
521 <h2 class="text-3xl md:text-6xl font-bold text-gray-900 dark:text-gray-100">Join the network</h2>
522 <p class="text-xl text-gray-600 dark:text-gray-300">
523 You can participate in the Tangled network with an AT account. If you
524 don't know what that is, you can sign up for one below.
525 </p>
526 <form class="flex gap-2 items-stretch w-full md:max-w-md mx-auto p-2 border border-gray-200 dark:border-gray-700 bg-white dark:bg-gray-800 rounded shadow-sm" method="get" action="/signup">
527 <input
528 type="email"
529 id="email"
530 name="id"
531 tabindex="4"
532 required
533 placeholder="Enter your email"
534 class="py-2 w-full"
535 />
536 <button class="btn-create flex items-center gap-2 text-base whitespace-nowrap" type="submit">
537 join now
538 {{ i "arrow-right" "size-4" }}
539 </button>
540 </form>
541 </div>
542{{ end }}