atproto explorer pdsls.dev
atproto tool
at main 2.9 kB view raw
1import { createSignal, For } from "solid-js"; 2import { buildScopeString, GRANULAR_SCOPES, scopeIdsToString } from "./scope-utils"; 3 4interface ScopeSelectorProps { 5 onConfirm: (scopeString: string, scopeIds: string) => void; 6 onCancel: () => void; 7 initialScopes?: Set<string>; 8} 9 10export const ScopeSelector = (props: ScopeSelectorProps) => { 11 const [selectedScopes, setSelectedScopes] = createSignal<Set<string>>( 12 props.initialScopes || new Set(["create", "update", "delete", "blob"]), 13 ); 14 15 const isBlobDisabled = () => { 16 const scopes = selectedScopes(); 17 return !scopes.has("create") && !scopes.has("update"); 18 }; 19 20 const toggleScope = (scopeId: string) => { 21 setSelectedScopes((prev) => { 22 const newSet = new Set(prev); 23 if (newSet.has(scopeId)) { 24 newSet.delete(scopeId); 25 if ( 26 (scopeId === "create" || scopeId === "update") && 27 !newSet.has("create") && 28 !newSet.has("update") 29 ) { 30 newSet.delete("blob"); 31 } 32 } else { 33 newSet.add(scopeId); 34 } 35 return newSet; 36 }); 37 }; 38 39 const handleConfirm = () => { 40 const scopes = selectedScopes(); 41 const scopeString = buildScopeString(scopes); 42 const scopeIds = scopeIdsToString(scopes); 43 props.onConfirm(scopeString, scopeIds); 44 }; 45 46 return ( 47 <div class="flex flex-col gap-y-2"> 48 <div class="mb-1 flex items-center gap-2"> 49 <button 50 onclick={props.onCancel} 51 class="flex items-center rounded-md p-1 hover:bg-neutral-200 active:bg-neutral-300 dark:hover:bg-neutral-700 dark:active:bg-neutral-600" 52 > 53 <span class="iconify lucide--arrow-left"></span> 54 </button> 55 <div class="font-semibold">Select permissions</div> 56 </div> 57 <div class="flex flex-col gap-y-2 px-1"> 58 <For each={GRANULAR_SCOPES}> 59 {(scope) => ( 60 <div 61 class="flex items-center gap-2" 62 classList={{ "opacity-50": scope.id === "blob" && isBlobDisabled() }} 63 > 64 <input 65 id={`scope-${scope.id}`} 66 type="checkbox" 67 checked={selectedScopes().has(scope.id)} 68 disabled={scope.id === "blob" && isBlobDisabled()} 69 onChange={() => toggleScope(scope.id)} 70 /> 71 <label for={`scope-${scope.id}`} class="flex grow items-center gap-2 select-none"> 72 <span>{scope.label}</span> 73 </label> 74 </div> 75 )} 76 </For> 77 </div> 78 <button 79 onclick={handleConfirm} 80 class="mt-2 grow rounded-lg border-[0.5px] border-neutral-300 bg-neutral-100 px-3 py-2 hover:bg-neutral-200 active:bg-neutral-300 dark:border-neutral-600 dark:bg-neutral-800 dark:hover:bg-neutral-700 dark:active:bg-neutral-600" 81 > 82 Continue 83 </button> 84 </div> 85 ); 86};