mysticals 0.8.1 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/cli.js +44 -3
  2. package/package.json +2 -2
package/dist/cli.js CHANGED
@@ -5,7 +5,7 @@ import { createElement } from "react";
5
5
  import { render } from "ink";
6
6
 
7
7
  // package.json
8
- var version = "0.8.1";
8
+ var version = "0.9.0";
9
9
 
10
10
  // src/client.ts
11
11
  import { spawn } from "child_process";
@@ -277,6 +277,8 @@ var en = {
277
277
  "notify.changed": "Event changed",
278
278
  "notify.cancelled": "Event cancelled",
279
279
  "notify.many": { one: "{n} calendar update", other: "{n} calendar updates" },
280
+ "reminder.in": "in {n} min",
281
+ "reminder.now": "starting now",
280
282
  // ---- desktop: menus, dialogs, update ----
281
283
  "menu.file": "File",
282
284
  "menu.newEvent": "New Event",
@@ -345,12 +347,19 @@ var en = {
345
347
  "settings.tab.language": "Language",
346
348
  "settings.tab.sync": "Sync",
347
349
  "settings.tab.privacy": "Privacy",
350
+ "settings.tab.notifications": "Notifications",
351
+ "settings.reminders.label": "Remind me before events",
352
+ "settings.reminders.off": "Off",
353
+ "settings.reminders.min": "{n} min before",
354
+ "settings.reminders.note": "A notification pops up before each event while Mysticals is open, with a button to join the call when the event has a link. Declined, all-day and hidden-calendar events stay silent.",
348
355
  "settings.noAccounts": "No accounts yet.",
349
356
  "settings.addAccount": "Add account\u2026",
350
357
  "settings.theme": "Theme",
351
358
  "theme.amber": "Phosphor amber",
352
359
  "theme.mono": "Black & White",
353
360
  "theme.toon": "Cartoon",
361
+ "theme.cloud": "Cloud",
362
+ "theme.light": "Light",
354
363
  "settings.language.auto": "Automatic",
355
364
  "settings.language.system": "system: {name}",
356
365
  "settings.sync.note": "Accounts sync automatically every 2 minutes and when the app regains focus.",
@@ -365,6 +374,7 @@ var en = {
365
374
  "settings.privacy.note": "Mysticals sends two anonymous events: when the app is first installed and when an account is added (provider only). Never emails, server addresses, calendars or events.",
366
375
  "settings.privacy.policy": "Privacy policy",
367
376
  "settings.privacy.share": "Share anonymous usage stats",
377
+ "settings.donate": "Support on Ko-fi",
368
378
  "settings.account.labelFor": "Label for {email}",
369
379
  "settings.account.colourFor": "Colour for {email}",
370
380
  "settings.account.remove": "Remove",
@@ -610,6 +620,8 @@ var uk = {
610
620
  "notify.changed": "\u041F\u043E\u0434\u0456\u044E \u0437\u043C\u0456\u043D\u0435\u043D\u043E",
611
621
  "notify.cancelled": "\u041F\u043E\u0434\u0456\u044E \u0441\u043A\u0430\u0441\u043E\u0432\u0430\u043D\u043E",
612
622
  "notify.many": { one: "{n} \u0437\u043C\u0456\u043D\u0430 \u0432 \u043A\u0430\u043B\u0435\u043D\u0434\u0430\u0440\u0456", few: "{n} \u0437\u043C\u0456\u043D\u0438 \u0432 \u043A\u0430\u043B\u0435\u043D\u0434\u0430\u0440\u0456", many: "{n} \u0437\u043C\u0456\u043D \u0443 \u043A\u0430\u043B\u0435\u043D\u0434\u0430\u0440\u0456", other: "{n} \u0437\u043C\u0456\u043D\u0438 \u0432 \u043A\u0430\u043B\u0435\u043D\u0434\u0430\u0440\u0456" },
623
+ "reminder.in": "\u0447\u0435\u0440\u0435\u0437 {n} \u0445\u0432",
624
+ "reminder.now": "\u043F\u043E\u0447\u0438\u043D\u0430\u0454\u0442\u044C\u0441\u044F \u0437\u0430\u0440\u0430\u0437",
613
625
  // ---- desktop: menus, dialogs, update ----
614
626
  "menu.file": "\u0424\u0430\u0439\u043B",
615
627
  "menu.newEvent": "\u041D\u043E\u0432\u0430 \u043F\u043E\u0434\u0456\u044F",
@@ -678,12 +690,19 @@ var uk = {
678
690
  "settings.tab.language": "\u041C\u043E\u0432\u0430",
679
691
  "settings.tab.sync": "\u0421\u0438\u043D\u0445\u0440\u043E\u043D\u0456\u0437\u0430\u0446\u0456\u044F",
680
692
  "settings.tab.privacy": "\u041A\u043E\u043D\u0444\u0456\u0434\u0435\u043D\u0446\u0456\u0439\u043D\u0456\u0441\u0442\u044C",
693
+ "settings.tab.notifications": "\u0421\u043F\u043E\u0432\u0456\u0449\u0435\u043D\u043D\u044F",
694
+ "settings.reminders.label": "\u041D\u0430\u0433\u0430\u0434\u0443\u0432\u0430\u0442\u0438 \u043F\u0435\u0440\u0435\u0434 \u043F\u043E\u0434\u0456\u044F\u043C\u0438",
695
+ "settings.reminders.off": "\u0412\u0438\u043C\u043A\u043D\u0435\u043D\u043E",
696
+ "settings.reminders.min": "\u0437\u0430 {n} \u0445\u0432",
697
+ "settings.reminders.note": "\u041F\u043E\u043A\u0438 Mysticals \u0432\u0456\u0434\u043A\u0440\u0438\u0442\u0438\u0439, \u043F\u0435\u0440\u0435\u0434 \u043A\u043E\u0436\u043D\u043E\u044E \u043F\u043E\u0434\u0456\u0454\u044E \u0437\u2019\u044F\u0432\u043B\u044F\u0454\u0442\u044C\u0441\u044F \u0441\u043F\u043E\u0432\u0456\u0449\u0435\u043D\u043D\u044F \u0437 \u043A\u043D\u043E\u043F\u043A\u043E\u044E, \u0449\u043E\u0431 \u043F\u0440\u0438\u0454\u0434\u043D\u0430\u0442\u0438\u0441\u044F \u0434\u043E \u0434\u0437\u0432\u0456\u043D\u043A\u0430, \u044F\u043A\u0449\u043E \u0432 \u043F\u043E\u0434\u0456\u0457 \u0454 \u043F\u043E\u0441\u0438\u043B\u0430\u043D\u043D\u044F. \u0412\u0456\u0434\u0445\u0438\u043B\u0435\u043D\u0456, \u0446\u0456\u043B\u043E\u0434\u0435\u043D\u043D\u0456 \u043F\u043E\u0434\u0456\u0457 \u0442\u0430 \u043F\u043E\u0434\u0456\u0457 \u0437 \u043F\u0440\u0438\u0445\u043E\u0432\u0430\u043D\u0438\u0445 \u043A\u0430\u043B\u0435\u043D\u0434\u0430\u0440\u0456\u0432 \u0431\u0435\u0437 \u0441\u043F\u043E\u0432\u0456\u0449\u0435\u043D\u044C.",
681
698
  "settings.noAccounts": "\u041E\u0431\u043B\u0456\u043A\u043E\u0432\u0438\u0445 \u0437\u0430\u043F\u0438\u0441\u0456\u0432 \u0449\u0435 \u043D\u0435\u043C\u0430\u0454.",
682
699
  "settings.addAccount": "\u0414\u043E\u0434\u0430\u0442\u0438 \u043E\u0431\u043B\u0456\u043A\u043E\u0432\u0438\u0439 \u0437\u0430\u043F\u0438\u0441\u2026",
683
700
  "settings.theme": "\u0422\u0435\u043C\u0430",
684
701
  "theme.amber": "\u0411\u0443\u0440\u0448\u0442\u0438\u043D\u043E\u0432\u0438\u0439 \u043B\u044E\u043C\u0456\u043D\u043E\u0444\u043E\u0440",
685
702
  "theme.mono": "\u0427\u043E\u0440\u043D\u043E-\u0431\u0456\u043B\u0430",
686
703
  "theme.toon": "\u041C\u0443\u043B\u044C\u0442\u044F\u0448\u043D\u0430",
704
+ "theme.cloud": "\u0425\u043C\u0430\u0440\u0438\u043D\u043A\u0430",
705
+ "theme.light": "\u0421\u0432\u0456\u0442\u043B\u0430",
687
706
  "settings.language.auto": "\u0410\u0432\u0442\u043E\u043C\u0430\u0442\u0438\u0447\u043D\u043E",
688
707
  "settings.language.system": "\u0441\u0438\u0441\u0442\u0435\u043C\u043D\u0430: {name}",
689
708
  "settings.sync.note": "\u041E\u0431\u043B\u0456\u043A\u043E\u0432\u0456 \u0437\u0430\u043F\u0438\u0441\u0438 \u0441\u0438\u043D\u0445\u0440\u043E\u043D\u0456\u0437\u0443\u044E\u0442\u044C\u0441\u044F \u0430\u0432\u0442\u043E\u043C\u0430\u0442\u0438\u0447\u043D\u043E \u043A\u043E\u0436\u043D\u0456 2 \u0445\u0432\u0438\u043B\u0438\u043D\u0438 \u0442\u0430 \u043A\u043E\u043B\u0438 \u0437\u0430\u0441\u0442\u043E\u0441\u0443\u043D\u043E\u043A \u0437\u043D\u043E\u0432\u0443 \u0441\u0442\u0430\u0454 \u0430\u043A\u0442\u0438\u0432\u043D\u0438\u043C.",
@@ -698,6 +717,7 @@ var uk = {
698
717
  "settings.privacy.note": "Mysticals \u043D\u0430\u0434\u0441\u0438\u043B\u0430\u0454 \u0434\u0432\u0456 \u0430\u043D\u043E\u043D\u0456\u043C\u043D\u0456 \u043F\u043E\u0434\u0456\u0457: \u043A\u043E\u043B\u0438 \u0437\u0430\u0441\u0442\u043E\u0441\u0443\u043D\u043E\u043A \u0443\u0441\u0442\u0430\u043D\u043E\u0432\u043B\u0435\u043D\u043E \u0432\u043F\u0435\u0440\u0448\u0435 \u0456 \u043A\u043E\u043B\u0438 \u0434\u043E\u0434\u0430\u043D\u043E \u043E\u0431\u043B\u0456\u043A\u043E\u0432\u0438\u0439 \u0437\u0430\u043F\u0438\u0441 (\u043B\u0438\u0448\u0435 \u0442\u0438\u043F \u0441\u0435\u0440\u0432\u0456\u0441\u0443). \u041D\u0456\u043A\u043E\u043B\u0438 \u043D\u0435 \u043D\u0430\u0434\u0441\u0438\u043B\u0430\u0454 \u0430\u0434\u0440\u0435\u0441\u0438 \u043F\u043E\u0448\u0442\u0438 \u0447\u0438 \u0441\u0435\u0440\u0432\u0435\u0440\u0456\u0432, \u043A\u0430\u043B\u0435\u043D\u0434\u0430\u0440\u0456 \u0430\u0431\u043E \u043F\u043E\u0434\u0456\u0457.",
699
718
  "settings.privacy.policy": "\u041F\u043E\u043B\u0456\u0442\u0438\u043A\u0430 \u043A\u043E\u043D\u0444\u0456\u0434\u0435\u043D\u0446\u0456\u0439\u043D\u043E\u0441\u0442\u0456",
700
719
  "settings.privacy.share": "\u041D\u0430\u0434\u0441\u0438\u043B\u0430\u0442\u0438 \u0430\u043D\u043E\u043D\u0456\u043C\u043D\u0443 \u0441\u0442\u0430\u0442\u0438\u0441\u0442\u0438\u043A\u0443 \u0432\u0438\u043A\u043E\u0440\u0438\u0441\u0442\u0430\u043D\u043D\u044F",
720
+ "settings.donate": "\u041F\u0456\u0434\u0442\u0440\u0438\u043C\u0430\u0442\u0438 \u043D\u0430 Ko-fi",
701
721
  "settings.account.labelFor": "\u041D\u0430\u0437\u0432\u0430 \u0434\u043B\u044F {email}",
702
722
  "settings.account.colourFor": "\u041A\u043E\u043B\u0456\u0440 \u0434\u043B\u044F {email}",
703
723
  "settings.account.remove": "\u0412\u0438\u0434\u0430\u043B\u0438\u0442\u0438",
@@ -2489,6 +2509,10 @@ function mapPeople(vevent, email) {
2489
2509
  });
2490
2510
  return { organizer, attendees, myStatus: attendees.find((a) => a.self)?.status };
2491
2511
  }
2512
+ function conferenceOf(vevent) {
2513
+ const urls = [...vevent.getAllProperties("conference"), ...vevent.getAllProperties("x-google-conference")].map((p) => String(p.getFirstValue() ?? "").trim());
2514
+ return urls.find((u) => /^https?:\/\//i.test(u));
2515
+ }
2492
2516
  function parseEvents(ics, href, etag, ctx, range) {
2493
2517
  const root = parse(ics);
2494
2518
  const vevents = root.getAllSubcomponents("vevent");
@@ -2502,6 +2526,7 @@ function parseEvents(ics, href, etag, ctx, range) {
2502
2526
  const build = (item, start, end, recurrenceId) => {
2503
2527
  const rid = recurrenceId?.toString();
2504
2528
  const raw = { href, ics, ...rid ? { recurrenceId: rid } : {} };
2529
+ const conference = conferenceOf(item.component);
2505
2530
  return {
2506
2531
  id: rid ? `${href}#${rid}` : href,
2507
2532
  accountId: ctx.accountId,
@@ -2512,6 +2537,7 @@ function parseEvents(ics, href, etag, ctx, range) {
2512
2537
  allDay: start.isDate,
2513
2538
  location: item.location || void 0,
2514
2539
  description: item.description || void 0,
2540
+ ...conference ? { conferenceUrl: conference } : {},
2515
2541
  ...mapPeople(item.component, ctx.email),
2516
2542
  etag,
2517
2543
  raw,
@@ -3847,8 +3873,15 @@ function htmlToText(html) {
3847
3873
  function meetingUrl(location) {
3848
3874
  return location?.match(/https?:\/\/[^\s<>"]+/i)?.[0].replace(/[.,;:!?)\]}'>]+$/, "");
3849
3875
  }
3876
+ var CALL_KINDS = ["meet", "zoom", "teams", "video"];
3877
+ function descriptionCallUrl(description) {
3878
+ if (!description) return void 0;
3879
+ const hrefs = [...description.matchAll(/href\s*=\s*["']([^"']+)["']/gi)].map((m) => m[1].replace(/&amp;/g, "&"));
3880
+ const urls = [...hrefs, ...linkify(description.replace(/<[^>]*>/g, " ")).flatMap((p) => p.href ? [p.href] : [])];
3881
+ return urls.find((u) => /^https?:\/\//i.test(u) && CALL_KINDS.includes(linkKind(u)));
3882
+ }
3850
3883
  function eventMeetingUrl(e) {
3851
- return e.conferenceUrl ?? meetingUrl(e.location);
3884
+ return e.conferenceUrl ?? meetingUrl(e.location) ?? descriptionCallUrl(e.description);
3852
3885
  }
3853
3886
  function locationText(location = "") {
3854
3887
  return location.replace(/https?:\/\/[^\s<>"]+/gi, "").replace(/^[\s/|,·-]+|[\s/|,·-]+$/g, "");
@@ -5163,6 +5196,7 @@ function AddCaldav({ onBack, onDone }) {
5163
5196
 
5164
5197
  // src/ui/screens/Accounts.tsx
5165
5198
  import { Fragment as Fragment3, jsx as jsx12, jsxs as jsxs10 } from "react/jsx-runtime";
5199
+ var DONATE_URL = "https://ko-fi.com/a1exalexander";
5166
5200
  function Accounts({ onClose }) {
5167
5201
  const api = useApi();
5168
5202
  const { accounts, calendars, loaded, error: loadError } = useDirectory();
@@ -5406,7 +5440,14 @@ function Accounts({ onClose }) {
5406
5440
  button("a", "add CalDAV"),
5407
5441
  /* @__PURE__ */ jsx12(Button, { k: "esc", label: "close", onPress: onClose })
5408
5442
  ] }),
5409
- mode.kind === "list" && /* @__PURE__ */ jsx12(Box10, { marginTop: 1, children: /* @__PURE__ */ jsx12(Text10, { color: C.muted, children: "Made in Ukraine" }) })
5443
+ mode.kind === "list" && /* @__PURE__ */ jsxs10(Box10, { marginTop: 1, children: [
5444
+ /* @__PURE__ */ jsx12(Text10, { color: C.muted, children: "Made in Ukraine \xB7 " }),
5445
+ /* @__PURE__ */ jsxs10(Clickable, { onClick: () => void openUrl(DONATE_URL).catch(() => {
5446
+ }), children: [
5447
+ /* @__PURE__ */ jsx12(Text10, { color: C.muted, children: "Support on Ko-fi: " }),
5448
+ /* @__PURE__ */ jsx12(Text10, { color: C.cyan, underline: true, children: DONATE_URL })
5449
+ ] })
5450
+ ] })
5410
5451
  ] });
5411
5452
  }
5412
5453
  var loopbackPort = (authUrl) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mysticals",
3
- "version": "0.8.1",
3
+ "version": "0.9.0",
4
4
  "description": "Isolated multi-account calendar for the terminal on macOS, Linux and Windows",
5
5
  "keywords": [
6
6
  "calendar",
@@ -47,7 +47,7 @@
47
47
  "tsup": "^8.5.1",
48
48
  "typescript": "^5.9.3",
49
49
  "vitest": "^3.2.7",
50
- "@mysticals/core": "0.8.1"
50
+ "@mysticals/core": "0.9.0"
51
51
  },
52
52
  "scripts": {
53
53
  "dev": "tsup --watch",