A vibe coded tangled fork which supports pijul.
at d0acfc930f3d0ca8f918cdc443d0278dcdc7e0d0 542 lines 27 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 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 }}