"""card_grid UI component for navi_ui."""
from __future__ import annotations
from pydantic import BaseModel, Field, field_validator
from .base import UIComponent
def _validate_url(value: str | None) -> str | None:
"""Reject values that are clearly not HTTP/HTTPS URLs."""
if value is None:
return value
value = value.strip()
if not value.startswith(("http://", "https://")):
raise ValueError("must be a valid http:// or https:// URL")
return value
class CardMeta(BaseModel):
label: str
value: str
class CardDetail(BaseModel):
label: str
value: str
class CardAction(BaseModel):
label: str
url: str
@field_validator("url", mode="before")
@classmethod
def _check_url(cls, value: str | None) -> str | None:
return _validate_url(value)
class CardGridCard(BaseModel):
id: str = Field(..., min_length=1)
title: str = Field(..., min_length=1)
subtitle: str | None = None
image: str | None = None
meta: list[CardMeta] = Field(default_factory=list)
description: str | None = None
details: list[CardDetail] = Field(default_factory=list)
actions: list[CardAction] = Field(default_factory=list)
@field_validator("image", mode="before")
@classmethod
def _check_image_url(cls, value: str | None) -> str | None:
return _validate_url(value)
class CardGridPayload(BaseModel):
title: str | None = None
cards: list[CardGridCard] = Field(..., min_length=1, max_length=8)
class CardGrid(UIComponent):
"""Render a flat, borderless grid of up to 4 cards with optional details modal."""
name = "card_grid"
description = "A compact grid of cards. Use for search results, listings, or summaries."
schema = CardGridPayload