diff options
author | (quasar) nebula <qznebula@protonmail.com> | 2024-12-29 13:53:25 -0400 |
---|---|---|
committer | (quasar) nebula <qznebula@protonmail.com> | 2024-12-29 13:53:25 -0400 |
commit | 012e29630fa0bddfd49faf97caf84585109e07ad (patch) | |
tree | 6528fe11ea7ef133385a8a4573c8d858eae1ab4c /src | |
parent | e23d54ab78cb38f90ed9f667759f986792aceb86 (diff) |
replacer, content, css: videos in content text
Diffstat (limited to 'src')
-rw-r--r-- | src/content/dependencies/transformContent.js | 56 | ||||
-rw-r--r-- | src/static/css/site.css | 18 | ||||
-rw-r--r-- | src/util/replacer.js | 51 |
3 files changed, 113 insertions, 12 deletions
diff --git a/src/content/dependencies/transformContent.js b/src/content/dependencies/transformContent.js index 3d9fdd60..48e20f94 100644 --- a/src/content/dependencies/transformContent.js +++ b/src/content/dependencies/transformContent.js @@ -362,6 +362,41 @@ export default { }; } + case 'video': { + const src = + (node.src.startsWith('media/') + ? to('media.path', node.src.slice('media/'.length)) + : node.src); + + const { + width, + height, + align, + pixelate, + } = node; + + const content = + html.tag('div', {class: 'content-video-container'}, + html.tag('video', + src && {src}, + width && {width}, + height && {height}, + + {controls: true}, + + align === 'center' && + {class: 'align-center'}, + + pixelate && + {class: 'pixelate'})); + + return { + type: 'processed-video', + data: + content, + }; + } + case 'internal-link': { const nodeFromRelations = relations.internalLinks[internalLinkIndex++]; if (nodeFromRelations.type === 'text') { @@ -541,15 +576,18 @@ export default { const attributes = html.parseAttributes(match[1]); - // Images that were all on their own line need to be removed from - // the surrounding <p> tag that marked generates. The HTML parser - // treats a <div> that starts inside a <p> as a Crocker-class - // misgiving, and will treat you very badly if you feed it that. - if (attributes.get('data-type') === 'processed-image') { - if (!attributes.get('data-inline')) { - tags[tags.length - 1] = tags[tags.length - 1].replace(/<p>$/, ''); - deleteParagraph = true; - } + // Images (or videos) that were all on their own line need to be + // removed from the surrounding <p> tag that marked generates. + // The HTML parser treats a <div> that starts inside a <p> as a + // Crocker-class misgiving, and will treat you very badly if you + // feed it that. + if ( + (attributes.get('data-type') === 'processed-image' && + !attributes.get('data-inline')) || + attributes.get('data-type') === 'processed-video' + ) { + tags[tags.length - 1] = tags[tags.length - 1].replace(/<p>$/, ''); + deleteParagraph = true; } const nonTextNodeIndex = match[2]; diff --git a/src/static/css/site.css b/src/static/css/site.css index 7fe6f915..56a6ad40 100644 --- a/src/static/css/site.css +++ b/src/static/css/site.css @@ -1399,12 +1399,14 @@ p.image-details.illustrator-details { display: none; } -.content-image-container { +.content-image-container, +.content-video-container { margin-top: 1em; margin-bottom: 1em; } -.content-image-container.align-center { +.content-image-container.align-center, +.content-video-container.align-center { text-align: center; margin-top: 1.5em; margin-bottom: 1.5em; @@ -1944,6 +1946,15 @@ h1 a[href="#additional-names-box"]:hover { color: white; } +/* Videos (in content) get a lite version of image-container. */ +.content-video-container { + width: min-content; + background-color: var(--dark-color); + border: 2px solid var(--primary-color); + border-radius: 2.5px 2.5px 3px 3px; + padding: 5px; +} + .image-text-area { position: absolute; top: 0; @@ -2013,7 +2024,8 @@ img { 6px -6px 2px -4px white inset; } -img.pixelate, .pixelate img { +img.pixelate, .pixelate img, +video.pixelate, .pixelate video { image-rendering: crisp-edges; } diff --git a/src/util/replacer.js b/src/util/replacer.js index 78b4a895..e3f5623e 100644 --- a/src/util/replacer.js +++ b/src/util/replacer.js @@ -599,6 +599,56 @@ export function postprocessImages(inputNodes) { return outputNodes; } +export function postprocessVideos(inputNodes) { + const outputNodes = []; + + for (const node of inputNodes) { + if (node.type !== 'text') { + outputNodes.push(node); + continue; + } + + const videoRegexp = /<video (.*?)>(<\/video>)?/g; + + let match = null, parseFrom = 0; + while (match = videoRegexp.exec(node.data)) { + const previousText = node.data.slice(parseFrom, match.index); + + outputNodes.push({ + type: 'text', + data: previousText, + i: node.i + parseFrom, + iEnd: node.i + parseFrom + match.index, + }); + + parseFrom = match.index + match[0].length; + + const videoNode = {type: 'video'}; + const attributes = html.parseAttributes(match[1]); + + videoNode.src = attributes.get('src'); + + if (attributes.get('width')) videoNode.width = parseInt(attributes.get('width')); + if (attributes.get('height')) videoNode.height = parseInt(attributes.get('height')); + if (attributes.get('align')) videoNode.align = attributes.get('align'); + if (attributes.get('pixelate')) videoNode.pixelate = true; + + outputNodes.push(videoNode); + } + + if (parseFrom !== node.data.length) { + outputNodes.push({ + type: 'text', + data: node.data.slice(parseFrom), + i: node.i + parseFrom, + iEnd: node.iEnd, + }); + } + } + + return outputNodes; +} + export function postprocessHeadings(inputNodes) { const outputNodes = []; @@ -760,6 +810,7 @@ export function parseInput(input) { let output = parseNodes(input, 0); output = postprocessComments(output); output = postprocessImages(output); + output = postprocessVideos(output); output = postprocessHeadings(output); output = postprocessSummaries(output); output = postprocessExternalLinks(output); |