Monorepo for Tangled tangled.org
10

Configure Feed

Select the types of activity you want to include in your feed.

1{{ define "repo/fragments/editLabelPanel" }} 2 <form 3 id="edit-label-panel" 4 hx-put="/{{ .RepoInfo.FullName }}/labels/perform" 5 hx-indicator="#spinner" 6 hx-disabled-elt="#save-btn,#cancel-btn" 7 hx-swap="none" 8 class="flex flex-col gap-6" 9 > 10 <input type="hidden" name="repo" value="{{ .RepoInfo.RepoAt }}"> 11 <input type="hidden" name="subject" value="{{ .Subject }}"> 12 {{ template "editBasicLabels" . }} 13 {{ template "editKvLabels" . }} 14 {{ template "editLabelPanelActions" . }} 15 <div id="add-label-error" class="text-red-500 dark:text-red-400"></div> 16 </form> 17{{ end }} 18 19{{ define "editBasicLabels" }} 20 {{ $defs := .Defs }} 21 {{ $subject := .Subject }} 22 {{ $state := .State }} 23 {{ $prefix := .Prefix }} 24 {{ $labelStyle := "flex items-center gap-2 rounded py-1 px-2 border border-gray-200 dark:border-gray-700 text-sm bg-white dark:bg-gray-800 text-black dark:text-white" }} 25 {{ $hasNullDefs := false }} 26 {{ range $k, $d := $defs }} 27 {{ if $d.ValueType.IsNull }}{{ $hasNullDefs = true }}{{ end }} 28 {{ end }} 29 {{ if or $hasNullDefs (not $defs) }} 30 <div> 31 {{ template "repo/fragments/labelSectionHeaderText" "Labels" }} 32 33 <div class="flex flex-col gap-1 items-start"> 34 {{ range $k, $d := $defs }} 35 {{ $isChecked := $state.ContainsLabel $k }} 36 {{ if $d.ValueType.IsNull }} 37 {{ $fieldName := $d.AtUri.String }} 38 {{ if $prefix }}{{ $fieldName = printf "%s[%s]" $prefix $d.AtUri }}{{ end }} 39 <label class="{{$labelStyle}}"> 40 <input type="checkbox" name="{{ $fieldName }}" value="null" {{if $isChecked}}checked{{end}}> 41 {{ template "labels/fragments/labelDef" $d }} 42 </label> 43 {{ end }} 44 {{ else }} 45 <p class="text-gray-500 dark:text-gray-400 text-sm py-1"> 46 No labels defined yet. You can choose default labels or define custom 47 labels in <a class="underline" href="/{{ $.RepoInfo.FullName }}/settings">settings</a>. 48 </p> 49 {{ end }} 50 </div> 51 </div> 52 {{ end }} 53{{ end }} 54 55{{ define "editKvLabels" }} 56 {{ $defs := .Defs }} 57 {{ $subject := .Subject }} 58 {{ $state := .State }} 59 {{ $prefix := .Prefix }} 60 {{ $groupSuffix := "" }} 61 {{ if $prefix }}{{ $groupSuffix = printf "-%s" $prefix }}{{ end }} 62 {{ $labelStyle := "font-normal normal-case flex items-center gap-2 p-0" }} 63 64 {{ range $k, $d := $defs }} 65 {{ if (not $d.ValueType.IsNull) }} 66 {{ $fieldName := $d.AtUri.String }} 67 {{ if $prefix }}{{ $fieldName = printf "%s[%s]" $prefix $d.AtUri }}{{ end }} 68 {{ $valset := $state.GetValSet $k }} 69 <div id="label-{{$d.Id}}{{ $groupSuffix }}" class="flex flex-col gap-1"> 70 {{ if not $d.ValueType.IsBool }} 71 {{ template "repo/fragments/labelSectionHeaderText" $d.Name }} 72 {{ end }} 73 {{ if (and $d.Multiple $d.ValueType.IsEnum) }} 74 <!-- checkbox --> 75 {{ range $variant := $d.ValueType.Enum }} 76 <label class="{{$labelStyle}}"> 77 <input type="checkbox" name="{{ $fieldName }}" value="{{$variant}}" {{if $state.ContainsLabelAndVal $k $variant}}checked{{end}}> 78 {{ $variant }} 79 </label> 80 {{ end }} 81 {{ else if $d.Multiple }} 82 <!-- dynamically growing input fields --> 83 {{ range $v, $s := $valset }} 84 {{ template "multipleInputField" (dict "def" $d "value" $v "key" $k "prefix" $prefix) }} 85 {{ else }} 86 {{ template "multipleInputField" (dict "def" $d "value" "" "key" $k "prefix" $prefix) }} 87 {{ end }} 88 {{ template "addFieldButton" (dict "def" $d "prefix" $prefix "groupSuffix" $groupSuffix) }} 89 {{ if and $.LoggedInUser $d.ValueType.IsString $d.ValueType.IsDidFormat }} 90 {{ template "assignToMeButton" (dict "def" $d "user" $.LoggedInUser "groupSuffix" $groupSuffix) }} 91 {{ end }} 92 {{ else if $d.ValueType.IsEnum }} 93 <!-- radio buttons --> 94 {{ $isUsed := $state.ContainsLabel $k }} 95 {{ range $variant := $d.ValueType.Enum }} 96 <label class="{{$labelStyle}}"> 97 <input type="radio" name="{{ $fieldName }}" value="{{$variant}}" {{if $state.ContainsLabelAndVal $k $variant}}checked{{end}}> 98 {{ $variant }} 99 </label> 100 {{ end }} 101 <label class="{{$labelStyle}}"> 102 <input type="radio" name="{{ $fieldName }}" value="" {{ if not $isUsed }}checked{{ end }}> 103 None 104 </label> 105 {{ else }} 106 <!-- single input field based on value type --> 107 {{ range $v, $s := $valset }} 108 {{ template "valueTypeInput" (dict "def" $d "value" $v "key" $k "prefix" $prefix) }} 109 {{ else }} 110 {{ template "valueTypeInput" (dict "def" $d "value" "" "key" $k "prefix" $prefix) }} 111 {{ end }} 112 {{ end }} 113 </div> 114 {{ end }} 115 {{ end }} 116{{ end }} 117 118{{ define "multipleInputField" }} 119 <div class="flex gap-1 items-stretch"> 120 <div class="flex-1 min-w-0"> 121 {{ template "valueTypeInput" . }} 122 </div> 123 {{ template "removeFieldButton" }} 124 </div> 125{{ end }} 126 127{{ define "assignToMeButton" }} 128 {{ $def := .def }} 129 {{ $user := .user }} 130 {{ $groupSuffix := .groupSuffix }} 131 {{ $handle := trimPrefix (resolve $user.Did) "@" }} 132 <button type="button" 133 data-assign-to-me="{{ $def.Id }}{{ $groupSuffix }}" 134 data-handle="{{ $handle }}" 135 onclick="(() => { 136 const group = document.getElementById('label-' + this.dataset.assignToMe); 137 const handle = this.dataset.handle; 138 const inputs = group.querySelectorAll('input[type=text]'); 139 const empty = Array.from(inputs).find(i => !i.value.trim()); 140 if (empty) { empty.value = handle; return; } 141 if (Array.from(inputs).some(i => i.value.trim() === handle)) return; 142 const tpl = document.getElementById('tpl-' + this.dataset.assignToMe); 143 if (!tpl) return; 144 const addBtn = tpl.nextElementSibling; 145 addBtn.insertAdjacentHTML('beforebegin', tpl.innerHTML); 146 const newInput = addBtn.previousElementSibling.querySelector('input[type=text]'); 147 if (newInput) newInput.value = handle; 148 })()" 149 class="text-xs text-gray-500 dark:text-gray-400 hover:underline self-end inline-flex items-center gap-1"> 150 {{ i "user-round-plus" "size-3.5" }} 151 Assign to me 152 </button> 153{{ end }} 154 155{{ define "addFieldButton" }} 156 {{ $def := .def }} 157 {{ $prefix := .prefix }} 158 {{ $groupSuffix := .groupSuffix }} 159 <div style="display:none" id="tpl-{{ $def.Id }}{{ $groupSuffix }}"> 160 {{ template "multipleInputField" (dict "def" $def "value" "" "key" $def.AtUri.String "prefix" $prefix) }} 161 </div> 162 <button type="button" onClick="this.insertAdjacentHTML('beforebegin', document.getElementById('tpl-{{ $def.Id }}{{ $groupSuffix }}').innerHTML)" class="w-full btn flex items-center gap-2"> 163 {{ i "plus" "size-4" }} Add 164 </button> 165{{ end }} 166 167{{ define "removeFieldButton" }} 168 <button type="button" onClick="this.parentElement.remove()" class="btn flex items-center gap-2 text-red-400 dark:text-red-500"> 169 {{ i "trash-2" "size-4" }} 170 </button> 171{{ end }} 172 173{{ define "valueTypeInput" }} 174 {{ $def := .def }} 175 {{ $valueType := $def.ValueType }} 176 {{ $value := .value }} 177 {{ $key := .key }} 178 179 {{ if $valueType.IsBool }} 180 {{ template "boolTypeInput" $ }} 181 {{ else if $valueType.IsInt }} 182 {{ template "intTypeInput" $ }} 183 {{ else if $valueType.IsString }} 184 {{ template "stringTypeInput" $ }} 185 {{ else if $valueType.IsNull }} 186 {{ template "nullTypeInput" $ }} 187 {{ end }} 188{{ end }} 189 190{{ define "boolTypeInput" }} 191 {{ $def := .def }} 192 {{ $prefix := .prefix }} 193 {{ $fieldName := $def.AtUri.String }} 194 {{ if $prefix }}{{ $fieldName = printf "%s[%s]" $prefix $def.AtUri }}{{ end }} 195 {{ $value := .value }} 196 {{ $isOn := eq $value "true" }} 197 <label class="font-normal normal-case flex items-center gap-2"> 198 <input type="checkbox" name="{{ $fieldName }}" value="true" {{ if $isOn }}checked{{ end }}> 199 {{ $def.Name }} 200 </label> 201{{ end }} 202 203{{ define "intTypeInput" }} 204 {{ $def := .def }} 205 {{ $prefix := .prefix }} 206 {{ $fieldName := $def.AtUri.String }} 207 {{ if $prefix }}{{ $fieldName = printf "%s[%s]" $prefix $def.AtUri }}{{ end }} 208 {{ $value := .value }} 209 <input class="p-1 w-full" type="number" name="{{$fieldName}}" value="{{$value}}"> 210{{ end }} 211 212{{ define "stringTypeInput" }} 213 {{ $def := .def }} 214 {{ $prefix := .prefix }} 215 {{ $fieldName := $def.AtUri.String }} 216 {{ if $prefix }}{{ $fieldName = printf "%s[%s]" $prefix $def.AtUri }}{{ end }} 217 {{ $valueType := $def.ValueType }} 218 {{ $value := .value }} 219 220 {{ if $valueType.IsDidFormat }} 221 {{ $value = trimPrefix (resolve .value) "@" }} 222 <actor-typeahead> 223 <input 224 autocapitalize="none" 225 autocorrect="off" 226 autocomplete="off" 227 placeholder="user.tngl.sh" 228 value="{{$value}}" 229 name="{{$fieldName}}" 230 type="text" 231 class="p-1 w-full h-full text-sm" 232 /> 233 </actor-typeahead> 234 {{ else }} 235 <input class="p-1 w-full" type="text" name="{{$fieldName}}" value="{{$value}}"> 236 {{ end }} 237{{ end }} 238 239{{ define "nullTypeInput" }} 240 {{ $def := .def }} 241 {{ $prefix := .prefix }} 242 {{ $fieldName := $def.AtUri.String }} 243 {{ if $prefix }}{{ $fieldName = printf "%s[%s]" $prefix $def.AtUri }}{{ end }} 244 <input class="p-1" type="hidden" name="{{$fieldName}}" value="null"> 245{{ end }} 246 247{{ define "editLabelPanelActions" }} 248 <div class="flex gap-2 pt-2"> 249 <button 250 id="cancel-btn" 251 type="button" 252 hx-get="/{{ .RepoInfo.FullName }}/label" 253 hx-vals='{"subject": "{{.Subject}}"}' 254 hx-swap="outerHTML" 255 hx-target="#edit-label-panel" 256 class="btn w-1/2 flex items-center gap-2 text-red-500 hover:text-red-700 dark:text-red-400 dark:hover:text-red-300 group"> 257 {{ i "x" "size-4" }} Cancel 258 </button> 259 260 <button 261 id="save-btn" 262 type="submit" 263 class="btn w-1/2 flex items-center"> 264 <span class="inline-flex gap-2 items-center">{{ i "check" "size-4" }} Save</span> 265 <span id="spinner" class="group"> 266 {{ i "loader-circle" "ml-2 w-4 h-4 animate-spin hidden group-[.htmx-request]:inline" }} 267 </span> 268 </button> 269 </div> 270{{ end }}