From 73c68fd11c7517e465bf5bcf690ee24f190bb6f9 Mon Sep 17 00:00:00 2001 From: David Bolack Date: Wed, 27 Nov 2024 21:35:29 -0600 Subject: [PATCH 01/47] 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 02/47] 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 03/47] 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 04/47] 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 05/47] 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 06/47] 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 07/47] 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 08/47] 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 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 09/47] 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 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 10/47] 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 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 11/47] 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 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 12/47] 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 13/47] 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 14/47] 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 15/47] 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 16/47] 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 c080e5b1915eea919c2f683aa4445a759b381ff4 Mon Sep 17 00:00:00 2001 From: Trevor Buckner Date: Mon, 10 Feb 2025 22:20:12 -0500 Subject: [PATCH 17/47] 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 18/47] 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 19/47] 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 20/47] 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 21/47] 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 22/47] 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