0
0
mirror of https://github.com/naturalcrit/homebrewery.git synced 2025-12-30 06:42:45 +00:00

Merge branch 'master' into PreprocessVars

This commit is contained in:
Trevor Buckner
2024-02-08 23:13:19 -05:00
9 changed files with 226 additions and 187 deletions

View File

@@ -4,6 +4,7 @@ const Nav = require('naturalcrit/nav/nav.jsx');
module.exports = function(props){ module.exports = function(props){
return <Nav.item return <Nav.item
href='/new' href='/new'
newTab={true}
color='purple' color='purple'
icon='fas fa-plus-square'> icon='fas fa-plus-square'>
new new

View File

@@ -125,7 +125,7 @@ const BrewItem = createClass({
<div className='info'> <div className='info'>
{brew.tags?.length ? <> {brew.tags?.length ? <>
<div className='brewTags' title={`Tags:\n${brew.tags.join('\n')}`}> <div className='brewTags' title={`${brew.tags.length} tags:\n${brew.tags.join('\n')}`}>
<i className='fas fa-tags'/> <i className='fas fa-tags'/>
{brew.tags.map((tag, idx)=>{ {brew.tags.map((tag, idx)=>{
const matches = tag.match(/^(?:([^:]+):)?([^:]+)$/); const matches = tag.match(/^(?:([^:]+):)?([^:]+)$/);
@@ -135,7 +135,7 @@ const BrewItem = createClass({
</> : <></> </> : <></>
} }
<span title={`Authors:\n${brew.authors?.join('\n')}`}> <span title={`Authors:\n${brew.authors?.join('\n')}`}>
<i className='fas fa-user'/> {brew.authors?.join(', ')} <i className='fas fa-user'/> {brew.authors.map((item) => <a href={`/user/${item}`}>{item}</a>)}
</span> </span>
<br /> <br />
<span title={`Last viewed: ${moment(brew.lastViewed).local().format(dateFormatString)}`}> <span title={`Last viewed: ${moment(brew.lastViewed).local().format(dateFormatString)}`}>

View File

@@ -48,6 +48,10 @@
&>span{ &>span{
margin-right : 12px; margin-right : 12px;
line-height : 1.5em; line-height : 1.5em;
a {
color:inherit;
}
} }
} }
.brewTags span { .brewTags span {

208
package-lock.json generated
View File

@@ -10,11 +10,11 @@
"hasInstallScript": true, "hasInstallScript": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@babel/core": "^7.23.7", "@babel/core": "^7.23.9",
"@babel/plugin-transform-runtime": "^7.23.7", "@babel/plugin-transform-runtime": "^7.23.9",
"@babel/preset-env": "^7.23.8", "@babel/preset-env": "^7.23.9",
"@babel/preset-react": "^7.23.3", "@babel/preset-react": "^7.23.3",
"@googleapis/drive": "^8.6.0", "@googleapis/drive": "^8.7.0",
"body-parser": "^1.20.2", "body-parser": "^1.20.2",
"classnames": "^2.3.2", "classnames": "^2.3.2",
"codemirror": "^5.65.6", "codemirror": "^5.65.6",
@@ -29,19 +29,19 @@
"jwt-simple": "^0.5.6", "jwt-simple": "^0.5.6",
"less": "^3.13.1", "less": "^3.13.1",
"lodash": "^4.17.21", "lodash": "^4.17.21",
"marked": "5.1.1", "marked": "11.2.0",
"marked-extended-tables": "^1.0.8", "marked-extended-tables": "^1.0.8",
"marked-gfm-heading-id": "^3.1.2", "marked-gfm-heading-id": "^3.1.3",
"marked-smartypants-lite": "^1.0.2", "marked-smartypants-lite": "^1.0.2",
"markedLegacy": "npm:marked@^0.3.19", "markedLegacy": "npm:marked@^0.3.19",
"moment": "^2.30.1", "moment": "^2.30.1",
"mongoose": "^8.1.0", "mongoose": "^8.1.1",
"nanoid": "3.3.4", "nanoid": "3.3.4",
"nconf": "^0.12.1", "nconf": "^0.12.1",
"react": "^18.2.0", "react": "^18.2.0",
"react-dom": "^18.2.0", "react-dom": "^18.2.0",
"react-frame-component": "^4.1.3", "react-frame-component": "^4.1.3",
"react-router-dom": "6.21.3", "react-router-dom": "6.22.0",
"sanitize-filename": "1.6.3", "sanitize-filename": "1.6.3",
"superagent": "^8.1.2", "superagent": "^8.1.2",
"vitreum": "git+https://git@github.com/calculuschild/vitreum.git" "vitreum": "git+https://git@github.com/calculuschild/vitreum.git"
@@ -54,7 +54,7 @@
"jest-expect-message": "^1.1.3", "jest-expect-message": "^1.1.3",
"postcss-less": "^6.0.0", "postcss-less": "^6.0.0",
"stylelint": "^15.11.0", "stylelint": "^15.11.0",
"stylelint-config-recess-order": "^4.4.0", "stylelint-config-recess-order": "^4.6.0",
"stylelint-config-recommended": "^13.0.0", "stylelint-config-recommended": "^13.0.0",
"stylelint-stylistic": "^0.4.3", "stylelint-stylistic": "^0.4.3",
"supertest": "^6.3.4" "supertest": "^6.3.4"
@@ -106,20 +106,20 @@
} }
}, },
"node_modules/@babel/core": { "node_modules/@babel/core": {
"version": "7.23.7", "version": "7.23.9",
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.23.7.tgz", "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.23.9.tgz",
"integrity": "sha512-+UpDgowcmqe36d4NwqvKsyPMlOLNGMsfMmQ5WGCu+siCe3t3dfe9njrzGfdN4qq+bcNUt0+Vw6haRxBOycs4dw==", "integrity": "sha512-5q0175NOjddqpvvzU+kDiSOAk4PfdO6FvwCWoQ6RO7rTzEe8vlo+4HVfcnAREhD4npMs0e9uZypjTwzZPCf/cw==",
"dependencies": { "dependencies": {
"@ampproject/remapping": "^2.2.0", "@ampproject/remapping": "^2.2.0",
"@babel/code-frame": "^7.23.5", "@babel/code-frame": "^7.23.5",
"@babel/generator": "^7.23.6", "@babel/generator": "^7.23.6",
"@babel/helper-compilation-targets": "^7.23.6", "@babel/helper-compilation-targets": "^7.23.6",
"@babel/helper-module-transforms": "^7.23.3", "@babel/helper-module-transforms": "^7.23.3",
"@babel/helpers": "^7.23.7", "@babel/helpers": "^7.23.9",
"@babel/parser": "^7.23.6", "@babel/parser": "^7.23.9",
"@babel/template": "^7.22.15", "@babel/template": "^7.23.9",
"@babel/traverse": "^7.23.7", "@babel/traverse": "^7.23.9",
"@babel/types": "^7.23.6", "@babel/types": "^7.23.9",
"convert-source-map": "^2.0.0", "convert-source-map": "^2.0.0",
"debug": "^4.1.0", "debug": "^4.1.0",
"gensync": "^1.0.0-beta.2", "gensync": "^1.0.0-beta.2",
@@ -242,9 +242,9 @@
} }
}, },
"node_modules/@babel/helper-define-polyfill-provider": { "node_modules/@babel/helper-define-polyfill-provider": {
"version": "0.4.4", "version": "0.5.0",
"resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.4.4.tgz", "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.5.0.tgz",
"integrity": "sha512-QcJMILQCu2jm5TFPGA3lCpJJTeEP+mqeXooG/NZbg/h5FTFi6V0+99ahlRsW8/kRLyb24LZVCCiclDedhLKcBA==", "integrity": "sha512-NovQquuQLAQ5HuyjCz7WQP9MjRj7dx++yspwiyUiGl9ZyadHRSql1HZh5ogRd8W8w6YM6EQ/NTB8rgjLt5W65Q==",
"dependencies": { "dependencies": {
"@babel/helper-compilation-targets": "^7.22.6", "@babel/helper-compilation-targets": "^7.22.6",
"@babel/helper-plugin-utils": "^7.22.5", "@babel/helper-plugin-utils": "^7.22.5",
@@ -449,13 +449,13 @@
} }
}, },
"node_modules/@babel/helpers": { "node_modules/@babel/helpers": {
"version": "7.23.7", "version": "7.23.9",
"resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.23.7.tgz", "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.23.9.tgz",
"integrity": "sha512-6AMnjCoC8wjqBzDHkuqpa7jAKwvMo4dC+lr/TFBz+ucfulO1XMpDnwWPGBNwClOKZ8h6xn5N81W/R5OrcKtCbQ==", "integrity": "sha512-87ICKgU5t5SzOT7sBMfCOZQ2rHjRU+Pcb9BoILMYz600W6DkVRLFBPwQ18gwUVvggqXivaUakpnxWQGbpywbBQ==",
"dependencies": { "dependencies": {
"@babel/template": "^7.22.15", "@babel/template": "^7.23.9",
"@babel/traverse": "^7.23.7", "@babel/traverse": "^7.23.9",
"@babel/types": "^7.23.6" "@babel/types": "^7.23.9"
}, },
"engines": { "engines": {
"node": ">=6.9.0" "node": ">=6.9.0"
@@ -475,9 +475,9 @@
} }
}, },
"node_modules/@babel/parser": { "node_modules/@babel/parser": {
"version": "7.23.6", "version": "7.23.9",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.6.tgz", "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.9.tgz",
"integrity": "sha512-Z2uID7YJ7oNvAI20O9X0bblw7Qqs8Q2hFy0R9tAfnfLkp5MW0UH9eUvnDSnFwKZ0AvgS1ucqR4KzvVHgnke1VQ==", "integrity": "sha512-9tcKgqKbs3xGJ+NtKF2ndOBBLVwPjl1SHxPQkd36r3Dlirw3xWUeGaTbqr7uGZcTaxkVNwc+03SVP7aCdWrTlA==",
"bin": { "bin": {
"parser": "bin/babel-parser.js" "parser": "bin/babel-parser.js"
}, },
@@ -814,9 +814,9 @@
} }
}, },
"node_modules/@babel/plugin-transform-async-generator-functions": { "node_modules/@babel/plugin-transform-async-generator-functions": {
"version": "7.23.7", "version": "7.23.9",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.23.7.tgz", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.23.9.tgz",
"integrity": "sha512-PdxEpL71bJp1byMG0va5gwQcXHxuEYC/BgI/e88mGTtohbZN28O5Yit0Plkkm/dBzCF/BxmbNcses1RH1T+urA==", "integrity": "sha512-8Q3veQEDGe14dTYuwagbRtwxQDnytyg1JFu4/HwEMETeofocrB0U0ejBJIXoeG/t2oXZ8kzCyI0ZZfbT80VFNQ==",
"dependencies": { "dependencies": {
"@babel/helper-environment-visitor": "^7.22.20", "@babel/helper-environment-visitor": "^7.22.20",
"@babel/helper-plugin-utils": "^7.22.5", "@babel/helper-plugin-utils": "^7.22.5",
@@ -1150,9 +1150,9 @@
} }
}, },
"node_modules/@babel/plugin-transform-modules-systemjs": { "node_modules/@babel/plugin-transform-modules-systemjs": {
"version": "7.23.3", "version": "7.23.9",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.23.3.tgz", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.23.9.tgz",
"integrity": "sha512-ZxyKGTkF9xT9YJuKQRo19ewf3pXpopuYQd8cDXqNzc3mUNbOME0RKMoZxviQk74hwzfQsEe66dE92MaZbdHKNQ==", "integrity": "sha512-KDlPRM6sLo4o1FkiSlXoAa8edLXFsKKIda779fbLrvmeuc3itnjCtaO6RrtoaANsIJANj+Vk1zqbZIMhkCAHVw==",
"dependencies": { "dependencies": {
"@babel/helper-hoist-variables": "^7.22.5", "@babel/helper-hoist-variables": "^7.22.5",
"@babel/helper-module-transforms": "^7.23.3", "@babel/helper-module-transforms": "^7.23.3",
@@ -1455,15 +1455,15 @@
} }
}, },
"node_modules/@babel/plugin-transform-runtime": { "node_modules/@babel/plugin-transform-runtime": {
"version": "7.23.7", "version": "7.23.9",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.23.7.tgz", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.23.9.tgz",
"integrity": "sha512-fa0hnfmiXc9fq/weK34MUV0drz2pOL/vfKWvN7Qw127hiUPabFCUMgAbYWcchRzMJit4o5ARsK/s+5h0249pLw==", "integrity": "sha512-A7clW3a0aSjm3ONU9o2HAILSegJCYlEZmOhmBRReVtIpY/Z/p7yIZ+wR41Z+UipwdGuqwtID/V/dOdZXjwi9gQ==",
"dependencies": { "dependencies": {
"@babel/helper-module-imports": "^7.22.15", "@babel/helper-module-imports": "^7.22.15",
"@babel/helper-plugin-utils": "^7.22.5", "@babel/helper-plugin-utils": "^7.22.5",
"babel-plugin-polyfill-corejs2": "^0.4.7", "babel-plugin-polyfill-corejs2": "^0.4.8",
"babel-plugin-polyfill-corejs3": "^0.8.7", "babel-plugin-polyfill-corejs3": "^0.9.0",
"babel-plugin-polyfill-regenerator": "^0.5.4", "babel-plugin-polyfill-regenerator": "^0.5.5",
"semver": "^6.3.1" "semver": "^6.3.1"
}, },
"engines": { "engines": {
@@ -1604,9 +1604,9 @@
} }
}, },
"node_modules/@babel/preset-env": { "node_modules/@babel/preset-env": {
"version": "7.23.8", "version": "7.23.9",
"resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.23.8.tgz", "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.23.9.tgz",
"integrity": "sha512-lFlpmkApLkEP6woIKprO6DO60RImpatTQKtz4sUcDjVcK8M8mQ4sZsuxaTMNOZf0sqAq/ReYW1ZBHnOQwKpLWA==", "integrity": "sha512-3kBGTNBBk9DQiPoXYS0g0BYlwTQYUTifqgKTjxUwEUkduRT2QOa0FPGBJ+NROQhGyYO5BuTJwGvBnqKDykac6A==",
"dependencies": { "dependencies": {
"@babel/compat-data": "^7.23.5", "@babel/compat-data": "^7.23.5",
"@babel/helper-compilation-targets": "^7.23.6", "@babel/helper-compilation-targets": "^7.23.6",
@@ -1635,7 +1635,7 @@
"@babel/plugin-syntax-top-level-await": "^7.14.5", "@babel/plugin-syntax-top-level-await": "^7.14.5",
"@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6",
"@babel/plugin-transform-arrow-functions": "^7.23.3", "@babel/plugin-transform-arrow-functions": "^7.23.3",
"@babel/plugin-transform-async-generator-functions": "^7.23.7", "@babel/plugin-transform-async-generator-functions": "^7.23.9",
"@babel/plugin-transform-async-to-generator": "^7.23.3", "@babel/plugin-transform-async-to-generator": "^7.23.3",
"@babel/plugin-transform-block-scoped-functions": "^7.23.3", "@babel/plugin-transform-block-scoped-functions": "^7.23.3",
"@babel/plugin-transform-block-scoping": "^7.23.4", "@babel/plugin-transform-block-scoping": "^7.23.4",
@@ -1657,7 +1657,7 @@
"@babel/plugin-transform-member-expression-literals": "^7.23.3", "@babel/plugin-transform-member-expression-literals": "^7.23.3",
"@babel/plugin-transform-modules-amd": "^7.23.3", "@babel/plugin-transform-modules-amd": "^7.23.3",
"@babel/plugin-transform-modules-commonjs": "^7.23.3", "@babel/plugin-transform-modules-commonjs": "^7.23.3",
"@babel/plugin-transform-modules-systemjs": "^7.23.3", "@babel/plugin-transform-modules-systemjs": "^7.23.9",
"@babel/plugin-transform-modules-umd": "^7.23.3", "@babel/plugin-transform-modules-umd": "^7.23.3",
"@babel/plugin-transform-named-capturing-groups-regex": "^7.22.5", "@babel/plugin-transform-named-capturing-groups-regex": "^7.22.5",
"@babel/plugin-transform-new-target": "^7.23.3", "@babel/plugin-transform-new-target": "^7.23.3",
@@ -1683,9 +1683,9 @@
"@babel/plugin-transform-unicode-regex": "^7.23.3", "@babel/plugin-transform-unicode-regex": "^7.23.3",
"@babel/plugin-transform-unicode-sets-regex": "^7.23.3", "@babel/plugin-transform-unicode-sets-regex": "^7.23.3",
"@babel/preset-modules": "0.1.6-no-external-plugins", "@babel/preset-modules": "0.1.6-no-external-plugins",
"babel-plugin-polyfill-corejs2": "^0.4.7", "babel-plugin-polyfill-corejs2": "^0.4.8",
"babel-plugin-polyfill-corejs3": "^0.8.7", "babel-plugin-polyfill-corejs3": "^0.9.0",
"babel-plugin-polyfill-regenerator": "^0.5.4", "babel-plugin-polyfill-regenerator": "^0.5.5",
"core-js-compat": "^3.31.0", "core-js-compat": "^3.31.0",
"semver": "^6.3.1" "semver": "^6.3.1"
}, },
@@ -1745,22 +1745,22 @@
} }
}, },
"node_modules/@babel/template": { "node_modules/@babel/template": {
"version": "7.22.15", "version": "7.23.9",
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz", "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.23.9.tgz",
"integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==", "integrity": "sha512-+xrD2BWLpvHKNmX2QbpdpsBaWnRxahMwJjO+KZk2JOElj5nSmKezyS1B4u+QbHMTX69t4ukm6hh9lsYQ7GHCKA==",
"dependencies": { "dependencies": {
"@babel/code-frame": "^7.22.13", "@babel/code-frame": "^7.23.5",
"@babel/parser": "^7.22.15", "@babel/parser": "^7.23.9",
"@babel/types": "^7.22.15" "@babel/types": "^7.23.9"
}, },
"engines": { "engines": {
"node": ">=6.9.0" "node": ">=6.9.0"
} }
}, },
"node_modules/@babel/traverse": { "node_modules/@babel/traverse": {
"version": "7.23.7", "version": "7.23.9",
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.7.tgz", "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.9.tgz",
"integrity": "sha512-tY3mM8rH9jM0YHFGyfC0/xf+SB5eKUu7HPj7/k3fpi9dAlsMc5YbQvDi0Sh2QTPXqMhyaAtzAr807TIyfQrmyg==", "integrity": "sha512-I/4UJ9vs90OkBtY6iiiTORVMyIhJ4kAVmsKo9KFc8UOxMeUfi2hvtIBsET5u9GizXE6/GFSuKCTNfgCswuEjRg==",
"dependencies": { "dependencies": {
"@babel/code-frame": "^7.23.5", "@babel/code-frame": "^7.23.5",
"@babel/generator": "^7.23.6", "@babel/generator": "^7.23.6",
@@ -1768,8 +1768,8 @@
"@babel/helper-function-name": "^7.23.0", "@babel/helper-function-name": "^7.23.0",
"@babel/helper-hoist-variables": "^7.22.5", "@babel/helper-hoist-variables": "^7.22.5",
"@babel/helper-split-export-declaration": "^7.22.6", "@babel/helper-split-export-declaration": "^7.22.6",
"@babel/parser": "^7.23.6", "@babel/parser": "^7.23.9",
"@babel/types": "^7.23.6", "@babel/types": "^7.23.9",
"debug": "^4.3.1", "debug": "^4.3.1",
"globals": "^11.1.0" "globals": "^11.1.0"
}, },
@@ -1778,9 +1778,9 @@
} }
}, },
"node_modules/@babel/types": { "node_modules/@babel/types": {
"version": "7.23.6", "version": "7.23.9",
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.6.tgz", "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.9.tgz",
"integrity": "sha512-+uarb83brBzPKN38NX1MkB6vb6+mwvR6amUulqAE7ccQw1pEl+bCia9TbdG1lsnFP7lZySvUn37CHyXQdfTwzg==", "integrity": "sha512-dQjSq/7HaSjRM43FFGnv5keM2HsxpmyV1PfaSVm0nzzjwwTmjOe6J4bC8e3+pTEIgHaHj+1ZlLThRJ2auc/w1Q==",
"dependencies": { "dependencies": {
"@babel/helper-string-parser": "^7.23.4", "@babel/helper-string-parser": "^7.23.4",
"@babel/helper-validator-identifier": "^7.22.20", "@babel/helper-validator-identifier": "^7.22.20",
@@ -1966,9 +1966,9 @@
} }
}, },
"node_modules/@googleapis/drive": { "node_modules/@googleapis/drive": {
"version": "8.6.0", "version": "8.7.0",
"resolved": "https://registry.npmjs.org/@googleapis/drive/-/drive-8.6.0.tgz", "resolved": "https://registry.npmjs.org/@googleapis/drive/-/drive-8.7.0.tgz",
"integrity": "sha512-Af3/5i6h7gbjHnwFuO9zMTpYOy2yhhfZlNciUEjb14L3ZdT1WNIDM038viIAb9ovFzkrIDqLSfUbFCgh1pywkw==", "integrity": "sha512-XAi6kfySIU4H3ivX2DpzTDce5UhNke5NxEWCL6tySEdcVqx+cmXJmkMqwfOAHJalEB5s9PPfdLBU29Xd5XlLSQ==",
"dependencies": { "dependencies": {
"googleapis-common": "^7.0.0" "googleapis-common": "^7.0.0"
}, },
@@ -2837,9 +2837,9 @@
} }
}, },
"node_modules/@remix-run/router": { "node_modules/@remix-run/router": {
"version": "1.14.2", "version": "1.15.0",
"resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.14.2.tgz", "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.15.0.tgz",
"integrity": "sha512-ACXpdMM9hmKZww21yEqWwiLws/UPLhNKvimN8RrYSqPSvB3ov7sLvAcfvaxePeLvccTQKGdkDIhLYApZVDFuKg==", "integrity": "sha512-HOil5aFtme37dVQTB6M34G95kPM3MMuqSmIRVCC52eKV+Y/tGSqw9P3rWhlAx6A+mz+MoX+XxsGsNJbaI5qCgQ==",
"engines": { "engines": {
"node": ">=14.0.0" "node": ">=14.0.0"
} }
@@ -3734,12 +3734,12 @@
} }
}, },
"node_modules/babel-plugin-polyfill-corejs2": { "node_modules/babel-plugin-polyfill-corejs2": {
"version": "0.4.7", "version": "0.4.8",
"resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.7.tgz", "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.8.tgz",
"integrity": "sha512-LidDk/tEGDfuHW2DWh/Hgo4rmnw3cduK6ZkOI1NPFceSK3n/yAGeOsNT7FLnSGHkXj3RHGSEVkN3FsCTY6w2CQ==", "integrity": "sha512-OtIuQfafSzpo/LhnJaykc0R/MMnuLSSVjVYy9mHArIZ9qTCSZ6TpWCuEKZYVoN//t8HqBNScHrOtCrIK5IaGLg==",
"dependencies": { "dependencies": {
"@babel/compat-data": "^7.22.6", "@babel/compat-data": "^7.22.6",
"@babel/helper-define-polyfill-provider": "^0.4.4", "@babel/helper-define-polyfill-provider": "^0.5.0",
"semver": "^6.3.1" "semver": "^6.3.1"
}, },
"peerDependencies": { "peerDependencies": {
@@ -3747,23 +3747,23 @@
} }
}, },
"node_modules/babel-plugin-polyfill-corejs3": { "node_modules/babel-plugin-polyfill-corejs3": {
"version": "0.8.7", "version": "0.9.0",
"resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.8.7.tgz", "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.9.0.tgz",
"integrity": "sha512-KyDvZYxAzkC0Aj2dAPyDzi2Ym15e5JKZSK+maI7NAwSqofvuFglbSsxE7wUOvTg9oFVnHMzVzBKcqEb4PJgtOA==", "integrity": "sha512-7nZPG1uzK2Ymhy/NbaOWTg3uibM2BmGASS4vHS4szRZAIR8R6GwA/xAujpdrXU5iyklrimWnLWU+BLF9suPTqg==",
"dependencies": { "dependencies": {
"@babel/helper-define-polyfill-provider": "^0.4.4", "@babel/helper-define-polyfill-provider": "^0.5.0",
"core-js-compat": "^3.33.1" "core-js-compat": "^3.34.0"
}, },
"peerDependencies": { "peerDependencies": {
"@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0"
} }
}, },
"node_modules/babel-plugin-polyfill-regenerator": { "node_modules/babel-plugin-polyfill-regenerator": {
"version": "0.5.4", "version": "0.5.5",
"resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.5.4.tgz", "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.5.5.tgz",
"integrity": "sha512-S/x2iOCvDaCASLYsOOgWOq4bCfKYVqvO/uxjkaYyZ3rVsVE3CeAI/c84NpyuBBymEgNvHgjEot3a9/Z/kXvqsg==", "integrity": "sha512-OJGYZlhLqBh2DDHeqAxWB1XIvr49CxiJ2gIt61/PU55CQK4Z58OzMqjDe1zwQdQk+rBYsRc+1rJmdajM3gimHg==",
"dependencies": { "dependencies": {
"@babel/helper-define-polyfill-provider": "^0.4.4" "@babel/helper-define-polyfill-provider": "^0.5.0"
}, },
"peerDependencies": { "peerDependencies": {
"@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0"
@@ -10041,9 +10041,9 @@
} }
}, },
"node_modules/marked": { "node_modules/marked": {
"version": "5.1.1", "version": "11.2.0",
"resolved": "https://registry.npmjs.org/marked/-/marked-5.1.1.tgz", "resolved": "https://registry.npmjs.org/marked/-/marked-11.2.0.tgz",
"integrity": "sha512-bTmmGdEINWmOMDjnPWDxGPQ4qkDLeYorpYbEtFOXzOruTwUE671q4Guiuchn4N8h/v6NGd7916kXsm3Iz4iUSg==", "integrity": "sha512-HR0m3bvu0jAPYiIvLUUQtdg1g6D247//lvcekpHO1WMvbwDlwSkZAX9Lw4F4YHE1T0HaaNve0tuAWuV1UJ6vtw==",
"bin": { "bin": {
"marked": "bin/marked.js" "marked": "bin/marked.js"
}, },
@@ -10060,14 +10060,14 @@
} }
}, },
"node_modules/marked-gfm-heading-id": { "node_modules/marked-gfm-heading-id": {
"version": "3.1.2", "version": "3.1.3",
"resolved": "https://registry.npmjs.org/marked-gfm-heading-id/-/marked-gfm-heading-id-3.1.2.tgz", "resolved": "https://registry.npmjs.org/marked-gfm-heading-id/-/marked-gfm-heading-id-3.1.3.tgz",
"integrity": "sha512-SdIZvhNxDgndFkDa2WRcFP4ahYm6k6hoHdTCN+fD7HRiI/R3Eimcw/Yl7ikQ+0KUuDpi75NnYQiThZnZsNr9Dg==", "integrity": "sha512-A0cRU4PCueX/5m8VE4mT8uTQ36l3xMYRojz3Eqnk4BmUFZ0T+9Xhn2KvHcANP4qbhfOeuMrWJCTQbASIBR5xeg==",
"dependencies": { "dependencies": {
"github-slugger": "^2.0.0" "github-slugger": "^2.0.0"
}, },
"peerDependencies": { "peerDependencies": {
"marked": ">=4 <12" "marked": ">=4 <13"
} }
}, },
"node_modules/marked-smartypants-lite": { "node_modules/marked-smartypants-lite": {
@@ -10453,9 +10453,9 @@
} }
}, },
"node_modules/mongoose": { "node_modules/mongoose": {
"version": "8.1.0", "version": "8.1.1",
"resolved": "https://registry.npmjs.org/mongoose/-/mongoose-8.1.0.tgz", "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-8.1.1.tgz",
"integrity": "sha512-kOA4Xnq2goqNpN9EmYElGNWfxA9H80fxcr7UdJKWi3UMflza0R7wpTihCpM67dE/0MNFljoa0sjQtlXVkkySAQ==", "integrity": "sha512-DbLb0NsiEXmaqLOpEz+AtAsgwhRw6f25gwa1dF5R7jj6lS1D8X6uTdhBSC8GDVtOwe5Tfw2EL7nTn6hiJT3Bgg==",
"dependencies": { "dependencies": {
"bson": "^6.2.0", "bson": "^6.2.0",
"kareem": "2.5.1", "kareem": "2.5.1",
@@ -11873,11 +11873,11 @@
"dev": true "dev": true
}, },
"node_modules/react-router": { "node_modules/react-router": {
"version": "6.21.3", "version": "6.22.0",
"resolved": "https://registry.npmjs.org/react-router/-/react-router-6.21.3.tgz", "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.22.0.tgz",
"integrity": "sha512-a0H638ZXULv1OdkmiK6s6itNhoy33ywxmUFT/xtSoVyf9VnC7n7+VT4LjVzdIHSaF5TIh9ylUgxMXksHTgGrKg==", "integrity": "sha512-q2yemJeg6gw/YixRlRnVx6IRJWZD6fonnfZhN1JIOhV2iJCPeRNSH3V1ISwHf+JWcESzLC3BOLD1T07tmO5dmg==",
"dependencies": { "dependencies": {
"@remix-run/router": "1.14.2" "@remix-run/router": "1.15.0"
}, },
"engines": { "engines": {
"node": ">=14.0.0" "node": ">=14.0.0"
@@ -11887,12 +11887,12 @@
} }
}, },
"node_modules/react-router-dom": { "node_modules/react-router-dom": {
"version": "6.21.3", "version": "6.22.0",
"resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.21.3.tgz", "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.22.0.tgz",
"integrity": "sha512-kNzubk7n4YHSrErzjLK72j0B5i969GsuCGazRl3G6j1zqZBLjuSlYBdVdkDOgzGdPIffUOc9nmgiadTEVoq91g==", "integrity": "sha512-z2w+M4tH5wlcLmH3BMMOMdrtrJ9T3oJJNsAlBJbwk+8Syxd5WFJ7J5dxMEW0/GEXD1BBis4uXRrNIz3mORr0ag==",
"dependencies": { "dependencies": {
"@remix-run/router": "1.14.2", "@remix-run/router": "1.15.0",
"react-router": "6.21.3" "react-router": "6.22.0"
}, },
"engines": { "engines": {
"node": ">=14.0.0" "node": ">=14.0.0"
@@ -13327,9 +13327,9 @@
} }
}, },
"node_modules/stylelint-config-recess-order": { "node_modules/stylelint-config-recess-order": {
"version": "4.4.0", "version": "4.6.0",
"resolved": "https://registry.npmjs.org/stylelint-config-recess-order/-/stylelint-config-recess-order-4.4.0.tgz", "resolved": "https://registry.npmjs.org/stylelint-config-recess-order/-/stylelint-config-recess-order-4.6.0.tgz",
"integrity": "sha512-Q99kvZyIM/aoPEV4dRDkzD3fZLzH0LXi+pawCf1r700uUeF/PHQ5PZXjwFUuGrWhOzd1N+cuVm+OUGsY2fRN5A==", "integrity": "sha512-V76fhv3YtcNXh/hyAuAdSzi5FmcrG54Mp2AThJ3D/PTMTSYzUPd7GIhP6z9mTqnRhmkk6YTfcu/JWB8h+Yrcaw==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"stylelint-order": "6.x" "stylelint-order": "6.x"

View File

@@ -3,7 +3,7 @@
"description": "Create authentic looking D&D homebrews using only markdown", "description": "Create authentic looking D&D homebrews using only markdown",
"version": "3.10.0", "version": "3.10.0",
"engines": { "engines": {
"npm": "^10.2.x", "npm": "^10.2.x",
"node": "^20.8.x" "node": "^20.8.x"
}, },
"repository": { "repository": {
@@ -79,11 +79,11 @@
] ]
}, },
"dependencies": { "dependencies": {
"@babel/core": "^7.23.7", "@babel/core": "^7.23.9",
"@babel/plugin-transform-runtime": "^7.23.7", "@babel/plugin-transform-runtime": "^7.23.9",
"@babel/preset-env": "^7.23.8", "@babel/preset-env": "^7.23.9",
"@babel/preset-react": "^7.23.3", "@babel/preset-react": "^7.23.3",
"@googleapis/drive": "^8.6.0", "@googleapis/drive": "^8.7.0",
"body-parser": "^1.20.2", "body-parser": "^1.20.2",
"classnames": "^2.3.2", "classnames": "^2.3.2",
"codemirror": "^5.65.6", "codemirror": "^5.65.6",
@@ -98,19 +98,19 @@
"jwt-simple": "^0.5.6", "jwt-simple": "^0.5.6",
"less": "^3.13.1", "less": "^3.13.1",
"lodash": "^4.17.21", "lodash": "^4.17.21",
"marked": "5.1.1", "marked": "11.2.0",
"marked-extended-tables": "^1.0.8", "marked-extended-tables": "^1.0.8",
"marked-gfm-heading-id": "^3.1.2", "marked-gfm-heading-id": "^3.1.3",
"marked-smartypants-lite": "^1.0.2", "marked-smartypants-lite": "^1.0.2",
"markedLegacy": "npm:marked@^0.3.19", "markedLegacy": "npm:marked@^0.3.19",
"moment": "^2.30.1", "moment": "^2.30.1",
"mongoose": "^8.1.0", "mongoose": "^8.1.1",
"nanoid": "3.3.4", "nanoid": "3.3.4",
"nconf": "^0.12.1", "nconf": "^0.12.1",
"react": "^18.2.0", "react": "^18.2.0",
"react-dom": "^18.2.0", "react-dom": "^18.2.0",
"react-frame-component": "^4.1.3", "react-frame-component": "^4.1.3",
"react-router-dom": "6.21.3", "react-router-dom": "6.22.0",
"sanitize-filename": "1.6.3", "sanitize-filename": "1.6.3",
"superagent": "^8.1.2", "superagent": "^8.1.2",
"vitreum": "git+https://git@github.com/calculuschild/vitreum.git" "vitreum": "git+https://git@github.com/calculuschild/vitreum.git"
@@ -123,7 +123,7 @@
"jest-expect-message": "^1.1.3", "jest-expect-message": "^1.1.3",
"postcss-less": "^6.0.0", "postcss-less": "^6.0.0",
"stylelint": "^15.11.0", "stylelint": "^15.11.0",
"stylelint-config-recess-order": "^4.4.0", "stylelint-config-recess-order": "^4.6.0",
"stylelint-config-recommended": "^13.0.0", "stylelint-config-recommended": "^13.0.0",
"stylelint-stylistic": "^0.4.3", "stylelint-stylistic": "^0.4.3",
"supertest": "^6.3.4" "supertest": "^6.3.4"

View File

@@ -26,7 +26,6 @@
"codemirror/addon/edit/trailingspace.js", "codemirror/addon/edit/trailingspace.js",
"codemirror/addon/selection/active-line.js", "codemirror/addon/selection/active-line.js",
"moment", "moment",
"superagent", "superagent"
"marked"
] ]
} }

