Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
102 changes: 102 additions & 0 deletions components/video-metadata-details.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
"use client";

import { useEffect, useRef, useState } from "react";
import { useTranslations } from "next-intl";
import { ChevronDown } from "lucide-react";

import { ExternalLink } from "./external-link";
import type { VideoMetadata } from "@/lib/un-api";
import { typography } from "@/lib/typography";
import { cn } from "@/lib/utils";

/**
* The descriptive half of a WebTV asset's metadata: the long-form description
* and any related sites and documents.
*
* The text is scraped from the English WebTV asset page regardless of the
* request locale (see getVideoMetadata), so the headings translate but the
* content stays English.
*/
export function VideoMetadataDetails({
metadata,
}: {
metadata: VideoMetadata;
}) {
const t = useTranslations("video.metadata");
const [expanded, setExpanded] = useState(false);
const [overflowing, setOverflowing] = useState(false);
const descriptionRef = useRef<HTMLParagraphElement>(null);

// Only measure while collapsed — once expanded the element no longer
// overflows, and re-measuring would hide the "show less" control.
useEffect(() => {
if (expanded) return;
const el = descriptionRef.current;
if (!el) return;
setOverflowing(el.scrollHeight > el.clientHeight + 1);
}, [metadata.description, expanded]);

const hasDescription = Boolean(metadata.description);
const hasRelatedDocuments = metadata.relatedDocuments.length > 0;
if (!hasDescription && !hasRelatedDocuments) return null;

return (
<>
{hasDescription && (
<section className="mt-4">
<h2 className={cn(typography.label, "text-muted-foreground")}>
{t("description")}
</h2>
<p
ref={descriptionRef}
className={cn(
"mt-1 whitespace-pre-line",
typography.body,
"text-muted-foreground",
!expanded && "line-clamp-3",
)}
>
{metadata.description}
</p>
{(overflowing || expanded) && (
<button
type="button"
aria-expanded={expanded}
onClick={() => setExpanded((value) => !value)}
className="mt-1 flex items-center gap-1 text-xs text-primary hover:underline"
>
{expanded ? t("showLess") : t("showMore")}
<ChevronDown
aria-hidden
className={cn(
"size-3.5 transition-transform",
expanded && "rotate-180",
)}
/>
</button>
)}
</section>
)}

{hasRelatedDocuments && (
<section className="mt-4">
<h2 className={cn(typography.label, "text-muted-foreground")}>
{t("relatedDocuments")}
</h2>
<ul className="mt-1 space-y-0.5">
{metadata.relatedDocuments.map((document) => (
<li key={document.url} className="text-sm">
<ExternalLink
href={document.url}
className="text-primary hover:underline"
>
{document.title}
</ExternalLink>
</li>
))}
</ul>
</section>
)}
</>
);
}
3 changes: 3 additions & 0 deletions components/video-page-client.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import { PVSpeakerToc } from "./pv-panel";
import { SiteHeader } from "./site-header";
import { ExternalLink } from "./external-link";
import { CategoryPill } from "./category-pill";
import { VideoMetadataDetails } from "./video-metadata-details";
import { FoldVertical, UnfoldVertical, ChevronDown } from "lucide-react";
import type { Video, VideoMetadata } from "@/lib/un-api";
import { useMeetingFormat } from "@/lib/hooks/use-meeting-format";
Expand Down Expand Up @@ -405,6 +406,8 @@ export function VideoPageClient({
{metadata.summary}
</p>
)}

<VideoMetadataDetails metadata={metadata} />
</div>
</div>

Expand Down
203 changes: 203 additions & 0 deletions lib/__fixtures__/webtv/c24.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,203 @@
<article class="node media-asset media-asset--full">
<div class="_none"><div class="container-fluid">
<div class="layout row no-gutters layout-builder__layout">

<div class="col-lg-4 col-md-12 col-12">

<div class="border-top border-4 border-primary py-3 block">





<div class="field field--name-title field--type-string field--label-hidden field__items media-asset__title">
<h2 class="field__item">(9th plenary meeting) Special Committee on Decolonization (C-24) - 2026 session</h2>
</div>

