From e62547526ba54b554cb6c1e511bfa6e2995804b3 Mon Sep 17 00:00:00 2001 From: Harshith Mullapudi Date: Sat, 7 Jun 2025 10:19:09 +0530 Subject: [PATCH] Feat: added website --- README.md | 5 +- .../app/components/graph/graph-popover.tsx | 303 +++ .../components/graph/graph-visualization.tsx | 185 ++ apps/webapp/app/components/graph/graph.tsx | 1051 ++++++++++ .../app/components/graph/node-colors.ts | 84 + apps/webapp/app/components/graph/type.ts | 82 + .../app/components/layout/LoginPageLayout.tsx | 6 +- apps/webapp/app/components/logo/logo.tsx | 108 +- .../app/components/sidebar/app-sidebar.tsx | 70 + .../app/components/sidebar/nav-main.tsx | 38 + .../app/components/sidebar/nav-user.tsx | 83 + apps/webapp/app/components/ui/avatar.tsx | 87 + apps/webapp/app/components/ui/button.tsx | 11 +- apps/webapp/app/components/ui/card.tsx | 80 + apps/webapp/app/components/ui/color-utils.ts | 43 + .../app/components/ui/dropdown-menu.tsx | 204 ++ apps/webapp/app/components/ui/input.tsx | 25 + .../webapp/app/components/ui/multi-select.tsx | 76 + apps/webapp/app/components/ui/popover.tsx | 38 + apps/webapp/app/components/ui/select.tsx | 174 ++ apps/webapp/app/components/ui/separator.tsx | 29 + apps/webapp/app/components/ui/sheet.tsx | 138 ++ apps/webapp/app/components/ui/sidebar.tsx | 724 +++++++ apps/webapp/app/components/ui/skeleton.tsx | 17 + apps/webapp/app/components/ui/tooltip.tsx | 28 + apps/webapp/app/db.server.ts | 4 +- apps/webapp/app/hooks/use-mobile.ts | 19 + apps/webapp/app/hooks/use-mobile.tsx | 21 + apps/webapp/app/hooks/useTypedMatchData.ts | 2 +- apps/webapp/app/hooks/useUser.ts | 4 +- apps/webapp/app/hooks/useWorkspace.ts | 25 + apps/webapp/app/models/message.server.ts | 3 +- .../app/models/personal-token.server.ts | 2 +- apps/webapp/app/models/user.server.ts | 4 +- apps/webapp/app/models/workspace.server.ts | 38 + apps/webapp/app/root.tsx | 10 +- apps/webapp/app/routes/_index.tsx | 177 +- .../app/routes/confirm-basic-details.tsx | 151 ++ apps/webapp/app/routes/ingest.tsx | 6 +- apps/webapp/app/routes/login.tsx | 64 +- apps/webapp/app/routes/logout.tsx | 18 + .../webapp/app/services/graphModels/entity.ts | 2 +- .../app/services/graphModels/episode.ts | 2 +- .../app/services/graphModels/statement.ts | 2 +- .../app/services/knowledgeGraph.server.ts | 2 +- .../services/personalAccessToken.server.ts | 2 +- .../webapp/app/services/prompts/statements.ts | 2 +- apps/webapp/app/services/session.server.ts | 41 + apps/webapp/app/tailwind.css | 263 +++ apps/webapp/app/utils/pathBuilder.ts | 7 + apps/webapp/app/utils/presets/apps.ts | 100 + apps/webapp/app/utils/singleton.ts | 6 +- apps/webapp/package.json | 27 +- apps/webapp/public/favicon.ico | Bin 16958 -> 10246 bytes apps/webapp/public/logo-dark.png | Bin 80332 -> 7951 bytes apps/webapp/public/logo-dark.svg | 12 + apps/webapp/public/logo-light.png | Bin 5906 -> 60010 bytes apps/webapp/public/logo-light.svg | 12 + apps/webapp/tailwind.config.ts | 128 -- package.json | 2 +- packages/database/package.json | 2 +- .../migration.sql | 2 + packages/database/prisma/schema.prisma | 2 + packages/types/package.json | 2 +- pnpm-lock.yaml | 1776 ++++++++++++++++- 65 files changed, 6262 insertions(+), 369 deletions(-) create mode 100644 apps/webapp/app/components/graph/graph-popover.tsx create mode 100644 apps/webapp/app/components/graph/graph-visualization.tsx create mode 100644 apps/webapp/app/components/graph/graph.tsx create mode 100644 apps/webapp/app/components/graph/node-colors.ts create mode 100644 apps/webapp/app/components/graph/type.ts create mode 100644 apps/webapp/app/components/sidebar/app-sidebar.tsx create mode 100644 apps/webapp/app/components/sidebar/nav-main.tsx create mode 100644 apps/webapp/app/components/sidebar/nav-user.tsx create mode 100644 apps/webapp/app/components/ui/avatar.tsx create mode 100644 apps/webapp/app/components/ui/card.tsx create mode 100644 apps/webapp/app/components/ui/color-utils.ts create mode 100644 apps/webapp/app/components/ui/dropdown-menu.tsx create mode 100644 apps/webapp/app/components/ui/input.tsx create mode 100644 apps/webapp/app/components/ui/multi-select.tsx create mode 100644 apps/webapp/app/components/ui/popover.tsx create mode 100644 apps/webapp/app/components/ui/select.tsx create mode 100644 apps/webapp/app/components/ui/separator.tsx create mode 100644 apps/webapp/app/components/ui/sheet.tsx create mode 100644 apps/webapp/app/components/ui/sidebar.tsx create mode 100644 apps/webapp/app/components/ui/skeleton.tsx create mode 100644 apps/webapp/app/components/ui/tooltip.tsx create mode 100644 apps/webapp/app/hooks/use-mobile.ts create mode 100644 apps/webapp/app/hooks/use-mobile.tsx create mode 100644 apps/webapp/app/hooks/useWorkspace.ts create mode 100644 apps/webapp/app/models/workspace.server.ts create mode 100644 apps/webapp/app/routes/confirm-basic-details.tsx create mode 100644 apps/webapp/app/routes/logout.tsx create mode 100644 apps/webapp/app/utils/pathBuilder.ts create mode 100644 apps/webapp/app/utils/presets/apps.ts create mode 100644 apps/webapp/public/logo-dark.svg create mode 100644 apps/webapp/public/logo-light.svg create mode 100644 packages/database/prisma/migrations/20250605181456_add_integrations/migration.sql diff --git a/README.md b/README.md index 70c82fc..967f28c 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,10 @@ -
- Recall logo + CORE logo
-# Recall +# CORE Simple memory management system for AI agents with per-space ingestion and search capabilities. diff --git a/apps/webapp/app/components/graph/graph-popover.tsx b/apps/webapp/app/components/graph/graph-popover.tsx new file mode 100644 index 0000000..e8ce04b --- /dev/null +++ b/apps/webapp/app/components/graph/graph-popover.tsx @@ -0,0 +1,303 @@ +"use client"; + +import { Popover, PopoverContent, PopoverTrigger } from "../ui/popover"; +import type { NodePopupContent, EdgePopupContent } from "./type"; +import { getNodeColor } from "./node-colors"; + +import { useMemo } from "react"; + +import { useTheme } from "remix-themes"; + +import dayjs from "dayjs"; + +/** + * Format a date string into a readable format + */ +export function formatDate( + dateString?: string | null, + format: string = "MMM D, YYYY", +): string { + if (!dateString) return "Unknown"; + + try { + return dayjs(dateString).format(format); + } catch (error) { + console.error("Error formatting date:", error); + return "Invalid date"; + } +} + +interface GraphPopoversProps { + showNodePopup: boolean; + showEdgePopup: boolean; + nodePopupContent: NodePopupContent | null; + edgePopupContent: EdgePopupContent | null; + onOpenChange?: (open: boolean) => void; + labelColorMap?: Map; +} + +export function GraphPopovers({ + showNodePopup, + showEdgePopup, + nodePopupContent, + edgePopupContent, + onOpenChange, + labelColorMap, +}: GraphPopoversProps) { + const [resolvedTheme] = useTheme(); + const isDarkMode = resolvedTheme === "dark"; + + const primaryNodeLabel = useMemo((): string | null => { + if (!nodePopupContent) { + return null; + } + + // Check if node has primaryLabel property (GraphNode) + const nodeAny = nodePopupContent.node as any; + if (nodeAny.primaryLabel && typeof nodeAny.primaryLabel === "string") { + return nodeAny.primaryLabel; + } + + // Fall back to original logic with labels + const primaryLabel = nodePopupContent.node.labels?.find( + (label) => label !== "Entity", + ); + return primaryLabel || "Entity"; + }, [nodePopupContent]); + + // Get the color for the primary label + const labelColor = useMemo(() => { + if (!primaryNodeLabel || !labelColorMap) return ""; + return getNodeColor(primaryNodeLabel, isDarkMode, labelColorMap); + }, [primaryNodeLabel, isDarkMode, labelColorMap]); + + const attributesToDisplay = useMemo(() => { + if (!nodePopupContent) { + return []; + } + const entityProperties = Object.fromEntries( + Object.entries(nodePopupContent.node.attributes || {}).filter( + ([key]) => key !== "labels", + ), + ); + + return Object.entries(entityProperties).map(([key, value]) => ({ + key, + value, + })); + }, [nodePopupContent]); + + return ( +
+ + +
+ + e.preventDefault()} + > +
+
+

Node Details

+ {primaryNodeLabel && ( + + {primaryNodeLabel} + + )} +
+
+

+ + Name: + + {nodePopupContent?.node.name || "Unknown"} +

+

+ + UUID: + + {nodePopupContent?.node.uuid || "Unknown"} +

+

+ + Created: + + {nodePopupContent?.node.created_at && + formatDate(nodePopupContent?.node.created_at)} +

+ + {attributesToDisplay.length > 0 && ( +
+

+ Properties: +

+
+ {attributesToDisplay.map(({ key, value }) => ( +

+ + {key}: + {" "} + + {typeof value === "object" + ? JSON.stringify(value) + : String(value)} + +

+ ))} +
+
+ )} + + {nodePopupContent?.node.summary && ( +
+

+ Summary: +

+
{ + e.stopPropagation(); + const target = e.currentTarget; + target.scrollTop += e.deltaY; + }} + > +

+ {nodePopupContent.node.summary} +

+
+
+ )} + + {nodePopupContent?.node.labels?.length ? ( +
+

+ Labels: +

+
+ {nodePopupContent.node.labels.map((label) => ( + + {label} + + ))} +
+
+ ) : null} +
+
+
+ + + + +
+ + e.preventDefault()} + > +
+

+ {edgePopupContent?.source.name || "Unknown"} →{" "} + + {edgePopupContent?.relation.name || "Unknown"} + {" "} + → {edgePopupContent?.target.name || "Unknown"} +

+
+
+

Relationship

+
+

+ + UUID: + + {edgePopupContent?.relation.uuid || "Unknown"} +

+

+ + Type: + + {edgePopupContent?.relation.name || "Unknown"} +

+ {edgePopupContent?.relation.fact && ( +

+ + Fact: + + {edgePopupContent.relation.fact} +

+ )} + {edgePopupContent?.relation.episodes?.length ? ( +
+

+ Episodes: +

+
+ {edgePopupContent.relation.episodes.map((episode) => ( + + {episode} + + ))} +
+
+ ) : null} +

+ + Created: + + {formatDate(edgePopupContent?.relation.created_at)} +

+ {edgePopupContent?.relation.valid_at && ( +

+ + Valid From: + + {formatDate(edgePopupContent.relation.valid_at)} +

+ )} + {edgePopupContent?.relation.expired_at && ( +

+ + Expired At: + + {formatDate(edgePopupContent.relation.expired_at)} +

+ )} + {edgePopupContent?.relation.invalid_at && ( +

+ + Invalid At: + + {formatDate(edgePopupContent.relation.invalid_at)} +

+ )} +
+
+
+ +
+ ); +} diff --git a/apps/webapp/app/components/graph/graph-visualization.tsx b/apps/webapp/app/components/graph/graph-visualization.tsx new file mode 100644 index 0000000..bd6118e --- /dev/null +++ b/apps/webapp/app/components/graph/graph-visualization.tsx @@ -0,0 +1,185 @@ +"use client"; + +import { useState, useMemo, forwardRef } from "react"; +import { Graph, GraphRef } from "./graph"; +import { GraphPopovers } from "./graph-popover"; +import type { RawTriplet, NodePopupContent, EdgePopupContent } from "./type"; +import { toGraphTriplets } from "./type"; +import { createLabelColorMap, getNodeColor } from "./node-colors"; + +import { + HoverCard, + HoverCardContent, + HoverCardTrigger, +} from "@/components/ui/hover-card"; +import { useTheme } from "remix-themes"; + +interface GraphVisualizationProps { + triplets: RawTriplet[]; + width?: number; + height?: number; + zoomOnMount?: boolean; + className?: string; +} + +export const GraphVisualization = forwardRef( + ( + { + triplets, + width = window.innerWidth * 0.85, + height = window.innerHeight * 0.85, + zoomOnMount = true, + className = "border border-border rounded-md h-[85vh] overflow-hidden relative", + }, + ref, + ) => { + const [resolvedTheme] = useTheme(); + const isDarkMode = resolvedTheme === "dark"; + + // Graph state for popovers + const [showNodePopup, setShowNodePopup] = useState(false); + const [showEdgePopup, setShowEdgePopup] = useState(false); + const [nodePopupContent, setNodePopupContent] = + useState(null); + const [edgePopupContent, setEdgePopupContent] = + useState(null); + + // Convert raw triplets to graph triplets + const graphTriplets = useMemo(() => toGraphTriplets(triplets), [triplets]); + + // Extract all unique labels from triplets + const allLabels = useMemo(() => { + const labels = new Set(); + labels.add("Entity"); // Always include Entity as default + + graphTriplets.forEach((triplet) => { + if (triplet.source.primaryLabel) + labels.add(triplet.source.primaryLabel); + if (triplet.target.primaryLabel) + labels.add(triplet.target.primaryLabel); + }); + + return Array.from(labels).sort((a, b) => { + // Always put "Entity" first + if (a === "Entity") return -1; + if (b === "Entity") return 1; + // Sort others alphabetically + return a.localeCompare(b); + }); + }, [graphTriplets]); + + // Create a shared label color map + const sharedLabelColorMap = useMemo(() => { + return createLabelColorMap(allLabels); + }, [allLabels]); + + // Handle node click + const handleNodeClick = (nodeId: string) => { + // Find the triplet that contains this node + const triplet = triplets.find( + (t) => t.sourceNode.uuid === nodeId || t.targetNode.uuid === nodeId, + ); + + if (!triplet) return; + + // Determine which node was clicked (source or target) + const node = + triplet.sourceNode.uuid === nodeId + ? triplet.sourceNode + : triplet.targetNode; + + // Set popup content and show the popup + setNodePopupContent({ + id: nodeId, + node: node, + }); + setShowNodePopup(true); + setShowEdgePopup(false); + }; + + // Handle edge click + const handleEdgeClick = (edgeId: string) => { + // Find the triplet that contains this edge + const triplet = triplets.find((t) => t.edge.uuid === edgeId); + + if (!triplet) return; + + // Set popup content and show the popup + setEdgePopupContent({ + id: edgeId, + source: triplet.sourceNode, + target: triplet.targetNode, + relation: triplet.edge, + }); + setShowEdgePopup(true); + setShowNodePopup(false); + }; + + // Handle popover close + const handlePopoverClose = () => { + setShowNodePopup(false); + setShowEdgePopup(false); + }; + return ( +
+ {/* Entity Types Legend Button */} +
+ + + + + +
+
+ {allLabels.map((label) => ( +
+
+ {label} +
+ ))} +
+
+ + +
+ + {triplets.length > 0 ? ( + + ) : ( +
+

No graph data to visualize.

+
+ )} + +
+ ); + }, +); diff --git a/apps/webapp/app/components/graph/graph.tsx b/apps/webapp/app/components/graph/graph.tsx new file mode 100644 index 0000000..cfd81fc --- /dev/null +++ b/apps/webapp/app/components/graph/graph.tsx @@ -0,0 +1,1051 @@ +"use client"; + +import { + useEffect, + useRef, + useMemo, + useCallback, + useImperativeHandle, + forwardRef, +} from "react"; +import * as d3 from "d3"; +import colors from "tailwindcss/colors"; + +import type { GraphTriplet, IdValue, GraphNode } from "./type"; +import { + createLabelColorMap, + getNodeColor as getNodeColorByLabel, +} from "./node-colors"; +import { useTheme } from "remix-themes"; + +interface GraphProps { + triplets: GraphTriplet[]; + width?: number; + height?: number; + zoomOnMount?: boolean; + onNodeClick?: (nodeId: string) => void; + onEdgeClick?: (edgeId: string) => void; + onBlur?: () => void; + labelColorMap?: Map; +} + +// Add ref type for zoomToLinkById +export interface GraphRef { + zoomToLinkById: (linkId: string) => void; +} + +export const Graph = forwardRef( + ( + { + triplets, + width = 1000, + height = 800, + zoomOnMount = true, + onNodeClick, + onEdgeClick, + onBlur, + labelColorMap: externalLabelColorMap, + }, + ref, + ) => { + const svgRef = useRef(null); + const [themeMode] = useTheme(); + + // Function refs to keep track of reset functions + const resetLinksRef = useRef<(() => void) | null>(null); + const resetNodesRef = useRef<(() => void) | null>(null); + const handleLinkClickRef = useRef< + ((event: any, d: any, relation: IdValue) => void) | null + >(null); + const simulationRef = useRef | null>(null); + const zoomRef = useRef | null>( + null, + ); + const isInitializedRef = useRef(false); + + // Add ref for zoomToLinkById + const graphRef = useRef({ + zoomToLinkById: (linkId: string) => { + if ( + !svgRef.current || + !resetLinksRef.current || + !resetNodesRef.current || + !handleLinkClickRef.current + ) + return; + const svgElement = d3.select(svgRef.current); + const linkGroups = svgElement.selectAll("g > g"); // Select all link groups + + let found = false; + + // Iterate through link groups to find matching relation + linkGroups.each(function (d: any) { + if (found) return; // Skip if already found + + if (d?.relationData) { + const relation = d.relationData.find( + (r: IdValue) => r.id === linkId, + ); + if (relation) { + found = true; + const resetLinks = resetLinksRef.current; + const resetNodes = resetNodesRef.current; + const handleLinkClick = handleLinkClickRef.current; + + if (resetLinks) resetLinks(); + if (resetNodes) resetNodes(); + if (handleLinkClick) + handleLinkClick({ stopPropagation: () => {} }, d, relation); + } + } + }); + + if (!found) { + console.warn(`Link with id ${linkId} not found`); + } + }, + }); + + // Expose the ref through forwardRef + useImperativeHandle(ref, () => graphRef.current); + + // Memoize theme to prevent unnecessary recreation + const theme = useMemo( + () => ({ + node: { + fill: colors.pink[500], + stroke: themeMode === "dark" ? colors.slate[100] : colors.slate[900], + hover: colors.blue[400], + text: themeMode === "dark" ? colors.slate[100] : colors.slate[900], + selected: colors.blue[500], + dimmed: colors.pink[300], + }, + link: { + stroke: themeMode === "dark" ? colors.slate[600] : colors.slate[400], + selected: colors.blue[400], + dimmed: themeMode === "dark" ? colors.slate[800] : colors.slate[200], + label: { + bg: themeMode === "dark" ? colors.slate[800] : colors.slate[200], + text: themeMode === "dark" ? colors.slate[100] : colors.slate[900], + }, + }, + background: + themeMode === "dark" ? colors.slate[900] : colors.slate[100], + controls: { + bg: themeMode === "dark" ? colors.slate[800] : colors.slate[200], + hover: themeMode === "dark" ? colors.slate[700] : colors.slate[300], + text: themeMode === "dark" ? colors.slate[100] : colors.slate[900], + }, + }), + [themeMode], + ); + + // Extract all unique labels from triplets + const allLabels = useMemo(() => { + // Only calculate if we need to create our own map + if (externalLabelColorMap) return []; + + const labels = new Set(); + labels.add("Entity"); // Always include Entity as default + + triplets.forEach((triplet) => { + if (triplet.source.primaryLabel) + labels.add(triplet.source.primaryLabel); + if (triplet.target.primaryLabel) + labels.add(triplet.target.primaryLabel); + }); + + return Array.from(labels); + }, [triplets, externalLabelColorMap]); + + // Create a mapping of label to color + const labelColorMap = useMemo(() => { + return externalLabelColorMap || createLabelColorMap(allLabels); + }, [allLabels, externalLabelColorMap]); + + // Create a mapping of node IDs to their data + const nodeDataMap = useMemo(() => { + const result = new Map(); + + triplets.forEach((triplet) => { + result.set(triplet.source.id, triplet.source); + result.set(triplet.target.id, triplet.target); + }); + + return result; + }, [triplets]); + + // Function to get node color + const getNodeColor = useCallback( + (node: any): string => { + if (!node) { + return getNodeColorByLabel(null, themeMode === "dark", labelColorMap); + } + + // Get the full node data if we only have an ID + const nodeData = nodeDataMap.get(node.id) || node; + + // Extract primaryLabel from node data + const primaryLabel = nodeData.primaryLabel; + + return getNodeColorByLabel( + primaryLabel, + themeMode === "dark", + labelColorMap, + ); + }, + [labelColorMap, nodeDataMap, themeMode], + ); + + // Process graph data + const { nodes, links } = useMemo(() => { + const nodes = Array.from( + new Set(triplets.flatMap((t) => [t.source.id, t.target.id])), + ).map((id) => { + const nodeData = triplets.find( + (t) => t.source.id === id || t.target.id === id, + ); + const value = nodeData + ? nodeData.source.id === id + ? nodeData.source.value + : nodeData.target.value + : id; + return { + id, + value, + }; + }); + + const linkGroups = triplets.reduce( + (groups, triplet) => { + // Skip isolated node edges (they are just placeholders for showing isolated nodes) + if (triplet.relation.type === "_isolated_node_") { + return groups; + } + + let key = `${triplet.source.id}-${triplet.target.id}`; + const reverseKey = `${triplet.target.id}-${triplet.source.id}`; + + if (groups[reverseKey]) { + key = reverseKey; + } + + if (!groups[key]) { + groups[key] = { + source: triplet.source.id, + target: triplet.target.id, + relations: [], + relationData: [], + curveStrength: 0, + }; + } + groups[key].relations.push(triplet.relation.value); + groups[key].relationData.push(triplet.relation); + return groups; + }, + {} as Record< + string, + { + source: string; + target: string; + relations: string[]; + relationData: IdValue[]; + curveStrength: number; + } + >, + ); + + return { + nodes, + links: Object.values(linkGroups), + }; + }, [triplets]); + + // Initialize or update visualization - This will run only once on mount + useEffect(() => { + // Skip if already initialized or ref not available + if (isInitializedRef.current || !svgRef.current) return; + + // Mark as initialized to prevent re-running + isInitializedRef.current = true; + + const svgElement = d3.select(svgRef.current); + svgElement.selectAll("*").remove(); + + const g = svgElement.append("g"); + + // Drag handler function + const drag = ( + simulation: d3.Simulation, + ) => { + const originalSettings = { + velocityDecay: 0.4, + alphaDecay: 0.05, + }; + + function dragstarted(event: any) { + if (!event.active) { + simulation + .velocityDecay(0.7) + .alphaDecay(0.1) + .alphaTarget(0.1) + .restart(); + } + d3.select(event.sourceEvent.target.parentNode) + .select("circle") + .attr("stroke", theme.node.hover) + .attr("stroke-width", 3); + + event.subject.fx = event.subject.x; + event.subject.fy = event.subject.y; + } + + function dragged(event: any) { + event.subject.x = event.x; + event.subject.y = event.y; + event.subject.fx = event.x; + event.subject.fy = event.y; + } + + function dragended(event: any) { + if (!event.active) { + simulation + .velocityDecay(originalSettings.velocityDecay) + .alphaDecay(originalSettings.alphaDecay) + .alphaTarget(0); + } + + // Keep the node fixed at its final position + event.subject.fx = event.x; + event.subject.fy = event.y; + + d3.select(event.sourceEvent.target.parentNode) + .select("circle") + .attr("stroke", theme.node.stroke) + .attr("stroke-width", 2); + } + + return d3 + .drag() + .on("start", dragstarted) + .on("drag", dragged) + .on("end", dragended); + }; + + // Setup zoom behavior + const zoom = d3 + .zoom() + .scaleExtent([0.1, 4]) + .on("zoom", (event) => { + g.attr("transform", event.transform); + }); + + zoomRef.current = zoom; + // @ts-ignore + svgElement.call(zoom).call(zoom.transform, d3.zoomIdentity.scale(0.8)); + + // Identify which nodes are isolated (not in any links) + const nodeIdSet = new Set(nodes.map((n: any) => n.id)); + const linkedNodeIds = new Set(); + + links.forEach((link: any) => { + const sourceId = + typeof link.source === "string" ? link.source : link.source.id; + const targetId = + typeof link.target === "string" ? link.target : link.target.id; + linkedNodeIds.add(sourceId); + linkedNodeIds.add(targetId); + }); + + // Nodes that don't appear in any link are isolated + const isolatedNodeIds = new Set(); + nodeIdSet.forEach((nodeId: string) => { + if (!linkedNodeIds.has(nodeId)) { + isolatedNodeIds.add(nodeId); + } + }); + + // Create simulation with custom forces + const simulation = d3 + .forceSimulation(nodes as d3.SimulationNodeDatum[]) + .force( + "link", + d3 + .forceLink(links) + .id((d: any) => d.id) + .distance(200) + .strength(0.2), + ) + .force( + "charge", + d3 + .forceManyBody() + .strength((d: any) => { + // Use a less negative strength for isolated nodes + // to pull them closer to the center + return isolatedNodeIds.has(d.id) ? -500 : -3000; + }) + .distanceMin(20) + .distanceMax(500) + .theta(0.8), + ) + .force("center", d3.forceCenter(width / 2, height / 2).strength(0.05)) + .force( + "collide", + d3.forceCollide().radius(50).strength(0.3).iterations(5), + ) + // Add a special gravity force for isolated nodes to pull them toward the center + .force( + "isolatedGravity", + d3 + .forceRadial( + 100, // distance from center + width / 2, // center x + height / 2, // center y + ) + .strength((d: any) => (isolatedNodeIds.has(d.id) ? 0.15 : 0.01)), + ) + .velocityDecay(0.4) + .alphaDecay(0.05) + .alphaMin(0.001); + + simulationRef.current = simulation; + + const link = g.append("g").selectAll("g").data(links).join("g"); + + // Define reset functions + resetLinksRef.current = () => { + // @ts-ignore + link + .selectAll("path") + .attr("stroke", theme.link.stroke) + .attr("stroke-opacity", 0.6) + .attr("stroke-width", 1); + + // @ts-ignore + link.selectAll(".link-label rect").attr("fill", theme.link.label.bg); + // @ts-ignore + link.selectAll(".link-label text").attr("fill", theme.link.label.text); + }; + + // Create node groups + const node = g + .append("g") + .selectAll("g") + .data(nodes) + .join("g") + // @ts-ignore + .call(drag(simulation)) + .attr("cursor", "pointer"); + + resetNodesRef.current = () => { + // @ts-ignore + node + .selectAll("circle") + .attr("fill", (d: any) => getNodeColor(d)) + .attr("stroke", theme.node.stroke) + .attr("stroke-width", 1); + }; + + // Handle link click + handleLinkClickRef.current = (event: any, d: any, relation: IdValue) => { + if (event.stopPropagation) { + event.stopPropagation(); + } + + if (resetLinksRef.current) resetLinksRef.current(); + if (onEdgeClick) onEdgeClick(relation.id); + + // Reset all elements to default state + // @ts-ignore + link + .selectAll("path") + .attr("stroke", theme.link.stroke) + .attr("stroke-opacity", 0.6) + .attr("stroke-width", 1); + + // Reset non-highlighted nodes to their proper colors + // @ts-ignore + node + .selectAll("circle") + .attr("fill", (d: any) => getNodeColor(d)) + .attr("stroke", theme.node.stroke) + .attr("stroke-width", 1); + + // Find and highlight the corresponding path and label + const linkGroup = event.target?.closest("g") + ? d3.select(event.target.closest("g")) + : link.filter((l: any) => l === d); + + // @ts-ignore + linkGroup + // @ts-ignore + .selectAll("path") + .attr("stroke", theme.link.selected) + .attr("stroke-opacity", 1) + .attr("stroke-width", 2); + + // Update label styling + // @ts-ignore + linkGroup.select(".link-label rect").attr("fill", theme.link.selected); + // @ts-ignore + linkGroup.select(".link-label text").attr("fill", theme.node.text); + + // Highlight connected nodes + // @ts-ignore + node + .selectAll("circle") + .filter((n: any) => n.id === d.source.id || n.id === d.target.id) + .attr("fill", theme.node.selected) + .attr("stroke", theme.node.selected) + .attr("stroke-width", 2); + + const sourceNode = d.source; + const targetNode = d.target; + + // Calculate bounding box for the two connected nodes and the edge + if ( + sourceNode && + targetNode && + sourceNode.x !== undefined && + targetNode.x !== undefined + ) { + const padding = 100; // Increased padding for better view + const minX = Math.min(sourceNode.x, targetNode.x) - padding; + const minY = Math.min(sourceNode.y, targetNode.y) - padding; + const maxX = Math.max(sourceNode.x, targetNode.x) + padding; + const maxY = Math.max(sourceNode.y, targetNode.y) + padding; + + // Calculate transform to fit the connected nodes + const boundWidth = maxX - minX; + const boundHeight = maxY - minY; + const scale = + 0.9 * Math.min(width / boundWidth, height / boundHeight); + const midX = (minX + maxX) / 2; + const midY = (minY + maxY) / 2; + + if ( + isFinite(scale) && + isFinite(midX) && + isFinite(midY) && + zoomRef.current + ) { + const transform = d3.zoomIdentity + .translate(width / 2 - midX * scale, height / 2 - midY * scale) + .scale(scale); + + // Animate transition to new view + // @ts-ignore + svgElement + .transition() + .duration(750) + .ease(d3.easeCubicInOut) // Add easing for smoother transitions + .call(zoomRef.current.transform, transform); + } + } + }; + + // Create links with proper curve paths + link.each(function (d: any) { + const linkGroup = d3.select(this); + const relationCount = d.relations.length; + + // Calculate curve strengths based on number of relations + const baseStrength = 0.2; + const strengthStep = + relationCount > 1 ? baseStrength / (relationCount - 1) : 0; + + d.relations.forEach((relation: string, index: number) => { + const curveStrength = + relationCount > 1 ? -baseStrength + index * strengthStep * 2 : 0; + const fullRelation = d.relationData[index]; + + linkGroup + .append("path") + .attr("stroke", theme.link.stroke) + .attr("stroke-opacity", 0.6) + .attr("stroke-width", 1) + .attr("fill", "none") + .attr("data-curve-strength", curveStrength) + .attr("cursor", "pointer") + .attr( + "data-source", + typeof d.source === "object" ? d.source.id : d.source, + ) + .attr( + "data-target", + typeof d.target === "object" ? d.target.id : d.target, + ) + .on("click", (event) => { + if (handleLinkClickRef.current) { + handleLinkClickRef.current(event, d, fullRelation); + } + }); + + const labelGroup = linkGroup + .append("g") + .attr("class", "link-label") + .attr("cursor", "pointer") + .attr("data-curve-strength", curveStrength) + .on("click", (event) => { + if (handleLinkClickRef.current) { + handleLinkClickRef.current(event, d, fullRelation); + } + }); + + labelGroup + .append("rect") + .attr("fill", theme.link.label.bg) + .attr("rx", 4) + .attr("ry", 4) + .attr("opacity", 0.9); + + labelGroup + .append("text") + .attr("fill", theme.link.label.text) + .attr("font-size", "8px") + .attr("text-anchor", "middle") + .attr("dominant-baseline", "middle") + .attr("pointer-events", "none") + .text(relation); + + labelGroup.attr("data-curve-strength", curveStrength); + }); + }); + + // Create node circles + node + .append("circle") + .attr("r", 10) + .attr("fill", (d: any) => getNodeColor(d)) + .attr("stroke", theme.node.stroke) + .attr("stroke-width", 1) + .attr("filter", "drop-shadow(0 2px 4px rgba(0,0,0,0.2))") + .attr("data-id", (d: any) => d.id) + .attr("cursor", "pointer"); + + // Add node labels + node + .append("text") + .attr("x", 15) + .attr("y", "0.3em") + .attr("text-anchor", "start") + .attr("fill", theme.node.text) + .attr("font-weight", "500") + .attr("font-size", "12px") + .text((d: any) => d.value) + .attr("cursor", "pointer"); + + // Handle node clicks + function handleNodeClick(event: any, d: any) { + event.stopPropagation(); // Ensure the event doesn't bubble up + + if (resetLinksRef.current) resetLinksRef.current(); + if (resetNodesRef.current) resetNodesRef.current(); + + const selectedNodeId = d?.id; + + if (selectedNodeId && onNodeClick) { + onNodeClick(selectedNodeId); + + // Highlight the selected node + // @ts-ignore + node + .selectAll("circle") + .filter((n: any) => n.id === selectedNodeId) + .attr("fill", theme.node.selected) + .attr("stroke", theme.node.selected) + .attr("stroke-width", 2); + + // Find connected nodes and links + const connectedLinks: any[] = []; + const connectedNodes = new Set(); + + // Add the selected node to the connected nodes + const selectedNode = nodes.find((n: any) => n.id === selectedNodeId); + if (selectedNode) { + connectedNodes.add(selectedNode); + } + + // @ts-ignore + link.selectAll("path").each(function () { + const path = d3.select(this); + const source = path.attr("data-source"); + const target = path.attr("data-target"); + + if (source === selectedNodeId || target === selectedNodeId) { + const sourceNode = nodes.find((n: any) => n.id === source); + const targetNode = nodes.find((n: any) => n.id === target); + + if (sourceNode && targetNode) { + connectedLinks.push({ source: sourceNode, target: targetNode }); + connectedNodes.add(sourceNode); + connectedNodes.add(targetNode); + } + } + }); + + // Calculate bounding box of connected nodes + if (connectedNodes.size > 0 && zoomRef.current) { + let minX = Infinity, + minY = Infinity; + let maxX = -Infinity, + maxY = -Infinity; + + connectedNodes.forEach((node: any) => { + if (node.x !== undefined && node.y !== undefined) { + minX = Math.min(minX, node.x); + minY = Math.min(minY, node.y); + maxX = Math.max(maxX, node.x); + maxY = Math.max(maxY, node.y); + } + }); + + // Add padding + const padding = 50; + minX -= padding; + minY -= padding; + maxX += padding; + maxY += padding; + + // Calculate transform to fit connected nodes + const boundWidth = maxX - minX; + const boundHeight = maxY - minY; + const scale = + 0.9 * Math.min(width / boundWidth, height / boundHeight); + const midX = (minX + maxX) / 2; + const midY = (minY + maxY) / 2; + + if (isFinite(scale) && isFinite(midX) && isFinite(midY)) { + const transform = d3.zoomIdentity + .translate(width / 2 - midX * scale, height / 2 - midY * scale) + .scale(scale); + + // Animate transition to new view + // @ts-ignore + svgElement + .transition() + .duration(750) + .ease(d3.easeCubicInOut) // Add easing for smoother transitions + .call(zoomRef.current.transform, transform); + } + } + + // Highlight connected links + // @ts-ignore + link + .selectAll("path") + .attr("stroke", theme.link.stroke) + .attr("stroke-opacity", 0.6) + .attr("stroke-width", 1) + .filter(function () { + const path = d3.select(this); + return ( + path.attr("data-source") === selectedNodeId || + path.attr("data-target") === selectedNodeId + ); + }) + .attr("stroke", themeMode === "dark" ? "#ffffff" : colors.pink[600]) + .attr("stroke-width", 2); + } + } + + // Attach click handler to nodes + node.on("click", handleNodeClick); + + // Store a reference to the current SVG element + const svgRefCurrent = svgRef.current; + + // Add blur handler + svgElement.on("click", function (event) { + // Make sure we only handle clicks directly on the SVG element, not on its children + if (event.target === svgRefCurrent) { + if (onBlur) onBlur(); + if (resetLinksRef.current) resetLinksRef.current(); + if (resetNodesRef.current) resetNodesRef.current(); + } + }); + + // Update positions on simulation tick + simulation.on("tick", () => { + // Update link paths and labels + link.each(function (d: any) { + // Make sure d.source and d.target have x and y properties + if (!d.source.x && typeof d.source === "string") { + const sourceNode = nodes.find((n: any) => n.id === d.source); + // @ts-ignore - Node will have x,y properties from d3 simulation + if (sourceNode && sourceNode.x) { + d.source = sourceNode; + } + } + + if (!d.target.x && typeof d.target === "string") { + const targetNode = nodes.find((n: any) => n.id === d.target); + // @ts-ignore - Node will have x,y properties from d3 simulation + if (targetNode && targetNode.x) { + d.target = targetNode; + } + } + + const linkGroup = d3.select(this); + linkGroup.selectAll("path").each(function () { + const path = d3.select(this); + const curveStrength = +path.attr("data-curve-strength") || 0; + + // Handle self-referencing nodes + if (d.source.id === d.target.id) { + // Create an elliptical path for self-references + const radiusX = 40; + const radiusY = 90; + const offset = radiusY + 20; + + const cx = d.source.x; + const cy = d.source.y - offset; + const path_d = `M${d.source.x},${d.source.y} + C${cx - radiusX},${cy} + ${cx + radiusX},${cy} + ${d.source.x},${d.source.y}`; + path.attr("d", path_d); + + // Position the label + // @ts-ignore + const labelGroup = linkGroup + .selectAll(".link-label") + .filter(function () { + return ( + d3.select(this).attr("data-curve-strength") === + String(curveStrength) + ); + }); + + // Update both the group position and the rectangle/text within it + labelGroup.attr("transform", `translate(${cx}, ${cy - 10})`); + + // Update the rectangle and text positioning + // @ts-ignore + const text = labelGroup.select("text"); + // @ts-ignore + const rect = labelGroup.select("rect"); + const textBBox = (text.node() as SVGTextElement)?.getBBox(); + + if (textBBox) { + rect + .attr("x", -textBBox.width / 2 - 6) + .attr("y", -textBBox.height / 2 - 4) + .attr("width", textBBox.width + 12) + .attr("height", textBBox.height + 8); + + text.attr("x", 0).attr("y", 0); + } + } else { + const dx = d.target.x - d.source.x; + const dy = d.target.y - d.source.y; + const dr = Math.sqrt(dx * dx + dy * dy); + + const midX = (d.source.x + d.target.x) / 2; + const midY = (d.source.y + d.target.y) / 2; + const normalX = -dy / dr; + const normalY = dx / dr; + const curveMagnitude = dr * curveStrength; + const controlX = midX + normalX * curveMagnitude; + const controlY = midY + normalY * curveMagnitude; + + const path_d = `M${d.source.x},${d.source.y} Q${controlX},${controlY} ${d.target.x},${d.target.y}`; + path.attr("d", path_d); + + const pathNode = path.node() as SVGPathElement; + if (pathNode) { + const pathLength = pathNode.getTotalLength(); + const midPoint = pathNode.getPointAtLength(pathLength / 2); + + // @ts-ignore - Intentionally ignoring d3 selection type issues as in the Svelte version + const labelGroup = linkGroup + .selectAll(".link-label") + .filter(function () { + return ( + d3.select(this).attr("data-curve-strength") === + String(curveStrength) + ); + }); + + if (midPoint) { + // @ts-ignore - Intentionally ignoring d3 selection type issues as in the Svelte version + const text = labelGroup.select("text"); + // @ts-ignore - Intentionally ignoring d3 selection type issues as in the Svelte version + const rect = labelGroup.select("rect"); + const textBBox = (text.node() as SVGTextElement)?.getBBox(); + + if (textBBox) { + const angle = + (Math.atan2( + d.target.y - d.source.y, + d.target.x - d.source.x, + ) * + 180) / + Math.PI; + const rotationAngle = + angle > 90 || angle < -90 ? angle - 180 : angle; + + labelGroup.attr( + "transform", + `translate(${midPoint.x}, ${midPoint.y}) rotate(${rotationAngle})`, + ); + + rect + .attr("x", -textBBox.width / 2 - 6) + .attr("y", -textBBox.height / 2 - 4) + .attr("width", textBBox.width + 12) + .attr("height", textBBox.height + 8); + + text.attr("x", 0).attr("y", 0); + } + } + } + } + }); + }); + + // Update node positions + node.attr("transform", (d: any) => `translate(${d.x},${d.y})`); + }); + + // Handle zoom-to-fit on mount + let hasInitialized = false; + + simulation.on("end", () => { + if (hasInitialized || !zoomOnMount || !zoomRef.current) return; + hasInitialized = true; + + const bounds = g.node()?.getBBox(); + if (bounds) { + const fullWidth = width; + const fullHeight = height; + const currentWidth = bounds.width || 1; + const currentHeight = bounds.height || 1; + + // Only proceed if we have valid dimensions + if ( + currentWidth > 0 && + currentHeight > 0 && + fullWidth > 0 && + fullHeight > 0 + ) { + const midX = bounds.x + currentWidth / 2; + const midY = bounds.y + currentHeight / 2; + + // Calculate scale to fit with padding + const scale = + 0.8 * + Math.min(fullWidth / currentWidth, fullHeight / currentHeight); + + // Ensure we have valid numbers before creating transform + if (isFinite(midX) && isFinite(midY) && isFinite(scale)) { + const transform = d3.zoomIdentity + .translate( + fullWidth / 2 - midX * scale, + fullHeight / 2 - midY * scale, + ) + .scale(scale); + + // Smoothly animate to the new transform + // @ts-ignore + svgElement + .transition() + .duration(750) + .ease(d3.easeCubicInOut) // Add easing for smoother transitions + .call(zoomRef.current.transform, transform); + } else { + console.warn("Invalid transform values:", { midX, midY, scale }); + // Fallback to a simple center transform + const transform = d3.zoomIdentity + .translate(fullWidth / 2, fullHeight / 2) + .scale(0.8); + svgElement.call(zoomRef.current.transform, transform); + } + } + } + }); + + // Cleanup function - only called when component unmounts + return () => { + simulation.stop(); + // Save the ref to a variable before using it in cleanup + const currentSvgRef = svgRef.current; + if (currentSvgRef) { + d3.select(currentSvgRef).on("click", null); + } + isInitializedRef.current = false; + }; + // We're keeping the dependency array empty to ensure initialization runs only once on mount + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + + // This effect updates the graph theme colors when the theme changes + useEffect(() => { + // Skip if not initialized + if (!svgRef.current || !isInitializedRef.current) return; + + const svgElement = d3.select(svgRef.current); + + // Update background + svgElement.style("background-color", theme.background); + + // Update nodes - use getNodeColor for proper color assignment + svgElement + .selectAll("circle") + .attr("fill", (d: any) => getNodeColor(d)) + .attr("stroke", theme.node.stroke); + + // Update node labels + // @ts-ignore + svgElement.selectAll("text").attr("fill", theme.node.text); + + // Update links + // @ts-ignore + svgElement + .selectAll("path") + .attr("stroke", theme.link.stroke) + .attr("stroke-opacity", 0.6); + + // Update selected links if any + // @ts-ignore + svgElement + .selectAll("path.selected") + .attr("stroke", theme.link.selected) + .attr("stroke-opacity", 1); + + // Update link labels + // @ts-ignore + svgElement + .selectAll(".link-label rect") + .attr("fill", theme.link.label.bg); + // @ts-ignore + svgElement + .selectAll(".link-label text") + .attr("fill", theme.link.label.text); + + // This effect has many dependencies that would cause frequent re-renders + // We're disabling the exhaustive deps rule to prevent unnecessary re-renders + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [themeMode]); + + return ( + + ); + }, +); diff --git a/apps/webapp/app/components/graph/node-colors.ts b/apps/webapp/app/components/graph/node-colors.ts new file mode 100644 index 0000000..e1f8745 --- /dev/null +++ b/apps/webapp/app/components/graph/node-colors.ts @@ -0,0 +1,84 @@ +import colors from "tailwindcss/colors"; + +// Define a color palette for node coloring +export const nodeColorPalette = { + light: [ + colors.pink[500], // Entity (default) + colors.blue[500], + colors.emerald[500], + colors.amber[500], + colors.indigo[500], + colors.orange[500], + colors.teal[500], + colors.purple[500], + colors.cyan[500], + colors.lime[500], + colors.rose[500], + colors.violet[500], + colors.green[500], + colors.red[500], + ], + dark: [ + colors.pink[400], // Entity (default) + colors.blue[400], + colors.emerald[400], + colors.amber[400], + colors.indigo[400], + colors.orange[400], + colors.teal[400], + colors.purple[400], + colors.cyan[400], + colors.lime[400], + colors.rose[400], + colors.violet[400], + colors.green[400], + colors.red[400], + ], +}; + +// Function to create a map of label to color index +export function createLabelColorMap(labels: string[]) { + // Start with Entity mapped to first color + const result = new Map(); + result.set("Entity", 0); + + // Sort all non-Entity labels alphabetically for consistent color assignment + const sortedLabels = labels + .filter((label) => label !== "Entity") + .sort((a, b) => a.localeCompare(b)); + + // Map each unique label to a color index + let nextIndex = 1; + sortedLabels.forEach((label) => { + if (!result.has(label)) { + result.set(label, nextIndex % nodeColorPalette.light.length); + nextIndex++; + } + }); + + return result; +} + +// Get color for a label directly +export function getNodeColor( + label: string | null | undefined, + isDarkMode: boolean, + labelColorMap: Map, +): string { + if (!label) { + return isDarkMode ? nodeColorPalette.dark[0] : nodeColorPalette.light[0]; + } + + // If label is "Entity" or not found in the map, return default color + if (label === "Entity" || !labelColorMap.has(label)) { + return isDarkMode ? nodeColorPalette.dark[0] : nodeColorPalette.light[0]; + } + + // Get the color index for this label + const colorIndex = labelColorMap.get(label) || 0; + + // Return the color from the appropriate theme palette + return isDarkMode + ? nodeColorPalette.dark[colorIndex] + : nodeColorPalette.light[colorIndex]; +} diff --git a/apps/webapp/app/components/graph/type.ts b/apps/webapp/app/components/graph/type.ts new file mode 100644 index 0000000..98ffdcc --- /dev/null +++ b/apps/webapp/app/components/graph/type.ts @@ -0,0 +1,82 @@ +export interface Node { + uuid: string; + name: string; + summary?: string; + labels?: string[]; + attributes?: Record; + created_at: string; + updated_at: string; +} + +export interface Edge { + uuid: string; + source_node_uuid: string; + target_node_uuid: string; + type: string; + name: string; + fact?: string; + episodes?: string[]; + created_at: string; + updated_at: string; + valid_at?: string; + expired_at?: string; + invalid_at?: string; +} + +export interface RawTriplet { + sourceNode: Node; + edge: Edge; + targetNode: Node; +} + +export interface GraphNode extends Node { + id: string; + value: string; + primaryLabel?: string; +} + +export interface GraphEdge extends Edge { + id: string; + value: string; +} + +export interface GraphTriplet { + source: GraphNode; + relation: GraphEdge; + target: GraphNode; +} + +export interface IdValue { + id: string; + value: string; +} + +// Graph visualization types +export interface GraphNode extends Node { + id: string; + value: string; +} + +export interface GraphEdge extends Edge { + id: string; + value: string; +} + +export interface GraphTriplet { + source: GraphNode; + relation: GraphEdge; + target: GraphNode; +} + +// Popup content types for UI +export interface NodePopupContent { + id: string; + node: Node; +} + +export interface EdgePopupContent { + id: string; + source: Node; + relation: Edge; + target: Node; +} diff --git a/apps/webapp/app/components/layout/LoginPageLayout.tsx b/apps/webapp/app/components/layout/LoginPageLayout.tsx index eb946f1..6462bb1 100644 --- a/apps/webapp/app/components/layout/LoginPageLayout.tsx +++ b/apps/webapp/app/components/layout/LoginPageLayout.tsx @@ -7,9 +7,9 @@ export function LoginPageLayout({ children }: { children: React.ReactNode }) { return (
-
- - +
+ + C.O.R.E
diff --git a/apps/webapp/app/components/logo/logo.tsx b/apps/webapp/app/components/logo/logo.tsx index 95fc0b7..a854395 100644 --- a/apps/webapp/app/components/logo/logo.tsx +++ b/apps/webapp/app/components/logo/logo.tsx @@ -9,59 +9,89 @@ export interface LogoProps { export default function StaticLogo({ width, height }: LogoProps) { const [theme] = useTheme(); - if (theme === Theme.LIGHT) { + if (theme === Theme.DARK) { return ( - - - - - - - - + + + + + + + + + + ); } return ( - - - - - - - - - + + + + + + + + + + ); } diff --git a/apps/webapp/app/components/sidebar/app-sidebar.tsx b/apps/webapp/app/components/sidebar/app-sidebar.tsx new file mode 100644 index 0000000..20aaac2 --- /dev/null +++ b/apps/webapp/app/components/sidebar/app-sidebar.tsx @@ -0,0 +1,70 @@ +import * as React from "react"; + +import { + Sidebar, + SidebarContent, + SidebarFooter, + SidebarHeader, + SidebarMenu, + SidebarMenuButton, + SidebarMenuItem, +} from "../ui/sidebar"; +import { DashboardIcon } from "@radix-ui/react-icons"; +import { Code, LucideFileStack } from "lucide-react"; +import { NavMain } from "./nav-main"; +import { useUser } from "~/hooks/useUser"; +import { NavUser } from "./nav-user"; +import { useWorkspace } from "~/hooks/useWorkspace"; + +const data = { + user: { + name: "shadcn", + email: "m@example.com", + avatar: "/avatars/shadcn.jpg", + }, + navMain: [ + { + title: "Dashboard", + url: "#", + icon: DashboardIcon, + }, + { + title: "API", + url: "#", + icon: Code, + }, + ], +}; + +export function AppSidebar({ ...props }: React.ComponentProps) { + const user = useUser(); + const workspace = useWorkspace(); + + return ( + + + + + + + + {workspace.name} + + + + + + + + + + + + + + + ); +} diff --git a/apps/webapp/app/components/sidebar/nav-main.tsx b/apps/webapp/app/components/sidebar/nav-main.tsx new file mode 100644 index 0000000..f7703ff --- /dev/null +++ b/apps/webapp/app/components/sidebar/nav-main.tsx @@ -0,0 +1,38 @@ +import { useUser } from "~/hooks/useUser"; +import { + SidebarFooter, + SidebarGroup, + SidebarGroupContent, + SidebarMenu, + SidebarMenuButton, + SidebarMenuItem, +} from "../ui/sidebar"; +import { NavUser } from "./nav-user"; + +export const NavMain = ({ + items, +}: { + items: { + title: string; + url: string; + icon?: any; + }[]; +}) => { + return ( + + + + + {items.map((item) => ( + + + {item.icon && } + {item.title} + + + ))} + + + + ); +}; diff --git a/apps/webapp/app/components/sidebar/nav-user.tsx b/apps/webapp/app/components/sidebar/nav-user.tsx new file mode 100644 index 0000000..086cddc --- /dev/null +++ b/apps/webapp/app/components/sidebar/nav-user.tsx @@ -0,0 +1,83 @@ +import { DotIcon, LogOut, User as UserI } from "lucide-react"; +import { Avatar, AvatarFallback, AvatarImage, AvatarText } from "../ui/avatar"; +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuGroup, + DropdownMenuItem, + DropdownMenuLabel, + DropdownMenuSeparator, + DropdownMenuTrigger, +} from "../ui/dropdown-menu"; +import { + SidebarMenu, + SidebarMenuButton, + SidebarMenuItem, + useSidebar, +} from "../ui/sidebar"; +import type { User } from "~/models/user.server"; +import { useUser } from "~/hooks/useUser"; + +export function NavUser({ user }: { user: User }) { + const { isMobile } = useSidebar(); + + return ( + + + + + + +
+ {user.name} + + {user.email} + +
+
+
+ + +
+ + + {user.name} + + +
+ {user.name} + + {user.email} + +
+
+
+ + + + + Account + + + + + + Log out + +
+
+
+
+ ); +} diff --git a/apps/webapp/app/components/ui/avatar.tsx b/apps/webapp/app/components/ui/avatar.tsx new file mode 100644 index 0000000..e08f8b3 --- /dev/null +++ b/apps/webapp/app/components/ui/avatar.tsx @@ -0,0 +1,87 @@ +import * as AvatarPrimitive from "@radix-ui/react-avatar"; +import React from "react"; + +import { getTailwindColor } from "./color-utils"; +import { cn } from "../../lib/utils"; + +const Avatar = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)); +Avatar.displayName = AvatarPrimitive.Root.displayName; + +const AvatarImage = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)); +AvatarImage.displayName = AvatarPrimitive.Image.displayName; + +const AvatarFallback = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)); +AvatarFallback.displayName = AvatarPrimitive.Fallback.displayName; + +// Function to get the first two letters +export const getInitials = (name: string, noOfChar?: number | undefined) => { + if (!name) { + return ""; + } + const words = name.split(" "); + return words + .map((word) => word.charAt(0)) + .filter((char) => char !== "") + .slice(0, noOfChar ? noOfChar : 2) + .join("") + .toUpperCase(); +}; + +const AvatarText = ({ + text, + className, + noOfChar, +}: { + text: string; + className?: string; + noOfChar?: number; +}) => { + return ( + + + + {getInitials(text, noOfChar)} + + + ); +}; + +export { Avatar, AvatarImage, AvatarFallback, AvatarText }; diff --git a/apps/webapp/app/components/ui/button.tsx b/apps/webapp/app/components/ui/button.tsx index 4235f9f..06eeb5e 100644 --- a/apps/webapp/app/components/ui/button.tsx +++ b/apps/webapp/app/components/ui/button.tsx @@ -11,7 +11,8 @@ const buttonVariants = cva( { variants: { variant: { - default: "bg-primary text-white shadow hover:bg-primary/90 dark:hover:bg-primary/90", + default: + "bg-primary text-white shadow hover:bg-primary/90 dark:hover:bg-primary/90", destructive: "text-red-500 bg-grayAlpha-100 border-none", outline: "border border-border shadow-sm hover:bg-gray-100 shadow-none", secondary: "bg-grayAlpha-100 border-none", @@ -37,7 +38,7 @@ const buttonVariants = cva( size: "default", full: false, }, - } + }, ); export interface ButtonProps @@ -62,7 +63,7 @@ const Button = React.forwardRef( disabled, ...props }, - ref + ref, ) => { const Comp = asChild ? Slot : "button"; @@ -70,7 +71,7 @@ const Button = React.forwardRef( ( {children} ); - } + }, ); Button.displayName = "Button"; diff --git a/apps/webapp/app/components/ui/card.tsx b/apps/webapp/app/components/ui/card.tsx new file mode 100644 index 0000000..68b766e --- /dev/null +++ b/apps/webapp/app/components/ui/card.tsx @@ -0,0 +1,80 @@ +import React from "react"; + +import { cn } from "../../lib/utils"; + +const Card = React.forwardRef< + HTMLDivElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +
+)); +Card.displayName = "Card"; + +const CardHeader = React.forwardRef< + HTMLDivElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +
+)); +CardHeader.displayName = "CardHeader"; + +const CardTitle = React.forwardRef< + HTMLParagraphElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +

+)); +CardTitle.displayName = "CardTitle"; + +const CardDescription = React.forwardRef< + HTMLParagraphElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +

+)); +CardDescription.displayName = "CardDescription"; + +const CardContent = React.forwardRef< + HTMLDivElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +

+)); +CardContent.displayName = "CardContent"; + +const CardFooter = React.forwardRef< + HTMLDivElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +
+)); +CardFooter.displayName = "CardFooter"; + +export { + Card, + CardHeader, + CardFooter, + CardTitle, + CardDescription, + CardContent, +}; diff --git a/apps/webapp/app/components/ui/color-utils.ts b/apps/webapp/app/components/ui/color-utils.ts new file mode 100644 index 0000000..df06ff9 --- /dev/null +++ b/apps/webapp/app/components/ui/color-utils.ts @@ -0,0 +1,43 @@ +/** + * Generates an OKLCH color string with fixed lightness, chroma, and a random hue. + * @returns {string} - The generated OKLCH color string. + */ +export function generateOklchColor(): string { + // Generate a random number between 30 and 360 for the hue + const hue = Math.floor(Math.random() * (360 - 30 + 1)) + 30; + + // Fixed lightness and chroma values + const lightness = 66; + const chroma = 0.1835; + + // Construct the OKLCH color string + const oklchColor = `oklch(${lightness}% ${chroma} ${hue})`; + + return oklchColor; +} + +export function getTailwindColor(name: string): string { + // Generate a hash value for the input name + let hash = 0; + for (let i = 0; i < name.length; i++) { + hash = name.charCodeAt(i) + ((hash << 5) - hash); + } + + // Ensure hash value is within the range of colors array + const index = Math.abs(hash) % 12; + + return `var(--custom-color-${index + 1})`; +} + +export function getTeamColor(name: string): string { + // Generate a hash value for the input name + let hash = 0; + for (let i = 0; i < name.length; i++) { + hash = name.charCodeAt(i) + ((hash << 5) - hash); + } + + // Ensure hash value is within the range of colors array + const index = Math.abs(hash) % 3; + + return `var(--team-color-${index + 1})`; +} diff --git a/apps/webapp/app/components/ui/dropdown-menu.tsx b/apps/webapp/app/components/ui/dropdown-menu.tsx new file mode 100644 index 0000000..7a57cbc --- /dev/null +++ b/apps/webapp/app/components/ui/dropdown-menu.tsx @@ -0,0 +1,204 @@ +import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu"; +import { + CheckIcon, + ChevronRightIcon, + DotFilledIcon, +} from "@radix-ui/react-icons"; + +import React from "react"; + +import { cn } from "../../lib/utils"; + +const DropdownMenu = DropdownMenuPrimitive.Root; + +const DropdownMenuTrigger = DropdownMenuPrimitive.Trigger; + +const DropdownMenuGroup = DropdownMenuPrimitive.Group; + +const DropdownMenuPortal = DropdownMenuPrimitive.Portal; + +const DropdownMenuSub = DropdownMenuPrimitive.Sub; + +const DropdownMenuRadioGroup = DropdownMenuPrimitive.RadioGroup; + +const DropdownMenuSubTrigger = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef & { + inset?: boolean; + } +>(({ className, inset, children, ...props }, ref) => ( + + {children} + + +)); +DropdownMenuSubTrigger.displayName = + DropdownMenuPrimitive.SubTrigger.displayName; + +const DropdownMenuSubContent = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)); +DropdownMenuSubContent.displayName = + DropdownMenuPrimitive.SubContent.displayName; + +const DropdownMenuContent = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, sideOffset = 4, ...props }, ref) => ( + + + +)); +DropdownMenuContent.displayName = DropdownMenuPrimitive.Content.displayName; + +const DropdownMenuItem = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef & { + inset?: boolean; + } +>(({ className, inset, ...props }, ref) => ( + +)); +DropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName; + +const DropdownMenuCheckboxItem = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, children, checked, ...props }, ref) => ( + + + + + + + {children} + +)); +DropdownMenuCheckboxItem.displayName = + DropdownMenuPrimitive.CheckboxItem.displayName; + +const DropdownMenuRadioItem = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, children, ...props }, ref) => ( + + + + + + + {children} + +)); +DropdownMenuRadioItem.displayName = DropdownMenuPrimitive.RadioItem.displayName; + +const DropdownMenuLabel = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef & { + inset?: boolean; + } +>(({ className, inset, ...props }, ref) => ( + +)); +DropdownMenuLabel.displayName = DropdownMenuPrimitive.Label.displayName; + +const DropdownMenuSeparator = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)); +DropdownMenuSeparator.displayName = DropdownMenuPrimitive.Separator.displayName; + +const DropdownMenuShortcut = ({ + className, + ...props +}: React.HTMLAttributes) => { + return ( + + ); +}; +DropdownMenuShortcut.displayName = "DropdownMenuShortcut"; + +export { + DropdownMenu, + DropdownMenuTrigger, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuCheckboxItem, + DropdownMenuRadioItem, + DropdownMenuLabel, + DropdownMenuSeparator, + DropdownMenuShortcut, + DropdownMenuGroup, + DropdownMenuPortal, + DropdownMenuSub, + DropdownMenuSubContent, + DropdownMenuSubTrigger, + DropdownMenuRadioGroup, +}; diff --git a/apps/webapp/app/components/ui/input.tsx b/apps/webapp/app/components/ui/input.tsx new file mode 100644 index 0000000..6a891a8 --- /dev/null +++ b/apps/webapp/app/components/ui/input.tsx @@ -0,0 +1,25 @@ +import React from "react"; + +import { cn } from "../../lib/utils"; + +export interface InputProps + extends React.InputHTMLAttributes {} + +const Input = React.forwardRef( + ({ className, type, ...props }, ref) => { + return ( + + ); + }, +); +Input.displayName = "Input"; + +export { Input }; diff --git a/apps/webapp/app/components/ui/multi-select.tsx b/apps/webapp/app/components/ui/multi-select.tsx new file mode 100644 index 0000000..6d1c4ab --- /dev/null +++ b/apps/webapp/app/components/ui/multi-select.tsx @@ -0,0 +1,76 @@ +"use client"; + +import { Button } from "./button"; +import { + DropdownMenu, + DropdownMenuCheckboxItem, + DropdownMenuContent, + DropdownMenuTrigger, +} from "./dropdown-menu"; +import { ChevronDown } from "lucide-react"; +import { type Dispatch, type SetStateAction } from "react"; + +type Option = { label: string; value: string }; + +interface ISelectProps { + placeholder: string; + options: Option[]; + selectedOptions: string[]; + setSelectedOptions: Dispatch>; +} +const MultiSelect = ({ + placeholder, + options: values, + selectedOptions: selectedItems, + setSelectedOptions: setSelectedItems, +}: ISelectProps) => { + const handleSelectChange = (value: string) => { + if (!selectedItems.includes(value)) { + setSelectedItems((prev) => [...prev, value]); + } else { + const referencedArray = [...selectedItems]; + const indexOfItemToBeRemoved = referencedArray.indexOf(value); + referencedArray.splice(indexOfItemToBeRemoved, 1); + setSelectedItems(referencedArray); + } + }; + + const isOptionSelected = (value: string): boolean => { + return selectedItems.includes(value) ? true : false; + }; + + return ( + <> + + + + + e.preventDefault()} + > + {values.map((value: ISelectProps["options"][0], index: number) => { + return ( + e.preventDefault()} + key={index} + checked={isOptionSelected(value.value)} + onCheckedChange={() => handleSelectChange(value.value)} + > + {value.label} + + ); + })} + + + + ); +}; + +export default MultiSelect; diff --git a/apps/webapp/app/components/ui/popover.tsx b/apps/webapp/app/components/ui/popover.tsx new file mode 100644 index 0000000..fc296fa --- /dev/null +++ b/apps/webapp/app/components/ui/popover.tsx @@ -0,0 +1,38 @@ +import * as PopoverPrimitive from "@radix-ui/react-popover"; +import React from "react"; + +import { cn } from "../../lib/utils"; + +const Popover = PopoverPrimitive.Root; + +const PopoverTrigger = PopoverPrimitive.Trigger; + +const PopoverAnchor = PopoverPrimitive.Anchor; +const PopoverPortal = PopoverPrimitive.Portal; + +const PopoverContent = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, align = "center", sideOffset = 4, ...props }, ref) => ( + <> + + +)); +PopoverContent.displayName = PopoverPrimitive.Content.displayName; + +export { + Popover, + PopoverTrigger, + PopoverContent, + PopoverAnchor, + PopoverPortal, +}; diff --git a/apps/webapp/app/components/ui/select.tsx b/apps/webapp/app/components/ui/select.tsx new file mode 100644 index 0000000..0e9dd9d --- /dev/null +++ b/apps/webapp/app/components/ui/select.tsx @@ -0,0 +1,174 @@ +import { + CheckIcon, + ChevronDownIcon, + ChevronUpIcon, +} from "@radix-ui/react-icons"; +import * as SelectPrimitive from "@radix-ui/react-select"; +import React from "react"; + +import { cn } from "../../lib/utils"; +import { ChevronDown } from "lucide-react"; + +const Select = SelectPrimitive.Root; + +const SelectGroup = SelectPrimitive.Group; + +const SelectValue = SelectPrimitive.Value; + +interface SelectTriggerProps + extends React.ComponentPropsWithoutRef { + showIcon: boolean; +} + +const SelectTrigger = React.forwardRef< + React.ElementRef, + SelectTriggerProps +>(({ className, children, showIcon = true, ...props }, ref) => ( + span]:line-clamp-1", + className, + )} + {...props} + > + {children} + {showIcon && ( + + + + )} + +)); +SelectTrigger.displayName = SelectPrimitive.Trigger.displayName; + +const SelectScrollUpButton = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + + + +)); +SelectScrollUpButton.displayName = SelectPrimitive.ScrollUpButton.displayName; + +const SelectScrollDownButton = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + + + +)); +SelectScrollDownButton.displayName = + SelectPrimitive.ScrollDownButton.displayName; + +const SelectContent = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, children, position = "popper", ...props }, ref) => ( + + + + + {children} + + + + +)); +SelectContent.displayName = SelectPrimitive.Content.displayName; + +const SelectLabel = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)); +SelectLabel.displayName = SelectPrimitive.Label.displayName; + +const SelectItem = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, children, ...props }, ref) => ( + + + + + + + + {children} + + +)); +SelectItem.displayName = SelectPrimitive.Item.displayName; + +const SelectSeparator = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)); +SelectSeparator.displayName = SelectPrimitive.Separator.displayName; + +export { + Select, + SelectGroup, + SelectValue, + SelectTrigger, + SelectContent, + SelectLabel, + SelectItem, + SelectSeparator, + SelectScrollUpButton, + SelectScrollDownButton, +}; diff --git a/apps/webapp/app/components/ui/separator.tsx b/apps/webapp/app/components/ui/separator.tsx new file mode 100644 index 0000000..9a3fb96 --- /dev/null +++ b/apps/webapp/app/components/ui/separator.tsx @@ -0,0 +1,29 @@ +import * as SeparatorPrimitive from "@radix-ui/react-separator"; +import React from "react"; + +import { cn } from "../../lib/utils"; + +const Separator = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>( + ( + { className, orientation = "horizontal", decorative = true, ...props }, + ref, + ) => ( + + ), +); +Separator.displayName = SeparatorPrimitive.Root.displayName; + +export { Separator }; diff --git a/apps/webapp/app/components/ui/sheet.tsx b/apps/webapp/app/components/ui/sheet.tsx new file mode 100644 index 0000000..104a951 --- /dev/null +++ b/apps/webapp/app/components/ui/sheet.tsx @@ -0,0 +1,138 @@ +import * as SheetPrimitive from "@radix-ui/react-dialog"; +import { Cross2Icon } from "@radix-ui/react-icons"; +import { cva, type VariantProps } from "class-variance-authority"; +import React from "react"; + +import { cn } from "../../lib/utils"; + +const Sheet = SheetPrimitive.Root; + +const SheetTrigger = SheetPrimitive.Trigger; + +const SheetClose = SheetPrimitive.Close; + +const SheetPortal = SheetPrimitive.Portal; + +const SheetOverlay = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)); +SheetOverlay.displayName = SheetPrimitive.Overlay.displayName; + +const sheetVariants = cva( + "fixed z-50 gap-4 bg-background p-6 shadow-lg transition ease-in-out data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:duration-300 data-[state=open]:duration-500", + { + variants: { + side: { + top: "inset-x-0 top-0 border-b data-[state=closed]:slide-out-to-top data-[state=open]:slide-in-from-top", + bottom: + "inset-x-0 bottom-0 border-t data-[state=closed]:slide-out-to-bottom data-[state=open]:slide-in-from-bottom", + left: "inset-y-0 left-0 h-full w-3/4 border-r data-[state=closed]:slide-out-to-left data-[state=open]:slide-in-from-left sm:max-w-sm", + right: + "inset-y-0 right-0 h-full w-3/4 border-l data-[state=closed]:slide-out-to-right data-[state=open]:slide-in-from-right sm:max-w-sm", + }, + }, + defaultVariants: { + side: "right", + }, + }, +); + +interface SheetContentProps + extends React.ComponentPropsWithoutRef, + VariantProps {} + +const SheetContent = React.forwardRef< + React.ElementRef, + SheetContentProps +>(({ side = "right", className, children, ...props }, ref) => ( + + + + {children} + + + Close + + + +)); +SheetContent.displayName = SheetPrimitive.Content.displayName; + +const SheetHeader = ({ + className, + ...props +}: React.HTMLAttributes) => ( +
+); +SheetHeader.displayName = "SheetHeader"; + +const SheetFooter = ({ + className, + ...props +}: React.HTMLAttributes) => ( +
+); +SheetFooter.displayName = "SheetFooter"; + +const SheetTitle = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)); +SheetTitle.displayName = SheetPrimitive.Title.displayName; + +const SheetDescription = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)); +SheetDescription.displayName = SheetPrimitive.Description.displayName; + +export { + Sheet, + SheetPortal, + SheetOverlay, + SheetTrigger, + SheetClose, + SheetContent, + SheetHeader, + SheetFooter, + SheetTitle, + SheetDescription, +}; diff --git a/apps/webapp/app/components/ui/sidebar.tsx b/apps/webapp/app/components/ui/sidebar.tsx new file mode 100644 index 0000000..d4d62eb --- /dev/null +++ b/apps/webapp/app/components/ui/sidebar.tsx @@ -0,0 +1,724 @@ +import * as React from "react"; +import { Slot } from "@radix-ui/react-slot"; +import { cva, VariantProps } from "class-variance-authority"; +import { PanelLeftIcon } from "lucide-react"; + +import { useIsMobile } from "~/hooks/use-mobile"; +import { cn } from "~/lib/utils"; +import { Button } from "~/components/ui/button"; +import { Input } from "~/components/ui/input"; +import { Separator } from "~/components/ui/separator"; +import { + Sheet, + SheetContent, + SheetDescription, + SheetHeader, + SheetTitle, +} from "~/components/ui/sheet"; +import { Skeleton } from "~/components/ui/skeleton"; +import { + Tooltip, + TooltipContent, + TooltipProvider, + TooltipTrigger, +} from "~/components/ui/tooltip"; + +const SIDEBAR_COOKIE_NAME = "sidebar_state"; +const SIDEBAR_COOKIE_MAX_AGE = 60 * 60 * 24 * 7; +const SIDEBAR_WIDTH = "16rem"; +const SIDEBAR_WIDTH_MOBILE = "18rem"; +const SIDEBAR_WIDTH_ICON = "3rem"; +const SIDEBAR_KEYBOARD_SHORTCUT = "b"; + +type SidebarContextProps = { + state: "expanded" | "collapsed"; + open: boolean; + setOpen: (open: boolean) => void; + openMobile: boolean; + setOpenMobile: (open: boolean) => void; + isMobile: boolean; + toggleSidebar: () => void; +}; + +const SidebarContext = React.createContext(null); + +function useSidebar() { + const context = React.useContext(SidebarContext); + if (!context) { + throw new Error("useSidebar must be used within a SidebarProvider."); + } + + return context; +} + +function SidebarProvider({ + defaultOpen = true, + open: openProp, + onOpenChange: setOpenProp, + className, + style, + children, + ...props +}: React.ComponentProps<"div"> & { + defaultOpen?: boolean; + open?: boolean; + onOpenChange?: (open: boolean) => void; +}) { + const isMobile = useIsMobile(); + const [openMobile, setOpenMobile] = React.useState(false); + + // This is the internal state of the sidebar. + // We use openProp and setOpenProp for control from outside the component. + const [_open, _setOpen] = React.useState(defaultOpen); + const open = openProp ?? _open; + const setOpen = React.useCallback( + (value: boolean | ((value: boolean) => boolean)) => { + const openState = typeof value === "function" ? value(open) : value; + if (setOpenProp) { + setOpenProp(openState); + } else { + _setOpen(openState); + } + + // This sets the cookie to keep the sidebar state. + document.cookie = `${SIDEBAR_COOKIE_NAME}=${openState}; path=/; max-age=${SIDEBAR_COOKIE_MAX_AGE}`; + }, + [setOpenProp, open], + ); + + // Helper to toggle the sidebar. + const toggleSidebar = React.useCallback(() => { + return isMobile ? setOpenMobile((open) => !open) : setOpen((open) => !open); + }, [isMobile, setOpen, setOpenMobile]); + + // Adds a keyboard shortcut to toggle the sidebar. + React.useEffect(() => { + const handleKeyDown = (event: KeyboardEvent) => { + if ( + event.key === SIDEBAR_KEYBOARD_SHORTCUT && + (event.metaKey || event.ctrlKey) + ) { + event.preventDefault(); + toggleSidebar(); + } + }; + + window.addEventListener("keydown", handleKeyDown); + return () => window.removeEventListener("keydown", handleKeyDown); + }, [toggleSidebar]); + + // We add a state so that we can do data-state="expanded" or "collapsed". + // This makes it easier to style the sidebar with Tailwind classes. + const state = open ? "expanded" : "collapsed"; + + const contextValue = React.useMemo( + () => ({ + state, + open, + setOpen, + isMobile, + openMobile, + setOpenMobile, + toggleSidebar, + }), + [state, open, setOpen, isMobile, openMobile, setOpenMobile, toggleSidebar], + ); + + return ( + + +
+ {children} +
+
+
+ ); +} + +function Sidebar({ + side = "left", + variant = "sidebar", + collapsible = "offcanvas", + className, + children, + ...props +}: React.ComponentProps<"div"> & { + side?: "left" | "right"; + variant?: "sidebar" | "floating" | "inset"; + collapsible?: "offcanvas" | "icon" | "none"; +}) { + const { isMobile, state, openMobile, setOpenMobile } = useSidebar(); + + if (collapsible === "none") { + return ( +
+ {children} +
+ ); + } + + if (isMobile) { + return ( + + + + Sidebar + Displays the mobile sidebar. + +
{children}
+
+
+ ); + } + + return ( +
+ {/* This is what handles the sidebar gap on desktop */} +
+ +
+ ); +} + +function SidebarTrigger({ + className, + onClick, + ...props +}: React.ComponentProps) { + const { toggleSidebar } = useSidebar(); + + return ( + + ); +} + +function SidebarRail({ className, ...props }: React.ComponentProps<"button">) { + const { toggleSidebar } = useSidebar(); + + return ( + +
+ + + + + ); +} diff --git a/apps/webapp/app/routes/ingest.tsx b/apps/webapp/app/routes/ingest.tsx index eaf06ea..dba820c 100644 --- a/apps/webapp/app/routes/ingest.tsx +++ b/apps/webapp/app/routes/ingest.tsx @@ -1,10 +1,10 @@ -import { EpisodeType } from "@recall/types"; -import { json } from "@remix-run/node"; +import { EpisodeType } from "@core/types"; +import { json, LoaderFunctionArgs } from "@remix-run/node"; import { z } from "zod"; import { createActionApiRoute } from "~/services/routeBuilders/apiBuilder.server"; import { getUserQueue } from "~/lib/ingest.queue"; import { prisma } from "~/db.server"; -import { IngestionStatus } from "@recall/database"; +import { IngestionStatus } from "@core/database"; export const IngestBodyRequest = z.object({ name: z.string(), diff --git a/apps/webapp/app/routes/login.tsx b/apps/webapp/app/routes/login.tsx index f4ed066..a622d57 100644 --- a/apps/webapp/app/routes/login.tsx +++ b/apps/webapp/app/routes/login.tsx @@ -1,10 +1,8 @@ import { type LoaderFunctionArgs } from "@remix-run/node"; -import { Form } from "@remix-run/react"; + import { redirect, typedjson, useTypedLoaderData } from "remix-typedjson"; import { LoginPageLayout } from "~/components/layout/LoginPageLayout"; import { Fieldset } from "~/components/ui/Fieldset"; -import { Header1 } from "~/components/ui/Headers"; -import { Paragraph } from "~/components/ui/Paragraph"; import { isGoogleAuthSupported } from "~/services/auth.server"; import { setRedirectTo } from "~/services/redirectTo.server"; import { getUserId } from "~/services/session.server"; @@ -12,6 +10,14 @@ import { commitSession } from "~/services/sessionStorage.server"; import { requestUrl } from "~/utils/requestUrl.server"; import { RiGoogleLine } from "@remixicon/react"; +import { + Card, + CardContent, + CardDescription, + CardHeader, + CardTitle, +} from "~/components/ui/card"; +import { Button } from "~/components/ui"; export async function loader({ request }: LoaderFunctionArgs) { const userId = await getUserId(request); @@ -43,29 +49,33 @@ export default function LoginPage() { const data = useTypedLoaderData(); return ( -
-
- - Welcome - - - Create an account or login - -
-
- {data.showGoogleAuth && ( - - )} -
-
-
-
+ + + + Login to your account + Create an account or login + + + +
+
+ {data.showGoogleAuth && ( + + )} +
+
+
+
+
); } diff --git a/apps/webapp/app/routes/logout.tsx b/apps/webapp/app/routes/logout.tsx new file mode 100644 index 0000000..48af79f --- /dev/null +++ b/apps/webapp/app/routes/logout.tsx @@ -0,0 +1,18 @@ +import { type ActionFunction, type LoaderFunction } from "@remix-run/node"; +import { redirect } from "remix-typedjson"; + +import { sessionStorage } from "~/services/sessionStorage.server"; + +export const action: ActionFunction = async ({ request }) => { + let session = await sessionStorage.getSession(request.headers.get("cookie")); + return redirect("/login", { + headers: { "Set-Cookie": await sessionStorage.destroySession(session) }, + }); +}; + +export const loader: LoaderFunction = async ({ request }) => { + let session = await sessionStorage.getSession(request.headers.get("cookie")); + return redirect("/login", { + headers: { "Set-Cookie": await sessionStorage.destroySession(session) }, + }); +}; diff --git a/apps/webapp/app/services/graphModels/entity.ts b/apps/webapp/app/services/graphModels/entity.ts index 0fc3b8f..975b2f8 100644 --- a/apps/webapp/app/services/graphModels/entity.ts +++ b/apps/webapp/app/services/graphModels/entity.ts @@ -1,4 +1,4 @@ -import type { EntityNode } from "@recall/types"; +import type { EntityNode } from "@core/types"; import { runQuery } from "~/lib/neo4j.server"; export async function saveEntity(entity: EntityNode): Promise { diff --git a/apps/webapp/app/services/graphModels/episode.ts b/apps/webapp/app/services/graphModels/episode.ts index b6f8da3..6ec7464 100644 --- a/apps/webapp/app/services/graphModels/episode.ts +++ b/apps/webapp/app/services/graphModels/episode.ts @@ -1,5 +1,5 @@ import { runQuery } from "~/lib/neo4j.server"; -import type { EpisodicNode } from "@recall/types"; +import type { EpisodicNode } from "@core/types"; export async function saveEpisode(episode: EpisodicNode): Promise { const query = ` diff --git a/apps/webapp/app/services/graphModels/statement.ts b/apps/webapp/app/services/graphModels/statement.ts index fb20f2e..b982ebc 100644 --- a/apps/webapp/app/services/graphModels/statement.ts +++ b/apps/webapp/app/services/graphModels/statement.ts @@ -3,7 +3,7 @@ import type { EpisodicNode, StatementNode, Triple, -} from "@recall/types"; +} from "@core/types"; import { runQuery } from "~/lib/neo4j.server"; import { saveEntity } from "./entity"; import { saveEpisode } from "./episode"; diff --git a/apps/webapp/app/services/knowledgeGraph.server.ts b/apps/webapp/app/services/knowledgeGraph.server.ts index 58acce4..8ccc586 100644 --- a/apps/webapp/app/services/knowledgeGraph.server.ts +++ b/apps/webapp/app/services/knowledgeGraph.server.ts @@ -9,7 +9,7 @@ import { type EpisodicNode, type StatementNode, type Triple, -} from "@recall/types"; +} from "@core/types"; import { logger } from "./logger.service"; import crypto from "crypto"; import { dedupeNodes, extractMessage, extractText } from "./prompts/nodes"; diff --git a/apps/webapp/app/services/personalAccessToken.server.ts b/apps/webapp/app/services/personalAccessToken.server.ts index fb054cd..21d6174 100644 --- a/apps/webapp/app/services/personalAccessToken.server.ts +++ b/apps/webapp/app/services/personalAccessToken.server.ts @@ -1,4 +1,4 @@ -import { type PersonalAccessToken } from "@recall/database"; +import { type PersonalAccessToken } from "@core/database"; import { customAlphabet, nanoid } from "nanoid"; import nodeCrypto from "node:crypto"; import { z } from "zod"; diff --git a/apps/webapp/app/services/prompts/statements.ts b/apps/webapp/app/services/prompts/statements.ts index 1101c88..a03054e 100644 --- a/apps/webapp/app/services/prompts/statements.ts +++ b/apps/webapp/app/services/prompts/statements.ts @@ -1,4 +1,4 @@ -import { type Triple } from "@recall/types"; +import { type Triple } from "@core/types"; import { type CoreMessage } from "ai"; /** diff --git a/apps/webapp/app/services/session.server.ts b/apps/webapp/app/services/session.server.ts index b841be4..309c2c9 100644 --- a/apps/webapp/app/services/session.server.ts +++ b/apps/webapp/app/services/session.server.ts @@ -2,6 +2,7 @@ import { redirect } from "@remix-run/node"; import { getUserById } from "~/models/user.server"; import { sessionStorage } from "./sessionStorage.server"; import { getImpersonationId } from "./impersonation.server"; +import { getWorkspaceByUser } from "~/models/workspace.server"; export async function getUserId(request: Request): Promise { const impersonatedUserId = await getImpersonationId(request); @@ -24,6 +25,46 @@ export async function getUser(request: Request) { throw await logout(request); } +export async function requireUserId(request: Request, redirectTo?: string) { + const userId = await getUserId(request); + if (!userId) { + const url = new URL(request.url); + const searchParams = new URLSearchParams([ + ["redirectTo", redirectTo ?? `${url.pathname}${url.search}`], + ]); + throw redirect(`/login?${searchParams}`); + } + return userId; +} + +export async function requireUser(request: Request) { + const userId = await requireUserId(request); + + const impersonationId = await getImpersonationId(request); + const user = await getUserById(userId); + if (user) { + return { + id: user.id, + email: user.email, + name: user.name, + displayName: user.displayName, + avatarUrl: user.avatarUrl, + admin: user.admin, + createdAt: user.createdAt, + updatedAt: user.updatedAt, + confirmedBasicDetails: user.confirmedBasicDetails, + isImpersonating: !!impersonationId, + }; + } + + throw await logout(request); +} + +export async function requireWorkpace(request: Request) { + const userId = await requireUserId(request); + return getWorkspaceByUser(userId); +} + export async function logout(request: Request) { return redirect("/logout"); } diff --git a/apps/webapp/app/tailwind.css b/apps/webapp/app/tailwind.css index 605af84..ec7189e 100644 --- a/apps/webapp/app/tailwind.css +++ b/apps/webapp/app/tailwind.css @@ -3,6 +3,7 @@ @import "tailwindcss"; +@custom-variant dark (&:is(.dark *)); :root { --background: oklch(91.28% 0 0); @@ -30,6 +31,14 @@ --input: oklch(0% 0 0 / 6.27%); --ring: 221.2 83.2% 53.3%; --radius: 8px; + --sidebar: hsl(0 0% 98%); + --sidebar-foreground: hsl(240 5.3% 26.1%); + --sidebar-primary: hsl(240 5.9% 10%); + --sidebar-primary-foreground: hsl(0 0% 98%); + --sidebar-accent: hsl(240 4.8% 95.9%); + --sidebar-accent-foreground: hsl(240 5.9% 10%); + --sidebar-border: hsl(220 13% 91%); + --sidebar-ring: hsl(217.2 91.2% 59.8%); } .dark, @@ -60,7 +69,261 @@ --ring: 221.2 83.2% 53.3%; } +:root { + --gray-50: #f9f9f9; + --gray-100: #efefef; + --gray-200: #e8e8e8; + --gray-300: #e0e0e0; + --gray-400: #cecece; + --gray-500: #d8d8d8; + --gray-600: #bbbbbb; + --gray-700: #8d8d8d; + --gray-800: #838383; + --gray-900: #646464; + --gray-950: #202020; + + --grayAlpha-50: 0% 0 0 / 2.35%; + --grayAlpha-100: 0% 0 0 / 6.27%; + --grayAlpha-200: 0% 0 0 / 9.02%; + --grayAlpha-300: 0% 0 0 / 12.16%; + --grayAlpha-400: 0% 0 0 / 15.29%; + --grayAlpha-500: 0% 0 0 / 19.22%; + --grayAlpha-600: 0% 0 0 / 26.67%; + --grayAlpha-700: 0% 0 0 / 44.71%; + --grayAlpha-800: 0% 0 0 / 48.63%; + --grayAlpha-900: 0% 0 0 / 60.78%; + --grayAlpha-950: 0% 0 0 / 87.45%; + + /* Colors for different status */ + --status-pill-0: #d94b0e26; + --status-icon-0: #d94b0e; + + --status-pill-1: #9f3def26; + --status-icon-1: #9f3def; + + --status-pill-2: #8e862c26; + --status-icon-2: #8e862c; + + --status-pill-3: #5c5c5c26; + --status-icon-3: #5c5c5c; + + --status-pill-4: #c28c1126; + --status-icon-4: #c28c11; + + --status-pill-5: #3f8ef726; + --status-icon-5: #3f8ef7; + + --status-pill-6: #3caf2026; + --status-icon-6: #3caf20; + + /* Avatar colors */ + --custom-color-1: #b56455; + --custom-color-2: #7b8a34; + --custom-color-3: #1c91a8; + --custom-color-4: #886dbc; + --custom-color-5: #ad6e30; + --custom-color-6: #54935b; + --custom-color-7: #4187c0; + --custom-color-8: #a165a1; + --custom-color-9: #997d1d; + --custom-color-10: #2b9684; + --custom-color-11: #2b9684; + --custom-color-12: #b0617c; + + /* Team Colors */ + --team-color-1: #89c794; + --team-color-2: #d2a1bb; + --team-color-3: #90c5d6; +} + +.dark { + --gray-50: #191919; + --gray-100: #222222; + --gray-200: #2a2a2a; + --gray-300: #313131; + --gray-400: #3a3a3a; + --gray-500: #484848; + --gray-600: #606060; + --gray-700: #6e6e6e; + --gray-800: #7b7b7b; + --gray-900: #b4b4b4; + --gray-950: #eeeeee; + + --grayAlpha-50: 100% 0 0 / 3.53%; + --grayAlpha-100: 100% 0 0 / 7.06%; + --grayAlpha-200: 100% 0 0 / 10.59%; + --grayAlpha-300: 100% 0 0 / 13.33%; + --grayAlpha-400: 100% 0 0 / 17.25%; + --grayAlpha-500: 100% 0 0 / 23.14%; + --grayAlpha-600: 100% 0 0 / 33.33%; + --grayAlpha-700: 100% 0 0 / 39.22%; + --grayAlpha-800: 100% 0 0 / 44.31%; + --grayAlpha-900: 100% 0 0 / 68.63%; + --grayAlpha-950: 100% 0 0 / 92.94%; + + /* Colors for different status */ + --status-pill-0: #c06142; + --status-icon-0: #c06142; + + --status-pill-1: #886dbc; + --status-icon-1: #886dbc; + + --status-pill-2: #83872c; + --status-icon-2: #83872c; + + --status-pill-3: #b4b4b4; + --status-icon-3: #5c5c5c; + + --status-pill-4: #c28c11; + --status-icon-4: #c28c11; + + --status-pill-5: #4187c0; + --status-icon-5: #4187c0; + + --status-pill-6: #5d9151; + --status-icon-6: #5d9151; + + /* Team Colors */ + --team-color-1: #54935b; + --team-color-2: #a165a1; + --team-color-3: #4187c0; + --sidebar: hsl(240 5.9% 10%); + --sidebar-foreground: hsl(240 4.8% 95.9%); + --sidebar-primary: hsl(224.3 76.3% 48%); + --sidebar-primary-foreground: hsl(0 0% 100%); + --sidebar-accent: hsl(240 3.7% 15.9%); + --sidebar-accent-foreground: hsl(240 4.8% 95.9%); + --sidebar-border: hsl(240 3.7% 15.9%); + --sidebar-ring: hsl(217.2 91.2% 59.8%); +} + @theme inline { --color-background: var(--background); --color-foreground: var(--foreground); + + --color-border: var(--border); + --color-border-dark: var(--border-dark); + --color-input: var(--input); + --color-ring: var(--ring); + --color-background-2: var(--background-2); + --color-background-3: var(--background-3); + --color-primary: var(--primary); + --color-primary-foreground: var(--primary-foreground); + --color-secondary: var(--secondary); + --color-secondary-foreground: var(--secondary-foreground); + --color-destructive: var(--destructive); + --color-destructive-foreground: var(--destructive-foreground); + --color-warning: var(--warning); + --color-warning-foreground: var(--warning-foreground); + --color-success: var(--success); + --color-success-foreground: var(--success-foreground); + --color-muted: var(--muted); + --color-muted-foreground: var(--muted-foreground); + --color-accent: var(--accent); + --color-accent-foreground: var(--accent-foreground); + --color-popover: var(--popover); + --color-popover-foreground: var(--popover-foreground); + + --color-gray-50: var(--gray-50); + --color-gray-100: var(--gray-100); + --color-gray-200: var(--gray-200); + --color-gray-300: var(--gray-300); + --color-gray-400: var(--gray-400); + --color-gray-500: var(--gray-500); + --color-gray-600: var(--gray-600); + --color-gray-700: var(--gray-700); + --color-gray-800: var(--gray-800); + --color-gray-900: var(--gray-900); + --color-gray-950: var(--gray-950); + + --color-grayAlpha-50: oklch(var(--grayAlpha-50)); + --color-grayAlpha-100: oklch(var(--grayAlpha-100)); + --color-grayAlpha-200: oklch(var(--grayAlpha-200)); + --color-grayAlpha-300: oklch(var(--grayAlpha-300)); + --color-grayAlpha-400: oklch(var(--grayAlpha-400)); + --color-grayAlpha-500: oklch(var(--grayAlpha-500)); + --color-grayAlpha-600: oklch(var(--grayAlpha-600)); + --color-grayAlpha-700: oklch(var(--grayAlpha-700)); + --color-grayAlpha-800: oklch(var(--grayAlpha-800)); + --color-grayAlpha-900: oklch(var(--grayAlpha-900)); + --color-grayAlpha-950: oklch(var(--grayAlpha-950)); + + --color-red-50: #fdf3f3; + --color-red-100: #fbe9e8; + --color-red-200: #f7d4d4; + --color-red-300: #f0b1b1; + --color-red-400: #e78587; + --color-red-500: #d75056; + --color-red-600: #c43a46; + --color-red-700: #a52b3a; + --color-red-800: #8a2735; + --color-red-900: #772433; + --color-red-950: #420f18; + + --color-orange-50: #fdf6ef; + --color-orange-100: #fbead9; + --color-orange-200: #f7d2b1; + --color-orange-300: #f1b480; + --color-orange-400: #ea8c4d; + --color-orange-500: #e67333; + --color-orange-600: #d65520; + --color-orange-700: #b2401c; + --color-orange-800: #8e341e; + --color-orange-900: #732d1b; + --color-orange-950: #3e140c; + + --color-yellow-50: #fdfbe9; + --color-yellow-100: #faf7c7; + --color-yellow-200: #f7ec91; + --color-yellow-300: #f1db53; + --color-yellow-400: #ebc724; + --color-yellow-500: #dcb016; + --color-yellow-600: #c28c11; + --color-yellow-700: #976211; + --color-yellow-800: #7d4f16; + --color-yellow-900: #6b4118; + --color-yellow-950: #3e220a; + + --text-xs: 12px; + --text-sm: 13px; + --text-base: 14px; + --text-md: 15px; + --text-lg: 17px; + --text-xl: 22px; + --text-2xl: 26px; + + --radius-none: 0px; + --radius: 0.375rem; + --radius-sm: 0.125rem; + --radius-md: 0.375rem; + --radius-lg: 0.5rem; + --radius-xl: 0.75rem; + --radius-2xl: 1rem; + --radius-3xl: 1.5rem; + --radius-4xl: 2rem; + --radius-5xl: 3rem; + --radius-full: 9999px; + + --shadow: 0px 6px 20px 0px rgba(0, 0, 0, 0.15), 0px 0px 2px 0px rgba(0, 0, 0, 0.2); + --shadow-1: 0px 6px 20px 0px rgba(0, 0, 0, 0.15), 0px 0px 2px 0px rgba(0, 0, 0, 0.2); + + --font-sans: "Geist Variable", "Helvetica Neue", "Helvetica", "Arial", sans-serif; + --font-mono: "Geist Mono Variable", monaco, Consolas, "Lucida Console", monospace; + --color-sidebar-ring: var(--sidebar-ring); + --color-sidebar-border: var(--sidebar-border); + --color-sidebar-accent-foreground: var(--sidebar-accent-foreground); + --color-sidebar-accent: var(--sidebar-accent); + --color-sidebar-primary-foreground: var(--sidebar-primary-foreground); + --color-sidebar-primary: var(--sidebar-primary); + --color-sidebar-foreground: var(--sidebar-foreground); + --color-sidebar: var(--sidebar); +} + +@layer base { + * { + @apply border-border outline-ring/50; + } + body { + @apply bg-background text-foreground; + } } \ No newline at end of file diff --git a/apps/webapp/app/utils/pathBuilder.ts b/apps/webapp/app/utils/pathBuilder.ts new file mode 100644 index 0000000..23f0ffb --- /dev/null +++ b/apps/webapp/app/utils/pathBuilder.ts @@ -0,0 +1,7 @@ +export function confirmBasicDetailsPath() { + return `/confirm-basic-details`; +} + +export function rootPath() { + return `/`; +} diff --git a/apps/webapp/app/utils/presets/apps.ts b/apps/webapp/app/utils/presets/apps.ts new file mode 100644 index 0000000..2be8912 --- /dev/null +++ b/apps/webapp/app/utils/presets/apps.ts @@ -0,0 +1,100 @@ +export enum Apps { + LINEAR = "LINEAR", + SLACK = "SLACK", +} + +export const AppNames = { + [Apps.LINEAR]: "Linear", + [Apps.SLACK]: "Slack", +} as const; + +// General node types that are common across all apps +export const GENERAL_NODE_TYPES = { + PERSON: { + name: "Person", + description: "Represents an individual, like a team member or contact", + }, + APP: { + name: "App", + description: "A software application or service that's integrated", + }, + PLACE: { + name: "Place", + description: "A physical location like an office, meeting room, or city", + }, + ORGANIZATION: { + name: "Organization", + description: "A company, team, or any formal group of people", + }, + EVENT: { + name: "Event", + description: "A meeting, deadline, or any time-based occurrence", + }, +} as const; + +// App-specific node types +export const APP_NODE_TYPES = { + [Apps.LINEAR]: { + ISSUE: { + name: "Linear Issue", + description: "A task, bug report, or feature request tracked in Linear", + }, + PROJECT: { + name: "Linear Project", + description: "A collection of related issues and work items in Linear", + }, + CYCLE: { + name: "Linear Cycle", + description: "A time-boxed iteration of work in Linear", + }, + TEAM: { + name: "Linear Team", + description: "A group of people working together in Linear", + }, + LABEL: { + name: "Linear Label", + description: "A tag used to categorize and organize issues in Linear", + }, + }, + [Apps.SLACK]: { + CHANNEL: { + name: "Slack Channel", + description: "A dedicated space for team communication in Slack", + }, + THREAD: { + name: "Slack Thread", + description: "A focused conversation branch within a Slack channel", + }, + MESSAGE: { + name: "Slack Message", + description: "A single communication sent in a Slack channel or thread", + }, + REACTION: { + name: "Slack Reaction", + description: "An emoji response to a message in Slack", + }, + FILE: { + name: "Slack File", + description: "A document, image or other file shared in Slack", + }, + }, +} as const; + +/** + * Returns both general node types and app-specific node types for given apps + * @param apps Array of app names to get node types for + * @returns Object containing general and app-specific node types + */ +export function getNodeTypes(apps: Array) { + const appSpecificTypes = apps.reduce((acc, appName) => { + return { + ...acc, + [appName]: APP_NODE_TYPES[appName], + }; + }, {}); + + return { + general: GENERAL_NODE_TYPES, + appSpecific: appSpecificTypes, + }; +} diff --git a/apps/webapp/app/utils/singleton.ts b/apps/webapp/app/utils/singleton.ts index 9b28165..4d49eb8 100644 --- a/apps/webapp/app/utils/singleton.ts +++ b/apps/webapp/app/utils/singleton.ts @@ -1,6 +1,6 @@ export function singleton(name: string, getValue: () => T): T { const thusly = globalThis as any; - thusly.__recall_singletons ??= {}; - thusly.__recall_singletons[name] ??= getValue(); - return thusly.__recall_singletons[name]; + thusly.__core_singletons ??= {}; + thusly.__core_singletons[name] ??= getValue(); + return thusly.__core_singletons[name]; } diff --git a/apps/webapp/package.json b/apps/webapp/package.json index 363b8a4..ad61b1d 100644 --- a/apps/webapp/package.json +++ b/apps/webapp/package.json @@ -13,10 +13,29 @@ "dependencies": { "@ai-sdk/openai": "^1.3.21", "@coji/remix-auth-google": "^4.2.0", + "@conform-to/react": "^0.6.1", + "@conform-to/zod": "^0.6.1", + "@core/database": "workspace:*", + "@core/types": "workspace:*", "@opentelemetry/api": "1.9.0", + "@radix-ui/react-accordion": "^1.1.2", + "@radix-ui/react-alert-dialog": "^1.0.5", + "@radix-ui/react-avatar": "^1.0.4", + "@radix-ui/react-checkbox": "^1.0.4", + "@radix-ui/react-collapsible": "^1.0.3", + "@radix-ui/react-dialog": "^1.1.14", + "@radix-ui/react-dropdown-menu": "^2.0.6", + "@radix-ui/react-icons": "^1.3.0", + "@radix-ui/react-label": "^2.0.2", + "@radix-ui/react-popover": "^1.0.7", + "@radix-ui/react-scroll-area": "^1.0.5", + "@radix-ui/react-select": "^2.0.0", + "@radix-ui/react-separator": "^1.1.7", "@radix-ui/react-slot": "^1.2.3", - "@recall/database": "workspace:*", - "@recall/types": "workspace:*", + "@radix-ui/react-switch": "^1.0.3", + "@radix-ui/react-tabs": "^1.0.4", + "@radix-ui/react-toast": "^1.1.5", + "@radix-ui/react-tooltip": "^1.2.7", "@remix-run/express": "2.16.7", "@remix-run/node": "2.1.0", "@remix-run/react": "2.16.7", @@ -33,6 +52,9 @@ "clsx": "^2.1.1", "compression": "^1.7.4", "cross-env": "^7.0.3", + "d3": "^7.9.0", + "dayjs": "^1.11.10", + "express": "^4.18.1", "ioredis": "^5.6.1", "isbot": "^4.1.0", @@ -67,6 +89,7 @@ "@tailwindcss/typography": "^0.5.16", "@tailwindcss/vite": "^4.1.7", "@types/compression": "^1.7.2", + "@types/d3": "^7.4.3", "@types/express": "^4.17.13", "@types/morgan": "^1.9.3", "@types/react": "^18.2.20", diff --git a/apps/webapp/public/favicon.ico b/apps/webapp/public/favicon.ico index 8830cf6821b354114848e6354889b8ecf6d2bc61..87c813a85fc8184522c4df560e2621e093cb72f2 100644 GIT binary patch literal 10246 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 EKbET!0{{R3 diff --git a/apps/webapp/public/logo-dark.png b/apps/webapp/public/logo-dark.png index b24c7aee3a86dad7eb334ba6fba94e5b18b84215..f282d0292115d75f5938121bcfe47b3ec905eef1 100644 GIT binary patch literal 7951 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 literal 80332 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 BAPKNXC&B9%2=3YBbo!Y+L4D-GS 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�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 + + + + + + + + + + + diff --git a/apps/webapp/public/logo-light.png b/apps/webapp/public/logo-light.png index 4490ae7930752afa15329f66e3a2dfef7de2418a..3caf6028371841c25837cc8900c37a37ac16051c 100644 GIT binary patch literal 60010 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

    &NPV;! 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 F{{et{IHv#r diff --git a/apps/webapp/public/logo-light.svg b/apps/webapp/public/logo-light.svg new file mode 100644 index 0000000..cdac18b --- /dev/null +++ b/apps/webapp/public/logo-light.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/apps/webapp/tailwind.config.ts b/apps/webapp/tailwind.config.ts index fee4ac5..cee353c 100644 --- a/apps/webapp/tailwind.config.ts +++ b/apps/webapp/tailwind.config.ts @@ -27,134 +27,6 @@ export default { "monospace", ], }, - borderRadius: { - lg: "var(--radius)", - md: "calc(var(--radius) - 2px)", - sm: "calc(var(--radius) - 4px)", - }, - colors: { - border: { - DEFAULT: "oklch(var(--border))", - dark: "oklch(var(--border-dark))", - }, - input: "oklch(var(--input))", - ring: "oklch(var(--ring))", - background: { - 2: "oklch(var(--background-2) / )", - 3: "oklch(var(--background-3) / )", - DEFAULT: "oklch(var(--background) / )", - }, - foreground: "oklch(var(--foreground) / )", - primary: { - DEFAULT: "oklch(var(--primary) / )", - foreground: "oklch(var(--primary-foreground) / )", - }, - secondary: { - DEFAULT: "hsl(var(--secondary))", - foreground: "hsl(var(--secondary-foreground))", - }, - destructive: { - DEFAULT: "oklch(var(--destructive) / )", - foreground: "oklch(var(--destructive-foreground) / )", - }, - warning: { - DEFAULT: "oklch(var(--warning) / )", - foreground: "oklch(var(--warning-foreground) / )", - }, - success: { - DEFAULT: "oklch(var(--success) / )", - foreground: "oklch(var(--success-foreground) / )", - }, - muted: { - DEFAULT: "oklch(var(--muted))", - foreground: "oklch(var(--muted-foreground) / )", - }, - accent: { - DEFAULT: "oklch(var(--accent) / )", - foreground: "oklch(var(--accent-foreground) / )", - }, - popover: { - DEFAULT: "oklch(var(--popover) / )", - foreground: "oklch(var(--popover-foreground) / )", - }, - gray: { - 50: "var(--gray-50)", - 100: "var(--gray-100)", - 200: "var(--gray-200)", - 300: "var(--gray-300)", - 400: "var(--gray-400)", - 500: "var(--gray-500)", - 600: "var(--gray-600)", - 700: "var(--gray-700)", - 800: "var(--gray-800)", - 900: "var(--gray-900)", - 950: "var(--gray-950)", - }, - grayAlpha: { - 50: "oklch(var(--grayAlpha-50))", - 100: "oklch(var(--grayAlpha-100))", - 200: "oklch(var(--grayAlpha-200))", - 300: "oklch(var(--grayAlpha-300))", - 400: "oklch(var(--grayAlpha-400))", - 500: "oklch(var(--grayAlpha-500))", - 600: "oklch(var(--grayAlpha-600))", - 700: "oklch(var(--grayAlpha-700))", - 800: "oklch(var(--grayAlpha-800))", - 900: "oklch(var(--grayAlpha-900))", - 950: "oklch(var(--grayAlpha-950))", - }, - red: { - 50: "#fdf3f3", - 100: "#fbe9e8", - 200: "#f7d4d4", - 300: "#f0b1b1", - 400: "#e78587", - 500: "#d75056", - 600: "#c43a46", - 700: "#a52b3a", - 800: "#8a2735", - 900: "#772433", - 950: "#420f18", - }, - orange: { - 50: "#fdf6ef", - 100: "#fbead9", - 200: "#f7d2b1", - 300: "#f1b480", - 400: "#ea8c4d", - 500: "#e67333", - 600: "#d65520", - 700: "#b2401c", - 800: "#8e341e", - 900: "#732d1b", - 950: "#3e140c", - }, - yellow: { - 50: "#fdfbe9", - 100: "#faf7c7", - 200: "#f7ec91", - 300: "#f1db53", - 400: "#ebc724", - 500: "#dcb016", - 600: "#c28c11", - 700: "#976211", - 800: "#7d4f16", - 900: "#6b4118", - 950: "#3e220a", - }, - sidebar: { - DEFAULT: "oklch(var(--background-2) / )", - foreground: "oklch(var(--foreground) / )", - primary: "oklch(var(--primary) / )", - "primary-foreground": - "oklch(var(--primary-foreground) / )", - accent: "oklch(var(--accent) / )", - "accent-foreground": - "oklch(var(--accent-foreground) / )", - border: "oklch(var(--border))", - ring: "oklch(var(--ring))", - }, - }, }, }, plugins: [ diff --git a/package.json b/package.json index 1eedf2c..21789f0 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { - "name": "recall", + "name": "core", "private": true, "workspaces": [ "apps/*", "packages/*" ] diff --git a/packages/database/package.json b/packages/database/package.json index af2516f..832878d 100644 --- a/packages/database/package.json +++ b/packages/database/package.json @@ -1,5 +1,5 @@ { - "name": "@recall/database", + "name": "@core/database", "private": true, "version": "0.0.1", "main": "./dist/index.js", diff --git a/packages/database/prisma/migrations/20250605181456_add_integrations/migration.sql b/packages/database/prisma/migrations/20250605181456_add_integrations/migration.sql new file mode 100644 index 0000000..103cfe6 --- /dev/null +++ b/packages/database/prisma/migrations/20250605181456_add_integrations/migration.sql @@ -0,0 +1,2 @@ +-- AlterTable +ALTER TABLE "Workspace" ADD COLUMN "integrations" TEXT[]; diff --git a/packages/database/prisma/schema.prisma b/packages/database/prisma/schema.prisma index 9a3f085..513ccd1 100644 --- a/packages/database/prisma/schema.prisma +++ b/packages/database/prisma/schema.prisma @@ -52,6 +52,8 @@ model Workspace { slug String @unique icon String? + integrations String[] + userId String? @unique user User? @relation(fields: [userId], references: [id]) } diff --git a/packages/types/package.json b/packages/types/package.json index 98f45c5..7096f50 100644 --- a/packages/types/package.json +++ b/packages/types/package.json @@ -1,5 +1,5 @@ { - "name": "@recall/types", + "name": "@core/types", "private": true, "version": "0.0.1", "main": "./dist/index.js", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 3a3fc8e..ca3a362 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -36,18 +36,75 @@ importers: '@coji/remix-auth-google': specifier: ^4.2.0 version: 4.2.0 + '@conform-to/react': + specifier: ^0.6.1 + version: 0.6.3(react@18.3.1) + '@conform-to/zod': + specifier: ^0.6.1 + version: 0.6.3(@conform-to/dom@0.6.3)(zod@3.23.8) + '@core/database': + specifier: workspace:* + version: link:../../packages/database + '@core/types': + specifier: workspace:* + version: link:../../packages/types '@opentelemetry/api': specifier: 1.9.0 version: 1.9.0 + '@radix-ui/react-accordion': + specifier: ^1.1.2 + version: 1.2.11(@types/react-dom@18.3.7(@types/react@18.3.23))(@types/react@18.3.23)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-alert-dialog': + specifier: ^1.0.5 + version: 1.1.14(@types/react-dom@18.3.7(@types/react@18.3.23))(@types/react@18.3.23)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-avatar': + specifier: ^1.0.4 + version: 1.1.10(@types/react-dom@18.3.7(@types/react@18.3.23))(@types/react@18.3.23)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-checkbox': + specifier: ^1.0.4 + version: 1.3.2(@types/react-dom@18.3.7(@types/react@18.3.23))(@types/react@18.3.23)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-collapsible': + specifier: ^1.0.3 + version: 1.1.11(@types/react-dom@18.3.7(@types/react@18.3.23))(@types/react@18.3.23)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-dialog': + specifier: ^1.1.14 + version: 1.1.14(@types/react-dom@18.3.7(@types/react@18.3.23))(@types/react@18.3.23)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-dropdown-menu': + specifier: ^2.0.6 + version: 2.1.15(@types/react-dom@18.3.7(@types/react@18.3.23))(@types/react@18.3.23)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-icons': + specifier: ^1.3.0 + version: 1.3.2(react@18.3.1) + '@radix-ui/react-label': + specifier: ^2.0.2 + version: 2.1.7(@types/react-dom@18.3.7(@types/react@18.3.23))(@types/react@18.3.23)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-popover': + specifier: ^1.0.7 + version: 1.1.14(@types/react-dom@18.3.7(@types/react@18.3.23))(@types/react@18.3.23)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-scroll-area': + specifier: ^1.0.5 + version: 1.2.9(@types/react-dom@18.3.7(@types/react@18.3.23))(@types/react@18.3.23)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-select': + specifier: ^2.0.0 + version: 2.2.5(@types/react-dom@18.3.7(@types/react@18.3.23))(@types/react@18.3.23)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-separator': + specifier: ^1.1.7 + version: 1.1.7(@types/react-dom@18.3.7(@types/react@18.3.23))(@types/react@18.3.23)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@radix-ui/react-slot': specifier: ^1.2.3 version: 1.2.3(@types/react@18.3.23)(react@18.3.1) - '@recall/database': - specifier: workspace:* - version: link:../../packages/database - '@recall/types': - specifier: workspace:* - version: link:../../packages/types + '@radix-ui/react-switch': + specifier: ^1.0.3 + version: 1.2.5(@types/react-dom@18.3.7(@types/react@18.3.23))(@types/react@18.3.23)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-tabs': + specifier: ^1.0.4 + version: 1.1.12(@types/react-dom@18.3.7(@types/react@18.3.23))(@types/react@18.3.23)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-toast': + specifier: ^1.1.5 + version: 1.2.14(@types/react-dom@18.3.7(@types/react@18.3.23))(@types/react@18.3.23)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-tooltip': + specifier: ^1.2.7 + version: 1.2.7(@types/react-dom@18.3.7(@types/react@18.3.23))(@types/react@18.3.23)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@remix-run/express': specifier: 2.16.7 version: 2.16.7(express@4.21.2)(typescript@5.8.3) @@ -96,6 +153,12 @@ importers: cross-env: specifier: ^7.0.3 version: 7.0.3 + d3: + specifier: ^7.9.0 + version: 7.9.0 + dayjs: + specifier: ^1.11.10 + version: 1.11.13 express: specifier: ^4.18.1 version: 4.21.2 @@ -193,6 +256,9 @@ importers: '@types/compression': specifier: ^1.7.2 version: 1.8.0 + '@types/d3': + specifier: ^7.4.3 + version: 7.4.3 '@types/express': specifier: ^4.17.13 version: 4.17.22 @@ -585,6 +651,20 @@ packages: '@coji/remix-auth-google@4.2.0': resolution: {integrity: sha512-H9i3fvVz0GE18GUZHpz7p7FQjuiuloTIBAPjW7cfv7lUEk+mI6WRTVLEHJBLLuTlAF1+0EbzvPRYKutxZiFdfw==} + '@conform-to/dom@0.6.3': + resolution: {integrity: sha512-8UbO8vTP0lwpJjzo0TIrQMqWQb65Gj6WpNEVfhHouTEkFTDCP9mND2kO6w1e4TgucRfIDKleYxcFee3lNZsBcw==} + + '@conform-to/react@0.6.3': + resolution: {integrity: sha512-s20D5nRDCa5JkkI+zMyHTaPqqaGgL+y8avenq8fr0r3keCxly/EcrbNH0aAr91OiTdiBD3+ar63XZLZbtx8hDQ==} + peerDependencies: + react: '>=16.8' + + '@conform-to/zod@0.6.3': + resolution: {integrity: sha512-x8HmWuYt/qJVZBB+EG5k0BKCgRUJLVsvy+d6Foqg/Ih/G1xcyPesv7YX/AborurbIiZEuO75Tws1yuZ1AAaIUw==} + peerDependencies: + '@conform-to/dom': 0.6.3 + zod: ^3.21.0 + '@edgefirst-dev/data@0.0.4': resolution: {integrity: sha512-VLhlvEPDJ0Sd0pE6sAYTQkIqZCXVonaWlgRJIQQHzfjTXCadF77qqHj5NxaPSc4wCul0DJO/0MnejVqJAXUiRg==} engines: {node: '>=20.0.0'} @@ -1051,6 +1131,21 @@ packages: resolution: {integrity: sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + '@floating-ui/core@1.7.1': + resolution: {integrity: sha512-azI0DrjMMfIug/ExbBaeDVJXcY0a7EPvPjb2xAJPa4HeimBX+Z18HK8QQR3jb6356SnDDdxx+hinMLcJEDdOjw==} + + '@floating-ui/dom@1.7.1': + resolution: {integrity: sha512-cwsmW/zyw5ltYTUeeYJ60CnQuPqmGwuGVhG9w0PRaRKkAyi38BT5CKrpIbb+jtahSwUl04cWzSx9ZOIxeS6RsQ==} + + '@floating-ui/react-dom@2.1.3': + resolution: {integrity: sha512-huMBfiU9UnQ2oBwIhgzyIiSpVgvlDstU8CX0AF+wS+KzmYMs0J2a3GwuFHV1Lz+jlrQGeC1fF+Nv0QoumyV0bA==} + peerDependencies: + react: '>=16.8.0' + react-dom: '>=16.8.0' + + '@floating-ui/utils@0.2.9': + resolution: {integrity: sha512-MDWhGtE+eHw5JW7lq4qhc5yRLS11ERl1c7Z6Xd0a58DozHES6EnNNwUWbMiG4J9Cgj053Bhk8zvlhFYKVhULwg==} + '@fullhuman/postcss-purgecss@2.3.0': resolution: {integrity: sha512-qnKm5dIOyPGJ70kPZ5jiz0I9foVOic0j+cOzNDoo8KoCf6HjicIZ99UfO2OmE7vCYSKAAepEwJtNzpiiZAh9xw==} @@ -1220,6 +1315,103 @@ packages: '@prisma/engines@5.4.1': resolution: {integrity: sha512-vJTdY4la/5V3N7SFvWRmSMUh4mIQnyb/MNoDjzVbh9iLmEC+uEykj/1GPviVsorvfz7DbYSQC4RiwmlEpTEvGA==} + '@radix-ui/number@1.1.1': + resolution: {integrity: sha512-MkKCwxlXTgz6CFoJx3pCwn07GKp36+aZyu/u2Ln2VrA5DcdyCZkASEDBTd8x5whTQQL5CiYf4prXKLcgQdv29g==} + + '@radix-ui/primitive@1.1.2': + resolution: {integrity: sha512-XnbHrrprsNqZKQhStrSwgRUQzoCI1glLzdw79xiZPoofhGICeZRSQ3dIxAKH1gb3OHfNf4d6f+vAv3kil2eggA==} + + '@radix-ui/react-accordion@1.2.11': + resolution: {integrity: sha512-l3W5D54emV2ues7jjeG1xcyN7S3jnK3zE2zHqgn0CmMsy9lNJwmgcrmaxS+7ipw15FAivzKNzH3d5EcGoFKw0A==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-alert-dialog@1.1.14': + resolution: {integrity: sha512-IOZfZ3nPvN6lXpJTBCunFQPRSvK8MDgSc1FB85xnIpUKOw9en0dJj8JmCAxV7BiZdtYlUpmrQjoTFkVYtdoWzQ==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-arrow@1.1.7': + resolution: {integrity: sha512-F+M1tLhO+mlQaOWspE8Wstg+z6PwxwRd8oQ8IXceWz92kfAmalTRf0EjrouQeo7QssEPfCn05B4Ihs1K9WQ/7w==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-avatar@1.1.10': + resolution: {integrity: sha512-V8piFfWapM5OmNCXTzVQY+E1rDa53zY+MQ4Y7356v4fFz6vqCyUtIz2rUD44ZEdwg78/jKmMJHj07+C/Z/rcog==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-checkbox@1.3.2': + resolution: {integrity: sha512-yd+dI56KZqawxKZrJ31eENUwqc1QSqg4OZ15rybGjF2ZNwMO+wCyHzAVLRp9qoYJf7kYy0YpZ2b0JCzJ42HZpA==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-collapsible@1.1.11': + resolution: {integrity: sha512-2qrRsVGSCYasSz1RFOorXwl0H7g7J1frQtgpQgYrt+MOidtPAINHn9CPovQXb83r8ahapdx3Tu0fa/pdFFSdPg==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-collection@1.1.7': + resolution: {integrity: sha512-Fh9rGN0MoI4ZFUNyfFVNU4y9LUz93u9/0K+yLgA2bwRojxM8JU1DyvvMBabnZPBgMWREAJvU2jjVzq+LrFUglw==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + '@radix-ui/react-compose-refs@1.1.2': resolution: {integrity: sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg==} peerDependencies: @@ -1229,6 +1421,242 @@ packages: '@types/react': optional: true + '@radix-ui/react-context@1.1.2': + resolution: {integrity: sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-dialog@1.1.14': + resolution: {integrity: sha512-+CpweKjqpzTmwRwcYECQcNYbI8V9VSQt0SNFKeEBLgfucbsLssU6Ppq7wUdNXEGb573bMjFhVjKVll8rmV6zMw==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-direction@1.1.1': + resolution: {integrity: sha512-1UEWRX6jnOA2y4H5WczZ44gOOjTEmlqv1uNW4GAJEO5+bauCBhv8snY65Iw5/VOS/ghKN9gr2KjnLKxrsvoMVw==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-dismissable-layer@1.1.10': + resolution: {integrity: sha512-IM1zzRV4W3HtVgftdQiiOmA0AdJlCtMLe00FXaHwgt3rAnNsIyDqshvkIW3hj/iu5hu8ERP7KIYki6NkqDxAwQ==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-dropdown-menu@2.1.15': + resolution: {integrity: sha512-mIBnOjgwo9AH3FyKaSWoSu/dYj6VdhJ7frEPiGTeXCdUFHjl9h3mFh2wwhEtINOmYXWhdpf1rY2minFsmaNgVQ==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-focus-guards@1.1.2': + resolution: {integrity: sha512-fyjAACV62oPV925xFCrH8DR5xWhg9KYtJT4s3u54jxp+L/hbpTY2kIeEFFbFe+a/HCE94zGQMZLIpVTPVZDhaA==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-focus-scope@1.1.7': + resolution: {integrity: sha512-t2ODlkXBQyn7jkl6TNaw/MtVEVvIGelJDCG41Okq/KwUsJBwQ4XVZsHAVUkK4mBv3ewiAS3PGuUWuY2BoK4ZUw==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-icons@1.3.2': + resolution: {integrity: sha512-fyQIhGDhzfc9pK2kH6Pl9c4BDJGfMkPqkyIgYDthyNYoNg3wVhoJMMh19WS4Up/1KMPFVpNsT2q3WmXn2N1m6g==} + peerDependencies: + react: ^16.x || ^17.x || ^18.x || ^19.0.0 || ^19.0.0-rc + + '@radix-ui/react-id@1.1.1': + resolution: {integrity: sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-label@2.1.7': + resolution: {integrity: sha512-YT1GqPSL8kJn20djelMX7/cTRp/Y9w5IZHvfxQTVHrOqa2yMl7i/UfMqKRU5V7mEyKTrUVgJXhNQPVCG8PBLoQ==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-menu@2.1.15': + resolution: {integrity: sha512-tVlmA3Vb9n8SZSd+YSbuFR66l87Wiy4du+YE+0hzKQEANA+7cWKH1WgqcEX4pXqxUFQKrWQGHdvEfw00TjFiew==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-popover@1.1.14': + resolution: {integrity: sha512-ODz16+1iIbGUfFEfKx2HTPKizg2MN39uIOV8MXeHnmdd3i/N9Wt7vU46wbHsqA0xoaQyXVcs0KIlBdOA2Y95bw==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-popper@1.2.7': + resolution: {integrity: sha512-IUFAccz1JyKcf/RjB552PlWwxjeCJB8/4KxT7EhBHOJM+mN7LdW+B3kacJXILm32xawcMMjb2i0cIZpo+f9kiQ==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-portal@1.1.9': + resolution: {integrity: sha512-bpIxvq03if6UNwXZ+HTK71JLh4APvnXntDc6XOX8UVq4XQOVl7lwok0AvIl+b8zgCw3fSaVTZMpAPPagXbKmHQ==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-presence@1.1.4': + resolution: {integrity: sha512-ueDqRbdc4/bkaQT3GIpLQssRlFgWaL/U2z/S31qRwwLWoxHLgry3SIfCwhxeQNbirEUXFa+lq3RL3oBYXtcmIA==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-primitive@2.1.3': + resolution: {integrity: sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-roving-focus@1.1.10': + resolution: {integrity: sha512-dT9aOXUen9JSsxnMPv/0VqySQf5eDQ6LCk5Sw28kamz8wSOW2bJdlX2Bg5VUIIcV+6XlHpWTIuTPCf/UNIyq8Q==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-scroll-area@1.2.9': + resolution: {integrity: sha512-YSjEfBXnhUELsO2VzjdtYYD4CfQjvao+lhhrX5XsHD7/cyUNzljF1FHEbgTPN7LH2MClfwRMIsYlqTYpKTTe2A==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-select@2.2.5': + resolution: {integrity: sha512-HnMTdXEVuuyzx63ME0ut4+sEMYW6oouHWNGUZc7ddvUWIcfCva/AMoqEW/3wnEllriMWBa0RHspCYnfCWJQYmA==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-separator@1.1.7': + resolution: {integrity: sha512-0HEb8R9E8A+jZjvmFCy/J4xhbXy3TV+9XSnGJ3KvTtjlIUy/YQ/p6UYZvi7YbeoeXdyU9+Y3scizK6hkY37baA==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + '@radix-ui/react-slot@1.2.3': resolution: {integrity: sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==} peerDependencies: @@ -1238,6 +1666,155 @@ packages: '@types/react': optional: true + '@radix-ui/react-switch@1.2.5': + resolution: {integrity: sha512-5ijLkak6ZMylXsaImpZ8u4Rlf5grRmoc0p0QeX9VJtlrM4f5m3nCTX8tWga/zOA8PZYIR/t0p2Mnvd7InrJ6yQ==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-tabs@1.1.12': + resolution: {integrity: sha512-GTVAlRVrQrSw3cEARM0nAx73ixrWDPNZAruETn3oHCNP6SbZ/hNxdxp+u7VkIEv3/sFoLq1PfcHrl7Pnp0CDpw==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-toast@1.2.14': + resolution: {integrity: sha512-nAP5FBxBJGQ/YfUB+r+O6USFVkWq3gAInkxyEnmvEV5jtSbfDhfa4hwX8CraCnbjMLsE7XSf/K75l9xXY7joWg==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-tooltip@1.2.7': + resolution: {integrity: sha512-Ap+fNYwKTYJ9pzqW+Xe2HtMRbQ/EeWkj2qykZ6SuEV4iS/o1bZI5ssJbk4D2r8XuDuOBVz/tIx2JObtuqU+5Zw==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-use-callback-ref@1.1.1': + resolution: {integrity: sha512-FkBMwD+qbGQeMu1cOHnuGB6x4yzPjho8ap5WtbEJ26umhgqVXbhekKUQO+hZEL1vU92a3wHwdp0HAcqAUF5iDg==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-controllable-state@1.2.2': + resolution: {integrity: sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-effect-event@0.0.2': + resolution: {integrity: sha512-Qp8WbZOBe+blgpuUT+lw2xheLP8q0oatc9UpmiemEICxGvFLYmHm9QowVZGHtJlGbS6A6yJ3iViad/2cVjnOiA==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-escape-keydown@1.1.1': + resolution: {integrity: sha512-Il0+boE7w/XebUHyBjroE+DbByORGR9KKmITzbR7MyQ4akpORYP/ZmbhAr0DG7RmmBqoOnZdy2QlvajJ2QA59g==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-is-hydrated@0.1.0': + resolution: {integrity: sha512-U+UORVEq+cTnRIaostJv9AGdV3G6Y+zbVd+12e18jQ5A3c0xL03IhnHuiU4UV69wolOQp5GfR58NW/EgdQhwOA==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-layout-effect@1.1.1': + resolution: {integrity: sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-previous@1.1.1': + resolution: {integrity: sha512-2dHfToCj/pzca2Ck724OZ5L0EVrr3eHRNsG/b3xQJLA2hZpVCS99bLAX+hm1IHXDEnzU6by5z/5MIY794/a8NQ==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-rect@1.1.1': + resolution: {integrity: sha512-QTYuDesS0VtuHNNvMh+CjlKJ4LJickCMUAqjlE3+j8w+RlRpwyX3apEQKGFzbZGdo7XNG1tXa+bQqIE7HIXT2w==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-size@1.1.1': + resolution: {integrity: sha512-ewrXRDTAqAXlkl6t/fkXWNAhFX9I+CkKlw6zjEwk86RSPKwZr3xpBRso655aqYafwtnbpHLj6toFzmd6xdVptQ==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-visually-hidden@1.2.3': + resolution: {integrity: sha512-pzJq12tEaaIhqjbzpCuv/OypJY/BPavOofm+dbab+MHLajy277+1lLm6JFcGgF5eskJ6mquGirhXY2GD/8u8Ug==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/rect@1.1.1': + resolution: {integrity: sha512-HPwpGIzkl28mWyZqG52jiqDJ12waP11Pa1lGoiyUkIEuMLBP0oeK/C89esbXrxsky5we7dfd8U58nm0SgAWpVw==} + '@remix-run/changelog-github@0.0.5': resolution: {integrity: sha512-43tqwUqWqirbv6D9uzo55ASPsCJ61Ein1k/M8qn+Qpros0MmbmuzjLVPmtaxfxfe2ANX0LefLvCD0pAgr1tp4g==} @@ -1621,6 +2198,99 @@ packages: '@types/cookie@0.6.0': resolution: {integrity: sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==} + '@types/d3-array@3.2.1': + resolution: {integrity: sha512-Y2Jn2idRrLzUfAKV2LyRImR+y4oa2AntrgID95SHJxuMUrkNXmanDSed71sRNZysveJVt1hLLemQZIady0FpEg==} + + '@types/d3-axis@3.0.6': + resolution: {integrity: sha512-pYeijfZuBd87T0hGn0FO1vQ/cgLk6E1ALJjfkC0oJ8cbwkZl3TpgS8bVBLZN+2jjGgg38epgxb2zmoGtSfvgMw==} + + '@types/d3-brush@3.0.6': + resolution: {integrity: sha512-nH60IZNNxEcrh6L1ZSMNA28rj27ut/2ZmI3r96Zd+1jrZD++zD3LsMIjWlvg4AYrHn/Pqz4CF3veCxGjtbqt7A==} + + '@types/d3-chord@3.0.6': + resolution: {integrity: sha512-LFYWWd8nwfwEmTZG9PfQxd17HbNPksHBiJHaKuY1XeqscXacsS2tyoo6OdRsjf+NQYeB6XrNL3a25E3gH69lcg==} + + '@types/d3-color@3.1.3': + resolution: {integrity: sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==} + + '@types/d3-contour@3.0.6': + resolution: {integrity: sha512-BjzLgXGnCWjUSYGfH1cpdo41/hgdWETu4YxpezoztawmqsvCeep+8QGfiY6YbDvfgHz/DkjeIkkZVJavB4a3rg==} + + '@types/d3-delaunay@6.0.4': + resolution: {integrity: sha512-ZMaSKu4THYCU6sV64Lhg6qjf1orxBthaC161plr5KuPHo3CNm8DTHiLw/5Eq2b6TsNP0W0iJrUOFscY6Q450Hw==} + + '@types/d3-dispatch@3.0.6': + resolution: {integrity: sha512-4fvZhzMeeuBJYZXRXrRIQnvUYfyXwYmLsdiN7XXmVNQKKw1cM8a5WdID0g1hVFZDqT9ZqZEY5pD44p24VS7iZQ==} + + '@types/d3-drag@3.0.7': + resolution: {integrity: sha512-HE3jVKlzU9AaMazNufooRJ5ZpWmLIoc90A37WU2JMmeq28w1FQqCZswHZ3xR+SuxYftzHq6WU6KJHvqxKzTxxQ==} + + '@types/d3-dsv@3.0.7': + resolution: {integrity: sha512-n6QBF9/+XASqcKK6waudgL0pf/S5XHPPI8APyMLLUHd8NqouBGLsU8MgtO7NINGtPBtk9Kko/W4ea0oAspwh9g==} + + '@types/d3-ease@3.0.2': + resolution: {integrity: sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA==} + + '@types/d3-fetch@3.0.7': + resolution: {integrity: sha512-fTAfNmxSb9SOWNB9IoG5c8Hg6R+AzUHDRlsXsDZsNp6sxAEOP0tkP3gKkNSO/qmHPoBFTxNrjDprVHDQDvo5aA==} + + '@types/d3-force@3.0.10': + resolution: {integrity: sha512-ZYeSaCF3p73RdOKcjj+swRlZfnYpK1EbaDiYICEEp5Q6sUiqFaFQ9qgoshp5CzIyyb/yD09kD9o2zEltCexlgw==} + + '@types/d3-format@3.0.4': + resolution: {integrity: sha512-fALi2aI6shfg7vM5KiR1wNJnZ7r6UuggVqtDA+xiEdPZQwy/trcQaHnwShLuLdta2rTymCNpxYTiMZX/e09F4g==} + + '@types/d3-geo@3.1.0': + resolution: {integrity: sha512-856sckF0oP/diXtS4jNsiQw/UuK5fQG8l/a9VVLeSouf1/PPbBE1i1W852zVwKwYCBkFJJB7nCFTbk6UMEXBOQ==} + + '@types/d3-hierarchy@3.1.7': + resolution: {integrity: sha512-tJFtNoYBtRtkNysX1Xq4sxtjK8YgoWUNpIiUee0/jHGRwqvzYxkq0hGVbbOGSz+JgFxxRu4K8nb3YpG3CMARtg==} + + '@types/d3-interpolate@3.0.4': + resolution: {integrity: sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA==} + + '@types/d3-path@3.1.1': + resolution: {integrity: sha512-VMZBYyQvbGmWyWVea0EHs/BwLgxc+MKi1zLDCONksozI4YJMcTt8ZEuIR4Sb1MMTE8MMW49v0IwI5+b7RmfWlg==} + + '@types/d3-polygon@3.0.2': + resolution: {integrity: sha512-ZuWOtMaHCkN9xoeEMr1ubW2nGWsp4nIql+OPQRstu4ypeZ+zk3YKqQT0CXVe/PYqrKpZAi+J9mTs05TKwjXSRA==} + + '@types/d3-quadtree@3.0.6': + resolution: {integrity: sha512-oUzyO1/Zm6rsxKRHA1vH0NEDG58HrT5icx/azi9MF1TWdtttWl0UIUsjEQBBh+SIkrpd21ZjEv7ptxWys1ncsg==} + + '@types/d3-random@3.0.3': + resolution: {integrity: sha512-Imagg1vJ3y76Y2ea0871wpabqp613+8/r0mCLEBfdtqC7xMSfj9idOnmBYyMoULfHePJyxMAw3nWhJxzc+LFwQ==} + + '@types/d3-scale-chromatic@3.1.0': + resolution: {integrity: sha512-iWMJgwkK7yTRmWqRB5plb1kadXyQ5Sj8V/zYlFGMUBbIPKQScw+Dku9cAAMgJG+z5GYDoMjWGLVOvjghDEFnKQ==} + + '@types/d3-scale@4.0.9': + resolution: {integrity: sha512-dLmtwB8zkAeO/juAMfnV+sItKjlsw2lKdZVVy6LRr0cBmegxSABiLEpGVmSJJ8O08i4+sGR6qQtb6WtuwJdvVw==} + + '@types/d3-selection@3.0.11': + resolution: {integrity: sha512-bhAXu23DJWsrI45xafYpkQ4NtcKMwWnAC/vKrd2l+nxMFuvOT3XMYTIj2opv8vq8AO5Yh7Qac/nSeP/3zjTK0w==} + + '@types/d3-shape@3.1.7': + resolution: {integrity: sha512-VLvUQ33C+3J+8p+Daf+nYSOsjB4GXp19/S/aGo60m9h1v6XaxjiT82lKVWJCfzhtuZ3yD7i/TPeC/fuKLLOSmg==} + + '@types/d3-time-format@4.0.3': + resolution: {integrity: sha512-5xg9rC+wWL8kdDj153qZcsJ0FWiFt0J5RB6LYUNZjwSnesfblqrI/bJ1wBdJ8OQfncgbJG5+2F+qfqnqyzYxyg==} + + '@types/d3-time@3.0.4': + resolution: {integrity: sha512-yuzZug1nkAAaBlBBikKZTgzCeA+k1uy4ZFwWANOfKw5z5LRhV0gNA7gNkKm7HoK+HRN0wX3EkxGk0fpbWhmB7g==} + + '@types/d3-timer@3.0.2': + resolution: {integrity: sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw==} + + '@types/d3-transition@3.0.9': + resolution: {integrity: sha512-uZS5shfxzO3rGlu0cC3bjmMFKsXv+SmZZcgp0KD22ts4uGXp5EVYGzu/0YdwZeKmddhcAccYtREJKkPfXkZuCg==} + + '@types/d3-zoom@3.0.8': + resolution: {integrity: sha512-iqMC4/YlFCSlO8+2Ii1GGGliCAY4XdeG748w5vQUbevlbDu0zSjH/+jojorQVBK/se0j6DUFNPBGSqD3YWYnDw==} + + '@types/d3@7.4.3': + resolution: {integrity: sha512-lZXZ9ckh5R8uiFVt8ogUNf+pIrK4EsWrx2Np75WvF/eTpJ0FMHNhjXk8CKEx/+gpHbNQyJWehbFaTvqmHWB3ww==} + '@types/debug@4.1.12': resolution: {integrity: sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==} @@ -1639,6 +2309,9 @@ packages: '@types/express@4.17.22': resolution: {integrity: sha512-eZUmSnhRX9YRSkplpz0N+k6NljUUn5l3EWZIKZvYzhvMphEuNiyyy1viH/ejgt66JWgALwC/gtSUAeQKtSwW/w==} + '@types/geojson@7946.0.16': + resolution: {integrity: sha512-6C8nqWur3j98U6+lXDfTUWIfgvZU+EumvpHKcYjujKH7woYyLj2sUmff0tRhrqM7BohUw7Pz3ZB1jj2gW9Fvmg==} + '@types/hast@2.3.10': resolution: {integrity: sha512-McWspRw8xx8J9HurkVBfYj0xKoE25tOFlHGdx4MJ5xORQrMGZNqJhVQWaIbm6Oyla5kYOXtDiopzKRJzEOkwJw==} @@ -2026,6 +2699,10 @@ packages: argparse@2.0.1: resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + aria-hidden@1.2.6: + resolution: {integrity: sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA==} + engines: {node: '>=10'} + aria-query@5.1.3: resolution: {integrity: sha512-R5iJ5lkuHybztUfuOAznmboyjWq8O6sqNqtK7CLOqdydi54VNbORp49mb14KbWgG1QD3JFO9hJdZ+y4KutfdOQ==} @@ -2323,6 +3000,10 @@ packages: resolution: {integrity: sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==} engines: {node: '>= 6'} + commander@7.2.0: + resolution: {integrity: sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==} + engines: {node: '>= 10'} + compressible@2.0.18: resolution: {integrity: sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==} engines: {node: '>= 0.6'} @@ -2441,6 +3122,133 @@ packages: resolution: {integrity: sha512-QTaY0XjjhTQOdguARF0lGKm5/mEq9PD9/VhZZegHDIBq2tQwgNpHc3dneD4mGo2iJs+fTKv5Bp0fZ+BRuY3Z0g==} engines: {node: '>= 0.1.90'} + d3-array@3.2.4: + resolution: {integrity: sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==} + engines: {node: '>=12'} + + d3-axis@3.0.0: + resolution: {integrity: sha512-IH5tgjV4jE/GhHkRV0HiVYPDtvfjHQlQfJHs0usq7M30XcSBvOotpmH1IgkcXsO/5gEQZD43B//fc7SRT5S+xw==} + engines: {node: '>=12'} + + d3-brush@3.0.0: + resolution: {integrity: sha512-ALnjWlVYkXsVIGlOsuWH1+3udkYFI48Ljihfnh8FZPF2QS9o+PzGLBslO0PjzVoHLZ2KCVgAM8NVkXPJB2aNnQ==} + engines: {node: '>=12'} + + d3-chord@3.0.1: + resolution: {integrity: sha512-VE5S6TNa+j8msksl7HwjxMHDM2yNK3XCkusIlpX5kwauBfXuyLAtNg9jCp/iHH61tgI4sb6R/EIMWCqEIdjT/g==} + engines: {node: '>=12'} + + d3-color@3.1.0: + resolution: {integrity: sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==} + engines: {node: '>=12'} + + d3-contour@4.0.2: + resolution: {integrity: sha512-4EzFTRIikzs47RGmdxbeUvLWtGedDUNkTcmzoeyg4sP/dvCexO47AaQL7VKy/gul85TOxw+IBgA8US2xwbToNA==} + engines: {node: '>=12'} + + d3-delaunay@6.0.4: + resolution: {integrity: sha512-mdjtIZ1XLAM8bm/hx3WwjfHt6Sggek7qH043O8KEjDXN40xi3vx/6pYSVTwLjEgiXQTbvaouWKynLBiUZ6SK6A==} + engines: {node: '>=12'} + + d3-dispatch@3.0.1: + resolution: {integrity: sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg==} + engines: {node: '>=12'} + + d3-drag@3.0.0: + resolution: {integrity: sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg==} + engines: {node: '>=12'} + + d3-dsv@3.0.1: + resolution: {integrity: sha512-UG6OvdI5afDIFP9w4G0mNq50dSOsXHJaRE8arAS5o9ApWnIElp8GZw1Dun8vP8OyHOZ/QJUKUJwxiiCCnUwm+Q==} + engines: {node: '>=12'} + hasBin: true + + d3-ease@3.0.1: + resolution: {integrity: sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==} + engines: {node: '>=12'} + + d3-fetch@3.0.1: + resolution: {integrity: sha512-kpkQIM20n3oLVBKGg6oHrUchHM3xODkTzjMoj7aWQFq5QEM+R6E4WkzT5+tojDY7yjez8KgCBRoj4aEr99Fdqw==} + engines: {node: '>=12'} + + d3-force@3.0.0: + resolution: {integrity: sha512-zxV/SsA+U4yte8051P4ECydjD/S+qeYtnaIyAs9tgHCqfguma/aAQDjo85A9Z6EKhBirHRJHXIgJUlffT4wdLg==} + engines: {node: '>=12'} + + d3-format@3.1.0: + resolution: {integrity: sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA==} + engines: {node: '>=12'} + + d3-geo@3.1.1: + resolution: {integrity: sha512-637ln3gXKXOwhalDzinUgY83KzNWZRKbYubaG+fGVuc/dxO64RRljtCTnf5ecMyE1RIdtqpkVcq0IbtU2S8j2Q==} + engines: {node: '>=12'} + + d3-hierarchy@3.1.2: + resolution: {integrity: sha512-FX/9frcub54beBdugHjDCdikxThEqjnR93Qt7PvQTOHxyiNCAlvMrHhclk3cD5VeAaq9fxmfRp+CnWw9rEMBuA==} + engines: {node: '>=12'} + + d3-interpolate@3.0.1: + resolution: {integrity: sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==} + engines: {node: '>=12'} + + d3-path@3.1.0: + resolution: {integrity: sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==} + engines: {node: '>=12'} + + d3-polygon@3.0.1: + resolution: {integrity: sha512-3vbA7vXYwfe1SYhED++fPUQlWSYTTGmFmQiany/gdbiWgU/iEyQzyymwL9SkJjFFuCS4902BSzewVGsHHmHtXg==} + engines: {node: '>=12'} + + d3-quadtree@3.0.1: + resolution: {integrity: sha512-04xDrxQTDTCFwP5H6hRhsRcb9xxv2RzkcsygFzmkSIOJy3PeRJP7sNk3VRIbKXcog561P9oU0/rVH6vDROAgUw==} + engines: {node: '>=12'} + + d3-random@3.0.1: + resolution: {integrity: sha512-FXMe9GfxTxqd5D6jFsQ+DJ8BJS4E/fT5mqqdjovykEB2oFbTMDVdg1MGFxfQW+FBOGoB++k8swBrgwSHT1cUXQ==} + engines: {node: '>=12'} + + d3-scale-chromatic@3.1.0: + resolution: {integrity: sha512-A3s5PWiZ9YCXFye1o246KoscMWqf8BsD9eRiJ3He7C9OBaxKhAd5TFCdEx/7VbKtxxTsu//1mMJFrEt572cEyQ==} + engines: {node: '>=12'} + + d3-scale@4.0.2: + resolution: {integrity: sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==} + engines: {node: '>=12'} + + d3-selection@3.0.0: + resolution: {integrity: sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==} + engines: {node: '>=12'} + + d3-shape@3.2.0: + resolution: {integrity: sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==} + engines: {node: '>=12'} + + d3-time-format@4.1.0: + resolution: {integrity: sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==} + engines: {node: '>=12'} + + d3-time@3.1.0: + resolution: {integrity: sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==} + engines: {node: '>=12'} + + d3-timer@3.0.1: + resolution: {integrity: sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==} + engines: {node: '>=12'} + + d3-transition@3.0.1: + resolution: {integrity: sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w==} + engines: {node: '>=12'} + peerDependencies: + d3-selection: 2 - 3 + + d3-zoom@3.0.0: + resolution: {integrity: sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw==} + engines: {node: '>=12'} + + d3@7.9.0: + resolution: {integrity: sha512-e1U46jVP+w7Iut8Jt8ri1YsPOvFpg46k+K8TpCb0P+zjCkjkPnV7WzfDJzMHy1LnA+wj5pLT1wjO901gLXeEhA==} + engines: {node: '>=12'} + damerau-levenshtein@1.0.8: resolution: {integrity: sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==} @@ -2463,6 +3271,9 @@ packages: dataloader@1.4.0: resolution: {integrity: sha512-68s5jYdlvasItOJnCuI2Q9s4q98g0pCyL3HrcKJu8KNugUl8ahgmZYg38ysLTgQjjXX3H8CJLkAvWrclWfcalw==} + dayjs@1.11.13: + resolution: {integrity: sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==} + debug@2.6.9: resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==} peerDependencies: @@ -2535,6 +3346,9 @@ packages: defined@1.0.1: resolution: {integrity: sha512-hsBd2qSVCRE+5PmNdHt1uzyrFu5d3RwmFDKzyNZMFq/EwDNJF7Ee5+D5oEKF0hU6LhtoUF1macFvOe4AskQC1Q==} + delaunator@5.0.1: + resolution: {integrity: sha512-8nvh+XBe96aCESrGOqMp/84b13H9cdKbG5P2ejQCh4d4sK9RL4371qou9drQjMhvnPmhWl5hnmqbEE0fXr9Xnw==} + denque@2.1.0: resolution: {integrity: sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==} engines: {node: '>=0.10'} @@ -2559,6 +3373,9 @@ packages: resolution: {integrity: sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA==} engines: {node: '>=8'} + detect-node-es@1.1.0: + resolution: {integrity: sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==} + detective@5.2.1: resolution: {integrity: sha512-v9XE1zRnz1wRtgurGu0Bs8uHKFSTdteYZNbIPFVhUZ39L/S79ppMpdmVOZAnoz1jfEFodc48n6MX483Xo3t1yw==} engines: {node: '>=0.8.0'} @@ -3233,6 +4050,10 @@ packages: resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} engines: {node: '>= 0.4'} + get-nonce@1.0.1: + resolution: {integrity: sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==} + engines: {node: '>=6'} + get-port@5.1.1: resolution: {integrity: sha512-g/Q1aTSDOxFpchXC4i8ZWvxA1lnPqx/JHqcpIw0/LX9T8x/GBbi6YnlN5nhaKIFkT8oFsscUKgDJYxfwfS6QsQ==} engines: {node: '>=8'} @@ -3376,6 +4197,10 @@ packages: resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==} engines: {node: '>=0.10.0'} + iconv-lite@0.6.3: + resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} + engines: {node: '>=0.10.0'} + icss-utils@5.1.0: resolution: {integrity: sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==} engines: {node: ^10 || ^12 || >= 14} @@ -3415,6 +4240,10 @@ packages: resolution: {integrity: sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==} engines: {node: '>= 0.4'} + internmap@2.0.3: + resolution: {integrity: sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==} + engines: {node: '>=12'} + ioredis@5.6.1: resolution: {integrity: sha512-UxC0Yv1Y4WRJiGQxQkP0hfdL0/5/6YvdfOOClRgJ0qppSarkhneSa6UvkMkms0AkdGimSH3Ikqm+6mkMmX7vGA==} engines: {node: '>=12.22.0'} @@ -4807,6 +5636,26 @@ packages: resolution: {integrity: sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA==} engines: {node: '>=0.10.0'} + react-remove-scroll-bar@2.3.8: + resolution: {integrity: sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + peerDependenciesMeta: + '@types/react': + optional: true + + react-remove-scroll@2.7.1: + resolution: {integrity: sha512-HpMh8+oahmIdOuS5aFKKY6Pyog+FNaZV/XyJOq7b4YFwsFHe5yYfdbIalI4k3vU2nSDql7YskmUseHsRrJqIPA==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + react-router-dom@6.30.0: resolution: {integrity: sha512-x30B78HV5tFk8ex0ITwzC9TTZMua4jGyA9IUlH1JLQYQTFyxr/ZxwOJq7evg1JX1qGVUcvhsmQSKdPncQrjTgA==} engines: {node: '>=14.0.0'} @@ -4820,6 +5669,16 @@ packages: peerDependencies: react: '>=16.8' + react-style-singleton@2.2.3: + resolution: {integrity: sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + react@18.3.1: resolution: {integrity: sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==} engines: {node: '>=0.10.0'} @@ -5009,6 +5868,9 @@ packages: engines: {node: 20 || >=22} hasBin: true + robust-predicates@3.0.2: + resolution: {integrity: sha512-IXgzBWvWQwE6PrDI05OvmXUIruQTcoMDzRsOd5CDvHCVLcLHMTSYvOK5Cm46kWqlV3yAbuSpBZdJ5oP5OUoStg==} + rollup@4.41.1: resolution: {integrity: sha512-cPmwD3FnFv8rKMBc1MxWCwVQFxwf1JEmSX3iQXrRVVG15zerAIXRjMFVWnd5Q5QvgKF7Aj+5ykXFhUl+QGnyOw==} engines: {node: '>=18.0.0', npm: '>=8.0.0'} @@ -5017,6 +5879,9 @@ packages: run-parallel@1.2.0: resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + rw@1.3.3: + resolution: {integrity: sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==} + rxjs@7.8.2: resolution: {integrity: sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==} @@ -5600,6 +6465,26 @@ packages: uri-js@4.4.1: resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + use-callback-ref@1.3.3: + resolution: {integrity: sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + use-sidecar@1.1.3: + resolution: {integrity: sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + use-sync-external-store@1.5.0: resolution: {integrity: sha512-Rb46I4cGGVBmjamjphe8L/UnvJD+uPPtTkNvX5mZgqdbavhI4EbgIWJiIHXJ8bc/i9EQGPRh4DwEURJ552Do0A==} peerDependencies: @@ -6342,6 +7227,18 @@ snapshots: '@coji/remix-auth-google@4.2.0': {} + '@conform-to/dom@0.6.3': {} + + '@conform-to/react@0.6.3(react@18.3.1)': + dependencies: + '@conform-to/dom': 0.6.3 + react: 18.3.1 + + '@conform-to/zod@0.6.3(@conform-to/dom@0.6.3)(zod@3.23.8)': + dependencies: + '@conform-to/dom': 0.6.3 + zod: 3.23.8 + '@edgefirst-dev/data@0.0.4': {} '@emnapi/core@1.4.3': @@ -6601,6 +7498,23 @@ snapshots: '@eslint/js@8.57.1': {} + '@floating-ui/core@1.7.1': + dependencies: + '@floating-ui/utils': 0.2.9 + + '@floating-ui/dom@1.7.1': + dependencies: + '@floating-ui/core': 1.7.1 + '@floating-ui/utils': 0.2.9 + + '@floating-ui/react-dom@2.1.3(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + dependencies: + '@floating-ui/dom': 1.7.1 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + + '@floating-ui/utils@0.2.9': {} + '@fullhuman/postcss-purgecss@2.3.0': dependencies: postcss: 7.0.32 @@ -6802,12 +7716,380 @@ snapshots: '@prisma/engines@5.4.1': {} + '@radix-ui/number@1.1.1': {} + + '@radix-ui/primitive@1.1.2': {} + + '@radix-ui/react-accordion@1.2.11(@types/react-dom@18.3.7(@types/react@18.3.23))(@types/react@18.3.23)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + dependencies: + '@radix-ui/primitive': 1.1.2 + '@radix-ui/react-collapsible': 1.1.11(@types/react-dom@18.3.7(@types/react@18.3.23))(@types/react@18.3.23)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-collection': 1.1.7(@types/react-dom@18.3.7(@types/react@18.3.23))(@types/react@18.3.23)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.23)(react@18.3.1) + '@radix-ui/react-context': 1.1.2(@types/react@18.3.23)(react@18.3.1) + '@radix-ui/react-direction': 1.1.1(@types/react@18.3.23)(react@18.3.1) + '@radix-ui/react-id': 1.1.1(@types/react@18.3.23)(react@18.3.1) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.23))(@types/react@18.3.23)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.3.23)(react@18.3.1) + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + optionalDependencies: + '@types/react': 18.3.23 + '@types/react-dom': 18.3.7(@types/react@18.3.23) + + '@radix-ui/react-alert-dialog@1.1.14(@types/react-dom@18.3.7(@types/react@18.3.23))(@types/react@18.3.23)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + dependencies: + '@radix-ui/primitive': 1.1.2 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.23)(react@18.3.1) + '@radix-ui/react-context': 1.1.2(@types/react@18.3.23)(react@18.3.1) + '@radix-ui/react-dialog': 1.1.14(@types/react-dom@18.3.7(@types/react@18.3.23))(@types/react@18.3.23)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.23))(@types/react@18.3.23)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-slot': 1.2.3(@types/react@18.3.23)(react@18.3.1) + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + optionalDependencies: + '@types/react': 18.3.23 + '@types/react-dom': 18.3.7(@types/react@18.3.23) + + '@radix-ui/react-arrow@1.1.7(@types/react-dom@18.3.7(@types/react@18.3.23))(@types/react@18.3.23)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + dependencies: + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.23))(@types/react@18.3.23)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + optionalDependencies: + '@types/react': 18.3.23 + '@types/react-dom': 18.3.7(@types/react@18.3.23) + + '@radix-ui/react-avatar@1.1.10(@types/react-dom@18.3.7(@types/react@18.3.23))(@types/react@18.3.23)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + dependencies: + '@radix-ui/react-context': 1.1.2(@types/react@18.3.23)(react@18.3.1) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.23))(@types/react@18.3.23)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@18.3.23)(react@18.3.1) + '@radix-ui/react-use-is-hydrated': 0.1.0(@types/react@18.3.23)(react@18.3.1) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.3.23)(react@18.3.1) + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + optionalDependencies: + '@types/react': 18.3.23 + '@types/react-dom': 18.3.7(@types/react@18.3.23) + + '@radix-ui/react-checkbox@1.3.2(@types/react-dom@18.3.7(@types/react@18.3.23))(@types/react@18.3.23)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + dependencies: + '@radix-ui/primitive': 1.1.2 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.23)(react@18.3.1) + '@radix-ui/react-context': 1.1.2(@types/react@18.3.23)(react@18.3.1) + '@radix-ui/react-presence': 1.1.4(@types/react-dom@18.3.7(@types/react@18.3.23))(@types/react@18.3.23)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.23))(@types/react@18.3.23)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.3.23)(react@18.3.1) + '@radix-ui/react-use-previous': 1.1.1(@types/react@18.3.23)(react@18.3.1) + '@radix-ui/react-use-size': 1.1.1(@types/react@18.3.23)(react@18.3.1) + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + optionalDependencies: + '@types/react': 18.3.23 + '@types/react-dom': 18.3.7(@types/react@18.3.23) + + '@radix-ui/react-collapsible@1.1.11(@types/react-dom@18.3.7(@types/react@18.3.23))(@types/react@18.3.23)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + dependencies: + '@radix-ui/primitive': 1.1.2 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.23)(react@18.3.1) + '@radix-ui/react-context': 1.1.2(@types/react@18.3.23)(react@18.3.1) + '@radix-ui/react-id': 1.1.1(@types/react@18.3.23)(react@18.3.1) + '@radix-ui/react-presence': 1.1.4(@types/react-dom@18.3.7(@types/react@18.3.23))(@types/react@18.3.23)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.23))(@types/react@18.3.23)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.3.23)(react@18.3.1) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.3.23)(react@18.3.1) + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + optionalDependencies: + '@types/react': 18.3.23 + '@types/react-dom': 18.3.7(@types/react@18.3.23) + + '@radix-ui/react-collection@1.1.7(@types/react-dom@18.3.7(@types/react@18.3.23))(@types/react@18.3.23)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + dependencies: + '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.23)(react@18.3.1) + '@radix-ui/react-context': 1.1.2(@types/react@18.3.23)(react@18.3.1) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.23))(@types/react@18.3.23)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-slot': 1.2.3(@types/react@18.3.23)(react@18.3.1) + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + optionalDependencies: + '@types/react': 18.3.23 + '@types/react-dom': 18.3.7(@types/react@18.3.23) + '@radix-ui/react-compose-refs@1.1.2(@types/react@18.3.23)(react@18.3.1)': dependencies: react: 18.3.1 optionalDependencies: '@types/react': 18.3.23 + '@radix-ui/react-context@1.1.2(@types/react@18.3.23)(react@18.3.1)': + dependencies: + react: 18.3.1 + optionalDependencies: + '@types/react': 18.3.23 + + '@radix-ui/react-dialog@1.1.14(@types/react-dom@18.3.7(@types/react@18.3.23))(@types/react@18.3.23)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + dependencies: + '@radix-ui/primitive': 1.1.2 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.23)(react@18.3.1) + '@radix-ui/react-context': 1.1.2(@types/react@18.3.23)(react@18.3.1) + '@radix-ui/react-dismissable-layer': 1.1.10(@types/react-dom@18.3.7(@types/react@18.3.23))(@types/react@18.3.23)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-focus-guards': 1.1.2(@types/react@18.3.23)(react@18.3.1) + '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@18.3.7(@types/react@18.3.23))(@types/react@18.3.23)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-id': 1.1.1(@types/react@18.3.23)(react@18.3.1) + '@radix-ui/react-portal': 1.1.9(@types/react-dom@18.3.7(@types/react@18.3.23))(@types/react@18.3.23)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-presence': 1.1.4(@types/react-dom@18.3.7(@types/react@18.3.23))(@types/react@18.3.23)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.23))(@types/react@18.3.23)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-slot': 1.2.3(@types/react@18.3.23)(react@18.3.1) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.3.23)(react@18.3.1) + aria-hidden: 1.2.6 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + react-remove-scroll: 2.7.1(@types/react@18.3.23)(react@18.3.1) + optionalDependencies: + '@types/react': 18.3.23 + '@types/react-dom': 18.3.7(@types/react@18.3.23) + + '@radix-ui/react-direction@1.1.1(@types/react@18.3.23)(react@18.3.1)': + dependencies: + react: 18.3.1 + optionalDependencies: + '@types/react': 18.3.23 + + '@radix-ui/react-dismissable-layer@1.1.10(@types/react-dom@18.3.7(@types/react@18.3.23))(@types/react@18.3.23)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + dependencies: + '@radix-ui/primitive': 1.1.2 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.23)(react@18.3.1) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.23))(@types/react@18.3.23)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@18.3.23)(react@18.3.1) + '@radix-ui/react-use-escape-keydown': 1.1.1(@types/react@18.3.23)(react@18.3.1) + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + optionalDependencies: + '@types/react': 18.3.23 + '@types/react-dom': 18.3.7(@types/react@18.3.23) + + '@radix-ui/react-dropdown-menu@2.1.15(@types/react-dom@18.3.7(@types/react@18.3.23))(@types/react@18.3.23)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + dependencies: + '@radix-ui/primitive': 1.1.2 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.23)(react@18.3.1) + '@radix-ui/react-context': 1.1.2(@types/react@18.3.23)(react@18.3.1) + '@radix-ui/react-id': 1.1.1(@types/react@18.3.23)(react@18.3.1) + '@radix-ui/react-menu': 2.1.15(@types/react-dom@18.3.7(@types/react@18.3.23))(@types/react@18.3.23)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.23))(@types/react@18.3.23)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.3.23)(react@18.3.1) + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + optionalDependencies: + '@types/react': 18.3.23 + '@types/react-dom': 18.3.7(@types/react@18.3.23) + + '@radix-ui/react-focus-guards@1.1.2(@types/react@18.3.23)(react@18.3.1)': + dependencies: + react: 18.3.1 + optionalDependencies: + '@types/react': 18.3.23 + + '@radix-ui/react-focus-scope@1.1.7(@types/react-dom@18.3.7(@types/react@18.3.23))(@types/react@18.3.23)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + dependencies: + '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.23)(react@18.3.1) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.23))(@types/react@18.3.23)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@18.3.23)(react@18.3.1) + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + optionalDependencies: + '@types/react': 18.3.23 + '@types/react-dom': 18.3.7(@types/react@18.3.23) + + '@radix-ui/react-icons@1.3.2(react@18.3.1)': + dependencies: + react: 18.3.1 + + '@radix-ui/react-id@1.1.1(@types/react@18.3.23)(react@18.3.1)': + dependencies: + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.3.23)(react@18.3.1) + react: 18.3.1 + optionalDependencies: + '@types/react': 18.3.23 + + '@radix-ui/react-label@2.1.7(@types/react-dom@18.3.7(@types/react@18.3.23))(@types/react@18.3.23)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + dependencies: + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.23))(@types/react@18.3.23)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + optionalDependencies: + '@types/react': 18.3.23 + '@types/react-dom': 18.3.7(@types/react@18.3.23) + + '@radix-ui/react-menu@2.1.15(@types/react-dom@18.3.7(@types/react@18.3.23))(@types/react@18.3.23)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + dependencies: + '@radix-ui/primitive': 1.1.2 + '@radix-ui/react-collection': 1.1.7(@types/react-dom@18.3.7(@types/react@18.3.23))(@types/react@18.3.23)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.23)(react@18.3.1) + '@radix-ui/react-context': 1.1.2(@types/react@18.3.23)(react@18.3.1) + '@radix-ui/react-direction': 1.1.1(@types/react@18.3.23)(react@18.3.1) + '@radix-ui/react-dismissable-layer': 1.1.10(@types/react-dom@18.3.7(@types/react@18.3.23))(@types/react@18.3.23)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-focus-guards': 1.1.2(@types/react@18.3.23)(react@18.3.1) + '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@18.3.7(@types/react@18.3.23))(@types/react@18.3.23)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-id': 1.1.1(@types/react@18.3.23)(react@18.3.1) + '@radix-ui/react-popper': 1.2.7(@types/react-dom@18.3.7(@types/react@18.3.23))(@types/react@18.3.23)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-portal': 1.1.9(@types/react-dom@18.3.7(@types/react@18.3.23))(@types/react@18.3.23)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-presence': 1.1.4(@types/react-dom@18.3.7(@types/react@18.3.23))(@types/react@18.3.23)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.23))(@types/react@18.3.23)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-roving-focus': 1.1.10(@types/react-dom@18.3.7(@types/react@18.3.23))(@types/react@18.3.23)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-slot': 1.2.3(@types/react@18.3.23)(react@18.3.1) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@18.3.23)(react@18.3.1) + aria-hidden: 1.2.6 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + react-remove-scroll: 2.7.1(@types/react@18.3.23)(react@18.3.1) + optionalDependencies: + '@types/react': 18.3.23 + '@types/react-dom': 18.3.7(@types/react@18.3.23) + + '@radix-ui/react-popover@1.1.14(@types/react-dom@18.3.7(@types/react@18.3.23))(@types/react@18.3.23)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + dependencies: + '@radix-ui/primitive': 1.1.2 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.23)(react@18.3.1) + '@radix-ui/react-context': 1.1.2(@types/react@18.3.23)(react@18.3.1) + '@radix-ui/react-dismissable-layer': 1.1.10(@types/react-dom@18.3.7(@types/react@18.3.23))(@types/react@18.3.23)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-focus-guards': 1.1.2(@types/react@18.3.23)(react@18.3.1) + '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@18.3.7(@types/react@18.3.23))(@types/react@18.3.23)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-id': 1.1.1(@types/react@18.3.23)(react@18.3.1) + '@radix-ui/react-popper': 1.2.7(@types/react-dom@18.3.7(@types/react@18.3.23))(@types/react@18.3.23)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-portal': 1.1.9(@types/react-dom@18.3.7(@types/react@18.3.23))(@types/react@18.3.23)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-presence': 1.1.4(@types/react-dom@18.3.7(@types/react@18.3.23))(@types/react@18.3.23)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.23))(@types/react@18.3.23)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-slot': 1.2.3(@types/react@18.3.23)(react@18.3.1) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.3.23)(react@18.3.1) + aria-hidden: 1.2.6 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + react-remove-scroll: 2.7.1(@types/react@18.3.23)(react@18.3.1) + optionalDependencies: + '@types/react': 18.3.23 + '@types/react-dom': 18.3.7(@types/react@18.3.23) + + '@radix-ui/react-popper@1.2.7(@types/react-dom@18.3.7(@types/react@18.3.23))(@types/react@18.3.23)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + dependencies: + '@floating-ui/react-dom': 2.1.3(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-arrow': 1.1.7(@types/react-dom@18.3.7(@types/react@18.3.23))(@types/react@18.3.23)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.23)(react@18.3.1) + '@radix-ui/react-context': 1.1.2(@types/react@18.3.23)(react@18.3.1) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.23))(@types/react@18.3.23)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@18.3.23)(react@18.3.1) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.3.23)(react@18.3.1) + '@radix-ui/react-use-rect': 1.1.1(@types/react@18.3.23)(react@18.3.1) + '@radix-ui/react-use-size': 1.1.1(@types/react@18.3.23)(react@18.3.1) + '@radix-ui/rect': 1.1.1 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + optionalDependencies: + '@types/react': 18.3.23 + '@types/react-dom': 18.3.7(@types/react@18.3.23) + + '@radix-ui/react-portal@1.1.9(@types/react-dom@18.3.7(@types/react@18.3.23))(@types/react@18.3.23)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + dependencies: + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.23))(@types/react@18.3.23)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.3.23)(react@18.3.1) + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + optionalDependencies: + '@types/react': 18.3.23 + '@types/react-dom': 18.3.7(@types/react@18.3.23) + + '@radix-ui/react-presence@1.1.4(@types/react-dom@18.3.7(@types/react@18.3.23))(@types/react@18.3.23)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + dependencies: + '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.23)(react@18.3.1) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.3.23)(react@18.3.1) + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + optionalDependencies: + '@types/react': 18.3.23 + '@types/react-dom': 18.3.7(@types/react@18.3.23) + + '@radix-ui/react-primitive@2.1.3(@types/react-dom@18.3.7(@types/react@18.3.23))(@types/react@18.3.23)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + dependencies: + '@radix-ui/react-slot': 1.2.3(@types/react@18.3.23)(react@18.3.1) + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + optionalDependencies: + '@types/react': 18.3.23 + '@types/react-dom': 18.3.7(@types/react@18.3.23) + + '@radix-ui/react-roving-focus@1.1.10(@types/react-dom@18.3.7(@types/react@18.3.23))(@types/react@18.3.23)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + dependencies: + '@radix-ui/primitive': 1.1.2 + '@radix-ui/react-collection': 1.1.7(@types/react-dom@18.3.7(@types/react@18.3.23))(@types/react@18.3.23)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.23)(react@18.3.1) + '@radix-ui/react-context': 1.1.2(@types/react@18.3.23)(react@18.3.1) + '@radix-ui/react-direction': 1.1.1(@types/react@18.3.23)(react@18.3.1) + '@radix-ui/react-id': 1.1.1(@types/react@18.3.23)(react@18.3.1) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.23))(@types/react@18.3.23)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@18.3.23)(react@18.3.1) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.3.23)(react@18.3.1) + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + optionalDependencies: + '@types/react': 18.3.23 + '@types/react-dom': 18.3.7(@types/react@18.3.23) + + '@radix-ui/react-scroll-area@1.2.9(@types/react-dom@18.3.7(@types/react@18.3.23))(@types/react@18.3.23)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + dependencies: + '@radix-ui/number': 1.1.1 + '@radix-ui/primitive': 1.1.2 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.23)(react@18.3.1) + '@radix-ui/react-context': 1.1.2(@types/react@18.3.23)(react@18.3.1) + '@radix-ui/react-direction': 1.1.1(@types/react@18.3.23)(react@18.3.1) + '@radix-ui/react-presence': 1.1.4(@types/react-dom@18.3.7(@types/react@18.3.23))(@types/react@18.3.23)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.23))(@types/react@18.3.23)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@18.3.23)(react@18.3.1) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.3.23)(react@18.3.1) + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + optionalDependencies: + '@types/react': 18.3.23 + '@types/react-dom': 18.3.7(@types/react@18.3.23) + + '@radix-ui/react-select@2.2.5(@types/react-dom@18.3.7(@types/react@18.3.23))(@types/react@18.3.23)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + dependencies: + '@radix-ui/number': 1.1.1 + '@radix-ui/primitive': 1.1.2 + '@radix-ui/react-collection': 1.1.7(@types/react-dom@18.3.7(@types/react@18.3.23))(@types/react@18.3.23)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.23)(react@18.3.1) + '@radix-ui/react-context': 1.1.2(@types/react@18.3.23)(react@18.3.1) + '@radix-ui/react-direction': 1.1.1(@types/react@18.3.23)(react@18.3.1) + '@radix-ui/react-dismissable-layer': 1.1.10(@types/react-dom@18.3.7(@types/react@18.3.23))(@types/react@18.3.23)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-focus-guards': 1.1.2(@types/react@18.3.23)(react@18.3.1) + '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@18.3.7(@types/react@18.3.23))(@types/react@18.3.23)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-id': 1.1.1(@types/react@18.3.23)(react@18.3.1) + '@radix-ui/react-popper': 1.2.7(@types/react-dom@18.3.7(@types/react@18.3.23))(@types/react@18.3.23)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-portal': 1.1.9(@types/react-dom@18.3.7(@types/react@18.3.23))(@types/react@18.3.23)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.23))(@types/react@18.3.23)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-slot': 1.2.3(@types/react@18.3.23)(react@18.3.1) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@18.3.23)(react@18.3.1) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.3.23)(react@18.3.1) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.3.23)(react@18.3.1) + '@radix-ui/react-use-previous': 1.1.1(@types/react@18.3.23)(react@18.3.1) + '@radix-ui/react-visually-hidden': 1.2.3(@types/react-dom@18.3.7(@types/react@18.3.23))(@types/react@18.3.23)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + aria-hidden: 1.2.6 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + react-remove-scroll: 2.7.1(@types/react@18.3.23)(react@18.3.1) + optionalDependencies: + '@types/react': 18.3.23 + '@types/react-dom': 18.3.7(@types/react@18.3.23) + + '@radix-ui/react-separator@1.1.7(@types/react-dom@18.3.7(@types/react@18.3.23))(@types/react@18.3.23)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + dependencies: + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.23))(@types/react@18.3.23)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + optionalDependencies: + '@types/react': 18.3.23 + '@types/react-dom': 18.3.7(@types/react@18.3.23) + '@radix-ui/react-slot@1.2.3(@types/react@18.3.23)(react@18.3.1)': dependencies: '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.23)(react@18.3.1) @@ -6815,6 +8097,149 @@ snapshots: optionalDependencies: '@types/react': 18.3.23 + '@radix-ui/react-switch@1.2.5(@types/react-dom@18.3.7(@types/react@18.3.23))(@types/react@18.3.23)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + dependencies: + '@radix-ui/primitive': 1.1.2 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.23)(react@18.3.1) + '@radix-ui/react-context': 1.1.2(@types/react@18.3.23)(react@18.3.1) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.23))(@types/react@18.3.23)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.3.23)(react@18.3.1) + '@radix-ui/react-use-previous': 1.1.1(@types/react@18.3.23)(react@18.3.1) + '@radix-ui/react-use-size': 1.1.1(@types/react@18.3.23)(react@18.3.1) + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + optionalDependencies: + '@types/react': 18.3.23 + '@types/react-dom': 18.3.7(@types/react@18.3.23) + + '@radix-ui/react-tabs@1.1.12(@types/react-dom@18.3.7(@types/react@18.3.23))(@types/react@18.3.23)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + dependencies: + '@radix-ui/primitive': 1.1.2 + '@radix-ui/react-context': 1.1.2(@types/react@18.3.23)(react@18.3.1) + '@radix-ui/react-direction': 1.1.1(@types/react@18.3.23)(react@18.3.1) + '@radix-ui/react-id': 1.1.1(@types/react@18.3.23)(react@18.3.1) + '@radix-ui/react-presence': 1.1.4(@types/react-dom@18.3.7(@types/react@18.3.23))(@types/react@18.3.23)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.23))(@types/react@18.3.23)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-roving-focus': 1.1.10(@types/react-dom@18.3.7(@types/react@18.3.23))(@types/react@18.3.23)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.3.23)(react@18.3.1) + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + optionalDependencies: + '@types/react': 18.3.23 + '@types/react-dom': 18.3.7(@types/react@18.3.23) + + '@radix-ui/react-toast@1.2.14(@types/react-dom@18.3.7(@types/react@18.3.23))(@types/react@18.3.23)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + dependencies: + '@radix-ui/primitive': 1.1.2 + '@radix-ui/react-collection': 1.1.7(@types/react-dom@18.3.7(@types/react@18.3.23))(@types/react@18.3.23)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.23)(react@18.3.1) + '@radix-ui/react-context': 1.1.2(@types/react@18.3.23)(react@18.3.1) + '@radix-ui/react-dismissable-layer': 1.1.10(@types/react-dom@18.3.7(@types/react@18.3.23))(@types/react@18.3.23)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-portal': 1.1.9(@types/react-dom@18.3.7(@types/react@18.3.23))(@types/react@18.3.23)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-presence': 1.1.4(@types/react-dom@18.3.7(@types/react@18.3.23))(@types/react@18.3.23)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.23))(@types/react@18.3.23)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@18.3.23)(react@18.3.1) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.3.23)(react@18.3.1) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.3.23)(react@18.3.1) + '@radix-ui/react-visually-hidden': 1.2.3(@types/react-dom@18.3.7(@types/react@18.3.23))(@types/react@18.3.23)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + optionalDependencies: + '@types/react': 18.3.23 + '@types/react-dom': 18.3.7(@types/react@18.3.23) + + '@radix-ui/react-tooltip@1.2.7(@types/react-dom@18.3.7(@types/react@18.3.23))(@types/react@18.3.23)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + dependencies: + '@radix-ui/primitive': 1.1.2 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.23)(react@18.3.1) + '@radix-ui/react-context': 1.1.2(@types/react@18.3.23)(react@18.3.1) + '@radix-ui/react-dismissable-layer': 1.1.10(@types/react-dom@18.3.7(@types/react@18.3.23))(@types/react@18.3.23)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-id': 1.1.1(@types/react@18.3.23)(react@18.3.1) + '@radix-ui/react-popper': 1.2.7(@types/react-dom@18.3.7(@types/react@18.3.23))(@types/react@18.3.23)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-portal': 1.1.9(@types/react-dom@18.3.7(@types/react@18.3.23))(@types/react@18.3.23)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-presence': 1.1.4(@types/react-dom@18.3.7(@types/react@18.3.23))(@types/react@18.3.23)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.23))(@types/react@18.3.23)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-slot': 1.2.3(@types/react@18.3.23)(react@18.3.1) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.3.23)(react@18.3.1) + '@radix-ui/react-visually-hidden': 1.2.3(@types/react-dom@18.3.7(@types/react@18.3.23))(@types/react@18.3.23)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + optionalDependencies: + '@types/react': 18.3.23 + '@types/react-dom': 18.3.7(@types/react@18.3.23) + + '@radix-ui/react-use-callback-ref@1.1.1(@types/react@18.3.23)(react@18.3.1)': + dependencies: + react: 18.3.1 + optionalDependencies: + '@types/react': 18.3.23 + + '@radix-ui/react-use-controllable-state@1.2.2(@types/react@18.3.23)(react@18.3.1)': + dependencies: + '@radix-ui/react-use-effect-event': 0.0.2(@types/react@18.3.23)(react@18.3.1) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.3.23)(react@18.3.1) + react: 18.3.1 + optionalDependencies: + '@types/react': 18.3.23 + + '@radix-ui/react-use-effect-event@0.0.2(@types/react@18.3.23)(react@18.3.1)': + dependencies: + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.3.23)(react@18.3.1) + react: 18.3.1 + optionalDependencies: + '@types/react': 18.3.23 + + '@radix-ui/react-use-escape-keydown@1.1.1(@types/react@18.3.23)(react@18.3.1)': + dependencies: + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@18.3.23)(react@18.3.1) + react: 18.3.1 + optionalDependencies: + '@types/react': 18.3.23 + + '@radix-ui/react-use-is-hydrated@0.1.0(@types/react@18.3.23)(react@18.3.1)': + dependencies: + react: 18.3.1 + use-sync-external-store: 1.5.0(react@18.3.1) + optionalDependencies: + '@types/react': 18.3.23 + + '@radix-ui/react-use-layout-effect@1.1.1(@types/react@18.3.23)(react@18.3.1)': + dependencies: + react: 18.3.1 + optionalDependencies: + '@types/react': 18.3.23 + + '@radix-ui/react-use-previous@1.1.1(@types/react@18.3.23)(react@18.3.1)': + dependencies: + react: 18.3.1 + optionalDependencies: + '@types/react': 18.3.23 + + '@radix-ui/react-use-rect@1.1.1(@types/react@18.3.23)(react@18.3.1)': + dependencies: + '@radix-ui/rect': 1.1.1 + react: 18.3.1 + optionalDependencies: + '@types/react': 18.3.23 + + '@radix-ui/react-use-size@1.1.1(@types/react@18.3.23)(react@18.3.1)': + dependencies: + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.3.23)(react@18.3.1) + react: 18.3.1 + optionalDependencies: + '@types/react': 18.3.23 + + '@radix-ui/react-visually-hidden@1.2.3(@types/react-dom@18.3.7(@types/react@18.3.23))(@types/react@18.3.23)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + dependencies: + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.23))(@types/react@18.3.23)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + optionalDependencies: + '@types/react': 18.3.23 + '@types/react-dom': 18.3.7(@types/react@18.3.23) + + '@radix-ui/rect@1.1.1': {} + '@remix-run/changelog-github@0.0.5': dependencies: '@changesets/errors': 0.1.4 @@ -7268,6 +8693,123 @@ snapshots: '@types/cookie@0.6.0': {} + '@types/d3-array@3.2.1': {} + + '@types/d3-axis@3.0.6': + dependencies: + '@types/d3-selection': 3.0.11 + + '@types/d3-brush@3.0.6': + dependencies: + '@types/d3-selection': 3.0.11 + + '@types/d3-chord@3.0.6': {} + + '@types/d3-color@3.1.3': {} + + '@types/d3-contour@3.0.6': + dependencies: + '@types/d3-array': 3.2.1 + '@types/geojson': 7946.0.16 + + '@types/d3-delaunay@6.0.4': {} + + '@types/d3-dispatch@3.0.6': {} + + '@types/d3-drag@3.0.7': + dependencies: + '@types/d3-selection': 3.0.11 + + '@types/d3-dsv@3.0.7': {} + + '@types/d3-ease@3.0.2': {} + + '@types/d3-fetch@3.0.7': + dependencies: + '@types/d3-dsv': 3.0.7 + + '@types/d3-force@3.0.10': {} + + '@types/d3-format@3.0.4': {} + + '@types/d3-geo@3.1.0': + dependencies: + '@types/geojson': 7946.0.16 + + '@types/d3-hierarchy@3.1.7': {} + + '@types/d3-interpolate@3.0.4': + dependencies: + '@types/d3-color': 3.1.3 + + '@types/d3-path@3.1.1': {} + + '@types/d3-polygon@3.0.2': {} + + '@types/d3-quadtree@3.0.6': {} + + '@types/d3-random@3.0.3': {} + + '@types/d3-scale-chromatic@3.1.0': {} + + '@types/d3-scale@4.0.9': + dependencies: + '@types/d3-time': 3.0.4 + + '@types/d3-selection@3.0.11': {} + + '@types/d3-shape@3.1.7': + dependencies: + '@types/d3-path': 3.1.1 + + '@types/d3-time-format@4.0.3': {} + + '@types/d3-time@3.0.4': {} + + '@types/d3-timer@3.0.2': {} + + '@types/d3-transition@3.0.9': + dependencies: + '@types/d3-selection': 3.0.11 + + '@types/d3-zoom@3.0.8': + dependencies: + '@types/d3-interpolate': 3.0.4 + '@types/d3-selection': 3.0.11 + + '@types/d3@7.4.3': + dependencies: + '@types/d3-array': 3.2.1 + '@types/d3-axis': 3.0.6 + '@types/d3-brush': 3.0.6 + '@types/d3-chord': 3.0.6 + '@types/d3-color': 3.1.3 + '@types/d3-contour': 3.0.6 + '@types/d3-delaunay': 6.0.4 + '@types/d3-dispatch': 3.0.6 + '@types/d3-drag': 3.0.7 + '@types/d3-dsv': 3.0.7 + '@types/d3-ease': 3.0.2 + '@types/d3-fetch': 3.0.7 + '@types/d3-force': 3.0.10 + '@types/d3-format': 3.0.4 + '@types/d3-geo': 3.1.0 + '@types/d3-hierarchy': 3.1.7 + '@types/d3-interpolate': 3.0.4 + '@types/d3-path': 3.1.1 + '@types/d3-polygon': 3.0.2 + '@types/d3-quadtree': 3.0.6 + '@types/d3-random': 3.0.3 + '@types/d3-scale': 4.0.9 + '@types/d3-scale-chromatic': 3.1.0 + '@types/d3-selection': 3.0.11 + '@types/d3-shape': 3.1.7 + '@types/d3-time': 3.0.4 + '@types/d3-time-format': 4.0.3 + '@types/d3-timer': 3.0.2 + '@types/d3-transition': 3.0.9 + '@types/d3-zoom': 3.0.8 + '@types/debug@4.1.12': dependencies: '@types/ms': 2.1.0 @@ -7294,6 +8836,8 @@ snapshots: '@types/qs': 6.14.0 '@types/serve-static': 1.15.7 + '@types/geojson@7946.0.16': {} + '@types/hast@2.3.10': dependencies: '@types/unist': 2.0.11 @@ -7732,6 +9276,10 @@ snapshots: argparse@2.0.1: {} + aria-hidden@1.2.6: + dependencies: + tslib: 2.8.1 + aria-query@5.1.3: dependencies: deep-equal: 2.2.3 @@ -8085,6 +9633,8 @@ snapshots: commander@5.1.0: {} + commander@7.2.0: {} + compressible@2.0.18: dependencies: mime-db: 1.54.0 @@ -8190,6 +9740,158 @@ snapshots: csv-stringify: 5.6.5 stream-transform: 2.1.3 + d3-array@3.2.4: + dependencies: + internmap: 2.0.3 + + d3-axis@3.0.0: {} + + d3-brush@3.0.0: + dependencies: + d3-dispatch: 3.0.1 + d3-drag: 3.0.0 + d3-interpolate: 3.0.1 + d3-selection: 3.0.0 + d3-transition: 3.0.1(d3-selection@3.0.0) + + d3-chord@3.0.1: + dependencies: + d3-path: 3.1.0 + + d3-color@3.1.0: {} + + d3-contour@4.0.2: + dependencies: + d3-array: 3.2.4 + + d3-delaunay@6.0.4: + dependencies: + delaunator: 5.0.1 + + d3-dispatch@3.0.1: {} + + d3-drag@3.0.0: + dependencies: + d3-dispatch: 3.0.1 + d3-selection: 3.0.0 + + d3-dsv@3.0.1: + dependencies: + commander: 7.2.0 + iconv-lite: 0.6.3 + rw: 1.3.3 + + d3-ease@3.0.1: {} + + d3-fetch@3.0.1: + dependencies: + d3-dsv: 3.0.1 + + d3-force@3.0.0: + dependencies: + d3-dispatch: 3.0.1 + d3-quadtree: 3.0.1 + d3-timer: 3.0.1 + + d3-format@3.1.0: {} + + d3-geo@3.1.1: + dependencies: + d3-array: 3.2.4 + + d3-hierarchy@3.1.2: {} + + d3-interpolate@3.0.1: + dependencies: + d3-color: 3.1.0 + + d3-path@3.1.0: {} + + d3-polygon@3.0.1: {} + + d3-quadtree@3.0.1: {} + + d3-random@3.0.1: {} + + d3-scale-chromatic@3.1.0: + dependencies: + d3-color: 3.1.0 + d3-interpolate: 3.0.1 + + d3-scale@4.0.2: + dependencies: + d3-array: 3.2.4 + d3-format: 3.1.0 + d3-interpolate: 3.0.1 + d3-time: 3.1.0 + d3-time-format: 4.1.0 + + d3-selection@3.0.0: {} + + d3-shape@3.2.0: + dependencies: + d3-path: 3.1.0 + + d3-time-format@4.1.0: + dependencies: + d3-time: 3.1.0 + + d3-time@3.1.0: + dependencies: + d3-array: 3.2.4 + + d3-timer@3.0.1: {} + + d3-transition@3.0.1(d3-selection@3.0.0): + dependencies: + d3-color: 3.1.0 + d3-dispatch: 3.0.1 + d3-ease: 3.0.1 + d3-interpolate: 3.0.1 + d3-selection: 3.0.0 + d3-timer: 3.0.1 + + d3-zoom@3.0.0: + dependencies: + d3-dispatch: 3.0.1 + d3-drag: 3.0.0 + d3-interpolate: 3.0.1 + d3-selection: 3.0.0 + d3-transition: 3.0.1(d3-selection@3.0.0) + + d3@7.9.0: + dependencies: + d3-array: 3.2.4 + d3-axis: 3.0.0 + d3-brush: 3.0.0 + d3-chord: 3.0.1 + d3-color: 3.1.0 + d3-contour: 4.0.2 + d3-delaunay: 6.0.4 + d3-dispatch: 3.0.1 + d3-drag: 3.0.0 + d3-dsv: 3.0.1 + d3-ease: 3.0.1 + d3-fetch: 3.0.1 + d3-force: 3.0.0 + d3-format: 3.1.0 + d3-geo: 3.1.1 + d3-hierarchy: 3.1.2 + d3-interpolate: 3.0.1 + d3-path: 3.1.0 + d3-polygon: 3.0.1 + d3-quadtree: 3.0.1 + d3-random: 3.0.1 + d3-scale: 4.0.2 + d3-scale-chromatic: 3.1.0 + d3-selection: 3.0.0 + d3-shape: 3.2.0 + d3-time: 3.1.0 + d3-time-format: 4.1.0 + d3-timer: 3.0.1 + d3-transition: 3.0.1(d3-selection@3.0.0) + d3-zoom: 3.0.0 + damerau-levenshtein@1.0.8: {} data-uri-to-buffer@3.0.1: {} @@ -8214,6 +9916,8 @@ snapshots: dataloader@1.4.0: {} + dayjs@1.11.13: {} + debug@2.6.9: dependencies: ms: 2.0.0 @@ -8284,6 +9988,10 @@ snapshots: defined@1.0.1: {} + delaunator@5.0.1: + dependencies: + robust-predicates: 3.0.2 + denque@2.1.0: {} depd@2.0.0: {} @@ -8296,6 +10004,8 @@ snapshots: detect-libc@2.0.4: {} + detect-node-es@1.1.0: {} + detective@5.2.1: dependencies: acorn-node: 1.8.2 @@ -9226,6 +10936,8 @@ snapshots: hasown: 2.0.2 math-intrinsics: 1.1.0 + get-nonce@1.0.1: {} + get-port@5.1.1: {} get-proto@1.0.1: @@ -9391,6 +11103,10 @@ snapshots: dependencies: safer-buffer: 2.1.2 + iconv-lite@0.6.3: + dependencies: + safer-buffer: 2.1.2 + icss-utils@5.1.0(postcss@8.5.3): dependencies: postcss: 8.5.3 @@ -9423,6 +11139,8 @@ snapshots: hasown: 2.0.2 side-channel: 1.1.0 + internmap@2.0.3: {} + ioredis@5.6.1: dependencies: '@ioredis/commands': 1.2.0 @@ -10892,6 +12610,25 @@ snapshots: react-refresh@0.14.2: {} + react-remove-scroll-bar@2.3.8(@types/react@18.3.23)(react@18.3.1): + dependencies: + react: 18.3.1 + react-style-singleton: 2.2.3(@types/react@18.3.23)(react@18.3.1) + tslib: 2.8.1 + optionalDependencies: + '@types/react': 18.3.23 + + react-remove-scroll@2.7.1(@types/react@18.3.23)(react@18.3.1): + dependencies: + react: 18.3.1 + react-remove-scroll-bar: 2.3.8(@types/react@18.3.23)(react@18.3.1) + react-style-singleton: 2.2.3(@types/react@18.3.23)(react@18.3.1) + tslib: 2.8.1 + use-callback-ref: 1.3.3(@types/react@18.3.23)(react@18.3.1) + use-sidecar: 1.1.3(@types/react@18.3.23)(react@18.3.1) + optionalDependencies: + '@types/react': 18.3.23 + react-router-dom@6.30.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1): dependencies: '@remix-run/router': 1.23.0 @@ -10904,6 +12641,14 @@ snapshots: '@remix-run/router': 1.23.0 react: 18.3.1 + react-style-singleton@2.2.3(@types/react@18.3.23)(react@18.3.1): + dependencies: + get-nonce: 1.0.1 + react: 18.3.1 + tslib: 2.8.1 + optionalDependencies: + '@types/react': 18.3.23 + react@18.3.1: dependencies: loose-envify: 1.4.0 @@ -11102,6 +12847,8 @@ snapshots: glob: 11.0.2 package-json-from-dist: 1.0.1 + robust-predicates@3.0.2: {} + rollup@4.41.1: dependencies: '@types/estree': 1.0.7 @@ -11132,6 +12879,8 @@ snapshots: dependencies: queue-microtask: 1.2.3 + rw@1.3.3: {} + rxjs@7.8.2: dependencies: tslib: 2.8.1 @@ -11816,6 +13565,21 @@ snapshots: dependencies: punycode: 2.3.1 + use-callback-ref@1.3.3(@types/react@18.3.23)(react@18.3.1): + dependencies: + react: 18.3.1 + tslib: 2.8.1 + optionalDependencies: + '@types/react': 18.3.23 + + use-sidecar@1.1.3(@types/react@18.3.23)(react@18.3.1): + dependencies: + detect-node-es: 1.1.0 + react: 18.3.1 + tslib: 2.8.1 + optionalDependencies: + '@types/react': 18.3.23 + use-sync-external-store@1.5.0(react@18.3.1): dependencies: react: 18.3.1