mirror of https://github.com/mue/mue.git
feat: add work in progress 7.0 code
Co-authored-by: Alex Sparkes <turbomarshmello@gmail.com>
This commit is contained in:
parent
e0820c6b2a
commit
361fae7f25
|
@ -2,6 +2,7 @@
|
|||
node_modules/
|
||||
.vscode/
|
||||
build/
|
||||
.idea/
|
||||
|
||||
# Files
|
||||
package-lock.json
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
import { PureComponent } from 'react';
|
||||
|
||||
import { InputBase } from '@mui/material';
|
||||
|
||||
import EventBus from 'modules/helpers/eventbus';
|
||||
|
||||
import './autocomplete.scss';
|
||||
|
@ -53,7 +55,7 @@ export default class Autocomplete extends PureComponent {
|
|||
});
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
componentWillUmount() {
|
||||
EventBus.off('refresh');
|
||||
}
|
||||
|
||||
|
@ -63,21 +65,21 @@ export default class Autocomplete extends PureComponent {
|
|||
// length will only be > 0 if enabled
|
||||
if (this.state.filtered.length > 0 && this.state.input.length > 0) {
|
||||
autocomplete = (
|
||||
<ul className='suggestions'>
|
||||
<div className='suggestions'>
|
||||
{this.state.filtered.map((suggestion) => (
|
||||
<li key={suggestion} onClick={this.onClick}>
|
||||
<div key={suggestion} onClick={this.onClick}>
|
||||
{suggestion}
|
||||
</li>
|
||||
</div>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<input type='text' onChange={this.onChange} value={this.state.input} placeholder={this.props.placeholder || ''} autoComplete='off' id={this.props.id || ''} />
|
||||
<div style={{display: 'flex', flexFlow: 'column'}}>
|
||||
<input type='text' onChange={this.onChange} value={this.state.input} placeholder={this.props.placeholder || ''} autoComplete='off' spellCheck={false} id={this.props.id || ''} />
|
||||
{autocomplete}
|
||||
</>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,23 +1,19 @@
|
|||
@use 'scss/variables';
|
||||
|
||||
.suggestions {
|
||||
@extend %basic;
|
||||
text-align: left;
|
||||
font-size: calc(5px + 1.2vmin);
|
||||
background-color: rgba(255, 255, 255, 0.8);
|
||||
color: black;
|
||||
border-top-width: 0;
|
||||
list-style: none;
|
||||
margin-top: 40px;
|
||||
max-height: 143px;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
margin-left: 40px;
|
||||
border-radius: 24px;
|
||||
width: 430px;
|
||||
opacity: 0;
|
||||
opacity: 1;
|
||||
margin-top: 5px;
|
||||
|
||||
li {
|
||||
padding: 0.5rem;
|
||||
padding-left: 20px;
|
||||
div {
|
||||
padding: 0.5rem 0.5rem 0.5rem 20px;
|
||||
font-size: 0.6em;
|
||||
|
||||
&:hover {
|
||||
background-color: rgba(255, 255, 255, 0.8);
|
||||
|
@ -27,24 +23,18 @@
|
|||
}
|
||||
|
||||
.searchBar {
|
||||
input[type=text]:focus+.suggestions {
|
||||
input[type='text']:focus + .suggestions {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (min-width: 1400px) {
|
||||
.suggestions {
|
||||
margin-top: 50px;
|
||||
}
|
||||
}
|
||||
|
||||
.dark .suggestions {
|
||||
background-color: rgba(0, 0, 0, 0.5);
|
||||
background: rgba(0, 0, 0, 0.7);
|
||||
color: white;
|
||||
|
||||
li {
|
||||
&:hover {
|
||||
background-color: rgba(0, 0, 0, 0.5);
|
||||
background: rgba(0, 0, 0, 0.7);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import variables from 'modules/variables';
|
||||
|
||||
import { MdArrowForwardIos } from 'react-icons/md';
|
||||
import './preview.scss';
|
||||
|
||||
export default function Preview(props) {
|
||||
|
@ -7,9 +7,9 @@ export default function Preview(props) {
|
|||
|
||||
return (
|
||||
<div className='preview-mode'>
|
||||
<h1>{getMessage('modals.main.settings.reminder.title')}</h1>
|
||||
<p>{getMessage('modals.welcome.preview.description')}</p>
|
||||
<button className='pinNote' onClick={() => props.setup()}>{getMessage('modals.welcome.preview.continue')}</button>
|
||||
<span className='title'>{getMessage('modals.main.settings.reminder.title')}</span>
|
||||
<span className='subtitle'>{getMessage('modals.welcome.preview.description')}</span>
|
||||
<button onClick={() => props.setup()}>{getMessage('modals.welcome.preview.continue')}</button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,17 +1,22 @@
|
|||
@import 'scss/variables';
|
||||
|
||||
.preview-mode {
|
||||
@extend %basic;
|
||||
position: absolute;
|
||||
bottom: 20px;
|
||||
right: 20px;
|
||||
bottom: 1rem;
|
||||
right: 1rem;
|
||||
padding: 15px;
|
||||
color: var(--modal-text);
|
||||
background: var(--background);
|
||||
max-width: 300px;
|
||||
border-radius: .7em;
|
||||
max-width: 250px;
|
||||
border-radius: 12px;
|
||||
z-index: 999;
|
||||
text-align: left;
|
||||
cursor: default;
|
||||
display: flex;
|
||||
flex-flow: column;
|
||||
gap: 15px;
|
||||
|
||||
h1 {
|
||||
font-size: 1rem;
|
||||
button {
|
||||
@include basicIconButton(10px, 14px, ui);
|
||||
gap: 20px;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,107 @@
|
|||
import variables from 'modules/variables';
|
||||
import { MdClose, MdEmail, MdContentCopy } from 'react-icons/md';
|
||||
import { FaTwitter, FaFacebookF } from 'react-icons/fa';
|
||||
import { AiFillWechat } from 'react-icons/ai';
|
||||
import { SiTencentqq } from 'react-icons/si';
|
||||
import Tooltip from '../tooltip/Tooltip';
|
||||
import { toast } from 'react-toastify';
|
||||
|
||||
import './sharemodal.scss';
|
||||
|
||||
export default function ShareModal({ modalClose, data }) {
|
||||
const getMessage = (text) => variables.language.getMessage(variables.languagecode, text);
|
||||
const url = variables.constants.MARKETPLACE_URL + '/share/' + btoa(data.api_name);
|
||||
|
||||
const copyLink = () => {
|
||||
navigator.clipboard.writeText(url);
|
||||
toast('Link copied!');
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="shareModal">
|
||||
<div className="shareHeader">
|
||||
<span className="title">Share</span>
|
||||
<Tooltip title="Close">
|
||||
<div className="close" onClick={modalClose}>
|
||||
<MdClose />
|
||||
</div>
|
||||
</Tooltip>
|
||||
</div>
|
||||
<div className="buttons">
|
||||
<Tooltip title="Twitter">
|
||||
<button
|
||||
onClick={() =>
|
||||
window
|
||||
.open(
|
||||
`https://twitter.com/intent/tweet?text=Check out ${data.data.name} on @getmue marketplace: ${url}`,
|
||||
'_blank',
|
||||
)
|
||||
.focus()
|
||||
}
|
||||
>
|
||||
<FaTwitter />
|
||||
</button>
|
||||
</Tooltip>
|
||||
<Tooltip title="Facebook">
|
||||
<button
|
||||
onClick={() =>
|
||||
window.open(`https://www.facebook.com/sharer/sharer.php?u=${url}`, '_blank').focus()
|
||||
}
|
||||
>
|
||||
<FaFacebookF />
|
||||
</button>
|
||||
</Tooltip>
|
||||
<Tooltip title="Email">
|
||||
<button
|
||||
onClick={() =>
|
||||
window
|
||||
.open(
|
||||
'mailto:email@example.com?subject=Check%20out%20this%20Mue%20addon!&body=' +
|
||||
data.data.name +
|
||||
'on Mue: ' +
|
||||
url,
|
||||
'_blank',
|
||||
)
|
||||
.focus()
|
||||
}
|
||||
>
|
||||
<MdEmail />
|
||||
</button>
|
||||
</Tooltip>
|
||||
<Tooltip title="WeChat">
|
||||
<button
|
||||
onClick={() =>
|
||||
window
|
||||
.open(
|
||||
`https://api.qrserver.com/v1/create-qr-code/?size=154x154&data=${url}`,
|
||||
'_blank',
|
||||
)
|
||||
.focus()
|
||||
}
|
||||
>
|
||||
<AiFillWechat />
|
||||
</button>
|
||||
</Tooltip>
|
||||
<Tooltip title="Tencent QQ">
|
||||
<button
|
||||
onClick={() =>
|
||||
window
|
||||
.open(`http://connect.qq.com/widget/shareqq/index.html?url=${url}`, '_blank')
|
||||
.focus()
|
||||
}
|
||||
>
|
||||
<SiTencentqq />
|
||||
</button>
|
||||
</Tooltip>
|
||||
</div>
|
||||
<div className="copy">
|
||||
<input type="text" value={url} className="left field" readOnly />
|
||||
<Tooltip title="Copy link" placement="top">
|
||||
<button onClick={() => copyLink()}>
|
||||
<MdContentCopy />
|
||||
</button>
|
||||
</Tooltip>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
@import '../../../scss/variables';
|
||||
|
||||
.shareModal {
|
||||
@extend %tabText;
|
||||
display: flex;
|
||||
flex-flow: column;
|
||||
gap: 15px;
|
||||
padding: 15px;
|
||||
@include themed() {
|
||||
background: t($modal-background);
|
||||
}
|
||||
.buttons {
|
||||
justify-content: space-between;
|
||||
display: flex;
|
||||
gap: 15px;
|
||||
}
|
||||
button {
|
||||
place-items: center;
|
||||
display: grid;
|
||||
@include basicIconButton(11px, 1.3rem, modal);
|
||||
}
|
||||
.copy {
|
||||
display: flex;
|
||||
flex-flow: row;
|
||||
gap: 15px;
|
||||
}
|
||||
input[type='text'] {
|
||||
@include themed() {
|
||||
background: t($modal-sidebar);
|
||||
border-radius: t($borderRadius);
|
||||
box-shadow: 0 0 0 4px t($modal-sidebarActive);
|
||||
padding: 11px;
|
||||
flex: 1;
|
||||
color: t($color);
|
||||
}
|
||||
border: none;
|
||||
outline: none;
|
||||
}
|
||||
.close {
|
||||
padding: 15px;
|
||||
place-items: center;
|
||||
display: grid;
|
||||
cursor: pointer;
|
||||
&:hover {
|
||||
@include themed() {
|
||||
background: t($modal-sidebar);
|
||||
border-radius: t($borderRadius);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.shareHeader {
|
||||
display: flex;
|
||||
flex-flow: row;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
|
@ -1,10 +1,38 @@
|
|||
import './tooltip.scss';
|
||||
import { useState } from "react";
|
||||
import { useFloating, flip, offset, shift } from "@floating-ui/react-dom";
|
||||
import "./tooltip.scss";
|
||||
|
||||
export default function Tooltip({ children, title, style, placement }) {
|
||||
const [showTooltip, setShowTooltip] = useState(false);
|
||||
const { x, y, reference, floating, strategy } = useFloating({
|
||||
placement: placement || "bottom",
|
||||
middleware: [flip(), offset(15), shift()],
|
||||
});
|
||||
|
||||
export default function Tooltip({ children, title }) {
|
||||
return (
|
||||
<div className='tooltip'>
|
||||
<div
|
||||
className="tooltip"
|
||||
style={style}
|
||||
onMouseEnter={() => setShowTooltip(true)}
|
||||
onMouseLeave={() => setShowTooltip(false)}
|
||||
onFocus={() => setShowTooltip(true)}
|
||||
onBlur={() => setShowTooltip(false)}
|
||||
ref={reference}
|
||||
>
|
||||
{children}
|
||||
<span className='tooltipTitle'>{title}</span>
|
||||
{showTooltip && (
|
||||
<span
|
||||
ref={floating}
|
||||
style={{
|
||||
position: strategy,
|
||||
top: y ?? "",
|
||||
left: x ?? "",
|
||||
}}
|
||||
className="tooltipTitle"
|
||||
>
|
||||
{title}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
import { useState } from 'react';
|
||||
import { useFloating, flip, offset, shift } from '@floating-ui/react-dom';
|
||||
import './tooltip.scss';
|
||||
|
||||
export default function InfoTooltip({
|
||||
children,
|
||||
title,
|
||||
style,
|
||||
placement,
|
||||
subtitle,
|
||||
linkText,
|
||||
linkURL,
|
||||
}) {
|
||||
const [showTooltip, setShowTooltip] = useState(true);
|
||||
const { x, y, reference, floating, strategy } = useFloating({
|
||||
placement: placement || 'bottom-end',
|
||||
middleware: [flip(), offset(15), shift()],
|
||||
});
|
||||
|
||||
return (
|
||||
<div className="tooltip" style={style} ref={reference}>
|
||||
{children}
|
||||
{showTooltip && (
|
||||
<div
|
||||
className="notification"
|
||||
ref={floating}
|
||||
style={{
|
||||
position: strategy,
|
||||
top: y ?? '',
|
||||
left: x ?? '',
|
||||
}}
|
||||
>
|
||||
<span className="title">{title}</span>
|
||||
<span className="subtitle">
|
||||
{subtitle}{' '}
|
||||
<a className="link" href={linkURL}>
|
||||
{linkText}
|
||||
</a>
|
||||
</span>
|
||||
<button onClick={() => setShowTooltip(false)}>Ok, Got it!</button>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
|
@ -1,37 +1,79 @@
|
|||
// todo: possibly add tooltip placement option
|
||||
@import 'scss/variables';
|
||||
|
||||
.tooltip {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
display: grid;
|
||||
}
|
||||
|
||||
.tooltipTitle {
|
||||
min-width: 60px;
|
||||
background-color: rgba(255, 255, 255, 0.89);
|
||||
color: #000;
|
||||
text-align: center;
|
||||
font-size: 0.6rem;
|
||||
border-radius: 6px;
|
||||
padding: 5px 0;
|
||||
position: absolute;
|
||||
z-index: 1;
|
||||
top: 100%;
|
||||
left: 50%;
|
||||
margin-left: -30px;
|
||||
visibility: hidden;
|
||||
cursor: initial;
|
||||
user-select: none;
|
||||
@keyframes floating {
|
||||
0% {
|
||||
transform: translate(0, -5px);
|
||||
opacity: 0;
|
||||
transition: 0.2s;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
.tooltipTitle {
|
||||
visibility: visible;
|
||||
opacity: 1;
|
||||
100% {
|
||||
transform: translate(0, -0px);
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.tooltipTitle {
|
||||
@extend %basic;
|
||||
text-align: center;
|
||||
font-size: 0.6rem;
|
||||
padding: 5px 10px;
|
||||
position: absolute;
|
||||
z-index: 1;
|
||||
/*top: 100%;
|
||||
left: 50%;
|
||||
margin-top: 15px;
|
||||
margin-left: -30px;*/
|
||||
cursor: initial;
|
||||
user-select: none;
|
||||
opacity: 1;
|
||||
animation-name: floating;
|
||||
animation-duration: 0.3s;
|
||||
animation-timing-function: ease-in;
|
||||
}
|
||||
|
||||
#modal {
|
||||
.tooltipTitle {
|
||||
@include themed() {
|
||||
background: t($modal-sidebar);
|
||||
box-shadow: 0 0 0 1px t($modal-sidebarActive);
|
||||
color: t($color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.dark .tooltipTitle {
|
||||
background-color: rgba(0, 0, 0, 0.79);
|
||||
color: #fff;
|
||||
#root {
|
||||
.tooltipTitle {
|
||||
@extend %basic;
|
||||
}
|
||||
}
|
||||
|
||||
.tooltipTitle:before {
|
||||
transform: scale3d(0.2, 0.2, 1);
|
||||
transition: all 0.2s ease-in-out;
|
||||
}
|
||||
.tooltipTitle:after {
|
||||
transform: translate3d(0, 6px, 0);
|
||||
transition: all 0.1s ease-in-out;
|
||||
}
|
||||
.tooltipTitle:hover:before,
|
||||
.tooltipTitle:hover:after {
|
||||
opacity: 1;
|
||||
transform: scale3d(1, 1, 1);
|
||||
}
|
||||
.tooltipTitle:hover:after {
|
||||
transition: all 0.2s 0.1s ease-in-out;
|
||||
}
|
||||
|
||||
#arrow {
|
||||
position: absolute;
|
||||
background: #333;
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
transform: rotate(45deg);
|
||||
}
|
||||
|
|
|
@ -6,27 +6,42 @@ export default class ErrorBoundary extends PureComponent {
|
|||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
error: false
|
||||
error: false,
|
||||
};
|
||||
}
|
||||
|
||||
static getDerivedStateFromError(error) {
|
||||
console.log(error);
|
||||
variables.stats.postEvent('modal', 'Error occurred');
|
||||
return {
|
||||
error: true
|
||||
return {
|
||||
error: true,
|
||||
};
|
||||
}
|
||||
|
||||
render() {
|
||||
if (this.state.error) {
|
||||
return (
|
||||
<div className='emptyitems'>
|
||||
<div className='emptyMessage'>
|
||||
<MdErrorOutline/>
|
||||
<h1>{variables.language.getMessage(variables.languagecode, 'modals.main.error_boundary.title')}</h1>
|
||||
<p>{variables.language.getMessage(variables.languagecode, 'modals.main.error_boundary.message')}</p>
|
||||
<button className='refresh' onClick={() => window.location.reload()}>{variables.language.getMessage(variables.languagecode, 'modals.main.error_boundary.refresh')}</button>
|
||||
<div className="emptyItems">
|
||||
<div className="emptyMessage">
|
||||
<MdErrorOutline />
|
||||
<h1>
|
||||
{variables.language.getMessage(
|
||||
variables.languagecode,
|
||||
'modals.main.error_boundary.title',
|
||||
)}
|
||||
</h1>
|
||||
<p>
|
||||
{variables.language.getMessage(
|
||||
variables.languagecode,
|
||||
'modals.main.error_boundary.message',
|
||||
)}
|
||||
</p>
|
||||
<button className="refresh" onClick={() => window.location.reload()}>
|
||||
{variables.language.getMessage(
|
||||
variables.languagecode,
|
||||
'modals.main.error_boundary.refresh',
|
||||
)}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import variables from 'modules/variables';
|
||||
import { PureComponent } from 'react';
|
||||
import { PureComponent, Suspense, lazy } from 'react';
|
||||
import Modal from 'react-modal';
|
||||
//import Hotkeys from 'react-hot-keys';
|
||||
|
||||
|
@ -9,7 +9,10 @@ import Preview from '../helpers/preview/Preview';
|
|||
|
||||
import EventBus from 'modules/helpers/eventbus';
|
||||
|
||||
import Welcome from './welcome/Welcome';
|
||||
// Welcome modal is lazy loaded as the user won't use it every time they open a tab
|
||||
// We used to lazy load the main and feedback modals, but doing so broke the modal open animation on first click
|
||||
const Welcome = lazy(() => import('./welcome/Welcome'));
|
||||
const renderLoader = () => <></>;
|
||||
|
||||
export default class Modals extends PureComponent {
|
||||
constructor() {
|
||||
|
@ -18,14 +21,18 @@ export default class Modals extends PureComponent {
|
|||
mainModal: false,
|
||||
updateModal: false,
|
||||
welcomeModal: false,
|
||||
preview: false
|
||||
feedbackModal: false,
|
||||
preview: false,
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
if (localStorage.getItem('showWelcome') === 'true' && window.location.search !== '?nointro=true') {
|
||||
if (
|
||||
localStorage.getItem('showWelcome') === 'true' &&
|
||||
window.location.search !== '?nointro=true'
|
||||
) {
|
||||
this.setState({
|
||||
welcomeModal: true
|
||||
welcomeModal: true,
|
||||
});
|
||||
variables.stats.postEvent('modal', 'Opened welcome');
|
||||
}
|
||||
|
@ -45,7 +52,7 @@ export default class Modals extends PureComponent {
|
|||
closeWelcome() {
|
||||
localStorage.setItem('showWelcome', false);
|
||||
this.setState({
|
||||
welcomeModal: false
|
||||
welcomeModal: false,
|
||||
});
|
||||
EventBus.dispatch('refresh', 'widgetsWelcomeDone');
|
||||
EventBus.dispatch('refresh', 'widgets');
|
||||
|
@ -57,14 +64,14 @@ export default class Modals extends PureComponent {
|
|||
localStorage.setItem('welcomePreview', true);
|
||||
this.setState({
|
||||
welcomeModal: false,
|
||||
preview: true
|
||||
preview: true,
|
||||
});
|
||||
EventBus.dispatch('refresh', 'widgetsWelcome');
|
||||
}
|
||||
|
||||
toggleModal(type, action) {
|
||||
this.setState({
|
||||
[type]: action
|
||||
[type]: action,
|
||||
});
|
||||
|
||||
if (action !== false) {
|
||||
|
@ -75,15 +82,38 @@ export default class Modals extends PureComponent {
|
|||
render() {
|
||||
return (
|
||||
<>
|
||||
{this.state.welcomeModal === false ? <Navbar openModal={(modal) => this.toggleModal(modal, true)}/> : null}
|
||||
<Modal closeTimeoutMS={300} id='modal' onRequestClose={() => this.toggleModal('mainModal', false)} isOpen={this.state.mainModal} className='Modal mainModal' overlayClassName='Overlay' ariaHideApp={false}>
|
||||
<Main modalClose={() => this.toggleModal('mainModal', false)}/>
|
||||
{this.state.welcomeModal === false ? (
|
||||
<Navbar openModal={(modal) => this.toggleModal(modal, true)} />
|
||||
) : null}
|
||||
<Modal
|
||||
closeTimeoutMS={300}
|
||||
id="modal"
|
||||
onRequestClose={() => this.toggleModal('mainModal', false)}
|
||||
isOpen={this.state.mainModal}
|
||||
className="Modal mainModal"
|
||||
overlayClassName="Overlay"
|
||||
ariaHideApp={false}
|
||||
>
|
||||
<Main modalClose={() => this.toggleModal('mainModal', false)} />
|
||||
</Modal>
|
||||
<Modal closeTimeoutMS={300} onRequestClose={() => this.closeWelcome()} isOpen={this.state.welcomeModal} className='Modal welcomemodal mainModal' overlayClassName='Overlay welcomeoverlay' shouldCloseOnOverlayClick={false} ariaHideApp={false}>
|
||||
<Welcome modalClose={() => this.closeWelcome()} modalSkip={() => this.previewWelcome()}/>
|
||||
</Modal>
|
||||
{this.state.preview ? <Preview setup={() => window.location.reload()}/> : null}
|
||||
{/*variables.keybinds.toggleModal && variables.keybinds.toggleModal !== '' ? <Hotkeys keyName={variables.keybinds.toggleModal} onKeyDown={() => this.toggleModal('mainModal', (this.state.mainModal === true ? false : true))}/> : null*/}
|
||||
<Suspense fallback={renderLoader()}>
|
||||
<Modal
|
||||
closeTimeoutMS={300}
|
||||
onRequestClose={() => this.closeWelcome()}
|
||||
isOpen={this.state.welcomeModal}
|
||||
className="Modal welcomemodal mainModal"
|
||||
overlayClassName="Overlay welcomeoverlay"
|
||||
shouldCloseOnOverlayClick={false}
|
||||
ariaHideApp={false}
|
||||
>
|
||||
<Welcome
|
||||
modalClose={() => this.closeWelcome()}
|
||||
modalSkip={() => this.previewWelcome()}
|
||||
/>
|
||||
</Modal>
|
||||
</Suspense>
|
||||
{this.state.preview ? <Preview setup={() => window.location.reload()} /> : null}
|
||||
{/*variables.keybinds.toggleModal && variables.keybinds.toggleModal !== '' ? <Hotkeys keyName={variables.keybinds.toggleModal} onKeyDown={() => this.toggleModal('mainModal', (this.state.mainModal === true ? false : true))}/> : null*/}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,56 +1,70 @@
|
|||
import variables from 'modules/variables';
|
||||
import { Suspense, lazy } from 'react';
|
||||
import { Suspense, lazy, useState } from 'react';
|
||||
|
||||
import { MdClose } from 'react-icons/md';
|
||||
|
||||
import Tabs from './tabs/backend/Tabs';
|
||||
|
||||
import './scss/index.scss';
|
||||
import Tooltip from '../../helpers/tooltip/Tooltip';
|
||||
|
||||
// Lazy load all the tabs instead of the modal itself
|
||||
const Settings = lazy(() => import('./tabs/Settings'));
|
||||
const Addons = lazy(() => import('./tabs/Addons'));
|
||||
const Marketplace = lazy(() => import('./tabs/Marketplace'));
|
||||
|
||||
const renderLoader = () => (
|
||||
<Tabs>
|
||||
const renderLoader = (current) => (
|
||||
<Tabs current={current}>
|
||||
<div label={variables.language.getMessage(variables.languagecode, 'modals.main.loading')}>
|
||||
<div className='emptyitems'>
|
||||
<div className='emptyMessage'>
|
||||
<h1>{variables.language.getMessage(variables.languagecode, 'modals.main.loading')}</h1>
|
||||
<div className="emptyItems">
|
||||
<div className="emptyMessage">
|
||||
<div className="loaderHolder">
|
||||
<div id="loader"></div>
|
||||
<span className="subtitle">Just be a sec.</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div label='' style={{ display: 'none' }}></div>
|
||||
<div label="" style={{ display: 'none' }}></div>
|
||||
</Tabs>
|
||||
);
|
||||
|
||||
export default function MainModal({ modalClose }) {
|
||||
const display = (localStorage.getItem('showReminder') === 'true') ? 'block' : 'none';
|
||||
const display = localStorage.getItem('showReminder') === 'true' ? 'block' : 'none';
|
||||
const [currentTab, setCurrentTab] = useState(0);
|
||||
|
||||
const changeTab = (type) => {
|
||||
switch (type) {
|
||||
case 'settings':
|
||||
setCurrentTab(<Settings changeTab={changeTab} />);
|
||||
break;
|
||||
case 'addons':
|
||||
setCurrentTab(<Addons changeTab={changeTab} />);
|
||||
break;
|
||||
case 'marketplace':
|
||||
setCurrentTab(<Marketplace changeTab={changeTab} />);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
if (currentTab === 0) {
|
||||
setCurrentTab(<Settings changeTab={changeTab} />);
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<span className='closeModal' onClick={modalClose}>×</span>
|
||||
<Tabs navbar={true}>
|
||||
<div label={variables.language.getMessage(variables.languagecode, 'modals.main.navbar.settings')} name='settings'>
|
||||
<Suspense fallback={renderLoader()}>
|
||||
<Settings/>
|
||||
</Suspense>
|
||||
</div>
|
||||
<div label={variables.language.getMessage(variables.languagecode, 'modals.main.navbar.addons')} name='addons'>
|
||||
<Suspense fallback={renderLoader()}>
|
||||
<Addons/>
|
||||
</Suspense>
|
||||
</div>
|
||||
<div label={variables.language.getMessage(variables.languagecode, 'modals.main.navbar.marketplace')} name='marketplace'>
|
||||
<Suspense fallback={renderLoader()}>
|
||||
<Marketplace/>
|
||||
</Suspense>
|
||||
</div>
|
||||
</Tabs>
|
||||
<div className='reminder-info' style={{ display }}>
|
||||
<h1>{variables.language.getMessage(variables.languagecode, 'modals.main.settings.reminder.title')}</h1>
|
||||
<p>{variables.language.getMessage(variables.languagecode, 'modals.main.settings.reminder.message')}</p>
|
||||
<button className='pinNote' onClick={() => window.location.reload()}>{variables.language.getMessage(variables.languagecode, 'modals.main.error_boundary.refresh')}</button>
|
||||
</div>
|
||||
</>
|
||||
<div className="frame">
|
||||
<Tooltip
|
||||
style={{ position: 'absolute', top: '3rem', right: '3rem' }}
|
||||
title="close"
|
||||
key="cheese"
|
||||
>
|
||||
<span className="closeModal" onClick={modalClose}>
|
||||
<MdClose />
|
||||
</span>
|
||||
</Tooltip>
|
||||
<Suspense fallback={renderLoader(currentTab)}>{currentTab}</Suspense>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
import variables from "modules/variables";
|
||||
|
||||
export default function Collection({ items, toggleFunction }) {
|
||||
return [
|
||||
<div className='collection starWars'>
|
||||
<div className='content'>
|
||||
<div className="tags">
|
||||
<div className="tag">
|
||||
<span>Star Wars</span>
|
||||
</div>
|
||||
</div>
|
||||
<span className='title'>Star Wars Collection</span>
|
||||
<span className='subtitle'>A Collection of stuff inspired by the film franchise star wars..</span>
|
||||
<button>Explore Collection</button>
|
||||
</div>
|
||||
</div>,
|
||||
<div className="items">
|
||||
{items.map((item) => (
|
||||
<div
|
||||
className="item"
|
||||
onClick={() => toggleFunction(item)}
|
||||
key={item.name}
|
||||
>
|
||||
<img
|
||||
alt="icon"
|
||||
draggable="false"
|
||||
src={variables.constants.DDG_IMAGE_PROXY + item.icon_url}
|
||||
/>
|
||||
<div className="card-details">
|
||||
<span className="card-title">{item.display_name || item.name}</span>
|
||||
<span className="card-subtitle">{item.author}</span>
|
||||
<div className="tags">
|
||||
<div className="tag">
|
||||
<span>{item.author}</span>
|
||||
</div>
|
||||
<div className='moreTag'>
|
||||
<span>1</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>,
|
||||
];
|
||||
}
|
|
@ -1,19 +1,38 @@
|
|||
import variables from 'modules/variables';
|
||||
import { PureComponent, Fragment } from 'react';
|
||||
import Tooltip from '../../../helpers/tooltip/Tooltip';
|
||||
import { toast } from 'react-toastify';
|
||||
import { MdArrowBack } from 'react-icons/md';
|
||||
import {
|
||||
MdArrowBack,
|
||||
MdFavoriteBorder,
|
||||
MdIosShare,
|
||||
MdFlag,
|
||||
MdWarning,
|
||||
MdAccountCircle,
|
||||
MdBugReport,
|
||||
MdFormatQuote,
|
||||
MdImage,
|
||||
MdTranslate,
|
||||
MdKeyboardArrowDown,
|
||||
MdKeyboardArrowUp,
|
||||
} from 'react-icons/md';
|
||||
import Modal from 'react-modal';
|
||||
|
||||
import { install, uninstall } from 'modules/helpers/marketplace';
|
||||
|
||||
import Lightbox from './Lightbox';
|
||||
import ShareModal from '../../../helpers/sharemodal/ShareModal';
|
||||
|
||||
export default class Item extends PureComponent {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
showLightbox: false,
|
||||
showUpdateButton: (this.props.addonInstalled === true && this.props.addonInstalledVersion !== this.props.data.version)
|
||||
showUpdateButton:
|
||||
this.props.addonInstalled === true &&
|
||||
this.props.addonInstalledVersion !== this.props.data.version,
|
||||
showMore: false,
|
||||
shareModal: false,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -21,11 +40,19 @@ export default class Item extends PureComponent {
|
|||
uninstall(this.props.data.type, this.props.data.display_name);
|
||||
install(this.props.data.type, this.props.data);
|
||||
toast(variables.language.getMessage(variables.languagecode, 'toasts.updated'));
|
||||
this.setState({
|
||||
showUpdateButton: false
|
||||
this.setState({
|
||||
showUpdateButton: false,
|
||||
});
|
||||
}
|
||||
|
||||
toggleShowMore() {
|
||||
if (this.state.showMore === true) {
|
||||
this.setState({ showMore: false });
|
||||
} else {
|
||||
this.setState({ showMore: true });
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
const getMessage = (text) => variables.language.getMessage(variables.languagecode, text);
|
||||
|
||||
|
@ -36,15 +63,20 @@ export default class Item extends PureComponent {
|
|||
let warningHTML;
|
||||
if (this.props.data.quote_api) {
|
||||
warningHTML = (
|
||||
<div className='productInformation'>
|
||||
<ul>
|
||||
<li className='header'>{getMessage('modals.main.marketplace.product.quote_warning.title')}</li>
|
||||
<li id='updated'>{getMessage('modals.main.marketplace.product.quote_warning.description')}</li>
|
||||
</ul>
|
||||
<div className="itemWarning">
|
||||
<div className="topRow">
|
||||
<MdWarning />
|
||||
<div className="title">
|
||||
{getMessage('modals.main.marketplace.product.quote_warning.title')}
|
||||
</div>
|
||||
</div>
|
||||
<div className="subtitle">
|
||||
{getMessage('modals.main.marketplace.product.quote_warning.description')}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
// prevent console error
|
||||
let iconsrc = variables.constants.DDG_IMAGE_PROXY + this.props.data.icon;
|
||||
if (!this.props.data.icon) {
|
||||
|
@ -54,48 +86,170 @@ export default class Item extends PureComponent {
|
|||
let updateButton;
|
||||
if (this.state.showUpdateButton) {
|
||||
updateButton = (
|
||||
<Fragment key='update'>
|
||||
<br/><br/>
|
||||
<button className='removeFromMue' onClick={() => this.updateAddon()}>
|
||||
<Fragment key="update">
|
||||
<button className="removeFromMue" onClick={() => this.updateAddon()}>
|
||||
{getMessage('modals.main.addons.product.buttons.update_addon')}
|
||||
</button>
|
||||
</Fragment>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return (
|
||||
<div id='item'>
|
||||
<br/>
|
||||
<MdArrowBack className='backArrow' onClick={this.props.toggleFunction}/>
|
||||
<br/>
|
||||
<h1>{this.props.data.display_name}</h1>
|
||||
{this.props.button}
|
||||
{updateButton}
|
||||
<br/><br/>
|
||||
{iconsrc ? <img alt='product' draggable='false' src={iconsrc} onClick={() => this.setState({ showLightbox: true })}/> : null}
|
||||
<div className='side'>
|
||||
<div className='productInformation'>
|
||||
<ul>
|
||||
<li className='header'>{getMessage('modals.main.marketplace.product.version')}</li>
|
||||
{updateButton ? <li>{this.props.data.version} (Installed: {this.props.data.addonInstalledVersion})</li> : <li>{this.props.data.version}</li>}
|
||||
<br/>
|
||||
<li className='header'>{getMessage('modals.main.marketplace.product.author')}</li>
|
||||
<li>{this.props.data.author}</li>
|
||||
</ul>
|
||||
</div>
|
||||
<br/>
|
||||
{warningHTML}
|
||||
</div>
|
||||
<div className='sidebr'>
|
||||
<br/><br/>
|
||||
</div>
|
||||
<div className='informationContainer'>
|
||||
<h1 className='overview'>{getMessage('modals.main.marketplace.product.overview')}</h1>
|
||||
<p className='description' dangerouslySetInnerHTML={{ __html: this.props.data.description }}></p>
|
||||
</div>
|
||||
<Modal closeTimeoutMS={100} onRequestClose={() => this.setState({ showLightbox: false })} isOpen={this.state.showLightbox} className='Modal lightboxmodal' overlayClassName='Overlay resetoverlay' ariaHideApp={false}>
|
||||
<Lightbox modalClose={() => this.setState({ showLightbox: false })} img={iconsrc}/>
|
||||
<div id="item">
|
||||
<Modal
|
||||
closeTimeoutMS={300}
|
||||
isOpen={this.state.shareModal}
|
||||
className="Modal mainModal"
|
||||
overlayClassName="Overlay"
|
||||
ariaHideApp={false}
|
||||
onRequestClose={() => this.setState({ shareModal: false })}
|
||||
>
|
||||
<ShareModal
|
||||
data={this.props.data}
|
||||
modalClose={() => this.setState({ shareModal: false })}
|
||||
/>
|
||||
</Modal>
|
||||
<div className="flexTopMarketplace">
|
||||
<div className="returnButton">
|
||||
<Tooltip title="back" key="cheese">
|
||||
<MdArrowBack className="backArrow" onClick={this.props.toggleFunction} />
|
||||
</Tooltip>
|
||||
</div>
|
||||
<span className="mainTitle">Marketplace</span>
|
||||
</div>
|
||||
<div className="itemPage">
|
||||
<div className="itemShowcase">
|
||||
<div className="titleTop">
|
||||
<span className="itemTitle">{this.props.data.display_name}</span>
|
||||
<span className="subtitle">{this.props.data.author}</span>
|
||||
</div>
|
||||
<img
|
||||
alt="product"
|
||||
draggable="false"
|
||||
src={iconsrc}
|
||||
onClick={() => this.setState({ showLightbox: true })}
|
||||
/>
|
||||
<span className="title">Description</span>
|
||||
<span
|
||||
className={this.state.showMore ? 'description' : 'description truncate'}
|
||||
dangerouslySetInnerHTML={{ __html: this.props.data.description }}
|
||||
/>
|
||||
{this.props.data.description.length > 100 ? (
|
||||
<div className="showMore" onClick={() => this.toggleShowMore()}>
|
||||
{this.state.showMore === true ? (
|
||||
<>
|
||||
<span>Show Less</span>
|
||||
<MdKeyboardArrowDown />
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<span>Show More</span>
|
||||
<MdKeyboardArrowUp />
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
) : null}
|
||||
<div className="moreInfo">
|
||||
<div className="infoItem">
|
||||
<MdBugReport />
|
||||
<div className="text">
|
||||
<span className="header">
|
||||
{getMessage('modals.main.marketplace.product.version')}
|
||||
</span>
|
||||
{updateButton ? (
|
||||
<span>
|
||||
{this.props.data.version} (Installed: {this.props.data.addonInstalledVersion})
|
||||
</span>
|
||||
) : (
|
||||
<span>{this.props.data.version}</span>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<div className="infoItem">
|
||||
<MdAccountCircle />
|
||||
<div className="text">
|
||||
<span className="header">
|
||||
{getMessage('modals.main.marketplace.product.author')}
|
||||
</span>
|
||||
<span>{this.props.data.author}</span>
|
||||
</div>
|
||||
</div>
|
||||
{this.props.data.data.quotes ? (
|
||||
<div className="infoItem">
|
||||
<MdFormatQuote />
|
||||
<div className="text">
|
||||
<span className="header">No. Quotes</span>
|
||||
<span>{this.props.data.data.quotes.length}</span>
|
||||
</div>
|
||||
</div>
|
||||
) : null}
|
||||
{this.props.data.data.photos ? (
|
||||
<div className="infoItem">
|
||||
<MdImage />
|
||||
<div className="text">
|
||||
<span className="header">No. Images</span>
|
||||
<span>{this.props.data.data.photos.length}</span>
|
||||
</div>
|
||||
</div>
|
||||
) : null}
|
||||
{!this.props.data.data.photos ? (
|
||||
<div className="infoItem">
|
||||
<MdTranslate />
|
||||
<div className="text">
|
||||
<span className="header">Language</span>
|
||||
<span>English</span>
|
||||
</div>
|
||||
</div>
|
||||
) : null}
|
||||
<div className="infoItem">
|
||||
<MdIosShare />
|
||||
<div className="text">
|
||||
<span className="header">Shares</span>
|
||||
<span>324</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="itemInfo">
|
||||
<img
|
||||
alt="icon"
|
||||
draggable="false"
|
||||
src={variables.constants.DDG_IMAGE_PROXY + this.props.data.data.icon_url}
|
||||
/>
|
||||
{this.props.button}
|
||||
<div className="iconButtons">
|
||||
<Tooltip title="Share" key="cheese">
|
||||
<MdIosShare onClick={() => this.setState({ shareModal: true })} />
|
||||
</Tooltip>
|
||||
<Tooltip title="Report" key="cheese">
|
||||
<MdFlag
|
||||
onClick={() =>
|
||||
window.open(
|
||||
variables.constants.REPORT_ITEM +
|
||||
this.props.data.display_name.split(' ').join('+'),
|
||||
'_blank',
|
||||
)
|
||||
}
|
||||
/>
|
||||
</Tooltip>
|
||||
</div>
|
||||
{this.props.data.data.collection ? (
|
||||
<div className="inCollection">
|
||||
<span className="subtitle">Part of</span>
|
||||
<span className="title">Red Dead Collection</span>
|
||||
<button>Explore</button>
|
||||
</div>
|
||||
) : null}
|
||||
{warningHTML}
|
||||
{/*<div className="itemWarning">
|
||||
<div className="topRow">
|
||||
<NewReleasesRounded />
|
||||
<div className="title">Update</div>
|
||||
</div>
|
||||
<div className="subtitle">React > Vue</div>
|
||||
</div>*/}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,17 +1,45 @@
|
|||
import variables from 'modules/variables';
|
||||
|
||||
export default function Items({ items, toggleFunction }) {
|
||||
export default function Items({
|
||||
type,
|
||||
items,
|
||||
collections,
|
||||
toggleFunction,
|
||||
collectionFunction,
|
||||
onCollection,
|
||||
}) {
|
||||
return (
|
||||
<div className='items'>
|
||||
{items.map((item) => (
|
||||
<div className='item' onClick={() => toggleFunction(item.name)} key={item.name}>
|
||||
<img alt='icon' draggable='false' src={variables.constants.DDG_IMAGE_PROXY + item.icon_url} />
|
||||
<div className='details'>
|
||||
<h4>{item.display_name || item.name}</h4>
|
||||
<p>{item.author}</p>
|
||||
<>
|
||||
{type === 'all' && !onCollection ? (
|
||||
<>
|
||||
{collections.map((collection) => (
|
||||
<div className="collection">
|
||||
<div className="content">
|
||||
<span className="title">{collection.display_name}</span>
|
||||
<span className="subtitle">{collection.description}</span>
|
||||
<button onClick={() => collectionFunction(collection.name)}>
|
||||
Explore Collection
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</>
|
||||
) : null}
|
||||
<div className="items">
|
||||
{items.map((item) => (
|
||||
<div className="item" onClick={() => toggleFunction(item)} key={item.name}>
|
||||
<img
|
||||
alt="icon"
|
||||
draggable="false"
|
||||
src={variables.constants.DDG_IMAGE_PROXY + item.icon_url}
|
||||
/>
|
||||
<div className="card-details">
|
||||
<span className="card-title">{item.display_name || item.name}</span>
|
||||
<span className="card-subtitle">{item.author}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -8,11 +8,12 @@ export default function SideloadFailedModal({ modalClose, reason }) {
|
|||
<>
|
||||
<h1>{getMessage('modals.main.error_boundary.title')}</h1>
|
||||
<span>{getMessage('modals.main.addons.sideload.failed')}</span>
|
||||
<br/><br/>
|
||||
<br />
|
||||
<br />
|
||||
<span>{reason}</span>
|
||||
<div className='resetfooter'>
|
||||
<button className='round import' style={{ marginLeft: '-30px' }} onClick={modalClose}>
|
||||
<MdClose/>
|
||||
<div className="resetFooter">
|
||||
<button className="round import" style={{ marginLeft: '-30px' }} onClick={modalClose}>
|
||||
<MdClose />
|
||||
</button>
|
||||
</div>
|
||||
</>
|
||||
|
|
|
@ -17,48 +17,53 @@ export default class Added extends PureComponent {
|
|||
this.state = {
|
||||
installed: JSON.parse(localStorage.getItem('installed')),
|
||||
item: {},
|
||||
button: ''
|
||||
button: '',
|
||||
};
|
||||
this.buttons = {
|
||||
uninstall: <button className='removeFromMue' onClick={() => this.uninstall()}>{this.getMessage('modals.main.marketplace.product.buttons.remove')}</button>,
|
||||
uninstall: (
|
||||
<button className="removeFromMue" onClick={() => this.uninstall()}>
|
||||
{this.getMessage('modals.main.marketplace.product.buttons.remove')}
|
||||
</button>
|
||||
),
|
||||
};
|
||||
}
|
||||
|
||||
toggle(type, data) {
|
||||
if (type === 'item') {
|
||||
const installed = JSON.parse(localStorage.getItem('installed'));
|
||||
const info = installed.find((i) => i.name === data);
|
||||
const info = {
|
||||
data: installed.find((i) => i.name === data.name),
|
||||
};
|
||||
|
||||
this.setState({
|
||||
item: {
|
||||
type: info.type,
|
||||
name: data,
|
||||
display_name: info.name,
|
||||
author: info.author,
|
||||
description: urlParser(info.description.replace(/\n/g, '<br>')),
|
||||
type: info.data.type,
|
||||
display_name: info.data.name,
|
||||
author: info.data.author,
|
||||
description: urlParser(info.data.description.replace(/\n/g, '<br>')),
|
||||
//updated: info.updated,
|
||||
version: info.version,
|
||||
icon: info.screenshot_url,
|
||||
quote_api: info.quote_api || null
|
||||
version: info.data.version,
|
||||
icon: info.data.screenshot_url,
|
||||
data: info.data,
|
||||
},
|
||||
button: this.buttons.uninstall
|
||||
button: this.buttons.uninstall,
|
||||
});
|
||||
variables.stats.postEvent('marketplace', 'Item viewed');
|
||||
} else {
|
||||
this.setState({
|
||||
item: {}
|
||||
item: {},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
uninstall() {
|
||||
uninstall(this.state.item.type, this.state.item.display_name);
|
||||
|
||||
|
||||
toast(this.getMessage('toasts.uninstalled'));
|
||||
|
||||
this.setState({
|
||||
button: '',
|
||||
installed: JSON.parse(localStorage.getItem('installed'))
|
||||
installed: JSON.parse(localStorage.getItem('installed')),
|
||||
});
|
||||
|
||||
variables.stats.postEvent('marketplace', 'Uninstall');
|
||||
|
@ -84,7 +89,7 @@ export default class Added extends PureComponent {
|
|||
}
|
||||
|
||||
this.setState({
|
||||
installed: installed
|
||||
installed: installed,
|
||||
});
|
||||
|
||||
if (sendEvent) {
|
||||
|
@ -95,16 +100,20 @@ export default class Added extends PureComponent {
|
|||
updateCheck() {
|
||||
let updates = 0;
|
||||
this.state.installed.forEach(async (item) => {
|
||||
const data = await (await fetch(variables.constants.MARKETPLACE_URL + '/item/' + item.name)).json();
|
||||
const data = await (
|
||||
await fetch(variables.constants.MARKETPLACE_URL + '/item/' + item.name)
|
||||
).json();
|
||||
if (data.version !== item.version) {
|
||||
updates++;
|
||||
}
|
||||
});
|
||||
|
||||
if (updates > 0) {
|
||||
toast(this.getMessage('modals.main.addons.updates_available', {
|
||||
amount: updates
|
||||
}));
|
||||
|
||||
if (updates > 0) {
|
||||
toast(
|
||||
this.getMessage('modals.main.addons.updates_available', {
|
||||
amount: updates,
|
||||
}),
|
||||
);
|
||||
} else {
|
||||
toast(this.getMessage('modals.main.addons.no_updates'));
|
||||
}
|
||||
|
@ -117,31 +126,48 @@ export default class Added extends PureComponent {
|
|||
render() {
|
||||
if (this.state.installed.length === 0) {
|
||||
return (
|
||||
<div className='emptyitems'>
|
||||
<div className='emptyMessage'>
|
||||
<MdLocalMall/>
|
||||
<h1>{this.getMessage('modals.main.addons.empty.title')}</h1>
|
||||
<p className='description'>{this.getMessage('modals.main.addons.empty.description')}</p>
|
||||
<div className="emptyItems">
|
||||
<div className="emptyMessage">
|
||||
<MdLocalMall />
|
||||
<span className="title">{this.getMessage('modals.main.addons.empty.title')}</span>
|
||||
<span className="subtitle">
|
||||
{this.getMessage('modals.main.addons.empty.description')}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
if (this.state.item.display_name) {
|
||||
return <Item data={this.state.item} button={this.state.button} toggleFunction={() => this.toggle()} />;
|
||||
return (
|
||||
<Item
|
||||
data={this.state.item}
|
||||
button={this.state.button}
|
||||
toggleFunction={() => this.toggle()}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<Dropdown label={this.getMessage('modals.main.addons.sort.title')} name='sortAddons' onChange={(value) => this.sortAddons(value)}>
|
||||
<option value='newest'>{this.getMessage('modals.main.addons.sort.newest')}</option>
|
||||
<option value='oldest'>{this.getMessage('modals.main.addons.sort.oldest')}</option>
|
||||
<option value='a-z'>{this.getMessage('modals.main.addons.sort.a_z')}</option>
|
||||
<option value='z-a'>{this.getMessage('modals.main.addons.sort.z_a')}</option>
|
||||
<Dropdown
|
||||
label={this.getMessage('modals.main.addons.sort.title')}
|
||||
name="sortAddons"
|
||||
onChange={(value) => this.sortAddons(value)}
|
||||
>
|
||||
<option value="newest">{this.getMessage('modals.main.addons.sort.newest')}</option>
|
||||
<option value="oldest">{this.getMessage('modals.main.addons.sort.oldest')}</option>
|
||||
<option value="a-z">{this.getMessage('modals.main.addons.sort.a_z')}</option>
|
||||
<option value="z-a">{this.getMessage('modals.main.addons.sort.z_a')}</option>
|
||||
</Dropdown>
|
||||
<button className='addToMue sideload updateCheck' onClick={() => this.updateCheck()}>{this.getMessage('modals.main.addons.check_updates')}</button>
|
||||
<br/>
|
||||
<Items items={this.state.installed} toggleFunction={(input) => this.toggle('item', input)} />
|
||||
<button className="addToMue sideload updateCheck" onClick={() => this.updateCheck()}>
|
||||
{this.getMessage('modals.main.addons.check_updates')}
|
||||
</button>
|
||||
<br />
|
||||
<Items
|
||||
items={this.state.installed}
|
||||
toggleFunction={(input) => this.toggle('item', input)}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -5,12 +5,17 @@ import {
|
|||
MdOutlineInsertPhoto as Photos,
|
||||
MdOutlineFormatQuote as Quotes,
|
||||
MdUpload as ImportIcon,
|
||||
MdDownload as ExportIcon
|
||||
MdDownload as ExportIcon,
|
||||
MdArrowBack,
|
||||
MdDownload,
|
||||
MdOpenInNew,
|
||||
} from 'react-icons/md';
|
||||
import { TextField } from '@mui/material';
|
||||
import { toast } from 'react-toastify';
|
||||
import SettingsItem from '../../../main/settings/SettingsItem';
|
||||
|
||||
import { saveFile } from 'modules/helpers/settings/modals';
|
||||
import Tooltip from '../../../../helpers/tooltip/Tooltip';
|
||||
|
||||
import FileUpload from '../../settings/FileUpload';
|
||||
import Dropdown from '../../settings/Dropdown';
|
||||
|
@ -29,37 +34,48 @@ export default class Create extends PureComponent {
|
|||
version: '',
|
||||
author: '',
|
||||
icon_url: '',
|
||||
screenshot_url: ''
|
||||
screenshot_url: '',
|
||||
},
|
||||
addonData: '',
|
||||
settingsClasses: {
|
||||
current: 'toggle lightTheme',
|
||||
json: 'toggle lightTheme'
|
||||
}
|
||||
json: 'toggle lightTheme',
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
changeTab(tab, type) {
|
||||
changeTab(tab, type) {
|
||||
if (type) {
|
||||
return this.setState({
|
||||
return this.setState({
|
||||
currentTab: tab,
|
||||
addonMetadata: {
|
||||
type: type
|
||||
}
|
||||
type: type,
|
||||
},
|
||||
});
|
||||
} else {
|
||||
this.setState({
|
||||
currentTab: tab,
|
||||
});
|
||||
}
|
||||
|
||||
this.setState({
|
||||
currentTab: tab
|
||||
});
|
||||
}
|
||||
|
||||
importSettings(input) {
|
||||
const data = input || localStorage;
|
||||
let settings = {};
|
||||
Object.keys(data).forEach((key) => {
|
||||
if (key === 'statsData' || key === 'firstRun' || key === 'showWelcome' || key === 'language' || key === 'installed' || key === 'stats' || key === 'backup_settings' || key === 'showReminder'
|
||||
|| key === 'experimental' || key === 'debugtimeout' || key === 'quotelanguage') {
|
||||
if (
|
||||
key === 'statsData' ||
|
||||
key === 'firstRun' ||
|
||||
key === 'showWelcome' ||
|
||||
key === 'language' ||
|
||||
key === 'installed' ||
|
||||
key === 'stats' ||
|
||||
key === 'backup_settings' ||
|
||||
key === 'showReminder' ||
|
||||
key === 'experimental' ||
|
||||
key === 'debugtimeout' ||
|
||||
key === 'quotelanguage'
|
||||
) {
|
||||
return;
|
||||
}
|
||||
settings[key] = localStorage.getItem(key);
|
||||
|
@ -69,60 +85,57 @@ export default class Create extends PureComponent {
|
|||
addonData: settings,
|
||||
settingsClasses: {
|
||||
current: input ? 'toggle lightTheme active' : 'toggle lightTheme',
|
||||
json: input ? 'toggle lightTheme active' : 'toggle lightTheme'
|
||||
}
|
||||
json: input ? 'toggle lightTheme active' : 'toggle lightTheme',
|
||||
},
|
||||
});
|
||||
|
||||
toast(variables.language.getMessage(variables.languagecode, 'toasts.imported'));
|
||||
}
|
||||
|
||||
updateQuotePackType(type) {
|
||||
const addonMetadata = {
|
||||
type,
|
||||
name: this.state.addonMetadata.name,
|
||||
description: this.state.addonMetadata.description,
|
||||
version: this.state.addonMetadata.version,
|
||||
author: this.state.addonMetadata.author,
|
||||
icon_url: this.state.addonMetadata.icon_url,
|
||||
screenshot_url: this.state.addonMetadata.screenshot_url,
|
||||
};
|
||||
if (type === 'quotePack') {
|
||||
this.setState({
|
||||
this.setState({
|
||||
addonMetadata: {
|
||||
type,
|
||||
name: this.state.addonMetadata.name,
|
||||
description: this.state.addonMetadata.description,
|
||||
version: this.state.addonMetadata.version,
|
||||
author: this.state.addonMetadata.author,
|
||||
icon_url: this.state.addonMetadata.icon_url,
|
||||
screenshot_url: this.state.addonMetadata.screenshot_url,
|
||||
quotes: []
|
||||
}
|
||||
addonMetadata,
|
||||
quotes: [],
|
||||
},
|
||||
});
|
||||
} else {
|
||||
this.setState({
|
||||
this.setState({
|
||||
addonMetadata: {
|
||||
type,
|
||||
name: this.state.addonMetadata.name,
|
||||
description: this.state.addonMetadata.description,
|
||||
version: this.state.addonMetadata.version,
|
||||
author: this.state.addonMetadata.author,
|
||||
icon_url: this.state.addonMetadata.icon_url,
|
||||
screenshot_url: this.state.addonMetadata.screenshot_url
|
||||
addonMetadata,
|
||||
},
|
||||
addonData: {
|
||||
url: '',
|
||||
name: '',
|
||||
author: ''
|
||||
}
|
||||
author: '',
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
updateQuotePackAPI(type, data) {
|
||||
this.setState({
|
||||
addonData: {
|
||||
url: (type === 'url') ? data : this.state.addonData.url || '',
|
||||
name: (type === 'name') ? data : this.state.addonData.name || '',
|
||||
author: (type === 'author') ? data : this.state.addonData.author || '',
|
||||
}
|
||||
url: type === 'url' ? data : this.state.addonData.url || '',
|
||||
name: type === 'name' ? data : this.state.addonData.name || '',
|
||||
author: type === 'author' ? data : this.state.addonData.author || '',
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
importQuotes() {
|
||||
this.setState({
|
||||
addonData: JSON.parse(localStorage.getItem('customQuote')) || []
|
||||
addonData: JSON.parse(localStorage.getItem('customQuote')) || [],
|
||||
});
|
||||
|
||||
toast(variables.language.getMessage(variables.languagecode, 'toasts.imported'));
|
||||
|
@ -137,9 +150,9 @@ export default class Create extends PureComponent {
|
|||
photographer: '???',
|
||||
location: '???',
|
||||
url: {
|
||||
default: item
|
||||
}
|
||||
}
|
||||
default: item,
|
||||
},
|
||||
};
|
||||
});
|
||||
toast(variables.language.getMessage(variables.languagecode, 'toasts.imported'));
|
||||
} catch (e) {
|
||||
|
@ -148,43 +161,57 @@ export default class Create extends PureComponent {
|
|||
}
|
||||
|
||||
this.setState({
|
||||
addonData: data
|
||||
addonData: data,
|
||||
});
|
||||
}
|
||||
|
||||
downloadAddon() {
|
||||
saveFile({
|
||||
name: this.state.addonMetadata.name,
|
||||
description: this.state.addonMetadata.description,
|
||||
type: (this.state.addonMetadata.type === 'quote_api') ? 'quotes' : this.state.addonMetadata.type,
|
||||
version: this.state.addonMetadata.version,
|
||||
author: this.state.addonMetadata.author,
|
||||
icon_url: this.state.addonMetadata.icon_url,
|
||||
screenshot_url: this.state.addonMetadata.screenshot_url,
|
||||
[this.state.addonMetadata.type]: this.state.addonData
|
||||
}, this.state.addonMetadata.name + '.json');
|
||||
saveFile(
|
||||
{
|
||||
name: this.state.addonMetadata.name,
|
||||
description: this.state.addonMetadata.description,
|
||||
type:
|
||||
this.state.addonMetadata.type === 'quote_api' ? 'quotes' : this.state.addonMetadata.type,
|
||||
version: this.state.addonMetadata.version,
|
||||
author: this.state.addonMetadata.author,
|
||||
icon_url: this.state.addonMetadata.icon_url,
|
||||
screenshot_url: this.state.addonMetadata.screenshot_url,
|
||||
[this.state.addonMetadata.type]: this.state.addonData,
|
||||
},
|
||||
this.state.addonMetadata.name + '.json',
|
||||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
let tabContent;
|
||||
|
||||
const getMessage = (text) => variables.language.getMessage(variables.languagecode, text);
|
||||
|
||||
const chooseType = (
|
||||
<>
|
||||
<h3>{getMessage('modals.main.settings.sections.time.type')}</h3>
|
||||
<div className='themesToggleArea'>
|
||||
<div className='options'>
|
||||
<div className='toggle lightTheme' onClick={() => this.changeTab(2, 'photos')}>
|
||||
<Photos/>
|
||||
<div className="smallBanner">
|
||||
<div className="content">
|
||||
<span className="title">Help Centre</span>
|
||||
<span className="subtitle">
|
||||
Home of all docs and guides on creating addons for Mue's marketplace
|
||||
</span>
|
||||
</div>
|
||||
<button>
|
||||
Open Site
|
||||
<MdOpenInNew />
|
||||
</button>
|
||||
</div>
|
||||
<div className="themesToggleArea">
|
||||
<div className="options">
|
||||
<div className="toggle lightTheme" onClick={() => this.changeTab(2, 'photos')}>
|
||||
<Photos />
|
||||
<span>{getMessage('modals.main.marketplace.photo_packs')}</span>
|
||||
</div>
|
||||
<div className='toggle lightTheme' onClick={() => this.changeTab(2, 'quotes')}>
|
||||
<Quotes/>
|
||||
<div className="toggle lightTheme" onClick={() => this.changeTab(2, 'quotes')}>
|
||||
<Quotes />
|
||||
<span>{getMessage('modals.main.marketplace.quote_packs')}</span>
|
||||
</div>
|
||||
<div className='toggle lightTheme' onClick={() => this.changeTab(2, 'settings')}>
|
||||
<Settings/>
|
||||
</div>
|
||||
<div className="toggle lightTheme" onClick={() => this.changeTab(2, 'settings')}>
|
||||
<Settings />
|
||||
<span>{getMessage('modals.main.marketplace.preset_settings')}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -193,142 +220,371 @@ export default class Create extends PureComponent {
|
|||
);
|
||||
|
||||
// todo: find a better way to do all this
|
||||
const nextDescriptionDisabled = (this.state.addonMetadata.name !== undefined &&
|
||||
const nextDescriptionDisabled = !(
|
||||
this.state.addonMetadata.name !== undefined &&
|
||||
this.state.addonMetadata.description !== undefined &&
|
||||
this.state.addonMetadata.version !== undefined && this.state.addonMetadata.author !== undefined &&
|
||||
this.state.addonMetadata.icon_url !== undefined && this.state.addonMetadata.screenshot_url !== undefined)
|
||||
? false : true;
|
||||
|
||||
this.state.addonMetadata.version !== undefined &&
|
||||
this.state.addonMetadata.author !== undefined &&
|
||||
this.state.addonMetadata.icon_url !== undefined &&
|
||||
this.state.addonMetadata.screenshot_url !== undefined
|
||||
);
|
||||
|
||||
const setMetadata = (data, type) => {
|
||||
this.setState({
|
||||
addonMetadata: {
|
||||
name: (type === 'name') ? data : this.state.addonMetadata.name,
|
||||
description: (type === 'description') ? data : this.state.addonMetadata.description,
|
||||
version: (type === 'version') ? data : this.state.addonMetadata.version,
|
||||
author: (type === 'author') ? data : this.state.addonMetadata.author,
|
||||
icon_url: (type === 'icon_url') ? data : this.state.addonMetadata.icon_url,
|
||||
screenshot_url: (type === 'screenshot_url') ? data : this.state.addonMetadata.screenshot_url,
|
||||
type: this.state.addonMetadata.type
|
||||
}
|
||||
name: type === 'name' ? data : this.state.addonMetadata.name,
|
||||
description: type === 'description' ? data : this.state.addonMetadata.description,
|
||||
version: type === 'version' ? data : this.state.addonMetadata.version,
|
||||
author: type === 'author' ? data : this.state.addonMetadata.author,
|
||||
icon_url: type === 'icon_url' ? data : this.state.addonMetadata.icon_url,
|
||||
screenshot_url:
|
||||
type === 'screenshot_url' ? data : this.state.addonMetadata.screenshot_url,
|
||||
type: this.state.addonMetadata.type,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const writeDescription = (
|
||||
const writeDescription = (
|
||||
<>
|
||||
<h3>{getMessage('modals.main.marketplace.product.information')}</h3>
|
||||
<TextField label={getMessage('modals.main.addons.create.metadata.name')} varient='outlined' InputLabelProps={{ shrink: true }} value={this.state.addonMetadata.name} onInput={(e) => setMetadata(e.target.value, 'name')}/>
|
||||
<TextField label={getMessage('modals.main.marketplace.product.version')} varient='outlined' InputLabelProps={{ shrink: true }} value={this.state.addonMetadata.version} onInput={(e) => setMetadata(e.target.value, 'version')}/>
|
||||
<TextField label={getMessage('modals.main.marketplace.product.author')} varient='outlined' InputLabelProps={{ shrink: true }} value={this.state.addonMetadata.author} onInput={(e) => setMetadata(e.target.value, 'author')}/>
|
||||
<TextField label={getMessage('modals.main.addons.create.metadata.icon_url')} varient='outlined' InputLabelProps={{ shrink: true }} value={this.state.addonMetadata.icon_url} onInput={(e) => setMetadata(e.target.value, 'icon_url')}/>
|
||||
<TextField label={getMessage('modals.main.addons.create.metadata.screenshot_url')} varient='outlined' InputLabelProps={{ shrink: true }} value={this.state.addonMetadata.screenshot_url} onInput={(e) => setMetadata(e.target.value, 'screenshot_url')}/>
|
||||
<TextField label={getMessage('modals.main.addons.create.metadata.description')} varient='outlined' InputLabelProps={{ shrink: true }} multiline spellCheck={false} rows={4} value={this.state.addonMetadata.description} onInput={(e) => setMetadata(e.target.value, 'description')}/>
|
||||
<br/>
|
||||
<button onClick={() => this.changeTab(1)} className='uploadbg' style={{ marginRight: '10px' }}>{getMessage('modals.welcome.buttons.previous')}</button>
|
||||
<button onClick={() => this.changeTab(this.state.addonMetadata.type)} className='uploadbg' disabled={nextDescriptionDisabled}>{getMessage('modals.welcome.buttons.next')}</button>
|
||||
<div className="smallBanner">
|
||||
<div className="content">
|
||||
<span className="title" style={{ textTransform: 'capitalize' }}>
|
||||
Create {this.state.addonMetadata.type} Pack
|
||||
</span>
|
||||
<span className="subtitle">Description of what is being made</span>
|
||||
</div>
|
||||
<button>
|
||||
Example
|
||||
<MdDownload />
|
||||
</button>
|
||||
</div>
|
||||
<SettingsItem title={getMessage('modals.main.addons.create.metadata.name')}>
|
||||
<TextField
|
||||
label={getMessage('modals.main.addons.create.metadata.name')}
|
||||
varient="outlined"
|
||||
InputLabelProps={{ shrink: true }}
|
||||
value={this.state.addonMetadata.name}
|
||||
onInput={(e) => setMetadata(e.target.value, 'name')}
|
||||
/>
|
||||
</SettingsItem>
|
||||
<SettingsItem title={getMessage('modals.main.marketplace.product.version')}>
|
||||
<TextField
|
||||
label={getMessage('modals.main.marketplace.product.version')}
|
||||
varient="outlined"
|
||||
InputLabelProps={{ shrink: true }}
|
||||
value={this.state.addonMetadata.version}
|
||||
onInput={(e) => setMetadata(e.target.value, 'version')}
|
||||
/>
|
||||
</SettingsItem>
|
||||
<SettingsItem title={getMessage('modals.main.marketplace.product.author')}>
|
||||
<TextField
|
||||
label={getMessage('modals.main.marketplace.product.author')}
|
||||
varient="outlined"
|
||||
InputLabelProps={{ shrink: true }}
|
||||
value={this.state.addonMetadata.author}
|
||||
onInput={(e) => setMetadata(e.target.value, 'author')}
|
||||
/>
|
||||
</SettingsItem>
|
||||
<SettingsItem title={getMessage('modals.main.addons.create.metadata.icon_url')}>
|
||||
<TextField
|
||||
label={getMessage('modals.main.addons.create.metadata.icon_url')}
|
||||
varient="outlined"
|
||||
InputLabelProps={{ shrink: true }}
|
||||
value={this.state.addonMetadata.icon_url}
|
||||
onInput={(e) => setMetadata(e.target.value, 'icon_url')}
|
||||
/>
|
||||
</SettingsItem>
|
||||
<SettingsItem title={getMessage('modals.main.addons.create.metadata.screenshot_url')}>
|
||||
<TextField
|
||||
label={getMessage('modals.main.addons.create.metadata.screenshot_url')}
|
||||
varient="outlined"
|
||||
InputLabelProps={{ shrink: true }}
|
||||
value={this.state.addonMetadata.screenshot_url}
|
||||
onInput={(e) => setMetadata(e.target.value, 'screenshot_url')}
|
||||
/>
|
||||
</SettingsItem>
|
||||
<SettingsItem title={getMessage('modals.main.addons.create.metadata.description')}>
|
||||
<TextField
|
||||
label={getMessage('modals.main.addons.create.metadata.description')}
|
||||
varient="outlined"
|
||||
InputLabelProps={{ shrink: true }}
|
||||
multiline
|
||||
spellCheck={false}
|
||||
rows={4}
|
||||
value={this.state.addonMetadata.description}
|
||||
onInput={(e) => setMetadata(e.target.value, 'description')}
|
||||
/>
|
||||
</SettingsItem>
|
||||
<div className="createButtons">
|
||||
<button onClick={() => this.changeTab(1)} className="uploadbg">
|
||||
{getMessage('modals.welcome.buttons.previous')}
|
||||
</button>
|
||||
<button
|
||||
onClick={() => this.changeTab(this.state.addonMetadata.type)}
|
||||
className="uploadbg"
|
||||
disabled={nextDescriptionDisabled}
|
||||
>
|
||||
{getMessage('modals.welcome.buttons.next')}
|
||||
</button>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
|
||||
// settings
|
||||
const nextSettingsDisabled = (this.state.addonData === '') ? true : false;
|
||||
const nextSettingsDisabled = this.state.addonData === '';
|
||||
const importSettings = (
|
||||
<>
|
||||
<h3>{getMessage('modals.welcome.sections.settings.title')}</h3>
|
||||
<div className='themesToggleArea' >
|
||||
<div className='options' style={{ maxWidth: '512px' }}>
|
||||
<div className={this.state.settingsClasses.current} onClick={() => this.importSettings()}>
|
||||
<ExportIcon/>
|
||||
<div className="themesToggleArea">
|
||||
<div className="options" style={{ maxWidth: '512px' }}>
|
||||
<div
|
||||
className={this.state.settingsClasses.current}
|
||||
onClick={() => this.importSettings()}
|
||||
>
|
||||
<ExportIcon />
|
||||
<span>{getMessage('modals.main.addons.create.settings.current')}</span>
|
||||
</div>
|
||||
<div className={this.state.settingsClasses.json} onClick={() => document.getElementById('file-input').click()}>
|
||||
<ImportIcon/>
|
||||
<div
|
||||
className={this.state.settingsClasses.json}
|
||||
onClick={() => document.getElementById('file-input').click()}
|
||||
>
|
||||
<ImportIcon />
|
||||
<span>{getMessage('modals.main.addons.create.settings.json')}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<FileUpload id='file-input' type='settings' accept='application/json' loadFunction={(e) => this.importSettings(JSON.parse(e.target.result))} />
|
||||
<br/><br/>
|
||||
<button onClick={() => this.changeTab(2)} className='uploadbg' style={{ margin: '10px' }}>{getMessage('modals.welcome.buttons.previous')}</button>
|
||||
<button onClick={() => this.changeTab(3)} className='uploadbg' style={{ margin: '10px' }} disabled={nextSettingsDisabled}>{getMessage('modals.welcome.buttons.next')}</button>
|
||||
<FileUpload
|
||||
id="file-input"
|
||||
type="settings"
|
||||
accept="application/json"
|
||||
loadFunction={(e) => this.importSettings(JSON.parse(e.target.result))}
|
||||
/>
|
||||
<br />
|
||||
<br />
|
||||
<button onClick={() => this.changeTab(2)} className="uploadbg" style={{ margin: '10px' }}>
|
||||
{getMessage('modals.welcome.buttons.previous')}
|
||||
</button>
|
||||
<button
|
||||
onClick={() => this.changeTab(3)}
|
||||
className="uploadbg"
|
||||
style={{ margin: '10px' }}
|
||||
disabled={nextSettingsDisabled}
|
||||
>
|
||||
{getMessage('modals.welcome.buttons.next')}
|
||||
</button>
|
||||
</>
|
||||
);
|
||||
|
||||
|
||||
// quotes
|
||||
const nextQuotesDisabled = ((this.state.addonMetadata.type === 'quote_api' && this.state.addonData.url !== '' && this.state.addonData.name !== '' && this.state.addonData.author !== '')
|
||||
|| (this.state.addonMetadata.type === 'quotes' && this.state.addonData.quotes !== '')) ? false : true;
|
||||
const nextQuotesDisabled = !(
|
||||
(this.state.addonMetadata.type === 'quote_api' &&
|
||||
this.state.addonData.url !== '' &&
|
||||
this.state.addonData.name !== '' &&
|
||||
this.state.addonData.author !== '') ||
|
||||
(this.state.addonMetadata.type === 'quotes' && this.state.addonData.quotes !== '')
|
||||
);
|
||||
const addQuotes = (
|
||||
<>
|
||||
<h3>{getMessage('modals.main.addons.create.quotes.title')}</h3>
|
||||
<Dropdown label={getMessage('modals.main.settings.sections.time.type')} noSetting onChange={(e) => this.updateQuotePackType(e)}>
|
||||
<option value='quotes'>{getMessage('modals.main.addons.create.quotes.local.title')}</option>
|
||||
<option value='quote_api'>{getMessage('modals.main.addons.create.quotes.api.title')}</option>
|
||||
<Dropdown
|
||||
label={getMessage('modals.main.settings.sections.time.type')}
|
||||
noSetting
|
||||
onChange={(e) => this.updateQuotePackType(e)}
|
||||
>
|
||||
<option value="quotes">
|
||||
{getMessage('modals.main.addons.create.quotes.local.title')}
|
||||
</option>
|
||||
<option value="quote_api">
|
||||
{getMessage('modals.main.addons.create.quotes.api.title')}
|
||||
</option>
|
||||
</Dropdown>
|
||||
{this.state.addonMetadata.type === 'quote_api' ? <>
|
||||
<TextField label={getMessage('modals.main.addons.create.quotes.api.url')} varient='outlined' InputLabelProps={{ shrink: true }} value={this.state.addonData.url} onInput={(e) => this.updateQuotePack(e.target.value, 'url')}/>
|
||||
<TextField label={getMessage('modals.main.addons.create.quotes.api.name')} varient='outlined' InputLabelProps={{ shrink: true }} value={this.state.addonData.name} onInput={(e) => this.updateQuotePack(e.target.value, 'name')}/>
|
||||
<TextField label={getMessage('modals.main.addons.create.quotes.api.author')} varient='outlined' InputLabelProps={{ shrink: true }} value={this.state.addonData.author} onInput={(e) => this.updateQuotePack(e.target.value, 'author')}/>
|
||||
<br/><br/>
|
||||
</> : <>
|
||||
<div className='themesToggleArea'>
|
||||
<div className='options'>
|
||||
<div onClick={() => this.importQuotes()} className='toggle lightTheme' style={{ width: '60%', margin: '10px 0 10px 0' }}>
|
||||
<ExportIcon/>
|
||||
<span>{getMessage('modals.main.addons.create.settings.current')}</span>
|
||||
{this.state.addonMetadata.type === 'quote_api' ? (
|
||||
<>
|
||||
<TextField
|
||||
label={getMessage('modals.main.addons.create.quotes.api.url')}
|
||||
varient="outlined"
|
||||
InputLabelProps={{ shrink: true }}
|
||||
value={this.state.addonData.url}
|
||||
onInput={(e) => this.updateQuotePack(e.target.value, 'url')}
|
||||
/>
|
||||
<TextField
|
||||
label={getMessage('modals.main.addons.create.quotes.api.name')}
|
||||
varient="outlined"
|
||||
InputLabelProps={{ shrink: true }}
|
||||
value={this.state.addonData.name}
|
||||
onInput={(e) => this.updateQuotePack(e.target.value, 'name')}
|
||||
/>
|
||||
<TextField
|
||||
label={getMessage('modals.main.addons.create.quotes.api.author')}
|
||||
varient="outlined"
|
||||
InputLabelProps={{ shrink: true }}
|
||||
value={this.state.addonData.author}
|
||||
onInput={(e) => this.updateQuotePack(e.target.value, 'author')}
|
||||
/>
|
||||
<br />
|
||||
<br />
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<div className="themesToggleArea">
|
||||
<div className="options">
|
||||
<div
|
||||
onClick={() => this.importQuotes()}
|
||||
className="toggle lightTheme"
|
||||
style={{ width: '60%', margin: '10px 0 10px 0' }}
|
||||
>
|
||||
<ExportIcon />
|
||||
<span>{getMessage('modals.main.addons.create.settings.current')}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<br/>
|
||||
</>}
|
||||
<button onClick={() => this.changeTab(2)} className='uploadbg'>{getMessage('modals.welcome.buttons.previous')}</button>
|
||||
<button onClick={() => this.changeTab(3)} className='uploadbg' style={{ margin: '10px' }} disabled={nextQuotesDisabled}>{getMessage('modals.welcome.buttons.next')}</button>
|
||||
<br />
|
||||
</>
|
||||
)}
|
||||
<button onClick={() => this.changeTab(2)} className="uploadbg">
|
||||
{getMessage('modals.welcome.buttons.previous')}
|
||||
</button>
|
||||
<button
|
||||
onClick={() => this.changeTab(3)}
|
||||
className="uploadbg"
|
||||
style={{ margin: '10px' }}
|
||||
disabled={nextQuotesDisabled}
|
||||
>
|
||||
{getMessage('modals.welcome.buttons.next')}
|
||||
</button>
|
||||
</>
|
||||
);
|
||||
|
||||
// photos
|
||||
const nextPhotosDisabled = (this.state.addonData.photos !== '' && this.state.addonData.photos !== []) ? false : true;
|
||||
const nextPhotosDisabled = !(
|
||||
this.state.addonData.photos !== '' && this.state.addonData.photos !== []
|
||||
);
|
||||
const addPhotos = (
|
||||
<>
|
||||
<h3>{getMessage('modals.main.addons.create.photos.title')}</h3>
|
||||
<div className='themesToggleArea'>
|
||||
<div className='options'>
|
||||
<div onClick={() => this.importPhotos()} className='toggle lightTheme' style={{ width: '60%', margin: '10px 0 10px 0' }}>
|
||||
<ExportIcon/>
|
||||
<div className="themesToggleArea">
|
||||
<div className="options">
|
||||
<div
|
||||
onClick={() => this.importPhotos()}
|
||||
className="toggle lightTheme"
|
||||
style={{ width: '60%', margin: '10px 0 10px 0' }}
|
||||
>
|
||||
<ExportIcon />
|
||||
<span>{getMessage('modals.main.addons.create.settings.current')}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<br/>
|
||||
<button onClick={() => this.changeTab(2)} className='uploadbg'>{getMessage('modals.welcome.buttons.previous')}</button>
|
||||
<button onClick={() => this.changeTab(3)} className='uploadbg' style={{ margin: '10px' }} disabled={nextPhotosDisabled}>{getMessage('modals.welcome.buttons.next')}</button>
|
||||
<br />
|
||||
<button onClick={() => this.changeTab(2)} className="uploadbg">
|
||||
{getMessage('modals.welcome.buttons.previous')}
|
||||
</button>
|
||||
<button
|
||||
onClick={() => this.changeTab(3)}
|
||||
className="uploadbg"
|
||||
style={{ margin: '10px' }}
|
||||
disabled={nextPhotosDisabled}
|
||||
>
|
||||
{getMessage('modals.welcome.buttons.next')}
|
||||
</button>
|
||||
</>
|
||||
);
|
||||
|
||||
const downloadAddon = (
|
||||
<>
|
||||
<div className='themesToggleArea'>
|
||||
<div className='options'>
|
||||
<div onClick={() => this.downloadAddon()} className='toggle lightTheme' style={{ width: '60%', margin: '10px 0 10px 0' }}>
|
||||
<ExportIcon/>
|
||||
<span>{getMessage('modals.main.addons.create.finish.download')}</span>
|
||||
<div className="smallBanner">
|
||||
<div className="content">
|
||||
<span className="title" style={{ textTransform: 'capitalize' }}>
|
||||
Next step, Publishing...
|
||||
</span>
|
||||
<span className="subtitle">
|
||||
Visit the Mue Knowledgebase on information on how to publish your newly created addon.
|
||||
</span>
|
||||
</div>
|
||||
<button>
|
||||
Learn More
|
||||
<MdOpenInNew />
|
||||
</button>
|
||||
</div>
|
||||
<SettingsItem final={true}>
|
||||
<div className="themesToggleArea">
|
||||
<div className="options">
|
||||
<div
|
||||
onClick={() => this.downloadAddon()}
|
||||
className="toggle lightTheme"
|
||||
style={{ width: '60%', margin: '10px 0 10px 0' }}
|
||||
>
|
||||
<ExportIcon />
|
||||
<span>{getMessage('modals.main.addons.create.finish.download')}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</SettingsItem>
|
||||
<div className="createButtons">
|
||||
<button
|
||||
onClick={() =>
|
||||
this.changeTab(
|
||||
this.state.addonMetadata.type === 'quote_api'
|
||||
? 'quotes'
|
||||
: this.state.addonMetadata.type,
|
||||
)
|
||||
}
|
||||
className="uploadbg"
|
||||
disabled={nextDescriptionDisabled}
|
||||
>
|
||||
{getMessage('modals.welcome.buttons.previous')}
|
||||
</button>
|
||||
</div>
|
||||
<br/>
|
||||
<button onClick={() => this.changeTab((this.state.addonMetadata.type === 'quote_api') ? 'quotes' : this.state.addonMetadata.type)} className='uploadbg' style={{ marginRight: '10px' }}>{getMessage('modals.welcome.buttons.previous')}</button>
|
||||
{/*<button
|
||||
onClick={() =>
|
||||
this.changeTab(
|
||||
this.state.addonMetadata.type === 'quote_api'
|
||||
? 'quotes'
|
||||
: this.state.addonMetadata.type,
|
||||
)
|
||||
}
|
||||
className="uploadbg"
|
||||
style={{ marginRight: '10px' }}
|
||||
>
|
||||
{getMessage('modals.welcome.buttons.previous')}
|
||||
</button>*/}
|
||||
</>
|
||||
);
|
||||
|
||||
switch (this.state.currentTab) {
|
||||
case 2: tabContent = writeDescription; break;
|
||||
case 'settings': tabContent = importSettings; break;
|
||||
case 'quotes': tabContent = addQuotes; break;
|
||||
case 'photos': tabContent = addPhotos; break;
|
||||
case 3: tabContent = downloadAddon; break;
|
||||
default: tabContent = chooseType;
|
||||
case 2:
|
||||
tabContent = writeDescription;
|
||||
break;
|
||||
case 'settings':
|
||||
tabContent = importSettings;
|
||||
break;
|
||||
case 'quotes':
|
||||
tabContent = addQuotes;
|
||||
break;
|
||||
case 'photos':
|
||||
tabContent = addPhotos;
|
||||
break;
|
||||
case 3:
|
||||
tabContent = downloadAddon;
|
||||
break;
|
||||
default:
|
||||
tabContent = chooseType;
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<h2>{getMessage('modals.main.addons.create.other_title')}</h2>
|
||||
<div className="flexTopMarketplace">
|
||||
{this.state.currentTab !== 1 && (
|
||||
<div className="returnButton">
|
||||
<Tooltip title="back" key="cheese">
|
||||
<MdArrowBack
|
||||
className="backArrow"
|
||||
onClick={() => this.changeTab(this.state.currentTab - 1)}
|
||||
/>
|
||||
</Tooltip>
|
||||
</div>
|
||||
)}
|
||||
<span className="mainTitle">{getMessage('modals.main.addons.create.other_title')}</span>
|
||||
</div>
|
||||
{tabContent}
|
||||
</>
|
||||
);
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
import variables from 'modules/variables';
|
||||
import { PureComponent } from 'react';
|
||||
import { toast } from 'react-toastify';
|
||||
import { MdWifiOff, MdLocalMall } from 'react-icons/md';
|
||||
import { MdWifiOff, MdLocalMall, MdArrowBack } from 'react-icons/md';
|
||||
|
||||
import Tooltip from '../../../../helpers/tooltip/Tooltip';
|
||||
|
||||
import Item from '../Item';
|
||||
import Items from '../Items';
|
||||
|
@ -19,11 +21,20 @@ export default class Marketplace extends PureComponent {
|
|||
button: '',
|
||||
featured: {},
|
||||
done: false,
|
||||
item: {}
|
||||
item: {},
|
||||
collection: false,
|
||||
};
|
||||
this.buttons = {
|
||||
uninstall: <button className='removeFromMue' onClick={() => this.manage('uninstall')}>{this.getMessage('modals.main.marketplace.product.buttons.remove')}</button>,
|
||||
install: <button className='addToMue' onClick={() => this.manage('install')}>{this.getMessage('modals.main.marketplace.product.buttons.addtomue')}</button>
|
||||
uninstall: (
|
||||
<button onClick={() => this.manage('uninstall')}>
|
||||
{this.getMessage('modals.main.marketplace.product.buttons.remove')}
|
||||
</button>
|
||||
),
|
||||
install: (
|
||||
<button onClick={() => this.manage('install')}>
|
||||
{this.getMessage('modals.main.marketplace.product.buttons.addtomue')}
|
||||
</button>
|
||||
),
|
||||
};
|
||||
this.controller = new AbortController();
|
||||
}
|
||||
|
@ -33,7 +44,15 @@ export default class Marketplace extends PureComponent {
|
|||
let info;
|
||||
// get item info
|
||||
try {
|
||||
info = await (await fetch(`${variables.constants.MARKETPLACE_URL}/item/${this.props.type}/${data}`, { signal: this.controller.signal })).json();
|
||||
let type = this.props.type;
|
||||
if (type === 'all') {
|
||||
type = data.type;
|
||||
}
|
||||
info = await (
|
||||
await fetch(`${variables.constants.MARKETPLACE_URL}/item/${type}/${data.name}`, {
|
||||
signal: this.controller.signal,
|
||||
})
|
||||
).json();
|
||||
} catch (e) {
|
||||
if (this.controller.signal.aborted === false) {
|
||||
return toast(this.getMessage('toasts.error'));
|
||||
|
@ -73,22 +92,50 @@ export default class Marketplace extends PureComponent {
|
|||
icon: info.data.screenshot_url,
|
||||
data: info.data,
|
||||
addonInstalled,
|
||||
addonInstalledVersion
|
||||
addonInstalledVersion,
|
||||
api_name: data.name,
|
||||
},
|
||||
button: button
|
||||
button: button,
|
||||
});
|
||||
|
||||
variables.stats.postEvent('marketplace-item', `${this.state.item.display_name} viewed`);
|
||||
} else if (type === 'collection') {
|
||||
this.setState({
|
||||
done: false,
|
||||
});
|
||||
const collection = await (
|
||||
await fetch(`${variables.constants.MARKETPLACE_URL}/collection/${data}`, {
|
||||
signal: this.controller.signal,
|
||||
})
|
||||
).json();
|
||||
this.setState({
|
||||
items: collection.data.items,
|
||||
collection: true,
|
||||
done: true,
|
||||
});
|
||||
} else {
|
||||
this.setState({
|
||||
item: {}
|
||||
item: {},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
async getItems() {
|
||||
const { data } = await (await fetch(variables.constants.MARKETPLACE_URL + '/items/' + this.props.type, { signal: this.controller.signal })).json();
|
||||
const featured = await (await fetch(variables.constants.MARKETPLACE_URL + '/featured', { signal: this.controller.signal })).json();
|
||||
const { data } = await (
|
||||
await fetch(variables.constants.MARKETPLACE_URL + '/items/' + this.props.type, {
|
||||
signal: this.controller.signal,
|
||||
})
|
||||
).json();
|
||||
const featured = await (
|
||||
await fetch(variables.constants.MARKETPLACE_URL + '/featured', {
|
||||
signal: this.controller.signal,
|
||||
})
|
||||
).json();
|
||||
const collections = await (
|
||||
await fetch(variables.constants.MARKETPLACE_URL + '/collections', {
|
||||
signal: this.controller.signal,
|
||||
})
|
||||
).json();
|
||||
|
||||
if (this.controller.signal.aborted === true) {
|
||||
return;
|
||||
|
@ -98,7 +145,8 @@ export default class Marketplace extends PureComponent {
|
|||
items: data,
|
||||
oldItems: data,
|
||||
featured: featured.data,
|
||||
done: true
|
||||
collections: collections.data,
|
||||
done: true,
|
||||
});
|
||||
|
||||
this.sortMarketplace(localStorage.getItem('sortMarketplace'), false);
|
||||
|
@ -113,11 +161,14 @@ export default class Marketplace extends PureComponent {
|
|||
|
||||
toast(this.getMessage('toasts.' + type + 'ed'));
|
||||
this.setState({
|
||||
button: (type === 'install') ? this.buttons.uninstall : this.buttons.install
|
||||
button: type === 'install' ? this.buttons.uninstall : this.buttons.install,
|
||||
});
|
||||
|
||||
variables.stats.postEvent('marketplace-item', `${this.state.item.display_name} ${(type === 'install' ? 'installed': 'uninstalled')}`);
|
||||
variables.stats.postEvent('marketplace', (type === 'install' ? 'Install': 'Uninstall'));
|
||||
variables.stats.postEvent(
|
||||
'marketplace-item',
|
||||
`${this.state.item.display_name} ${type === 'install' ? 'installed' : 'uninstalled'}`,
|
||||
);
|
||||
variables.stats.postEvent('marketplace', type === 'install' ? 'Install' : 'Uninstall');
|
||||
}
|
||||
|
||||
sortMarketplace(value, sendEvent) {
|
||||
|
@ -140,7 +191,7 @@ export default class Marketplace extends PureComponent {
|
|||
|
||||
this.setState({
|
||||
items: items,
|
||||
sortType: value
|
||||
sortType: value,
|
||||
});
|
||||
|
||||
if (sendEvent) {
|
||||
|
@ -148,6 +199,13 @@ export default class Marketplace extends PureComponent {
|
|||
}
|
||||
}
|
||||
|
||||
returnToMain() {
|
||||
this.setState({
|
||||
items: this.state.oldItems,
|
||||
collection: false,
|
||||
});
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
if (navigator.onLine === false || localStorage.getItem('offlineMode') === 'true') {
|
||||
return;
|
||||
|
@ -164,24 +222,31 @@ export default class Marketplace extends PureComponent {
|
|||
render() {
|
||||
const errorMessage = (msg) => {
|
||||
return (
|
||||
<div className='emptyitems'>
|
||||
<div className='emptyMessage'>
|
||||
{msg}
|
||||
</div>
|
||||
<div className="emptyItems">
|
||||
<div className="emptyMessage">{msg}</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
if (navigator.onLine === false || localStorage.getItem('offlineMode') === 'true') {
|
||||
return errorMessage(<>
|
||||
<MdWifiOff/>
|
||||
<h1>{this.getMessage('modals.main.marketplace.offline.title')}</h1>
|
||||
<p className='description'>{this.getMessage('modals.main.marketplace.offline.description')}</p>
|
||||
</>);
|
||||
return errorMessage(
|
||||
<>
|
||||
<MdWifiOff />
|
||||
<h1>{this.getMessage('modals.main.marketplace.offline.title')}</h1>
|
||||
<p className="description">
|
||||
{this.getMessage('modals.main.marketplace.offline.description')}
|
||||
</p>
|
||||
</>,
|
||||
);
|
||||
}
|
||||
|
||||
if (this.state.done === false) {
|
||||
return errorMessage(<h1>{this.getMessage('modals.main.loading')}</h1>);
|
||||
return errorMessage(
|
||||
<div className="loaderHolder">
|
||||
<div id="loader"></div>
|
||||
<span className="subtitle">Just be a sec.</span>
|
||||
</div>,
|
||||
);
|
||||
}
|
||||
|
||||
const featured = () => {
|
||||
|
@ -191,40 +256,79 @@ export default class Marketplace extends PureComponent {
|
|||
};
|
||||
|
||||
return (
|
||||
<div className='featured' style={{ backgroundColor: this.state.featured.colour }}>
|
||||
<div className="featured" style={{ backgroundColor: this.state.featured.colour }}>
|
||||
<p>{this.state.featured.title}</p>
|
||||
<h1>{this.state.featured.name}</h1>
|
||||
<button className='addToMue' onClick={() => openFeatured()}>{this.state.featured.buttonText}</button>
|
||||
<button className="addToMue" onClick={() => openFeatured()}>
|
||||
{this.state.featured.buttonText}
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
if (this.state.items.length === 0) {
|
||||
return (
|
||||
<>
|
||||
{featured()}
|
||||
{errorMessage(<>
|
||||
<MdLocalMall/>
|
||||
<h1>{this.getMessage('modals.main.addons.empty.title')}</h1>
|
||||
<p className='description'>{this.getMessage('modals.main.marketplace.no_items')}</p>
|
||||
</>)}
|
||||
{errorMessage(
|
||||
<>
|
||||
<MdLocalMall />
|
||||
<h1>{this.getMessage('modals.main.addons.empty.title')}</h1>
|
||||
<p className="description">{this.getMessage('modals.main.marketplace.no_items')}</p>
|
||||
</>,
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
if (this.state.item.display_name) {
|
||||
return <Item data={this.state.item} button={this.state.button} toggleFunction={() => this.toggle()} addonInstalled={this.state.item.addonInstalled} addonInstalledVersion={this.state.item.addonInstalledVersion}/>;
|
||||
return (
|
||||
<Item
|
||||
data={this.state.item}
|
||||
button={this.state.button}
|
||||
toggleFunction={() => this.toggle()}
|
||||
addonInstalled={this.state.item.addonInstalled}
|
||||
addonInstalledVersion={this.state.item.addonInstalledVersion}
|
||||
icon={this.state.item.screenshot_url}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
{featured()}
|
||||
<br/>
|
||||
<Dropdown label={this.getMessage('modals.main.addons.sort.title')} name='sortMarketplace' onChange={(value) => this.sortMarketplace(value)}>
|
||||
<option value='a-z'>{this.getMessage('modals.main.addons.sort.a_z')}</option>
|
||||
<option value='z-a'>{this.getMessage('modals.main.addons.sort.z_a')}</option>
|
||||
</Dropdown>
|
||||
<Items items={this.state.items} toggleFunction={(input) => this.toggle('item', input)} />
|
||||
{this.state.collection === true ? (
|
||||
<>
|
||||
<div className="flexTopMarketplace">
|
||||
<div className="returnButton">
|
||||
<Tooltip title="back" key="cheese">
|
||||
<MdArrowBack className="backArrow" onClick={() => this.returnToMain()} />
|
||||
</Tooltip>
|
||||
</div>
|
||||
<span className="mainTitle">Marketplace</span>
|
||||
</div>
|
||||
</>
|
||||
) : (
|
||||
<span className="mainTitle">Marketplace</span>
|
||||
)}
|
||||
{/*{featured()}*/}
|
||||
<div className="filter">
|
||||
<Dropdown
|
||||
label={this.getMessage('modals.main.addons.sort.title')}
|
||||
name="sortMarketplace"
|
||||
onChange={(value) => this.sortMarketplace(value)}
|
||||
>
|
||||
<option value="a-z">{this.getMessage('modals.main.addons.sort.a_z')}</option>
|
||||
<option value="z-a">{this.getMessage('modals.main.addons.sort.z_a')}</option>
|
||||
</Dropdown>
|
||||
</div>
|
||||
<Items
|
||||
type={this.props.type}
|
||||
items={this.state.items}
|
||||
collections={this.state.collections}
|
||||
onCollection={this.state.collection}
|
||||
toggleFunction={(input) => this.toggle('item', input)}
|
||||
collectionFunction={(input) => this.toggle('collection', input)}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -17,8 +17,8 @@ export default class Sideload extends PureComponent {
|
|||
super(props);
|
||||
this.state = {
|
||||
showFailed: false,
|
||||
failedReason: ''
|
||||
}
|
||||
failedReason: '',
|
||||
};
|
||||
}
|
||||
|
||||
installAddon(input) {
|
||||
|
@ -31,16 +31,27 @@ export default class Sideload extends PureComponent {
|
|||
failedReason = this.getMessage('modals.main.addons.sideload.errors.no_type');
|
||||
} else if (!input.version) {
|
||||
failedReason = this.getMessage('modals.main.addons.sideload.errors.no_version');
|
||||
} else if (input.type === 'photos' && (!input.photos || !input.photos.length || !input.photos[0].url || !input.photos[0].url.default || !input.photos[0].photographer || !input.photos[0].location)) {
|
||||
} else if (
|
||||
input.type === 'photos' &&
|
||||
(!input.photos ||
|
||||
!input.photos.length ||
|
||||
!input.photos[0].url ||
|
||||
!input.photos[0].url.default ||
|
||||
!input.photos[0].photographer ||
|
||||
!input.photos[0].location)
|
||||
) {
|
||||
failedReason = this.getMessage('modals.main.addons.sideload.errors.invalid_photos');
|
||||
} else if (input.type === 'quotes' && (!input.quotes || !input.quotes.length || !input.quotes[0].quote || !input.quotes[0].author)) {
|
||||
} else if (
|
||||
input.type === 'quotes' &&
|
||||
(!input.quotes || !input.quotes.length || !input.quotes[0].quote || !input.quotes[0].author)
|
||||
) {
|
||||
failedReason = this.getMessage('modals.main.addons.sideload.errors.invalid_quotes');
|
||||
}
|
||||
|
||||
if (failedReason !== '') {
|
||||
return this.setState({
|
||||
return this.setState({
|
||||
failedReason,
|
||||
showFailed: true
|
||||
showFailed: true,
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -48,18 +59,39 @@ export default class Sideload extends PureComponent {
|
|||
toast(this.getMessage('toasts.installed'));
|
||||
variables.stats.postEvent('marketplace', 'Sideload');
|
||||
}
|
||||
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div className='emptyitems'>
|
||||
<div className='emptyMessage'>
|
||||
<FileUpload id='file-input' type='settings' accept='application/json' loadFunction={(e) => this.installAddon(JSON.parse(e.target.result))} />
|
||||
<div className="emptyItems">
|
||||
<div className="emptyMessage">
|
||||
<FileUpload
|
||||
id="file-input"
|
||||
type="settings"
|
||||
accept="application/json"
|
||||
loadFunction={(e) => this.installAddon(JSON.parse(e.target.result))}
|
||||
/>
|
||||
<MdIntegrationInstructions />
|
||||
<h1>{this.getMessage('modals.main.addons.sideload.title')}</h1>
|
||||
<button className='addToMue sideload' onClick={() => document.getElementById('file-input').click()}>{this.getMessage('modals.main.settings.sections.background.source.upload')}</button>
|
||||
<span className="title">{this.getMessage('modals.main.addons.sideload.title')}</span>
|
||||
<span className="subtitle">idk something about it</span>
|
||||
<button
|
||||
className="addToMue sideload"
|
||||
onClick={() => document.getElementById('file-input').click()}
|
||||
>
|
||||
{this.getMessage('modals.main.settings.sections.background.source.upload')}
|
||||
</button>
|
||||
</div>
|
||||
<Modal closeTimeoutMS={100} onRequestClose={() => this.setState({ showFailed: false })} isOpen={this.state.showFailed} className='Modal resetmodal mainModal sideloadModal' overlayClassName='Overlay resetoverlay' ariaHideApp={false}>
|
||||
<SideloadFailedModal modalClose={() => this.setState({ showFailed: false })} reason={this.state.failedReason}/>
|
||||
<Modal
|
||||
closeTimeoutMS={100}
|
||||
onRequestClose={() => this.setState({ showFailed: false })}
|
||||
isOpen={this.state.showFailed}
|
||||
className="Modal resetmodal mainModal sideloadModal"
|
||||
overlayClassName="Overlay resetoverlay"
|
||||
ariaHideApp={false}
|
||||
>
|
||||
<SideloadFailedModal
|
||||
modalClose={() => this.setState({ showFailed: false })}
|
||||
reason={this.state.failedReason}
|
||||
/>
|
||||
</Modal>
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
@import '../../../../scss/variables';
|
||||
@import 'scss/variables';
|
||||
|
||||
@import 'modules/sidebar';
|
||||
@import 'modules/navbar';
|
||||
|
@ -11,42 +11,6 @@
|
|||
|
||||
@import 'marketplace/main';
|
||||
|
||||
.Modal {
|
||||
color: var(--modal-text);
|
||||
background-color: var(--background);
|
||||
box-shadow: 0 0 20px rgba(0, 0, 0, 0.3);
|
||||
border: none;
|
||||
opacity: 1;
|
||||
z-index: -2;
|
||||
transition-timing-function: ease-in;
|
||||
border-radius: map-get($modal, 'border-radius');
|
||||
user-select: none;
|
||||
scrollbar-width: thin;
|
||||
scrollbar-color: #34495e #bdc3c7;
|
||||
position: relative;
|
||||
|
||||
&:focus {
|
||||
outline: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.closeModal {
|
||||
position: absolute;
|
||||
top: 1rem;
|
||||
right: 2rem;
|
||||
font-size: 4em;
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
color: grey;
|
||||
}
|
||||
}
|
||||
|
||||
.ReactModal__Html--open,
|
||||
.ReactModal__Body--open {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.Overlay {
|
||||
position: fixed;
|
||||
z-index: 100;
|
||||
|
@ -56,18 +20,53 @@
|
|||
bottom: 0;
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
justify-content: center;
|
||||
display: grid;
|
||||
place-items: center;
|
||||
}
|
||||
|
||||
.ReactModal__Content {
|
||||
box-shadow: 0 0 30px 0 rgba(0, 0, 0, 0.25);
|
||||
overflow-y: auto;
|
||||
position: relative;
|
||||
.Modal {
|
||||
@include themed() {
|
||||
color: t($color);
|
||||
}
|
||||
box-shadow: 0 0 20px rgba(0, 0, 0, 0.3);
|
||||
opacity: 1;
|
||||
z-index: -2;
|
||||
transition-timing-function: ease-in;
|
||||
border-radius: map-get($modal, 'border-radius');
|
||||
user-select: none;
|
||||
|
||||
overflow-y: auto;
|
||||
transform: scale(0);
|
||||
transition: all 300ms cubic-bezier(0.47, 1.64, 0.41, 0.8);
|
||||
transition: all 0.3s cubic-bezier(0.47, 1.64, 0.41, 0.8);
|
||||
|
||||
&:focus {
|
||||
outline: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.closePositioning {
|
||||
position: absolute;
|
||||
top: 3rem;
|
||||
right: 3rem;
|
||||
}
|
||||
|
||||
.closeModal {
|
||||
display: grid;
|
||||
place-items: center;
|
||||
padding: 0.5em;
|
||||
border-radius: 12px;
|
||||
cursor: pointer;
|
||||
svg {
|
||||
font-size: 2em;
|
||||
}
|
||||
&:hover {
|
||||
background: rgba(121, 121, 121, 0.226);
|
||||
}
|
||||
}
|
||||
|
||||
.ReactModal__Html--open,
|
||||
.ReactModal__Body--open {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* modal transition */
|
||||
|
@ -81,33 +80,9 @@
|
|||
transform: scale(0);
|
||||
}
|
||||
|
||||
@media only screen and (max-height: 700px) {
|
||||
.ReactModal__Content {
|
||||
min-height: 500px;
|
||||
max-height: calc(100vh - 30vh);
|
||||
}
|
||||
}
|
||||
|
||||
/* main modal */
|
||||
.mainModal {
|
||||
padding: 25px;
|
||||
}
|
||||
|
||||
#modal {
|
||||
position: absolute;
|
||||
margin: auto;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
height: 80%;
|
||||
width: 60%;
|
||||
}
|
||||
|
||||
@media (max-width: 1700px) {
|
||||
#modal {
|
||||
width: 80% !important;
|
||||
}
|
||||
height: 80vh;
|
||||
width: clamp(60vw, 1200px, 90vw);
|
||||
}
|
||||
|
||||
/* fixes for font size on extension */
|
||||
|
@ -130,12 +105,80 @@ h5 {
|
|||
font-size: 0.8rem;
|
||||
}
|
||||
|
||||
.tab-content {
|
||||
hr {
|
||||
height: 5px;
|
||||
background: rgba(196, 196, 196, 0.74);
|
||||
outline: none;
|
||||
border: none;
|
||||
margin: 50px 0 30px 0;
|
||||
.loaderHolder {
|
||||
display: flex;
|
||||
gap: 15px;
|
||||
flex-flow: column;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
#loader {
|
||||
display: inline-block;
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
@include themed() {
|
||||
border: 3px solid t($modal-sidebar);
|
||||
border-radius: 50%;
|
||||
border-top-color: t($modal-sidebarActive);
|
||||
}
|
||||
}
|
||||
animation: spin 1s ease-in-out infinite;
|
||||
-webkit-animation: spin 1s ease-in-out infinite;
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
to {
|
||||
-webkit-transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
@-webkit-keyframes spin {
|
||||
to {
|
||||
-webkit-transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
.headerExtras {
|
||||
display: flex;
|
||||
flex-flow: column;
|
||||
gap: -1px;
|
||||
.link {
|
||||
display: flex;
|
||||
flex-flow: row;
|
||||
gap: 15px;
|
||||
align-items: center;
|
||||
&:hover {
|
||||
opacity: .8;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.languageSettings {
|
||||
margin-bottom: 15px;
|
||||
.MuiFormGroup-root {
|
||||
gap: 5px;
|
||||
}
|
||||
.MuiFormControl-root {
|
||||
width: 100% !important;
|
||||
gap: 15px;
|
||||
.MuiFormControlLabel-root {
|
||||
display: flex;
|
||||
flex-direction: row-reverse;
|
||||
justify-content: space-between;
|
||||
padding: 5px 5px 5px 20px;
|
||||
@include themed() {
|
||||
background: t($modal-sidebar);
|
||||
border-radius: t($borderRadius);
|
||||
&:hover {
|
||||
background: t($modal-sidebarActive);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.sliderTitle {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
padding: 15px 0 15px 0;
|
||||
}
|
||||
|
|
|
@ -2,58 +2,157 @@
|
|||
@import 'modules/buttons';
|
||||
@import 'modules/featured';
|
||||
@import 'modules/lightbox';
|
||||
@import '../../../../../scss/variables';
|
||||
|
||||
.items {
|
||||
display: inline-grid;
|
||||
grid-template-columns: repeat(4, 1fr);
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
gap: 15px;
|
||||
margin-top: 15px;
|
||||
|
||||
.item {
|
||||
position: relative;
|
||||
border-radius: 12px;
|
||||
height: 80px;
|
||||
height: 70px;
|
||||
width: 260px;
|
||||
background: var(--sidebar);
|
||||
padding: 10px;
|
||||
cursor: pointer;
|
||||
margin-right: 20px;
|
||||
margin-top: 20px;
|
||||
|
||||
img {
|
||||
height: 80px;
|
||||
width: 80px;
|
||||
border-radius: 12px 0 0 12px;
|
||||
background: white;
|
||||
}
|
||||
|
||||
h4 {
|
||||
font-size: 20px;
|
||||
line-height: 20px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
img,
|
||||
.details {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
.details {
|
||||
position: absolute;
|
||||
left: 85px;
|
||||
top: -15px;
|
||||
|
||||
img {
|
||||
margin-left: 10px;
|
||||
height: 15px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 15px;
|
||||
transition: 0.5s;
|
||||
@include themed() {
|
||||
background: t($modal-sidebar);
|
||||
box-shadow: 0 0 0 1px t($modal-sidebarActive);
|
||||
&:hover {
|
||||
background: t($modal-sidebarActive);
|
||||
}
|
||||
}
|
||||
|
||||
p {
|
||||
margin-top: 5px;
|
||||
line-height: 20px;
|
||||
.tags {
|
||||
margin-top: 7px;
|
||||
}
|
||||
img {
|
||||
height: 80% !important;
|
||||
width: auto !important;
|
||||
border-radius: 12px;
|
||||
@include themed() {
|
||||
background: t($modal-sidebar);
|
||||
}
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
.card-details {
|
||||
display: flex;
|
||||
flex-flow: column;
|
||||
.card-title {
|
||||
font-size: 18px;
|
||||
}
|
||||
.card-subtitle {
|
||||
font-size: 12px;
|
||||
@include themed() {
|
||||
color: t($subColor);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.itemPage {
|
||||
display: flex;
|
||||
flex-flow: row;
|
||||
justify-content: space-between;
|
||||
.itemShowcase {
|
||||
display: flex;
|
||||
flex-flow: column;
|
||||
gap: 15px;
|
||||
width: 50%;
|
||||
.description {
|
||||
max-lines: 3;
|
||||
font-size: 16px;
|
||||
}
|
||||
img {
|
||||
width: 100%;
|
||||
height: auto;
|
||||
}
|
||||
}
|
||||
.itemInfo {
|
||||
display: flex;
|
||||
flex-flow: column;
|
||||
gap: 15px;
|
||||
width: 170px;
|
||||
img {
|
||||
width: 100%;
|
||||
height: auto;
|
||||
border-radius: 12px;
|
||||
@include themed() {
|
||||
box-shadow: 0 0 0 3px t($modal-sidebarActive);
|
||||
}
|
||||
}
|
||||
.divider {
|
||||
text-transform: uppercase;
|
||||
@include themed() {
|
||||
color: t($subColor);
|
||||
}
|
||||
}
|
||||
.iconButtons {
|
||||
display: flex;
|
||||
flex-flow: row;
|
||||
justify-content: space-between;
|
||||
svg {
|
||||
@include basicIconButton(11px, 1.3rem, modal);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.tags {
|
||||
display: flex;
|
||||
flex-flow: row;
|
||||
flex-wrap: wrap;
|
||||
gap: 15px;
|
||||
align-items: center;
|
||||
}
|
||||
.tag {
|
||||
padding: 2px 10px 2px 10px;
|
||||
border-radius: 12px;
|
||||
font-size: 12px;
|
||||
display: grid;
|
||||
place-items: center;
|
||||
@include themed() {
|
||||
background: t($modal-sidebar);
|
||||
box-shadow: 0 0 0 3px t($modal-sidebarActive);
|
||||
span {
|
||||
&:before {
|
||||
content: '#';
|
||||
color: t($subColor);
|
||||
margin-right: 5px;
|
||||
}
|
||||
}
|
||||
&:hover {
|
||||
background: var(--tab-active);
|
||||
background: t($modal-sidebarActive);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.moreTag {
|
||||
padding: 2px 10px 2px 10px;
|
||||
border-radius: 12px;
|
||||
font-size: 12px;
|
||||
display: grid;
|
||||
place-items: center;
|
||||
@include themed() {
|
||||
background: t($modal-sidebar);
|
||||
box-shadow: 0 0 0 3px t($modal-sidebarActive);
|
||||
span {
|
||||
&:before {
|
||||
content: '+';
|
||||
color: t($subColor);
|
||||
margin-right: 5px;
|
||||
}
|
||||
}
|
||||
&:hover {
|
||||
background: t($modal-sidebarActive);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -76,29 +175,27 @@
|
|||
}
|
||||
}
|
||||
|
||||
.emptyitems {
|
||||
width: 25vw;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
margin-top: 90px;
|
||||
.emptyItems {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: grid;
|
||||
place-items: center;
|
||||
}
|
||||
|
||||
.emptyMessage {
|
||||
text-align: center;
|
||||
background: var(--sidebar);
|
||||
padding: 25px;
|
||||
border-radius: 30px;
|
||||
box-shadow: 0 0 10px rgb(0 0 0 / 30%);
|
||||
position: absolute;
|
||||
width: 300px;
|
||||
|
||||
h1 {
|
||||
font-size: 2rem;
|
||||
}
|
||||
|
||||
svg {
|
||||
font-size: 50px;
|
||||
margin-bottom: -20px;
|
||||
display: flex;
|
||||
flex-flow: column;
|
||||
align-items: center;
|
||||
gap: 15px;
|
||||
@include themed() {
|
||||
padding: 45px;
|
||||
border-radius: t($borderRadius);
|
||||
background: t($modal-sidebar);
|
||||
box-shadow: 0 0 0 4px t($modal-sidebarActive);
|
||||
svg {
|
||||
font-size: 50px;
|
||||
color: t($subColor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -106,9 +203,9 @@ p.author {
|
|||
margin-top: -5px;
|
||||
}
|
||||
|
||||
#item>img,
|
||||
.updateimage,
|
||||
.updatechangelog>p>img {
|
||||
#item > img,
|
||||
.updateImage,
|
||||
.updateChangelog > p > img {
|
||||
border-radius: 12px;
|
||||
height: 200px;
|
||||
width: auto;
|
||||
|
@ -122,8 +219,142 @@ p.author {
|
|||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
@media (max-height: 1080px) {
|
||||
@media (max-height: 1080px) {
|
||||
.dropdownsortAddons {
|
||||
margin-top: 40px !important;
|
||||
}
|
||||
}
|
||||
|
||||
.returnButton {
|
||||
display: grid;
|
||||
place-items: center;
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
border-radius: 12px;
|
||||
cursor: pointer;
|
||||
margin-right: 25px;
|
||||
svg {
|
||||
font-size: 2em;
|
||||
}
|
||||
&:hover {
|
||||
background: rgba(121, 121, 121, 0.226);
|
||||
}
|
||||
}
|
||||
|
||||
.flexTopMarketplace {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.itemWarning {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
@include themed() {
|
||||
background: t($modal-sidebar);
|
||||
box-shadow: 0 0 0 4px t($modal-sidebarActive);
|
||||
border-radius: t($borderRadius);
|
||||
padding: 15px;
|
||||
}
|
||||
.topRow {
|
||||
display: flex;
|
||||
flex-flow: column;
|
||||
align-items: center;
|
||||
}
|
||||
.subtitle {
|
||||
text-align: justify;
|
||||
}
|
||||
}
|
||||
|
||||
.truncate {
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.filter {
|
||||
display: flex;
|
||||
flex-flow: row;
|
||||
padding: 15px;
|
||||
gap: 15px;
|
||||
justify-content: space-between;
|
||||
@include themed() {
|
||||
background: t($modal-sidebar);
|
||||
border-radius: t($borderRadius);
|
||||
box-shadow: 0 0 0 4px t($modal-sidebarActive);
|
||||
}
|
||||
.tags {
|
||||
max-width: 50%;
|
||||
}
|
||||
}
|
||||
|
||||
.collection {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
padding: 15px;
|
||||
margin-top: 15px;
|
||||
background-image: linear-gradient(to left, transparent, #000),
|
||||
url('https://www.gonefullgeek.com/wp-content/uploads/2017/09/RDR2-Banner.jpg');
|
||||
align-items: center;
|
||||
@include themed() {
|
||||
box-shadow: 0 0 0 4px t($modal-sidebarActive);
|
||||
border-radius: t($borderRadius);
|
||||
}
|
||||
.content {
|
||||
display: flex;
|
||||
flex-flow: column;
|
||||
gap: 15px;
|
||||
max-width: 250px;
|
||||
.title {
|
||||
color: #fff !important;
|
||||
}
|
||||
.subtitle {
|
||||
color: #ccc !important;
|
||||
}
|
||||
}
|
||||
.items {
|
||||
justify-content: center;
|
||||
}
|
||||
}
|
||||
|
||||
.smallBanner {
|
||||
button {
|
||||
padding: 0 15px 0 15px;
|
||||
}
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
padding: 15px;
|
||||
margin-top: 15px;
|
||||
align-items: center;
|
||||
@include themed() {
|
||||
box-shadow: 0 0 0 4px t($modal-sidebarActive);
|
||||
border-radius: t($borderRadius);
|
||||
background: t($modal-sidebar);
|
||||
}
|
||||
.content {
|
||||
display: flex;
|
||||
flex-flow: column;
|
||||
gap: 15px;
|
||||
max-width: 250px;
|
||||
}
|
||||
}
|
||||
|
||||
.inCollection {
|
||||
background-image: linear-gradient(to left, transparent, #000),
|
||||
url('https://www.gonefullgeek.com/wp-content/uploads/2017/09/RDR2-Banner.jpg');
|
||||
display: flex;
|
||||
flex-flow: column;
|
||||
gap: 15px;
|
||||
padding: 15px;
|
||||
@include themed() {
|
||||
box-shadow: 0 0 0 4px t($modal-sidebarActive);
|
||||
border-radius: t($borderRadius);
|
||||
}
|
||||
}
|
||||
|
||||
.starWars {
|
||||
background-image: linear-gradient(to left, transparent, #000),
|
||||
url(https://www.broadway.org.uk/sites/default/files/styles/banner_crop/public/2019-10/star-wars-the-rise-of-skywalker-banner-min.jpg?h=639d4ef1&itok=z4KZ-3Tt);
|
||||
background-size: cover !important;
|
||||
background-repeat: no-repeat !important;
|
||||
background-position: center !important;
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
%storebutton {
|
||||
%storeButton {
|
||||
cursor: pointer;
|
||||
font-size: 18px;
|
||||
display: block;
|
||||
|
@ -14,7 +14,7 @@
|
|||
}
|
||||
}
|
||||
|
||||
.dark %storebutton {
|
||||
.dark %storeButton {
|
||||
border: 2px solid map-get($theme-colours, 'main');
|
||||
color: map-get($theme-colours, 'main');
|
||||
|
||||
|
@ -24,42 +24,11 @@
|
|||
}
|
||||
}
|
||||
|
||||
.removeFromMue {
|
||||
@extend %storebutton;
|
||||
|
||||
border: 2px solid #ff4757;
|
||||
color: #ff4757;
|
||||
float: right;
|
||||
margin-top: -10px;
|
||||
|
||||
&:hover {
|
||||
background: #ff4757;
|
||||
color: map-get($theme-colours, 'main');
|
||||
}
|
||||
}
|
||||
|
||||
.addToMue {
|
||||
@extend %storebutton;
|
||||
|
||||
float: right;
|
||||
margin-top: -10px;
|
||||
}
|
||||
|
||||
.sideload {
|
||||
display: inline;
|
||||
margin-top: 0px;
|
||||
margin-top: 0;
|
||||
float: none !important;
|
||||
}
|
||||
|
||||
button.round {
|
||||
margin-left: 5px;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
border-radius: 50%;
|
||||
text-align: center;
|
||||
line-height: 3px;
|
||||
vertical-align: middle;
|
||||
padding: 10px;
|
||||
width: 200px;
|
||||
}
|
||||
|
||||
.updateCheck {
|
||||
|
|
|
@ -1,10 +1,9 @@
|
|||
.featured {
|
||||
margin-top: 40px;
|
||||
border-radius: 15px;
|
||||
padding: 50px;
|
||||
color: #fff;
|
||||
box-shadow: 0 0 10px rgb(0 0 0 / 30%);
|
||||
width: 85%;
|
||||
width: calc(100% - 6rem);
|
||||
margin-top: 13px;
|
||||
|
||||
button {
|
||||
float: left;
|
||||
|
|
|
@ -1,90 +1,84 @@
|
|||
#item {
|
||||
h1 {
|
||||
font-size: 40px;
|
||||
line-height: 20px;
|
||||
}
|
||||
|
||||
img {
|
||||
float: left;
|
||||
}
|
||||
|
||||
a {
|
||||
color: var(--modal-link);
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
opacity: 0.8;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.side {
|
||||
float: right;
|
||||
margin-left: 20px;
|
||||
}
|
||||
|
||||
#item>h1,
|
||||
#item>svg {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
p.description {
|
||||
margin-top: 0px;
|
||||
margin-top: 0;
|
||||
max-width: 800px;
|
||||
}
|
||||
|
||||
.backArrow {
|
||||
cursor: pointer;
|
||||
width: 2rem !important;
|
||||
height: 2rem !important;
|
||||
|
||||
&:hover {
|
||||
color: grey;
|
||||
}
|
||||
}
|
||||
|
||||
.informationContainer {
|
||||
margin-top: 150px;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.productInformation {
|
||||
padding: 10px;
|
||||
background: var(--sidebar);
|
||||
width: 350px;
|
||||
border-radius: 12px;
|
||||
min-height: 180px;
|
||||
|
||||
h4 {
|
||||
cursor: initial !important;
|
||||
.moreInfo {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
flex-wrap: wrap;
|
||||
width: calc(100% - 30px);
|
||||
gap: 15px;
|
||||
.items {
|
||||
margin-top: 0 !important;
|
||||
}
|
||||
|
||||
li {
|
||||
margin-left: -4px;
|
||||
list-style: none;
|
||||
font-size: 16px;
|
||||
cursor: initial !important;
|
||||
|
||||
&.header {
|
||||
.item {
|
||||
flex: 1 0 40% !important;
|
||||
}
|
||||
@include themed() {
|
||||
background: t($modal-sidebar);
|
||||
box-shadow: 0 0 0 4px t($modal-sidebarActive);
|
||||
border-radius: t($borderRadius);
|
||||
padding: 15px;
|
||||
.infoItem {
|
||||
display: flex;
|
||||
flex-flow: row;
|
||||
align-items: center;
|
||||
gap: 15px;
|
||||
flex: 1 0 44%;
|
||||
svg {
|
||||
font-size: 25px;
|
||||
color: t($subColor);
|
||||
}
|
||||
.text {
|
||||
display: flex;
|
||||
flex-flow: column;
|
||||
}
|
||||
}
|
||||
.header {
|
||||
text-transform: uppercase;
|
||||
color: #787878;
|
||||
margin-left: -5px;
|
||||
color: t($subColor);
|
||||
}
|
||||
span {
|
||||
color: t($color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 1200px) {
|
||||
.side {
|
||||
margin-top: 222px;
|
||||
float: none !important;
|
||||
}
|
||||
|
||||
.overview {
|
||||
margin-top: -160px !important;
|
||||
.itemTitle {
|
||||
font-size: 38px;
|
||||
font-weight: 600;
|
||||
@include themed() {
|
||||
color: t($color);
|
||||
}
|
||||
}
|
||||
|
||||
.overview {
|
||||
font-size: 30px !important;
|
||||
margin-top: 33px;
|
||||
.titleTop {
|
||||
display: flex;
|
||||
flex-flow: column;
|
||||
gap: 3px;
|
||||
}
|
||||
|
||||
.showMore {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 5px;
|
||||
transition: 0.5s;
|
||||
cursor: pointer;
|
||||
@include themed() {
|
||||
&:hover {
|
||||
color: t($subColor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
.lightboxmodal {
|
||||
.lightBoxModal {
|
||||
margin: auto;
|
||||
max-width: 60%;
|
||||
background: none !important;
|
||||
|
|
|
@ -1,17 +1,12 @@
|
|||
.navbar-item {
|
||||
font-size: 22px;
|
||||
font-weight: 500;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
color: var(--photo-info);
|
||||
|
||||
flex-flow: row !important;
|
||||
padding: 0 15px 0 15px;
|
||||
&:hover {
|
||||
svg {
|
||||
background: var(--tab-active);
|
||||
}
|
||||
|
||||
color: var(--modal-text)
|
||||
color: var(--modal-text);
|
||||
}
|
||||
|
||||
span,
|
||||
|
@ -21,9 +16,6 @@
|
|||
|
||||
svg {
|
||||
font-size: 1.2em !important;
|
||||
width: 60px;
|
||||
padding: 5px;
|
||||
border-radius: 20px;
|
||||
color: var(--photo-info);
|
||||
}
|
||||
}
|
||||
|
@ -35,38 +27,21 @@
|
|||
}
|
||||
}
|
||||
|
||||
.modalNavbar {
|
||||
position: absolute;
|
||||
left: 20rem;
|
||||
top: 1rem;
|
||||
justify-content: center;
|
||||
#modal {
|
||||
display: flex;
|
||||
|
||||
svg {
|
||||
margin-right: 0.5rem;
|
||||
padding: 3px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
align-items: flex-start;
|
||||
justify-content: flex-start;
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 1200px) {
|
||||
.modalNavbar {
|
||||
left: 6rem;
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 800px) {
|
||||
li.navbar-item {
|
||||
span {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
.modalNavbar {
|
||||
display: flex;
|
||||
flex-flow: row;
|
||||
gap: 25px;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.navbar-item-active {
|
||||
color: var(--modal-text);
|
||||
|
||||
svg {
|
||||
background: var(--sidebar);
|
||||
@include themed() {
|
||||
background: t($modal-sidebarActive) !important;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,12 +1,17 @@
|
|||
@import '../.../../../../../././../scss/variables';
|
||||
|
||||
::-webkit-scrollbar {
|
||||
width: 6px;
|
||||
height: 6px;
|
||||
border-top-right-radius: map-get($modal, 'border-radius');
|
||||
border-bottom-right-radius: map-get($modal, 'border-radius');
|
||||
border-radius: 12px;
|
||||
@include themed() {
|
||||
background: t($modal-sidebar);
|
||||
}
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb {
|
||||
background: #636e72;
|
||||
border-top-right-radius: map-get($modal, 'border-radius');
|
||||
border-bottom-right-radius: map-get($modal, 'border-radius');
|
||||
@include themed() {
|
||||
background: t($modal-sidebarActive);
|
||||
}
|
||||
border-radius: 12px;
|
||||
}
|
||||
|
|
|
@ -1,87 +1,66 @@
|
|||
ul.sidebar {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
margin: 0;
|
||||
padding-left: 0;
|
||||
background: var(--sidebar);
|
||||
border-radius: 12px 0 0 12px;
|
||||
text-align: left;
|
||||
font-size: 24px;
|
||||
min-height: 110vh;
|
||||
@import '../.../../../../../././../scss/variables';
|
||||
|
||||
h1 {
|
||||
text-align: center;
|
||||
font-size: 1.8em;
|
||||
}
|
||||
.sidebar {
|
||||
@include themed() {
|
||||
top: 0;
|
||||
left: 0;
|
||||
position: sticky;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
background: t($modal-sidebar);
|
||||
border-radius: 12px 0 0 12px;
|
||||
overflow-y: auto;
|
||||
height: 80vh;
|
||||
min-width: 250px;
|
||||
overflow-x: hidden;
|
||||
|
||||
svg {
|
||||
vertical-align: middle;
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
hr {
|
||||
height: 3px;
|
||||
background: rgba(196, 196, 196, 0.74);
|
||||
width: 75%;
|
||||
outline: none;
|
||||
border: none;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-height: 999px) and (min-height: 920px) {
|
||||
ul.sidebar {
|
||||
min-height: 160vh;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-height: 919px) and (min-height: 700px) {
|
||||
ul.sidebar {
|
||||
min-height: 200vh;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-height: 699px) and (min-height: 400px) {
|
||||
ul.sidebar {
|
||||
min-height: 260vh;
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (min-width: 1200px) {
|
||||
ul.sidebar {
|
||||
width: 310px;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
|
||||
li {
|
||||
list-style: none;
|
||||
font-size: 24px;
|
||||
padding: 5px 30px 5px 30px;
|
||||
cursor: pointer;
|
||||
margin-top: 2px;
|
||||
}
|
||||
|
||||
.tab-list-active {
|
||||
background: var(--tab-active);
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 1200px) {
|
||||
li.tab-list-item {
|
||||
span {
|
||||
display: none;
|
||||
svg {
|
||||
margin-left: 20px;
|
||||
margin-right: 20px;
|
||||
color: t($subColor);
|
||||
font-size: 17px;
|
||||
}
|
||||
}
|
||||
|
||||
ul.sidebar {
|
||||
h1 {
|
||||
display: none;
|
||||
hr {
|
||||
height: 1px;
|
||||
background: #ccc;
|
||||
margin: 0 1.75rem 0 1.75rem;
|
||||
border: none;
|
||||
}
|
||||
|
||||
button {
|
||||
color: t($color);
|
||||
font-size: 18px;
|
||||
list-style: none;
|
||||
cursor: pointer;
|
||||
border-radius: 12px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin: 0.2rem;
|
||||
padding: 0.5rem;
|
||||
transition: 0.5s;
|
||||
outline: none;
|
||||
border: none;
|
||||
background: none;
|
||||
min-width: calc(100% - 1.2em);
|
||||
|
||||
&:hover {
|
||||
background: t($modal-sidebarActive);
|
||||
}
|
||||
|
||||
&:active {
|
||||
background: t($modal-sidebarActive);
|
||||
box-shadow: 0 0 0 0.5px t($color);
|
||||
}
|
||||
|
||||
&:focus {
|
||||
background: t($modal-sidebarActive);
|
||||
box-shadow: 0 0 0 0.5px t($color);
|
||||
}
|
||||
}
|
||||
|
||||
.tab-list-active {
|
||||
background: t($modal-sidebarActive);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.tab-list-item {
|
||||
&:hover {
|
||||
background: var(--tab-active);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,43 +1,95 @@
|
|||
@import '../../../../../scss/variables';
|
||||
|
||||
.tab-content {
|
||||
position: absolute;
|
||||
button {
|
||||
@include modal-button(standard);
|
||||
}
|
||||
@include themed() {
|
||||
padding: 1rem 3rem 3rem 3rem;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
background: t($modal-background);
|
||||
@extend %tabText;
|
||||
hr {
|
||||
width: 100%;
|
||||
background: rgba(196, 196, 196, 0.74);
|
||||
outline: none;
|
||||
}
|
||||
.settingsRow {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
min-height: 100px;
|
||||
justify-content: space-between;
|
||||
/*border-top: 1px solid #ccc;*/
|
||||
border-bottom: 1px solid #ccc;
|
||||
padding-top: 1rem;
|
||||
padding-bottom: 1rem;
|
||||
|
||||
h3 {
|
||||
font-size: 1.5rem;
|
||||
margin-bottom: 0;
|
||||
&.settingsNoBorder {
|
||||
border-bottom: none;
|
||||
}
|
||||
.content {
|
||||
display: flex;
|
||||
flex-flow: column;
|
||||
max-width: 50%;
|
||||
}
|
||||
.action {
|
||||
display: flex;
|
||||
flex-flow: column;
|
||||
align-items: flex-end;
|
||||
width: 300px;
|
||||
button {
|
||||
margin-top: 10px;
|
||||
width: 283px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (min-width: 2300px) {
|
||||
.tab-content {
|
||||
left: 350px;
|
||||
top: 7%;
|
||||
.activityButtons {
|
||||
flex-wrap: wrap !important;
|
||||
justify-content: space-between !important;
|
||||
align-items: flex-end !important;
|
||||
align-content: space-between !important;
|
||||
flex-wrap: wrap !important;
|
||||
flex-direction: row !important;
|
||||
button:not(:first-child) {
|
||||
width: 40% !important;
|
||||
height: 99px !important;
|
||||
flex-flow: column-reverse !important;
|
||||
}
|
||||
button {
|
||||
@include modal-button(standard);
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 1920px) {
|
||||
.tab-content {
|
||||
left: 120px;
|
||||
top: 60px;
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (min-width: 1920px) {
|
||||
.tab-content {
|
||||
left: 350px;
|
||||
top: 9%;
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 1400px),
|
||||
(min-width: 1400px) {
|
||||
.tab-content {
|
||||
left: 350px;
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 1200px) {
|
||||
.tab-content {
|
||||
left: 125px;
|
||||
top: 90px;
|
||||
table {
|
||||
@include themed() {
|
||||
margin-top: 20px;
|
||||
tr:first-child {
|
||||
background: t($modal-sidebarActive);
|
||||
th {
|
||||
padding: 1rem;
|
||||
}
|
||||
}
|
||||
tr {
|
||||
th:last-child {
|
||||
display: grid;
|
||||
place-items: center;
|
||||
}
|
||||
}
|
||||
tr:not(:first-child) {
|
||||
background: t($modal-sidebar);
|
||||
textarea {
|
||||
width: 90%;
|
||||
margin: 10px;
|
||||
color: t($color);
|
||||
::placeholder {
|
||||
color: t($color);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
@import '../../../../../scss/modules/buttons';
|
||||
|
||||
@import 'scss/modules/buttons';
|
||||
/*
|
||||
.refresh {
|
||||
@extend %settingsButton;
|
||||
|
||||
|
@ -84,12 +84,8 @@
|
|||
width: 10px !important;
|
||||
}
|
||||
|
||||
.data-buttons-row {
|
||||
width: 350px;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
|
||||
button {
|
||||
/* button {
|
||||
background: var(--sidebar);
|
||||
text-align: center;
|
||||
border-radius: 20px;
|
||||
|
@ -102,20 +98,16 @@
|
|||
flex-direction: column-reverse;
|
||||
align-items: center;
|
||||
color: var(--modal-text);
|
||||
|
||||
svg {
|
||||
font-size: 2em;
|
||||
}
|
||||
transition: 0.5s;
|
||||
|
||||
&:hover {
|
||||
background: var(--tab-active);
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.customvideoicon {
|
||||
position: absolute;
|
||||
margin-bottom: 45px;
|
||||
font-size: 3em !important;
|
||||
}
|
||||
*/
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
@import 'modules/resetmodal';
|
||||
@import 'scss/variables';
|
||||
@import 'modules/material-ui';
|
||||
@import 'modules/reminder';
|
||||
|
||||
|
@ -8,7 +9,7 @@
|
|||
|
||||
input {
|
||||
/* colour picker */
|
||||
&[type=color] {
|
||||
&[type='color'] {
|
||||
border-radius: 100%;
|
||||
height: 30px;
|
||||
width: 30px;
|
||||
|
@ -29,7 +30,7 @@ input {
|
|||
}
|
||||
|
||||
/* firefox fixes for colour picker (using "," didn't work) */
|
||||
&[type=color]::-moz-color-swatch {
|
||||
&[type='color']::-moz-color-swatch {
|
||||
border-radius: 100%;
|
||||
height: 30px;
|
||||
width: 30px;
|
||||
|
@ -50,11 +51,13 @@ input {
|
|||
}
|
||||
|
||||
/* date picker */
|
||||
&[type=date] {
|
||||
width: 280px;
|
||||
color: var(--modal-text);
|
||||
background: var(--background);
|
||||
border: solid var(--modal-text) 1px;
|
||||
&[type='date'] {
|
||||
width: 260px;
|
||||
@include themed() {
|
||||
background: t($modal-sidebar);
|
||||
border: 3px solid t($modal-sidebarActive);
|
||||
color: t($color);
|
||||
}
|
||||
padding: 15px 20px;
|
||||
border-radius: 4px;
|
||||
display: flex !important;
|
||||
|
@ -84,3 +87,72 @@ h4 {
|
|||
padding-right: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.dropzone {
|
||||
@include themed() {
|
||||
background: t($modal-sidebar);
|
||||
border: 3px solid t($modal-sidebarActive);
|
||||
color: t($color);
|
||||
border-radius: 12px;
|
||||
font-size: 1rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-flow: column;
|
||||
justify-content: center;
|
||||
gap: 10px;
|
||||
transition: 0.5s;
|
||||
padding: 45px 25px 45px 25px;
|
||||
svg {
|
||||
font-size: 48px;
|
||||
}
|
||||
.title {
|
||||
font-size: 18px;
|
||||
}
|
||||
&:hover {
|
||||
border-style: dashed;
|
||||
}
|
||||
button {
|
||||
width: 80% !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.statsGrid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
grid-template-rows: repeat(3, 1fr);
|
||||
column-gap: 100px;
|
||||
row-gap: 100px;
|
||||
padding: 25px;
|
||||
div {
|
||||
padding: 25px;
|
||||
@include themed() {
|
||||
padding: 45px;
|
||||
border-radius: t($borderRadius);
|
||||
background: t($modal-sidebar);
|
||||
box-shadow: 0 0 0 4px t($modal-sidebarActive);
|
||||
svg {
|
||||
font-size: 50px;
|
||||
color: t($subColor);
|
||||
}
|
||||
}
|
||||
}
|
||||
div:nth-child(1) {
|
||||
grid-area: 1 / 1 / 3 / 3;
|
||||
}
|
||||
div:nth-child(2) {
|
||||
grid-area: 3 / 1 / 4 / 3;
|
||||
}
|
||||
div:nth-child(3) {
|
||||
grid-area: 1 / 3 / 4 / 4;
|
||||
display: flex;
|
||||
flex-flow: column;
|
||||
gap: 10px;
|
||||
.subtitle {
|
||||
text-transform: capitalize;
|
||||
}
|
||||
span {
|
||||
font-size: 20px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
/* these are overrides for the material ui default styles */
|
||||
|
||||
@import '../../../../../../scss/variables';
|
||||
|
||||
.MuiCheckbox-colorPrimary.Mui-checked,
|
||||
.MuiSwitch-colorPrimary.Mui-checked,
|
||||
.MuIconButton-colorPrimary.Mui-checked,
|
||||
|
@ -9,19 +12,23 @@
|
|||
.aboutLink,
|
||||
.MuiSlider-colorPrimary,
|
||||
legend {
|
||||
color: var(--modal-text) !important;
|
||||
@include themed() {
|
||||
color: t($color) !important;
|
||||
}
|
||||
}
|
||||
|
||||
.MuiFormControlLabel-labelPlacementStart {
|
||||
margin-left: 0px !important;
|
||||
margin-left: 0 !important;
|
||||
}
|
||||
|
||||
.MuiSwitch-colorPrimary.Mui-checked+.MuiSwitch-track {
|
||||
.MuiSwitch-colorPrimary.Mui-checked + .MuiSwitch-track {
|
||||
background: darkgray !important;
|
||||
}
|
||||
|
||||
.MuiIconButton-label>svg.MuiSvgIcon-root {
|
||||
color: var(--modal-text) !important;
|
||||
.MuiIconButton-label > svg.MuiSvgIcon-root {
|
||||
@include themed() {
|
||||
color: t($color) !important;
|
||||
}
|
||||
}
|
||||
|
||||
.MuiTouchRipple-root {
|
||||
|
@ -33,7 +40,9 @@ legend {
|
|||
}
|
||||
|
||||
.checkbox svg {
|
||||
fill: var(--modal-text) !important;
|
||||
@include themed() {
|
||||
fill: t($color) !important;
|
||||
}
|
||||
}
|
||||
|
||||
.radio-title {
|
||||
|
@ -51,11 +60,15 @@ legend {
|
|||
}
|
||||
|
||||
.MuiOutlinedInput-notchedOutline {
|
||||
border-color: var(--modal-text) !important;
|
||||
@include themed() {
|
||||
border-color: t($color) !important;
|
||||
}
|
||||
}
|
||||
|
||||
.MuiFormLabel-root-MuiInputLabel-root {
|
||||
color: var(--modal-text) !important;
|
||||
@include themed() {
|
||||
color: t($color) !important;
|
||||
}
|
||||
}
|
||||
|
||||
.MuiInputLabel-root,
|
||||
|
@ -66,23 +79,28 @@ legend {
|
|||
.Mui-focused,
|
||||
legend,
|
||||
.MuiOutlinedInput-input {
|
||||
color: var(--modal-text) !important;
|
||||
@include themed() {
|
||||
color: t($color) !important;
|
||||
}
|
||||
}
|
||||
|
||||
.MuiMenu-list {
|
||||
background-color: var(--background) !important;
|
||||
color: var(--modal-text) !important;
|
||||
@include themed() {
|
||||
background-color: t($modal-background);
|
||||
color: t($color);
|
||||
}
|
||||
}
|
||||
|
||||
.Mui-selected {
|
||||
background-color: var(--tab-active) !important;
|
||||
@include themed() {
|
||||
background-color: t($modal-sidebarActive) !important;
|
||||
}
|
||||
}
|
||||
|
||||
.MuiTextField-root,
|
||||
.MuiFormControl-root,
|
||||
.MuiSlider-root {
|
||||
width: 300px !important;
|
||||
display: flex !important;
|
||||
}
|
||||
|
||||
.Mui-disabled {
|
||||
|
@ -95,9 +113,31 @@ legend,
|
|||
}
|
||||
|
||||
.MuiPaper-root {
|
||||
background-color: var(--background) !important;
|
||||
@include themed() {
|
||||
background-color: t($modal-background) !important;
|
||||
}
|
||||
}
|
||||
|
||||
.MuiSlider-valueLabel {
|
||||
background-color: var(--tab-active) !important;
|
||||
@include themed() {
|
||||
background-color: t($modal-sidebarActive) !important;
|
||||
}
|
||||
}
|
||||
|
||||
.MuiFormControlLabel-labelPlacementStart {
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
.settingsRow {
|
||||
.MuiFormControlLabel-root {
|
||||
flex-direction: row-reverse;
|
||||
margin-right: 0;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
width: 100%;
|
||||
margin-left: 0;
|
||||
}
|
||||
.MuiFormControlLabel-root {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,14 +1,20 @@
|
|||
@import '../../../../../../scss/variables';
|
||||
|
||||
.reminder-info {
|
||||
position: absolute;
|
||||
bottom: 20px;
|
||||
right: 20px;
|
||||
bottom: 0;
|
||||
padding: 15px;
|
||||
color: var(--modal-text);
|
||||
background: var(--sidebar);
|
||||
max-width: 300px;
|
||||
border-radius: 0.7em;
|
||||
|
||||
h1 {
|
||||
font-size: 1rem;
|
||||
flex-flow: column;
|
||||
gap: 10px;
|
||||
margin: 5px;
|
||||
@extend %tabText;
|
||||
@include themed() {
|
||||
color: t($color);
|
||||
background: t($modal-sidebar);
|
||||
box-shadow: 0 0 0 4px t($modal-sidebarActive);
|
||||
border-radius: t($borderRadius);
|
||||
}
|
||||
button {
|
||||
@include modal-button(standard);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,27 +1,29 @@
|
|||
.resetmodal {
|
||||
min-height: 300px !important;
|
||||
max-width: 300px !important;
|
||||
margin: auto;
|
||||
font-size: 1rem;
|
||||
@import '../../../../../../scss/variables';
|
||||
|
||||
h4 {
|
||||
cursor: initial;
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
}
|
||||
|
||||
.resetfooter {
|
||||
position: absolute;
|
||||
bottom: 20px;
|
||||
width: 300px;
|
||||
justify-content: center;
|
||||
.resetModal {
|
||||
@extend %tabText;
|
||||
display: flex;
|
||||
|
||||
button.reset {
|
||||
margin-right: 43px;
|
||||
flex-flow: column;
|
||||
padding: 2rem;
|
||||
justify-content: center;
|
||||
gap: 15px;
|
||||
@include themed() {
|
||||
background: t($modal-background);
|
||||
}
|
||||
button {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 15px;
|
||||
}
|
||||
button:nth-child(1) {
|
||||
@include basicIconButton(11px, 1.3rem, modal-text);
|
||||
}
|
||||
button:nth-child(2) {
|
||||
@include basicIconButton(11px, 1.3rem, modal);
|
||||
}
|
||||
}
|
||||
|
||||
.resetoverlay {
|
||||
background-color: rgba(0, 0, 0, 0.5);
|
||||
}
|
||||
.resetFooter {
|
||||
display: flex;
|
||||
flex-flow: row;
|
||||
justify-content: space-around;
|
||||
}
|
|
@ -1,16 +1,3 @@
|
|||
.aboutIcon {
|
||||
color: var(--modal-text) !important;
|
||||
padding-right: 10px;
|
||||
|
||||
&:hover {
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
svg {
|
||||
font-size: 1.5em;
|
||||
}
|
||||
}
|
||||
|
||||
.aboutLink {
|
||||
&:hover {
|
||||
opacity: 0.8;
|
||||
|
@ -20,17 +7,28 @@
|
|||
.aboutLogo {
|
||||
height: 100px;
|
||||
width: auto;
|
||||
margin-left: -15px;
|
||||
margin: calc(1rem - 15px) 0 1rem 0;
|
||||
align-self: center;
|
||||
}
|
||||
|
||||
.abouticon {
|
||||
width: 96px;
|
||||
height: auto;
|
||||
border-radius: 50%;
|
||||
padding-right: 5px;
|
||||
.aboutContact {
|
||||
flex-flow: row;
|
||||
display: flex;
|
||||
gap: 15px;
|
||||
a {
|
||||
@include basicIconButton(11px, 1.5rem, modal);
|
||||
}
|
||||
}
|
||||
|
||||
.contacth3 {
|
||||
font-size: 1.5rem;
|
||||
margin-bottom: 0.8em !important;
|
||||
.contributorImages {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 15px;
|
||||
img {
|
||||
width: 75px;
|
||||
height: auto;
|
||||
@include themed() {
|
||||
border-radius: t($borderRadius);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
.updatechangelog {
|
||||
.updateChangelog {
|
||||
max-width: 75%;
|
||||
|
||||
li {
|
||||
|
@ -26,7 +26,7 @@
|
|||
}
|
||||
|
||||
h5 {
|
||||
line-height: 0px !important;
|
||||
line-height: 0 !important;
|
||||
}
|
||||
|
||||
img {
|
||||
|
|
|
@ -1,54 +1,57 @@
|
|||
.sortableitem {
|
||||
background: var(--sidebar) !important;
|
||||
padding: 10px 80px;
|
||||
padding-left: 10px;
|
||||
border-radius: 15px;
|
||||
margin-bottom: 10px;
|
||||
font-size: 1.325rem;
|
||||
color: var(--modal-text) !important;
|
||||
cursor: move;
|
||||
width: 150px;
|
||||
z-index: 999 !important;
|
||||
@import '../../../../../../../scss/variables';
|
||||
|
||||
svg {
|
||||
font-size: 1.3rem;
|
||||
.sortableItem {
|
||||
@include themed() {
|
||||
background: t($modal-sidebar) !important;
|
||||
padding: 10px 80px 10px 10px;
|
||||
border-radius: 15px;
|
||||
margin-bottom: 10px;
|
||||
font-size: 1.325rem;
|
||||
color: t($color) !important;
|
||||
cursor: move;
|
||||
width: 150px;
|
||||
z-index: 999 !important;
|
||||
|
||||
svg {
|
||||
font-size: 1.3rem;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background: t($modal-sidebarActive) !important;
|
||||
}
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background: var(--tab-active) !important;
|
||||
}
|
||||
}
|
||||
ul {
|
||||
padding-left: 0;
|
||||
margin: 0;
|
||||
|
||||
ul {
|
||||
padding-left: 0px;
|
||||
margin: 0;
|
||||
|
||||
>label {
|
||||
vertical-align: middle;
|
||||
> label {
|
||||
vertical-align: middle;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.images-row {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
width: 500px;
|
||||
|
||||
div {
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
background-repeat: no-repeat;
|
||||
background-size: cover;
|
||||
background-position: center;
|
||||
background-color: var(--sidebar);
|
||||
border: 20px solid var(--sidebar);
|
||||
border-radius: 20px;
|
||||
margin: 0 20px 20px 0;
|
||||
@include themed() {
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
justify-content: center;
|
||||
|
||||
svg {
|
||||
font-size: 1.9em;
|
||||
flex-wrap: wrap;
|
||||
gap: 15px;
|
||||
div {
|
||||
background: t($modal-sidebar);
|
||||
padding: 10px;
|
||||
box-shadow: 0 0 0 4px t($modal-sidebarActive);
|
||||
border-radius: t($borderRadius);
|
||||
gap: 10px;
|
||||
img {
|
||||
width: auto;
|
||||
height: 100px;
|
||||
border-radius: t($borderRadius);
|
||||
}
|
||||
}
|
||||
.iconButton {
|
||||
width: calc(100% - 22px);
|
||||
margin-top: 10px;
|
||||
@include basicIconButton(11px, 1.3rem, modal);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -32,7 +32,16 @@ div.color-preview-area > div > div:nth-child(5) {
|
|||
border: 2px solid var(--modal-text) !important;
|
||||
}
|
||||
|
||||
.text-input, .number-input {
|
||||
.text-input,
|
||||
.number-input {
|
||||
background-color: var(--sidebar) !important;
|
||||
color: var(--modal-text) !important;
|
||||
}
|
||||
|
||||
.colourInput {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
flex-flow: row-reverse;
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@ export default class Checkbox extends PureComponent {
|
|||
}
|
||||
|
||||
handleChange = () => {
|
||||
const value = (this.state.checked === true) ? false : true;
|
||||
const value = (this.state.checked !== true);
|
||||
localStorage.setItem(this.props.name, value);
|
||||
|
||||
this.setState({
|
||||
|
@ -28,7 +28,7 @@ export default class Checkbox extends PureComponent {
|
|||
|
||||
if (this.props.element) {
|
||||
if (!document.querySelector(this.props.element)) {
|
||||
document.querySelector('.reminder-info').style.display = 'block';
|
||||
document.querySelector('.reminder-info').style.display = 'flex';
|
||||
return localStorage.setItem('showReminder', true);
|
||||
}
|
||||
}
|
||||
|
@ -43,7 +43,6 @@ export default class Checkbox extends PureComponent {
|
|||
control={<CheckboxUI name={this.props.name} color='primary' className='checkbox' checked={this.state.checked} onChange={this.handleChange} disabled={this.props.disabled || false} />}
|
||||
label={this.props.text}
|
||||
/>
|
||||
<br/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -37,7 +37,7 @@ export default class Dropdown extends PureComponent {
|
|||
|
||||
if (this.props.element) {
|
||||
if (!document.querySelector(this.props.element)) {
|
||||
document.querySelector('.reminder-info').style.display = 'block';
|
||||
document.querySelector('.reminder-info').style.display = 'flex';
|
||||
return localStorage.setItem('showReminder', true);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
import variables from 'modules/variables';
|
||||
|
||||
import { PureComponent } from 'react';
|
||||
import { MdHelpOutline, MdFlag } from 'react-icons/md';
|
||||
|
||||
import Slider from './Slider';
|
||||
import Switch from './Switch';
|
||||
import SettingsItem from './SettingsItem';
|
||||
|
||||
import { values } from 'modules/helpers/settings/modals';
|
||||
|
||||
|
@ -13,11 +15,57 @@ export default class Header extends PureComponent {
|
|||
|
||||
return (
|
||||
<>
|
||||
<h2>{this.props.title}</h2>
|
||||
<Switch name={this.props.setting} text={getMessage('modals.main.settings.enabled')} category={this.props.category} element={this.props.element || null} />
|
||||
{this.props.zoomSetting ?
|
||||
<><Slider title={getMessage('modals.main.settings.sections.appearance.accessibility.widget_zoom')} name={this.props.zoomSetting} min='10' max='400' default='100' display='%' marks={values('zoom')} category={this.props.zoomCategory || this.props.category}/></>
|
||||
: <br/>}
|
||||
<span className="mainTitle">{this.props.title}</span>
|
||||
<div className="headerExtras">
|
||||
<span className="link">
|
||||
<MdHelpOutline /> More Info
|
||||
</span>
|
||||
<span
|
||||
className="link"
|
||||
onClick={() =>
|
||||
window.open(
|
||||
variables.constants.BUG_REPORT + this.props.title.split(' ').join('+'),
|
||||
'_blank',
|
||||
)
|
||||
}
|
||||
>
|
||||
<MdFlag /> Report Issue
|
||||
</span>
|
||||
</div>
|
||||
{this.props.switch ? (
|
||||
<SettingsItem
|
||||
title={getMessage('modals.main.settings.enabled')}
|
||||
subtitle={getMessage('modals.main.settings.enabled')}
|
||||
>
|
||||
<Switch
|
||||
name={this.props.setting}
|
||||
text={getMessage('modals.main.settings.enabled')}
|
||||
category={this.props.category}
|
||||
element={this.props.element || null}
|
||||
/>
|
||||
</SettingsItem>
|
||||
) : null}
|
||||
{this.props.zoomSetting ? (
|
||||
<div className="settingsRow">
|
||||
<div className="content">
|
||||
<span className="title">
|
||||
{getMessage('modals.main.settings.sections.appearance.accessibility.widget_zoom')}
|
||||
</span>
|
||||
<span className="subtitle">eeeh course</span>
|
||||
</div>
|
||||
<div className="action">
|
||||
<Slider
|
||||
name={this.props.zoomSetting}
|
||||
min="10"
|
||||
max="400"
|
||||
default="100"
|
||||
display="%"
|
||||
marks={values('zoom')}
|
||||
category={this.props.zoomCategory || this.props.category}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
) : null}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@ export default function KeybindInput(props) {
|
|||
|
||||
const getButton = () => {
|
||||
if (!value) {
|
||||
return <button className='cleanButton' style={{ visibility: 'hidden' }} onClick={() => props.action('reset', props.setting)}><Cancel/></button>;;
|
||||
return <button className='cleanButton' style={{ visibility: 'hidden' }} onClick={() => props.action('reset', props.setting)}><MdCancel/></button>;;
|
||||
} else if (value === variables.language.getMessage(variables.languagecode, 'modals.main.settings.sections.keybinds.recording')) {
|
||||
return <button className='cleanButton' onClick={() => props.action('cancel', props.setting)}><MdCancel/></button>;
|
||||
} else {
|
||||
|
|
|
@ -40,7 +40,7 @@ export default class Radio extends PureComponent {
|
|||
|
||||
if (this.props.element) {
|
||||
if (!document.querySelector(this.props.element)) {
|
||||
document.querySelector('.reminder-info').style.display = 'block';
|
||||
document.querySelector('.reminder-info').style.display = 'flex';
|
||||
return localStorage.setItem('showReminder', true);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,19 +10,35 @@ export default function ResetModal({ modalClose }) {
|
|||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<h1 style={{ textAlign: 'center' }}>{variables.language.getMessage(variables.languagecode, 'modals.main.settings.sections.advanced.reset_modal.title')}</h1>
|
||||
<span>{variables.language.getMessage(variables.languagecode, 'modals.main.settings.sections.advanced.reset_modal.question')}</span>
|
||||
<br/><br/>
|
||||
<span>{variables.language.getMessage(variables.languagecode, 'modals.main.settings.sections.advanced.reset_modal.information')}</span>
|
||||
<div className='resetfooter'>
|
||||
<button className='round reset' style={{ marginLeft: 0 }} onClick={() => reset()}>
|
||||
<MdRestartAlt/>
|
||||
<div className="resetModal">
|
||||
<span className="mainTitle" style={{ textAlign: 'center' }}>
|
||||
{variables.language.getMessage(
|
||||
variables.languagecode,
|
||||
'modals.main.settings.sections.advanced.reset_modal.title',
|
||||
)}
|
||||
</span>
|
||||
<span className="title">
|
||||
{variables.language.getMessage(
|
||||
variables.languagecode,
|
||||
'modals.main.settings.sections.advanced.reset_modal.question',
|
||||
)}
|
||||
</span>
|
||||
<span style={{ maxWidth: '450px' }} className="subtitle">
|
||||
{variables.language.getMessage(
|
||||
variables.languagecode,
|
||||
'modals.main.settings.sections.advanced.reset_modal.information',
|
||||
)}
|
||||
</span>
|
||||
<div className="resetFooter">
|
||||
<button onClick={modalClose}>
|
||||
<MdClose />
|
||||
Close
|
||||
</button>
|
||||
<button className='round add' style={{ marginLeft: '5px' }} onClick={modalClose}>
|
||||
<MdClose/>
|
||||
<button onClick={() => reset()}>
|
||||
<MdRestartAlt />
|
||||
Reset
|
||||
</button>
|
||||
</div>
|
||||
</>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
import variables from 'modules/variables';
|
||||
|
||||
export default function SettingsItem(props) {
|
||||
/*const getMessage = (text) => variables.language.getMessage(variables.languageCode, text);*/
|
||||
return (
|
||||
<div className={props.final ? 'settingsRow settingsNoBorder' : 'settingsRow'}>
|
||||
<div className="content">
|
||||
<span className="title">{props.title}</span>
|
||||
<span className="subtitle">{props.subtitle}</span>
|
||||
{/*<span className='link'>{getMessage('modals.main.settings.buttons.reset')}</span>*/}
|
||||
</div>
|
||||
<div className="action">{props.children}</div>
|
||||
</div>
|
||||
);
|
||||
}
|
|
@ -9,7 +9,7 @@ export default class SliderComponent extends PureComponent {
|
|||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
value: localStorage.getItem(this.props.name) || this.props.default
|
||||
value: localStorage.getItem(this.props.name) || this.props.default,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -20,56 +20,64 @@ export default class SliderComponent extends PureComponent {
|
|||
if (text) {
|
||||
if (value === '') {
|
||||
return this.setState({
|
||||
value: 0
|
||||
value: 0,
|
||||
});
|
||||
}
|
||||
|
||||
if (value > this.props.max) {
|
||||
value = this.props.max;
|
||||
}
|
||||
|
||||
|
||||
if (value < this.props.min) {
|
||||
value = this.props.min;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
localStorage.setItem(this.props.name, value);
|
||||
this.setState({
|
||||
value
|
||||
value,
|
||||
});
|
||||
|
||||
if (this.props.element) {
|
||||
if (!document.querySelector(this.props.element)) {
|
||||
document.querySelector('.reminder-info').style.display = 'block';
|
||||
document.querySelector('.reminder-info').style.display = 'flex';
|
||||
return localStorage.setItem('showReminder', true);
|
||||
}
|
||||
}
|
||||
|
||||
EventBus.dispatch('refresh', this.props.category);
|
||||
}
|
||||
};
|
||||
|
||||
resetItem = () => {
|
||||
this.handleChange({
|
||||
target: {
|
||||
value: this.props.default || ''
|
||||
}
|
||||
value: this.props.default || '',
|
||||
},
|
||||
});
|
||||
toast(variables.language.getMessage(variables.languagecode, 'toasts.reset'));
|
||||
}
|
||||
};
|
||||
|
||||
render() {
|
||||
return (
|
||||
<>
|
||||
<p>{this.props.title}<span className='modalLink' onClick={this.resetItem}>{variables.language.getMessage(variables.languagecode, 'modals.main.settings.buttons.reset')}</span></p>
|
||||
<Slider
|
||||
value={Number(this.state.value)}
|
||||
onChange={this.handleChange}
|
||||
valueLabelDisplay='auto'
|
||||
default={Number(this.props.default)}
|
||||
min={Number(this.props.min)}
|
||||
max={Number(this.props.max)}
|
||||
step={Number(this.props.step) || 1}
|
||||
getAriaValueText={(value) => `${value}`}
|
||||
<span className={'sliderTitle'}>
|
||||
{this.props.title}
|
||||
<span className="link" onClick={this.resetItem}>
|
||||
{variables.language.getMessage(
|
||||
variables.languagecode,
|
||||
'modals.main.settings.buttons.reset',
|
||||
)}
|
||||
</span>
|
||||
</span>
|
||||
<Slider
|
||||
value={Number(this.state.value)}
|
||||
onChange={this.handleChange}
|
||||
valueLabelDisplay="auto"
|
||||
default={Number(this.props.default)}
|
||||
min={Number(this.props.min)}
|
||||
max={Number(this.props.max)}
|
||||
step={Number(this.props.step) || 1}
|
||||
getAriaValueText={(value) => `${value}`}
|
||||
marks={this.props.marks || []}
|
||||
/>
|
||||
</>
|
||||
|
|
|
@ -13,7 +13,7 @@ export default class Switch extends PureComponent {
|
|||
}
|
||||
|
||||
handleChange = () => {
|
||||
const value = (this.state.checked === true) ? false : true;
|
||||
const value = (this.state.checked !== true);
|
||||
localStorage.setItem(this.props.name, value);
|
||||
|
||||
this.setState({
|
||||
|
@ -24,7 +24,7 @@ export default class Switch extends PureComponent {
|
|||
|
||||
if (this.props.element) {
|
||||
if (!document.querySelector(this.props.element)) {
|
||||
document.querySelector('.reminder-info').style.display = 'block';
|
||||
document.querySelector('.reminder-info').style.display = 'flex';
|
||||
return localStorage.setItem('showReminder', true);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,7 +28,7 @@ export default class Text extends PureComponent {
|
|||
|
||||
if (this.props.element) {
|
||||
if (!document.querySelector(this.props.element)) {
|
||||
document.querySelector('.reminder-info').style.display = 'block';
|
||||
document.querySelector('.reminder-info').style.display = 'flex';
|
||||
return localStorage.setItem('showReminder', true);
|
||||
}
|
||||
}
|
||||
|
@ -52,7 +52,7 @@ export default class Text extends PureComponent {
|
|||
<TextField label={this.props.title} value={this.state.value} onChange={this.handleChange} varient='outlined' multiline spellCheck={false} minRows={4} maxRows={10} InputLabelProps={{ shrink: true }} />
|
||||
: <TextField label={this.props.title} value={this.state.value} onChange={this.handleChange} varient='outlined' InputLabelProps={{ shrink: true }} />
|
||||
}
|
||||
<span className='modalLink' onClick={this.resetItem}>{variables.language.getMessage(variables.languagecode, 'modals.main.settings.buttons.reset')}</span>
|
||||
<span className='link' onClick={this.resetItem}>{variables.language.getMessage(variables.languagecode, 'modals.main.settings.buttons.reset')}</span>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,11 +1,13 @@
|
|||
import variables from 'modules/variables';
|
||||
import { PureComponent } from 'react';
|
||||
import { MdEmail } from 'react-icons/md';
|
||||
import { FaDiscord, FaTwitter } from 'react-icons/fa';
|
||||
import { SiGithubsponsors, SiLiberapay, SiKofi, SiPatreon } from 'react-icons/si';
|
||||
import { FaDiscord, FaTwitter, FaPatreon, FaGithub } from 'react-icons/fa';
|
||||
import { SiKofi } from 'react-icons/si';
|
||||
|
||||
import Tooltip from 'components/helpers/tooltip/Tooltip';
|
||||
|
||||
import SettingsItem from '../SettingsItem';
|
||||
|
||||
const other_contributors = require('modules/other_contributors.json');
|
||||
|
||||
export default class About extends PureComponent {
|
||||
|
@ -19,7 +21,11 @@ export default class About extends PureComponent {
|
|||
other_contributors: [],
|
||||
photographers: this.getMessage('modals.main.loading'),
|
||||
update: this.getMessage('modals.main.settings.sections.about.version.checking_update'),
|
||||
loading: this.getMessage('modals.main.loading')
|
||||
loading: this.getMessage('modals.main.loading'),
|
||||
image:
|
||||
localStorage.getItem('theme') === 'dark'
|
||||
? './././icons/mue_dark.svg'
|
||||
: './././icons/mue_light.svg',
|
||||
};
|
||||
this.controller = new AbortController();
|
||||
}
|
||||
|
@ -28,10 +34,40 @@ export default class About extends PureComponent {
|
|||
let contributors, sponsors, photographers, versionData;
|
||||
|
||||
try {
|
||||
versionData = await (await fetch(variables.constants.GITHUB_URL + '/repos/' + variables.constants.ORG_NAME + '/' + variables.constants.REPO_NAME + '/releases', { signal: this.controller.signal })).json();
|
||||
contributors = await (await fetch(variables.constants.GITHUB_URL + '/repos/'+ variables.constants.ORG_NAME + '/' + variables.constants.REPO_NAME + '/contributors', { signal: this.controller.signal })).json();
|
||||
sponsors = (await (await fetch(variables.constants.SPONSORS_URL + '/list', { signal: this.controller.signal })).json()).sponsors;
|
||||
photographers = await (await fetch(variables.constants.API_URL + '/images/photographers', { signal: this.controller.signal })).json();
|
||||
versionData = await (
|
||||
await fetch(
|
||||
variables.constants.GITHUB_URL +
|
||||
'/repos/' +
|
||||
variables.constants.ORG_NAME +
|
||||
'/' +
|
||||
variables.constants.REPO_NAME +
|
||||
'/releases',
|
||||
{ signal: this.controller.signal },
|
||||
)
|
||||
).json();
|
||||
contributors = await (
|
||||
await fetch(
|
||||
variables.constants.GITHUB_URL +
|
||||
'/repos/' +
|
||||
variables.constants.ORG_NAME +
|
||||
'/' +
|
||||
variables.constants.REPO_NAME +
|
||||
'/contributors',
|
||||
{ signal: this.controller.signal },
|
||||
)
|
||||
).json();
|
||||
sponsors = (
|
||||
await (
|
||||
await fetch(variables.constants.SPONSORS_URL + '/list', {
|
||||
signal: this.controller.signal,
|
||||
})
|
||||
).json()
|
||||
).sponsors;
|
||||
photographers = await (
|
||||
await fetch(variables.constants.API_URL + '/images/photographers', {
|
||||
signal: this.controller.signal,
|
||||
})
|
||||
).json();
|
||||
} catch (e) {
|
||||
if (this.controller.signal.aborted === true) {
|
||||
return;
|
||||
|
@ -39,11 +75,11 @@ export default class About extends PureComponent {
|
|||
|
||||
return this.setState({
|
||||
update: this.getMessage('modals.main.settings.sections.about.version.error.title'),
|
||||
loading: this.getMessage('modals.main.settings.sections.about.version.error.description')
|
||||
loading: this.getMessage('modals.main.settings.sections.about.version.error.description'),
|
||||
});
|
||||
}
|
||||
|
||||
if (sponsors.length === 0) {
|
||||
if (sponsors.length === 0) {
|
||||
sponsors = [{ handle: 'empty' }];
|
||||
}
|
||||
|
||||
|
@ -54,8 +90,13 @@ export default class About extends PureComponent {
|
|||
const newVersion = versionData[0].tag_name;
|
||||
|
||||
let update = this.getMessage('modals.main.settings.sections.about.version.no_update');
|
||||
if (Number(variables.constants.VERSION.replaceAll('.', '')) < Number(newVersion.replaceAll('.', ''))) {
|
||||
update = `${this.getMessage('modals.main.settings.sections.about.version.update_available')}: ${newVersion}`;
|
||||
if (
|
||||
Number(variables.constants.VERSION.replaceAll('.', '')) <
|
||||
Number(newVersion.replaceAll('.', ''))
|
||||
) {
|
||||
update = `${this.getMessage(
|
||||
'modals.main.settings.sections.about.version.update_available',
|
||||
)}: ${newVersion}`;
|
||||
}
|
||||
|
||||
this.setState({
|
||||
|
@ -64,8 +105,8 @@ export default class About extends PureComponent {
|
|||
sponsors,
|
||||
update,
|
||||
other_contributors,
|
||||
photographers: photographers.sort().join(', '),
|
||||
loading: null
|
||||
photographers: photographers.sort().join(', '),
|
||||
loading: null,
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -73,7 +114,7 @@ export default class About extends PureComponent {
|
|||
if (navigator.onLine === false || localStorage.getItem('offlineMode') === 'true') {
|
||||
this.setState({
|
||||
update: this.getMessage('modals.main.settings.sections.about.version.checking_update'),
|
||||
loading: this.getMessage('modals.main.marketplace.offline.description')
|
||||
loading: this.getMessage('modals.main.marketplace.offline.description'),
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
@ -89,59 +130,189 @@ export default class About extends PureComponent {
|
|||
render() {
|
||||
return (
|
||||
<>
|
||||
<h2>{this.getMessage('modals.main.settings.sections.about.title')}</h2>
|
||||
<img draggable='false' className='aboutLogo' src='./././icons/logo_horizontal.png' alt='Logo'></img>
|
||||
<p>{this.getMessage('modals.main.settings.sections.about.copyright')} {variables.constants.COPYRIGHT_YEAR}-{new Date().getFullYear()} <a href={'https://github.com/' + variables.constants.ORG_NAME + '/' + variables.constants.REPO_NAME + '/graphs/contributors'} className='aboutLink' target='_blank' rel='noopener noreferrer'>{variables.constants.COPYRIGHT_NAME}</a> ({variables.constants.COPYRIGHT_LICENSE})</p>
|
||||
<p>{this.getMessage('modals.main.settings.sections.about.version.title')} {variables.constants.VERSION} ({this.state.update})</p>
|
||||
<a href={variables.constants.PRIVACY_URL} className='aboutLink' target='_blank' rel='noopener noreferrer' style={{ fontSize: '1rem' }}>{this.getMessage('modals.welcome.sections.privacy.links.privacy_policy')}</a>
|
||||
<span className="mainTitle">
|
||||
{this.getMessage('modals.main.settings.sections.about.title')}
|
||||
</span>
|
||||
<SettingsItem>
|
||||
<div style={{ display: 'flex', flexFlow: 'column', gap: '5px' }}>
|
||||
<img draggable="false" className="aboutLogo" src={this.state.image} alt="Logo" />
|
||||
<span className="title">
|
||||
{this.getMessage('modals.main.settings.sections.about.version.title')}{' '}
|
||||
{variables.constants.VERSION}
|
||||
</span>
|
||||
<span className="subtitle">({this.state.update})</span>
|
||||
<span className="subtitle">
|
||||
{this.getMessage('modals.main.settings.sections.about.copyright')}{' '}
|
||||
{variables.constants.COPYRIGHT_YEAR}-{new Date().getFullYear()}{' '}
|
||||
<a
|
||||
className="link"
|
||||
href={
|
||||
'https://github.com/' +
|
||||
variables.constants.ORG_NAME +
|
||||
'/' +
|
||||
variables.constants.REPO_NAME +
|
||||
'/graphs/contributors'
|
||||
}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
{variables.constants.COPYRIGHT_NAME}
|
||||
</a>{' '}
|
||||
({variables.constants.COPYRIGHT_LICENSE})
|
||||
</span>
|
||||
<span className="subtitle">
|
||||
<a
|
||||
href={variables.constants.PRIVACY_URL}
|
||||
className="link"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
{this.getMessage('modals.welcome.sections.privacy.links.privacy_policy')}
|
||||
</a>
|
||||
</span>
|
||||
</div>
|
||||
</SettingsItem>
|
||||
|
||||
<h3 className='contacth3'>{this.getMessage('modals.main.settings.sections.about.contact_us')}</h3>
|
||||
<a href={'mailto:' + variables.constants.EMAIL} className='aboutIcon' target='_blank' rel='noopener noreferrer'><MdEmail/></a>
|
||||
<a href={'https://twitter.com/' + variables.constants.TWITTER_HANDLE} className='aboutIcon' target='_blank' rel='noopener noreferrer'><FaTwitter/></a>
|
||||
<a href={'https://discord.gg/' + variables.constants.DISCORD_SERVER} className='aboutIcon' target='_blank' rel='noopener noreferrer'><FaDiscord/></a>
|
||||
|
||||
<h3 className='contacth3'>{this.getMessage('modals.main.settings.sections.about.support_mue')}</h3>
|
||||
<a href={'https://github.com/sponsors/' + variables.constants.SPONSORS_USERNAME} className='aboutIcon' target='_blank' rel='noopener noreferrer'><SiGithubsponsors/></a>
|
||||
<a href={'https://liberapay.com/' + variables.constants.LIBERAPAY_USERNAME} className='aboutIcon' target='_blank' rel='noopener noreferrer'><SiLiberapay/></a>
|
||||
<a href={'https://ko-fi.com/' + variables.constants.KOFI_USERNAME} className='aboutIcon' target='_blank' rel='noopener noreferrer'><SiKofi/></a>
|
||||
<a href={'https://patreon.com/' + variables.constants.PATREON_USERNAME} className='aboutIcon' target='_blank' rel='noopener noreferrer'><SiPatreon/></a>
|
||||
|
||||
<h3>{this.getMessage('modals.main.settings.sections.about.resources_used.title')}</h3>
|
||||
<p>
|
||||
<a href='https://www.pexels.com' className='aboutLink' target='_blank' rel='noopener noreferrer'>Pexels</a>
|
||||
, <a href='https://unsplash.com' className='aboutLink' target='_blank' rel='noopener noreferrer'>Unsplash</a> ({this.getMessage('modals.main.settings.sections.about.resources_used.bg_images')})
|
||||
</p>
|
||||
|
||||
<h3>{this.getMessage('modals.main.settings.sections.about.contributors')}</h3>
|
||||
<p>{this.state.loading}</p>
|
||||
{this.state.contributors.map(({ login, id }) => (
|
||||
<Tooltip title={login} key={login}>
|
||||
<a href={'https://github.com/' + login} target='_blank' rel='noopener noreferrer'><img draggable='false' className='abouticon' src={'https://avatars.githubusercontent.com/u/' + id + '?s=128'} alt={login}></img></a>
|
||||
</Tooltip>
|
||||
))}
|
||||
{ // for those who contributed without opening a pull request
|
||||
this.state.other_contributors.map(({ login, avatar_url }) => (
|
||||
<Tooltip title={login} key={login}>
|
||||
<a href={'https://github.com/' + login} target='_blank' rel='noopener noreferrer'><img draggable='false' className='abouticon' src={avatar_url + '&s=128'} alt={login}></img></a>
|
||||
</Tooltip>
|
||||
))}
|
||||
|
||||
<h3>{this.getMessage('modals.main.settings.sections.about.supporters')}</h3>
|
||||
<p>{this.state.loading}</p>
|
||||
{this.state.sponsors.map(({ handle, avatar }) => {
|
||||
if (handle === 'empty') {
|
||||
return <p>{this.getMessage('modals.main.settings.sections.about.no_supporters')}</p>;
|
||||
}
|
||||
|
||||
return (
|
||||
<Tooltip title={handle} key={handle}>
|
||||
<a href={'https://github.com/' + handle} target='_blank' rel='noopener noreferrer'><img draggable='false' className='abouticon' src={avatar.split('?')[0] + '?s=128'} alt={handle}></img></a>
|
||||
<div className="settingsRow" style={{ flexFlow: 'column', alignItems: 'flex-start' }}>
|
||||
<span className="title">
|
||||
{this.getMessage('modals.main.settings.sections.about.contact_us')}
|
||||
</span>
|
||||
<div className="aboutContact">
|
||||
<Tooltip title={'Email'}>
|
||||
<a
|
||||
href={'mailto:' + variables.constants.EMAIL}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
<MdEmail />
|
||||
</a>
|
||||
</Tooltip>
|
||||
)
|
||||
})}
|
||||
<Tooltip title={'Twitter'}>
|
||||
<a
|
||||
href={'https://twitter.com/' + variables.constants.TWITTER_HANDLE}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
<FaTwitter />
|
||||
</a>
|
||||
</Tooltip>
|
||||
<Tooltip title={'Discord'}>
|
||||
<a
|
||||
href={'https://discord.gg/' + variables.constants.DISCORD_SERVER}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
<FaDiscord />
|
||||
</a>
|
||||
</Tooltip>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h3>{this.getMessage('modals.main.settings.sections.about.photographers')}</h3>
|
||||
<p>{this.state.photographers}</p>
|
||||
<div className="settingsRow" style={{ flexFlow: 'column', alignItems: 'flex-start' }}>
|
||||
<span className="title">
|
||||
{this.getMessage('modals.main.settings.sections.about.support_mue')}
|
||||
</span>
|
||||
<p>As Mue is entirely free, we rely on donations to cover pay the server bills and fund development</p>
|
||||
<div className="aboutContact">
|
||||
<a class='button' href={variables.constants.DONATE_LINK}>Donate</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="settingsRow" style={{ flexFlow: 'column', alignItems: 'flex-start' }}>
|
||||
<span className="title">
|
||||
{this.getMessage('modals.main.settings.sections.about.resources_used.title')}
|
||||
</span>
|
||||
<span className="subtitle">
|
||||
<a
|
||||
href="https://www.pexels.com"
|
||||
className="link"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
Pexels
|
||||
</a>
|
||||
,{' '}
|
||||
<a
|
||||
href="https://unsplash.com"
|
||||
className="link"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
Unsplash
|
||||
</a>{' '}
|
||||
({this.getMessage('modals.main.settings.sections.about.resources_used.bg_images')})
|
||||
</span>
|
||||
<span className="subtitle">
|
||||
<a href="https://undraw.co" className="link" target="_blank" rel="noopener noreferrer">
|
||||
Undraw
|
||||
</a>{' '}
|
||||
({this.getMessage('modals.main.settings.sections.about.resources_used.welcome_img')})
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div className="settingsRow" style={{ flexFlow: 'column', alignItems: 'flex-start' }}>
|
||||
<span className="title">
|
||||
{this.getMessage('modals.main.settings.sections.about.contributors')}
|
||||
</span>
|
||||
<p>{this.state.loading}</p>
|
||||
<div className="contributorImages">
|
||||
{this.state.contributors.map(({ login, id }) => (
|
||||
<Tooltip title={login} key={login}>
|
||||
<a href={'https://github.com/' + login} target="_blank" rel="noopener noreferrer">
|
||||
<img
|
||||
draggable="false"
|
||||
src={'https://avatars.githubusercontent.com/u/' + id + '?s=128'}
|
||||
alt={login}
|
||||
></img>
|
||||
</a>
|
||||
</Tooltip>
|
||||
))}
|
||||
{
|
||||
// for those who contributed without opening a pull request
|
||||
this.state.other_contributors.map(({ login, avatar_url }) => (
|
||||
<Tooltip title={login} key={login}>
|
||||
<a href={'https://github.com/' + login} target="_blank" rel="noopener noreferrer">
|
||||
<img draggable="false" src={avatar_url + '&s=128'} alt={login}></img>
|
||||
</a>
|
||||
</Tooltip>
|
||||
))
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="settingsRow" style={{ flexFlow: 'column', alignItems: 'flex-start' }}>
|
||||
<span className="title">
|
||||
{this.getMessage('modals.main.settings.sections.about.supporters')}
|
||||
</span>
|
||||
<p>{this.state.loading}</p>
|
||||
<div className="contributorImages">
|
||||
{this.state.sponsors.map(({ handle, avatar }) => {
|
||||
if (handle === 'empty') {
|
||||
return (
|
||||
<p>{this.getMessage('modals.main.settings.sections.about.no_supporters')}</p>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Tooltip title={handle} key={handle}>
|
||||
<a
|
||||
href={'https://github.com/' + handle}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
<img draggable="false" src={avatar.split('?')[0] + '?s=128'} alt={handle}></img>
|
||||
</a>
|
||||
</Tooltip>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
<div className="settingsRow" style={{ flexFlow: 'column', alignItems: 'flex-start' }}>
|
||||
<span className="title">
|
||||
{this.getMessage('modals.main.settings.sections.about.photographers')}
|
||||
</span>
|
||||
<span className="subtitle">{this.state.photographers}</span>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,73 +1,169 @@
|
|||
import variables from 'modules/variables';
|
||||
import { PureComponent } from 'react';
|
||||
import Modal from 'react-modal';
|
||||
import { MenuItem } from '@mui/material';
|
||||
import { MdUpload as ImportIcon, MdDownload as ExportIcon, MdRestartAlt as ResetIcon } from 'react-icons/md';
|
||||
import variables from "modules/variables";
|
||||
import { PureComponent } from "react";
|
||||
import Modal from "react-modal";
|
||||
import { MenuItem } from "@mui/material";
|
||||
import {
|
||||
MdUpload as ImportIcon,
|
||||
MdDownload as ExportIcon,
|
||||
MdRestartAlt as ResetIcon,
|
||||
} from "react-icons/md";
|
||||
|
||||
import { exportSettings, importSettings } from 'modules/helpers/settings/modals';
|
||||
import {
|
||||
exportSettings,
|
||||
importSettings,
|
||||
} from "modules/helpers/settings/modals";
|
||||
|
||||
import Checkbox from '../Checkbox';
|
||||
import FileUpload from '../FileUpload';
|
||||
import Text from '../Text';
|
||||
import Switch from '../Switch';
|
||||
import ResetModal from '../ResetModal';
|
||||
import Dropdown from '../Dropdown';
|
||||
import Checkbox from "../Checkbox";
|
||||
import FileUpload from "../FileUpload";
|
||||
import Text from "../Text";
|
||||
import Switch from "../Switch";
|
||||
import ResetModal from "../ResetModal";
|
||||
import Dropdown from "../Dropdown";
|
||||
import SettingsItem from "../SettingsItem";
|
||||
|
||||
const time_zones = require('components/widgets/time/timezones.json');
|
||||
const time_zones = require("components/widgets/time/timezones.json");
|
||||
|
||||
export default class AdvancedSettings extends PureComponent {
|
||||
constructor() {
|
||||
super();
|
||||
this.state = {
|
||||
resetModal: false
|
||||
resetModal: false,
|
||||
};
|
||||
}
|
||||
|
||||
render() {
|
||||
const getMessage = (text) => variables.language.getMessage(variables.languagecode, text);
|
||||
const getMessage = (text) =>
|
||||
variables.language.getMessage(variables.languagecode, text);
|
||||
|
||||
return (
|
||||
<>
|
||||
<h2>{getMessage('modals.main.settings.sections.advanced.title')}</h2>
|
||||
<Checkbox name='offlineMode' text={getMessage('modals.main.settings.sections.advanced.offline_mode')} element='.other' />
|
||||
<Dropdown name='timezone' label={getMessage('modals.main.settings.sections.advanced.timezone.title')} category='timezone' manual={true}>
|
||||
<MenuItem value='auto'>{getMessage('modals.main.settings.sections.advanced.timezone.automatic')}</MenuItem>
|
||||
{time_zones.map((timezone) => (
|
||||
<MenuItem value={timezone} key={timezone}>{timezone}</MenuItem>
|
||||
))}
|
||||
</Dropdown>
|
||||
<span className="mainTitle">
|
||||
{getMessage("modals.main.settings.sections.advanced.title")}
|
||||
</span>
|
||||
<SettingsItem
|
||||
title={getMessage(
|
||||
"modals.main.settings.sections.advanced.offline_mode"
|
||||
)}
|
||||
>
|
||||
<Switch
|
||||
name="offlineMode"
|
||||
text={getMessage(
|
||||
"modals.main.settings.sections.advanced.offline_mode"
|
||||
)}
|
||||
element=".other"
|
||||
/>
|
||||
</SettingsItem>
|
||||
{localStorage.getItem("welcomePreview") !== "true" ? (
|
||||
<div className="settingsRow">
|
||||
<div className="content">
|
||||
<span className="title">
|
||||
{getMessage("modals.main.settings.sections.advanced.data")}
|
||||
</span>
|
||||
<span className="subtitle">
|
||||
{getMessage(
|
||||
"modals.main.settings.sections.advanced.experimental_warning"
|
||||
)}
|
||||
</span>
|
||||
</div>
|
||||
<div className="action activityButtons">
|
||||
<button onClick={() => this.setState({ resetModal: true })}>
|
||||
{getMessage("modals.main.settings.buttons.reset")}
|
||||
<ResetIcon />
|
||||
</button>
|
||||
<button onClick={() => exportSettings()}>
|
||||
{getMessage("modals.main.settings.buttons.export")}
|
||||
<ExportIcon />
|
||||
</button>
|
||||
<button
|
||||
onClick={() => document.getElementById("file-input").click()}
|
||||
>
|
||||
{getMessage("modals.main.settings.buttons.import")}
|
||||
<ImportIcon />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
) : null}
|
||||
<SettingsItem title="This should really be in time">
|
||||
<Dropdown
|
||||
name="timezone"
|
||||
label={getMessage(
|
||||
"modals.main.settings.sections.advanced.timezone.title"
|
||||
)}
|
||||
category="timezone"
|
||||
manual={true}
|
||||
>
|
||||
<MenuItem value="auto">
|
||||
{getMessage(
|
||||
"modals.main.settings.sections.advanced.timezone.automatic"
|
||||
)}
|
||||
</MenuItem>
|
||||
{time_zones.map((timezone) => (
|
||||
<MenuItem value={timezone} key={timezone}>
|
||||
{timezone}
|
||||
</MenuItem>
|
||||
))}
|
||||
</Dropdown>
|
||||
</SettingsItem>
|
||||
<SettingsItem
|
||||
title={getMessage("modals.main.settings.sections.advanced.tab_name")}
|
||||
>
|
||||
<Text
|
||||
title={getMessage(
|
||||
"modals.main.settings.sections.advanced.tab_name"
|
||||
)}
|
||||
name="tabName"
|
||||
default={getMessage("tabname")}
|
||||
category="other"
|
||||
/>
|
||||
</SettingsItem>
|
||||
<FileUpload
|
||||
id="file-input"
|
||||
accept="application/json"
|
||||
type="settings"
|
||||
loadFunction={(e) => importSettings(e)}
|
||||
/>
|
||||
<SettingsItem
|
||||
title={getMessage(
|
||||
"modals.main.settings.sections.advanced.custom_css"
|
||||
)}
|
||||
>
|
||||
<Text
|
||||
title={getMessage(
|
||||
"modals.main.settings.sections.advanced.custom_css"
|
||||
)}
|
||||
name="customcss"
|
||||
textarea={true}
|
||||
category="other"
|
||||
/>
|
||||
</SettingsItem>
|
||||
<div className="settingsRow">
|
||||
<div className="content">
|
||||
<span className="title">
|
||||
{getMessage("modals.main.settings.sections.experimental.title")}
|
||||
</span>
|
||||
<span className="subtitle">
|
||||
{getMessage(
|
||||
"modals.main.settings.sections.advanced.experimental_warning"
|
||||
)}
|
||||
</span>
|
||||
</div>
|
||||
<div className="action">
|
||||
<Switch
|
||||
name="experimental"
|
||||
text={getMessage("modals.main.settings.enabled")}
|
||||
element=".other"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{localStorage.getItem('welcomePreview') !== 'true' ?
|
||||
<>
|
||||
<h3>{getMessage('modals.main.settings.sections.advanced.data')}</h3>
|
||||
<br/>
|
||||
<div className='data-buttons-row'>
|
||||
<button onClick={() => this.setState({ resetModal: true })}>
|
||||
{getMessage('modals.main.settings.buttons.reset')}
|
||||
<ResetIcon/>
|
||||
</button>
|
||||
<button onClick={() => exportSettings()}>
|
||||
{getMessage('modals.main.settings.buttons.export')}
|
||||
<ExportIcon/>
|
||||
</button>
|
||||
<button onClick={() => document.getElementById('file-input').click()}>
|
||||
{getMessage('modals.main.settings.buttons.import')}
|
||||
<ImportIcon/>
|
||||
</button>
|
||||
</div>
|
||||
</>
|
||||
: null}
|
||||
<FileUpload id='file-input' accept='application/json' type='settings' loadFunction={(e) => importSettings(e)}/>
|
||||
|
||||
<h3>{getMessage('modals.main.settings.sections.advanced.customisation')}</h3>
|
||||
<Text title={getMessage('modals.main.settings.sections.advanced.tab_name')} name='tabName' default={getMessage('tabname')} category='other'/>
|
||||
<Text title={getMessage('modals.main.settings.sections.advanced.custom_css')} name='customcss' textarea={true} category='other'/>
|
||||
|
||||
<h3>{getMessage('modals.main.settings.sections.experimental.title')}</h3>
|
||||
<p style={{ maxWidth: '75%' }}>{getMessage('modals.main.settings.sections.advanced.experimental_warning')}</p>
|
||||
<Switch name='experimental' text={getMessage('modals.main.settings.enabled')} element='.other'/>
|
||||
|
||||
<Modal closeTimeoutMS={100} onRequestClose={() => this.setState({ resetModal: false })} isOpen={this.state.resetModal} className='Modal resetmodal mainModal' overlayClassName='Overlay resetoverlay' ariaHideApp={false}>
|
||||
<Modal
|
||||
closeTimeoutMS={100}
|
||||
onRequestClose={() => this.setState({ resetModal: false })}
|
||||
isOpen={this.state.resetModal}
|
||||
className="Modal resetmodal mainModal"
|
||||
overlayClassName="Overlay resetoverlay"
|
||||
ariaHideApp={false}
|
||||
>
|
||||
<ResetModal modalClose={() => this.setState({ resetModal: false })} />
|
||||
</Modal>
|
||||
</>
|
||||
|
|
|
@ -1,62 +1,216 @@
|
|||
import variables from 'modules/variables';
|
||||
import variables from "modules/variables";
|
||||
|
||||
import Checkbox from '../Checkbox';
|
||||
import Dropdown from '../Dropdown';
|
||||
import Radio from '../Radio';
|
||||
import Slider from '../Slider';
|
||||
import Text from '../Text';
|
||||
import Checkbox from "../Checkbox";
|
||||
import Dropdown from "../Dropdown";
|
||||
import Radio from "../Radio";
|
||||
import Slider from "../Slider";
|
||||
import Text from "../Text";
|
||||
import SettingsItem from "../SettingsItem";
|
||||
|
||||
import { values } from 'modules/helpers/settings/modals';
|
||||
import { values } from "modules/helpers/settings/modals";
|
||||
|
||||
export default function AppearanceSettings() {
|
||||
const getMessage = (text) => variables.language.getMessage(variables.languagecode, text);
|
||||
const getMessage = (text) =>
|
||||
variables.language.getMessage(variables.languagecode, text);
|
||||
|
||||
const themeOptions = [
|
||||
{
|
||||
name: getMessage('modals.main.settings.sections.appearance.theme.auto'),
|
||||
value: 'auto'
|
||||
name: getMessage("modals.main.settings.sections.appearance.theme.auto"),
|
||||
value: "auto",
|
||||
},
|
||||
{
|
||||
name: getMessage('modals.main.settings.sections.appearance.theme.light'),
|
||||
value: 'light'
|
||||
},
|
||||
name: getMessage("modals.main.settings.sections.appearance.theme.light"),
|
||||
value: "light",
|
||||
},
|
||||
{
|
||||
name: getMessage('modals.main.settings.sections.appearance.theme.dark'),
|
||||
value: 'dark'
|
||||
}
|
||||
name: getMessage("modals.main.settings.sections.appearance.theme.dark"),
|
||||
value: "dark",
|
||||
},
|
||||
];
|
||||
|
||||
const styleOptions = [
|
||||
{
|
||||
name: "Legacy",
|
||||
value: "legacy",
|
||||
},
|
||||
{
|
||||
name: "New",
|
||||
value: "new",
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<>
|
||||
<h2>{getMessage('modals.main.settings.sections.appearance.title')}</h2>
|
||||
<Radio name='theme' title={getMessage('modals.main.settings.sections.appearance.theme.title')} options={themeOptions} category='other' />
|
||||
<span className="mainTitle">
|
||||
{getMessage("modals.main.settings.sections.appearance.title")}
|
||||
</span>
|
||||
<div className="settingsRow">
|
||||
<div className="content">
|
||||
<span className="title">
|
||||
{getMessage("modals.main.settings.sections.appearance.theme.title")}
|
||||
</span>
|
||||
<span className="subtitle">subtitle</span>
|
||||
</div>
|
||||
<div className="action">
|
||||
<Radio name="theme" options={themeOptions} category="other" />
|
||||
</div>
|
||||
</div>
|
||||
<div className="settingsRow">
|
||||
<div className="content">
|
||||
<span className="title">
|
||||
{getMessage("modals.main.settings.sections.appearance.font.title")}
|
||||
</span>
|
||||
<span className="subtitle">subtitle</span>
|
||||
</div>
|
||||
<div className="action">
|
||||
<Checkbox
|
||||
name="fontGoogle"
|
||||
text={getMessage(
|
||||
"modals.main.settings.sections.appearance.font.google"
|
||||
)}
|
||||
category="other"
|
||||
/>
|
||||
<Text
|
||||
title={getMessage(
|
||||
"modals.main.settings.sections.appearance.font.custom"
|
||||
)}
|
||||
name="font"
|
||||
upperCaseFirst={true}
|
||||
category="other"
|
||||
/>
|
||||
<Dropdown
|
||||
label={getMessage(
|
||||
"modals.main.settings.sections.appearance.font.weight.title"
|
||||
)}
|
||||
name="fontweight"
|
||||
category="other"
|
||||
>
|
||||
{/* names are taken from https://developer.mozilla.org/en-US/docs/Web/CSS/font-weight */}
|
||||
<option value="100">
|
||||
{getMessage(
|
||||
"modals.main.settings.sections.appearance.font.weight.thin"
|
||||
)}
|
||||
</option>
|
||||
<option value="200">
|
||||
{getMessage(
|
||||
"modals.main.settings.sections.appearance.font.weight.extra_light"
|
||||
)}
|
||||
</option>
|
||||
<option value="300">
|
||||
{getMessage(
|
||||
"modals.main.settings.sections.appearance.font.weight.light"
|
||||
)}
|
||||
</option>
|
||||
<option value="400">
|
||||
{getMessage(
|
||||
"modals.main.settings.sections.appearance.font.weight.normal"
|
||||
)}
|
||||
</option>
|
||||
<option value="500">
|
||||
{getMessage(
|
||||
"modals.main.settings.sections.appearance.font.weight.medium"
|
||||
)}
|
||||
</option>
|
||||
<option value="600">
|
||||
{getMessage(
|
||||
"modals.main.settings.sections.appearance.font.weight.semi_bold"
|
||||
)}
|
||||
</option>
|
||||
<option value="700">
|
||||
{getMessage(
|
||||
"modals.main.settings.sections.appearance.font.weight.bold"
|
||||
)}
|
||||
</option>
|
||||
<option value="800">
|
||||
{getMessage(
|
||||
"modals.main.settings.sections.appearance.font.weight.extra_bold"
|
||||
)}
|
||||
</option>
|
||||
</Dropdown>
|
||||
<Dropdown
|
||||
label={getMessage(
|
||||
"modals.main.settings.sections.appearance.font.style.title"
|
||||
)}
|
||||
name="fontstyle"
|
||||
category="other"
|
||||
>
|
||||
<option value="normal">
|
||||
{getMessage(
|
||||
"modals.main.settings.sections.appearance.font.style.normal"
|
||||
)}
|
||||
</option>
|
||||
<option value="italic">
|
||||
{getMessage(
|
||||
"modals.main.settings.sections.appearance.font.style.italic"
|
||||
)}
|
||||
</option>
|
||||
<option value="oblique">
|
||||
{getMessage(
|
||||
"modals.main.settings.sections.appearance.font.style.oblique"
|
||||
)}
|
||||
</option>
|
||||
</Dropdown>
|
||||
</div>
|
||||
</div>
|
||||
<SettingsItem
|
||||
title="Widget Style"
|
||||
subtitle="Choose between the two styles, legacy (enabled for pre 7.0 users) and our slick modern styling."
|
||||
>
|
||||
<Radio name="widgetStyle" options={styleOptions} category="widgets" />
|
||||
</SettingsItem>
|
||||
|
||||
<h3>{getMessage('modals.main.settings.sections.appearance.font.title')}</h3>
|
||||
<Text title={getMessage('modals.main.settings.sections.appearance.font.custom')} name='font' upperCaseFirst={true} category='other' />
|
||||
<br/>
|
||||
<Checkbox name='fontGoogle' text={getMessage('modals.main.settings.sections.appearance.font.google')} category='other' />
|
||||
<Dropdown label={getMessage('modals.main.settings.sections.appearance.font.weight.title')} name='fontweight' category='other'>
|
||||
{/* names are taken from https://developer.mozilla.org/en-US/docs/Web/CSS/font-weight */}
|
||||
<option value='100'>{getMessage('modals.main.settings.sections.appearance.font.weight.thin')}</option>
|
||||
<option value='200'>{getMessage('modals.main.settings.sections.appearance.font.weight.extra_light')}</option>
|
||||
<option value='300'>{getMessage('modals.main.settings.sections.appearance.font.weight.light')}</option>
|
||||
<option value='400'>{getMessage('modals.main.settings.sections.appearance.font.weight.normal')}</option>
|
||||
<option value='500'>{getMessage('modals.main.settings.sections.appearance.font.weight.medium')}</option>
|
||||
<option value='600'>{getMessage('modals.main.settings.sections.appearance.font.weight.semi_bold')}</option>
|
||||
<option value='700'>{getMessage('modals.main.settings.sections.appearance.font.weight.bold')}</option>
|
||||
<option value='800'>{getMessage('modals.main.settings.sections.appearance.font.weight.extra_bold')}</option>
|
||||
</Dropdown>
|
||||
<Dropdown label={getMessage('modals.main.settings.sections.appearance.font.style.title')} name='fontstyle' category='other'>
|
||||
<option value='normal'>{getMessage('modals.main.settings.sections.appearance.font.style.normal')}</option>
|
||||
<option value='italic'>{getMessage('modals.main.settings.sections.appearance.font.style.italic')}</option>
|
||||
<option value='oblique'>{getMessage('modals.main.settings.sections.appearance.font.style.oblique')}</option>
|
||||
</Dropdown>
|
||||
|
||||
<h3>{getMessage('modals.main.settings.sections.appearance.accessibility.title')}</h3>
|
||||
{/*<h3>{getMessage('modals.main.settings.sections.appearance.accessibility.title')}</h3>
|
||||
<Checkbox text={getMessage('modals.main.settings.sections.appearance.accessibility.text_shadow')} name='textBorder' category='other'/>
|
||||
<Checkbox text={getMessage('modals.main.settings.sections.appearance.accessibility.animations')} name='animations' category='other'/>
|
||||
<Slider title={getMessage('modals.main.settings.sections.appearance.accessibility.toast_duration')} name='toastDisplayTime' default='2500' step='100' min='500' max='5000' marks={values('toast')} toast={true}
|
||||
display={' ' + getMessage('modals.main.settings.sections.appearance.accessibility.milliseconds')} />
|
||||
<Slider title={getMessage('modals.main.settings.sections.appearance.accessibility.toast_duration')} name='toastDisplayTime' default='2500' step='100' min='500' max='5000' marks={values('toast')}
|
||||
display={' ' + getMessage('modals.main.settings.sections.appearance.accessibility.milliseconds')} />*/}
|
||||
<div className="settingsRow">
|
||||
<div className="content">
|
||||
<span className="title">
|
||||
{getMessage(
|
||||
"modals.main.settings.sections.appearance.accessibility.title"
|
||||
)}
|
||||
</span>
|
||||
<span className="subtitle">subtitle</span>
|
||||
</div>
|
||||
<div className="action">
|
||||
<Dropdown
|
||||
label={getMessage(
|
||||
"modals.main.settings.sections.appearance.accessibility.text_shadow"
|
||||
)}
|
||||
name="textBorder"
|
||||
category="other"
|
||||
>
|
||||
<option value="new">New</option> {/* default */}
|
||||
<option value="true">Old</option> {/* old checkbox setting */}
|
||||
<option value="none">None</option>
|
||||
</Dropdown>
|
||||
<Checkbox
|
||||
text={getMessage(
|
||||
"modals.main.settings.sections.appearance.accessibility.animations"
|
||||
)}
|
||||
name="animations"
|
||||
category="other"
|
||||
/>
|
||||
<Slider
|
||||
title={getMessage(
|
||||
"modals.main.settings.sections.appearance.accessibility.toast_duration"
|
||||
)}
|
||||
name="toastDisplayTime"
|
||||
default="2500"
|
||||
step="100"
|
||||
min="500"
|
||||
max="5000"
|
||||
marks={values("toast")}
|
||||
display={
|
||||
" " +
|
||||
getMessage(
|
||||
"modals.main.settings.sections.appearance.accessibility.milliseconds"
|
||||
)
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
import variables from 'modules/variables';
|
||||
import { PureComponent, createRef } from 'react';
|
||||
import { MdOutlineWifiOff } from 'react-icons/md';
|
||||
import Modal from 'react-modal';
|
||||
import variables from "modules/variables";
|
||||
import { PureComponent, createRef } from "react";
|
||||
import { MdOutlineWifiOff } from "react-icons/md";
|
||||
import Modal from "react-modal";
|
||||
|
||||
import Lightbox from '../../marketplace/Lightbox';
|
||||
import Lightbox from "../../marketplace/Lightbox";
|
||||
|
||||
export default class Changelog extends PureComponent {
|
||||
constructor() {
|
||||
|
@ -11,63 +11,71 @@ export default class Changelog extends PureComponent {
|
|||
this.state = {
|
||||
title: null,
|
||||
showLightbox: false,
|
||||
lightboxImg: null
|
||||
lightboxImg: null,
|
||||
};
|
||||
this.offlineMode = (localStorage.getItem('offlineMode') === 'true');
|
||||
this.offlineMode = localStorage.getItem("offlineMode") === "true";
|
||||
this.controller = new AbortController();
|
||||
this.changelog = createRef();
|
||||
}
|
||||
|
||||
async getUpdate() {
|
||||
const data = await (await fetch(variables.constants.BLOG_POST + '/index.json', { signal: this.controller.signal })).json();
|
||||
const data = await (
|
||||
await fetch(variables.constants.BLOG_POST + "/index.json", {
|
||||
signal: this.controller.signal,
|
||||
})
|
||||
).json();
|
||||
|
||||
if (this.controller.signal.aborted === true) {
|
||||
return;
|
||||
}
|
||||
|
||||
let date = new Date(data.date.split(' ')[0]);
|
||||
date = date.toLocaleDateString(variables.languagecode.replace('_', '-'), {
|
||||
year: 'numeric',
|
||||
month: 'long',
|
||||
day: 'numeric'
|
||||
let date = new Date(data.date.split(" ")[0]);
|
||||
date = date.toLocaleDateString(variables.languagecode.replace("_", "-"), {
|
||||
year: "numeric",
|
||||
month: "long",
|
||||
day: "numeric",
|
||||
});
|
||||
|
||||
this.setState({
|
||||
title: data.title,
|
||||
date,
|
||||
image: data.featured_image || null,
|
||||
author: variables.language.getMessage(variables.languagecode, 'modals.main.settings.sections.changelog.by', {
|
||||
author: data.authors.join(', ')
|
||||
}),
|
||||
html: data.html
|
||||
author: variables.language.getMessage(
|
||||
variables.languagecode,
|
||||
"modals.main.settings.sections.changelog.by",
|
||||
{
|
||||
author: data.authors.join(", "),
|
||||
}
|
||||
),
|
||||
html: data.html,
|
||||
});
|
||||
|
||||
// lightbox etc
|
||||
const images = this.changelog.current.getElementsByTagName('img');
|
||||
const links = this.changelog.current.getElementsByTagName('a');
|
||||
const images = this.changelog.current.getElementsByTagName("img");
|
||||
const links = this.changelog.current.getElementsByTagName("a");
|
||||
|
||||
for (const img of images) {
|
||||
img.draggable = false;
|
||||
img.onclick = () => {
|
||||
this.setState({
|
||||
showLightbox: true,
|
||||
lightboxImg: img.src
|
||||
lightboxImg: img.src,
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
// open in new tab
|
||||
for (let link = 0; link < links.length; link++) {
|
||||
links[link].target = '_blank';
|
||||
links[link].rel = 'noopener noreferrer';
|
||||
links[link].target = "_blank";
|
||||
links[link].rel = "noopener noreferrer";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
componentDidMount() {
|
||||
if (navigator.onLine === false || this.offlineMode) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
this.getUpdate();
|
||||
}
|
||||
|
||||
|
@ -77,38 +85,68 @@ export default class Changelog extends PureComponent {
|
|||
}
|
||||
|
||||
render() {
|
||||
const getMessage = (text) => variables.language.getMessage(variables.languagecode, text);
|
||||
const getMessage = (text) =>
|
||||
variables.language.getMessage(variables.languagecode, text);
|
||||
|
||||
const errorMessage = (msg) => {
|
||||
return (
|
||||
<div className='emptyitems'>
|
||||
<div className='emptyMessage'>
|
||||
{msg}
|
||||
</div>
|
||||
<div className="emptyItems">
|
||||
<div className="emptyMessage">{msg}</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
if (navigator.onLine === false || this.offlineMode) {
|
||||
return errorMessage(<>
|
||||
<MdOutlineWifiOff/>
|
||||
<h1>{getMessage('modals.main.marketplace.offline.title')}</h1>
|
||||
<p className='description'>{getMessage('modals.main.marketplace.offline.description')}</p>
|
||||
</>);
|
||||
if (navigator.onLine === false || this.offlineMode) {
|
||||
return errorMessage(
|
||||
<>
|
||||
<MdOutlineWifiOff />
|
||||
<h1>{getMessage("modals.main.marketplace.offline.title")}</h1>
|
||||
<p className="description">
|
||||
{getMessage("modals.main.marketplace.offline.description")}
|
||||
</p>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
if (!this.state.title) {
|
||||
return errorMessage(<h1>{getMessage('modals.main.loading')}</h1>);
|
||||
return errorMessage(
|
||||
<div className="loaderHolder">
|
||||
<div id="loader"></div>
|
||||
<span className="subtitle">Just be a sec.</span>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className='changelogtab' ref={this.changelog}>
|
||||
<div className="changelogtab" ref={this.changelog}>
|
||||
<h1>{this.state.title}</h1>
|
||||
<h5>{this.state.author} • {this.state.date}</h5>
|
||||
{this.state.image ? <img draggable='false' src={this.state.image} alt={this.state.title} className='updateimage'/> : null}
|
||||
<div className='updatechangelog' dangerouslySetInnerHTML={{ __html: this.state.html }}/>
|
||||
<Modal closeTimeoutMS={100} onRequestClose={() => this.setState({ showLightbox: false })} isOpen={this.state.showLightbox} className='Modal lightboxmodal' overlayClassName='Overlay resetoverlay' ariaHideApp={false}>
|
||||
<Lightbox modalClose={() => this.setState({ showLightbox: false })} img={this.state.lightboxImg}/>
|
||||
<h5>
|
||||
{this.state.author} • {this.state.date}
|
||||
</h5>
|
||||
{this.state.image ? (
|
||||
<img
|
||||
draggable="false"
|
||||
src={this.state.image}
|
||||
alt={this.state.title}
|
||||
className="updateImage"
|
||||
/>
|
||||
) : null}
|
||||
<div
|
||||
className="updateChangelog"
|
||||
dangerouslySetInnerHTML={{ __html: this.state.html }}
|
||||
/>
|
||||
<Modal
|
||||
closeTimeoutMS={100}
|
||||
onRequestClose={() => this.setState({ showLightbox: false })}
|
||||
isOpen={this.state.showLightbox}
|
||||
className="Modal lightBoxModal"
|
||||
overlayClassName="Overlay resetoverlay"
|
||||
ariaHideApp={false}
|
||||
>
|
||||
<Lightbox
|
||||
modalClose={() => this.setState({ showLightbox: false })}
|
||||
img={this.state.lightboxImg}
|
||||
/>
|
||||
</Modal>
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -1,49 +1,93 @@
|
|||
import variables from 'modules/variables';
|
||||
import { PureComponent } from 'react';
|
||||
import variables from "modules/variables";
|
||||
import { PureComponent } from "react";
|
||||
|
||||
import Header from '../Header';
|
||||
import Checkbox from '../Checkbox';
|
||||
import Dropdown from '../Dropdown';
|
||||
import Header from "../Header";
|
||||
import Checkbox from "../Checkbox";
|
||||
import Dropdown from "../Dropdown";
|
||||
import SettingsItem from "../SettingsItem";
|
||||
|
||||
export default class DateSettings extends PureComponent {
|
||||
constructor() {
|
||||
super();
|
||||
this.state = {
|
||||
dateType: localStorage.getItem('dateType') || 'long'
|
||||
dateType: localStorage.getItem("dateType") || "long",
|
||||
};
|
||||
}
|
||||
|
||||
render() {
|
||||
const getMessage = (text) => variables.language.getMessage(variables.languagecode, text);
|
||||
const getMessage = (text) =>
|
||||
variables.language.getMessage(variables.languagecode, text);
|
||||
|
||||
let dateSettings;
|
||||
|
||||
|
||||
const longSettings = (
|
||||
<>
|
||||
<Checkbox name='dayofweek' text={getMessage('modals.main.settings.sections.date.day_of_week')} category='date' />
|
||||
<Checkbox name='datenth' text={getMessage('modals.main.settings.sections.date.datenth')} category='date' />
|
||||
<Dropdown
|
||||
label="Long Format"
|
||||
name="longFormat"
|
||||
category="date"
|
||||
>
|
||||
<option value="DMY">DMY</option>
|
||||
<option value="MDY">MDY</option>
|
||||
<option value="YMD">YMD</option>
|
||||
</Dropdown>
|
||||
<Checkbox
|
||||
name="dayofweek"
|
||||
text={getMessage("modals.main.settings.sections.date.day_of_week")}
|
||||
category="date"
|
||||
/>
|
||||
<Checkbox
|
||||
name="datenth"
|
||||
text={getMessage("modals.main.settings.sections.date.datenth")}
|
||||
category="date"
|
||||
/>
|
||||
</>
|
||||
);
|
||||
|
||||
const shortSettings = (
|
||||
<>
|
||||
|
||||
<Dropdown label={getMessage('modals.main.settings.sections.date.short_format')} name='dateFormat' category='date'>
|
||||
<option value='DMY'>DMY</option>
|
||||
<option value='MDY'>MDY</option>
|
||||
<option value='YMD'>YMD</option>
|
||||
<Dropdown
|
||||
label={getMessage("modals.main.settings.sections.date.short_format")}
|
||||
name="dateFormat"
|
||||
category="date"
|
||||
>
|
||||
<option value="DMY">DMY</option>
|
||||
<option value="MDY">MDY</option>
|
||||
<option value="YMD">YMD</option>
|
||||
</Dropdown>
|
||||
|
||||
<Dropdown
|
||||
label={getMessage(
|
||||
"modals.main.settings.sections.date.short_separator.title"
|
||||
)}
|
||||
name="shortFormat"
|
||||
category="date"
|
||||
>
|
||||
<option value="dash">
|
||||
{getMessage(
|
||||
"modals.main.settings.sections.date.short_separator.dash"
|
||||
)}
|
||||
</option>
|
||||
<option value="dots">
|
||||
{getMessage(
|
||||
"modals.main.settings.sections.date.short_separator.dots"
|
||||
)}
|
||||
</option>
|
||||
<option value="gaps">
|
||||
{getMessage(
|
||||
"modals.main.settings.sections.date.short_separator.gaps"
|
||||
)}
|
||||
</option>
|
||||
<option value="slashes">
|
||||
{getMessage(
|
||||
"modals.main.settings.sections.date.short_separator.slashes"
|
||||
)}
|
||||
</option>
|
||||
</Dropdown>
|
||||
|
||||
<Dropdown label={getMessage('modals.main.settings.sections.date.short_separator.title')} name='shortFormat' category='date'>
|
||||
<option value='dash'>{getMessage('modals.main.settings.sections.date.short_separator.dash')}</option>
|
||||
<option value='dots'>{getMessage('modals.main.settings.sections.date.short_separator.dots')}</option>
|
||||
<option value='gaps'>{getMessage('modals.main.settings.sections.date.short_separator.gaps')}</option>
|
||||
<option value='slashes'>{getMessage('modals.main.settings.sections.date.short_separator.slashes')}</option>
|
||||
</Dropdown>
|
||||
</>
|
||||
);
|
||||
|
||||
if (this.state.dateType === 'long') {
|
||||
if (this.state.dateType === "long") {
|
||||
dateSettings = longSettings;
|
||||
} else {
|
||||
dateSettings = shortSettings;
|
||||
|
@ -51,15 +95,42 @@ export default class DateSettings extends PureComponent {
|
|||
|
||||
return (
|
||||
<>
|
||||
<Header title={getMessage('modals.main.settings.sections.date.title')} setting='date' category='date' element='.date' zoomSetting='zoomDate'/>
|
||||
<Checkbox name='weeknumber' text={getMessage('modals.main.settings.sections.date.week_number')} category='date'/>
|
||||
<Dropdown label={getMessage('modals.main.settings.sections.time.type')} name='dateType' onChange={(value) => this.setState({ dateType: value })} category='date'>
|
||||
<option value='long'>{getMessage('modals.main.settings.sections.date.type.long')}</option>
|
||||
<option value='short'>{getMessage('modals.main.settings.sections.date.type.short')}</option>
|
||||
</Dropdown>
|
||||
|
||||
<Checkbox name='datezero' text={getMessage('modals.main.settings.sections.time.digital.zero')} category='date'/>
|
||||
{dateSettings}
|
||||
<Header
|
||||
title={getMessage("modals.main.settings.sections.date.title")}
|
||||
setting="date"
|
||||
category="date"
|
||||
element=".date"
|
||||
zoomSetting="zoomDate"
|
||||
switch={true}
|
||||
/>
|
||||
<SettingsItem title="Date Type">
|
||||
<Dropdown
|
||||
label={getMessage("modals.main.settings.sections.time.type")}
|
||||
name="dateType"
|
||||
onChange={(value) => this.setState({ dateType: value })}
|
||||
category="date"
|
||||
>
|
||||
<option value="long">
|
||||
{getMessage("modals.main.settings.sections.date.type.long")}
|
||||
</option>
|
||||
<option value="short">
|
||||
{getMessage("modals.main.settings.sections.date.type.short")}
|
||||
</option>
|
||||
</Dropdown>
|
||||
</SettingsItem>
|
||||
<SettingsItem title="Extra Options">
|
||||
<Checkbox
|
||||
name="weeknumber"
|
||||
text={getMessage("modals.main.settings.sections.date.week_number")}
|
||||
category="date"
|
||||
/>
|
||||
<Checkbox
|
||||
name="datezero"
|
||||
text={getMessage("modals.main.settings.sections.time.digital.zero")}
|
||||
category="date"
|
||||
/>
|
||||
{dateSettings}
|
||||
</SettingsItem>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,31 +1,69 @@
|
|||
import variables from 'modules/variables';
|
||||
import { useState } from 'react';
|
||||
import Checkbox from '../Checkbox';
|
||||
import Slider from '../Slider';
|
||||
import { TextField } from '@mui/material';
|
||||
import variables from "modules/variables";
|
||||
import { useState } from "react";
|
||||
import Checkbox from "../Checkbox";
|
||||
import Slider from "../Slider";
|
||||
import { TextField } from "@mui/material";
|
||||
|
||||
import EventBus from 'modules/helpers/eventbus';
|
||||
import { values } from 'modules/helpers/settings/modals';
|
||||
import EventBus from "modules/helpers/eventbus";
|
||||
import { values } from "modules/helpers/settings/modals";
|
||||
|
||||
export default function ExperimentalSettings() {
|
||||
const getMessage = (text) => variables.language.getMessage(variables.languagecode, text);
|
||||
const getMessage = (text) =>
|
||||
variables.language.getMessage(variables.languagecode, text);
|
||||
const [eventType, setEventType] = useState();
|
||||
const [eventName, setEventName] = useState();
|
||||
|
||||
return (
|
||||
<>
|
||||
<h2>{getMessage('modals.main.settings.sections.experimental.title')}</h2>
|
||||
<p>{getMessage('modals.main.settings.sections.experimental.warning')}</p>
|
||||
<h3>{getMessage('modals.main.settings.sections.experimental.developer')}</h3>
|
||||
<Checkbox name='debug' text='Debug hotkey (Ctrl + #)' element='.other'/>
|
||||
<Slider title='Debug timeout' name='debugtimeout' min='0' max='5000' default='0' step='100' marks={values('experimental')} element='.other' />
|
||||
<h2>{getMessage("modals.main.settings.sections.experimental.title")}</h2>
|
||||
<p>{getMessage("modals.main.settings.sections.experimental.warning")}</p>
|
||||
<h3>
|
||||
{getMessage("modals.main.settings.sections.experimental.developer")}
|
||||
</h3>
|
||||
<Checkbox name="debug" text="Debug hotkey (Ctrl + #)" element=".other" />
|
||||
<Slider
|
||||
title="Debug timeout"
|
||||
name="debugtimeout"
|
||||
min="0"
|
||||
max="5000"
|
||||
default="0"
|
||||
step="100"
|
||||
marks={values("experimental")}
|
||||
element=".other"
|
||||
/>
|
||||
<p>Send Event</p>
|
||||
<TextField label={'Type'} value={eventType} onChange={(e) => setEventType(e.target.value)} spellCheck={false} varient='outlined' InputLabelProps={{ shrink: true }} />
|
||||
<TextField label={'Name'} value={eventName} onChange={(e) => setEventName(e.target.value)} spellCheck={false} varient='outlined' InputLabelProps={{ shrink: true }} />
|
||||
<br/>
|
||||
<button className='uploadbg' onClick={() => EventBus.dispatch(eventType, eventName)}>Send</button>
|
||||
<br/><br/>
|
||||
<button className='reset' style={{ marginLeft: '0px' }} onClick={() => localStorage.clear()}>Clear LocalStorage</button>
|
||||
<TextField
|
||||
label={"Type"}
|
||||
value={eventType}
|
||||
onChange={(e) => setEventType(e.target.value)}
|
||||
spellCheck={false}
|
||||
varient="outlined"
|
||||
InputLabelProps={{ shrink: true }}
|
||||
/>
|
||||
<TextField
|
||||
label={"Name"}
|
||||
value={eventName}
|
||||
onChange={(e) => setEventName(e.target.value)}
|
||||
spellCheck={false}
|
||||
varient="outlined"
|
||||
InputLabelProps={{ shrink: true }}
|
||||
/>
|
||||
<br />
|
||||
<button
|
||||
className="uploadbg"
|
||||
onClick={() => EventBus.dispatch(eventType, eventName)}
|
||||
>
|
||||
Send
|
||||
</button>
|
||||
<br />
|
||||
<br />
|
||||
<button
|
||||
className="reset"
|
||||
style={{ marginLeft: "0px" }}
|
||||
onClick={() => localStorage.clear()}
|
||||
>
|
||||
Clear LocalStorage
|
||||
</button>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@ import Header from '../Header';
|
|||
import Checkbox from '../Checkbox';
|
||||
import Switch from '../Switch';
|
||||
import Text from '../Text';
|
||||
import SettingsItem from '../SettingsItem';
|
||||
|
||||
export default class GreetingSettings extends PureComponent {
|
||||
constructor() {
|
||||
|
@ -27,17 +28,24 @@ export default class GreetingSettings extends PureComponent {
|
|||
|
||||
return (
|
||||
<>
|
||||
<Header title={getMessage('modals.main.settings.sections.greeting.title')} setting='greeting' category='greeting' element='.greeting' zoomSetting='zoomGreeting'/>
|
||||
<Header title={getMessage('modals.main.settings.sections.greeting.title')} setting='greeting' category='greeting' element='.greeting' zoomSetting='zoomGreeting' switch={true}/>
|
||||
<SettingsItem title={getMessage('modals.main.settings.sections.greeting.birthday')} subtitle={getMessage('modals.main.settings.enabled')}>
|
||||
<Switch name='birthdayenabled' text={getMessage('modals.main.settings.enabled')} category='greeting'/>
|
||||
<Checkbox name='birthdayage' text={getMessage('modals.main.settings.sections.greeting.birthday_age')} category='greeting'/>
|
||||
<p>{getMessage('modals.main.settings.sections.greeting.birthday_date')}</p>
|
||||
<input type='date' onChange={this.changeDate} value={this.state.birthday.toISOString().substr(0, 10)} required/>
|
||||
</SettingsItem>
|
||||
<SettingsItem title="Additional Settings" subtitle={getMessage('modals.main.settings.enabled')}>
|
||||
<Checkbox name='events' text={getMessage('modals.main.settings.sections.greeting.events')} category='greeting'/>
|
||||
<Checkbox name='defaultGreetingMessage' text={getMessage('modals.main.settings.sections.greeting.default')} category='greeting'/>
|
||||
<Text title={getMessage('modals.main.settings.sections.greeting.name')} name='greetingName' category='greeting'/>
|
||||
|
||||
<h3>{getMessage('modals.main.settings.sections.greeting.birthday')}</h3>
|
||||
</SettingsItem>
|
||||
{/*<h3>{getMessage('modals.main.settings.sections.greeting.birthday')}</h3>
|
||||
<Switch name='birthdayenabled' text={getMessage('modals.main.settings.enabled')} category='greeting'/>
|
||||
<br/>
|
||||
<Checkbox name='birthdayage' text={getMessage('modals.main.settings.sections.greeting.birthday_age')} category='greeting'/>
|
||||
<p>{getMessage('modals.main.settings.sections.greeting.birthday_date')}</p>
|
||||
<input type='date' onChange={this.changeDate} value={this.state.birthday.toISOString().substr(0, 10)} required/>
|
||||
<input type='date' onChange={this.changeDate} value={this.state.birthday.toISOString().substr(0, 10)} required/>*/}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -11,16 +11,22 @@ export default class LanguageSettings extends PureComponent {
|
|||
constructor() {
|
||||
super();
|
||||
this.state = {
|
||||
quoteLanguages: [{
|
||||
name: this.getMessage('modals.main.loading'),
|
||||
value: 'loading'
|
||||
}]
|
||||
quoteLanguages: [
|
||||
{
|
||||
name: this.getMessage('modals.main.loading'),
|
||||
value: 'loading',
|
||||
},
|
||||
],
|
||||
};
|
||||
this.controller = new AbortController();
|
||||
}
|
||||
|
||||
async getQuoteLanguages() {
|
||||
const data = await (await fetch(variables.constants.API_URL + '/quotes/languages', { signal: this.controller.signal })).json();
|
||||
const data = await (
|
||||
await fetch(variables.constants.API_URL + '/quotes/languages', {
|
||||
signal: this.controller.signal,
|
||||
})
|
||||
).json();
|
||||
|
||||
if (this.controller.signal.aborted === true) {
|
||||
return;
|
||||
|
@ -30,22 +36,24 @@ export default class LanguageSettings extends PureComponent {
|
|||
data.forEach((item) => {
|
||||
quoteLanguages.push({
|
||||
name: item,
|
||||
value: item
|
||||
value: item,
|
||||
});
|
||||
});
|
||||
|
||||
this.setState({
|
||||
quoteLanguages
|
||||
quoteLanguages,
|
||||
});
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
if (navigator.onLine === false || localStorage.getItem('offlineMode') === 'true') {
|
||||
return this.setState({
|
||||
quoteLanguages: [{
|
||||
name: this.getMessage('modals.main.marketplace.offline.description'),
|
||||
value: 'loading'
|
||||
}]
|
||||
quoteLanguages: [
|
||||
{
|
||||
name: this.getMessage('modals.main.marketplace.offline.description'),
|
||||
value: 'loading',
|
||||
},
|
||||
],
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -60,10 +68,18 @@ export default class LanguageSettings extends PureComponent {
|
|||
render() {
|
||||
return (
|
||||
<>
|
||||
<h2>{this.getMessage('modals.main.settings.sections.language.title')}</h2>
|
||||
<Radio name='language' options={languages} element='.other' />
|
||||
<h3>{this.getMessage('modals.main.settings.sections.language.quote')}</h3>
|
||||
<Radio name='quotelanguage' options={this.state.quoteLanguages} category='quote' />
|
||||
<span className="mainTitle">
|
||||
{this.getMessage('modals.main.settings.sections.language.title')}
|
||||
</span>
|
||||
<div className={'languageSettings'}>
|
||||
<Radio name="language" options={languages} element=".other" />
|
||||
</div>
|
||||
<span className={'mainTitle'}>
|
||||
{this.getMessage('modals.main.settings.sections.language.quote')}
|
||||
</span>
|
||||
<div className={'languageSettings'}>
|
||||
<Radio name="quotelanguage" options={this.state.quoteLanguages} category="quote" />
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -2,7 +2,8 @@ import variables from 'modules/variables';
|
|||
import { PureComponent } from 'react';
|
||||
import { MdCancel, MdAdd } from 'react-icons/md';
|
||||
import { toast } from 'react-toastify';
|
||||
import { TextField } from '@mui/material';
|
||||
import { TextField, TextareaAutosize } from '@mui/material';
|
||||
import SettingsItem from '../SettingsItem';
|
||||
|
||||
import Header from '../Header';
|
||||
|
||||
|
@ -21,22 +22,22 @@ export default class Message extends PureComponent {
|
|||
reset = () => {
|
||||
localStorage.setItem('messages', '[""]');
|
||||
this.setState({
|
||||
messages: ['']
|
||||
messages: [''],
|
||||
});
|
||||
toast(this.getMessage(this.languagecode, 'toasts.reset'));
|
||||
EventBus.dispatch('refresh', 'message');
|
||||
}
|
||||
};
|
||||
|
||||
modifyMessage(type, index) {
|
||||
const messages = this.state.messages;
|
||||
if (type === 'add') {
|
||||
messages.push('');
|
||||
messages.push(' ');
|
||||
} else {
|
||||
messages.splice(index, 1);
|
||||
}
|
||||
|
||||
this.setState({
|
||||
messages
|
||||
messages,
|
||||
});
|
||||
this.forceUpdate();
|
||||
|
||||
|
@ -44,37 +45,67 @@ export default class Message extends PureComponent {
|
|||
}
|
||||
|
||||
message(e, text, index) {
|
||||
const result = (text === true) ? e.target.value : e.target.result;
|
||||
const result = text === true ? e.target.value : e.target.result;
|
||||
|
||||
const messages = this.state.messages;
|
||||
messages[index] = result;
|
||||
this.setState({
|
||||
messages
|
||||
messages,
|
||||
});
|
||||
this.forceUpdate();
|
||||
|
||||
localStorage.setItem('messages', JSON.stringify(messages));
|
||||
document.querySelector('.reminder-info').style.display = 'block';
|
||||
document.querySelector('.reminder-info').style.display = 'flex';
|
||||
localStorage.setItem('showReminder', true);
|
||||
}
|
||||
|
||||
|
||||
render() {
|
||||
return (
|
||||
<>
|
||||
<Header title={this.getMessage('modals.main.settings.sections.message.title')} setting='message' category='message' element='.message' zoomSetting='zoomMessage'/>
|
||||
<p>{this.getMessage('modals.main.settings.sections.message.text')}</p>
|
||||
<div className='data-buttons-row'>
|
||||
<button onClick={() => this.modifyMessage('add')}>{this.getMessage('modals.main.settings.sections.message.add')} <MdAdd/></button>
|
||||
</div>
|
||||
{this.state.messages.map((_url, index) => (
|
||||
<div style={{ display: 'flex' }} key={index}>
|
||||
<TextField value={this.state.messages[index]} onChange={(e) => this.message(e, true, index)} varient='outlined' />
|
||||
{this.state.messages.length > 1 ? <button className='cleanButton' onClick={() => this.modifyMessage('remove', index)}>
|
||||
<MdCancel/>
|
||||
</button> : null}
|
||||
</div>
|
||||
))}
|
||||
<br/>
|
||||
<Header
|
||||
title={this.getMessage('modals.main.settings.sections.message.title')}
|
||||
setting="message"
|
||||
category="message"
|
||||
element=".message"
|
||||
zoomSetting="zoomMessage"
|
||||
switch={true}
|
||||
/>
|
||||
<SettingsItem
|
||||
title={this.getMessage('modals.main.settings.sections.message.text')}
|
||||
subtitle=""
|
||||
>
|
||||
<button onClick={() => this.modifyMessage('add')}>
|
||||
{this.getMessage('modals.main.settings.sections.message.add')} <MdAdd />
|
||||
</button>
|
||||
</SettingsItem>
|
||||
<table style={{ width: '100%' }}>
|
||||
<tr>
|
||||
<th>Messages</th>
|
||||
<th>Buttons</th>
|
||||
</tr>
|
||||
{this.state.messages.map((_url, index) => (
|
||||
<tr>
|
||||
<th>
|
||||
<TextareaAutosize
|
||||
value={this.state.messages[index]}
|
||||
placeholder="Message"
|
||||
onChange={(e) => this.message(e, true, index)}
|
||||
varient="outlined"
|
||||
/>
|
||||
</th>
|
||||
<th>
|
||||
{this.state.messages.length > 1 ? (
|
||||
<button
|
||||
className='deleteButton'
|
||||
onClick={() => this.modifyMessage('remove', index)}>
|
||||
<MdCancel />
|
||||
</button>
|
||||
) : null}
|
||||
</th>
|
||||
</tr>
|
||||
))}
|
||||
</table>
|
||||
<br />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,34 +1,76 @@
|
|||
import variables from 'modules/variables';
|
||||
|
||||
import { PureComponent } from 'react';
|
||||
import { useState } from 'react';
|
||||
|
||||
import Checkbox from '../Checkbox';
|
||||
import Dropdown from '../Dropdown';
|
||||
import Slider from '../Slider';
|
||||
|
||||
import { values } from 'modules/helpers/settings/modals';
|
||||
import SettingsItem from '../SettingsItem';
|
||||
import Header from '../Header';
|
||||
|
||||
export default class Navbar extends PureComponent {
|
||||
render() {
|
||||
const getMessage = (text) => variables.language.getMessage(variables.languagecode, text);
|
||||
export default function Navbar() {
|
||||
const getMessage = (text) => variables.language.getMessage(variables.languagecode, text);
|
||||
const [showRefreshOptions, setShowRefreshOptions] = useState(
|
||||
localStorage.getItem('refresh') === 'true',
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
<h2>{getMessage('modals.main.settings.sections.appearance.navbar.title')}</h2>
|
||||
<Slider title={getMessage('modals.main.settings.sections.appearance.accessibility.widget_zoom')} name='zoomNavbar' min='10' max='400' default='100' display='%' marks={values('zoom')} category='navbar' />
|
||||
<Checkbox name='navbarHover' text={getMessage('modals.main.settings.sections.appearance.navbar.hover')} category='navbar'/>
|
||||
<Checkbox name='notesEnabled' text={getMessage('modals.main.settings.sections.appearance.navbar.notes')} category='navbar' />
|
||||
<Checkbox name='view' text={getMessage('modals.main.settings.sections.background.buttons.view')} category='navbar' />
|
||||
<Checkbox name='favouriteEnabled' text={getMessage('modals.main.settings.sections.background.buttons.favourite')} category='navbar' />
|
||||
<Dropdown label={getMessage('modals.main.settings.sections.appearance.navbar.refresh')} name='refresh' category='navbar'>
|
||||
<option value='false'>{getMessage('modals.main.settings.sections.appearance.navbar.refresh_options.none')}</option>
|
||||
<option value='background'>{getMessage('modals.main.settings.sections.background.title')}</option>
|
||||
<option value='quote'>{getMessage('modals.main.settings.sections.quote.title')}</option>
|
||||
<option value='quotebackground'>{getMessage('modals.main.settings.sections.quote.title')} + {getMessage('modals.main.settings.sections.background.title')}</option>
|
||||
{/* before it was just a checkbox */}
|
||||
<option value='true'>{getMessage('modals.main.settings.sections.appearance.navbar.refresh_options.page')}</option>
|
||||
</Dropdown>
|
||||
</>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<>
|
||||
<Header
|
||||
title={getMessage('modals.main.settings.sections.appearance.navbar.title')}
|
||||
setting="navbar"
|
||||
category="widgets"
|
||||
zoomSetting="zoomNavbar"
|
||||
zoomCategory="navbar"
|
||||
/>
|
||||
<SettingsItem title="Extra Options" subtitle="subtitle" final={!showRefreshOptions}>
|
||||
<Checkbox
|
||||
name="navbarHover"
|
||||
text={getMessage('modals.main.settings.sections.appearance.navbar.hover')}
|
||||
category="navbar"
|
||||
/>
|
||||
<Checkbox
|
||||
name="notesEnabled"
|
||||
text={getMessage('modals.main.settings.sections.appearance.navbar.notes')}
|
||||
category="navbar"
|
||||
/>
|
||||
<Checkbox
|
||||
name="view"
|
||||
text={getMessage('modals.main.settings.sections.background.buttons.view')}
|
||||
category="navbar"
|
||||
/>
|
||||
<Checkbox
|
||||
name="refresh"
|
||||
text={getMessage('modals.main.settings.sections.appearance.navbar.refresh')}
|
||||
category="navbar"
|
||||
onChange={setShowRefreshOptions}
|
||||
/>
|
||||
<Checkbox name="todo" text="Todos" category="navbar" />
|
||||
</SettingsItem>
|
||||
{showRefreshOptions ? (
|
||||
<SettingsItem
|
||||
title={getMessage('modals.main.settings.sections.appearance.navbar.refresh')}
|
||||
final={true}
|
||||
>
|
||||
<Dropdown
|
||||
label={getMessage('modals.main.settings.sections.appearance.navbar.refresh')}
|
||||
name="refreshOption"
|
||||
category="navbar"
|
||||
>
|
||||
<option value="page">
|
||||
{getMessage('modals.main.settings.sections.appearance.navbar.refresh_options.page')}
|
||||
</option>
|
||||
<option value="background">
|
||||
{getMessage('modals.main.settings.sections.background.title')}
|
||||
</option>
|
||||
<option value="quote">{getMessage('modals.main.settings.sections.quote.title')}</option>
|
||||
<option value="quotebackground">
|
||||
{getMessage('modals.main.settings.sections.quote.title')} +{' '}
|
||||
{getMessage('modals.main.settings.sections.background.title')}
|
||||
</option>
|
||||
</Dropdown>
|
||||
</SettingsItem>
|
||||
) : null}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -13,25 +13,26 @@ const widget_name = {
|
|||
quicklinks: getMessage('modals.main.settings.sections.quicklinks.title'),
|
||||
quote: getMessage('modals.main.settings.sections.quote.title'),
|
||||
date: getMessage('modals.main.settings.sections.date.title'),
|
||||
message: getMessage('modals.main.settings.sections.message.title')
|
||||
message: getMessage('modals.main.settings.sections.message.title'),
|
||||
reminder: 'reminder',
|
||||
};
|
||||
|
||||
const SortableItem = sortableElement(({ value }) => (
|
||||
<li className='sortableitem'>
|
||||
<li className="sortableItem">
|
||||
<MdOutlineDragIndicator style={{ verticalAlign: 'middle' }} />
|
||||
{widget_name[value]}
|
||||
</li>
|
||||
));
|
||||
|
||||
|
||||
const SortableContainer = sortableContainer(({ children }) => (
|
||||
<ul className='sortablecontainer'>{children}</ul>
|
||||
<ul className="sortablecontainer">{children}</ul>
|
||||
));
|
||||
|
||||
export default class OrderSettings extends PureComponent {
|
||||
constructor() {
|
||||
super();
|
||||
this.state = {
|
||||
items: JSON.parse(localStorage.getItem('order'))
|
||||
items: JSON.parse(localStorage.getItem('order')),
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -39,34 +40,37 @@ export default class OrderSettings extends PureComponent {
|
|||
const result = Array.from(array);
|
||||
const [removed] = result.splice(oldIndex, 1);
|
||||
result.splice(newIndex, 0, removed);
|
||||
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
onSortEnd = ({ oldIndex, newIndex }) => {
|
||||
this.setState({
|
||||
items: this.arrayMove(this.state.items, oldIndex, newIndex)
|
||||
items: this.arrayMove(this.state.items, oldIndex, newIndex),
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
reset = () => {
|
||||
localStorage.setItem('order', JSON.stringify(['greeting', 'time', 'quicklinks', 'quote', 'date', 'message']));
|
||||
|
||||
localStorage.setItem(
|
||||
'order',
|
||||
JSON.stringify(['greeting', 'time', 'quicklinks', 'quote', 'date', 'message', 'reminder']),
|
||||
);
|
||||
|
||||
this.setState({
|
||||
items: JSON.parse(localStorage.getItem('order'))
|
||||
items: JSON.parse(localStorage.getItem('order')),
|
||||
});
|
||||
|
||||
toast(getMessage('toasts.reset'));
|
||||
}
|
||||
};
|
||||
|
||||
enabled = (setting) => {
|
||||
switch (setting) {
|
||||
case 'quicklinks':
|
||||
return (localStorage.getItem('quicklinksenabled') === 'true');
|
||||
return localStorage.getItem('quicklinksenabled') === 'true';
|
||||
default:
|
||||
return (localStorage.getItem(setting) === 'true');
|
||||
return localStorage.getItem(setting) === 'true';
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
componentDidUpdate() {
|
||||
localStorage.setItem('order', JSON.stringify(this.state.items));
|
||||
|
@ -77,17 +81,22 @@ export default class OrderSettings extends PureComponent {
|
|||
render() {
|
||||
return (
|
||||
<>
|
||||
<h2>{getMessage('modals.main.settings.sections.order.title')}</h2>
|
||||
<span className='modalLink' onClick={this.reset}>{getMessage('modals.main.settings.buttons.reset')}</span>
|
||||
<SortableContainer onSortEnd={this.onSortEnd} lockAxis='y' lockToContainerEdges disableAutoscroll>
|
||||
<span className="mainTitle">{getMessage('modals.main.settings.sections.order.title')}</span>
|
||||
<span className="link" onClick={this.reset}>
|
||||
{getMessage('modals.main.settings.buttons.reset')}
|
||||
</span>
|
||||
<SortableContainer
|
||||
onSortEnd={this.onSortEnd}
|
||||
lockAxis="y"
|
||||
lockToContainerEdges
|
||||
disableAutoscroll
|
||||
>
|
||||
{this.state.items.map((value, index) => {
|
||||
if (!this.enabled(value)) {
|
||||
if (!this.enabled(value)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<SortableItem key={`item-${value}`} index={index} value={value} />
|
||||
);
|
||||
return <SortableItem key={`item-${value}`} index={index} value={value} />;
|
||||
})}
|
||||
</SortableContainer>
|
||||
</>
|
||||
|
|
|
@ -4,17 +4,21 @@ import { useState } from 'react';
|
|||
import Header from '../Header';
|
||||
import Checkbox from '../Checkbox';
|
||||
|
||||
import SettingsItem from '../SettingsItem';
|
||||
|
||||
export default function QuickLinks() {
|
||||
const getMessage = (text) => variables.language.getMessage(variables.languagecode, text);
|
||||
const [textOnly, setTextOnly] = useState(localStorage.getItem('quicklinksText') === 'true');
|
||||
|
||||
return (
|
||||
<>
|
||||
<Header title={getMessage('modals.main.settings.sections.quicklinks.title')} setting='quicklinksenabled' category='quicklinks' element='.quicklinks-container' zoomSetting='zoomQuicklinks'/>
|
||||
<Checkbox name='quicklinksText' text={getMessage('modals.main.settings.sections.quicklinks.text_only')} category='quicklinks' onChange={(value) => setTextOnly(value)}/>
|
||||
<Checkbox name='quicklinksddgProxy' text={getMessage('modals.main.settings.sections.background.ddg_image_proxy')} category='quicklinks' disabled={textOnly}/>
|
||||
<Checkbox name='quicklinksnewtab' text={getMessage('modals.main.settings.sections.quicklinks.open_new')} category='quicklinks'/>
|
||||
<Checkbox name='quicklinkstooltip' text={getMessage('modals.main.settings.sections.quicklinks.tooltip')} category='quicklinks' disabled={textOnly}/>
|
||||
<Header title={getMessage('modals.main.settings.sections.quicklinks.title')} setting='quicklinksenabled' category='quicklinks' element='.quicklinks-container' zoomSetting='zoomQuicklinks' switch={true}/>
|
||||
<SettingsItem title="Extra Options" subtitle="subtitle">
|
||||
<Checkbox name='quicklinksText' text={getMessage('modals.main.settings.sections.quicklinks.text_only')} category='quicklinks' onChange={(value) => setTextOnly(value)}/>
|
||||
<Checkbox name='quicklinksddgProxy' text={getMessage('modals.main.settings.sections.background.ddg_image_proxy')} category='quicklinks' disabled={textOnly}/>
|
||||
<Checkbox name='quicklinksnewtab' text={getMessage('modals.main.settings.sections.quicklinks.open_new')} category='quicklinks'/>
|
||||
<Checkbox name='quicklinkstooltip' text={getMessage('modals.main.settings.sections.quicklinks.tooltip')} category='quicklinks' disabled={textOnly}/>
|
||||
</SettingsItem>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,11 +1,13 @@
|
|||
import variables from 'modules/variables';
|
||||
import { PureComponent } from 'react';
|
||||
import React, { PureComponent } from 'react';
|
||||
import { MdCancel, MdAdd } from 'react-icons/md';
|
||||
import { TextField } from '@mui/material';
|
||||
import TextareaAutosize from '@mui/material/TextareaAutosize';
|
||||
|
||||
import Header from '../Header';
|
||||
import Checkbox from '../Checkbox';
|
||||
import Dropdown from '../Dropdown';
|
||||
import SettingsItem from '../SettingsItem';
|
||||
|
||||
import { toast } from 'react-toastify';
|
||||
import EventBus from 'modules/helpers/eventbus';
|
||||
|
@ -17,40 +19,44 @@ export default class QuoteSettings extends PureComponent {
|
|||
super();
|
||||
this.state = {
|
||||
quoteType: localStorage.getItem('quoteType') || 'api',
|
||||
customQuote: this.getCustom()
|
||||
customQuote: this.getCustom(),
|
||||
};
|
||||
}
|
||||
|
||||
marketplaceType = () => {
|
||||
if (localStorage.getItem('quote_packs')) {
|
||||
return <option value='quote_pack'>{this.getMessage('modals.main.navbar.marketplace')}</option>;
|
||||
return (
|
||||
<option value="quote_pack">{this.getMessage('modals.main.navbar.marketplace')}</option>
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
resetCustom = () => {
|
||||
localStorage.setItem('customQuote', '[{"quote": "", "author": ""}]');
|
||||
this.setState({
|
||||
customQuote: [{
|
||||
quote: '',
|
||||
author: ''
|
||||
}]
|
||||
customQuote: [
|
||||
{
|
||||
quote: '',
|
||||
author: '',
|
||||
},
|
||||
],
|
||||
});
|
||||
toast(this.getMessage('toasts.reset'));
|
||||
EventBus.dispatch('refresh', 'background');
|
||||
}
|
||||
};
|
||||
|
||||
customQuote(e, text, index, type) {
|
||||
const result = (text === true) ? e.target.value : e.target.result;
|
||||
const result = text === true ? e.target.value : e.target.result;
|
||||
|
||||
const customQuote = this.state.customQuote;
|
||||
customQuote[index][type] = result;
|
||||
this.setState({
|
||||
customQuote
|
||||
customQuote,
|
||||
});
|
||||
this.forceUpdate();
|
||||
|
||||
localStorage.setItem('customQuote', JSON.stringify(customQuote));
|
||||
document.querySelector('.reminder-info').style.display = 'block';
|
||||
document.querySelector('.reminder-info').style.display = 'flex';
|
||||
localStorage.setItem('showReminder', true);
|
||||
}
|
||||
|
||||
|
@ -59,14 +65,14 @@ export default class QuoteSettings extends PureComponent {
|
|||
if (type === 'add') {
|
||||
customQuote.push({
|
||||
quote: '',
|
||||
author: ''
|
||||
author: '',
|
||||
});
|
||||
} else {
|
||||
customQuote.splice(index, 1);
|
||||
}
|
||||
|
||||
this.setState({
|
||||
customQuote
|
||||
customQuote,
|
||||
});
|
||||
this.forceUpdate();
|
||||
|
||||
|
@ -76,10 +82,12 @@ export default class QuoteSettings extends PureComponent {
|
|||
getCustom() {
|
||||
let data = JSON.parse(localStorage.getItem('customQuote'));
|
||||
if (data === null) {
|
||||
data = [{
|
||||
quote: localStorage.getItem('customQuote') || '',
|
||||
author: localStorage.getItem('customQuoteAuthor') || ''
|
||||
}];
|
||||
data = [
|
||||
{
|
||||
quote: localStorage.getItem('customQuote') || '',
|
||||
author: localStorage.getItem('customQuoteAuthor') || '',
|
||||
},
|
||||
];
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
@ -89,53 +97,146 @@ export default class QuoteSettings extends PureComponent {
|
|||
if (this.state.quoteType === 'custom') {
|
||||
customSettings = (
|
||||
<>
|
||||
<p>{this.getMessage('modals.main.settings.sections.quote.custom')} <span className='modalLink' onClick={this.resetCustom}>{this.getMessage('modals.main.settings.buttons.reset')}</span></p>
|
||||
<div className='data-buttons-row'>
|
||||
<button onClick={() => this.modifyCustomQuote('add')}>{this.getMessage('modals.main.settings.sections.quote.add')} <MdAdd/></button>
|
||||
</div>
|
||||
{this.state.customQuote.map((_url, index) => (
|
||||
<div style={{ display: 'flex' }} key={index}>
|
||||
<TextField value={this.state.customQuote[index].quote} placeholder='Quote' onChange={(e) => this.customQuote(e, true, index, 'quote')} varient='outlined' style={{ marginRight: '10px' }} />
|
||||
<TextField value={this.state.customQuote[index].author} placeholder='Author' onChange={(e) => this.customQuote(e, true, index, 'author')} varient='outlined' />
|
||||
{this.state.customQuote.length > 1 ? <button className='cleanButton' onClick={() => this.modifyCustomQuote('remove', index)} style={{ marginBottom: '-14px' }}>
|
||||
<MdCancel/>
|
||||
</button> : null}
|
||||
</div>
|
||||
))}
|
||||
<SettingsItem
|
||||
title={this.getMessage('modals.main.settings.sections.quote.custom')}
|
||||
subtitle="subtitle"
|
||||
>
|
||||
<button onClick={() => this.modifyCustomQuote('add')}>
|
||||
{this.getMessage('modals.main.settings.sections.quote.add')} <MdAdd />
|
||||
</button>
|
||||
</SettingsItem>
|
||||
<table style={{ width: '100%' }}>
|
||||
<tr>
|
||||
<th>Quote</th>
|
||||
<th>Author</th>
|
||||
<th>Buttons</th>
|
||||
</tr>
|
||||
{this.state.customQuote.map((_url, index) => (
|
||||
<tr>
|
||||
<th>
|
||||
<TextareaAutosize
|
||||
value={this.state.customQuote[index].quote}
|
||||
placeholder="Quote"
|
||||
onChange={(e) => this.customQuote(e, true, index, 'quote')}
|
||||
varient="outlined"
|
||||
style={{ marginRight: '10px' }}
|
||||
/>
|
||||
</th>
|
||||
<th>
|
||||
<TextareaAutosize
|
||||
value={this.state.customQuote[index].author}
|
||||
placeholder="Author"
|
||||
onChange={(e) => this.customQuote(e, true, index, 'author')}
|
||||
varient="outlined"
|
||||
/>
|
||||
</th>
|
||||
<th>
|
||||
{this.state.customQuote.length > 1 ? (
|
||||
<button
|
||||
className="deleteButton"
|
||||
onClick={() => this.modifyCustomQuote('remove', index)}
|
||||
style={{}}
|
||||
>
|
||||
<MdCancel />
|
||||
</button>
|
||||
) : null}
|
||||
</th>
|
||||
</tr>
|
||||
))}
|
||||
</table>
|
||||
</>
|
||||
);
|
||||
} else {
|
||||
// api
|
||||
customSettings = (
|
||||
<>
|
||||
<Dropdown label={this.getMessage('modals.main.settings.sections.background.interval.title')} name='quotechange'>
|
||||
<option value='refresh'>{this.getMessage('tabname')}</option>
|
||||
<option value='60000'>{this.getMessage('modals.main.settings.sections.background.interval.minute')}</option>
|
||||
<option value='1800000'>{this.getMessage('modals.main.settings.sections.background.interval.half_hour')}</option>
|
||||
<option value='3600000'>{this.getMessage('modals.main.settings.sections.background.interval.hour')}</option>
|
||||
<option value='86400000'>{this.getMessage('modals.main.settings.sections.background.interval.day')}</option>
|
||||
<option value='604800000'>{this.getMessage('widgets.date.week')}</option>
|
||||
<option value='2628000000'>{this.getMessage('modals.main.settings.sections.background.interval.month')}</option>
|
||||
<SettingsItem title="Additional Options">
|
||||
<Dropdown
|
||||
label={this.getMessage('modals.main.settings.sections.background.interval.title')}
|
||||
name="quotechange"
|
||||
>
|
||||
<option value="refresh">{this.getMessage('tabname')}</option>
|
||||
<option value="60000">
|
||||
{this.getMessage('modals.main.settings.sections.background.interval.minute')}
|
||||
</option>
|
||||
<option value="1800000">
|
||||
{this.getMessage('modals.main.settings.sections.background.interval.half_hour')}
|
||||
</option>
|
||||
<option value="3600000">
|
||||
{this.getMessage('modals.main.settings.sections.background.interval.hour')}
|
||||
</option>
|
||||
<option value="86400000">
|
||||
{this.getMessage('modals.main.settings.sections.background.interval.day')}
|
||||
</option>
|
||||
<option value="604800000">{this.getMessage('widgets.date.week')}</option>
|
||||
<option value="2628000000">
|
||||
{this.getMessage('modals.main.settings.sections.background.interval.month')}
|
||||
</option>
|
||||
</Dropdown>
|
||||
</>
|
||||
</SettingsItem>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<Header title={this.getMessage('modals.main.settings.sections.quote.title')} setting='quote' category='quote' element='.quotediv' zoomSetting='zoomQuote'/>
|
||||
<Checkbox name='authorLink' text={this.getMessage('modals.main.settings.sections.quote.author_link')} element='.other' />
|
||||
<Dropdown label={this.getMessage('modals.main.settings.sections.background.type.title')} name='quoteType' onChange={(value) => this.setState({ quoteType: value })} category='quote'>
|
||||
{this.marketplaceType()}
|
||||
<option value='api'>{this.getMessage('modals.main.settings.sections.background.type.api')}</option>
|
||||
<option value='custom'>{this.getMessage('modals.main.settings.sections.quote.custom')}</option>
|
||||
</Dropdown>
|
||||
<Header
|
||||
title={this.getMessage('modals.main.settings.sections.quote.title')}
|
||||
setting="quote"
|
||||
category="quote"
|
||||
element=".quotediv"
|
||||
zoomSetting="zoomQuote"
|
||||
switch={true}
|
||||
/>
|
||||
<SettingsItem
|
||||
title={this.getMessage('modals.main.settings.sections.quote.buttons.title')}
|
||||
subtitle="subtitle"
|
||||
>
|
||||
<Checkbox
|
||||
name="copyButton"
|
||||
text={this.getMessage('modals.main.settings.sections.quote.buttons.copy')}
|
||||
category="quote"
|
||||
/>
|
||||
<Checkbox
|
||||
name="quoteShareButton"
|
||||
text={this.getMessage('modals.main.settings.sections.quote.buttons.tweet')}
|
||||
category="quote"
|
||||
/>
|
||||
<Checkbox
|
||||
name="favouriteQuoteEnabled"
|
||||
text={this.getMessage('modals.main.settings.sections.quote.buttons.favourite')}
|
||||
category="quote"
|
||||
/>
|
||||
<Checkbox
|
||||
name="authorLink"
|
||||
text={this.getMessage('modals.main.settings.sections.quote.author_link')}
|
||||
element=".other"
|
||||
/>
|
||||
</SettingsItem>
|
||||
<SettingsItem
|
||||
title={this.getMessage('modals.main.settings.sections.background.type.title')}
|
||||
subtitle="subtitle"
|
||||
>
|
||||
<Checkbox name="quoteModern" text="Use modern style" />
|
||||
</SettingsItem>
|
||||
<SettingsItem
|
||||
title={this.getMessage('modals.main.settings.sections.background.type.title')}
|
||||
subtitle="subtitle"
|
||||
>
|
||||
<Dropdown
|
||||
label={this.getMessage('modals.main.settings.sections.background.type.title')}
|
||||
name="quoteType"
|
||||
onChange={(value) => this.setState({ quoteType: value })}
|
||||
category="quote"
|
||||
>
|
||||
{this.marketplaceType()}
|
||||
<option value="api">
|
||||
{this.getMessage('modals.main.settings.sections.background.type.api')}
|
||||
</option>
|
||||
<option value="custom">
|
||||
{this.getMessage('modals.main.settings.sections.quote.custom')}
|
||||
</option>
|
||||
</Dropdown>
|
||||
</SettingsItem>
|
||||
{customSettings}
|
||||
|
||||
<h3>{this.getMessage('modals.main.settings.sections.quote.buttons.title')}</h3>
|
||||
<Checkbox name='copyButton' text={this.getMessage('modals.main.settings.sections.quote.buttons.copy')} category='quote'/>
|
||||
<Checkbox name='tweetButton' text={this.getMessage('modals.main.settings.sections.quote.buttons.tweet')} category='quote'/>
|
||||
<Checkbox name='favouriteQuoteEnabled' text={this.getMessage('modals.main.settings.sections.quote.buttons.favourite')} category='quote'/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
import variables from 'modules/variables';
|
||||
import { PureComponent } from 'react';
|
||||
import Header from '../Header';
|
||||
|
||||
export default class ReminderSettings extends PureComponent {
|
||||
constructor() {
|
||||
super();
|
||||
this.state = {
|
||||
colour: localStorage.getItem('reminderColour') || '#ffa500'
|
||||
};
|
||||
}
|
||||
|
||||
updateColour(event) {
|
||||
const colour = event.target.value;
|
||||
this.setState({ colour });
|
||||
localStorage.setItem('reminderColour', colour);
|
||||
}
|
||||
|
||||
render() {
|
||||
const getMessage = (text) => variables.language.getMessage(variables.languagecode, text);
|
||||
return (
|
||||
<>
|
||||
<Header title='Reminder' setting='reminder' category='reminder' element='.reminder' zoomSetting='zoomReminder' switch={true}/>
|
||||
<input type='color' name='colour' className='colour' onChange={(event) => this.updateColour(event)} value={this.state.colour}></input>
|
||||
<label htmlFor={'colour'} className='customBackgroundHex'>{this.state.colour}</label>
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
|
@ -7,6 +7,7 @@ import Header from '../Header';
|
|||
import Dropdown from '../Dropdown';
|
||||
import Checkbox from '../Checkbox';
|
||||
import Radio from '../Radio';
|
||||
import SettingsItem from '../SettingsItem';
|
||||
|
||||
import EventBus from 'modules/helpers/eventbus';
|
||||
|
||||
|
@ -73,24 +74,31 @@ export default class SearchSettings extends PureComponent {
|
|||
render() {
|
||||
return (
|
||||
<>
|
||||
<Header title={this.getMessage('modals.main.settings.sections.search.title')} setting='searchBar' category='widgets'/>
|
||||
<Header title={this.getMessage('modals.main.settings.sections.search.title')} setting='searchBar' category='widgets' switch={true}/>
|
||||
<SettingsItem title="Extra Options" subtitle="eeeee">
|
||||
{/* not supported on firefox */}
|
||||
{(navigator.userAgent.includes('Chrome') && typeof InstallTrigger === 'undefined') ?
|
||||
<Checkbox name='voiceSearch' text={this.getMessage('modals.main.settings.sections.search.voice_search')} category='search'/>
|
||||
: null}
|
||||
<Checkbox name='searchDropdown' text={this.getMessage('modals.main.settings.sections.search.dropdown')} category='search' element='.other'/>
|
||||
<Checkbox name='searchFocus' text={this.getMessage('modals.main.settings.sections.search.focus')} category='search' element='.other'/>
|
||||
<ul style={{ display: this.state.customDisplay }}>
|
||||
<p style={{ marginTop: '0px' }}><span className='link' onClick={() => this.resetSearch()}>{this.getMessage('modals.main.settings.buttons.reset')}</span></p>
|
||||
<TextField label={this.getMessage('modals.main.settings.sections.search.custom')} value={this.state.customValue} onInput={(e) => this.setState({ customValue: e.target.value })} varient='outlined' InputLabelProps={{ shrink: true }} />
|
||||
</ul>
|
||||
<Checkbox name='autocomplete' text={this.getMessage('modals.main.settings.sections.search.autocomplete')} category='search' />
|
||||
</SettingsItem>
|
||||
<SettingsItem title={this.getMessage('modals.main.settings.sections.search.search_engine')} subtitle="cheese is gucci tbf">
|
||||
<Dropdown label={this.getMessage('modals.main.settings.sections.search.search_engine')} name='searchEngine' onChange={(value) => this.setSearchEngine(value)} manual={true}>
|
||||
{searchEngines.map((engine) => (
|
||||
<MenuItem key={engine.name} value={engine.settingsName}>{engine.name}</MenuItem>
|
||||
))}
|
||||
<MenuItem value='custom'>{this.getMessage('modals.main.settings.sections.search.custom').split(' ')[0]}</MenuItem>
|
||||
</Dropdown>
|
||||
<ul style={{ display: this.state.customDisplay }}>
|
||||
<p style={{ marginTop: '0px' }}><span className='modalLink' onClick={() => this.resetSearch()}>{this.getMessage('modals.main.settings.buttons.reset')}</span></p>
|
||||
<TextField label={this.getMessage('modals.main.settings.sections.search.custom')} value={this.state.customValue} onInput={(e) => this.setState({ customValue: e.target.value })} varient='outlined' InputLabelProps={{ shrink: true }} />
|
||||
</ul>
|
||||
<Checkbox name='autocomplete' text={this.getMessage('modals.main.settings.sections.search.autocomplete')} category='search' />
|
||||
<Radio title={this.getMessage('modals.main.settings.sections.search.autocomplete_provider')} options={autocompleteProviders} name='autocompleteProvider' category='search'/>
|
||||
</SettingsItem>
|
||||
<SettingsItem title={this.getMessage('modals.main.settings.sections.search.autocomplete_provider')} subtitle="cheese">
|
||||
<Radio options={autocompleteProviders} name='autocompleteProvider' category='search'/>
|
||||
</SettingsItem>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
import variables from 'modules/variables';
|
||||
import { PureComponent } from 'react';
|
||||
import { MdShowChart } from 'react-icons/md';
|
||||
|
||||
import Switch from '../Switch';
|
||||
import SettingsItem from '../SettingsItem';
|
||||
|
||||
import EventBus from 'modules/helpers/eventbus';
|
||||
|
||||
|
@ -9,17 +11,17 @@ export default class Stats extends PureComponent {
|
|||
constructor() {
|
||||
super();
|
||||
this.state = {
|
||||
stats: JSON.parse(localStorage.getItem('statsData')) || {}
|
||||
stats: JSON.parse(localStorage.getItem('statsData')) || {},
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
EventBus.on('refresh', (data) => {
|
||||
componentDidMount() {
|
||||
EventBus.on('refresh', (data) => {
|
||||
if (data === 'stats') {
|
||||
if (localStorage.getItem('stats') === 'false') {
|
||||
localStorage.setItem('statsData', JSON.stringify({}));
|
||||
return this.setState({
|
||||
stats: {}
|
||||
stats: {},
|
||||
});
|
||||
}
|
||||
this.forceUpdate();
|
||||
|
@ -37,24 +39,95 @@ export default class Stats extends PureComponent {
|
|||
if (localStorage.getItem('stats') === 'false') {
|
||||
return (
|
||||
<>
|
||||
<h2>{getMessage('modals.main.settings.reminder.title')}</h2>
|
||||
<p>{getMessage('modals.main.settings.sections.stats.warning')}</p>
|
||||
<Switch name='stats' text={getMessage('modals.main.settings.sections.stats.usage')} category='stats'/>
|
||||
<span className="mainTitle">
|
||||
{getMessage('modals.main.settings.sections.stats.title')}
|
||||
</span>
|
||||
<SettingsItem
|
||||
title={getMessage('modals.main.settings.reminder.title')}
|
||||
subtitle={getMessage('modals.main.settings.sections.stats.warning')}
|
||||
>
|
||||
<Switch
|
||||
name="stats"
|
||||
text={getMessage('modals.main.settings.sections.stats.usage')}
|
||||
category="stats"
|
||||
/>
|
||||
</SettingsItem>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<h2>{getMessage('modals.main.settings.sections.stats.title')}</h2>
|
||||
<Switch name='stats' text={getMessage('modals.main.settings.sections.stats.usage')} category='stats'/>
|
||||
<p>{getMessage('modals.main.settings.sections.stats.sections.tabs_opened')}: {this.state.stats['tabs-opened'] || 0}</p>
|
||||
<p>{getMessage('modals.main.settings.sections.stats.sections.backgrounds_favourited')}: {this.state.stats.feature ? this.state.stats.feature['background-favourite'] || 0 : 0}</p>
|
||||
<p>{getMessage('modals.main.settings.sections.stats.sections.backgrounds_downloaded')}: {this.state.stats.feature ? this.state.stats.feature['background-download'] || 0 : 0}</p>
|
||||
<p>{getMessage('modals.main.settings.sections.stats.sections.quotes_favourited')}: {this.state.stats.feature ? this.state.stats.feature['quoted-favourite'] || 0 : 0}</p>
|
||||
<p>{getMessage('modals.main.settings.sections.stats.sections.quicklinks_added')}: {this.state.stats.feature ? this.state.stats.feature['quicklink-add'] || 0 : 0}</p>
|
||||
<p>{getMessage('modals.main.settings.sections.stats.sections.settings_changed')}: {this.state.stats.setting ? Object.keys(this.state.stats.setting).length : 0}</p>
|
||||
<p>{getMessage('modals.main.settings.sections.stats.sections.addons_installed')}: {this.state.stats.marketplace ? this.state.stats.marketplace['install'] : 0}</p>
|
||||
{/*<h2>{getMessage('modals.main.settings.sections.stats.title')}</h2>
|
||||
<Switch name='stats' text={getMessage('modals.main.settings.sections.stats.usage')} category='stats'/>*/}
|
||||
<span className="mainTitle">{getMessage('modals.main.settings.sections.stats.title')}</span>
|
||||
<SettingsItem
|
||||
title={getMessage('modals.main.settings.reminder.title')}
|
||||
subtitle={getMessage('modals.main.settings.sections.stats.warning')}
|
||||
>
|
||||
<Switch
|
||||
name="stats"
|
||||
text={getMessage('modals.main.settings.sections.stats.usage')}
|
||||
category="stats"
|
||||
/>
|
||||
</SettingsItem>
|
||||
<div className="statsGrid">
|
||||
<div>
|
||||
<span>
|
||||
{getMessage('modals.main.settings.sections.stats.sections.tabs_opened')}:{' '}
|
||||
{this.state.stats['tabs-opened'] || 0}
|
||||
</span>
|
||||
</div>
|
||||
<div>
|
||||
<span>
|
||||
{getMessage('modals.main.settings.sections.stats.sections.tabs_opened')}:{' '}
|
||||
{this.state.stats['tabs-opened'] || 0}
|
||||
</span>
|
||||
</div>
|
||||
<div>
|
||||
<MdShowChart />
|
||||
<span className="subtitle">
|
||||
{getMessage('modals.main.settings.sections.stats.sections.tabs_opened')}{' '}
|
||||
</span>
|
||||
<span>{this.state.stats['tabs-opened'] || 0}</span>
|
||||
<span className="subtitle">
|
||||
{getMessage('modals.main.settings.sections.stats.sections.backgrounds_favourited')}{' '}
|
||||
</span>
|
||||
<span>
|
||||
{this.state.stats.feature ? this.state.stats.feature['background-favourite'] || 0 : 0}
|
||||
</span>
|
||||
<span className="subtitle">
|
||||
{getMessage('modals.main.settings.sections.stats.sections.backgrounds_downloaded')}{' '}
|
||||
</span>
|
||||
<span>
|
||||
{this.state.stats.feature ? this.state.stats.feature['background-download'] || 0 : 0}
|
||||
</span>
|
||||
<span className="subtitle">
|
||||
{getMessage('modals.main.settings.sections.stats.sections.quotes_favourited')}{' '}
|
||||
</span>
|
||||
<span>
|
||||
{this.state.stats.feature ? this.state.stats.feature['quoted-favourite'] || 0 : 0}
|
||||
</span>
|
||||
<span className="subtitle">
|
||||
{getMessage('modals.main.settings.sections.stats.sections.quicklinks_added')}{' '}
|
||||
</span>
|
||||
<span>
|
||||
{this.state.stats.feature ? this.state.stats.feature['quicklink-add'] || 0 : 0}
|
||||
</span>
|
||||
<span className="subtitle">
|
||||
{getMessage('modals.main.settings.sections.stats.sections.settings_changed')}{' '}
|
||||
</span>
|
||||
<span>
|
||||
{this.state.stats.setting ? Object.keys(this.state.stats.setting).length : 0}
|
||||
</span>
|
||||
<span className="subtitle">
|
||||
{getMessage('modals.main.settings.sections.stats.sections.addons_installed')}{' '}
|
||||
</span>
|
||||
<span>
|
||||
{this.state.stats.marketplace ? this.state.stats.marketplace['install'] : 0}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -6,11 +6,13 @@ import Checkbox from '../Checkbox';
|
|||
import Dropdown from '../Dropdown';
|
||||
import Radio from '../Radio';
|
||||
|
||||
import SettingsItem from '../SettingsItem';
|
||||
|
||||
export default class TimeSettings extends PureComponent {
|
||||
constructor() {
|
||||
super();
|
||||
this.state = {
|
||||
timeType: localStorage.getItem('timeType') || 'digital'
|
||||
timeType: localStorage.getItem('timeType') || 'digital',
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -22,32 +24,64 @@ export default class TimeSettings extends PureComponent {
|
|||
const digitalOptions = [
|
||||
{
|
||||
name: getMessage('modals.main.settings.sections.time.digital.twentyfourhour'),
|
||||
value: 'twentyfourhour'
|
||||
value: 'twentyfourhour',
|
||||
},
|
||||
{
|
||||
name: getMessage('modals.main.settings.sections.time.digital.twelvehour'),
|
||||
value: 'twelvehour'
|
||||
}
|
||||
value: 'twelvehour',
|
||||
},
|
||||
];
|
||||
|
||||
const digitalSettings = (
|
||||
<>
|
||||
<h3>{getMessage('modals.main.settings.sections.time.digital.title')}</h3>
|
||||
<Radio title={getMessage('modals.main.settings.sections.time.format')} name='timeformat' options={digitalOptions} smallTitle={true} category='clock' />
|
||||
<Checkbox name='seconds' text={getMessage('modals.main.settings.sections.time.digital.seconds')} category='clock' />
|
||||
<Checkbox name='zero' text={getMessage('modals.main.settings.sections.time.digital.zero')} category='clock' />
|
||||
</>
|
||||
<SettingsItem
|
||||
title={getMessage('modals.main.settings.sections.time.digital.title')}
|
||||
subtitle={getMessage('modals.main.settings.sections.time.format')}
|
||||
>
|
||||
<Radio name="timeformat" options={digitalOptions} smallTitle={true} category="clock" />
|
||||
<Checkbox
|
||||
name="seconds"
|
||||
text={getMessage('modals.main.settings.sections.time.digital.seconds')}
|
||||
category="clock"
|
||||
/>
|
||||
<Checkbox
|
||||
name="zero"
|
||||
text={getMessage('modals.main.settings.sections.time.digital.zero')}
|
||||
category="clock"
|
||||
/>
|
||||
</SettingsItem>
|
||||
);
|
||||
|
||||
const analogSettings = (
|
||||
<>
|
||||
<h3>{getMessage('modals.main.settings.sections.time.analogue.title')}</h3>
|
||||
<Checkbox name='secondHand' text={getMessage('modals.main.settings.sections.time.analogue.second_hand')} category='clock' />
|
||||
<Checkbox name='minuteHand' text={getMessage('modals.main.settings.sections.time.analogue.minute_hand')} category='clock' />
|
||||
<Checkbox name='hourHand' text={getMessage('modals.main.settings.sections.time.analogue.hour_hand')} category='clock' />
|
||||
<Checkbox name='hourMarks' text={getMessage('modals.main.settings.sections.time.analogue.hour_marks')} category='clock' />
|
||||
<Checkbox name='minuteMarks' text={getMessage('modals.main.settings.sections.time.analogue.minute_marks')} category='clock' />
|
||||
</>
|
||||
<SettingsItem
|
||||
title={getMessage('modals.main.settings.sections.time.analogue.title')}
|
||||
subtitle="subtitle"
|
||||
>
|
||||
<Checkbox
|
||||
name="secondHand"
|
||||
text={getMessage('modals.main.settings.sections.time.analogue.second_hand')}
|
||||
category="clock"
|
||||
/>
|
||||
<Checkbox
|
||||
name="minuteHand"
|
||||
text={getMessage('modals.main.settings.sections.time.analogue.minute_hand')}
|
||||
category="clock"
|
||||
/>
|
||||
<Checkbox
|
||||
name="hourHand"
|
||||
text={getMessage('modals.main.settings.sections.time.analogue.hour_hand')}
|
||||
category="clock"
|
||||
/>
|
||||
<Checkbox
|
||||
name="hourMarks"
|
||||
text={getMessage('modals.main.settings.sections.time.analogue.hour_marks')}
|
||||
category="clock"
|
||||
/>
|
||||
<Checkbox
|
||||
name="minuteMarks"
|
||||
text={getMessage('modals.main.settings.sections.time.analogue.minute_marks')}
|
||||
category="clock"
|
||||
/>
|
||||
</SettingsItem>
|
||||
);
|
||||
|
||||
if (this.state.timeType === 'digital') {
|
||||
|
@ -58,12 +92,35 @@ export default class TimeSettings extends PureComponent {
|
|||
|
||||
return (
|
||||
<>
|
||||
<Header title={getMessage('modals.main.settings.sections.time.title')} setting='time' category='clock' element='.clock-container' zoomSetting='zoomClock'/>
|
||||
<Dropdown label={getMessage('modals.main.settings.sections.time.type')} name='timeType' onChange={(value) => this.setState({ timeType: value })} category='clock'>
|
||||
<option value='digital'>{getMessage('modals.main.settings.sections.time.digital.title')}</option>
|
||||
<option value='analogue'>{getMessage('modals.main.settings.sections.time.analogue.title')}</option>
|
||||
<option value='percentageComplete'>{getMessage('modals.main.settings.sections.time.percentage_complete')}</option>
|
||||
</Dropdown>
|
||||
<Header
|
||||
title={getMessage('modals.main.settings.sections.time.title')}
|
||||
setting="time"
|
||||
category="clock"
|
||||
element=".clock-container"
|
||||
zoomSetting="zoomClock"
|
||||
switch={true}
|
||||
/>
|
||||
<SettingsItem
|
||||
title={getMessage('modals.main.settings.sections.time.type')}
|
||||
subtitle="subtitle"
|
||||
>
|
||||
<Dropdown
|
||||
label={getMessage('modals.main.settings.sections.time.type')}
|
||||
name="timeType"
|
||||
onChange={(value) => this.setState({ timeType: value })}
|
||||
category="clock"
|
||||
>
|
||||
<option value="digital">
|
||||
{getMessage('modals.main.settings.sections.time.digital.title')}
|
||||
</option>
|
||||
<option value="analogue">
|
||||
{getMessage('modals.main.settings.sections.time.analogue.title')}
|
||||
</option>
|
||||
<option value="percentageComplete">
|
||||
{getMessage('modals.main.settings.sections.time.percentage_complete')}
|
||||
</option>
|
||||
</Dropdown>
|
||||
</SettingsItem>
|
||||
{timeSettings}
|
||||
</>
|
||||
);
|
||||
|
|
|
@ -3,8 +3,11 @@ import { PureComponent } from 'react';
|
|||
|
||||
import Header from '../Header';
|
||||
import Radio from '../Radio';
|
||||
import Dropdown from '../Dropdown';
|
||||
import Checkbox from '../Checkbox';
|
||||
import { TextField } from '@mui/material';
|
||||
import SettingsItem from '../SettingsItem';
|
||||
|
||||
|
||||
export default class TimeSettings extends PureComponent {
|
||||
constructor() {
|
||||
|
@ -20,13 +23,13 @@ export default class TimeSettings extends PureComponent {
|
|||
}
|
||||
|
||||
showReminder() {
|
||||
document.querySelector('.reminder-info').style.display = 'block';
|
||||
document.querySelector('.reminder-info').style.display = 'flex';
|
||||
localStorage.setItem('showReminder', true);
|
||||
}
|
||||
|
||||
changeLocation(e) {
|
||||
this.setState({
|
||||
location: e.target.value
|
||||
this.setState({
|
||||
location: e.target.value
|
||||
});
|
||||
|
||||
this.showReminder();
|
||||
|
@ -43,8 +46,8 @@ export default class TimeSettings extends PureComponent {
|
|||
}, (error) => {
|
||||
// firefox requires this 2nd function
|
||||
console.log(error);
|
||||
}, {
|
||||
enableHighAccuracy: true
|
||||
}, {
|
||||
enableHighAccuracy: true
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -65,24 +68,50 @@ export default class TimeSettings extends PureComponent {
|
|||
value: 'kelvin'
|
||||
}
|
||||
];
|
||||
|
||||
|
||||
return (
|
||||
<>
|
||||
<Header title={getMessage('modals.main.settings.sections.weather.title')} setting='weatherEnabled' category='widgets' zoomSetting='zoomWeather' zoomCategory='weather'/>
|
||||
<TextField label={getMessage('modals.main.settings.sections.weather.location')} value={this.state.location} onChange={(e) => this.changeLocation(e)} placeholder='London' varient='outlined' InputLabelProps={{ shrink: true }} />
|
||||
<span className='modalLink' onClick={() => this.getAuto()}>{getMessage('modals.main.settings.sections.weather.auto')}</span>
|
||||
<Radio name='tempformat' title={getMessage('modals.main.settings.sections.weather.temp_format.title')} options={tempFormat} category='weather'/>
|
||||
|
||||
<h3>{getMessage('modals.main.settings.sections.weather.extra_info.title')}</h3>
|
||||
<Header title={getMessage('modals.main.settings.sections.weather.title')} setting='weatherEnabled' category='widgets' zoomSetting='zoomWeather' zoomCategory='weather' switch={true}/>
|
||||
<SettingsItem title="Widget Type">
|
||||
<Dropdown label="Type" name="weatherType">
|
||||
<option value='1'>Basic</option>
|
||||
<option value='2'>Standard</option>
|
||||
<option value='3'>Expanded</option>
|
||||
</Dropdown>
|
||||
</SettingsItem>
|
||||
<SettingsItem title={getMessage('modals.main.settings.sections.weather.location')}>
|
||||
<TextField label={getMessage('modals.main.settings.sections.weather.location')} value={this.state.location} onChange={(e) => this.changeLocation(e)} placeholder='London' varient='outlined' InputLabelProps={{ shrink: true }} />
|
||||
<span className='link' onClick={() => this.getAuto()}>{getMessage('modals.main.settings.sections.weather.auto')}</span>
|
||||
</SettingsItem>
|
||||
<SettingsItem title={getMessage('modals.main.settings.sections.weather.temp_format.title')}>
|
||||
<Radio name='tempformat' options={tempFormat} category='weather'/>
|
||||
</SettingsItem>
|
||||
{ localStorage.getItem('weatherType') > 1 &&
|
||||
<SettingsItem title="Active bit" subtitle="idk a better word for it sorry">
|
||||
<Dropdown label="Type" name="weatherActiveBit" category='weather'>
|
||||
<option value='weatherdescription'>{getMessage('modals.main.settings.sections.weather.extra_info.show_description')} </option>
|
||||
<option value='cloudiness'>{getMessage('modals.main.settings.sections.weather.extra_info.cloudiness')}</option>
|
||||
<option value='humidity'>{getMessage('modals.main.settings.sections.weather.extra_info.humidity')}</option>
|
||||
<option value='visibility'>{getMessage('modals.main.settings.sections.weather.extra_info.visibility')}</option>
|
||||
<option value='windspeed' onChange={() => this.setState({ windSpeed: (localStorage.getItem('windspeed') !== 'true') })}>{getMessage('modals.main.settings.sections.weather.extra_info.wind_speed')}</option>
|
||||
<option value='windDirection' disabled={this.state.windSpeed}>{getMessage('modals.main.settings.sections.weather.extra_info.wind_direction')}</option>
|
||||
<option value='mintemp'>{getMessage('modals.main.settings.sections.weather.extra_info.min_temp')}</option>
|
||||
<option value='maxtemp'>{getMessage('modals.main.settings.sections.weather.extra_info.max_temp')}</option>
|
||||
<option value='feelsliketemp'>Feels like temperature</option>
|
||||
<option value='atmosphericpressure'>{getMessage('modals.main.settings.sections.weather.extra_info.atmospheric_pressure')}</option>
|
||||
</Dropdown>
|
||||
</SettingsItem>
|
||||
}
|
||||
<Checkbox name='showlocation' text={getMessage('modals.main.settings.sections.weather.extra_info.show_location')} category='weather'/>
|
||||
<Checkbox name='weatherdescription' text={getMessage('modals.main.settings.sections.weather.extra_info.show_description')} category='weather'/>
|
||||
<Checkbox name='cloudiness' text={getMessage('modals.main.settings.sections.weather.extra_info.cloudiness')} category='weather'/>
|
||||
<Checkbox name='humidity' text={getMessage('modals.main.settings.sections.weather.extra_info.humidity')} category='weather'/>
|
||||
<Checkbox name='visibility' text={getMessage('modals.main.settings.sections.weather.extra_info.visibility')} category='weather'/>
|
||||
<Checkbox name='windspeed' text={getMessage('modals.main.settings.sections.weather.extra_info.wind_speed')} category='weather' onChange={() => this.setState({ windSpeed: (localStorage.getItem('windspeed') !== 'true') })}/>
|
||||
<Checkbox name='windDirection' text={getMessage('modals.main.settings.sections.weather.extra_info.wind_direction')} category='weather' disabled={this.state.windSpeed}/>
|
||||
<Checkbox name='windDirection' text={getMessage('modals.main.settings.sections.weather.extra_info.wind_direction')} category='weather' disabled={this.state.windSpeed}/>
|
||||
<Checkbox name='mintemp' text={getMessage('modals.main.settings.sections.weather.extra_info.min_temp')} category='weather'/>
|
||||
<Checkbox name='maxtemp' text={getMessage('modals.main.settings.sections.weather.extra_info.max_temp')} category='weather'/>
|
||||
<Checkbox name='feelsliketemp' text={'Feels like temperature'} category='weather'/>
|
||||
<Checkbox name='atmosphericpressure' text={getMessage('modals.main.settings.sections.weather.extra_info.atmospheric_pressure')} category='weather'/>
|
||||
</>
|
||||
);
|
||||
|
|
|
@ -1,49 +1,58 @@
|
|||
import variables from 'modules/variables';
|
||||
import { PureComponent } from 'react';
|
||||
import { MenuItem } from '@mui/material';
|
||||
import variables from "modules/variables";
|
||||
import { PureComponent } from "react";
|
||||
import { MenuItem } from "@mui/material";
|
||||
|
||||
import Header from '../../Header';
|
||||
import Checkbox from '../../Checkbox';
|
||||
import Dropdown from '../../Dropdown';
|
||||
import Slider from '../../Slider';
|
||||
import Radio from '../../Radio';
|
||||
import Header from "../../Header";
|
||||
import Checkbox from "../../Checkbox";
|
||||
import Dropdown from "../../Dropdown";
|
||||
import Slider from "../../Slider";
|
||||
import Radio from "../../Radio";
|
||||
import SettingsItem from "../../SettingsItem";
|
||||
|
||||
import ColourSettings from './Colour';
|
||||
import CustomSettings from './Custom';
|
||||
import ColourSettings from "./Colour";
|
||||
import CustomSettings from "./Custom";
|
||||
|
||||
import { values } from 'modules/helpers/settings/modals';
|
||||
import { values } from "modules/helpers/settings/modals";
|
||||
|
||||
export default class BackgroundSettings extends PureComponent {
|
||||
getMessage = (text) => variables.language.getMessage(variables.languagecode, text);
|
||||
getMessage = (text) =>
|
||||
variables.language.getMessage(variables.languagecode, text);
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.state = {
|
||||
backgroundType: localStorage.getItem('backgroundType') || 'api',
|
||||
backgroundFilter: localStorage.getItem('backgroundFilter') || 'none',
|
||||
backgroundCategories: [this.getMessage('modals.main.loading')],
|
||||
backgroundAPI: localStorage.getItem('backgroundAPI') || 'mue',
|
||||
marketplaceEnabled: localStorage.getItem('photo_packs')
|
||||
backgroundType: localStorage.getItem("backgroundType") || "api",
|
||||
backgroundFilter: localStorage.getItem("backgroundFilter") || "none",
|
||||
backgroundCategories: [this.getMessage("modals.main.loading")],
|
||||
backgroundAPI: localStorage.getItem("backgroundAPI") || "mue",
|
||||
marketplaceEnabled: localStorage.getItem("photo_packs"),
|
||||
};
|
||||
this.controller = new AbortController();
|
||||
}
|
||||
|
||||
async getBackgroundCategories() {
|
||||
const data = await (await fetch(variables.constants.API_URL + '/images/categories', { signal: this.controller.signal })).json();
|
||||
const data = await (
|
||||
await fetch(variables.constants.API_URL + "/images/categories", {
|
||||
signal: this.controller.signal,
|
||||
})
|
||||
).json();
|
||||
|
||||
if (this.controller.signal.aborted === true) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.setState({
|
||||
backgroundCategories: data
|
||||
backgroundCategories: data,
|
||||
});
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
if (navigator.onLine === false || localStorage.getItem('offlineMode') === 'true') {
|
||||
if (
|
||||
navigator.onLine === false ||
|
||||
localStorage.getItem("offlineMode") === "true"
|
||||
) {
|
||||
return this.setState({
|
||||
backgroundCategories: [this.getMessage('modals.update.offline.title')]
|
||||
backgroundCategories: [this.getMessage("modals.update.offline.title")],
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -62,117 +71,374 @@ export default class BackgroundSettings extends PureComponent {
|
|||
|
||||
const apiOptions = [
|
||||
{
|
||||
name: 'Mue',
|
||||
value: 'mue'
|
||||
name: "Mue",
|
||||
value: "mue",
|
||||
},
|
||||
{
|
||||
name: 'Unsplash',
|
||||
value: 'unsplash'
|
||||
name: "Unsplash",
|
||||
value: "unsplash",
|
||||
},
|
||||
{
|
||||
name: 'Pexels',
|
||||
value: 'pexels'
|
||||
}
|
||||
name: "Pexels",
|
||||
value: "pexels",
|
||||
},
|
||||
];
|
||||
|
||||
const interval = (
|
||||
<Dropdown label={getMessage('modals.main.settings.sections.background.interval.title')} name='backgroundchange'>
|
||||
<option value='refresh'>{getMessage('tabname')}</option>
|
||||
<option value='60000'>{getMessage('modals.main.settings.sections.background.interval.minute')}</option>
|
||||
<option value='1800000'>{getMessage('modals.main.settings.sections.background.interval.half_hour')}</option>
|
||||
<option value='3600000'>{getMessage('modals.main.settings.sections.background.interval.hour')}</option>
|
||||
<option value='86400000'>{getMessage('modals.main.settings.sections.background.interval.day')}</option>
|
||||
<option value='604800000'>{getMessage('widgets.date.week')}</option>
|
||||
<option value='2628000000'>{getMessage('modals.main.settings.sections.background.interval.month')}</option>
|
||||
</Dropdown>
|
||||
<SettingsItem>
|
||||
<Dropdown
|
||||
label={getMessage(
|
||||
"modals.main.settings.sections.background.interval.title"
|
||||
)}
|
||||
name="backgroundchange"
|
||||
>
|
||||
<option value="refresh">{getMessage("tabname")}</option>
|
||||
<option value="60000">
|
||||
{getMessage(
|
||||
"modals.main.settings.sections.background.interval.minute"
|
||||
)}
|
||||
</option>
|
||||
<option value="1800000">
|
||||
{getMessage(
|
||||
"modals.main.settings.sections.background.interval.half_hour"
|
||||
)}
|
||||
</option>
|
||||
<option value="3600000">
|
||||
{getMessage(
|
||||
"modals.main.settings.sections.background.interval.hour"
|
||||
)}
|
||||
</option>
|
||||
<option value="86400000">
|
||||
{getMessage(
|
||||
"modals.main.settings.sections.background.interval.day"
|
||||
)}
|
||||
</option>
|
||||
<option value="604800000">{getMessage("widgets.date.week")}</option>
|
||||
<option value="2628000000">
|
||||
{getMessage(
|
||||
"modals.main.settings.sections.background.interval.month"
|
||||
)}
|
||||
</option>
|
||||
</Dropdown>
|
||||
</SettingsItem>
|
||||
);
|
||||
|
||||
const APISettings = (
|
||||
<>
|
||||
<Radio title={getMessage('modals.main.settings.sections.background.source.api')} options={apiOptions} name='backgroundAPI' category='background' element='#backgroundImage' onChange={(e) => this.setState({ backgroundAPI: e })}/>
|
||||
{this.state.backgroundCategories[0] === getMessage('modals.main.loading') ?
|
||||
<>
|
||||
<Dropdown label={getMessage('modals.main.settings.sections.background.category')} name='apiCategory'>
|
||||
<MenuItem value='loading' key='loading'>{getMessage('modals.main.loading')}</MenuItem>
|
||||
<MenuItem value='loading' key='loading'>{getMessage('modals.main.loading')}</MenuItem>
|
||||
<SettingsItem>
|
||||
<Radio
|
||||
title={getMessage(
|
||||
"modals.main.settings.sections.background.source.api"
|
||||
)}
|
||||
options={apiOptions}
|
||||
name="backgroundAPI"
|
||||
category="background"
|
||||
element="#backgroundImage"
|
||||
onChange={(e) => this.setState({ backgroundAPI: e })}
|
||||
/>
|
||||
{this.state.backgroundCategories[0] ===
|
||||
getMessage("modals.main.loading") ? (
|
||||
<>
|
||||
<Dropdown
|
||||
label={getMessage(
|
||||
"modals.main.settings.sections.background.category"
|
||||
)}
|
||||
name="apiCategory"
|
||||
>
|
||||
<MenuItem value="loading" key="loading">
|
||||
{getMessage("modals.main.loading")}
|
||||
</MenuItem>
|
||||
<MenuItem value="loading" key="loading">
|
||||
{getMessage("modals.main.loading")}
|
||||
</MenuItem>
|
||||
</Dropdown>
|
||||
</>
|
||||
) : (
|
||||
<Dropdown
|
||||
label={getMessage(
|
||||
"modals.main.settings.sections.background.category"
|
||||
)}
|
||||
name="apiCategory"
|
||||
>
|
||||
{this.state.backgroundCategories.map((category) => (
|
||||
<MenuItem value={category} key={category}>
|
||||
{category.charAt(0).toUpperCase() + category.slice(1)}
|
||||
</MenuItem>
|
||||
))}
|
||||
</Dropdown>
|
||||
</> :
|
||||
<Dropdown label={getMessage('modals.main.settings.sections.background.category')} name='apiCategory' >
|
||||
{this.state.backgroundCategories.map((category) => (
|
||||
<MenuItem value={category} key={category}>{category.charAt(0).toUpperCase() + category.slice(1)}</MenuItem>
|
||||
))}
|
||||
)}
|
||||
<Dropdown
|
||||
label={getMessage(
|
||||
"modals.main.settings.sections.background.source.quality.title"
|
||||
)}
|
||||
name="apiQuality"
|
||||
element=".other"
|
||||
>
|
||||
<option value="original">
|
||||
{getMessage(
|
||||
"modals.main.settings.sections.background.source.quality.original"
|
||||
)}
|
||||
</option>
|
||||
<option value="high">
|
||||
{getMessage(
|
||||
"modals.main.settings.sections.background.source.quality.high"
|
||||
)}
|
||||
</option>
|
||||
<option value="normal">
|
||||
{getMessage(
|
||||
"modals.main.settings.sections.background.source.quality.normal"
|
||||
)}
|
||||
</option>
|
||||
<option value="datasaver">
|
||||
{getMessage(
|
||||
"modals.main.settings.sections.background.source.quality.datasaver"
|
||||
)}
|
||||
</option>
|
||||
</Dropdown>
|
||||
}
|
||||
<Dropdown label={getMessage('modals.main.settings.sections.background.source.quality.title')} name='apiQuality' element='.other'>
|
||||
<option value='original'>{getMessage('modals.main.settings.sections.background.source.quality.original')}</option>
|
||||
<option value='high'>{getMessage('modals.main.settings.sections.background.source.quality.high')}</option>
|
||||
<option value='normal'>{getMessage('modals.main.settings.sections.background.source.quality.normal')}</option>
|
||||
<option value='datasaver'>{getMessage('modals.main.settings.sections.background.source.quality.datasaver')}</option>
|
||||
</Dropdown>
|
||||
</SettingsItem>
|
||||
{interval}
|
||||
</>
|
||||
);
|
||||
|
||||
switch (this.state.backgroundType) {
|
||||
case 'custom': backgroundSettings = <CustomSettings interval={interval}/>; break;
|
||||
case 'colour': backgroundSettings = <ColourSettings/>; break;
|
||||
case 'random_colour': backgroundSettings = <></>; break;
|
||||
case 'random_gradient': backgroundSettings = <></>; break;
|
||||
default: backgroundSettings = APISettings; break;
|
||||
case "custom":
|
||||
backgroundSettings = <CustomSettings interval={interval} />;
|
||||
break;
|
||||
case "colour":
|
||||
backgroundSettings = <ColourSettings />;
|
||||
break;
|
||||
case "random_colour":
|
||||
backgroundSettings = <></>;
|
||||
break;
|
||||
case "random_gradient":
|
||||
backgroundSettings = <></>;
|
||||
break;
|
||||
default:
|
||||
backgroundSettings = APISettings;
|
||||
break;
|
||||
}
|
||||
|
||||
if (localStorage.getItem('photo_packs') && this.state.backgroundType !== 'custom' && this.state.backgroundType !== 'colour' && this.state.backgroundType !== 'api') {
|
||||
if (
|
||||
localStorage.getItem("photo_packs") &&
|
||||
this.state.backgroundType !== "custom" &&
|
||||
this.state.backgroundType !== "colour" &&
|
||||
this.state.backgroundType !== "api"
|
||||
) {
|
||||
backgroundSettings = null;
|
||||
}
|
||||
|
||||
const usingImage = this.state.backgroundType !== 'colour' && this.state.backgroundType !== 'random_colour' && this.state.backgroundType !== 'random_gradient';
|
||||
|
||||
const usingImage =
|
||||
this.state.backgroundType !== "colour" &&
|
||||
this.state.backgroundType !== "random_colour" &&
|
||||
this.state.backgroundType !== "random_gradient";
|
||||
|
||||
return (
|
||||
<>
|
||||
<Header title={getMessage('modals.main.settings.sections.background.title')} setting='background' category='background' element='#backgroundImage'/>
|
||||
<Checkbox name='ddgProxy' text={getMessage('modals.main.settings.sections.background.ddg_image_proxy')} element='.other' disabled={!usingImage} />
|
||||
<Checkbox name='bgtransition' text={getMessage('modals.main.settings.sections.background.transition')} element='.other' disabled={!usingImage} />
|
||||
<Checkbox name='photoInformation' text={getMessage('modals.main.settings.sections.background.photo_information')} element='.other' disabled={this.state.backgroundType !== 'api' && this.state.backgroundType !== 'marketplace'} />
|
||||
<Checkbox name='photoMap' text={getMessage('modals.main.settings.sections.background.show_map')} element='.other' disabled={this.state.backgroundAPI !== 'unsplash'}/>
|
||||
|
||||
<h3>{getMessage('modals.main.settings.sections.background.source.title')}</h3>
|
||||
<Dropdown label={getMessage('modals.main.settings.sections.background.type.title')} name='backgroundType' onChange={(value) => this.setState({ backgroundType: value })} category='background'>
|
||||
{this.state.marketplaceEnabled ? <option value='photo_pack'>{this.getMessage('modals.main.navbar.marketplace')}</option> : null}
|
||||
<option value='api'>{getMessage('modals.main.settings.sections.background.type.api')}</option>
|
||||
<option value='custom'>{getMessage('modals.main.settings.sections.background.type.custom_image')}</option>
|
||||
<option value='colour'>{getMessage('modals.main.settings.sections.background.type.custom_colour')}</option>
|
||||
<option value='random_colour'>{getMessage('modals.main.settings.sections.background.type.random_colour')}</option>
|
||||
<option value='random_gradient'>{getMessage('modals.main.settings.sections.background.type.random_gradient')}</option>
|
||||
</Dropdown>
|
||||
|
||||
<Header
|
||||
title={getMessage("modals.main.settings.sections.background.title")}
|
||||
setting="background"
|
||||
category="background"
|
||||
element="#backgroundImage"
|
||||
/>
|
||||
<SettingsItem title="cheese" subtitle="cheese">
|
||||
<Checkbox
|
||||
name="ddgProxy"
|
||||
text={getMessage(
|
||||
"modals.main.settings.sections.background.ddg_image_proxy"
|
||||
)}
|
||||
element=".other"
|
||||
disabled={!usingImage}
|
||||
/>
|
||||
<Checkbox
|
||||
name="bgtransition"
|
||||
text={getMessage(
|
||||
"modals.main.settings.sections.background.transition"
|
||||
)}
|
||||
element=".other"
|
||||
disabled={!usingImage}
|
||||
/>
|
||||
<Checkbox
|
||||
name="photoInformation"
|
||||
text={getMessage(
|
||||
"modals.main.settings.sections.background.photo_information"
|
||||
)}
|
||||
element=".other"
|
||||
disabled={
|
||||
this.state.backgroundType !== "api" &&
|
||||
this.state.backgroundType !== "marketplace"
|
||||
}
|
||||
/>
|
||||
<Checkbox
|
||||
name="photoMap"
|
||||
text={getMessage(
|
||||
"modals.main.settings.sections.background.show_map"
|
||||
)}
|
||||
element=".other"
|
||||
disabled={this.state.backgroundAPI !== "unsplash"}
|
||||
/>
|
||||
</SettingsItem>
|
||||
<SettingsItem
|
||||
title={getMessage(
|
||||
"modals.main.settings.sections.background.buttons.title"
|
||||
)}
|
||||
subtitle="cheese"
|
||||
>
|
||||
<Checkbox
|
||||
name="favouriteEnabled"
|
||||
text={getMessage(
|
||||
"modals.main.settings.sections.background.buttons.favourite"
|
||||
)}
|
||||
category="navbar"
|
||||
/>
|
||||
{this.state.backgroundType === "api" &&
|
||||
APISettings &&
|
||||
this.state.backgroundAPI === "mue" ? (
|
||||
<Checkbox
|
||||
name="downloadbtn"
|
||||
text={getMessage(
|
||||
"modals.main.settings.sections.background.buttons.download"
|
||||
)}
|
||||
element=".other"
|
||||
/>
|
||||
) : null}
|
||||
</SettingsItem>
|
||||
<SettingsItem
|
||||
title={getMessage(
|
||||
"modals.main.settings.sections.background.source.title"
|
||||
)}
|
||||
subtitle="mucho gracias"
|
||||
>
|
||||
<Dropdown
|
||||
label={getMessage(
|
||||
"modals.main.settings.sections.background.type.title"
|
||||
)}
|
||||
name="backgroundType"
|
||||
onChange={(value) => this.setState({ backgroundType: value })}
|
||||
category="background"
|
||||
>
|
||||
{this.state.marketplaceEnabled ? (
|
||||
<option value="photo_pack">
|
||||
{this.getMessage("modals.main.navbar.marketplace")}
|
||||
</option>
|
||||
) : null}
|
||||
<option value="api">
|
||||
{getMessage("modals.main.settings.sections.background.type.api")}
|
||||
</option>
|
||||
<option value="custom">
|
||||
{getMessage(
|
||||
"modals.main.settings.sections.background.type.custom_image"
|
||||
)}
|
||||
</option>
|
||||
<option value="colour">
|
||||
{getMessage(
|
||||
"modals.main.settings.sections.background.type.custom_colour"
|
||||
)}
|
||||
</option>
|
||||
<option value="random_colour">
|
||||
{getMessage(
|
||||
"modals.main.settings.sections.background.type.random_colour"
|
||||
)}
|
||||
</option>
|
||||
<option value="random_gradient">
|
||||
{getMessage(
|
||||
"modals.main.settings.sections.background.type.random_gradient"
|
||||
)}
|
||||
</option>
|
||||
</Dropdown>
|
||||
</SettingsItem>
|
||||
{backgroundSettings}
|
||||
|
||||
{this.state.backgroundType === 'api' && APISettings && this.state.backgroundAPI === 'mue' ?
|
||||
<>
|
||||
<h3>{getMessage('modals.main.settings.sections.background.buttons.title')}</h3>
|
||||
<Checkbox name='downloadbtn' text={getMessage('modals.main.settings.sections.background.buttons.download')} element='.other' />
|
||||
</>
|
||||
: null}
|
||||
|
||||
{this.state.backgroundType === 'api' || this.state.backgroundType === 'custom' || this.state.marketplaceEnabled ?
|
||||
<>
|
||||
<h3>{getMessage('modals.main.settings.sections.background.effects.title')}</h3>
|
||||
<Slider title={getMessage('modals.main.settings.sections.background.effects.blur')} name='blur' min='0' max='100' default='0' display='%' marks={values('background')} category='background' element='#backgroundImage' />
|
||||
<Slider title={getMessage('modals.main.settings.sections.background.effects.brightness')} name='brightness' min='0' max='100' default='90' display='%' marks={values('background')} category='background' element='#backgroundImage' />
|
||||
<br/>
|
||||
<Dropdown label={getMessage('modals.main.settings.sections.background.effects.filters.title')} name='backgroundFilter' onChange={(value) => this.setState({ backgroundFilter: value })} category='background' element='#backgroundImage'>
|
||||
<option value='none'>{getMessage('modals.main.settings.sections.appearance.navbar.refresh_options.none')}</option>
|
||||
<option value='grayscale'>{getMessage('modals.main.settings.sections.background.effects.filters.grayscale')}</option>
|
||||
<option value='sepia'>{getMessage('modals.main.settings.sections.background.effects.filters.sepia')}</option>
|
||||
<option value='invert'>{getMessage('modals.main.settings.sections.background.effects.filters.invert')}</option>
|
||||
<option value='saturate'>{getMessage('modals.main.settings.sections.background.effects.filters.saturate')}</option>
|
||||
<option value='contrast'>{getMessage('modals.main.settings.sections.background.effects.filters.contrast')}</option>
|
||||
{this.state.backgroundType === "api" ||
|
||||
this.state.backgroundType === "custom" ||
|
||||
this.state.marketplaceEnabled ? (
|
||||
<SettingsItem
|
||||
title={getMessage(
|
||||
"modals.main.settings.sections.background.effects.title"
|
||||
)}
|
||||
subtitle="cheese"
|
||||
>
|
||||
<Slider
|
||||
title={getMessage(
|
||||
"modals.main.settings.sections.background.effects.blur"
|
||||
)}
|
||||
name="blur"
|
||||
min="0"
|
||||
max="100"
|
||||
default="0"
|
||||
display="%"
|
||||
marks={values("background")}
|
||||
category="background"
|
||||
element="#backgroundImage"
|
||||
/>
|
||||
<Slider
|
||||
title={getMessage(
|
||||
"modals.main.settings.sections.background.effects.brightness"
|
||||
)}
|
||||
name="brightness"
|
||||
min="0"
|
||||
max="100"
|
||||
default="90"
|
||||
display="%"
|
||||
marks={values("background")}
|
||||
category="background"
|
||||
element="#backgroundImage"
|
||||
/>
|
||||
<Dropdown
|
||||
label={getMessage(
|
||||
"modals.main.settings.sections.background.effects.filters.title"
|
||||
)}
|
||||
name="backgroundFilter"
|
||||
onChange={(value) => this.setState({ backgroundFilter: value })}
|
||||
category="background"
|
||||
element="#backgroundImage"
|
||||
>
|
||||
<option value="none">
|
||||
{getMessage(
|
||||
"modals.main.settings.sections.appearance.navbar.refresh_options.none"
|
||||
)}
|
||||
</option>
|
||||
<option value="grayscale">
|
||||
{getMessage(
|
||||
"modals.main.settings.sections.background.effects.filters.grayscale"
|
||||
)}
|
||||
</option>
|
||||
<option value="sepia">
|
||||
{getMessage(
|
||||
"modals.main.settings.sections.background.effects.filters.sepia"
|
||||
)}
|
||||
</option>
|
||||
<option value="invert">
|
||||
{getMessage(
|
||||
"modals.main.settings.sections.background.effects.filters.invert"
|
||||
)}
|
||||
</option>
|
||||
<option value="saturate">
|
||||
{getMessage(
|
||||
"modals.main.settings.sections.background.effects.filters.saturate"
|
||||
)}
|
||||
</option>
|
||||
<option value="contrast">
|
||||
{getMessage(
|
||||
"modals.main.settings.sections.background.effects.filters.contrast"
|
||||
)}
|
||||
</option>
|
||||
</Dropdown>
|
||||
{this.state.backgroundFilter !== 'none' ?
|
||||
<Slider title={getMessage('modals.main.settings.sections.background.effects.filters.amount')} name='backgroundFilterAmount' min='0' max='100' default='0' display='%' marks={values('background')} category='background' element='#backgroundImage' />
|
||||
: null}
|
||||
</>
|
||||
: null}
|
||||
{this.state.backgroundFilter !== "none" ? (
|
||||
<Slider
|
||||
title={getMessage(
|
||||
"modals.main.settings.sections.background.effects.filters.amount"
|
||||
)}
|
||||
name="backgroundFilterAmount"
|
||||
min="0"
|
||||
max="100"
|
||||
default="0"
|
||||
display="%"
|
||||
marks={values("background")}
|
||||
category="background"
|
||||
element="#backgroundImage"
|
||||
/>
|
||||
) : null}
|
||||
</SettingsItem>
|
||||
) : null}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,37 +1,43 @@
|
|||
import variables from 'modules/variables';
|
||||
import { PureComponent, Fragment } from 'react';
|
||||
import { ColorPicker } from 'react-color-gradient-picker';
|
||||
import { toast } from 'react-toastify';
|
||||
import variables from "modules/variables";
|
||||
import { PureComponent, Fragment } from "react";
|
||||
import { ColorPicker } from "react-color-gradient-picker";
|
||||
import { toast } from "react-toastify";
|
||||
import SettingsItem from "../../SettingsItem";
|
||||
|
||||
import hexToRgb from 'modules/helpers/background/hexToRgb';
|
||||
import rgbToHex from 'modules/helpers/background/rgbToHex';
|
||||
import hexToRgb from "modules/helpers/background/hexToRgb";
|
||||
import rgbToHex from "modules/helpers/background/rgbToHex";
|
||||
|
||||
import 'react-color-gradient-picker/dist/index.css';
|
||||
import '../../../scss/settings/react-color-picker-gradient-picker-custom-styles.scss';
|
||||
import "react-color-gradient-picker/dist/index.css";
|
||||
import "../../../scss/settings/react-color-picker-gradient-picker-custom-styles.scss";
|
||||
|
||||
export default class ColourSettings extends PureComponent {
|
||||
DefaultGradientSettings = { angle: '180', gradient: [{ colour: '#ffb032', stop: 0 }], type: 'linear' };
|
||||
GradientPickerInitalState = undefined;
|
||||
DefaultGradientSettings = {
|
||||
angle: "180",
|
||||
gradient: [{ colour: "#ffb032", stop: 0 }],
|
||||
type: "linear",
|
||||
};
|
||||
GradientPickerInitialState = undefined;
|
||||
|
||||
getMessage = (text) =>
|
||||
variables.language.getMessage(variables.languagecode, text);
|
||||
|
||||
getMessage = (text) => variables.language.getMessage(variables.languagecode, text);
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.state = {
|
||||
gradientSettings: this.DefaultGradientSettings
|
||||
gradientSettings: this.DefaultGradientSettings,
|
||||
};
|
||||
}
|
||||
|
||||
resetColour() {
|
||||
localStorage.setItem('customBackgroundColour', '');
|
||||
localStorage.setItem("customBackgroundColour", "");
|
||||
this.setState({
|
||||
gradientSettings: this.DefaultGradientSettings
|
||||
gradientSettings: this.DefaultGradientSettings,
|
||||
});
|
||||
toast(this.getMessage('toasts.reset'));
|
||||
toast(this.getMessage("toasts.reset"));
|
||||
}
|
||||
|
||||
initialiseColourPickerState(gradientSettings) {
|
||||
this.GradientPickerInitalState = {
|
||||
this.GradientPickerInitialState = {
|
||||
points: gradientSettings.gradient.map((g) => {
|
||||
const rgb = hexToRgb(g.colour);
|
||||
return {
|
||||
|
@ -39,19 +45,19 @@ export default class ColourSettings extends PureComponent {
|
|||
red: rgb.red,
|
||||
green: rgb.green,
|
||||
blue: rgb.blue,
|
||||
alpha: 1
|
||||
alpha: 1,
|
||||
};
|
||||
}),
|
||||
degree: + gradientSettings.angle,
|
||||
type: gradientSettings.type
|
||||
degree: +gradientSettings.angle,
|
||||
type: gradientSettings.type,
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
const hex = localStorage.getItem('customBackgroundColour');
|
||||
const hex = localStorage.getItem("customBackgroundColour");
|
||||
let gradientSettings = undefined;
|
||||
|
||||
if (hex !== '') {
|
||||
if (hex !== "") {
|
||||
try {
|
||||
gradientSettings = JSON.parse(hex);
|
||||
} catch (e) {
|
||||
|
@ -64,58 +70,91 @@ export default class ColourSettings extends PureComponent {
|
|||
}
|
||||
|
||||
this.setState({
|
||||
gradientSettings
|
||||
gradientSettings,
|
||||
});
|
||||
}
|
||||
|
||||
componentDidUpdate() {
|
||||
localStorage.setItem('customBackgroundColour', this.currentGradientSettings());
|
||||
localStorage.setItem(
|
||||
"customBackgroundColour",
|
||||
this.currentGradientSettings()
|
||||
);
|
||||
}
|
||||
|
||||
onGradientChange = (event, index) => {
|
||||
const newValue = event.target.value;
|
||||
const name = event.target.name;
|
||||
this.setState((s) => {
|
||||
const newState = {
|
||||
return (newState = {
|
||||
gradientSettings: {
|
||||
...s.gradientSettings,
|
||||
gradient: s.gradientSettings.gradient.map((g, i) => i === index ? { ...g, [name]: newValue } : g)
|
||||
}
|
||||
};
|
||||
return newState;
|
||||
gradient: s.gradientSettings.gradient.map((g, i) =>
|
||||
i === index ? { ...g, [name]: newValue } : g
|
||||
),
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
this.showReminder();
|
||||
}
|
||||
};
|
||||
|
||||
addColour = () => {
|
||||
this.setState((s) => {
|
||||
const [lastGradient, ...initGradients] = s.gradientSettings.gradient.reverse();
|
||||
const newState = {
|
||||
const [lastGradient, ...initGradients] =
|
||||
s.gradientSettings.gradient.reverse();
|
||||
return {
|
||||
gradientSettings: {
|
||||
...s.gradientSettings,
|
||||
gradient: [...initGradients, lastGradient, { colour: localStorage.getItem('theme') === 'dark' ? '#000000' : '#ffffff', stop: 100 }].sort((a, b) => (a.stop > b.stop) ? 1 : -1)
|
||||
}
|
||||
gradient: [
|
||||
...initGradients,
|
||||
lastGradient,
|
||||
{
|
||||
colour:
|
||||
localStorage.getItem("theme") === "dark"
|
||||
? "#000000"
|
||||
: "#ffffff",
|
||||
stop: 100,
|
||||
},
|
||||
].sort((a, b) => (a.stop > b.stop ? 1 : -1)),
|
||||
},
|
||||
};
|
||||
return newState;
|
||||
});
|
||||
|
||||
variables.stats.postEvent('setting', 'Changed backgroundtype from colour to gradient');
|
||||
}
|
||||
variables.stats.postEvent(
|
||||
"setting",
|
||||
"Changed backgroundType from colour to gradient"
|
||||
);
|
||||
};
|
||||
|
||||
currentGradientSettings = () => {
|
||||
if (typeof this.state.gradientSettings === 'object' && this.state.gradientSettings.gradient.every(g => g.colour !== this.getMessage('modals.main.settings.sections.background.source.disabled'))) {
|
||||
const clampNumber = (num, a, b) => Math.max(Math.min(num, Math.max(a, b)), Math.min(a, b));
|
||||
if (
|
||||
typeof this.state.gradientSettings === "object" &&
|
||||
this.state.gradientSettings.gradient.every(
|
||||
(g) =>
|
||||
g.colour !==
|
||||
this.getMessage(
|
||||
"modals.main.settings.sections.background.source.disabled"
|
||||
)
|
||||
)
|
||||
) {
|
||||
const clampNumber = (num, a, b) =>
|
||||
Math.max(Math.min(num, Math.max(a, b)), Math.min(a, b));
|
||||
return JSON.stringify({
|
||||
...this.state.gradientSettings,
|
||||
gradient: [...this.state.gradientSettings.gradient.map(g => { return { ...g, stop: clampNumber(+g.stop, 0, 100) } })].sort((a, b) => (a.stop > b.stop) ? 1 : -1)
|
||||
gradient: [
|
||||
...this.state.gradientSettings.gradient.map((g) => {
|
||||
return { ...g, stop: clampNumber(+g.stop, 0, 100) };
|
||||
}),
|
||||
].sort((a, b) => (a.stop > b.stop ? 1 : -1)),
|
||||
});
|
||||
}
|
||||
return this.getMessage('modals.main.settings.sections.background.source.disabled');
|
||||
}
|
||||
return this.getMessage(
|
||||
"modals.main.settings.sections.background.source.disabled"
|
||||
);
|
||||
};
|
||||
|
||||
onColourPickerChange = (attrs, name) => {
|
||||
if (process.env.NODE_ENV === 'development') {
|
||||
if (process.env.NODE_ENV === "development") {
|
||||
console.log(attrs, name);
|
||||
}
|
||||
|
||||
|
@ -124,49 +163,63 @@ export default class ColourSettings extends PureComponent {
|
|||
angle: attrs.degree,
|
||||
gradient: attrs.points.map((p) => {
|
||||
return {
|
||||
colour: '#' + rgbToHex(p.red, p.green, p.blue),
|
||||
stop: p.left
|
||||
}}),
|
||||
type: attrs.type
|
||||
}
|
||||
colour: "#" + rgbToHex(p.red, p.green, p.blue),
|
||||
stop: p.left,
|
||||
};
|
||||
}),
|
||||
type: attrs.type,
|
||||
},
|
||||
});
|
||||
|
||||
this.showReminder();
|
||||
};
|
||||
|
||||
showReminder() {
|
||||
const reminderInfo = document.querySelector('.reminder-info');
|
||||
if (reminderInfo.style.display !== 'block') {
|
||||
reminderInfo.style.display = 'block';
|
||||
localStorage.setItem('showReminder', true);
|
||||
const reminderInfo = document.querySelector(".reminder-info");
|
||||
if (reminderInfo.style.display !== "block") {
|
||||
reminderInfo.style.display = "block";
|
||||
localStorage.setItem("showReminder", true);
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
let colourSettings = null;
|
||||
if (typeof this.state.gradientSettings === 'object') {
|
||||
const gradientHasMoreThanOneColour = this.state.gradientSettings.gradient.length > 1;
|
||||
if (typeof this.state.gradientSettings === "object") {
|
||||
const gradientHasMoreThanOneColour =
|
||||
this.state.gradientSettings.gradient.length > 1;
|
||||
|
||||
let gradientInputs;
|
||||
if (gradientHasMoreThanOneColour) {
|
||||
if (this.GradientPickerInitalState === undefined) {
|
||||
if (this.GradientPickerInitialState === undefined) {
|
||||
this.initialiseColourPickerState(this.state.gradientSettings);
|
||||
}
|
||||
|
||||
gradientInputs = (
|
||||
<ColorPicker
|
||||
onStartChange={(colour) => this.onColourPickerChange(colour, 'start')}
|
||||
onChange={(colour) => this.onColourPickerChange(colour, 'change')}
|
||||
onEndChange={(colour) => this.onColourPickerChange(colour, 'end')}
|
||||
gradient={this.GradientPickerInitalState}
|
||||
isGradient/>
|
||||
onStartChange={(colour) =>
|
||||
this.onColourPickerChange(colour, "start")
|
||||
}
|
||||
onChange={(colour) => this.onColourPickerChange(colour, "change")}
|
||||
onEndChange={(colour) => this.onColourPickerChange(colour, "end")}
|
||||
gradient={this.GradientPickerInitialState}
|
||||
isGradient
|
||||
/>
|
||||
);
|
||||
} else {
|
||||
gradientInputs = this.state.gradientSettings.gradient.map((g, i) => {
|
||||
return (
|
||||
<Fragment key={i}>
|
||||
<input id={'colour_' + i} type='color' name='colour' className='colour' onChange={(event) => this.onGradientChange(event, i)} value={g.colour}></input>
|
||||
<label htmlFor={'colour_' + i} className='customBackgroundHex'>{g.colour}</label>
|
||||
<input
|
||||
id={"colour_" + i}
|
||||
type="color"
|
||||
name="colour"
|
||||
className="colour"
|
||||
onChange={(event) => this.onGradientChange(event, i)}
|
||||
value={g.colour}
|
||||
></input>
|
||||
<label htmlFor={"colour_" + i} className="customBackgroundHex">
|
||||
{g.colour}
|
||||
</label>
|
||||
</Fragment>
|
||||
);
|
||||
});
|
||||
|
@ -174,16 +227,32 @@ export default class ColourSettings extends PureComponent {
|
|||
|
||||
colourSettings = (
|
||||
<>
|
||||
{gradientInputs}
|
||||
{!gradientHasMoreThanOneColour ? (<><br/><br/><button type='button' className='add' onClick={this.addColour}>{this.getMessage('modals.main.settings.sections.background.source.add_colour')}</button></>) : null}
|
||||
<div className="colourInput">{gradientInputs}</div>
|
||||
{!gradientHasMoreThanOneColour ? (
|
||||
<>
|
||||
<button type="button" className="add" onClick={this.addColour}>
|
||||
{this.getMessage(
|
||||
"modals.main.settings.sections.background.source.add_colour"
|
||||
)}
|
||||
</button>
|
||||
</>
|
||||
) : null}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<p>{this.getMessage('modals.main.settings.sections.background.source.custom_colour')} <span className='modalLink' onClick={() => this.resetColour()}>{this.getMessage('modals.main.settings.buttons.reset')}</span></p>
|
||||
{colourSettings}
|
||||
<SettingsItem
|
||||
title={this.getMessage(
|
||||
"modals.main.settings.sections.background.source.custom_colour"
|
||||
)}
|
||||
>
|
||||
<span className="link" onClick={() => this.resetColour()}>
|
||||
{this.getMessage("modals.main.settings.buttons.reset")}
|
||||
</span>
|
||||
{colourSettings}
|
||||
</SettingsItem>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,141 +1,228 @@
|
|||
import variables from 'modules/variables';
|
||||
import { PureComponent } from 'react';
|
||||
import { toast } from 'react-toastify';
|
||||
import { MdCancel, MdAddLink, MdAddPhotoAlternate, MdPersonalVideo } from 'react-icons/md';
|
||||
import EventBus from 'modules/helpers/eventbus';
|
||||
import variables from "modules/variables";
|
||||
import { PureComponent } from "react";
|
||||
import { toast } from "react-toastify";
|
||||
import {
|
||||
MdCancel,
|
||||
MdAddLink,
|
||||
MdAddPhotoAlternate,
|
||||
MdPersonalVideo,
|
||||
} from "react-icons/md";
|
||||
import EventBus from "modules/helpers/eventbus";
|
||||
|
||||
import Checkbox from '../../Checkbox';
|
||||
import FileUpload from '../../FileUpload';
|
||||
import Checkbox from "../../Checkbox";
|
||||
import FileUpload from "../../FileUpload";
|
||||
import SettingsItem from "../../SettingsItem";
|
||||
|
||||
import Modal from 'react-modal';
|
||||
import Modal from "react-modal";
|
||||
|
||||
import CustomURLModal from './CustomURLModal';
|
||||
import CustomURLModal from "./CustomURLModal";
|
||||
|
||||
export default class CustomSettings extends PureComponent {
|
||||
getMessage = (text) => variables.language.getMessage(variables.languagecode, text);
|
||||
getMessage = (text) =>
|
||||
variables.language.getMessage(variables.languagecode, text);
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.state = {
|
||||
customBackground: this.getCustom(),
|
||||
customURLModal: false
|
||||
customURLModal: false,
|
||||
};
|
||||
}
|
||||
|
||||
resetCustom = () => {
|
||||
localStorage.setItem('customBackground', '[]');
|
||||
localStorage.setItem("customBackground", "[]");
|
||||
this.setState({
|
||||
customBackground: []
|
||||
customBackground: [],
|
||||
});
|
||||
toast(this.getMessage('toasts.reset'));
|
||||
EventBus.dispatch('refresh', 'background');
|
||||
}
|
||||
|
||||
toast(this.getMessage("toasts.reset"));
|
||||
EventBus.dispatch("refresh", "background");
|
||||
};
|
||||
|
||||
customBackground(e, text, index) {
|
||||
const result = (text === true) ? e.target.value : e.target.result;
|
||||
|
||||
const result = text === true ? e.target.value : e.target.result;
|
||||
|
||||
const customBackground = this.state.customBackground;
|
||||
customBackground[index] = result;
|
||||
this.setState({
|
||||
customBackground
|
||||
customBackground,
|
||||
});
|
||||
this.forceUpdate();
|
||||
|
||||
localStorage.setItem('customBackground', JSON.stringify(customBackground));
|
||||
document.querySelector('.reminder-info').style.display = 'block';
|
||||
localStorage.setItem('showReminder', true);
|
||||
|
||||
localStorage.setItem("customBackground", JSON.stringify(customBackground));
|
||||
document.querySelector(".reminder-info").style.display = "flex";
|
||||
localStorage.setItem("showReminder", true);
|
||||
}
|
||||
|
||||
|
||||
modifyCustomBackground(type, index) {
|
||||
const customBackground = this.state.customBackground;
|
||||
if (type === 'add') {
|
||||
customBackground.push('');
|
||||
if (type === "add") {
|
||||
customBackground.push("");
|
||||
} else {
|
||||
customBackground.splice(index, 1);
|
||||
}
|
||||
|
||||
|
||||
this.setState({
|
||||
customBackground
|
||||
customBackground,
|
||||
});
|
||||
this.forceUpdate();
|
||||
|
||||
localStorage.setItem('customBackground', JSON.stringify(customBackground));
|
||||
document.querySelector('.reminder-info').style.display = 'block';
|
||||
localStorage.setItem('showReminder', true);
|
||||
|
||||
localStorage.setItem("customBackground", JSON.stringify(customBackground));
|
||||
document.querySelector(".reminder-info").style.display = "flex";
|
||||
localStorage.setItem("showReminder", true);
|
||||
}
|
||||
|
||||
videoCheck(url) {
|
||||
return url.startsWith('data:video/') || url.endsWith('.mp4') || url.endsWith('.webm') || url.endsWith('.ogg');
|
||||
return (
|
||||
url.startsWith("data:video/") ||
|
||||
url.endsWith(".mp4") ||
|
||||
url.endsWith(".webm") ||
|
||||
url.endsWith(".ogg")
|
||||
);
|
||||
}
|
||||
|
||||
videoCustomSettings = () => {
|
||||
const hasVideo = this.state.customBackground.filter(bg => this.videoCheck(bg));
|
||||
|
||||
if (hasVideo.length > 0) {
|
||||
videoCustomSettings = () => {
|
||||
const hasVideo = this.state.customBackground.filter((bg) =>
|
||||
this.videoCheck(bg)
|
||||
);
|
||||
|
||||
if (hasVideo.length > 0) {
|
||||
return (
|
||||
<>
|
||||
<Checkbox name='backgroundVideoLoop' text={this.getMessage('modals.main.settings.sections.background.source.loop_video')}/>
|
||||
<Checkbox name='backgroundVideoMute' text={this.getMessage('modals.main.settings.sections.background.source.mute_video')}/>
|
||||
<Checkbox
|
||||
name="backgroundVideoLoop"
|
||||
text={this.getMessage(
|
||||
"modals.main.settings.sections.background.source.loop_video"
|
||||
)}
|
||||
/>
|
||||
<Checkbox
|
||||
name="backgroundVideoMute"
|
||||
text={this.getMessage(
|
||||
"modals.main.settings.sections.background.source.mute_video"
|
||||
)}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
getCustom() {
|
||||
let data;
|
||||
try {
|
||||
data = JSON.parse(localStorage.getItem('customBackground'));
|
||||
data = JSON.parse(localStorage.getItem("customBackground"));
|
||||
} catch (e) {
|
||||
data = [localStorage.getItem('customBackground')];
|
||||
data = [localStorage.getItem("customBackground")];
|
||||
}
|
||||
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
uploadCustomBackground() {
|
||||
document.getElementById('bg-input').setAttribute('index', this.state.customBackground.length);
|
||||
document.getElementById('bg-input').click();
|
||||
document
|
||||
.getElementById("bg-input")
|
||||
.setAttribute("index", this.state.customBackground.length);
|
||||
document.getElementById("bg-input").click();
|
||||
// to fix loadFunction
|
||||
this.setState({
|
||||
currentBackgroundIndex: this.state.customBackground.length
|
||||
currentBackgroundIndex: this.state.customBackground.length,
|
||||
});
|
||||
}
|
||||
|
||||
addCustomURL(e) {
|
||||
this.setState({
|
||||
customURLModal: false,
|
||||
currentBackgroundIndex: this.state.customBackground.length
|
||||
currentBackgroundIndex: this.state.customBackground.length,
|
||||
});
|
||||
this.customBackground({ target: { value: e }}, true, this.state.customBackground.length);
|
||||
this.customBackground(
|
||||
{ target: { value: e } },
|
||||
true,
|
||||
this.state.customBackground.length
|
||||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<ul>
|
||||
<p>{this.getMessage('modals.main.settings.sections.background.source.custom_background')} <span className='modalLink' onClick={this.resetCustom}>{this.getMessage('modals.main.settings.buttons.reset')}</span></p>
|
||||
<div className='data-buttons-row'>
|
||||
<button onClick={() => this.uploadCustomBackground()}>{this.getMessage('modals.main.settings.sections.background.source.add_background')} <MdAddPhotoAlternate/></button>
|
||||
<button onClick={() => this.setState({ customURLModal: true })}>{this.getMessage('modals.main.settings.sections.background.source.add_url')} <MdAddLink/></button>
|
||||
</div>
|
||||
<div className='images-row'>
|
||||
{this.state.customBackground.map((url, index) => (
|
||||
<div style={{ backgroundImage: `url(${!this.videoCheck(url) ? this.state.customBackground[index] : ''})` }} key={index}>
|
||||
{this.videoCheck(url) ? <MdPersonalVideo className='customvideoicon'/> : null}
|
||||
{this.state.customBackground.length > 0 ? <button className='cleanButton' onClick={() => this.modifyCustomBackground('remove', index)}>
|
||||
<MdCancel/>
|
||||
</button> : null}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
<FileUpload id='bg-input' accept='image/jpeg, image/png, image/webp, image/webm, image/gif, video/mp4, video/webm, video/ogg' loadFunction={(e) => this.customBackground(e, false, this.state.currentBackgroundIndex)} />
|
||||
<>
|
||||
{this.props.interval}
|
||||
<div className="settingsRow" style={{ alignItems: "flex-start" }}>
|
||||
<div className="content">
|
||||
<div className="images-row">
|
||||
{this.state.customBackground.map((url, index) => (
|
||||
<div key={index}>
|
||||
<img
|
||||
alt={"Custom background " + (index || 0)}
|
||||
src={`${
|
||||
!this.videoCheck(url)
|
||||
? this.state.customBackground[index]
|
||||
: ""
|
||||
}`}
|
||||
/>
|
||||
{this.videoCheck(url) ? (
|
||||
<MdPersonalVideo className="customvideoicon" />
|
||||
) : null}
|
||||
{this.state.customBackground.length > 0 ? (
|
||||
<button
|
||||
className="iconButton"
|
||||
onClick={() =>
|
||||
this.modifyCustomBackground("remove", index)
|
||||
}
|
||||
>
|
||||
<MdCancel />
|
||||
</button>
|
||||
) : null}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
<div className="action">
|
||||
{/*<button onClick={() => this.uploadCustomBackground()}>{this.getMessage('modals.main.settings.sections.background.source.add_background')} <MdAddPhotoAlternate/></button>*/}
|
||||
<div className="dropzone">
|
||||
<MdAddPhotoAlternate />
|
||||
<span className="title">Drop to upload</span>
|
||||
<span className="subtitle">
|
||||
Available formats, jpeg, png, webp, webm, gif, mp4, webm, ogg
|
||||
</span>
|
||||
<button onClick={() => this.uploadCustomBackground()}>
|
||||
Or Select
|
||||
</button>
|
||||
</div>
|
||||
<button onClick={() => this.setState({ customURLModal: true })}>
|
||||
{this.getMessage(
|
||||
"modals.main.settings.sections.background.source.add_url"
|
||||
)}{" "}
|
||||
<MdAddLink />
|
||||
</button>
|
||||
{/*<span className='subtitle'>
|
||||
{this.getMessage('modals.main.settings.sections.background.source.custom_background')}{' '}
|
||||
<span className="link" onClick={this.resetCustom}>
|
||||
{this.getMessage('modals.main.settings.buttons.reset')}
|
||||
</span>
|
||||
</span>*/}
|
||||
</div>
|
||||
</div>
|
||||
<FileUpload
|
||||
id="bg-input"
|
||||
accept="image/jpeg, image/png, image/webp, image/webm, image/gif, video/mp4, video/webm, video/ogg"
|
||||
loadFunction={(e) =>
|
||||
this.customBackground(e, false, this.state.currentBackgroundIndex)
|
||||
}
|
||||
/>
|
||||
{this.videoCustomSettings()}
|
||||
<Modal closeTimeoutMS={100} onRequestClose={() => this.setState({ customURLModal: false })} isOpen={this.state.customURLModal} className='Modal resetmodal mainModal' overlayClassName='Overlay resetoverlay' ariaHideApp={false}>
|
||||
<CustomURLModal modalClose={(e) => this.addCustomURL(e)} modalCloseOnly={() => this.setState({ customURLModal: false })} />
|
||||
<Modal
|
||||
closeTimeoutMS={100}
|
||||
onRequestClose={() => this.setState({ customURLModal: false })}
|
||||
isOpen={this.state.customURLModal}
|
||||
className="Modal resetmodal mainModal"
|
||||
overlayClassName="Overlay resetoverlay"
|
||||
ariaHideApp={false}
|
||||
>
|
||||
<CustomURLModal
|
||||
modalClose={(e) => this.addCustomURL(e)}
|
||||
modalCloseOnly={() => this.setState({ customURLModal: false })}
|
||||
/>
|
||||
</Modal>
|
||||
</ul>
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,19 +1,34 @@
|
|||
import variables from 'modules/variables';
|
||||
import { useState } from 'react';
|
||||
import { MdAdd } from 'react-icons/md';
|
||||
import { TextField } from '@mui/material';
|
||||
import variables from "modules/variables";
|
||||
import { useState } from "react";
|
||||
import { MdAdd } from "react-icons/md";
|
||||
import { TextField } from "@mui/material";
|
||||
|
||||
export default function CustomURLModal({ modalClose, modalCloseOnly }) {
|
||||
const [url, setURL] = useState();
|
||||
|
||||
return (
|
||||
<>
|
||||
<span className='closeModal' onClick={modalCloseOnly}>×</span>
|
||||
<h1>{variables.language.getMessage(variables.languagecode, 'modals.main.settings.sections.background.source.add_url')}</h1>
|
||||
<TextField value={url} onChange={(e) => setURL(e.target.value)} varient='outlined'/>
|
||||
<div className='resetfooter'>
|
||||
<button className='round import' style={{ marginLeft: '5px' }} onClick={() => modalClose(url)}>
|
||||
<MdAdd/>
|
||||
<span className="closeModal" onClick={modalCloseOnly}>
|
||||
×
|
||||
</span>
|
||||
<h1>
|
||||
{variables.language.getMessage(
|
||||
variables.languagecode,
|
||||
"modals.main.settings.sections.background.source.add_url"
|
||||
)}
|
||||
</h1>
|
||||
<TextField
|
||||
value={url}
|
||||
onChange={(e) => setURL(e.target.value)}
|
||||
varient="outlined"
|
||||
/>
|
||||
<div className="resetFooter">
|
||||
<button
|
||||
className="round import"
|
||||
style={{ marginLeft: "5px" }}
|
||||
onClick={() => modalClose(url)}
|
||||
>
|
||||
<MdAdd />
|
||||
</button>
|
||||
</div>
|
||||
</>
|
||||
|
|
|
@ -5,11 +5,11 @@ import Added from '../marketplace/sections/Added';
|
|||
import Sideload from '../marketplace/sections/Sideload';
|
||||
import Create from '../marketplace/sections/Create';
|
||||
|
||||
export default function Addons() {
|
||||
export default function Addons(props) {
|
||||
const getMessage = (text) => variables.language.getMessage(variables.languagecode, text);
|
||||
|
||||
return (
|
||||
<Tabs>
|
||||
<Tabs changeTab={(type) => props.changeTab(type)} current='addons'>
|
||||
<div label={getMessage('modals.main.addons.added')} name='added'><Added/></div>
|
||||
<div label={getMessage('modals.main.addons.sideload.title')} name='sideload'><Sideload/></div>
|
||||
<div label={getMessage('modals.main.addons.create.title')} name='create'><Create/></div>
|
||||
|
|
|
@ -3,11 +3,12 @@ import Tabs from './backend/Tabs';
|
|||
|
||||
import MarketplaceTab from '../marketplace/sections/Marketplace';
|
||||
|
||||
export default function Marketplace() {
|
||||
export default function Marketplace(props) {
|
||||
const getMessage = (text) => variables.language.getMessage(variables.languagecode, text);
|
||||
|
||||
return (
|
||||
<Tabs>
|
||||
<Tabs changeTab={(type) => props.changeTab(type)} current='marketplace'>
|
||||
<div label='All' name='all'><MarketplaceTab type='all'/></div>
|
||||
<div label={getMessage('modals.main.marketplace.photo_packs')} name='photo_packs'><MarketplaceTab type='photo_packs'/></div>
|
||||
<div label={getMessage('modals.main.marketplace.quote_packs')} name='quote_packs'><MarketplaceTab type='quote_packs'/></div>
|
||||
<div label={getMessage('modals.main.marketplace.preset_settings')} name='preset_settings'><MarketplaceTab type='preset_settings'/></div>
|
||||
|
|
|
@ -7,6 +7,7 @@ import Time from '../settings/sections/Time';
|
|||
import QuickLinks from '../settings/sections/QuickLinks';
|
||||
import Quote from '../settings/sections/Quote';
|
||||
import Date from '../settings/sections/Date';
|
||||
import Reminder from '../settings/sections/Reminder';
|
||||
import Message from '../settings/sections/Message';
|
||||
import Background from '../settings/sections/background/Background';
|
||||
import Search from '../settings/sections/Search';
|
||||
|
@ -21,22 +22,23 @@ import Experimental from '../settings/sections/Experimental';
|
|||
import Changelog from '../settings/sections/Changelog';
|
||||
import About from '../settings/sections/About';
|
||||
|
||||
export default function Settings() {
|
||||
export default function Settings(props) {
|
||||
const getMessage = (text) => variables.language.getMessage(variables.languagecode, text);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Tabs>
|
||||
<Tabs changeTab={(type) => props.changeTab(type)} current='settings'>
|
||||
<div label={getMessage('modals.main.settings.sections.appearance.navbar.title')} name='navbar'><Navbar/></div>
|
||||
<div label={getMessage('modals.main.settings.sections.greeting.title')} name='greeting'><Greeting/></div>
|
||||
<div label={getMessage('modals.main.settings.sections.time.title')} name='time'><Time/></div>
|
||||
<div label={getMessage('modals.main.settings.sections.quicklinks.title')} name='quicklinks'><QuickLinks/></div>
|
||||
<div label={getMessage('modals.main.settings.sections.quote.title')} name='quote'><Quote/></div>
|
||||
<div label={getMessage('modals.main.settings.sections.date.title')} name='date'><Date/></div>
|
||||
<div label='Reminder' name='reminder'><Reminder/></div>
|
||||
<div label={getMessage('modals.main.settings.sections.message.title')} name='message'><Message/></div>
|
||||
<div label={getMessage('modals.main.settings.sections.background.title')} name='background'><Background/></div>
|
||||
<div label={getMessage('modals.main.settings.sections.search.title')} name='search'><Search/></div>
|
||||
<div label={getMessage('modals.main.settings.sections.weather.title')} name='weather'><Weather/></div>
|
||||
|
||||
<div label={getMessage('modals.main.settings.sections.order.title')} name='order'><Order/></div>
|
||||
<div label={getMessage('modals.main.settings.sections.appearance.title')} name='appearance'><Appearance/></div>
|
||||
<div label={getMessage('modals.main.settings.sections.language.title')} name='language'><Language/></div>
|
||||
|
@ -47,6 +49,5 @@ export default function Settings() {
|
|||
<div label={getMessage('modals.main.settings.sections.changelog.title')} name='changelog'><Changelog/></div>
|
||||
<div label={getMessage('modals.main.settings.sections.about.title')} name='about'><About/></div>
|
||||
</Tabs>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -29,7 +29,6 @@ import {
|
|||
MdAddCircleOutline as Create
|
||||
} from 'react-icons/md';
|
||||
|
||||
|
||||
function Tab({ label, currentTab, onClick, navbarTab }) {
|
||||
const getMessage = (text) => variables.language.getMessage(variables.languagecode, text);
|
||||
|
||||
|
@ -62,6 +61,7 @@ function Tab({ label, currentTab, onClick, navbarTab }) {
|
|||
case getMessage('modals.main.settings.sections.search.title'): icon = <MdSearch/>; break;
|
||||
case getMessage('modals.main.settings.sections.weather.title'): icon = <Weather/>; divider = true; break;
|
||||
case getMessage('modals.main.settings.sections.order.title'): icon = <Order/>; break;
|
||||
case 'Reminder': icon = <Reminder/>; break;
|
||||
|
||||
case getMessage('modals.main.settings.sections.appearance.title'): icon = <Appearance/>; break;
|
||||
case getMessage('modals.main.settings.sections.language.title'): icon = <Language/>; divider = true; break;
|
||||
|
@ -76,6 +76,7 @@ function Tab({ label, currentTab, onClick, navbarTab }) {
|
|||
case getMessage('modals.main.addons.sideload.title'): icon = <Sideload/>; break;
|
||||
case getMessage('modals.main.addons.create.title'): icon = <Create/>; break;
|
||||
|
||||
case 'All': icon = <Addons/>; divider = true; break;
|
||||
case getMessage('modals.main.marketplace.photo_packs'): icon = <Background/>; break;
|
||||
case getMessage('modals.main.marketplace.quote_packs'): icon = <Quote/>; break;
|
||||
case getMessage('modals.main.marketplace.preset_settings'): icon = <Advanced/>; break;
|
||||
|
@ -91,9 +92,9 @@ function Tab({ label, currentTab, onClick, navbarTab }) {
|
|||
|
||||
return (
|
||||
<>
|
||||
<li className={className} onClick={() => onClick(label)}>
|
||||
<button className={className} onClick={() => onClick(label)}>
|
||||
{icon} <span>{label}</span>
|
||||
</li>
|
||||
</button>
|
||||
{(divider === true) ? <hr/> : null}
|
||||
</>
|
||||
);
|
||||
|
|
|
@ -1,8 +1,12 @@
|
|||
import variables from 'modules/variables';
|
||||
import { PureComponent } from 'react';
|
||||
|
||||
import Tab from './Tab';
|
||||
import ErrorBoundary from '../../../ErrorBoundary';
|
||||
import variables from "modules/variables";
|
||||
import { PureComponent } from "react";
|
||||
import {
|
||||
MdSettings,
|
||||
MdOutlineShoppingBasket,
|
||||
MdOutlineExtension,
|
||||
} from "react-icons/md";
|
||||
import Tab from "./Tab";
|
||||
import ErrorBoundary from "../../../ErrorBoundary";
|
||||
|
||||
export default class Tabs extends PureComponent {
|
||||
constructor(props) {
|
||||
|
@ -10,36 +14,67 @@ export default class Tabs extends PureComponent {
|
|||
|
||||
this.state = {
|
||||
currentTab: this.props.children[0].props.label,
|
||||
currentName: this.props.children[0].props.name
|
||||
currentName: this.props.children[0].props.name,
|
||||
};
|
||||
}
|
||||
|
||||
onClick = (tab, name) => {
|
||||
if (name !== this.state.currentName) {
|
||||
variables.stats.postEvent('tab', `Opened ${name}`);
|
||||
variables.stats.postEvent("tab", `Opened ${name}`);
|
||||
}
|
||||
|
||||
this.setState({
|
||||
this.setState({
|
||||
currentTab: tab,
|
||||
currentName: name
|
||||
currentName: name,
|
||||
});
|
||||
};
|
||||
|
||||
render() {
|
||||
let className = 'sidebar';
|
||||
let tabClass = 'tab-content';
|
||||
let optionsText = (<h1>{variables.language.getMessage(variables.languagecode, 'modals.main.title')}</h1>);
|
||||
const reminderInfo = (
|
||||
<div className="reminder-info" style={{ display: "none" }}>
|
||||
<span className="title">
|
||||
{variables.language.getMessage(
|
||||
variables.languagecode,
|
||||
"modals.main.settings.reminder.title"
|
||||
)}
|
||||
</span>
|
||||
<span className="subtitle">
|
||||
{variables.language.getMessage(
|
||||
variables.languagecode,
|
||||
"modals.main.settings.reminder.message"
|
||||
)}
|
||||
</span>
|
||||
<button onClick={() => window.location.reload()}>
|
||||
{variables.language.getMessage(
|
||||
variables.languagecode,
|
||||
"modals.main.error_boundary.refresh"
|
||||
)}
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
|
||||
if (this.props.navbar) {
|
||||
className = 'modalNavbar';
|
||||
tabClass = '';
|
||||
optionsText = '';
|
||||
let settingsActive = "";
|
||||
let addonsActive = "";
|
||||
let marketplaceActive = "";
|
||||
|
||||
switch (this.props.current) {
|
||||
case "settings":
|
||||
settingsActive = "navbar-item-active";
|
||||
break;
|
||||
case "addons":
|
||||
addonsActive = "navbar-item-active";
|
||||
break;
|
||||
case "marketplace":
|
||||
marketplaceActive = "navbar-item-active";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
return (
|
||||
<>
|
||||
<ul className={className}>
|
||||
{optionsText}
|
||||
<div style={{ display: "flex", width: "100%" }}>
|
||||
<ul className="sidebar">
|
||||
{reminderInfo}
|
||||
{this.props.children.map((tab, index) => (
|
||||
<Tab
|
||||
currentTab={this.state.currentTab}
|
||||
|
@ -50,8 +85,31 @@ export default class Tabs extends PureComponent {
|
|||
/>
|
||||
))}
|
||||
</ul>
|
||||
<div className={tabClass}>
|
||||
<div className="tab-content" style={{ width: "100%" }}>
|
||||
<ErrorBoundary>
|
||||
<div className="modalNavbar">
|
||||
<button
|
||||
className={"navbar-item" + settingsActive}
|
||||
onClick={() => this.props.changeTab("settings")}
|
||||
>
|
||||
<MdSettings />
|
||||
<span>Settings</span>
|
||||
</button>
|
||||
<button
|
||||
className={"navbar-item" + addonsActive}
|
||||
onClick={() => this.props.changeTab("addons")}
|
||||
>
|
||||
<MdOutlineExtension />
|
||||
<span>Add-ons</span>
|
||||
</button>
|
||||
<button
|
||||
className={"navbar-item" + marketplaceActive}
|
||||
onClick={() => this.props.changeTab("marketplace")}
|
||||
>
|
||||
<MdOutlineShoppingBasket />
|
||||
<span>Marketplace</span>
|
||||
</button>
|
||||
</div>
|
||||
{this.props.children.map((tab) => {
|
||||
if (tab.props.label !== this.state.currentTab) {
|
||||
return undefined;
|
||||
|
@ -61,7 +119,7 @@ export default class Tabs extends PureComponent {
|
|||
})}
|
||||
</ErrorBoundary>
|
||||
</div>
|
||||
</>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
export default function ProgressBar({ count, currentTab, switchTab }) {
|
||||
return (
|
||||
<div className='progressbar'>
|
||||
<div className="progressbar">
|
||||
{count.map((num) => {
|
||||
let className = 'step';
|
||||
|
||||
|
@ -9,7 +9,7 @@ export default function ProgressBar({ count, currentTab, switchTab }) {
|
|||
className = 'step active';
|
||||
}
|
||||
|
||||
return <div className={className} key={index} onClick={() => switchTab(index)}></div>;
|
||||
return <div className={className} key={index} onClick={() => switchTab(index)} />;
|
||||
})}
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -17,15 +17,15 @@ export default class WelcomeModal extends PureComponent {
|
|||
image: './././icons/undraw_celebration.svg',
|
||||
currentTab: 0,
|
||||
finalTab: 4,
|
||||
buttonText: this.getMessage('modals.welcome.buttons.next')
|
||||
buttonText: this.getMessage('modals.welcome.buttons.next'),
|
||||
};
|
||||
this.images = [
|
||||
'./././icons/undraw_celebration.svg',
|
||||
'./././icons/undraw_around_the_world_modified.svg',
|
||||
'./././icons/undraw_add_files_modified.svg',
|
||||
'./././icons/undraw_celebration.svg',
|
||||
'./././icons/undraw_around_the_world_modified.svg',
|
||||
'./././icons/undraw_add_files_modified.svg',
|
||||
'./././icons/undraw_dark_mode.svg',
|
||||
'./././icons/undraw_private_data_modified.svg',
|
||||
'./././icons/undraw_upgrade_modified.svg'
|
||||
'./././icons/undraw_private_data_modified.svg',
|
||||
'./././icons/undraw_upgrade_modified.svg',
|
||||
];
|
||||
}
|
||||
|
||||
|
@ -37,7 +37,7 @@ export default class WelcomeModal extends PureComponent {
|
|||
return this.setState({
|
||||
currentTab: this.state.currentTab - 1,
|
||||
image: this.images[this.state.currentTab - 1],
|
||||
buttonText: this.getMessage('modals.welcome.buttons.next')
|
||||
buttonText: this.getMessage('modals.welcome.buttons.next'),
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -48,7 +48,10 @@ export default class WelcomeModal extends PureComponent {
|
|||
this.setState({
|
||||
currentTab: this.state.currentTab + 1,
|
||||
image: this.images[this.state.currentTab + 1],
|
||||
buttonText: (this.state.currentTab !== this.state.finalTab) ? this.getMessage('modals.welcome.buttons.next') : this.getMessage('modals.main.addons.create.finish.title')
|
||||
buttonText:
|
||||
this.state.currentTab !== this.state.finalTab
|
||||
? this.getMessage('modals.welcome.buttons.next')
|
||||
: this.getMessage('modals.main.addons.create.finish.title'),
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -57,7 +60,10 @@ export default class WelcomeModal extends PureComponent {
|
|||
this.setState({
|
||||
currentTab: tab,
|
||||
image: this.images[tab],
|
||||
buttonText: (tab !== this.state.finalTab + 1) ? this.getMessage('modals.welcome.buttons.next') : this.getMessage('modals.main.addons.create.finish.title')
|
||||
buttonText:
|
||||
tab !== this.state.finalTab + 1
|
||||
? this.getMessage('modals.welcome.buttons.next')
|
||||
: this.getMessage('modals.main.addons.create.finish.title'),
|
||||
});
|
||||
|
||||
localStorage.setItem('bgtransition', true);
|
||||
|
@ -70,7 +76,10 @@ export default class WelcomeModal extends PureComponent {
|
|||
this.setState({
|
||||
currentTab: Number(welcomeTab),
|
||||
image: this.images[Number(welcomeTab)],
|
||||
buttonText: (Number(welcomeTab) !== this.state.finalTab + 1) ? this.getMessage('modals.welcome.buttons.next') : this.getMessage('modals.main.addons.create.finish.title')
|
||||
buttonText:
|
||||
Number(welcomeTab) !== this.state.finalTab + 1
|
||||
? this.getMessage('modals.welcome.buttons.next')
|
||||
: this.getMessage('modals.main.addons.create.finish.title'),
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -89,19 +98,49 @@ export default class WelcomeModal extends PureComponent {
|
|||
|
||||
render() {
|
||||
return (
|
||||
<div className='welcomeContent'>
|
||||
<div className="welcomeContent">
|
||||
<section>
|
||||
<img className='showcaseimg' alt='sidebar icon' draggable={false} src={this.state.image} />
|
||||
<ProgressBar count={this.images} currentTab={this.state.currentTab} switchTab={(tab) => this.switchTab(tab)}/>
|
||||
<img
|
||||
className="showcaseimg"
|
||||
alt="sidebar icon"
|
||||
draggable={false}
|
||||
src={this.state.image}
|
||||
/>
|
||||
<ProgressBar
|
||||
count={this.images}
|
||||
currentTab={this.state.currentTab}
|
||||
switchTab={(tab) => this.switchTab(tab)}
|
||||
/>
|
||||
</section>
|
||||
<section>
|
||||
<div className='content'>
|
||||
<WelcomeSections currentTab={this.state.currentTab} switchTab={(tab) => this.switchTab(tab)}/>
|
||||
<div className="content">
|
||||
<WelcomeSections
|
||||
currentTab={this.state.currentTab}
|
||||
switchTab={(tab) => this.switchTab(tab)}
|
||||
/>
|
||||
</div>
|
||||
<div className='buttons'>
|
||||
{(this.state.currentTab === 0) ? <button className='close' style={{ marginRight: '20px' }} onClick={() => this.props.modalSkip()}>{this.getMessage('modals.welcome.buttons.preview')}</button> : null}
|
||||
{(this.state.currentTab !== 0) ? <button className='close' style={{ marginRight: '20px' }} onClick={() => this.changeTab(true)}>{this.getMessage('modals.welcome.buttons.previous')}</button> : null}
|
||||
<button className='close' onClick={() => this.changeTab()}>{this.state.buttonText}</button>
|
||||
<div className="buttons">
|
||||
{this.state.currentTab === 0 ? (
|
||||
<button
|
||||
className="close"
|
||||
style={{ marginRight: '20px' }}
|
||||
onClick={() => this.props.modalSkip()}
|
||||
>
|
||||
{this.getMessage('modals.welcome.buttons.preview')}
|
||||
</button>
|
||||
) : null}
|
||||
{this.state.currentTab !== 0 ? (
|
||||
<button
|
||||
className="close"
|
||||
style={{ marginRight: '20px' }}
|
||||
onClick={() => this.changeTab(true)}
|
||||
>
|
||||
{this.getMessage('modals.welcome.buttons.previous')}
|
||||
</button>
|
||||
) : null}
|
||||
<button className="close" onClick={() => this.changeTab()}>
|
||||
{this.state.buttonText}
|
||||
</button>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
|
|
|
@ -1,31 +1,37 @@
|
|||
import variables from 'modules/variables';
|
||||
import { PureComponent } from 'react';
|
||||
import { MdCloudUpload, MdAutoAwesome, MdLightMode, MdDarkMode } from 'react-icons/md';
|
||||
import variables from "modules/variables";
|
||||
import { PureComponent } from "react";
|
||||
import {
|
||||
MdCloudUpload,
|
||||
MdAutoAwesome,
|
||||
MdLightMode,
|
||||
MdDarkMode,
|
||||
} from "react-icons/md";
|
||||
|
||||
import Radio from '../main/settings/Radio';
|
||||
import Checkbox from '../main/settings/Checkbox';
|
||||
import FileUpload from '../main/settings/FileUpload';
|
||||
import Radio from "../main/settings/Radio";
|
||||
import Checkbox from "../main/settings/Checkbox";
|
||||
import FileUpload from "../main/settings/FileUpload";
|
||||
|
||||
import { loadSettings } from 'modules/helpers/settings';
|
||||
import { importSettings } from 'modules/helpers/settings/modals';
|
||||
import { loadSettings } from "modules/helpers/settings";
|
||||
import { importSettings } from "modules/helpers/settings/modals";
|
||||
|
||||
const languages = require('modules/languages.json');
|
||||
const default_settings = require('modules/default_settings.json');
|
||||
const languages = require("modules/languages.json");
|
||||
const default_settings = require("modules/default_settings.json");
|
||||
|
||||
export default class WelcomeSections extends PureComponent {
|
||||
getMessage = (text) => variables.language.getMessage(variables.languagecode, text);
|
||||
getMessage = (text) =>
|
||||
variables.language.getMessage(variables.languagecode, text);
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.state = {
|
||||
// themes
|
||||
autoClass: 'toggle auto active',
|
||||
lightClass: 'toggle lightTheme',
|
||||
darkClass: 'toggle darkTheme',
|
||||
autoClass: "toggle auto active",
|
||||
lightClass: "toggle lightTheme",
|
||||
darkClass: "toggle darkTheme",
|
||||
// welcome
|
||||
welcomeImage: 0,
|
||||
// final
|
||||
importedSettings: []
|
||||
importedSettings: [],
|
||||
};
|
||||
this.changeWelcomeImg = this.changeWelcomeImg.bind(this);
|
||||
this.welcomeImages = 4;
|
||||
|
@ -33,17 +39,22 @@ export default class WelcomeSections extends PureComponent {
|
|||
|
||||
changeTheme(type) {
|
||||
this.setState({
|
||||
autoClass: (type === 'auto') ? 'toggle auto active' : 'toggle auto',
|
||||
lightClass: (type === 'light') ? 'toggle lightTheme active' : 'toggle lightTheme',
|
||||
darkClass: (type === 'dark') ? 'toggle darkTheme active': 'toggle darkTheme'
|
||||
autoClass: type === "auto" ? "toggle auto active" : "toggle auto",
|
||||
lightClass:
|
||||
type === "light" ? "toggle lightTheme active" : "toggle lightTheme",
|
||||
darkClass:
|
||||
type === "dark" ? "toggle darkTheme active" : "toggle darkTheme",
|
||||
});
|
||||
|
||||
localStorage.setItem('theme', type);
|
||||
localStorage.setItem("theme", type);
|
||||
loadSettings(true);
|
||||
}
|
||||
|
||||
getSetting(name) {
|
||||
const value = localStorage.getItem(name).replace('false', 'Off').replace('true', 'On');
|
||||
const value = localStorage
|
||||
.getItem(name)
|
||||
.replace("false", "Off")
|
||||
.replace("true", "On");
|
||||
return value.charAt(0).toUpperCase() + value.slice(1);
|
||||
}
|
||||
|
||||
|
@ -54,7 +65,13 @@ export default class WelcomeSections extends PureComponent {
|
|||
const data = JSON.parse(e.target.result);
|
||||
Object.keys(data).forEach((setting) => {
|
||||
// language and theme already shown, the others are only used internally
|
||||
if (setting === 'language' || setting === 'theme'|| setting === 'firstRun' || setting === 'showWelcome' || setting === 'showReminder') {
|
||||
if (
|
||||
setting === "language" ||
|
||||
setting === "theme" ||
|
||||
setting === "firstRun" ||
|
||||
setting === "showWelcome" ||
|
||||
setting === "showReminder"
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -67,12 +84,12 @@ export default class WelcomeSections extends PureComponent {
|
|||
|
||||
settings.push({
|
||||
name: setting,
|
||||
value: data[setting]
|
||||
value: data[setting],
|
||||
});
|
||||
});
|
||||
|
||||
this.setState({
|
||||
importedSettings: settings
|
||||
importedSettings: settings,
|
||||
});
|
||||
|
||||
this.props.switchTab(5);
|
||||
|
@ -82,7 +99,7 @@ export default class WelcomeSections extends PureComponent {
|
|||
let welcomeImage = this.state.welcomeImage;
|
||||
|
||||
this.setState({
|
||||
welcomeImage: ++welcomeImage % this.welcomeImages
|
||||
welcomeImage: ++welcomeImage % this.welcomeImages.length,
|
||||
});
|
||||
|
||||
this.timeout = setTimeout(this.changeWelcomeImg, 3000);
|
||||
|
@ -111,104 +128,246 @@ export default class WelcomeSections extends PureComponent {
|
|||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
render() {
|
||||
const intro = (
|
||||
<>
|
||||
<h1>{this.getMessage('modals.welcome.sections.intro.title')}</h1>
|
||||
<p>{this.getMessage('modals.welcome.sections.intro.description')}</p>
|
||||
<h3 className='quicktip'>#shareyourmue</h3>
|
||||
<div className='examples'>
|
||||
<img src={`./welcome-images/example${[this.state.welcomeImage + 1]}.webp`} alt='Example Mue setup' draggable={false}/>
|
||||
<span className="mainTitle">
|
||||
{this.getMessage("modals.welcome.sections.intro.title")}
|
||||
</span>
|
||||
<p>{this.getMessage("modals.welcome.sections.intro.description")}</p>
|
||||
<h3 className="quicktip">#shareyourmue</h3>
|
||||
<div className="examples">
|
||||
<img
|
||||
src={this.welcomeImages[this.state.welcomeImage]}
|
||||
alt="Example Mue setup"
|
||||
draggable={false}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
|
||||
|
||||
const chooseLanguage = (
|
||||
<>
|
||||
<h1>{this.getMessage('modals.welcome.sections.language.title')}</h1>
|
||||
<p>{this.getMessage('modals.welcome.sections.language.description')} <a href={variables.constants.TRANSLATIONS_URL} className='resetLink' target='_blank' rel='noopener noreferrer'>GitHub</a>!</p>
|
||||
<Radio name='language' options={languages} category='welcomeLanguage'/>
|
||||
<span className="mainTitle">
|
||||
{this.getMessage("modals.welcome.sections.language.title")}
|
||||
</span>
|
||||
<p>
|
||||
{this.getMessage("modals.welcome.sections.language.description")}{" "}
|
||||
<a
|
||||
href={variables.constants.TRANSLATIONS_URL}
|
||||
className="resetLink"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
GitHub
|
||||
</a>
|
||||
!
|
||||
</p>
|
||||
<Radio name="language" options={languages} category="welcomeLanguage" />
|
||||
</>
|
||||
);
|
||||
|
||||
const theme = (
|
||||
<>
|
||||
<h1>{this.getMessage('modals.welcome.sections.theme.title')}</h1>
|
||||
<p>{this.getMessage('modals.welcome.sections.theme.description')}</p>
|
||||
<div className='themesToggleArea'>
|
||||
<div className={this.state.autoClass} onClick={() => this.changeTheme('auto')}>
|
||||
<MdAutoAwesome/>
|
||||
<span>{this.getMessage('modals.main.settings.sections.appearance.theme.auto')}</span>
|
||||
<span className="mainTitle">
|
||||
{this.getMessage("modals.welcome.sections.theme.title")}
|
||||
</span>
|
||||
<p>{this.getMessage("modals.welcome.sections.theme.description")}</p>
|
||||
<div className="themesToggleArea">
|
||||
<div
|
||||
className={this.state.autoClass}
|
||||
onClick={() => this.changeTheme("auto")}
|
||||
>
|
||||
<MdAutoAwesome />
|
||||
<span>
|
||||
{this.getMessage(
|
||||
"modals.main.settings.sections.appearance.theme.auto"
|
||||
)}
|
||||
</span>
|
||||
</div>
|
||||
<div className='options'>
|
||||
<div className={this.state.lightClass} onClick={() => this.changeTheme('light')}>
|
||||
<MdLightMode/>
|
||||
<span>{this.getMessage('modals.main.settings.sections.appearance.theme.light')}</span>
|
||||
<div className="options">
|
||||
<div
|
||||
className={this.state.lightClass}
|
||||
onClick={() => this.changeTheme("light")}
|
||||
>
|
||||
<MdLightMode />
|
||||
<span>
|
||||
{this.getMessage(
|
||||
"modals.main.settings.sections.appearance.theme.light"
|
||||
)}
|
||||
</span>
|
||||
</div>
|
||||
<div className={this.state.darkClass} onClick={() => this.changeTheme('dark')}>
|
||||
<MdDarkMode/>
|
||||
<span>{this.getMessage('modals.main.settings.sections.appearance.theme.dark')}</span>
|
||||
<div
|
||||
className={this.state.darkClass}
|
||||
onClick={() => this.changeTheme("dark")}
|
||||
>
|
||||
<MdDarkMode />
|
||||
<span>
|
||||
{this.getMessage(
|
||||
"modals.main.settings.sections.appearance.theme.dark"
|
||||
)}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<h3 className='quicktip'>{this.getMessage('modals.welcome.tip')}</h3>
|
||||
<p>{this.getMessage('modals.welcome.sections.theme.tip')}</p>
|
||||
<h3 className="quicktip">{this.getMessage("modals.welcome.tip")}</h3>
|
||||
<p>{this.getMessage("modals.welcome.sections.theme.tip")}</p>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
|
||||
|
||||
const settings = (
|
||||
<>
|
||||
<h1>{this.getMessage('modals.welcome.sections.settings.title')}</h1>
|
||||
<p>{this.getMessage('modals.welcome.sections.settings.description')}</p>
|
||||
<button className='upload' onClick={() => document.getElementById('file-input').click()}>
|
||||
<MdCloudUpload/>
|
||||
<br/>
|
||||
<span>{this.getMessage('modals.main.settings.buttons.import')}</span>
|
||||
<span className="mainTitle">
|
||||
{this.getMessage("modals.welcome.sections.settings.title")}
|
||||
</span>
|
||||
<p>{this.getMessage("modals.welcome.sections.settings.description")}</p>
|
||||
<button
|
||||
className="upload"
|
||||
onClick={() => document.getElementById("file-input").click()}
|
||||
>
|
||||
<MdCloudUpload />
|
||||
<br />
|
||||
<span>{this.getMessage("modals.main.settings.buttons.import")}</span>
|
||||
</button>
|
||||
<FileUpload id='file-input' accept='application/json' type='settings' loadFunction={(e) => this.importSettings(e)}/>
|
||||
<h3 className='quicktip'>{this.getMessage('modals.welcome.tip')}</h3>
|
||||
<p>{this.getMessage('modals.welcome.sections.settings.tip')}</p>
|
||||
<FileUpload
|
||||
id="file-input"
|
||||
accept="application/json"
|
||||
type="settings"
|
||||
loadFunction={(e) => this.importSettings(e)}
|
||||
/>
|
||||
<h3 className="quicktip">{this.getMessage("modals.welcome.tip")}</h3>
|
||||
<p>{this.getMessage("modals.welcome.sections.settings.tip")}</p>
|
||||
</>
|
||||
);
|
||||
|
||||
const privacy = (
|
||||
<>
|
||||
<h1>{this.getMessage('modals.welcome.sections.privacy.title')}</h1>
|
||||
<p>{this.getMessage('modals.welcome.sections.privacy.description')}</p>
|
||||
<Checkbox name='offlineMode' text={this.getMessage('modals.main.settings.sections.advanced.offline_mode')} element='.other' />
|
||||
<p>{this.getMessage('modals.welcome.sections.privacy.offline_mode_description')}</p>
|
||||
<Checkbox name='quicklinksddgProxy' text={this.getMessage('modals.main.settings.sections.background.ddg_image_proxy') + ' (' + this.getMessage('modals.main.settings.sections.quicklinks.title') + ')'}/>
|
||||
<Checkbox name='ddgProxy' text={this.getMessage('modals.main.settings.sections.background.ddg_image_proxy') + ' (' +this.getMessage('modals.main.settings.sections.background.title') + ')'}/>
|
||||
<p>{this.getMessage('modals.welcome.sections.privacy.ddg_proxy_description')}</p>
|
||||
<h3 className='quicktip'>{this.getMessage('modals.welcome.sections.privacy.links.title')}</h3>
|
||||
<a className='privacy' href={variables.constants.PRIVACY_URL} target='_blank' rel='noopener noreferrer'>{this.getMessage('modals.welcome.sections.privacy.links.privacy_policy')}</a>
|
||||
<br/><br/>
|
||||
<a className='privacy' href={'https://github.com/' + variables.constants.ORG_NAME} target='_blank' rel='noopener noreferrer'>{this.getMessage('modals.welcome.sections.privacy.links.source_code')}</a>
|
||||
<span className="mainTitle">
|
||||
{this.getMessage("modals.welcome.sections.privacy.title")}
|
||||
</span>
|
||||
<p>{this.getMessage("modals.welcome.sections.privacy.description")}</p>
|
||||
<Checkbox
|
||||
name="offlineMode"
|
||||
text={this.getMessage(
|
||||
"modals.main.settings.sections.advanced.offline_mode"
|
||||
)}
|
||||
element=".other"
|
||||
/>
|
||||
<p>
|
||||
{this.getMessage(
|
||||
"modals.welcome.sections.privacy.offline_mode_description"
|
||||
)}
|
||||
</p>
|
||||
<Checkbox
|
||||
name="quicklinksddgProxy"
|
||||
text={
|
||||
this.getMessage(
|
||||
"modals.main.settings.sections.background.ddg_image_proxy"
|
||||
) +
|
||||
" (" +
|
||||
this.getMessage("modals.main.settings.sections.quicklinks.title") +
|
||||
")"
|
||||
}
|
||||
/>
|
||||
<Checkbox
|
||||
name="ddgProxy"
|
||||
text={
|
||||
this.getMessage(
|
||||
"modals.main.settings.sections.background.ddg_image_proxy"
|
||||
) +
|
||||
" (" +
|
||||
this.getMessage("modals.main.settings.sections.background.title") +
|
||||
")"
|
||||
}
|
||||
/>
|
||||
<p>
|
||||
{this.getMessage(
|
||||
"modals.welcome.sections.privacy.ddg_proxy_description"
|
||||
)}
|
||||
</p>
|
||||
<h3 className="quicktip">
|
||||
{this.getMessage("modals.welcome.sections.privacy.links.title")}
|
||||
</h3>
|
||||
<a
|
||||
className="privacy"
|
||||
href={variables.constants.PRIVACY_URL}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
{this.getMessage(
|
||||
"modals.welcome.sections.privacy.links.privacy_policy"
|
||||
)}
|
||||
</a>
|
||||
<br />
|
||||
<br />
|
||||
<a
|
||||
className="privacy"
|
||||
href={"https://github.com/" + variables.constants.ORG_NAME}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
{this.getMessage("modals.welcome.sections.privacy.links.source_code")}
|
||||
</a>
|
||||
</>
|
||||
);
|
||||
|
||||
const final = (
|
||||
<>
|
||||
<h1>{this.getMessage('modals.welcome.sections.final.title')}</h1>
|
||||
<p>{this.getMessage('modals.welcome.sections.final.description')}</p>
|
||||
<h3 className='quicktip'>{this.getMessage('modals.welcome.sections.final.changes')}</h3>
|
||||
<p>{this.getMessage('modals.welcome.sections.final.changes_description')}</p>
|
||||
<div className='themesToggleArea'>
|
||||
<div className='toggle' onClick={() => this.props.switchTab(1)}><span>{this.getMessage('modals.main.settings.sections.language.title')}: {languages.find((i) => i.value === localStorage.getItem('language')).name}</span></div>
|
||||
<div className='toggle' onClick={() => this.props.switchTab(3)}><span>{this.getMessage('modals.main.settings.sections.appearance.theme.title')}: {this.getSetting('theme')}</span></div>
|
||||
{(this.state.importedSettings.length !== 0) ? <div className='toggle' onClick={() => this.props.switchTab(2)}>{this.getMessage('modals.main.settings.sections.final.imported', { amount: this.state.importedSettings.length })} {this.state.importedSettings.length}</div> : null}
|
||||
<span className="mainTitle">
|
||||
{this.getMessage("modals.welcome.sections.final.title")}
|
||||
</span>
|
||||
<p>{this.getMessage("modals.welcome.sections.final.description")}</p>
|
||||
<h3 className="quicktip">
|
||||
{this.getMessage("modals.welcome.sections.final.changes")}
|
||||
</h3>
|
||||
<p>
|
||||
{this.getMessage("modals.welcome.sections.final.changes_description")}
|
||||
</p>
|
||||
<div className="themesToggleArea">
|
||||
<div className="toggle" onClick={() => this.props.switchTab(1)}>
|
||||
<span>
|
||||
{this.getMessage("modals.main.settings.sections.language.title")}:{" "}
|
||||
{
|
||||
languages.find(
|
||||
(i) => i.value === localStorage.getItem("language")
|
||||
).name
|
||||
}
|
||||
</span>
|
||||
</div>
|
||||
<div className="toggle" onClick={() => this.props.switchTab(3)}>
|
||||
<span>
|
||||
{this.getMessage(
|
||||
"modals.main.settings.sections.appearance.theme.title"
|
||||
)}
|
||||
: {this.getSetting("theme")}
|
||||
</span>
|
||||
</div>
|
||||
{this.state.importedSettings.length !== 0 ? (
|
||||
<div className="toggle" onClick={() => this.props.switchTab(2)}>
|
||||
{this.getMessage("modals.main.settings.sections.final.imported", {
|
||||
amount: this.state.importedSettings.length,
|
||||
})}{" "}
|
||||
{this.state.importedSettings.length}
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
|
||||
|
||||
switch (this.props.currentTab) {
|
||||
case 1: return chooseLanguage;
|
||||
case 2: return settings;
|
||||
case 3: return theme;
|
||||
case 4: return privacy;
|
||||
case 5: return final;
|
||||
case 1:
|
||||
return chooseLanguage;
|
||||
case 2:
|
||||
return settings;
|
||||
case 3:
|
||||
return theme;
|
||||
case 4:
|
||||
return privacy;
|
||||
case 5:
|
||||
return final;
|
||||
// 0
|
||||
default: return intro;
|
||||
default:
|
||||
return intro;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
@import '../main/scss/index.scss';
|
||||
@import 'scss/variables';
|
||||
|
||||
.welcomemodal {
|
||||
position: absolute;
|
||||
|
@ -19,7 +20,9 @@
|
|||
|
||||
section:nth-child(1) {
|
||||
float: left;
|
||||
background: var(--sidebar);
|
||||
@include themed() {
|
||||
background: t($modal-sidebar);
|
||||
}
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
@ -27,15 +30,27 @@
|
|||
|
||||
section:nth-child(2) {
|
||||
float: right;
|
||||
|
||||
@include themed() {
|
||||
background: t($modal-background);
|
||||
}
|
||||
.content {
|
||||
padding: 20px;
|
||||
.mainTitle {
|
||||
font-size: 38px;
|
||||
font-weight: 600;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
}
|
||||
|
||||
.buttons {
|
||||
position: absolute;
|
||||
bottom: 2rem;
|
||||
right: 2rem;
|
||||
display: flex;
|
||||
button {
|
||||
@include modal-button(standard);
|
||||
width: 150px;
|
||||
}
|
||||
}
|
||||
|
||||
h1 {
|
||||
|
@ -78,57 +93,61 @@
|
|||
}
|
||||
|
||||
.themesToggleArea {
|
||||
.active {
|
||||
background: var(--tab-active);
|
||||
}
|
||||
|
||||
.toggle {
|
||||
background: var(--sidebar);
|
||||
text-align: center;
|
||||
border-radius: 20px;
|
||||
padding: 20px;
|
||||
margin: 10px;
|
||||
border: 3px solid var(--tab-active);
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
align-content: center;
|
||||
justify-content: center;
|
||||
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
background: var(--tab-active);
|
||||
@include themed() {
|
||||
.active {
|
||||
background: t($modal-sidebarActive);
|
||||
}
|
||||
|
||||
span {
|
||||
font-size: 1rem;
|
||||
}
|
||||
.toggle {
|
||||
background: t($modal-sidebar);
|
||||
text-align: center;
|
||||
border-radius: 20px;
|
||||
padding: 20px;
|
||||
border: 3px solid t($modal-sidebarActive);
|
||||
transition: 0.33s;
|
||||
|
||||
svg {
|
||||
font-size: 2.5em;
|
||||
}
|
||||
}
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
align-content: center;
|
||||
justify-content: center;
|
||||
|
||||
.auto {
|
||||
svg {
|
||||
font-size: 12px;
|
||||
padding-right: 5px;
|
||||
}
|
||||
}
|
||||
cursor: pointer;
|
||||
|
||||
.options {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
|
||||
.lightTheme,
|
||||
.darkTheme {
|
||||
width: 40%;
|
||||
padding: 50px;
|
||||
&:hover {
|
||||
background: t($modal-sidebarActive);
|
||||
}
|
||||
|
||||
span {
|
||||
display: block;
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
svg {
|
||||
font-size: 2.5em;
|
||||
}
|
||||
}
|
||||
|
||||
.auto {
|
||||
svg {
|
||||
font-size: 12px;
|
||||
padding-right: 5px;
|
||||
}
|
||||
}
|
||||
|
||||
.options {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
gap: 25px;
|
||||
margin-top: 25px;
|
||||
|
||||
.lightTheme,
|
||||
.darkTheme {
|
||||
width: 40%;
|
||||
padding: 50px;
|
||||
|
||||
span {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -141,13 +160,14 @@
|
|||
border: none;
|
||||
outline: none;
|
||||
padding: 50px;
|
||||
background: var(--sidebar);
|
||||
color: var(--modal-text);
|
||||
cursor: pointer;
|
||||
border: 3px solid var(--tab-active);
|
||||
|
||||
&:hover {
|
||||
background: var(--tab-active);
|
||||
@include themed() {
|
||||
background: t($modal-sidebar);
|
||||
color: t($color);
|
||||
cursor: pointer;
|
||||
border: 3px solid t($modal-sidebarActive);
|
||||
&:hover {
|
||||
background: t($modal-sidebarActive);
|
||||
}
|
||||
}
|
||||
|
||||
svg {
|
||||
|
@ -220,14 +240,14 @@ a.privacy {
|
|||
}
|
||||
}
|
||||
|
||||
@media (max-width: 1190px) {
|
||||
@media (max-width: 1190px) {
|
||||
.welcomemodal {
|
||||
width: 90%;
|
||||
height: 90%;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 800px) {
|
||||
@media (max-width: 800px) {
|
||||
.welcomemodal {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
@ -241,3 +261,14 @@ a.privacy {
|
|||
height: 140vh !important;
|
||||
}
|
||||
}
|
||||
|
||||
.createButtons {
|
||||
display: flex;
|
||||
flex-flow: row;
|
||||
justify-content: space-between;
|
||||
margin-top: 15px;
|
||||
button {
|
||||
width: 150px;
|
||||
height: 40px;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,62 +1,67 @@
|
|||
import { PureComponent, Fragment, Suspense, lazy } from 'react';
|
||||
import { PureComponent, Fragment, Suspense, lazy } from "react";
|
||||
|
||||
import Clock from './time/Clock';
|
||||
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 Message from './message/Message';
|
||||
import Clock from "./time/Clock";
|
||||
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 Message from "./message/Message";
|
||||
import Reminder from "./reminder/Reminder";
|
||||
|
||||
import EventBus from 'modules/helpers/eventbus';
|
||||
import EventBus from "modules/helpers/eventbus";
|
||||
|
||||
const Weather = lazy(() => import('./weather/Weather'));
|
||||
const Weather = lazy(() => import("./weather/Weather"));
|
||||
const renderLoader = () => <></>;
|
||||
|
||||
export default class Widgets extends PureComponent {
|
||||
online = (localStorage.getItem('offlineMode') === 'false');
|
||||
online = localStorage.getItem("offlineMode") === "false";
|
||||
constructor() {
|
||||
super();
|
||||
this.state = {
|
||||
order: JSON.parse(localStorage.getItem('order')),
|
||||
welcome: localStorage.getItem('showWelcome')
|
||||
order: JSON.parse(localStorage.getItem("order")),
|
||||
welcome: localStorage.getItem("showWelcome"),
|
||||
};
|
||||
// widgets we can re-order
|
||||
this.widgets = {
|
||||
time: this.enabled('time') ? <Clock/> : null,
|
||||
greeting: this.enabled('greeting') ? <Greeting/> : null,
|
||||
quote: this.enabled('quote') ? <Quote/> : null,
|
||||
date: this.enabled('date') ? <Date/> : null,
|
||||
quicklinks: this.enabled('quicklinksenabled') && this.online ? <QuickLinks/> : null,
|
||||
message: this.enabled('message') ? <Message/> : null
|
||||
time: this.enabled("time") ? <Clock /> : null,
|
||||
greeting: this.enabled("greeting") ? <Greeting /> : null,
|
||||
quote: this.enabled("quote") ? <Quote /> : null,
|
||||
date: this.enabled("date") ? <Date /> : null,
|
||||
quicklinks:
|
||||
this.enabled("quicklinksenabled") && this.online ? (
|
||||
<QuickLinks />
|
||||
) : null,
|
||||
message: this.enabled("message") ? <Message /> : null,
|
||||
reminder: this.enabled("reminder") ? <Reminder /> : null,
|
||||
};
|
||||
}
|
||||
|
||||
enabled(key) {
|
||||
return (localStorage.getItem(key) === 'true');
|
||||
return localStorage.getItem(key) === "true";
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
EventBus.on('refresh', (data) => {
|
||||
if (data === 'widgets') {
|
||||
EventBus.on("refresh", (data) => {
|
||||
if (data === "widgets") {
|
||||
this.setState({
|
||||
order: JSON.parse(localStorage.getItem('order'))
|
||||
order: JSON.parse(localStorage.getItem("order")),
|
||||
});
|
||||
}
|
||||
|
||||
if (data === 'widgetsWelcome') {
|
||||
if (data === "widgetsWelcome") {
|
||||
this.setState({
|
||||
welcome: localStorage.getItem('showWelcome')
|
||||
welcome: localStorage.getItem("showWelcome"),
|
||||
});
|
||||
localStorage.setItem('showWelcome', true);
|
||||
localStorage.setItem("showWelcome", true);
|
||||
window.onbeforeunload = () => {
|
||||
localStorage.clear();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
if (data === 'widgetsWelcomeDone') {
|
||||
if (data === "widgetsWelcomeDone") {
|
||||
this.setState({
|
||||
welcome: localStorage.getItem('showWelcome')
|
||||
welcome: localStorage.getItem("showWelcome"),
|
||||
});
|
||||
window.onbeforeunload = null;
|
||||
}
|
||||
|
@ -65,8 +70,8 @@ export default class Widgets extends PureComponent {
|
|||
|
||||
render() {
|
||||
// don't show when welcome is there
|
||||
if (this.state.welcome !== 'false') {
|
||||
return <div id='widgets'></div>;
|
||||
if (this.state.welcome !== "false") {
|
||||
return <div id="widgets"></div>;
|
||||
}
|
||||
|
||||
// allow for re-ordering widgets
|
||||
|
@ -74,19 +79,29 @@ export default class Widgets extends PureComponent {
|
|||
|
||||
if (this.state.order) {
|
||||
this.state.order.forEach((element) => {
|
||||
elements.push(<Fragment key={element}>{this.widgets[element]}</Fragment>);
|
||||
elements.push(
|
||||
<Fragment key={element}>{this.widgets[element]}</Fragment>
|
||||
);
|
||||
});
|
||||
} else {
|
||||
// prevent error
|
||||
elements = [<Greeting/>, <Clock/>, <QuickLinks/>, <Quote/>, <Date/>, <Message/>];
|
||||
elements = [
|
||||
<Greeting />,
|
||||
<Clock />,
|
||||
<QuickLinks />,
|
||||
<Quote />,
|
||||
<Date />,
|
||||
<Message />,
|
||||
<Reminder />,
|
||||
];
|
||||
}
|
||||
|
||||
return (
|
||||
<div id='widgets'>
|
||||
<div id="widgets">
|
||||
<Suspense fallback={renderLoader()}>
|
||||
{this.enabled('searchBar') ? <Search/> : null}
|
||||
{this.enabled("searchBar") ? <Search /> : null}
|
||||
{elements}
|
||||
{this.enabled('weatherEnabled') && this.online ? <Weather/> : null}
|
||||
{this.enabled("weatherEnabled") && this.online ? <Weather /> : null}
|
||||
</Suspense>
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -6,7 +6,12 @@ import PhotoInformation from './PhotoInformation';
|
|||
|
||||
import EventBus from 'modules/helpers/eventbus';
|
||||
import Interval from 'modules/helpers/interval';
|
||||
import { videoCheck, offlineBackground, getGradient, randomColourStyleBuilder } from 'modules/helpers/background/widget';
|
||||
import {
|
||||
videoCheck,
|
||||
offlineBackground,
|
||||
getGradient,
|
||||
randomColourStyleBuilder,
|
||||
} from 'modules/helpers/background/widget';
|
||||
|
||||
import './scss/index.scss';
|
||||
|
||||
|
@ -21,8 +26,8 @@ export default class Background extends PureComponent {
|
|||
hidden: false,
|
||||
offline: false,
|
||||
photographerURL: '',
|
||||
photoURL: ''
|
||||
}
|
||||
photoURL: '',
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -31,7 +36,11 @@ export default class Background extends PureComponent {
|
|||
|
||||
if (this.state.url !== '') {
|
||||
let url = this.state.url;
|
||||
if (localStorage.getItem('ddgProxy') === 'true' && this.state.photoInfo.offline !== true && !this.state.url.startsWith('data:')) {
|
||||
if (
|
||||
localStorage.getItem('ddgProxy') === 'true' &&
|
||||
this.state.photoInfo.offline !== true &&
|
||||
!this.state.url.startsWith('data:')
|
||||
) {
|
||||
url = variables.constants.DDG_IMAGE_PROXY + this.state.url;
|
||||
}
|
||||
|
||||
|
@ -39,8 +48,8 @@ export default class Background extends PureComponent {
|
|||
|
||||
// just set the background
|
||||
if (localStorage.getItem('bgtransition') === 'false') {
|
||||
photoInformation?.[photoInformation.style.display = 'block'];
|
||||
return backgroundImage.style.background = `url(${url})`;
|
||||
photoInformation?.[(photoInformation.style.display = 'block')];
|
||||
return (backgroundImage.style.background = `url(${url})`);
|
||||
}
|
||||
|
||||
// firstly we set the background as hidden and make sure there is no background set currently
|
||||
|
@ -50,7 +59,7 @@ export default class Background extends PureComponent {
|
|||
// same with photo information if not using custom background
|
||||
photoInformation?.classList.add('backgroundPreload');
|
||||
|
||||
// preloader for background transition, required so it loads in nice
|
||||
// preloader for background transition, required, so it loads in nice
|
||||
const preloader = document.createElement('img');
|
||||
preloader.src = url;
|
||||
|
||||
|
@ -76,17 +85,17 @@ export default class Background extends PureComponent {
|
|||
|
||||
// Main background getting function
|
||||
async getBackground() {
|
||||
let offline = (localStorage.getItem('offlineMode') === 'true');
|
||||
let offline = localStorage.getItem('offlineMode') === 'true';
|
||||
if (localStorage.getItem('showWelcome') === 'true') {
|
||||
offline = true;
|
||||
}
|
||||
|
||||
const setFavourited = ({ type, url, credit, location, camera }) => {
|
||||
console.log(type)
|
||||
if (type === 'random_colour' || type === 'random_gradient') {
|
||||
return this.setState({
|
||||
console.log(type);
|
||||
if (type === 'random_colour' || type === 'random_gradient') {
|
||||
return this.setState({
|
||||
type: 'colour',
|
||||
style: `background:${url}`
|
||||
style: `background:${url}`,
|
||||
});
|
||||
}
|
||||
this.setState({
|
||||
|
@ -94,10 +103,10 @@ export default class Background extends PureComponent {
|
|||
photoInfo: {
|
||||
credit,
|
||||
location,
|
||||
camera
|
||||
}
|
||||
camera,
|
||||
},
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const favourited = JSON.parse(localStorage.getItem('favourite'));
|
||||
if (favourited) {
|
||||
|
@ -115,7 +124,7 @@ export default class Background extends PureComponent {
|
|||
const backgroundAPI = localStorage.getItem('backgroundAPI');
|
||||
const apiCategory = localStorage.getItem('apiCategory');
|
||||
const apiQuality = localStorage.getItem('apiQuality');
|
||||
const photoMap = (localStorage.getItem('photoMap') === 'true');
|
||||
const photoMap = localStorage.getItem('photoMap') === 'true';
|
||||
|
||||
let requestURL, data;
|
||||
switch (backgroundAPI) {
|
||||
|
@ -160,8 +169,10 @@ export default class Background extends PureComponent {
|
|||
latitude: data.latitude || null,
|
||||
longitude: data.longitude || null,
|
||||
// location map token from mapbox
|
||||
maptoken: data.maptoken || null
|
||||
}
|
||||
maptoken: data.maptoken || null,
|
||||
views: data.views || null,
|
||||
downloads: data.downloads || null,
|
||||
},
|
||||
};
|
||||
|
||||
this.setState(object);
|
||||
|
@ -180,7 +191,6 @@ export default class Background extends PureComponent {
|
|||
case 'random_gradient':
|
||||
this.setState(randomColourStyleBuilder(type));
|
||||
break;
|
||||
|
||||
case 'custom':
|
||||
let customBackground = [];
|
||||
const customSaved = localStorage.getItem('customBackground');
|
||||
|
@ -202,14 +212,19 @@ export default class Background extends PureComponent {
|
|||
return this.setState(offlineBackground());
|
||||
}
|
||||
|
||||
if (customBackground !== '' && customBackground !== 'undefined' && customBackground !== [''] && customBackground !== undefined) {
|
||||
if (
|
||||
customBackground !== '' &&
|
||||
customBackground !== 'undefined' &&
|
||||
customBackground !== [''] &&
|
||||
customBackground !== undefined
|
||||
) {
|
||||
const object = {
|
||||
url: customBackground,
|
||||
type: 'custom',
|
||||
video: videoCheck(customBackground),
|
||||
photoInfo: {
|
||||
hidden: true
|
||||
}
|
||||
hidden: true,
|
||||
},
|
||||
};
|
||||
|
||||
this.setState(object);
|
||||
|
@ -237,8 +252,8 @@ export default class Background extends PureComponent {
|
|||
photoInfo: {
|
||||
hidden: false,
|
||||
credit: randomPhoto.photographer,
|
||||
location: randomPhoto.location || 'N/A'
|
||||
}
|
||||
location: randomPhoto.location || 'N/A',
|
||||
},
|
||||
});
|
||||
}
|
||||
break;
|
||||
|
@ -259,8 +274,8 @@ export default class Background extends PureComponent {
|
|||
type: '',
|
||||
video: false,
|
||||
photoInfo: {
|
||||
hidden: true
|
||||
}
|
||||
hidden: true,
|
||||
},
|
||||
});
|
||||
this.getBackground();
|
||||
};
|
||||
|
@ -279,9 +294,9 @@ export default class Background extends PureComponent {
|
|||
|
||||
// video backgrounds
|
||||
if (this.state.video === true) {
|
||||
return document.getElementById('backgroundVideo').style.display = 'none';
|
||||
return (document.getElementById('backgroundVideo').style.display = 'none');
|
||||
} else {
|
||||
return element.style.display = 'none';
|
||||
return (element.style.display = 'none');
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -304,7 +319,13 @@ export default class Background extends PureComponent {
|
|||
|
||||
if (this.state.photoInfo.offline !== true) {
|
||||
// basically check to make sure something has changed before we try getting another background
|
||||
if (backgroundType !== this.state.type || (this.state.type === 'api' && localStorage.getItem('backgroundAPI') !== this.state.currentAPI) || (this.state.type === 'custom' && localStorage.getItem('customBackground') !== this.state.url)) {
|
||||
if (
|
||||
backgroundType !== this.state.type ||
|
||||
(this.state.type === 'api' &&
|
||||
localStorage.getItem('backgroundAPI') !== this.state.currentAPI) ||
|
||||
(this.state.type === 'custom' &&
|
||||
localStorage.getItem('customBackground') !== this.state.url)
|
||||
) {
|
||||
return refresh();
|
||||
}
|
||||
} else if (backgroundType !== this.state.type) {
|
||||
|
@ -316,14 +337,38 @@ export default class Background extends PureComponent {
|
|||
const backgroundFilter = backgroundFilterSetting && backgroundFilterSetting !== 'none';
|
||||
|
||||
if (this.state.video === true) {
|
||||
document.getElementById('backgroundVideo').style.webkitFilter = `blur(${localStorage.getItem('blur')}px) brightness(${localStorage.getItem('brightness')}%) ${backgroundFilter ? backgroundFilterSetting + '(' + localStorage.getItem('backgroundFilterAmount') + '%)' : ''}`;
|
||||
document.getElementById(
|
||||
'backgroundVideo',
|
||||
).style.webkitFilter = `blur(${localStorage.getItem(
|
||||
'blur',
|
||||
)}px) brightness(${localStorage.getItem('brightness')}%) ${
|
||||
backgroundFilter
|
||||
? backgroundFilterSetting +
|
||||
'(' +
|
||||
localStorage.getItem('backgroundFilterAmount') +
|
||||
'%)'
|
||||
: ''
|
||||
}`;
|
||||
} else {
|
||||
element.style.webkitFilter = `blur(${localStorage.getItem('blur')}px) brightness(${localStorage.getItem('brightness')}%) ${backgroundFilter ? backgroundFilterSetting + '(' + localStorage.getItem('backgroundFilterAmount') + '%)' : ''}`;
|
||||
element.style.webkitFilter = `blur(${localStorage.getItem(
|
||||
'blur',
|
||||
)}px) brightness(${localStorage.getItem('brightness')}%) ${
|
||||
backgroundFilter
|
||||
? backgroundFilterSetting +
|
||||
'(' +
|
||||
localStorage.getItem('backgroundFilterAmount') +
|
||||
'%)'
|
||||
: ''
|
||||
}`;
|
||||
}
|
||||
}
|
||||
|
||||
// uninstall photo pack reverts your background to what you had previously
|
||||
if (data === 'marketplacebackgrounduninstall' || data === 'backgroundwelcome' || data === 'backgroundrefresh') {
|
||||
if (
|
||||
data === 'marketplacebackgrounduninstall' ||
|
||||
data === 'backgroundwelcome' ||
|
||||
data === 'backgroundrefresh'
|
||||
) {
|
||||
refresh();
|
||||
}
|
||||
});
|
||||
|
@ -337,16 +382,20 @@ export default class Background extends PureComponent {
|
|||
const type = localStorage.getItem('backgroundType');
|
||||
|
||||
if (type === 'api' || type === 'custom') {
|
||||
Interval(() => {
|
||||
try {
|
||||
document.getElementById('backgroundImage').classList.remove('fade-in');
|
||||
document.getElementsByClassName('photoInformation')[0].classList.remove('fade-in');
|
||||
} catch (e) {
|
||||
// Disregard exception
|
||||
}
|
||||
this.getBackground();
|
||||
}, Number(interval), 'background');
|
||||
|
||||
Interval(
|
||||
() => {
|
||||
try {
|
||||
document.getElementById('backgroundImage').classList.remove('fade-in');
|
||||
document.getElementsByClassName('photoInformation')[0].classList.remove('fade-in');
|
||||
} catch (e) {
|
||||
// Disregard exception
|
||||
}
|
||||
this.getBackground();
|
||||
},
|
||||
Number(interval),
|
||||
'background',
|
||||
);
|
||||
|
||||
try {
|
||||
// todo: refactor this mess
|
||||
const current = JSON.parse(localStorage.getItem('currentBackground'));
|
||||
|
@ -390,12 +439,22 @@ export default class Background extends PureComponent {
|
|||
render() {
|
||||
if (this.state.video === true) {
|
||||
const enabled = (setting) => {
|
||||
return (localStorage.getItem(setting) === 'true');
|
||||
return localStorage.getItem(setting) === 'true';
|
||||
};
|
||||
|
||||
return (
|
||||
<video autoPlay muted={enabled('backgroundVideoMute')} loop={enabled('backgroundVideoLoop')} style={{ WebkitFilter: `blur(${localStorage.getItem('blur')}px) brightness(${localStorage.getItem('brightness')}%)` }} id='backgroundVideo'>
|
||||
<source src={this.state.url}/>
|
||||
<video
|
||||
autoPlay
|
||||
muted={enabled('backgroundVideoMute')}
|
||||
loop={enabled('backgroundVideoLoop')}
|
||||
style={{
|
||||
WebkitFilter: `blur(${localStorage.getItem(
|
||||
'blur',
|
||||
)}px) brightness(${localStorage.getItem('brightness')}%)`,
|
||||
}}
|
||||
id="backgroundVideo"
|
||||
>
|
||||
<source src={this.state.url} />
|
||||
</video>
|
||||
);
|
||||
}
|
||||
|
@ -404,10 +463,25 @@ export default class Background extends PureComponent {
|
|||
|
||||
return (
|
||||
<>
|
||||
<div style={{ WebkitFilter: `blur(${localStorage.getItem('blur')}px) brightness(${localStorage.getItem('brightness')}%) ${backgroundFilter && backgroundFilter !== 'none' ? (backgroundFilter + '(' + localStorage.getItem('backgroundFilterAmount') + '%)') : ''}` }} id='backgroundImage'/>
|
||||
{(this.state.photoInfo.credit !== '') ?
|
||||
<PhotoInformation info={this.state.photoInfo} api={this.state.currentAPI} url={this.state.url}/>
|
||||
: null}
|
||||
<div
|
||||
style={{
|
||||
WebkitFilter: `blur(${localStorage.getItem(
|
||||
'blur',
|
||||
)}px) brightness(${localStorage.getItem('brightness')}%) ${
|
||||
backgroundFilter && backgroundFilter !== 'none'
|
||||
? backgroundFilter + '(' + localStorage.getItem('backgroundFilterAmount') + '%)'
|
||||
: ''
|
||||
}`,
|
||||
}}
|
||||
id="backgroundImage"
|
||||
/>
|
||||
{this.state.photoInfo.credit !== '' ? (
|
||||
<PhotoInformation
|
||||
info={this.state.photoInfo}
|
||||
api={this.state.currentAPI}
|
||||
url={this.state.url}
|
||||
/>
|
||||
) : null}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -3,18 +3,18 @@ import { PureComponent } from 'react';
|
|||
import { MdStar, MdStarBorder } from 'react-icons/md';
|
||||
//import Hotkeys from 'react-hot-keys';
|
||||
|
||||
import Tooltip from 'components/helpers/tooltip/Tooltip';
|
||||
|
||||
export default class Favourite extends PureComponent {
|
||||
buttons = {
|
||||
favourited: <MdStar onClick={() => this.favourite()} className='topicons' />,
|
||||
unfavourited: <MdStarBorder onClick={() => this.favourite()} className='topicons' />
|
||||
}
|
||||
favourited: <MdStar onClick={() => this.favourite()} className="topicons" />,
|
||||
unfavourited: <MdStarBorder onClick={() => this.favourite()} className="topicons" />,
|
||||
};
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.state = {
|
||||
favourited: (localStorage.getItem('favourite')) ? this.buttons.favourited : this.buttons.unfavourited
|
||||
favourited: localStorage.getItem('favourite')
|
||||
? this.buttons.favourited
|
||||
: this.buttons.unfavourited,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -22,7 +22,7 @@ export default class Favourite extends PureComponent {
|
|||
if (localStorage.getItem('favourite')) {
|
||||
localStorage.removeItem('favourite');
|
||||
this.setState({
|
||||
favourited: this.buttons.unfavourited
|
||||
favourited: this.buttons.unfavourited,
|
||||
});
|
||||
variables.stats.postEvent('feature', 'Background favourite');
|
||||
} else {
|
||||
|
@ -32,41 +32,54 @@ export default class Favourite extends PureComponent {
|
|||
return;
|
||||
case 'random_colour':
|
||||
case 'random_gradient':
|
||||
localStorage.setItem('favourite', JSON.stringify({
|
||||
type: localStorage.getItem('backgroundType'),
|
||||
url: document.getElementById('backgroundImage').style.background
|
||||
}));
|
||||
localStorage.setItem(
|
||||
'favourite',
|
||||
JSON.stringify({
|
||||
type: localStorage.getItem('backgroundType'),
|
||||
url: document.getElementById('backgroundImage').style.background,
|
||||
}),
|
||||
);
|
||||
break;
|
||||
default:
|
||||
const url = document.getElementById('backgroundImage').style.backgroundImage.replace('url("', '').replace('")', '').replace(variables.constants.DDG_IMAGE_PROXY, '');
|
||||
const url = document
|
||||
.getElementById('backgroundImage')
|
||||
.style.backgroundImage.replace('url("', '')
|
||||
.replace('")', '')
|
||||
.replace(variables.constants.DDG_IMAGE_PROXY, '');
|
||||
|
||||
if (!url) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (type === 'custom') {
|
||||
localStorage.setItem('favourite', JSON.stringify({
|
||||
type,
|
||||
url
|
||||
}));
|
||||
localStorage.setItem(
|
||||
'favourite',
|
||||
JSON.stringify({
|
||||
type,
|
||||
url,
|
||||
}),
|
||||
);
|
||||
} else {
|
||||
// photo information now hides information if it isn't sent, unless if photoinformation hover is hidden
|
||||
const location = document.getElementById('infoLocation');
|
||||
const camera = document.getElementById('infoCamera');
|
||||
|
||||
localStorage.setItem('favourite', JSON.stringify({
|
||||
type,
|
||||
url,
|
||||
credit: document.getElementById('credit').textContent || '',
|
||||
location: location ? location.innerText : 'N/A',
|
||||
camera: camera ? camera.innerText : 'N/A',
|
||||
resolution: document.getElementById('infoResolution').textContent || '',
|
||||
}));
|
||||
|
||||
localStorage.setItem(
|
||||
'favourite',
|
||||
JSON.stringify({
|
||||
type,
|
||||
url,
|
||||
credit: document.getElementById('credit').textContent || '',
|
||||
location: location ? location.innerText : 'N/A',
|
||||
camera: camera ? camera.innerText : 'N/A',
|
||||
resolution: document.getElementById('infoResolution').textContent || '',
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
this.setState({
|
||||
favourited: this.buttons.favourited
|
||||
favourited: this.buttons.favourited,
|
||||
});
|
||||
variables.stats.postEvent('feature', 'Background unfavourite');
|
||||
}
|
||||
|
@ -79,10 +92,10 @@ export default class Favourite extends PureComponent {
|
|||
}
|
||||
|
||||
return (
|
||||
<Tooltip title={variables.language.getMessage(variables.languagecode, 'modals.main.settings.sections.background.buttons.favourite')}>
|
||||
<>
|
||||
{this.state.favourited}
|
||||
{/*variables.keybinds.favouriteBackground && variables.keybinds.favouriteBackground !== '' ? <Hotkeys keyName={variables.keybinds.favouriteBackground} onKeyDown={() => this.favourite()} /> : null*/}
|
||||
</Tooltip>
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,14 +9,18 @@ export default class Maximise extends PureComponent {
|
|||
constructor() {
|
||||
super();
|
||||
this.state = {
|
||||
hidden: false
|
||||
hidden: false,
|
||||
};
|
||||
}
|
||||
|
||||
setAttribute(blur, brightness, filter) {
|
||||
// don't attempt to modify the background if it isn't an image
|
||||
const backgroundType = localStorage.getItem('backgroundType');
|
||||
if (backgroundType === 'colour' || backgroundType === 'random_colour' || backgroundType === 'random_gradient') {
|
||||
if (
|
||||
backgroundType === 'colour' ||
|
||||
backgroundType === 'random_colour' ||
|
||||
backgroundType === 'random_gradient'
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -29,36 +33,51 @@ export default class Maximise extends PureComponent {
|
|||
|
||||
element.setAttribute(
|
||||
'style',
|
||||
`background-image: url(${element.style.backgroundImage.replace('url("', '').replace('")', '')}); -webkit-filter: blur(${blur}px) brightness(${brightness}%) ${backgroundFilter ? backgroundFilter + '(' + localStorage.getItem('backgroundFilterAmount') + '%)' : ''};`
|
||||
`background-image: url(${element.style.backgroundImage
|
||||
.replace('url("', '')
|
||||
.replace('")', '')}); -webkit-filter: blur(${blur}px) brightness(${brightness}%) ${
|
||||
backgroundFilter
|
||||
? backgroundFilter + '(' + localStorage.getItem('backgroundFilterAmount') + '%)'
|
||||
: ''
|
||||
};`,
|
||||
);
|
||||
}
|
||||
|
||||
maximise = () => {
|
||||
// hide widgets
|
||||
const widgets = document.getElementById('widgets');
|
||||
(this.state.hidden === false) ? widgets.style.display = 'none' : widgets.style.display = 'block';
|
||||
this.state.hidden === false
|
||||
? (widgets.style.display = 'none')
|
||||
: (widgets.style.display = 'flex');
|
||||
|
||||
if (this.state.hidden === false) {
|
||||
this.setState({
|
||||
hidden: true
|
||||
hidden: true,
|
||||
});
|
||||
|
||||
this.setAttribute(0, 100);
|
||||
variables.stats.postEvent('feature', 'Background maximise');
|
||||
} else {
|
||||
this.setState({
|
||||
hidden: false
|
||||
hidden: false,
|
||||
});
|
||||
|
||||
this.setAttribute(localStorage.getItem('blur'), localStorage.getItem('brightness'), true);
|
||||
variables.stats.postEvent('feature', 'Background unmaximise');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
render() {
|
||||
return (
|
||||
<Tooltip title={variables.language.getMessage(variables.languagecode, 'modals.main.settings.sections.background.buttons.view')}>
|
||||
<MdCropFree onClick={this.maximise} className='topicons' />
|
||||
<Tooltip
|
||||
title={variables.language.getMessage(
|
||||
variables.languagecode,
|
||||
'modals.main.settings.sections.background.buttons.view',
|
||||
)}
|
||||
>
|
||||
<button>
|
||||
<MdCropFree onClick={this.maximise} className="topicons" />
|
||||
</button>
|
||||
{/*variables.keybinds.maximiseBackground && variables.keybinds.maximiseBackground !== '' ? <Hotkeys keyName={variables.keybinds.maximiseBackground} onKeyDown={this.maximise} /> : null*/}
|
||||
</Tooltip>
|
||||
);
|
||||
|
|
|
@ -1,14 +1,20 @@
|
|||
import variables from 'modules/variables';
|
||||
import { useState, Fragment } from 'react';
|
||||
import Favourite from './Favourite';
|
||||
import {
|
||||
MdInfo,
|
||||
MdLocationOn,
|
||||
MdPhotoCamera,
|
||||
MdCrop as Resolution,
|
||||
MdPerson as Photographer,
|
||||
MdGetApp as Download
|
||||
MdGetApp as Download,
|
||||
MdVisibility as Views,
|
||||
MdIosShare as Share,
|
||||
} from 'react-icons/md';
|
||||
import Tooltip from '../../helpers/tooltip/Tooltip';
|
||||
import ShareModal from '../../helpers/sharemodal/ShareModal';
|
||||
//import Hotkeys from 'react-hot-keys';
|
||||
import { toast } from 'react-toastify';
|
||||
|
||||
const toDataURL = async (url) => {
|
||||
const res = await fetch(url);
|
||||
|
@ -29,17 +35,31 @@ const downloadImage = async (info) => {
|
|||
variables.stats.postEvent('feature', 'Background download');
|
||||
};
|
||||
|
||||
// todo: copy link to unsplash/pexels page not image url
|
||||
const copyImage = (info) => {
|
||||
variables.stats.postEvent('feature', 'Background copied');
|
||||
navigator.clipboard.writeText(info.url);
|
||||
toast('Background copied');
|
||||
};
|
||||
|
||||
export default function PhotoInformation({ info, url, api }) {
|
||||
const [width, setWidth] = useState(0);
|
||||
const [height, setHeight] = useState(0);
|
||||
const [usePhotoMap, setPhotoMap] = useState(false);
|
||||
const [setMapIcon] = useState(true);
|
||||
const [showExtraInfo, setshowExtraInfo] = useState(false);
|
||||
const [showOld, setShowOld] = useState(true);
|
||||
const [other, setOther] = useState(false);
|
||||
|
||||
if (info.hidden === true || !info.credit) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// remove unsplash and pexels text
|
||||
const unsplash = variables.language.getMessage(variables.languagecode, 'widgets.background.unsplash');
|
||||
const unsplash = variables.language.getMessage(
|
||||
variables.languagecode,
|
||||
'widgets.background.unsplash',
|
||||
);
|
||||
const pexels = variables.language.getMessage(variables.languagecode, 'widgets.background.pexels');
|
||||
const photographer = info.credit.split(` ${unsplash}`)[0].split(` ${pexels}`);
|
||||
|
||||
|
@ -49,15 +69,41 @@ export default function PhotoInformation({ info, url, api }) {
|
|||
// unsplash and pexels credit
|
||||
if (info.photographerURL && info.photographerURL !== '' && !info.offline && api) {
|
||||
if (api === 'unsplash') {
|
||||
photo = <a href={info.photoURL + '?utm_source=mue'} target='_blank' rel='noopener noreferrer'>{photo}</a>;
|
||||
credit = <><a href={info.photographerURL} target='_blank' rel='noopener noreferrer'>{info.credit}</a> <a href='https://unsplash.com?utm_source=mue' target='_blank' rel='noopener noreferrer'>{unsplash}</a></>;
|
||||
photo = (
|
||||
<a href={info.photoURL + '?utm_source=mue'} target="_blank" rel="noopener noreferrer">
|
||||
{photo}
|
||||
</a>
|
||||
);
|
||||
credit = (
|
||||
<>
|
||||
<a href={info.photographerURL} target="_blank" rel="noopener noreferrer">
|
||||
{info.credit}
|
||||
</a>{' '}
|
||||
<a href="https://unsplash.com?utm_source=mue" target="_blank" rel="noopener noreferrer">
|
||||
{unsplash}
|
||||
</a>
|
||||
</>
|
||||
);
|
||||
} else {
|
||||
photo = <a href={info.photoURL} target='_blank' rel='noopener noreferrer'>{photo}</a>;
|
||||
credit = <><a href={info.photographerURL} target='_blank' rel='noopener noreferrer'>{info.credit}</a> <a href='https://pexels.com' target='_blank' rel='noopener noreferrer'>{pexels}</a></>;
|
||||
photo = (
|
||||
<a href={info.photoURL} target="_blank" rel="noopener noreferrer">
|
||||
{photo}
|
||||
</a>
|
||||
);
|
||||
credit = (
|
||||
<>
|
||||
<a href={info.photographerURL} target="_blank" rel="noopener noreferrer">
|
||||
{info.credit}
|
||||
</a>{' '}
|
||||
<a href="https://pexels.com" target="_blank" rel="noopener noreferrer">
|
||||
{pexels}
|
||||
</a>
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const ddgProxy = (localStorage.getItem('ddgProxy') === 'true');
|
||||
const ddgProxy = localStorage.getItem('ddgProxy') === 'true';
|
||||
|
||||
// get resolution
|
||||
const img = new Image();
|
||||
|
@ -65,24 +111,32 @@ export default function PhotoInformation({ info, url, api }) {
|
|||
setWidth(event.target.width);
|
||||
setHeight(event.target.height);
|
||||
};
|
||||
img.src = (ddgProxy && !info.offline && !url.startsWith('data:')) ? variables.constants.DDG_IMAGE_PROXY + url : url;
|
||||
img.src =
|
||||
ddgProxy && !info.offline && !url.startsWith('data:')
|
||||
? variables.constants.DDG_IMAGE_PROXY + url
|
||||
: url;
|
||||
|
||||
// info is still there because we want the favourite button to work
|
||||
if (localStorage.getItem('photoInformation') === 'false') {
|
||||
return (
|
||||
<div className='photoInformation'>
|
||||
<h1>{photo} <span id='credit'>{credit}</span></h1>
|
||||
<div className="photoInformation">
|
||||
<h1>
|
||||
{photo} <span id="credit">{credit}</span>
|
||||
</h1>
|
||||
<div style={{ display: 'none' }}>
|
||||
<span id='infoLocation'>{info.location || 'N/A'}</span>
|
||||
<span id='infoCamera'>{info.camera || 'N/A'}</span>
|
||||
<span id='infoResolution'>{width}x{height}</span>
|
||||
<span id="infoLocation">{info.location || 'N/A'}</span>
|
||||
<span id="infoCamera">{info.camera || 'N/A'}</span>
|
||||
<span id="infoResolution">
|
||||
{width}x{height}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
const downloadEnabled = (localStorage.getItem('downloadbtn') === 'true') && !info.offline && !info.photographerURL && api;
|
||||
const downloadBackground = () => {
|
||||
const downloadEnabled =
|
||||
localStorage.getItem('downloadbtn') === 'true' && !info.offline && !info.photographerURL && api;
|
||||
const downloadBackground = () => {
|
||||
if (downloadEnabled) {
|
||||
downloadImage(info);
|
||||
}
|
||||
|
@ -99,66 +153,181 @@ export default function PhotoInformation({ info, url, api }) {
|
|||
}
|
||||
};
|
||||
|
||||
let showingPhotoMap = false;
|
||||
const photoMap = () => {
|
||||
if (localStorage.getItem('photoMap') !== 'true' || !info.latitude || !info.longitude || usePhotoMap === false) {
|
||||
if (
|
||||
localStorage.getItem('photoMap') !== 'true' ||
|
||||
!info.latitude ||
|
||||
!info.longitude ||
|
||||
usePhotoMap === false
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const zoom = 12;
|
||||
const tile = `${variables.constants.MAPBOX_URL}/styles/v1/mapbox/streets-v11/static/pin-s+555555(${info.longitude},${info.latitude})/${info.longitude},${info.latitude},${zoom},0/300x100?access_token=${info.maptoken}`;
|
||||
showingPhotoMap = true;
|
||||
|
||||
return (
|
||||
<Fragment key='photomap'>
|
||||
<a href={`${variables.constants.OPENSTREETMAP_URL}/?mlat=${info.latitude}&mlon=${info.longitude}`} target='_blank' rel='noopener noreferrer'>
|
||||
<img className='locationMap' src={tile} alt='location' draggable={false}/>
|
||||
<Fragment key="photomap">
|
||||
<a
|
||||
href={`${variables.constants.OPENSTREETMAP_URL}/?mlat=${info.latitude}&mlon=${info.longitude}`}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
<img className="locationMap" src={tile} alt="location" draggable={false} />
|
||||
</a>
|
||||
<br/>
|
||||
<span className='mapCopyright'>
|
||||
<a href='https://www.mapbox.com/about/maps/' target='_blank' rel='noopener noreferrer'> © Mapbox</a>, <a href='https://www.openstreetmap.org/about/' target='_blank' rel='noopener noreferrer'>© OpenStreetMap</a>. <a href='https://www.mapbox.com/map-feedback/' target='_blank' rel='noopener noreferrer'>Improve this map</a>.
|
||||
</span>
|
||||
<br />
|
||||
</Fragment>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
// only request map image if the user looks at the photo information
|
||||
// this is to reduce requests to the api
|
||||
try {
|
||||
document.getElementsByClassName('photoInformation')[0].onmouseover = () => {
|
||||
setPhotoMap(true);
|
||||
}
|
||||
try {
|
||||
setPhotoMap(true);
|
||||
setMapIcon(false);
|
||||
} catch (e) {}
|
||||
};
|
||||
} catch (e) {}
|
||||
|
||||
return (
|
||||
<div className='photoInformation'>
|
||||
<h1>{photo} <span id='credit'>{credit}</span></h1>
|
||||
<MdInfo className='photoInformationHover'/>
|
||||
<div className='infoCard'>
|
||||
<MdInfo className='infoIcon'/>
|
||||
<h1>{variables.language.getMessage(variables.languagecode, 'widgets.background.information')}</h1>
|
||||
<hr/>
|
||||
{photoMap()}
|
||||
{/* fix console error by using fragment and key */}
|
||||
{info.location && info.location !== 'N/A' ? <Fragment key='location'>
|
||||
<MdLocationOn/>
|
||||
<span id='infoLocation'>{info.location}</span>
|
||||
</Fragment> : null}
|
||||
{info.camera && info.camera !== 'N/A' ? <Fragment key='camera'>
|
||||
<MdPhotoCamera/>
|
||||
<span id='infoCamera'>{info.camera}</span>
|
||||
</Fragment> : null}
|
||||
<Resolution/>
|
||||
<span id='infoResolution'>{width}x{height}</span>
|
||||
<Photographer/>
|
||||
<span>{photographer}</span>
|
||||
{downloadEnabled ?
|
||||
<>
|
||||
<Download/>
|
||||
<span className='download' onClick={() => downloadImage(info)}>{variables.language.getMessage(variables.languagecode, 'widgets.background.download')}</span>
|
||||
</>
|
||||
: null}
|
||||
</div>
|
||||
{/*variables.keybinds.downloadBackground && variables.keybinds.downloadBackground !== '' ? <Hotkeys keyName={variables.keybinds.downloadBackground} onKeyDown={() => downloadBackground()} /> : null*/}
|
||||
{/*variables.keybinds.showBackgroundInformation && variables.keybinds.showBackgroundInformation !== '' ? <Hotkeys keyName={variables.keybinds.showBackgroundInformation} onKeyDown={() => showBackgroundInformation()} /> : null*/}
|
||||
<div
|
||||
className="photoInformationHolder"
|
||||
onMouseEnter={() => setOther(true)}
|
||||
onMouseLeave={() => setOther(false)}
|
||||
>
|
||||
{localStorage.getItem('widgetStyle') === 'legacy' && (
|
||||
<div className="photoInformation-legacy">
|
||||
<MdInfo />
|
||||
<span className="title">
|
||||
{photo} <span id="credit">{credit}</span>
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
{localStorage.getItem('widgetStyle') !== 'legacy' || other ? (
|
||||
<div
|
||||
className="photoInformation orHover"
|
||||
onMouseEnter={() => setshowExtraInfo(true)}
|
||||
onMouseLeave={() => setshowExtraInfo(false)}
|
||||
>
|
||||
<div className="map-concept">
|
||||
<MdLocationOn />
|
||||
{photoMap()}
|
||||
</div>
|
||||
{showingPhotoMap ? (
|
||||
<div className="concept-copyright">
|
||||
<a
|
||||
href="https://www.mapbox.com/about/maps/"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
{' '}
|
||||
© Mapbox{' '}
|
||||
</a>{' '}
|
||||
•{' '}
|
||||
<a
|
||||
href="https://www.openstreetmap.org/about/"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
{' '}
|
||||
© OpenStreetMap{' '}
|
||||
</a>{' '}
|
||||
•{' '}
|
||||
<a
|
||||
href="https://www.mapbox.com/map-feedback/"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
{' '}
|
||||
Improve this map{' '}
|
||||
</a>
|
||||
</div>
|
||||
) : null}
|
||||
<div className="photoInformation-content">
|
||||
<span className="title">{info.location}</span>
|
||||
<span className="subtitle" id="credit">
|
||||
{credit}
|
||||
</span>
|
||||
{info.views && info.downloads !== null ? (
|
||||
<div className="concept-stats">
|
||||
<div>
|
||||
<Views />
|
||||
<span>{info.views.toLocaleString()}</span>
|
||||
</div>
|
||||
<div>
|
||||
<Download />
|
||||
<span>{info.downloads.toLocaleString()}</span>
|
||||
</div>
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
|
||||
{showExtraInfo || other ? (
|
||||
<>
|
||||
<div className="concept-buttons">
|
||||
<Tooltip title="Share" key="other">
|
||||
<Share onClick={() => copyImage(info)} />
|
||||
</Tooltip>
|
||||
<Tooltip title="Favourite" key="other">
|
||||
<Favourite />
|
||||
</Tooltip>
|
||||
<Tooltip title="Download" key="other">
|
||||
<Download onClick={() => downloadImage(info)} />
|
||||
</Tooltip>
|
||||
</div>
|
||||
<div className="extra-content">
|
||||
<span className="subtitle">
|
||||
{variables.language.getMessage(
|
||||
variables.languagecode,
|
||||
'widgets.background.information',
|
||||
)}
|
||||
</span>
|
||||
{info.location && info.location !== 'N/A' ? (
|
||||
<Fragment key="location">
|
||||
<div className="concept-row">
|
||||
<MdLocationOn />
|
||||
<span id="infoLocation">{info.location}</span>
|
||||
</div>
|
||||
</Fragment>
|
||||
) : null}
|
||||
{info.camera && info.camera !== 'N/A' ? (
|
||||
<Fragment key="camera">
|
||||
<div className="concept-row">
|
||||
<MdPhotoCamera />
|
||||
<span id="infoCamera">{info.camera}</span>
|
||||
</div>
|
||||
</Fragment>
|
||||
) : null}
|
||||
<div className="concept-row">
|
||||
<Resolution />
|
||||
<span id="infoResolution">
|
||||
{width}x{height}
|
||||
</span>
|
||||
</div>
|
||||
<div className="concept-row">
|
||||
<Photographer />
|
||||
<span>{photographer}</span>
|
||||
</div>
|
||||
{downloadEnabled ? (
|
||||
<>
|
||||
<Download />
|
||||
<span className="download" onClick={() => downloadImage(info)}>
|
||||
{variables.language.getMessage(
|
||||
variables.languagecode,
|
||||
'widgets.background.download',
|
||||
)}
|
||||
</span>
|
||||
</>
|
||||
) : null}
|
||||
</div>
|
||||
</>
|
||||
) : null}
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,26 +1,86 @@
|
|||
.photoInformation {
|
||||
@import 'scss/variables';
|
||||
|
||||
.photoInformationHolder {
|
||||
position: absolute;
|
||||
bottom: 1rem;
|
||||
left: 1rem;
|
||||
font-size: calc(10px + 0.1vmin) !important;
|
||||
flex-flow: column-reverse;
|
||||
display: flex;
|
||||
&:hover {
|
||||
.photoInformation {
|
||||
height: auto;
|
||||
align-items: flex-start;
|
||||
flex-flow: column;
|
||||
.concept-buttons {
|
||||
padding: 0 0 20px;
|
||||
display: flex;
|
||||
}
|
||||
.extra-content {
|
||||
display: flex;
|
||||
flex-flow: column;
|
||||
gap: 10px;
|
||||
transition: 0.8s;
|
||||
}
|
||||
.concept-stats {
|
||||
display: flex;
|
||||
gap: 15px;
|
||||
@include themed() {
|
||||
color: t($subColor);
|
||||
}
|
||||
div {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
align-content: center;
|
||||
flex-direction: row;
|
||||
gap: 10px;
|
||||
svg {
|
||||
font-size: 1em;
|
||||
}
|
||||
}
|
||||
}
|
||||
.concept-copyright {
|
||||
display: flex;
|
||||
margin-top: 10px;
|
||||
gap: 10px;
|
||||
a {
|
||||
text-decoration: none;
|
||||
@include themed() {
|
||||
color: t($subColor);
|
||||
}
|
||||
}
|
||||
}
|
||||
.photoInformation-content {
|
||||
padding-left: 0;
|
||||
}
|
||||
.map-concept {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.photoInformation-legacy {
|
||||
font-size: 1.36em;
|
||||
text-shadow: 0 0 10px rgba(0, 0, 0, 0.3);
|
||||
color: #fff;
|
||||
z-index: 99;
|
||||
user-select: none;
|
||||
cursor: initial;
|
||||
font-weight: bolder;
|
||||
|
||||
svg {
|
||||
float: left;
|
||||
margin-right: 1rem;
|
||||
font-size: calc(10px + 2vmin);
|
||||
cursor: pointer;
|
||||
font-size: 1.36em;
|
||||
}
|
||||
|
||||
svg,
|
||||
h1 {
|
||||
display: inline;
|
||||
&:hover .infoCard {
|
||||
display: block !important;
|
||||
}
|
||||
|
||||
svg:hover+.infoCard {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 15px;
|
||||
|
||||
svg:hover + .infoCard {
|
||||
display: block;
|
||||
}
|
||||
|
||||
|
@ -78,7 +138,7 @@
|
|||
}
|
||||
|
||||
h1,
|
||||
svg {
|
||||
.MuiSvgIcon-root {
|
||||
user-select: none;
|
||||
cursor: initial;
|
||||
}
|
||||
|
@ -117,3 +177,152 @@
|
|||
font-size: 0.9em;
|
||||
}
|
||||
}
|
||||
|
||||
.photoInformation {
|
||||
@extend %basic;
|
||||
font-size: 0.8em;
|
||||
font-weight: 300;
|
||||
z-index: 99;
|
||||
padding: 20px;
|
||||
display: flex;
|
||||
flex-flow: row;
|
||||
align-items: center;
|
||||
transition: 0.8s cubic-bezier(0.075, 0.82, 0.165, 1);
|
||||
width: 380px;
|
||||
&:hover {
|
||||
height: auto;
|
||||
align-items: flex-start;
|
||||
flex-flow: column;
|
||||
.concept-buttons {
|
||||
padding: 0 0 20px;
|
||||
display: flex;
|
||||
}
|
||||
.extra-content {
|
||||
display: flex;
|
||||
flex-flow: column;
|
||||
gap: 10px;
|
||||
transition: 0.8s;
|
||||
}
|
||||
.concept-stats {
|
||||
display: flex;
|
||||
gap: 15px;
|
||||
@include themed() {
|
||||
color: t($subColor);
|
||||
}
|
||||
div {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
align-content: center;
|
||||
flex-direction: row;
|
||||
gap: 10px;
|
||||
svg {
|
||||
font-size: 1em;
|
||||
}
|
||||
}
|
||||
}
|
||||
.concept-copyright {
|
||||
display: flex;
|
||||
margin-top: 10px;
|
||||
gap: 10px;
|
||||
a {
|
||||
text-decoration: none;
|
||||
@include themed() {
|
||||
color: t($subColor);
|
||||
}
|
||||
}
|
||||
}
|
||||
.photoInformation-content {
|
||||
padding-left: 0;
|
||||
}
|
||||
.map-concept {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
.map-concept {
|
||||
@extend %basic;
|
||||
height: 80px;
|
||||
width: 80px;
|
||||
border-radius: 12px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border: none !important;
|
||||
svg {
|
||||
font-size: 25px;
|
||||
}
|
||||
img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-repeat: no-repeat;
|
||||
background-size: cover;
|
||||
object-fit: cover;
|
||||
border-radius: 12px;
|
||||
}
|
||||
}
|
||||
.concept-location {
|
||||
font-size: 1.9em;
|
||||
}
|
||||
.concept-credit {
|
||||
font-size: 1.4em;
|
||||
@include themed() {
|
||||
color: t($subColor);
|
||||
}
|
||||
a {
|
||||
@include themed() {
|
||||
color: t($subColor);
|
||||
}
|
||||
&:nth-child(2) {
|
||||
color: var(--modal-link);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.photoInformation-content {
|
||||
display: flex;
|
||||
flex-flow: column;
|
||||
padding: 20px;
|
||||
a {
|
||||
color: #5352ed;
|
||||
text-decoration: none;
|
||||
&:hover {
|
||||
opacity: 0.9;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.extra-content {
|
||||
display: none;
|
||||
flex-flow: column;
|
||||
width: 100%;
|
||||
transition: 1s;
|
||||
.concept-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 20px;
|
||||
svg {
|
||||
@include themed() {
|
||||
color: t($subColor);
|
||||
font-size: 18px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.concept-copyright {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.concept-stats {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.concept-buttons {
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
padding: 20px 20px 20px 0;
|
||||
display: none;
|
||||
svg {
|
||||
@include basicIconButton(11px, 1.3rem, ui);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
@import 'photoinformation';
|
||||
@import '../../../../scss/mixins';
|
||||
@import 'scss/mixins';
|
||||
|
||||
#backgroundImage {
|
||||
height: 100vh;
|
||||
|
|
|
@ -10,7 +10,7 @@ export default class Greeting extends PureComponent {
|
|||
constructor() {
|
||||
super();
|
||||
this.state = {
|
||||
greeting: ''
|
||||
greeting: '',
|
||||
};
|
||||
this.timer = undefined;
|
||||
this.greeting = createRef();
|
||||
|
@ -28,10 +28,10 @@ export default class Greeting extends PureComponent {
|
|||
// If it's December 25th, set the greeting string to "Merry Christmas"
|
||||
if (month === 11 && date === 25) {
|
||||
message = variables.language.getMessage(variables.languagecode, 'widgets.greeting.christmas');
|
||||
// If the date is January 1st, set the greeting string to "Happy new year"
|
||||
// If the date is January 1st, set the greeting string to "Happy new year"
|
||||
} else if (month === 0 && date === 1) {
|
||||
message = variables.language.getMessage(variables.languagecode, 'widgets.greeting.newyear');
|
||||
// If it's October 31st, set the greeting string to "Happy Halloween"
|
||||
// If it's October 31st, set the greeting string to "Happy Halloween"
|
||||
} else if (month === 9 && date === 31) {
|
||||
message = variables.language.getMessage(variables.languagecode, 'widgets.greeting.halloween');
|
||||
}
|
||||
|
@ -45,7 +45,7 @@ export default class Greeting extends PureComponent {
|
|||
return Math.abs(birthday.getUTCFullYear() - 1970);
|
||||
}
|
||||
|
||||
getGreeting(time = (60000 - Date.now() % 60000)) {
|
||||
getGreeting(time = 60000 - (Date.now() % 60000)) {
|
||||
this.timer = setTimeout(() => {
|
||||
let now = new Date();
|
||||
const timezone = localStorage.getItem('timezone');
|
||||
|
@ -56,13 +56,19 @@ export default class Greeting extends PureComponent {
|
|||
const hour = now.getHours();
|
||||
|
||||
// Set the default greeting string to "Good evening"
|
||||
let message = variables.language.getMessage(variables.languagecode, 'widgets.greeting.evening');
|
||||
let message = variables.language.getMessage(
|
||||
variables.languagecode,
|
||||
'widgets.greeting.evening',
|
||||
);
|
||||
// If it's before 12am, set the greeting string to "Good morning"
|
||||
if (hour < 12) {
|
||||
message = variables.language.getMessage(variables.languagecode, 'widgets.greeting.morning');
|
||||
// If it's before 6pm, set the greeting string to "Good afternoon"
|
||||
// If it's before 6pm, set the greeting string to "Good afternoon"
|
||||
} else if (hour < 18) {
|
||||
message = variables.language.getMessage(variables.languagecode, 'widgets.greeting.afternoon');
|
||||
message = variables.language.getMessage(
|
||||
variables.languagecode,
|
||||
'widgets.greeting.afternoon',
|
||||
);
|
||||
}
|
||||
|
||||
// Events and custom
|
||||
|
@ -95,19 +101,24 @@ export default class Greeting extends PureComponent {
|
|||
|
||||
if (birth.getDate() === now.getDate() && birth.getMonth() === now.getMonth()) {
|
||||
if (localStorage.getItem('birthdayage') === 'true') {
|
||||
const text = variables.language.getMessage(variables.languagecode, 'widgets.greeting.birthday').split(' ');
|
||||
const text = variables.language
|
||||
.getMessage(variables.languagecode, 'widgets.greeting.birthday')
|
||||
.split(' ');
|
||||
message = `${text[0]} ${nth(this.calculateAge(birth))} ${text[1]}`;
|
||||
} else {
|
||||
message = variables.language.getMessage(variables.languagecode, 'widgets.greeting.birthday');
|
||||
message = variables.language.getMessage(
|
||||
variables.languagecode,
|
||||
'widgets.greeting.birthday',
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Set the state to the greeting string
|
||||
this.setState({
|
||||
greeting: `${message}${name}`
|
||||
greeting: `${message}${name}`,
|
||||
});
|
||||
|
||||
|
||||
this.getGreeting();
|
||||
}, time);
|
||||
}
|
||||
|
@ -116,20 +127,24 @@ export default class Greeting extends PureComponent {
|
|||
EventBus.on('refresh', (data) => {
|
||||
if (data === 'greeting' || data === 'timezone') {
|
||||
if (localStorage.getItem('greeting') === 'false') {
|
||||
return this.greeting.current.style.display = 'none';
|
||||
return (this.greeting.current.style.display = 'none');
|
||||
}
|
||||
|
||||
this.timer = null;
|
||||
this.getGreeting(0);
|
||||
|
||||
this.greeting.current.style.display = 'block';
|
||||
this.greeting.current.style.fontSize = `${1.6 * Number((localStorage.getItem('zoomGreeting') || 100) / 100)}em`;
|
||||
this.greeting.current.style.fontSize = `${
|
||||
1.6 * Number((localStorage.getItem('zoomGreeting') || 100) / 100)
|
||||
}em`;
|
||||
}
|
||||
});
|
||||
|
||||
// this comment can apply to all widget zoom features apart from the general one in the Accessibility section
|
||||
// in a nutshell: 1.6 is the current font size and we do "localstorage || 100" so we don't have to try that 4.0 -> 5.0 thing again
|
||||
this.greeting.current.style.fontSize = `${1.6 * Number((localStorage.getItem('zoomGreeting') || 100) / 100)}em`;
|
||||
// in a nutshell: 1.6 is the current font size, and we do "localstorage || 100" so we don't have to try that 4.0 -> 5.0 thing again
|
||||
this.greeting.current.style.fontSize = `${
|
||||
1.6 * Number((localStorage.getItem('zoomGreeting') || 100) / 100)
|
||||
}em`;
|
||||
|
||||
this.getGreeting(0);
|
||||
}
|
||||
|
@ -140,9 +155,9 @@ export default class Greeting extends PureComponent {
|
|||
|
||||
render() {
|
||||
return (
|
||||
<h1 className='greeting' ref={this.greeting}>
|
||||
<span className="greeting" ref={this.greeting}>
|
||||
{this.state.greeting}
|
||||
</h1>
|
||||
</span>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
font-size: 1.6em;
|
||||
cursor: initial;
|
||||
user-select: none;
|
||||
font-weight: 600;
|
||||
|
||||
--shadow-shift: 0.2rem;
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@ export default class Message extends PureComponent {
|
|||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
messageText: ''
|
||||
messageText: '',
|
||||
};
|
||||
this.message = createRef();
|
||||
}
|
||||
|
@ -17,24 +17,28 @@ export default class Message extends PureComponent {
|
|||
EventBus.on('refresh', (data) => {
|
||||
if (data === 'message') {
|
||||
if (localStorage.getItem('message') === 'false') {
|
||||
return this.message.current.style.display = 'none';
|
||||
return (this.message.current.style.display = 'none');
|
||||
}
|
||||
|
||||
this.message.current.style.display = 'block';
|
||||
this.message.current.style.fontSize = `${1.6 * Number((localStorage.getItem('zoomMessage') || 100) / 100)}em`;
|
||||
this.message.current.style.fontSize = `${
|
||||
1.6 * Number((localStorage.getItem('zoomMessage') || 100) / 100)
|
||||
}em`;
|
||||
}
|
||||
});
|
||||
|
||||
this.message.current.style.fontSize = `${1.6 * Number((localStorage.getItem('zoomMessage') || 100) / 100)}em`;
|
||||
this.message.current.style.fontSize = `${
|
||||
1.6 * Number((localStorage.getItem('zoomMessage') || 100) / 100)
|
||||
}em`;
|
||||
const messages = JSON.parse(localStorage.getItem('messages')) || [];
|
||||
this.setState({
|
||||
messageText: messages[Math.floor(Math.random() * messages.length)]
|
||||
messageText: messages[Math.floor(Math.random() * messages.length)],
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<h2 className='message' ref={this.message}>
|
||||
<h2 className="message" ref={this.message}>
|
||||
{this.state.messageText.split('\\n').map((item, i) => (
|
||||
<span key={i}>
|
||||
{item}
|
||||
|
|
|
@ -3,19 +3,25 @@ import { PureComponent, createRef } from 'react';
|
|||
import { MdRefresh, MdSettings, MdAssignment } from 'react-icons/md';
|
||||
|
||||
import Notes from './Notes';
|
||||
import Todo from './Todo';
|
||||
import Maximise from '../background/Maximise';
|
||||
import Favourite from '../background/Favourite';
|
||||
import Tooltip from 'components/helpers/tooltip/Tooltip';
|
||||
import InfoTooltip from 'components/helpers/tooltip/infoTooltip';
|
||||
|
||||
import EventBus from 'modules/helpers/eventbus';
|
||||
|
||||
import './scss/index.scss';
|
||||
import { FaThemeisle } from 'react-icons/fa';
|
||||
|
||||
export default class Navbar extends PureComponent {
|
||||
constructor() {
|
||||
super();
|
||||
this.navbarContainer = createRef();
|
||||
this.refreshValue = localStorage.getItem('refresh');
|
||||
this.refreshEnabled = localStorage.getItem('refresh');
|
||||
this.refreshValue = localStorage.getItem('refreshOption');
|
||||
this.state = {
|
||||
classList: localStorage.getItem('widgetStyle') === 'legacy' ? 'navbar old' : 'navbar new',
|
||||
};
|
||||
}
|
||||
|
||||
setZoom() {
|
||||
|
@ -26,7 +32,8 @@ export default class Navbar extends PureComponent {
|
|||
componentDidMount() {
|
||||
EventBus.on('refresh', (data) => {
|
||||
if (data === 'navbar' || data === 'background') {
|
||||
this.refreshValue = localStorage.getItem('refresh');
|
||||
this.refreshEnabled = localStorage.getItem('refresh');
|
||||
this.refreshValue = localStorage.getItem('refreshOption');
|
||||
this.forceUpdate();
|
||||
this.setZoom();
|
||||
}
|
||||
|
@ -36,7 +43,7 @@ export default class Navbar extends PureComponent {
|
|||
}
|
||||
|
||||
refresh() {
|
||||
switch (this.refreshValue) {
|
||||
switch (this.refreshValue) {
|
||||
case 'background':
|
||||
EventBus.dispatch('refresh', 'backgroundrefresh');
|
||||
break;
|
||||
|
@ -53,36 +60,53 @@ export default class Navbar extends PureComponent {
|
|||
}
|
||||
|
||||
render() {
|
||||
const backgroundEnabled = (localStorage.getItem('background') === 'true');
|
||||
const backgroundEnabled = localStorage.getItem('background') === 'true';
|
||||
|
||||
const navbar = (
|
||||
<div className='navbar-container' ref={this.navbarContainer}>
|
||||
{(localStorage.getItem('view') === 'true' && backgroundEnabled) ? <Maximise/> : null}
|
||||
{(localStorage.getItem('favouriteEnabled') === 'true' && backgroundEnabled) ? <Favourite/> : null}
|
||||
|
||||
{(localStorage.getItem('notesEnabled') === 'true') ?
|
||||
<div className='notes'>
|
||||
<MdAssignment className='topicons'/>
|
||||
<Notes/>
|
||||
</div>
|
||||
: null}
|
||||
<div className="navbar-container">
|
||||
<div className={this.state.classList} ref={this.navbarContainer}>
|
||||
{localStorage.getItem('view') === 'true' && backgroundEnabled ? <Maximise /> : null}
|
||||
{localStorage.getItem('notesEnabled') === 'true' ? <Notes /> : null}
|
||||
{localStorage.getItem('todo') === 'true' ? <Todo /> : null}
|
||||
|
||||
{(this.refreshValue !== 'false') ?
|
||||
<Tooltip title={variables.language.getMessage(variables.languagecode, 'widgets.navbar.tooltips.refresh')}>
|
||||
<MdRefresh className='refreshicon topicons' onClick={() => this.refresh()}/>
|
||||
</Tooltip>
|
||||
: null}
|
||||
|
||||
<Tooltip title={variables.language.getMessage(variables.languagecode, 'modals.main.navbar.settings')}>
|
||||
<MdSettings className='settings-icon topicons' onClick={() => this.props.openModal('mainModal')}/>
|
||||
</Tooltip>
|
||||
{this.refreshEnabled !== 'false' ? (
|
||||
<Tooltip
|
||||
title={variables.language.getMessage(
|
||||
variables.languagecode,
|
||||
'widgets.navbar.tooltips.refresh',
|
||||
)}
|
||||
>
|
||||
<button onClick={() => this.refresh()}>
|
||||
<MdRefresh className="refreshicon topicons" />
|
||||
</button>
|
||||
</Tooltip>
|
||||
) : null}
|
||||
|
||||
<InfoTooltip
|
||||
title="You can now sync your settings"
|
||||
subtitle={'All settings, such as theme can now be synced across clients'}
|
||||
linkURL={'https://www.youtube.com/watch?v=dQw4w9WgXcQ'}
|
||||
linkText={'Learn more'}
|
||||
>
|
||||
<button onClick={() => this.props.openModal('mainModal')}>
|
||||
<MdSettings className="settings-icon topicons" />
|
||||
</button>
|
||||
</InfoTooltip>
|
||||
</div>
|
||||
{/*<div className="notification">
|
||||
<span className="title">New Update</span>
|
||||
<span className="subtitle">
|
||||
The newest update includes a lot of cheese plus urmm donate to david ralph on github.
|
||||
</span>
|
||||
<button>Learn More</button>
|
||||
</div>*/}
|
||||
</div>
|
||||
);
|
||||
|
||||
if (localStorage.getItem('navbarHover') === 'true') {
|
||||
return <div className='navbar-hover'>{navbar}</div>;
|
||||
} else {
|
||||
return navbar;
|
||||
}
|
||||
return localStorage.getItem('navbarHover') === 'true' ? (
|
||||
<div className="navbar-hover">{navbar}</div>
|
||||
) : (
|
||||
navbar
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,39 +1,58 @@
|
|||
import variables from 'modules/variables';
|
||||
import { PureComponent } from 'react';
|
||||
import { MdFileCopy, MdAssignment, MdPushPin } from 'react-icons/md';
|
||||
import { PureComponent, useRef } from 'react';
|
||||
import { MdContentCopy, MdAssignment, MdPushPin, MdDownload } from 'react-icons/md';
|
||||
import { useFloating, shift } from '@floating-ui/react-dom';
|
||||
import TextareaAutosize from '@mui/material/TextareaAutosize';
|
||||
import { toast } from 'react-toastify';
|
||||
//import Hotkeys from 'react-hot-keys';
|
||||
import Tooltip from '../../helpers/tooltip/Tooltip'; //import Hotkeys from 'react-hot-keys';
|
||||
import { saveFile } from 'modules/helpers/settings/modals';
|
||||
|
||||
export default class Notes extends PureComponent {
|
||||
class Notes extends PureComponent {
|
||||
constructor() {
|
||||
super();
|
||||
this.state = {
|
||||
notes: localStorage.getItem('notes') || '',
|
||||
visibility: (localStorage.getItem('notesPinned') === 'true') ? 'visible' : 'hidden',
|
||||
marginLeft: (localStorage.getItem('refresh') === 'false') ? '-200px' : '-150px'
|
||||
visibility: localStorage.getItem('notesPinned') === 'true' ? 'visible' : 'hidden',
|
||||
showNotes: localStorage.getItem('notesPinned') === 'true' ? true : false,
|
||||
};
|
||||
}
|
||||
|
||||
setNotes = (e) => {
|
||||
localStorage.setItem('notes', e.target.value);
|
||||
this.setState({
|
||||
notes: e.target.value
|
||||
notes: e.target.value,
|
||||
});
|
||||
};
|
||||
|
||||
showNotes() {
|
||||
this.setState({
|
||||
showNotes: true,
|
||||
});
|
||||
}
|
||||
|
||||
hideNotes() {
|
||||
if (localStorage.getItem('notesPinned') === 'true') {
|
||||
this.setState({
|
||||
showNotes: true,
|
||||
});
|
||||
} else {
|
||||
this.setState({
|
||||
showNotes: false,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
pin() {
|
||||
variables.stats.postEvent('feature', 'Notes pin');
|
||||
|
||||
if (localStorage.getItem('notesPinned') === 'true') {
|
||||
localStorage.setItem('notesPinned', false);
|
||||
this.setState({
|
||||
visibility: 'hidden'
|
||||
showNotes: false,
|
||||
});
|
||||
} else {
|
||||
localStorage.setItem('notesPinned', true);
|
||||
this.setState({
|
||||
visibility: 'visible'
|
||||
showNotes: true,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -44,19 +63,97 @@ export default class Notes extends PureComponent {
|
|||
toast(variables.language.getMessage(variables.languagecode, 'toasts.notes'));
|
||||
}
|
||||
|
||||
download() {
|
||||
const notes = localStorage.getItem('notes');
|
||||
if (!notes || notes === '') {
|
||||
return;
|
||||
}
|
||||
|
||||
variables.stats.postEvent('feature', 'Notes download');
|
||||
saveFile(this.state.notes, 'mue-notes.txt', 'text/plain');
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<span className='notescontainer' style={{ visibility: this.state.visibility, marginLeft: this.state.marginLeft }}>
|
||||
<div className='topbarnotes'>
|
||||
<MdAssignment/>
|
||||
<h3>{variables.language.getMessage(variables.languagecode, 'widgets.navbar.notes.title')}</h3>
|
||||
</div>
|
||||
<TextareaAutosize placeholder={variables.language.getMessage(variables.languagecode, 'widgets.navbar.notes.placeholder')} value={this.state.notes} onChange={this.setNotes}/>
|
||||
<button onClick={() => this.pin()} className='pinNote'><MdPushPin/></button>
|
||||
<button onClick={() => this.copy()} className='copyNote'><MdFileCopy/></button>
|
||||
{/*variables.keybinds.pinNotes && variables.keybinds.pinNotes !== '' ? <Hotkeys keyName={variables.keybinds.pinNotes} onKeyDown={() => this.pin()}/> : null*/}
|
||||
{/*variables.keybinds.copyNotes && variables.keybinds.copyNotes !== '' ? <Hotkeys keyName={variables.keybinds.copyNotes} onKeyDown={() => this.copy()}/> : null*/}
|
||||
</span>
|
||||
<div className="notes" onMouseLeave={() => this.hideNotes()} onFocus={() => this.showNotes()}>
|
||||
<button
|
||||
className="first"
|
||||
onMouseEnter={() => this.showNotes()}
|
||||
onFocus={() => this.showNotes()}
|
||||
onBlur={() => this.hideNotes()}
|
||||
ref={this.props.notesRef}
|
||||
>
|
||||
<MdAssignment className="topicons" />
|
||||
</button>
|
||||
{this.state.showNotes && (
|
||||
<span
|
||||
className="notesContainer"
|
||||
ref={this.props.floatRef}
|
||||
style={{
|
||||
position: this.props.position,
|
||||
top: this.props.yPosition ?? '44',
|
||||
left: this.props.xPosition ?? '',
|
||||
}}
|
||||
>
|
||||
<div className="flexNotes">
|
||||
<div className="topBarNotes" style={{ display: 'flex' }}>
|
||||
<MdAssignment />
|
||||
<span>
|
||||
{variables.language.getMessage(
|
||||
variables.languagecode,
|
||||
'widgets.navbar.notes.title',
|
||||
)}
|
||||
</span>
|
||||
</div>
|
||||
<div className="notes-buttons">
|
||||
<Tooltip title="Pin">
|
||||
<button onClick={() => this.pin()}>
|
||||
<MdPushPin />
|
||||
</button>
|
||||
</Tooltip>
|
||||
<Tooltip title="Copy">
|
||||
<button onClick={() => this.copy()}>
|
||||
<MdContentCopy />
|
||||
</button>
|
||||
</Tooltip>
|
||||
<Tooltip title="Download">
|
||||
<button onClick={() => this.download()}>
|
||||
<MdDownload />
|
||||
</button>
|
||||
</Tooltip>
|
||||
</div>
|
||||
<TextareaAutosize
|
||||
placeholder={variables.language.getMessage(
|
||||
variables.languagecode,
|
||||
'widgets.navbar.notes.placeholder',
|
||||
)}
|
||||
value={this.state.notes}
|
||||
onChange={this.setNotes}
|
||||
minRows={5}
|
||||
/>
|
||||
{/*variables.keybinds.pinNotes && variables.keybinds.pinNotes !== '' ? <Hotkeys keyName={variables.keybinds.pinNotes} onKeyDown={() => this.pin()}/> : null*/}
|
||||
{/*variables.keybinds.copyNotes && variables.keybinds.copyNotes !== '' ? <Hotkeys keyName={variables.keybinds.copyNotes} onKeyDown={() => this.copy()}/> : null*/}
|
||||
</div>
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default function NotesWrapper() {
|
||||
const { x, y, reference, floating, strategy } = useFloating({
|
||||
placement: 'bottom',
|
||||
middleware: [shift()],
|
||||
});
|
||||
|
||||
return (
|
||||
<Notes
|
||||
notesRef={reference}
|
||||
floatRef={floating}
|
||||
position={strategy}
|
||||
xPosition={x}
|
||||
yPosition={y}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,181 @@
|
|||
import variables from 'modules/variables';
|
||||
import { PureComponent } from 'react';
|
||||
import { MdChecklist, MdPushPin, MdDelete, MdPlaylistAdd } 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 Hotkeys from 'react-hot-keys';
|
||||
|
||||
class Todo extends PureComponent {
|
||||
constructor() {
|
||||
super();
|
||||
this.state = {
|
||||
todo: JSON.parse(localStorage.getItem('todoContent')) || [
|
||||
{
|
||||
value: '',
|
||||
done: false,
|
||||
},
|
||||
],
|
||||
visibility: localStorage.getItem('todoPinned') === 'true' ? 'visible' : 'hidden',
|
||||
marginLeft: localStorage.getItem('refresh') === 'false' ? '-200px' : '-130px',
|
||||
showTodo: localStorage.getItem('todoPinned') === 'true',
|
||||
};
|
||||
}
|
||||
|
||||
showTodo() {
|
||||
this.setState({
|
||||
showTodo: true,
|
||||
});
|
||||
}
|
||||
|
||||
hideTodo() {
|
||||
if (localStorage.getItem('todoPinned') === 'true') {
|
||||
this.setState({
|
||||
showTodo: true,
|
||||
});
|
||||
} else {
|
||||
this.setState({
|
||||
showTodo: false,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
updateTodoState(todoContent) {
|
||||
localStorage.setItem('todoContent', JSON.stringify(todoContent));
|
||||
this.setState({
|
||||
todo: todoContent,
|
||||
});
|
||||
this.forceUpdate();
|
||||
}
|
||||
|
||||
setTodo(index, data) {
|
||||
let todoContent = this.state.todo;
|
||||
todoContent[index] = {
|
||||
value: data.target.value,
|
||||
done: todoContent[index].done,
|
||||
};
|
||||
this.updateTodoState(todoContent);
|
||||
}
|
||||
|
||||
addTodo() {
|
||||
let todoContent = this.state.todo;
|
||||
todoContent.push({
|
||||
value: '',
|
||||
done: false,
|
||||
});
|
||||
this.updateTodoState(todoContent);
|
||||
}
|
||||
|
||||
removeTodo(index) {
|
||||
let todoContent = this.state.todo;
|
||||
todoContent.splice(index, 1);
|
||||
if (todoContent.length === 0) {
|
||||
todoContent.push({
|
||||
value: '',
|
||||
done: false,
|
||||
});
|
||||
}
|
||||
this.updateTodoState(todoContent);
|
||||
}
|
||||
|
||||
doneTodo(index) {
|
||||
let todoContent = this.state.todo;
|
||||
todoContent[index].done = !todoContent[index].done;
|
||||
this.updateTodoState(todoContent);
|
||||
}
|
||||
|
||||
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,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div className="notes" onMouseLeave={() => this.hideTodo()} onFocus={() => this.showTodo()}>
|
||||
<button
|
||||
className="first"
|
||||
onMouseEnter={() => this.showTodo()}
|
||||
onFocus={() => this.hideTodo()}
|
||||
onBlur={() => this.showTodo()}
|
||||
ref={this.props.todoRef}
|
||||
>
|
||||
<MdChecklist className="topicons" />
|
||||
</button>
|
||||
{this.state.showTodo && (
|
||||
<span
|
||||
className="notesContainer"
|
||||
ref={this.props.floatRef}
|
||||
style={{
|
||||
position: this.props.position,
|
||||
top: this.props.yPosition ?? '44px',
|
||||
left: this.props.xPosition ?? '',
|
||||
}}
|
||||
>
|
||||
<div className="flexTodo">
|
||||
<div className="topBarNotes" style={{ display: 'flex' }}>
|
||||
<MdChecklist />
|
||||
<span>Todo</span>
|
||||
</div>
|
||||
<div className="notes-buttons">
|
||||
<Tooltip title="Pin">
|
||||
<button onClick={() => this.pin()}>
|
||||
<MdPushPin />
|
||||
</button>
|
||||
</Tooltip>
|
||||
<Tooltip title={'Add'}>
|
||||
<button onClick={() => this.addTodo()}>
|
||||
<MdPlaylistAdd />
|
||||
</button>
|
||||
</Tooltip>
|
||||
</div>
|
||||
<div className={'todoRows'}>
|
||||
{this.state.todo.map((value, index) => (
|
||||
<div
|
||||
className={'todoRow' + (this.state.todo[index].done ? ' done' : '')}
|
||||
key={index}
|
||||
>
|
||||
<Checkbox
|
||||
checked={this.state.todo[index].done}
|
||||
onClick={() => this.doneTodo(index)}
|
||||
/>
|
||||
<TextareaAutosize
|
||||
placeholder={variables.language.getMessage(
|
||||
variables.languagecode,
|
||||
'widgets.navbar.notes.placeholder',
|
||||
)}
|
||||
value={this.state.todo[index].value}
|
||||
onChange={(data) => this.setTodo(index, data)}
|
||||
readOnly={this.state.todo[index].done}
|
||||
/>
|
||||
<MdDelete onClick={() => this.removeTodo(index)} />
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
export default function TodoWrapper() {
|
||||
const { x, y, reference, floating, strategy } = useFloating({
|
||||
placement: 'bottom',
|
||||
middleware: [shift()],
|
||||
});
|
||||
|
||||
return (
|
||||
<Todo todoRef={reference} floatRef={floating} position={strategy} xPosition={x} yPosition={y} />
|
||||
);
|
||||
}
|
|
@ -1,3 +1,5 @@
|
|||
@import 'scss/variables';
|
||||
|
||||
.notes {
|
||||
position: relative;
|
||||
|
||||
|
@ -8,32 +10,68 @@
|
|||
user-select: none;
|
||||
}
|
||||
|
||||
&:hover .notescontainer {
|
||||
&:hover .notesContainer {
|
||||
visibility: visible !important;
|
||||
}
|
||||
|
||||
&:active .notesContainer {
|
||||
visibility: visible !important;
|
||||
}
|
||||
|
||||
&:focus .notesContainer {
|
||||
visibility: visible !important;
|
||||
}
|
||||
}
|
||||
|
||||
.notescontainer {
|
||||
.notesContainer {
|
||||
@extend %basic;
|
||||
padding: 15px;
|
||||
visibility: hidden;
|
||||
background-color: var(--background);
|
||||
color: var(--modal-text);
|
||||
text-align: center;
|
||||
border-radius: 12px;
|
||||
position: absolute;
|
||||
top: 80%;
|
||||
margin-left: -150px;
|
||||
max-height: 80vh !important;
|
||||
font-size: 1rem !important;
|
||||
/*top: 100%;
|
||||
left: 50%;
|
||||
margin-left: -130px;*/
|
||||
|
||||
textarea {
|
||||
max-height: 65vh !important;
|
||||
overflow-y: visible !important;
|
||||
.notes-buttons {
|
||||
button {
|
||||
@include basicIconButton(11px, 1.3rem, ui);
|
||||
|
||||
@include themed() {
|
||||
background: t($btn-background) !important;
|
||||
|
||||
&:hover {
|
||||
background: t($btn-backgroundHover) !important;
|
||||
}
|
||||
}
|
||||
|
||||
flex-grow: 1;
|
||||
display: grid;
|
||||
place-items: center;
|
||||
|
||||
svg {
|
||||
font-size: 1.3rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
svg {
|
||||
float: left;
|
||||
font-size: 1em !important;
|
||||
|
||||
.flexNotes {
|
||||
display: flex;
|
||||
flex-flow: column;
|
||||
gap: 15px;
|
||||
|
||||
textarea {
|
||||
max-height: 65vh !important;
|
||||
overflow-y: visible !important;
|
||||
@extend %basic;
|
||||
border: none;
|
||||
padding: 15px;
|
||||
border-radius: 12px;
|
||||
width: 200px;
|
||||
}
|
||||
}
|
||||
|
||||
::placeholder {
|
||||
|
@ -46,24 +84,29 @@ textarea {
|
|||
border: none;
|
||||
resize: none;
|
||||
background: none;
|
||||
width: 200px;
|
||||
height: 100px;
|
||||
margin: 10px;
|
||||
}
|
||||
|
||||
.topbarnotes {
|
||||
.topBarNotes {
|
||||
@extend %basic;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-flow: row;
|
||||
height: 50px;
|
||||
border-radius: 12px;
|
||||
flex-flow: row;
|
||||
gap: 5px;
|
||||
|
||||
svg {
|
||||
font-size: 46px !important;
|
||||
padding: 9px;
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: 46px;
|
||||
margin-right: 20px;
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
.dark textarea {
|
||||
background-color: #2f3542;
|
||||
color: white;
|
||||
.notes-buttons {
|
||||
display: flex !important;
|
||||
gap: 10px;
|
||||
|
||||
.tooltip {
|
||||
flex: 1 !important;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,64 @@
|
|||
.notesContainer {
|
||||
.flexTodo {
|
||||
display: flex;
|
||||
flex-flow: column;
|
||||
gap: 15px;
|
||||
width: 223px;
|
||||
|
||||
.todoRows {
|
||||
max-height: 65vh !important;
|
||||
overflow-y: visible !important;
|
||||
display: flex;
|
||||
flex-flow: column;
|
||||
gap: 15px;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.todoRow {
|
||||
@include basicIconButton(1px, 16px, ui);
|
||||
display: flex;
|
||||
flex-flow: row;
|
||||
align-items: center;
|
||||
padding-right: 10px;
|
||||
margin: 1px;
|
||||
|
||||
@include themed() {
|
||||
color: t($color) !important;
|
||||
}
|
||||
|
||||
textarea {
|
||||
width: 120px;
|
||||
@include themed() {
|
||||
color: t($color) !important;
|
||||
}
|
||||
}
|
||||
|
||||
svg {
|
||||
padding: 10px;
|
||||
place-items: center;
|
||||
display: grid;
|
||||
cursor: pointer;
|
||||
|
||||
@include themed() {
|
||||
color: t($color) !important;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
@include themed() {
|
||||
background: t($modal-sidebar);
|
||||
border-radius: t($borderRadius);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.done {
|
||||
text-decoration: line-through;
|
||||
|
||||
textarea {
|
||||
cursor: not-allowed;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,52 +1,87 @@
|
|||
@import 'notes';
|
||||
@import '../../../../scss/variables';
|
||||
@import 'todo';
|
||||
@import 'scss/variables';
|
||||
|
||||
.navbar-container {
|
||||
position: absolute;
|
||||
top: 1rem;
|
||||
right: 1rem;
|
||||
|
||||
div {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
img {
|
||||
height: 1em;
|
||||
width: auto;
|
||||
margin: 0.5rem;
|
||||
}
|
||||
|
||||
svg.topicons {
|
||||
color: map-get($theme-colours, 'main-text-color');
|
||||
.navbar {
|
||||
display: flex;
|
||||
flex-flow: row;
|
||||
gap: 10px;
|
||||
animation: fadeIn 2s;
|
||||
button {
|
||||
-webkit-font-smoothing: subpixel-antialiased;
|
||||
font-size: 1em;
|
||||
margin: 0.5rem;
|
||||
filter: drop-shadow(0 0 6px rgba(0, 0, 0, 0.3));
|
||||
/*filter: drop-shadow(0 0 6px rgba(0, 0, 0, 0.3));*/
|
||||
cursor: pointer;
|
||||
transition: 0.2s ease;
|
||||
// transition: 0.2s ease;
|
||||
margin-top: 0;
|
||||
|
||||
&:hover {
|
||||
@keyframes fadeIn {
|
||||
0% {
|
||||
opacity: 0;
|
||||
}
|
||||
100% {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* &:hover {
|
||||
color: map-get($theme-colours, 'main-text-color');
|
||||
transform: translateZ(0);
|
||||
transform: scale(1.3);
|
||||
}*/
|
||||
}
|
||||
}
|
||||
|
||||
.old {
|
||||
.tooltip {
|
||||
button {
|
||||
@include basicIconButton(12px, 20px, legacy);
|
||||
}
|
||||
}
|
||||
.first {
|
||||
@include basicIconButton(12px, 20px, legacy);
|
||||
}
|
||||
}
|
||||
.new {
|
||||
button {
|
||||
@include basicIconButton(12px, 20px, ui);
|
||||
}
|
||||
}
|
||||
|
||||
.navbar-hover {
|
||||
position: absolute;
|
||||
top: 0rem;
|
||||
right: 0rem;
|
||||
top: 0;
|
||||
right: 0;
|
||||
height: 50px;
|
||||
width: 500px;
|
||||
|
||||
.navbar-container {
|
||||
.navbar {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
.navbar-container {
|
||||
.navbar {
|
||||
visibility: visible;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.navbar-container {
|
||||
position: absolute;
|
||||
top: 1rem;
|
||||
right: 1rem;
|
||||
display: flex;
|
||||
flex-flow: column;
|
||||
.notification {
|
||||
@extend %basic;
|
||||
display: flex;
|
||||
flex-flow: column;
|
||||
gap: 15px;
|
||||
padding: 15px;
|
||||
text-align: left;
|
||||
width: 200px;
|
||||
button {
|
||||
@include basicIconButton(10px, 14px, ui);
|
||||
gap: 20px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import variables from 'modules/variables';
|
||||
import { PureComponent, createRef } from 'react';
|
||||
import { TextareaAutosize } from '@mui/material';
|
||||
import { MdAddToPhotos } from 'react-icons/md';
|
||||
//import Hotkeys from 'react-hot-keys';
|
||||
|
||||
import Tooltip from 'components/helpers/tooltip/Tooltip';
|
||||
|
@ -18,8 +19,9 @@ export default class QuickLinks extends PureComponent {
|
|||
items: JSON.parse(localStorage.getItem('quicklinks')),
|
||||
name: '',
|
||||
url: '',
|
||||
showAddLink: 'hidden',
|
||||
urlError: ''
|
||||
showAddLink: 'none',
|
||||
nameError: '',
|
||||
urlError: '',
|
||||
};
|
||||
this.quicklinksContainer = createRef();
|
||||
}
|
||||
|
@ -32,7 +34,7 @@ export default class QuickLinks extends PureComponent {
|
|||
|
||||
localStorage.setItem('quicklinks', JSON.stringify(data));
|
||||
this.setState({
|
||||
items: data
|
||||
items: data,
|
||||
});
|
||||
|
||||
variables.stats.postEvent('feature', 'Quicklink delete');
|
||||
|
@ -41,18 +43,22 @@ export default class QuickLinks extends PureComponent {
|
|||
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) {
|
||||
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 = this.getMessage('widgets.quicklinks.url_error');
|
||||
}
|
||||
|
||||
if (urlError) {
|
||||
return this.setState({
|
||||
urlError
|
||||
urlError,
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -64,7 +70,7 @@ export default class QuickLinks extends PureComponent {
|
|||
name: this.state.name || url,
|
||||
url: url,
|
||||
icon: this.state.icon || '',
|
||||
key: Math.random().toString(36).substring(7) + 1
|
||||
key: Math.random().toString(36).substring(7) + 1,
|
||||
});
|
||||
|
||||
localStorage.setItem('quicklinks', JSON.stringify(data));
|
||||
|
@ -72,7 +78,7 @@ export default class QuickLinks extends PureComponent {
|
|||
this.setState({
|
||||
items: data,
|
||||
name: '',
|
||||
url: ''
|
||||
url: '',
|
||||
});
|
||||
|
||||
variables.stats.postEvent('feature', 'Quicklink add');
|
||||
|
@ -81,31 +87,25 @@ export default class QuickLinks extends PureComponent {
|
|||
|
||||
// make sure image is correct size
|
||||
this.setZoom(this.quicklinksContainer.current);
|
||||
}
|
||||
};
|
||||
|
||||
toggleAdd = () => {
|
||||
this.setState({
|
||||
showAddLink: (this.state.showAddLink === 'hidden') ? 'visible' : 'hidden'
|
||||
showAddLink: this.state.showAddLink === 'none' ? 'flex' : 'none',
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// widget zoom
|
||||
setZoom(element) {
|
||||
const zoom = localStorage.getItem('zoomQuicklinks') || 100;
|
||||
if (localStorage.getItem('quicklinksText')) {
|
||||
const links = element.getElementsByTagName('a');
|
||||
|
||||
for (const link of links) {
|
||||
link.style.fontSize = `${0.87 * Number(zoom / 100)}em`;
|
||||
for (const link of element.getElementsByTagName('a')) {
|
||||
link.style.fontSize = `${1.4 * Number(zoom / 100)}em`;
|
||||
}
|
||||
} else {
|
||||
for (const img of element.getElementsByTagName('img')) {
|
||||
img.style.height = `${1.4 * Number(zoom / 100)}em`;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const images = element.getElementsByTagName('img');
|
||||
|
||||
for (const img of images) {
|
||||
img.style.height = `${0.87 * Number(zoom / 100)}em`;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -113,14 +113,14 @@ export default class QuickLinks extends PureComponent {
|
|||
EventBus.on('refresh', (data) => {
|
||||
if (data === 'quicklinks') {
|
||||
if (localStorage.getItem('quicklinksenabled') === 'false') {
|
||||
return this.quicklinksContainer.current.style.display = 'none';
|
||||
return (this.quicklinksContainer.current.style.display = 'none');
|
||||
}
|
||||
|
||||
this.quicklinksContainer.current.style.display = 'block';
|
||||
this.setZoom(this.quicklinksContainer.current);
|
||||
|
||||
this.setState({
|
||||
items: JSON.parse(localStorage.getItem('quicklinks'))
|
||||
items: JSON.parse(localStorage.getItem('quicklinks')),
|
||||
});
|
||||
}
|
||||
});
|
||||
|
@ -136,66 +136,118 @@ export default class QuickLinks extends PureComponent {
|
|||
this.addLink();
|
||||
e.preventDefault();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
componentWillUnmount() {
|
||||
EventBus.off('refresh');
|
||||
}
|
||||
|
||||
render() {
|
||||
let target, rel = null;
|
||||
let target,
|
||||
rel = null;
|
||||
if (localStorage.getItem('quicklinksnewtab') === 'true') {
|
||||
target = '_blank';
|
||||
rel = 'noopener noreferrer';
|
||||
}
|
||||
|
||||
const tooltipEnabled = localStorage.getItem('quicklinkstooltip');
|
||||
const useProxy = (localStorage.getItem('quicklinksddgProxy') !== 'false');
|
||||
const useText = (localStorage.getItem('quicklinksText') === 'true');
|
||||
const useProxy = localStorage.getItem('quicklinksddgProxy') !== 'false';
|
||||
const useText = localStorage.getItem('quicklinksText') === 'true';
|
||||
|
||||
const quickLink = (item) => {
|
||||
if (useText) {
|
||||
return <a className='quicklinkstext' key={item.key} onContextMenu={(e) => this.deleteLink(item.key, e)} href={item.url} target={target} rel={rel} draggable={false}>{item.name}</a>;
|
||||
return (
|
||||
<a
|
||||
className="quicklinkstext"
|
||||
key={item.key}
|
||||
onContextMenu={(e) => this.deleteLink(item.key, e)}
|
||||
href={item.url}
|
||||
target={target}
|
||||
rel={rel}
|
||||
draggable={false}
|
||||
>
|
||||
{item.name}
|
||||
</a>
|
||||
);
|
||||
}
|
||||
|
||||
const url = useProxy ? 'https://icons.duckduckgo.com/ip2/' : 'https://www.google.com/s2/favicons?sz=32&domain=';
|
||||
const img = item.icon || url + item.url.replace('https://', '').replace('http://', '') + (useProxy ? '.ico' : '');
|
||||
const url = useProxy
|
||||
? 'https://icons.duckduckgo.com/ip2/'
|
||||
: 'https://www.google.com/s2/favicons?sz=32&domain=';
|
||||
const img =
|
||||
item.icon ||
|
||||
url + item.url.replace('https://', '').replace('http://', '') + (useProxy ? '.ico' : '');
|
||||
|
||||
const link = (
|
||||
<a key={item.key} onContextMenu={(e) => this.deleteLink(item.key, e)} href={item.url} target={target} rel={rel} draggable={false}>
|
||||
<img src={img} alt={item.name} draggable={false}/>
|
||||
<a
|
||||
key={item.key}
|
||||
onContextMenu={(e) => this.deleteLink(item.key, e)}
|
||||
href={item.url}
|
||||
target={target}
|
||||
rel={rel}
|
||||
draggable={false}
|
||||
>
|
||||
<img src={img} alt={item.name} draggable={false} />
|
||||
</a>
|
||||
);
|
||||
|
||||
if (tooltipEnabled === 'true') {
|
||||
return <Tooltip title={item.name}>{link}</Tooltip>;
|
||||
} else {
|
||||
return link;
|
||||
}
|
||||
return tooltipEnabled === 'true' ? (
|
||||
<Tooltip title={item.name} placement="top">
|
||||
{link}
|
||||
</Tooltip>
|
||||
) : (
|
||||
link
|
||||
);
|
||||
};
|
||||
|
||||
const marginTop = (this.state.items.length > 0) ? '9vh' : '4vh';
|
||||
|
||||
return (
|
||||
<div className='quicklinks-container' ref={this.quicklinksContainer}>
|
||||
{this.state.items.map((item) => (
|
||||
quickLink(item)
|
||||
))}
|
||||
<button className='quicklinks' onClick={this.toggleAdd}>+</button>
|
||||
<span className='quicklinkscontainer' style={{ visibility: this.state.showAddLink, marginTop }}>
|
||||
<div className='topbarquicklinks' onKeyDown={this.topbarEnter}>
|
||||
<h4>{this.getMessage('widgets.quicklinks.new')}</h4>
|
||||
<TextareaAutosize rowsmax={1} placeholder={this.getMessage('widgets.quicklinks.name')} value={this.state.name} onChange={(e) => this.setState({ name: e.target.value })} />
|
||||
<p/>
|
||||
<TextareaAutosize rowsmax={10} placeholder={this.getMessage('widgets.quicklinks.url')} value={this.state.url} onChange={(e) => this.setState({ url: e.target.value })} />
|
||||
<p>{this.state.urlError}</p>
|
||||
<TextareaAutosize rowsmax={10} placeholder={this.getMessage('widgets.quicklinks.icon')} value={this.state.icon} onChange={(e) => this.setState({ icon: e.target.value })} />
|
||||
<p></p>
|
||||
<button className='pinNote' onClick={this.addLink}>{this.getMessage('widgets.quicklinks.add')}</button>
|
||||
<>
|
||||
<div className="quicklinkscontainer" ref={this.quicklinksContainer}>
|
||||
{this.state.items.map((item) => quickLink(item))}
|
||||
</div>
|
||||
<div className="quicklinkscontainer">
|
||||
<button className="quicklinks" onClick={this.toggleAdd}>
|
||||
<MdAddToPhotos /> {this.getMessage('widgets.quicklinks.add')}
|
||||
</button>
|
||||
</div>
|
||||
<div className="quicklinkscontainer">
|
||||
<div
|
||||
className="quicklinksdropdown"
|
||||
onKeyDown={this.topbarEnter}
|
||||
style={{ display: this.state.showAddLink }}
|
||||
>
|
||||
<span className="dropdown-title">{this.getMessage('widgets.quicklinks.new')}</span>
|
||||
<span className="dropdown-subtitle">
|
||||
{this.getMessage('widgets.quicklinks.new')} Description
|
||||
</span>
|
||||
<TextareaAutosize
|
||||
maxRows={1}
|
||||
placeholder={this.getMessage('widgets.quicklinks.name')}
|
||||
value={this.state.name}
|
||||
onChange={(e) => this.setState({ name: e.target.value })}
|
||||
/>
|
||||
<span className="dropdown-error" />
|
||||
<TextareaAutosize
|
||||
maxRows={10}
|
||||
placeholder={this.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={this.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 /> {this.getMessage('widgets.quicklinks.add')}
|
||||
</button>
|
||||
</div>
|
||||
</span>
|
||||
{/*variables.keybinds.toggleQuicklinks && variables.keybinds.toggleQuicklinks !== '' ? <Hotkeys keyName={variables.keybinds.toggleQuicklinks} onKeyDown={this.toggleAdd} /> : null*/}
|
||||
</div>
|
||||
{/*variables.keybinds.toggleQuicklinks && variables.keybinds.toggleQuicklinks !== '' ? <Hotkeys keyName={variables.keybinds.toggleQuicklinks} onKeyDown={this.toggleAdd} /> : null*/}
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,48 +1,42 @@
|
|||
.quicklinks {
|
||||
position: relative;
|
||||
user-select: none;
|
||||
border: none;
|
||||
color: #fff;
|
||||
font-size: 42px;
|
||||
background: none;
|
||||
cursor: pointer;
|
||||
text-shadow: 0 0 10px rgb(0 0 0 / 60%);
|
||||
@import 'scss/variables';
|
||||
|
||||
h3 {
|
||||
text-shadow: none;
|
||||
margin: 0;
|
||||
}
|
||||
.quicklinks {
|
||||
@include basicIconButton(10px, 14px, ui);
|
||||
outline: none;
|
||||
border: none;
|
||||
box-shadow: 0 0 0 1px #484848;
|
||||
border-radius: 12px;
|
||||
color: #fff;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-evenly;
|
||||
font-size: 0.5em;
|
||||
padding: 10px 40px 10px 40px;
|
||||
gap: 15px;
|
||||
}
|
||||
|
||||
.quicklinkscontainer {
|
||||
padding: 15px;
|
||||
background-color: var(--background);
|
||||
color: var(--modal-text);
|
||||
text-align: center;
|
||||
border-radius: 12px;
|
||||
position: absolute;
|
||||
margin-left: -140px;
|
||||
margin-top: 50px;
|
||||
z-index: 1;
|
||||
display: flex;
|
||||
align-content: center;
|
||||
justify-content: center;
|
||||
gap: 12px;
|
||||
|
||||
svg {
|
||||
float: left;
|
||||
textarea {
|
||||
@extend %basic;
|
||||
border: none;
|
||||
padding: 15px;
|
||||
border-radius: 12px;
|
||||
}
|
||||
|
||||
|
||||
::placeholder {
|
||||
color: #636e72;
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
textarea {
|
||||
border: none;
|
||||
width: 200px;
|
||||
resize: none;
|
||||
height: 100px;
|
||||
margin: 10px;
|
||||
}
|
||||
|
||||
.topbarquicklinks {
|
||||
svg {
|
||||
font-size: 46px;
|
||||
|
@ -64,13 +58,8 @@ textarea {
|
|||
}
|
||||
}
|
||||
|
||||
.dark textarea {
|
||||
background-color: #2f3542;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.quicklinks-container>a,
|
||||
.quicklinks-container>.quicklinks>button {
|
||||
.quicklinks-container > a,
|
||||
.quicklinks-container > .quicklinks > button {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
|
@ -94,9 +83,65 @@ textarea {
|
|||
.quicklinkstext {
|
||||
text-decoration: none;
|
||||
color: white;
|
||||
font-size: smaller;
|
||||
font-size: 0.8em;
|
||||
|
||||
&:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
|
||||
/* background-color: var(--background);
|
||||
color: var(--modal-text);*/
|
||||
|
||||
.quicklinksdropdown {
|
||||
@extend %basic;
|
||||
position: absolute;
|
||||
z-index: 99;
|
||||
display: none;
|
||||
flex-flow: column;
|
||||
padding: 15px;
|
||||
box-shadow: 0 0 0 1px #484848;
|
||||
gap: 5px;
|
||||
|
||||
&:hover {
|
||||
.quicklinksdropdown {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
.dropdown-title {
|
||||
font-size: 0.9em;
|
||||
}
|
||||
|
||||
.dropdown-subtitle {
|
||||
font-size: 0.4em;
|
||||
|
||||
@include themed() {
|
||||
color: t($subColor);
|
||||
}
|
||||
}
|
||||
|
||||
button {
|
||||
@include basicIconButton(10px, 0.9rem, ui);
|
||||
border-radius: 12px;
|
||||
border: none;
|
||||
outline: none;
|
||||
color: #fff;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
.dropdown-error {
|
||||
font-size: 0.4em;
|
||||
}
|
||||
|
||||
button.quicklinks {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.outOfScreen {
|
||||
bottom: 515px;
|
||||
}
|
||||
|
|
|
@ -1,10 +1,20 @@
|
|||
import variables from 'modules/variables';
|
||||
import { PureComponent, createRef } from 'react';
|
||||
import { MdContentCopy, MdStarBorder, MdStar } from 'react-icons/md';
|
||||
import { FaTwitter } from 'react-icons/fa';
|
||||
import {
|
||||
MdContentCopy,
|
||||
MdStarBorder,
|
||||
MdStar,
|
||||
MdPerson,
|
||||
MdOpenInNew,
|
||||
MdIosShare,
|
||||
} from 'react-icons/md';
|
||||
|
||||
import { toast } from 'react-toastify';
|
||||
//import Hotkeys from 'react-hot-keys';
|
||||
|
||||
import Tooltip from '../../helpers/tooltip/Tooltip';
|
||||
import ShareModal from '../../helpers/sharemodal/ShareModal';
|
||||
|
||||
import Interval from 'modules/helpers/interval';
|
||||
import EventBus from 'modules/helpers/eventbus';
|
||||
|
||||
|
@ -12,22 +22,48 @@ import './quote.scss';
|
|||
|
||||
export default class Quote extends PureComponent {
|
||||
buttons = {
|
||||
tweet: <FaTwitter className='copyButton' onClick={() => this.tweetQuote()} />,
|
||||
copy: <MdContentCopy className='copyButton' onClick={() => this.copyQuote()} />,
|
||||
unfavourited: <MdStarBorder className='copyButton' onClick={() => this.favourite()} />,
|
||||
favourited: <MdStar className='copyButton' onClick={() => this.favourite()} />
|
||||
}
|
||||
share: (
|
||||
<Tooltip title="Share">
|
||||
<button onClick={() => this.shareQuote()}>
|
||||
<MdIosShare className="copyButton" />
|
||||
</button>
|
||||
</Tooltip>
|
||||
),
|
||||
copy: (
|
||||
<Tooltip title="Copy">
|
||||
<button onClick={() => this.copyQuote()}>
|
||||
<MdContentCopy className="copyButton" />
|
||||
</button>
|
||||
</Tooltip>
|
||||
),
|
||||
unfavourited: (
|
||||
<Tooltip title="Favourite">
|
||||
<button onClick={() => this.favourite()}>
|
||||
<MdStarBorder className="copyButton" />
|
||||
</button>
|
||||
</Tooltip>
|
||||
),
|
||||
favourited: (
|
||||
<Tooltip title="Unfavourite">
|
||||
<button onClick={() => this.favourite()}>
|
||||
<MdStar className="copyButton" />
|
||||
</button>
|
||||
</Tooltip>
|
||||
),
|
||||
};
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.state = {
|
||||
quote: '',
|
||||
author: '',
|
||||
authorOccupation: '',
|
||||
favourited: this.useFavourite(),
|
||||
tweet: (localStorage.getItem('tweetButton') === 'false') ? null : this.buttons.tweet,
|
||||
copy: (localStorage.getItem('copyButton') === 'false') ? null : this.buttons.copy,
|
||||
share: localStorage.getItem('quoteShareButton') === 'false' ? null : this.buttons.share,
|
||||
copy: localStorage.getItem('copyButton') === 'false' ? null : this.buttons.copy,
|
||||
quoteLanguage: '',
|
||||
type: localStorage.getItem('quoteType') || 'api'
|
||||
type: localStorage.getItem('quoteType') || 'api',
|
||||
shareModal: false
|
||||
};
|
||||
this.quote = createRef();
|
||||
this.quotediv = createRef();
|
||||
|
@ -35,11 +71,13 @@ export default class Quote extends PureComponent {
|
|||
}
|
||||
|
||||
useFavourite() {
|
||||
let favouriteQuote = null;
|
||||
if (localStorage.getItem('favouriteQuoteEnabled') === 'true') {
|
||||
favouriteQuote = localStorage.getItem('favouriteQuote') ? this.buttons.favourited : this.buttons.unfavourited;
|
||||
return localStorage.getItem('favouriteQuote')
|
||||
? this.buttons.favourited
|
||||
: this.buttons.unfavourited;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
return favouriteQuote;
|
||||
}
|
||||
|
||||
doOffline() {
|
||||
|
@ -51,28 +89,77 @@ export default class Quote extends PureComponent {
|
|||
this.setState({
|
||||
quote: '"' + quote.quote + '"',
|
||||
author: quote.author,
|
||||
authorlink: this.getAuthorLink(quote.author)
|
||||
authorlink: this.getAuthorLink(quote.author),
|
||||
});
|
||||
}
|
||||
|
||||
getAuthorLink(author) {
|
||||
let authorlink = `https://${variables.languagecode.split('_')[0]}.wikipedia.org/wiki/${author.split(' ').join('_')}`;
|
||||
if (localStorage.getItem('authorLink') === 'false' || author === 'Unknown') {
|
||||
authorlink = null;
|
||||
return localStorage.getItem('authorLink') === 'false' || author === 'Unknown'
|
||||
? null
|
||||
: `https://${variables.languagecode.split('_')[0]}.wikipedia.org/wiki/${author
|
||||
.split(' ')
|
||||
.join('_')}`;
|
||||
}
|
||||
|
||||
async getAuthorImg(author) {
|
||||
const authorimgdata = await (
|
||||
await fetch(
|
||||
`https://en.wikipedia.org/w/api.php?action=query&titles=${author}&origin=*&prop=pageimages&format=json&pithumbsize=100`,
|
||||
)
|
||||
).json();
|
||||
let authorimg, authorimglicense;
|
||||
try {
|
||||
authorimg =
|
||||
authorimgdata.query.pages[Object.keys(authorimgdata.query.pages)[0]].thumbnail.source;
|
||||
const authorimglicensedata = await (
|
||||
await fetch(
|
||||
`https://en.wikipedia.org/w/api.php?action=query&prop=imageinfo&iiprop=extmetadata&titles=File:${
|
||||
authorimgdata.query.pages[Object.keys(authorimgdata.query.pages)[0]].pageimage
|
||||
}&origin=*&format=json`,
|
||||
)
|
||||
).json();
|
||||
const license =
|
||||
authorimglicensedata.query.pages[Object.keys(authorimglicensedata.query.pages)[0]]
|
||||
.imageinfo[0].extmetadata.LicenseShortName;
|
||||
const photographer =
|
||||
authorimglicensedata.query.pages[Object.keys(authorimglicensedata.query.pages)[0]]
|
||||
.imageinfo[0].extmetadata.Attribution || 'Unknown';
|
||||
authorimglicense = `© ${photographer.value}. ${license.value}`;
|
||||
if (license.value === 'Public domain') {
|
||||
authorimglicense = null;
|
||||
} else if (photographer.value === 'Unknown' || !photographer) {
|
||||
authorimglicense = null;
|
||||
authorimg = null;
|
||||
}
|
||||
} catch (e) {
|
||||
authorimg = null;
|
||||
authorimglicense = null;
|
||||
}
|
||||
|
||||
return authorlink;
|
||||
if (author === 'Unknown') {
|
||||
authorimg = null;
|
||||
authorimglicense = null;
|
||||
}
|
||||
|
||||
return {
|
||||
authorimg,
|
||||
authorimglicense,
|
||||
};
|
||||
}
|
||||
|
||||
async getQuote() {
|
||||
const offline = (localStorage.getItem('offlineMode') === 'true');
|
||||
const offline = localStorage.getItem('offlineMode') === 'true';
|
||||
|
||||
const favouriteQuote = localStorage.getItem('favouriteQuote');
|
||||
if (favouriteQuote) {
|
||||
let author = favouriteQuote.split(' - ')[1];
|
||||
const authorimgdata = await this.getAuthorImg(author);
|
||||
return this.setState({
|
||||
quote: favouriteQuote.split(' - ')[0],
|
||||
author: favouriteQuote.split(' - ')[1],
|
||||
authorlink: this.getAuthorLink(favouriteQuote.split(' - ')[1])
|
||||
author,
|
||||
authorlink: this.getAuthorLink(author),
|
||||
authorimg: authorimgdata.authorimg,
|
||||
authorimglicense: authorimgdata.authorimglicense,
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -83,21 +170,31 @@ export default class Quote extends PureComponent {
|
|||
customQuote = JSON.parse(localStorage.getItem('customQuote'));
|
||||
} catch (e) {
|
||||
// move to new format
|
||||
customQuote = [{
|
||||
quote: localStorage.getItem('customQuote'),
|
||||
author: localStorage.getItem('customQuoteAuthor')
|
||||
}];
|
||||
customQuote = [
|
||||
{
|
||||
quote: localStorage.getItem('customQuote'),
|
||||
author: localStorage.getItem('customQuoteAuthor'),
|
||||
},
|
||||
];
|
||||
localStorage.setItem('customQuote', JSON.stringify(customQuote));
|
||||
}
|
||||
|
||||
// pick random
|
||||
customQuote = customQuote ? customQuote[Math.floor(Math.random() * customQuote.length)] : null;
|
||||
customQuote = customQuote
|
||||
? customQuote[Math.floor(Math.random() * customQuote.length)]
|
||||
: null;
|
||||
|
||||
if (customQuote && customQuote !== '' && customQuote !== 'undefined' && customQuote !== ['']) {
|
||||
if (
|
||||
customQuote &&
|
||||
customQuote !== '' &&
|
||||
customQuote !== 'undefined' &&
|
||||
customQuote !== ['']
|
||||
) {
|
||||
return this.setState({
|
||||
quote: '"' + customQuote.quote + '"',
|
||||
author: customQuote.author,
|
||||
authorlink: this.getAuthorLink(customQuote.author)
|
||||
authorlink: this.getAuthorLink(customQuote.author),
|
||||
authorimg: await this.getAuthorImg(customQuote.author),
|
||||
});
|
||||
}
|
||||
break;
|
||||
|
@ -111,28 +208,34 @@ export default class Quote extends PureComponent {
|
|||
try {
|
||||
const data = await (await fetch(quotePackAPI.url)).json();
|
||||
const author = data[quotePackAPI.author] || quotePackAPI.author;
|
||||
const authorimgdata = await this.getAuthorImg(author);
|
||||
|
||||
return this.setState({
|
||||
quote: '"' + data[quotePackAPI.quote] + '"',
|
||||
author: author,
|
||||
authorlink: this.getAuthorLink(author)
|
||||
author,
|
||||
authorimg: authorimgdata.authorimg,
|
||||
authorimglicense: authorimgdata.authorimglicense,
|
||||
});
|
||||
} catch (e) {
|
||||
return this.doOffline();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
let quotePack = localStorage.getItem('quote_packs');
|
||||
|
||||
|
||||
if (quotePack !== null) {
|
||||
quotePack = JSON.parse(quotePack);
|
||||
|
||||
|
||||
if (quotePack) {
|
||||
const data = quotePack[Math.floor(Math.random() * quotePack.length)];
|
||||
const authorimgdata = await this.getAuthorImg(data.author);
|
||||
|
||||
return this.setState({
|
||||
quote: '"' + data.quote + '"',
|
||||
author: data.author,
|
||||
authorlink: this.getAuthorLink(data.author)
|
||||
authorlink: this.getAuthorLink(data.author),
|
||||
authorimg: authorimgdata.authorimg,
|
||||
authorimglicense: authorimgdata.authorimglicense,
|
||||
});
|
||||
} else {
|
||||
return this.doOffline();
|
||||
|
@ -147,24 +250,31 @@ export default class Quote extends PureComponent {
|
|||
// First we try and get a quote from the API...
|
||||
try {
|
||||
const quotelanguage = localStorage.getItem('quotelanguage');
|
||||
const data = await (await fetch(variables.constants.API_URL + '/quotes/random?language=' + quotelanguage)).json();
|
||||
const data = await (
|
||||
await fetch(variables.constants.API_URL + '/quotes/random?language=' + quotelanguage)
|
||||
).json();
|
||||
|
||||
// If we hit the ratelimit, we fallback to local quotes
|
||||
// If we hit the ratelimit, we fall back to local quotes
|
||||
if (data.statusCode === 429) {
|
||||
return this.doOffline();
|
||||
}
|
||||
|
||||
const authorimgdata = await this.getAuthorImg(data.author);
|
||||
|
||||
const object = {
|
||||
quote: '"' + data.quote + '"',
|
||||
author: data.author,
|
||||
authorlink: this.getAuthorLink(data.author),
|
||||
quoteLanguage: quotelanguage
|
||||
authorimg: authorimgdata.authorimg,
|
||||
authorimglicense: authorimgdata.authorimglicense,
|
||||
quoteLanguage: quotelanguage,
|
||||
authorOccupation: data.author_occupation,
|
||||
};
|
||||
|
||||
this.setState(object);
|
||||
localStorage.setItem('currentQuote', JSON.stringify(object));
|
||||
} catch (e) {
|
||||
// ..and if that fails we load one locally
|
||||
// ...and if that fails we load one locally
|
||||
this.doOffline();
|
||||
}
|
||||
break;
|
||||
|
@ -181,19 +291,24 @@ export default class Quote extends PureComponent {
|
|||
|
||||
tweetQuote() {
|
||||
variables.stats.postEvent('feature', 'Quote tweet');
|
||||
window.open(`https://twitter.com/intent/tweet?text=${this.state.quote} - ${this.state.author} on @getmue`, '_blank').focus();
|
||||
window
|
||||
.open(
|
||||
`https://twitter.com/intent/tweet?text=${this.state.quote} - ${this.state.author} on @getmue`,
|
||||
'_blank',
|
||||
)
|
||||
.focus();
|
||||
}
|
||||
|
||||
favourite() {
|
||||
if (localStorage.getItem('favouriteQuote')) {
|
||||
localStorage.removeItem('favouriteQuote');
|
||||
this.setState({
|
||||
favourited: this.buttons.unfavourited
|
||||
favourited: this.buttons.unfavourited,
|
||||
});
|
||||
} else {
|
||||
localStorage.setItem('favouriteQuote', this.state.quote + ' - ' + this.state.author);
|
||||
this.setState({
|
||||
favourited: this.buttons.favourited
|
||||
favourited: this.buttons.favourited,
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -205,8 +320,12 @@ export default class Quote extends PureComponent {
|
|||
|
||||
const quoteType = localStorage.getItem('quoteType');
|
||||
|
||||
if (this.state.type !== quoteType || localStorage.getItem('quotelanguage') !== this.state.quoteLanguage || (quoteType === 'custom' && this.state.quote !== localStorage.getItem('customQuote'))
|
||||
|| (quoteType === 'custom' && this.state.author !== localStorage.getItem('customQuoteAuthor'))) {
|
||||
if (
|
||||
this.state.type !== quoteType ||
|
||||
localStorage.getItem('quotelanguage') !== this.state.quoteLanguage ||
|
||||
(quoteType === 'custom' && this.state.quote !== localStorage.getItem('customQuote')) ||
|
||||
(quoteType === 'custom' && this.state.author !== localStorage.getItem('customQuoteAuthor'))
|
||||
) {
|
||||
this.getQuote();
|
||||
}
|
||||
}
|
||||
|
@ -221,7 +340,7 @@ export default class Quote extends PureComponent {
|
|||
EventBus.on('refresh', (data) => {
|
||||
if (data === 'quote') {
|
||||
if (localStorage.getItem('quote') === 'false') {
|
||||
return this.quotediv.current.style.display = 'none';
|
||||
return (this.quotediv.current.style.display = 'none');
|
||||
}
|
||||
|
||||
this.quotediv.current.style.display = 'block';
|
||||
|
@ -230,8 +349,8 @@ export default class Quote extends PureComponent {
|
|||
// buttons hot reload
|
||||
this.setState({
|
||||
favourited: this.useFavourite(),
|
||||
tweet: (localStorage.getItem('tweetButton') === 'false') ? null : this.buttons.tweet,
|
||||
copy: (localStorage.getItem('copyButton') === 'false') ? null : this.buttons.copy
|
||||
share: localStorage.getItem('quoteShareButton') === 'false' ? null : this.buttons.share,
|
||||
copy: localStorage.getItem('copyButton') === 'false' ? null : this.buttons.copy,
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -247,10 +366,14 @@ export default class Quote extends PureComponent {
|
|||
|
||||
const interval = localStorage.getItem('quotechange');
|
||||
if (interval && interval !== 'refresh' && localStorage.getItem('quoteType') === 'api') {
|
||||
Interval(() => {
|
||||
this.setZoom();
|
||||
this.getQuote();
|
||||
}, Number(interval), 'quote');
|
||||
Interval(
|
||||
() => {
|
||||
this.setZoom();
|
||||
this.getQuote();
|
||||
},
|
||||
Number(interval),
|
||||
'quote',
|
||||
);
|
||||
|
||||
try {
|
||||
this.setState(JSON.parse(localStorage.getItem('currentQuote')));
|
||||
|
@ -271,13 +394,62 @@ export default class Quote extends PureComponent {
|
|||
|
||||
render() {
|
||||
return (
|
||||
<div className='quotediv' ref={this.quotediv}>
|
||||
<h1 className='quote' ref={this.quote}>{this.state.quote}</h1>
|
||||
<h1 className='quoteauthor' ref={this.quoteauthor}>
|
||||
<a href={this.state.authorlink} className='quoteauthorlink' target='_blank' rel='noopener noreferrer'>{this.state.author}</a>
|
||||
<br/>
|
||||
{this.state.copy} {this.state.tweet} {this.state.favourited}
|
||||
</h1>
|
||||
<div className="quotediv" ref={this.quotediv}>
|
||||
<span className="quote" ref={this.quote}>
|
||||
{this.state.quote}
|
||||
</span>
|
||||
{localStorage.getItem('widgetStyle') === 'legacy' ? (
|
||||
<>
|
||||
<div>
|
||||
<h1 className="quoteauthor" ref={this.quoteauthor}>
|
||||
<a
|
||||
href={this.state.authorlink}
|
||||
className="quoteAuthorLink"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
{this.state.author}
|
||||
</a>
|
||||
</h1>
|
||||
</div>
|
||||
<div style={{ display: 'flex', justifyContent: 'center', gap: '20px' }}>
|
||||
{this.state.copy} {this.state.share} {this.state.favourited}
|
||||
</div>
|
||||
</>
|
||||
) : (
|
||||
<div className="author-holder">
|
||||
<div className="author">
|
||||
<div
|
||||
className="author-img"
|
||||
style={{ backgroundImage: `url(${this.state.authorimg})` }}
|
||||
>
|
||||
{this.state.authorimg === undefined || this.state.authorimg ? '' : <MdPerson />}
|
||||
</div>
|
||||
<div className="author-content" ref={this.quoteauthor}>
|
||||
<span className="title">{this.state.author}</span>
|
||||
{this.state.authorOccupation !== 'Unknown' ? (
|
||||
<span className="subtitle">{this.state.authorOccupation}</span>
|
||||
) : null}
|
||||
<span className="author-license">{this.state.authorimglicense}</span>
|
||||
</div>
|
||||
<div className="quote-buttons">
|
||||
{this.state.authorOccupation !== 'Unknown' ? (
|
||||
<Tooltip title="Open">
|
||||
<a
|
||||
href={this.state.authorlink}
|
||||
className="quoteAuthorLink"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
<MdOpenInNew />
|
||||
</a>{' '}
|
||||
</Tooltip>
|
||||
) : null}
|
||||
{this.state.copy} {this.state.share} {this.state.favourited}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{/*variables.keybinds.favouriteQuote && variables.keybinds.favouriteQuote !== '' ? <Hotkeys keyName={variables.keybinds.favouriteQuote} onKeyDown={() => this.favourite()} /> : null*/}
|
||||
{/*variables.keybinds.tweetQuote && variables.keybinds.tweetQuote !== '' ? <Hotkeys keyName={variables.keybinds.tweetQuote} onKeyDown={() => this.tweetQuote()} /> : null*/}
|
||||
{/*variables.keybinds.copyQuote && variables.keybinds.copyQuote !== '' ? <Hotkeys keyName={variables.keybinds.copyQuote} onKeyDown={() => this.copyQuote()} /> : null*/}
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue