mirror of
https://github.com/block/buzz.git
synced 2026-11-09 02:41:57 +00:00
## What changed - render video-review timecode chips inside the first Markdown paragraph so comment text wraps naturally around them - reuse the canonical video-review chip treatment across the timeline, Inbox previews, and Inbox detail - preserve video-review context in Inbox so timestamp chips remain interactive ## Why Video comments now support Markdown-like effects, but non-player surfaces rendered the timestamp beside a separate text layout. That kept the chip and comment from sharing the same inline flow and made Inbox behavior inconsistent with the player. ## Validation - `pnpm --dir desktop check` - 100 focused Markdown, timecode, video-review, and Inbox unit tests - `pnpm --dir desktop build:e2e` - focused `video-attachment.spec.ts` Playwright scenario - pre-push desktop typecheck and 4,761-test desktop suite - native Builderlab staging with the configured profile Focused timeline and Inbox snapshots will be attached in a PR comment. --------- Signed-off-by: kenny lopez <klopez4212@gmail.com> Signed-off-by: Fast Fizz <2df81cb51f05a9d5387ef24d7b9ecb8fcdfcd1c70ffabc67061c9596e1b5b1c4@buzz.block.builderlab.xyz> Co-authored-by: Fast Fizz <2df81cb51f05a9d5387ef24d7b9ecb8fcdfcd1c70ffabc67061c9596e1b5b1c4@buzz.block.builderlab.xyz>
78 lines
2.2 KiB
TypeScript
78 lines
2.2 KiB
TypeScript
import * as React from "react";
|
|
|
|
import { Markdown } from "@/shared/ui/markdown";
|
|
import type { MarkdownProps } from "@/shared/ui/markdown/types";
|
|
import { useOpenVideoReviewAt } from "@/shared/ui/VideoReviewNavigation";
|
|
import { parseVideoReviewTimecode } from "@/shared/ui/videoReviewTimecode";
|
|
import {
|
|
VideoReviewTimecodeButton,
|
|
VideoReviewTimecodeChip,
|
|
} from "@/shared/ui/VideoReviewTimecodeButton";
|
|
|
|
type VideoReviewCommentMarkdownProps = Omit<
|
|
MarkdownProps,
|
|
"leadingInlineContent"
|
|
> & {
|
|
videoReviewCommentRootId?: string;
|
|
};
|
|
|
|
/** Renders a video-review timecode inside the comment's first Markdown line. */
|
|
export function VideoReviewCommentMarkdown({
|
|
content,
|
|
interactive = true,
|
|
videoReviewCommentRootId,
|
|
...markdownProps
|
|
}: VideoReviewCommentMarkdownProps) {
|
|
const openVideoReviewAt = useOpenVideoReviewAt();
|
|
const reviewTimecode = React.useMemo(
|
|
() => (videoReviewCommentRootId ? parseVideoReviewTimecode(content) : null),
|
|
[content, videoReviewCommentRootId],
|
|
);
|
|
const handleTimecodeClick = React.useCallback(
|
|
(event: React.MouseEvent<HTMLButtonElement>) => {
|
|
event.stopPropagation();
|
|
if (reviewTimecode && videoReviewCommentRootId) {
|
|
openVideoReviewAt?.(videoReviewCommentRootId, reviewTimecode.seconds);
|
|
}
|
|
},
|
|
[openVideoReviewAt, reviewTimecode, videoReviewCommentRootId],
|
|
);
|
|
const leadingInlineContent = React.useMemo(() => {
|
|
if (!reviewTimecode) return undefined;
|
|
|
|
const timecode =
|
|
interactive && openVideoReviewAt ? (
|
|
<VideoReviewTimecodeButton
|
|
surface="message"
|
|
timecode={reviewTimecode.timecode}
|
|
onClick={handleTimecodeClick}
|
|
/>
|
|
) : (
|
|
<VideoReviewTimecodeChip
|
|
surface="message"
|
|
timecode={reviewTimecode.timecode}
|
|
/>
|
|
);
|
|
return <>{timecode} </>;
|
|
}, [handleTimecodeClick, interactive, openVideoReviewAt, reviewTimecode]);
|
|
|
|
if (!reviewTimecode) {
|
|
return (
|
|
<Markdown
|
|
{...markdownProps}
|
|
content={content}
|
|
interactive={interactive}
|
|
/>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<Markdown
|
|
{...markdownProps}
|
|
content={reviewTimecode.text || "\u200B"}
|
|
interactive={interactive}
|
|
leadingInlineContent={leadingInlineContent}
|
|
/>
|
|
);
|
|
}
|