This commit is contained in:
seb
2026-10-11 14:24:30 +02:00
parent 31467f106a
commit 95523ce9f3
4 changed files with 86 additions and 80 deletions

View File

@@ -7,7 +7,7 @@ import CategoryIcon from '@mui/icons-material/Category';
import HistoryIcon from '@mui/icons-material/History';
import LabelIcon from '@mui/icons-material/Label';
import LocalShippingIcon from '@mui/icons-material/LocalShipping';
import ManageSearchIcon from '@mui/icons-material/ManageSearch';
import DescriptionIcon from '@mui/icons-material/Description';
import PushPinIcon from '@mui/icons-material/PushPin';
import SettingsIcon from '@mui/icons-material/Settings';
import {
@@ -27,7 +27,7 @@ import { PANEL_TILE_BORDER_RADIUS, responsiveColumnSpan } from 'dashgui/panels/p
import ArticleAttributesTab from './tabs/ArticleAttributesTab';
import ArticleHistoryTab from './tabs/ArticleHistoryTab';
import ArticleLabelTab from './tabs/ArticleLabelTab';
import ArticleSeoTab from './tabs/ArticleSeoTab';
import ArticleDescTab from './tabs/ArticleDescTab';
import ArticleSettingsTab from './tabs/ArticleSettingsTab';
import ArticleSupplierTab from './tabs/ArticleSupplierTab';
import HelpBadge from '../HelpBadge';
@@ -58,11 +58,11 @@ const ALWAYS_TABS = [
help: 'Zugeordnete Lieferanten, Einkaufspreise und Lieferanten-Artikelnummern',
},
{
id: ARTICLE_TAB.seo,
label: 'SEO & Beschreibung',
id: ARTICLE_TAB.desc,
label: 'Beschreibung',
color: PETROL_PANEL,
Icon: ManageSearchIcon,
help: 'Shop-Texte, Beschreibungen und Suchmaschinen-Metadaten',
Icon: DescriptionIcon,
help: 'Shop-Texte, Beschreibungen und Produktdetails',
},
{
id: ARTICLE_TAB.label,
@@ -184,8 +184,8 @@ class ArticleTileTab extends PureComponent {
return <ArticleHistoryTab sku={articleData.sku} />;
case ARTICLE_TAB.supplier:
return <ArticleSupplierTab article={articleData} />;
case ARTICLE_TAB.seo:
return <ArticleSeoTab article={articleData} />;
case ARTICLE_TAB.desc:
return <ArticleDescTab article={articleData} />;
case ARTICLE_TAB.label:
return <ArticleLabelTab article={articleData} />;
case ARTICLE_TAB.attributes:

View File

@@ -3,14 +3,15 @@ import { matchPath } from 'react-router-dom';
export const ARTICLE_TAB = {
history: 'history',
supplier: 'supplier',
seo: 'seo',
desc: 'desc',
seo: 'desc',
label: 'label',
attributes: 'attributes',
settings: 'settings',
};
/** Factory fallback when nothing is stored in localStorage. */
export const DEFAULT_ARTICLE_TAB = ARTICLE_TAB.seo;
export const DEFAULT_ARTICLE_TAB = ARTICLE_TAB.desc;
const PREFERRED_ARTICLE_TAB_KEY = 'dashfront:article-default-tab';
@@ -19,7 +20,7 @@ const ALL_ARTICLE_TAB_IDS = new Set(Object.values(ARTICLE_TAB));
const BASE_ARTICLE_TAB_IDS = [
ARTICLE_TAB.history,
ARTICLE_TAB.supplier,
ARTICLE_TAB.seo,
ARTICLE_TAB.desc,
ARTICLE_TAB.label,
ARTICLE_TAB.attributes,
];
@@ -45,6 +46,7 @@ export function isArticleTabId(tab) {
export function readPreferredArticleTab() {
try {
const raw = localStorage.getItem(PREFERRED_ARTICLE_TAB_KEY);
if (raw === 'seo') return ARTICLE_TAB.desc;
if (raw && isArticleTabId(raw)) return raw;
} catch {
// ignore quota / private mode
@@ -71,6 +73,7 @@ export function preferredArticleTab(article) {
export function resolveArticleTab(tabParam, article) {
const ids = articleTabIds(article);
if (tabParam === 'seo') return ARTICLE_TAB.desc;
if (tabParam && ids.includes(tabParam)) return tabParam;
return preferredArticleTab(article);
}
@@ -92,9 +95,10 @@ export function artikelDetailPath(articleOrSku, tab) {
: articleSku(articleOrSku);
if (!sku) return null;
const normalizedTab = tab === 'seo' ? ARTICLE_TAB.desc : tab;
let segment;
if (isArticleTabId(tab)) {
segment = tab;
if (isArticleTabId(normalizedTab)) {
segment = normalizedTab;
} else if (articleOrSku && typeof articleOrSku === 'object') {
segment = preferredArticleTab(articleOrSku);
} else {

View File

@@ -0,0 +1,68 @@
import { Component } from 'react';
import Box from '@mui/material/Box';
import PageMinimap from '../../PageMinimap';
function PanelHtmlValue({ html }) {
if (html == null || html === '') return null;
return (
<Box sx={{ mb: 1.5 }}>
<Box
sx={(theme) => ({
p: 1.5,
borderRadius: 1.5,
bgcolor:
theme.palette.mode === 'dark'
? 'rgba(255, 255, 255, 0.08)'
: 'rgba(255, 255, 255, 0.85)',
border: '1px solid',
borderColor:
theme.palette.mode === 'dark'
? 'rgba(255, 255, 255, 0.12)'
: 'rgba(255, 255, 255, 0.95)',
boxShadow:
theme.palette.mode === 'dark'
? 'none'
: '0 1px 3px rgba(0, 0, 0, 0.04)',
fontSize: '0.875rem',
lineHeight: 1.55,
color: 'text.primary',
wordBreak: 'break-word',
'& h1, & h2, & h3, & h4, & h5, & h6': {
fontSize: '1rem',
fontWeight: 600,
mt: 1.25,
mb: 0.5,
'&:first-child': { mt: 0 },
},
'& p': {
my: 0.5,
'&:first-child': { mt: 0 },
'&:last-child': { mb: 0 },
},
'& ul, & ol': {
pl: 2.5,
my: 0.5,
},
'& a': {
color: 'primary.main',
textDecoration: 'underline',
},
})}
dangerouslySetInnerHTML={{ __html: html }}
/>
</Box>
);
}
export default class ArticleDescTab extends Component {
render() {
const { article: articleData } = this.props;
const desc = articleData.desc ?? articleData.description;
return (
<>
<PanelHtmlValue html={desc} />
<PageMinimap />
</>
);
}
}

View File

@@ -1,68 +1,2 @@
import { Component } from 'react';
import Box from '@mui/material/Box';
import PageMinimap from '../../PageMinimap';
export { default } from './ArticleDescTab';
function PanelHtmlValue({ html }) {
if (html == null || html === '') return null;
return (
<Box sx={{ mb: 1.5 }}>
<Box
sx={(theme) => ({
p: 1.5,
borderRadius: 1.5,
bgcolor:
theme.palette.mode === 'dark'
? 'rgba(255, 255, 255, 0.08)'
: 'rgba(255, 255, 255, 0.85)',
border: '1px solid',
borderColor:
theme.palette.mode === 'dark'
? 'rgba(255, 255, 255, 0.12)'
: 'rgba(255, 255, 255, 0.95)',
boxShadow:
theme.palette.mode === 'dark'
? 'none'
: '0 1px 3px rgba(0, 0, 0, 0.04)',
fontSize: '0.875rem',
lineHeight: 1.55,
color: 'text.primary',
wordBreak: 'break-word',
'& h1, & h2, & h3, & h4, & h5, & h6': {
fontSize: '1rem',
fontWeight: 600,
mt: 1.25,
mb: 0.5,
'&:first-child': { mt: 0 },
},
'& p': {
my: 0.5,
'&:first-child': { mt: 0 },
'&:last-child': { mb: 0 },
},
'& ul, & ol': {
pl: 2.5,
my: 0.5,
},
'& a': {
color: 'primary.main',
textDecoration: 'underline',
},
})}
dangerouslySetInnerHTML={{ __html: html }}
/>
</Box>
);
}
export default class ArticleSeoTab extends Component {
render() {
const { article: articleData } = this.props;
const desc = articleData.desc ?? articleData.description;
return (
<>
<PanelHtmlValue html={desc} />
<PageMinimap />
</>
);
}
}