A vibe coded tangled fork which supports pijul.
at 1a84afde51804ed9ad6c420cf1315a1a0c85b589 535 lines 26 kB view raw
1{{ define "title" }}tangled &middot; 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 better 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"> 170 <div class="w-full md:w-full flex justify-center"> 171 <img src="https://assets.tangled.network/home-page-prs.svg" class="w-[120%] md:w-full" /> 172 </div> 173 </div> 174 <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"> 175 Learn more 176 {{ i "arrow-right" "size-4" }} 177 </a> 178 </div> 179 180 <div class="col-span-3 {{ $contentStyle }} peer-checked/knots:grid relative"> 181 <div class="{{ $textContentStyle }} flex place-content-between gap-4 md:gap-8"> 182 <section class="space-y-4"> 183 <h1 class="{{ $titleStyle }}">Run it at home</h1> 184 <p class="text-gray-600 dark:text-gray-400"> 185 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>. 186 Run CI on your own machines with <a href="https://docs.tangled.org/spindles.html#self-hosting-guide" class="no-underline">spindles</a>. 187 <br> 188 Don't want to self-host? All are welcome on our hosted instances. 189 </p> 190 <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"> 191 Learn more 192 {{ i "arrow-right" "size-4" }} 193 </a> 194 </section> 195 <div class="w-fit hidden md:flex items-center"> 196 <div class="size-32 rounded-full flex items-center justify-center bg-blue-100 dark:bg-blue-900 -mr-4" > 197 {{ i "workflow" "size-16 text-blue-500 dark:text-blue-500" }} 198 </div> 199 <div class="size-40 rounded-full flex items-center justify-center bg-yellow-100 dark:bg-yellow-900 z-10"> 200 {{ i "server" "size-24 text-yellow-500 dark:text-yellow-500" }} 201 </div> 202 </div> 203 </div> 204 <div class="{{ $imgContentStyle }} relative overflow-hidden flex items-center"> 205 <div class="w-full md:w-full flex justify-center"> 206 <img src="https://assets.tangled.network/home-page-self-host.svg" class="w-[120%] md:w-full" /> 207 </div> 208 </div> 209 <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"> 210 Learn more 211 {{ i "arrow-right" "size-4" }} 212 </a> 213 </div> 214 215 <div class="col-span-3 {{ $contentStyle }} peer-checked/spindles:grid relative"> 216 <div class="{{ $textContentStyle }} flex place-content-between gap-4 md:gap-8"> 217 <section class="space-y-4"> 218 <h1 class="{{ $titleStyle }}">Nix-powered CI</h1> 219 <p class="text-gray-600 dark:text-gray-400"> 220 Pick and choose dependencies for your CI pipelines from <a 221 href="https://docs.tangled.org/spindles.html#dependencies" 222 class="no-underline"><code>nixpkgs</code></a>, one of the biggest 223 package repositories. 224 <br> 225 Support for Docker and MicroVM based runners coming soon! 226 </p> 227 <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"> 228 Learn more 229 {{ i "arrow-right" "size-4" }} 230 </a> 231 </section> 232 <div class="w-fit hidden md:flex items-center"> 233 <div class="size-32 rounded-full flex items-center justify-center bg-green-100 dark:bg-green-900 -mr-4" > 234 {{ i "package" "size-16 text-green-500 dark:text-green-500" }} 235 </div> 236 <div class="size-40 rounded-full flex items-center justify-center bg-indigo-100 dark:bg-indigo-900 z-10"> 237 {{ i "snowflake" "size-24 text-indigo-500 dark:text-indigo-500 rotate-12" }} 238 </div> 239 </div> 240 </div> 241 <div class="{{ $imgContentStyle }} flex items-end pb-0 overflow-hidden"> 242 <div class="w-full md:w-full flex justify-center"> 243 <img src="https://assets.tangled.network/home-page-ci.svg" class="w-[120%] md:w-full" /> 244 </div> 245 </div> 246 <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"> 247 Learn more 248 {{ i "arrow-right" "size-4" }} 249 </a> 250 </div> 251 </div> 252 253 <script> 254 document.addEventListener('DOMContentLoaded', function() { 255 const featureIds = ['feature-prs', 'feature-knots', 'feature-spindles']; 256 const progressNames = ['prs', 'knots', 'spindles']; 257 let currentIndex = 0; 258 let timerInterval = null; 259 260 function stopTimer() { 261 if (timerInterval) { 262 clearInterval(timerInterval); 263 timerInterval = null; 264 } 265 document.querySelectorAll('[data-progress]').forEach(el => { 266 el.classList.remove('animate-progress'); 267 }); 268 } 269 270 const firstProgress = document.querySelector('[data-progress="prs"]'); 271 if (firstProgress) { 272 firstProgress.classList.add('animate-progress'); 273 } 274 275 document.querySelectorAll('label[for^="feature-"]').forEach(label => { 276 label.addEventListener('click', stopTimer); 277 }); 278 279 timerInterval = setInterval(function() { 280 document.querySelectorAll('[data-progress]').forEach(el => { 281 el.classList.remove('animate-progress'); 282 void el.offsetWidth; // force reflow 283 }); 284 285 currentIndex = (currentIndex + 1) % featureIds.length; 286 document.getElementById(featureIds[currentIndex]).checked = true; 287 288 const activeProgress = document.querySelector('[data-progress="' + progressNames[currentIndex] + '"]'); 289 if (activeProgress) { 290 activeProgress.classList.add('animate-progress'); 291 } 292 }, 5000); 293 }); 294 </script> 295{{ end }} 296 297{{ define "features2" }} 298 {{ $cardStyle := "bg-white dark:bg-gray-800 rounded shadow-sm border border-gray-200 dark:border-gray-700" }} 299 {{ $cardInnerStyle := "flex flex-row items-center gap-4 md:gap-6 p-4 md:p-6 md:pt-8 relative" }} 300 {{ $contentStyle := "flex-1 flex flex-col" }} 301 {{ $titleStyle := "text-xl md:text-2xl font-bold mb-2 md:mb-3 text-gray-900 dark:text-gray-100" }} 302 {{ $descriptionStyle := "text-gray-600 dark:text-gray-300 text-sm md:text-base leading-relaxed mb-5 md:mb-0" }} 303 {{ $linkMobileStyle := "hover:no-underline inline-flex md:hidden items-center gap-2 text-sm text-black dark:text-white font-medium" }} 304 {{ $iconContainerStyle := "relative shrink-0 w-24 h-24 md:w-48 md:h-48" }} 305 {{ $iconCircleStyle := "rounded-full flex items-center justify-center border border-gray-200 dark:border-gray-700" }} 306 {{ $linkDesktopStyle := "hover:no-underline hidden md:inline-flex absolute -bottom-10 -right-14 items-center gap-2 p-3 text-base btn" }} 307 308 <div class="w-full flex flex-col gap-6 md:gap-40 max-w-5xl mx-auto px-2"> 309 <div class="{{ $cardStyle }} md:mr-32"> 310 <div class="{{ $cardInnerStyle }}"> 311 {{ $moreLink := "https://docs.tangled.org/quick-start-guide.html#login-or-sign-up" }} 312 <div class="{{ $contentStyle }}"> 313 <h3 class="{{ $titleStyle }}">Built on AT Protocol</h3> 314 <p class="{{ $descriptionStyle }}"> 315 AT Protocol enables federated code-collaboration. Submit 316 pull-requests or bug-reports to any repository hosted on any 317 server. 318 <br> 319 <br> 320 Bring an existing AT Protocol account (such as your Bluesky 321 account), or signup for one with us. 322 </p> 323 <a href="{{ $moreLink }}" class="{{ $linkMobileStyle }}"> 324 Learn more 325 {{ i "arrow-right" "size-4" }} 326 </a> 327 </div> 328 <div class="{{ $iconContainerStyle }}"> 329 <div class="{{ $iconCircleStyle }} w-full h-full bg-blue-100 dark:bg-blue-900/50"> 330 {{ i "at-sign" "size-12 md:size-24" "text-blue-500 dark:text-blue-500" "rotate-12" }} 331 </div> 332 <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"> 333 {{ i "globe" "size-4 md:size-8" "text-blue-500 dark:text-blue-500" }} 334 </div> 335 <a href="{{ $moreLink }}" class="{{ $linkDesktopStyle }}"> 336 Learn more 337 {{ i "arrow-right" "size-4" }} 338 </a> 339 </div> 340 </div> 341 </div> 342 343 <div class="{{ $cardStyle }} md:ml-32"> 344 <div class="{{ $cardInnerStyle }}"> 345 {{ $moreLink := "https://tangled.org/core" }} 346 <div class="{{ $contentStyle }}"> 347 <h3 class="{{ $titleStyle }}">Free and open source</h3> 348 <p class="{{ $descriptionStyle }}"> 349 All of Tangled is open source and built with the community! 350 Check out the <a href="https://tangled.org/core">monorepo</a> and join in on the fun. 351 <br> 352 <br> 353 We welcome contributions however big or small. You can start contributing by picking up a 354 <a href="https://tangled.org/tangled.org/core/issues">good-first-issue</a>. 355 </p> 356 <a href="{{ $moreLink }}" class="{{ $linkMobileStyle }}"> 357 View source 358 {{ i "arrow-right" "size-4" }} 359 </a> 360 </div> 361 <div class="{{ $iconContainerStyle }}"> 362 <div class="{{ $iconCircleStyle }} w-full h-full bg-green-100 dark:bg-green-900/50"> 363 {{ i "package-open" "size-12 md:size-24" "text-green-500 dark:text-green-500" "-rotate-12" }} 364 </div> 365 <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"> 366 {{ i "heart" "size-4 md:size-8" "text-green-500 dark:text-green-500" }} 367 </div> 368 <a href="{{ $moreLink }}" class="{{ $linkDesktopStyle }}"> 369 View source 370 {{ i "arrow-right" "size-4" }} 371 </a> 372 </div> 373 </div> 374 </div> 375 376 <div class="{{ $cardStyle }} md:mr-32"> 377 <div class="{{ $cardInnerStyle }}"> 378 {{ $moreLink := "/timeline" }} 379 <div class="{{ $contentStyle }}"> 380 <h3 class="{{ $titleStyle }}">Social coding is back</h3> 381 <p class="{{ $descriptionStyle }}"> 382 Discover trending projects, follow your friends and star your favourite repositories. Coding is better together! 383 </p> 384 <a href="{{ $moreLink }}" class="{{ $linkMobileStyle }}"> 385 Explore timeline 386 {{ i "arrow-right" "size-4" }} 387 </a> 388 </div> 389 <div class="{{ $iconContainerStyle }}"> 390 <div class="{{ $iconCircleStyle }} w-full h-full bg-amber-100 dark:bg-amber-900/50"> 391 {{ i "message-circle-heart" "size-12 md:size-24" "text-amber-500 dark:text-amber-500" "rotate-12" }} 392 </div> 393 <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"> 394 {{ i "users" "size-4 md:size-8" "text-amber-500 dark:text-amber-500" }} 395 </div> 396 <a href="{{ $moreLink }}" class="{{ $linkDesktopStyle }}"> 397 Explore timeline 398 {{ i "arrow-right" "size-4" }} 399 </a> 400 </div> 401 </div> 402 </div> 403 </div> 404{{ end }} 405 406{{ define "changelog" }} 407 <div class="w-full px-2 py-16 md:py-24"> 408 <h2 class="text-3xl md:text-4xl font-bold mb-8 text-gray-900 dark:text-gray-100">Changelog</h2> 409 410 <div class="grid grid-cols-1 gap-6 mb-6"> 411 {{ range $index := list 0 1 2 3 }} 412 <div class="bg-white dark:bg-gray-800 rounded shadow-sm border border-gray-200 dark:border-gray-700 p-6"> 413 <div class="flex items-center gap-2 mb-3"> 414 <span class="text-xs font-medium text-gray-500 dark:text-gray-400">v1.{{ sub 3 $index }}.0</span> 415 <span class="text-xs text-gray-400 dark:text-gray-500"></span> 416 <span class="text-xs text-gray-500 dark:text-gray-400">Feb {{ sub 16 $index }}, 2026</span> 417 </div> 418 <h3 class="text-lg font-semibold mb-2 text-gray-900 dark:text-gray-100">Feature Update {{ sub 4 $index }}</h3> 419 <p class="text-sm text-gray-600 dark:text-gray-300 leading-relaxed"> 420 Improvements to the platform including bug fixes, performance enhancements, and new features. 421 </p> 422 </div> 423 {{ end }} 424 </div> 425 426 <div class="flex justify-end"> 427 <a href="/changelog" class="hover:no-underline inline-flex items-center gap-2 px-4 py-2 text-base btn"> 428 View full changelog 429 {{ i "arrow-right" "size-4" }} 430 </a> 431 </div> 432 </div> 433{{ end }} 434 435{{ define "recentUpdates" }} 436 <div class="w-full px-2 py-16 md:py-24"> 437 <h2 class="px-4 text-3xl md:text-4xl font-bold text-gray-900 dark:text-gray-100 mb-2">Recent updates</h2> 438 <p class="px-4 mb-8 text-gray-500 dark:text-gray-400"> 439 Follow <a href="https://bsky.app/profile/tangled.org">@tangled.org</a> on Bluesky for more! 440 </p> 441 <div class="columns-1 md:columns-2 lg:columns-3 gap-6"> 442 {{ range $index, $post := .BlueskyPosts }} 443 <div class="{{ if ge $index 3 }}hidden md:block{{ end }}"> 444 {{ template "post" $post }} 445 </div> 446 {{ end }} 447 </div> 448 </div> 449{{ end }} 450 451{{ define "post" }} 452 <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"> 453 <div class="flex items-center justify-between text-sm text-gray-500 dark:text-gray-400"> 454 <span class="flex items-center gap-2"> 455 {{ template "user/fragments/picHandle" "tangled.org" }} 456 </span> 457 <span>{{ template "repo/fragments/shortTimeAgo" .CreatedAt }}</span> 458 </div> 459 <p class="text-gray-900 dark:text-gray-100 text-base leading-relaxed whitespace-pre-wrap">{{ .Text }}</p> 460 461 {{ if .Embed }} 462 {{ if .Embed.EmbedImages_View }} 463 <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"> 464 {{ range .Embed.EmbedImages_View.Images }} 465 <img src="{{ .Fullsize }}" alt="{{ .Alt }}" class="rounded w-full h-auto object-cover border border-gray-200 dark:border-gray-700" loading="lazy" /> 466 {{ end }} 467 </div> 468 {{ else if .Embed.EmbedExternal_View }} 469 <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"> 470 {{ if .Embed.EmbedExternal_View.External.Thumb }} 471 <img src="{{ .Embed.EmbedExternal_View.External.Thumb }}" alt="" class="w-full h-48 object-cover" loading="lazy" /> 472 {{ end }} 473 <div class="p-3"> 474 <div class="font-medium text-gray-900 dark:text-gray-100 text-sm mb-1">{{ .Embed.EmbedExternal_View.External.Title }}</div> 475 <div class="text-xs text-gray-600 dark:text-gray-400 line-clamp-2">{{ .Embed.EmbedExternal_View.External.Description }}</div> 476 <div class="text-xs text-gray-500 dark:text-gray-500 mt-1">{{ .Embed.EmbedExternal_View.External.Uri }}</div> 477 </div> 478 </a> 479 {{ else if .Embed.EmbedVideo_View }} 480 <div class="rounded overflow-hidden bg-gray-100 dark:bg-gray-700 aspect-video flex items-center justify-center"> 481 <span class="text-gray-500 dark:text-gray-400 text-sm">Video embed</span> 482 </div> 483 {{ end }} 484 {{ end }} 485 486 <a href="https://bsky.app/profile/tangled.org/post/{{ .Rkey }}" 487 target="_blank" 488 rel="noopener noreferrer" 489 class="flex items-center justify-between gap-4 text-sm text-gray-500 dark:text-gray-400 pt-2 no-underline hover:no-underline"> 490 <div class="flex items-center gap-4"> 491 <div class="flex items-center gap-1"> 492 {{ i "heart" "size-4" }} 493 <span>{{ .LikeCount }}</span> 494 </div> 495 <div class="flex items-center gap-1"> 496 {{ i "repeat-2" "size-4" }} 497 <span>{{ .RepostCount }}</span> 498 </div> 499 <div class="flex items-center gap-1"> 500 {{ i "message-square" "size-4 -scale-x-1" }} 501 <span>{{ add64 .ReplyCount .QuoteCount }}</span> 502 </div> 503 </div> 504 {{ i "arrow-up-right" "size-4" }} 505 </a> 506 </div> 507{{ end }} 508 509{{ define "community" }} 510 <div class="w-full px-2 py-16 md:py-24"> 511 <div class="max-w-2xl mx-auto text-center space-y-6"> 512 <h2 class="text-3xl md:text-6xl font-bold text-gray-900 dark:text-gray-100">Join the network</h2> 513 <p class="text-xl text-gray-600 dark:text-gray-300"> 514 You can participate in the Tangled network with an AT account. If you 515 don't know what that is, you can sign up for one below. 516 <br> 517 <a href="https://docs.tangled.org/quick-start-guide.html#login-or-sign-up">Read more on the docs.</a> 518 </p> 519 <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"> 520 <input 521 type="email" 522 id="email" 523 name="id" 524 tabindex="4" 525 required 526 placeholder="Enter your email" 527 class="py-2 w-full" 528 /> 529 <button class="btn-create flex items-center gap-2 text-base whitespace-nowrap" type="submit"> 530 join now 531 {{ i "arrow-right" "size-4" }} 532 </button> 533 </form> 534 </div> 535{{ end }}