0
0
mirror of https://github.com/naturalcrit/homebrewery.git synced 2025-12-24 22:52:40 +00:00

Merge branch 'master' into addMongoIndexes

This commit is contained in:
G.Ambatte
2025-10-03 13:42:25 +13:00
committed by GitHub
5 changed files with 96 additions and 90 deletions

View File

@@ -40,11 +40,8 @@ const Editor = createClass({
style : ''
},
onTextChange : ()=>{},
onStyleChange : ()=>{},
onMetaChange : ()=>{},
onSnipChange : ()=>{},
reportError : ()=>{},
onBrewChange : ()=>{},
reportError : ()=>{},
onCursorPageChange : ()=>{},
onViewPageChange : ()=>{},
@@ -438,7 +435,7 @@ const Editor = createClass({
language='gfm'
view={this.state.view}
value={this.props.brew.text}
onChange={this.props.onTextChange}
onChange={this.props.onBrewChange('text')}
editorTheme={this.state.editorTheme}
rerenderParent={this.rerenderParent}
style={{ height: `calc(100% - ${this.state.snippetbarHeight}px)` }} />
@@ -451,7 +448,7 @@ const Editor = createClass({
language='css'
view={this.state.view}
value={this.props.brew.style ?? DEFAULT_STYLE_TEXT}
onChange={this.props.onStyleChange}
onChange={this.props.onBrewChange('style')}
enableFolding={true}
editorTheme={this.state.editorTheme}
rerenderParent={this.rerenderParent}
@@ -467,7 +464,7 @@ const Editor = createClass({
<MetadataEditor
metadata={this.props.brew}
themeBundle={this.props.themeBundle}
onChange={this.props.onMetaChange}
onChange={this.props.onBrewChange('metadata')}
reportError={this.props.reportError}
userThemes={this.props.userThemes}/>
</>;
@@ -481,7 +478,7 @@ const Editor = createClass({
language='gfm'
view={this.state.view}
value={this.props.brew.snippets}
onChange={this.props.onSnipChange}
onChange={this.props.onBrewChange('snippets')}
enableFolding={true}
editorTheme={this.state.editorTheme}
rerenderParent={this.rerenderParent}

View File

@@ -39,6 +39,11 @@ const SAVE_TIMEOUT = 10000;
const UNSAVED_WARNING_TIMEOUT = 900000; //Warn user afer 15 minutes of unsaved changes
const UNSAVED_WARNING_POPUP_TIMEOUT = 4000; //Show the warning for 4 seconds
const BREWKEY = 'homebrewery-new';
const STYLEKEY = 'homebrewery-new-style';
const SNIPKEY = 'homebrewery-new-snippets';
const METAKEY = 'homebrewery-new-meta';
const EditPage = (props)=>{
props = {
brew : DEFAULT_BREW_LOAD,
@@ -69,6 +74,8 @@ const EditPage = (props)=>{
const trySaveRef = useRef(trySave); // CTRL+S listener lives outside React and needs ref to use trySave with latest copy of brew
const unsavedChangesRef = useRef(unsavedChanges); // Similarly, onBeforeUnload lives outside React and needs ref to unsavedChanges
const useLocalStorage = false;
useEffect(()=>{
const autoSavePref = JSON.parse(localStorage.getItem('AUTOSAVE_ON') ?? true);
setAutoSaveEnabled(autoSavePref);
@@ -125,29 +132,27 @@ const EditPage = (props)=>{
setCurrentBrewRendererPageNum(pageNumber);
};
const handleTextChange = (text)=>{
const handleBrewChange = (field) => (value, subfield) => { //'text', 'style', 'snippets', 'metadata'
if (subfield == 'renderer' || subfield == 'theme')
fetchThemeBundle(setError, setThemeBundle, value.renderer, value.theme);
//If there are HTML errors, run the validator on every change to give quick feedback
if(HTMLErrors.length)
setHTMLErrors(Markdown.validate(text));
setCurrentBrew((prevBrew)=>({ ...prevBrew, text }));
};
if(HTMLErrors.length && (field == 'text' || field == 'snippets'))
setHTMLErrors(Markdown.validate(value));
const handleStyleChange = (style)=>{
setCurrentBrew((prevBrew)=>({ ...prevBrew, style }));
};
if(field == 'metadata') setCurrentBrew(prev => ({ ...prev, ...value }));
else setCurrentBrew(prev => ({ ...prev, [field]: value }));
const handleSnipChange = (snippet)=>{
//If there are HTML errors, run the validator on every change to give quick feedback
if(HTMLErrors.length)
setHTMLErrors(Markdown.validate(snippet));
setCurrentBrew((prevBrew)=>({ ...prevBrew, snippets: snippet }));
};
const handleMetaChange = (metadata, field = undefined)=>{
if(field === 'theme' || field === 'renderer')
fetchThemeBundle(setError, setThemeBundle, metadata.renderer, metadata.theme);
setCurrentBrew((prev)=>({ ...prev, ...metadata }));
if(useLocalStorage) {
if(field == 'text') localStorage.setItem(BREWKEY, value);
if(field == 'style') localStorage.setItem(STYLEKEY, value);
if(field == 'snippets') localStorage.setItem(SNIPKEY, value);
if(field == 'metadata') localStorage.setItem(METAKEY, JSON.stringify({
renderer : value.renderer,
theme : value.theme,
lang : value.lang
}));
}
};
const updateBrew = (newData)=>setCurrentBrew((prevBrew)=>({
@@ -380,10 +385,7 @@ const EditPage = (props)=>{
<Editor
ref={editorRef}
brew={currentBrew}
onTextChange={handleTextChange}
onStyleChange={handleStyleChange}
onSnipChange={handleSnipChange}
onMetaChange={handleMetaChange}
onBrewChange={handleBrewChange}
reportError={setError}
renderer={currentBrew.renderer}
userThemes={props.userThemes}

View File

@@ -3,6 +3,7 @@ import './homePage.less';
import React from 'react';
import { useEffect, useState, useRef } from 'react';
import request from '../../utils/request-middleware.js';
import Markdown from 'naturalcrit/markdown.js';
import { Meta } from 'vitreum/headtags';
import Nav from 'naturalcrit/nav/nav.jsx';
@@ -21,6 +22,11 @@ import BrewRenderer from '../../brewRenderer/brewRenderer.jsx
import { DEFAULT_BREW } from '../../../../server/brewDefaults.js';
const BREWKEY = 'homebrewery-new';
const STYLEKEY = 'homebrewery-new-style';
const SNIPKEY = 'homebrewery-new-snippets';
const METAKEY = 'homebrewery-new-meta';
const HomePage =(props)=>{
props = {
brew : DEFAULT_BREW,
@@ -28,9 +34,10 @@ const HomePage =(props)=>{
...props
};
const [brew , setBrew] = useState(props.brew);
const [currentBrew , setCurrentBrew] = useState(props.brew);
const [welcomeText , setWelcomeText] = useState(props.brew.text);
const [error , setError] = useState(undefined);
const [HTMLErrors , setHTMLErrors ] = useState(Markdown.validate(props.brew.text));
const [currentEditorViewPageNum , setCurrentEditorViewPageNum] = useState(1);
const [currentEditorCursorPageNum, setCurrentEditorCursorPageNum] = useState(1);
const [currentBrewRendererPageNum, setCurrentBrewRendererPageNum] = useState(1);
@@ -39,13 +46,15 @@ const HomePage =(props)=>{
const editorRef = useRef(null);
const useLocalStorage = false;
useEffect(()=>{
fetchThemeBundle(setError, setThemeBundle, brew.renderer, brew.theme);
fetchThemeBundle(setError, setThemeBundle, currentBrew.renderer, currentBrew.theme);
}, []);
const save = ()=>{
request.post('/api')
.send(brew)
.send(currentBrew)
.end((err, res)=>{
if(err) {
setError(err);
@@ -72,8 +81,27 @@ const HomePage =(props)=>{
setCurrentBrewRendererPageNum(pageNumber);
};
const handleTextChange = (text)=>{
setBrew((prevBrew) => ({ ...prevBrew, text }));
const handleBrewChange = (field) => (value, subfield) => { //'text', 'style', 'snippets', 'metadata'
if (subfield == 'renderer' || subfield == 'theme')
fetchThemeBundle(setError, setThemeBundle, value.renderer, value.theme);
//If there are HTML errors, run the validator on every change to give quick feedback
if(HTMLErrors.length && (field == 'text' || field == 'snippets'))
setHTMLErrors(Markdown.validate(value));
if(field == 'metadata') setCurrentBrew(prev => ({ ...prev, ...value }));
else setCurrentBrew(prev => ({ ...prev, [field]: value }));
if(useLocalStorage) {
if(field == 'text') localStorage.setItem(BREWKEY, value);
if(field == 'style') localStorage.setItem(STYLEKEY, value);
if(field == 'snippets') localStorage.setItem(SNIPKEY, value);
if(field == 'metadata') localStorage.setItem(METAKEY, JSON.stringify({
renderer : value.renderer,
theme : value.theme,
lang : value.lang
}));
}
};
const clearError = ()=>{
@@ -105,9 +133,9 @@ const HomePage =(props)=>{
<SplitPane onDragFinish={handleSplitMove}>
<Editor
ref={editorRef}
brew={brew}
onTextChange={handleTextChange}
renderer={brew.renderer}
brew={currentBrew}
onBrewChange={handleBrewChange}
renderer={currentBrew.renderer}
showEditButtons={false}
themeBundle={themeBundle}
onCursorPageChange={handleEditorCursorPageChange}
@@ -117,9 +145,9 @@ const HomePage =(props)=>{
currentBrewRendererPageNum={currentBrewRendererPageNum}
/>
<BrewRenderer
text={brew.text}
style={brew.style}
renderer={brew.renderer}
text={currentBrew.text}
style={currentBrew.style}
renderer={currentBrew.renderer}
onPageChange={handleBrewRendererPageChange}
currentEditorViewPageNum={currentEditorViewPageNum}
currentEditorCursorPageNum={currentEditorCursorPageNum}
@@ -128,7 +156,7 @@ const HomePage =(props)=>{
/>
</SplitPane>
</div>
<div className={`floatingSaveButton${welcomeText !== brew.text ? ' show' : ''}`} onClick={save}>
<div className={`floatingSaveButton${welcomeText !== currentBrew.text ? ' show' : ''}`} onClick={save}>
Save current <i className='fas fa-save' />
</div>

View File

@@ -22,8 +22,9 @@ import { printCurrentBrew, fetchThemeBundle, splitTextStyleAndMetadata } from '.
const BREWKEY = 'homebrewery-new';
const STYLEKEY = 'homebrewery-new-style';
const SNIPKEY = 'homebrewery-new-snippets';
const METAKEY = 'homebrewery-new-meta';
const SAVEKEY = `HOMEBREWERY-DEFAULT-SAVE-LOCATION-${global.account?.username || ''}`;
const SAVEKEYPREFIX = 'HOMEBREWERY-DEFAULT-SAVE-LOCATION-';
const NewPage = (props) => {
props = {
@@ -43,6 +44,8 @@ const NewPage = (props) => {
const editorRef = useRef(null);
const useLocalStorage = true;
useEffect(() => {
document.addEventListener('keydown', handleControlKeys);
loadBrew();
@@ -67,6 +70,7 @@ const NewPage = (props) => {
brew.lang = metaStorage?.lang ?? brew.lang;
}
const SAVEKEY = `${SAVEKEYPREFIX}${global.account?.username}`;
const saveStorage = localStorage.getItem(SAVEKEY) || 'HOMEBREWERY';
setCurrentBrew(brew);
@@ -108,40 +112,27 @@ const NewPage = (props) => {
setCurrentBrewRendererPageNum(pageNumber);
};
const handleTextChange = (text)=>{
const handleBrewChange = (field) => (value, subfield) => { //'text', 'style', 'snippets', 'metadata'
if (subfield == 'renderer' || subfield == 'theme')
fetchThemeBundle(setError, setThemeBundle, value.renderer, value.theme);
//If there are HTML errors, run the validator on every change to give quick feedback
if(HTMLErrors.length)
HTMLErrors = Markdown.validate(text);
if(HTMLErrors.length && (field == 'text' || field == 'snippets'))
setHTMLErrors(Markdown.validate(value));
setHTMLErrors(HTMLErrors);
setCurrentBrew((prevBrew) => ({ ...prevBrew, text }));
localStorage.setItem(BREWKEY, text);
};
if(field == 'metadata') setCurrentBrew(prev => ({ ...prev, ...value }));
else setCurrentBrew(prev => ({ ...prev, [field]: value }));
const handleStyleChange = (style) => {
setCurrentBrew(prevBrew => ({ ...prevBrew, style }));
localStorage.setItem(STYLEKEY, style);
};
const handleSnipChange = (snippet)=>{
//If there are HTML errors, run the validator on every change to give quick feedback
if(HTMLErrors.length)
HTMLErrors = Markdown.validate(snippet);
setHTMLErrors(HTMLErrors);
setCurrentBrew((prevBrew) => ({ ...prevBrew, snippets: snippet }));
};
const handleMetaChange = (metadata, field = undefined) => {
if (field === 'theme' || field === 'renderer')
fetchThemeBundle(setError, setThemeBundle, metadata.renderer, metadata.theme);
setCurrentBrew(prev => ({ ...prev, ...metadata }));
localStorage.setItem(METAKEY, JSON.stringify({
renderer : metadata.renderer,
theme : metadata.theme,
lang : metadata.lang
}));
if(useLocalStorage) {
if(field == 'text') localStorage.setItem(BREWKEY, value);
if(field == 'style') localStorage.setItem(STYLEKEY, value);
if(field == 'snippets') localStorage.setItem(SNIPKEY, value);
if(field == 'metadata') localStorage.setItem(METAKEY, JSON.stringify({
renderer : value.renderer,
theme : value.theme,
lang : value.lang
}));
}
};
const save = async () => {
@@ -215,10 +206,7 @@ const NewPage = (props) => {
<Editor
ref={editorRef}
brew={currentBrew}
onTextChange={handleTextChange}
onStyleChange={handleStyleChange}
onMetaChange={handleMetaChange}
onSnipChange={handleSnipChange}
onBrewChange={handleBrewChange}
renderer={currentBrew.renderer}
userThemes={props.userThemes}
themeBundle={themeBundle}

View File

@@ -38,15 +38,6 @@
animation-duration : 0.4s;
}
.CodeMirror-vscrollbar {
&::-webkit-scrollbar { width : 20px; }
&::-webkit-scrollbar-thumb {
width : 20px;
background : linear-gradient(90deg, #858585 15px, #808080 15px);
}
}
//.cm-tab {
// background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAMCAQAAACOs/baAAAARUlEQVR4nGJgIAG8JkXxUAcCtDWemcGR1lY4MvgzCEKY7jSBjgxBDAG09UEQzAe0AMwMHrSOAwEGRtpaMIwAAAAA//8DAG4ID9EKs6YqAAAAAElFTkSuQmCC) no-repeat right;
//}