Created
June 5, 2025 01:56
-
-
Save delaneyj/205e51ddb7d5d5e87071ddcf3375d256 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package examples | |
import ( | |
"github.com/XANi/loremipsum" | |
"github.com/go-chi/chi/v5" | |
. "github.com/starfederation/datastar-dev/site/shared" | |
datastar "github.com/starfederation/datastar/sdk/go" | |
"math/rand/v2" | |
"net/http" | |
"time" | |
) | |
func setupProgressiveLOD(examplesRouter chi.Router) { | |
lorem := loremipsum.New() | |
examplesRouter.Route("/progressive_lod", func(progressiveLODRouter chi.Router) { | |
progressiveLODRouter.Get("/", func(w http.ResponseWriter, r *http.Request) { | |
RenderPage(progressiveLOD(), w, r) | |
}) | |
progressiveLODRouter.Get("/updates", func(w http.ResponseWriter, r *http.Request) { | |
sse := datastar.NewSSE(w, r, datastar.WithCompression()) | |
sse.MergeFragmentTempl(progressiveLODEmpty()) | |
components := []templ.Component{ | |
progressiveLODHeaderContent(), | |
progressiveLODArticleContent("This is my article"), | |
progressiveLODCommentsContent(), | |
progressiveLODFooterContent(), | |
} | |
rand.Shuffle(len(components), func(i, j int) { | |
components[i], components[j] = components[j], components[i] | |
}) | |
for _, c := range components { | |
sse.MergeFragmentTempl(c) | |
time.Sleep(500 * time.Millisecond) | |
} | |
sse.MergeFragmentTempl(progressiveLODArticleBody(lorem.Paragraphs(2))) | |
commentCount := rand.IntN(5) + 5 | |
for i := 0; i < commentCount; i++ { | |
comment := lorem.Sentence() | |
avatarUrl := "https://avatar.iran.liara.run/username?username=" + lorem.Word() | |
c := progressiveLODCommentItem(i+1, comment, avatarUrl) | |
sse.MergeFragmentTempl( | |
c, | |
datastar.WithSelectorID("comments-list"), | |
datastar.WithMergeAppend(), | |
) | |
time.Sleep(250 * time.Millisecond) | |
} | |
sse.MergeFragmentTempl(progressiveLODLoadButton()) | |
}) | |
}) | |
} | |
templ progressiveLODArticleBody(content string) { | |
<section id="articleBody"> | |
<p> | |
{content} | |
</p> | |
</section> | |
} | |
templ progressiveLOD() { | |
@page("progressive_lod") { | |
@Heading("Explanation") | |
<p> | |
This is a response to <a href="https://overreacted.io/progressive-json/">Dan Abramov's article on progressive JSON</a>. I think it's overcomplicated and show a lack of understanding of how powerful native hypermedia is. | |
</p> | |
@Subheading("Note") | |
<p> | |
This example shows how to progressively load a page using Datastar. The page is divided into sections. We already have examples of <a href="/examples/infinite_scroll">infinite scroll</a> and <a href="/examples/progress_bar">progress bar</a>, but this example shows how to progressively load a page in a more structured way. | |
</p> | |
<p> | |
It's truly baffling to me the amount of complexity that React developers tend to introduces. Hypermedia is a powerful tool that allows you to progressively load content in a way that is simple and efficient. This example shows how to use Datastar's server-sent events (SSE) to progressively load a page in a way that is easy to understand and maintain. | |
</p> | |
<p> | |
Nothing is faster than direct HTML morphing without a virtual DOM, let the browser do the heavy lifting. This example shows how to use Datastar's templating system to progressively load a page in a way that is simple and efficient while only using a one-time cost CDN shim. | |
</p> | |
@Demo() { | |
@progressiveLODDemoContents() | |
} | |
} | |
} | |
templ progressiveLODDemoContents() { | |
<style> | |
#lod { | |
display: grid; | |
background-color: var(--gray-1); | |
grid-template-areas: | |
"header header" | |
"article comments" | |
"footer footer"; | |
grid-template-rows: auto 1fr auto auto; | |
grid-template-columns: auto 1fr auto; | |
height: 100%; | |
border: 1px solid var(--gray-6); | |
} | |
#header{ | |
grid-area: header; | |
background-color: var(--gray-2); | |
padding: 1rem; | |
box-shadow: var(--shadow-2); | |
} | |
#article { | |
grid-area: article; | |
padding: 1rem; | |
background-color: var(--gray-3); | |
} | |
#comments { | |
grid-area: comments; | |
padding: 1rem; | |
background-color: var(--gray-4); | |
ul { | |
display: flex; | |
flex-direction: column; | |
gap: var(--size-2); | |
} | |
li { | |
font-size: var(--font-size-0); | |
list-style: none; | |
} | |
.avatar { | |
float:left; | |
margin-right: var(--size-4); | |
width: var(--size-8); | |
aspect-ratio: var(--aspect-square); | |
border-radius: 50%; | |
margin-right: 1rem; | |
} | |
} | |
#footer { | |
grid-area: footer; | |
background-color: var(--gray-5); | |
padding: 1rem; | |
} | |
</style> | |
<div> | |
@progressiveLODLoadButton() | |
<p> | |
Each part is loaded randomly and progressively. | |
</p> | |
</div> | |
@progressiveLODEmpty() | |
} | |
templ progressiveLODLoadButton() { | |
<button | |
id="load-button" | |
data-signals-load-disabled="false" | |
data-on-click="$loadDisabled=true; @get('/examples/progressive_lod/updates')" | |
data-attr-disabled="$loadDisabled" | |
> | |
Load | |
</button> | |
} | |
templ progressiveLODEmpty() { | |
<div id="lod"> | |
<header id="header"></header> | |
<section id="article"></section> | |
<section id="comments"></section> | |
<div id="footer"></div> | |
</div> | |
} | |
templ progressiveLODHeaderContent() { | |
<header id="header">Welcome to my blog</header> | |
} | |
templ progressiveLODArticleContent(title string) { | |
<section id="article"> | |
<h4>{ title }</h4> // This is my article | |
<section id="articleBody"></section> | |
</section> | |
} | |
templ progressiveLODCommentsContent() { | |
<section id="comments"> | |
<h5>Comments</h5> | |
<p> | |
This is the comments section. It will also be progressively loaded as you scroll down. | |
</p> | |
<ul id="comments-list"></ul> | |
</section> | |
} | |
templ progressiveLODCommentItem(id int, comment, avatarUrl string) { | |
<li id={ id }> | |
<img src={ avatarUrl } alt="Avatar" class="avatar" /> | |
{ comment } | |
</li> | |
} | |
templ progressiveLODFooterContent() { | |
<div id="footer">Hope you like it</div> | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment