Skip to content

Commit 78377fb

Browse files
committed
feat: digital clock
1 parent 1284384 commit 78377fb

File tree

18 files changed

+3118
-31
lines changed

18 files changed

+3118
-31
lines changed

provisioning/dashboards/digital-sizes.json

Lines changed: 1025 additions & 0 deletions
Large diffs are not rendered by default.

provisioning/dashboards/digital.json

Lines changed: 1407 additions & 0 deletions
Large diffs are not rendered by default.

src/ClockPanel.test.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import {
55
ClockMode,
66
ClockRefresh,
77
ClockSource,
8+
ClockStyle,
89
ClockType,
910
CountdownQueryCalculation,
1011
CountupQueryCalculation,
@@ -489,6 +490,7 @@ const getDefaultProps = () => {
489490
clockType: ClockType.H24,
490491
mode: ClockMode.time,
491492
refresh: ClockRefresh.sec,
493+
style: ClockStyle.text,
492494
countdownSettings: {
493495
source: ClockSource.input,
494496
queryCalculation: CountdownQueryCalculation.lastNotNull,

src/ClockPanel.tsx

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -73,11 +73,13 @@ export function ClockPanel(props: Props) {
7373
height,
7474
}}
7575
>
76-
{dateSettings.showDate ? <RenderDate now={now} options={props.options} /> : null}
77-
<RenderTime options={props.options} targetTime={targetTime} err={err} now={now} />
78-
{timezoneSettings.showTimezone ? <RenderZone now={now} options={props.options} timezone={timezoneToUse} /> : null}
76+
{dateSettings.showDate ? <RenderDate now={now} options={props.options} width={width} height={height} /> : null}
77+
<RenderTime options={props.options} targetTime={targetTime} err={err} now={now} width={width} height={height} />
78+
{timezoneSettings.showTimezone ? (
79+
<RenderZone now={now} options={props.options} timezone={timezoneToUse} width={width} height={height} />
80+
) : null}
7981
{props.options.descriptionSettings.source !== DescriptionSource.none ? (
80-
<RenderDescription options={props.options} descriptionText={descriptionText} />
82+
<RenderDescription options={props.options} descriptionText={descriptionText} width={width} height={height} />
8183
) : null}
8284
</div>
8385
);

src/components/RenderDate.tsx

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,28 @@
11
import { css } from '@emotion/css';
22
import { Moment } from 'moment-timezone';
33
import React, { useMemo } from 'react';
4-
import { ClockOptions } from 'types';
4+
import { ClockOptions, ClockStyle } from '../types';
5+
import { useTheme2 } from '@grafana/ui';
6+
import { DigitalTime } from './digital/DigitalTime';
7+
import { getHeights } from './digital/utils';
8+
9+
export function RenderDate({
10+
options,
11+
now,
12+
width,
13+
height,
14+
}: {
15+
options: ClockOptions;
16+
now: Moment;
17+
width: number;
18+
height: number;
19+
}) {
20+
const theme = useTheme2();
21+
const fill =
22+
options.style === ClockStyle.digital && options.digitalSettings?.fillColor
23+
? theme.visualization.getColorByName(options.digitalSettings.fillColor)
24+
: '';
525

6-
export function RenderDate({ options, now }: { options: ClockOptions; now: Moment }) {
726
const { dateSettings } = options;
827

928
const className = useMemo(() => {
@@ -12,11 +31,16 @@ export function RenderDate({ options, now }: { options: ClockOptions; now: Momen
1231
font-weight: ${dateSettings.fontWeight};
1332
font-family: ${options.fontMono ? 'monospace' : ''};
1433
margin: 0;
34+
color: ${fill};
1535
`;
16-
}, [dateSettings.fontSize, dateSettings.fontWeight, options.fontMono]);
36+
}, [dateSettings.fontSize, dateSettings.fontWeight, options.fontMono, fill]);
1737

1838
const display = now.locale(dateSettings.locale || '').format(dateSettings.dateFormat);
1939

40+
if (options.style === ClockStyle.digital) {
41+
return <DigitalTime width={width} height={getHeights(height, options).date} options={options} text={display} />;
42+
}
43+
2044
return (
2145
<span>
2246
<h3 className={className}>{display}</h3>

src/components/RenderDescription.tsx

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,48 @@
11
import { css } from '@emotion/css';
2+
import { useTheme2 } from '@grafana/ui';
23
import React, { useMemo } from 'react';
3-
import { ClockOptions } from 'types';
4+
import { ClockOptions, ClockStyle } from 'types';
5+
import { DigitalTime } from './digital/DigitalTime';
6+
import { getHeights } from './digital/utils';
47

5-
export function RenderDescription({ options, descriptionText }: { options: ClockOptions; descriptionText: string }) {
8+
export function RenderDescription({
9+
options,
10+
descriptionText,
11+
width,
12+
height,
13+
}: {
14+
options: ClockOptions;
15+
descriptionText: string;
16+
width: number;
17+
height: number;
18+
}) {
619
const { descriptionSettings } = options;
20+
const theme = useTheme2();
21+
const fill =
22+
options.style === ClockStyle.digital && options.digitalSettings?.fillColor
23+
? theme.visualization.getColorByName(options.digitalSettings.fillColor)
24+
: '';
725

826
const className = useMemo(() => {
927
return css`
1028
font-size: ${descriptionSettings.fontSize};
1129
font-weight: ${descriptionSettings.fontWeight};
1230
font-family: ${options.fontMono ? 'monospace' : ''};
1331
margin: 0;
32+
color: ${fill};
1433
`;
15-
}, [descriptionSettings.fontSize, descriptionSettings.fontWeight, options.fontMono]);
34+
}, [descriptionSettings.fontSize, descriptionSettings.fontWeight, options.fontMono, fill]);
35+
36+
if (options.style === ClockStyle.digital) {
37+
return (
38+
<DigitalTime
39+
width={width}
40+
height={getHeights(height, options).description}
41+
options={options}
42+
text={descriptionText}
43+
/>
44+
);
45+
}
1646

1747
return (
1848
<span>

src/components/RenderTime.tsx

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,10 @@ import { css } from '@emotion/css';
22
import { t } from '@grafana/i18n';
33
import moment, { Moment } from 'moment-timezone';
44
import React, { useMemo } from 'react';
5-
import { ClockMode, ClockOptions, ClockType, TimeSettings } from 'types';
5+
import { ClockMode, ClockOptions, ClockStyle, ClockType, TimeSettings } from 'types';
6+
import { DigitalTime } from './digital/DigitalTime';
7+
import { getHeights } from './digital/utils';
8+
import { useTheme2 } from '@grafana/ui';
69

710
function getStrings() {
811
const oneYear = t('components.RenderTime.getStrings.oneYear', '1 year');
@@ -150,26 +153,31 @@ function getTimeFormat(clockType: ClockType, timeSettings: TimeSettings): string
150153
return 'HH:mm:ss';
151154
}
152155

153-
export function RenderTime({
154-
now,
155-
options,
156-
targetTime,
157-
err,
158-
}: {
156+
interface RenderTimeProps {
159157
now: moment.Moment;
160158
options: ClockOptions;
161159
targetTime: moment.Moment;
162160
err: string | null;
163-
}) {
161+
width: number;
162+
height: number;
163+
}
164+
165+
export function RenderTime({ now, options, targetTime, err, width, height }: RenderTimeProps) {
164166
const { clockType, timeSettings, mode } = options;
167+
const theme = useTheme2();
168+
const fill =
169+
options.style === ClockStyle.digital && options.digitalSettings?.fillColor
170+
? theme.visualization.getColorByName(options.digitalSettings.fillColor)
171+
: '';
165172
const className = useMemo(() => {
166173
return css`
167174
font-size: ${timeSettings.fontSize};
168175
font-family: ${options.fontMono ? 'monospace' : ''};
169176
font-weight: ${timeSettings.fontWeight};
177+
color: ${fill};
170178
margin: 0;
171179
`;
172-
}, [options.fontMono, timeSettings.fontSize, timeSettings.fontWeight]);
180+
}, [options.fontMono, timeSettings.fontSize, timeSettings.fontWeight, fill]);
173181

174182
let display = '';
175183
if (err !== null) {
@@ -196,5 +204,9 @@ export function RenderTime({
196204
break;
197205
}
198206

207+
if (options.style === ClockStyle.digital) {
208+
return <DigitalTime text={display} width={width} height={getHeights(height, options).time} options={options} />;
209+
}
210+
199211
return <h2 className={className}>{display}</h2>;
200212
}

src/components/RenderZone.tsx

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,43 @@
11
import { css } from '@emotion/css';
22
import { Moment } from 'moment-timezone';
33
import React, { useMemo } from 'react';
4-
import { ClockOptions, ZoneFormat } from 'types';
5-
import { getMoment } from 'utils';
4+
import { ClockOptions, ClockStyle, ZoneFormat } from '../types';
5+
import { getMoment } from '../utils';
6+
import { useTheme2 } from '@grafana/ui';
7+
import { DigitalTime } from './digital/DigitalTime';
8+
import { getHeights } from './digital/utils';
69

7-
export function RenderZone({ options, now, timezone }: { options: ClockOptions; now: Moment; timezone: string }) {
10+
export function RenderZone({
11+
options,
12+
now,
13+
timezone,
14+
width,
15+
height,
16+
}: {
17+
options: ClockOptions;
18+
now: Moment;
19+
timezone: string;
20+
width: number;
21+
height: number;
22+
}) {
823
const { timezoneSettings } = options;
924
const { zoneFormat } = timezoneSettings;
1025

26+
const theme = useTheme2();
27+
const fill =
28+
options.style === ClockStyle.digital && options.digitalSettings?.fillColor
29+
? theme.visualization.getColorByName(options.digitalSettings.fillColor)
30+
: '';
1131
const className = useMemo(() => {
1232
return css`
1333
font-size: ${timezoneSettings.fontSize};
1434
font-weight: ${timezoneSettings.fontWeight};
1535
font-family: ${options.fontMono ? 'monospace' : ''};
1636
line-height: 1.4;
1737
margin: 0;
38+
color: ${fill};
1839
`;
19-
}, [options.fontMono, timezoneSettings.fontSize, timezoneSettings.fontWeight]);
40+
}, [options.fontMono, timezoneSettings.fontSize, timezoneSettings.fontWeight, fill]);
2041

2142
let zone = timezone;
2243

@@ -38,6 +59,11 @@ export function RenderZone({ options, now, timezone }: { options: ClockOptions;
3859
}
3960
}
4061

62+
if (options.style === ClockStyle.digital) {
63+
const text = zoneFormat === ZoneFormat.nameOffset ? `${zone}\n${now.format('Z z')}` : zone;
64+
return <DigitalTime width={width} height={getHeights(height, options).zone} options={options} text={text} />;
65+
}
66+
4167
return (
4268
<h4 className={className} data-testid="time-zone">
4369
{zone}

src/components/digital/Colon.tsx

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import React from 'react';
2+
3+
interface ColonProps {
4+
char: string;
5+
stroke: string;
6+
strokeWidth: number;
7+
fill: string;
8+
filter: string;
9+
x?: number;
10+
}
11+
12+
export function Colon({ char, fill, filter, stroke, strokeWidth, x = 0 }: ColonProps) {
13+
if (char !== ':') {
14+
return null;
15+
}
16+
17+
const transform = `translate(${x}, 0)`;
18+
19+
return (
20+
<>
21+
<path
22+
d="M 73.5,47.317565 L 89,55.991045 L 89,76.508955 L 73.5,85.182435 L 58,76.508955 L 58,55.991045 L 73.5,47.317565 z "
23+
stroke={stroke}
24+
strokeWidth={strokeWidth}
25+
fill={fill}
26+
filter={filter}
27+
transform={transform}
28+
/>
29+
<path
30+
d="M 73.5,129.375003 L 89,138.048483 L 89,158.566393 L 73.5,167.239873 L 58,158.566393 L 58,138.048483 L 73.5,129.375003 z "
31+
stroke={stroke}
32+
strokeWidth={strokeWidth}
33+
fill={fill}
34+
filter={filter}
35+
transform={transform}
36+
/>
37+
</>
38+
);
39+
}

src/components/digital/Dash.tsx

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import React from 'react';
2+
3+
interface DashProps {
4+
char: string;
5+
stroke: string;
6+
strokeWidth: number;
7+
fill: string;
8+
filter: string;
9+
x?: number;
10+
}
11+
12+
export function Dash({ char, fill, filter, stroke, strokeWidth, x = 0 }: DashProps) {
13+
if (char !== '-') {
14+
return null;
15+
}
16+
17+
const transform = `translate(${x}, 0)`;
18+
19+
return (
20+
<path
21+
d="M 118.29731,107 L 103.08534,122.5 L 44.08535,122.5 L 28.56756,107 L 44.08535,91.5 L 103.08534,91.5 L 118.29731,107 z "
22+
stroke={stroke}
23+
strokeWidth={strokeWidth}
24+
fill={fill}
25+
filter={filter}
26+
transform={transform}
27+
/>
28+
);
29+
}

0 commit comments

Comments
 (0)