One Calendar is a privacy-first calendar web app built with Next.js. It has modern security features, including e2ee, password-protected sharing, and self-destructing share links ๐Ÿ“… calendar.xyehr.cn
5
fork

Configure Feed

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

Merge pull request #237 from EvanTechDev/codex/fix-tabs-component-style-bug

fix: correct active tab highlight in import cards tabs

authored by

Evan Huang and committed by
GitHub
d47471af ee278455

+96 -125
+25
components/app/profile/shared-event.tsx
··· 4 4 import { useEffect, useState } from "react"; 5 5 import { useRouter } from "next/navigation"; 6 6 import Image from "next/image"; 7 + import Link from "next/link"; 7 8 import { format } from "date-fns"; 8 9 import { 9 10 MapPin, ··· 58 59 handle?: string; 59 60 } 60 61 62 + const APP_VERSION = process.env.NEXT_PUBLIC_APP_VERSION ?? "unknown"; 63 + 64 + function SharePageFooter({ isZh }: { isZh: boolean }) { 65 + return ( 66 + <footer className="fixed bottom-0 inset-x-0 z-20 px-4 py-3"> 67 + <div className="mx-auto flex w-full max-w-5xl items-center justify-between text-xs text-muted-foreground"> 68 + <span className="font-mono">v{APP_VERSION}</span> 69 + <div className="flex items-center gap-4"> 70 + <Link href="/privacy" className="transition-colors hover:text-foreground"> 71 + {isZh ? "้š็งๆ”ฟ็ญ–" : "Privacy Policy"} 72 + </Link> 73 + <Link href="/terms" className="transition-colors hover:text-foreground"> 74 + {isZh ? "ๆœๅŠกๆกๆฌพ" : "Terms of Service"} 75 + </Link> 76 + </div> 77 + </div> 78 + </footer> 79 + ); 80 + } 81 + 61 82 function getDarkerColorClass(color: string) { 62 83 const colorMapping: Record<string, string> = { 63 84 "bg-[#E6F6FD]": "#3B82F6", ··· 330 351 <p className="mt-6 text-lg font-medium text-gray-600 dark:text-gray-300"> 331 352 {isZh ? "ๅŠ ่ฝฝไธญ..." : "Loading..."} 332 353 </p> 354 + <SharePageFooter isZh={isZh} /> 333 355 </div> 334 356 ); 335 357 } ··· 461 483 </Card> 462 484 </motion.div> 463 485 </div> 486 + <SharePageFooter isZh={isZh} /> 464 487 </div> 465 488 ); 466 489 } ··· 528 551 </Card> 529 552 </motion.div> 530 553 </div> 554 + <SharePageFooter isZh={isZh} /> 531 555 </div> 532 556 ); 533 557 } ··· 728 752 </Card> 729 753 </motion.div> 730 754 </div> 755 + <SharePageFooter isZh={isZh} /> 731 756 </div> 732 757 ); 733 758 }
+5 -1
components/auth/login-form.tsx
··· 20 20 OAUTH_PROVIDER_CONFIG, 21 21 type OAuthStrategy, 22 22 } from "@/lib/clerk-oauth"; 23 + import { OAuthProviderIcon } from "@/components/auth/oauth-provider-icon"; 23 24 24 25 export function LoginForm({ 25 26 className, ··· 161 162 type="button" 162 163 onClick={() => handleOAuthLogin(provider.strategy)} 163 164 > 164 - <span>Login with {provider.label}</span> 165 + <span className="flex items-center justify-center gap-2"> 166 + <OAuthProviderIcon providerKey={providerKey} /> 167 + <span>Login with {provider.label}</span> 168 + </span> 165 169 </Button> 166 170 ); 167 171 })}
+57
components/auth/oauth-provider-icon.tsx
··· 1 + "use client"; 2 + 3 + import type { OAuthProviderKey } from "@/lib/clerk-oauth"; 4 + 5 + interface OAuthProviderIconProps { 6 + providerKey: OAuthProviderKey; 7 + className?: string; 8 + } 9 + 10 + export function OAuthProviderIcon({ 11 + providerKey, 12 + className = "h-5 w-5", 13 + }: OAuthProviderIconProps) { 14 + if (providerKey === "microsoft") { 15 + return ( 16 + <svg viewBox="0 0 23 23" className={className} aria-hidden="true"> 17 + <path fill="#f25022" d="M1 1h10v10H1z" /> 18 + <path fill="#00a4ef" d="M12 1h10v10H12z" /> 19 + <path fill="#7fba00" d="M1 12h10v10H1z" /> 20 + <path fill="#ffb900" d="M12 12h10v10H12z" /> 21 + </svg> 22 + ); 23 + } 24 + 25 + if (providerKey === "google") { 26 + return ( 27 + <svg viewBox="0 0 24 24" className={className} aria-hidden="true"> 28 + <path 29 + d="M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92c-.26 1.37-1.04 2.53-2.21 3.31v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.09z" 30 + fill="#4285F4" 31 + /> 32 + <path 33 + d="M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z" 34 + fill="#34A853" 35 + /> 36 + <path 37 + d="M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l2.85-2.22.81-.62z" 38 + fill="#FBBC05" 39 + /> 40 + <path 41 + d="M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z" 42 + fill="#EA4335" 43 + /> 44 + <path d="M1 1h22v22H1z" fill="none" /> 45 + </svg> 46 + ); 47 + } 48 + 49 + return ( 50 + <svg viewBox="0 0 24 24" className={className} aria-hidden="true"> 51 + <path 52 + d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12" 53 + fill="currentColor" 54 + /> 55 + </svg> 56 + ); 57 + }
+5 -1
components/auth/sign-up-form.tsx
··· 14 14 OAUTH_PROVIDER_CONFIG, 15 15 type OAuthStrategy, 16 16 } from "@/lib/clerk-oauth"; 17 + import { OAuthProviderIcon } from "@/components/auth/oauth-provider-icon"; 17 18 18 19 export function SignUpForm({ 19 20 className, ··· 318 319 type="button" 319 320 onClick={() => handleOAuthSignUp(provider.strategy)} 320 321 > 321 - <span>Continue with {provider.label}</span> 322 + <span className="flex items-center justify-center gap-2"> 323 + <OAuthProviderIcon providerKey={providerKey} /> 324 + <span>Continue with {provider.label}</span> 325 + </span> 322 326 </Button> 323 327 ); 324 328 })}
+4 -4
components/ui/tabs.tsx
··· 63 63 <TabsPrimitive.Trigger 64 64 data-slot="tabs-trigger" 65 65 className={cn( 66 - "relative inline-flex h-[calc(100%-1px)] flex-1 items-center justify-center gap-1.5 rounded-md border border-transparent px-1.5 py-0.5 text-sm font-medium whitespace-nowrap text-foreground/60 transition-all group-data-vertical/tabs:w-full group-data-vertical/tabs:justify-start hover:text-foreground focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 focus-visible:outline-1 focus-visible:outline-ring disabled:pointer-events-none disabled:opacity-50 has-data-[icon=inline-end]:pr-1 has-data-[icon=inline-start]:pl-1 dark:text-muted-foreground dark:hover:text-foreground group-data-[variant=default]/tabs-list:data-active:shadow-sm group-data-[variant=line]/tabs-list:data-active:shadow-none [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4", 67 - "group-data-[variant=line]/tabs-list:bg-transparent group-data-[variant=line]/tabs-list:data-active:bg-transparent dark:group-data-[variant=line]/tabs-list:data-active:border-transparent dark:group-data-[variant=line]/tabs-list:data-active:bg-transparent", 68 - "data-active:bg-background data-active:text-foreground dark:data-active:border-input dark:data-active:bg-input/30 dark:data-active:text-foreground", 69 - "after:absolute after:bg-foreground after:opacity-0 after:transition-opacity group-data-horizontal/tabs:after:inset-x-0 group-data-horizontal/tabs:after:bottom-[-5px] group-data-horizontal/tabs:after:h-0.5 group-data-vertical/tabs:after:inset-y-0 group-data-vertical/tabs:after:-right-1 group-data-vertical/tabs:after:w-0.5 group-data-[variant=line]/tabs-list:data-active:after:opacity-100", 66 + "relative inline-flex h-[calc(100%-1px)] flex-1 items-center justify-center gap-1.5 rounded-md border border-transparent px-1.5 py-0.5 text-sm font-medium whitespace-nowrap text-foreground/60 transition-all group-data-vertical/tabs:w-full group-data-vertical/tabs:justify-start hover:text-foreground focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 focus-visible:outline-1 focus-visible:outline-ring disabled:pointer-events-none disabled:opacity-50 has-data-[icon=inline-end]:pr-1 has-data-[icon=inline-start]:pl-1 dark:text-muted-foreground dark:hover:text-foreground group-data-[variant=default]/tabs-list:data-[state=active]:shadow-sm group-data-[variant=line]/tabs-list:data-[state=active]:shadow-none [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4", 67 + "group-data-[variant=line]/tabs-list:bg-transparent group-data-[variant=line]/tabs-list:data-[state=active]:bg-transparent dark:group-data-[variant=line]/tabs-list:data-[state=active]:border-transparent dark:group-data-[variant=line]/tabs-list:data-[state=active]:bg-transparent", 68 + "data-[state=active]:bg-background data-[state=active]:text-foreground dark:data-[state=active]:border-input dark:data-[state=active]:bg-input/30 dark:data-[state=active]:text-foreground", 69 + "after:absolute after:bg-foreground after:opacity-0 after:transition-opacity group-data-horizontal/tabs:after:inset-x-0 group-data-horizontal/tabs:after:bottom-[-5px] group-data-horizontal/tabs:after:h-0.5 group-data-vertical/tabs:after:inset-y-0 group-data-vertical/tabs:after:-right-1 group-data-vertical/tabs:after:w-0.5 group-data-[variant=line]/tabs-list:data-[state=active]:after:opacity-100", 70 70 className 71 71 )} 72 72 {...props}
-102
lib/icsUtils.ts
··· 1 - import { createEvents, type EventAttributes } from "ics"; 2 - 3 - interface Event { 4 - id: string; 5 - title: string; 6 - date: Date; 7 - description?: string; 8 - } 9 - 10 - export function exportToICS(events: Event[]) { 11 - const icsEvents: EventAttributes[] = events.map((event) => { 12 - const startDate = new Date(event.date); 13 - 14 - const endDate = new Date(startDate.getTime() + 60 * 60 * 1000); 15 - 16 - const start = [ 17 - startDate.getUTCFullYear(), 18 - startDate.getUTCMonth() + 1, 19 - startDate.getUTCDate(), 20 - startDate.getUTCHours(), 21 - startDate.getUTCMinutes(), 22 - ]; 23 - 24 - const durationHours = Math.floor( 25 - (endDate.getTime() - startDate.getTime()) / (1000 * 60 * 60), 26 - ); 27 - const durationMinutes = Math.floor( 28 - ((endDate.getTime() - startDate.getTime()) % (1000 * 60 * 60)) / 29 - (1000 * 60), 30 - ); 31 - 32 - return { 33 - title: event.title, 34 - description: event.description, 35 - start: start, 36 - duration: { hours: durationHours, minutes: durationMinutes }, 37 - }; 38 - }); 39 - 40 - createEvents(icsEvents, (error, value) => { 41 - if (error) { 42 - console.log(error); 43 - return; 44 - } 45 - 46 - const blob = new Blob([value], { type: "text/calendar;charset=utf-8" }); 47 - const link = document.createElement("a"); 48 - link.href = window.URL.createObjectURL(blob); 49 - link.setAttribute("download", "calendar.ics"); 50 - document.body.appendChild(link); 51 - link.click(); 52 - document.body.removeChild(link); 53 - }); 54 - } 55 - 56 - export async function importFromICS(file: File): Promise<Event[]> { 57 - const text = await file.text(); 58 - const lines = text.split("\n"); 59 - const events: Event[] = []; 60 - let currentEvent: Partial<Event> = {}; 61 - 62 - for (const line of lines) { 63 - if (line.startsWith("BEGIN:VEVENT")) { 64 - currentEvent = {}; 65 - } else if (line.startsWith("END:VEVENT")) { 66 - if (currentEvent.title && currentEvent.date) { 67 - events.push(currentEvent as Event); 68 - } 69 - currentEvent = {}; 70 - } else if (line.startsWith("SUMMARY:")) { 71 - currentEvent.title = line.slice(8); 72 - } else if (line.startsWith("DTSTART:")) { 73 - const dateString = line.slice(8); 74 - 75 - if (dateString.endsWith("Z")) { 76 - const year = Number.parseInt(dateString.slice(0, 4), 10); 77 - const month = Number.parseInt(dateString.slice(4, 6), 10) - 1; 78 - const day = Number.parseInt(dateString.slice(6, 8), 10); 79 - const hour = Number.parseInt(dateString.slice(9, 11), 10); 80 - const minute = Number.parseInt(dateString.slice(11, 13), 10); 81 - const second = Number.parseInt(dateString.slice(13, 15), 10); 82 - 83 - currentEvent.date = new Date( 84 - Date.UTC(year, month, day, hour, minute, second), 85 - ); 86 - } else { 87 - currentEvent.date = new Date( 88 - Number.parseInt(dateString.slice(0, 4), 10), 89 - Number.parseInt(dateString.slice(4, 6), 10) - 1, 90 - Number.parseInt(dateString.slice(6, 8), 10), 91 - Number.parseInt(dateString.slice(9, 11), 10), 92 - Number.parseInt(dateString.slice(11, 13), 10), 93 - Number.parseInt(dateString.slice(13, 15), 10), 94 - ); 95 - } 96 - } else if (line.startsWith("DESCRIPTION:")) { 97 - currentEvent.description = line.slice(12); 98 - } 99 - } 100 - 101 - return events; 102 - }
-1
public/file.svg
··· 1 - <svg fill="none" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><path d="M14.5 13.5V5.41a1 1 0 0 0-.3-.7L9.8.29A1 1 0 0 0 9.08 0H1.5v13.5A2.5 2.5 0 0 0 4 16h8a2.5 2.5 0 0 0 2.5-2.5m-1.5 0v-7H8v-5H3v12a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1M9.5 5V2.12L12.38 5zM5.13 5h-.62v1.25h2.12V5zm-.62 3h7.12v1.25H4.5zm.62 3h-.62v1.25h7.12V11z" clip-rule="evenodd" fill="#666" fill-rule="evenodd"/></svg>
-1
public/globe.svg
··· 1 - <svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><g clip-path="url(#a)"><path fill-rule="evenodd" clip-rule="evenodd" d="M10.27 14.1a6.5 6.5 0 0 0 3.67-3.45q-1.24.21-2.7.34-.31 1.83-.97 3.1M8 16A8 8 0 1 0 8 0a8 8 0 0 0 0 16m.48-1.52a7 7 0 0 1-.96 0H7.5a4 4 0 0 1-.84-1.32q-.38-.89-.63-2.08a40 40 0 0 0 3.92 0q-.25 1.2-.63 2.08a4 4 0 0 1-.84 1.31zm2.94-4.76q1.66-.15 2.95-.43a7 7 0 0 0 0-2.58q-1.3-.27-2.95-.43a18 18 0 0 1 0 3.44m-1.27-3.54a17 17 0 0 1 0 3.64 39 39 0 0 1-4.3 0 17 17 0 0 1 0-3.64 39 39 0 0 1 4.3 0m1.1-1.17q1.45.13 2.69.34a6.5 6.5 0 0 0-3.67-3.44q.65 1.26.98 3.1M8.48 1.5l.01.02q.41.37.84 1.31.38.89.63 2.08a40 40 0 0 0-3.92 0q.25-1.2.63-2.08a4 4 0 0 1 .85-1.32 7 7 0 0 1 .96 0m-2.75.4a6.5 6.5 0 0 0-3.67 3.44 29 29 0 0 1 2.7-.34q.31-1.83.97-3.1M4.58 6.28q-1.66.16-2.95.43a7 7 0 0 0 0 2.58q1.3.27 2.95.43a18 18 0 0 1 0-3.44m.17 4.71q-1.45-.12-2.69-.34a6.5 6.5 0 0 0 3.67 3.44q-.65-1.27-.98-3.1" fill="#666"/></g><defs><clipPath id="a"><path fill="#fff" d="M0 0h16v16H0z"/></clipPath></defs></svg>
-13
public/icon_no_border.svg
··· 1 - <svg version="1.0" xmlns="http://www.w3.org/2000/svg" width="375" height="644" viewBox="324.5 178.12 367.99 643.88" preserveAspectRatio="xMidYMid meet"> 2 - 3 - <g transform="translate(0,1000) scale(0.1,-0.1)" fill="currentColor" stroke="none" style="fill:rgb(0, 0, 0);stroke:none;color:rgb(0, 0, 0);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:&quot;Anthropic Sans&quot;, -apple-system, BlinkMacSystemFont, &quot;Segoe UI&quot;, sans-serif;font-size:16px;font-weight:400;text-anchor:start;dominant-baseline:auto"> 4 - <path d="M4960 8206 c-87 -24 -164 -70 -231 -136 -101 -101 -149 -217 -149&#10;-360 0 -144 48 -259 150 -360 102 -102 218 -150 360 -150 140 0 264 53 365&#10;156 194 198 194 508 0 709 -67 69 -165 125 -253 144 -68 14 -184 13 -242 -3z" style="fill:rgb(0, 0, 0);stroke:none;color:rgb(0, 0, 0);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:&quot;Anthropic Sans&quot;, -apple-system, BlinkMacSystemFont, &quot;Segoe UI&quot;, sans-serif;font-size:16px;font-weight:400;text-anchor:start;dominant-baseline:auto"/> 5 - <path d="M3616 6859 c-109 -26 -239 -117 -307 -215 -97 -141 -111 -350 -34&#10;-510 61 -126 166 -217 305 -264 55 -19 82 -21 175 -18 102 3 115 6 185 39 147&#10;70 239 172 281 311 17 57 21 88 18 182 -4 109 -5 115 -46 198 -68 136 -202&#10;245 -343 277 -54 13 -180 12 -234 0z" style="fill:rgb(0, 0, 0);stroke:none;color:rgb(0, 0, 0);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:&quot;Anthropic Sans&quot;, -apple-system, BlinkMacSystemFont, &quot;Segoe UI&quot;, sans-serif;font-size:16px;font-weight:400;text-anchor:start;dominant-baseline:auto"/> 6 - <path d="M4963 6855 c-228 -64 -383 -263 -383 -493 0 -149 45 -259 149 -363&#10;105 -105 212 -149 362 -149 188 0 345 90 443 254 70 117 85 297 35 434 -48&#10;130 -170 250 -306 302 -75 29 -225 37 -300 15z" style="fill:rgb(0, 0, 0);stroke:none;color:rgb(0, 0, 0);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:&quot;Anthropic Sans&quot;, -apple-system, BlinkMacSystemFont, &quot;Segoe UI&quot;, sans-serif;font-size:16px;font-weight:400;text-anchor:start;dominant-baseline:auto"/> 7 - <path d="M4940 5491 c-91 -29 -142 -61 -211 -130 -103 -103 -149 -214 -149&#10;-361 0 -328 308 -570 629 -495 279 66 450 358 373 636 -46 164 -177 299 -340&#10;349 -83 26 -224 26 -302 1z" style="fill:rgb(0, 0, 0);stroke:none;color:rgb(0, 0, 0);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:&quot;Anthropic Sans&quot;, -apple-system, BlinkMacSystemFont, &quot;Segoe UI&quot;, sans-serif;font-size:16px;font-weight:400;text-anchor:start;dominant-baseline:auto"/> 8 - <path d="M4980 4149 c-81 -16 -188 -76 -255 -145 -97 -100 -145 -215 -145&#10;-354 0 -147 46 -258 149 -361 105 -105 212 -149 362 -149 455 0 680 547 358&#10;869 -121 122 -296 174 -469 140z" style="fill:rgb(0, 0, 0);stroke:none;color:rgb(0, 0, 0);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:&quot;Anthropic Sans&quot;, -apple-system, BlinkMacSystemFont, &quot;Segoe UI&quot;, sans-serif;font-size:16px;font-weight:400;text-anchor:start;dominant-baseline:auto"/> 9 - <path d="M3601 2784 c-116 -31 -242 -125 -306 -229 -65 -105 -87 -283 -50&#10;-410 61 -215 263 -365 490 -365 134 0 244 43 343 135 118 109 162 211 162 376&#10;0 160 -46 267 -159 371 -103 96 -213 139 -351 137 -41 0 -99 -7 -129 -15z" style="fill:rgb(0, 0, 0);stroke:none;color:rgb(0, 0, 0);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:&quot;Anthropic Sans&quot;, -apple-system, BlinkMacSystemFont, &quot;Segoe UI&quot;, sans-serif;font-size:16px;font-weight:400;text-anchor:start;dominant-baseline:auto"/> 10 - <path d="M4959 2785 c-85 -23 -162 -69 -229 -135 -102 -101 -150 -216 -150&#10;-360 0 -147 57 -278 162 -374 205 -187 515 -181 709 13 157 157 193 397 91&#10;600 -56 112 -196 223 -326 257 -63 17 -195 17 -257 -1z" style="fill:rgb(0, 0, 0);stroke:none;color:rgb(0, 0, 0);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:&quot;Anthropic Sans&quot;, -apple-system, BlinkMacSystemFont, &quot;Segoe UI&quot;, sans-serif;font-size:16px;font-weight:400;text-anchor:start;dominant-baseline:auto"/> 11 - <path d="M6311 2784 c-76 -20 -146 -60 -212 -122 -113 -104 -159 -211 -159&#10;-371 0 -189 74 -329 228 -431 103 -68 259 -97 385 -71 130 28 271 129 336 245&#10;86 151 86 361 1 512 -38 65 -141 164 -208 198 -109 55 -256 71 -371 40z" style="fill:rgb(0, 0, 0);stroke:none;color:rgb(0, 0, 0);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:&quot;Anthropic Sans&quot;, -apple-system, BlinkMacSystemFont, &quot;Segoe UI&quot;, sans-serif;font-size:16px;font-weight:400;text-anchor:start;dominant-baseline:auto"/> 12 - </g> 13 - </svg>
public/og.png

This is a binary file and will not be displayed.

public/sf.otf

This is a binary file and will not be displayed.

-1
public/vercel.svg
··· 1 - <svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1155 1000"><path d="m577.3 0 577.4 1000H0z" fill="#fff"/></svg>
-1
public/window.svg
··· 1 - <svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path fill-rule="evenodd" clip-rule="evenodd" d="M1.5 2.5h13v10a1 1 0 0 1-1 1h-11a1 1 0 0 1-1-1zM0 1h16v11.5a2.5 2.5 0 0 1-2.5 2.5h-11A2.5 2.5 0 0 1 0 12.5zm3.75 4.5a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5M7 4.75a.75.75 0 1 1-1.5 0 .75.75 0 0 1 1.5 0m1.75.75a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5" fill="#666"/></svg>