"""Entity profile HTML component.""" from __future__ import annotations from ui import assets from world.events import get_interactions_for_entity from world.locations import get_location_by_id from world.relationships import get_relationships_enriched from ui.avatars import render_avatar REL_LABELS = { "allied": "Allied", "friends": "Friends", "rivals": "Rivals", "enemies": "Enemies", "mentor": "Mentor", "owes_debt": "Owes a debt", } TYPE_LABELS = { "character": "Character", "creature": "Creature", "object": "Object", "place": "Place", } STATUS_LABELS = { "active": "Active", "dormant": "Dormant", "legendary": "Legendary", } def render_entity_card(entity: dict) -> str: location = get_location_by_id(entity["location_id"]) loc_name = location["name"].replace("The ", "") if location else "Unknown" type_label = TYPE_LABELS.get(entity["type"], entity["type"].title()) status = STATUS_LABELS.get(entity["status"], entity["status"].title()) status_class = f"status-{entity['status']}" traits_html = "".join( f'{t}' for t in entity["personality_traits"] ) tags_html = "" if entity.get("tags"): tags_html = "".join( f'{t}' for t in entity["tags"] ) secret_html = "" if entity.get("secret_name"): secret_html = f"""
Secret Name (only the Sea knows)

{entity['secret_name']}

""" memory = entity["memory_summary"] or "Nothing yet — they just arrived." rel_count = entity.get("relationship_count", 0) int_count = entity.get("interaction_count", 0) rels = get_relationships_enriched(entity["id"]) rel_html = "" if rels: items = [] for r in rels[:8]: label = REL_LABELS.get(r["relationship_type"], r["relationship_type"].title()) items.append( f'
  • ' f'{r["partner_name"]} ' f'{label} ' f'{"●" * r["strength"]}' f'

    {r["description"]}

  • ' ) rel_html = f"""
    Bonds in the Realm
    """ encounters = get_interactions_for_entity(entity["id"], limit=5) enc_html = "" if encounters: enc_items = [] for ix in encounters: other = ( ix["entity_b_name"] if ix["entity_a_id"] == entity["id"] else ix["entity_a_name"] ) loc = (ix.get("location_name") or "").replace("The ", "") enc_items.append( f'
  • ' f'Day {ix["world_day"]} ' f'Met {other} at {loc} — ' f'{ix.get("book_of_ages_entry") or ix["description"][:100]}
  • ' ) enc_html = f"""
    Encounters Remembered
    """ slug = location["slug"] if location else None avatar = render_avatar(entity, size=96, location_slug=slug) loc_img = assets.location_image_url(slug) banner_style = f"background-image: url('{loc_img}');" if loc_img else "" return f"""
    {avatar}
    {type_label} ▸ {loc_name} Day {entity['days_in_realm']} · {status}

    {entity['name']}

    {f'
    {tags_html}
    ' if tags_html else ''}
    {entity['appearance']}
    {traits_html}

    {entity['primary_goal']}

    {entity['secondary_goal']}

    {entity['primary_fear']}

    "{entity['greeting']}"
    {secret_html}

    {memory}

    {rel_html} {enc_html}
    """ def render_entity_hologram(entity: dict | None) -> str: """3D-styled entity detail panel for the Souls spread right page.""" if not entity: return """

    Select a soul on the left leaf to unveil their story.

    """ location = get_location_by_id(entity["location_id"]) loc_name = location["name"].replace("The ", "") if location else "Unknown" slug = location["slug"] if location else None avatar = render_avatar(entity, size=72, location_slug=slug) loc_img = assets.location_image_url(slug) banner = f"background-image:url('{loc_img}');" if loc_img else "" type_label = TYPE_LABELS.get(entity["type"], entity["type"].title()) status = STATUS_LABELS.get(entity["status"], entity["status"].title()) return f"""
    {avatar}

    {type_label} · {loc_name} · Day {entity['days_in_realm']} · {status}

    {entity['display_name']}

    {entity['appearance']}

    Seeks {entity['primary_goal']}

    Fears {entity['primary_fear']}

    "{entity['greeting']}"

    {entity['memory_summary'] or 'They have only just arrived.'}

    """ def render_entity_grid(entities: list[dict]) -> str: if not entities: return '
    The Realm waits for its first arrivals.
    ' cards = [] for entity in entities: location = get_location_by_id(entity["location_id"]) loc_short = location["name"].replace("The ", "")[:20] if location else "?" status_class = f"grid-status-{entity['status']}" slug = location["slug"] if location else None avatar = render_avatar(entity, size=48, location_slug=slug) cards.append(f"""
    {avatar}
    {entity['type']}

    {entity['display_name']}

    {loc_short}

    {entity['appearance'][:120]}{'…' if len(entity['appearance']) > 120 else ''}

    Day {entity['days_in_realm']} · {entity['status']}
    """) return f'
    {"".join(cards)}
    '