Add support for imprints

This commit is contained in:
Bastian Meissner 2020-09-08 13:18:58 +02:00
parent 5656d91845
commit a8f2136736
8 changed files with 358 additions and 60 deletions

22
data/imprint.json Normal file
View file

@ -0,0 +1,22 @@
{
"name": {
"text": "John Doe",
"link": "#"
},
"address": {
"text": "Null Ave. 1234, 90008 Los Angeles",
"link": "#"
},
"phone": {
"text": "+1-202-555-0167",
"link": "#"
},
"email": {
"text": "doe.john@example.com",
"link": "#"
},
"url": {
"text": "example.com",
"link": "#"
}
}

View file

@ -5,10 +5,12 @@ import SearchBar from "./components/searchBar";
import Greeter from "./components/greeter"; import Greeter from "./components/greeter";
import AppList from "./components/appList"; import AppList from "./components/appList";
import BookmarkList from "./components/bookmarkList"; import BookmarkList from "./components/bookmarkList";
import SettingsModal from "./components/settingsModal"; import Settings from "./components/settings";
import selectedTheme from "./components/themeManager"; import selectedTheme from "./components/themeManager";
import Imprint from "./components/imprint";
const GlobalStyle = createGlobalStyle` const GlobalStyle = createGlobalStyle`
body { body {
background-color: ${selectedTheme.backgroundColor}; background-color: ${selectedTheme.backgroundColor};
@ -32,10 +34,11 @@ const App = () => (
<GlobalStyle /> <GlobalStyle />
<AppContainer> <AppContainer>
<SearchBar /> <SearchBar />
<SettingsModal /> <Settings />
<Greeter /> <Greeter />
<AppList /> <AppList />
<BookmarkList /> <BookmarkList />
<Imprint />
</AppContainer> </AppContainer>
</> </>
); );

View file

@ -48,7 +48,7 @@ const AppList = () => {
))} ))}
{apps && ( {apps && (
<AppCategory <AppCategory
name={categories > 0 ? "Uncategorized apps" : ""} name={categories ? "Uncategorized apps" : ""}
items={apps} items={apps}
/> />
)} )}

View file

@ -0,0 +1,22 @@
{
"name": {
"text": "John Doe",
"link": "#"
},
"address": {
"text": "Null Ave. 1234, 90008 Los Angeles",
"link": "#"
},
"phone": {
"text": "+1-202-555-0167",
"link": "#"
},
"email": {
"text": "doe.john@example.com",
"link": "#"
},
"url": {
"text": "example.com",
"link": "#"
}
}

View file

