mirror of
https://github.com/PR0M3TH3AN/bitvid.git
synced 2026-10-27 16:02:26 +00:00
Merge pull request #359 from PR0M3TH3AN/codex/update-video-card-highlight-styles
Highlight owner-only private videos
This commit is contained in:
6 files changed
+383
-36
No files matched your search
@@ -199,6 +199,59 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="space-y-1">
|
||||
<span id="editVideoVisibilityLabel" class="block text-sm font-medium text-gray-200">
|
||||
Visibility
|
||||
</span>
|
||||
<div
|
||||
class="space-y-3 rounded-md border border-gray-800 bg-black/30 p-3"
|
||||
role="group"
|
||||
aria-labelledby="editVideoVisibilityLabel"
|
||||
data-visibility-toggle
|
||||
>
|
||||
<div class="flex flex-wrap items-center gap-2 sm:justify-between">
|
||||
<div
|
||||
class="video-visibility-toggle"
|
||||
data-visibility-options
|
||||
>
|
||||
<button
|
||||
type="button"
|
||||
class="video-visibility-toggle__option"
|
||||
data-visibility-option="public"
|
||||
aria-pressed="false"
|
||||
>
|
||||
Public
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="video-visibility-toggle__option"
|
||||
data-visibility-option="private"
|
||||
aria-pressed="false"
|
||||
>
|
||||
Private
|
||||
</button>
|
||||
</div>
|
||||
<input
|
||||
type="checkbox"
|
||||
id="editVideoIsPrivate"
|
||||
class="hidden"
|
||||
data-default-checked="false"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
</div>
|
||||
<p class="text-xs text-gray-400" data-visibility-helper>
|
||||
Private notes stay visible only to you. Switch back to public when you're ready to share.
|
||||
</p>
|
||||
<button
|
||||
type="button"
|
||||
class="edit-field-button hidden"
|
||||
data-edit-target="editVideoIsPrivate"
|
||||
>
|
||||
Edit field
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="space-y-1">
|
||||
<label for="editEnableComments" class="block text-sm font-medium text-gray-200">
|
||||
Enable comments
|
||||
@@ -211,6 +264,8 @@
|
||||
type="checkbox"
|
||||
id="editEnableComments"
|
||||
class="h-5 w-5 rounded border-gray-600 bg-gray-800 text-blue-500 focus:ring-blue-500"
|
||||
data-default-checked="true"
|
||||
checked
|
||||
/>
|
||||
<span class="text-sm text-gray-300">
|
||||
Allow replies once comment threads are available.
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
--color-surface: #0f172a;
|
||||
--color-bg: var(--color-surface);
|
||||
--color-card: #1e293b;
|
||||
--color-card-private: #3b1d74;
|
||||
--color-primary: #fe0032;
|
||||
--color-secondary: #ff93a5;
|
||||
--color-card-critical: #3f0b13;
|
||||
@@ -167,6 +168,66 @@ header img {
|
||||
box-shadow: var(--shadow-md);
|
||||
}
|
||||
|
||||
.video-card.video-card--owner-private {
|
||||
background-color: var(--color-card-private) !important;
|
||||
box-shadow: 0 0 0 0.125rem rgba(168, 85, 247, 0.55), var(--shadow-md);
|
||||
}
|
||||
|
||||
.video-card.video-card--owner-private:hover {
|
||||
box-shadow: 0 0 0 0.125rem rgba(192, 132, 252, 0.65), var(--shadow-lg);
|
||||
}
|
||||
|
||||
.video-visibility-toggle {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.35rem;
|
||||
border-radius: 9999px;
|
||||
border: 1px solid rgba(30, 41, 59, 0.7);
|
||||
background-color: rgba(15, 23, 42, 0.55);
|
||||
padding: 0.35rem;
|
||||
}
|
||||
|
||||
.video-visibility-toggle__option {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 9999px;
|
||||
border: 1px solid transparent;
|
||||
background-color: rgba(15, 23, 42, 0.6);
|
||||
color: rgba(203, 213, 225, 0.78);
|
||||
font-size: 0.75rem;
|
||||
font-weight: 600;
|
||||
letter-spacing: 0.08em;
|
||||
min-width: 5.5rem;
|
||||
padding: 0.4rem 0.95rem;
|
||||
text-transform: uppercase;
|
||||
cursor: pointer;
|
||||
transition: background-color 0.18s ease, color 0.18s ease,
|
||||
border-color 0.18s ease, box-shadow 0.18s ease, opacity 0.18s ease;
|
||||
}
|
||||
|
||||
.video-visibility-toggle__option:not(.is-disabled):hover {
|
||||
background-color: rgba(148, 163, 184, 0.16);
|
||||
color: rgba(226, 232, 240, 0.88);
|
||||
}
|
||||
|
||||
.video-visibility-toggle__option[data-active="true"] {
|
||||
background: linear-gradient(135deg, rgba(129, 140, 248, 0.4), rgba(192, 132, 252, 0.32));
|
||||
color: #f8fafc;
|
||||
border-color: rgba(129, 140, 248, 0.6);
|
||||
box-shadow: 0 0 0 1px rgba(129, 140, 248, 0.4) inset,
|
||||
0 6px 14px -6px rgba(129, 140, 248, 0.55);
|
||||
}
|
||||
|
||||
.video-visibility-toggle__option.is-disabled {
|
||||
opacity: 0.45;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.video-visibility-toggle__option.is-disabled[data-active="true"] {
|
||||
opacity: 0.65;
|
||||
}
|
||||
|
||||
.video-card[data-owner-is-viewer="false"][data-url-health-state="offline"][data-stream-health-state="unhealthy"] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
@@ -1819,6 +1819,9 @@ function renderChannelVideosFromList({
|
||||
? app.formatTimeAgo(video.created_at)
|
||||
: new Date(video.created_at * 1000).toLocaleString();
|
||||
|
||||
const highlightClass =
|
||||
canEdit && video.isPrivate ? "video-card--owner-private" : "";
|
||||
|
||||
const videoCard = new VideoCard({
|
||||
document,
|
||||
video,
|
||||
@@ -1826,6 +1829,7 @@ function renderChannelVideosFromList({
|
||||
shareUrl,
|
||||
pointerInfo,
|
||||
timeAgo,
|
||||
highlightClass,
|
||||
capabilities: {
|
||||
canEdit,
|
||||
canDelete: canEdit,
|
||||
|
||||
+259
-32
@@ -48,9 +48,15 @@ export class EditModal {
|
||||
this.submitButton = null;
|
||||
this.fieldButtons = [];
|
||||
this.fields = {};
|
||||
this.visibility = {
|
||||
container: null,
|
||||
buttons: [],
|
||||
};
|
||||
|
||||
this.activeVideo = null;
|
||||
this.isVisible = false;
|
||||
this.eventsBound = false;
|
||||
this.loadPromise = null;
|
||||
}
|
||||
|
||||
addEventListener(type, listener, options) {
|
||||
@@ -74,39 +80,54 @@ export class EditModal {
|
||||
return this.root;
|
||||
}
|
||||
|
||||
const targetContainer =
|
||||
container || this.container || document.getElementById("modalContainer");
|
||||
if (!targetContainer) {
|
||||
throw new Error("Modal container element not found!");
|
||||
if (this.loadPromise) {
|
||||
return this.loadPromise;
|
||||
}
|
||||
|
||||
let modal = targetContainer.querySelector("#editVideoModal");
|
||||
if (!modal) {
|
||||
const response = await fetch("components/edit-video-modal.html");
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP error! status: ${response.status}`);
|
||||
this.loadPromise = (async () => {
|
||||
const targetContainer =
|
||||
container || this.container || document.getElementById("modalContainer");
|
||||
if (!targetContainer) {
|
||||
throw new Error("Modal container element not found!");
|
||||
}
|
||||
|
||||
const html = await response.text();
|
||||
const wrapper = document.createElement("div");
|
||||
wrapper.innerHTML = html;
|
||||
this.removeTrackingScripts(wrapper);
|
||||
targetContainer.appendChild(wrapper);
|
||||
modal = wrapper.querySelector("#editVideoModal");
|
||||
let modal = targetContainer.querySelector("#editVideoModal");
|
||||
if (!modal) {
|
||||
const response = await fetch("components/edit-video-modal.html");
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP error! status: ${response.status}`);
|
||||
}
|
||||
|
||||
const html = await response.text();
|
||||
const wrapper = document.createElement("div");
|
||||
wrapper.innerHTML = html;
|
||||
this.removeTrackingScripts(wrapper);
|
||||
targetContainer.appendChild(wrapper);
|
||||
modal = wrapper.querySelector("#editVideoModal");
|
||||
}
|
||||
|
||||
if (!modal) {
|
||||
throw new Error("Edit video modal markup missing after load.");
|
||||
}
|
||||
|
||||
this.container = targetContainer;
|
||||
this.root = modal;
|
||||
|
||||
this.cacheElements(modal);
|
||||
if (!this.eventsBound) {
|
||||
this.bindEvents();
|
||||
this.eventsBound = true;
|
||||
}
|
||||
this.reset();
|
||||
|
||||
return this.root;
|
||||
})();
|
||||
|
||||
try {
|
||||
return await this.loadPromise;
|
||||
} finally {
|
||||
this.loadPromise = null;
|
||||
}
|
||||
|
||||
if (!modal) {
|
||||
throw new Error("Edit video modal markup missing after load.");
|
||||
}
|
||||
|
||||
this.container = targetContainer;
|
||||
this.root = modal;
|
||||
|
||||
this.cacheElements(modal);
|
||||
this.bindEvents();
|
||||
this.reset();
|
||||
|
||||
return this.root;
|
||||
}
|
||||
|
||||
cacheElements(context) {
|
||||
@@ -126,8 +147,22 @@ export class EditModal {
|
||||
xs: context.querySelector("#editVideoXs") || null,
|
||||
thumbnail: context.querySelector("#editVideoThumbnail") || null,
|
||||
description: context.querySelector("#editVideoDescription") || null,
|
||||
isPrivate: context.querySelector("#editVideoIsPrivate") || null,
|
||||
enableComments: context.querySelector("#editEnableComments") || null,
|
||||
};
|
||||
|
||||
this.visibility = {
|
||||
container: context.querySelector("[data-visibility-toggle]") || null,
|
||||
buttons: Array.from(
|
||||
context.querySelectorAll("[data-visibility-option]") || []
|
||||
),
|
||||
helper: context.querySelector("[data-visibility-helper]") || null,
|
||||
helperDefault: "",
|
||||
};
|
||||
|
||||
if (this.visibility.helper) {
|
||||
this.visibility.helperDefault = this.visibility.helper.textContent || "";
|
||||
}
|
||||
}
|
||||
|
||||
bindEvents() {
|
||||
@@ -157,9 +192,31 @@ export class EditModal {
|
||||
|
||||
if (Array.isArray(this.fieldButtons)) {
|
||||
this.fieldButtons.forEach((button) => {
|
||||
if (!button || button.dataset.editListenerAttached === "true") {
|
||||
return;
|
||||
}
|
||||
button.addEventListener("click", (event) => {
|
||||
this.handleEditFieldToggle(event);
|
||||
});
|
||||
button.dataset.editListenerAttached = "true";
|
||||
});
|
||||
}
|
||||
|
||||
if (Array.isArray(this.visibility?.buttons)) {
|
||||
this.visibility.buttons.forEach((button) => {
|
||||
button.addEventListener("click", (event) => {
|
||||
const option = event?.currentTarget?.dataset?.visibilityOption;
|
||||
if (!option) {
|
||||
return;
|
||||
}
|
||||
this.setVisibility(option);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
if (this.fields.isPrivate) {
|
||||
this.fields.isPrivate.addEventListener("change", () => {
|
||||
this.handleIsPrivateChange({ emit: true });
|
||||
});
|
||||
}
|
||||
|
||||
@@ -189,12 +246,23 @@ export class EditModal {
|
||||
return;
|
||||
}
|
||||
if (input.type === "checkbox") {
|
||||
input.checked = true;
|
||||
const defaultAttr = input.dataset?.defaultChecked;
|
||||
const defaultChecked =
|
||||
defaultAttr === "true"
|
||||
? true
|
||||
: defaultAttr === "false"
|
||||
? false
|
||||
: input.defaultChecked;
|
||||
input.checked = defaultChecked;
|
||||
input.disabled = false;
|
||||
input.removeAttribute("disabled");
|
||||
delete input.dataset.isEditing;
|
||||
} else {
|
||||
input.value = "";
|
||||
input.readOnly = false;
|
||||
input.removeAttribute("readonly");
|
||||
input.classList.remove("locked-input");
|
||||
delete input.dataset.isEditing;
|
||||
}
|
||||
delete input.dataset.originalValue;
|
||||
});
|
||||
@@ -207,6 +275,8 @@ export class EditModal {
|
||||
});
|
||||
}
|
||||
|
||||
this.handleIsPrivateChange({ emit: false });
|
||||
|
||||
this.activeVideo = null;
|
||||
}
|
||||
|
||||
@@ -225,12 +295,14 @@ export class EditModal {
|
||||
const effectiveXs = video.xs || magnetHints.xs || "";
|
||||
const enableCommentsValue =
|
||||
typeof video.enableComments === "boolean" ? video.enableComments : true;
|
||||
const isPrivateValue = video.isPrivate === true;
|
||||
|
||||
const editContext = {
|
||||
...video,
|
||||
ws: effectiveWs,
|
||||
xs: effectiveXs,
|
||||
enableComments: enableCommentsValue,
|
||||
isPrivate: isPrivateValue,
|
||||
};
|
||||
|
||||
this.applyVideoToForm(editContext);
|
||||
@@ -258,6 +330,7 @@ export class EditModal {
|
||||
xs: editContext.xs || "",
|
||||
thumbnail: editContext.thumbnail || "",
|
||||
description: editContext.description || "",
|
||||
isPrivate: editContext.isPrivate,
|
||||
enableComments: editContext.enableComments,
|
||||
};
|
||||
|
||||
@@ -287,7 +360,13 @@ export class EditModal {
|
||||
const boolValue = rawValue === true;
|
||||
input.checked = boolValue;
|
||||
input.disabled = hasValue;
|
||||
if (hasValue) {
|
||||
input.setAttribute("disabled", "disabled");
|
||||
} else {
|
||||
input.removeAttribute("disabled");
|
||||
}
|
||||
input.dataset.originalValue = boolValue ? "true" : "false";
|
||||
input.dataset.isEditing = hasValue ? "false" : "true";
|
||||
if (button) {
|
||||
if (hasValue) {
|
||||
button.classList.remove("hidden");
|
||||
@@ -307,11 +386,14 @@ export class EditModal {
|
||||
|
||||
input.value = value;
|
||||
input.dataset.originalValue = value;
|
||||
input.dataset.isEditing = hasValue ? "false" : "true";
|
||||
if (hasValue) {
|
||||
input.readOnly = true;
|
||||
input.setAttribute("readonly", "readonly");
|
||||
input.classList.add("locked-input");
|
||||
} else {
|
||||
input.readOnly = false;
|
||||
input.removeAttribute("readonly");
|
||||
input.classList.remove("locked-input");
|
||||
}
|
||||
|
||||
@@ -327,6 +409,8 @@ export class EditModal {
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
this.handleIsPrivateChange({ emit: false });
|
||||
}
|
||||
|
||||
fieldIdForKey(key) {
|
||||
@@ -345,6 +429,8 @@ export class EditModal {
|
||||
return "editVideoThumbnail";
|
||||
case "description":
|
||||
return "editVideoDescription";
|
||||
case "isPrivate":
|
||||
return "editVideoIsPrivate";
|
||||
case "enableComments":
|
||||
return "editEnableComments";
|
||||
default:
|
||||
@@ -385,15 +471,22 @@ export class EditModal {
|
||||
return;
|
||||
}
|
||||
|
||||
const mode = button.dataset.mode || "locked";
|
||||
const isCheckbox = input.type === "checkbox";
|
||||
const isLocked = isCheckbox
|
||||
? input.disabled === true
|
||||
: input.readOnly === true;
|
||||
|
||||
if (mode === "locked") {
|
||||
if (isLocked) {
|
||||
if (isCheckbox) {
|
||||
input.disabled = false;
|
||||
input.removeAttribute("disabled");
|
||||
input.dataset.isEditing = "true";
|
||||
} else {
|
||||
input.disabled = false;
|
||||
input.readOnly = false;
|
||||
input.removeAttribute("readonly");
|
||||
input.classList.remove("locked-input");
|
||||
input.dataset.isEditing = "true";
|
||||
}
|
||||
button.dataset.mode = "editing";
|
||||
button.textContent = "Restore original";
|
||||
@@ -408,6 +501,9 @@ export class EditModal {
|
||||
}
|
||||
}
|
||||
}
|
||||
if (input === this.fields.isPrivate) {
|
||||
this.updateVisibilityToggleUI();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -416,8 +512,13 @@ export class EditModal {
|
||||
if (isCheckbox) {
|
||||
input.checked = originalValue === "true";
|
||||
input.disabled = true;
|
||||
input.setAttribute("disabled", "disabled");
|
||||
input.dataset.isEditing = "false";
|
||||
button.dataset.mode = "locked";
|
||||
button.textContent = "Edit field";
|
||||
if (input === this.fields.isPrivate) {
|
||||
this.updateVisibilityToggleUI();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -425,18 +526,121 @@ export class EditModal {
|
||||
|
||||
if (originalValue) {
|
||||
input.readOnly = true;
|
||||
input.setAttribute("readonly", "readonly");
|
||||
input.classList.add("locked-input");
|
||||
input.dataset.isEditing = "false";
|
||||
button.dataset.mode = "locked";
|
||||
button.textContent = "Edit field";
|
||||
} else {
|
||||
input.readOnly = false;
|
||||
input.removeAttribute("readonly");
|
||||
input.classList.remove("locked-input");
|
||||
input.dataset.isEditing = "true";
|
||||
button.classList.add("hidden");
|
||||
button.dataset.mode = "locked";
|
||||
button.textContent = "Edit field";
|
||||
}
|
||||
}
|
||||
|
||||
setVisibility(option, { emit = true } = {}) {
|
||||
const checkbox = this.fields.isPrivate;
|
||||
if (!checkbox) {
|
||||
return;
|
||||
}
|
||||
|
||||
const normalized = typeof option === "string" ? option.toLowerCase() : "";
|
||||
if (normalized !== "public" && normalized !== "private") {
|
||||
return;
|
||||
}
|
||||
|
||||
if (checkbox.disabled) {
|
||||
this.updateVisibilityToggleUI();
|
||||
return;
|
||||
}
|
||||
|
||||
const wantPrivate = normalized === "private";
|
||||
if (checkbox.checked === wantPrivate) {
|
||||
this.updateVisibilityToggleUI();
|
||||
return;
|
||||
}
|
||||
|
||||
checkbox.checked = wantPrivate;
|
||||
this.handleIsPrivateChange({ emit });
|
||||
}
|
||||
|
||||
updateVisibilityToggleUI() {
|
||||
const checkbox = this.fields.isPrivate;
|
||||
const buttons = Array.isArray(this.visibility?.buttons)
|
||||
? this.visibility.buttons
|
||||
: [];
|
||||
if (!checkbox) {
|
||||
return;
|
||||
}
|
||||
|
||||
const isPrivate = checkbox.checked === true;
|
||||
const disabled = checkbox.disabled === true;
|
||||
|
||||
buttons.forEach((button) => {
|
||||
if (!button) {
|
||||
return;
|
||||
}
|
||||
const option = button.dataset?.visibilityOption || "";
|
||||
const normalized = option.toLowerCase();
|
||||
const isActive =
|
||||
(normalized === "private" && isPrivate) ||
|
||||
(normalized === "public" && !isPrivate);
|
||||
button.dataset.active = isActive ? "true" : "false";
|
||||
button.setAttribute("aria-pressed", isActive ? "true" : "false");
|
||||
if (disabled) {
|
||||
button.classList.add("is-disabled");
|
||||
button.setAttribute("aria-disabled", "true");
|
||||
button.tabIndex = -1;
|
||||
} else {
|
||||
button.classList.remove("is-disabled");
|
||||
button.removeAttribute("aria-disabled");
|
||||
button.tabIndex = 0;
|
||||
}
|
||||
});
|
||||
|
||||
if (this.visibility?.container) {
|
||||
this.visibility.container.dataset.state = isPrivate ? "private" : "public";
|
||||
if (disabled) {
|
||||
this.visibility.container.dataset.disabled = "true";
|
||||
} else {
|
||||
delete this.visibility.container.dataset.disabled;
|
||||
}
|
||||
}
|
||||
|
||||
const helper = this.visibility?.helper;
|
||||
if (helper) {
|
||||
const privateCopy = this.visibility.helperDefault || helper.textContent;
|
||||
const publicCopy =
|
||||
"Public notes appear in feeds for everyone who can view your channel.";
|
||||
helper.textContent = isPrivate ? privateCopy : publicCopy;
|
||||
}
|
||||
}
|
||||
|
||||
handleIsPrivateChange({ emit = true } = {}) {
|
||||
const checkbox = this.fields.isPrivate;
|
||||
if (!checkbox) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.updateVisibilityToggleUI();
|
||||
|
||||
if (!emit) {
|
||||
return;
|
||||
}
|
||||
|
||||
const value = this.sanitizers.checkbox(checkbox.checked);
|
||||
const detail = {
|
||||
field: "isPrivate",
|
||||
value,
|
||||
videoId: this.escapeHtml(this.activeVideo?.id || ""),
|
||||
};
|
||||
this.emit("video:edit-visibility-change", detail);
|
||||
}
|
||||
|
||||
submit() {
|
||||
if (!this.activeVideo || !this.root) {
|
||||
this.showError("No video selected for editing.");
|
||||
@@ -467,6 +671,7 @@ export class EditModal {
|
||||
const thumbnailInput = this.fields.thumbnail;
|
||||
const descriptionInput = this.fields.description;
|
||||
const commentsInput = this.fields.enableComments;
|
||||
const privateInput = this.fields.isPrivate;
|
||||
|
||||
const newTitle = fieldValue("title");
|
||||
const newUrl = fieldValue("url");
|
||||
@@ -476,7 +681,18 @@ export class EditModal {
|
||||
const newThumbnail = fieldValue("thumbnail");
|
||||
const newDescription = fieldValue("description");
|
||||
|
||||
const isEditing = (input) => !input || input.readOnly === false;
|
||||
const isEditing = (input) => {
|
||||
if (!input) {
|
||||
return true;
|
||||
}
|
||||
if (input.dataset?.isEditing === "true") {
|
||||
return true;
|
||||
}
|
||||
if (input.type === "checkbox") {
|
||||
return input.disabled === false;
|
||||
}
|
||||
return input.readOnly === false;
|
||||
};
|
||||
|
||||
const titleWasEdited = isEditing(titleInput);
|
||||
const urlWasEdited = isEditing(urlInput);
|
||||
@@ -497,6 +713,7 @@ export class EditModal {
|
||||
: original.description || "";
|
||||
const originalEnableComments =
|
||||
typeof original.enableComments === "boolean" ? original.enableComments : true;
|
||||
const originalIsPrivate = original.isPrivate === true;
|
||||
|
||||
let finalEnableComments = originalEnableComments;
|
||||
if (commentsInput) {
|
||||
@@ -507,6 +724,15 @@ export class EditModal {
|
||||
}
|
||||
}
|
||||
|
||||
let finalIsPrivate = originalIsPrivate;
|
||||
if (privateInput) {
|
||||
if (privateInput.disabled) {
|
||||
finalIsPrivate = privateInput.dataset.originalValue === "true";
|
||||
} else {
|
||||
finalIsPrivate = this.sanitizers.checkbox(privateInput.checked);
|
||||
}
|
||||
}
|
||||
|
||||
if (!finalTitle || (!finalUrl && !finalMagnet)) {
|
||||
this.showError("Title and at least one of URL or Magnet is required.");
|
||||
return;
|
||||
@@ -546,6 +772,7 @@ export class EditModal {
|
||||
urlEdited: urlWasEdited,
|
||||
magnetEdited: magnetWasEdited,
|
||||
enableComments: finalEnableComments,
|
||||
isPrivate: finalIsPrivate,
|
||||
};
|
||||
|
||||
const originalEvent = {
|
||||
|
||||
@@ -28,7 +28,8 @@ export class VideoCard {
|
||||
this.video = video;
|
||||
this.index = index;
|
||||
this.shareUrl = shareUrl;
|
||||
this.highlightClass = highlightClass || "";
|
||||
this.highlightClass =
|
||||
typeof highlightClass === "string" ? highlightClass : "";
|
||||
this.animationClass = animationClass || "";
|
||||
this.pointerInfo = pointerInfo;
|
||||
this.capabilities = {
|
||||
|
||||
@@ -321,9 +321,8 @@ export class VideoListView {
|
||||
const shareUrl = this.buildShareUrl(video, shareBase);
|
||||
const canEdit = this.utils.canEditVideo(video);
|
||||
const canDelete = this.utils.canDeleteVideo(video);
|
||||
const highlightClass = canEdit && video.isPrivate
|
||||
? "border-2 border-yellow-500"
|
||||
: "border-none";
|
||||
const highlightClass =
|
||||
canEdit && video.isPrivate ? "video-card--owner-private" : "";
|
||||
const isNewlyRendered = !previouslyRenderedIds.has(video.id);
|
||||
const animationClass = isNewlyRendered ? "video-card--enter" : "";
|
||||
const timeAgo = this.formatters.formatTimeAgo(video.created_at);
|
||||
|
||||
Reference in new issue
Block a user