UI fixes: modal scroll, Bewerbungen-Aktionen, E-Mail-Uhrzeit Berlin

- Modal „Bewerbung hinzufügen" lässt sich auf allen Bildschirmgrößen scrollen
  (nicht nur ≤640px), sonst war Speichern abgeschnitten
- Aktionen-Spalte der Bewerbungen von 4.5rem auf 5.5rem (passt zur
  Cluster-Breite, Icons wandern nicht mehr nach rechts)
- Merken-Stern im Compact-Modus ohne Rahmen
- E-Mail-Uhrzeiten in Postfach, Bewerbung und Reply-Quote in Europe/Berlin

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2026-07-20 08:02:37 +02:00
co-authored by Claude
parent 96fd0e282d
commit 1ba615fa80
6 changed files with 21 additions and 13 deletions
+17 -9
View File
@@ -454,18 +454,26 @@ button.loading::after {
/* Modals: the overlay locks body scroll (overflow:hidden on <body>), so a panel /* Modals: the overlay locks body scroll (overflow:hidden on <body>), so a panel
taller than the viewport would have its bottom cut off and unreachable. Cap taller than the viewport would have its bottom cut off and unreachable. Cap
the panel to the viewport and let it scroll internally; align the wrapper to the panel to the viewport and let it scroll internally; align the wrapper to
the top so the close button stays in reach instead of being clipped. */ the top so the close button stays in reach instead of being clipped. This
@media (max-width: 640px) { applies on every screen size — the Bewerbung-hinzufügen form has enough fields
.max-w-lg, (Datum bis Interne Notizen) to overflow even on a laptop, not just a phone. */
.max-w-md {
max-width: calc(100vw - 2rem) !important;
max-height: calc(100vh - 2rem) !important;
overflow-y: auto !important;
margin: 0 !important;
}
.fixed.inset-0 > .min-h-screen { .fixed.inset-0 > .min-h-screen {
align-items: flex-start !important; align-items: flex-start !important;
} }
.fixed.inset-0 > .min-h-screen > .max-w-lg,
.fixed.inset-0 > .min-h-screen > .max-w-md,
.fixed.inset-0 > .min-h-screen > .max-w-2xl,
.fixed.inset-0 > .min-h-screen > .max-w-3xl,
.fixed.inset-0 > .min-h-screen > .max-w-4xl {
max-height: calc(100vh - 2rem) !important;
overflow-y: auto !important;
}
@media (max-width: 640px) {
.fixed.inset-0 > .min-h-screen > .max-w-lg,
.fixed.inset-0 > .min-h-screen > .max-w-md {
max-width: calc(100vw - 2rem) !important;
margin: 0 !important;
}
} }
/* Dashboard application list: the desktop layout is a 7-column grid forced to /* Dashboard application list: the desktop layout is a 7-column grid forced to
+1 -1
View File
@@ -386,7 +386,7 @@ function emailPlainText(e) {
// followed by the original body with every line prefixed by "> ". // followed by the original body with every line prefixed by "> ".
function buildReplyQuote(e) { function buildReplyQuote(e) {
const d = e.email_date ? new Date(e.email_date) : null; const d = e.email_date ? new Date(e.email_date) : null;
const when = d && !isNaN(d.getTime()) ? d.toLocaleString('de-DE') : ''; const when = d && !isNaN(d.getTime()) ? d.toLocaleString('de-DE', { timeZone: 'Europe/Berlin' }) : '';
const who = String(e.from_addr || '').trim(); const who = String(e.from_addr || '').trim();
const src = emailPlainText(e).replace(/\r\n/g, '\n').replace(/\s+$/, ''); const src = emailPlainText(e).replace(/\r\n/g, '\n').replace(/\s+$/, '');
const quoted = src.split('\n').map((l) => '> ' + l).join('\n'); const quoted = src.split('\n').map((l) => '> ' + l).join('\n');
+1 -1
View File
@@ -472,7 +472,7 @@
<%= out ? ('An: ' + (e.to_addr || '')) : ('Von: ' + (e.from_addr || '')) %> <%= out ? ('An: ' + (e.to_addr || '')) : ('Von: ' + (e.from_addr || '')) %>
</span> </span>
</div> </div>
<span class="text-xs text-gray-500 dark:text-gray-400 shrink-0"><%= e.email_date ? new Date(e.email_date).toLocaleString('de-DE') : '' %></span> <span class="text-xs text-gray-500 dark:text-gray-400 shrink-0"><%= e.email_date ? new Date(e.email_date).toLocaleString('de-DE', { timeZone: 'Europe/Berlin' }) : '' %></span>
</div> </div>
<p class="text-sm font-medium text-gray-800 dark:text-gray-100 mb-1"><%= e.subject || '(kein Betreff)' %></p> <p class="text-sm font-medium text-gray-800 dark:text-gray-100 mb-1"><%= e.subject || '(kein Betreff)' %></p>
<% if (e.display_srcdoc) { %> <% if (e.display_srcdoc) { %>
+1 -1
View File
@@ -117,7 +117,7 @@
/* Shared column grid used by the header labels and every application line */ /* Shared column grid used by the header labels and every application line */
.app-grid { .app-grid {
display: grid; display: grid;
grid-template-columns: 1.25rem 5.5rem minmax(7rem, 1.6fr) minmax(8rem, 2fr) 5.5rem 8.5rem 4.5rem; grid-template-columns: 1.25rem 5.5rem minmax(7rem, 1.6fr) minmax(8rem, 2fr) 5.5rem 8.5rem 5.5rem;
gap: 0 0.75rem; gap: 0 0.75rem;
align-items: center; align-items: center;
} }
+1 -1
View File
@@ -14,7 +14,7 @@
: ('/jobangebote/' + encodeURIComponent(favId) + '/favorit'); : ('/jobangebote/' + encodeURIComponent(favId) + '/favorit');
var favCompact = !!(typeof compact !== 'undefined' && compact); var favCompact = !!(typeof compact !== 'undefined' && compact);
%> %>
<button type="button" class="fav-star<%= favAktiv ? ' is-fav' : '' %> inline-flex items-center justify-center gap-1.5 rounded-md border <%= favCompact ? 'p-1.5' : 'px-3 py-1.5' %> text-xs font-medium transition-colors" <button type="button" class="fav-star<%= favAktiv ? ' is-fav' : '' %> inline-flex items-center justify-center gap-1.5 rounded-md <%= favCompact ? 'p-1' : 'px-3 py-1.5 border' %> text-xs font-medium transition-colors"
data-favorit="<%= favId %>" data-aktiv="<%= favAktiv ? 1 : 0 %>" data-endpoint="<%= favEndpoint %>" data-favorit="<%= favId %>" data-aktiv="<%= favAktiv ? 1 : 0 %>" data-endpoint="<%= favEndpoint %>"
title="<%= favAktiv ? 'Favorit entfernen' : 'Als Favorit merken' %>" title="<%= favAktiv ? 'Favorit entfernen' : 'Als Favorit merken' %>"
aria-pressed="<%= favAktiv ? 'true' : 'false' %>"> aria-pressed="<%= favAktiv ? 'true' : 'false' %>">
+1 -1
View File
@@ -57,7 +57,7 @@
<span class="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-gray-600 text-white">Empfangen</span> <span class="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-gray-600 text-white">Empfangen</span>
<span class="text-sm text-gray-700 dark:text-gray-200 truncate">Von: <%= e.from_addr || '(unbekannt)' %></span> <span class="text-sm text-gray-700 dark:text-gray-200 truncate">Von: <%= e.from_addr || '(unbekannt)' %></span>
</div> </div>
<span class="text-xs text-gray-500 dark:text-gray-400 shrink-0"><%= e.email_date ? new Date(e.email_date).toLocaleString('de-DE') : '' %></span> <span class="text-xs text-gray-500 dark:text-gray-400 shrink-0"><%= e.email_date ? new Date(e.email_date).toLocaleString('de-DE', { timeZone: 'Europe/Berlin' }) : '' %></span>
</div> </div>
<p class="text-sm font-medium text-gray-800 dark:text-gray-100 mb-1"><%= e.subject || '(kein Betreff)' %></p> <p class="text-sm font-medium text-gray-800 dark:text-gray-100 mb-1"><%= e.subject || '(kein Betreff)' %></p>
<% if (e.display_srcdoc) { %> <% if (e.display_srcdoc) { %>