plotlink-ows 1.2.95 → 1.2.96

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -85,67 +85,78 @@ export function FinishEpisodePanel({
85
85
  ? "Episode ready to publish"
86
86
  : "Finish episode";
87
87
 
88
+ const outstandingCount = steps.filter((s) => s.status !== "done").length;
89
+ const issuesCount = groups.reduce((sum, g) => sum + g.lines.length, 0);
90
+
88
91
  return (
89
92
  <div
90
- className="px-3 py-2 border-b border-border bg-surface/50 space-y-2 flex-shrink-0"
93
+ className="px-3 py-1.5 border-b border-border bg-surface/50 flex-shrink-0"
91
94
  data-testid="finish-episode-panel"
92
95
  >
93
- <div className="flex items-center justify-between gap-2">
96
+ <div className="flex flex-wrap items-center gap-2">
94
97
  <span className="text-[11px] font-medium text-foreground">Finish episode</span>
95
98
  {checklist.nextStep && (
96
- <span className="text-[10px] text-muted truncate" data-testid="finish-next-step">
99
+ <span className="min-w-0 flex-1 text-[10px] text-muted truncate" data-testid="finish-next-step">
97
100
  Next: {checklist.nextStep}
98
101
  </span>
99
102
  )}
103
+ <button
104
+ onClick={onFinish}
105
+ disabled={finishing || !canFinish}
106
+ data-testid="finish-episode-btn"
107
+ title="Upload the exported final panels, then prepare the episode for publishing — picks up where it left off"
108
+ className="px-2.5 py-0.5 text-[11px] border border-accent/40 text-accent rounded hover:bg-accent/5 disabled:opacity-50"
109
+ >
110
+ {buttonLabel}
111
+ </button>
100
112
  </div>
101
113
 
102
- {/* Writer-language step status — the exact webtoon production sequence. */}
103
- <ol className="flex flex-wrap gap-1.5">
104
- {steps.map((s) => (
105
- <li
106
- key={s.key}
107
- data-testid={`finish-step-${s.key}`}
108
- data-status={s.status}
109
- className={`flex items-center gap-1 rounded border px-1.5 py-0.5 text-[10px] ${
110
- s.status === "current"
111
- ? "border-accent/40 bg-accent/10 text-accent"
112
- : s.status === "done"
113
- ? "border-border bg-background/70 text-foreground"
114
- : "border-border/70 bg-background/40 text-muted"
115
- }`}
116
- >
117
- <span aria-hidden>{STATUS_MARK[s.status]}</span>
118
- <span>{s.label}</span>
119
- {s.detail && <span className="text-muted">· {s.detail}</span>}
120
- </li>
121
- ))}
122
- </ol>
114
+ <details className="mt-1" data-testid="finish-episode-details">
115
+ <summary className="cursor-pointer select-none text-[10px] text-muted hover:text-foreground">
116
+ {outstandingCount === 0 ? "Progress details" : `${outstandingCount} step${outstandingCount === 1 ? "" : "s"} left`}
117
+ {issuesCount > 0 ? ` · ${issuesCount} blocker${issuesCount === 1 ? "" : "s"}` : ""}
118
+ </summary>
123
119
 
124
- <button
125
- onClick={onFinish}
126
- disabled={finishing || !canFinish}
127
- data-testid="finish-episode-btn"
128
- title="Upload the exported final panels, then prepare the episode for publishing — picks up where it left off"
129
- className="px-3 py-1 text-xs border border-accent/40 text-accent rounded hover:bg-accent/5 disabled:opacity-50"
130
- >
131
- {buttonLabel}
132
- </button>
120
+ <div className="mt-1.5 space-y-1.5">
121
+ {/* Writer-language step status — the exact webtoon production sequence. */}
122
+ <ol className="flex flex-wrap gap-1.5">
123
+ {steps.map((s) => (
124
+ <li
125
+ key={s.key}
126
+ data-testid={`finish-step-${s.key}`}
127
+ data-status={s.status}
128
+ className={`flex items-center gap-1 rounded border px-1.5 py-0.5 text-[10px] ${
129
+ s.status === "current"
130
+ ? "border-accent/40 bg-accent/10 text-accent"
131
+ : s.status === "done"
132
+ ? "border-border bg-background/70 text-foreground"
133
+ : "border-border/70 bg-background/40 text-muted"
134
+ }`}
135
+ >
136
+ <span aria-hidden>{STATUS_MARK[s.status]}</span>
137
+ <span>{s.label}</span>
138
+ {s.detail && <span className="text-muted">· {s.detail}</span>}
139
+ </li>
140
+ ))}
141
+ </ol>
133
142
 
134
- {/* Blockers grouped by the step that fixes them, not a flat red list. */}
135
- {groups.length > 0 && (
136
- <div className="space-y-1.5" data-testid="finish-issues">
137
- {groups.map((g) => (
138
- <div key={g.key} data-testid={`finish-issue-group-${g.key}`} className="text-[10px]">
139
- <p className="font-medium text-amber-700">{g.title}</p>
140
- <ul className="ml-3 list-disc text-muted">
141
- {g.lines.map((line, i) => (
142
- <li key={i}>{line}</li>
143
- ))}
144
- </ul>
143
+ {/* Blockers grouped by the step that fixes them, not a flat red list. */}
144
+ {groups.length > 0 && (
145
+ <div className="space-y-1.5" data-testid="finish-issues">
146
+ {groups.map((g) => (
147
+ <div key={g.key} data-testid={`finish-issue-group-${g.key}`} className="text-[10px]">
148
+ <p className="font-medium text-amber-700">{g.title}</p>
149
+ <ul className="ml-3 list-disc text-muted">
150
+ {g.lines.map((line, i) => (
151
+ <li key={i}>{line}</li>
152
+ ))}
153
+ </ul>
154
+ </div>
155
+ ))}
145
156
  </div>
146
- ))}
157
+ )}
147
158
  </div>
148
- )}
159
+ </details>
149
160
  </div>
150
161
  );
151
162
  }