One-click backups for AT Protocol

Compare changes

Choose any two refs to compare.

Changed files
+196 -67
docs
+14 -7
README.md
··· 1 1 <div align="center"> 2 2 <img src="./images/atbackup_large.png"/> 3 + </div> 4 + 5 + ## Features 6 + 7 + - Local first: saved to your file system 8 + - Standard format: backups are stored as CAR files, which Bluesky uses 9 + - Backup overview: see your backup's size and record types 10 + 11 + ## Contributing 12 + 13 + We're welcome to any and all contributions. Mention us on Bluesky if we're slow, we may have missed your PR! 3 14 4 - <h1>AT Backup</h1> 5 - <p>One-click local Bluesky/ATProto backups</p> 6 - </div> 15 + ## Forking 16 + 17 + You have our blessing and encouragement to fork this project and we're excited to see what you build! 7 18 8 19 ## Built with 9 20 ··· 12 23 - ATProto 13 24 - atcute (for CAR file parsing) 14 25 - shadcn UI 15 - 16 - ## Recommended IDE Setup 17 - 18 - - [VS Code](https://code.visualstudio.com/) + [Tauri](https://marketplace.visualstudio.com/items?itemName=tauri-apps.tauri-vscode) + [rust-analyzer](https://marketplace.visualstudio.com/items?itemName=rust-lang.rust-analyzer)
docs/.yarn/install-state.gz

This is a binary file and will not be displayed.

