Improved Sidebar styling

This commit is contained in:
Tim Howitz 2025-06-01 14:18:44 +01:00
parent f88f783de9
commit 6cd95fa0e4

View File

@ -1,124 +1,128 @@
import React, { Dispatch, SetStateAction, useEffect, useRef } from "react"; import React, { Dispatch, SetStateAction, useEffect, useRef } from "react";
import { TbHexagon } from "react-icons/tb"; import { TbHexagon } from "react-icons/tb";
import GeologicalEvent from "@appTypes/Event"; import GeologicalEvent from "@appTypes/GeologicalEvent";
import getMagnitudeColor from "@utils/getMagnitudeColour"; import getMagnitudeColor from "@utils/getMagnitudeColour";
interface SidebarProps { interface SidebarProps {
logTitle: string; logTitle: string;
logSubtitle: string; logSubtitle: string;
recentsTitle: string; recentsTitle: string;
events: GeologicalEvent[]; events: GeologicalEvent[];
selectedEventId: GeologicalEvent["id"]; selectedEventId: GeologicalEvent["id"];
setSelectedEventId: Dispatch<SetStateAction<string>>; setSelectedEventId: Dispatch<SetStateAction<string>>;
hoveredEventId: GeologicalEvent["id"]; hoveredEventId: GeologicalEvent["id"];
setHoveredEventId: Dispatch<SetStateAction<string>>; setHoveredEventId: Dispatch<SetStateAction<string>>;
button1Name: string; button1Name: string;
button2Name: string; button2Name: string;
onButton2Click?: () => void; onButton2Click?: () => void;
onButton1Click?: () => void; onButton1Click?: () => void;
button1Disabled?: boolean; button1Disabled?: boolean;
} }
function MagnitudeNumber({ magnitude }: { magnitude: number }) { function MagnitudeNumber({ magnitude }: { magnitude: number }) {
const magnitudeStr = magnitude.toFixed(1); const magnitudeStr = magnitude.toFixed(1);
const [whole, decimal] = magnitudeStr.split("."); const [whole, decimal] = magnitudeStr.split(".");
return ( return (
<div className="relative" style={{ color: getMagnitudeColor(magnitude) }}> <div className="relative" style={{ color: getMagnitudeColor(magnitude) }}>
<TbHexagon size={40} className="drop-shadow-sm" /> <TbHexagon size={40} className="drop-shadow-sm" />
<div className="absolute inset-0 flex items-center justify-center"> <div className="absolute inset-0 flex items-center justify-center">
<div className="flex items-baseline font-mono font-bold tracking-tight"> <div className="flex items-baseline font-mono font-bold tracking-tight">
<span className="text-xl -mr-1">{whole}</span> <span className="text-xl -mr-1">{whole}</span>
<span className="text-xs ml-[1.5px] -mr-[2.5px]">.</span> <span className="text-xs ml-[1.5px] -mr-[2.5px]">.</span>
<span className="text-xs -mr-[1px]">{decimal}</span> <span className="text-xs -mr-[1px]">{decimal}</span>
</div> </div>
</div> </div>
</div> </div>
); );
} }
export default function Sidebar({ export default function Sidebar({
logTitle, logTitle,
logSubtitle, logSubtitle,
recentsTitle, recentsTitle,
events, events,
selectedEventId, selectedEventId,
setSelectedEventId, setSelectedEventId,
hoveredEventId, hoveredEventId,
setHoveredEventId, setHoveredEventId,
button1Name, button1Name,
button2Name, button2Name,
onButton2Click, onButton2Click,
onButton1Click, onButton1Click,
button1Disabled = false, button1Disabled = false,
}: SidebarProps) { }: SidebarProps) {
const eventsContainerRef = useRef<HTMLDivElement>(null); const eventsContainerRef = useRef<HTMLDivElement>(null);
useEffect(() => { useEffect(() => {
if (selectedEventId && eventsContainerRef.current) { if (selectedEventId && eventsContainerRef.current) {
const selectedEventElement = eventsContainerRef.current.querySelector(`[data-event-id="${selectedEventId}"]`); const selectedEventElement = eventsContainerRef.current.querySelector(`[data-event-id="${selectedEventId}"]`);
if (selectedEventElement) { if (selectedEventElement) {
selectedEventElement.scrollIntoView({ selectedEventElement.scrollIntoView({
block: "center", block: "center",
behavior: "smooth", behavior: "smooth",
}); });
} }
} }
}, [selectedEventId]); }, [selectedEventId]);
return ( return (
<div className="flex flex-col h-full w-80 bg-gradient-to-b from-neutral-100 to-neutral-50 shadow-lg"> <div className="flex flex-col h-full w-80 bg-gradient-to-b from-neutral-100 to-neutral-50 shadow-lg">
<div className="py-6 flex flex-col h-full"> <div className="py-6 flex flex-col h-full">
<div className="px-6 pb-8 border-b border-neutral-200"> <div className="px-6 pb-8 border-b border-neutral-200">
<h2 className="text-2xl font-bold text-neutral-800 mb-2">{logTitle}</h2> <h2 className="text-2xl font-bold text-neutral-800 mb-2">{logTitle}</h2>
<p className="text-sm text-neutral-600 leading-relaxed">{logSubtitle}</p> <p className="text-sm text-neutral-600 leading-relaxed">{logSubtitle}</p>
<button <button
className={`mt-4 w-full py-2 px-4 rounded-lg transition-colors duration-200 font-medium className={`mt-4 w-full py-2 px-4 rounded-lg transition-colors duration-200 font-medium
${button1Disabled ${
? "bg-gray-300 text-gray-500 cursor-not-allowed" button1Disabled
: "bg-blue-600 hover:bg-blue-700 text-white" ? "bg-gray-300 text-gray-500 cursor-not-allowed"
}`} : "bg-blue-600 hover:bg-blue-700 text-white"
onClick={onButton1Click} }`}
type="button" onClick={onButton1Click}
type="button"
tabIndex={button1Disabled ? -1 : 0} tabIndex={button1Disabled ? -1 : 0}
aria-disabled={button1Disabled ? "true" : "false"} aria-disabled={button1Disabled ? "true" : "false"}
> >
{button1Name} {button1Name}
</button> </button>
<button <button
className="mt-4 w-full bg-blue-600 hover:bg-blue-700 text-white py-2 px-4 rounded-lg transition-colors duration-200 font-medium" className="mt-4 w-full bg-blue-600 hover:bg-blue-700 text-white py-2 px-4 rounded-lg transition-colors duration-200 font-medium"
onClick={onButton2Click} onClick={onButton2Click}
type="button" type="button"
> >
{button2Name} {button2Name}
</button> </button>
</div> </div>
<div className="px-6 pt-6"> <div className="px-6 pt-6">
<h2 className="text-xl font-bold text-neutral-800 mb-4">{recentsTitle}</h2> <h2 className="text-xl font-bold text-neutral-800 mb-4">{recentsTitle}</h2>
</div> </div>
<div className="flex-1 px-6 overflow-y-auto" ref={eventsContainerRef}> <div className="flex-1 px-6 overflow-y-auto" ref={eventsContainerRef}>
<div className="space-y-3"> <div className="space-y-3">
{events.map((event) => ( {events.map((event) => (
<button <button
key={event.id} key={event.id}
data-event-id={event.id} data-event-id={event.id}
className={`w-full border ${hoveredEventId === event.id ? "bg-neutral-100" : "bg-white"} ${ className={`w-full border ${
selectedEventId === event.id ? "border-neutral-800" : "border-neutral-200" selectedEventId === event.id
} rounded-lg p-4 flex items-center gap-4 hover:bg-neutral-100 transition-colors duration-150 shadow-sm text-left`} ? "border-neutral-500 border-2 shadow-md"
onClick={() => { : hoveredEventId === event.id
setSelectedEventId((prevEventId) => (prevEventId !== event.id ? event.id : "")); ? "bg-neutral-100 shadow-sm"
}} : "bg-white border-neutral-200 shadow-sm"
onMouseEnter={() => setHoveredEventId(event.id)} } rounded-lg p-4 flex items-center gap-4 hover:bg-neutral-100 transition-colors duration-150 text-left`}
onMouseLeave={() => setHoveredEventId("")} onClick={() => {
> setSelectedEventId((prevEventId) => (prevEventId !== event.id ? event.id : ""));
<div className="flex-1"> }}
<p className="text-sm font-medium text-neutral-800 line-clamp-1">{event.title}</p> onMouseEnter={() => setHoveredEventId(event.id)}
<p className="text-xs text-neutral-500 mt-1 line-clamp-1">{event.text2}</p> onMouseLeave={() => setHoveredEventId("")}
</div> >
{event.magnitude ? <MagnitudeNumber magnitude={event.magnitude} /> : <></>} <div className="flex-1">
</button> <p className="text-sm font-medium text-neutral-800 line-clamp-1">{event.title}</p>
))} <p className="text-xs text-neutral-500 mt-1 line-clamp-1">{event.text2}</p>
</div> </div>
</div> {event.magnitude ? <MagnitudeNumber magnitude={event.magnitude} /> : <></>}
</div> </button>
</div> ))}
); </div>
</div>
</div>
</div>
);
} }