mirror of
https://github.com/mue/mue.git
synced 2026-07-16 05:23:49 +02:00
Cleanup, refactor and new features
This commit is contained in:
@@ -19,6 +19,7 @@ export default class Checkbox extends React.PureComponent {
|
||||
render() {
|
||||
let text = this.props.text;
|
||||
if (this.props.newFeature) text = <span>{this.props.text} <span className='newFeature'> NEW</span></span>;
|
||||
else if (this.props.betaFeature) text = <span>{this.props.text} <span className='newFeature'> BETA</span></span>;
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
|
||||
@@ -12,7 +12,7 @@ export default class Section extends React.PureComponent {
|
||||
}
|
||||
|
||||
toggleSection() {
|
||||
const display = (this.state.display === 'none') ? 'block': 'none';
|
||||
const display = (this.state.display === 'none') ? 'block' : 'none';
|
||||
|
||||
this.setState({
|
||||
display: display,
|
||||
@@ -26,7 +26,11 @@ export default class Section extends React.PureComponent {
|
||||
let extraHTML, expandMore, slider, noDropdown;
|
||||
|
||||
if (this.props.children) {
|
||||
extraHTML = <li className='extraSettings'>{this.props.children}</li>
|
||||
extraHTML = (
|
||||
<div style={{ display: this.state.display }}>
|
||||
<li className='extraSettings'>{this.props.children}</li>
|
||||
</div>
|
||||
);
|
||||
expandMore = (
|
||||
<ExpandMore
|
||||
style={{ 'transition': 'all 0.5s ease 0s', 'transform': this.state.transform }}
|
||||
@@ -35,16 +39,14 @@ export default class Section extends React.PureComponent {
|
||||
);
|
||||
}
|
||||
if (this.props.slider !== false) slider = <Slider name={this.props.name} />;
|
||||
if (this.props.noDropdown) noDropdown = 'nodropdown';
|
||||
if (this.props.dropdown === false) noDropdown = 'nodropdown';
|
||||
|
||||
return (
|
||||
<div className='section'>
|
||||
<h4 className={noDropdown} onClick={() => this.toggleSection()}>{this.props.title}</h4>
|
||||
{expandMore}
|
||||
{slider}
|
||||
<div style={{ display: this.state.display }}>
|
||||
{extraHTML}
|
||||
</div>
|
||||
{extraHTML}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -194,6 +194,7 @@ export default class BackgroundSettings extends React.PureComponent {
|
||||
<Checkbox name='view' text={this.props.language.background.view} />
|
||||
<Checkbox name='favouriteEnabled' text={this.props.language.background.favourite} />
|
||||
<Checkbox name='refresh' text={this.props.language.background.refresh} />
|
||||
<Checkbox name='webp' text={this.props.language.experimental.webp} betaFeature={true} />
|
||||
</ul>
|
||||
<ul>
|
||||
<Dropdown
|
||||
|
||||
@@ -3,8 +3,9 @@ import SettingsFunctions from '../../../../modules/helpers/settings';
|
||||
import { toast } from 'react-toastify';
|
||||
import Section from '../Section';
|
||||
import Dropdown from '../Dropdown';
|
||||
import Checkbox from '../Checkbox';
|
||||
|
||||
const searchEngines = require('../../../../modules/json/search_engines.json');
|
||||
const searchEngines = require('../../../widgets/search/search_engines.json');
|
||||
|
||||
export default class SearchSettings extends React.PureComponent {
|
||||
resetSearch() {
|
||||
@@ -27,6 +28,9 @@ export default class SearchSettings extends React.PureComponent {
|
||||
render() {
|
||||
return (
|
||||
<Section title={this.props.language.searchbar.title} name='searchBar'>
|
||||
<ul>
|
||||
<Checkbox name='voiceSearch' text={this.props.language.experimental.voice_search} />
|
||||
</ul>
|
||||
<ul>
|
||||
<Dropdown label={this.props.language.searchbar.search_engine}
|
||||
name='searchEngine'
|
||||
@@ -39,7 +43,7 @@ export default class SearchSettings extends React.PureComponent {
|
||||
</Dropdown>
|
||||
</ul>
|
||||
<ul id='searchEngineInput' style={{ display: 'none' }}>
|
||||
<p style={{ "marginTop": "0px" }}>{this.props.language.searchbar.custom} <span className='modalLink' onClick={() => this.resetSearch()}>{this.props.language.reset}</span></p>
|
||||
<p style={{ 'marginTop': '0px' }}>{this.props.language.searchbar.custom} <span className='modalLink' onClick={() => this.resetSearch()}>{this.props.language.reset}</span></p>
|
||||
<input type='text' id='customSearchEngine'></input>
|
||||
</ul>
|
||||
</Section>
|
||||
|
||||
@@ -9,8 +9,12 @@ import SearchSettings from '../settings/sections/SearchSettings';
|
||||
import LanguageSettings from '../settings/sections/LanguageSettings';
|
||||
|
||||
export default class Settings extends React.PureComponent {
|
||||
resetGreeting() {
|
||||
document.getElementById('greetingName').value = '';
|
||||
resetItem(type) {
|
||||
switch (type) {
|
||||
case 'greeting': document.getElementById('greetingName').value = ''; break;
|
||||
case 'css': document.getElementById('customcss').value = ''; break;
|
||||
default: break;
|
||||
}
|
||||
toast(this.props.toastLanguage.reset);
|
||||
}
|
||||
|
||||
@@ -18,6 +22,7 @@ export default class Settings extends React.PureComponent {
|
||||
// Settings
|
||||
document.getElementById('greetingName').value = localStorage.getItem('greetingName');
|
||||
document.getElementById('language').value = localStorage.getItem('language');
|
||||
document.getElementById('customcss').value = localStorage.getItem('customcss');
|
||||
|
||||
if (document.getElementById('modal').classList.contains('dark')) { // Dark theme support for dropdowns
|
||||
const choices = document.getElementsByClassName('choices');
|
||||
@@ -45,13 +50,14 @@ export default class Settings extends React.PureComponent {
|
||||
<Checkbox name='ampm' text={this.props.language.time.ampm} />
|
||||
<Checkbox name='zero' text={this.props.language.time.zero} />
|
||||
<Checkbox name='analog' text={this.props.language.time.analog} />
|
||||
<Checkbox name='percentageComplete' text={this.props.language.time.percentageComplete} />
|
||||
</Section>
|
||||
|
||||
<Section title={this.props.language.greeting.title} name='greeting'>
|
||||
<Checkbox name='events' text={this.props.language.greeting.events} />
|
||||
<Checkbox name='defaultGreetingMessage' text={this.props.language.greeting.default} />
|
||||
<ul>
|
||||
<p>{this.props.language.greeting.name} <span className='modalLink' onClick={() => this.resetGreeting()}>{this.props.language.reset}</span></p>
|
||||
<p>{this.props.language.greeting.name} <span className='modalLink' onClick={() => this.resetItem('greeting')}>{this.props.language.reset}</span></p>
|
||||
<input type='text' id='greetingName'></input>
|
||||
</ul>
|
||||
</Section>
|
||||
@@ -63,17 +69,17 @@ export default class Settings extends React.PureComponent {
|
||||
</Section>
|
||||
|
||||
<BackgroundSettings language={this.props.language} toastLanguage={this.props.toastLanguage} />
|
||||
|
||||
<SearchSettings language={this.props.language} toastLanguage={this.props.toastLanguage} />
|
||||
<Section title={this.props.language.offline} name='offlineMode' dropdown={false} />
|
||||
|
||||
<Section title={this.props.language.offline} name='offlineMode' noDropdown={true} />
|
||||
<Section title={this.props.language.dark} name='darkTheme' noDropdown={true} />
|
||||
|
||||
<Section title={this.props.language.experimental.title} name='experimental' slider={false}>
|
||||
<Checkbox name='webp' text={this.props.language.experimental.webp} />
|
||||
<Checkbox name='animations' text={this.props.language.experimental.animations} />
|
||||
<Checkbox name='voiceSearch' text={this.props.language.experimental.voice_search} newFeature={true} />
|
||||
<Checkbox name='brightnessTime' text={this.props.language.experimental.night_mode} newFeature={true} />
|
||||
<Section title='Appearance' name='appearance' slider={false}>
|
||||
<Checkbox name='animations' text={this.props.language.experimental.animations} betaFeature={true} />
|
||||
<Checkbox name='darkTheme' text={this.props.language.dark} />
|
||||
<Checkbox name='brightnessTime' text={this.props.language.experimental.night_mode} betaFeature={true} />
|
||||
<ul>
|
||||
<p>Custom CSS <span className='modalLink' onClick={() => this.resetItem('css')}>{this.props.language.reset}</span> <span className='newFeature'> NEW</span></p>
|
||||
<textarea id='customcss'></textarea>
|
||||
</ul>
|
||||
</Section>
|
||||
|
||||
<LanguageSettings language={this.props.language} />
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import React from 'react';
|
||||
import * as Constants from '../../modules/constants';
|
||||
import * as Constants from '../../../modules/constants';
|
||||
|
||||
import './scss/index.scss';
|
||||
|
||||
export default class Background extends React.PureComponent {
|
||||
gradientStyleBuilder(gradientSettings) {
|
||||
@@ -46,7 +48,7 @@ export default class Background extends React.PureComponent {
|
||||
}
|
||||
|
||||
doOffline() { // Handles setting the background if the user is offline
|
||||
const offlineImages = require('../../modules/json/offline_images.json');
|
||||
const offlineImages = require('./offline_images.json');
|
||||
const photographers = Object.keys(offlineImages); // Get all photographers from the keys in offlineImages.json
|
||||
const photographer = photographers[Math.floor(Math.random() * photographers.length)]; // Select a random photographer from the keys
|
||||
const randomImage = offlineImages[photographer].photo[
|
||||
@@ -67,7 +69,6 @@ export default class Background extends React.PureComponent {
|
||||
const customBackgroundColour = localStorage.getItem('customBackgroundColour');
|
||||
const customBackground = localStorage.getItem('customBackground');
|
||||
const favourited = JSON.parse(localStorage.getItem('favourite'));
|
||||
const customBackgroundVideo = localStorage.getItem('customBackgroundVideo');
|
||||
|
||||
if (favourited) {
|
||||
if (offlineMode === 'true') return this.doOffline();
|
||||
@@ -82,13 +83,13 @@ export default class Background extends React.PureComponent {
|
||||
document.getElementById('location').textContent = randomPhoto.location;
|
||||
}
|
||||
else if (customBackgroundColour) this.setBackground(null, customBackgroundColour, 'false');
|
||||
else if (customBackground !== '') this.setBackground(customBackground, null, 'false'); // Local
|
||||
else if (customBackgroundVideo) {
|
||||
document.getElementById('backgroundImage').innerHTML = `
|
||||
<video autoplay muted loop id="backgroundVideo">
|
||||
<source src="${customBackgroundVideo}"/>
|
||||
</video>`;
|
||||
document.querySelector('.photoInformation').style.display = 'none'; // Hide the credit
|
||||
else if (customBackground !== '') {
|
||||
if (customBackground.includes('.mp4') || customBackground.includes('.webm') || customBackground.includes('.ogg')) {
|
||||
document.getElementById('backgroundImage').innerHTML = `
|
||||
<video autoplay muted loop id='backgroundVideo'>
|
||||
<source src='${customBackground}'/>
|
||||
</video>`;
|
||||
} else this.setBackground(customBackground, null, 'false'); // Local
|
||||
} else { // Online
|
||||
if (offlineMode === 'true') return this.doOffline();
|
||||
try { // First we try and get an image from the API...
|
||||
@@ -96,9 +97,7 @@ export default class Background extends React.PureComponent {
|
||||
let requestURL;
|
||||
|
||||
switch (localStorage.getItem('backgroundAPI')) {
|
||||
case 'unsplash':
|
||||
requestURL = `${Constants.UNSPLASH_URL}/getImage`;
|
||||
break;
|
||||
case 'unsplash': requestURL = `${Constants.UNSPLASH_URL}/getImage`; break;
|
||||
default: // Defaults to Mue
|
||||
if (localStorage.getItem('supportswebp') === 'true' && enabled === 'true') requestURL = `${Constants.API_URL}/getImage?webp=true`;
|
||||
else requestURL = `${Constants.API_URL}/getImage?category=Outdoors`;
|
||||
20
src/components/widgets/background/offline_images.json
Normal file
20
src/components/widgets/background/offline_images.json
Normal file
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"Tirachard Kumtanom" : {
|
||||
"photo": [1]
|
||||
},
|
||||
"Sohail Na": {
|
||||
"photo": [4]
|
||||
},
|
||||
"Miriam Espacio": {
|
||||
"photo": [7]
|
||||
},
|
||||
"Fabian Wiktor": {
|
||||
"photo": [20]
|
||||
},
|
||||
"Pixabay": {
|
||||
"photo": [2, 3, 9, 11, 13, 14, 15]
|
||||
},
|
||||
"Unknown" : {
|
||||
"photo": [5, 6, 8, 10, 12, 16, 17, 18, 19]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
.photoInformation {
|
||||
position: absolute;
|
||||
bottom: 1rem;
|
||||
left: 1rem;
|
||||
font-size: calc(10px + 0.1vmin) !important;
|
||||
text-shadow: 0 0 10px rgba(0, 0, 0, 0.3);
|
||||
|
||||
svg {
|
||||
float: left;
|
||||
vertical-align: middle;
|
||||
margin-right: 1rem;
|
||||
font-size: calc(10px + 2vmin);
|
||||
}
|
||||
|
||||
span {
|
||||
display: none;
|
||||
}
|
||||
|
||||
h1 {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
svg,
|
||||
h1 {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
svg:hover+.infoCard {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
.infoCard {
|
||||
display: none;
|
||||
background: #fff;
|
||||
box-shadow: 0 0 10px rgba(0, 0, 0, 0.3);
|
||||
color: #000;
|
||||
position: fixed;
|
||||
bottom: 3.25rem;
|
||||
left: 0.7em;
|
||||
padding: 1rem;
|
||||
border-radius: 24px 24px 24px 0;
|
||||
max-width: 500px;
|
||||
text-align: left;
|
||||
text-shadow: none;
|
||||
|
||||
span {
|
||||
display: block;
|
||||
}
|
||||
|
||||
svg {
|
||||
margin-right: 0.5rem;
|
||||
vertical-align: middle;
|
||||
display: inline-flex;
|
||||
padding: 2px;
|
||||
}
|
||||
|
||||
span,
|
||||
svg {
|
||||
font-size: 2em;
|
||||
}
|
||||
|
||||
h1,
|
||||
.infoIcon {
|
||||
font-size: 3em;
|
||||
}
|
||||
|
||||
.infoIcon {
|
||||
padding: 4px;
|
||||
}
|
||||
|
||||
hr {
|
||||
height: 3px;
|
||||
background: #2d3436;
|
||||
outline: none;
|
||||
border: none;
|
||||
}
|
||||
}
|
||||
|
||||
.infoCard:hover {
|
||||
display: block !important;
|
||||
}
|
||||
|
||||
.photoInformationHover {
|
||||
cursor: pointer;
|
||||
}
|
||||
69
src/components/widgets/background/scss/index.scss
Normal file
69
src/components/widgets/background/scss/index.scss
Normal file
@@ -0,0 +1,69 @@
|
||||
@import 'photoinformation';
|
||||
@import '../../../../scss/mixins';
|
||||
|
||||
#backgroundImage {
|
||||
height: 100vh;
|
||||
background-size: cover;
|
||||
background-repeat: no-repeat;
|
||||
background-position: center;
|
||||
background-attachment: fixed;
|
||||
}
|
||||
|
||||
#backgroundVideo {
|
||||
position: fixed;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
min-width: 100%;
|
||||
min-height: 100%;
|
||||
}
|
||||
|
||||
.fade-in {
|
||||
@include animation('fadein 2s');
|
||||
}
|
||||
|
||||
@include keyframes(fadein) {
|
||||
from {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
to {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.backgroundEffects {
|
||||
opacity: 0.7;
|
||||
transition: ease 0.6s;
|
||||
}
|
||||
|
||||
.creditlink {
|
||||
text-decoration: none;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.view {
|
||||
bottom: 10px;
|
||||
right: 25px;
|
||||
}
|
||||
|
||||
.favourite {
|
||||
bottom: 10px;
|
||||
right: 50px;
|
||||
padding-right: 5px;
|
||||
}
|
||||
|
||||
.view,
|
||||
.favourite {
|
||||
position: absolute;
|
||||
transition: all 0.5s ease 0s;
|
||||
|
||||
&:hover {
|
||||
transform: scale(1.1);
|
||||
}
|
||||
}
|
||||
|
||||
#viewButton,
|
||||
#favouriteButton {
|
||||
width: auto;
|
||||
cursor: pointer;
|
||||
}
|
||||
@@ -1,5 +1,7 @@
|
||||
import React from 'react';
|
||||
|
||||
import './greeting.scss';
|
||||
|
||||
export default class Greeting extends React.PureComponent {
|
||||
constructor(...args) {
|
||||
super(...args);
|
||||
4
src/components/widgets/greeting/greeting.scss
Normal file
4
src/components/widgets/greeting/greeting.scss
Normal file
@@ -0,0 +1,4 @@
|
||||
.greeting {
|
||||
margin: 0;
|
||||
font-size: 1.6em;
|
||||
}
|
||||
@@ -5,9 +5,11 @@ import NewReleases from '@material-ui/icons/NewReleasesRounded';
|
||||
import NotesIcon from '@material-ui/icons/AssignmentRounded';
|
||||
import Tooltip from '@material-ui/core/Tooltip';
|
||||
import Report from '@material-ui/icons/SmsFailed';
|
||||
import * as Constants from '../modules/constants';
|
||||
import * as Constants from '../../../modules/constants';
|
||||
|
||||
const Notes = React.lazy(() => import('./widgets/Notes')); // the user probably won't use the notes feature every time so we lazy load
|
||||
import './scss/index.scss';
|
||||
|
||||
const Notes = React.lazy(() => import('./Notes')); // the user probably won't use the notes feature every time so we lazy load
|
||||
const renderLoader = () => <div></div>;
|
||||
|
||||
export default class Navbar extends React.PureComponent {
|
||||
@@ -1,7 +1,7 @@
|
||||
import React from 'react';
|
||||
import TextareaAutosize from '@material-ui/core/TextareaAutosize';
|
||||
import CopyIcon from '@material-ui/icons/FileCopyRounded';
|
||||
import Pin from './icons/Pin';
|
||||
import Pin from './Pin';
|
||||
import NotesIcon from '@material-ui/icons/AssignmentRounded';
|
||||
|
||||
export default class Notes extends React.PureComponent {
|
||||
80
src/components/widgets/navbar/scss/_notes.scss
Normal file
80
src/components/widgets/navbar/scss/_notes.scss
Normal file
@@ -0,0 +1,80 @@
|
||||
.notes {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
|
||||
h3 {
|
||||
text-shadow: none;
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.notes .notescontainer {
|
||||
text-align: center;
|
||||
padding: 15px;
|
||||
visibility: hidden;
|
||||
background-color: #fff;
|
||||
color: #000;
|
||||
text-align: center;
|
||||
border-radius: 12px;
|
||||
position: absolute;
|
||||
z-index: 1;
|
||||
top: 80%;
|
||||
left: 50%;
|
||||
margin-left: -125px;
|
||||
|
||||
input[type=text] {
|
||||
border: none;
|
||||
color: #2d3436;
|
||||
}
|
||||
|
||||
svg,
|
||||
input[type=text] {
|
||||
display: inline-flex;
|
||||
}
|
||||
|
||||
svg {
|
||||
float: left;
|
||||
}
|
||||
|
||||
::placeholder {
|
||||
color: #636e72;
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.notes:hover .notescontainer {
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
textarea {
|
||||
overflow: none;
|
||||
border: none;
|
||||
outline: none;
|
||||
width: 200px;
|
||||
resize: none;
|
||||
height: 100px;
|
||||
margin: 10px;
|
||||
}
|
||||
|
||||
.noteIcon {
|
||||
display: inline;
|
||||
font-size: 1em;
|
||||
float: none;
|
||||
}
|
||||
|
||||
.topbarnotes {
|
||||
text-align: center;
|
||||
|
||||
svg {
|
||||
font-size: 48px;
|
||||
float: left !important;
|
||||
padding: 9px;
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: 48px;
|
||||
float: right;
|
||||
margin-right: 20px;
|
||||
}
|
||||
}
|
||||
71
src/components/widgets/navbar/scss/index.scss
Normal file
71
src/components/widgets/navbar/scss/index.scss
Normal file
@@ -0,0 +1,71 @@
|
||||
@import 'notes';
|
||||
@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');
|
||||
-webkit-font-smoothing: subpixel-antialiased;
|
||||
font-size: 1em;
|
||||
display: inline;
|
||||
margin: 0.5rem;
|
||||
filter: drop-shadow(0 0 6px rgba(0, 0, 0, 0.3));
|
||||
cursor: pointer;
|
||||
transition: .2s ease;
|
||||
|
||||
&:hover {
|
||||
color: map-get($theme-colours, 'main-text-color');
|
||||
transform: translateZ(0);
|
||||
transform: scale(1.3);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.bottom-navbar {
|
||||
position: absolute;
|
||||
bottom: 1rem;
|
||||
right: 1rem;
|
||||
|
||||
div {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
img {
|
||||
height: 1em;
|
||||
width: auto;
|
||||
margin: 0.5rem;
|
||||
}
|
||||
|
||||
svg.topicons {
|
||||
color: map-get($theme-colours, 'main-text-color');
|
||||
-webkit-font-smoothing: subpixel-antialiased;
|
||||
font-size: 1em;
|
||||
display: inline;
|
||||
margin: 0.5rem;
|
||||
filter: drop-shadow(0 0 6px rgba(0, 0, 0, 0.3));
|
||||
cursor: pointer;
|
||||
transition: .2s ease;
|
||||
|
||||
&:hover {
|
||||
transform: translateZ(0);
|
||||
transform: scale(1.3);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.visibilityshow {
|
||||
visibility: visible !important;
|
||||
}
|
||||
@@ -2,11 +2,13 @@ import React from 'react';
|
||||
import Quotes from '@muetab/quotes';
|
||||
import FileCopy from '@material-ui/icons/FilterNone';
|
||||
import { toast } from 'react-toastify';
|
||||
import * as Constants from '../../modules/constants';
|
||||
import * as Constants from '../../../modules/constants';
|
||||
import TwitterIcon from '@material-ui/icons/Twitter';
|
||||
import StarIcon from '@material-ui/icons/Star';
|
||||
import StarIcon2 from '@material-ui/icons/StarBorder';
|
||||
|
||||
import './quote.scss';
|
||||
|
||||
export default class Quote extends React.PureComponent {
|
||||
constructor(...args) {
|
||||
super(...args);
|
||||
59
src/components/widgets/quote/quote.scss
Normal file
59
src/components/widgets/quote/quote.scss
Normal file
@@ -0,0 +1,59 @@
|
||||
@import '../../../scss/variables';
|
||||
|
||||
.quote {
|
||||
font-size: 0.8em;
|
||||
text-shadow: 0 0 10px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
@media screen and (min-width: 600px) {
|
||||
.quote {
|
||||
margin-left: 30%;
|
||||
margin-right: 30%;
|
||||
}
|
||||
}
|
||||
|
||||
.quoteauthor {
|
||||
font-size: 0.9em;
|
||||
letter-spacing: 0.5px;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.quoteAuthor,
|
||||
.copyButton {
|
||||
display: inline;
|
||||
font-size: 0.8em;
|
||||
position: relative !important;
|
||||
display: block;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.copyButton {
|
||||
cursor: pointer;
|
||||
vertical-align: middle;
|
||||
float: middle;
|
||||
margin: 0 auto;
|
||||
text-align: right;
|
||||
transition: ease 0.2s !important;
|
||||
|
||||
&:hover {
|
||||
transform: scale(1.1);
|
||||
}
|
||||
}
|
||||
|
||||
i.material-icons,
|
||||
h1.quoteauthor {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
button.copyButton {
|
||||
background: transparent;
|
||||
border: none;
|
||||
color: map-get($theme-colours, 'main');
|
||||
padding: 20px 20px;
|
||||
text-align: center;
|
||||
text-decoration: none;
|
||||
font-size: 20px;
|
||||
cursor: pointer;
|
||||
border-radius: 5px;
|
||||
display: table-cell
|
||||
}
|
||||
@@ -2,7 +2,9 @@ import React from 'react';
|
||||
import SearchIcon from '@material-ui/icons/Search';
|
||||
import MicIcon from '@material-ui/icons/Mic';
|
||||
|
||||
const searchEngines = require('../../modules/json/search_engines.json');
|
||||
import './search.scss';
|
||||
|
||||
const searchEngines = require('./search_engines.json');
|
||||
|
||||
export default class Search extends React.PureComponent {
|
||||
constructor(...args) {
|
||||
48
src/components/widgets/search/search.scss
Normal file
48
src/components/widgets/search/search.scss
Normal file
@@ -0,0 +1,48 @@
|
||||
@import '../../../scss/variables';
|
||||
|
||||
.searchbar {
|
||||
position: absolute;
|
||||
left: 20px;
|
||||
top: 20px;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
display: block;
|
||||
color: map-get($theme-colours, 'main-text-color');
|
||||
|
||||
input[type=text] {
|
||||
width: 140px;
|
||||
margin-left: 12px;
|
||||
border-radius: 24px;
|
||||
font-size: calc(5px + 1.2vmin);
|
||||
background: transparent;
|
||||
border: none;
|
||||
position: absolute;
|
||||
background-color: rgba(0, 0, 0, 0.1);
|
||||
-webkit-transition: width 0.5s ease-in-out;
|
||||
transition: width 0.5s ease-in-out;
|
||||
|
||||
&:focus {
|
||||
width: 400px;
|
||||
background-color: rgba(0, 0, 0, .3);
|
||||
}
|
||||
}
|
||||
|
||||
.MuiSvgIcon-root {
|
||||
margin-top: 4px;
|
||||
font-size: 30px;
|
||||
filter: drop-shadow(0 0 6px rgba(0, 0, 0, 0.3));
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
.input.searchtext {
|
||||
border: none;
|
||||
}
|
||||
|
||||
.micIcon {
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
#searchEngine {
|
||||
width: 130px;
|
||||
}
|
||||
48
src/components/widgets/search/search_engines.json
Normal file
48
src/components/widgets/search/search_engines.json
Normal file
@@ -0,0 +1,48 @@
|
||||
[
|
||||
{
|
||||
"name": "DuckDuckGo",
|
||||
"settingsName": "duckduckgo",
|
||||
"url": "https://duckduckgo.com"
|
||||
},
|
||||
{
|
||||
"name": "Google",
|
||||
"settingsName": "google",
|
||||
"url": "https://google.com/search"
|
||||
},
|
||||
{
|
||||
"name": "Bing",
|
||||
"settingsName": "bing",
|
||||
"url": "https://bing.com/search"
|
||||
},
|
||||
{
|
||||
"name": "Yahoo",
|
||||
"settingsName": "yahoo",
|
||||
"url": "https://search.yahoo.com/search"
|
||||
},
|
||||
{
|
||||
"name": "Ecosia",
|
||||
"settingsName": "ecosia",
|
||||
"url": "https://ecosia.org/search"
|
||||
},
|
||||
{
|
||||
"name": "Яндекс",
|
||||
"settingsName": "yandex",
|
||||
"url": "https://yandex.ru/search",
|
||||
"query": "text"
|
||||
},
|
||||
{
|
||||
"name": "Qwant",
|
||||
"settingsName": "qwant",
|
||||
"url": "https://www.qwant.com/"
|
||||
},
|
||||
{
|
||||
"name": "Ask",
|
||||
"settingsName": "ask",
|
||||
"url": "https://ask.com/web"
|
||||
},
|
||||
{
|
||||
"name": "Startpage",
|
||||
"settingsName": "startpage",
|
||||
"url": "https://www.startpage.com/sp/search"
|
||||
}
|
||||
]
|
||||
@@ -1,6 +1,8 @@
|
||||
import React from 'react';
|
||||
import Analog from 'react-clock';
|
||||
|
||||
import './clock.scss';
|
||||
|
||||
export default class Clock extends React.PureComponent {
|
||||
constructor(...args) {
|
||||
super(...args);
|
||||
@@ -17,14 +19,12 @@ export default class Clock extends React.PureComponent {
|
||||
const now = new Date();
|
||||
|
||||
// Percentage
|
||||
if (localStorage.getItem('percentageComplete') === 'true') {
|
||||
return this.setState({ time: (now.getHours() / 24).toFixed(2) + '%'})
|
||||
}
|
||||
if (localStorage.getItem('percentageComplete') === 'true') return this.setState({ time: (now.getHours() / 24).toFixed(2).replace('0.', '') + '%'});
|
||||
|
||||
// Analog clock
|
||||
if (localStorage.getItem('analog') === 'true') this.setState({ time: now });
|
||||
else {
|
||||
let sec = '';
|
||||
let time, sec = '';
|
||||
|
||||
// Extra 0
|
||||
const zero = localStorage.getItem('zero');
|
||||
@@ -35,7 +35,6 @@ export default class Clock extends React.PureComponent {
|
||||
}
|
||||
|
||||
if (localStorage.getItem('24hour') === 'true') {
|
||||
let time = '';
|
||||
if (zero === 'false') time = `${now.getHours()}:${now.getMinutes()}${sec}`;
|
||||
else time = `${('00' + now.getHours()).slice(-2)}:${('00' + now.getMinutes()).slice(-2)}${sec}`;
|
||||
|
||||
@@ -49,7 +48,6 @@ export default class Clock extends React.PureComponent {
|
||||
let ampm = now.getHours() > 11 ? 'PM' : 'AM';
|
||||
if (localStorage.getItem('ampm') === 'false') ampm = '';
|
||||
|
||||
let time = '';
|
||||
if (zero === 'false') time = `${hours}:${now.getMinutes()}${sec}`;
|
||||
else time = `${('00' + hours).slice(-2)}:${('00' + now.getMinutes()).slice(-2)}${sec}`;
|
||||
|
||||
@@ -11,15 +11,16 @@ export default class DateWidget extends React.PureComponent {
|
||||
|
||||
getDate() {
|
||||
const date = new Date();
|
||||
const dateFormat = localStorage.getItem('dateFormat');
|
||||
|
||||
if (localStorage.getItem('dateFormat') === 'short') {
|
||||
if (dateFormat === 'short') {
|
||||
const dateDay = date.getDate();
|
||||
const dateMonth = date.getMonth() + 1;
|
||||
const dateYear = date.getFullYear();
|
||||
|
||||
let day = dateDay, month = dateMonth, year = dateYear;
|
||||
|
||||
switch (localStorage.getItem('dateFormat')) {
|
||||
switch (dateFormat) {
|
||||
case 'MDY':
|
||||
day = dateMonth;
|
||||
month = dateDay;
|
||||
@@ -28,8 +29,7 @@ export default class DateWidget extends React.PureComponent {
|
||||
day = dateYear;
|
||||
year = dateDay;
|
||||
break;
|
||||
default: // DMY
|
||||
break;
|
||||
default: break; // DMY
|
||||
}
|
||||
|
||||
let format;
|
||||
@@ -58,6 +58,6 @@ export default class DateWidget extends React.PureComponent {
|
||||
}
|
||||
|
||||
render() {
|
||||
return <span style={{ 'textTransform': 'capitalize', 'fontWeight': 'bold'}}>{this.state.date}</span>
|
||||
return <span style={{ 'textTransform': 'capitalize', 'fontWeight': 'bold' }}>{this.state.date}</span>
|
||||
}
|
||||
}
|
||||
24
src/components/widgets/time/clock.scss
Normal file
24
src/components/widgets/time/clock.scss
Normal file
@@ -0,0 +1,24 @@
|
||||
@import '../../../scss/variables';
|
||||
|
||||
.clock {
|
||||
font-size: 4em;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.ampm {
|
||||
font-size: 0.5em;
|
||||
}
|
||||
|
||||
.analogclock,
|
||||
.react-clock__face {
|
||||
margin: 0 auto;
|
||||
border-radius: 100%;
|
||||
box-shadow: inset 0 0 100px rgba(0, 0, 0, 0.3);
|
||||
border: 1px solid map-get($theme-colours, "main");
|
||||
}
|
||||
|
||||
.react-clock__hand__body {
|
||||
background: map-get($theme-colours, "main");
|
||||
;
|
||||
box-shadow: 0 0 25px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
Reference in New Issue
Block a user