</div>

<div class="pb-3 block">





<div class="field field--name-field-categories field--type-entity-reference field--label-above field__items media-asset__field-categories">
<div class="small text-muted field__label">Categories</div>
<div class="field__item"><a href="/en/search/categories/meetings-events" hreflang="en">Meetings &amp; Events</a> / <a href="/en/search/categories/meetings-events/general-assembly" hreflang="en">General Assembly</a> / <a href="/en/search/categories/meetings-events/general-assembly/subsidiary-organs-general-assembly" hreflang="en">Subsidiary organs of the General Assembly</a> / <a href="/en/search/categories/meetings-events/general-assembly/subsidiary-organs-general-assembly/special-committee-decolonization-c-24" hreflang="en">Special Committee on Decolonization (C-24)</a> / <a href="/en/search/categories/meetings-events/general-assembly/subsidiary-organs-general-assembly/special-committee-decolonization-c-24/2026-session" hreflang="en">2026 Session</a></div>
</div>

</div>

<div class="pb-3 block">





<div class="field field--name-field-production-date field--type-datetime field--label-above field__items media-asset__field-production-date">
<div class="small text-muted field__label">Production Date</div>
<div class="field__item"><time datetime="2026-06-25T12:00:00Z">25 Jun 2026</time>
</div>
</div>

</div>

<div class="pb-3 block">





<div class="field field--name-field-duration field--type-string field--label-above field__items media-asset__field-duration">
<div class="small text-muted field__label">Video Length</div>
<div class="field__item">02:31:55</div>
</div>

</div>

<div class="pb-3 block">





<div class="field field--name-field-asset-language field--type-entity-reference field--label-above field__items media-asset__field-asset-language">
<div class="small text-muted field__label">Asset Language</div>
<div class="field__item"><a href="https://webtv.un.org/en/search?f%5B0%5D=asset_language%3A5761" rel="nofollow" hreflang="en">Arabic</a></div>
<div class="field__item"><a href="https://webtv.un.org/en/search?f%5B0%5D=asset_language%3A5763" rel="nofollow" hreflang="en">Chinese</a></div>
<div class="field__item"><a href="https://webtv.un.org/en/search?f%5B0%5D=asset_language%3A5764" rel="nofollow" hreflang="en">English</a></div>
<div class="field__item"><a href="https://webtv.un.org/en/search?f%5B0%5D=asset_language%3A5765" rel="nofollow" hreflang="en">French</a></div>
<div class="field__item"><a href="https://webtv.un.org/en/search?f%5B0%5D=asset_language%3A5774" rel="nofollow" hreflang="en">Russian</a></div>
<div class="field__item"><a href="https://webtv.un.org/en/search?f%5B0%5D=asset_language%3A5777" rel="nofollow" hreflang="en">Spanish</a></div>
<div class="field__item"><a href="https://webtv.un.org/en/search?f%5B0%5D=asset_language%3A5772" rel="nofollow" hreflang="en">Original</a></div>
</div>

</div>

<div class="pb-3 block">





<div class="field field--name-field-un-entity field--type-entity-reference field--label-above field__items media-asset__field-un-entity">
<div class="small text-muted field__label">Broadcasting UN Entity</div>
<div class="field__item"><a href="https://webtv.un.org/en/search?f%5B0%5D=un_entity%3A7759" rel="nofollow" hreflang="en">DEPARTMENT OF GLOBAL COMMUNICATIONS - DGC</a></div>
</div>

</div>

<div class="pb-3 block">





<div class="field field--name-field-subject-topical field--type-entity-reference field--label-above field__items media-asset__field-subject-topical">
<div class="small text-muted field__label">Subject Topical</div>
<div class="field__item"><a href="https://webtv.un.org/en/search?f%5B0%5D=topic%3A562" rel="nofollow" hreflang="en">DECOLONIZATION</a></div>
<div class="field__item"><a href="https://webtv.un.org/en/search?f%5B0%5D=topic%3A997" rel="nofollow" hreflang="en">NON-SELF-GOVERNING TERRITORIES</a></div>
<div class="field__item"><a href="https://webtv.un.org/en/search?f%5B0%5D=topic%3A1234" rel="nofollow" hreflang="en">SOVEREIGNTY</a></div>
</div>

