diff --git a/www/src/scripts/employee-portal.ts b/www/src/scripts/employee-portal.ts index 7d12f05..59d8fb0 100644 --- a/www/src/scripts/employee-portal.ts +++ b/www/src/scripts/employee-portal.ts @@ -41,8 +41,42 @@ export function safePortalContent(html: string): DocumentFragment { target.appendChild(element); }; for (const child of template.content.childNodes) copy(child, output); + enhanceStaffPortalPresentation(output); return output; } +/** + * The staff stream has a "Management Templates" section. Its resource links + * used HubSpot presentation rules that are intentionally removed by the safe + * renderer. Restore local visual semantics only after sanitization; never + * copy arbitrary source classes, attributes, styles or executable content. + */ +function enhanceStaffPortalPresentation(fragment: DocumentFragment): void { + const headings = [...fragment.querySelectorAll('h1, h2, h3, h4, h5, h6')]; + const templatesHeading = headings.find((heading) => + heading.textContent?.replace(/\s+/g, ' ').trim().toLowerCase() === 'management templates'); + if (!templatesHeading) return; + + // This heading distinguishes the general-staff resource directory from the + // separate management-report view. Preserve contact links as links. + for (const anchor of fragment.querySelectorAll('a[href]')) { + const protocol = new URL(anchor.href).protocol; + if (protocol === 'https:' || protocol === location.protocol) { + anchor.classList.add('portal-resource-button'); + } + } + + // The original section is a heading followed by a list, occasionally with + // intervening wrappers. Keep the list and its reading/tab order intact. + let templatesList: HTMLUListElement | null = null; + for (let sibling = templatesHeading.nextElementSibling; sibling; sibling = sibling.nextElementSibling) { + if (/^H[1-6]$/.test(sibling.tagName)) break; + if (sibling instanceof HTMLUListElement) { templatesList = sibling; break; } + templatesList = sibling.querySelector('ul'); + if (templatesList) break; + } + if (!templatesList) templatesList = templatesHeading.closest('section, article')?.querySelector('ul') ?? null; + templatesList?.classList.add('portal-template-grid'); +} function initialize() { const root = document.querySelector('[data-employee-portal]'); if (!root || root.dataset.bound) return;