mirror of
https://github.com/mue/mue.git
synced 2026-07-16 13:34:03 +02:00
refactor(PhotoInformation): simplify state management and improve rendering logic
refactor(Widgets): optimize state initialization and event handling remove(Tabs): delete unused Tabs component
This commit is contained in:
@@ -1,86 +0,0 @@
|
||||
import variables from 'config/variables';
|
||||
import React, { useState, useEffect, useMemo } from 'react';
|
||||
import { motion } from 'framer-motion';
|
||||
import {
|
||||
MdSettings,
|
||||
MdOutlineShoppingBasket,
|
||||
MdOutlineExtension,
|
||||
MdRefresh,
|
||||
MdClose,
|
||||
} from 'react-icons/md';
|
||||
import Tab from './Tab';
|
||||
import { Button, Tooltip } from 'components/Elements';
|
||||
import ErrorBoundary from '../../../../features/misc/modals/ErrorBoundary';
|
||||
|
||||
const Tabs = (props) => {
|
||||
const [currentTab, setCurrentTab] = useState(props.children[0].props.label);
|
||||
const [currentName, setCurrentName] = useState(props.children[0].props.name);
|
||||
|
||||
const onClick = (tab, name) => {
|
||||
if (name !== currentName) {
|
||||
variables.stats.postEvent('tab', ${name}, 'opened');
|
||||
}
|
||||
setCurrentTab(tab);
|
||||
setCurrentName(name);
|
||||
props.setSubTab(name);
|
||||
};
|
||||
|
||||
const hideReminder = () => {
|
||||
localStorage.setItem('showReminder', false);
|
||||
document.querySelector('.reminder-info').style.display = 'none';
|
||||
};
|
||||
|
||||
const reminderInfo = useMemo(
|
||||
() => (
|
||||
<div
|
||||
className="reminder-info"
|
||||
style={{ display: localStorage.getItem('showReminder') === 'true' ? 'flex' : 'none' }}
|
||||
>
|
||||
<div className="shareHeader">
|
||||
<span className="title">{variables.getMessage('settings:reminder.title')}</span>
|
||||
<span className="closeModal" onClick={hideReminder}>
|
||||
<MdClose />
|
||||
</span>
|
||||
</div>
|
||||
<span className="subtitle">{variables.getMessage('settings:reminder.message')}</span>
|
||||
<button onClick={() => window.location.reload()}>
|
||||
<MdRefresh />
|
||||
{variables.getMessage('modals.main.error_boundary.refresh')}
|
||||
</button>
|
||||
</div>
|
||||
),
|
||||
[],
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
{props.current === 'settings' && (
|
||||
<div className="modalSidebar">
|
||||
{props.children.map((tab, index) => (
|
||||
<Tab
|
||||
currentTab={currentTab}
|
||||
key={index}
|
||||
label={tab.props.label}
|
||||
onClick={(nextTab) => onClick(nextTab, tab.props.name)}
|
||||
navbarTab={props.navbar || false}
|
||||
/>
|
||||
))}
|
||||
{reminderInfo}
|
||||
</div>
|
||||
)}
|
||||
<div className="w-full rounded h-[calc(78vh-80px)] bg-modal-content-light dark:bg-modal-content-dark p-10 flex flex-col overflow-scroll">
|
||||
{props.children.map((tab, index) => {
|
||||
if (tab.props.label !== currentTab) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<ErrorBoundary key={`error-boundary-${index}`}>{tab.props.children}</ErrorBoundary>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default React.memo(Tabs);
|
||||
@@ -12,9 +12,6 @@ function PhotoInformation({ info, url, api }) {
|
||||
const [width, setWidth] = useState(0);
|
||||
const [height, setHeight] = useState(0);
|
||||
const [usePhotoMap, setPhotoMap] = useState(false);
|
||||
const [useMapIcon, setMapIcon] = useState(true);
|
||||
const [showExtraInfo, setShowExtraInfo] = useState(false);
|
||||
const [other, setOther] = useState(false);
|
||||
const [shareModal, openShareModal] = useState(false);
|
||||
const [excludeModal, openExcludeModal] = useState(false);
|
||||
const [favouriteTooltipText, setFavouriteTooltipText] = useState(
|
||||
@@ -52,16 +49,6 @@ function PhotoInformation({ info, url, api }) {
|
||||
);
|
||||
}, [info.latitude, info.longitude, usePhotoMap]);
|
||||
|
||||
useEffect(() => {
|
||||
const photoInformationElement = document.getElementsByClassName('photoInformation')[0];
|
||||
if (photoInformationElement) {
|
||||
photoInformationElement.onmouseover = () => {
|
||||
setPhotoMap(true);
|
||||
setMapIcon(false);
|
||||
};
|
||||
}
|
||||
}, []);
|
||||
|
||||
if (info.hidden === true || !info.credit) {
|
||||
return null;
|
||||
}
|
||||
@@ -103,11 +90,7 @@ function PhotoInformation({ info, url, api }) {
|
||||
const widgetStyle = localStorage.getItem('widgetStyle');
|
||||
|
||||
return (
|
||||
<div
|
||||
className="photoInformationHolder"
|
||||
onMouseEnter={() => setOther(true)}
|
||||
onMouseLeave={() => setOther(false)}
|
||||
>
|
||||
<div className="photoInformationHolder">
|
||||
<Modal
|
||||
closeTimeoutMS={300}
|
||||
isOpen={shareModal}
|
||||
@@ -136,15 +119,13 @@ function PhotoInformation({ info, url, api }) {
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
{(widgetStyle !== 'legacy' || other) && (
|
||||
{widgetStyle !== 'legacy' && (
|
||||
<div
|
||||
className="photoInformation orHover"
|
||||
style={{ padding: widgetStyle === 'legacy' && '20px' }}
|
||||
onMouseEnter={() => setShowExtraInfo(true)}
|
||||
onMouseLeave={() => setShowExtraInfo(false)}
|
||||
>
|
||||
<div className={photoMapClassList}>
|
||||
{useMapIcon || photoMap() === null ? <MdLocationOn /> : ''}
|
||||
<MdLocationOn />
|
||||
{photoMap()}
|
||||
</div>
|
||||
{photoMap() && (
|
||||
@@ -179,16 +160,9 @@ function PhotoInformation({ info, url, api }) {
|
||||
)}
|
||||
<div className="photoInformation-content">
|
||||
<div className="photoInformation-text">
|
||||
<span
|
||||
className="title"
|
||||
title={
|
||||
(showExtraInfo || other) && info.description ? info.description : info.location
|
||||
}
|
||||
>
|
||||
{(showExtraInfo || other) && info.description
|
||||
? info.description.length > 40
|
||||
? `${info.description.substring(0, 40)}...`
|
||||
: info.description
|
||||
<span className="title" title={info.description || info.location}>
|
||||
{info.description?.length > 40
|
||||
? `${info.description.substring(0, 40)}...`
|
||||
: info.location?.split(',').slice(-2).join(', ').trim()}
|
||||
</span>
|
||||
<span className="subtitle" id="credit">
|
||||
@@ -197,21 +171,17 @@ function PhotoInformation({ info, url, api }) {
|
||||
</div>
|
||||
{info.views && info.downloads !== null && <UnsplashStats info={info} />}
|
||||
</div>
|
||||
{(showExtraInfo || other) && !excludeModal && (
|
||||
<>
|
||||
<span className="subtitle">
|
||||
{variables.getMessage('widgets.background.information')}
|
||||
</span>
|
||||
<InformationItems info={info} width={width} height={height} api={api} />
|
||||
<ActionButtons
|
||||
info={info}
|
||||
favouriteTooltipText={favouriteTooltipText}
|
||||
setFavouriteTooltipText={setFavouriteTooltipText}
|
||||
openShareModal={openShareModal}
|
||||
openExcludeModal={openExcludeModal}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
<span className="subtitle information-title">
|
||||
{variables.getMessage('widgets.background.information')}
|
||||
</span>
|
||||
<InformationItems info={info} width={width} height={height} api={api} />
|
||||
<ActionButtons
|
||||
info={info}
|
||||
favouriteTooltipText={favouriteTooltipText}
|
||||
setFavouriteTooltipText={setFavouriteTooltipText}
|
||||
openShareModal={openShareModal}
|
||||
openExcludeModal={openExcludeModal}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -244,12 +244,20 @@
|
||||
}
|
||||
}
|
||||
|
||||
.information-title {
|
||||
display: none;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
padding: 20px;
|
||||
height: auto;
|
||||
align-items: flex-start;
|
||||
flex-flow: column;
|
||||
|
||||
.information-title {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.buttons {
|
||||
padding: 30px 0 0;
|
||||
display: flex;
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { Fragment, Suspense, lazy, useState, useEffect } from 'react';
|
||||
|
||||
import { Fragment, Suspense, lazy, useState, useEffect, useCallback, useMemo } from 'react';
|
||||
import Clock from '../../time/Clock';
|
||||
import Greeting from '../../greeting/Greeting';
|
||||
import Quote from '../../quote/Quote';
|
||||
@@ -8,37 +7,35 @@ import QuickLinks from '../../quicklinks/QuickLinks';
|
||||
import Date from '../../time/Date';
|
||||
import Message from '../../message/Message';
|
||||
import { WidgetsLayout } from 'components/Layout';
|
||||
|
||||
import EventBus from 'utils/eventbus';
|
||||
import defaults from 'config/default';
|
||||
|
||||
// weather is lazy loaded due to the size of the weather icons module
|
||||
// since we're using react-icons this might not be accurate,
|
||||
// however, when we used the original module https://bundlephobia.com/package/weather-icons-react@1.2.0
|
||||
// as seen here it is ridiculously large
|
||||
const Weather = lazy(() => import('../../weather/Weather'));
|
||||
|
||||
export function Widgets() {
|
||||
const [order, setOrder] = useState(JSON.parse(localStorage.getItem('order')) || defaults.order);
|
||||
const [welcome, setWelcome] = useState(localStorage.getItem('showWelcome'));
|
||||
const Widgets = () => {
|
||||
const [order, setOrder] = useState(
|
||||
() => JSON.parse(localStorage.getItem('order')) || defaults.order,
|
||||
);
|
||||
const [welcome, setWelcome] = useState(() => localStorage.getItem('showWelcome'));
|
||||
const online = useMemo(() => localStorage.getItem('offlineMode') === 'false', []);
|
||||
|
||||
const online = localStorage.getItem('offlineMode') === 'false';
|
||||
const enabled = useCallback((key) => localStorage.getItem(key) !== 'false', []);
|
||||
|
||||
const widgets = {
|
||||
time: enabled('time') && <Clock />,
|
||||
greeting: enabled('greeting') && <Greeting />,
|
||||
quote: enabled('quote') && <Quote />,
|
||||
date: enabled('date') && <Date />,
|
||||
quicklinks: enabled('quicklinksenabled') && online ? <QuickLinks /> : null,
|
||||
message: enabled('message') && <Message />,
|
||||
};
|
||||
|
||||
function enabled(key) {
|
||||
return localStorage.getItem(key) !== 'false';
|
||||
}
|
||||
const widgets = useMemo(
|
||||
() => ({
|
||||
time: enabled('time') && <Clock />,
|
||||
greeting: enabled('greeting') && <Greeting />,
|
||||
quote: enabled('quote') && <Quote />,
|
||||
date: enabled('date') && <Date />,
|
||||
quicklinks: enabled('quicklinksenabled') && online ? <QuickLinks /> : null,
|
||||
message: enabled('message') && <Message />,
|
||||
}),
|
||||
[enabled, online],
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
EventBus.on('refresh', (data) => {
|
||||
const handleRefresh = (data) => {
|
||||
switch (data) {
|
||||
case 'widgets':
|
||||
setOrder(JSON.parse(localStorage.getItem('order')) || defaults.order);
|
||||
@@ -56,8 +53,10 @@ export function Widgets() {
|
||||
default:
|
||||
break;
|
||||
}
|
||||
});
|
||||
return () => EventBus.off('refresh');
|
||||
};
|
||||
|
||||
EventBus.on('refresh', handleRefresh);
|
||||
return () => EventBus.off('refresh', handleRefresh);
|
||||
}, []);
|
||||
|
||||
return welcome !== 'false' ? (
|
||||
@@ -73,6 +72,6 @@ export function Widgets() {
|
||||
</Suspense>
|
||||
</WidgetsLayout>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
export default Widgets;
|
||||
|
||||
Reference in New Issue
Block a user