diff --git a/src/components/FrameRenderer/FrameRenderer.astro b/src/components/FrameRenderer/FrameRenderer.astro index fb90eb446..86d4d3695 100644 --- a/src/components/FrameRenderer/FrameRenderer.astro +++ b/src/components/FrameRenderer/FrameRenderer.astro @@ -4,7 +4,8 @@ import TopicOverlay from '../TopicOverlay/TopicOverlay.astro'; import './FrameRenderer.css'; export interface Props { - roadmapId: string; + resourceType: 'roadmap' | 'best-practice'; + resourceId: string; jsonUrl: string; dimensions?: { width: number; @@ -12,13 +13,14 @@ export interface Props { }; } -const { roadmapId, jsonUrl, dimensions = null } = Astro.props; +const { resourceId, resourceType, jsonUrl, dimensions = null } = Astro.props; ---
diff --git a/src/components/FrameRenderer/renderer.js b/src/components/FrameRenderer/renderer.js index 55b09e544..ddb25f551 100644 --- a/src/components/FrameRenderer/renderer.js +++ b/src/components/FrameRenderer/renderer.js @@ -1,23 +1,17 @@ import { wireframeJSONToSVG } from 'roadmap-renderer'; -/** - * @typedef {{ roadmapId: string, jsonUrl: string }} RoadmapConfig - */ - export class Renderer { - /** - * @param {RoadmapConfig} config - */ constructor() { - this.roadmapId = ''; + this.resourceId = ''; + this.resourceType = ''; this.jsonUrl = ''; - this.containerId = 'roadmap-svg'; + this.containerId = 'resource-svg'; this.init = this.init.bind(this); this.onDOMLoaded = this.onDOMLoaded.bind(this); - this.fetchRoadmapSvg = this.fetchRoadmapSvg.bind(this); - this.handleRoadmapClick = this.handleRoadmapClick.bind(this); + this.jsonToSvg = this.jsonToSvg.bind(this); + this.handleSvgClick = this.handleSvgClick.bind(this); this.prepareConfig = this.prepareConfig.bind(this); } @@ -32,7 +26,8 @@ export class Renderer { const dataset = this.containerEl.dataset; - this.roadmapId = dataset.roadmapId; + this.resourceType = dataset.resourceType; + this.resourceId = dataset.resourceId; this.jsonUrl = dataset.jsonUrl; return true; @@ -42,7 +37,7 @@ export class Renderer { * @param { string } jsonUrl * @returns {Promise} */ - fetchRoadmapSvg(jsonUrl) { + jsonToSvg(jsonUrl) { if (!jsonUrl) { console.error('jsonUrl not defined in frontmatter'); return null; @@ -64,14 +59,14 @@ export class Renderer { return; } - this.fetchRoadmapSvg(this.jsonUrl) + this.jsonToSvg(this.jsonUrl) .then((svg) => { document.getElementById(this.containerId).replaceChildren(svg); }) .catch(console.error); } - handleRoadmapClick(e) { + handleSvgClick(e) { const targetGroup = e.target.closest('g') || {}; const groupId = targetGroup.dataset ? targetGroup.dataset.groupId : ''; if (!groupId) { @@ -80,11 +75,19 @@ export class Renderer { e.stopImmediatePropagation(); + if (/^ext_link/.test(groupId)) { + window.open(`https://${groupId.replace('ext_link:', '')}`); + return; + } + + // Remove sorting prefix from groupId + const normalizedGroupId = groupId.replace(/^\d+-/, ''); + window.dispatchEvent( - new CustomEvent('topic.click', { + new CustomEvent(`${this.resourceType}.topic.click`, { detail: { - topicId: groupId, - roadmapId: this.roadmapId, + topicId: normalizedGroupId, + resourceId: this.resourceId, }, }) ); @@ -92,7 +95,7 @@ export class Renderer { init() { window.addEventListener('DOMContentLoaded', this.onDOMLoaded); - window.addEventListener('click', this.handleRoadmapClick); + window.addEventListener('click', this.handleSvgClick); } } diff --git a/src/components/TopicOverlay/topic.js b/src/components/TopicOverlay/topic.js index 971f142d8..c47b8a52a 100644 --- a/src/components/TopicOverlay/topic.js +++ b/src/components/TopicOverlay/topic.js @@ -10,10 +10,12 @@ export class Topic { this.closeTopicId = 'close-topic'; this.contributionTextId = 'contrib-meta'; - this.activeRoadmapId = null; + this.activeResourceType = null; + this.activeResourceId = null; this.activeTopicId = null; - this.handleTopicClick = this.handleTopicClick.bind(this); + this.handleRoadmapTopicClick = this.handleRoadmapTopicClick.bind(this); + this.handleBestPracticeTopicClick = this.handleBestPracticeTopicClick.bind(this); this.close = this.close.bind(this); this.resetDOM = this.resetDOM.bind(this); @@ -86,7 +88,7 @@ export class Topic { close() { this.resetDOM(true); - this.activeRoadmapId = null; + this.activeResourceId = null; this.activeTopicId = null; } @@ -115,11 +117,8 @@ export class Topic { } } - fetchTopicHtml(roadmapId, topicId) { - const topicPartial = topicId.replace(/^\d+-/, '').replaceAll(/:/g, '/'); - const fullUrl = `/${roadmapId}/${topicPartial}`; - - return fetch(fullUrl) + renderTopicFromUrl(url) { + return fetch(url) .then((res) => { return res.text(); }) @@ -129,33 +128,45 @@ export class Topic { const node = new DOMParser().parseFromString(topicHtml, 'text/html'); return node.getElementById('main-content'); + }) + .then((content) => { + this.populate(content); + }) + .catch((e) => { + console.error(e); + this.populate('Error loading the content!'); }); } - handleTopicClick(e) { - const { roadmapId, topicId } = e.detail; - if (!topicId || !roadmapId) { - console.log('Missing topic or roadmap: ', e.detail); + handleBestPracticeTopicClick(e) { + const { resourceId: bestPracticeId, topicId } = e.detail; + if (!topicId || !bestPracticeId) { + console.log('Missing topic or bestPracticeId: ', e.detail); return; } - this.activeRoadmapId = roadmapId; + this.activeResourceType = 'best-practice'; + this.activeResourceId = bestPracticeId; this.activeTopicId = topicId; - if (/^ext_link/.test(topicId)) { - window.open(`https://${topicId.replace('ext_link:', '')}`); + this.resetDOM(); + + alert('Best practices are not yet implemented!'); + } + + handleRoadmapTopicClick(e) { + const { resourceId: roadmapId, topicId } = e.detail; + if (!topicId || !roadmapId) { + console.log('Missing topic or roadmap: ', e.detail); return; } + this.activeResourceType = 'roadmap'; + this.activeResourceId = roadmapId; + this.activeTopicId = topicId; + this.resetDOM(); - this.fetchTopicHtml(roadmapId, topicId) - .then((content) => { - this.populate(content); - }) - .catch((e) => { - console.error(e); - this.populate('Error loading the content!'); - }); + this.renderTopicFromUrl(`/${roadmapId}/${topicId.replaceAll(':', '/')}`); } queryRoadmapElementsByTopicId(topicId) { @@ -219,7 +230,8 @@ export class Topic { } init() { - window.addEventListener('topic.click', this.handleTopicClick); + window.addEventListener('roadmap.topic.click', this.handleRoadmapTopicClick); + window.addEventListener('best-practice.topic.click', this.handleBestPracticeTopicClick); window.addEventListener('click', this.handleOverlayClick); window.addEventListener('contextmenu', this.rightClickListener); diff --git a/src/pages/[roadmapId]/index.astro b/src/pages/[roadmapId]/index.astro index 545aeee4a..d7c65426b 100644 --- a/src/pages/[roadmapId]/index.astro +++ b/src/pages/[roadmapId]/index.astro @@ -79,7 +79,12 @@ const contentContributionLink = `https://github.com/kamranahmedse/developer-road - +
) } diff --git a/src/pages/best-practices/[bestPracticeId].astro b/src/pages/best-practices/[bestPracticeId].astro index c4a666003..f66b9cbfa 100644 --- a/src/pages/best-practices/[bestPracticeId].astro +++ b/src/pages/best-practices/[bestPracticeId].astro @@ -75,7 +75,8 @@ const contentContributionLink = `https://github.com/kamranahmedse/developer-road