feat: add world clock module (#795)
Co-authored-by: Louis Dalibard <ontake@ontake.dev> Co-authored-by: Jas Singh <jaskiratpal.singh@outlook.com>
This commit is contained in:
@@ -291,6 +291,16 @@ in
|
||||
bar.customModules.weather.scrollDown = mkStrOption "";
|
||||
bar.customModules.weather.scrollUp = mkStrOption "";
|
||||
bar.customModules.weather.unit = mkStrOption "imperial";
|
||||
bar.customModules.worldclock.format = mkStrOption "%I:%M:%S %p %Z";
|
||||
bar.customModules.worldclock.formatDiffDate = mkStrOption "%a %b %d %I:%M:%S %p %Z";
|
||||
bar.customModules.worldclock.icon = mkStrOption "";
|
||||
bar.customModules.worldclock.middleClick = mkStrOption "";
|
||||
bar.customModules.worldclock.rightClick = mkStrOption "";
|
||||
bar.customModules.worldclock.scrollDown = mkStrOption "";
|
||||
bar.customModules.worldclock.scrollUp = mkStrOption "";
|
||||
bar.customModules.worldclock.showIcon = mkBoolOption true;
|
||||
bar.customModules.worldclock.showTime = mkBoolOption true;
|
||||
bar.customModules.worldclock.tz = mkStrListOption ["America/New_York" "Europe/Paris" "Asia/Tokyo"];
|
||||
bar.launcher.autoDetectIcon = mkBoolOption false;
|
||||
bar.launcher.icon = mkStrOption "";
|
||||
bar.launcher.middleClick = mkStrOption "";
|
||||
@@ -507,6 +517,8 @@ in
|
||||
theme.bar.buttons.modules.updates.spacing = mkStrOption "0.45em";
|
||||
theme.bar.buttons.modules.weather.enableBorder = mkBoolOption false;
|
||||
theme.bar.buttons.modules.weather.spacing = mkStrOption "0.45em";
|
||||
theme.bar.buttons.modules.worldclock.enableBorder = mkBoolOption false;
|
||||
theme.bar.buttons.modules.worldclock.spacing = mkStrOption "0.45em";
|
||||
theme.bar.buttons.monochrome = mkBoolOption false;
|
||||
theme.bar.buttons.network.enableBorder = mkBoolOption false;
|
||||
theme.bar.buttons.network.spacing = mkStrOption "0.5em";
|
||||
@@ -724,3 +736,4 @@ in
|
||||
];
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -25,6 +25,7 @@ import { Power } from '../../components/bar/modules/power/index';
|
||||
import { Hyprsunset } from '../../components/bar/modules/hyprsunset/index';
|
||||
import { Hypridle } from '../../components/bar/modules/hypridle/index';
|
||||
import { Cava } from '../../components/bar/modules/cava/index';
|
||||
import { WorldClock } from '../../components/bar/modules/worldclock/index';
|
||||
|
||||
export {
|
||||
Menu,
|
||||
@@ -54,4 +55,5 @@ export {
|
||||
Hyprsunset,
|
||||
Hypridle,
|
||||
Cava,
|
||||
WorldClock,
|
||||
};
|
||||
|
||||
@@ -26,6 +26,7 @@ import {
|
||||
Hyprsunset,
|
||||
Hypridle,
|
||||
Cava,
|
||||
WorldClock,
|
||||
} from './exports';
|
||||
|
||||
import { WidgetContainer } from './shared/WidgetContainer';
|
||||
@@ -67,6 +68,7 @@ const widget = {
|
||||
hyprsunset: (): JSX.Element => WidgetContainer(Hyprsunset()),
|
||||
hypridle: (): JSX.Element => WidgetContainer(Hypridle()),
|
||||
cava: (): JSX.Element => WidgetContainer(Cava()),
|
||||
worldclock: (): JSX.Element => WidgetContainer(WorldClock()),
|
||||
};
|
||||
|
||||
const gdkMonitorMapper = new GdkMonitorMapper();
|
||||
|
||||
120
src/components/bar/modules/worldclock/index.tsx
Normal file
120
src/components/bar/modules/worldclock/index.tsx
Normal file
@@ -0,0 +1,120 @@
|
||||
import { openMenu } from '../../utils/menu';
|
||||
import options from 'src/options';
|
||||
import { BarBoxChild } from 'src/lib/types/bar.js';
|
||||
import { runAsyncCommand, throttledScrollHandler } from 'src/components/bar/utils/helpers.js';
|
||||
import { bind, Variable } from 'astal';
|
||||
import { onMiddleClick, onPrimaryClick, onScroll, onSecondaryClick } from 'src/lib/shared/eventHandlers';
|
||||
import { Astal } from 'astal/gtk3';
|
||||
import { systemTime } from 'src/globals/time';
|
||||
import { GLib } from 'astal';
|
||||
|
||||
const { format, formatDiffDate, tz, icon, showIcon, showTime, rightClick, middleClick, scrollUp, scrollDown } =
|
||||
options.bar.customModules.worldclock;
|
||||
const { style } = options.theme.bar.buttons;
|
||||
|
||||
const time = Variable.derive(
|
||||
[systemTime, format, formatDiffDate, tz],
|
||||
(c, f, fdd, tzn) =>
|
||||
tzn
|
||||
.map((t) =>
|
||||
c
|
||||
.to_timezone(GLib.TimeZone.new(t))
|
||||
.format(c.to_timezone(GLib.TimeZone.new(t)).get_day_of_year() == c.get_day_of_year() ? f : fdd),
|
||||
)
|
||||
.join(' | ') || '',
|
||||
);
|
||||
|
||||
const WorldClock = (): BarBoxChild => {
|
||||
const ClockTime = (): JSX.Element => <label className={'bar-button-label worldclock bar'} label={bind(time)} />;
|
||||
const ClockIcon = (): JSX.Element => (
|
||||
<label className={'bar-button-icon worldclock txt-icon bar'} label={bind(icon)} />
|
||||
);
|
||||
|
||||
const componentClassName = Variable.derive(
|
||||
[bind(style), bind(showIcon), bind(showTime)],
|
||||
(btnStyle, shwIcn, shwLbl) => {
|
||||
const styleMap = {
|
||||
default: 'style1',
|
||||
split: 'style2',
|
||||
wave: 'style3',
|
||||
wave2: 'style3',
|
||||
};
|
||||
return `worldclock-container ${styleMap[btnStyle]} ${!shwLbl ? 'no-label' : ''} ${!shwIcn ? 'no-icon' : ''}`;
|
||||
},
|
||||
);
|
||||
|
||||
const componentChildren = Variable.derive([bind(showIcon), bind(showTime)], (shIcn, shTm) => {
|
||||
if (shIcn && !shTm) {
|
||||
return <ClockIcon />;
|
||||
} else if (shTm && !shIcn) {
|
||||
return <ClockTime />;
|
||||
}
|
||||
return (
|
||||
<box>
|
||||
<ClockIcon />
|
||||
<ClockTime />
|
||||
</box>
|
||||
);
|
||||
});
|
||||
|
||||
const component = (
|
||||
<box
|
||||
className={componentClassName()}
|
||||
onDestroy={() => {
|
||||
componentClassName.drop();
|
||||
componentChildren.drop();
|
||||
}}
|
||||
>
|
||||
{componentChildren()}
|
||||
</box>
|
||||
);
|
||||
|
||||
return {
|
||||
component,
|
||||
isVisible: true,
|
||||
boxClass: 'worldclock',
|
||||
props: {
|
||||
setup: (self: Astal.Button): void => {
|
||||
let disconnectFunctions: (() => void)[] = [];
|
||||
|
||||
Variable.derive(
|
||||
[
|
||||
bind(rightClick),
|
||||
bind(middleClick),
|
||||
bind(scrollUp),
|
||||
bind(scrollDown),
|
||||
bind(options.bar.scrollSpeed),
|
||||
],
|
||||
() => {
|
||||
disconnectFunctions.forEach((disconnect) => disconnect());
|
||||
disconnectFunctions = [];
|
||||
|
||||
const throttledHandler = throttledScrollHandler(options.bar.scrollSpeed.get());
|
||||
|
||||
disconnectFunctions.push(
|
||||
onPrimaryClick(self, (clicked, event) => {
|
||||
openMenu(clicked, event, 'calendarmenu');
|
||||
}),
|
||||
);
|
||||
|
||||
disconnectFunctions.push(
|
||||
onSecondaryClick(self, (clicked, event) => {
|
||||
runAsyncCommand(rightClick.get(), { clicked, event });
|
||||
}),
|
||||
);
|
||||
|
||||
disconnectFunctions.push(
|
||||
onMiddleClick(self, (clicked, event) => {
|
||||
runAsyncCommand(middleClick.get(), { clicked, event });
|
||||
}),
|
||||
);
|
||||
|
||||
disconnectFunctions.push(onScroll(self, throttledHandler, scrollUp.get(), scrollDown.get()));
|
||||
},
|
||||
);
|
||||
},
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
export { WorldClock };
|
||||
@@ -419,6 +419,29 @@ export const CustomModuleSettings = (): JSX.Element => {
|
||||
<Option opt={options.bar.customModules.cava.scrollUp} title="Scroll Up" type="string" />
|
||||
<Option opt={options.bar.customModules.cava.scrollDown} title="Scroll Down" type="string" />
|
||||
|
||||
{/* World Clock Section */}
|
||||
<Header title="World Clock" />
|
||||
<Option
|
||||
opt={options.theme.bar.buttons.modules.worldclock.enableBorder}
|
||||
title="Button Border"
|
||||
type="boolean"
|
||||
/>
|
||||
<Option opt={options.bar.customModules.worldclock.icon} title="Icon" type="string" />
|
||||
<Option opt={options.bar.customModules.worldclock.showIcon} title="Show Icon" type="boolean" />
|
||||
<Option opt={options.theme.bar.buttons.modules.worldclock.spacing} title="Spacing" type="string" />
|
||||
<Option opt={options.bar.customModules.worldclock.showTime} title="Show Time" type="boolean" />
|
||||
<Option opt={options.bar.customModules.worldclock.format} title="Format" type="string" />
|
||||
<Option
|
||||
opt={options.bar.customModules.worldclock.formatDiffDate}
|
||||
title="Format (when date different from local date)"
|
||||
type="string"
|
||||
/>
|
||||
<Option opt={options.bar.customModules.worldclock.rightClick} title="Right Click" type="string" />
|
||||
<Option opt={options.bar.customModules.worldclock.middleClick} title="Middle Click" type="string" />
|
||||
<Option opt={options.bar.customModules.worldclock.scrollUp} title="Scroll Up" type="string" />
|
||||
<Option opt={options.bar.customModules.worldclock.scrollDown} title="Scroll Down" type="string" />
|
||||
<Option opt={options.bar.customModules.worldclock.tz} title="Timezones Displayed" type="object" />
|
||||
|
||||
{/* Power Section */}
|
||||
<Header title="Power" />
|
||||
<Option
|
||||
|
||||
@@ -223,6 +223,23 @@ export const CustomModuleTheme = (): JSX.Element => {
|
||||
/>
|
||||
<Option opt={options.theme.bar.buttons.modules.cava.border} title="Border" type="color" />
|
||||
|
||||
{/* World Clock Module Section */}
|
||||
<Header title="World Clock" />
|
||||
<Option opt={options.theme.bar.buttons.modules.worldclock.text} title="Bars" type="color" />
|
||||
<Option opt={options.theme.bar.buttons.modules.worldclock.icon} title="Icon" type="color" />
|
||||
<Option
|
||||
opt={options.theme.bar.buttons.modules.worldclock.background}
|
||||
title="Label Background"
|
||||
type="color"
|
||||
/>
|
||||
<Option
|
||||
opt={options.theme.bar.buttons.modules.worldclock.icon_background}
|
||||
title="Icon Background"
|
||||
subtitle="Applies a background color to the icon section of the button.\nRequires 'split' button styling."
|
||||
type="color"
|
||||
/>
|
||||
<Option opt={options.theme.bar.buttons.modules.worldclock.border} title="Border" type="color" />
|
||||
|
||||
{/* Power Module Section */}
|
||||
<Header title="Power" />
|
||||
<Option opt={options.theme.bar.buttons.modules.power.icon} title="Icon" type="color" />
|
||||
|
||||
@@ -435,6 +435,15 @@ const options = mkOptions({
|
||||
icon_background: opt(colors.base2),
|
||||
spacing: opt('0.5em'),
|
||||
},
|
||||
worldclock: {
|
||||
enableBorder: opt(false),
|
||||
border: opt(colors.yellow),
|
||||
background: opt(colors.base2),
|
||||
text: opt(colors.yellow),
|
||||
icon: opt(colors.yellow),
|
||||
icon_background: opt(colors.base2),
|
||||
spacing: opt('0.5em'),
|
||||
},
|
||||
},
|
||||
},
|
||||
menus: {
|
||||
@@ -1235,6 +1244,18 @@ const options = mkOptions({
|
||||
scrollUp: opt(''),
|
||||
scrollDown: opt(''),
|
||||
},
|
||||
worldclock: {
|
||||
icon: opt(''),
|
||||
showIcon: opt(true),
|
||||
showTime: opt(true),
|
||||
format: opt('%I:%M:%S %p %Z'),
|
||||
formatDiffDate: opt('%a %b %d %I:%M:%S %p %Z'),
|
||||
rightClick: opt(''),
|
||||
middleClick: opt(''),
|
||||
scrollUp: opt(''),
|
||||
scrollDown: opt(''),
|
||||
tz: opt(['America/New_York', 'Europe/Paris', 'Asia/Tokyo']),
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
|
||||
@@ -58,3 +58,69 @@
|
||||
0em
|
||||
);
|
||||
}
|
||||
|
||||
.bar-button-label.worldclock {
|
||||
color: if($bar-buttons-monochrome, $bar-buttons-text, $bar-buttons-modules-worldclock-text);
|
||||
margin-left: $bar-buttons-modules-worldclock-spacing;
|
||||
}
|
||||
|
||||
.bar-button-icon.worldclock {
|
||||
font-size: 1.2em;
|
||||
color: if($bar-buttons-monochrome, $bar-buttons-icon, $bar-buttons-modules-worldclock-icon);
|
||||
}
|
||||
|
||||
.style2 {
|
||||
.bar-button-icon.worldclock {
|
||||
border-top-left-radius: $bar-buttons-radius;
|
||||
border-bottom-left-radius: $bar-buttons-radius;
|
||||
background: if(
|
||||
$bar-buttons-monochrome,
|
||||
$bar-buttons-icon_background,
|
||||
$bar-buttons-modules-worldclock-icon_background
|
||||
);
|
||||
padding: $bar-buttons-padding_y 0em;
|
||||
padding-left: $bar-buttons-padding_x;
|
||||
padding-right: $bar-buttons-modules-worldclock-spacing;
|
||||
border-top-left-radius: if(
|
||||
$bar-buttons-modules-worldclock-enableBorder or $bar-buttons-enableBorders,
|
||||
$bar-buttons-radius * $bar-buttons-innerRadiusMultiplier,
|
||||
$bar-buttons-radius
|
||||
);
|
||||
border-bottom-left-radius: if(
|
||||
$bar-buttons-modules-worldclock-enableBorder or $bar-buttons-enableBorders,
|
||||
$bar-buttons-radius * $bar-buttons-innerRadiusMultiplier,
|
||||
$bar-buttons-radius
|
||||
);
|
||||
color: if($bar-buttons-monochrome, $bar-buttons-icon, $bar-buttons-modules-worldclock-icon);
|
||||
}
|
||||
|
||||
.bar-button-label.worldclock {
|
||||
padding: $bar-buttons-padding_y 0em;
|
||||
padding-right: $bar-buttons-padding_x;
|
||||
padding-left: $bar-buttons-modules-worldclock-spacing;
|
||||
margin-left: 0em;
|
||||
}
|
||||
&.no-label.worldclock-container {
|
||||
.bar-button-icon.worldclock {
|
||||
border-top-right-radius: if(
|
||||
$bar-buttons-modules-worldclock-enableBorder or $bar-buttons-enableBorders,
|
||||
$bar-buttons-radius * $bar-buttons-innerRadiusMultiplier,
|
||||
$bar-buttons-radius
|
||||
);
|
||||
border-bottom-right-radius: if(
|
||||
$bar-buttons-modules-worldclock-enableBorder or $bar-buttons-enableBorders,
|
||||
$bar-buttons-radius * $bar-buttons-innerRadiusMultiplier,
|
||||
$bar-buttons-radius
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.bar_item_box_visible.worldclock {
|
||||
border: if(
|
||||
$bar-buttons-modules-worldclock-enableBorder or $bar-buttons-enableBorders,
|
||||
$bar-buttons-borderSize solid
|
||||
if($bar-buttons-monochrome, $bar-buttons-borderColor, $bar-buttons-modules-worldclock-border),
|
||||
0em
|
||||
);
|
||||
}
|
||||
|
||||
@@ -503,3 +503,30 @@
|
||||
// custom font size
|
||||
1.2em //
|
||||
);
|
||||
|
||||
/*
|
||||
* #################################
|
||||
* # World Clock Styling #
|
||||
* #################################
|
||||
*/
|
||||
@include styleModule(
|
||||
//
|
||||
// class name
|
||||
'worldclock',
|
||||
// label color
|
||||
$bar-buttons-modules-worldclock-text,
|
||||
// icon color
|
||||
$bar-buttons-modules-worldclock-icon,
|
||||
// icon background if split style is used
|
||||
$bar-buttons-modules-worldclock-icon_background,
|
||||
// label background
|
||||
$bar-buttons-modules-worldclock-background,
|
||||
// inner spacing
|
||||
$bar-buttons-modules-worldclock-spacing,
|
||||
// if border enabled
|
||||
$bar-buttons-modules-worldclock-enableBorder,
|
||||
// border color
|
||||
$bar-buttons-modules-worldclock-border,
|
||||
// custom font size
|
||||
1.2em //
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user