diff --git a/front/src/lib/_utils/shape-shifters/shapeExperienceData.js b/front/src/lib/_utils/shape-shifters/shapeExperienceData.js index 3a07fc830..566389cc1 100644 --- a/front/src/lib/_utils/shape-shifters/shapeExperienceData.js +++ b/front/src/lib/_utils/shape-shifters/shapeExperienceData.js @@ -1,10 +1,5 @@ -import { marked } from 'marked'; -import { link } from '@components/content/renderers'; - -// Configure the marked renderer -const renderer = new marked.Renderer(); -renderer.link = link; -marked.use({ renderer, gfm: true }); +// import { Marked, Renderer } from 'marked'; +import marked from '@components/content/markers/marker'; /** * Shapes and prepares experience data for rendering. @@ -58,11 +53,14 @@ export async function shapeExperienceData(data) { } ); + // Process markdown + const markedBody = body ? await marked(body) : false; + return { experience: { ...experience, highlightedSkills, - body: body ? marked(body) : false, + body: markedBody, hero: hero?.data?.attributes || false, }, pageMeta, diff --git a/front/src/lib/_utils/shape-shifters/shapeProjectData.js b/front/src/lib/_utils/shape-shifters/shapeProjectData.js index 4f0d055dc..18b6b0e16 100644 --- a/front/src/lib/_utils/shape-shifters/shapeProjectData.js +++ b/front/src/lib/_utils/shape-shifters/shapeProjectData.js @@ -1,5 +1,4 @@ -import { marked } from 'marked'; -import { link, heading } from '@components/content/renderers'; +import marked from '@components/content/markers/marker'; /** * Shapes artifact data by categorizing websites and videos. @@ -44,16 +43,6 @@ async function shapeArtifactData(data) { * @returns {Object} - Shaped project data with optimized artifacts and parsed body. */ export async function shapeProjectData(data) { - /** - * Custom renderer for marked library. - * @type {marked.Renderer} - */ - const renderer = new marked.Renderer(); - renderer.link = link; - renderer.heading = heading; - - marked.use({ renderer, gfm: true }); - /** * Destructuring relevant attributes from the first element of the data array. * @type {Object} diff --git a/front/src/lib/components/content/markers/marker.js b/front/src/lib/components/content/markers/marker.js new file mode 100644 index 000000000..af918ae94 --- /dev/null +++ b/front/src/lib/components/content/markers/marker.js @@ -0,0 +1,22 @@ +import { Marked, Renderer } from 'marked'; +import markedAlert from 'marked-alert'; +import { heading, link } from '../renderers/index.js'; + +const renderer = new Renderer(); +renderer.link = link; +renderer.heading = heading; + +const marker = new Marked(); +marker.use(markedAlert(), { renderer: renderer, gfm: true }); + +// General markdown rendering function +/** + * Render markdown text using the marked library. + * + * @param {string} text - The markdown text to render. + * @returns {string} - Rendered HTML content. + */ +export default async function marked(text) { + const content = marker.parse(text); + return content; +} diff --git a/front/src/lib/components/content/markers/postMarker.js b/front/src/lib/components/content/markers/postMarker.js new file mode 100644 index 000000000..8fbca6bc2 --- /dev/null +++ b/front/src/lib/components/content/markers/postMarker.js @@ -0,0 +1,23 @@ +import { Marked, Renderer } from 'marked'; +import markedAlert from 'marked-alert'; +import { link, anchorHeading, image } from '../renderers/index.js'; + +const postRenderer = new Renderer(); +postRenderer.link = link; +postRenderer.heading = anchorHeading; +postRenderer.image = image; + +const postMarker = new Marked(); +postMarker.use(markedAlert(), { renderer: postRenderer, gfm: true }); + +// Post markdown rendering/parsing function +/** + * Render markdown text using the marked library. + * + * @param {string} text - The markdown text to render. + * @returns {string} - Rendered HTML content. + */ +export default async function postMarked(text) { + const content = postMarker.parse(text); + return content; +} diff --git a/front/src/lib/components/content/parsers/index.js b/front/src/lib/components/content/parsers/index.js index 5e92b62cd..c70b4fa59 100644 --- a/front/src/lib/components/content/parsers/index.js +++ b/front/src/lib/components/content/parsers/index.js @@ -22,3 +22,38 @@ export const parseTOC = function (contents) { return headings; }; + +/** + * Parses the highlighted lines string into an array of line numbers. + * Adjusts line numbers for zero-based indexing and sorts them in ascending order. + * + * @param {string|false} lines - The string of highlighted lines or false. + * @returns {Array|false} An array of adjusted line numbers, or false if input is falsy. + */ +export const parseHighlightedLines = async function parseHighlightedLines( + lines +) { + if (!lines) { + return false; + } + + return lines + .split(',') + .reduce((acc, part) => { + const range = part + .trim() + .split('-') + .map((num) => parseInt(num, 10) - 1); + + if (range.length === 2) { + for (let i = range[0]; i <= range[1]; i++) { + acc.push(i); + } + } else { + acc.push(range[0]); + } + + return acc; + }, []) + .sort((a, b) => a - b); +}; diff --git a/front/src/lib/components/content/renderers/index.js b/front/src/lib/components/content/renderers/index.js index 6e790c744..2e65b9544 100644 --- a/front/src/lib/components/content/renderers/index.js +++ b/front/src/lib/components/content/renderers/index.js @@ -10,7 +10,23 @@ import { extractDomainWithoutWWW } from '@utils'; * @param {number} level The heading level * @returns A heading with offset level, anchor id, and anchor link */ -export const heading = function (text, level, raw) { +export const heading = function (text, level) { + let depth = level + 1; + + return ` + ${text} + `; +}; + +/** + * @function + * @name anchorHeading + * + * @param {string} text The heading text + * @param {number} level The heading level + * @returns A heading with offset level, anchor id, and anchor link + */ +export const anchorHeading = function (text, level, raw) { const id = slugger(raw); let depth = level + 1; diff --git a/front/src/routes/post/[slug]/+page.server.js b/front/src/routes/post/[slug]/+page.server.js index 7775f64f9..2bd06dba0 100644 --- a/front/src/routes/post/[slug]/+page.server.js +++ b/front/src/routes/post/[slug]/+page.server.js @@ -5,62 +5,8 @@ import { API_PATH_POST as POST, POST_PARAMS as PARAMS, } from '$env/static/private'; -import { marked } from 'marked'; -import markedAlert from 'marked-alert'; -import { link, heading, image } from '@components/content/renderers'; -import { parseTOC } from '@components/content/parsers'; - -const renderer = new marked.Renderer(); -renderer.link = link; -renderer.heading = heading; -renderer.image = image; - -marked.use(markedAlert(), { renderer, gfm: true }); - -// Markdown rendering function -/** - * Render markdown text using the marked library. - * - * @param {string} text - The markdown text to render. - * @returns {string} - Rendered HTML content. - */ -async function markItUp(text) { - const content = marked.parse(text); - return content; -} - -/** - * Parses the highlighted lines string into an array of line numbers. - * Adjusts line numbers for zero-based indexing and sorts them in ascending order. - * - * @param {string|false} lines - The string of highlighted lines or false. - * @returns {Array|false} An array of adjusted line numbers, or false if input is falsy. - */ -async function parseHighlightedLines(lines) { - if (!lines) { - return false; - } - - return lines - .split(',') - .reduce((acc, part) => { - const range = part - .trim() - .split('-') - .map((num) => parseInt(num, 10) - 1); - - if (range.length === 2) { - for (let i = range[0]; i <= range[1]; i++) { - acc.push(i); - } - } else { - acc.push(range[0]); - } - - return acc; - }, []) - .sort((a, b) => a - b); -} +import { parseTOC, parseHighlightedLines } from '@components/content/parsers'; +import postMarked from '@components/content/markers/postMarker'; /** * Load function to fetch and process a blog post. @@ -114,7 +60,7 @@ export async function load({ params: { slug }, route }) { parsedTOC = parseTOC(c.text); toc.push(...parsedTOC); // Render markdown text - return { ...c, text: await markItUp(c.text) }; + return { ...c, text: await postMarked(c.text) }; case 'posts.code': return { ...c, @@ -143,7 +89,7 @@ export async function load({ params: { slug }, route }) { } = c; const enhancedFigcaption = figcaption - ? await markItUp(figcaption) + ? await postMarked(figcaption) : null; return { @@ -191,7 +137,7 @@ export async function load({ params: { slug }, route }) { return { post: post || {}, toc, - summary: summary ? await markItUp(summary) : false, + summary: summary ? await postMarked(summary) : false, content: parsedContent, pageMeta, }; diff --git a/front/src/routes/privacy/+page.server.js b/front/src/routes/privacy/+page.server.js index f160050e9..b3e4ba8df 100644 --- a/front/src/routes/privacy/+page.server.js +++ b/front/src/routes/privacy/+page.server.js @@ -4,14 +4,7 @@ import { API_URL as URL, API_PATH_PRIVACY as PRIVACY, } from '$env/static/private'; -import { marked } from 'marked'; -import { heading, link } from '@components/content/renderers'; - -const renderer = new marked.Renderer(); -renderer.link = link; -renderer.heading = heading; - -marked.use({ renderer, gfm: true }); +import marked from '@components/content/markers/marker'; const endpoint = URL + PRIVACY; @@ -42,7 +35,7 @@ export async function load() { }; var markedPrivacyDetails = privacyContent - ? marked(privacyContent.details) + ? await marked(privacyContent.details) : false; return {