diff --git a/frontend/apps/artcraft/app/src/components/experiences/ImageTo3DExperience.tsx b/frontend/apps/artcraft/app/src/components/experiences/ImageTo3DExperience.tsx index 3f0e4f3b7a..973ac36977 100644 --- a/frontend/apps/artcraft/app/src/components/experiences/ImageTo3DExperience.tsx +++ b/frontend/apps/artcraft/app/src/components/experiences/ImageTo3DExperience.tsx @@ -944,7 +944,7 @@ export const ImageTo3DExperience = ({
@@ -1111,7 +1111,7 @@ export const ImageTo3DExperience = ({
{option.label}
- {option.description && option.description} + {option.description}
{showSelected && ( <> diff --git a/frontend/libs/components/gallery-modal/src/lib/FolderNameDialog.tsx b/frontend/libs/components/gallery-modal/src/lib/FolderNameDialog.tsx index 8e232b85ae..26b006c461 100644 --- a/frontend/libs/components/gallery-modal/src/lib/FolderNameDialog.tsx +++ b/frontend/libs/components/gallery-modal/src/lib/FolderNameDialog.tsx @@ -64,7 +64,6 @@ export const FolderNameDialog: React.FC = ({ if (e.key === "Enter") submit(); }} className="w-full rounded-[3px] border border-ui-panel-border bg-ui-controls/40 px-3 py-1.5 text-sm text-base-fg outline-none focus:ring-1 focus:ring-primary/50" - autoFocus />
@@ -47,21 +45,6 @@ export function EditorHeader({ endSlot, exitTo = "/projects" }: EditorHeaderProp ); } -function CurrentUserBadge() { - const { authUser } = useEditorAdapters(); - const user = useAuthUser(authUser); - if (!user) return null; - return ( - // - // {user.displayName} - // - null - ); -} - function ProjectDropdown({ exitTo }: { exitTo: string }) { const [openDialog, setOpenDialog] = useState< "delete" | "rename" | "shortcuts" | null diff --git a/frontend/libs/components/video-editor/src/lib/components/ui/alert.tsx b/frontend/libs/components/video-editor/src/lib/components/ui/alert.tsx index cfcf4cbc84..84c4a648d4 100644 --- a/frontend/libs/components/video-editor/src/lib/components/ui/alert.tsx +++ b/frontend/libs/components/video-editor/src/lib/components/ui/alert.tsx @@ -44,7 +44,7 @@ Alert.displayName = "Alert"; const AlertTitle = React.forwardRef< HTMLParagraphElement, React.HTMLAttributes ->(({ className, ...props }, ref) => ( +>(({ className, children, ...props }, ref) => (
+ > + {children} +
)); AlertTitle.displayName = "AlertTitle"; diff --git a/frontend/libs/components/video-editor/src/lib/core/managers/audio-manager.ts b/frontend/libs/components/video-editor/src/lib/core/managers/audio-manager.ts index 8f0aaea5a0..85a7e00054 100644 --- a/frontend/libs/components/video-editor/src/lib/core/managers/audio-manager.ts +++ b/frontend/libs/components/video-editor/src/lib/core/managers/audio-manager.ts @@ -539,7 +539,7 @@ export class AudioManager { }): Promise { const cacheKey = this.buildPreparedClipCacheKey({ clip }); const existing = this.preparedClipBuffers.get(cacheKey); - if (existing) { + if (existing !== undefined) { return existing; } @@ -574,7 +574,7 @@ export class AudioManager { clip: AudioClipSource; }): Promise { const existing = this.decodedBuffers.get(clip.sourceKey); - if (existing) { + if (existing !== undefined) { return existing; } diff --git a/frontend/libs/components/video-editor/src/lib/fonts/google-fonts.ts b/frontend/libs/components/video-editor/src/lib/fonts/google-fonts.ts index d3303c6b06..fa537feb4c 100644 --- a/frontend/libs/components/video-editor/src/lib/fonts/google-fonts.ts +++ b/frontend/libs/components/video-editor/src/lib/fonts/google-fonts.ts @@ -26,7 +26,7 @@ export function clearFontAtlasCache(): void { export function loadFontAtlas(): Promise { if (cachedAtlas) return Promise.resolve(cachedAtlas); - if (atlasFetchPromise) return atlasFetchPromise; + if (atlasFetchPromise !== null) return atlasFetchPromise; atlasFetchPromise = fetch(FONT_ATLAS_PATH) .then(async (response) => { diff --git a/frontend/libs/components/video-editor/src/lib/fonts/use-font-atlas.ts b/frontend/libs/components/video-editor/src/lib/fonts/use-font-atlas.ts index cb71f70c3d..a4d7fc12ae 100644 --- a/frontend/libs/components/video-editor/src/lib/fonts/use-font-atlas.ts +++ b/frontend/libs/components/video-editor/src/lib/fonts/use-font-atlas.ts @@ -46,7 +46,9 @@ export function useFontAtlas({ open }: { open: boolean }) { const fontNames = useMemo(() => { if (!atlas) return []; - return [...Object.keys(atlas.fonts), ...SYSTEM_FONTS].sort(); + return [...Object.keys(atlas.fonts), ...SYSTEM_FONTS].sort((a, b) => + a.localeCompare(b), + ); }, [atlas]); return { atlas, status, fontNames, retry }; diff --git a/frontend/libs/components/video-editor/src/lib/guides/definitions/grid.tsx b/frontend/libs/components/video-editor/src/lib/guides/definitions/grid.tsx index afa74a773a..e957301e35 100644 --- a/frontend/libs/components/video-editor/src/lib/guides/definitions/grid.tsx +++ b/frontend/libs/components/video-editor/src/lib/guides/definitions/grid.tsx @@ -7,7 +7,6 @@ import { HugeiconsIcon } from "@hugeicons/react"; import { GRID_MIN, GRID_MAX, - DEFAULT_GRID_CONFIG, } from "../grid"; import { usePreviewStore } from "../../preview/preview-store"; import { clampRound } from "../../utils/math"; @@ -113,9 +112,6 @@ function GridGuideOptions() { }} /> - {/* Acknowledge DEFAULT_GRID_CONFIG so the reset import stays parked - for when NumberField (with its onReset affordance) is ported. */} - {DEFAULT_GRID_CONFIG ? null : null}
); } diff --git a/frontend/libs/components/video-editor/src/lib/preview/preview-snap.ts b/frontend/libs/components/video-editor/src/lib/preview/preview-snap.ts index 48bc5f2767..11ed819659 100644 --- a/frontend/libs/components/video-editor/src/lib/preview/preview-snap.ts +++ b/frontend/libs/components/video-editor/src/lib/preview/preview-snap.ts @@ -75,7 +75,7 @@ function pickClosestScaleCandidate - current.distance < closest.distance ? current : closest, + return snapCandidatesWithinThreshold.reduce( + (closest, current) => + current.distance < closest.distance ? current : closest, + snapCandidatesWithinThreshold[0], ); } diff --git a/frontend/libs/components/video-editor/src/lib/services/renderer/nodes/image-node.ts b/frontend/libs/components/video-editor/src/lib/services/renderer/nodes/image-node.ts index c64e9809e1..67f6d18e3f 100644 --- a/frontend/libs/components/video-editor/src/lib/services/renderer/nodes/image-node.ts +++ b/frontend/libs/components/video-editor/src/lib/services/renderer/nodes/image-node.ts @@ -35,7 +35,7 @@ export function loadImageSource({ const cacheKey = `${url}::${maxSourceSize ?? "full"}`; const cached = imageSourceCache.get(cacheKey); - if (cached) return cached; + if (cached !== undefined) return cached; const promise = (async (): Promise => { const image = new Image(); diff --git a/frontend/libs/components/video-editor/src/lib/services/renderer/nodes/sticker-node.ts b/frontend/libs/components/video-editor/src/lib/services/renderer/nodes/sticker-node.ts index 6a15d04c79..ceb23a9108 100644 --- a/frontend/libs/components/video-editor/src/lib/services/renderer/nodes/sticker-node.ts +++ b/frontend/libs/components/video-editor/src/lib/services/renderer/nodes/sticker-node.ts @@ -25,7 +25,7 @@ export function loadStickerSource({ stickerId: string; }): Promise { const cached = stickerSourceCache.get(stickerId); - if (cached) return cached; + if (cached !== undefined) return cached; const promise = (async (): Promise => { const url = resolveStickerId({ diff --git a/frontend/libs/components/video-editor/src/lib/services/video-cache/service.ts b/frontend/libs/components/video-editor/src/lib/services/video-cache/service.ts index 01f230698e..e32326c32f 100644 --- a/frontend/libs/components/video-editor/src/lib/services/video-cache/service.ts +++ b/frontend/libs/components/video-editor/src/lib/services/video-cache/service.ts @@ -170,7 +170,7 @@ export class VideoCache { try { while (true) { - if (sinkData.prefetching && sinkData.prefetchPromise) { + if (sinkData.prefetching && sinkData.prefetchPromise !== null) { await sinkData.prefetchPromise; } @@ -215,7 +215,7 @@ export class VideoCache { time: number; }): Promise { try { - if (sinkData.prefetching && sinkData.prefetchPromise) { + if (sinkData.prefetching && sinkData.prefetchPromise !== null) { await sinkData.prefetchPromise; } diff --git a/frontend/libs/components/video-editor/src/lib/services/waveform-cache/service.ts b/frontend/libs/components/video-editor/src/lib/services/waveform-cache/service.ts index 59fbb914e8..48da5f0d89 100644 --- a/frontend/libs/components/video-editor/src/lib/services/waveform-cache/service.ts +++ b/frontend/libs/components/video-editor/src/lib/services/waveform-cache/service.ts @@ -27,7 +27,7 @@ export class WaveformCache { audioUrl, }: GetSourceWaveformSummaryArgs): Promise { const existing = this.summaries.get(sourceKey); - if (existing) { + if (existing !== undefined) { return existing; } diff --git a/frontend/libs/components/video-editor/src/lib/timeline/components/timeline-element.tsx b/frontend/libs/components/video-editor/src/lib/timeline/components/timeline-element.tsx index 6a1342b583..9126806e74 100644 --- a/frontend/libs/components/video-editor/src/lib/timeline/components/timeline-element.tsx +++ b/frontend/libs/components/video-editor/src/lib/timeline/components/timeline-element.tsx @@ -47,7 +47,6 @@ import { mediaSupportsAudio } from "../../media/media-utils"; import { canToggleSourceAudio, getSourceAudioActionLabel, - isSourceAudioSeparated, } from "../audio-separation"; import { buildWaveformGainSamples, isElementMuted } from "../audio-state"; import { getTimelinePixelsPerSecond } from "../pixel-utils"; @@ -346,8 +345,6 @@ export function TimelineElement({ element.type === "video" ? getSourceAudioActionLabel({ element }) : "Extract audio"; - const isElementSourceAudioSeparated = - element.type === "video" && isSourceAudioSeparated({ element }); const hasKeyframes = elementKeyframes.length > 0; const expansionHeight = getExpansionHeight({ rows: expandedRows }); const baseTrackHeight = getTrackHeight({ type: track.type }); @@ -450,11 +447,7 @@ export function TimelineElement({ {canToggleCurrentSourceAudio && ( + } onClick={(event: React.MouseEvent) => { event.stopPropagation(); diff --git a/frontend/libs/components/video-editor/src/lib/timeline/placement/main-track.ts b/frontend/libs/components/video-editor/src/lib/timeline/placement/main-track.ts index a3c6152614..5a46d56534 100644 --- a/frontend/libs/components/video-editor/src/lib/timeline/placement/main-track.ts +++ b/frontend/libs/components/video-editor/src/lib/timeline/placement/main-track.ts @@ -26,7 +26,7 @@ export function getEarliestMainTrackElement({ return element.startTime < earliestElement.startTime ? element : earliestElement; - }); + }, elements[0]); } export function enforceMainTrackStart({ diff --git a/frontend/libs/components/video-editor/src/lib/utils/color.ts b/frontend/libs/components/video-editor/src/lib/utils/color.ts index a792894150..20839ed74a 100644 --- a/frontend/libs/components/video-editor/src/lib/utils/color.ts +++ b/frontend/libs/components/video-editor/src/lib/utils/color.ts @@ -54,10 +54,8 @@ export function appendAlpha({ function stripCssNoise({ text }: { text: string }): string { let cleaned = text.trim(); - cleaned = cleaned - .replace(/\s*!important\s*/gi, "") - .replace(/;+\s*$/, "") - .trim(); + cleaned = cleaned.replace(/!important/gi, " ").trim(); + while (cleaned.endsWith(";")) cleaned = cleaned.slice(0, -1).trimEnd(); const colonIndex = cleaned.indexOf(":"); const parenIndex = cleaned.indexOf("("); diff --git a/frontend/libs/components/viewer-3d/src/lib/viewer-3d.tsx b/frontend/libs/components/viewer-3d/src/lib/viewer-3d.tsx index 0ddde8f2ce..a3808f86b8 100644 --- a/frontend/libs/components/viewer-3d/src/lib/viewer-3d.tsx +++ b/frontend/libs/components/viewer-3d/src/lib/viewer-3d.tsx @@ -408,9 +408,8 @@ export function Viewer3D({ if (SPLAT_EXTENSIONS.includes(urlExtension)) { console.log(`[Viewer3D] splat format detected (.${urlExtension})`); - new SplatMesh({ - url: modelUrl, - onLoad: (mesh) => { + void new SplatMesh({ url: modelUrl }).initialized + .then((mesh) => { if (cancelled) { mesh.dispose(); return; @@ -434,8 +433,10 @@ export function Viewer3D({ } console.log("Splat loaded"); - }, - }); + }) + .catch((error) => + console.error("[Viewer3D] splat load failed:", error), + ); } else if (!GLTF_EXTENSIONS.includes(urlExtension)) { // Known non-glTF model format with no loader wired here (obj, fbx, // pmx, …). Show the fallback shape rather than spamming a parse error. diff --git a/frontend/libs/markdown-content/src/lib/utils/markdown.ts b/frontend/libs/markdown-content/src/lib/utils/markdown.ts index a50469bc47..c240865e5d 100644 --- a/frontend/libs/markdown-content/src/lib/utils/markdown.ts +++ b/frontend/libs/markdown-content/src/lib/utils/markdown.ts @@ -143,7 +143,7 @@ export const markdownToHtml = ( return renderImage(safeUrl, alt, size); }); // links: [text](url) - out = out.replace(/\[([^\]]+)\]\(([^)]+)\)/g, (_m, label, url) => { + out = out.replace(/\[([^\][]+)\]\(([^)]+)\)/g, (_m, label, url) => { const safeLabel = String(label || "").replace(/"/g, """); const safeUrl = normalizeLink(String(url || "")); return `${safeLabel}`; @@ -220,7 +220,7 @@ export const markdownToHtml = ( // Image/GIF embed: @image(url, size) or @gif(url, size) const imageMatch = ltrim.match( - /^@(image|gif)\(([^,)]+)(?:,\s*([^)]+))?\)\s*$/, + /^@(image|gif)\(([^,)]+)(?:,([^)]+))?\)\s*$/, ); if (imageMatch) { flushParagraph(); @@ -232,12 +232,12 @@ export const markdownToHtml = ( } // ATX headings: support #..###### with optional space after hashes - const heading = ltrim.match(/^(#{1,6})\s*(.*)$/); + const heading = ltrim.match(/^(#{1,6})(.*)$/); if (heading) { flushParagraph(); closeListIfOpen(); const level = Math.min(heading[1].length, 6); - const text = renderInline(heading[2] || ""); + const text = renderInline((heading[2] || "").trimStart()); htmlParts.push(`${text}`); continue; } @@ -318,7 +318,7 @@ export const slugify = (s: string): string => .replace(/[_\s]+/g, "-") .replace(/[^a-z0-9-]/g, "") .replace(/--+/g, "-") - .replace(/^-+|-+$/g, ""); + .replace(/^-|-$/g, ""); export const pathToFilename = (path: string): string => { const parts = path.split("/"); diff --git a/frontend/libs/model-list/src/lib/classes/videoOptions.ts b/frontend/libs/model-list/src/lib/classes/videoOptions.ts index 7657fb5c05..76d07dd229 100644 --- a/frontend/libs/model-list/src/lib/classes/videoOptions.ts +++ b/frontend/libs/model-list/src/lib/classes/videoOptions.ts @@ -70,7 +70,7 @@ export function resolveVideoDuration( (distance === bestDistance && option > best) ? option : best; - }); + }, model.durationOptions[0]); } return model.defaultDuration ?? null; }