diff --git a/changelog.md b/changelog.md index 3736ba9b0..8cfb499f6 100644 --- a/changelog.md +++ b/changelog.md @@ -77,14 +77,100 @@ pre { } .varSyntaxTable th:first-of-type { - width:6cm; + width:6cm; +} + +.page .exampleTable td,th { + border:1px dashed #00000030; } ``` - ## changelog For a full record of development, visit our [Github Page](https://github.com/naturalcrit/homebrewery). +### Thursday 01/30/2024 - v3.17.0 + +{{taskList +##### 5e-Cleric + +* [x] Update FAQ + +* [x] Fix styling for Vault buttons and checkboxes + +* [x] Improve navigation bar styling + +* [x] Add feature to change username at https://www.naturalcrit.com/account + +* [x] Fix Reddit link crash when title has non-latin chars + +##### dbolack + +* [x] Fix page shadows toolbar option + +Fixes issue [#3919](https://github.com/naturalcrit/homebrewery/issues/3919) + +* [x] Add `:>>>` syntax for horizontal :>>>>> spaces + +* [x] Update Docker install instructions + +Fixes issue [#1930](https://github.com/naturalcrit/homebrewery/issues/1930) + +* [x] Allow styling pages via `\page{myStyles}` (with calculuschild) + +Fixes issue [#3901](https://github.com/naturalcrit/homebrewery/issues/3901) + +* [x] Update Ubuntu install instructions + +Fixes issue [#1952](https://github.com/naturalcrit/homebrewery/issues/1952) + +* [x] Add `:-:` `:-` `-:` syntax for paragraph alignment, similar to table column alignment; for example: + +-: -: Right-aligned + +:-: :-: Centered + +* [x] Add `:-- 50% --:` syntax to allow setting table column widths by percentage; for example: +``` +| Narrow | Wide | +|:- 10% -:|:-90%--:| +| Cell | Cell | +``` + + +| Narrow | Wide | +|:- 10% -:|:-90%--:| +|Cell | Cell | +{exampleTable} + +##### G-Ambatte + +* [x] Fix crash when opening brew Properties tab + +Fixes issue [#3927](https://github.com/naturalcrit/homebrewery/issues/3927) + +* [x] Update error pages with steps to refresh credentials + +Fixes issue [#3955](https://github.com/naturalcrit/homebrewery/issues/3955) + +* [x] Add {{openSans :fas_rectangle_list: **NAVIGATION**}} menu to the viewer toolbar + +##### calculuschild + +* [x] Reduce display lag on large brews + +##### Gazook89 + +* [x] Smarter detection of current page number + +Fixes issue [#3824](https://github.com/naturalcrit/homebrewery/issues/3824) + +##### All +* [x] Update dependencies and scripts +* [x] Refactor components and fix various errors +}} + +\column + ### Wednesday 11/27/2024 - v3.16.1 {{taskList @@ -131,6 +217,8 @@ Fixes issue [#3744](https://github.com/naturalcrit/homebrewery/issues/3744) * [x] Multiple code refactors, cleanups, and security fixes }} +\page + ### Saturday 10/12/2024 - v3.16.0 {{taskList @@ -2053,4 +2141,4 @@ Massive changelog incoming: * Added `phb.standalone.css` plus a build system for creating it * Added page numbers and footer text -* Page accent now flips each page +* Page accent now flips each page \ No newline at end of file diff --git a/client/homebrew/brewRenderer/brewRenderer.jsx b/client/homebrew/brewRenderer/brewRenderer.jsx index 17f261c2d..a82ea8b34 100644 --- a/client/homebrew/brewRenderer/brewRenderer.jsx +++ b/client/homebrew/brewRenderer/brewRenderer.jsx @@ -17,10 +17,9 @@ const dedent = require('dedent-tabs').default; const { printCurrentBrew } = require('../../../shared/helpers.js'); import HeaderNav from './headerNav/headerNav.jsx'; - import { safeHTML } from './safeHTML.js'; - +const PAGEBREAK_REGEX_V3 = /^(?=\\page(?: *{[^\n{}]*})?$)/m; const PAGE_HEIGHT = 1056; const INITIAL_CONTENT = dedent` @@ -78,7 +77,7 @@ const BrewPage = (props)=>{ }; }, []); - return
+ return
; }; @@ -126,7 +125,7 @@ const BrewRenderer = (props)=>{ if(props.renderer == 'legacy') { rawPages = props.text.split('\\page'); } else { - rawPages = props.text.split(/^\\page$/gm); + rawPages = props.text.split(PAGEBREAK_REGEX_V3); } const handlePageVisibilityChange = (pageNum, isVisible, isCenter)=>{ @@ -173,20 +172,34 @@ const BrewRenderer = (props)=>{ const renderPage = (pageText, index)=>{ - const styles = { + let styles = { ...(!displayOptions.pageShadows ? { boxShadow: 'none' } : {}) // Add more conditions as needed }; + let classes = 'page'; + let attributes = {}; if(props.renderer == 'legacy') { const html = MarkdownLegacy.render(pageText); return ; } else { + if(pageText.startsWith('\\page')) { + const firstLineTokens = Markdown.marked.lexer(pageText.split('\n', 1)[0])[0].tokens; + const injectedTags = firstLineTokens.find((obj)=>obj.injectedTags !== undefined)?.injectedTags; + if(injectedTags) { + styles = { ...styles, ...injectedTags.styles }; + styles = _.mapKeys(styles, (v, k) => k.startsWith('--') ? k : _.camelCase(k)); // Convert CSS to camelCase for React + classes = [classes, injectedTags.classes].join(' ').trim(); + attributes = injectedTags.attributes; + } + pageText = pageText.includes('\n') ? pageText.substring(pageText.indexOf('\n') + 1) : ''; // Remove the \page line + } + pageText += `\n\n \n\\column\n `; //Artificial column break at page end to emulate column-fill:auto (until `wide` is used, when column-fill:balance will reappear) const html = Markdown.render(pageText, index); - return ; + return ; } }; diff --git a/client/homebrew/editor/editor.jsx b/client/homebrew/editor/editor.jsx index bba5f3ad9..2d0a26268 100644 --- a/client/homebrew/editor/editor.jsx +++ b/client/homebrew/editor/editor.jsx @@ -12,7 +12,8 @@ const MetadataEditor = require('./metadataEditor/metadataEditor.jsx'); const EDITOR_THEME_KEY = 'HOMEBREWERY-EDITOR-THEME'; -const SNIPPETBAR_HEIGHT = 25; +const PAGEBREAK_REGEX_V3 = /^(?=\\page(?: *{[^\n{}]*})?$)/m; +const SNIPPETBAR_HEIGHT = 25; const DEFAULT_STYLE_TEXT = dedent` /*=======--- Example CSS styling ---=======*/ /* Any CSS here will apply to your document! */ @@ -126,15 +127,15 @@ const Editor = createClass({ }, updateCurrentCursorPage : function(cursor) { - const lines = this.props.brew.text.split('\n').slice(0, cursor.line + 1); - const pageRegex = this.props.brew.renderer == 'V3' ? /^\\page$/ : /\\page/; + const lines = this.props.brew.text.split('\n').slice(1, cursor.line + 1); + const pageRegex = this.props.brew.renderer == 'V3' ? PAGEBREAK_REGEX_V3 : /\\page/; const currentPage = lines.reduce((count, line)=>count + (pageRegex.test(line) ? 1 : 0), 1); this.props.onCursorPageChange(currentPage); }, updateCurrentViewPage : function(topScrollLine) { - const lines = this.props.brew.text.split('\n').slice(0, topScrollLine + 1); - const pageRegex = this.props.brew.renderer == 'V3' ? /^\\page$/ : /\\page/; + const lines = this.props.brew.text.split('\n').slice(1, topScrollLine + 1); + const pageRegex = this.props.brew.renderer == 'V3' ? PAGEBREAK_REGEX_V3 : /\\page/; const currentPage = lines.reduce((count, line)=>count + (pageRegex.test(line) ? 1 : 0), 1); this.props.onViewPageChange(currentPage); }, @@ -174,7 +175,7 @@ const Editor = createClass({ for (let i=customHighlights.length - 1;i>=0;i--) customHighlights[i].clear(); - let editorPageCount = 2; // start page count from page 2 + let editorPageCount = 1; // start page count from page 1 _.forEach(this.props.brew.text.split('\n'), (line, lineNumber)=>{ @@ -190,7 +191,10 @@ const Editor = createClass({ // Styling for \page breaks if((this.props.renderer == 'legacy' && line.includes('\\page')) || - (this.props.renderer == 'V3' && line.match(/^\\page$/))) { + (this.props.renderer == 'V3' && line.match(PAGEBREAK_REGEX_V3))) { + + if(lineNumber > 0) // Since \page is optional on first line of document, + editorPageCount += 1; // don't use it to increment page count; stay at 1 // add back the original class 'background' but also add the new class '.pageline' codeMirror.addLineClass(lineNumber, 'background', 'pageLine'); @@ -199,8 +203,6 @@ const Editor = createClass({ textContent : editorPageCount }); codeMirror.setBookmark({ line: lineNumber, ch: line.length }, pageCountElement); - - editorPageCount += 1; }; // New Codemirror styling for V3 renderer @@ -358,7 +360,7 @@ const Editor = createClass({ if(!this.isText() || isJumping) return; - const textSplit = this.props.renderer == 'V3' ? /^\\page$/gm : /\\page/; + const textSplit = this.props.renderer == 'V3' ? PAGEBREAK_REGEX_V3 : /\\page/; const textString = this.props.brew.text.split(textSplit).slice(0, targetPage-1).join(textSplit); const targetLine = textString.match('\n') ? textString.split('\n').length - 1 : -1; diff --git a/package-lock.json b/package-lock.json index 281c24b1f..643d1f0e3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "homebrewery", - "version": "3.16.1", + "version": "3.17.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "homebrewery", - "version": "3.16.1", + "version": "3.17.0", "hasInstallScript": true, "license": "MIT", "dependencies": { @@ -23,7 +23,7 @@ "cors": "^2.8.5", "create-react-class": "^15.7.0", "dedent-tabs": "^0.10.3", - "dompurify": "^3.2.3", + "dompurify": "^3.2.4", "expr-eval": "^2.0.2", "express": "^4.21.2", "express-async-handler": "^1.2.0", @@ -34,11 +34,11 @@ "jwt-simple": "^0.5.6", "less": "^3.13.1", "lodash": "^4.17.21", - "marked": "11.2.0", + "marked": "13.0.3", "marked-emoji": "^1.4.3", "marked-extended-tables": "^1.1.0", - "marked-gfm-heading-id": "^3.2.0", - "marked-smartypants-lite": "^1.0.2", + "marked-gfm-heading-id": "^4.0.1", + "marked-smartypants-lite": "^1.0.3", "markedLegacy": "npm:marked@^0.3.19", "moment": "^2.30.1", "mongoose": "^8.9.5", @@ -47,7 +47,7 @@ "react": "^18.3.1", "react-dom": "^18.3.1", "react-frame-component": "^4.1.3", - "react-router": "^7.1.3", + "react-router": "^7.1.4", "sanitize-filename": "1.6.3", "superagent": "^10.1.1", "vitreum": "git+https://git@github.com/calculuschild/vitreum.git" @@ -3837,16 +3837,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/bindings": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", - "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", - "license": "MIT", - "optional": true, - "dependencies": { - "file-uri-to-path": "1.0.0" - } - }, "node_modules/bn.js": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.1.tgz", @@ -5323,9 +5313,10 @@ } }, "node_modules/dompurify": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.2.3.tgz", - "integrity": "sha512-U1U5Hzc2MO0oW3DF+G9qYN0aT7atAou4AgI0XjWz061nyBPbdxkfdhfy5uMgGn6+oLFCfn44ZGbdDqCzVmlOWA==", + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.2.4.tgz", + "integrity": "sha512-ysFSFEDVduQpyhzAob/kkuJjf5zWkZD8/A9ywSp1byueyuCfHamrCBa14/Oc2iiB0e51B+NpxSl5gmzn+Ms/mg==", + "license": "(MPL-2.0 OR Apache-2.0)", "optionalDependencies": { "@types/trusted-types": "^2.0.7" } @@ -6337,13 +6328,6 @@ "node": ">=16.0.0" } }, - "node_modules/file-uri-to-path": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", - "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==", - "license": "MIT", - "optional": true - }, "node_modules/fill-range": { "version": "7.1.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", @@ -6517,20 +6501,6 @@ "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", "license": "ISC" }, - "node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "hasInstallScript": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, "node_modules/function-bind": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", @@ -9819,9 +9789,9 @@ } }, "node_modules/marked": { - "version": "11.2.0", - "resolved": "https://registry.npmjs.org/marked/-/marked-11.2.0.tgz", - "integrity": "sha512-HR0m3bvu0jAPYiIvLUUQtdg1g6D247//lvcekpHO1WMvbwDlwSkZAX9Lw4F4YHE1T0HaaNve0tuAWuV1UJ6vtw==", + "version": "13.0.3", + "resolved": "https://registry.npmjs.org/marked/-/marked-13.0.3.tgz", + "integrity": "sha512-rqRix3/TWzE9rIoFGIn8JmsVfhiuC8VIQ8IdX5TfzmeBucdY05/0UlzKaw0eVtpcN/OdVFpBk7CjKGo9iHJ/zA==", "license": "MIT", "bin": { "marked": "bin/marked.js" @@ -9847,24 +9817,24 @@ } }, "node_modules/marked-gfm-heading-id": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/marked-gfm-heading-id/-/marked-gfm-heading-id-3.2.0.tgz", - "integrity": "sha512-Xfxpr5lXLDLY10XqzSCA9l2dDaiabQUgtYM9hw8yunyVsB/xYBRpiic6BOiY/EAJw1ik1eWr1ET1HKOAPZBhXg==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/marked-gfm-heading-id/-/marked-gfm-heading-id-4.1.1.tgz", + "integrity": "sha512-EeQZieAQmsI6c2tWLx0ETd0VjPwLV8qi+HT0dIsfVMERm0rCIuXfRvZXJbo1SgUi++lmuR1LVY+QzgNiLNvVpw==", "license": "MIT", "dependencies": { "github-slugger": "^2.0.0" }, "peerDependencies": { - "marked": ">=4 <13" + "marked": ">=13 <16" } }, "node_modules/marked-smartypants-lite": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/marked-smartypants-lite/-/marked-smartypants-lite-1.0.2.tgz", - "integrity": "sha512-cEANts+s3+gnTzXPvPT2z4V8NfbMEL9QooKUviug0DkaKkXQWrUwDAmFnQAkLSJCw2BQcD8YPDyxu0HJ3mg36w==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/marked-smartypants-lite/-/marked-smartypants-lite-1.0.3.tgz", + "integrity": "sha512-OOL8cjFog8KtgUFpkihRu6G42Dz2QPOU4k2xfKmMJ0CdoX+BHBDmdesHUdoQKM0mlwTsRSU3shpMeM/LWuUokg==", "license": "MIT", "peerDependencies": { - "marked": ">=4 <12" + "marked": ">=4 <16" } }, "node_modules/markedLegacy": { @@ -10365,13 +10335,6 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" }, - "node_modules/nan": { - "version": "2.20.0", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.20.0.tgz", - "integrity": "sha512-bk3gXBZDGILuuo/6sKtr0DQmSThYHLtNCdSdXk9YkxD/jK6X2vmCyyXBBxyqZ4XcnzTyYEAThfX3DCEnLf6igw==", - "license": "MIT", - "optional": true - }, "node_modules/nanoid": { "version": "5.0.9", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-5.0.9.tgz", @@ -11646,9 +11609,10 @@ "license": "MIT" }, "node_modules/react-router": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/react-router/-/react-router-7.1.3.tgz", - "integrity": "sha512-EezYymLY6Guk/zLQ2vRA8WvdUhWFEj5fcE3RfWihhxXBW7+cd1LsIiA3lmx+KCmneAGQuyBv820o44L2+TtkSA==", + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-7.1.4.tgz", + "integrity": "sha512-aJWVrKoLI0nIK1lfbTU3d5al1ZEUiwtSus/xjYL8K5sv2hyPesiOIojHM7QnaNLVtroOB1McZsWk37fMQVoc6A==", + "license": "MIT", "dependencies": { "@types/cookie": "^0.6.0", "cookie": "^1.0.1", @@ -14429,25 +14393,6 @@ "node": ">=0.10.0" } }, - "node_modules/watchify/node_modules/fsevents": { - "version": "1.2.13", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz", - "integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==", - "deprecated": "The v1 package contains DANGEROUS / INSECURE binaries. Upgrade to safe fsevents v2", - "hasInstallScript": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "dependencies": { - "bindings": "^1.5.0", - "nan": "^2.12.1" - }, - "engines": { - "node": ">= 4.0" - } - }, "node_modules/watchify/node_modules/glob-parent": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", diff --git a/package.json b/package.json index 840975977..cd43bb5e2 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "homebrewery", "description": "Create authentic looking D&D homebrews using only markdown", - "version": "3.16.1", + "version": "3.17.0", "type": "module", "engines": { "npm": "^10.2.x", @@ -98,7 +98,7 @@ "cors": "^2.8.5", "create-react-class": "^15.7.0", "dedent-tabs": "^0.10.3", - "dompurify": "^3.2.3", + "dompurify": "^3.2.4", "expr-eval": "^2.0.2", "express": "^4.21.2", "express-async-handler": "^1.2.0", @@ -109,11 +109,11 @@ "jwt-simple": "^0.5.6", "less": "^3.13.1", "lodash": "^4.17.21", - "marked": "11.2.0", + "marked": "13.0.3", "marked-emoji": "^1.4.3", "marked-extended-tables": "^1.1.0", - "marked-gfm-heading-id": "^3.2.0", - "marked-smartypants-lite": "^1.0.2", + "marked-gfm-heading-id": "^4.0.1", + "marked-smartypants-lite": "^1.0.3", "markedLegacy": "npm:marked@^0.3.19", "moment": "^2.30.1", "mongoose": "^8.9.5", @@ -122,7 +122,7 @@ "react": "^18.3.1", "react-dom": "^18.3.1", "react-frame-component": "^4.1.3", - "react-router": "^7.1.3", + "react-router": "^7.1.4", "sanitize-filename": "1.6.3", "superagent": "^10.1.1", "vitreum": "git+https://git@github.com/calculuschild/vitreum.git"