Nice little directory browser :D
1@*
2 This file is part of Utatane.
3
4 Utatane is free software: you can redistribute it and/or modify it under
5 the terms of the GNU Affero General Public License as published by the Free
6 Software Foundation, either version 3 of the License, or (at your option)
7 any later version.
8
9 Utatane is distributed in the hope that it will be useful, but WITHOUT ANY
10 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11 FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
12 more details.
13
14 You should have received a copy of the GNU Affero General Public License
15 along with Utatane. If not, see <http://www.gnu.org/licenses/>.
16*@
17
18@page "/{*Path:nonfile}"
19
20@* <PageTitle>Index</PageTitle> *@
21<HeadContent>
22 <script src="/.nhnd/_hyperscript.js"></script>
23 <script src="/.nhnd/_hs_tailwind.js"></script>
24
25 <script type="text/hyperscript">
26def get_dir(x)
27 if not x
28 return "descending"
29 otherwise
30 return "ascending"
31 end
32end
33
34behavior sort_table(property)
35 on click
36 -- wait 0.1s
37 remove @@aria-sort from <th/>
38
39 set target to the first <#prop-${property}/>
40 set dir_target to the first <input[name="sort-asc"]/>
41
42 if (target's checked is true)
43 set dir_target's checked to (not dir_target's checked)
44 otherwise
45 set <input[name=sort-by]/>'s checked to false
46 set dir_target's checked to true
47 set target's checked to true
48 end
49
50 set my @@aria-sort to get_dir((dir_target's checked))
51 send nhnd:run to me
52 end
53end
54 </script>
55</HeadContent>
56
57<Header Path="@Path" />
58
59@* redirect notice here... *@
60
61<div class="n-box flex flex-row">
62 <div id="main">
63 <form id="sorting-on" class="hidden">
64 <input autocomplete="off" type="text" name="path" value="@Path" id="prop-path" />
65
66 <input autocomplete="off" type="radio" name="sort-by" value="name" id="prop-name" checked/>
67 <input autocomplete="off" type="radio" name="sort-by" value="size" id="prop-size"/>
68 <input autocomplete="off" type="radio" name="sort-by" value="time" id="prop-time"/>
69
70 <input autocomplete="off" type="checkbox" name="sort-asc" checked/>
71 </form>
72
73 <table
74 id="filetable"
75 hx-swap="innerHtml"
76 hx-target="#filetable tbody"
77 hx-include="#sorting-on input"
78 hx-select="table tbody tr"
79 _="on htmx:afterSettle send nhnd:update to #file-counter"
80 >
81 <thead>
82 <tr>
83 @{ String InstallSort(String x) => $"install sort_table(property: '{x}') end"; }
84 <th id="filetable-head-dl" class="pointer-events-none" tabindex="0">
85 <span class="visually-hidden">Download link</span>
86 </th>
87
88 <th id="filetable-head-icon" class="pointer-events-none" tabindex="0">
89 <span class="visually-hidden">File type icon</span>
90 </th>
91
92 <th id="filetable-head-name"
93 hx-get="/api/files"
94 hx-trigger="load from:document, nhnd:run"
95 hx-indicator="#filetable-body, #name-spinner, #filetable-head-name"
96 aria-sort="ascending"
97 _="@InstallSort("name")"
98 >
99 <div>
100 <span class="header-label">
101 Name
102 <span id="name-spinner" class="spinner" />
103 </span>
104 </div>
105 </th>
106
107 <th id="filetable-head-size"
108 hx-get="/api/files"
109 hx-trigger="nhnd:run"
110 hx-indicator="#filetable-body, #name-spinner, #filetable-head-size"
111 _="@InstallSort("size")"
112 >
113 <div>
114 <span class="header-label">
115 Size
116 <span id="size-spinner" class="spinner" />
117 </span>
118 </div>
119 </th>
120
121 <th id="filetable-head-time"
122 hx-get="/api/files"
123 hx-trigger="nhnd:run"
124 hx-indicator="#filetable-body, #name-spinner, #filetable-head-time"
125 _="@InstallSort("time")"
126 >
127 <div>
128 <span class="header-label">
129 Time
130 <span id="time-spinner" class="spinner" />
131 </span>
132 </div>
133 </th>
134 </tr>
135 </thead>
136 <tbody id="filetable-body"
137 class="htmx-indicator"
138 hx-swap="scroll:top"
139 _="on htmx:beforeRequest(target) set #prop-path's value to the target"
140 >
141 @* pregen rows to prevent massive layout shift *@
142 @foreach (FileSystemInfo fsi in _joinedPath.EnumerateFileSystemInfos()) {
143 <tr>
144 <td />
145 <td />
146 <td>@( "\u00A0" )</td>
147 <td />
148 <td />
149 </tr>
150 }
151 </tbody>
152 </table>
153 </div>
154</div>
155
156
157@code {
158 [Parameter]
159 public required String Path {
160 get;
161 set => field = $"/{value}";
162 }
163
164 private DirectoryInfo _joinedPath;
165
166 protected override Task OnInitializedAsync() {
167 // we checked in middleware dw
168 _joinedPath = Utils.VerifyPath(Path).Value.AsT1();
169
170 return base.OnInitializedAsync();
171 }
172
173}