a tool for shared writing and social publishing
0

Configure Feed

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

add loaders

Jared Pereira (Mar 14, 2026, 8:43 PM EDT) 031d7009 f2db84ee

+36 -11
+6 -2
components/Domains/AddDomainForm.tsx
··· 5 5 import { useSmoker } from "components/Toast"; 6 6 import { useIdentityData } from "components/IdentityProvider"; 7 7 import { addDomain } from "actions/domains/addDomain"; 8 + import { DotLoader } from "components/utils/DotLoader"; 8 9 9 10 export function AddDomainForm(props: { 10 11 onDomainAdded: (domain: string) => void; 11 12 onBack: () => void; 12 13 }) { 13 14 let [value, setValue] = useState(""); 15 + let [loading, setLoading] = useState(false); 14 16 let { mutate } = useIdentityData(); 15 17 let smoker = useSmoker(); 16 18 ··· 39 41 Back 40 42 </button> 41 43 <ButtonPrimary 42 - disabled={!value} 44 + disabled={!value || loading} 43 45 onMouseDown={async (e) => { 46 + setLoading(true); 44 47 let { error } = await addDomain(value); 45 48 if (error) { 49 + setLoading(false); 46 50 smoker({ 47 51 error: true, 48 52 text: ··· 62 66 props.onDomainAdded(value); 63 67 }} 64 68 > 65 - Verify Domain 69 + {loading ? <DotLoader /> : "Verify Domain"} 66 70 </ButtonPrimary> 67 71 </div> 68 72 </div>
+4 -1
components/Domains/DomainSettingsView.tsx
··· 214 214 mutateIdentity: ReturnType<typeof useIdentityData>["mutate"]; 215 215 }) { 216 216 let [confirming, setConfirming] = useState(false); 217 + let [loading, setLoading] = useState(false); 217 218 218 219 if (!props.onDeleteDomain) return null; 219 220 ··· 247 248 </button> 248 249 <ButtonPrimary 249 250 compact 251 + disabled={loading} 250 252 onMouseDown={async () => { 253 + setLoading(true); 251 254 mutateIdentityData(props.mutateIdentity, (draft) => { 252 255 draft.custom_domains = draft.custom_domains.filter( 253 256 (d) => d.domain !== props.domain, ··· 257 260 await deleteDomain({ domain: props.domain }); 258 261 }} 259 262 > 260 - Delete 263 + {loading ? <DotLoader /> : "Delete"} 261 264 </ButtonPrimary> 262 265 </div> 263 266 </div>
+21 -7
components/Domains/PublicationDomains.tsx
··· 20 20 import { PinTiny } from "components/Icons/PinTiny"; 21 21 import { LoadingTiny } from "components/Icons/LoadingTiny"; 22 22 import { AddTiny } from "components/Icons/AddTiny"; 23 + import { DotLoader } from "components/utils/DotLoader"; 23 24 import type { CustomDomain } from "./DomainList"; 24 25 25 26 type State = ··· 138 139 onSettings: () => void; 139 140 }) { 140 141 let { pending } = useDomainStatus(props.domain); 142 + let [loading, setLoading] = useState(false); 141 143 142 144 return ( 143 145 <div className="text-sm text-secondary relative w-full flex items-center justify-between px-[6px] py-1 border rounded-md border-border-light"> ··· 170 172 ) : ( 171 173 <button 172 174 type="button" 175 + disabled={loading} 173 176 onClick={async () => { 177 + setLoading(true); 174 178 await updatePublicationBasePath({ 175 179 uri: props.publication_uri, 176 180 base_path: props.domain, 177 181 }); 178 182 mutate("publication-data"); 183 + setLoading(false); 179 184 }} 180 185 className="group/domain flex gap-1 items-center rounded-full bg-none w-max font-bold px-1 py-0.5 hover:bg-accent-1 hover:text-accent-2 border-transparent outline-solid outline-transparent hover:outline-accent-1 selected-outline" 181 186 > 182 - <p className="group-hover/domain:block hidden w-max pl-1"> 183 - set as default 184 - </p> 185 - <PinTiny className="text-secondary group-hover/domain:text-accent-2 shrink-0" /> 187 + {loading ? ( 188 + <DotLoader /> 189 + ) : ( 190 + <> 191 + <p className="group-hover/domain:block hidden w-max pl-1"> 192 + set as default 193 + </p> 194 + <PinTiny className="text-secondary group-hover/domain:text-accent-2 shrink-0" /> 195 + </> 196 + )} 186 197 </button> 187 198 )} 188 199 </div> ··· 200 211 let { mutate: mutateIdentity } = useIdentityData(); 201 212 let assignment = getDomainAssignment(props.domainData); 202 213 let [confirming, setConfirming] = useState(false); 214 + let [loading, setLoading] = useState(false); 203 215 204 216 async function doAssign() { 217 + setLoading(true); 205 218 mutateIdentityData(mutateIdentity, (draft) => { 206 219 let domain = draft.custom_domains.find( 207 220 (d) => d.domain === props.domainData.domain, ··· 248 261 <button 249 262 className="text-accent-contrast text-xs font-bold" 250 263 type="button" 264 + disabled={loading} 251 265 onClick={() => { 252 266 if (assignment.type === "document") { 253 267 setConfirming(true); ··· 256 270 } 257 271 }} 258 272 > 259 - assign to this publication 273 + {loading ? <DotLoader /> : "assign to this publication"} 260 274 </button> 261 275 )} 262 276 </div> ··· 275 289 > 276 290 Cancel 277 291 </button> 278 - <ButtonPrimary compact onMouseDown={doAssign}> 279 - Reassign 292 + <ButtonPrimary compact disabled={loading} onMouseDown={doAssign}> 293 + {loading ? <DotLoader /> : "Reassign"} 280 294 </ButtonPrimary> 281 295 </div> 282 296 </div>
+5 -1
app/[leaflet_id]/actions/ShareOptions/DomainOptions.tsx
··· 15 15 import { AddDomainForm } from "components/Domains/AddDomainForm"; 16 16 import { DomainSettingsView } from "components/Domains/DomainSettingsView"; 17 17 import { AddTiny } from "components/Icons/AddTiny"; 18 + import { DotLoader } from "components/utils/DotLoader"; 18 19 19 20 type DomainMenuState = 20 21 | { state: "default" } ··· 81 82 let { identity, mutate: mutateIdentity } = useIdentityData(); 82 83 let { permission_token } = useReplicache(); 83 84 85 + let [loading, setLoading] = useState(false); 84 86 let toaster = useToaster(); 85 87 let publishLink = useReadOnlyShareLink(); 86 88 ··· 106 108 107 109 async function doPublish() { 108 110 if (!selectedDomain || !publishLink) return; 111 + setLoading(true); 109 112 let route = "/" + selectedRoute; 110 113 111 114 // Optimistic update ··· 209 212 <ButtonPrimary 210 213 id="publish-to-domain" 211 214 disabled={ 215 + loading || 212 216 routeConflict || 213 217 (domains?.[0] 214 218 ? domains[0].domain === selectedDomain && ··· 217 221 } 218 222 onClick={doPublish} 219 223 > 220 - Publish! 224 + {loading ? <DotLoader /> : "Publish!"} 221 225 </ButtonPrimary> 222 226 </div> 223 227 </div>