work-in-progress atproto PDS
typescript atproto pds atcute
4
fork

Configure Feed

Select the types of activity you want to include in your feed.

refactor: clean up app password design

mary.my.id 3b77cdfe 8052748d

verified
+178 -52
+93 -7
packages/danaus/src/web/account/index.tsx
··· 4 4 import { HTTPException } from 'hono/http-exception'; 5 5 import { jsxRenderer } from 'hono/jsx-renderer'; 6 6 7 - import { formatAppPasswordPrivilege } from '#app/accounts/app-passwords.ts'; 7 + import { AppPasswordPrivilege } from '#app/accounts/db/schema.ts'; 8 8 import type { WebSession } from '#app/accounts/manager.ts'; 9 9 import { readWebSessionToken, verifyWebSessionToken } from '#app/auth/web.ts'; 10 10 import type { AppContext } from '#app/context.ts'; ··· 20 20 import PhoneOutlined from '../icons/central/phone-outlined.tsx'; 21 21 import PlusLargeOutlined from '../icons/central/plus-large-outlined.tsx'; 22 22 import ShieldOutlined from '../icons/central/shield-outlined.tsx'; 23 - import TrashCanOutlined from '../icons/central/trash-can-outlined.tsx'; 24 23 import UsbOutlined from '../icons/central/usb-outlined.tsx'; 25 24 import Button from '../primitives/button.tsx'; 26 25 import DialogActions from '../primitives/dialog-actions.tsx'; 27 26 import DialogBody from '../primitives/dialog-body.tsx'; 27 + import DialogClose from '../primitives/dialog-close.tsx'; 28 28 import DialogContent from '../primitives/dialog-content.tsx'; 29 29 import DialogSurface from '../primitives/dialog-surface.tsx'; 30 30 import DialogTitle from '../primitives/dialog-title.tsx'; 31 + import DialogTrigger from '../primitives/dialog-trigger.tsx'; 31 32 import Dialog from '../primitives/dialog.tsx'; 32 33 import Field from '../primitives/field.tsx'; 33 34 import Input from '../primitives/input.tsx'; ··· 266 267 </MessageBar> 267 268 )} 268 269 269 - {passwords.length === 0 ? ( 270 + {/* {passwords.length === 0 ? ( 270 271 <p class="py-8 text-center text-base-300 text-neutral-foreground-3">no app passwords yet.</p> 271 272 ) : ( 272 273 <ul class="divide-y divide-neutral-stroke-2"> ··· 289 290 </li> 290 291 ))} 291 292 </ul> 292 - )} 293 + )} */} 294 + 295 + <div class="flex flex-col divide-y divide-neutral-stroke-2 rounded-md bg-neutral-background-1 shadow-4"> 296 + {passwords.length === 0 && ( 297 + <div class="flex flex-col gap-1 p-8 text-center"> 298 + <p class="text-base-300 font-medium">No app passwords created</p> 299 + <p class="text-base-300 text-neutral-foreground-3"> 300 + App passwords lets you sign into legacy AT Protocol apps. 301 + </p> 302 + </div> 303 + )} 304 + 305 + {passwords.map((password) => { 306 + let privilege = `Unknown`; 307 + switch (password.privilege) { 308 + case AppPasswordPrivilege.Full: { 309 + privilege = `Full access`; 310 + break; 311 + } 312 + case AppPasswordPrivilege.Privileged: { 313 + privilege = `Privileged access`; 314 + break; 315 + } 316 + case AppPasswordPrivilege.Limited: { 317 + privilege = `Limited access`; 318 + break; 319 + } 320 + } 321 + 322 + return ( 323 + <div class="flex items-center gap-4 px-4 py-3"> 324 + <Key2Outlined size={24} class="shrink-0" /> 325 + 326 + <div class="min-w-0 grow"> 327 + <p class="text-base-300">{password.name}</p> 328 + <p class="text-base-300 text-neutral-foreground-3">{privilege}</p> 329 + </div> 330 + 331 + <Menu> 332 + <MenuTrigger> 333 + <button class="grid h-6 w-6 shrink-0 place-items-center rounded-md bg-subtle-background text-neutral-foreground-3 outline-2 -outline-offset-2 outline-transparent transition hover:bg-subtle-background-hover hover:text-neutral-foreground-3-hover focus-visible:outline-stroke-focus-2 active:bg-subtle-background-active active:text-neutral-foreground-3-active"> 334 + <DotGrid1x3HorizontalOutlined size={16} /> 335 + </button> 336 + </MenuTrigger> 337 + 338 + <MenuPopover> 339 + <MenuList> 340 + <Dialog> 341 + <DialogTrigger> 342 + <MenuItem>Delete</MenuItem> 343 + </DialogTrigger> 344 + 345 + <DialogSurface> 346 + <DialogBody> 347 + <DialogTitle>Delete this app password?</DialogTitle> 348 + 349 + <form {...deleteAppPasswordForm} class="contents"> 350 + <DialogContent> 351 + <p class="text-base-300"> 352 + You'll no longer be able to sign in to legacy apps using the{' '} 353 + <strong>{password.name}</strong> app password. 354 + </p> 355 + 356 + <input {...deleteAppPasswordForm.fields.name.as('hidden', password.name)} /> 357 + </DialogContent> 358 + 359 + <DialogActions> 360 + <DialogClose> 361 + <Button>Cancel</Button> 362 + </DialogClose> 363 + 364 + <Button type="submit" variant="primary"> 365 + Delete 366 + </Button> 367 + </DialogActions> 368 + </form> 369 + </DialogBody> 370 + </DialogSurface> 371 + </Dialog> 372 + </MenuList> 373 + </MenuPopover> 374 + </Menu> 375 + </div> 376 + ); 377 + })} 378 + </div> 293 379 </div> 294 380 295 381 <Dialog id="create-app-password-dialog"> ··· 316 402 </DialogContent> 317 403 318 404 <DialogActions> 319 - <Button type="submit" variant="primary"> 320 - Create 321 - </Button> 322 405 <Button commandfor="create-app-password-dialog" command="close" variant="outlined"> 323 406 Cancel 407 + </Button> 408 + <Button type="submit" variant="primary"> 409 + Create 324 410 </Button> 325 411 </DialogActions> 326 412 </form>
+1 -1
packages/danaus/src/web/primitives/dialog-actions.tsx
··· 3 3 4 4 const root = cva({ 5 5 base: [ 6 - 'box-border', 6 + 'box-border pt-2', 7 7 'h-fit', 8 8 // grid position: row 3 9 9 'row-start-3 row-end-3',
+20
packages/danaus/src/web/primitives/dialog-close.tsx
··· 1 + import { cloneElement } from 'hono/jsx'; 2 + import type { JSX } from 'hono/jsx/jsx-runtime'; 3 + 4 + import { useDialogContext } from './utils/dialog-context.tsx'; 5 + 6 + export interface DialogCloseProps { 7 + children: JSX.Element; 8 + } 9 + 10 + const DialogClose = (props: DialogCloseProps) => { 11 + const { children } = props; 12 + const { dialogId } = useDialogContext(); 13 + 14 + return cloneElement(children, { 15 + commandfor: dialogId, 16 + command: 'close', 17 + }); 18 + }; 19 + 20 + export default DialogClose;
+36 -3
packages/danaus/src/web/primitives/dialog-surface.tsx
··· 1 1 import { cva } from 'cva'; 2 2 import type { Child } from 'hono/jsx'; 3 3 4 + import { useDialogContext } from './utils/dialog-context'; 5 + 4 6 const root = cva({ 5 7 base: [ 8 + 'fixed inset-0 m-0 h-dvh max-h-dvh w-dvw max-w-dvw', 9 + 'border-none p-0', 10 + 'bg-transparent', 11 + 'overflow-visible', 12 + // reset dialog defaults 13 + 'open:flex open:items-center open:justify-center', 14 + // backdrop 15 + 'backdrop:bg-background-overlay', 16 + ], 17 + }); 18 + 19 + const backdrop = cva({ 20 + base: ['absolute inset-0 z-0'], 21 + }); 22 + 23 + const surface = cva({ 24 + base: [ 6 25 'relative z-10', 7 26 'box-border', 8 27 'max-h-[calc(100dvh-48px)]', ··· 16 35 }); 17 36 18 37 export interface DialogSurfaceProps { 19 - class?: string; 20 38 children?: Child; 21 39 } 22 40 ··· 25 43 * @param props.class additional CSS classes 26 44 */ 27 45 const DialogSurface = (props: DialogSurfaceProps) => { 28 - const { class: className, children } = props; 46 + const { children } = props; 47 + 48 + const { dialogId, titleId } = useDialogContext(); 29 49 30 - return <div class={root({ className })}>{children}</div>; 50 + return ( 51 + <dialog id={dialogId} aria-labelledby={titleId} class={root()}> 52 + <div class={surface()}>{children}</div> 53 + 54 + <button 55 + type="button" 56 + tabindex={-1} 57 + aria-hidden="true" 58 + commandfor={dialogId} 59 + command="close" 60 + class={backdrop()} 61 + /> 62 + </dialog> 63 + ); 31 64 }; 32 65 33 66 export default DialogSurface;
+1 -1
packages/danaus/src/web/primitives/dialog-title.tsx
··· 5 5 6 6 const root = cva({ 7 7 base: [ 8 - 'm-0', 8 + 'm-0 pb-2', 9 9 'text-base-500 font-semibold', 10 10 // grid position: row 1, col 1-2 (leaves col 3 for action) 11 11 'col-start-1 col-end-3 row-start-1 row-end-1',
+20
packages/danaus/src/web/primitives/dialog-trigger.tsx
··· 1 + import { cloneElement } from 'hono/jsx'; 2 + import type { JSX } from 'hono/jsx/jsx-runtime'; 3 + 4 + import { useDialogContext } from './utils/dialog-context.tsx'; 5 + 6 + export interface DialogTriggerProps { 7 + children: JSX.Element; 8 + } 9 + 10 + const DialogTrigger = (props: DialogTriggerProps) => { 11 + const { children } = props; 12 + const { dialogId } = useDialogContext(); 13 + 14 + return cloneElement(children, { 15 + commandfor: dialogId, 16 + command: 'show-modal', 17 + }); 18 + }; 19 + 20 + export default DialogTrigger;
+4 -40
packages/danaus/src/web/primitives/dialog.tsx
··· 1 - import { cva } from 'cva'; 2 1 import type { Child } from 'hono/jsx'; 3 2 4 3 import { useId } from '../components/id.tsx'; 5 4 6 5 import { DialogContext, type DialogContextValue } from './utils/dialog-context.tsx'; 7 6 8 - const root = cva({ 9 - base: [ 10 - 'fixed inset-0 m-0 h-dvh max-h-dvh w-dvw max-w-dvw', 11 - 'border-none p-0', 12 - 'bg-transparent', 13 - 'overflow-visible', 14 - // reset dialog defaults 15 - 'open:flex open:items-center open:justify-center', 16 - // backdrop 17 - 'backdrop:bg-background-overlay', 18 - ], 19 - }); 20 - 21 - const backdrop = cva({ 22 - base: ['absolute inset-0 z-0'], 23 - }); 24 - 25 7 export interface DialogProps { 26 - id: string; 27 - class?: string; 8 + id?: string; 28 9 children?: Child; 29 10 } 30 11 ··· 34 15 * @param props.class additional CSS classes 35 16 */ 36 17 const Dialog = (props: DialogProps) => { 37 - const { id, class: className, children } = props; 38 - 39 - const titleId = useId(); 18 + const { id = useId(), children } = props; 40 19 41 20 const contextValue: DialogContextValue = { 42 21 dialogId: id, 43 - titleId, 22 + titleId: useId(), 44 23 }; 45 24 46 - return ( 47 - <DialogContext.Provider value={contextValue}> 48 - <dialog id={id} aria-labelledby={titleId} class={root({ className })}> 49 - {children} 50 - 51 - <button 52 - type="button" 53 - tabindex={-1} 54 - aria-hidden="true" 55 - commandfor={id} 56 - command="close" 57 - class={backdrop()} 58 - /> 59 - </dialog> 60 - </DialogContext.Provider> 61 - ); 25 + return <DialogContext.Provider value={contextValue}>{children}</DialogContext.Provider>; 62 26 }; 63 27 64 28 export default Dialog;
+3
packages/danaus/src/web/styles/main.out.css
··· 722 722 .p-6 { 723 723 padding: calc(var(--spacing) * 6); 724 724 } 725 + .p-8 { 726 + padding: calc(var(--spacing) * 8); 727 + } 725 728 .px-1\.5 { 726 729 padding-inline: calc(var(--spacing) * 1.5); 727 730 }