View File

@@ -26,85 +26,124 @@ const mw = {
} }
}; };
const junkBrewPipeline = [
/* Search for brews that are older than 3 days and that are shorter than a tweet */ { $match : {
const junkBrewQuery = HomebrewModel.find({ updatedAt : { $lt: Moment().subtract(30, 'days').toDate() },
'$where' : 'this.text.length < 140', lastViewed : { $lt: Moment().subtract(30, 'days').toDate() }
createdAt : { }},
$lt : Moment().subtract(30, 'days').toDate() { $project: { textBinSize: { $binarySize: '$textBin' } } },
} { $match: { textBinSize: { $lt: 140 } } },
}).limit(100).maxTime(60000); { $limit: 100 }
];
/* Search for brews that aren't compressed (missing the compressed text field) */ /* Search for brews that aren't compressed (missing the compressed text field) */
const uncompressedBrewQuery = HomebrewModel.find({ const uncompressedBrewQuery = HomebrewModel.find({
'text' : { '$exists': true } 'text' : { '$exists': true }
}).lean().limit(10000).select('_id'); }).lean().limit(10000).select('_id');
// Search for up to 100 brews that have not been viewed or updated in 30 days and are shorter than 140 bytes
router.get('/admin/cleanup', mw.adminOnly, (req, res)=>{ router.get('/admin/cleanup', mw.adminOnly, (req, res)=>{
junkBrewQuery.exec((err, objs)=>{ HomebrewModel.aggregate(junkBrewPipeline).option({ maxTimeMS: 60000 })
if(err) return res.status(500).send(err); .then((objs)=>res.json({ count: objs.length }))
return res.json({ count: objs.length }); .catch((error)=>{
}); console.error(error);
res.status(500).json({ error: 'Internal Server Error' });
});
}); });
/* Removes all empty brews that are older than 3 days and that are shorter than a tweet */
// Delete up to 100 brews that have not been viewed or updated in 30 days and are shorter than 140 bytes
router.post('/admin/cleanup', mw.adminOnly, (req, res)=>{ router.post('/admin/cleanup', mw.adminOnly, (req, res)=>{
junkBrewQuery.remove().exec((err, objs)=>{ HomebrewModel.aggregate(junkBrewPipeline).option({ maxTimeMS: 60000 })
if(err) return res.status(500).send(err); .then((docs)=>{
return res.json({ count: objs.length }); const ids = docs.map((doc)=>doc._id);
}); return HomebrewModel.deleteMany({ _id: { $in: ids } });
}).then((result)=>{
res.json({ count: result.deletedCount });
}).catch((error)=>{
console.error(error);
res.status(500).json({ error: 'Internal Server Error' });
});
}); });
/* Searches for matching edit or share id, also attempts to partial match */ /* Searches for matching edit or share id, also attempts to partial match */
router.get('/admin/lookup/:id', mw.adminOnly, (req, res, next)=>{ router.get('/admin/lookup/:id', mw.adminOnly, async (req, res, next)=>{
HomebrewModel.findOne({ $or : [ HomebrewModel.findOne({
{ editId: { '$regex': req.params.id, '$options': 'i' } }, $or : [
{ shareId: { '$regex': req.params.id, '$options': 'i' } }, { editId: { $regex: req.params.id, $options: 'i' } },
] }).exec((err, brew)=>{ { shareId: { $regex: req.params.id, $options: 'i' } },
return res.json(brew); ]
}).exec()
.then((brew)=>{
if(!brew) // No document found
return res.status(404).json({ error: 'Document not found' });
else
return res.json(brew);
})
.catch((err)=>{
console.error(err);
return res.status(500).json({ error: 'Internal Server Error' });
}); });
}); });
/* Find 50 brews that aren't compressed yet */ /* Find 50 brews that aren't compressed yet */
router.get('/admin/finduncompressed', mw.adminOnly, (req, res)=>{ router.get('/admin/finduncompressed', mw.adminOnly, (req, res)=>{
uncompressedBrewQuery.exec((err, objs)=>{ const query = uncompressedBrewQuery.clone();
if(err) return res.status(500).send(err);
objs = objs.map((obj)=>{return obj._id;}); query.exec()
return res.json({ count: objs.length, ids: objs }); .then((objs)=>{
}); const ids = objs.map((obj)=>obj._id);
res.json({ count: ids.length, ids });
})
.catch((err)=>{
console.error(err);
res.status(500).send(err.message || 'Internal Server Error');
});
}); });
/* Compresses the "text" field of a brew to binary */ /* Compresses the "text" field of a brew to binary */
router.put('/admin/compress/:id', (req, res)=>{ router.put('/admin/compress/:id', (req, res)=>{
HomebrewModel.get({ _id: req.params.id }) HomebrewModel.findOne({ _id: req.params.id })
.then((brew)=>{ .then((brew)=>{
brew.textBin = zlib.deflateRawSync(brew.text); // Compress brew text to binary before saving if(!brew)
brew.text = undefined; // Delete the non-binary text field since it's not needed anymore return res.status(404).send('Brew not found');
brew.save((err, obj)=>{ if(brew.text) {
if(err) throw err; brew.textBin = brew.textBin || zlib.deflateRawSync(brew.text); //Don't overwrite textBin if exists
return res.status(200).send(obj); brew.text = undefined;
}); }
return brew.save();
}) })
.then((obj)=>res.status(200).send(obj))
.catch((err)=>{ .catch((err)=>{
console.log(err); console.error(err);
return res.status(500).send('Error while saving'); res.status(500).send('Error while saving');
}); });
}); });
router.get('/admin/stats', mw.adminOnly, (req, res)=>{
HomebrewModel.count({}, (err, count)=>{ router.get('/admin/stats', mw.adminOnly, async (req, res)=>{
try {
const totalBrewsCount = await HomebrewModel.countDocuments({});
const publishedBrewsCount = await HomebrewModel.countDocuments({ published: true });
return res.json({ return res.json({
totalBrews : count totalBrews : totalBrewsCount,
totalPublishedBrews : publishedBrewsCount
}); });
}); } catch (error) {
console.error(error);
return res.status(500).json({ error: 'Internal Server Error' });
}
}); });
router.get('/admin', mw.adminOnly, (req, res)=>{ router.get('/admin', mw.adminOnly, (req, res)=>{
templateFn('admin', { templateFn('admin', {
url : req.originalUrl url : req.originalUrl
}) })
.then((page)=>res.send(page)) .then((page)=>res.send(page))
.catch((err)=>res.sendStatus(500)); .catch((err)=>res.sendStatus(500));
}); });
module.exports = router; module.exports = router;

