mirror of
https://github.com/mue/mue.git
synced 2026-07-16 13:34:03 +02:00
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:
68
src/features/date/Date.jsx
Normal file
68
src/features/date/Date.jsx
Normal 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 };
|
||||
39
src/features/date/components/LongDate.jsx
Normal file
39
src/features/date/components/LongDate.jsx
Normal 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}`;
|
||||
};
|
||||
38
src/features/date/components/ShortDate.jsx
Normal file
38
src/features/date/components/ShortDate.jsx
Normal 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}`}</>;
|
||||
};
|
||||
24
src/features/date/components/WeekNumber.jsx
Normal file
24
src/features/date/components/WeekNumber.jsx
Normal 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>
|
||||
);
|
||||
};
|
||||
1
src/features/date/index.jsx
Normal file
1
src/features/date/index.jsx
Normal file
@@ -0,0 +1 @@
|
||||
export * from './options';
|
||||
@@ -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 = (
|
||||
14
src/features/date/options/default.js
Normal file
14
src/features/date/options/default.js
Normal 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;
|
||||
1
src/features/date/options/index.jsx
Normal file
1
src/features/date/options/index.jsx
Normal file
@@ -0,0 +1 @@
|
||||
export * from './DateOptions';
|
||||
@@ -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';
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -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>
|
||||
</>
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
|
||||
color: #fff;
|
||||
font-weight: 600;
|
||||
width: 40vw;
|
||||
}
|
||||
|
||||
.quoteauthor {
|
||||
|
||||
@@ -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 };
|
||||
@@ -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;
|
||||
|
||||
@@ -1,2 +1 @@
|
||||
export * from './TimeOptions';
|
||||
export * from './DateOptions';
|
||||
|
||||
Reference in New Issue
Block a user