Files
icloud-contacts-sync/src/api/templates/contact.html
T

454 lines
14 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!-- Copyright (c) 2026 Stefan Koelle (https://stefankoelle.de) -->
<!-- Licensed under the MIT License. See LICENSE file in project root for details. -->
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="icon" type="image/svg+xml" href="/static/favicon.svg">
<title>{{ contact.full_name or 'Kontakt' }} Kontakte</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
background: #f5f5f5;
color: #333;
line-height: 1.6;
overflow-y: scroll;
}
.container {
max-width: 800px;
margin: 0 auto;
padding: 2rem 1rem;
}
h1 {
font-size: 1.5rem;
margin-bottom: 0.5rem;
color: #222;
}
.back-link {
display: inline-flex;
align-items: center;
gap: 0.5rem;
color: #0066cc;
text-decoration: none;
font-size: 0.875rem;
margin-bottom: 1.5rem;
}
.back-link:hover {
text-decoration: underline;
}
.contact-card {
background: #fff;
border-radius: 8px;
padding: 1rem 1.25rem;
box-shadow: 0 1px 3px rgba(0,0,0,0.1);
}
.custom-links-box {
position: fixed;
top: 136px;
right: 2rem;
width: 280px;
background: #fff;
border-radius: 8px;
padding: 1rem 1.25rem;
box-shadow: 0 1px 3px rgba(0,0,0,0.1);
max-height: calc(100vh - 4rem);
overflow-y: auto;
}
.quicklink-item {
display: block;
padding: 0.75rem;
background: #f8f9fa;
border-radius: 6px;
color: #0066cc;
text-decoration: none;
font-size: 0.875rem;
transition: background 0.15s ease;
}
.quicklink-item:hover {
background: #e7f3ff;
text-decoration: underline;
}
.contact-header {
display: flex;
justify-content: space-between;
align-items: flex-start;
gap: 1rem;
margin-bottom: 1.5rem;
padding-bottom: 1.5rem;
border-bottom: 1px solid #eee;
}
.contact-photo {
width: 160px;
height: 160px;
border-radius: 50%;
object-fit: cover;
flex-shrink: 0;
}
.contact-name {
font-size: 1.5rem;
font-weight: 600;
color: #222;
}
.contact-subtitle {
font-size: 0.875rem;
color: #666;
margin-top: 0.25rem;
}
.badge {
display: inline-block;
padding: 0.1rem 0.4rem;
border-radius: 3px;
font-size: 0.6rem;
font-weight: 400;
text-transform: none;
letter-spacing: 0;
white-space: nowrap;
color: #888;
background: #f0f0f0;
}
.section {
margin-bottom: 1.5rem;
}
.section:last-child {
margin-bottom: 0;
}
.section-title {
font-size: 0.75rem;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.5px;
color: #888;
margin-bottom: 0.75rem;
}
.section-list {
display: flex;
flex-direction: column;
gap: 0.5rem;
}
.section-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 0.75rem;
background: #f8f9fa;
border-radius: 6px;
}
.section-item-label {
font-size: 0.75rem;
color: #888;
text-transform: capitalize;
}
.section-item-value {
font-size: 0.875rem;
color: #333;
}
.section-item-value a {
color: #0066cc;
text-decoration: none;
}
.section-item-value a:hover {
text-decoration: underline;
}
.tiles-grid {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 0.5rem;
}
.tile {
padding: 0.75rem;
background: #f8f9fa;
border-radius: 6px;
}
.tile-label {
font-size: 0.7rem;
color: #888;
text-transform: capitalize;
margin-bottom: 0.25rem;
line-height: 1.3;
}
.tile-value {
font-size: 0.875rem;
color: #333;
word-break: break-word;
}
.tile-value a {
color: #0066cc;
text-decoration: none;
}
.tile-value a:hover {
text-decoration: underline;
}
.birthday-highlight {
display: inline-flex;
align-items: center;
gap: 0.5rem;
padding: 0.75rem;
background: #fff3cd;
border-radius: 6px;
font-size: 0.875rem;
color: #856404;
}
.notes-content {
padding: 0.75rem;
background: #f8f9fa;
border-radius: 6px;
font-size: 0.875rem;
color: #333;
white-space: pre-wrap;
}
.tags {
display: flex;
flex-wrap: wrap;
gap: 0.5rem;
}
.tag {
display: inline-block;
padding: 0.25rem 0.75rem;
background: #e7f3ff;
color: #0066cc;
border-radius: 20px;
font-size: 0.8rem;
}
.no-data {
color: #888;
font-style: italic;
font-size: 0.875rem;
}
.photo-dialog {
border: none;
border-radius: 12px;
padding: 10px;
max-width: 90vw;
max-height: 90vh;
background: transparent;
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
.photo-dialog::backdrop {
background: rgba(0, 0, 0, 0.85);
}
.photo-dialog img {
display: block;
max-width: 90vw;
max-height: 85vh;
border-radius: 8px;
object-fit: contain;
}
.contact-photo {
cursor: pointer;
transition: transform 0.15s ease;
}
.contact-photo:hover {
transform: scale(1.03);
}
@media (max-width: 600px) {
.tiles-grid {
grid-template-columns: 1fr;
}
}
@media (max-width: 1450px) {
.custom-links-box {
display: none;
}
}
</style>
</head>
<body>
<div class="container">
<h1><a href="/" style="text-decoration:none;color:inherit;display:inline-flex;align-items:center;gap:0.4rem"><img src="/static/favicon.svg" alt="" style="height:1.5em;width:1.5em;vertical-align:middle">Kontakte</a></h1>
<a href="/search{% if search %}?search={{ search }}{% endif %}" class="back-link">← Zurück zur Liste</a>
<div class="contact-card">
<div class="contact-header">
<div>
<div class="contact-name">{{ contact.full_name or '(Kein Name)' }}</div>
{% if contact.organization or contact.job_title %}
<div class="contact-subtitle">
{% if contact.job_title %}{{ contact.job_title }}{% endif %}
{% if contact.job_title and contact.organization %} bei {% endif %}
{% if contact.organization %}{{ contact.organization }}{% endif %}
</div>
{% endif %}
</div>
<div style="display:flex;flex-direction:column;align-items:center;gap:0.3rem">
{% if contact.photo_url %}
<img src="{{ contact.photo_url }}" alt="Foto" class="contact-photo" onerror="this.style.display='none'" onclick="document.getElementById('photo-dialog').showModal()">
{% endif %}
{% if show_all and contact.account %}
<span class="badge">Account: {{ contact.account }}</span>
{% endif %}
</div>
</div>
{% if contact.birthday %}
<div class="section">
<div class="birthday-highlight">
🎂 {{ contact.birthday }}
</div>
</div>
{% endif %}
{% if contact.emails %}
<div class="section">
<div class="section-title">E-Mail</div>
<div class="tiles-grid">
{% for email in contact.emails %}
<div class="tile">
<div class="tile-label">{{ email.type }}</div>
<div class="tile-value"><a href="mailto:{{ email.value }}">{{ email.value }}</a></div>
</div>
{% endfor %}
</div>
</div>
{% endif %}
{% if contact.phones %}
<div class="section">
<div class="section-title">Telefon</div>
<div class="tiles-grid">
{% for phone in contact.phones %}
<div class="tile">
<div class="tile-label">{{ phone.type }}</div>
<div class="tile-value"><a href="tel:{{ phone.value }}">{{ phone.value }}</a></div>
</div>
{% endfor %}
</div>
</div>
{% endif %}
{% if contact.addresses %}
<div class="section">
<div class="section-title">Adresse</div>
<div class="tiles-grid">
{% for addr in contact.addresses %}
<div class="tile">
<div class="tile-label">{{ addr.type }}</div>
<div class="tile-value">
{{ addr.street }}<br>
{% if addr.zip %}{{ addr.zip }} {% endif %}{{ addr.city }}<br>
{{ addr.region }}{% if addr.region and addr.country %}, {% endif %}{{ addr.country }}
</div>
</div>
{% endfor %}
</div>
</div>
{% endif %}
{% if contact.urls %}
<div class="section">
<div class="section-title">Website</div>
<div class="tiles-grid">
{% for url in contact.urls %}
<div class="tile">
<div class="tile-label">{{ url.type }}</div>
<div class="tile-value"><a href="{{ url.value }}" target="_blank">{{ url.value }}</a></div>
</div>
{% endfor %}
</div>
</div>
{% endif %}
{% if contact.social_profiles %}
<div class="section">
<div class="section-title">Soziale Profile</div>
<div class="tiles-grid">
{% for sp in contact.social_profiles %}
<div class="tile">
<div class="tile-label">{{ sp.type }}{% if sp.username %} ({{ sp.username }}){% endif %}</div>
<div class="tile-value"><a href="{{ sp.url }}" target="_blank">{{ sp.url }}</a></div>
</div>
{% endfor %}
</div>
</div>
{% endif %}
{% if contact.categories %}
<div class="section">
<div class="section-title">Kategorien</div>
<div class="tags">
{% for cat in contact.categories %}
<span class="tag">{{ cat }}</span>
{% endfor %}
</div>
</div>
{% endif %}
{% if contact.notes %}
<div class="section">
<div class="section-title">Notizen</div>
<div class="notes-content">{{ contact.notes }}</div>
</div>
{% endif %}
</div>
{% if custom_links %}
<div class="custom-links-box">
<div class="section-title">Schnelllinks</div>
<div class="section-list">
{% for link in custom_links %}
<a href="{{ link.url }}" target="_blank" class="quicklink-item">
{{ link.label }}
</a>
{% endfor %}
</div>
</div>
{% endif %}
</div>
{% if contact.photo_url %}
<dialog id="photo-dialog" class="photo-dialog" onclick="if(event.target===this)this.close()">
<img src="{{ contact.photo_url }}" alt="Foto" onerror="this.parentElement.close()">
</dialog>
{% endif %}
</body>
</html>