@plasius/video 0.1.2 → 0.1.4
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.
- package/CHANGELOG.md +8 -2
- package/README.md +57 -18
- package/dist/index.cjs +1163 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +147 -1
- package/dist/index.d.ts +147 -1
- package/dist/index.js +1155 -1
- package/dist/index.js.map +1 -1
- package/package.json +10 -5
- package/src/ai-video-generation/demo-model.ts +115 -0
- package/src/ai-video-generation/demo.tsx +69 -0
- package/src/ai-video-generation/index.ts +6 -0
- package/src/ai-video-generation/screen.tsx +1024 -0
- package/src/ai-video-generation/stages.ts +53 -0
- package/src/ai-video-generation/tokens.ts +52 -0
- package/src/ai-video-generation/types.ts +62 -0
- package/src/index.ts +3 -1
|
@@ -0,0 +1,1024 @@
|
|
|
1
|
+
import type { CSSProperties, ReactNode } from "react";
|
|
2
|
+
import { aiVideoStageFlow } from "./stages.js";
|
|
3
|
+
import { aiVideoGenerationTokens } from "./tokens.js";
|
|
4
|
+
import type { AIVideoGenerationScreenModel, AIVideoImageVariant, AIVideoGenerationStage } from "./types.js";
|
|
5
|
+
|
|
6
|
+
const stageLabel: Record<AIVideoGenerationStage, string> = {
|
|
7
|
+
idle: "Prompt",
|
|
8
|
+
generatingImages: "Images",
|
|
9
|
+
imageSelection: "Selection",
|
|
10
|
+
generatingVideo: "Video",
|
|
11
|
+
playback: "Playback",
|
|
12
|
+
voiceover: "Voiceover",
|
|
13
|
+
export: "Export",
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
function clampProgress(value: number | undefined): number {
|
|
17
|
+
if (typeof value !== "number" || Number.isNaN(value)) {
|
|
18
|
+
return 0;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
if (value < 0) {
|
|
22
|
+
return 0;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
if (value > 100) {
|
|
26
|
+
return 100;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
return Math.round(value);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function gradientForCard(index: number): string {
|
|
33
|
+
const gradients = [
|
|
34
|
+
"linear-gradient(140deg, #20305a 0%, #6c5ce7 45%, #00d4ff 100%)",
|
|
35
|
+
"linear-gradient(140deg, #2b1f3f 0%, #6c5ce7 48%, #3dd9f5 100%)",
|
|
36
|
+
"linear-gradient(140deg, #283645 0%, #4f89c2 46%, #9be3ff 100%)",
|
|
37
|
+
"linear-gradient(140deg, #2f2921 0%, #8a5f3a 48%, #ffd39f 100%)",
|
|
38
|
+
];
|
|
39
|
+
|
|
40
|
+
return gradients[index % gradients.length];
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export interface AIVideoGenerationScreenCallbacks {
|
|
44
|
+
onHistory?: () => void;
|
|
45
|
+
onSettings?: () => void;
|
|
46
|
+
onExport?: () => void;
|
|
47
|
+
onAccount?: () => void;
|
|
48
|
+
onGenerate?: () => void;
|
|
49
|
+
onUploadImage?: () => void;
|
|
50
|
+
onAdvanced?: () => void;
|
|
51
|
+
onSelectImage?: (variant: AIVideoImageVariant) => void;
|
|
52
|
+
onRefineImage?: (variant: AIVideoImageVariant) => void;
|
|
53
|
+
onSaveImage?: (variant: AIVideoImageVariant) => void;
|
|
54
|
+
onUseForVideo?: (variant: AIVideoImageVariant) => void;
|
|
55
|
+
onAddVoiceover?: () => void;
|
|
56
|
+
onRegenerateVideo?: () => void;
|
|
57
|
+
onDownloadVideo?: () => void;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export interface AIVideoGenerationScreenProps extends AIVideoGenerationScreenCallbacks {
|
|
61
|
+
model: AIVideoGenerationScreenModel;
|
|
62
|
+
className?: string;
|
|
63
|
+
style?: CSSProperties;
|
|
64
|
+
showContextPanel?: boolean;
|
|
65
|
+
reduceMotion?: boolean;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function renderImageCard(
|
|
69
|
+
variant: AIVideoImageVariant,
|
|
70
|
+
index: number,
|
|
71
|
+
callbacks: AIVideoGenerationScreenCallbacks,
|
|
72
|
+
): ReactNode {
|
|
73
|
+
const isSelected = Boolean(variant.isSelected);
|
|
74
|
+
|
|
75
|
+
return (
|
|
76
|
+
<article
|
|
77
|
+
className={`plv-image-card${isSelected ? " is-selected" : ""}`}
|
|
78
|
+
key={variant.id}
|
|
79
|
+
aria-label={variant.alt ?? variant.label}
|
|
80
|
+
>
|
|
81
|
+
<button
|
|
82
|
+
type="button"
|
|
83
|
+
className="plv-image-select-hitbox"
|
|
84
|
+
aria-pressed={isSelected}
|
|
85
|
+
onClick={() => callbacks.onSelectImage?.(variant)}
|
|
86
|
+
>
|
|
87
|
+
{variant.src ? (
|
|
88
|
+
<img src={variant.src} alt={variant.alt ?? variant.label} className="plv-image-media" />
|
|
89
|
+
) : (
|
|
90
|
+
<div className="plv-image-media" style={{ background: gradientForCard(index) }} />
|
|
91
|
+
)}
|
|
92
|
+
<div className="plv-image-caption">
|
|
93
|
+
<span>{variant.label}</span>
|
|
94
|
+
{isSelected ? <span className="plv-chip">Selected</span> : null}
|
|
95
|
+
</div>
|
|
96
|
+
</button>
|
|
97
|
+
|
|
98
|
+
<div className="plv-image-overlay-controls" role="group" aria-label={`${variant.label} controls`}>
|
|
99
|
+
<button type="button" onClick={() => callbacks.onRefineImage?.(variant)}>
|
|
100
|
+
Refine
|
|
101
|
+
</button>
|
|
102
|
+
<button type="button" onClick={() => callbacks.onSaveImage?.(variant)}>
|
|
103
|
+
Save
|
|
104
|
+
</button>
|
|
105
|
+
<button type="button" onClick={() => callbacks.onUseForVideo?.(variant)}>
|
|
106
|
+
Use for Video
|
|
107
|
+
</button>
|
|
108
|
+
</div>
|
|
109
|
+
|
|
110
|
+
{isSelected ? (
|
|
111
|
+
<span className="plv-selected-checkmark" aria-hidden="true">
|
|
112
|
+
✓
|
|
113
|
+
</span>
|
|
114
|
+
) : null}
|
|
115
|
+
</article>
|
|
116
|
+
);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
function renderSkeletonGrid(count: number): ReactNode {
|
|
120
|
+
const items = Array.from({ length: count }).map((_, index) => (
|
|
121
|
+
<div className="plv-skeleton-card" key={`skeleton-${index}`} />
|
|
122
|
+
));
|
|
123
|
+
|
|
124
|
+
return <div className="plv-image-grid">{items}</div>;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
function renderStageCanvas(
|
|
128
|
+
model: AIVideoGenerationScreenModel,
|
|
129
|
+
callbacks: AIVideoGenerationScreenCallbacks,
|
|
130
|
+
): ReactNode {
|
|
131
|
+
const progress = clampProgress(model.generationProgress);
|
|
132
|
+
|
|
133
|
+
if (model.stage === "generatingImages") {
|
|
134
|
+
return (
|
|
135
|
+
<>
|
|
136
|
+
<h2>Generating Image Variants</h2>
|
|
137
|
+
<p className="plv-muted">{model.statusText}</p>
|
|
138
|
+
{renderSkeletonGrid(model.imageVariants.length > 0 ? model.imageVariants.length : 8)}
|
|
139
|
+
</>
|
|
140
|
+
);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
if (model.stage === "imageSelection") {
|
|
144
|
+
return (
|
|
145
|
+
<>
|
|
146
|
+
<h2>Course Setting Image Grid</h2>
|
|
147
|
+
<p className="plv-muted">Select a visual anchor before video generation.</p>
|
|
148
|
+
<div className="plv-image-grid">
|
|
149
|
+
{model.imageVariants.map((variant, index) => renderImageCard(variant, index, callbacks))}
|
|
150
|
+
</div>
|
|
151
|
+
</>
|
|
152
|
+
);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
if (model.stage === "generatingVideo") {
|
|
156
|
+
return (
|
|
157
|
+
<>
|
|
158
|
+
<h2>Video Generation Phase</h2>
|
|
159
|
+
<div className="plv-split-panel">
|
|
160
|
+
<div className="plv-preview-box">
|
|
161
|
+
<div className="plv-preview-title">Image Preview</div>
|
|
162
|
+
<div className="plv-preview-media" />
|
|
163
|
+
</div>
|
|
164
|
+
<div className="plv-motion-panel">
|
|
165
|
+
<div className="plv-preview-title">Motion Summary</div>
|
|
166
|
+
<label>
|
|
167
|
+
Camera motion
|
|
168
|
+
<textarea readOnly value={model.motionDraft.cameraMotion} />
|
|
169
|
+
</label>
|
|
170
|
+
<label>
|
|
171
|
+
Environmental motion
|
|
172
|
+
<textarea readOnly value={model.motionDraft.environmentalMotion} />
|
|
173
|
+
</label>
|
|
174
|
+
<label>
|
|
175
|
+
Subject motion
|
|
176
|
+
<textarea readOnly value={model.motionDraft.subjectMotion} />
|
|
177
|
+
</label>
|
|
178
|
+
</div>
|
|
179
|
+
</div>
|
|
180
|
+
<div className="plv-progress-panel">
|
|
181
|
+
<div className="plv-progress-topline">
|
|
182
|
+
<span>Generating Video...</span>
|
|
183
|
+
<span>{progress}%</span>
|
|
184
|
+
</div>
|
|
185
|
+
<div className="plv-progress-track" role="progressbar" aria-valuemin={0} aria-valuemax={100} aria-valuenow={progress}>
|
|
186
|
+
<div className="plv-progress-fill" style={{ width: `${progress}%` }} />
|
|
187
|
+
</div>
|
|
188
|
+
<div className="plv-waveform" aria-hidden="true" />
|
|
189
|
+
</div>
|
|
190
|
+
</>
|
|
191
|
+
);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
if (model.stage === "playback" || model.stage === "voiceover" || model.stage === "export") {
|
|
195
|
+
return (
|
|
196
|
+
<>
|
|
197
|
+
<h2>Video Playback</h2>
|
|
198
|
+
<div className="plv-player-shell">
|
|
199
|
+
<div className="plv-player-frame">
|
|
200
|
+
<div className="plv-player-glow" />
|
|
201
|
+
<div className="plv-player-screen">16:9 Preview Frame</div>
|
|
202
|
+
</div>
|
|
203
|
+
<div className="plv-player-controls">
|
|
204
|
+
<button type="button">Play / Pause</button>
|
|
205
|
+
<button type="button">Timeline</button>
|
|
206
|
+
<button type="button">Volume</button>
|
|
207
|
+
<button type="button" onClick={callbacks.onDownloadVideo}>
|
|
208
|
+
Download
|
|
209
|
+
</button>
|
|
210
|
+
<button type="button" onClick={callbacks.onRegenerateVideo}>
|
|
211
|
+
Regenerate
|
|
212
|
+
</button>
|
|
213
|
+
<button type="button" onClick={callbacks.onAddVoiceover}>
|
|
214
|
+
Add Voiceover
|
|
215
|
+
</button>
|
|
216
|
+
</div>
|
|
217
|
+
</div>
|
|
218
|
+
|
|
219
|
+
{model.stage === "voiceover" ? (
|
|
220
|
+
<section className="plv-voiceover-panel" aria-label="Voiceover panel">
|
|
221
|
+
<div className="plv-preview-title">Extracted Speech</div>
|
|
222
|
+
<textarea readOnly value={model.voiceSettings.script} />
|
|
223
|
+
<div className="plv-voice-grid">
|
|
224
|
+
<div>
|
|
225
|
+
<div className="plv-field-label">Voice</div>
|
|
226
|
+
<div className="plv-pill-group">
|
|
227
|
+
{model.voicePresets.map((voice) => (
|
|
228
|
+
<button
|
|
229
|
+
type="button"
|
|
230
|
+
key={voice.id}
|
|
231
|
+
className={voice.id === model.voiceSettings.voiceId ? "is-active" : undefined}
|
|
232
|
+
>
|
|
233
|
+
{voice.label}
|
|
234
|
+
</button>
|
|
235
|
+
))}
|
|
236
|
+
</div>
|
|
237
|
+
</div>
|
|
238
|
+
<div>
|
|
239
|
+
<div className="plv-field-label">Speed: {model.voiceSettings.speed.toFixed(1)}x</div>
|
|
240
|
+
<div className="plv-slider-track" />
|
|
241
|
+
</div>
|
|
242
|
+
<div>
|
|
243
|
+
<div className="plv-field-label">Emotion: {model.voiceSettings.emotion}</div>
|
|
244
|
+
<div className="plv-slider-track" />
|
|
245
|
+
</div>
|
|
246
|
+
</div>
|
|
247
|
+
<div className="plv-waveform is-voiceover" aria-hidden="true" />
|
|
248
|
+
</section>
|
|
249
|
+
) : null}
|
|
250
|
+
|
|
251
|
+
{model.stage === "export" ? (
|
|
252
|
+
<div className="plv-export-modal" role="dialog" aria-label="Export modal">
|
|
253
|
+
<h3>Export</h3>
|
|
254
|
+
<p>Finalize codec, quality, and voice mixdown profile.</p>
|
|
255
|
+
<button type="button" onClick={callbacks.onExport}>
|
|
256
|
+
Confirm Export
|
|
257
|
+
</button>
|
|
258
|
+
</div>
|
|
259
|
+
) : null}
|
|
260
|
+
</>
|
|
261
|
+
);
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
return (
|
|
265
|
+
<>
|
|
266
|
+
<h2>Prompt Entry</h2>
|
|
267
|
+
<p className="plv-muted">Start with a cinematic prompt, then generate course-setting images.</p>
|
|
268
|
+
<div className="plv-idle-canvas">
|
|
269
|
+
{model.uploadedImageName ? (
|
|
270
|
+
<>
|
|
271
|
+
<div className="plv-upload-chip">Upload Image: {model.uploadedImageName}</div>
|
|
272
|
+
<div className="plv-required-chip">Add Motion Instructions (Required)</div>
|
|
273
|
+
</>
|
|
274
|
+
) : (
|
|
275
|
+
<div className="plv-upload-chip">Upload an image or write a prompt to begin.</div>
|
|
276
|
+
)}
|
|
277
|
+
</div>
|
|
278
|
+
</>
|
|
279
|
+
);
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
export function AIVideoGenerationScreen({
|
|
283
|
+
model,
|
|
284
|
+
className,
|
|
285
|
+
style,
|
|
286
|
+
showContextPanel = true,
|
|
287
|
+
reduceMotion = false,
|
|
288
|
+
...callbacks
|
|
289
|
+
}: AIVideoGenerationScreenProps) {
|
|
290
|
+
const rootClassName = [
|
|
291
|
+
"plv-video-screen",
|
|
292
|
+
reduceMotion ? "plv-reduce-motion" : "",
|
|
293
|
+
className ?? "",
|
|
294
|
+
]
|
|
295
|
+
.filter(Boolean)
|
|
296
|
+
.join(" ");
|
|
297
|
+
|
|
298
|
+
const requiresMotionPrompt = Boolean(model.uploadedImageName) && !model.motionPrompt?.trim();
|
|
299
|
+
|
|
300
|
+
return (
|
|
301
|
+
<section className={rootClassName} style={style}>
|
|
302
|
+
<style>{AI_VIDEO_GENERATION_SCREEN_STYLES}</style>
|
|
303
|
+
|
|
304
|
+
<header className="plv-header">
|
|
305
|
+
<div className="plv-logo">PLASIUS</div>
|
|
306
|
+
<div className="plv-project-title">{model.projectName}</div>
|
|
307
|
+
<div className="plv-header-actions">
|
|
308
|
+
<button type="button" onClick={callbacks.onHistory}>
|
|
309
|
+
History
|
|
310
|
+
</button>
|
|
311
|
+
<button type="button" onClick={callbacks.onSettings}>
|
|
312
|
+
Settings
|
|
313
|
+
</button>
|
|
314
|
+
<button type="button" onClick={callbacks.onExport}>
|
|
315
|
+
Export
|
|
316
|
+
</button>
|
|
317
|
+
<button type="button" onClick={callbacks.onAccount}>
|
|
318
|
+
Account
|
|
319
|
+
</button>
|
|
320
|
+
</div>
|
|
321
|
+
</header>
|
|
322
|
+
|
|
323
|
+
<main className="plv-main-canvas">{renderStageCanvas(model, callbacks)}</main>
|
|
324
|
+
|
|
325
|
+
{showContextPanel ? (
|
|
326
|
+
<aside className="plv-context-panel">
|
|
327
|
+
<div className="plv-context-title">Context Panel</div>
|
|
328
|
+
<div className="plv-chip-row" role="list" aria-label="Prompt versions">
|
|
329
|
+
{model.promptVersions.map((version) => (
|
|
330
|
+
<button
|
|
331
|
+
type="button"
|
|
332
|
+
key={version.id}
|
|
333
|
+
role="listitem"
|
|
334
|
+
className={version.isActive ? "is-active" : undefined}
|
|
335
|
+
>
|
|
336
|
+
{version.label}
|
|
337
|
+
</button>
|
|
338
|
+
))}
|
|
339
|
+
</div>
|
|
340
|
+
<div className="plv-metadata-grid">
|
|
341
|
+
<div>
|
|
342
|
+
<span>Stage</span>
|
|
343
|
+
<strong>{stageLabel[model.stage]}</strong>
|
|
344
|
+
</div>
|
|
345
|
+
<div>
|
|
346
|
+
<span>Status</span>
|
|
347
|
+
<strong>{model.statusText}</strong>
|
|
348
|
+
</div>
|
|
349
|
+
<div>
|
|
350
|
+
<span>Prompt</span>
|
|
351
|
+
<strong>{model.prompt}</strong>
|
|
352
|
+
</div>
|
|
353
|
+
</div>
|
|
354
|
+
<div className="plv-stage-row">
|
|
355
|
+
{aiVideoStageFlow.map((stage) => (
|
|
356
|
+
<span key={stage.stage} className={stage.stage === model.stage ? "is-active" : undefined}>
|
|
357
|
+
{stage.label}
|
|
358
|
+
</span>
|
|
359
|
+
))}
|
|
360
|
+
</div>
|
|
361
|
+
</aside>
|
|
362
|
+
) : null}
|
|
363
|
+
|
|
364
|
+
<footer className="plv-prompt-area">
|
|
365
|
+
<label className="plv-sr-only" htmlFor="plv-prompt-textarea">
|
|
366
|
+
Prompt input
|
|
367
|
+
</label>
|
|
368
|
+
<textarea
|
|
369
|
+
id="plv-prompt-textarea"
|
|
370
|
+
value={model.prompt}
|
|
371
|
+
readOnly
|
|
372
|
+
placeholder={model.promptPlaceholder}
|
|
373
|
+
aria-label="Prompt input"
|
|
374
|
+
/>
|
|
375
|
+
|
|
376
|
+
<div className="plv-prompt-actions">
|
|
377
|
+
<button type="button" onClick={callbacks.onUploadImage}>
|
|
378
|
+
Upload Image
|
|
379
|
+
</button>
|
|
380
|
+
<button type="button" onClick={callbacks.onAdvanced}>
|
|
381
|
+
Advanced
|
|
382
|
+
</button>
|
|
383
|
+
<button type="button" className="is-generate" disabled={!model.canGenerate} onClick={callbacks.onGenerate}>
|
|
384
|
+
Generate
|
|
385
|
+
</button>
|
|
386
|
+
</div>
|
|
387
|
+
|
|
388
|
+
{requiresMotionPrompt ? (
|
|
389
|
+
<div className="plv-required-chip">Upload Image complete. Motion prompt is required before generating.</div>
|
|
390
|
+
) : null}
|
|
391
|
+
</footer>
|
|
392
|
+
</section>
|
|
393
|
+
);
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
export const AI_VIDEO_GENERATION_SCREEN_STYLES = `
|
|
397
|
+
.plv-video-screen {
|
|
398
|
+
--plv-background: ${aiVideoGenerationTokens.color.background};
|
|
399
|
+
--plv-surface: ${aiVideoGenerationTokens.color.surface};
|
|
400
|
+
--plv-border: ${aiVideoGenerationTokens.color.borderSubtle};
|
|
401
|
+
--plv-text: ${aiVideoGenerationTokens.color.textPrimary};
|
|
402
|
+
--plv-text-muted: ${aiVideoGenerationTokens.color.textSecondary};
|
|
403
|
+
--plv-accent-primary: ${aiVideoGenerationTokens.color.accentPrimary};
|
|
404
|
+
--plv-accent-secondary: ${aiVideoGenerationTokens.color.accentSecondary};
|
|
405
|
+
--plv-success: ${aiVideoGenerationTokens.color.success};
|
|
406
|
+
--plv-warning: ${aiVideoGenerationTokens.color.warning};
|
|
407
|
+
--plv-error: ${aiVideoGenerationTokens.color.error};
|
|
408
|
+
--plv-prompt-placeholder: ${aiVideoGenerationTokens.color.placeholderText};
|
|
409
|
+
--plv-header-height: ${aiVideoGenerationTokens.layout.headerHeightPx}px;
|
|
410
|
+
--plv-transition: ${aiVideoGenerationTokens.animation.standardMs}ms ${aiVideoGenerationTokens.animation.easing};
|
|
411
|
+
font-family: ${aiVideoGenerationTokens.typography.bodyFontFamily};
|
|
412
|
+
color: var(--plv-text);
|
|
413
|
+
background:
|
|
414
|
+
radial-gradient(1200px 520px at 20% -10%, rgba(108, 92, 231, 0.22), transparent 62%),
|
|
415
|
+
radial-gradient(1000px 540px at 80% -20%, rgba(0, 212, 255, 0.16), transparent 60%),
|
|
416
|
+
var(--plv-background);
|
|
417
|
+
border-radius: ${aiVideoGenerationTokens.radius.panelPx}px;
|
|
418
|
+
border: 1px solid var(--plv-border);
|
|
419
|
+
overflow: hidden;
|
|
420
|
+
display: grid;
|
|
421
|
+
grid-template-rows: var(--plv-header-height) minmax(360px, 1fr) auto auto;
|
|
422
|
+
min-height: 820px;
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
.plv-header {
|
|
426
|
+
display: flex;
|
|
427
|
+
align-items: center;
|
|
428
|
+
gap: 14px;
|
|
429
|
+
padding: 0 16px;
|
|
430
|
+
border-bottom: 1px solid var(--plv-border);
|
|
431
|
+
background: #0f1117;
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
.plv-logo {
|
|
435
|
+
font-weight: 800;
|
|
436
|
+
letter-spacing: 0.08em;
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
.plv-project-title {
|
|
440
|
+
font-size: 15px;
|
|
441
|
+
color: var(--plv-text-muted);
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
.plv-header-actions {
|
|
445
|
+
margin-left: auto;
|
|
446
|
+
display: flex;
|
|
447
|
+
gap: 8px;
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
.plv-header-actions button,
|
|
451
|
+
.plv-player-controls button,
|
|
452
|
+
.plv-prompt-actions button,
|
|
453
|
+
.plv-chip-row button,
|
|
454
|
+
.plv-pill-group button,
|
|
455
|
+
.plv-image-overlay-controls button {
|
|
456
|
+
border: 1px solid var(--plv-border);
|
|
457
|
+
background: rgba(255, 255, 255, 0.02);
|
|
458
|
+
color: var(--plv-text);
|
|
459
|
+
border-radius: 10px;
|
|
460
|
+
padding: 8px 12px;
|
|
461
|
+
font-size: 13px;
|
|
462
|
+
transition: all var(--plv-transition);
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
.plv-header-actions button:hover,
|
|
466
|
+
.plv-player-controls button:hover,
|
|
467
|
+
.plv-prompt-actions button:hover,
|
|
468
|
+
.plv-chip-row button:hover,
|
|
469
|
+
.plv-pill-group button:hover,
|
|
470
|
+
.plv-image-overlay-controls button:hover {
|
|
471
|
+
border-color: rgba(0, 212, 255, 0.45);
|
|
472
|
+
box-shadow: 0 0 0 1px rgba(0, 212, 255, 0.22);
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
.plv-main-canvas {
|
|
476
|
+
padding: 18px;
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
.plv-main-canvas h2 {
|
|
480
|
+
margin: 0 0 8px;
|
|
481
|
+
font-family: ${aiVideoGenerationTokens.typography.headingFontFamily};
|
|
482
|
+
font-size: ${aiVideoGenerationTokens.typography.h2Px}px;
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
.plv-muted {
|
|
486
|
+
margin: 0 0 14px;
|
|
487
|
+
color: var(--plv-text-muted);
|
|
488
|
+
font-size: ${aiVideoGenerationTokens.typography.smallPx}px;
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
.plv-image-grid {
|
|
492
|
+
display: grid;
|
|
493
|
+
gap: ${aiVideoGenerationTokens.layout.gridGapPx}px;
|
|
494
|
+
grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
.plv-image-card,
|
|
498
|
+
.plv-skeleton-card {
|
|
499
|
+
aspect-ratio: ${aiVideoGenerationTokens.layout.cardAspectRatio};
|
|
500
|
+
border-radius: ${aiVideoGenerationTokens.radius.cardPx}px;
|
|
501
|
+
position: relative;
|
|
502
|
+
overflow: hidden;
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
.plv-image-card {
|
|
506
|
+
border: 1px solid var(--plv-border);
|
|
507
|
+
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.4);
|
|
508
|
+
transition: transform var(--plv-transition), box-shadow var(--plv-transition), border-color var(--plv-transition);
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
.plv-image-card:hover {
|
|
512
|
+
transform: scale(1.02);
|
|
513
|
+
border-color: rgba(0, 212, 255, 0.55);
|
|
514
|
+
box-shadow: 0 14px 36px rgba(0, 0, 0, 0.48);
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
.plv-image-card.is-selected {
|
|
518
|
+
border: 2px solid var(--plv-accent-secondary);
|
|
519
|
+
box-shadow: 0 0 0 1px rgba(108, 92, 231, 0.35), 0 16px 32px rgba(0, 0, 0, 0.55);
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
.plv-image-select-hitbox {
|
|
523
|
+
border: 0;
|
|
524
|
+
margin: 0;
|
|
525
|
+
width: 100%;
|
|
526
|
+
height: 100%;
|
|
527
|
+
padding: 0;
|
|
528
|
+
background: none;
|
|
529
|
+
display: flex;
|
|
530
|
+
flex-direction: column;
|
|
531
|
+
justify-content: flex-end;
|
|
532
|
+
cursor: pointer;
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
.plv-image-media {
|
|
536
|
+
position: absolute;
|
|
537
|
+
inset: 0;
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
.plv-image-caption {
|
|
541
|
+
z-index: 1;
|
|
542
|
+
display: flex;
|
|
543
|
+
justify-content: space-between;
|
|
544
|
+
align-items: center;
|
|
545
|
+
gap: 8px;
|
|
546
|
+
padding: 10px;
|
|
547
|
+
background: linear-gradient(180deg, transparent 0%, rgba(15, 17, 23, 0.84) 60%);
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
.plv-chip {
|
|
551
|
+
font-size: 11px;
|
|
552
|
+
border-radius: 999px;
|
|
553
|
+
padding: 2px 8px;
|
|
554
|
+
background: rgba(0, 212, 255, 0.14);
|
|
555
|
+
border: 1px solid rgba(0, 212, 255, 0.36);
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
.plv-selected-checkmark {
|
|
559
|
+
position: absolute;
|
|
560
|
+
top: 10px;
|
|
561
|
+
right: 10px;
|
|
562
|
+
width: 24px;
|
|
563
|
+
height: 24px;
|
|
564
|
+
display: grid;
|
|
565
|
+
place-items: center;
|
|
566
|
+
border-radius: 999px;
|
|
567
|
+
color: #00121a;
|
|
568
|
+
background: #7ff3ff;
|
|
569
|
+
font-weight: 900;
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
.plv-image-overlay-controls {
|
|
573
|
+
position: absolute;
|
|
574
|
+
top: 10px;
|
|
575
|
+
left: 10px;
|
|
576
|
+
display: flex;
|
|
577
|
+
gap: 8px;
|
|
578
|
+
opacity: 0;
|
|
579
|
+
transform: translateY(-6px);
|
|
580
|
+
transition: opacity var(--plv-transition), transform var(--plv-transition);
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
.plv-image-card:hover .plv-image-overlay-controls {
|
|
584
|
+
opacity: 1;
|
|
585
|
+
transform: translateY(0);
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
.plv-skeleton-card {
|
|
589
|
+
background: linear-gradient(
|
|
590
|
+
100deg,
|
|
591
|
+
rgba(255, 255, 255, 0.03) 20%,
|
|
592
|
+
rgba(255, 255, 255, 0.14) 40%,
|
|
593
|
+
rgba(255, 255, 255, 0.03) 60%
|
|
594
|
+
);
|
|
595
|
+
background-size: 200% 100%;
|
|
596
|
+
animation: plv-shimmer 1.25s linear infinite;
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
.plv-split-panel {
|
|
600
|
+
display: grid;
|
|
601
|
+
grid-template-columns: 1.1fr 0.9fr;
|
|
602
|
+
gap: 16px;
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
.plv-preview-box,
|
|
606
|
+
.plv-motion-panel,
|
|
607
|
+
.plv-progress-panel,
|
|
608
|
+
.plv-player-shell,
|
|
609
|
+
.plv-voiceover-panel,
|
|
610
|
+
.plv-idle-canvas,
|
|
611
|
+
.plv-context-panel,
|
|
612
|
+
.plv-prompt-area {
|
|
613
|
+
background: var(--plv-surface);
|
|
614
|
+
border: 1px solid var(--plv-border);
|
|
615
|
+
border-radius: ${aiVideoGenerationTokens.radius.panelPx}px;
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
.plv-preview-box,
|
|
619
|
+
.plv-motion-panel {
|
|
620
|
+
padding: 14px;
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
.plv-preview-title {
|
|
624
|
+
font-size: ${aiVideoGenerationTokens.typography.smallPx}px;
|
|
625
|
+
text-transform: uppercase;
|
|
626
|
+
letter-spacing: 0.08em;
|
|
627
|
+
color: var(--plv-text-muted);
|
|
628
|
+
margin-bottom: 10px;
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
.plv-preview-media {
|
|
632
|
+
width: 100%;
|
|
633
|
+
aspect-ratio: ${aiVideoGenerationTokens.layout.cardAspectRatio};
|
|
634
|
+
border-radius: ${aiVideoGenerationTokens.radius.cardPx}px;
|
|
635
|
+
background: linear-gradient(135deg, #2d3e67 0%, #6c5ce7 45%, #00d4ff 100%);
|
|
636
|
+
}
|
|
637
|
+
|
|
638
|
+
.plv-motion-panel label {
|
|
639
|
+
display: block;
|
|
640
|
+
font-size: ${aiVideoGenerationTokens.typography.smallPx}px;
|
|
641
|
+
color: var(--plv-text-muted);
|
|
642
|
+
margin-bottom: 10px;
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
.plv-motion-panel textarea,
|
|
646
|
+
.plv-voiceover-panel textarea {
|
|
647
|
+
width: 100%;
|
|
648
|
+
margin-top: 6px;
|
|
649
|
+
border: 1px solid var(--plv-border);
|
|
650
|
+
border-radius: 10px;
|
|
651
|
+
min-height: 62px;
|
|
652
|
+
resize: none;
|
|
653
|
+
background: rgba(255, 255, 255, 0.02);
|
|
654
|
+
color: var(--plv-text);
|
|
655
|
+
padding: 10px;
|
|
656
|
+
font-family: ${aiVideoGenerationTokens.typography.bodyFontFamily};
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
.plv-progress-panel {
|
|
660
|
+
margin-top: 16px;
|
|
661
|
+
padding: 12px 14px;
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
.plv-progress-topline {
|
|
665
|
+
display: flex;
|
|
666
|
+
justify-content: space-between;
|
|
667
|
+
font-size: ${aiVideoGenerationTokens.typography.smallPx}px;
|
|
668
|
+
margin-bottom: 8px;
|
|
669
|
+
}
|
|
670
|
+
|
|
671
|
+
.plv-progress-track {
|
|
672
|
+
height: 8px;
|
|
673
|
+
border-radius: 999px;
|
|
674
|
+
background: rgba(255, 255, 255, 0.08);
|
|
675
|
+
overflow: hidden;
|
|
676
|
+
}
|
|
677
|
+
|
|
678
|
+
.plv-progress-fill {
|
|
679
|
+
height: 100%;
|
|
680
|
+
background: linear-gradient(135deg, var(--plv-accent-primary), var(--plv-accent-secondary));
|
|
681
|
+
transition: width var(--plv-transition);
|
|
682
|
+
}
|
|
683
|
+
|
|
684
|
+
.plv-waveform {
|
|
685
|
+
margin-top: 10px;
|
|
686
|
+
height: 32px;
|
|
687
|
+
border-radius: 10px;
|
|
688
|
+
background:
|
|
689
|
+
repeating-linear-gradient(
|
|
690
|
+
90deg,
|
|
691
|
+
rgba(108, 92, 231, 0.24) 0,
|
|
692
|
+
rgba(108, 92, 231, 0.24) 4px,
|
|
693
|
+
rgba(0, 212, 255, 0.28) 4px,
|
|
694
|
+
rgba(0, 212, 255, 0.28) 8px
|
|
695
|
+
);
|
|
696
|
+
animation: plv-wave 1.2s linear infinite;
|
|
697
|
+
}
|
|
698
|
+
|
|
699
|
+
.plv-waveform.is-voiceover {
|
|
700
|
+
height: 46px;
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
.plv-player-shell {
|
|
704
|
+
padding: 14px;
|
|
705
|
+
}
|
|
706
|
+
|
|
707
|
+
.plv-player-frame {
|
|
708
|
+
position: relative;
|
|
709
|
+
aspect-ratio: ${aiVideoGenerationTokens.layout.cardAspectRatio};
|
|
710
|
+
background: #020202;
|
|
711
|
+
border-radius: ${aiVideoGenerationTokens.radius.cardPx}px;
|
|
712
|
+
overflow: hidden;
|
|
713
|
+
}
|
|
714
|
+
|
|
715
|
+
.plv-player-glow {
|
|
716
|
+
position: absolute;
|
|
717
|
+
inset: -20%;
|
|
718
|
+
background: radial-gradient(circle at center, rgba(0, 212, 255, 0.26), transparent 60%);
|
|
719
|
+
}
|
|
720
|
+
|
|
721
|
+
.plv-player-screen {
|
|
722
|
+
position: absolute;
|
|
723
|
+
inset: 0;
|
|
724
|
+
display: grid;
|
|
725
|
+
place-items: center;
|
|
726
|
+
color: rgba(230, 234, 242, 0.74);
|
|
727
|
+
font-size: 15px;
|
|
728
|
+
}
|
|
729
|
+
|
|
730
|
+
.plv-player-controls {
|
|
731
|
+
margin-top: 12px;
|
|
732
|
+
display: grid;
|
|
733
|
+
grid-template-columns: repeat(6, minmax(0, 1fr));
|
|
734
|
+
gap: 8px;
|
|
735
|
+
}
|
|
736
|
+
|
|
737
|
+
.plv-voiceover-panel {
|
|
738
|
+
margin-top: 14px;
|
|
739
|
+
padding: 14px;
|
|
740
|
+
animation: plv-slide-up var(--plv-transition);
|
|
741
|
+
}
|
|
742
|
+
|
|
743
|
+
.plv-voice-grid {
|
|
744
|
+
margin-top: 10px;
|
|
745
|
+
display: grid;
|
|
746
|
+
gap: 10px;
|
|
747
|
+
}
|
|
748
|
+
|
|
749
|
+
.plv-pill-group {
|
|
750
|
+
display: flex;
|
|
751
|
+
flex-wrap: wrap;
|
|
752
|
+
gap: 8px;
|
|
753
|
+
}
|
|
754
|
+
|
|
755
|
+
.plv-pill-group .is-active,
|
|
756
|
+
.plv-chip-row .is-active {
|
|
757
|
+
border-color: rgba(0, 212, 255, 0.6);
|
|
758
|
+
box-shadow: 0 0 0 1px rgba(0, 212, 255, 0.24);
|
|
759
|
+
}
|
|
760
|
+
|
|
761
|
+
.plv-field-label {
|
|
762
|
+
font-size: ${aiVideoGenerationTokens.typography.smallPx}px;
|
|
763
|
+
color: var(--plv-text-muted);
|
|
764
|
+
margin-bottom: 6px;
|
|
765
|
+
}
|
|
766
|
+
|
|
767
|
+
.plv-slider-track {
|
|
768
|
+
height: 8px;
|
|
769
|
+
border-radius: 999px;
|
|
770
|
+
background: linear-gradient(135deg, rgba(108, 92, 231, 0.7), rgba(0, 212, 255, 0.7));
|
|
771
|
+
}
|
|
772
|
+
|
|
773
|
+
.plv-export-modal {
|
|
774
|
+
margin-top: 14px;
|
|
775
|
+
padding: 14px;
|
|
776
|
+
border-radius: ${aiVideoGenerationTokens.radius.panelPx}px;
|
|
777
|
+
border: 1px solid rgba(255, 176, 32, 0.4);
|
|
778
|
+
background: rgba(255, 176, 32, 0.08);
|
|
779
|
+
}
|
|
780
|
+
|
|
781
|
+
.plv-export-modal h3 {
|
|
782
|
+
margin: 0 0 6px;
|
|
783
|
+
font-size: 18px;
|
|
784
|
+
}
|
|
785
|
+
|
|
786
|
+
.plv-export-modal p {
|
|
787
|
+
margin: 0 0 10px;
|
|
788
|
+
color: var(--plv-text-muted);
|
|
789
|
+
font-size: ${aiVideoGenerationTokens.typography.smallPx}px;
|
|
790
|
+
}
|
|
791
|
+
|
|
792
|
+
.plv-export-modal button {
|
|
793
|
+
border: 0;
|
|
794
|
+
border-radius: 10px;
|
|
795
|
+
background: linear-gradient(135deg, #ffb020, #ffd386);
|
|
796
|
+
color: #161a23;
|
|
797
|
+
font-weight: 700;
|
|
798
|
+
padding: 8px 12px;
|
|
799
|
+
}
|
|
800
|
+
|
|
801
|
+
.plv-idle-canvas {
|
|
802
|
+
min-height: 180px;
|
|
803
|
+
display: grid;
|
|
804
|
+
place-items: center;
|
|
805
|
+
gap: 10px;
|
|
806
|
+
padding: 16px;
|
|
807
|
+
}
|
|
808
|
+
|
|
809
|
+
.plv-upload-chip,
|
|
810
|
+
.plv-required-chip {
|
|
811
|
+
border-radius: 999px;
|
|
812
|
+
padding: 8px 12px;
|
|
813
|
+
font-size: ${aiVideoGenerationTokens.typography.smallPx}px;
|
|
814
|
+
}
|
|
815
|
+
|
|
816
|
+
.plv-upload-chip {
|
|
817
|
+
background: rgba(255, 255, 255, 0.04);
|
|
818
|
+
border: 1px solid var(--plv-border);
|
|
819
|
+
}
|
|
820
|
+
|
|
821
|
+
.plv-required-chip {
|
|
822
|
+
background: rgba(255, 176, 32, 0.12);
|
|
823
|
+
border: 1px solid rgba(255, 176, 32, 0.4);
|
|
824
|
+
color: #ffd18a;
|
|
825
|
+
}
|
|
826
|
+
|
|
827
|
+
.plv-context-panel {
|
|
828
|
+
margin: 0 18px 16px;
|
|
829
|
+
padding: 14px;
|
|
830
|
+
}
|
|
831
|
+
|
|
832
|
+
.plv-context-title {
|
|
833
|
+
margin-bottom: 10px;
|
|
834
|
+
font-size: ${aiVideoGenerationTokens.typography.smallPx}px;
|
|
835
|
+
text-transform: uppercase;
|
|
836
|
+
letter-spacing: 0.08em;
|
|
837
|
+
color: var(--plv-text-muted);
|
|
838
|
+
}
|
|
839
|
+
|
|
840
|
+
.plv-chip-row {
|
|
841
|
+
display: flex;
|
|
842
|
+
gap: 8px;
|
|
843
|
+
flex-wrap: wrap;
|
|
844
|
+
}
|
|
845
|
+
|
|
846
|
+
.plv-metadata-grid {
|
|
847
|
+
margin-top: 12px;
|
|
848
|
+
display: grid;
|
|
849
|
+
gap: 8px;
|
|
850
|
+
grid-template-columns: repeat(3, minmax(0, 1fr));
|
|
851
|
+
}
|
|
852
|
+
|
|
853
|
+
.plv-metadata-grid div {
|
|
854
|
+
display: grid;
|
|
855
|
+
gap: 4px;
|
|
856
|
+
}
|
|
857
|
+
|
|
858
|
+
.plv-metadata-grid span {
|
|
859
|
+
font-size: ${aiVideoGenerationTokens.typography.smallPx}px;
|
|
860
|
+
color: var(--plv-text-muted);
|
|
861
|
+
}
|
|
862
|
+
|
|
863
|
+
.plv-metadata-grid strong {
|
|
864
|
+
font-size: 14px;
|
|
865
|
+
line-height: 1.35;
|
|
866
|
+
}
|
|
867
|
+
|
|
868
|
+
.plv-stage-row {
|
|
869
|
+
margin-top: 10px;
|
|
870
|
+
display: flex;
|
|
871
|
+
gap: 8px;
|
|
872
|
+
flex-wrap: wrap;
|
|
873
|
+
}
|
|
874
|
+
|
|
875
|
+
.plv-stage-row span {
|
|
876
|
+
border-radius: 999px;
|
|
877
|
+
padding: 5px 10px;
|
|
878
|
+
border: 1px solid var(--plv-border);
|
|
879
|
+
color: var(--plv-text-muted);
|
|
880
|
+
font-size: 12px;
|
|
881
|
+
}
|
|
882
|
+
|
|
883
|
+
.plv-stage-row .is-active {
|
|
884
|
+
color: var(--plv-text);
|
|
885
|
+
border-color: rgba(0, 212, 255, 0.55);
|
|
886
|
+
}
|
|
887
|
+
|
|
888
|
+
.plv-prompt-area {
|
|
889
|
+
margin: 0 18px 18px;
|
|
890
|
+
padding: 14px;
|
|
891
|
+
}
|
|
892
|
+
|
|
893
|
+
.plv-prompt-area textarea {
|
|
894
|
+
width: 100%;
|
|
895
|
+
min-height: ${aiVideoGenerationTokens.layout.promptBarMinHeightPx}px;
|
|
896
|
+
border: 1px solid var(--plv-border);
|
|
897
|
+
border-radius: ${aiVideoGenerationTokens.radius.promptPx}px;
|
|
898
|
+
background: rgba(255, 255, 255, 0.02);
|
|
899
|
+
color: var(--plv-text);
|
|
900
|
+
font-family: ${aiVideoGenerationTokens.typography.bodyFontFamily};
|
|
901
|
+
font-size: 17px;
|
|
902
|
+
line-height: 1.45;
|
|
903
|
+
padding: 12px;
|
|
904
|
+
resize: vertical;
|
|
905
|
+
}
|
|
906
|
+
|
|
907
|
+
.plv-prompt-area textarea::placeholder {
|
|
908
|
+
color: var(--plv-prompt-placeholder);
|
|
909
|
+
}
|
|
910
|
+
|
|
911
|
+
.plv-prompt-actions {
|
|
912
|
+
margin-top: 10px;
|
|
913
|
+
display: flex;
|
|
914
|
+
gap: 8px;
|
|
915
|
+
align-items: center;
|
|
916
|
+
}
|
|
917
|
+
|
|
918
|
+
.plv-prompt-actions .is-generate {
|
|
919
|
+
margin-left: auto;
|
|
920
|
+
border: 0;
|
|
921
|
+
background: linear-gradient(135deg, #6c5ce7, #00d4ff);
|
|
922
|
+
box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.08), 0 12px 28px rgba(0, 212, 255, 0.22);
|
|
923
|
+
}
|
|
924
|
+
|
|
925
|
+
.plv-prompt-actions .is-generate:hover {
|
|
926
|
+
box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.08), 0 14px 34px rgba(0, 212, 255, 0.34);
|
|
927
|
+
}
|
|
928
|
+
|
|
929
|
+
.plv-prompt-actions .is-generate:disabled {
|
|
930
|
+
opacity: 0.4;
|
|
931
|
+
cursor: not-allowed;
|
|
932
|
+
}
|
|
933
|
+
|
|
934
|
+
.plv-sr-only {
|
|
935
|
+
position: absolute;
|
|
936
|
+
width: 1px;
|
|
937
|
+
height: 1px;
|
|
938
|
+
margin: -1px;
|
|
939
|
+
padding: 0;
|
|
940
|
+
overflow: hidden;
|
|
941
|
+
clip: rect(0, 0, 0, 0);
|
|
942
|
+
border: 0;
|
|
943
|
+
}
|
|
944
|
+
|
|
945
|
+
.plv-reduce-motion * {
|
|
946
|
+
animation: none !important;
|
|
947
|
+
transition: none !important;
|
|
948
|
+
}
|
|
949
|
+
|
|
950
|
+
@media (max-width: 1024px) {
|
|
951
|
+
.plv-video-screen {
|
|
952
|
+
min-height: 920px;
|
|
953
|
+
}
|
|
954
|
+
|
|
955
|
+
.plv-split-panel {
|
|
956
|
+
grid-template-columns: 1fr;
|
|
957
|
+
}
|
|
958
|
+
|
|
959
|
+
.plv-player-controls {
|
|
960
|
+
grid-template-columns: repeat(2, minmax(0, 1fr));
|
|
961
|
+
}
|
|
962
|
+
|
|
963
|
+
.plv-metadata-grid {
|
|
964
|
+
grid-template-columns: 1fr;
|
|
965
|
+
}
|
|
966
|
+
}
|
|
967
|
+
|
|
968
|
+
@media (max-width: 720px) {
|
|
969
|
+
.plv-header {
|
|
970
|
+
flex-wrap: wrap;
|
|
971
|
+
height: auto;
|
|
972
|
+
min-height: var(--plv-header-height);
|
|
973
|
+
padding-top: 10px;
|
|
974
|
+
padding-bottom: 10px;
|
|
975
|
+
}
|
|
976
|
+
|
|
977
|
+
.plv-header-actions {
|
|
978
|
+
width: 100%;
|
|
979
|
+
justify-content: space-between;
|
|
980
|
+
}
|
|
981
|
+
|
|
982
|
+
.plv-image-grid {
|
|
983
|
+
grid-template-columns: 1fr;
|
|
984
|
+
}
|
|
985
|
+
|
|
986
|
+
.plv-prompt-actions {
|
|
987
|
+
flex-wrap: wrap;
|
|
988
|
+
}
|
|
989
|
+
|
|
990
|
+
.plv-prompt-actions .is-generate {
|
|
991
|
+
margin-left: 0;
|
|
992
|
+
width: 100%;
|
|
993
|
+
}
|
|
994
|
+
}
|
|
995
|
+
|
|
996
|
+
@keyframes plv-shimmer {
|
|
997
|
+
from {
|
|
998
|
+
background-position: 120% 0;
|
|
999
|
+
}
|
|
1000
|
+
to {
|
|
1001
|
+
background-position: -120% 0;
|
|
1002
|
+
}
|
|
1003
|
+
}
|
|
1004
|
+
|
|
1005
|
+
@keyframes plv-wave {
|
|
1006
|
+
from {
|
|
1007
|
+
background-position: 0 0;
|
|
1008
|
+
}
|
|
1009
|
+
to {
|
|
1010
|
+
background-position: 64px 0;
|
|
1011
|
+
}
|
|
1012
|
+
}
|
|
1013
|
+
|
|
1014
|
+
@keyframes plv-slide-up {
|
|
1015
|
+
from {
|
|
1016
|
+
opacity: 0;
|
|
1017
|
+
transform: translateY(10px);
|
|
1018
|
+
}
|
|
1019
|
+
to {
|
|
1020
|
+
opacity: 1;
|
|
1021
|
+
transform: translateY(0);
|
|
1022
|
+
}
|
|
1023
|
+
}
|
|
1024
|
+
`;
|