diff --git a/.stylelintrc.json b/.stylelintrc.json
index 2c7a9afdf..b5f2e7712 100644
--- a/.stylelintrc.json
+++ b/.stylelintrc.json
@@ -1,48 +1,48 @@
{
- "extends": [
- "stylelint-config-recess-order",
- "stylelint-config-recommended"],
- "plugins": [
- "@stylistic/stylelint-plugin",
- "./stylelint_plugins/declaration-colon-align.js",
- "./stylelint_plugins/declaration-colon-min-space-before",
- "./stylelint_plugins/declaration-block-multi-line-min-declarations"
- ],
- "customSyntax": "postcss-less",
- "rules": {
- "no-descending-specificity" : null,
- "at-rule-no-unknown" : null,
- "function-no-unknown" : null,
- "font-family-no-missing-generic-family-keyword" : null,
- "font-weight-notation" : "named-where-possible",
- "font-family-name-quotes" : "always-unless-keyword",
- "@stylistic/indentation" : "tab",
- "no-duplicate-selectors" : true,
- "@stylistic/color-hex-case" : "upper",
- "color-hex-length" : "long",
- "@stylistic/selector-combinator-space-after" : "always",
- "@stylistic/selector-combinator-space-before" : "always",
- "@stylistic/selector-attribute-operator-space-before" : "never",
- "@stylistic/selector-attribute-operator-space-after" : "never",
- "@stylistic/selector-attribute-brackets-space-inside" : "never",
- "selector-attribute-quotes" : "always",
- "selector-pseudo-element-colon-notation" : "double",
- "@stylistic/selector-pseudo-class-parentheses-space-inside" : "never",
- "@stylistic/block-opening-brace-space-before" : "always",
- "naturalcrit/declaration-colon-min-space-before" : 1,
- "@stylistic/declaration-block-trailing-semicolon" : "always",
- "@stylistic/declaration-colon-space-after" : "always",
- "@stylistic/number-leading-zero" : "always",
- "function-url-quotes" : ["always", { "except": ["empty"] }],
- "function-url-scheme-disallowed-list" : ["data","http"],
- "comment-whitespace-inside" : "always",
- "@stylistic/string-quotes" : "single",
- "@stylistic/media-feature-range-operator-space-before" : "always",
- "@stylistic/media-feature-range-operator-space-after" : "always",
- "@stylistic/media-feature-parentheses-space-inside" : "never",
- "@stylistic/media-feature-colon-space-before" : "always",
- "@stylistic/media-feature-colon-space-after" : "always",
- "naturalcrit/declaration-colon-align" : true,
- "naturalcrit/declaration-block-multi-line-min-declarations": 1
- }
+ "extends": [
+ "stylelint-config-recess-order",
+ "stylelint-config-recommended"],
+ "plugins": [
+ "@stylistic/stylelint-plugin",
+ "./stylelint_plugins/declaration-colon-align.js",
+ "./stylelint_plugins/declaration-colon-min-space-before",
+ "./stylelint_plugins/declaration-block-multi-line-min-declarations"
+ ],
+ "customSyntax": "postcss-less",
+ "rules": {
+ "no-descending-specificity" : null,
+ "at-rule-no-unknown" : null,
+ "function-no-unknown" : null,
+ "font-family-no-missing-generic-family-keyword" : null,
+ "font-weight-notation" : "named-where-possible",
+ "font-family-name-quotes" : "always-unless-keyword",
+ "@stylistic/indentation" : "tab",
+ "no-duplicate-selectors" : true,
+ "@stylistic/color-hex-case" : "upper",
+ "color-hex-length" : "long",
+ "@stylistic/selector-combinator-space-after" : "always",
+ "@stylistic/selector-combinator-space-before" : "always",
+ "@stylistic/selector-attribute-operator-space-before" : "never",
+ "@stylistic/selector-attribute-operator-space-after" : "never",
+ "@stylistic/selector-attribute-brackets-space-inside" : "never",
+ "selector-attribute-quotes" : "always",
+ "selector-pseudo-element-colon-notation" : "double",
+ "@stylistic/selector-pseudo-class-parentheses-space-inside" : "never",
+ "@stylistic/block-opening-brace-space-before" : "always",
+ "naturalcrit/declaration-colon-min-space-before" : 1,
+ "@stylistic/declaration-block-trailing-semicolon" : "always",
+ "@stylistic/declaration-colon-space-after" : "always",
+ "@stylistic/number-leading-zero" : "always",
+ "function-url-quotes" : ["always", { "except": ["empty"] }],
+ "function-url-scheme-disallowed-list" : ["data","http"],
+ "comment-whitespace-inside" : "always",
+ "@stylistic/string-quotes" : "single",
+ "@stylistic/media-feature-range-operator-space-before" : "always",
+ "@stylistic/media-feature-range-operator-space-after" : "always",
+ "@stylistic/media-feature-parentheses-space-inside" : "never",
+ "@stylistic/media-feature-colon-space-before" : "always",
+ "@stylistic/media-feature-colon-space-after" : "always",
+ "naturalcrit/declaration-colon-align" : true,
+ "naturalcrit/declaration-block-multi-line-min-declarations" : 1
+ }
}
diff --git a/changelog.md b/changelog.md
index 3736ba9b0..8cfb499f6 100644
--- a/changelog.md
+++ b/changelog.md
@@ -77,14 +77,100 @@ pre {
}
.varSyntaxTable th:first-of-type {
- width:6cm;
+ width:6cm;
+}
+
+.page .exampleTable td,th {
+ border:1px dashed #00000030;
}
```
-
## changelog
For a full record of development, visit our [Github Page](https://github.com/naturalcrit/homebrewery).
+### Thursday 01/30/2024 - v3.17.0
+
+{{taskList
+##### 5e-Cleric
+
+* [x] Update FAQ
+
+* [x] Fix styling for Vault buttons and checkboxes
+
+* [x] Improve navigation bar styling
+
+* [x] Add feature to change username at https://www.naturalcrit.com/account
+
+* [x] Fix Reddit link crash when title has non-latin chars
+
+##### dbolack
+
+* [x] Fix page shadows toolbar option
+
+Fixes issue [#3919](https://github.com/naturalcrit/homebrewery/issues/3919)
+
+* [x] Add `:>>>` syntax for horizontal :>>>>> spaces
+
+* [x] Update Docker install instructions
+
+Fixes issue [#1930](https://github.com/naturalcrit/homebrewery/issues/1930)
+
+* [x] Allow styling pages via `\page{myStyles}` (with calculuschild)
+
+Fixes issue [#3901](https://github.com/naturalcrit/homebrewery/issues/3901)
+
+* [x] Update Ubuntu install instructions
+
+Fixes issue [#1952](https://github.com/naturalcrit/homebrewery/issues/1952)
+
+* [x] Add `:-:` `:-` `-:` syntax for paragraph alignment, similar to table column alignment; for example:
+
+-: -: Right-aligned
+
+:-: :-: Centered
+
+* [x] Add `:-- 50% --:` syntax to allow setting table column widths by percentage; for example:
+```
+| Narrow | Wide |
+|:- 10% -:|:-90%--:|
+| Cell | Cell |
+```
+
+
+| Narrow | Wide |
+|:- 10% -:|:-90%--:|
+|Cell | Cell |
+{exampleTable}
+
+##### G-Ambatte
+
+* [x] Fix crash when opening brew Properties tab
+
+Fixes issue [#3927](https://github.com/naturalcrit/homebrewery/issues/3927)
+
+* [x] Update error pages with steps to refresh credentials
+
+Fixes issue [#3955](https://github.com/naturalcrit/homebrewery/issues/3955)
+
+* [x] Add {{openSans :fas_rectangle_list: **NAVIGATION**}} menu to the viewer toolbar
+
+##### calculuschild
+
+* [x] Reduce display lag on large brews
+
+##### Gazook89
+
+* [x] Smarter detection of current page number
+
+Fixes issue [#3824](https://github.com/naturalcrit/homebrewery/issues/3824)
+
+##### All
+* [x] Update dependencies and scripts
+* [x] Refactor components and fix various errors
+}}
+
+\column
+
### Wednesday 11/27/2024 - v3.16.1
{{taskList
@@ -131,6 +217,8 @@ Fixes issue [#3744](https://github.com/naturalcrit/homebrewery/issues/3744)
* [x] Multiple code refactors, cleanups, and security fixes
}}
+\page
+
### Saturday 10/12/2024 - v3.16.0
{{taskList
@@ -2053,4 +2141,4 @@ Massive changelog incoming:
* Added `phb.standalone.css` plus a build system for creating it
* Added page numbers and footer text
-* Page accent now flips each page
+* Page accent now flips each page
\ No newline at end of file
diff --git a/client/homebrew/brewRenderer/brewRenderer.jsx b/client/homebrew/brewRenderer/brewRenderer.jsx
index 17f261c2d..a82ea8b34 100644
--- a/client/homebrew/brewRenderer/brewRenderer.jsx
+++ b/client/homebrew/brewRenderer/brewRenderer.jsx
@@ -17,10 +17,9 @@ const dedent = require('dedent-tabs').default;
const { printCurrentBrew } = require('../../../shared/helpers.js');
import HeaderNav from './headerNav/headerNav.jsx';
-
import { safeHTML } from './safeHTML.js';
-
+const PAGEBREAK_REGEX_V3 = /^(?=\\page(?: *{[^\n{}]*})?$)/m;
const PAGE_HEIGHT = 1056;
const INITIAL_CONTENT = dedent`
@@ -78,7 +77,7 @@ const BrewPage = (props)=>{
};
}, []);
- return
+ return
;
};
@@ -126,7 +125,7 @@ const BrewRenderer = (props)=>{
if(props.renderer == 'legacy') {
rawPages = props.text.split('\\page');
} else {
- rawPages = props.text.split(/^\\page$/gm);
+ rawPages = props.text.split(PAGEBREAK_REGEX_V3);
}
const handlePageVisibilityChange = (pageNum, isVisible, isCenter)=>{
@@ -173,20 +172,34 @@ const BrewRenderer = (props)=>{
const renderPage = (pageText, index)=>{
- const styles = {
+ let styles = {
...(!displayOptions.pageShadows ? { boxShadow: 'none' } : {})
// Add more conditions as needed
};
+ let classes = 'page';
+ let attributes = {};
if(props.renderer == 'legacy') {
const html = MarkdownLegacy.render(pageText);
return
;
} else {
+ if(pageText.startsWith('\\page')) {
+ const firstLineTokens = Markdown.marked.lexer(pageText.split('\n', 1)[0])[0].tokens;
+ const injectedTags = firstLineTokens.find((obj)=>obj.injectedTags !== undefined)?.injectedTags;
+ if(injectedTags) {
+ styles = { ...styles, ...injectedTags.styles };
+ styles = _.mapKeys(styles, (v, k) => k.startsWith('--') ? k : _.camelCase(k)); // Convert CSS to camelCase for React
+ classes = [classes, injectedTags.classes].join(' ').trim();
+ attributes = injectedTags.attributes;
+ }
+ pageText = pageText.includes('\n') ? pageText.substring(pageText.indexOf('\n') + 1) : ''; // Remove the \page line
+ }
+
pageText += `\n\n \n\\column\n `; //Artificial column break at page end to emulate column-fill:auto (until `wide` is used, when column-fill:balance will reappear)
const html = Markdown.render(pageText, index);
- return
;
+ return
;
}
};
diff --git a/client/homebrew/brewRenderer/notificationPopup/notificationPopup.jsx b/client/homebrew/brewRenderer/notificationPopup/notificationPopup.jsx
index b2045f13d..38a85e0c7 100644
--- a/client/homebrew/brewRenderer/notificationPopup/notificationPopup.jsx
+++ b/client/homebrew/brewRenderer/notificationPopup/notificationPopup.jsx
@@ -1,6 +1,7 @@
require('./notificationPopup.less');
import React, { useEffect, useState } from 'react';
import request from '../../utils/request-middleware.js';
+import Markdown from 'naturalcrit/markdown.js';
import Dialog from '../../../components/dialog.jsx';
@@ -40,11 +41,10 @@ const NotificationPopup = ()=>{
const renderNotificationsList = ()=>{
if(error) return
{error}
;
-
return notifications.map((notification)=>(
{notification.title}
-
+
));
};
diff --git a/client/homebrew/brewRenderer/notificationPopup/notificationPopup.less b/client/homebrew/brewRenderer/notificationPopup/notificationPopup.less
index 79edf37b2..be642f0fe 100644
--- a/client/homebrew/brewRenderer/notificationPopup/notificationPopup.less
+++ b/client/homebrew/brewRenderer/notificationPopup/notificationPopup.less
@@ -48,17 +48,46 @@
}
ul {
margin-top : 15px;
- font-size : 0.8em;
+ font-size : 0.9em;
list-style-position : outside;
list-style-type : disc;
li {
- margin-top : 1.4em;
- font-size : 0.8em;
- line-height : 1.4em;
- em {
- text-transform:capitalize;
- font-weight : 800;
+ padding-left : 1em;
+ margin-top : 1.5em;
+ font-size : 0.9em;
+ line-height : 1.5em;
+ em {
+ font-weight : 800;
+ text-transform : capitalize;
+ }
+ li {
+ margin-top : 0;
+ line-height : 1.2em;
+ list-style-type : square;
}
}
+ ul ul,ol ol,ul ol,ol ul {
+ margin-bottom : 0px;
+ margin-left : 1.5em;
+ }
}
-}
+
+ /* Markdown styling */
+ code {
+ padding : 0.1em 0.5em;
+ font-family : 'Courier New', 'Courier', monospace;
+ overflow-wrap : break-word;
+ white-space : pre-wrap;
+ background : #08115A;
+ border-radius : 2px;
+ }
+ pre code {
+ display : inline-block;
+ width : 100%;
+ }
+ .blank {
+ height : 1em;
+ margin-top : 0;
+ & + * { margin-top : 0; }
+ }
+}
\ No newline at end of file
diff --git a/client/homebrew/editor/editor.jsx b/client/homebrew/editor/editor.jsx
index bba5f3ad9..2d0a26268 100644
--- a/client/homebrew/editor/editor.jsx
+++ b/client/homebrew/editor/editor.jsx
@@ -12,7 +12,8 @@ const MetadataEditor = require('./metadataEditor/metadataEditor.jsx');
const EDITOR_THEME_KEY = 'HOMEBREWERY-EDITOR-THEME';
-const SNIPPETBAR_HEIGHT = 25;
+const PAGEBREAK_REGEX_V3 = /^(?=\\page(?: *{[^\n{}]*})?$)/m;
+const SNIPPETBAR_HEIGHT = 25;
const DEFAULT_STYLE_TEXT = dedent`
/*=======--- Example CSS styling ---=======*/
/* Any CSS here will apply to your document! */
@@ -126,15 +127,15 @@ const Editor = createClass({
},
updateCurrentCursorPage : function(cursor) {
- const lines = this.props.brew.text.split('\n').slice(0, cursor.line + 1);
- const pageRegex = this.props.brew.renderer == 'V3' ? /^\\page$/ : /\\page/;
+ const lines = this.props.brew.text.split('\n').slice(1, cursor.line + 1);
+ const pageRegex = this.props.brew.renderer == 'V3' ? PAGEBREAK_REGEX_V3 : /\\page/;
const currentPage = lines.reduce((count, line)=>count + (pageRegex.test(line) ? 1 : 0), 1);
this.props.onCursorPageChange(currentPage);
},
updateCurrentViewPage : function(topScrollLine) {
- const lines = this.props.brew.text.split('\n').slice(0, topScrollLine + 1);
- const pageRegex = this.props.brew.renderer == 'V3' ? /^\\page$/ : /\\page/;
+ const lines = this.props.brew.text.split('\n').slice(1, topScrollLine + 1);
+ const pageRegex = this.props.brew.renderer == 'V3' ? PAGEBREAK_REGEX_V3 : /\\page/;
const currentPage = lines.reduce((count, line)=>count + (pageRegex.test(line) ? 1 : 0), 1);
this.props.onViewPageChange(currentPage);
},
@@ -174,7 +175,7 @@ const Editor = createClass({
for (let i=customHighlights.length - 1;i>=0;i--) customHighlights[i].clear();
- let editorPageCount = 2; // start page count from page 2
+ let editorPageCount = 1; // start page count from page 1
_.forEach(this.props.brew.text.split('\n'), (line, lineNumber)=>{
@@ -190,7 +191,10 @@ const Editor = createClass({
// Styling for \page breaks
if((this.props.renderer == 'legacy' && line.includes('\\page')) ||
- (this.props.renderer == 'V3' && line.match(/^\\page$/))) {
+ (this.props.renderer == 'V3' && line.match(PAGEBREAK_REGEX_V3))) {
+
+ if(lineNumber > 0) // Since \page is optional on first line of document,
+ editorPageCount += 1; // don't use it to increment page count; stay at 1
// add back the original class 'background' but also add the new class '.pageline'
codeMirror.addLineClass(lineNumber, 'background', 'pageLine');
@@ -199,8 +203,6 @@ const Editor = createClass({
textContent : editorPageCount
});
codeMirror.setBookmark({ line: lineNumber, ch: line.length }, pageCountElement);
-
- editorPageCount += 1;
};
// New Codemirror styling for V3 renderer
@@ -358,7 +360,7 @@ const Editor = createClass({
if(!this.isText() || isJumping)
return;
- const textSplit = this.props.renderer == 'V3' ? /^\\page$/gm : /\\page/;
+ const textSplit = this.props.renderer == 'V3' ? PAGEBREAK_REGEX_V3 : /\\page/;
const textString = this.props.brew.text.split(textSplit).slice(0, targetPage-1).join(textSplit);
const targetLine = textString.match('\n') ? textString.split('\n').length - 1 : -1;
diff --git a/client/homebrew/pages/errorPage/errors/errorIndex.js b/client/homebrew/pages/errorPage/errors/errorIndex.js
index f7614a37a..2c7be5d4b 100644
--- a/client/homebrew/pages/errorPage/errors/errorIndex.js
+++ b/client/homebrew/pages/errorPage/errors/errorIndex.js
@@ -3,8 +3,8 @@ const dedent = require('dedent-tabs').default;
const loginUrl = 'https://www.naturalcrit.com/login';
// Prevent parsing text (e.g. document titles) as markdown
-const escape = (text) => {
- return text.split('').map(char => `${char.charCodeAt(0)};`).join('');
+const escape = (text = '')=>{
+ return text.split('').map((char)=>`${char.charCodeAt(0)};`).join('');
};
//001-050 : Brew errors
diff --git a/package-lock.json b/package-lock.json
index 281c24b1f..649c6597c 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "homebrewery",
- "version": "3.16.1",
+ "version": "3.17.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "homebrewery",
- "version": "3.16.1",
+ "version": "3.17.0",
"hasInstallScript": true,
"license": "MIT",
"dependencies": {
@@ -23,7 +23,7 @@
"cors": "^2.8.5",
"create-react-class": "^15.7.0",
"dedent-tabs": "^0.10.3",
- "dompurify": "^3.2.3",
+ "dompurify": "^3.2.4",
"expr-eval": "^2.0.2",
"express": "^4.21.2",
"express-async-handler": "^1.2.0",
@@ -34,20 +34,20 @@
"jwt-simple": "^0.5.6",
"less": "^3.13.1",
"lodash": "^4.17.21",
- "marked": "11.2.0",
+ "marked": "13.0.3",
"marked-emoji": "^1.4.3",
"marked-extended-tables": "^1.1.0",
- "marked-gfm-heading-id": "^3.2.0",
- "marked-smartypants-lite": "^1.0.2",
+ "marked-gfm-heading-id": "^4.0.1",
+ "marked-smartypants-lite": "^1.0.3",
"markedLegacy": "npm:marked@^0.3.19",
"moment": "^2.30.1",
- "mongoose": "^8.9.5",
+ "mongoose": "^8.9.6",
"nanoid": "5.0.9",
"nconf": "^0.12.1",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-frame-component": "^4.1.3",
- "react-router": "^7.1.3",
+ "react-router": "^7.1.5",
"sanitize-filename": "1.6.3",
"superagent": "^10.1.1",
"vitreum": "git+https://git@github.com/calculuschild/vitreum.git"
@@ -3837,16 +3837,6 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
- "node_modules/bindings": {
- "version": "1.5.0",
- "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz",
- "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==",
- "license": "MIT",
- "optional": true,
- "dependencies": {
- "file-uri-to-path": "1.0.0"
- }
- },
"node_modules/bn.js": {
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.1.tgz",
@@ -5323,9 +5313,10 @@
}
},
"node_modules/dompurify": {
- "version": "3.2.3",
- "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.2.3.tgz",
- "integrity": "sha512-U1U5Hzc2MO0oW3DF+G9qYN0aT7atAou4AgI0XjWz061nyBPbdxkfdhfy5uMgGn6+oLFCfn44ZGbdDqCzVmlOWA==",
+ "version": "3.2.4",
+ "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.2.4.tgz",
+ "integrity": "sha512-ysFSFEDVduQpyhzAob/kkuJjf5zWkZD8/A9ywSp1byueyuCfHamrCBa14/Oc2iiB0e51B+NpxSl5gmzn+Ms/mg==",
+ "license": "(MPL-2.0 OR Apache-2.0)",
"optionalDependencies": {
"@types/trusted-types": "^2.0.7"
}
@@ -6337,13 +6328,6 @@
"node": ">=16.0.0"
}
},
- "node_modules/file-uri-to-path": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz",
- "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==",
- "license": "MIT",
- "optional": true
- },
"node_modules/fill-range": {
"version": "7.1.1",
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
@@ -6517,20 +6501,6 @@
"integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==",
"license": "ISC"
},
- "node_modules/fsevents": {
- "version": "2.3.3",
- "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
- "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
- "hasInstallScript": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "darwin"
- ],
- "engines": {
- "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
- }
- },
"node_modules/function-bind": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
@@ -9819,9 +9789,9 @@
}
},
"node_modules/marked": {
- "version": "11.2.0",
- "resolved": "https://registry.npmjs.org/marked/-/marked-11.2.0.tgz",
- "integrity": "sha512-HR0m3bvu0jAPYiIvLUUQtdg1g6D247//lvcekpHO1WMvbwDlwSkZAX9Lw4F4YHE1T0HaaNve0tuAWuV1UJ6vtw==",
+ "version": "13.0.3",
+ "resolved": "https://registry.npmjs.org/marked/-/marked-13.0.3.tgz",
+ "integrity": "sha512-rqRix3/TWzE9rIoFGIn8JmsVfhiuC8VIQ8IdX5TfzmeBucdY05/0UlzKaw0eVtpcN/OdVFpBk7CjKGo9iHJ/zA==",
"license": "MIT",
"bin": {
"marked": "bin/marked.js"
@@ -9847,24 +9817,24 @@
}
},
"node_modules/marked-gfm-heading-id": {
- "version": "3.2.0",
- "resolved": "https://registry.npmjs.org/marked-gfm-heading-id/-/marked-gfm-heading-id-3.2.0.tgz",
- "integrity": "sha512-Xfxpr5lXLDLY10XqzSCA9l2dDaiabQUgtYM9hw8yunyVsB/xYBRpiic6BOiY/EAJw1ik1eWr1ET1HKOAPZBhXg==",
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/marked-gfm-heading-id/-/marked-gfm-heading-id-4.1.1.tgz",
+ "integrity": "sha512-EeQZieAQmsI6c2tWLx0ETd0VjPwLV8qi+HT0dIsfVMERm0rCIuXfRvZXJbo1SgUi++lmuR1LVY+QzgNiLNvVpw==",
"license": "MIT",
"dependencies": {
"github-slugger": "^2.0.0"
},
"peerDependencies": {
- "marked": ">=4 <13"
+ "marked": ">=13 <16"
}
},
"node_modules/marked-smartypants-lite": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/marked-smartypants-lite/-/marked-smartypants-lite-1.0.2.tgz",
- "integrity": "sha512-cEANts+s3+gnTzXPvPT2z4V8NfbMEL9QooKUviug0DkaKkXQWrUwDAmFnQAkLSJCw2BQcD8YPDyxu0HJ3mg36w==",
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/marked-smartypants-lite/-/marked-smartypants-lite-1.0.3.tgz",
+ "integrity": "sha512-OOL8cjFog8KtgUFpkihRu6G42Dz2QPOU4k2xfKmMJ0CdoX+BHBDmdesHUdoQKM0mlwTsRSU3shpMeM/LWuUokg==",
"license": "MIT",
"peerDependencies": {
- "marked": ">=4 <12"
+ "marked": ">=4 <16"
}
},
"node_modules/markedLegacy": {
@@ -10217,9 +10187,10 @@
}
},
"node_modules/mongoose": {
- "version": "8.9.5",
- "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-8.9.5.tgz",
- "integrity": "sha512-SPhOrgBm0nKV3b+IIHGqpUTOmgVL5Z3OO9AwkFEmvOZznXTvplbomstCnPOGAyungtRXE5pJTgKpKcZTdjeESg==",
+ "version": "8.9.6",
+ "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-8.9.6.tgz",
+ "integrity": "sha512-ipLvXwNPVuuuq5H3lnSD0lpaRH3DlCoC6emnMVJvweTwxU29uxDJWxMsNpERDQt8JMvYF1HGVuTK+Id2BlQLCA==",
+ "license": "MIT",
"dependencies": {
"bson": "^6.10.1",
"kareem": "2.6.3",
@@ -10365,13 +10336,6 @@
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
},
- "node_modules/nan": {
- "version": "2.20.0",
- "resolved": "https://registry.npmjs.org/nan/-/nan-2.20.0.tgz",
- "integrity": "sha512-bk3gXBZDGILuuo/6sKtr0DQmSThYHLtNCdSdXk9YkxD/jK6X2vmCyyXBBxyqZ4XcnzTyYEAThfX3DCEnLf6igw==",
- "license": "MIT",
- "optional": true
- },
"node_modules/nanoid": {
"version": "5.0.9",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-5.0.9.tgz",
@@ -11646,9 +11610,10 @@
"license": "MIT"
},
"node_modules/react-router": {
- "version": "7.1.3",
- "resolved": "https://registry.npmjs.org/react-router/-/react-router-7.1.3.tgz",
- "integrity": "sha512-EezYymLY6Guk/zLQ2vRA8WvdUhWFEj5fcE3RfWihhxXBW7+cd1LsIiA3lmx+KCmneAGQuyBv820o44L2+TtkSA==",
+ "version": "7.1.5",
+ "resolved": "https://registry.npmjs.org/react-router/-/react-router-7.1.5.tgz",
+ "integrity": "sha512-8BUF+hZEU4/z/JD201yK6S+UYhsf58bzYIDq2NS1iGpwxSXDu7F+DeGSkIXMFBuHZB21FSiCzEcUb18cQNdRkA==",
+ "license": "MIT",
"dependencies": {
"@types/cookie": "^0.6.0",
"cookie": "^1.0.1",
@@ -14429,25 +14394,6 @@
"node": ">=0.10.0"
}
},
- "node_modules/watchify/node_modules/fsevents": {
- "version": "1.2.13",
- "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz",
- "integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==",
- "deprecated": "The v1 package contains DANGEROUS / INSECURE binaries. Upgrade to safe fsevents v2",
- "hasInstallScript": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "darwin"
- ],
- "dependencies": {
- "bindings": "^1.5.0",
- "nan": "^2.12.1"
- },
- "engines": {
- "node": ">= 4.0"
- }
- },
"node_modules/watchify/node_modules/glob-parent": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz",
diff --git a/package.json b/package.json
index 840975977..2bf3a0a93 100644
--- a/package.json
+++ b/package.json
@@ -1,7 +1,7 @@
{
"name": "homebrewery",
"description": "Create authentic looking D&D homebrews using only markdown",
- "version": "3.16.1",
+ "version": "3.17.0",
"type": "module",
"engines": {
"npm": "^10.2.x",
@@ -98,7 +98,7 @@
"cors": "^2.8.5",
"create-react-class": "^15.7.0",
"dedent-tabs": "^0.10.3",
- "dompurify": "^3.2.3",
+ "dompurify": "^3.2.4",
"expr-eval": "^2.0.2",
"express": "^4.21.2",
"express-async-handler": "^1.2.0",
@@ -109,20 +109,20 @@
"jwt-simple": "^0.5.6",
"less": "^3.13.1",
"lodash": "^4.17.21",
- "marked": "11.2.0",
+ "marked": "13.0.3",
"marked-emoji": "^1.4.3",
"marked-extended-tables": "^1.1.0",
- "marked-gfm-heading-id": "^3.2.0",
- "marked-smartypants-lite": "^1.0.2",
+ "marked-gfm-heading-id": "^4.0.1",
+ "marked-smartypants-lite": "^1.0.3",
"markedLegacy": "npm:marked@^0.3.19",
"moment": "^2.30.1",
- "mongoose": "^8.9.5",
+ "mongoose": "^8.9.6",
"nanoid": "5.0.9",
"nconf": "^0.12.1",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-frame-component": "^4.1.3",
- "react-router": "^7.1.3",
+ "react-router": "^7.1.5",
"sanitize-filename": "1.6.3",
"superagent": "^10.1.1",
"vitreum": "git+https://git@github.com/calculuschild/vitreum.git"
diff --git a/stylelint_plugins/declaration-block-multi-line-min-declarations.js b/stylelint_plugins/declaration-block-multi-line-min-declarations.js
index ba40ab5f6..517fd27ec 100644
--- a/stylelint_plugins/declaration-block-multi-line-min-declarations.js
+++ b/stylelint_plugins/declaration-block-multi-line-min-declarations.js
@@ -1,5 +1,5 @@
-const stylelint = require('stylelint');
-const { isNumber } = require('stylelint/lib/utils/validateTypes.cjs');
+import stylelint from 'stylelint';
+import { isNumber } from 'stylelint/lib/utils/validateTypes.mjs';
const { report, ruleMessages, validateOptions } = stylelint.utils;
const ruleName = 'naturalcrit/declaration-block-multi-line-min-declarations';
@@ -7,9 +7,8 @@ const messages = ruleMessages(ruleName, {
expected : (decls)=>`Rule with ${decls} declaration${decls == 1 ? '' : 's'} should be single line`,
});
-
-module.exports = stylelint.createPlugin(ruleName, function getPlugin(primaryOption, secondaryOptionObject, context) {
- return function lint(postcssRoot, postcssResult) {
+const ruleFunction = (primaryOption, secondaryOptionObject, context)=>{
+ return (postcssRoot, postcssResult)=>{
const validOptions = validateOptions(
postcssResult,
@@ -20,26 +19,23 @@ module.exports = stylelint.createPlugin(ruleName, function getPlugin(primaryOpti
}
);
- if(!validOptions) { //If the options are invalid, don't lint
+ if(!validOptions) //If the options are invalid, don't lint
return;
- }
+
const isAutoFixing = Boolean(context.fix);
postcssRoot.walkRules((rule)=>{ //Iterate CSS rules
//Apply rule only if all children are decls (no further nested rules)
- if(rule.nodes.length > primaryOption || !rule.nodes.every((node)=>node.type === 'decl')) {
+ if(rule.nodes.length > primaryOption || !rule.nodes.every((node)=>node.type === 'decl'))
return;
- }
//Ignore if already one line
if(!rule.nodes.some((node)=>node.raws.before.includes('\n')) && !rule.raws.after.includes('\n'))
return;
if(isAutoFixing) { //We are in “fix” mode
- rule.each((decl)=>{
- decl.raws.before = ' ';
- });
+ rule.each((decl)=>decl.raws.before = ' ');
rule.raws.after = ' ';
} else {
report({
@@ -52,7 +48,9 @@ module.exports = stylelint.createPlugin(ruleName, function getPlugin(primaryOpti
}
});
};
-});
+};
-module.exports.ruleName = ruleName;
-module.exports.messages = messages;
+ruleFunction.ruleName = ruleName;
+ruleFunction.messages = messages;
+
+export default stylelint.createPlugin(ruleName, ruleFunction);
diff --git a/stylelint_plugins/declaration-colon-align.js b/stylelint_plugins/declaration-colon-align.js
index f1f5269d3..aeb92fcd8 100644
--- a/stylelint_plugins/declaration-colon-align.js
+++ b/stylelint_plugins/declaration-colon-align.js
@@ -1,32 +1,29 @@
-const stylelint = require('stylelint');
-
+import stylelint from 'stylelint';
const { report, ruleMessages, validateOptions } = stylelint.utils;
+
const ruleName = 'naturalcrit/declaration-colon-align';
const messages = ruleMessages(ruleName, {
expected : (rule)=>`Expected colons aligned within rule "${rule}"`,
});
-
-module.exports = stylelint.createPlugin(ruleName, function getPlugin(primaryOption, secondaryOptionObject, context) {
- return function lint(postcssRoot, postcssResult) {
+const ruleFunction = (primaryOption, secondaryOptionObject, context)=>{
+ return (postcssRoot, postcssResult)=>{
const validOptions = validateOptions(
postcssResult,
ruleName,
{
actual : primaryOption,
- possible : [
- true,
- false
- ]
+ possible : [true, false]
}
);
- if(!validOptions) { //If the options are invalid, don't lint
+ if(!validOptions) // If the options are invalid, don't lint
return;
- }
+
const isAutoFixing = Boolean(context.fix);
- postcssRoot.walkRules((rule)=>{ //Iterate CSS rules
+
+ postcssRoot.walkRules((rule)=>{ // Iterate CSS rules
let maxColonPos = 0;
let misaligned = false;
@@ -36,33 +33,37 @@ module.exports = stylelint.createPlugin(ruleName, function getPlugin(primaryOpti
return;
const colonPos = declaration.prop.length + declaration.raws.between.indexOf(':');
- if(maxColonPos > 0 && colonPos != maxColonPos) {
+
+ if(maxColonPos > 0 && colonPos != maxColonPos)
misaligned = true;
- }
+
maxColonPos = Math.max(maxColonPos, colonPos);
});
- if(misaligned) {
- if(isAutoFixing) { //We are in “fix” mode
- rule.each((declaration)=>{
- if(declaration.type != 'decl')
- return;
+ if(!misaligned)
+ return;
- declaration.raws.between = `${' '.repeat(maxColonPos - declaration.prop.length)}:${declaration.raws.between.split(':')[1]}`;
- });
- } else { //We are in “report only” mode
- report({
- ruleName,
- result : postcssResult,
- message : messages.expected(rule.selector), // Build the reported message
- node : rule, // Specify the reported node
- word : rule.selector, // Which exact word caused the error? This positions the error properly
- });
- }
+ if(isAutoFixing) { // We are in “fix” mode
+ rule.each((declaration)=>{
+ if(declaration.type != 'decl')
+ return;
+
+ declaration.raws.between = `${' '.repeat(maxColonPos - declaration.prop.length)}:${declaration.raws.between.split(':')[1]}`;
+ });
+ } else { // We are in “report only” mode
+ report({
+ ruleName,
+ result : postcssResult,
+ message : messages.expected(rule.selector), // Build the reported message
+ node : rule, // Specify the reported node
+ word : rule.selector, // Which exact word caused the error? This positions the error properly
+ });
}
});
};
-});
+};
-module.exports.ruleName = ruleName;
-module.exports.messages = messages;
+ruleFunction.ruleName = ruleName;
+ruleFunction.messages = messages;
+
+export default stylelint.createPlugin(ruleName, ruleFunction);
\ No newline at end of file
diff --git a/stylelint_plugins/declaration-colon-min-space-before.js b/stylelint_plugins/declaration-colon-min-space-before.js
index e75c035a6..7776c6fef 100644
--- a/stylelint_plugins/declaration-colon-min-space-before.js
+++ b/stylelint_plugins/declaration-colon-min-space-before.js
@@ -1,5 +1,5 @@
-const stylelint = require('stylelint');
-const { isNumber } = require('stylelint/lib/utils/validateTypes.cjs');
+import stylelint from 'stylelint';
+import { isNumber } from 'stylelint/lib/utils/validateTypes.mjs';
const { report, ruleMessages, validateOptions } = stylelint.utils;
const ruleName = 'naturalcrit/declaration-colon-min-space-before';
@@ -7,9 +7,8 @@ const messages = ruleMessages(ruleName, {
expected : (num)=>`Expected at least ${num} space${num == 1 ? '' : 's'} before ":"`
});
-
-module.exports = stylelint.createPlugin(ruleName, function getPlugin(primaryOption, secondaryOptionObject, context) {
- return function lint(postcssRoot, postcssResult) {
+const ruleFunction = (primaryOption, secondaryOptionObject, context)=>{
+ return (postcssRoot, postcssResult)=>{
const validOptions = validateOptions(
postcssResult,
@@ -30,9 +29,9 @@ module.exports = stylelint.createPlugin(ruleName, function getPlugin(primaryOpti
const between = decl.raws.between;
const colonIndex = between.indexOf(':');
- if(between.slice(0, colonIndex).length >= primaryOption) {
+ if(between.slice(0, colonIndex).length >= primaryOption)
return;
- }
+
if(isAutoFixing) { //We are in “fix” mode
decl.raws.between = between.slice(0, colonIndex).replace(/\s*$/, ' '.repeat(primaryOption)) + between.slice(colonIndex);
} else {
@@ -46,7 +45,9 @@ module.exports = stylelint.createPlugin(ruleName, function getPlugin(primaryOpti
}
});
};
-});
+};
-module.exports.ruleName = ruleName;
-module.exports.messages = messages;
+ruleFunction.ruleName = ruleName;
+ruleFunction.messages = messages;
+
+export default stylelint.createPlugin(ruleName, ruleFunction);
\ No newline at end of file