feat: add mobile-responsive layout and card views across all pages
Build and Push Multi-Platform Images / build-and-push (push) Successful in 39s

- New useIsMobile hook and MobileCardList component
- AppLayout: hamburger menu + Drawer navigation on mobile
- All list pages (Inbox, Posteingang, Manuell, Mail, Freigabe, Zahlung, TaskLog)
  show card layout on mobile instead of tables
- CSS: responsive modal height, horizontal table scroll, text-size-adjust
- Backend: Agrarmonitor polling fixes, Zahlung service improvements,
  IMAP folder service extended, misc controller fixes

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
bjoernpoettkerandClaude Sonnet 4.6 committed 2026-07-14 09:22:58 +02:00
1 parent 0765d14d3b
commit 7076eef57b
28 files changed
+1081 -462

No files matched your search

@@ -10,12 +10,14 @@ import { emailsApi, type EmailItem, type EmailAttachment } from '../api/emails';
import { emailImportApi } from '../api/email-import';
import { getEnv } from '../utils/env';
import MailImportWizard from '../components/MailImportWizard';
import { useIsMobile } from '../hooks/useIsMobile';
const { Title, Text } = Typography;
export default function MailDetailPage() {
const { id } = useParams<{ id: string }>();
const navigate = useNavigate();
const isMobile = useIsMobile();
const [email, setEmail] = useState<EmailItem | null>(null);
const [attachments, setAttachments] = useState<EmailAttachment[]>([]);
const [selected, setSelected] = useState<EmailAttachment | null>(null);
@@ -136,16 +138,16 @@ export default function MailDetailPage() {
return (
<div>
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 16 }}>
<Space>
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', flexWrap: 'wrap', gap: 8, marginBottom: 16 }}>
<Space wrap>
<Button icon={<ArrowLeftOutlined />} onClick={() => navigate('/mailpostfach')}>
Zurück
</Button>
<Title level={3} style={{ margin: 0 }}>{email.Subject}</Title>
<Title level={isMobile ? 5 : 3} style={{ margin: 0 }}>{email.Subject}</Title>
{hasErechnung && <Tag color="green">eRechnung</Tag>}
</Space>
<Space>
<Space wrap>
<Popconfirm
title="E-Mail ignorieren"
description="Möchten Sie diese E-Mail wirklich als ignoriert markieren?"
@@ -183,12 +185,26 @@ export default function MailDetailPage() {
</Space>
</div>
<div style={{ display: 'grid', gridTemplateColumns: '2fr 3fr', gap: 16, height: 'calc(100vh - 140px)' }}>
<div
style={{
display: 'grid',
gridTemplateColumns: isMobile ? '1fr' : '2fr 3fr',
gap: 16,
height: isMobile ? 'auto' : 'calc(100vh - 140px)',
}}
>
{/* Linke Seite: E-Mail-Inhalt */}
<Card
title="E-Mail"
size="small"
styles={{ body: { overflow: 'auto', height: 'calc(100vh - 200px)', display: 'flex', flexDirection: 'column' } }}
styles={{
body: {
overflow: 'auto',
height: isMobile ? 'auto' : 'calc(100vh - 200px)',
display: 'flex',
flexDirection: 'column',
},
}}
>
<div style={{ marginBottom: 12 }}>
<div><Text type="secondary">Von:</Text> <Text>{email.SenderAddress}</Text></div>
@@ -208,7 +224,17 @@ export default function MailDetailPage() {
</Card>
{/* Rechte Seite: Anhänge + Vorschau */}
<Card size="small" styles={{ body: { padding: 0, display: 'flex', flexDirection: 'column', height: 'calc(100vh - 200px)' } }}>
<Card
size="small"
styles={{
body: {
padding: 0,
display: 'flex',
flexDirection: 'column',
height: isMobile ? 'auto' : 'calc(100vh - 200px)',
},
}}
>
<div style={{ flex: '0 0 auto', borderBottom: `1px solid ${token.colorBorder}`, maxHeight: 240, overflow: 'auto' }}>
<Table<EmailAttachment>
columns={columns}
@@ -224,7 +250,7 @@ export default function MailDetailPage() {
locale={{ emptyText: <Empty description="Keine Anhänge" image={Empty.PRESENTED_IMAGE_SIMPLE} /> }}
/>
</div>
<div style={{ flex: 1, minHeight: 0, background: token.colorBgLayout }}>
<div style={isMobile ? { height: '60vh', background: token.colorBgLayout } : { flex: 1, minHeight: 0, background: token.colorBgLayout }}>
{previewLoading ? (
<div style={{ display: 'flex', justifyContent: 'center', alignItems: 'center', height: '100%' }}>
<Spin />