feat(channel): enrich the About tab + fix the tab-switch header shift
- fix: reserve the scrollbar gutter (scrollbar-gutter:stable) on the channel page's scroll container, so switching between the tall Videos tab and the short About tab no longer shifts the banner/avatar/buttons a few px sideways (the vertical scrollbar was appearing/disappearing between the two tabs). - About tab now shows Country (flag + localized name), Language, Topics (topicCategories → readable chips), and Keywords (brandingSettings keywords parsed into chips, quoted multi-word tags kept whole). country/language/topics were already stored; keywords is new (migration 0055_channel_keywords, mapped in apply_channel_details, returned by channel_detail). - Discovery → channel page: the Channel-manager "Discover from playlists" tab now links each channel name to its in-app channel page (ChannelLink onView), so a discovered channel's About/videos can be inspected BEFORE subscribing (was subscribe-only, plain text before). Note: the channel info-card epic itself was already delivered in v0.19.0; this is the About-tab enrichment follow-up + the header-shift fix. external_links stays empty by design (YouTube removed the field from the Data API ~2023).
This commit is contained in:
parent
fe387f06af
commit
45d16452f2
11 changed files with 141 additions and 6 deletions
23
backend/alembic/versions/0055_channel_keywords.py
Normal file
23
backend/alembic/versions/0055_channel_keywords.py
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
"""channels.keywords: creator keyword tags from brandingSettings (About tab)
|
||||
|
||||
Revision ID: 0055_channel_keywords
|
||||
Revises: 0054_audit_log
|
||||
Create Date: 2026-07-12
|
||||
"""
|
||||
from typing import Sequence, Union
|
||||
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
revision: str = "0055_channel_keywords"
|
||||
down_revision: Union[str, None] = "0054_audit_log"
|
||||
branch_labels: Union[str, Sequence[str], None] = None
|
||||
depends_on: Union[str, Sequence[str], None] = None
|
||||
|
||||
|
||||
def upgrade() -> None:
|
||||
op.add_column("channels", sa.Column("keywords", sa.Text(), nullable=True))
|
||||
|
||||
|
||||
def downgrade() -> None:
|
||||
op.drop_column("channels", "keywords")
|
||||
|
|
@ -180,6 +180,9 @@ class Channel(Base, TimestampMixin):
|
|||
topic_categories: Mapped[list | None] = mapped_column(JSON)
|
||||
default_language: Mapped[str | None] = mapped_column(String(16))
|
||||
country: Mapped[str | None] = mapped_column(String(8))
|
||||
# Creator keyword tags (brandingSettings.channel.keywords) — a single space-separated string,
|
||||
# multi-word tags quoted; the client parses it into chips for the About tab.
|
||||
keywords: Mapped[str | None] = mapped_column(Text)
|
||||
|
||||
# Sync bookkeeping.
|
||||
details_synced_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True))
|
||||
|
|
|
|||
|
|
@ -233,6 +233,9 @@ def _channel_detail_dict(
|
|||
"published_at": channel.published_at.isoformat() if channel.published_at else None,
|
||||
"external_links": channel.external_links or [],
|
||||
"country": channel.country,
|
||||
"default_language": channel.default_language,
|
||||
"topic_categories": channel.topic_categories or [],
|
||||
"keywords": channel.keywords,
|
||||
"subscribed": subscribed,
|
||||
"explored": explored,
|
||||
"blocked": blocked,
|
||||
|
|
|
|||
|
|
@ -69,6 +69,7 @@ def apply_channel_details(db: Session, items: list[dict]) -> None:
|
|||
channel.banner_url = branding.get("image", {}).get("bannerExternalUrl")
|
||||
channel.external_links = _external_links(branding)
|
||||
channel.topic_categories = topics.get("topicCategories")
|
||||
channel.keywords = branding.get("channel", {}).get("keywords")
|
||||
channel.details_synced_at = now
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue