feat: exclude modal, various fixes

Co-authored-by: Alex Sparkes <alexsparkes@gmail.com>
This commit is contained in:
David Ralph 2023-03-11 19:03:55 +00:00
parent 76f5bff3dd
commit 510dc1c023
29 changed files with 2953 additions and 2844 deletions

View File

@ -12,39 +12,39 @@
"version": "7.0.0",
"dependencies": {
"@eartharoid/i18n": "1.2.1",
"@emotion/react": "^11.10.5",
"@emotion/styled": "^11.10.5",
"@floating-ui/react-dom": "^1.0.1",
"@fontsource/lexend-deca": "4.5.12",
"@fontsource/montserrat": "4.5.13",
"@emotion/react": "^11.10.6",
"@emotion/styled": "^11.10.6",
"@floating-ui/react-dom": "^1.3.0",
"@fontsource/lexend-deca": "4.5.14",
"@fontsource/montserrat": "4.5.14",
"@mui/material": "5.11.12",
"@sentry/react": "^7.21.1",
"embla-carousel-autoplay": "^7.0.5",
"embla-carousel-react": "^7.0.5",
"@sentry/react": "^7.42.0",
"embla-carousel-autoplay": "^7.1.0",
"embla-carousel-react": "^7.1.0",
"fast-blurhash": "^1.1.2",
"image-conversion": "^2.1.1",
"react": "^18.2.0",
"react-clock": "4.1.0",
"react-color-gradient-picker": "0.1.2",
"react-dom": "^18.2.0",
"react-icons": "^4.6.0",
"react-icons": "^4.8.0",
"react-modal": "3.16.1",
"react-sortable-hoc": "2.0.0",
"react-toastify": "9.1.1"
},
"devDependencies": {
"@commitlint/cli": "^17.3.0",
"@commitlint/config-conventional": "^17.3.0",
"@commitlint/cli": "^17.4.4",
"@commitlint/config-conventional": "^17.4.4",
"@eartharoid/deep-merge": "^0.0.2",
"@vitejs/plugin-react": "3.1.0",
"eslint": "^8.30.0",
"eslint": "^8.36.0",
"eslint-config-react-app": "^7.0.1",
"husky": "^8.0.2",
"prettier": "^2.8.1",
"sass": "^1.57.1",
"stylelint": "^15.0.0",
"husky": "^8.0.3",
"prettier": "^2.8.4",
"sass": "^1.59.2",
"stylelint": "^15.2.0",
"stylelint-config-prettier-scss": "^0.0.1",
"stylelint-config-standard-scss": "^7.0.0",
"stylelint-config-standard-scss": "^7.0.1",
"vite": "4.1.4"
},
"scripts": {

View File

@ -25,7 +25,7 @@ specifiers:
react-clock: 4.1.0
react-color-gradient-picker: 0.1.2
react-dom: ^18.2.0
react-icons: ^4.6.0
react-icons: ^4.8.0
react-modal: 3.16.1
react-sortable-hoc: 2.0.0
react-toastify: 9.1.1
@ -52,7 +52,7 @@ dependencies:
react-clock: 4.1.0_biqbaboplfbrettd7655fr4n2y
react-color-gradient-picker: 0.1.2_biqbaboplfbrettd7655fr4n2y
react-dom: 18.2.0_react@18.2.0
react-icons: 4.7.1_react@18.2.0
react-icons: 4.8.0_react@18.2.0
react-modal: 3.16.1_biqbaboplfbrettd7655fr4n2y
react-sortable-hoc: 2.0.0_biqbaboplfbrettd7655fr4n2y
react-toastify: 9.1.1_biqbaboplfbrettd7655fr4n2y
@ -4904,8 +4904,8 @@ packages:
scheduler: 0.23.0
dev: false
/react-icons/4.7.1_react@18.2.0:
resolution: {integrity: sha512-yHd3oKGMgm7zxo3EA7H2n7vxSoiGmHk5t6Ou4bXsfcgWyhfDKMpyKfhHR6Bjnn63c+YXBLBPUql9H4wPJM6sXw==}
/react-icons/4.8.0_react@18.2.0:
resolution: {integrity: sha512-N6+kOLcihDiAnj5Czu637waJqSnwlMNROzVZMhfX68V/9bu9qHaMIJC4UdozWoOk57gahFCNHwVvWzm0MTzRjg==}
peerDependencies:
react: '*'
dependencies:

View File

@ -273,6 +273,7 @@
flex-flow: column;
text-align: center;
align-items: center;
user-select: none;
img {
width: 200px;

View File

@ -230,3 +230,7 @@ h4 {
font-size: 15px;
}
}
.customcss {
color: orange !important;
}

View File

@ -102,7 +102,7 @@ export default class AdvancedSettings extends PureComponent {
'modals.main.settings.sections.advanced.custom_css_subtitle',
)}
>
<Text name="customcss" textarea={true} category="other" />
<Text name="customcss" textarea={true} category="other" />
</SettingsItem>
<SettingsItem
title={variables.getMessage('modals.main.settings.sections.experimental.title')}

View File

@ -231,7 +231,7 @@ export default class QuickLinks extends PureComponent {
<Dropdown
label={variables.getMessage('modals.main.settings.sections.quicklinks.style')}
name="quickLinksStyle"
category="other"
category="quicklinks"
>
<option value="icon">
{variables.getMessage('modals.main.settings.sections.quicklinks.options.icon')}

View File

@ -1,6 +1,6 @@
import { memo } from 'react';
import { FaDiscord, FaTwitter } from 'react-icons/fa';
import { SiKofi, SiPatreon } from 'react-icons/si';
import { SiGithubsponsors, SiOpencollective } from 'react-icons/si';
function QuicklinksSkeleton() {
return (
@ -13,10 +13,10 @@ function QuicklinksSkeleton() {
<FaTwitter />
</div>
<div>
<SiKofi />
<SiGithubsponsors />
</div>
<div>
<SiPatreon />
<SiOpencollective />
</div>
</div>
</div>

View File

@ -137,6 +137,10 @@ function Tab({ label, currentTab, onClick, navbarTab }) {
icon = <Collections />;
break;
case variables.getMessage('modals.main.loading'):
mue = true;
break;
default:
break;
}

View File

@ -0,0 +1,49 @@
import variables from 'modules/variables';
import { memo } from 'react';
import EventBus from 'modules/helpers/eventbus';
import Tooltip from 'components/helpers/tooltip/Tooltip';
import { MdClose, MdDone } from 'react-icons/md';
function ExcludeModal({ modalClose, info }) {
const excludeImage = async () => {
let backgroundExclude = JSON.parse(localStorage.getItem('backgroundExclude'));
backgroundExclude.push(info.pun);
backgroundExclude = JSON.stringify(backgroundExclude);
localStorage.setItem('backgroundExclude', backgroundExclude);
EventBus.dispatch('refresh', 'background');
modalClose();
};
return (
<div className="smallModal">
<div className="shareHeader">
<span className="title">
{variables.getMessage('modals.main.settings.sections.advanced.reset_modal.title')}
</span>
<Tooltip
title={variables.getMessage('modals.main.settings.sections.advanced.reset_modal.cancel')}
>
<div className="close" onClick={modalClose}>
<MdClose />
</div>
</Tooltip>
</div>
<span className="subtitle">
{ variables.getMessage('widgets.background.exclude_confirm', { category: info.category })}
</span>
<div className="resetFooter">
<button className="textButton" onClick={modalClose}>
<MdClose />
{variables.getMessage('modals.main.settings.sections.advanced.reset_modal.cancel')}
</button>
<button onClick={() => excludeImage()}>
<MdDone />
{variables.getMessage('widgets.background.confirm')}
</button>
</div>
</div>
)
}
export default memo(ExcludeModal);

View File

@ -1,7 +1,6 @@
import variables from 'modules/variables';
import { useState, memo } from 'react';
import Favourite from './Favourite';
import EventBus from 'modules/helpers/eventbus';
import {
MdInfo,
MdLocationOn,
@ -18,6 +17,7 @@ import {
import Tooltip from '../../helpers/tooltip/Tooltip';
import Modal from 'react-modal';
import ShareModal from '../../helpers/sharemodal/ShareModal';
import ExcludeModal from './ExcludeModal';
const toDataURL = async (url) => {
const res = await fetch(url);
@ -38,19 +38,6 @@ const downloadImage = async (info) => {
variables.stats.postEvent('feature', 'Background download');
};
const excludeImage = async (info) => {
// eslint-disable-next-line no-restricted-globals
const confirmed = confirm(
variables.getMessage('widgets.background.exclude_confirm', { category: info.category }),
);
if (!confirmed) return;
let backgroundExclude = JSON.parse(localStorage.getItem('backgroundExclude'));
backgroundExclude.push(info.pun);
backgroundExclude = JSON.stringify(backgroundExclude);
localStorage.setItem('backgroundExclude', backgroundExclude);
EventBus.dispatch('refresh', 'background');
};
function PhotoInformation({ info, url, api }) {
const [width, setWidth] = useState(0);
const [height, setHeight] = useState(0);
@ -60,6 +47,7 @@ function PhotoInformation({ info, url, api }) {
//const [showOld, setShowOld] = useState(true);
const [other, setOther] = useState(false);
const [shareModal, openShareModal] = useState(false);
const [excludeModal, openExcludeModal] = useState(false);
if (info.hidden === true || !info.credit) {
return null;
@ -194,6 +182,16 @@ function PhotoInformation({ info, url, api }) {
>
<ShareModal data={info.photoURL || info.url} modalClose={() => openShareModal(false)} />
</Modal>
<Modal
closeTimeoutMS={300}
isOpen={excludeModal}
className="Modal mainModal"
overlayClassName="Overlay"
ariaHideApp={false}
onRequestClose={() => openExcludeModal(false)}
>
<ExcludeModal info={info} modalClose={() => openExcludeModal(false)} />
</Modal>
{localStorage.getItem('widgetStyle') === 'legacy' && (
<div className="photoInformation-legacy">
<MdInfo />
@ -381,7 +379,7 @@ function PhotoInformation({ info, url, api }) {
key="exclude"
placement="top"
>
<VisibilityOff onClick={() => excludeImage(info)} />
<VisibilityOff onClick={() => openExcludeModal(true)} />
</Tooltip>
) : null}
</div>

View File

@ -6,24 +6,24 @@ import {
MdDelete,
MdPlaylistAdd,
MdOutlineDragIndicator,
MdOutlineTextsms,
MdAdd
MdPlaylistRemove,
} from 'react-icons/md';
import TextareaAutosize from '@mui/material/TextareaAutosize';
import Tooltip from '../../helpers/tooltip/Tooltip';
import Checkbox from '@mui/material/Checkbox';
import { shift, useFloating } from '@floating-ui/react-dom';
import { sortableContainer, sortableElement } from 'react-sortable-hoc';
import { sortableContainer, sortableElement, sortableHandle } from 'react-sortable-hoc';
import EventBus from 'modules/helpers/eventbus';
const SortableItem = sortableElement(({ value }) => <div>{value}</div>);
const SortableContainer = sortableContainer(({ children }) => <div>{children}</div>);
const SortableHandle = sortableHandle(() => <MdOutlineDragIndicator />);
class Todo extends PureComponent {
constructor() {
super();
this.state = {
todo: JSON.parse(localStorage.getItem('todoContent')) || [],
todo: JSON.parse(localStorage.getItem('todo')) || [],
visibility: localStorage.getItem('todoPinned') === 'true' ? 'visible' : 'hidden',
marginLeft: localStorage.getItem('refresh') === 'false' ? '-200px' : '-130px',
showTodo: localStorage.getItem('todoPinned') === 'true',
@ -162,55 +162,52 @@ class Todo extends PureComponent {
</div>
<div className={'todoRows'}>
{this.state.todo.length === 0 ? (
<div className="photosEmpty">
<div className="emptyNewMessage">
<MdOutlineTextsms />
<span className="title">
{variables.getMessage('modals.main.settings.sections.message.no_messages')}
</span>
<span className="subtitle">
{variables.getMessage('modals.main.settings.sections.message.add_some')}
</span>
<button onClick={() => this.modifyMessage('add')}>
{variables.getMessage('modals.main.settings.sections.message.add')}
<MdAdd />
</button>
</div>
</div>
) :
<SortableContainer
onSortEnd={this.onSortEnd}
lockAxis="y"
lockToContainerEdges
disableAutoscroll
>
{this.state.todo.map((_value, index) => (
<SortableItem
key={`item-${index}`}
index={index}
value={
<div
className={'todoRow' + (this.state.todo[index].done ? ' done' : '')}
key={index}
>
<Checkbox
checked={this.state.todo[index].done}
onClick={() => this.updateTodo('done', index)}
/>
<TextareaAutosize
placeholder={variables.getMessage('widgets.navbar.notes.placeholder')}
value={this.state.todo[index].value}
onChange={(data) => this.updateTodo('set', index, data)}
readOnly={this.state.todo[index].done}
/>
<MdDelete onClick={() => this.updateTodo('remove', index)} />
<MdOutlineDragIndicator />
</div>
}
/>
))}
</SortableContainer>
}
<div className="todosEmpty">
<div className="emptyNewMessage">
<MdPlaylistRemove />
<span className="title">
{variables.getMessage('widgets.navbar.todo.no_todos')}
</span>
<span className="subtitle">
{variables.getMessage('modals.main.settings.sections.message.add_some')}
</span>
</div>
</div>
) : (
<SortableContainer
onSortEnd={this.onSortEnd}
lockAxis="y"
lockToContainerEdges
disableAutoscroll
useDragHandle
>
{this.state.todo.map((_value, index) => (
<SortableItem
key={`item-${index}`}
index={index}
value={
<div
className={'todoRow' + (this.state.todo[index].done ? ' done' : '')}
key={index}
>
<Checkbox
checked={this.state.todo[index].done}
onClick={() => this.updateTodo('done', index)}
/>
<TextareaAutosize
placeholder={variables.getMessage('widgets.navbar.notes.placeholder')}
value={this.state.todo[index].value}
onChange={(data) => this.updateTodo('set', index, data)}
readOnly={this.state.todo[index].done}
/>
<MdDelete onClick={() => this.updateTodo('remove', index)} />
<SortableHandle/>
</div>
}
/>
))}
</SortableContainer>
)}
</div>
</div>
</span>

View File

@ -29,7 +29,6 @@
text-align: center;
border-radius: 12px;
position: absolute;
max-height: 80vh !important;
font-size: 1rem !important;
/*top: 100%;
left: 50%;
@ -95,6 +94,7 @@ textarea {
border-radius: 12px;
flex-flow: row;
gap: 5px;
user-select: none;
svg {
font-size: 1.5rem;

View File

@ -8,12 +8,17 @@
.todoRows {
max-height: 65vh !important;
overflow-y: visible !important;
overflow-x: hidden;
display: flex;
flex-flow: column;
gap: 15px;
overflow-x: hidden;
}
}
.todosEmpty {
height: 200px;
display: grid;
place-items: center;
}
}
.todoRow {
@ -21,9 +26,7 @@
display: flex;
flex-flow: row;
align-items: center;
padding-right: 10px;
margin: 10px 0 10px 0;
margin: 15px 5px 15px 5px;
@include themed() {
color: t($color) !important;
}

View File

@ -1,6 +1,9 @@
import variables from 'modules/variables';
import { PureComponent, createRef } from 'react';
import { MdSearch, MdMic, MdScreenSearchDesktop } from 'react-icons/md';
import { BsGoogle } from 'react-icons/bs';
import { SiDuckduckgo, SiMicrosoftbing, SiYahoo, SiBaidu } from 'react-icons/si';
import { FaYandex } from 'react-icons/fa';
import Tooltip from 'components/helpers/tooltip/Tooltip';
import AutocompleteInput from 'components/helpers/autocomplete/Autocomplete';
@ -130,6 +133,8 @@ export default class Search extends PureComponent {
} else {
url = this.state.url;
}
} else {
localStorage.setItem('searchEngine', info.settingsName);
}
this.setState({
@ -161,6 +166,26 @@ export default class Search extends PureComponent {
EventBus.off('refresh');
}
getSearchDropdownicon(name) {
switch (name) {
case 'Google':
return <BsGoogle />;
case 'DuckDuckGo':
return <SiDuckduckgo />;
case 'Bing':
return <SiMicrosoftbing />;
case 'Yahoo':
case 'Yahoo! JAPAN':
return <SiYahoo />;
case 'Яндекс':
return <FaYandex />;
case '百度':
return <SiBaidu />;
default:
return <MdScreenSearchDesktop />;
}
}
render() {
const customText = variables
.getMessage('modals.main.settings.sections.search.custom')
@ -175,7 +200,7 @@ export default class Search extends PureComponent {
<button
onClick={() => this.setState({ searchDropdown: !this.state.searchDropdown })}
>
<MdScreenSearchDesktop />
{this.getSearchDropdownicon(this.state.currentSearch)}
</button>
</Tooltip>
) : (
@ -207,13 +232,9 @@ export default class Search extends PureComponent {
this.state.searchDropdown === true ? (
<div className="searchDropdown">
{searchEngines.map(({ name }, key) => {
if (name === this.state.currentSearch) {
return null;
}
return (
<span
className="searchDropdownList"
className={"searchDropdownList" + (this.state.currentSearch === name ? " searchDropdownListActive" : "")}
onClick={() => this.setSearch(name)}
key={key}
>
@ -221,14 +242,12 @@ export default class Search extends PureComponent {
</span>
);
})}
{this.state.currentSearch !== customText ? (
<span
className="searchDropdownList"
className={"searchDropdownList" + (this.state.currentSearch === customText ? " searchDropdownListActive" : "")}
onClick={() => this.setSearch(customText, 'custom')}
>
{customText}
</span>
) : null}
</div>
) : null}
</div>

View File

@ -68,6 +68,12 @@
}
}
.searchDropdownListActive {
@include themed() {
background: t($btn-backgroundHover);
}
}
.searchMain {
display: flex;
flex-flow: row;

View File

@ -25,7 +25,8 @@
"source": "Source",
"category": "Category",
"exclude": "Don't show again",
"exclude_confirm": "Are you sure you don't want to see this image again?\nNote: if you don't like \"{category}\" images, you can deselect the category in the background source settings."
"exclude_confirm": "Are you sure you don't want to see this image again?\nNote: if you don't like \"{category}\" images, you can deselect the category in the background source settings.",
"confirm": "Confirm"
},
"search": "Suche",
"quicklinks": {
@ -64,7 +65,8 @@
"todo": {
"title": "Todo",
"pin": "Pin",
"add": "Add"
"add": "Add",
"no_todos": "No Todos"
}
}
},

View File

@ -25,7 +25,8 @@
"source": "Source",
"category": "Category",
"exclude": "Don't show again",
"exclude_confirm": "Are you sure you don't want to see this image again?\nNote: if you don't like \"{category}\" images, you can deselect the category in the background source settings."
"exclude_confirm": "Are you sure you don't want to see this image again?\nNote: if you don't like \"{category}\" images, you can deselect the category in the background source settings.",
"confirm": "Confirm"
},
"search": "Search",
"quicklinks": {
@ -64,7 +65,8 @@
"todo": {
"title": "Todo",
"pin": "Pin",
"add": "Add"
"add": "Add",
"no_todos": "No Todos"
}
}
},

View File

@ -25,7 +25,8 @@
"source": "Source",
"category": "Category",
"exclude": "Don't show again",
"exclude_confirm": "Are you sure you don't want to see this image again?\nNote: if you don't like \"{category}\" images, you can deselect the category in the background source settings."
"exclude_confirm": "Are you sure you don't want to see this image again?\nNote: if you don't like \"{category}\" images, you can deselect the category in the background source settings.",
"confirm": "Confirm"
},
"search": "Search",
"quicklinks": {
@ -64,7 +65,8 @@
"todo": {
"title": "Todo",
"pin": "Pin",
"add": "Add"
"add": "Add",
"no_todos": "No Todos"
}
}
},

View File

@ -25,7 +25,8 @@
"source": "Source",
"category": "Category",
"exclude": "Don't show again",
"exclude_confirm": "Are you sure you don't want to see this image again?\nNote: if you don't like \"{category}\" images, you can deselect the category in the background source settings."
"exclude_confirm": "Are you sure you don't want to see this image again?\nNote: if you don't like \"{category}\" images, you can deselect the category in the background source settings.",
"confirm": "Confirm"
},
"search": "Buscar",
"quicklinks": {
@ -64,7 +65,8 @@
"todo": {
"title": "Todo",
"pin": "Pin",
"add": "Add"
"add": "Add",
"no_todos": "No Todos"
}
}
},

File diff suppressed because it is too large Load Diff

View File

@ -25,7 +25,8 @@
"source": "Source",
"category": "Category",
"exclude": "Don't show again",
"exclude_confirm": "Are you sure you don't want to see this image again?\nNote: if you don't like \"{category}\" images, you can deselect the category in the background source settings."
"exclude_confirm": "Are you sure you don't want to see this image again?\nNote: if you don't like \"{category}\" images, you can deselect the category in the background source settings.",
"confirm": "Confirm"
},
"search": "Rechercher",
"quicklinks": {
@ -64,7 +65,8 @@
"todo": {
"title": "Todo",
"pin": "Pin",
"add": "Add"
"add": "Add",
"no_todos": "No Todos"
}
}
},

View File

@ -25,7 +25,8 @@
"source": "Source",
"category": "Category",
"exclude": "Don't show again",
"exclude_confirm": "Are you sure you don't want to see this image again?\nNote: if you don't like \"{category}\" images, you can deselect the category in the background source settings."
"exclude_confirm": "Are you sure you don't want to see this image again?\nNote: if you don't like \"{category}\" images, you can deselect the category in the background source settings.",
"confirm": "Confirm"
},
"search": "Cari",
"quicklinks": {
@ -64,7 +65,8 @@
"todo": {
"title": "Todo",
"pin": "Pin",
"add": "Add"
"add": "Add",
"no_todos": "No Todos"
}
}
},

View File

@ -25,7 +25,8 @@
"source": "Source",
"category": "Category",
"exclude": "Don't show again",
"exclude_confirm": "Are you sure you don't want to see this image again?\nNote: if you don't like \"{category}\" images, you can deselect the category in the background source settings."
"exclude_confirm": "Are you sure you don't want to see this image again?\nNote: if you don't like \"{category}\" images, you can deselect the category in the background source settings.",
"confirm": "Confirm"
},
"search": "Zoeken",
"quicklinks": {
@ -64,7 +65,8 @@
"todo": {
"title": "Todo",
"pin": "Pin",
"add": "Add"
"add": "Add",
"no_todos": "No Todos"
}
}
},

View File

@ -25,7 +25,8 @@
"source": "Source",
"category": "Category",
"exclude": "Don't show again",
"exclude_confirm": "Are you sure you don't want to see this image again?\nNote: if you don't like \"{category}\" images, you can deselect the category in the background source settings."
"exclude_confirm": "Are you sure you don't want to see this image again?\nNote: if you don't like \"{category}\" images, you can deselect the category in the background source settings.",
"confirm": "Confirm"
},
"search": "Søk",
"quicklinks": {
@ -64,7 +65,8 @@
"todo": {
"title": "Todo",
"pin": "Pin",
"add": "Add"
"add": "Add",
"no_todos": "No Todos"
}
}
},

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -25,7 +25,8 @@
"source": "Source",
"category": "Category",
"exclude": "Don't show again",
"exclude_confirm": "Are you sure you don't want to see this image again?\nNote: if you don't like \"{category}\" images, you can deselect the category in the background source settings."
"exclude_confirm": "Are you sure you don't want to see this image again?\nNote: if you don't like \"{category}\" images, you can deselect the category in the background source settings.",
"confirm": "Confirm"
},
"search": "Поиск",
"quicklinks": {
@ -64,7 +65,8 @@
"todo": {
"title": "Todo",
"pin": "Pin",
"add": "Add"
"add": "Add",
"no_todos": "No Todos"
}
}
},

File diff suppressed because it is too large Load Diff

View File

@ -25,7 +25,8 @@
"source": "Source",
"category": "Category",
"exclude": "Don't show again",
"exclude_confirm": "Are you sure you don't want to see this image again?\nNote: if you don't like \"{category}\" images, you can deselect the category in the background source settings."
"exclude_confirm": "Are you sure you don't want to see this image again?\nNote: if you don't like \"{category}\" images, you can deselect the category in the background source settings.",
"confirm": "Confirm"
},
"search": "搜索",
"quicklinks": {
@ -64,7 +65,8 @@
"todo": {
"title": "Todo",
"pin": "Pin",
"add": "Add"
"add": "Add",
"no_todos": "No Todos"
}
}
},