This commit is contained in:
seb
2026-10-05 01:01:03 +02:00
parent 81b59fd309
commit b766769634
59 changed files with 903 additions and 280 deletions

View File

@@ -32,6 +32,9 @@ import { artikelDetailPath } from '../components/article/articleRoute';
import withSearchParams from '../components/article/withSearchParams';
import { setLastArticleSku } from '../automats';
import { BrandLabel } from '../components/brand';
import {
BLUE_BG,
} from '../colors';
const resultRowSx = {
alignItems: 'center',
@@ -276,7 +279,6 @@ class ArtikelSearchPage extends Component {
onChange={this.handleInputChange}
slotProps={{
htmlInput: {
spellCheck: false,
autoCapitalize: 'off',
autoCorrect: 'off',
},
@@ -373,7 +375,7 @@ class ArtikelSearchPage extends Component {
measureElement={
<Box
sx={{
bgcolor: '#dbeafe',
bgcolor: BLUE_BG,
p: 2,
borderRadius: 1,
textAlign: 'center',

View File

@@ -498,7 +498,10 @@ class ArtikelKategorienPage extends PureComponent {
}}
variant="standard"
size="small"
slotProps={{ inputLabel: { shrink: true }, input: { spellCheck: false } }}
slotProps={{
inputLabel: { shrink: true },
htmlInput: { spellCheck: false },
}}
sx={{
width: '100%',
'& .MuiInput-underline:before, & .MuiInput-underline:after': {

View File

@@ -21,6 +21,9 @@ import { backendErrorFrom } from '../../utils/backendError';
import { notifyError } from '../../utils/notify';
import { setLastArticleSku } from '../../automats';
import warehouseAutomat from '../../automats/warehouseAutomat';
import {
GREEN_PANEL,
} from '../../colors';
function draftsFrom(warehouses) {
return Object.fromEntries(warehouses.map((row) => [row.id, row.name]));
@@ -285,15 +288,9 @@ class ArtikelLagerPage extends PureComponent {
return (
<>
{/* SortableJS ghost / chosen styling */}
<style>{`
.sortable-ghost { opacity: 0.35 !important; }
.sortable-chosen { box-shadow: 0 4px 16px rgba(0,0,0,0.12); }
.drag-handle { cursor: grab; touch-action: none; }
.drag-handle:active { cursor: grabbing; }
`}</style>
<PanelTileGrid>
<PanelTile wide={2} minHeight={280} color="#bbf7d0">
<PanelTile wide={2} minHeight={280} color={GREEN_PANEL}>
<Stack spacing={2}>
{returnTo ? (
<Alert

View File

@@ -19,6 +19,9 @@ import { setLastArticleSku } from '../../automats';
import brandAutomat from '../../automats/brandAutomat';
import { enqueueSnackbar } from 'notistack';
import { BrandThumb, BrandImageSearchDialog } from '../../components/brand';
import {
PURPLE_PANEL,
} from '../../colors';
function draftsFrom(brands) {
return Object.fromEntries(brands.map((b) => [b.id, b.name]));
@@ -180,7 +183,7 @@ class ArtikelMarkenPage extends PureComponent {
return (
<PanelTileGrid>
<PanelTile wide={2} minHeight={280} color="#ddd6fe">
<PanelTile wide={2} minHeight={280} color={PURPLE_PANEL}>
<List dense disablePadding>
{brands.length === 0 ? (
<Typography variant="body2" color="text.secondary" sx={{ py: 1 }}>

View File

@@ -24,6 +24,15 @@ import { notifyError } from '../../utils/notify';
import { setLastArticleSku } from '../../automats';
import attributeAutomat, { selectAttributes } from '../../automats/attributeAutomat';
import propertyAutomat, { selectProperties } from '../../automats/propertyAutomat';
import {
BLUE_PANEL,
ORANGE_PANEL,
PURPLE_PANEL,
SELECT_BG,
SELECT_BG_HOVER,
SELECT_BORDER,
TINT_SUBTLE,
} from '../../colors';
function draftsFrom(items, key = 'name') {
return Object.fromEntries((items || []).map((row) => [row.id, row[key]]));
@@ -609,16 +618,10 @@ class ArtikelMerkmalePage extends PureComponent {
return (
<>
{/* SortableJS ghost / chosen styling from /artikel/lager */}
<style>{`
.sortable-ghost { opacity: 0.35 !important; }
.sortable-chosen { box-shadow: 0 4px 16px rgba(0,0,0,0.12); }
.drag-handle { cursor: grab; touch-action: none; }
.drag-handle:active { cursor: grabbing; }
`}</style>
<PanelTileGrid>
{/* Tile 1: Attribute (Auswahllisten) */}
<PanelTile wide={2} minHeight={280} color="#bfdbfe">
<PanelTile wide={2} minHeight={280} color={BLUE_PANEL}>
<Stack spacing={2}>
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1 }}>
<StyleIcon sx={{ color: 'text.secondary', fontSize: 20 }} />
@@ -642,11 +645,11 @@ class ArtikelMerkmalePage extends PureComponent {
borderRadius: 1.5,
alignItems: 'center',
cursor: 'pointer',
bgcolor: isSelected ? 'rgba(59, 130, 246, 0.12)' : 'transparent',
border: isSelected ? '1px solid rgba(59, 130, 246, 0.3)' : '1px solid transparent',
bgcolor: isSelected ? SELECT_BG : 'transparent',
border: isSelected ? `1px solid ${SELECT_BORDER}` : '1px solid transparent',
transition: 'all 0.15s ease',
'&:hover': {
bgcolor: isSelected ? 'rgba(59, 130, 246, 0.16)' : 'rgba(0, 0, 0, 0.04)',
bgcolor: isSelected ? SELECT_BG_HOVER : TINT_SUBTLE,
},
}}
data-id={a.id}
@@ -764,7 +767,7 @@ class ArtikelMerkmalePage extends PureComponent {
</PanelTile>
{/* Tile 2: Werte für das gewählte Attribut */}
<PanelTile wide={2} minHeight={280} color="#ddd6fe">
<PanelTile wide={2} minHeight={280} color={PURPLE_PANEL}>
<Stack spacing={2}>
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1 }}>
<LabelImportantIcon sx={{ color: 'text.secondary', fontSize: 20 }} />
@@ -867,7 +870,7 @@ class ArtikelMerkmalePage extends PureComponent {
</PanelTile>
{/* Tile 3: Merkmale (Freitext) */}
<PanelTile wide={2} minHeight={280} color="#fed7aa">
<PanelTile wide={2} minHeight={280} color={ORANGE_PANEL}>
<Stack spacing={2}>
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1 }}>
<TuneIcon sx={{ color: 'text.secondary', fontSize: 20 }} />

View File

@@ -25,6 +25,10 @@ import { notifyError } from '../../utils/notify';
import { setLastArticleSku } from '../../automats';
import { labeltemplate } from '../../api';
import { enqueueSnackbar } from 'notistack';
import {
BLUE_BG,
SURFACE_BASE,
} from '../../colors';
const CanvasEditor = lazy(async () => {
await import('react-canvas-label-editor/style.css');
@@ -465,7 +469,7 @@ class ArtikelVorlagenPage extends PureComponent {
return (
<>
<PanelTileGrid>
<PanelTile wide={3} color="#dbeafe">
<PanelTile wide={3} color={BLUE_BG}>
<Box sx={{ display: 'flex', alignItems: 'center', justifyContent: 'flex-end', mb: 2 }}>
<Button
variant="contained"
@@ -517,7 +521,7 @@ class ArtikelVorlagenPage extends PureComponent {
onClick={() => this.handleOpenEdit(tmpl)}
sx={{
height: 100,
bgcolor: '#f8f8f8',
bgcolor: SURFACE_BASE,
display: 'flex',
alignItems: 'center',
justifyContent: 'center',

View File

@@ -8,6 +8,9 @@ import { PanelTile } from 'dashgui/panels';
import { AutomatGrid } from 'react-virtual-aggridautomat';
import { articleHistoryGridAutomat } from '../../automats';
import { router } from '../../appRouter';
import {
LINK,
} from '../../colors';
const COLUMN_DEFS = [
{
@@ -43,7 +46,7 @@ const COLUMN_DEFS = [
e.preventDefault();
void router.navigate(`/artikel/${encodeURIComponent(p.value)}`);
}}
style={{ color: '#2563eb', fontWeight: 600, textDecoration: 'none' }}
style={{ color: LINK, fontWeight: 600, textDecoration: 'none' }}
>
{p.value}
</a>

View File

@@ -8,6 +8,9 @@ import customergroupAutomat from '../automats/customergroupAutomat';
import { router } from '../appRouter';
import { backendErrorFrom } from '../utils/backendError';
import { notifyError } from '../utils/notify';
import {
BLUE_PANEL,
} from '../colors';
function sortEntities(entities) {
return [...entities].sort((a, b) => {
@@ -142,7 +145,7 @@ class KundeListePage extends PureComponent {
onDelete={this.handleDelete}
deleteDisabled={busyId != null}
emptyMessage="Noch keine Kunden."
color="#bfdbfe"
color={BLUE_PANEL}
getEditLabel={(row) => `„${label(row)}“ bearbeiten`}
getDeleteLabel={(row) => `„${label(row)}“ löschen`}
/>

View File

@@ -18,6 +18,11 @@ import { requireArray, requireDefined, requireObject } from '../../utils/apiShap
import { backendErrorFrom } from '../../utils/backendError';
import { notifyError } from '../../utils/notify';
import withEntityRoute from '../../components/kunde/withEntityRoute';
import {
BLUE_PANEL,
GREEN_PANEL,
YELLOW_PANEL,
} from '../../colors';
const ADDRESS_FIELDS = [
'addressType',
@@ -551,7 +556,7 @@ class KundeEditPage extends PureComponent {
return (
<PanelTileGrid>
<PanelTile wide={2} minHeight={200} color="#bfdbfe" title="Stammdaten">
<PanelTile wide={2} minHeight={200} color={BLUE_PANEL} title="Stammdaten">
<Stack spacing={2}>
{groupName != null ? (
<Typography variant="body2" color="text.secondary">
@@ -586,7 +591,7 @@ class KundeEditPage extends PureComponent {
</Stack>
</PanelTile>
<PanelTile wide={3} minHeight={240} color="#bbf7d0" title="Adressen">
<PanelTile wide={3} minHeight={240} color={GREEN_PANEL} title="Adressen">
<Stack spacing={2}>
{addresses.length === 0 ? (
<Typography variant="body2" color="text.secondary">
@@ -656,7 +661,7 @@ class KundeEditPage extends PureComponent {
</Stack>
</PanelTile>
<PanelTile wide={3} minHeight={200} color="#fde68a" title="Kontakte">
<PanelTile wide={3} minHeight={200} color={YELLOW_PANEL} title="Kontakte">
<Stack spacing={2}>
{contacts.length === 0 ? (
<Typography variant="body2" color="text.secondary">

View File

@@ -20,6 +20,9 @@ import customergroupAutomat from '../../automats/customergroupAutomat';
import { requireArray, requireDefined, requireObject } from '../../utils/apiShape';
import { backendErrorFrom } from '../../utils/backendError';
import { notifyError } from '../../utils/notify';
import {
PURPLE_BG,
} from '../../colors';
function sortGroups(groups) {
return [...groups].sort((a, b) => {
@@ -231,7 +234,7 @@ class KundeGruppenPage extends PureComponent {
return (
<PanelTileGrid>
<PanelTile wide={2} minHeight={280} color="#e9d5ff">
<PanelTile wide={2} minHeight={280} color={PURPLE_BG}>
<Stack spacing={2}>
<List dense disablePadding>
{groups.length === 0 ? (

View File

@@ -14,6 +14,9 @@ import customergroupAutomat from '../../automats/customergroupAutomat';
import { router } from '../../appRouter';
import { requireDefined, requireObject } from '../../utils/apiShape';
import { notifyError } from '../../utils/notify';
import {
BLUE_PANEL,
} from '../../colors';
class KundeNeuPage extends PureComponent {
constructor(props) {
@@ -95,7 +98,7 @@ class KundeNeuPage extends PureComponent {
return (
<PanelTileGrid>
<PanelTile wide={2} minHeight={220} color="#bfdbfe" title="Neuer Kunde">
<PanelTile wide={2} minHeight={220} color={BLUE_PANEL} title="Neuer Kunde">
<Stack spacing={2}>
<TextField
size="small"
@@ -103,7 +106,7 @@ class KundeNeuPage extends PureComponent {
value={number}
disabled
slotProps={{
htmlInput: { spellCheck: false, autoComplete: 'off' },
htmlInput: { autoComplete: 'off' },
}}
/>
<Select
@@ -112,9 +115,8 @@ class KundeNeuPage extends PureComponent {
disabled={saving}
onChange={this.handleGroupChange}
displayEmpty
inputProps={{
spellCheck: false,
autoComplete: 'off',
slotProps={{
htmlInput: { autoComplete: 'off' },
}}
>
{groups.map((row) => (

View File

@@ -21,6 +21,9 @@ import { notifyError } from '../../utils/notify';
import { setLastDeliveryPath } from '../../automats';
import supplierAutomat from '../../automats/supplierAutomat';
import { deliveryDraftAutomat } from '../../automats/deliveryEditorAutomat';
import {
GREEN_PANEL,
} from '../../colors';
function sortSuppliers(suppliers) {
@@ -224,7 +227,7 @@ class LieferungLieferantenPage extends PureComponent {
return (
<PanelTileGrid>
<PanelTile wide={2} minHeight={280} color="#bbf7d0">
<PanelTile wide={2} minHeight={280} color={GREEN_PANEL}>
<Stack spacing={2}>
{returnTo ? (
<Alert

View File

@@ -50,6 +50,11 @@ import { getDeliveryEditorAutomat } from '../../automats/deliveryEditorAutomat';
import { setLastDeliveryPath, userSettingsAutomat, setViewerPosition } from '../../automats';
import { fetchDeliveryLedgerSummary } from '../../utils/deliveryLedger';
import {
SURFACE_BASE,
SURFACE_RAISED,
YELLOW_BG,
} from '../../colors';
class LieferungNeuPage extends PureComponent {
constructor(props) {
@@ -1266,7 +1271,7 @@ class LieferungNeuPage extends PureComponent {
/>
{this.state.viewerPosition === 'top' && this.renderViewerPanels(4)}
{this.state.unmatchedSupplierName && (
<PanelTile wide={4} color="#fef3c7" sx={{ gridColumn: { xs: '1 / -1', sm: '1 / -1', md: 'span 4' } }}>
<PanelTile wide={4} color={YELLOW_BG} sx={{ gridColumn: { xs: '1 / -1', sm: '1 / -1', md: 'span 4' } }}>
<Alert
severity="warning"
action={
@@ -1316,7 +1321,7 @@ class LieferungNeuPage extends PureComponent {
{this.state.viewerPosition === 'below' && this.renderViewerPanels(4)}
{this.props.docId != null && this.renderLedgerPanel()}
{notes && notes.length > 0 && (
<PanelTile wide={4} color="#fffbeb" sx={{ gridColumn: { xs: '1 / -1', sm: '1 / -1', md: 'span 4' } }}>
<PanelTile wide={4} color={YELLOW_BG} sx={{ gridColumn: { xs: '1 / -1', sm: '1 / -1', md: 'span 4' } }}>
<Typography variant="subtitle2" fontWeight={700} color="warning.dark" sx={{ mb: 1.5 }}>
Hinweise zur PDF-Analyse ({notes.length})
</Typography>
@@ -1401,7 +1406,7 @@ class LieferungNeuPage extends PureComponent {
<PanelTile
wide={4}
title="Lagerstatus (Ledger)"
color="#f8fafc"
color={SURFACE_BASE}
sx={{
gridColumn: { xs: '1 / -1', sm: '1 / -1', md: 'span 4' },
border: '1px solid',
@@ -1519,7 +1524,7 @@ class LieferungNeuPage extends PureComponent {
</Typography>
<TableContainer component={Paper} variant="outlined">
<Table size="small">
<TableHead sx={{ bgcolor: '#f1f5f9' }}>
<TableHead sx={{ bgcolor: SURFACE_RAISED }}>
<TableRow>
<TableCell sx={{ fontWeight: 600, py: 0.5 }}>Zeitpunkt</TableCell>
<TableCell sx={{ fontWeight: 600, py: 0.5 }}>Typ</TableCell>