summaryrefslogtreecommitdiff
path: root/src/modules/popdowns/sideright.tsx
blob: 5e873b3dfb8a894ef94a7e3ec4eb077b53bec770 (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
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
import SWeather, { type WeatherData } from "@/services/weather";
import { ellipsize } from "@/utils/strings";
import { bindCurrentTime } from "@/utils/system";
import { setupCustomTooltip, Calendar as WCal } from "@/utils/widgets";
import PopupWindow from "@/widgets/popupwindow";
import { bind, timeout } from "astal";
import { Astal, Gtk, type Gdk } from "astal/gtk3";

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}
                setup={self => {
                    const update = () =>
                        timeout(0.1, () => {
                            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")} />
                        <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 => ` ${w}`)}
                        setup={self =>
                            setupCustomTooltip(
                                self,
                                bind(weather, "wind").as(w => `${w} wind speed`)
                            )
                        }
                    />
                    <label
                        xalign={0}
                        label={bind(weather, "rainChance").as(r => ` ${r}`)}
                        setup={self =>
                            setupCustomTooltip(
                                self,
                                bind(weather, "rainChance").as(r => `${r} chance of rain`)
                            )
                        }
                    />
                </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 =>
                                weather.getTemp(weather.forecast[getHoursFromUpdate(r, i + 1)])
                            )}
                        />
                    </box>
                ))}
            </box>
        </box>
    );
};

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