feat(date): implement date widget with short and long date formats

Co-authored-by: David Ralph <me@davidcralph.co.uk>
This commit is contained in:
alexsparkes
2024-12-16 14:08:46 +00:00
parent a4ae9496a3
commit ae014e46f2
17 changed files with 223 additions and 218 deletions

View File

@@ -0,0 +1,68 @@
import { useState, useEffect, useRef, useCallback } from 'react';
import { convertTimezone } from 'utils/date';
import EventBus from 'utils/eventbus';
import defaults from './options/default';
import { WeekNumber } from './components/WeekNumber';
import { ShortDate } from './components/ShortDate';
import { LongDate } from './components/LongDate';
import './date.scss';
const DateWidget = () => {
const [date, setDate] = useState('');
const [weekNumber, setWeekNumber] = useState('');
const dateRef = useRef();
const getDate = useCallback(() => {
let currentDate = new Date();
const timezone = localStorage.getItem('timezone');
if (timezone && timezone !== 'auto') {
currentDate = convertTimezone(currentDate, timezone);
}
if (localStorage.getItem('dateType') === 'short') {
setDate(ShortDate(currentDate));
} else {
setDate(LongDate(currentDate));
}
setWeekNumber(WeekNumber(currentDate));
}, []);
useEffect(() => {
const handleRefresh = (data) => {
if (data === 'date' || data === 'timezone') {
if (localStorage.getItem('date') === 'false') {
dateRef.current.style.display = 'none';
return;
}
dateRef.current.style.display = 'block';
dateRef.current.style.fontSize = `${Number(
(localStorage.getItem('zoomDate') || defaults.zoomDate) / 100,
)}em`;
getDate();
}
};
EventBus.on('refresh', handleRefresh);
dateRef.current.style.fontSize = `${Number((localStorage.getItem('zoomDate') || defaults.zoomDate) / 100)}em`;
getDate();
return () => {
EventBus.off('refresh', handleRefresh);
};
}, [getDate]);
return (
<div className="flex flex-col" ref={dateRef}>
<span className="date">{date}</span>
<span className="date">{weekNumber}</span>
</div>
);
};
export { DateWidget as default, DateWidget };

View File

@@ -0,0 +1,39 @@
import variables from 'config/variables';
import defaults from '../options/default';
import { appendNth } from 'utils/date';
export const LongDate = (currentDate) => {
const lang = variables.locale_id.split('-')[0];
const datenth =
localStorage.getItem('datenth') === 'true'
? appendNth(currentDate.getDate())
: currentDate.getDate();
const dateDay =
localStorage.getItem('dayofweek') === 'true'
? currentDate.toLocaleDateString(lang, { weekday: 'long' })
: '';
const dateMonth = currentDate.toLocaleDateString(lang, { month: 'long' });
const dateYear = currentDate.getFullYear();
let day = dateDay + ' ' + datenth;
let month = dateMonth;
let year = dateYear;
switch (localStorage.getItem('longFormat')) {
case 'MDY':
day = dateMonth;
month = dateDay + ' ' + datenth;
break;
case 'YMD':
day = dateYear;
year = dateDay + ' ' + datenth;
break;
// DMY
default:
break;
}
return `${day} ${month} ${year}`;
};

View File

@@ -0,0 +1,38 @@
import defaults from '../options/default';
export const ShortDate = (currentDate) => {
const dateDay = currentDate.getDate();
const dateMonth = currentDate.getMonth() + 1;
const dateYear = currentDate.getFullYear();
const zero = localStorage.getItem('datezero') === 'true' || defaults.datezero;
let day = zero ? ('00' + dateDay).slice(-2) : dateDay;
let month = zero ? ('00' + dateMonth).slice(-2) : dateMonth;
let year = dateYear;
switch (localStorage.getItem('dateFormat')) {
case 'MDY':
day = dateMonth;
month = dateDay;
break;
case 'YMD':
day = dateYear;
year = dateDay;
break;
// DMY
default:
break;
}
const separators = {
dots: '.',
dash: '-',
gaps: ' - ',
slashes: '/',
};
const format = separators[localStorage.getItem('shortFormat') || defaults.shortFormat];
return <>{`${day}${format}${month}${format}${year}`}</>;
};

View File

@@ -0,0 +1,24 @@
import variables from 'config/variables';
import defaults from '../options/default';
const getWeekNumber = (date) => {
const firstDayOfYear = new Date(date.getFullYear(), 0, 1);
const pastDaysOfYear = (date - firstDayOfYear) / 86400000;
return Math.ceil((pastDaysOfYear + firstDayOfYear.getDay() + 1) / 7);
};
export const WeekNumber = (date) => {
const enabled = localStorage.getItem('weeknumber') === 'true' || defaults.weeknumber;
if (!enabled || !date) {
return null;
}
const weekNumber = getWeekNumber(date);
return (
<span className="date">
{variables.getMessage('widgets.date.week')} {weekNumber}
</span>
);
};

View File

@@ -0,0 +1 @@
export * from './options';

