0
0
mirror of https://github.com/naturalcrit/homebrewery.git synced 2026-01-14 02:02:51 +00:00

Use ComboBox component for Theme Selector

This commit is contained in:
Trevor Buckner
2025-02-10 22:20:54 -05:00
parent c080e5b191
commit 1aed753911
2 changed files with 94 additions and 128 deletions

View File

@@ -49,12 +49,8 @@ const MetadataEditor = createClass({
}, },
getInitialState : function(){ getInitialState : function(){
mergedThemes = _.merge(Themes, this.props.userThemes);
return { return {
showThumbnail : true, 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
}; };
}, },
@@ -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(){ renderThumbnail : function(){
if(!this.state.showThumbnail) return; if(!this.state.showThumbnail) return;
return <img className='thumbnail-preview' src={this.props.metadata.thumbnail || homebreweryThumbnail}></img>; return <img className='thumbnail-preview' src={this.props.metadata.thumbnail || homebreweryThumbnail}></img>;
@@ -128,21 +115,15 @@ const MetadataEditor = createClass({
handleTheme : function(theme){ handleTheme : function(theme){
this.props.metadata.renderer = theme.renderer; this.props.metadata.renderer = theme.renderer;
this.props.metadata.theme = theme.path; this.props.metadata.theme = theme.path;
this.setState({
lastThemePulldown : theme.path
});
this.props.onChange(this.props.metadata, 'theme'); this.props.onChange(this.props.metadata, 'theme');
}, },
handleThemeWritein : function(e) { handleThemeWritein : function(e) {
this.props.metadata.renderer = 'V3';
this.props.metadata.theme = e.target.value; 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'); this.props.onChange(this.props.metadata, 'theme');
}, },
@@ -224,12 +205,14 @@ const MetadataEditor = createClass({
renderThemeDropdown : function(){ renderThemeDropdown : function(){
if(!global.enable_themes) return; if(!global.enable_themes) return;
const mergedThemes = _.merge(Themes, this.props.userThemes);
const listThemes = (renderer)=>{ const listThemes = (renderer)=>{
return _.map(_.values(mergedThemes[renderer]), (theme)=>{ return _.map(_.values(mergedThemes[renderer]), (theme)=>{
if(theme.path == this.props.metadata.shareId) return; if(theme.path == this.props.metadata.shareId) return;
const preview = theme.thumbnail || `/themes/${theme.renderer}/${theme.path}/dropdownPreview.png`; const preview = theme.thumbnail || `/themes/${theme.renderer}/${theme.path}/dropdownPreview.png`;
const texture = theme.thumbnail || `/themes/${theme.renderer}/${theme.path}/dropdownTexture.png`; const texture = theme.thumbnail || `/themes/${theme.renderer}/${theme.path}/dropdownTexture.png`;
return <div className='item' key={`${renderer}_${theme.name}`} onClick={()=>this.handleTheme(theme)} title={''}> return <div className='item' key={`${renderer}_${theme.name}`} value={`${theme.author ?? renderer} : ${theme.name}`} data={theme} title={''}>
{theme.author ?? renderer} : {theme.name} {theme.author ?? renderer} : {theme.name}
<div className='texture-container'> <div className='texture-container'>
<img src={texture}/> <img src={texture}/>
@@ -242,45 +225,45 @@ const MetadataEditor = createClass({
}); });
}; };
console.log(this.props.themeBundle);
const currentRenderer = this.props.metadata.renderer; const currentRenderer = this.props.metadata.renderer;
const currentTheme = mergedThemes[`${_.upperFirst(this.props.metadata.renderer)}`][this.props.metadata.theme] 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; let dropdown;
if(currentRenderer == 'legacy') { if(currentRenderer == 'legacy') {
dropdown = dropdown =
<Nav.dropdown className='disabled value' trigger='disabled'> <div className='disabled value' trigger='disabled'>
<div> {`Themes are not supported in the Legacy Renderer`} <i className='fas fa-caret-down'></i> </div> <div> Themes are not supported in the Legacy Renderer </div>
</Nav.dropdown>; </div>;
} else { } else {
dropdown = dropdown =
<Nav.dropdown className='value' trigger='click'> <div className='value'>
<div> {currentTheme.author ?? _.upperFirst(currentRenderer)} : {currentTheme.name} <i className='fas fa-caret-down'></i> </div> <Combobox trigger='click'
className='themes-dropdown'
{listThemes(currentRenderer)} default={`${currentTheme.author ?? _.upperFirst(currentRenderer)} : ${currentTheme.name}`}
</Nav.dropdown>; placeholder='Enter the Share URL or ID of any brew with the meta:theme tag'
onSelect={(value)=>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']
}}
/>
<small>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.</small>
</div>;
} }
return <div className='field themes'> return <div className='field themes'>
<label>theme</label> <label>theme</label>
{!this.state.showThemeWritein?dropdown:''} {dropdown}
<button className='display writeIn' onClick={this.toggleThemeWritein}>
{`${this.state.showThemeWritein ? 'Theme List' : 'Use Brew Theme'}`}
</button>
{this.renderThemeWritein()}
</div>;
},
renderThemeWritein : function(){
if(!this.state.showThemeWritein) return;
return <div>
<input type='text'
default=''
placeholder='Enter share id'
className='value'
defaultValue={this.state.lastThemeWriteIn || this.props.metadata.theme}
onChange={(e)=>this.handleThemeWritein(e)} />
<span class='userThemeName'>{`${this.state.lastThemeWriteIn ? this.props.themeBundle?.path || '' : ''}`}</span>
</div>; </div>;
}, },
@@ -317,8 +300,7 @@ const MetadataEditor = createClass({
clearAutoSuggestOnClick : true, clearAutoSuggestOnClick : true,
filterOn : ['value', 'detail', 'title'] filterOn : ['value', 'detail', 'title']
}} }}
> />
</Combobox>
<small>Sets the HTML Lang property for your brew. May affect hyphenation or spellcheck.</small> <small>Sets the HTML Lang property for your brew. May affect hyphenation or spellcheck.</small>
</div> </div>

View File

@@ -171,89 +171,73 @@
} }
.themes.field { .themes.field {
.navDropdownContainer { & .dropdown-container {
position : relative; position : relative;
z-index : 100; z-index : 100;
background-color : white; background-color : white;
&.disabled { }
font-style : italic; & .dropdown-options {
color : dimgray; overflow-y : visible;
background-color : darkgray; }
} .disabled {
& > div:first-child { font-style : italic;
padding : 3px 3px; color : dimgray;
background-color : inherit; background-color : darkgray;
border : 1px solid gray; }
i { float : right; } .item {
&:hover { position : relative;
color : white; padding : 3px 3px;
background-color : @blue; 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%; .texture-container {
height : 1.1em; position : absolute;
overflow : hidden; top : 0;
text-overflow : ellipsis; left : 0;
white-space : nowrap; width : 100%;
} height : 100%;
.navDropdown { min-height : 100%;
position : absolute; overflow : hidden;
width : 100%; > img {
box-shadow : 0px 5px 10px rgba(0, 0, 0, 0.3); position : absolute;
.item { top : 0;
position : relative; right : 0;
padding : 3px 3px; width : 50%;
overflow : visible; min-height : 100%;
background-color : white; -webkit-mask-image : linear-gradient(90deg, transparent, black 20%);
border-top : 1px solid rgb(118, 118, 118); mask-image : linear-gradient(90deg, transparent, black 20%);
.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%);
}
}
} }
} }
&:hover {
color : white;
background-color : @blue;
filter : unset;
}
&:hover > .preview { opacity : 1; }
} }
} }