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.

chore: remove unused lib helper and static assets

-119
-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>