mirror of
				https://github.com/gethomepage/homepage.git
				synced 2025-11-04 03:27:02 -05:00 
			
		
		
		
	background images, document title
This commit is contained in:
		
							parent
							
								
									0b43f83daa
								
							
						
					
					
						commit
						0c8bbdf02b
					
				@ -6,10 +6,10 @@ export default function Item({ bookmark }) {
 | 
			
		||||
      <button
 | 
			
		||||
        type="button"
 | 
			
		||||
        onClick={() => window.open(bookmark.href, "_blank").focus()}
 | 
			
		||||
        className="w-full text-left mb-3 cursor-pointer rounded-md font-medium text-theme-700 hover:text-theme-800 dark:text-theme-200 dark:hover:text-theme-300 shadow-md shadow-theme-900/10 dark:shadow-theme-900/50 bg-white/50 hover:bg-theme-300/10 dark:bg-white/5 dark:hover:bg-white/10"
 | 
			
		||||
        className="w-full text-left mb-3 cursor-pointer rounded-md font-medium text-theme-700 hover:text-theme-700 dark:text-theme-200 dark:hover:text-theme-300 shadow-md shadow-black/10 dark:shadow-black/20 bg-white/50 hover:bg-theme-300/10 dark:bg-white/10 dark:hover:bg-white/20"
 | 
			
		||||
      >
 | 
			
		||||
        <div className="flex">
 | 
			
		||||
          <div className="flex-shrink-0 flex items-center justify-center w-11 bg-theme-500/10 dark:bg-theme-900/50 text-theme-700 dark:text-theme-200 text-sm font-medium rounded-l-md">
 | 
			
		||||
          <div className="flex-shrink-0 flex items-center justify-center w-11 bg-theme-500/10 dark:bg-theme-900/50 text-theme-700 hover:text-theme-700 dark:text-theme-200 text-sm font-medium rounded-l-md">
 | 
			
		||||
            {bookmark.abbr}
 | 
			
		||||
          </div>
 | 
			
		||||
          <div className="flex-1 flex items-center justify-between rounded-r-md ">
 | 
			
		||||
 | 
			
		||||
@ -27,6 +27,7 @@ const colors = [
 | 
			
		||||
  "pink",
 | 
			
		||||
  "rose",
 | 
			
		||||
  "red",
 | 
			
		||||
  "white",
 | 
			
		||||
];
 | 
			
		||||
 | 
			
		||||
export default function ColorToggle() {
 | 
			
		||||
@ -56,13 +57,13 @@ export default function ColorToggle() {
 | 
			
		||||
        >
 | 
			
		||||
          <Popover.Panel className="absolute -top-[75px] left-0">
 | 
			
		||||
            <div className="rounded-md shadow-lg ring-1 ring-black ring-opacity-5">
 | 
			
		||||
              <div className="relative grid gap-2 p-2 grid-cols-11 shadow-theme-900/10 dark:shadow-theme-900 rounded-md shadow-md">
 | 
			
		||||
              <div className="relative grid gap-2 p-2 grid-cols-11 bg-white/50 dark:bg-white/10 shadow-black/10 dark:shadow-black/20 rounded-md shadow-md">
 | 
			
		||||
                {colors.map((color) => (
 | 
			
		||||
                  <button type="button" onClick={() => setColor(color)} key={color}>
 | 
			
		||||
                    <div
 | 
			
		||||
                      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-500`
 | 
			
		||||
                        `rounded-md w-5 h-5 border-black/50 dark:border-white/50 theme-${color} bg-theme-400`
 | 
			
		||||
                      )}
 | 
			
		||||
                    />
 | 
			
		||||
                  </button>
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										17
									
								
								src/components/revalidate.jsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								src/components/revalidate.jsx
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,17 @@
 | 
			
		||||
import { MdRefresh } from "react-icons/md";
 | 
			
		||||
 | 
			
		||||
export default function Revalidate() {
 | 
			
		||||
  const revalidate = () => {
 | 
			
		||||
    fetch("/api/revalidate").then((res) => {
 | 
			
		||||
      if (res.ok) {
 | 
			
		||||
        window.location.reload();
 | 
			
		||||
      }
 | 
			
		||||
    });
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  return (
 | 
			
		||||
    <div className="rounded-full flex align-middle self-center mr-3">
 | 
			
		||||
      <MdRefresh onClick={() => revalidate()} className="text-theme-800 dark:text-theme-200 w-6 h-6 cursor-pointer" />
 | 
			
		||||
    </div>
 | 
			
		||||
  );
 | 
			
		||||
}
 | 
			
		||||
@ -28,7 +28,7 @@ export default function Item({ service }) {
 | 
			
		||||
        <div
 | 
			
		||||
          className={`${
 | 
			
		||||
            service.href && service.href !== "#" ? "cursor-pointer " : "cursor-default "
 | 
			
		||||
          }transition-all h-15 overflow-hidden mb-3 p-1 rounded-md font-medium text-theme-700 hover:text-theme-800 dark:text-theme-200 dark:hover:text-theme-300 shadow-md shadow-theme-900/10 dark:shadow-theme-900/40 bg-white/50 hover:bg-theme-300/10 dark:bg-white/5 dark:hover:bg-white/10`}
 | 
			
		||||
          }transition-all h-15 overflow-hidden mb-3 p-1 rounded-md font-medium text-theme-700 hover:text-theme-700/70 dark:text-theme-200 dark:hover:text-theme-300 shadow-md shadow-black/10 dark:shadow-black/20 bg-white/50 hover:bg-theme-300/20 dark:bg-white/10 dark:hover:bg-white/20`}
 | 
			
		||||
        >
 | 
			
		||||
          <div className="flex">
 | 
			
		||||
            {service.icon && (
 | 
			
		||||
 | 
			
		||||
@ -1,10 +1,5 @@
 | 
			
		||||
import { useContext } from "react";
 | 
			
		||||
import {
 | 
			
		||||
  MdDarkMode,
 | 
			
		||||
  MdLightMode,
 | 
			
		||||
  MdToggleOff,
 | 
			
		||||
  MdToggleOn,
 | 
			
		||||
} from "react-icons/md";
 | 
			
		||||
import { MdDarkMode, MdLightMode, MdToggleOff, MdToggleOn } from "react-icons/md";
 | 
			
		||||
 | 
			
		||||
import { ThemeContext } from "utils/theme-context";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -2,6 +2,7 @@ import useSWR from "swr";
 | 
			
		||||
import { FiCpu } from "react-icons/fi";
 | 
			
		||||
import { BiError } from "react-icons/bi";
 | 
			
		||||
import { useTranslation } from "react-i18next";
 | 
			
		||||
import UsageBar from "./usage-bar";
 | 
			
		||||
 | 
			
		||||
export default function Cpu() {
 | 
			
		||||
  const { t } = useTranslation();
 | 
			
		||||
@ -41,14 +42,7 @@ export default function Cpu() {
 | 
			
		||||
        <div className="text-theme-800 dark:text-theme-200 text-xs">
 | 
			
		||||
          {t("common.number", { value: data.cpu.usage, style: "unit", unit: "percent", maximumFractionDigits: 0 })}
 | 
			
		||||
        </div>
 | 
			
		||||
        <div className="w-full bg-gray-200 rounded-full h-1 dark:bg-gray-700">
 | 
			
		||||
          <div
 | 
			
		||||
            className="bg-theme-600 h-1 rounded-full dark:bg-theme-500"
 | 
			
		||||
            style={{
 | 
			
		||||
              width: `${percent}%`,
 | 
			
		||||
            }}
 | 
			
		||||
          />
 | 
			
		||||
        </div>
 | 
			
		||||
        <UsageBar percent={percent} />
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
  );
 | 
			
		||||
 | 
			
		||||
@ -2,6 +2,7 @@ import useSWR from "swr";
 | 
			
		||||
import { FiHardDrive } from "react-icons/fi";
 | 
			
		||||
import { BiError } from "react-icons/bi";
 | 
			
		||||
import { useTranslation } from "react-i18next";
 | 
			
		||||
import UsageBar from "./usage-bar";
 | 
			
		||||
 | 
			
		||||
export default function Disk({ options }) {
 | 
			
		||||
  const { t } = useTranslation();
 | 
			
		||||
@ -44,14 +45,7 @@ export default function Disk({ options }) {
 | 
			
		||||
        <span className="text-theme-800 dark:text-theme-200 text-xs hidden group-hover:block">
 | 
			
		||||
          {t("common.bytes", { value: data.drive.totalGb * 1024 * 1024 * 1024 })} {t("resources.total")}
 | 
			
		||||
        </span>
 | 
			
		||||
        <div className="w-full bg-gray-200 rounded-full h-1 dark:bg-gray-700">
 | 
			
		||||
          <div
 | 
			
		||||
            className="bg-theme-600 h-1 rounded-full dark:bg-theme-500"
 | 
			
		||||
            style={{
 | 
			
		||||
              width: `${percent}%`,
 | 
			
		||||
            }}
 | 
			
		||||
          />
 | 
			
		||||
        </div>
 | 
			
		||||
        <UsageBar percent={percent} />
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
  );
 | 
			
		||||
 | 
			
		||||
@ -2,6 +2,7 @@ import useSWR from "swr";
 | 
			
		||||
import { FaMemory } from "react-icons/fa";
 | 
			
		||||
import { BiError } from "react-icons/bi";
 | 
			
		||||
import { useTranslation } from "react-i18next";
 | 
			
		||||
import UsageBar from "./usage-bar";
 | 
			
		||||
 | 
			
		||||
export default function Memory() {
 | 
			
		||||
  const { t } = useTranslation();
 | 
			
		||||
@ -44,14 +45,7 @@ export default function Memory() {
 | 
			
		||||
        <span className="text-theme-800 dark:text-theme-200 text-xs hidden group-hover:block">
 | 
			
		||||
          {t("common.bytes", { value: data.memory.usedMemMb * 1024 * 1024 })} {t("resources.used")}
 | 
			
		||||
        </span>
 | 
			
		||||
        <div className="w-full bg-gray-200 rounded-full h-1 dark:bg-gray-700">
 | 
			
		||||
          <div
 | 
			
		||||
            className="bg-theme-600 h-1 rounded-full dark:bg-theme-500"
 | 
			
		||||
            style={{
 | 
			
		||||
              width: `${percent}%`,
 | 
			
		||||
            }}
 | 
			
		||||
          />
 | 
			
		||||
        </div>
 | 
			
		||||
        <UsageBar percent={percent} />
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
  );
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										12
									
								
								src/components/widgets/resources/usage-bar.jsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								src/components/widgets/resources/usage-bar.jsx
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,12 @@
 | 
			
		||||
export default function UsageBar({ percent }) {
 | 
			
		||||
  return (
 | 
			
		||||
    <div className="mt-0.5 w-full bg-theme-800/30 rounded-full h-1 dark:bg-white/20">
 | 
			
		||||
      <div
 | 
			
		||||
        className="bg-theme-800/70 h-1 rounded-full dark:bg-white/50"
 | 
			
		||||
        style={{
 | 
			
		||||
          width: `${percent}%`,
 | 
			
		||||
        }}
 | 
			
		||||
      />
 | 
			
		||||
    </div>
 | 
			
		||||
  );
 | 
			
		||||
}
 | 
			
		||||
@ -52,19 +52,33 @@ export default function Search({ options }) {
 | 
			
		||||
 | 
			
		||||
  return (
 | 
			
		||||
    <form className="flex-col relative h-8 my-4 min-w-full md:min-w-fit grow" onSubmit={handleSubmit}>
 | 
			
		||||
      <div className="flex absolute inset-y-0 left-0 items-center pl-3 pointer-events-none w-full text-theme-800 dark:text-theme-200" />
 | 
			
		||||
      <div className="flex absolute inset-y-0 left-0 items-center pl-3 pointer-events-none w-full text-theme-800 dark:text-white" />
 | 
			
		||||
      <input
 | 
			
		||||
        type="search"
 | 
			
		||||
        className="overflow-hidden w-full placeholder-theme-900 text-xs text-theme-900 bg-theme-50 rounded-md border border-theme-300 focus:ring-theme-500 focus:border-theme-500 dark:bg-theme-800 dark:border-theme-600 dark:placeholder-theme-400 dark:text-white dark:focus:ring-theme-500 dark:focus:border-theme-500 h-full"
 | 
			
		||||
        type="text"
 | 
			
		||||
        className="
 | 
			
		||||
          overflow-hidden w-full h-full rounded-md
 | 
			
		||||
          text-xs text-theme-900 dark:text-white
 | 
			
		||||
          placeholder-theme-900 dark:placeholder-white/80
 | 
			
		||||
          bg-white/50 dark:bg-white/10
 | 
			
		||||
          focus:ring-theme-500 dark:focus:ring-white/50
 | 
			
		||||
          focus:border-theme-500 dark:focus:border-white/50
 | 
			
		||||
          border border-theme-300 dark:border-theme-200/50"
 | 
			
		||||
        placeholder={t("search.placeholder")}
 | 
			
		||||
        onChange={(s) => setQuery(s.currentTarget.value)}
 | 
			
		||||
        required
 | 
			
		||||
        autoCapitalize="off"
 | 
			
		||||
        autoCorrect="off"
 | 
			
		||||
        autoComplete="off"
 | 
			
		||||
      />
 | 
			
		||||
      <button
 | 
			
		||||
        type="submit"
 | 
			
		||||
        className="text-white absolute right-0.5 bottom-0.5 bg-theme-700 hover:bg-theme-800 border-1 focus:ring-2 focus:ring-theme-300 font-medium rounded-r-md text-sm px-4 py-2 dark:bg-theme-600 dark:hover:bg-theme-700 dark:focus:ring-theme-500"
 | 
			
		||||
        className="
 | 
			
		||||
        absolute right-0.5 bottom-0.5 rounded-r-md px-4 py-2 border-1
 | 
			
		||||
        text-white font-medium text-sm
 | 
			
		||||
        bg-theme-600/40 dark:bg-white/10
 | 
			
		||||
        focus:ring-theme-500 dark:focus:ring-white/50"
 | 
			
		||||
      >
 | 
			
		||||
        <provider.icon className="text-theme-800 dark:text-theme-200 w-3 h-3" />
 | 
			
		||||
        <provider.icon className="text-white w-3 h-3" />
 | 
			
		||||
      </button>
 | 
			
		||||
    </form>
 | 
			
		||||
  );
 | 
			
		||||
 | 
			
		||||
@ -11,7 +11,7 @@ export default function Document() {
 | 
			
		||||
          rel="stylesheet"
 | 
			
		||||
        />
 | 
			
		||||
      </Head>
 | 
			
		||||
      <body className="w-full h-full bg-theme-50 dark:bg-theme-800 transition duration-150 ease-in-out">
 | 
			
		||||
      <body className="relative w-full h-full bg-theme-50 dark:bg-theme-800 transition duration-150 ease-in-out">
 | 
			
		||||
        <Main />
 | 
			
		||||
        <NextScript />
 | 
			
		||||
      </body>
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										8
									
								
								src/pages/api/revalidate.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								src/pages/api/revalidate.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,8 @@
 | 
			
		||||
export default async function handler(req, res) {
 | 
			
		||||
  try {
 | 
			
		||||
    await res.revalidate("/");
 | 
			
		||||
    return res.json({ revalidated: true });
 | 
			
		||||
  } catch (err) {
 | 
			
		||||
    return res.status(500).send("Error revalidating");
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@ -6,6 +6,8 @@ import dynamic from "next/dynamic";
 | 
			
		||||
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";
 | 
			
		||||
 | 
			
		||||
@ -19,18 +21,34 @@ const ColorToggle = dynamic(() => import("components/color-toggle"), {
 | 
			
		||||
 | 
			
		||||
const rightAlignedWidgets = ["weatherapi", "openweathermap", "weather", "search"];
 | 
			
		||||
 | 
			
		||||
export default function Home() {
 | 
			
		||||
export async function getStaticProps() {
 | 
			
		||||
  const settings = await getSettings();
 | 
			
		||||
 | 
			
		||||
  return {
 | 
			
		||||
    props: {
 | 
			
		||||
      settings,
 | 
			
		||||
    },
 | 
			
		||||
  };
 | 
			
		||||
}
 | 
			
		||||
export default function Home({ settings }) {
 | 
			
		||||
  const { data: services } = useSWR("/api/services");
 | 
			
		||||
  const { data: bookmarks } = useSWR("/api/bookmarks");
 | 
			
		||||
  const { data: widgets } = useSWR("/api/widgets");
 | 
			
		||||
 | 
			
		||||
  const wrappedStyle = {};
 | 
			
		||||
  if (settings.background) {
 | 
			
		||||
    wrappedStyle.backgroundImage = `url(${settings.background})`;
 | 
			
		||||
    wrappedStyle.backgroundSize = "cover";
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return (
 | 
			
		||||
    <ColorProvider>
 | 
			
		||||
      <ThemeProvider>
 | 
			
		||||
        <Head>
 | 
			
		||||
          <title>Welcome</title>
 | 
			
		||||
          <title>{settings.title || "Homepage"}</title>
 | 
			
		||||
        </Head>
 | 
			
		||||
        <div className="w-full container m-auto flex flex-col h-screen justify-between">
 | 
			
		||||
        <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 space-x-0 sm:space-x-4 m-8 pb-4 mt-10 border-b-2 border-theme-800 dark:border-theme-200 justify-between md:justify-start">
 | 
			
		||||
            {widgets && (
 | 
			
		||||
              <>
 | 
			
		||||
@ -69,6 +87,7 @@ export default function Home() {
 | 
			
		||||
 | 
			
		||||
          <div className="rounded-full flex p-8 w-full justify-between">
 | 
			
		||||
            <ColorToggle />
 | 
			
		||||
            <Revalidate />
 | 
			
		||||
            <ThemeToggle />
 | 
			
		||||
          </div>
 | 
			
		||||
        </div>
 | 
			
		||||
 | 
			
		||||
@ -1,3 +1,16 @@
 | 
			
		||||
.theme-white {
 | 
			
		||||
  --color-50: 255 255 255;
 | 
			
		||||
  --color-100: 255 255 255;
 | 
			
		||||
  --color-200: 255 255 255;
 | 
			
		||||
  --color-300: 255 255 255;
 | 
			
		||||
  --color-400: 255 255 255;
 | 
			
		||||
  --color-500: 60 60 60;
 | 
			
		||||
  --color-600: 255 255 255;
 | 
			
		||||
  --color-700: 40 40 40;
 | 
			
		||||
  --color-800: 255 255 255;
 | 
			
		||||
  --color-900: 255 255 255;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.theme-slate {
 | 
			
		||||
  --color-50: 248 250 252;
 | 
			
		||||
  --color-100: 241 245 249;
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user