diff --git a/client/src/FloatingActionButton.tsx b/client/src/FloatingActionButton.tsx new file mode 100644 index 0000000..8888fb8 --- /dev/null +++ b/client/src/FloatingActionButton.tsx @@ -0,0 +1,57 @@ +import { + createContext, + createEffect, + createSignal, + onCleanup, + useContext, + type Accessor, + type ParentProps, + type Signal, + type VoidProps, +} from "solid-js"; + +import type { IconId } from "./Icon"; + +type FloatingActionButtonConfig = { + to: string; + label: string; + icon: IconId; +} | null; + +const context = createContext | undefined>(undefined); + +export function FloatingActionButtonProvider(properties: ParentProps) { + const signal = createSignal(null); + return {properties.children}; +} + +export function useFloatingActionButton(): Accessor { + const signal = useContext(context); + if (!signal) + throw new Error("useFloatingActionButton must be used within a FloatingActionButtonProvider"); + + const [floatingActionButton] = signal; + return floatingActionButton; +} + +export function FloatingActionButton( + properties: VoidProps<{ to: string; label: string; icon: IconId }>, +) { + const signal = useContext(context); + if (!signal) + throw new Error("FloatingActionButton must be used within a FloatingActionButtonProvider"); + + const [, setFloatingActionButton] = signal; + + createEffect(() => { + setFloatingActionButton({ + to: properties.to, + label: properties.label, + icon: properties.icon as IconId, + }); + }); + + onCleanup(() => setFloatingActionButton(null)); + + return undefined; +} diff --git a/client/src/Navigation.tsx b/client/src/Navigation.tsx index c703200..f2b3e08 100644 --- a/client/src/Navigation.tsx +++ b/client/src/Navigation.tsx @@ -1,53 +1,70 @@ import { Link } from "@tanstack/solid-router"; +import { Show } from "solid-js"; import type { JSX, VoidProps } from "solid-js"; -import Icon from "./Icon"; +import { useFloatingActionButton } from "@/FloatingActionButton"; +import Icon from "@/Icon"; + +export default function Navigation(properties: VoidProps>) { + const floatingActionButton = useFloatingActionButton(); -export default function Navigation(properties: VoidProps>) { return ( - + )} + + + ); } diff --git a/client/src/index.css b/client/src/index.css index ed5ed49..2d6f901 100644 --- a/client/src/index.css +++ b/client/src/index.css @@ -45,7 +45,7 @@ when we have perfectly fine CSS solutions to deal with the same problem. } .floating-action-button { - @apply rounded-medium bg-primary text-on-primary focus-within:outline-primary absolute right-6 bottom-6 grid size-14 cursor-default content-center justify-items-center outline-offset-4 focus:outline-none; + @apply rounded-medium bg-primary text-on-primary focus-within:outline-primary grid size-14 cursor-default content-center justify-items-center outline-offset-4 focus:outline-none; } .icon-button { diff --git a/client/src/index.tsx b/client/src/index.tsx index 332460e..b3c161f 100644 --- a/client/src/index.tsx +++ b/client/src/index.tsx @@ -5,6 +5,7 @@ import { createRouter, RouterProvider } from "@tanstack/solid-router"; import { render } from "solid-js/web"; import { routeTree } from "./routeTree.gen"; +import { FloatingActionButtonProvider } from "./FloatingActionButton"; import { TitleProvider } from "./Title"; import { idQuery } from "./user"; @@ -42,9 +43,11 @@ declare module "@tanstack/solid-router" { render( () => ( - - - + + + + + ), document.body, diff --git a/client/src/routes/_app/projects.tsx b/client/src/routes/_app/projects.tsx index b2e4076..a29f37c 100644 --- a/client/src/routes/_app/projects.tsx +++ b/client/src/routes/_app/projects.tsx @@ -17,10 +17,6 @@ export const Route = createFileRoute("/_app/projects")({ }, }); -function Card(properties: VoidProps<{ project: Project }>) { - return
  • {properties.project.name}
  • ; -} - function Projects() { const routeData = Route.useLoaderData(); const userId = () => routeData().userId; diff --git a/client/src/routes/_app/route.tsx b/client/src/routes/_app/route.tsx index 6f42eed..751d59d 100644 --- a/client/src/routes/_app/route.tsx +++ b/client/src/routes/_app/route.tsx @@ -34,7 +34,7 @@ function RouteComponent() { return ( - + - - Log time - - + <FloatingActionButton to="/times/new" label="Log time" icon="add" /> <main class="grid h-min gap-y-4 px-4"> <For each={times()}> {([day, timesForDay]) => (