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.scrollDown = mkStrOption "";
|
||||||
bar.customModules.weather.scrollUp = mkStrOption "";
|
bar.customModules.weather.scrollUp = mkStrOption "";
|
||||||
bar.customModules.weather.unit = mkStrOption "imperial";
|
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.autoDetectIcon = mkBoolOption false;
|
||||||
bar.launcher.icon = mkStrOption "";
|
bar.launcher.icon = mkStrOption "";
|
||||||
bar.launcher.middleClick = mkStrOption "";
|
bar.launcher.middleClick = mkStrOption "";
|
||||||
@@ -507,6 +517,8 @@ in
|
|||||||
theme.bar.buttons.modules.updates.spacing = mkStrOption "0.45em";
|
theme.bar.buttons.modules.updates.spacing = mkStrOption "0.45em";
|
||||||
theme.bar.buttons.modules.weather.enableBorder = mkBoolOption false;
|
theme.bar.buttons.modules.weather.enableBorder = mkBoolOption false;
|
||||||
theme.bar.buttons.modules.weather.spacing = mkStrOption "0.45em";
|
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.monochrome = mkBoolOption false;
|
||||||
theme.bar.buttons.network.enableBorder = mkBoolOption false;
|
theme.bar.buttons.network.enableBorder = mkBoolOption false;
|
||||||
theme.bar.buttons.network.spacing = mkStrOption "0.5em";
|
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 { Hyprsunset } from '../../components/bar/modules/hyprsunset/index';
|
||||||
import { Hypridle } from '../../components/bar/modules/hypridle/index';
|
import { Hypridle } from '../../components/bar/modules/hypridle/index';
|
||||||
import { Cava } from '../../components/bar/modules/cava/index';
|
import { Cava } from '../../components/bar/modules/cava/index';
|
||||||
|
import { WorldClock } from '../../components/bar/modules/worldclock/index';
|
||||||
|
|
||||||
export {
|
export {
|
||||||
Menu,
|
Menu,
|
||||||
@@ -54,4 +55,5 @@ export {
|
|||||||
Hyprsunset,
|
Hyprsunset,
|
||||||
Hypridle,
|
Hypridle,
|
||||||
Cava,
|
Cava,
|
||||||
|
WorldClock,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ import {
|
|||||||
Hyprsunset,
|
Hyprsunset,
|
||||||
Hypridle,
|
Hypridle,
|
||||||
Cava,
|
Cava,
|
||||||
|
WorldClock,
|
||||||
} from './exports';
|
} from './exports';
|
||||||
|
|
||||||
import { WidgetContainer } from './shared/WidgetContainer';
|
import { WidgetContainer } from './shared/WidgetContainer';
|
||||||
@@ -67,6 +68,7 @@ const widget = {
|
|||||||
hyprsunset: (): JSX.Element => WidgetContainer(Hyprsunset()),
|
hyprsunset: (): JSX.Element => WidgetContainer(Hyprsunset()),
|
||||||
hypridle: (): JSX.Element => WidgetContainer(Hypridle()),
|
hypridle: (): JSX.Element => WidgetContainer(Hypridle()),
|
||||||
cava: (): JSX.Element => WidgetContainer(Cava()),
|
cava: (): JSX.Element => WidgetContainer(Cava()),
|
||||||
|
worldclock: (): JSX.Element => WidgetContainer(WorldClock()),
|
||||||
};
|
};
|
||||||
|
|
||||||
const gdkMonitorMapper = new GdkMonitorMapper();
|
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.scrollUp} title="Scroll Up" type="string" />
|
||||||
<Option opt={options.bar.customModules.cava.scrollDown} title="Scroll Down" 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 */}
|
{/* Power Section */}
|
||||||
<Header title="Power" />
|
<Header title="Power" />
|
||||||
<Option
|
<Option
|
||||||
|
|||||||
@@ -223,6 +223,23 @@ export const CustomModuleTheme = (): JSX.Element => {
|
|||||||
/>
|
/>
|
||||||
<Option opt={options.theme.bar.buttons.modules.cava.border} title="Border" type="color" />
|
<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 */}
|
{/* Power Module Section */}
|
||||||
<Header title="Power" />
|
<Header title="Power" />
|
||||||
<Option opt={options.theme.bar.buttons.modules.power.icon} title="Icon" type="color" />
|
<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),
|
icon_background: opt(colors.base2),
|
||||||
spacing: opt('0.5em'),
|
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: {
|
menus: {
|
||||||
@@ -1235,6 +1244,18 @@ const options = mkOptions({
|
|||||||
scrollUp: opt(''),
|
scrollUp: opt(''),
|
||||||
scrollDown: 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
|
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
|
// custom font size
|
||||||
1.2em //
|
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