Monorepo for wisp.place. A static site hosting service built on top of the AT Protocol.

contrast fixes

+233 -53
+16 -16
apps/hosting-service/src/lib/cache-manager.test.ts
··· 22 22 test('stores and retrieves a value', () => { 23 23 const c = createTestCache() 24 24 c.set('ttl', 'k', 42) 25 - expect(c.get('ttl', 'k')).toBe(42) 25 + expect(c.get<number>('ttl', 'k')).toBe(42) 26 26 }) 27 27 28 28 test('namespaces are isolated', () => { 29 29 const c = createTestCache() 30 30 c.set('ttl', 'k', 'from-ttl') 31 31 c.set('lru', 'k', 'from-lru') 32 - expect(c.get('ttl', 'k')).toBe('from-ttl') 33 - expect(c.get('lru', 'k')).toBe('from-lru') 32 + expect(c.get<string>('ttl', 'k')).toBe('from-ttl') 33 + expect(c.get<string>('lru', 'k')).toBe('from-lru') 34 34 }) 35 35 36 36 test('overwrites existing key', () => { 37 37 const c = createTestCache() 38 38 c.set('lru', 'k', 'v1') 39 39 c.set('lru', 'k', 'v2') 40 - expect(c.get('lru', 'k')).toBe('v2') 40 + expect(c.get<string>('lru', 'k')).toBe('v2') 41 41 }) 42 42 }) 43 43 ··· 45 45 test('returns value within TTL', () => { 46 46 const c = createTestCache() 47 47 c.set('ttl', 'k', 'fresh') 48 - expect(c.get('ttl', 'k')).toBe('fresh') 48 + expect(c.get<string>('ttl', 'k')).toBe('fresh') 49 49 }) 50 50 51 51 test('expires value after TTL', async () => { ··· 64 64 c.set('lru', 'c', 3) 65 65 // At capacity (3). Adding a 4th should evict 'a' (oldest). 66 66 c.set('lru', 'd', 4) 67 - expect(c.get('lru', 'a')).toBeUndefined() 68 - expect(c.get('lru', 'b')).toBe(2) 69 - expect(c.get('lru', 'd')).toBe(4) 67 + expect(c.get<number>('lru', 'a')).toBeUndefined() 68 + expect(c.get<number>('lru', 'b')).toBe(2) 69 + expect(c.get<number>('lru', 'd')).toBe(4) 70 70 }) 71 71 72 72 test('accessing a key refreshes its LRU position', () => { ··· 78 78 c.get('lru', 'a') 79 79 // Now 'b' is the oldest 80 80 c.set('lru', 'd', 4) 81 - expect(c.get('lru', 'b')).toBeUndefined() 82 - expect(c.get('lru', 'a')).toBe(1) 81 + expect(c.get<number>('lru', 'b')).toBeUndefined() 82 + expect(c.get<number>('lru', 'a')).toBe(1) 83 83 }) 84 84 }) 85 85 ··· 118 118 c.set('lru', 'b', 2) 119 119 c.set('ttl', 'x', 3) 120 120 c.clear('lru') 121 - expect(c.get('lru', 'a')).toBeUndefined() 122 - expect(c.get('lru', 'b')).toBeUndefined() 121 + expect(c.get<number>('lru', 'a')).toBeUndefined() 122 + expect(c.get<number>('lru', 'b')).toBeUndefined() 123 123 // Other namespace untouched 124 - expect(c.get('ttl', 'x')).toBe(3) 124 + expect(c.get<number>('ttl', 'x')).toBe(3) 125 125 }) 126 126 }) 127 127 ··· 151 151 }) 152 152 expect(val).toBe('async-result') 153 153 // Second call should be from cache 154 - expect(c.get('lru', 'k')).toBe('async-result') 154 + expect(c.get<string>('lru', 'k')).toBe('async-result') 155 155 }) 156 156 157 157 test('cacheIf: false skips caching', async () => { ··· 170 170 cacheIf: (v) => v !== null, 171 171 }) 172 172 expect(val).toBe('good') 173 - expect(c.get('lru', 'k')).toBe('good') 173 + expect(c.get<string>('lru', 'k')).toBe('good') 174 174 }) 175 175 }) 176 176 ··· 248 248 c.startCleanup(50) 249 249 await Bun.sleep(200) 250 250 c.stopCleanup() 251 - expect(c.get('lru', 'k')).toBe('val') 251 + expect(c.get<string>('lru', 'k')).toBe('val') 252 252 }) 253 253 }) 254 254 })
+33
apps/main-app/public/components/ui/dialog.tsx
··· 89 89 } 90 90 91 91 function DialogFooter({ className, ...props }: React.ComponentProps<"div">) { 92 + const footerRef = React.useRef<HTMLDivElement>(null) 93 + 94 + React.useEffect(() => { 95 + const footer = footerRef.current 96 + if (!footer) return 97 + 98 + const handleKeyDown = (e: KeyboardEvent) => { 99 + if (e.key !== 'ArrowLeft' && e.key !== 'ArrowRight') return 100 + 101 + const buttons = Array.from( 102 + footer.querySelectorAll('button:not([disabled])') 103 + ) as HTMLElement[] 104 + const currentIndex = buttons.indexOf(document.activeElement as HTMLElement) 105 + 106 + if (currentIndex === -1) return 107 + 108 + e.preventDefault() 109 + let nextIndex = currentIndex 110 + 111 + if (e.key === 'ArrowRight') { 112 + nextIndex = (currentIndex + 1) % buttons.length 113 + } else if (e.key === 'ArrowLeft') { 114 + nextIndex = (currentIndex - 1 + buttons.length) % buttons.length 115 + } 116 + 117 + buttons[nextIndex]?.focus() 118 + } 119 + 120 + footer.addEventListener('keydown', handleKeyDown) 121 + return () => footer.removeEventListener('keydown', handleKeyDown) 122 + }, []) 123 + 92 124 return ( 93 125 <div 126 + ref={footerRef} 94 127 data-slot="dialog-footer" 95 128 className={cn( 96 129 "flex flex-col-reverse gap-2 sm:flex-row sm:justify-end",
+1 -1
apps/main-app/public/components/ui/tabs.tsx
··· 40 40 <TabsPrimitive.Trigger 41 41 data-slot="tabs-trigger" 42 42 className={cn( 43 - "data-[state=active]:bg-background dark:data-[state=active]:bg-background dark:data-[state=active]:text-foreground dark:data-[state=active]:border-border focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:outline-ring dark:data-[state=active]:border-border dark:data-[state=active]:shadow-sm text-foreground dark:text-muted-foreground/70 inline-flex h-[calc(100%-1px)] flex-1 items-center justify-center gap-1.5 rounded-md border border-transparent px-2 py-1 text-sm font-medium whitespace-nowrap transition-[color,box-shadow] focus-visible:ring-[3px] focus-visible:outline-1 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:shadow-sm [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4", 43 + "data-[state=active]:bg-background dark:data-[state=active]:bg-background data-[state=active]:text-foreground dark:data-[state=active]:text-foreground dark:data-[state=active]:border-border focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:outline-ring dark:data-[state=active]:border-border dark:data-[state=active]:shadow-sm text-muted-foreground dark:text-muted-foreground/70 hover:bg-muted/50 dark:hover:bg-muted/50 inline-flex h-[calc(100%-1px)] flex-1 items-center justify-center gap-1.5 rounded-md border border-transparent px-2 py-1 text-sm font-medium whitespace-nowrap transition-[color,box-shadow] focus-visible:ring-[3px] focus-visible:outline-1 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:shadow-sm [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4", 44 44 className 45 45 )} 46 46 {...props}
+58 -14
apps/main-app/public/editor/editor.tsx
··· 61 61 const [selectedDomains, setSelectedDomains] = useState<Set<string>>(new Set()) 62 62 const [isSavingConfig, setIsSavingConfig] = useState(false) 63 63 const [isDeletingSite, setIsDeletingSite] = useState(false) 64 + const [deleteConfirmSite, setDeleteConfirmSite] = useState<SiteWithDomains | null>(null) 64 65 65 66 // Site settings state 66 67 type RoutingMode = 'default' | 'spa' | 'directory' | 'custom404' ··· 303 304 } 304 305 } 305 306 306 - const handleDeleteSite = async () => { 307 - if (!configuringSite) return 307 + const handleDeleteConfirmSite = async (site: SiteWithDomains) => { 308 + setDeleteConfirmSite(site) 309 + } 308 310 309 - if (!confirm(`Are you sure you want to delete "${configuringSite.display_name || configuringSite.rkey}"? This action cannot be undone.`)) { 310 - return 311 - } 311 + const handleDeleteSite = async () => { 312 + const site = configuringSite || deleteConfirmSite 313 + if (!site) return 312 314 313 315 setIsDeletingSite(true) 314 - const success = await deleteSite(configuringSite.rkey) 316 + const success = await deleteSite(site.rkey) 315 317 if (success) { 316 318 // Refresh domains in case this site was mapped 317 319 await fetchDomains() 318 320 setConfiguringSite(null) 321 + setDeleteConfirmSite(null) 319 322 } 320 323 setIsDeletingSite(false) 321 324 } ··· 441 444 </div> 442 445 443 446 <Tabs value={activeTab} onValueChange={setActiveTab} className="flex flex-col flex-1 overflow-hidden"> 444 - <TabsList className="grid w-full grid-cols-4 bg-transparent border-b border-border/50 rounded-none h-auto p-0 flex-shrink-0"> 447 + <TabsList className="grid w-full grid-cols-4 bg-card border-b border-border/50 rounded-none h-auto p-0 flex-shrink-0"> 445 448 <TabsTrigger 446 449 value="sites" 447 - className="rounded-none border-b-2 border-transparent data-[state=active]:border-accent data-[state=active]:bg-transparent data-[state=active]:shadow-none py-3" 450 + className="rounded-none border-b-2 border-transparent text-muted-foreground hover:text-foreground hover:bg-muted/50 data-[state=active]:border-accent data-[state=active]:bg-transparent data-[state=active]:text-foreground data-[state=active]:shadow-none py-3" 448 451 > 449 452 Sites 450 453 </TabsTrigger> 451 454 <TabsTrigger 452 455 value="domains" 453 - className="rounded-none border-b-2 border-transparent data-[state=active]:border-accent data-[state=active]:bg-transparent data-[state=active]:shadow-none py-3" 456 + className="rounded-none border-b-2 border-transparent text-muted-foreground hover:text-foreground hover:bg-muted/50 data-[state=active]:border-accent data-[state=active]:bg-transparent data-[state=active]:text-foreground data-[state=active]:shadow-none py-3" 454 457 > 455 458 Domains 456 459 </TabsTrigger> 457 460 <TabsTrigger 458 461 value="upload" 459 - className="rounded-none border-b-2 border-transparent data-[state=active]:border-accent data-[state=active]:bg-transparent data-[state=active]:shadow-none py-3" 462 + className="rounded-none border-b-2 border-transparent text-muted-foreground hover:text-foreground hover:bg-muted/50 data-[state=active]:border-accent data-[state=active]:bg-transparent data-[state=active]:text-foreground data-[state=active]:shadow-none py-3" 460 463 > 461 464 Upload 462 465 </TabsTrigger> 463 466 <TabsTrigger 464 467 value="cli" 465 - className="rounded-none border-b-2 border-transparent data-[state=active]:border-accent data-[state=active]:bg-transparent data-[state=active]:shadow-none py-3" 468 + className="rounded-none border-b-2 border-transparent text-muted-foreground hover:text-foreground hover:bg-muted/50 data-[state=active]:border-accent data-[state=active]:bg-transparent data-[state=active]:text-foreground data-[state=active]:shadow-none py-3" 466 469 > 467 470 Cli 468 471 </TabsTrigger> ··· 475 478 sitesLoading={sitesLoading} 476 479 userInfo={userInfo} 477 480 onConfigureSite={handleConfigureSite} 481 + onDeleteSite={handleDeleteConfirmSite} 478 482 /> 479 483 </TabsContent> 480 484 ··· 580 584 </div> 581 585 582 586 <Tabs defaultValue="domains" className="w-full"> 583 - <TabsList className="grid w-full grid-cols-2"> 584 - <TabsTrigger value="domains">Domains</TabsTrigger> 585 - <TabsTrigger value="settings">Settings</TabsTrigger> 587 + <TabsList className="grid w-full grid-cols-2 bg-card border-b border-border/50 rounded-none h-auto p-0 flex-shrink-0"> 588 + <TabsTrigger value="domains" className="text-muted-foreground hover:text-foreground hover:bg-muted/50 data-[state=active]:bg-transparent data-[state=active]:text-foreground">Domains</TabsTrigger> 589 + <TabsTrigger value="settings" className="text-muted-foreground hover:text-foreground hover:bg-muted/50 data-[state=active]:bg-transparent data-[state=active]:text-foreground">Settings</TabsTrigger> 586 590 </TabsList> 587 591 588 592 {/* Domains Tab */} ··· 907 911 )} 908 912 </Button> 909 913 </div> 914 + </DialogFooter> 915 + </DialogContent> 916 + </Dialog> 917 + 918 + {/* Delete Site Confirmation Modal */} 919 + <Dialog 920 + open={deleteConfirmSite !== null} 921 + onOpenChange={(open) => !open && setDeleteConfirmSite(null)} 922 + > 923 + <DialogContent className="sm:max-w-md"> 924 + <DialogHeader> 925 + <DialogTitle>Delete Site</DialogTitle> 926 + <DialogDescription> 927 + Are you sure you want to delete "{deleteConfirmSite?.display_name || deleteConfirmSite?.rkey}"? This action cannot be undone. 928 + </DialogDescription> 929 + </DialogHeader> 930 + <DialogFooter className="flex flex-col sm:flex-row gap-2 sm:justify-end"> 931 + <Button 932 + variant="outline" 933 + onClick={() => setDeleteConfirmSite(null)} 934 + disabled={isDeletingSite} 935 + className="w-full sm:w-auto" 936 + > 937 + Cancel 938 + </Button> 939 + <Button 940 + variant="destructive" 941 + onClick={handleDeleteSite} 942 + disabled={isDeletingSite} 943 + className="w-full sm:w-auto" 944 + > 945 + {isDeletingSite ? ( 946 + <> 947 + <Loader2 className="w-4 h-4 mr-2 animate-spin" /> 948 + Deleting... 949 + </> 950 + ) : ( 951 + 'Delete' 952 + )} 953 + </Button> 910 954 </DialogFooter> 911 955 </DialogContent> 912 956 </Dialog>
+4 -3
apps/main-app/public/editor/tabs/DomainsTab.tsx
··· 31 31 32 32 // Hosting node IP addresses for A record fallback 33 33 const HOSTING_NODES = [ 34 - { region: 'US East (Virginia)', ip: '192.0.2.1' }, 35 - { region: 'US West (California)', ip: '192.0.2.2' }, 36 - { region: 'Europe (Frankfurt)', ip: '192.0.2.3' }, 34 + { region: 'US East (Virginia)', ip: '129.213.110.75' }, 35 + { region: 'US West (California)', ip: '152.44.44.138' }, 36 + { region: 'Europe (Netherlands)', ip: '152.53.121.97' }, 37 + { region: 'Asia (Singapore)', ip: '213.163.207.16' }, 37 38 ] as const 38 39 39 40 interface DomainsTabProps {
+7 -5
apps/main-app/public/editor/tabs/SitesTab.tsx
··· 18 18 sitesLoading: boolean 19 19 userInfo: UserInfo | null 20 20 onConfigureSite: (site: SiteWithDomains) => void 21 + onDeleteSite: (site: SiteWithDomains) => void 21 22 } 22 23 23 24 // Helper to generate unique site key ··· 42 43 sites, 43 44 sitesLoading, 44 45 userInfo, 45 - onConfigureSite 46 + onConfigureSite, 47 + onDeleteSite 46 48 }: SitesTabProps) { 47 49 // State: only one site can be expanded at a time (null = none expanded) 48 50 const [expandedSiteKey, setExpandedSiteKey] = useState<string | null>(null) ··· 166 168 case 'd': 167 169 if (isExpanded && currentSite) { 168 170 e.preventDefault() 169 - onConfigureSite(currentSite) 171 + onDeleteSite(currentSite) 170 172 } 171 173 break 172 174 } ··· 174 176 175 177 window.addEventListener('keydown', handleKeyDown) 176 178 return () => window.removeEventListener('keydown', handleKeyDown) 177 - }, [sites, focusedIndex, expandedSiteKey, toggleExpanded, getSiteUrl, onConfigureSite]) 179 + }, [sites, focusedIndex, expandedSiteKey, toggleExpanded, getSiteUrl, onConfigureSite, onDeleteSite]) 178 180 179 181 // Loading state 180 182 if (sitesLoading) { ··· 255 257 key={siteKey} 256 258 ref={el => { siteRefs.current[index] = el }} 257 259 className={`border transition-colors ${ 258 - isFocused ? 'border-accent bg-accent/10' : 'border-border/30 hover:bg-muted/20' 260 + isFocused ? 'border-accent bg-accent/10' : 'border-border/30 bg-card hover:bg-muted/10' 259 261 }`} 260 262 > 261 263 {/* Site header */} ··· 365 367 variant="outline" 366 368 size="sm" 367 369 className="font-mono text-xs text-red-400 hover:text-red-500 hover:border-red-400/50" 368 - onClick={() => onConfigureSite(site)} 370 + onClick={() => onDeleteSite(site)} 369 371 > 370 372 <Trash2 className="w-3 h-3 mr-2" /> 371 373 Delete
+105 -5
apps/main-app/public/styles/global.css
··· 22 22 --primary: oklch(0.30 0.025 35); 23 23 --primary-foreground: oklch(0.96 0.008 35); 24 24 25 - /* Deeper pink accent for better visibility */ 26 - --accent: oklch(0.65 0.18 345); 25 + /* Bubblegum pink accent */ 26 + --accent: #ff5c8a; 27 27 --accent-foreground: oklch(0.15 0.015 30); 28 28 29 29 /* Darker taupe secondary for better contrast */ ··· 38 38 --border: oklch(0.65 0.02 30); 39 39 /* Input backgrounds lighter than cards */ 40 40 --input: oklch(0.97 0.005 35); 41 - --ring: oklch(0.55 0.12 345); 41 + --ring: #ff5c8a; 42 42 43 43 --destructive: oklch(0.50 0.20 25); 44 44 --destructive-foreground: oklch(0.98 0 0); 45 45 46 - --chart-1: oklch(0.65 0.18 345); 46 + --chart-1: #ff5c8a; 47 47 --chart-2: oklch(0.32 0.04 285); 48 48 --chart-3: oklch(0.50 0.10 220); 49 49 --chart-4: oklch(0.70 0.08 130); ··· 57 57 --sidebar-accent: oklch(0.90 0.01 35); 58 58 --sidebar-accent-foreground: oklch(0.20 0.02 30); 59 59 --sidebar-border: oklch(0.65 0.02 30); 60 - --sidebar-ring: oklch(0.55 0.12 345); 60 + --sidebar-ring: #ff5c8a; 61 61 } 62 62 63 63 .dark { ··· 156 156 --color-sidebar-accent-foreground: var(--sidebar-accent-foreground); 157 157 --color-sidebar-border: var(--sidebar-border); 158 158 --color-sidebar-ring: var(--sidebar-ring); 159 + --color-hot-fuchsia: #ff0a54; 160 + --color-hot-fuchsia-100: #350010; 161 + --color-hot-fuchsia-200: #6a0020; 162 + --color-hot-fuchsia-300: #9f0030; 163 + --color-hot-fuchsia-400: #d40040; 164 + --color-hot-fuchsia-500: #ff0a54; 165 + --color-hot-fuchsia-600: #ff3b76; 166 + --color-hot-fuchsia-700: #ff6c98; 167 + --color-hot-fuchsia-800: #ff9dba; 168 + --color-hot-fuchsia-900: #ffcedd; 169 + --color-wild-strawberry: #ff477e; 170 + --color-wild-strawberry-100: #410014; 171 + --color-wild-strawberry-200: #830027; 172 + --color-wild-strawberry-300: #c4003b; 173 + --color-wild-strawberry-400: #ff0651; 174 + --color-wild-strawberry-500: #ff477e; 175 + --color-wild-strawberry-600: #ff6c98; 176 + --color-wild-strawberry-700: #ff91b2; 177 + --color-wild-strawberry-800: #ffb6cc; 178 + --color-wild-strawberry-900: #ffdae5; 179 + --color-bubblegum-pink: #ff5c8a; 180 + --color-bubblegum-pink-100: #450014; 181 + --color-bubblegum-pink-200: #8b0027; 182 + --color-bubblegum-pink-300: #d0003b; 183 + --color-bubblegum-pink-400: #ff1658; 184 + --color-bubblegum-pink-500: #ff5c8a; 185 + --color-bubblegum-pink-600: #ff7ca1; 186 + --color-bubblegum-pink-700: #ff9db9; 187 + --color-bubblegum-pink-800: #ffbed0; 188 + --color-bubblegum-pink-900: #ffdee8; 189 + --color-petal-rouge: #ff7096; 190 + --color-petal-rouge-100: #490014; 191 + --color-petal-rouge-200: #930027; 192 + --color-petal-rouge-300: #dc003b; 193 + --color-petal-rouge-400: #ff2760; 194 + --color-petal-rouge-500: #ff7096; 195 + --color-petal-rouge-600: #ff8dab; 196 + --color-petal-rouge-700: #ffa9c0; 197 + --color-petal-rouge-800: #ffc6d5; 198 + --color-petal-rouge-900: #ffe2ea; 199 + --color-bubblegum-tint: #ff85a1; 200 + --color-bubblegum-tint-100: #4e0012; 201 + --color-bubblegum-tint-200: #9b0024; 202 + --color-bubblegum-tint-300: #e90036; 203 + --color-bubblegum-tint-400: #ff3766; 204 + --color-bubblegum-tint-500: #ff85a1; 205 + --color-bubblegum-tint-600: #ff9db4; 206 + --color-bubblegum-tint-700: #ffb6c7; 207 + --color-bubblegum-tint-800: #ffced9; 208 + --color-bubblegum-tint-900: #ffe7ec; 209 + --color-cotton-candy: #ff99ac; 210 + --color-cotton-candy-100: #52000f; 211 + --color-cotton-candy-200: #a3001e; 212 + --color-cotton-candy-300: #f5002d; 213 + --color-cotton-candy-400: #ff4769; 214 + --color-cotton-candy-500: #ff99ac; 215 + --color-cotton-candy-600: #ffadbc; 216 + --color-cotton-candy-700: #ffc2cd; 217 + --color-cotton-candy-800: #ffd6de; 218 + --color-cotton-candy-900: #ffebee; 219 + --color-cherry-blossom: #fbb1bd; 220 + --color-cherry-blossom-100: #510411; 221 + --color-cherry-blossom-200: #a30922; 222 + --color-cherry-blossom-300: #f20f35; 223 + --color-cherry-blossom-400: #f76079; 224 + --color-cherry-blossom-500: #fbb1bd; 225 + --color-cherry-blossom-600: #fcc1cb; 226 + --color-cherry-blossom-700: #fdd0d8; 227 + --color-cherry-blossom-800: #fde0e5; 228 + --color-cherry-blossom-900: #feeff2; 229 + --color-pastel-pink: #f9bec7; 230 + --color-pastel-pink-100: #500712; 231 + --color-pastel-pink-200: #a10f25; 232 + --color-pastel-pink-300: #ea1d3c; 233 + --color-pastel-pink-400: #f16d81; 234 + --color-pastel-pink-500: #f9bec7; 235 + --color-pastel-pink-600: #facbd2; 236 + --color-pastel-pink-700: #fbd8dd; 237 + --color-pastel-pink-800: #fde5e8; 238 + --color-pastel-pink-900: #fef2f4; 239 + --color-cotton-rose: #f7cad0; 240 + --color-cotton-rose-100: #4e0c15; 241 + --color-cotton-rose-200: #9c1729; 242 + --color-cotton-rose-300: #e02e45; 243 + --color-cotton-rose-400: #eb7c8b; 244 + --color-cotton-rose-500: #f7cad0; 245 + --color-cotton-rose-600: #f9d4d9; 246 + --color-cotton-rose-700: #fadfe3; 247 + --color-cotton-rose-800: #fceaec; 248 + --color-cotton-rose-900: #fdf4f6; 249 + --color-soft-blush: #fae0e4; 250 + --color-soft-blush-100: #520d18; 251 + --color-soft-blush-200: #a31b2f; 252 + --color-soft-blush-300: #df3d55; 253 + --color-soft-blush-400: #ed8f9d; 254 + --color-soft-blush-500: #fae0e4; 255 + --color-soft-blush-600: #fbe6ea; 256 + --color-soft-blush-700: #fcedef; 257 + --color-soft-blush-800: #fdf3f4; 258 + --color-soft-blush-900: #fef9fa; 159 259 } 160 260 161 261 @layer base {
+9 -9
apps/main-app/src/routes/wisp.ts
··· 317 317 await upsertSiteCache(did, rkey, record.data.cid, {}); 318 318 } catch (err) { 319 319 // Don't fail the upload if caching fails 320 - logger.warn('Failed to cache site', err); 320 + logger.warn('Failed to cache site', err as any); 321 321 } 322 322 323 323 // Auto-map claimed domain to this site if user has a claimed domain with no rkey ··· 331 331 logger.info(`Auto-mapped domain ${existingDomain} to new site ${siteName}`); 332 332 } 333 333 } 334 - } catch (err) { 335 - // Don't fail the upload if domain mapping fails 336 - logger.warn('Failed to auto-map domain to new site', err); 337 - } 334 + } catch (err) { 335 + // Don't fail the upload if domain mapping fails 336 + logger.warn('Failed to auto-map domain to new site', err as any); 337 + } 338 338 339 339 completeUploadJob(jobId, { 340 340 success: true, ··· 888 888 await upsertSiteCache(did, rkey, record.data.cid, fileCids); 889 889 } catch (err) { 890 890 // Don't fail the upload if caching fails 891 - logger.warn('Failed to cache site files', err); 891 + logger.warn('Failed to cache site files', err as any); 892 892 } 893 893 894 894 // Auto-map claimed domain to this site if user has a claimed domain with no rkey ··· 904 904 } 905 905 } catch (err) { 906 906 // Don't fail the upload if domain mapping fails 907 - logger.warn('Failed to auto-map domain to new site', err); 907 + logger.warn('Failed to auto-map domain to new site', err as any); 908 908 } 909 909 910 910 // Clean up old subfs records if we had any ··· 1135 1135 await upsertSiteCache(auth.did, rkey, record.data.cid, {}); 1136 1136 } catch (err) { 1137 1137 // Don't fail the upload if caching fails 1138 - logger.warn('Failed to cache site', err); 1138 + logger.warn('Failed to cache site', err as any); 1139 1139 } 1140 1140 1141 1141 // Auto-map claimed domain to this site if user has a claimed domain with no rkey ··· 1151 1151 } 1152 1152 } catch (err) { 1153 1153 // Don't fail the upload if domain mapping fails 1154 - logger.warn('Failed to auto-map domain to new site', err); 1154 + logger.warn('Failed to auto-map domain to new site', err as any); 1155 1155 } 1156 1156 1157 1157 return {