From 73c68fd11c7517e465bf5bcf690ee24f190bb6f9 Mon Sep 17 00:00:00 2001 From: David Bolack Date: Wed, 27 Nov 2024 21:35:29 -0600 Subject: [PATCH 001/124] 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 7c357a2aa130a072cad58779c377d0888e61992c Mon Sep 17 00:00:00 2001 From: David Bolack Date: Sun, 29 Dec 2024 23:23:48 -0600 Subject: [PATCH 002/124] 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 003/124] 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 004/124] 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 74122d90579812916b526626144f85ff9f7debba Mon Sep 17 00:00:00 2001 From: David Bolack Date: Tue, 7 Jan 2025 22:11:01 -0600 Subject: [PATCH 005/124] 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 006/124] 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 007/124] 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 008/124] 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 f6c95fb8b773ebeff021bd7a581e352e7ea5bddd Mon Sep 17 00:00:00 2001 From: "G.Ambatte" Date: Tue, 14 Jan 2025 08:25:46 +1300 Subject: [PATCH 009/124] 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 60b6dbb38809677939e1052165f669cf9aa751f5 Mon Sep 17 00:00:00 2001 From: David Bolack Date: Fri, 24 Jan 2025 13:52:49 -0600 Subject: [PATCH 010/124] 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 f1eb6e1ce473bd1a6cacbbbce0bac9bb55875dda Mon Sep 17 00:00:00 2001 From: David Bolack Date: Tue, 28 Jan 2025 21:31:43 -0600 Subject: [PATCH 011/124] 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 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 012/124] 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 013/124] 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 014/124] 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 015/124] 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 016/124] 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 017/124] 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 018/124] 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 019/124] 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 6d2cbaacc04e068c77e7c70f3f10e1f8945a26fc Mon Sep 17 00:00:00 2001 From: "G.Ambatte" Date: Wed, 5 Feb 2025 21:35:21 +1300 Subject: [PATCH 020/124] 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 021/124] 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 659510e364c68ea5a3e1199a3f74498c61119376 Mon Sep 17 00:00:00 2001 From: Trevor Buckner Date: Sun, 9 Feb 2025 12:07:09 -0500 Subject: [PATCH 022/124] 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 023/124] 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 11396389abf8c29d4d6aea2dbebe3547ddc34b36 Mon Sep 17 00:00:00 2001 From: David Bolack Date: Mon, 10 Feb 2025 20:47:17 -0600 Subject: [PATCH 024/124] 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 025/124] 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 026/124] 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 e89920bd1e0a3949f56b9218dde87eb9fdc703b2 Mon Sep 17 00:00:00 2001 From: "G.Ambatte" Date: Wed, 12 Feb 2025 07:41:53 +1300 Subject: [PATCH 027/124] 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 028/124] 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 029/124] 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 030/124] 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 cb618914506f55bcf4523657227bad294cdd1031 Mon Sep 17 00:00:00 2001 From: "G.Ambatte" Date: Sat, 22 Mar 2025 12:31:38 +1300 Subject: [PATCH 124/124] 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');