+ {/* Quick Mode Full-width Thumbnail */}
+ {isQuickMode && (
+ layer.resultSrc ? (
+
+ )
+ )}
+
+ {/* Progress bar (running only) */}
+ {layer.status === 'running' && (
+
+ {/* Title row */}
+
+ {/* Drag handle / Thumbnail (Normal Mode Only) */}
+ {!isQuickMode && (
+ <>
+
+
+ {layer.resultSrc ? (
+

+ ) : (
+
+ ...
+
+ )}
+ >
+ )}
+
+
+
{layer.effectName}
+
{statusLabel}
+
+
+ {/* Visibility toggle (only when done and has result) */}
+ {layer.status === 'done' && layer.resultSrc && (
+
+ )}
+
+ {/* Delete */}
+ {layer.status !== 'running' && (!isQuickMode || isTopLayer) && (
+
+ )}
+
+
+ {/* Settings preview */}
+
+ {Object.entries(layer.settings).slice(0, 4).map(([k, v]) => (
+
+ {k}: {typeof v === 'boolean' ? (v ? 'on' : 'off') : typeof v === 'string' ? (
+
+
+ {v}
+
+ ) : v}
+
+ ))}
+
+
+ {/* Action buttons */}
+
+ {(() => {
+ const effect = useAppStore.getState().effects.find(e => e.id === layer.effectId)
+ if (!effect || layer.status !== 'idle') return null
+
+ const count = layer.strokes.length
+ const min = effect.min_strokes ?? 1
+ const max = effect.max_strokes
+
+ let warning = null
+ if (count < min) {
+ warning = `Requires at least ${min} stroke${min === 1 ? '' : 's'}`
+ } else if (max && count > max) {
+ warning = `Max ${max} stroke${max === 1 ? '' : 's'} allowed`
+ }
+
+ if (!warning) return null
+
+ return (
+
+ β οΈ {warning}. You have {count}.
+
+ )
+ })()}
+
+ {/* Hide Run Effect button if in Quick Mode */}
+ {!isQuickMode && (layer.status === 'idle' || layer.status === 'aborted' || layer.status === 'error') && (
+
+ )}
+
+ {layer.status === 'running' && (
+ <>
+
+
+ {Math.round(layer.progress * 100)}%
+
+
+ >
+ )}
+
+ {/* Hide Rerun and Merge buttons if in Quick Mode */}
+ {!isQuickMode && layer.status === 'done' && layer.resultSrc && (
+
+
+
+
+ )}
+
+