소스 검색

add options for layout, theme and color settings

Ben Phelps 2 년 전
부모
커밋
93d5dd88ba
5개의 변경된 파일94개의 추가작업 그리고 57개의 파일을 삭제
  1. 1 0
      src/components/color-toggle.jsx
  2. 9 6
      src/components/services/group.jsx
  3. 21 2
      src/components/services/list.jsx
  4. 7 1
      src/pages/_app.jsx
  5. 56 48
      src/pages/index.jsx

+ 1 - 0
src/components/color-toggle.jsx

@@ -61,6 +61,7 @@ export default function ColorToggle() {
                 {colors.map((color) => (
                   <button type="button" onClick={() => setColor(color)} key={color}>
                     <div
+                      title={color}
                       className={classNames(
                         active === color ? "border-2" : "border-0",
                         `rounded-md w-5 h-5 border-black/50 dark:border-white/50 theme-${color} bg-theme-400`

+ 9 - 6
src/components/services/group.jsx

@@ -1,15 +1,18 @@
+import classNames from "classnames";
+
 import List from "components/services/list";
 
-export default function ServicesGroup({ services }) {
+export default function ServicesGroup({ services, layout }) {
   return (
     <div
       key={services.name}
-      className="basis-full md:basis-1/2 lg:basis-1/3 xl:basis-1/4 flex-1 p-1"
+      className={classNames(
+        layout?.style === "row" ? "basis-full" : "basis-full md:basis-1/2 lg:basis-1/3 xl:basis-1/4",
+        "flex-1 p-1"
+      )}
     >
-      <h2 className="text-theme-800 dark:text-theme-300 text-xl font-medium">
-        {services.name}
-      </h2>
-      <List services={services.services} />
+      <h2 className="text-theme-800 dark:text-theme-300 text-xl font-medium">{services.name}</h2>
+      <List services={services.services} layout={layout} />
     </div>
   );
 }

+ 21 - 2
src/components/services/list.jsx

@@ -1,8 +1,27 @@
+import classNames from "classnames";
+
 import Item from "components/services/item";
 
-export default function List({ services }) {
+const columnMap = [
+  "grid-cols-1 md:grid-cols-1 lg:grid-cols-1",
+  "grid-cols-1 md:grid-cols-1 lg:grid-cols-1",
+  "grid-cols-1 md:grid-cols-2 lg:grid-cols-2",
+  "grid-cols-1 md:grid-cols-2 lg:grid-cols-3",
+  "grid-cols-1 md:grid-cols-2 lg:grid-cols-4",
+  "grid-cols-1 md:grid-cols-2 lg:grid-cols-5",
+  "grid-cols-1 md:grid-cols-2 lg:grid-cols-6",
+  "grid-cols-1 md:grid-cols-2 lg:grid-cols-7",
+  "grid-cols-1 md:grid-cols-2 lg:grid-cols-8",
+];
+
+export default function List({ services, layout }) {
   return (
-    <ul className="mt-3 flex flex-col">
+    <ul
+      className={classNames(
+        layout?.style === "row" ? `grid ${columnMap[layout?.columns]} gap-x-2` : "flex flex-col",
+        "mt-3"
+      )}
+    >
       {services.map((service) => (
         <Item key={service.name} service={service} />
       ))}

+ 7 - 1
src/pages/_app.jsx

@@ -6,6 +6,8 @@ import "styles/weather-icons.css";
 import "styles/theme.css";
 
 import "utils/i18n";
+import { ColorProvider } from "utils/color-context";
+import { ThemeProvider } from "utils/theme-context";
 
 function MyApp({ Component, pageProps }) {
   return (
@@ -14,7 +16,11 @@ function MyApp({ Component, pageProps }) {
         fetcher: (resource, init) => fetch(resource, init).then((res) => res.json()),
       }}
     >
-      <Component {...pageProps} />
+      <ColorProvider>
+        <ThemeProvider>
+          <Component {...pageProps} />
+        </ThemeProvider>
+      </ColorProvider>
     </SWRConfig>
   );
 }

+ 56 - 48
src/pages/index.jsx

@@ -3,15 +3,15 @@ import useSWR from "swr";
 import Head from "next/head";
 import dynamic from "next/dynamic";
 import { useTranslation } from "react-i18next";
-import { useEffect } from "react";
+import { useEffect, useContext } from "react";
 
 import ServicesGroup from "components/services/group";
 import BookmarksGroup from "components/bookmarks/group";
 import Widget from "components/widget";
 import Revalidate from "components/revalidate";
 import { getSettings } from "utils/config";
-import { ColorProvider } from "utils/color-context";
-import { ThemeProvider } from "utils/theme-context";
+import { ColorContext } from "utils/color-context";
+import { ThemeContext } from "utils/theme-context";
 
 const ThemeToggle = dynamic(() => import("components/theme-toggle"), {
   ssr: false,
@@ -35,6 +35,8 @@ export async function getStaticProps() {
 
 export default function Home({ settings }) {
   const { i18n } = useTranslation();
+  const { theme, setTheme } = useContext(ThemeContext);
+  const { color, setColor } = useContext(ColorContext);
 
   const { data: services } = useSWR("/api/services");
   const { data: bookmarks } = useSWR("/api/bookmarks");
@@ -50,61 +52,67 @@ export default function Home({ settings }) {
     if (settings.language) {
       i18n.changeLanguage(settings.language);
     }
-  }, [i18n, settings.language]);
+
+    if (settings.theme && theme !== settings.theme) {
+      setTheme(settings.theme);
+    }
+
+    if (settings.color && color !== settings.color) {
+      setColor(settings.color);
+    }
+  }, [i18n, settings, color, setColor, theme, setTheme]);
 
   return (
-    <ColorProvider>
-      <ThemeProvider>
-        <Head>
-          <title>{settings.title || "Homepage"}</title>
-          {settings.base && <base href={settings.base} />}
-          {settings.favicon && <link rel="icon" href={settings.favicon} />}
-        </Head>
-        <div className="fixed w-full h-full m-0 p-0" style={wrappedStyle} />
-        <div className="relative w-full container m-auto flex flex-col h-screen justify-between">
-          <div className="flex flex-row flex-wrap m-8 pb-4 mt-10 border-b-2 border-theme-800 dark:border-theme-200 justify-between">
-            {widgets && (
-              <>
+    <>
+      <Head>
+        <title>{settings.title || "Homepage"}</title>
+        {settings.base && <base href={settings.base} />}
+        {settings.favicon && <link rel="icon" href={settings.favicon} />}
+      </Head>
+      <div className="fixed w-full h-full m-0 p-0" style={wrappedStyle} />
+      <div className="relative w-full container m-auto flex flex-col h-screen justify-between">
+        <div className="flex flex-row flex-wrap m-8 pb-4 mt-10 border-b-2 border-theme-800 dark:border-theme-200 justify-between">
+          {widgets && (
+            <>
+              {widgets
+                .filter((widget) => !rightAlignedWidgets.includes(widget.type))
+                .map((widget, i) => (
+                  <Widget key={i} widget={widget} />
+                ))}
+
+              <div className="ml-4 flex flex-wrap basis-full grow sm:basis-auto justify-between md:justify-end mt-2 md:mt-0">
                 {widgets
-                  .filter((widget) => !rightAlignedWidgets.includes(widget.type))
+                  .filter((widget) => rightAlignedWidgets.includes(widget.type))
                   .map((widget, i) => (
                     <Widget key={i} widget={widget} />
                   ))}
-
-                <div className="ml-4 flex flex-wrap basis-full grow sm:basis-auto justify-between md:justify-end mt-2 md:mt-0">
-                  {widgets
-                    .filter((widget) => rightAlignedWidgets.includes(widget.type))
-                    .map((widget, i) => (
-                      <Widget key={i} widget={widget} />
-                    ))}
-                </div>
-              </>
-            )}
-          </div>
-
-          {services && (
-            <div className="flex flex-wrap p-8 items-start">
-              {services.map((group) => (
-                <ServicesGroup key={group.name} services={group} />
-              ))}
-            </div>
+              </div>
+            </>
           )}
+        </div>
 
-          {bookmarks && (
-            <div className="grow flex flex-wrap pt-0 p-8">
-              {bookmarks.map((group) => (
-                <BookmarksGroup key={group.name} group={group} />
-              ))}
-            </div>
-          )}
+        {services && (
+          <div className="flex flex-wrap p-8 items-start">
+            {services.map((group) => (
+              <ServicesGroup key={group.name} services={group} layout={settings.layout?.[group.name]} />
+            ))}
+          </div>
+        )}
 
-          <div className="rounded-full flex p-8 w-full justify-between">
-            <ColorToggle />
-            <Revalidate />
-            <ThemeToggle />
+        {bookmarks && (
+          <div className="grow flex flex-wrap pt-0 p-8">
+            {bookmarks.map((group) => (
+              <BookmarksGroup key={group.name} group={group} />
+            ))}
           </div>
+        )}
+
+        <div className="rounded-full flex p-8 w-full justify-end">
+          {!settings?.color && <ColorToggle />}
+          <Revalidate />
+          {!settings?.theme && <ThemeToggle />}
         </div>
-      </ThemeProvider>
-    </ColorProvider>
+      </div>
+    </>
   );
 }