diff --git a/data/greeter.json b/data/greeter.json
new file mode 100644
index 0000000..487bd37
--- /dev/null
+++ b/data/greeter.json
@@ -0,0 +1,50 @@
+{
+ "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"
+ }
+}
diff --git a/package.json b/package.json
index f72d980..d230260 100644
--- a/package.json
+++ b/package.json
@@ -30,5 +30,17 @@
},
"eslintConfig": {
"extends": "react-app"
+ },
+ "browserslist": {
+ "production": [
+ ">0.2%",
+ "not dead",
+ "not op_mini all"
+ ],
+ "development": [
+ "last 1 chrome version",
+ "last 1 firefox version",
+ "last 1 safari version"
+ ]
}
}
diff --git a/src/app.tsx b/src/app.tsx
index 96c9ec8..0245f9e 100644
--- a/src/app.tsx
+++ b/src/app.tsx
@@ -1,4 +1,3 @@
-import React from "react";
import { createGlobalStyle } from "styled-components";
import SearchBar from "./components/searchBar";
@@ -31,7 +30,7 @@ const GlobalStyle = createGlobalStyle`
*/
const App = () => {
- const { appData, bookmarkData, searchProviderData, themeData, imprintData } = useFetcher();
+ const { appData, bookmarkData, searchProviderData, themeData, imprintData, greeterData } = useFetcher();
return (
<>
@@ -44,8 +43,7 @@ const App = () => {
providers={searchProviderData?.providers}
/>
)}
-
-
+
{!appData.error && (
)}
diff --git a/src/components/app.tsx b/src/components/app.tsx
index 8987287..aabd910 100644
--- a/src/components/app.tsx
+++ b/src/components/app.tsx
@@ -1,4 +1,4 @@
-import React from "react";
+import React, { useEffect } from "react";
import Icon from "./icon";
import styled from "styled-components";
import selectedTheme from "../lib/theme";
@@ -48,20 +48,31 @@ export interface IAppProps {
icon: string;
url: string;
displayURL: string;
+ newTab?: boolean;
}
/**
* Renders a single app shortcut
* @param {IAppProps} props - The props of the given app
*/
-export const App = ({ name, icon, url, displayURL }: IAppProps) => (
-
-
-
-
-
- {name}
- {displayURL}
-
-
-);
+export const App = ({ name, icon, url, displayURL, newTab }: IAppProps) => {
+
+ useEffect(() => { console.log(newTab) }, [newTab])
+
+ return (
+
+
+
+
+
+
+ {
+ (newTab !== undefined && newTab) ?
+ {name} : {name}
+ }
+
+ {displayURL}
+
+
+ );
+}
diff --git a/src/components/appCategory.tsx b/src/components/appCategory.tsx
index c13aacd..83d0fc3 100644
--- a/src/components/appCategory.tsx
+++ b/src/components/appCategory.tsx
@@ -31,6 +31,7 @@ export const AppCategory = ({ name, items }: IAppCategoryProps) => (
icon={app.icon}
url={app.url}
displayURL={app.displayURL}
+ newTab={app.newTab}
/>
))}
diff --git a/src/components/appList.tsx b/src/components/appList.tsx
index b09529c..3781438 100644
--- a/src/components/appList.tsx
+++ b/src/components/appList.tsx
@@ -1,4 +1,3 @@
-import React from "react";
import { AppCategory, IAppCategoryProps } from "./appCategory";
import { IAppProps } from "./app";
diff --git a/src/components/greeter.tsx b/src/components/greeter.tsx
index 14bb96a..b91185d 100644
--- a/src/components/greeter.tsx
+++ b/src/components/greeter.tsx
@@ -1,6 +1,4 @@
-import React from "react";
import styled from "styled-components";
-
import selectedTheme from "../lib/theme";
const GreeterContainer = styled.div`
@@ -22,48 +20,45 @@ const DateText = styled.h3`
color: ${selectedTheme.accentColor};
`;
-const monthNames = [
- "January",
- "February",
- "March",
- "April",
- "May",
- "June",
- "July",
- "August",
- "September",
- "October",
- "November",
- "December",
-];
+export interface IGreeterProps {
+ months: Array;
+ days: Array;
+ greetings: Array;
+ dateformat: string;
+}
-const weekDayNames = [
- "Sunday",
- "Monday",
- "Tuesday",
- "Wednesday",
- "Thursday",
- "Friday",
- "Saturday",
-];
+interface IGreetingProps {
+ greeting: string;
+ start: number;
+ end: number;
+}
+
+interface IGreeterComponentProps {
+ data: IGreeterProps;
+}
+
+/**
+ *
+ * @param a the number that's supposed to be checked
+ * @param b the minimum
+ * @param c the 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
*/
-const getGreeting = () => {
- switch (Math.floor(new Date().getHours() / 6)) {
- case 0:
- return "Good night!";
- case 1:
- return "Good morning!";
- case 2:
- return "Good afternoon!";
- case 3:
- return "Good evening!";
- default:
- break;
- }
+const getGreeting = (greetings: Array): string => {
+
+ let hours = Math.floor(new Date().getHours())
+ let result = "";
+
+ greetings.forEach(greeting => {
+ if (isBetween(hours, greeting.start, greeting.end)) result = greeting.greeting;
+ })
+
+ return result;
};
/**
@@ -89,30 +84,28 @@ 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
*/
-const getDateString = () => {
+const getDateString = (weekdays: Array, months: Array, format: string) => {
let currentDate = new Date();
- return (
- weekDayNames[currentDate.getUTCDay()] +
- ", " +
- monthNames[currentDate.getUTCMonth()] +
- " " +
- currentDate.getDate() +
- getExtension(currentDate.getDate()) +
- " " +
- currentDate.getFullYear()
- );
+ let weekday = weekdays[currentDate.getUTCDay()];
+ let day = currentDate.getDate();
+ let month = months[currentDate.getUTCMonth()];
+ let extension = getExtension(day);
+ let year = currentDate.getFullYear();
+
+ return format.replace("%wd", weekday).replace("%d", day.toString()).replace("%e", extension).replace("%m", month).replace("%y", year.toString());
};
/**
* Renders the Greeter
*/
-const Greeter = () => (
+const Greeter = ({ data }: IGreeterComponentProps) => (
- {getDateString()}
- {getGreeting()}
+ {getDateString(data.days, data.months, data.dateformat)}
+ {getGreeting(data.greetings)}
);
diff --git a/src/components/settings.tsx b/src/components/settings.tsx
index a765697..3e69737 100644
--- a/src/components/settings.tsx
+++ b/src/components/settings.tsx
@@ -1,7 +1,7 @@
import React, { useState } from "react";
import styled from "styled-components";
-import Select, { Styles, ValueType } from "react-select";
+import Select, { ValueType } from "react-select";
import { ISearchProviderProps } from "./searchBar";
import selectedTheme, { setTheme, IThemeProps } from "../lib/theme";
@@ -9,17 +9,6 @@ import { Button, SubHeadline } from "./elements";
import Modal from "./modal";
-interface IHoverProps {
- color?: string;
- backgroundColor?: string;
- border?: string;
- borderColor?: string;
-}
-
-interface IPseudoProps extends React.CSSProperties {
- "&:hover": IHoverProps
-}
-
const FormContainer = styled.div`
display: grid;
grid-template-columns: auto auto auto;
@@ -55,22 +44,12 @@ const SectionHeadline = styled(SubHeadline)`
margin-bottom: 0.5rem;
`;
-const SelectorStyle: Partial> = {
- indicatorSeparator: () => ({
- display: "none",
- }),
- container: (base: React.CSSProperties): React.CSSProperties => ({
+const SelectorStyle: any = {
+ container: (base: any): any => ({
...base,
margin: "0 2px",
}),
- dropdownIndicator: (base: React.CSSProperties): IPseudoProps => ({
- ...base,
- color: selectedTheme.mainColor,
- "&:hover": {
- color: selectedTheme.mainColor
- }
- }),
- control: (base: React.CSSProperties): IPseudoProps => ({
+ control: (base: any): any => ({
...base,
fontWeight: 500,
color: selectedTheme.mainColor,
@@ -86,7 +65,17 @@ const SelectorStyle: Partial> = {
borderColor: selectedTheme.mainColor
},
}),
- menu: (base: React.CSSProperties): React.CSSProperties => ({
+ dropdownIndicator: (base: any): any => ({
+ ...base,
+ color: selectedTheme.mainColor,
+ "&:hover": {
+ color: selectedTheme.mainColor
+ }
+ }),
+ indicatorSeparator: () => ({
+ display: "none",
+ }),
+ menu: (base: any): any => ({
...base,
backgroundColor: selectedTheme.backgroundColor,
border: "1px solid " + selectedTheme.mainColor,
@@ -94,7 +83,7 @@ const SelectorStyle: Partial> = {
boxShadow: "none",
margin: "4px 0"
}),
- option: (base: React.CSSProperties): IPseudoProps => ({
+ option: (base: any): any => ({
...base,
fontWeight: 500,
color: selectedTheme.mainColor,
@@ -107,7 +96,7 @@ const SelectorStyle: Partial> = {
color: selectedTheme.backgroundColor,
},
}),
- singleValue: (base: React.CSSProperties): React.CSSProperties => ({
+ singleValue: (base: any): any => ({
...base,
color: selectedTheme.mainColor,
}),
diff --git a/src/data/greeter.json b/src/data/greeter.json
new file mode 100644
index 0000000..487bd37
--- /dev/null
+++ b/src/data/greeter.json
@@ -0,0 +1,50 @@
+{
+ "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"
+ }
+}
diff --git a/src/lib/fetcher.tsx b/src/lib/fetcher.tsx
index 54a362b..2aa6aaa 100644
--- a/src/lib/fetcher.tsx
+++ b/src/lib/fetcher.tsx
@@ -6,6 +6,7 @@ import { IAppCategoryProps } from "../components/appCategory";
import { IAppProps } from "../components/app";
import { IThemeProps } from "./theme";
import { IImprintProps } from "../components/imprint";
+import { IGreeterProps } from "../components/greeter";
const errorMessage = "Failed to load data.";
const inProduction = process.env.NODE_ENV === "production";
@@ -47,6 +48,11 @@ export interface IImprintDataProps {
error: string | boolean;
}
+export interface IGreeterDataProps {
+ greeter: IGreeterProps;
+ error: string | boolean;
+}
+
/**
* Default values for the respective state variables
*/
@@ -79,6 +85,57 @@ const defaults = {
},
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,
+ }
};
/**
@@ -98,6 +155,8 @@ const handleError = (status: string, error: Error) => {
return { ...defaults.theme, error: error.message }
case "imprint":
return { ...defaults.imprint, error: error.message }
+ case "greeter":
+ return { ...defaults.greeter, error: error.message }
default:
break;
}
@@ -112,6 +171,7 @@ const fetchProduction = Promise.all([
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))
]);
/**
@@ -123,6 +183,7 @@ const fetchDevelopment = Promise.all([
import("../data/search.json"),
import("../data/themes.json"),
import("../data/imprint.json"),
+ import("../data/greeter.json")
]);
/**
@@ -146,14 +207,17 @@ export const useFetcher = () => {
defaults.imprint
);
+ const [greeterData, setGreeterData] = useState(defaults.greeter);
+
const callback = useCallback(() => {
(inProduction ? fetchProduction : fetchDevelopment).then(
- ([appData, bookmarkData, searchData, themeData, imprintData]: [IAppDataProps, IBookmarkDataProps, ISearchProviderDataProps, IThemeDataProps, IImprintDataProps]) => {
- (appData.error) ? setAppData(appData) : setAppData({ ...appData, error: false });
- (bookmarkData.error) ? setBookmarkData(bookmarkData) : setBookmarkData({ ...bookmarkData, error: false });
- (searchData.error) ? setSearchProviderData(searchData) : setSearchProviderData({ ...searchData, error: false });
- (themeData.error) ? setThemeData(themeData) : setThemeData({ ...themeData, error: false });
- (imprintData.error) ? setImprintData(imprintData) : setImprintData({ ...imprintData, error: false });
+ ([appData, bookmarkData, searchData, themeData, imprintData, greeterData]: [IAppDataProps, IBookmarkDataProps, ISearchProviderDataProps, 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 });
}
);
}, []);
@@ -166,6 +230,7 @@ export const useFetcher = () => {
searchProviderData,
themeData,
imprintData,
+ greeterData,
callback
};
};
diff --git a/tsconfig.json b/tsconfig.json
index fbce9be..e18c413 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -17,7 +17,7 @@
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
- "jsx": "react",
+ "jsx": "react-jsx",
"noFallthroughCasesInSwitch": true
},
"include": [