objective categorical abstract machine language personal data server

Fix account switcher, admin pages sizing

futur.blue f0e70709 51cda44f

verified
+40 -32
+8 -4
frontend/src/components/AccountSwitcher.mlx
··· 10 10 active:bg-mist-20/40" 11 11 12 12 let button_class_default = 13 - "group min-w-48 flex flex-row items-center gap-x-1 px-2 py-1.5 -mx-2 \ 13 + "group w-64 flex flex-row items-center gap-x-1 px-2 py-1.5 -mx-2 \ 14 14 rounded-lg focus-visible:outline-none hover:bg-mist-20/40 \ 15 15 active:bg-mist-20/40" 16 16 ··· 44 44 [%browser_only 45 45 fun newDid -> 46 46 if newDid <> current_user.did then 47 - let formData = Fetch.FormData.make () in 48 - Fetch.FormData.set "did" newDid formData ; 47 + let body = 48 + Fetch.BodyInit.make 49 + (Webapi.Url.URLSearchParams.makeWithArray [|("did", newDid)|] 50 + |> Webapi.Url.URLSearchParams.toString ) 51 + in 49 52 let _ = 50 53 Fetch.fetchWithInit "/account/switch" 51 54 (Fetch.RequestInit.make ~method_:Fetch.Post 52 - ~body:(Fetch.BodyInit.makeWithFormData formData) 55 + ~headers:(Fetch.HeadersInit.makeWithArray [|("Content-Type", "application/x-www-form-urlencoded")|]) 56 + ~body 53 57 () ) 54 58 |> Js.Promise.then_ (fun response -> 55 59 if Fetch.Response.ok response then (
+1 -1
frontend/src/components/Sidebar.mlx
··· 5 5 let[@react.component] make ~pages ~active_page ?header () = 6 6 let selected_class = "text-mana-100 font-medium" in 7 7 let unselected_class = "text-mist-100 hover:text-mana-100" in 8 - <aside className="flex flex-col gap-y-2 min-w-24 max-w-3xs"> 8 + <aside className="flex flex-col gap-y-2 w-auto min-w-32"> 9 9 (match header with Some h -> h | None -> null) 10 10 <nav className="flex flex-col gap-y-1 mt-2"> 11 11 ( List.map
+12 -10
frontend/src/templates/AdminInvitesPage.mlx
··· 38 38 let editRemaining, setEditRemaining = useState (fun () -> "") in 39 39 (* delete confirmation state *) 40 40 let deleteConfirmFor, setDeleteConfirmFor = useState (fun () -> (None : invite option)) in 41 - <div className="w-full max-w-3xl h-full px-4 sm:px-0 pt-16 mx-auto flex flex-col md:flex-row gap-12"> 41 + <div className="w-auto h-full max-w-full px-4 pt-16 mx-auto flex flex-1 flex-col md:flex-row justify-center gap-12"> 42 42 <Sidebar pages=admin_pages active_page="/admin/invites" /> 43 43 <main className="flex-1 w-full max-w-2xl"> 44 44 <h1 className="text-2xl font-serif text-mana-200 mb-1"> ··· 138 138 </div> 139 139 | None -> null ) 140 140 <div className="overflow-x-auto"> 141 - <table className="w-full min-w-xl text-sm"> 142 - <thead> 143 - <tr className="text-left text-mist-80"> 144 - <th className="pb-2 font-normal">(string "Code")</th> 145 - <th className="pb-2 font-normal">(string "For")</th> 146 - <th className="pb-2 font-normal">(string "Remaining")</th> 147 - <th className="pb-2 font-normal w-20"></th> 141 + <table 142 + className="w-full grid border-collapse text-sm" 143 + style=(ReactDOM.Style.make ~gridTemplateColumns:"minmax(6rem, 1fr) 1fr minmax(2rem, 1fr) 4rem" ())> 144 + <thead className="contents"> 145 + <tr className="contents text-left text-mist-80"> 146 + <th className="border-b border-mist-60/50 pb-2 font-normal">(string "Code")</th> 147 + <th className="border-b border-mist-60/50 pb-2 font-normal">(string "For")</th> 148 + <th className="border-b border-mist-60/50 pb-2 font-normal">(string "Remaining")</th> 149 + <th className="border-b border-mist-60/50 pb-2 font-normal w-20"></th> 148 150 </tr> 149 151 </thead> 150 - <tbody> 152 + <tbody className="contents"> 151 153 ( List.map 152 154 (fun (invite : invite) -> 153 - <tr key=invite.code className="border-t border-mist-60/50"> 155 + <tr key=invite.code className="contents"> 154 156 <td className="py-3 pr-4"> 155 157 <span className="font-mono text-mana-100"> 156 158 (string invite.code)
+19 -17
frontend/src/templates/AdminUsersPage.mlx
··· 62 62 let editValue, setEditValue = useState (fun () -> "") in 63 63 (* delete confirmation state *) 64 64 let deleteConfirmFor, setDeleteConfirmFor = useState (fun () -> (None : actor option)) in 65 - <div className="w-full max-w-3xl h-full px-4 sm:px-0 pt-16 mx-auto flex flex-col md:flex-row gap-12"> 65 + <div className="w-auto h-full max-w-full px-4 pt-16 mx-auto flex flex-col md:flex-row gap-12"> 66 66 <Sidebar pages=admin_pages active_page="/admin/users" /> 67 67 <main className="flex-1 w-full max-w-2xl"> 68 68 <h1 className="text-2xl font-serif text-mana-200 mb-1"> ··· 169 169 </div> 170 170 | None -> null ) 171 171 <div className="overflow-x-auto"> 172 - <table className="w-full min-w-xl text-sm"> 173 - <thead> 174 - <tr className="text-left text-mist-80"> 175 - <th className="pb-2 font-normal">(string "Handle")</th> 176 - <th className="pb-2 font-normal">(string "Email")</th> 177 - <th className="pb-2 font-normal">(string "Created at")</th> 178 - <th className="pb-2 font-normal w-8"></th> 172 + <table 173 + className="w-full min-w-xl grid border-collapse text-sm" 174 + style=(ReactDOM.Style.make ~gridTemplateColumns:"minmax(200px, 2fr) minmax(160px, 2fr) minmax(160px, 1.5fr) 1.25rem" ())> 175 + <thead className="contents"> 176 + <tr className="contents text-left text-mist-80"> 177 + <th className="border-b border-mist-60/50 pb-2 font-normal">(string "Handle")</th> 178 + <th className="border-b border-mist-60/50 pb-2 font-normal">(string "Email")</th> 179 + <th className="border-b border-mist-60/50 pb-2 font-normal">(string "Created at")</th> 180 + <th className="border-b border-mist-60/50 pb-2 font-normal w-8"></th> 179 181 </tr> 180 182 </thead> 181 - <tbody> 183 + <tbody className="contents"> 182 184 ( List.map 183 185 (fun (actor : actor) -> 184 186 if filter <> "" ··· 187 189 && not (contains_str actor.email filter) then null else 188 190 let handleClasses = "font-medium truncate " ^ 189 191 (if actor.deactivated then "text-phoenix-100" else "text-mana-100") in 190 - <tr key=actor.did className="border-t border-mist-60/50"> 192 + <tr key=actor.did className="contents"> 191 193 <td className="py-3 pr-4"> 192 194 <div className="flex items-center gap-3"> 193 - <div className="max-w-54"> 195 + <div className="max-w-54 truncate"> 194 196 <p className=handleClasses ?title=(if actor.deactivated then Some "Deactivated" else None)> 195 197 (string actor.handle) 196 198 </p> ··· 202 204 </td> 203 205 <td className="py-3 pr-4"> 204 206 <div className="flex items-center gap-1"> 205 - <span className="text-mist-100">(string actor.email)</span> 207 + <span className="text-mist-100 truncate">(string actor.email)</span> 206 208 ( if actor.email_confirmed then 207 - <CheckmarkIcon className="w-4 h-4 text-mana-100" /> 209 + <CheckmarkIcon className="flex-shrink-0 w-4 h-4 text-mana-100" /> 208 210 else 209 - <XIcon className="w-4 h-4 text-phoenix-100" /> ) 211 + <XIcon className="flex-shrink-0 w-4 h-4 text-phoenix-100" /> ) 210 212 </div> 211 213 </td> 212 - <td className="py-3 pr-4 text-mist-100"> 214 + <td className="py-3 pr-4 text-mist-100 truncate"> 213 215 (string actor.created_at) 214 216 </td> 215 217 <td className="py-3"> 216 218 <ClientOnly fallback=( 217 - <button className="p-1 text-mist-80 hover:text-mana-100"> 219 + <button className="text-mist-80 hover:text-mana-100"> 218 220 <EllipsisIcon className="w-5 h-5" /> 219 221 </button> 220 222 )> ··· 228 230 setMenuOpenFor (fun _ -> if o then Some actor.did else None))> 229 231 <Aria.Pressable> 230 232 <button 231 - className="p-1 text-mist-80 hover:text-mana-100 cursor-pointer" 233 + className="text-mist-80 hover:text-mana-100 cursor-pointer" 232 234 onClick=(fun _ -> setMenuOpenFor (fun _ -> Some actor.did))> 233 235 <EllipsisIcon className="w-5 h-5" /> 234 236 </button>