View File

@@ -304,7 +304,8 @@ app.get('/new/:id', asyncHandler(getBrew('share')), (req, res, next)=>{
text : req.brew.text, text : req.brew.text,
style : req.brew.style, style : req.brew.style,
renderer : req.brew.renderer, renderer : req.brew.renderer,
theme : req.brew.theme theme : req.brew.theme,
tags : req.brew.tags
}; };
req.brew = _.defaults(brew, DEFAULT_BREW); req.brew = _.defaults(brew, DEFAULT_BREW);

View File

@@ -29,9 +29,26 @@ renderer.paragraph = function(text){
return `<p>${text}</p>\n`; return `<p>${text}</p>\n`;
}; };
//TODO: may not be needed //Fix local links in the Preview iFrame to link inside the frame
// Disable default reflink definitions renderer.link = function (href, title, text) {
tokenizer.def = function(){ let self = false;
if(href[0] == '#') {
self = true;
}
href = cleanUrl(this.options.sanitize, this.options.baseUrl, href);
if(href === null) {
return text;
}
let out = `<a href="${escape(href)}"`;
if(title) {
out += ` title="${title}"`;
}
if(self) {
out += ' target="_self"';
}
out += `>${text}</a>`;
return out;
}; };
const mustacheSpans = { const mustacheSpans = {
@@ -539,28 +556,6 @@ Marked.use(mustacheInjectBlock);
Marked.use({ renderer: renderer, tokenizer: tokenizer, mangle: false }); Marked.use({ renderer: renderer, tokenizer: tokenizer, mangle: false });
Marked.use(MarkedExtendedTables(), MarkedGFMHeadingId(), MarkedSmartypantsLite()); Marked.use(MarkedExtendedTables(), MarkedGFMHeadingId(), MarkedSmartypantsLite());
//Fix local links in the Preview iFrame to link inside the frame
renderer.link = function (href, title, text) {
let self = false;
if(href[0] == '#') {
self = true;
}
href = cleanUrl(this.options.sanitize, this.options.baseUrl, href);
if(href === null) {
return text;
}
let out = `<a href="${escape(href)}"`;
if(title) {
out += ` title="${title}"`;
}
if(self) {
out += ' target="_self"';
}
out += `>${text}</a>`;
return out;
};
const nonWordAndColonTest = /[^\w:]/g; const nonWordAndColonTest = /[^\w:]/g;
const cleanUrl = function (sanitize, base, href) { const cleanUrl = function (sanitize, base, href) {
if(sanitize) { if(sanitize) {