ScreenshotDisplay.tsx 2.0 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465
  1. "use client";
  2. import Image from "next/image";
  3. import { useState } from "react";
  4. import { LucideIcon } from "lucide-react";
  5. interface ScreenshotDisplayProps {
  6. imageName: string; // 图片文件名,如 "dashboard.png"
  7. placeholderIcon: LucideIcon;
  8. placeholderText: string;
  9. alt: string;
  10. }
  11. /**
  12. * 截图显示组件
  13. * 如果图片存在则显示图片,否则显示占位符
  14. */
  15. export function ScreenshotDisplay({
  16. imageName,
  17. placeholderIcon: PlaceholderIcon,
  18. placeholderText,
  19. alt,
  20. }: ScreenshotDisplayProps) {
  21. const [imageError, setImageError] = useState(false);
  22. const [imageLoaded, setImageLoaded] = useState(false);
  23. const imagePath = `/images/screenshots/${imageName}`;
  24. // 如果图片加载失败,显示占位符
  25. if (imageError) {
  26. return (
  27. <div className="aspect-video flex items-center justify-center bg-gradient-to-br from-primary/10 to-primary/5">
  28. <div className="text-center">
  29. <PlaceholderIcon className="w-16 h-16 text-primary/50 mx-auto mb-4" />
  30. <p className="text-muted-foreground">{placeholderText}</p>
  31. </div>
  32. </div>
  33. );
  34. }
  35. return (
  36. <div className="relative aspect-video w-full overflow-hidden bg-muted/30">
  37. <Image
  38. src={imagePath}
  39. alt={alt}
  40. fill
  41. className="object-contain"
  42. onError={() => setImageError(true)}
  43. onLoad={() => setImageLoaded(true)}
  44. sizes="(max-width: 768px) 100vw, (max-width: 1200px) 80vw, 1200px"
  45. priority={false}
  46. // 营销截图常替换;走 /_next/image 会强缓存优化结果,本地改 public 后仍像旧图
  47. unoptimized
  48. />
  49. {!imageLoaded && !imageError && (
  50. <div className="absolute inset-0 flex items-center justify-center bg-gradient-to-br from-primary/10 to-primary/5">
  51. <div className="text-center">
  52. <PlaceholderIcon className="w-16 h-16 text-primary/50 mx-auto mb-4" />
  53. <p className="text-muted-foreground">加载中...</p>
  54. </div>
  55. </div>
  56. )}
  57. </div>
  58. );
  59. }