format and fix

This commit is contained in:
2026-02-24 23:01:11 +01:00
parent 1bb9241116
commit 81a6daaa75
17 changed files with 133 additions and 59 deletions

View File

@@ -31,12 +31,14 @@ type FlutterViewProps = {
state: Record<string, unknown>;
onEvent: (event: { type: string; payload?: Record<string, unknown> }) => void;
className?: string;
height?: number;
};
export function FlutterView({
state,
onEvent,
className,
height,
}: FlutterViewProps) {
const containerRef = useRef<HTMLDivElement>(null);
const [status, setStatus] = useState<"loading" | "ready" | "error">(
@@ -142,7 +144,7 @@ export function FlutterView({
}, [state]);
return (
<div className={className} style={{ height: "100%", position: "relative" }}>
<div className={className} style={{ position: "relative" }}>
{status === "loading" && (
<div
style={{
@@ -170,7 +172,10 @@ export function FlutterView({
Failed to load Flutter view
</div>
)}
<div ref={containerRef} style={{ width: "100%", height: "100%" }} />
<div
ref={containerRef}
style={{ width: "100%", height: height ?? 400 }}
/>
</div>
);
}

View File

@@ -3,21 +3,25 @@ import { useForm } from "@tanstack/react-form";
import { useQueryClient } from "@tanstack/react-query";
import { toast } from "sonner";
import { createTimelineGroup } from "@/functions/create-timeline-group";
import { Button } from "./ui/button";
import { FieldControl, FieldError, FieldLabel, FieldRoot } from "./ui/field";
import {
DrawerRoot,
DrawerTrigger,
DrawerPortal,
DrawerViewport,
DrawerPopup,
DrawerTitle,
DrawerContent,
DrawerClose,
DrawerContent,
DrawerPopup,
DrawerPortal,
DrawerRoot,
DrawerTitle,
DrawerTrigger,
DrawerViewport,
} from "./ui/drawer";
import { createTimelineGroup } from "@/functions/create-timeline-group";
export default function GroupFormDrawer({ timelineId }: { timelineId: string }) {
export default function GroupFormDrawer({
timelineId,
}: {
timelineId: string;
}) {
const [open, setOpen] = useState(false);
const queryClient = useQueryClient();
@@ -30,12 +34,16 @@ export default function GroupFormDrawer({ timelineId }: { timelineId: string })
await createTimelineGroup({
data: { title: value.title, timelineId },
});
await queryClient.invalidateQueries({ queryKey: ["timeline", timelineId] });
await queryClient.invalidateQueries({
queryKey: ["timeline", timelineId],
});
setOpen(false);
form.reset();
toast.success("Group created");
} catch (error) {
toast.error(error instanceof Error ? error.message : "Failed to create group");
toast.error(
error instanceof Error ? error.message : "Failed to create group"
);
}
},
});
@@ -73,10 +81,14 @@ export default function GroupFormDrawer({ timelineId }: { timelineId: string })
value={field.state.value}
onBlur={field.handleBlur}
onChange={(e) =>
field.handleChange((e.target as HTMLInputElement).value)
field.handleChange(
(e.target as HTMLInputElement).value
)
}
/>
<FieldError match="valueMissing">Title is required</FieldError>
<FieldError match="valueMissing">
Title is required
</FieldError>
</FieldRoot>
)}
</form.Field>

View File

@@ -3,19 +3,19 @@ import { useForm } from "@tanstack/react-form";
import { useQueryClient } from "@tanstack/react-query";
import { toast } from "sonner";
import { createTimelineItem } from "@/functions/create-timeline-item";
import { Button } from "./ui/button";
import { FieldControl, FieldError, FieldLabel, FieldRoot } from "./ui/field";
import {
DrawerRoot,
DrawerTrigger,
DrawerPortal,
DrawerViewport,
DrawerPopup,
DrawerTitle,
DrawerContent,
DrawerClose,
DrawerContent,
DrawerPopup,
DrawerPortal,
DrawerRoot,
DrawerTitle,
DrawerTrigger,
DrawerViewport,
} from "./ui/drawer";
import { createTimelineItem } from "@/functions/create-timeline-item";
export default function ItemFormDrawer({
timelineGroupId,
@@ -45,12 +45,16 @@ export default function ItemFormDrawer({
timelineGroupId,
},
});
await queryClient.invalidateQueries({ queryKey: ["timeline", timelineId] });
await queryClient.invalidateQueries({
queryKey: ["timeline", timelineId],
});
setOpen(false);
form.reset();
toast.success("Item created");
} catch (error) {
toast.error(error instanceof Error ? error.message : "Failed to create item");
toast.error(
error instanceof Error ? error.message : "Failed to create item"
);
}
},
});
@@ -88,10 +92,14 @@ export default function ItemFormDrawer({
value={field.state.value}
onBlur={field.handleBlur}
onChange={(e) =>
field.handleChange((e.target as HTMLInputElement).value)
field.handleChange(
(e.target as HTMLInputElement).value
)
}
/>
<FieldError match="valueMissing">Title is required</FieldError>
<FieldError match="valueMissing">
Title is required
</FieldError>
</FieldRoot>
)}
</form.Field>
@@ -105,7 +113,9 @@ export default function ItemFormDrawer({
value={field.state.value}
onBlur={field.handleBlur}
onChange={(e) =>
field.handleChange((e.target as HTMLInputElement).value)
field.handleChange(
(e.target as HTMLInputElement).value
)
}
/>
</FieldRoot>
@@ -122,10 +132,14 @@ export default function ItemFormDrawer({
value={field.state.value}
onBlur={field.handleBlur}
onChange={(e) =>
field.handleChange((e.target as HTMLInputElement).value)
field.handleChange(
(e.target as HTMLInputElement).value
)
}
/>
<FieldError match="valueMissing">Start date is required</FieldError>
<FieldError match="valueMissing">
Start date is required
</FieldError>
</FieldRoot>
)}
</form.Field>
@@ -139,7 +153,9 @@ export default function ItemFormDrawer({
value={field.state.value}
onBlur={field.handleBlur}
onChange={(e) =>
field.handleChange((e.target as HTMLInputElement).value)
field.handleChange(
(e.target as HTMLInputElement).value
)
}
/>
</FieldRoot>

View File

@@ -11,5 +11,5 @@ export const Route = createFileRoute("/.well-known/oauth-authorization-server")(
GET: ({ request }) => handler(request),
},
},
},
}
);