@ -27,7 +27,7 @@ interface IIconProps {
export const ComponentIcon = ({ name, size }: IIconProps) => { export const ComponentIcon = ({ name, size }: IIconProps) => {
let IconContainer = styled(RawIcon)` let IconContainer = styled(RawIcon)`
font-size: ${size ? size : "24px"}; font-size: ${size ? size : "24px"};
text-color: ${selectedTheme.mainColor}; color: ${selectedTheme.mainColor};
`; `;
return <IconContainer>{name}</IconContainer>; return <IconContainer>{name}</IconContainer>;

206
src/components/imprint.tsx Normal file
View file

@ -0,0 +1,206 @@
import React, { useCallback, useEffect, useState } from "react";
import Modal from "./modal";
import styled from "styled-components";
import selectedTheme from "./themeManager";
import {
handleResponse,
ErrorMessage,
ListContainer,
ItemList,
Headline as Hl,
SubHeadline as SHl,
} from "./elements";
const Headline = styled(Hl)`
display: block;
padding: 1rem 0;
`;
const SubHeadline = styled(SHl)`
display: block;
`;
const ModalSubHeadline = styled(SubHeadline)`
padding: 0.5rem 0;
`;
const Text = styled.p`
padding: 0;
margin: 0;
color: ${selectedTheme.mainColor};
`;
const Link = styled.a`
display: block;
padding: 0;
color: ${selectedTheme.mainColor};
text-decoration: none;
&:hover {
text-decoration: underline;
}
`;
const ItemContainer = styled.div`
padding: 1rem 0;
`;
const useImprintData = () => {
const [imprintData, setImprintData] = useState({
name: { text: "", link: "" },
address: { text: "", link: "" },
phone: { text: "", link: "" },
email: { text: "", link: "" },
url: { text: "", link: "" },
error: false,
});
const fetchImprintData = useCallback(() => {
(process.env.NODE_ENV === "production"
? fetch("/data/imprint.json").then(handleResponse)
: import("./data/imprint.json")
)
.then((jsonResponse: any) => {
setImprintData({ ...jsonResponse, error: false });
})
.catch((error: any) => {
setImprintData({
name: { text: "", link: "" },
address: { text: "", link: "" },
phone: { text: "", link: "" },
email: { text: "", link: "" },
url: { text: "", link: "" },
error: error.message,
});
});
}, []);
useEffect(() => {
fetchImprintData();
}, [fetchImprintData]);
return { imprintData, fetchImprintData };
};
const Imprint = () => {
const {
imprintData: { name, address, phone, email, url, error },
} = useImprintData();
return (
<ListContainer>
<Hl>About</Hl>
<ItemList>
<ItemContainer>
<SHl>Imprint</SHl>
<Modal element="text" text="View Imprint">
<Headline>Legal Disclosure</Headline>
{error && <ErrorMessage>{error}</ErrorMessage>}
<ModalSubHeadline>
Information in accordance with section 5 TMG
</ModalSubHeadline>
{!error && (
<>
<Link href={name.link}>{name.text}</Link>
<Link href={address.link}>{address.text}</Link>
<Link href={phone.link}>{phone.text}</Link>
<Link href={email.link}>{email.text}</Link>
<Link href={url.link}>{url.text}</Link>
</>
)}
<Headline>Disclaimer</Headline>
<ModalSubHeadline>Accountability for content</ModalSubHeadline>
<Text>
The contents of our pages have been created with the utmost care.
However, we cannot guarantee the contents' accuracy, completeness
or topicality. According to statutory provisions, we are
furthermore responsible for our own content on these web pages. In
this matter, please note that we are not obliged to monitor the
transmitted or saved information of third parties, or investigate
circumstances pointing to illegal activity. Our obligations to
remove or block the use of information under generally applicable
laws remain unaffected by this as per §§ 8 to 10 of the Telemedia
Act (TMG).
</Text>
<ModalSubHeadline>Accountability for links</ModalSubHeadline>
<Text>
Responsibility for the content of external links (to web pages of
third parties) lies solely with the operators of the linked pages.
No violations were evident to us at the time of linking. Should
any legal infringement become known to us, we will remove the
respective link immediately.
</Text>
<ModalSubHeadline>Copyright</ModalSubHeadline>
<Text>
Our web pages and their contents are subject to German copyright
law. Unless expressly permitted by law, every form of utilizing,
reproducing or processing works subject to copyright protection on
our web pages requires the prior consent of the respective owner
of the rights. Individual reproductions of a work are only allowed
for private use. The materials from these pages are copyrighted
and any unauthorized use may violate copyright laws.
</Text>
</Modal>
</ItemContainer>
</ItemList>
</ListContainer>
);
};
/*
<ImprintContainer>
<Hl>About</Hl>
<ModalContainer>
<SHl>Imprint</SHl>
<Modal element="text" text="View Imprint">
<Headline>Legal Disclosure</Headline>
{error && <ErrorMessage>{error}</ErrorMessage>}
<ModalSubHeadline>
Information in accordance with section 5 TMG
</ModalSubHeadline>
{!error && (
<>
<Link href={name.link}>{name.text}</Link>
<Link href={address.link}>{address.text}</Link>
<Link href={phone.link}>{phone.text}</Link>
<Link href={email.link}>{email.text}</Link>
<Link href={url.link}>{url.text}</Link>
</>
)}
<Headline>Disclaimer</Headline>
<ModalSubHeadline>Accountability for content</ModalSubHeadline>
<Text>
The contents of our pages have been created with the utmost care.
However, we cannot guarantee the contents' accuracy, completeness or
topicality. According to statutory provisions, we are furthermore
responsible for our own content on these web pages. In this matter,
please note that we are not obliged to monitor the transmitted or
saved information of third parties, or investigate circumstances
pointing to illegal activity. Our obligations to remove or block the
use of information under generally applicable laws remain unaffected
by this as per §§ 8 to 10 of the Telemedia Act (TMG).
</Text>
<ModalSubHeadline>Accountability for links</ModalSubHeadline>
<Text>
Responsibility for the content of external links (to web pages of
third parties) lies solely with the operators of the linked pages.
No violations were evident to us at the time of linking. Should any
legal infringement become known to us, we will remove the respective
link immediately.
</Text>
<ModalSubHeadline>Copyright</ModalSubHeadline>
<Text>
Our web pages and their contents are subject to German copyright
law. Unless expressly permitted by law, every form of utilizing,
reproducing or processing works subject to copyright protection on
our web pages requires the prior consent of the respective owner of
the rights. Individual reproductions of a work are only allowed for
private use. The materials from these pages are copyrighted and any
unauthorized use may violate copyright laws.
</Text>
</Modal>
</ModalContainer>
</ImprintContainer>
*/
export default Imprint;

64
src/components/modal.tsx Normal file
View file

@ -0,0 +1,64 @@
import React, { useState } from "react";
import styled from "styled-components";
import selectedTheme from "./themeManager";
import { IconButton } from "./elements";
const ModalContainer = styled.div`
position: absolute;
left: 50%;
top: 50%;
padding: 1rem;
transform: translate(-50%, -50%);
z-index: 10;
border: 1px solid ${selectedTheme.mainColor};
background-color: ${selectedTheme.backgroundColor};
`;
const Text = styled.p`
padding: 0;
margin: 0;
font-weight: 400;
text-decoration: none;
color: ${selectedTheme.accentColor};
padding-top: 0.75rem;
font-size: 0.9rem;
&:hover {
text-decoration: underline;
}
`;
interface IModalInterface {
element: string;
icon?: string;
text?: string;
children: React.ReactNode;
}
const Modal = (props: IModalInterface) => {
const [modalHidden, setModalHidden] = useState(true);
return (
<>
{props.element === "icon" && (
<IconButton
icon={props.icon ? props.icon : ""}
onClick={() => setModalHidden(!modalHidden)}
/>
)}
{props.element === "text" && (
<Text onClick={() => setModalHidden(!modalHidden)}>{props.text}</Text>
)}
<ModalContainer hidden={modalHidden}>
<IconButton icon="close" onClick={() => setModalHidden(!modalHidden)} />
{props.children}
</ModalContainer>
</>
);
};
export default Modal;

View file

@ -9,26 +9,16 @@ import selectedTheme, { setTheme } from "./themeManager";
import { import {
handleResponse, handleResponse,
Button, Button,
IconButton,
ErrorMessage, ErrorMessage,
Headline as hl, Headline as hl,
} from "./elements"; } from "./elements";
import Modal from "./modal";
const Headline = styled(hl)` const Headline = styled(hl)`
padding: 0.5rem 0; padding: 0.5rem 0;
`; `;
const Modal = styled.div`
position: absolute;
left: 50%;
top: 50%;
padding: 1rem;
transform: translate(-50%, -50%);
z-index: 10;
border: 1px solid ${selectedTheme.mainColor};
background-color: ${selectedTheme.backgroundColor};
`;
const SelectContainer = styled.div` const SelectContainer = styled.div`
padding-bottom: 1rem; padding-bottom: 1rem;
`; `;
@ -123,9 +113,7 @@ const useThemeData = () => {
return { themeData, fetchThemeData }; return { themeData, fetchThemeData };
}; };
const SettingsModal = () => { const Settings = () => {
const [modalHidden, setModalHidden] = useState(true);
const [newTheme, setNewTheme] = useState(); const [newTheme, setNewTheme] = useState();
const { const {
@ -137,49 +125,42 @@ const SettingsModal = () => {
}, [newTheme]); }, [newTheme]);
return ( return (
<> <Modal element="icon" icon="settings">
<IconButton {error && <ErrorMessage>{error}</ErrorMessage>}
icon="settings" <SelectContainer>
onClick={() => setModalHidden(!modalHidden)} <Headline>Theme:</Headline>
/> <FormContainer>
<Modal hidden={modalHidden}> <Select
<IconButton icon="close" onClick={() => setModalHidden(!modalHidden)} /> options={themes}
{error && <ErrorMessage>{error}</ErrorMessage>} defaultValue={selectedTheme}
<SelectContainer> onChange={(e: any) => {
<Headline>Theme:</Headline> setNewTheme(e);
<FormContainer> }}
<Select styles={SelectorStyle}
options={themes} />
defaultValue={selectedTheme}
onChange={(e: any) => {
setNewTheme(e);
}}
styles={SelectorStyle}
/>
<Button onClick={() => setTheme(JSON.stringify(newTheme))}> <Button onClick={() => setTheme(JSON.stringify(newTheme))}>
Apply Apply
</Button> </Button>
<Button onClick={() => window.location.reload()}>Refresh</Button> <Button onClick={() => window.location.reload()}>Refresh</Button>
</FormContainer> </FormContainer>
</SelectContainer> </SelectContainer>
<Table> <Table>
<tbody> <tbody>
<TableRow> <TableRow>
<HeadCell>Search Provider</HeadCell> <HeadCell>Search Provider</HeadCell>
<HeadCell>Prefix</HeadCell> <HeadCell>Prefix</HeadCell>
</TableRow>
{searchData.providers.map((provider, index) => (
<TableRow key={provider.name + index}>
<TableCell>{provider.name}</TableCell>
<TableCell>{provider.prefix}</TableCell>
</TableRow> </TableRow>
{searchData.providers.map((provider, index) => ( ))}
<TableRow key={provider.name + index}> </tbody>
<TableCell>{provider.name}</TableCell> </Table>
<TableCell>{provider.prefix}</TableCell> </Modal>
</TableRow>
))}
</tbody>
</Table>
</Modal>
</>
); );
}; };
export default SettingsModal; export default Settings;