fix some errors
This commit is contained in:
parent
9019a97496
commit
2a34588074
3 changed files with 239 additions and 256 deletions
|
@ -59,21 +59,9 @@ const fileManager = FileManager.getInstance();
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="tapSection">
|
<div id="tapSection">
|
||||||
<TAPSection
|
<TAPSection client:load>
|
||||||
client:load
|
<ASFundingSection client:load />
|
||||||
onDataChange={(data) => {
|
</TAPSection>
|
||||||
// This will be handled in the client-side script
|
|
||||||
document.dispatchEvent(
|
|
||||||
new CustomEvent("tap-section-change", {
|
|
||||||
detail: data,
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="asFundingSection" class="hidden">
|
|
||||||
<ASFundingSection client:load />
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex justify-end space-x-4 mt-8">
|
<div class="flex justify-end space-x-4 mt-8">
|
||||||
|
@ -122,45 +110,8 @@ const fileManager = FileManager.getInstance();
|
||||||
// Form visibility logic
|
// Form visibility logic
|
||||||
const form = document.getElementById("eventRequestForm") as HTMLFormElement;
|
const form = document.getElementById("eventRequestForm") as HTMLFormElement;
|
||||||
const prSection = document.getElementById("prSection");
|
const prSection = document.getElementById("prSection");
|
||||||
const asFundingSection = document.getElementById("asFundingSection");
|
|
||||||
const needsGraphicsRadios = document.getElementsByName("needsGraphics");
|
const needsGraphicsRadios = document.getElementsByName("needsGraphics");
|
||||||
|
|
||||||
// Debug log for initial state
|
|
||||||
console.log("Initial ASFundingSection state:", {
|
|
||||||
element: asFundingSection,
|
|
||||||
isHidden: asFundingSection?.classList.contains("hidden"),
|
|
||||||
display: asFundingSection?.style.display,
|
|
||||||
});
|
|
||||||
|
|
||||||
// Handle TAPSection changes
|
|
||||||
document.addEventListener("tap-section-change", (event: any) => {
|
|
||||||
const data = event.detail;
|
|
||||||
console.log("TAP section change event received:", data);
|
|
||||||
|
|
||||||
if (asFundingSection) {
|
|
||||||
console.log("Found ASFundingSection element");
|
|
||||||
if (data.as_funding_required) {
|
|
||||||
console.log("Showing AS Funding section");
|
|
||||||
asFundingSection.classList.remove("hidden");
|
|
||||||
asFundingSection.style.removeProperty("display");
|
|
||||||
// Force a reflow
|
|
||||||
void asFundingSection.offsetHeight;
|
|
||||||
} else {
|
|
||||||
console.log("Hiding AS Funding section");
|
|
||||||
asFundingSection.classList.add("hidden");
|
|
||||||
asFundingSection.style.display = "none";
|
|
||||||
}
|
|
||||||
|
|
||||||
// Log the state after change
|
|
||||||
console.log("ASFundingSection state after change:", {
|
|
||||||
isHidden: asFundingSection.classList.contains("hidden"),
|
|
||||||
display: asFundingSection.style.display,
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
console.error("ASFundingSection element not found");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Show/hide PR section based on radio selection
|
// Show/hide PR section based on radio selection
|
||||||
needsGraphicsRadios.forEach((radio) => {
|
needsGraphicsRadios.forEach((radio) => {
|
||||||
radio.addEventListener("change", (e) => {
|
radio.addEventListener("change", (e) => {
|
||||||
|
|
|
@ -9,9 +9,10 @@ import { Icon } from '@iconify/react';
|
||||||
interface TAPSectionProps {
|
interface TAPSectionProps {
|
||||||
onDataChange?: (data: any) => void;
|
onDataChange?: (data: any) => void;
|
||||||
onASFundingChange?: (enabled: boolean) => void;
|
onASFundingChange?: (enabled: boolean) => void;
|
||||||
|
children?: React.ReactNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
const TAPSection: React.FC<TAPSectionProps> = ({ onDataChange, onASFundingChange }) => {
|
const TAPSection: React.FC<TAPSectionProps> = ({ onDataChange, onASFundingChange, children }) => {
|
||||||
const [expectedAttendance, setExpectedAttendance] = useState<number>(0);
|
const [expectedAttendance, setExpectedAttendance] = useState<number>(0);
|
||||||
const [roomBooking, setRoomBooking] = useState<string>('');
|
const [roomBooking, setRoomBooking] = useState<string>('');
|
||||||
const [needsASFunding, setNeedsASFunding] = useState<boolean>(false);
|
const [needsASFunding, setNeedsASFunding] = useState<boolean>(false);
|
||||||
|
@ -34,14 +35,12 @@ const TAPSection: React.FC<TAPSectionProps> = ({ onDataChange, onASFundingChange
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleASFundingChange = (enabled: boolean) => {
|
const handleASFundingChange = (enabled: boolean) => {
|
||||||
console.log('AS Funding change:', enabled);
|
|
||||||
setNeedsASFunding(enabled);
|
setNeedsASFunding(enabled);
|
||||||
if (!enabled) {
|
if (!enabled) {
|
||||||
setNeedsFoodDrinks(false);
|
setNeedsFoodDrinks(false);
|
||||||
onDataChange?.({ needs_food_drinks: false });
|
onDataChange?.({ needs_food_drinks: false });
|
||||||
}
|
}
|
||||||
onASFundingChange?.(enabled);
|
onASFundingChange?.(enabled);
|
||||||
console.log('Sending data change:', { as_funding_required: enabled });
|
|
||||||
onDataChange?.({ as_funding_required: enabled });
|
onDataChange?.({ as_funding_required: enabled });
|
||||||
|
|
||||||
toast(enabled ? 'AS Funding enabled - please fill out funding details.' : 'AS Funding disabled', {
|
toast(enabled ? 'AS Funding enabled - please fill out funding details.' : 'AS Funding disabled', {
|
||||||
|
@ -56,206 +55,227 @@ const TAPSection: React.FC<TAPSectionProps> = ({ onDataChange, onASFundingChange
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<motion.div
|
<>
|
||||||
initial={{ opacity: 0, y: 20 }}
|
<motion.div
|
||||||
animate={{ opacity: 1, y: 0 }}
|
initial={{ opacity: 0, y: 20 }}
|
||||||
transition={{ duration: 0.5 }}
|
animate={{ opacity: 1, y: 0 }}
|
||||||
className="card bg-base-100/95 backdrop-blur-md shadow-lg hover:shadow-xl transition-all duration-300"
|
transition={{ duration: 0.5 }}
|
||||||
>
|
className="card bg-base-100/95 backdrop-blur-md shadow-lg hover:shadow-xl transition-all duration-300"
|
||||||
<div className="card-body">
|
>
|
||||||
<motion.h2
|
<div className="card-body">
|
||||||
initial={{ opacity: 0, x: -20 }}
|
<motion.h2
|
||||||
animate={{ opacity: 1, x: 0 }}
|
initial={{ opacity: 0, x: -20 }}
|
||||||
transition={{ delay: 0.2 }}
|
animate={{ opacity: 1, x: 0 }}
|
||||||
className="card-title text-xl mb-6 bg-gradient-to-r from-primary to-secondary bg-clip-text text-transparent flex items-center gap-2"
|
transition={{ delay: 0.2 }}
|
||||||
>
|
className="card-title text-xl mb-6 bg-gradient-to-r from-primary to-secondary bg-clip-text text-transparent flex items-center gap-2"
|
||||||
<Icon icon="mdi:clipboard-text-outline" className="h-6 w-6" />
|
|
||||||
TAP Form
|
|
||||||
</motion.h2>
|
|
||||||
|
|
||||||
<div className="space-y-8">
|
|
||||||
<motion.div
|
|
||||||
initial={{ opacity: 0, y: 20 }}
|
|
||||||
animate={{ opacity: 1, y: 0 }}
|
|
||||||
transition={{ delay: 0.4 }}
|
|
||||||
className="form-control w-full"
|
|
||||||
>
|
>
|
||||||
<div className="flex items-center justify-between mb-2">
|
<Icon icon="mdi:clipboard-text-outline" className="h-6 w-6" />
|
||||||
<label className="label">
|
TAP Form
|
||||||
<span className="label-text font-medium text-lg flex items-center gap-2">
|
</motion.h2>
|
||||||
<Icon icon="mdi:account-group" className="h-5 w-5 text-primary" />
|
|
||||||
Expected Attendance
|
|
||||||
</span>
|
|
||||||
</label>
|
|
||||||
<Tooltip
|
|
||||||
title={tooltips.attendance.title}
|
|
||||||
description={tooltips.attendance.description}
|
|
||||||
position="left"
|
|
||||||
>
|
|
||||||
<div className="badge badge-primary badge-outline p-3 cursor-help">
|
|
||||||
<Icon icon="mdi:information-outline" className="h-4 w-4" />
|
|
||||||
</div>
|
|
||||||
</Tooltip>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="relative group">
|
<div className="space-y-8">
|
||||||
<input
|
<motion.div
|
||||||
type="number"
|
initial={{ opacity: 0, y: 20 }}
|
||||||
min="0"
|
animate={{ opacity: 1, y: 0 }}
|
||||||
className="input input-bordered w-full pl-12 transition-all duration-300 focus:ring-2 focus:ring-primary/20"
|
transition={{ delay: 0.4 }}
|
||||||
value={expectedAttendance || ''}
|
className="form-control w-full"
|
||||||
onChange={(e) => handleAttendanceChange(Number(e.target.value))}
|
>
|
||||||
required
|
<div className="flex items-center justify-between mb-2">
|
||||||
/>
|
<label className="label">
|
||||||
</div>
|
<span className="label-text font-medium text-lg flex items-center gap-2">
|
||||||
</motion.div>
|
<Icon icon="mdi:account-group" className="h-5 w-5 text-primary" />
|
||||||
|
Expected Attendance
|
||||||
|
</span>
|
||||||
|
</label>
|
||||||
|
<Tooltip
|
||||||
|
title={tooltips.attendance.title}
|
||||||
|
description={tooltips.attendance.description}
|
||||||
|
position="left"
|
||||||
|
>
|
||||||
|
<div className="badge badge-primary badge-outline p-3 cursor-help">
|
||||||
|
<Icon icon="mdi:information-outline" className="h-4 w-4" />
|
||||||
|
</div>
|
||||||
|
</Tooltip>
|
||||||
|
</div>
|
||||||
|
|
||||||
<motion.div
|
<div className="relative group">
|
||||||
initial={{ opacity: 0, y: 20 }}
|
|
||||||
animate={{ opacity: 1, y: 0 }}
|
|
||||||
transition={{ delay: 0.5 }}
|
|
||||||
className="form-control w-full"
|
|
||||||
>
|
|
||||||
<div className="flex items-center justify-between mb-2">
|
|
||||||
<label className="label">
|
|
||||||
<span className="label-text font-medium text-lg flex items-center gap-2">
|
|
||||||
<Icon icon="mdi:office-building-outline" className="h-5 w-5 text-primary" />
|
|
||||||
Room Booking
|
|
||||||
</span>
|
|
||||||
</label>
|
|
||||||
<Tooltip
|
|
||||||
title={tooltips.room.title}
|
|
||||||
description={tooltips.room.description}
|
|
||||||
position="left"
|
|
||||||
>
|
|
||||||
<div className="badge badge-primary badge-outline p-3 cursor-help">
|
|
||||||
<Icon icon="mdi:information-outline" className="h-4 w-4" />
|
|
||||||
</div>
|
|
||||||
</Tooltip>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<InfoCard
|
|
||||||
title={infoNotes.room.title}
|
|
||||||
items={infoNotes.room.items}
|
|
||||||
type="info"
|
|
||||||
className="mb-4"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<div className="relative group">
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
placeholder="Enter room number and building (e.g. EBU1 2315)"
|
|
||||||
className="input input-bordered w-full pl-12 transition-all duration-300 focus:ring-2 focus:ring-primary/20"
|
|
||||||
value={roomBooking}
|
|
||||||
onChange={(e) => handleRoomBookingChange(e.target.value)}
|
|
||||||
required
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</motion.div>
|
|
||||||
|
|
||||||
<motion.div
|
|
||||||
initial={{ opacity: 0, y: 20 }}
|
|
||||||
animate={{ opacity: 1, y: 0 }}
|
|
||||||
transition={{ delay: 0.6 }}
|
|
||||||
className="form-control w-full"
|
|
||||||
>
|
|
||||||
<div className="flex items-center justify-between mb-2">
|
|
||||||
<label className="label">
|
|
||||||
<span className="label-text font-medium text-lg flex items-center gap-2">
|
|
||||||
<Icon icon="mdi:cash" className="h-5 w-5 text-primary" />
|
|
||||||
AS Funding
|
|
||||||
</span>
|
|
||||||
</label>
|
|
||||||
<Tooltip
|
|
||||||
title={tooltips.asFunding.title}
|
|
||||||
description={tooltips.asFunding.description}
|
|
||||||
position="left"
|
|
||||||
>
|
|
||||||
<div className="badge badge-primary badge-outline p-3 cursor-help">
|
|
||||||
<Icon icon="mdi:information-outline" className="h-4 w-4" />
|
|
||||||
</div>
|
|
||||||
</Tooltip>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="flex flex-col gap-2">
|
|
||||||
<label className="label cursor-pointer justify-start gap-4 hover:bg-base-200/50 p-4 rounded-lg transition-colors duration-300">
|
|
||||||
<input
|
<input
|
||||||
type="radio"
|
type="number"
|
||||||
name="as_funding"
|
min="0"
|
||||||
className="radio radio-primary"
|
className="input input-bordered w-full pl-12 transition-all duration-300 focus:ring-2 focus:ring-primary/20"
|
||||||
checked={needsASFunding}
|
value={expectedAttendance || ''}
|
||||||
onChange={() => handleASFundingChange(true)}
|
onChange={(e) => handleAttendanceChange(Number(e.target.value))}
|
||||||
|
required
|
||||||
/>
|
/>
|
||||||
<span className="label-text">Yes, I need AS Funding</span>
|
</div>
|
||||||
</label>
|
</motion.div>
|
||||||
<label className="label cursor-pointer justify-start gap-4 hover:bg-base-200/50 p-4 rounded-lg transition-colors duration-300">
|
|
||||||
|
<motion.div
|
||||||
|
initial={{ opacity: 0, y: 20 }}
|
||||||
|
animate={{ opacity: 1, y: 0 }}
|
||||||
|
transition={{ delay: 0.5 }}
|
||||||
|
className="form-control w-full"
|
||||||
|
>
|
||||||
|
<div className="flex items-center justify-between mb-2">
|
||||||
|
<label className="label">
|
||||||
|
<span className="label-text font-medium text-lg flex items-center gap-2">
|
||||||
|
<Icon icon="mdi:office-building-outline" className="h-5 w-5 text-primary" />
|
||||||
|
Room Booking
|
||||||
|
</span>
|
||||||
|
</label>
|
||||||
|
<Tooltip
|
||||||
|
title={tooltips.room.title}
|
||||||
|
description={tooltips.room.description}
|
||||||
|
position="left"
|
||||||
|
>
|
||||||
|
<div className="badge badge-primary badge-outline p-3 cursor-help">
|
||||||
|
<Icon icon="mdi:information-outline" className="h-4 w-4" />
|
||||||
|
</div>
|
||||||
|
</Tooltip>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<InfoCard
|
||||||
|
title={infoNotes.room.title}
|
||||||
|
items={infoNotes.room.items}
|
||||||
|
type="info"
|
||||||
|
className="mb-4"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<div className="relative group">
|
||||||
<input
|
<input
|
||||||
type="radio"
|
type="text"
|
||||||
name="as_funding"
|
placeholder="Enter room number and building (e.g. EBU1 2315)"
|
||||||
className="radio radio-primary"
|
className="input input-bordered w-full pl-12 transition-all duration-300 focus:ring-2 focus:ring-primary/20"
|
||||||
checked={!needsASFunding}
|
value={roomBooking}
|
||||||
onChange={() => handleASFundingChange(false)}
|
onChange={(e) => handleRoomBookingChange(e.target.value)}
|
||||||
|
required
|
||||||
/>
|
/>
|
||||||
<span className="label-text">No, I don't need AS Funding</span>
|
</div>
|
||||||
</label>
|
</motion.div>
|
||||||
</div>
|
|
||||||
</motion.div>
|
|
||||||
|
|
||||||
<AnimatePresence mode="wait">
|
<motion.div
|
||||||
{needsASFunding && (
|
initial={{ opacity: 0, y: 20 }}
|
||||||
<motion.div
|
animate={{ opacity: 1, y: 0 }}
|
||||||
initial={{ opacity: 0, height: 0 }}
|
transition={{ delay: 0.6 }}
|
||||||
animate={{ opacity: 1, height: 'auto' }}
|
className="form-control w-full"
|
||||||
exit={{ opacity: 0, height: 0 }}
|
>
|
||||||
transition={{ duration: 0.3 }}
|
<div className="flex items-center justify-between mb-2">
|
||||||
className="form-control w-full overflow-hidden"
|
<label className="label">
|
||||||
>
|
<span className="label-text font-medium text-lg flex items-center gap-2">
|
||||||
<div className="flex items-center justify-between mb-2">
|
<Icon icon="mdi:cash" className="h-5 w-5 text-primary" />
|
||||||
<label className="label">
|
AS Funding
|
||||||
<span className="label-text font-medium text-lg flex items-center gap-2">
|
</span>
|
||||||
<Icon icon="mdi:food" className="h-5 w-5 text-primary" />
|
</label>
|
||||||
Food/Drinks
|
<Tooltip
|
||||||
</span>
|
title={tooltips.asFunding.title}
|
||||||
</label>
|
description={tooltips.asFunding.description}
|
||||||
<Tooltip
|
position="left"
|
||||||
title={tooltips.food.title}
|
>
|
||||||
description={tooltips.food.description}
|
<div className="badge badge-primary badge-outline p-3 cursor-help">
|
||||||
position="left"
|
<Icon icon="mdi:information-outline" className="h-4 w-4" />
|
||||||
>
|
</div>
|
||||||
<div className="badge badge-primary badge-outline p-3 cursor-help">
|
</Tooltip>
|
||||||
<Icon icon="mdi:information-outline" className="h-4 w-4" />
|
</div>
|
||||||
</div>
|
|
||||||
</Tooltip>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="flex flex-col gap-2">
|
<div className="flex flex-col gap-2">
|
||||||
<label className="label cursor-pointer justify-start gap-4 hover:bg-base-200/50 p-4 rounded-lg transition-colors duration-300">
|
<label className="label cursor-pointer justify-start gap-4 hover:bg-base-200/50 p-4 rounded-lg transition-colors duration-300">
|
||||||
<input
|
<input
|
||||||
type="radio"
|
type="radio"
|
||||||
name="food_drinks"
|
name="as_funding"
|
||||||
className="radio radio-primary"
|
className="radio radio-primary"
|
||||||
checked={needsFoodDrinks}
|
checked={needsASFunding}
|
||||||
onChange={() => handleFoodDrinksChange(true)}
|
onChange={() => handleASFundingChange(true)}
|
||||||
/>
|
/>
|
||||||
<span className="label-text">Yes, I need food/drinks</span>
|
<span className="label-text">Yes, I need AS Funding</span>
|
||||||
</label>
|
</label>
|
||||||
<label className="label cursor-pointer justify-start gap-4 hover:bg-base-200/50 p-4 rounded-lg transition-colors duration-300">
|
<label className="label cursor-pointer justify-start gap-4 hover:bg-base-200/50 p-4 rounded-lg transition-colors duration-300">
|
||||||
<input
|
<input
|
||||||
type="radio"
|
type="radio"
|
||||||
name="food_drinks"
|
name="as_funding"
|
||||||
className="radio radio-primary"
|
className="radio radio-primary"
|
||||||
checked={!needsFoodDrinks}
|
checked={!needsASFunding}
|
||||||
onChange={() => handleFoodDrinksChange(false)}
|
onChange={() => handleASFundingChange(false)}
|
||||||
/>
|
/>
|
||||||
<span className="label-text">No, I don't need food/drinks</span>
|
<span className="label-text">No, I don't need AS Funding</span>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
</motion.div>
|
</motion.div>
|
||||||
)}
|
|
||||||
</AnimatePresence>
|
<AnimatePresence mode="wait">
|
||||||
|
{needsASFunding && (
|
||||||
|
<motion.div
|
||||||
|
initial={{ opacity: 0, height: 0 }}
|
||||||
|
animate={{ opacity: 1, height: 'auto' }}
|
||||||
|
exit={{ opacity: 0, height: 0 }}
|
||||||
|
transition={{ duration: 0.3 }}
|
||||||
|
className="form-control w-full overflow-hidden"
|
||||||
|
>
|
||||||
|
<div className="flex items-center justify-between mb-2">
|
||||||
|
<label className="label">
|
||||||
|
<span className="label-text font-medium text-lg flex items-center gap-2">
|
||||||
|
<Icon icon="mdi:food" className="h-5 w-5 text-primary" />
|
||||||
|
Food/Drinks
|
||||||
|
</span>
|
||||||
|
</label>
|
||||||
|
<Tooltip
|
||||||
|
title={tooltips.food.title}
|
||||||
|
description={tooltips.food.description}
|
||||||
|
position="left"
|
||||||
|
>
|
||||||
|
<div className="badge badge-primary badge-outline p-3 cursor-help">
|
||||||
|
<Icon icon="mdi:information-outline" className="h-4 w-4" />
|
||||||
|
</div>
|
||||||
|
</Tooltip>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="flex flex-col gap-2">
|
||||||
|
<label className="label cursor-pointer justify-start gap-4 hover:bg-base-200/50 p-4 rounded-lg transition-colors duration-300">
|
||||||
|
<input
|
||||||
|
type="radio"
|
||||||
|
name="food_drinks"
|
||||||
|
className="radio radio-primary"
|
||||||
|
checked={needsFoodDrinks}
|
||||||
|
onChange={() => handleFoodDrinksChange(true)}
|
||||||
|
/>
|
||||||
|
<span className="label-text">Yes, I need food/drinks</span>
|
||||||
|
</label>
|
||||||
|
<label className="label cursor-pointer justify-start gap-4 hover:bg-base-200/50 p-4 rounded-lg transition-colors duration-300">
|
||||||
|
<input
|
||||||
|
type="radio"
|
||||||
|
name="food_drinks"
|
||||||
|
className="radio radio-primary"
|
||||||
|
checked={!needsFoodDrinks}
|
||||||
|
onChange={() => handleFoodDrinksChange(false)}
|
||||||
|
/>
|
||||||
|
<span className="label-text">No, I don't need food/drinks</span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</motion.div>
|
||||||
|
)}
|
||||||
|
</AnimatePresence>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</motion.div>
|
||||||
</motion.div>
|
|
||||||
|
<AnimatePresence mode="popLayout">
|
||||||
|
{needsASFunding && (
|
||||||
|
<motion.div
|
||||||
|
initial={{ opacity: 0, height: 0, y: -20 }}
|
||||||
|
animate={{ opacity: 1, height: 'auto', y: 0 }}
|
||||||
|
exit={{ opacity: 0, height: 0, y: -20 }}
|
||||||
|
transition={{
|
||||||
|
duration: 0.3,
|
||||||
|
height: { duration: 0.4 },
|
||||||
|
opacity: { duration: 0.3 },
|
||||||
|
y: { duration: 0.3 }
|
||||||
|
}}
|
||||||
|
className="mt-8"
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</motion.div>
|
||||||
|
)}
|
||||||
|
</AnimatePresence>
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,8 @@ interface TooltipProps {
|
||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
className?: string;
|
className?: string;
|
||||||
position?: 'top' | 'bottom' | 'left' | 'right';
|
position?: 'top' | 'bottom' | 'left' | 'right';
|
||||||
|
icon?: string;
|
||||||
|
maxWidth?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const positionStyles = {
|
const positionStyles = {
|
||||||
|
@ -18,10 +20,10 @@ const positionStyles = {
|
||||||
};
|
};
|
||||||
|
|
||||||
const arrowStyles = {
|
const arrowStyles = {
|
||||||
top: 'bottom-[-6px] left-1/2 -translate-x-1/2 border-t-base-300 border-l-transparent border-r-transparent border-b-transparent',
|
top: 'bottom-[-6px] left-1/2 -translate-x-1/2 border-t-base-200 border-l-transparent border-r-transparent border-b-transparent',
|
||||||
bottom: 'top-[-6px] left-1/2 -translate-x-1/2 border-b-base-300 border-l-transparent border-r-transparent border-t-transparent',
|
bottom: 'top-[-6px] left-1/2 -translate-x-1/2 border-b-base-200 border-l-transparent border-r-transparent border-t-transparent',
|
||||||
left: 'right-[-6px] top-1/2 -translate-y-1/2 border-l-base-300 border-t-transparent border-b-transparent border-r-transparent',
|
left: 'right-[-6px] top-1/2 -translate-y-1/2 border-l-base-200 border-t-transparent border-b-transparent border-r-transparent',
|
||||||
right: 'left-[-6px] top-1/2 -translate-y-1/2 border-r-base-300 border-t-transparent border-b-transparent border-l-transparent'
|
right: 'left-[-6px] top-1/2 -translate-y-1/2 border-r-base-200 border-t-transparent border-b-transparent border-l-transparent'
|
||||||
};
|
};
|
||||||
|
|
||||||
export const Tooltip: React.FC<TooltipProps> = ({
|
export const Tooltip: React.FC<TooltipProps> = ({
|
||||||
|
@ -29,7 +31,9 @@ export const Tooltip: React.FC<TooltipProps> = ({
|
||||||
description,
|
description,
|
||||||
children,
|
children,
|
||||||
className = '',
|
className = '',
|
||||||
position = 'top'
|
position = 'left',
|
||||||
|
icon = 'mdi:information',
|
||||||
|
maxWidth = '350px'
|
||||||
}) => {
|
}) => {
|
||||||
const [isVisible, setIsVisible] = React.useState(false);
|
const [isVisible, setIsVisible] = React.useState(false);
|
||||||
|
|
||||||
|
@ -48,13 +52,21 @@ export const Tooltip: React.FC<TooltipProps> = ({
|
||||||
initial={{ opacity: 0, scale: 0.95 }}
|
initial={{ opacity: 0, scale: 0.95 }}
|
||||||
animate={{ opacity: 1, scale: 1 }}
|
animate={{ opacity: 1, scale: 1 }}
|
||||||
exit={{ opacity: 0, scale: 0.95 }}
|
exit={{ opacity: 0, scale: 0.95 }}
|
||||||
transition={{ duration: 0.1 }}
|
transition={{
|
||||||
className={`absolute z-50 min-w-[320px] max-w-md p-4 bg-base-100 border border-base-300 rounded-lg shadow-lg ${positionStyles[position]}`}
|
duration: 0.15,
|
||||||
|
ease: 'easeOut'
|
||||||
|
}}
|
||||||
|
style={{ maxWidth }}
|
||||||
|
className={`absolute z-50 p-3 bg-base-200/95 border border-base-300 rounded-lg shadow-lg backdrop-blur-sm
|
||||||
|
${positionStyles[position]}`}
|
||||||
>
|
>
|
||||||
<div className={`absolute w-0 h-0 border-4 ${arrowStyles[position]}`} />
|
<div className={`absolute w-0 h-0 border-[6px] ${arrowStyles[position]}`} />
|
||||||
<div className="space-y-2">
|
<div className="flex items-start gap-2">
|
||||||
<p className="font-medium text-base">{title}</p>
|
<Icon icon={icon} className="w-5 h-5 text-primary mt-0.5 flex-shrink-0" />
|
||||||
<p className="text-sm leading-relaxed text-base-content/80">{description}</p>
|
<div>
|
||||||
|
<h3 className="font-medium text-base text-base-content">{title}</h3>
|
||||||
|
<p className="text-sm leading-relaxed text-base-content/80 mt-0.5 whitespace-pre-wrap">{description}</p>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</motion.div>
|
</motion.div>
|
||||||
)}
|
)}
|
||||||
|
|
Loading…
Reference in a new issue