diff --git a/client/icons/customIcons.less b/client/icons/customIcons.less index c288e6eb2..7525d50af 100644 --- a/client/icons/customIcons.less +++ b/client/icons/customIcons.less @@ -52,6 +52,12 @@ .book-part-cover { mask-image: url('../icons/book-part-cover.svg'); } +.image-wrap-left { + content: url('../icons/image-wrap-left.svg'); +} +.image-wrap-right { + content: url('../icons/image-wrap-right.svg'); +} .davek { mask-image: url('../icons/Davek.svg'); } diff --git a/client/icons/image-wrap-left.svg b/client/icons/image-wrap-left.svg new file mode 100644 index 000000000..fe1024e43 --- /dev/null +++ b/client/icons/image-wrap-left.svg @@ -0,0 +1,58 @@ + + diff --git a/client/icons/image-wrap-right.svg b/client/icons/image-wrap-right.svg new file mode 100644 index 000000000..336a20b64 --- /dev/null +++ b/client/icons/image-wrap-right.svg @@ -0,0 +1,58 @@ + + diff --git a/package-lock.json b/package-lock.json index 6863e9ece..6c926df8f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,7 +14,7 @@ "@babel/plugin-transform-runtime": "^7.25.4", "@babel/preset-env": "^7.25.4", "@babel/preset-react": "^7.24.7", - "@googleapis/drive": "^8.13.0", + "@googleapis/drive": "^8.13.1", "body-parser": "^1.20.2", "classnames": "^2.5.1", "codemirror": "^5.65.6", @@ -2091,9 +2091,9 @@ } }, "node_modules/@googleapis/drive": { - "version": "8.13.0", - "resolved": "https://registry.npmjs.org/@googleapis/drive/-/drive-8.13.0.tgz", - "integrity": "sha512-xpXzZeYtNNFLy1m2D5A8/QR2bngpjLPEvO5KZUW4Dlwi/SBHYNTjVm37IQagtQg6QUJlFb4lVLewenUdZZB1rA==", + "version": "8.13.1", + "resolved": "https://registry.npmjs.org/@googleapis/drive/-/drive-8.13.1.tgz", + "integrity": "sha512-ODfl4VUIKNox570DFA6AzAEHQcKI1EQs0xzzupeAIa+S/kFan85TItXU7XywK8mDORnfkgqwXQ5N/u/BFBj5lw==", "dependencies": { "googleapis-common": "^7.0.0" }, diff --git a/package.json b/package.json index 8c4264f3c..063fc83e9 100644 --- a/package.json +++ b/package.json @@ -89,7 +89,7 @@ "@babel/plugin-transform-runtime": "^7.25.4", "@babel/preset-env": "^7.25.4", "@babel/preset-react": "^7.24.7", - "@googleapis/drive": "^8.13.0", + "@googleapis/drive": "^8.13.1", "body-parser": "^1.20.2", "classnames": "^2.5.1", "codemirror": "^5.65.6", diff --git a/shared/naturalcrit/markdown.js b/shared/naturalcrit/markdown.js index f5a4b9a58..24b74689f 100644 --- a/shared/naturalcrit/markdown.js +++ b/shared/naturalcrit/markdown.js @@ -102,6 +102,20 @@ renderer.link = function (href, title, text) { return out; }; +// Expose `src` attribute as `--HB_src` to make the URL accessible via CSS +renderer.image = function (href, title, text) { + href = cleanUrl(href); + if (href === null) + return text; + + let out = `${text}{ }); it('Renders an image element with injected style', function() { - const source = '![alt text](http://i.imgur.com/hMna6G0.png){position:absolute}'; + const source = '![alt text](https://i.imgur.com/hMna6G0.png){position:absolute}'; const rendered = Markdown.render(source).trimReturns(); - expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('

alt text

'); + expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('

alt text

'); }); it('Renders an element modified by only the first of two consecutive injections', function() { @@ -343,19 +343,19 @@ describe('Injection: When an injection tag follows an element', ()=>{ it('Renders an image with added attributes', function() { const source = `![homebrew mug](https://i.imgur.com/hMna6G0.png) {position:absolute,bottom:20px,left:130px,width:220px,a="b and c",d=e}`; const rendered = Markdown.render(source).trimReturns(); - expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe(`

homebrew mug

`); + expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe(`

homebrew mug

`); }); it('Renders an image with "=" in the url, and added attributes', function() { const source = `![homebrew mug](https://i.imgur.com/hMna6G0.png?auth=12345&height=1024) {position:absolute,bottom:20px,left:130px,width:220px,a="b and c",d=e}`; const rendered = Markdown.render(source).trimReturns(); - expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe(`

homebrew mug

`); + expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe(`

homebrew mug

`); }); it('Renders an image and added attributes with "=" in the value, ', function() { const source = `![homebrew mug](https://i.imgur.com/hMna6G0.png) {position:absolute,bottom:20px,left:130px,width:220px,a="b and c",d=e,otherUrl="url?auth=12345"}`; const rendered = Markdown.render(source).trimReturns(); - expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe(`

homebrew mug

`); + expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe(`

homebrew mug

`); }); }); diff --git a/tests/markdown/variables.test.js b/tests/markdown/variables.test.js index 2c8db375e..bf778b14d 100644 --- a/tests/markdown/variables.test.js +++ b/tests/markdown/variables.test.js @@ -315,21 +315,21 @@ describe('Normal Links and Images', ()=>{ const source = `![alt text](url)`; const rendered = Markdown.render(source).trimReturns(); expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe(dedent` -

alt text

`.trimReturns()); +

alt text

`.trimReturns()); }); it('Renders normal images with a title', function() { const source = 'An image ![alt text](url "and title")!'; const rendered = Markdown.render(source).trimReturns(); expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe(dedent` -

An image alt text!

`.trimReturns()); +

An image alt text!

`.trimReturns()); }); it('Applies curly injectors to images', function() { const source = `![alt text](url){width:100px}`; const rendered = Markdown.render(source).trimReturns(); expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe(dedent` -

alt text

`.trimReturns()); +

alt text

`.trimReturns()); }); it('Renders normal links', function() { diff --git a/themes/V3/Blank/snippets.js b/themes/V3/Blank/snippets.js index 8d45560c5..8437dab2e 100644 --- a/themes/V3/Blank/snippets.js +++ b/themes/V3/Blank/snippets.js @@ -153,6 +153,18 @@ module.exports = [ gen : dedent` ![cat warrior](https://s-media-cache-ak0.pinimg.com/736x/4a/81/79/4a8179462cfdf39054a418efd4cb743e.jpg) {width:325px,mix-blend-mode:multiply}` }, + { + name : 'Image Wrap Left', + icon : 'fac image-wrap-left', + gen : dedent` + ![homebrewery_mug](http://i.imgur.com/hMna6G0.png) {width:280px,margin-right:-3cm,wrapLeft}` + }, + { + name : 'Image Wrap Right', + icon : 'fac image-wrap-right', + gen : dedent` + ![homebrewery_mug](http://i.imgur.com/hMna6G0.png) {width:280px,margin-left:-3cm,wrapRight}` + }, { name : 'Background Image', icon : 'fas fa-tree', diff --git a/themes/V3/Blank/style.less b/themes/V3/Blank/style.less index 18a478cf9..0f3766342 100644 --- a/themes/V3/Blank/style.less +++ b/themes/V3/Blank/style.less @@ -156,6 +156,19 @@ body { counter-reset : page-numbers; } break-inside : avoid; } + /* Wrap Text */ + .wrapLeft { + shape-outside : var(--HB_src); + float : right; + shape-margin : 0.2cm; + } + + .wrapRight { + shape-outside : var(--HB_src); + float : left; + shape-margin : 0.2cm; + } + /* Watermark */ .watermark { position : absolute;