55{% block title_extra %}{{ user.name }}{% endblock %}
66
77{% block content %}
8- < header class ="grid gap-y-4 mb-4 mt-6 py-4 border-b border-b-slate-300 ">
8+ < header class ="grid gap-y-4 mb-4 mt-6 py-8 border-b border-b-slate-300 ">
99 < h1 class ="text-2xl max-w-prose tracking-tight wrap-break-word md:text-4xl font-bold text-slate-900 ">
1010 Hello, {{ user.name }}
1111 </ h1 >
@@ -18,30 +18,52 @@ <h1 class="text-2xl max-w-prose tracking-tight wrap-break-word md:text-4xl font-
1818
1919{% block full_width_content %}
2020 < div class ="px-4 sm:px-6 lg:px-8 pt-6 pb-24 ">
21- < h2 class ="text-2xl/tight font-bold text-slate-900 "> Your codelists</ h2 >
22- < p class ="mt-2 text-base/snug text-slate-700 "> A list of all the the codelists you have access to edit, update, and publish.</ p >
21+ < div class ="container ">
22+ < h2 class ="text-2xl/tight font-bold text-slate-900 "> Your codelists</ h2 >
23+ < p class ="mt-2 text-base/snug text-slate-700 "> A list of all the the codelists you have access to edit, update, and publish.</ p >
24+ </ div >
2325 < div class ="mt-8 flow-root ">
2426 < div class ="-mx-4 -my-2 overflow-x-auto sm:-mx-6 lg:-mx-8 ">
2527 < div class ="inline-block min-w-full py-2 align-middle sm:px-6 lg:px-8 ">
2628 < div class ="overflow-hidden shadow-sm outline-1 outline-black/5 sm:rounded-lg dark:shadow-none dark:-outline-offset-1 dark:outline-white/10 ">
2729 < table class ="relative min-w-full divide-y divide-slate-200 ">
2830 < thead class ="bg-slate-100 text-left text-sm font-semibold text-slate-900 border-b-slate-300 ">
2931 < tr class ="align-bottom ">
30- < th class ="py-3.5 pr-3 pl-4 whitespace-nowrap sm:pl-6 " rowspan ="2 ">
31- < div class ="inline-flex items-center gap-x-1 ">
32- Name
33- < button
34- id ="sort-codelists-by-name "
35- type ="button "
36- aria-label ="Sort codelists by name "
37- aria-pressed ="false "
38- class ="ml-2 flex-none cursor-pointer rounded-sm bg-gray-200 text-gray-900 transition-colors hover:bg-gray-300 "
32+ < th id ="name-column-heading " class ="py-3.5 pr-3 pl-4 whitespace-nowrap sm:pl-6 " rowspan ="2 ">
33+ < button
34+ id ="sort-codelists-by-name "
35+ type ="button "
36+ aria-label ="Sort codelists by name "
37+ aria-pressed ="false "
38+ class ="group inline-flex items-center gap-x-1 cursor-pointer rounded-sm focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-slate-400 "
39+ >
40+ < span > Name</ span >
41+ < svg
42+ viewBox ="0 0 24 24 "
43+ fill ="none "
44+ stroke ="currentColor "
45+ stroke-width ="1.5 "
46+ aria-hidden ="true "
47+ data-sort-icon ="unsorted "
48+ class ="size-5 text-gray-400 "
49+ >
50+ < path
51+ stroke-linecap ="round "
52+ stroke-linejoin ="round "
53+ d ="M3 7.5 7.5 3m0 0L12 7.5M7.5 3v13.5m13.5 0L16.5 21m0 0L12 16.5m4.5 4.5V7.5 "
54+ />
55+ </ svg >
56+ < svg
57+ viewBox ="0 0 20 20 "
58+ fill ="currentColor "
59+ data-slot ="icon "
60+ aria-hidden ="true "
61+ data-sort-icon ="direction "
62+ class ="hidden size-5 rounded-sm transition-transform "
3963 >
40- < svg viewBox ="0 0 20 20 " fill ="currentColor " data-slot ="icon " aria-hidden ="true " class ="size-5 ">
41- < path d ="M5.22 8.22a.75.75 0 0 1 1.06 0L10 11.94l3.72-3.72a.75.75 0 1 1 1.06 1.06l-4.25 4.25a.75.75 0 0 1-1.06 0L5.22 9.28a.75.75 0 0 1 0-1.06Z " clip-rule ="evenodd " fill-rule ="evenodd " />
42- </ svg >
43- </ button >
44- </ div >
64+ < path d ="M5.22 8.22a.75.75 0 0 1 1.06 0L10 11.94l3.72-3.72a.75.75 0 1 1 1.06 1.06l-4.25 4.25a.75.75 0 0 1-1.06 0L5.22 9.28a.75.75 0 0 1 0-1.06Z " clip-rule ="evenodd " fill-rule ="evenodd " />
65+ </ svg >
66+ </ button >
4567 </ th >
4668 < th class ="px-3 py-3.5 whitespace-nowrap " rowspan ="2 "> Owner</ th >
4769 < th class ="px-3 py-3.5 whitespace-nowrap " rowspan ="2 "> Coding system</ th >
@@ -51,38 +73,58 @@ <h2 class="text-2xl/tight font-bold text-slate-900">Your codelists</h2>
5173 < th class ="px-3 py-3.5 whitespace-nowrap "> Version ID</ th >
5274 < th class ="px-3 py-3.5 whitespace-nowrap "> Status</ th >
5375 < th class ="px-3 py-3.5 whitespace-nowrap "> Number of codes</ th >
54- < th class ="px-3 py-3.5 whitespace-nowrap pl-3 sm:pr-3 ">
55- < div class ="inline-flex items-center gap-x-1 ">
56- Last updated
57- < button
58- id ="sort-codelists-by-date "
59- type ="button "
60- aria-label ="Sort codelists by date "
61- aria-pressed ="false "
62- class ="ml-2 flex-none cursor-pointer rounded-sm bg-gray-200 text-gray-900 transition-colors hover:bg-gray-300 "
76+ < th id ="date-column-heading " class ="px-3 py-3.5 whitespace-nowrap pl-3 sm:pr-3 ">
77+ < button
78+ id ="sort-codelists-by-date "
79+ type ="button "
80+ aria-label ="Sort codelists by date "
81+ aria-pressed ="false "
82+ class ="group inline-flex items-center gap-x-1 cursor-pointer rounded-sm focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-slate-400 "
83+ >
84+ < span > Last updated</ span >
85+ < svg
86+ viewBox ="0 0 24 24 "
87+ fill ="none "
88+ stroke ="currentColor "
89+ stroke-width ="1.5 "
90+ aria-hidden ="true "
91+ data-sort-icon ="unsorted "
92+ class ="size-5 text-gray-400 "
93+ >
94+ < path
95+ stroke-linecap ="round "
96+ stroke-linejoin ="round "
97+ d ="M3 7.5 7.5 3m0 0L12 7.5M7.5 3v13.5m13.5 0L16.5 21m0 0L12 16.5m4.5 4.5V7.5 "
98+ />
99+ </ svg >
100+ < svg
101+ viewBox ="0 0 20 20 "
102+ fill ="currentColor "
103+ data-slot ="icon "
104+ aria-hidden ="true "
105+ data-sort-icon ="direction "
106+ class ="hidden size-5 rounded-sm transition-transform "
63107 >
64- < svg viewBox ="0 0 20 20 " fill ="currentColor " data-slot ="icon " aria-hidden ="true " class ="size-5 ">
65- < path d ="M5.22 8.22a.75.75 0 0 1 1.06 0L10 11.94l3.72-3.72a.75.75 0 1 1 1.06 1.06l-4.25 4.25a.75.75 0 0 1-1.06 0L5.22 9.28a.75.75 0 0 1 0-1.06Z " clip-rule ="evenodd " fill-rule ="evenodd " />
66- </ svg >
67- </ button >
68- </ div >
108+ < path d ="M5.22 8.22a.75.75 0 0 1 1.06 0L10 11.94l3.72-3.72a.75.75 0 1 1 1.06 1.06l-4.25 4.25a.75.75 0 0 1-1.06 0L5.22 9.28a.75.75 0 0 1 0-1.06Z " clip-rule ="evenodd " fill-rule ="evenodd " />
109+ </ svg >
110+ </ button >
69111 </ th >
70112 </ tr >
71113 </ thead >
72114 {% for item in all_codelists %}
73115 {% if item.versions|length == 1 %}
74- < tbody class ="bg-white even:bg-slate-50 hover:bg-yellow-50 ">
116+ < tbody class ="bg-white even:bg-slate-50 group ">
75117 {% with version=item.versions.0 %}
76118 < tr class ="text-sm text-slate-900 ">
77- < td class ="py-4 pr-3 pl-4 text-base/snug font-semibold sm:pl-6 "> {{ item.codelist.name }}</ td >
78- < td class ="px-3 py-4 "> {{ item.codelist.owner }}</ td >
79- < td class ="px-3 py-4 whitespace-nowrap "> {{ item.codelist.coding_system_short_name }}</ td >
80- < td class ="px-3 py-4 ">
119+ < td class ="name-sort-column py-4 pr-3 group-hover:bg-yellow-50 pl-4 text-base/snug font-semibold sm:pl-6 "> {{ item.codelist.name }}</ td >
120+ < td class ="px-3 py-4 group-hover:bg-yellow-50 "> {{ item.codelist.owner }}</ td >
121+ < td class ="px-3 py-4 group-hover:bg-yellow-50 whitespace-nowrap "> {{ item.codelist.coding_system_short_name }}</ td >
122+ < td class ="px-3 py-4 group-hover:bg-yellow-50 ">
81123 < a class ="link whitespace-nowrap " href ="{{ version.get_absolute_url }} ">
82124 {{ version.tag_or_hash }}
83125 </ a >
84126 </ td >
85- < td class ="px-3 ">
127+ < td class ="px-3 group-hover:bg-yellow-50 ">
86128 {% if version.is_under_review %}
87129 < span class ="inline-flex rounded-full px-2 py-0.5 text-sm/tight font-semibold border bg-blue-200 text-blue-900 border-blue-200 whitespace-nowrap "> Under review</ span >
88130 {% elif version.is_draft %}
@@ -91,8 +133,8 @@ <h2 class="text-2xl/tight font-bold text-slate-900">Your codelists</h2>
91133 < span class ="inline-flex rounded-full px-2 py-0.5 text-sm/tight font-semibold border bg-green-200 text-green-900 border-green-200 whitespace-nowrap "> Published</ span >
92134 {% endif %}
93135 </ td >
94- < td class ="px-3 py-4 whitespace-nowrap "> {{ version.codes|length }} code{{ version.codes|pluralize}}</ td >
95- < td class ="px-3 py-4 pl-3 sm:pr-3 ">
136+ < td class ="px-3 py-4 group-hover:bg-yellow-50 whitespace-nowrap "> {{ version.codes|length }} code{{ version.codes|pluralize}}</ td >
137+ < td class ="date-sort-column px-3 py-4 group-hover:bg-yellow-50 pl-3 sm:pr-3 ">
96138 < time class ="whitespace-nowrap " datetime ="{{ version.updated_at|date: "c " }}">
97139 {{ version.updated_at|date:'d M Y' }} at {{ version.updated_at|date:'H:i' }}
98140 </ time >
@@ -103,22 +145,22 @@ <h2 class="text-2xl/tight font-bold text-slate-900">Your codelists</h2>
103145 {% else %}
104146 < tbody class ="group bg-white even:bg-slate-50 ">
105147 {% for version in item.versions %}
106- < tr class ="text-sm text-slate-900 group-hover:bg-yellow-50 ">
107- < td class ="py-2 pr-3 pl-4 font-semibold sm:pl-6 text-base/snug ">
148+ < tr class ="text-sm text-slate-900 ">
149+ < td class ="name-sort-column py-2 pr-3 pl-4 font-semibold sm:pl-6 text-base/snug group-hover:bg-yellow-50 ">
108150 < span class ="{% if not forloop.first %}sr-only{% endif %} "> {{ item.codelist.name }}</ span >
109151 </ td >
110- < td class ="px-3 py-2 min-w-[20ch] ">
152+ < td class ="px-3 py-2 min-w-[20ch] group-hover:bg-yellow-50 ">
111153 < span class ="{% if not forloop.first %}sr-only{% endif %} "> {{ item.codelist.owner }}</ span >
112154 </ td >
113- < td class ="px-3 py-2 whitespace-nowrap ">
155+ < td class ="px-3 py-2 whitespace-nowrap group-hover:bg-yellow-50 ">
114156 < span class ="{% if not forloop.first %}sr-only{% endif %} "> {{ item.codelist.coding_system_short_name }}</ span >
115157 </ td >
116- < td class ="px-3 py-2 ">
158+ < td class ="px-3 py-2 group-hover:bg-yellow-50 ">
117159 < a class ="link whitespace-nowrap " href ="{{ version.get_absolute_url }} ">
118160 {{ version.tag_or_hash }}
119161 </ a >
120162 </ td >
121- < td class ="px-3 ">
163+ < td class ="px-3 group-hover:bg-yellow-50 ">
122164 {% if version.is_under_review %}
123165 < span class ="inline-flex rounded-full px-2 py-0.5 text-sm/tight font-semibold border bg-blue-200 text-blue-900 border-blue-200 whitespace-nowrap "> Under review</ span >
124166 {% elif version.is_draft %}
@@ -127,8 +169,8 @@ <h2 class="text-2xl/tight font-bold text-slate-900">Your codelists</h2>
127169 < span class ="inline-flex rounded-full px-2 py-0.5 text-sm/tight font-semibold border bg-green-200 text-green-900 border-green-200 whitespace-nowrap "> Published</ span >
128170 {% endif %}
129171 </ td >
130- < td class ="px-3 py-2 whitespace-nowrap "> {{ version.codes|length }} code{{ version.codes|pluralize}}</ td >
131- < td class ="px-3 py-2 pl-3 sm:pr-3 ">
172+ < td class ="px-3 py-2 whitespace-nowrap group-hover:bg-yellow-50 "> {{ version.codes|length }} code{{ version.codes|pluralize}}</ td >
173+ < td class ="date-sort-column px-3 py-2 pl-3 sm:pr-3 group-hover:bg-yellow-50 ">
132174 < time class ="whitespace-nowrap " datetime ="{{ version.updated_at|date: "c " }}">
133175 {{ version.updated_at|date:'d M Y' }} at {{ version.updated_at|date:'H:i' }}
134176 </ time >
@@ -150,9 +192,15 @@ <h2 class="text-2xl/tight font-bold text-slate-900">Your codelists</h2>
150192 < script nonce ="{{ request.csp_nonce }} ">
151193 const nameSortButton = document . getElementById ( "sort-codelists-by-name" ) ;
152194 const dateSortButton = document . getElementById ( "sort-codelists-by-date" ) ;
195+ const nameSortIcon = nameSortButton ?. querySelector ( '[data-sort-icon="direction"]' ) ;
196+ const dateSortIcon = dateSortButton ?. querySelector ( '[data-sort-icon="direction"]' ) ;
197+ const nameUnsortedIcon = nameSortButton ?. querySelector ( '[data-sort-icon="unsorted"]' ) ;
198+ const dateUnsortedIcon = dateSortButton ?. querySelector ( '[data-sort-icon="unsorted"]' ) ;
153199 const codelistsTable = nameSortButton ?. closest ( "table" ) ;
154200 let isNameDescending = false ;
155201 let isDateDescending = false ;
202+ const activeIconClasses = [ "bg-gray-200" , "text-gray-900" , "group-hover:bg-gray-300" ] ;
203+ const sortedColumnClass = "bg-transparent" ;
156204
157205 const getCodelistName = ( tbody ) => {
158206 const nameCell = tbody . querySelector ( "tr td" ) ;
@@ -188,6 +236,49 @@ <h2 class="text-2xl/tight font-bold text-slate-900">Your codelists</h2>
188236 : Math . min ( ...timestamps ) ;
189237 } ;
190238
239+ const updateSortIcon = ( icon , isActive , isDescending ) => {
240+ if ( ! icon ) {
241+ return ;
242+ }
243+
244+ icon . classList . remove ( ...activeIconClasses , "rotate-180" , "hidden" ) ;
245+
246+ if ( isActive ) {
247+ icon . classList . add ( ...activeIconClasses ) ;
248+ if ( ! isDescending ) {
249+ icon . classList . add ( "rotate-180" ) ;
250+ }
251+ } else {
252+ icon . classList . add ( "hidden" ) ;
253+ }
254+ } ;
255+
256+ const updateUnsortedIcon = ( icon , shouldShow ) => {
257+ if ( ! icon ) {
258+ return ;
259+ }
260+
261+ icon . classList . toggle ( "hidden" , ! shouldShow ) ;
262+ } ;
263+
264+ const highlightSortedColumn = ( columnName ) => {
265+ document . querySelectorAll ( ".name-sort-column, .date-sort-column" ) . forEach ( ( cell ) => {
266+ cell . classList . remove ( sortedColumnClass ) ;
267+ } ) ;
268+
269+ if ( columnName === "name" ) {
270+ document . querySelectorAll ( ".name-sort-column" ) . forEach ( ( cell ) => {
271+ cell . classList . add ( sortedColumnClass ) ;
272+ } ) ;
273+ }
274+
275+ if ( columnName === "date" ) {
276+ document . querySelectorAll ( ".date-sort-column" ) . forEach ( ( cell ) => {
277+ cell . classList . add ( sortedColumnClass ) ;
278+ } ) ;
279+ }
280+ } ;
281+
191282 const setSortState = ( activeButton ) => {
192283 [ nameSortButton , dateSortButton ] . forEach ( ( button ) => {
193284 if ( ! button ) {
@@ -196,10 +287,18 @@ <h2 class="text-2xl/tight font-bold text-slate-900">Your codelists</h2>
196287
197288 button . setAttribute ( "aria-pressed" , String ( button === activeButton ) ) ;
198289 } ) ;
290+
291+ updateSortIcon ( nameSortIcon , activeButton === nameSortButton , isNameDescending ) ;
292+ updateSortIcon ( dateSortIcon , activeButton === dateSortButton , isDateDescending ) ;
293+ updateUnsortedIcon ( nameUnsortedIcon , activeButton !== nameSortButton ) ;
294+ updateUnsortedIcon ( dateUnsortedIcon , activeButton !== dateSortButton ) ;
295+ highlightSortedColumn ( activeButton === nameSortButton ? "name" : "date" ) ;
199296 } ;
200297
201298 const sortTableBodiesByName = ( ) => {
202299 const tableBodies = getTableBodies ( ) ;
300+ tableBodies . forEach ( ( tbody ) => sortRowsByDate ( tbody , true ) ) ;
301+
203302 tableBodies
204303 . sort ( ( leftBody , rightBody ) => {
205304 const leftName = getCodelistName ( leftBody ) ;
0 commit comments