perf: major widget refactoring

This commit is contained in:
David Ralph
2022-10-30 16:43:08 +00:00
parent d762a7c504
commit a9276a5fdb
15 changed files with 236 additions and 395 deletions

View File

@@ -55,7 +55,7 @@ export default class Autocomplete extends PureComponent {
});
}
componentWillUmount() {
componentWillUnmount() {
EventBus.off('refresh');
}

View File

@@ -30,7 +30,6 @@ const renderLoader = (current) => (
);
export default function MainModal({ modalClose }) {
const display = localStorage.getItem('showReminder') === 'true' ? 'flex' : 'none';
const [currentTab, setCurrentTab] = useState(0);
const changeTab = (type) => {

View File

@@ -1,5 +1,5 @@
import variables from 'modules/variables';
import { PureComponent, createRef } from 'react';
import { PureComponent } from 'react';
import { MdUpdate, MdOutlineExtensionOff, MdCode } from 'react-icons/md';
import { toast } from 'react-toastify';
import Modal from 'react-modal';

View File

@@ -26,8 +26,10 @@ export default class Tabs extends PureComponent {
};
render() {
const display = localStorage.getItem('showReminder') === 'true' ? 'flex' : 'none';
const reminderInfo = (
<div className="reminder-info" style={{ display: 'none' }}>
<div className="reminder-info" style={{ display }}>
<span className="title">{variables.getMessage('modals.main.settings.reminder.title')}</span>
<span className="subtitle">
{variables.getMessage('modals.main.settings.reminder.message')}

View File

@@ -66,6 +66,10 @@ export default class Widgets extends PureComponent {
});
}
componentWillUnmount() {
EventBus.off('refresh');
}
render() {
// don't show when welcome is there
return this.state.welcome !== 'false' ? (

View File

@@ -119,25 +119,6 @@ export default function PhotoInformation({ info, url, api }) {
);
}
/*const downloadEnabled =
localStorage.getItem('downloadbtn') === 'true' && !info.offline && !info.photographerURL && api;
const downloadBackground = () => {
if (downloadEnabled) {
downloadImage(info);
}
};
const showBackgroundInformation = () => {
const element = document.querySelector('.infoCard');
if (element) {
if (element.style.display === 'none' || element.style.display === '') {
element.style.display = 'block';
} else {
element.style.display = 'none';
}
}
};*/
let showingPhotoMap = false;
const photoMap = () => {
if (

View File

@@ -28,20 +28,23 @@ export default class Message extends PureComponent {
});
const messages = JSON.parse(localStorage.getItem('messages')) || [];
if (messages.length === 0) {
return (this.message.current.style.display = 'none');
}
this.message.current.style.fontSize = `${
1 * Number((localStorage.getItem('zoomMessage') || 100) / 100)
}em`;
if (messages.length === 0) {
return (this.message.current.style.display = 'none');
}
this.setState({
messageText: messages[Math.floor(Math.random() * messages.length)],
});
}
componentWillUnmount() {
EventBus.off('refresh');
}
render() {
return (
<h2 className="message" ref={this.message}>

View File

@@ -15,11 +15,11 @@ export default class Navbar extends PureComponent {
constructor() {
super();
this.navbarContainer = createRef();
this.refreshEnabled = localStorage.getItem('refresh');
this.refreshValue = localStorage.getItem('refreshOption');
this.state = {
classList: localStorage.getItem('widgetStyle') === 'legacy' ? 'navbar old' : 'navbar new',
refreshText: '',
refreshEnabled: localStorage.getItem('refresh'),
refreshOption: localStorage.getItem('refreshOption') || ''
};
}
@@ -29,46 +29,57 @@ export default class Navbar extends PureComponent {
});
}
updateRefreshText() {
let refreshText;
switch (localStorage.getItem('refreshOption')) {
case 'background':
refreshText = variables.getMessage('modals.main.settings.sections.background.title');
break;
case 'quote':
refreshText = variables.getMessage('modals.main.settings.sections.quote.title');
break;
case 'quotebackground':
refreshText =
variables.getMessage('modals.main.settings.sections.quote.title') +
' ' +
variables.getMessage('modals.main.settings.sections.background.title');
break;
default:
refreshText = variables.getMessage(
'modals.main.settings.sections.appearance.navbar.refresh_options.page',
);
break;
}
this.setState({
refreshText,
});
}
componentDidMount() {
EventBus.on('refresh', (data) => {
if (data === 'navbar' || data === 'background') {
this.refreshEnabled = localStorage.getItem('refresh');
this.refreshValue = localStorage.getItem('refreshOption');
this.forceUpdate();
this.setState({
refreshEnabled: localStorage.getItem('refresh'),
refreshOption: localStorage.getItem('refreshOption')
});
try {
this.updateRefreshText();
this.setZoom();
} catch (e) {}
}
});
if (localStorage.getItem('refreshOption') === 'background') {
this.setState({
refreshText: variables.getMessage('modals.main.settings.sections.background.title'),
});
} else if (localStorage.getItem('refreshOption') === 'quote') {
this.setState({
refreshText: variables.getMessage('modals.main.settings.sections.quote.title'),
});
} else if (localStorage.getItem('refreshOption') === 'quotebackground') {
this.setState({
refreshText:
variables.getMessage('modals.main.settings.sections.quote.title') +
' ' +
variables.getMessage('modals.main.settings.sections.background.title'),
});
} else {
this.setState({
refreshText: variables.getMessage(
'modals.main.settings.sections.appearance.navbar.refresh_options.page',
),
});
}
this.updateRefreshText();
this.setZoom();
}
componentWillUnmount() {
EventBus.off('refresh');
}
refresh() {
switch (this.refreshValue) {
switch (this.state.refreshOption) {
case 'background':
return EventBus.dispatch('refresh', 'backgroundrefresh');
case 'quote':

View File

@@ -26,7 +26,7 @@ class Notes extends PureComponent {
componentDidMount() {
EventBus.on('refresh', (data) => {
if (data === 'navbar' || data === 'background') {
if (data === 'navbar') {
this.forceUpdate();
try {
this.setZoom();
@@ -37,6 +37,10 @@ class Notes extends PureComponent {
this.setZoom();
}
componentWillUnmount() {
EventBus.off('refresh');
}
setNotes = (e) => {
localStorage.setItem('notes', e.target.value);
this.setState({
@@ -140,7 +144,7 @@ class Notes extends PureComponent {
}
}
export default function NotesWrapper(props) {
export default function NotesWrapper() {
const { x, y, reference, floating, strategy } = useFloating({
placement: 'bottom',
middleware: [shift()],

View File

@@ -36,12 +36,12 @@ class Todo extends PureComponent {
setZoom() {
this.setState({
zoomFontSize: Number(((localStorage.getItem('zoomNavbar') || 100) / 100) * 1.2) + "rem"
})
});
}
componentDidMount() {
EventBus.on('refresh', (data) => {
if (data === 'navbar' || data === 'background') {
if (data === 'navbar') {
this.forceUpdate();
try {
this.setZoom();
@@ -52,6 +52,10 @@ class Todo extends PureComponent {
this.setZoom();
}
componentWillUnmount() {
EventBus.off('refresh');
}
arrayMove(array, oldIndex, newIndex) {
const result = Array.from(array);
const [removed] = result.splice(oldIndex, 1);
@@ -79,56 +83,50 @@ class Todo extends PureComponent {
}
updateTodo(action, index, data) {
let todoContent = this.state.todo;
let todo = this.state.todo;
switch (action) {
case 'add':
todoContent.push({
todo.push({
value: '',
done: false,
});
break;
case 'remove':
todoContent.splice(index, 1);
if (todoContent.length === 0) {
todoContent.push({
todo.splice(index, 1);
if (todo.length === 0) {
todo.push({
value: '',
done: false,
});
}
break;
case 'set':
todoContent[index] = {
todo[index] = {
value: data.target.value,
done: todoContent[index].done,
done: todo[index].done,
};
break;
case 'done':
todoContent[index].done = !todoContent[index].done;
todo[index].done = !todo[index].done;
break;
default:
break;
}
localStorage.setItem('todoContent', JSON.stringify(todoContent));
localStorage.setItem('todo', JSON.stringify(todo));
this.setState({
todo: todoContent,
todo,
});
this.forceUpdate();
}
pin() {
variables.stats.postEvent('feature', 'Todo pin');
if (localStorage.getItem('todoPinned') === 'true') {
localStorage.setItem('todoPinned', false);
this.setState({
showTodo: false,
});
} else {
localStorage.setItem('todoPinned', true);
this.setState({
showTodo: true,
});
}
const todoPinned = (localStorage.getItem('todoPinned') === 'true');
localStorage.setItem('todoPinned', !todoPinned);
this.setState({
showTodo: !todoPinned,
});
}
render() {

View File

@@ -1,10 +1,5 @@
import variables from 'modules/variables';
import { PureComponent, createRef } from 'react';
import { TextareaAutosize } from '@mui/material';
import { MdAddToPhotos } from 'react-icons/md';
import Tooltip from 'components/helpers/tooltip/Tooltip';
import EventBus from 'modules/helpers/eventbus';
import './quicklinks.scss';
@@ -14,98 +9,21 @@ export default class QuickLinks extends PureComponent {
super();
this.state = {
items: JSON.parse(localStorage.getItem('quicklinks')),
name: '',
url: '',
showAddLink: 'none',
nameError: '',
urlError: '',
};
this.quicklinksContainer = createRef();
}
deleteLink(key, event) {
event.preventDefault();
// remove link from array
const data = JSON.parse(localStorage.getItem('quicklinks')).filter((i) => i.key !== key);
localStorage.setItem('quicklinks', JSON.stringify(data));
this.setState({
items: data,
});
variables.stats.postEvent('feature', 'Quicklink delete');
}
addLink = () => {
const data = JSON.parse(localStorage.getItem('quicklinks'));
let url = this.state.url;
let urlError;
// regex: https://ihateregex.io/expr/url/
// eslint-disable-next-line no-useless-escape
if (
url.length <= 0 ||
/https?:\/\/(www\.)?[-a-zA-Z0-9@:%._~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()!@:%_.~#?&=]*)/.test(
url,
) === false
) {
urlError = variables.getMessage('widgets.quicklinks.url_error');
}
if (urlError) {
return this.setState({
urlError,
});
}
if (!url.startsWith('http://') && !url.startsWith('https://')) {
url = 'http://' + url;
}
data.push({
name: this.state.name || url,
url,
icon: this.state.icon || '',
key: Math.random().toString(36).substring(7) + 1,
});
localStorage.setItem('quicklinks', JSON.stringify(data));
this.setState({
items: data,
name: '',
url: '',
});
variables.stats.postEvent('feature', 'Quicklink add');
this.toggleAdd();
// make sure image is correct size
this.setZoom(this.quicklinksContainer.current);
};
toggleAdd = () => {
this.setState({
showAddLink: this.state.showAddLink === 'none' ? 'flex' : 'none',
});
};
// widget zoom
setZoom(element) {
const zoom = localStorage.getItem('zoomQuicklinks') || 100;
for (const link of element.getElementsByTagName('span')) {
link.style.fontSize = `${14 * Number(zoom / 100)}px`;
}
if (localStorage.getItem('quickLinksStyle') !== 'text') {
for (const link of element.getElementsByTagName('span')) {
link.style.fontSize = `${14 * Number(zoom / 100)}px`;
}
for (const img of element.getElementsByTagName('img')) {
img.style.height = `${30 * Number(zoom / 100)}px`;
}
} else {
for (const link of element.getElementsByTagName('span')) {
link.style.fontSize = `${14 * Number(zoom / 100)}px`;
}
}
}
@@ -128,16 +46,6 @@ export default class QuickLinks extends PureComponent {
this.setZoom(this.quicklinksContainer.current);
}
// allows you to add a link by pressing enter
topbarEnter = (e) => {
e = e || window.event;
const code = e.which || e.keyCode;
if (code === 13 && this.state.showAddLink === 'visible') {
this.addLink();
e.preventDefault();
}
};
componentWillUnmount() {
EventBus.off('refresh');
}
@@ -199,7 +107,7 @@ export default class QuickLinks extends PureComponent {
);
return tooltipEnabled === 'true' ? (
<Tooltip title={item.name} placement="bottom">
<Tooltip title={item.name} placement="bottom" key={item.key}>
{link}
</Tooltip>
) : (
@@ -208,44 +116,9 @@ export default class QuickLinks extends PureComponent {
};
return (
<>
<div className="quicklinkscontainer" ref={this.quicklinksContainer}>
{this.state.items.map((item) => quickLink(item))}
</div>
<div className="quicklinkscontainer">
<div
className="quicklinksdropdown"
onKeyDown={this.topbarEnter}
style={{ display: this.state.showAddLink }}
>
<span className="dropdown-title">{variables.getMessage('widgets.quicklinks.new')}</span>
<TextareaAutosize
maxRows={1}
placeholder={variables.getMessage('widgets.quicklinks.name')}
value={this.state.name}
onChange={(e) => this.setState({ name: e.target.value })}
/>
<span className="dropdown-error" />
<TextareaAutosize
maxRows={10}
placeholder={variables.getMessage('widgets.quicklinks.url')}
value={this.state.url}
onChange={(e) => this.setState({ url: e.target.value })}
/>
<span className="dropdown-error">{this.state.urlError}</span>
<TextareaAutosize
maxRows={10}
placeholder={variables.getMessage('widgets.quicklinks.icon')}
value={this.state.icon}
onChange={(e) => this.setState({ icon: e.target.value })}
/>
<span className="dropdown-error" />
<button onClick={this.addLink}>
<MdAddToPhotos /> {variables.getMessage('widgets.quicklinks.add')}
</button>
</div>
</div>
</>
<div className="quicklinkscontainer" ref={this.quicklinksContainer}>
{this.state.items.map((item) => quickLink(item))}
</div>
);
}
}

View File

@@ -359,6 +359,7 @@ export default class Quote extends PureComponent {
}
}
});
EventBus.on('refresh', (data) => {
if (data === 'quote') {
if (localStorage.getItem('quote') === 'false') {

View File

@@ -0,0 +1,109 @@
import { WiHumidity, WiWindy, WiBarometer, WiCloud } from 'react-icons/wi';
import { MdDisabledVisible } from 'react-icons/md';
import WeatherIcon from './WeatherIcon';
import WindDirectionIcon from './WindDirectionIcon';
import Tooltip from '../../helpers/tooltip/Tooltip';
export default function Expanded({ state, weatherType, variables }) {
const enabled = (setting) => {
return (localStorage.getItem(setting) === 'true' && weatherType >= 3) || weatherType === '3';
};
return (
<div className="expanded-info">
{weatherType >= 3 && (
<span className="subtitle">
{variables.getMessage('widgets.weather.extra_information')}
</span>
)}
{enabled('cloudiness') ? (
<Tooltip
title={variables.getMessage(
'modals.main.settings.sections.weather.extra_info.cloudiness',
)}
placement="left"
>
<span>
<WiCloud className="weatherIcon" />
{state.weather.cloudiness}%
</span>
</Tooltip>
) : null}
{enabled('windspeed') ? (
<Tooltip
title={variables.getMessage(
'modals.main.settings.sections.weather.extra_info.wind_speed',
)}
placement="left"
>
<span>
<WiWindy className="weatherIcon" />
{state.weather.wind_speed}
<span className="minmax"> m/s</span>{' '}
{enabled('windDirection') ? (
<WindDirectionIcon
className="weatherIcon"
degrees={state.weather.wind_degrees}
/>
) : null}
</span>
</Tooltip>
) : null}
{enabled('atmosphericpressure') ? (
<Tooltip
title={variables.getMessage(
'modals.main.settings.sections.weather.extra_info.atmospheric_pressure',
)}
placement="left"
>
<span>
<WiBarometer className="weatherIcon" />
{state.weather.pressure}
<span className="minmax"> hPa</span>
</span>
</Tooltip>
) : null}
{enabled('weatherdescription') ? (
<Tooltip
title={variables.getMessage(
'modals.main.settings.sections.weather.extra_info.show_description',
)}
placement="left"
>
<span>
<WeatherIcon className="weatherIcon" name={state.icon} />
{state.weather.description}
</span>
</Tooltip>
) : null}
{enabled('visibility') ? (
<Tooltip
title={variables.getMessage(
'modals.main.settings.sections.weather.extra_info.visibility',
)}
placement="left"
>
<span>
<MdDisabledVisible className="materialWeatherIcon" />
{variables.getMessage('widgets.weather.meters', {
amount: state.weather.visibility,
})}
</span>
</Tooltip>
) : null}
{enabled('humidity') ? (
<Tooltip
title={variables.getMessage('modals.main.settings.sections.weather.extra_info.humidity')}
placement="left"
>
<span>
<WiHumidity className="materialWeatherIcon" />
{state.weather.humidity}
</span>
</Tooltip>
) : null}
</div>
);
}

View File

@@ -1,12 +1,9 @@
import variables from 'modules/variables';
import { PureComponent } from 'react';
import { WiHumidity, WiWindy, WiBarometer, WiCloud } from 'react-icons/wi';
import { MdDisabledVisible } from 'react-icons/md';
import WeatherIcon from './WeatherIcon';
import WindDirectionIcon from './WindDirectionIcon';
import Expanded from './Expanded';
import Tooltip from '../../helpers/tooltip/Tooltip';
import EventBus from 'modules/helpers/eventbus';
import './weather.scss';
@@ -16,21 +13,7 @@ export default class Weather extends PureComponent {
super();
this.state = {
location: localStorage.getItem('location') || 'London',
icon: '',
temp_text: '',
weather: {
temp: '',
description: '',
temp_min: '',
temp_max: '',
temp_feels_like: '',
humidity: '',
wind_speed: '',
wind_degrees: '',
cloudiness: '',
visibility: '',
pressure: '',
},
done: false,
};
}
@@ -38,40 +21,17 @@ export default class Weather extends PureComponent {
const zoomWeather = `${Number((localStorage.getItem('zoomWeather') || 100) / 100)}em`;
document.querySelector('.weather').style.fontSize = zoomWeather;
let data = {
weather: [
{
description: this.state.weather.description,
icon: this.state.icon,
},
],
main: {
temp: this.state.weather.original_temp,
temp_min: this.state.weather.original_temp_min,
temp_max: this.state.weather.original_temp_max,
temp_feels_like: this.state.weather.original_temp_feels_like,
humidity: this.state.weather.humidity,
pressure: this.state.weather.pressure,
},
visibility: this.state.weather.visibility,
wind: {
speed: this.state.weather.wind_speed,
deg: this.state.weather.wind_degrees,
},
clouds: {
all: this.state.weather.cloudiness,
},
};
if (!this.state.weather.temp) {
data = await (
await fetch(
variables.constants.PROXY_URL +
`/weather/current?city=${this.state.location}&lang=${variables.languagecode}`,
)
).json();
if (this.state.done === true) {
return;
}
const data = await (
await fetch(
variables.constants.PROXY_URL +
`/weather/current?city=${this.state.location}&lang=${variables.languagecode}`,
)
).json();
if (data.cod === '404') {
return this.setState({
location: variables.getMessage('widgets.weather.not_found'),
@@ -84,24 +44,18 @@ export default class Weather extends PureComponent {
let temp_feels_like = data.main.temp_feels_like;
let temp_text = 'K';
switch (localStorage.getItem('tempformat')) {
case 'celsius':
temp -= 273.15;
temp_min -= 273.15;
temp_max -= 273.15;
temp_feels_like -= 273.15;
temp_text = '°C';
break;
case 'fahrenheit':
temp = (temp - 273.15) * 1.8 + 32;
temp_min = (temp_min - 273.15) * 1.8 + 32;
temp_max = (temp_max - 273.15) * 1.8 + 32;
temp_feels_like = (temp_feels_like - 273.15) * 1.8 + 32;
temp_text = '°F';
break;
// kelvin
default:
break;
if (localStorage.getItem('tempformat') === 'celsius') {
temp -= 273.15;
temp_min -= 273.15;
temp_max -= 273.15;
temp_feels_like -= 273.15;
temp_text = '°C';
} else {
temp = (temp - 273.15) * 1.8 + 32;
temp_min = (temp_min - 273.15) * 1.8 + 32;
temp_max = (temp_max - 273.15) * 1.8 + 32;
temp_feels_like = (temp_feels_like - 273.15) * 1.8 + 32;
temp_text = '°F';
}
this.setState({
@@ -118,12 +72,9 @@ export default class Weather extends PureComponent {
wind_degrees: data.wind.deg,
cloudiness: data.clouds.all,
visibility: data.visibility,
pressure: data.main.pressure,
original_temp: data.main.temp,
original_temp_min: data.main.temp_min,
original_temp_max: data.main.temp_max,
original_temp_feels_like: data.main.temp_feels_like,
pressure: data.main.pressure
},
done: true
});
document.querySelector('.weather svg').style.fontSize = zoomWeather;
@@ -144,10 +95,11 @@ export default class Weather extends PureComponent {
}
render() {
if (this.state.done === false) {
return <div className="weather"></div>;
}
const weatherType = localStorage.getItem('weatherType') || 1;
const enabled = (setting) => {
return (localStorage.getItem(setting) === 'true' && weatherType >= 3) || weatherType === '3';
};
if (this.state.location === variables.getMessage('weather.not_found')) {
return (
@@ -156,107 +108,7 @@ export default class Weather extends PureComponent {
</div>
);
}
const expandedInfo = () => {
return (
<div className="expanded-info">
{weatherType >= 3 && (
<span className="subtitle">
{variables.getMessage('widgets.weather.extra_information')}
</span>
)}
{enabled('cloudiness') ? (
<Tooltip
title={variables.getMessage(
'modals.main.settings.sections.weather.extra_info.cloudiness',
)}
placement="left"
>
<span>
<WiCloud className="weatherIcon" />
{this.state.weather.cloudiness}%
</span>
</Tooltip>
) : null}
{enabled('windspeed') ? (
<Tooltip
title={variables.getMessage(
'modals.main.settings.sections.weather.extra_info.wind_speed',
)}
placement="left"
>
<span>
<WiWindy className="weatherIcon" />
{this.state.weather.wind_speed}
<span className="minmax"> m/s</span>{' '}
{enabled('windDirection') ? (
<WindDirectionIcon
className="weatherIcon"
degrees={this.state.weather.wind_degrees}
/>
) : null}
</span>
</Tooltip>
) : null}
{enabled('atmosphericpressure') ? (
<Tooltip
title={variables.getMessage(
'modals.main.settings.sections.weather.extra_info.atmospheric_pressure',
)}
placement="left"
>
<span>
<WiBarometer className="weatherIcon" />
{this.state.weather.pressure}
<span className="minmax"> hPa</span>
</span>
</Tooltip>
) : null}
{enabled('weatherdescription') ? (
<Tooltip
title={variables.getMessage(
'modals.main.settings.sections.weather.extra_info.show_description',
)}
placement="left"
>
<span>
<WeatherIcon className="weatherIcon" name={this.state.icon} />
{this.state.weather.description}
</span>
</Tooltip>
) : null}
{enabled('visibility') ? (
<Tooltip
title={variables.getMessage(
'modals.main.settings.sections.weather.extra_info.visibility',
)}
placement="left"
>
<span>
<MdDisabledVisible className="materialWeatherIcon" />
{variables.getMessage('widgets.weather.meters', {
amount: this.state.weather.visibility,
})}
</span>
</Tooltip>
) : null}
{enabled('humidity') ? (
<Tooltip
title={variables.getMessage(
'modals.main.settings.sections.weather.extra_info.humidity',
)}
placement="left"
>
<span>
<WiHumidity className="materialWeatherIcon" />
{this.state.weather.humidity}
</span>
</Tooltip>
) : null}
</div>
);
};
return (
<div className="weather">
<div className="top-weather">
@@ -283,7 +135,7 @@ export default class Weather extends PureComponent {
<span className="loc">{this.state.location}</span>
</div>
)}
{weatherType >= 3 ? expandedInfo() : null}
{weatherType >= 3 ? <Expanded weatherType={weatherType} state={this.state} variables={variables}/> : null}
</div>
);
}