Add support for imprints
This commit is contained in:
parent
5656d91845
commit
a8f2136736
8 changed files with 358 additions and 60 deletions
22
data/imprint.json
Normal file
22
data/imprint.json
Normal 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": "#"
|
||||
}
|
||||
}
|
|
@ -5,10 +5,12 @@ 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 Settings from "./components/settings";
|
||||
|
||||
import selectedTheme from "./components/themeManager";
|
||||
|
||||
import Imprint from "./components/imprint";
|
||||
|
||||
const GlobalStyle = createGlobalStyle`
|
||||
body {
|
||||
background-color: ${selectedTheme.backgroundColor};
|
||||
|
@ -32,10 +34,11 @@ const App = () => (
|
|||
<GlobalStyle />
|
||||
<AppContainer>
|
||||
<SearchBar />
|
||||
<SettingsModal />
|
||||
<Settings />
|
||||
<Greeter />
|
||||
<AppList />
|
||||
<BookmarkList />
|
||||
<Imprint />
|
||||
</AppContainer>
|
||||
</>
|
||||
);
|
||||
|
|
|
@ -48,7 +48,7 @@ const AppList = () => {
|
|||
))}
|
||||
{apps && (
|
||||
<AppCategory
|
||||
name={categories > 0 ? "Uncategorized apps" : ""}
|
||||
name={categories ? "Uncategorized apps" : ""}
|
||||
items={apps}
|
||||
/>
|
||||
)}
|
||||
|
|
22
src/components/data/imprint.json
Normal file
22
src/components/data/imprint.json
Normal 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": "#"
|
||||
}
|
||||
}
|
|
@ -27,7 +27,7 @@ interface IIconProps {
|
|||
export const ComponentIcon = ({ name, size }: IIconProps) => {
|
||||
let IconContainer = styled(RawIcon)`
|
||||
font-size: ${size ? size : "24px"};
|
||||
text-color: ${selectedTheme.mainColor};
|
||||
color: ${selectedTheme.mainColor};
|
||||
`;
|
||||
|
||||
return <IconContainer>{name}</IconContainer>;
|
||||
|
|
206
src/components/imprint.tsx
Normal file
206
src/components/imprint.tsx
Normal 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
64
src/components/modal.tsx
Normal 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;
|
|
@ -9,26 +9,16 @@ import selectedTheme, { setTheme } from "./themeManager";
|
|||
import {
|
||||
handleResponse,
|
||||
Button,
|
||||
IconButton,
|
||||
ErrorMessage,
|
||||
Headline as hl,
|
||||
} from "./elements";
|
||||
|
||||
import Modal from "./modal";
|
||||
|
||||
const Headline = styled(hl)`
|
||||
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`
|
||||
padding-bottom: 1rem;
|
||||
`;
|
||||
|
@ -123,9 +113,7 @@ const useThemeData = () => {
|
|||
return { themeData, fetchThemeData };
|
||||
};
|
||||
|
||||
const SettingsModal = () => {
|
||||
const [modalHidden, setModalHidden] = useState(true);
|
||||
|
||||
const Settings = () => {
|
||||
const [newTheme, setNewTheme] = useState();
|
||||
|
||||
const {
|
||||
|
@ -137,49 +125,42 @@ const SettingsModal = () => {
|
|||
}, [newTheme]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<IconButton
|
||||
icon="settings"
|
||||
onClick={() => setModalHidden(!modalHidden)}
|
||||
/>
|
||||
<Modal hidden={modalHidden}>
|
||||
<IconButton icon="close" onClick={() => setModalHidden(!modalHidden)} />
|
||||
{error && <ErrorMessage>{error}</ErrorMessage>}
|
||||
<SelectContainer>
|
||||
<Headline>Theme:</Headline>
|
||||
<FormContainer>
|
||||
<Select
|
||||
options={themes}
|
||||
defaultValue={selectedTheme}
|
||||
onChange={(e: any) => {
|
||||
setNewTheme(e);
|
||||
}}
|
||||
styles={SelectorStyle}
|
||||
/>
|
||||
<Modal element="icon" icon="settings">
|
||||
{error && <ErrorMessage>{error}</ErrorMessage>}
|
||||
<SelectContainer>
|
||||
<Headline>Theme:</Headline>
|
||||
<FormContainer>
|
||||
<Select
|
||||
options={themes}
|
||||
defaultValue={selectedTheme}
|
||||
onChange={(e: any) => {
|
||||
setNewTheme(e);
|
||||
}}
|
||||
styles={SelectorStyle}
|
||||
/>
|
||||
|
||||
<Button onClick={() => setTheme(JSON.stringify(newTheme))}>
|
||||
Apply
|
||||
</Button>
|
||||
<Button onClick={() => window.location.reload()}>Refresh</Button>
|
||||
</FormContainer>
|
||||
</SelectContainer>
|
||||
<Table>
|
||||
<tbody>
|
||||
<TableRow>
|
||||
<HeadCell>Search Provider</HeadCell>
|
||||
<HeadCell>Prefix</HeadCell>
|
||||
<Button onClick={() => setTheme(JSON.stringify(newTheme))}>
|
||||
Apply
|
||||
</Button>
|
||||
<Button onClick={() => window.location.reload()}>Refresh</Button>
|
||||
</FormContainer>
|
||||
</SelectContainer>
|
||||
<Table>
|
||||
<tbody>
|
||||
<TableRow>
|
||||
<HeadCell>Search Provider</HeadCell>
|
||||
<HeadCell>Prefix</HeadCell>
|
||||
</TableRow>
|
||||
{searchData.providers.map((provider, index) => (
|
||||
<TableRow key={provider.name + index}>
|
||||
<TableCell>{provider.name}</TableCell>
|
||||
<TableCell>{provider.prefix}</TableCell>
|
||||
</TableRow>
|
||||
{searchData.providers.map((provider, index) => (
|
||||
<TableRow key={provider.name + index}>
|
||||
<TableCell>{provider.name}</TableCell>
|
||||
<TableCell>{provider.prefix}</TableCell>
|
||||
</TableRow>
|
||||
))}
|
||||
</tbody>
|
||||
</Table>
|
||||
</Modal>
|
||||
</>
|
||||
))}
|
||||
</tbody>
|
||||
</Table>
|
||||
</Modal>
|
||||
);
|
||||
};
|
||||
|
||||
export default SettingsModal;
|
||||
export default Settings;
|
Loading…
Reference in a new issue