This commit is contained in:
qiuchenfan 2025-11-21 17:51:54 +08:00
commit 10506e6295
4 changed files with 191 additions and 1 deletions

View File

@ -0,0 +1,101 @@
import React, { useState } from 'react';
import { usePopupManager } from './Popup';
// 单独的“添加飘窗”表单弹窗组件
const AddPopupForm = () => {
const { addPopup } = usePopupManager();
const [isOpen, setIsOpen] = useState(false);
const [formData, setFormData] = useState({
title: '',
description: '',
backgroundImage: '',
});
const handleChange = (e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => {
const { name, value } = e.target;
setFormData((prev) => ({ ...prev, [name]: value }));
};
const handleSubmit = (e: React.FormEvent) => {
e.preventDefault();
if (!formData.title.trim() || !formData.description.trim()) return;
addPopup({
title: formData.title,
description: formData.description,
backgroundImage: formData.backgroundImage || undefined,
});
setIsOpen(false);
setFormData({ title: '', description: '', backgroundImage: '' });
};
return (
<>
<button
onClick={() => setIsOpen(true)}
className="px-4 py-2 bg-blue-600 text-white rounded hover:bg-blue-700 transition"
>
+
</button>
{isOpen && (
<div className="fixed inset-0 bg-black bg-opacity-40 flex items-center justify-center z-50 p-4">
<div className="bg-white rounded-lg w-full max-w-md p-6 relative">
<button
onClick={() => setIsOpen(false)}
className="absolute top-3 right-3 text-gray-500 hover:text-gray-800"
>
&times;
</button>
<h2 className="text-xl font-bold mb-4"></h2>
<form onSubmit={handleSubmit}>
<input
name="title"
placeholder="标题"
value={formData.title}
onChange={handleChange}
className="w-full mb-3 px-3 py-2 border rounded"
required
/>
<input
name="backgroundImage"
placeholder="背景图 URL可选"
type="url"
value={formData.backgroundImage}
onChange={handleChange}
className="w-full mb-3 px-3 py-2 border rounded"
/>
<textarea
name="description"
placeholder="详细说明"
value={formData.description}
onChange={handleChange}
rows={3}
className="w-full mb-4 px-3 py-2 border rounded"
required
/>
<div className="flex justify-end gap-2">
<button
type="button"
onClick={() => setIsOpen(false)}
className="px-3 py-1.5 border rounded"
>
</button>
<button type="submit" className="px-3 py-1.5 bg-blue-600 text-white rounded">
</button>
</div>
</form>
</div>
</div>
)}
</>
);
};
export default AddPopupForm;

View File

@ -0,0 +1,85 @@
// src/components/FloatingPopupManager.tsx
import React, { useState, createContext, useContext, type ReactNode } from 'react';
type PopupItem = {
id: string;
title: string;
description: string;
backgroundImage?: string;
};
type PopupContextType = {
addPopup: (popup: Omit<PopupItem, 'id'>) => void;
};
const PopupContext = createContext<PopupContextType | undefined>(undefined);
export const usePopupManager = () => {
const context = useContext(PopupContext);
if (!context) {
throw new Error('usePopupManager must be used within a PopupProvider');
}
return context;
};
export const FloatingPopupManager: React.FC<{ children: ReactNode }> = ({ children }) => {
const [popups, setPopups] = useState<PopupItem[]>([]);
const addPopup = (popup: Omit<PopupItem, 'id'>) => {
const newPopup: PopupItem = {
...popup,
id: Date.now().toString(),
};
setPopups((prev) => [...prev, newPopup]);
};
const removePopup = (id: string) => {
setPopups((prev) => prev.filter((p) => p.id !== id));
};
return (
<PopupContext.Provider value={{ addPopup }}>
{children}
{/* 渲染所有飘窗 */}
<div className="fixed bottom-4 right-4 space-y-3 z-[9999] pointer-events-none">
{popups.map((popup, index) => (
<div
key={popup.id}
className="pointer-events-auto relative bg-white shadow-xl rounded-lg w-80 overflow-hidden border border-gray-200"
style={{
transform: `translateY(${index * 12}px)`,
}}
>
{/* 背景区域 */}
{popup.backgroundImage ? (
<div className="h-32 w-full overflow-hidden">
<img
src={popup.backgroundImage}
alt=""
className="w-full h-full object-cover opacity-90"
/>
</div>
) : (
<div className="h-32 bg-gradient-to-r from-blue-500 to-indigo-600"></div>
)}
{/* 内容 */}
<div className="p-4">
<div className="flex justify-between items-start">
<h3 className="text-lg font-bold text-gray-800">{popup.title}</h3>
<button
onClick={() => removePopup(popup.id)}
className="text-gray-500 hover:text-gray-800 text-xl font-bold"
>
&times;
</button>
</div>
<p className="mt-2 text-gray-600 text-sm">{popup.description}</p>
</div>
</div>
))}
</div>
</PopupContext.Provider>
);
};

View File

@ -55,7 +55,7 @@ const Train = () => {
{ src: '/images/carousel-3.jpg', colSpan: 2, link: 'https://www.baidu.com' },
{ src: '/images/carousel-4.jpg', colSpan: 3, link: 'https://www.baidu.com' },
{ src: '/logo/logo2.png', colSpan: 1, link: '' },
{ src: '/images/carousel-5.jpg', colSpan: 1, link: 'https://www.baidu.com' },
{ src: '/images/carousel-5.jpg', colSpan: 2, link: 'https://www.baidu.com' },
{ src: '/images/carousel-7.jpg', colSpan: 3, link: 'https://www.baidu.com' },
];
{/* 弹性 默认纵向 大屏横向 */ }

View File

@ -14,6 +14,8 @@ import { Hotline } from "@/components/news/body/FireNews/Hotline";
import { AutoCarouselDemo } from "@/components/AutoCarousel";
import Footer from "@/components/news/footer/footer";
import Train from "@/components/news/body/Train";
import AddPopupForm from "@/components/news/body/PopupfloatingMangement/AddPopup";
export function meta( ) {
return [
@ -44,6 +46,8 @@ export default function Home() {
</div>
<Footer />
<Train />
<AddPopupForm />
</div>
);
}