diff --git a/frontend/src/core/components/tools/getPdfInfo/GetPdfInfoReportView.tsx b/frontend/src/core/components/tools/getPdfInfo/GetPdfInfoReportView.tsx index 01e53eaf6..5fb05d6c1 100644 --- a/frontend/src/core/components/tools/getPdfInfo/GetPdfInfoReportView.tsx +++ b/frontend/src/core/components/tools/getPdfInfo/GetPdfInfoReportView.tsx @@ -34,9 +34,23 @@ const GetPdfInfoReportView: React.FC = ({ data }) => }; const anchor = idMap[data.scrollTo]; if (!anchor) return; - const el = containerRef.current?.querySelector(`#${anchor}`); - if (el) { - el.scrollIntoView({ behavior: 'smooth', block: 'start' }); + const container = containerRef.current; + const el = container?.querySelector(`#${anchor}`); + if (el && container) { + // Calculate scroll position with 4rem buffer from top + const bufferPx = parseFloat(getComputedStyle(document.documentElement).fontSize) * 4; + const elementTop = el.getBoundingClientRect().top; + const containerTop = container.getBoundingClientRect().top; + const currentScroll = container.scrollTop; + const targetScroll = currentScroll + (elementTop - containerTop) - bufferPx; + + container.scrollTo({ top: Math.max(0, targetScroll), behavior: 'smooth' }); + + // Flash highlight the section + el.classList.remove('section-flash-highlight'); + void el.offsetWidth; // Force reflow + el.classList.add('section-flash-highlight'); + setTimeout(() => el.classList.remove('section-flash-highlight'), 1500); } }, [data.scrollTo]); diff --git a/frontend/src/core/components/tools/getPdfInfo/sections/OtherSection.tsx b/frontend/src/core/components/tools/getPdfInfo/sections/OtherSection.tsx index aeb07c168..33759fae1 100644 --- a/frontend/src/core/components/tools/getPdfInfo/sections/OtherSection.tsx +++ b/frontend/src/core/components/tools/getPdfInfo/sections/OtherSection.tsx @@ -3,6 +3,7 @@ import { Accordion, Code, Stack, Text } from '@mantine/core'; import { useTranslation } from 'react-i18next'; import SectionBlock from '../shared/SectionBlock'; import SimpleArrayList from '../shared/SimpleArrayList'; +import { pdfInfoAccordionStyles } from '../shared/accordionStyles'; interface OtherSectionProps { anchorId: string; @@ -32,7 +33,12 @@ const OtherSection: React.FC = ({ anchorId, other }) => { {t('getPdfInfo.other.layers', 'Layers')} - + {t('getPdfInfo.other.structureTree', 'StructureTree')} @@ -44,7 +50,9 @@ const OtherSection: React.FC = ({ anchorId, other }) => { style={{ whiteSpace: 'pre-wrap', backgroundColor: panelBg, - color: panelText + color: panelText, + maxHeight: '20rem', + overflowY: 'auto' }} > {JSON.stringify(other?.StructureTree, null, 2)} @@ -63,7 +71,9 @@ const OtherSection: React.FC = ({ anchorId, other }) => { style={{ whiteSpace: 'pre-wrap', backgroundColor: panelBg, - color: panelText + color: panelText, + maxHeight: '400px', + overflowY: 'auto' }} > {String(other?.XMPMetadata)} diff --git a/frontend/src/core/components/tools/getPdfInfo/sections/PerPageSection.tsx b/frontend/src/core/components/tools/getPdfInfo/sections/PerPageSection.tsx index 16bce3404..9340c1bd8 100644 --- a/frontend/src/core/components/tools/getPdfInfo/sections/PerPageSection.tsx +++ b/frontend/src/core/components/tools/getPdfInfo/sections/PerPageSection.tsx @@ -4,6 +4,7 @@ import { useTranslation } from 'react-i18next'; import SectionBlock from '../shared/SectionBlock'; import KeyValueList from '../shared/KeyValueList'; import SimpleArrayList from '../shared/SimpleArrayList'; +import { pdfInfoAccordionStyles } from '../shared/accordionStyles'; interface PerPageSectionProps { anchorId: string; @@ -18,7 +19,12 @@ const PerPageSection: React.FC = ({ anchorId, perPage }) => return ( {perPage && Object.keys(perPage as any).length > 0 ? ( - + {Object.entries(perPage as any).map(([pageLabel, pageInfo]: [string, any]) => ( diff --git a/frontend/src/core/components/tools/getPdfInfo/shared/accordionStyles.ts b/frontend/src/core/components/tools/getPdfInfo/shared/accordionStyles.ts new file mode 100644 index 000000000..e974c9845 --- /dev/null +++ b/frontend/src/core/components/tools/getPdfInfo/shared/accordionStyles.ts @@ -0,0 +1,14 @@ +import type { AccordionStylesNames } from '@mantine/core'; +import type { CSSProperties } from 'react'; + +type AccordionStyles = Partial>; + +export const pdfInfoAccordionStyles: AccordionStyles = { + item: { + backgroundColor: 'var(--accordion-item-bg)', + }, + control: { + backgroundColor: 'transparent', + }, +}; + diff --git a/frontend/src/core/components/tools/validateSignature/reportView/styles.css b/frontend/src/core/components/tools/validateSignature/reportView/styles.css index 94ac2a963..27b1081d4 100644 --- a/frontend/src/core/components/tools/validateSignature/reportView/styles.css +++ b/frontend/src/core/components/tools/validateSignature/reportView/styles.css @@ -103,3 +103,28 @@ color: rgb(var(--pdf-light-text-muted)); background: linear-gradient(145deg, var(--mantine-color-gray-1) 0%, var(--mantine-color-gray-0) 100%); } + +/* Flash highlight animation for section navigation */ +@keyframes section-flash { + 0% { + background-color: rgba(255, 235, 59, 0); + box-shadow: none; + } + 20% { + background-color: rgba(255, 235, 59, 0.35); + box-shadow: 0 0 20px rgba(255, 235, 59, 0.5); + } + 50% { + background-color: rgba(255, 235, 59, 0.25); + box-shadow: 0 0 15px rgba(255, 235, 59, 0.4); + } + 100% { + background-color: rgba(255, 235, 59, 0); + box-shadow: none; + } +} + +.section-flash-highlight { + animation: section-flash 1.5s ease-out; + border-radius: 8px; +} diff --git a/frontend/src/core/styles/theme.css b/frontend/src/core/styles/theme.css index 30991cf30..8551735ed 100644 --- a/frontend/src/core/styles/theme.css +++ b/frontend/src/core/styles/theme.css @@ -256,6 +256,7 @@ --header-selected-bg: #1E88E5; /* light mode selected header matches dark */ --header-selected-fg: #FFFFFF; --file-card-bg: #FFFFFF; /* file card background (light/dark paired) */ + --accordion-item-bg: #E8EAED; /* accordion item background - more distinguishable */ /* shadows */ --drop-shadow-color: rgba(0, 0, 0, 0.08); @@ -519,6 +520,7 @@ --header-selected-fg: #FFFFFF; /* file card background (dark) */ --file-card-bg: #1F2329; + --accordion-item-bg: #373D45; /* accordion item background - more distinguishable */ /* shadows */ --drop-shadow-color: rgba(255, 255, 255, 0.08);