parent
eaad2d56f0
commit
fa28f68551
36 changed files with 962 additions and 368 deletions
10
package.json
10
package.json
|
@ -3,7 +3,9 @@
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"repository": "git@github.com:phntxx/dashboard",
|
"repository": "git@github.com:phntxx/dashboard",
|
||||||
"contributors": ["phntxx <hello@phntxx.com>"],
|
"contributors": [
|
||||||
|
"phntxx <hello@phntxx.com>"
|
||||||
|
],
|
||||||
"private": false,
|
"private": false,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/node": "^14.14.37",
|
"@types/node": "^14.14.37",
|
||||||
|
@ -45,7 +47,11 @@
|
||||||
"extends": "react-app"
|
"extends": "react-app"
|
||||||
},
|
},
|
||||||
"browserslist": {
|
"browserslist": {
|
||||||
"production": [">0.2%", "not dead", "not op_mini all"],
|
"production": [
|
||||||
|
">0.2%",
|
||||||
|
"not dead",
|
||||||
|
"not op_mini all"
|
||||||
|
],
|
||||||
"development": [
|
"development": [
|
||||||
"last 1 chrome version",
|
"last 1 chrome version",
|
||||||
"last 1 firefox version",
|
"last 1 firefox version",
|
||||||
|
|
33
src/app.tsx
33
src/app.tsx
|
@ -2,13 +2,13 @@ import { createGlobalStyle, ThemeProvider } from "styled-components";
|
||||||
|
|
||||||
import SearchBar from "./components/searchBar";
|
import SearchBar from "./components/searchBar";
|
||||||
import Greeter from "./components/greeter";
|
import Greeter from "./components/greeter";
|
||||||
import { AppList } from "./components/apps";
|
import AppList from "./components/appList";
|
||||||
import BookmarkList from "./components/bookmarks";
|
import BookmarkList from "./components/bookmarks";
|
||||||
import Settings from "./components/settings";
|
import Settings from "./components/settings";
|
||||||
import Imprint from "./components/imprint";
|
import Imprint from "./components/imprint";
|
||||||
|
|
||||||
import { IThemeProps, getTheme, setScheme } from "./lib/useTheme";
|
import { IThemeProps, getTheme, setScheme } from "./lib/useTheme";
|
||||||
import useFetch from "./lib/useFetch";
|
import useFetcher from "./lib/fetcher";
|
||||||
import useMediaQuery from "./lib/useMediaQuery";
|
import useMediaQuery from "./lib/useMediaQuery";
|
||||||
|
|
||||||
export const GlobalStyle = createGlobalStyle<{ theme: IThemeProps }>`
|
export const GlobalStyle = createGlobalStyle<{ theme: IThemeProps }>`
|
||||||
|
@ -33,26 +33,37 @@ const App = () => {
|
||||||
const {
|
const {
|
||||||
appData,
|
appData,
|
||||||
bookmarkData,
|
bookmarkData,
|
||||||
searchData,
|
searchProviderData,
|
||||||
themeData,
|
themeData,
|
||||||
imprintData,
|
imprintData,
|
||||||
greeterData,
|
greeterData,
|
||||||
} = useFetch();
|
} = useFetcher();
|
||||||
|
|
||||||
const theme = getTheme();
|
const theme = getTheme();
|
||||||
let isDark = useMediaQuery("(prefers-color-scheme: dark)");
|
let isDark = useMediaQuery("(prefers-color-scheme: dark)");
|
||||||
setScheme(isDark ? "dark-theme" : "light-theme");
|
if (isDark) {
|
||||||
|
setScheme("dark-theme");
|
||||||
|
} else {
|
||||||
|
setScheme("light-theme");
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ThemeProvider theme={theme}>
|
<ThemeProvider theme={theme}>
|
||||||
<GlobalStyle />
|
<GlobalStyle />
|
||||||
<div>
|
<div>
|
||||||
<SearchBar search={searchData} />
|
<SearchBar search={searchProviderData?.search} />
|
||||||
<Settings themes={themeData} search={searchData} />
|
{(!themeData.error || !searchProviderData.error) && (
|
||||||
<Greeter greeter={greeterData} />
|
<Settings
|
||||||
<AppList apps={appData?.apps} categories={appData?.categories} />
|
themes={themeData?.themes}
|
||||||
<BookmarkList groups={bookmarkData} />
|
search={searchProviderData?.search}
|
||||||
<Imprint imprint={imprintData} />
|
/>
|
||||||
|
)}
|
||||||
|
<Greeter data={greeterData.greeter} />
|
||||||
|
{!appData.error && (
|
||||||
|
<AppList apps={appData.apps} categories={appData.categories} />
|
||||||
|
)}
|
||||||
|
{!bookmarkData.error && <BookmarkList groups={bookmarkData.groups} />}
|
||||||
|
{!imprintData.error && <Imprint imprint={imprintData.imprint} />}
|
||||||
</div>
|
</div>
|
||||||
</ThemeProvider>
|
</ThemeProvider>
|
||||||
);
|
);
|
||||||
|
|
77
src/components/app.tsx
Normal file
77
src/components/app.tsx
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
import Icon from "./icon";
|
||||||
|
import styled from "styled-components";
|
||||||
|
|
||||||
|
const AppContainer = styled.a`
|
||||||
|
display: flex;
|
||||||
|
flex: 1 0 auto;
|
||||||
|
padding: 1rem;
|
||||||
|
color: ${(props) => props.theme.mainColor};
|
||||||
|
font-weight: 500;
|
||||||
|
text-transform: uppercase;
|
||||||
|
margin: 0;
|
||||||
|
text-decoration: none;
|
||||||
|
font-size: 1rem;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const IconContainer = styled.div`
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
margin-right: 0.5rem;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const DetailsContainer = styled.div`
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const AppName = styled.div`
|
||||||
|
a:hover {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
const AppDescription = styled.p`
|
||||||
|
text-transform: uppercase;
|
||||||
|
margin: 0;
|
||||||
|
font-size: 0.65rem;
|
||||||
|
font-weight: 400;
|
||||||
|
color: ${(props) => props.theme.accentColor};
|
||||||
|
`;
|
||||||
|
|
||||||
|
export interface IAppProps {
|
||||||
|
name: string;
|
||||||
|
icon: string;
|
||||||
|
url: string;
|
||||||
|
displayURL: string;
|
||||||
|
newTab?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Renders a single app shortcut
|
||||||
|
* @param {IAppProps} props the props of the given app
|
||||||
|
* @returns {React.ReactNode} the child node for the given app
|
||||||
|
*/
|
||||||
|
const App = ({ name, icon, url, displayURL, newTab }: IAppProps) => {
|
||||||
|
const linkAttrs =
|
||||||
|
newTab !== undefined && newTab
|
||||||
|
? {
|
||||||
|
target: "_blank",
|
||||||
|
rel: "noopener noreferrer",
|
||||||
|
}
|
||||||
|
: {};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<AppContainer href={url} {...linkAttrs}>
|
||||||
|
<IconContainer>
|
||||||
|
<Icon name={icon} />
|
||||||
|
</IconContainer>
|
||||||
|
<DetailsContainer>
|
||||||
|
<AppName>{name}</AppName>
|
||||||
|
<AppDescription>{displayURL}</AppDescription>
|
||||||
|
</DetailsContainer>
|
||||||
|
</AppContainer>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default App;
|
42
src/components/appCategory.tsx
Normal file
42
src/components/appCategory.tsx
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
import styled from "styled-components";
|
||||||
|
import App, { IAppProps } from "./app";
|
||||||
|
import { ItemList, Item, SubHeadline } from "./elements";
|
||||||
|
|
||||||
|
const CategoryHeadline = styled(SubHeadline)`
|
||||||
|
padding-top: 1rem;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const CategoryContainer = styled.div`
|
||||||
|
width: 100%;
|
||||||
|
`;
|
||||||
|
|
||||||
|
export interface IAppCategoryProps {
|
||||||
|
name: string;
|
||||||
|
items: Array<IAppProps>;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Renders one app category
|
||||||
|
* @param {IAppCategoryProps} props props of the given category
|
||||||
|
* @returns {React.ReactNode} the app category node
|
||||||
|
*/
|
||||||
|
const AppCategory = ({ name, items }: IAppCategoryProps) => (
|
||||||
|
<CategoryContainer>
|
||||||
|
{name && <CategoryHeadline>{name}</CategoryHeadline>}
|
||||||
|
<ItemList>
|
||||||
|
{items.map(({ name, icon, displayURL, newTab, url }, index) => (
|
||||||
|
<Item key={[name, index].join("")}>
|
||||||
|
<App
|
||||||
|
name={name}
|
||||||
|
icon={icon}
|
||||||
|
url={url}
|
||||||
|
displayURL={displayURL}
|
||||||
|
newTab={newTab}
|
||||||
|
/>
|
||||||
|
</Item>
|
||||||
|
))}
|
||||||
|
</ItemList>
|
||||||
|
</CategoryContainer>
|
||||||
|
);
|
||||||
|
|
||||||
|
export default AppCategory;
|
42
src/components/appList.tsx
Normal file
42
src/components/appList.tsx
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
import AppCategory, { IAppCategoryProps } from "./appCategory";
|
||||||
|
import { IAppProps } from "./app";
|
||||||
|
|
||||||
|
import { Headline, ListContainer } from "./elements";
|
||||||
|
|
||||||
|
export interface IAppListProps {
|
||||||
|
categories?: Array<IAppCategoryProps>;
|
||||||
|
apps?: Array<IAppProps>;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Renders one list containing all app categories and uncategorized apps
|
||||||
|
* @param {IAppListProps} props props of the given list of apps
|
||||||
|
* @returns {React.ReactNode} the app list component
|
||||||
|
*/
|
||||||
|
const AppList = ({ categories, apps }: IAppListProps) => {
|
||||||
|
if (apps || categories) {
|
||||||
|
return (
|
||||||
|
<ListContainer>
|
||||||
|
<Headline>Applications</Headline>
|
||||||
|
{categories &&
|
||||||
|
categories.map(({ name, items }, index) => (
|
||||||
|
<AppCategory
|
||||||
|
key={[name, index].join("")}
|
||||||
|
name={name}
|
||||||
|
items={items}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
{apps && (
|
||||||
|
<AppCategory
|
||||||
|
name={categories ? "Uncategorized apps" : ""}
|
||||||
|
items={apps}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</ListContainer>
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return <></>;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export default AppList;
|
|
@ -69,10 +69,15 @@ export interface IAppCategoryProps {
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IAppListProps {
|
export interface IAppListProps {
|
||||||
apps?: Array<IAppProps>;
|
|
||||||
categories?: Array<IAppCategoryProps>;
|
categories?: Array<IAppCategoryProps>;
|
||||||
|
apps?: Array<IAppProps>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const defaults: IAppListProps = {
|
||||||
|
categories: [],
|
||||||
|
apps: [],
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Renders a single app shortcut
|
* Renders a single app shortcut
|
||||||
* @param {IAppProps} props the props of the given app
|
* @param {IAppProps} props the props of the given app
|
||||||
|
@ -130,7 +135,7 @@ export const AppCategory = ({ name, items }: IAppCategoryProps) => (
|
||||||
* @returns {React.ReactNode} the app list component
|
* @returns {React.ReactNode} the app list component
|
||||||
*/
|
*/
|
||||||
export const AppList = ({ categories, apps }: IAppListProps) => {
|
export const AppList = ({ categories, apps }: IAppListProps) => {
|
||||||
if (apps || categories)
|
if (apps || categories) {
|
||||||
return (
|
return (
|
||||||
<ListContainer>
|
<ListContainer>
|
||||||
<Headline>Applications</Headline>
|
<Headline>Applications</Headline>
|
||||||
|
@ -150,8 +155,9 @@ export const AppList = ({ categories, apps }: IAppListProps) => {
|
||||||
)}
|
)}
|
||||||
</ListContainer>
|
</ListContainer>
|
||||||
);
|
);
|
||||||
|
} else {
|
||||||
return <></>;
|
return <></>;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export default AppList;
|
export default AppList;
|
||||||
|
|
|
@ -37,7 +37,7 @@ export interface IBookmarkGroupProps {
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IBookmarkListProps {
|
export interface IBookmarkListProps {
|
||||||
groups?: Array<IBookmarkGroupProps>;
|
groups: Array<IBookmarkGroupProps>;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -63,24 +63,15 @@ export const BookmarkGroup = ({ name, items }: IBookmarkGroupProps) => (
|
||||||
* @param {IBookmarkListProps} props props of the given bookmark list
|
* @param {IBookmarkListProps} props props of the given bookmark list
|
||||||
* @returns {React.ReactNode} the bookmark list component
|
* @returns {React.ReactNode} the bookmark list component
|
||||||
*/
|
*/
|
||||||
const BookmarkList = ({ groups }: IBookmarkListProps) => {
|
const BookmarkList = ({ groups }: IBookmarkListProps) => (
|
||||||
if (groups)
|
|
||||||
return (
|
|
||||||
<ListContainer>
|
<ListContainer>
|
||||||
<Headline>Bookmarks</Headline>
|
<Headline>Bookmarks</Headline>
|
||||||
<ItemList>
|
<ItemList>
|
||||||
{groups.map(({ name, items }, index) => (
|
{groups.map(({ name, items }, index) => (
|
||||||
<BookmarkGroup
|
<BookmarkGroup key={[name, index].join("")} name={name} items={items} />
|
||||||
key={[name, index].join("")}
|
|
||||||
name={name}
|
|
||||||
items={items}
|
|
||||||
/>
|
|
||||||
))}
|
))}
|
||||||
</ItemList>
|
</ItemList>
|
||||||
</ListContainer>
|
</ListContainer>
|
||||||
);
|
);
|
||||||
|
|
||||||
return <></>;
|
|
||||||
};
|
|
||||||
|
|
||||||
export default BookmarkList;
|
export default BookmarkList;
|
||||||
|
|
|
@ -20,7 +20,7 @@ const DateText = styled.h3`
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export interface IGreeterComponentProps {
|
export interface IGreeterComponentProps {
|
||||||
greeter?: IGreeterProps;
|
data: IGreeterProps;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IGreeterProps {
|
export interface IGreeterProps {
|
||||||
|
@ -112,18 +112,13 @@ export const getDateString = (
|
||||||
* @param {IGreeterComponentProps} data required greeter data
|
* @param {IGreeterComponentProps} data required greeter data
|
||||||
* @returns {React.ReactNode} the greeter
|
* @returns {React.ReactNode} the greeter
|
||||||
*/
|
*/
|
||||||
const Greeter = ({ greeter }: IGreeterComponentProps) => {
|
const Greeter = ({ data }: IGreeterComponentProps) => (
|
||||||
if (greeter)
|
|
||||||
return (
|
|
||||||
<GreeterContainer>
|
<GreeterContainer>
|
||||||
<DateText>
|
<DateText>
|
||||||
{getDateString(greeter.days, greeter.months, greeter.dateformat)}
|
{getDateString(data.days, data.months, data.dateformat)}
|
||||||
</DateText>
|
</DateText>
|
||||||
<GreetText>{getGreeting(greeter.greetings)}</GreetText>
|
<GreetText>{getGreeting(data.greetings)}</GreetText>
|
||||||
</GreeterContainer>
|
</GreeterContainer>
|
||||||
);
|
);
|
||||||
|
|
||||||
return <></>;
|
|
||||||
};
|
|
||||||
|
|
||||||
export default Greeter;
|
export default Greeter;
|
||||||
|
|
|
@ -31,12 +31,16 @@ const ItemContainer = styled.div`
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export interface IImprintProps {
|
export interface IImprintProps {
|
||||||
fields: Array<IImprintFieldProps>;
|
name: IImprintFieldProps;
|
||||||
|
address: IImprintFieldProps;
|
||||||
|
phone: IImprintFieldProps;
|
||||||
|
email: IImprintFieldProps;
|
||||||
|
url: IImprintFieldProps;
|
||||||
text: string;
|
text: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IImprintComponentProps {
|
export interface IImprintComponentProps {
|
||||||
imprint?: IImprintProps;
|
imprint: IImprintProps;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface IImprintFieldComponentProps {
|
interface IImprintFieldComponentProps {
|
||||||
|
@ -68,9 +72,7 @@ export const onClose = () => {
|
||||||
* @param {IImprintProps} props contents of the imprint
|
* @param {IImprintProps} props contents of the imprint
|
||||||
* @returns {React.ReactNode} the imprint node
|
* @returns {React.ReactNode} the imprint node
|
||||||
*/
|
*/
|
||||||
const Imprint = ({ imprint }: IImprintComponentProps) => {
|
const Imprint = ({ imprint }: IImprintComponentProps) => (
|
||||||
if (imprint)
|
|
||||||
return (
|
|
||||||
<>
|
<>
|
||||||
<ListContainer>
|
<ListContainer>
|
||||||
<Headline>About</Headline>
|
<Headline>About</Headline>
|
||||||
|
@ -84,21 +86,18 @@ const Imprint = ({ imprint }: IImprintComponentProps) => {
|
||||||
condition={!window.location.href.endsWith("#imprint")}
|
condition={!window.location.href.endsWith("#imprint")}
|
||||||
onClose={onClose}
|
onClose={onClose}
|
||||||
>
|
>
|
||||||
{imprint.fields && (
|
|
||||||
<div>
|
<div>
|
||||||
<ModalSubHeadline>
|
<ModalSubHeadline>
|
||||||
Information in accordance with section 5 TMG
|
Information in accordance with section 5 TMG
|
||||||
</ModalSubHeadline>
|
</ModalSubHeadline>
|
||||||
<>
|
<>
|
||||||
{imprint.fields.map((field, index) => (
|
{imprint.name && <ImprintField field={imprint.name} />}
|
||||||
<ImprintField
|
{imprint.address && <ImprintField field={imprint.address} />}
|
||||||
key={[field.text, index].join("")}
|
{imprint.email && <ImprintField field={imprint.email} />}
|
||||||
field={field}
|
{imprint.phone && <ImprintField field={imprint.phone} />}
|
||||||
/>
|
{imprint.url && <ImprintField field={imprint.url} />}
|
||||||
))}
|
|
||||||
</>
|
</>
|
||||||
</div>
|
</div>
|
||||||
)}
|
|
||||||
<div>
|
<div>
|
||||||
<ModalSubHeadline>Imprint</ModalSubHeadline>
|
<ModalSubHeadline>Imprint</ModalSubHeadline>
|
||||||
{imprint.text && <Text>{imprint.text}</Text>}
|
{imprint.text && <Text>{imprint.text}</Text>}
|
||||||
|
@ -110,7 +109,4 @@ const Imprint = ({ imprint }: IImprintComponentProps) => {
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|
||||||
return <></>;
|
|
||||||
};
|
|
||||||
|
|
||||||
export default Imprint;
|
export default Imprint;
|
||||||
|
|
|
@ -48,7 +48,7 @@ export interface ISearchProps {
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ISearchBarProps {
|
interface ISearchBarProps {
|
||||||
search?: ISearchProps;
|
search: ISearchProps;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const handleQueryWithProvider = (
|
export const handleQueryWithProvider = (
|
||||||
|
@ -79,13 +79,7 @@ export const handleQueryWithProvider = (
|
||||||
* Renders a search bar
|
* Renders a search bar
|
||||||
* @param {ISearchBarProps} search - The search providers for the search bar to use
|
* @param {ISearchBarProps} search - The search providers for the search bar to use
|
||||||
*/
|
*/
|
||||||
const SearchBar = ({
|
const SearchBar = ({ search }: ISearchBarProps) => {
|
||||||
search = {
|
|
||||||
placeholder: "",
|
|
||||||
defaultProvider: "",
|
|
||||||
providers: [],
|
|
||||||
},
|
|
||||||
}: ISearchBarProps) => {
|
|
||||||
let [input, setInput] = useState<string>("");
|
let [input, setInput] = useState<string>("");
|
||||||
let [buttonsHidden, setButtonsHidden] = useState<boolean>(true);
|
let [buttonsHidden, setButtonsHidden] = useState<boolean>(true);
|
||||||
|
|
||||||
|
|
|
@ -54,6 +54,11 @@ const Code = styled.p`
|
||||||
color: ${(props) => props.theme.accentColor};
|
color: ${(props) => props.theme.accentColor};
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
const ThemeHeader = styled.p`
|
||||||
|
grid-column: 1 / 4;
|
||||||
|
color: ${(props) => props.theme.accentColor};
|
||||||
|
`;
|
||||||
|
|
||||||
const ThemeSelect = styled(Select)`
|
const ThemeSelect = styled(Select)`
|
||||||
-webkit-appearance: button;
|
-webkit-appearance: button;
|
||||||
-moz-appearance: button;
|
-moz-appearance: button;
|
||||||
|
@ -61,7 +66,6 @@ const ThemeSelect = styled(Select)`
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
font-family: Roboto, sans-serif;
|
font-family: Roboto, sans-serif;
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
border-radius: 0;
|
|
||||||
border: 1px solid ${(props) => props.theme.mainColor};
|
border: 1px solid ${(props) => props.theme.mainColor};
|
||||||
color: ${(props) => props.theme.mainColor};
|
color: ${(props) => props.theme.mainColor};
|
||||||
background: none;
|
background: none;
|
||||||
|
@ -72,8 +76,8 @@ const ThemeSelect = styled(Select)`
|
||||||
`;
|
`;
|
||||||
|
|
||||||
interface ISettingsProps {
|
interface ISettingsProps {
|
||||||
themes?: Array<IThemeProps>;
|
themes: Array<IThemeProps> | undefined;
|
||||||
search?: ISearchProps;
|
search: ISearchProps | undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -95,36 +99,20 @@ const Settings = ({ themes, search }: ISettingsProps) => {
|
||||||
<Section>
|
<Section>
|
||||||
<SectionHeadline>Theme:</SectionHeadline>
|
<SectionHeadline>Theme:</SectionHeadline>
|
||||||
<FormContainer>
|
<FormContainer>
|
||||||
<Table>
|
<ThemeHeader>Light</ThemeHeader>
|
||||||
<tbody>
|
|
||||||
<TableRow>
|
|
||||||
<HeadCell>Light</HeadCell>
|
|
||||||
<HeadCell>Dark</HeadCell>
|
|
||||||
</TableRow>
|
|
||||||
<TableRow>
|
|
||||||
<TableCell>
|
|
||||||
<ThemeSelect
|
<ThemeSelect
|
||||||
items={themes}
|
items={themes}
|
||||||
onChange={(theme: IThemeProps) =>
|
onChange={(theme: IThemeProps) => setNewLightTheme(theme)}
|
||||||
setNewLightTheme(theme)
|
|
||||||
}
|
|
||||||
current={currentLightTheme}
|
current={currentLightTheme}
|
||||||
testId="light"
|
testId="light"
|
||||||
></ThemeSelect>
|
></ThemeSelect>
|
||||||
</TableCell>
|
<ThemeHeader>Dark</ThemeHeader>
|
||||||
<TableCell>
|
|
||||||
<ThemeSelect
|
<ThemeSelect
|
||||||
items={themes}
|
items={themes}
|
||||||
onChange={(theme: IThemeProps) =>
|
onChange={(theme: IThemeProps) => setNewDarkTheme(theme)}
|
||||||
setNewDarkTheme(theme)
|
|
||||||
}
|
|
||||||
current={currentDarkTheme}
|
current={currentDarkTheme}
|
||||||
testId="dark"
|
testId="dark"
|
||||||
></ThemeSelect>
|
></ThemeSelect>
|
||||||
</TableCell>
|
|
||||||
</TableRow>
|
|
||||||
</tbody>
|
|
||||||
</Table>
|
|
||||||
</FormContainer>
|
</FormContainer>
|
||||||
<Button
|
<Button
|
||||||
data-testid="button-submit"
|
data-testid="button-submit"
|
||||||
|
|
2
src/lib/useFetch.d.ts → src/lib/fetch.d.ts
vendored
2
src/lib/useFetch.d.ts → src/lib/fetch.d.ts
vendored
|
@ -1,7 +1,7 @@
|
||||||
import { ISearchProps } from "../components/searchBar";
|
import { ISearchProps } from "../components/searchBar";
|
||||||
import { IBookmarkGroupProps } from "../components/bookmarks";
|
import { IBookmarkGroupProps } from "../components/bookmarks";
|
||||||
import { IAppProps, IAppCategoryProps } from "../components/apps";
|
import { IAppProps, IAppCategoryProps } from "../components/apps";
|
||||||
import { IThemeProps } from "./useTheme";
|
import { IThemeProps } from "./theme";
|
||||||
import { IImprintProps } from "../components/imprint";
|
import { IImprintProps } from "../components/imprint";
|
||||||
import { IGreeterProps } from "../components/greeter";
|
import { IGreeterProps } from "../components/greeter";
|
||||||
|
|
91
src/lib/fetch.tsx
Normal file
91
src/lib/fetch.tsx
Normal file
|
@ -0,0 +1,91 @@
|
||||||
|
import React, { useCallback, useEffect, useState } from "react";
|
||||||
|
import { IAppListProps } from "../components/apps";
|
||||||
|
import { IThemeProps } from "./useTheme";
|
||||||
|
import { IBookmarkListProps } from "../components/bookmarks";
|
||||||
|
import { ISearchProps } from "../components/searchBar";
|
||||||
|
import { IImprintProps } from "../components/imprint";
|
||||||
|
import { IGreeterProps } from "../components/greeter";
|
||||||
|
|
||||||
|
const inProduction = process.env.NODE_ENV === "production";
|
||||||
|
|
||||||
|
interface IFetchItemProps {
|
||||||
|
url: string;
|
||||||
|
setHook?: React.Dispatch<React.SetStateAction<any>>;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IFetchListProps {
|
||||||
|
app: IFetchItemProps;
|
||||||
|
bookmarks: IFetchItemProps;
|
||||||
|
greeter: IFetchItemProps;
|
||||||
|
imprint: IFetchItemProps;
|
||||||
|
search: IFetchItemProps;
|
||||||
|
themes: IFetchItemProps;
|
||||||
|
}
|
||||||
|
|
||||||
|
let fetchList: IFetchListProps = {
|
||||||
|
app: { url: "/data/app.json" },
|
||||||
|
bookmarks: { url: "/data/bookmarks.json" },
|
||||||
|
greeter: { url: "/data/greeter.json" },
|
||||||
|
imprint: { url: "/data/imprint.json" },
|
||||||
|
search: { url: "/data/search.json" },
|
||||||
|
themes: { url: "/data/themes.json" },
|
||||||
|
};
|
||||||
|
|
||||||
|
export const handleResponse = (response: Response, type: string) => {
|
||||||
|
if (response.ok) return response.json();
|
||||||
|
throw new Error("Error fetching " + type + " data");
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleError = (error: Error) => {
|
||||||
|
console.error(error.message);
|
||||||
|
};
|
||||||
|
|
||||||
|
const fetchURL = (url: string, type: string) => {
|
||||||
|
const response = inProduction ? fetch(url) : import(".." + url);
|
||||||
|
|
||||||
|
return response
|
||||||
|
.then((response: Response) => handleResponse(response, type))
|
||||||
|
.catch(handleError);
|
||||||
|
};
|
||||||
|
|
||||||
|
const useFetch = () => {
|
||||||
|
const [appData, setAppData] = useState<IAppListProps>();
|
||||||
|
fetchList.app.setHook = setAppData;
|
||||||
|
|
||||||
|
const [bookmarkData, setBookmarkData] = useState<IBookmarkListProps>();
|
||||||
|
fetchList.bookmarks.setHook = setBookmarkData;
|
||||||
|
|
||||||
|
const [greeterData, setGreeterData] = useState<IGreeterProps>();
|
||||||
|
fetchList.greeter.setHook = setGreeterData;
|
||||||
|
|
||||||
|
const [imprintData, setImprintData] = useState<IImprintProps>();
|
||||||
|
fetchList.imprint.setHook = setImprintData;
|
||||||
|
|
||||||
|
const [searchData, setSearchData] = useState<ISearchProps>();
|
||||||
|
fetchList.search.setHook = setSearchData;
|
||||||
|
|
||||||
|
const [themeData, setThemeData] = useState<Array<IThemeProps>>();
|
||||||
|
fetchList.themes.setHook = setThemeData;
|
||||||
|
|
||||||
|
const callback = useCallback(() => {
|
||||||
|
Object.entries(fetchList).forEach(([key, val]) => {
|
||||||
|
fetchURL(val.url, key).then((data) => {
|
||||||
|
val.setHook(data);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() => callback(), [callback]);
|
||||||
|
|
||||||
|
return {
|
||||||
|
appData,
|
||||||
|
bookmarkData,
|
||||||
|
greeterData,
|
||||||
|
imprintData,
|
||||||
|
searchData,
|
||||||
|
themeData,
|
||||||
|
callback,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export default useFetch;
|
32
src/lib/fetcher.d.ts
vendored
Normal file
32
src/lib/fetcher.d.ts
vendored
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
import { ISearchProps } from "../components/searchBar";
|
||||||
|
import { IBookmarkGroupProps } from "../components/bookmarks";
|
||||||
|
import { IAppCategoryProps } from "../components/appCategory";
|
||||||
|
import { IAppProps } from "../components/app";
|
||||||
|
import { IThemeProps } from "./theme";
|
||||||
|
import { IImprintProps } from "../components/imprint";
|
||||||
|
import { IGreeterProps } from "../components/greeter";
|
||||||
|
|
||||||
|
declare module "../data/apps.json" {
|
||||||
|
export const categories: IAppCategoryProps[];
|
||||||
|
export const apps: IAppProps[];
|
||||||
|
}
|
||||||
|
|
||||||
|
declare module "../data/search.json" {
|
||||||
|
export const search: ISearchProps;
|
||||||
|
}
|
||||||
|
|
||||||
|
declare module "../data/bookmarks.json" {
|
||||||
|
export const groups: IBookmarkGroupProps[];
|
||||||
|
}
|
||||||
|
|
||||||
|
declare module "../data/themes.json" {
|
||||||
|
export const themes: IThemeProps[];
|
||||||
|
}
|
||||||
|
|
||||||
|
declare module "../data/imprint.json" {
|
||||||
|
export const imprint: IImprintProps;
|
||||||
|
}
|
||||||
|
|
||||||
|
declare module "../data/greeter.json" {
|
||||||
|
export const greeter: IGreeterProps;
|
||||||
|
}
|
278
src/lib/fetcher.tsx
Normal file
278
src/lib/fetcher.tsx
Normal file
|
@ -0,0 +1,278 @@
|
||||||
|
import { useCallback, useEffect, useState } from "react";
|
||||||
|
|
||||||
|
import { ISearchProps } from "../components/searchBar";
|
||||||
|
import { IBookmarkGroupProps } from "../components/bookmarks";
|
||||||
|
import { IAppCategoryProps } from "../components/appCategory";
|
||||||
|
import { IAppProps } from "../components/app";
|
||||||
|
import { IThemeProps } from "./useTheme";
|
||||||
|
import { IImprintProps } from "../components/imprint";
|
||||||
|
import { IGreeterProps } from "../components/greeter";
|
||||||
|
|
||||||
|
const errorMessage = "Failed to load data.";
|
||||||
|
const inProduction = process.env.NODE_ENV === "production";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles the response from the fetch requests
|
||||||
|
* @param {Response} response - The response given by the fetch request
|
||||||
|
* @returns - The response in JSON
|
||||||
|
* @throws - Error with given error message if request failed
|
||||||
|
*/
|
||||||
|
export const handleResponse = (response: Response) => {
|
||||||
|
if (response.ok) return response.json();
|
||||||
|
throw new Error(errorMessage);
|
||||||
|
};
|
||||||
|
|
||||||
|
export interface ISearchDataProps {
|
||||||
|
search: ISearchProps;
|
||||||
|
error: string | boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IBookmarkDataProps {
|
||||||
|
groups: Array<IBookmarkGroupProps>;
|
||||||
|
error: string | boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IAppDataProps {
|
||||||
|
categories: Array<IAppCategoryProps>;
|
||||||
|
apps: Array<IAppProps>;
|
||||||
|
error: string | boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IThemeDataProps {
|
||||||
|
themes: Array<IThemeProps>;
|
||||||
|
error: string | boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IImprintDataProps {
|
||||||
|
imprint: IImprintProps;
|
||||||
|
error: string | boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IGreeterDataProps {
|
||||||
|
greeter: IGreeterProps;
|
||||||
|
error: string | boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default values for the respective state variables
|
||||||
|
*/
|
||||||
|
export const defaults = {
|
||||||
|
app: {
|
||||||
|
categories: [],
|
||||||
|
apps: [],
|
||||||
|
error: false,
|
||||||
|
},
|
||||||
|
bookmark: {
|
||||||
|
groups: [],
|
||||||
|
error: false,
|
||||||
|
},
|
||||||
|
search: {
|
||||||
|
search: {
|
||||||
|
placeholder: "",
|
||||||
|
defaultProvider: "https://google.com/search?q=",
|
||||||
|
providers: [],
|
||||||
|
},
|
||||||
|
error: false,
|
||||||
|
},
|
||||||
|
theme: {
|
||||||
|
themes: [],
|
||||||
|
error: false,
|
||||||
|
},
|
||||||
|
imprint: {
|
||||||
|
imprint: {
|
||||||
|
name: { text: "", link: "" },
|
||||||
|
address: { text: "", link: "" },
|
||||||
|
phone: { text: "", link: "" },
|
||||||
|
email: { text: "", link: "" },
|
||||||
|
url: { text: "", link: "" },
|
||||||
|
text: "",
|
||||||
|
},
|
||||||
|
error: false,
|
||||||
|
},
|
||||||
|
greeter: {
|
||||||
|
greeter: {
|
||||||
|
months: [
|
||||||
|
"January",
|
||||||
|
"February",
|
||||||
|
"March",
|
||||||
|
"April",
|
||||||
|
"May",
|
||||||
|
"June",
|
||||||
|
"July",
|
||||||
|
"August",
|
||||||
|
"September",
|
||||||
|
"October",
|
||||||
|
"November",
|
||||||
|
"December",
|
||||||
|
],
|
||||||
|
days: [
|
||||||
|
"Sunday",
|
||||||
|
"Monday",
|
||||||
|
"Tuesday",
|
||||||
|
"Wednesday",
|
||||||
|
"Thursday",
|
||||||
|
"Friday",
|
||||||
|
"Saturday",
|
||||||
|
],
|
||||||
|
greetings: [
|
||||||
|
{
|
||||||
|
greeting: "Good night!",
|
||||||
|
start: 0,
|
||||||
|
end: 6,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
greeting: "Good morning!",
|
||||||
|
start: 6,
|
||||||
|
end: 12,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
greeting: "Good afternoon!",
|
||||||
|
start: 12,
|
||||||
|
end: 18,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
greeting: "Good evening!",
|
||||||
|
start: 18,
|
||||||
|
end: 0,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
dateformat: "%wd, %m %d%e %y",
|
||||||
|
},
|
||||||
|
error: false,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles fetch errors by returning the error message.
|
||||||
|
* @param {string} type - The type of fetch request that threw an error
|
||||||
|
* @param {Error} error - The error itself
|
||||||
|
*/
|
||||||
|
export const handleError = (status: string, error: Error) => {
|
||||||
|
switch (status) {
|
||||||
|
case "apps":
|
||||||
|
return { ...defaults.app, error: error.message };
|
||||||
|
case "bookmark":
|
||||||
|
return { ...defaults.bookmark, error: error.message };
|
||||||
|
case "searchProvider":
|
||||||
|
return { ...defaults.search, error: error.message };
|
||||||
|
case "theme":
|
||||||
|
return { ...defaults.theme, error: error.message };
|
||||||
|
case "imprint":
|
||||||
|
return { ...defaults.imprint, error: error.message };
|
||||||
|
case "greeter":
|
||||||
|
return { ...defaults.greeter, error: error.message };
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetches all of the data by doing fetch requests (only available in production)
|
||||||
|
*/
|
||||||
|
export const fetchProduction = Promise.all([
|
||||||
|
fetch("/data/apps.json")
|
||||||
|
.then(handleResponse)
|
||||||
|
.catch((error: Error) => handleError("apps", error)),
|
||||||
|
fetch("/data/bookmarks.json")
|
||||||
|
.then(handleResponse)
|
||||||
|
.catch((error: Error) => handleError("bookmark", error)),
|
||||||
|
fetch("/data/search.json")
|
||||||
|
.then(handleResponse)
|
||||||
|
.catch((error: Error) => handleError("searchProvider", error)),
|
||||||
|
fetch("/data/themes.json")
|
||||||
|
.then(handleResponse)
|
||||||
|
.catch((error: Error) => handleError("theme", error)),
|
||||||
|
fetch("/data/imprint.json")
|
||||||
|
.then(handleResponse)
|
||||||
|
.catch((error: Error) => handleError("imprint", error)),
|
||||||
|
fetch("/data/greeter.json")
|
||||||
|
.then(handleResponse)
|
||||||
|
.catch((error: Error) => handleError("greeter", error)),
|
||||||
|
]);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetches all of the data by importing it (only available in development)
|
||||||
|
*/
|
||||||
|
export const fetchDevelopment = Promise.all([
|
||||||
|
import("../data/apps.json"),
|
||||||
|
import("../data/bookmarks.json"),
|
||||||
|
import("../data/search.json"),
|
||||||
|
import("../data/themes.json"),
|
||||||
|
import("../data/imprint.json"),
|
||||||
|
import("../data/greeter.json"),
|
||||||
|
]);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetches app, bookmark, search, theme and imprint data and returns it.
|
||||||
|
*/
|
||||||
|
export const useFetcher = () => {
|
||||||
|
const [appData, setAppData] = useState<IAppDataProps>(defaults.app);
|
||||||
|
|
||||||
|
const [bookmarkData, setBookmarkData] = useState<IBookmarkDataProps>(
|
||||||
|
defaults.bookmark,
|
||||||
|
);
|
||||||
|
|
||||||
|
const [searchProviderData, setSearchProviderData] =
|
||||||
|
useState<ISearchDataProps>(defaults.search);
|
||||||
|
|
||||||
|
const [themeData, setThemeData] = useState<IThemeDataProps>(defaults.theme);
|
||||||
|
|
||||||
|
const [imprintData, setImprintData] = useState<IImprintDataProps>(
|
||||||
|
defaults.imprint,
|
||||||
|
);
|
||||||
|
|
||||||
|
const [greeterData, setGreeterData] = useState<IGreeterDataProps>(
|
||||||
|
defaults.greeter,
|
||||||
|
);
|
||||||
|
|
||||||
|
const callback = useCallback(() => {
|
||||||
|
(inProduction ? fetchProduction : fetchDevelopment).then(
|
||||||
|
([
|
||||||
|
appData,
|
||||||
|
bookmarkData,
|
||||||
|
searchData,
|
||||||
|
themeData,
|
||||||
|
imprintData,
|
||||||
|
greeterData,
|
||||||
|
]: [
|
||||||
|
IAppDataProps,
|
||||||
|
IBookmarkDataProps,
|
||||||
|
ISearchDataProps,
|
||||||
|
IThemeDataProps,
|
||||||
|
IImprintDataProps,
|
||||||
|
IGreeterDataProps,
|
||||||
|
]) => {
|
||||||
|
setAppData(appData.error ? appData : { ...appData, error: false });
|
||||||
|
setBookmarkData(
|
||||||
|
bookmarkData.error ? bookmarkData : { ...bookmarkData, error: false },
|
||||||
|
);
|
||||||
|
setSearchProviderData(
|
||||||
|
searchData.error ? searchData : { ...searchData, error: false },
|
||||||
|
);
|
||||||
|
setThemeData(
|
||||||
|
themeData.error ? themeData : { ...themeData, error: false },
|
||||||
|
);
|
||||||
|
setImprintData(
|
||||||
|
imprintData.error ? imprintData : { ...imprintData, error: false },
|
||||||
|
);
|
||||||
|
setGreeterData(
|
||||||
|
greeterData.error ? greeterData : { ...greeterData, error: false },
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() => callback(), [callback]);
|
||||||
|
|
||||||
|
return {
|
||||||
|
appData,
|
||||||
|
bookmarkData,
|
||||||
|
searchProviderData,
|
||||||
|
themeData,
|
||||||
|
imprintData,
|
||||||
|
greeterData,
|
||||||
|
callback,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export default useFetcher;
|
|
@ -1,119 +0,0 @@
|
||||||
import { useCallback, useEffect, useState } from "react";
|
|
||||||
|
|
||||||
import { ISearchProps } from "../components/searchBar";
|
|
||||||
import { IBookmarkGroupProps } from "../components/bookmarks";
|
|
||||||
import { IAppProps, IAppCategoryProps } from "../components/apps";
|
|
||||||
import { IImprintProps } from "../components/imprint";
|
|
||||||
import { IGreeterProps } from "../components/greeter";
|
|
||||||
|
|
||||||
import { IThemeProps } from "./useTheme";
|
|
||||||
|
|
||||||
const inProduction = process.env.NODE_ENV === "production";
|
|
||||||
|
|
||||||
export interface IAppDataProps {
|
|
||||||
categories: Array<IAppCategoryProps>;
|
|
||||||
apps: Array<IAppProps>;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IBookmarkDataProps {
|
|
||||||
groups: Array<IBookmarkGroupProps>;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IGreeterDataProps {
|
|
||||||
greeter: IGreeterProps;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IImprintDataProps {
|
|
||||||
imprint: IImprintProps;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ISearchDataProps {
|
|
||||||
search: ISearchProps;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IThemeDataProps {
|
|
||||||
themes: Array<IThemeProps>;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Fetches all of the data by doing fetch requests (only available in production)
|
|
||||||
*/
|
|
||||||
export const fetchProduction = Promise.all([
|
|
||||||
fetch("/data/apps.json")
|
|
||||||
.then((res) => res.json())
|
|
||||||
.catch(console.error),
|
|
||||||
fetch("/data/bookmarks.json")
|
|
||||||
.then((res) => res.json())
|
|
||||||
.catch(console.error),
|
|
||||||
fetch("/data/search.json")
|
|
||||||
.then((res) => res.json())
|
|
||||||
.catch(console.error),
|
|
||||||
fetch("/data/themes.json")
|
|
||||||
.then((res) => res.json())
|
|
||||||
.catch(console.error),
|
|
||||||
fetch("/data/imprint.json")
|
|
||||||
.then((res) => res.json())
|
|
||||||
.catch(console.error),
|
|
||||||
fetch("/data/greeter.json")
|
|
||||||
.then((res) => res.json())
|
|
||||||
.catch(console.error),
|
|
||||||
]);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Fetches all of the data by importing it (only available in development)
|
|
||||||
*/
|
|
||||||
export const fetchDevelopment = Promise.all([
|
|
||||||
import("../data/apps.json"),
|
|
||||||
import("../data/bookmarks.json"),
|
|
||||||
import("../data/search.json"),
|
|
||||||
import("../data/themes.json"),
|
|
||||||
import("../data/imprint.json"),
|
|
||||||
import("../data/greeter.json"),
|
|
||||||
]);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Fetches app, bookmark, search, theme and imprint data and returns it.
|
|
||||||
*/
|
|
||||||
export const useFetch = () => {
|
|
||||||
const [appData, setAppData] = useState<IAppDataProps>();
|
|
||||||
const [bookmarkData, setBookmarkData] =
|
|
||||||
useState<Array<IBookmarkGroupProps>>();
|
|
||||||
const [greeterData, setGreeterData] = useState<IGreeterProps>();
|
|
||||||
const [imprintData, setImprintData] = useState<IImprintProps>();
|
|
||||||
const [searchData, setSearchData] = useState<ISearchProps>();
|
|
||||||
const [themeData, setThemeData] = useState<Array<IThemeProps>>();
|
|
||||||
|
|
||||||
const callback = useCallback(() => {
|
|
||||||
(inProduction ? fetchProduction : fetchDevelopment).then(
|
|
||||||
([apps, { groups }, { search }, { themes }, { imprint }, { greeter }]: [
|
|
||||||
IAppDataProps,
|
|
||||||
IBookmarkDataProps,
|
|
||||||
ISearchDataProps,
|
|
||||||
IThemeDataProps,
|
|
||||||
IImprintDataProps,
|
|
||||||
IGreeterDataProps,
|
|
||||||
]) => {
|
|
||||||
setAppData(apps);
|
|
||||||
setBookmarkData(groups);
|
|
||||||
setSearchData(search);
|
|
||||||
setThemeData(themes);
|
|
||||||
setImprintData(imprint);
|
|
||||||
setGreeterData(greeter);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
useEffect(() => callback(), [callback]);
|
|
||||||
|
|
||||||
return {
|
|
||||||
appData,
|
|
||||||
bookmarkData,
|
|
||||||
searchData,
|
|
||||||
themeData,
|
|
||||||
imprintData,
|
|
||||||
greeterData,
|
|
||||||
callback,
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
export default useFetch;
|
|
7
src/test/components/__snapshots__/app.spec.tsx.snap
Normal file
7
src/test/components/__snapshots__/app.spec.tsx.snap
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
|
exports[`app.tsx Tests app rendering with newTab=false 1`] = `[Function]`;
|
||||||
|
|
||||||
|
exports[`app.tsx Tests app rendering with newTab=true 1`] = `[Function]`;
|
||||||
|
|
||||||
|
exports[`app.tsx Tests app rendering without newTab 1`] = `[Function]`;
|
|
@ -0,0 +1,3 @@
|
||||||
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
|
exports[`AppCategory snapshot test 1`] = `[Function]`;
|
9
src/test/components/__snapshots__/appList.spec.tsx.snap
Normal file
9
src/test/components/__snapshots__/appList.spec.tsx.snap
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
|
exports[`appList.tsx Tests AppList rendering with apps 1`] = `[Function]`;
|
||||||
|
|
||||||
|
exports[`appList.tsx Tests AppList rendering with categories 1`] = `[Function]`;
|
||||||
|
|
||||||
|
exports[`appList.tsx Tests AppList rendering with categories and apps 1`] = `[Function]`;
|
||||||
|
|
||||||
|
exports[`appList.tsx Tests AppList rendering with neither 1`] = `[Function]`;
|
|
@ -17,5 +17,3 @@ exports[`app.tsx Tests AppList rendering 2`] = `[Function]`;
|
||||||
exports[`app.tsx Tests AppList rendering 3`] = `[Function]`;
|
exports[`app.tsx Tests AppList rendering 3`] = `[Function]`;
|
||||||
|
|
||||||
exports[`app.tsx Tests AppList rendering 4`] = `[Function]`;
|
exports[`app.tsx Tests AppList rendering 4`] = `[Function]`;
|
||||||
|
|
||||||
exports[`app.tsx Tests AppList rendering without any props 1`] = `[Function]`;
|
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
exports[`bookmarks.tsx Tests BookmarkGroup rendering 1`] = `[Function]`;
|
exports[`BookmarkGroup snapshot test 1`] = `[Function]`;
|
||||||
|
|
||||||
exports[`bookmarks.tsx Tests BookmarkList rendering with props 1`] = `[Function]`;
|
exports[`BookmarkList snapshot test 1`] = `[Function]`;
|
||||||
|
|
||||||
exports[`bookmarks.tsx Tests BookmarkList rendering without props 1`] = `[Function]`;
|
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
exports[`greeter.tsx tests greeter rendering with props 1`] = `[Function]`;
|
exports[`Greeter snapshot test 1`] = `[Function]`;
|
||||||
|
|
||||||
exports[`greeter.tsx tests greeter rendering without props 1`] = `[Function]`;
|
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
exports[`imprint.tsx Tests Imprint rendering with props 1`] = `[Function]`;
|
exports[`imprint.tsx Tests Imprint 1`] = `[Function]`;
|
||||||
|
|
||||||
exports[`imprint.tsx Tests ImprintField 1`] = `[Function]`;
|
exports[`imprint.tsx Tests ImprintField 1`] = `[Function]`;
|
||||||
|
|
||||||
exports[`imprint.tsx Tests imprint rendering without props 1`] = `[Function]`;
|
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
exports[`searchBar.tsx Tests SearchBar rendering with props 1`] = `[Function]`;
|
exports[`searchBar.tsx Tests SearchBar rendering 1`] = `[Function]`;
|
||||||
|
|
||||||
exports[`searchBar.tsx Tests SearchBar rendering without props 1`] = `[Function]`;
|
|
||||||
|
|
52
src/test/components/app.spec.tsx
Normal file
52
src/test/components/app.spec.tsx
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
import { render } from "@testing-library/react";
|
||||||
|
import App, { IAppProps } from "../../components/app";
|
||||||
|
|
||||||
|
const props: IAppProps = {
|
||||||
|
name: "App Test",
|
||||||
|
icon: "bug_report",
|
||||||
|
url: "#",
|
||||||
|
displayURL: "test",
|
||||||
|
};
|
||||||
|
|
||||||
|
describe("app.tsx", () => {
|
||||||
|
it("Tests app rendering with newTab=true", () => {
|
||||||
|
const { asFragment } = render(
|
||||||
|
<App
|
||||||
|
name={props.name}
|
||||||
|
icon={props.icon}
|
||||||
|
url={props.url}
|
||||||
|
displayURL={props.displayURL}
|
||||||
|
newTab={true}
|
||||||
|
/>,
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(asFragment).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Tests app rendering with newTab=false", () => {
|
||||||
|
const { asFragment } = render(
|
||||||
|
<App
|
||||||
|
name={props.name}
|
||||||
|
icon={props.icon}
|
||||||
|
url={props.url}
|
||||||
|
displayURL={props.displayURL}
|
||||||
|
newTab={false}
|
||||||
|
/>,
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(asFragment).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Tests app rendering without newTab", () => {
|
||||||
|
const { asFragment } = render(
|
||||||
|
<App
|
||||||
|
name={props.name}
|
||||||
|
icon={props.icon}
|
||||||
|
url={props.url}
|
||||||
|
displayURL={props.displayURL}
|
||||||
|
/>,
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(asFragment).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
});
|
30
src/test/components/appCategory.spec.tsx
Normal file
30
src/test/components/appCategory.spec.tsx
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
import { render } from "@testing-library/react";
|
||||||
|
import AppCategory, { IAppCategoryProps } from "../../components/appCategory";
|
||||||
|
|
||||||
|
const props: IAppCategoryProps = {
|
||||||
|
name: "Category Test",
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
name: "App Test",
|
||||||
|
icon: "bug_report",
|
||||||
|
url: "#",
|
||||||
|
displayURL: "test",
|
||||||
|
newTab: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "App Test",
|
||||||
|
icon: "bug_report",
|
||||||
|
url: "#",
|
||||||
|
displayURL: "test",
|
||||||
|
newTab: false,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
it("AppCategory snapshot test", () => {
|
||||||
|
const { asFragment } = render(
|
||||||
|
<AppCategory name={props.name} items={props.items} />,
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(asFragment).toMatchSnapshot();
|
||||||
|
});
|
60
src/test/components/appList.spec.tsx
Normal file
60
src/test/components/appList.spec.tsx
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
import { render } from "@testing-library/react";
|
||||||
|
import AppList, { IAppListProps } from "../../components/appList";
|
||||||
|
|
||||||
|
const props: IAppListProps = {
|
||||||
|
categories: [
|
||||||
|
{
|
||||||
|
name: "Category Test",
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
name: "App Test",
|
||||||
|
icon: "bug_report",
|
||||||
|
url: "#",
|
||||||
|
displayURL: "test",
|
||||||
|
newTab: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "App Test",
|
||||||
|
icon: "bug_report",
|
||||||
|
url: "#",
|
||||||
|
displayURL: "test",
|
||||||
|
newTab: false,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
apps: [
|
||||||
|
{
|
||||||
|
name: "App Test",
|
||||||
|
icon: "bug_report",
|
||||||
|
url: "#",
|
||||||
|
displayURL: "test",
|
||||||
|
newTab: false,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
describe("appList.tsx", () => {
|
||||||
|
it("Tests AppList rendering with categories and apps", () => {
|
||||||
|
const { asFragment } = render(
|
||||||
|
<AppList categories={props.categories} apps={props.apps} />,
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(asFragment).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Tests AppList rendering with categories", () => {
|
||||||
|
const { asFragment } = render(<AppList categories={props.categories} />);
|
||||||
|
expect(asFragment).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Tests AppList rendering with apps", () => {
|
||||||
|
const { asFragment } = render(<AppList apps={props.apps} />);
|
||||||
|
expect(asFragment).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Tests AppList rendering with neither", () => {
|
||||||
|
const { asFragment } = render(<AppList />);
|
||||||
|
expect(asFragment).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
});
|
|
@ -96,9 +96,4 @@ describe("app.tsx", () => {
|
||||||
expect(asFragment).toMatchSnapshot();
|
expect(asFragment).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Tests AppList rendering without any props", () => {
|
|
||||||
const { asFragment } = render(<AppList />);
|
|
||||||
expect(asFragment).toMatchSnapshot();
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
|
@ -19,8 +19,7 @@ const bookmarkListProps: IBookmarkListProps = {
|
||||||
groups: [bookmarkGroupProps, bookmarkGroupProps],
|
groups: [bookmarkGroupProps, bookmarkGroupProps],
|
||||||
};
|
};
|
||||||
|
|
||||||
describe("bookmarks.tsx", () => {
|
it("BookmarkGroup snapshot test", () => {
|
||||||
it("Tests BookmarkGroup rendering", () => {
|
|
||||||
const { asFragment } = render(
|
const { asFragment } = render(
|
||||||
<BookmarkGroup
|
<BookmarkGroup
|
||||||
name={bookmarkGroupProps.name}
|
name={bookmarkGroupProps.name}
|
||||||
|
@ -31,16 +30,10 @@ describe("bookmarks.tsx", () => {
|
||||||
expect(asFragment).toMatchSnapshot();
|
expect(asFragment).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Tests BookmarkList rendering with props", () => {
|
it("BookmarkList snapshot test", () => {
|
||||||
const { asFragment } = render(
|
const { asFragment } = render(
|
||||||
<BookmarkList groups={bookmarkListProps.groups} />,
|
<BookmarkList groups={bookmarkListProps.groups} />,
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(asFragment).toMatchSnapshot();
|
expect(asFragment).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Tests BookmarkList rendering without props", () => {
|
|
||||||
const { asFragment } = render(<BookmarkList />);
|
|
||||||
expect(asFragment).toMatchSnapshot();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
|
@ -54,8 +54,7 @@ const props: IGreeterProps = {
|
||||||
dateformat: "%wd, %m %d%e %y",
|
dateformat: "%wd, %m %d%e %y",
|
||||||
};
|
};
|
||||||
|
|
||||||
describe("greeter.tsx", () => {
|
it("isBetween test", () => {
|
||||||
it("tests isBetween", () => {
|
|
||||||
expect(isBetween(5, 1, 3)).toBeFalsy;
|
expect(isBetween(5, 1, 3)).toBeFalsy;
|
||||||
expect(isBetween(64, 1, 8)).toBeFalsy;
|
expect(isBetween(64, 1, 8)).toBeFalsy;
|
||||||
expect(isBetween(-1, -5, -3)).toBeFalsy;
|
expect(isBetween(-1, -5, -3)).toBeFalsy;
|
||||||
|
@ -64,7 +63,7 @@ describe("greeter.tsx", () => {
|
||||||
expect(isBetween(-3, -5, -1)).toBeTruthy;
|
expect(isBetween(-3, -5, -1)).toBeTruthy;
|
||||||
});
|
});
|
||||||
|
|
||||||
it("tests getExtension", () => {
|
it("getExtension test", () => {
|
||||||
expect(getExtension(0)).toEqual("th");
|
expect(getExtension(0)).toEqual("th");
|
||||||
expect(getExtension(1)).toEqual("st");
|
expect(getExtension(1)).toEqual("st");
|
||||||
expect(getExtension(2)).toEqual("nd");
|
expect(getExtension(2)).toEqual("nd");
|
||||||
|
@ -72,13 +71,7 @@ describe("greeter.tsx", () => {
|
||||||
expect(getExtension(15)).toEqual("th");
|
expect(getExtension(15)).toEqual("th");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("tests greeter rendering with props", () => {
|
it("Greeter snapshot test", () => {
|
||||||
const { asFragment } = render(<Greeter greeter={props} />);
|
const { asFragment } = render(<Greeter data={props} />);
|
||||||
expect(asFragment).toMatchSnapshot();
|
expect(asFragment).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("tests greeter rendering without props", () => {
|
|
||||||
const { asFragment } = render(<Greeter />);
|
|
||||||
expect(asFragment).toMatchSnapshot();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
|
@ -6,16 +6,26 @@ import Imprint, {
|
||||||
} from "../../components/imprint";
|
} from "../../components/imprint";
|
||||||
|
|
||||||
const props: IImprintProps = {
|
const props: IImprintProps = {
|
||||||
fields: [
|
name: {
|
||||||
{
|
text: "Test Name",
|
||||||
text: "Test Field",
|
|
||||||
link: "#",
|
link: "#",
|
||||||
},
|
},
|
||||||
{
|
address: {
|
||||||
text: "Test Field",
|
text: "Test Address",
|
||||||
|
link: "#",
|
||||||
|
},
|
||||||
|
phone: {
|
||||||
|
text: "Test Phone",
|
||||||
|
link: "#",
|
||||||
|
},
|
||||||
|
email: {
|
||||||
|
text: "Test Email",
|
||||||
|
link: "#",
|
||||||
|
},
|
||||||
|
url: {
|
||||||
|
text: "Test URL",
|
||||||
link: "#",
|
link: "#",
|
||||||
},
|
},
|
||||||
],
|
|
||||||
text: "This is a test!",
|
text: "This is a test!",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -32,16 +42,11 @@ describe("imprint.tsx", () => {
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Tests Imprint rendering with props", () => {
|
it("Tests Imprint", () => {
|
||||||
const { asFragment } = render(<Imprint imprint={props} />);
|
const { asFragment } = render(<Imprint imprint={props} />);
|
||||||
expect(asFragment).toMatchSnapshot();
|
expect(asFragment).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Tests imprint rendering without props", () => {
|
|
||||||
const { asFragment } = render(<Imprint />);
|
|
||||||
expect(asFragment).toMatchSnapshot();
|
|
||||||
});
|
|
||||||
|
|
||||||
it("Tests onClose with #imprint", () => {
|
it("Tests onClose with #imprint", () => {
|
||||||
const location = window.location.href;
|
const location = window.location.href;
|
||||||
window.location.href = location + "#imprint";
|
window.location.href = location + "#imprint";
|
||||||
|
@ -56,7 +61,7 @@ describe("imprint.tsx", () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Tests ImprintField", () => {
|
it("Tests ImprintField", () => {
|
||||||
const { asFragment } = render(<ImprintField field={props.fields[0]} />);
|
const { asFragment } = render(<ImprintField field={props.name} />);
|
||||||
expect(asFragment).toMatchSnapshot();
|
expect(asFragment).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -54,16 +54,11 @@ describe("searchBar.tsx", () => {
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Tests SearchBar rendering with props", () => {
|
it("Tests SearchBar rendering", () => {
|
||||||
const { asFragment } = render(<SearchBar search={props} />);
|
const { asFragment } = render(<SearchBar search={props} />);
|
||||||
expect(asFragment).toMatchSnapshot();
|
expect(asFragment).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Tests SearchBar rendering without props", () => {
|
|
||||||
const { asFragment } = render(<SearchBar />);
|
|
||||||
expect(asFragment).toMatchSnapshot();
|
|
||||||
});
|
|
||||||
|
|
||||||
it("Tests handleQueryWithProvider", () => {
|
it("Tests handleQueryWithProvider", () => {
|
||||||
props.providers?.forEach((provider: ISearchProviderProps) => {
|
props.providers?.forEach((provider: ISearchProviderProps) => {
|
||||||
handleQueryWithProvider(props, provider.prefix + " test");
|
handleQueryWithProvider(props, provider.prefix + " test");
|
||||||
|
|
46
src/test/lib/fetcher.spec.tsx
Normal file
46
src/test/lib/fetcher.spec.tsx
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
import { ok } from "assert";
|
||||||
|
import useFetcher, {
|
||||||
|
defaults,
|
||||||
|
handleResponse,
|
||||||
|
handleError,
|
||||||
|
fetchProduction,
|
||||||
|
fetchDevelopment,
|
||||||
|
} from "../../lib/fetcher";
|
||||||
|
|
||||||
|
describe("fetcher.tsx", () => {
|
||||||
|
it("Tests handleResponse", () => {});
|
||||||
|
|
||||||
|
it("Tests handleError", () => {
|
||||||
|
expect(handleError("apps", Error("Test!"))).toEqual({
|
||||||
|
...defaults.app,
|
||||||
|
error: "Test!",
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(handleError("bookmark", Error("Test!"))).toEqual({
|
||||||
|
...defaults.bookmark,
|
||||||
|
error: "Test!",
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(handleError("searchProvider", Error("Test!"))).toEqual({
|
||||||
|
...defaults.search,
|
||||||
|
error: "Test!",
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(handleError("theme", Error("Test!"))).toEqual({
|
||||||
|
...defaults.theme,
|
||||||
|
error: "Test!",
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(handleError("imprint", Error("Test!"))).toEqual({
|
||||||
|
...defaults.imprint,
|
||||||
|
error: "Test!",
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(handleError("greeter", Error("Test!"))).toEqual({
|
||||||
|
...defaults.greeter,
|
||||||
|
error: "Test!",
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(handleError("", Error("Test!"))).toEqual(undefined);
|
||||||
|
});
|
||||||
|
});
|
|
@ -1,4 +1,4 @@
|
||||||
import { getTheme, IThemeProps, setTheme, setScheme } from "../../lib/useTheme";
|
import { getTheme, IThemeProps, setTheme } from "../../lib/useTheme";
|
||||||
|
|
||||||
const props: IThemeProps = {
|
const props: IThemeProps = {
|
||||||
label: "Classic",
|
label: "Classic",
|
||||||
|
@ -27,15 +27,7 @@ const setup = () => {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
describe("useTheme.tsx", () => {
|
describe("theme.tsx", () => {
|
||||||
it("tests setScheme", () => {
|
|
||||||
setup();
|
|
||||||
|
|
||||||
setScheme("Test");
|
|
||||||
expect(window.localStorage.setItem).toHaveBeenCalledTimes(1);
|
|
||||||
expect(window.localStorage.setItem).toHaveBeenCalledWith("theme", "Test");
|
|
||||||
});
|
|
||||||
|
|
||||||
it("setTheme light test", () => {
|
it("setTheme light test", () => {
|
||||||
setup();
|
setup();
|
||||||
|
|
|
@ -14,8 +14,7 @@
|
||||||
"isolatedModules": true,
|
"isolatedModules": true,
|
||||||
"noEmit": true,
|
"noEmit": true,
|
||||||
"jsx": "react-jsx",
|
"jsx": "react-jsx",
|
||||||
"noFallthroughCasesInSwitch": true,
|
"noFallthroughCasesInSwitch": true
|
||||||
"typeRoots": ["node_modules/@types", "./src/lib/useFetch.d.ts"]
|
|
||||||
},
|
},
|
||||||
"include": ["src", "src/test"]
|
"include": ["src", "src/test"]
|
||||||
}
|
}
|
||||||
|
|
|
@ -6827,11 +6827,6 @@ jsesc@~0.5.0:
|
||||||
resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d"
|
resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d"
|
||||||
integrity sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=
|
integrity sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=
|
||||||
|
|
||||||
json-loader@^0.5.7:
|
|
||||||
version "0.5.7"
|
|
||||||
resolved "https://registry.yarnpkg.com/json-loader/-/json-loader-0.5.7.tgz#dca14a70235ff82f0ac9a3abeb60d337a365185d"
|
|
||||||
integrity sha512-QLPs8Dj7lnf3e3QYS1zkCo+4ZwqOiF9d/nZnYozTISxXWCfNs9yuky5rJw4/W34s7POaNlbZmQGaB5NiXCbP4w==
|
|
||||||
|
|
||||||
json-parse-better-errors@^1.0.1, json-parse-better-errors@^1.0.2:
|
json-parse-better-errors@^1.0.1, json-parse-better-errors@^1.0.2:
|
||||||
version "1.0.2"
|
version "1.0.2"
|
||||||
resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9"
|
resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9"
|
||||||
|
|
Loading…
Reference in a new issue