timezone-overlap-map 0.1.1 → 0.2.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.
- package/README.md +3 -3
- package/dist/WorldMap.d.ts +11 -2
- package/dist/messages.d.ts +2 -0
- package/dist/timezone-overlap-map.js +107 -112
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
A web component that shows your timezone next to your visitor's on a world map, and how your working hours overlap. Built with React and TypeScript, shipped as a standard custom element, so it works in any framework or in plain HTML.
|
|
4
4
|
|
|
5
|
-
- A world map
|
|
6
|
-
-
|
|
7
|
-
-
|
|
5
|
+
- A world map read as your day, 00 to 24: your working hours stay put, the visitor's slide with their zone, and the overlap is labeled with its length ("5 h").
|
|
6
|
+
- A dot per city and the live day/night line with the sun's position.
|
|
7
|
+
- Both clocks, a zone picker that starts at the visitor's zone, and the overlap in the visitor's own time as text (also for screen readers).
|
|
8
8
|
|
|
9
9
|
About 15 KB gzipped, map included, plus React.
|
|
10
10
|
|
package/dist/WorldMap.d.ts
CHANGED
|
@@ -1,5 +1,14 @@
|
|
|
1
|
-
|
|
1
|
+
import { type Segment } from './overlap';
|
|
2
|
+
export type WorldMapProps = {
|
|
2
3
|
homeZone: string;
|
|
3
4
|
visitorZone: string;
|
|
4
5
|
now: Date;
|
|
5
|
-
|
|
6
|
+
/** Working hours in the home zone's day (minutes), already split at midnight. */
|
|
7
|
+
home: Segment[];
|
|
8
|
+
visitor: Segment[];
|
|
9
|
+
both: Segment[];
|
|
10
|
+
nowMinute: number;
|
|
11
|
+
/** Written on the overlap, e.g. "4 h". */
|
|
12
|
+
label: string;
|
|
13
|
+
};
|
|
14
|
+
export declare function WorldMap({ homeZone, visitorZone, now, home, visitor, both, nowMinute, label }: WorldMapProps): import("react").JSX.Element;
|
package/dist/messages.d.ts
CHANGED
|
@@ -4,6 +4,8 @@ export type Messages = {
|
|
|
4
4
|
/** `duration` is already formatted ("2 h 30 min"), `ranges` is in the visitor's local time. */
|
|
5
5
|
overlap: (duration: string, home: string, ranges: string) => string;
|
|
6
6
|
none: (home: string) => string;
|
|
7
|
+
/** Under the map, whose clock its hours follow. */
|
|
8
|
+
axis: (home: string) => string;
|
|
7
9
|
};
|
|
8
10
|
export declare const MESSAGES: {
|
|
9
11
|
en: Messages;
|
|
@@ -90,12 +90,14 @@ var b = {
|
|
|
90
90
|
en: {
|
|
91
91
|
zoneLabel: "Your time zone",
|
|
92
92
|
overlap: (e, t, n) => `${e} of overlap with ${t}: ${n} your time.`,
|
|
93
|
-
none: (e) => `No working-hours overlap with ${e}
|
|
93
|
+
none: (e) => `No working-hours overlap with ${e}.`,
|
|
94
|
+
axis: (e) => `${e}’s time`
|
|
94
95
|
},
|
|
95
96
|
es: {
|
|
96
97
|
zoneLabel: "Tu zona horaria",
|
|
97
98
|
overlap: (e, t, n) => `${e} en común con ${t}: ${n} en tu horario.`,
|
|
98
|
-
none: (e) => `No hay horario laboral en común con ${e}
|
|
99
|
+
none: (e) => `No hay horario laboral en común con ${e}.`,
|
|
100
|
+
axis: (e) => `hora de ${e}`
|
|
99
101
|
}
|
|
100
102
|
};
|
|
101
103
|
function x(e) {
|
|
@@ -675,22 +677,7 @@ function k(e, t = 2) {
|
|
|
675
677
|
return `${i}L360 ${r}Z`;
|
|
676
678
|
}
|
|
677
679
|
// src/WorldMap.tsx
|
|
678
|
-
|
|
679
|
-
let r = u(e, t) / 60 * 15 + 180 - 7.5;
|
|
680
|
-
return /* @__PURE__ */ a("g", {
|
|
681
|
-
className: `band ${n}`,
|
|
682
|
-
children: [
|
|
683
|
-
r - 360,
|
|
684
|
-
r,
|
|
685
|
-
r + 360
|
|
686
|
-
].map((e) => /* @__PURE__ */ a("rect", {
|
|
687
|
-
x: e,
|
|
688
|
-
y: 0,
|
|
689
|
-
width: 15,
|
|
690
|
-
height: 142
|
|
691
|
-
}, e))
|
|
692
|
-
});
|
|
693
|
-
}
|
|
680
|
+
var A = (e) => e / s * 360;
|
|
694
681
|
function j({ zone: e, side: t }) {
|
|
695
682
|
let n = C[e];
|
|
696
683
|
if (!n) return null;
|
|
@@ -702,8 +689,19 @@ function j({ zone: e, side: t }) {
|
|
|
702
689
|
r: 2.5
|
|
703
690
|
});
|
|
704
691
|
}
|
|
705
|
-
function M({
|
|
706
|
-
|
|
692
|
+
function M({ segments: e, className: t }) {
|
|
693
|
+
return /* @__PURE__ */ a("g", {
|
|
694
|
+
className: `window ${t}`,
|
|
695
|
+
children: e.map((e) => /* @__PURE__ */ a("rect", {
|
|
696
|
+
x: A(e.start),
|
|
697
|
+
y: 0,
|
|
698
|
+
width: A(e.end - e.start),
|
|
699
|
+
height: 142
|
|
700
|
+
}, e.start))
|
|
701
|
+
});
|
|
702
|
+
}
|
|
703
|
+
function N({ homeZone: e, visitorZone: t, now: r, home: i, visitor: s, both: c, nowMinute: l, label: u }) {
|
|
704
|
+
let d = n(() => k(r), [r]), f = D(r), p = c.reduce((e, t) => !e || t.end - t.start > e.end - e.start ? t : e, void 0);
|
|
707
705
|
return /* @__PURE__ */ o("svg", {
|
|
708
706
|
className: "map",
|
|
709
707
|
viewBox: "0 0 360 142",
|
|
@@ -713,22 +711,24 @@ function M({ homeZone: e, visitorZone: t, now: r }) {
|
|
|
713
711
|
className: "land",
|
|
714
712
|
d: S
|
|
715
713
|
}),
|
|
716
|
-
/* @__PURE__ */ a(A, {
|
|
717
|
-
zone: e,
|
|
718
|
-
date: r,
|
|
719
|
-
side: "home"
|
|
720
|
-
}),
|
|
721
|
-
/* @__PURE__ */ a(A, {
|
|
722
|
-
zone: t,
|
|
723
|
-
date: r,
|
|
724
|
-
side: "visitor"
|
|
725
|
-
}),
|
|
726
714
|
/* @__PURE__ */ a("path", {
|
|
727
715
|
className: "night",
|
|
728
|
-
d
|
|
716
|
+
d
|
|
717
|
+
}),
|
|
718
|
+
/* @__PURE__ */ a(M, {
|
|
719
|
+
segments: i,
|
|
720
|
+
className: "home"
|
|
721
|
+
}),
|
|
722
|
+
/* @__PURE__ */ a(M, {
|
|
723
|
+
segments: s,
|
|
724
|
+
className: "visitor"
|
|
725
|
+
}),
|
|
726
|
+
/* @__PURE__ */ a(M, {
|
|
727
|
+
segments: c,
|
|
728
|
+
className: "both"
|
|
729
729
|
}),
|
|
730
730
|
/* @__PURE__ */ o("g", {
|
|
731
|
-
transform: `translate(${
|
|
731
|
+
transform: `translate(${f.lon + 180} ${84 - f.lat})`,
|
|
732
732
|
children: [/* @__PURE__ */ a("circle", {
|
|
733
733
|
className: "sun-halo",
|
|
734
734
|
r: 7
|
|
@@ -744,75 +744,105 @@ function M({ homeZone: e, visitorZone: t, now: r }) {
|
|
|
744
744
|
/* @__PURE__ */ a(j, {
|
|
745
745
|
zone: t,
|
|
746
746
|
side: "visitor"
|
|
747
|
+
}),
|
|
748
|
+
/* @__PURE__ */ a("line", {
|
|
749
|
+
className: "now",
|
|
750
|
+
x1: A(l),
|
|
751
|
+
x2: A(l),
|
|
752
|
+
y1: 0,
|
|
753
|
+
y2: 142
|
|
754
|
+
}),
|
|
755
|
+
p && /* @__PURE__ */ a("text", {
|
|
756
|
+
className: "label",
|
|
757
|
+
x: A((p.start + p.end) / 2),
|
|
758
|
+
y: 71,
|
|
759
|
+
children: u
|
|
747
760
|
})
|
|
748
761
|
]
|
|
749
762
|
});
|
|
750
763
|
}
|
|
751
764
|
// src/zones.ts
|
|
752
|
-
function
|
|
765
|
+
function P(e) {
|
|
753
766
|
return (e.split("/").pop() ?? e).replaceAll("_", " ");
|
|
754
767
|
}
|
|
755
|
-
function
|
|
768
|
+
function F() {
|
|
756
769
|
return Intl.DateTimeFormat().resolvedOptions().timeZone;
|
|
757
770
|
}
|
|
758
|
-
function
|
|
771
|
+
function I(e = []) {
|
|
759
772
|
let t = Intl.supportedValuesOf("timeZone");
|
|
760
773
|
return [.../* @__PURE__ */ new Set([...t, ...e])].sort();
|
|
761
774
|
}
|
|
762
775
|
// src/TimezoneOverlap.tsx
|
|
763
|
-
function
|
|
776
|
+
function L(e = 6e4) {
|
|
764
777
|
let [n, i] = r(() => /* @__PURE__ */ new Date());
|
|
765
778
|
return t(() => {
|
|
766
779
|
let t = setInterval(() => i(/* @__PURE__ */ new Date()), e);
|
|
767
780
|
return () => clearInterval(t);
|
|
768
781
|
}, [e]), n;
|
|
769
782
|
}
|
|
770
|
-
var
|
|
783
|
+
var R = (e, t, n) => new Intl.DateTimeFormat(n, {
|
|
771
784
|
timeZone: t,
|
|
772
785
|
hour: "2-digit",
|
|
773
786
|
minute: "2-digit",
|
|
774
787
|
hourCycle: "h23"
|
|
775
|
-
}).format(e),
|
|
788
|
+
}).format(e), z = (e) => {
|
|
776
789
|
let t = c(e);
|
|
777
790
|
return `${String(Math.floor(t / 60)).padStart(2, "0")}:${String(t % 60).padStart(2, "0")}`;
|
|
778
|
-
},
|
|
791
|
+
}, B = (e) => {
|
|
779
792
|
let t = Math.floor(e / 60), n = e % 60;
|
|
780
793
|
return n ? `${t} h ${n} min` : `${t} h`;
|
|
781
|
-
},
|
|
782
|
-
function
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
style: {
|
|
788
|
-
left: `${e.start / s * 100}%`,
|
|
789
|
-
width: `${(e.end - e.start) / s * 100}%`
|
|
790
|
-
}
|
|
791
|
-
}, e.start))
|
|
792
|
-
});
|
|
793
|
-
}
|
|
794
|
-
function H({ homeZone: e, homeLabel: t, visitorZone: i, workStart: l, workEnd: d, lang: p, onVisitorZoneChange: m }) {
|
|
795
|
-
let h = b[p], g = I(), [v, y] = r(i), x = n(() => F([e, v]), [e, v]), S = n(() => _(e, v, {
|
|
796
|
-
workStart: l,
|
|
797
|
-
workEnd: d,
|
|
798
|
-
date: g
|
|
794
|
+
}, V = (e) => h(e).map((e) => `${z(e.start)}–${z(e.end)}`).join(", ");
|
|
795
|
+
function H({ homeZone: e, homeLabel: t, visitorZone: i, workStart: s, workEnd: l, lang: d, onVisitorZoneChange: p }) {
|
|
796
|
+
let m = b[d], h = L(), [g, v] = r(i), y = n(() => I([e, g]), [e, g]), x = n(() => _(e, g, {
|
|
797
|
+
workStart: s,
|
|
798
|
+
workEnd: l,
|
|
799
|
+
date: h
|
|
799
800
|
}), [
|
|
800
801
|
e,
|
|
801
|
-
|
|
802
|
+
g,
|
|
803
|
+
s,
|
|
802
804
|
l,
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
y(e), m?.(e);
|
|
805
|
+
h
|
|
806
|
+
]), S = u(e, h), C = c(h.getUTCHours() * 60 + h.getUTCMinutes() + S), w = t || P(e), T = f(x.both, S), E = f(x.both, u(g, h));
|
|
807
|
+
function D(e) {
|
|
808
|
+
v(e), p?.(e);
|
|
808
809
|
}
|
|
809
810
|
return /* @__PURE__ */ o("div", {
|
|
810
811
|
className: "widget",
|
|
811
812
|
children: [
|
|
812
|
-
/* @__PURE__ */
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
813
|
+
/* @__PURE__ */ o("div", {
|
|
814
|
+
className: "chart",
|
|
815
|
+
children: [
|
|
816
|
+
/* @__PURE__ */ a(N, {
|
|
817
|
+
homeZone: e,
|
|
818
|
+
visitorZone: g,
|
|
819
|
+
now: h,
|
|
820
|
+
home: f(x.home, S),
|
|
821
|
+
visitor: f(x.visitor, S),
|
|
822
|
+
both: T,
|
|
823
|
+
nowMinute: C,
|
|
824
|
+
label: B(x.minutes)
|
|
825
|
+
}),
|
|
826
|
+
/* @__PURE__ */ a("div", {
|
|
827
|
+
className: "ticks",
|
|
828
|
+
"aria-hidden": "true",
|
|
829
|
+
children: [
|
|
830
|
+
0,
|
|
831
|
+
6,
|
|
832
|
+
12,
|
|
833
|
+
18,
|
|
834
|
+
24
|
|
835
|
+
].map((e) => /* @__PURE__ */ a("span", {
|
|
836
|
+
style: { left: `${e / 24 * 100}%` },
|
|
837
|
+
children: z(e * 60).slice(0, 2)
|
|
838
|
+
}, e))
|
|
839
|
+
}),
|
|
840
|
+
/* @__PURE__ */ a("p", {
|
|
841
|
+
className: "axis-name",
|
|
842
|
+
"aria-hidden": "true",
|
|
843
|
+
children: m.axis(w)
|
|
844
|
+
})
|
|
845
|
+
]
|
|
816
846
|
}),
|
|
817
847
|
/* @__PURE__ */ o("div", {
|
|
818
848
|
className: "clocks",
|
|
@@ -823,9 +853,9 @@ function H({ homeZone: e, homeLabel: t, visitorZone: i, workStart: l, workEnd: d
|
|
|
823
853
|
className: "swatch home",
|
|
824
854
|
"aria-hidden": "true"
|
|
825
855
|
}),
|
|
826
|
-
|
|
856
|
+
w,
|
|
827
857
|
" ",
|
|
828
|
-
/* @__PURE__ */ a("time", { children:
|
|
858
|
+
/* @__PURE__ */ a("time", { children: R(h, e, d) })
|
|
829
859
|
]
|
|
830
860
|
}), /* @__PURE__ */ o("label", {
|
|
831
861
|
className: "clock",
|
|
@@ -835,63 +865,28 @@ function H({ homeZone: e, homeLabel: t, visitorZone: i, workStart: l, workEnd: d
|
|
|
835
865
|
"aria-hidden": "true"
|
|
836
866
|
}),
|
|
837
867
|
/* @__PURE__ */ a("select", {
|
|
838
|
-
"aria-label":
|
|
839
|
-
value:
|
|
840
|
-
onChange: (e) =>
|
|
841
|
-
children:
|
|
868
|
+
"aria-label": m.zoneLabel,
|
|
869
|
+
value: g,
|
|
870
|
+
onChange: (e) => D(e.target.value),
|
|
871
|
+
children: y.map((e) => /* @__PURE__ */ a("option", {
|
|
842
872
|
value: e,
|
|
843
873
|
children: e.replaceAll("_", " ")
|
|
844
874
|
}, e))
|
|
845
875
|
}),
|
|
846
|
-
/* @__PURE__ */ a("time", { children:
|
|
876
|
+
/* @__PURE__ */ a("time", { children: R(h, g, d) })
|
|
847
877
|
]
|
|
848
878
|
})]
|
|
849
879
|
}),
|
|
850
|
-
/* @__PURE__ */ o("div", {
|
|
851
|
-
className: "timeline",
|
|
852
|
-
"aria-hidden": "true",
|
|
853
|
-
children: [
|
|
854
|
-
/* @__PURE__ */ a(V, {
|
|
855
|
-
segments: f(S.home, C),
|
|
856
|
-
className: "home"
|
|
857
|
-
}),
|
|
858
|
-
/* @__PURE__ */ a(V, {
|
|
859
|
-
segments: f(S.visitor, C),
|
|
860
|
-
className: "visitor"
|
|
861
|
-
}),
|
|
862
|
-
/* @__PURE__ */ a(V, {
|
|
863
|
-
segments: f(S.both, C),
|
|
864
|
-
className: "both"
|
|
865
|
-
}),
|
|
866
|
-
/* @__PURE__ */ a("span", {
|
|
867
|
-
className: "now",
|
|
868
|
-
style: { left: `${w / s * 100}%` }
|
|
869
|
-
}),
|
|
870
|
-
/* @__PURE__ */ a("div", {
|
|
871
|
-
className: "ticks",
|
|
872
|
-
children: [
|
|
873
|
-
0,
|
|
874
|
-
6,
|
|
875
|
-
12,
|
|
876
|
-
18,
|
|
877
|
-
24
|
|
878
|
-
].map((e) => /* @__PURE__ */ a("span", {
|
|
879
|
-
style: { left: `${e / 24 * 100}%` },
|
|
880
|
-
children: R(e * 60).slice(0, 2)
|
|
881
|
-
}, e))
|
|
882
|
-
})
|
|
883
|
-
]
|
|
884
|
-
}),
|
|
885
880
|
/* @__PURE__ */ a("p", {
|
|
886
881
|
className: "summary",
|
|
887
882
|
role: "status",
|
|
888
|
-
children:
|
|
883
|
+
children: x.minutes > 0 ? m.overlap(B(x.minutes), w, V(E)) : m.none(w)
|
|
889
884
|
})
|
|
890
885
|
]
|
|
891
886
|
});
|
|
892
887
|
}
|
|
893
888
|
// src/styles.css?inline
|
|
894
|
-
var U = ":host{--_bg:var(--tom-bg,transparent);--_fg:var(--tom-fg,CanvasText);--_muted:var(--tom-muted,color-mix(in oklch, var(--_fg) 55%, transparent));--_track:var(--tom-track,color-mix(in oklch, var(--_fg) 10%, transparent));--_home:var(--tom-home,oklch(72% .14 200));--_visitor:var(--tom-visitor,oklch(75% .15 70));--_both:var(--tom-overlap,oklch(72% .17 145));--_land:var(--tom-land,color-mix(in oklch, var(--_fg) 22%, transparent));--_night:var(--tom-night,oklch(0% 0 0/.42));--_sun:var(--tom-sun,oklch(97% .06 95));--_radius:var(--tom-radius,4px);font:var(--tom-font,inherit);color:var(--_fg);background:var(--_bg);display:block}@supports (color:light-dark(black, white)){:host{--_night:var(--tom-night,light-dark(oklch(30% .03 260/.16),oklch(0% 0 0/.42)));--_sun:var(--tom-sun,light-dark(oklch(78% .16 75),oklch(97% .06 95)))}}:host([hidden]){display:none}.widget{gap:1rem;display:grid;container-type:inline-size}.map{block-size:auto;inline-size:100%;display:block;overflow:hidden}.land{fill:var(--_land)}.
|
|
889
|
+
var U = ":host{--_bg:var(--tom-bg,transparent);--_fg:var(--tom-fg,CanvasText);--_muted:var(--tom-muted,color-mix(in oklch, var(--_fg) 55%, transparent));--_track:var(--tom-track,color-mix(in oklch, var(--_fg) 10%, transparent));--_home:var(--tom-home,oklch(72% .14 200));--_visitor:var(--tom-visitor,oklch(75% .15 70));--_both:var(--tom-overlap,oklch(72% .17 145));--_land:var(--tom-land,color-mix(in oklch, var(--_fg) 22%, transparent));--_night:var(--tom-night,oklch(0% 0 0/.42));--_sun:var(--tom-sun,oklch(97% .06 95));--_radius:var(--tom-radius,4px);font:var(--tom-font,inherit);color:var(--_fg);background:var(--_bg);display:block}@supports (color:light-dark(black, white)){:host{--_night:var(--tom-night,light-dark(oklch(30% .03 260/.16),oklch(0% 0 0/.42)));--_sun:var(--tom-sun,light-dark(oklch(78% .16 75),oklch(97% .06 95)))}}:host([hidden]){display:none}.widget{gap:1rem;display:grid;container-type:inline-size}.map{block-size:auto;inline-size:100%;display:block;overflow:hidden}.land{fill:var(--_land)}.window rect{opacity:.22}.window.home rect{fill:var(--_home)}.window.visitor rect{fill:var(--_visitor)}.window.both rect{fill:var(--_both);opacity:.5}.map .now{stroke:var(--_fg);stroke-width:.75px;stroke-dasharray:2 2}.label{fill:var(--_fg);text-anchor:middle;dominant-baseline:central;paint-order:stroke;stroke:var(--tom-bg,Canvas);stroke-width:3px;stroke-linejoin:round;font-size:14px;font-weight:700}.night{fill:var(--_night)}.sun{fill:var(--_sun)}.sun-halo{fill:var(--_sun);opacity:.22}.dot{stroke:var(--_fg);stroke-width:.75px}.dot.home{fill:var(--_home)}.dot.visitor{fill:var(--_visitor)}@container (width<480px){.dot{r:4;stroke-width:1px}.sun{r:3.5}.sun-halo{r:9}}.clocks{flex-wrap:wrap;justify-content:space-between;gap:.5rem 1.5rem;display:flex}.clock{align-items:center;gap:.5rem;margin:0;display:flex}.clock time{font-variant-numeric:tabular-nums;color:var(--_muted)}select{font:inherit;color:inherit;border:1px solid var(--_track);border-radius:var(--_radius);background:0 0;max-width:16rem;padding:.125rem .25rem}.swatch{border-radius:50%;block-size:.75rem;inline-size:.75rem}.swatch.home{background:var(--_home)}.swatch.visitor{background:var(--_visitor)}.ticks{block-size:1.5em;color:var(--_muted);font-size:.75em;position:relative}.ticks>span{position:absolute;translate:-50%}.ticks>span:first-child{translate:0}.ticks>span:last-child{translate:-100%}.axis-name{text-align:center;color:var(--_muted);margin:0;font-size:.75em}.summary{margin:0}", W = "timezone-overlap-map", G = [
|
|
895
890
|
"home-zone",
|
|
896
891
|
"home-label",
|
|
897
892
|
"visitor-zone",
|
|
@@ -932,7 +927,7 @@ var X = class extends K {
|
|
|
932
927
|
this.#e && this.#n();
|
|
933
928
|
}
|
|
934
929
|
#n() {
|
|
935
|
-
let t = this.getAttribute("home-zone"), n = this.getAttribute("visitor-zone"), r = n && l(n) ? n :
|
|
930
|
+
let t = this.getAttribute("home-zone"), n = this.getAttribute("visitor-zone"), r = n && l(n) ? n : F();
|
|
936
931
|
this.#e?.render(/* @__PURE__ */ a(e, { children: /* @__PURE__ */ a(H, {
|
|
937
932
|
homeZone: t && l(t) ? t : "UTC",
|
|
938
933
|
homeLabel: this.getAttribute("home-label") ?? void 0,
|