View File

@@ -18,7 +18,7 @@ export const Route = createFileRoute("/.well-known/oauth-protected-resource")({
"Cache-Control":
"public, max-age=15, stale-while-revalidate=15, stale-if-error=86400",
},
},
}
);
},
},

View File

@@ -47,7 +47,7 @@ function RootDocument() {
<HeadContent />
</head>
<body>
<div className="grid h-svh grid-rows-[auto_1fr]">
<div className="grid min-h-svh grid-rows-[auto_1fr]">
<Header />
<Outlet />
</div>

View File

@@ -5,8 +5,8 @@ import { Button } from "@/components/ui/button";
export const Route = createFileRoute("/consent")({
validateSearch: (search: Record<string, unknown>) => ({
client_id: (search.client_id as string) ?? "",
scope: (search.scope as string) ?? "",
client_id: (search.client_id as string | undefined) ?? "",
scope: (search.scope as string | undefined) ?? "",
}),
component: ConsentComponent,
});

View File

@@ -5,7 +5,12 @@ import { toast } from "sonner";
import { authClient } from "@/lib/auth-client";
import { createTimeline } from "@/functions/create-timeline";
import { Button } from "@/components/ui/button";
import { FieldControl, FieldError, FieldLabel, FieldRoot } from "@/components/ui/field";
import {
FieldControl,
FieldError,
FieldLabel,
FieldRoot,
} from "@/components/ui/field";
export const Route = createFileRoute("/")({
component: HomeComponent,
@@ -22,9 +27,14 @@ function HomeComponent() {
try {
await authClient.signIn.anonymous();
const timeline = await createTimeline({ data: { title: value.title } });
navigate({ to: "/timeline/$timelineId", params: { timelineId: timeline.id } });
navigate({
to: "/timeline/$timelineId",
params: { timelineId: timeline.id },
});
} catch (error) {
toast.error(error instanceof Error ? error.message : "Failed to create timeline");
toast.error(
error instanceof Error ? error.message : "Failed to create timeline"
);
}
},
});
@@ -66,9 +76,7 @@ function HomeComponent() {
field.handleChange((e.target as HTMLInputElement).value)
}
/>
<FieldError match="valueMissing">
Name is required
</FieldError>
<FieldError match="valueMissing">Name is required</FieldError>
</FieldRoot>
)}
</form.Field>

View File

@@ -2,8 +2,6 @@ import { useCallback, useMemo, useState } from "react";
import { createFileRoute } from "@tanstack/react-router";
import { useSuspenseQuery } from "@tanstack/react-query";
import { timelineQueryOptions } from "@/functions/get-timeline";
import GroupFormDrawer from "@/components/group-form-drawer";
import ItemFormDrawer from "@/components/item-form-drawer";
import { FlutterView } from "@/components/flutter-view";
export const Route = createFileRoute("/timeline/$timelineId")({
@@ -44,11 +42,16 @@ function RouteComponent() {
[timeline, selectedItemId]
);
const [flutterHeight, setFlutterHeight] = useState<number | undefined>();
const handleEvent = useCallback(
(event: { type: string; payload?: Record<string, unknown> }) => {
switch (event.type) {
case "content_height":
setFlutterHeight(event.payload?.height as number);
break;
case "item_selected":
setSelectedItemId((event.payload?.itemId as string) ?? null);
// setSelectedItemId((event.payload?.itemId as string) ?? null);
break;
case "item_deselected":
setSelectedItemId(null);
@@ -59,13 +62,16 @@ function RouteComponent() {
);
return (
<div className="flex h-screen flex-col px-4 py-6">
<h1 className="text-3xl font-serif font-bold mb-6">{timeline.title}</h1>
<div className="flex flex-col">
<h1 className="text-3xl font-serif font-bold mb-6 mx-4">
{timeline.title}
</h1>
<FlutterView
state={flutterState}
onEvent={handleEvent}
className="min-h-0 flex-1 rounded-lg overflow-hidden"
className="overflow-hidden"
height={flutterHeight}
/>
</div>
);