styles({ ...renderProps, className }),
)}
@@ -38,7 +38,7 @@ export function Tooltip({ children, ...props }: TooltipProps) {
width={8}
height={8}
viewBox="0 0 8 8"
- className="group-placement-left:-rotate-90 group-placement-right:rotate-90 group-placement-bottom:rotate-180 block fill-neutral-700 stroke-neutral-800 dark:fill-neutral-600 dark:stroke-white/10 forced-colors:fill-[Canvas] forced-colors:stroke-[ButtonBorder]"
+ className="group-placement-left:-rotate-90 group-placement-right:rotate-90 group-placement-bottom:rotate-180 block fill-white stroke-neutral-200 forced-colors:fill-[Canvas] forced-colors:stroke-[ButtonBorder]"
>
diff --git a/src/components/ui/EventFrame.tsx b/src/components/ui/EventFrame.tsx
new file mode 100644
index 0000000..185a0d9
--- /dev/null
+++ b/src/components/ui/EventFrame.tsx
@@ -0,0 +1,76 @@
+"use client";
+
+import { useState } from "react";
+import Link from "next/link";
+import Image from "next/image";
+import { TooltipTrigger, Focusable } from "react-aria-components";
+import { Tooltip } from "@/components/aria/Tooltip";
+
+type EventFrameProps = {
+ name: string;
+ href: string;
+ imageUrl: string;
+};
+
+const DISPLAY_NAME_MAX_LENGTH = 24;
+const LARGE_TEXT_MAX_LENGTH = 14;
+const TOOLTIP_OFFSET = -120;
+const FALLBACK_LOGO = "/favicon/45th-LogoBlue.svg";
+
+export default function EventFrame(props: EventFrameProps) {
+ const { name, href, imageUrl } = props;
+
+ const [hasImageError, setHasImageError] = useState(false);
+
+ const handleImageError = () => {
+ setHasImageError(true);
+ };
+
+ const isTruncated = name.length > DISPLAY_NAME_MAX_LENGTH;
+
+ const displayName = isTruncated ? name.slice(0, DISPLAY_NAME_MAX_LENGTH - 1) + "…" : name;
+
+ const nameClassName =
+ name.length <= LARGE_TEXT_MAX_LENGTH ? "text-textb" : "text-[14px] leading-[20px]";
+
+ const card = (
+
+
+ {hasImageError ? (
+
+ ) : (
+
+ )}
+
+
+
+
+ );
+
+ if (!isTruncated) {
+ return card;
+ }
+
+ return (
+
+ {card}
+
+ {name}
+
+
+ );
+}