</div>

<div class="pb-3 block">





<div class="field field--name-field-corporate-name field--type-entity-reference field--label-above field__items media-asset__field-corporate-name">
<div class="small text-muted field__label">Corporate Name</div>
<div class="field__item"><a href="https://webtv.un.org/en/search?f%5B0%5D=corporate_name%3A8280" rel="nofollow" hreflang="en">SPECIAL COMMITTEE ON DECOLONIZATION - C24</a></div>
</div>

</div>

</div>
<div class="col-lg-6 col-md-12 col-12">

<div class="border-top border-4 border-white py-3 block">





<div class="field field--name-field-summary field--type-text field--label-above field__items media-asset__field-summary">
<div class="h4 field__label">Summary</div>
<div class="field__item"><div class="smt-wrapper"><div class="smt-content" style="max-height: 220px">The Special Committee on the Situation with regard to the Implementation of the Declaration on the Granting of Independence to Colonial Countries and Peoples is also known as the Special Committee on Decolonization, or C-24.</div>
<span class="smt-toggle smt-more">View more</span><span class="smt-toggle smt-less">View less</span></div>
</div>
</div>

</div>

<div class="block">





<div class="field field--name-field-description field--type-text-long field--label-above field__items media-asset__field-description">
<div class="h4 field__label">Description</div>
<div class="field__item"><div class="smt-wrapper"><div class="smt-content" style="max-height: 220px"><ul> <li>Question of the Falkland Islands (Malvinas)</li> </ul> <p>The C-24 annually reviews the list of Non-Self-Governing Territories to which the Declaration is applicable. It also hears statements from representatives of the Non-Self-Governing Territories at its annual sessions, dispatches visiting missions to Non-Self-Governing Territories and annually organizes regional seminars.</p></div>
<span class="smt-toggle smt-more">View more</span><span class="smt-toggle smt-less">View less</span></div>
</div>
</div>

</div>

<div class="block">





<div class="pb-3 field field--name-field-related-url field--type-entity-reference-revisions field--label-above field__items media-asset__field-related-url">
<div class="h4 field__label">Related Sites and Documents</div>
<div class="field__item"> <div class="paragraph paragraph--type--related-url paragraph--view-mode--default">
<p class="details-p">
<a href="https://www.un.org/dppa/decolonization/en/c24/about" target="_blank">Special Committee on Decolonization website</a>
</p>
</div>
</div>
<div class="field__item"> <div class="paragraph paragraph--type--related-url paragraph--view-mode--default">
<p class="details-p">
<a href="https://docs.un.org/A/AC.109/2026/L.2/Rev.1" target="_blank">Organization of Work</a>
</p>
</div>
</div>
</div>

</div>

</div>
<div class="col-lg-2 col-md-12 col-12">

<div class="border-top border-4 border-primary py-3 block">




<span class="a2a_kit a2a_kit_size_16 addtoany_list" data-a2a-url="https://webtv.un.org/en/asset/k1s/k1sjz1in6d" data-a2a-title="(9th plenary meeting) Special Committee on Decolonization (C-24) - 2026 session"><h2 class="h5">Share</h2><div class="d-flex flex-column align-items-start gap-2"><a class="a2a_button_facebook btn btn-link text-nowrap p-0"><i class="fa-brands fa-square-facebook me-1"></i> Facebook</a><a class="a2a_button_twitter btn btn-link text-nowrap p-0"><i class="fa-brands fa-x-twitter me-1"></i> Twitter</a><a class="a2a_button_copy_link btn btn-link text-nowrap p-0"><i class="fas fa-link me-1"></i> Copy link</a></div></span>


</div>

<div class="block">






</div>

</div>

</div>

</div></div>
</article>
Loading
Loading