summaryrefslogtreecommitdiff
path: root/src/modules/popdowns/sideright.tsx
blob: 86c05475f1b77045f536158081d668d0b7408b9f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
import { bind } from "astal";
import { Astal, Gtk, type Gdk } from "astal/gtk3";
import SWeather, { type WeatherData } from "../../services/weather";
import { ellipsize } from "../../utils/strings";
import { bindCurrentTime } from "../../utils/system";
import { Calendar as WCal } from "../../utils/widgets";
import PopupWindow from "../../widgets/popupwindow";

const getHoursFromUpdate = (data: WeatherData, hours: number) => {
    const updateTime = data.location.localtime_epoch;
    const updateHourStart = updateTime - (updateTime % 3600);

    let nextHour = new Date((updateHourStart + hours * 3600) * 1000).getHours();
    if (nextHour >= 24) nextHour -= 24;

    return nextHour;
};

const Time = () => (
    <box className="time">
        <box hexpand halign={Gtk.Align.CENTER}>
            <label label={bindCurrentTime("%I:%M:%S")} />
            <label className="ampm" label={bindCurrentTime("%p", c => (c.get_hour() < 12 ? "AM" : "PM"))} />
        </box>
    </box>
);

const Calendar = () => (
    <box className="calendar">
        <eventbox
            setup={self => {
                self.connect("button-press-event", (_, event: Gdk.Event) => {
                    if (event.get_button()[1] === Astal.MouseButton.MIDDLE) {
                        const now = new Date();
                        const child = self.get_child() as WCal | null;
                        if (!child) return;
                        child.select_month(now.getMonth(), now.getFullYear());
                    }
                });
            }}
        >
            <WCal
                hexpand
                showDetails={false}
                day={0}
                setup={self => {
                    const update = () => {
                        const now = new Date();
                        if (self.month === now.getMonth() && self.year === now.getFullYear()) self.day = now.getDate();
                        else self.day = 0;
                    };
                    self.connect("month-changed", update);
                    self.connect("next-month", update);
                    self.connect("prev-month", update);
                    self.connect("next-year", update);
                    self.connect("prev-year", update);
                    update();
                }}
            />
        </eventbox>
    </box>
);

const Weather = () => {
    const weather = SWeather.get_default();

    return (
        <box vertical className="weather">
            <centerbox className="current">
                <label
                    halign={Gtk.Align.START}
                    valign={Gtk.Align.CENTER}
                    className="status-icon"
                    label={bind(weather, "icon")}
                />
                <box vertical halign={Gtk.Align.CENTER} valign={Gtk.Align.CENTER} className="status">
                    <box halign={Gtk.Align.CENTER} className="temperature">
                        <label label={bind(weather, "temperature").as(t => `${Math.round(t)}°C`)} />
                        <label
                            className={bind(weather, "tempColour").as(c => `temp-icon ${c}`)}
                            label={bind(weather, "tempIcon")}
                        />
                    </box>
                    <label label={bind(weather, "condition").as(c => ellipsize(c, 16))} />
                </box>
                <box vertical halign={Gtk.Align.END} valign={Gtk.Align.CENTER} className="other-data">
                    <label xalign={0} label={bind(weather, "wind").as(w => ` ${Math.round(w)} kph`)} />
                    <label xalign={0} label={bind(weather, "rainChance").as(r => ` ${r}%`)} />
                </box>
            </centerbox>
            <box className="separator" />
            <box className="forecast">
                {Array.from({ length: 4 }).map((_, i) => (
                    <box vertical hexpand className="hour">
                        <label
                            label={bind(weather, "raw").as(r => {
                                const hour = getHoursFromUpdate(r, i + 1);
                                return `${hour % 12 || 12}${hour < 12 ? "AM" : "PM"}`;
                            })}
                        />
                        <label
                            className="icon"
                            label={bind(weather, "raw").as(r =>
                                weather.getIcon(weather.forecast[getHoursFromUpdate(r, i + 1)]?.condition.text ?? "")
                            )}
                        />
                        <label
                            label={bind(weather, "raw").as(
                                r => `${Math.round(weather.forecast[getHoursFromUpdate(r, i + 1)]?.temp_c) ?? "-"}°C`
                            )}
                        />
                    </box>
                ))}
            </box>
        </box>
    );
};

export default () => (
    <PopupWindow name="sideright">
        <box vertical className="sideright">
            <Time />
            <Calendar />
            <Weather />
        </box>
    </PopupWindow>
);