{% from "_macros.html" import cover %} {# Portfolio card list fragment (ARG-154). Rendered inside portfolio.html for both the "새 신호 있음" (active) and "조용함" (quiet) sections. Shares the cover() macro with the feed so the favicon-chip / og-image / glyph branch stays identical (a bare favicon is never stretched across the cover). #}
{% for asset in items %} {% set cat = (asset.category.value if asset.category else 'none')|lower %} {% set replace_successor = handoff_banners.get(asset.id) if handoff_banners is defined else None %}
{% if replace_successor %} {# Replace successor exists (ARG-209 AC1/AC3): a card-top handoff banner, computed eagerly by `app.py::_load_handoff_banners` (bounded to assets with lineage_count > 0) so it's visible without expanding the timeline. Empty 200 + outerHTML on the whole card removes the (now-Archived) predecessor from this Keep-only list, mirroring Untrack's contract. #}

🔁 {{ replace_successor.title }}이(가) 이 기술을 대체합니다

{% endif %} {# Card taps open the in-app reader (ARG-138) keyed on the tech_item id; "원문 보기" on the detail page handles the external source_url redirect. #} {# transition_id = the tech item, so this cover morphs into the item page's hero exactly like a feed card's does. #} {{ cover(asset.image_url, asset.category, "/item/" ~ asset.tech_id, asset.source_url, transition_id=asset.tech_id) }}

{% if asset.category %} {{ asset.category.value }} {% endif %} {{ asset.source_url | domain }} {% if asset.signal_count > 0 %}🔭 {{ asset.signal_count }}{% endif %} {% if asset.lineage_count > 0 %}🧬 {{ asset.lineage_count }}{% endif %}

{{ asset.title }}

Keep {{ asset.kept_since.strftime('%Y-%m-%d') }} {% if asset.last_signal_at %} · 마지막 신호 {{ asset.last_signal_at.strftime('%Y-%m-%d') }} {% endif %}

{# Tapping toggles the timeline open/closed; portfolio-timeline.js fetches GET /portfolio/{asset.id}/timeline on first open and just clears the container (no re-fetch) on the retap that closes it. #} {# Untrack archives the asset; the route returns an empty body so this outerHTML swap removes the card from the Keep-only portfolio. #}
{% endfor %}