Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion components/ColorMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export default function ColorMenu(props: {
}) {
const [customColor, setCustomColor] = useState(props.currentColor);
const [sliderPosition, setSliderPosition] = useState(0);
const [shouldSmoothAnimate, setShouldSmoothAnimate] = useState(false);
const gradientRef = useRef<HTMLDivElement>(null);
const isDraggingRef = useRef(false);

Expand Down Expand Up @@ -175,6 +176,10 @@ export default function ColorMenu(props: {
const x = e.clientX - rect.left;

// Immediately update slider position and color
setShouldSmoothAnimate(true);
setTimeout(() => {
setShouldSmoothAnimate(false);
}, 100);
setSliderPosition(x);
processColorAtPosition(x);

Expand Down Expand Up @@ -254,7 +259,11 @@ export default function ColorMenu(props: {
/>
{/* Slider indicator */}
<div
className="absolute top-0 w-2 h-8 bg-white border border-gray-800 rounded-sm cursor-grab active:cursor-grabbing"
className={`absolute top-0 w-2 h-8 bg-white border border-gray-800 rounded-sm cursor-grab active:cursor-grabbing ${
shouldSmoothAnimate
? "transition-all duration-100"
: "transition-none"
}`}
style={{
left: `${sliderPosition}px`,
transform: "translateX(-50%)",
Expand Down
51 changes: 51 additions & 0 deletions components/ControlButtons.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
"use client";
import { IconButton, Tooltip } from "@mui/material";
import { Panel } from "@xyflow/react";
import { Card } from "@/components/ui/card";
import EventSettings from "@/components/EventSettings";
import { Event, Location } from "@prisma/client";
import { useRouter } from "next/navigation";
import { Undo, Redo, Save, Home } from "lucide-react";

export default function ControlButtons(props: {
undo: () => void;
redo: () => void;
event: Event;
eventLocations: Location[];
}) {
const isMobile = /Mobi|Android/i.test(navigator?.userAgent);

const { event, eventLocations } = props;
const router = useRouter();

return (
<Panel position="top-right">
<Card className={`flex flex-${isMobile ? "col" : "row"} justify-center`}>
<Tooltip title="Undo">
<IconButton onClick={props.undo} style={{ color: "black" }}>
<Undo />
</IconButton>
</Tooltip>
<Tooltip title="Redo">
<IconButton onClick={props.redo} style={{ color: "black" }}>
<Redo />
</IconButton>
</Tooltip>
<Tooltip title="Save">
<IconButton style={{ color: "black" }}>
<Save />
</IconButton>
</Tooltip>
<Tooltip title="Home">
<IconButton
onClick={() => router.push("/home")}
style={{ color: "black" }}
>
<Home />
</IconButton>
</Tooltip>
<EventSettings event={event} locations={eventLocations} />
</Card>
</Panel>
);
}
18 changes: 10 additions & 8 deletions components/EventFlow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ import { ActiveNodeContext, IconNode } from "@components/IconNode";
import { CustomImageNode } from "@components/CustomImageNode";
import Legend from "@components/Legend";
import EventMapSelect from "@components/EventMapSelect";
import StateButtons from "./stateButtons";
import ControlButtons from "./ControlButtons";

// Types
import { CustomNode } from "@/types/CustomNode";
Expand Down Expand Up @@ -451,9 +451,6 @@ function Flow({
return (
<ActiveNodeContext.Provider value={{ activeNodeId, setActiveNodeId }}>
<div style={{ width: "100vw", height: "100vh" }}>
<h1 className="fixed left-[50vw] -translate-x-1/2 flex space-x-4 content-center items-center justify-center z-10 bg-white py-2 px-3 mt-3 text-2xl rounded-xl border bg-card text-card-foreground shadow">
{event.name}
</h1>
<ReactFlow
nodes={nodes}
minZoom={0.1}
Expand All @@ -468,21 +465,26 @@ function Flow({
elementsSelectable={isEditable}
className="touch-none"
>
<Background color="#ccc" variant={BackgroundVariant.Dots} gap={144} size={12} />
<Controls position="bottom-right" showInteractive={false} />
<Background
color="#ccc"
variant={BackgroundVariant.Dots}
gap={144}
size={12}
/>
<Controls position="bottom-left" showInteractive={false} />

{/* Hide legend on view only mode */}
{isEditable && <Legend isGettingStarted={event.isGS} />}
{isEditable && (
<StateButtons
<ControlButtons
undo={onUndo}
redo={onRedo}
event={event}
eventLocations={eventLocations}
/>
)}

<EventMapSelect eventId={event.id} locations={eventLocations} />
<EventMapSelect eventName={event.name} eventId={event.id} locations={eventLocations} />
</ReactFlow>
</div>
</ActiveNodeContext.Provider>
Expand Down
123 changes: 80 additions & 43 deletions components/EventMapSelect.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,64 +11,101 @@ import { Location } from "@prisma/client";
import { Panel } from "@xyflow/react";
import { useParams, useRouter } from "next/navigation";
import { useState } from "react";
import NavButtons from "./navButtons";
import { IconButton, Tooltip } from "@mui/material";
import { ArrowBigLeftDash, ArrowBigRightDash } from "lucide-react";

interface EventMapsSelectProps {
eventName: string;
eventId: string;
locations: Location[];
}

export default function EventMapsSelect({
eventName,
eventId,
locations,
}: EventMapsSelectProps) {
const router = useRouter();
const params = useParams();

const [isOpen, setIsOpen] = useState(false);

const locationIds = locations.map((l) => l.id.toString());

function nextLocation(direction: "forward" | "backward") {
const currId = (params.locationId || locationIds[0]).toString();
const currIndex = locationIds.indexOf(currId) || 0;

const offset = direction === "forward" ? 1 : -1;
const newIndex =
(currIndex + offset + locationIds.length) % locationIds.length;

if (params.mode && params.eventId && locationIds[newIndex]) {
router.push(
`/event/${params.mode}/${params.eventId}/${locationIds[newIndex]}`
);
}
}

return (
<Panel position="bottom-left">
<div className="bg-white text-black p-4 flex flex-col rounded-xl border bg-card text-card-foreground shadow">
<NavButtons locations={locations} />
<Dialog open={isOpen} onOpenChange={setIsOpen}>
<DialogTrigger asChild>
<Button>Change Location</Button>
</DialogTrigger>
<DialogContent className="max-w-64">
<DialogHeader>
<DialogTitle>Choose a Different Map</DialogTitle>
</DialogHeader>
{locations
.filter((v) => v.id === params.locationId?.[0])
.map((location) => (
<fieldset
key={location.id}
className="border-2 border-black rounded pb-1.5 pt-0.25 text-sm text-center w-full"
>
<legend className="text-xs text-left ml-1 px-1 text-blue-500">
Current
</legend>
{location.name}
</fieldset>
))}
{locations
.filter((v) => v.id !== params.locationId?.[0])
.map((location) => (
<Button
key={location.id}
onClick={() => {
setIsOpen(false);
router.push(
`/event/${params.mode}/${eventId}/${location.id}`
);
}}
>
{location.name}
</Button>
))}
</DialogContent>
</Dialog>
<Panel position="bottom-right">
<div className="bg-white text-black p-3 flex flex-col items-center rounded-xl border bg-card text-card-foreground shadow">
<h1 className="text-center font-extrabold mb-2">{eventName}</h1>
<div className="flex flex-row items-center space-x-3">
<Tooltip title="Previous Location">
<IconButton
onClick={() => nextLocation("backward")}
style={{ color: "black" }}
>
<ArrowBigLeftDash />
</IconButton>
</Tooltip>
<Dialog open={isOpen} onOpenChange={setIsOpen}>
<DialogTrigger asChild>
<Button>Change Location</Button>
</DialogTrigger>
<DialogContent className="max-w-64">
<DialogHeader>
<DialogTitle>Choose a Different Map</DialogTitle>
</DialogHeader>
{locations
.filter((v) => v.id === params.locationId?.[0])
.map((location) => (
<fieldset
key={location.id}
className="border-2 border-black rounded pb-1.5 pt-0.25 text-sm text-center w-full"
>
<legend className="text-xs text-left ml-1 px-1 text-blue-500">
Current
</legend>
{location.name}
</fieldset>
))}
{locations
.filter((v) => v.id !== params.locationId?.[0])
.map((location) => (
<Button
key={location.id}
onClick={() => {
setIsOpen(false);
router.push(
`/event/${params.mode}/${eventId}/${location.id}`
);
}}
>
{location.name}
</Button>
))}
</DialogContent>
</Dialog>
<Tooltip title="Next Location">
<IconButton
onClick={() => nextLocation("forward")}
style={{ color: "black" }}
>
<ArrowBigRightDash />
</IconButton>
</Tooltip>
</div>
</div>
</Panel>
);
Expand Down
Loading
Loading