+19 -12
docs/app/auth/complete/page.tsx
··· 12 12 13 13 function AuthCompleteContent() { 14 14 const [loading, setLoading] = React.useState(true); 15 - // Get all parameters from the URL 16 - const currentUrl = new URL(window.location.href); 17 - const params = new URLSearchParams(currentUrl.search); 15 + const [redirectUrl, setRedirectUrl] = React.useState(""); 16 + 17 + useEffect(() => { 18 + // Only run on client side 19 + if (typeof window === "undefined") return; 20 + 21 + // Get all parameters from the URL 22 + const currentUrl = new URL(window.location.href); 23 + const params = new URLSearchParams(currentUrl.search); 24 + 25 + params.forEach((value, key) => { 26 + console.log(key, "=", value); 27 + }); 18 28 19 - params.forEach((value, key) => { 20 - console.log(key, "=", value); 21 - }); 29 + // Construct the redirect URL preserving all parameters 30 + const url = `atprotobackups://auth${ 31 + currentUrl.search || "?" + currentUrl.hash.slice(1) 32 + }`; 33 + setRedirectUrl(url); 22 34 23 - // Construct the redirect URL preserving all parameters 24 - const redirectUrl = `atprotobackups://auth${ 25 - currentUrl.search || "?" + currentUrl.hash.slice(1) 26 - }`; 27 - useEffect(() => { 28 35 // Open the URL in the system's default handler and close the window after a short delay 29 - window.location.href = redirectUrl; 36 + window.location.href = url; 30 37 31 38 // Close the window after a short delay to ensure the protocol handler is triggered 32 39 setTimeout(() => {
+20 -15
docs/app/layout.tsx
··· 6 6 import Image from "next/image"; 7 7 import Link from "next/link"; 8 8 import { Metadata } from "next"; 9 + import { Bluesky, Tangled } from "@/components/icons"; 9 10 10 11 export const metadata: Metadata = { 11 12 description: "One-click backup for Bluesky", ··· 53 54 <Footer> 54 55 <div className="flex items-center justify-between w-full"> 55 56 <span /> 56 - <Link 57 - href="https://bsky.app/profile/atbackup.pages.dev" 58 - className="hover:opacity-80 transition-opacity" 59 - target="_blank" 60 - rel="noopener noreferrer" 61 - > 62 - <Image 63 - src="/bsky.svg" 64 - alt="Bluesky" 65 - width={24} 66 - height={24} 67 - color="white" 68 - /> 69 - </Link> 57 + <div className="flex flex-row gap-2"> 58 + <Link 59 + href="https://tangled.org/did:plc:5fzwpxt3rctfetyqpbigvgic/atbackup" 60 + className="hover:opacity-70 transition-opacity" 61 + target="_blank" 62 + rel="noopener noreferrer" 63 + > 64 + <Tangled className="w-6 h-6 text-black dark:text-white" /> 65 + </Link> 66 + <Link 67 + href="https://bsky.app/profile/atbackup.pages.dev" 68 + className="hover:opacity-70 transition-opacity" 69 + target="_blank" 70 + rel="noopener noreferrer" 71 + > 72 + <Bluesky className="w-6 h-6 text-black dark:text-white" /> 73 + </Link> 74 + </div> 70 75 </div> 71 76 </Footer> 72 77 ); ··· 84 89 suppressHydrationWarning 85 90 > 86 91 <Head 87 - // ... Your additional head options 92 + // ... Your additional head options 88 93 > 89 94 {/* Your additional tags should be passed as `children` of `<Head>` element */} 90 95 </Head>
+78 -32
docs/app/page.tsx
··· 2 2 3 3 import Image from "next/image"; 4 4 import React from "react"; 5 - import { Download, Pause, Play, RefreshCcw } from "lucide-react"; 5 + import { 6 + CloudOff, 7 + Download, 8 + FolderGit2, 9 + Pause, 10 + Play, 11 + RefreshCcw, 12 + } from "lucide-react"; 6 13 import { useThemeConfig } from "nextra-theme-docs"; 7 14 import { 8 15 Accordion, ··· 11 18 AccordionTrigger, 12 19 } from "@/components/ui/accordion"; 13 20 21 + // Accordion styling constants 22 + const ACCORDION_TRIGGER_CLASSES = 23 + "flex items-center justify-between gap-2 text-lg font-medium bg-black/5 dark:bg-white/5 rounded-md px-4 py-3 cursor-pointer hover:no-underline hover:bg-black/8 dark:hover:bg-white/8 transition"; 24 + const ACCORDION_CONTENT_CLASSES = 25 + "mt-2 text-black/75 dark:text-white/75 text-base rounded-md p-4"; 26 + 14 27 function getOS(): "windows" | "macos" | "linux" | "unknown" { 15 28 if (typeof window === "undefined") return "unknown"; 16 29 const ua = window.navigator.userAgent; ··· 61 74 }/70`} 62 75 > 63 76 <div> 64 - <h1 className="text-[2.5rem] font-bold text-white m-0 max-w-[350px] leading-tight"> 77 + <h1 className="text-[2.5rem] font-bold text-black dark:text-white m-0 max-w-[350px] leading-tight"> 65 78 One-click local backups of your atproto data 66 79 </h1> 67 - <p className="text-lg text-white/80 mt-4 max-w-[350px]"> 80 + <p className="text-lg text-black/80 dark:text-white/80 mt-4 max-w-[350px]"> 68 81 Easily back up your Bluesky posts, likes, and other records (e.g. 69 82 other AT Protocol app data) to your computer's filesystem. 70 83 </p> 71 84 <a 72 85 href={url} 73 - className="mt-6 px-6 py-3 bg-white text-black rounded-md hover:bg-white/80 transition-colors inline-block" 86 + className="mt-6 px-6 py-3 dark:bg-white bg-black dark:text-black text-white rounded-md hover:bg-black/80 dark:hover:bg-white/80 transition-colors inline-block" 74 87 download 75 88 > 76 89 <div className="flex items-center gap-2 font-medium"> ··· 91 104 </div> 92 105 </div> 93 106 <div className="w-full h-[0.5px] bg-white/10 mb-4" /> 107 + 108 + <div className="flex flex-col items-center w-full"> 109 + <div className="flex flex-col md:flex-row items-center justify-center gap-8 min-h-[60vh] p-8"> 110 + <div> 111 + <VideoPlayer className="w-lg" /> 112 + </div> 113 + <div className="relative mt-8 md:mt-0"> 114 + <h1 className="text-[2.5rem] font-bold text-black dark:text-white m-0 max-w-[350px] leading-tight"> 115 + Intuitive and cozy 116 + </h1> 117 + <p className="text-lg text-black/80 dark:text-white/80 mt-4 max-w-[350px]"> 118 + See how easy it is to save your Bluesky data to your computer. 119 + </p> 120 + </div> 121 + </div> 122 + </div> 94 123 <div className="flex flex-col items-center max-w[800px] mx-auto my-16 px-4 w-full"> 95 124 <Accordion 96 125 type="single" 97 126 collapsible 98 127 className="w-full max-w-2xl flex flex-col gap-4" 99 128 > 100 - <AccordionItem value="item-1"> 101 - <AccordionTrigger className="flex items-center justify-between gap-2 text-lg font-medium bg-white/5 rounded-md px-4 py-3 cursor-pointer hover:no-underline hover:bg-white/8 transition"> 129 + <AccordionItem value="item-1" className="border-none"> 130 + <AccordionTrigger className={ACCORDION_TRIGGER_CLASSES}> 102 131 <div className="flex items-center gap-4"> 103 132 <RefreshCcw size={20} /> 104 133 <span className="text-left">Unified backup format</span> 105 134 </div> 106 135 <span className="ml-auto" /> 107 136 </AccordionTrigger> 108 - <AccordionContent className="mt-2 text-gray-300 text-base rounded-md p-4"> 137 + <AccordionContent className={ACCORDION_CONTENT_CLASSES}> 109 138 Your data is saved as a CAR file, which Bluesky uses, and blobs 110 - are stored as their original files. This ensures you can restore 111 - your data in the future by yourself. 139 + are stored as their original format (in blob files). This ensures 140 + you can restore your data in the future by yourself. 112 141 </AccordionContent> 113 142 </AccordionItem> 114 - <AccordionItem value="item-2"> 115 - <AccordionTrigger className="flex items-center justify-between gap-2 text-lg font-medium bg-white/5 rounded-md px-4 py-3 cursor-pointer hover:no-underline hover:bg-white/8 transition"> 143 + <AccordionItem value="item-2" className="border-none"> 144 + <AccordionTrigger className={ACCORDION_TRIGGER_CLASSES}> 116 145 <div className="flex items-center gap-4"> 117 - <RefreshCcw size={20} /> 118 - <span className="text-left">Unified backup format</span> 146 + <CloudOff size={20} /> 147 + <span className="text-left">Local only</span> 119 148 </div> 120 149 <span className="ml-auto" /> 121 150 </AccordionTrigger> 122 - <AccordionContent className="mt-2 text-gray-300 text-base rounded-md p-4"> 123 - Your data is saved as a CAR file, which Bluesky uses, and blobs 124 - are stored as their original files. This ensures you can restore 125 - your data in the future by yourself. 151 + <AccordionContent className={ACCORDION_CONTENT_CLASSES}> 152 + Your backups are saved directly to your computer's file system, in 153 + documents, ensuring you always have access. If you prefer cloud 154 + storage, you can tools like{" "} 155 + <a 156 + href="https://bsky.storage" 157 + className="text-blue-500 underline" 158 + > 159 + Storacha 160 + </a>. 161 + </AccordionContent> 162 + </AccordionItem> 163 + <AccordionItem value="item-3"> 164 + <AccordionTrigger className={ACCORDION_TRIGGER_CLASSES}> 165 + <div className="flex items-center gap-4"> 166 + <FolderGit2 size={20} /> 167 + <span className="text-left">Open-source</span> 168 + </div> 169 + <span className="ml-auto" /> 170 + </AccordionTrigger> 171 + <AccordionContent className={ACCORDION_CONTENT_CLASSES}> 172 + We're completly open-source, star us on{" "} 173 + <a 174 + href="https://github.com/Turtlepaw/atproto-backup" 175 + className="text-blue-500 underline" 176 + > 177 + GitHub 178 + </a>{" "} 179 + or{" "} 180 + <a 181 + href="https://tangled.org/did:plc:5fzwpxt3rctfetyqpbigvgic/atbackup" 182 + className="text-blue-500 underline" 183 + > 184 + Tangled 185 + </a>. We're also happy to merge your pull request! (mention us on 186 + Bluesky if we're a little slow) 126 187 </AccordionContent> 127 188 </AccordionItem> 128 189 </Accordion> 129 - </div> 130 - <div className="flex flex-col items-center w-full"> 131 - <div className="flex flex-col md:flex-row items-center justify-center gap-8 min-h-[60vh] p-8"> 132 - <div> 133 - <VideoPlayer className="w-lg" /> 134 - </div> 135 - <div className="relative mt-8 md:mt-0"> 136 - <h1 className="text-[2.5rem] font-bold text-white m-0 max-w-[350px] leading-tight"> 137 - Intuitive and cozy 138 - </h1> 139 - <p className="text-lg text-white/80 mt-4 max-w-[350px]"> 140 - See how easy it is to save your Bluesky data to your computer. 141 - </p> 142 - </div> 143 - </div> 144 190 </div> 145 191 </div> 146 192 );
+42
docs/components/icons.tsx
··· 1 + export function Tangled(props: React.SVGProps<SVGSVGElement>) { 2 + return ( 3 + <svg 4 + version="1.1" 5 + id="svg1" 6 + width="25" 7 + height="25" 8 + viewBox="0 0 25 25" 9 + xmlns="http://www.w3.org/2000/svg" 10 + {...props} 11 + > 12 + <title>Dolly</title> 13 + <defs id="defs1"></defs> 14 + 15 + <g id="g1"> 16 + <path 17 + fill="currentColor" 18 + style={{ strokeWidth: 0.111183 }} 19 + d="m 16.348974,24.09935 -0.06485,-0.03766 -0.202005,-0.0106 -0.202008,-0.01048 -0.275736,-0.02601 -0.275734,-0.02602 v -0.02649 -0.02648 l -0.204577,-0.04019 -0.204578,-0.04019 -0.167616,-0.08035 -0.167617,-0.08035 -0.0014,-0.04137 -0.0014,-0.04137 -0.266473,-0.143735 -0.266475,-0.143735 -0.276098,-0.20335 -0.2761,-0.203347 -0.262064,-0.251949 -0.262064,-0.25195 -0.22095,-0.284628 -0.220948,-0.284629 -0.170253,-0.284631 -0.170252,-0.284628 -0.01341,-0.0144 -0.0134,-0.0144 -0.141982,0.161297 -0.14198,0.1613 -0.22313,0.21426 -0.223132,0.214264 -0.186025,0.146053 -0.186023,0.14605 -0.252501,0.163342 -0.252502,0.163342 -0.249014,0.115348 -0.249013,0.115336 0.0053,0.03241 0.0053,0.03241 -0.1716725,0.04599 -0.171669,0.046 -0.3379966,0.101058 -0.3379972,0.101058 -0.1778925,0.04506 -0.1778935,0.04508 -0.3913655,0.02601 -0.3913643,0.02603 -0.3557868,-0.03514 -0.3557863,-0.03514 -0.037426,-0.03029 -0.037427,-0.03029 -0.076924,0.02011 -0.076924,0.02011 -0.050508,-0.05051 -0.050405,-0.05056 L 6.6604532,23.110188 6.451745,23.063961 6.1546135,22.960559 5.8574835,22.857156 5.5319879,22.694039 5.2064938,22.530922 4.8793922,22.302961 4.5522905,22.075005 4.247598,21.786585 3.9429055,21.49817 3.7185335,21.208777 3.4941628,20.919385 3.3669822,20.705914 3.239803,20.492443 3.1335213,20.278969 3.0272397,20.065499 2.9015252,19.7275 2.7758105,19.389504 2.6925225,18.998139 2.6092345,18.606774 2.6096814,17.91299 2.6101284,17.219208 2.6744634,16.90029 2.7387984,16.581374 2.8474286,16.242088 2.9560588,15.9028 3.1137374,15.583492 3.2714148,15.264182 3.3415068,15.150766 3.4115988,15.03735 3.3127798,14.96945 3.2139618,14.90157 3.0360685,14.800239 2.8581753,14.698908 2.5913347,14.503228 2.3244955,14.307547 2.0621238,14.055599 1.7997507,13.803651 1.6111953,13.56878 1.4226411,13.333906 1.2632237,13.087474 1.1038089,12.841042 0.97442,12.575195 0.8450307,12.30935 0.724603,11.971351 0.6041766,11.633356 0.52150365,11.241991 0.4388285,10.850626 0.44091592,10.156842 0.44300333,9.4630594 0.54235911,9.0369608 0.6417149,8.6108622 0.7741173,8.2694368 0.9065196,7.9280115 1.0736303,7.6214262 1.2407515,7.3148397 1.45931,7.0191718 1.6778685,6.7235039 1.9300326,6.4611321 2.1821966,6.1987592 2.4134579,6.0137228 2.6447193,5.8286865 2.8759792,5.6776409 3.1072406,5.526594 3.4282004,5.3713977 3.7491603,5.2162016 3.9263009,5.1508695 4.1034416,5.0855373 4.2813348,4.7481598 4.4592292,4.4107823 4.6718,4.108422 4.8843733,3.8060618 5.198353,3.4805372 5.5123313,3.155014 5.7685095,2.9596425 6.0246877,2.7642722 6.329187,2.5851365 6.6336863,2.406002 6.9497657,2.2751596 7.2658453,2.1443184 7.4756394,2.0772947 7.6854348,2.01027 8.0825241,1.931086 8.4796139,1.851902 l 0.5870477,0.00291 0.5870469,0.00291 0.4447315,0.092455 0.444734,0.092455 0.302419,0.1105495 0.302417,0.1105495 0.329929,0.1646046 0.32993,0.1646033 0.239329,-0.2316919 0.239329,-0.2316919 0.160103,-0.1256767 0.160105,-0.1256767 0.160102,-0.1021909 0.160105,-0.1021899 0.142315,-0.082328 0.142314,-0.082328 0.231262,-0.1090091 0.231259,-0.1090091 0.26684,-0.098743 0.266839,-0.098743 0.320208,-0.073514 0.320209,-0.073527 0.355787,-0.041833 0.355785,-0.041834 0.426942,0.023827 0.426945,0.023828 0.355785,0.071179 0.355788,0.0711791 0.284627,0.09267 0.284629,0.09267 0.28514,0.1310267 0.28514,0.1310255 0.238179,0.1446969 0.238174,0.1446979 0.259413,0.1955332 0.259413,0.1955319 0.290757,0.296774 0.290758,0.2967753 0.151736,0.1941581 0.151734,0.1941594 0.135326,0.2149951 0.135327,0.2149952 0.154755,0.3202073 0.154758,0.3202085 0.09409,0.2677358 0.09409,0.267737 0.06948,0.3319087 0.06948,0.3319099 0.01111,0.00808 0.01111,0.00808 0.444734,0.2173653 0.444734,0.2173665 0.309499,0.2161102 0.309497,0.2161101 0.309694,0.2930023 0.309694,0.2930037 0.18752,0.2348726 0.187524,0.2348727 0.166516,0.2574092 0.166519,0.2574108 0.15273,0.3260252 0.152734,0.3260262 0.08972,0.2668403 0.08971,0.2668391 0.08295,0.3913655 0.08295,0.3913652 -6.21e-4,0.6582049 -6.21e-4,0.658204 -0.06362,0.315725 -0.06362,0.315725 -0.09046,0.289112 -0.09046,0.289112 -0.122759,0.281358 -0.12276,0.281356 -0.146626,0.252323 -0.146629,0.252322 -0.190443,0.258668 -0.190448,0.258671 -0.254911,0.268356 -0.254911,0.268355 -0.286872,0.223127 -0.286874,0.223127 -0.320203,0.187693 -0.320209,0.187693 -0.04347,0.03519 -0.04347,0.03521 0.0564,0.12989 0.0564,0.129892 0.08728,0.213472 0.08728,0.213471 0.189755,0.729363 0.189753,0.729362 0.0652,0.302417 0.0652,0.302419 -0.0018,0.675994 -0.0018,0.675995 -0.0801,0.373573 -0.08009,0.373577 -0.09,0.266839 -0.09,0.26684 -0.190389,0.391364 -0.19039,0.391366 -0.223169,0.320207 -0.223167,0.320209 -0.303585,0.315294 -0.303584,0.315291 -0.284631,0.220665 -0.284629,0.220663 -0.220128,0.132359 -0.220127,0.132358 -0.242395,0.106698 -0.242394,0.106699 -0.08895,0.04734 -0.08895,0.04733 -0.249052,0.07247 -0.24905,0.07247 -0.322042,0.0574 -0.322044,0.0574 -0.282794,-0.003 -0.282795,-0.003 -0.07115,-0.0031 -0.07115,-0.0031 -0.177894,-0.0033 -0.177893,-0.0033 -0.124528,0.02555 -0.124528,0.02555 z m -4.470079,-5.349839 0.214838,-0.01739 0.206601,-0.06782 0.206602,-0.06782 0.244389,-0.117874 0.244393,-0.11786 0.274473,-0.206822 0.27447,-0.20682 0.229308,-0.257201 0.229306,-0.2572 0.219161,-0.28463 0.219159,-0.284629 0.188541,-0.284628 0.188543,-0.28463 0.214594,-0.373574 0.214593,-0.373577 0.133861,-0.312006 0.133865,-0.312007 0.02861,-0.01769 0.02861,-0.01769 0.197275,0.26212 0.197278,0.262119 0.163613,0.150814 0.163614,0.150814 0.201914,0.09276 0.201914,0.09276 0.302417,0.01421 0.302418,0.01421 0.213472,-0.08025 0.213471,-0.08025 0.200606,-0.204641 0.200606,-0.204642 0.09242,-0.278887 0.09241,-0.278888 0.05765,-0.302418 0.05764,-0.302416 L 18.41327,13.768114 18.39502,13.34117 18.31849,12.915185 18.24196,12.4892 18.15595,12.168033 18.06994,11.846867 17.928869,11.444534 17.787801,11.042201 17.621278,10.73296 17.454757,10.423723 17.337388,10.263619 17.220021,10.103516 17.095645,9.9837986 16.971268,9.8640816 16.990048,9.6813736 17.008828,9.4986654 16.947568,9.249616 16.886308,9.0005655 16.752419,8.7159355 16.618521,8.4313217 16.435707,8.2294676 16.252892,8.0276114 16.079629,7.9004245 15.906366,7.773238 l -0.20429,0.1230127 -0.204289,0.1230121 -0.26702,0.059413 -0.267022,0.059413 -0.205761,-0.021508 -0.205766,-0.021508 -0.23495,-0.08844 -0.234953,-0.08844 -0.118429,-0.090334 -0.118428,-0.090333 h -0.03944 -0.03944 L 13.711268,7.8540732 13.655958,7.9706205 13.497227,8.1520709 13.338499,8.3335203 13.168394,8.4419112 12.998289,8.550301 12.777045,8.624223 12.5558,8.698155 H 12.275611 11.995429 L 11.799973,8.6309015 11.604513,8.5636472 11.491311,8.5051061 11.37811,8.446565 11.138172,8.2254579 10.898231,8.0043497 l -0.09565,-0.084618 -0.09565,-0.084613 -0.218822,0.198024 -0.218822,0.1980231 -0.165392,0.078387 -0.1653925,0.078387 -0.177894,0.047948 -0.177892,0.047948 L 9.3635263,8.4842631 9.144328,8.4846889 8.9195029,8.4147138 8.6946778,8.3447386 8.5931214,8.4414036 8.491565,8.5380686 8.3707618,8.7019598 8.2499597,8.8658478 8.0802403,8.9290726 7.9105231,8.9922974 7.7952769,9.0780061 7.6800299,9.1637148 7.5706169,9.2778257 7.4612038,9.3919481 7.1059768,9.9205267 6.7507497,10.449105 l -0.2159851,0.449834 -0.2159839,0.449834 -0.2216572,0.462522 -0.2216559,0.462523 -0.1459343,0.337996 -0.1459342,0.337998 -0.055483,0.220042 -0.055483,0.220041 -0.015885,0.206903 -0.015872,0.206901 0.034307,0.242939 0.034307,0.24294 0.096281,0.196632 0.096281,0.196634 0.143607,0.125222 0.1436071,0.125222 0.1873143,0.08737 0.1873141,0.08737 0.2752084,0.002 0.2752084,0.002 0.2312297,-0.09773 0.231231,-0.09772 0.1067615,-0.07603 0.1067614,-0.07603 0.3679062,-0.29377 0.3679065,-0.293771 0.026804,0.01656 0.026804,0.01656 0.023626,0.466819 0.023626,0.466815 0.088326,0.513195 0.088326,0.513193 0.08897,0.364413 0.08897,0.364411 0.1315362,0.302418 0.1315352,0.302418 0.1051964,0.160105 0.1051954,0.160103 0.1104741,0.11877 0.1104731,0.118769 0.2846284,0.205644 0.2846305,0.205642 0.144448,0.07312 0.144448,0.07312 0.214787,0.05566 0.214787,0.05566 0.245601,0.03075 0.245602,0.03075 0.204577,-0.0125 0.204578,-0.0125 z m 0.686342,-3.497495 -0.11281,-0.06077 -0.106155,-0.134033 -0.106155,-0.134031 -0.04406,-0.18371 -0.04406,-0.183707 0.02417,-0.553937 0.02417,-0.553936 0.03513,-0.426945 0.03513,-0.426942 0.07225,-0.373576 0.07225,-0.373575 0.05417,-0.211338 0.05417,-0.211339 0.0674,-0.132112 0.0674,-0.132112 0.132437,-0.10916 0.132437,-0.109161 0.187436,-0.04195 0.187438,-0.04195 0.170366,0.06469 0.170364,0.06469 0.114312,0.124073 0.114313,0.124086 0.04139,0.18495 0.04139,0.184951 -0.111218,0.459845 -0.111219,0.459844 -0.03383,0.26584 -0.03382,0.265841 -0.03986,0.818307 -0.03986,0.818309 -0.0378,0.15162 -0.03779,0.151621 -0.11089,0.110562 -0.110891,0.110561 -0.114489,0.04913 -0.114489,0.04913 -0.187932,-0.0016 -0.187929,-0.0016 z m -2.8087655,-0.358124 -0.146445,-0.06848 -0.088025,-0.119502 -0.088024,-0.119502 -0.038581,-0.106736 -0.038581,-0.106736 -0.02237,-0.134956 -0.02239,-0.134957 -0.031955,-0.46988 -0.031955,-0.469881 0.036203,-0.444733 0.036203,-0.444731 0.048862,-0.215257 0.048862,-0.215255 0.076082,-0.203349 0.076081,-0.203348 0.0936,-0.111244 0.0936,-0.111245 0.143787,-0.06531 0.1437865,-0.06532 h 0.142315 0.142314 l 0.142314,0.06588 0.142316,0.06588 0.093,0.102325 0.093,0.102325 0.04042,0.120942 0.04042,0.120942 v 0.152479 0.152477 l -0.03347,0.08804 -0.03347,0.08805 -0.05693,0.275653 -0.05693,0.275651 2.11e-4,0.430246 2.12e-4,0.430243 0.04294,0.392646 0.04295,0.392647 -0.09189,0.200702 -0.09189,0.200702 -0.148688,0.0984 -0.148687,0.0984 -0.20136,0.01212 -0.2013595,0.01212 z" 20 + id="path4" 21 + > 22 + </path> 23 + </g> 24 + </svg> 25 + ); 26 + } 27 + export function Bluesky(props: React.SVGProps<SVGSVGElement>) { 28 + return ( 29 + <svg 30 + role="img" 31 + viewBox="0 0 24 24" 32 + xmlns="http://www.w3.org/2000/svg" 33 + {...props} 34 + > 35 + <title>Bluesky</title> 36 + <path 37 + d="M12 10.8c-1.087-2.114-4.046-6.053-6.798-7.995C2.566.944 1.561 1.266.902 1.565.139 1.908 0 3.08 0 3.768c0 .69.378 5.65.624 6.479.815 2.736 3.713 3.66 6.383 3.364.136-.02.275-.039.415-.056-.138.022-.276.04-.415.056-3.912.58-7.387 2.005-2.83 7.078 5.013 5.19 6.87-1.113 7.823-4.308.953 3.195 2.05 9.271 7.733 4.308 4.267-4.308 1.172-6.498-2.74-7.078a8.741 8.741 0 0 1-.415-.056c.14.017.279.036.415.056 2.67.297 5.568-.628 6.383-3.364.246-.828.624-5.79.624-6.478 0-.69-.139-1.861-.902-2.206-.659-.298-1.664-.62-4.3 1.24C16.046 4.748 13.087 8.687 12 10.8Z" 38 + fill="currentColor" 39 + /> 40 + </svg> 41 + ); 42 + }
+2 -1
docs/package.json
··· 28 28 "@types/node": "^24.0.10", 29 29 "@types/react": "^19.1.8", 30 30 "pagefind": "^1.3.0", 31 - "tw-animate-css": "^1.3.8" 31 + "tw-animate-css": "^1.3.8", 32 + "typescript": "^5.9.2" 32 33 }, 33 34 "packageManager": "yarn@4.9.4" 34 35 }
+21
docs/yarn.lock
··· 7139 7139 tailwind-merge: "npm:^3.3.1" 7140 7140 tailwindcss: "npm:^4.1.11" 7141 7141 tw-animate-css: "npm:^1.3.8" 7142 + typescript: "npm:^5.9.2" 7142 7143 languageName: unknown 7143 7144 linkType: soft 7144 7145 ··· 7924 7925 media-typer: "npm:^1.1.0" 7925 7926 mime-types: "npm:^3.0.0" 7926 7927 checksum: 10c0/7f7ec0a060b16880bdad36824ab37c26019454b67d73e8a465ed5a3587440fbe158bc765f0da68344498235c877e7dbbb1600beccc94628ed05599d667951b99 7928 + languageName: node 7929 + linkType: hard 7930 + 7931 + "typescript@npm:^5.9.2": 7932 + version: 5.9.2 7933 + resolution: "typescript@npm:5.9.2" 7934 + bin: 7935 + tsc: bin/tsc 7936 + tsserver: bin/tsserver 7937 + checksum: 10c0/cd635d50f02d6cf98ed42de2f76289701c1ec587a363369255f01ed15aaf22be0813226bff3c53e99d971f9b540e0b3cc7583dbe05faded49b1b0bed2f638a18 7938 + languageName: node 7939 + linkType: hard 7940 + 7941 + "typescript@patch:typescript@npm%3A^5.9.2#optional!builtin<compat/typescript>": 7942 + version: 5.9.2 7943 + resolution: "typescript@patch:typescript@npm%3A5.9.2#optional!builtin<compat/typescript>::version=5.9.2&hash=5786d5" 7944 + bin: 7945 + tsc: bin/tsc 7946 + tsserver: bin/tsserver 7947 + checksum: 10c0/34d2a8e23eb8e0d1875072064d5e1d9c102e0bdce56a10a25c0b917b8aa9001a9cf5c225df12497e99da107dc379360bc138163c66b55b95f5b105b50578067e 7927 7948 languageName: node 7928 7949 linkType: hard 7929 7950