440 lines
16 KiB
HTML
440 lines
16 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<link rel="icon" type="image/x-icon" href="favicon.ico">
|
|
<title>Editor — Dragonflight</title>
|
|
<link rel="stylesheet" href="css/common.css">
|
|
<style>
|
|
/* ── Editor layout ── */
|
|
.edit-shell { display: flex; flex: 1; overflow: hidden; min-height: 0; }
|
|
|
|
/* Left rail: asset library */
|
|
.edit-assets {
|
|
width: 280px;
|
|
flex-shrink: 0;
|
|
border-right: 1px solid var(--border);
|
|
display: flex; flex-direction: column;
|
|
background: oklch(11% 0.018 250 / 0.7);
|
|
min-height: 0;
|
|
}
|
|
.edit-assets-head {
|
|
padding: 12px 14px;
|
|
border-bottom: 1px solid var(--border);
|
|
display: flex; flex-direction: column; gap: 8px;
|
|
}
|
|
.edit-assets-title {
|
|
font-size: 11px; font-weight: 600;
|
|
letter-spacing: 0.16em; text-transform: uppercase;
|
|
color: var(--text-tertiary);
|
|
}
|
|
.edit-assets-search input {
|
|
width: 100%; padding: 7px 10px;
|
|
background: oklch(15% 0.020 250);
|
|
border: 1px solid var(--border);
|
|
border-radius: var(--r-sm);
|
|
color: var(--text-primary); font-size: 13px;
|
|
}
|
|
.edit-assets-list {
|
|
flex: 1; overflow: auto; padding: 6px;
|
|
}
|
|
.edit-asset {
|
|
display: flex; gap: 10px; align-items: center;
|
|
padding: 6px;
|
|
border-radius: var(--r-sm);
|
|
cursor: grab;
|
|
border: 1px solid transparent;
|
|
}
|
|
.edit-asset:hover { background: oklch(15% 0.020 250 / 0.7); border-color: var(--border); }
|
|
.edit-asset:active { cursor: grabbing; }
|
|
.edit-asset-thumb {
|
|
width: 56px; height: 32px;
|
|
background: #000; border-radius: 3px;
|
|
object-fit: cover; flex-shrink: 0;
|
|
}
|
|
.edit-asset-name {
|
|
font-size: 12px; line-height: 1.3;
|
|
color: var(--text-primary);
|
|
overflow: hidden; text-overflow: ellipsis;
|
|
display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
|
|
}
|
|
|
|
/* Middle: preview + timeline */
|
|
.edit-stage {
|
|
flex: 1; display: flex; flex-direction: column;
|
|
min-width: 0; min-height: 0;
|
|
background: var(--bg-base);
|
|
}
|
|
.edit-preview-wrap {
|
|
flex: 1; display: flex; flex-direction: column;
|
|
padding: 18px 24px 0;
|
|
min-height: 0;
|
|
}
|
|
.edit-preview {
|
|
flex: 1;
|
|
background: #000;
|
|
border-radius: 8px;
|
|
overflow: hidden;
|
|
position: relative;
|
|
display: flex; align-items: center; justify-content: center;
|
|
border: 1px solid oklch(28% 0.04 260 / 0.4);
|
|
min-height: 200px;
|
|
}
|
|
.edit-preview video {
|
|
width: 100%; height: 100%;
|
|
object-fit: contain;
|
|
background: #000;
|
|
}
|
|
.edit-preview-empty {
|
|
color: var(--text-tertiary); font-size: 13px;
|
|
display: flex; flex-direction: column; align-items: center; gap: 10px;
|
|
padding: 24px;
|
|
}
|
|
.edit-transport {
|
|
display: flex; align-items: center; gap: 10px;
|
|
padding: 12px 0 14px;
|
|
flex-wrap: wrap;
|
|
}
|
|
.edit-transport-btn {
|
|
width: 32px; height: 32px;
|
|
display: inline-flex; align-items: center; justify-content: center;
|
|
background: oklch(15% 0.020 250);
|
|
border: 1px solid var(--border);
|
|
border-radius: var(--r-sm);
|
|
color: var(--text-primary);
|
|
cursor: pointer;
|
|
}
|
|
.edit-transport-btn:hover { background: oklch(20% 0.030 260); border-color: oklch(45% 0.20 32 / 0.5); }
|
|
.edit-transport-btn:disabled { opacity: 0.4; cursor: not-allowed; }
|
|
.edit-scrubber {
|
|
flex: 1; min-width: 200px;
|
|
position: relative;
|
|
height: 32px;
|
|
display: flex; align-items: center;
|
|
}
|
|
.edit-scrubber input[type=range] {
|
|
width: 100%;
|
|
-webkit-appearance: none; appearance: none;
|
|
background: transparent;
|
|
height: 6px;
|
|
}
|
|
.edit-scrubber input[type=range]::-webkit-slider-runnable-track {
|
|
height: 6px;
|
|
background: linear-gradient(90deg,
|
|
oklch(25% 0.05 260) 0%,
|
|
oklch(25% 0.05 260) var(--in-pct, 0%),
|
|
oklch(55% 0.20 32) var(--in-pct, 0%),
|
|
oklch(55% 0.20 32) var(--out-pct, 100%),
|
|
oklch(25% 0.05 260) var(--out-pct, 100%),
|
|
oklch(25% 0.05 260) 100%);
|
|
border-radius: 3px;
|
|
}
|
|
.edit-scrubber input[type=range]::-webkit-slider-thumb {
|
|
-webkit-appearance: none; appearance: none;
|
|
width: 14px; height: 14px;
|
|
background: var(--text-primary);
|
|
border-radius: 50%;
|
|
border: 2px solid oklch(70% 0.18 32);
|
|
margin-top: -4px;
|
|
cursor: pointer;
|
|
}
|
|
.edit-time {
|
|
font-family: var(--font-mono); font-size: 12px;
|
|
color: var(--text-secondary);
|
|
min-width: 110px; text-align: right;
|
|
letter-spacing: 0.04em;
|
|
}
|
|
.edit-marker-btn {
|
|
padding: 6px 12px;
|
|
background: oklch(15% 0.020 250);
|
|
border: 1px solid var(--border);
|
|
border-radius: var(--r-sm);
|
|
color: var(--text-primary);
|
|
font-size: 12px; font-weight: 500;
|
|
cursor: pointer;
|
|
}
|
|
.edit-marker-btn:hover { border-color: oklch(45% 0.20 32 / 0.6); }
|
|
.edit-marker-btn.in { color: oklch(70% 0.18 32); }
|
|
.edit-marker-btn.out { color: oklch(70% 0.18 32); }
|
|
|
|
/* Timeline strip */
|
|
.edit-timeline {
|
|
flex-shrink: 0;
|
|
height: 140px;
|
|
padding: 12px 24px 18px;
|
|
border-top: 1px solid var(--border);
|
|
background: oklch(10% 0.015 250 / 0.6);
|
|
display: flex; flex-direction: column; gap: 8px;
|
|
overflow: hidden;
|
|
}
|
|
.edit-timeline-head {
|
|
display: flex; justify-content: space-between; align-items: baseline;
|
|
}
|
|
.edit-timeline-title {
|
|
font-size: 11px; font-weight: 600;
|
|
letter-spacing: 0.16em; text-transform: uppercase;
|
|
color: var(--text-tertiary);
|
|
}
|
|
.edit-timeline-total {
|
|
font-family: var(--font-mono); font-size: 11px;
|
|
color: var(--text-secondary); letter-spacing: 0.04em;
|
|
}
|
|
.edit-track {
|
|
flex: 1;
|
|
display: flex; gap: 4px;
|
|
overflow-x: auto;
|
|
align-items: stretch;
|
|
padding: 4px 0;
|
|
}
|
|
.edit-track-empty {
|
|
flex: 1;
|
|
display: flex; align-items: center; justify-content: center;
|
|
color: var(--text-tertiary); font-size: 12px;
|
|
border: 1px dashed var(--border);
|
|
border-radius: var(--r-sm);
|
|
transition: background 120ms ease, border-color 120ms ease;
|
|
}
|
|
.edit-track-empty.drag-over {
|
|
background: oklch(20% 0.05 32 / 0.4);
|
|
border-color: oklch(55% 0.20 32 / 0.8);
|
|
color: var(--accent-strong);
|
|
}
|
|
.edit-clip {
|
|
position: relative;
|
|
flex-shrink: 0;
|
|
display: flex; flex-direction: column;
|
|
width: 140px;
|
|
background: oklch(15% 0.025 250);
|
|
border: 1px solid oklch(28% 0.04 260 / 0.5);
|
|
border-radius: var(--r-sm);
|
|
overflow: hidden;
|
|
cursor: pointer;
|
|
transition: border-color 100ms ease;
|
|
}
|
|
.edit-clip:hover { border-color: oklch(45% 0.20 32 / 0.5); }
|
|
.edit-clip.active {
|
|
border-color: oklch(70% 0.18 32);
|
|
box-shadow: 0 0 0 1px oklch(70% 0.18 32 / 0.4);
|
|
}
|
|
.edit-clip-thumb {
|
|
width: 100%; height: 64px;
|
|
background: #000;
|
|
object-fit: cover;
|
|
}
|
|
.edit-clip-bar {
|
|
position: relative;
|
|
height: 6px;
|
|
background: oklch(20% 0.04 260);
|
|
margin: 4px 6px 0;
|
|
border-radius: 2px;
|
|
overflow: hidden;
|
|
}
|
|
.edit-clip-bar-fill {
|
|
position: absolute;
|
|
top: 0; bottom: 0;
|
|
background: oklch(55% 0.20 32);
|
|
}
|
|
.edit-clip-meta {
|
|
padding: 4px 8px 6px;
|
|
font-size: 10px; font-family: var(--font-mono);
|
|
color: var(--text-tertiary);
|
|
display: flex; justify-content: space-between;
|
|
letter-spacing: 0.02em;
|
|
}
|
|
.edit-clip-name {
|
|
padding: 2px 8px;
|
|
font-size: 11px;
|
|
color: var(--text-primary);
|
|
overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
|
|
}
|
|
.edit-clip-remove {
|
|
position: absolute; top: 4px; right: 4px;
|
|
width: 18px; height: 18px;
|
|
background: rgba(0,0,0,0.6); color: #fff;
|
|
border: 0; border-radius: 50%;
|
|
font-size: 11px; line-height: 1;
|
|
cursor: pointer; display: none;
|
|
align-items: center; justify-content: center;
|
|
}
|
|
.edit-clip:hover .edit-clip-remove { display: flex; }
|
|
|
|
/* Right: clip inspector */
|
|
.edit-inspector {
|
|
width: 280px;
|
|
flex-shrink: 0;
|
|
border-left: 1px solid var(--border);
|
|
background: oklch(11% 0.018 250 / 0.7);
|
|
padding: 14px;
|
|
display: flex; flex-direction: column; gap: 14px;
|
|
overflow: auto;
|
|
}
|
|
.edit-inspector-empty {
|
|
color: var(--text-tertiary); font-size: 13px;
|
|
text-align: center; padding: 32px 12px;
|
|
}
|
|
.edit-inspector-section {
|
|
display: flex; flex-direction: column; gap: 8px;
|
|
}
|
|
.edit-inspector-label {
|
|
font-size: 10px; font-weight: 600;
|
|
letter-spacing: 0.16em; text-transform: uppercase;
|
|
color: var(--text-tertiary);
|
|
}
|
|
.edit-inspector-clipname {
|
|
font-size: 14px; font-weight: 500;
|
|
color: var(--text-primary);
|
|
word-break: break-all;
|
|
}
|
|
.edit-inspector-stats {
|
|
display: grid; grid-template-columns: auto 1fr;
|
|
gap: 4px 12px;
|
|
font-family: var(--font-mono); font-size: 12px;
|
|
}
|
|
.edit-inspector-stats dt {
|
|
color: var(--text-tertiary); letter-spacing: 0.04em;
|
|
text-transform: uppercase; font-size: 10px;
|
|
align-self: center;
|
|
}
|
|
.edit-inspector-stats dd { color: var(--text-primary); margin: 0; }
|
|
.edit-inspector-actions {
|
|
display: flex; gap: 6px; flex-wrap: wrap;
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
|
|
<div class="shell">
|
|
<nav class="sidebar" aria-label="Main navigation">
|
|
<div class="sidebar-brand">
|
|
<img src="img/dragon-logo.png?v=1" alt="Dragonflight" class="sidebar-logo">
|
|
<span class="sidebar-brand-name">Dragonflight</span>
|
|
</div>
|
|
<nav class="sidebar-nav">
|
|
<a href="home.html" class="nav-item">
|
|
<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5"><path d="M2 7l6-5 6 5v7a1 1 0 0 1-1 1h-3v-5H6v5H3a1 1 0 0 1-1-1z"/></svg>
|
|
Home
|
|
</a>
|
|
<a href="index.html" class="nav-item">
|
|
<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5"><rect x="1" y="1" width="6" height="6" rx="1"/><rect x="9" y="1" width="6" height="6" rx="1"/><rect x="1" y="9" width="6" height="6" rx="1"/><rect x="9" y="9" width="6" height="6" rx="1"/></svg>
|
|
Library
|
|
</a>
|
|
<a href="projects.html" class="nav-item">
|
|
<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5"><path d="M1 4a1 1 0 0 1 1-1h4l2 2h5a1 1 0 0 1 1 1v6a1 1 0 0 1-1 1H2a1 1 0 0 1-1-1z"/></svg>
|
|
Projects
|
|
</a>
|
|
<a href="upload.html" class="nav-item">
|
|
<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5"><path d="M8 11V3M5 6l3-3 3 3"/><path d="M2 13h12"/></svg>
|
|
Ingest
|
|
</a>
|
|
<a href="recorders.html" class="nav-item">
|
|
<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5"><rect x="1" y="4" width="10" height="8" rx="1"/><path d="M11 7l4-2v6l-4-2"/></svg>
|
|
Recorders
|
|
</a>
|
|
<a href="capture.html" class="nav-item">
|
|
<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5"><circle cx="8" cy="8" r="3"/><circle cx="8" cy="8" r="6.5"/></svg>
|
|
Capture
|
|
</a>
|
|
<a href="jobs.html" class="nav-item">
|
|
<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5"><path d="M2 4h12M2 8h8M2 12h5"/></svg>
|
|
Jobs
|
|
</a>
|
|
<a href="#" id="editor-nav-link" class="nav-item active" target="_blank" rel="noopener">
|
|
<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5"><path d="M2 13l1.5-3.5L11 2l3 3-7.5 7.5L3 14zM10 3l3 3"/></svg>
|
|
Editor
|
|
</a>
|
|
<div class="sidebar-section-label">Admin</div>
|
|
<a href="users.html" class="nav-item">
|
|
<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5"><circle cx="6" cy="5" r="2.5"/><path d="M1 13c0-2.8 2.2-5 5-5s5 2.2 5 5"/><circle cx="12" cy="5" r="2"/><path d="M15 12c0-1.9-1.3-3.5-3-4"/></svg>
|
|
Users
|
|
</a>
|
|
<a href="tokens.html" class="nav-item">
|
|
<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5"><circle cx="6" cy="10" r="3.5"/><path d="M8.7 7.3L13 3M11.5 3.5l1.5 1.5M13.5 2.5l1 1"/></svg>
|
|
Tokens
|
|
</a>
|
|
</nav>
|
|
<div class="sidebar-footer">
|
|
<div class="sidebar-user">
|
|
<div class="sidebar-user-avatar" id="userAvatar">?</div>
|
|
<div class="sidebar-user-info">
|
|
<div class="sidebar-user-name" id="userName">—</div>
|
|
<div class="sidebar-user-role" id="userRole"></div>
|
|
</div>
|
|
<button class="btn btn-ghost" id="logoutBtn" title="Sign out" style="padding:0;width:24px;height:24px;flex-shrink:0;">
|
|
<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" width="14" height="14"><path d="M10 8H3M6 5l-3 3 3 3"/><path d="M7 3h5a1 1 0 0 1 1 1v8a1 1 0 0 1-1 1H7"/></svg>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</nav>
|
|
|
|
<div class="main">
|
|
<header class="topbar">
|
|
<div class="topbar-left">
|
|
<span class="page-title">Editor</span>
|
|
<span class="topbar-sep">/</span>
|
|
<span class="text-sm" style="color:var(--text-tertiary)">Phase A · single-track</span>
|
|
</div>
|
|
<div class="topbar-right">
|
|
<button class="btn btn-ghost btn-sm" onclick="saveEDL()">Save draft</button>
|
|
<button class="btn btn-primary btn-sm" onclick="exportEDL()">Export</button>
|
|
</div>
|
|
</header>
|
|
|
|
<div class="edit-shell">
|
|
<!-- Left: asset library -->
|
|
<aside class="edit-assets">
|
|
<div class="edit-assets-head">
|
|
<span class="edit-assets-title">Library</span>
|
|
<div class="edit-assets-search"><input type="text" id="assetSearch" placeholder="Search assets…" /></div>
|
|
</div>
|
|
<div class="edit-assets-list" id="assetList">
|
|
<div class="edit-inspector-empty">Loading…</div>
|
|
</div>
|
|
</aside>
|
|
|
|
<!-- Middle: preview + timeline -->
|
|
<section class="edit-stage">
|
|
<div class="edit-preview-wrap">
|
|
<div class="edit-preview" id="previewWrap">
|
|
<div class="edit-preview-empty" id="previewEmpty">
|
|
<svg viewBox="0 0 32 32" fill="none" stroke="currentColor" stroke-width="1" width="36" height="36" style="opacity:0.4"><polygon points="11,8 24,16 11,24"/></svg>
|
|
<div>Drag a clip onto the timeline below, then click it to preview.</div>
|
|
</div>
|
|
<video id="previewVideo" style="display:none" playsinline></video>
|
|
</div>
|
|
<div class="edit-transport">
|
|
<button class="edit-transport-btn" id="btnPlay" title="Play / pause (space)" disabled>
|
|
<svg viewBox="0 0 16 16" fill="currentColor" width="12" height="12"><polygon points="4,3 13,8 4,13"/></svg>
|
|
</button>
|
|
<div class="edit-scrubber"><input type="range" id="scrubber" min="0" max="100" value="0" step="0.01" disabled></div>
|
|
<span class="edit-time" id="timeDisplay">--:--.-- / --:--.--</span>
|
|
<button class="edit-marker-btn in" id="btnSetIn" title="Set In (I)" disabled>I IN</button>
|
|
<button class="edit-marker-btn out" id="btnSetOut" title="Set Out (O)" disabled>O OUT</button>
|
|
<button class="edit-marker-btn" id="btnSplit" title="Split at playhead (B)" disabled style="color:oklch(70% 0.18 80)">B SPLIT</button>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="edit-timeline">
|
|
<div class="edit-timeline-head">
|
|
<span class="edit-timeline-title">Timeline · Track 1</span>
|
|
<span class="edit-timeline-total" id="timelineTotal">0 clips · 00:00.00</span>
|
|
</div>
|
|
<div class="edit-track" id="track">
|
|
<div class="edit-track-empty" id="trackEmpty">Drag clips here from the Library</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<!-- Right: inspector -->
|
|
<aside class="edit-inspector" id="inspector">
|
|
<div class="edit-inspector-empty">Select a clip on the timeline to inspect.</div>
|
|
</aside>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<script src="js/api.js?v=6"></script>
|
|
<script src="js/topbar-strip.js?v=1"></script>
|
|
<script src="js/edit.js?v=2"></script>
|
|
</body>
|
|
</html>
|