Processing.jsx 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
  1. import './processing.css';
  2. import { useHistory } from './processing.js';
  3. // SVG 图标组件
  4. const LoopIcon = ({ active = false }) => (
  5. <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
  6. <path d="M21.5 2v6h-6M2.5 22v-6h6M2 11.5a10 10 0 0 1 18.8-4.3M22 12.5a10 10 0 0 1-18.8 4.2" opacity={active ? 1 : 0.5}></path>
  7. </svg>
  8. );
  9. const PlayIcon = () => (
  10. <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
  11. <polygon points="5 3 19 12 5 21 5 3"></polygon>
  12. </svg>
  13. );
  14. const PauseIcon = () => (
  15. <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
  16. <rect x="6" y="4" width="4" height="16"></rect>
  17. <rect x="14" y="4" width="4" height="16"></rect>
  18. </svg>
  19. );
  20. const DeleteIcon = () => (
  21. <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
  22. <polyline points="3 6 5 6 21 6"></polyline>
  23. <path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"></path>
  24. <line x1="10" y1="11" x2="10" y2="17"></line>
  25. <line x1="14" y1="11" x2="14" y2="17"></line>
  26. </svg>
  27. );
  28. function History() {
  29. const {
  30. folders,
  31. handlePlayPause,
  32. handleLoop,
  33. handleDelete,
  34. handleKeyDown,
  35. getLoopButtonClassName,
  36. getLoopButtonTitle,
  37. getPlayButtonTitle,
  38. isPlaying,
  39. isLooping,
  40. formatCreatedAt,
  41. } = useHistory();
  42. const createKeyDownHandler = (handler) => (e) => handleKeyDown(e, handler);
  43. return (
  44. <div className="History-container">
  45. <div className="History-list">
  46. {folders.map((folder, index) => (
  47. <div key={index} className="History-item">
  48. <div className="History-item-content">
  49. <div className="History-item-buttons">
  50. <div
  51. className={getLoopButtonClassName(index)}
  52. onClick={(e) => handleLoop(index, e)}
  53. role="button"
  54. tabIndex={0}
  55. onKeyDown={createKeyDownHandler((e) => handleLoop(index, e))}
  56. title={getLoopButtonTitle(index)}
  57. >
  58. <LoopIcon active={isLooping(index)} />
  59. </div>
  60. <div
  61. className="History-item-button"
  62. onClick={(e) => handlePlayPause(index, e)}
  63. role="button"
  64. tabIndex={0}
  65. onKeyDown={createKeyDownHandler((e) => handlePlayPause(index, e))}
  66. title={getPlayButtonTitle(index)}
  67. >
  68. {isPlaying(index) ? <PauseIcon /> : <PlayIcon />}
  69. </div>
  70. <div
  71. className="History-item-button"
  72. onClick={(e) => handleDelete(index, e)}
  73. role="button"
  74. tabIndex={0}
  75. onKeyDown={createKeyDownHandler((e) => handleDelete(index, e))}
  76. title="删除"
  77. >
  78. <DeleteIcon />
  79. </div>
  80. </div>
  81. <div
  82. className="History-item-info"
  83. onClick={(e) => {
  84. // 如果点击的是按钮区域,不触发
  85. if (e.target.closest('.History-item-buttons')) {
  86. return;
  87. }
  88. // 触发打开蓝图编辑器事件
  89. window.dispatchEvent(new CustomEvent('open-blueprint', {
  90. detail: { workflowName: folder.name }
  91. }));
  92. }}
  93. style={{ cursor: 'pointer' }}
  94. title="点击进入可视化编程界面"
  95. >
  96. <div className="History-item-name">{folder.name}</div>
  97. {folder.createdAt && (
  98. <div className="History-item-time">{formatCreatedAt(folder.createdAt)}</div>
  99. )}
  100. </div>
  101. </div>
  102. </div>
  103. ))}
  104. </div>
  105. </div>
  106. );
  107. }
  108. export default History;