From ae014e46f263b0320d258bec82d29bab9917dfd6 Mon Sep 17 00:00:00 2001 From: alexsparkes Date: Mon, 16 Dec 2024 14:08:46 +0000 Subject: [PATCH] feat(date): implement date widget with short and long date formats Co-authored-by: David Ralph --- src/features/date/Date.jsx | 68 +++++++ src/features/date/components/LongDate.jsx | 39 ++++ src/features/date/components/ShortDate.jsx | 38 ++++ src/features/date/components/WeekNumber.jsx | 24 +++ src/features/{time => date}/date.scss | 0 src/features/date/index.jsx | 1 + .../{time => date}/options/DateOptions.jsx | 4 +- src/features/date/options/default.js | 14 ++ src/features/date/options/index.jsx | 1 + src/features/misc/views/Settings.jsx | 3 +- src/features/misc/views/Widgets.jsx | 2 +- src/features/quote/Quote.jsx | 2 +- src/features/quote/options/QuoteOptions.jsx | 57 +++--- src/features/quote/quote.scss | 1 - src/features/time/Date.jsx | 166 ------------------ src/features/time/options/default.js | 20 +-- src/features/time/options/index.jsx | 1 - 17 files changed, 223 insertions(+), 218 deletions(-) create mode 100644 src/features/date/Date.jsx create mode 100644 src/features/date/components/LongDate.jsx create mode 100644 src/features/date/components/ShortDate.jsx create mode 100644 src/features/date/components/WeekNumber.jsx rename src/features/{time => date}/date.scss (100%) create mode 100644 src/features/date/index.jsx rename src/features/{time => date}/options/DateOptions.jsx (97%) create mode 100644 src/features/date/options/default.js create mode 100644 src/features/date/options/index.jsx delete mode 100644 src/features/time/Date.jsx diff --git a/src/features/date/Date.jsx b/src/features/date/Date.jsx new file mode 100644 index 00000000..3772f26a --- /dev/null +++ b/src/features/date/Date.jsx @@ -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 ( +
+ {date} + {weekNumber} +
+ ); +}; + +export { DateWidget as default, DateWidget }; diff --git a/src/features/date/components/LongDate.jsx b/src/features/date/components/LongDate.jsx new file mode 100644 index 00000000..ce33644d --- /dev/null +++ b/src/features/date/components/LongDate.jsx @@ -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}`; +}; diff --git a/src/features/date/components/ShortDate.jsx b/src/features/date/components/ShortDate.jsx new file mode 100644 index 00000000..404dd52d --- /dev/null +++ b/src/features/date/components/ShortDate.jsx @@ -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}`}; +}; diff --git a/src/features/date/components/WeekNumber.jsx b/src/features/date/components/WeekNumber.jsx new file mode 100644 index 00000000..f9a2d99d --- /dev/null +++ b/src/features/date/components/WeekNumber.jsx @@ -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 ( + + {variables.getMessage('widgets.date.week')} {weekNumber} + + ); +}; diff --git a/src/features/time/date.scss b/src/features/date/date.scss similarity index 100% rename from src/features/time/date.scss rename to src/features/date/date.scss diff --git a/src/features/date/index.jsx b/src/features/date/index.jsx new file mode 100644 index 00000000..5f30ef38 --- /dev/null +++ b/src/features/date/index.jsx @@ -0,0 +1 @@ +export * from './options'; diff --git a/src/features/time/options/DateOptions.jsx b/src/features/date/options/DateOptions.jsx similarity index 97% rename from src/features/time/options/DateOptions.jsx rename to src/features/date/options/DateOptions.jsx index b79cdf4a..46816e62 100644 --- a/src/features/time/options/DateOptions.jsx +++ b/src/features/date/options/DateOptions.jsx @@ -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 = ( diff --git a/src/features/date/options/default.js b/src/features/date/options/default.js new file mode 100644 index 00000000..b65cdf7d --- /dev/null +++ b/src/features/date/options/default.js @@ -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; diff --git a/src/features/date/options/index.jsx b/src/features/date/options/index.jsx new file mode 100644 index 00000000..b844d1c4 --- /dev/null +++ b/src/features/date/options/index.jsx @@ -0,0 +1 @@ +export * from './DateOptions'; diff --git a/src/features/misc/views/Settings.jsx b/src/features/misc/views/Settings.jsx index 08827963..4a219c87 100644 --- a/src/features/misc/views/Settings.jsx +++ b/src/features/misc/views/Settings.jsx @@ -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'; diff --git a/src/features/misc/views/Widgets.jsx b/src/features/misc/views/Widgets.jsx index 3b639fd9..18fec3fc 100644 --- a/src/features/misc/views/Widgets.jsx +++ b/src/features/misc/views/Widgets.jsx @@ -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'; diff --git a/src/features/quote/Quote.jsx b/src/features/quote/Quote.jsx index addda85c..a8cd2aef 100644 --- a/src/features/quote/Quote.jsx +++ b/src/features/quote/Quote.jsx @@ -434,7 +434,7 @@ class Quote extends PureComponent { modalClose={() => this.setState({ shareModal: false })} /> - + {this.state.quote} diff --git a/src/features/quote/options/QuoteOptions.jsx b/src/features/quote/options/QuoteOptions.jsx index 19500df3..00a4e9e8 100644 --- a/src/features/quote/options/QuoteOptions.jsx +++ b/src/features/quote/options/QuoteOptions.jsx @@ -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 ( +
+ "The best way to predict the future is to invent it." +
+
+
+ +
+
+ Alan Kay + Computer Scientist +
+
+ + + +
+
+
+
+ ); +}; + const QuoteOptions = () => { const [quoteType, setQuoteType] = useState( localStorage.getItem('quoteType') || defaults.quoteType, @@ -108,24 +132,11 @@ const QuoteOptions = () => { return ( <> - {/* {subSection === 'source' ? ( -
- ) : ( -
- )} */} {subSection === '' && ( + + + { > - + + + diff --git a/src/features/quote/quote.scss b/src/features/quote/quote.scss index 42c99246..9ccb1479 100644 --- a/src/features/quote/quote.scss +++ b/src/features/quote/quote.scss @@ -10,7 +10,6 @@ color: #fff; font-weight: 600; - width: 40vw; } .quoteauthor { diff --git a/src/features/time/Date.jsx b/src/features/time/Date.jsx deleted file mode 100644 index ad284bb3..00000000 --- a/src/features/time/Date.jsx +++ /dev/null @@ -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 ( -
- {date} - {weekNumber} -
- ); -}; - -export { DateWidget as default, DateWidget }; diff --git a/src/features/time/options/default.js b/src/features/time/options/default.js index 4d979cb2..cf73d3d3 100644 --- a/src/features/time/options/default.js +++ b/src/features/time/options/default.js @@ -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; diff --git a/src/features/time/options/index.jsx b/src/features/time/options/index.jsx index 12c65064..dad2d727 100644 --- a/src/features/time/options/index.jsx +++ b/src/features/time/options/index.jsx @@ -1,2 +1 @@ export * from './TimeOptions'; -export * from './DateOptions';