From eb719e34a8b42672dfebf59564a0c4c6681bc618 Mon Sep 17 00:00:00 2001 From: "G.Ambatte" Date: Sun, 21 Apr 2024 14:35:51 +1200 Subject: [PATCH 001/398] Add aggregate query to HB model --- server/homebrew.model.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/server/homebrew.model.js b/server/homebrew.model.js index 36c9aa192..57e57d9e8 100644 --- a/server/homebrew.model.js +++ b/server/homebrew.model.js @@ -60,6 +60,12 @@ HomebrewSchema.statics.getByUser = async function(username, allowAccess=false, f return brews; }; +HomebrewSchema.statics.getAggregate = async function(aggregate, options={}){ + const output = await Homebrew.aggregate(aggregate, options) + .catch((error)=>{throw 'Can not get aggregate';}); + return output; +}; + const Homebrew = mongoose.model('Homebrew', HomebrewSchema); module.exports = { From 770025da0473aadd15bf450b1112e5c8cc50480b Mon Sep 17 00:00:00 2001 From: "G.Ambatte" Date: Sun, 21 Apr 2024 14:42:20 +1200 Subject: [PATCH 002/398] Add lock count route, update pipelines --- server/admin.api.js | 35 +++++++++++++++++++++++++++++++---- 1 file changed, 31 insertions(+), 4 deletions(-) diff --git a/server/admin.api.js b/server/admin.api.js index 5363ecc08..93c7771a7 100644 --- a/server/admin.api.js +++ b/server/admin.api.js @@ -27,10 +27,12 @@ const mw = { }; const junkBrewPipeline = [ - { $match : { - updatedAt : { $lt: Moment().subtract(30, 'days').toDate() }, - lastViewed : { $lt: Moment().subtract(30, 'days').toDate() } - }}, + { $match : + { + updatedAt : { $lt: Moment().subtract(30, 'days').toDate() }, + lastViewed : { $lt: Moment().subtract(30, 'days').toDate() } + } + }, { $project: { textBinSize: { $binarySize: '$textBin' } } }, { $match: { textBinSize: { $lt: 140 } } }, { $limit: 100 } @@ -138,6 +140,31 @@ router.get('/admin/stats', mw.adminOnly, async (req, res)=>{ } }); +router.get('/admin/lock', mw.adminOnly, async (req, res)=>{ + try { + const countLocksPipeline = [ + { + $match : + { + 'lock.locked' : true, + }, + }, + { + $count : + 'count', + } + ]; + const totalLockCount = await HomebrewModel.getAggregate(countLocksPipeline); + const count = totalLockCount[0].count; + return res.json({ + count + }); + } catch (error) { + console.error(error); + return res.status(500).json({ error: 'Unable to get lock count' }); + } +}); + router.get('/admin', mw.adminOnly, (req, res)=>{ templateFn('admin', { url : req.originalUrl From 8c5f2ff61cb12f44d00399f19fdd6e97b024b24e Mon Sep 17 00:00:00 2001 From: "G.Ambatte" Date: Sun, 21 Apr 2024 22:17:10 +1200 Subject: [PATCH 003/398] Add route to get locked documents with review requested --- server/admin.api.js | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/server/admin.api.js b/server/admin.api.js index 93c7771a7..b6f72efa1 100644 --- a/server/admin.api.js +++ b/server/admin.api.js @@ -165,6 +165,27 @@ router.get('/admin/lock', mw.adminOnly, async (req, res)=>{ } }); +router.get('/admin/lockreviews', mw.adminOnly, async (req, res)=>{ + try { + const countReviewsPipeline = [ + { + $match : + { + 'lock.locked' : true, + 'lock.reviewRequested' : { '$exists': 1 } + }, + } + ]; + const reviewDocuments = await HomebrewModel.getAggregate(countReviewsPipeline); + return res.json({ + reviewDocuments + }); + } catch (error) { + console.error(error); + return res.status(500).json({ error: 'Unable to get lock count' }); + } +}); + router.get('/admin', mw.adminOnly, (req, res)=>{ templateFn('admin', { url : req.originalUrl From b4a7dc0cbd13bf9145e4398ecad89bed08f5c1b6 Mon Sep 17 00:00:00 2001 From: "G.Ambatte" Date: Sun, 21 Apr 2024 22:48:11 +1200 Subject: [PATCH 004/398] Update lock review route --- server/admin.api.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/admin.api.js b/server/admin.api.js index b6f72efa1..552b8a30f 100644 --- a/server/admin.api.js +++ b/server/admin.api.js @@ -165,7 +165,7 @@ router.get('/admin/lock', mw.adminOnly, async (req, res)=>{ } }); -router.get('/admin/lockreviews', mw.adminOnly, async (req, res)=>{ +router.get('/admin/lock/reviews', mw.adminOnly, async (req, res)=>{ try { const countReviewsPipeline = [ { From 14c7a1152802da1e8eba5570efeb2495cab18be3 Mon Sep 17 00:00:00 2001 From: "G.Ambatte" Date: Sun, 21 Apr 2024 22:51:53 +1200 Subject: [PATCH 005/398] Fix error message --- server/admin.api.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/admin.api.js b/server/admin.api.js index 552b8a30f..48a05438d 100644 --- a/server/admin.api.js +++ b/server/admin.api.js @@ -182,7 +182,7 @@ router.get('/admin/lock/reviews', mw.adminOnly, async (req, res)=>{ }); } catch (error) { console.error(error); - return res.status(500).json({ error: 'Unable to get lock count' }); + return res.status(500).json({ error: 'Unable to get review collection' }); } }); From 874cbe1da43d9da27e732249b92fd2ed2bf32213 Mon Sep 17 00:00:00 2001 From: "G.Ambatte" Date: Mon, 22 Apr 2024 00:26:34 +1200 Subject: [PATCH 006/398] Don't forget to update the schema! --- server/homebrew.model.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/server/homebrew.model.js b/server/homebrew.model.js index 57e57d9e8..81f31f1eb 100644 --- a/server/homebrew.model.js +++ b/server/homebrew.model.js @@ -26,7 +26,9 @@ const HomebrewSchema = mongoose.Schema({ updatedAt : { type: Date, default: Date.now }, lastViewed : { type: Date, default: Date.now }, views : { type: Number, default: 0 }, - version : { type: Number, default: 1 } + version : { type: Number, default: 1 }, + + lock : { type: Object } }, { versionKey: false }); HomebrewSchema.statics.increaseView = async function(query) { From 8feae7efb622f1e2727bead01e83e7951244339b Mon Sep 17 00:00:00 2001 From: "G.Ambatte" Date: Mon, 22 Apr 2024 00:32:32 +1200 Subject: [PATCH 007/398] Function request review route --- server/admin.api.js | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/server/admin.api.js b/server/admin.api.js index 48a05438d..846757f23 100644 --- a/server/admin.api.js +++ b/server/admin.api.js @@ -186,6 +186,33 @@ router.get('/admin/lock/reviews', mw.adminOnly, async (req, res)=>{ } }); +router.get('/admin/lock/requestreview/:id', mw.adminOnly, async (req, res)=>{ + try { + const filter = { + shareId : req.params.id, + 'lock.locked' : true + }; + + const brew = await HomebrewModel.findOne(filter).exec(); + if(!brew) { return res.status(500).json({ error: `Brew ID ${req.params.id} is not locked!` }); }; + + brew.lock.reviewRequested = new Date(); + brew.markModified('lock'); + + console.log(brew); + + await brew.save() + .catch((err)=>{ + return err; + }); + + return res.json(brew); + } catch (error) { + console.error(error); + return res.status(500).json({ error: `Unable to set request for review on brew ID ${req.params.id}` }); + } +}); + router.get('/admin', mw.adminOnly, (req, res)=>{ templateFn('admin', { url : req.originalUrl From 99f5aad94238030207bd0a349bb4ea902aefd822 Mon Sep 17 00:00:00 2001 From: "G.Ambatte" Date: Thu, 25 Apr 2024 14:32:04 +1200 Subject: [PATCH 008/398] Stop review request if it has already been logged --- server/admin.api.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/server/admin.api.js b/server/admin.api.js index 846757f23..dfaa6d03f 100644 --- a/server/admin.api.js +++ b/server/admin.api.js @@ -193,19 +193,20 @@ router.get('/admin/lock/requestreview/:id', mw.adminOnly, async (req, res)=>{ 'lock.locked' : true }; - const brew = await HomebrewModel.findOne(filter).exec(); + const brew = await HomebrewModel.findOne(filter); if(!brew) { return res.status(500).json({ error: `Brew ID ${req.params.id} is not locked!` }); }; + if(brew.lock.reviewRequested){ return res.status(500).json({ error: `Review already requested for brew ${brew.shareId} - ${brew.title}` }); }; + brew.lock.reviewRequested = new Date(); brew.markModified('lock'); - console.log(brew); - await brew.save() .catch((err)=>{ return err; }); + console.log(`Review requested on brew ${brew.shareId} - ${brew.title}`); return res.json(brew); } catch (error) { console.error(error); From 71b84e1aba73c38bce5d08348747aa7e7e813ccd Mon Sep 17 00:00:00 2001 From: "G.Ambatte" Date: Thu, 25 Apr 2024 14:33:29 +1200 Subject: [PATCH 009/398] Log message when review already requested --- server/admin.api.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/server/admin.api.js b/server/admin.api.js index dfaa6d03f..e28b2fff8 100644 --- a/server/admin.api.js +++ b/server/admin.api.js @@ -196,7 +196,10 @@ router.get('/admin/lock/requestreview/:id', mw.adminOnly, async (req, res)=>{ const brew = await HomebrewModel.findOne(filter); if(!brew) { return res.status(500).json({ error: `Brew ID ${req.params.id} is not locked!` }); }; - if(brew.lock.reviewRequested){ return res.status(500).json({ error: `Review already requested for brew ${brew.shareId} - ${brew.title}` }); }; + if(brew.lock.reviewRequested){ + console.log(`Review already requested for brew ${brew.shareId} - ${brew.title}`); + return res.status(500).json({ error: `Review already requested for brew ${brew.shareId} - ${brew.title}` }); + }; brew.lock.reviewRequested = new Date(); brew.markModified('lock'); From e8b9b3d583b2496bd42a2b547854be4d6bc4faaa Mon Sep 17 00:00:00 2001 From: "G.Ambatte" Date: Thu, 25 Apr 2024 15:27:40 +1200 Subject: [PATCH 010/398] Add lock route --- server/admin.api.js | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/server/admin.api.js b/server/admin.api.js index e28b2fff8..cbde256f7 100644 --- a/server/admin.api.js +++ b/server/admin.api.js @@ -165,6 +165,27 @@ router.get('/admin/lock', mw.adminOnly, async (req, res)=>{ } }); +router.post('/admin/lock/:id', mw.adminOnly, async (req, res)=>{ + const lock = req.body; + + try { + const filter = { + shareId : req.params.id + }; + + const brew = await HomebrewModel.findOne(filter); + + brew.lock = lock; + brew.markModified('lock'); + + await brew.save(); + + console.log(`Lock applied to brew ID ${brew.shareId} - ${brew.title}`); + } catch {} + + return; +}); + router.get('/admin/lock/reviews', mw.adminOnly, async (req, res)=>{ try { const countReviewsPipeline = [ From 1c2ae8392c56a79598ec2b7519382ca8cad9c719 Mon Sep 17 00:00:00 2001 From: "G.Ambatte" Date: Thu, 25 Apr 2024 15:32:26 +1200 Subject: [PATCH 011/398] Increase max lines in Linter --- server/admin.api.js | 1 + 1 file changed, 1 insertion(+) diff --git a/server/admin.api.js b/server/admin.api.js index cbde256f7..2034a0e68 100644 --- a/server/admin.api.js +++ b/server/admin.api.js @@ -1,3 +1,4 @@ +/*eslint max-lines: ["warn", {"max": 500, "skipBlankLines": true, "skipComments": true}]*/ const HomebrewModel = require('./homebrew.model.js').model; const router = require('express').Router(); const Moment = require('moment'); From e9db7d1bb92014bc14b69209f30f4911ccdab048 Mon Sep 17 00:00:00 2001 From: "G.Ambatte" Date: Thu, 25 Apr 2024 15:37:50 +1200 Subject: [PATCH 012/398] Add return on success to lock route --- server/admin.api.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/server/admin.api.js b/server/admin.api.js index 2034a0e68..5a8b19acb 100644 --- a/server/admin.api.js +++ b/server/admin.api.js @@ -182,9 +182,12 @@ router.post('/admin/lock/:id', mw.adminOnly, async (req, res)=>{ await brew.save(); console.log(`Lock applied to brew ID ${brew.shareId} - ${brew.title}`); - } catch {} + } catch (error) { + console.error(error); + return res.status(500).json({ error: `Unable to set lock on brew ${req.params.id}` }); + } - return; + return res.status(200).json({ status: 'SUCCESS', lock }); }); router.get('/admin/lock/reviews', mw.adminOnly, async (req, res)=>{ From 4b1d6ebd7c6537ad700b42078772f0595368c186 Mon Sep 17 00:00:00 2001 From: "G.Ambatte" Date: Thu, 25 Apr 2024 15:58:43 +1200 Subject: [PATCH 013/398] Rename review request route --- server/admin.api.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/admin.api.js b/server/admin.api.js index 5a8b19acb..620ddebae 100644 --- a/server/admin.api.js +++ b/server/admin.api.js @@ -211,7 +211,7 @@ router.get('/admin/lock/reviews', mw.adminOnly, async (req, res)=>{ } }); -router.get('/admin/lock/requestreview/:id', mw.adminOnly, async (req, res)=>{ +router.get('/admin/lock/review/request/:id', mw.adminOnly, async (req, res)=>{ try { const filter = { shareId : req.params.id, From 20d48d7dc2d74def10e3e760cedf2f3b544661bd Mon Sep 17 00:00:00 2001 From: "G.Ambatte" Date: Thu, 25 Apr 2024 15:59:11 +1200 Subject: [PATCH 014/398] Add review removal route --- server/admin.api.js | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/server/admin.api.js b/server/admin.api.js index 620ddebae..9f72a5ea2 100644 --- a/server/admin.api.js +++ b/server/admin.api.js @@ -242,6 +242,30 @@ router.get('/admin/lock/review/request/:id', mw.adminOnly, async (req, res)=>{ } }); +router.get('/admin/lock/review/remove/:id', mw.adminOnly, async (req, res)=>{ + try { + const filter = { + shareId : req.params.id, + 'lock.locked' : true, + 'lock.reviewRequested' : { '$exists': 1 } + }; + + const brew = await HomebrewModel.findOne(filter); + if(!brew) { return res.status(500).json({ error: `Brew ID ${req.params.id} does not have a review pending!` }); }; + + delete brew.lock.reviewRequested; + brew.markModified('lock'); + + await brew.save(); + + console.log(`Review request removed on brew ID ${brew.shareId} - ${brew.title}`); + return res.json(brew); + } catch (error) { + console.error(error); + return res.status(500).json({ error: `Unable to remove request for review on brew ID ${req.params.id}` }); + } +}); + router.get('/admin', mw.adminOnly, (req, res)=>{ templateFn('admin', { url : req.originalUrl From b4ce621630c39e03be9f1737ba83a287d473d470 Mon Sep 17 00:00:00 2001 From: "G.Ambatte" Date: Thu, 9 May 2024 07:37:37 +1200 Subject: [PATCH 015/398] Request review no longer Admin only --- server/admin.api.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/server/admin.api.js b/server/admin.api.js index 9f72a5ea2..455258555 100644 --- a/server/admin.api.js +++ b/server/admin.api.js @@ -211,7 +211,9 @@ router.get('/admin/lock/reviews', mw.adminOnly, async (req, res)=>{ } }); -router.get('/admin/lock/review/request/:id', mw.adminOnly, async (req, res)=>{ +router.get('/admin/lock/review/request/:id', async (req, res)=>{ + // === This route is NOT Admin only === + // Any user can request a review of their document try { const filter = { shareId : req.params.id, From 1fe2a26e8336a03b5730e7b03441e8cd52411296 Mon Sep 17 00:00:00 2001 From: "G.Ambatte" Date: Fri, 10 May 2024 12:38:31 +1200 Subject: [PATCH 016/398] Tabify Admin page --- client/admin/admin.jsx | 40 +++++++++++++++++++++++++++++++++------- 1 file changed, 33 insertions(+), 7 deletions(-) diff --git a/client/admin/admin.jsx b/client/admin/admin.jsx index 92e0b2aee..c20b6abed 100644 --- a/client/admin/admin.jsx +++ b/client/admin/admin.jsx @@ -8,11 +8,38 @@ const BrewLookup = require('./brewLookup/brewLookup.jsx'); const BrewCompress = require ('./brewCompress/brewCompress.jsx'); const Stats = require('./stats/stats.jsx'); +const tabGroups = ['brews']; + const Admin = createClass({ getDefaultProps : function() { return {}; }, + getInitialState : function() { + return { + currentTab : 'brews' + }; + }, + + handleClick : function(newTab) { + if(this.state.currentTab === newTab) return; + this.setState({ + currentTab : newTab + }); + }, + + renderBrewTools : function(){ + return <> + +
+ +
+ +
+ + ; + }, + render : function(){ return
@@ -23,13 +50,12 @@ const Admin = createClass({
- -
- -
- -
- +
+ {tabGroups.map((name, idx)=>{ + return ; + })} +
+ {this.state.currentTab == 'brews' && this.renderBrewTools()}
; } From e7dc757293f00d7f78c21b4aad4a3f22d5447051 Mon Sep 17 00:00:00 2001 From: "G.Ambatte" Date: Sat, 11 May 2024 23:58:37 +1200 Subject: [PATCH 017/398] Initial UI functionality for most Lock functions --- client/admin/admin.jsx | 7 +- client/admin/admin.less | 18 +++ client/admin/lockTools/lockTools.jsx | 176 ++++++++++++++++++++++++++ client/admin/lockTools/lockTools.less | 3 + server/admin.api.js | 48 +++++-- 5 files changed, 240 insertions(+), 12 deletions(-) create mode 100644 client/admin/lockTools/lockTools.jsx create mode 100644 client/admin/lockTools/lockTools.less diff --git a/client/admin/admin.jsx b/client/admin/admin.jsx index c20b6abed..088847a66 100644 --- a/client/admin/admin.jsx +++ b/client/admin/admin.jsx @@ -8,7 +8,9 @@ const BrewLookup = require('./brewLookup/brewLookup.jsx'); const BrewCompress = require ('./brewCompress/brewCompress.jsx'); const Stats = require('./stats/stats.jsx'); -const tabGroups = ['brews']; +const LockTools = require('./lockTools/lockTools.jsx'); + +const tabGroups = ['brews', 'locks']; const Admin = createClass({ getDefaultProps : function() { @@ -52,10 +54,11 @@ const Admin = createClass({
{tabGroups.map((name, idx)=>{ - return ; + return ; })}
{this.state.currentTab == 'brews' && this.renderBrewTools()} + {this.state.currentTab == 'locks' && }
; } diff --git a/client/admin/admin.less b/client/admin/admin.less index a61335835..39a66bd54 100644 --- a/client/admin/admin.less +++ b/client/admin/admin.less @@ -40,5 +40,23 @@ body{ margin : 30px 0px; } + .tabs { + border-bottom: 1px solid black; + } + + button.tab { + margin: 2px 2px 0px; + border-width: 1px 1px 0px; + border-style: solid; + border-color: black; + border-radius: 5px 5px 0px 0px; + color: black; + background-color: transparent; + &.active { + background-color: #000000a0; + color: white; + text-decoration: underline; + } + } } diff --git a/client/admin/lockTools/lockTools.jsx b/client/admin/lockTools/lockTools.jsx new file mode 100644 index 000000000..710a29681 --- /dev/null +++ b/client/admin/lockTools/lockTools.jsx @@ -0,0 +1,176 @@ +require('./lockTools.less'); +const React = require('react'); +const createClass = require('create-react-class'); + +const request = require('superagent'); + +const LockTools = createClass({ + getInitialState : function() { + return { + fetching : false, + reviewCount : 0 + }; + }, + + componentDidMount : function() { + this.updateReviewCount(); + }, + + updateReviewCount : async function() { + const newCount = await request.get('/admin/lock') + .then((res)=>{return res.body?.count || 'Unknown';}); + if(newCount != this.state.reviewCount){ + this.setState({ + reviewCount : newCount + }); + } + }, + + render : function() { + return
+

Lock Count

+

Number of brews currently locked: {this.state.reviewCount}

+ +
+ +
+

Lock Brew

+ NYI +
+ +
+ +
; + } +}); + +const LockTable = createClass({ + getDefaultProps : function() { + return { + title : '', + fetchURL : '/admin/locks', + resultName : '', + propertyNames : ['shareId'] + }; + }, + + getInitialState : function() { + return { + result : '', + error : '', + searching : false + }; + }, + + clickFn(){ + this.setState({ searching: true, error: null }); + + request.get(this.props.fetchURL) + .then((res)=>this.setState({ result: res.body })) + .catch((err)=>this.setState({ error: err })) + .finally(()=>{ + this.setState({ searching: false }); + }); + }, + + render : function () { + return <> +

{this.props.title}

+ + {this.state.result[this.props.resultName] && + <> +

Total Reviews Waiting: {this.state.result[this.props.resultName].length}

+ + + + {this.props.propertyNames.map((name, idx)=>{ + return ; + })} + + + + {this.state.result[this.props.resultName].map((result, resultIdx)=>{ + return {navigator.clipboard.writeText(result.shareId.toString());}}> + {this.props.propertyNames.map((name, nameIdx)=>{ + return ; + })} + ; + })} + +
{name}
+ {result[name].toString()} +
+ + } + ; + } +}); + +const LockLookup = createClass({ + getDefaultProps : function() { + return { + fetchURL : '/admin/lookup' + }; + }, + + getInitialState : function() { + return { + query : '', + result : '', + error : '', + searching : false + }; + }, + + handleChange(e){ + this.setState({ query: e.target.value }); + }, + + clickFn(){ + this.setState({ searching: true, error: null }); + + request.get(`${this.props.fetchURL}/${this.state.query}`) + .then((res)=>this.setState({ result: res.body })) + .catch((err)=>this.setState({ error: err })) + .finally(()=>{ + this.setState({ searching: false }); + }); + }, + + renderResult : function(){ + return <> +

Result:

+ + + {Object.keys(this.state.result).map((key, idx)=>{ + return + + + ; + })} + +
{key}{this.state.result[key].toString()} +
+ ; + }, + + render : function() { + return
+

{this.props.title}

+ + + + {this.state.error + &&
{this.state.error.toString()}
+ } + + {this.state.result && this.renderResult()} +
; + } +}); + +module.exports = LockTools; \ No newline at end of file diff --git a/client/admin/lockTools/lockTools.less b/client/admin/lockTools/lockTools.less new file mode 100644 index 000000000..8f0ec04bd --- /dev/null +++ b/client/admin/lockTools/lockTools.less @@ -0,0 +1,3 @@ +.lockTools { + display: block; +} \ No newline at end of file diff --git a/server/admin.api.js b/server/admin.api.js index 455258555..e1d33f029 100644 --- a/server/admin.api.js +++ b/server/admin.api.js @@ -162,12 +162,13 @@ router.get('/admin/lock', mw.adminOnly, async (req, res)=>{ }); } catch (error) { console.error(error); - return res.status(500).json({ error: 'Unable to get lock count' }); + return res.json({ status: 'ERROR', detail: 'Unable to get lock count', error }); } }); router.post('/admin/lock/:id', mw.adminOnly, async (req, res)=>{ const lock = req.body; + lock.applied = new Date; try { const filter = { @@ -176,6 +177,8 @@ router.post('/admin/lock/:id', mw.adminOnly, async (req, res)=>{ const brew = await HomebrewModel.findOne(filter); + if(brew.lock) return res.json({ status: 'ALREADY LOCKED', detail: `Lock already exists on brew ${req.params.id} - ${brew.title}` }); + brew.lock = lock; brew.markModified('lock'); @@ -184,10 +187,34 @@ router.post('/admin/lock/:id', mw.adminOnly, async (req, res)=>{ console.log(`Lock applied to brew ID ${brew.shareId} - ${brew.title}`); } catch (error) { console.error(error); - return res.status(500).json({ error: `Unable to set lock on brew ${req.params.id}` }); + return res.json({ error, message: `Unable to set lock on brew ${req.params.id}` }); } - return res.status(200).json({ status: 'SUCCESS', lock }); + return res.json({ status: 'LOCKED', detail: `Lock applied to brew ID ${brew.shareId} - ${brew.title}`, lock }); +}); + +router.get('/admin/unlock/:id', mw.adminOnly, async (req, res)=>{ + try { + const filter = { + shareId : req.params.id + }; + + const brew = await HomebrewModel.findOne(filter); + + if(!brew.lock) return res.json({ status: 'NOT LOCKED', detail: `Brew ID ${req.params.id} is not locked!` }); + + brew.lock = undefined; + brew.markModified('lock'); + + await brew.save(); + + console.log(`Lock removed from brew ID ${brew.shareId} - ${brew.title}`); + } catch (error) { + console.error(error); + return res.json({ status: 'ERROR', detail: `Unable to clear lock on brew ${req.params.id}`, error }); + } + + return res.json({ status: 'UNLOCKED', detail: `Lock removed from brew ID ${req.params.id}` }); }); router.get('/admin/lock/reviews', mw.adminOnly, async (req, res)=>{ @@ -202,12 +229,13 @@ router.get('/admin/lock/reviews', mw.adminOnly, async (req, res)=>{ } ]; const reviewDocuments = await HomebrewModel.getAggregate(countReviewsPipeline); + console.log(reviewDocuments); return res.json({ reviewDocuments }); } catch (error) { console.error(error); - return res.status(500).json({ error: 'Unable to get review collection' }); + return res.json({ status: 'ERROR', detail: 'Unable to get review collection', error }); } }); @@ -221,11 +249,11 @@ router.get('/admin/lock/review/request/:id', async (req, res)=>{ }; const brew = await HomebrewModel.findOne(filter); - if(!brew) { return res.status(500).json({ error: `Brew ID ${req.params.id} is not locked!` }); }; + if(!brew) { return res.json({ status: 'NOT LOCKED', detail: `Brew ID ${req.params.id} is not locked!` }); }; if(brew.lock.reviewRequested){ console.log(`Review already requested for brew ${brew.shareId} - ${brew.title}`); - return res.status(500).json({ error: `Review already requested for brew ${brew.shareId} - ${brew.title}` }); + return res.json({ status: 'NOT REQUESTED', detail: `Review already requested for brew ${brew.shareId} - ${brew.title}` }); }; brew.lock.reviewRequested = new Date(); @@ -237,10 +265,10 @@ router.get('/admin/lock/review/request/:id', async (req, res)=>{ }); console.log(`Review requested on brew ${brew.shareId} - ${brew.title}`); - return res.json(brew); + return res.json({ status: 'REVIEW REQUESTED', brew }); } catch (error) { console.error(error); - return res.status(500).json({ error: `Unable to set request for review on brew ID ${req.params.id}` }); + return res.json({ status: 'ERROR', detail: `Unable to set request for review on brew ID ${req.params.id}`, error }); } }); @@ -253,7 +281,7 @@ router.get('/admin/lock/review/remove/:id', mw.adminOnly, async (req, res)=>{ }; const brew = await HomebrewModel.findOne(filter); - if(!brew) { return res.status(500).json({ error: `Brew ID ${req.params.id} does not have a review pending!` }); }; + if(!brew) { return res.json({ status: 'NOT REMOVED', detail: `Brew ID ${req.params.id} does not have a review pending!` }); }; delete brew.lock.reviewRequested; brew.markModified('lock'); @@ -264,7 +292,7 @@ router.get('/admin/lock/review/remove/:id', mw.adminOnly, async (req, res)=>{ return res.json(brew); } catch (error) { console.error(error); - return res.status(500).json({ error: `Unable to remove request for review on brew ID ${req.params.id}` }); + return res.json({ error: `Unable to remove request for review on brew ID ${req.params.id}` }); } }); From 2a91d3ddbdaab7387d7c5c07a0eb356173f5edbc Mon Sep 17 00:00:00 2001 From: "G.Ambatte" Date: Wed, 15 May 2024 16:07:28 +1200 Subject: [PATCH 018/398] Additional styling --- client/admin/lockTools/lockTools.less | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/client/admin/lockTools/lockTools.less b/client/admin/lockTools/lockTools.less index 8f0ec04bd..9554ffa19 100644 --- a/client/admin/lockTools/lockTools.less +++ b/client/admin/lockTools/lockTools.less @@ -1,3 +1,13 @@ .lockTools { - display: block; + .lockBrew label { + width: 50%; + display: inline-block; + text-align: right; + line-height: 1.5em; + input { + float: right; + width: 70%; + margin-left: 10px; + } + } } \ No newline at end of file From 2502c0e87ca04e35f01987ffb3a60d969488b383 Mon Sep 17 00:00:00 2001 From: "G.Ambatte" Date: Wed, 15 May 2024 16:08:26 +1200 Subject: [PATCH 019/398] Add missing return status messages --- server/admin.api.js | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/server/admin.api.js b/server/admin.api.js index e1d33f029..eb025a686 100644 --- a/server/admin.api.js +++ b/server/admin.api.js @@ -170,14 +170,18 @@ router.post('/admin/lock/:id', mw.adminOnly, async (req, res)=>{ const lock = req.body; lock.applied = new Date; + let brew; try { const filter = { shareId : req.params.id }; - const brew = await HomebrewModel.findOne(filter); + brew = await HomebrewModel.findOne(filter); - if(brew.lock) return res.json({ status: 'ALREADY LOCKED', detail: `Lock already exists on brew ${req.params.id} - ${brew.title}` }); + if(brew.lock) { + console.log('ALREADY LOCKED'); + return res.json({ status: 'ALREADY LOCKED', detail: `Lock already exists on brew ${req.params.id} - ${brew.title}` }); + } brew.lock = lock; brew.markModified('lock'); @@ -187,7 +191,7 @@ router.post('/admin/lock/:id', mw.adminOnly, async (req, res)=>{ console.log(`Lock applied to brew ID ${brew.shareId} - ${brew.title}`); } catch (error) { console.error(error); - return res.json({ error, message: `Unable to set lock on brew ${req.params.id}` }); + return res.json({ status: 'ERROR', error, message: `Unable to set lock on brew ${req.params.id}` }); } return res.json({ status: 'LOCKED', detail: `Lock applied to brew ID ${brew.shareId} - ${brew.title}`, lock }); @@ -244,8 +248,8 @@ router.get('/admin/lock/review/request/:id', async (req, res)=>{ // Any user can request a review of their document try { const filter = { - shareId : req.params.id, - 'lock.locked' : true + shareId : req.params.id, + lock : { $exists: 1 } }; const brew = await HomebrewModel.findOne(filter); @@ -283,7 +287,7 @@ router.get('/admin/lock/review/remove/:id', mw.adminOnly, async (req, res)=>{ const brew = await HomebrewModel.findOne(filter); if(!brew) { return res.json({ status: 'NOT REMOVED', detail: `Brew ID ${req.params.id} does not have a review pending!` }); }; - delete brew.lock.reviewRequested; + brew.lock.reviewRequested = undefined; brew.markModified('lock'); await brew.save(); From 65f1c19721b9a8f9eeeb930253a17c026a28674b Mon Sep 17 00:00:00 2001 From: "G.Ambatte" Date: Wed, 15 May 2024 16:14:09 +1200 Subject: [PATCH 020/398] Add functional Lock Brew component --- client/admin/lockTools/lockTools.jsx | 75 +++++++++++++++++++++++++++- 1 file changed, 73 insertions(+), 2 deletions(-) diff --git a/client/admin/lockTools/lockTools.jsx b/client/admin/lockTools/lockTools.jsx index 710a29681..6e5d7f90e 100644 --- a/client/admin/lockTools/lockTools.jsx +++ b/client/admin/lockTools/lockTools.jsx @@ -34,8 +34,7 @@ const LockTools = createClass({

-

Lock Brew

- NYI +

@@ -44,6 +43,77 @@ const LockTools = createClass({ } }); +const LockBrew = createClass({ + getInitialState : function() { + return { + brewId : '', + code : 1000, + editMessage : '', + shareMessage : '' + }; + }, + + handleChange : function(e, varName) { + const output = {}; + output[varName] = e.target.value; + this.setState(output); + }, + + submit : function(e){ + e.preventDefault(); + if(!this.state.editMessage) return; + const newLock = { + code : parseInt(this.state.code) || 100, + editMessage : this.state.editMessage, + shareMessage : this.state.shareMessage, + applied : new Date, + locked : true + }; + + request.post(`/admin/lock/${this.state.brewId}`) + .send(newLock) + .set('Content-Type', 'application/json') + .then((response)=>{ + console.log(response.body); + }); + }, + + renderInput : function (name) { + return this.handleChange(e, name)} autoComplete='off' required/>; + }, + + render : function() { + return
+

Lock Brew

+
+ +
+ +
+ +
+ +
+ +
+
; + } +}); + const LockTable = createClass({ getDefaultProps : function() { return { @@ -140,6 +210,7 @@ const LockLookup = createClass({ }, renderResult : function(){ + console.log(this.state.result); return <>

Result:

From b093be52a25321e2f0148c148b8c830371839d20 Mon Sep 17 00:00:00 2001 From: "G.Ambatte" Date: Wed, 15 May 2024 16:57:28 +1200 Subject: [PATCH 021/398] Update esLint rules --- client/admin/lockTools/lockTools.jsx | 1 + 1 file changed, 1 insertion(+) diff --git a/client/admin/lockTools/lockTools.jsx b/client/admin/lockTools/lockTools.jsx index 6e5d7f90e..9e53e31fd 100644 --- a/client/admin/lockTools/lockTools.jsx +++ b/client/admin/lockTools/lockTools.jsx @@ -1,3 +1,4 @@ +/*eslint max-lines: ["warn", {"max": 300, "skipBlankLines": true, "skipComments": true}]*/ require('./lockTools.less'); const React = require('react'); const createClass = require('create-react-class'); From 7c4721932dcd6c1adea242aa0bf80fca77b5e4a3 Mon Sep 17 00:00:00 2001 From: "G.Ambatte" Date: Wed, 15 May 2024 19:50:27 +1200 Subject: [PATCH 022/398] Remove unnecessary function from HB.model --- server/admin.api.js | 45 ++++++++++++++++++---------------------- server/homebrew.model.js | 6 ------ 2 files changed, 20 insertions(+), 31 deletions(-) diff --git a/server/admin.api.js b/server/admin.api.js index eb025a686..625e44f22 100644 --- a/server/admin.api.js +++ b/server/admin.api.js @@ -147,16 +147,16 @@ router.get('/admin/lock', mw.adminOnly, async (req, res)=>{ { $match : { - 'lock.locked' : true, - }, + lock : { $exists: 1 } + } }, { - $count : - 'count', + $count : 'count' } ]; - const totalLockCount = await HomebrewModel.getAggregate(countLocksPipeline); + const totalLockCount = await HomebrewModel.aggregate(countLocksPipeline); const count = totalLockCount[0].count; + console.log(totalLockCount); return res.json({ count }); @@ -188,10 +188,10 @@ router.post('/admin/lock/:id', mw.adminOnly, async (req, res)=>{ await brew.save(); - console.log(`Lock applied to brew ID ${brew.shareId} - ${brew.title}`); + // console.log(`Lock applied to brew ID ${brew.shareId} - ${brew.title}`); } catch (error) { console.error(error); - return res.json({ status: 'ERROR', error, message: `Unable to set lock on brew ${req.params.id}` }); + return res.json({ status: 'ERROR', error, detail: `Unable to set lock on brew ${req.params.id}` }); } return res.json({ status: 'LOCKED', detail: `Lock applied to brew ID ${brew.shareId} - ${brew.title}`, lock }); @@ -212,7 +212,7 @@ router.get('/admin/unlock/:id', mw.adminOnly, async (req, res)=>{ await brew.save(); - console.log(`Lock removed from brew ID ${brew.shareId} - ${brew.title}`); + // console.log(`Lock removed from brew ID ${brew.shareId} - ${brew.title}`); } catch (error) { console.error(error); return res.json({ status: 'ERROR', detail: `Unable to clear lock on brew ${req.params.id}`, error }); @@ -227,13 +227,11 @@ router.get('/admin/lock/reviews', mw.adminOnly, async (req, res)=>{ { $match : { - 'lock.locked' : true, 'lock.reviewRequested' : { '$exists': 1 } }, } ]; - const reviewDocuments = await HomebrewModel.getAggregate(countReviewsPipeline); - console.log(reviewDocuments); + const reviewDocuments = await HomebrewModel.aggregate(countReviewsPipeline); return res.json({ reviewDocuments }); @@ -256,20 +254,17 @@ router.get('/admin/lock/review/request/:id', async (req, res)=>{ if(!brew) { return res.json({ status: 'NOT LOCKED', detail: `Brew ID ${req.params.id} is not locked!` }); }; if(brew.lock.reviewRequested){ - console.log(`Review already requested for brew ${brew.shareId} - ${brew.title}`); - return res.json({ status: 'NOT REQUESTED', detail: `Review already requested for brew ${brew.shareId} - ${brew.title}` }); + // console.log(`Review already requested for brew ${brew.shareId} - ${brew.title}`); + return res.json({ status: 'ALREADY REQUESTED', detail: `Review already requested for brew ${brew.shareId} - ${brew.title}` }); }; brew.lock.reviewRequested = new Date(); brew.markModified('lock'); - await brew.save() - .catch((err)=>{ - return err; - }); + await brew.save(); - console.log(`Review requested on brew ${brew.shareId} - ${brew.title}`); - return res.json({ status: 'REVIEW REQUESTED', brew }); + // console.log(`Review requested on brew ${brew.shareId} - ${brew.title}`); + return res.json({ status: 'REVIEW REQUESTED', detail: `Review requested for ${brew.shareId} - ${brew.title}` }); } catch (error) { console.error(error); return res.json({ status: 'ERROR', detail: `Unable to set request for review on brew ID ${req.params.id}`, error }); @@ -277,14 +272,14 @@ router.get('/admin/lock/review/request/:id', async (req, res)=>{ }); router.get('/admin/lock/review/remove/:id', mw.adminOnly, async (req, res)=>{ + let brew; try { const filter = { shareId : req.params.id, - 'lock.locked' : true, - 'lock.reviewRequested' : { '$exists': 1 } + 'lock.reviewRequested' : { $exists: 1 } }; - const brew = await HomebrewModel.findOne(filter); + brew = await HomebrewModel.findOne(filter); if(!brew) { return res.json({ status: 'NOT REMOVED', detail: `Brew ID ${req.params.id} does not have a review pending!` }); }; brew.lock.reviewRequested = undefined; @@ -292,11 +287,11 @@ router.get('/admin/lock/review/remove/:id', mw.adminOnly, async (req, res)=>{ await brew.save(); - console.log(`Review request removed on brew ID ${brew.shareId} - ${brew.title}`); - return res.json(brew); + // console.log(`Review request removed on brew ID ${brew.shareId} - ${brew.title}`); + return res.json({ status: 'REVIEW REQUEST REMOVED', detail: `Request for Review removed from brew ID ${brew.shareId} - ${brew.title}` }); } catch (error) { console.error(error); - return res.json({ error: `Unable to remove request for review on brew ID ${req.params.id}` }); + return res.json({ status: 'ERROR', detail: `Unable to remove request for review on brew ID ${req.params.id}`, error }); } }); diff --git a/server/homebrew.model.js b/server/homebrew.model.js index 81f31f1eb..ea32265ff 100644 --- a/server/homebrew.model.js +++ b/server/homebrew.model.js @@ -62,12 +62,6 @@ HomebrewSchema.statics.getByUser = async function(username, allowAccess=false, f return brews; }; -HomebrewSchema.statics.getAggregate = async function(aggregate, options={}){ - const output = await Homebrew.aggregate(aggregate, options) - .catch((error)=>{throw 'Can not get aggregate';}); - return output; -}; - const Homebrew = mongoose.model('Homebrew', HomebrewSchema); module.exports = { From c0c674d8626abcc74169e2f4f548327831e73966 Mon Sep 17 00:00:00 2001 From: "G.Ambatte" Date: Wed, 15 May 2024 19:52:08 +1200 Subject: [PATCH 023/398] Comment out debug logging --- server/admin.api.js | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/server/admin.api.js b/server/admin.api.js index 625e44f22..8c29791ce 100644 --- a/server/admin.api.js +++ b/server/admin.api.js @@ -147,16 +147,16 @@ router.get('/admin/lock', mw.adminOnly, async (req, res)=>{ { $match : { - lock : { $exists: 1 } + lock : true } }, { - $count : 'count' + $count : + 'count' } ]; const totalLockCount = await HomebrewModel.aggregate(countLocksPipeline); const count = totalLockCount[0].count; - console.log(totalLockCount); return res.json({ count }); @@ -179,7 +179,7 @@ router.post('/admin/lock/:id', mw.adminOnly, async (req, res)=>{ brew = await HomebrewModel.findOne(filter); if(brew.lock) { - console.log('ALREADY LOCKED'); + // console.log('ALREADY LOCKED'); return res.json({ status: 'ALREADY LOCKED', detail: `Lock already exists on brew ${req.params.id} - ${brew.title}` }); } @@ -191,7 +191,7 @@ router.post('/admin/lock/:id', mw.adminOnly, async (req, res)=>{ // console.log(`Lock applied to brew ID ${brew.shareId} - ${brew.title}`); } catch (error) { console.error(error); - return res.json({ status: 'ERROR', error, detail: `Unable to set lock on brew ${req.params.id}` }); + return res.json({ status: 'ERROR', error, message: `Unable to set lock on brew ${req.params.id}` }); } return res.json({ status: 'LOCKED', detail: `Lock applied to brew ID ${brew.shareId} - ${brew.title}`, lock }); @@ -227,6 +227,7 @@ router.get('/admin/lock/reviews', mw.adminOnly, async (req, res)=>{ { $match : { + 'lock.locked' : true, 'lock.reviewRequested' : { '$exists': 1 } }, } @@ -255,16 +256,19 @@ router.get('/admin/lock/review/request/:id', async (req, res)=>{ if(brew.lock.reviewRequested){ // console.log(`Review already requested for brew ${brew.shareId} - ${brew.title}`); - return res.json({ status: 'ALREADY REQUESTED', detail: `Review already requested for brew ${brew.shareId} - ${brew.title}` }); + return res.json({ status: 'NOT REQUESTED', detail: `Review already requested for brew ${brew.shareId} - ${brew.title}` }); }; brew.lock.reviewRequested = new Date(); brew.markModified('lock'); - await brew.save(); + await brew.save() + .catch((err)=>{ + return err; + }); // console.log(`Review requested on brew ${brew.shareId} - ${brew.title}`); - return res.json({ status: 'REVIEW REQUESTED', detail: `Review requested for ${brew.shareId} - ${brew.title}` }); + return res.json({ status: 'REVIEW REQUESTED', brew }); } catch (error) { console.error(error); return res.json({ status: 'ERROR', detail: `Unable to set request for review on brew ID ${req.params.id}`, error }); @@ -272,14 +276,14 @@ router.get('/admin/lock/review/request/:id', async (req, res)=>{ }); router.get('/admin/lock/review/remove/:id', mw.adminOnly, async (req, res)=>{ - let brew; try { const filter = { shareId : req.params.id, - 'lock.reviewRequested' : { $exists: 1 } + 'lock.locked' : true, + 'lock.reviewRequested' : { '$exists': 1 } }; - brew = await HomebrewModel.findOne(filter); + const brew = await HomebrewModel.findOne(filter); if(!brew) { return res.json({ status: 'NOT REMOVED', detail: `Brew ID ${req.params.id} does not have a review pending!` }); }; brew.lock.reviewRequested = undefined; @@ -288,10 +292,10 @@ router.get('/admin/lock/review/remove/:id', mw.adminOnly, async (req, res)=>{ await brew.save(); // console.log(`Review request removed on brew ID ${brew.shareId} - ${brew.title}`); - return res.json({ status: 'REVIEW REQUEST REMOVED', detail: `Request for Review removed from brew ID ${brew.shareId} - ${brew.title}` }); + return res.json(brew); } catch (error) { console.error(error); - return res.json({ status: 'ERROR', detail: `Unable to remove request for review on brew ID ${req.params.id}`, error }); + return res.json({ error: `Unable to remove request for review on brew ID ${req.params.id}` }); } }); From b237f29636bea20f7486915e0883b62ed8a3da2b Mon Sep 17 00:00:00 2001 From: "G.Ambatte" Date: Wed, 15 May 2024 19:58:29 +1200 Subject: [PATCH 024/398] Clean up API functions --- server/admin.api.js | 33 +++++++++++++-------------------- 1 file changed, 13 insertions(+), 20 deletions(-) diff --git a/server/admin.api.js b/server/admin.api.js index 8c29791ce..13d3cb78c 100644 --- a/server/admin.api.js +++ b/server/admin.api.js @@ -155,8 +155,7 @@ router.get('/admin/lock', mw.adminOnly, async (req, res)=>{ 'count' } ]; - const totalLockCount = await HomebrewModel.aggregate(countLocksPipeline); - const count = totalLockCount[0].count; + const count = await HomebrewModel.aggregate(countLocksPipeline); return res.json({ count }); @@ -167,16 +166,15 @@ router.get('/admin/lock', mw.adminOnly, async (req, res)=>{ }); router.post('/admin/lock/:id', mw.adminOnly, async (req, res)=>{ - const lock = req.body; - lock.applied = new Date; - - let brew; try { + const lock = req.body; + lock.applied = new Date; + const filter = { shareId : req.params.id }; - brew = await HomebrewModel.findOne(filter); + const brew = await HomebrewModel.findOne(filter); if(brew.lock) { // console.log('ALREADY LOCKED'); @@ -189,12 +187,11 @@ router.post('/admin/lock/:id', mw.adminOnly, async (req, res)=>{ await brew.save(); // console.log(`Lock applied to brew ID ${brew.shareId} - ${brew.title}`); + return res.json({ status: 'LOCKED', detail: `Lock applied to brew ID ${brew.shareId} - ${brew.title}`, lock }); } catch (error) { console.error(error); return res.json({ status: 'ERROR', error, message: `Unable to set lock on brew ${req.params.id}` }); } - - return res.json({ status: 'LOCKED', detail: `Lock applied to brew ID ${brew.shareId} - ${brew.title}`, lock }); }); router.get('/admin/unlock/:id', mw.adminOnly, async (req, res)=>{ @@ -256,19 +253,16 @@ router.get('/admin/lock/review/request/:id', async (req, res)=>{ if(brew.lock.reviewRequested){ // console.log(`Review already requested for brew ${brew.shareId} - ${brew.title}`); - return res.json({ status: 'NOT REQUESTED', detail: `Review already requested for brew ${brew.shareId} - ${brew.title}` }); + return res.json({ status: 'ALREADY REQUESTED', detail: `Review already requested for brew ${brew.shareId} - ${brew.title}` }); }; brew.lock.reviewRequested = new Date(); brew.markModified('lock'); - await brew.save() - .catch((err)=>{ - return err; - }); + await brew.save(); // console.log(`Review requested on brew ${brew.shareId} - ${brew.title}`); - return res.json({ status: 'REVIEW REQUESTED', brew }); + return res.json({ status: 'REVIEW REQUESTED', detail: `Review requested on brew ID ${brew.shareId} - ${brew.title}` }); } catch (error) { console.error(error); return res.json({ status: 'ERROR', detail: `Unable to set request for review on brew ID ${req.params.id}`, error }); @@ -279,12 +273,11 @@ router.get('/admin/lock/review/remove/:id', mw.adminOnly, async (req, res)=>{ try { const filter = { shareId : req.params.id, - 'lock.locked' : true, - 'lock.reviewRequested' : { '$exists': 1 } + 'lock.reviewRequested' : { $exists: 1 } }; const brew = await HomebrewModel.findOne(filter); - if(!brew) { return res.json({ status: 'NOT REMOVED', detail: `Brew ID ${req.params.id} does not have a review pending!` }); }; + if(!brew) { return res.json({ status: 'REVIEW REQUEST NOT REMOVED', detail: `Brew ID ${req.params.id} does not have a review pending!` }); }; brew.lock.reviewRequested = undefined; brew.markModified('lock'); @@ -292,10 +285,10 @@ router.get('/admin/lock/review/remove/:id', mw.adminOnly, async (req, res)=>{ await brew.save(); // console.log(`Review request removed on brew ID ${brew.shareId} - ${brew.title}`); - return res.json(brew); + return res.json({status: 'REVIEW REQUEST REMOVED', detail: `Review request removed for brew ID ${brew.shareId} - ${brew.title}` }); } catch (error) { console.error(error); - return res.json({ error: `Unable to remove request for review on brew ID ${req.params.id}` }); + return res.json({ status: 'ERROR', detail: `Unable to remove request for review on brew ID ${req.params.id}`, error }); } }); From f5014f29c3973c1442c76d497fa78c4cad01b5ad Mon Sep 17 00:00:00 2001 From: "G.Ambatte" Date: Wed, 15 May 2024 23:13:53 +1200 Subject: [PATCH 025/398] Linter fix --- server/admin.api.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/admin.api.js b/server/admin.api.js index 13d3cb78c..f0714f1ce 100644 --- a/server/admin.api.js +++ b/server/admin.api.js @@ -285,7 +285,7 @@ router.get('/admin/lock/review/remove/:id', mw.adminOnly, async (req, res)=>{ await brew.save(); // console.log(`Review request removed on brew ID ${brew.shareId} - ${brew.title}`); - return res.json({status: 'REVIEW REQUEST REMOVED', detail: `Review request removed for brew ID ${brew.shareId} - ${brew.title}` }); + return res.json({ status: 'REVIEW REQUEST REMOVED', detail: `Review request removed for brew ID ${brew.shareId} - ${brew.title}` }); } catch (error) { console.error(error); return res.json({ status: 'ERROR', detail: `Unable to remove request for review on brew ID ${req.params.id}`, error }); From 96b955f2fe5b885cabb4e73b96b6c03422d6f55d Mon Sep 17 00:00:00 2001 From: "G.Ambatte" Date: Thu, 16 May 2024 17:00:26 +1200 Subject: [PATCH 026/398] Change lock check to stub.lock from stub.lock.locked --- server/homebrew.api.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/server/homebrew.api.js b/server/homebrew.api.js index e73a704a8..ef3af9a21 100644 --- a/server/homebrew.api.js +++ b/server/homebrew.api.js @@ -54,7 +54,7 @@ const api = { }); stub = stub?.toObject(); - if(stub?.lock?.locked && accessType != 'edit') { + if(stub?.lock && accessType != 'edit') { throw { HBErrorCode: '100', code: stub.lock.code, message: stub.lock.message, brewId: stub.shareId, brewTitle: stub.title }; } @@ -83,9 +83,9 @@ const api = { if(accessType === 'edit' && (authorsExist && !(isAuthor || isInvited))) { const accessError = { name: 'Access Error', status: 401 }; if(req.account){ - throw { ...accessError, message: 'User is not an Author', HBErrorCode: '03', authors: stub.authors, brewTitle: stub.title, shareId: stub.shareId}; + throw { ...accessError, message: 'User is not an Author', HBErrorCode: '03', authors: stub.authors, brewTitle: stub.title, shareId: stub.shareId }; } - throw { ...accessError, message: 'User is not logged in', HBErrorCode: '04', authors: stub.authors, brewTitle: stub.title, shareId: stub.shareId}; + throw { ...accessError, message: 'User is not logged in', HBErrorCode: '04', authors: stub.authors, brewTitle: stub.title, shareId: stub.shareId }; } // If after all of that we still don't have a brew, throw an exception From 4e11a0c737e0ad3332ba7dba6effae7a455d01c3 Mon Sep 17 00:00:00 2001 From: "G.Ambatte" Date: Thu, 16 May 2024 17:02:00 +1200 Subject: [PATCH 027/398] Fix error message --- server/homebrew.api.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/homebrew.api.js b/server/homebrew.api.js index ef3af9a21..4baab48ce 100644 --- a/server/homebrew.api.js +++ b/server/homebrew.api.js @@ -55,7 +55,7 @@ const api = { stub = stub?.toObject(); if(stub?.lock && accessType != 'edit') { - throw { HBErrorCode: '100', code: stub.lock.code, message: stub.lock.message, brewId: stub.shareId, brewTitle: stub.title }; + throw { HBErrorCode: '100', code: stub.lock.code, message: stub.lock.shareMessage, brewId: stub.shareId, brewTitle: stub.title }; } // If there is a google id, try to find the google brew From 7b287fb0f438b5d16e0a670a497a46048bb6f42a Mon Sep 17 00:00:00 2001 From: "G.Ambatte" Date: Thu, 16 May 2024 17:04:37 +1200 Subject: [PATCH 028/398] Fix test --- server/homebrew.api.spec.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/homebrew.api.spec.js b/server/homebrew.api.spec.js index 8a4748e38..c8539bf63 100644 --- a/server/homebrew.api.spec.js +++ b/server/homebrew.api.spec.js @@ -300,7 +300,7 @@ describe('Tests for api', ()=>{ }); it('access is denied to a locked brew', async()=>{ - const lockBrew = { title: 'test brew', shareId: '1', lock: { locked: true, code: 404, message: 'brew locked' } }; + const lockBrew = { title: 'test brew', shareId: '1', lock: { locked: true, code: 404, shareMessage: 'brew locked' } }; model.get = jest.fn(()=>toBrewPromise(lockBrew)); api.getId = jest.fn(()=>({ id: '1', googleId: undefined })); From d751addf9d8224be02f56d661ef1c7661f6fe344 Mon Sep 17 00:00:00 2001 From: "G.Ambatte" Date: Thu, 16 May 2024 17:18:50 +1200 Subject: [PATCH 029/398] Change lock static error message --- client/homebrew/pages/errorPage/errors/errorIndex.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/homebrew/pages/errorPage/errors/errorIndex.js b/client/homebrew/pages/errorPage/errors/errorIndex.js index f9d52c109..85df6d286 100644 --- a/client/homebrew/pages/errorPage/errors/errorIndex.js +++ b/client/homebrew/pages/errorPage/errors/errorIndex.js @@ -140,7 +140,7 @@ const errorIndex = (props)=>{ '100' : dedent` ## This brew has been locked. - Please contact the Administrators to unlock this document. + Once the author has taken corrective action, they may request an administrative review to have this document unlocked. : From 6314672109a4fdf9e2b16dce32fc08e3c0b7cf5c Mon Sep 17 00:00:00 2001 From: "G.Ambatte" Date: Sat, 8 Jun 2024 14:59:08 +1200 Subject: [PATCH 030/398] Pass the entire lock object to LockNotification --- client/homebrew/pages/editPage/editPage.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/homebrew/pages/editPage/editPage.jsx b/client/homebrew/pages/editPage/editPage.jsx index 48d0f3fe5..a9652a3ad 100644 --- a/client/homebrew/pages/editPage/editPage.jsx +++ b/client/homebrew/pages/editPage/editPage.jsx @@ -396,7 +396,7 @@ const EditPage = createClass({ {this.renderNavbar()}
- {this.props.brew.lock && } + {this.props.brew.lock && } Date: Sat, 8 Jun 2024 15:31:46 +1200 Subject: [PATCH 031/398] Shift API call for REQUEST REVIEW to PUT --- server/admin.api.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/admin.api.js b/server/admin.api.js index bc4f1fe73..9f25d74c8 100644 --- a/server/admin.api.js +++ b/server/admin.api.js @@ -237,7 +237,7 @@ router.get('/admin/lock/reviews', mw.adminOnly, async (req, res)=>{ } }); -router.get('/admin/lock/review/request/:id', async (req, res)=>{ +router.put('/admin/lock/review/request/:id', async (req, res)=>{ // === This route is NOT Admin only === // Any user can request a review of their document try { From f81d16309c872cffb4b91310abdc0a3d2e35a16c Mon Sep 17 00:00:00 2001 From: "G.Ambatte" Date: Sat, 8 Jun 2024 15:53:01 +1200 Subject: [PATCH 032/398] Add functionality to REQUEST REVIEW button --- .../lockNotification/lockNotification.jsx | 21 ++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/client/homebrew/pages/editPage/lockNotification/lockNotification.jsx b/client/homebrew/pages/editPage/lockNotification/lockNotification.jsx index c5eeaee47..da79ff265 100644 --- a/client/homebrew/pages/editPage/lockNotification/lockNotification.jsx +++ b/client/homebrew/pages/editPage/lockNotification/lockNotification.jsx @@ -1,17 +1,28 @@ require('./lockNotification.less'); const React = require('react'); +const request = require('../../../utils/request-middleware.js'); import Dialog from '../../../../components/dialog.jsx'; function LockNotification(props) { props = { shareId : 0, disableLock : ()=>{}, - message : '', + lock : {}, ...props }; - const removeLock = ()=>{ - alert(`Not yet implemented - ID ${props.shareId}`); + const [reviewState, setReviewState] = React.useState(false); + + const removeLock = async ()=>{ + await request.put(`/admin/lock/review/request/${props.shareId}`) + .then(()=>{ + setReviewState(true); + }); + }; + + const renderReviewButton = function(){ + if(reviewState || props.lock.reviewRequested){ return ; }; + return ; }; return @@ -19,11 +30,11 @@ function LockNotification(props) {

This brew been locked by the Administrators. It will not be accessible by any method other than the Editor until the lock is removed.


LOCK REASON

-

{props.message || 'Unable to retrieve Lock Message'}

+

{props.lock.editMessage || 'Unable to retrieve Lock Message'}


Once you have resolved this issue, click REQUEST LOCK REMOVAL to notify the Administrators for review.

Click CONTINUE TO EDITOR to temporarily hide this notification; it will reappear the next time the page is reloaded.

- + {renderReviewButton()}
; }; From 00fd1e415c8ac350f30759f4ecceb57894321d16 Mon Sep 17 00:00:00 2001 From: "G.Ambatte" Date: Sat, 8 Jun 2024 15:53:28 +1200 Subject: [PATCH 033/398] Change styling for inactive REQUEST REVIEW button --- .../pages/editPage/lockNotification/lockNotification.less | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/client/homebrew/pages/editPage/lockNotification/lockNotification.less b/client/homebrew/pages/editPage/lockNotification/lockNotification.less index 54f1a9569..de2692ec0 100644 --- a/client/homebrew/pages/editPage/lockNotification/lockNotification.less +++ b/client/homebrew/pages/editPage/lockNotification/lockNotification.less @@ -15,7 +15,10 @@ color : white; background-color : #333333; - &:hover { background-color : #777777; } + &.inactive, + &:hover { + background-color : #777777; + } } h1, h3 { From bc7731b819b9e7d5e8534e739a007043b00c6372 Mon Sep 17 00:00:00 2001 From: "G.Ambatte" Date: Sat, 8 Jun 2024 16:08:18 +1200 Subject: [PATCH 034/398] Fix review requested aggregation pipeline --- server/admin.api.js | 1 - 1 file changed, 1 deletion(-) diff --git a/server/admin.api.js b/server/admin.api.js index 9f25d74c8..498c1bff3 100644 --- a/server/admin.api.js +++ b/server/admin.api.js @@ -222,7 +222,6 @@ router.get('/admin/lock/reviews', mw.adminOnly, async (req, res)=>{ { $match : { - 'lock.locked' : true, 'lock.reviewRequested' : { '$exists': 1 } }, } From 240342007b955c269b1e092614963e3429a120bd Mon Sep 17 00:00:00 2001 From: "G.Ambatte" Date: Sat, 8 Jun 2024 16:36:20 +1200 Subject: [PATCH 035/398] Fix lock count function --- server/admin.api.js | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/server/admin.api.js b/server/admin.api.js index 498c1bff3..8559143c2 100644 --- a/server/admin.api.js +++ b/server/admin.api.js @@ -141,19 +141,13 @@ router.get('/admin/stats', mw.adminOnly, async (req, res)=>{ router.get('/admin/lock', mw.adminOnly, async (req, res)=>{ try { - const countLocksPipeline = [ - { - $match : - { - lock : true - } - }, - { - $count : - 'count' - } - ]; - const count = await HomebrewModel.aggregate(countLocksPipeline); + const countLocksQuery = { + lock : { $exists: true } + }; + const count = await HomebrewModel.countDocuments(countLocksQuery) + .then((result)=>{ + return result; + }); return res.json({ count }); From 634b099ade26c18e122c83e9d25a0c024f6883ce Mon Sep 17 00:00:00 2001 From: "G.Ambatte" Date: Sat, 8 Jun 2024 16:48:16 +1200 Subject: [PATCH 036/398] Add styling to LockTable --- client/admin/lockTools/lockTools.jsx | 2 +- client/admin/lockTools/lockTools.less | 12 ++++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/client/admin/lockTools/lockTools.jsx b/client/admin/lockTools/lockTools.jsx index 9e53e31fd..808f9058e 100644 --- a/client/admin/lockTools/lockTools.jsx +++ b/client/admin/lockTools/lockTools.jsx @@ -153,7 +153,7 @@ const LockTable = createClass({ {this.state.result[this.props.resultName] && <>

Total Reviews Waiting: {this.state.result[this.props.resultName].length}

-
+
{this.props.propertyNames.map((name, idx)=>{ diff --git a/client/admin/lockTools/lockTools.less b/client/admin/lockTools/lockTools.less index 9554ffa19..765c3cc5d 100644 --- a/client/admin/lockTools/lockTools.less +++ b/client/admin/lockTools/lockTools.less @@ -10,4 +10,16 @@ margin-left: 10px; } } + + .lockTable{ + td{ + border: 1px solid #333333; + padding: 4px 10px; + text-align: center; + + &:hover { + cursor: pointer; + } + } + } } \ No newline at end of file From 01ae858a1461a068eedbb10077ec6407190dc5b1 Mon Sep 17 00:00:00 2001 From: "G.Ambatte" Date: Sat, 8 Jun 2024 17:08:05 +1200 Subject: [PATCH 037/398] Update LockLookup placeholder value --- client/admin/lockTools/lockTools.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/admin/lockTools/lockTools.jsx b/client/admin/lockTools/lockTools.jsx index 808f9058e..d9448fc14 100644 --- a/client/admin/lockTools/lockTools.jsx +++ b/client/admin/lockTools/lockTools.jsx @@ -231,7 +231,7 @@ const LockLookup = createClass({ render : function() { return

{this.props.title}

- + From deef5998c54199ade997cb06e0629c6a49262d4a Mon Sep 17 00:00:00 2001 From: "G.Ambatte" Date: Sat, 8 Jun 2024 18:55:14 +1200 Subject: [PATCH 038/398] Update LockBrew text and styling --- client/admin/lockTools/lockTools.jsx | 80 ++++++++++++++++++--------- client/admin/lockTools/lockTools.less | 45 ++++++++++++--- 2 files changed, 90 insertions(+), 35 deletions(-) diff --git a/client/admin/lockTools/lockTools.jsx b/client/admin/lockTools/lockTools.jsx index d9448fc14..58829eacf 100644 --- a/client/admin/lockTools/lockTools.jsx +++ b/client/admin/lockTools/lockTools.jsx @@ -85,32 +85,60 @@ const LockBrew = createClass({ render : function() { return
-

Lock Brew

-
- -
- -
- -
- -
- - +
+

Lock Brew

+
+ +
+ +
+ +
+ +
+ + +
+
+

Suggestions

+
+

Codes

+
    +
  • 455 - Generic Lock
  • +
  • 456 - Copyright issues
  • +
  • 457 - Confidential Information Leakage
  • +
  • 458 - Sensitive Personal Information
  • +
  • 459 - Defamation or Libel
  • +
  • 460 - Hate Speech or Discrimination
  • +
  • 461 - Illegal Activities
  • +
  • 462 - Malware or Phishing
  • +
  • 463 - Plagiarism
  • +
  • 465 - Misrepresentation
  • +
  • 466 - Inappropriate Content
  • +
+
+
+

Messages

+
    +
  • Edit Message: This is the private message that is ONLY displayed to the authors of the locked brew. This message MUST specify exactly what actions must be taken in order to have the brew unlocked.
  • +
  • Share Message: This is the public message that is displayed to the EVERYONE that attempts to view the locked brew.
  • +
+
+
; } }); diff --git a/client/admin/lockTools/lockTools.less b/client/admin/lockTools/lockTools.less index 765c3cc5d..c34a69485 100644 --- a/client/admin/lockTools/lockTools.less +++ b/client/admin/lockTools/lockTools.less @@ -1,13 +1,40 @@ .lockTools { - .lockBrew label { - width: 50%; - display: inline-block; - text-align: right; - line-height: 1.5em; - input { - float: right; - width: 70%; - margin-left: 10px; + .lockBrew { + columns: 2; + + .lockForm { + break-inside: avoid; + + label { + width: 100%; + display: inline-block; + text-align: right; + line-height: 1.5em; + input { + float: right; + width: 70%; + margin-left: 10px; + } + } + } + + .lockSuggestions { + break-inside: avoid; + columns: 2; + line-height: 1.2em; + h2 { + column-span: all; + } + h3 { + margin-top: 0px; + } + b { + font-weight: 600; + } + + .lockCodes { + break-inside: avoid; + } } } From 7830c7e2eb6bd0fc4e6af5cdac23eee4e5cfc15a Mon Sep 17 00:00:00 2001 From: "G.Ambatte" Date: Sat, 8 Jun 2024 19:59:01 +1200 Subject: [PATCH 039/398] Add divs for styling of brewsAwaitingReview --- client/admin/lockTools/lockTools.jsx | 65 +++++++++++++++------------- 1 file changed, 36 insertions(+), 29 deletions(-) diff --git a/client/admin/lockTools/lockTools.jsx b/client/admin/lockTools/lockTools.jsx index 58829eacf..7f92cdd0e 100644 --- a/client/admin/lockTools/lockTools.jsx +++ b/client/admin/lockTools/lockTools.jsx @@ -174,35 +174,42 @@ const LockTable = createClass({ render : function () { return <> -

{this.props.title}

- - {this.state.result[this.props.resultName] && - <> -

Total Reviews Waiting: {this.state.result[this.props.resultName].length}

-
- - - {this.props.propertyNames.map((name, idx)=>{ - return ; - })} - - - - {this.state.result[this.props.resultName].map((result, resultIdx)=>{ - return {navigator.clipboard.writeText(result.shareId.toString());}}> - {this.props.propertyNames.map((name, nameIdx)=>{ - return ; - })} - ; - })} - -
{name}
- {result[name].toString()} -
- - } +
+
+

{this.props.title}

+ +
+ {this.state.result[this.props.resultName] && + <> +

Total Reviews Waiting: {this.state.result[this.props.resultName].length}

+
+

Click a row to copy the Share ID to the clipboard

+ + + + {this.props.propertyNames.map((name, idx)=>{ + return ; + })} + + + + {this.state.result[this.props.resultName].map((result, resultIdx)=>{ + return {navigator.clipboard.writeText(result.shareId.toString());}}> + {this.props.propertyNames.map((name, nameIdx)=>{ + return ; + })} + ; + })} + +
{name}
+ {result[name].toString()} +
+ + } +
; } }); From 44f2e3838735868203129b142f93298c79cb3d17 Mon Sep 17 00:00:00 2001 From: "G.Ambatte" Date: Sat, 8 Jun 2024 20:00:10 +1200 Subject: [PATCH 040/398] Shift unlock and removeReview functions to use PUT --- client/admin/lockTools/lockTools.jsx | 2 +- server/admin.api.js | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/client/admin/lockTools/lockTools.jsx b/client/admin/lockTools/lockTools.jsx index 7f92cdd0e..710d08ff2 100644 --- a/client/admin/lockTools/lockTools.jsx +++ b/client/admin/lockTools/lockTools.jsx @@ -237,7 +237,7 @@ const LockLookup = createClass({ clickFn(){ this.setState({ searching: true, error: null }); - request.get(`${this.props.fetchURL}/${this.state.query}`) + request.put(`${this.props.fetchURL}/${this.state.query}`) .then((res)=>this.setState({ result: res.body })) .catch((err)=>this.setState({ error: err })) .finally(()=>{ diff --git a/server/admin.api.js b/server/admin.api.js index 8559143c2..d02cdb67b 100644 --- a/server/admin.api.js +++ b/server/admin.api.js @@ -186,7 +186,7 @@ router.post('/admin/lock/:id', mw.adminOnly, async (req, res)=>{ } }); -router.get('/admin/unlock/:id', mw.adminOnly, async (req, res)=>{ +router.put('/admin/unlock/:id', mw.adminOnly, async (req, res)=>{ try { const filter = { shareId : req.params.id @@ -260,7 +260,7 @@ router.put('/admin/lock/review/request/:id', async (req, res)=>{ } }); -router.get('/admin/lock/review/remove/:id', mw.adminOnly, async (req, res)=>{ +router.put('/admin/lock/review/remove/:id', mw.adminOnly, async (req, res)=>{ try { const filter = { shareId : req.params.id, From 7d37602d433895c063857df733c0ae2dbdce8e30 Mon Sep 17 00:00:00 2001 From: "G.Ambatte" Date: Sat, 8 Jun 2024 20:01:53 +1200 Subject: [PATCH 041/398] Remove debugging line --- client/admin/lockTools/lockTools.jsx | 1 - 1 file changed, 1 deletion(-) diff --git a/client/admin/lockTools/lockTools.jsx b/client/admin/lockTools/lockTools.jsx index 710d08ff2..9a1d1d0ce 100644 --- a/client/admin/lockTools/lockTools.jsx +++ b/client/admin/lockTools/lockTools.jsx @@ -246,7 +246,6 @@ const LockLookup = createClass({ }, renderResult : function(){ - console.log(this.state.result); return <>

Result:

From 17aa564c57c27174d847676efc86f83efb7e5f24 Mon Sep 17 00:00:00 2001 From: "G.Ambatte" Date: Sat, 8 Jun 2024 21:05:44 +1200 Subject: [PATCH 042/398] Add styling for result tables --- client/admin/lockTools/lockTools.less | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/client/admin/lockTools/lockTools.less b/client/admin/lockTools/lockTools.less index c34a69485..272646ce2 100644 --- a/client/admin/lockTools/lockTools.less +++ b/client/admin/lockTools/lockTools.less @@ -39,14 +39,14 @@ } .lockTable{ - td{ - border: 1px solid #333333; - padding: 4px 10px; - text-align: center; - - &:hover { - cursor: pointer; - } + td:hover { + cursor: pointer; } } + + td { + border: 1px solid #333333; + padding: 4px 10px; + text-align: center; + } } \ No newline at end of file From 24cf78bc033b565ccde43b78c3837d2c132cbfdf Mon Sep 17 00:00:00 2001 From: "G.Ambatte" Date: Wed, 12 Jun 2024 20:44:55 +1200 Subject: [PATCH 043/398] Add lock result --- client/admin/lockTools/lockTools.jsx | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/client/admin/lockTools/lockTools.jsx b/client/admin/lockTools/lockTools.jsx index 9a1d1d0ce..bf77be018 100644 --- a/client/admin/lockTools/lockTools.jsx +++ b/client/admin/lockTools/lockTools.jsx @@ -50,7 +50,8 @@ const LockBrew = createClass({ brewId : '', code : 1000, editMessage : '', - shareMessage : '' + shareMessage : '', + result : {} }; }, @@ -75,7 +76,7 @@ const LockBrew = createClass({ .send(newLock) .set('Content-Type', 'application/json') .then((response)=>{ - console.log(response.body); + this.setState({ result: response.body }); }); }, @@ -83,6 +84,23 @@ const LockBrew = createClass({ return this.handleChange(e, name)} autoComplete='off' required/>; }, + renderResult : function(){ + return <> +

Result:

+
+ + {Object.keys(this.state.result).map((key, idx)=>{ + return + + + ; + })} + +
{key}{this.state.result[key].toString()} +
+ ; + }, + render : function() { return
@@ -112,6 +130,7 @@ const LockBrew = createClass({ + {this.state.result && this.renderResult()}

Suggestions

From c594fc58b35ee76d00770e1a8d885523d29246fa Mon Sep 17 00:00:00 2001 From: "G.Ambatte" Date: Wed, 12 Jun 2024 21:47:52 +1200 Subject: [PATCH 044/398] Spread lock object in /lock response --- server/admin.api.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/admin.api.js b/server/admin.api.js index d02cdb67b..8f997aed9 100644 --- a/server/admin.api.js +++ b/server/admin.api.js @@ -179,7 +179,7 @@ router.post('/admin/lock/:id', mw.adminOnly, async (req, res)=>{ await brew.save(); // console.log(`Lock applied to brew ID ${brew.shareId} - ${brew.title}`); - return res.json({ status: 'LOCKED', detail: `Lock applied to brew ID ${brew.shareId} - ${brew.title}`, lock }); + return res.json({ status: 'LOCKED', detail: `Lock applied to brew ID ${brew.shareId} - ${brew.title}`, ...lock }); } catch (error) { console.error(error); return res.json({ status: 'ERROR', error, message: `Unable to set lock on brew ${req.params.id}` }); From fc99328459b1aec2df0aa90cb8890a23a112faa4 Mon Sep 17 00:00:00 2001 From: "G.Ambatte" Date: Wed, 12 Jun 2024 21:48:55 +1200 Subject: [PATCH 045/398] Tweak styling, remove obsolete locked property --- client/admin/lockTools/lockTools.jsx | 10 +++++----- client/admin/lockTools/lockTools.less | 6 ++++++ 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/client/admin/lockTools/lockTools.jsx b/client/admin/lockTools/lockTools.jsx index bf77be018..2135425eb 100644 --- a/client/admin/lockTools/lockTools.jsx +++ b/client/admin/lockTools/lockTools.jsx @@ -37,9 +37,11 @@ const LockTools = createClass({

- +
+ + +

-
; } }); @@ -68,8 +70,7 @@ const LockBrew = createClass({ code : parseInt(this.state.code) || 100, editMessage : this.state.editMessage, shareMessage : this.state.shareMessage, - applied : new Date, - locked : true + applied : new Date }; request.post(`/admin/lock/${this.state.brewId}`) @@ -204,7 +205,6 @@ const LockTable = createClass({ {this.state.result[this.props.resultName] && <>

Total Reviews Waiting: {this.state.result[this.props.resultName].length}

-

Click a row to copy the Share ID to the clipboard

diff --git a/client/admin/lockTools/lockTools.less b/client/admin/lockTools/lockTools.less index 272646ce2..d78462d35 100644 --- a/client/admin/lockTools/lockTools.less +++ b/client/admin/lockTools/lockTools.less @@ -49,4 +49,10 @@ padding: 4px 10px; text-align: center; } + + .brewLookup{ + h2 { + margin-top: 0px; + } + } } \ No newline at end of file From 7e8078767982710bd05285ff2138a0abd60b793d Mon Sep 17 00:00:00 2001 From: "G.Ambatte" Date: Wed, 12 Jun 2024 22:18:12 +1200 Subject: [PATCH 046/398] Tweak styling --- client/admin/lockTools/lockTools.less | 1 + 1 file changed, 1 insertion(+) diff --git a/client/admin/lockTools/lockTools.less b/client/admin/lockTools/lockTools.less index d78462d35..9bf2b39ef 100644 --- a/client/admin/lockTools/lockTools.less +++ b/client/admin/lockTools/lockTools.less @@ -51,6 +51,7 @@ } .brewLookup{ + min-height: 175px; h2 { margin-top: 0px; } From 0803362a504e5c2c4bacc8d58533cd598e8a54e0 Mon Sep 17 00:00:00 2001 From: "G.Ambatte" Date: Wed, 12 Jun 2024 22:29:47 +1200 Subject: [PATCH 047/398] More styling tweaks --- client/admin/lockTools/lockTools.less | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/client/admin/lockTools/lockTools.less b/client/admin/lockTools/lockTools.less index 9bf2b39ef..82341eddb 100644 --- a/client/admin/lockTools/lockTools.less +++ b/client/admin/lockTools/lockTools.less @@ -44,11 +44,13 @@ } } - td { - border: 1px solid #333333; + th, td { padding: 4px 10px; text-align: center; } + td{ + border: 1px solid #333333; + } .brewLookup{ min-height: 175px; From 7094d43ee5169d725b48e74a64cb8e9a821bbc1a Mon Sep 17 00:00:00 2001 From: "G.Ambatte" Date: Sat, 29 Jun 2024 15:29:02 +1200 Subject: [PATCH 048/398] Shift API calls to /api from /admin --- client/admin/lockTools/lockTools.jsx | 22 +++++++++++---------- client/homebrew/utils/request-middleware.js | 3 ++- server/admin.api.js | 10 +++++----- 3 files changed, 19 insertions(+), 16 deletions(-) diff --git a/client/admin/lockTools/lockTools.jsx b/client/admin/lockTools/lockTools.jsx index 2135425eb..31520b88c 100644 --- a/client/admin/lockTools/lockTools.jsx +++ b/client/admin/lockTools/lockTools.jsx @@ -3,7 +3,8 @@ require('./lockTools.less'); const React = require('react'); const createClass = require('create-react-class'); -const request = require('superagent'); +// const request = require('superagent'); +const request = require('../../homebrew/utils/request-middleware.js'); const LockTools = createClass({ getInitialState : function() { @@ -18,7 +19,7 @@ const LockTools = createClass({ }, updateReviewCount : async function() { - const newCount = await request.get('/admin/lock') + const newCount = await request.get('/api/lock/count') .then((res)=>{return res.body?.count || 'Unknown';}); if(newCount != this.state.reviewCount){ this.setState({ @@ -33,13 +34,13 @@ const LockTools = createClass({

Number of brews currently locked: {this.state.reviewCount}


- +

- - + +

; @@ -48,11 +49,12 @@ const LockTools = createClass({ const LockBrew = createClass({ getInitialState : function() { + // Default values return { brewId : '', - code : 1000, + code : 455, editMessage : '', - shareMessage : '', + shareMessage : 'This Brew has been locked.', result : {} }; }, @@ -73,7 +75,7 @@ const LockBrew = createClass({ applied : new Date }; - request.post(`/admin/lock/${this.state.brewId}`) + request.post(`/api/lock/${this.state.brewId}`) .send(newLock) .set('Content-Type', 'application/json') .then((response)=>{ @@ -167,7 +169,7 @@ const LockTable = createClass({ getDefaultProps : function() { return { title : '', - fetchURL : '/admin/locks', + fetchURL : '/api/locks', resultName : '', propertyNames : ['shareId'] }; @@ -236,7 +238,7 @@ const LockTable = createClass({ const LockLookup = createClass({ getDefaultProps : function() { return { - fetchURL : '/admin/lookup' + fetchURL : '/api/lookup' }; }, diff --git a/client/homebrew/utils/request-middleware.js b/client/homebrew/utils/request-middleware.js index f6bc2571b..80ee58f5d 100644 --- a/client/homebrew/utils/request-middleware.js +++ b/client/homebrew/utils/request-middleware.js @@ -1,6 +1,7 @@ const request = require('superagent'); +const version = require('../../../package.json').version; -const addHeader = (request)=>request.set('Homebrewery-Version', global.version); +const addHeader = (request)=>request.set('Homebrewery-Version', version); const requestMiddleware = { get : (path)=>addHeader(request.get(path)), diff --git a/server/admin.api.js b/server/admin.api.js index 8f997aed9..1bf597bb4 100644 --- a/server/admin.api.js +++ b/server/admin.api.js @@ -139,7 +139,7 @@ router.get('/admin/stats', mw.adminOnly, async (req, res)=>{ } }); -router.get('/admin/lock', mw.adminOnly, async (req, res)=>{ +router.get('/api/lock/count', mw.adminOnly, async (req, res)=>{ try { const countLocksQuery = { lock : { $exists: true } @@ -157,7 +157,7 @@ router.get('/admin/lock', mw.adminOnly, async (req, res)=>{ } }); -router.post('/admin/lock/:id', mw.adminOnly, async (req, res)=>{ +router.post('/api/lock/:id', mw.adminOnly, async (req, res)=>{ try { const lock = req.body; lock.applied = new Date; @@ -186,7 +186,7 @@ router.post('/admin/lock/:id', mw.adminOnly, async (req, res)=>{ } }); -router.put('/admin/unlock/:id', mw.adminOnly, async (req, res)=>{ +router.put('/api/unlock/:id', mw.adminOnly, async (req, res)=>{ try { const filter = { shareId : req.params.id @@ -210,7 +210,7 @@ router.put('/admin/unlock/:id', mw.adminOnly, async (req, res)=>{ return res.json({ status: 'UNLOCKED', detail: `Lock removed from brew ID ${req.params.id}` }); }); -router.get('/admin/lock/reviews', mw.adminOnly, async (req, res)=>{ +router.get('/api/lock/reviews', mw.adminOnly, async (req, res)=>{ try { const countReviewsPipeline = [ { @@ -260,7 +260,7 @@ router.put('/admin/lock/review/request/:id', async (req, res)=>{ } }); -router.put('/admin/lock/review/remove/:id', mw.adminOnly, async (req, res)=>{ +router.put('/api/lock/review/remove/:id', mw.adminOnly, async (req, res)=>{ try { const filter = { shareId : req.params.id, From b0687493803eda0e8500a8223c2d34ec01b141ec Mon Sep 17 00:00:00 2001 From: "G.Ambatte" Date: Thu, 25 Jul 2024 22:11:14 +1200 Subject: [PATCH 049/398] Move copy ID to clipboard to separate button --- client/admin/lockTools/lockTools.jsx | 7 +++++-- client/admin/lockTools/lockTools.less | 10 +++++++++- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/client/admin/lockTools/lockTools.jsx b/client/admin/lockTools/lockTools.jsx index 31520b88c..b5c94399a 100644 --- a/client/admin/lockTools/lockTools.jsx +++ b/client/admin/lockTools/lockTools.jsx @@ -207,23 +207,26 @@ const LockTable = createClass({ {this.state.result[this.props.resultName] && <>

Total Reviews Waiting: {this.state.result[this.props.resultName].length}

-

Click a row to copy the Share ID to the clipboard

{this.props.propertyNames.map((name, idx)=>{ return ; })} + + {this.state.result[this.props.resultName].map((result, resultIdx)=>{ - return {navigator.clipboard.writeText(result.shareId.toString());}}> + return {this.props.propertyNames.map((name, nameIdx)=>{ return ; })} + + ; })} diff --git a/client/admin/lockTools/lockTools.less b/client/admin/lockTools/lockTools.less index 82341eddb..5737a32e0 100644 --- a/client/admin/lockTools/lockTools.less +++ b/client/admin/lockTools/lockTools.less @@ -39,8 +39,16 @@ } .lockTable{ - td:hover { + cursor: default; + .row:hover { + background-color: #ccc; + color: #000; + } + .icon { cursor: pointer; + &:hover{ + text-shadow: 0px 0px 6px black; + } } } From fd5ff2c61a38137ec956491a7e31a8bf2ab7287b Mon Sep 17 00:00:00 2001 From: David Bolack Date: Fri, 23 Aug 2024 14:04:04 -0500 Subject: [PATCH 050/398] Relocate more general purposes snippets from 5ePHB to Blank Should include all supporting style content. --- themes/V3/5ePHB/snippets.js | 128 ------------------ themes/V3/Blank/snippets.js | 73 +++++++++- .../V3/{5ePHB => Blank}/snippets/index.gen.js | 0 .../snippets/tableOfContents.gen.js | 0 themes/V3/Blank/style.less | 127 +++++++++++++++++ 5 files changed, 199 insertions(+), 129 deletions(-) rename themes/V3/{5ePHB => Blank}/snippets/index.gen.js (100%) rename themes/V3/{5ePHB => Blank}/snippets/tableOfContents.gen.js (100%) diff --git a/themes/V3/5ePHB/snippets.js b/themes/V3/5ePHB/snippets.js index 4daa05c51..f5c8120c1 100644 --- a/themes/V3/5ePHB/snippets.js +++ b/themes/V3/5ePHB/snippets.js @@ -6,138 +6,13 @@ const MonsterBlockGen = require('./snippets/monsterblock.gen.js'); const scriptGen = require('./snippets/script.gen.js'); const ClassFeatureGen = require('./snippets/classfeature.gen.js'); const CoverPageGen = require('./snippets/coverpage.gen.js'); -const TableOfContentsGen = require('./snippets/tableOfContents.gen.js'); -const indexGen = require('./snippets/index.gen.js'); const QuoteGen = require('./snippets/quote.gen.js'); const dedent = require('dedent-tabs').default; module.exports = [ - - { - groupName : 'Text Editor', - icon : 'fas fa-pencil-alt', - view : 'text', - snippets : [ - { - name : 'Table of Contents', - icon : 'fas fa-book', - gen : TableOfContentsGen, - experimental : true, - subsnippets : [ - { - name : 'Table of Contents', - icon : 'fas fa-book', - gen : TableOfContentsGen, - experimental : true - }, - { - name : 'Include in ToC up to H3', - icon : 'fas fa-dice-three', - gen : dedent `\n{{tocDepthH3 - }}\n`, - - }, - { - name : 'Include in ToC up to H4', - icon : 'fas fa-dice-four', - gen : dedent `\n{{tocDepthH4 - }}\n`, - }, - { - name : 'Include in ToC up to H5', - icon : 'fas fa-dice-five', - gen : dedent `\n{{tocDepthH5 - }}\n`, - }, - { - name : 'Include in ToC up to H6', - icon : 'fas fa-dice-six', - gen : dedent `\n{{tocDepthH6 - }}\n`, - } - ] - }, - { - name : 'Index', - icon : 'fas fa-bars', - gen : indexGen, - experimental : true - } - ] - }, - { - groupName : 'Style Editor', - icon : 'fas fa-pencil-alt', - view : 'style', - snippets : [ - { - name : 'Remove Drop Cap', - icon : 'fas fa-remove-format', - gen : dedent`/* Removes Drop Caps */ - .page h1+p:first-letter { - all: unset; - }\n\n - /* Removes Small-Caps in first line */ - .page h1+p:first-line { - all: unset; - }` - }, - { - name : 'Tweak Drop Cap', - icon : 'fas fa-sliders-h', - gen : dedent`/* Drop Cap settings */ - .page h1 + p::first-letter { - font-family: SolberaImitationRemake; - font-size: 3.5cm; - background-image: linear-gradient(-45deg, #322814, #998250, #322814); - line-height: 1em; - }\n\n` - } - ] - }, - - /*********************** IMAGES *******************/ - { - groupName : 'Images', - icon : 'fas fa-images', - view : 'text', - snippets : [ - { - name : 'Image', - icon : 'fas fa-image', - gen : dedent` - ![cat warrior](https://s-media-cache-ak0.pinimg.com/736x/4a/81/79/4a8179462cfdf39054a418efd4cb743e.jpg) {width:325px,mix-blend-mode:multiply} - - {{artist,position:relative,top:-230px,left:10px,margin-bottom:-30px - ##### Cat Warrior - [Kyoung Hwan Kim](https://www.artstation.com/tahra) - }}` - }, - { - name : 'Background Image', - icon : 'fas fa-tree', - gen : dedent` - ![homebrew mug](http://i.imgur.com/hMna6G0.png) {position:absolute,top:50px,right:30px,width:280px} - - {{artist,top:80px,right:30px - ##### Homebrew Mug - [naturalcrit](https://homebrew.naturalcrit.com) - }}` - }, - { - name : 'Watermark', - icon : 'fas fa-id-card', - gen : dedent` - {{watermark Homebrewery}}\n` - }, - ] - }, - - /************************* PHB ********************/ - { groupName : 'PHB', icon : 'fas fa-book', @@ -332,9 +207,6 @@ module.exports = [ ] }, - - - /**************** PAGE *************/ { diff --git a/themes/V3/Blank/snippets.js b/themes/V3/Blank/snippets.js index 8d45560c5..b30412bd0 100644 --- a/themes/V3/Blank/snippets.js +++ b/themes/V3/Blank/snippets.js @@ -4,6 +4,8 @@ const WatercolorGen = require('./snippets/watercolor.gen.js'); const ImageMaskGen = require('./snippets/imageMask.gen.js'); const FooterGen = require('./snippets/footer.gen.js'); const dedent = require('dedent-tabs').default; +const TableOfContentsGen = require('./snippets/tableOfContents.gen.js'); +const indexGen = require('./snippets/index.gen.js'); module.exports = [ @@ -125,7 +127,53 @@ module.exports = [ [Homebrewery.Naturalcrit.com](https://homebrewery.naturalcrit.com) }}\n\n`; }, - } + }, + { + name : 'Table of Contents', + icon : 'fas fa-book', + gen : TableOfContentsGen, + experimental : true, + subsnippets : [ + { + name : 'Table of Contents', + icon : 'fas fa-book', + gen : TableOfContentsGen, + experimental : true + }, + { + name : 'Include in ToC up to H3', + icon : 'fas fa-dice-three', + gen : dedent `\n{{tocDepthH3 + }}\n`, + + }, + { + name : 'Include in ToC up to H4', + icon : 'fas fa-dice-four', + gen : dedent `\n{{tocDepthH4 + }}\n`, + }, + { + name : 'Include in ToC up to H5', + icon : 'fas fa-dice-five', + gen : dedent `\n{{tocDepthH5 + }}\n`, + }, + { + name : 'Include in ToC up to H6', + icon : 'fas fa-dice-six', + gen : dedent `\n{{tocDepthH6 + }}\n`, + } + ] + }, + { + name : 'Index', + icon : 'fas fa-bars', + gen : indexGen, + experimental : true + }, + ] }, { @@ -138,6 +186,29 @@ module.exports = [ icon : 'fas fa-code', gen : '/* This is a comment that will not be rendered into your brew. */' }, + { + name : 'Remove Drop Cap', + icon : 'fas fa-remove-format', + gen : dedent`/* Removes Drop Caps */ + .page h1+p:first-letter { + all: unset; + }\n\n + /* Removes Small-Caps in first line */ + .page h1+p:first-line { + all: unset; + }` + }, + { + name : 'Tweak Drop Cap', + icon : 'fas fa-sliders-h', + gen : dedent`/* Drop Cap settings */ + .page h1 + p::first-letter { + font-family: SolberaImitationRemake; + font-size: 3.5cm; + background-image: linear-gradient(-45deg, #322814, #998250, #322814); + line-height: 1em; + }\n\n` + }, ] }, diff --git a/themes/V3/5ePHB/snippets/index.gen.js b/themes/V3/Blank/snippets/index.gen.js similarity index 100% rename from themes/V3/5ePHB/snippets/index.gen.js rename to themes/V3/Blank/snippets/index.gen.js diff --git a/themes/V3/5ePHB/snippets/tableOfContents.gen.js b/themes/V3/Blank/snippets/tableOfContents.gen.js similarity index 100% rename from themes/V3/5ePHB/snippets/tableOfContents.gen.js rename to themes/V3/Blank/snippets/tableOfContents.gen.js diff --git a/themes/V3/Blank/style.less b/themes/V3/Blank/style.less index 18a478cf9..4b0653f4b 100644 --- a/themes/V3/Blank/style.less +++ b/themes/V3/Blank/style.less @@ -482,3 +482,130 @@ body { counter-reset : page-numbers; } .pageNumber { left : 30px; } } } + +// ***************************** +// * INDEX +// *****************************/ +.page { + .index { + font-size : 0.218cm; + + ul ul { margin : 0; } + + ul { + padding-left : 0; + text-indent : 0; + list-style-type : none; + } + + & > ul > li { + padding-left : 1.5em; + text-indent : -1.5em; + } + } +} + +// ***************************** +// * TABLE OF CONTENTS +// *****************************/ + +// Default Exclusions +// Anything not exlcuded is included, default Headers are H1, H2, and H3. +h4, +h5, +h6, +.page:has(.frontCover), +.page:has(.backCover), +.page:has(.insideCover), +.monster, +.noToC, +.toc { --TOC: exclude; } + +.tocDepthH2 :is(h1, h2) {--TOC: include; } +.tocDepthH3 :is(h1, h2, h3) {--TOC: include; } +.tocDepthH4 :is(h1, h2, h3, h4) {--TOC: include; } +.tocDepthH5 :is(h1, h2, h3, h4, h5) {--TOC: include; } +.tocDepthH6 :is(h1, h2, h3, h4, h5, h6) {--TOC: include; } + +.tocIncludeH1 h1 {--TOC: include; } +.tocIncludeH2 h2 {--TOC: include; } +.tocIncludeH3 h3 {--TOC: include; } +.tocIncludeH4 h4 {--TOC: include; } +.tocIncludeH5 h5 {--TOC: include; } +.tocIncludeH6 h6 {--TOC: include; } + +.page:has(.partCover) { + --TOC: exclude; + & h1 { + --TOC: include; + } + } + +.page { + &:has(.toc)::after { display : none; } + .toc { + -webkit-column-break-inside : avoid; + page-break-inside : avoid; + break-inside : avoid; + h1 { + margin-bottom : 0.3cm; + text-align : center; + } + a { + display : inline; + color : inherit; + text-decoration : none; + &:hover { text-decoration : underline; } + } + h4 { + margin-top : 0.2cm; + line-height : 0.4cm; + & + ul li { line-height : 1.2em; } + } + ul { + padding-left : 0; + margin-top : 0; + list-style-type : none; + a { + display : flex; + flex-flow : row nowrap; + justify-content : space-between; + width : 100%; + } + li + li h3 { + margin-top : 0.26cm; + line-height : 1em; + } + h3 span:first-child::after { border : none; } + span { + display : contents; + &:first-child::after { + bottom : 0.08cm; + flex : 1; + margin-right : 0.16cm; + margin-bottom : 0.08cm; + margin-left : 0.08cm; /* Spacing before dot leaders */ + content : ''; + border-bottom : 0.05cm dotted #000000; + } + &:last-child { + display : inline-block; + align-self : flex-end; + font-family : 'BookInsanityRemake'; + font-size : 0.34cm; + font-weight : normal; + color : #000000; + } + } + ul { /* List indent */ + margin-left : 1em; + } + } + &.wide { + .useColumns(0.96, @fillMode: balance); + } + } + .toc.wide li { + break-inside: auto; + } +} From 2c573bfef5dee6829418318c99822c223af0cc8e Mon Sep 17 00:00:00 2001 From: David Bolack Date: Fri, 23 Aug 2024 14:18:58 -0500 Subject: [PATCH 051/398] Failed to save one file's changes. --- themes/V3/5ePHB/style.less | 126 ------------------------------------- 1 file changed, 126 deletions(-) diff --git a/themes/V3/5ePHB/style.less b/themes/V3/5ePHB/style.less index ddffbec2f..e4bbb3514 100644 --- a/themes/V3/5ePHB/style.less +++ b/themes/V3/5ePHB/style.less @@ -792,111 +792,6 @@ } } -// ***************************** -// * TABLE OF CONTENTS -// *****************************/ - -// Default Exclusions -// Anything not exlcuded is included, default Headers are H1, H2, and H3. -h4, -h5, -h6, -.page:has(.frontCover), -.page:has(.backCover), -.page:has(.insideCover), -.monster, -.noToC, -.toc { --TOC: exclude; } - -.tocDepthH2 :is(h1, h2) {--TOC: include; } -.tocDepthH3 :is(h1, h2, h3) {--TOC: include; } -.tocDepthH4 :is(h1, h2, h3, h4) {--TOC: include; } -.tocDepthH5 :is(h1, h2, h3, h4, h5) {--TOC: include; } -.tocDepthH6 :is(h1, h2, h3, h4, h5, h6) {--TOC: include; } - -.tocIncludeH1 h1 {--TOC: include; } -.tocIncludeH2 h2 {--TOC: include; } -.tocIncludeH3 h3 {--TOC: include; } -.tocIncludeH4 h4 {--TOC: include; } -.tocIncludeH5 h5 {--TOC: include; } -.tocIncludeH6 h6 {--TOC: include; } - -.page:has(.partCover) { - --TOC: exclude; - & h1 { - --TOC: include; - } - } - -.page { - &:has(.toc)::after { display : none; } - .toc { - -webkit-column-break-inside : avoid; - page-break-inside : avoid; - break-inside : avoid; - h1 { - margin-bottom : 0.3cm; - text-align : center; - } - a { - display : inline; - color : inherit; - text-decoration : none; - &:hover { text-decoration : underline; } - } - h4 { - margin-top : 0.2cm; - line-height : 0.4cm; - & + ul li { line-height : 1.2em; } - } - ul { - padding-left : 0; - margin-top : 0; - list-style-type : none; - a { - display : flex; - flex-flow : row nowrap; - justify-content : space-between; - width : 100%; - } - li + li h3 { - margin-top : 0.26cm; - line-height : 1em; - } - h3 span:first-child::after { border : none; } - span { - display : contents; - &:first-child::after { - bottom : 0.08cm; - flex : 1; - margin-right : 0.16cm; - margin-bottom : 0.08cm; - margin-left : 0.08cm; /* Spacing before dot leaders */ - content : ''; - border-bottom : 0.05cm dotted #000000; - } - &:last-child { - display : inline-block; - align-self : flex-end; - font-family : 'BookInsanityRemake'; - font-size : 0.34cm; - font-weight : normal; - color : #000000; - } - } - ul { /* List indent */ - margin-left : 1em; - } - } - &.wide { - .useColumns(0.96, @fillMode: balance); - } - } - .toc.wide li { - break-inside: auto; - } -} - // ***************************** // * DEFINITION LISTS // *****************************/ @@ -958,24 +853,3 @@ h6, } } } -// ***************************** -// * INDEX -// *****************************/ -.page { - .index { - font-size : 0.218cm; - - ul ul { margin : 0; } - - ul { - padding-left : 0; - text-indent : 0; - list-style-type : none; - } - - & > ul > li { - padding-left : 1.5em; - text-indent : -1.5em; - } - } -} From ad1dfc8e2bc10f82f581c3267882df2cc1545235 Mon Sep 17 00:00:00 2001 From: David Bolack Date: Fri, 23 Aug 2024 16:52:35 -0500 Subject: [PATCH 052/398] Move Page styles ( cover Page, etc ) to Blank from 5ePHB --- themes/V3/5ePHB/style.less | 264 ------------------------------------ themes/V3/Blank/style.less | 265 +++++++++++++++++++++++++++++++++++++ 2 files changed, 265 insertions(+), 264 deletions(-) diff --git a/themes/V3/5ePHB/style.less b/themes/V3/5ePHB/style.less index e4bbb3514..e33a0b2be 100644 --- a/themes/V3/5ePHB/style.less +++ b/themes/V3/5ePHB/style.less @@ -538,259 +538,6 @@ } h5 + table { margin-top : 0.2cm; } } -// ***************************** -// * FRONT COVER PAGE -// *****************************/ -.page:has(.frontCover) { - columns : 1; - text-align : center; - &::after { display : none; } - h1 { - margin-top : 1.2cm; - margin-bottom : 0; - font-family : 'NodestoCapsCondensed'; - font-size : 2.245cm; - font-weight : normal; - line-height : 1.9cm; - color : white; - text-shadow : unset; - text-transform : uppercase; - -webkit-text-stroke: 0.2cm black; - paint-order:stroke; - } - h2 { - font-family : 'NodestoCapsCondensed'; - font-size : 0.85cm; - font-weight : normal; - color : white; - letter-spacing : 0.1cm; - -webkit-text-stroke: 0.14cm black; - paint-order:stroke; - } - hr { - position : relative; - display : block; - width : 12cm; - height : 0.5cm; - margin : auto; - visibility : visible; - background-image : @horizontalRule; - filter : drop-shadow(0 0 3px black); - background-size : 100% 100%; - border : none; - } - .banner { - position : absolute; - bottom : 4.2cm; - left : 0; - display : flex; - flex-direction : column; - justify-content : center; - width : 10.5cm; - height : 1.7cm; - padding-top : 0.1cm; - padding-left : 1cm; - font-family : 'NodestoCapsCondensed'; - font-size : 1cm; - font-weight : normal; - color : white; - text-align : left; - letter-spacing : 0.014cm; - background-image : url('/assets/coverPageBanner.svg'); - filter : drop-shadow(2px 2px 2px black); - } - .footnote { - position : absolute; - right : 0; - bottom : 1.3cm; - left : 0; - width : 70%; - margin-right : auto; - margin-left : auto; - font-family : 'Overpass'; - font-size : 0.496cm; - color : white; - text-align : center; - -webkit-text-stroke: 0.1cm black; - paint-order:stroke; - } - .logo { - position : absolute; - top : 0.5cm; - right : 0; - left : 0; - filter : drop-shadow(0 0 0.075cm black); - img { - width : 100%; - height : 2cm; - } - } -} -// ***************************** -// * INSIDE COVER PAGE -// *****************************/ -.page:has(.insideCover) { - columns : 1; - text-align : center; - &::after { display : none; } - h1 { - margin-top : 1.2cm; - margin-bottom : 0; - font-family : 'NodestoCapsCondensed'; - font-size : 2.1cm; - font-weight : normal; - line-height : 1.785cm; - text-transform : uppercase; - } - h2 { - font-family : 'NodestoCapsCondensed'; - font-size : 0.85cm; - font-weight : normal; - letter-spacing : 0.5cm; - } - hr { - position : relative; - display : block; - width : 12cm; - height : 0.5cm; - margin : auto; - visibility : visible; - background-image : @horizontalRule; - background-size : 100% 100%; - border : none; - } - .logo { - position : absolute; - right : 0; - bottom : 1cm; - left : 0; - height : 2cm; - img { - width : 100%; - height : 2cm; - } - } -} -// ***************************** -// * BACK COVER -// *****************************/ -.page:has(.backCover) { - padding : 2.25cm 1.3cm 2cm 1.3cm; - color : #FFFFFF; - columns : 1; - &::after { display : none; } - .columnWrapper { width : 7.6cm; } - .backCover { - position : absolute; - inset : 0; - z-index : -1; - width : 11cm; - background-image : @backCover; - background-repeat : no-repeat; - background-size : contain; - } - .blank { height : 1.4em; } - h1 { - margin-bottom : 0.3cm; - font-family : 'NodestoCapsCondensed'; - font-size : 1.35cm; - line-height : 1.28cm; - color : #ED1C24; - text-align : center; - } - h1 + p::first-line, - h1 + p::first-letter { all : unset; } - img { - position : absolute; - top : 0px; - z-index : -2; - height : 100%; - } - hr { - width : 4.5cm; - height : 0.53cm; - margin-top : 1.1cm; - margin-right : auto; - margin-left : auto; - visibility : visible; - background-image : @horizontalRule; - background-size : 100% 100%; - border : none; - } - p { - font-family : 'Overpass'; - font-size : 0.332cm; - line-height : 0.35cm; - } - hr + p { - margin-top : 0.6cm; - text-align : center; - } - .logo { - position : absolute; - bottom : 2cm; - left : 1.2cm; - z-index : 0; - width : 7.6cm; - height : 1.5cm; - img { - position : relative; - z-index : 0; - width : 100%; - height : 1.5cm; - } - p { - position : relative; - width : 100%; - font-family : 'NodestoCapsWide'; - font-size : 0.4cm; - line-height : 1em; - line-height : 1.28cm; - color : #FFFFFF; - text-align : center; - text-indent : 0; - } - } -} - -// ***************************** -// * PART COVER -// *****************************/ -.page:has(.partCover) { - padding-top : 0; - text-align : center; - columns : 1; - - .partCover { - position : absolute; - top : 0; - left : 0; - width : 100%; - height : 6cm; - background-image : @partCoverHeaderPHB; - background-repeat : no-repeat; - background-size : 100%; - } - - h1 { - position : relative; - margin-top : 0.4cm; - font-family : 'NodestoCapsCondensed'; - font-size : 2.3cm; - text-align : center; - text-transform : uppercase; - } - - h2 { - position : relative; - margin-top : -0.7em; - margin-right : auto; - margin-left : auto; - font-family : 'Overpass'; - font-size : 0.45cm; - line-height : 0.495cm; - } -} // ***************************** // * DEFINITION LISTS @@ -807,17 +554,6 @@ } } -// ***************************** -// * WIDE -// *****************************/ -.page .wide { margin-bottom : 0.325cm; } - -.page h1 + * { margin-top : 0; } - -.page .descriptive.wide + * { - margin-top: 0; -} - //***************************** // * RUNE TABLE // *****************************/ diff --git a/themes/V3/Blank/style.less b/themes/V3/Blank/style.less index 4b0653f4b..791ebce73 100644 --- a/themes/V3/Blank/style.less +++ b/themes/V3/Blank/style.less @@ -609,3 +609,268 @@ h6, break-inside: auto; } } + +// ***************************** +// * WIDE +// *****************************/ +.page .wide { margin-bottom : 0.325cm; } + +.page h1 + * { margin-top : 0; } + +.page .descriptive.wide + * { + margin-top: 0; +} + +// ***************************** +// * FRONT COVER PAGE +// *****************************/ +.page:has(.frontCover) { + columns : 1; + text-align : center; + &::after { display : none; } + h1 { + margin-top : 1.2cm; + margin-bottom : 0; + font-family : 'NodestoCapsCondensed'; + font-size : 2.245cm; + font-weight : normal; + line-height : 1.9cm; + color : white; + text-shadow : unset; + text-transform : uppercase; + -webkit-text-stroke: 0.2cm black; + paint-order:stroke; + } + h2 { + font-family : 'NodestoCapsCondensed'; + font-size : 0.85cm; + font-weight : normal; + color : white; + letter-spacing : 0.1cm; + -webkit-text-stroke: 0.14cm black; + paint-order:stroke; + } + hr { + position : relative; + display : block; + width : 12cm; + height : 0.5cm; + margin : auto; + visibility : visible; + background-image : @horizontalRule; + filter : drop-shadow(0 0 3px black); + background-size : 100% 100%; + border : none; + } + .banner { + position : absolute; + bottom : 4.2cm; + left : 0; + display : flex; + flex-direction : column; + justify-content : center; + width : 10.5cm; + height : 1.7cm; + padding-top : 0.1cm; + padding-left : 1cm; + font-family : 'NodestoCapsCondensed'; + font-size : 1cm; + font-weight : normal; + color : white; + text-align : left; + letter-spacing : 0.014cm; + background-image : url('/assets/coverPageBanner.svg'); + filter : drop-shadow(2px 2px 2px black); + } + .footnote { + position : absolute; + right : 0; + bottom : 1.3cm; + left : 0; + width : 70%; + margin-right : auto; + margin-left : auto; + font-family : 'Overpass'; + font-size : 0.496cm; + color : white; + text-align : center; + -webkit-text-stroke: 0.1cm black; + paint-order:stroke; + } + .logo { + position : absolute; + top : 0.5cm; + right : 0; + left : 0; + filter : drop-shadow(0 0 0.075cm black); + img { + width : 100%; + height : 2cm; + } + } +} +// ***************************** +// * INSIDE COVER PAGE +// *****************************/ +.page:has(.insideCover) { + columns : 1; + text-align : center; + &::after { display : none; } + h1 { + margin-top : 1.2cm; + margin-bottom : 0; + font-family : 'NodestoCapsCondensed'; + font-size : 2.1cm; + font-weight : normal; + line-height : 1.785cm; + text-transform : uppercase; + } + h2 { + font-family : 'NodestoCapsCondensed'; + font-size : 0.85cm; + font-weight : normal; + letter-spacing : 0.5cm; + } + hr { + position : relative; + display : block; + width : 12cm; + height : 0.5cm; + margin : auto; + visibility : visible; + background-image : @horizontalRule; + background-size : 100% 100%; + border : none; + } + .logo { + position : absolute; + right : 0; + bottom : 1cm; + left : 0; + height : 2cm; + img { + width : 100%; + height : 2cm; + } + } +} +// ***************************** +// * BACK COVER +// *****************************/ +.page:has(.backCover) { + padding : 2.25cm 1.3cm 2cm 1.3cm; + color : #FFFFFF; + columns : 1; + &::after { display : none; } + .columnWrapper { width : 7.6cm; } + .backCover { + position : absolute; + inset : 0; + z-index : -1; + width : 11cm; + background-image : @backCover; + background-repeat : no-repeat; + background-size : contain; + } + .blank { height : 1.4em; } + h1 { + margin-bottom : 0.3cm; + font-family : 'NodestoCapsCondensed'; + font-size : 1.35cm; + line-height : 1.28cm; + color : #ED1C24; + text-align : center; + } + h1 + p::first-line, + h1 + p::first-letter { all : unset; } + img { + position : absolute; + top : 0px; + z-index : -2; + height : 100%; + } + hr { + width : 4.5cm; + height : 0.53cm; + margin-top : 1.1cm; + margin-right : auto; + margin-left : auto; + visibility : visible; + background-image : @horizontalRule; + background-size : 100% 100%; + border : none; + } + p { + font-family : 'Overpass'; + font-size : 0.332cm; + line-height : 0.35cm; + } + hr + p { + margin-top : 0.6cm; + text-align : center; + } + .logo { + position : absolute; + bottom : 2cm; + left : 1.2cm; + z-index : 0; + width : 7.6cm; + height : 1.5cm; + img { + position : relative; + z-index : 0; + width : 100%; + height : 1.5cm; + } + p { + position : relative; + width : 100%; + font-family : 'NodestoCapsWide'; + font-size : 0.4cm; + line-height : 1em; + line-height : 1.28cm; + color : #FFFFFF; + text-align : center; + text-indent : 0; + } + } +} + +// ***************************** +// * PART COVER +// *****************************/ +.page:has(.partCover) { + padding-top : 0; + text-align : center; + columns : 1; + + .partCover { + position : absolute; + top : 0; + left : 0; + width : 100%; + height : 6cm; + background-image : @partCoverHeaderPHB; + background-repeat : no-repeat; + background-size : 100%; + } + + h1 { + position : relative; + margin-top : 0.4cm; + font-family : 'NodestoCapsCondensed'; + font-size : 2.3cm; + text-align : center; + text-transform : uppercase; + } + + h2 { + position : relative; + margin-top : -0.7em; + margin-right : auto; + margin-left : auto; + font-family : 'Overpass'; + font-size : 0.45cm; + line-height : 0.495cm; + } +} From a3c01305df17b78d860de1d0c407941103516393 Mon Sep 17 00:00:00 2001 From: David Bolack Date: Sun, 25 Aug 2024 19:15:57 -0500 Subject: [PATCH 053/398] Revert "Move Page styles ( cover Page, etc ) to Blank from 5ePHB" This reverts commit ad1dfc8e2bc10f82f581c3267882df2cc1545235. --- themes/V3/5ePHB/style.less | 264 ++++++++++++++++++++++++++++++++++++ themes/V3/Blank/style.less | 265 ------------------------------------- 2 files changed, 264 insertions(+), 265 deletions(-) diff --git a/themes/V3/5ePHB/style.less b/themes/V3/5ePHB/style.less index e33a0b2be..e4bbb3514 100644 --- a/themes/V3/5ePHB/style.less +++ b/themes/V3/5ePHB/style.less @@ -538,6 +538,259 @@ } h5 + table { margin-top : 0.2cm; } } +// ***************************** +// * FRONT COVER PAGE +// *****************************/ +.page:has(.frontCover) { + columns : 1; + text-align : center; + &::after { display : none; } + h1 { + margin-top : 1.2cm; + margin-bottom : 0; + font-family : 'NodestoCapsCondensed'; + font-size : 2.245cm; + font-weight : normal; + line-height : 1.9cm; + color : white; + text-shadow : unset; + text-transform : uppercase; + -webkit-text-stroke: 0.2cm black; + paint-order:stroke; + } + h2 { + font-family : 'NodestoCapsCondensed'; + font-size : 0.85cm; + font-weight : normal; + color : white; + letter-spacing : 0.1cm; + -webkit-text-stroke: 0.14cm black; + paint-order:stroke; + } + hr { + position : relative; + display : block; + width : 12cm; + height : 0.5cm; + margin : auto; + visibility : visible; + background-image : @horizontalRule; + filter : drop-shadow(0 0 3px black); + background-size : 100% 100%; + border : none; + } + .banner { + position : absolute; + bottom : 4.2cm; + left : 0; + display : flex; + flex-direction : column; + justify-content : center; + width : 10.5cm; + height : 1.7cm; + padding-top : 0.1cm; + padding-left : 1cm; + font-family : 'NodestoCapsCondensed'; + font-size : 1cm; + font-weight : normal; + color : white; + text-align : left; + letter-spacing : 0.014cm; + background-image : url('/assets/coverPageBanner.svg'); + filter : drop-shadow(2px 2px 2px black); + } + .footnote { + position : absolute; + right : 0; + bottom : 1.3cm; + left : 0; + width : 70%; + margin-right : auto; + margin-left : auto; + font-family : 'Overpass'; + font-size : 0.496cm; + color : white; + text-align : center; + -webkit-text-stroke: 0.1cm black; + paint-order:stroke; + } + .logo { + position : absolute; + top : 0.5cm; + right : 0; + left : 0; + filter : drop-shadow(0 0 0.075cm black); + img { + width : 100%; + height : 2cm; + } + } +} +// ***************************** +// * INSIDE COVER PAGE +// *****************************/ +.page:has(.insideCover) { + columns : 1; + text-align : center; + &::after { display : none; } + h1 { + margin-top : 1.2cm; + margin-bottom : 0; + font-family : 'NodestoCapsCondensed'; + font-size : 2.1cm; + font-weight : normal; + line-height : 1.785cm; + text-transform : uppercase; + } + h2 { + font-family : 'NodestoCapsCondensed'; + font-size : 0.85cm; + font-weight : normal; + letter-spacing : 0.5cm; + } + hr { + position : relative; + display : block; + width : 12cm; + height : 0.5cm; + margin : auto; + visibility : visible; + background-image : @horizontalRule; + background-size : 100% 100%; + border : none; + } + .logo { + position : absolute; + right : 0; + bottom : 1cm; + left : 0; + height : 2cm; + img { + width : 100%; + height : 2cm; + } + } +} +// ***************************** +// * BACK COVER +// *****************************/ +.page:has(.backCover) { + padding : 2.25cm 1.3cm 2cm 1.3cm; + color : #FFFFFF; + columns : 1; + &::after { display : none; } + .columnWrapper { width : 7.6cm; } + .backCover { + position : absolute; + inset : 0; + z-index : -1; + width : 11cm; + background-image : @backCover; + background-repeat : no-repeat; + background-size : contain; + } + .blank { height : 1.4em; } + h1 { + margin-bottom : 0.3cm; + font-family : 'NodestoCapsCondensed'; + font-size : 1.35cm; + line-height : 1.28cm; + color : #ED1C24; + text-align : center; + } + h1 + p::first-line, + h1 + p::first-letter { all : unset; } + img { + position : absolute; + top : 0px; + z-index : -2; + height : 100%; + } + hr { + width : 4.5cm; + height : 0.53cm; + margin-top : 1.1cm; + margin-right : auto; + margin-left : auto; + visibility : visible; + background-image : @horizontalRule; + background-size : 100% 100%; + border : none; + } + p { + font-family : 'Overpass'; + font-size : 0.332cm; + line-height : 0.35cm; + } + hr + p { + margin-top : 0.6cm; + text-align : center; + } + .logo { + position : absolute; + bottom : 2cm; + left : 1.2cm; + z-index : 0; + width : 7.6cm; + height : 1.5cm; + img { + position : relative; + z-index : 0; + width : 100%; + height : 1.5cm; + } + p { + position : relative; + width : 100%; + font-family : 'NodestoCapsWide'; + font-size : 0.4cm; + line-height : 1em; + line-height : 1.28cm; + color : #FFFFFF; + text-align : center; + text-indent : 0; + } + } +} + +// ***************************** +// * PART COVER +// *****************************/ +.page:has(.partCover) { + padding-top : 0; + text-align : center; + columns : 1; + + .partCover { + position : absolute; + top : 0; + left : 0; + width : 100%; + height : 6cm; + background-image : @partCoverHeaderPHB; + background-repeat : no-repeat; + background-size : 100%; + } + + h1 { + position : relative; + margin-top : 0.4cm; + font-family : 'NodestoCapsCondensed'; + font-size : 2.3cm; + text-align : center; + text-transform : uppercase; + } + + h2 { + position : relative; + margin-top : -0.7em; + margin-right : auto; + margin-left : auto; + font-family : 'Overpass'; + font-size : 0.45cm; + line-height : 0.495cm; + } +} // ***************************** // * DEFINITION LISTS @@ -554,6 +807,17 @@ } } +// ***************************** +// * WIDE +// *****************************/ +.page .wide { margin-bottom : 0.325cm; } + +.page h1 + * { margin-top : 0; } + +.page .descriptive.wide + * { + margin-top: 0; +} + //***************************** // * RUNE TABLE // *****************************/ diff --git a/themes/V3/Blank/style.less b/themes/V3/Blank/style.less index 791ebce73..4b0653f4b 100644 --- a/themes/V3/Blank/style.less +++ b/themes/V3/Blank/style.less @@ -609,268 +609,3 @@ h6, break-inside: auto; } } - -// ***************************** -// * WIDE -// *****************************/ -.page .wide { margin-bottom : 0.325cm; } - -.page h1 + * { margin-top : 0; } - -.page .descriptive.wide + * { - margin-top: 0; -} - -// ***************************** -// * FRONT COVER PAGE -// *****************************/ -.page:has(.frontCover) { - columns : 1; - text-align : center; - &::after { display : none; } - h1 { - margin-top : 1.2cm; - margin-bottom : 0; - font-family : 'NodestoCapsCondensed'; - font-size : 2.245cm; - font-weight : normal; - line-height : 1.9cm; - color : white; - text-shadow : unset; - text-transform : uppercase; - -webkit-text-stroke: 0.2cm black; - paint-order:stroke; - } - h2 { - font-family : 'NodestoCapsCondensed'; - font-size : 0.85cm; - font-weight : normal; - color : white; - letter-spacing : 0.1cm; - -webkit-text-stroke: 0.14cm black; - paint-order:stroke; - } - hr { - position : relative; - display : block; - width : 12cm; - height : 0.5cm; - margin : auto; - visibility : visible; - background-image : @horizontalRule; - filter : drop-shadow(0 0 3px black); - background-size : 100% 100%; - border : none; - } - .banner { - position : absolute; - bottom : 4.2cm; - left : 0; - display : flex; - flex-direction : column; - justify-content : center; - width : 10.5cm; - height : 1.7cm; - padding-top : 0.1cm; - padding-left : 1cm; - font-family : 'NodestoCapsCondensed'; - font-size : 1cm; - font-weight : normal; - color : white; - text-align : left; - letter-spacing : 0.014cm; - background-image : url('/assets/coverPageBanner.svg'); - filter : drop-shadow(2px 2px 2px black); - } - .footnote { - position : absolute; - right : 0; - bottom : 1.3cm; - left : 0; - width : 70%; - margin-right : auto; - margin-left : auto; - font-family : 'Overpass'; - font-size : 0.496cm; - color : white; - text-align : center; - -webkit-text-stroke: 0.1cm black; - paint-order:stroke; - } - .logo { - position : absolute; - top : 0.5cm; - right : 0; - left : 0; - filter : drop-shadow(0 0 0.075cm black); - img { - width : 100%; - height : 2cm; - } - } -} -// ***************************** -// * INSIDE COVER PAGE -// *****************************/ -.page:has(.insideCover) { - columns : 1; - text-align : center; - &::after { display : none; } - h1 { - margin-top : 1.2cm; - margin-bottom : 0; - font-family : 'NodestoCapsCondensed'; - font-size : 2.1cm; - font-weight : normal; - line-height : 1.785cm; - text-transform : uppercase; - } - h2 { - font-family : 'NodestoCapsCondensed'; - font-size : 0.85cm; - font-weight : normal; - letter-spacing : 0.5cm; - } - hr { - position : relative; - display : block; - width : 12cm; - height : 0.5cm; - margin : auto; - visibility : visible; - background-image : @horizontalRule; - background-size : 100% 100%; - border : none; - } - .logo { - position : absolute; - right : 0; - bottom : 1cm; - left : 0; - height : 2cm; - img { - width : 100%; - height : 2cm; - } - } -} -// ***************************** -// * BACK COVER -// *****************************/ -.page:has(.backCover) { - padding : 2.25cm 1.3cm 2cm 1.3cm; - color : #FFFFFF; - columns : 1; - &::after { display : none; } - .columnWrapper { width : 7.6cm; } - .backCover { - position : absolute; - inset : 0; - z-index : -1; - width : 11cm; - background-image : @backCover; - background-repeat : no-repeat; - background-size : contain; - } - .blank { height : 1.4em; } - h1 { - margin-bottom : 0.3cm; - font-family : 'NodestoCapsCondensed'; - font-size : 1.35cm; - line-height : 1.28cm; - color : #ED1C24; - text-align : center; - } - h1 + p::first-line, - h1 + p::first-letter { all : unset; } - img { - position : absolute; - top : 0px; - z-index : -2; - height : 100%; - } - hr { - width : 4.5cm; - height : 0.53cm; - margin-top : 1.1cm; - margin-right : auto; - margin-left : auto; - visibility : visible; - background-image : @horizontalRule; - background-size : 100% 100%; - border : none; - } - p { - font-family : 'Overpass'; - font-size : 0.332cm; - line-height : 0.35cm; - } - hr + p { - margin-top : 0.6cm; - text-align : center; - } - .logo { - position : absolute; - bottom : 2cm; - left : 1.2cm; - z-index : 0; - width : 7.6cm; - height : 1.5cm; - img { - position : relative; - z-index : 0; - width : 100%; - height : 1.5cm; - } - p { - position : relative; - width : 100%; - font-family : 'NodestoCapsWide'; - font-size : 0.4cm; - line-height : 1em; - line-height : 1.28cm; - color : #FFFFFF; - text-align : center; - text-indent : 0; - } - } -} - -// ***************************** -// * PART COVER -// *****************************/ -.page:has(.partCover) { - padding-top : 0; - text-align : center; - columns : 1; - - .partCover { - position : absolute; - top : 0; - left : 0; - width : 100%; - height : 6cm; - background-image : @partCoverHeaderPHB; - background-repeat : no-repeat; - background-size : 100%; - } - - h1 { - position : relative; - margin-top : 0.4cm; - font-family : 'NodestoCapsCondensed'; - font-size : 2.3cm; - text-align : center; - text-transform : uppercase; - } - - h2 { - position : relative; - margin-top : -0.7em; - margin-right : auto; - margin-left : auto; - font-family : 'Overpass'; - font-size : 0.45cm; - line-height : 0.495cm; - } -} From 4448410c3ea263e1ac2cc10d9caacbc571645e42 Mon Sep 17 00:00:00 2001 From: David Bolack Date: Fri, 1 Nov 2024 14:02:27 -0500 Subject: [PATCH 054/398] Partial implementation --- .circleci/config.yml | 2 +- .../homebrew/editor/snippetbar/snippetbar.jsx | 4 ++ client/homebrew/pages/editPage/editPage.jsx | 2 + package.json | 4 +- server/homebrew.api.js | 6 ++ shared/helpers.js | 60 +++++++++++++++++++ 6 files changed, 75 insertions(+), 3 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index f18f84943..abd8faacc 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -10,7 +10,7 @@ orbs: jobs: build: docker: - - image: cimg/node:20.17.0 + - image: cimg/node:20.18.0 - image: mongo:4.4 working_directory: ~/homebrewery diff --git a/client/homebrew/editor/snippetbar/snippetbar.jsx b/client/homebrew/editor/snippetbar/snippetbar.jsx index 50237b914..1f786fd93 100644 --- a/client/homebrew/editor/snippetbar/snippetbar.jsx +++ b/client/homebrew/editor/snippetbar/snippetbar.jsx @@ -6,6 +6,7 @@ const _ = require('lodash'); const cx = require('classnames'); import { loadHistory } from '../../utils/versionHistory.js'; +import { brewSnippetsToJSON } from '../../../../shared/helpers.js'; //Import all themes const ThemeSnippets = {}; @@ -114,6 +115,9 @@ const Snippetbar = createClass({ oldSnippets = _.keyBy(compiledSnippets, 'groupName'); } + const userSnippetsasJSON = brewSnippetsToJSON(this.props.brew.title, this.props.brew.snippets, this.props.snippetsBundle); + compiledSnippets.push(userSnippetsasJSON); + return compiledSnippets; }, diff --git a/client/homebrew/pages/editPage/editPage.jsx b/client/homebrew/pages/editPage/editPage.jsx index 744e187a6..a98b16717 100644 --- a/client/homebrew/pages/editPage/editPage.jsx +++ b/client/homebrew/pages/editPage/editPage.jsx @@ -61,6 +61,7 @@ const EditPage = createClass({ currentEditorCursorPageNum : 1, currentBrewRendererPageNum : 1, displayLockMessage : this.props.brew.lock || false, + snippetsBundle : {}, themeBundle : {} }; }, @@ -440,6 +441,7 @@ const EditPage = createClass({ reportError={this.errorReported} renderer={this.state.brew.renderer} userThemes={this.props.userThemes} + snippets={this.props.snippets} snippetBundle={this.state.themeBundle.snippets} updateBrew={this.updateBrew} onCursorPageChange={this.handleEditorCursorPageChange} diff --git a/package.json b/package.json index 94d0122ab..3fe3ce5a6 100644 --- a/package.json +++ b/package.json @@ -3,8 +3,8 @@ "description": "Create authentic looking D&D homebrews using only markdown", "version": "3.16.0", "engines": { - "npm": "^10.2.x", - "node": "^20.17.x" + "npm": "^10.8.x", + "node": "^20.18.x" }, "repository": { "type": "git", diff --git a/server/homebrew.api.js b/server/homebrew.api.js index 213b341ca..2abbf9485 100644 --- a/server/homebrew.api.js +++ b/server/homebrew.api.js @@ -170,6 +170,12 @@ const api = { `\`\`\`\n\n` + `${text}`; } + if(brew.snippets !== undefined) { + text = `\`\`\`snippets\n` + + `${brew.snippets || ''}\n` + + `\`\`\`\n\n` + + `${text}`; + } const metadata = _.pick(brew, ['title', 'description', 'tags', 'systems', 'renderer', 'theme']); text = `\`\`\`metadata\n` + `${yaml.dump(metadata)}\n` + diff --git a/shared/helpers.js b/shared/helpers.js index ac684b06f..e75dcdb28 100644 --- a/shared/helpers.js +++ b/shared/helpers.js @@ -1,6 +1,65 @@ const _ = require('lodash'); const yaml = require('js-yaml'); const request = require('../client/homebrew/utils/request-middleware.js'); +const dedent = require('dedent'); + +// Convert the templates from a brew to a Snippets Structure. +const brewSnippetsToJSON = (menuTitle, userBrewSnippets, themeBundleSnippets)=>{ + const textSplit = /^\\page/gm; + const mpAsSnippets = []; + // Snippets from Themes first. + if(themeBundleSnippets) { + for (let themes of themeBundleSnippets) { + const userSnippets = []; + for (let snips of themes.snippets.split(textSplit)) { + const name = snips.split('\n')[0]; + if(name.length != 0) { + userSnippets.push({ + name : name, + icon : '', + gen : snips.split('\n').slice(0), + }); + } + } + if(userSnippets.length > 0) { + mpAsSnippets.push({ + name : themes.name, + icon : '', + gen : '', + subsnippets : userSnippets + }); + } + } + } + // Local Snippets + if(userBrewSnippets) { + const userSnippets = []; + for (let snips of userBrewSnippets.split(textSplit)) { + let name = mp.split('\n')[0]; + if(name.length != 0) { + userSnippets.push({ + name : name, + icon : '', + gen : snips.split('\n').slice(0), + }); + } + } + if(userSnippets.length) { + mpAsSnippets.push({ + name : menuTitle, + icon : '', + subsnippets : userSnippets + }); + } + } + + return { + groupName : 'Brew Snippets', + icon : 'fas fa-th-list', + view : 'text', + snippets : mpAsSnippets + }; +}; const splitTextStyleAndMetadata = (brew)=>{ brew.text = brew.text.replaceAll('\r\n', '\n'); @@ -55,4 +114,5 @@ module.exports = { splitTextStyleAndMetadata, printCurrentBrew, fetchThemeBundle, + brewSnippetsToJSON }; From 7cd82ffc4edaf2ee47b38cb6ca4298957483ed47 Mon Sep 17 00:00:00 2001 From: David Bolack Date: Sat, 2 Nov 2024 17:37:43 -0500 Subject: [PATCH 055/398] WOrking snippets insertion from local. --- shared/helpers.js | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/shared/helpers.js b/shared/helpers.js index e75dcdb28..b84cb0332 100644 --- a/shared/helpers.js +++ b/shared/helpers.js @@ -35,12 +35,12 @@ const brewSnippetsToJSON = (menuTitle, userBrewSnippets, themeBundleSnippets)=>{ if(userBrewSnippets) { const userSnippets = []; for (let snips of userBrewSnippets.split(textSplit)) { - let name = mp.split('\n')[0]; + let name = snips.split('\n')[0]; if(name.length != 0) { userSnippets.push({ - name : name, + name : name.slice('\snippet '.length), icon : '', - gen : snips.split('\n').slice(0), + gen : snips.slice(name.length + 1), }); } } @@ -70,16 +70,19 @@ const splitTextStyleAndMetadata = (brew)=>{ Object.assign(brew, _.pick(metadata, ['title', 'description', 'tags', 'systems', 'renderer', 'theme', 'lang'])); brew.text = brew.text.slice(index + 5); } - if(brew.text.startsWith('```css')) { - const index = brew.text.indexOf('```\n\n'); - brew.style = brew.text.slice(7, index - 1); - brew.text = brew.text.slice(index + 5); - } if(brew.text.startsWith('```snippets')) { const index = brew.text.indexOf('```\n\n'); brew.snippets = brew.text.slice(11, index - 1); brew.text = brew.text.slice(index + 5); } + if(brew.text.startsWith('```css')) { + const index = brew.text.indexOf('```\n\n'); + brew.style = brew.text.slice(7, index - 1); + brew.text = brew.text.slice(index + 5); + } + // if(!brew?.snippets) { + brew.snippets = `\\snippet Example\nI am an example user snippet\n`; + // } }; const printCurrentBrew = ()=>{ From 4f240bf1100c46fca948b00899d71a2db2bb4205 Mon Sep 17 00:00:00 2001 From: David Bolack Date: Sat, 2 Nov 2024 22:30:18 -0500 Subject: [PATCH 056/398] WIP --- client/homebrew/editor/editor.jsx | 2 +- .../homebrew/editor/snippetbar/snippetbar.jsx | 21 ++++++++++++------- server/homebrew.api.js | 4 +--- server/homebrew.api.spec.js | 2 -- shared/helpers.js | 7 +++++-- 5 files changed, 20 insertions(+), 16 deletions(-) diff --git a/client/homebrew/editor/editor.jsx b/client/homebrew/editor/editor.jsx index 9fef72cbb..27737fcba 100644 --- a/client/homebrew/editor/editor.jsx +++ b/client/homebrew/editor/editor.jsx @@ -499,7 +499,7 @@ const Editor = createClass({ historySize={this.historySize()} currentEditorTheme={this.state.editorTheme} updateEditorTheme={this.updateEditorTheme} - snippetBundle={this.props.snippetBundle} + themeBundle={this.props.themeBundle} cursorPos={this.codeEditor.current?.getCursorPosition() || {}} updateBrew={this.props.updateBrew} /> diff --git a/client/homebrew/editor/snippetbar/snippetbar.jsx b/client/homebrew/editor/snippetbar/snippetbar.jsx index 1f786fd93..111b4fd38 100644 --- a/client/homebrew/editor/snippetbar/snippetbar.jsx +++ b/client/homebrew/editor/snippetbar/snippetbar.jsx @@ -41,7 +41,6 @@ const Snippetbar = createClass({ unfoldCode : ()=>{}, updateEditorTheme : ()=>{}, cursorPos : {}, - snippetBundle : [], updateBrew : ()=>{} }; }, @@ -102,20 +101,26 @@ const Snippetbar = createClass({ }, compileSnippets : function() { + console.log('compileSnippets'); let compiledSnippets = []; let oldSnippets = _.keyBy(compiledSnippets, 'groupName'); - for (let snippets of this.props.snippetBundle) { - if(typeof(snippets) == 'string') // load staticThemes as needed; they were sent as just a file name - snippets = ThemeSnippets[snippets]; + console.log(this.props.themesBundle); - const newSnippets = _.keyBy(_.cloneDeep(snippets), 'groupName'); - compiledSnippets = _.values(_.mergeWith(oldSnippets, newSnippets, this.mergeCustomizer)); + if( this.props.themesBundle) { + for (let snippets of this.props?.themesBundle?.snippets) { + if(typeof(snippets) == 'string') // load staticThemes as needed; they were sent as just a file name + snippets = ThemeSnippets[snippets]; - oldSnippets = _.keyBy(compiledSnippets, 'groupName'); + const newSnippets = _.keyBy(_.cloneDeep(snippets), 'groupName'); + compiledSnippets = _.values(_.mergeWith(oldSnippets, newSnippets, this.mergeCustomizer)); + + oldSnippets = _.keyBy(compiledSnippets, 'groupName'); + } } - const userSnippetsasJSON = brewSnippetsToJSON(this.props.brew.title, this.props.brew.snippets, this.props.snippetsBundle); + console.log(this.props.themesBundle); + const userSnippetsasJSON = brewSnippetsToJSON(this.props.brew.title, this.props.brew.snippets, this.props?.themesBundle?.snippets); compiledSnippets.push(userSnippetsasJSON); return compiledSnippets; diff --git a/server/homebrew.api.js b/server/homebrew.api.js index 2abbf9485..685415c14 100644 --- a/server/homebrew.api.js +++ b/server/homebrew.api.js @@ -296,7 +296,7 @@ const api = { splitTextStyleAndMetadata(currentTheme); // If there is anything in the snippets or style members, append them to the appropriate array - if(currentTheme?.snippets) completeSnippets.push(JSON.parse(currentTheme.snippets)); + if(currentTheme?.snippets) completeSnippets.push({ name: currentTheme.title, snippets: currentTheme.snippets }); if(currentTheme?.style) completeStyles.push(`/* From Brew: ${req.protocol}://${req.get('host')}/share/${req.params.id} */\n\n${currentTheme.style}`); req.params.id = currentTheme.theme; @@ -304,9 +304,7 @@ const api = { } //=== Static Themes ===// else { - const localSnippets = `${req.params.renderer}_${req.params.id}`; // Just log the name for loading on client const localStyle = `@import url(\"/themes/${req.params.renderer}/${req.params.id}/style.css\");`; - completeSnippets.push(localSnippets); completeStyles.push(`/* From Theme ${req.params.id} */\n\n${localStyle}`); req.params.id = Themes[req.params.renderer][req.params.id].baseTheme; diff --git a/server/homebrew.api.spec.js b/server/homebrew.api.spec.js index a1222cb57..3c86e4208 100644 --- a/server/homebrew.api.spec.js +++ b/server/homebrew.api.spec.js @@ -627,8 +627,6 @@ brew`); `/* From Theme 5ePHB */\n\n@import url("/themes/V3/5ePHB/style.css");` ], snippets : [ - 'V3_Blank', - 'V3_5ePHB' ] }); }); diff --git a/shared/helpers.js b/shared/helpers.js index b84cb0332..d5a4512a6 100644 --- a/shared/helpers.js +++ b/shared/helpers.js @@ -8,9 +8,12 @@ const brewSnippetsToJSON = (menuTitle, userBrewSnippets, themeBundleSnippets)=>{ const textSplit = /^\\page/gm; const mpAsSnippets = []; // Snippets from Themes first. + //console.log(themeBundleSnippets); if(themeBundleSnippets) { + console.log('Looping!'); for (let themes of themeBundleSnippets) { const userSnippets = []; + console.log(themes); for (let snips of themes.snippets.split(textSplit)) { const name = snips.split('\n')[0]; if(name.length != 0) { @@ -80,9 +83,9 @@ const splitTextStyleAndMetadata = (brew)=>{ brew.style = brew.text.slice(7, index - 1); brew.text = brew.text.slice(index + 5); } - // if(!brew?.snippets) { + if(!brew?.snippets) { brew.snippets = `\\snippet Example\nI am an example user snippet\n`; - // } + } }; const printCurrentBrew = ()=>{ From b9b3d284cf3d89a62b671789047cd7c0ea0defde Mon Sep 17 00:00:00 2001 From: David Bolack Date: Sun, 3 Nov 2024 11:14:31 -0600 Subject: [PATCH 057/398] WOrking snippet editor - menu population regression --- client/homebrew/editor/editor.jsx | 19 +++++++++++- .../homebrew/editor/snippetbar/snippetbar.jsx | 18 +++++++----- .../editor/snippetbar/snippetbar.less | 3 ++ client/homebrew/pages/editPage/editPage.jsx | 17 +++++++++-- server/homebrew.api.js | 2 ++ shared/helpers.js | 29 +++++++++---------- 6 files changed, 61 insertions(+), 27 deletions(-) diff --git a/client/homebrew/editor/editor.jsx b/client/homebrew/editor/editor.jsx index 27737fcba..dedfeaebb 100644 --- a/client/homebrew/editor/editor.jsx +++ b/client/homebrew/editor/editor.jsx @@ -21,6 +21,7 @@ const DEFAULT_STYLE_TEXT = dedent` color: black; }`; +const DEFAULT_SNIPPET_TEXT = ``; let isJumping = false; const Editor = createClass({ @@ -35,6 +36,7 @@ const Editor = createClass({ onTextChange : ()=>{}, onStyleChange : ()=>{}, onMetaChange : ()=>{}, + onSnipChange : ()=>{}, reportError : ()=>{}, onCursorPageChange : ()=>{}, @@ -51,7 +53,7 @@ const Editor = createClass({ getInitialState : function() { return { editorTheme : this.props.editorTheme, - view : 'text' //'text', 'style', 'meta' + view : 'text' //'text', 'style', 'meta', 'snip' }; }, @@ -61,6 +63,7 @@ const Editor = createClass({ isText : function() {return this.state.view == 'text';}, isStyle : function() {return this.state.view == 'style';}, isMeta : function() {return this.state.view == 'meta';}, + isSnip : function() {return this.state.view == 'snip';}, componentDidMount : function() { @@ -459,6 +462,20 @@ const Editor = createClass({ userThemes={this.props.userThemes}/> ; } + + if(this.isSnip()){ + return <> + + ; + } }, redo : function(){ diff --git a/client/homebrew/editor/snippetbar/snippetbar.jsx b/client/homebrew/editor/snippetbar/snippetbar.jsx index 111b4fd38..bb932c0fe 100644 --- a/client/homebrew/editor/snippetbar/snippetbar.jsx +++ b/client/homebrew/editor/snippetbar/snippetbar.jsx @@ -41,6 +41,7 @@ const Snippetbar = createClass({ unfoldCode : ()=>{}, updateEditorTheme : ()=>{}, cursorPos : {}, + themeBundle : [], updateBrew : ()=>{} }; }, @@ -64,7 +65,7 @@ const Snippetbar = createClass({ }, componentDidUpdate : async function(prevProps, prevState) { - if(prevProps.renderer != this.props.renderer || prevProps.theme != this.props.theme || prevProps.snippetBundle != this.props.snippetBundle) { + if(prevProps.renderer != this.props.renderer || prevProps.theme != this.props.theme || prevProps.themeBundle != this.props.themeBundle) { this.setState({ snippets : this.compileSnippets() }); @@ -101,15 +102,12 @@ const Snippetbar = createClass({ }, compileSnippets : function() { - console.log('compileSnippets'); let compiledSnippets = []; let oldSnippets = _.keyBy(compiledSnippets, 'groupName'); - console.log(this.props.themesBundle); - - if( this.props.themesBundle) { - for (let snippets of this.props?.themesBundle?.snippets) { + if(this.props.themeBundle.snippets) { + for (let snippets of this.props.themeBundle.snippets) { if(typeof(snippets) == 'string') // load staticThemes as needed; they were sent as just a file name snippets = ThemeSnippets[snippets]; @@ -119,8 +117,8 @@ const Snippetbar = createClass({ oldSnippets = _.keyBy(compiledSnippets, 'groupName'); } } - console.log(this.props.themesBundle); - const userSnippetsasJSON = brewSnippetsToJSON(this.props.brew.title, this.props.brew.snippets, this.props?.themesBundle?.snippets); + + const userSnippetsasJSON = brewSnippetsToJSON(this.props.brew.title, this.props.brew.snippets, this.props.themeBundle.snippets); compiledSnippets.push(userSnippetsasJSON); return compiledSnippets; @@ -266,6 +264,10 @@ const Snippetbar = createClass({ onClick={()=>this.props.onViewChange('meta')}> +
this.props.onViewChange('snip')}> + +
; diff --git a/client/homebrew/editor/snippetbar/snippetbar.less b/client/homebrew/editor/snippetbar/snippetbar.less index 319cd0cad..a7202c428 100644 --- a/client/homebrew/editor/snippetbar/snippetbar.less +++ b/client/homebrew/editor/snippetbar/snippetbar.less @@ -48,6 +48,9 @@ &.meta { .tooltipLeft('Properties'); } + &.snip { + .tooltipLeft('Snippets'); + } &.undo { .tooltipLeft('Undo'); font-size : 0.75em; diff --git a/client/homebrew/pages/editPage/editPage.jsx b/client/homebrew/pages/editPage/editPage.jsx index a98b16717..df840bc48 100644 --- a/client/homebrew/pages/editPage/editPage.jsx +++ b/client/homebrew/pages/editPage/editPage.jsx @@ -61,7 +61,6 @@ const EditPage = createClass({ currentEditorCursorPageNum : 1, currentBrewRendererPageNum : 1, displayLockMessage : this.props.brew.lock || false, - snippetsBundle : {}, themeBundle : {} }; }, @@ -143,6 +142,19 @@ const EditPage = createClass({ }), ()=>{if(this.state.autoSave) this.trySave();}); }, + handleSnipChange : function(snippet){ + console.log('Snip Change!'); + //If there are errors, run the validator on every change to give quick feedback + let htmlErrors = this.state.htmlErrors; + if(htmlErrors.length) htmlErrors = Markdown.validate(snippet); + + this.setState((prevState)=>({ + brew : { ...prevState.brew, snippets: snippet }, + isPending : true, + htmlErrors : htmlErrors, + }), ()=>{if(this.state.autoSave) this.trySave();}); + }, + handleStyleChange : function(style){ this.setState((prevState)=>({ brew : { ...prevState.brew, style: style }, @@ -438,11 +450,12 @@ const EditPage = createClass({ onTextChange={this.handleTextChange} onStyleChange={this.handleStyleChange} onMetaChange={this.handleMetaChange} + onSnipChange={this.handleSnipChange} reportError={this.errorReported} renderer={this.state.brew.renderer} userThemes={this.props.userThemes} snippets={this.props.snippets} - snippetBundle={this.state.themeBundle.snippets} + themeBundle={this.state.themeBundle} updateBrew={this.updateBrew} onCursorPageChange={this.handleEditorCursorPageChange} onViewPageChange={this.handleEditorViewPageChange} diff --git a/server/homebrew.api.js b/server/homebrew.api.js index 685415c14..9c4f55ef7 100644 --- a/server/homebrew.api.js +++ b/server/homebrew.api.js @@ -304,7 +304,9 @@ const api = { } //=== Static Themes ===// else { + const localSnippets = `${req.params.renderer}_${req.params.id}`; // Just log the name for loading on client const localStyle = `@import url(\"/themes/${req.params.renderer}/${req.params.id}/style.css\");`; + completeSnippets.push(localSnippets); completeStyles.push(`/* From Theme ${req.params.id} */\n\n${localStyle}`); req.params.id = Themes[req.params.renderer][req.params.id].baseTheme; diff --git a/shared/helpers.js b/shared/helpers.js index d5a4512a6..27c372dd7 100644 --- a/shared/helpers.js +++ b/shared/helpers.js @@ -8,29 +8,26 @@ const brewSnippetsToJSON = (menuTitle, userBrewSnippets, themeBundleSnippets)=>{ const textSplit = /^\\page/gm; const mpAsSnippets = []; // Snippets from Themes first. - //console.log(themeBundleSnippets); if(themeBundleSnippets) { - console.log('Looping!'); for (let themes of themeBundleSnippets) { - const userSnippets = []; - console.log(themes); - for (let snips of themes.snippets.split(textSplit)) { - const name = snips.split('\n')[0]; + if(typeof themes !== 'string') { + const userSnippets = []; + const name = themes.snippets.split('\n')[0]; if(name.length != 0) { userSnippets.push({ - name : name, + name : name.slice('\snippets '.length), icon : '', - gen : snips.split('\n').slice(0), + gen : themes.snippets.slice(name.length + 1), + }); + } + if(userSnippets.length > 0) { + mpAsSnippets.push({ + name : themes.name, + icon : '', + gen : '', + subsnippets : userSnippets }); } - } - if(userSnippets.length > 0) { - mpAsSnippets.push({ - name : themes.name, - icon : '', - gen : '', - subsnippets : userSnippets - }); } } } From 7f7f3557b36e29575e3703137445149d015f49fd Mon Sep 17 00:00:00 2001 From: David Bolack Date: Sun, 3 Nov 2024 12:30:14 -0600 Subject: [PATCH 058/398] Mostly working. Needs tweakages. Presentable --- client/homebrew/editor/editor.jsx | 2 +- .../homebrew/editor/snippetbar/snippetbar.jsx | 5 +++- client/homebrew/pages/editPage/editPage.jsx | 1 - shared/helpers.js | 24 ++++++++++--------- 4 files changed, 18 insertions(+), 14 deletions(-) diff --git a/client/homebrew/editor/editor.jsx b/client/homebrew/editor/editor.jsx index dedfeaebb..6c74bfdf7 100644 --- a/client/homebrew/editor/editor.jsx +++ b/client/homebrew/editor/editor.jsx @@ -158,7 +158,7 @@ const Editor = createClass({ highlightCustomMarkdown : function(){ if(!this.codeEditor.current) return; - if(this.state.view === 'text') { + if(this.state.view === 'text') { const codeMirror = this.codeEditor.current.codeMirror; codeMirror.operation(()=>{ // Batch CodeMirror styling diff --git a/client/homebrew/editor/snippetbar/snippetbar.jsx b/client/homebrew/editor/snippetbar/snippetbar.jsx index bb932c0fe..066711c41 100644 --- a/client/homebrew/editor/snippetbar/snippetbar.jsx +++ b/client/homebrew/editor/snippetbar/snippetbar.jsx @@ -65,7 +65,10 @@ const Snippetbar = createClass({ }, componentDidUpdate : async function(prevProps, prevState) { - if(prevProps.renderer != this.props.renderer || prevProps.theme != this.props.theme || prevProps.themeBundle != this.props.themeBundle) { + if(prevProps.renderer != this.props.renderer || + prevProps.theme != this.props.theme || + prevProps.themeBundle != this.props.themeBundle || + prevProps.brew.snippets != this.props.brew.snippets) { this.setState({ snippets : this.compileSnippets() }); diff --git a/client/homebrew/pages/editPage/editPage.jsx b/client/homebrew/pages/editPage/editPage.jsx index df840bc48..be5af729b 100644 --- a/client/homebrew/pages/editPage/editPage.jsx +++ b/client/homebrew/pages/editPage/editPage.jsx @@ -143,7 +143,6 @@ const EditPage = createClass({ }, handleSnipChange : function(snippet){ - console.log('Snip Change!'); //If there are errors, run the validator on every change to give quick feedback let htmlErrors = this.state.htmlErrors; if(htmlErrors.length) htmlErrors = Markdown.validate(snippet); diff --git a/shared/helpers.js b/shared/helpers.js index 27c372dd7..750f533cd 100644 --- a/shared/helpers.js +++ b/shared/helpers.js @@ -5,20 +5,22 @@ const dedent = require('dedent'); // Convert the templates from a brew to a Snippets Structure. const brewSnippetsToJSON = (menuTitle, userBrewSnippets, themeBundleSnippets)=>{ - const textSplit = /^\\page/gm; + const textSplit = /^\\snippet /gm; const mpAsSnippets = []; // Snippets from Themes first. if(themeBundleSnippets) { for (let themes of themeBundleSnippets) { if(typeof themes !== 'string') { const userSnippets = []; - const name = themes.snippets.split('\n')[0]; - if(name.length != 0) { - userSnippets.push({ - name : name.slice('\snippets '.length), - icon : '', - gen : themes.snippets.slice(name.length + 1), - }); + for (let snips of themes.snippets.trim().split(textSplit)) { + const name = snips.trim().split('\n')[0]; + if(name.length != 0) { + userSnippets.push({ + name : name.slice('\snippets'.length), + icon : '', + gen : snips.slice(name.length + 1), + }); + } } if(userSnippets.length > 0) { mpAsSnippets.push({ @@ -34,11 +36,11 @@ const brewSnippetsToJSON = (menuTitle, userBrewSnippets, themeBundleSnippets)=>{ // Local Snippets if(userBrewSnippets) { const userSnippets = []; - for (let snips of userBrewSnippets.split(textSplit)) { + for (let snips of userBrewSnippets.trim().split(textSplit)) { let name = snips.split('\n')[0]; if(name.length != 0) { userSnippets.push({ - name : name.slice('\snippet '.length), + name : name, icon : '', gen : snips.slice(name.length + 1), }); @@ -72,7 +74,7 @@ const splitTextStyleAndMetadata = (brew)=>{ } if(brew.text.startsWith('```snippets')) { const index = brew.text.indexOf('```\n\n'); - brew.snippets = brew.text.slice(11, index - 1); + brew.snippets = brew.text.slice(12, index - 1); brew.text = brew.text.slice(index + 5); } if(brew.text.startsWith('```css')) { From f4e951623348728d243f5097e532b459a8cee638 Mon Sep 17 00:00:00 2001 From: David Bolack Date: Sun, 3 Nov 2024 12:41:04 -0600 Subject: [PATCH 059/398] Remove testing helper --- shared/helpers.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/shared/helpers.js b/shared/helpers.js index 750f533cd..8b94704bd 100644 --- a/shared/helpers.js +++ b/shared/helpers.js @@ -82,9 +82,6 @@ const splitTextStyleAndMetadata = (brew)=>{ brew.style = brew.text.slice(7, index - 1); brew.text = brew.text.slice(index + 5); } - if(!brew?.snippets) { - brew.snippets = `\\snippet Example\nI am an example user snippet\n`; - } }; const printCurrentBrew = ()=>{ From f43a155e6efad0e267ebfb0196d94546923062fc Mon Sep 17 00:00:00 2001 From: David Bolack Date: Sun, 3 Nov 2024 12:52:54 -0600 Subject: [PATCH 060/398] Fix Test --- server/homebrew.api.spec.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/server/homebrew.api.spec.js b/server/homebrew.api.spec.js index 3c86e4208..a1222cb57 100644 --- a/server/homebrew.api.spec.js +++ b/server/homebrew.api.spec.js @@ -627,6 +627,8 @@ brew`); `/* From Theme 5ePHB */\n\n@import url("/themes/V3/5ePHB/style.css");` ], snippets : [ + 'V3_Blank', + 'V3_5ePHB' ] }); }); From e0400c0425be5d00c3541fca64bda5f2ed43bf8f Mon Sep 17 00:00:00 2001 From: David Bolack Date: Tue, 12 Nov 2024 18:41:31 -0600 Subject: [PATCH 061/398] Snippets should go after existing tab sections --- shared/helpers.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/shared/helpers.js b/shared/helpers.js index 8b94704bd..e603abaf0 100644 --- a/shared/helpers.js +++ b/shared/helpers.js @@ -72,16 +72,16 @@ const splitTextStyleAndMetadata = (brew)=>{ Object.assign(brew, _.pick(metadata, ['title', 'description', 'tags', 'systems', 'renderer', 'theme', 'lang'])); brew.text = brew.text.slice(index + 5); } - if(brew.text.startsWith('```snippets')) { - const index = brew.text.indexOf('```\n\n'); - brew.snippets = brew.text.slice(12, index - 1); - brew.text = brew.text.slice(index + 5); - } if(brew.text.startsWith('```css')) { const index = brew.text.indexOf('```\n\n'); brew.style = brew.text.slice(7, index - 1); brew.text = brew.text.slice(index + 5); } + if(brew.text.startsWith('```snippets')) { + const index = brew.text.indexOf('```\n\n'); + brew.snippets = brew.text.slice(12, index - 1); + brew.text = brew.text.slice(index + 5); + } }; const printCurrentBrew = ()=>{ From f7561b78247ea98c85a5f65f0452bf578ef0890d Mon Sep 17 00:00:00 2001 From: David Bolack Date: Wed, 13 Nov 2024 20:53:04 -0600 Subject: [PATCH 062/398] Insert a CR --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index df7f41503..5206f4cbf 100644 --- a/README.md +++ b/README.md @@ -144,3 +144,4 @@ your contribution to the project, please join our [gitter chat][gitter-url]. [github-mark-duplicate-url]: https://docs.github.com/en/free-pro-team@latest/github/managing-your-work-on-github/about-duplicate-issues-and-pull-requests [github-pr-docs-url]: https://docs.github.com/en/free-pro-team@latest/github/collaborating-with-issues-and-pull-requests/creating-a-pull-request [gitter-url]: https://gitter.im/naturalcrit/Lobby + From d541a70da54ee4f59f72255518cfe3380e6690ab Mon Sep 17 00:00:00 2001 From: David Bolack Date: Thu, 14 Nov 2024 06:54:36 -0600 Subject: [PATCH 063/398] Remove unneeded dedent --- shared/helpers.js | 1 - 1 file changed, 1 deletion(-) diff --git a/shared/helpers.js b/shared/helpers.js index e603abaf0..f5411f501 100644 --- a/shared/helpers.js +++ b/shared/helpers.js @@ -1,7 +1,6 @@ const _ = require('lodash'); const yaml = require('js-yaml'); const request = require('../client/homebrew/utils/request-middleware.js'); -const dedent = require('dedent'); // Convert the templates from a brew to a Snippets Structure. const brewSnippetsToJSON = (menuTitle, userBrewSnippets, themeBundleSnippets)=>{ From 929469d0c05852712db71b3cf15971c7e6cd1af9 Mon Sep 17 00:00:00 2001 From: David Bolack Date: Fri, 22 Nov 2024 20:11:14 -0600 Subject: [PATCH 064/398] Working feature. --- shared/naturalcrit/markdown.js | 40 +++++++++++++++++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) diff --git a/shared/naturalcrit/markdown.js b/shared/naturalcrit/markdown.js index 4c1a2f92a..6dfc64d25 100644 --- a/shared/naturalcrit/markdown.js +++ b/shared/naturalcrit/markdown.js @@ -370,6 +370,44 @@ const superSubScripts = { } }; + +const justifiedParagraphClasses = []; +justifiedParagraphClasses[2] = 'mdParagraphJiustifyLeft'; +justifiedParagraphClasses[4] = 'mdParagraphJiustifyRight'; +justifiedParagraphClasses[6] = 'mdParagraphJiustifyCenter'; + +const justifiedParagraphs = { + name : 'justifiedParagraphs', + level : 'block', + start(src) { + return src.match(/\n(?:-:|:-|:-:) {1}/m)?.index; + + }, // Hint to Marked.js to stop and check for a match + tokenizer(src, tokens) { + const regex = /^((:- ).*)|((-: ).*)|((:-:) .*)(?:\n|$)/ym; + const match = regex.exec(src); + if(match?.length) { + let whichJustify; + if(match[2]?.length) whichJustify = 2; + if(match[4]?.length) whichJustify = 4; + if(match[6]?.length) whichJustify = 6; + return { + type : 'justifiedParagraphs', // Should match "name" above + raw : match[0], // Text to consume from the source + length : match[whichJustify].length, + text : match[0].slice(match[whichJustify].length), + class : justifiedParagraphClasses[whichJustify], + tokens : this.lexer.inlineTokens(match[0].slice(match[whichJustify].length)) + }; + } + }, + renderer(token) { + return `

${this.parser.parseInline(token.tokens)}

`; + } + +}; + + const forcedParagraphBreaks = { name : 'hardBreaks', level : 'block', @@ -748,7 +786,7 @@ const tableTerminators = [ ]; Marked.use(MarkedVariables()); -Marked.use({ extensions : [definitionListsMultiLine, definitionListsSingleLine, forcedParagraphBreaks, superSubScripts, +Marked.use({ extensions : [justifiedParagraphs, definitionListsMultiLine, definitionListsSingleLine, forcedParagraphBreaks, superSubScripts, mustacheSpans, mustacheDivs, mustacheInjectInline] }); Marked.use(mustacheInjectBlock); Marked.use({ renderer: renderer, tokenizer: tokenizer, mangle: false }); From 440ad516df6317ee529723f6055a42da05b4f9f6 Mon Sep 17 00:00:00 2001 From: David Bolack Date: Fri, 22 Nov 2024 20:39:31 -0600 Subject: [PATCH 065/398] Add justification token testing --- shared/naturalcrit/markdown.js | 8 ++++---- tests/markdown/justification.test.js | 27 +++++++++++++++++++++++++++ 2 files changed, 31 insertions(+), 4 deletions(-) create mode 100644 tests/markdown/justification.test.js diff --git a/shared/naturalcrit/markdown.js b/shared/naturalcrit/markdown.js index 6dfc64d25..5e81be3f0 100644 --- a/shared/naturalcrit/markdown.js +++ b/shared/naturalcrit/markdown.js @@ -372,9 +372,9 @@ const superSubScripts = { const justifiedParagraphClasses = []; -justifiedParagraphClasses[2] = 'mdParagraphJiustifyLeft'; -justifiedParagraphClasses[4] = 'mdParagraphJiustifyRight'; -justifiedParagraphClasses[6] = 'mdParagraphJiustifyCenter'; +justifiedParagraphClasses[2] = 'mdParagraphJustifyLeft'; +justifiedParagraphClasses[4] = 'mdParagraphJustifyRight'; +justifiedParagraphClasses[6] = 'mdParagraphJustifyCenter'; const justifiedParagraphs = { name : 'justifiedParagraphs', @@ -384,7 +384,7 @@ const justifiedParagraphs = { }, // Hint to Marked.js to stop and check for a match tokenizer(src, tokens) { - const regex = /^((:- ).*)|((-: ).*)|((:-:) .*)(?:\n|$)/ym; + const regex = /^((:- ).*)|((-: ).*)|((:-: ).*)(?:\n|$)/ym; const match = regex.exec(src); if(match?.length) { let whichJustify; diff --git a/tests/markdown/justification.test.js b/tests/markdown/justification.test.js new file mode 100644 index 000000000..e3639eb81 --- /dev/null +++ b/tests/markdown/justification.test.js @@ -0,0 +1,27 @@ +/* eslint-disable max-lines */ + +import Markdown from 'naturalcrit/markdown.js'; + +describe('Justification', ()=>{ + test('Left Justify', function() { + const source = ':- Hello'; + const rendered = Markdown.render(source); + expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe(`

Hello

`); + }); + test('Right Justify', function() { + const source = '-: Hello'; + const rendered = Markdown.render(source); + expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe(`

Hello

`); + }); + test('Center Justify', function() { + const source = ':-: Hello'; + const rendered = Markdown.render(source); + expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe(`

Hello

`); + }); + + test('Ignored inside a code block', function() { + const source = '```\n\n:- Hello\n\n```\n'; + const rendered = Markdown.render(source); + expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe(`
\n:- Hello\n
\n`); + }); +}); From deb9c6651fdf4849f7d0554fa58706fbc7d07b44 Mon Sep 17 00:00:00 2001 From: David Bolack Date: Fri, 22 Nov 2024 20:45:58 -0600 Subject: [PATCH 066/398] Add Styles for Forced Justifcation Tokens --- themes/V3/Blank/style.less | 21 +- themes/V4/Blank/dropdownPreview.png | Bin 0 -> 142231 bytes themes/V4/Blank/dropdownTexture.png | Bin 0 -> 236 bytes themes/V4/Blank/settings.json | 6 + themes/V4/Blank/snippets.js | 506 ++++++++++++++++++++ themes/V4/Blank/snippets/footer.gen.js | 17 + themes/V4/Blank/snippets/imageMask.gen.js | 46 ++ themes/V4/Blank/snippets/watercolor.gen.js | 5 + themes/V4/Blank/style.less | 524 +++++++++++++++++++++ themes/themes.json | 9 + 10 files changed, 1133 insertions(+), 1 deletion(-) create mode 100644 themes/V4/Blank/dropdownPreview.png create mode 100644 themes/V4/Blank/dropdownTexture.png create mode 100644 themes/V4/Blank/settings.json create mode 100644 themes/V4/Blank/snippets.js create mode 100644 themes/V4/Blank/snippets/footer.gen.js create mode 100644 themes/V4/Blank/snippets/imageMask.gen.js create mode 100644 themes/V4/Blank/snippets/watercolor.gen.js create mode 100644 themes/V4/Blank/style.less diff --git a/themes/V3/Blank/style.less b/themes/V3/Blank/style.less index 8229baa28..0c7864399 100644 --- a/themes/V3/Blank/style.less +++ b/themes/V3/Blank/style.less @@ -503,4 +503,23 @@ body { counter-reset : page-numbers 0; } counter-increment : page-numbers; } -} \ No newline at end of file +} + +//***************************** +//* Forced Justification +//* DELETE WHEN V4 GOES LIVE +//*****************************/ + +.page { + .mdParagraphJustifyLeft { + text-align: left; + } + + .mdParagraphJustifyRight { + text-align: right; + } + + .mdParagraphJustifyCenter { + text-align: center; + } +} diff --git a/themes/V4/Blank/dropdownPreview.png b/themes/V4/Blank/dropdownPreview.png new file mode 100644 index 0000000000000000000000000000000000000000..7ff524ad486550e2c948769ff273066c0f3d2290 GIT binary patch literal 142231 zcmeGD^;;Z4*EI@bArJ^ILvVL8KyVEjJh;nXNpN>(fB=KLC&As_2N($M?iwVx>zTaY zb3fnx{tf5+)YtSi-L-3X)vi@*tqT9FEc^D&yEh032yf*+NvRD$9-q7O27EsBg57MZTKCl za!uSZT2I}e_DV)JWhc~5BXa? z#YgzR(TL;zK|zuS2yu=Ge)>;@|K7hy`vY7p;&xx~-$7=Hi=&${7U;hIznb!fhu+Yy zyr%JAo&151#soU*{cuS2-%Wju3BZG0&+ljaPpALS#RUl-R931bdES3F^%vgvc?uz4 z_5aFUpfVLaDEz6i;Qy;B5qSJdW`*|uS5ML5LAjZxyT<-^Q+2ZN_`Q!VmHxY@f`Ra$ zloe~S)c(7vYk2(sUsC_ymQ<5jTz-~0dm8KR%TkU)#QX(lb0oWL#ejg`kx7U9h*t8XeqocL=;Csenb2Pv0w(Z~J6s^>oTCJQ6r(o(nYpH6-& zeHHDQkmy$NABdoB!MzAtGX#@xJ>N2J_7gI(Ace6+{;jq5M?KF|hgHf3lQvmqzFL07 zSjRoH?VdUhR9<11bCW;iQp46xPq1*l0dlg+F?s& z7j)%~0Bl5dKQ<1kwY28VSXg|EpcBgXvL#z}W?rO?z46q!7BJJ?+V_BN6lftnf^TZxKC%tta5Anp0g%*zu(gOO3#;mPkTc#CulmDXzm&T`mC<+}k_qp@7a6%8?J z)^y3niU3yY{5c;Ivp;BN<5^^k?VBwm7x~#0a&ghxxT!qwg2w{N#7cYGv*o{NE^T<9 z@$x|Hu@#wvbbE`_AbQ8vX7{XGWhH#OK~$FMO&(o}%LW}ydNtqS(|%7(51Ha@FDxbY z1Wz;qO$jouDmtVl2ZES%sL)}}+Z8RRHHgU07Z2YE%ziVnH;zp4EC{~)pN#S&L2pl2 z+5fz3z2(2%z+OK!j$9&Y|Dv_NJSb?>)`s-uMPGbX)DPk0<@EJ^p+4%9xD#Sjn+t>#y}iqH^?KDCH%y@x7bUuRnDwYUU}PxJ72g-;R@2I|7s z)2+|oGiow_GeWHnx3BhR5&q6Yrw3vk=&i=)qtnJKLE71V6xTuTiONUX>#$|lb}Hs$ zK&P{)Y)|`vw<~>}^I@(!VU>@*VBqr{0#?T(TN#F<{|tY&K_K7iLfFWd>FjsDn%b&| zXY%>mF`Py!X9 zUo$Sla}s{vOAsRf=Fa*Mhu^Oj<2%>tPs;8+RMnv}IX13qxh3DSL3KLpKkW_$vk;pl z5eU0RwxXNgm;EaM!bmF&ki9jq|HCNDaO9K+<-PwsiAP`W*n-%aJm2m0#p(Y0wUV`L z?>EUgyyZ`*sErt<#%GOattXV-r8#|+_kd_){h<7z5Y3Utk*6DrTg*p&i~O?H4!76Q zHj2h)H)kr9&~r*V+Mwik$<>>fjnh&QkLwd0eIBimRYt_;L(#{j7_p-8Kg$e{>&K)H z6*cjbZ%>!k41!dAwpiNb(Cc?N=WA7QWuD;>gc&rx_8+hk2t#wp0P+S!##I=v1ZY3U zXwEy^3fCgbinXCcj`}}FBI_6%gdz9;HahN+UDN$}ykoo?P~O>&J>=hvHPm^-Ty*5| zxH5JO&AKtJ|7M9m0gV###nf6W5fZ!UBcFdU&ZshhK2wl&uWIv|JQ&)vnESpg99B8F z4Yhc&tMX_KpOk$(X^eRBza7)wSl+Xe@Vd@$UmrCVg1&P~x-vO~3g|rdPzYbYT&*uB z5qhu?8som3 zDU*%o!IVCisF@hA=;HkxwDIMcgMTOaenGx}xnn3>=a*BqOmn@wz-XxHCqC7stMicIs>5__KJ6bYIe(w*tc&63`*MXN+O!h( z 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⁡=B5jVo;0X`3P=$s9!NKPdFDdo_JNk=8&=mx?x} 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%0AvP)0c-T2@`xL@jGEyeyb#SQx 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

a8x0C{*b{eu)Hn%0G_vP)GoanFI=% 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 TG>HB$;A5m`a=r4JL->CI;&2u+ literal 0 HcmV?d00001 diff --git a/themes/V4/Blank/dropdownTexture.png b/themes/V4/Blank/dropdownTexture.png new file mode 100644 index 0000000000000000000000000000000000000000..d0c0256c0930789944d3b6567692a532620bdc84 GIT binary patch literal 236 zcmeAS@N?(olHy`uVBq!ia0y~yVAKJ!YL8Sly literal 0 HcmV?d00001 diff --git a/themes/V4/Blank/settings.json b/themes/V4/Blank/settings.json new file mode 100644 index 000000000..3786248fb --- /dev/null +++ b/themes/V4/Blank/settings.json @@ -0,0 +1,6 @@ +{ + "name" : "Blank", + "renderer" : "V3", + "baseTheme" : false, + "baseSnippets" : false +} diff --git a/themes/V4/Blank/snippets.js b/themes/V4/Blank/snippets.js new file mode 100644 index 000000000..e92e757cf --- /dev/null +++ b/themes/V4/Blank/snippets.js @@ -0,0 +1,506 @@ +/* eslint-disable max-lines */ + +const WatercolorGen = require('./snippets/watercolor.gen.js'); +const ImageMaskGen = require('./snippets/imageMask.gen.js'); +const FooterGen = require('./snippets/footer.gen.js'); +const dedent = require('dedent-tabs').default; + +module.exports = [ + + { + groupName : 'Text Editor', + icon : 'fas fa-pencil-alt', + view : 'text', + snippets : [ + { + name : 'Column Break', + icon : 'fas fa-columns', + gen : '\n\\column\n' + }, + { + name : 'New Page', + icon : 'fas fa-file-alt', + gen : '\n\\page\n' + }, + { + name : 'Page Numbering', + icon : 'fas fa-bookmark', + subsnippets : [ + { + name : 'Page Number', + icon : 'fas fa-bookmark', + gen : '{{pageNumber 1}}\n' + }, + { + name : 'Auto-incrementing Page Number', + icon : 'fas fa-sort-numeric-down', + gen : '{{pageNumber,auto}}\n' + }, + { + name : 'Skip Page Number Increment this Page', + icon : 'fas fa-xmark', + gen : '{{skipCounting}}\n' + }, + { + name : 'Restart Numbering', + icon : 'fas fa-arrow-rotate-left', + gen : '{{resetCounting}}\n' + }, + ] + }, + { + name : 'Footer', + icon : 'fas fa-shoe-prints', + gen : FooterGen.createFooterFunc(), + subsnippets : [ + { + name : 'Footer from H1', + icon : 'fas fa-dice-one', + gen : FooterGen.createFooterFunc(1) + }, + { + name : 'Footer from H2', + icon : 'fas fa-dice-two', + gen : FooterGen.createFooterFunc(2) + }, + { + name : 'Footer from H3', + icon : 'fas fa-dice-three', + gen : FooterGen.createFooterFunc(3) + }, + { + name : 'Footer from H4', + icon : 'fas fa-dice-four', + gen : FooterGen.createFooterFunc(4) + }, + { + name : 'Footer from H5', + icon : 'fas fa-dice-five', + gen : FooterGen.createFooterFunc(5) + }, + { + name : 'Footer from H6', + icon : 'fas fa-dice-six', + gen : FooterGen.createFooterFunc(6) + } + ] + }, + { + name : 'Vertical Spacing', + icon : 'fas fa-arrows-alt-v', + gen : '\n::::\n' + }, + { + name : 'Horizontal Spacing', + icon : 'fas fa-arrows-alt-h', + gen : ' {{width:100px}} ' + }, + { + name : 'Wide Block', + icon : 'fas fa-window-maximize', + gen : dedent`\n + {{wide + Everything in here will be extra wide. Tables, text, everything! + Beware though, CSS columns can behave a bit weird sometimes. You may + have to manually place column breaks with \`\column\` to make the + surrounding text flow with this wide block the way you want. + }} + \n` + }, + { + name : 'QR Code', + icon : 'fas fa-qrcode', + gen : (brew)=>{ + return `![]` + + `(https://api.qrserver.com/v1/create-qr-code/?data=` + + `https://homebrewery.naturalcrit.com${brew.shareId ? `/share/${brew.shareId}` : ''}` + + `&size=100x100) {width:100px;mix-blend-mode:multiply}`; + } + }, + { + name : 'Link to page', + icon : 'fas fa-link', + gen : '[Click here](#p3) to go to page 3\n' + }, + { + name : 'Add Comment', + icon : 'fas fa-code', + gen : '' + }, + { + name : 'Homebrewery Credit', + icon : 'fas fa-dice-d20', + gen : function(){ + return dedent` + {{homebreweryCredits + Made With + + {{homebreweryIcon}} + + The Homebrewery + [Homebrewery.Naturalcrit.com](https://homebrewery.naturalcrit.com) + }}\n\n`; + }, + } + ] + }, + { + groupName : 'Style Editor', + icon : 'fas fa-pencil-alt', + view : 'style', + snippets : [ + { + name : 'Add Comment', + icon : 'fas fa-code', + gen : '/* This is a comment that will not be rendered into your brew. */' + }, + ] + }, + + /*********************** IMAGES *******************/ + { + groupName : 'Images', + icon : 'fas fa-images', + view : 'text', + snippets : [ + { + name : 'Image', + icon : 'fas fa-image', + gen : dedent` + ![cat warrior](https://s-media-cache-ak0.pinimg.com/736x/4a/81/79/4a8179462cfdf39054a418efd4cb743e.jpg) {width:325px,mix-blend-mode:multiply}` + }, + { + name : 'Image Wrap Left', + icon : 'fac image-wrap-left', + gen : dedent` + ![homebrewery_mug](http://i.imgur.com/hMna6G0.png) {width:280px,margin-right:-3cm,wrapLeft}` + }, + { + name : 'Image Wrap Right', + icon : 'fac image-wrap-right', + gen : dedent` + ![homebrewery_mug](http://i.imgur.com/hMna6G0.png) {width:280px,margin-left:-3cm,wrapRight}` + }, + { + name : 'Background Image', + icon : 'fas fa-tree', + gen : dedent` + ![homebrew mug](http://i.imgur.com/hMna6G0.png) {position:absolute,top:50px,right:30px,width:280px}` + }, + { + name : 'Watercolor Splatter', + icon : 'fas fa-fill-drip', + gen : WatercolorGen, + }, + { + name : 'Watercolor Center', + icon : 'fac mask-center', + gen : ImageMaskGen.center, + experimental : true, + }, + { + name : 'Watercolor Edge', + icon : 'fac mask-edge', + gen : ImageMaskGen.edge('bottom'), + experimental : true, + subsnippets : [ + { + name : 'Top', + icon : 'fac position-top', + gen : ImageMaskGen.edge('top'), + }, + { + name : 'Right', + icon : 'fac position-right', + gen : ImageMaskGen.edge('right'), + }, + { + name : 'Bottom', + icon : 'fac position-bottom', + gen : ImageMaskGen.edge('bottom'), + }, + { + name : 'Left', + icon : 'fac position-left', + gen : ImageMaskGen.edge('left'), + }, + ] + }, + { + name : 'Watercolor Corner', + icon : 'fac mask-corner', + gen : ImageMaskGen.corner, + experimental : true, + subsnippets : [ + { + name : 'Top-Left', + icon : 'fac position-top-left', + gen : ImageMaskGen.corner('top', 'left'), + }, + { + name : 'Top-Right', + icon : 'fac position-top-right', + gen : ImageMaskGen.corner('top', 'right'), + }, + { + name : 'Bottom-Left', + icon : 'fac position-bottom-left', + gen : ImageMaskGen.corner('bottom', 'left'), + }, + { + name : 'Bottom-Right', + icon : 'fac position-bottom-right', + gen : ImageMaskGen.corner('bottom', 'right'), + } + ] + }, + { + name : 'Watermark', + icon : 'fas fa-id-card', + gen : dedent` + {{watermark Homebrewery}}\n` + }, + ] + }, + + /********************* TABLES *********************/ + + { + groupName : 'Tables', + icon : 'fas fa-table', + view : 'text', + snippets : [ + { + name : 'Table', + icon : 'fas fa-th-list', + gen : function(){ + return dedent` + ##### Character Advancement + | Experience Points | Level | Proficiency Bonus | + |:------------------|:-----:|:-----------------:| + | 0 | 1 | +2 | + | 300 | 2 | +2 | + | 900 | 3 | +2 | + | 2,700 | 4 | +2 | + | 6,500 | 5 | +3 | + | 14,000 | 6 | +3 | + \n`; + } + }, + { + name : 'Wide Table', + icon : 'fas fa-list', + gen : function(){ + return dedent` + {{wide + ##### Weapons + | Name | Cost | Damage | Weight | Properties | + |:------------------------|:-----:|:----------------|--------:|:-----------| + | *Simple Melee Weapons* | | | | | + |   Club | 1 sp | 1d4 bludgeoning | 2 lb. | Light | + |   Dagger | 2 gp | 1d4 piercing | 1 lb. | Finesse | + |   Spear | 1 gp | 1d6 piercing | 3 lb. | Thrown | + | *Simple Ranged Weapons* | | | | | + |   Dart | 5 cp | 1d4 piercig | 1/4 lb. | Finesse | + |   Shortbow | 25 gp | 1d6 piercing | 2 lb. | Ammunition | + |   Sling | 1 sp | 1d4 bludgeoning | — | Ammunition | + }} + \n`; + } + }, + { + name : 'Split Table', + icon : 'fas fa-th-large', + gen : function(){ + return dedent` + ##### Typical Difficulty Classes + {{column-count:2 + | Task Difficulty | DC | + |:----------------|:--:| + | Very easy | 5 | + | Easy | 10 | + | Medium | 15 | + + | Task Difficulty | DC | + |:------------------|:--:| + | Hard | 20 | + | Very hard | 25 | + | Nearly impossible | 30 | + }} + \n`; + } + } + ] + }, + /**************** FONTS *************/ + { + groupName : 'Fonts', + icon : 'fas fa-keyboard', + view : 'text', + snippets : [ + { + name : 'Open Sans', + icon : 'font OpenSans', + gen : dedent`{{font-family:OpenSans Dummy Text}}` + }, + { + name : 'Code Bold', + icon : 'font CodeBold', + gen : dedent`{{font-family:CodeBold Dummy Text}}` + }, + { + name : 'Code Light', + icon : 'font CodeLight', + gen : dedent`{{font-family:CodeLight Dummy Text}}` + }, + { + name : 'Scaly Sans', + icon : 'font ScalySansRemake', + gen : dedent`{{font-family:ScalySansRemake Dummy Text}}` + }, + { + name : 'Book Insanity', + icon : 'font BookInsanityRemake', + gen : dedent`{{font-family:BookInsanityRemake Dummy Text}}` + }, + { + name : 'Mr Eaves', + icon : 'font MrEavesRemake', + gen : dedent`{{font-family:MrEavesRemake Dummy Text}}` + }, + { + name : 'Pagella', + icon : 'font Pagella', + gen : dedent`{{font-family:Pagella Dummy Text}}` + }, + { + name : 'Solbera Imitation', + icon : 'font SolberaImitationRemake', + gen : dedent`{{font-family:SolberaImitationRemake Dummy Text}}` + }, + { + name : 'Scaly Sans Small Caps', + icon : 'font ScalySansSmallCapsRemake', + gen : dedent`{{font-family:ScalySansSmallCapsRemake Dummy Text}}` + }, + { + name : 'Walter Turncoat', + icon : 'font WalterTurncoat', + gen : dedent`{{font-family:WalterTurncoat Dummy Text}}` + }, + { + name : 'Lato', + icon : 'font Lato', + gen : dedent`{{font-family:Lato Dummy Text}}` + }, + { + name : 'Courier', + icon : 'font Courier', + gen : dedent`{{font-family:Courier Dummy Text}}` + }, + { + name : 'Nodesto Caps Condensed', + icon : 'font NodestoCapsCondensed', + gen : dedent`{{font-family:NodestoCapsCondensed Dummy Text}}` + }, + { + name : 'Overpass', + icon : 'font Overpass', + gen : dedent`{{font-family:Overpass Dummy Text}}` + }, + { + name : 'Davek', + icon : 'font Davek', + gen : dedent`{{font-family:Davek Dummy Text}}` + }, + { + name : 'Iokharic', + icon : 'font Iokharic', + gen : dedent`{{font-family:Iokharic Dummy Text}}` + }, + { + name : 'Rellanic', + icon : 'font Rellanic', + gen : dedent`{{font-family:Rellanic Dummy Text}}` + }, + { + name : 'Times New Roman', + icon : 'font TimesNewRoman', + gen : dedent`{{font-family:"Times New Roman" Dummy Text}}` + } + ] + }, + + /**************** LAYOUT *************/ + + { + groupName : 'Print', + icon : 'fas fa-print', + view : 'style', + snippets : [ + { + name : 'A3 Page Size', + icon : 'far fa-file', + gen : dedent`/* A3 Page Size */ + .page { + width : 297mm; + height : 420mm; + }\n\n`, + }, + { + name : 'A4 Page Size', + icon : 'far fa-file', + gen : dedent`/* A4 Page Size */ + .page { + width : 210mm; + height : 296.8mm; + }\n\n` + }, + { + name : 'A5 Page Size', + icon : 'far fa-file', + gen : dedent`/* A5 Page Size */ + .page { + width : 148mm; + height : 210mm; + }\n\n`, + }, + { + name : 'Square Page Size', + icon : 'far fa-file', + gen : dedent`/* Square Page Size */ + .page { + width : 125mm; + height : 125mm; + padding : 12.5mm; + columns : unset; + }\n\n` + }, + { + name : 'Card Page Size', + icon : 'far fa-file', + gen : dedent`/* Card Size */ + .page { + width : 63.5mm; + height : 88.9mm; + padding : 5mm; + columns : unset; + }\n\n` + }, + { + name : 'Ink Friendly', + icon : 'fas fa-tint', + gen : dedent` + /* Ink Friendly */ + *:is(.page) { + background : white !important; + filter : drop-shadow(0px 0px 3px #888) !important; + } + + .page img { + visibility : hidden; + }\n\n` + }, + ] + }, +]; diff --git a/themes/V4/Blank/snippets/footer.gen.js b/themes/V4/Blank/snippets/footer.gen.js new file mode 100644 index 000000000..9384baed7 --- /dev/null +++ b/themes/V4/Blank/snippets/footer.gen.js @@ -0,0 +1,17 @@ +import Markdown from '../../../../shared/naturalcrit/markdown.js'; + +module.exports = { + createFooterFunc : function(headerSize=1){ + return (props)=>{ + const cursorPos = props.cursorPos; + + const markdownText = props.brew.text.split('\n').slice(0, cursorPos.line).join('\n'); + const markdownTokens = Markdown.marked.lexer(markdownText); + const headerToken = markdownTokens.findLast((lexerToken)=>{ return lexerToken.type === 'heading' && lexerToken.depth === headerSize; }); + const headerText = headerToken?.tokens.map((token)=>{ return token.text; }).join(''); + const outputText = headerText || 'PART 1 | SECTION NAME'; + + return `\n{{footnote ${outputText}}}\n`; + }; + } +}; \ No newline at end of file diff --git a/themes/V4/Blank/snippets/imageMask.gen.js b/themes/V4/Blank/snippets/imageMask.gen.js new file mode 100644 index 000000000..323f89a1f --- /dev/null +++ b/themes/V4/Blank/snippets/imageMask.gen.js @@ -0,0 +1,46 @@ +const _ = require('lodash'); +const dedent = require('dedent-tabs').default; + +module.exports = { + center : ()=>{ + return dedent` + {{imageMaskCenter${_.random(1, 16)},--offsetX:0%,--offsetY:0%,--rotation:0 + ![](https://i.imgur.com/GZfjDWV.png){height:100%} + }} + \n\n`; + }, + + edge : (side = 'bottom')=>{ + const rotation = { + 'bottom' : 0, + 'top' : 180, + 'left' : 90, + 'right' : 270 + }[side]; + return dedent` + {{imageMaskEdge${_.random(1, 8)},--offset:0%,--rotation:${rotation} + ![](https://i.imgur.com/GZfjDWV.png){height:100%} + }} + \n\n`; + }, + + corner : (y = 'top', x = 'left')=>{ + const offsetX = (x == 'left' ? '-50%' : '50%'); + const offsetY = (y == 'top' ? '50%' : '-50%'); + return dedent` + {{imageMaskCorner${_.random(1, 37)},--offsetX:${offsetX},--offsetY:${offsetY},--rotation:0 + ![](https://i.imgur.com/GZfjDWV.png){height:100%} + }} + \n\n`; + } + +}; + +()=>{ + +}; diff --git a/themes/V4/Blank/snippets/watercolor.gen.js b/themes/V4/Blank/snippets/watercolor.gen.js new file mode 100644 index 000000000..735a35602 --- /dev/null +++ b/themes/V4/Blank/snippets/watercolor.gen.js @@ -0,0 +1,5 @@ +const _ = require('lodash'); + +module.exports = ()=>{ + return `{{watercolor${_.random(1, 12)},top:20px,left:30px,width:300px,background-color:#BBAD82,opacity:80%}}\n\n`; +}; diff --git a/themes/V4/Blank/style.less b/themes/V4/Blank/style.less new file mode 100644 index 000000000..68d2ff07d --- /dev/null +++ b/themes/V4/Blank/style.less @@ -0,0 +1,524 @@ +@import (less) './themes/fonts/Blank/fonts.less'; +@import (less) './themes/fonts/5e/fonts.less'; +@import (less) './themes/assets/assets.less'; +@import (less) './themes/fonts/iconFonts/elderberryInn.less'; +@import (less) './themes/fonts/iconFonts/diceFont.less'; +@import (less) './themes/fonts/iconFonts/gameIcons.less'; +@import (less) './themes/fonts/iconFonts/fontAwesome.less'; + +:root { + //Colors + --HB_Color_Background : #FFFFFF; // White + --HB_Color_WatercolorStain : #000000; // Black +} + +@page { margin : 0; } +body { counter-reset : page-numbers 0; } +* { -webkit-print-color-adjust : exact; } + +//***************************** +// * MUSTACHE DIVS/SPANS +// *****************************/ +.page { + .block { + break-inside : avoid; + display : inline-block; + width : 100%; + img { z-index : 0; } + } + .inline-block { + display : inline-block; + text-indent : initial; + } +} + +.useColumns(@multiplier : 1, @fillMode: auto) { + column-fill : @fillMode; + column-count : 2; +} +.columnWrapper { + column-gap : inherit; + max-height : 100%; + column-span : all; + columns : inherit; + column-fill : inherit; +} +.page { + .useColumns(); + position : relative; + z-index : 15; + box-sizing : border-box; + width : 215.9mm; + height : 279.4mm; + padding : 1.4cm 1.9cm 1.7cm; + overflow : hidden; + background-color : var(--HB_Color_Background); + text-rendering : optimizeLegibility; + contain : size; +} +//***************************** +// * BASE + // *****************************/ +.page { + p { + display : block; + overflow-wrap : break-word; + } + strong { font-weight : bold; } + em { font-style : italic; } + sup { + font-size : smaller; + line-height : 0; + vertical-align : super; + } + sub { + font-size : smaller; + line-height : 0; + vertical-align : sub; + } + ul { + padding-left : 1.4em; + list-style-position : outside; //Needed for multiline list items + list-style-type : disc; + } + ol { + padding-left : 1.4em; + list-style-position : outside; + list-style-type : decimal; + } + img { z-index : -1; } + + //***************************** + // * HEADERS + // *****************************/ + h1,h2,h3,h4,h5,h6 { + font-weight : bold; + line-height : 1.2em; + } + h1 { font-size : 2em; } + h2 { font-size : 1.5em; } + h3 { font-size : 1.17em; } + h4 { font-size : 1em; } + h5 { font-size : 0.83em; } + //***************************** + // * TABLE + // *****************************/ + table { + width : 100%; + thead { + display : table-row-group; + font-weight : bold; + } + } + div:not(.columnWrapper) > table + table { // Side-by-side tables should not + margin-top : 0; // have vertical spacing. + } + + //************************************ + // * CODE BLOCKS + // ************************************/ + code { + font-family : 'Courier New', "Courier", monospace; + overflow-wrap : break-word; + white-space : pre-wrap; + } + + pre code { + display : inline-block; + width : 100%; + } + //***************************** + // * EXTRAS + // *****************************/ + .columnSplit { + margin-top : 0; + visibility : hidden; + -webkit-column-break-after : always; + break-after : always; + -moz-column-break-after : always; + & + * { margin-top : 0; } + } + //Avoid breaking up + blockquote,table { + z-index : 15; + -webkit-column-break-inside : avoid; + page-break-inside : avoid; + break-inside : avoid; + } + // Nested lists + ul ul,ol ol,ul ol,ol ul { + margin-bottom : 0px; + margin-left : 1.5em; + } + li { + -webkit-column-break-inside : avoid; + page-break-inside : avoid; + break-inside : avoid; + } + + /* Wrap Text */ + .wrapLeft { + shape-outside : var(--HB_src); + float : right; + shape-margin : 0.2cm; + } + + .wrapRight { + shape-outside : var(--HB_src); + float : left; + shape-margin : 0.2cm; + } + + /* Watermark */ + .watermark { + position : absolute; + top : 0; + left : 0; + z-index : 500; + display : grid !important; + place-items : center; + justify-content : center; + width : 100%; + height : 100%; + margin : 0; + font-size : 120px; + text-transform : uppercase; + opacity : 30%; + transform : rotate(-45deg); + p { margin-bottom : none; } + } + + /* Watercolor */ + [class*='watercolor'] { + position : absolute; + z-index : -2; + width : 2000px; /* dimensions need to be real big so the user can set */ + height : 2000px; /* height or width and the image will maintain aspect ratio */ + background-color : var(--HB_Color_WatercolorStain); /* default color */ + background-size : cover; + -webkit-mask-image : var(--wc); + -webkit-mask-size : contain; + -webkit-mask-repeat : no-repeat; + mask-image : var(--wc); + mask-size : contain; + mask-repeat : no-repeat; + --wc : @watercolor1; /* default image */ + } + + .watercolor1 { --wc : @watercolor1; } + .watercolor2 { --wc : @watercolor2; } + .watercolor3 { --wc : @watercolor3; } + .watercolor4 { --wc : @watercolor4; } + .watercolor5 { --wc : @watercolor5; } + .watercolor6 { --wc : @watercolor6; } + .watercolor7 { --wc : @watercolor7; } + .watercolor8 { --wc : @watercolor8; } + .watercolor9 { --wc : @watercolor9; } + .watercolor10 { --wc : @watercolor10; } + .watercolor11 { --wc : @watercolor11; } + .watercolor12 { --wc : @watercolor12; } + + /* Image Masks */ + + [class*='imageMask'] { + position : absolute; + bottom : 50%; + left : 50%; + z-index : -1; + width : 200%; + height : 200%; + background-image : var(--checkerboard); + background-size : 20px; + transform : translateY(50%) translateX(-50%) rotate(calc(1deg * var(--rotation))) scaleX(var(--scaleX)) scaleY(var(--scaleY)); + -webkit-mask-image : var(--wc), var(--revealer); + -webkit-mask-repeat : repeat-x; + -webkit-mask-size : 50%; //Scale only X to fit page width, leave height at aspect ratio, designed to hang off the edge + -webkit-mask-position : 50% calc(50% - var(--offset)); + mask-image : var(--wc); + mask-repeat : repeat-x; + mask-size : 50%; + mask-position : 50% calc(50% - var(--offset)); + --rotation : 0; + --revealer : none; + --checkerboard : none; + --scaleX : 1; + --scaleY : 1; + & > p:has(img) { + position : absolute; + bottom : 50%; + left : 50%; + width : 50%; + height : 50%; + transform : translateX(-50%) translateY(50%) scaleX(calc(1 / var(--scaleX))) scaleY(calc(1 / var(--scaleY))) rotate(calc(-1deg * var(--rotation))); + } + & img { + position : absolute; + bottom : 0; + display : block; + } + &.bottom { + --rotation : 0; + & img {bottom : 0;} + } + &.top { + --rotation : 180; + & img {top : 0;} + } + &.left { + --rotation : 90; + & img {left : 0;} + } + &.right { + --rotation : -90; + & img {right : 0;} + } + &.revealImage { + --revealer : linear-gradient(0deg, rgba(0,0,0,0.2) 0%, rgba(0,0,0,0.2)); + --checkerboard : url("/assets/waterColorMasks/missingImage.png"); //shows any masked regions not filled by image + } + } + + .imageMaskEdge { + &1 { --wc : url("/assets/waterColorMasks/edge/0001.webp"); } + &2 { --wc : url("/assets/waterColorMasks/edge/0002.webp"); } + &3 { --wc : url("/assets/waterColorMasks/edge/0003.webp"); } + &4 { --wc : url("/assets/waterColorMasks/edge/0004.webp"); } + &5 { --wc : url("/assets/waterColorMasks/edge/0005.webp"); } + &6 { --wc : url("/assets/waterColorMasks/edge/0006.webp"); } + &7 { --wc : url("/assets/waterColorMasks/edge/0007.webp"); } + &8 { --wc : url("/assets/waterColorMasks/edge/0008.webp"); } + } + + [class*='imageMaskCenter'] { + bottom : calc(var(--offsetY)); + left : calc(var(--offsetX)); + width : 100%; + height : 100%; + transform : rotate(calc(1deg * var(--rotation))) scaleX(var(--scaleX)) scaleY(var(--scaleY)); + -webkit-mask-image : var(--wc), var(--revealer); + -webkit-mask-repeat : no-repeat; + -webkit-mask-size : 100% 100%; //Scale both dimensions to fit page size + -webkit-mask-position : 0% 0%; + mask-image : var(--wc), var(--revealer); + mask-repeat : no-repeat; + mask-size : 100% 100%; //Scale both dimensions to fit page size + mask-position : 50% 50%; + + & > p:has(img) { + position : absolute; + bottom : 0; + left : 0; + width : 100%; + height : 100%; + transform : unset; + transform : scaleX(calc(1 / var(--scaleX))) scaleY(calc(1 / var(--scaleY))) + rotate(calc(-1deg * var(--rotation))) + translateX(calc(-1 * var(--offsetX))) + translateY(calc(1 * var(--offsetY))); + } + } + + .imageMaskCenter { + &1 { --wc : url("/assets/waterColorMasks/center/0001.webp"); } + &2 { --wc : url("/assets/waterColorMasks/center/0002.webp"); } + &3 { --wc : url("/assets/waterColorMasks/center/0003.webp"); } + &4 { --wc : url("/assets/waterColorMasks/center/0004.webp"); } + &5 { --wc : url("/assets/waterColorMasks/center/0005.webp"); } + &6 { --wc : url("/assets/waterColorMasks/center/0006.webp"); } + &7 { --wc : url("/assets/waterColorMasks/center/0007.webp"); } + &8 { --wc : url("/assets/waterColorMasks/center/0008.webp"); } + &9 { --wc : url("/assets/waterColorMasks/center/0009.webp"); } + &10 { --wc : url("/assets/waterColorMasks/center/0010.webp"); } + &11 { --wc : url("/assets/waterColorMasks/center/0011.webp"); } + &12 { --wc : url("/assets/waterColorMasks/center/0012.webp"); } + &13 { --wc : url("/assets/waterColorMasks/center/0013.webp"); } + &14 { --wc : url("/assets/waterColorMasks/center/0014.webp"); } + &15 { --wc : url("/assets/waterColorMasks/center/0015.webp"); } + &16 { --wc : url("/assets/waterColorMasks/center/0016.webp"); } + &special { --wc : url("/assets/waterColorMasks/center/special.webp"); } + } + + + [class*='imageMaskCorner'] { + bottom : calc(-50% + var(--offsetY)); + left : calc(-50% + var(--offsetX)); + width : 200%; + height : 200%; + transform : rotate(calc(1deg * var(--rotation))) scaleX(var(--scaleX)) scaleY(var(--scaleY)); + -webkit-mask-image : var(--wc), var(--revealer); + -webkit-mask-repeat : no-repeat; + -webkit-mask-size : 100% 100%; //Scale both dimensions to fit page size + -webkit-mask-position : 50% 50%; + mask-image : var(--wc), var(--revealer); + mask-repeat : no-repeat; + mask-size : 100% 100%; //Scale both dimensions to fit page size + mask-position : 50% 50%; + & > p:has(img) { + bottom : 25%; + left : 25%; + width : 50%; + height : 50%; //Complex transform below to handle mix of % and cm offsets + transform : scaleX(calc(1 / var(--scaleX))) scaleY(calc(1 / var(--scaleY))) + rotate(calc(-1deg * var(--rotation))) + translateX(calc(-1 * var(--offsetX))) + translateY(calc(1 * var(--offsetY))); + } + } + .imageMaskCorner { + &1 { --wc : url("/assets/waterColorMasks/corner/0001.webp"); } + &2 { --wc : url("/assets/waterColorMasks/corner/0002.webp"); } + &3 { --wc : url("/assets/waterColorMasks/corner/0003.webp"); } + &4 { --wc : url("/assets/waterColorMasks/corner/0004.webp"); } + &5 { --wc : url("/assets/waterColorMasks/corner/0005.webp"); } + &6 { --wc : url("/assets/waterColorMasks/corner/0006.webp"); } + &7 { --wc : url("/assets/waterColorMasks/corner/0007.webp"); } + &8 { --wc : url("/assets/waterColorMasks/corner/0008.webp"); } + &9 { --wc : url("/assets/waterColorMasks/corner/0009.webp"); } + &10 { --wc : url("/assets/waterColorMasks/corner/0010.webp"); } + &11 { --wc : url("/assets/waterColorMasks/corner/0011.webp"); } + &12 { --wc : url("/assets/waterColorMasks/corner/0012.webp"); } + &13 { --wc : url("/assets/waterColorMasks/corner/0013.webp"); } + &14 { --wc : url("/assets/waterColorMasks/corner/0014.webp"); } + &15 { --wc : url("/assets/waterColorMasks/corner/0015.webp"); } + &16 { --wc : url("/assets/waterColorMasks/corner/0016.webp"); } + &17 { --wc : url("/assets/waterColorMasks/corner/0017.webp"); } + &18 { --wc : url("/assets/waterColorMasks/corner/0018.webp"); } + &19 { --wc : url("/assets/waterColorMasks/corner/0019.webp"); } + &20 { --wc : url("/assets/waterColorMasks/corner/0020.webp"); } + &21 { --wc : url("/assets/waterColorMasks/corner/0021.webp"); } + &22 { --wc : url("/assets/waterColorMasks/corner/0022.webp"); } + &23 { --wc : url("/assets/waterColorMasks/corner/0023.webp"); } + &24 { --wc : url("/assets/waterColorMasks/corner/0024.webp"); } + &25 { --wc : url("/assets/waterColorMasks/corner/0025.webp"); } + &26 { --wc : url("/assets/waterColorMasks/corner/0026.webp"); } + &27 { --wc : url("/assets/waterColorMasks/corner/0027.webp"); } + &28 { --wc : url("/assets/waterColorMasks/corner/0028.webp"); } + &29 { --wc : url("/assets/waterColorMasks/corner/0029.webp"); } + &30 { --wc : url("/assets/waterColorMasks/corner/0030.webp"); } + &31 { --wc : url("/assets/waterColorMasks/corner/0031.webp"); } + &32 { --wc : url("/assets/waterColorMasks/corner/0032.webp"); } + &33 { --wc : url("/assets/waterColorMasks/corner/0033.webp"); } + &34 { --wc : url("/assets/waterColorMasks/corner/0034.webp"); } + &35 { --wc : url("/assets/waterColorMasks/corner/0035.webp"); } + &36 { --wc : url("/assets/waterColorMasks/corner/0036.webp"); } + &37 { --wc : url("/assets/waterColorMasks/corner/0037.webp"); } + } +} + +//***************************** +// * DEFINITION LISTS +// *****************************/ +.page { + dl { + padding-left : 1em; + white-space : pre-line; + } + dt { + display : inline; + margin-right : 0.5ch; + margin-left : -1em; + } + dd { + display : inline; + margin-left : 0; + text-indent : 0; + } +} + +//***************************** +// * BLANK LINE +// *****************************/ +.page { + .blank { + height : 1em; + margin-top : 0; + & + * { margin-top : 0; } + } +} + +//***************************** +// * WIDE +// *****************************/ +.page { + .wide { + column-span : all; + display : block; + margin-bottom : 1em; + & + * { margin-top : 0; } + } +} + +//***************************** +//* CREDITS +//*****************************/ +.page .homebreweryCredits { + p { + font-family : 'NodestoCapsWide'; + font-size : 0.4cm; + line-height : 1em; + text-align : center; + text-indent : 0; + letter-spacing : 0.08em; + } + a { + color : inherit; + text-decoration : none; + &:hover { text-decoration : underline; } + } + .homebreweryIcon { + display : block; + height : 1.5cm; + margin : 0 auto; + background-color : black; + -webkit-mask : url("/assets/naturalCritLogoWhite.svg") center / contain no-repeat; + mask : url("/assets/naturalCritLogoWhite.svg") center / contain no-repeat; + } + .homebreweryIcon.red { background-color : red; } + .homebreweryIcon.gold { background-image : linear-gradient(to top left, brown 22.5%, gold 40%, white 60%, gold 67.5%, brown 82.5%); } +} + +//***************************** +//* Page Number +//*****************************/ +.page { + .pageNumber { + position : absolute; + right : 30px; + bottom : 30px; + width : 50px; + font-size : 0.9em; + text-align : center; + &.auto::after { content : counter(page-numbers); } + } + + &:nth-child(even) { + .pageNumber { left : 30px; } + } + + .resetCounting { + counter-set : page-numbers 1; + } + + &:not(:has(.skipCounting)) { + counter-increment : page-numbers; + } + +} + +//***************************** +//* Forced Justification +//*****************************/ + +.page { + .mdParagraphJustifyLeft { + text-align: left; + } + + .mdParagraphJustifyRight { + text-align: right; + } + + .mdParagraphJustifyCenter { + text-align: center; + } +} diff --git a/themes/themes.json b/themes/themes.json index 16a4b9b13..46b6e57c3 100644 --- a/themes/themes.json +++ b/themes/themes.json @@ -36,5 +36,14 @@ "baseSnippets": "5ePHB", "path": "Journal" } + }, + "V4": { + "Blank": { + "name": "Blank", + "renderer": "V3", + "baseTheme": false, + "baseSnippets": false, + "path": "Blank" + } } } \ No newline at end of file From c5935ec262c3c59fd5db441df868655eb0232232 Mon Sep 17 00:00:00 2001 From: David Bolack Date: Sat, 23 Nov 2024 01:57:07 -0600 Subject: [PATCH 067/398] Add Snippets to /new --- client/homebrew/pages/homePage/homePage.jsx | 3 ++- client/homebrew/pages/newPage/newPage.jsx | 16 +++++++++++++++- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/client/homebrew/pages/homePage/homePage.jsx b/client/homebrew/pages/homePage/homePage.jsx index 00d0c801d..0a598556a 100644 --- a/client/homebrew/pages/homePage/homePage.jsx +++ b/client/homebrew/pages/homePage/homePage.jsx @@ -108,7 +108,8 @@ const HomePage = createClass({ onTextChange={this.handleTextChange} renderer={this.state.brew.renderer} showEditButtons={false} - snippetBundle={this.state.themeBundle.snippets} + snippets={this.props.snippets} + themeBundle={this.state.themeBundle} onCursorPageChange={this.handleEditorCursorPageChange} onViewPageChange={this.handleEditorViewPageChange} currentEditorViewPageNum={this.state.currentEditorViewPageNum} diff --git a/client/homebrew/pages/newPage/newPage.jsx b/client/homebrew/pages/newPage/newPage.jsx index ee2c67d5f..ca31e03a5 100644 --- a/client/homebrew/pages/newPage/newPage.jsx +++ b/client/homebrew/pages/newPage/newPage.jsx @@ -141,6 +141,18 @@ const NewPage = createClass({ localStorage.setItem(STYLEKEY, style); }, + handleSnipChange : function(snippet){ + //If there are errors, run the validator on every change to give quick feedback + let htmlErrors = this.state.htmlErrors; + if(htmlErrors.length) htmlErrors = Markdown.validate(snippet); + + this.setState((prevState)=>({ + brew : { ...prevState.brew, snippets: snippet }, + isPending : true, + htmlErrors : htmlErrors, + }), ()=>{if(this.state.autoSave) this.trySave();}); + }, + handleMetaChange : function(metadata, field=undefined){ if(field == 'theme' || field == 'renderer') // Fetch theme bundle only if theme or renderer was changed fetchThemeBundle(this, metadata.renderer, metadata.theme); @@ -231,9 +243,11 @@ const NewPage = createClass({ onTextChange={this.handleTextChange} onStyleChange={this.handleStyleChange} onMetaChange={this.handleMetaChange} + onSnipChange={this.handleSnipChange} renderer={this.state.brew.renderer} userThemes={this.props.userThemes} - snippetBundle={this.state.themeBundle.snippets} + snippets={this.props.snippets} + themeBundle={this.state.themeBundle} onCursorPageChange={this.handleEditorCursorPageChange} onViewPageChange={this.handleEditorViewPageChange} currentEditorViewPageNum={this.state.currentEditorViewPageNum} From b6e445c445355d60bc272fd20628fd0d7ab14cc3 Mon Sep 17 00:00:00 2001 From: David Bolack Date: Sun, 24 Nov 2024 18:13:32 -0600 Subject: [PATCH 068/398] Convert storage of snippets in Brew to yaml by request. --- server/homebrew.api.js | 16 ++++++----- shared/helpers.js | 64 ++++++++++++++++++++++++++++-------------- 2 files changed, 52 insertions(+), 28 deletions(-) diff --git a/server/homebrew.api.js b/server/homebrew.api.js index 42d4efca3..b0532e392 100644 --- a/server/homebrew.api.js +++ b/server/homebrew.api.js @@ -8,9 +8,11 @@ import Markdown from '../shared/naturalcrit/markdown.js'; import yaml from 'js-yaml'; import asyncHandler from 'express-async-handler'; import { nanoid } from 'nanoid'; -import { splitTextStyleAndMetadata } from '../shared/helpers.js'; +import { splitTextStyleAndMetadata, + brewSnippetsToJSON } from '../shared/helpers.js'; import checkClientVersion from './middleware/check-client-version.js'; + const router = express.Router(); import { DEFAULT_BREW, DEFAULT_BREW_LOAD } from './brewDefaults.js'; @@ -176,15 +178,15 @@ const api = { mergeBrewText : (brew)=>{ let text = brew.text; - if(brew.style !== undefined) { - text = `\`\`\`css\n` + - `${brew.style || ''}\n` + + if(brew.snippets !== undefined) { + text = `\`\`\`snippets\n` + + `${yaml.dump(brewSnippetsToJSON('brew_snippets', brew.snippets, null, false))}` + `\`\`\`\n\n` + `${text}`; } - if(brew.snippets !== undefined) { - text = `\`\`\`snippets\n` + - `${brew.snippets || ''}\n` + + if(brew.style !== undefined) { + text = `\`\`\`css\n` + + `${brew.style || ''}\n` + `\`\`\`\n\n` + `${text}`; } diff --git a/shared/helpers.js b/shared/helpers.js index be3c3331d..b6cbe2df8 100644 --- a/shared/helpers.js +++ b/shared/helpers.js @@ -3,7 +3,7 @@ import yaml from 'js-yaml'; import request from '../client/homebrew/utils/request-middleware.js'; // Convert the templates from a brew to a Snippets Structure. -const brewSnippetsToJSON = (menuTitle, userBrewSnippets, themeBundleSnippets)=>{ +const brewSnippetsToJSON = (menuTitle, userBrewSnippets, themeBundleSnippets=null, full=true)=>{ const textSplit = /^\\snippet /gm; const mpAsSnippets = []; // Snippets from Themes first. @@ -17,7 +17,7 @@ const brewSnippetsToJSON = (menuTitle, userBrewSnippets, themeBundleSnippets)=>{ userSnippets.push({ name : name.slice('\snippets'.length), icon : '', - gen : snips.slice(name.length + 1), + gen : snips.slice(name.length + 1).trim(), }); } } @@ -37,49 +37,71 @@ const brewSnippetsToJSON = (menuTitle, userBrewSnippets, themeBundleSnippets)=>{ const userSnippets = []; for (let snips of userBrewSnippets.trim().split(textSplit)) { let name = snips.split('\n')[0]; + let justSnippet = snips.slice(name.length + 1); + if(justSnippet.slice(-1) === '\n') { + justSnippet = justSnippet.slice(0, -1); + } if(name.length != 0) { - userSnippets.push({ + const subSnip = { name : name, - icon : '', - gen : snips.slice(name.length + 1), - }); + gen : justSnippet, + }; + // if(full) subSnip.icon = ''; + userSnippets.push(subSnip); } } if(userSnippets.length) { mpAsSnippets.push({ name : menuTitle, - icon : '', + // icon : '', subsnippets : userSnippets }); } } - return { - groupName : 'Brew Snippets', - icon : 'fas fa-th-list', - view : 'text', - snippets : mpAsSnippets + const returnObj = { + snippets : mpAsSnippets }; + + if(full) { + returnObj.groupName = 'Brew Snippets'; + returnObj.icon = 'fas fa-th-list'; + returnObj.view = 'text'; + } + + return returnObj; +}; + +const yamlSnippetsToText = (yamlObj)=>{ + if(typeof yamlObj == 'string') return yamlObj; + + let snippetsText = ''; + for (let snippet of yamlObj.snippets) { + for (let subSnippet of snippet.subsnippets) { + snippetsText = `${snippetsText}\\snippet ${subSnippet.name}\n${subSnippet.gen || ''}\n`; + } + } + return snippetsText; }; const splitTextStyleAndMetadata = (brew)=>{ brew.text = brew.text.replaceAll('\r\n', '\n'); if(brew.text.startsWith('```metadata')) { - const index = brew.text.indexOf('```\n\n'); - const metadataSection = brew.text.slice(12, index - 1); + const index = brew.text.indexOf('\n```\n\n'); + const metadataSection = brew.text.slice(11, index - 1); const metadata = yaml.load(metadataSection); Object.assign(brew, _.pick(metadata, ['title', 'description', 'tags', 'systems', 'renderer', 'theme', 'lang'])); - brew.text = brew.text.slice(index + 5); + brew.text = brew.text.slice(index + 6); } if(brew.text.startsWith('```css')) { - const index = brew.text.indexOf('```\n\n'); - brew.style = brew.text.slice(7, index - 1); - brew.text = brew.text.slice(index + 5); + const index = brew.text.indexOf('\n```\n\n'); + brew.style = brew.text.slice(6, index - 1); + brew.text = brew.text.slice(index + 6); } if(brew.text.startsWith('```snippets')) { - const index = brew.text.indexOf('```\n\n'); - brew.snippets = brew.text.slice(12, index - 1); - brew.text = brew.text.slice(index + 5); + const index = brew.text.indexOf('\n```\n\n'); + brew.snippets = yamlSnippetsToText(yaml.load(brew.text.slice(11, index - 1))).slice(0, -1); + brew.text = brew.text.slice(index + 6); } }; From 008b31e530166abbe7d9646af19b7a57747ef5cd Mon Sep 17 00:00:00 2001 From: David Bolack Date: Sun, 24 Nov 2024 18:58:50 -0600 Subject: [PATCH 069/398] Correct failing test. --- server/homebrew.api.spec.js | 2 +- shared/helpers.js | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/server/homebrew.api.spec.js b/server/homebrew.api.spec.js index 84ffc3052..2da940e40 100644 --- a/server/homebrew.api.spec.js +++ b/server/homebrew.api.spec.js @@ -908,7 +908,7 @@ brew`); }); describe('Get CSS', ()=>{ it('should return brew style content as CSS text', async ()=>{ - const testBrew = { title: 'test brew', text: '```css\n\nI Have a style!\n````\n\n' }; + const testBrew = { title: 'test brew', text: '```css\n\nI Have a style!\n```\n\n' }; const toBrewPromise = (brew)=>new Promise((res)=>res({ toObject: ()=>brew })); api.getId = jest.fn(()=>({ id: '1', googleId: undefined })); diff --git a/shared/helpers.js b/shared/helpers.js index b6cbe2df8..9b0b43084 100644 --- a/shared/helpers.js +++ b/shared/helpers.js @@ -88,19 +88,19 @@ const splitTextStyleAndMetadata = (brew)=>{ brew.text = brew.text.replaceAll('\r\n', '\n'); if(brew.text.startsWith('```metadata')) { const index = brew.text.indexOf('\n```\n\n'); - const metadataSection = brew.text.slice(11, index - 1); + const metadataSection = brew.text.slice(11, index + 1); const metadata = yaml.load(metadataSection); Object.assign(brew, _.pick(metadata, ['title', 'description', 'tags', 'systems', 'renderer', 'theme', 'lang'])); brew.text = brew.text.slice(index + 6); } if(brew.text.startsWith('```css')) { const index = brew.text.indexOf('\n```\n\n'); - brew.style = brew.text.slice(6, index - 1); + brew.style = brew.text.slice(7, index + 1); brew.text = brew.text.slice(index + 6); } if(brew.text.startsWith('```snippets')) { const index = brew.text.indexOf('\n```\n\n'); - brew.snippets = yamlSnippetsToText(yaml.load(brew.text.slice(11, index - 1))).slice(0, -1); + brew.snippets = yamlSnippetsToText(yaml.load(brew.text.slice(11, index + 1))).slice(0, -1); brew.text = brew.text.slice(index + 6); } }; From e763ae16313ff03713ea1f42f2c30af004d26929 Mon Sep 17 00:00:00 2001 From: David Bolack Date: Sun, 24 Nov 2024 21:57:59 -0600 Subject: [PATCH 070/398] t shouldn't have been saved... --- package-lock.json | 39 ++++++++++++++++++++++++++++++++------- package.json | 2 +- 2 files changed, 33 insertions(+), 8 deletions(-) diff --git a/package-lock.json b/package-lock.json index b20286889..589e7b661 100644 --- a/package-lock.json +++ b/package-lock.json @@ -34,7 +34,7 @@ "lodash": "^4.17.21", "marked": "11.2.0", "marked-emoji": "^1.4.3", - "marked-extended-tables": "^1.0.10", + "marked-extended-tables": "file:../marked-extended-tables", "marked-gfm-heading-id": "^3.2.0", "marked-smartypants-lite": "^1.0.2", "markedLegacy": "npm:marked@^0.3.19", @@ -71,6 +71,35 @@ "npm": "^10.8.x" } }, + "../marked-extended-tables": { + "version": "1.0.10", + "license": "MIT", + "devDependencies": { + "@babel/core": "^7.24.6", + "@babel/preset-env": "^7.25.4", + "@rollup/plugin-commonjs": "^26.0.1", + "@rollup/plugin-node-resolve": "^15.2.3", + "@semantic-release/changelog": "^6.0.3", + "@semantic-release/commit-analyzer": "^12.0.0", + "@semantic-release/git": "^10.0.1", + "@semantic-release/github": "^10.1.7", + "@semantic-release/npm": "^12.0.1", + "@semantic-release/release-notes-generator": "^13.0.0", + "babel-jest": "^29.5.0", + "eslint": "^8.57.0", + "eslint-config-standard": "^17.1.0", + "eslint-plugin-import": "^2.29.1", + "eslint-plugin-node": "^11.1.0", + "eslint-plugin-promise": "^6.1.1", + "jest-cli": "^29.7.0", + "marked": "^14.1.0", + "rollup": "^4.18.0", + "semantic-release": "^24.1.0" + }, + "peerDependencies": { + "marked": ">=3 <15" + } + }, "node_modules/@ampproject/remapping": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", @@ -10543,12 +10572,8 @@ } }, "node_modules/marked-extended-tables": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/marked-extended-tables/-/marked-extended-tables-1.0.10.tgz", - "integrity": "sha512-zvRS0GPTkxq8UWawSDecd1Rxd2KD8crrmq2QALGDdrgkcgRNQzHlbnlujBGuXxdgDJg7f6UTv+JpcfejBpKdSg==", - "peerDependencies": { - "marked": ">=3 <15" - } + "resolved": "../marked-extended-tables", + "link": true }, "node_modules/marked-gfm-heading-id": { "version": "3.2.0", diff --git a/package.json b/package.json index 8755d0699..87390b48d 100644 --- a/package.json +++ b/package.json @@ -106,7 +106,7 @@ "lodash": "^4.17.21", "marked": "11.2.0", "marked-emoji": "^1.4.3", - "marked-extended-tables": "^1.0.10", + "marked-extended-tables": "file:../marked-extended-tables", "marked-gfm-heading-id": "^3.2.0", "marked-smartypants-lite": "^1.0.2", "markedLegacy": "npm:marked@^0.3.19", From 74b4cb2afde0f97b02aa60781378670651bfe212 Mon Sep 17 00:00:00 2001 From: David Bolack Date: Mon, 25 Nov 2024 13:59:24 -0600 Subject: [PATCH 071/398] Revert local error in package.json --- package-lock.json | 40 ++++++++-------------------------------- package.json | 2 +- 2 files changed, 9 insertions(+), 33 deletions(-) diff --git a/package-lock.json b/package-lock.json index 589e7b661..e5f637e46 100644 --- a/package-lock.json +++ b/package-lock.json @@ -34,7 +34,7 @@ "lodash": "^4.17.21", "marked": "11.2.0", "marked-emoji": "^1.4.3", - "marked-extended-tables": "file:../marked-extended-tables", + "marked-extended-tables": "^1.0.10", "marked-gfm-heading-id": "^3.2.0", "marked-smartypants-lite": "^1.0.2", "markedLegacy": "npm:marked@^0.3.19", @@ -71,35 +71,6 @@ "npm": "^10.8.x" } }, - "../marked-extended-tables": { - "version": "1.0.10", - "license": "MIT", - "devDependencies": { - "@babel/core": "^7.24.6", - "@babel/preset-env": "^7.25.4", - "@rollup/plugin-commonjs": "^26.0.1", - "@rollup/plugin-node-resolve": "^15.2.3", - "@semantic-release/changelog": "^6.0.3", - "@semantic-release/commit-analyzer": "^12.0.0", - "@semantic-release/git": "^10.0.1", - "@semantic-release/github": "^10.1.7", - "@semantic-release/npm": "^12.0.1", - "@semantic-release/release-notes-generator": "^13.0.0", - "babel-jest": "^29.5.0", - "eslint": "^8.57.0", - "eslint-config-standard": "^17.1.0", - "eslint-plugin-import": "^2.29.1", - "eslint-plugin-node": "^11.1.0", - "eslint-plugin-promise": "^6.1.1", - "jest-cli": "^29.7.0", - "marked": "^14.1.0", - "rollup": "^4.18.0", - "semantic-release": "^24.1.0" - }, - "peerDependencies": { - "marked": ">=3 <15" - } - }, "node_modules/@ampproject/remapping": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", @@ -10572,8 +10543,13 @@ } }, "node_modules/marked-extended-tables": { - "resolved": "../marked-extended-tables", - "link": true + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/marked-extended-tables/-/marked-extended-tables-1.0.10.tgz", + "integrity": "sha512-zvRS0GPTkxq8UWawSDecd1Rxd2KD8crrmq2QALGDdrgkcgRNQzHlbnlujBGuXxdgDJg7f6UTv+JpcfejBpKdSg==", + "license": "MIT", + "peerDependencies": { + "marked": ">=3 <15" + } }, "node_modules/marked-gfm-heading-id": { "version": "3.2.0", diff --git a/package.json b/package.json index 87390b48d..8755d0699 100644 --- a/package.json +++ b/package.json @@ -106,7 +106,7 @@ "lodash": "^4.17.21", "marked": "11.2.0", "marked-emoji": "^1.4.3", - "marked-extended-tables": "file:../marked-extended-tables", + "marked-extended-tables": "^1.0.10", "marked-gfm-heading-id": "^3.2.0", "marked-smartypants-lite": "^1.0.2", "markedLegacy": "npm:marked@^0.3.19", From 73c68fd11c7517e465bf5bcf690ee24f190bb6f9 Mon Sep 17 00:00:00 2001 From: David Bolack Date: Wed, 27 Nov 2024 21:35:29 -0600 Subject: [PATCH 072/398] Functional first pass. Needs: - [ ] opinions on UI placement - [ ] opinions on best choice for displaying a write-in based User Brew ( flip to writin box? Add to drop-down list? ) --- .../editor/metadataEditor/metadataEditor.jsx | 35 ++++++++++++++++--- server/homebrew.api.js | 4 +-- 2 files changed, 33 insertions(+), 6 deletions(-) diff --git a/client/homebrew/editor/metadataEditor/metadataEditor.jsx b/client/homebrew/editor/metadataEditor/metadataEditor.jsx index bfc3b8b61..0405b942b 100644 --- a/client/homebrew/editor/metadataEditor/metadataEditor.jsx +++ b/client/homebrew/editor/metadataEditor/metadataEditor.jsx @@ -47,7 +47,8 @@ const MetadataEditor = createClass({ getInitialState : function(){ return { - showThumbnail : true + showThumbnail : true, + showThemeWritein : false }; }, @@ -57,6 +58,12 @@ const MetadataEditor = createClass({ }); }, + toggleThemeWritein : function(){ + this.setState({ + showThemeWritein : !this.state.showThemeWritein + }); + }, + renderThumbnail : function(){ if(!this.state.showThumbnail) return; return ; @@ -115,6 +122,12 @@ const MetadataEditor = createClass({ this.props.onChange(this.props.metadata, 'theme'); }, + handleThemeWritein : function(e) { + this.props.metadata.renderer = 'V3'; + this.props.metadata.theme = e.target.value; + this.props.onChange(this.props.metadata, 'theme'); + }, + handleLanguage : function(languageCode){ this.props.metadata.lang = languageCode; this.props.onChange(this.props.metadata); @@ -213,6 +226,7 @@ const MetadataEditor = createClass({ }); }; + const currentRenderer = this.props.metadata.renderer; const currentTheme = mergedThemes[`${_.upperFirst(this.props.metadata.renderer)}`][this.props.metadata.theme] ?? { name: `!!! THEME MISSING !!! ID=${this.props.metadata.theme}` }; @@ -234,10 +248,23 @@ const MetadataEditor = createClass({ return

- {dropdown} + {!this.state.showThemeWritein?dropdown:''} + + {this.renderThemeWritein()}
; }, + renderThemeWritein : function(){ + if(!this.state.showThemeWritein) return; + return this.handleThemeWritein(e)} />; + }, + renderLanguageDropdown : function(){ const langCodes = ['en', 'de', 'de-ch', 'fr', 'ja', 'es', 'it', 'sv', 'ru', 'zh-Hans', 'zh-Hant']; const listLanguages = ()=>{ @@ -345,7 +372,7 @@ const MetadataEditor = createClass({ placeholder='add tag' unique={true} values={this.props.metadata.tags} onChange={(e)=>this.handleFieldChange('tags', e)} - /> + />
@@ -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)} - /> + />

Privacy

diff --git a/server/homebrew.api.js b/server/homebrew.api.js index b8d4024ad..f997de1c4 100644 --- a/server/homebrew.api.js +++ b/server/homebrew.api.js @@ -1,6 +1,6 @@ /* eslint-disable max-lines */ import _ from 'lodash'; -import {model as HomebrewModel} from './homebrew.model.js'; +import { model as HomebrewModel } from './homebrew.model.js'; import express from 'express'; import zlib from 'zlib'; import GoogleActions from './googleActions.js'; @@ -302,7 +302,7 @@ const api = { splitTextStyleAndMetadata(currentTheme); // If there is anything in the snippets or style members, append them to the appropriate array - if(currentTheme?.snippets) completeSnippets.push(JSON.parse(currentTheme.snippets)); + // if(currentTheme?.snippets) completeSnippets.push(JSON.parse(currentTheme.snippets)); if(currentTheme?.style) completeStyles.push(`/* From Brew: ${req.protocol}://${req.get('host')}/share/${req.params.id} */\n\n${currentTheme.style}`); req.params.id = currentTheme.theme; From 43222b7651040e981ee09ffc3207b8e3027588ab Mon Sep 17 00:00:00 2001 From: David Bolack Date: Wed, 4 Dec 2024 21:41:04 -0600 Subject: [PATCH 073/398] Fix test --- server/homebrew.api.spec.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/homebrew.api.spec.js b/server/homebrew.api.spec.js index de0d35e40..0af9863aa 100644 --- a/server/homebrew.api.spec.js +++ b/server/homebrew.api.spec.js @@ -1005,7 +1005,7 @@ brew`); expect(testBrew.theme).toEqual('5ePHB'); expect(testBrew.lang).toEqual('en'); // Style - expect(testBrew.style).toEqual('style\nstyle\nstyle'); + expect(testBrew.style).toEqual('style\nstyle\nstyle\n'); // Text expect(testBrew.text).toEqual('text\n'); }); From 6e5f071f2273fec3450464c83d349c3e52f758af Mon Sep 17 00:00:00 2001 From: David Bolack Date: Tue, 10 Dec 2024 21:21:41 -0600 Subject: [PATCH 074/398] Move Properties icon to the end of the snippets bar. --- client/homebrew/editor/snippetbar/snippetbar.jsx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/client/homebrew/editor/snippetbar/snippetbar.jsx b/client/homebrew/editor/snippetbar/snippetbar.jsx index d252c7120..00a826bc1 100644 --- a/client/homebrew/editor/snippetbar/snippetbar.jsx +++ b/client/homebrew/editor/snippetbar/snippetbar.jsx @@ -262,14 +262,14 @@ const Snippetbar = createClass({ onClick={()=>this.props.onViewChange('style')}>
-
this.props.onViewChange('meta')}> - -
this.props.onViewChange('snip')}>
+
this.props.onViewChange('meta')}> + +
From dae297e0f54aa23333dbb3a9c1e19d3feabae223 Mon Sep 17 00:00:00 2001 From: David Bolack Date: Tue, 10 Dec 2024 21:52:38 -0600 Subject: [PATCH 075/398] Partially implement disabled BrewSnippets --- client/homebrew/editor/snippetbar/snippetbar.jsx | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/client/homebrew/editor/snippetbar/snippetbar.jsx b/client/homebrew/editor/snippetbar/snippetbar.jsx index 00a826bc1..1809d8f7b 100644 --- a/client/homebrew/editor/snippetbar/snippetbar.jsx +++ b/client/homebrew/editor/snippetbar/snippetbar.jsx @@ -217,8 +217,6 @@ const Snippetbar = createClass({ renderEditorButtons : function(){ if(!this.props.showEditButtons) return; - - return (
{this.props.view !== 'meta' && <>
@@ -324,10 +322,11 @@ const SnippetGroup = createClass({ }, render : function(){ + const groupName = `groupName ${this.props.snippets.length === 0 ? 'disabled' : ''}`; return
- {this.props.groupName} + {this.props.groupName}
{this.renderSnippets(this.props.snippets)} From 86856605b94d50eef6aced21447d00d8ecf583aa Mon Sep 17 00:00:00 2001 From: David Bolack Date: Tue, 10 Dec 2024 23:08:51 -0600 Subject: [PATCH 076/398] Add editor highlighting --- client/homebrew/editor/editor.jsx | 22 +++++++++++++++++++--- client/homebrew/editor/editor.less | 8 ++++++++ 2 files changed, 27 insertions(+), 3 deletions(-) diff --git a/client/homebrew/editor/editor.jsx b/client/homebrew/editor/editor.jsx index 95581e5d8..46fcf46c7 100644 --- a/client/homebrew/editor/editor.jsx +++ b/client/homebrew/editor/editor.jsx @@ -158,7 +158,7 @@ const Editor = createClass({ highlightCustomMarkdown : function(){ if(!this.codeEditor.current) return; - if(this.state.view === 'text') { + if((this.state.view === 'text') ||(this.state.view === 'snip')) { const codeMirror = this.codeEditor.current.codeMirror; codeMirror.operation(()=>{ // Batch CodeMirror styling @@ -178,8 +178,10 @@ 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 userSnippetCount = 1; // start snippet count from page 2 - _.forEach(this.props.brew.text.split('\n'), (line, lineNumber)=>{ + const whichSource = this.state.view === 'text' ? this.props.brew.text : this.props.brew.snippets; + _.forEach(whichSource.split('\n'), (line, lineNumber)=>{ //reset custom line styles codeMirror.removeLineClass(lineNumber, 'background', 'pageLine'); @@ -193,7 +195,7 @@ 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(/^\\page$/) && this.state.view === 'text')) { // add back the original class 'background' but also add the new class '.pageline' codeMirror.addLineClass(lineNumber, 'background', 'pageLine'); @@ -206,12 +208,26 @@ const Editor = createClass({ editorPageCount += 1; }; + // New Codemirror styling for V3 renderer if(this.props.renderer == 'V3') { if(line.match(/^\\column$/)){ codeMirror.addLineClass(lineNumber, 'text', 'columnSplit'); } + // Styling for \snippet breaks + if(this.state.view === 'snip' && line.match(/^\\snippet\ .*$/)) { + + // add back the original class 'background' but also add the new class '.snippetLine' + codeMirror.addLineClass(lineNumber, 'background', 'snippetLine'); + const userSnippetCountElement = Object.assign(document.createElement('span'), { + className : 'editor-snippet-count', + textContent : userSnippetCount + }); + codeMirror.setBookmark({ line: lineNumber, ch: line.length }, userSnippetCountElement); + + userSnippetCount += 1; + }; // definition lists if(line.includes('::')){ if(/^:*$/.test(line) == true){ return; }; diff --git a/client/homebrew/editor/editor.less b/client/homebrew/editor/editor.less index b2e96683e..a73b596d7 100644 --- a/client/homebrew/editor/editor.less +++ b/client/homebrew/editor/editor.less @@ -10,10 +10,18 @@ background : #33333328; border-top : #333399 solid 1px; } + .snippetLine { + background : #33333328; + border-top : #333399 solid 1px; + } .editor-page-count { float : right; color : grey; } + .editor-snippet-count { + float : right; + color : grey; + } .columnSplit { font-style : italic; color : grey; From 89bd0829675bac840bcfebd7a5a85231cf6b3567 Mon Sep 17 00:00:00 2001 From: David Bolack Date: Tue, 10 Dec 2024 23:28:06 -0600 Subject: [PATCH 077/398] Shift alignment assignment from CSS to HTML --- shared/naturalcrit/markdown.js | 8 ++++---- themes/themes.json | 9 --------- 2 files changed, 4 insertions(+), 13 deletions(-) diff --git a/shared/naturalcrit/markdown.js b/shared/naturalcrit/markdown.js index 5e81be3f0..6c76194cb 100644 --- a/shared/naturalcrit/markdown.js +++ b/shared/naturalcrit/markdown.js @@ -372,9 +372,9 @@ const superSubScripts = { const justifiedParagraphClasses = []; -justifiedParagraphClasses[2] = 'mdParagraphJustifyLeft'; -justifiedParagraphClasses[4] = 'mdParagraphJustifyRight'; -justifiedParagraphClasses[6] = 'mdParagraphJustifyCenter'; +justifiedParagraphClasses[2] = 'Left'; +justifiedParagraphClasses[4] = 'Right'; +justifiedParagraphClasses[6] = 'Center'; const justifiedParagraphs = { name : 'justifiedParagraphs', @@ -402,7 +402,7 @@ const justifiedParagraphs = { } }, renderer(token) { - return `

${this.parser.parseInline(token.tokens)}

`; + return `

${this.parser.parseInline(token.tokens)}

`; } }; diff --git a/themes/themes.json b/themes/themes.json index 46b6e57c3..16a4b9b13 100644 --- a/themes/themes.json +++ b/themes/themes.json @@ -36,14 +36,5 @@ "baseSnippets": "5ePHB", "path": "Journal" } - }, - "V4": { - "Blank": { - "name": "Blank", - "renderer": "V3", - "baseTheme": false, - "baseSnippets": false, - "path": "Blank" - } } } \ No newline at end of file From 7c69d2a74db3e7dd22a05a6b6c8d40d72498046d Mon Sep 17 00:00:00 2001 From: David Bolack Date: Tue, 10 Dec 2024 23:37:48 -0600 Subject: [PATCH 078/398] Update tests to match --- tests/markdown/justification.test.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/markdown/justification.test.js b/tests/markdown/justification.test.js index e3639eb81..48b311e85 100644 --- a/tests/markdown/justification.test.js +++ b/tests/markdown/justification.test.js @@ -6,17 +6,17 @@ describe('Justification', ()=>{ test('Left Justify', function() { const source = ':- Hello'; const rendered = Markdown.render(source); - expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe(`

Hello

`); + expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe(`

Hello

`); }); test('Right Justify', function() { const source = '-: Hello'; const rendered = Markdown.render(source); - expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe(`

Hello

`); + expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe(`

Hello

`); }); test('Center Justify', function() { const source = ':-: Hello'; const rendered = Markdown.render(source); - expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe(`

Hello

`); + expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe(`

Hello

`); }); test('Ignored inside a code block', function() { From 08b0f47ea25005d80579079b10cc1a8717da39f9 Mon Sep 17 00:00:00 2001 From: David Bolack Date: Tue, 17 Dec 2024 21:33:33 -0600 Subject: [PATCH 079/398] Fix Regex for Justified paragraphs --- shared/naturalcrit/markdown.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/shared/naturalcrit/markdown.js b/shared/naturalcrit/markdown.js index 6c76194cb..7a5c45d99 100644 --- a/shared/naturalcrit/markdown.js +++ b/shared/naturalcrit/markdown.js @@ -380,11 +380,10 @@ const justifiedParagraphs = { name : 'justifiedParagraphs', level : 'block', start(src) { - return src.match(/\n(?:-:|:-|:-:) {1}/m)?.index; - + return src.match(/\n(?:-:|:-|-:) {1}/m)?.index; }, // Hint to Marked.js to stop and check for a match tokenizer(src, tokens) { - const regex = /^((:- ).*)|((-: ).*)|((:-: ).*)(?:\n|$)/ym; + const regex = /^(((:-))|((-:))|((:-:))) .+\n([^\n].*\n)*\n/ygm; const match = regex.exec(src); if(match?.length) { let whichJustify; From 99d3d287543c84257e09e6432045dcf8ff4e40e9 Mon Sep 17 00:00:00 2001 From: David Bolack Date: Tue, 17 Dec 2024 21:48:11 -0600 Subject: [PATCH 080/398] Correct end of match criteria for justified paragraph to account for end of stream --- shared/naturalcrit/markdown.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/shared/naturalcrit/markdown.js b/shared/naturalcrit/markdown.js index 7a5c45d99..c87121ddc 100644 --- a/shared/naturalcrit/markdown.js +++ b/shared/naturalcrit/markdown.js @@ -383,7 +383,7 @@ const justifiedParagraphs = { return src.match(/\n(?:-:|:-|-:) {1}/m)?.index; }, // Hint to Marked.js to stop and check for a match tokenizer(src, tokens) { - const regex = /^(((:-))|((-:))|((:-:))) .+\n([^\n].*\n)*\n/ygm; + const regex = /^(((:-))|((-:))|((:-:))) .+(\n(([^\n].*\n)*(\n|$))|$)/ygm; const match = regex.exec(src); if(match?.length) { let whichJustify; @@ -396,7 +396,7 @@ const justifiedParagraphs = { length : match[whichJustify].length, text : match[0].slice(match[whichJustify].length), class : justifiedParagraphClasses[whichJustify], - tokens : this.lexer.inlineTokens(match[0].slice(match[whichJustify].length)) + tokens : this.lexer.inlineTokens(match[0].slice(match[whichJustify].length + 1)) }; } }, From 90632b78cefaee367b929b3f9ab6a6e33534e226 Mon Sep 17 00:00:00 2001 From: David Bolack Date: Fri, 20 Dec 2024 14:58:56 -0600 Subject: [PATCH 081/398] Add direct tests for paragraph justification --- package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/package.json b/package.json index 2ce79f112..76e00f809 100644 --- a/package.json +++ b/package.json @@ -39,6 +39,7 @@ "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", From 79c8309291180606615ac4f9824c446240dbd949 Mon Sep 17 00:00:00 2001 From: David Bolack Date: Fri, 20 Dec 2024 19:54:25 -0600 Subject: [PATCH 082/398] Add circleci --- .circleci/config.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.circleci/config.yml b/.circleci/config.yml index 2025e8fe7..c195df81c 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -73,6 +73,9 @@ jobs: - run: name: Test - Non-Breaking Spaces command: npm run test:non-breaking-spaces + - run: + name: Test - Paragraph Justification + command: npm run test:paragraph-justification - run: name: Test - Variables command: npm run test:variables From ed099aa061bef4ad783d64a459232beed0c12602 Mon Sep 17 00:00:00 2001 From: David Bolack Date: Fri, 20 Dec 2024 21:47:05 -0600 Subject: [PATCH 083/398] Disable the BrewSnippets menu if empty. --- client/homebrew/editor/snippetbar/snippetbar.jsx | 6 +++--- client/homebrew/editor/snippetbar/snippetbar.less | 7 +++++++ 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/client/homebrew/editor/snippetbar/snippetbar.jsx b/client/homebrew/editor/snippetbar/snippetbar.jsx index 1809d8f7b..b1fd02fd2 100644 --- a/client/homebrew/editor/snippetbar/snippetbar.jsx +++ b/client/homebrew/editor/snippetbar/snippetbar.jsx @@ -322,11 +322,11 @@ const SnippetGroup = createClass({ }, render : function(){ - const groupName = `groupName ${this.props.snippets.length === 0 ? 'disabled' : ''}`; - return
+ const snippetGroup = `snippetGroup snippetBarButton ${this.props.snippets.length === 0 ? 'disabledSnippets' : ''}`; + return
- {this.props.groupName} + {this.props.groupName}
{this.renderSnippets(this.props.snippets)} diff --git a/client/homebrew/editor/snippetbar/snippetbar.less b/client/homebrew/editor/snippetbar/snippetbar.less index 33242174b..3478dfde0 100644 --- a/client/homebrew/editor/snippetbar/snippetbar.less +++ b/client/homebrew/editor/snippetbar/snippetbar.less @@ -231,6 +231,13 @@ } } } + .disabledSnippets { + color: grey; + cursor: not-allowed; + + &:hover { background-color: #DDDDDD;} + } + } @container editor (width < 553px) { .snippetBar { From 7c357a2aa130a072cad58779c377d0888e61992c Mon Sep 17 00:00:00 2001 From: David Bolack Date: Sun, 29 Dec 2024 23:23:48 -0600 Subject: [PATCH 084/398] Attempt to save state but seems to break brew. --- .../editor/metadataEditor/metadataEditor.jsx | 13 ++++++++++--- .../editor/metadataEditor/metadataEditor.less | 2 +- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/client/homebrew/editor/metadataEditor/metadataEditor.jsx b/client/homebrew/editor/metadataEditor/metadataEditor.jsx index 0405b942b..0bd91ae35 100644 --- a/client/homebrew/editor/metadataEditor/metadataEditor.jsx +++ b/client/homebrew/editor/metadataEditor/metadataEditor.jsx @@ -40,6 +40,7 @@ const MetadataEditor = createClass({ theme : '5ePHB', lang : 'en' }, + onChange : ()=>{}, reportError : ()=>{} }; @@ -47,8 +48,10 @@ const MetadataEditor = createClass({ getInitialState : function(){ return { - showThumbnail : true, - showThemeWritein : false + showThumbnail : true, + showThemeWritein : false, + lastThemePulldown : '', + lastThemeWriteIn : '' }; }, @@ -60,8 +63,12 @@ const MetadataEditor = createClass({ toggleThemeWritein : function(){ this.setState({ - showThemeWritein : !this.state.showThemeWritein + showThemeWritein : !this.state.showThemeWritein, + // lastThemePulldown : !this.state.showThemeWritein ? this.props.metadata.theme : this.state.lastThemePulldown, + // lastThemeWriteIn : !this.state.showThemeWritein ? this.state.lastThemePulldown : this.props.metadata.theme }); + // if(this.state.showThemeWritein) this.props.metadata.theme = this.state.lastThemeWriteIn; + // else this.props.metadata.theme = this.state.lastThemePulldown; }, renderThumbnail : function(){ diff --git a/client/homebrew/editor/metadataEditor/metadataEditor.less b/client/homebrew/editor/metadataEditor/metadataEditor.less index 2cff01cfe..13397c89f 100644 --- a/client/homebrew/editor/metadataEditor/metadataEditor.less +++ b/client/homebrew/editor/metadataEditor/metadataEditor.less @@ -71,7 +71,7 @@ border : 1px solid gray; &:focus { outline : 1px solid #444444; } } - &.thumbnail { + &.thumbnail, &.themes{ height : 1.4em; label { line-height : 2.0em; } .value { From fe2d02a24c570c829eca48a7481cf7f99e245cbf Mon Sep 17 00:00:00 2001 From: David Bolack Date: Mon, 30 Dec 2024 12:28:47 -0600 Subject: [PATCH 085/398] Work in progress. Still issues with saving the state of the theme pulldowns and collecting the written in theme. --- .../editor/metadataEditor/metadataEditor.jsx | 27 +++++++++++++------ .../editor/metadataEditor/metadataEditor.less | 11 ++++++++ client/homebrew/pages/editPage/editPage.jsx | 5 ++-- 3 files changed, 33 insertions(+), 10 deletions(-) diff --git a/client/homebrew/editor/metadataEditor/metadataEditor.jsx b/client/homebrew/editor/metadataEditor/metadataEditor.jsx index 0bd91ae35..08b9c7165 100644 --- a/client/homebrew/editor/metadataEditor/metadataEditor.jsx +++ b/client/homebrew/editor/metadataEditor/metadataEditor.jsx @@ -62,13 +62,17 @@ const MetadataEditor = createClass({ }, toggleThemeWritein : function(){ + console.log('toggleThemeWritein'); this.setState({ showThemeWritein : !this.state.showThemeWritein, - // lastThemePulldown : !this.state.showThemeWritein ? this.props.metadata.theme : this.state.lastThemePulldown, - // lastThemeWriteIn : !this.state.showThemeWritein ? this.state.lastThemePulldown : this.props.metadata.theme + lastThemePulldown : this.state.showThemeWritein ? this.props.metadata.theme : this.state.lastThemePulldown, + lastThemeWriteIn : this.state.showThemeWritein ? this.state.lastThemePulldown : this.props.metadata.theme }); - // if(this.state.showThemeWritein) this.props.metadata.theme = this.state.lastThemeWriteIn; - // else this.props.metadata.theme = this.state.lastThemePulldown; + console.log(this.state); + console.log(this.props.metadata); + if(!this.state.showThemeWritein) this.props.metadata.theme = this.state.lastThemeWriteIn; + else this.props.metadata.theme = this.state.lastThemePulldown; + this.props.onChange(this.props.metadata, 'theme'); }, renderThumbnail : function(){ @@ -130,9 +134,13 @@ const MetadataEditor = createClass({ }, handleThemeWritein : function(e) { + console.log('Enter!'); this.props.metadata.renderer = 'V3'; this.props.metadata.theme = e.target.value; + console.log(e.target.value); + this.props.onChange(this.props.metadata, 'renderer'); this.props.onChange(this.props.metadata, 'theme'); + console.log(this.props.metadata); }, handleLanguage : function(languageCode){ @@ -214,6 +222,7 @@ const MetadataEditor = createClass({ if(!global.enable_themes) return; const mergedThemes = _.merge(Themes, this.props.userThemes); + console.log(mergedThemes); const listThemes = (renderer)=>{ return _.map(_.values(mergedThemes[renderer]), (theme)=>{ @@ -230,11 +239,11 @@ const MetadataEditor = createClass({
; - }); + }).filter(Boolean); }; - const currentRenderer = this.props.metadata.renderer; + console.log(this.props.metadata.theme); const currentTheme = mergedThemes[`${_.upperFirst(this.props.metadata.renderer)}`][this.props.metadata.theme] ?? { name: `!!! THEME MISSING !!! ID=${this.props.metadata.theme}` }; let dropdown; @@ -250,13 +259,14 @@ const MetadataEditor = createClass({
{currentTheme.author ?? _.upperFirst(currentRenderer)} : {currentTheme.name}
{listThemes(currentRenderer)} + {console.log(listThemes(currentRenderer))} ; } return
{!this.state.showThemeWritein?dropdown:''} - {this.renderThemeWritein()} @@ -268,7 +278,8 @@ const MetadataEditor = createClass({ return this.handleThemeWritein(e)} />; }, diff --git a/client/homebrew/editor/metadataEditor/metadataEditor.less b/client/homebrew/editor/metadataEditor/metadataEditor.less index 13397c89f..9f13fbc49 100644 --- a/client/homebrew/editor/metadataEditor/metadataEditor.less +++ b/client/homebrew/editor/metadataEditor/metadataEditor.less @@ -88,6 +88,17 @@ } } + &.themes{ + .value { + overflow : visible; + text-overflow : auto; + } + button { + padding-left: 5px; + padding-right: 5px; + } + } + &.description { flex : 1; textarea.value { diff --git a/client/homebrew/pages/editPage/editPage.jsx b/client/homebrew/pages/editPage/editPage.jsx index cf2b559c3..585d5205d 100644 --- a/client/homebrew/pages/editPage/editPage.jsx +++ b/client/homebrew/pages/editPage/editPage.jsx @@ -151,9 +151,10 @@ const EditPage = createClass({ }, handleMetaChange : function(metadata, field=undefined){ - if(field == 'theme' || field == 'renderer') // Fetch theme bundle only if theme or renderer was changed + if(field == 'theme' || field == 'renderer') {// Fetch theme bundle only if theme or renderer was changed + console.log(metadata); fetchThemeBundle(this, metadata.renderer, metadata.theme); - + } this.setState((prevState)=>({ brew : { ...prevState.brew, From b9f7e820c7d9f4320386941c54e8b3de1ebc384a Mon Sep 17 00:00:00 2001 From: David Bolack Date: Tue, 7 Jan 2025 20:36:38 -0600 Subject: [PATCH 086/398] Functionally? working. --- .../editor/metadataEditor/metadataEditor.jsx | 40 +++++++++---------- client/homebrew/pages/editPage/editPage.jsx | 1 - 2 files changed, 19 insertions(+), 22 deletions(-) diff --git a/client/homebrew/editor/metadataEditor/metadataEditor.jsx b/client/homebrew/editor/metadataEditor/metadataEditor.jsx index 08b9c7165..6d8755aba 100644 --- a/client/homebrew/editor/metadataEditor/metadataEditor.jsx +++ b/client/homebrew/editor/metadataEditor/metadataEditor.jsx @@ -16,6 +16,8 @@ const SYSTEMS = ['5e', '4e', '3.5e', 'Pathfinder']; const homebreweryThumbnail = require('../../thumbnail.png'); +let mergedThemes; + const callIfExists = (val, fn, ...args)=>{ if(val[fn]) { val[fn](...args); @@ -47,11 +49,12 @@ const MetadataEditor = createClass({ }, getInitialState : function(){ + mergedThemes = _.merge(Themes, this.props.userThemes); return { showThumbnail : true, - showThemeWritein : false, - lastThemePulldown : '', - lastThemeWriteIn : '' + showThemeWritein : mergedThemes[this.props.metadata.renderer][this.props.metadata.theme] ? false : true, + lastThemePulldown : mergedThemes[this.props.metadata.renderer][this.props.metadata.theme] ? mergedThemes[this.props.metadata.renderer][this.props.metadata.theme] : '', + lastThemeWriteIn : mergedThemes[this.props.metadata.renderer][this.props.metadata.theme] ? '' : mergedThemes[this.props.metadata.renderer][this.props.metadata.theme] }; }, @@ -62,17 +65,12 @@ const MetadataEditor = createClass({ }, toggleThemeWritein : function(){ - console.log('toggleThemeWritein'); - this.setState({ - showThemeWritein : !this.state.showThemeWritein, - lastThemePulldown : this.state.showThemeWritein ? this.props.metadata.theme : this.state.lastThemePulldown, - lastThemeWriteIn : this.state.showThemeWritein ? this.state.lastThemePulldown : this.props.metadata.theme - }); - console.log(this.state); - console.log(this.props.metadata); if(!this.state.showThemeWritein) this.props.metadata.theme = this.state.lastThemeWriteIn; else this.props.metadata.theme = this.state.lastThemePulldown; this.props.onChange(this.props.metadata, 'theme'); + this.setState({ + showThemeWritein : !this.state.showThemeWritein + }); }, renderThumbnail : function(){ @@ -130,17 +128,22 @@ const MetadataEditor = createClass({ handleTheme : function(theme){ this.props.metadata.renderer = theme.renderer; this.props.metadata.theme = theme.path; + this.setState({ + lastThemePulldown : theme.path + }); + this.props.onChange(this.props.metadata, 'theme'); }, handleThemeWritein : function(e) { - console.log('Enter!'); this.props.metadata.renderer = 'V3'; this.props.metadata.theme = e.target.value; - console.log(e.target.value); + this.setState({ + lastThemeWriteIn : e.target.value + }); + this.props.onChange(this.props.metadata, 'renderer'); this.props.onChange(this.props.metadata, 'theme'); - console.log(this.props.metadata); }, handleLanguage : function(languageCode){ @@ -221,9 +224,6 @@ const MetadataEditor = createClass({ renderThemeDropdown : function(){ if(!global.enable_themes) return; - const mergedThemes = _.merge(Themes, this.props.userThemes); - console.log(mergedThemes); - const listThemes = (renderer)=>{ return _.map(_.values(mergedThemes[renderer]), (theme)=>{ if(theme.path == this.props.metadata.shareId) return; @@ -243,9 +243,8 @@ const MetadataEditor = createClass({ }; const currentRenderer = this.props.metadata.renderer; - console.log(this.props.metadata.theme); const currentTheme = mergedThemes[`${_.upperFirst(this.props.metadata.renderer)}`][this.props.metadata.theme] - ?? { name: `!!! THEME MISSING !!! ID=${this.props.metadata.theme}` }; + ?? { name: `!!! Manually selected theme !!! ID=${this.props.metadata.theme}` }; let dropdown; if(currentRenderer == 'legacy') { @@ -259,7 +258,6 @@ const MetadataEditor = createClass({
{currentTheme.author ?? _.upperFirst(currentRenderer)} : {currentTheme.name}
{listThemes(currentRenderer)} - {console.log(listThemes(currentRenderer))} ; } @@ -279,7 +277,7 @@ const MetadataEditor = createClass({ default='' placeholder='Enter share id' className='value' - defaultValue={this.state.lastThemeWriteIn} + defaultValue={this.state.lastThemeWriteIn || this.props.metadata.theme} onChange={(e)=>this.handleThemeWritein(e)} />; }, diff --git a/client/homebrew/pages/editPage/editPage.jsx b/client/homebrew/pages/editPage/editPage.jsx index 585d5205d..ef6da5099 100644 --- a/client/homebrew/pages/editPage/editPage.jsx +++ b/client/homebrew/pages/editPage/editPage.jsx @@ -152,7 +152,6 @@ const EditPage = createClass({ handleMetaChange : function(metadata, field=undefined){ if(field == 'theme' || field == 'renderer') {// Fetch theme bundle only if theme or renderer was changed - console.log(metadata); fetchThemeBundle(this, metadata.renderer, metadata.theme); } this.setState((prevState)=>({ From 7516c0cbd31ffe2f2bf768cddd1cd3aefb65d50e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 8 Jan 2025 03:46:18 +0000 Subject: [PATCH 087/398] Bump core-js from 3.39.0 to 3.40.0 Bumps [core-js](https://github.com/zloirock/core-js/tree/HEAD/packages/core-js) from 3.39.0 to 3.40.0. - [Release notes](https://github.com/zloirock/core-js/releases) - [Changelog](https://github.com/zloirock/core-js/blob/master/CHANGELOG.md) - [Commits](https://github.com/zloirock/core-js/commits/v3.40.0/packages/core-js) --- updated-dependencies: - dependency-name: core-js dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- package-lock.json | 9 ++++----- package.json | 2 +- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/package-lock.json b/package-lock.json index da1759b43..13ed53773 100644 --- a/package-lock.json +++ b/package-lock.json @@ -19,7 +19,7 @@ "classnames": "^2.5.1", "codemirror": "^5.65.6", "cookie-parser": "^1.4.7", - "core-js": "^3.39.0", + "core-js": "^3.40.0", "cors": "^2.8.5", "create-react-class": "^15.7.0", "dedent-tabs": "^0.10.3", @@ -4619,11 +4619,10 @@ } }, "node_modules/core-js": { - "version": "3.39.0", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.39.0.tgz", - "integrity": "sha512-raM0ew0/jJUqkJ0E6e8UDtl+y/7ktFivgWvqw8dNSQeNWoSDLvQ1H/RN3aPXB9tBd4/FhyR4RDPGhsNIMsAn7g==", + "version": "3.40.0", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.40.0.tgz", + "integrity": "sha512-7vsMc/Lty6AGnn7uFpYT56QesI5D2Y/UkgKounk87OP9Z2H9Z8kj6jzcSGAxFmUtDOS0ntK6lbQz+Nsa0Jj6mQ==", "hasInstallScript": true, - "license": "MIT", "funding": { "type": "opencollective", "url": "https://opencollective.com/core-js" diff --git a/package.json b/package.json index 7acffcda8..1488d2103 100644 --- a/package.json +++ b/package.json @@ -93,7 +93,7 @@ "classnames": "^2.5.1", "codemirror": "^5.65.6", "cookie-parser": "^1.4.7", - "core-js": "^3.39.0", + "core-js": "^3.40.0", "cors": "^2.8.5", "create-react-class": "^15.7.0", "dedent-tabs": "^0.10.3", From 74122d90579812916b526626144f85ff9f7debba Mon Sep 17 00:00:00 2001 From: David Bolack Date: Tue, 7 Jan 2025 22:11:01 -0600 Subject: [PATCH 088/398] Display name of write in theme next to write-in Clear user's active ThemeBundle when an incomplete/broken/invalid writein. Needs theming help. --- client/homebrew/editor/editor.jsx | 1 + .../editor/metadataEditor/metadataEditor.jsx | 13 ++++++++----- .../editor/metadataEditor/metadataEditor.less | 4 ++++ client/homebrew/pages/editPage/editPage.jsx | 1 + server/homebrew.api.js | 6 +++++- shared/helpers.js | 15 +++++++++++++-- 6 files changed, 32 insertions(+), 8 deletions(-) diff --git a/client/homebrew/editor/editor.jsx b/client/homebrew/editor/editor.jsx index bba5f3ad9..3e37aba57 100644 --- a/client/homebrew/editor/editor.jsx +++ b/client/homebrew/editor/editor.jsx @@ -454,6 +454,7 @@ const Editor = createClass({ rerenderParent={this.rerenderParent} /> diff --git a/client/homebrew/editor/metadataEditor/metadataEditor.jsx b/client/homebrew/editor/metadataEditor/metadataEditor.jsx index 6d8755aba..694444bc9 100644 --- a/client/homebrew/editor/metadataEditor/metadataEditor.jsx +++ b/client/homebrew/editor/metadataEditor/metadataEditor.jsx @@ -53,8 +53,8 @@ const MetadataEditor = createClass({ return { showThumbnail : true, showThemeWritein : mergedThemes[this.props.metadata.renderer][this.props.metadata.theme] ? false : true, - lastThemePulldown : mergedThemes[this.props.metadata.renderer][this.props.metadata.theme] ? mergedThemes[this.props.metadata.renderer][this.props.metadata.theme] : '', - lastThemeWriteIn : mergedThemes[this.props.metadata.renderer][this.props.metadata.theme] ? '' : mergedThemes[this.props.metadata.renderer][this.props.metadata.theme] + lastThemePulldown : mergedThemes[this.props.metadata.renderer][this.props.metadata.theme] ? mergedThemes[this.props.metadata.renderer][this.props.metadata.theme].path : '', + lastThemeWriteIn : mergedThemes[this.props.metadata.renderer][this.props.metadata.theme] ? '' : this.props.metadata.theme }; }, @@ -244,7 +244,7 @@ const MetadataEditor = createClass({ const currentRenderer = this.props.metadata.renderer; const currentTheme = mergedThemes[`${_.upperFirst(this.props.metadata.renderer)}`][this.props.metadata.theme] - ?? { name: `!!! Manually selected theme !!! ID=${this.props.metadata.theme}` }; + ?? { name: `${this.props.themeBundle?.path || ''}`, author: '!!!' }; let dropdown; if(currentRenderer == 'legacy') { @@ -273,12 +273,15 @@ const MetadataEditor = createClass({ renderThemeWritein : function(){ if(!this.state.showThemeWritein) return; - return + this.handleThemeWritein(e)} />; + onChange={(e)=>this.handleThemeWritein(e)} /> + {`${this.state.lastThemeWriteIn ? this.props.themeBundle?.path || '' : ''}`} +
; }, renderLanguageDropdown : function(){ diff --git a/client/homebrew/editor/metadataEditor/metadataEditor.less b/client/homebrew/editor/metadataEditor/metadataEditor.less index 9f13fbc49..d06e420ae 100644 --- a/client/homebrew/editor/metadataEditor/metadataEditor.less +++ b/client/homebrew/editor/metadataEditor/metadataEditor.less @@ -1,5 +1,9 @@ @import 'naturalcrit/styles/colors.less'; +.userThemeName { + padding-left: 10px; + padding-right: 10px; +} .metadataEditor { position : absolute; diff --git a/client/homebrew/pages/editPage/editPage.jsx b/client/homebrew/pages/editPage/editPage.jsx index ef6da5099..7c7044832 100644 --- a/client/homebrew/pages/editPage/editPage.jsx +++ b/client/homebrew/pages/editPage/editPage.jsx @@ -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/server/homebrew.api.js b/server/homebrew.api.js index 8f0d143fa..8b4175491 100644 --- a/server/homebrew.api.js +++ b/server/homebrew.api.js @@ -279,6 +279,7 @@ const api = { let currentTheme; const completeStyles = []; const completeSnippets = []; + let themePath = ''; while (req.params.id) { //=== User Themes ===// @@ -292,6 +293,7 @@ const api = { currentTheme = req.brew; splitTextStyleAndMetadata(currentTheme); + if(themePath === '') themePath = currentTheme.title; // If there is anything in the snippets or style members, append them to the appropriate array // if(currentTheme?.snippets) completeSnippets.push(JSON.parse(currentTheme.snippets)); @@ -301,6 +303,7 @@ const api = { req.params.renderer = currentTheme.renderer; } else { //=== Static Themes ===// + if(themePath === '') themePath = req.params.id; const localSnippets = `${req.params.renderer}_${req.params.id}`; // Just log the name for loading on client const localStyle = `@import url(\"/themes/${req.params.renderer}/${req.params.id}/style.css\");`; completeSnippets.push(localSnippets); @@ -313,7 +316,8 @@ const api = { const returnObj = { // Reverse the order of the arrays so they are listed oldest parent to youngest child. styles : completeStyles.reverse(), - snippets : completeSnippets.reverse() + snippets : completeSnippets.reverse(), + path : themePath }; res.setHeader('Content-Type', 'application/json'); diff --git a/shared/helpers.js b/shared/helpers.js index b2190cdcd..3aff9538a 100644 --- a/shared/helpers.js +++ b/shared/helpers.js @@ -44,8 +44,13 @@ const fetchThemeBundle = async (obj, renderer, theme)=>{ .catch((err)=>{ obj.setState({ error: err }); }); - if(!res) return; - + if(!res) { + obj.setState((prevState)=>({ + ...prevState, + themeBundle : {} + })); + return; + } const themeBundle = res.body; themeBundle.joinedStyles = themeBundle.styles.map((style)=>``).join('\n\n'); obj.setState((prevState)=>({ @@ -54,8 +59,14 @@ const fetchThemeBundle = async (obj, renderer, theme)=>{ })); }; +const fetchBrewAsThemeJSON = async (renderer, theme)=>{ + if(!renderer || !theme) return; + +} + export { splitTextStyleAndMetadata, printCurrentBrew, fetchThemeBundle, + fetchBrewAsThemeJSON }; From 94a431eec8ffeed1340615d15e56a5136529040f Mon Sep 17 00:00:00 2001 From: David Bolack Date: Tue, 7 Jan 2025 22:28:12 -0600 Subject: [PATCH 089/398] Update tests. --- server/homebrew.api.spec.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/server/homebrew.api.spec.js b/server/homebrew.api.spec.js index 8270b1568..d6433bced 100644 --- a/server/homebrew.api.spec.js +++ b/server/homebrew.api.spec.js @@ -587,6 +587,7 @@ brew`); expect(res.status).toHaveBeenCalledWith(200); expect(res.send).toHaveBeenCalledWith({ + path : 'User Theme A', styles : ['/* From Brew: https://localhost/share/userThemeAID */\n\nUser Theme A Style'], snippets : [] }); @@ -607,6 +608,7 @@ brew`); expect(res.status).toHaveBeenCalledWith(200); expect(res.send).toHaveBeenCalledWith({ + path : 'User Theme A', styles : [ '/* From Brew: https://localhost/share/userThemeCID */\n\nUser Theme C Style', '/* From Brew: https://localhost/share/userThemeBID */\n\nUser Theme B Style', @@ -623,6 +625,7 @@ brew`); expect(res.status).toHaveBeenCalledWith(200); expect(res.send).toHaveBeenCalledWith({ + path : '5ePHB', styles : [ `/* From Theme Blank */\n\n@import url("/themes/V3/Blank/style.css");`, `/* From Theme 5ePHB */\n\n@import url("/themes/V3/5ePHB/style.css");` @@ -649,6 +652,7 @@ brew`); expect(res.status).toHaveBeenCalledWith(200); expect(res.send).toHaveBeenCalledWith({ + path : 'User Theme A', styles : [ `/* From Theme Blank */\n\n@import url("/themes/V3/Blank/style.css");`, `/* From Theme 5ePHB */\n\n@import url("/themes/V3/5ePHB/style.css");`, From 6eb938bb373b2d15428f9c3425c0ce8bdcddd8ce Mon Sep 17 00:00:00 2001 From: David Bolack Date: Wed, 8 Jan 2025 09:25:16 -0600 Subject: [PATCH 090/398] Change theme button toggle to be a bit more obvious. --- client/homebrew/editor/metadataEditor/metadataEditor.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/homebrew/editor/metadataEditor/metadataEditor.jsx b/client/homebrew/editor/metadataEditor/metadataEditor.jsx index 694444bc9..0fd17db3e 100644 --- a/client/homebrew/editor/metadataEditor/metadataEditor.jsx +++ b/client/homebrew/editor/metadataEditor/metadataEditor.jsx @@ -265,7 +265,7 @@ const MetadataEditor = createClass({ {!this.state.showThemeWritein?dropdown:''} {this.renderThemeWritein()}
; From 2d47cd2a767f7e2f258bd057efc09ad4a58eb3e6 Mon Sep 17 00:00:00 2001 From: David Bolack Date: Wed, 8 Jan 2025 09:28:37 -0600 Subject: [PATCH 091/398] Formatting cleanup --- .../editor/metadataEditor/metadataEditor.jsx | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/client/homebrew/editor/metadataEditor/metadataEditor.jsx b/client/homebrew/editor/metadataEditor/metadataEditor.jsx index 0fd17db3e..92e737764 100644 --- a/client/homebrew/editor/metadataEditor/metadataEditor.jsx +++ b/client/homebrew/editor/metadataEditor/metadataEditor.jsx @@ -265,7 +265,7 @@ const MetadataEditor = createClass({ {!this.state.showThemeWritein?dropdown:''} {this.renderThemeWritein()}
; @@ -275,11 +275,11 @@ const MetadataEditor = createClass({ if(!this.state.showThemeWritein) return; return
this.handleThemeWritein(e)} /> + default='' + placeholder='Enter share id' + className='value' + defaultValue={this.state.lastThemeWriteIn || this.props.metadata.theme} + onChange={(e)=>this.handleThemeWritein(e)} /> {`${this.state.lastThemeWriteIn ? this.props.themeBundle?.path || '' : ''}`}
; }, From 96ebe0f6179e60c9db28b6c89c83c995692b9f82 Mon Sep 17 00:00:00 2001 From: David Bolack Date: Thu, 9 Jan 2025 16:42:55 -0600 Subject: [PATCH 092/398] Apply fix to clear error. --- client/homebrew/pages/sharePage/sharePage.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/homebrew/pages/sharePage/sharePage.jsx b/client/homebrew/pages/sharePage/sharePage.jsx index 15eae54f7..3af6ec830 100644 --- a/client/homebrew/pages/sharePage/sharePage.jsx +++ b/client/homebrew/pages/sharePage/sharePage.jsx @@ -23,7 +23,7 @@ const SharePage = (props)=>{ }); const handleBrewRendererPageChange = useCallback((pageNumber)=>{ - updateState({ currentBrewRendererPageNum: pageNumber }); + this.setState({ currentBrewRendererPageNum: pageNumber }); }, []); const handleControlKeys = (e)=>{ From 63bd483b3e87a4b7947c6905dac07ff87d3b7aa8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 10 Jan 2025 03:51:06 +0000 Subject: [PATCH 093/398] Bump mongoose from 8.9.3 to 8.9.4 Bumps [mongoose](https://github.com/Automattic/mongoose) from 8.9.3 to 8.9.4. - [Release notes](https://github.com/Automattic/mongoose/releases) - [Changelog](https://github.com/Automattic/mongoose/blob/master/CHANGELOG.md) - [Commits](https://github.com/Automattic/mongoose/compare/8.9.3...8.9.4) --- updated-dependencies: - dependency-name: mongoose dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- package-lock.json | 8 ++++---- package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index da1759b43..35f8e181e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -41,7 +41,7 @@ "marked-smartypants-lite": "^1.0.2", "markedLegacy": "npm:marked@^0.3.19", "moment": "^2.30.1", - "mongoose": "^8.9.3", + "mongoose": "^8.9.4", "nanoid": "5.0.9", "nconf": "^0.12.1", "react": "^18.3.1", @@ -10169,9 +10169,9 @@ } }, "node_modules/mongoose": { - "version": "8.9.3", - "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-8.9.3.tgz", - "integrity": "sha512-G50GNPdMqhoiRAJ/24GYAzg13yxXDD3FOOFeYiFwtHmHpAJem3hxbYIxAhLJGWbYEiUZL0qFMu2LXYkgGAmo+Q==", + "version": "8.9.4", + "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-8.9.4.tgz", + "integrity": "sha512-DndoI01aV/q40P9DiYDXsYjhj8vZjmmuFwcC3Tro5wFznoE1z6Fe2JgMnbLR6ghglym5ziYizSfAJykp+UPZWg==", "dependencies": { "bson": "^6.10.1", "kareem": "2.6.3", diff --git a/package.json b/package.json index 7acffcda8..bb55afffd 100644 --- a/package.json +++ b/package.json @@ -115,7 +115,7 @@ "marked-smartypants-lite": "^1.0.2", "markedLegacy": "npm:marked@^0.3.19", "moment": "^2.30.1", - "mongoose": "^8.9.3", + "mongoose": "^8.9.4", "nanoid": "5.0.9", "nconf": "^0.12.1", "react": "^18.3.1", From 1aeea034d2c54939a847fd462faf84e748b27b9b Mon Sep 17 00:00:00 2001 From: David Bolack Date: Thu, 9 Jan 2025 22:34:35 -0600 Subject: [PATCH 094/398] Requested corrections? --- client/homebrew/pages/sharePage/sharePage.jsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/client/homebrew/pages/sharePage/sharePage.jsx b/client/homebrew/pages/sharePage/sharePage.jsx index 3af6ec830..e9c5540a2 100644 --- a/client/homebrew/pages/sharePage/sharePage.jsx +++ b/client/homebrew/pages/sharePage/sharePage.jsx @@ -23,7 +23,9 @@ const SharePage = (props)=>{ }); const handleBrewRendererPageChange = useCallback((pageNumber)=>{ - this.setState({ currentBrewRendererPageNum: pageNumber }); + setState((prevState)=>({ + currentBrewRendererPageNum : pageNumber, + ...prevState })); }, []); const handleControlKeys = (e)=>{ From 591ccf564c25b1642d9fcab0cd18e5a759f6b7b2 Mon Sep 17 00:00:00 2001 From: David Bolack Date: Fri, 10 Jan 2025 20:22:33 -0600 Subject: [PATCH 095/398] Working changes --- install/ubuntu/etc/systemd/system/homebrewery.service | 2 +- install/ubuntu/install.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/install/ubuntu/etc/systemd/system/homebrewery.service b/install/ubuntu/etc/systemd/system/homebrewery.service index 939d11fb8..4152943d9 100644 --- a/install/ubuntu/etc/systemd/system/homebrewery.service +++ b/install/ubuntu/etc/systemd/system/homebrewery.service @@ -3,7 +3,7 @@ Description=Homebrewery Web Server [Service] User=root -After=mongodb +Requires=mongodb Environment=NODE_ENV=local WorkingDirectory=/usr/local/homebrewery ExecStart=node server.js diff --git a/install/ubuntu/install.sh b/install/ubuntu/install.sh index ebad7f3f2..e1de299e7 100644 --- a/install/ubuntu/install.sh +++ b/install/ubuntu/install.sh @@ -4,7 +4,7 @@ echo ::Install CURL apt install -y curl echo ::Add NodeJS source to package repo -curl -fsSL https://deb.nodesource.com/setup_16.x | sudo -E bash - +curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash - # Install required packages echo ::Install Homebrewery requirements From 533586f516b02b290942e969f3f7c1c208f1d545 Mon Sep 17 00:00:00 2001 From: David Bolack Date: Fri, 10 Jan 2025 21:09:50 -0600 Subject: [PATCH 096/398] Rough draft of update. --- install/README.UBUNTU.md | 4 +++- .../etc/systemd/system/homebrewery.service | 3 ++- install/ubuntu/install.sh | 18 ++++++++++++++---- 3 files changed, 19 insertions(+), 6 deletions(-) diff --git a/install/README.UBUNTU.md b/install/README.UBUNTU.md index d14cfef46..d97d6b362 100644 --- a/install/README.UBUNTU.md +++ b/install/README.UBUNTU.md @@ -24,12 +24,14 @@ These instructions assume that you are installing to a completely new, fresh Ubu These installation instructions have been tested on the following Ubuntu releases: -- *ubuntu-20.04.3-desktop-amd64* +- *ubuntu-24.04.1-desktop-amd64* ## Final Notes While this installation process works successfully at the time of writing (December 19, 2021), it relies on all of the Node.JS packages used in the HomeBrewery project retaining their cross-platform capabilities to continue to function. This is one of the inherent advantages of Node.JS, but it is by no means guaranteed and as such, functionality or even installation may fail without warning at some point in the future. +Earlier versions of Ubuntu may requier an alternate Mongo setup, see https://www.mongodb.com/docs/manual/tutorial/install-mongodb-on-ubuntu/ for assistance. + Regards, G December 19, 2021 diff --git a/install/ubuntu/etc/systemd/system/homebrewery.service b/install/ubuntu/etc/systemd/system/homebrewery.service index 4152943d9..defa85a31 100644 --- a/install/ubuntu/etc/systemd/system/homebrewery.service +++ b/install/ubuntu/etc/systemd/system/homebrewery.service @@ -3,7 +3,8 @@ Description=Homebrewery Web Server [Service] User=root -Requires=mongodb +BindsTo=mongod.service +After=mongod.service Environment=NODE_ENV=local WorkingDirectory=/usr/local/homebrewery ExecStart=node server.js diff --git a/install/ubuntu/install.sh b/install/ubuntu/install.sh index e1de299e7..13265779a 100644 --- a/install/ubuntu/install.sh +++ b/install/ubuntu/install.sh @@ -6,9 +6,21 @@ apt install -y curl echo ::Add NodeJS source to package repo curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash - +# Add Mongo CE Source +echo ::Add Mongo CE source to package repo +curl -fsSL https://www.mongodb.org/static/pgp/server-8.0.asc | \ + sudo gpg -o /usr/share/keyrings/mongodb-server-8.0.gpg \ + --dearmor +echo "deb [ arch=amd64,arm64 signed-by=/usr/share/keyrings/mongodb-server-8.0.gpg ] https://repo.mongodb.org/apt/ubuntu noble/mongodb-org/8.0 multiverse" | sudo tee /etc/apt/sources.list.d/mongodb-org-8.0.list +sudo apt-get update + # Install required packages echo ::Install Homebrewery requirements -apt satisfy -y git nodejs npm mongodb +apt satisfy -y git nodejs npm mongodb-org + +# Enable and start Mongo +systemctl enable mongod +systemctl start mongod # Clone Homebrewery repo echo ::Get Homebrewery files @@ -23,9 +35,7 @@ npm audit fix npm run postinstall # Create Homebrewery service -echo ::Create Homebrewery service -ln -s /usr/local/homebrewery/install/ubuntu/etc/systemd/system/homebrewery.service /etc/systemd/system/homebrewery.service -systemctl daemon-reload +echo ::Create systemctl daemon-reload echo ::Set Homebrewery to start automatically systemctl enable homebrewery From 3578a7e1e2d10d067624acffa92ea75bd576521b Mon Sep 17 00:00:00 2001 From: David Bolack Date: Fri, 10 Jan 2025 22:52:18 -0600 Subject: [PATCH 097/398] Updated for last three LTS releases --- install/README.UBUNTU.md | 4 +++- install/ubuntu/install.sh | 50 +++++++++++++++++++++++++++++++++------ 2 files changed, 46 insertions(+), 8 deletions(-) diff --git a/install/README.UBUNTU.md b/install/README.UBUNTU.md index d97d6b362..13fa7631d 100644 --- a/install/README.UBUNTU.md +++ b/install/README.UBUNTU.md @@ -24,7 +24,9 @@ These instructions assume that you are installing to a completely new, fresh Ubu These installation instructions have been tested on the following Ubuntu releases: -- *ubuntu-24.04.1-desktop-amd64* + - *ubuntu-24.04.1-desktop-amd64* + - *ubuntu-22.04.5-desktop-amd64* + - *ubuntu-20.04.6-desktop-amd64* ## Final Notes diff --git a/install/ubuntu/install.sh b/install/ubuntu/install.sh index 13265779a..a0fcc8c17 100644 --- a/install/ubuntu/install.sh +++ b/install/ubuntu/install.sh @@ -1,5 +1,22 @@ #!/bin/sh +# Detect Ubuntu Version +export DISTRO=$(grep "^NAME=" /etc/os-release | awk -F '=' '{print $2}' | sed 's/"//g') +export DISTRO_VER=$(grep "VERSION_ID=" /etc/os-release | awk -F '=' '{print $2}' | sed 's/"//g') +export MATCHED="Yes" + +if [ "${DISTRO}" != "Ubuntu" ]; +then + echo :: Ubuntu not detected. Are you using an alternate spin or derivative? + echo :: Detected - ${DISTRO} + read -p [y/N] YESNO + if [ "${YESNO}" != "Y" ] && [ ]"${YESNO}" != "y" ]; then + exit + fi + + MATCHED="No" +fi + # Install CURL and add required NodeJS source to package repo echo ::Install CURL apt install -y curl @@ -7,13 +24,30 @@ echo ::Add NodeJS source to package repo curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash - # Add Mongo CE Source -echo ::Add Mongo CE source to package repo -curl -fsSL https://www.mongodb.org/static/pgp/server-8.0.asc | \ - sudo gpg -o /usr/share/keyrings/mongodb-server-8.0.gpg \ - --dearmor -echo "deb [ arch=amd64,arm64 signed-by=/usr/share/keyrings/mongodb-server-8.0.gpg ] https://repo.mongodb.org/apt/ubuntu noble/mongodb-org/8.0 multiverse" | sudo tee /etc/apt/sources.list.d/mongodb-org-8.0.list -sudo apt-get update +if [ ${DISTRO} = "Ubuntu" ]; + then + echo ::Add Mongo CE source to package repo + curl -fsSL https://www.mongodb.org/static/pgp/server-8.0.asc | \ + sudo gpg -o /usr/share/keyrings/mongodb-server-8.0.gpg \ + --dearmor + if [ "${DISTRO_VER}" == "24.04" ]; then + echo "deb [ arch=amd64,arm64 signed-by=/usr/share/keyrings/mongodb-server-8.0.gpg ] https://repo.mongodb.org/apt/ubuntu noble/mongodb-org/8.0 multiverse" | sudo tee /etc/apt/sources.list.d/mongodb-org-8.0.list + elif [ "${DISTRO_VER}" == "22.04" ]; then + echo "deb [ arch=amd64,arm64 signed-by=/usr/share/keyrings/mongodb-server-8.0.gpg ] https://repo.mongodb.org/apt/ubuntu jammy/mongodb-org/8.0 multiverse" | sudo tee /etc/apt/sources.list.d/mongodb-org-8.0.list + elif [ "${DISTRO_VER}" == "20.04" ]; then + echo "deb [ arch=amd64,arm64 signed-by=/usr/share/keyrings/mongodb-server-8.0.gpg ] https://repo.mongodb.org/apt/ubuntu focal/mongodb-org/8.0 multiverse" | sudo tee /etc/apt/sources.list.d/mongodb-org-8.0.list + else + MATCHED="No" + fi + sudo apt-get update +fi +if [ ${MATCHED} == "No" ]; then + echo :: WARNING + echo :: Unable to determine Ubuntu version for Mongo installation purposes. + echo :: Please check your spin/distro documentation to install Mongo CE and enable it on startup. +fi + # Install required packages echo ::Install Homebrewery requirements apt satisfy -y git nodejs npm mongodb-org @@ -35,7 +69,9 @@ npm audit fix npm run postinstall # Create Homebrewery service -echo ::Create systemctl daemon-reload +echo ::Create Homebrewery service +ln -s /usr/local/homebrewery/install/ubuntu/etc/systemd/system/homebrewery.service /etc/systemd/system/homebrewery.service +systemctl daemon-reload echo ::Set Homebrewery to start automatically systemctl enable homebrewery From 9d67724da9c4d042092663055764bf3c7a662b6a Mon Sep 17 00:00:00 2001 From: David Bolack Date: Fri, 10 Jan 2025 23:22:22 -0600 Subject: [PATCH 098/398] Wrap titles in error messages with pre blocks to prevent rendering. --- client/homebrew/pages/errorPage/errors/errorIndex.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/client/homebrew/pages/errorPage/errors/errorIndex.js b/client/homebrew/pages/errorPage/errors/errorIndex.js index ccdd86768..73040ec68 100644 --- a/client/homebrew/pages/errorPage/errors/errorIndex.js +++ b/client/homebrew/pages/errorPage/errors/errorIndex.js @@ -89,7 +89,7 @@ const errorIndex = (props)=>{ : - **Brew Title:** ${props.brew.brewTitle || 'Unable to show title'} + **Brew Title:** \`${props.brew.brewTitle || 'Unable to show title'}\` **Current Authors:** ${props.brew.authors?.map((author)=>{return `[${author}](/user/${author})`;}).join(', ') || 'Unable to list authors'} @@ -104,7 +104,7 @@ const errorIndex = (props)=>{ : - **Brew Title:** ${props.brew.brewTitle || 'Unable to show title'} + **Brew Title:** \`${props.brew.brewTitle || 'Unable to show title'}\` **Current Authors:** ${props.brew.authors?.map((author)=>{return `[${author}](/user/${author})`;}).join(', ') || 'Unable to list authors'} @@ -181,7 +181,7 @@ const errorIndex = (props)=>{ **Brew ID:** ${props.brew.brewId} - **Brew Title:** ${props.brew.brewTitle}`, + **Brew Title:** \`${props.brew.brewTitle}\`, // ####### Admin page error ####### '52' : dedent` From 80003f6c5735a290f6ab6e22f377bf525f90eabb Mon Sep 17 00:00:00 2001 From: David Bolack Date: Sat, 11 Jan 2025 08:44:11 -0600 Subject: [PATCH 099/398] Return overremoved backtick --- client/homebrew/pages/errorPage/errors/errorIndex.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/homebrew/pages/errorPage/errors/errorIndex.js b/client/homebrew/pages/errorPage/errors/errorIndex.js index 73040ec68..f05f93838 100644 --- a/client/homebrew/pages/errorPage/errors/errorIndex.js +++ b/client/homebrew/pages/errorPage/errors/errorIndex.js @@ -181,7 +181,7 @@ const errorIndex = (props)=>{ **Brew ID:** ${props.brew.brewId} - **Brew Title:** \`${props.brew.brewTitle}\`, + **Brew Title:** \`${props.brew.brewTitle}\``, // ####### Admin page error ####### '52' : dedent` From 69c45d63a454d0c1bd3da56eb17a90bfb7ae4284 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 11 Jan 2025 15:46:07 +0000 Subject: [PATCH 100/398] Bump react-frame-component from 4.1.3 to 5.2.7 Bumps [react-frame-component](https://github.com/ryanseddon/react-frame-component) from 4.1.3 to 5.2.7. - [Release notes](https://github.com/ryanseddon/react-frame-component/releases) - [Commits](https://github.com/ryanseddon/react-frame-component/compare/v4.1.3...v5.2.7) --- updated-dependencies: - dependency-name: react-frame-component dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- package-lock.json | 9 ++++----- package.json | 2 +- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/package-lock.json b/package-lock.json index d9158a2d3..781bdaec7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -46,7 +46,7 @@ "nconf": "^0.12.1", "react": "^18.3.1", "react-dom": "^18.3.1", - "react-frame-component": "^4.1.3", + "react-frame-component": "^5.2.7", "react-router": "^7.1.1", "sanitize-filename": "1.6.3", "superagent": "^10.1.1", @@ -11579,10 +11579,9 @@ } }, "node_modules/react-frame-component": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/react-frame-component/-/react-frame-component-4.1.3.tgz", - "integrity": "sha512-4PurhctiqnmC1F5prPZ+LdsalH7pZ3SFA5xoc0HBe8mSHctdLLt4Cr2WXfXOoajHBYq/yiipp9zOgx+vy8GiEA==", - "license": "MIT", + "version": "5.2.7", + "resolved": "https://registry.npmjs.org/react-frame-component/-/react-frame-component-5.2.7.tgz", + "integrity": "sha512-ROjHtSLoSVYUBfTieazj/nL8jIX9rZFmHC0yXEU+dx6Y82OcBEGgU9o7VyHMrBFUN9FuQ849MtIPNNLsb4krbg==", "peerDependencies": { "prop-types": "^15.5.9", "react": ">= 16.3", diff --git a/package.json b/package.json index 3019c3dce..687fa473d 100644 --- a/package.json +++ b/package.json @@ -120,7 +120,7 @@ "nconf": "^0.12.1", "react": "^18.3.1", "react-dom": "^18.3.1", - "react-frame-component": "^4.1.3", + "react-frame-component": "^5.2.7", "react-router": "^7.1.1", "sanitize-filename": "1.6.3", "superagent": "^10.1.1", From 662f039daa9437317cd128271d2962ecfbd32fb0 Mon Sep 17 00:00:00 2001 From: David Bolack Date: Sun, 12 Jan 2025 14:13:27 -0600 Subject: [PATCH 101/398] Merge conflict clearing --- package-lock.json | 46 +++++++++++++++++++++++----------------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/package-lock.json b/package-lock.json index 072108b1f..d05e97f62 100644 --- a/package-lock.json +++ b/package-lock.json @@ -19,7 +19,7 @@ "classnames": "^2.5.1", "codemirror": "^5.65.6", "cookie-parser": "^1.4.7", - "core-js": "^3.39.0", + "core-js": "^3.40.0", "cors": "^2.8.5", "create-react-class": "^15.7.0", "dedent-tabs": "^0.10.3", @@ -36,17 +36,17 @@ "lodash": "^4.17.21", "marked": "11.2.0", "marked-emoji": "^1.4.3", - "marked-extended-tables": "^1.0.10", + "marked-extended-tables": "^1.1.0", "marked-gfm-heading-id": "^3.2.0", "marked-smartypants-lite": "^1.0.2", "markedLegacy": "npm:marked@^0.3.19", "moment": "^2.30.1", - "mongoose": "^8.9.2", + "mongoose": "^8.9.4", "nanoid": "5.0.9", "nconf": "^0.12.1", "react": "^18.3.1", "react-dom": "^18.3.1", - "react-frame-component": "^4.1.3", + "react-frame-component": "^5.2.7", "react-router": "^7.1.1", "sanitize-filename": "1.6.3", "superagent": "^10.1.1", @@ -54,7 +54,7 @@ }, "devDependencies": { "@stylistic/stylelint-plugin": "^3.1.1", - "babel-plugin-transform-import-meta": "^2.2.1", + "babel-plugin-transform-import-meta": "^2.3.2", "eslint": "^9.17.0", "eslint-plugin-jest": "^28.10.0", "eslint-plugin-react": "^7.37.3", @@ -3678,14 +3678,14 @@ } }, "node_modules/babel-plugin-transform-import-meta": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-import-meta/-/babel-plugin-transform-import-meta-2.2.1.tgz", - "integrity": "sha512-AxNh27Pcg8Kt112RGa3Vod2QS2YXKKJ6+nSvRtv7qQTJAdx0MZa4UHZ4lnxHUWA2MNbLuZQv5FVab4P1CoLOWw==", + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-import-meta/-/babel-plugin-transform-import-meta-2.3.2.tgz", + "integrity": "sha512-902o4GiQqI1GqAXfD5rEoz0PJamUfJ3VllpdWaNsFTwdaNjFSFHawvBO+cp5K2j+g2h3bZ4lnM1Xb6yFYGihtA==", "dev": true, "license": "BSD", "dependencies": { - "@babel/template": "^7.4.4", - "tslib": "^2.4.0" + "@babel/template": "^7.25.9", + "tslib": "^2.8.1" }, "peerDependencies": { "@babel/core": "^7.10.0" @@ -4645,9 +4645,9 @@ } }, "node_modules/core-js": { - "version": "3.39.0", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.39.0.tgz", - "integrity": "sha512-raM0ew0/jJUqkJ0E6e8UDtl+y/7ktFivgWvqw8dNSQeNWoSDLvQ1H/RN3aPXB9tBd4/FhyR4RDPGhsNIMsAn7g==", + "version": "3.40.0", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.40.0.tgz", + "integrity": "sha512-7vsMc/Lty6AGnn7uFpYT56QesI5D2Y/UkgKounk87OP9Z2H9Z8kj6jzcSGAxFmUtDOS0ntK6lbQz+Nsa0Jj6mQ==", "hasInstallScript": true, "license": "MIT", "funding": { @@ -9868,12 +9868,12 @@ } }, "node_modules/marked-extended-tables": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/marked-extended-tables/-/marked-extended-tables-1.0.10.tgz", - "integrity": "sha512-zvRS0GPTkxq8UWawSDecd1Rxd2KD8crrmq2QALGDdrgkcgRNQzHlbnlujBGuXxdgDJg7f6UTv+JpcfejBpKdSg==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/marked-extended-tables/-/marked-extended-tables-1.1.0.tgz", + "integrity": "sha512-xPQlnmr/mpIJEjwg9/guSKzxoKu7hyCD/sM59mcZc+nMIh2JuVM2se+kCa1Jo1UH+BEHcNlZ221ziJ/cOxAgCA==", "license": "MIT", "peerDependencies": { - "marked": ">=3 <15" + "marked": ">=3 <16" } }, "node_modules/marked-gfm-heading-id": { @@ -10254,9 +10254,9 @@ } }, "node_modules/mongoose": { - "version": "8.9.2", - "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-8.9.2.tgz", - "integrity": "sha512-mLWynmZS1v8HTeMxyLhskQncS1SkrjW1eLNuFDYGQMQ/5QrFrxTLNwWXeCRZeKT2lXyaxW8bnJC9AKPT9jYMkw==", + "version": "8.9.4", + "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-8.9.4.tgz", + "integrity": "sha512-DndoI01aV/q40P9DiYDXsYjhj8vZjmmuFwcC3Tro5wFznoE1z6Fe2JgMnbLR6ghglym5ziYizSfAJykp+UPZWg==", "license": "MIT", "dependencies": { "bson": "^6.10.1", @@ -11675,9 +11675,9 @@ } }, "node_modules/react-frame-component": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/react-frame-component/-/react-frame-component-4.1.3.tgz", - "integrity": "sha512-4PurhctiqnmC1F5prPZ+LdsalH7pZ3SFA5xoc0HBe8mSHctdLLt4Cr2WXfXOoajHBYq/yiipp9zOgx+vy8GiEA==", + "version": "5.2.7", + "resolved": "https://registry.npmjs.org/react-frame-component/-/react-frame-component-5.2.7.tgz", + "integrity": "sha512-ROjHtSLoSVYUBfTieazj/nL8jIX9rZFmHC0yXEU+dx6Y82OcBEGgU9o7VyHMrBFUN9FuQ849MtIPNNLsb4krbg==", "license": "MIT", "peerDependencies": { "prop-types": "^15.5.9", From b8d65f2f56622170484258ba3335a9df781e436c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 13 Jan 2025 03:35:40 +0000 Subject: [PATCH 102/398] Bump stylelint from 16.12.0 to 16.13.0 Bumps [stylelint](https://github.com/stylelint/stylelint) from 16.12.0 to 16.13.0. - [Release notes](https://github.com/stylelint/stylelint/releases) - [Changelog](https://github.com/stylelint/stylelint/blob/main/CHANGELOG.md) - [Commits](https://github.com/stylelint/stylelint/compare/16.12.0...16.13.0) --- updated-dependencies: - dependency-name: stylelint dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- package-lock.json | 141 +++++++++++++++++++++++++++++++--------------- package.json | 2 +- 2 files changed, 96 insertions(+), 47 deletions(-) diff --git a/package-lock.json b/package-lock.json index 781bdaec7..e3b093084 100644 --- a/package-lock.json +++ b/package-lock.json @@ -63,7 +63,7 @@ "jest-expect-message": "^1.1.3", "jsdom-global": "^3.0.2", "postcss-less": "^6.0.0", - "stylelint": "^16.12.0", + "stylelint": "^16.13.0", "stylelint-config-recess-order": "^5.1.1", "stylelint-config-recommended": "^14.0.1", "supertest": "^7.0.0" @@ -2671,6 +2671,39 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, + "node_modules/@keyv/serialize": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@keyv/serialize/-/serialize-1.0.2.tgz", + "integrity": "sha512-+E/LyaAeuABniD/RvUezWVXKpeuvwLEA9//nE9952zBaOdBd2mQ3pPoM8cUe2X6IcMByfuSLzmYqnYshG60+HQ==", + "dev": true, + "dependencies": { + "buffer": "^6.0.3" + } + }, + "node_modules/@keyv/serialize/node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, "node_modules/@mongodb-js/saslprep": { "version": "1.1.9", "resolved": "https://registry.npmjs.org/@mongodb-js/saslprep/-/saslprep-1.1.9.tgz", @@ -4194,6 +4227,25 @@ "node": ">=0.10.0" } }, + "node_modules/cacheable": { + "version": "1.8.7", + "resolved": "https://registry.npmjs.org/cacheable/-/cacheable-1.8.7.tgz", + "integrity": "sha512-AbfG7dAuYNjYxFUtL1lAqmlWdxczCJ47w7cFjhGcnGnUdwSo6VgmSojfoW3tUI12HUkgTJ5kqj78yyq6TsFtlg==", + "dev": true, + "dependencies": { + "hookified": "^1.6.0", + "keyv": "^5.2.3" + } + }, + "node_modules/cacheable/node_modules/keyv": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-5.2.3.tgz", + "integrity": "sha512-AGKecUfzrowabUv0bH1RIR5Vf7w+l4S3xtQAypKaUpTdIR1EbrAcTxHCrpo9Q+IWeUlFE2palRtgIQcgm+PQJw==", + "dev": true, + "dependencies": { + "@keyv/serialize": "^1.0.2" + } + }, "node_modules/cached-path-relative": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/cached-path-relative/-/cached-path-relative-1.1.0.tgz", @@ -4847,13 +4899,12 @@ } }, "node_modules/css-tree": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-3.0.1.tgz", - "integrity": "sha512-8Fxxv+tGhORlshCdCwnNJytvlvq46sOLSYEx2ZIGurahWvMucSRnyjPA3AmrMq4VPRYbHVpWj5VkiVasrM2H4Q==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-3.1.0.tgz", + "integrity": "sha512-0eW44TGN5SQXU1mWSkKwFstI/22X2bG1nYzZTYMAWjylYURhse752YgbE4Cx46AC+bAvI+/dYTPRk1LqSUnu6w==", "dev": true, - "license": "MIT", "dependencies": { - "mdn-data": "2.12.1", + "mdn-data": "2.12.2", "source-map-js": "^1.0.1" }, "engines": { @@ -6193,17 +6244,16 @@ "license": "MIT" }, "node_modules/fast-glob": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", - "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", "dev": true, - "license": "MIT", "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", "glob-parent": "^5.1.2", "merge2": "^1.3.0", - "micromatch": "^4.0.4" + "micromatch": "^4.0.8" }, "engines": { "node": ">=8.6.0" @@ -6372,11 +6422,10 @@ } }, "node_modules/flatted": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", - "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==", - "dev": true, - "license": "ISC" + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.2.tgz", + "integrity": "sha512-AiwGJM8YcNOaobumgtng+6NHuOqC3A7MixFeDafM3X9cIUM+xUXoS5Vfgf+OihAYe20fxqNM9yPBXJzRtZ/4eA==", + "dev": true }, "node_modules/for-each": { "version": "0.3.3", @@ -7074,6 +7123,12 @@ "minimalistic-crypto-utils": "^1.0.1" } }, + "node_modules/hookified": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/hookified/-/hookified-1.6.0.tgz", + "integrity": "sha512-se7cpwTA+iA/eY548Bu03JJqBiEZAqU2jnyKdj5B5qurtBg64CZGHTgqCv4Yh7NWu6FGI09W61MCq+NoPj9GXA==", + "dev": true + }, "node_modules/html-encoding-sniffer": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-4.0.0.tgz", @@ -9861,11 +9916,10 @@ } }, "node_modules/mdn-data": { - "version": "2.12.1", - "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.12.1.tgz", - "integrity": "sha512-rsfnCbOHjqrhWxwt5/wtSLzpoKTzW7OXdT5lLOIH1OTYhWu9rRJveGq0sKvDZODABH7RX+uoR+DYcpFnq4Tf6Q==", - "dev": true, - "license": "CC0-1.0" + "version": "2.12.2", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.12.2.tgz", + "integrity": "sha512-IEn+pegP1aManZuckezWCO+XZQDplx1366JoVhTpMpBB1sPey/SbveZQUosKiKiGYjg1wH4pMlNgXbCiYgihQA==", + "dev": true }, "node_modules/media-typer": { "version": "0.3.0", @@ -12980,9 +13034,9 @@ "license": "ISC" }, "node_modules/stylelint": { - "version": "16.12.0", - "resolved": "https://registry.npmjs.org/stylelint/-/stylelint-16.12.0.tgz", - "integrity": "sha512-F8zZ3L/rBpuoBZRvI4JVT20ZanPLXfQLzMOZg1tzPflRVh9mKpOZ8qcSIhh1my3FjAjZWG4T2POwGnmn6a6hbg==", + "version": "16.13.0", + "resolved": "https://registry.npmjs.org/stylelint/-/stylelint-16.13.0.tgz", + "integrity": "sha512-muxVjMhZB8BrDFSKNva0dmvD2tM0o/szrvuZuXYcAnN9a8nQmbGLqNUOemSgumaCMCPQ+0USYyG3hA5vJjUC1Q==", "dev": true, "funding": [ { @@ -13004,16 +13058,16 @@ "colord": "^2.9.3", "cosmiconfig": "^9.0.0", "css-functions-list": "^3.2.3", - "css-tree": "^3.0.1", + "css-tree": "^3.1.0", "debug": "^4.3.7", - "fast-glob": "^3.3.2", + "fast-glob": "^3.3.3", "fastest-levenshtein": "^1.0.16", - "file-entry-cache": "^9.1.0", + "file-entry-cache": "^10.0.5", "global-modules": "^2.0.0", "globby": "^11.1.0", "globjoin": "^0.1.4", "html-tags": "^3.3.1", - "ignore": "^6.0.2", + "ignore": "^7.0.0", "imurmurhash": "^0.1.4", "is-plain-object": "^5.0.0", "known-css-properties": "^0.35.0", @@ -13145,34 +13199,29 @@ "license": "MIT" }, "node_modules/stylelint/node_modules/file-entry-cache": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-9.1.0.tgz", - "integrity": "sha512-/pqPFG+FdxWQj+/WSuzXSDaNzxgTLr/OrR1QuqfEZzDakpdYE70PwUxL7BPUa8hpjbvY1+qvCl8k+8Tq34xJgg==", + "version": "10.0.5", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-10.0.5.tgz", + "integrity": "sha512-umpQsJrBNsdMDgreSryMEXvJh66XeLtZUwA8Gj7rHGearGufUFv6rB/bcXRFsiGWw/VeSUgUofF4Rf2UKEOrTA==", "dev": true, "dependencies": { - "flat-cache": "^5.0.0" - }, - "engines": { - "node": ">=18" + "flat-cache": "^6.1.5" } }, "node_modules/stylelint/node_modules/flat-cache": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-5.0.0.tgz", - "integrity": "sha512-JrqFmyUl2PnPi1OvLyTVHnQvwQ0S+e6lGSwu8OkAZlSaNIZciTY2H/cOOROxsBA1m/LZNHDsqAgDZt6akWcjsQ==", + "version": "6.1.5", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-6.1.5.tgz", + "integrity": "sha512-QR+2kN38f8nMfiIQ1LHYjuDEmZNZVjxuxY+HufbS3BW0EX01Q5OnH7iduOYRutmgiXb797HAKcXUeXrvRjjgSQ==", "dev": true, "dependencies": { - "flatted": "^3.3.1", - "keyv": "^4.5.4" - }, - "engines": { - "node": ">=18" + "cacheable": "^1.8.7", + "flatted": "^3.3.2", + "hookified": "^1.6.0" } }, "node_modules/stylelint/node_modules/ignore": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-6.0.2.tgz", - "integrity": "sha512-InwqeHHN2XpumIkMvpl/DCJVrAHgCsG5+cn1XlnLWGwtZBm8QJfSusItfrwx81CTp5agNZqpKU2J/ccC5nGT4A==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.0.tgz", + "integrity": "sha512-lcX8PNQygAa22u/0BysEY8VhaFRzlOkvdlKczDPnJvrkJD1EuqzEky5VYYKM2iySIuaVIDv9N190DfSreSLw2A==", "dev": true, "engines": { "node": ">= 4" diff --git a/package.json b/package.json index 687fa473d..d70701223 100644 --- a/package.json +++ b/package.json @@ -137,7 +137,7 @@ "jest-expect-message": "^1.1.3", "jsdom-global": "^3.0.2", "postcss-less": "^6.0.0", - "stylelint": "^16.12.0", + "stylelint": "^16.13.0", "stylelint-config-recess-order": "^5.1.1", "stylelint-config-recommended": "^14.0.1", "supertest": "^7.0.0" From 7a071496f3b22568bd6fcc46af9298a307174308 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 13 Jan 2025 03:36:04 +0000 Subject: [PATCH 103/398] Bump eslint from 9.17.0 to 9.18.0 Bumps [eslint](https://github.com/eslint/eslint) from 9.17.0 to 9.18.0. - [Release notes](https://github.com/eslint/eslint/releases) - [Changelog](https://github.com/eslint/eslint/blob/main/CHANGELOG.md) - [Commits](https://github.com/eslint/eslint/compare/v9.17.0...v9.18.0) --- updated-dependencies: - dependency-name: eslint dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- package-lock.json | 36 ++++++++++++++++++++---------------- package.json | 2 +- 2 files changed, 21 insertions(+), 17 deletions(-) diff --git a/package-lock.json b/package-lock.json index 781bdaec7..df30320e0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -55,7 +55,7 @@ "devDependencies": { "@stylistic/stylelint-plugin": "^3.1.1", "babel-plugin-transform-import-meta": "^2.3.2", - "eslint": "^9.17.0", + "eslint": "^9.18.0", "eslint-plugin-jest": "^28.10.0", "eslint-plugin-react": "^7.37.3", "globals": "^15.14.0", @@ -1868,10 +1868,13 @@ } }, "node_modules/@eslint/core": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.9.0.tgz", - "integrity": "sha512-7ATR9F0e4W85D/0w7cU0SNj7qkAexMG+bAHEZOjo9akvGuhHE2m7umzWzfnpa0XAg5Kxc1BWmtPMV67jJ+9VUg==", + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.10.0.tgz", + "integrity": "sha512-gFHJ+xBOo4G3WRlR1e/3G8A6/KZAH6zcE/hkLRCZTi/B9avAG365QhFA8uOGzTMqgTghpn7/fSnscW++dpMSAw==", "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.15" + }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } @@ -1912,9 +1915,9 @@ } }, "node_modules/@eslint/js": { - "version": "9.17.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.17.0.tgz", - "integrity": "sha512-Sxc4hqcs1kTu0iID3kcZDW3JHq2a77HO9P8CP6YEA/FpH3Ll8UXE2r/86Rz9YJLKme39S9vU5OWNjC6Xl0Cr3w==", + "version": "9.18.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.18.0.tgz", + "integrity": "sha512-fK6L7rxcq6/z+AaQMtiFTkvbHkBLNlwyRxHpKawP0x3u9+NC6MQTnFW+AdpwC6gfHTW0051cokQgtTN2FqlxQA==", "dev": true, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -1930,11 +1933,12 @@ } }, "node_modules/@eslint/plugin-kit": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.3.tgz", - "integrity": "sha512-2b/g5hRmpbb1o4GnTZax9N9m0FXzz9OV42ZzI4rDDMDuHUqigAiQCEWChBWCY4ztAGVRjoWT19v0yMmc5/L5kA==", + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.5.tgz", + "integrity": "sha512-lB05FkqEdUg2AA0xEbUz0SnkXT1LcCTa438W4IWTUh4hdOnVbQyOJ81OrDXsJk/LSiJHubgGEFoR5EHq1NsH1A==", "dev": true, "dependencies": { + "@eslint/core": "^0.10.0", "levn": "^0.4.1" }, "engines": { @@ -5595,18 +5599,18 @@ "license": "MIT" }, "node_modules/eslint": { - "version": "9.17.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.17.0.tgz", - "integrity": "sha512-evtlNcpJg+cZLcnVKwsai8fExnqjGPicK7gnUtlNuzu+Fv9bI0aLpND5T44VLQtoMEnI57LoXO9XAkIXwohKrA==", + "version": "9.18.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.18.0.tgz", + "integrity": "sha512-+waTfRWQlSbpt3KWE+CjrPPYnbq9kfZIYUqapc0uBXyjTp8aYXZDsUH16m39Ryq3NjAVP4tjuF7KaukeqoCoaA==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.12.1", "@eslint/config-array": "^0.19.0", - "@eslint/core": "^0.9.0", + "@eslint/core": "^0.10.0", "@eslint/eslintrc": "^3.2.0", - "@eslint/js": "9.17.0", - "@eslint/plugin-kit": "^0.2.3", + "@eslint/js": "9.18.0", + "@eslint/plugin-kit": "^0.2.5", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", "@humanwhocodes/retry": "^0.4.1", diff --git a/package.json b/package.json index 687fa473d..f42052729 100644 --- a/package.json +++ b/package.json @@ -129,7 +129,7 @@ "devDependencies": { "@stylistic/stylelint-plugin": "^3.1.1", "babel-plugin-transform-import-meta": "^2.3.2", - "eslint": "^9.17.0", + "eslint": "^9.18.0", "eslint-plugin-jest": "^28.10.0", "eslint-plugin-react": "^7.37.3", "globals": "^15.14.0", From 2cb19848aa7f8c6cbdad79c4e97156a29a17414d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 13 Jan 2025 12:54:21 +0000 Subject: [PATCH 104/398] Bump stylelint-config-recommended from 14.0.1 to 15.0.0 Bumps [stylelint-config-recommended](https://github.com/stylelint/stylelint-config-recommended) from 14.0.1 to 15.0.0. - [Release notes](https://github.com/stylelint/stylelint-config-recommended/releases) - [Changelog](https://github.com/stylelint/stylelint-config-recommended/blob/main/CHANGELOG.md) - [Commits](https://github.com/stylelint/stylelint-config-recommended/compare/14.0.1...15.0.0) --- updated-dependencies: - dependency-name: stylelint-config-recommended dependency-type: direct:development update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- package-lock.json | 11 +++++------ package.json | 2 +- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/package-lock.json b/package-lock.json index c36a8f254..31fafffb1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -65,7 +65,7 @@ "postcss-less": "^6.0.0", "stylelint": "^16.13.0", "stylelint-config-recess-order": "^5.1.1", - "stylelint-config-recommended": "^14.0.1", + "stylelint-config-recommended": "^15.0.0", "supertest": "^7.0.0" }, "engines": { @@ -13112,9 +13112,9 @@ } }, "node_modules/stylelint-config-recommended": { - "version": "14.0.1", - "resolved": "https://registry.npmjs.org/stylelint-config-recommended/-/stylelint-config-recommended-14.0.1.tgz", - "integrity": "sha512-bLvc1WOz/14aPImu/cufKAZYfXs/A/owZfSMZ4N+16WGXLoX5lOir53M6odBxvhgmgdxCVnNySJmZKx73T93cg==", + "version": "15.0.0", + "resolved": "https://registry.npmjs.org/stylelint-config-recommended/-/stylelint-config-recommended-15.0.0.tgz", + "integrity": "sha512-9LejMFsat7L+NXttdHdTq94byn25TD+82bzGRiV1Pgasl99pWnwipXS5DguTpp3nP1XjvLXVnEJIuYBfsRjRkA==", "dev": true, "funding": [ { @@ -13126,12 +13126,11 @@ "url": "https://github.com/sponsors/stylelint" } ], - "license": "MIT", "engines": { "node": ">=18.12.0" }, "peerDependencies": { - "stylelint": "^16.1.0" + "stylelint": "^16.13.0" } }, "node_modules/stylelint-order": { diff --git a/package.json b/package.json index 225be4f7c..2d71539a1 100644 --- a/package.json +++ b/package.json @@ -139,7 +139,7 @@ "postcss-less": "^6.0.0", "stylelint": "^16.13.0", "stylelint-config-recess-order": "^5.1.1", - "stylelint-config-recommended": "^14.0.1", + "stylelint-config-recommended": "^15.0.0", "supertest": "^7.0.0" } } From f6c95fb8b773ebeff021bd7a581e352e7ea5bddd Mon Sep 17 00:00:00 2001 From: "G.Ambatte" Date: Tue, 14 Jan 2025 08:25:46 +1300 Subject: [PATCH 105/398] Extend header nav to exclude frontCover pages --- .../brewRenderer/headerNav/headerNav.jsx | 25 +++++++++++++------ 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/client/homebrew/brewRenderer/headerNav/headerNav.jsx b/client/homebrew/brewRenderer/headerNav/headerNav.jsx index 68963129f..8278e2bd9 100644 --- a/client/homebrew/brewRenderer/headerNav/headerNav.jsx +++ b/client/homebrew/brewRenderer/headerNav/headerNav.jsx @@ -11,11 +11,18 @@ const HeaderNav = React.forwardRef(({}, pagesRef)=>{ const renderHeaderLinks = ()=>{ if(!pagesRef.current) return; + const excludedPages = { + '.frontCover' : 'Cover Page', + '.toc' : 'Contents' + }; + + const excluded = Object.keys(excludedPages).join(','); + const selector = [ - '.pages > .page', // All page elements, which by definition have IDs - '.page:not(:has(.toc)) > [id]', // All direct children of non-ToC .page with an ID (Legacy) - '.page:not(:has(.toc)) > .columnWrapper > [id]', // All direct children of non-ToC .page > .columnWrapper with an ID (V3) - '.page:not(:has(.toc)) h2', // All non-ToC H2 titles, like Monster frame titles + '.pages > .page', // All page elements, which by definition have IDs + `.page:not(:has(${excluded})) > [id]`, // All direct children of non-excluded .pages with an ID (Legacy) + `.page:not(:has(${excluded})) > .columnWrapper > [id]`, // All direct children of non-excluded .page > .columnWrapper with an ID (V3) + `.page:not(:has(${excluded})) h2`, // All non-excluded H2 titles, like Monster frame titles ]; const elements = pagesRef.current.querySelectorAll(selector.join(',')); if(!elements) return; @@ -32,9 +39,13 @@ const HeaderNav = React.forwardRef(({}, pagesRef)=>{ elements.forEach((el)=>{ if(el.className.match(/\bpage\b/)) { let text = `Page ${el.id.slice(1)}`; // The ID of a page *should* always be equal to `p` followed by the page number - if(el.querySelector('.toc')){ // If the page contains a table of contents, add "- Contents" to the display text - text += ' - Contents'; - }; + Object.keys(excludedPages).every((pageType)=>{ + if(el.querySelector(pageType)){ // If the page contains a table of contents, add "- Contents" to the display text + text += ` - ${excludedPages[pageType]}`; + return false; + }; + return true; + }); navList.push({ depth : 0, // Pages are always at the least indented level text : text, From 7c4f163042b118eb727d79034b072270add23d3d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 14 Jan 2025 03:57:47 +0000 Subject: [PATCH 106/398] Bump stylelint from 16.13.0 to 16.13.1 Bumps [stylelint](https://github.com/stylelint/stylelint) from 16.13.0 to 16.13.1. - [Release notes](https://github.com/stylelint/stylelint/releases) - [Changelog](https://github.com/stylelint/stylelint/blob/main/CHANGELOG.md) - [Commits](https://github.com/stylelint/stylelint/compare/16.13.0...16.13.1) --- updated-dependencies: - dependency-name: stylelint dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- package-lock.json | 16 ++++++++-------- package.json | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/package-lock.json b/package-lock.json index 31fafffb1..303d2d22e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -63,7 +63,7 @@ "jest-expect-message": "^1.1.3", "jsdom-global": "^3.0.2", "postcss-less": "^6.0.0", - "stylelint": "^16.13.0", + "stylelint": "^16.13.1", "stylelint-config-recess-order": "^5.1.1", "stylelint-config-recommended": "^15.0.0", "supertest": "^7.0.0" @@ -13038,9 +13038,9 @@ "license": "ISC" }, "node_modules/stylelint": { - "version": "16.13.0", - "resolved": "https://registry.npmjs.org/stylelint/-/stylelint-16.13.0.tgz", - "integrity": "sha512-muxVjMhZB8BrDFSKNva0dmvD2tM0o/szrvuZuXYcAnN9a8nQmbGLqNUOemSgumaCMCPQ+0USYyG3hA5vJjUC1Q==", + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/stylelint/-/stylelint-16.13.1.tgz", + "integrity": "sha512-691JjSIIcP6f9QJFz0J0/AMG3lupE9RqYAgYCON3wiqp5nQiKqDYIsz321GeTOYNznoRPNh0Mf6VjzP1eBVz/Q==", "dev": true, "funding": [ { @@ -13071,7 +13071,7 @@ "globby": "^11.1.0", "globjoin": "^0.1.4", "html-tags": "^3.3.1", - "ignore": "^7.0.0", + "ignore": "^7.0.1", "imurmurhash": "^0.1.4", "is-plain-object": "^5.0.0", "known-css-properties": "^0.35.0", @@ -13222,9 +13222,9 @@ } }, "node_modules/stylelint/node_modules/ignore": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.0.tgz", - "integrity": "sha512-lcX8PNQygAa22u/0BysEY8VhaFRzlOkvdlKczDPnJvrkJD1EuqzEky5VYYKM2iySIuaVIDv9N190DfSreSLw2A==", + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.3.tgz", + "integrity": "sha512-bAH5jbK/F3T3Jls4I0SO1hmPR0dKU0a7+SY6n1yzRtG54FLO8d6w/nxLFX2Nb7dBu6cCWXPaAME6cYqFUMmuCA==", "dev": true, "engines": { "node": ">= 4" diff --git a/package.json b/package.json index 2d71539a1..6d60a59dd 100644 --- a/package.json +++ b/package.json @@ -137,7 +137,7 @@ "jest-expect-message": "^1.1.3", "jsdom-global": "^3.0.2", "postcss-less": "^6.0.0", - "stylelint": "^16.13.0", + "stylelint": "^16.13.1", "stylelint-config-recess-order": "^5.1.1", "stylelint-config-recommended": "^15.0.0", "supertest": "^7.0.0" From cac6dbd40cd5245939a6e5ceaa49919d0f08c655 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 14 Jan 2025 03:58:15 +0000 Subject: [PATCH 107/398] Bump eslint-plugin-react from 7.37.3 to 7.37.4 Bumps [eslint-plugin-react](https://github.com/jsx-eslint/eslint-plugin-react) from 7.37.3 to 7.37.4. - [Release notes](https://github.com/jsx-eslint/eslint-plugin-react/releases) - [Changelog](https://github.com/jsx-eslint/eslint-plugin-react/blob/master/CHANGELOG.md) - [Commits](https://github.com/jsx-eslint/eslint-plugin-react/compare/v7.37.3...v7.37.4) --- updated-dependencies: - dependency-name: eslint-plugin-react dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- package-lock.json | 8 ++++---- package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index 303d2d22e..0e1d78abf 100644 --- a/package-lock.json +++ b/package-lock.json @@ -57,7 +57,7 @@ "babel-plugin-transform-import-meta": "^2.3.2", "eslint": "^9.18.0", "eslint-plugin-jest": "^28.10.0", - "eslint-plugin-react": "^7.37.3", + "eslint-plugin-react": "^7.37.4", "globals": "^15.14.0", "jest": "^29.7.0", "jest-expect-message": "^1.1.3", @@ -5734,9 +5734,9 @@ } }, "node_modules/eslint-plugin-react": { - "version": "7.37.3", - "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.37.3.tgz", - "integrity": "sha512-DomWuTQPFYZwF/7c9W2fkKkStqZmBd3uugfqBYLdkZ3Hii23WzZuOLUskGxB8qkSKqftxEeGL1TB2kMhrce0jA==", + "version": "7.37.4", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.37.4.tgz", + "integrity": "sha512-BGP0jRmfYyvOyvMoRX/uoUeW+GqNj9y16bPQzqAHf3AYII/tDs+jMN0dBVkl88/OZwNGwrVFxE7riHsXVfy/LQ==", "dev": true, "dependencies": { "array-includes": "^3.1.8", diff --git a/package.json b/package.json index 6d60a59dd..5c5d87fa4 100644 --- a/package.json +++ b/package.json @@ -131,7 +131,7 @@ "babel-plugin-transform-import-meta": "^2.3.2", "eslint": "^9.18.0", "eslint-plugin-jest": "^28.10.0", - "eslint-plugin-react": "^7.37.3", + "eslint-plugin-react": "^7.37.4", "globals": "^15.14.0", "jest": "^29.7.0", "jest-expect-message": "^1.1.3", From 3c5ad74e387514a32b7c2a4dad833db263d58ced Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 14 Jan 2025 07:10:13 +0000 Subject: [PATCH 108/398] Bump mongoose from 8.9.4 to 8.9.5 Bumps [mongoose](https://github.com/Automattic/mongoose) from 8.9.4 to 8.9.5. - [Release notes](https://github.com/Automattic/mongoose/releases) - [Changelog](https://github.com/Automattic/mongoose/blob/master/CHANGELOG.md) - [Commits](https://github.com/Automattic/mongoose/compare/8.9.4...8.9.5) --- updated-dependencies: - dependency-name: mongoose dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- package-lock.json | 8 ++++---- package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index 0e1d78abf..bc7a69d43 100644 --- a/package-lock.json +++ b/package-lock.json @@ -41,7 +41,7 @@ "marked-smartypants-lite": "^1.0.2", "markedLegacy": "npm:marked@^0.3.19", "moment": "^2.30.1", - "mongoose": "^8.9.4", + "mongoose": "^8.9.5", "nanoid": "5.0.9", "nconf": "^0.12.1", "react": "^18.3.1", @@ -10226,9 +10226,9 @@ } }, "node_modules/mongoose": { - "version": "8.9.4", - "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-8.9.4.tgz", - "integrity": "sha512-DndoI01aV/q40P9DiYDXsYjhj8vZjmmuFwcC3Tro5wFznoE1z6Fe2JgMnbLR6ghglym5ziYizSfAJykp+UPZWg==", + "version": "8.9.5", + "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-8.9.5.tgz", + "integrity": "sha512-SPhOrgBm0nKV3b+IIHGqpUTOmgVL5Z3OO9AwkFEmvOZznXTvplbomstCnPOGAyungtRXE5pJTgKpKcZTdjeESg==", "dependencies": { "bson": "^6.10.1", "kareem": "2.6.3", diff --git a/package.json b/package.json index 5c5d87fa4..df2453171 100644 --- a/package.json +++ b/package.json @@ -115,7 +115,7 @@ "marked-smartypants-lite": "^1.0.2", "markedLegacy": "npm:marked@^0.3.19", "moment": "^2.30.1", - "mongoose": "^8.9.4", + "mongoose": "^8.9.5", "nanoid": "5.0.9", "nconf": "^0.12.1", "react": "^18.3.1", From 4958ade9378c44e7315226bb63e59bdb378a58d0 Mon Sep 17 00:00:00 2001 From: David Bolack Date: Tue, 14 Jan 2025 06:58:48 -0600 Subject: [PATCH 109/398] Remove V4 cruft that should never have been merged --- themes/V3/Blank/style.less | 19 - themes/V4/Blank/dropdownPreview.png | Bin 142231 -> 0 bytes themes/V4/Blank/dropdownTexture.png | Bin 236 -> 0 bytes themes/V4/Blank/settings.json | 6 - themes/V4/Blank/snippets.js | 506 -------------------- themes/V4/Blank/snippets/footer.gen.js | 17 - themes/V4/Blank/snippets/imageMask.gen.js | 46 -- themes/V4/Blank/snippets/watercolor.gen.js | 5 - themes/V4/Blank/style.less | 524 --------------------- 9 files changed, 1123 deletions(-) delete mode 100644 themes/V4/Blank/dropdownPreview.png delete mode 100644 themes/V4/Blank/dropdownTexture.png delete mode 100644 themes/V4/Blank/settings.json delete mode 100644 themes/V4/Blank/snippets.js delete mode 100644 themes/V4/Blank/snippets/footer.gen.js delete mode 100644 themes/V4/Blank/snippets/imageMask.gen.js delete mode 100644 themes/V4/Blank/snippets/watercolor.gen.js delete mode 100644 themes/V4/Blank/style.less diff --git a/themes/V3/Blank/style.less b/themes/V3/Blank/style.less index d2c54be0c..65eeee683 100644 --- a/themes/V3/Blank/style.less +++ b/themes/V3/Blank/style.less @@ -506,22 +506,3 @@ body { counter-reset : page-numbers 0; } } } - -//***************************** -//* Forced Justification -//* DELETE WHEN V4 GOES LIVE -//*****************************/ - -.page { - .mdParagraphJustifyLeft { - text-align: left; - } - - .mdParagraphJustifyRight { - text-align: right; - } - - .mdParagraphJustifyCenter { - text-align: center; - } -} diff --git a/themes/V4/Blank/dropdownPreview.png b/themes/V4/Blank/dropdownPreview.png deleted file mode 100644 index 7ff524ad486550e2c948769ff273066c0f3d2290..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 142231 zcmeGD^;;Z4*EI@bArJ^ILvVL8KyVEjJh;nXNpN>(fB=KLC&As_2N($M?iwVx>zTaY zb3fnx{tf5+)YtSi-L-3X)vi@*tqT9FEc^D&yEh032yf*+NvRD$9-q7O27EsBg57MZTKCl za!uSZT2I}e_DV)JWhc~5BXa? z#YgzR(TL;zK|zuS2yu=Ge)>;@|K7hy`vY7p;&xx~-$7=Hi=&${7U;hIznb!fhu+Yy zyr%JAo&151#soU*{cuS2-%Wju3BZG0&+ljaPpALS#RUl-R931bdES3F^%vgvc?uz4 z_5aFUpfVLaDEz6i;Qy;B5qSJdW`*|uS5ML5LAjZxyT<-^Q+2ZN_`Q!VmHxY@f`Ra$ zloe~S)c(7vYk2(sUsC_ymQ<5jTz-~0dm8KR%TkU)#QX(lb0oWL#ejg`kx7U9h*t8XeqocL=;Csenb2Pv0w(Z~J6s^>oTCJQ6r(o(nYpH6-& zeHHDQkmy$NABdoB!MzAtGX#@xJ>N2J_7gI(Ace6+{;jq5M?KF|hgHf3lQvmqzFL07 zSjRoH?VdUhR9<11bCW;iQp46xPq1*l0dlg+F?s& z7j)%~0Bl5dKQ<1kwY28VSXg|EpcBgXvL#z}W?rO?z46q!7BJJ?+V_BN6lftnf^TZxKC%tta5Anp0g%*zu(gOO3#;mPkTc#CulmDXzm&T`mC<+}k_qp@7a6%8?J z)^y3niU3yY{5c;Ivp;BN<5^^k?VBwm7x~#0a&ghxxT!qwg2w{N#7cYGv*o{NE^T<9 z@$x|Hu@#wvbbE`_AbQ8vX7{XGWhH#OK~$FMO&(o}%LW}ydNtqS(|%7(51Ha@FDxbY z1Wz;qO$jouDmtVl2ZES%sL)}}+Z8RRHHgU07Z2YE%ziVnH;zp4EC{~)pN#S&L2pl2 z+5fz3z2(2%z+OK!j$9&Y|Dv_NJSb?>)`s-uMPGbX)DPk0<@EJ^p+4%9xD#Sjn+t>#y}iqH^?KDCH%y@x7bUuRnDwYUU}PxJ72g-;R@2I|7s z)2+|oGiow_GeWHnx3BhR5&q6Yrw3vk=&i=)qtnJKLE71V6xTuTiONUX>#$|lb}Hs$ zK&P{)Y)|`vw<~>}^I@(!VU>@*VBqr{0#?T(TN#F<{|tY&K_K7iLfFWd>FjsDn%b&| zXY%>mF`Py!X9 zUo$Sla}s{vOAsRf=Fa*Mhu^Oj<2%>tPs;8+RMnv}IX13qxh3DSL3KLpKkW_$vk;pl z5eU0RwxXNgm;EaM!bmF&ki9jq|HCNDaO9K+<-PwsiAP`W*n-%aJm2m0#p(Y0wUV`L z?>EUgyyZ`*sErt<#%GOattXV-r8#|+_kd_){h<7z5Y3Utk*6DrTg*p&i~O?H4!76Q zHj2h)H)kr9&~r*V+Mwik$<>>fjnh&QkLwd0eIBimRYt_;L(#{j7_p-8Kg$e{>&K)H z6*cjbZ%>!k41!dAwpiNb(Cc?N=WA7QWuD;>gc&rx_8+hk2t#wp0P+S!##I=v1ZY3U zXwEy^3fCgbinXCcj`}}FBI_6%gdz9;HahN+UDN$}ykoo?P~O>&J>=hvHPm^-Ty*5| zxH5JO&AKtJ|7M9m0gV###nf6W5fZ!UBcFdU&ZshhK2wl&uWIv|JQ&)vnESpg99B8F z4Yhc&tMX_KpOk$(X^eRBza7)wSl+Xe@Vd@$UmrCVg1&P~x-vO~3g|rdPzYbYT&*uB z5qhu?8som3 zDU*%o!IVCisF@hA=;HkxwDIMcgMTOaenGx}xnn3>=a*BqOmn@wz-XxHCqC7stMicIs>5__KJ6bYIe(w*tc&63`*MXN+O!h( z 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⁡=B5jVo;0X`3P=$s9!NKPdFDdo_JNk=8&=mx?x} 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%0AvP)0c-T2@`xL@jGEyeyb#SQx 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

a8x0C{*b{eu)Hn%0G_vP)GoanFI=% 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 TG>HB$;A5m`a=r4JL->CI;&2u+ diff --git a/themes/V4/Blank/dropdownTexture.png b/themes/V4/Blank/dropdownTexture.png deleted file mode 100644 index d0c0256c0930789944d3b6567692a532620bdc84..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 236 zcmeAS@N?(olHy`uVBq!ia0y~yVAKJ!YL8Sly diff --git a/themes/V4/Blank/settings.json b/themes/V4/Blank/settings.json deleted file mode 100644 index 3786248fb..000000000 --- a/themes/V4/Blank/settings.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "name" : "Blank", - "renderer" : "V3", - "baseTheme" : false, - "baseSnippets" : false -} diff --git a/themes/V4/Blank/snippets.js b/themes/V4/Blank/snippets.js deleted file mode 100644 index e92e757cf..000000000 --- a/themes/V4/Blank/snippets.js +++ /dev/null @@ -1,506 +0,0 @@ -/* eslint-disable max-lines */ - -const WatercolorGen = require('./snippets/watercolor.gen.js'); -const ImageMaskGen = require('./snippets/imageMask.gen.js'); -const FooterGen = require('./snippets/footer.gen.js'); -const dedent = require('dedent-tabs').default; - -module.exports = [ - - { - groupName : 'Text Editor', - icon : 'fas fa-pencil-alt', - view : 'text', - snippets : [ - { - name : 'Column Break', - icon : 'fas fa-columns', - gen : '\n\\column\n' - }, - { - name : 'New Page', - icon : 'fas fa-file-alt', - gen : '\n\\page\n' - }, - { - name : 'Page Numbering', - icon : 'fas fa-bookmark', - subsnippets : [ - { - name : 'Page Number', - icon : 'fas fa-bookmark', - gen : '{{pageNumber 1}}\n' - }, - { - name : 'Auto-incrementing Page Number', - icon : 'fas fa-sort-numeric-down', - gen : '{{pageNumber,auto}}\n' - }, - { - name : 'Skip Page Number Increment this Page', - icon : 'fas fa-xmark', - gen : '{{skipCounting}}\n' - }, - { - name : 'Restart Numbering', - icon : 'fas fa-arrow-rotate-left', - gen : '{{resetCounting}}\n' - }, - ] - }, - { - name : 'Footer', - icon : 'fas fa-shoe-prints', - gen : FooterGen.createFooterFunc(), - subsnippets : [ - { - name : 'Footer from H1', - icon : 'fas fa-dice-one', - gen : FooterGen.createFooterFunc(1) - }, - { - name : 'Footer from H2', - icon : 'fas fa-dice-two', - gen : FooterGen.createFooterFunc(2) - }, - { - name : 'Footer from H3', - icon : 'fas fa-dice-three', - gen : FooterGen.createFooterFunc(3) - }, - { - name : 'Footer from H4', - icon : 'fas fa-dice-four', - gen : FooterGen.createFooterFunc(4) - }, - { - name : 'Footer from H5', - icon : 'fas fa-dice-five', - gen : FooterGen.createFooterFunc(5) - }, - { - name : 'Footer from H6', - icon : 'fas fa-dice-six', - gen : FooterGen.createFooterFunc(6) - } - ] - }, - { - name : 'Vertical Spacing', - icon : 'fas fa-arrows-alt-v', - gen : '\n::::\n' - }, - { - name : 'Horizontal Spacing', - icon : 'fas fa-arrows-alt-h', - gen : ' {{width:100px}} ' - }, - { - name : 'Wide Block', - icon : 'fas fa-window-maximize', - gen : dedent`\n - {{wide - Everything in here will be extra wide. Tables, text, everything! - Beware though, CSS columns can behave a bit weird sometimes. You may - have to manually place column breaks with \`\column\` to make the - surrounding text flow with this wide block the way you want. - }} - \n` - }, - { - name : 'QR Code', - icon : 'fas fa-qrcode', - gen : (brew)=>{ - return `![]` + - `(https://api.qrserver.com/v1/create-qr-code/?data=` + - `https://homebrewery.naturalcrit.com${brew.shareId ? `/share/${brew.shareId}` : ''}` + - `&size=100x100) {width:100px;mix-blend-mode:multiply}`; - } - }, - { - name : 'Link to page', - icon : 'fas fa-link', - gen : '[Click here](#p3) to go to page 3\n' - }, - { - name : 'Add Comment', - icon : 'fas fa-code', - gen : '' - }, - { - name : 'Homebrewery Credit', - icon : 'fas fa-dice-d20', - gen : function(){ - return dedent` - {{homebreweryCredits - Made With - - {{homebreweryIcon}} - - The Homebrewery - [Homebrewery.Naturalcrit.com](https://homebrewery.naturalcrit.com) - }}\n\n`; - }, - } - ] - }, - { - groupName : 'Style Editor', - icon : 'fas fa-pencil-alt', - view : 'style', - snippets : [ - { - name : 'Add Comment', - icon : 'fas fa-code', - gen : '/* This is a comment that will not be rendered into your brew. */' - }, - ] - }, - - /*********************** IMAGES *******************/ - { - groupName : 'Images', - icon : 'fas fa-images', - view : 'text', - snippets : [ - { - name : 'Image', - icon : 'fas fa-image', - gen : dedent` - ![cat warrior](https://s-media-cache-ak0.pinimg.com/736x/4a/81/79/4a8179462cfdf39054a418efd4cb743e.jpg) {width:325px,mix-blend-mode:multiply}` - }, - { - name : 'Image Wrap Left', - icon : 'fac image-wrap-left', - gen : dedent` - ![homebrewery_mug](http://i.imgur.com/hMna6G0.png) {width:280px,margin-right:-3cm,wrapLeft}` - }, - { - name : 'Image Wrap Right', - icon : 'fac image-wrap-right', - gen : dedent` - ![homebrewery_mug](http://i.imgur.com/hMna6G0.png) {width:280px,margin-left:-3cm,wrapRight}` - }, - { - name : 'Background Image', - icon : 'fas fa-tree', - gen : dedent` - ![homebrew mug](http://i.imgur.com/hMna6G0.png) {position:absolute,top:50px,right:30px,width:280px}` - }, - { - name : 'Watercolor Splatter', - icon : 'fas fa-fill-drip', - gen : WatercolorGen, - }, - { - name : 'Watercolor Center', - icon : 'fac mask-center', - gen : ImageMaskGen.center, - experimental : true, - }, - { - name : 'Watercolor Edge', - icon : 'fac mask-edge', - gen : ImageMaskGen.edge('bottom'), - experimental : true, - subsnippets : [ - { - name : 'Top', - icon : 'fac position-top', - gen : ImageMaskGen.edge('top'), - }, - { - name : 'Right', - icon : 'fac position-right', - gen : ImageMaskGen.edge('right'), - }, - { - name : 'Bottom', - icon : 'fac position-bottom', - gen : ImageMaskGen.edge('bottom'), - }, - { - name : 'Left', - icon : 'fac position-left', - gen : ImageMaskGen.edge('left'), - }, - ] - }, - { - name : 'Watercolor Corner', - icon : 'fac mask-corner', - gen : ImageMaskGen.corner, - experimental : true, - subsnippets : [ - { - name : 'Top-Left', - icon : 'fac position-top-left', - gen : ImageMaskGen.corner('top', 'left'), - }, - { - name : 'Top-Right', - icon : 'fac position-top-right', - gen : ImageMaskGen.corner('top', 'right'), - }, - { - name : 'Bottom-Left', - icon : 'fac position-bottom-left', - gen : ImageMaskGen.corner('bottom', 'left'), - }, - { - name : 'Bottom-Right', - icon : 'fac position-bottom-right', - gen : ImageMaskGen.corner('bottom', 'right'), - } - ] - }, - { - name : 'Watermark', - icon : 'fas fa-id-card', - gen : dedent` - {{watermark Homebrewery}}\n` - }, - ] - }, - - /********************* TABLES *********************/ - - { - groupName : 'Tables', - icon : 'fas fa-table', - view : 'text', - snippets : [ - { - name : 'Table', - icon : 'fas fa-th-list', - gen : function(){ - return dedent` - ##### Character Advancement - | Experience Points | Level | Proficiency Bonus | - |:------------------|:-----:|:-----------------:| - | 0 | 1 | +2 | - | 300 | 2 | +2 | - | 900 | 3 | +2 | - | 2,700 | 4 | +2 | - | 6,500 | 5 | +3 | - | 14,000 | 6 | +3 | - \n`; - } - }, - { - name : 'Wide Table', - icon : 'fas fa-list', - gen : function(){ - return dedent` - {{wide - ##### Weapons - | Name | Cost | Damage | Weight | Properties | - |:------------------------|:-----:|:----------------|--------:|:-----------| - | *Simple Melee Weapons* | | | | | - |   Club | 1 sp | 1d4 bludgeoning | 2 lb. | Light | - |   Dagger | 2 gp | 1d4 piercing | 1 lb. | Finesse | - |   Spear | 1 gp | 1d6 piercing | 3 lb. | Thrown | - | *Simple Ranged Weapons* | | | | | - |   Dart | 5 cp | 1d4 piercig | 1/4 lb. | Finesse | - |   Shortbow | 25 gp | 1d6 piercing | 2 lb. | Ammunition | - |   Sling | 1 sp | 1d4 bludgeoning | — | Ammunition | - }} - \n`; - } - }, - { - name : 'Split Table', - icon : 'fas fa-th-large', - gen : function(){ - return dedent` - ##### Typical Difficulty Classes - {{column-count:2 - | Task Difficulty | DC | - |:----------------|:--:| - | Very easy | 5 | - | Easy | 10 | - | Medium | 15 | - - | Task Difficulty | DC | - |:------------------|:--:| - | Hard | 20 | - | Very hard | 25 | - | Nearly impossible | 30 | - }} - \n`; - } - } - ] - }, - /**************** FONTS *************/ - { - groupName : 'Fonts', - icon : 'fas fa-keyboard', - view : 'text', - snippets : [ - { - name : 'Open Sans', - icon : 'font OpenSans', - gen : dedent`{{font-family:OpenSans Dummy Text}}` - }, - { - name : 'Code Bold', - icon : 'font CodeBold', - gen : dedent`{{font-family:CodeBold Dummy Text}}` - }, - { - name : 'Code Light', - icon : 'font CodeLight', - gen : dedent`{{font-family:CodeLight Dummy Text}}` - }, - { - name : 'Scaly Sans', - icon : 'font ScalySansRemake', - gen : dedent`{{font-family:ScalySansRemake Dummy Text}}` - }, - { - name : 'Book Insanity', - icon : 'font BookInsanityRemake', - gen : dedent`{{font-family:BookInsanityRemake Dummy Text}}` - }, - { - name : 'Mr Eaves', - icon : 'font MrEavesRemake', - gen : dedent`{{font-family:MrEavesRemake Dummy Text}}` - }, - { - name : 'Pagella', - icon : 'font Pagella', - gen : dedent`{{font-family:Pagella Dummy Text}}` - }, - { - name : 'Solbera Imitation', - icon : 'font SolberaImitationRemake', - gen : dedent`{{font-family:SolberaImitationRemake Dummy Text}}` - }, - { - name : 'Scaly Sans Small Caps', - icon : 'font ScalySansSmallCapsRemake', - gen : dedent`{{font-family:ScalySansSmallCapsRemake Dummy Text}}` - }, - { - name : 'Walter Turncoat', - icon : 'font WalterTurncoat', - gen : dedent`{{font-family:WalterTurncoat Dummy Text}}` - }, - { - name : 'Lato', - icon : 'font Lato', - gen : dedent`{{font-family:Lato Dummy Text}}` - }, - { - name : 'Courier', - icon : 'font Courier', - gen : dedent`{{font-family:Courier Dummy Text}}` - }, - { - name : 'Nodesto Caps Condensed', - icon : 'font NodestoCapsCondensed', - gen : dedent`{{font-family:NodestoCapsCondensed Dummy Text}}` - }, - { - name : 'Overpass', - icon : 'font Overpass', - gen : dedent`{{font-family:Overpass Dummy Text}}` - }, - { - name : 'Davek', - icon : 'font Davek', - gen : dedent`{{font-family:Davek Dummy Text}}` - }, - { - name : 'Iokharic', - icon : 'font Iokharic', - gen : dedent`{{font-family:Iokharic Dummy Text}}` - }, - { - name : 'Rellanic', - icon : 'font Rellanic', - gen : dedent`{{font-family:Rellanic Dummy Text}}` - }, - { - name : 'Times New Roman', - icon : 'font TimesNewRoman', - gen : dedent`{{font-family:"Times New Roman" Dummy Text}}` - } - ] - }, - - /**************** LAYOUT *************/ - - { - groupName : 'Print', - icon : 'fas fa-print', - view : 'style', - snippets : [ - { - name : 'A3 Page Size', - icon : 'far fa-file', - gen : dedent`/* A3 Page Size */ - .page { - width : 297mm; - height : 420mm; - }\n\n`, - }, - { - name : 'A4 Page Size', - icon : 'far fa-file', - gen : dedent`/* A4 Page Size */ - .page { - width : 210mm; - height : 296.8mm; - }\n\n` - }, - { - name : 'A5 Page Size', - icon : 'far fa-file', - gen : dedent`/* A5 Page Size */ - .page { - width : 148mm; - height : 210mm; - }\n\n`, - }, - { - name : 'Square Page Size', - icon : 'far fa-file', - gen : dedent`/* Square Page Size */ - .page { - width : 125mm; - height : 125mm; - padding : 12.5mm; - columns : unset; - }\n\n` - }, - { - name : 'Card Page Size', - icon : 'far fa-file', - gen : dedent`/* Card Size */ - .page { - width : 63.5mm; - height : 88.9mm; - padding : 5mm; - columns : unset; - }\n\n` - }, - { - name : 'Ink Friendly', - icon : 'fas fa-tint', - gen : dedent` - /* Ink Friendly */ - *:is(.page) { - background : white !important; - filter : drop-shadow(0px 0px 3px #888) !important; - } - - .page img { - visibility : hidden; - }\n\n` - }, - ] - }, -]; diff --git a/themes/V4/Blank/snippets/footer.gen.js b/themes/V4/Blank/snippets/footer.gen.js deleted file mode 100644 index 9384baed7..000000000 --- a/themes/V4/Blank/snippets/footer.gen.js +++ /dev/null @@ -1,17 +0,0 @@ -import Markdown from '../../../../shared/naturalcrit/markdown.js'; - -module.exports = { - createFooterFunc : function(headerSize=1){ - return (props)=>{ - const cursorPos = props.cursorPos; - - const markdownText = props.brew.text.split('\n').slice(0, cursorPos.line).join('\n'); - const markdownTokens = Markdown.marked.lexer(markdownText); - const headerToken = markdownTokens.findLast((lexerToken)=>{ return lexerToken.type === 'heading' && lexerToken.depth === headerSize; }); - const headerText = headerToken?.tokens.map((token)=>{ return token.text; }).join(''); - const outputText = headerText || 'PART 1 | SECTION NAME'; - - return `\n{{footnote ${outputText}}}\n`; - }; - } -}; \ No newline at end of file diff --git a/themes/V4/Blank/snippets/imageMask.gen.js b/themes/V4/Blank/snippets/imageMask.gen.js deleted file mode 100644 index 323f89a1f..000000000 --- a/themes/V4/Blank/snippets/imageMask.gen.js +++ /dev/null @@ -1,46 +0,0 @@ -const _ = require('lodash'); -const dedent = require('dedent-tabs').default; - -module.exports = { - center : ()=>{ - return dedent` - {{imageMaskCenter${_.random(1, 16)},--offsetX:0%,--offsetY:0%,--rotation:0 - ![](https://i.imgur.com/GZfjDWV.png){height:100%} - }} - \n\n`; - }, - - edge : (side = 'bottom')=>{ - const rotation = { - 'bottom' : 0, - 'top' : 180, - 'left' : 90, - 'right' : 270 - }[side]; - return dedent` - {{imageMaskEdge${_.random(1, 8)},--offset:0%,--rotation:${rotation} - ![](https://i.imgur.com/GZfjDWV.png){height:100%} - }} - \n\n`; - }, - - corner : (y = 'top', x = 'left')=>{ - const offsetX = (x == 'left' ? '-50%' : '50%'); - const offsetY = (y == 'top' ? '50%' : '-50%'); - return dedent` - {{imageMaskCorner${_.random(1, 37)},--offsetX:${offsetX},--offsetY:${offsetY},--rotation:0 - ![](https://i.imgur.com/GZfjDWV.png){height:100%} - }} - \n\n`; - } - -}; - -()=>{ - -}; diff --git a/themes/V4/Blank/snippets/watercolor.gen.js b/themes/V4/Blank/snippets/watercolor.gen.js deleted file mode 100644 index 735a35602..000000000 --- a/themes/V4/Blank/snippets/watercolor.gen.js +++ /dev/null @@ -1,5 +0,0 @@ -const _ = require('lodash'); - -module.exports = ()=>{ - return `{{watercolor${_.random(1, 12)},top:20px,left:30px,width:300px,background-color:#BBAD82,opacity:80%}}\n\n`; -}; diff --git a/themes/V4/Blank/style.less b/themes/V4/Blank/style.less deleted file mode 100644 index 68d2ff07d..000000000 --- a/themes/V4/Blank/style.less +++ /dev/null @@ -1,524 +0,0 @@ -@import (less) './themes/fonts/Blank/fonts.less'; -@import (less) './themes/fonts/5e/fonts.less'; -@import (less) './themes/assets/assets.less'; -@import (less) './themes/fonts/iconFonts/elderberryInn.less'; -@import (less) './themes/fonts/iconFonts/diceFont.less'; -@import (less) './themes/fonts/iconFonts/gameIcons.less'; -@import (less) './themes/fonts/iconFonts/fontAwesome.less'; - -:root { - //Colors - --HB_Color_Background : #FFFFFF; // White - --HB_Color_WatercolorStain : #000000; // Black -} - -@page { margin : 0; } -body { counter-reset : page-numbers 0; } -* { -webkit-print-color-adjust : exact; } - -//***************************** -// * MUSTACHE DIVS/SPANS -// *****************************/ -.page { - .block { - break-inside : avoid; - display : inline-block; - width : 100%; - img { z-index : 0; } - } - .inline-block { - display : inline-block; - text-indent : initial; - } -} - -.useColumns(@multiplier : 1, @fillMode: auto) { - column-fill : @fillMode; - column-count : 2; -} -.columnWrapper { - column-gap : inherit; - max-height : 100%; - column-span : all; - columns : inherit; - column-fill : inherit; -} -.page { - .useColumns(); - position : relative; - z-index : 15; - box-sizing : border-box; - width : 215.9mm; - height : 279.4mm; - padding : 1.4cm 1.9cm 1.7cm; - overflow : hidden; - background-color : var(--HB_Color_Background); - text-rendering : optimizeLegibility; - contain : size; -} -//***************************** -// * BASE - // *****************************/ -.page { - p { - display : block; - overflow-wrap : break-word; - } - strong { font-weight : bold; } - em { font-style : italic; } - sup { - font-size : smaller; - line-height : 0; - vertical-align : super; - } - sub { - font-size : smaller; - line-height : 0; - vertical-align : sub; - } - ul { - padding-left : 1.4em; - list-style-position : outside; //Needed for multiline list items - list-style-type : disc; - } - ol { - padding-left : 1.4em; - list-style-position : outside; - list-style-type : decimal; - } - img { z-index : -1; } - - //***************************** - // * HEADERS - // *****************************/ - h1,h2,h3,h4,h5,h6 { - font-weight : bold; - line-height : 1.2em; - } - h1 { font-size : 2em; } - h2 { font-size : 1.5em; } - h3 { font-size : 1.17em; } - h4 { font-size : 1em; } - h5 { font-size : 0.83em; } - //***************************** - // * TABLE - // *****************************/ - table { - width : 100%; - thead { - display : table-row-group; - font-weight : bold; - } - } - div:not(.columnWrapper) > table + table { // Side-by-side tables should not - margin-top : 0; // have vertical spacing. - } - - //************************************ - // * CODE BLOCKS - // ************************************/ - code { - font-family : 'Courier New', "Courier", monospace; - overflow-wrap : break-word; - white-space : pre-wrap; - } - - pre code { - display : inline-block; - width : 100%; - } - //***************************** - // * EXTRAS - // *****************************/ - .columnSplit { - margin-top : 0; - visibility : hidden; - -webkit-column-break-after : always; - break-after : always; - -moz-column-break-after : always; - & + * { margin-top : 0; } - } - //Avoid breaking up - blockquote,table { - z-index : 15; - -webkit-column-break-inside : avoid; - page-break-inside : avoid; - break-inside : avoid; - } - // Nested lists - ul ul,ol ol,ul ol,ol ul { - margin-bottom : 0px; - margin-left : 1.5em; - } - li { - -webkit-column-break-inside : avoid; - page-break-inside : avoid; - break-inside : avoid; - } - - /* Wrap Text */ - .wrapLeft { - shape-outside : var(--HB_src); - float : right; - shape-margin : 0.2cm; - } - - .wrapRight { - shape-outside : var(--HB_src); - float : left; - shape-margin : 0.2cm; - } - - /* Watermark */ - .watermark { - position : absolute; - top : 0; - left : 0; - z-index : 500; - display : grid !important; - place-items : center; - justify-content : center; - width : 100%; - height : 100%; - margin : 0; - font-size : 120px; - text-transform : uppercase; - opacity : 30%; - transform : rotate(-45deg); - p { margin-bottom : none; } - } - - /* Watercolor */ - [class*='watercolor'] { - position : absolute; - z-index : -2; - width : 2000px; /* dimensions need to be real big so the user can set */ - height : 2000px; /* height or width and the image will maintain aspect ratio */ - background-color : var(--HB_Color_WatercolorStain); /* default color */ - background-size : cover; - -webkit-mask-image : var(--wc); - -webkit-mask-size : contain; - -webkit-mask-repeat : no-repeat; - mask-image : var(--wc); - mask-size : contain; - mask-repeat : no-repeat; - --wc : @watercolor1; /* default image */ - } - - .watercolor1 { --wc : @watercolor1; } - .watercolor2 { --wc : @watercolor2; } - .watercolor3 { --wc : @watercolor3; } - .watercolor4 { --wc : @watercolor4; } - .watercolor5 { --wc : @watercolor5; } - .watercolor6 { --wc : @watercolor6; } - .watercolor7 { --wc : @watercolor7; } - .watercolor8 { --wc : @watercolor8; } - .watercolor9 { --wc : @watercolor9; } - .watercolor10 { --wc : @watercolor10; } - .watercolor11 { --wc : @watercolor11; } - .watercolor12 { --wc : @watercolor12; } - - /* Image Masks */ - - [class*='imageMask'] { - position : absolute; - bottom : 50%; - left : 50%; - z-index : -1; - width : 200%; - height : 200%; - background-image : var(--checkerboard); - background-size : 20px; - transform : translateY(50%) translateX(-50%) rotate(calc(1deg * var(--rotation))) scaleX(var(--scaleX)) scaleY(var(--scaleY)); - -webkit-mask-image : var(--wc), var(--revealer); - -webkit-mask-repeat : repeat-x; - -webkit-mask-size : 50%; //Scale only X to fit page width, leave height at aspect ratio, designed to hang off the edge - -webkit-mask-position : 50% calc(50% - var(--offset)); - mask-image : var(--wc); - mask-repeat : repeat-x; - mask-size : 50%; - mask-position : 50% calc(50% - var(--offset)); - --rotation : 0; - --revealer : none; - --checkerboard : none; - --scaleX : 1; - --scaleY : 1; - & > p:has(img) { - position : absolute; - bottom : 50%; - left : 50%; - width : 50%; - height : 50%; - transform : translateX(-50%) translateY(50%) scaleX(calc(1 / var(--scaleX))) scaleY(calc(1 / var(--scaleY))) rotate(calc(-1deg * var(--rotation))); - } - & img { - position : absolute; - bottom : 0; - display : block; - } - &.bottom { - --rotation : 0; - & img {bottom : 0;} - } - &.top { - --rotation : 180; - & img {top : 0;} - } - &.left { - --rotation : 90; - & img {left : 0;} - } - &.right { - --rotation : -90; - & img {right : 0;} - } - &.revealImage { - --revealer : linear-gradient(0deg, rgba(0,0,0,0.2) 0%, rgba(0,0,0,0.2)); - --checkerboard : url("/assets/waterColorMasks/missingImage.png"); //shows any masked regions not filled by image - } - } - - .imageMaskEdge { - &1 { --wc : url("/assets/waterColorMasks/edge/0001.webp"); } - &2 { --wc : url("/assets/waterColorMasks/edge/0002.webp"); } - &3 { --wc : url("/assets/waterColorMasks/edge/0003.webp"); } - &4 { --wc : url("/assets/waterColorMasks/edge/0004.webp"); } - &5 { --wc : url("/assets/waterColorMasks/edge/0005.webp"); } - &6 { --wc : url("/assets/waterColorMasks/edge/0006.webp"); } - &7 { --wc : url("/assets/waterColorMasks/edge/0007.webp"); } - &8 { --wc : url("/assets/waterColorMasks/edge/0008.webp"); } - } - - [class*='imageMaskCenter'] { - bottom : calc(var(--offsetY)); - left : calc(var(--offsetX)); - width : 100%; - height : 100%; - transform : rotate(calc(1deg * var(--rotation))) scaleX(var(--scaleX)) scaleY(var(--scaleY)); - -webkit-mask-image : var(--wc), var(--revealer); - -webkit-mask-repeat : no-repeat; - -webkit-mask-size : 100% 100%; //Scale both dimensions to fit page size - -webkit-mask-position : 0% 0%; - mask-image : var(--wc), var(--revealer); - mask-repeat : no-repeat; - mask-size : 100% 100%; //Scale both dimensions to fit page size - mask-position : 50% 50%; - - & > p:has(img) { - position : absolute; - bottom : 0; - left : 0; - width : 100%; - height : 100%; - transform : unset; - transform : scaleX(calc(1 / var(--scaleX))) scaleY(calc(1 / var(--scaleY))) - rotate(calc(-1deg * var(--rotation))) - translateX(calc(-1 * var(--offsetX))) - translateY(calc(1 * var(--offsetY))); - } - } - - .imageMaskCenter { - &1 { --wc : url("/assets/waterColorMasks/center/0001.webp"); } - &2 { --wc : url("/assets/waterColorMasks/center/0002.webp"); } - &3 { --wc : url("/assets/waterColorMasks/center/0003.webp"); } - &4 { --wc : url("/assets/waterColorMasks/center/0004.webp"); } - &5 { --wc : url("/assets/waterColorMasks/center/0005.webp"); } - &6 { --wc : url("/assets/waterColorMasks/center/0006.webp"); } - &7 { --wc : url("/assets/waterColorMasks/center/0007.webp"); } - &8 { --wc : url("/assets/waterColorMasks/center/0008.webp"); } - &9 { --wc : url("/assets/waterColorMasks/center/0009.webp"); } - &10 { --wc : url("/assets/waterColorMasks/center/0010.webp"); } - &11 { --wc : url("/assets/waterColorMasks/center/0011.webp"); } - &12 { --wc : url("/assets/waterColorMasks/center/0012.webp"); } - &13 { --wc : url("/assets/waterColorMasks/center/0013.webp"); } - &14 { --wc : url("/assets/waterColorMasks/center/0014.webp"); } - &15 { --wc : url("/assets/waterColorMasks/center/0015.webp"); } - &16 { --wc : url("/assets/waterColorMasks/center/0016.webp"); } - &special { --wc : url("/assets/waterColorMasks/center/special.webp"); } - } - - - [class*='imageMaskCorner'] { - bottom : calc(-50% + var(--offsetY)); - left : calc(-50% + var(--offsetX)); - width : 200%; - height : 200%; - transform : rotate(calc(1deg * var(--rotation))) scaleX(var(--scaleX)) scaleY(var(--scaleY)); - -webkit-mask-image : var(--wc), var(--revealer); - -webkit-mask-repeat : no-repeat; - -webkit-mask-size : 100% 100%; //Scale both dimensions to fit page size - -webkit-mask-position : 50% 50%; - mask-image : var(--wc), var(--revealer); - mask-repeat : no-repeat; - mask-size : 100% 100%; //Scale both dimensions to fit page size - mask-position : 50% 50%; - & > p:has(img) { - bottom : 25%; - left : 25%; - width : 50%; - height : 50%; //Complex transform below to handle mix of % and cm offsets - transform : scaleX(calc(1 / var(--scaleX))) scaleY(calc(1 / var(--scaleY))) - rotate(calc(-1deg * var(--rotation))) - translateX(calc(-1 * var(--offsetX))) - translateY(calc(1 * var(--offsetY))); - } - } - .imageMaskCorner { - &1 { --wc : url("/assets/waterColorMasks/corner/0001.webp"); } - &2 { --wc : url("/assets/waterColorMasks/corner/0002.webp"); } - &3 { --wc : url("/assets/waterColorMasks/corner/0003.webp"); } - &4 { --wc : url("/assets/waterColorMasks/corner/0004.webp"); } - &5 { --wc : url("/assets/waterColorMasks/corner/0005.webp"); } - &6 { --wc : url("/assets/waterColorMasks/corner/0006.webp"); } - &7 { --wc : url("/assets/waterColorMasks/corner/0007.webp"); } - &8 { --wc : url("/assets/waterColorMasks/corner/0008.webp"); } - &9 { --wc : url("/assets/waterColorMasks/corner/0009.webp"); } - &10 { --wc : url("/assets/waterColorMasks/corner/0010.webp"); } - &11 { --wc : url("/assets/waterColorMasks/corner/0011.webp"); } - &12 { --wc : url("/assets/waterColorMasks/corner/0012.webp"); } - &13 { --wc : url("/assets/waterColorMasks/corner/0013.webp"); } - &14 { --wc : url("/assets/waterColorMasks/corner/0014.webp"); } - &15 { --wc : url("/assets/waterColorMasks/corner/0015.webp"); } - &16 { --wc : url("/assets/waterColorMasks/corner/0016.webp"); } - &17 { --wc : url("/assets/waterColorMasks/corner/0017.webp"); } - &18 { --wc : url("/assets/waterColorMasks/corner/0018.webp"); } - &19 { --wc : url("/assets/waterColorMasks/corner/0019.webp"); } - &20 { --wc : url("/assets/waterColorMasks/corner/0020.webp"); } - &21 { --wc : url("/assets/waterColorMasks/corner/0021.webp"); } - &22 { --wc : url("/assets/waterColorMasks/corner/0022.webp"); } - &23 { --wc : url("/assets/waterColorMasks/corner/0023.webp"); } - &24 { --wc : url("/assets/waterColorMasks/corner/0024.webp"); } - &25 { --wc : url("/assets/waterColorMasks/corner/0025.webp"); } - &26 { --wc : url("/assets/waterColorMasks/corner/0026.webp"); } - &27 { --wc : url("/assets/waterColorMasks/corner/0027.webp"); } - &28 { --wc : url("/assets/waterColorMasks/corner/0028.webp"); } - &29 { --wc : url("/assets/waterColorMasks/corner/0029.webp"); } - &30 { --wc : url("/assets/waterColorMasks/corner/0030.webp"); } - &31 { --wc : url("/assets/waterColorMasks/corner/0031.webp"); } - &32 { --wc : url("/assets/waterColorMasks/corner/0032.webp"); } - &33 { --wc : url("/assets/waterColorMasks/corner/0033.webp"); } - &34 { --wc : url("/assets/waterColorMasks/corner/0034.webp"); } - &35 { --wc : url("/assets/waterColorMasks/corner/0035.webp"); } - &36 { --wc : url("/assets/waterColorMasks/corner/0036.webp"); } - &37 { --wc : url("/assets/waterColorMasks/corner/0037.webp"); } - } -} - -//***************************** -// * DEFINITION LISTS -// *****************************/ -.page { - dl { - padding-left : 1em; - white-space : pre-line; - } - dt { - display : inline; - margin-right : 0.5ch; - margin-left : -1em; - } - dd { - display : inline; - margin-left : 0; - text-indent : 0; - } -} - -//***************************** -// * BLANK LINE -// *****************************/ -.page { - .blank { - height : 1em; - margin-top : 0; - & + * { margin-top : 0; } - } -} - -//***************************** -// * WIDE -// *****************************/ -.page { - .wide { - column-span : all; - display : block; - margin-bottom : 1em; - & + * { margin-top : 0; } - } -} - -//***************************** -//* CREDITS -//*****************************/ -.page .homebreweryCredits { - p { - font-family : 'NodestoCapsWide'; - font-size : 0.4cm; - line-height : 1em; - text-align : center; - text-indent : 0; - letter-spacing : 0.08em; - } - a { - color : inherit; - text-decoration : none; - &:hover { text-decoration : underline; } - } - .homebreweryIcon { - display : block; - height : 1.5cm; - margin : 0 auto; - background-color : black; - -webkit-mask : url("/assets/naturalCritLogoWhite.svg") center / contain no-repeat; - mask : url("/assets/naturalCritLogoWhite.svg") center / contain no-repeat; - } - .homebreweryIcon.red { background-color : red; } - .homebreweryIcon.gold { background-image : linear-gradient(to top left, brown 22.5%, gold 40%, white 60%, gold 67.5%, brown 82.5%); } -} - -//***************************** -//* Page Number -//*****************************/ -.page { - .pageNumber { - position : absolute; - right : 30px; - bottom : 30px; - width : 50px; - font-size : 0.9em; - text-align : center; - &.auto::after { content : counter(page-numbers); } - } - - &:nth-child(even) { - .pageNumber { left : 30px; } - } - - .resetCounting { - counter-set : page-numbers 1; - } - - &:not(:has(.skipCounting)) { - counter-increment : page-numbers; - } - -} - -//***************************** -//* Forced Justification -//*****************************/ - -.page { - .mdParagraphJustifyLeft { - text-align: left; - } - - .mdParagraphJustifyRight { - text-align: right; - } - - .mdParagraphJustifyCenter { - text-align: center; - } -} From 3c735e599fb6f5b57b048c19da02dda759340509 Mon Sep 17 00:00:00 2001 From: David Bolack Date: Tue, 14 Jan 2025 06:59:46 -0600 Subject: [PATCH 110/398] Add a CR --- themes/V3/Blank/style.less | 1 + 1 file changed, 1 insertion(+) diff --git a/themes/V3/Blank/style.less b/themes/V3/Blank/style.less index 65eeee683..441bd3588 100644 --- a/themes/V3/Blank/style.less +++ b/themes/V3/Blank/style.less @@ -506,3 +506,4 @@ body { counter-reset : page-numbers 0; } } } + From 20bfff51570ddea9ad063613bf3932f7b56d0c43 Mon Sep 17 00:00:00 2001 From: David Bolack Date: Tue, 14 Jan 2025 07:00:24 -0600 Subject: [PATCH 111/398] Remove it back? Meh. Just trying to revert to last --- themes/V3/Blank/style.less | 1 - 1 file changed, 1 deletion(-) diff --git a/themes/V3/Blank/style.less b/themes/V3/Blank/style.less index 441bd3588..65eeee683 100644 --- a/themes/V3/Blank/style.less +++ b/themes/V3/Blank/style.less @@ -506,4 +506,3 @@ body { counter-reset : page-numbers 0; } } } - From aafc6fad7d80883a2b92936bf27db15461849afc Mon Sep 17 00:00:00 2001 From: David Bolack Date: Tue, 14 Jan 2025 21:40:15 -0600 Subject: [PATCH 112/398] Implement suggested fix for 3488 Per issue --- shared/naturalcrit/markdown.js | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/shared/naturalcrit/markdown.js b/shared/naturalcrit/markdown.js index 852243d81..76938c7e0 100644 --- a/shared/naturalcrit/markdown.js +++ b/shared/naturalcrit/markdown.js @@ -1,3 +1,4 @@ +/* eslint-disable max-depth */ /* eslint-disable max-lines */ import _ from 'lodash'; import { Parser as MathParser } from 'expr-eval'; @@ -680,7 +681,7 @@ function MarkedVariables() { } if(match[8]) { // Inline Definition const label = match[10] ? match[10].trim().replace(/\s+/g, ' ') : null; // Trim edge spaces and shorten blocks of whitespace to 1 space - let content = match[11] ? match[11].trim().replace(/\s+/g, ' ') : null; // Trim edge spaces and shorten blocks of whitespace to 1 space + let content = match[11] ? match[11] : null; // Trim edge spaces and shorten blocks of whitespace to 1 space // In case of nested (), find the correct matching end ) let level = 0; @@ -696,10 +697,8 @@ function MarkedVariables() { break; } } - if(i > -1) { - combinedRegex.lastIndex = combinedRegex.lastIndex - (content.length - i); - content = content.slice(0, i).trim().replace(/\s+/g, ' '); - } + combinedRegex.lastIndex = combinedRegex.lastIndex - (content.length - i); + content = content.slice(0, i).trim().replace(/\s+/g, ' '); varsQueue.push( { type : 'varDefBlock', From e5e9a9efe14239d2a94d003cd0d3d332eea00c5b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 15 Jan 2025 03:42:56 +0000 Subject: [PATCH 113/398] Bump eslint-plugin-jest from 28.10.0 to 28.11.0 Bumps [eslint-plugin-jest](https://github.com/jest-community/eslint-plugin-jest) from 28.10.0 to 28.11.0. - [Release notes](https://github.com/jest-community/eslint-plugin-jest/releases) - [Changelog](https://github.com/jest-community/eslint-plugin-jest/blob/main/CHANGELOG.md) - [Commits](https://github.com/jest-community/eslint-plugin-jest/compare/v28.10.0...v28.11.0) --- updated-dependencies: - dependency-name: eslint-plugin-jest dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- package-lock.json | 8 ++++---- package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index bc7a69d43..938183607 100644 --- a/package-lock.json +++ b/package-lock.json @@ -56,7 +56,7 @@ "@stylistic/stylelint-plugin": "^3.1.1", "babel-plugin-transform-import-meta": "^2.3.2", "eslint": "^9.18.0", - "eslint-plugin-jest": "^28.10.0", + "eslint-plugin-jest": "^28.11.0", "eslint-plugin-react": "^7.37.4", "globals": "^15.14.0", "jest": "^29.7.0", @@ -5709,9 +5709,9 @@ } }, "node_modules/eslint-plugin-jest": { - "version": "28.10.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-28.10.0.tgz", - "integrity": "sha512-hyMWUxkBH99HpXT3p8hc7REbEZK3D+nk8vHXGgpB+XXsi0gO4PxMSP+pjfUzb67GnV9yawV9a53eUmcde1CCZA==", + "version": "28.11.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-28.11.0.tgz", + "integrity": "sha512-QAfipLcNCWLVocVbZW8GimKn5p5iiMcgGbRzz8z/P5q7xw+cNEpYqyzFMtIF/ZgF2HLOyy+dYBut+DoYolvqig==", "dev": true, "dependencies": { "@typescript-eslint/utils": "^6.0.0 || ^7.0.0 || ^8.0.0" diff --git a/package.json b/package.json index df2453171..db96a2779 100644 --- a/package.json +++ b/package.json @@ -130,7 +130,7 @@ "@stylistic/stylelint-plugin": "^3.1.1", "babel-plugin-transform-import-meta": "^2.3.2", "eslint": "^9.18.0", - "eslint-plugin-jest": "^28.10.0", + "eslint-plugin-jest": "^28.11.0", "eslint-plugin-react": "^7.37.4", "globals": "^15.14.0", "jest": "^29.7.0", From aea9296908746aeb3c19c3a046e49dd38346c258 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 15 Jan 2025 08:29:16 +0000 Subject: [PATCH 114/398] Bump stylelint from 16.13.1 to 16.13.2 Bumps [stylelint](https://github.com/stylelint/stylelint) from 16.13.1 to 16.13.2. - [Release notes](https://github.com/stylelint/stylelint/releases) - [Changelog](https://github.com/stylelint/stylelint/blob/main/CHANGELOG.md) - [Commits](https://github.com/stylelint/stylelint/compare/16.13.1...16.13.2) --- updated-dependencies: - dependency-name: stylelint dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- package-lock.json | 8 ++++---- package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index 938183607..a35f04806 100644 --- a/package-lock.json +++ b/package-lock.json @@ -63,7 +63,7 @@ "jest-expect-message": "^1.1.3", "jsdom-global": "^3.0.2", "postcss-less": "^6.0.0", - "stylelint": "^16.13.1", + "stylelint": "^16.13.2", "stylelint-config-recess-order": "^5.1.1", "stylelint-config-recommended": "^15.0.0", "supertest": "^7.0.0" @@ -13038,9 +13038,9 @@ "license": "ISC" }, "node_modules/stylelint": { - "version": "16.13.1", - "resolved": "https://registry.npmjs.org/stylelint/-/stylelint-16.13.1.tgz", - "integrity": "sha512-691JjSIIcP6f9QJFz0J0/AMG3lupE9RqYAgYCON3wiqp5nQiKqDYIsz321GeTOYNznoRPNh0Mf6VjzP1eBVz/Q==", + "version": "16.13.2", + "resolved": "https://registry.npmjs.org/stylelint/-/stylelint-16.13.2.tgz", + "integrity": "sha512-wDlgh0mRO9RtSa3TdidqHd0nOG8MmUyVKl+dxA6C1j8aZRzpNeEgdhFmU5y4sZx4Fc6r46p0fI7p1vR5O2DZqA==", "dev": true, "funding": [ { diff --git a/package.json b/package.json index db96a2779..37720f49e 100644 --- a/package.json +++ b/package.json @@ -137,7 +137,7 @@ "jest-expect-message": "^1.1.3", "jsdom-global": "^3.0.2", "postcss-less": "^6.0.0", - "stylelint": "^16.13.1", + "stylelint": "^16.13.2", "stylelint-config-recess-order": "^5.1.1", "stylelint-config-recommended": "^15.0.0", "supertest": "^7.0.0" From d4f6c329b8064350a654b90094c5c483c0299b7a Mon Sep 17 00:00:00 2001 From: David Bolack Date: Wed, 15 Jan 2025 17:36:18 -0600 Subject: [PATCH 115/398] Add a test! --- shared/naturalcrit/markdown.js | 2 +- tests/markdown/variables.test.js | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/shared/naturalcrit/markdown.js b/shared/naturalcrit/markdown.js index 76938c7e0..ffd2395fa 100644 --- a/shared/naturalcrit/markdown.js +++ b/shared/naturalcrit/markdown.js @@ -681,7 +681,7 @@ function MarkedVariables() { } if(match[8]) { // Inline Definition const label = match[10] ? match[10].trim().replace(/\s+/g, ' ') : null; // Trim edge spaces and shorten blocks of whitespace to 1 space - let content = match[11] ? match[11] : null; // Trim edge spaces and shorten blocks of whitespace to 1 space + let content = match[11] || null; // In case of nested (), find the correct matching end ) let level = 0; diff --git a/tests/markdown/variables.test.js b/tests/markdown/variables.test.js index be16e8a22..9a02d15eb 100644 --- a/tests/markdown/variables.test.js +++ b/tests/markdown/variables.test.js @@ -402,4 +402,10 @@ describe('Variable names that are subsets of other names', ()=>{ const rendered = Markdown.render(source).trimReturns(); expect(rendered).toBe('

14

'); }); +}); + +describe('Don\'t Eat all the parentheticals!', ()=>{ + const source='\n| title 1 | title 2 | title 3 | title 4|\n|-----------|---------|---------|--------|\n|[foo](bar) | Ipsum | ) | ) |\n'; + const rendered = Markdown.render(source).trimReturns(); + expect(rendered).toBe('
{name}clipview
{result[name].toString()} {navigator.clipboard.writeText(result.shareId.toString());}}>
title 1title 2title 3title 4
fooIpsum))
'); }); \ No newline at end of file From 5dbb5499c6fe8f0f6c9971e13d4c07820c5e0e29 Mon Sep 17 00:00:00 2001 From: David Bolack Date: Fri, 17 Jan 2025 10:02:32 -0600 Subject: [PATCH 116/398] fix test --- tests/markdown/variables.test.js | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/tests/markdown/variables.test.js b/tests/markdown/variables.test.js index 9a02d15eb..41259da7e 100644 --- a/tests/markdown/variables.test.js +++ b/tests/markdown/variables.test.js @@ -404,8 +404,10 @@ describe('Variable names that are subsets of other names', ()=>{ }); }); -describe('Don\'t Eat all the parentheticals!', ()=>{ - const source='\n| title 1 | title 2 | title 3 | title 4|\n|-----------|---------|---------|--------|\n|[foo](bar) | Ipsum | ) | ) |\n'; - const rendered = Markdown.render(source).trimReturns(); - expect(rendered).toBe('
title 1title 2title 3title 4
fooIpsum))
'); +describe('Regression Tests', ()=>{ + it('Don\'t Eat all the parentheticals!', function() { + const source='\n| title 1 | title 2 | title 3 | title 4|\n|-----------|---------|---------|--------|\n|[foo](bar) | Ipsum | ) | ) |\n'; + const rendered = Markdown.render(source).trimReturns(); + expect(rendered).toBe('
title 1title 2title 3title 4
fooIpsum))
'); + }); }); \ No newline at end of file From 7c1545a07db9045de9f205c7733fbf6dc8fd0658 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 17 Jan 2025 16:52:32 +0000 Subject: [PATCH 117/398] Bump fs-extra from 11.2.0 to 11.3.0 Bumps [fs-extra](https://github.com/jprichardson/node-fs-extra) from 11.2.0 to 11.3.0. - [Changelog](https://github.com/jprichardson/node-fs-extra/blob/master/CHANGELOG.md) - [Commits](https://github.com/jprichardson/node-fs-extra/compare/11.2.0...11.3.0) --- updated-dependencies: - dependency-name: fs-extra dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- package-lock.json | 9 ++++----- package.json | 2 +- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/package-lock.json b/package-lock.json index a35f04806..8fe35a233 100644 --- a/package-lock.json +++ b/package-lock.json @@ -28,7 +28,7 @@ "express": "^4.21.2", "express-async-handler": "^1.2.0", "express-static-gzip": "2.2.0", - "fs-extra": "11.2.0", + "fs-extra": "11.3.0", "idb-keyval": "^6.2.1", "js-yaml": "^4.1.0", "jwt-simple": "^0.5.6", @@ -6507,10 +6507,9 @@ } }, "node_modules/fs-extra": { - "version": "11.2.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.2.0.tgz", - "integrity": "sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==", - "license": "MIT", + "version": "11.3.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.0.tgz", + "integrity": "sha512-Z4XaCL6dUDHfP/jT25jJKMmtxvuwbkrD1vNSMFlo9lNLY2c5FHYSQgHPRZUjAB26TpDEoW9HCOgplrdbaPV/ew==", "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", diff --git a/package.json b/package.json index 37720f49e..57448640c 100644 --- a/package.json +++ b/package.json @@ -102,7 +102,7 @@ "express": "^4.21.2", "express-async-handler": "^1.2.0", "express-static-gzip": "2.2.0", - "fs-extra": "11.2.0", + "fs-extra": "11.3.0", "idb-keyval": "^6.2.1", "js-yaml": "^4.1.0", "jwt-simple": "^0.5.6", From aa34bb44c967badaae6688bb95361ad8b62fe938 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 17 Jan 2025 03:45:57 +0000 Subject: [PATCH 118/398] Bump react-router from 7.1.1 to 7.1.2 Bumps [react-router](https://github.com/remix-run/react-router/tree/HEAD/packages/react-router) from 7.1.1 to 7.1.2. - [Release notes](https://github.com/remix-run/react-router/releases) - [Changelog](https://github.com/remix-run/react-router/blob/main/packages/react-router/CHANGELOG.md) - [Commits](https://github.com/remix-run/react-router/commits/react-router@7.1.2/packages/react-router) --- updated-dependencies: - dependency-name: react-router dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- package-lock.json | 8 ++++---- package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index 8fe35a233..41ac55fe6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -47,7 +47,7 @@ "react": "^18.3.1", "react-dom": "^18.3.1", "react-frame-component": "^5.2.7", - "react-router": "^7.1.1", + "react-router": "^7.1.2", "sanitize-filename": "1.6.3", "superagent": "^10.1.1", "vitreum": "git+https://git@github.com/calculuschild/vitreum.git" @@ -11653,9 +11653,9 @@ "license": "MIT" }, "node_modules/react-router": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/react-router/-/react-router-7.1.1.tgz", - "integrity": "sha512-39sXJkftkKWRZ2oJtHhCxmoCrBCULr/HAH4IT5DHlgu/Q0FCPV0S4Lx+abjDTx/74xoZzNYDYbOZWlJjruyuDQ==", + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-7.1.2.tgz", + "integrity": "sha512-KeallSO30KLpIe/ZZqfk6pCJ1c+5JhMxl3SCS3Zx1LgaGuQbgLDmjuNi6KZ5LnAV9sWjbmBWGRw8Um/Pw6BExg==", "dependencies": { "@types/cookie": "^0.6.0", "cookie": "^1.0.1", diff --git a/package.json b/package.json index 57448640c..a74dcf3e0 100644 --- a/package.json +++ b/package.json @@ -121,7 +121,7 @@ "react": "^18.3.1", "react-dom": "^18.3.1", "react-frame-component": "^5.2.7", - "react-router": "^7.1.1", + "react-router": "^7.1.2", "sanitize-filename": "1.6.3", "superagent": "^10.1.1", "vitreum": "git+https://git@github.com/calculuschild/vitreum.git" From 4a2b8dc261da349231f765a4871aa6f472048531 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 20 Jan 2025 03:44:58 +0000 Subject: [PATCH 119/398] Bump stylelint-config-recess-order from 5.1.1 to 6.0.0 Bumps [stylelint-config-recess-order](https://github.com/stormwarning/stylelint-config-recess-order) from 5.1.1 to 6.0.0. - [Release notes](https://github.com/stormwarning/stylelint-config-recess-order/releases) - [Changelog](https://github.com/stormwarning/stylelint-config-recess-order/blob/main/CHANGELOG.md) - [Commits](https://github.com/stormwarning/stylelint-config-recess-order/compare/v5.1.1...v6.0.0) --- updated-dependencies: - dependency-name: stylelint-config-recess-order dependency-type: direct:development update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- package-lock.json | 8 ++++---- package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index 41ac55fe6..727314014 100644 --- a/package-lock.json +++ b/package-lock.json @@ -64,7 +64,7 @@ "jsdom-global": "^3.0.2", "postcss-less": "^6.0.0", "stylelint": "^16.13.2", - "stylelint-config-recess-order": "^5.1.1", + "stylelint-config-recess-order": "^6.0.0", "stylelint-config-recommended": "^15.0.0", "supertest": "^7.0.0" }, @@ -13099,9 +13099,9 @@ } }, "node_modules/stylelint-config-recess-order": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/stylelint-config-recess-order/-/stylelint-config-recess-order-5.1.1.tgz", - "integrity": "sha512-eDAHWVBelzDbMbdMj15pSw0Ycykv5eLeriJdbGCp0zd44yvhgZLI+wyVHegzXp5NrstxTPSxl0fuOVKdMm0XLA==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/stylelint-config-recess-order/-/stylelint-config-recess-order-6.0.0.tgz", + "integrity": "sha512-1KqrttqpIrCYFAVQ1/bbgXo7EvvcjmkxxmnzVr+U66Xr2OlrNZqQ5+44Tmct6grCWY6wGTIBh2tSANqcmwIM2g==", "dev": true, "dependencies": { "stylelint-order": "^6.0.4" diff --git a/package.json b/package.json index d70b05c61..0f10e5d8e 100644 --- a/package.json +++ b/package.json @@ -139,7 +139,7 @@ "jsdom-global": "^3.0.2", "postcss-less": "^6.0.0", "stylelint": "^16.13.2", - "stylelint-config-recess-order": "^5.1.1", + "stylelint-config-recess-order": "^6.0.0", "stylelint-config-recommended": "^15.0.0", "supertest": "^7.0.0" } From 76ccbfbf2014af1dc537b3d38f00dd7e4830106e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 20 Jan 2025 09:12:11 +0000 Subject: [PATCH 120/398] Bump react-router from 7.1.2 to 7.1.3 Bumps [react-router](https://github.com/remix-run/react-router/tree/HEAD/packages/react-router) from 7.1.2 to 7.1.3. - [Release notes](https://github.com/remix-run/react-router/releases) - [Changelog](https://github.com/remix-run/react-router/blob/main/packages/react-router/CHANGELOG.md) - [Commits](https://github.com/remix-run/react-router/commits/react-router@7.1.3/packages/react-router) --- updated-dependencies: - dependency-name: react-router dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- package-lock.json | 8 ++++---- package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index 727314014..5e5b3a6b1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -47,7 +47,7 @@ "react": "^18.3.1", "react-dom": "^18.3.1", "react-frame-component": "^5.2.7", - "react-router": "^7.1.2", + "react-router": "^7.1.3", "sanitize-filename": "1.6.3", "superagent": "^10.1.1", "vitreum": "git+https://git@github.com/calculuschild/vitreum.git" @@ -11653,9 +11653,9 @@ "license": "MIT" }, "node_modules/react-router": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/react-router/-/react-router-7.1.2.tgz", - "integrity": "sha512-KeallSO30KLpIe/ZZqfk6pCJ1c+5JhMxl3SCS3Zx1LgaGuQbgLDmjuNi6KZ5LnAV9sWjbmBWGRw8Um/Pw6BExg==", + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-7.1.3.tgz", + "integrity": "sha512-EezYymLY6Guk/zLQ2vRA8WvdUhWFEj5fcE3RfWihhxXBW7+cd1LsIiA3lmx+KCmneAGQuyBv820o44L2+TtkSA==", "dependencies": { "@types/cookie": "^0.6.0", "cookie": "^1.0.1", diff --git a/package.json b/package.json index 0f10e5d8e..09e9d4ef9 100644 --- a/package.json +++ b/package.json @@ -122,7 +122,7 @@ "react": "^18.3.1", "react-dom": "^18.3.1", "react-frame-component": "^5.2.7", - "react-router": "^7.1.2", + "react-router": "^7.1.3", "sanitize-filename": "1.6.3", "superagent": "^10.1.1", "vitreum": "git+https://git@github.com/calculuschild/vitreum.git" From 2a9945f09ff31abcd8b9a9533cdac3c7edeee7c7 Mon Sep 17 00:00:00 2001 From: Trevor Buckner Date: Tue, 21 Jan 2025 16:14:36 -0500 Subject: [PATCH 121/398] Extract common function to merge HTML tags --- shared/naturalcrit/markdown.js | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/shared/naturalcrit/markdown.js b/shared/naturalcrit/markdown.js index 16dc14440..c2aa89fb5 100644 --- a/shared/naturalcrit/markdown.js +++ b/shared/naturalcrit/markdown.js @@ -2,7 +2,7 @@ /* eslint-disable max-lines */ import _ from 'lodash'; import { Parser as MathParser } from 'expr-eval'; -import { marked as Marked } from 'marked'; +import { marked as Marked } from 'marked'; import MarkedExtendedTables from 'marked-extended-tables'; import { markedSmartypantsLite as MarkedSmartypantsLite } from 'marked-smartypants-lite'; import { gfmHeadingId as MarkedGFMHeadingId, resetHeadings as MarkedGFMResetHeadingIDs } from 'marked-gfm-heading-id'; @@ -266,12 +266,7 @@ const mustacheInjectInline = { const text = this.parser.parseInline([token]); const originalTags = extractHTMLStyleTags(text); const injectedTags = token.injectedTags; - const tags = { - id : injectedTags.id || originalTags.id || null, - classes : [originalTags.classes, injectedTags.classes].join(' ').trim() || null, - styles : [originalTags.styles, injectedTags.styles].join(' ').trim() || null, - attributes : Object.assign(originalTags.attributes ?? {}, injectedTags.attributes ?? {}) - }; + const tags = mergeHTMLTags(originalTags, injectedTags); const openingTag = /(<[^\s<>]+)[^\n<>]*(>.*)/s.exec(text); if(openingTag) { return `${openingTag[1]}` + @@ -315,12 +310,7 @@ const mustacheInjectBlock = { const text = this.parser.parse([token]); const originalTags = extractHTMLStyleTags(text); const injectedTags = token.injectedTags; - const tags = { - id : injectedTags.id || originalTags.id || null, - classes : [originalTags.classes, injectedTags.classes].join(' ').trim() || null, - styles : [originalTags.styles, injectedTags.styles].join(' ').trim() || null, - attributes : Object.assign(originalTags.attributes ?? {}, injectedTags.attributes ?? {}) - }; + const tags = mergeHTMLTags(originalTags, injectedTags); const openingTag = /(<[^\s<>]+)[^\n<>]*(>.*)/s.exec(text); if(openingTag) { return `${openingTag[1]}` + @@ -908,6 +898,15 @@ const extractHTMLStyleTags = (htmlString)=>{ }; }; +const mergeHTMLTags = (originalTags, newTags) => { + return { + id : newTags.id || originalTags.id || null, + classes : [originalTags.classes, newTags.classes].join(' ').trim() || null, + styles : [originalTags.styles, newTags.styles].join(' ').trim() || null, + attributes : Object.assign(originalTags.attributes ?? {}, newTags.attributes ?? {}) + }; +}; + const globalVarsList = {}; let varsQueue = []; let globalPageNumber = 0; From eebc9c2bfae935072a49453a50ae390829140ac0 Mon Sep 17 00:00:00 2001 From: Trevor Buckner Date: Wed, 22 Jan 2025 15:04:33 -0500 Subject: [PATCH 122/398] commit changes so far --- client/homebrew/brewRenderer/brewRenderer.jsx | 23 +++++++++++++++++-- shared/naturalcrit/markdown.js | 19 ++++++++++++++- 2 files changed, 39 insertions(+), 3 deletions(-) diff --git a/client/homebrew/brewRenderer/brewRenderer.jsx b/client/homebrew/brewRenderer/brewRenderer.jsx index 17f261c2d..529605a40 100644 --- a/client/homebrew/brewRenderer/brewRenderer.jsx +++ b/client/homebrew/brewRenderer/brewRenderer.jsx @@ -40,7 +40,7 @@ const BrewPage = (props)=>{ ...props }; const pageRef = useRef(null); - const cleanText = safeHTML(props.contents); + let cleanText = safeHTML(props.contents); useEffect(()=>{ if(!pageRef.current) return; @@ -78,6 +78,20 @@ const BrewPage = (props)=>{ }; }, []); + // Extract any page styles from `\page{cssProp:value}` + if(cleanText.match(/^ { + const [key, value] = curr.split(':').map(item => item.trim()); + const camelCaseKey = key.replace(/-([a-z])/g, g => g[1].toUpperCase()); //Convert to camelCase for React + acc[camelCaseKey] = value; + return acc; + }, {}); + + props.style = {...props.style, ...styleObject}; + cleanText = cleanText.substring(cleanText.indexOf('\n')); + } + return
; @@ -126,7 +140,7 @@ const BrewRenderer = (props)=>{ if(props.renderer == 'legacy') { rawPages = props.text.split('\\page'); } else { - rawPages = props.text.split(/^\\page$/gm); + rawPages = props.text.split(/^(?=\\page(?:{[^\n{}]+})?$)/gm); } const handlePageVisibilityChange = (pageNum, isVisible, isCenter)=>{ @@ -183,6 +197,11 @@ const BrewRenderer = (props)=>{ return ; } else { + let pageText2 = pageText.substring(0, pageText.indexOf('\n')); + let butt = Markdown.marked.lexer(pageText2); + console.log(butt) + + 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); diff --git a/shared/naturalcrit/markdown.js b/shared/naturalcrit/markdown.js index c2aa89fb5..78eef8ebd 100644 --- a/shared/naturalcrit/markdown.js +++ b/shared/naturalcrit/markdown.js @@ -527,6 +527,21 @@ const definitionListsMultiLine = { } }; +const pageBreak = { + name : 'pageBreak', + level : 'block', + start(src) { return src.match(/\n\\page/m)?.index; }, // Hint to Marked.js to stop and check for a match + tokenizer(src) { + const regex = /^\\page(?:$|(?={[^\n{}]+}$))/m; + const match = regex.exec(src); + if(match?.length) + return { type : 'pageBreak', raw : match[0] }; + }, + renderer(token) { + return `\n`; + } +}; + //v=====--------------------< Variable Handling >-------------------=====v// 242 lines const replaceVar = function(input, hoist=false, allowUnresolved=false) { const regex = /([!$]?)\[((?!\s*\])(?:\\.|[^\[\]\\])+)\]/g; @@ -795,7 +810,7 @@ const tableTerminators = [ ]; Marked.use(MarkedVariables()); -Marked.use({ extensions : [justifiedParagraphs, definitionListsMultiLine, definitionListsSingleLine, forcedParagraphBreaks, +Marked.use({ extensions : [pageBreak, justifiedParagraphs, definitionListsMultiLine, definitionListsSingleLine, forcedParagraphBreaks, nonbreakingSpaces, superSubScripts, mustacheSpans, mustacheDivs, mustacheInjectInline] }); Marked.use(mustacheInjectBlock); Marked.use({ renderer: renderer, tokenizer: tokenizer, mangle: false }); @@ -992,6 +1007,8 @@ const Markdown = { return errors; }, + + extractHTMLStyleTags : extractHTMLStyleTags }; export default Markdown; From 8e99d478696889a47ad7e4ae7725834c79bcea2e Mon Sep 17 00:00:00 2001 From: Trevor Buckner Date: Thu, 23 Jan 2025 00:54:07 -0500 Subject: [PATCH 123/398] Parse mustache "style" properties into object instead of string --- shared/naturalcrit/markdown.js | 37 +++++++++++++++++--------- tests/markdown/mustache-syntax.test.js | 4 +-- 2 files changed, 26 insertions(+), 15 deletions(-) diff --git a/shared/naturalcrit/markdown.js b/shared/naturalcrit/markdown.js index c2aa89fb5..99766b536 100644 --- a/shared/naturalcrit/markdown.js +++ b/shared/naturalcrit/markdown.js @@ -173,8 +173,8 @@ const mustacheSpans = { return ``${key}="${value}"`).join(' ')}` : ''}` + + `${tags.styles ? ` style="${Object.entries(tags.styles).map(([key, value])=>`${key}:${value};`).join(' ')}"` : ''}` + + `${tags.attributes ? ` ${Object.entries(tags.attributes).map(([key, value])=>`${key}="${value}"`).join(' ')}` : ''}` + `>${this.parser.parseInline(token.tokens)}`; // parseInline to turn child tokens into HTML } }; @@ -229,7 +229,7 @@ const mustacheDivs = { return ``${key}="${value}"`).join(' ')}` : ''}` + `>${this.parser.parse(token.tokens)}
`; // parse to turn child tokens into HTML } @@ -272,7 +272,7 @@ const mustacheInjectInline = { return `${openingTag[1]}` + `${tags.classes ? ` class="${tags.classes}"` : ''}` + `${tags.id ? ` id="${tags.id}"` : ''}` + - `${tags.styles ? ` style="${tags.styles}"` : ''}` + + `${!_.isEmpty(tags.styles) ? ` style="${Object.entries(tags.styles).map(([key, value])=>`${key}:${value};`).join(' ')}"` : ''}` + `${!_.isEmpty(tags.attributes) ? ` ${Object.entries(tags.attributes).map(([key, value])=>`${key}="${value}"`).join(' ')}` : ''}` + `${openingTag[2]}`; // parse to turn child tokens into HTML } @@ -316,7 +316,7 @@ const mustacheInjectBlock = { return `${openingTag[1]}` + `${tags.classes ? ` class="${tags.classes}"` : ''}` + `${tags.id ? ` id="${tags.id}"` : ''}` + - `${tags.styles ? ` style="${tags.styles}"` : ''}` + + `${!_.isEmpty(tags.styles) ? ` style="${Object.entries(tags.styles).map(([key, value])=>`${key}:${value};`).join(' ')}"` : ''}` + `${!_.isEmpty(tags.attributes) ? ` ${Object.entries(tags.attributes).map(([key, value])=>`${key}="${value}"`).join(' ')}` : ''}` + `${openingTag[2]}`; // parse to turn child tokens into HTML } @@ -861,15 +861,20 @@ const processStyleTags = (string)=>{ const index = attr.indexOf('='); let [key, value] = [attr.substring(0, index), attr.substring(index + 1)]; value = value.replace(/"/g, ''); - obj[key] = value; + obj[key.trim()] = value.trim(); return obj; }, {}) || null; - const styles = tags?.length ? tags.map((tag)=>tag.replace(/:"?([^"]*)"?/g, ':$1;').trim()).join(' ') : null; + const styles = tags?.length ? tags.reduce((styleObj, style) => { + const index = style.indexOf(':'); + const [key, value] = [style.substring(0, index), style.substring(index + 1)]; + styleObj[key.trim()] = value.replace(/"?([^"]*)"?/g, '$1').trim(); + return styleObj; + }, {}) : null; return { id : id, classes : classes, - styles : styles, + styles : _.isEmpty(styles) ? null : styles, attributes : _.isEmpty(attributes) ? null : attributes }; }; @@ -879,21 +884,27 @@ const extractHTMLStyleTags = (htmlString)=>{ const firstElementOnly = htmlString.split('>')[0]; const id = firstElementOnly.match(/id="([^"]*)"/)?.[1] || null; const classes = firstElementOnly.match(/class="([^"]*)"/)?.[1] || null; - const styles = firstElementOnly.match(/style="([^"]*)"/)?.[1] || null; + const styles = firstElementOnly.match(/style="([^"]*)"/)?.[1] + ?.split(';').reduce((styleObj, style) => { + if (style.trim() === '') return styleObj; + const index = style.indexOf(':'); + const [key, value] = [style.substring(0, index), style.substring(index + 1)]; + styleObj[key.trim()] = value.trim(); + return styleObj; + }, {}) || null; const attributes = firstElementOnly.match(/[a-zA-Z]+="[^"]*"/g) ?.filter((attr)=>!attr.startsWith('class="') && !attr.startsWith('style="') && !attr.startsWith('id="')) .reduce((obj, attr)=>{ const index = attr.indexOf('='); let [key, value] = [attr.substring(0, index), attr.substring(index + 1)]; - value = value.replace(/"/g, ''); - obj[key] = value; + obj[key.trim()] = value.replace(/"/g, ''); return obj; }, {}) || null; return { id : id, classes : classes, - styles : styles, + styles : _.isEmpty(styles) ? null : styles, attributes : _.isEmpty(attributes) ? null : attributes }; }; @@ -902,7 +913,7 @@ const mergeHTMLTags = (originalTags, newTags) => { return { id : newTags.id || originalTags.id || null, classes : [originalTags.classes, newTags.classes].join(' ').trim() || null, - styles : [originalTags.styles, newTags.styles].join(' ').trim() || null, + styles : Object.assign(originalTags.styles ?? {}, newTags.styles ?? {}), attributes : Object.assign(originalTags.attributes ?? {}, newTags.attributes ?? {}) }; }; diff --git a/tests/markdown/mustache-syntax.test.js b/tests/markdown/mustache-syntax.test.js index 261a5fd32..d17518411 100644 --- a/tests/markdown/mustache-syntax.test.js +++ b/tests/markdown/mustache-syntax.test.js @@ -300,7 +300,7 @@ describe('Injection: When an injection tag follows an element', ()=>{ it('Renders a span "text" with its own styles, appended with injected styles', function() { const source = '{{color:blue,height:10px text}}{width:10px,color:red}'; const rendered = Markdown.render(source); - expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('text'); + expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('text'); }); it('Renders a span "text" with its own classes, appended with injected classes', function() { @@ -429,7 +429,7 @@ describe('Injection: When an injection tag follows an element', ()=>{ }} {width:10px,color:red}`; const rendered = Markdown.render(source).trimReturns(); - expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('

text

'); + expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('

text

'); }); it('Renders a span "text" with its own classes, appended with injected classes', function() { From 5e03d97869d1da6049438d2f1c83dd59470d5bbb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Losada=20Hern=C3=A1ndez?= Date: Thu, 23 Jan 2025 13:56:07 +0100 Subject: [PATCH 124/398] revert react frame update --- package-lock.json | 9 +++++---- package.json | 2 +- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index 5e5b3a6b1..6cf876186 100644 --- a/package-lock.json +++ b/package-lock.json @@ -46,7 +46,7 @@ "nconf": "^0.12.1", "react": "^18.3.1", "react-dom": "^18.3.1", - "react-frame-component": "^5.2.7", + "react-frame-component": "^4.1.3", "react-router": "^7.1.3", "sanitize-filename": "1.6.3", "superagent": "^10.1.1", @@ -11636,9 +11636,10 @@ } }, "node_modules/react-frame-component": { - "version": "5.2.7", - "resolved": "https://registry.npmjs.org/react-frame-component/-/react-frame-component-5.2.7.tgz", - "integrity": "sha512-ROjHtSLoSVYUBfTieazj/nL8jIX9rZFmHC0yXEU+dx6Y82OcBEGgU9o7VyHMrBFUN9FuQ849MtIPNNLsb4krbg==", + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/react-frame-component/-/react-frame-component-4.1.3.tgz", + "integrity": "sha512-4PurhctiqnmC1F5prPZ+LdsalH7pZ3SFA5xoc0HBe8mSHctdLLt4Cr2WXfXOoajHBYq/yiipp9zOgx+vy8GiEA==", + "license": "MIT", "peerDependencies": { "prop-types": "^15.5.9", "react": ">= 16.3", diff --git a/package.json b/package.json index 09e9d4ef9..40f6aad81 100644 --- a/package.json +++ b/package.json @@ -121,7 +121,7 @@ "nconf": "^0.12.1", "react": "^18.3.1", "react-dom": "^18.3.1", - "react-frame-component": "^5.2.7", + "react-frame-component": "^4.1.3", "react-router": "^7.1.3", "sanitize-filename": "1.6.3", "superagent": "^10.1.1", From 0ac981586f0f2bb4a6713f7e8b69989aa52a0ff4 Mon Sep 17 00:00:00 2001 From: Trevor Buckner Date: Fri, 24 Jan 2025 01:16:22 -0500 Subject: [PATCH 125/398] Clean up --- client/homebrew/brewRenderer/brewRenderer.jsx | 35 ++++++++----------- shared/naturalcrit/markdown.js | 21 ++--------- 2 files changed, 16 insertions(+), 40 deletions(-) diff --git a/client/homebrew/brewRenderer/brewRenderer.jsx b/client/homebrew/brewRenderer/brewRenderer.jsx index 529605a40..a4774523f 100644 --- a/client/homebrew/brewRenderer/brewRenderer.jsx +++ b/client/homebrew/brewRenderer/brewRenderer.jsx @@ -77,22 +77,8 @@ const BrewPage = (props)=>{ centerObserver.disconnect(); }; }, []); - - // Extract any page styles from `\page{cssProp:value}` - if(cleanText.match(/^ { - const [key, value] = curr.split(':').map(item => item.trim()); - const camelCaseKey = key.replace(/-([a-z])/g, g => g[1].toUpperCase()); //Convert to camelCase for React - acc[camelCaseKey] = value; - return acc; - }, {}); - - props.style = {...props.style, ...styleObject}; - cleanText = cleanText.substring(cleanText.indexOf('\n')); - } - return
+ return
; }; @@ -187,25 +173,32 @@ const BrewRenderer = (props)=>{ const renderPage = (pageText, index)=>{ - const styles = { + let styles = { ...(!displayOptions.pageShadows ? { boxShadow: 'none' } : {}) // Add more conditions as needed }; + let attributes = {}; if(props.renderer == 'legacy') { const html = MarkdownLegacy.render(pageText); return ; } else { - let pageText2 = pageText.substring(0, pageText.indexOf('\n')); - let butt = Markdown.marked.lexer(pageText2); - console.log(butt) - + if(pageText.startsWith('\\page')) { + let firstLineTokens = Markdown.marked.lexer(pageText.split('\n', 1)[0])[0].tokens; + let injectedTags = firstLineTokens.find(obj => obj.injectedTags !== undefined)?.injectedTags; + if(injectedTags) { + styles = {...styles, ...injectedTags.styles}; + styles = _.mapKeys(styles, (v, k) => _.camelCase(k)); // Convert CSS to camelCase for React + 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/shared/naturalcrit/markdown.js b/shared/naturalcrit/markdown.js index c0feef234..ab19d06ba 100644 --- a/shared/naturalcrit/markdown.js +++ b/shared/naturalcrit/markdown.js @@ -527,21 +527,6 @@ const definitionListsMultiLine = { } }; -const pageBreak = { - name : 'pageBreak', - level : 'block', - start(src) { return src.match(/\n\\page/m)?.index; }, // Hint to Marked.js to stop and check for a match - tokenizer(src) { - const regex = /^\\page(?:$|(?={[^\n{}]+}$))/m; - const match = regex.exec(src); - if(match?.length) - return { type : 'pageBreak', raw : match[0] }; - }, - renderer(token) { - return `\n`; - } -}; - //v=====--------------------< Variable Handling >-------------------=====v// 242 lines const replaceVar = function(input, hoist=false, allowUnresolved=false) { const regex = /([!$]?)\[((?!\s*\])(?:\\.|[^\[\]\\])+)\]/g; @@ -810,7 +795,7 @@ const tableTerminators = [ ]; Marked.use(MarkedVariables()); -Marked.use({ extensions : [pageBreak, justifiedParagraphs, definitionListsMultiLine, definitionListsSingleLine, forcedParagraphBreaks, +Marked.use({ extensions : [justifiedParagraphs, definitionListsMultiLine, definitionListsSingleLine, forcedParagraphBreaks, nonbreakingSpaces, superSubScripts, mustacheSpans, mustacheDivs, mustacheInjectInline] }); Marked.use(mustacheInjectBlock); Marked.use({ renderer: renderer, tokenizer: tokenizer, mangle: false }); @@ -1017,9 +1002,7 @@ const Markdown = { }); return errors; - }, - - extractHTMLStyleTags : extractHTMLStyleTags + } }; export default Markdown; From 9f8831eed620fb28ee3b5cda22bffa032b76c192 Mon Sep 17 00:00:00 2001 From: Trevor Buckner Date: Fri, 24 Jan 2025 01:16:55 -0500 Subject: [PATCH 126/398] Adjust display and page count when first line has \page --- client/homebrew/editor/editor.jsx | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/client/homebrew/editor/editor.jsx b/client/homebrew/editor/editor.jsx index bba5f3ad9..3bda5f989 100644 --- a/client/homebrew/editor/editor.jsx +++ b/client/homebrew/editor/editor.jsx @@ -126,15 +126,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' ? /^(?=\\page(?:{[^\n{}]+})?$)/ : /\\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' ? /^(?=\\page(?:{[^\n{}]+})?$)/ : /\\page/; const currentPage = lines.reduce((count, line)=>count + (pageRegex.test(line) ? 1 : 0), 1); this.props.onViewPageChange(currentPage); }, @@ -174,7 +174,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 +190,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(/^(?=\\page(?:{[^\n{}]+})?$)/))) { + + if(lineNumber > 1) // 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 +202,6 @@ const Editor = createClass({ textContent : editorPageCount }); codeMirror.setBookmark({ line: lineNumber, ch: line.length }, pageCountElement); - - editorPageCount += 1; }; // New Codemirror styling for V3 renderer @@ -358,7 +359,7 @@ const Editor = createClass({ if(!this.isText() || isJumping) return; - const textSplit = this.props.renderer == 'V3' ? /^\\page$/gm : /\\page/; + const textSplit = this.props.renderer == 'V3' ? /^(?=\\page(?:{[^\n{}]+})?$)/gm : /\\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; From 7610466ee455a05cf11d1210e7828519796408f8 Mon Sep 17 00:00:00 2001 From: Trevor Buckner Date: Fri, 24 Jan 2025 01:48:18 -0500 Subject: [PATCH 127/398] Off by 1 error --- client/homebrew/editor/editor.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/homebrew/editor/editor.jsx b/client/homebrew/editor/editor.jsx index 3bda5f989..fc2813f38 100644 --- a/client/homebrew/editor/editor.jsx +++ b/client/homebrew/editor/editor.jsx @@ -192,7 +192,7 @@ const Editor = createClass({ if((this.props.renderer == 'legacy' && line.includes('\\page')) || (this.props.renderer == 'V3' && line.match(/^(?=\\page(?:{[^\n{}]+})?$)/))) { - if(lineNumber > 1) // Since \page is optional on first line of document, + 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' From 60b6dbb38809677939e1052165f669cf9aa751f5 Mon Sep 17 00:00:00 2001 From: David Bolack Date: Fri, 24 Jan 2025 13:52:49 -0600 Subject: [PATCH 128/398] Workaround for unclosed
 blocks before
 rendering.

Unsure if this is a fix you really need but it resolves the issue posted.
---
 shared/naturalcrit/markdown.js | 14 +++++++++++++-
 1 file changed, 13 insertions(+), 1 deletion(-)

diff --git a/shared/naturalcrit/markdown.js b/shared/naturalcrit/markdown.js
index 99766b536..74f29cebf 100644
--- a/shared/naturalcrit/markdown.js
+++ b/shared/naturalcrit/markdown.js
@@ -922,6 +922,18 @@ const globalVarsList    = {};
 let varsQueue       = [];
 let globalPageNumber = 0;
 
+const closePre = (text)=>{
+	const cols = text.split(/^\\column$/gm);
+	if((cols[0].match(/```/g)||[]).length % 2 != 0) {
+		// Catch inserted column pattern
+		if(cols[0].endsWith('\n\n \n')) {
+			cols[0] = cols[0].slice(0, cols[0].length-'\n\n \n'.length);
+			cols[0] += '\n```\n\n \n';
+		} else cols[0] += '\n```\n';
+	}
+	return cols.join(`\n\\column\n`);
+};
+
 const Markdown = {
 	marked : Marked,
 	render : (rawBrewText, pageNumber=0)=>{
@@ -932,7 +944,7 @@ const Markdown = {
 			MarkedGFMResetHeadingIDs();
 		}
 
-		rawBrewText = rawBrewText.replace(/^\\column$/gm, `\n
\n`); + rawBrewText = closePre(rawBrewText).replace(/^\\column$/gm, `\n
\n`); const opts = Marked.defaults; From abc830eda2210a64607ff338ecec376e1957ff73 Mon Sep 17 00:00:00 2001 From: David Bolack Date: Fri, 24 Jan 2025 14:09:13 -0600 Subject: [PATCH 129/398] Change backticks to `
` literals.

---
 client/homebrew/pages/errorPage/errors/errorIndex.js | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/client/homebrew/pages/errorPage/errors/errorIndex.js b/client/homebrew/pages/errorPage/errors/errorIndex.js
index f05f93838..caa5e662c 100644
--- a/client/homebrew/pages/errorPage/errors/errorIndex.js
+++ b/client/homebrew/pages/errorPage/errors/errorIndex.js
@@ -89,7 +89,7 @@ const errorIndex = (props)=>{
 		
 		:
 
-		**Brew Title:** \`${props.brew.brewTitle || 'Unable to show title'}\`
+		**Brew Title:** 
${props.brew.brewTitle || 'Unable to show title'}
**Current Authors:** ${props.brew.authors?.map((author)=>{return `[${author}](/user/${author})`;}).join(', ') || 'Unable to list authors'} @@ -104,7 +104,7 @@ const errorIndex = (props)=>{ : - **Brew Title:** \`${props.brew.brewTitle || 'Unable to show title'}\` + **Brew Title:**
${props.brew.brewTitle || 'Unable to show title'}
**Current Authors:** ${props.brew.authors?.map((author)=>{return `[${author}](/user/${author})`;}).join(', ') || 'Unable to list authors'} @@ -181,7 +181,7 @@ const errorIndex = (props)=>{ **Brew ID:** ${props.brew.brewId} - **Brew Title:** \`${props.brew.brewTitle}\``, + **Brew Title:**
${props.brew.brewTitle}
`, // ####### Admin page error ####### '52' : dedent` From 29d04fe57ddbbd4d031d9bc63bbf447f3b7c149e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 27 Jan 2025 03:42:09 +0000 Subject: [PATCH 130/398] Bump eslint from 9.18.0 to 9.19.0 Bumps [eslint](https://github.com/eslint/eslint) from 9.18.0 to 9.19.0. - [Release notes](https://github.com/eslint/eslint/releases) - [Changelog](https://github.com/eslint/eslint/blob/main/CHANGELOG.md) - [Commits](https://github.com/eslint/eslint/compare/v9.18.0...v9.19.0) --- updated-dependencies: - dependency-name: eslint dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- package-lock.json | 18 ++++++++++-------- package.json | 2 +- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/package-lock.json b/package-lock.json index 6cf876186..85f052f2b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -55,7 +55,7 @@ "devDependencies": { "@stylistic/stylelint-plugin": "^3.1.1", "babel-plugin-transform-import-meta": "^2.3.2", - "eslint": "^9.18.0", + "eslint": "^9.19.0", "eslint-plugin-jest": "^28.11.0", "eslint-plugin-react": "^7.37.4", "globals": "^15.14.0", @@ -1915,10 +1915,11 @@ } }, "node_modules/@eslint/js": { - "version": "9.18.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.18.0.tgz", - "integrity": "sha512-fK6L7rxcq6/z+AaQMtiFTkvbHkBLNlwyRxHpKawP0x3u9+NC6MQTnFW+AdpwC6gfHTW0051cokQgtTN2FqlxQA==", + "version": "9.19.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.19.0.tgz", + "integrity": "sha512-rbq9/g38qjfqFLOVPvwjIvFFdNziEC5S65jmjPw5r6A//QH+W91akh9irMwjDN8zKUTak6W9EsAv4m/7Wnw0UQ==", "dev": true, + "license": "MIT", "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } @@ -5650,17 +5651,18 @@ "license": "MIT" }, "node_modules/eslint": { - "version": "9.18.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.18.0.tgz", - "integrity": "sha512-+waTfRWQlSbpt3KWE+CjrPPYnbq9kfZIYUqapc0uBXyjTp8aYXZDsUH16m39Ryq3NjAVP4tjuF7KaukeqoCoaA==", + "version": "9.19.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.19.0.tgz", + "integrity": "sha512-ug92j0LepKlbbEv6hD911THhoRHmbdXt2gX+VDABAW/Ir7D3nqKdv5Pf5vtlyY6HQMTEP2skXY43ueqTCWssEA==", "dev": true, + "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.12.1", "@eslint/config-array": "^0.19.0", "@eslint/core": "^0.10.0", "@eslint/eslintrc": "^3.2.0", - "@eslint/js": "9.18.0", + "@eslint/js": "9.19.0", "@eslint/plugin-kit": "^0.2.5", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", diff --git a/package.json b/package.json index 40f6aad81..15c0efcea 100644 --- a/package.json +++ b/package.json @@ -130,7 +130,7 @@ "devDependencies": { "@stylistic/stylelint-plugin": "^3.1.1", "babel-plugin-transform-import-meta": "^2.3.2", - "eslint": "^9.18.0", + "eslint": "^9.19.0", "eslint-plugin-jest": "^28.11.0", "eslint-plugin-react": "^7.37.4", "globals": "^15.14.0", From fb20be833ce97e7d25a283f2f63e30721a4aac64 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 27 Jan 2025 16:32:07 +0000 Subject: [PATCH 131/398] Bump stylelint from 16.13.2 to 16.14.1 Bumps [stylelint](https://github.com/stylelint/stylelint) from 16.13.2 to 16.14.1. - [Release notes](https://github.com/stylelint/stylelint/releases) - [Changelog](https://github.com/stylelint/stylelint/blob/main/CHANGELOG.md) - [Commits](https://github.com/stylelint/stylelint/compare/16.13.2...16.14.1) --- updated-dependencies: - dependency-name: stylelint dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- package-lock.json | 27 ++++++++++++++------------- package.json | 2 +- 2 files changed, 15 insertions(+), 14 deletions(-) diff --git a/package-lock.json b/package-lock.json index 85f052f2b..7fee96257 100644 --- a/package-lock.json +++ b/package-lock.json @@ -63,7 +63,7 @@ "jest-expect-message": "^1.1.3", "jsdom-global": "^3.0.2", "postcss-less": "^6.0.0", - "stylelint": "^16.13.2", + "stylelint": "^16.14.1", "stylelint-config-recess-order": "^6.0.0", "stylelint-config-recommended": "^15.0.0", "supertest": "^7.0.0" @@ -11248,9 +11248,9 @@ } }, "node_modules/postcss": { - "version": "8.4.49", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.49.tgz", - "integrity": "sha512-OCVPnIObs4N29kxTjzLfUryOkvZEq+pf8jTF0lg8E7uETuWHA+v7j3c/xJmiqpX450191LlmZfUKkXxkTry7nA==", + "version": "8.5.1", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.1.tgz", + "integrity": "sha512-6oz2beyjc5VMn/KV1pPw8fliQkhBXrVn1Z3TVyqZxU8kZpzEKhBdmCFqI6ZbmGtamQvQGuU1sgPTk8ZrXDD7jQ==", "dev": true, "funding": [ { @@ -11268,7 +11268,7 @@ ], "license": "MIT", "dependencies": { - "nanoid": "^3.3.7", + "nanoid": "^3.3.8", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" }, @@ -11352,9 +11352,9 @@ "license": "MIT" }, "node_modules/postcss/node_modules/nanoid": { - "version": "3.3.7", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", - "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", + "version": "3.3.8", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.8.tgz", + "integrity": "sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==", "dev": true, "funding": [ { @@ -13040,9 +13040,9 @@ "license": "ISC" }, "node_modules/stylelint": { - "version": "16.13.2", - "resolved": "https://registry.npmjs.org/stylelint/-/stylelint-16.13.2.tgz", - "integrity": "sha512-wDlgh0mRO9RtSa3TdidqHd0nOG8MmUyVKl+dxA6C1j8aZRzpNeEgdhFmU5y4sZx4Fc6r46p0fI7p1vR5O2DZqA==", + "version": "16.14.1", + "resolved": "https://registry.npmjs.org/stylelint/-/stylelint-16.14.1.tgz", + "integrity": "sha512-oqCL7AC3786oTax35T/nuLL8p2C3k/8rHKAooezrPGRvUX0wX+qqs5kMWh5YYT4PHQgVDobHT4tw55WgpYG6Sw==", "dev": true, "funding": [ { @@ -13054,6 +13054,7 @@ "url": "https://github.com/sponsors/stylelint" } ], + "license": "MIT", "dependencies": { "@csstools/css-parser-algorithms": "^3.0.4", "@csstools/css-tokenizer": "^3.0.3", @@ -13073,7 +13074,7 @@ "globby": "^11.1.0", "globjoin": "^0.1.4", "html-tags": "^3.3.1", - "ignore": "^7.0.1", + "ignore": "^7.0.3", "imurmurhash": "^0.1.4", "is-plain-object": "^5.0.0", "known-css-properties": "^0.35.0", @@ -13082,7 +13083,7 @@ "micromatch": "^4.0.8", "normalize-path": "^3.0.0", "picocolors": "^1.1.1", - "postcss": "^8.4.49", + "postcss": "^8.5.1", "postcss-resolve-nested-selector": "^0.1.6", "postcss-safe-parser": "^7.0.1", "postcss-selector-parser": "^7.0.0", diff --git a/package.json b/package.json index 15c0efcea..c7781d69c 100644 --- a/package.json +++ b/package.json @@ -138,7 +138,7 @@ "jest-expect-message": "^1.1.3", "jsdom-global": "^3.0.2", "postcss-less": "^6.0.0", - "stylelint": "^16.13.2", + "stylelint": "^16.14.1", "stylelint-config-recess-order": "^6.0.0", "stylelint-config-recommended": "^15.0.0", "supertest": "^7.0.0" From 66fd9e188b7ca1d826304c505c68ca694392b216 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 27 Jan 2025 16:36:51 +0000 Subject: [PATCH 132/398] Bump @babel/core from 7.26.0 to 7.26.7 Bumps [@babel/core](https://github.com/babel/babel/tree/HEAD/packages/babel-core) from 7.26.0 to 7.26.7. - [Release notes](https://github.com/babel/babel/releases) - [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md) - [Commits](https://github.com/babel/babel/commits/v7.26.7/packages/babel-core) --- updated-dependencies: - dependency-name: "@babel/core" dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- package-lock.json | 97 ++++++++++++++++++++++++++--------------------- package.json | 2 +- 2 files changed, 54 insertions(+), 45 deletions(-) diff --git a/package-lock.json b/package-lock.json index 7fee96257..2bef0ba67 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,7 +10,7 @@ "hasInstallScript": true, "license": "MIT", "dependencies": { - "@babel/core": "^7.26.0", + "@babel/core": "^7.26.7", "@babel/plugin-transform-runtime": "^7.25.9", "@babel/preset-env": "^7.26.0", "@babel/preset-react": "^7.26.3", @@ -87,9 +87,10 @@ } }, "node_modules/@babel/code-frame": { - "version": "7.26.0", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.26.0.tgz", - "integrity": "sha512-INCKxTtbXtcNbUZ3YXutwMpEleqttcswhAdee7dhuoVrD2cnuc3PqtERBtxkX5nziX9vnBL8WXmSGwv8CuPV6g==", + "version": "7.26.2", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.26.2.tgz", + "integrity": "sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==", + "license": "MIT", "dependencies": { "@babel/helper-validator-identifier": "^7.25.9", "js-tokens": "^4.0.0", @@ -100,28 +101,30 @@ } }, "node_modules/@babel/compat-data": { - "version": "7.26.0", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.26.0.tgz", - "integrity": "sha512-qETICbZSLe7uXv9VE8T/RWOdIE5qqyTucOt4zLYMafj2MRO271VGgLd4RACJMeBO37UPWhXiKMBk7YlJ0fOzQA==", + "version": "7.26.5", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.26.5.tgz", + "integrity": "sha512-XvcZi1KWf88RVbF9wn8MN6tYFloU5qX8KjuF3E1PVBmJ9eypXfs4GRiJwLuTZL0iSnJUKn1BFPa5BPZZJyFzPg==", + "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/core": { - "version": "7.26.0", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.26.0.tgz", - "integrity": "sha512-i1SLeK+DzNnQ3LL/CswPCa/E5u4lh1k6IAEphON8F+cXt0t9euTshDru0q7/IqMa1PMPz5RnHuHscF8/ZJsStg==", + "version": "7.26.7", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.26.7.tgz", + "integrity": "sha512-SRijHmF0PSPgLIBYlWnG0hyeJLwXE2CgpsXaMOrtt2yp9/86ALw6oUlj9KYuZ0JN07T4eBMVIW4li/9S1j2BGA==", + "license": "MIT", "dependencies": { "@ampproject/remapping": "^2.2.0", - "@babel/code-frame": "^7.26.0", - "@babel/generator": "^7.26.0", - "@babel/helper-compilation-targets": "^7.25.9", + "@babel/code-frame": "^7.26.2", + "@babel/generator": "^7.26.5", + "@babel/helper-compilation-targets": "^7.26.5", "@babel/helper-module-transforms": "^7.26.0", - "@babel/helpers": "^7.26.0", - "@babel/parser": "^7.26.0", + "@babel/helpers": "^7.26.7", + "@babel/parser": "^7.26.7", "@babel/template": "^7.25.9", - "@babel/traverse": "^7.25.9", - "@babel/types": "^7.26.0", + "@babel/traverse": "^7.26.7", + "@babel/types": "^7.26.7", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", @@ -137,12 +140,13 @@ } }, "node_modules/@babel/generator": { - "version": "7.26.0", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.26.0.tgz", - "integrity": "sha512-/AIkAmInnWwgEAJGQr9vY0c66Mj6kjkE2ZPB1PurTRaRAh3U+J45sAQMjQDJdh4WbR3l0x5xkimXBKyBXXAu2w==", + "version": "7.26.5", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.26.5.tgz", + "integrity": "sha512-2caSP6fN9I7HOe6nqhtft7V4g7/V/gfDsC3Ag4W7kEzzvRGKqiv0pu0HogPiZ3KaVSoNDhUws6IJjDjpfmYIXw==", + "license": "MIT", "dependencies": { - "@babel/parser": "^7.26.0", - "@babel/types": "^7.26.0", + "@babel/parser": "^7.26.5", + "@babel/types": "^7.26.5", "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.25", "jsesc": "^3.0.2" @@ -175,11 +179,12 @@ } }, "node_modules/@babel/helper-compilation-targets": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.25.9.tgz", - "integrity": "sha512-j9Db8Suy6yV/VHa4qzrj9yZfZxhLWQdVnRlXxmKLYlhWUVB1sB2G5sxuWYXk/whHD9iW76PmNzxZ4UCnTQTVEQ==", + "version": "7.26.5", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.26.5.tgz", + "integrity": "sha512-IXuyn5EkouFJscIDuFF5EsiSolseme1s0CZB+QxVugqJLYmKdxI1VfIBOst0SUu4rnk2Z7kqTwmoO1lp3HIfnA==", + "license": "MIT", "dependencies": { - "@babel/compat-data": "^7.25.9", + "@babel/compat-data": "^7.26.5", "@babel/helper-validator-option": "^7.25.9", "browserslist": "^4.24.0", "lru-cache": "^5.1.1", @@ -394,23 +399,25 @@ } }, "node_modules/@babel/helpers": { - "version": "7.26.0", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.26.0.tgz", - "integrity": "sha512-tbhNuIxNcVb21pInl3ZSjksLCvgdZy9KwJ8brv993QtIVKJBBkYXz4q4ZbAv31GdnC+R90np23L5FbEBlthAEw==", + "version": "7.26.7", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.26.7.tgz", + "integrity": "sha512-8NHiL98vsi0mbPQmYAGWwfcFaOy4j2HY49fXJCfuDcdE7fMIsH9a7GdaeXpIBsbT7307WU8KCMp5pUVDNL4f9A==", + "license": "MIT", "dependencies": { "@babel/template": "^7.25.9", - "@babel/types": "^7.26.0" + "@babel/types": "^7.26.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/parser": { - "version": "7.26.1", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.26.1.tgz", - "integrity": "sha512-reoQYNiAJreZNsJzyrDNzFQ+IQ5JFiIzAHJg9bn94S3l+4++J7RsIhNMoB+lgP/9tpmiAQqspv+xfdxTSzREOw==", + "version": "7.26.7", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.26.7.tgz", + "integrity": "sha512-kEvgGGgEjRUutvdVvZhbn/BxVt+5VSpwXz1j3WYXQbXDo8KzFOPNG2GQbdAiNq8g6wn1yKk7C/qrke03a84V+w==", + "license": "MIT", "dependencies": { - "@babel/types": "^7.26.0" + "@babel/types": "^7.26.7" }, "bin": { "parser": "bin/babel-parser.js" @@ -1707,15 +1714,16 @@ } }, "node_modules/@babel/traverse": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.25.9.tgz", - "integrity": "sha512-ZCuvfwOwlz/bawvAuvcj8rrithP2/N55Tzz342AkTvq4qaWbGfmCk/tKhNaV2cthijKrPAA8SRJV5WWe7IBMJw==", + "version": "7.26.7", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.26.7.tgz", + "integrity": "sha512-1x1sgeyRLC3r5fQOM0/xtQKsYjyxmFjaOrLJNtZ81inNjyJHGIolTULPiSc/2qe1/qfpFLisLQYFnnZl7QoedA==", + "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.25.9", - "@babel/generator": "^7.25.9", - "@babel/parser": "^7.25.9", + "@babel/code-frame": "^7.26.2", + "@babel/generator": "^7.26.5", + "@babel/parser": "^7.26.7", "@babel/template": "^7.25.9", - "@babel/types": "^7.25.9", + "@babel/types": "^7.26.7", "debug": "^4.3.1", "globals": "^11.1.0" }, @@ -1733,9 +1741,10 @@ } }, "node_modules/@babel/types": { - "version": "7.26.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.26.0.tgz", - "integrity": "sha512-Z/yiTPj+lDVnF7lWeKCIJzaIkI0vYO87dMpZ4bg4TDrFe4XXLFWL1TbXU27gBP3QccxV9mZICCrnjnYlJjXHOA==", + "version": "7.26.7", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.26.7.tgz", + "integrity": "sha512-t8kDRGrKXyp6+tjUh7hw2RLyclsW4TRoRvRHtSyAX9Bb5ldlFh+90YAYY6awRXrlB4G5G2izNeGySpATlFzmOg==", + "license": "MIT", "dependencies": { "@babel/helper-string-parser": "^7.25.9", "@babel/helper-validator-identifier": "^7.25.9" diff --git a/package.json b/package.json index c7781d69c..c27922422 100644 --- a/package.json +++ b/package.json @@ -85,7 +85,7 @@ ] }, "dependencies": { - "@babel/core": "^7.26.0", + "@babel/core": "^7.26.7", "@babel/plugin-transform-runtime": "^7.25.9", "@babel/preset-env": "^7.26.0", "@babel/preset-react": "^7.26.3", From 1576a946b017c749633d7f819899a6257d004467 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 27 Jan 2025 18:09:34 +0000 Subject: [PATCH 133/398] Bump @babel/preset-env from 7.26.0 to 7.26.7 Bumps [@babel/preset-env](https://github.com/babel/babel/tree/HEAD/packages/babel-preset-env) from 7.26.0 to 7.26.7. - [Release notes](https://github.com/babel/babel/releases) - [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md) - [Commits](https://github.com/babel/babel/commits/v7.26.7/packages/babel-preset-env) --- updated-dependencies: - dependency-name: "@babel/preset-env" dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- package-lock.json | 103 +++++++++++++++++++--------------------------- package.json | 2 +- 2 files changed, 43 insertions(+), 62 deletions(-) diff --git a/package-lock.json b/package-lock.json index 2bef0ba67..281c24b1f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,7 +12,7 @@ "dependencies": { "@babel/core": "^7.26.7", "@babel/plugin-transform-runtime": "^7.25.9", - "@babel/preset-env": "^7.26.0", + "@babel/preset-env": "^7.26.7", "@babel/preset-react": "^7.26.3", "@googleapis/drive": "^8.14.0", "body-parser": "^1.20.2", @@ -166,18 +166,6 @@ "node": ">=6.9.0" } }, - "node_modules/@babel/helper-builder-binary-assignment-operator-visitor": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.25.9.tgz", - "integrity": "sha512-C47lC7LIDCnz0h4vai/tpNOI95tCd5ZT3iBt/DBH5lXKHZsyNQv18yf1wIIg2ntiQNgmAvA+DgZ82iW8Qdym8g==", - "dependencies": { - "@babel/traverse": "^7.25.9", - "@babel/types": "^7.25.9" - }, - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/@babel/helper-compilation-targets": { "version": "7.26.5", "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.26.5.tgz", @@ -298,9 +286,10 @@ } }, "node_modules/@babel/helper-plugin-utils": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.25.9.tgz", - "integrity": "sha512-kSMlyUVdWe25rEsRGviIgOWnoT/nfABVWlqt9N19/dIPWViAOW2s9wznP5tURbs/IDuNk4gPy3YdYRgH3uxhBw==", + "version": "7.26.5", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.26.5.tgz", + "integrity": "sha512-RS+jZcRdZdRFzMyr+wcsaqOmld1/EqTghfaBGQQd/WnRdzdlvSZ//kF7U8VQTxf1ynZ4cjUcYgjVGx13ewNPMg==", + "license": "MIT", "engines": { "node": ">=6.9.0" } @@ -337,18 +326,6 @@ "@babel/core": "^7.0.0" } }, - "node_modules/@babel/helper-simple-access": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.25.9.tgz", - "integrity": "sha512-c6WHXuiaRsJTyHYLJV75t9IqsmTbItYfdj99PnzYGQZkYKvan5/2jKJ7gu31J3/BJ/A18grImSPModuyG/Eo0Q==", - "dependencies": { - "@babel/traverse": "^7.25.9", - "@babel/types": "^7.25.9" - }, - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/@babel/helper-skip-transparent-expression-wrappers": { "version": "7.25.9", "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.25.9.tgz", @@ -793,11 +770,12 @@ } }, "node_modules/@babel/plugin-transform-block-scoped-functions": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.25.9.tgz", - "integrity": "sha512-toHc9fzab0ZfenFpsyYinOX0J/5dgJVA2fm64xPewu7CoYHWEivIWKxkK2rMi4r3yQqLnVmheMXRdG+k239CgA==", + "version": "7.26.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.26.5.tgz", + "integrity": "sha512-chuTSY+hq09+/f5lMj8ZSYgCFpppV2CbYrhNFJ1BFoXpiWPnnAb7R0MqrafCpN8E1+YRrtM1MXZHJdIx8B6rMQ==", + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-plugin-utils": "^7.26.5" }, "engines": { "node": ">=6.9.0" @@ -965,11 +943,11 @@ } }, "node_modules/@babel/plugin-transform-exponentiation-operator": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.25.9.tgz", - "integrity": "sha512-KRhdhlVk2nObA5AYa7QMgTMTVJdfHprfpAk4DjZVtllqRg9qarilstTKEhpVjyt+Npi8ThRyiV8176Am3CodPA==", + "version": "7.26.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.26.3.tgz", + "integrity": "sha512-7CAHcQ58z2chuXPWblnn1K6rLDnDWieghSOEmqQsrBenH0P9InCUtOJYD89pvngljmZlJcz3fcmgYsXFNGa1ZQ==", + "license": "MIT", "dependencies": { - "@babel/helper-builder-binary-assignment-operator-visitor": "^7.25.9", "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { @@ -1096,13 +1074,13 @@ } }, "node_modules/@babel/plugin-transform-modules-commonjs": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.25.9.tgz", - "integrity": "sha512-dwh2Ol1jWwL2MgkCzUSOvfmKElqQcuswAZypBSUsScMXvgdT8Ekq5YA6TtqpTVWH+4903NmboMuH1o9i8Rxlyg==", + "version": "7.26.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.26.3.tgz", + "integrity": "sha512-MgR55l4q9KddUDITEzEFYn5ZsGDXMSsU9E+kh7fjRXTIC3RHqfCo8RPRbyReYJh44HQ/yomFkqbOFohXvDCiIQ==", + "license": "MIT", "dependencies": { - "@babel/helper-module-transforms": "^7.25.9", - "@babel/helper-plugin-utils": "^7.25.9", - "@babel/helper-simple-access": "^7.25.9" + "@babel/helper-module-transforms": "^7.26.0", + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1173,11 +1151,12 @@ } }, "node_modules/@babel/plugin-transform-nullish-coalescing-operator": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.25.9.tgz", - "integrity": "sha512-ENfftpLZw5EItALAD4WsY/KUWvhUlZndm5GC7G3evUsVeSJB6p0pBeLQUnRnBCBx7zV0RKQjR9kCuwrsIrjWog==", + "version": "7.26.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.26.6.tgz", + "integrity": "sha512-CKW8Vu+uUZneQCPtXmSBUC6NCAUdya26hWCElAWh5mVSlSRsmiCPUUDKb3Z0szng1hiAJa098Hkhg9o4SE35Qw==", + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-plugin-utils": "^7.26.5" }, "engines": { "node": ">=6.9.0" @@ -1501,11 +1480,12 @@ } }, "node_modules/@babel/plugin-transform-typeof-symbol": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.25.9.tgz", - "integrity": "sha512-v61XqUMiueJROUv66BVIOi0Fv/CUuZuZMl5NkRoCVxLAnMexZ0A3kMe7vvZ0nulxMuMp0Mk6S5hNh48yki08ZA==", + "version": "7.26.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.26.7.tgz", + "integrity": "sha512-jfoTXXZTgGg36BmhqT3cAYK5qkmqvJpvNrPhaK/52Vgjhw4Rq29s9UqpWWV0D6yuRmgiFH/BUVlkl96zJWqnaw==", + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-plugin-utils": "^7.26.5" }, "engines": { "node": ">=6.9.0" @@ -1574,13 +1554,14 @@ } }, "node_modules/@babel/preset-env": { - "version": "7.26.0", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.26.0.tgz", - "integrity": "sha512-H84Fxq0CQJNdPFT2DrfnylZ3cf5K43rGfWK4LJGPpjKHiZlk0/RzwEus3PDDZZg+/Er7lCA03MVacueUuXdzfw==", + "version": "7.26.7", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.26.7.tgz", + "integrity": "sha512-Ycg2tnXwixaXOVb29rana8HNPgLVBof8qqtNQ9LE22IoyZboQbGSxI6ZySMdW3K5nAe6gu35IaJefUJflhUFTQ==", + "license": "MIT", "dependencies": { - "@babel/compat-data": "^7.26.0", - "@babel/helper-compilation-targets": "^7.25.9", - "@babel/helper-plugin-utils": "^7.25.9", + "@babel/compat-data": "^7.26.5", + "@babel/helper-compilation-targets": "^7.26.5", + "@babel/helper-plugin-utils": "^7.26.5", "@babel/helper-validator-option": "^7.25.9", "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.25.9", "@babel/plugin-bugfix-safari-class-field-initializer-scope": "^7.25.9", @@ -1594,7 +1575,7 @@ "@babel/plugin-transform-arrow-functions": "^7.25.9", "@babel/plugin-transform-async-generator-functions": "^7.25.9", "@babel/plugin-transform-async-to-generator": "^7.25.9", - "@babel/plugin-transform-block-scoped-functions": "^7.25.9", + "@babel/plugin-transform-block-scoped-functions": "^7.26.5", "@babel/plugin-transform-block-scoping": "^7.25.9", "@babel/plugin-transform-class-properties": "^7.25.9", "@babel/plugin-transform-class-static-block": "^7.26.0", @@ -1605,7 +1586,7 @@ "@babel/plugin-transform-duplicate-keys": "^7.25.9", "@babel/plugin-transform-duplicate-named-capturing-groups-regex": "^7.25.9", "@babel/plugin-transform-dynamic-import": "^7.25.9", - "@babel/plugin-transform-exponentiation-operator": "^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-function-name": "^7.25.9", @@ -1614,12 +1595,12 @@ "@babel/plugin-transform-logical-assignment-operators": "^7.25.9", "@babel/plugin-transform-member-expression-literals": "^7.25.9", "@babel/plugin-transform-modules-amd": "^7.25.9", - "@babel/plugin-transform-modules-commonjs": "^7.25.9", + "@babel/plugin-transform-modules-commonjs": "^7.26.3", "@babel/plugin-transform-modules-systemjs": "^7.25.9", "@babel/plugin-transform-modules-umd": "^7.25.9", "@babel/plugin-transform-named-capturing-groups-regex": "^7.25.9", "@babel/plugin-transform-new-target": "^7.25.9", - "@babel/plugin-transform-nullish-coalescing-operator": "^7.25.9", + "@babel/plugin-transform-nullish-coalescing-operator": "^7.26.6", "@babel/plugin-transform-numeric-separator": "^7.25.9", "@babel/plugin-transform-object-rest-spread": "^7.25.9", "@babel/plugin-transform-object-super": "^7.25.9", @@ -1636,7 +1617,7 @@ "@babel/plugin-transform-spread": "^7.25.9", "@babel/plugin-transform-sticky-regex": "^7.25.9", "@babel/plugin-transform-template-literals": "^7.25.9", - "@babel/plugin-transform-typeof-symbol": "^7.25.9", + "@babel/plugin-transform-typeof-symbol": "^7.26.7", "@babel/plugin-transform-unicode-escapes": "^7.25.9", "@babel/plugin-transform-unicode-property-regex": "^7.25.9", "@babel/plugin-transform-unicode-regex": "^7.25.9", diff --git a/package.json b/package.json index c27922422..840975977 100644 --- a/package.json +++ b/package.json @@ -87,7 +87,7 @@ "dependencies": { "@babel/core": "^7.26.7", "@babel/plugin-transform-runtime": "^7.25.9", - "@babel/preset-env": "^7.26.0", + "@babel/preset-env": "^7.26.7", "@babel/preset-react": "^7.26.3", "@googleapis/drive": "^8.14.0", "body-parser": "^1.20.2", From 36df121cf66b530d30beb6266ed897115b4fe350 Mon Sep 17 00:00:00 2001 From: Trevor Buckner Date: Mon, 27 Jan 2025 23:10:37 -0500 Subject: [PATCH 134/398] Lint --- client/homebrew/brewRenderer/brewRenderer.jsx | 12 ++++++------ client/homebrew/editor/editor.jsx | 2 +- shared/naturalcrit/markdown.js | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/client/homebrew/brewRenderer/brewRenderer.jsx b/client/homebrew/brewRenderer/brewRenderer.jsx index a4774523f..a11710433 100644 --- a/client/homebrew/brewRenderer/brewRenderer.jsx +++ b/client/homebrew/brewRenderer/brewRenderer.jsx @@ -40,7 +40,7 @@ const BrewPage = (props)=>{ ...props }; const pageRef = useRef(null); - let cleanText = safeHTML(props.contents); + const cleanText = safeHTML(props.contents); useEffect(()=>{ if(!pageRef.current) return; @@ -77,7 +77,7 @@ const BrewPage = (props)=>{ centerObserver.disconnect(); }; }, []); - + return
; @@ -185,11 +185,11 @@ const BrewRenderer = (props)=>{ return ; } else { if(pageText.startsWith('\\page')) { - let firstLineTokens = Markdown.marked.lexer(pageText.split('\n', 1)[0])[0].tokens; - let injectedTags = firstLineTokens.find(obj => obj.injectedTags !== undefined)?.injectedTags; + 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) => _.camelCase(k)); // Convert CSS to camelCase for React + styles = { ...styles, ...injectedTags.styles }; + styles = _.mapKeys(styles, (v, k)=>_.camelCase(k)); // Convert CSS to camelCase for React attributes = injectedTags.attributes; } pageText = pageText.includes('\n') ? pageText.substring(pageText.indexOf('\n') + 1) : ''; // Remove the \page line diff --git a/client/homebrew/editor/editor.jsx b/client/homebrew/editor/editor.jsx index fc2813f38..f56b18618 100644 --- a/client/homebrew/editor/editor.jsx +++ b/client/homebrew/editor/editor.jsx @@ -193,7 +193,7 @@ const Editor = createClass({ (this.props.renderer == 'V3' && line.match(/^(?=\\page(?:{[^\n{}]+})?$)/))) { 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 + 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'); diff --git a/shared/naturalcrit/markdown.js b/shared/naturalcrit/markdown.js index ab19d06ba..99766b536 100644 --- a/shared/naturalcrit/markdown.js +++ b/shared/naturalcrit/markdown.js @@ -1002,7 +1002,7 @@ const Markdown = { }); return errors; - } + }, }; export default Markdown; From f1ff032e1e42041c53743255c9140d1346a99f12 Mon Sep 17 00:00:00 2001 From: Trevor Buckner Date: Mon, 27 Jan 2025 23:24:25 -0500 Subject: [PATCH 135/398] Extract repeated pagebreak regex into a constant --- client/homebrew/editor/editor.jsx | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/client/homebrew/editor/editor.jsx b/client/homebrew/editor/editor.jsx index f56b18618..9a88efca5 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! */ @@ -21,6 +22,8 @@ const DEFAULT_STYLE_TEXT = dedent` color: black; }`; + + let isJumping = false; const Editor = createClass({ @@ -127,14 +130,14 @@ const Editor = createClass({ updateCurrentCursorPage : function(cursor) { const lines = this.props.brew.text.split('\n').slice(1, cursor.line + 1); - const pageRegex = this.props.brew.renderer == 'V3' ? /^(?=\\page(?:{[^\n{}]+})?$)/ : /\\page/; + 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(1, topScrollLine + 1); - const pageRegex = this.props.brew.renderer == 'V3' ? /^(?=\\page(?:{[^\n{}]+})?$)/ : /\\page/; + 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); }, @@ -190,7 +193,7 @@ const Editor = createClass({ // Styling for \page breaks if((this.props.renderer == 'legacy' && line.includes('\\page')) || - (this.props.renderer == 'V3' && line.match(/^(?=\\page(?:{[^\n{}]+})?$)/))) { + (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 @@ -359,7 +362,7 @@ const Editor = createClass({ if(!this.isText() || isJumping) return; - const textSplit = this.props.renderer == 'V3' ? /^(?=\\page(?:{[^\n{}]+})?$)/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; From be18843b092003cbf729b888d2a5a6f910f8daf9 Mon Sep 17 00:00:00 2001 From: Trevor Buckner Date: Mon, 27 Jan 2025 23:27:03 -0500 Subject: [PATCH 136/398] Allow empty braces: \page{} --- client/homebrew/brewRenderer/brewRenderer.jsx | 2 +- client/homebrew/editor/editor.jsx | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/client/homebrew/brewRenderer/brewRenderer.jsx b/client/homebrew/brewRenderer/brewRenderer.jsx index a11710433..7210a65d0 100644 --- a/client/homebrew/brewRenderer/brewRenderer.jsx +++ b/client/homebrew/brewRenderer/brewRenderer.jsx @@ -126,7 +126,7 @@ const BrewRenderer = (props)=>{ if(props.renderer == 'legacy') { rawPages = props.text.split('\\page'); } else { - rawPages = props.text.split(/^(?=\\page(?:{[^\n{}]+})?$)/gm); + rawPages = props.text.split(/^(?=\\page(?:{[^\n{}]*})?$)/gm); } const handlePageVisibilityChange = (pageNum, isVisible, isCenter)=>{ diff --git a/client/homebrew/editor/editor.jsx b/client/homebrew/editor/editor.jsx index 9a88efca5..20cb8968c 100644 --- a/client/homebrew/editor/editor.jsx +++ b/client/homebrew/editor/editor.jsx @@ -12,7 +12,7 @@ const MetadataEditor = require('./metadataEditor/metadataEditor.jsx'); const EDITOR_THEME_KEY = 'HOMEBREWERY-EDITOR-THEME'; -const PAGEBREAK_REGEX_V3 = /^(?=\\page(?:{[^\n{}]+})?$)/m; +const PAGEBREAK_REGEX_V3 = /^(?=\\page(?:{[^\n{}]*})?$)/m; const SNIPPETBAR_HEIGHT = 25; const DEFAULT_STYLE_TEXT = dedent` /*=======--- Example CSS styling ---=======*/ @@ -22,8 +22,6 @@ const DEFAULT_STYLE_TEXT = dedent` color: black; }`; - - let isJumping = false; const Editor = createClass({ From d69288076af8f86e2f877b5f02d09be79e25ba48 Mon Sep 17 00:00:00 2001 From: Trevor Buckner Date: Mon, 27 Jan 2025 23:34:50 -0500 Subject: [PATCH 137/398] Change to _.escape() to escape HTML characters --- client/homebrew/pages/errorPage/errors/errorIndex.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/client/homebrew/pages/errorPage/errors/errorIndex.js b/client/homebrew/pages/errorPage/errors/errorIndex.js index caa5e662c..1353cf889 100644 --- a/client/homebrew/pages/errorPage/errors/errorIndex.js +++ b/client/homebrew/pages/errorPage/errors/errorIndex.js @@ -1,4 +1,5 @@ const dedent = require('dedent-tabs').default; +import _ from 'lodash'; const loginUrl = 'https://www.naturalcrit.com/login'; @@ -89,7 +90,7 @@ const errorIndex = (props)=>{ : - **Brew Title:**
${props.brew.brewTitle || 'Unable to show title'}
+ **Brew Title:** ${_.escape(props.brew.brewTitle) || 'Unable to show title'} **Current Authors:** ${props.brew.authors?.map((author)=>{return `[${author}](/user/${author})`;}).join(', ') || 'Unable to list authors'} @@ -104,7 +105,7 @@ const errorIndex = (props)=>{ : - **Brew Title:**
${props.brew.brewTitle || 'Unable to show title'}
+ **Brew Title:** ${_.escape(props.brew.brewTitle) || 'Unable to show title'} **Current Authors:** ${props.brew.authors?.map((author)=>{return `[${author}](/user/${author})`;}).join(', ') || 'Unable to list authors'} @@ -181,7 +182,7 @@ const errorIndex = (props)=>{ **Brew ID:** ${props.brew.brewId} - **Brew Title:**
${props.brew.brewTitle}
`, + **Brew Title:** ${_.escape(props.brew.brewTitle)}`, // ####### Admin page error ####### '52' : dedent` From 73c2be147cb56e18b515abaeb61c52e9a15551f3 Mon Sep 17 00:00:00 2001 From: Trevor Buckner Date: Tue, 28 Jan 2025 00:13:51 -0500 Subject: [PATCH 138/398] Custom escape function --- client/homebrew/pages/errorPage/errors/errorIndex.js | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/client/homebrew/pages/errorPage/errors/errorIndex.js b/client/homebrew/pages/errorPage/errors/errorIndex.js index 1353cf889..5c21b719c 100644 --- a/client/homebrew/pages/errorPage/errors/errorIndex.js +++ b/client/homebrew/pages/errorPage/errors/errorIndex.js @@ -7,6 +7,10 @@ const loginUrl = 'https://www.naturalcrit.com/login'; //050-100 : Other pages errors const errorIndex = (props)=>{ + const escape = (text) => { + return text.split('').map(char => `\\${char}`).join(''); + }; + return { // Default catch all '00' : dedent` @@ -90,7 +94,7 @@ const errorIndex = (props)=>{ : - **Brew Title:** ${_.escape(props.brew.brewTitle) || 'Unable to show title'} + **Brew Title:** ${escape(props.brew.brewTitle) || 'Unable to show title'} **Current Authors:** ${props.brew.authors?.map((author)=>{return `[${author}](/user/${author})`;}).join(', ') || 'Unable to list authors'} @@ -105,7 +109,7 @@ const errorIndex = (props)=>{ : - **Brew Title:** ${_.escape(props.brew.brewTitle) || 'Unable to show title'} + **Brew Title:** ${escape(props.brew.brewTitle) || 'Unable to show title'} **Current Authors:** ${props.brew.authors?.map((author)=>{return `[${author}](/user/${author})`;}).join(', ') || 'Unable to list authors'} @@ -182,7 +186,7 @@ const errorIndex = (props)=>{ **Brew ID:** ${props.brew.brewId} - **Brew Title:** ${_.escape(props.brew.brewTitle)}`, + **Brew Title:** ${escape(props.brew.brewTitle)}`, // ####### Admin page error ####### '52' : dedent` From ecd8869097a8c81260f572f24ae278185b3ddda9 Mon Sep 17 00:00:00 2001 From: Trevor Buckner Date: Tue, 28 Jan 2025 00:17:08 -0500 Subject: [PATCH 139/398] Add a comment --- client/homebrew/pages/errorPage/errors/errorIndex.js | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/client/homebrew/pages/errorPage/errors/errorIndex.js b/client/homebrew/pages/errorPage/errors/errorIndex.js index 5c21b719c..fe8e505e5 100644 --- a/client/homebrew/pages/errorPage/errors/errorIndex.js +++ b/client/homebrew/pages/errorPage/errors/errorIndex.js @@ -3,14 +3,15 @@ import _ from 'lodash'; 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}`).join(''); +}; + //001-050 : Brew errors //050-100 : Other pages errors const errorIndex = (props)=>{ - const escape = (text) => { - return text.split('').map(char => `\\${char}`).join(''); - }; - return { // Default catch all '00' : dedent` From 6a31d612e632e95d3ccfdf410f9e8186a5af1fb5 Mon Sep 17 00:00:00 2001 From: Trevor Buckner Date: Tue, 28 Jan 2025 00:24:15 -0500 Subject: [PATCH 140/398] Escape to HTML entities --- client/homebrew/pages/errorPage/errors/errorIndex.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/homebrew/pages/errorPage/errors/errorIndex.js b/client/homebrew/pages/errorPage/errors/errorIndex.js index fe8e505e5..63cb2619f 100644 --- a/client/homebrew/pages/errorPage/errors/errorIndex.js +++ b/client/homebrew/pages/errorPage/errors/errorIndex.js @@ -5,7 +5,7 @@ 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}`).join(''); + return text.split('').map(char => `&#${char.charCodeAt(0)};`).join(''); }; //001-050 : Brew errors From 3e78b037850390b3e94a06d9021c6c1417ea7f11 Mon Sep 17 00:00:00 2001 From: Trevor Buckner Date: Tue, 28 Jan 2025 00:28:46 -0500 Subject: [PATCH 141/398] Remove lodash again --- client/homebrew/pages/errorPage/errors/errorIndex.js | 1 - 1 file changed, 1 deletion(-) diff --git a/client/homebrew/pages/errorPage/errors/errorIndex.js b/client/homebrew/pages/errorPage/errors/errorIndex.js index 63cb2619f..f7614a37a 100644 --- a/client/homebrew/pages/errorPage/errors/errorIndex.js +++ b/client/homebrew/pages/errorPage/errors/errorIndex.js @@ -1,5 +1,4 @@ const dedent = require('dedent-tabs').default; -import _ from 'lodash'; const loginUrl = 'https://www.naturalcrit.com/login'; From 004729b2a4f0ad27711a1c60a9ba415c4ad47141 Mon Sep 17 00:00:00 2001 From: David Bolack Date: Tue, 28 Jan 2025 19:37:02 -0600 Subject: [PATCH 142/398] Fix editor regression. --- client/homebrew/editor/editor.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/homebrew/editor/editor.jsx b/client/homebrew/editor/editor.jsx index 46fcf46c7..2d349252a 100644 --- a/client/homebrew/editor/editor.jsx +++ b/client/homebrew/editor/editor.jsx @@ -181,7 +181,7 @@ const Editor = createClass({ let userSnippetCount = 1; // start snippet count from page 2 const whichSource = this.state.view === 'text' ? this.props.brew.text : this.props.brew.snippets; - _.forEach(whichSource.split('\n'), (line, lineNumber)=>{ + _.forEach(whichSource?.split('\n'), (line, lineNumber)=>{ //reset custom line styles codeMirror.removeLineClass(lineNumber, 'background', 'pageLine'); From f1eb6e1ce473bd1a6cacbbbce0bac9bb55875dda Mon Sep 17 00:00:00 2001 From: David Bolack Date: Tue, 28 Jan 2025 21:31:43 -0600 Subject: [PATCH 143/398] Alter varCallInline content to alig with preceeding varDefBlock in inline definitions. This was failing due to both labels having the extraneous spaces cleaned up but the variable label portion of the varCallInline did not, preventing them from being matched during variable resolution. --- shared/naturalcrit/markdown.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shared/naturalcrit/markdown.js b/shared/naturalcrit/markdown.js index 99766b536..1914cd201 100644 --- a/shared/naturalcrit/markdown.js +++ b/shared/naturalcrit/markdown.js @@ -735,7 +735,7 @@ function MarkedVariables() { varsQueue.push( { type : 'varCallInline', varName : label, - content : match[9] + content : match[9].replace(/\s+/g, ' ').replace(/\[\s+/, '[').replace(/\s+\]/, ']') }); } if(match[12]) { // Inline Call From 6dfd44e2f12e3daa5e94c91c25e3f9f4457095f1 Mon Sep 17 00:00:00 2001 From: Trevor Buckner Date: Wed, 29 Jan 2025 11:48:18 -0500 Subject: [PATCH 144/398] Allow spaces between `\page` and `{}` Consistent behavior with other curly injections --- client/homebrew/brewRenderer/brewRenderer.jsx | 5 ++--- client/homebrew/editor/editor.jsx | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/client/homebrew/brewRenderer/brewRenderer.jsx b/client/homebrew/brewRenderer/brewRenderer.jsx index 7210a65d0..fd88af403 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` @@ -126,7 +125,7 @@ const BrewRenderer = (props)=>{ if(props.renderer == 'legacy') { rawPages = props.text.split('\\page'); } else { - rawPages = props.text.split(/^(?=\\page(?:{[^\n{}]*})?$)/gm); + rawPages = props.text.split(PAGEBREAK_REGEX_V3); } const handlePageVisibilityChange = (pageNum, isVisible, isCenter)=>{ diff --git a/client/homebrew/editor/editor.jsx b/client/homebrew/editor/editor.jsx index 20cb8968c..2d0a26268 100644 --- a/client/homebrew/editor/editor.jsx +++ b/client/homebrew/editor/editor.jsx @@ -12,7 +12,7 @@ const MetadataEditor = require('./metadataEditor/metadataEditor.jsx'); const EDITOR_THEME_KEY = 'HOMEBREWERY-EDITOR-THEME'; -const PAGEBREAK_REGEX_V3 = /^(?=\\page(?:{[^\n{}]*})?$)/m; +const PAGEBREAK_REGEX_V3 = /^(?=\\page(?: *{[^\n{}]*})?$)/m; const SNIPPETBAR_HEIGHT = 25; const DEFAULT_STYLE_TEXT = dedent` /*=======--- Example CSS styling ---=======*/ From d0a06b5cf755472841c039a56659087d77ef82a7 Mon Sep 17 00:00:00 2001 From: Trevor Buckner Date: Wed, 29 Jan 2025 12:00:36 -0500 Subject: [PATCH 145/398] Fix class injection --- client/homebrew/brewRenderer/brewRenderer.jsx | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/client/homebrew/brewRenderer/brewRenderer.jsx b/client/homebrew/brewRenderer/brewRenderer.jsx index fd88af403..e15cec3bb 100644 --- a/client/homebrew/brewRenderer/brewRenderer.jsx +++ b/client/homebrew/brewRenderer/brewRenderer.jsx @@ -176,6 +176,7 @@ const BrewRenderer = (props)=>{ ...(!displayOptions.pageShadows ? { boxShadow: 'none' } : {}) // Add more conditions as needed }; + let classes = 'page'; let attributes = {}; if(props.renderer == 'legacy') { @@ -187,8 +188,9 @@ const BrewRenderer = (props)=>{ 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)=>_.camelCase(k)); // Convert CSS to camelCase for React + styles = { ...styles, ...injectedTags.styles }; + styles = _.mapKeys(styles, (v, 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 @@ -197,7 +199,7 @@ const BrewRenderer = (props)=>{ 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 ; } }; From 7f4a304f04bc0323bd00bbb6630ec24d5e865cdf Mon Sep 17 00:00:00 2001 From: Trevor Buckner Date: Wed, 29 Jan 2025 12:10:50 -0500 Subject: [PATCH 146/398] Fix custom CSS variables --- client/homebrew/brewRenderer/brewRenderer.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/homebrew/brewRenderer/brewRenderer.jsx b/client/homebrew/brewRenderer/brewRenderer.jsx index e15cec3bb..a82ea8b34 100644 --- a/client/homebrew/brewRenderer/brewRenderer.jsx +++ b/client/homebrew/brewRenderer/brewRenderer.jsx @@ -189,7 +189,7 @@ const BrewRenderer = (props)=>{ const injectedTags = firstLineTokens.find((obj)=>obj.injectedTags !== undefined)?.injectedTags; if(injectedTags) { styles = { ...styles, ...injectedTags.styles }; - styles = _.mapKeys(styles, (v, k)=>_.camelCase(k)); // Convert CSS to camelCase for React + 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; } From d8d403ffb8887a27124e736dfae19005a77cd6bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Losada=20Hern=C3=A1ndez?= Date: Thu, 30 Jan 2025 18:54:27 +0100 Subject: [PATCH 147/398] Update to v3.17.0 --- changelog.md | 45 ++++++++++++++++++++++++++++++++++ package-lock.json | 61 ++--------------------------------------------- package.json | 2 +- 3 files changed, 48 insertions(+), 60 deletions(-) diff --git a/changelog.md b/changelog.md index 3736ba9b0..723b5f1b2 100644 --- a/changelog.md +++ b/changelog.md @@ -85,6 +85,51 @@ pre { ## 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 + +- Update FAQ +- Fix styling for Vault buttons and checkboxes +- Improve navigation bar styling +- Add author renaming backend functions +- Fix malformed URI error when generating Reddit links +- Refactor User Page's Brew item component +- Refactor Share Page +- Refactor `dialog` notifications (with calculuschild and G-Ambatte) + +##### dbolack + +- Fix page shadows toolbar option - fixes issue [#3919](https://github.com/naturalcrit/homebrewery/issues/3919) +- Add Markdown for non-breaking spaces (` :>>> `) +- Update Docker install instructions - fixes issue [#1930](https://github.com/naturalcrit/homebrewery/issues/1930) +- Fix incorrect state update call - fixes issue [#3974](https://github.com/naturalcrit/homebrewery/issues/3974) +- Allow CSS inject directly in page by doing: `/page{}` - fixes issue [#3901](https://github.com/naturalcrit/homebrewery/issues/3901) With calculuschild +- Update Ubuntu install instructions - fixes issue [#1952](https://github.com/naturalcrit/homebrewery/issues/1952) +- Add align paragraph markdown (`:-: text`) + +##### G-Ambatte + +- Correct obsolete tag data - fixes issue [#3927](https://github.com/naturalcrit/homebrewery/issues/3927) +- Stop admin user being added as an author when updating brews via admin tools - fixes issue [#3952](https://github.com/naturalcrit/homebrewery/issues/3952) +- Add steps to refresh Google token to error page - fixes issue [#3955](https://github.com/naturalcrit/homebrewery/issues/3955) +- Add navigation by header/ID menu + +##### calculuschild + +- Fetch Google brews using user auth instead of service account - fixes issue [#2954](https://github.com/naturalcrit/homebrewery/issues/2954) +- Fix content negotiation middleware and tests - fixes issue [#3904](https://github.com/naturalcrit/homebrewery/issues/3904) +- Add Emojis testing +- Fix `toWellFormed() is not a function` for Win 7 users +- Add `content-visibility` property to decrease reflow time on large brews + +##### Gazook89 + +- Use Intersection Observers to detect on-screen pages - fixes issue [#3824](https://github.com/naturalcrit/homebrewery/issues/3824) + +}} + ### Wednesday 11/27/2024 - v3.16.1 {{taskList diff --git a/package-lock.json b/package-lock.json index 281c24b1f..1697ccc35 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": { @@ -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", @@ -6337,13 +6327,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 +6500,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", @@ -10365,13 +10334,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", @@ -14429,25 +14391,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..854f0c2f7 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", From d733b1f8f83b3bc43819ddef90872ae58314d8bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Losada=20Hern=C3=A1ndez?= Date: Thu, 30 Jan 2025 20:02:34 +0100 Subject: [PATCH 148/398] reformat changelog --- changelog.md | 90 +++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 65 insertions(+), 25 deletions(-) diff --git a/changelog.md b/changelog.md index 723b5f1b2..c6e712105 100644 --- a/changelog.md +++ b/changelog.md @@ -90,43 +90,83 @@ For a full record of development, visit our [Github Page](https://github.com/nat {{tasklist ##### 5e-Cleric -- Update FAQ -- Fix styling for Vault buttons and checkboxes -- Improve navigation bar styling -- Add author renaming backend functions -- Fix malformed URI error when generating Reddit links -- Refactor User Page's Brew item component -- Refactor Share Page -- Refactor `dialog` notifications (with calculuschild and G-Ambatte) +* [x] Update FAQ + +* [x] Fix styling for Vault buttons and checkboxes + +* [x] Improve navigation bar styling + +* [x] Add author renaming backend functions + +* [x] Fix malformed URI error when generating Reddit links + +* [x] Refactor User Page's Brew item component + +* [x] Refactor Share Page + +* [x] Refactor `dialog` notifications (with calculuschild and G-Ambatte) ##### dbolack -- Fix page shadows toolbar option - fixes issue [#3919](https://github.com/naturalcrit/homebrewery/issues/3919) -- Add Markdown for non-breaking spaces (` :>>> `) -- Update Docker install instructions - fixes issue [#1930](https://github.com/naturalcrit/homebrewery/issues/1930) -- Fix incorrect state update call - fixes issue [#3974](https://github.com/naturalcrit/homebrewery/issues/3974) -- Allow CSS inject directly in page by doing: `/page{}` - fixes issue [#3901](https://github.com/naturalcrit/homebrewery/issues/3901) With calculuschild -- Update Ubuntu install instructions - fixes issue [#1952](https://github.com/naturalcrit/homebrewery/issues/1952) -- Add align paragraph markdown (`:-: text`) +* [x] Fix page shadows toolbar option + +Fixes issue [#3919](https://github.com/naturalcrit/homebrewery/issues/3919) + +* [x] Add Markdown for non-breaking spaces (` :>>> `) + +* [x] Update Docker install instructions + +Fixes issue [#1930](https://github.com/naturalcrit/homebrewery/issues/1930) + +* [x] Fix incorrect state update call + +Fixes issue [#3974](https://github.com/naturalcrit/homebrewery/issues/3974) + +* [x] Allow CSS inject directly in page by doing: `/page{}` + +Fixes issue [#3901](https://github.com/naturalcrit/homebrewery/issues/3901) With calculuschild + +* [x] Update Ubuntu install instructions + +Fixes issue [#1952](https://github.com/naturalcrit/homebrewery/issues/1952) + +* [x] Add align paragraph markdown (`:-: text`) ##### G-Ambatte -- Correct obsolete tag data - fixes issue [#3927](https://github.com/naturalcrit/homebrewery/issues/3927) -- Stop admin user being added as an author when updating brews via admin tools - fixes issue [#3952](https://github.com/naturalcrit/homebrewery/issues/3952) -- Add steps to refresh Google token to error page - fixes issue [#3955](https://github.com/naturalcrit/homebrewery/issues/3955) -- Add navigation by header/ID menu +* [x] Correct obsolete tag data + +Fixes issue [#3927](https://github.com/naturalcrit/homebrewery/issues/3927) + +* [x] Stop admin user being added as an author when updating brews via admin tools + +Fixes issue [#3952](https://github.com/naturalcrit/homebrewery/issues/3952) + +* [x] Add steps to refresh Google token to error page + +Fixes issue [#3955](https://github.com/naturalcrit/homebrewery/issues/3955) + +* [x] Add navigation by header/ID menu ##### calculuschild -- Fetch Google brews using user auth instead of service account - fixes issue [#2954](https://github.com/naturalcrit/homebrewery/issues/2954) -- Fix content negotiation middleware and tests - fixes issue [#3904](https://github.com/naturalcrit/homebrewery/issues/3904) -- Add Emojis testing -- Fix `toWellFormed() is not a function` for Win 7 users -- Add `content-visibility` property to decrease reflow time on large brews +* [x] Fetch Google brews using user auth instead of service account + +Fixes issue [#2954](https://github.com/naturalcrit/homebrewery/issues/2954) + +* [x] Fix content negotiation middleware and tests + +Fixes issue [#3904](https://github.com/naturalcrit/homebrewery/issues/3904) + +* [x] Add Emojis testing + +* [x] Fix `toWellFormed() is not a function` for Win 7 users + +* [x] Add `content-visibility` property to decrease reflow time on large brews ##### Gazook89 -- Use Intersection Observers to detect on-screen pages - fixes issue [#3824](https://github.com/naturalcrit/homebrewery/issues/3824) +* [x] Use Intersection Observers to detect on-screen pages - fixes issue [#3824](https://github.com/naturalcrit/homebrewery/issues/3824) }} From f005cb784f2c57119f03f462fde3b7101af8b59b Mon Sep 17 00:00:00 2001 From: Trevor Buckner Date: Thu, 30 Jan 2025 14:18:26 -0500 Subject: [PATCH 149/398] Update changelog.md --- changelog.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/changelog.md b/changelog.md index c6e712105..89cb73e41 100644 --- a/changelog.md +++ b/changelog.md @@ -166,7 +166,9 @@ Fixes issue [#3904](https://github.com/naturalcrit/homebrewery/issues/3904) ##### Gazook89 -* [x] Use Intersection Observers to detect on-screen pages - fixes issue [#3824](https://github.com/naturalcrit/homebrewery/issues/3824) +* [x] Use Intersection Observers to detect on-screen pages + +Fixes issue [#3824](https://github.com/naturalcrit/homebrewery/issues/3824) }} From e4df577a322a5ed47c13f2f5dae13f292a37c7b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Losada=20Hern=C3=A1ndez?= Date: Thu, 30 Jan 2025 23:33:49 +0100 Subject: [PATCH 150/398] remove internal changes --- changelog.md | 34 ++++++---------------------------- 1 file changed, 6 insertions(+), 28 deletions(-) diff --git a/changelog.md b/changelog.md index c6e712105..facf8d647 100644 --- a/changelog.md +++ b/changelog.md @@ -96,16 +96,10 @@ For a full record of development, visit our [Github Page](https://github.com/nat * [x] Improve navigation bar styling -* [x] Add author renaming backend functions +* [x] Add author renaming feature * [x] Fix malformed URI error when generating Reddit links -* [x] Refactor User Page's Brew item component - -* [x] Refactor Share Page - -* [x] Refactor `dialog` notifications (with calculuschild and G-Ambatte) - ##### dbolack * [x] Fix page shadows toolbar option @@ -118,13 +112,9 @@ Fixes issue [#3919](https://github.com/naturalcrit/homebrewery/issues/3919) Fixes issue [#1930](https://github.com/naturalcrit/homebrewery/issues/1930) -* [x] Fix incorrect state update call +* [x] Allow CSS inject directly in page by doing: `/page{}` (With calculuschild) -Fixes issue [#3974](https://github.com/naturalcrit/homebrewery/issues/3974) - -* [x] Allow CSS inject directly in page by doing: `/page{}` - -Fixes issue [#3901](https://github.com/naturalcrit/homebrewery/issues/3901) With calculuschild +Fixes issue [#3901](https://github.com/naturalcrit/homebrewery/issues/3901) * [x] Update Ubuntu install instructions @@ -134,15 +124,11 @@ Fixes issue [#1952](https://github.com/naturalcrit/homebrewery/issues/1952) ##### G-Ambatte -* [x] Correct obsolete tag data +* [x] Fix crash when opening brew Properties tab Fixes issue [#3927](https://github.com/naturalcrit/homebrewery/issues/3927) -* [x] Stop admin user being added as an author when updating brews via admin tools - -Fixes issue [#3952](https://github.com/naturalcrit/homebrewery/issues/3952) - -* [x] Add steps to refresh Google token to error page +* [x] Show credentials error when oportune Fixes issue [#3955](https://github.com/naturalcrit/homebrewery/issues/3955) @@ -150,15 +136,7 @@ Fixes issue [#3955](https://github.com/naturalcrit/homebrewery/issues/3955) ##### calculuschild -* [x] Fetch Google brews using user auth instead of service account - -Fixes issue [#2954](https://github.com/naturalcrit/homebrewery/issues/2954) - -* [x] Fix content negotiation middleware and tests - -Fixes issue [#3904](https://github.com/naturalcrit/homebrewery/issues/3904) - -* [x] Add Emojis testing +* [x] Add CMM and emojis tests * [x] Fix `toWellFormed() is not a function` for Win 7 users From 37d56f736537147f79c797ab2d7aa5f9ae1614c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Losada=20Hern=C3=A1ndez?= Date: Thu, 30 Jan 2025 23:35:42 +0100 Subject: [PATCH 151/398] compile removed items --- changelog.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/changelog.md b/changelog.md index 521ef39a4..926d213ef 100644 --- a/changelog.md +++ b/changelog.md @@ -148,6 +148,10 @@ Fixes issue [#3955](https://github.com/naturalcrit/homebrewery/issues/3955) Fixes issue [#3824](https://github.com/naturalcrit/homebrewery/issues/3824) + +##### All +* [x] Update dependencies and scripts +* [x] Refactor components and fix various errors }} ### Wednesday 11/27/2024 - v3.16.1 From 8848c06b15cb4d3d7a80b5867308ee35a3ae1b78 Mon Sep 17 00:00:00 2001 From: Trevor Buckner Date: Thu, 30 Jan 2025 22:37:55 -0500 Subject: [PATCH 152/398] Rewording. Add more detailed examples. Add Table width syntax --- changelog.md | 55 +++++++++++++++++++++++++++++++++++----------------- 1 file changed, 37 insertions(+), 18 deletions(-) diff --git a/changelog.md b/changelog.md index 926d213ef..8cfb499f6 100644 --- a/changelog.md +++ b/changelog.md @@ -77,17 +77,20 @@ 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 +{{taskList ##### 5e-Cleric * [x] Update FAQ @@ -96,9 +99,9 @@ For a full record of development, visit our [Github Page](https://github.com/nat * [x] Improve navigation bar styling -* [x] Add author renaming feature +* [x] Add feature to change username at https://www.naturalcrit.com/account -* [x] Fix malformed URI error when generating Reddit links +* [x] Fix Reddit link crash when title has non-latin chars ##### dbolack @@ -106,13 +109,13 @@ For a full record of development, visit our [Github Page](https://github.com/nat Fixes issue [#3919](https://github.com/naturalcrit/homebrewery/issues/3919) -* [x] Add Markdown for non-breaking spaces (` :>>> `) +* [x] Add `:>>>` syntax for horizontal :>>>>> spaces * [x] Update Docker install instructions Fixes issue [#1930](https://github.com/naturalcrit/homebrewery/issues/1930) -* [x] Allow CSS inject directly in page by doing: `/page{}` (With calculuschild) +* [x] Allow styling pages via `\page{myStyles}` (with calculuschild) Fixes issue [#3901](https://github.com/naturalcrit/homebrewery/issues/3901) @@ -120,7 +123,24 @@ Fixes issue [#3901](https://github.com/naturalcrit/homebrewery/issues/3901) Fixes issue [#1952](https://github.com/naturalcrit/homebrewery/issues/1952) -* [x] Add align paragraph markdown (`:-: text`) +* [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 @@ -128,32 +148,29 @@ Fixes issue [#1952](https://github.com/naturalcrit/homebrewery/issues/1952) Fixes issue [#3927](https://github.com/naturalcrit/homebrewery/issues/3927) -* [x] Show credentials error when oportune +* [x] Update error pages with steps to refresh credentials Fixes issue [#3955](https://github.com/naturalcrit/homebrewery/issues/3955) -* [x] Add navigation by header/ID menu +* [x] Add {{openSans :fas_rectangle_list: **NAVIGATION**}} menu to the viewer toolbar ##### calculuschild -* [x] Add CMM and emojis tests - -* [x] Fix `toWellFormed() is not a function` for Win 7 users - -* [x] Add `content-visibility` property to decrease reflow time on large brews +* [x] Reduce display lag on large brews ##### Gazook89 -* [x] Use Intersection Observers to detect on-screen pages +* [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 @@ -200,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 @@ -2122,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 From 23944f4fe05e0a133fb99d4260db7bae2d4bbd6f Mon Sep 17 00:00:00 2001 From: Trevor Buckner Date: Fri, 31 Jan 2025 00:03:44 -0500 Subject: [PATCH 153/398] smartypants package updated to support higher Marked versions Next Marked versions break things; need to update incrementally --- package-lock.json | 18 +++++++++--------- package.json | 4 ++-- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/package-lock.json b/package-lock.json index 1697ccc35..0889af57e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -34,11 +34,11 @@ "jwt-simple": "^0.5.6", "less": "^3.13.1", "lodash": "^4.17.21", - "marked": "11.2.0", + "marked": "12.0.0", "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-smartypants-lite": "^1.0.3", "markedLegacy": "npm:marked@^0.3.19", "moment": "^2.30.1", "mongoose": "^8.9.5", @@ -9788,9 +9788,9 @@ } }, "node_modules/marked": { - "version": "11.2.0", - "resolved": "https://registry.npmjs.org/marked/-/marked-11.2.0.tgz", - "integrity": "sha512-HR0m3bvu0jAPYiIvLUUQtdg1g6D247//lvcekpHO1WMvbwDlwSkZAX9Lw4F4YHE1T0HaaNve0tuAWuV1UJ6vtw==", + "version": "12.0.0", + "resolved": "https://registry.npmjs.org/marked/-/marked-12.0.0.tgz", + "integrity": "sha512-Vkwtq9rLqXryZnWaQc86+FHLC6tr/fycMfYAhiOIXkrNmeGAyhSxjqu0Rs1i0bBqw5u0S7+lV9fdH2ZSVaoa0w==", "license": "MIT", "bin": { "marked": "bin/marked.js" @@ -9828,12 +9828,12 @@ } }, "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": { diff --git a/package.json b/package.json index 854f0c2f7..3ad7ac233 100644 --- a/package.json +++ b/package.json @@ -109,11 +109,11 @@ "jwt-simple": "^0.5.6", "less": "^3.13.1", "lodash": "^4.17.21", - "marked": "11.2.0", + "marked": "12.0.0", "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-smartypants-lite": "^1.0.3", "markedLegacy": "npm:marked@^0.3.19", "moment": "^2.30.1", "mongoose": "^8.9.5", From 4e0b6d634dbc70dce49177c30419c4154df0d16a Mon Sep 17 00:00:00 2001 From: Trevor Buckner Date: Fri, 31 Jan 2025 00:12:13 -0500 Subject: [PATCH 154/398] Marked 12.0.1 --- package-lock.json | 8 ++++---- package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index 0889af57e..79d4a210a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -34,7 +34,7 @@ "jwt-simple": "^0.5.6", "less": "^3.13.1", "lodash": "^4.17.21", - "marked": "12.0.0", + "marked": "12.0.1", "marked-emoji": "^1.4.3", "marked-extended-tables": "^1.1.0", "marked-gfm-heading-id": "^3.2.0", @@ -9788,9 +9788,9 @@ } }, "node_modules/marked": { - "version": "12.0.0", - "resolved": "https://registry.npmjs.org/marked/-/marked-12.0.0.tgz", - "integrity": "sha512-Vkwtq9rLqXryZnWaQc86+FHLC6tr/fycMfYAhiOIXkrNmeGAyhSxjqu0Rs1i0bBqw5u0S7+lV9fdH2ZSVaoa0w==", + "version": "12.0.1", + "resolved": "https://registry.npmjs.org/marked/-/marked-12.0.1.tgz", + "integrity": "sha512-Y1/V2yafOcOdWQCX0XpAKXzDakPOpn6U0YLxTJs3cww6VxOzZV1BTOOYWLvH3gX38cq+iLwljHHTnMtlDfg01Q==", "license": "MIT", "bin": { "marked": "bin/marked.js" diff --git a/package.json b/package.json index 3ad7ac233..985435ff6 100644 --- a/package.json +++ b/package.json @@ -109,7 +109,7 @@ "jwt-simple": "^0.5.6", "less": "^3.13.1", "lodash": "^4.17.21", - "marked": "12.0.0", + "marked": "12.0.1", "marked-emoji": "^1.4.3", "marked-extended-tables": "^1.1.0", "marked-gfm-heading-id": "^3.2.0", From b1e99f1385ec8bc4efa744e61405a761953e1e06 Mon Sep 17 00:00:00 2001 From: Trevor Buckner Date: Fri, 31 Jan 2025 00:16:37 -0500 Subject: [PATCH 155/398] Marked 12.0.2 --- package-lock.json | 8 ++++---- package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index 79d4a210a..8142ef89d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -34,7 +34,7 @@ "jwt-simple": "^0.5.6", "less": "^3.13.1", "lodash": "^4.17.21", - "marked": "12.0.1", + "marked": "12.0.2", "marked-emoji": "^1.4.3", "marked-extended-tables": "^1.1.0", "marked-gfm-heading-id": "^3.2.0", @@ -9788,9 +9788,9 @@ } }, "node_modules/marked": { - "version": "12.0.1", - "resolved": "https://registry.npmjs.org/marked/-/marked-12.0.1.tgz", - "integrity": "sha512-Y1/V2yafOcOdWQCX0XpAKXzDakPOpn6U0YLxTJs3cww6VxOzZV1BTOOYWLvH3gX38cq+iLwljHHTnMtlDfg01Q==", + "version": "12.0.2", + "resolved": "https://registry.npmjs.org/marked/-/marked-12.0.2.tgz", + "integrity": "sha512-qXUm7e/YKFoqFPYPa3Ukg9xlI5cyAtGmyEIzMfW//m6kXwCy2Ps9DYf5ioijFKQ8qyuscrHoY04iJGctu2Kg0Q==", "license": "MIT", "bin": { "marked": "bin/marked.js" diff --git a/package.json b/package.json index 985435ff6..fe77b3e17 100644 --- a/package.json +++ b/package.json @@ -109,7 +109,7 @@ "jwt-simple": "^0.5.6", "less": "^3.13.1", "lodash": "^4.17.21", - "marked": "12.0.1", + "marked": "12.0.2", "marked-emoji": "^1.4.3", "marked-extended-tables": "^1.1.0", "marked-gfm-heading-id": "^3.2.0", From e87acc3f0f66b8bce7c228b9cf07ae3def719528 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 31 Jan 2025 05:17:57 +0000 Subject: [PATCH 156/398] Bump dompurify from 3.2.3 to 3.2.4 Bumps [dompurify](https://github.com/cure53/DOMPurify) from 3.2.3 to 3.2.4. - [Release notes](https://github.com/cure53/DOMPurify/releases) - [Commits](https://github.com/cure53/DOMPurify/compare/3.2.3...3.2.4) --- updated-dependencies: - dependency-name: dompurify dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- package-lock.json | 9 +++++---- package.json | 2 +- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index 8142ef89d..af0d9e14d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -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", @@ -5313,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" } diff --git a/package.json b/package.json index fe77b3e17..2ef557033 100644 --- a/package.json +++ b/package.json @@ -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", From 7e826cd4f5629e517af0cd1c44ebd7b5c482ef7e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 31 Jan 2025 05:22:30 +0000 Subject: [PATCH 157/398] Bump react-router from 7.1.3 to 7.1.4 Bumps [react-router](https://github.com/remix-run/react-router/tree/HEAD/packages/react-router) from 7.1.3 to 7.1.4. - [Release notes](https://github.com/remix-run/react-router/releases) - [Changelog](https://github.com/remix-run/react-router/blob/main/packages/react-router/CHANGELOG.md) - [Commits](https://github.com/remix-run/react-router/commits/react-router@7.1.4/packages/react-router) --- updated-dependencies: - dependency-name: react-router dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- package-lock.json | 9 +++++---- package.json | 2 +- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index af0d9e14d..3e0e541ff 100644 --- a/package-lock.json +++ b/package-lock.json @@ -47,7 +47,7 @@ "react": "^18.3.1", "react-dom": "^18.3.1", "react-frame-component": "^4.1.3", - "react-router": "^7.1.3", + "react-router": "^7.1.4", "sanitize-filename": "1.6.3", "superagent": "^10.1.1", "vitreum": "git+https://git@github.com/calculuschild/vitreum.git" @@ -11609,9 +11609,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.4", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-7.1.4.tgz", + "integrity": "sha512-aJWVrKoLI0nIK1lfbTU3d5al1ZEUiwtSus/xjYL8K5sv2hyPesiOIojHM7QnaNLVtroOB1McZsWk37fMQVoc6A==", + "license": "MIT", "dependencies": { "@types/cookie": "^0.6.0", "cookie": "^1.0.1", diff --git a/package.json b/package.json index 2ef557033..0598cdbd8 100644 --- a/package.json +++ b/package.json @@ -122,7 +122,7 @@ "react": "^18.3.1", "react-dom": "^18.3.1", "react-frame-component": "^4.1.3", - "react-router": "^7.1.3", + "react-router": "^7.1.4", "sanitize-filename": "1.6.3", "superagent": "^10.1.1", "vitreum": "git+https://git@github.com/calculuschild/vitreum.git" From b6b23a787cba68ec0b99a081c6842210e557156f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Losada=20Hern=C3=A1ndez?= Date: Fri, 31 Jan 2025 11:52:46 +0100 Subject: [PATCH 158/398] upadte notification popup to handle markdown --- .../notificationPopup/notificationPopup.jsx | 5 ++- .../notificationPopup/notificationPopup.less | 40 ++++++++++++++++--- 2 files changed, 38 insertions(+), 7 deletions(-) diff --git a/client/homebrew/brewRenderer/notificationPopup/notificationPopup.jsx b/client/homebrew/brewRenderer/notificationPopup/notificationPopup.jsx index b2045f13d..49ac57994 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,11 @@ const NotificationPopup = ()=>{ const renderNotificationsList = ()=>{ if(error) return
{error}
; - + notifications.map((notification) =>console.log(Markdown.render(notification.text, 1))); return notifications.map((notification)=>(
  • {notification.title}
    -

    +

  • )); }; diff --git a/client/homebrew/brewRenderer/notificationPopup/notificationPopup.less b/client/homebrew/brewRenderer/notificationPopup/notificationPopup.less index 79edf37b2..61f79e501 100644 --- a/client/homebrew/brewRenderer/notificationPopup/notificationPopup.less +++ b/client/homebrew/brewRenderer/notificationPopup/notificationPopup.less @@ -8,6 +8,7 @@ } .notificationPopup { + font-size:17px; position : relative; width : 100%; padding : 15px; @@ -48,17 +49,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; + margin-top : 1.2em; + font-size : 0.9em; + line-height : 1.2em; + padding-left: 1em; em { text-transform:capitalize; font-weight : 800; } + li { list-style-type: square;} + } + ul ul,ol ol,ul ol,ol ul { + margin-bottom : 0px; + margin-left : 1.5em; } } -} + + /*Markdown styling*/ + code { + background:#08115a; + padding: 0.1em 0.5em; + border-radius:2px; + font-family : 'Courier New', "Courier", monospace; + overflow-wrap : break-word; + white-space : pre-wrap; + } + pre code { + display : inline-block; + width : 100%; + } + .blank { + height : 1em; + margin-top : 0; + & + * { margin-top : 0; } + } + + + + +} \ No newline at end of file From 057abcda0d85d1e8821ea1c13c39f14bdfee3152 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Losada=20Hern=C3=A1ndez?= Date: Fri, 31 Jan 2025 12:04:40 +0100 Subject: [PATCH 159/398] reduce style between li elements --- .../notificationPopup/notificationPopup.less | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/client/homebrew/brewRenderer/notificationPopup/notificationPopup.less b/client/homebrew/brewRenderer/notificationPopup/notificationPopup.less index 61f79e501..4f5a0a2de 100644 --- a/client/homebrew/brewRenderer/notificationPopup/notificationPopup.less +++ b/client/homebrew/brewRenderer/notificationPopup/notificationPopup.less @@ -8,7 +8,6 @@ } .notificationPopup { - font-size:17px; position : relative; width : 100%; padding : 15px; @@ -53,15 +52,14 @@ list-style-position : outside; list-style-type : disc; li { - margin-top : 1.2em; font-size : 0.9em; - line-height : 1.2em; + line-height : 1.5em; padding-left: 1em; em { text-transform:capitalize; font-weight : 800; } - li { list-style-type: square;} + li { list-style-type: square; line-height : 1.2em;} } ul ul,ol ol,ul ol,ol ul { margin-bottom : 0px; @@ -79,12 +77,12 @@ white-space : pre-wrap; } pre code { - display : inline-block; - width : 100%; + display : inline-block; + width : 100%; } .blank { - height : 1em; - margin-top : 0; + height : 1em; + margin-top : 0; & + * { margin-top : 0; } } From 6269651c8dc0b8e25f25c9b139e9ebbd66c815d1 Mon Sep 17 00:00:00 2001 From: Trevor Buckner Date: Fri, 31 Jan 2025 12:42:54 -0500 Subject: [PATCH 160/398] Update Marked to v13.0.3 --- package-lock.json | 18 +++++++++--------- package.json | 4 ++-- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/package-lock.json b/package-lock.json index 3e0e541ff..643d1f0e3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -34,10 +34,10 @@ "jwt-simple": "^0.5.6", "less": "^3.13.1", "lodash": "^4.17.21", - "marked": "12.0.2", + "marked": "13.0.3", "marked-emoji": "^1.4.3", "marked-extended-tables": "^1.1.0", - "marked-gfm-heading-id": "^3.2.0", + "marked-gfm-heading-id": "^4.0.1", "marked-smartypants-lite": "^1.0.3", "markedLegacy": "npm:marked@^0.3.19", "moment": "^2.30.1", @@ -9789,9 +9789,9 @@ } }, "node_modules/marked": { - "version": "12.0.2", - "resolved": "https://registry.npmjs.org/marked/-/marked-12.0.2.tgz", - "integrity": "sha512-qXUm7e/YKFoqFPYPa3Ukg9xlI5cyAtGmyEIzMfW//m6kXwCy2Ps9DYf5ioijFKQ8qyuscrHoY04iJGctu2Kg0Q==", + "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" @@ -9817,15 +9817,15 @@ } }, "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": { diff --git a/package.json b/package.json index 0598cdbd8..cd43bb5e2 100644 --- a/package.json +++ b/package.json @@ -109,10 +109,10 @@ "jwt-simple": "^0.5.6", "less": "^3.13.1", "lodash": "^4.17.21", - "marked": "12.0.2", + "marked": "13.0.3", "marked-emoji": "^1.4.3", "marked-extended-tables": "^1.1.0", - "marked-gfm-heading-id": "^3.2.0", + "marked-gfm-heading-id": "^4.0.1", "marked-smartypants-lite": "^1.0.3", "markedLegacy": "npm:marked@^0.3.19", "moment": "^2.30.1", From 518924d72590e5ba11ae237391811a4118c92107 Mon Sep 17 00:00:00 2001 From: Trevor Buckner Date: Fri, 31 Jan 2025 13:36:42 -0500 Subject: [PATCH 161/398] Use import, run eslint --- ...ation-block-multi-line-min-declarations.js | 28 ++++---- stylelint_plugins/declaration-colon-align.js | 67 ++++++++++--------- .../declaration-colon-min-space-before.js | 21 +++--- 3 files changed, 58 insertions(+), 58 deletions(-) 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 From 2f1ade84636857fde18832e795e4cfc81b55ef61 Mon Sep 17 00:00:00 2001 From: Trevor Buckner Date: Fri, 31 Jan 2025 13:38:25 -0500 Subject: [PATCH 162/398] lint --- .stylelintrc.json | 92 +++++++++++++++++++++++------------------------ 1 file changed, 46 insertions(+), 46 deletions(-) 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 + } } From 19660272898744fde1210805b3789d1663c910a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Losada=20Hern=C3=A1ndez?= Date: Fri, 31 Jan 2025 20:02:31 +0100 Subject: [PATCH 163/398] linting & suggested changes --- .../notificationPopup/notificationPopup.jsx | 3 +-- .../notificationPopup/notificationPopup.less | 24 +++++++++---------- 2 files changed, 13 insertions(+), 14 deletions(-) diff --git a/client/homebrew/brewRenderer/notificationPopup/notificationPopup.jsx b/client/homebrew/brewRenderer/notificationPopup/notificationPopup.jsx index 49ac57994..38a85e0c7 100644 --- a/client/homebrew/brewRenderer/notificationPopup/notificationPopup.jsx +++ b/client/homebrew/brewRenderer/notificationPopup/notificationPopup.jsx @@ -41,11 +41,10 @@ const NotificationPopup = ()=>{ const renderNotificationsList = ()=>{ if(error) return
    {error}
    ; - notifications.map((notification) =>console.log(Markdown.render(notification.text, 1))); return notifications.map((notification)=>(
  • {notification.title}
    -

    +

  • )); }; diff --git a/client/homebrew/brewRenderer/notificationPopup/notificationPopup.less b/client/homebrew/brewRenderer/notificationPopup/notificationPopup.less index 4f5a0a2de..8c32f037f 100644 --- a/client/homebrew/brewRenderer/notificationPopup/notificationPopup.less +++ b/client/homebrew/brewRenderer/notificationPopup/notificationPopup.less @@ -52,14 +52,14 @@ list-style-position : outside; list-style-type : disc; li { - font-size : 0.9em; - line-height : 1.5em; - padding-left: 1em; - em { - text-transform:capitalize; - font-weight : 800; + padding-left : 1em; + font-size : 0.9em; + line-height : 1.5em; + em { + font-weight : 800; + text-transform : capitalize; } - li { list-style-type: square; line-height : 1.2em;} + li { line-height : 1.2em; list-style-type : square;} } ul ul,ol ol,ul ol,ol ul { margin-bottom : 0px; @@ -67,14 +67,14 @@ } } - /*Markdown styling*/ + /* Markdown styling */ code { - background:#08115a; - padding: 0.1em 0.5em; - border-radius:2px; - font-family : 'Courier New', "Courier", monospace; + 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; From be1742d01d52c7e5be960482daf7dbdf118846d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Losada=20Hern=C3=A1ndez?= Date: Fri, 31 Jan 2025 20:08:10 +0100 Subject: [PATCH 164/398] remove unnecessary spaces --- .../notificationPopup/notificationPopup.less | 28 ++++++++----------- 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/client/homebrew/brewRenderer/notificationPopup/notificationPopup.less b/client/homebrew/brewRenderer/notificationPopup/notificationPopup.less index 8c32f037f..8383920a5 100644 --- a/client/homebrew/brewRenderer/notificationPopup/notificationPopup.less +++ b/client/homebrew/brewRenderer/notificationPopup/notificationPopup.less @@ -52,14 +52,14 @@ list-style-position : outside; list-style-type : disc; li { - padding-left : 1em; - font-size : 0.9em; - line-height : 1.5em; - em { - font-weight : 800; - text-transform : capitalize; + font-size : 0.9em; + line-height : 1.5em; + padding-left: 1em; + em { + text-transform:capitalize; + font-weight : 800; } - li { line-height : 1.2em; list-style-type : square;} + li { list-style-type: square; line-height : 1.2em;} } ul ul,ol ol,ul ol,ol ul { margin-bottom : 0px; @@ -67,14 +67,14 @@ } } - /* Markdown styling */ + /*Markdown styling*/ code { - padding : 0.1em 0.5em; - font-family : 'Courier New', 'Courier', monospace; + background:#08115a; + padding: 0.1em 0.5em; + border-radius:2px; + font-family : 'Courier New', "Courier", monospace; overflow-wrap : break-word; white-space : pre-wrap; - background : #08115A; - border-radius : 2px; } pre code { display : inline-block; @@ -85,8 +85,4 @@ margin-top : 0; & + * { margin-top : 0; } } - - - - } \ No newline at end of file From 460fb655d82127a46ac715d0d04993ab77bd532d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Losada=20Hern=C3=A1ndez?= Date: Fri, 31 Jan 2025 20:11:57 +0100 Subject: [PATCH 165/398] bring margin back --- .../notificationPopup/notificationPopup.less | 29 +++++++++++-------- 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/client/homebrew/brewRenderer/notificationPopup/notificationPopup.less b/client/homebrew/brewRenderer/notificationPopup/notificationPopup.less index 8383920a5..be642f0fe 100644 --- a/client/homebrew/brewRenderer/notificationPopup/notificationPopup.less +++ b/client/homebrew/brewRenderer/notificationPopup/notificationPopup.less @@ -52,14 +52,19 @@ list-style-position : outside; list-style-type : disc; li { - font-size : 0.9em; - line-height : 1.5em; - padding-left: 1em; - 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; } - li { list-style-type: square; line-height : 1.2em;} } ul ul,ol ol,ul ol,ol ul { margin-bottom : 0px; @@ -67,14 +72,14 @@ } } - /*Markdown styling*/ + /* Markdown styling */ code { - background:#08115a; - padding: 0.1em 0.5em; - border-radius:2px; - font-family : 'Courier New', "Courier", monospace; + 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; From 66bfc8f27b8fd5784267c3f6cfd26ec18842fdc9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Losada=20Hern=C3=A1ndez?= Date: Fri, 31 Jan 2025 22:33:47 +0100 Subject: [PATCH 166/398] style change --- .../notificationLookup/notificationLookup.less | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/client/admin/notificationUtils/notificationLookup/notificationLookup.less b/client/admin/notificationUtils/notificationLookup/notificationLookup.less index 3f9b78310..edef88b71 100644 --- a/client/admin/notificationUtils/notificationLookup/notificationLookup.less +++ b/client/admin/notificationUtils/notificationLookup/notificationLookup.less @@ -31,8 +31,12 @@ font-weight : 900; } - dl dt{ - font-weight: 900; + dl { + padding-top:0.5em; + dt { + font-weight: 900; + height:fit-content; + } } } } From 564f5d71b2549dbc86bb8fa0d2f4b033340a4764 Mon Sep 17 00:00:00 2001 From: David Bolack Date: Fri, 31 Jan 2025 16:12:00 -0600 Subject: [PATCH 167/398] WIP --- shared/naturalcrit/markdown.js | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/shared/naturalcrit/markdown.js b/shared/naturalcrit/markdown.js index 1914cd201..1cd11d7b5 100644 --- a/shared/naturalcrit/markdown.js +++ b/shared/naturalcrit/markdown.js @@ -59,6 +59,12 @@ mathParser.functions.signed = function (a) { return `${a}`; }; +// Make sure we normalize variable names consistantly. +const normalizeVarNames = (label)=>{ + return label.trim() + .replace(/\s+/g, ' '); +}; + //Processes the markdown within an HTML block if it's just a class-wrapper renderer.html = function (html) { if(_.startsWith(_.trim(html), '')){ @@ -533,7 +539,7 @@ const replaceVar = function(input, hoist=false, allowUnresolved=false) { const match = regex.exec(input); const prefix = match[1]; - const label = match[2]; + const label = normalizeVarNames(match[2]); // Ensure the label name is normalized as it should be in the var stack. //v=====--------------------< HANDLE MATH >-------------------=====v// const mathRegex = /[a-z]+\(|[+\-*/^(),]/g; @@ -688,7 +694,7 @@ function MarkedVariables() { }); } if(match[3]) { // Block Definition - const label = match[4] ? match[4].trim().replace(/\s+/g, ' ') : null; // Trim edge spaces and shorten blocks of whitespace to 1 space + const label = match[4] ? normalizeVarNames(match[4]) : null; // Trim edge spaces and shorten blocks of whitespace to 1 space const content = match[5] ? match[5].trim().replace(/[ \t]+/g, ' ') : null; // Trim edge spaces and shorten blocks of whitespace to 1 space varsQueue.push( @@ -698,7 +704,7 @@ function MarkedVariables() { }); } if(match[6]) { // Block Call - const label = match[7] ? match[7].trim().replace(/\s+/g, ' ') : null; // Trim edge spaces and shorten blocks of whitespace to 1 space + const label = match[7] ? normalizeVarNames(match[7]) : null; // Trim edge spaces and shorten blocks of whitespace to 1 space varsQueue.push( { type : 'varCallBlock', @@ -707,7 +713,7 @@ function MarkedVariables() { }); } if(match[8]) { // Inline Definition - const label = match[10] ? match[10].trim().replace(/\s+/g, ' ') : null; // Trim edge spaces and shorten blocks of whitespace to 1 space + const label = match[10] ? normalizeVarNames(match[10]) : null; // Trim edge spaces and shorten blocks of whitespace to 1 space let content = match[11] || null; // In case of nested (), find the correct matching end ) @@ -735,11 +741,11 @@ function MarkedVariables() { varsQueue.push( { type : 'varCallInline', varName : label, - content : match[9].replace(/\s+/g, ' ').replace(/\[\s+/, '[').replace(/\s+\]/, ']') + content : match[9] }); } if(match[12]) { // Inline Call - const label = match[13] ? match[13].trim().replace(/\s+/g, ' ') : null; // Trim edge spaces and shorten blocks of whitespace to 1 space + const label = match[13] ? normalizeVarNames(match[13]) : null; // Trim edge spaces and shorten blocks of whitespace to 1 space varsQueue.push( { type : 'varCallInline', From 3ce9bb13102c315f2f1c2e8d9dca827b988569e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Losada=20Hern=C3=A1ndez?= Date: Fri, 31 Jan 2025 23:20:35 +0100 Subject: [PATCH 168/398] initial commit --- client/admin/admin.jsx | 56 ++++++++++++------------- client/admin/admin.less | 8 +++- client/admin/brewUtils/stats/stats.jsx | 5 ++- client/admin/brewUtils/stats/stats.less | 9 ++-- server/admin.api.js | 1 - 5 files changed, 44 insertions(+), 35 deletions(-) diff --git a/client/admin/admin.jsx b/client/admin/admin.jsx index f2f2667a4..9f84eaad4 100644 --- a/client/admin/admin.jsx +++ b/client/admin/admin.jsx @@ -1,47 +1,47 @@ -require('./admin.less'); -const React = require('react'); -const createClass = require('create-react-class'); - +import './admin.less'; +import React, { useEffect, useState } from 'react'; const BrewUtils = require('./brewUtils/brewUtils.jsx'); const NotificationUtils = require('./notificationUtils/notificationUtils.jsx'); const tabGroups = ['brew', 'notifications']; -const Admin = createClass({ - getDefaultProps : function() { - return {}; - }, +const Admin = ()=>{ + const [currentTab, setCurrentTab] = useState('brew'); - getInitialState : function(){ - return ({ - currentTab : 'brew' - }); - }, + useEffect(()=>{ + setCurrentTab(localStorage.getItem('hbAdminTab')); + }, []); - handleClick : function(newTab){ - if(this.state.currentTab === newTab) return; - this.setState({ - currentTab : newTab - }); - }, + useEffect(()=>{ + localStorage.setItem('hbAdminTab', currentTab); + }, [currentTab]); - render : function(){ - return
    + return ( +
    - homebrewery admin + The Homebrewery Admin Page + back to homepage
    +
    - {this.state.currentTab==='brew' && } - {this.state.currentTab==='notifications' && } + {currentTab === 'brew' && } + {currentTab === 'notifications' && }
    -
    ; - } -}); +
    + ); +}; module.exports = Admin; diff --git a/client/admin/admin.less b/client/admin/admin.less index c6c9b4662..47ef10528 100644 --- a/client/admin/admin.less +++ b/client/admin/admin.less @@ -30,6 +30,10 @@ body { color : white; background-color : @red; i { margin-right : 30px; } + + a { + float:right; + } } hr { margin : 30px 0px; } @@ -48,10 +52,10 @@ body { } dl { - @maxItemWidth : 132px; + @maxItemWidth : 180px; dt { float : left; - width : @maxItemWidth; + max-width : @maxItemWidth; clear : left; text-align : right; &::after { content : ' : '; } diff --git a/client/admin/brewUtils/stats/stats.jsx b/client/admin/brewUtils/stats/stats.jsx index 85ce10610..35f46d143 100644 --- a/client/admin/brewUtils/stats/stats.jsx +++ b/client/admin/brewUtils/stats/stats.jsx @@ -14,7 +14,8 @@ const Stats = createClass({ getInitialState(){ return { stats : { - totalBrews : 0 + totalBrews : 0, + totalPublishedBrews : 0 }, fetching : false }; @@ -34,6 +35,8 @@ const Stats = createClass({
    Total Brew Count
    {this.state.stats.totalBrews}
    +
    Total Brews Published
    +
    {this.state.stats.totalPublishedBrews}
    {this.state.fetching diff --git a/client/admin/brewUtils/stats/stats.less b/client/admin/brewUtils/stats/stats.less index b5a4612e1..355845cbc 100644 --- a/client/admin/brewUtils/stats/stats.less +++ b/client/admin/brewUtils/stats/stats.less @@ -4,10 +4,13 @@ .pending { position : absolute; - top : 0px; - left : 0px; + top : 0.5em; + left : 100px; width : 100%; height : 100%; - background-color : rgba(238,238,238, 0.5); + } + + &:has(.pending) { + opacity:0.5; } } \ No newline at end of file diff --git a/server/admin.api.js b/server/admin.api.js index 1a39f020b..65c91fee8 100644 --- a/server/admin.api.js +++ b/server/admin.api.js @@ -135,7 +135,6 @@ router.put('/admin/compress/:id', (req, res)=>{ }); }); - router.get('/admin/stats', mw.adminOnly, async (req, res)=>{ try { const totalBrewsCount = await HomebrewModel.countDocuments({}); From b1ff68c3b1df577a8e51654373ac62024f0baaf9 Mon Sep 17 00:00:00 2001 From: David Bolack Date: Fri, 31 Jan 2025 16:12:00 -0600 Subject: [PATCH 169/398] Update code to use helper function to ensure unifrom normalization of Variable labels. --- shared/naturalcrit/markdown.js | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/shared/naturalcrit/markdown.js b/shared/naturalcrit/markdown.js index 1914cd201..1cd11d7b5 100644 --- a/shared/naturalcrit/markdown.js +++ b/shared/naturalcrit/markdown.js @@ -59,6 +59,12 @@ mathParser.functions.signed = function (a) { return `${a}`; }; +// Make sure we normalize variable names consistantly. +const normalizeVarNames = (label)=>{ + return label.trim() + .replace(/\s+/g, ' '); +}; + //Processes the markdown within an HTML block if it's just a class-wrapper renderer.html = function (html) { if(_.startsWith(_.trim(html), '')){ @@ -533,7 +539,7 @@ const replaceVar = function(input, hoist=false, allowUnresolved=false) { const match = regex.exec(input); const prefix = match[1]; - const label = match[2]; + const label = normalizeVarNames(match[2]); // Ensure the label name is normalized as it should be in the var stack. //v=====--------------------< HANDLE MATH >-------------------=====v// const mathRegex = /[a-z]+\(|[+\-*/^(),]/g; @@ -688,7 +694,7 @@ function MarkedVariables() { }); } if(match[3]) { // Block Definition - const label = match[4] ? match[4].trim().replace(/\s+/g, ' ') : null; // Trim edge spaces and shorten blocks of whitespace to 1 space + const label = match[4] ? normalizeVarNames(match[4]) : null; // Trim edge spaces and shorten blocks of whitespace to 1 space const content = match[5] ? match[5].trim().replace(/[ \t]+/g, ' ') : null; // Trim edge spaces and shorten blocks of whitespace to 1 space varsQueue.push( @@ -698,7 +704,7 @@ function MarkedVariables() { }); } if(match[6]) { // Block Call - const label = match[7] ? match[7].trim().replace(/\s+/g, ' ') : null; // Trim edge spaces and shorten blocks of whitespace to 1 space + const label = match[7] ? normalizeVarNames(match[7]) : null; // Trim edge spaces and shorten blocks of whitespace to 1 space varsQueue.push( { type : 'varCallBlock', @@ -707,7 +713,7 @@ function MarkedVariables() { }); } if(match[8]) { // Inline Definition - const label = match[10] ? match[10].trim().replace(/\s+/g, ' ') : null; // Trim edge spaces and shorten blocks of whitespace to 1 space + const label = match[10] ? normalizeVarNames(match[10]) : null; // Trim edge spaces and shorten blocks of whitespace to 1 space let content = match[11] || null; // In case of nested (), find the correct matching end ) @@ -735,11 +741,11 @@ function MarkedVariables() { varsQueue.push( { type : 'varCallInline', varName : label, - content : match[9].replace(/\s+/g, ' ').replace(/\[\s+/, '[').replace(/\s+\]/, ']') + content : match[9] }); } if(match[12]) { // Inline Call - const label = match[13] ? match[13].trim().replace(/\s+/g, ' ') : null; // Trim edge spaces and shorten blocks of whitespace to 1 space + const label = match[13] ? normalizeVarNames(match[13]) : null; // Trim edge spaces and shorten blocks of whitespace to 1 space varsQueue.push( { type : 'varCallInline', From a504703d411c8a7c34cd2057b8f8ec66ac2ecb90 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Losada=20Hern=C3=A1ndez?= Date: Sat, 1 Feb 2025 15:47:41 +0100 Subject: [PATCH 170/398] removed unnecessary files and refactored layout of dl --- client/admin/admin.less | 40 ++++++++++--------- .../brewUtils/brewCleanup/brewCleanup.jsx | 10 ++--- .../brewUtils/brewCleanup/brewCleanup.less | 9 ----- .../brewUtils/brewCompress/brewCompress.jsx | 9 ++--- .../brewUtils/brewCompress/brewCompress.less | 9 ----- .../admin/brewUtils/brewLookup/brewLookup.jsx | 8 ++-- .../brewUtils/brewLookup/brewLookup.less | 6 --- client/admin/brewUtils/brewUtils.jsx | 2 +- client/admin/brewUtils/brewUtils.less | 33 +++++++++++++++ client/admin/brewUtils/stats/stats.jsx | 5 +-- client/admin/brewUtils/stats/stats.less | 16 -------- .../notificationAdd/notificationAdd.less | 6 ++- .../notificationLookup.less | 7 ---- 13 files changed, 71 insertions(+), 89 deletions(-) delete mode 100644 client/admin/brewUtils/brewCleanup/brewCleanup.less delete mode 100644 client/admin/brewUtils/brewCompress/brewCompress.less delete mode 100644 client/admin/brewUtils/brewLookup/brewLookup.less create mode 100644 client/admin/brewUtils/brewUtils.less delete mode 100644 client/admin/brewUtils/stats/stats.less diff --git a/client/admin/admin.less b/client/admin/admin.less index 47ef10528..51c675b5f 100644 --- a/client/admin/admin.less +++ b/client/admin/admin.less @@ -22,7 +22,6 @@ body { } :where(.admin) { - header { padding : 20px 0px; margin-bottom : 30px; @@ -31,14 +30,13 @@ body { background-color : @red; i { margin-right : 30px; } - a { - float:right; - } + a { float : right; } } hr { margin : 30px 0px; } :where(.container) { + padding-bottom : 50px; input { height : 33px; padding : 0px 10px; @@ -52,20 +50,23 @@ body { } dl { - @maxItemWidth : 180px; + display : grid; + grid-template-columns : 120px 1fr; + row-gap : 10px; + align-items : center; + justify-items : start; + padding-top : 0.5em; dt { - float : left; - max-width : @maxItemWidth; - clear : left; - text-align : right; + float : left; + clear : left; + height : fit-content; + font-weight : 900; + text-align : right; &::after { content : ' : '; } } - dd { - height : 1em; - padding : 0 0 0.5em 0; - margin-left : @maxItemWidth + 6px; - } + dd { height : fit-content; } } + .tabs button { margin-right : 3px; @@ -95,10 +96,11 @@ body { } .error { - background: rgb(178, 54, 54); - color:white; - font-weight: 900; - margin-block:10px; - padding:10px; + float : right; + padding : 10px; + margin-block : 10px; + font-weight : 900; + color : white; + background : rgb(178, 54, 54); } } diff --git a/client/admin/brewUtils/brewCleanup/brewCleanup.jsx b/client/admin/brewUtils/brewCleanup/brewCleanup.jsx index a166ae112..d4b17c570 100644 --- a/client/admin/brewUtils/brewCleanup/brewCleanup.jsx +++ b/client/admin/brewUtils/brewCleanup/brewCleanup.jsx @@ -1,10 +1,8 @@ -require('./brewCleanup.less'); const React = require('react'); const createClass = require('create-react-class'); const request = require('superagent'); - const BrewCleanup = createClass({ displayName : 'BrewCleanup', getDefaultProps(){ @@ -39,9 +37,9 @@ const BrewCleanup = createClass({ if(!this.state.primed) return; if(!this.state.count){ - return
    No Matching Brews found.
    ; + return
    No Matching Brews found.
    ; } - return
    + return
    ; }, render(){ - return
    + return

    Brew Cleanup

    Removes very short brews to tidy up the database

    @@ -65,7 +63,7 @@ const BrewCleanup = createClass({ {this.renderPrimed()} {this.state.error - &&
    {this.state.error.toString()}
    + &&
    {this.state.error.toString()}
    }
    ; } diff --git a/client/admin/brewUtils/brewCleanup/brewCleanup.less b/client/admin/brewUtils/brewCleanup/brewCleanup.less deleted file mode 100644 index 16fc98957..000000000 --- a/client/admin/brewUtils/brewCleanup/brewCleanup.less +++ /dev/null @@ -1,9 +0,0 @@ -.BrewCleanup { - .removeBox { - margin-top : 20px; - button { - margin-right : 10px; - background-color : @red; - } - } -} \ No newline at end of file diff --git a/client/admin/brewUtils/brewCompress/brewCompress.jsx b/client/admin/brewUtils/brewCompress/brewCompress.jsx index 2c8e5b023..ccb59e027 100644 --- a/client/admin/brewUtils/brewCompress/brewCompress.jsx +++ b/client/admin/brewUtils/brewCompress/brewCompress.jsx @@ -1,10 +1,7 @@ -require('./brewCompress.less'); const React = require('react'); const createClass = require('create-react-class'); - const request = require('superagent'); - const BrewCompress = createClass({ displayName : 'BrewCompress', getDefaultProps(){ @@ -53,9 +50,9 @@ const BrewCompress = createClass({ if(!this.state.primed) return; if(!this.state.count){ - return
    No Matching Brews found.
    ; + return
    No Matching Brews found.
    ; } - return
    + return
    ; }, render(){ - return
    + return

    Brew Compression

    Compresses the text in brews to binary

    diff --git a/client/admin/brewUtils/brewCompress/brewCompress.less b/client/admin/brewUtils/brewCompress/brewCompress.less deleted file mode 100644 index 8668e9280..000000000 --- a/client/admin/brewUtils/brewCompress/brewCompress.less +++ /dev/null @@ -1,9 +0,0 @@ -.BrewCompress { - .removeBox { - margin-top : 20px; - button { - margin-right : 10px; - background-color : @red; - } - } -} \ No newline at end of file diff --git a/client/admin/brewUtils/brewLookup/brewLookup.jsx b/client/admin/brewUtils/brewLookup/brewLookup.jsx index e5b585ced..fb780f29e 100644 --- a/client/admin/brewUtils/brewLookup/brewLookup.jsx +++ b/client/admin/brewUtils/brewLookup/brewLookup.jsx @@ -1,5 +1,3 @@ -require('./brewLookup.less'); - const React = require('react'); const createClass = require('create-react-class'); const cx = require('classnames'); @@ -55,7 +53,7 @@ const BrewLookup = createClass({ renderFoundBrew(){ const brew = this.state.foundBrew; - return
    + return
    Title
    {brew.title}
    @@ -90,7 +88,7 @@ const BrewLookup = createClass({ }, render(){ - return
    + return

    Brew Lookup

    ; } diff --git a/client/admin/brewUtils/brewLookup/brewLookup.less b/client/admin/brewUtils/brewLookup/brewLookup.less deleted file mode 100644 index da15e3a64..000000000 --- a/client/admin/brewUtils/brewLookup/brewLookup.less +++ /dev/null @@ -1,6 +0,0 @@ -.brewLookup { - .cleanButton { - display : inline-block; - width : 100%; - } -} \ No newline at end of file diff --git a/client/admin/brewUtils/brewUtils.jsx b/client/admin/brewUtils/brewUtils.jsx index de8c29895..bab2cb82f 100644 --- a/client/admin/brewUtils/brewUtils.jsx +++ b/client/admin/brewUtils/brewUtils.jsx @@ -1,6 +1,6 @@ const React = require('react'); const createClass = require('create-react-class'); - +require('./brewUtils.less'); const BrewCleanup = require('./brewCleanup/brewCleanup.jsx'); const BrewLookup = require('./brewLookup/brewLookup.jsx'); diff --git a/client/admin/brewUtils/brewUtils.less b/client/admin/brewUtils/brewUtils.less new file mode 100644 index 000000000..25e40a818 --- /dev/null +++ b/client/admin/brewUtils/brewUtils.less @@ -0,0 +1,33 @@ +.brewUtil { + .result { + margin-top : 20px; + button { + margin-right : 10px; + background-color : @red; + } + } + .cleanButton { + display : inline-block; + width : 100%; + } +} + +.stats { + position : relative; + + .pending { + position : absolute; + top : 0.5em; + left : 100px; + width : 100%; + height : 100%; + } + + &:has(.pending) { + opacity:0.5; + } + + dl { + grid-template-columns: 200px 250px; + } +} \ No newline at end of file diff --git a/client/admin/brewUtils/stats/stats.jsx b/client/admin/brewUtils/stats/stats.jsx index 35f46d143..7f96618f9 100644 --- a/client/admin/brewUtils/stats/stats.jsx +++ b/client/admin/brewUtils/stats/stats.jsx @@ -1,11 +1,8 @@ -require('./stats.less'); const React = require('react'); const createClass = require('create-react-class'); -const cx = require('classnames'); const request = require('superagent'); - const Stats = createClass({ displayName : 'Stats', getDefaultProps(){ @@ -30,7 +27,7 @@ const Stats = createClass({ .finally(()=>this.setState({ fetching: false })); }, render(){ - return
    + return

    Stats

    Total Brew Count
    diff --git a/client/admin/brewUtils/stats/stats.less b/client/admin/brewUtils/stats/stats.less deleted file mode 100644 index 355845cbc..000000000 --- a/client/admin/brewUtils/stats/stats.less +++ /dev/null @@ -1,16 +0,0 @@ - -.Stats { - position : relative; - - .pending { - position : absolute; - top : 0.5em; - left : 100px; - width : 100%; - height : 100%; - } - - &:has(.pending) { - opacity:0.5; - } -} \ No newline at end of file diff --git a/client/admin/notificationUtils/notificationAdd/notificationAdd.less b/client/admin/notificationUtils/notificationAdd/notificationAdd.less index 878da24c2..72862e956 100644 --- a/client/admin/notificationUtils/notificationAdd/notificationAdd.less +++ b/client/admin/notificationUtils/notificationAdd/notificationAdd.less @@ -6,7 +6,7 @@ .field { display : grid; - grid-template-columns : 120px 150px; + grid-template-columns : 120px 200px; align-items : center; justify-items : stretch; width : 100%; @@ -18,6 +18,10 @@ padding : 0px 10px; margin-bottom : unset; font-family : monospace; + + &[type="date"] { + width:14ch; + } } textarea { diff --git a/client/admin/notificationUtils/notificationLookup/notificationLookup.less b/client/admin/notificationUtils/notificationLookup/notificationLookup.less index edef88b71..25d29251d 100644 --- a/client/admin/notificationUtils/notificationLookup/notificationLookup.less +++ b/client/admin/notificationUtils/notificationLookup/notificationLookup.less @@ -31,13 +31,6 @@ font-weight : 900; } - dl { - padding-top:0.5em; - dt { - font-weight: 900; - height:fit-content; - } - } } } .noNotification { margin-block : 20px; } From a04df0fdfc5fc2ca9a10a086e9d07fae4c15f230 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Losada=20Hern=C3=A1ndez?= Date: Sat, 1 Feb 2025 19:27:55 +0100 Subject: [PATCH 171/398] small adjustements --- themes/V3/5ePHB/style.less | 3 --- 1 file changed, 3 deletions(-) diff --git a/themes/V3/5ePHB/style.less b/themes/V3/5ePHB/style.less index ba975e58a..4f3e1d7a4 100644 --- a/themes/V3/5ePHB/style.less +++ b/themes/V3/5ePHB/style.less @@ -622,7 +622,6 @@ left : 0; filter : drop-shadow(0 0 0.075cm black); img { - width : 100%; height : 2cm; } } @@ -667,7 +666,6 @@ left : 0; height : 2cm; img { - width : 100%; height : 2cm; } } @@ -685,7 +683,6 @@ position : absolute; inset : 0; z-index : -1; - width : 11cm; background-image : @backCover; background-repeat : no-repeat; background-size : contain; From 8eef810f3f8f2dae658a8053435f84fff1eeb4d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Losada=20Hern=C3=A1ndez?= Date: Sat, 1 Feb 2025 20:30:54 +0100 Subject: [PATCH 172/398] backcover logo width --- themes/V3/5ePHB/style.less | 1 - 1 file changed, 1 deletion(-) diff --git a/themes/V3/5ePHB/style.less b/themes/V3/5ePHB/style.less index 4f3e1d7a4..6b8126eb6 100644 --- a/themes/V3/5ePHB/style.less +++ b/themes/V3/5ePHB/style.less @@ -734,7 +734,6 @@ img { position : relative; z-index : 0; - width : 100%; height : 1.5cm; } p { From bf2210447497b8b65e07c8881d6308dc82bc3c45 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Losada=20Hern=C3=A1ndez?= Date: Sun, 2 Feb 2025 22:19:38 +0100 Subject: [PATCH 173/398] move padding to a more deserving place --- client/admin/admin.less | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/admin/admin.less b/client/admin/admin.less index 51c675b5f..92d63da2c 100644 --- a/client/admin/admin.less +++ b/client/admin/admin.less @@ -22,6 +22,7 @@ body { } :where(.admin) { + padding-bottom : 50px; header { padding : 20px 0px; margin-bottom : 30px; @@ -36,7 +37,6 @@ body { hr { margin : 30px 0px; } :where(.container) { - padding-bottom : 50px; input { height : 33px; padding : 0px 10px; From 27c4cfd25c5c7789c1f796d2434f781ccd30f8ab Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 3 Feb 2025 03:16:41 +0000 Subject: [PATCH 174/398] Bump mongoose from 8.9.5 to 8.9.6 Bumps [mongoose](https://github.com/Automattic/mongoose) from 8.9.5 to 8.9.6. - [Release notes](https://github.com/Automattic/mongoose/releases) - [Changelog](https://github.com/Automattic/mongoose/blob/master/CHANGELOG.md) - [Commits](https://github.com/Automattic/mongoose/compare/8.9.5...8.9.6) --- updated-dependencies: - dependency-name: mongoose dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- package-lock.json | 9 +++++---- package.json | 2 +- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index 643d1f0e3..a06b29c1e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -41,7 +41,7 @@ "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", @@ -10187,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", diff --git a/package.json b/package.json index cd43bb5e2..7031004ee 100644 --- a/package.json +++ b/package.json @@ -116,7 +116,7 @@ "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", From 423caefe1aea07154e593558a98c66b4e506e31b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 3 Feb 2025 04:45:39 +0000 Subject: [PATCH 175/398] Bump react-router from 7.1.4 to 7.1.5 Bumps [react-router](https://github.com/remix-run/react-router/tree/HEAD/packages/react-router) from 7.1.4 to 7.1.5. - [Release notes](https://github.com/remix-run/react-router/releases) - [Changelog](https://github.com/remix-run/react-router/blob/main/packages/react-router/CHANGELOG.md) - [Commits](https://github.com/remix-run/react-router/commits/react-router@7.1.5/packages/react-router) --- updated-dependencies: - dependency-name: react-router dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- package-lock.json | 8 ++++---- package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index a06b29c1e..649c6597c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -47,7 +47,7 @@ "react": "^18.3.1", "react-dom": "^18.3.1", "react-frame-component": "^4.1.3", - "react-router": "^7.1.4", + "react-router": "^7.1.5", "sanitize-filename": "1.6.3", "superagent": "^10.1.1", "vitreum": "git+https://git@github.com/calculuschild/vitreum.git" @@ -11610,9 +11610,9 @@ "license": "MIT" }, "node_modules/react-router": { - "version": "7.1.4", - "resolved": "https://registry.npmjs.org/react-router/-/react-router-7.1.4.tgz", - "integrity": "sha512-aJWVrKoLI0nIK1lfbTU3d5al1ZEUiwtSus/xjYL8K5sv2hyPesiOIojHM7QnaNLVtroOB1McZsWk37fMQVoc6A==", + "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", diff --git a/package.json b/package.json index 7031004ee..2bf3a0a93 100644 --- a/package.json +++ b/package.json @@ -122,7 +122,7 @@ "react": "^18.3.1", "react-dom": "^18.3.1", "react-frame-component": "^4.1.3", - "react-router": "^7.1.4", + "react-router": "^7.1.5", "sanitize-filename": "1.6.3", "superagent": "^10.1.1", "vitreum": "git+https://git@github.com/calculuschild/vitreum.git" From ce01b6c1ff81c62f2fcf4948d399adb598a2408b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Losada=20Hern=C3=A1ndez?= Date: Mon, 3 Feb 2025 15:10:34 +0100 Subject: [PATCH 176/398] initial commit --- client/homebrew/pages/errorPage/errors/errorIndex.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 From 6d2cbaacc04e068c77e7c70f3f10e1f8945a26fc Mon Sep 17 00:00:00 2001 From: "G.Ambatte" Date: Wed, 5 Feb 2025 21:35:21 +1300 Subject: [PATCH 177/398] Add Admin API for getByUser --- server/admin.api.js | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/server/admin.api.js b/server/admin.api.js index 1a39f020b..a7d1d9811 100644 --- a/server/admin.api.js +++ b/server/admin.api.js @@ -93,7 +93,7 @@ router.get('/admin/finduncompressed', mw.adminOnly, (req, res)=>{ /* Cleans `` from the "text" field of a brew */ router.put('/admin/clean/script/:id', asyncHandler(HomebrewAPI.getBrew('admin', false)), async (req, res)=>{ - console.log(`[ADMIN] Cleaning script tags from ShareID ${req.params.id}`); + console.log(`[ADMIN: ${req.account?.username || 'Not Logged In'}] Cleaning script tags from ShareID ${req.params.id}`); function cleanText(text){return text.replaceAll(/(<\/?s)cript/gi, '');}; @@ -114,6 +114,18 @@ router.put('/admin/clean/script/:id', asyncHandler(HomebrewAPI.getBrew('admin', return await HomebrewAPI.updateBrew(req, res); }); +/* Get list of a user's documents */ +router.get('/admin/user/list/:user', mw.adminOnly, async (req, res)=>{ + const username = req.params.user; + const fields = { _id: 0, text: 0, textBin: 0 }; // Remove unnecessary fields from document lists + + console.log(`[ADMIN: ${req.account?.username || 'Not Logged In'}] Get brew list for ${username}`); + + const brews = await HomebrewModel.getByUser(username, true, fields); + + return res.json(brews); +}); + /* Compresses the "text" field of a brew to binary */ router.put('/admin/compress/:id', (req, res)=>{ HomebrewModel.findOne({ _id: req.params.id }) From 03798e945dc4e69845e6da1b456c52afba8e7dbc Mon Sep 17 00:00:00 2001 From: "G.Ambatte" Date: Wed, 5 Feb 2025 21:35:33 +1300 Subject: [PATCH 178/398] Add UI --- client/admin/admin.jsx | 4 +- .../authorUtils/authorLookup/authorLookup.jsx | 90 +++++++++++++++++++ .../authorLookup/authorLookup.less | 48 ++++++++++ client/admin/authorUtils/authorUtils.jsx | 13 +++ 4 files changed, 154 insertions(+), 1 deletion(-) create mode 100644 client/admin/authorUtils/authorLookup/authorLookup.jsx create mode 100644 client/admin/authorUtils/authorLookup/authorLookup.less create mode 100644 client/admin/authorUtils/authorUtils.jsx diff --git a/client/admin/admin.jsx b/client/admin/admin.jsx index f2f2667a4..c24f7f176 100644 --- a/client/admin/admin.jsx +++ b/client/admin/admin.jsx @@ -4,8 +4,9 @@ const createClass = require('create-react-class'); const BrewUtils = require('./brewUtils/brewUtils.jsx'); const NotificationUtils = require('./notificationUtils/notificationUtils.jsx'); +import AuthorUtils from './authorUtils/authorUtils.jsx'; -const tabGroups = ['brew', 'notifications']; +const tabGroups = ['brew', 'notifications', 'authors']; const Admin = createClass({ getDefaultProps : function() { @@ -39,6 +40,7 @@ const Admin = createClass({ {this.state.currentTab==='brew' && } {this.state.currentTab==='notifications' && } + {this.state.currentTab==='authors' && }
    ; } diff --git a/client/admin/authorUtils/authorLookup/authorLookup.jsx b/client/admin/authorUtils/authorLookup/authorLookup.jsx new file mode 100644 index 000000000..50226d93d --- /dev/null +++ b/client/admin/authorUtils/authorLookup/authorLookup.jsx @@ -0,0 +1,90 @@ +import './authorLookup.less'; + +import React from 'react'; +import request from 'superagent'; + +const authorLookup = ()=>{ + const [author, setAuthor] = React.useState(''); + const [searching, setSearching] = React.useState(false); + const [results, setResults] = React.useState([]); + + const lookup = async ()=>{ + if(!author) return; + + setSearching(true); + setResults([]); + + await request.get(`/admin/user/list/${author}`) + .then((brews)=>{ + setResults(brews.body); + setSearching(false); + }); + }; + + const renderResults = ()=>{ + if(results.length == 0) return <> +

    Results

    +

    None found.

    + ; + + return <> +

    {`Results - ${results.length}`}

    + + + + + + + + + + + + {results + .sort((a, b)=>{ // Sort brews from most recently updated + if(a.updatedAt > b.updatedAt) return -1; + if(a.updatedAt < b.updatedAt) return 1; + return 0; + }) + .map((brew, idx)=>{ + return + + + + + + ; + })} + +
    TitleShareEditLast UpdateStorage
    {brew.title}{brew.shareId}{brew.editId}{brew.updatedAt}{brew.googleId ? 'Google' : 'Homebrewery'}
    + ; + }; + + const handleKeyPress = (evt)=>{ + if(evt.key === 'Enter') return lookup(); + }; + + const handleChange = (evt)=>{ + setAuthor(evt.target.value); + }; + + return ( +
    +
    +

    Author Lookup

    + +
    +
    + {renderResults()} +
    +
    + ); +}; + +module.exports = authorLookup; diff --git a/client/admin/authorUtils/authorLookup/authorLookup.less b/client/admin/authorUtils/authorLookup/authorLookup.less new file mode 100644 index 000000000..7f6903aa5 --- /dev/null +++ b/client/admin/authorUtils/authorLookup/authorLookup.less @@ -0,0 +1,48 @@ +.authorLookup { + position : relative; + display : flex; + flex-direction : column; + + .field { + display : flex; + gap : 5px; + align-items : center; + justify-items : stretch; + width : 100%; + margin-bottom : 20px; + + + input { + height : 33px; + padding : 0px 10px; + margin-bottom : unset; + font-family : monospace; + } + + button { + width: 50px; + + i { margin-right : 10px; } + } + } + + table.resultsTable { + * { + border: 1px solid black; + vertical-align: middle; + padding: 5px; + } + + th { + font-weight: bold; + } + + th, td { + text-align: center; + + &:first-of-type { + text-align: left; + } + } + } +} \ No newline at end of file diff --git a/client/admin/authorUtils/authorUtils.jsx b/client/admin/authorUtils/authorUtils.jsx new file mode 100644 index 000000000..a96eea528 --- /dev/null +++ b/client/admin/authorUtils/authorUtils.jsx @@ -0,0 +1,13 @@ +import React from 'react'; + +import AuthorLookup from './authorLookup/authorLookup.jsx'; + +const authorUtils = ()=>{ + return ( +
    + +
    + ); +}; + +module.exports = authorUtils; \ No newline at end of file From ada06c961869a9f28ce34554d7bae0098da84f76 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 6 Feb 2025 03:24:23 +0000 Subject: [PATCH 179/398] Bump @stylistic/stylelint-plugin from 3.1.1 to 3.1.2 Bumps [@stylistic/stylelint-plugin](https://github.com/stylelint-stylistic/stylelint-stylistic) from 3.1.1 to 3.1.2. - [Release notes](https://github.com/stylelint-stylistic/stylelint-stylistic/releases) - [Changelog](https://github.com/stylelint-stylistic/stylelint-stylistic/blob/main/CHANGELOG.md) - [Commits](https://github.com/stylelint-stylistic/stylelint-stylistic/compare/v3.1.1...v3.1.2) --- updated-dependencies: - dependency-name: "@stylistic/stylelint-plugin" dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- package-lock.json | 9 +++++---- package.json | 2 +- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index 649c6597c..94ec75f88 100644 --- a/package-lock.json +++ b/package-lock.json @@ -53,7 +53,7 @@ "vitreum": "git+https://git@github.com/calculuschild/vitreum.git" }, "devDependencies": { - "@stylistic/stylelint-plugin": "^3.1.1", + "@stylistic/stylelint-plugin": "^3.1.2", "babel-plugin-transform-import-meta": "^2.3.2", "eslint": "^9.19.0", "eslint-plugin-jest": "^28.11.0", @@ -2773,10 +2773,11 @@ } }, "node_modules/@stylistic/stylelint-plugin": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/@stylistic/stylelint-plugin/-/stylelint-plugin-3.1.1.tgz", - "integrity": "sha512-XagAHHIa528EvyGybv8EEYGK5zrVW74cHpsjhtovVATbhDRuJYfE+X4HCaAieW9lCkwbX6L+X0I4CiUG3w/hFw==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@stylistic/stylelint-plugin/-/stylelint-plugin-3.1.2.tgz", + "integrity": "sha512-tylFJGMQo62alGazK74MNxFjMagYOHmBZiePZFOJK2n13JZta0uVkB3Bh5qodUmOLtRH+uxH297EibK14UKm8g==", "dev": true, + "license": "MIT", "dependencies": { "@csstools/css-parser-algorithms": "^3.0.1", "@csstools/css-tokenizer": "^3.0.1", diff --git a/package.json b/package.json index 2bf3a0a93..b83237d59 100644 --- a/package.json +++ b/package.json @@ -128,7 +128,7 @@ "vitreum": "git+https://git@github.com/calculuschild/vitreum.git" }, "devDependencies": { - "@stylistic/stylelint-plugin": "^3.1.1", + "@stylistic/stylelint-plugin": "^3.1.2", "babel-plugin-transform-import-meta": "^2.3.2", "eslint": "^9.19.0", "eslint-plugin-jest": "^28.11.0", From d061b902d5c8ddf03bf7d8abfa2c7c8e62377dec Mon Sep 17 00:00:00 2001 From: David Bolack Date: Fri, 7 Feb 2025 19:26:56 -0600 Subject: [PATCH 180/398] Make all typefaces available via blank - for now. --- themes/V3/Blank/style.less | 1 + 1 file changed, 1 insertion(+) diff --git a/themes/V3/Blank/style.less b/themes/V3/Blank/style.less index 82a101d09..ded7370ba 100644 --- a/themes/V3/Blank/style.less +++ b/themes/V3/Blank/style.less @@ -5,6 +5,7 @@ @import (less) './themes/fonts/iconFonts/diceFont.less'; @import (less) './themes/fonts/iconFonts/gameIcons.less'; @import (less) './themes/fonts/iconFonts/fontAwesome.less'; +@import (less) './themes/fonts/Journal/fonts.less'; :root { //Colors From a7a7e46e89c8ac0c9cf66c08bd004335d3071cfd Mon Sep 17 00:00:00 2001 From: "G.Ambatte" Date: Sun, 9 Feb 2025 22:40:54 +1300 Subject: [PATCH 181/398] Correct typo in date of v3.17.0 --- changelog.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/changelog.md b/changelog.md index 8cfb499f6..1464df6b0 100644 --- a/changelog.md +++ b/changelog.md @@ -88,7 +88,7 @@ pre { ## changelog For a full record of development, visit our [Github Page](https://github.com/naturalcrit/homebrewery). -### Thursday 01/30/2024 - v3.17.0 +### Thursday 01/30/2025 - v3.17.0 {{taskList ##### 5e-Cleric From 659510e364c68ea5a3e1199a3f74498c61119376 Mon Sep 17 00:00:00 2001 From: Trevor Buckner Date: Sun, 9 Feb 2025 12:07:09 -0500 Subject: [PATCH 182/398] Remove unused function --- shared/helpers.js | 6 ------ 1 file changed, 6 deletions(-) diff --git a/shared/helpers.js b/shared/helpers.js index 3aff9538a..c31516ac9 100644 --- a/shared/helpers.js +++ b/shared/helpers.js @@ -59,14 +59,8 @@ const fetchThemeBundle = async (obj, renderer, theme)=>{ })); }; -const fetchBrewAsThemeJSON = async (renderer, theme)=>{ - if(!renderer || !theme) return; - -} - export { splitTextStyleAndMetadata, printCurrentBrew, fetchThemeBundle, - fetchBrewAsThemeJSON }; From cfbf4021dccb57df02cbd64db116a5a0ab54f651 Mon Sep 17 00:00:00 2001 From: Trevor Buckner Date: Sun, 9 Feb 2025 12:23:42 -0500 Subject: [PATCH 183/398] Remove unneeded filter --- client/homebrew/editor/metadataEditor/metadataEditor.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/homebrew/editor/metadataEditor/metadataEditor.jsx b/client/homebrew/editor/metadataEditor/metadataEditor.jsx index 92e737764..8b7c31e53 100644 --- a/client/homebrew/editor/metadataEditor/metadataEditor.jsx +++ b/client/homebrew/editor/metadataEditor/metadataEditor.jsx @@ -239,7 +239,7 @@ const MetadataEditor = createClass({
    ; - }).filter(Boolean); + }); }; const currentRenderer = this.props.metadata.renderer; From a9fa0bd32d55a760a9f48a81df3351f2074dd05d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 10 Feb 2025 03:10:29 +0000 Subject: [PATCH 184/398] Bump @babel/plugin-transform-runtime from 7.25.9 to 7.26.8 Bumps [@babel/plugin-transform-runtime](https://github.com/babel/babel/tree/HEAD/packages/babel-plugin-transform-runtime) from 7.25.9 to 7.26.8. - [Release notes](https://github.com/babel/babel/releases) - [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md) - [Commits](https://github.com/babel/babel/commits/v7.26.8/packages/babel-plugin-transform-runtime) --- updated-dependencies: - dependency-name: "@babel/plugin-transform-runtime" dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- package-lock.json | 11 ++++++----- package.json | 2 +- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/package-lock.json b/package-lock.json index 649c6597c..0a3b2752c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,7 +11,7 @@ "license": "MIT", "dependencies": { "@babel/core": "^7.26.7", - "@babel/plugin-transform-runtime": "^7.25.9", + "@babel/plugin-transform-runtime": "^7.26.8", "@babel/preset-env": "^7.26.7", "@babel/preset-react": "^7.26.3", "@googleapis/drive": "^8.14.0", @@ -1404,12 +1404,13 @@ } }, "node_modules/@babel/plugin-transform-runtime": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.25.9.tgz", - "integrity": "sha512-nZp7GlEl+yULJrClz0SwHPqir3lc0zsPrDHQUcxGspSL7AKrexNSEfTbfqnDNJUO13bgKyfuOLMF8Xqtu8j3YQ==", + "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==", + "license": "MIT", "dependencies": { "@babel/helper-module-imports": "^7.25.9", - "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-plugin-utils": "^7.26.5", "babel-plugin-polyfill-corejs2": "^0.4.10", "babel-plugin-polyfill-corejs3": "^0.10.6", "babel-plugin-polyfill-regenerator": "^0.6.1", diff --git a/package.json b/package.json index 2bf3a0a93..1c010c365 100644 --- a/package.json +++ b/package.json @@ -86,7 +86,7 @@ }, "dependencies": { "@babel/core": "^7.26.7", - "@babel/plugin-transform-runtime": "^7.25.9", + "@babel/plugin-transform-runtime": "^7.26.8", "@babel/preset-env": "^7.26.7", "@babel/preset-react": "^7.26.3", "@googleapis/drive": "^8.14.0", From 6cfdfad7d326bfb9e93a57cdcfb9f0e94fb724a6 Mon Sep 17 00:00:00 2001 From: Trevor Buckner Date: Mon, 10 Feb 2025 00:33:33 -0500 Subject: [PATCH 185/398] Clean up combobox component --- client/components/combobox.jsx | 14 +-- client/components/combobox.less | 88 +++++++++---------- .../editor/metadataEditor/metadataEditor.jsx | 8 +- 3 files changed, 53 insertions(+), 57 deletions(-) diff --git a/client/components/combobox.jsx b/client/components/combobox.jsx index 5fcc154bc..56633bbdd 100644 --- a/client/components/combobox.jsx +++ b/client/components/combobox.jsx @@ -58,10 +58,10 @@ const Combobox = createClass({ this.props.onEntry(e); }); }, - handleSelect : function(e){ + handleSelect : function(value, data=value){ this.setState({ - value : e.currentTarget.getAttribute('data-value') - }, ()=>{this.props.onSelect(this.state.value);}); + value : value + }, ()=>{this.props.onSelect(data);}); ; }, renderTextInput : function(){ @@ -82,6 +82,7 @@ const Combobox = createClass({ } }} /> +
    ); }, @@ -92,11 +93,10 @@ const Combobox = createClass({ const filterOn = _.isString(this.props.autoSuggest.filterOn) ? [this.props.autoSuggest.filterOn] : this.props.autoSuggest.filterOn; const filteredArrays = filterOn.map((attr)=>{ const children = dropdownChildren.filter((item)=>{ - if(suggestMethod === 'includes'){ + if(suggestMethod === 'includes') return item.props[attr]?.toLowerCase().includes(this.state.value.toLowerCase()); - } else if(suggestMethod === 'startsWith'){ + if(suggestMethod === 'startsWith') return item.props[attr]?.toLowerCase().startsWith(this.state.value.toLowerCase()); - } }); return children; }); @@ -111,7 +111,7 @@ const Combobox = createClass({ }, render : function () { const dropdownChildren = this.state.options.map((child, i)=>{ - const clone = React.cloneElement(child, { onClick: (e)=>this.handleSelect(e) }); + const clone = React.cloneElement(child, { onClick: ()=>this.handleSelect(child.props.value, child.props.data) }); return clone; }); return ( diff --git a/client/components/combobox.less b/client/components/combobox.less index 3810a874e..d58019f6f 100644 --- a/client/components/combobox.less +++ b/client/components/combobox.less @@ -1,50 +1,46 @@ .dropdown-container { - position:relative; - input { - width: 100%; - } - .dropdown-options { - position:absolute; - background-color: white; - z-index: 100; - width: 100%; - border: 1px solid gray; - overflow-y: auto; - max-height: 200px; + position : relative; + input { width : 100%; } + .item i { + position : absolute; + right : 10px; + color : black; + } + .dropdown-options { + position : absolute; + z-index : 100; + width : 100%; + max-height : 200px; + overflow-y : auto; + background-color : white; + border : 1px solid gray; - &::-webkit-scrollbar { - width: 14px; - } - &::-webkit-scrollbar-track { - background: #ffffff; - } - &::-webkit-scrollbar-thumb { - background-color: #949494; - border-radius: 10px; - border: 3px solid #ffffff; - } - - .item { - position:relative; - font-size: 11px; - font-family: Open Sans; - padding: 5px; - cursor: default; - margin: 0 3px; - //border-bottom: 1px solid darkgray; - &:hover { - filter: brightness(120%); - background-color: rgb(163, 163, 163); - } - .detail { - width:100%; - text-align: left; - color: rgb(124, 124, 124); - font-style:italic; - font-size: 9px; - } - } - - } + &::-webkit-scrollbar { width : 14px; } + &::-webkit-scrollbar-track { background : #FFFFFF; } + &::-webkit-scrollbar-thumb { + background-color : #949494; + border : 3px solid #FFFFFF; + border-radius : 10px; + } + .item { + position : relative; + padding : 5px; + margin : 0 3px; + font-family : "Open Sans"; + font-size : 11px; + cursor : default; + &:hover { + background-color : rgb(163, 163, 163); + filter : brightness(120%); + } + .detail { + width : 100%; + font-size : 9px; + font-style : italic; + color : rgb(124, 124, 124); + text-align : left; + } + } + } } diff --git a/client/homebrew/editor/metadataEditor/metadataEditor.jsx b/client/homebrew/editor/metadataEditor/metadataEditor.jsx index bfc3b8b61..9d2ec7db6 100644 --- a/client/homebrew/editor/metadataEditor/metadataEditor.jsx +++ b/client/homebrew/editor/metadataEditor/metadataEditor.jsx @@ -244,9 +244,9 @@ const MetadataEditor = createClass({ return _.map(langCodes.sort(), (code, index)=>{ const localName = new Intl.DisplayNames([code], { type: 'language' }); const englishName = new Intl.DisplayNames('en', { type: 'language' }); - return
    - {`${code}`} -
    {`${localName.of(code)}`}
    + return
    + {code} +
    {localName.of(code)}
    ; }); }; @@ -269,7 +269,7 @@ const MetadataEditor = createClass({ autoSuggest={{ suggestMethod : 'startsWith', clearAutoSuggestOnClick : true, - filterOn : ['data-value', 'data-detail', 'title'] + filterOn : ['value', 'detail', 'title'] }} > From 11396389abf8c29d4d6aea2dbebe3547ddc34b36 Mon Sep 17 00:00:00 2001 From: David Bolack Date: Mon, 10 Feb 2025 20:47:17 -0600 Subject: [PATCH 186/398] Move Superscript/Subscript functions into their own module --- package-lock.json | 10 ++++++++++ package.json | 1 + shared/naturalcrit/markdown.js | 33 +++------------------------------ 3 files changed, 14 insertions(+), 30 deletions(-) diff --git a/package-lock.json b/package-lock.json index 649c6597c..165f4d343 100644 --- a/package-lock.json +++ b/package-lock.json @@ -39,6 +39,7 @@ "marked-extended-tables": "^1.1.0", "marked-gfm-heading-id": "^4.0.1", "marked-smartypants-lite": "^1.0.3", + "marked-subsuper-text": "^1.0.1", "markedLegacy": "npm:marked@^0.3.19", "moment": "^2.30.1", "mongoose": "^8.9.6", @@ -9837,6 +9838,15 @@ "marked": ">=4 <16" } }, + "node_modules/marked-subsuper-text": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/marked-subsuper-text/-/marked-subsuper-text-1.0.1.tgz", + "integrity": "sha512-VxKzXdijXd/smeoBcKBJstzxCuTddSvDpsIs1EPhEXCHYfk1MenDxqPXzRrC5kksZe47eptUzg+Bd6EK9HmMbw==", + "license": "MIT", + "peerDependencies": { + "marked": ">=3 <16" + } + }, "node_modules/markedLegacy": { "name": "marked", "version": "0.3.19", diff --git a/package.json b/package.json index 2bf3a0a93..0e2ca72c1 100644 --- a/package.json +++ b/package.json @@ -114,6 +114,7 @@ "marked-extended-tables": "^1.1.0", "marked-gfm-heading-id": "^4.0.1", "marked-smartypants-lite": "^1.0.3", + "marked-subsuper-text": "^1.0.1", "markedLegacy": "npm:marked@^0.3.19", "moment": "^2.30.1", "mongoose": "^8.9.6", diff --git a/shared/naturalcrit/markdown.js b/shared/naturalcrit/markdown.js index 99766b536..181cc55bd 100644 --- a/shared/naturalcrit/markdown.js +++ b/shared/naturalcrit/markdown.js @@ -7,6 +7,7 @@ import MarkedExtendedTables from 'marked-extended-tables'; import { markedSmartypantsLite as MarkedSmartypantsLite } from 'marked-smartypants-lite'; import { gfmHeadingId as MarkedGFMHeadingId, resetHeadings as MarkedGFMResetHeadingIDs } from 'marked-gfm-heading-id'; import { markedEmoji as MarkedEmojis } from 'marked-emoji'; +import MarkedSubSuperText from 'marked-subsuper-text'; //Icon fonts included so they can appear in emoji autosuggest dropdown import diceFont from '../../themes/fonts/iconFonts/diceFont.js'; @@ -333,35 +334,6 @@ const mustacheInjectBlock = { } }; -const superSubScripts = { - name : 'superSubScript', - level : 'inline', - start(src) { return src.match(/\^/m)?.index; }, // Hint to Marked.js to stop and check for a match - tokenizer(src, tokens) { - const superRegex = /^\^(?!\s)(?=([^\n\^]*[^\s\^]))\1\^/m; - const subRegex = /^\^\^(?!\s)(?=([^\n\^]*[^\s\^]))\1\^\^/m; - let isSuper = false; - let match = subRegex.exec(src); - if(!match){ - match = superRegex.exec(src); - if(match) - isSuper = true; - } - if(match?.length) { - return { - type : 'superSubScript', // Should match "name" above - raw : match[0], // Text to consume from the source - tag : isSuper ? 'sup' : 'sub', - tokens : this.lexer.inlineTokens(match[1]) - }; - } - }, - renderer(token) { - return `<${token.tag}>${this.parser.parseInline(token.tokens)}`; - } -}; - - const justifiedParagraphClasses = []; justifiedParagraphClasses[2] = 'Left'; justifiedParagraphClasses[4] = 'Right'; @@ -796,8 +768,9 @@ const tableTerminators = [ Marked.use(MarkedVariables()); Marked.use({ extensions : [justifiedParagraphs, definitionListsMultiLine, definitionListsSingleLine, forcedParagraphBreaks, - nonbreakingSpaces, superSubScripts, mustacheSpans, mustacheDivs, mustacheInjectInline] }); + nonbreakingSpaces, mustacheSpans, mustacheDivs, mustacheInjectInline] }); Marked.use(mustacheInjectBlock); +Marked.use(MarkedSubSuperText()); Marked.use({ renderer: renderer, tokenizer: tokenizer, mangle: false }); Marked.use(MarkedExtendedTables(tableTerminators), MarkedGFMHeadingId({ globalSlugs: true }), MarkedSmartypantsLite(), MarkedEmojis(MarkedEmojiOptions)); From c080e5b1915eea919c2f683aa4445a759b381ff4 Mon Sep 17 00:00:00 2001 From: Trevor Buckner Date: Mon, 10 Feb 2025 22:20:12 -0500 Subject: [PATCH 187/398] Add author to snippetBundle --- server/homebrew.api.js | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/server/homebrew.api.js b/server/homebrew.api.js index 8b4175491..17e9ae7fe 100644 --- a/server/homebrew.api.js +++ b/server/homebrew.api.js @@ -279,7 +279,8 @@ const api = { let currentTheme; const completeStyles = []; const completeSnippets = []; - let themePath = ''; + let themeName; + let themeAuthor; while (req.params.id) { //=== User Themes ===// @@ -293,17 +294,18 @@ const api = { currentTheme = req.brew; splitTextStyleAndMetadata(currentTheme); - if(themePath === '') themePath = currentTheme.title; + themeName ??= currentTheme.title; + themeAuthor ??= currentTheme.authors?.[0]; // If there is anything in the snippets or style members, append them to the appropriate array - // if(currentTheme?.snippets) completeSnippets.push(JSON.parse(currentTheme.snippets)); + if(currentTheme?.snippets) completeSnippets.push(JSON.parse(currentTheme.snippets)); if(currentTheme?.style) completeStyles.push(`/* From Brew: ${req.protocol}://${req.get('host')}/share/${req.params.id} */\n\n${currentTheme.style}`); req.params.id = currentTheme.theme; req.params.renderer = currentTheme.renderer; } else { //=== Static Themes ===// - if(themePath === '') themePath = req.params.id; + themeName ??= req.params.id; const localSnippets = `${req.params.renderer}_${req.params.id}`; // Just log the name for loading on client const localStyle = `@import url(\"/themes/${req.params.renderer}/${req.params.id}/style.css\");`; completeSnippets.push(localSnippets); @@ -317,7 +319,8 @@ const api = { // Reverse the order of the arrays so they are listed oldest parent to youngest child. styles : completeStyles.reverse(), snippets : completeSnippets.reverse(), - path : themePath + name : themeName, + author : themeAuthor }; res.setHeader('Content-Type', 'application/json'); From 1aed7539110badb8c7b3429f4dd30db113238905 Mon Sep 17 00:00:00 2001 From: Trevor Buckner Date: Mon, 10 Feb 2025 22:20:54 -0500 Subject: [PATCH 188/398] Use ComboBox component for Theme Selector --- .../editor/metadataEditor/metadataEditor.jsx | 86 +++++------ .../editor/metadataEditor/metadataEditor.less | 136 ++++++++---------- 2 files changed, 94 insertions(+), 128 deletions(-) diff --git a/client/homebrew/editor/metadataEditor/metadataEditor.jsx b/client/homebrew/editor/metadataEditor/metadataEditor.jsx index 199d2c4b7..141e1ab92 100644 --- a/client/homebrew/editor/metadataEditor/metadataEditor.jsx +++ b/client/homebrew/editor/metadataEditor/metadataEditor.jsx @@ -49,12 +49,8 @@ const MetadataEditor = createClass({ }, getInitialState : function(){ - mergedThemes = _.merge(Themes, this.props.userThemes); return { - showThumbnail : true, - showThemeWritein : mergedThemes[this.props.metadata.renderer][this.props.metadata.theme] ? false : true, - lastThemePulldown : mergedThemes[this.props.metadata.renderer][this.props.metadata.theme] ? mergedThemes[this.props.metadata.renderer][this.props.metadata.theme].path : '', - lastThemeWriteIn : mergedThemes[this.props.metadata.renderer][this.props.metadata.theme] ? '' : this.props.metadata.theme + showThumbnail : true }; }, @@ -64,15 +60,6 @@ const MetadataEditor = createClass({ }); }, - toggleThemeWritein : function(){ - if(!this.state.showThemeWritein) this.props.metadata.theme = this.state.lastThemeWriteIn; - else this.props.metadata.theme = this.state.lastThemePulldown; - this.props.onChange(this.props.metadata, 'theme'); - this.setState({ - showThemeWritein : !this.state.showThemeWritein - }); - }, - renderThumbnail : function(){ if(!this.state.showThumbnail) return; return ; @@ -128,21 +115,15 @@ const MetadataEditor = createClass({ handleTheme : function(theme){ this.props.metadata.renderer = theme.renderer; this.props.metadata.theme = theme.path; - this.setState({ - lastThemePulldown : theme.path - }); this.props.onChange(this.props.metadata, 'theme'); }, handleThemeWritein : function(e) { - this.props.metadata.renderer = 'V3'; this.props.metadata.theme = e.target.value; - this.setState({ - lastThemeWriteIn : e.target.value - }); - this.props.onChange(this.props.metadata, 'renderer'); + + this.props.onChange(this.props.metadata, 'theme'); }, @@ -224,12 +205,14 @@ const MetadataEditor = createClass({ renderThemeDropdown : function(){ if(!global.enable_themes) return; + const mergedThemes = _.merge(Themes, this.props.userThemes); + const listThemes = (renderer)=>{ return _.map(_.values(mergedThemes[renderer]), (theme)=>{ if(theme.path == this.props.metadata.shareId) return; const preview = theme.thumbnail || `/themes/${theme.renderer}/${theme.path}/dropdownPreview.png`; const texture = theme.thumbnail || `/themes/${theme.renderer}/${theme.path}/dropdownTexture.png`; - return
    this.handleTheme(theme)} title={''}> + return
    {theme.author ?? renderer} : {theme.name}
    @@ -242,45 +225,45 @@ const MetadataEditor = createClass({ }); }; + console.log(this.props.themeBundle); + const currentRenderer = this.props.metadata.renderer; const currentTheme = mergedThemes[`${_.upperFirst(this.props.metadata.renderer)}`][this.props.metadata.theme] - ?? { name: `${this.props.themeBundle?.path || ''}`, author: '!!!' }; + ?? { name: `${this.props.themeBundle?.name || ''}`, author: `${this.props.themeBundle?.author || ''}` }; let dropdown; if(currentRenderer == 'legacy') { dropdown = - -
    {`Themes are not supported in the Legacy Renderer`}
    -
    ; +
    +
    Themes are not supported in the Legacy Renderer
    +
    ; } else { dropdown = - -
    {currentTheme.author ?? _.upperFirst(currentRenderer)} : {currentTheme.name}
    - - {listThemes(currentRenderer)} -
    ; +
    + this.handleTheme(value)} + onEntry={(e)=>{ + e.target.setCustomValidity(''); //Clear the validation popup while typing + //debouncedHandleFieldChange('theme', e); + this.handleThemeWritein(e); + }} + options={listThemes(currentRenderer)} + autoSuggest={{ + suggestMethod : 'includes', + clearAutoSuggestOnClick : true, + filterOn : ['value', 'title'] + }} + /> + Select from the list below (built-in themes and brews you have tagged "meta:theme"), or paste in the Share URL or Share ID of any brew. +
    ; } return
    - {!this.state.showThemeWritein?dropdown:''} - - {this.renderThemeWritein()} -
    ; - }, - - renderThemeWritein : function(){ - if(!this.state.showThemeWritein) return; - return
    - this.handleThemeWritein(e)} /> - {`${this.state.lastThemeWriteIn ? this.props.themeBundle?.path || '' : ''}`} + {dropdown}
    ; }, @@ -317,8 +300,7 @@ const MetadataEditor = createClass({ clearAutoSuggestOnClick : true, filterOn : ['value', 'detail', 'title'] }} - > - + /> Sets the HTML Lang property for your brew. May affect hyphenation or spellcheck.
    diff --git a/client/homebrew/editor/metadataEditor/metadataEditor.less b/client/homebrew/editor/metadataEditor/metadataEditor.less index d06e420ae..d76220e48 100644 --- a/client/homebrew/editor/metadataEditor/metadataEditor.less +++ b/client/homebrew/editor/metadataEditor/metadataEditor.less @@ -171,89 +171,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; } } } From 6d0d0057f6ef18a222a0ffccef3695ad2a580528 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 11 Feb 2025 15:22:28 +0000 Subject: [PATCH 189/398] Bump eslint from 9.19.0 to 9.20.0 Bumps [eslint](https://github.com/eslint/eslint) from 9.19.0 to 9.20.0. - [Release notes](https://github.com/eslint/eslint/releases) - [Changelog](https://github.com/eslint/eslint/blob/main/CHANGELOG.md) - [Commits](https://github.com/eslint/eslint/compare/v9.19.0...v9.20.0) --- updated-dependencies: - dependency-name: eslint dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- package-lock.json | 31 ++++++++++++++++++++++--------- package.json | 2 +- 2 files changed, 23 insertions(+), 10 deletions(-) diff --git a/package-lock.json b/package-lock.json index f005f9ec9..baf696afe 100644 --- a/package-lock.json +++ b/package-lock.json @@ -55,7 +55,7 @@ "devDependencies": { "@stylistic/stylelint-plugin": "^3.1.2", "babel-plugin-transform-import-meta": "^2.3.2", - "eslint": "^9.19.0", + "eslint": "^9.20.0", "eslint-plugin-jest": "^28.11.0", "eslint-plugin-react": "^7.37.4", "globals": "^15.14.0", @@ -1906,9 +1906,9 @@ } }, "node_modules/@eslint/js": { - "version": "9.19.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.19.0.tgz", - "integrity": "sha512-rbq9/g38qjfqFLOVPvwjIvFFdNziEC5S65jmjPw5r6A//QH+W91akh9irMwjDN8zKUTak6W9EsAv4m/7Wnw0UQ==", + "version": "9.20.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.20.0.tgz", + "integrity": "sha512-iZA07H9io9Wn836aVTytRaNqh00Sad+EamwOVJT12GTLw1VGMFV/4JaME+JjLtr9fiGaoWgYnS54wrfWsSs4oQ==", "dev": true, "license": "MIT", "engines": { @@ -5634,18 +5634,18 @@ "license": "MIT" }, "node_modules/eslint": { - "version": "9.19.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.19.0.tgz", - "integrity": "sha512-ug92j0LepKlbbEv6hD911THhoRHmbdXt2gX+VDABAW/Ir7D3nqKdv5Pf5vtlyY6HQMTEP2skXY43ueqTCWssEA==", + "version": "9.20.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.20.0.tgz", + "integrity": "sha512-aL4F8167Hg4IvsW89ejnpTwx+B/UQRzJPGgbIOl+4XqffWsahVVsLEWoZvnrVuwpWmnRd7XeXmQI1zlKcFDteA==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.12.1", "@eslint/config-array": "^0.19.0", - "@eslint/core": "^0.10.0", + "@eslint/core": "^0.11.0", "@eslint/eslintrc": "^3.2.0", - "@eslint/js": "9.19.0", + "@eslint/js": "9.20.0", "@eslint/plugin-kit": "^0.2.5", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", @@ -5810,6 +5810,19 @@ "url": "https://opencollective.com/eslint" } }, + "node_modules/eslint/node_modules/@eslint/core": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.11.0.tgz", + "integrity": "sha512-DWUB2pksgNEb6Bz2fggIy1wh6fGgZP4Xyy/Mt0QZPiloKKXerbqq9D3SBQTlCRYOrcRPu4vuz+CGjwdfqxnoWA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@types/json-schema": "^7.0.15" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, "node_modules/eslint/node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", diff --git a/package.json b/package.json index c5bae6369..9bf60842b 100644 --- a/package.json +++ b/package.json @@ -130,7 +130,7 @@ "devDependencies": { "@stylistic/stylelint-plugin": "^3.1.2", "babel-plugin-transform-import-meta": "^2.3.2", - "eslint": "^9.19.0", + "eslint": "^9.20.0", "eslint-plugin-jest": "^28.11.0", "eslint-plugin-react": "^7.37.4", "globals": "^15.14.0", From 9d16f4556e12d2a6a9786150aab2160bce5b3462 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 11 Feb 2025 15:23:08 +0000 Subject: [PATCH 190/398] Bump mongoose from 8.9.6 to 8.10.0 Bumps [mongoose](https://github.com/Automattic/mongoose) from 8.9.6 to 8.10.0. - [Release notes](https://github.com/Automattic/mongoose/releases) - [Changelog](https://github.com/Automattic/mongoose/blob/master/CHANGELOG.md) - [Commits](https://github.com/Automattic/mongoose/compare/8.9.6...8.10.0) --- updated-dependencies: - dependency-name: mongoose dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- package-lock.json | 75 ++++++++++++++++++++++++++++------------------- package.json | 2 +- 2 files changed, 46 insertions(+), 31 deletions(-) diff --git a/package-lock.json b/package-lock.json index f005f9ec9..6f48c6812 100644 --- a/package-lock.json +++ b/package-lock.json @@ -41,7 +41,7 @@ "marked-smartypants-lite": "^1.0.3", "markedLegacy": "npm:marked@^0.3.19", "moment": "^2.30.1", - "mongoose": "^8.9.6", + "mongoose": "^8.10.0", "nanoid": "5.0.9", "nconf": "^0.12.1", "react": "^18.3.1", @@ -2701,9 +2701,10 @@ } }, "node_modules/@mongodb-js/saslprep": { - "version": "1.1.9", - "resolved": "https://registry.npmjs.org/@mongodb-js/saslprep/-/saslprep-1.1.9.tgz", - "integrity": "sha512-tVkljjeEaAhCqTzajSdgbQ6gE6f3oneVwa3iXR6csiEwXXOFsiC6Uh9iAjAhXPtqa/XMDHWjjeNH/77m/Yq2dw==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@mongodb-js/saslprep/-/saslprep-1.2.0.tgz", + "integrity": "sha512-+ywrb0AqkfaYuhHs6LxKWgqbh3I72EpEgESCw37o+9qPx9WTCkgDm2B+eMrwehGtHBWHFU4GXvnSCNiFhhausg==", + "license": "MIT", "dependencies": { "sparse-bitfield": "^3.0.3" } @@ -2922,12 +2923,14 @@ "node_modules/@types/webidl-conversions": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/@types/webidl-conversions/-/webidl-conversions-7.0.3.tgz", - "integrity": "sha512-CiJJvcRtIgzadHCYXw7dqEnMNRjhGZlYK05Mj9OyktqV8uVT8fD2BFOB7S1uwBE3Kj2Z+4UyPmFw/Ixgw/LAlA==" + "integrity": "sha512-CiJJvcRtIgzadHCYXw7dqEnMNRjhGZlYK05Mj9OyktqV8uVT8fD2BFOB7S1uwBE3Kj2Z+4UyPmFw/Ixgw/LAlA==", + "license": "MIT" }, "node_modules/@types/whatwg-url": { "version": "11.0.5", "resolved": "https://registry.npmjs.org/@types/whatwg-url/-/whatwg-url-11.0.5.tgz", "integrity": "sha512-coYR071JRaHa+xoEvvYqvnIHaVqaYrLPbsufM9BF63HkwI5Lgmy2QR8Q5K/lYDYo5AK82wOvSOS0UsLTpTG7uQ==", + "license": "MIT", "dependencies": { "@types/webidl-conversions": "*" } @@ -4144,9 +4147,10 @@ } }, "node_modules/bson": { - "version": "6.10.1", - "resolved": "https://registry.npmjs.org/bson/-/bson-6.10.1.tgz", - "integrity": "sha512-P92xmHDQjSKPLHqFxefqMxASNq/aWJMEZugpCjf+AF/pgcUpMMQCg7t7+ewko0/u8AapvF3luf/FoehddEK+sA==", + "version": "6.10.2", + "resolved": "https://registry.npmjs.org/bson/-/bson-6.10.2.tgz", + "integrity": "sha512-5afhLTjqDSA3akH56E+/2J6kTDuSIlBxyXPdQslj9hcIgOUE378xdOfZvC/9q3LifJNI6KR/juZ+d0NRNYBwXg==", + "license": "Apache-2.0", "engines": { "node": ">=16.20.1" } @@ -9900,7 +9904,8 @@ "node_modules/memory-pager": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/memory-pager/-/memory-pager-1.5.0.tgz", - "integrity": "sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==" + "integrity": "sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==", + "license": "MIT" }, "node_modules/meow": { "version": "13.2.0", @@ -10149,54 +10154,58 @@ } }, "node_modules/mongodb-connection-string-url": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/mongodb-connection-string-url/-/mongodb-connection-string-url-3.0.1.tgz", - "integrity": "sha512-XqMGwRX0Lgn05TDB4PyG2h2kKO/FfWJyCzYQbIhXUxz7ETt0I/FqHjUeqj37irJ+Dl1ZtU82uYyj14u2XsZKfg==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/mongodb-connection-string-url/-/mongodb-connection-string-url-3.0.2.tgz", + "integrity": "sha512-rMO7CGo/9BFwyZABcKAWL8UJwH/Kc2x0g72uhDWzG48URRax5TCIcJ7Rc3RZqffZzO/Gwff/jyKwCU9TN8gehA==", + "license": "Apache-2.0", "dependencies": { "@types/whatwg-url": "^11.0.2", - "whatwg-url": "^13.0.0" + "whatwg-url": "^14.1.0 || ^13.0.0" } }, "node_modules/mongodb-connection-string-url/node_modules/tr46": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-4.1.1.tgz", - "integrity": "sha512-2lv/66T7e5yNyhAAC4NaKe5nVavzuGJQVVtRYLyQ2OI8tsJ61PMLlelehb0wi2Hx6+hT/OJUWZcw8MjlSRnxvw==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-5.0.0.tgz", + "integrity": "sha512-tk2G5R2KRwBd+ZN0zaEXpmzdKyOYksXwywulIX95MBODjSzMIuQnQ3m8JxgbhnL1LeVo7lqQKsYa1O3Htl7K5g==", + "license": "MIT", "dependencies": { - "punycode": "^2.3.0" + "punycode": "^2.3.1" }, "engines": { - "node": ">=14" + "node": ">=18" } }, "node_modules/mongodb-connection-string-url/node_modules/webidl-conversions": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", + "license": "BSD-2-Clause", "engines": { "node": ">=12" } }, "node_modules/mongodb-connection-string-url/node_modules/whatwg-url": { - "version": "13.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-13.0.0.tgz", - "integrity": "sha512-9WWbymnqj57+XEuqADHrCJ2eSXzn8WXIW/YSGaZtb2WKAInQ6CHfaUUcTyyver0p8BDg5StLQq8h1vtZuwmOig==", + "version": "14.1.1", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-14.1.1.tgz", + "integrity": "sha512-mDGf9diDad/giZ/Sm9Xi2YcyzaFpbdLpJPr+E9fSkyQ7KpQD4SdFcugkRQYzhmfI4KeV4Qpnn2sKPdo+kmsgRQ==", + "license": "MIT", "dependencies": { - "tr46": "^4.1.1", + "tr46": "^5.0.0", "webidl-conversions": "^7.0.0" }, "engines": { - "node": ">=16" + "node": ">=18" } }, "node_modules/mongoose": { - "version": "8.9.6", - "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-8.9.6.tgz", - "integrity": "sha512-ipLvXwNPVuuuq5H3lnSD0lpaRH3DlCoC6emnMVJvweTwxU29uxDJWxMsNpERDQt8JMvYF1HGVuTK+Id2BlQLCA==", + "version": "8.10.0", + "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-8.10.0.tgz", + "integrity": "sha512-nLhk3Qrv6q/HpD2k1O7kbBqsq+/kmKpdv5KJ+LLhQlII3e1p/SSLoLP6jMuSiU6+iLK7zFw4T1niAk3mA3QVug==", "license": "MIT", "dependencies": { "bson": "^6.10.1", "kareem": "2.6.3", - "mongodb": "~6.12.0", + "mongodb": "~6.13.0", "mpath": "0.9.0", "mquery": "5.0.0", "ms": "2.1.3", @@ -10214,6 +10223,7 @@ "version": "6.0.2", "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "license": "MIT", "optional": true, "peer": true, "dependencies": { @@ -10227,6 +10237,7 @@ "version": "5.1.3", "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-5.1.3.tgz", "integrity": "sha512-95hVgBRgEIRQQQHIbnxBXeHbW4TqFk4ZDJW7wmVtvYar72FdhRIo1UGOLS2eRAKCPEdPBWu+M7+A33D9CdX9rA==", + "license": "Apache-2.0", "optional": true, "peer": true, "dependencies": { @@ -10243,6 +10254,7 @@ "version": "5.3.0", "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-5.3.0.tgz", "integrity": "sha512-FNTkdNEnBdlqF2oatizolQqNANMrcqJt6AAYt99B3y1aLLC8Hc5IOBb+ZnnzllodEEf6xMBp6wRcBbc16fa65w==", + "license": "Apache-2.0", "optional": true, "peer": true, "dependencies": { @@ -10257,6 +10269,7 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "license": "MIT", "optional": true, "peer": true, "dependencies": { @@ -10268,9 +10281,10 @@ } }, "node_modules/mongoose/node_modules/mongodb": { - "version": "6.12.0", - "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-6.12.0.tgz", - "integrity": "sha512-RM7AHlvYfS7jv7+BXund/kR64DryVI+cHbVAy9P61fnb1RcWZqOW1/Wj2YhqMCx+MuYhqTRGv7AwHBzmsCKBfA==", + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-6.13.0.tgz", + "integrity": "sha512-KeESYR5TEaFxOuwRqkOm3XOsMqCSkdeDMjaW5u2nuKfX7rqaofp7JQGoi7sVqQcNJTKuveNbzZtWMstb8ABP6Q==", + "license": "Apache-2.0", "dependencies": { "@mongodb-js/saslprep": "^1.1.9", "bson": "^6.10.1", @@ -12651,6 +12665,7 @@ "version": "3.0.3", "resolved": "https://registry.npmjs.org/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz", "integrity": "sha512-kvzhi7vqKTfkh0PZU+2D2PIllw2ymqJKujUcyPMd9Y75Nv4nPbGJZXNhxsgdQab2BmlDct1YnfQCguEvHr7VsQ==", + "license": "MIT", "dependencies": { "memory-pager": "^1.0.2" } diff --git a/package.json b/package.json index c5bae6369..d1ac71c14 100644 --- a/package.json +++ b/package.json @@ -116,7 +116,7 @@ "marked-smartypants-lite": "^1.0.3", "markedLegacy": "npm:marked@^0.3.19", "moment": "^2.30.1", - "mongoose": "^8.9.6", + "mongoose": "^8.10.0", "nanoid": "5.0.9", "nconf": "^0.12.1", "react": "^18.3.1", From d1c0557341795e82c0e343e91a1c370f735690f4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 11 Feb 2025 16:04:52 +0000 Subject: [PATCH 191/398] Bump @babel/core from 7.26.7 to 7.26.8 Bumps [@babel/core](https://github.com/babel/babel/tree/HEAD/packages/babel-core) from 7.26.7 to 7.26.8. - [Release notes](https://github.com/babel/babel/releases) - [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md) - [Commits](https://github.com/babel/babel/commits/v7.26.8/packages/babel-core) --- updated-dependencies: - dependency-name: "@babel/core" dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- package-lock.json | 76 ++++++++++++++++++++++++++--------------------- package.json | 2 +- 2 files changed, 43 insertions(+), 35 deletions(-) diff --git a/package-lock.json b/package-lock.json index e33618722..914b656da 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,7 +10,7 @@ "hasInstallScript": true, "license": "MIT", "dependencies": { - "@babel/core": "^7.26.7", + "@babel/core": "^7.26.8", "@babel/plugin-transform-runtime": "^7.26.8", "@babel/preset-env": "^7.26.7", "@babel/preset-react": "^7.26.3", @@ -110,21 +110,22 @@ } }, "node_modules/@babel/core": { - "version": "7.26.7", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.26.7.tgz", - "integrity": "sha512-SRijHmF0PSPgLIBYlWnG0hyeJLwXE2CgpsXaMOrtt2yp9/86ALw6oUlj9KYuZ0JN07T4eBMVIW4li/9S1j2BGA==", + "version": "7.26.8", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.26.8.tgz", + "integrity": "sha512-l+lkXCHS6tQEc5oUpK28xBOZ6+HwaH7YwoYQbLFiYb4nS2/l1tKnZEtEWkD0GuiYdvArf9qBS0XlQGXzPMsNqQ==", "license": "MIT", "dependencies": { "@ampproject/remapping": "^2.2.0", "@babel/code-frame": "^7.26.2", - "@babel/generator": "^7.26.5", + "@babel/generator": "^7.26.8", "@babel/helper-compilation-targets": "^7.26.5", "@babel/helper-module-transforms": "^7.26.0", "@babel/helpers": "^7.26.7", - "@babel/parser": "^7.26.7", - "@babel/template": "^7.25.9", - "@babel/traverse": "^7.26.7", - "@babel/types": "^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", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", @@ -140,13 +141,13 @@ } }, "node_modules/@babel/generator": { - "version": "7.26.5", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.26.5.tgz", - "integrity": "sha512-2caSP6fN9I7HOe6nqhtft7V4g7/V/gfDsC3Ag4W7kEzzvRGKqiv0pu0HogPiZ3KaVSoNDhUws6IJjDjpfmYIXw==", + "version": "7.26.8", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.26.8.tgz", + "integrity": "sha512-ef383X5++iZHWAXX0SXQR6ZyQhw/0KtTkrTz61WXRhFM6dhpHulO/RJz79L8S6ugZHJkOOkUrUdxgdF2YiPFnA==", "license": "MIT", "dependencies": { - "@babel/parser": "^7.26.5", - "@babel/types": "^7.26.5", + "@babel/parser": "^7.26.8", + "@babel/types": "^7.26.8", "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.25", "jsesc": "^3.0.2" @@ -389,12 +390,12 @@ } }, "node_modules/@babel/parser": { - "version": "7.26.7", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.26.7.tgz", - "integrity": "sha512-kEvgGGgEjRUutvdVvZhbn/BxVt+5VSpwXz1j3WYXQbXDo8KzFOPNG2GQbdAiNq8g6wn1yKk7C/qrke03a84V+w==", + "version": "7.26.8", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.26.8.tgz", + "integrity": "sha512-TZIQ25pkSoaKEYYaHbbxkfL36GNsQ6iFiBbeuzAkLnXayKR1yP1zFe+NxuZWWsUyvt8icPU9CCq0sgWGXR1GEw==", "license": "MIT", "dependencies": { - "@babel/types": "^7.26.7" + "@babel/types": "^7.26.8" }, "bin": { "parser": "bin/babel-parser.js" @@ -1683,29 +1684,30 @@ } }, "node_modules/@babel/template": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.25.9.tgz", - "integrity": "sha512-9DGttpmPvIxBb/2uwpVo3dqJ+O6RooAFOS+lB+xDqoE2PVCE8nfoHMdZLpfCQRLwvohzXISPZcgxt80xLfsuwg==", + "version": "7.26.8", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.26.8.tgz", + "integrity": "sha512-iNKaX3ZebKIsCvJ+0jd6embf+Aulaa3vNBqZ41kM7iTWjx5qzWKXGHiJUW3+nTpQ18SG11hdF8OAzKrpXkb96Q==", + "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.25.9", - "@babel/parser": "^7.25.9", - "@babel/types": "^7.25.9" + "@babel/code-frame": "^7.26.2", + "@babel/parser": "^7.26.8", + "@babel/types": "^7.26.8" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/traverse": { - "version": "7.26.7", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.26.7.tgz", - "integrity": "sha512-1x1sgeyRLC3r5fQOM0/xtQKsYjyxmFjaOrLJNtZ81inNjyJHGIolTULPiSc/2qe1/qfpFLisLQYFnnZl7QoedA==", + "version": "7.26.8", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.26.8.tgz", + "integrity": "sha512-nic9tRkjYH0oB2dzr/JoGIm+4Q6SuYeLEiIiZDwBscRMYFJ+tMAz98fuel9ZnbXViA2I0HVSSRRK8DW5fjXStA==", "license": "MIT", "dependencies": { "@babel/code-frame": "^7.26.2", - "@babel/generator": "^7.26.5", - "@babel/parser": "^7.26.7", - "@babel/template": "^7.25.9", - "@babel/types": "^7.26.7", + "@babel/generator": "^7.26.8", + "@babel/parser": "^7.26.8", + "@babel/template": "^7.26.8", + "@babel/types": "^7.26.8", "debug": "^4.3.1", "globals": "^11.1.0" }, @@ -1723,9 +1725,9 @@ } }, "node_modules/@babel/types": { - "version": "7.26.7", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.26.7.tgz", - "integrity": "sha512-t8kDRGrKXyp6+tjUh7hw2RLyclsW4TRoRvRHtSyAX9Bb5ldlFh+90YAYY6awRXrlB4G5G2izNeGySpATlFzmOg==", + "version": "7.26.8", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.26.8.tgz", + "integrity": "sha512-eUuWapzEGWFEpHFxgEaBG8e3n6S8L3MSu0oda755rOfabWPnh0Our1AozNFVUxGFIhbKgd1ksprsoDGMinTOTA==", "license": "MIT", "dependencies": { "@babel/helper-string-parser": "^7.25.9", @@ -2854,6 +2856,12 @@ "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", diff --git a/package.json b/package.json index a27f46524..69d651752 100644 --- a/package.json +++ b/package.json @@ -85,7 +85,7 @@ ] }, "dependencies": { - "@babel/core": "^7.26.7", + "@babel/core": "^7.26.8", "@babel/plugin-transform-runtime": "^7.26.8", "@babel/preset-env": "^7.26.7", "@babel/preset-react": "^7.26.3", From 45d188fea1ddd079c92d4436e7729c0244d3bc7a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 11 Feb 2025 16:19:50 +0000 Subject: [PATCH 192/398] Bump @babel/preset-env from 7.26.7 to 7.26.8 Bumps [@babel/preset-env](https://github.com/babel/babel/tree/HEAD/packages/babel-preset-env) from 7.26.7 to 7.26.8. - [Release notes](https://github.com/babel/babel/releases) - [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md) - [Commits](https://github.com/babel/babel/commits/v7.26.8/packages/babel-preset-env) --- updated-dependencies: - dependency-name: "@babel/preset-env" dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- package-lock.json | 125 ++++++++++++++++++++++++++-------------------- package.json | 2 +- 2 files changed, 73 insertions(+), 54 deletions(-) diff --git a/package-lock.json b/package-lock.json index 914b656da..bd3f71491 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,7 +12,7 @@ "dependencies": { "@babel/core": "^7.26.8", "@babel/plugin-transform-runtime": "^7.26.8", - "@babel/preset-env": "^7.26.7", + "@babel/preset-env": "^7.26.8", "@babel/preset-react": "^7.26.3", "@googleapis/drive": "^8.14.0", "body-parser": "^1.20.2", @@ -101,9 +101,9 @@ } }, "node_modules/@babel/compat-data": { - "version": "7.26.5", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.26.5.tgz", - "integrity": "sha512-XvcZi1KWf88RVbF9wn8MN6tYFloU5qX8KjuF3E1PVBmJ9eypXfs4GRiJwLuTZL0iSnJUKn1BFPa5BPZZJyFzPg==", + "version": "7.26.8", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.26.8.tgz", + "integrity": "sha512-oH5UPLMWR3L2wEFLnFJ1TZXqHufiTKAiLfqw5zkhS4dKXLJ10yVztfil/twG8EDTA4F/tvVNw9nOl4ZMslB8rQ==", "license": "MIT", "engines": { "node": ">=6.9.0" @@ -220,9 +220,9 @@ } }, "node_modules/@babel/helper-define-polyfill-provider": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.2.tgz", - "integrity": "sha512-LV76g+C502biUK6AyZ3LK10vDpDyCzZnhZFXkH1L75zHPj68+qc8Zfpx2th+gzwA2MzyK+1g/3EPl62yFnVttQ==", + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.3.tgz", + "integrity": "sha512-HK7Bi+Hj6H+VTHA3ZvBis7V/6hu9QuTrnMXNybfUf2iiuU/N97I8VjB+KbhFF8Rld/Lx5MzoCwPCpPjfK+n8Cg==", "license": "MIT", "dependencies": { "@babel/helper-compilation-targets": "^7.22.6", @@ -739,13 +739,14 @@ } }, "node_modules/@babel/plugin-transform-async-generator-functions": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.25.9.tgz", - "integrity": "sha512-RXV6QAzTBbhDMO9fWwOmwwTuYaiPbggWQ9INdZqAYeSHyG7FzQ+nOZaUUjNwKv9pV3aE4WFqFm1Hnbci5tBCAw==", + "version": "7.26.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.26.8.tgz", + "integrity": "sha512-He9Ej2X7tNf2zdKMAGOsmg2MrFc+hfoAhd3po4cWfo/NWjzEAKa0oQruj1ROVUdl0e6fb6/kE/G3SSxE0lRJOg==", + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-plugin-utils": "^7.26.5", "@babel/helper-remap-async-to-generator": "^7.25.9", - "@babel/traverse": "^7.25.9" + "@babel/traverse": "^7.26.8" }, "engines": { "node": ">=6.9.0" @@ -1468,11 +1469,12 @@ } }, "node_modules/@babel/plugin-transform-template-literals": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.25.9.tgz", - "integrity": "sha512-o97AE4syN71M/lxrCtQByzphAdlYluKPDBzDVzMmfCobUjjhAryZV0AIpRPrxN0eAkxXO6ZLEScmt+PNhj2OTw==", + "version": "7.26.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.26.8.tgz", + "integrity": "sha512-OmGDL5/J0CJPJZTHZbi2XpO0tyT2Ia7fzpW5GURwdtp2X3fMmN8au/ej6peC/T33/+CRiIpA8Krse8hFGVmT5Q==", + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-plugin-utils": "^7.26.5" }, "engines": { "node": ">=6.9.0" @@ -1556,12 +1558,12 @@ } }, "node_modules/@babel/preset-env": { - "version": "7.26.7", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.26.7.tgz", - "integrity": "sha512-Ycg2tnXwixaXOVb29rana8HNPgLVBof8qqtNQ9LE22IoyZboQbGSxI6ZySMdW3K5nAe6gu35IaJefUJflhUFTQ==", + "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==", "license": "MIT", "dependencies": { - "@babel/compat-data": "^7.26.5", + "@babel/compat-data": "^7.26.8", "@babel/helper-compilation-targets": "^7.26.5", "@babel/helper-plugin-utils": "^7.26.5", "@babel/helper-validator-option": "^7.25.9", @@ -1575,7 +1577,7 @@ "@babel/plugin-syntax-import-attributes": "^7.26.0", "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", "@babel/plugin-transform-arrow-functions": "^7.25.9", - "@babel/plugin-transform-async-generator-functions": "^7.25.9", + "@babel/plugin-transform-async-generator-functions": "^7.26.8", "@babel/plugin-transform-async-to-generator": "^7.25.9", "@babel/plugin-transform-block-scoped-functions": "^7.26.5", "@babel/plugin-transform-block-scoping": "^7.25.9", @@ -1618,7 +1620,7 @@ "@babel/plugin-transform-shorthand-properties": "^7.25.9", "@babel/plugin-transform-spread": "^7.25.9", "@babel/plugin-transform-sticky-regex": "^7.25.9", - "@babel/plugin-transform-template-literals": "^7.25.9", + "@babel/plugin-transform-template-literals": "^7.26.8", "@babel/plugin-transform-typeof-symbol": "^7.26.7", "@babel/plugin-transform-unicode-escapes": "^7.25.9", "@babel/plugin-transform-unicode-property-regex": "^7.25.9", @@ -1626,9 +1628,9 @@ "@babel/plugin-transform-unicode-sets-regex": "^7.25.9", "@babel/preset-modules": "0.1.6-no-external-plugins", "babel-plugin-polyfill-corejs2": "^0.4.10", - "babel-plugin-polyfill-corejs3": "^0.10.6", + "babel-plugin-polyfill-corejs3": "^0.11.0", "babel-plugin-polyfill-regenerator": "^0.6.1", - "core-js-compat": "^3.38.1", + "core-js-compat": "^3.40.0", "semver": "^6.3.1" }, "engines": { @@ -1638,6 +1640,19 @@ "@babel/core": "^7.0.0-0" } }, + "node_modules/@babel/preset-env/node_modules/babel-plugin-polyfill-corejs3": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.11.1.tgz", + "integrity": "sha512-yGCqvBT4rwMczo28xkH/noxJ6MZ4nJfkVYdoDaC/utLtWrXxv27HVrzAeSbqR8SxDsp46n0YF47EbHoixy6rXQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.6.3", + "core-js-compat": "^3.40.0" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, "node_modules/@babel/preset-modules": { "version": "0.1.6-no-external-plugins", "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.6-no-external-plugins.tgz", @@ -4114,9 +4129,9 @@ } }, "node_modules/browserslist": { - "version": "4.24.0", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.0.tgz", - "integrity": "sha512-Rmb62sR1Zpjql25eSanFGEhAxcFwfA1K0GuQcLoaJBAcENegrQut3hYdhXFF1obQfiDyqIW/cLM5HSJ/9k884A==", + "version": "4.24.4", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.4.tgz", + "integrity": "sha512-KDi1Ny1gSePi1vm0q4oxSF8b4DR44GF4BbmS2YdhPLOEqd8pDviZOGH/GsmRwoWJ2+5Lr085X7naowMwKHDG1A==", "funding": [ { "type": "opencollective", @@ -4131,11 +4146,12 @@ "url": "https://github.com/sponsors/ai" } ], + "license": "MIT", "dependencies": { - "caniuse-lite": "^1.0.30001663", - "electron-to-chromium": "^1.5.28", - "node-releases": "^2.0.18", - "update-browserslist-db": "^1.1.0" + "caniuse-lite": "^1.0.30001688", + "electron-to-chromium": "^1.5.73", + "node-releases": "^2.0.19", + "update-browserslist-db": "^1.1.1" }, "bin": { "browserslist": "cli.js" @@ -4316,9 +4332,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001667", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001667.tgz", - "integrity": "sha512-7LTwJjcRkzKFmtqGsibMeuXmvFDfZq/nzIjnmgCGzKKRVzjD72selLDK1oPF/Oxzmt4fNcPvTDvGqSDG4tCALw==", + "version": "1.0.30001699", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001699.tgz", + "integrity": "sha512-b+uH5BakXZ9Do9iK+CkDmctUSEqZl+SP056vc5usa0PL+ev5OHw003rZXcnjNDv3L8P5j6rwT6C0BPKSikW08w==", "funding": [ { "type": "opencollective", @@ -4332,7 +4348,8 @@ "type": "github", "url": "https://github.com/sponsors/ai" } - ] + ], + "license": "CC-BY-4.0" }, "node_modules/char-regex": { "version": "1.0.2", @@ -4680,11 +4697,12 @@ } }, "node_modules/core-js-compat": { - "version": "3.38.1", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.38.1.tgz", - "integrity": "sha512-JRH6gfXxGmrzF3tZ57lFx97YARxCXPaMzPo6jELZhv88pBH5VXpQ+y0znKGlFnzuaihqhLbefxSJxWJMPtfDzw==", + "version": "3.40.0", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.40.0.tgz", + "integrity": "sha512-0XEDpr5y5mijvw8Lbc6E5AkjrHfp7eEoPlu36SWeAbcL8fn1G1ANe8DBlo2XoNN89oVpxWwOjYIPVzR4ZvsKCQ==", + "license": "MIT", "dependencies": { - "browserslist": "^4.23.3" + "browserslist": "^4.24.3" }, "funding": { "type": "opencollective", @@ -5373,9 +5391,10 @@ "license": "MIT" }, "node_modules/electron-to-chromium": { - "version": "1.5.32", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.32.tgz", - "integrity": "sha512-M+7ph0VGBQqqpTT2YrabjNKSQ2fEl9PVx6AK3N558gDH9NO8O6XN9SXXFWRo9u9PbEg/bWq+tjXQr+eXmxubCw==" + "version": "1.5.97", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.97.tgz", + "integrity": "sha512-HKLtaH02augM7ZOdYRuO19rWDeY+QSJ1VxnXFa/XDFLf07HvM90pALIJFgrO+UVaajI3+aJMMpojoUTLZyQ7JQ==", + "license": "ISC" }, "node_modules/elliptic": { "version": "6.6.0", @@ -5631,9 +5650,9 @@ } }, "node_modules/escalade": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", - "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", "license": "MIT", "engines": { "node": ">=6" @@ -10580,9 +10599,9 @@ "license": "MIT" }, "node_modules/node-releases": { - "version": "2.0.18", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.18.tgz", - "integrity": "sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==", + "version": "2.0.19", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.19.tgz", + "integrity": "sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==", "license": "MIT" }, "node_modules/nodemon": { @@ -14082,9 +14101,9 @@ } }, "node_modules/update-browserslist-db": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.0.tgz", - "integrity": "sha512-EdRAaAyk2cUE1wOf2DkEhzxqOQvFOoRJFNS6NeyJ01Gp2beMRpBAINjM2iDXE3KCuKhwnvHIQCJm6ThL2Z+HzQ==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.2.tgz", + "integrity": "sha512-PPypAm5qvlD7XMZC3BujecnaOxwhrtoFR+Dqkk5Aa/6DssiH0ibKoketaj9w8LP7Bont1rYeoV5plxD7RTEPRg==", "funding": [ { "type": "opencollective", @@ -14101,8 +14120,8 @@ ], "license": "MIT", "dependencies": { - "escalade": "^3.1.2", - "picocolors": "^1.0.1" + "escalade": "^3.2.0", + "picocolors": "^1.1.1" }, "bin": { "update-browserslist-db": "cli.js" diff --git a/package.json b/package.json index 69d651752..342af4d6e 100644 --- a/package.json +++ b/package.json @@ -87,7 +87,7 @@ "dependencies": { "@babel/core": "^7.26.8", "@babel/plugin-transform-runtime": "^7.26.8", - "@babel/preset-env": "^7.26.7", + "@babel/preset-env": "^7.26.8", "@babel/preset-react": "^7.26.3", "@googleapis/drive": "^8.14.0", "body-parser": "^1.20.2", From e89920bd1e0a3949f56b9218dde87eb9fdc703b2 Mon Sep 17 00:00:00 2001 From: "G.Ambatte" Date: Wed, 12 Feb 2025 07:41:53 +1300 Subject: [PATCH 193/398] Remove unneeded `.then()` Co-authored-by: Trevor Buckner --- client/admin/authorUtils/authorLookup/authorLookup.jsx | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/client/admin/authorUtils/authorLookup/authorLookup.jsx b/client/admin/authorUtils/authorLookup/authorLookup.jsx index 50226d93d..b5b7735e7 100644 --- a/client/admin/authorUtils/authorLookup/authorLookup.jsx +++ b/client/admin/authorUtils/authorLookup/authorLookup.jsx @@ -14,12 +14,9 @@ const authorLookup = ()=>{ setSearching(true); setResults([]); - await request.get(`/admin/user/list/${author}`) - .then((brews)=>{ - setResults(brews.body); - setSearching(false); - }); - }; + const brews = await request.get(`/admin/user/list/${author}`); + setResults(brews.body); + setSearching(false); const renderResults = ()=>{ if(results.length == 0) return <> From bbc601cf47d8d7bd1e52944709a9fb229dc099e5 Mon Sep 17 00:00:00 2001 From: "G.Ambatte" Date: Wed, 12 Feb 2025 07:42:35 +1300 Subject: [PATCH 194/398] Simplify sort algorithm Co-authored-by: Trevor Buckner --- client/admin/authorUtils/authorLookup/authorLookup.jsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/client/admin/authorUtils/authorLookup/authorLookup.jsx b/client/admin/authorUtils/authorLookup/authorLookup.jsx index b5b7735e7..8cbe31176 100644 --- a/client/admin/authorUtils/authorLookup/authorLookup.jsx +++ b/client/admin/authorUtils/authorLookup/authorLookup.jsx @@ -40,8 +40,7 @@ const authorLookup = ()=>{ {results .sort((a, b)=>{ // Sort brews from most recently updated if(a.updatedAt > b.updatedAt) return -1; - if(a.updatedAt < b.updatedAt) return 1; - return 0; + return 1; }) .map((brew, idx)=>{ return From d48d5260a4f5b044befa03e830921a37efc89710 Mon Sep 17 00:00:00 2001 From: "G.Ambatte" Date: Wed, 12 Feb 2025 07:54:15 +1300 Subject: [PATCH 195/398] Fix missing } --- client/admin/authorUtils/authorLookup/authorLookup.jsx | 1 + 1 file changed, 1 insertion(+) diff --git a/client/admin/authorUtils/authorLookup/authorLookup.jsx b/client/admin/authorUtils/authorLookup/authorLookup.jsx index 8cbe31176..d4d117147 100644 --- a/client/admin/authorUtils/authorLookup/authorLookup.jsx +++ b/client/admin/authorUtils/authorLookup/authorLookup.jsx @@ -17,6 +17,7 @@ const authorLookup = ()=>{ const brews = await request.get(`/admin/user/list/${author}`); setResults(brews.body); setSearching(false); + }; const renderResults = ()=>{ if(results.length == 0) return <> From 64b7527ad0fcd3fa2b5bc18d1bd577246f505b68 Mon Sep 17 00:00:00 2001 From: "G.Ambatte" Date: Wed, 12 Feb 2025 08:01:07 +1300 Subject: [PATCH 196/398] Convert space indentation to tabs --- .../authorUtils/authorLookup/authorLookup.jsx | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/client/admin/authorUtils/authorLookup/authorLookup.jsx b/client/admin/authorUtils/authorLookup/authorLookup.jsx index d4d117147..a239f901f 100644 --- a/client/admin/authorUtils/authorLookup/authorLookup.jsx +++ b/client/admin/authorUtils/authorLookup/authorLookup.jsx @@ -39,19 +39,19 @@ const authorLookup = ()=>{ {results - .sort((a, b)=>{ // Sort brews from most recently updated - if(a.updatedAt > b.updatedAt) return -1; - return 1; - }) - .map((brew, idx)=>{ - return - {brew.title} - {brew.shareId} - {brew.editId} - {brew.updatedAt} - {brew.googleId ? 'Google' : 'Homebrewery'} - ; - })} + .sort((a, b)=>{ // Sort brews from most recently updated + if(a.updatedAt > b.updatedAt) return -1; + return 1; + }) + .map((brew, idx)=>{ + return + {brew.title} + {brew.shareId} + {brew.editId} + {brew.updatedAt} + {brew.googleId ? 'Google' : 'Homebrewery'} + ; + })} ; @@ -70,7 +70,7 @@ const authorLookup = ()=>{

    Author Lookup

    diff --git a/client/homebrew/pages/basePages/listPage/brewItem/brewItem.jsx b/client/homebrew/pages/basePages/listPage/brewItem/brewItem.jsx index ef98e8425..ef309a613 100644 --- a/client/homebrew/pages/basePages/listPage/brewItem/brewItem.jsx +++ b/client/homebrew/pages/basePages/listPage/brewItem/brewItem.jsx @@ -30,11 +30,11 @@ const BrewItem = ({ } request.delete(`/api/${brew.googleId ?? ''}${brew.editId}`).send().end((err, res)=>{ - if (err) reportError(err); else window.location.reload(); - }); + if(err) reportError(err); else window.location.reload(); + }); }, [brew, reportError]); - const updateFilter = useCallback((type, term)=> updateListFilter(type, term), [updateListFilter]); + const updateFilter = useCallback((type, term)=>updateListFilter(type, term), [updateListFilter]); const renderDeleteBrewLink = ()=>{ if(!brew.editId) return null; diff --git a/client/homebrew/pages/homePage/homePage.jsx b/client/homebrew/pages/homePage/homePage.jsx index 00d0c801d..b9c1b7371 100644 --- a/client/homebrew/pages/homePage/homePage.jsx +++ b/client/homebrew/pages/homePage/homePage.jsx @@ -100,32 +100,32 @@ const HomePage = createClass({ return
    {this.renderNavbar()} -
    - - - - +
    + + + +
    Save current diff --git a/client/homebrew/pages/newPage/newPage.jsx b/client/homebrew/pages/newPage/newPage.jsx index 1d5887b8a..7aaeb3fd3 100644 --- a/client/homebrew/pages/newPage/newPage.jsx +++ b/client/homebrew/pages/newPage/newPage.jsx @@ -223,39 +223,39 @@ const NewPage = createClass({ render : function(){ return
    {this.renderNavbar()} -
    - - - - +
    + + + +
    ; } diff --git a/shared/naturalcrit/nav/nav.jsx b/shared/naturalcrit/nav/nav.jsx index d9b403239..50dff4c33 100644 --- a/shared/naturalcrit/nav/nav.jsx +++ b/shared/naturalcrit/nav/nav.jsx @@ -12,8 +12,8 @@ const Nav = { displayName : 'Nav.base', render : function(){ return ; + {this.props.children} + ; } }), logo : function(){ diff --git a/shared/naturalcrit/splitPane/splitPane.jsx b/shared/naturalcrit/splitPane/splitPane.jsx index 1500c759f..4c77d81a5 100644 --- a/shared/naturalcrit/splitPane/splitPane.jsx +++ b/shared/naturalcrit/splitPane/splitPane.jsx @@ -29,8 +29,8 @@ const SplitPane = (props)=>{ const limitPosition = (x, min = 1, max = window.innerWidth - 13)=>Math.round(Math.min(max, Math.max(min, x))); //when resizing, the divider should grow smaller if less space is given, then grow back if the space is restored, to the original position - const handleResize = () =>setDividerPos(limitPosition(window.localStorage.getItem(storageKey), 0.1 * (window.innerWidth - 13), 0.9 * (window.innerWidth - 13))); - + const handleResize = ()=>setDividerPos(limitPosition(window.localStorage.getItem(storageKey), 0.1 * (window.innerWidth - 13), 0.9 * (window.innerWidth - 13))); + const handleUp =(e)=>{ e.preventDefault(); if(isDragging) { From 962d98543ebd9e2dfb447851e07dd0a8934bd2bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Losada=20Hern=C3=A1ndez?= Date: Wed, 19 Mar 2025 10:56:16 +0100 Subject: [PATCH 312/398] initial fix --- client/homebrew/editor/editor.jsx | 17 +---------------- client/homebrew/editor/editor.less | 13 +++++++++++++ 2 files changed, 14 insertions(+), 16 deletions(-) diff --git a/client/homebrew/editor/editor.jsx b/client/homebrew/editor/editor.jsx index 9e6178f3e..d00a126e3 100644 --- a/client/homebrew/editor/editor.jsx +++ b/client/homebrew/editor/editor.jsx @@ -13,7 +13,6 @@ const MetadataEditor = require('./metadataEditor/metadataEditor.jsx'); const EDITOR_THEME_KEY = 'HOMEBREWERY-EDITOR-THEME'; 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! */ @@ -65,9 +64,7 @@ const Editor = createClass({ componentDidMount : function() { - this.updateEditorSize(); this.highlightCustomMarkdown(); - window.addEventListener('resize', this.updateEditorSize); document.getElementById('BrewRenderer').addEventListener('keydown', this.handleControlKeys); document.addEventListener('keydown', this.handleControlKeys); @@ -82,10 +79,6 @@ const Editor = createClass({ } }, - componentWillUnmount : function() { - window.removeEventListener('resize', this.updateEditorSize); - }, - componentDidUpdate : function(prevProps, prevState, snapshot) { this.highlightCustomMarkdown(); @@ -118,13 +111,6 @@ const Editor = createClass({ } }, - updateEditorSize : function() { - if(this.codeEditor.current) { - let paneHeight = this.editor.current.parentNode.clientHeight; - paneHeight -= SNIPPETBAR_HEIGHT; - this.codeEditor.current.codeMirror.setSize(null, paneHeight); - } - }, updateCurrentCursorPage : function(cursor) { const lines = this.props.brew.text.split('\n').slice(1, cursor.line + 1); @@ -150,8 +136,7 @@ const Editor = createClass({ view : newView }, ()=>{ this.codeEditor.current?.codeMirror.focus(); - this.updateEditorSize(); - }); //TODO: not sure if updateeditorsize needed + }); }, highlightCustomMarkdown : function(){ diff --git a/client/homebrew/editor/editor.less b/client/homebrew/editor/editor.less index 5511bee6e..974403447 100644 --- a/client/homebrew/editor/editor.less +++ b/client/homebrew/editor/editor.less @@ -1,11 +1,16 @@ @import 'themes/codeMirror/customEditorStyles.less'; .editor { + height:100%; position : relative; width : 100%; container : editor / inline-size; .codeEditor { height : 100%; + + .CodeMirror { + height:100%; + } .pageLine { background : #33333328; border-top : #333399 solid 1px; @@ -104,3 +109,11 @@ } } + + +@container editor (width < 553px) { + + .editor .codeEditor .CodeMirror { + height:calc(100% - 51px) ; + } +} \ No newline at end of file From 07ff9a114ed8121d47676d300f42761f8230a7a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Losada=20Hern=C3=A1ndez?= Date: Wed, 19 Mar 2025 13:26:58 +0100 Subject: [PATCH 313/398] lint --- client/homebrew/editor/editor.less | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/client/homebrew/editor/editor.less b/client/homebrew/editor/editor.less index 974403447..b9acaa8c0 100644 --- a/client/homebrew/editor/editor.less +++ b/client/homebrew/editor/editor.less @@ -1,16 +1,14 @@ @import 'themes/codeMirror/customEditorStyles.less'; .editor { - height:100%; position : relative; width : 100%; + height : 100%; container : editor / inline-size; .codeEditor { height : 100%; - .CodeMirror { - height:100%; - } + .CodeMirror { height : 100%; } .pageLine { background : #33333328; border-top : #333399 solid 1px; @@ -113,7 +111,5 @@ @container editor (width < 553px) { - .editor .codeEditor .CodeMirror { - height:calc(100% - 51px) ; - } + .editor .codeEditor .CodeMirror { height : calc(100% - 51px) ; } } \ No newline at end of file From d2507fe99f1dad25ab2b18048f2a03d3883cc8bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Losada=20Hern=C3=A1ndez?= Date: Wed, 19 Mar 2025 13:29:16 +0100 Subject: [PATCH 314/398] remove empty lines --- client/homebrew/editor/editor.jsx | 1 - client/homebrew/editor/editor.less | 6 +----- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/client/homebrew/editor/editor.jsx b/client/homebrew/editor/editor.jsx index d00a126e3..a58980377 100644 --- a/client/homebrew/editor/editor.jsx +++ b/client/homebrew/editor/editor.jsx @@ -111,7 +111,6 @@ const Editor = createClass({ } }, - updateCurrentCursorPage : function(cursor) { const lines = this.props.brew.text.split('\n').slice(1, cursor.line + 1); const pageRegex = this.props.brew.renderer == 'V3' ? PAGEBREAK_REGEX_V3 : /\\page/; diff --git a/client/homebrew/editor/editor.less b/client/homebrew/editor/editor.less index b9acaa8c0..79859f5db 100644 --- a/client/homebrew/editor/editor.less +++ b/client/homebrew/editor/editor.less @@ -4,10 +4,8 @@ width : 100%; height : 100%; container : editor / inline-size; - .codeEditor { height : 100%; - .CodeMirror { height : 100%; } .pageLine { background : #33333328; @@ -108,8 +106,6 @@ } - @container editor (width < 553px) { - - .editor .codeEditor .CodeMirror { height : calc(100% - 51px) ; } + .editor .codeEditor .CodeMirror { height : calc(100% - 51px);} } \ No newline at end of file From 48285e67383bf6841c22ac930600e95b493677e6 Mon Sep 17 00:00:00 2001 From: David Bolack Date: Wed, 19 Mar 2025 17:45:47 -0500 Subject: [PATCH 315/398] Add validation to ensure \page mustaches have return valid contents from the lexar --- client/homebrew/brewRenderer/brewRenderer.jsx | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/client/homebrew/brewRenderer/brewRenderer.jsx b/client/homebrew/brewRenderer/brewRenderer.jsx index 21c0608bd..f666d9ba9 100644 --- a/client/homebrew/brewRenderer/brewRenderer.jsx +++ b/client/homebrew/brewRenderer/brewRenderer.jsx @@ -186,12 +186,14 @@ const BrewRenderer = (props)=>{ } else { if(pageText.startsWith('\\page')) { const firstLineTokens = Markdown.marked.lexer(pageText.split('\n', 1)[0])[0].tokens; - const injectedTags = firstLineTokens.find((obj)=>obj.injectedTags !== undefined)?.injectedTags; - 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; + if(firstLineTokens) { // Catch invalid/empty mustache blocks + 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 } From 481219402c34aa6b49235a2174dad968fa49fe1a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 21 Mar 2025 03:29:48 +0000 Subject: [PATCH 316/398] Bump supertest from 7.0.0 to 7.1.0 Bumps [supertest](https://github.com/ladjs/supertest) from 7.0.0 to 7.1.0. - [Release notes](https://github.com/ladjs/supertest/releases) - [Commits](https://github.com/ladjs/supertest/compare/v7.0.0...v7.1.0) --- updated-dependencies: - dependency-name: supertest dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- package-lock.json | 8 ++++---- package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index 69cc1cade..9220e4e12 100644 --- a/package-lock.json +++ b/package-lock.json @@ -66,7 +66,7 @@ "stylelint": "^16.16.0", "stylelint-config-recess-order": "^6.0.0", "stylelint-config-recommended": "^15.0.0", - "supertest": "^7.0.0" + "supertest": "^7.1.0" }, "engines": { "node": "^20.18.x", @@ -13426,9 +13426,9 @@ } }, "node_modules/supertest": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/supertest/-/supertest-7.0.0.tgz", - "integrity": "sha512-qlsr7fIC0lSddmA3tzojvzubYxvlGtzumcdHgPwbFWMISQwL22MhM2Y3LNt+6w9Yyx7559VW5ab70dgphm8qQA==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/supertest/-/supertest-7.1.0.tgz", + "integrity": "sha512-5QeSO8hSrKghtcWEoPiO036fxH0Ii2wVQfFZSP0oqQhmjk8bOLhDFXr4JrvaFmPuEWUoq4znY3uSi8UzLKxGqw==", "dev": true, "license": "MIT", "dependencies": { diff --git a/package.json b/package.json index 96528b786..7f7b10bf5 100644 --- a/package.json +++ b/package.json @@ -140,6 +140,6 @@ "stylelint": "^16.16.0", "stylelint-config-recess-order": "^6.0.0", "stylelint-config-recommended": "^15.0.0", - "supertest": "^7.0.0" + "supertest": "^7.1.0" } } From cb618914506f55bcf4523657227bad294cdd1031 Mon Sep 17 00:00:00 2001 From: "G.Ambatte" Date: Sat, 22 Mar 2025 12:31:38 +1300 Subject: [PATCH 317/398] Change local regex testing --- server/app.js | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/server/app.js b/server/app.js index 079f5e03c..6bd0c7c9a 100644 --- a/server/app.js +++ b/server/app.js @@ -69,14 +69,11 @@ const corsOptions = { 'https://homebrewery-stage.herokuapp.com', ]; - if(isLocalEnvironment) { - const localNetworkRegex = /^http:\/\/(localhost|127\.0\.0\.1|10\.\d+\.\d+\.\d+|192\.168\.\d+\.\d+|172\.(1[6-9]|2\d|3[0-1])\.\d+\.\d+):\d+$/; - allowedOrigins.push(localNetworkRegex); - } + const localNetworkRegex = /^http:\/\/(localhost|127\.0\.0\.1|10\.\d+\.\d+\.\d+|192\.168\.\d+\.\d+|172\.(1[6-9]|2\d|3[0-1])\.\d+\.\d+):\d+$/; const herokuRegex = /^https:\/\/(?:homebrewery-pr-\d+\.herokuapp\.com|naturalcrit-pr-\d+\.herokuapp\.com)$/; // Matches any Heroku app - if(!origin || allowedOrigins.includes(origin) || herokuRegex.test(origin)) { + if(!origin || allowedOrigins.includes(origin) || herokuRegex.test(origin) || (isLocalEnvironment && localNetworkRegex.test(origin))) { callback(null, true); } else { console.log(origin, 'not allowed'); From 0fc7571c35940bd5252a0f190f2a5767672a46e9 Mon Sep 17 00:00:00 2001 From: David Bolack Date: Sun, 23 Mar 2025 20:41:14 -0500 Subject: [PATCH 318/398] Somehow this change did not get commited or pushed. This swaps the if block for an optional chaining --- client/homebrew/brewRenderer/brewRenderer.jsx | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/client/homebrew/brewRenderer/brewRenderer.jsx b/client/homebrew/brewRenderer/brewRenderer.jsx index f666d9ba9..c83a2029b 100644 --- a/client/homebrew/brewRenderer/brewRenderer.jsx +++ b/client/homebrew/brewRenderer/brewRenderer.jsx @@ -186,14 +186,12 @@ const BrewRenderer = (props)=>{ } else { if(pageText.startsWith('\\page')) { const firstLineTokens = Markdown.marked.lexer(pageText.split('\n', 1)[0])[0].tokens; - if(firstLineTokens) { // Catch invalid/empty mustache blocks - 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; - } + 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 } From 712ee111d4480121eff300b09b4ab8522135a9da Mon Sep 17 00:00:00 2001 From: David Bolack Date: Sun, 23 Mar 2025 20:48:30 -0500 Subject: [PATCH 319/398] Move Dropcap settings back to PHB --- themes/V3/5ePHB/snippets.js | 30 ++++++++++++++++++++++++++++++ themes/V3/Blank/snippets.js | 25 +------------------------ 2 files changed, 31 insertions(+), 24 deletions(-) diff --git a/themes/V3/5ePHB/snippets.js b/themes/V3/5ePHB/snippets.js index f5c8120c1..27ea62bea 100644 --- a/themes/V3/5ePHB/snippets.js +++ b/themes/V3/5ePHB/snippets.js @@ -12,6 +12,36 @@ const dedent = require('dedent-tabs').default; module.exports = [ + { + groupName : 'Style Editor', + icon : 'fas fa-pencil-alt', + view : 'style', + snippets : [ + { + name : 'Remove Drop Cap', + icon : 'fas fa-remove-format', + gen : dedent`/* Removes Drop Caps */ + .page h1+p:first-letter { + all: unset; + }\n\n + /* Removes Small-Caps in first line */ + .page h1+p:first-line { + all: unset; + }` + }, + { + name : 'Tweak Drop Cap', + icon : 'fas fa-sliders-h', + gen : dedent`/* Drop Cap settings */ + .page h1 + p::first-letter { + font-family: SolberaImitationRemake; + font-size: 3.5cm; + background-image: linear-gradient(-45deg, #322814, #998250, #322814); + line-height: 1em; + }\n\n` + }, + ] + }, /************************* PHB ********************/ { groupName : 'PHB', diff --git a/themes/V3/Blank/snippets.js b/themes/V3/Blank/snippets.js index 08e378490..809035a3a 100644 --- a/themes/V3/Blank/snippets.js +++ b/themes/V3/Blank/snippets.js @@ -201,30 +201,7 @@ module.exports = [ name : 'Add Comment', icon : 'fas fa-code', gen : '/* This is a comment that will not be rendered into your brew. */' - }, - { - name : 'Remove Drop Cap', - icon : 'fas fa-remove-format', - gen : dedent`/* Removes Drop Caps */ - .page h1+p:first-letter { - all: unset; - }\n\n - /* Removes Small-Caps in first line */ - .page h1+p:first-line { - all: unset; - }` - }, - { - name : 'Tweak Drop Cap', - icon : 'fas fa-sliders-h', - gen : dedent`/* Drop Cap settings */ - .page h1 + p::first-letter { - font-family: SolberaImitationRemake; - font-size: 3.5cm; - background-image: linear-gradient(-45deg, #322814, #998250, #322814); - line-height: 1em; - }\n\n` - }, + } ] }, From 3672285e923a2f5de9cef4a2ae7bffff02df47c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Losada=20Hern=C3=A1ndez?= Date: Mon, 24 Mar 2025 13:09:56 +0100 Subject: [PATCH 320/398] additional linting pass through themes --- themes/Legacy/5ePHB/style.less | 26 +++++++++++++------------- themes/V3/5eDMG/style.less | 4 ++-- themes/V3/5ePHB/style.less | 2 +- themes/V3/Blank/style.less | 28 +++++++++++++--------------- themes/V3/Journal/style.less | 30 +++++++++++++++--------------- 5 files changed, 44 insertions(+), 46 deletions(-) diff --git a/themes/Legacy/5ePHB/style.less b/themes/Legacy/5ePHB/style.less index 56d1bed94..41524c74c 100644 --- a/themes/Legacy/5ePHB/style.less +++ b/themes/Legacy/5ePHB/style.less @@ -13,13 +13,13 @@ body { counter-reset : phb-page-numbers; } * { -webkit-print-color-adjust : exact; } .useSansSerif() { - font-family : "ScalySans"; + font-family : 'ScalySans'; em { - font-family : "ScalySans"; + font-family : 'ScalySans'; font-style : italic; } strong { - font-family : "ScalySans"; + font-family : 'ScalySans'; font-weight : 800; letter-spacing : -0.02em; } @@ -46,7 +46,7 @@ body { counter-reset : phb-page-numbers; } padding : 1.0cm 1.7cm; padding-bottom : 1.5cm; overflow : hidden; - font-family : "BookSanity"; + font-family : 'BookSanity'; font-size : 0.317cm; counter-increment : phb-page-numbers; background-color : @background; @@ -106,7 +106,7 @@ body { counter-reset : phb-page-numbers; } h1,h2,h3,h4 { margin-top : 0.2em; margin-bottom : 0.2em; - font-family : "MrJeeves"; + font-family : 'MrJeeves'; font-weight : 800; color : @headerText; } @@ -117,7 +117,7 @@ body { counter-reset : phb-page-numbers; } -moz-column-span : all; & + p::first-letter { float : left; - font-family : "Solberry"; + font-family : 'Solberry'; font-size : 10em; line-height : 0.795em; color : #222222; @@ -134,7 +134,7 @@ body { counter-reset : phb-page-numbers; } } h5 { margin-bottom : 0.2em; - font-family : "ScalySansSmallCaps"; + font-family : 'ScalySansSmallCaps'; font-size : 0.423cm; font-weight : 900; } @@ -200,7 +200,7 @@ body { counter-reset : phb-page-numbers; } & + p { padding-bottom : 0px; } } h3 { - font-family : "ScalySans"; + font-family : 'ScalySans'; font-weight : normal; border-bottom : 1px solid @headerText; } @@ -380,7 +380,7 @@ body { counter-reset : phb-page-numbers; } // ************************************/ .phb .descriptive { margin-bottom : 1em; - font-family : "ScalySans"; + font-family : 'ScalySans'; background-color : #FAF7EA; border-style : solid; border-width : 7px; @@ -394,11 +394,11 @@ body { counter-reset : phb-page-numbers; } } p + p { padding-top : 0.8em; } em { - font-family : "ScalySans"; + font-family : 'ScalySans'; font-style : italic; } strong { - font-family : "ScalySans"; + font-family : 'ScalySans'; font-weight : 800; letter-spacing : -0.02em; } @@ -411,7 +411,7 @@ body { counter-reset : phb-page-numbers; } .phb { .artist { position : absolute; - font-family : "WalterTurncoat"; + font-family : 'WalterTurncoat'; font-size : 0.27cm; color : @captionText; text-align : center; @@ -421,7 +421,7 @@ body { counter-reset : phb-page-numbers; } text-indent : unset; } h5 { - font-family : "WalterTurncoat"; + font-family : 'WalterTurncoat'; font-size : 1.3em; } a { diff --git a/themes/V3/5eDMG/style.less b/themes/V3/5eDMG/style.less index cbc3fa890..d79533c2c 100644 --- a/themes/V3/5eDMG/style.less +++ b/themes/V3/5eDMG/style.less @@ -7,7 +7,7 @@ } .page { - background-image : url("/assets/DMG_background.png"); + background-image : url('/assets/DMG_background.png'); background-size : cover; /* TABLES WITHIN NOTES */ @@ -23,7 +23,7 @@ &::after { height : 58px; - background-image : url("/assets/DMG_footerAccent.png"); + background-image : url('/assets/DMG_footerAccent.png'); } .footnote { bottom : 40px; } diff --git a/themes/V3/5ePHB/style.less b/themes/V3/5ePHB/style.less index d51cfd313..555866ba4 100644 --- a/themes/V3/5ePHB/style.less +++ b/themes/V3/5ePHB/style.less @@ -792,7 +792,7 @@ // *****************************/ // Additional Default Exclusions -.monster { --TOC: exclude; } +.monster { --TOC : exclude; } .page:has(.partCover) { --TOC : exclude; diff --git a/themes/V3/Blank/style.less b/themes/V3/Blank/style.less index 519b60207..01b85326f 100644 --- a/themes/V3/Blank/style.less +++ b/themes/V3/Blank/style.less @@ -532,20 +532,20 @@ h6, .page:has(.backCover), .page:has(.insideCover), .noToC, -.toc { --TOC: exclude; } +.toc { --TOC : exclude; } -.tocDepthH2 :is(h1, h2) {--TOC: include; } -.tocDepthH3 :is(h1, h2, h3) {--TOC: include; } -.tocDepthH4 :is(h1, h2, h3, h4) {--TOC: include; } -.tocDepthH5 :is(h1, h2, h3, h4, h5) {--TOC: include; } -.tocDepthH6 :is(h1, h2, h3, h4, h5, h6) {--TOC: include; } +.tocDepthH2 :is(h1, h2) {--TOC : include; } +.tocDepthH3 :is(h1, h2, h3) {--TOC : include; } +.tocDepthH4 :is(h1, h2, h3, h4) {--TOC : include; } +.tocDepthH5 :is(h1, h2, h3, h4, h5) {--TOC : include; } +.tocDepthH6 :is(h1, h2, h3, h4, h5, h6) {--TOC : include; } -.tocIncludeH1 h1 {--TOC: include; } -.tocIncludeH2 h2 {--TOC: include; } -.tocIncludeH3 h3 {--TOC: include; } -.tocIncludeH4 h4 {--TOC: include; } -.tocIncludeH5 h5 {--TOC: include; } -.tocIncludeH6 h6 {--TOC: include; } +.tocIncludeH1 h1 {--TOC : include; } +.tocIncludeH2 h2 {--TOC : include; } +.tocIncludeH3 h3 {--TOC : include; } +.tocIncludeH4 h4 {--TOC : include; } +.tocIncludeH5 h5 {--TOC : include; } +.tocIncludeH6 h6 {--TOC : include; } .page { &:has(.toc)::after { display : none; } @@ -609,7 +609,5 @@ h6, .useColumns(0.96, @fillMode: balance); } } - .toc.wide li { - break-inside: auto; - } + .toc.wide li { break-inside : auto; } } diff --git a/themes/V3/Journal/style.less b/themes/V3/Journal/style.less index bddefb749..74c976f47 100644 --- a/themes/V3/Journal/style.less +++ b/themes/V3/Journal/style.less @@ -12,7 +12,7 @@ } .useSansSerif() { - font-family : "PermanentMarker"; + font-family : 'PermanentMarker'; font-size : 0.3cm; line-height : 1.2em; color : var(--HB_Color_Text2); @@ -29,7 +29,7 @@ .page { padding : 2.1cm 1.9cm 1.7cm 3.8cm; - background-image : url("/assets/Journal/Background1.webp"); + background-image : url('/assets/Journal/Background1.webp'); background-repeat : no-repeat; background-size : 200% 100%; filter : drop-shadow(1px 4px 14px black); @@ -39,7 +39,7 @@ background-position : right; } &:nth-of-type(2) { - background-image : url("/assets/Journal/Background2.webp"); //Only first page should show ribbon + background-image : url('/assets/Journal/Background2.webp'); //Only first page should show ribbon } & .columnWrapper { @@ -51,7 +51,7 @@ // * BASE // *****************************/ .page { - font-family : "ReenieBeanie"; + font-family : 'ReenieBeanie'; font-size : 0.53cm; line-height : 0.8em; color : var(--HB_Color_Text); @@ -71,7 +71,7 @@ // * HEADERS // *****************************/ h1,h2,h3,h4,h5 { - font-family : "FrederickaTheGreat"; + font-family : 'FrederickaTheGreat'; font-weight : unset; color : var(--HB_Color_HeaderText); } @@ -89,7 +89,7 @@ margin-right : 0.1em; margin-bottom : -20px; margin-left : -40px; - font-family : "FrederickaTheGreat"; + font-family : 'FrederickaTheGreat'; font-size : 1.9em; line-height : 1em; } @@ -114,7 +114,7 @@ &:nth-of-type(3n) { transform : rotate(-1.5deg); } } h5 { - font-family : "PermanentMarker"; + font-family : 'PermanentMarker'; font-size : 0.4cm; font-weight : bold; line-height : 0.951em; //Font is misaligned. Shift up slightly @@ -146,14 +146,14 @@ .note { .useSansSerif(); padding : 0.2cm; - background-image : url("/assets/Journal/HashMarks.png"), + background-image : url('/assets/Journal/HashMarks.png'), linear-gradient(to bottom right, #FF000000, #A36A4E14, #41212100); background-repeat : no-repeat; background-position : center; background-size : 120% 120%; border-style : solid; border-width : 1px; - border-image-source : url("/assets/Journal/Border1.png"); + border-image-source : url('/assets/Journal/Border1.png'); border-image-slice : 18 18 18 18; border-image-width : 6px 6px 6px 6px; border-image-outset : 5px 5px 5px 5px; @@ -173,7 +173,7 @@ .descriptive { .useSansSerif(); padding : 0.2cm; - background-image : url("/assets/Journal/HashMarks.png"), + background-image : url('/assets/Journal/HashMarks.png'), linear-gradient(to bottom right, #FF000000, #41212114, #41212100); background-repeat : no-repeat; background-position : center; @@ -201,7 +201,7 @@ .artist { position : absolute; width : auto; - font-family : "WalterTurncoat"; + font-family : 'WalterTurncoat'; font-size : 0.27cm; color : var(--HB_Color_CaptionText); text-align : center; @@ -211,7 +211,7 @@ text-indent : unset; } h5 { - font-family : "WalterTurncoat"; + font-family : 'WalterTurncoat'; font-size : 1.3em; } a { @@ -309,7 +309,7 @@ .pageNumber { right : 3cm; bottom : 1.25cm; - font-family : "FrederickaTheGreat"; + font-family : 'FrederickaTheGreat'; color : var(--HB_Color_HeaderText); } .footnote { @@ -370,7 +370,7 @@ .page .spellList { .useSansSerif(); - font-family : "PermanentMarker"; + font-family : 'PermanentMarker'; column-count : 2; ul + h5 { margin-top : 15px; } ul { @@ -439,7 +439,7 @@ &:last-child { width : 1%; padding-left : 0.06cm; /* Spacing after dot leaders */ - font-family : "ReenieBeanie"; + font-family : 'ReenieBeanie'; font-size : 0.34cm; font-weight : normal; vertical-align : bottom; /* Keep page number bottom-aligned */ From a62588a4c9e495f7281b4178b05a02c30046739c Mon Sep 17 00:00:00 2001 From: David Bolack Date: Mon, 24 Mar 2025 14:58:14 -0500 Subject: [PATCH 321/398] Fix fouled up regex that only worked by accident --- shared/helpers.js | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/shared/helpers.js b/shared/helpers.js index efe7eb008..997d77cec 100644 --- a/shared/helpers.js +++ b/shared/helpers.js @@ -4,20 +4,22 @@ import request from '../client/homebrew/utils/request-middleware.js'; // Convert the templates from a brew to a Snippets Structure. const brewSnippetsToJSON = (menuTitle, userBrewSnippets, themeBundleSnippets=null, full=true)=>{ - const textSplit = /^\\snippet +/gm; + const textSplit = /^(\\snippet +.+\n)/gm; const mpAsSnippets = []; // Snippets from Themes first. if(themeBundleSnippets) { for (let themes of themeBundleSnippets) { if(typeof themes !== 'string') { const userSnippets = []; - for (let snips of themes.snippets.trim().split(textSplit)) { - const name = snips.trim().split('\n')[0]; - if(name.length != 0) { + const snipSplit = themes.snippets.trim().split(textSplit).slice(1); + for (let snips = 0; snips < snipSplit.length; snips+=2) { + if(!snipSplit[snips].startsWith('\\snippet ')) break; + const snippetName = snipSplit[snips].split(/\\snippet +/)[1].split('\n')[0].trim(); + if(snippetName.length != 0) { userSnippets.push({ - name : name, + name : snippetName, icon : '', - gen : snips.slice(name.length + 1).trim(), + gen : snipSplit[snips + 1], }); } } @@ -35,16 +37,14 @@ const brewSnippetsToJSON = (menuTitle, userBrewSnippets, themeBundleSnippets=nul // Local Snippets if(userBrewSnippets) { const userSnippets = []; - for (let snips of userBrewSnippets.trim().split(textSplit)) { - let name = snips.split('\n')[0]; - let justSnippet = snips.slice(name.length + 1); - if(justSnippet.slice(-1) === '\n') { - justSnippet = justSnippet.slice(0, -1); - } - if(name.length != 0) { + const snipSplit = userBrewSnippets.trim().split(textSplit).slice(1); + for (let snips = 0; snips < snipSplit.length; snips+=2) { + if(!snipSplit[snips].startsWith('\\snippet ')) break; + const snippetName = snipSplit[snips].split(/\\snippet +/)[1].split('\n')[0].trim(); + if(snippetName.length != 0) { const subSnip = { - name : name, - gen : justSnippet, + name : snippetName, + gen : snipSplit[snips + 1], }; // if(full) subSnip.icon = ''; userSnippets.push(subSnip); From 565d58bb31e77d75742057966a322bdea8ed80b8 Mon Sep 17 00:00:00 2001 From: David Bolack Date: Mon, 24 Mar 2025 21:06:55 -0500 Subject: [PATCH 322/398] Add clearing for snippets --- client/homebrew/editor/editor.jsx | 1 + 1 file changed, 1 insertion(+) diff --git a/client/homebrew/editor/editor.jsx b/client/homebrew/editor/editor.jsx index cdad4abb3..7800717d5 100644 --- a/client/homebrew/editor/editor.jsx +++ b/client/homebrew/editor/editor.jsx @@ -186,6 +186,7 @@ const Editor = createClass({ //reset custom line styles codeMirror.removeLineClass(lineNumber, 'background', 'pageLine'); + codeMirror.removeLineClass(lineNumber, 'background', 'snippetLine'); codeMirror.removeLineClass(lineNumber, 'text'); codeMirror.removeLineClass(lineNumber, 'wrap', 'sourceMoveFlash'); From 7bc323c92c54b1aa0e663319d0537b1008e68945 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 26 Mar 2025 15:06:16 +0000 Subject: [PATCH 323/398] Bump nanoid from 5.1.3 to 5.1.5 Bumps [nanoid](https://github.com/ai/nanoid) from 5.1.3 to 5.1.5. - [Release notes](https://github.com/ai/nanoid/releases) - [Changelog](https://github.com/ai/nanoid/blob/main/CHANGELOG.md) - [Commits](https://github.com/ai/nanoid/compare/5.1.3...5.1.5) --- updated-dependencies: - dependency-name: nanoid dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- package-lock.json | 8 ++++---- package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index 9220e4e12..36e94533a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -42,7 +42,7 @@ "markedLegacy": "npm:marked@^0.3.19", "moment": "^2.30.1", "mongoose": "^8.12.1", - "nanoid": "5.1.3", + "nanoid": "5.1.5", "nconf": "^0.12.1", "react": "^18.3.1", "react-dom": "^18.3.1", @@ -10480,9 +10480,9 @@ "optional": true }, "node_modules/nanoid": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-5.1.3.tgz", - "integrity": "sha512-zAbEOEr7u2CbxwoMRlz/pNSpRP0FdAU4pRaYunCdEezWohXFs+a0Xw7RfkKaezMsmSM1vttcLthJtwRnVtOfHQ==", + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-5.1.5.tgz", + "integrity": "sha512-Ir/+ZpE9fDsNH0hQ3C68uyThDXzYcim2EqcZ8zn8Chtt1iylPT9xXJB0kPCnqzgcEGikO9RxSrh63MsmVCU7Fw==", "funding": [ { "type": "github", diff --git a/package.json b/package.json index 7f7b10bf5..74fd4ab9a 100644 --- a/package.json +++ b/package.json @@ -116,7 +116,7 @@ "markedLegacy": "npm:marked@^0.3.19", "moment": "^2.30.1", "mongoose": "^8.12.1", - "nanoid": "5.1.3", + "nanoid": "5.1.5", "nconf": "^0.12.1", "react": "^18.3.1", "react-dom": "^18.3.1", From c8cf9e3002073c21233f7e31791ad40f70ad23fa Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 26 Mar 2025 15:06:30 +0000 Subject: [PATCH 324/398] Bump @googleapis/drive from 8.16.0 to 11.0.0 Bumps [@googleapis/drive](https://github.com/googleapis/google-api-nodejs-client) from 8.16.0 to 11.0.0. - [Release notes](https://github.com/googleapis/google-api-nodejs-client/releases) - [Changelog](https://github.com/googleapis/google-api-nodejs-client/blob/11.0.0/CHANGELOG.md) - [Commits](https://github.com/googleapis/google-api-nodejs-client/compare/drive-v8.16.0...11.0.0) --- updated-dependencies: - dependency-name: "@googleapis/drive" dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- package-lock.json | 8 ++++---- package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index 9220e4e12..579c0c65c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,7 +14,7 @@ "@babel/plugin-transform-runtime": "^7.26.9", "@babel/preset-env": "^7.26.9", "@babel/preset-react": "^7.26.3", - "@googleapis/drive": "^8.16.0", + "@googleapis/drive": "^11.0.0", "body-parser": "^1.20.2", "classnames": "^2.5.1", "codemirror": "^5.65.6", @@ -1972,9 +1972,9 @@ } }, "node_modules/@googleapis/drive": { - "version": "8.16.0", - "resolved": "https://registry.npmjs.org/@googleapis/drive/-/drive-8.16.0.tgz", - "integrity": "sha512-Xi2mMrUTQ+gsfyouRGd0pfnL+jjg4n4sjKsJruM1y4DknuRfdSBTk5E//WrL0YJ/CqpcBgyd7L8DvaPRtxZD3Q==", + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/@googleapis/drive/-/drive-11.0.0.tgz", + "integrity": "sha512-vhkl6/MZ8k5h5XOyenWOD4ys+SNdb8wKYvzU6OBGFx/TzJyHRm4JwgvE8uVDFU6efzNRS0mOiNRfY6nrmHOTtg==", "license": "Apache-2.0", "dependencies": { "googleapis-common": "^7.0.0" diff --git a/package.json b/package.json index 7f7b10bf5..21cd55db1 100644 --- a/package.json +++ b/package.json @@ -88,7 +88,7 @@ "@babel/plugin-transform-runtime": "^7.26.9", "@babel/preset-env": "^7.26.9", "@babel/preset-react": "^7.26.3", - "@googleapis/drive": "^8.16.0", + "@googleapis/drive": "^11.0.0", "body-parser": "^1.20.2", "classnames": "^2.5.1", "codemirror": "^5.65.6", From 8e10e9dea9c16e295e1468c051d6ed9568ba7a86 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 26 Mar 2025 15:13:56 +0000 Subject: [PATCH 325/398] Bump react-router from 7.3.0 to 7.4.0 Bumps [react-router](https://github.com/remix-run/react-router/tree/HEAD/packages/react-router) from 7.3.0 to 7.4.0. - [Release notes](https://github.com/remix-run/react-router/releases) - [Changelog](https://github.com/remix-run/react-router/blob/main/packages/react-router/CHANGELOG.md) - [Commits](https://github.com/remix-run/react-router/commits/react-router@7.4.0/packages/react-router) --- updated-dependencies: - dependency-name: react-router dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- package-lock.json | 8 ++++---- package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index d019bb561..bc68da76a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -47,7 +47,7 @@ "react": "^18.3.1", "react-dom": "^18.3.1", "react-frame-component": "^4.1.3", - "react-router": "^7.3.0", + "react-router": "^7.4.0", "sanitize-filename": "1.6.3", "superagent": "^10.1.1", "vitreum": "git+https://git@github.com/calculuschild/vitreum.git" @@ -11753,9 +11753,9 @@ "license": "MIT" }, "node_modules/react-router": { - "version": "7.3.0", - "resolved": "https://registry.npmjs.org/react-router/-/react-router-7.3.0.tgz", - "integrity": "sha512-466f2W7HIWaNXTKM5nHTqNxLrHTyXybm7R0eBlVSt0k/u55tTCDO194OIx/NrYD4TS5SXKTNekXfT37kMKUjgw==", + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-7.4.0.tgz", + "integrity": "sha512-Y2g5ObjkvX3VFeVt+0CIPuYd9PpgqCslG7ASSIdN73LwA1nNWzcMLaoMRJfP3prZFI92svxFwbn7XkLJ+UPQ6A==", "license": "MIT", "dependencies": { "@types/cookie": "^0.6.0", diff --git a/package.json b/package.json index 294c301e6..944431e07 100644 --- a/package.json +++ b/package.json @@ -121,7 +121,7 @@ "react": "^18.3.1", "react-dom": "^18.3.1", "react-frame-component": "^4.1.3", - "react-router": "^7.3.0", + "react-router": "^7.4.0", "sanitize-filename": "1.6.3", "superagent": "^10.1.1", "vitreum": "git+https://git@github.com/calculuschild/vitreum.git" From 0095e4582b8b96776a0b3a42edf98285ad9f72d5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 26 Mar 2025 15:18:49 +0000 Subject: [PATCH 326/398] Bump superagent from 10.1.1 to 10.2.0 Bumps [superagent](https://github.com/ladjs/superagent) from 10.1.1 to 10.2.0. - [Release notes](https://github.com/ladjs/superagent/releases) - [Changelog](https://github.com/ladjs/superagent/blob/master/HISTORY.md) - [Commits](https://github.com/ladjs/superagent/compare/v10.1.1...v10.2.0) --- updated-dependencies: - dependency-name: superagent dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- package-lock.json | 9 +++++---- package.json | 2 +- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index bc68da76a..678fa39cb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -49,7 +49,7 @@ "react-frame-component": "^4.1.3", "react-router": "^7.4.0", "sanitize-filename": "1.6.3", - "superagent": "^10.1.1", + "superagent": "^10.2.0", "vitreum": "git+https://git@github.com/calculuschild/vitreum.git" }, "devDependencies": { @@ -13395,9 +13395,10 @@ } }, "node_modules/superagent": { - "version": "10.1.1", - "resolved": "https://registry.npmjs.org/superagent/-/superagent-10.1.1.tgz", - "integrity": "sha512-9pIwrHrOj3uAnqg9gDlW7EA2xv+N5au/dSM0kM22HTqmUu8jBxNT+8uA7tA3UoCnmiqzpSbu8rasIUZvbyamMQ==", + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/superagent/-/superagent-10.2.0.tgz", + "integrity": "sha512-IKeoGox6oG9zyDeizaezkJ2/aK0wc5la9st7WsAKyrAkfJ56W3whVbVtF68k6wuc87/y9T85NyON5FLz7Mrzzw==", + "license": "MIT", "dependencies": { "component-emitter": "^1.3.0", "cookiejar": "^2.1.4", diff --git a/package.json b/package.json index 944431e07..0ce9d56a2 100644 --- a/package.json +++ b/package.json @@ -123,7 +123,7 @@ "react-frame-component": "^4.1.3", "react-router": "^7.4.0", "sanitize-filename": "1.6.3", - "superagent": "^10.1.1", + "superagent": "^10.2.0", "vitreum": "git+https://git@github.com/calculuschild/vitreum.git" }, "devDependencies": { From cdacaac049d1bbe810fa3472a71184cbe5d28114 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 26 Mar 2025 15:26:53 +0000 Subject: [PATCH 327/398] Bump eslint from 9.22.0 to 9.23.0 Bumps [eslint](https://github.com/eslint/eslint) from 9.22.0 to 9.23.0. - [Release notes](https://github.com/eslint/eslint/releases) - [Changelog](https://github.com/eslint/eslint/blob/main/CHANGELOG.md) - [Commits](https://github.com/eslint/eslint/compare/v9.22.0...v9.23.0) --- updated-dependencies: - dependency-name: eslint dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- package-lock.json | 38 +++++++++++++++++++------------------- package.json | 2 +- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/package-lock.json b/package-lock.json index 678fa39cb..a8118abce 100644 --- a/package-lock.json +++ b/package-lock.json @@ -55,7 +55,7 @@ "devDependencies": { "@stylistic/stylelint-plugin": "^3.1.2", "babel-plugin-transform-import-meta": "^2.3.2", - "eslint": "^9.22.0", + "eslint": "^9.23.0", "eslint-plugin-jest": "^28.11.0", "eslint-plugin-react": "^7.37.4", "globals": "^16.0.0", @@ -1878,9 +1878,9 @@ } }, "node_modules/@eslint/config-helpers": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.1.0.tgz", - "integrity": "sha512-kLrdPDJE1ckPo94kmPPf9Hfd0DU0Jw6oKYrhe+pwSC0iTUInmTa+w6fw8sGgcfkFJGNdWOUeOaDM4quW4a7OkA==", + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.2.0.tgz", + "integrity": "sha512-yJLLmLexii32mGrhW29qvU3QBVTu0GUmEf/J4XsBtVhp4JkIUFN/BjWqTF63yRvGApIDpZm5fa97LtYtINmfeQ==", "dev": true, "license": "Apache-2.0", "engines": { @@ -1901,9 +1901,9 @@ } }, "node_modules/@eslint/eslintrc": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.0.tgz", - "integrity": "sha512-yaVPAiNAalnCZedKLdR21GOGILMLKPyqSLWaAjQFvYA2i/ciDi8ArYVr69Anohb6cH2Ukhqti4aFnYyPm8wdwQ==", + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.1.tgz", + "integrity": "sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==", "dev": true, "license": "MIT", "dependencies": { @@ -1938,9 +1938,9 @@ } }, "node_modules/@eslint/js": { - "version": "9.22.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.22.0.tgz", - "integrity": "sha512-vLFajx9o8d1/oL2ZkpMYbkLv8nDB6yaIwFNt7nI4+I80U/z03SxmfOMsLbvWr3p7C+Wnoh//aOu2pQW8cS0HCQ==", + "version": "9.23.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.23.0.tgz", + "integrity": "sha512-35MJ8vCPU0ZMxo7zfev2pypqTwWTofFZO6m4KAtdoFhRpLJUpHTZZ+KB3C7Hb1d7bULYwO4lJXGCi5Se+8OMbw==", "dev": true, "license": "MIT", "engines": { @@ -3140,9 +3140,9 @@ } }, "node_modules/acorn": { - "version": "8.14.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz", - "integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==", + "version": "8.14.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.1.tgz", + "integrity": "sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==", "dev": true, "license": "MIT", "bin": { @@ -5697,19 +5697,19 @@ "license": "MIT" }, "node_modules/eslint": { - "version": "9.22.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.22.0.tgz", - "integrity": "sha512-9V/QURhsRN40xuHXWjV64yvrzMjcz7ZyNoF2jJFmy9j/SLk0u1OLSZgXi28MrXjymnjEGSR80WCdab3RGMDveQ==", + "version": "9.23.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.23.0.tgz", + "integrity": "sha512-jV7AbNoFPAY1EkFYpLq5bslU9NLNO8xnEeQXwErNibVryjk67wHVmddTBilc5srIttJDBrB0eMHKZBFbSIABCw==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.12.1", "@eslint/config-array": "^0.19.2", - "@eslint/config-helpers": "^0.1.0", + "@eslint/config-helpers": "^0.2.0", "@eslint/core": "^0.12.0", - "@eslint/eslintrc": "^3.3.0", - "@eslint/js": "9.22.0", + "@eslint/eslintrc": "^3.3.1", + "@eslint/js": "9.23.0", "@eslint/plugin-kit": "^0.2.7", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", diff --git a/package.json b/package.json index 0ce9d56a2..94738a27d 100644 --- a/package.json +++ b/package.json @@ -129,7 +129,7 @@ "devDependencies": { "@stylistic/stylelint-plugin": "^3.1.2", "babel-plugin-transform-import-meta": "^2.3.2", - "eslint": "^9.22.0", + "eslint": "^9.23.0", "eslint-plugin-jest": "^28.11.0", "eslint-plugin-react": "^7.37.4", "globals": "^16.0.0", From d315e4f008600bb1f28eaaeeacc2a191a01be764 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 26 Mar 2025 15:28:21 +0000 Subject: [PATCH 328/398] Bump mongoose from 8.12.1 to 8.13.0 Bumps [mongoose](https://github.com/Automattic/mongoose) from 8.12.1 to 8.13.0. - [Release notes](https://github.com/Automattic/mongoose/releases) - [Changelog](https://github.com/Automattic/mongoose/blob/master/CHANGELOG.md) - [Commits](https://github.com/Automattic/mongoose/compare/8.12.1...8.13.0) --- updated-dependencies: - dependency-name: mongoose dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- package-lock.json | 30 +++++++++++++++--------------- package.json | 2 +- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/package-lock.json b/package-lock.json index a8118abce..3ebb25945 100644 --- a/package-lock.json +++ b/package-lock.json @@ -41,7 +41,7 @@ "marked-subsuper-text": "^1.0.3", "markedLegacy": "npm:marked@^0.3.19", "moment": "^2.30.1", - "mongoose": "^8.12.1", + "mongoose": "^8.13.0", "nanoid": "5.1.5", "nconf": "^0.12.1", "react": "^18.3.1", @@ -10284,9 +10284,9 @@ } }, "node_modules/mongodb-connection-string-url/node_modules/tr46": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-5.0.0.tgz", - "integrity": "sha512-tk2G5R2KRwBd+ZN0zaEXpmzdKyOYksXwywulIX95MBODjSzMIuQnQ3m8JxgbhnL1LeVo7lqQKsYa1O3Htl7K5g==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-5.1.0.tgz", + "integrity": "sha512-IUWnUK7ADYR5Sl1fZlO1INDUhVhatWl7BtJWsIhwJ0UAK7ilzzIa8uIqOO/aYVWHZPJkKbEL+362wrzoeRF7bw==", "license": "MIT", "dependencies": { "punycode": "^2.3.1" @@ -10305,12 +10305,12 @@ } }, "node_modules/mongodb-connection-string-url/node_modules/whatwg-url": { - "version": "14.1.1", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-14.1.1.tgz", - "integrity": "sha512-mDGf9diDad/giZ/Sm9Xi2YcyzaFpbdLpJPr+E9fSkyQ7KpQD4SdFcugkRQYzhmfI4KeV4Qpnn2sKPdo+kmsgRQ==", + "version": "14.2.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-14.2.0.tgz", + "integrity": "sha512-De72GdQZzNTUBBChsXueQUnPKDkg/5A5zp7pFDuQAj5UFoENpiACU0wlCvzpAGnTkj++ihpKwKyYewn/XNUbKw==", "license": "MIT", "dependencies": { - "tr46": "^5.0.0", + "tr46": "^5.1.0", "webidl-conversions": "^7.0.0" }, "engines": { @@ -10318,14 +10318,14 @@ } }, "node_modules/mongoose": { - "version": "8.12.1", - "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-8.12.1.tgz", - "integrity": "sha512-UW22y8QFVYmrb36hm8cGncfn4ARc/XsYWQwRTaj0gxtQk1rDuhzDO1eBantS+hTTatfAIS96LlRCJrcNHvW5+Q==", + "version": "8.13.0", + "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-8.13.0.tgz", + "integrity": "sha512-e/iYV1mPeOkg+SWAMHzt3t42/EZyER3OB1H2pjP9C3vQ+Qb5DMeV9Kb+YCUycKgScA3fbwL7dKG4EpinGlg21g==", "license": "MIT", "dependencies": { "bson": "^6.10.3", "kareem": "2.6.3", - "mongodb": "~6.14.0", + "mongodb": "~6.15.0", "mpath": "0.9.0", "mquery": "5.0.0", "ms": "2.1.3", @@ -10401,9 +10401,9 @@ } }, "node_modules/mongoose/node_modules/mongodb": { - "version": "6.14.2", - "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-6.14.2.tgz", - "integrity": "sha512-kMEHNo0F3P6QKDq17zcDuPeaywK/YaJVCEQRzPF3TOM/Bl9MFg64YE5Tu7ifj37qZJMhwU1tl2Ioivws5gRG5Q==", + "version": "6.15.0", + "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-6.15.0.tgz", + "integrity": "sha512-ifBhQ0rRzHDzqp9jAQP6OwHSH7dbYIQjD3SbJs9YYk9AikKEettW/9s/tbSFDTpXcRbF+u1aLrhHxDFaYtZpFQ==", "license": "Apache-2.0", "dependencies": { "@mongodb-js/saslprep": "^1.1.9", diff --git a/package.json b/package.json index 94738a27d..e22ec0714 100644 --- a/package.json +++ b/package.json @@ -115,7 +115,7 @@ "marked-subsuper-text": "^1.0.3", "markedLegacy": "npm:marked@^0.3.19", "moment": "^2.30.1", - "mongoose": "^8.12.1", + "mongoose": "^8.13.0", "nanoid": "5.1.5", "nconf": "^0.12.1", "react": "^18.3.1", From 8fc1919d7ccfa2f85616bb911d65f9dc3116ac34 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 26 Mar 2025 15:40:50 +0000 Subject: [PATCH 329/398] Bump @babel/plugin-transform-runtime from 7.26.9 to 7.26.10 Bumps [@babel/plugin-transform-runtime](https://github.com/babel/babel/tree/HEAD/packages/babel-plugin-transform-runtime) from 7.26.9 to 7.26.10. - [Release notes](https://github.com/babel/babel/releases) - [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md) - [Commits](https://github.com/babel/babel/commits/v7.26.10/packages/babel-plugin-transform-runtime) --- updated-dependencies: - dependency-name: "@babel/plugin-transform-runtime" dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- package-lock.json | 34 +++++++++++----------------------- package.json | 2 +- 2 files changed, 12 insertions(+), 24 deletions(-) diff --git a/package-lock.json b/package-lock.json index 3ebb25945..901e6b1f0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,7 +11,7 @@ "license": "MIT", "dependencies": { "@babel/core": "^7.26.9", - "@babel/plugin-transform-runtime": "^7.26.9", + "@babel/plugin-transform-runtime": "^7.26.10", "@babel/preset-env": "^7.26.9", "@babel/preset-react": "^7.26.3", "@googleapis/drive": "^11.0.0", @@ -1406,15 +1406,15 @@ } }, "node_modules/@babel/plugin-transform-runtime": { - "version": "7.26.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.26.9.tgz", - "integrity": "sha512-Jf+8y9wXQbbxvVYTM8gO5oEF2POdNji0NMltEkG7FtmzD9PVz7/lxpqSdTvwsjTMU5HIHuDVNf2SOxLkWi+wPQ==", + "version": "7.26.10", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.26.10.tgz", + "integrity": "sha512-NWaL2qG6HRpONTnj4JvDU6th4jYeZOJgu3QhmFTCihib0ermtOJqktA5BduGm3suhhVe9EMP9c9+mfJ/I9slqw==", "license": "MIT", "dependencies": { "@babel/helper-module-imports": "^7.25.9", "@babel/helper-plugin-utils": "^7.26.5", "babel-plugin-polyfill-corejs2": "^0.4.10", - "babel-plugin-polyfill-corejs3": "^0.10.6", + "babel-plugin-polyfill-corejs3": "^0.11.0", "babel-plugin-polyfill-regenerator": "^0.6.1", "semver": "^6.3.1" }, @@ -1640,19 +1640,6 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/preset-env/node_modules/babel-plugin-polyfill-corejs3": { - "version": "0.11.1", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.11.1.tgz", - "integrity": "sha512-yGCqvBT4rwMczo28xkH/noxJ6MZ4nJfkVYdoDaC/utLtWrXxv27HVrzAeSbqR8SxDsp46n0YF47EbHoixy6rXQ==", - "license": "MIT", - "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.6.3", - "core-js-compat": "^3.40.0" - }, - "peerDependencies": { - "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" - } - }, "node_modules/@babel/preset-modules": { "version": "0.1.6-no-external-plugins", "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.6-no-external-plugins.tgz", @@ -3704,12 +3691,13 @@ } }, "node_modules/babel-plugin-polyfill-corejs3": { - "version": "0.10.6", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.10.6.tgz", - "integrity": "sha512-b37+KR2i/khY5sKmWNVQAnitvquQbNdWy6lJdsr0kmquCKEEUgMKK4SboVM3HtfnZilfjr4MMQ7vY58FVWDtIA==", + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.11.1.tgz", + "integrity": "sha512-yGCqvBT4rwMczo28xkH/noxJ6MZ4nJfkVYdoDaC/utLtWrXxv27HVrzAeSbqR8SxDsp46n0YF47EbHoixy6rXQ==", + "license": "MIT", "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.6.2", - "core-js-compat": "^3.38.0" + "@babel/helper-define-polyfill-provider": "^0.6.3", + "core-js-compat": "^3.40.0" }, "peerDependencies": { "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" diff --git a/package.json b/package.json index e22ec0714..c95ba6470 100644 --- a/package.json +++ b/package.json @@ -85,7 +85,7 @@ }, "dependencies": { "@babel/core": "^7.26.9", - "@babel/plugin-transform-runtime": "^7.26.9", + "@babel/plugin-transform-runtime": "^7.26.10", "@babel/preset-env": "^7.26.9", "@babel/preset-react": "^7.26.3", "@googleapis/drive": "^11.0.0", From 1c1808378b0393a510e8bb8fd27c6de48abeb2b7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 26 Mar 2025 15:47:08 +0000 Subject: [PATCH 330/398] Bump @babel/core from 7.26.9 to 7.26.10 Bumps [@babel/core](https://github.com/babel/babel/tree/HEAD/packages/babel-core) from 7.26.9 to 7.26.10. - [Release notes](https://github.com/babel/babel/releases) - [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md) - [Commits](https://github.com/babel/babel/commits/v7.26.10/packages/babel-core) --- updated-dependencies: - dependency-name: "@babel/core" dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- package-lock.json | 66 +++++++++++++++++++++++------------------------ package.json | 2 +- 2 files changed, 34 insertions(+), 34 deletions(-) diff --git a/package-lock.json b/package-lock.json index 901e6b1f0..4a55cb477 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,7 +10,7 @@ "hasInstallScript": true, "license": "MIT", "dependencies": { - "@babel/core": "^7.26.9", + "@babel/core": "^7.26.10", "@babel/plugin-transform-runtime": "^7.26.10", "@babel/preset-env": "^7.26.9", "@babel/preset-react": "^7.26.3", @@ -110,21 +110,21 @@ } }, "node_modules/@babel/core": { - "version": "7.26.9", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.26.9.tgz", - "integrity": "sha512-lWBYIrF7qK5+GjY5Uy+/hEgp8OJWOD/rpy74GplYRhEauvbHDeFB8t5hPOZxCZ0Oxf4Cc36tK51/l3ymJysrKw==", + "version": "7.26.10", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.26.10.tgz", + "integrity": "sha512-vMqyb7XCDMPvJFFOaT9kxtiRh42GwlZEg1/uIgtZshS5a/8OaduUfCi7kynKgc3Tw/6Uo2D+db9qBttghhmxwQ==", "license": "MIT", "dependencies": { "@ampproject/remapping": "^2.2.0", "@babel/code-frame": "^7.26.2", - "@babel/generator": "^7.26.9", + "@babel/generator": "^7.26.10", "@babel/helper-compilation-targets": "^7.26.5", "@babel/helper-module-transforms": "^7.26.0", - "@babel/helpers": "^7.26.9", - "@babel/parser": "^7.26.9", + "@babel/helpers": "^7.26.10", + "@babel/parser": "^7.26.10", "@babel/template": "^7.26.9", - "@babel/traverse": "^7.26.9", - "@babel/types": "^7.26.9", + "@babel/traverse": "^7.26.10", + "@babel/types": "^7.26.10", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", @@ -140,13 +140,13 @@ } }, "node_modules/@babel/generator": { - "version": "7.26.9", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.26.9.tgz", - "integrity": "sha512-kEWdzjOAUMW4hAyrzJ0ZaTOu9OmpyDIQicIh0zg0EEcEkYXZb2TjtBhnHi2ViX7PKwZqF4xwqfAm299/QMP3lg==", + "version": "7.27.0", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.27.0.tgz", + "integrity": "sha512-VybsKvpiN1gU1sdMZIp7FcqphVVKEwcuj02x73uvcHE0PTihx1nlBcowYWhDwjpoAXRv43+gDzyggGnn1XZhVw==", "license": "MIT", "dependencies": { - "@babel/parser": "^7.26.9", - "@babel/types": "^7.26.9", + "@babel/parser": "^7.27.0", + "@babel/types": "^7.27.0", "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.25", "jsesc": "^3.0.2" @@ -389,12 +389,12 @@ } }, "node_modules/@babel/parser": { - "version": "7.26.9", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.26.9.tgz", - "integrity": "sha512-81NWa1njQblgZbQHxWHpxxCzNsa3ZwvFqpUg7P+NNUU6f3UU2jBEg4OlF/J6rl8+PQGh1q6/zWScd001YwcA5A==", + "version": "7.27.0", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.27.0.tgz", + "integrity": "sha512-iaepho73/2Pz7w2eMS0Q5f83+0RKI7i4xmiYeBmDzfRVbQtTOG7Ts0S4HzJVsTMGI9keU8rNfuZr8DKfSt7Yyg==", "license": "MIT", "dependencies": { - "@babel/types": "^7.26.9" + "@babel/types": "^7.27.0" }, "bin": { "parser": "bin/babel-parser.js" @@ -1687,30 +1687,30 @@ } }, "node_modules/@babel/template": { - "version": "7.26.9", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.26.9.tgz", - "integrity": "sha512-qyRplbeIpNZhmzOysF/wFMuP9sctmh2cFzRAZOn1YapxBsE1i9bJIY586R/WBLfLcmcBlM8ROBiQURnnNy+zfA==", + "version": "7.27.0", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.0.tgz", + "integrity": "sha512-2ncevenBqXI6qRMukPlXwHKHchC7RyMuu4xv5JBXRfOGVcTy1mXCD12qrp7Jsoxll1EV3+9sE4GugBVRjT2jFA==", "license": "MIT", "dependencies": { "@babel/code-frame": "^7.26.2", - "@babel/parser": "^7.26.9", - "@babel/types": "^7.26.9" + "@babel/parser": "^7.27.0", + "@babel/types": "^7.27.0" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/traverse": { - "version": "7.26.9", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.26.9.tgz", - "integrity": "sha512-ZYW7L+pL8ahU5fXmNbPF+iZFHCv5scFak7MZ9bwaRPLUhHh7QQEMjZUg0HevihoqCM5iSYHN61EyCoZvqC+bxg==", + "version": "7.27.0", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.27.0.tgz", + "integrity": "sha512-19lYZFzYVQkkHkl4Cy4WrAVcqBkgvV2YM2TU3xG6DIwO7O3ecbDPfW3yM3bjAGcqcQHi+CCtjMR3dIEHxsd6bA==", "license": "MIT", "dependencies": { "@babel/code-frame": "^7.26.2", - "@babel/generator": "^7.26.9", - "@babel/parser": "^7.26.9", - "@babel/template": "^7.26.9", - "@babel/types": "^7.26.9", + "@babel/generator": "^7.27.0", + "@babel/parser": "^7.27.0", + "@babel/template": "^7.27.0", + "@babel/types": "^7.27.0", "debug": "^4.3.1", "globals": "^11.1.0" }, @@ -1728,9 +1728,9 @@ } }, "node_modules/@babel/types": { - "version": "7.26.10", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.26.10.tgz", - "integrity": "sha512-emqcG3vHrpxUKTrxcblR36dcrcoRDvKmnL/dCL6ZsHaShW80qxCAcNhzQZrpeM765VzEos+xOi4s+r4IXzTwdQ==", + "version": "7.27.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.27.0.tgz", + "integrity": "sha512-H45s8fVLYjbhFH62dIJ3WtmJ6RSPt/3DRO0ZcT2SUiYiQyz3BLVb9ADEnLl91m74aQPS3AzzeajZHYOalWe3bg==", "license": "MIT", "dependencies": { "@babel/helper-string-parser": "^7.25.9", diff --git a/package.json b/package.json index c95ba6470..3a68d15d7 100644 --- a/package.json +++ b/package.json @@ -84,7 +84,7 @@ ] }, "dependencies": { - "@babel/core": "^7.26.9", + "@babel/core": "^7.26.10", "@babel/plugin-transform-runtime": "^7.26.10", "@babel/preset-env": "^7.26.9", "@babel/preset-react": "^7.26.3", From 225fcef291faf1d7737754c09c47cb0faaebfa42 Mon Sep 17 00:00:00 2001 From: Trevor Buckner Date: Wed, 26 Mar 2025 18:03:22 -0400 Subject: [PATCH 331/398] up Marked to v14.1.4 --- package-lock.json | 8 ++++---- package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index 4a55cb477..87d573e8e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -33,7 +33,7 @@ "jwt-simple": "^0.5.6", "less": "^3.13.1", "lodash": "^4.17.21", - "marked": "14.0.0", + "marked": "14.1.4", "marked-emoji": "^2.0.0", "marked-extended-tables": "^2.0.1", "marked-gfm-heading-id": "^4.0.1", @@ -9892,9 +9892,9 @@ } }, "node_modules/marked": { - "version": "14.0.0", - "resolved": "https://registry.npmjs.org/marked/-/marked-14.0.0.tgz", - "integrity": "sha512-uIj4+faQ+MgHgwUW1l2PsPglZLOLOT1uErt06dAPtx2kjteLAkbsd/0FiYg/MGS+i7ZKLb7w2WClxHkzOOuryQ==", + "version": "14.1.4", + "resolved": "https://registry.npmjs.org/marked/-/marked-14.1.4.tgz", + "integrity": "sha512-vkVZ8ONmUdPnjCKc5uTRvmkRbx4EAi2OkTOXmfTDhZz3OFqMNBM1oTTWwTr4HY4uAEojhzPf+Fy8F1DWa3Sndg==", "license": "MIT", "bin": { "marked": "bin/marked.js" diff --git a/package.json b/package.json index 3a68d15d7..9e2a8450d 100644 --- a/package.json +++ b/package.json @@ -107,7 +107,7 @@ "jwt-simple": "^0.5.6", "less": "^3.13.1", "lodash": "^4.17.21", - "marked": "14.0.0", + "marked": "14.1.4", "marked-emoji": "^2.0.0", "marked-extended-tables": "^2.0.1", "marked-gfm-heading-id": "^4.0.1", From 6ec37d3fa46451e8fbe2a5d155d60a06d88ad82a Mon Sep 17 00:00:00 2001 From: "G.Ambatte" Date: Thu, 27 Mar 2025 12:03:00 +1300 Subject: [PATCH 332/398] Rename HB_PageNumber to HB_pageNumber --- shared/naturalcrit/markdown.js | 4 ++-- themes/V3/Blank/snippets.js | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/shared/naturalcrit/markdown.js b/shared/naturalcrit/markdown.js index 251c8d3bc..a0a5f3a00 100644 --- a/shared/naturalcrit/markdown.js +++ b/shared/naturalcrit/markdown.js @@ -951,9 +951,9 @@ let globalPageNumber = 0; const Markdown = { marked : Marked, render : (rawBrewText, pageNumber=0)=>{ - const lastPageNumber = pageNumber > 0 ? globalVarsList[pageNumber - 1].HB_PageNumber.content : 0; + const lastPageNumber = pageNumber > 0 ? globalVarsList[pageNumber - 1].HB_pageNumber.content : 0; globalVarsList[pageNumber] = { //Reset global links for current page, to ensure values are parsed in order - 'HB_PageNumber' : { //Add document variables for this page + 'HB_pageNumber' : { //Add document variables for this page content : !isNaN(Number(lastPageNumber)) ? Number(lastPageNumber) + 1 : lastPageNumber, resolved : true } diff --git a/themes/V3/Blank/snippets.js b/themes/V3/Blank/snippets.js index 65af13aef..c5198fd87 100644 --- a/themes/V3/Blank/snippets.js +++ b/themes/V3/Blank/snippets.js @@ -41,7 +41,7 @@ module.exports = [ { name : 'Variable Auto Page Number', icon : 'fas fa-sort-numeric-down', - gen : '{{pageNumber $[HB_PageNumber]}}\n' + gen : '{{pageNumber $[HB_pageNumber]}}\n' }, { name : 'Skip Page Number Increment this Page', From 65001c44e6690b4afc35a0c12cf81b11ee5ecfff Mon Sep 17 00:00:00 2001 From: "G.Ambatte" Date: Thu, 27 Mar 2025 12:03:22 +1300 Subject: [PATCH 333/398] Add tests for variable page numbering --- tests/markdown/variables.test.js | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/tests/markdown/variables.test.js b/tests/markdown/variables.test.js index bba1341e1..1f9d8b55a 100644 --- a/tests/markdown/variables.test.js +++ b/tests/markdown/variables.test.js @@ -370,6 +370,22 @@ describe('Cross-page variables', ()=>{ const rendered = renderAllPages([source0, source1]).join('\n\\page\n').trimReturns(); expect(rendered, `Input:\n${[source0, source1].join('\n\\page\n')}`, { showPrefix: false }).toBe('

    two

    one

    \\page

    two

    '); }); + + it('Page numbering across pages', function() { + const source0 = `$[HB_pageNumber]\n\n`; + const source1 = `$[HB_pageNumber]\n\n`; + renderAllPages([source0, source1]).join('\n\\page\n').trimReturns(); //Requires one full render of document before hoisting is picked up + const rendered = renderAllPages([source0, source1]).join('\n\\page\n').trimReturns(); + expect(rendered, `Input:\n${[source0, source1].join('\n\\page\n')}`, { showPrefix: false }).toBe('

    1

    \\page

    2

    '); + }); + + it('Page numbering across pages - custom page number', function() { + const source0 = `[HB_pageNumber]:100\n\n$[HB_pageNumber]\n\n`; + const source1 = `$[HB_pageNumber]\n\n`; + renderAllPages([source0, source1]).join('\n\\page\n').trimReturns(); //Requires one full render of document before hoisting is picked up + const rendered = renderAllPages([source0, source1]).join('\n\\page\n').trimReturns(); + expect(rendered, `Input:\n${[source0, source1].join('\n\\page\n')}`, { showPrefix: false }).toBe('

    100

    \\page

    101

    '); + }); }); describe('Math function parameter handling', ()=>{ @@ -410,7 +426,7 @@ describe('Regression Tests', ()=>{ const rendered = Markdown.render(source).trimReturns(); expect(rendered).toBe('
    title 1title 2title 3title 4
    fooIpsum))
    '); }); - + it('Handle Extra spaces in image alt-text 1', function(){ const source='![ where is my image??](http://i.imgur.com/hMna6G0.png)'; const rendered = Markdown.render(source).trimReturns(); @@ -433,7 +449,7 @@ describe('Regression Tests', ()=>{ const source='![where is my image??](http://i.imgur.com/hMna6G0.png){height=20%,width=20%}'; const rendered = Markdown.render(source).trimReturns(); expect(rendered).toBe('

    \"where

    '); - }); + }); }); describe('Custom Math Function Tests', ()=>{ From 848c68689d2741e23a4657bd3d4941fe631e2b32 Mon Sep 17 00:00:00 2001 From: "G.Ambatte" Date: Thu, 27 Mar 2025 12:09:58 +1300 Subject: [PATCH 334/398] Add NaN custom pageNumber test --- tests/markdown/variables.test.js | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/tests/markdown/variables.test.js b/tests/markdown/variables.test.js index 1f9d8b55a..ea98fe56c 100644 --- a/tests/markdown/variables.test.js +++ b/tests/markdown/variables.test.js @@ -371,7 +371,7 @@ describe('Cross-page variables', ()=>{ expect(rendered, `Input:\n${[source0, source1].join('\n\\page\n')}`, { showPrefix: false }).toBe('

    two

    one

    \\page

    two

    '); }); - it('Page numbering across pages', function() { + it('Page numbering across pages : default', function() { const source0 = `$[HB_pageNumber]\n\n`; const source1 = `$[HB_pageNumber]\n\n`; renderAllPages([source0, source1]).join('\n\\page\n').trimReturns(); //Requires one full render of document before hoisting is picked up @@ -379,13 +379,21 @@ describe('Cross-page variables', ()=>{ expect(rendered, `Input:\n${[source0, source1].join('\n\\page\n')}`, { showPrefix: false }).toBe('

    1

    \\page

    2

    '); }); - it('Page numbering across pages - custom page number', function() { + it('Page numbering across pages : custom page number (Number)', function() { const source0 = `[HB_pageNumber]:100\n\n$[HB_pageNumber]\n\n`; const source1 = `$[HB_pageNumber]\n\n`; renderAllPages([source0, source1]).join('\n\\page\n').trimReturns(); //Requires one full render of document before hoisting is picked up const rendered = renderAllPages([source0, source1]).join('\n\\page\n').trimReturns(); expect(rendered, `Input:\n${[source0, source1].join('\n\\page\n')}`, { showPrefix: false }).toBe('

    100

    \\page

    101

    '); }); + + it('Page numbering across pages : custom page number (NaN)', function() { + const source0 = `[HB_pageNumber]:a\n\n$[HB_pageNumber]\n\n`; + const source1 = `$[HB_pageNumber]\n\n`; + renderAllPages([source0, source1]).join('\n\\page\n').trimReturns(); //Requires one full render of document before hoisting is picked up + const rendered = renderAllPages([source0, source1]).join('\n\\page\n').trimReturns(); + expect(rendered, `Input:\n${[source0, source1].join('\n\\page\n')}`, { showPrefix: false }).toBe('

    a

    \\page

    a

    '); + }); }); describe('Math function parameter handling', ()=>{ From eac87b65d8b8804bfd50d232f699919b7ea2c637 Mon Sep 17 00:00:00 2001 From: Trevor Buckner Date: Wed, 26 Mar 2025 19:26:20 -0400 Subject: [PATCH 335/398] Update tests and custom link renderer v15 changes where html gets escaped and escapes plain text more consistently. Needed to update tests to match. --- package-lock.json | 8 ++++---- package.json | 2 +- shared/naturalcrit/markdown.js | 2 +- tests/markdown/non-breaking-spaces.test.js | 6 +++--- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/package-lock.json b/package-lock.json index 87d573e8e..9ce7a789b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -33,7 +33,7 @@ "jwt-simple": "^0.5.6", "less": "^3.13.1", "lodash": "^4.17.21", - "marked": "14.1.4", + "marked": "15.0.0", "marked-emoji": "^2.0.0", "marked-extended-tables": "^2.0.1", "marked-gfm-heading-id": "^4.0.1", @@ -9892,9 +9892,9 @@ } }, "node_modules/marked": { - "version": "14.1.4", - "resolved": "https://registry.npmjs.org/marked/-/marked-14.1.4.tgz", - "integrity": "sha512-vkVZ8ONmUdPnjCKc5uTRvmkRbx4EAi2OkTOXmfTDhZz3OFqMNBM1oTTWwTr4HY4uAEojhzPf+Fy8F1DWa3Sndg==", + "version": "15.0.0", + "resolved": "https://registry.npmjs.org/marked/-/marked-15.0.0.tgz", + "integrity": "sha512-0mouKmBROJv/WSHJBPZZyYofUgawMChnD5je/g+aOBXsHDjb/IsnTQj7mnhQZu+qPJmRQ0ecX3mLGEUm3BgwYA==", "license": "MIT", "bin": { "marked": "bin/marked.js" diff --git a/package.json b/package.json index 9e2a8450d..36471950a 100644 --- a/package.json +++ b/package.json @@ -107,7 +107,7 @@ "jwt-simple": "^0.5.6", "less": "^3.13.1", "lodash": "^4.17.21", - "marked": "14.1.4", + "marked": "15.0.0", "marked-emoji": "^2.0.0", "marked-extended-tables": "^2.0.1", "marked-gfm-heading-id": "^4.0.1", diff --git a/shared/naturalcrit/markdown.js b/shared/naturalcrit/markdown.js index 0b90c051c..485aa281f 100644 --- a/shared/naturalcrit/markdown.js +++ b/shared/naturalcrit/markdown.js @@ -104,7 +104,7 @@ renderer.link = function (token) { } let out = `{ test('I am actually a single-line definition list!', function() { const source = 'Term ::> Definition 1\n'; const rendered = Markdown.render(source).trim(); - expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe(`
    Term
    > Definition 1
    \n
    `); + expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe(`
    Term
    > Definition 1
    \n
    `); }); test('I am actually a definition list!', function() { const source = 'Term\n::> Definition 1\n'; const rendered = Markdown.render(source).trim(); - expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe(`
    Term
    \n
    > Definition 1
    `); + expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe(`
    Term
    \n
    > Definition 1
    `); }); test('I am actually a two-term definition list!', function() { const source = 'Term\n::> Definition 1\n::>> Definition 2'; const rendered = Markdown.render(source).trim(); - expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe(`
    Term
    \n
    > Definition 1
    \n
    >> Definition 2
    `); + expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe(`
    Term
    \n
    > Definition 1
    \n
    >> Definition 2
    `); }); }); From 8729407da6a8fe39051bdc159e6828b8061e89f1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 27 Mar 2025 03:39:34 +0000 Subject: [PATCH 336/398] Bump stylelint from 16.16.0 to 16.17.0 Bumps [stylelint](https://github.com/stylelint/stylelint) from 16.16.0 to 16.17.0. - [Release notes](https://github.com/stylelint/stylelint/releases) - [Changelog](https://github.com/stylelint/stylelint/blob/main/CHANGELOG.md) - [Commits](https://github.com/stylelint/stylelint/compare/16.16.0...16.17.0) --- updated-dependencies: - dependency-name: stylelint dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- package-lock.json | 8 ++++---- package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index 9ce7a789b..eccc537ff 100644 --- a/package-lock.json +++ b/package-lock.json @@ -63,7 +63,7 @@ "jest-expect-message": "^1.1.3", "jsdom-global": "^3.0.2", "postcss-less": "^6.0.0", - "stylelint": "^16.16.0", + "stylelint": "^16.17.0", "stylelint-config-recess-order": "^6.0.0", "stylelint-config-recommended": "^15.0.0", "supertest": "^7.1.0" @@ -13127,9 +13127,9 @@ "license": "ISC" }, "node_modules/stylelint": { - "version": "16.16.0", - "resolved": "https://registry.npmjs.org/stylelint/-/stylelint-16.16.0.tgz", - "integrity": "sha512-40X5UOb/0CEFnZVEHyN260HlSSUxPES+arrUphOumGWgXERHfwCD0kNBVILgQSij8iliYVwlc0V7M5bcLP9vPg==", + "version": "16.17.0", + "resolved": "https://registry.npmjs.org/stylelint/-/stylelint-16.17.0.tgz", + "integrity": "sha512-I9OwVIWRMqVm2Br5iTbrfSqGRPWQUlvm6oXO1xZuYYu0Gpduy67N8wXOZv15p6E/JdlZiAtQaIoLKZEWk5hrjw==", "dev": true, "funding": [ { diff --git a/package.json b/package.json index 36471950a..94ac51006 100644 --- a/package.json +++ b/package.json @@ -137,7 +137,7 @@ "jest-expect-message": "^1.1.3", "jsdom-global": "^3.0.2", "postcss-less": "^6.0.0", - "stylelint": "^16.16.0", + "stylelint": "^16.17.0", "stylelint-config-recess-order": "^6.0.0", "stylelint-config-recommended": "^15.0.0", "supertest": "^7.1.0" From ac89f428b2824425a0ee9e3106d7d6127c167ac8 Mon Sep 17 00:00:00 2001 From: "G.Ambatte" Date: Thu, 27 Mar 2025 18:25:56 +1300 Subject: [PATCH 337/398] Post merge fixes --- client/admin/admin.jsx | 6 +++--- client/admin/lockTools/lockTools.jsx | 4 ++-- client/homebrew/utils/request-middleware.js | 4 ++-- server/admin.api.js | 2 ++ 4 files changed, 9 insertions(+), 7 deletions(-) diff --git a/client/admin/admin.jsx b/client/admin/admin.jsx index 025d78abf..f59162e1d 100644 --- a/client/admin/admin.jsx +++ b/client/admin/admin.jsx @@ -3,9 +3,9 @@ import React, { useEffect, useState } from 'react'; const BrewUtils = require('./brewUtils/brewUtils.jsx'); const NotificationUtils = require('./notificationUtils/notificationUtils.jsx'); import AuthorUtils from './authorUtils/authorUtils.jsx'; -const LockTools = require('./lockTools/lockTools.jsx'); +import LockTools from './lockTools/lockTools.jsx'; -const tabGroups = ['brew', 'notifications', 'authors']; +const tabGroups = ['brew', 'notifications', 'authors', 'locks']; const Admin = ()=>{ const [currentTab, setCurrentTab] = useState('brew'); @@ -41,7 +41,7 @@ const Admin = ()=>{ {currentTab === 'brew' && } {currentTab === 'notifications' && } {currentTab === 'authors' && } - {currentTab === 'locks' && } + {currentTab === 'locks' && }
    ); diff --git a/client/admin/lockTools/lockTools.jsx b/client/admin/lockTools/lockTools.jsx index b5c94399a..5f8a4ba39 100644 --- a/client/admin/lockTools/lockTools.jsx +++ b/client/admin/lockTools/lockTools.jsx @@ -4,7 +4,7 @@ const React = require('react'); const createClass = require('create-react-class'); // const request = require('superagent'); -const request = require('../../homebrew/utils/request-middleware.js'); +import request from '../../homebrew/utils/request-middleware.js'; const LockTools = createClass({ getInitialState : function() { @@ -226,7 +226,7 @@ const LockTable = createClass({ ; })} {navigator.clipboard.writeText(result.shareId.toString());}}> - + ; })} diff --git a/client/homebrew/utils/request-middleware.js b/client/homebrew/utils/request-middleware.js index 22609dadb..deb08d265 100644 --- a/client/homebrew/utils/request-middleware.js +++ b/client/homebrew/utils/request-middleware.js @@ -1,8 +1,8 @@ -const version = require('../../../package.json').version; +import packageJSON from '../../../package.json' with { type: 'json' }; import request from 'superagent'; -const addHeader = (request)=>request.set('Homebrewery-Version', version); +const addHeader = (request)=>request.set('Homebrewery-Version', packageJSON.version); const requestMiddleware = { get : (path)=>addHeader(request.get(path)), diff --git a/server/admin.api.js b/server/admin.api.js index 3685492d5..96a21c8a7 100644 --- a/server/admin.api.js +++ b/server/admin.api.js @@ -305,6 +305,8 @@ router.put('/api/lock/review/remove/:id', mw.adminOnly, async (req, res)=>{ } catch (error) { console.error(error); return res.json({ status: 'ERROR', detail: `Unable to remove request for review on brew ID ${req.params.id}`, error }); + }; +}); // ####################### NOTIFICATIONS From 7525e087ff0264f9ae28508b2b3f3619a3528511 Mon Sep 17 00:00:00 2001 From: David Bolack Date: Sat, 29 Mar 2025 18:47:03 -0500 Subject: [PATCH 338/398] Regression Fix WIP --- client/homebrew/editor/snippetbar/snippetbar.jsx | 9 +++------ client/homebrew/pages/editPage/editPage.jsx | 1 + client/homebrew/pages/homePage/homePage.jsx | 3 ++- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/client/homebrew/editor/snippetbar/snippetbar.jsx b/client/homebrew/editor/snippetbar/snippetbar.jsx index c8c8fb590..ac3062ecf 100644 --- a/client/homebrew/editor/snippetbar/snippetbar.jsx +++ b/client/homebrew/editor/snippetbar/snippetbar.jsx @@ -101,10 +101,11 @@ const Snippetbar = createClass({ if(key == 'snippets') { const result = _.reverse(_.unionBy(_.reverse(newValue), _.reverse(oldValue), 'name')); // Join snippets together, with preference for the child theme over the parent theme return result.filter((snip)=>snip.gen || snip.subsnippets); - } + }; }, compileSnippets : function() { + console.log('compileSnippets'); let compiledSnippets = []; let oldSnippets = _.keyBy(compiledSnippets, 'groupName'); @@ -122,6 +123,7 @@ const Snippetbar = createClass({ } const userSnippetsasJSON = brewSnippetsToJSON(this.props.brew.title || 'New Document', this.props.brew.snippets, this.props.themeBundle.snippets); + console.log(userSnippetsasJSON); compiledSnippets.push(userSnippetsasJSON); return compiledSnippets; @@ -283,11 +285,6 @@ const Snippetbar = createClass({ module.exports = Snippetbar; - - - - - const SnippetGroup = createClass({ displayName : 'SnippetGroup', getDefaultProps : function() { diff --git a/client/homebrew/pages/editPage/editPage.jsx b/client/homebrew/pages/editPage/editPage.jsx index b209e7ef7..a4d8a1ed4 100644 --- a/client/homebrew/pages/editPage/editPage.jsx +++ b/client/homebrew/pages/editPage/editPage.jsx @@ -451,6 +451,7 @@ const EditPage = createClass({ }, render : function(){ + console.log(this.state.themeBundle); return
    {this.renderNavbar()} diff --git a/client/homebrew/pages/homePage/homePage.jsx b/client/homebrew/pages/homePage/homePage.jsx index b9c1b7371..47cb23d50 100644 --- a/client/homebrew/pages/homePage/homePage.jsx +++ b/client/homebrew/pages/homePage/homePage.jsx @@ -97,6 +97,7 @@ const HomePage = createClass({ }, render : function(){ + console.log(this.state.themeBundle); return
    {this.renderNavbar()} @@ -108,7 +109,7 @@ const HomePage = createClass({ onTextChange={this.handleTextChange} renderer={this.state.brew.renderer} showEditButtons={false} - snippetBundle={this.state.themeBundle.snippets} + themeBundle={this.state.themeBundle} onCursorPageChange={this.handleEditorCursorPageChange} onViewPageChange={this.handleEditorViewPageChange} currentEditorViewPageNum={this.state.currentEditorViewPageNum} From 9d1601f4244813407321ba6bfc24946644e530a6 Mon Sep 17 00:00:00 2001 From: David Bolack Date: Sat, 29 Mar 2025 19:14:10 -0500 Subject: [PATCH 339/398] Seems to be working - no idea why... --- client/homebrew/editor/snippetbar/snippetbar.jsx | 2 -- client/homebrew/pages/editPage/editPage.jsx | 1 - client/homebrew/pages/homePage/homePage.jsx | 1 - 3 files changed, 4 deletions(-) diff --git a/client/homebrew/editor/snippetbar/snippetbar.jsx b/client/homebrew/editor/snippetbar/snippetbar.jsx index ac3062ecf..8c6872ab4 100644 --- a/client/homebrew/editor/snippetbar/snippetbar.jsx +++ b/client/homebrew/editor/snippetbar/snippetbar.jsx @@ -105,7 +105,6 @@ const Snippetbar = createClass({ }, compileSnippets : function() { - console.log('compileSnippets'); let compiledSnippets = []; let oldSnippets = _.keyBy(compiledSnippets, 'groupName'); @@ -123,7 +122,6 @@ const Snippetbar = createClass({ } const userSnippetsasJSON = brewSnippetsToJSON(this.props.brew.title || 'New Document', this.props.brew.snippets, this.props.themeBundle.snippets); - console.log(userSnippetsasJSON); compiledSnippets.push(userSnippetsasJSON); return compiledSnippets; diff --git a/client/homebrew/pages/editPage/editPage.jsx b/client/homebrew/pages/editPage/editPage.jsx index a4d8a1ed4..b209e7ef7 100644 --- a/client/homebrew/pages/editPage/editPage.jsx +++ b/client/homebrew/pages/editPage/editPage.jsx @@ -451,7 +451,6 @@ const EditPage = createClass({ }, render : function(){ - console.log(this.state.themeBundle); return
    {this.renderNavbar()} diff --git a/client/homebrew/pages/homePage/homePage.jsx b/client/homebrew/pages/homePage/homePage.jsx index 47cb23d50..d03e30c91 100644 --- a/client/homebrew/pages/homePage/homePage.jsx +++ b/client/homebrew/pages/homePage/homePage.jsx @@ -97,7 +97,6 @@ const HomePage = createClass({ }, render : function(){ - console.log(this.state.themeBundle); return
    {this.renderNavbar()} From 2ce7c6c2be86e89b22e794472e5da344d1234459 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Losada=20Hern=C3=A1ndez?= Date: Mon, 31 Mar 2025 00:14:03 +0200 Subject: [PATCH 340/398] css breakpoint changed --- client/homebrew/editor/snippetbar/snippetbar.less | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/homebrew/editor/snippetbar/snippetbar.less b/client/homebrew/editor/snippetbar/snippetbar.less index 7a39173e6..5c98ccfda 100644 --- a/client/homebrew/editor/snippetbar/snippetbar.less +++ b/client/homebrew/editor/snippetbar/snippetbar.less @@ -237,7 +237,7 @@ } } -@container editor (width < 553px) { +@container editor (width < 681px) { .snippetBar { .editors { flex : 1; From b9b45632b0ac714ab948268f37ad2facd728c92e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Losada=20Hern=C3=A1ndez?= Date: Mon, 31 Mar 2025 00:19:43 +0200 Subject: [PATCH 341/398] fix package-lock --- package-lock.json | 123 +++++++++++++++++++++++----------------------- 1 file changed, 62 insertions(+), 61 deletions(-) diff --git a/package-lock.json b/package-lock.json index 2d060d210..450d4e364 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,11 +10,11 @@ "hasInstallScript": true, "license": "MIT", "dependencies": { - "@babel/core": "^7.26.9", - "@babel/plugin-transform-runtime": "^7.26.9", + "@babel/core": "^7.26.10", + "@babel/plugin-transform-runtime": "^7.26.10", "@babel/preset-env": "^7.26.9", "@babel/preset-react": "^7.26.3", - "@googleapis/drive": "^8.16.0", + "@googleapis/drive": "^11.0.0", "body-parser": "^1.20.2", "classnames": "^2.5.1", "codemirror": "^5.65.6", @@ -33,7 +33,7 @@ "jwt-simple": "^0.5.6", "less": "^3.13.1", "lodash": "^4.17.21", - "marked": "14.0.0", + "marked": "15.0.0", "marked-emoji": "^2.0.0", "marked-extended-tables": "^2.0.1", "marked-gfm-heading-id": "^4.0.1", @@ -41,21 +41,21 @@ "marked-subsuper-text": "^1.0.3", "markedLegacy": "npm:marked@^0.3.19", "moment": "^2.30.1", - "mongoose": "^8.12.1", - "nanoid": "5.1.3", + "mongoose": "^8.13.0", + "nanoid": "5.1.5", "nconf": "^0.12.1", "react": "^18.3.1", "react-dom": "^18.3.1", "react-frame-component": "^4.1.3", - "react-router": "^7.3.0", + "react-router": "^7.4.0", "sanitize-filename": "1.6.3", - "superagent": "^10.1.1", + "superagent": "^10.2.0", "vitreum": "git+https://git@github.com/calculuschild/vitreum.git" }, "devDependencies": { "@stylistic/stylelint-plugin": "^3.1.2", "babel-plugin-transform-import-meta": "^2.3.2", - "eslint": "^9.22.0", + "eslint": "^9.23.0", "eslint-plugin-jest": "^28.11.0", "eslint-plugin-react": "^7.37.4", "globals": "^16.0.0", @@ -63,10 +63,10 @@ "jest-expect-message": "^1.1.3", "jsdom-global": "^3.0.2", "postcss-less": "^6.0.0", - "stylelint": "^16.16.0", + "stylelint": "^16.17.0", "stylelint-config-recess-order": "^6.0.0", "stylelint-config-recommended": "^15.0.0", - "supertest": "^7.0.0" + "supertest": "^7.1.0" }, "engines": { "node": "^20.18.x", @@ -1863,9 +1863,9 @@ } }, "node_modules/@eslint/config-helpers": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.1.0.tgz", - "integrity": "sha512-kLrdPDJE1ckPo94kmPPf9Hfd0DU0Jw6oKYrhe+pwSC0iTUInmTa+w6fw8sGgcfkFJGNdWOUeOaDM4quW4a7OkA==", + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.2.0.tgz", + "integrity": "sha512-yJLLmLexii32mGrhW29qvU3QBVTu0GUmEf/J4XsBtVhp4JkIUFN/BjWqTF63yRvGApIDpZm5fa97LtYtINmfeQ==", "dev": true, "license": "Apache-2.0", "engines": { @@ -1886,9 +1886,9 @@ } }, "node_modules/@eslint/eslintrc": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.0.tgz", - "integrity": "sha512-yaVPAiNAalnCZedKLdR21GOGILMLKPyqSLWaAjQFvYA2i/ciDi8ArYVr69Anohb6cH2Ukhqti4aFnYyPm8wdwQ==", + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.1.tgz", + "integrity": "sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==", "dev": true, "license": "MIT", "dependencies": { @@ -1923,9 +1923,9 @@ } }, "node_modules/@eslint/js": { - "version": "9.22.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.22.0.tgz", - "integrity": "sha512-vLFajx9o8d1/oL2ZkpMYbkLv8nDB6yaIwFNt7nI4+I80U/z03SxmfOMsLbvWr3p7C+Wnoh//aOu2pQW8cS0HCQ==", + "version": "9.23.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.23.0.tgz", + "integrity": "sha512-35MJ8vCPU0ZMxo7zfev2pypqTwWTofFZO6m4KAtdoFhRpLJUpHTZZ+KB3C7Hb1d7bULYwO4lJXGCi5Se+8OMbw==", "dev": true, "license": "MIT", "engines": { @@ -1957,9 +1957,9 @@ } }, "node_modules/@googleapis/drive": { - "version": "8.16.0", - "resolved": "https://registry.npmjs.org/@googleapis/drive/-/drive-8.16.0.tgz", - "integrity": "sha512-Xi2mMrUTQ+gsfyouRGd0pfnL+jjg4n4sjKsJruM1y4DknuRfdSBTk5E//WrL0YJ/CqpcBgyd7L8DvaPRtxZD3Q==", + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/@googleapis/drive/-/drive-11.0.0.tgz", + "integrity": "sha512-vhkl6/MZ8k5h5XOyenWOD4ys+SNdb8wKYvzU6OBGFx/TzJyHRm4JwgvE8uVDFU6efzNRS0mOiNRfY6nrmHOTtg==", "license": "Apache-2.0", "dependencies": { "googleapis-common": "^7.0.0" @@ -5690,19 +5690,19 @@ "license": "MIT" }, "node_modules/eslint": { - "version": "9.22.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.22.0.tgz", - "integrity": "sha512-9V/QURhsRN40xuHXWjV64yvrzMjcz7ZyNoF2jJFmy9j/SLk0u1OLSZgXi28MrXjymnjEGSR80WCdab3RGMDveQ==", + "version": "9.23.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.23.0.tgz", + "integrity": "sha512-jV7AbNoFPAY1EkFYpLq5bslU9NLNO8xnEeQXwErNibVryjk67wHVmddTBilc5srIttJDBrB0eMHKZBFbSIABCw==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.12.1", "@eslint/config-array": "^0.19.2", - "@eslint/config-helpers": "^0.1.0", + "@eslint/config-helpers": "^0.2.0", "@eslint/core": "^0.12.0", - "@eslint/eslintrc": "^3.3.0", - "@eslint/js": "9.22.0", + "@eslint/eslintrc": "^3.3.1", + "@eslint/js": "9.23.0", "@eslint/plugin-kit": "^0.2.7", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", @@ -9915,9 +9915,9 @@ } }, "node_modules/marked": { - "version": "14.0.0", - "resolved": "https://registry.npmjs.org/marked/-/marked-14.0.0.tgz", - "integrity": "sha512-uIj4+faQ+MgHgwUW1l2PsPglZLOLOT1uErt06dAPtx2kjteLAkbsd/0FiYg/MGS+i7ZKLb7w2WClxHkzOOuryQ==", + "version": "15.0.0", + "resolved": "https://registry.npmjs.org/marked/-/marked-15.0.0.tgz", + "integrity": "sha512-0mouKmBROJv/WSHJBPZZyYofUgawMChnD5je/g+aOBXsHDjb/IsnTQj7mnhQZu+qPJmRQ0ecX3mLGEUm3BgwYA==", "license": "MIT", "bin": { "marked": "bin/marked.js" @@ -10297,9 +10297,9 @@ } }, "node_modules/mongodb-connection-string-url/node_modules/tr46": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-5.0.0.tgz", - "integrity": "sha512-tk2G5R2KRwBd+ZN0zaEXpmzdKyOYksXwywulIX95MBODjSzMIuQnQ3m8JxgbhnL1LeVo7lqQKsYa1O3Htl7K5g==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-5.1.0.tgz", + "integrity": "sha512-IUWnUK7ADYR5Sl1fZlO1INDUhVhatWl7BtJWsIhwJ0UAK7ilzzIa8uIqOO/aYVWHZPJkKbEL+362wrzoeRF7bw==", "license": "MIT", "dependencies": { "punycode": "^2.3.1" @@ -10318,12 +10318,12 @@ } }, "node_modules/mongodb-connection-string-url/node_modules/whatwg-url": { - "version": "14.1.1", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-14.1.1.tgz", - "integrity": "sha512-mDGf9diDad/giZ/Sm9Xi2YcyzaFpbdLpJPr+E9fSkyQ7KpQD4SdFcugkRQYzhmfI4KeV4Qpnn2sKPdo+kmsgRQ==", + "version": "14.2.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-14.2.0.tgz", + "integrity": "sha512-De72GdQZzNTUBBChsXueQUnPKDkg/5A5zp7pFDuQAj5UFoENpiACU0wlCvzpAGnTkj++ihpKwKyYewn/XNUbKw==", "license": "MIT", "dependencies": { - "tr46": "^5.0.0", + "tr46": "^5.1.0", "webidl-conversions": "^7.0.0" }, "engines": { @@ -10331,14 +10331,14 @@ } }, "node_modules/mongoose": { - "version": "8.12.1", - "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-8.12.1.tgz", - "integrity": "sha512-UW22y8QFVYmrb36hm8cGncfn4ARc/XsYWQwRTaj0gxtQk1rDuhzDO1eBantS+hTTatfAIS96LlRCJrcNHvW5+Q==", + "version": "8.13.1", + "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-8.13.1.tgz", + "integrity": "sha512-sRqlXI+6jhr9/KicCOjet1VVPONFsOxTrh14tfueX5y3GJ2ihswc5ewUUojuwdSS/5koGXLIPmGivDSApVXflA==", "license": "MIT", "dependencies": { "bson": "^6.10.3", "kareem": "2.6.3", - "mongodb": "~6.14.0", + "mongodb": "~6.15.0", "mpath": "0.9.0", "mquery": "5.0.0", "ms": "2.1.3", @@ -10414,9 +10414,9 @@ } }, "node_modules/mongoose/node_modules/mongodb": { - "version": "6.14.2", - "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-6.14.2.tgz", - "integrity": "sha512-kMEHNo0F3P6QKDq17zcDuPeaywK/YaJVCEQRzPF3TOM/Bl9MFg64YE5Tu7ifj37qZJMhwU1tl2Ioivws5gRG5Q==", + "version": "6.15.0", + "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-6.15.0.tgz", + "integrity": "sha512-ifBhQ0rRzHDzqp9jAQP6OwHSH7dbYIQjD3SbJs9YYk9AikKEettW/9s/tbSFDTpXcRbF+u1aLrhHxDFaYtZpFQ==", "license": "Apache-2.0", "dependencies": { "@mongodb-js/saslprep": "^1.1.9", @@ -10493,9 +10493,9 @@ "optional": true }, "node_modules/nanoid": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-5.1.3.tgz", - "integrity": "sha512-zAbEOEr7u2CbxwoMRlz/pNSpRP0FdAU4pRaYunCdEezWohXFs+a0Xw7RfkKaezMsmSM1vttcLthJtwRnVtOfHQ==", + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-5.1.5.tgz", + "integrity": "sha512-Ir/+ZpE9fDsNH0hQ3C68uyThDXzYcim2EqcZ8zn8Chtt1iylPT9xXJB0kPCnqzgcEGikO9RxSrh63MsmVCU7Fw==", "funding": [ { "type": "github", @@ -11770,9 +11770,9 @@ "license": "MIT" }, "node_modules/react-router": { - "version": "7.3.0", - "resolved": "https://registry.npmjs.org/react-router/-/react-router-7.3.0.tgz", - "integrity": "sha512-466f2W7HIWaNXTKM5nHTqNxLrHTyXybm7R0eBlVSt0k/u55tTCDO194OIx/NrYD4TS5SXKTNekXfT37kMKUjgw==", + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-7.4.1.tgz", + "integrity": "sha512-Vmizn9ZNzxfh3cumddqv3kLOKvc7AskUT0dC1prTabhiEi0U4A33LmkDOJ79tXaeSqCqMBXBU/ySX88W85+EUg==", "license": "MIT", "dependencies": { "@types/cookie": "^0.6.0", @@ -13169,9 +13169,9 @@ "license": "ISC" }, "node_modules/stylelint": { - "version": "16.16.0", - "resolved": "https://registry.npmjs.org/stylelint/-/stylelint-16.16.0.tgz", - "integrity": "sha512-40X5UOb/0CEFnZVEHyN260HlSSUxPES+arrUphOumGWgXERHfwCD0kNBVILgQSij8iliYVwlc0V7M5bcLP9vPg==", + "version": "16.17.0", + "resolved": "https://registry.npmjs.org/stylelint/-/stylelint-16.17.0.tgz", + "integrity": "sha512-I9OwVIWRMqVm2Br5iTbrfSqGRPWQUlvm6oXO1xZuYYu0Gpduy67N8wXOZv15p6E/JdlZiAtQaIoLKZEWk5hrjw==", "dev": true, "funding": [ { @@ -13428,9 +13428,10 @@ } }, "node_modules/superagent": { - "version": "10.1.1", - "resolved": "https://registry.npmjs.org/superagent/-/superagent-10.1.1.tgz", - "integrity": "sha512-9pIwrHrOj3uAnqg9gDlW7EA2xv+N5au/dSM0kM22HTqmUu8jBxNT+8uA7tA3UoCnmiqzpSbu8rasIUZvbyamMQ==", + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/superagent/-/superagent-10.2.0.tgz", + "integrity": "sha512-IKeoGox6oG9zyDeizaezkJ2/aK0wc5la9st7WsAKyrAkfJ56W3whVbVtF68k6wuc87/y9T85NyON5FLz7Mrzzw==", + "license": "MIT", "dependencies": { "component-emitter": "^1.3.0", "cookiejar": "^2.1.4", @@ -13459,9 +13460,9 @@ } }, "node_modules/supertest": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/supertest/-/supertest-7.0.0.tgz", - "integrity": "sha512-qlsr7fIC0lSddmA3tzojvzubYxvlGtzumcdHgPwbFWMISQwL22MhM2Y3LNt+6w9Yyx7559VW5ab70dgphm8qQA==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/supertest/-/supertest-7.1.0.tgz", + "integrity": "sha512-5QeSO8hSrKghtcWEoPiO036fxH0Ii2wVQfFZSP0oqQhmjk8bOLhDFXr4JrvaFmPuEWUoq4znY3uSi8UzLKxGqw==", "dev": true, "license": "MIT", "dependencies": { From de1773361ae0d0f2977e221c0e3a7fe9feb597e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Losada=20Hern=C3=A1ndez?= Date: Mon, 31 Mar 2025 00:40:00 +0200 Subject: [PATCH 342/398] final css fix --- client/homebrew/editor/snippetbar/snippetbar.less | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/client/homebrew/editor/snippetbar/snippetbar.less b/client/homebrew/editor/snippetbar/snippetbar.less index 5c98ccfda..d7c8d3847 100644 --- a/client/homebrew/editor/snippetbar/snippetbar.less +++ b/client/homebrew/editor/snippetbar/snippetbar.less @@ -14,13 +14,13 @@ .snippets { display : flex; justify-content : flex-start; - min-width : 327.58px; + min-width : 432.18px; //must be controlled every time an item is added, must be hardcoded for the wrapping as it is applied } .editors { display : flex; justify-content : flex-end; - min-width : 225px; + min-width : 250px; //must be controlled every time an item is added, must be hardcoded for the wrapping as it is applied &:only-child {min-width : unset; margin-left : auto;} @@ -237,7 +237,7 @@ } } -@container editor (width < 681px) { +@container editor (width < 682px) { .snippetBar { .editors { flex : 1; From f5fc106d0184660fea8a2c13c99d6e1289789963 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Losada=20Hern=C3=A1ndez?= Date: Mon, 31 Mar 2025 00:52:41 +0200 Subject: [PATCH 343/398] pixel frame fix --- client/homebrew/editor/snippetbar/snippetbar.less | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/homebrew/editor/snippetbar/snippetbar.less b/client/homebrew/editor/snippetbar/snippetbar.less index d7c8d3847..a0691f8b6 100644 --- a/client/homebrew/editor/snippetbar/snippetbar.less +++ b/client/homebrew/editor/snippetbar/snippetbar.less @@ -237,7 +237,7 @@ } } -@container editor (width < 682px) { +@container editor (width < 683px) { .snippetBar { .editors { flex : 1; From 4eeaa7c650e7becbca773833c0a1efcea0779e9e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Losada=20Hern=C3=A1ndez?= Date: Mon, 31 Mar 2025 17:11:25 +0200 Subject: [PATCH 344/398] default text for snippet tab --- client/homebrew/editor/editor.jsx | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/client/homebrew/editor/editor.jsx b/client/homebrew/editor/editor.jsx index 7800717d5..411476131 100644 --- a/client/homebrew/editor/editor.jsx +++ b/client/homebrew/editor/editor.jsx @@ -22,7 +22,13 @@ const DEFAULT_STYLE_TEXT = dedent` color: black; }`; -const DEFAULT_SNIPPET_TEXT = ``; +const DEFAULT_SNIPPET_TEXT = dedent` + \snippet example snippet + + The text between \`\snippet title\` lines will become a snippet of name \`title\` as this example provides. + + This snippet is accessible in the brew tab, and will be inherited if the brew is used as a theme. +`; let isJumping = false; const Editor = createClass({ From 8e8f520eaaed2b8929b8e7a19905890912ea4399 Mon Sep 17 00:00:00 2001 From: David Bolack Date: Mon, 31 Mar 2025 20:50:54 -0500 Subject: [PATCH 345/398] Fix Highlighting issue with new brew sample snippets --- client/homebrew/editor/editor.jsx | 32 +++++++++++++------------------ 1 file changed, 13 insertions(+), 19 deletions(-) diff --git a/client/homebrew/editor/editor.jsx b/client/homebrew/editor/editor.jsx index 411476131..7112aa4b9 100644 --- a/client/homebrew/editor/editor.jsx +++ b/client/homebrew/editor/editor.jsx @@ -13,6 +13,7 @@ const MetadataEditor = require('./metadataEditor/metadataEditor.jsx'); const EDITOR_THEME_KEY = 'HOMEBREWERY-EDITOR-THEME'; const PAGEBREAK_REGEX_V3 = /^(?=\\page(?: *{[^\n{}]*})?$)/m; +const SNIPPETBREAK_REGEX_V3 = /^\\snippet\ .*$/; const SNIPPETBAR_HEIGHT = 25; const DEFAULT_STYLE_TEXT = dedent` /*=======--- Example CSS styling ---=======*/ @@ -155,6 +156,7 @@ const Editor = createClass({ handleViewChange : function(newView){ this.props.setMoveArrows(newView === 'text'); + this.setState({ view : newView }, ()=>{ @@ -190,6 +192,9 @@ const Editor = createClass({ const whichSource = this.state.view === 'text' ? this.props.brew.text : this.props.brew.snippets; _.forEach(whichSource?.split('\n'), (line, lineNumber)=>{ + const tabHighlight = this.state.view === 'text' ? 'pageLine' : 'snippetLine'; + const textOrSnip = this.state.view === 'text'; + //reset custom line styles codeMirror.removeLineClass(lineNumber, 'background', 'pageLine'); codeMirror.removeLineClass(lineNumber, 'background', 'snippetLine'); @@ -203,40 +208,28 @@ const Editor = createClass({ // Styling for \page breaks if((this.props.renderer == 'legacy' && line.includes('\\page')) || - (this.props.renderer == 'V3' && line.match(PAGEBREAK_REGEX_V3))) { + (this.props.renderer == 'V3' && line.match(textOrSnip ? PAGEBREAK_REGEX_V3 : SNIPPETBREAK_REGEX_V3))) { - if(lineNumber > 0) // Since \page is optional on first line of document, + if((lineNumber > 0) && (textOrSnip)) // Since \page is optional on first line of document, editorPageCount += 1; // don't use it to increment page count; stay at 1 + else if(this.state.view !== 'text') userSnippetCount += 1; // add back the original class 'background' but also add the new class '.pageline' - codeMirror.addLineClass(lineNumber, 'background', 'pageLine'); + codeMirror.addLineClass(lineNumber, 'background', tabHighlight); const pageCountElement = Object.assign(document.createElement('span'), { className : 'editor-page-count', - textContent : editorPageCount + textContent : textOrSnip ? editorPageCount : userSnippetCount }); codeMirror.setBookmark({ line: lineNumber, ch: line.length }, pageCountElement); }; // New Codemirror styling for V3 renderer - if(this.props.renderer == 'V3') { + if(this.props.renderer === 'V3') { if(line.match(/^\\column$/)){ codeMirror.addLineClass(lineNumber, 'text', 'columnSplit'); } - // Styling for \snippet breaks - if(this.state.view === 'snip' && line.match(/^\\snippet\ .*$/)) { - - // add back the original class 'background' but also add the new class '.snippetLine' - codeMirror.addLineClass(lineNumber, 'background', 'snippetLine'); - const userSnippetCountElement = Object.assign(document.createElement('span'), { - className : 'editor-snippet-count', - textContent : userSnippetCount - }); - codeMirror.setBookmark({ line: lineNumber, ch: line.length }, userSnippetCountElement); - - userSnippetCount += 1; - }; // definition lists if(line.includes('::')){ if(/^:*$/.test(line) == true){ return; }; @@ -490,12 +483,13 @@ const Editor = createClass({ } if(this.isSnip()){ + if(!this.props.brew.snippets) { this.props.brew.snippets = DEFAULT_SNIPPET_TEXT; } return <> Date: Sun, 6 Apr 2025 19:09:11 +1200 Subject: [PATCH 346/398] Shift request calls to import --- .../pages/editPage/lockNotification/lockNotification.jsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/client/homebrew/pages/editPage/lockNotification/lockNotification.jsx b/client/homebrew/pages/editPage/lockNotification/lockNotification.jsx index da79ff265..ed3802c4c 100644 --- a/client/homebrew/pages/editPage/lockNotification/lockNotification.jsx +++ b/client/homebrew/pages/editPage/lockNotification/lockNotification.jsx @@ -1,6 +1,6 @@ -require('./lockNotification.less'); -const React = require('react'); -const request = require('../../../utils/request-middleware.js'); +import './lockNotification.less'; +import * as React from 'react'; +import request from '../../../utils/request-middleware.js'; import Dialog from '../../../../components/dialog.jsx'; function LockNotification(props) { From cb060ae8b11525db420053f1cfb964458096917b Mon Sep 17 00:00:00 2001 From: "G.Ambatte" Date: Sun, 6 Apr 2025 19:26:39 +1200 Subject: [PATCH 347/398] Fix state of "Request Review" button on page load --- client/homebrew/pages/editPage/editPage.jsx | 2 +- .../pages/editPage/lockNotification/lockNotification.jsx | 9 +++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/client/homebrew/pages/editPage/editPage.jsx b/client/homebrew/pages/editPage/editPage.jsx index dc2520373..856a0e347 100644 --- a/client/homebrew/pages/editPage/editPage.jsx +++ b/client/homebrew/pages/editPage/editPage.jsx @@ -443,7 +443,7 @@ const EditPage = createClass({ {this.renderNavbar()} - {this.props.brew.lock && } + {this.props.brew.lock && }
    {}, - lock : {}, + shareId : 0, + disableLock : ()=>{}, + lock : {}, + reviewRequested : false, ...props }; - const [reviewState, setReviewState] = React.useState(false); + const [reviewState, setReviewState] = React.useState(props.reviewRequested); const removeLock = async ()=>{ await request.put(`/admin/lock/review/request/${props.shareId}`) From 0a4ac7a35a01acd47b545167a1e3dbff40fac137 Mon Sep 17 00:00:00 2001 From: "G.Ambatte" Date: Sun, 6 Apr 2025 19:48:32 +1200 Subject: [PATCH 348/398] Adjust location of package.json --- server/app.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/server/app.js b/server/app.js index 6bd0c7c9a..fc0954efd 100644 --- a/server/app.js +++ b/server/app.js @@ -2,10 +2,11 @@ // Set working directory to project root import { dirname } from 'path'; import { fileURLToPath } from 'url'; -import packageJSON from './../package.json' with { type: 'json' }; const __dirname = dirname(fileURLToPath(import.meta.url)); process.chdir(`${__dirname}/..`); + +import packageJSON from '../package.json' with { type: 'json' }; const version = packageJSON.version; import _ from 'lodash'; From e2b38829f2ac7db54b551f5019cd63a8f4ed87bf Mon Sep 17 00:00:00 2001 From: "G.Ambatte" Date: Mon, 7 Apr 2025 08:25:42 +1200 Subject: [PATCH 349/398] Refactor /api/lock/count --- server/admin.api.js | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/server/admin.api.js b/server/admin.api.js index 96a21c8a7..9207daf71 100644 --- a/server/admin.api.js +++ b/server/admin.api.js @@ -165,21 +165,18 @@ router.get('/admin/stats', mw.adminOnly, async (req, res)=>{ }); router.get('/api/lock/count', mw.adminOnly, async (req, res)=>{ - try { - const countLocksQuery = { - lock : { $exists: true } - }; - const count = await HomebrewModel.countDocuments(countLocksQuery) - .then((result)=>{ - return result; - }); - return res.json({ - count + + const countLocksQuery = { + lock : { $exists: true } + }; + const count = await HomebrewModel.countDocuments(countLocksQuery) + .catch((error)=>{ + console.error(error); + return res.json({ status: 'ERROR', detail: 'Unable to get lock count', error }); }); - } catch (error) { - console.error(error); - return res.json({ status: 'ERROR', detail: 'Unable to get lock count', error }); - } + + return res.json({ count }); + }); router.post('/api/lock/:id', mw.adminOnly, async (req, res)=>{ From fa4b2ae0e362895b888337da96a9b6775aa41c38 Mon Sep 17 00:00:00 2001 From: "G.Ambatte" Date: Mon, 7 Apr 2025 08:27:32 +1200 Subject: [PATCH 350/398] Refactor /api/lock --- server/admin.api.js | 43 ++++++++++++++++++++++--------------------- 1 file changed, 22 insertions(+), 21 deletions(-) diff --git a/server/admin.api.js b/server/admin.api.js index 9207daf71..30396d1db 100644 --- a/server/admin.api.js +++ b/server/admin.api.js @@ -180,32 +180,33 @@ router.get('/api/lock/count', mw.adminOnly, async (req, res)=>{ }); router.post('/api/lock/:id', mw.adminOnly, async (req, res)=>{ - try { - const lock = req.body; - lock.applied = new Date; - const filter = { - shareId : req.params.id - }; + const lock = req.body; + lock.applied = new Date; - const brew = await HomebrewModel.findOne(filter); + const filter = { + shareId : req.params.id + }; - if(brew.lock) { - // console.log('ALREADY LOCKED'); - return res.json({ status: 'ALREADY LOCKED', detail: `Lock already exists on brew ${req.params.id} - ${brew.title}` }); - } + const brew = await HomebrewModel.findOne(filter); - brew.lock = lock; - brew.markModified('lock'); - - await brew.save(); - - // console.log(`Lock applied to brew ID ${brew.shareId} - ${brew.title}`); - return res.json({ status: 'LOCKED', detail: `Lock applied to brew ID ${brew.shareId} - ${brew.title}`, ...lock }); - } catch (error) { - console.error(error); - return res.json({ status: 'ERROR', error, message: `Unable to set lock on brew ${req.params.id}` }); + if(brew.lock) { + // console.log('ALREADY LOCKED'); + return res.json({ status: 'ALREADY LOCKED', detail: `Lock already exists on brew ${req.params.id} - ${brew.title}` }); } + + brew.lock = lock; + brew.markModified('lock'); + + await brew.save() + .catch((error)=>{ + console.error(error); + return res.json({ status: 'ERROR', error, message: `Unable to set lock on brew ${req.params.id}` }); + }); + + // console.log(`Lock applied to brew ID ${brew.shareId} - ${brew.title}`); + return res.json({ status: 'LOCKED', detail: `Lock applied to brew ID ${brew.shareId} - ${brew.title}`, ...lock }); + }); router.put('/api/unlock/:id', mw.adminOnly, async (req, res)=>{ From 3cf98617f5b8ee0f4a1c82f5f8a8b247ba19ed82 Mon Sep 17 00:00:00 2001 From: "G.Ambatte" Date: Mon, 7 Apr 2025 08:33:39 +1200 Subject: [PATCH 351/398] Refactor /api/lock/reviews --- server/admin.api.js | 53 +++++++++++++++++++++++---------------------- 1 file changed, 27 insertions(+), 26 deletions(-) diff --git a/server/admin.api.js b/server/admin.api.js index 30396d1db..45e8ecc57 100644 --- a/server/admin.api.js +++ b/server/admin.api.js @@ -210,47 +210,48 @@ router.post('/api/lock/:id', mw.adminOnly, async (req, res)=>{ }); router.put('/api/unlock/:id', mw.adminOnly, async (req, res)=>{ - try { - const filter = { - shareId : req.params.id - }; - const brew = await HomebrewModel.findOne(filter); + const filter = { + shareId : req.params.id + }; - if(!brew.lock) return res.json({ status: 'NOT LOCKED', detail: `Brew ID ${req.params.id} is not locked!` }); + const brew = await HomebrewModel.findOne(filter); - brew.lock = undefined; - brew.markModified('lock'); + if(!brew.lock) return res.json({ status: 'NOT LOCKED', detail: `Brew ID ${req.params.id} is not locked!` }); - await brew.save(); + brew.lock = undefined; + brew.markModified('lock'); + + await brew.save() + .catch((error)=>{ + console.error(error); + return res.json({ status: 'ERROR', detail: `Unable to clear lock on brew ${req.params.id}`, error }); + }); + + // console.log(`Lock removed from brew ID ${brew.shareId} - ${brew.title}`); - // console.log(`Lock removed from brew ID ${brew.shareId} - ${brew.title}`); - } catch (error) { - console.error(error); - return res.json({ status: 'ERROR', detail: `Unable to clear lock on brew ${req.params.id}`, error }); - } return res.json({ status: 'UNLOCKED', detail: `Lock removed from brew ID ${req.params.id}` }); }); router.get('/api/lock/reviews', mw.adminOnly, async (req, res)=>{ - try { - const countReviewsPipeline = [ - { + const countReviewsPipeline = [ + { $match : { 'lock.reviewRequested' : { '$exists': 1 } }, - } - ]; - const reviewDocuments = await HomebrewModel.aggregate(countReviewsPipeline); - return res.json({ - reviewDocuments + } + ]; + const reviewDocuments = await HomebrewModel.aggregate(countReviewsPipeline) + .catch((error)=>{ + console.error(error); + return res.json({ status: 'ERROR', detail: 'Unable to get review collection', error }); }); - } catch (error) { - console.error(error); - return res.json({ status: 'ERROR', detail: 'Unable to get review collection', error }); - } + return res.json({ + reviewDocuments + }); + }); router.put('/admin/lock/review/request/:id', async (req, res)=>{ From 30430cb8cbcf43032df3a14b9c6283f647d9f339 Mon Sep 17 00:00:00 2001 From: "G.Ambatte" Date: Mon, 7 Apr 2025 08:36:33 +1200 Subject: [PATCH 352/398] Refactor /admin/lock/review/request --- server/admin.api.js | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/server/admin.api.js b/server/admin.api.js index 45e8ecc57..dbfe4bc5c 100644 --- a/server/admin.api.js +++ b/server/admin.api.js @@ -257,31 +257,31 @@ router.get('/api/lock/reviews', mw.adminOnly, async (req, res)=>{ router.put('/admin/lock/review/request/:id', async (req, res)=>{ // === This route is NOT Admin only === // Any user can request a review of their document - try { - const filter = { - shareId : req.params.id, - lock : { $exists: 1 } - }; + const filter = { + shareId : req.params.id, + lock : { $exists: 1 } + }; - const brew = await HomebrewModel.findOne(filter); - if(!brew) { return res.json({ status: 'NOT LOCKED', detail: `Brew ID ${req.params.id} is not locked!` }); }; + const brew = await HomebrewModel.findOne(filter); + if(!brew) { return res.json({ status: 'NOT LOCKED', detail: `Brew ID ${req.params.id} is not locked!` }); }; - if(brew.lock.reviewRequested){ - // console.log(`Review already requested for brew ${brew.shareId} - ${brew.title}`); - return res.json({ status: 'ALREADY REQUESTED', detail: `Review already requested for brew ${brew.shareId} - ${brew.title}` }); - }; + if(brew.lock.reviewRequested){ + // console.log(`Review already requested for brew ${brew.shareId} - ${brew.title}`); + return res.json({ status: 'ALREADY REQUESTED', detail: `Review already requested for brew ${brew.shareId} - ${brew.title}` }); + }; - brew.lock.reviewRequested = new Date(); - brew.markModified('lock'); + brew.lock.reviewRequested = new Date(); + brew.markModified('lock'); - await brew.save(); + await brew.save() + .catch((error)=>{ + console.error(error); + return res.json({ status: 'ERROR', detail: `Unable to set request for review on brew ID ${req.params.id}`, error }); + }); + + // console.log(`Review requested on brew ${brew.shareId} - ${brew.title}`); + return res.json({ status: 'REVIEW REQUESTED', detail: `Review requested on brew ID ${brew.shareId} - ${brew.title}` }); - // console.log(`Review requested on brew ${brew.shareId} - ${brew.title}`); - return res.json({ status: 'REVIEW REQUESTED', detail: `Review requested on brew ID ${brew.shareId} - ${brew.title}` }); - } catch (error) { - console.error(error); - return res.json({ status: 'ERROR', detail: `Unable to set request for review on brew ID ${req.params.id}`, error }); - } }); router.put('/api/lock/review/remove/:id', mw.adminOnly, async (req, res)=>{ From 41bd27b573d25b3dda910b1fca95646eaf271b31 Mon Sep 17 00:00:00 2001 From: "G.Ambatte" Date: Mon, 7 Apr 2025 08:37:35 +1200 Subject: [PATCH 353/398] Refactor /api/lock/review/remove --- server/admin.api.js | 37 +++++++++++++++++++------------------ 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/server/admin.api.js b/server/admin.api.js index dbfe4bc5c..2526a5951 100644 --- a/server/admin.api.js +++ b/server/admin.api.js @@ -285,26 +285,27 @@ router.put('/admin/lock/review/request/:id', async (req, res)=>{ }); router.put('/api/lock/review/remove/:id', mw.adminOnly, async (req, res)=>{ - try { - const filter = { - shareId : req.params.id, - 'lock.reviewRequested' : { $exists: 1 } - }; - const brew = await HomebrewModel.findOne(filter); - if(!brew) { return res.json({ status: 'REVIEW REQUEST NOT REMOVED', detail: `Brew ID ${req.params.id} does not have a review pending!` }); }; - - brew.lock.reviewRequested = undefined; - brew.markModified('lock'); - - await brew.save(); - - // console.log(`Review request removed on brew ID ${brew.shareId} - ${brew.title}`); - return res.json({ status: 'REVIEW REQUEST REMOVED', detail: `Review request removed for brew ID ${brew.shareId} - ${brew.title}` }); - } catch (error) { - console.error(error); - return res.json({ status: 'ERROR', detail: `Unable to remove request for review on brew ID ${req.params.id}`, error }); + const filter = { + shareId : req.params.id, + 'lock.reviewRequested' : { $exists: 1 } }; + + const brew = await HomebrewModel.findOne(filter); + if(!brew) { return res.json({ status: 'REVIEW REQUEST NOT REMOVED', detail: `Brew ID ${req.params.id} does not have a review pending!` }); }; + + brew.lock.reviewRequested = undefined; + brew.markModified('lock'); + + await brew.save() + .catch((error)=>{ + console.error(error); + return res.json({ status: 'ERROR', detail: `Unable to remove request for review on brew ID ${req.params.id}`, error }); + }); + + // console.log(`Review request removed on brew ID ${brew.shareId} - ${brew.title}`); + return res.json({ status: 'REVIEW REQUEST REMOVED', detail: `Review request removed for brew ID ${brew.shareId} - ${brew.title}` }); + }); // ####################### NOTIFICATIONS From 0bca3393d4f70cfd8caa080372e31771dd41d362 Mon Sep 17 00:00:00 2001 From: "G.Ambatte" Date: Mon, 7 Apr 2025 08:39:33 +1200 Subject: [PATCH 354/398] Add LOCK header in comment --- server/admin.api.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/server/admin.api.js b/server/admin.api.js index 2526a5951..a2dc76498 100644 --- a/server/admin.api.js +++ b/server/admin.api.js @@ -164,6 +164,8 @@ router.get('/admin/stats', mw.adminOnly, async (req, res)=>{ } }); +// ####################### LOCKS + router.get('/api/lock/count', mw.adminOnly, async (req, res)=>{ const countLocksQuery = { From 99c342f19b89c777875c725f2fabd54024e2a479 Mon Sep 17 00:00:00 2001 From: "G.Ambatte" Date: Mon, 7 Apr 2025 14:38:25 +1200 Subject: [PATCH 355/398] Use throw in Lock API calls --- client/admin/lockTools/lockTools.jsx | 15 ++++-- .../pages/errorPage/errors/errorIndex.js | 22 ++++++++ server/admin.api.js | 52 ++++++++++--------- 3 files changed, 61 insertions(+), 28 deletions(-) diff --git a/client/admin/lockTools/lockTools.jsx b/client/admin/lockTools/lockTools.jsx index 5f8a4ba39..a1cffce24 100644 --- a/client/admin/lockTools/lockTools.jsx +++ b/client/admin/lockTools/lockTools.jsx @@ -7,6 +7,7 @@ const createClass = require('create-react-class'); import request from '../../homebrew/utils/request-middleware.js'; const LockTools = createClass({ + displayName : 'LockTools', getInitialState : function() { return { fetching : false, @@ -48,6 +49,7 @@ const LockTools = createClass({ }); const LockBrew = createClass({ + displayName : 'LockBrew', getInitialState : function() { // Default values return { @@ -80,6 +82,9 @@ const LockBrew = createClass({ .set('Content-Type', 'application/json') .then((response)=>{ this.setState({ result: response.body }); + }) + .catch((err)=>{ + this.setState({ result: err.response.body }); }); }, @@ -166,6 +171,7 @@ const LockBrew = createClass({ }); const LockTable = createClass({ + displayName : 'LockTable', getDefaultProps : function() { return { title : '', @@ -188,7 +194,7 @@ const LockTable = createClass({ request.get(this.props.fetchURL) .then((res)=>this.setState({ result: res.body })) - .catch((err)=>this.setState({ error: err })) + .catch((err)=>this.setState({ result: err.response.body })) .finally(()=>{ this.setState({ searching: false }); }); @@ -239,6 +245,7 @@ const LockTable = createClass({ }); const LockLookup = createClass({ + displayName : 'LockLookup', getDefaultProps : function() { return { fetchURL : '/api/lookup' @@ -263,14 +270,14 @@ const LockLookup = createClass({ request.put(`${this.props.fetchURL}/${this.state.query}`) .then((res)=>this.setState({ result: res.body })) - .catch((err)=>this.setState({ error: err })) + .catch((err)=>this.setState({ result: err.response.body })) .finally(()=>{ this.setState({ searching: false }); }); }, renderResult : function(){ - return <> + return

    Result:

    @@ -283,7 +290,7 @@ const LockLookup = createClass({ })}
    - ; +
    ; }, render : function() { diff --git a/client/homebrew/pages/errorPage/errors/errorIndex.js b/client/homebrew/pages/errorPage/errors/errorIndex.js index 9584a14b9..d00aec8d5 100644 --- a/client/homebrew/pages/errorPage/errors/errorIndex.js +++ b/client/homebrew/pages/errorPage/errors/errorIndex.js @@ -201,6 +201,28 @@ const errorIndex = (props)=>{ ## Access Denied You need to provide correct administrator credentials to access this page.`, + // ####### Lock Errors + + '60' : dedent`General Lock Error`, + + '61' : dedent`Lock Error: Unable to get lock count`, + + '62' : dedent`Lock Error: Cannot lock`, + + '63' : dedent`Lock Error: Cannot lock - brew not found`, + + '64' : dedent`Lock Error: Cannot lock - already locked`, + + '65' : dedent`Lock Error: Cannot unlock`, + + '66' : dedent`Lock Error: Cannot unlock - brew not found`, + + '67' : dedent`Lock Error: Cannot unlock - not locked`, + + '68' : dedent`Lock Error: Cannot get pending reviews`, + + // ####### Other Errors + '90' : dedent` An unexpected error occurred while looking for these brews. Try again in a few minutes.`, diff --git a/server/admin.api.js b/server/admin.api.js index a2dc76498..12a35cf89 100644 --- a/server/admin.api.js +++ b/server/admin.api.js @@ -166,22 +166,25 @@ router.get('/admin/stats', mw.adminOnly, async (req, res)=>{ // ####################### LOCKS -router.get('/api/lock/count', mw.adminOnly, async (req, res)=>{ +router.get('/api/lock/throw', asyncHandler(async ()=>{ + throw { HBErrorCode: '60', code: 500, message: 'Thrown deliberately' }; +})); + +router.get('/api/lock/count', mw.adminOnly, asyncHandler(async (req, res)=>{ const countLocksQuery = { lock : { $exists: true } }; const count = await HomebrewModel.countDocuments(countLocksQuery) .catch((error)=>{ - console.error(error); - return res.json({ status: 'ERROR', detail: 'Unable to get lock count', error }); + throw { name: 'Lock Count Error', message: 'Unable to get lock count', status: 500, HBErrorCode: '61', error }; }); return res.json({ count }); -}); +})); -router.post('/api/lock/:id', mw.adminOnly, async (req, res)=>{ +router.post('/api/lock/:id', mw.adminOnly, asyncHandler(async (req, res)=>{ const lock = req.body; lock.applied = new Date; @@ -192,9 +195,11 @@ router.post('/api/lock/:id', mw.adminOnly, async (req, res)=>{ const brew = await HomebrewModel.findOne(filter); + if(!brew) throw { name: 'Brew Not Found', message: 'Cannot find brew to lock', shareId: req.params.id, status: 500, HBErrorCode: '63' }; + if(brew.lock) { // console.log('ALREADY LOCKED'); - return res.json({ status: 'ALREADY LOCKED', detail: `Lock already exists on brew ${req.params.id} - ${brew.title}` }); + throw { name: 'Already Locked', message: 'Lock already exists on brew', shareId: req.params.id, title: brew.title, status: 500, HBErrorCode: '64' }; } brew.lock = lock; @@ -202,16 +207,15 @@ router.post('/api/lock/:id', mw.adminOnly, async (req, res)=>{ await brew.save() .catch((error)=>{ - console.error(error); - return res.json({ status: 'ERROR', error, message: `Unable to set lock on brew ${req.params.id}` }); + throw { name: 'Already Locked', message: 'Unable to set lock', shareId: req.params.id, status: 500, HBErrorCode: '62', error }; }); // console.log(`Lock applied to brew ID ${brew.shareId} - ${brew.title}`); - return res.json({ status: 'LOCKED', detail: `Lock applied to brew ID ${brew.shareId} - ${brew.title}`, ...lock }); + return res.json({ name: 'LOCKED', message: `Lock applied to brew ID ${brew.shareId} - ${brew.title}`, ...lock }); -}); +})); -router.put('/api/unlock/:id', mw.adminOnly, async (req, res)=>{ +router.put('/api/unlock/:id', mw.adminOnly, asyncHandler(async (req, res)=>{ const filter = { shareId : req.params.id @@ -219,24 +223,25 @@ router.put('/api/unlock/:id', mw.adminOnly, async (req, res)=>{ const brew = await HomebrewModel.findOne(filter); - if(!brew.lock) return res.json({ status: 'NOT LOCKED', detail: `Brew ID ${req.params.id} is not locked!` }); + if(!brew) throw { name: 'Brew Not Found', message: 'Cannot find brew to unlock', shareId: req.params.id, status: 500, HBErrorCode: '66' }; + + if(!brew.lock) throw { name: 'Not Locked', message: 'Cannot unlock as brew is not locked', shareId: req.params.id, status: 500, HBErrorCode: '67' }; brew.lock = undefined; brew.markModified('lock'); await brew.save() .catch((error)=>{ - console.error(error); - return res.json({ status: 'ERROR', detail: `Unable to clear lock on brew ${req.params.id}`, error }); + throw { name: 'Cannot Unlock', message: 'Unable to clear lock', shareId: req.params.id, status: 500, HBErrorCode: '65', error }; }); // console.log(`Lock removed from brew ID ${brew.shareId} - ${brew.title}`); - return res.json({ status: 'UNLOCKED', detail: `Lock removed from brew ID ${req.params.id}` }); -}); + return res.json({ name: 'Unlocked', message: `Lock removed from brew ID ${req.params.id}` }); +})); -router.get('/api/lock/reviews', mw.adminOnly, async (req, res)=>{ +router.get('/api/lock/reviews', mw.adminOnly, asyncHandler(async (req, res)=>{ const countReviewsPipeline = [ { $match : @@ -247,16 +252,15 @@ router.get('/api/lock/reviews', mw.adminOnly, async (req, res)=>{ ]; const reviewDocuments = await HomebrewModel.aggregate(countReviewsPipeline) .catch((error)=>{ - console.error(error); - return res.json({ status: 'ERROR', detail: 'Unable to get review collection', error }); + throw { name: 'Unable to get reviews', message: 'Unable to get review collection', status: 500, HBErrorCode: '68', error }; }); return res.json({ reviewDocuments }); -}); +})); -router.put('/admin/lock/review/request/:id', async (req, res)=>{ +router.put('/admin/lock/review/request/:id', asyncHandler(async (req, res)=>{ // === This route is NOT Admin only === // Any user can request a review of their document const filter = { @@ -284,9 +288,9 @@ router.put('/admin/lock/review/request/:id', async (req, res)=>{ // console.log(`Review requested on brew ${brew.shareId} - ${brew.title}`); return res.json({ status: 'REVIEW REQUESTED', detail: `Review requested on brew ID ${brew.shareId} - ${brew.title}` }); -}); +})); -router.put('/api/lock/review/remove/:id', mw.adminOnly, async (req, res)=>{ +router.put('/api/lock/review/remove/:id', mw.adminOnly, asyncHandler(async (req, res)=>{ const filter = { shareId : req.params.id, @@ -308,7 +312,7 @@ router.put('/api/lock/review/remove/:id', mw.adminOnly, async (req, res)=>{ // console.log(`Review request removed on brew ID ${brew.shareId} - ${brew.title}`); return res.json({ status: 'REVIEW REQUEST REMOVED', detail: `Review request removed for brew ID ${brew.shareId} - ${brew.title}` }); -}); +})); // ####################### NOTIFICATIONS From bd145f17da5b7af3cfd0106e8d38a0e1c2cfb8f8 Mon Sep 17 00:00:00 2001 From: "G.Ambatte" Date: Mon, 7 Apr 2025 14:38:37 +1200 Subject: [PATCH 356/398] Tweak styling --- client/admin/lockTools/lockTools.less | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/client/admin/lockTools/lockTools.less b/client/admin/lockTools/lockTools.less index 5737a32e0..0b6cb615d 100644 --- a/client/admin/lockTools/lockTools.less +++ b/client/admin/lockTools/lockTools.less @@ -39,6 +39,7 @@ } .lockTable{ + break-inside: avoid; cursor: default; .row:hover { background-color: #ccc; @@ -56,11 +57,12 @@ padding: 4px 10px; text-align: center; } - td{ + table, td{ border: 1px solid #333333; } .brewLookup{ + break-inside: avoid; min-height: 175px; h2 { margin-top: 0px; From 1e35e1096fd426197b712b84faec82e9d049eba0 Mon Sep 17 00:00:00 2001 From: "G.Ambatte" Date: Mon, 7 Apr 2025 14:39:33 +1200 Subject: [PATCH 357/398] Reduce data retrieved for brews with requested reviews --- server/admin.api.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/server/admin.api.js b/server/admin.api.js index 12a35cf89..6a3a943d5 100644 --- a/server/admin.api.js +++ b/server/admin.api.js @@ -248,6 +248,12 @@ router.get('/api/lock/reviews', mw.adminOnly, asyncHandler(async (req, res)=>{ { 'lock.reviewRequested' : { '$exists': 1 } }, + }, + { + $project : { + shareId : 1, + title : 1 + } } ]; const reviewDocuments = await HomebrewModel.aggregate(countReviewsPipeline) From 4c4a023f34305073f8677331aca0fe6e475ac7a6 Mon Sep 17 00:00:00 2001 From: "G.Ambatte" Date: Mon, 7 Apr 2025 15:59:06 +1200 Subject: [PATCH 358/398] Fix lock notification message --- .../pages/editPage/lockNotification/lockNotification.jsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/client/homebrew/pages/editPage/lockNotification/lockNotification.jsx b/client/homebrew/pages/editPage/lockNotification/lockNotification.jsx index cc77e6204..9c8bb2c47 100644 --- a/client/homebrew/pages/editPage/lockNotification/lockNotification.jsx +++ b/client/homebrew/pages/editPage/lockNotification/lockNotification.jsx @@ -8,6 +8,7 @@ function LockNotification(props) { shareId : 0, disableLock : ()=>{}, lock : {}, + message : 'Unable to retrieve Lock Message', reviewRequested : false, ...props }; @@ -31,7 +32,7 @@ function LockNotification(props) {

    This brew been locked by the Administrators. It will not be accessible by any method other than the Editor until the lock is removed.


    LOCK REASON

    -

    {props.lock.editMessage || 'Unable to retrieve Lock Message'}

    +

    {props.message}


    Once you have resolved this issue, click REQUEST LOCK REMOVAL to notify the Administrators for review.

    Click CONTINUE TO EDITOR to temporarily hide this notification; it will reappear the next time the page is reloaded.

    From a594d456116dfb069ae9c750605884c072474fc0 Mon Sep 17 00:00:00 2001 From: "G.Ambatte" Date: Mon, 7 Apr 2025 15:59:34 +1200 Subject: [PATCH 359/398] Remove unnecessary default option --- .../pages/editPage/lockNotification/lockNotification.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/homebrew/pages/editPage/lockNotification/lockNotification.jsx b/client/homebrew/pages/editPage/lockNotification/lockNotification.jsx index 9c8bb2c47..0750a599c 100644 --- a/client/homebrew/pages/editPage/lockNotification/lockNotification.jsx +++ b/client/homebrew/pages/editPage/lockNotification/lockNotification.jsx @@ -23,7 +23,7 @@ function LockNotification(props) { }; const renderReviewButton = function(){ - if(reviewState || props.lock.reviewRequested){ return ; }; + if(reviewState){ return ; }; return ; }; From ef6f022ea3fb6781488c6a8aed311a8ca008aa72 Mon Sep 17 00:00:00 2001 From: "G.Ambatte" Date: Mon, 7 Apr 2025 15:59:54 +1200 Subject: [PATCH 360/398] Tweak lock notification styling --- .../pages/editPage/lockNotification/lockNotification.less | 1 + 1 file changed, 1 insertion(+) diff --git a/client/homebrew/pages/editPage/lockNotification/lockNotification.less b/client/homebrew/pages/editPage/lockNotification/lockNotification.less index de2692ec0..88133ea98 100644 --- a/client/homebrew/pages/editPage/lockNotification/lockNotification.less +++ b/client/homebrew/pages/editPage/lockNotification/lockNotification.less @@ -14,6 +14,7 @@ margin : 10px; color : white; background-color : #333333; + padding : 2px 15px; &.inactive, &:hover { From a218b87215305e4828454191859f0eda63796cf7 Mon Sep 17 00:00:00 2001 From: "G.Ambatte" Date: Mon, 7 Apr 2025 16:32:33 +1200 Subject: [PATCH 361/398] Shift remaining lock API functions to use throw --- .../pages/errorPage/errors/errorIndex.js | 28 +++++++++++++------ server/admin.api.js | 18 ++++++------ 2 files changed, 27 insertions(+), 19 deletions(-) diff --git a/client/homebrew/pages/errorPage/errors/errorIndex.js b/client/homebrew/pages/errorPage/errors/errorIndex.js index d00aec8d5..2f0d4599b 100644 --- a/client/homebrew/pages/errorPage/errors/errorIndex.js +++ b/client/homebrew/pages/errorPage/errors/errorIndex.js @@ -203,23 +203,33 @@ const errorIndex = (props)=>{ // ####### Lock Errors - '60' : dedent`General Lock Error`, + '60' : dedent`Lock Error: General`, - '61' : dedent`Lock Error: Unable to get lock count`, + '61' : dedent`Lock Get Error: Unable to get lock count`, - '62' : dedent`Lock Error: Cannot lock`, + '62' : dedent`Lock Set Error: Cannot lock`, - '63' : dedent`Lock Error: Cannot lock - brew not found`, + '63' : dedent`Lock Set Error: Brew not found`, - '64' : dedent`Lock Error: Cannot lock - already locked`, + '64' : dedent`Lock Set Error: Already locked`, - '65' : dedent`Lock Error: Cannot unlock`, + '65' : dedent`Lock Remove Error: Cannot unlock`, - '66' : dedent`Lock Error: Cannot unlock - brew not found`, + '66' : dedent`Lock Remove Error: Brew not found`, - '67' : dedent`Lock Error: Cannot unlock - not locked`, + '67' : dedent`Lock Remove Error: Not locked`, - '68' : dedent`Lock Error: Cannot get pending reviews`, + '68' : dedent`Lock Get Review Error: Cannot get review requests`, + + '69' : dedent`Lock Set Review Error: Cannot set review request`, + + '70' : dedent`Lock Set Review Error: Brew not found`, + + '71' : dedent`Lock Set Review Error: Review already requested`, + + '72' : dedent`Lock Remove Review Error: Cannot clear review request`, + + '73' : dedent`Lock Remove Review Error: Brew not found`, // ####### Other Errors diff --git a/server/admin.api.js b/server/admin.api.js index 6a3a943d5..77de3fd52 100644 --- a/server/admin.api.js +++ b/server/admin.api.js @@ -258,7 +258,7 @@ router.get('/api/lock/reviews', mw.adminOnly, asyncHandler(async (req, res)=>{ ]; const reviewDocuments = await HomebrewModel.aggregate(countReviewsPipeline) .catch((error)=>{ - throw { name: 'Unable to get reviews', message: 'Unable to get review collection', status: 500, HBErrorCode: '68', error }; + throw { name: 'Can Not Get Reviews', message: 'Unable to get review collection', status: 500, HBErrorCode: '68', error }; }); return res.json({ reviewDocuments @@ -275,11 +275,11 @@ router.put('/admin/lock/review/request/:id', asyncHandler(async (req, res)=>{ }; const brew = await HomebrewModel.findOne(filter); - if(!brew) { return res.json({ status: 'NOT LOCKED', detail: `Brew ID ${req.params.id} is not locked!` }); }; + if(!brew) { throw { name: 'Brew Not Found', message: `Cannot find a locked brew with ID ${req.params.id}`, code: 500, HBErrorCode: '70' }; }; if(brew.lock.reviewRequested){ // console.log(`Review already requested for brew ${brew.shareId} - ${brew.title}`); - return res.json({ status: 'ALREADY REQUESTED', detail: `Review already requested for brew ${brew.shareId} - ${brew.title}` }); + throw { name: 'Review Already Requested', message: `Review already requested for brew ${brew.shareId} - ${brew.title}`, code: 500, HBErrorCode: '71' }; }; brew.lock.reviewRequested = new Date(); @@ -287,12 +287,11 @@ router.put('/admin/lock/review/request/:id', asyncHandler(async (req, res)=>{ await brew.save() .catch((error)=>{ - console.error(error); - return res.json({ status: 'ERROR', detail: `Unable to set request for review on brew ID ${req.params.id}`, error }); + throw { name: 'Can Not Set Review Request', message: `Unable to set request for review on brew ID ${req.params.id}`, code: 500, HBErrorCode: '69', error }; }); // console.log(`Review requested on brew ${brew.shareId} - ${brew.title}`); - return res.json({ status: 'REVIEW REQUESTED', detail: `Review requested on brew ID ${brew.shareId} - ${brew.title}` }); + return res.json({ name: 'Review Requested', message: `Review requested on brew ID ${brew.shareId} - ${brew.title}` }); })); @@ -304,19 +303,18 @@ router.put('/api/lock/review/remove/:id', mw.adminOnly, asyncHandler(async (req, }; const brew = await HomebrewModel.findOne(filter); - if(!brew) { return res.json({ status: 'REVIEW REQUEST NOT REMOVED', detail: `Brew ID ${req.params.id} does not have a review pending!` }); }; + if(!brew) { throw { name: 'Can Not Clear Review Request', message: `Brew ID ${req.params.id} does not have a review pending!`, HBErrorCode: '73' }; }; brew.lock.reviewRequested = undefined; brew.markModified('lock'); await brew.save() .catch((error)=>{ - console.error(error); - return res.json({ status: 'ERROR', detail: `Unable to remove request for review on brew ID ${req.params.id}`, error }); + throw { name: 'Can Not Clear Review Request', message: `Unable to remove request for review on brew ID ${req.params.id}`, HBErrorCode: '72', error }; }); // console.log(`Review request removed on brew ID ${brew.shareId} - ${brew.title}`); - return res.json({ status: 'REVIEW REQUEST REMOVED', detail: `Review request removed for brew ID ${brew.shareId} - ${brew.title}` }); + return res.json({ name: 'Review Request Cleared', message: `Review request removed for brew ID ${brew.shareId} - ${brew.title}` }); })); From e2f2b2962f47532df8079e2294718f0b62a0cc27 Mon Sep 17 00:00:00 2001 From: "G.Ambatte" Date: Mon, 7 Apr 2025 17:34:31 +1200 Subject: [PATCH 362/398] Revert request middleware change as it is no longer necessary --- client/homebrew/utils/request-middleware.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/client/homebrew/utils/request-middleware.js b/client/homebrew/utils/request-middleware.js index deb08d265..01a9d2571 100644 --- a/client/homebrew/utils/request-middleware.js +++ b/client/homebrew/utils/request-middleware.js @@ -1,8 +1,6 @@ -import packageJSON from '../../../package.json' with { type: 'json' }; import request from 'superagent'; - -const addHeader = (request)=>request.set('Homebrewery-Version', packageJSON.version); +const addHeader = (request)=>request.set('Homebrewery-Version', global.version); const requestMiddleware = { get : (path)=>addHeader(request.get(path)), From 26aa302714ad9364ee34008741543f1e6a1f9399 Mon Sep 17 00:00:00 2001 From: "G.Ambatte" Date: Mon, 7 Apr 2025 20:04:45 +1200 Subject: [PATCH 363/398] Remove debugging test route --- server/admin.api.js | 4 ---- 1 file changed, 4 deletions(-) diff --git a/server/admin.api.js b/server/admin.api.js index 77de3fd52..8d8500c37 100644 --- a/server/admin.api.js +++ b/server/admin.api.js @@ -166,10 +166,6 @@ router.get('/admin/stats', mw.adminOnly, async (req, res)=>{ // ####################### LOCKS -router.get('/api/lock/throw', asyncHandler(async ()=>{ - throw { HBErrorCode: '60', code: 500, message: 'Thrown deliberately' }; -})); - router.get('/api/lock/count', mw.adminOnly, asyncHandler(async (req, res)=>{ const countLocksQuery = { From ab9b151b8a583e85806b2ebde33b17c99335f0e3 Mon Sep 17 00:00:00 2001 From: "G.Ambatte" Date: Mon, 7 Apr 2025 20:52:35 +1200 Subject: [PATCH 364/398] Add API route to return all locked brews --- server/admin.api.js | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/server/admin.api.js b/server/admin.api.js index 8d8500c37..f770e4adf 100644 --- a/server/admin.api.js +++ b/server/admin.api.js @@ -180,6 +180,31 @@ router.get('/api/lock/count', mw.adminOnly, asyncHandler(async (req, res)=>{ })); +router.get('/api/locks', mw.adminOnly, asyncHandler(async (req, res)=>{ + const countLocksPipeline = [ + { + $match : + { + 'lock' : { '$exists': 1 } + }, + }, + { + $project : { + shareId : 1, + title : 1 + } + } + ]; + const lockedDocuments = await HomebrewModel.aggregate(countLocksPipeline) + .catch((error)=>{ + throw { name: 'Can Not Get Locked Brews', message: 'Unable to get locked brew collection', status: 500, HBErrorCode: '68', error }; + }); + return res.json({ + lockedDocuments + }); + +})); + router.post('/api/lock/:id', mw.adminOnly, asyncHandler(async (req, res)=>{ const lock = req.body; From 7451dda632415a875360d4ca6ba0e9fc29eca1cf Mon Sep 17 00:00:00 2001 From: "G.Ambatte" Date: Mon, 7 Apr 2025 20:54:21 +1200 Subject: [PATCH 365/398] Add locked brews table --- client/admin/lockTools/lockTools.jsx | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/client/admin/lockTools/lockTools.jsx b/client/admin/lockTools/lockTools.jsx index a1cffce24..253d5f006 100644 --- a/client/admin/lockTools/lockTools.jsx +++ b/client/admin/lockTools/lockTools.jsx @@ -35,7 +35,9 @@ const LockTools = createClass({

    Number of brews currently locked: {this.state.reviewCount}


    - + +
    +

    @@ -175,6 +177,7 @@ const LockTable = createClass({ getDefaultProps : function() { return { title : '', + text : '', fetchURL : '/api/locks', resultName : '', propertyNames : ['shareId'] @@ -212,7 +215,7 @@ const LockTable = createClass({
    {this.state.result[this.props.resultName] && <> -

    Total Reviews Waiting: {this.state.result[this.props.resultName].length}

    +

    {this.props.text}: {this.state.result[this.props.resultName].length}

    From f74c2049a767e4d751b9f279c7a93e37bf9b5609 Mon Sep 17 00:00:00 2001 From: "G.Ambatte" Date: Mon, 7 Apr 2025 20:54:44 +1200 Subject: [PATCH 366/398] Rename Edit and Share page message fields --- client/admin/lockTools/lockTools.jsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/admin/lockTools/lockTools.jsx b/client/admin/lockTools/lockTools.jsx index 253d5f006..7c7580edf 100644 --- a/client/admin/lockTools/lockTools.jsx +++ b/client/admin/lockTools/lockTools.jsx @@ -127,12 +127,12 @@ const LockBrew = createClass({


    From 61efc2d1522aba1fa24118a68bf431f3d7a86f23 Mon Sep 17 00:00:00 2001 From: "G.Ambatte" Date: Mon, 7 Apr 2025 21:12:37 +1200 Subject: [PATCH 367/398] Tweak styling --- client/admin/lockTools/lockTools.less | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/client/admin/lockTools/lockTools.less b/client/admin/lockTools/lockTools.less index 0b6cb615d..2666b4bb0 100644 --- a/client/admin/lockTools/lockTools.less +++ b/client/admin/lockTools/lockTools.less @@ -12,7 +12,7 @@ line-height: 1.5em; input { float: right; - width: 70%; + width: 65%; margin-left: 10px; } } @@ -68,4 +68,8 @@ margin-top: 0px; } } + + button i { + padding-left: 5px; + } } \ No newline at end of file From 7a1042fedd7abec5161783bb668d14a3d87f7fef Mon Sep 17 00:00:00 2001 From: "G.Ambatte" Date: Mon, 7 Apr 2025 22:02:08 +1200 Subject: [PATCH 368/398] Stylelint fixes --- client/admin/lockTools/lockTools.less | 118 ++++++++---------- .../lockNotification/lockNotification.less | 6 +- 2 files changed, 55 insertions(+), 69 deletions(-) diff --git a/client/admin/lockTools/lockTools.less b/client/admin/lockTools/lockTools.less index 2666b4bb0..f6e7ea9dd 100644 --- a/client/admin/lockTools/lockTools.less +++ b/client/admin/lockTools/lockTools.less @@ -1,75 +1,63 @@ .lockTools { - .lockBrew { - columns: 2; + .lockBrew { + columns : 2; - .lockForm { - break-inside: avoid; + .lockForm { + break-inside : avoid; - label { - width: 100%; - display: inline-block; - text-align: right; - line-height: 1.5em; - input { - float: right; - width: 65%; - margin-left: 10px; - } - } - } + label { + display : inline-block; + width : 100%; + line-height : 1.5em; + text-align : right; + input { + float : right; + width : 65%; + margin-left : 10px; + } + input.checkbox { + width : 1.5em; + height : 1.5em; + } + } + } - .lockSuggestions { - break-inside: avoid; - columns: 2; - line-height: 1.2em; - h2 { - column-span: all; - } - h3 { - margin-top: 0px; - } - b { - font-weight: 600; - } + .lockSuggestions { + line-height : 1.2em; + break-inside : avoid; + columns : 2; + h2 { column-span : all; } + h3 { margin-top : 0px; } + b { font-weight : 600; } - .lockCodes { - break-inside: avoid; - } - } - } + .lockCodes { break-inside : avoid; } + } + } - .lockTable{ - break-inside: avoid; - cursor: default; - .row:hover { - background-color: #ccc; - color: #000; - } - .icon { - cursor: pointer; - &:hover{ - text-shadow: 0px 0px 6px black; - } - } - } + .lockTable { + cursor : default; + break-inside : avoid; + .row:hover { + color : #000000; + background-color : #CCCCCC; + } + .icon { + cursor : pointer; + &:hover { text-shadow : 0px 0px 6px black; } + } + } - th, td { - padding: 4px 10px; - text-align: center; - } - table, td{ - border: 1px solid #333333; - } + th, td { + padding : 4px 10px; + text-align : center; + } + table, td { border : 1px solid #333333; } - .brewLookup{ - break-inside: avoid; - min-height: 175px; - h2 { - margin-top: 0px; - } - } + .brewLookup { + min-height : 175px; + break-inside : avoid; + h2 { margin-top : 0px; } + } - button i { - padding-left: 5px; - } + button i { padding-left : 5px; } } \ No newline at end of file diff --git a/client/homebrew/pages/editPage/lockNotification/lockNotification.less b/client/homebrew/pages/editPage/lockNotification/lockNotification.less index 88133ea98..930b070c4 100644 --- a/client/homebrew/pages/editPage/lockNotification/lockNotification.less +++ b/client/homebrew/pages/editPage/lockNotification/lockNotification.less @@ -11,15 +11,13 @@ &::backdrop { background-color : #000000AA; } button { + padding : 2px 15px; margin : 10px; color : white; background-color : #333333; - padding : 2px 15px; &.inactive, - &:hover { - background-color : #777777; - } + &:hover { background-color : #777777; } } h1, h3 { From f8566392f6ec9fcf8e12cfb07eefbfd7693cd747 Mon Sep 17 00:00:00 2001 From: "G.Ambatte" Date: Mon, 7 Apr 2025 22:02:28 +1200 Subject: [PATCH 369/398] Add overwrite option for updating locks --- client/admin/lockTools/lockTools.jsx | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/client/admin/lockTools/lockTools.jsx b/client/admin/lockTools/lockTools.jsx index 7c7580edf..c528fb13d 100644 --- a/client/admin/lockTools/lockTools.jsx +++ b/client/admin/lockTools/lockTools.jsx @@ -59,7 +59,8 @@ const LockBrew = createClass({ code : 455, editMessage : '', shareMessage : 'This Brew has been locked.', - result : {} + result : {}, + overwrite : false }; }, @@ -73,6 +74,7 @@ const LockBrew = createClass({ e.preventDefault(); if(!this.state.editMessage) return; const newLock = { + overwrite : this.state.overwrite, code : parseInt(this.state.code) || 100, editMessage : this.state.editMessage, shareMessage : this.state.shareMessage, @@ -136,6 +138,10 @@ const LockBrew = createClass({ {this.renderInput('shareMessage')}
    + @@ -163,8 +169,8 @@ const LockBrew = createClass({

    Messages

      -
    • Edit Message: This is the private message that is ONLY displayed to the authors of the locked brew. This message MUST specify exactly what actions must be taken in order to have the brew unlocked.
    • -
    • Share Message: This is the public message that is displayed to the EVERYONE that attempts to view the locked brew.
    • +
    • Private Message: This is the private message that is ONLY displayed to the authors of the locked brew. This message MUST specify exactly what actions must be taken in order to have the brew unlocked.
    • +
    • Public Message: This is the public message that is displayed to the EVERYONE that attempts to view the locked brew.
    From ec6258a2a5b219f518f2bc4b4672431e64391fff Mon Sep 17 00:00:00 2001 From: "G.Ambatte" Date: Mon, 7 Apr 2025 22:02:53 +1200 Subject: [PATCH 370/398] Add overwrite option to API function --- server/admin.api.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/server/admin.api.js b/server/admin.api.js index f770e4adf..8942a4675 100644 --- a/server/admin.api.js +++ b/server/admin.api.js @@ -208,6 +208,10 @@ router.get('/api/locks', mw.adminOnly, asyncHandler(async (req, res)=>{ router.post('/api/lock/:id', mw.adminOnly, asyncHandler(async (req, res)=>{ const lock = req.body; + + const overwrite = lock.overwrite || false; + lock.overwrite = undefined; + lock.applied = new Date; const filter = { @@ -218,7 +222,7 @@ router.post('/api/lock/:id', mw.adminOnly, asyncHandler(async (req, res)=>{ if(!brew) throw { name: 'Brew Not Found', message: 'Cannot find brew to lock', shareId: req.params.id, status: 500, HBErrorCode: '63' }; - if(brew.lock) { + if(brew.lock && !overwrite) { // console.log('ALREADY LOCKED'); throw { name: 'Already Locked', message: 'Lock already exists on brew', shareId: req.params.id, title: brew.title, status: 500, HBErrorCode: '64' }; } From 1ded1cad5a123ac7fb4f74a7a89eadba21e293b0 Mon Sep 17 00:00:00 2001 From: "G.Ambatte" Date: Tue, 8 Apr 2025 09:28:54 +1200 Subject: [PATCH 371/398] Change accessType check --- server/homebrew.api.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/homebrew.api.js b/server/homebrew.api.js index 055d72eba..c59c6c4d7 100644 --- a/server/homebrew.api.js +++ b/server/homebrew.api.js @@ -118,7 +118,7 @@ const api = { throw { ...accessError, message: 'User is not logged in', HBErrorCode: '04' }; } - if(stub?.lock && accessType != 'edit') { + if(stub?.lock && accessType === 'share') { throw { HBErrorCode: '51', code: stub.lock.code, message: stub.lock.shareMessage, brewId: stub.shareId, brewTitle: stub.title }; } From d0c3765f8f82959bf7bffd597448dc66f18a0836 Mon Sep 17 00:00:00 2001 From: David Bolack Date: Mon, 7 Apr 2025 23:22:47 -0500 Subject: [PATCH 372/398] Move Snippets store to metadata block. Note this still stores the snippets as a string for the passed about brew object. --- server/homebrew.api.js | 7 +------ shared/helpers.js | 6 +----- 2 files changed, 2 insertions(+), 11 deletions(-) diff --git a/server/homebrew.api.js b/server/homebrew.api.js index 4534c5cb7..84e338ef4 100644 --- a/server/homebrew.api.js +++ b/server/homebrew.api.js @@ -170,12 +170,6 @@ const api = { mergeBrewText : (brew)=>{ let text = brew.text; - if(brew.snippets !== undefined) { - text = `\`\`\`snippets\n` + - `${yaml.dump(brewSnippetsToJSON('brew_snippets', brew.snippets, null, false))}` + - `\`\`\`\n\n` + - `${text}`; - } if(brew.style !== undefined) { text = `\`\`\`css\n` + `${brew.style || ''}\n` + @@ -183,6 +177,7 @@ const api = { `${text}`; } const metadata = _.pick(brew, ['title', 'description', 'tags', 'systems', 'renderer', 'theme']); + metadata.snippets = brewSnippetsToJSON('brew_snippets', brew.snippets, null, false); text = `\`\`\`metadata\n` + `${yaml.dump(metadata)}\n` + `\`\`\`\n\n` + diff --git a/shared/helpers.js b/shared/helpers.js index 997d77cec..e4dc9eba8 100644 --- a/shared/helpers.js +++ b/shared/helpers.js @@ -91,6 +91,7 @@ const splitTextStyleAndMetadata = (brew)=>{ const metadataSection = brew.text.slice(11, index + 1); const metadata = yaml.load(metadataSection); Object.assign(brew, _.pick(metadata, ['title', 'description', 'tags', 'systems', 'renderer', 'theme', 'lang'])); + brew.snippets = yamlSnippetsToText(_.pick(metadata, ['snippets']).snippets); brew.text = brew.text.slice(index + 6); } if(brew.text.startsWith('```css')) { @@ -98,11 +99,6 @@ const splitTextStyleAndMetadata = (brew)=>{ brew.style = brew.text.slice(7, index + 1); brew.text = brew.text.slice(index + 6); } - if(brew.text.startsWith('```snippets')) { - const index = brew.text.indexOf('\n```\n\n'); - brew.snippets = yamlSnippetsToText(yaml.load(brew.text.slice(11, index + 1))).slice(0, -1); - brew.text = brew.text.slice(index + 6); - } // Handle old brews that still have empty strings in the tags metadata if(typeof brew.tags === 'string') brew.tags = brew.tags ? [brew.tags] : []; From 9f56d100aaf5a250715fc70872e3410237378625 Mon Sep 17 00:00:00 2001 From: David Bolack Date: Tue, 8 Apr 2025 00:32:11 -0500 Subject: [PATCH 373/398] change tab --- client/homebrew/editor/editor.jsx | 6 +++--- client/homebrew/editor/snippetbar/snippetbar.jsx | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/client/homebrew/editor/editor.jsx b/client/homebrew/editor/editor.jsx index 7112aa4b9..77da1fcd9 100644 --- a/client/homebrew/editor/editor.jsx +++ b/client/homebrew/editor/editor.jsx @@ -61,7 +61,7 @@ const Editor = createClass({ getInitialState : function() { return { editorTheme : this.props.editorTheme, - view : 'text' //'text', 'style', 'meta', 'snip' + view : 'text' //'text', 'style', 'meta', 'snippet' }; }, @@ -71,7 +71,7 @@ const Editor = createClass({ isText : function() {return this.state.view == 'text';}, isStyle : function() {return this.state.view == 'style';}, isMeta : function() {return this.state.view == 'meta';}, - isSnip : function() {return this.state.view == 'snip';}, + isSnip : function() {return this.state.view == 'snippet';}, componentDidMount : function() { @@ -167,7 +167,7 @@ const Editor = createClass({ highlightCustomMarkdown : function(){ if(!this.codeEditor.current) return; - if((this.state.view === 'text') ||(this.state.view === 'snip')) { + if((this.state.view === 'text') ||(this.state.view === 'snippet')) { const codeMirror = this.codeEditor.current.codeMirror; codeMirror.operation(()=>{ // Batch CodeMirror styling diff --git a/client/homebrew/editor/snippetbar/snippetbar.jsx b/client/homebrew/editor/snippetbar/snippetbar.jsx index 8c6872ab4..5e2051a86 100644 --- a/client/homebrew/editor/snippetbar/snippetbar.jsx +++ b/client/homebrew/editor/snippetbar/snippetbar.jsx @@ -259,8 +259,8 @@ const Snippetbar = createClass({ onClick={()=>this.props.onViewChange('style')}> -
    this.props.onViewChange('snip')}> +
    this.props.onViewChange('snippet')}>
    Date: Tue, 8 Apr 2025 17:22:37 +0000 Subject: [PATCH 374/398] Bump eslint-plugin-react from 7.37.4 to 7.37.5 Bumps [eslint-plugin-react](https://github.com/jsx-eslint/eslint-plugin-react) from 7.37.4 to 7.37.5. - [Release notes](https://github.com/jsx-eslint/eslint-plugin-react/releases) - [Changelog](https://github.com/jsx-eslint/eslint-plugin-react/blob/master/CHANGELOG.md) - [Commits](https://github.com/jsx-eslint/eslint-plugin-react/compare/v7.37.4...v7.37.5) --- updated-dependencies: - dependency-name: eslint-plugin-react dependency-version: 7.37.5 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- package-lock.json | 74 +++++++++++++++++++++++++++++------------------ package.json | 2 +- 2 files changed, 47 insertions(+), 29 deletions(-) diff --git a/package-lock.json b/package-lock.json index 2e3af673a..582306d8f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -59,7 +59,7 @@ "babel-plugin-transform-import-meta": "^2.3.2", "eslint": "^9.23.0", "eslint-plugin-jest": "^28.11.0", - "eslint-plugin-react": "^7.37.4", + "eslint-plugin-react": "^7.37.5", "globals": "^16.0.0", "jest": "^29.7.0", "jest-expect-message": "^1.1.3", @@ -4300,9 +4300,10 @@ } }, "node_modules/call-bind-apply-helpers": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.1.tgz", - "integrity": "sha512-BhYE+WDaywFg2TBWYNXAE+8B1ATnThNBqXHP5nQu0jWJdVvY2hvkpyB3qOmtmDePiS5/BDQ8wASEWGMWRG148g==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "license": "MIT", "dependencies": { "es-errors": "^1.3.0", "function-bind": "^1.1.2" @@ -4312,12 +4313,13 @@ } }, "node_modules/call-bound": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.3.tgz", - "integrity": "sha512-YTd+6wGlNlPxSuri7Y6X8tY2dmm12UMH66RpKMhiX6rsk5wXXnYgbUcOt8kiS31/AjfoTOvCsE+w8nZQLQnzHA==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "license": "MIT", "dependencies": { - "call-bind-apply-helpers": "^1.0.1", - "get-intrinsic": "^1.2.6" + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" }, "engines": { "node": ">= 0.4" @@ -5618,9 +5620,9 @@ } }, "node_modules/es-object-atoms": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.0.0.tgz", - "integrity": "sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", "license": "MIT", "dependencies": { "es-errors": "^1.3.0" @@ -5773,10 +5775,11 @@ } }, "node_modules/eslint-plugin-react": { - "version": "7.37.4", - "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.37.4.tgz", - "integrity": "sha512-BGP0jRmfYyvOyvMoRX/uoUeW+GqNj9y16bPQzqAHf3AYII/tDs+jMN0dBVkl88/OZwNGwrVFxE7riHsXVfy/LQ==", + "version": "7.37.5", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.37.5.tgz", + "integrity": "sha512-Qteup0SqU15kdocexFNAJMvCJEfa2xUKNV4CC1xsVMrIIqEy3SQ/rqyxCWNzfrd3/ldy6HMlD2e0JDVpDg2qIA==", "dev": true, + "license": "MIT", "dependencies": { "array-includes": "^3.1.8", "array.prototype.findlast": "^1.2.5", @@ -5788,7 +5791,7 @@ "hasown": "^2.0.2", "jsx-ast-utils": "^2.4.1 || ^3.0.0", "minimatch": "^3.1.2", - "object.entries": "^1.1.8", + "object.entries": "^1.1.9", "object.fromentries": "^2.0.8", "object.values": "^1.2.1", "prop-types": "^15.8.1", @@ -6694,20 +6697,21 @@ } }, "node_modules/get-intrinsic": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.6.tgz", - "integrity": "sha512-qxsEs+9A+u85HhllWJJFicJfPDhRmjzoYdl64aMWW9yRIJmSyxdn8IEkuIM530/7T+lv0TIHd8L6Q/ra0tEoeA==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "license": "MIT", "dependencies": { - "call-bind-apply-helpers": "^1.0.1", - "dunder-proto": "^1.0.0", + "call-bind-apply-helpers": "^1.0.2", "es-define-property": "^1.0.1", "es-errors": "^1.3.0", - "es-object-atoms": "^1.0.0", + "es-object-atoms": "^1.1.1", "function-bind": "^1.1.2", + "get-proto": "^1.0.1", "gopd": "^1.2.0", "has-symbols": "^1.1.0", "hasown": "^2.0.2", - "math-intrinsics": "^1.0.0" + "math-intrinsics": "^1.1.0" }, "engines": { "node": ">= 0.4" @@ -6726,6 +6730,19 @@ "node": ">=8.0.0" } }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/get-stream": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", @@ -10844,15 +10861,16 @@ } }, "node_modules/object.entries": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.8.tgz", - "integrity": "sha512-cmopxi8VwRIAw/fkijJohSfpef5PdN0pMQJN6VC/ZKvn0LIknWD8KtgY6KlQdEc4tIjcQ3HxSMmnvtzIscdaYQ==", + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.9.tgz", + "integrity": "sha512-8u/hfXFRBD1O0hPUjioLhoWFHRmt6tKA4/vZPyckBr18l1KE9uHrFaFaUi8MDRTpi4uak2goyPTSNJLXX2k2Hw==", "dev": true, "license": "MIT", "dependencies": { - "call-bind": "^1.0.7", + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", "define-properties": "^1.2.1", - "es-object-atoms": "^1.0.0" + "es-object-atoms": "^1.1.1" }, "engines": { "node": ">= 0.4" diff --git a/package.json b/package.json index 8e88a3fd4..587ba6b1d 100644 --- a/package.json +++ b/package.json @@ -133,7 +133,7 @@ "babel-plugin-transform-import-meta": "^2.3.2", "eslint": "^9.23.0", "eslint-plugin-jest": "^28.11.0", - "eslint-plugin-react": "^7.37.4", + "eslint-plugin-react": "^7.37.5", "globals": "^16.0.0", "jest": "^29.7.0", "jest-expect-message": "^1.1.3", From 08946ce5d46069f0dfd64ac1c2be81c357d1acf0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 8 Apr 2025 17:22:50 +0000 Subject: [PATCH 375/398] Bump marked from 15.0.0 to 15.0.8 Bumps [marked](https://github.com/markedjs/marked) from 15.0.0 to 15.0.8. - [Release notes](https://github.com/markedjs/marked/releases) - [Changelog](https://github.com/markedjs/marked/blob/master/.releaserc.json) - [Commits](https://github.com/markedjs/marked/compare/v15.0.0...v15.0.8) --- updated-dependencies: - dependency-name: marked dependency-version: 15.0.8 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- package-lock.json | 8 ++++---- package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index 2e3af673a..3f1117e44 100644 --- a/package-lock.json +++ b/package-lock.json @@ -33,7 +33,7 @@ "jwt-simple": "^0.5.6", "less": "^3.13.1", "lodash": "^4.17.21", - "marked": "15.0.0", + "marked": "15.0.8", "marked-emoji": "^2.0.0", "marked-extended-tables": "^2.0.1", "marked-gfm-heading-id": "^4.0.1", @@ -9894,9 +9894,9 @@ } }, "node_modules/marked": { - "version": "15.0.0", - "resolved": "https://registry.npmjs.org/marked/-/marked-15.0.0.tgz", - "integrity": "sha512-0mouKmBROJv/WSHJBPZZyYofUgawMChnD5je/g+aOBXsHDjb/IsnTQj7mnhQZu+qPJmRQ0ecX3mLGEUm3BgwYA==", + "version": "15.0.8", + "resolved": "https://registry.npmjs.org/marked/-/marked-15.0.8.tgz", + "integrity": "sha512-rli4l2LyZqpQuRve5C0rkn6pj3hT8EWPC+zkAxFTAJLxRbENfTAhEQq9itrmf1Y81QtAX5D/MYlGlIomNgj9lA==", "license": "MIT", "bin": { "marked": "bin/marked.js" diff --git a/package.json b/package.json index 8e88a3fd4..fba5fca50 100644 --- a/package.json +++ b/package.json @@ -107,7 +107,7 @@ "jwt-simple": "^0.5.6", "less": "^3.13.1", "lodash": "^4.17.21", - "marked": "15.0.0", + "marked": "15.0.8", "marked-emoji": "^2.0.0", "marked-extended-tables": "^2.0.1", "marked-gfm-heading-id": "^4.0.1", From 9a57b407a595773218449ca536348f843212df21 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 8 Apr 2025 17:46:52 +0000 Subject: [PATCH 376/398] Bump mongoose from 8.13.0 to 8.13.2 Bumps [mongoose](https://github.com/Automattic/mongoose) from 8.13.0 to 8.13.2. - [Release notes](https://github.com/Automattic/mongoose/releases) - [Changelog](https://github.com/Automattic/mongoose/blob/master/CHANGELOG.md) - [Commits](https://github.com/Automattic/mongoose/compare/8.13.0...8.13.2) --- updated-dependencies: - dependency-name: mongoose dependency-version: 8.13.2 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- package-lock.json | 8 ++++---- package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index 3f1117e44..183b68410 100644 --- a/package-lock.json +++ b/package-lock.json @@ -41,7 +41,7 @@ "marked-subsuper-text": "^1.0.3", "markedLegacy": "npm:marked@^0.3.19", "moment": "^2.30.1", - "mongoose": "^8.13.0", + "mongoose": "^8.13.2", "nanoid": "5.1.5", "nconf": "^0.12.1", "react": "^18.3.1", @@ -10308,9 +10308,9 @@ } }, "node_modules/mongoose": { - "version": "8.13.0", - "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-8.13.0.tgz", - "integrity": "sha512-e/iYV1mPeOkg+SWAMHzt3t42/EZyER3OB1H2pjP9C3vQ+Qb5DMeV9Kb+YCUycKgScA3fbwL7dKG4EpinGlg21g==", + "version": "8.13.2", + "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-8.13.2.tgz", + "integrity": "sha512-riCBqZmNkYBWjXpM3qWLDQw7QmTKsVZDPhLXFJqC87+OjocEVpvS3dA2BPPUiLAu+m0/QmEj5pSXKhH+/DgerQ==", "license": "MIT", "dependencies": { "bson": "^6.10.3", diff --git a/package.json b/package.json index fba5fca50..834c15f58 100644 --- a/package.json +++ b/package.json @@ -115,7 +115,7 @@ "marked-subsuper-text": "^1.0.3", "markedLegacy": "npm:marked@^0.3.19", "moment": "^2.30.1", - "mongoose": "^8.13.0", + "mongoose": "^8.13.2", "nanoid": "5.1.5", "nconf": "^0.12.1", "react": "^18.3.1", From 518bc7030d73067b59032426962def95afa73595 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 8 Apr 2025 17:51:04 +0000 Subject: [PATCH 377/398] Bump eslint from 9.23.0 to 9.24.0 Bumps [eslint](https://github.com/eslint/eslint) from 9.23.0 to 9.24.0. - [Release notes](https://github.com/eslint/eslint/releases) - [Changelog](https://github.com/eslint/eslint/blob/main/CHANGELOG.md) - [Commits](https://github.com/eslint/eslint/compare/v9.23.0...v9.24.0) --- updated-dependencies: - dependency-name: eslint dependency-version: 9.24.0 dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- package-lock.json | 24 ++++++++++++------------ package.json | 2 +- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/package-lock.json b/package-lock.json index 183b68410..e3caa64b9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -57,7 +57,7 @@ "devDependencies": { "@stylistic/stylelint-plugin": "^3.1.2", "babel-plugin-transform-import-meta": "^2.3.2", - "eslint": "^9.23.0", + "eslint": "^9.24.0", "eslint-plugin-jest": "^28.11.0", "eslint-plugin-react": "^7.37.4", "globals": "^16.0.0", @@ -1852,9 +1852,9 @@ } }, "node_modules/@eslint/config-array": { - "version": "0.19.2", - "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.19.2.tgz", - "integrity": "sha512-GNKqxfHG2ySmJOBSHg7LxeUx4xpuCoFjacmlCoYWEbaPXLwvfIjixRI12xCQZeULksQb23uiA8F40w5TojpV7w==", + "version": "0.20.0", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.20.0.tgz", + "integrity": "sha512-fxlS1kkIjx8+vy2SjuCB94q3htSNrufYTXubwiBFeaQHbH6Ipi43gFJq2zCMt6PHhImH3Xmr0NksKDvchWlpQQ==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -1927,9 +1927,9 @@ } }, "node_modules/@eslint/js": { - "version": "9.23.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.23.0.tgz", - "integrity": "sha512-35MJ8vCPU0ZMxo7zfev2pypqTwWTofFZO6m4KAtdoFhRpLJUpHTZZ+KB3C7Hb1d7bULYwO4lJXGCi5Se+8OMbw==", + "version": "9.24.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.24.0.tgz", + "integrity": "sha512-uIY/y3z0uvOGX8cp1C2fiC4+ZmBhp6yZWkojtHL1YEMnRt1Y63HB9TM17proGEmeG7HeUY+UP36F0aknKYTpYA==", "dev": true, "license": "MIT", "engines": { @@ -5687,19 +5687,19 @@ "license": "MIT" }, "node_modules/eslint": { - "version": "9.23.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.23.0.tgz", - "integrity": "sha512-jV7AbNoFPAY1EkFYpLq5bslU9NLNO8xnEeQXwErNibVryjk67wHVmddTBilc5srIttJDBrB0eMHKZBFbSIABCw==", + "version": "9.24.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.24.0.tgz", + "integrity": "sha512-eh/jxIEJyZrvbWRe4XuVclLPDYSYYYgLy5zXGGxD6j8zjSAxFEzI2fL/8xNq6O2yKqVt+eF2YhV+hxjV6UKXwQ==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.12.1", - "@eslint/config-array": "^0.19.2", + "@eslint/config-array": "^0.20.0", "@eslint/config-helpers": "^0.2.0", "@eslint/core": "^0.12.0", "@eslint/eslintrc": "^3.3.1", - "@eslint/js": "9.23.0", + "@eslint/js": "9.24.0", "@eslint/plugin-kit": "^0.2.7", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", diff --git a/package.json b/package.json index 834c15f58..9589576a5 100644 --- a/package.json +++ b/package.json @@ -131,7 +131,7 @@ "devDependencies": { "@stylistic/stylelint-plugin": "^3.1.2", "babel-plugin-transform-import-meta": "^2.3.2", - "eslint": "^9.23.0", + "eslint": "^9.24.0", "eslint-plugin-jest": "^28.11.0", "eslint-plugin-react": "^7.37.4", "globals": "^16.0.0", From 512eedfc3986ed2f03a24ffe6c5e4745c5883bec Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 8 Apr 2025 17:51:04 +0000 Subject: [PATCH 378/398] Bump stylelint from 16.17.0 to 16.18.0 Bumps [stylelint](https://github.com/stylelint/stylelint) from 16.17.0 to 16.18.0. - [Release notes](https://github.com/stylelint/stylelint/releases) - [Changelog](https://github.com/stylelint/stylelint/blob/main/CHANGELOG.md) - [Commits](https://github.com/stylelint/stylelint/compare/16.17.0...16.18.0) --- updated-dependencies: - dependency-name: stylelint dependency-version: 16.18.0 dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- package-lock.json | 8 ++++---- package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index 183b68410..4e3b46355 100644 --- a/package-lock.json +++ b/package-lock.json @@ -65,7 +65,7 @@ "jest-expect-message": "^1.1.3", "jsdom-global": "^3.0.2", "postcss-less": "^6.0.0", - "stylelint": "^16.17.0", + "stylelint": "^16.18.0", "stylelint-config-recess-order": "^6.0.0", "stylelint-config-recommended": "^15.0.0", "supertest": "^7.1.0" @@ -13135,9 +13135,9 @@ "license": "ISC" }, "node_modules/stylelint": { - "version": "16.17.0", - "resolved": "https://registry.npmjs.org/stylelint/-/stylelint-16.17.0.tgz", - "integrity": "sha512-I9OwVIWRMqVm2Br5iTbrfSqGRPWQUlvm6oXO1xZuYYu0Gpduy67N8wXOZv15p6E/JdlZiAtQaIoLKZEWk5hrjw==", + "version": "16.18.0", + "resolved": "https://registry.npmjs.org/stylelint/-/stylelint-16.18.0.tgz", + "integrity": "sha512-OXb68qzesv7J70BSbFwfK3yTVLEVXiQ/ro6wUE4UrSbKCMjLLA02S8Qq3LC01DxKyVjk7z8xh35aB4JzO3/sNA==", "dev": true, "funding": [ { diff --git a/package.json b/package.json index 834c15f58..4694e6ae8 100644 --- a/package.json +++ b/package.json @@ -139,7 +139,7 @@ "jest-expect-message": "^1.1.3", "jsdom-global": "^3.0.2", "postcss-less": "^6.0.0", - "stylelint": "^16.17.0", + "stylelint": "^16.18.0", "stylelint-config-recess-order": "^6.0.0", "stylelint-config-recommended": "^15.0.0", "supertest": "^7.1.0" From b461ac0a683d1b3ff0a647ee7b181597baae3096 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 8 Apr 2025 17:55:07 +0000 Subject: [PATCH 379/398] Bump react-router from 7.4.0 to 7.5.0 Bumps [react-router](https://github.com/remix-run/react-router/tree/HEAD/packages/react-router) from 7.4.0 to 7.5.0. - [Release notes](https://github.com/remix-run/react-router/releases) - [Changelog](https://github.com/remix-run/react-router/blob/main/packages/react-router/CHANGELOG.md) - [Commits](https://github.com/remix-run/react-router/commits/react-router@7.5.0/packages/react-router) --- updated-dependencies: - dependency-name: react-router dependency-version: 7.5.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- package-lock.json | 8 ++++---- package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index e3caa64b9..429262ac7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -47,7 +47,7 @@ "react": "^18.3.1", "react-dom": "^18.3.1", "react-frame-component": "^4.1.3", - "react-router": "^7.4.0", + "react-router": "^7.5.0", "romans": "^3.0.0", "sanitize-filename": "1.6.3", "superagent": "^10.2.0", @@ -11743,9 +11743,9 @@ "license": "MIT" }, "node_modules/react-router": { - "version": "7.4.0", - "resolved": "https://registry.npmjs.org/react-router/-/react-router-7.4.0.tgz", - "integrity": "sha512-Y2g5ObjkvX3VFeVt+0CIPuYd9PpgqCslG7ASSIdN73LwA1nNWzcMLaoMRJfP3prZFI92svxFwbn7XkLJ+UPQ6A==", + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-7.5.0.tgz", + "integrity": "sha512-estOHrRlDMKdlQa6Mj32gIks4J+AxNsYoE0DbTTxiMy2mPzZuWSDU+N85/r1IlNR7kGfznF3VCUlvc5IUO+B9g==", "license": "MIT", "dependencies": { "@types/cookie": "^0.6.0", diff --git a/package.json b/package.json index 9589576a5..976ebcc6c 100644 --- a/package.json +++ b/package.json @@ -121,7 +121,7 @@ "react": "^18.3.1", "react-dom": "^18.3.1", "react-frame-component": "^4.1.3", - "react-router": "^7.4.0", + "react-router": "^7.5.0", "romans": "^3.0.0", "sanitize-filename": "1.6.3", "superagent": "^10.2.0", From 075fdb194ecec97c7ebab8dcfd31f8e9812e50bd Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 8 Apr 2025 18:41:53 +0000 Subject: [PATCH 380/398] Bump stylelint-config-recommended from 15.0.0 to 16.0.0 Bumps [stylelint-config-recommended](https://github.com/stylelint/stylelint-config-recommended) from 15.0.0 to 16.0.0. - [Release notes](https://github.com/stylelint/stylelint-config-recommended/releases) - [Changelog](https://github.com/stylelint/stylelint-config-recommended/blob/main/CHANGELOG.md) - [Commits](https://github.com/stylelint/stylelint-config-recommended/compare/15.0.0...16.0.0) --- updated-dependencies: - dependency-name: stylelint-config-recommended dependency-version: 16.0.0 dependency-type: direct:development update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- package-lock.json | 11 ++++++----- package.json | 2 +- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/package-lock.json b/package-lock.json index 06923181b..eb5ceec82 100644 --- a/package-lock.json +++ b/package-lock.json @@ -67,7 +67,7 @@ "postcss-less": "^6.0.0", "stylelint": "^16.18.0", "stylelint-config-recess-order": "^6.0.0", - "stylelint-config-recommended": "^15.0.0", + "stylelint-config-recommended": "^16.0.0", "supertest": "^7.1.0" }, "engines": { @@ -13210,9 +13210,9 @@ } }, "node_modules/stylelint-config-recommended": { - "version": "15.0.0", - "resolved": "https://registry.npmjs.org/stylelint-config-recommended/-/stylelint-config-recommended-15.0.0.tgz", - "integrity": "sha512-9LejMFsat7L+NXttdHdTq94byn25TD+82bzGRiV1Pgasl99pWnwipXS5DguTpp3nP1XjvLXVnEJIuYBfsRjRkA==", + "version": "16.0.0", + "resolved": "https://registry.npmjs.org/stylelint-config-recommended/-/stylelint-config-recommended-16.0.0.tgz", + "integrity": "sha512-4RSmPjQegF34wNcK1e1O3Uz91HN8P1aFdFzio90wNK9mjgAI19u5vsU868cVZboKzCaa5XbpvtTzAAGQAxpcXA==", "dev": true, "funding": [ { @@ -13224,11 +13224,12 @@ "url": "https://github.com/sponsors/stylelint" } ], + "license": "MIT", "engines": { "node": ">=18.12.0" }, "peerDependencies": { - "stylelint": "^16.13.0" + "stylelint": "^16.16.0" } }, "node_modules/stylelint-order": { diff --git a/package.json b/package.json index 6be967070..29d9cec56 100644 --- a/package.json +++ b/package.json @@ -141,7 +141,7 @@ "postcss-less": "^6.0.0", "stylelint": "^16.18.0", "stylelint-config-recess-order": "^6.0.0", - "stylelint-config-recommended": "^15.0.0", + "stylelint-config-recommended": "^16.0.0", "supertest": "^7.1.0" } } From 0be5c6c57673b88a6de00fa5c8d7c3eb41845155 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 8 Apr 2025 20:57:29 +0000 Subject: [PATCH 381/398] Bump body-parser from 1.20.3 to 2.2.0 Bumps [body-parser](https://github.com/expressjs/body-parser) from 1.20.3 to 2.2.0. - [Release notes](https://github.com/expressjs/body-parser/releases) - [Changelog](https://github.com/expressjs/body-parser/blob/master/HISTORY.md) - [Commits](https://github.com/expressjs/body-parser/compare/1.20.3...v2.2.0) --- updated-dependencies: - dependency-name: body-parser dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- package-lock.json | 195 ++++++++++++++++++++++++++++++++-------------- package.json | 2 +- 2 files changed, 138 insertions(+), 59 deletions(-) diff --git a/package-lock.json b/package-lock.json index 81cb9c6c0..8828ff7c8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15,7 +15,7 @@ "@babel/preset-env": "^7.26.9", "@babel/preset-react": "^7.26.3", "@googleapis/drive": "^11.0.0", - "body-parser": "^1.20.2", + "body-parser": "^2.2.0", "classnames": "^2.5.1", "codemirror": "^5.65.6", "cookie-parser": "^1.4.7", @@ -3885,42 +3885,83 @@ "license": "MIT" }, "node_modules/body-parser": { - "version": "1.20.3", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz", - "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==", - "dependencies": { - "bytes": "3.1.2", - "content-type": "~1.0.5", - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "1.2.0", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "on-finished": "2.4.1", - "qs": "6.13.0", - "raw-body": "2.5.2", - "type-is": "~1.6.18", - "unpipe": "1.0.0" - }, - "engines": { - "node": ">= 0.8", - "npm": "1.2.8000 || >= 1.4.16" - } - }, - "node_modules/body-parser/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.0.tgz", + "integrity": "sha512-02qvAaxv8tp7fBa/mw1ga98OGm+eCbqzJOKoRt70sLmfEEi+jyBYVTDGfCL/k06/4EMk/z01gCe7HoCH/f2LTg==", "license": "MIT", "dependencies": { - "ms": "2.0.0" + "bytes": "^3.1.2", + "content-type": "^1.0.5", + "debug": "^4.4.0", + "http-errors": "^2.0.0", + "iconv-lite": "^0.6.3", + "on-finished": "^2.4.1", + "qs": "^6.14.0", + "raw-body": "^3.0.0", + "type-is": "^2.0.0" + }, + "engines": { + "node": ">=18" } }, - "node_modules/body-parser/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "license": "MIT" + "node_modules/body-parser/node_modules/media-typer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.0.tgz", + "integrity": "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/body-parser/node_modules/mime-db": { + "version": "1.54.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", + "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/body-parser/node_modules/mime-types": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.1.tgz", + "integrity": "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==", + "license": "MIT", + "dependencies": { + "mime-db": "^1.54.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/body-parser/node_modules/qs": { + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.0.tgz", + "integrity": "sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==", + "license": "BSD-3-Clause", + "dependencies": { + "side-channel": "^1.1.0" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/body-parser/node_modules/type-is": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-2.0.1.tgz", + "integrity": "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==", + "license": "MIT", + "dependencies": { + "content-type": "^1.0.5", + "media-typer": "^1.1.0", + "mime-types": "^3.0.0" + }, + "engines": { + "node": ">= 0.6" + } }, "node_modules/brace-expansion": { "version": "1.1.11", @@ -5100,9 +5141,10 @@ } }, "node_modules/debug": { - "version": "4.3.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", - "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", + "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", + "license": "MIT", "dependencies": { "ms": "^2.1.3" }, @@ -6201,6 +6243,30 @@ "serve-static": "^1.16.2" } }, + "node_modules/express/node_modules/body-parser": { + "version": "1.20.3", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz", + "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==", + "license": "MIT", + "dependencies": { + "bytes": "3.1.2", + "content-type": "~1.0.5", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.13.0", + "raw-body": "2.5.2", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, "node_modules/express/node_modules/cookie": { "version": "0.7.1", "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz", @@ -6218,12 +6284,39 @@ "ms": "2.0.0" } }, + "node_modules/express/node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/express/node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "license": "MIT" }, + "node_modules/express/node_modules/raw-body": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", + "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", + "license": "MIT", + "dependencies": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/extend": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", @@ -7304,12 +7397,12 @@ } }, "node_modules/iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", "license": "MIT", "dependencies": { - "safer-buffer": ">= 2.1.2 < 3" + "safer-buffer": ">= 2.1.2 < 3.0.0" }, "engines": { "node": ">=0.10.0" @@ -11703,14 +11796,14 @@ } }, "node_modules/raw-body": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", - "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.0.tgz", + "integrity": "sha512-RmkhL8CAyCRPXCE28MMH0z2PNWQBNk2Q09ZdxM9IOOXwxwZbN+qbWaatPkdkWIKL2ZVDImrN/pK5HTRz2PcS4g==", "license": "MIT", "dependencies": { "bytes": "3.1.2", "http-errors": "2.0.0", - "iconv-lite": "0.4.24", + "iconv-lite": "0.6.3", "unpipe": "1.0.0" }, "engines": { @@ -14749,20 +14842,6 @@ "node": ">=18" } }, - "node_modules/whatwg-encoding/node_modules/iconv-lite": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", - "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/whatwg-mimetype": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-4.0.0.tgz", diff --git a/package.json b/package.json index be15f22ad..171434945 100644 --- a/package.json +++ b/package.json @@ -89,7 +89,7 @@ "@babel/preset-env": "^7.26.9", "@babel/preset-react": "^7.26.3", "@googleapis/drive": "^11.0.0", - "body-parser": "^1.20.2", + "body-parser": "^2.2.0", "classnames": "^2.5.1", "codemirror": "^5.65.6", "cookie-parser": "^1.4.7", From 0dbbc469e1d8316c90744414b42c3797a47fd568 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 8 Apr 2025 21:12:15 +0000 Subject: [PATCH 382/398] Bump express from 4.21.2 to 5.1.0 Bumps [express](https://github.com/expressjs/express) from 4.21.2 to 5.1.0. - [Release notes](https://github.com/expressjs/express/releases) - [Changelog](https://github.com/expressjs/express/blob/master/History.md) - [Commits](https://github.com/expressjs/express/compare/4.21.2...v5.1.0) --- updated-dependencies: - dependency-name: express dependency-version: 5.1.0 dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- package-lock.json | 420 ++++++++++++++++++++++------------------------ package.json | 2 +- 2 files changed, 203 insertions(+), 219 deletions(-) diff --git a/package-lock.json b/package-lock.json index 8828ff7c8..9dd4a93c4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -24,7 +24,7 @@ "create-react-class": "^15.7.0", "dedent-tabs": "^0.10.3", "expr-eval": "^2.0.2", - "express": "^4.21.2", + "express": "^5.1.0", "express-async-handler": "^1.2.0", "express-static-gzip": "2.2.0", "fs-extra": "11.3.0", @@ -3116,13 +3116,34 @@ } }, "node_modules/accepts": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", - "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz", + "integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==", "license": "MIT", "dependencies": { - "mime-types": "~2.1.34", - "negotiator": "0.6.3" + "mime-types": "^3.0.0", + "negotiator": "^1.0.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/accepts/node_modules/mime-db": { + "version": "1.54.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", + "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/accepts/node_modules/mime-types": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.1.tgz", + "integrity": "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==", + "license": "MIT", + "dependencies": { + "mime-db": "^1.54.0" }, "engines": { "node": ">= 0.6" @@ -3313,12 +3334,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/array-flatten": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", - "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", - "license": "MIT" - }, "node_modules/array-includes": { "version": "3.1.8", "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.8.tgz", @@ -3904,65 +3919,6 @@ "node": ">=18" } }, - "node_modules/body-parser/node_modules/media-typer": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.0.tgz", - "integrity": "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/body-parser/node_modules/mime-db": { - "version": "1.54.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", - "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/body-parser/node_modules/mime-types": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.1.tgz", - "integrity": "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==", - "license": "MIT", - "dependencies": { - "mime-db": "^1.54.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/body-parser/node_modules/qs": { - "version": "6.14.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.0.tgz", - "integrity": "sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==", - "license": "BSD-3-Clause", - "dependencies": { - "side-channel": "^1.1.0" - }, - "engines": { - "node": ">=0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/body-parser/node_modules/type-is": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/type-is/-/type-is-2.0.1.tgz", - "integrity": "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==", - "license": "MIT", - "dependencies": { - "content-type": "^1.0.5", - "media-typer": "^1.1.0", - "mime-types": "^3.0.0" - }, - "engines": { - "node": ">= 0.6" - } - }, "node_modules/brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -4679,9 +4635,9 @@ "license": "MIT" }, "node_modules/content-disposition": { - "version": "0.5.4", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", - "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.0.0.tgz", + "integrity": "sha512-Au9nRL8VNUut/XSzbQA38+M78dzP4D+eqg3gfJHMIHHYa3bg067xj1KxMUWj+VULbiZMowKngFFbKczUrNJ1mg==", "license": "MIT", "dependencies": { "safe-buffer": "5.2.1" @@ -6183,45 +6139,41 @@ "license": "MIT" }, "node_modules/express": { - "version": "4.21.2", - "resolved": "https://registry.npmjs.org/express/-/express-4.21.2.tgz", - "integrity": "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/express/-/express-5.1.0.tgz", + "integrity": "sha512-DT9ck5YIRU+8GYzzU5kT3eHGA5iL+1Zd0EutOmTE9Dtk+Tvuzd23VBU+ec7HPNSTxXYO55gPV/hq4pSBJDjFpA==", "license": "MIT", "dependencies": { - "accepts": "~1.3.8", - "array-flatten": "1.1.1", - "body-parser": "1.20.3", - "content-disposition": "0.5.4", - "content-type": "~1.0.4", - "cookie": "0.7.1", - "cookie-signature": "1.0.6", - "debug": "2.6.9", - "depd": "2.0.0", - "encodeurl": "~2.0.0", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "finalhandler": "1.3.1", - "fresh": "0.5.2", - "http-errors": "2.0.0", - "merge-descriptors": "1.0.3", - "methods": "~1.1.2", - "on-finished": "2.4.1", - "parseurl": "~1.3.3", - "path-to-regexp": "0.1.12", - "proxy-addr": "~2.0.7", - "qs": "6.13.0", - "range-parser": "~1.2.1", - "safe-buffer": "5.2.1", - "send": "0.19.0", - "serve-static": "1.16.2", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "type-is": "~1.6.18", - "utils-merge": "1.0.1", - "vary": "~1.1.2" + "accepts": "^2.0.0", + "body-parser": "^2.2.0", + "content-disposition": "^1.0.0", + "content-type": "^1.0.5", + "cookie": "^0.7.1", + "cookie-signature": "^1.2.1", + "debug": "^4.4.0", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "etag": "^1.8.1", + "finalhandler": "^2.1.0", + "fresh": "^2.0.0", + "http-errors": "^2.0.0", + "merge-descriptors": "^2.0.0", + "mime-types": "^3.0.0", + "on-finished": "^2.4.1", + "once": "^1.4.0", + "parseurl": "^1.3.3", + "proxy-addr": "^2.0.7", + "qs": "^6.14.0", + "range-parser": "^1.2.1", + "router": "^2.2.0", + "send": "^1.1.0", + "serve-static": "^2.2.0", + "statuses": "^2.0.1", + "type-is": "^2.0.1", + "vary": "^1.1.2" }, "engines": { - "node": ">= 0.10.0" + "node": ">= 18" }, "funding": { "type": "opencollective", @@ -6243,78 +6195,80 @@ "serve-static": "^1.16.2" } }, - "node_modules/express/node_modules/body-parser": { - "version": "1.20.3", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz", - "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==", + "node_modules/express/node_modules/cookie-signature": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.2.2.tgz", + "integrity": "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==", "license": "MIT", - "dependencies": { - "bytes": "3.1.2", - "content-type": "~1.0.5", - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "1.2.0", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "on-finished": "2.4.1", - "qs": "6.13.0", - "raw-body": "2.5.2", - "type-is": "~1.6.18", - "unpipe": "1.0.0" - }, "engines": { - "node": ">= 0.8", - "npm": "1.2.8000 || >= 1.4.16" + "node": ">=6.6.0" } }, - "node_modules/express/node_modules/cookie": { - "version": "0.7.1", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz", - "integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==", + "node_modules/express/node_modules/fresh": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz", + "integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/express/node_modules/mime-db": { + "version": "1.54.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", + "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", + "license": "MIT", "engines": { "node": ">= 0.6" } }, - "node_modules/express/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "node_modules/express/node_modules/mime-types": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.1.tgz", + "integrity": "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==", "license": "MIT", "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/express/node_modules/iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "license": "MIT", - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3" + "mime-db": "^1.54.0" }, "engines": { - "node": ">=0.10.0" + "node": ">= 0.6" } }, - "node_modules/express/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "license": "MIT" - }, - "node_modules/express/node_modules/raw-body": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", - "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", + "node_modules/express/node_modules/send": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/send/-/send-1.2.0.tgz", + "integrity": "sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw==", "license": "MIT", "dependencies": { - "bytes": "3.1.2", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "unpipe": "1.0.0" + "debug": "^4.3.5", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "etag": "^1.8.1", + "fresh": "^2.0.0", + "http-errors": "^2.0.0", + "mime-types": "^3.0.1", + "ms": "^2.1.3", + "on-finished": "^2.4.1", + "range-parser": "^1.2.1", + "statuses": "^2.0.1" }, "engines": { - "node": ">= 0.8" + "node": ">= 18" + } + }, + "node_modules/express/node_modules/serve-static": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.2.0.tgz", + "integrity": "sha512-61g9pCh0Vnh7IutZjtLGGpTA355+OPn2TyDv/6ivP2h/AdAVX9azsoxmg2/M6nZeQZNYBEwIcsne1mJd9oQItQ==", + "license": "MIT", + "dependencies": { + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "parseurl": "^1.3.3", + "send": "^1.2.0" + }, + "engines": { + "node": ">= 18" } }, "node_modules/extend": { @@ -6504,35 +6458,22 @@ } }, "node_modules/finalhandler": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz", - "integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.0.tgz", + "integrity": "sha512-/t88Ty3d5JWQbWYgaOGCCYfXRwV1+be02WqYYlL6h0lEiUAMPM8o8qKGO01YIkOHzka2up08wvgYD0mDiI+q3Q==", + "license": "MIT", "dependencies": { - "debug": "2.6.9", - "encodeurl": "~2.0.0", - "escape-html": "~1.0.3", - "on-finished": "2.4.1", - "parseurl": "~1.3.3", - "statuses": "2.0.1", - "unpipe": "~1.0.0" + "debug": "^4.4.0", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "on-finished": "^2.4.1", + "parseurl": "^1.3.3", + "statuses": "^2.0.1" }, "engines": { "node": ">= 0.8" } }, - "node_modules/finalhandler/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/finalhandler/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" - }, "node_modules/find-up": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", @@ -7925,6 +7866,12 @@ "license": "MIT", "peer": true }, + "node_modules/is-promise": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz", + "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==", + "license": "MIT" + }, "node_modules/is-regex": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz", @@ -10113,12 +10060,12 @@ "dev": true }, "node_modules/media-typer": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", - "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.0.tgz", + "integrity": "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==", "license": "MIT", "engines": { - "node": ">= 0.6" + "node": ">= 0.8" } }, "node_modules/memory-pager": { @@ -10141,9 +10088,13 @@ } }, "node_modules/merge-descriptors": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", - "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-2.0.0.tgz", + "integrity": "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==", + "license": "MIT", + "engines": { + "node": ">=18" + }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } @@ -10750,9 +10701,9 @@ } }, "node_modules/negotiator": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", - "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz", + "integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==", "license": "MIT", "engines": { "node": ">= 0.6" @@ -11289,10 +11240,13 @@ } }, "node_modules/path-to-regexp": { - "version": "0.1.12", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz", - "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==", - "license": "MIT" + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.2.0.tgz", + "integrity": "sha512-TdrF7fW9Rphjq4RjrW0Kp2AW0Ahwu9sRGTkS6bvDi0SCwZlEZYmcfDbEsTz8RVk0EHIS/Vd1bv3JhG+1xZuAyQ==", + "license": "MIT", + "engines": { + "node": ">=16" + } }, "node_modules/path-type": { "version": "4.0.0", @@ -11725,11 +11679,12 @@ "license": "MIT" }, "node_modules/qs": { - "version": "6.13.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", - "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.0.tgz", + "integrity": "sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==", + "license": "BSD-3-Clause", "dependencies": { - "side-channel": "^1.0.6" + "side-channel": "^1.1.0" }, "engines": { "node": ">=0.6" @@ -12239,6 +12194,22 @@ "integrity": "sha512-7DDsAfhtpRr/ZFQXiHDrC3Pe00agcAsFiNt5nNx4ZAQlsc6yJG0mvXA5WAvO8YZyOg349twm2GYhHLw7rCXAzw==", "license": "MIT" }, + "node_modules/router": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/router/-/router-2.2.0.tgz", + "integrity": "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==", + "license": "MIT", + "dependencies": { + "debug": "^4.4.0", + "depd": "^2.0.0", + "is-promise": "^4.0.0", + "parseurl": "^1.3.3", + "path-to-regexp": "^8.0.0" + }, + "engines": { + "node": ">= 18" + } + }, "node_modules/rrweb-cssom": { "version": "0.7.1", "resolved": "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.7.1.tgz", @@ -14005,13 +13976,35 @@ } }, "node_modules/type-is": { - "version": "1.6.18", - "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", - "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-2.0.1.tgz", + "integrity": "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==", "license": "MIT", "dependencies": { - "media-typer": "0.3.0", - "mime-types": "~2.1.24" + "content-type": "^1.0.5", + "media-typer": "^1.1.0", + "mime-types": "^3.0.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/type-is/node_modules/mime-db": { + "version": "1.54.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", + "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/type-is/node_modules/mime-types": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.1.tgz", + "integrity": "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==", + "license": "MIT", + "dependencies": { + "mime-db": "^1.54.0" }, "engines": { "node": ">= 0.6" @@ -14409,15 +14402,6 @@ "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==", "license": "ISC" }, - "node_modules/utils-merge": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", - "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", - "license": "MIT", - "engines": { - "node": ">= 0.4.0" - } - }, "node_modules/uuid": { "version": "9.0.1", "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", diff --git a/package.json b/package.json index 171434945..b630070cb 100644 --- a/package.json +++ b/package.json @@ -98,7 +98,7 @@ "create-react-class": "^15.7.0", "dedent-tabs": "^0.10.3", "expr-eval": "^2.0.2", - "express": "^4.21.2", + "express": "^5.1.0", "express-async-handler": "^1.2.0", "express-static-gzip": "2.2.0", "fs-extra": "11.3.0", From be2f1786b59a23621e6c1058d1fb8fa96662298f Mon Sep 17 00:00:00 2001 From: "G.Ambatte" Date: Wed, 9 Apr 2025 09:59:34 +1200 Subject: [PATCH 383/398] Add authors to locked brew error message --- client/homebrew/pages/errorPage/errors/errorIndex.js | 4 +++- server/homebrew.api.js | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/client/homebrew/pages/errorPage/errors/errorIndex.js b/client/homebrew/pages/errorPage/errors/errorIndex.js index 2f0d4599b..0315c021c 100644 --- a/client/homebrew/pages/errorPage/errors/errorIndex.js +++ b/client/homebrew/pages/errorPage/errors/errorIndex.js @@ -194,7 +194,9 @@ const errorIndex = (props)=>{ **Brew ID:** ${props.brew.brewId} - **Brew Title:** ${escape(props.brew.brewTitle)}`, + **Brew Title:** ${escape(props.brew.brewTitle)} + + **Brew Authors:** ${escape(props.brew.brewAuthors.length ? props.brew.brewAuthors.join(',') : 'No listed authors')}`, // ####### Admin page error ####### '52' : dedent` diff --git a/server/homebrew.api.js b/server/homebrew.api.js index c59c6c4d7..3c7566af7 100644 --- a/server/homebrew.api.js +++ b/server/homebrew.api.js @@ -119,7 +119,7 @@ const api = { } if(stub?.lock && accessType === 'share') { - throw { HBErrorCode: '51', code: stub.lock.code, message: stub.lock.shareMessage, brewId: stub.shareId, brewTitle: stub.title }; + throw { HBErrorCode: '51', code: stub.lock.code, message: stub.lock.shareMessage, brewId: stub.shareId, brewTitle: stub.title, brewAuthors: stub.authors }; } // If there's a google id, get it if requesting the full brew or if no stub found yet From e3de7b9f012770719aaf9933d2bcab1cfda540e6 Mon Sep 17 00:00:00 2001 From: "G.Ambatte" Date: Wed, 9 Apr 2025 10:17:35 +1200 Subject: [PATCH 384/398] Tweak lock styling --- client/admin/lockTools/lockTools.less | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/admin/lockTools/lockTools.less b/client/admin/lockTools/lockTools.less index f6e7ea9dd..94a27ac8e 100644 --- a/client/admin/lockTools/lockTools.less +++ b/client/admin/lockTools/lockTools.less @@ -8,7 +8,7 @@ label { display : inline-block; width : 100%; - line-height : 1.5em; + line-height : 2.25em; text-align : right; input { float : right; From dc724492efbf6debebbf6ae3584846fdf1c3c9b6 Mon Sep 17 00:00:00 2001 From: "G.Ambatte" Date: Wed, 9 Apr 2025 10:26:10 +1200 Subject: [PATCH 385/398] Prevent BrewUtils from loading when it is not the current Admin tab --- client/admin/admin.jsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/admin/admin.jsx b/client/admin/admin.jsx index f59162e1d..29973d221 100644 --- a/client/admin/admin.jsx +++ b/client/admin/admin.jsx @@ -8,10 +8,10 @@ import LockTools from './lockTools/lockTools.jsx'; const tabGroups = ['brew', 'notifications', 'authors', 'locks']; const Admin = ()=>{ - const [currentTab, setCurrentTab] = useState('brew'); + const [currentTab, setCurrentTab] = useState(''); useEffect(()=>{ - setCurrentTab(localStorage.getItem('hbAdminTab')); + setCurrentTab(localStorage.getItem('hbAdminTab') || 'brew'); }, []); useEffect(()=>{ From b19d05fbf78d08955ccfa3a82ed79918e2303ad7 Mon Sep 17 00:00:00 2001 From: "G.Ambatte" Date: Wed, 9 Apr 2025 10:41:58 +1200 Subject: [PATCH 386/398] Remove commented out console.logs --- server/admin.api.js | 8 -------- 1 file changed, 8 deletions(-) diff --git a/server/admin.api.js b/server/admin.api.js index 8942a4675..bced73c83 100644 --- a/server/admin.api.js +++ b/server/admin.api.js @@ -223,7 +223,6 @@ router.post('/api/lock/:id', mw.adminOnly, asyncHandler(async (req, res)=>{ if(!brew) throw { name: 'Brew Not Found', message: 'Cannot find brew to lock', shareId: req.params.id, status: 500, HBErrorCode: '63' }; if(brew.lock && !overwrite) { - // console.log('ALREADY LOCKED'); throw { name: 'Already Locked', message: 'Lock already exists on brew', shareId: req.params.id, title: brew.title, status: 500, HBErrorCode: '64' }; } @@ -235,7 +234,6 @@ router.post('/api/lock/:id', mw.adminOnly, asyncHandler(async (req, res)=>{ throw { name: 'Already Locked', message: 'Unable to set lock', shareId: req.params.id, status: 500, HBErrorCode: '62', error }; }); - // console.log(`Lock applied to brew ID ${brew.shareId} - ${brew.title}`); return res.json({ name: 'LOCKED', message: `Lock applied to brew ID ${brew.shareId} - ${brew.title}`, ...lock }); })); @@ -260,9 +258,6 @@ router.put('/api/unlock/:id', mw.adminOnly, asyncHandler(async (req, res)=>{ throw { name: 'Cannot Unlock', message: 'Unable to clear lock', shareId: req.params.id, status: 500, HBErrorCode: '65', error }; }); - // console.log(`Lock removed from brew ID ${brew.shareId} - ${brew.title}`); - - return res.json({ name: 'Unlocked', message: `Lock removed from brew ID ${req.params.id}` }); })); @@ -303,7 +298,6 @@ router.put('/admin/lock/review/request/:id', asyncHandler(async (req, res)=>{ if(!brew) { throw { name: 'Brew Not Found', message: `Cannot find a locked brew with ID ${req.params.id}`, code: 500, HBErrorCode: '70' }; }; if(brew.lock.reviewRequested){ - // console.log(`Review already requested for brew ${brew.shareId} - ${brew.title}`); throw { name: 'Review Already Requested', message: `Review already requested for brew ${brew.shareId} - ${brew.title}`, code: 500, HBErrorCode: '71' }; }; @@ -315,7 +309,6 @@ router.put('/admin/lock/review/request/:id', asyncHandler(async (req, res)=>{ throw { name: 'Can Not Set Review Request', message: `Unable to set request for review on brew ID ${req.params.id}`, code: 500, HBErrorCode: '69', error }; }); - // console.log(`Review requested on brew ${brew.shareId} - ${brew.title}`); return res.json({ name: 'Review Requested', message: `Review requested on brew ID ${brew.shareId} - ${brew.title}` }); })); @@ -338,7 +331,6 @@ router.put('/api/lock/review/remove/:id', mw.adminOnly, asyncHandler(async (req, throw { name: 'Can Not Clear Review Request', message: `Unable to remove request for review on brew ID ${req.params.id}`, HBErrorCode: '72', error }; }); - // console.log(`Review request removed on brew ID ${brew.shareId} - ${brew.title}`); return res.json({ name: 'Review Request Cleared', message: `Review request removed for brew ID ${brew.shareId} - ${brew.title}` }); })); From bd68b9c0cb376f83e56960b5c60ac2de5fd9e0e9 Mon Sep 17 00:00:00 2001 From: "G.Ambatte" Date: Wed, 9 Apr 2025 10:48:02 +1200 Subject: [PATCH 387/398] Remove unnecessary variable --- server/admin.api.js | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/server/admin.api.js b/server/admin.api.js index bced73c83..8327dfd49 100644 --- a/server/admin.api.js +++ b/server/admin.api.js @@ -209,9 +209,6 @@ router.post('/api/lock/:id', mw.adminOnly, asyncHandler(async (req, res)=>{ const lock = req.body; - const overwrite = lock.overwrite || false; - lock.overwrite = undefined; - lock.applied = new Date; const filter = { @@ -222,10 +219,12 @@ router.post('/api/lock/:id', mw.adminOnly, asyncHandler(async (req, res)=>{ if(!brew) throw { name: 'Brew Not Found', message: 'Cannot find brew to lock', shareId: req.params.id, status: 500, HBErrorCode: '63' }; - if(brew.lock && !overwrite) { + if(brew.lock && !lock.overwrite) { throw { name: 'Already Locked', message: 'Lock already exists on brew', shareId: req.params.id, title: brew.title, status: 500, HBErrorCode: '64' }; } + lock.overwrite = undefined; + brew.lock = lock; brew.markModified('lock'); From 95f44f446036f9f182d9d63e315d660d223e3f98 Mon Sep 17 00:00:00 2001 From: "G.Ambatte" Date: Wed, 9 Apr 2025 11:04:57 +1200 Subject: [PATCH 388/398] Revert unnecessary change in app.js --- server/app.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/server/app.js b/server/app.js index fc0954efd..b7d990baf 100644 --- a/server/app.js +++ b/server/app.js @@ -2,11 +2,10 @@ // Set working directory to project root import { dirname } from 'path'; import { fileURLToPath } from 'url'; +import packageJSON from './../package.json' with { type: 'json' }; const __dirname = dirname(fileURLToPath(import.meta.url)); process.chdir(`${__dirname}/..`); - -import packageJSON from '../package.json' with { type: 'json' }; const version = packageJSON.version; import _ from 'lodash'; From 5e7e314baacd437685ae8b31050da8ac288b7dd9 Mon Sep 17 00:00:00 2001 From: "G.Ambatte" Date: Wed, 9 Apr 2025 11:38:57 +1200 Subject: [PATCH 389/398] Update fields returned for Lock and Review Tables --- server/admin.api.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/server/admin.api.js b/server/admin.api.js index 8327dfd49..ee859a3e0 100644 --- a/server/admin.api.js +++ b/server/admin.api.js @@ -191,7 +191,9 @@ router.get('/api/locks', mw.adminOnly, asyncHandler(async (req, res)=>{ { $project : { shareId : 1, - title : 1 + editId : 1, + title : 1, + lock : 1 } } ]; @@ -271,7 +273,9 @@ router.get('/api/lock/reviews', mw.adminOnly, asyncHandler(async (req, res)=>{ { $project : { shareId : 1, - title : 1 + editId : 1, + title : 1, + lock : 1 } } ]; From c6cd6e9864fb1911eea84d2602ff52cefb008bf9 Mon Sep 17 00:00:00 2001 From: David Bolack Date: Tue, 8 Apr 2025 20:29:32 -0500 Subject: [PATCH 390/398] A little bit of cleanup and structure flattening Fixes failed tests. --- server/homebrew.api.js | 3 ++- shared/helpers.js | 5 +++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/server/homebrew.api.js b/server/homebrew.api.js index 84e338ef4..8a98d50a8 100644 --- a/server/homebrew.api.js +++ b/server/homebrew.api.js @@ -177,7 +177,8 @@ const api = { `${text}`; } const metadata = _.pick(brew, ['title', 'description', 'tags', 'systems', 'renderer', 'theme']); - metadata.snippets = brewSnippetsToJSON('brew_snippets', brew.snippets, null, false); + const snippetsArray = brewSnippetsToJSON('brew_snippets', brew.snippets, null, false).snippets; + metadata.snippets = snippetsArray.length > 0 ? snippetsArray : undefined; text = `\`\`\`metadata\n` + `${yaml.dump(metadata)}\n` + `\`\`\`\n\n` + diff --git a/shared/helpers.js b/shared/helpers.js index e4dc9eba8..0ca681dfb 100644 --- a/shared/helpers.js +++ b/shared/helpers.js @@ -76,7 +76,8 @@ const yamlSnippetsToText = (yamlObj)=>{ if(typeof yamlObj == 'string') return yamlObj; let snippetsText = ''; - for (let snippet of yamlObj.snippets) { + + for (let snippet of yamlObj) { for (let subSnippet of snippet.subsnippets) { snippetsText = `${snippetsText}\\snippet ${subSnippet.name}\n${subSnippet.gen || ''}\n`; } @@ -91,7 +92,7 @@ const splitTextStyleAndMetadata = (brew)=>{ const metadataSection = brew.text.slice(11, index + 1); const metadata = yaml.load(metadataSection); Object.assign(brew, _.pick(metadata, ['title', 'description', 'tags', 'systems', 'renderer', 'theme', 'lang'])); - brew.snippets = yamlSnippetsToText(_.pick(metadata, ['snippets']).snippets); + brew.snippets = yamlSnippetsToText(_.pick(metadata, ['snippets']).snippets || ''); brew.text = brew.text.slice(index + 6); } if(brew.text.startsWith('```css')) { From da4f6c9307d8e2853713529b7e6c5c729372de1e Mon Sep 17 00:00:00 2001 From: "G.Ambatte" Date: Wed, 9 Apr 2025 17:54:51 +1200 Subject: [PATCH 391/398] Load lock details to the Lock Brew form --- client/admin/lockTools/lockTools.jsx | 50 +++++++++++++++++++--------- 1 file changed, 35 insertions(+), 15 deletions(-) diff --git a/client/admin/lockTools/lockTools.jsx b/client/admin/lockTools/lockTools.jsx index c528fb13d..c639adaca 100644 --- a/client/admin/lockTools/lockTools.jsx +++ b/client/admin/lockTools/lockTools.jsx @@ -1,9 +1,8 @@ -/*eslint max-lines: ["warn", {"max": 300, "skipBlankLines": true, "skipComments": true}]*/ +/*eslint max-lines: ["warn", {"max": 500, "skipBlankLines": true, "skipComments": true}]*/ require('./lockTools.less'); const React = require('react'); const createClass = require('create-react-class'); -// const request = require('superagent'); import request from '../../homebrew/utils/request-middleware.js'; const LockTools = createClass({ @@ -29,17 +28,23 @@ const LockTools = createClass({ } }, + updateLockData : function(lock){ + this.setState({ + lock : lock + }); + }, + render : function() { return

    Lock Count

    Number of brews currently locked: {this.state.reviewCount}


    - +
    - +
    - +
    @@ -55,12 +60,12 @@ const LockBrew = createClass({ getInitialState : function() { // Default values return { - brewId : '', - code : 455, - editMessage : '', - shareMessage : 'This Brew has been locked.', + brewId : this.props.lock?.shareId || '', + code : this.props.lock?.code || 455, + editMessage : this.props.lock?.editMessage || '', + shareMessage : this.props.lock?.shareMessage || 'This Brew has been locked.', result : {}, - overwrite : false + overwrite : false, }; }, @@ -186,7 +191,8 @@ const LockTable = createClass({ text : '', fetchURL : '/api/locks', resultName : '', - propertyNames : ['shareId'] + propertyNames : ['shareId'], + loadBrew : ()=>{} }; }, @@ -198,7 +204,9 @@ const LockTable = createClass({ }; }, - clickFn(){ + lockKey : React.createRef(0), + + clickFn : function (){ this.setState({ searching: true, error: null }); request.get(this.props.fetchURL) @@ -209,6 +217,18 @@ const LockTable = createClass({ }); }, + updateBrewLockData : function (lockData){ + this.lockKey.current++; + const brewData = { + key : this.lockKey.current, + shareId : lockData.shareId, + code : lockData.lock.code, + editMessage : lockData.lock.editMessage, + shareMessage : lockData.lock.shareMessage + }; + this.props.loadBrew(brewData); + }, + render : function () { return <>
    @@ -229,7 +249,7 @@ const LockTable = createClass({ return
    ; })} - + @@ -240,8 +260,8 @@ const LockTable = createClass({ {result[name].toString()} ; })} - - + + ; })} From 04defb97b09e99def4a56e35b1f154cf71e89b92 Mon Sep 17 00:00:00 2001 From: "G.Ambatte" Date: Wed, 9 Apr 2025 20:10:48 +1200 Subject: [PATCH 392/398] Tweak styling for Overwrite checkbox --- client/admin/lockTools/lockTools.jsx | 2 +- client/admin/lockTools/lockTools.less | 9 ++++++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/client/admin/lockTools/lockTools.jsx b/client/admin/lockTools/lockTools.jsx index c639adaca..9a28d330f 100644 --- a/client/admin/lockTools/lockTools.jsx +++ b/client/admin/lockTools/lockTools.jsx @@ -143,7 +143,7 @@ const LockBrew = createClass({ {this.renderInput('shareMessage')}
    -
    {name}clipviewload
    {navigator.clipboard.writeText(result.shareId.toString());}}>{navigator.clipboard.writeText(result.shareId.toString());}}>{this.updateBrewLockData(result);}}>