Quelltext des aktuellen Standes
<?php
$this->layout('layouts/main', [
'page_title' => 'Adressbuch',
'breadcrumbs' => [],
'full_width' => true,
'current_route' => 'contacts',
'extra_css' => ['/assets/css/contacts.css?v=' . filemtime(dirname(__DIR__, 2) . '/public/assets/css/contacts.css')],
'extra_js' => ['/assets/js/contacts.js?v=' . filemtime(dirname(__DIR__, 2) . '/public/assets/js/contacts.js')],
]);
$companies = $companies ?? [];
$contacts = $contacts ?? [];
$search = $search ?? '';
$canManage = $can_manage ?? false;
$viewMode = $view_mode ?? 'cards';
$page = $page ?? 1;
$totalPages = $total_pages ?? 1;
$totalComp = $total_companies ?? count($companies);
$sort = $sort ?? 'name';
$dir = $dir ?? 'asc';
$csrfToken = $this->csrf();
$view = $this;
// Baut einen Link unter Beibehaltung von Suche und Sortierung
$pageUrl = function (int $p) use ($search, $sort, $dir): string {
$params = ['page' => $p];
if ($search !== '') {
$params['q'] = $search;
}
if ($sort !== 'name') {
$params['sort'] = $sort;
}
if ($dir !== 'asc') {
$params['dir'] = $dir;
}
return '/contacts?' . http_build_query($params);
};
$sortOptions = ['name' => 'Name', 'contacts' => 'Anzahl Kontakte', 'created' => 'Neueste zuerst'];
?>
<div class="cb-fullwidth">
<div class="content-header">
<div>
<h1><?= $this->te('Adressbuch') ?></h1>
<ol class="breadcrumb">
<li class="breadcrumb-item"><a href="/"><?= $this->te('Home') ?></a></li>
<li class="breadcrumb-item active"><?= $this->te('Adressbuch') ?></li>
</ol>
</div>
<div class="content-header-actions">
<div class="cb-view-toggle" id="cbViewToggle" role="group" aria-label="<?= $this->te('Ansicht wählen') ?>">
<button type="button" class="cb-view-btn <?= $viewMode === 'cards' ? 'active' : '' ?>"
data-mode="cards" title="<?= $this->te('Kartenansicht') ?>" aria-label="<?= $this->te('Kartenansicht') ?>"
aria-pressed="<?= $viewMode === 'cards' ? 'true' : 'false' ?>">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="16" height="16" aria-hidden="true" focusable="false">
<rect x="3" y="3" width="7" height="7"/><rect x="14" y="3" width="7" height="7"/>
<rect x="3" y="14" width="7" height="7"/><rect x="14" y="14" width="7" height="7"/>
</svg>
</button>
<button type="button" class="cb-view-btn <?= $viewMode === 'list' ? 'active' : '' ?>"
data-mode="list" title="<?= $this->te('Listenansicht') ?>" aria-label="<?= $this->te('Listenansicht') ?>"
aria-pressed="<?= $viewMode === 'list' ? 'true' : 'false' ?>">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="16" height="16" aria-hidden="true" focusable="false">
<line x1="8" y1="6" x2="21" y2="6"/><line x1="8" y1="12" x2="21" y2="12"/>
<line x1="8" y1="18" x2="21" y2="18"/>
<line x1="3" y1="6" x2="3.01" y2="6"/><line x1="3" y1="12" x2="3.01" y2="12"/>
<line x1="3" y1="18" x2="3.01" y2="18"/>
</svg>
</button>
</div>
<?php if ($canManage): ?>
<button type="button" class="btn btn-default" data-modal-open="importModal" title="<?= $this->te('Kontakte importieren') ?>"><?= $this->te('Import') ?></button>
<a href="/contacts/trash" class="btn btn-default" title="<?= $this->te('Papierkorb') ?>"><?= $this->te('Papierkorb') ?></a>
<button type="button" class="btn btn-primary" data-modal-open="newCompanyModal">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="18" height="18" aria-hidden="true" focusable="false"><line x1="12" y1="5" x2="12" y2="19"/><line x1="5" y1="12" x2="19" y2="12"/></svg>
<?= $this->te('Neue Firma') ?>
</button>
<?php endif; ?>
</div>
</div>
<!-- Suchleiste -->
<div class="card card-outline card-primary" style="margin: 1.25rem 1rem;">
<div class="filter-card-body">
<form method="GET" action="/contacts" class="cb-search-form" role="search">
<div class="cb-search-field">
<svg class="cb-search-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="15" height="15" aria-hidden="true" focusable="false"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>
<label for="cb-search" class="sr-only"><?= $this->te('Firma oder Person suchen') ?></label>
<input id="cb-search" type="search" name="q" class="form-control cb-search-input" placeholder="<?= $this->te('Firma oder Person suchen…') ?>" value="<?= $view->e($search) ?>" autocomplete="off">
</div>
<button type="submit" class="btn btn-default"><?= $this->te('Suchen') ?></button>
<?php if ($search !== ''): ?>
<a href="/contacts" class="btn btn-default">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="13" height="13" aria-hidden="true" focusable="false"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg>
<?= $this->te('Zurücksetzen') ?>
</a>
<?php endif; ?>
<span class="cb-sort-spacer"></span>
<label for="cb-sort" class="sr-only"><?= $this->te('Sortieren nach') ?></label>
<select id="cb-sort" name="sort" class="form-control cb-inline-select" data-autosubmit>
<?php foreach ($sortOptions as $val => $label): ?>
<option value="<?= $val ?>"<?= $sort === $val ? ' selected' : '' ?>><?= $label ?></option>
<?php endforeach; ?>
</select>
<select name="dir" class="form-control cb-inline-select" data-autosubmit aria-label="<?= $this->te('Reihenfolge') ?>">
<option value="asc"<?= $dir === 'asc' ? ' selected' : '' ?>><?= $this->te('Aufsteigend') ?></option>
<option value="desc"<?= $dir === 'desc' ? ' selected' : '' ?>><?= $this->te('Absteigend') ?></option>
</select>
</form>
</div>
</div>
<!-- Suchergebnisse: Personen -->
<?php if ($search !== '' && !empty($contacts)): ?>
<div class="cb-content">
<h2 class="cb-section-title"><?= $this->t('Personen') ?> (<?= count($contacts) ?>)</h2>
<div class="cb-contacts-grid">
<?php foreach ($contacts as $contact):
$personName = trim(($contact['last_name'] ?? '') . ', ' . ($contact['first_name'] ?? ''));
?>
<a href="/contacts/companies/<?= (int)$contact['company_id'] ?>" class="cb-person-card">
<?php if (!empty($contact['image_path'])): ?>
<img src="<?= $view->e($contact['image_path']) ?>" alt="<?= $this->te('Foto von {name}', ['name' => $personName]) ?>" class="cb-person-avatar-img">
<?php else: ?>
<span class="cb-person-avatar" aria-hidden="true">
<?= $view->e(strtoupper(mb_substr($contact['first_name'] ?? '?', 0, 1))) ?><?= $view->e(strtoupper(mb_substr($contact['last_name'] ?? '?', 0, 1))) ?>
</span>
<?php endif; ?>
<div class="cb-person-info">
<div class="cb-person-name"><?= $view->e($personName) ?></div>
<?php if (!empty($contact['position'])): ?>
<div class="cb-person-position"><?= $view->e($contact['position']) ?></div>
<?php endif; ?>
<div class="cb-person-company"><?= $view->e($contact['company_name'] ?? '') ?></div>
</div>
<div class="cb-person-contacts">
<?php if (!empty($contact['phone'])): ?>
<span class="cb-person-detail">📞 <?= $view->e($contact['phone']) ?></span>
<?php endif; ?>
<?php if (!empty($contact['email'])): ?>
<span class="cb-person-detail">✉ <?= $view->e($contact['email']) ?></span>
<?php endif; ?>
</div>
</a>
<?php endforeach; ?>
</div>
</div>
<?php endif; ?>
<!-- Firmen-Liste -->
<div class="cb-content">
<?php if ($search !== ''): ?>
<h2 class="cb-section-title"><?= $this->t('Firmen') ?> (<?= (int)$totalComp ?>)</h2>
<?php endif; ?>
<?php if ($search !== '' && empty($companies) && empty($contacts)): ?>
<div class="cb-empty-state">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" width="48" height="48" aria-hidden="true" focusable="false"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>
<p><?= $this->t('Keine Ergebnisse für „{suche}“ gefunden', ['suche' => $view->e($search)]) ?></p>
<a href="/contacts" class="cb-btn cb-btn-secondary"><?= $this->te('Alle Firmen anzeigen') ?></a>
</div>
<?php elseif ($search === '' && empty($companies)): ?>
<div class="cb-empty-state">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" width="48" height="48" aria-hidden="true" focusable="false"><path d="M3 21h18"/><path d="M5 21V7l8-4v18"/><path d="M19 21V11l-6-4"/><path d="M9 9h1"/><path d="M9 13h1"/><path d="M9 17h1"/></svg>
<p><?= $this->te('Noch keine Firmen vorhanden') ?></p>
<?php if ($canManage): ?>
<button type="button" class="cb-btn cb-btn-primary" data-modal-open="newCompanyModal"><?= $this->te('Erste Firma anlegen') ?></button>
<?php endif; ?>
</div>
<?php elseif (!empty($companies)): ?>
<!-- KARTENANSICHT -->
<div class="cb-grid <?= $viewMode === 'list' ? 'cb-hidden' : '' ?>" id="cbCardsView">
<?php foreach ($companies as $company): ?>
<a href="/contacts/companies/<?= (int)$company['id'] ?>" class="cb-card">
<div class="cb-card-header">
<?php if (!empty($company['image_path'])): ?>
<img src="<?= $view->e($company['image_path']) ?>" alt="<?= $this->te('Logo von {firma}', ['firma' => $company['name'] ?? '']) ?>" class="cb-card-avatar-img">
<?php else: ?>
<span class="cb-card-avatar" style="background: <?= $view->e($company['color'] ?? 'var(--color-primary)') ?>" aria-hidden="true">
<?= $view->e(strtoupper(mb_substr($company['name'] ?? '', 0, 1))) ?>
</span>
<?php endif; ?>
<div class="cb-card-title">
<div class="cb-card-name"><?= $view->e($company['name'] ?? '') ?></div>
<?php if (!empty($company['customer_number'])): ?>
<div class="cb-card-custnr"><?= $this->te('Kd-Nr: {nummer}', ['nummer' => $company['customer_number']]) ?></div>
<?php endif; ?>
<?php if (!empty($company['address'])): ?>
<div class="cb-card-address">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="13" height="13" aria-hidden="true" focusable="false"><path d="M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0 1 18 0z"/><circle cx="12" cy="10" r="3"/></svg>
<span><?= $view->e($company['address']) ?></span>
</div>
<?php endif; ?>
</div>
</div>
<div class="cb-card-details">
<?php if (!empty($company['phone'])): ?>
<span class="cb-card-detail">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="14" height="14" aria-hidden="true" focusable="false"><path d="M22 16.92v3a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-3.07 19.5 19.5 0 0 1-6-6 19.79 19.79 0 0 1-3.07-8.67A2 2 0 0 1 4.11 2h3a2 2 0 0 1 2 1.72c.127.96.361 1.903.7 2.81a2 2 0 0 1-.45 2.11L8.09 9.91a16 16 0 0 0 6 6l1.27-1.27a2 2 0 0 1 2.11-.45c.907.339 1.85.573 2.81.7A2 2 0 0 1 22 16.92z"/></svg>
<span><?= $view->e($company['phone']) ?></span>
</span>
<?php endif; ?>
<?php if (!empty($company['email'])): ?>
<span class="cb-card-detail">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="14" height="14" aria-hidden="true" focusable="false"><path d="M4 4h16c1.1 0 2 .9 2 2v12c0 1.1-.9 2-2 2H4c-1.1 0-2-.9-2-2V6c0-1.1.9-2 2-2z"/><polyline points="22,6 12,13 2,6"/></svg>
<span><?= $view->e($company['email']) ?></span>
</span>
<?php endif; ?>
</div>
<div class="cb-card-footer">
<span class="cb-card-contacts-badge">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="14" height="14" aria-hidden="true" focusable="false"><path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/><path d="M23 21v-2a4 4 0 0 0-3-3.87"/><path d="M16 3.13a4 4 0 0 1 0 7.75"/></svg>
<?= (int)($company['contact_count'] ?? 0) ?> Kontakt<?= ((int)($company['contact_count'] ?? 0)) !== 1 ? 'e' : '' ?>
</span>
<span class="cb-card-arrow">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="16" height="16" aria-hidden="true" focusable="false"><polyline points="9 18 15 12 9 6"/></svg>
</span>
</div>
</a>
<?php endforeach; ?>
</div>
<!-- LISTENANSICHT -->
<div class="cb-list-view <?= $viewMode !== 'list' ? 'cb-hidden' : '' ?>" id="cbListView">
<?php foreach ($companies as $company):
$contactCount = (int)($company['contact_count'] ?? 0);
$phone = trim((string)($company['phone'] ?? ''));
$email = trim((string)($company['email'] ?? ''));
$address = trim((string)($company['address'] ?? ''));
?>
<a href="/contacts/companies/<?= (int)$company['id'] ?>" class="cb-list-item">
<div class="cb-list-avatar">
<?php if (!empty($company['image_path'])): ?>
<img src="<?= $view->e($company['image_path']) ?>" alt="<?= $this->te('Logo von {firma}', ['firma' => $company['name'] ?? '']) ?>" class="cb-list-avatar-img">
<?php else: ?>
<span class="cb-list-avatar-initials" style="background: <?= $view->e($company['color'] ?? 'var(--color-primary)') ?>" aria-hidden="true">
<?= $view->e(strtoupper(mb_substr($company['name'] ?? '', 0, 1))) ?>
</span>
<?php endif; ?>
</div>
<div class="cb-list-main">
<span class="cb-list-name"><?= $view->e($company['name'] ?? '') ?></span>
<?php if (!empty($company['customer_number'])): ?>
<span class="cb-list-custnr"><?= $this->te('Kd-Nr: {nummer}', ['nummer' => $company['customer_number']]) ?></span>
<?php endif; ?>
</div>
<span class="cb-list-cell<?= $phone === '' ? ' cb-list-cell-empty' : '' ?>">
<svg class="cb-list-cell-ico" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="14" height="14" aria-hidden="true" focusable="false"><path d="M22 16.92v3a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-3.07 19.5 19.5 0 0 1-6-6 19.79 19.79 0 0 1-3.07-8.67A2 2 0 0 1 4.11 2h3a2 2 0 0 1 2 1.72c.127.96.361 1.903.7 2.81a2 2 0 0 1-.45 2.11L8.09 9.91a16 16 0 0 0 6 6l1.27-1.27a2 2 0 0 1 2.11-.45c.907.339 1.85.573 2.81.7A2 2 0 0 1 22 16.92z"/></svg>
<span class="cb-list-cell-val"><?= $phone !== '' ? $view->e($phone) : '–' ?></span>
</span>
<span class="cb-list-cell<?= $email === '' ? ' cb-list-cell-empty' : '' ?>">
<svg class="cb-list-cell-ico" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="14" height="14" aria-hidden="true" focusable="false"><path d="M4 4h16c1.1 0 2 .9 2 2v12c0 1.1-.9 2-2 2H4c-1.1 0-2-.9-2-2V6c0-1.1.9-2 2-2z"/><polyline points="22,6 12,13 2,6"/></svg>
<span class="cb-list-cell-val"><?= $email !== '' ? $view->e($email) : '–' ?></span>
</span>
<span class="cb-list-cell cb-list-cell-addr<?= $address === '' ? ' cb-list-cell-empty' : '' ?>">
<svg class="cb-list-cell-ico" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="14" height="14" aria-hidden="true" focusable="false"><path d="M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0 1 18 0z"/><circle cx="12" cy="10" r="3"/></svg>
<span class="cb-list-cell-val"><?= $address !== '' ? $view->e($address) : '–' ?></span>
</span>
<div class="cb-list-badge">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="13" height="13" aria-hidden="true" focusable="false"><path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/><path d="M23 21v-2a4 4 0 0 0-3-3.87"/><path d="M16 3.13a4 4 0 0 1 0 7.75"/></svg>
<?= $contactCount ?> Kontakt<?= $contactCount !== 1 ? 'e' : '' ?>
</div>
<span class="cb-list-arrow">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="14" height="14" aria-hidden="true" focusable="false"><polyline points="9 18 15 12 9 6"/></svg>
</span>
</a>
<?php endforeach; ?>
</div>
<!-- Pagination -->
<?php if ($totalPages > 1): ?>
<nav class="cb-pagination" aria-label="<?= $this->te('Seitennavigation') ?>">
<?php if ($page > 1): ?>
<a class="cb-page-link" href="<?= $view->e($pageUrl($page - 1)) ?>" rel="prev" aria-label="<?= $this->te('Vorherige Seite') ?>">«</a>
<?php endif; ?>
<?php
$start = max(1, $page - 2);
$end = min($totalPages, $page + 2);
if ($start > 1): ?>
<a class="cb-page-link" href="<?= $view->e($pageUrl(1)) ?>">1</a>
<?php if ($start > 2): ?><span class="cb-page-ellipsis">…</span><?php endif; ?>
<?php endif; ?>
<?php for ($p = $start; $p <= $end; $p++): ?>
<?php if ($p === $page): ?>
<span class="cb-page-link cb-page-current" aria-current="page"><?= $p ?></span>
<?php else: ?>
<a class="cb-page-link" href="<?= $view->e($pageUrl($p)) ?>"><?= $p ?></a>
<?php endif; ?>
<?php endfor; ?>
<?php if ($end < $totalPages): ?>
<?php if ($end < $totalPages - 1): ?><span class="cb-page-ellipsis">…</span><?php endif; ?>
<a class="cb-page-link" href="<?= $view->e($pageUrl($totalPages)) ?>"><?= $totalPages ?></a>
<?php endif; ?>
<?php if ($page < $totalPages): ?>
<a class="cb-page-link" href="<?= $view->e($pageUrl($page + 1)) ?>" rel="next" aria-label="<?= $this->te('Nächste Seite') ?>">»</a>
<?php endif; ?>
</nav>
<div class="cb-page-info"><?= $this->te('Seite {seite} von {gesamt} · {firmen} Firmen', ['seite' => (int)$page, 'gesamt' => (int)$totalPages, 'firmen' => (int)$totalComp]) ?></div>
<?php endif; ?>
<?php endif; ?>
</div>
</div>
<?php if ($canManage): ?>
<!-- Modal: Neue Firma -->
<div id="newCompanyModal" class="cb-modal" role="dialog" aria-modal="true" aria-labelledby="newCompanyModalTitle" hidden>
<div class="cb-modal-backdrop" data-close></div>
<div class="cb-modal-dialog">
<div class="cb-modal-header">
<h2 id="newCompanyModalTitle"><?= $this->te('Neue Firma anlegen') ?></h2>
<button type="button" class="cb-modal-close" data-close aria-label="<?= $this->te('Dialog schließen') ?>">×</button>
</div>
<form method="POST" action="/contacts/companies" enctype="multipart/form-data">
<input type="hidden" name="_csrf" value="<?= $view->e($csrfToken) ?>">
<div class="cb-modal-body">
<div class="cb-form-group">
<label for="cb-company-image"><?= $this->te('Firmenlogo') ?></label>
<input type="file" id="cb-company-image" name="image" class="cb-input" accept="image/jpeg,image/png,image/gif,image/webp">
</div>
<div class="cb-form-row">
<div class="cb-form-group">
<label for="cb-company-name"><?= $this->te('Name *') ?></label>
<input type="text" id="cb-company-name" name="name" class="cb-input" placeholder="<?= $this->te('z.B. Muster GmbH') ?>" required>
</div>
<div class="cb-form-group">
<label for="cb-company-custnr"><?= $this->te('Kundennummer') ?></label>
<input type="text" id="cb-company-custnr" name="customer_number" class="cb-input" placeholder="<?= $this->te('z.B. KD-12345') ?>">
</div>
</div>
<div class="cb-form-group">
<label for="cb-company-address"><?= $this->te('Adresse') ?></label>
<textarea id="cb-company-address" name="address" class="cb-input cb-textarea" rows="2" placeholder="<?= $this->te('Straße, PLZ Ort') ?>"></textarea>
</div>
<div class="cb-form-row">
<div class="cb-form-group">
<label for="cb-company-phone"><?= $this->te('Telefon') ?></label>
<input type="text" id="cb-company-phone" name="phone" class="cb-input" placeholder="+49 ...">
</div>
<div class="cb-form-group">
<label for="cb-company-email"><?= $this->t('E-Mail') ?></label>
<input type="email" id="cb-company-email" name="email" class="cb-input" placeholder="<?= $this->te('info@firma.de') ?>">
</div>
</div>
<div class="cb-form-group">
<label for="cb-company-website"><?= $this->te('Website') ?></label>
<input type="url" id="cb-company-website" name="website" class="cb-input" placeholder="https://www.firma.de">
</div>
<?= $view->render('contacts/_channel_fields', ['channels' => []]) ?>
<div class="cb-form-group">
<label for="cb-company-notes"><?= $this->te('Notizen') ?></label>
<textarea id="cb-company-notes" name="notes" class="cb-input cb-textarea" rows="3" placeholder="<?= $this->te('Interne Anmerkungen...') ?>"></textarea>
</div>
</div>
<div class="cb-modal-footer">
<button type="button" class="cb-btn cb-btn-secondary" data-close><?= $this->te('Abbrechen') ?></button>
<button type="submit" class="cb-btn cb-btn-primary"><?= $this->te('Firma erstellen') ?></button>
</div>
</form>
</div>
</div>
<div id="importModal" class="cb-modal" role="dialog" aria-modal="true" aria-labelledby="importModalTitle" hidden>
<div class="cb-modal-backdrop" data-close></div>
<div class="cb-modal-dialog">
<div class="cb-modal-header">
<h2 id="importModalTitle"><?= $this->te('Kontakte importieren') ?></h2>
<button type="button" class="cb-modal-close" data-close aria-label="<?= $this->te('Dialog schließen') ?>">×</button>
</div>
<form action="/contacts/import" method="POST" enctype="multipart/form-data">
<input type="hidden" name="_csrf" value="<?= $view->e($csrfToken) ?>">
<div class="cb-modal-body">
<div class="cb-form-group">
<label for="cb-import-file"><?= $this->te('CSV- oder vCard-Datei') ?></label>
<input type="file" id="cb-import-file" name="file" class="cb-input" accept=".csv,.vcf,.vcard,text/csv,text/vcard" required>
</div>
<p class="cb-import-hint">
<?= $this->t('<strong>CSV:</strong> Erste Zeile als Kopfzeile mit Spalten wie <code>Vorname;Nachname;Position;Firma;Telefon;Mobil;E-Mail;Notizen</code> (Semikolon- oder Komma-getrennt). Das Format entspricht dem CSV-Export.<br> <strong>vCard (.vcf):</strong> Standard-vCards werden erkannt; <code>ORG</code> wird als Firma übernommen.<br> Existierende Firmen werden anhand des Namens wiederverwendet, fehlende neu angelegt. Kontakte ohne Firma landen unter „Unzugeordnet“.') ?>
</p>
</div>
<div class="cb-modal-footer">
<button type="button" class="cb-btn cb-btn-secondary" data-close><?= $this->te('Abbrechen') ?></button>
<button type="submit" class="cb-btn cb-btn-primary"><?= $this->te('Importieren') ?></button>
</div>
</form>
</div>
</div>
<?php endif; ?>