background images, document title
This commit is contained in:
parent
0b43f83daa
commit
0c8bbdf02b
14 changed files with 105 additions and 44 deletions
|
@ -6,10 +6,10 @@ export default function Item({ bookmark }) {
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() => window.open(bookmark.href, "_blank").focus()}
|
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">
|
||||||
<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}
|
{bookmark.abbr}
|
||||||
</div>
|
</div>
|
||||||
<div className="flex-1 flex items-center justify-between rounded-r-md ">
|
<div className="flex-1 flex items-center justify-between rounded-r-md ">
|
||||||
|
|
|
@ -27,6 +27,7 @@ const colors = [
|
||||||
"pink",
|
"pink",
|
||||||
"rose",
|
"rose",
|
||||||
"red",
|
"red",
|
||||||
|
"white",
|
||||||
];
|
];
|
||||||
|
|
||||||
export default function ColorToggle() {
|
export default function ColorToggle() {
|
||||||
|
@ -56,13 +57,13 @@ export default function ColorToggle() {
|
||||||
>
|
>
|
||||||
<Popover.Panel className="absolute -top-[75px] left-0">
|
<Popover.Panel className="absolute -top-[75px] left-0">
|
||||||
<div className="rounded-md shadow-lg ring-1 ring-black ring-opacity-5">
|
<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) => (
|
{colors.map((color) => (
|
||||||
<button type="button" onClick={() => setColor(color)} key={color}>
|
<button type="button" onClick={() => setColor(color)} key={color}>
|
||||||
<div
|
<div
|
||||||
className={classNames(
|
className={classNames(
|
||||||
active === color ? "border-2" : "border-0",
|
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>
|
</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
|
<div
|
||||||
className={`${
|
className={`${
|
||||||
service.href && service.href !== "#" ? "cursor-pointer " : "cursor-default "
|
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">
|
<div className="flex">
|
||||||
{service.icon && (
|
{service.icon && (
|
||||||
|
|
|
@ -1,10 +1,5 @@
|
||||||
import { useContext } from "react";
|
import { useContext } from "react";
|
||||||
import {
|
import { MdDarkMode, MdLightMode, MdToggleOff, MdToggleOn } from "react-icons/md";
|
||||||
MdDarkMode,
|
|
||||||
MdLightMode,
|
|
||||||
MdToggleOff,
|
|
||||||
MdToggleOn,
|
|
||||||
} from "react-icons/md";
|
|
||||||
|
|
||||||
import { ThemeContext } from "utils/theme-context";
|
import { ThemeContext } from "utils/theme-context";
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@ import useSWR from "swr";
|
||||||
import { FiCpu } from "react-icons/fi";
|
import { FiCpu } from "react-icons/fi";
|
||||||
import { BiError } from "react-icons/bi";
|
import { BiError } from "react-icons/bi";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
|
import UsageBar from "./usage-bar";
|
||||||
|
|
||||||
export default function Cpu() {
|
export default function Cpu() {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
@ -41,14 +42,7 @@ export default function Cpu() {
|
||||||
<div className="text-theme-800 dark:text-theme-200 text-xs">
|
<div className="text-theme-800 dark:text-theme-200 text-xs">
|
||||||
{t("common.number", { value: data.cpu.usage, style: "unit", unit: "percent", maximumFractionDigits: 0 })}
|
{t("common.number", { value: data.cpu.usage, style: "unit", unit: "percent", maximumFractionDigits: 0 })}
|
||||||
</div>
|
</div>
|
||||||
<div className="w-full bg-gray-200 rounded-full h-1 dark:bg-gray-700">
|
<UsageBar percent={percent} />
|
||||||
<div
|
|
||||||
className="bg-theme-600 h-1 rounded-full dark:bg-theme-500"
|
|
||||||
style={{
|
|
||||||
width: `${percent}%`,
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
@ -2,6 +2,7 @@ import useSWR from "swr";
|
||||||
import { FiHardDrive } from "react-icons/fi";
|
import { FiHardDrive } from "react-icons/fi";
|
||||||
import { BiError } from "react-icons/bi";
|
import { BiError } from "react-icons/bi";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
|
import UsageBar from "./usage-bar";
|
||||||
|
|
||||||
export default function Disk({ options }) {
|
export default function Disk({ options }) {
|
||||||
const { t } = useTranslation();
|
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">
|
<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")}
|
{t("common.bytes", { value: data.drive.totalGb * 1024 * 1024 * 1024 })} {t("resources.total")}
|
||||||
</span>
|
</span>
|
||||||
<div className="w-full bg-gray-200 rounded-full h-1 dark:bg-gray-700">
|
<UsageBar percent={percent} />
|
||||||
<div
|
|
||||||
className="bg-theme-600 h-1 rounded-full dark:bg-theme-500"
|
|
||||||
style={{
|
|
||||||
width: `${percent}%`,
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
@ -2,6 +2,7 @@ import useSWR from "swr";
|
||||||
import { FaMemory } from "react-icons/fa";
|
import { FaMemory } from "react-icons/fa";
|
||||||
import { BiError } from "react-icons/bi";
|
import { BiError } from "react-icons/bi";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
|
import UsageBar from "./usage-bar";
|
||||||
|
|
||||||
export default function Memory() {
|
export default function Memory() {
|
||||||
const { t } = useTranslation();
|
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">
|
<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")}
|
{t("common.bytes", { value: data.memory.usedMemMb * 1024 * 1024 })} {t("resources.used")}
|
||||||
</span>
|
</span>
|
||||||
<div className="w-full bg-gray-200 rounded-full h-1 dark:bg-gray-700">
|
<UsageBar percent={percent} />
|
||||||
<div
|
|
||||||
className="bg-theme-600 h-1 rounded-full dark:bg-theme-500"
|
|
||||||
style={{
|
|
||||||
width: `${percent}%`,
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</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 (
|
return (
|
||||||
<form className="flex-col relative h-8 my-4 min-w-full md:min-w-fit grow" onSubmit={handleSubmit}>
|
<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
|
<input
|
||||||
type="search"
|
type="text"
|
||||||
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"
|
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")}
|
placeholder={t("search.placeholder")}
|
||||||
onChange={(s) => setQuery(s.currentTarget.value)}
|
onChange={(s) => setQuery(s.currentTarget.value)}
|
||||||
required
|
required
|
||||||
|
autoCapitalize="off"
|
||||||
|
autoCorrect="off"
|
||||||
|
autoComplete="off"
|
||||||
/>
|
/>
|
||||||
<button
|
<button
|
||||||
type="submit"
|
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>
|
</button>
|
||||||
</form>
|
</form>
|
||||||
);
|
);
|
||||||
|
|
|
@ -11,7 +11,7 @@ export default function Document() {
|
||||||
rel="stylesheet"
|
rel="stylesheet"
|
||||||
/>
|
/>
|
||||||
</Head>
|
</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 />
|
<Main />
|
||||||
<NextScript />
|
<NextScript />
|
||||||
</body>
|
</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 ServicesGroup from "components/services/group";
|
||||||
import BookmarksGroup from "components/bookmarks/group";
|
import BookmarksGroup from "components/bookmarks/group";
|
||||||
import Widget from "components/widget";
|
import Widget from "components/widget";
|
||||||
|
import Revalidate from "components/revalidate";
|
||||||
|
import { getSettings } from "utils/config";
|
||||||
import { ColorProvider } from "utils/color-context";
|
import { ColorProvider } from "utils/color-context";
|
||||||
import { ThemeProvider } from "utils/theme-context";
|
import { ThemeProvider } from "utils/theme-context";
|
||||||
|
|
||||||
|
@ -19,18 +21,34 @@ const ColorToggle = dynamic(() => import("components/color-toggle"), {
|
||||||
|
|
||||||
const rightAlignedWidgets = ["weatherapi", "openweathermap", "weather", "search"];
|
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: services } = useSWR("/api/services");
|
||||||
const { data: bookmarks } = useSWR("/api/bookmarks");
|
const { data: bookmarks } = useSWR("/api/bookmarks");
|
||||||
const { data: widgets } = useSWR("/api/widgets");
|
const { data: widgets } = useSWR("/api/widgets");
|
||||||
|
|
||||||
|
const wrappedStyle = {};
|
||||||
|
if (settings.background) {
|
||||||
|
wrappedStyle.backgroundImage = `url(${settings.background})`;
|
||||||
|
wrappedStyle.backgroundSize = "cover";
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ColorProvider>
|
<ColorProvider>
|
||||||
<ThemeProvider>
|
<ThemeProvider>
|
||||||
<Head>
|
<Head>
|
||||||
<title>Welcome</title>
|
<title>{settings.title || "Homepage"}</title>
|
||||||
</Head>
|
</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">
|
<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 && (
|
{widgets && (
|
||||||
<>
|
<>
|
||||||
|
@ -69,6 +87,7 @@ export default function Home() {
|
||||||
|
|
||||||
<div className="rounded-full flex p-8 w-full justify-between">
|
<div className="rounded-full flex p-8 w-full justify-between">
|
||||||
<ColorToggle />
|
<ColorToggle />
|
||||||
|
<Revalidate />
|
||||||
<ThemeToggle />
|
<ThemeToggle />
|
||||||
</div>
|
</div>
|
||||||
</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 {
|
.theme-slate {
|
||||||
--color-50: 248 250 252;
|
--color-50: 248 250 252;
|
||||||
--color-100: 241 245 249;
|
--color-100: 241 245 249;
|
||||||
|
|
Loading…
Add table
Reference in a new issue