Merge branch 'master' of https://github.com/naturalcrit/homebrewery into add-settings-editor

This commit is contained in:
Víctor Losada Hernández
2026-08-29 22:43:09 +02:00
8 changed files with 4010 additions and 2102 deletions
+5 -3
View File
@@ -44,9 +44,9 @@ const themeCompartment = new Compartment();
const highlightCompartment = new Compartment();
const settingsCompartment = new Compartment();
import { generalKeymap, markdownKeymap } from './extensions/customKeyMaps.js';
import { generalKeymap, markdownKeymap, cssKeymap, formatCSS } from './extensions/customKeyMaps.js';
import foldOnPages from './extensions/customFolding.js';
import { customHighlightPlugin, customHighlightStyle } from './extensions/customHighlight.js';
import { customHighlightStyle , customHighlightPlugin } from './extensions/customHighlight.js';
import { legacyCustomHighlightStyle } from './extensions/legacyCustomHighlight.js';
const PAGEBREAK_REGEX_V3 = /^(?=\\page(?:break)?(?: *{[^\n{}]*})?$)/m;
@@ -199,7 +199,7 @@ const CodeEditor = forwardRef(
//keyboard shortcut
keymap.of([...defaultKeymap, foldKeymap, ...searchKeymap]),
generalKeymap,
...(tab !== 'brewStyles' ? [markdownKeymap] : []),
...(tab === 'brewStyles' ? [cssKeymap] : [markdownKeymap]),
//multiple cursors and selections
drawSelection(),
@@ -386,6 +386,8 @@ const CodeEditor = forwardRef(
}, 400);
},
formatCode : ()=>formatCSS(viewRef.current),
undo : ()=>undo(viewRef.current),
redo : ()=>redo(viewRef.current),
@@ -15,6 +15,18 @@
}
}
@keyframes slideacross {
0% {
bottom: -200px;
left: -200px;
}
100% {
bottom:100%;
left:100%;
}
}
:where(.codeEditor) {
width : 100%;
height : calc(100% - 25px);
@@ -23,6 +35,27 @@
.cm-editor {
height : 100%;
outline : none !important;
&.cm-flash {
position:relative;
&::after {
position:absolute;
content:'';
bottom:-200px;
left:-200px;
translate:-50%;
width:200%;
height:100px;
background:linear-gradient(0deg, #89eafc00 0px, #89ebfc8e 50px, #89eafc00 100px, transparent);
display:block;
rotate:30deg;
@media screen and (prefers-reduced-motion: no-preference) {
animation: .5s linear 1 slideacross ;
}
}
}
}
&.brewSnippets .cm-snippetLine,
@@ -3,7 +3,60 @@ import { keymap } from '@codemirror/view';
import { undo, redo, indentMore, indentLess, deleteLine } from '@codemirror/commands';
import { EditorSelection } from '@codemirror/state';
import { Prec } from '@codemirror/state';
import * as prettier from 'prettier/standalone';
import * as postcssPlugin from 'prettier/plugins/postcss';
export async function formatCSS(view) {
try {
const { from, to, empty } = view.state.selection.main;
const fullDoc = view.state.doc.toString();
const selection = view.state.doc.sliceString(from, to);
const code = empty ? fullDoc : selection;
let formatted = await prettier.format(code, {
parser: 'css',
plugins: [postcssPlugin],
// formatting options
tabWidth: 2,
useTabs: false,
printWidth: 100,
singleQuote: false,
trailingComma: 'all',
bracketSpacing: true,
endOfLine: 'lf'
});
//format manually single declaration rules to span one line.
//Prettier can't do it by default, this is crude but it works
formatted = formatted.replace(
/([^{]+)\{\s*\n\s*([^;\n]+:[^;\n]+;)\s*\n\s*\}(\s*)/g,
(_, selector, decl, whitespace) =>
`${selector} { ${decl.trim()} }${whitespace}`
);
if(formatted === code) return true;
const dom = view.dom;
dom.classList.add('cm-flash');
setTimeout(()=>{
dom.classList.remove('cm-flash');
view.dispatch({
changes : {
from : empty ? 0 : from,
to : empty ? view.state.doc.length : to,
insert : formatted
}
});
}, 500);
} catch (err) {
console.error('Error formatting css: ', err);
}
return true;
}
const insertTab = (view)=>{
// If any selection spans multiple lines, delegates to CodeMirror's indentMore
// Otherwise inserts two spaces at each cursor/selection
@@ -188,6 +241,11 @@ export const generalKeymap = Prec.high(keymap.of([
{ key: 'Mod-d', run: deleteLine }, //annoyingly overrides "selectNextOccurrence" because users asked
]));
export const cssKeymap = Prec.highest(keymap.of([
{ key: 'Mod-Shift-f', run: formatCSS },
{ key: 'Alt-Shift-f', run: formatCSS },
]));
export const markdownKeymap = Prec.highest(keymap.of([
{ key: 'Mod-b', run: wrapSelection('**', '**') }, // makeBold
+5
View File
@@ -138,6 +138,10 @@ const Editor = forwardRef(
useEffect(()=>{ if(liveScroll) brewJump(currentEditorViewPageNum, false); }, [currentEditorViewPageNum, liveScroll]);
useEffect(()=>{ if(liveScroll) brewJump(currentEditorCursorPageNum, false); }, [currentEditorCursorPageNum, liveScroll]);
const handleFormatCode = () => {
codeEditor.current?.formatCode();
};
const handleControlKeys = (e)=>{
if(!(e.ctrlKey && e.metaKey && e.shiftKey)) return;
const LEFTARROW_KEY = 37;
@@ -371,6 +375,7 @@ const Editor = forwardRef(
redo={redo}
foldCode={foldCode}
unfoldCode={unfoldCode}
formatCode={isStyle() ? handleFormatCode : null}
historySize={historySize()}
currentEditorTheme={editorSettings.editorTheme}
updateEditorTheme={updateEditorTheme}
@@ -35,21 +35,22 @@ const Snippetbar = createReactClass({
displayName : 'SnippetBar',
getDefaultProps : function() {
return {
brew : {},
view : 'text',
onViewChange : ()=>{},
onInject : ()=>{},
onToggle : ()=>{},
showEditButtons : true,
renderer : 'legacy',
undo : ()=>{},
redo : ()=>{},
historySize : ()=>{},
foldCode : ()=>{},
unfoldCode : ()=>{},
cursorPos : {},
themeBundle : [],
updateBrew : ()=>{}
brew : {},
view : 'text',
onViewChange : ()=>{},
onInject : ()=>{},
onToggle : ()=>{},
showEditButtons : true,
renderer : 'legacy',
undo : ()=>{},
redo : ()=>{},
historySize : ()=>{},
foldCode : ()=>{},
unfoldCode : ()=>{},
formatCode : ()=>{},
cursorPos : {},
themeBundle : [],
updateBrew : ()=>{}
};
},
@@ -223,6 +224,11 @@ const Snippetbar = createReactClass({
onClick={this.props.unfoldCode} >
<i className='fas fa-expand-alt' />
</div>
<div className={`editorTheme ${this.state.themeSelector ? 'active' : ''}`}
onClick={this.toggleThemeSelector} >
<i className='fas fa-palette' />
{this.state.themeSelector && this.renderThemeSelector()}
</div>
</div></>}
<div className='tabs'>
@@ -22,7 +22,7 @@
display : flex;
justify-content : flex-end;
min-width : 275px; //must be controlled every time an item is added, must be hardcoded for the wrapping as it is applied
font-size : 0.85rem;
font-size: .85rem;
&:only-child {min-width : unset; margin-left : auto;}
>div {
@@ -75,6 +75,11 @@
color : grey;
&.active { color : inherit; }
}
&.formatCode {
.tooltipLeft('Clean your Code');
color : grey;
&.active { color : inherit; }
}
&.history {
.tooltipLeft('History');
position : relative;
@@ -203,7 +208,7 @@
}
}
@container editor (width < 841px) {
.snippetBar {
.snippetBar {
.editors {
flex : 1;
justify-content : space-between;
@@ -216,4 +221,3 @@
.editors > div.history > .dropdown { right : unset; }
}
}
+3880 -2081
View File
File diff suppressed because it is too large Load Diff
+1
View File
@@ -144,6 +144,7 @@
"nanoid": "6.0.1",
"nconf": "^0.13.0",
"node": "^26.7.0",
"prettier": "^3.8.1",
"react": "^19.2.7",
"react-dom": "^19.2.7",
"react-frame-component": "^5.3.2",