feat: add widget preview pages (#9)

* feat: add widget definition system

* fix: wrong typecheck command in turbo generator

* chore: fix formatting

* feat: add widget preview page

* chore: fix formatting and type errors

* chore: fix from widget edit modal and remove some never casts

* chore: address pull request feedback
This commit is contained in:
Meier Lukas
2024-01-02 15:36:59 +01:00
committed by GitHub
parent fa19966fcc
commit 782897527f
48 changed files with 1226 additions and 81 deletions

View File

@@ -0,0 +1,15 @@
import type { PropsWithChildren } from "react";
import { AppShellMain } from "@homarr/ui";
import { MainHeader } from "~/components/layout/header";
import { ClientShell } from "~/components/layout/shell";
export default function MainLayout({ children }: PropsWithChildren) {
return (
<ClientShell hasNavigation={false}>
<MainHeader />
<AppShellMain>{children}</AppShellMain>
</ClientShell>
);
}

View File

@@ -0,0 +1,9 @@
import { Stack, Title } from "@homarr/ui";
export default function HomePage() {
return (
<Stack>
<Title>Home</Title>
</Stack>
);
}

View File

@@ -0,0 +1,9 @@
"use client";
import type { PropsWithChildren } from "react";
import { ModalsManager } from "../modals";
export const ModalsProvider = ({ children }: PropsWithChildren) => {
return <ModalsManager>{children}</ModalsManager>;
};

View File

@@ -10,7 +10,7 @@ export default async function Login() {
return (
<Center>
<Stack align="center" mt="xl">
<LogoWithTitle />
<LogoWithTitle size="lg" />
<Stack gap={6} align="center">
<Title order={3} fw={400} ta="center">
{t("title")}

View File

@@ -23,7 +23,7 @@ export default async function InitUser() {
return (
<Center>
<Stack align="center" mt="xl">
<LogoWithTitle />
<LogoWithTitle size="lg" />
<Stack gap={6} align="center">
<Title order={3} fw={400} ta="center">
{t("title")}

View File

@@ -3,6 +3,7 @@ import { Inter } from "next/font/google";
import "@homarr/ui/styles.css";
import "@homarr/notifications/styles.css";
import "@homarr/spotlight/styles.css";
import { headers } from "next/headers";
@@ -13,6 +14,7 @@ import {
uiConfiguration,
} from "@homarr/ui";
import { ModalsProvider } from "./_client-providers/modals";
import { NextInternationalProvider } from "./_client-providers/next-international";
import { TRPCReactProvider } from "./_client-providers/trpc";
@@ -51,8 +53,10 @@ export default function Layout(props: {
defaultColorScheme={colorScheme}
{...uiConfiguration}
>
<Notifications />
{props.children}
<ModalsProvider>
<Notifications />
{props.children}
</ModalsProvider>
</MantineProvider>
</NextInternationalProvider>
</TRPCReactProvider>

View File

@@ -0,0 +1,9 @@
"use client";
import { createModalManager } from "mantine-modal-manager";
import { WidgetEditModal } from "@homarr/widgets";
export const [ModalsManager, modalEvents] = createModalManager({
widgetEditModal: WidgetEditModal,
});

View File

@@ -1,21 +0,0 @@
import { auth } from "@homarr/auth";
import { db } from "@homarr/db";
import { Button, Stack, Title } from "@homarr/ui";
export default async function HomePage() {
const currentSession = await auth();
const users = await db.query.users.findMany();
return (
<Stack>
<Title>Home</Title>
<Button>Test</Button>
<pre>{JSON.stringify(users)}</pre>
{currentSession && (
<span>
Currently logged in as <b>{currentSession.user.name}</b>
</span>
)}
</Stack>
);
}

View File

@@ -0,0 +1,27 @@
import type { PropsWithChildren } from "react";
import { widgetImports } from "@homarr/widgets";
import { MainNavigation } from "~/components/layout/navigation";
import { ClientShell } from "~/components/layout/shell";
const getLinks = () => {
return Object.entries(widgetImports).map(([key, value]) => {
return {
href: `/widgets/${key}`,
icon: value.definition.icon,
label: value.definition.sort,
};
});
};
export default function WidgetPreviewLayout({ children }: PropsWithChildren) {
const links = getLinks();
return (
<ClientShell hasHeader={false}>
<MainNavigation links={links} />
{children}
</ClientShell>
);
}

View File

@@ -0,0 +1,48 @@
"use client";
import type { PropsWithChildren } from "react";
import { useState } from "react";
import { notFound } from "next/navigation";
import { ActionIcon, Affix, Center, IconPencil } from "@homarr/ui";
import type { WidgetSort } from "@homarr/widgets";
import { loadWidgetDynamic, widgetImports } from "@homarr/widgets";
import { modalEvents } from "../../modals";
type Props = PropsWithChildren<{ params: { sort: string } }>;
export default function WidgetPreview(props: Props) {
const [options, setOptions] = useState<Record<string, unknown>>({});
if (!(props.params.sort in widgetImports)) {
notFound();
}
const sort = props.params.sort as WidgetSort;
const Comp = loadWidgetDynamic(sort);
return (
<Center h="100vh">
<Comp options={options as never} integrations={[]} />
<Affix bottom={12} right={72}>
<ActionIcon
size={48}
variant="default"
radius="xl"
onClick={() => {
return modalEvents.openManagedModal({
modal: "widgetEditModal",
innerProps: {
sort,
definition: widgetImports[sort].definition.options,
state: [options, setOptions],
},
});
}}
>
<IconPencil size={24} />
</ActionIcon>
</Affix>
</Center>
);
}