ui: Upload-Form & Jobs-Liste aufgeräumt
Upload-Form: - Title-Label nicht mehr mit "(optional)" suffix — Hinweis wandert in den Placeholder. Labels haben jetzt einheitliches Spalten-Layout (flex-column + align-items: end), Inputs sind bündig - "Standard: X" Hinweis unter dem Profil entfernt (Dropdown ist selbst-erklärend, das Header-Dropdown zeigt's eh schon) Jobs-Liste: - Wenn kein Titel gesetzt ist, wird der Dateiname nur 1× als Titel gezeigt (vorher: groß als Titel + nochmal klein darunter) - Profile/Modell-Tags in eigene flex-Zeile statt margin-left-Hack - Dateiname-Zeile mit Ellipsis bei zu langen Namen - Tags 1px kleiner, weniger Padding - Datumsformat: heute → nur HH:MM, sonst dd.mm HH:MM (statt langem dd.mm.yyyy HH:MM:SS) — col-updated von 120px auf 78px geschrumpft - col-status von 110px auf 170px → Aktions-Buttons stapeln weniger Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
79d6cfec74
commit
f03d46afb5
@ -33,7 +33,6 @@ const usersBody = document.getElementById("users-body");
|
||||
|
||||
const profileLabel = document.getElementById("profile-label");
|
||||
const profileSelect = document.getElementById("profile-select");
|
||||
const defaultProfileName = document.getElementById("default-profile-name");
|
||||
const headerProfileWrap = document.getElementById("header-profile-wrap");
|
||||
const headerProfile = document.getElementById("header-profile");
|
||||
const headerModelWrap = document.getElementById("header-model-wrap");
|
||||
@ -77,7 +76,12 @@ function escapeHtml(s) {
|
||||
|
||||
function fmtDate(s) {
|
||||
const d = new Date(s);
|
||||
return d.toLocaleString("de-DE", { dateStyle: "short", timeStyle: "medium" });
|
||||
const now = new Date();
|
||||
const sameDay = d.toDateString() === now.toDateString();
|
||||
if (sameDay) {
|
||||
return d.toLocaleTimeString("de-DE", { hour: "2-digit", minute: "2-digit" });
|
||||
}
|
||||
return d.toLocaleString("de-DE", { day: "2-digit", month: "2-digit", hour: "2-digit", minute: "2-digit" });
|
||||
}
|
||||
|
||||
function fmtSecs(sec) {
|
||||
@ -228,7 +232,6 @@ function applyProfileUI() {
|
||||
const def = currentUser.default_profile || "meeting";
|
||||
profileSelect.value = def;
|
||||
headerProfile.value = def;
|
||||
defaultProfileName.textContent = profileLabelOf(def);
|
||||
}
|
||||
|
||||
async function loadModels() {
|
||||
@ -306,7 +309,6 @@ headerProfile.addEventListener("change", async () => {
|
||||
currentUser = await r.json();
|
||||
// Upload-Dropdown synchron mitziehen
|
||||
profileSelect.value = currentUser.default_profile;
|
||||
defaultProfileName.textContent = profileLabelOf(currentUser.default_profile);
|
||||
} catch (e) {
|
||||
alert("Konnte Standard-Profil nicht speichern.");
|
||||
headerProfile.value = currentUser.default_profile || "meeting";
|
||||
@ -376,6 +378,9 @@ async function checkMac() {
|
||||
// ─── Jobs ──────────────────────────────────────────────────────────────────
|
||||
function row(job) {
|
||||
const tr = document.createElement("tr");
|
||||
// Wenn kein Titel gesetzt ist, zeigen wir den Dateinamen nur EINMAL als Titel —
|
||||
// sonst doppelt (großer Titel + kleine muted-Zeile) und unnötig hässlich.
|
||||
const hasRealTitle = !!job.title;
|
||||
const title = job.title || job.original_name;
|
||||
|
||||
const dlCell = document.createElement("td");
|
||||
@ -395,7 +400,7 @@ function row(job) {
|
||||
});
|
||||
|
||||
const ownerLine = currentUser?.is_admin && job.owner_username
|
||||
? `<br><small class="muted">von ${escapeHtml(job.owner_username)}</small>`
|
||||
? `<div class="job-owner muted">von ${escapeHtml(job.owner_username)}</div>`
|
||||
: "";
|
||||
|
||||
// Profile-Tag nur sichtbar wenn ≥2 Profile in der Auswahl ODER es ein anderes als "meeting" ist.
|
||||
@ -423,9 +428,19 @@ function row(job) {
|
||||
${runsButtonHtml(job)}
|
||||
`;
|
||||
|
||||
// Dateiname nur dann als zweite Zeile, wenn er sich vom angezeigten Titel unterscheidet.
|
||||
const fileLine = hasRealTitle
|
||||
? `<div class="job-filename muted">${escapeHtml(job.original_name)}</div>`
|
||||
: "";
|
||||
|
||||
tr.innerHTML = `
|
||||
<td class="col-id">#${job.id}</td>
|
||||
<td class="col-title">${escapeHtml(title)} ${profileTag} ${modelTag}<br><small class="muted">${escapeHtml(job.original_name)}</small>${ownerLine}</td>
|
||||
<td class="col-title">
|
||||
<div class="job-title">${escapeHtml(title)}</div>
|
||||
<div class="job-tags">${profileTag}${modelTag}</div>
|
||||
${fileLine}
|
||||
${ownerLine}
|
||||
</td>
|
||||
<td class="col-status">${statusCell}</td>
|
||||
<td class="col-progress"><div class="bar"><div class="bar-fill" style="width:${job.progress}%"></div></div><small class="muted">${job.progress}%</small></td>
|
||||
<td class="col-updated"><small class="muted">${fmtDate(job.updated_at)}</small></td>
|
||||
|
||||
@ -95,11 +95,10 @@
|
||||
<label id="profile-label" class="hidden">
|
||||
Verarbeitungs-Profil
|
||||
<select id="profile-select"></select>
|
||||
<small class="muted desktop-only">Standard: <span id="default-profile-name">—</span></small>
|
||||
</label>
|
||||
<label>
|
||||
Titel <span class="muted">(optional)</span>
|
||||
<input type="text" name="title" id="title" placeholder="z. B. Monatsbesprechung" />
|
||||
Titel
|
||||
<input type="text" name="title" id="title" placeholder="optional, z. B. Monatsbesprechung" />
|
||||
</label>
|
||||
</div>
|
||||
|
||||
|
||||
@ -96,15 +96,38 @@ table { width: 100%; border-collapse: collapse; font-size: 14px; table-layout: f
|
||||
th, td { padding: 10px 8px; text-align: left; border-bottom: 1px solid var(--border); vertical-align: top; }
|
||||
th { color: var(--muted); font-weight: 600; font-size: 12px; text-transform: uppercase; letter-spacing: .5px; }
|
||||
|
||||
/* Spaltenbreiten — Status bleibt schmal, Downloads bekommen Platz */
|
||||
.col-id { width: 56px; }
|
||||
.col-status { width: 110px; }
|
||||
.col-progress { width: 120px; }
|
||||
.col-updated { width: 120px; }
|
||||
/* Spaltenbreiten — Status bekommt Platz für die Aktions-Buttons,
|
||||
Updated wird schmaler weil das neue Format kürzer ist (Uhrzeit/dd.mm hh:mm) */
|
||||
.col-id { width: 52px; }
|
||||
.col-status { width: 170px; }
|
||||
.col-progress { width: 110px; }
|
||||
.col-updated { width: 78px; }
|
||||
.col-dl { width: 320px; }
|
||||
/* col-title nimmt den Rest */
|
||||
|
||||
.col-title { word-break: break-word; }
|
||||
.col-title .job-title {
|
||||
font-weight: 500;
|
||||
line-height: 1.35;
|
||||
font-size: 14px;
|
||||
}
|
||||
.col-title .job-tags {
|
||||
margin-top: 3px;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 4px;
|
||||
}
|
||||
.col-title .job-tags:empty { display: none; }
|
||||
.col-title .job-filename {
|
||||
margin-top: 4px;
|
||||
font-size: 11.5px;
|
||||
font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
max-width: 100%;
|
||||
}
|
||||
.col-title .job-owner { margin-top: 2px; font-size: 11.5px; }
|
||||
|
||||
.status-pill {
|
||||
display: inline-block;
|
||||
@ -368,6 +391,12 @@ select {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 12px;
|
||||
align-items: end; /* Labels unten bündig → Inputs auf gleicher Höhe */
|
||||
}
|
||||
.upload-meta > label {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 4px; /* einheitlicher Abstand zwischen Label-Text und Control */
|
||||
}
|
||||
.audio-file-details summary {
|
||||
cursor: pointer;
|
||||
@ -547,34 +576,39 @@ select {
|
||||
.btn-retry:hover { background: rgba(241,196,15,.22); text-decoration: none; }
|
||||
.btn-retry:disabled { opacity: .55; cursor: not-allowed; }
|
||||
|
||||
/* Profile-Tag in der Job-Zeile */
|
||||
/* Profile-Tag in der Job-Zeile — kleiner & ohne Außenabstand,
|
||||
weil sie jetzt in einem eigenen .job-tags-Container mit gap leben */
|
||||
.tag-profile {
|
||||
display: inline-block;
|
||||
padding: 1px 8px;
|
||||
margin-left: 6px;
|
||||
padding: 1px 7px;
|
||||
border-radius: 4px;
|
||||
background: rgba(46,204,113,.12);
|
||||
border: 1px solid rgba(46,204,113,.4);
|
||||
color: var(--ok);
|
||||
font-size: 11px;
|
||||
font-size: 10.5px;
|
||||
text-transform: lowercase;
|
||||
vertical-align: middle;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
/* Modell-Tag — gleicher Stil wie Profile-Tag, andere Farbe (lila) */
|
||||
.tag-model {
|
||||
display: inline-block;
|
||||
padding: 1px 8px;
|
||||
margin-left: 4px;
|
||||
padding: 1px 7px;
|
||||
border-radius: 4px;
|
||||
background: rgba(155,89,182,.10);
|
||||
border: 1px solid rgba(155,89,182,.4);
|
||||
color: #b07cd6;
|
||||
font-size: 11px;
|
||||
font-size: 10.5px;
|
||||
font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
|
||||
vertical-align: middle;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
/* In der mobilen Karte (jc-title) sitzen Tags inline neben dem Titeltext —
|
||||
dort brauchen sie etwas Luft nach links. In der Desktop-Tabelle stehen sie
|
||||
im eigenen .job-tags-Container mit gap, dort kein margin nötig. */
|
||||
.jc-title .tag-profile,
|
||||
.jc-title .tag-model { margin-left: 6px; }
|
||||
|
||||
/* Modal für Modell-Auswahl beim Reprocess */
|
||||
dialog.model-picker {
|
||||
border: 1px solid rgba(255,255,255,.15);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user