diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 00000000..c3de7ee0 --- /dev/null +++ b/.eslintignore @@ -0,0 +1 @@ +tools/importer/helix-importer-ui/* diff --git a/blocks/developers-content/developers-content.css b/blocks/developers-content/developers-content.css new file mode 100644 index 00000000..58f7d06f --- /dev/null +++ b/blocks/developers-content/developers-content.css @@ -0,0 +1,6 @@ +raqn-developers-toc h2, +raqn-developers-toc h3 { + margin: 10px; + color: var(--scope-color); + font-size: var(--scope-font-size, 1.3em); +} \ No newline at end of file diff --git a/blocks/developers-content/developers-content.js b/blocks/developers-content/developers-content.js new file mode 100644 index 00000000..41971f02 --- /dev/null +++ b/blocks/developers-content/developers-content.js @@ -0,0 +1,150 @@ +import ComponentBase from '../../scripts/component-base.js'; + +const sitePathPrefix = 'developers'; + +export default class DeveloperToc extends ComponentBase { + static loaderConfig = { + ...ComponentBase.loaderConfig, + targetsSelectors: 'main > div:first-child', + targetsSelectorsLimit: 1, + }; + + extendConfig() { + return [ + ...super.extendConfig(), + { + contentFromTargets: false, + addToTargetMethod: 'replaceWith', + targetsAsContainers: { + addToTargetMethod: 'prepend', + contentFromTargets: false, + }, + }, + ]; + } + + ready() { + this.generateTablesOfContent(); + } + + isIndex(node) { + return node.page && (node.segment === 'README' || node.segment === 'readme'); + } + + toLink(path) { + if(window.location.host.startsWith('localhost') || window.location.host.search(/\.aem\.(page|live)/) > 0) { + return path; + } + return `/${sitePathPrefix}${path}`; + } + + async loadPageHierarchy() { + const response = await fetch(`/${sitePathPrefix}/query-index.json`); + if(!response.ok) return []; + const json = await response.json(); + + const pageHierarchy = []; + const pageHierarchyObject = { children:pageHierarchy }; + let currentNode; + json.data.forEach(page => { + const segments = page.path.split('/').slice(1); + let currentParent = pageHierarchyObject; + let nodePath = ''; + segments.forEach((segment) => { + nodePath += `/${segment}`; + let node = currentParent.children.find((child) => child.segment === segment); + if (!node) { + node = { + nodePath, + segment, + active: window.location.pathname.startsWith(nodePath), + children: [], + }; + if(nodePath === page.path) { + node.page = page; + if(this.isIndex(node)) { + currentParent.link = page.path; + } + if(!currentNode && node.active) { + currentNode = node; + } + } + currentParent.children.push(node); + } + currentParent = node; + }); + }); + + const postProcessHierarchy = (node) => { + node.children.sort((a, b) => a.segment.localeCompare(b.segment)); + if(!node.page && !node.link) { + const firstChildPage = node.children.find((child) => child.page); + if(firstChildPage) { + node.link = firstChildPage.page.path; + } + } + node.children.forEach((child) => postProcessHierarchy(child)); + }; + postProcessHierarchy(pageHierarchyObject); + + return [pageHierarchy, currentNode]; + } + + generateRepository(repository) { + const a = document.createElement('a'); + a.href = this.toLink(repository.link); + a.innerText = repository.segment; + return `
  • ${a.outerHTML}

    `; + } + + generateProjects(org) { + return org.children.map((project) => { + const h2 = document.createElement('h2'); + h2.innerText = `${org.segment} - ${project.segment}`; + return `
  • ${h2.outerHTML} +
  • `; + }).join(''); + } + + generatePages(node) { + if(this.isIndex(node)) return ''; + + const link = node.link || node.page?.path; + const li = document.createElement('li'); + if(link) { + const a = document.createElement('a'); + a.href = this.toLink(link); + a.innerText = node.segment; + li.innerHTML = a.outerHTML; + } else { + li.innerText = node.segment; + } + + const childrenHTML = node.children.map((child) => this.generatePages(child)).join(''); + if(childrenHTML) { + const ul = document.createElement('ul'); + ul.innerHTML = childrenHTML; + li.appendChild(ul); + } + + return li.outerHTML; + } + + async generateTablesOfContent() { + const [pageHierarchy, currentNode] = await this.loadPageHierarchy(); + const currentOrg = pageHierarchy.find((org) => org.active); + const currentProject = currentOrg?.children.find((project) => project.active); + const currentRepository = currentProject?.children.find((repository) => repository.active); + + let tocs = ``; + + if(currentRepository && currentNode) { + const h2 = document.createElement('h2'); + h2.innerText = `${currentOrg.segment} - ${currentProject.segment} - ${currentRepository.segment}`; + tocs += `
    ${h2.outerHTML} +
    `; + } + + this.innerHTML = tocs; + } +} diff --git a/scripts/init.js b/scripts/init.js index 5d3f9b94..57ce18fd 100644 --- a/scripts/init.js +++ b/scripts/init.js @@ -143,6 +143,12 @@ export const onLoadComponents = { componentName: name.trim(), }; }); + const template = getMeta(metaTags.template.metaName); + if(template) { + this.structureComponents = [...this.structureComponents, { + componentName: template, + }]; + } }, setLcpBlocks() { diff --git a/scripts/libs.js b/scripts/libs.js index 11c0be2b..36f98a6f 100644 --- a/scripts/libs.js +++ b/scripts/libs.js @@ -43,6 +43,10 @@ export const metaTags = { metaNamePrefix: 'structure', // contentType: 'boolean string', }, + template: { + metaName: 'structure', + // contentType: 'boolean string', + }, lcp: { metaName: 'lcp', fallbackContent: ['theming', 'header', 'breadcrumbs'],