@@ -370,7 +397,7 @@ const MetadataEditor = createClass({
values={this.props.metadata.invitedAuthors}
notes={['Invited author usernames are case sensitive.', 'After adding an invited author, send them the edit link. There, they can choose to accept or decline the invitation.']}
onChange={(e)=>this.handleFieldChange('invitedAuthors', e)}
- />
+ />
diff --git a/client/homebrew/editor/metadataEditor/metadataEditor.less b/client/homebrew/editor/metadataEditor/metadataEditor.less
index 2cff01cfe..c5658a796 100644
--- a/client/homebrew/editor/metadataEditor/metadataEditor.less
+++ b/client/homebrew/editor/metadataEditor/metadataEditor.less
@@ -1,9 +1,12 @@
@import 'naturalcrit/styles/colors.less';
+.userThemeName {
+ padding-left: 10px;
+ padding-right: 10px;
+}
.metadataEditor {
position : absolute;
- z-index : 5;
box-sizing : border-box;
width : 100%;
height : calc(100vh - 54px); // 54px is the height of the navbar + snippet bar. probably a better way to dynamic get this.
@@ -71,8 +74,7 @@
border : 1px solid gray;
&:focus { outline : 1px solid #444444; }
}
- &.thumbnail {
- height : 1.4em;
+ &.thumbnail, &.themes{
label { line-height : 2.0em; }
.value {
overflow : hidden;
@@ -88,6 +90,17 @@
}
}
+ &.themes{
+ .value {
+ overflow : visible;
+ text-overflow : auto;
+ }
+ button {
+ padding-left: 5px;
+ padding-right: 5px;
+ }
+ }
+
&.description {
flex : 1;
textarea.value {
@@ -156,89 +169,73 @@
}
.themes.field {
- .navDropdownContainer {
+ & .dropdown-container {
position : relative;
z-index : 100;
background-color : white;
- &.disabled {
- font-style : italic;
- color : dimgray;
- background-color : darkgray;
- }
- & > div:first-child {
- padding : 3px 3px;
- background-color : inherit;
- border : 1px solid gray;
- i { float : right; }
- &:hover {
- color : white;
- background-color : @blue;
+ }
+ & .dropdown-options {
+ overflow-y : visible;
+ }
+ .disabled {
+ font-style : italic;
+ color : dimgray;
+ background-color : darkgray;
+ }
+ .item {
+ position : relative;
+ padding : 3px 3px;
+ overflow : visible;
+ background-color : white;
+ border-top : 1px solid rgb(118, 118, 118);
+ .preview {
+ position : absolute;
+ top : 0;
+ right : 0;
+ z-index : 1;
+ display : flex;
+ flex-direction : column;
+ width : 200px;
+ overflow : hidden;
+ color : black;
+ background : #CCCCCC;
+ border-radius : 5px;
+ box-shadow : 0 0 5px black;
+ opacity : 0;
+ transition : opacity 250ms ease;
+ h6 {
+ padding-block : 0.5em;
+ padding-inline : 1em;
+ font-weight : 900;
+ border-bottom : 2px solid hsl(0,0%,40%);
}
}
- .navDropdown .item > p {
- width : 45%;
- height : 1.1em;
- overflow : hidden;
- text-overflow : ellipsis;
- white-space : nowrap;
- }
- .navDropdown {
- position : absolute;
- width : 100%;
- box-shadow : 0px 5px 10px rgba(0, 0, 0, 0.3);
- .item {
- position : relative;
- padding : 3px 3px;
- overflow : visible;
- background-color : white;
- border-top : 1px solid rgb(118, 118, 118);
- .preview {
- position : absolute;
- top : 0;
- right : 0;
- z-index : 1;
- display : flex;
- flex-direction : column;
- width : 200px;
- overflow : hidden;
- color : black;
- background : #CCCCCC;
- border-radius : 5px;
- box-shadow : 0 0 5px black;
- opacity : 0;
- transition : opacity 250ms ease;
- h6 {
- padding-block : 0.5em;
- padding-inline : 1em;
- font-weight : 900;
- border-bottom : 2px solid hsl(0,0%,40%);
- }
- }
- &:hover {
- color : white;
- background-color : @blue;
- }
- &:hover > .preview { opacity : 1; }
- .texture-container {
- position : absolute;
- top : 0;
- left : 0;
- width : 100%;
- height : 100%;
- min-height : 100%;
- overflow : hidden;
- > img {
- position : absolute;
- top : 0px;
- right : 0;
- width : 50%;
- min-height : 100%;
- -webkit-mask-image : linear-gradient(90deg, transparent, black 20%);
- mask-image : linear-gradient(90deg, transparent, black 20%);
- }
- }
+
+ .texture-container {
+ position : absolute;
+ top : 0;
+ left : 0;
+ width : 100%;
+ height : 100%;
+ min-height : 100%;
+ overflow : hidden;
+ > img {
+ position : absolute;
+ top : 0;
+ right : 0;
+ width : 50%;
+ min-height : 100%;
+ -webkit-mask-image : linear-gradient(90deg, transparent, black 20%);
+ mask-image : linear-gradient(90deg, transparent, black 20%);
}
}
+
+ &:hover {
+ color : white;
+ background-color : @blue;
+ filter : unset;
+ }
+ &:hover > .preview { opacity : 1; }
}
}
diff --git a/client/homebrew/editor/metadataEditor/validations.js b/client/homebrew/editor/metadataEditor/validations.js
index 32c8131f6..b475783a4 100644
--- a/client/homebrew/editor/metadataEditor/validations.js
+++ b/client/homebrew/editor/metadataEditor/validations.js
@@ -27,6 +27,19 @@ module.exports = {
(value)=>{
return new RegExp(/^([a-zA-Z]{2,3})(-[a-zA-Z]{4})?(-(?:[0-9]{3}|[a-zA-Z]{2}))?$/).test(value) === false && (value.length > 0) ? 'Invalid language code.' : null;
}
+ ],
+ theme: [
+ (value) => {
+ const URL = global.config.baseUrl.replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&'); //Escape any regex characters
+ const shareIDPattern = '[a-zA-Z0-9-_]{12}';
+ const shareURLRegex = new RegExp(`^${URL}\\/share\\/${shareIDPattern}$`);
+ const shareIDRegex = new RegExp(`^${shareIDPattern}$`);
+ if (value?.length === 0) return null;
+ if (shareURLRegex.test(value)) return null;
+ if (shareIDRegex.test(value)) return null;
+
+ return 'Must be a valid Share URL or a 12-character ID.';
+ }
]
};
diff --git a/client/homebrew/navbar/error-navitem.jsx b/client/homebrew/navbar/error-navitem.jsx
index f6788e6d5..3de26ca56 100644
--- a/client/homebrew/navbar/error-navitem.jsx
+++ b/client/homebrew/navbar/error-navitem.jsx
@@ -116,6 +116,19 @@ const ErrorNavItem = createClass({
;
}
+ if(HBErrorCode === '10') {
+ return
Oops!
diff --git a/client/homebrew/pages/basePages/uiPage/uiPage.less b/client/homebrew/pages/basePages/uiPage/uiPage.less
index 913c74a2e..49cb8311d 100644
--- a/client/homebrew/pages/basePages/uiPage/uiPage.less
+++ b/client/homebrew/pages/basePages/uiPage/uiPage.less
@@ -59,11 +59,6 @@
padding-left : 1.25em;
list-style : square;
}
- .blank {
- height : 1em;
- margin-top : 0;
- & + * { margin-top : 0; }
- }
}
}
}
\ No newline at end of file
diff --git a/client/homebrew/pages/editPage/editPage.jsx b/client/homebrew/pages/editPage/editPage.jsx
index ffb6a6b40..4db6d6e23 100644
--- a/client/homebrew/pages/editPage/editPage.jsx
+++ b/client/homebrew/pages/editPage/editPage.jsx
@@ -379,7 +379,7 @@ const EditPage = createClass({
const title = `${this.props.brew.title} ${systems}`;
const text = `Hey guys! I've been working on this homebrew. I'd love your feedback. Check it out.
-**[Homebrewery Link](${global.config.publicUrl}/share/${shareLink})**`;
+**[Homebrewery Link](${global.config.baseUrl}/share/${shareLink})**`;
return `https://www.reddit.com/r/UnearthedArcana/submit?title=${encodeURIComponent(title.toWellFormed())}&text=${encodeURIComponent(text)}`;
},
@@ -410,7 +410,7 @@ const EditPage = createClass({
view
- {navigator.clipboard.writeText(`${global.config.publicUrl}/share/${shareLink}`);}}>
+ {navigator.clipboard.writeText(`${global.config.baseUrl}/share/${shareLink}`);}}>
copy url
@@ -443,6 +443,7 @@ const EditPage = createClass({
reportError={this.errorReported}
renderer={this.state.brew.renderer}
userThemes={this.props.userThemes}
+ themeBundle={this.state.themeBundle}
snippetBundle={this.state.themeBundle.snippets}
updateBrew={this.updateBrew}
onCursorPageChange={this.handleEditorCursorPageChange}
diff --git a/client/homebrew/pages/errorPage/errors/errorIndex.js b/client/homebrew/pages/errorPage/errors/errorIndex.js
index 2c7be5d4b..c2c49f958 100644
--- a/client/homebrew/pages/errorPage/errors/errorIndex.js
+++ b/client/homebrew/pages/errorPage/errors/errorIndex.js
@@ -167,6 +167,14 @@ const errorIndex = (props)=>{
**Requested access:** ${props.brew.accessType}
**Brew ID:** ${props.brew.brewId}`,
+
+ // Theme Not Valid
+ '10' : dedent`
+ ## The selected theme is not tagged as a theme.
+
+ The brew selected as a theme exists, but has not been marked for use as a theme with the \`theme:meta\` tag.
+
+ If the selected brew is your document, you may designate it as a theme by adding the \`theme:meta\` tag.`,
//account page when account is not defined
'50' : dedent`
diff --git a/client/homebrew/pages/newPage/newPage.jsx b/client/homebrew/pages/newPage/newPage.jsx
index ee2c67d5f..1d5887b8a 100644
--- a/client/homebrew/pages/newPage/newPage.jsx
+++ b/client/homebrew/pages/newPage/newPage.jsx
@@ -233,6 +233,7 @@ const NewPage = createClass({
onMetaChange={this.handleMetaChange}
renderer={this.state.brew.renderer}
userThemes={this.props.userThemes}
+ themeBundle={this.state.themeBundle}
snippetBundle={this.state.themeBundle.snippets}
onCursorPageChange={this.handleEditorCursorPageChange}
onViewPageChange={this.handleEditorViewPageChange}
diff --git a/package-lock.json b/package-lock.json
index bd3f71491..d17771395 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -10,9 +10,9 @@
"hasInstallScript": true,
"license": "MIT",
"dependencies": {
- "@babel/core": "^7.26.8",
- "@babel/plugin-transform-runtime": "^7.26.8",
- "@babel/preset-env": "^7.26.8",
+ "@babel/core": "^7.26.9",
+ "@babel/plugin-transform-runtime": "^7.26.9",
+ "@babel/preset-env": "^7.26.9",
"@babel/preset-react": "^7.26.3",
"@googleapis/drive": "^8.14.0",
"body-parser": "^1.20.2",
@@ -39,15 +39,16 @@
"marked-extended-tables": "^1.1.0",
"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.10.0",
- "nanoid": "5.0.9",
+ "mongoose": "^8.10.1",
+ "nanoid": "5.1.0",
"nconf": "^0.12.1",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-frame-component": "^4.1.3",
- "react-router": "^7.1.5",
+ "react-router": "^7.2.0",
"sanitize-filename": "1.6.3",
"superagent": "^10.1.1",
"vitreum": "git+https://git@github.com/calculuschild/vitreum.git"
@@ -55,10 +56,10 @@
"devDependencies": {
"@stylistic/stylelint-plugin": "^3.1.2",
"babel-plugin-transform-import-meta": "^2.3.2",
- "eslint": "^9.20.0",
+ "eslint": "^9.20.1",
"eslint-plugin-jest": "^28.11.0",
"eslint-plugin-react": "^7.37.4",
- "globals": "^15.14.0",
+ "globals": "^15.15.0",
"jest": "^29.7.0",
"jest-expect-message": "^1.1.3",
"jsdom-global": "^3.0.2",
@@ -110,22 +111,21 @@
}
},
"node_modules/@babel/core": {
- "version": "7.26.8",
- "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.26.8.tgz",
- "integrity": "sha512-l+lkXCHS6tQEc5oUpK28xBOZ6+HwaH7YwoYQbLFiYb4nS2/l1tKnZEtEWkD0GuiYdvArf9qBS0XlQGXzPMsNqQ==",
+ "version": "7.26.9",
+ "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.26.9.tgz",
+ "integrity": "sha512-lWBYIrF7qK5+GjY5Uy+/hEgp8OJWOD/rpy74GplYRhEauvbHDeFB8t5hPOZxCZ0Oxf4Cc36tK51/l3ymJysrKw==",
"license": "MIT",
"dependencies": {
"@ampproject/remapping": "^2.2.0",
"@babel/code-frame": "^7.26.2",
- "@babel/generator": "^7.26.8",
+ "@babel/generator": "^7.26.9",
"@babel/helper-compilation-targets": "^7.26.5",
"@babel/helper-module-transforms": "^7.26.0",
- "@babel/helpers": "^7.26.7",
- "@babel/parser": "^7.26.8",
- "@babel/template": "^7.26.8",
- "@babel/traverse": "^7.26.8",
- "@babel/types": "^7.26.8",
- "@types/gensync": "^1.0.0",
+ "@babel/helpers": "^7.26.9",
+ "@babel/parser": "^7.26.9",
+ "@babel/template": "^7.26.9",
+ "@babel/traverse": "^7.26.9",
+ "@babel/types": "^7.26.9",
"convert-source-map": "^2.0.0",
"debug": "^4.1.0",
"gensync": "^1.0.0-beta.2",
@@ -141,13 +141,13 @@
}
},
"node_modules/@babel/generator": {
- "version": "7.26.8",
- "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.26.8.tgz",
- "integrity": "sha512-ef383X5++iZHWAXX0SXQR6ZyQhw/0KtTkrTz61WXRhFM6dhpHulO/RJz79L8S6ugZHJkOOkUrUdxgdF2YiPFnA==",
+ "version": "7.26.9",
+ "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.26.9.tgz",
+ "integrity": "sha512-kEWdzjOAUMW4hAyrzJ0ZaTOu9OmpyDIQicIh0zg0EEcEkYXZb2TjtBhnHi2ViX7PKwZqF4xwqfAm299/QMP3lg==",
"license": "MIT",
"dependencies": {
- "@babel/parser": "^7.26.8",
- "@babel/types": "^7.26.8",
+ "@babel/parser": "^7.26.9",
+ "@babel/types": "^7.26.9",
"@jridgewell/gen-mapping": "^0.3.5",
"@jridgewell/trace-mapping": "^0.3.25",
"jsesc": "^3.0.2"
@@ -377,25 +377,25 @@
}
},
"node_modules/@babel/helpers": {
- "version": "7.26.7",
- "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.26.7.tgz",
- "integrity": "sha512-8NHiL98vsi0mbPQmYAGWwfcFaOy4j2HY49fXJCfuDcdE7fMIsH9a7GdaeXpIBsbT7307WU8KCMp5pUVDNL4f9A==",
+ "version": "7.26.9",
+ "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.26.9.tgz",
+ "integrity": "sha512-Mz/4+y8udxBKdmzt/UjPACs4G3j5SshJJEFFKxlCGPydG4JAHXxjWjAwjd09tf6oINvl1VfMJo+nB7H2YKQ0dA==",
"license": "MIT",
"dependencies": {
- "@babel/template": "^7.25.9",
- "@babel/types": "^7.26.7"
+ "@babel/template": "^7.26.9",
+ "@babel/types": "^7.26.9"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/parser": {
- "version": "7.26.8",
- "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.26.8.tgz",
- "integrity": "sha512-TZIQ25pkSoaKEYYaHbbxkfL36GNsQ6iFiBbeuzAkLnXayKR1yP1zFe+NxuZWWsUyvt8icPU9CCq0sgWGXR1GEw==",
+ "version": "7.26.9",
+ "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.26.9.tgz",
+ "integrity": "sha512-81NWa1njQblgZbQHxWHpxxCzNsa3ZwvFqpUg7P+NNUU6f3UU2jBEg4OlF/J6rl8+PQGh1q6/zWScd001YwcA5A==",
"license": "MIT",
"dependencies": {
- "@babel/types": "^7.26.8"
+ "@babel/types": "^7.26.9"
},
"bin": {
"parser": "bin/babel-parser.js"
@@ -974,11 +974,12 @@
}
},
"node_modules/@babel/plugin-transform-for-of": {
- "version": "7.25.9",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.25.9.tgz",
- "integrity": "sha512-LqHxduHoaGELJl2uhImHwRQudhCM50pT46rIBNvtT/Oql3nqiS3wOwP+5ten7NpYSXrrVLgtZU3DZmPtWZo16A==",
+ "version": "7.26.9",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.26.9.tgz",
+ "integrity": "sha512-Hry8AusVm8LW5BVFgiyUReuoGzPUpdHQQqJY5bZnbbf+ngOHWuCuYFKw/BqaaWlvEUrF91HMhDtEaI1hZzNbLg==",
+ "license": "MIT",
"dependencies": {
- "@babel/helper-plugin-utils": "^7.25.9",
+ "@babel/helper-plugin-utils": "^7.26.5",
"@babel/helper-skip-transparent-expression-wrappers": "^7.25.9"
},
"engines": {
@@ -1406,9 +1407,9 @@
}
},
"node_modules/@babel/plugin-transform-runtime": {
- "version": "7.26.8",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.26.8.tgz",
- "integrity": "sha512-H0jlQxFMI0Q8SyGPsj9pO3ygVQRxPkIGytsL3m1Zqca8KrCPpMlvh+e2dxknqdfS8LFwBw+PpiYPD9qy/FPQpA==",
+ "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==",
"license": "MIT",
"dependencies": {
"@babel/helper-module-imports": "^7.25.9",
@@ -1558,9 +1559,9 @@
}
},
"node_modules/@babel/preset-env": {
- "version": "7.26.8",
- "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.26.8.tgz",
- "integrity": "sha512-um7Sy+2THd697S4zJEfv/U5MHGJzkN2xhtsR3T/SWRbVSic62nbISh51VVfU9JiO/L/Z97QczHTaFVkOU8IzNg==",
+ "version": "7.26.9",
+ "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.26.9.tgz",
+ "integrity": "sha512-vX3qPGE8sEKEAZCWk05k3cpTAE3/nOYca++JA+Rd0z2NCNzabmYvEiSShKzm10zdquOIAVXsy2Ei/DTW34KlKQ==",
"license": "MIT",
"dependencies": {
"@babel/compat-data": "^7.26.8",
@@ -1592,7 +1593,7 @@
"@babel/plugin-transform-dynamic-import": "^7.25.9",
"@babel/plugin-transform-exponentiation-operator": "^7.26.3",
"@babel/plugin-transform-export-namespace-from": "^7.25.9",
- "@babel/plugin-transform-for-of": "^7.25.9",
+ "@babel/plugin-transform-for-of": "^7.26.9",
"@babel/plugin-transform-function-name": "^7.25.9",
"@babel/plugin-transform-json-strings": "^7.25.9",
"@babel/plugin-transform-literals": "^7.25.9",
@@ -1699,30 +1700,30 @@
}
},
"node_modules/@babel/template": {
- "version": "7.26.8",
- "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.26.8.tgz",
- "integrity": "sha512-iNKaX3ZebKIsCvJ+0jd6embf+Aulaa3vNBqZ41kM7iTWjx5qzWKXGHiJUW3+nTpQ18SG11hdF8OAzKrpXkb96Q==",
+ "version": "7.26.9",
+ "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.26.9.tgz",
+ "integrity": "sha512-qyRplbeIpNZhmzOysF/wFMuP9sctmh2cFzRAZOn1YapxBsE1i9bJIY586R/WBLfLcmcBlM8ROBiQURnnNy+zfA==",
"license": "MIT",
"dependencies": {
"@babel/code-frame": "^7.26.2",
- "@babel/parser": "^7.26.8",
- "@babel/types": "^7.26.8"
+ "@babel/parser": "^7.26.9",
+ "@babel/types": "^7.26.9"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/traverse": {
- "version": "7.26.8",
- "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.26.8.tgz",
- "integrity": "sha512-nic9tRkjYH0oB2dzr/JoGIm+4Q6SuYeLEiIiZDwBscRMYFJ+tMAz98fuel9ZnbXViA2I0HVSSRRK8DW5fjXStA==",
+ "version": "7.26.9",
+ "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.26.9.tgz",
+ "integrity": "sha512-ZYW7L+pL8ahU5fXmNbPF+iZFHCv5scFak7MZ9bwaRPLUhHh7QQEMjZUg0HevihoqCM5iSYHN61EyCoZvqC+bxg==",
"license": "MIT",
"dependencies": {
"@babel/code-frame": "^7.26.2",
- "@babel/generator": "^7.26.8",
- "@babel/parser": "^7.26.8",
- "@babel/template": "^7.26.8",
- "@babel/types": "^7.26.8",
+ "@babel/generator": "^7.26.9",
+ "@babel/parser": "^7.26.9",
+ "@babel/template": "^7.26.9",
+ "@babel/types": "^7.26.9",
"debug": "^4.3.1",
"globals": "^11.1.0"
},
@@ -1740,9 +1741,9 @@
}
},
"node_modules/@babel/types": {
- "version": "7.26.8",
- "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.26.8.tgz",
- "integrity": "sha512-eUuWapzEGWFEpHFxgEaBG8e3n6S8L3MSu0oda755rOfabWPnh0Our1AozNFVUxGFIhbKgd1ksprsoDGMinTOTA==",
+ "version": "7.26.9",
+ "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.26.9.tgz",
+ "integrity": "sha512-Y3IR1cRnOxOCDvMmNiym7XpXQ93iGDDPHx+Zj+NM+rg0fBaShfQLkg+hKPaZCEvg5N/LeCo4+Rj/i3FuJsIQaw==",
"license": "MIT",
"dependencies": {
"@babel/helper-string-parser": "^7.25.9",
@@ -2871,12 +2872,6 @@
"integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==",
"dev": true
},
- "node_modules/@types/gensync": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/@types/gensync/-/gensync-1.0.4.tgz",
- "integrity": "sha512-C3YYeRQWp2fmq9OryX+FoDy8nXS6scQ7dPptD8LnFDAUNcKWJjXQKDNJD3HVm+kOUsXhTOkpi69vI4EuAr95bA==",
- "license": "MIT"
- },
"node_modules/@types/graceful-fs": {
"version": "4.1.9",
"resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.9.tgz",
@@ -5665,9 +5660,9 @@
"license": "MIT"
},
"node_modules/eslint": {
- "version": "9.20.0",
- "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.20.0.tgz",
- "integrity": "sha512-aL4F8167Hg4IvsW89ejnpTwx+B/UQRzJPGgbIOl+4XqffWsahVVsLEWoZvnrVuwpWmnRd7XeXmQI1zlKcFDteA==",
+ "version": "9.20.1",
+ "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.20.1.tgz",
+ "integrity": "sha512-m1mM33o6dBUjxl2qb6wv6nGNwCAsns1eKtaQ4l/NPHeTvhiUPbtdfMyktxN4B3fgHIgsYh1VT3V9txblpQHq+g==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -6813,10 +6808,11 @@
}
},
"node_modules/globals": {
- "version": "15.14.0",
- "resolved": "https://registry.npmjs.org/globals/-/globals-15.14.0.tgz",
- "integrity": "sha512-OkToC372DtlQeje9/zHIo5CT8lRP/FUgEOKBEhU4e0abL7J7CD24fD9ohiLN5hagG/kWCYj4K5oaxxtj2Z0Dig==",
+ "version": "15.15.0",
+ "resolved": "https://registry.npmjs.org/globals/-/globals-15.15.0.tgz",
+ "integrity": "sha512-7ACyT3wmyp3I61S4fG682L0VA2RGD9otkqGJIwNUMF1SWUombIIk+af1unuDYgMm082aHYwD+mzJvv9Iu8dsgg==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": ">=18"
},
@@ -9883,6 +9879,15 @@
"marked": ">=4 <16"
}
},
+ "node_modules/marked-subsuper-text": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/marked-subsuper-text/-/marked-subsuper-text-1.0.3.tgz",
+ "integrity": "sha512-v5hVVJo6L7HQtplIT8OYNbRWMCGupXYuZ7U9qTsC4yLDtfw24oM5xmWVYfzqzX6hD7KneMfDssMPt6U7fslbxQ==",
+ "license": "MIT",
+ "peerDependencies": {
+ "marked": ">=3 <16"
+ }
+ },
"node_modules/markedLegacy": {
"name": "marked",
"version": "0.3.19",
@@ -10238,9 +10243,9 @@
}
},
"node_modules/mongoose": {
- "version": "8.10.0",
- "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-8.10.0.tgz",
- "integrity": "sha512-nLhk3Qrv6q/HpD2k1O7kbBqsq+/kmKpdv5KJ+LLhQlII3e1p/SSLoLP6jMuSiU6+iLK7zFw4T1niAk3mA3QVug==",
+ "version": "8.10.1",
+ "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-8.10.1.tgz",
+ "integrity": "sha512-5beTeBZnJNndRXU9rxPol0JmTWZMAtgkPbooROkGilswvrZALDERY4cJrGZmgGwDS9dl0mxiB7si+Mv9Yms2fg==",
"license": "MIT",
"dependencies": {
"bson": "^6.10.1",
@@ -10393,9 +10398,9 @@
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
},
"node_modules/nanoid": {
- "version": "5.0.9",
- "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-5.0.9.tgz",
- "integrity": "sha512-Aooyr6MXU6HpvvWXKoVoXwKMs/KyVakWwg7xQfv5/S/RIgJMy0Ifa45H9qqYy7pTCszrHzP21Uk4PZq2HpEM8Q==",
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-5.1.0.tgz",
+ "integrity": "sha512-zDAl/llz8Ue/EblwSYwdxGBYfj46IM1dhjVi8dyp9LQffoIGxJEAHj2oeZ4uNcgycSRcQ83CnfcZqEJzVDLcDw==",
"funding": [
{
"type": "github",
@@ -11666,9 +11671,9 @@
"license": "MIT"
},
"node_modules/react-router": {
- "version": "7.1.5",
- "resolved": "https://registry.npmjs.org/react-router/-/react-router-7.1.5.tgz",
- "integrity": "sha512-8BUF+hZEU4/z/JD201yK6S+UYhsf58bzYIDq2NS1iGpwxSXDu7F+DeGSkIXMFBuHZB21FSiCzEcUb18cQNdRkA==",
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/react-router/-/react-router-7.2.0.tgz",
+ "integrity": "sha512-fXyqzPgCPZbqhrk7k3hPcCpYIlQ2ugIXDboHUzhJISFVy2DEPsmHgN588MyGmkIOv3jDgNfUE3kJi83L28s/LQ==",
"license": "MIT",
"dependencies": {
"@types/cookie": "^0.6.0",
diff --git a/package.json b/package.json
index 342af4d6e..ac27c793a 100644
--- a/package.json
+++ b/package.json
@@ -39,7 +39,6 @@
"test:definition-lists": "jest tests/markdown/definition-lists.test.js --verbose --noStackTrace",
"test:hard-breaks": "jest tests/markdown/hard-breaks.test.js --verbose --noStackTrace",
"test:non-breaking-spaces": "jest tests/markdown/non-breaking-spaces.test.js --verbose --noStackTrace",
- "test:paragraph-justification": "jest tests/markdown/paragraph-justification.test.js --verbose --noStackTrace",
"test:emojis": "jest tests/markdown/emojis.test.js --verbose --noStackTrace",
"test:route": "jest tests/routes/static-pages.test.js --verbose",
"test:safehtml": "jest tests/html/safeHTML.test.js --verbose",
@@ -85,9 +84,9 @@
]
},
"dependencies": {
- "@babel/core": "^7.26.8",
- "@babel/plugin-transform-runtime": "^7.26.8",
- "@babel/preset-env": "^7.26.8",
+ "@babel/core": "^7.26.9",
+ "@babel/plugin-transform-runtime": "^7.26.9",
+ "@babel/preset-env": "^7.26.9",
"@babel/preset-react": "^7.26.3",
"@googleapis/drive": "^8.14.0",
"body-parser": "^1.20.2",
@@ -114,15 +113,16 @@
"marked-extended-tables": "^1.1.0",
"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.10.0",
- "nanoid": "5.0.9",
+ "mongoose": "^8.10.1",
+ "nanoid": "5.1.0",
"nconf": "^0.12.1",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-frame-component": "^4.1.3",
- "react-router": "^7.1.5",
+ "react-router": "^7.2.0",
"sanitize-filename": "1.6.3",
"superagent": "^10.1.1",
"vitreum": "git+https://git@github.com/calculuschild/vitreum.git"
@@ -130,10 +130,10 @@
"devDependencies": {
"@stylistic/stylelint-plugin": "^3.1.2",
"babel-plugin-transform-import-meta": "^2.3.2",
- "eslint": "^9.20.0",
+ "eslint": "^9.20.1",
"eslint-plugin-jest": "^28.11.0",
"eslint-plugin-react": "^7.37.4",
- "globals": "^15.14.0",
+ "globals": "^15.15.0",
"jest": "^29.7.0",
"jest-expect-message": "^1.1.3",
"jsdom-global": "^3.0.2",
diff --git a/server/admin.api.js b/server/admin.api.js
index 1a39f020b..e70268afa 100644
--- a/server/admin.api.js
+++ b/server/admin.api.js
@@ -93,7 +93,7 @@ router.get('/admin/finduncompressed', mw.adminOnly, (req, res)=>{
/* Cleans `