0
0
mirror of https://github.com/naturalcrit/homebrewery.git synced 2025-12-24 20:42:43 +00:00

Merge branch 'master' into fix-editor-overflow

This commit is contained in:
Trevor Buckner
2025-04-08 13:22:26 -04:00
committed by GitHub
16 changed files with 530 additions and 437 deletions

View File

@@ -186,7 +186,7 @@ const BrewRenderer = (props)=>{
} 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;
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

241
package-lock.json generated
View File

@@ -10,11 +10,11 @@
"hasInstallScript": true,
"license": "MIT",
"dependencies": {
"@babel/core": "^7.26.9",
"@babel/plugin-transform-runtime": "^7.26.9",
"@babel/core": "^7.26.10",
"@babel/plugin-transform-runtime": "^7.26.10",
"@babel/preset-env": "^7.26.9",
"@babel/preset-react": "^7.26.3",
"@googleapis/drive": "^8.16.0",
"@googleapis/drive": "^11.0.0",
"body-parser": "^1.20.2",
"classnames": "^2.5.1",
"codemirror": "^5.65.6",
@@ -33,7 +33,7 @@
"jwt-simple": "^0.5.6",
"less": "^3.13.1",
"lodash": "^4.17.21",
"marked": "14.0.0",
"marked": "15.0.0",
"marked-emoji": "^2.0.0",
"marked-extended-tables": "^2.0.1",
"marked-gfm-heading-id": "^4.0.1",
@@ -41,21 +41,23 @@
"marked-subsuper-text": "^1.0.3",
"markedLegacy": "npm:marked@^0.3.19",
"moment": "^2.30.1",
"mongoose": "^8.12.1",
"nanoid": "5.1.3",
"mongoose": "^8.13.0",
"nanoid": "5.1.5",
"nconf": "^0.12.1",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-frame-component": "^4.1.3",
"react-router": "^7.3.0",
"react-router": "^7.4.0",
"romans": "^3.0.0",
"sanitize-filename": "1.6.3",
"superagent": "^10.1.1",
"vitreum": "git+https://git@github.com/calculuschild/vitreum.git"
"superagent": "^10.2.0",
"vitreum": "git+https://git@github.com/calculuschild/vitreum.git",
"written-number": "^0.11.1"
},
"devDependencies": {
"@stylistic/stylelint-plugin": "^3.1.2",
"babel-plugin-transform-import-meta": "^2.3.2",
"eslint": "^9.22.0",
"eslint": "^9.23.0",
"eslint-plugin-jest": "^28.11.0",
"eslint-plugin-react": "^7.37.4",
"globals": "^16.0.0",
@@ -63,10 +65,10 @@
"jest-expect-message": "^1.1.3",
"jsdom-global": "^3.0.2",
"postcss-less": "^6.0.0",
"stylelint": "^16.16.0",
"stylelint": "^16.17.0",
"stylelint-config-recess-order": "^6.0.0",
"stylelint-config-recommended": "^15.0.0",
"supertest": "^7.0.0"
"supertest": "^7.1.0"
},
"engines": {
"node": "^20.18.x",
@@ -110,21 +112,21 @@
}
},
"node_modules/@babel/core": {
"version": "7.26.9",
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.26.9.tgz",
"integrity": "sha512-lWBYIrF7qK5+GjY5Uy+/hEgp8OJWOD/rpy74GplYRhEauvbHDeFB8t5hPOZxCZ0Oxf4Cc36tK51/l3ymJysrKw==",
"version": "7.26.10",
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.26.10.tgz",
"integrity": "sha512-vMqyb7XCDMPvJFFOaT9kxtiRh42GwlZEg1/uIgtZshS5a/8OaduUfCi7kynKgc3Tw/6Uo2D+db9qBttghhmxwQ==",
"license": "MIT",
"dependencies": {
"@ampproject/remapping": "^2.2.0",
"@babel/code-frame": "^7.26.2",
"@babel/generator": "^7.26.9",
"@babel/generator": "^7.26.10",
"@babel/helper-compilation-targets": "^7.26.5",
"@babel/helper-module-transforms": "^7.26.0",
"@babel/helpers": "^7.26.9",
"@babel/parser": "^7.26.9",
"@babel/helpers": "^7.26.10",
"@babel/parser": "^7.26.10",
"@babel/template": "^7.26.9",
"@babel/traverse": "^7.26.9",
"@babel/types": "^7.26.9",
"@babel/traverse": "^7.26.10",
"@babel/types": "^7.26.10",
"convert-source-map": "^2.0.0",
"debug": "^4.1.0",
"gensync": "^1.0.0-beta.2",
@@ -140,13 +142,13 @@
}
},
"node_modules/@babel/generator": {
"version": "7.26.9",
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.26.9.tgz",
"integrity": "sha512-kEWdzjOAUMW4hAyrzJ0ZaTOu9OmpyDIQicIh0zg0EEcEkYXZb2TjtBhnHi2ViX7PKwZqF4xwqfAm299/QMP3lg==",
"version": "7.27.0",
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.27.0.tgz",
"integrity": "sha512-VybsKvpiN1gU1sdMZIp7FcqphVVKEwcuj02x73uvcHE0PTihx1nlBcowYWhDwjpoAXRv43+gDzyggGnn1XZhVw==",
"license": "MIT",
"dependencies": {
"@babel/parser": "^7.26.9",
"@babel/types": "^7.26.9",
"@babel/parser": "^7.27.0",
"@babel/types": "^7.27.0",
"@jridgewell/gen-mapping": "^0.3.5",
"@jridgewell/trace-mapping": "^0.3.25",
"jsesc": "^3.0.2"
@@ -389,12 +391,12 @@
}
},
"node_modules/@babel/parser": {
"version": "7.26.9",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.26.9.tgz",
"integrity": "sha512-81NWa1njQblgZbQHxWHpxxCzNsa3ZwvFqpUg7P+NNUU6f3UU2jBEg4OlF/J6rl8+PQGh1q6/zWScd001YwcA5A==",
"version": "7.27.0",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.27.0.tgz",
"integrity": "sha512-iaepho73/2Pz7w2eMS0Q5f83+0RKI7i4xmiYeBmDzfRVbQtTOG7Ts0S4HzJVsTMGI9keU8rNfuZr8DKfSt7Yyg==",
"license": "MIT",
"dependencies": {
"@babel/types": "^7.26.9"
"@babel/types": "^7.27.0"
},
"bin": {
"parser": "bin/babel-parser.js"
@@ -1406,15 +1408,15 @@
}
},
"node_modules/@babel/plugin-transform-runtime": {
"version": "7.26.9",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.26.9.tgz",
"integrity": "sha512-Jf+8y9wXQbbxvVYTM8gO5oEF2POdNji0NMltEkG7FtmzD9PVz7/lxpqSdTvwsjTMU5HIHuDVNf2SOxLkWi+wPQ==",
"version": "7.26.10",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.26.10.tgz",
"integrity": "sha512-NWaL2qG6HRpONTnj4JvDU6th4jYeZOJgu3QhmFTCihib0ermtOJqktA5BduGm3suhhVe9EMP9c9+mfJ/I9slqw==",
"license": "MIT",
"dependencies": {
"@babel/helper-module-imports": "^7.25.9",
"@babel/helper-plugin-utils": "^7.26.5",
"babel-plugin-polyfill-corejs2": "^0.4.10",
"babel-plugin-polyfill-corejs3": "^0.10.6",
"babel-plugin-polyfill-corejs3": "^0.11.0",
"babel-plugin-polyfill-regenerator": "^0.6.1",
"semver": "^6.3.1"
},
@@ -1640,19 +1642,6 @@
"@babel/core": "^7.0.0-0"
}
},
"node_modules/@babel/preset-env/node_modules/babel-plugin-polyfill-corejs3": {
"version": "0.11.1",
"resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.11.1.tgz",
"integrity": "sha512-yGCqvBT4rwMczo28xkH/noxJ6MZ4nJfkVYdoDaC/utLtWrXxv27HVrzAeSbqR8SxDsp46n0YF47EbHoixy6rXQ==",
"license": "MIT",
"dependencies": {
"@babel/helper-define-polyfill-provider": "^0.6.3",
"core-js-compat": "^3.40.0"
},
"peerDependencies": {
"@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0"
}
},
"node_modules/@babel/preset-modules": {
"version": "0.1.6-no-external-plugins",
"resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.6-no-external-plugins.tgz",
@@ -1700,30 +1689,30 @@
}
},
"node_modules/@babel/template": {
"version": "7.26.9",
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.26.9.tgz",
"integrity": "sha512-qyRplbeIpNZhmzOysF/wFMuP9sctmh2cFzRAZOn1YapxBsE1i9bJIY586R/WBLfLcmcBlM8ROBiQURnnNy+zfA==",
"version": "7.27.0",
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.0.tgz",
"integrity": "sha512-2ncevenBqXI6qRMukPlXwHKHchC7RyMuu4xv5JBXRfOGVcTy1mXCD12qrp7Jsoxll1EV3+9sE4GugBVRjT2jFA==",
"license": "MIT",
"dependencies": {
"@babel/code-frame": "^7.26.2",
"@babel/parser": "^7.26.9",
"@babel/types": "^7.26.9"
"@babel/parser": "^7.27.0",
"@babel/types": "^7.27.0"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/traverse": {
"version": "7.26.9",
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.26.9.tgz",
"integrity": "sha512-ZYW7L+pL8ahU5fXmNbPF+iZFHCv5scFak7MZ9bwaRPLUhHh7QQEMjZUg0HevihoqCM5iSYHN61EyCoZvqC+bxg==",
"version": "7.27.0",
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.27.0.tgz",
"integrity": "sha512-19lYZFzYVQkkHkl4Cy4WrAVcqBkgvV2YM2TU3xG6DIwO7O3ecbDPfW3yM3bjAGcqcQHi+CCtjMR3dIEHxsd6bA==",
"license": "MIT",
"dependencies": {
"@babel/code-frame": "^7.26.2",
"@babel/generator": "^7.26.9",
"@babel/parser": "^7.26.9",
"@babel/template": "^7.26.9",
"@babel/types": "^7.26.9",
"@babel/generator": "^7.27.0",
"@babel/parser": "^7.27.0",
"@babel/template": "^7.27.0",
"@babel/types": "^7.27.0",
"debug": "^4.3.1",
"globals": "^11.1.0"
},
@@ -1741,9 +1730,9 @@
}
},
"node_modules/@babel/types": {
"version": "7.26.10",
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.26.10.tgz",
"integrity": "sha512-emqcG3vHrpxUKTrxcblR36dcrcoRDvKmnL/dCL6ZsHaShW80qxCAcNhzQZrpeM765VzEos+xOi4s+r4IXzTwdQ==",
"version": "7.27.0",
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.27.0.tgz",
"integrity": "sha512-H45s8fVLYjbhFH62dIJ3WtmJ6RSPt/3DRO0ZcT2SUiYiQyz3BLVb9ADEnLl91m74aQPS3AzzeajZHYOalWe3bg==",
"license": "MIT",
"dependencies": {
"@babel/helper-string-parser": "^7.25.9",
@@ -1878,9 +1867,9 @@
}
},
"node_modules/@eslint/config-helpers": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.1.0.tgz",
"integrity": "sha512-kLrdPDJE1ckPo94kmPPf9Hfd0DU0Jw6oKYrhe+pwSC0iTUInmTa+w6fw8sGgcfkFJGNdWOUeOaDM4quW4a7OkA==",
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.2.0.tgz",
"integrity": "sha512-yJLLmLexii32mGrhW29qvU3QBVTu0GUmEf/J4XsBtVhp4JkIUFN/BjWqTF63yRvGApIDpZm5fa97LtYtINmfeQ==",
"dev": true,
"license": "Apache-2.0",
"engines": {
@@ -1901,9 +1890,9 @@
}
},
"node_modules/@eslint/eslintrc": {
"version": "3.3.0",
"resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.0.tgz",
"integrity": "sha512-yaVPAiNAalnCZedKLdR21GOGILMLKPyqSLWaAjQFvYA2i/ciDi8ArYVr69Anohb6cH2Ukhqti4aFnYyPm8wdwQ==",
"version": "3.3.1",
"resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.1.tgz",
"integrity": "sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -1938,9 +1927,9 @@
}
},
"node_modules/@eslint/js": {
"version": "9.22.0",
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.22.0.tgz",
"integrity": "sha512-vLFajx9o8d1/oL2ZkpMYbkLv8nDB6yaIwFNt7nI4+I80U/z03SxmfOMsLbvWr3p7C+Wnoh//aOu2pQW8cS0HCQ==",
"version": "9.23.0",
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.23.0.tgz",
"integrity": "sha512-35MJ8vCPU0ZMxo7zfev2pypqTwWTofFZO6m4KAtdoFhRpLJUpHTZZ+KB3C7Hb1d7bULYwO4lJXGCi5Se+8OMbw==",
"dev": true,
"license": "MIT",
"engines": {
@@ -1972,9 +1961,9 @@
}
},
"node_modules/@googleapis/drive": {
"version": "8.16.0",
"resolved": "https://registry.npmjs.org/@googleapis/drive/-/drive-8.16.0.tgz",
"integrity": "sha512-Xi2mMrUTQ+gsfyouRGd0pfnL+jjg4n4sjKsJruM1y4DknuRfdSBTk5E//WrL0YJ/CqpcBgyd7L8DvaPRtxZD3Q==",
"version": "11.0.0",
"resolved": "https://registry.npmjs.org/@googleapis/drive/-/drive-11.0.0.tgz",
"integrity": "sha512-vhkl6/MZ8k5h5XOyenWOD4ys+SNdb8wKYvzU6OBGFx/TzJyHRm4JwgvE8uVDFU6efzNRS0mOiNRfY6nrmHOTtg==",
"license": "Apache-2.0",
"dependencies": {
"googleapis-common": "^7.0.0"
@@ -3140,9 +3129,9 @@
}
},
"node_modules/acorn": {
"version": "8.14.0",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz",
"integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==",
"version": "8.14.1",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.1.tgz",
"integrity": "sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==",
"dev": true,
"license": "MIT",
"bin": {
@@ -3704,12 +3693,13 @@
}
},
"node_modules/babel-plugin-polyfill-corejs3": {
"version": "0.10.6",
"resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.10.6.tgz",
"integrity": "sha512-b37+KR2i/khY5sKmWNVQAnitvquQbNdWy6lJdsr0kmquCKEEUgMKK4SboVM3HtfnZilfjr4MMQ7vY58FVWDtIA==",
"version": "0.11.1",
"resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.11.1.tgz",
"integrity": "sha512-yGCqvBT4rwMczo28xkH/noxJ6MZ4nJfkVYdoDaC/utLtWrXxv27HVrzAeSbqR8SxDsp46n0YF47EbHoixy6rXQ==",
"license": "MIT",
"dependencies": {
"@babel/helper-define-polyfill-provider": "^0.6.2",
"core-js-compat": "^3.38.0"
"@babel/helper-define-polyfill-provider": "^0.6.3",
"core-js-compat": "^3.40.0"
},
"peerDependencies": {
"@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0"
@@ -5697,19 +5687,19 @@
"license": "MIT"
},
"node_modules/eslint": {
"version": "9.22.0",
"resolved": "https://registry.npmjs.org/eslint/-/eslint-9.22.0.tgz",
"integrity": "sha512-9V/QURhsRN40xuHXWjV64yvrzMjcz7ZyNoF2jJFmy9j/SLk0u1OLSZgXi28MrXjymnjEGSR80WCdab3RGMDveQ==",
"version": "9.23.0",
"resolved": "https://registry.npmjs.org/eslint/-/eslint-9.23.0.tgz",
"integrity": "sha512-jV7AbNoFPAY1EkFYpLq5bslU9NLNO8xnEeQXwErNibVryjk67wHVmddTBilc5srIttJDBrB0eMHKZBFbSIABCw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@eslint-community/eslint-utils": "^4.2.0",
"@eslint-community/regexpp": "^4.12.1",
"@eslint/config-array": "^0.19.2",
"@eslint/config-helpers": "^0.1.0",
"@eslint/config-helpers": "^0.2.0",
"@eslint/core": "^0.12.0",
"@eslint/eslintrc": "^3.3.0",
"@eslint/js": "9.22.0",
"@eslint/eslintrc": "^3.3.1",
"@eslint/js": "9.23.0",
"@eslint/plugin-kit": "^0.2.7",
"@humanfs/node": "^0.16.6",
"@humanwhocodes/module-importer": "^1.0.1",
@@ -9904,9 +9894,9 @@
}
},
"node_modules/marked": {
"version": "14.0.0",
"resolved": "https://registry.npmjs.org/marked/-/marked-14.0.0.tgz",
"integrity": "sha512-uIj4+faQ+MgHgwUW1l2PsPglZLOLOT1uErt06dAPtx2kjteLAkbsd/0FiYg/MGS+i7ZKLb7w2WClxHkzOOuryQ==",
"version": "15.0.0",
"resolved": "https://registry.npmjs.org/marked/-/marked-15.0.0.tgz",
"integrity": "sha512-0mouKmBROJv/WSHJBPZZyYofUgawMChnD5je/g+aOBXsHDjb/IsnTQj7mnhQZu+qPJmRQ0ecX3mLGEUm3BgwYA==",
"license": "MIT",
"bin": {
"marked": "bin/marked.js"
@@ -10284,9 +10274,9 @@
}
},
"node_modules/mongodb-connection-string-url/node_modules/tr46": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/tr46/-/tr46-5.0.0.tgz",
"integrity": "sha512-tk2G5R2KRwBd+ZN0zaEXpmzdKyOYksXwywulIX95MBODjSzMIuQnQ3m8JxgbhnL1LeVo7lqQKsYa1O3Htl7K5g==",
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/tr46/-/tr46-5.1.0.tgz",
"integrity": "sha512-IUWnUK7ADYR5Sl1fZlO1INDUhVhatWl7BtJWsIhwJ0UAK7ilzzIa8uIqOO/aYVWHZPJkKbEL+362wrzoeRF7bw==",
"license": "MIT",
"dependencies": {
"punycode": "^2.3.1"
@@ -10305,12 +10295,12 @@
}
},
"node_modules/mongodb-connection-string-url/node_modules/whatwg-url": {
"version": "14.1.1",
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-14.1.1.tgz",
"integrity": "sha512-mDGf9diDad/giZ/Sm9Xi2YcyzaFpbdLpJPr+E9fSkyQ7KpQD4SdFcugkRQYzhmfI4KeV4Qpnn2sKPdo+kmsgRQ==",
"version": "14.2.0",
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-14.2.0.tgz",
"integrity": "sha512-De72GdQZzNTUBBChsXueQUnPKDkg/5A5zp7pFDuQAj5UFoENpiACU0wlCvzpAGnTkj++ihpKwKyYewn/XNUbKw==",
"license": "MIT",
"dependencies": {
"tr46": "^5.0.0",
"tr46": "^5.1.0",
"webidl-conversions": "^7.0.0"
},
"engines": {
@@ -10318,14 +10308,14 @@
}
},
"node_modules/mongoose": {
"version": "8.12.1",
"resolved": "https://registry.npmjs.org/mongoose/-/mongoose-8.12.1.tgz",
"integrity": "sha512-UW22y8QFVYmrb36hm8cGncfn4ARc/XsYWQwRTaj0gxtQk1rDuhzDO1eBantS+hTTatfAIS96LlRCJrcNHvW5+Q==",
"version": "8.13.0",
"resolved": "https://registry.npmjs.org/mongoose/-/mongoose-8.13.0.tgz",
"integrity": "sha512-e/iYV1mPeOkg+SWAMHzt3t42/EZyER3OB1H2pjP9C3vQ+Qb5DMeV9Kb+YCUycKgScA3fbwL7dKG4EpinGlg21g==",
"license": "MIT",
"dependencies": {
"bson": "^6.10.3",
"kareem": "2.6.3",
"mongodb": "~6.14.0",
"mongodb": "~6.15.0",
"mpath": "0.9.0",
"mquery": "5.0.0",
"ms": "2.1.3",
@@ -10401,9 +10391,9 @@
}
},
"node_modules/mongoose/node_modules/mongodb": {
"version": "6.14.2",
"resolved": "https://registry.npmjs.org/mongodb/-/mongodb-6.14.2.tgz",
"integrity": "sha512-kMEHNo0F3P6QKDq17zcDuPeaywK/YaJVCEQRzPF3TOM/Bl9MFg64YE5Tu7ifj37qZJMhwU1tl2Ioivws5gRG5Q==",
"version": "6.15.0",
"resolved": "https://registry.npmjs.org/mongodb/-/mongodb-6.15.0.tgz",
"integrity": "sha512-ifBhQ0rRzHDzqp9jAQP6OwHSH7dbYIQjD3SbJs9YYk9AikKEettW/9s/tbSFDTpXcRbF+u1aLrhHxDFaYtZpFQ==",
"license": "Apache-2.0",
"dependencies": {
"@mongodb-js/saslprep": "^1.1.9",
@@ -10480,9 +10470,9 @@
"optional": true
},
"node_modules/nanoid": {
"version": "5.1.3",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-5.1.3.tgz",
"integrity": "sha512-zAbEOEr7u2CbxwoMRlz/pNSpRP0FdAU4pRaYunCdEezWohXFs+a0Xw7RfkKaezMsmSM1vttcLthJtwRnVtOfHQ==",
"version": "5.1.5",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-5.1.5.tgz",
"integrity": "sha512-Ir/+ZpE9fDsNH0hQ3C68uyThDXzYcim2EqcZ8zn8Chtt1iylPT9xXJB0kPCnqzgcEGikO9RxSrh63MsmVCU7Fw==",
"funding": [
{
"type": "github",
@@ -11753,9 +11743,9 @@
"license": "MIT"
},
"node_modules/react-router": {
"version": "7.3.0",
"resolved": "https://registry.npmjs.org/react-router/-/react-router-7.3.0.tgz",
"integrity": "sha512-466f2W7HIWaNXTKM5nHTqNxLrHTyXybm7R0eBlVSt0k/u55tTCDO194OIx/NrYD4TS5SXKTNekXfT37kMKUjgw==",
"version": "7.4.0",
"resolved": "https://registry.npmjs.org/react-router/-/react-router-7.4.0.tgz",
"integrity": "sha512-Y2g5ObjkvX3VFeVt+0CIPuYd9PpgqCslG7ASSIdN73LwA1nNWzcMLaoMRJfP3prZFI92svxFwbn7XkLJ+UPQ6A==",
"license": "MIT",
"dependencies": {
"@types/cookie": "^0.6.0",
@@ -12132,6 +12122,12 @@
"inherits": "^2.0.1"
}
},
"node_modules/romans": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/romans/-/romans-3.0.0.tgz",
"integrity": "sha512-7DDsAfhtpRr/ZFQXiHDrC3Pe00agcAsFiNt5nNx4ZAQlsc6yJG0mvXA5WAvO8YZyOg349twm2GYhHLw7rCXAzw==",
"license": "MIT"
},
"node_modules/rrweb-cssom": {
"version": "0.7.1",
"resolved": "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.7.1.tgz",
@@ -13139,9 +13135,9 @@
"license": "ISC"
},
"node_modules/stylelint": {
"version": "16.16.0",
"resolved": "https://registry.npmjs.org/stylelint/-/stylelint-16.16.0.tgz",
"integrity": "sha512-40X5UOb/0CEFnZVEHyN260HlSSUxPES+arrUphOumGWgXERHfwCD0kNBVILgQSij8iliYVwlc0V7M5bcLP9vPg==",
"version": "16.17.0",
"resolved": "https://registry.npmjs.org/stylelint/-/stylelint-16.17.0.tgz",
"integrity": "sha512-I9OwVIWRMqVm2Br5iTbrfSqGRPWQUlvm6oXO1xZuYYu0Gpduy67N8wXOZv15p6E/JdlZiAtQaIoLKZEWk5hrjw==",
"dev": true,
"funding": [
{
@@ -13395,9 +13391,10 @@
}
},
"node_modules/superagent": {
"version": "10.1.1",
"resolved": "https://registry.npmjs.org/superagent/-/superagent-10.1.1.tgz",
"integrity": "sha512-9pIwrHrOj3uAnqg9gDlW7EA2xv+N5au/dSM0kM22HTqmUu8jBxNT+8uA7tA3UoCnmiqzpSbu8rasIUZvbyamMQ==",
"version": "10.2.0",
"resolved": "https://registry.npmjs.org/superagent/-/superagent-10.2.0.tgz",
"integrity": "sha512-IKeoGox6oG9zyDeizaezkJ2/aK0wc5la9st7WsAKyrAkfJ56W3whVbVtF68k6wuc87/y9T85NyON5FLz7Mrzzw==",
"license": "MIT",
"dependencies": {
"component-emitter": "^1.3.0",
"cookiejar": "^2.1.4",
@@ -13426,9 +13423,9 @@
}
},
"node_modules/supertest": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/supertest/-/supertest-7.0.0.tgz",
"integrity": "sha512-qlsr7fIC0lSddmA3tzojvzubYxvlGtzumcdHgPwbFWMISQwL22MhM2Y3LNt+6w9Yyx7559VW5ab70dgphm8qQA==",
"version": "7.1.0",
"resolved": "https://registry.npmjs.org/supertest/-/supertest-7.1.0.tgz",
"integrity": "sha512-5QeSO8hSrKghtcWEoPiO036fxH0Ii2wVQfFZSP0oqQhmjk8bOLhDFXr4JrvaFmPuEWUoq4znY3uSi8UzLKxGqw==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -14915,6 +14912,12 @@
"node": "^12.13.0 || ^14.15.0 || >=16.0.0"
}
},
"node_modules/written-number": {
"version": "0.11.1",
"resolved": "https://registry.npmjs.org/written-number/-/written-number-0.11.1.tgz",
"integrity": "sha512-LhQ68uUnzHH0bwm/QiGA9JwqgadSDOwqB2AIs/LBsrOY6ScqVXKRN2slTCeKAhstDBJ/Of/Yxcjn0pnQmVlmtg==",
"license": "MIT"
},
"node_modules/ws": {
"version": "7.5.10",
"resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz",

View File

@@ -84,11 +84,11 @@
]
},
"dependencies": {
"@babel/core": "^7.26.9",
"@babel/plugin-transform-runtime": "^7.26.9",
"@babel/core": "^7.26.10",
"@babel/plugin-transform-runtime": "^7.26.10",
"@babel/preset-env": "^7.26.9",
"@babel/preset-react": "^7.26.3",
"@googleapis/drive": "^8.16.0",
"@googleapis/drive": "^11.0.0",
"body-parser": "^1.20.2",
"classnames": "^2.5.1",
"codemirror": "^5.65.6",
@@ -107,7 +107,7 @@
"jwt-simple": "^0.5.6",
"less": "^3.13.1",
"lodash": "^4.17.21",
"marked": "14.0.0",
"marked": "15.0.0",
"marked-emoji": "^2.0.0",
"marked-extended-tables": "^2.0.1",
"marked-gfm-heading-id": "^4.0.1",
@@ -115,21 +115,23 @@
"marked-subsuper-text": "^1.0.3",
"markedLegacy": "npm:marked@^0.3.19",
"moment": "^2.30.1",
"mongoose": "^8.12.1",
"nanoid": "5.1.3",
"mongoose": "^8.13.0",
"nanoid": "5.1.5",
"nconf": "^0.12.1",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-frame-component": "^4.1.3",
"react-router": "^7.3.0",
"react-router": "^7.4.0",
"romans": "^3.0.0",
"sanitize-filename": "1.6.3",
"superagent": "^10.1.1",
"vitreum": "git+https://git@github.com/calculuschild/vitreum.git"
"superagent": "^10.2.0",
"vitreum": "git+https://git@github.com/calculuschild/vitreum.git",
"written-number": "^0.11.1"
},
"devDependencies": {
"@stylistic/stylelint-plugin": "^3.1.2",
"babel-plugin-transform-import-meta": "^2.3.2",
"eslint": "^9.22.0",
"eslint": "^9.23.0",
"eslint-plugin-jest": "^28.11.0",
"eslint-plugin-react": "^7.37.4",
"globals": "^16.0.0",
@@ -137,9 +139,9 @@
"jest-expect-message": "^1.1.3",
"jsdom-global": "^3.0.2",
"postcss-less": "^6.0.0",
"stylelint": "^16.16.0",
"stylelint": "^16.17.0",
"stylelint-config-recess-order": "^6.0.0",
"stylelint-config-recommended": "^15.0.0",
"supertest": "^7.0.0"
"supertest": "^7.1.0"
}
}

