A vibe coded tangled fork which supports pijul.
1{{ define "strings/fragments/form" }}
2 <form
3 {{ if eq .Action "new" }}
4 hx-post="/strings/new"
5 {{ else }}
6 hx-post="/strings/{{ .String.Did }}/{{ .String.Rkey }}/edit"
7 {{ end }}
8 hx-indicator="#new-button"
9 class="p-6 pb-4 dark:text-white flex flex-col gap-2 bg-white dark:bg-gray-800 drop-shadow-sm rounded"
10 hx-swap="none">
11 <div class="flex flex-col md:flex-row md:items-center gap-2">
12 <input
13 type="text"
14 id="filename"
15 name="filename"
16 placeholder="Filename with extension"
17 required
18 value="{{ .String.Filename }}"
19 class="md:max-w-64 dark:bg-gray-700 dark:text-white dark:border-gray-600 dark:placeholder-gray-400 px-3 py-2 border rounded" />
20 <input
21 type="text"
22 id="description"
23 name="description"
24 value="{{ .String.Description }}"
25 placeholder="Description ..."
26 class="flex-1 dark:bg-gray-700 dark:text-white dark:border-gray-600 dark:placeholder-gray-400 px-3 py-2 border rounded" />
27 </div>
28 <textarea
29 name="content"
30 id="content-textarea"
31 wrap="off"
32 class="w-full dark:bg-gray-700 dark:text-white dark:border-gray-600 dark:placeholder-gray-400"
33 rows="20"
34 placeholder="Paste your string here!"
35 required>
36{{ .String.Contents }}</textarea
37 >
38 <div class="flex justify-between items-center">
39 <div id="content-stats" class="text-sm text-gray-500 dark:text-gray-400">
40 <span id="line-count">0 lines</span>
41 <span class="select-none px-1 [&:before]:content-['·']"></span>
42 <span id="byte-count">0 bytes</span>
43 </div>
44 <div id="actions" class="flex gap-2 items-center">
45 {{ if eq .Action "edit" }}
46 <a
47 class="btn flex items-center gap-2 no-underline hover:no-underline p-2 group text-red-500 hover:text-red-700 dark:text-red-400 dark:hover:text-red-300 "
48 href="/strings/{{ .String.Did }}/{{ .String.Rkey }}">
49 {{ i "x" "size-4" }}
50 <span class="hidden md:inline">cancel</span>
51 {{ i "loader-circle" "w-4 h-4 animate-spin hidden group-[.htmx-request]:inline" }}
52 </a>
53 {{ end }}
54 <button
55 type="submit"
56 id="new-button"
57 class="w-fit btn-create rounded flex items-center py-0 dark:bg-gray-700 dark:text-white dark:hover:bg-gray-600 group">
58 <span class="inline-flex items-center gap-2">
59 {{ i "arrow-up" "w-4 h-4" }}
60 publish
61 </span>
62 <span class="pl-2 hidden group-[.htmx-request]:inline">
63 {{ i "loader-circle" "w-4 h-4 animate-spin" }}
64 </span>
65 </button>
66 </div>
67 </div>
68 <script>
69 (function () {
70 const textarea = document.getElementById("content-textarea");
71 const lineCount = document.getElementById("line-count");
72 const byteCount = document.getElementById("byte-count");
73 function updateStats() {
74 const content = textarea.value;
75 const lines = content === "" ? 0 : content.split("\n").length;
76 const bytes = new TextEncoder().encode(content).length;
77 lineCount.textContent = `${lines} line${lines !== 1 ? "s" : ""}`;
78 byteCount.textContent = `${bytes} byte${bytes !== 1 ? "s" : ""}`;
79 }
80 textarea.addEventListener("input", updateStats);
81 textarea.addEventListener("paste", () => {
82 setTimeout(updateStats, 0);
83 });
84 updateStats();
85 })();
86 </script>
87 <div id="error" class="error dark:text-red-400"></div>
88 </form>
89{{ end }}