web: line the accounts row's controls up in columns !457
3 files changed, +45 −8
Layout: unified · split
CHANGELOG.org +6 −1
| @@ -48,7 +48,12 @@ Eleven web findings, mostly alignment and affordance (#247). | |||
| 48 | active, rather than leaving the cell short, and the page is wide. At | 48 | active, rather than leaving the cell short, and the page is wide. At |
| 49 | 48rem the Actions cell clipped the second form's button, which left | 49 | 48rem the Actions cell clipped the second form's button, which left |
| 50 | its confirm field looking like it belonged to the button before it — | 50 | its confirm field looking like it belonged to the button before it — |
| 51 | an active row read as though Promote wanted the name typed. | 51 | an active row read as though Promote wanted the name typed. The cell |
| 52 | is now two fixed slots, each right-aligned, so the role button, the | ||
| 53 | confirm field and the access button each hold one column whichever | ||
| 54 | controls a row carries: an admin's row has a field on both forms, a | ||
| 55 | disabled account's enable form has none. The field is 14rem, which | ||
| 56 | fits "type <name> to confirm" for a name of ordinary length. | ||
| 52 | - The profile's inactive tabs draw their underline in =--line=, so the | 57 | - The profile's inactive tabs draw their underline in =--line=, so the |
| 53 | strip reads as a track the current tab is marked in. | 58 | strip reads as a track the current tab is marked in. |
| 54 | - =.listhead= sheds its children's block margins, which is what kept a | 59 | - =.listhead= sheds its children's block margins, which is what kept a |
internal/web/static/style.css +34 −3
| @@ -920,9 +920,40 @@ table.keys td.act, table.assets td.size { text-align: right; } | |||
| 920 | keep one line each and .tablewrap scrolls what does not fit */ | 920 | keep one line each and .tablewrap scrolls what does not fit */ |
| 921 | table.keys.nowrap th, table.keys.nowrap td { white-space: nowrap; } | 921 | table.keys.nowrap th, table.keys.nowrap td { white-space: nowrap; } |
| 922 | /* The account list types a username to confirm, which is longer than | 922 | /* The account list types a username to confirm, which is longer than |
| 923 | the key prefixes the confirm field is sized for elsewhere. */ | 923 | the key prefixes the confirm field is sized for elsewhere. 14rem, not |
| 924 | table.accounts input[name="confirm"] { width: 11rem; } | 924 | 11rem, because "type <name> to confirm" was cut mid-word for a name of |
| 925 | table.accounts form.actions { display: inline-flex; gap: var(--sp-2); margin: 0 var(--sp-2) var(--sp-2) 0; } | 925 | ordinary length; a long enough name still truncates and the field's |
| 926 | aria-label carries the instruction in full either way. | ||
| 927 | |||
| 928 | The cell is two fixed slots, each right-aligned. A form cannot span | ||
| 929 | table cells, so one column per control — which would let the table | ||
| 930 | align them — is out without form="" plumbing, and the forms hold | ||
| 931 | different numbers of controls: only an admin's role form has a | ||
| 932 | confirm field, and the enable form has none. Sizing the slot instead | ||
| 933 | of the form is what puts every button in one column and every field | ||
| 934 | in another; right-aligning the cell alone left the disabled row's | ||
| 935 | Promote where other rows keep their field. A slot is a field, a gap | ||
| 936 | and a button wide, so a form that is only a button still ends on the | ||
| 937 | same rule. No element stands in for the controls a row lacks. */ | ||
| 938 | table.accounts { --acct-field: 14rem; --acct-btn: 6rem; } | ||
| 939 | table.accounts td.acts { display: flex; justify-content: flex-end; align-items: center; gap: var(--sp-2); } | ||
| 940 | table.accounts input[name="confirm"] { width: var(--acct-field); } | ||
| 941 | table.accounts form.actions { | ||
| 942 | flex: none; | ||
| 943 | display: inline-flex; | ||
| 944 | /* the generic form.actions wraps and grows its button to fill; both | ||
| 945 | have to go, or the slot takes the button to a second line and the | ||
| 946 | field sits above it */ | ||
| 947 | flex-wrap: nowrap; | ||
| 948 | justify-content: flex-end; | ||
| 949 | align-items: center; | ||
| 950 | gap: var(--sp-2); | ||
| 951 | width: calc(var(--acct-field) + var(--acct-btn) + var(--sp-2)); | ||
| 952 | margin: 0; | ||
| 953 | } | ||
| 954 | /* a set width, not a minimum: it makes the slot's arithmetic exact, and | ||
| 955 | 6rem clears the widest of Promote, Demote, Disable and Enable */ | ||
| 956 | table.accounts form.actions button { flex: none; width: var(--acct-btn); justify-content: center; } | ||
| 926 | table.assets td.name { width: 100%; font-family: var(--mono); font-size: var(--fs-1); } | 957 | table.assets td.name { width: 100%; font-family: var(--mono); font-size: var(--fs-1); } |
| 927 | table.assets { margin-top: var(--sp-2); } | 958 | table.assets { margin-top: var(--sp-2); } |
| 928 | 959 | ||
internal/web/templates/adminusers.html +5 −4
| @@ -25,7 +25,7 @@ | |||
| 25 | <td><span class="chip {{if eq .State "active"}}chip-open{{else if eq .State "disabled"}}chip-closed{{else}}chip-neutral{{end}}">{{.State}}</span></td> | 25 | <td><span class="chip {{if eq .State "active"}}chip-open{{else if eq .State "disabled"}}chip-closed{{else}}chip-neutral{{end}}">{{.State}}</span></td> |
| 26 | <td>{{when .CreatedAt}}</td> | 26 | <td>{{when .CreatedAt}}</td> |
| 27 | <td>{{if .LastSeen}}{{when .LastSeen}}{{else}}never{{end}}</td> | 27 | <td>{{if .LastSeen}}{{when .LastSeen}}{{else}}never{{end}}</td> |
| 28 | <td> | 28 | <td class="acts"> |
| 29 | {{if .Admin}} | 29 | {{if .Admin}} |
| 30 | <form method="post" action="/admin/users" class="actions"> | 30 | <form method="post" action="/admin/users" class="actions"> |
| 31 | <input type="hidden" name="field" value="demote"> | 31 | <input type="hidden" name="field" value="demote"> |
| @@ -42,10 +42,11 @@ | |||
| 42 | </form> | 42 | </form> |
| 43 | {{else}} | 43 | {{else}} |
| 44 | {{/* An account that is not active cannot be promoted, but the row | 44 | {{/* An account that is not active cannot be promoted, but the row |
| 45 | still draws the control so every Actions cell is the same | 45 | still draws the button so the cell keeps its shape. It carries |
| 46 | shape. Both parts are disabled, so the form never posts. */}} | 46 | no confirm field: nothing is confirmed, and a second field with |
| 47 | the same placeholder as the disable form's reads as a duplicate | ||
| 48 | of it. Disabled, so the form never posts. */}} | ||
| 47 | <form method="post" action="/admin/users" class="actions" title="Only an active account can be promoted"> | 49 | <form method="post" action="/admin/users" class="actions" title="Only an active account can be promoted"> |
| 48 | <input type="text" name="confirm" aria-label="Type {{.Username}} to confirm" placeholder="type {{.Username}} to confirm" size="{{len .Username}}" autocomplete="off" disabled> | ||
| 49 | <button type="submit" class="btn" disabled>Promote</button> | 50 | <button type="submit" class="btn" disabled>Promote</button> |
| 50 | </form> | 51 | </form> |
| 51 | {{end}} | 52 | {{end}} |