forked from 77media/video-flow
183 lines
5.0 KiB
TypeScript
183 lines
5.0 KiB
TypeScript
import { notification } from 'antd';
|
||
|
||
const darkGlassStyle = {
|
||
background: 'rgba(30, 32, 40, 0.95)',
|
||
backdropFilter: 'blur(10px)',
|
||
WebkitBackdropFilter: 'blur(10px)',
|
||
border: '1px solid rgba(255, 255, 255, 0.08)',
|
||
borderRadius: '8px',
|
||
boxShadow: '0 4px 16px rgba(0, 0, 0, 0.4)',
|
||
padding: '12px 16px',
|
||
};
|
||
|
||
/** 胶片容器样式 */
|
||
const filmStripContainerStyle = {
|
||
position: 'relative' as const,
|
||
width: '100%',
|
||
height: '80px',
|
||
marginBottom: '16px',
|
||
overflow: 'hidden',
|
||
};
|
||
|
||
/** 胶片样式 */
|
||
const filmStripStyle = {
|
||
display: 'flex',
|
||
alignItems: 'center',
|
||
animation: 'filmScroll 20s linear infinite',
|
||
};
|
||
|
||
/** 文字样式 */
|
||
const textStyle = {
|
||
fontSize: '13px',
|
||
color: 'rgba(255, 255, 255, 0.9)',
|
||
marginBottom: '12px',
|
||
};
|
||
|
||
/** 胶片帧组件 */
|
||
const FilmFrame = () => (
|
||
<div style={{ margin: '0 4px' }}>
|
||
<svg width="60" height="80" viewBox="0 0 60 80" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||
{/* 胶片外框 */}
|
||
<rect x="0" y="0" width="60" height="80" fill="#1A1B1E" stroke="#F6B266" strokeWidth="1"/>
|
||
{/* 齿孔 */}
|
||
<circle cx="10" cy="5" r="3" fill="none" stroke="#F6B266" strokeWidth="1"/>
|
||
<circle cx="50" cy="5" r="3" fill="none" stroke="#F6B266" strokeWidth="1"/>
|
||
<circle cx="10" cy="75" r="3" fill="none" stroke="#F6B266" strokeWidth="1"/>
|
||
<circle cx="50" cy="75" r="3" fill="none" stroke="#F6B266" strokeWidth="1"/>
|
||
{/* 胶片画面区域 */}
|
||
<rect x="5" y="15" width="50" height="50" fill="#2A2B2E" stroke="#F6B266" strokeWidth="1"/>
|
||
</svg>
|
||
</div>
|
||
);
|
||
|
||
/** 放映机音效组件 */
|
||
const ProjectorSound = () => (
|
||
<audio
|
||
src="/assets/audio/projector.mp3"
|
||
autoPlay
|
||
loop
|
||
style={{ display: 'none' }}
|
||
/>
|
||
);
|
||
|
||
/**
|
||
* 显示队列等待通知
|
||
* @param position - 当前队列位置
|
||
* @param estimatedMinutes - 预计等待分钟数
|
||
*/
|
||
export const showQueueNotification = (position: number, estimatedMinutes: number) => {
|
||
notification.open({
|
||
message: null,
|
||
description: (
|
||
<div data-alt="queue-notification" style={{ minWidth: '320px' }}>
|
||
{/* 胶片动画区域 */}
|
||
<div style={filmStripContainerStyle}>
|
||
<div style={filmStripStyle}>
|
||
{[...Array(6)].map((_, i) => (
|
||
<FilmFrame key={i} />
|
||
))}
|
||
</div>
|
||
<div style={filmStripStyle} className="film-strip-2">
|
||
{[...Array(6)].map((_, i) => (
|
||
<FilmFrame key={i} />
|
||
))}
|
||
</div>
|
||
</div>
|
||
|
||
{/* 队列信息 */}
|
||
<div style={textStyle}>
|
||
<span style={{ marginRight: '8px' }}>🎬</span>
|
||
您的作品正在第 {position} 位等待制作
|
||
</div>
|
||
|
||
{/* 预计等待时间 */}
|
||
<div style={{ ...textStyle, color: 'rgba(255, 255, 255, 0.65)' }}>
|
||
预计等待时间:约 {estimatedMinutes} 分钟
|
||
</div>
|
||
|
||
{/* 取消按钮 */}
|
||
<button
|
||
onClick={() => notification.destroy()}
|
||
style={{
|
||
color: 'rgb(250 173 20 / 90%)',
|
||
background: 'transparent',
|
||
border: 'none',
|
||
cursor: 'pointer',
|
||
padding: 0,
|
||
fontSize: '12px',
|
||
fontWeight: 500,
|
||
textDecoration: 'underline',
|
||
textUnderlineOffset: '2px',
|
||
textDecorationColor: 'rgb(250 173 20 / 60%)',
|
||
transition: 'all 0.2s ease',
|
||
}}
|
||
data-alt="cancel-queue-button"
|
||
>
|
||
取消制作 →
|
||
</button>
|
||
|
||
{/* 放映机音效 */}
|
||
<ProjectorSound />
|
||
</div>
|
||
),
|
||
duration: 0,
|
||
placement: 'topRight',
|
||
style: {
|
||
...darkGlassStyle,
|
||
border: '1px solid rgba(246, 178, 102, 0.2)',
|
||
},
|
||
className: 'movie-queue-notification',
|
||
closeIcon: (
|
||
<button
|
||
className="hover:text-white"
|
||
style={{
|
||
background: 'transparent',
|
||
border: 'none',
|
||
padding: '2px',
|
||
cursor: 'pointer',
|
||
color: 'rgba(255, 255, 255, 0.45)',
|
||
transition: 'color 0.2s ease',
|
||
}}
|
||
>
|
||
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||
<path d="M18 6L6 18M6 6L18 18" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/>
|
||
</svg>
|
||
</button>
|
||
),
|
||
});
|
||
};
|
||
|
||
// 添加必要的CSS动画
|
||
const styles = `
|
||
@keyframes filmScroll {
|
||
0% { transform: translateX(0); }
|
||
100% { transform: translateX(-360px); }
|
||
}
|
||
|
||
.film-strip-2 {
|
||
position: absolute;
|
||
top: 0;
|
||
left: 360px;
|
||
}
|
||
|
||
.movie-queue-notification {
|
||
animation: slideIn 0.3s ease-out;
|
||
}
|
||
|
||
@keyframes slideIn {
|
||
from { transform: translateX(100%); opacity: 0; }
|
||
to { transform: translateX(0); opacity: 1; }
|
||
}
|
||
`;
|
||
|
||
// 将样式注入到页面
|
||
if (typeof document !== 'undefined') {
|
||
const styleSheet = document.createElement('style');
|
||
styleSheet.textContent = styles;
|
||
document.head.appendChild(styleSheet);
|
||
}
|
||
|
||
// 配置通知
|
||
notification.config({
|
||
maxCount: 3,
|
||
}); |