forked from tangled.org/core
Monorepo for Tangled — https://tangled.org

appview: add spinners to all buttons

how it works:

- hx-indicator adds the htmx-request class to the target of choice
- with tailwind, we can use `group-[.class]` to check if a parent
element has a certain class, and style things conditionally
- by applying `group-[.htmx-request]`, we can detect when a request is
in progress, and show/hide a lucide loader
- the loader is a static icon made to spin using the `animate-spin`
class

Changed files
+60 -31
appview
pages
templates
+1
appview/pages/templates/layouts/base.html
···
name="viewport"
content="width=device-width, initial-scale=1.0"
/>
+
<meta name="htmx-config" content='{"includeIndicatorStyles": false}'>
<script src="/static/htmx.min.js"></script>
<link rel="stylesheet" href="/static/tw.css?{{ cssContentHash }}" type="text/css" />
<title>{{ block "title" . }}{{ end }} · tangled</title>
+13 -12
appview/pages/templates/repo/fragments/repoActions.html
···
<div class="flex items-center gap-2 z-auto">
<button
id="starBtn"
-
class="btn disabled:opacity-50 disabled:cursor-not-allowed"
+
class="btn disabled:opacity-50 disabled:cursor-not-allowed flex gap-2 items-center group"
{{ if .IsStarred }}
hx-delete="/star?subject={{ .RepoAt }}&countHint={{ .Stats.StarCount }}"
{{ else }}
···
hx-swap="outerHTML"
hx-disabled-elt="#starBtn"
>
-
<div class="flex gap-2 items-center">
-
{{ if .IsStarred }}
-
{{ i "star" "w-4 h-4 fill-current" }}
-
{{ else }}
-
{{ i "star" "w-4 h-4" }}
-
{{ end }}
-
<span class="text-sm">
-
{{ .Stats.StarCount }}
-
</span>
-
</div>
+
{{ if .IsStarred }}
+
{{ i "star" "w-4 h-4 fill-current" }}
+
{{ else }}
+
{{ i "star" "w-4 h-4" }}
+
{{ end }}
+
<span class="text-sm">
+
{{ .Stats.StarCount }}
+
</span>
+
{{ i "loader-circle" "w-4 h-4 animate-spin hidden group-[.htmx-request]:inline" }}
</button>
{{ if .DisableFork }}
<button
···
</button>
{{ else }}
<a
-
class="btn text-sm no-underline hover:no-underline flex items-center gap-2"
+
class="btn text-sm no-underline hover:no-underline flex items-center gap-2 group"
+
hx-boost="true"
href="/{{ .FullName }}/fork"
>
{{ i "git-fork" "w-4 h-4" }}
fork
+
{{ i "loader-circle" "w-4 h-4 animate-spin hidden group-[.htmx-request]:inline" }}
</a>
{{ end }}
</div>
+7 -2
appview/pages/templates/repo/new.html
···
<p class="text-xl font-bold dark:text-white">Create a new repository</p>
</div>
<div class="p-6 bg-white dark:bg-gray-800 drop-shadow-sm rounded">
-
<form hx-post="/repo/new" class="space-y-12" hx-swap="none">
+
<form hx-post="/repo/new" class="space-y-12" hx-swap="none" hx-indicator="#spinner">
<div class="space-y-2">
<label for="name" class="-mb-1 dark:text-white">Repository name</label>
<input
···
</fieldset>
<div class="space-y-2">
-
<button type="submit" class="btn">create repo</button>
+
<button type="submit" class="btn flex gap-2 items-center">
+
create repo
+
<span id="spinner" class="group">
+
{{ i "loader-circle" "w-4 h-4 animate-spin hidden group-[.htmx-request]:inline" }}
+
</span>
+
</button>
<div id="repo" class="error"></div>
</div>
</form>
+14 -9
appview/pages/templates/repo/pulls/fragments/pullActions.html
···
hx-get="/{{ .RepoInfo.FullName }}/pulls/{{ .Pull.PullId }}/round/{{ $roundNumber }}/comment"
hx-target="#actions-{{$roundNumber}}"
hx-swap="outerHtml"
-
class="btn p-2 flex items-center gap-2 no-underline hover:no-underline">
+
class="btn p-2 flex items-center gap-2 no-underline hover:no-underline group">
{{ i "message-square-plus" "w-4 h-4" }}
<span>comment</span>
+
{{ i "loader-circle" "w-4 h-4 animate-spin hidden group-[.htmx-request]:inline" }}
</button>
{{ if and $isPushAllowed $isOpen $isLastRound }}
{{ $disabled := "" }}
···
hx-post="/{{ .RepoInfo.FullName }}/pulls/{{ .Pull.PullId }}/merge"
hx-swap="none"
hx-confirm="Are you sure you want to merge pull #{{ .Pull.PullId }} into the `{{ .Pull.TargetBranch }}` branch?"
-
class="btn p-2 flex items-center gap-2" {{ $disabled }}>
+
class="btn p-2 flex items-center gap-2 group" {{ $disabled }}>
{{ i "git-merge" "w-4 h-4" }}
-
<span>merge</span>
+
<span>merge</span>
+
{{ i "loader-circle" "w-4 h-4 animate-spin hidden group-[.htmx-request]:inline" }}
</button>
{{ end }}
···
{{ end }}
hx-disabled-elt="#resubmitBtn"
-
class="btn p-2 flex items-center gap-2 disabled:opacity-50 disabled:cursor-not-allowed" {{ $disabled }}
+
class="btn p-2 flex items-center gap-2 disabled:opacity-50 disabled:cursor-not-allowed group" {{ $disabled }}
{{ if $disabled }}
title="Update this branch to resubmit this pull request"
···
title="Resubmit this pull request"
{{ end }}
>
-
{{ i "rotate-ccw" "w-4 h-4" }}
+
{{ i "rotate-ccw" "w-4 h-4" }}
<span>resubmit</span>
+
{{ i "loader-circle" "w-4 h-4 animate-spin hidden group-[.htmx-request]:inline" }}
</button>
{{ end }}
···
<button
hx-post="/{{ .RepoInfo.FullName }}/pulls/{{ .Pull.PullId }}/close"
hx-swap="none"
-
class="btn p-2 flex items-center gap-2">
-
{{ i "ban" "w-4 h-4" }}
+
class="btn p-2 flex items-center gap-2 group">
+
{{ i "ban" "w-4 h-4" }}
<span>close</span>
+
{{ i "loader-circle" "w-4 h-4 animate-spin hidden group-[.htmx-request]:inline" }}
</button>
{{ end }}
···
<button
hx-post="/{{ .RepoInfo.FullName }}/pulls/{{ .Pull.PullId }}/reopen"
hx-swap="none"
-
class="btn p-2 flex items-center gap-2">
-
{{ i "refresh-ccw-dot" "w-4 h-4" }}
+
class="btn p-2 flex items-center gap-2 group">
+
{{ i "refresh-ccw-dot" "w-4 h-4" }}
<span>reopen</span>
+
{{ i "loader-circle" "w-4 h-4 animate-spin hidden group-[.htmx-request]:inline" }}
</button>
{{ end }}
</div>
+8 -4
appview/pages/templates/repo/pulls/pull.html
···
</span>
</div>
-
<a class="btn flex items-center gap-2 no-underline hover:no-underline p-2"
+
<a class="btn flex items-center gap-2 no-underline hover:no-underline p-2 group"
hx-boost="true"
href="/{{ $.RepoInfo.FullName }}/pulls/{{ $.Pull.PullId }}/round/{{.RoundNumber}}">
-
{{ i "file-diff" "w-4 h-4" }} <span class="hidden md:inline">diff</span>
+
{{ i "file-diff" "w-4 h-4" }}
+
<span class="hidden md:inline">diff</span>
+
{{ i "loader-circle" "w-4 h-4 animate-spin hidden group-[.htmx-request]:inline" }}
</a>
{{ if not (eq .RoundNumber 0) }}
-
<a class="btn flex items-center gap-2 no-underline hover:no-underline p-2"
+
<a class="btn flex items-center gap-2 no-underline hover:no-underline p-2 group"
hx-boost="true"
href="/{{ $.RepoInfo.FullName }}/pulls/{{ $.Pull.PullId }}/round/{{.RoundNumber}}/interdiff">
-
{{ i "chevrons-left-right-ellipsis" "w-4 h-4 rotate-90" }} <span class="hidden md:inline">interdiff</span>
+
{{ i "chevrons-left-right-ellipsis" "w-4 h-4 rotate-90" }}
+
<span class="hidden md:inline">interdiff</span>
+
{{ i "loader-circle" "w-4 h-4 animate-spin hidden group-[.htmx-request]:inline" }}
</a>
<span id="interdiff-error-{{.RoundNumber}}"></span>
{{ end }}
+5 -1
appview/pages/templates/user/fragments/editBio.html
···
hx-post="/profile/bio"
class="flex flex-col gap-4 my-2 max-w-full"
hx-disabled-elt="#save-btn,#cancel-btn"
-
hx-swap="none">
+
hx-swap="none"
+
hx-indicator="#spinner">
<div class="flex flex-col gap-1">
{{ $description := "" }}
{{ if and .Profile .Profile.Description }}
···
<div class="flex items-center gap-2 justify-between">
<button id="save-btn" type="submit" class="btn p-1 w-full flex items-center gap-2 no-underline text-sm">
{{ i "check" "size-4" }} save
+
<span id="spinner" class="group">
+
{{ i "loader-circle" "w-4 h-4 animate-spin hidden group-[.htmx-request]:inline" }}
+
</span>
</button>
<a href="/{{.LoggedInUser.Did}}" class="w-full no-underline hover:no-underline">
<button id="cancel-btn" type="button" class="btn p-1 w-full flex items-center gap-2 no-underline text-sm">
+5 -1
appview/pages/templates/user/fragments/editPins.html
···
<form
hx-post="/profile/pins"
hx-disabled-elt="#save-btn,#cancel-btn"
-
hx-swap="none">
+
hx-swap="none"
+
hx-indicator="#spinner">
<div class="flex items-center justify-between mb-2">
<p class="text-sm font-bold p-2 dark:text-white">SELECT PINNED REPOS</p>
<div class="flex items-center gap-2">
<button id="save-btn" type="submit" class="btn px-2 flex items-center gap-2 no-underline text-sm">
{{ i "check" "w-3 h-3" }} save
+
<span id="spinner" class="group">
+
{{ i "loader-circle" "w-3 h-3 animate-spin hidden group-[.htmx-request]:inline" }}
+
</span>
</button>
<a href="/{{.LoggedInUser.Did}}" class="w-full no-underline hover:no-underline">
<button id="cancel-btn" type="button" class="btn px-2 w-full flex items-center gap-2 no-underline text-sm">
+2 -1
appview/pages/templates/user/fragments/profileCard.html
···
{{ template "user/fragments/follow" . }}
{{ else }}
<button id="editBtn"
-
class="btn mt-2 w-full flex items-center gap-2"
+
class="btn mt-2 w-full flex items-center gap-2 group"
hx-target="#profile-bio"
hx-get="/profile/edit-bio"
hx-swap="innerHTML">
{{ i "pencil" "w-4 h-4" }}
edit
+
{{ i "loader-circle" "w-4 h-4 animate-spin hidden group-[.htmx-request]:inline" }}
</button>
{{ end }}
</div>
+5 -1
appview/pages/templates/user/profile.html
···
</span>
</a>
{{ if and .LoggedInUser (eq .LoggedInUser.Did .Card.UserDid) }}
-
<button hx-get="profile/edit-pins" hx-target="#all-repos" class="btn font-normal text-sm flex gap-2 items-center">
+
<button
+
hx-get="profile/edit-pins"
+
hx-target="#all-repos"
+
class="btn font-normal text-sm flex gap-2 items-center group">
{{ i "pencil" "w-3 h-3" }}
edit
+
{{ i "loader-circle" "w-4 h-4 animate-spin hidden group-[.htmx-request]:inline" }}
</button>
{{ end }}
</div>