Added tests

This commit is contained in:
phntxx 2021-06-14 11:29:03 +02:00
parent 753a55c9c1
commit 24e61efcf1
30 changed files with 2089 additions and 1737 deletions

View file

@ -1,4 +1,4 @@
import React, { useEffect } from "react";
import { useEffect } from "react";
import Icon from "./icon";
import styled from "styled-components";
import selectedTheme from "../lib/theme";
@ -51,16 +51,17 @@ export interface IAppProps {
/**
* Renders a single app shortcut
* @param {IAppProps} props - The props of the given app
* @param {IAppProps} props the props of the given app
* @returns {React.ReactNode} the child node for the given app
*/
export const App = ({ name, icon, url, displayURL, newTab }: IAppProps) => {
useEffect(() => { console.log(newTab) }, [newTab])
const linkAttrs = (newTab !== undefined && newTab) ? {
target: '_blank',
rel: 'noopener noreferrer',
} : {};
const App = ({ name, icon, url, displayURL, newTab }: IAppProps) => {
const linkAttrs =
newTab !== undefined && newTab
? {
target: "_blank",
rel: "noopener noreferrer",
}
: {};
return (
<AppContainer href={url} {...linkAttrs}>
@ -73,4 +74,6 @@ export const App = ({ name, icon, url, displayURL, newTab }: IAppProps) => {
</DetailsContainer>
</AppContainer>
);
}
};
export default App;

View file

@ -1,6 +1,5 @@
import React from "react";
import styled from "styled-components";
import { App, IAppProps } from "./app";
import App, { IAppProps } from "./app";
import { ItemList, Item, SubHeadline } from "./elements";
const CategoryHeadline = styled(SubHeadline)`
@ -18,9 +17,10 @@ export interface IAppCategoryProps {
/**
* Renders one app category
* @param {IAppCategoryProps} props - The props of the given category
* @param {IAppCategoryProps} props props of the given category
* @returns {React.ReactNode} the app category node
*/
export const AppCategory = ({ name, items }: IAppCategoryProps) => (
const AppCategory = ({ name, items }: IAppCategoryProps) => (
<CategoryContainer>
{name && <CategoryHeadline>{name}</CategoryHeadline>}
<ItemList>
@ -38,3 +38,5 @@ export const AppCategory = ({ name, items }: IAppCategoryProps) => (
</ItemList>
</CategoryContainer>
);
export default AppCategory;

View file

@ -1,4 +1,4 @@
import { AppCategory, IAppCategoryProps } from "./appCategory";
import AppCategory, { IAppCategoryProps } from "./appCategory";
import { IAppProps } from "./app";
import { Headline, ListContainer } from "./elements";
@ -10,7 +10,8 @@ export interface IAppListProps {
/**
* Renders one list containing all app categories and uncategorized apps
* @param {IAppListProps} props - The props of the given list of apps
* @param {IAppListProps} props props of the given list of apps
* @returns {React.ReactNode} the app list component
*/
const AppList = ({ categories, apps }: IAppListProps) => (
<ListContainer>
@ -20,10 +21,7 @@ const AppList = ({ categories, apps }: IAppListProps) => (
<AppCategory key={[name, idx].join("")} name={name} items={items} />
))}
{apps && (
<AppCategory
name={categories ? "Uncategorized apps" : ""}
items={apps}
/>
<AppCategory name={categories ? "Uncategorized apps" : ""} items={apps} />
)}
</ListContainer>
);

View file

@ -1,24 +0,0 @@
import React from "react";
import { Headline, ListContainer, ItemList } from "./elements";
import { BookmarkGroup, IBookmarkGroupProps } from "./bookmarkGroup";
interface IBookmarkListProps {
groups: Array<IBookmarkGroupProps>;
}
/**
* Renders a given list of categorized bookmarks
* @param {IBookmarkListProps} props - The props of the given bookmark list
*/
const BookmarkList = ({ groups }: IBookmarkListProps) => (
<ListContainer>
<Headline>Bookmarks</Headline>
<ItemList>
{groups.map(({ name, items }, idx) => (
<BookmarkGroup key={[name, idx].join("")} name={name} items={items} />
))}
</ItemList>
</ListContainer>
);
export default BookmarkList;

View file

@ -1,6 +1,11 @@
import React from "react";
import styled from "styled-components";
import { Item, SubHeadline } from "./elements";
import {
Headline,
Item,
ItemList,
ListContainer,
SubHeadline,
} from "./elements";
import selectedTheme from "../lib/theme";
const GroupContainer = styled.div`
@ -32,9 +37,14 @@ export interface IBookmarkGroupProps {
items: Array<IBookmarkProps>;
}
export interface IBookmarkListProps {
groups: Array<IBookmarkGroupProps>;
}
/**
* Renders a given bookmark group
* @param {IBookmarkGroupProps} props - The given props of the bookmark group
* @param {IBookmarkGroupProps} props given props of the bookmark group
* @returns {React.ReactNode} the bookmark group component
*/
export const BookmarkGroup = ({ name, items }: IBookmarkGroupProps) => (
<Item>
@ -48,3 +58,21 @@ export const BookmarkGroup = ({ name, items }: IBookmarkGroupProps) => (
</GroupContainer>
</Item>
);
/**
* Renders a given list of categorized bookmarks
* @param {IBookmarkListProps} props props of the given bookmark list
* @returns {React.ReactNode} the bookmark list component
*/
const BookmarkList = ({ groups }: IBookmarkListProps) => (
<ListContainer>
<Headline>Bookmarks</Headline>
<ItemList>
{groups.map(({ name, items }, idx) => (
<BookmarkGroup key={[name, idx].join("")} name={name} items={items} />
))}
</ItemList>
</ListContainer>
);
export default BookmarkList;

View file

@ -1,7 +1,5 @@
import React from "react";
import styled from "styled-components";
import selectedTheme from "../lib/theme";
import Icon from "./icon";
export const ListContainer = styled.div`
padding: 2rem 0;
@ -56,29 +54,3 @@ export const Button = styled.button`
cursor: pointer;
}
`;
const StyledButton = styled.button`
float: right;
border: none;
padding: 0;
background: none;
&:hover {
cursor: pointer;
}
`;
interface IIconButtonProps {
icon: string;
onClick: (e: React.FormEvent) => void;
}
/**
* Renders a button with an icon
* @param {IIconProps} props - The props of the given IconButton
*/
export const IconButton = ({ icon, onClick }: IIconButtonProps) => (
<StyledButton onClick={onClick}>
<Icon name={icon} />
</StyledButton>
);

View file

@ -38,17 +38,18 @@ interface IGreeterComponentProps {
}
/**
*
* @param a the number that's supposed to be checked
* @param b the minimum
* @param c the maximum
* Checks if a number is between two numbers
* @param {number} a number that's supposed to be checked
* @param {number} b minimum
* @param {number} c maximum
*/
const isBetween = (a: number, b: number, c: number): boolean =>
a >= b && a <= c;
/**
* Returns a greeting based on the current time
* @returns {string} - A greeting
* @param {Array<IGreetingProps>} greetings a list of greetings with start and end date
* @returns {string} a greeting
*/
const getGreeting = (greetings: Array<IGreetingProps>): string => {
let hours = Math.floor(new Date().getHours());
@ -64,8 +65,8 @@ const getGreeting = (greetings: Array<IGreetingProps>): string => {
/**
* Returns the appropriate extension for a number (eg. 'rd' for '3' to make '3rd')
* @param {number} day - The number of a day within a month
* @returns {string} - The extension for that number
* @param {number} day number of a day within a month
* @returns {string} extension for that number
*/
const getExtension = (day: number) => {
let extension = "";
@ -85,13 +86,13 @@ const getExtension = (day: number) => {
/**
* Generates the current date
* @param {string} format - The format of the date string
* @returns {string} - The current date as a string
* @param {string} format format of the date string
* @returns {string} current date as a string
*/
const getDateString = (
weekdays: Array<string>,
months: Array<string>,
format: string
format: string,
) => {
let currentDate = new Date();
@ -111,6 +112,8 @@ const getDateString = (
/**
* Renders the Greeter
* @param {IGreeterComponentProps} data required greeter data
* @returns {React.ReactNode} the greeter
*/
const Greeter = ({ data }: IGreeterComponentProps) => (
<GreeterContainer>

View file

@ -7,32 +7,62 @@ interface IIconProps {
size?: string;
}
interface IIconButtonProps {
icon: string;
onClick: (e: React.FormEvent) => void;
}
const StyledButton = styled.button`
float: right;
border: none;
padding: 0;
background: none;
&:hover {
cursor: pointer;
}
`;
const IconContainer = styled.i`
font-family: "Material Icons";
font-weight: normal;
font-style: normal;
display: inline-block;
line-height: 1;
text-transform: none;
letter-spacing: normal;
word-wrap: normal;
white-space: nowrap;
direction: ltr;
-webkit-font-smoothing: antialiased;
text-rendering: optimizeLegibility;
-moz-osx-font-smoothing: grayscale;
font-feature-settings: "liga";
`;
/**
* Renders an Icon
* @param {IIconProps} props - The props needed for the given icon
* @param {IIconProps} props props needed for the given icon
* @returns {React.ReactNode} the icon node
*/
export const Icon = ({ name, size }: IIconProps) => {
let IconContainer = styled.i`
font-family: "Material Icons";
font-weight: normal;
font-style: normal;
let Container = styled(IconContainer)`
font-size: ${size ? size : "24px"};
color: ${selectedTheme.mainColor};
display: inline-block;
line-height: 1;
text-transform: none;
letter-spacing: normal;
word-wrap: normal;
white-space: nowrap;
direction: ltr;
-webkit-font-smoothing: antialiased;
text-rendering: optimizeLegibility;
-moz-osx-font-smoothing: grayscale;
font-feature-settings: "liga";
`;
return <IconContainer>{name}</IconContainer>;
return <Container>{name}</Container>;
};
/**
* Renders a button with an icon
* @param {IIconProps} props - The props of the given IconButton
* @returns {React.ReactNode} the icon button node
*/
export const IconButton = ({ icon, onClick }: IIconButtonProps) => (
<StyledButton onClick={onClick}>
<Icon name={icon} />
</StyledButton>
);
export default Icon;

View file

@ -2,12 +2,7 @@ import React from "react";
import Modal from "./modal";
import styled from "styled-components";
import selectedTheme from "../lib/theme";
import {
ListContainer,
ItemList,
Headline,
SubHeadline,
} from "./elements";
import { ListContainer, ItemList, Headline, SubHeadline } from "./elements";
const ModalSubHeadline = styled(SubHeadline)`
display: block;
@ -37,11 +32,6 @@ const ItemContainer = styled.div`
padding: 1rem 0;
`;
interface IImprintFieldProps {
text: string;
link: string;
}
export interface IImprintProps {
name: IImprintFieldProps;
address: IImprintFieldProps;
@ -51,17 +41,23 @@ export interface IImprintProps {
text: string;
}
interface IImprintFieldComponentProps {
field: IImprintFieldProps;
}
interface IImprintComponentProps {
imprint: IImprintProps;
}
interface IImprintFieldComponentProps {
field: IImprintFieldProps;
}
interface IImprintFieldProps {
text: string;
link: string;
}
/**
* Renders an imprint field
* @param {IImprintFieldComponentProps} props - The data for the field
* @param {IImprintFieldComponentProps} props data for the field
* @returns {React.ReactNode} the imprint field component
*/
const ImprintField = ({ field }: IImprintFieldComponentProps) => (
<Link href={field.link}>{field.text}</Link>
@ -69,7 +65,8 @@ const ImprintField = ({ field }: IImprintFieldComponentProps) => (
/**
* Renders the imprint component
* @param {IImprintProps} props - The contents of the imprint
* @param {IImprintProps} props contents of the imprint
* @returns {React.ReactNode} the imprint node
*/
const Imprint = ({ imprint }: IImprintComponentProps) => (
<>
@ -93,7 +90,7 @@ const Imprint = ({ imprint }: IImprintComponentProps) => (
<div>
<ModalSubHeadline>
Information in accordance with section 5 TMG
</ModalSubHeadline>
</ModalSubHeadline>
<>
{imprint.name && <ImprintField field={imprint.name} />}
{imprint.address && <ImprintField field={imprint.address} />}
@ -103,9 +100,7 @@ const Imprint = ({ imprint }: IImprintComponentProps) => (
</>
</div>
<div>
<ModalSubHeadline>
Imprint
</ModalSubHeadline>
<ModalSubHeadline>Imprint</ModalSubHeadline>
{imprint.text && <Text>{imprint.text}</Text>}
</div>
</Modal>

View file

@ -2,7 +2,8 @@ import React, { useState } from "react";
import styled from "styled-components";
import selectedTheme from "../lib/theme";
import { Headline, IconButton } from "./elements";
import { Headline } from "./elements";
import { IconButton } from "./icon";
const ModalContainer = styled.div`
position: absolute;
@ -49,9 +50,18 @@ interface IModalProps {
/**
* Renders a modal with button to hide and un-hide
* @param {IModalProps} props - The needed props for the modal
* @param {IModalProps} props needed props for the modal
* @returns {React.ReactNode} the modal component
*/
const Modal = ({ element, icon, text, condition, title, onClose, children }: IModalProps) => {
const Modal = ({
element,
icon,
text,
condition,
title,
onClose,
children,
}: IModalProps) => {
const [modalHidden, setModalHidden] = useState<boolean>(condition ?? true);
const closeModal = () => {
@ -65,9 +75,7 @@ const Modal = ({ element, icon, text, condition, title, onClose, children }: IMo
<IconButton icon={icon ?? ""} onClick={() => closeModal()} />
)}
{element === "text" && (
<Text onClick={() => closeModal()}>{text}</Text>
)}
{element === "text" && <Text onClick={() => closeModal()}>{text}</Text>}
<ModalContainer hidden={modalHidden}>
<TitleContainer>

View file

@ -16,18 +16,17 @@ const Search = styled.form`
const SearchInput = styled.input`
width: 100%;
margin: 0px;
font-size: 1rem;
border: none;
border-bottom: 1px solid ${selectedTheme.accentColor};
border-radius: 0;
background: none;
border-radius: 0;
color: ${selectedTheme.mainColor};
margin: 0px;
:focus {
outline: none;
}
@ -50,7 +49,7 @@ interface ISearchBarProps {
/**
* Renders a search bar
* @param {ISearchBarProps} props - The search providers for the search bar to use
* @param {ISearchBarProps} props - The search providers for the search bar to use
*/
const SearchBar = ({ providers }: ISearchBarProps) => {
let [input, setInput] = useState<string>("");

View file

@ -1,4 +1,4 @@
import React, { useState } from "react";
import { useState } from "react";
import styled from "styled-components";
import Select, { ValueType } from "react-select";
@ -62,15 +62,15 @@ const SelectorStyle: any = {
boxShadow: "none",
"&:hover": {
border: "1px solid",
borderColor: selectedTheme.mainColor
borderColor: selectedTheme.mainColor,
},
}),
dropdownIndicator: (base: any): any => ({
...base,
color: selectedTheme.mainColor,
"&:hover": {
color: selectedTheme.mainColor
}
color: selectedTheme.mainColor,
},
}),
indicatorSeparator: () => ({
display: "none",
@ -81,7 +81,7 @@ const SelectorStyle: any = {
border: "1px solid " + selectedTheme.mainColor,
borderRadius: 0,
boxShadow: "none",
margin: "4px 0"
margin: "4px 0",
}),
option: (base: any): any => ({
...base,
@ -115,7 +115,7 @@ interface ISettingsProps {
const Settings = ({ themes, providers }: ISettingsProps) => {
const [newTheme, setNewTheme] = useState<IThemeProps>();
if (themes && providers) {
if (themes || providers) {
return (
<Modal element="icon" icon="settings" title="Settings">
{themes && (