Added support for categories

This commit is contained in:
Bastian Meissner 2020-06-26 15:24:37 +02:00
parent d2b35f7339
commit 9c372553f9
6 changed files with 106 additions and 63 deletions

View file

@ -12,6 +12,7 @@ import selectedTheme from './components/themeManager';
const GlobalStyle = createGlobalStyle` const GlobalStyle = createGlobalStyle`
body { body {
background-color: ${selectedTheme.backgroundColor}; background-color: ${selectedTheme.backgroundColor};
font-family: Roboto, sans-serif;
} }
`; `;

View file

@ -7,10 +7,11 @@ import selectedTheme from './themeManager';
import { import {
handleResponse, handleResponse,
Headline, Headline,
SubHeadline,
ListContainer, ListContainer,
ItemList, ItemList,
Item, Item,
ErrorMessage ErrorMessage,
} from './elements'; } from './elements';
const IconContainer = styled.div` const IconContainer = styled.div`
@ -46,9 +47,13 @@ const Description = styled.p`
color: ${selectedTheme.accentColor}; color: ${selectedTheme.accentColor};
`; `;
const CategoryContainer = styled.div`
padding: 1rem 0;
`;
const App = styled.div` const App = styled.div`
display: flex; display: flex;
flex-basis: 25%; flex: auto 25%;
padding: 1rem; padding: 1rem;
`; `;
@ -59,11 +64,11 @@ const useAppData = () => {
? fetch('/data/apps.json').then(handleResponse) ? fetch('/data/apps.json').then(handleResponse)
: import('./data/apps.json') : import('./data/apps.json')
) )
.then(jsonResponse => { .then((jsonResponse) => {
setAppData({ ...jsonResponse, error: false }); setAppData({ ...jsonResponse, error: false });
}) })
.catch(error => { .catch((error) => {
setAppData({ apps: [], error: error.message }); setAppData({ categories: [], apps: [], error: error.message });
}); });
}, []); }, []);
@ -75,32 +80,66 @@ const useAppData = () => {
const AppList = () => { const AppList = () => {
const { const {
appData: { apps, error } appData: { categories, apps, error },
} = useAppData(); } = useAppData();
return ( return (
<ListContainer> <ListContainer>
<Headline>Applications</Headline> <Headline>Applications</Headline>
{categories && (
<CategoryContainer>
{categories.map((category, idx) => (
<>
<SubHeadline key={[category.name, idx].join('')}>
{category.name}
</SubHeadline>
<ItemList>
{category.items.map((app, idx) => (
<Item key={[app.name, idx].join('')}>
<App>
<IconContainer>
<MaterialIcon
icon={app.icon}
color={
selectedTheme.mainColor
}
/>
</IconContainer>
<DetailsContainer>
<Link href={app.URL}>
{app.name}
</Link>
<Description>
{app.displayURL}
</Description>
</DetailsContainer>
</App>
</Item>
))}
</ItemList>
</>
))}
</CategoryContainer>
)}
<ItemList> <ItemList>
{error && <ErrorMessage>{error}</ErrorMessage>} {error && <ErrorMessage>{error}</ErrorMessage>}
{apps.map((app, idx) => { {apps.map((app, idx) => (
const { name } = app; <Item key={[app.name, idx].join('')}>
return ( <App>
<Item key={[name, idx].join('')}> <IconContainer>
<App> <MaterialIcon
<IconContainer> icon={app.icon}
<MaterialIcon color={selectedTheme.mainColor}
icon={app.icon} />
color={selectedTheme.mainColor} </IconContainer>
/> <DetailsContainer>
</IconContainer> <Link href={app.URL}>{app.name}</Link>
<DetailsContainer> <Description>{app.displayURL}</Description>
<Link href={app.URL}>{app.name}</Link> </DetailsContainer>
<Description>{app.displayURL}</Description> </App>
</DetailsContainer> </Item>
</App> ))}
</Item>
);
})}
</ItemList> </ItemList>
</ListContainer> </ListContainer>
); );

View file

@ -8,7 +8,7 @@ import {
ListContainer, ListContainer,
ItemList, ItemList,
Item, Item,
ErrorMessage ErrorMessage,
} from './elements'; } from './elements';
const Group = styled.h4` const Group = styled.h4`
@ -23,7 +23,7 @@ const BookmarkGroup = styled.div`
display: flex; display: flex;
flex-direction: column; flex-direction: column;
flex: 2 1 auto; flex: 2 1 auto;
padding: 1rem 0 1rem 0; padding: 1rem 0;
`; `;
const Bookmark = styled.a` const Bookmark = styled.a`
@ -31,7 +31,7 @@ const Bookmark = styled.a`
font-weight: 400; font-weight: 400;
text-decoration: none; text-decoration: none;
color: ${selectedTheme.accentColor}; color: ${selectedTheme.accentColor};
padding: 10px 0 0 0; padding-top: 10px;
font-size: 14px; font-size: 14px;
&:hover { &:hover {
@ -42,7 +42,7 @@ const Bookmark = styled.a`
const useBookmarkData = () => { const useBookmarkData = () => {
const [bookmarkData, setBookmarkData] = useState({ const [bookmarkData, setBookmarkData] = useState({
groups: [], groups: [],
error: false error: false,
}); });
const fetchBookmarkData = useCallback(() => { const fetchBookmarkData = useCallback(() => {
@ -50,10 +50,10 @@ const useBookmarkData = () => {
? fetch('/data/bookmarks.json').then(handleResponse) ? fetch('/data/bookmarks.json').then(handleResponse)
: import('./data/bookmarks.json') : import('./data/bookmarks.json')
) )
.then(jsonResponse => { .then((jsonResponse) => {
setBookmarkData({ ...jsonResponse, error: false }); setBookmarkData({ ...jsonResponse, error: false });
}) })
.catch(error => { .catch((error) => {
setBookmarkData({ groups: [], error: error.message }); setBookmarkData({ groups: [], error: error.message });
}); });
}, []); }, []);
@ -66,7 +66,7 @@ const useBookmarkData = () => {
const BookmarkList = () => { const BookmarkList = () => {
const { const {
bookmarkData: { groups, error } bookmarkData: { groups, error },
} = useBookmarkData(); } = useBookmarkData();
return ( return (
<ListContainer> <ListContainer>

View file

@ -5,7 +5,7 @@ import MaterialIcon from 'material-icons-react';
// File for elements that are/can be reused across the entire site. // File for elements that are/can be reused across the entire site.
export const handleResponse = response => { export const handleResponse = (response) => {
if (response.ok) { if (response.ok) {
return response.json(); return response.json();
} }
@ -13,12 +13,11 @@ export const handleResponse = response => {
}; };
export const ListContainer = styled.div` export const ListContainer = styled.div`
padding: 2rem 0 2rem 0; padding: 2rem 0;
`; `;
export const Headline = styled.h3` export const Headline = styled.h3`
display: inline-block; display: inline-block;
font-family: Roboto, sans-serif;
font-weight: 900; font-weight: 900;
text-transform: uppercase; text-transform: uppercase;
margin: 0px; margin: 0px;
@ -26,6 +25,15 @@ export const Headline = styled.h3`
color: ${selectedTheme.mainColor}; color: ${selectedTheme.mainColor};
`; `;
export const SubHeadline = styled.h4`
display: inline-block;
font-weight: 700;
text-transform: uppercase;
margin: 0px;
font-size: 1.5rem;
color: ${selectedTheme.mainColor};
`;
export const ItemList = styled.ul` export const ItemList = styled.ul`
display: grid; display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
@ -41,7 +49,6 @@ export const Item = styled.li`
`; `;
export const Button = styled.button` export const Button = styled.button`
font-family: Roboto, sans-serif;
text-transform: uppercase; text-transform: uppercase;
font-weight: 400; font-weight: 400;
border: 1px solid ${selectedTheme.mainColor}; border: 1px solid ${selectedTheme.mainColor};
@ -75,7 +82,7 @@ export const ErrorMessage = styled.p`
color: red; color: red;
`; `;
export const IconButton = props => { export const IconButton = (props) => {
if ( if (
props.icon && props.icon &&
props.icon !== '' && props.icon !== '' &&

View file

@ -4,19 +4,17 @@ import styled from 'styled-components';
import selectedTheme from './themeManager'; import selectedTheme from './themeManager';
const GreeterContainer = styled.div` const GreeterContainer = styled.div`
padding: 2rem 0 2rem 0; padding: 2rem 0;
`; `;
const GreetText = styled.h1` const GreetText = styled.h1`
font-family: Roboto, sans-serif;
font-weight: 900; font-weight: 900;
font-size: 45px; font-size: 45px;
margin: 0.5rem 0 0.5rem 0; margin: 0.5rem 0;
color: ${selectedTheme.mainColor}; color: ${selectedTheme.mainColor};
`; `;
const DateText = styled.h3` const DateText = styled.h3`
font-family: Roboto, sans-serif;
font-weight: 400; font-weight: 400;
font-size: 15px; font-size: 15px;
text-transform: uppercase; text-transform: uppercase;
@ -39,7 +37,7 @@ const getGreeting = () => {
} }
}; };
const getExtension = day => { const getExtension = (day) => {
let extension = ''; let extension = '';
if ((day > 4 && day <= 20) || (day > 20 && day % 10 >= 4)) { if ((day > 4 && day <= 20) || (day > 20 && day % 10 >= 4)) {
@ -67,7 +65,7 @@ const monthNames = [
'September', 'September',
'October', 'October',
'November', 'November',
'December' 'December',
]; ];
const weekDayNames = [ const weekDayNames = [
@ -77,7 +75,7 @@ const weekDayNames = [
'Wednesday', 'Wednesday',
'Thursday', 'Thursday',
'Friday', 'Friday',
'Saturday' 'Saturday',
]; ];
const getDateString = () => { const getDateString = () => {

View file

@ -11,11 +11,11 @@ import {
Button, Button,
IconButton, IconButton,
ErrorMessage, ErrorMessage,
Headline as hl Headline as hl,
} from './elements'; } from './elements';
const Headline = styled(hl)` const Headline = styled(hl)`
padding: 0.5rem 0 0.5rem 0; padding: 0.5rem 0;
`; `;
const Modal = styled.div` const Modal = styled.div`
@ -60,9 +60,8 @@ const HeadCell = styled.th`
`; `;
const SelectorStyle = { const SelectorStyle = {
control: provided => ({ control: (provided) => ({
...provided, ...provided,
fontFamily: 'Roboto, sans-serif',
fontWeight: '500', fontWeight: '500',
color: selectedTheme.mainColor, color: selectedTheme.mainColor,
textTransform: 'uppercase', textTransform: 'uppercase',
@ -72,19 +71,18 @@ const SelectorStyle = {
border: '1px solid ' + selectedTheme.mainColor, border: '1px solid ' + selectedTheme.mainColor,
boxShadow: 0, boxShadow: 0,
'&:hover': { '&:hover': {
border: '1px solid ' + selectedTheme.mainColor border: '1px solid ' + selectedTheme.mainColor,
} },
}), }),
menu: provided => ({ menu: (provided) => ({
...provided, ...provided,
backgroundColor: selectedTheme.backgroundColor, backgroundColor: selectedTheme.backgroundColor,
border: '1px solid ' + selectedTheme.mainColor, border: '1px solid ' + selectedTheme.mainColor,
borderRadius: '0px', borderRadius: '0px',
boxShadow: 0 boxShadow: 0,
}), }),
option: provided => ({ option: (provided) => ({
...provided, ...provided,
fontFamily: 'Roboto, sans-serif',
fontWeight: '500', fontWeight: '500',
color: selectedTheme.mainColor, color: selectedTheme.mainColor,
textTransform: 'uppercase', textTransform: 'uppercase',
@ -93,15 +91,15 @@ const SelectorStyle = {
backgroundColor: selectedTheme.backgroundColor, backgroundColor: selectedTheme.backgroundColor,
'&:hover': { '&:hover': {
backgroundColor: selectedTheme.mainColor, backgroundColor: selectedTheme.mainColor,
color: selectedTheme.backgroundColor color: selectedTheme.backgroundColor,
} },
}), }),
singleValue: provided => { singleValue: (provided) => {
return { return {
...provided, ...provided,
color: selectedTheme.mainColor color: selectedTheme.mainColor,
}; };
} },
}; };
const useThemeData = () => { const useThemeData = () => {
@ -112,10 +110,10 @@ const useThemeData = () => {
? fetch('/data/themes.json').then(handleResponse) ? fetch('/data/themes.json').then(handleResponse)
: import('./data/themes.json') : import('./data/themes.json')
) )
.then(jsonResponse => { .then((jsonResponse) => {
setThemeData({ ...jsonResponse, error: false }); setThemeData({ ...jsonResponse, error: false });
}) })
.catch(error => { .catch((error) => {
setThemeData({ themes: [], error: error.message }); setThemeData({ themes: [], error: error.message });
}); });
}, []); }, []);
@ -131,7 +129,7 @@ const SettingsModal = () => {
const [newTheme, setNewTheme] = useState(); const [newTheme, setNewTheme] = useState();
const { const {
themeData: { themes, error } themeData: { themes, error },
} = useThemeData(); } = useThemeData();
return ( return (
@ -152,7 +150,7 @@ const SettingsModal = () => {
<Select <Select
options={themes} options={themes}
defaultValue={selectedTheme} defaultValue={selectedTheme}
onChange={e => { onChange={(e) => {
setNewTheme(e); setNewTheme(e);
}} }}
styles={SelectorStyle} styles={SelectorStyle}