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

@@ -25,6 +25,7 @@ import {
import { inboxApi, type InboxBarcode, type InboxFile, type PostprocessActionResult } from '../api/inbox';
import { paperlessApi } from '../api/paperless';
import { userSettingsApi, type SenderOption } from '../api/userSettings';
import { useIsMobile } from '../hooks/useIsMobile';
const ZOOM_MIN = 0.5;
const ZOOM_MAX = 3;
@@ -113,6 +114,7 @@ function CompareModal({
onCreateNewVersion,
onSkip,
}: CompareModalProps) {
const compareIsMobile = useIsMobile();
const [paperlessUrl, setPaperlessUrl] = useState<string | null>(null);
const [inboxUrl, setInboxUrl] = useState<string | null>(null);
const [loading, setLoading] = useState(false);
@@ -165,8 +167,8 @@ function CompareModal({
</Button>,
]}
>
<div style={{ display: 'flex', gap: 12, height: '75vh' }}>
<div style={{ flex: 1, display: 'flex', flexDirection: 'column', minWidth: 0 }}>
<div style={{ display: 'flex', flexDirection: compareIsMobile ? 'column' : 'row', gap: 12, height: '75vh' }}>
<div style={{ flex: 1, display: 'flex', flexDirection: 'column', minWidth: 0, minHeight: 0 }}>
<Typography.Text strong style={{ marginBottom: 4 }}>
Original (Paperless)
</Typography.Text>
@@ -180,7 +182,7 @@ function CompareModal({
)}
</div>
</div>
<div style={{ flex: 1, display: 'flex', flexDirection: 'column', minWidth: 0 }}>
<div style={{ flex: 1, display: 'flex', flexDirection: 'column', minWidth: 0, minHeight: 0 }}>
<Typography.Text strong style={{ marginBottom: 4 }}>
Aktueller Abschnitt (Inbox)
</Typography.Text>
@@ -858,6 +860,7 @@ function SendEmailDialog({ open, fileId, fileName, documents, thumbUrls, onClose
export default function InboxDetailPage() {
const { id } = useParams<{ id: string }>();
const navigate = useNavigate();
const isMobile = useIsMobile();
const [file, setFile] = useState<InboxFile | null>(null);
const [loading, setLoading] = useState(true);
const [thumbUrls, setThumbUrls] = useState<Map<number, string>>(new Map());
@@ -1211,13 +1214,13 @@ export default function InboxDetailPage() {
})();
return (
<div style={{ display: 'flex', flexDirection: 'column', height: 'calc(100vh - 120px)' }}>
<div style={{ display: 'flex', alignItems: 'center', marginBottom: 12, gap: 12 }}>
<Space>
<div style={{ display: 'flex', flexDirection: 'column', height: isMobile ? 'calc(100dvh - 180px)' : 'calc(100vh - 120px)' }}>
<div style={{ display: 'flex', alignItems: 'center', flexWrap: 'wrap', rowGap: 8, marginBottom: 12, gap: 12 }}>
<Space wrap>
<Button icon={<ArrowLeftOutlined />} onClick={() => navigate('/inbox')}>
Zurück
</Button>
<Title level={3} style={{ margin: 0 }}>
<Title level={isMobile ? 5 : 3} style={{ margin: 0, maxWidth: isMobile ? 180 : undefined }} ellipsis={{ tooltip: file.name }}>
{file.name}
</Title>
<SourceTag source={file.source} />
@@ -1399,12 +1402,13 @@ export default function InboxDetailPage() {
>
<div
style={{
width: 140,
width: isMobile ? 84 : 140,
overflowY: 'auto',
padding: 6,
background: '#fafafa',
border: '1px solid #f0f0f0',
borderRadius: 8,
flexShrink: 0,
}}
>
{sidebarPages.map((n, idx) => {
@@ -1428,7 +1432,7 @@ export default function InboxDetailPage() {
<div
style={{
width: '100%',
height: 170,
height: isMobile ? 100 : 170,
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
@@ -1439,7 +1443,7 @@ export default function InboxDetailPage() {
<img
src={url}
alt={`Seite ${docPage}`}
style={thumbImageStyle(rotationFor(n), 130)}
style={thumbImageStyle(rotationFor(n), isMobile ? 72 : 130)}
/>
) : (
<Spin size="small" />