View File

@@ -69,14 +69,11 @@ const corsOptions = {
'https://homebrewery-stage.herokuapp.com',
];
if(isLocalEnvironment) {
const localNetworkRegex = /^http:\/\/(localhost|127\.0\.0\.1|10\.\d+\.\d+\.\d+|192\.168\.\d+\.\d+|172\.(1[6-9]|2\d|3[0-1])\.\d+\.\d+):\d+$/;
allowedOrigins.push(localNetworkRegex);
}
const localNetworkRegex = /^http:\/\/(localhost|127\.0\.0\.1|10\.\d+\.\d+\.\d+|192\.168\.\d+\.\d+|172\.(1[6-9]|2\d|3[0-1])\.\d+\.\d+):\d+$/;
const herokuRegex = /^https:\/\/(?:homebrewery-pr-\d+\.herokuapp\.com|naturalcrit-pr-\d+\.herokuapp\.com)$/; // Matches any Heroku app
if(!origin || allowedOrigins.includes(origin) || herokuRegex.test(origin)) {
if(!origin || allowedOrigins.includes(origin) || herokuRegex.test(origin) || (isLocalEnvironment && localNetworkRegex.test(origin))) {
callback(null, true);
} else {
console.log(origin, 'not allowed');

View File

@@ -8,6 +8,8 @@ import { markedSmartypantsLite as MarkedSmartypantsLite }
import { gfmHeadingId as MarkedGFMHeadingId, resetHeadings as MarkedGFMResetHeadingIDs } from 'marked-gfm-heading-id';
import { markedEmoji as MarkedEmojis } from 'marked-emoji';
import MarkedSubSuperText from 'marked-subsuper-text';
import { romanize } from 'romans';
import writtenNumber from 'written-number';
//Icon fonts included so they can appear in emoji autosuggest dropdown
import diceFont from '../../themes/fonts/iconFonts/diceFont.js';
@@ -59,6 +61,53 @@ mathParser.functions.signed = function (a) {
if(a >= 0) return `+${a}`;
return `${a}`;
};
// Add Roman numeral functions
mathParser.functions.toRomans = function (a) {
return romanize(a);
};
mathParser.functions.toRomansUpper = function (a) {
return romanize(a).toUpperCase();
};
mathParser.functions.toRomansLower = function (a) {
return romanize(a).toLowerCase();
};
// Add character functions
mathParser.functions.toChar = function (a) {
if(a <= 0) return a;
const genChars = function (i) {
return (i > 26 ? genChars(Math.floor((i - 1) / 26)) : '') + 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'[(i - 1) % 26];
};
return genChars(a);
};
mathParser.functions.toCharUpper = function (a) {
return mathParser.functions.toChar(a).toUpperCase();
};
mathParser.functions.toCharLower = function (a) {
return mathParser.functions.toChar(a).toLowerCase();
};
// Add word functions
mathParser.functions.toWords = function (a) {
return writtenNumber(a);
};
mathParser.functions.toWordsUpper = function (a) {
return mathParser.functions.toWords(a).toUpperCase();
};
mathParser.functions.toWordsLower = function (a) {
return mathParser.functions.toWords(a).toLowerCase();
};
mathParser.functions.toWordsCaps = function (a) {
const words = mathParser.functions.toWords(a).split(' ');
return words.map((word)=>{
return word.replace(/(?:^|\b|\s)(\w)/g, function(w, index) {
return index === 0 ? w.toLowerCase() : w.toUpperCase();
});
}).join(' ');
};
// Normalize variable names; trim edge spaces and shorten blocks of whitespace to 1 space
const normalizeVarNames = (label)=>{
return label.trim().replace(/\s+/g, ' ');
};
//Processes the markdown within an HTML block if it's just a class-wrapper
renderer.html = function (token) {
@@ -99,7 +148,7 @@ renderer.link = function (token) {
}
let out = `<a href="${escape(href)}"`;
if(title) {
out += ` title="${title}"`;
out += ` title="${escape(title)}"`;
}
if(self) {
out += ' target="_self"';
@@ -509,7 +558,7 @@ const replaceVar = function(input, hoist=false, allowUnresolved=false) {
const match = regex.exec(input);
const prefix = match[1];
const label = match[2];
const label = normalizeVarNames(match[2]); // Ensure the label name is normalized as it should be in the var stack.
//v=====--------------------< HANDLE MATH >-------------------=====v//
const mathRegex = /[a-z]+\(|[+\-*/^(),]/g;
@@ -664,8 +713,8 @@ function MarkedVariables() {
});
}
if(match[3]) { // Block Definition
const label = match[4] ? match[4].trim().replace(/\s+/g, ' ') : null; // Trim edge spaces and shorten blocks of whitespace to 1 space
const content = match[5] ? match[5].trim().replace(/[ \t]+/g, ' ') : null; // Trim edge spaces and shorten blocks of whitespace to 1 space
const label = match[4] ? normalizeVarNames(match[4]) : null;
const content = match[5] ? match[5].trim().replace(/[ \t]+/g, ' ') : null; // Normalize text content (except newlines for block-level content)
varsQueue.push(
{ type : 'varDefBlock',
@@ -674,7 +723,7 @@ function MarkedVariables() {
});
}
if(match[6]) { // Block Call
const label = match[7] ? match[7].trim().replace(/\s+/g, ' ') : null; // Trim edge spaces and shorten blocks of whitespace to 1 space
const label = match[7] ? normalizeVarNames(match[7]) : null;
varsQueue.push(
{ type : 'varCallBlock',
@@ -683,7 +732,7 @@ function MarkedVariables() {
});
}
if(match[8]) { // Inline Definition
const label = match[10] ? match[10].trim().replace(/\s+/g, ' ') : null; // Trim edge spaces and shorten blocks of whitespace to 1 space
const label = match[10] ? normalizeVarNames(match[10]) : null;
let content = match[11] || null;
// In case of nested (), find the correct matching end )
@@ -715,7 +764,7 @@ function MarkedVariables() {
});
}
if(match[12]) { // Inline Call
const label = match[13] ? match[13].trim().replace(/\s+/g, ' ') : null; // Trim edge spaces and shorten blocks of whitespace to 1 space
const label = match[13] ? normalizeVarNames(match[13]) : null;
varsQueue.push(
{ type : 'varCallInline',
@@ -902,7 +951,13 @@ let globalPageNumber = 0;
const Markdown = {
marked : Marked,
render : (rawBrewText, pageNumber=0)=>{
globalVarsList[pageNumber] = {}; //Reset global links for current page, to ensure values are parsed in order
const lastPageNumber = pageNumber > 0 ? globalVarsList[pageNumber - 1].HB_pageNumber.content : 0;
globalVarsList[pageNumber] = { //Reset global links for current page, to ensure values are parsed in order
'HB_pageNumber' : { //Add document variables for this page
content : !isNaN(Number(lastPageNumber)) ? Number(lastPageNumber) + 1 : lastPageNumber,
resolved : true
}
};
varsQueue = []; //Could move into MarkedVariables()
globalPageNumber = pageNumber;
if(pageNumber==0) {

View File

@@ -54,19 +54,19 @@ describe('Non-Breaking Spaces', ()=>{
test('I am actually a single-line definition list!', function() {
const source = 'Term ::> Definition 1\n';
const rendered = Markdown.render(source).trim();
expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe(`<dl><dt>Term</dt><dd>> Definition 1</dd>\n</dl>`);
expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe(`<dl><dt>Term</dt><dd>&gt; Definition 1</dd>\n</dl>`);
});
test('I am actually a definition list!', function() {
const source = 'Term\n::> Definition 1\n';
const rendered = Markdown.render(source).trim();
expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe(`<dl><dt>Term</dt>\n<dd>> Definition 1</dd></dl>`);
expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe(`<dl><dt>Term</dt>\n<dd>&gt; Definition 1</dd></dl>`);
});
test('I am actually a two-term definition list!', function() {
const source = 'Term\n::> Definition 1\n::>> Definition 2';
const rendered = Markdown.render(source).trim();
expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe(`<dl><dt>Term</dt>\n<dd>> Definition 1</dd>\n<dd>>> Definition 2</dd></dl>`);
expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe(`<dl><dt>Term</dt>\n<dd>&gt; Definition 1</dd>\n<dd>&gt;&gt; Definition 2</dd></dl>`);
});
});

View File

@@ -370,6 +370,30 @@ describe('Cross-page variables', ()=>{
const rendered = renderAllPages([source0, source1]).join('\n\\page\n').trimReturns();
expect(rendered, `Input:\n${[source0, source1].join('\n\\page\n')}`, { showPrefix: false }).toBe('<p>two</p><p>one</p>\\page<p>two</p>');
});
it('Page numbering across pages : default', function() {
const source0 = `$[HB_pageNumber]\n\n`;
const source1 = `$[HB_pageNumber]\n\n`;
renderAllPages([source0, source1]).join('\n\\page\n').trimReturns(); //Requires one full render of document before hoisting is picked up
const rendered = renderAllPages([source0, source1]).join('\n\\page\n').trimReturns();
expect(rendered, `Input:\n${[source0, source1].join('\n\\page\n')}`, { showPrefix: false }).toBe('<p>1</p>\\page<p>2</p>');
});
it('Page numbering across pages : custom page number (Number)', function() {
const source0 = `[HB_pageNumber]:100\n\n$[HB_pageNumber]\n\n`;
const source1 = `$[HB_pageNumber]\n\n`;
renderAllPages([source0, source1]).join('\n\\page\n').trimReturns(); //Requires one full render of document before hoisting is picked up
const rendered = renderAllPages([source0, source1]).join('\n\\page\n').trimReturns();
expect(rendered, `Input:\n${[source0, source1].join('\n\\page\n')}`, { showPrefix: false }).toBe('<p>100</p>\\page<p>101</p>');
});
it('Page numbering across pages : custom page number (NaN)', function() {
const source0 = `[HB_pageNumber]:a\n\n$[HB_pageNumber]\n\n`;
const source1 = `$[HB_pageNumber]\n\n`;
renderAllPages([source0, source1]).join('\n\\page\n').trimReturns(); //Requires one full render of document before hoisting is picked up
const rendered = renderAllPages([source0, source1]).join('\n\\page\n').trimReturns();
expect(rendered, `Input:\n${[source0, source1].join('\n\\page\n')}`, { showPrefix: false }).toBe('<p>a</p>\\page<p>a</p>');
});
});
describe('Math function parameter handling', ()=>{
@@ -410,4 +434,102 @@ describe('Regression Tests', ()=>{
const rendered = Markdown.render(source).trimReturns();
expect(rendered).toBe('<table><thead><tr><th>title 1</th><th>title 2</th><th>title 3</th><th>title 4</th></tr></thead><tbody><tr><td><a href=\"bar\">foo</a></td><td>Ipsum</td><td>)</td><td>)</td></tr></tbody></table>');
});
it('Handle Extra spaces in image alt-text 1', function(){
const source='![ where is my image??](http://i.imgur.com/hMna6G0.png)';
const rendered = Markdown.render(source).trimReturns();
expect(rendered).toBe('<p><img src=\"http://i.imgur.com/hMna6G0.png\" alt=\"where is my image??\" style=\"--HB_src:url(http://i.imgur.com/hMna6G0.png);\"></p>');
});
it('Handle Extra spaces in image alt-text 2', function(){
const source='![where is my image??](http://i.imgur.com/hMna6G0.png)';
const rendered = Markdown.render(source).trimReturns();
expect(rendered).toBe('<p><img src=\"http://i.imgur.com/hMna6G0.png\" alt=\"where is my image??\" style=\"--HB_src:url(http://i.imgur.com/hMna6G0.png);\"></p>');
});
it('Handle Extra spaces in image alt-text 3', function(){
const source='![where is my image?? ](http://i.imgur.com/hMna6G0.png)';
const rendered = Markdown.render(source).trimReturns();
expect(rendered).toBe('<p><img src=\"http://i.imgur.com/hMna6G0.png\" alt=\"where is my image??\" style=\"--HB_src:url(http://i.imgur.com/hMna6G0.png);\"></p>');
});
it('Handle Extra spaces in image alt-text 4', function(){
const source='![where is my image??](http://i.imgur.com/hMna6G0.png){height=20%,width=20%}';
const rendered = Markdown.render(source).trimReturns();
expect(rendered).toBe('<p><img style=\"--HB_src:url(http://i.imgur.com/hMna6G0.png);\" src=\"http://i.imgur.com/hMna6G0.png\" alt=\"where is my image??\" height=\"20%\" width=\"20%\"></p>');
});
});
describe('Custom Math Function Tests', ()=>{
it('Sign Test', function() {
const source = `[a]: 13\n\n[b]: -11\n\nPositive: $[sign(a)]\n\nNegative: $[sign(b)]`;
const rendered = Markdown.render(source).trimReturns();
expect(rendered).toBe('<p>Positive: +</p><p>Negative: -</p>');
});
it('Signed Test', function() {
const source = `[a]: 13\n\n[b]: -11\n\nPositive: $[signed(a)]\n\nNegative: $[signed(b)]`;
const rendered = Markdown.render(source).trimReturns();
expect(rendered).toBe('<p>Positive: +13</p><p>Negative: -11</p>');
});
it('Roman Numerals Test', function() {
const source = `[a]: 18\n\nRoman Numeral: $[toRomans(a)]`;
const rendered = Markdown.render(source).trimReturns();
expect(rendered).toBe('<p>Roman Numeral: XVIII</p>');
});
it('Roman Numerals Test - Uppercase', function() {
const source = `[a]: 18\n\nRoman Numeral: $[toRomansUpper(a)]`;
const rendered = Markdown.render(source).trimReturns();
expect(rendered).toBe('<p>Roman Numeral: XVIII</p>');
});
it('Roman Numerals Test - Lowercase', function() {
const source = `[a]: 18\n\nRoman Numeral: $[toRomansLower(a)]`;
const rendered = Markdown.render(source).trimReturns();
expect(rendered).toBe('<p>Roman Numeral: xviii</p>');
});
it('Number to Characters Test', function() {
const source = `[a]: 18\n\n[b]: 39\n\nCharacters: $[toChar(a)] $[toChar(b)]`;
const rendered = Markdown.render(source).trimReturns();
expect(rendered).toBe('<p>Characters: R AM</p>');
});
it('Number to Characters Test - Uppercase', function() {
const source = `[a]: 18\n\n[b]: 39\n\nCharacters: $[toCharUpper(a)] $[toCharUpper(b)]`;
const rendered = Markdown.render(source).trimReturns();
expect(rendered).toBe('<p>Characters: R AM</p>');
});
it('Number to Characters Test - Lowercase', function() {
const source = `[a]: 18\n\n[b]: 39\n\nCharacters: $[toCharLower(a)] $[toCharLower(b)]`;
const rendered = Markdown.render(source).trimReturns();
expect(rendered).toBe('<p>Characters: r am</p>');
});
it('Number to Words Test', function() {
const source = `[a]: 80085\n\nWords: $[toWords(a)]`;
const rendered = Markdown.render(source).trimReturns();
expect(rendered).toBe('<p>Words: eighty thousand and eighty-five</p>');
});
it('Number to Words Test - Uppercase', function() {
const source = `[a]: 80085\n\nWords: $[toWordsUpper(a)]`;
const rendered = Markdown.render(source).trimReturns();
expect(rendered).toBe('<p>Words: EIGHTY THOUSAND AND EIGHTY-FIVE</p>');
});
it('Number to Words Test - Lowercase', function() {
const source = `[a]: 80085\n\nWords: $[toWordsLower(a)]`;
const rendered = Markdown.render(source).trimReturns();
expect(rendered).toBe('<p>Words: eighty thousand and eighty-five</p>');
});
it('Number to Words Test - Capitalized', function() {
const source = `[a]: 80085\n\nWords: $[toWordsCaps(a)]`;
const rendered = Markdown.render(source).trimReturns();
expect(rendered).toBe('<p>Words: Eighty Thousand And Eighty-Five</p>');
});
});

View File

@@ -13,13 +13,13 @@
body { counter-reset : phb-page-numbers; }
* { -webkit-print-color-adjust : exact; }
.useSansSerif() {
font-family : "ScalySans";
font-family : 'ScalySans';
em {
font-family : "ScalySans";
font-family : 'ScalySans';
font-style : italic;
}
strong {
font-family : "ScalySans";
font-family : 'ScalySans';
font-weight : 800;
letter-spacing : -0.02em;
}
@@ -46,7 +46,7 @@ body { counter-reset : phb-page-numbers; }
padding : 1.0cm 1.7cm;
padding-bottom : 1.5cm;
overflow : hidden;
font-family : "BookSanity";
font-family : 'BookSanity';
font-size : 0.317cm;
counter-increment : phb-page-numbers;
background-color : @background;
@@ -106,7 +106,7 @@ body { counter-reset : phb-page-numbers; }
h1,h2,h3,h4 {
margin-top : 0.2em;
margin-bottom : 0.2em;
font-family : "MrJeeves";
font-family : 'MrJeeves';
font-weight : 800;
color : @headerText;
}
@@ -117,7 +117,7 @@ body { counter-reset : phb-page-numbers; }
-moz-column-span : all;
& + p::first-letter {
float : left;
font-family : "Solberry";
font-family : 'Solberry';
font-size : 10em;
line-height : 0.795em;
color : #222222;
@@ -134,7 +134,7 @@ body { counter-reset : phb-page-numbers; }
}
h5 {
margin-bottom : 0.2em;
font-family : "ScalySansSmallCaps";
font-family : 'ScalySansSmallCaps';
font-size : 0.423cm;
font-weight : 900;
}
@@ -200,7 +200,7 @@ body { counter-reset : phb-page-numbers; }
& + p { padding-bottom : 0px; }
}
h3 {
font-family : "ScalySans";
font-family : 'ScalySans';
font-weight : normal;
border-bottom : 1px solid @headerText;
}
@@ -380,7 +380,7 @@ body { counter-reset : phb-page-numbers; }
// ************************************/
.phb .descriptive {
margin-bottom : 1em;
font-family : "ScalySans";
font-family : 'ScalySans';
background-color : #FAF7EA;
border-style : solid;
border-width : 7px;
@@ -394,11 +394,11 @@ body { counter-reset : phb-page-numbers; }
}
p + p { padding-top : 0.8em; }
em {
font-family : "ScalySans";
font-family : 'ScalySans';
font-style : italic;
}
strong {
font-family : "ScalySans";
font-family : 'ScalySans';
font-weight : 800;
letter-spacing : -0.02em;
}
@@ -411,7 +411,7 @@ body { counter-reset : phb-page-numbers; }
.phb {
.artist {
position : absolute;
font-family : "WalterTurncoat";
font-family : 'WalterTurncoat';
font-size : 0.27cm;
color : @captionText;
text-align : center;
@@ -421,7 +421,7 @@ body { counter-reset : phb-page-numbers; }
text-indent : unset;
}
h5 {
font-family : "WalterTurncoat";
font-family : 'WalterTurncoat';
font-size : 1.3em;
}
a {

View File

@@ -7,7 +7,7 @@
}
.page {
background-image : url("/assets/DMG_background.png");
background-image : url('/assets/DMG_background.png');
background-size : cover;
/* TABLES WITHIN NOTES */
@@ -23,7 +23,7 @@
&::after {
height : 58px;
background-image : url("/assets/DMG_footerAccent.png");
background-image : url('/assets/DMG_footerAccent.png');
}
.footnote { bottom : 40px; }

View File

@@ -6,164 +6,12 @@ const MonsterBlockGen = require('./snippets/monsterblock.gen.js');
const scriptGen = require('./snippets/script.gen.js');
const ClassFeatureGen = require('./snippets/classfeature.gen.js');
const CoverPageGen = require('./snippets/coverpage.gen.js');
const TableOfContentsGen = require('./snippets/tableOfContents.gen.js');
const indexGen = require('./snippets/index.gen.js');
const QuoteGen = require('./snippets/quote.gen.js');
const dedent = require('dedent-tabs').default;
module.exports = [
{
groupName : 'Text Editor',
icon : 'fas fa-pencil-alt',
view : 'text',
snippets : [
{
name : 'Table of Contents',
icon : 'fas fa-book',
gen : TableOfContentsGen,
experimental : true,
subsnippets : [
{
name : 'Generate Table of Contents',
icon : 'fas fa-book',
gen : TableOfContentsGen,
experimental : true
},
{
name : 'Table of Contents Individual Inclusion',
icon : 'fas fa-book',
gen : dedent `\n{{tocInclude# CHANGE # to your header level
}}\n`,
subsnippets : [
{
name : 'Individual Inclusion H1',
icon : 'fas fa-book',
gen : dedent `\n{{tocIncludeH1 \n
}}\n`,
},
{
name : 'Individual Inclusion H2',
icon : 'fas fa-book',
gen : dedent `\n{{tocIncludeH2 \n
}}\n`,
},
{
name : 'Individual Inclusion H3',
icon : 'fas fa-book',
gen : dedent `\n{{tocIncludeH3 \n
}}\n`,
},
{
name : 'Individual Inclusion H4',
icon : 'fas fa-book',
gen : dedent `\n{{tocIncludeH4 \n
}}\n`,
},
{
name : 'Individual Inclusion H5',
icon : 'fas fa-book',
gen : dedent `\n{{tocIncludeH5 \n
}}\n`,
},
{
name : 'Individual Inclusion H6',
icon : 'fas fa-book',
gen : dedent `\n{{tocIncludeH6 \n
}}\n`,
}
]
},
{
name : 'Table of Contents Range Inclusion',
icon : 'fas fa-book',
gen : dedent `\n{{tocDepthH3
}}\n`,
subsnippets : [
{
name : 'Include in ToC up to H3',
icon : 'fas fa-dice-three',
gen : dedent `\n{{tocDepthH3
}}\n`,
},
{
name : 'Include in ToC up to H4',
icon : 'fas fa-dice-four',
gen : dedent `\n{{tocDepthH4
}}\n`,
},
{
name : 'Include in ToC up to H5',
icon : 'fas fa-dice-five',
gen : dedent `\n{{tocDepthH5
}}\n`,
},
{
name : 'Include in ToC up to H6',
icon : 'fas fa-dice-six',
gen : dedent `\n{{tocDepthH6
}}\n`,
},
]
},
{
name : 'Table of Contents Individual Exclusion',
icon : 'fas fa-book',
gen : dedent `\n{{tocExcludeH1 \n
}}\n`,
subsnippets : [
{
name : 'Individual Exclusion H1',
icon : 'fas fa-book',
gen : dedent `\n{{tocExcludeH1 \n
}}\n`,
},
{
name : 'Individual Exclusion H2',
icon : 'fas fa-book',
gen : dedent `\n{{tocExcludeH2 \n
}}\n`,
},
{
name : 'Individual Exclusion H3',
icon : 'fas fa-book',
gen : dedent `\n{{tocExcludeH3 \n
}}\n`,
},
{
name : 'Individual Exclusion H4',
icon : 'fas fa-book',
gen : dedent `\n{{tocExcludeH4 \n
}}\n`,
},
{
name : 'Individual Exclusion H5',
icon : 'fas fa-book',
gen : dedent `\n{{tocExcludeH5 \n
}}\n`,
},
{
name : 'Individual Exclusion H6',
icon : 'fas fa-book',
gen : dedent `\n{{tocExcludeH6 \n
}}\n`,
},
]
},
]
},
{
name : 'Index',
icon : 'fas fa-bars',
gen : indexGen,
experimental : true
}
]
},
{
groupName : 'Style Editor',
icon : 'fas fa-pencil-alt',
@@ -192,70 +40,9 @@ module.exports = [
line-height: 1em;
}\n\n`
},
{
name : 'Table of Contents Toggles',
icon : 'fas fa-book',
subsnippets : [
{
name : 'Enable H1-H4 all pages',
icon : 'fas fa-dice-four',
gen : `.page {\n\th4 {--TOC: include; }\n}\n\n`,
},
{
name : 'Enable H1-H5 all pages',
icon : 'fas fa-dice-five',
gen : `.page {\n\th4, h5 {--TOC: include; }\n}\n\n`,
},
{
name : 'Enable H1-H6 all pages',
icon : 'fas fa-dice-six',
gen : `.page {\n\th4, h5, h6 {--TOC: include; }\n}\n\n`,
},
]
}
]
},
/*********************** IMAGES *******************/
{
groupName : 'Images',
icon : 'fas fa-images',
view : 'text',
snippets : [
{
name : 'Image',
icon : 'fas fa-image',
gen : dedent`
![cat warrior](https://s-media-cache-ak0.pinimg.com/736x/4a/81/79/4a8179462cfdf39054a418efd4cb743e.jpg) {width:325px,mix-blend-mode:multiply}
{{artist,position:relative,top:-230px,left:10px,margin-bottom:-30px
##### Cat Warrior
[Kyoung Hwan Kim](https://www.artstation.com/tahra)
}}`
},
{
name : 'Background Image',
icon : 'fas fa-tree',
gen : dedent`
![homebrew mug](http://i.imgur.com/hMna6G0.png) {position:absolute,top:50px,right:30px,width:280px}
{{artist,top:80px,right:30px
##### Homebrew Mug
[naturalcrit](https://homebrew.naturalcrit.com)
}}`
},
{
name : 'Watermark',
icon : 'fas fa-id-card',
gen : dedent`
{{watermark Homebrewery}}\n`
},
]
},
/************************* PHB ********************/
{
groupName : 'PHB',
icon : 'fas fa-book',
@@ -450,9 +237,6 @@ module.exports = [
]
},
/**************** PAGE *************/
{

View File

@@ -791,47 +791,8 @@
// * TABLE OF CONTENTS
// *****************************/
// Default Exclusions
// Anything not excluded is included, default Headers are H1, H2, and H3.
h4,
h5,
h6,
.page:has(.frontCover),
.page:has(.backCover),
.page:has(.insideCover),
.monster,
.noToC,
.toc { --TOC : exclude; }
// Brew level default inclusion changes.
// These add Headers 'back' to inclusion.
//NOTE: DO NOT USE :HAS WITH .PAGES!!! EXTREMELY SLOW TO RENDER ON LARGE DOCS!
// Block level inclusion changes
// These include either a single (include) or a range (depth)
.tocIncludeH1 h1 {--TOC : include; }
.tocIncludeH2 h2 {--TOC : include; }
.tocIncludeH3 h3 {--TOC : include; }
.tocIncludeH4 h4 {--TOC : include; }
.tocIncludeH5 h5 {--TOC : include; }
.tocIncludeH6 h6 {--TOC : include; }
.tocDepthH2 :is(h1, h2) {--TOC : include; }
.tocDepthH3 :is(h1, h2, h3) {--TOC : include; }
.tocDepthH4 :is(h1, h2, h3, h4) {--TOC : include; }
.tocDepthH5 :is(h1, h2, h3, h4, h5) {--TOC : include; }
.tocDepthH6 :is(h1, h2, h3, h4, h5, h6) {--TOC : include; }
// Block level exclusion changes
// These exclude a single block level
.tocExcludeH1 h1 {--TOC : exclude; }
.tocExcludeH2 h2 {--TOC : exclude; }
.tocExcludeH3 h3 {--TOC : exclude; }
.tocExcludeH4 h4 {--TOC : exclude; }
.tocExcludeH5 h5 {--TOC : exclude; }
.tocExcludeH6 h6 {--TOC : exclude; }
// Additional Default Exclusions
.monster { --TOC : exclude; }
.page:has(.partCover) {
--TOC : exclude;
@@ -964,6 +925,7 @@ h6,
}
}
}
// *****************************
// * INDEX
// *****************************/

View File

@@ -4,6 +4,8 @@ const WatercolorGen = require('./snippets/watercolor.gen.js');
const ImageMaskGen = require('./snippets/imageMask.gen.js');
const FooterGen = require('./snippets/footer.gen.js');
const dedent = require('dedent-tabs').default;
const TableOfContentsGen = require('./snippets/tableOfContents.gen.js');
const indexGen = require('./snippets/index.gen.js');
module.exports = [
@@ -36,6 +38,11 @@ module.exports = [
icon : 'fas fa-sort-numeric-down',
gen : '{{pageNumber,auto}}\n'
},
{
name : 'Variable Auto Page Number',
icon : 'fas fa-sort-numeric-down',
gen : '{{pageNumber $[HB_pageNumber]}}\n'
},
{
name : 'Skip Page Number Increment this Page',
icon : 'fas fa-xmark',
@@ -141,7 +148,53 @@ module.exports = [
[Homebrewery.Naturalcrit.com](https://homebrewery.naturalcrit.com)
}}\n\n`;
},
}
},
{
name : 'Table of Contents',
icon : 'fas fa-book',
gen : TableOfContentsGen,
experimental : true,
subsnippets : [
{
name : 'Table of Contents',
icon : 'fas fa-book',
gen : TableOfContentsGen,
experimental : true
},
{
name : 'Include in ToC up to H3',
icon : 'fas fa-dice-three',
gen : dedent `\n{{tocDepthH3
}}\n`,
},
{
name : 'Include in ToC up to H4',
icon : 'fas fa-dice-four',
gen : dedent `\n{{tocDepthH4
}}\n`,
},
{
name : 'Include in ToC up to H5',
icon : 'fas fa-dice-five',
gen : dedent `\n{{tocDepthH5
}}\n`,
},
{
name : 'Include in ToC up to H6',
icon : 'fas fa-dice-six',
gen : dedent `\n{{tocDepthH6
}}\n`,
}
]
},
{
name : 'Index',
icon : 'fas fa-bars',
gen : indexGen,
experimental : true
},
]
},
{
@@ -153,7 +206,7 @@ module.exports = [
name : 'Add Comment',
icon : 'fas fa-code',
gen : '/* This is a comment that will not be rendered into your brew. */'
},
}
]
},

View File

@@ -5,6 +5,7 @@
@import (less) './themes/fonts/iconFonts/diceFont.less';
@import (less) './themes/fonts/iconFonts/gameIcons.less';
@import (less) './themes/fonts/iconFonts/fontAwesome.less';
@import (less) './themes/fonts/Journal/fonts.less';
:root {
//Colors
@@ -496,3 +497,117 @@ body { counter-reset : page-numbers 0; }
&:not(:has(.skipCounting)) { counter-increment : page-numbers; }
}
// *****************************
// * INDEX
// *****************************/
.page {
.index {
ul ul { margin : 0; }
ul {
padding-left : 0;
text-indent : 0;
list-style-type : none;
}
& > ul > li {
padding-left : 1.5em;
text-indent : -1.5em;
}
}
}
// *****************************
// * TABLE OF CONTENTS
// *****************************/
// Default Exclusions
// Anything not exlcuded is included, default Headers are H1, H2, and H3.
h4,
h5,
h6,
.page:has(.frontCover),
.page:has(.backCover),
.page:has(.insideCover),
.noToC,
.toc { --TOC : exclude; }
.tocDepthH2 :is(h1, h2) {--TOC : include; }
.tocDepthH3 :is(h1, h2, h3) {--TOC : include; }
.tocDepthH4 :is(h1, h2, h3, h4) {--TOC : include; }
.tocDepthH5 :is(h1, h2, h3, h4, h5) {--TOC : include; }
.tocDepthH6 :is(h1, h2, h3, h4, h5, h6) {--TOC : include; }
.tocIncludeH1 h1 {--TOC : include; }
.tocIncludeH2 h2 {--TOC : include; }
.tocIncludeH3 h3 {--TOC : include; }
.tocIncludeH4 h4 {--TOC : include; }
.tocIncludeH5 h5 {--TOC : include; }
.tocIncludeH6 h6 {--TOC : include; }
.page {
&:has(.toc)::after { display : none; }
.toc {
-webkit-column-break-inside : avoid;
page-break-inside : avoid;
break-inside : avoid;
h1 {
margin-bottom : 0.3cm;
text-align : center;
}
a {
display : inline;
color : inherit;
text-decoration : none;
&:hover { text-decoration : underline; }
}
h4 {
margin-top : 0.2cm;
line-height : 0.4cm;
& + ul li { line-height : 1.2em; }
}
ul {
padding-left : 0;
margin-top : 0;
list-style-type : none;
a {
display : flex;
flex-flow : row nowrap;
justify-content : space-between;
width : 100%;
}
li + li h3 {
margin-top : 0.26cm;
line-height : 1em;
}
h3 span:first-child::after { border : none; }
span {
display : contents;
&:first-child::after {
bottom : 0.08cm;
flex : 1;
margin-right : 0.16cm;
margin-bottom : 0.08cm;
margin-left : 0.08cm; /* Spacing before dot leaders */
content : '';
border-bottom : 0.05cm dotted #000000;
}
&:last-child {
display : inline-block;
align-self : flex-end;
font-size : 0.34cm;
font-weight : normal;
}
}
ul { /* List indent */
margin-left : 1em;
}
}
&.wide {
.useColumns(0.96, @fillMode: balance);
}
}
.toc.wide li { break-inside : auto; }
}

View File

@@ -12,7 +12,7 @@
}
.useSansSerif() {
font-family : "PermanentMarker";
font-family : 'PermanentMarker';
font-size : 0.3cm;
line-height : 1.2em;
color : var(--HB_Color_Text2);
@@ -29,7 +29,7 @@
.page {
padding : 2.1cm 1.9cm 1.7cm 3.8cm;
background-image : url("/assets/Journal/Background1.webp");
background-image : url('/assets/Journal/Background1.webp');
background-repeat : no-repeat;
background-size : 200% 100%;
filter : drop-shadow(1px 4px 14px black);
@@ -39,7 +39,7 @@
background-position : right;
}
&:nth-of-type(2) {
background-image : url("/assets/Journal/Background2.webp"); //Only first page should show ribbon
background-image : url('/assets/Journal/Background2.webp'); //Only first page should show ribbon
}
& .columnWrapper {
@@ -51,7 +51,7 @@
// * BASE
// *****************************/
.page {
font-family : "ReenieBeanie";
font-family : 'ReenieBeanie';
font-size : 0.53cm;
line-height : 0.8em;
color : var(--HB_Color_Text);
@@ -71,7 +71,7 @@
// * HEADERS
// *****************************/
h1,h2,h3,h4,h5 {
font-family : "FrederickaTheGreat";
font-family : 'FrederickaTheGreat';
font-weight : unset;
color : var(--HB_Color_HeaderText);
}
@@ -89,7 +89,7 @@
margin-right : 0.1em;
margin-bottom : -20px;
margin-left : -40px;
font-family : "FrederickaTheGreat";
font-family : 'FrederickaTheGreat';
font-size : 1.9em;
line-height : 1em;
}
@@ -114,7 +114,7 @@
&:nth-of-type(3n) { transform : rotate(-1.5deg); }
}
h5 {
font-family : "PermanentMarker";
font-family : 'PermanentMarker';
font-size : 0.4cm;
font-weight : bold;
line-height : 0.951em; //Font is misaligned. Shift up slightly
@@ -146,14 +146,14 @@
.note {
.useSansSerif();
padding : 0.2cm;
background-image : url("/assets/Journal/HashMarks.png"),
background-image : url('/assets/Journal/HashMarks.png'),
linear-gradient(to bottom right, #FF000000, #A36A4E14, #41212100);
background-repeat : no-repeat;
background-position : center;
background-size : 120% 120%;
border-style : solid;
border-width : 1px;
border-image-source : url("/assets/Journal/Border1.png");
border-image-source : url('/assets/Journal/Border1.png');
border-image-slice : 18 18 18 18;
border-image-width : 6px 6px 6px 6px;
border-image-outset : 5px 5px 5px 5px;
@@ -173,7 +173,7 @@
.descriptive {
.useSansSerif();
padding : 0.2cm;
background-image : url("/assets/Journal/HashMarks.png"),
background-image : url('/assets/Journal/HashMarks.png'),
linear-gradient(to bottom right, #FF000000, #41212114, #41212100);
background-repeat : no-repeat;
background-position : center;
@@ -201,7 +201,7 @@
.artist {
position : absolute;
width : auto;
font-family : "WalterTurncoat";
font-family : 'WalterTurncoat';
font-size : 0.27cm;
color : var(--HB_Color_CaptionText);
text-align : center;
@@ -211,7 +211,7 @@
text-indent : unset;
}
h5 {
font-family : "WalterTurncoat";
font-family : 'WalterTurncoat';
font-size : 1.3em;
}
a {
@@ -309,7 +309,7 @@
.pageNumber {
right : 3cm;
bottom : 1.25cm;
font-family : "FrederickaTheGreat";
font-family : 'FrederickaTheGreat';
color : var(--HB_Color_HeaderText);
}
.footnote {
@@ -370,7 +370,7 @@
.page .spellList {
.useSansSerif();
font-family : "PermanentMarker";
font-family : 'PermanentMarker';
column-count : 2;
ul + h5 { margin-top : 15px; }
ul {
@@ -439,7 +439,7 @@
&:last-child {
width : 1%;
padding-left : 0.06cm; /* Spacing after dot leaders */
font-family : "ReenieBeanie";
font-family : 'ReenieBeanie';
font-size : 0.34cm;
font-weight : normal;
vertical-align : bottom; /* Keep page number bottom-aligned */