View File

@@ -9,9 +9,7 @@ import { Row, Content, Action, PreferencesWrapper } from 'components/Layout/Sett
import defaults from './default';
function DateOptions() {
const [dateType, setDateType] = useState(
localStorage.getItem('dateType') || defaults.date.dateType,
);
const [dateType, setDateType] = useState(localStorage.getItem('dateType') || defaults.dateType);
const dateFormats = ['DMY', 'MDY', 'YMD'];
const longSettings = (

View File

@@ -0,0 +1,14 @@
const DefaultOptions = {
date: false,
dateType: 'long',
longFormat: 'DMY',
dayofweek: false,
datenth: false,
dateFormat: 'DMY',
shortFormat: 'dots',
zoomDate: 100,
weeknumber: false,
datezero: false,
};
export default DefaultOptions;

View File

@@ -0,0 +1 @@
export * from './DateOptions';

View File

@@ -6,7 +6,8 @@ import { Tabs } from 'components/Elements/MainModal/backend/newTabs';
import { NavbarOptions } from 'features/navbar';
import { GreetingOptions } from 'features/greeting';
import { TimeOptions, DateOptions } from 'features/time';
import { TimeOptions } from 'features/time';
import { DateOptions } from 'features/date';
import { QuickLinksOptions } from 'features/quicklinks';
import { QuoteOptions } from 'features/quote';
import { MessageOptions } from 'features/message';

View File

@@ -4,7 +4,7 @@ import Greeting from '../../greeting/Greeting';
import Quote from '../../quote/Quote';
import Search from '../../search/Search';
import QuickLinks from '../../quicklinks/QuickLinks';
import Date from '../../time/Date';
import Date from '../../date/Date';
import Message from '../../message/Message';
import { WidgetsLayout } from 'components/Layout';
import EventBus from 'utils/eventbus';

View File

@@ -434,7 +434,7 @@ class Quote extends PureComponent {
modalClose={() => this.setState({ shareModal: false })}
/>
</Modal>
<span className="quote" ref={this.quote}>
<span className="quote w-[40vw]" ref={this.quote}>
{this.state.quote}
</span>

View File

@@ -2,7 +2,7 @@ import variables from 'config/variables';
import { useState, useEffect } from 'react';
import { MdSource } from 'react-icons/md';
import { MdSource, MdPerson, MdContentCopy, MdIosShare, MdStarBorder } from 'react-icons/md';
import {
Header,
@@ -16,11 +16,35 @@ import { Checkbox, Dropdown } from 'components/Form/Settings';
import { useTab } from 'components/Elements/MainModal/backend/TabContext';
import { Hero, Preview, Controls } from 'components/Layout/Settings/Hero';
import { Quote } from 'features/quote';
import CustomSettings from './Custom';
import defaults from './default';
const QuotePreview = () => {
return (
<div className="quotediv">
<span className="quote">"The best way to predict the future is to invent it."</span>
<div className="author-holder">
<div className="author">
<div className="author-img">
<MdPerson />
</div>
<div className="author-content">
<span className="title">Alan Kay</span>
<span className="subtitle">Computer Scientist</span>
</div>
<div className="quote-buttons">
<MdContentCopy />
<MdIosShare />
<MdStarBorder />
</div>
</div>
</div>
</div>
);
};
const QuoteOptions = () => {
const [quoteType, setQuoteType] = useState(
localStorage.getItem('quoteType') || defaults.quoteType,
@@ -108,24 +132,11 @@ const QuoteOptions = () => {
return (
<>
{/* {subSection === 'source' ? (
<Header
title={variables.getMessage(`${QUOTE_SECTION}.title`)}
secondaryTitle={variables.getMessage('settings:sections.background.source.title')}
report={false}
/>
) : (
<Header
title={variables.getMessage(`${QUOTE_SECTION}.title`)}
setting="quote"
category="quote"
element=".quotediv"
zoomSetting="zoomQuote"
visibilityToggle={true}
/>
)} */}
{subSection === '' && (
<Hero>
<Preview>
<QuotePreview />
</Preview>
<Controls
title={variables.getMessage(`${QUOTE_SECTION}.title`)}
setting="quote"
@@ -160,14 +171,10 @@ const QuoteOptions = () => {
>
<SourceDropdown />
</Section>
<PreferencesWrapper
setting="quote"
default={defaults.quote}
zoomSetting="zoomQuote"
category="quote"
visibilityToggle={true}
>
<PreferencesWrapper setting="quote">
<ButtonOptions />
</PreferencesWrapper>
<PreferencesWrapper setting="quote">
<AdditionalOptions />
</PreferencesWrapper>
</>

View File

@@ -10,7 +10,6 @@
color: #fff;
font-weight: 600;
width: 40vw;
}
.quoteauthor {

View File

@@ -1,166 +0,0 @@
import variables from 'config/variables';
import { useState, useEffect, useRef, useCallback } from 'react';
import { appendNth, convertTimezone } from 'utils/date';
import EventBus from 'utils/eventbus';
import defaults from './options/default';
import './date.scss';
const DateWidget = () => {
const [date, setDate] = useState('');
const [weekNumber, setWeekNumber] = useState(null);
const dateRef = useRef();
/**
* Get the week number of the year for the given date.
* @param {Date} date
*/
const getWeekNumber = useCallback((date) => {
const dateToday = new Date(date.valueOf());
const dayNumber = (dateToday.getDay() + 6) % 7;
dateToday.setDate(dateToday.getDate() - dayNumber + 3);
const firstThursday = dateToday.valueOf();
dateToday.setMonth(0, 1);
if (dateToday.getDay() !== 4) {
dateToday.setMonth(0, 1 + ((4 - dateToday.getDay() + 7) % 7));
}
setWeekNumber(
`${variables.getMessage('widgets.date.week')} ${
1 + Math.ceil((firstThursday - dateToday) / 604800000)
}`,
);
}, []);
const getDate = useCallback(() => {
let currentDate = new Date();
const timezone = localStorage.getItem('timezone');
if (timezone && timezone !== 'auto') {
currentDate = convertTimezone(currentDate, timezone);
}
if (localStorage.getItem('weeknumber') === 'true') {
getWeekNumber(currentDate);
} else if (weekNumber !== null) {
setWeekNumber(null);
}
if (localStorage.getItem('dateType') === 'short') {
const dateDay = currentDate.getDate();
const dateMonth = currentDate.getMonth() + 1;
const dateYear = currentDate.getFullYear();
const zero = localStorage.getItem('datezero') === 'true';
let day = zero ? ('00' + dateDay).slice(-2) : dateDay;
let month = zero ? ('00' + dateMonth).slice(-2) : dateMonth;
let year = dateYear;
switch (localStorage.getItem('dateFormat')) {
case 'MDY':
day = dateMonth;
month = dateDay;
break;
case 'YMD':
day = dateYear;
year = dateDay;
break;
// DMY
default:
break;
}
let format;
switch (localStorage.getItem('shortFormat')) {
case 'dots':
format = `${day}.${month}.${year}`;
break;
case 'dash':
format = `${day}-${month}-${year}`;
break;
case 'gaps':
format = `${day} - ${month} - ${year}`;
break;
case 'slashes':
format = `${day}/${month}/${year}`;
break;
default:
break;
}
setDate(format);
} else {
// Long date
const lang = variables.locale_id.split('-')[0];
const datenth =
localStorage.getItem('datenth') === 'true'
? appendNth(currentDate.getDate())
: currentDate.getDate();
const dateDay =
localStorage.getItem('dayofweek') === 'true'
? currentDate.toLocaleDateString(lang, { weekday: 'long' })
: '';
const dateMonth = currentDate.toLocaleDateString(lang, { month: 'long' });
const dateYear = currentDate.getFullYear();
let day = dateDay + ' ' + datenth;
let month = dateMonth;
let year = dateYear;
switch (localStorage.getItem('longFormat')) {
case 'MDY':
day = dateMonth;
month = dateDay + ' ' + datenth;
break;
case 'YMD':
day = dateYear;
year = dateDay + ' ' + datenth;
break;
// DMY
default:
break;
}
setDate(`${day} ${month} ${year}`);
}
}, [getWeekNumber, weekNumber]);
useEffect(() => {
const handleRefresh = (data) => {
if (data === 'date' || data === 'timezone') {
if (localStorage.getItem('date') === 'false') {
dateRef.current.style.display = 'none';
return;
}
dateRef.current.style.display = 'block';
dateRef.current.style.fontSize = `${Number(
(localStorage.getItem('zoomDate') || defaults.zoomDate) / 100,
)}em`;
getDate();
}
};
EventBus.on('refresh', handleRefresh);
dateRef.current.style.fontSize = `${Number((localStorage.getItem('zoomDate') || defaults.zoomDate) / 100)}em`;
getDate();
return () => {
EventBus.off('refresh', handleRefresh);
};
}, [getDate]);
return (
<div className="flex flex-col" ref={dateRef}>
<span className="date">{date}</span>
<span className="date">{weekNumber}</span>
</div>
);
};
export { DateWidget as default, DateWidget };

View File

@@ -1,17 +1,4 @@
const DefaultDateOptions = {
date: false,
dateType: 'long',
longFormat: 'DMY',
dayofweek: false,
datenth: false,
dateFormat: 'DMY',
shortFormat: 'dots',
zoomDate: 100,
weeknumber: false,
datezero: false,
};
const DefaultTimeOptions = {
const DefaultOptions = {
time: true,
timeType: 'digital',
hourColour: '#ffffff',
@@ -29,9 +16,4 @@ const DefaultTimeOptions = {
zoomClock: 100,
};
const DefaultOptions = {
date: DefaultDateOptions,
time: DefaultTimeOptions,
};
export default DefaultOptions;

View File

@@ -1,2 +1 @@
export * from './TimeOptions';
export * from './DateOptions';