diff --git a/src/components/Events.tsx b/src/components/Events.tsx
index b47043bf..4ca0057c 100644
--- a/src/components/Events.tsx
+++ b/src/components/Events.tsx
@@ -1,14 +1,15 @@
-import { useContext, useEffect, useState } from "react";
+import { useContext, useEffect, useRef, useState } from "react";
import { Dialog, DialogContent, DialogActions } from "@mui/material";
import { hasMeaningfulDescription, primaryEventLink, type EventItem } from "../store/eventsClient";
import {
displayTitle,
getUpcomingEvents,
groupIntoSections,
+ isEventPast,
type EventSection,
type UpcomingEvent,
} from "../utils/eventSections";
-import { copyAnchorLink } from "../utils/copyAnchorLink";
+import { copyAnchorLink, copyEventLink } from "../utils/copyAnchorLink";
import {
formatSpeakerList,
getDescriptionExcerpt,
@@ -22,6 +23,7 @@ import {
ChevronDown,
CloseIcon,
EventModalContext,
+ ShareIcon,
useCarouselScroll,
useEventDate,
type SelectedEvent,
@@ -171,6 +173,14 @@ function EventDetailsDialogBody({
} = useEventDate(event);
const { link: infoLink, label: infoLabel } = primaryEventLink(event, isPast);
const title = displayTitle(event);
+ const [copied, setCopied] = useState(false);
+
+ const handleCopyLink = async () => {
+ const ok = await copyEventLink(event.id);
+ if (!ok) return;
+ setCopied(true);
+ window.setTimeout(() => setCopied(false), COPIED_FEEDBACK_MS);
+ };
// MUI Dialog is kept for its focus trap, escape handling, and scroll lock;
// everything inside the paper is plain markup.
@@ -194,6 +204,24 @@ function EventDetailsDialogBody({
alt={title}
className="max-h-[70vh] w-auto max-w-full object-contain"
/>
+
+
+ {copied && (
+
+ Copied!
+
+ )}
+