feat: rich command templates with public links + media text-first flow

- Command templates now match notification template style: type icons,
  linked filenames via album shared links, location, favorite status
- Media mode sends text message first, then media as reply (was media-only)
- Search/find/person/place resolve asset public URLs from tracked albums'
  shared links (share/{key}/photos/{id})
- Albums/summary commands include album public_url in context
- Enriched command template preview sample context with public_url, city,
  country, is_favorite
- Extract sanitizePreview to shared lib/sanitize.ts
- Command template preview now renders HTML links (was raw text)
- Global provider filter moved above search in sidebar
- CLAUDE.md: template consistency + context variable sync rules
This commit is contained in:
2026-03-24 16:48:57 +03:00
parent f90cc36ebd
commit d0bc767e98
26 changed files with 253 additions and 116 deletions
@@ -1,7 +1,7 @@
📚 Tracked albums:
{%- if albums %}
{%- for album in albums %}
• {{ album.name }} ({{ album.asset_count }} assets)
• {% if album.public_url %}<a href="{{ album.public_url }}">{{ album.name }}</a>{% else %}{{ album.name }}{% endif %} ({{ album.asset_count }} assets)
{%- endfor %}
{%- else %}
(none)
@@ -1,4 +1,5 @@
⭐ Favorites:
{%- for asset in assets %}
• {{ asset.originalFileName }}
• {%- if asset.type == "VIDEO" or asset.type == "video" %} 🎬{% else %} 🖼️{% endif %} {% if asset.public_url %}<a href="{{ asset.public_url }}">{{ asset.originalFileName }}</a>{% else %}{{ asset.originalFileName }}{% endif %} ❤️
{%- if asset.city %} 📍 {{ asset.city }}{% if asset.country %}, {{ asset.country }}{% endif %}{% endif %}
{%- endfor %}
@@ -1,4 +1,6 @@
📸 Latest:
{%- for asset in assets %}
• {{ asset.originalFileName }}{% if asset.year %} ({{ asset.year }}){% endif %}
• {%- if asset.type == "VIDEO" or asset.type == "video" %} 🎬{% else %} 🖼️{% endif %} {% if asset.public_url %}<a href="{{ asset.public_url }}">{{ asset.originalFileName }}</a>{% else %}{{ asset.originalFileName }}{% endif %}{% if asset.year %} ({{ asset.year }}){% endif %}
{%- if asset.city %} 📍 {{ asset.city }}{% if asset.country %}, {{ asset.country }}{% endif %}{% endif %}
{%- if asset.is_favorite %} ❤️{% endif %}
{%- endfor %}
@@ -1,4 +1,5 @@
📅 On this day:
{%- for asset in assets %}
• {{ asset.originalFileName }}{% if asset.year %} ({{ asset.year }}){% endif %}
• {%- if asset.type == "VIDEO" or asset.type == "video" %} 🎬{% else %} 🖼️{% endif %} {% if asset.public_url %}<a href="{{ asset.public_url }}">{{ asset.originalFileName }}</a>{% else %}{{ asset.originalFileName }}{% endif %}{% if asset.year %} ({{ asset.year }}){% endif %}
{%- if asset.city %} 📍 {{ asset.city }}{% if asset.country %}, {{ asset.country }}{% endif %}{% endif %}
{%- endfor %}
@@ -1,4 +1,6 @@
🎲 Random:
{%- for asset in assets %}
• {{ asset.originalFileName }}
• {%- if asset.type == "VIDEO" or asset.type == "video" %} 🎬{% else %} 🖼️{% endif %} {% if asset.public_url %}<a href="{{ asset.public_url }}">{{ asset.originalFileName }}</a>{% else %}{{ asset.originalFileName }}{% endif %}
{%- if asset.city %} 📍 {{ asset.city }}{% if asset.country %}, {{ asset.country }}{% endif %}{% endif %}
{%- if asset.is_favorite %} ❤️{% endif %}
{%- endfor %}
@@ -4,5 +4,7 @@
{%- else %}🔍 Results for "{{ query }}":
{%- endif %}
{%- for asset in assets %}
• {{ asset.originalFileName }}{% if asset.year %} ({{ asset.year }}){% endif %}
• {%- if asset.type == "VIDEO" or asset.type == "video" %} 🎬{% else %} 🖼️{% endif %} {% if asset.public_url %}<a href="{{ asset.public_url }}">{{ asset.originalFileName }}</a>{% else %}{{ asset.originalFileName }}{% endif %}{% if asset.year %} ({{ asset.year }}){% endif %}
{%- if asset.city %} 📍 {{ asset.city }}{% if asset.country %}, {{ asset.country }}{% endif %}{% endif %}
{%- if asset.is_favorite %} ❤️{% endif %}
{%- endfor %}
@@ -1,4 +1,4 @@
📋 Album summary ({{ albums | length }}):
{%- for album in albums %}
• {{ album.name }}: {{ album.asset_count }} assets
• {% if album.public_url %}<a href="{{ album.public_url }}">{{ album.name }}</a>{% else %}{{ album.name }}{% endif %}: {{ album.asset_count }} assets
{%- endfor %}
@@ -1,7 +1,7 @@
📚 Отслеживаемые альбомы:
{%- if albums %}
{%- for album in albums %}
• {{ album.name }} ({{ album.asset_count }} файлов)
• {% if album.public_url %}<a href="{{ album.public_url }}">{{ album.name }}</a>{% else %}{{ album.name }}{% endif %} ({{ album.asset_count }} файлов)
{%- endfor %}
{%- else %}
(нет)
@@ -1,4 +1,5 @@
⭐ Избранное:
{%- for asset in assets %}
• {{ asset.originalFileName }}
• {%- if asset.type == "VIDEO" or asset.type == "video" %} 🎬{% else %} 🖼️{% endif %} {% if asset.public_url %}<a href="{{ asset.public_url }}">{{ asset.originalFileName }}</a>{% else %}{{ asset.originalFileName }}{% endif %} ❤️
{%- if asset.city %} 📍 {{ asset.city }}{% if asset.country %}, {{ asset.country }}{% endif %}{% endif %}
{%- endfor %}
@@ -1,4 +1,6 @@
📸 Последние:
{%- for asset in assets %}
• {{ asset.originalFileName }}{% if asset.year %} ({{ asset.year }}){% endif %}
• {%- if asset.type == "VIDEO" or asset.type == "video" %} 🎬{% else %} 🖼️{% endif %} {% if asset.public_url %}<a href="{{ asset.public_url }}">{{ asset.originalFileName }}</a>{% else %}{{ asset.originalFileName }}{% endif %}{% if asset.year %} ({{ asset.year }}){% endif %}
{%- if asset.city %} 📍 {{ asset.city }}{% if asset.country %}, {{ asset.country }}{% endif %}{% endif %}
{%- if asset.is_favorite %} ❤️{% endif %}
{%- endfor %}
@@ -1,4 +1,5 @@
📅 В этот день:
{%- for asset in assets %}
• {{ asset.originalFileName }}{% if asset.year %} ({{ asset.year }}){% endif %}
• {%- if asset.type == "VIDEO" or asset.type == "video" %} 🎬{% else %} 🖼️{% endif %} {% if asset.public_url %}<a href="{{ asset.public_url }}">{{ asset.originalFileName }}</a>{% else %}{{ asset.originalFileName }}{% endif %}{% if asset.year %} ({{ asset.year }}){% endif %}
{%- if asset.city %} 📍 {{ asset.city }}{% if asset.country %}, {{ asset.country }}{% endif %}{% endif %}
{%- endfor %}
@@ -1,4 +1,6 @@
🎲 Случайные:
{%- for asset in assets %}
• {{ asset.originalFileName }}
• {%- if asset.type == "VIDEO" or asset.type == "video" %} 🎬{% else %} 🖼️{% endif %} {% if asset.public_url %}<a href="{{ asset.public_url }}">{{ asset.originalFileName }}</a>{% else %}{{ asset.originalFileName }}{% endif %}
{%- if asset.city %} 📍 {{ asset.city }}{% if asset.country %}, {{ asset.country }}{% endif %}{% endif %}
{%- if asset.is_favorite %} ❤️{% endif %}
{%- endfor %}
@@ -1,8 +1,10 @@
{%- if command == "find" %}📄 Файлы по запросу "{{ query }}":
{%- elif command == "person" %}👤 Фото {{ query }}:
{%- elif command == "place" %}📍 Фото из {{ query }}:
{%- else %}🔍 Результаты для "{{ query }}":
{%- else %}🔍 Результаты по "{{ query }}":
{%- endif %}
{%- for asset in assets %}
• {{ asset.originalFileName }}{% if asset.year %} ({{ asset.year }}){% endif %}
• {%- if asset.type == "VIDEO" or asset.type == "video" %} 🎬{% else %} 🖼️{% endif %} {% if asset.public_url %}<a href="{{ asset.public_url }}">{{ asset.originalFileName }}</a>{% else %}{{ asset.originalFileName }}{% endif %}{% if asset.year %} ({{ asset.year }}){% endif %}
{%- if asset.city %} 📍 {{ asset.city }}{% if asset.country %}, {{ asset.country }}{% endif %}{% endif %}
{%- if asset.is_favorite %} ❤️{% endif %}
{%- endfor %}
@@ -1,4 +1,4 @@
📋 Сводка альбомов ({{ albums | length }}):
{%- for album in albums %}
• {{ album.name }}: {{ album.asset_count }} файлов
• {% if album.public_url %}<a href="{{ album.public_url }}">{{ album.name }}</a>{% else %}{{ album.name }}{% endif %}: {{ album.asset_count }} файлов
{%- endfor %}