Ben Phelps пре 2 година
родитељ
комит
17f54da524

+ 3 - 13
src/components/services/item.jsx

@@ -22,12 +22,6 @@ function resolveIcon(icon) {
 }
 }
 
 
 export default function Item({ service }) {
 export default function Item({ service }) {
-  const handleOnClick = () => {
-    if (service.href && service.href !== "#") {
-      window.open(service.href, "_blank").focus();
-    }
-  };
-
   const hasLink = service.href && service.href !== "#";
   const hasLink = service.href && service.href !== "#";
 
 
   return (
   return (
@@ -41,13 +35,9 @@ export default function Item({ service }) {
           <div className="flex select-none">
           <div className="flex select-none">
             {service.icon &&
             {service.icon &&
               (hasLink ? (
               (hasLink ? (
-                <button
-                  type="button"
-                  onClick={handleOnClick}
-                  className="flex-shrink-0 flex items-center justify-center w-12 "
-                >
+                <a type="button" href={service.href} className="flex-shrink-0 flex items-center justify-center w-12 ">
                   <Image src={resolveIcon(service.icon)} width={32} height={32} alt="logo" />
                   <Image src={resolveIcon(service.icon)} width={32} height={32} alt="logo" />
-                </button>
+                </a>
               ) : (
               ) : (
                 <div className="flex-shrink-0 flex items-center justify-center w-12 ">
                 <div className="flex-shrink-0 flex items-center justify-center w-12 ">
                   <Image src={resolveIcon(service.icon)} width={32} height={32} alt="logo" />
                   <Image src={resolveIcon(service.icon)} width={32} height={32} alt="logo" />
@@ -57,7 +47,7 @@ export default function Item({ service }) {
             {hasLink ? (
             {hasLink ? (
               <button
               <button
                 type="button"
                 type="button"
-                onClick={handleOnClick}
+                href={service.href}
                 className="flex-1 flex items-center justify-between rounded-r-md "
                 className="flex-1 flex items-center justify-between rounded-r-md "
               >
               >
                 <div className="flex-1 px-2 py-2 text-sm text-left">
                 <div className="flex-1 px-2 py-2 text-sm text-left">

+ 9 - 0
src/pages/api/validate.js

@@ -0,0 +1,9 @@
+import checkAndCopyConfig from "utils/config";
+
+const configs = ["docker.yaml", "settings.yaml", "services.yaml", "bookmarks.yaml"];
+
+export default async function handler(req, res) {
+  const errors = configs.map((config) => checkAndCopyConfig(config)).filter((status) => status !== true);
+
+  res.send(errors);
+}

+ 1 - 1
src/pages/api/widgets/openweathermap.js

@@ -14,7 +14,7 @@ export default async function handler(req, res) {
   }
   }
 
 
   if (!apiKey && provider) {
   if (!apiKey && provider) {
-    const settings = await getSettings();
+    const settings = getSettings();
     apiKey = settings?.providers?.openweathermap;
     apiKey = settings?.providers?.openweathermap;
   }
   }
 
 

+ 1 - 1
src/pages/api/widgets/weather.js

@@ -14,7 +14,7 @@ export default async function handler(req, res) {
   }
   }
 
 
   if (!apiKey && provider) {
   if (!apiKey && provider) {
-    const settings = await getSettings();
+    const settings = getSettings();
     apiKey = settings?.providers?.weatherapi;
     apiKey = settings?.providers?.weatherapi;
   }
   }
 
 

+ 46 - 8
src/pages/index.jsx

@@ -4,6 +4,7 @@ import Head from "next/head";
 import dynamic from "next/dynamic";
 import dynamic from "next/dynamic";
 import { useTranslation } from "react-i18next";
 import { useTranslation } from "react-i18next";
 import { useEffect, useContext } from "react";
 import { useEffect, useContext } from "react";
+import { BiError } from "react-icons/bi";
 
 
 import ServicesGroup from "components/services/group";
 import ServicesGroup from "components/services/group";
 import BookmarksGroup from "components/bookmarks/group";
 import BookmarksGroup from "components/bookmarks/group";
@@ -23,17 +24,54 @@ const ColorToggle = dynamic(() => import("components/color-toggle"), {
 
 
 const rightAlignedWidgets = ["weatherapi", "openweathermap", "weather", "search", "datetime"];
 const rightAlignedWidgets = ["weatherapi", "openweathermap", "weather", "search", "datetime"];
 
 
-export async function getStaticProps() {
-  const settings = await getSettings();
+export function getStaticProps() {
+  try {
+    const settings = getSettings();
+    return {
+      props: {
+        settings,
+      },
+    };
+  } catch (e) {
+    return {
+      props: {
+        settings: {},
+      },
+    };
+  }
+}
+
+export default function Index({ settings }) {
+  const { data: errorsData } = useSWR("/api/validate");
+
+  if (errorsData && errorsData.length > 0) {
+    return (
+      <div className="w-full container m-auto justify-center p-10">
+        <div className="flex flex-col">
+          {errorsData.map((error, i) => (
+            <div
+              className="basis-1/2 bg-theme-500 dark:bg-theme-600 text-theme-600 dark:text-theme-300 m-2 rounded-md font-mono shadow-md border-4 border-transparent"
+              key={i}
+            >
+              <div className="bg-amber-200 text-amber-800 dark:text-amber-200 dark:bg-amber-800 p-2 rounded-md font-bold">
+                <BiError className="float-right w-6 h-6" />
+                {error.config}
+              </div>
+              <div className="p-2 text-theme-100 dark:text-theme-200">
+                <pre className="opacity-50 font-bold pb-2">{error.reason}</pre>
+                <pre className="text-sm">{error.mark.snippet}</pre>
+              </div>
+            </div>
+          ))}
+        </div>
+      </div>
+    );
+  }
 
 
-  return {
-    props: {
-      settings,
-    },
-  };
+  return <Home settings={settings} />;
 }
 }
 
 
-export default function Home({ settings }) {
+function Home({ settings }) {
   const { i18n } = useTranslation();
   const { i18n } = useTranslation();
   const { theme, setTheme } = useContext(ThemeContext);
   const { theme, setTheme } = useContext(ThemeContext);
   const { color, setColor } = useContext(ColorContext);
   const { color, setColor } = useContext(ColorContext);

+ 1 - 0
src/skeleton/bookmarks.yaml

@@ -1,3 +1,4 @@
+---
 # For configuration options and examples, please see:
 # For configuration options and examples, please see:
 # https://github.com/benphelps/homepage/wiki/Bookmarks
 # https://github.com/benphelps/homepage/wiki/Bookmarks
 
 

+ 6 - 5
src/skeleton/docker.yaml

@@ -1,9 +1,10 @@
+---
 # For configuration options and examples, please see:
 # For configuration options and examples, please see:
 # https://github.com/benphelps/homepage/wiki/Docker-Integration
 # https://github.com/benphelps/homepage/wiki/Docker-Integration
 
 
-my-docker:
-  host: 127.0.0.1
-  port: 2375
+# my-docker:
+#   host: 127.0.0.1
+#   port: 2375
 
 
-other-docker:
-  socket: /var/run/docker.sock
+# my-docker:
+#   socket: /var/run/docker.sock

+ 1 - 0
src/skeleton/services.yaml

@@ -1,3 +1,4 @@
+---
 # For configuration options and examples, please see:
 # For configuration options and examples, please see:
 # https://github.com/benphelps/homepage/wiki/Services
 # https://github.com/benphelps/homepage/wiki/Services
 
 

+ 1 - 0
src/skeleton/settings.yaml

@@ -1,3 +1,4 @@
+---
 # For configuration options and examples, please see:
 # For configuration options and examples, please see:
 # https://github.com/benphelps/homepage/wiki/Settings
 # https://github.com/benphelps/homepage/wiki/Settings
 
 

+ 1 - 0
src/skeleton/widgets.yaml

@@ -1,3 +1,4 @@
+---
 # For configuration options and examples, please see:
 # For configuration options and examples, please see:
 # https://github.com/benphelps/homepage/wiki/Information-Widgets
 # https://github.com/benphelps/homepage/wiki/Information-Widgets
 
 

+ 12 - 3
src/utils/config.js

@@ -1,6 +1,6 @@
 /* eslint-disable no-console */
 /* eslint-disable no-console */
 import { join } from "path";
 import { join } from "path";
-import { existsSync, copyFile, promises as fs } from "fs";
+import { existsSync, copyFile, readFileSync } from "fs";
 
 
 import yaml from "js-yaml";
 import yaml from "js-yaml";
 
 
@@ -15,13 +15,22 @@ export default function checkAndCopyConfig(config) {
       }
       }
       console.info("%s was copied to the config folder", config);
       console.info("%s was copied to the config folder", config);
     });
     });
+
+    return true;
+  }
+
+  try {
+    yaml.load(readFileSync(configYaml, "utf8"));
+    return true;
+  } catch (e) {
+    return { ...e, config };
   }
   }
 }
 }
 
 
-export async function getSettings() {
+export function getSettings() {
   checkAndCopyConfig("settings.yaml");
   checkAndCopyConfig("settings.yaml");
 
 
   const settingsYaml = join(process.cwd(), "config", "settings.yaml");
   const settingsYaml = join(process.cwd(), "config", "settings.yaml");
-  const fileContents = await fs.readFile(settingsYaml, "utf8");
+  const fileContents = readFileSync(settingsYaml, "utf8");
   return yaml.load(fileContents);
   return yaml.load(fileContents);
 }
 }