diff --git a/changelog.md b/changelog.md
index 1464df6b0..2a8ce15f4 100644
--- a/changelog.md
+++ b/changelog.md
@@ -88,6 +88,56 @@ pre {
## changelog
For a full record of development, visit our [Github Page](https://github.com/naturalcrit/homebrewery).
+### Monday 03/10/2025 - v3.18.0
+
+{{taskList
+##### dbolack
+* [x] Add ability to paste in any Share ID/URL into a brew's {{openSans :fas_circle_info: **Properties** :fas_arrow_right: **THEMES**}} selection, as long as that brew has been tagged as `meta:theme`. You can now share your custom brew themes without needing to make a personal copy.
+* [x] Begin migration of custom Markdown extensions into their own NPM packages, for easier adoption by other users or projects
+* [x] Fix external HTML appearing in open codeblocks
+
+Fixes issue [#3206](https://github.com/naturalcrit/homebrewery/issues/3206)
+
+* [x] Fix tables not rendering when directly after text
+
+
+##### G-Ambatte
+* [x] Cleanup of "cover pages" in the {{openSans :fas_rectangle_list: **NAVIGATION**}} list
+* [x] Fix autosave triggering when no changes are present
+
+Fixes issue [#4051](https://github.com/naturalcrit/homebrewery/issues/4051)
+
+* [x] Remove empty table rows resulting from rowspan
+
+Fixes issue [#1729](https://github.com/naturalcrit/homebrewery/issues/1729)
+
+##### 5e-Cleric
+* [x] Style fixes for covers art and logos on A4 size pages
+* [x] Fix crash when trying to open brews that don't exist
+* [x] Tweaks and style update styling on {{openSans **VAULT** :fas_dungeon:}} page.
+
+Fixes issue [#4079](https://github.com/naturalcrit/homebrewery/issues/4079)
+
+##### Calculuschild
+* [x] `꞉꞉꞉꞉` now produces ` ` instead of a `
`
+* [x] Fix typos in tables freezing the editor
+
+Fixes issue [#4059](https://github.com/naturalcrit/homebrewery/issues/4059)
+
+
+##### MollyMaclachlan (New Contributor!)
+* [x] Fixed typos in the Monster Stat Block snippet
+
+Fixes issue [#4073](https://github.com/naturalcrit/homebrewery/issues/4073)
+
+
+##### All
+* [x] Update dependencies and scripts
+* [x] Refactor components and backend tools
+}}
+
+\column
+
### Thursday 01/30/2025 - v3.17.0
{{taskList
@@ -169,7 +219,7 @@ Fixes issue [#3824](https://github.com/naturalcrit/homebrewery/issues/3824)
* [x] Refactor components and fix various errors
}}
-\column
+\page
### Wednesday 11/27/2024 - v3.16.1
@@ -217,8 +267,6 @@ 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
diff --git a/client/homebrew/pages/vaultPage/vaultPage.jsx b/client/homebrew/pages/vaultPage/vaultPage.jsx
index 21a8e8363..f979aa4f7 100644
--- a/client/homebrew/pages/vaultPage/vaultPage.jsx
+++ b/client/homebrew/pages/vaultPage/vaultPage.jsx
@@ -99,14 +99,14 @@ const VaultPage = (props)=>{
setSearching(true);
setError(null);
- const title = titleRef.current.value || '';
- const author = authorRef.current.value || '';
- const count = countRef.current.value || 10;
- const v3 = v3Ref.current.checked != false;
- const legacy = legacyRef.current.checked != false;
+ const title = titleRef.current.value || '';
+ const author = authorRef.current.value || '';
+ const count = countRef.current.value || 10;
+ const v3 = v3Ref.current.checked != false;
+ const legacy = legacyRef.current.checked != false;
const sortOption = sort || 'title';
- const dirOption = dir || 'asc';
- const pageProp = page || 1;
+ const dirOption = dir || 'asc';
+ const pageProp = page || 1;
setSort(sortOption);
setdir(dirOption);
@@ -247,7 +247,7 @@ const VaultPage = (props)=>{
Some common words like "a", "after", "through", "itself", "here", etc.,
- are ignored in searches. The full list can be found
+ are ignored in searches. The full list can be found
here
@@ -286,9 +286,9 @@ const VaultPage = (props)=>{
};
const renderPaginationControls = ()=>{
- if(!totalBrews) return null;
+ if(!totalBrews || totalBrews < 10) return null;
- const countInt = parseInt(props.query.count || 20);
+ const countInt = parseInt(brewCollection.length || 20);
const totalPages = Math.ceil(totalBrews / countInt);
let startPage, endPage;
@@ -355,7 +355,7 @@ const VaultPage = (props)=>{
};
const renderFoundBrews = ()=>{
- if(searching) {
+ if(searching && !brewCollection) {
return (
Searching
@@ -395,6 +395,7 @@ const VaultPage = (props)=>{
{`Brews found: `}
{totalBrews}
+ {brewCollection.length > 10 && renderPaginationControls()}
{brewCollection.map((brew, index)=>{
return (
{
{renderNavItems()}
-
-
- {renderForm()}
-
- {renderSortBar()}
- {renderFoundBrews()}
-
-
+
+
+ {renderForm()}
+
+ {renderSortBar()}
+ {renderFoundBrews()}
+
+
);
diff --git a/client/homebrew/pages/vaultPage/vaultPage.less b/client/homebrew/pages/vaultPage/vaultPage.less
index a69bcb33b..8a5f3a714 100644
--- a/client/homebrew/pages/vaultPage/vaultPage.less
+++ b/client/homebrew/pages/vaultPage/vaultPage.less
@@ -5,7 +5,7 @@
*:not(input) { user-select : none; }
- .content .dataGroup {
+ :where(.content .dataGroup) {
width : 100%;
height : 100%;
background : white;
@@ -169,9 +169,10 @@
width : 100%;
height : 100%;
max-height : 100%;
- padding : 50px 50px 70px 50px;
+ padding : 70px 50px;
overflow-y : scroll;
background-color : #2C3E50;
+ container-type : inline-size;
h3 { font-size : 25px; }
@@ -236,6 +237,7 @@
margin-right : 40px;
color : black;
isolation : isolate;
+ transition : width 0.5s;
&::after {
position : absolute;
@@ -269,8 +271,8 @@
.links { z-index : 2; }
hr {
- margin : 0px;
visibility : hidden;
+ margin : 0px;
}
.thumbnail { z-index : -1; }
@@ -278,30 +280,37 @@
.paginationControls {
position : absolute;
+ top : 35px;
left : 50%;
display : grid;
grid-template-areas : 'previousPage currentPage nextPage';
grid-template-columns : 50px 1fr 50px;
+ gap : 20px;
place-items : center;
width : auto;
+ font-size : 15px;
translate : -50%;
+ &:last-child { top : unset; }
+
.pages {
display : flex;
grid-area : currentPage;
+ gap : 1em;
justify-content : space-evenly;
width : 100%;
height : 100%;
- padding : 5px 8px;
text-align : center;
.pageNumber {
- margin-inline : 1vw;
+ place-content : center;
+ width : fit-content;
+ min-width : 2em;
font-family : 'Open Sans';
font-weight : 900;
color : white;
- text-underline-position : under;
text-wrap : nowrap;
+ text-underline-position : under;
cursor : pointer;
&.currentPage {
@@ -329,7 +338,6 @@
}
}
}
-
}
@keyframes trailingDots {
@@ -344,8 +352,7 @@
100% { content : ' ...'; }
}
-// media query for when the page is smaller than 1079 px in width
-@media screen and (max-width : 1079px) {
+@container (width < 670px) {
.vaultPage {
.dataGroup.form .brewLookup { padding : 1px 20px 20px 10px; }
diff --git a/package-lock.json b/package-lock.json
index c87c30c6d..ac8ca11af 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "homebrewery",
- "version": "3.17.0",
+ "version": "3.18.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "homebrewery",
- "version": "3.17.0",
+ "version": "3.18.0",
"hasInstallScript": true,
"license": "MIT",
"dependencies": {
@@ -23,7 +23,6 @@
"cors": "^2.8.5",
"create-react-class": "^15.7.0",
"dedent-tabs": "^0.10.3",
- "dompurify": "^3.2.4",
"expr-eval": "^2.0.2",
"express": "^4.21.2",
"express-async-handler": "^1.2.0",
@@ -36,14 +35,14 @@
"lodash": "^4.17.21",
"marked": "14.0.0",
"marked-emoji": "^2.0.0",
- "marked-extended-tables": "^2.0.0",
+ "marked-extended-tables": "^2.0.1",
"marked-gfm-heading-id": "^4.0.1",
"marked-smartypants-lite": "^1.0.3",
"marked-subsuper-text": "^1.0.3",
"markedLegacy": "npm:marked@^0.3.19",
"moment": "^2.30.1",
"mongoose": "^8.12.1",
- "nanoid": "5.1.2",
+ "nanoid": "5.1.3",
"nconf": "^0.12.1",
"react": "^18.3.1",
"react-dom": "^18.3.1",
@@ -56,7 +55,7 @@
"devDependencies": {
"@stylistic/stylelint-plugin": "^3.1.2",
"babel-plugin-transform-import-meta": "^2.3.2",
- "eslint": "^9.21.0",
+ "eslint": "^9.22.0",
"eslint-plugin-jest": "^28.11.0",
"eslint-plugin-react": "^7.37.4",
"globals": "^16.0.0",
@@ -1877,6 +1876,16 @@
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
}
},
+ "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==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ }
+ },
"node_modules/@eslint/core": {
"version": "0.12.0",
"resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.12.0.tgz",
@@ -1928,9 +1937,9 @@
}
},
"node_modules/@eslint/js": {
- "version": "9.21.0",
- "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.21.0.tgz",
- "integrity": "sha512-BqStZ3HX8Yz6LvsF5ByXYrtigrV5AXADWLAGc7PH/1SxOb7/FIYYMszZZWiUou/GB9P2lXWk2SV4d+Z8h0nknw==",
+ "version": "9.22.0",
+ "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.22.0.tgz",
+ "integrity": "sha512-vLFajx9o8d1/oL2ZkpMYbkLv8nDB6yaIwFNt7nI4+I80U/z03SxmfOMsLbvWr3p7C+Wnoh//aOu2pQW8cS0HCQ==",
"dev": true,
"license": "MIT",
"engines": {
@@ -2943,12 +2952,6 @@
"dev": true,
"license": "MIT"
},
- "node_modules/@types/trusted-types": {
- "version": "2.0.7",
- "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz",
- "integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==",
- "optional": true
- },
"node_modules/@types/webidl-conversions": {
"version": "7.0.3",
"resolved": "https://registry.npmjs.org/@types/webidl-conversions/-/webidl-conversions-7.0.3.tgz",
@@ -5356,15 +5359,6 @@
"npm": ">=1.2"
}
},
- "node_modules/dompurify": {
- "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"
- }
- },
"node_modules/dunder-proto": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
@@ -5677,18 +5671,19 @@
"license": "MIT"
},
"node_modules/eslint": {
- "version": "9.21.0",
- "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.21.0.tgz",
- "integrity": "sha512-KjeihdFqTPhOMXTt7StsDxriV4n66ueuF/jfPNC3j/lduHwr/ijDwJMsF+wyMJethgiKi5wniIE243vi07d3pg==",
+ "version": "9.22.0",
+ "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.22.0.tgz",
+ "integrity": "sha512-9V/QURhsRN40xuHXWjV64yvrzMjcz7ZyNoF2jJFmy9j/SLk0u1OLSZgXi28MrXjymnjEGSR80WCdab3RGMDveQ==",
"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/core": "^0.12.0",
"@eslint/eslintrc": "^3.3.0",
- "@eslint/js": "9.21.0",
+ "@eslint/js": "9.22.0",
"@eslint/plugin-kit": "^0.2.7",
"@humanfs/node": "^0.16.6",
"@humanwhocodes/module-importer": "^1.0.1",
@@ -5700,7 +5695,7 @@
"cross-spawn": "^7.0.6",
"debug": "^4.3.2",
"escape-string-regexp": "^4.0.0",
- "eslint-scope": "^8.2.0",
+ "eslint-scope": "^8.3.0",
"eslint-visitor-keys": "^4.2.0",
"espree": "^10.3.0",
"esquery": "^1.5.0",
@@ -5825,10 +5820,11 @@
}
},
"node_modules/eslint-scope": {
- "version": "8.2.0",
- "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.2.0.tgz",
- "integrity": "sha512-PHlWUfG6lvPc3yvP5A4PNyBL1W8fkDUccmI21JUu/+GKZBoH/W5u6usENXUrWFRsyoW5ACUjFGgAFQp5gUlb/A==",
+ "version": "8.3.0",
+ "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.3.0.tgz",
+ "integrity": "sha512-pUNxi75F8MJ/GdeKtVLSbYg4ZI34J6C0C7sbL4YOp2exGwen7ZsuBqKzUhXd0qMQ362yET3z+uPwKeg/0C2XCQ==",
"dev": true,
+ "license": "BSD-2-Clause",
"dependencies": {
"esrecurse": "^4.3.0",
"estraverse": "^5.2.0"
@@ -5981,6 +5977,7 @@
"resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz",
"integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==",
"dev": true,
+ "license": "BSD-2-Clause",
"dependencies": {
"estraverse": "^5.2.0"
},
@@ -9861,9 +9858,9 @@
}
},
"node_modules/marked-extended-tables": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/marked-extended-tables/-/marked-extended-tables-2.0.0.tgz",
- "integrity": "sha512-MWmxvFLkJYQ5K46MFieOP1uueMgfIpDPMkYLLgIyTl20HyvLIW4J37BAtIGfR8fDp2uE4Kyyev4s3dhoT2FQOA==",
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/marked-extended-tables/-/marked-extended-tables-2.0.1.tgz",
+ "integrity": "sha512-DV4Si978ZdaFbycIxzG4TdaNMtC0J8QfIKj1UOCejgJHwVjVJse8DNdJriWDeo/n74DWVYpRC6S56AdgWDPrPA==",
"license": "MIT",
"peerDependencies": {
"marked": ">=3 <16"
@@ -10409,9 +10406,9 @@
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
},
"node_modules/nanoid": {
- "version": "5.1.2",
- "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-5.1.2.tgz",
- "integrity": "sha512-b+CiXQCNMUGe0Ri64S9SXFcP9hogjAJ2Rd6GdVxhPLRm7mhGaM7VgOvCAJ1ZshfHbqVDI3uqTI5C8/GaKuLI7g==",
+ "version": "5.1.3",
+ "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-5.1.3.tgz",
+ "integrity": "sha512-zAbEOEr7u2CbxwoMRlz/pNSpRP0FdAU4pRaYunCdEezWohXFs+a0Xw7RfkKaezMsmSM1vttcLthJtwRnVtOfHQ==",
"funding": [
{
"type": "github",
diff --git a/package.json b/package.json
index 724a610ac..50dda84ce 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.17.0",
+ "version": "3.18.0",
"type": "module",
"engines": {
"npm": "^10.2.x",
@@ -97,7 +97,6 @@
"cors": "^2.8.5",
"create-react-class": "^15.7.0",
"dedent-tabs": "^0.10.3",
- "dompurify": "^3.2.4",
"expr-eval": "^2.0.2",
"express": "^4.21.2",
"express-async-handler": "^1.2.0",
@@ -110,14 +109,14 @@
"lodash": "^4.17.21",
"marked": "14.0.0",
"marked-emoji": "^2.0.0",
- "marked-extended-tables": "^2.0.0",
+ "marked-extended-tables": "^2.0.1",
"marked-gfm-heading-id": "^4.0.1",
"marked-smartypants-lite": "^1.0.3",
"marked-subsuper-text": "^1.0.3",
"markedLegacy": "npm:marked@^0.3.19",
"moment": "^2.30.1",
"mongoose": "^8.12.1",
- "nanoid": "5.1.2",
+ "nanoid": "5.1.3",
"nconf": "^0.12.1",
"react": "^18.3.1",
"react-dom": "^18.3.1",
@@ -130,7 +129,7 @@
"devDependencies": {
"@stylistic/stylelint-plugin": "^3.1.2",
"babel-plugin-transform-import-meta": "^2.3.2",
- "eslint": "^9.21.0",
+ "eslint": "^9.22.0",
"eslint-plugin-jest": "^28.11.0",
"eslint-plugin-react": "^7.37.4",
"globals": "^16.0.0",
diff --git a/server/vault.api.js b/server/vault.api.js
index 6a7b9fb91..3a6c6e989 100644
--- a/server/vault.api.js
+++ b/server/vault.api.js
@@ -1,6 +1,6 @@
import express from 'express';
import asyncHandler from 'express-async-handler';
-import {model as HomebrewModel } from './homebrew.model.js';
+import { model as HomebrewModel } from './homebrew.model.js';
const router = express.Router();
@@ -29,7 +29,7 @@ const rendererConditions = (legacy, v3)=>{
return {}; // If all renderers selected, renderer field not needed in query for speed
};
-const sortConditions = (sort, dir) => {
+const sortConditions = (sort, dir)=>{
return { [sort]: dir === 'asc' ? 1 : -1 };
};
diff --git a/themes/V3/5ePHB/style.less b/themes/V3/5ePHB/style.less
index 5eebcb12e..00804c19c 100644
--- a/themes/V3/5ePHB/style.less
+++ b/themes/V3/5ePHB/style.less
@@ -545,8 +545,9 @@
columns : 1;
text-align : center;
&::after { display : none; }
+ .frontCover { position : absolute; }
h1 {
- margin-top : 1.2cm;
+ margin-top : 1.55cm;
margin-bottom : 0;
font-family : 'NodestoCapsCondensed';
font-size : 2.245cm;
@@ -632,8 +633,9 @@
columns : 1;
text-align : center;
&::after { display : none; }
+ .insideCover { position : absolute; }
h1 {
- margin-top : 1.2cm;
+ margin-top : 1.55cm;
margin-bottom : 0;
font-family : 'NodestoCapsCondensed';
font-size : 2.1cm;