Merge branch 'master' of https://github.com/naturalcrit/homebrewery into change-metadata-ui-theme

This commit is contained in:
Víctor Losada Hernández
2026-09-25 15:44:36 +02:00
42 changed files with 2357 additions and 3869 deletions
@@ -10,6 +10,7 @@ import cx from 'classnames';
import { loadHistory } from '../../utils/versionHistory.js';
import { brewSnippetsToJSON } from '@shared/helpers.js';
/*eslint-disable camelcase*/
import Legacy5ePHB from '@themes/Legacy/5ePHB/snippets.js';
import V3_5ePHB from '@themes/V3/5ePHB/snippets.js';
import V3_5eDMG from '@themes/V3/5eDMG/snippets.js';
@@ -23,26 +24,7 @@ const ThemeSnippets = {
V3_Journal : V3_Journal,
V3_Blank : V3_Blank,
};
import defaultCM5Theme from '@themes/codeMirror/default.js';
import darkbrewery from '@themes/codeMirror/darkbrewery.js';
import cm5Themes from 'codemirror-5-themes';
const themes = { default: defaultCM5Theme, ...cm5Themes, darkbrewery };
const themeNames = Object.entries(themes)
.filter(([name, value])=>Array.isArray(value) &&
!name.endsWith('Init') &&
!name.endsWith('Style')
)
.map(([name])=>name);
const EditorThemes = [
'default',
...themeNames
.filter((name)=>name !== 'default')
.sort((a, b)=>a.localeCompare(b))
];
/*eslint-enable camelcase */
const execute = function(val, props){
if(_.isFunction(val)) return val(props);
@@ -53,30 +35,28 @@ const Snippetbar = createReactClass({
displayName : 'SnippetBar',
getDefaultProps : function() {
return {
brew : {},
view : 'text',
onViewChange : ()=>{},
onInject : ()=>{},
onToggle : ()=>{},
showEditButtons : true,
renderer : 'legacy',
undo : ()=>{},
redo : ()=>{},
historySize : ()=>{},
foldCode : ()=>{},
unfoldCode : ()=>{},
formatCode : ()=>{},
updateEditorTheme : ()=>{},
cursorPos : {},
themeBundle : [],
updateBrew : ()=>{}
brew : {},
view : 'text',
onViewChange : ()=>{},
onInject : ()=>{},
onToggle : ()=>{},
showEditButtons : true,
renderer : 'legacy',
undo : ()=>{},
redo : ()=>{},
historySize : ()=>{},
foldCode : ()=>{},
unfoldCode : ()=>{},
formatCode : ()=>{},
cursorPos : {},
themeBundle : [],
updateBrew : ()=>{}
};
},
getInitialState : function() {
return {
renderer : this.props.renderer,
themeSelector : false,
snippets : [],
showHistory : false,
historyExists : false,
@@ -93,7 +73,6 @@ const Snippetbar = createReactClass({
componentDidUpdate : async function(prevProps, prevState) {
if(prevProps.renderer != this.props.renderer ||
prevProps.theme != this.props.theme ||
prevProps.themeBundle != this.props.themeBundle ||
prevProps.brew.snippets != this.props.brew.snippets) {
this.setState({
@@ -158,33 +137,6 @@ const Snippetbar = createReactClass({
this.props.onInject(injectedText);
},
toggleThemeSelector : function(e){
if(e.target.tagName != 'SELECT'){
this.setState({
themeSelector : !this.state.themeSelector
});
}
},
changeTheme : function(e){
if(e.target.value == this.props.currentEditorTheme) return;
this.props.updateEditorTheme(e.target.value);
this.setState({
themeSelector : false,
});
},
renderThemeSelector : function(){
return <div className='themeSelector'>
<select value={this.props.currentEditorTheme} onChange={this.changeTheme} >
{EditorThemes.map((theme, key)=>{
return <option key={key} value={theme}>{theme}</option>;
})}
</select>
</div>;
},
renderSnippetGroups : function(){
const snippets = this.state.snippets.filter((snippetGroup)=>snippetGroup.view === this.props.view);
if(snippets.length === 0) return null;
@@ -246,7 +198,7 @@ const Snippetbar = createReactClass({
return (
<div className='editors'>
{this.props.view !== 'meta' && <><div className='historyTools'>
{this.props.view !== 'meta' && this.props.view !== 'settings' && <><div className='historyTools'>
<button className={`editorTool snippetGroup history ${this.state.historyExists ? 'active' : ''}`}
onClick={this.toggleHistoryMenu} >
<i className='fas fa-clock-rotate-left' />
@@ -274,11 +226,6 @@ const Snippetbar = createReactClass({
onClick={this.props.formatCode} >
<i className='fas fa-wand-magic-sparkles' />
</button>
<button className={`editorTheme ${this.state.themeSelector ? 'active' : ''}`}
onClick={this.toggleThemeSelector} >
<i className='fas fa-palette' />
{this.state.themeSelector && this.renderThemeSelector()}
</button>
</div></>}
<div className='tabs'>
@@ -298,6 +245,10 @@ const Snippetbar = createReactClass({
onClick={()=>this.props.onViewChange('meta')}>
<i className='fas fa-info-circle' />
</button>
<button className={cx('settings', { selected: this.props.view === 'settings' })}
onClick={()=>this.props.onViewChange('settings')}>
<i className='fas fa-gear' />
</button>
</div>
</div>
@@ -346,7 +297,7 @@ const SnippetGroup = createReactClass({
<Dropdown groupName={snippet.name} icon={snippet.icon} key={snippet.name}>
{this.renderSnippets(snippet.subsnippets)}
</Dropdown>
)
);
}
});
@@ -25,7 +25,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: .85rem;
font-size : 0.85rem;
&:only-child {min-width : unset; margin-left : auto;}
reading-order : 2;
@@ -135,36 +135,32 @@
}
// removed caret for top level items, by request (makes buttons too wide).
.menu-wrapper .menu-item:is(.snippets > .menu-wrapper > .menu-item):first-child .caret { display: none; }
.menu-wrapper .menu-item:is(.snippets > .menu-wrapper > .menu-item):first-child .caret { display : none; }
.menu-item {
position : relative;
display : flex;
justify-content: space-between;
align-items : center;
min-width : max-content;
padding : 5px;
cursor : pointer;
width: 100%;
&:is(.menu-list .menu-item) [class*="name"] {
padding-inline: 8px; // additional space between icon and name (helpful in Fonts menu especially).
position : relative;
display : flex;
align-items : center;
justify-content : space-between;
width : 100%;
min-width : max-content;
padding : 5px;
cursor : pointer;
&:is(.menu-list .menu-item) [class*='name'] {
padding-inline : 8px; // additional space between icon and name (helpful in Fonts menu especially).
}
.menu-name {
flex: 1;
text-align: left;
text-box-trim: trim-end;
flex : 1;
text-align : left;
text-box-trim : trim-end;
}
i {
min-width : 25px;
height : .85rem;
height : 0.85rem;
font-size : 1.2em;
text-align : center;
&.caret {
margin-right: 0;
}
&.caret:is(.menu-wrapper .menu-wrapper * ) {
text-align: right;
}
&.caret { margin-right : 0; }
&.caret:is(.menu-wrapper .menu-wrapper *) { text-align : right; }
/* Fonts */
&.font {
height : auto;
@@ -207,14 +203,14 @@
background-color : var(--hoverMenuColor);
}
&:disabled {
color: gray;
cursor: not-allowed;
&:hover { background-color: unset; }
color : gray;
cursor : not-allowed;
&:hover { background-color : unset; }
}
}
}
@container editor (width < 841px) {
.snippetBar {
.snippetBar {
.editors {
flex : 1;
justify-content : space-between;