Refactor
This commit is contained in:
parent
4f6f479134
commit
3a337e6408
20 changed files with 631 additions and 358 deletions
39
src/App.js
39
src/App.js
|
@ -1,14 +1,13 @@
|
|||
import React from 'react';
|
||||
import styled, { createGlobalStyle } from 'styled-components';
|
||||
|
||||
import SearchBar from './components/searchBar'
|
||||
import Greeter from './components/greeter'
|
||||
import AppList from './components/appList'
|
||||
import BookmarkList from './components/bookmarkList'
|
||||
import SettingsModal from './components/settingsModal'
|
||||
import SearchBar from './components/searchBar';
|
||||
import Greeter from './components/greeter';
|
||||
import AppList from './components/appList';
|
||||
import BookmarkList from './components/bookmarkList';
|
||||
import SettingsModal from './components/settingsModal';
|
||||
|
||||
import themeData from './components/data/themes.json';
|
||||
const selectedTheme = localStorage.getItem("theme") ? JSON.parse(localStorage.getItem("theme")) : themeData.themes[0];
|
||||
import { selectedTheme } from './selectedTheme';
|
||||
|
||||
const GlobalStyle = createGlobalStyle`
|
||||
body {
|
||||
|
@ -17,22 +16,22 @@ const GlobalStyle = createGlobalStyle`
|
|||
`;
|
||||
|
||||
const AppContainer = styled.div`
|
||||
max-width: 80%;
|
||||
margin: auto;
|
||||
padding: 10px;
|
||||
max-width: 80%;
|
||||
margin: auto;
|
||||
padding: 10px;
|
||||
`;
|
||||
|
||||
const App = () => (
|
||||
<>
|
||||
<GlobalStyle />
|
||||
<AppContainer>
|
||||
<SearchBar />
|
||||
<SettingsModal />
|
||||
<Greeter />
|
||||
<AppList />
|
||||
<BookmarkList />
|
||||
</AppContainer>
|
||||
</>
|
||||
<>
|
||||
<GlobalStyle />
|
||||
<AppContainer>
|
||||
<SearchBar />
|
||||
<SettingsModal />
|
||||
<Greeter />
|
||||
<AppList />
|
||||
<BookmarkList />
|
||||
</AppContainer>
|
||||
</>
|
||||
);
|
||||
|
||||
export default App;
|
||||
|
|
|
@ -1,11 +1,9 @@
|
|||
import React from 'react';
|
||||
import React, { useCallback, useEffect, useState } from 'react';
|
||||
import MaterialIcon from 'material-icons-react';
|
||||
import styled from 'styled-components';
|
||||
|
||||
import appData from './data/apps.json';
|
||||
|
||||
import themeData from './data/themes.json'
|
||||
const selectedTheme = localStorage.getItem("theme") ? JSON.parse(localStorage.getItem("theme")) : themeData.themes[0];
|
||||
import { Button } from './button';
|
||||
import { selectedTheme } from '../selectedTheme';
|
||||
|
||||
const AppListContainer = styled.div`
|
||||
padding: 2rem 0 2rem 0;
|
||||
|
@ -69,25 +67,69 @@ const Description = styled.p`
|
|||
color: ${selectedTheme.accentColor};
|
||||
`;
|
||||
|
||||
const appList = () => (
|
||||
<AppListContainer>
|
||||
<ApplicationsText>Applications</ApplicationsText>
|
||||
<AppsContainer>
|
||||
{
|
||||
appData.apps.map((app) => (
|
||||
<AppContainer>
|
||||
<IconContainer>
|
||||
<MaterialIcon icon={app.icon} color={selectedTheme.mainColor}/>
|
||||
</IconContainer>
|
||||
<AppDetails>
|
||||
<Link href={app.URL}>{app.name}</Link>
|
||||
<Description>{app.displayURL}</Description>
|
||||
</AppDetails>
|
||||
</AppContainer>
|
||||
))
|
||||
}
|
||||
</AppsContainer>
|
||||
</AppListContainer>
|
||||
);
|
||||
const ErrorMessage = styled.p`
|
||||
color: red;
|
||||
`;
|
||||
|
||||
export default appList;
|
||||
function handleResponse(response) {
|
||||
if (response.ok) {
|
||||
return response.json();
|
||||
}
|
||||
throw new Error('Failed to load app data.');
|
||||
}
|
||||
|
||||
function useAppData() {
|
||||
const [appData, setAppData] = useState({ apps: [], error: false });
|
||||
const fetchAppData = useCallback(() => {
|
||||
(process.env.NODE_ENV === 'production'
|
||||
? fetch('/apps.json').then(handleResponse)
|
||||
: import('./data/apps.json')
|
||||
)
|
||||
.then((jsonResponse) => {
|
||||
setAppData({ ...jsonResponse, error: false });
|
||||
})
|
||||
.catch((error) => {
|
||||
setAppData({ apps: [], error: error.message });
|
||||
});
|
||||
}, []);
|
||||
useEffect(() => {
|
||||
fetchAppData();
|
||||
}, [fetchAppData]);
|
||||
return { appData, fetchAppData };
|
||||
}
|
||||
|
||||
const AppList = () => {
|
||||
const {
|
||||
appData: { apps, error },
|
||||
fetchAppData,
|
||||
} = useAppData();
|
||||
return (
|
||||
<AppListContainer>
|
||||
<ApplicationsText>
|
||||
Applications <Button onClick={fetchAppData}>refresh</Button>
|
||||
</ApplicationsText>
|
||||
<AppsContainer>
|
||||
{error && <ErrorMessage>{error}</ErrorMessage>}
|
||||
{apps.map((app, idx) => {
|
||||
const { name } = app;
|
||||
return (
|
||||
<AppContainer key={[name, idx].join('')}>
|
||||
<IconContainer>
|
||||
<MaterialIcon
|
||||
icon={app.icon}
|
||||
color={selectedTheme.mainColor}
|
||||
/>
|
||||
</IconContainer>
|
||||
<AppDetails>
|
||||
<Link href={app.URL}>{app.name}</Link>
|
||||
<Description>{app.displayURL}</Description>
|
||||
</AppDetails>
|
||||
</AppContainer>
|
||||
);
|
||||
})}
|
||||
</AppsContainer>
|
||||
</AppListContainer>
|
||||
);
|
||||
};
|
||||
|
||||
export default AppList;
|
||||
|
|
|
@ -3,8 +3,7 @@ import styled from 'styled-components';
|
|||
|
||||
import bookmarkData from './data/bookmarks.json';
|
||||
|
||||
import themeData from './data/themes.json'
|
||||
const selectedTheme = localStorage.getItem("theme") ? JSON.parse(localStorage.getItem("theme")) : themeData.themes[0];
|
||||
import { selectedTheme } from '../selectedTheme';
|
||||
|
||||
const BookmarksText = styled.h3`
|
||||
font-family: Roboto, sans-serif;
|
||||
|
@ -54,26 +53,24 @@ const Bookmark = styled.a`
|
|||
font-size: 14px;
|
||||
`;
|
||||
|
||||
const bookmarkList = () => (
|
||||
const BookmarkList = () => (
|
||||
<BookmarkListContainer>
|
||||
<BookmarksText>Bookmarks</BookmarksText>
|
||||
<BookmarksContainer>
|
||||
|
||||
{
|
||||
bookmarkData.groups.map((group) => (
|
||||
<BookmarkGroupContainer>
|
||||
<GroupText>{group.name}</GroupText>
|
||||
{
|
||||
group.items.map((link) => (
|
||||
<Bookmark href={link.url}>{link.name}</Bookmark>
|
||||
))
|
||||
}
|
||||
</BookmarkGroupContainer>
|
||||
))
|
||||
}
|
||||
|
||||
{bookmarkData.groups.map(({ name, items }) => {
|
||||
return (
|
||||
<BookmarkGroupContainer key={name}>
|
||||
<GroupText>{name}</GroupText>
|
||||
{items.map(({ url, name: linkName }) => (
|
||||
<Bookmark key={linkName} href={url}>
|
||||
{linkName}
|
||||
</Bookmark>
|
||||
))}
|
||||
</BookmarkGroupContainer>
|
||||
);
|
||||
})}
|
||||
</BookmarksContainer>
|
||||
</BookmarkListContainer>
|
||||
);
|
||||
|
||||
export default bookmarkList;
|
||||
export default BookmarkList;
|
||||
|
|
13
src/components/button.js
Normal file
13
src/components/button.js
Normal file
|
@ -0,0 +1,13 @@
|
|||
import styled from 'styled-components';
|
||||
import { selectedTheme } from '../selectedTheme';
|
||||
|
||||
export const Button = styled.button`
|
||||
font-family: Roboto, sans-serif;
|
||||
text-transform: uppercase;
|
||||
font-weight: 400;
|
||||
border: 1px solid ${selectedTheme.mainColor};
|
||||
color: ${selectedTheme.mainColor};
|
||||
background: none;
|
||||
margin-left: 1rem;
|
||||
min-height: 3em;
|
||||
`;
|
|
@ -55,4 +55,4 @@
|
|||
"icon": "show_chart"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -137,4 +137,4 @@
|
|||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,64 +1,64 @@
|
|||
{
|
||||
"providers":[
|
||||
{
|
||||
"name":"Allmusic",
|
||||
"url":"https://www.allmusic.com/search/all/",
|
||||
"prefix":"/a"
|
||||
},
|
||||
{
|
||||
"name":"Discogs",
|
||||
"url":"https://www.discogs.com/search/?q=",
|
||||
"prefix":"/di"
|
||||
},
|
||||
{
|
||||
"name":"Duck Duck Go",
|
||||
"url":"https://duckduckgo.com/?q=",
|
||||
"prefix":"/d"
|
||||
},
|
||||
{
|
||||
"name":"iMDB",
|
||||
"url":"https://www.imdb.com/find?q=",
|
||||
"prefix":"/i"
|
||||
},
|
||||
{
|
||||
"name":"TheMovieDB",
|
||||
"url":"https://www.themoviedb.org/search?query=",
|
||||
"prefix":"/m"
|
||||
},
|
||||
{
|
||||
"name":"Reddit",
|
||||
"url":"https://www.reddit.com/search?q=",
|
||||
"prefix":"/r"
|
||||
},
|
||||
{
|
||||
"name":"Qwant",
|
||||
"url":"https://www.qwant.com/?q=",
|
||||
"prefix":"/q"
|
||||
},
|
||||
{
|
||||
"name":"Soundcloud",
|
||||
"url":"https://soundcloud.com/search?q=",
|
||||
"prefix":"/so"
|
||||
},
|
||||
{
|
||||
"name":"Spotify",
|
||||
"url":"https://open.spotify.com/search/results/",
|
||||
"prefix":"/s"
|
||||
},
|
||||
{
|
||||
"name":"TheTVDB",
|
||||
"url":"https://www.thetvdb.com/search?q=",
|
||||
"prefix":"/tv"
|
||||
},
|
||||
{
|
||||
"name":"Trakt",
|
||||
"url":"https://trakt.tv/search?query=",
|
||||
"prefix":"/t"
|
||||
},
|
||||
{
|
||||
"name": "YouTube",
|
||||
"url": "https://youtube.com/results?search_query=",
|
||||
"prefix":"/yt"
|
||||
}
|
||||
"providers": [
|
||||
{
|
||||
"name": "Allmusic",
|
||||
"url": "https://www.allmusic.com/search/all/",
|
||||
"prefix": "/a"
|
||||
},
|
||||
{
|
||||
"name": "Discogs",
|
||||
"url": "https://www.discogs.com/search/?q=",
|
||||
"prefix": "/di"
|
||||
},
|
||||
{
|
||||
"name": "Duck Duck Go",
|
||||
"url": "https://duckduckgo.com/?q=",
|
||||
"prefix": "/d"
|
||||
},
|
||||
{
|
||||
"name": "iMDB",
|
||||
"url": "https://www.imdb.com/find?q=",
|
||||
"prefix": "/i"
|
||||
},
|
||||
{
|
||||
"name": "TheMovieDB",
|
||||
"url": "https://www.themoviedb.org/search?query=",
|
||||
"prefix": "/m"
|
||||
},
|
||||
{
|
||||
"name": "Reddit",
|
||||
"url": "https://www.reddit.com/search?q=",
|
||||
"prefix": "/r"
|
||||
},
|
||||
{
|
||||
"name": "Qwant",
|
||||
"url": "https://www.qwant.com/?q=",
|
||||
"prefix": "/q"
|
||||
},
|
||||
{
|
||||
"name": "Soundcloud",
|
||||
"url": "https://soundcloud.com/search?q=",
|
||||
"prefix": "/so"
|
||||
},
|
||||
{
|
||||
"name": "Spotify",
|
||||
"url": "https://open.spotify.com/search/results/",
|
||||
"prefix": "/s"
|
||||
},
|
||||
{
|
||||
"name": "TheTVDB",
|
||||
"url": "https://www.thetvdb.com/search?q=",
|
||||
"prefix": "/tv"
|
||||
},
|
||||
{
|
||||
"name": "Trakt",
|
||||
"url": "https://trakt.tv/search?query=",
|
||||
"prefix": "/t"
|
||||
},
|
||||
{
|
||||
"name": "YouTube",
|
||||
"url": "https://youtube.com/results?search_query=",
|
||||
"prefix": "/yt"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,4 +22,4 @@
|
|||
"backgroundColor": "#ffffff"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
import React from 'react';
|
||||
import styled from 'styled-components';
|
||||
|
||||
import themeData from './data/themes.json'
|
||||
const selectedTheme = localStorage.getItem("theme") ? JSON.parse(localStorage.getItem("theme")) : themeData.themes[0];
|
||||
import { selectedTheme } from '../selectedTheme';
|
||||
|
||||
const GreeterContainer = styled.div`
|
||||
padding: 2rem 0 2rem 0;
|
||||
|
@ -27,47 +26,75 @@ const DateText = styled.h3`
|
|||
|
||||
const getGreeting = () => {
|
||||
// Maybe add some expandability for different greetings?
|
||||
return "Hello World!"
|
||||
}
|
||||
return 'Hello World!';
|
||||
};
|
||||
|
||||
const getExtension = (day) => {
|
||||
let extension = ""
|
||||
let extension = '';
|
||||
|
||||
if ((day > 4 && day <= 20) || (day > 20 && day % 10 >= 4)) {
|
||||
extension = "th"
|
||||
extension = 'th';
|
||||
} else if (day % 10 === 1) {
|
||||
extension = "st"
|
||||
extension = 'st';
|
||||
} else if (day % 10 === 2) {
|
||||
extension = "nd"
|
||||
extension = 'nd';
|
||||
} else if (day % 10 === 3) {
|
||||
extension = "rd"
|
||||
extension = 'rd';
|
||||
}
|
||||
|
||||
return extension
|
||||
}
|
||||
return extension;
|
||||
};
|
||||
|
||||
const monthNames = [
|
||||
'January',
|
||||
'February',
|
||||
'March',
|
||||
'April',
|
||||
'May',
|
||||
'June',
|
||||
'July',
|
||||
'August',
|
||||
'September',
|
||||
'October',
|
||||
'November',
|
||||
'December',
|
||||
];
|
||||
|
||||
const weekDayNames = [
|
||||
'Sunday',
|
||||
'Monday',
|
||||
'Tuesday',
|
||||
'Wednesday',
|
||||
'Thursday',
|
||||
'Friday',
|
||||
'Saturday',
|
||||
];
|
||||
|
||||
const getDateString = () => {
|
||||
let currentDate = new Date();
|
||||
|
||||
const monthNames = [ "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" ];
|
||||
|
||||
const weekDayNames = [ "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" ];
|
||||
|
||||
return weekDayNames[currentDate.getUTCDay()] + ", " + monthNames[currentDate.getUTCMonth()] + " " + currentDate.getDate() + getExtension(currentDate.getDate()) + " " + currentDate.getFullYear();
|
||||
}
|
||||
|
||||
const greeter = () => {
|
||||
return (
|
||||
weekDayNames[currentDate.getUTCDay()] +
|
||||
', ' +
|
||||
monthNames[currentDate.getUTCMonth()] +
|
||||
' ' +
|
||||
currentDate.getDate() +
|
||||
getExtension(currentDate.getDate()) +
|
||||
' ' +
|
||||
currentDate.getFullYear()
|
||||
);
|
||||
};
|
||||
|
||||
const Greeter = () => {
|
||||
let date = getDateString();
|
||||
let greeting = getGreeting();
|
||||
|
||||
return (
|
||||
<GreeterContainer>
|
||||
<DateText>{ date }</DateText>
|
||||
<GreetText>{ greeting }</GreetText>
|
||||
<DateText>{date}</DateText>
|
||||
<GreetText>{greeting}</GreetText>
|
||||
</GreeterContainer>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
export default greeter;
|
||||
export default Greeter;
|
||||
|
|
|
@ -1,10 +1,9 @@
|
|||
import React, {useState} from 'react';
|
||||
import React, { useState } from 'react';
|
||||
import styled from 'styled-components';
|
||||
|
||||
import searchData from './data/search.json';
|
||||
|
||||
import themeData from './data/themes.json';
|
||||
const selectedTheme = localStorage.getItem("theme") ? JSON.parse(localStorage.getItem("theme")) : themeData.themes[0];
|
||||
import { selectedTheme } from '../selectedTheme';
|
||||
|
||||
const SearchInput = styled.input`
|
||||
width: 100%;
|
||||
|
@ -17,53 +16,53 @@ const SearchInput = styled.input`
|
|||
`;
|
||||
|
||||
const handleQueryWithProvider = (query) => {
|
||||
|
||||
let queryArray = query.split(" ");
|
||||
let queryArray = query.split(' ');
|
||||
|
||||
let prefix = queryArray[0];
|
||||
|
||||
queryArray.shift();
|
||||
|
||||
let searchQuery = queryArray.join(" ");
|
||||
|
||||
let searchQuery = queryArray.join(' ');
|
||||
|
||||
var foundProvider = false;
|
||||
searchData.providers.forEach((provider) => {
|
||||
if (provider.prefix === prefix) {
|
||||
foundProvider = true;
|
||||
window.location = provider.url + searchQuery
|
||||
window.location = provider.url + searchQuery;
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
if (!foundProvider) {
|
||||
window.location = "https://google.com/search?q=" + query;
|
||||
window.location = 'https://google.com/search?q=' + query;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const SearchBar = () => {
|
||||
|
||||
let [input, setInput] = useState();
|
||||
|
||||
const handleSearchQuery = (e) => {
|
||||
|
||||
var query = input;
|
||||
|
||||
console.log(query)
|
||||
console.log(query);
|
||||
|
||||
if (query.split(" ")[0].includes("/")) {
|
||||
handleQueryWithProvider(query)
|
||||
if (query.split(' ')[0].includes('/')) {
|
||||
handleQueryWithProvider(query);
|
||||
} else {
|
||||
window.location = "https://google.com/search?q=" + query;
|
||||
window.location = 'https://google.com/search?q=' + query;
|
||||
}
|
||||
|
||||
e.preventDefault();
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<form onSubmit={(e) => handleSearchQuery(e)}>
|
||||
<SearchInput type="text" onChange={(e) => setInput(e.target.value)}></SearchInput>
|
||||
<SearchInput
|
||||
type="text"
|
||||
onChange={(e) => setInput(e.target.value)}
|
||||
></SearchInput>
|
||||
<button type="submit" hidden />
|
||||
</form>
|
||||
)
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
export default SearchBar;
|
||||
export default SearchBar;
|
||||
|
|
|
@ -4,10 +4,11 @@ import styled from 'styled-components';
|
|||
|
||||
import Select from 'react-select';
|
||||
|
||||
import searchData from './data/search.json'
|
||||
import themeData from './data/themes.json'
|
||||
import searchData from './data/search.json';
|
||||
import themeData from './data/themes.json';
|
||||
|
||||
import getTheme, { setTheme } from './themeManager'
|
||||
import getTheme, { setTheme } from './themeManager';
|
||||
import { Button } from './button';
|
||||
|
||||
const selectedTheme = getTheme();
|
||||
|
||||
|
@ -47,15 +48,7 @@ const FormContainer = styled.div`
|
|||
flex-wrap: nowrap;
|
||||
`;
|
||||
|
||||
const ApplyButton = styled.button`
|
||||
font-family: Roboto, sans-serif;
|
||||
text-transform: uppercase;
|
||||
font-weight: 400;
|
||||
border: 1px solid ${selectedTheme.mainColor};
|
||||
color: ${selectedTheme.mainColor};
|
||||
background: none;
|
||||
margin-left: 1rem;
|
||||
`;
|
||||
const ApplyButton = Button;
|
||||
|
||||
const Headline = styled.h3`
|
||||
font-family: Roboto, sans-serif;
|
||||
|
@ -67,48 +60,47 @@ const Headline = styled.h3`
|
|||
const SelectorStyle = {
|
||||
control: (provided) => ({
|
||||
...provided,
|
||||
fontFamily: "Roboto, sans-serif",
|
||||
fontWeight: "500",
|
||||
fontFamily: 'Roboto, sans-serif',
|
||||
fontWeight: '500',
|
||||
color: selectedTheme.mainColor,
|
||||
textTransform: "uppercase",
|
||||
width: "200px",
|
||||
background: "none",
|
||||
borderRadius: "0px",
|
||||
border: "1px solid " + selectedTheme.mainColor,
|
||||
textTransform: 'uppercase',
|
||||
width: '200px',
|
||||
background: 'none',
|
||||
borderRadius: '0px',
|
||||
border: '1px solid ' + selectedTheme.mainColor,
|
||||
boxShadow: 0,
|
||||
'&:hover': {
|
||||
border: "1px solid " + selectedTheme.mainColor,
|
||||
}
|
||||
border: '1px solid ' + selectedTheme.mainColor,
|
||||
},
|
||||
}),
|
||||
menu: (provided) => ({
|
||||
...provided,
|
||||
backgroundColor: selectedTheme.backgroundColor,
|
||||
border: "1px solid " + selectedTheme.mainColor,
|
||||
borderRadius: "0px",
|
||||
border: '1px solid ' + selectedTheme.mainColor,
|
||||
borderRadius: '0px',
|
||||
boxShadow: 0,
|
||||
}),
|
||||
option: (provided) => ({
|
||||
...provided,
|
||||
fontFamily: "Roboto, sans-serif",
|
||||
fontWeight: "500",
|
||||
fontFamily: 'Roboto, sans-serif',
|
||||
fontWeight: '500',
|
||||
color: selectedTheme.mainColor,
|
||||
textTransform: "uppercase",
|
||||
borderRadius: "0px",
|
||||
textTransform: 'uppercase',
|
||||
borderRadius: '0px',
|
||||
boxShadow: 0,
|
||||
backgroundColor: selectedTheme.backgroundColor,
|
||||
'&:hover': {
|
||||
backgroundColor: selectedTheme.mainColor,
|
||||
color: selectedTheme.backgroundColor,
|
||||
}
|
||||
},
|
||||
}),
|
||||
singleValue: (provided) => {
|
||||
return {
|
||||
...provided,
|
||||
color: selectedTheme.mainColor,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
},
|
||||
};
|
||||
|
||||
const Table = styled.table`
|
||||
font-family: Roboto, sans-serif;
|
||||
|
@ -132,7 +124,6 @@ const HeadCell = styled.th`
|
|||
`;
|
||||
|
||||
const SettingsModal = () => {
|
||||
|
||||
const [modalHidden, setModalHidden] = useState(true);
|
||||
const [newTheme, setNewTheme] = useState();
|
||||
|
||||
|
@ -143,33 +134,49 @@ const SettingsModal = () => {
|
|||
</ModalButton>
|
||||
<Modal hidden={modalHidden}>
|
||||
<ExitButton onClick={() => setModalHidden(!modalHidden)}>
|
||||
<MaterialIcon icon="close" color={selectedTheme.mainColor} />
|
||||
<MaterialIcon
|
||||
icon="close"
|
||||
color={selectedTheme.mainColor}
|
||||
/>
|
||||
</ExitButton>
|
||||
<SelectContainer>
|
||||
<Headline>Theme:</Headline>
|
||||
<FormContainer>
|
||||
<Select options={themeData.themes} defaultValue={selectedTheme} onChange={(e) => {setNewTheme(e)}} styles={SelectorStyle} />
|
||||
<ApplyButton onClick={() => setTheme(JSON.stringify(newTheme))}>Apply</ApplyButton>
|
||||
<Select
|
||||
options={themeData.themes}
|
||||
defaultValue={selectedTheme}
|
||||
onChange={(e) => {
|
||||
setNewTheme(e);
|
||||
}}
|
||||
styles={SelectorStyle}
|
||||
/>
|
||||
<ApplyButton
|
||||
onClick={() => setTheme(JSON.stringify(newTheme))}
|
||||
>
|
||||
Apply
|
||||
</ApplyButton>
|
||||
</FormContainer>
|
||||
</SelectContainer>
|
||||
<Table>
|
||||
<TableRow>
|
||||
<HeadCell>Search Provider</HeadCell>
|
||||
<HeadCell>Prefix</HeadCell>
|
||||
</TableRow>
|
||||
{
|
||||
searchData.providers.map((provider) => (
|
||||
<TableRow>
|
||||
<TableCell>{provider.name}</TableCell>
|
||||
<TableCell>{provider.prefix}</TableCell>
|
||||
</TableRow>
|
||||
))
|
||||
}
|
||||
<tbody>
|
||||
<TableRow>
|
||||
<HeadCell>Search Provider</HeadCell>
|
||||
<HeadCell>Prefix</HeadCell>
|
||||
</TableRow>
|
||||
{searchData.providers.map((provider) => {
|
||||
const { name, prefix } = provider;
|
||||
return (
|
||||
<TableRow key={name}>
|
||||
<TableCell>{name}</TableCell>
|
||||
<TableCell>{prefix}</TableCell>
|
||||
</TableRow>
|
||||
);
|
||||
})}
|
||||
</tbody>
|
||||
</Table>
|
||||
</Modal>
|
||||
</>
|
||||
)
|
||||
);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
export default SettingsModal;
|
||||
export default SettingsModal;
|
||||
|
|
|
@ -1,25 +1,27 @@
|
|||
import themeData from './data/themes.json';
|
||||
|
||||
const setTheme = (theme) => {
|
||||
localStorage.setItem("theme", theme);
|
||||
localStorage.setItem('theme', theme);
|
||||
window.location.reload();
|
||||
}
|
||||
};
|
||||
|
||||
const resetTheme = () => {
|
||||
localStorage.removeItem("theme");
|
||||
}
|
||||
localStorage.removeItem('theme');
|
||||
};
|
||||
|
||||
const getTheme = () => {
|
||||
|
||||
let selectedTheme = themeData.themes[0];
|
||||
|
||||
if (localStorage.getItem("theme") && localStorage.getItem("theme") !== undefined) {
|
||||
selectedTheme = JSON.parse(localStorage.getItem("theme"));
|
||||
if (
|
||||
localStorage.getItem('theme') &&
|
||||
localStorage.getItem('theme') !== undefined
|
||||
) {
|
||||
selectedTheme = JSON.parse(localStorage.getItem('theme'));
|
||||
}
|
||||
|
||||
return selectedTheme;
|
||||
}
|
||||
};
|
||||
|
||||
export { setTheme, resetTheme }
|
||||
export { setTheme, resetTheme };
|
||||
|
||||
export default getTheme;
|
||||
export default getTheme;
|
||||
|
|
|
@ -4,10 +4,10 @@ import App from './App';
|
|||
import * as serviceWorker from './serviceWorker';
|
||||
|
||||
ReactDOM.render(
|
||||
<React.StrictMode>
|
||||
<App />
|
||||
</React.StrictMode>,
|
||||
document.getElementById('root')
|
||||
<React.StrictMode>
|
||||
<App />
|
||||
</React.StrictMode>,
|
||||
document.getElementById('root')
|
||||
);
|
||||
|
||||
// If you want your app to work offline and load faster, you can change
|
||||
|
|
5
src/selectedTheme.js
Normal file
5
src/selectedTheme.js
Normal file
|
@ -0,0 +1,5 @@
|
|||
import themeData from './components/data/themes.json';
|
||||
|
||||
export const selectedTheme = localStorage.getItem('theme')
|
||||
? JSON.parse(localStorage.getItem('theme'))
|
||||
: themeData.themes[0];
|
|
@ -11,131 +11,132 @@
|
|||
// opt-in, read https://bit.ly/CRA-PWA
|
||||
|
||||
const isLocalhost = Boolean(
|
||||
window.location.hostname === 'localhost' ||
|
||||
// [::1] is the IPv6 localhost address.
|
||||
window.location.hostname === '[::1]' ||
|
||||
// 127.0.0.0/8 are considered localhost for IPv4.
|
||||
window.location.hostname.match(
|
||||
/^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/
|
||||
)
|
||||
window.location.hostname === 'localhost' ||
|
||||
// [::1] is the IPv6 localhost address.
|
||||
window.location.hostname === '[::1]' ||
|
||||
// 127.0.0.0/8 are considered localhost for IPv4.
|
||||
window.location.hostname.match(
|
||||
/^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/
|
||||
)
|
||||
);
|
||||
|
||||
export function register(config) {
|
||||
if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) {
|
||||
// The URL constructor is available in all browsers that support SW.
|
||||
const publicUrl = new URL(process.env.PUBLIC_URL, window.location.href);
|
||||
if (publicUrl.origin !== window.location.origin) {
|
||||
// Our service worker won't work if PUBLIC_URL is on a different origin
|
||||
// from what our page is served on. This might happen if a CDN is used to
|
||||
// serve assets; see https://github.com/facebook/create-react-app/issues/2374
|
||||
return;
|
||||
}
|
||||
if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) {
|
||||
// The URL constructor is available in all browsers that support SW.
|
||||
const publicUrl = new URL(process.env.PUBLIC_URL, window.location.href);
|
||||
if (publicUrl.origin !== window.location.origin) {
|
||||
// Our service worker won't work if PUBLIC_URL is on a different origin
|
||||
// from what our page is served on. This might happen if a CDN is used to
|
||||
// serve assets; see https://github.com/facebook/create-react-app/issues/2374
|
||||
return;
|
||||
}
|
||||
|
||||
window.addEventListener('load', () => {
|
||||
const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`;
|
||||
window.addEventListener('load', () => {
|
||||
const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`;
|
||||
|
||||
if (isLocalhost) {
|
||||
// This is running on localhost. Let's check if a service worker still exists or not.
|
||||
checkValidServiceWorker(swUrl, config);
|
||||
if (isLocalhost) {
|
||||
// This is running on localhost. Let's check if a service worker still exists or not.
|
||||
checkValidServiceWorker(swUrl, config);
|
||||
|
||||
// Add some additional logging to localhost, pointing developers to the
|
||||
// service worker/PWA documentation.
|
||||
navigator.serviceWorker.ready.then(() => {
|
||||
console.log(
|
||||
'This web app is being served cache-first by a service ' +
|
||||
'worker. To learn more, visit https://bit.ly/CRA-PWA'
|
||||
);
|
||||
// Add some additional logging to localhost, pointing developers to the
|
||||
// service worker/PWA documentation.
|
||||
navigator.serviceWorker.ready.then(() => {
|
||||
console.log(
|
||||
'This web app is being served cache-first by a service ' +
|
||||
'worker. To learn more, visit https://bit.ly/CRA-PWA'
|
||||
);
|
||||
});
|
||||
} else {
|
||||
// Is not localhost. Just register service worker
|
||||
registerValidSW(swUrl, config);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
// Is not localhost. Just register service worker
|
||||
registerValidSW(swUrl, config);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function registerValidSW(swUrl, config) {
|
||||
navigator.serviceWorker
|
||||
.register(swUrl)
|
||||
.then(registration => {
|
||||
registration.onupdatefound = () => {
|
||||
const installingWorker = registration.installing;
|
||||
if (installingWorker == null) {
|
||||
return;
|
||||
}
|
||||
installingWorker.onstatechange = () => {
|
||||
if (installingWorker.state === 'installed') {
|
||||
if (navigator.serviceWorker.controller) {
|
||||
// At this point, the updated precached content has been fetched,
|
||||
// but the previous service worker will still serve the older
|
||||
// content until all client tabs are closed.
|
||||
console.log(
|
||||
'New content is available and will be used when all ' +
|
||||
'tabs for this page are closed. See https://bit.ly/CRA-PWA.'
|
||||
);
|
||||
navigator.serviceWorker
|
||||
.register(swUrl)
|
||||
.then((registration) => {
|
||||
registration.onupdatefound = () => {
|
||||
const installingWorker = registration.installing;
|
||||
if (installingWorker == null) {
|
||||
return;
|
||||
}
|
||||
installingWorker.onstatechange = () => {
|
||||
if (installingWorker.state === 'installed') {
|
||||
if (navigator.serviceWorker.controller) {
|
||||
// At this point, the updated precached content has been fetched,
|
||||
// but the previous service worker will still serve the older
|
||||
// content until all client tabs are closed.
|
||||
console.log(
|
||||
'New content is available and will be used when all ' +
|
||||
'tabs for this page are closed. See https://bit.ly/CRA-PWA.'
|
||||
);
|
||||
|
||||
// Execute callback
|
||||
if (config && config.onUpdate) {
|
||||
config.onUpdate(registration);
|
||||
}
|
||||
} else {
|
||||
// At this point, everything has been precached.
|
||||
// It's the perfect time to display a
|
||||
// "Content is cached for offline use." message.
|
||||
console.log('Content is cached for offline use.');
|
||||
// Execute callback
|
||||
if (config && config.onUpdate) {
|
||||
config.onUpdate(registration);
|
||||
}
|
||||
} else {
|
||||
// At this point, everything has been precached.
|
||||
// It's the perfect time to display a
|
||||
// "Content is cached for offline use." message.
|
||||
console.log('Content is cached for offline use.');
|
||||
|
||||
// Execute callback
|
||||
if (config && config.onSuccess) {
|
||||
config.onSuccess(registration);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error during service worker registration:', error);
|
||||
});
|
||||
// Execute callback
|
||||
if (config && config.onSuccess) {
|
||||
config.onSuccess(registration);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error('Error during service worker registration:', error);
|
||||
});
|
||||
}
|
||||
|
||||
function checkValidServiceWorker(swUrl, config) {
|
||||
// Check if the service worker can be found. If it can't reload the page.
|
||||
fetch(swUrl, {
|
||||
headers: { 'Service-Worker': 'script' },
|
||||
})
|
||||
.then(response => {
|
||||
// Ensure service worker exists, and that we really are getting a JS file.
|
||||
const contentType = response.headers.get('content-type');
|
||||
if (
|
||||
response.status === 404 ||
|
||||
(contentType != null && contentType.indexOf('javascript') === -1)
|
||||
) {
|
||||
// No service worker found. Probably a different app. Reload the page.
|
||||
navigator.serviceWorker.ready.then(registration => {
|
||||
registration.unregister().then(() => {
|
||||
window.location.reload();
|
||||
});
|
||||
});
|
||||
} else {
|
||||
// Service worker found. Proceed as normal.
|
||||
registerValidSW(swUrl, config);
|
||||
}
|
||||
// Check if the service worker can be found. If it can't reload the page.
|
||||
fetch(swUrl, {
|
||||
headers: { 'Service-Worker': 'script' },
|
||||
})
|
||||
.catch(() => {
|
||||
console.log(
|
||||
'No internet connection found. App is running in offline mode.'
|
||||
);
|
||||
});
|
||||
.then((response) => {
|
||||
// Ensure service worker exists, and that we really are getting a JS file.
|
||||
const contentType = response.headers.get('content-type');
|
||||
if (
|
||||
response.status === 404 ||
|
||||
(contentType != null &&
|
||||
contentType.indexOf('javascript') === -1)
|
||||
) {
|
||||
// No service worker found. Probably a different app. Reload the page.
|
||||
navigator.serviceWorker.ready.then((registration) => {
|
||||
registration.unregister().then(() => {
|
||||
window.location.reload();
|
||||
});
|
||||
});
|
||||
} else {
|
||||
// Service worker found. Proceed as normal.
|
||||
registerValidSW(swUrl, config);
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
console.log(
|
||||
'No internet connection found. App is running in offline mode.'
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
export function unregister() {
|
||||
if ('serviceWorker' in navigator) {
|
||||
navigator.serviceWorker.ready
|
||||
.then(registration => {
|
||||
registration.unregister();
|
||||
})
|
||||
.catch(error => {
|
||||
console.error(error.message);
|
||||
});
|
||||
}
|
||||
if ('serviceWorker' in navigator) {
|
||||
navigator.serviceWorker.ready
|
||||
.then((registration) => {
|
||||
registration.unregister();
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error(error.message);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue