0
0
mirror of https://github.com/naturalcrit/homebrewery.git synced 2026-03-22 08:58:11 +00:00

next stable

This commit is contained in:
Víctor Losada Hernández
2026-02-16 00:58:50 +01:00
parent 2a9970705b
commit dec91cc76e
4 changed files with 33 additions and 51 deletions

View File

@@ -16,6 +16,7 @@ const Combobox = createReactClass({
suggestMethod : 'includes', suggestMethod : 'includes',
filterOn : [] // should allow as array to filter on multiple attributes, or even custom filter filterOn : [] // should allow as array to filter on multiple attributes, or even custom filter
}, },
valuePatterns: [/.+/]
}; };
}, },
getInitialState : function() { getInitialState : function() {
@@ -74,6 +75,7 @@ const Combobox = createReactClass({
type='text' type='text'
onChange={(e)=>this.handleInput(e)} onChange={(e)=>this.handleInput(e)}
value={this.state.value || ''} value={this.state.value || ''}
pattern={this.props.valuePatterns}
placeholder={this.props.placeholder} placeholder={this.props.placeholder}
onBlur={(e)=>{ onBlur={(e)=>{
if(!e.target.checkValidity()){ if(!e.target.checkValidity()){
@@ -82,6 +84,12 @@ const Combobox = createReactClass({
}); });
} }
}} }}
onKeyDown={(e)=>{
if (e.key === "Enter") {
e.preventDefault();
this.props.onEntry(e);
}
}}
/> />
<i className='fas fa-caret-down'/> <i className='fas fa-caret-down'/>
</div> </div>

View File

@@ -10,8 +10,6 @@ import TagInput from '../tagInput/tagInput.jsx';
import Themes from 'themes/themes.json'; import Themes from 'themes/themes.json';
import validations from './validations.js'; import validations from './validations.js';
const SYSTEMS = ['5e', '4e', '3.5e', 'Pathfinder'];
import homebreweryThumbnail from '../../thumbnail.png'; import homebreweryThumbnail from '../../thumbnail.png';
const callIfExists = (val, fn, ...args)=>{ const callIfExists = (val, fn, ...args)=>{
@@ -33,7 +31,6 @@ const MetadataEditor = createReactClass({
tags : [], tags : [],
published : false, published : false,
authors : [], authors : [],
systems : [],
renderer : 'legacy', renderer : 'legacy',
theme : '5ePHB', theme : '5ePHB',
lang : 'en' lang : 'en'
@@ -91,15 +88,6 @@ const MetadataEditor = createReactClass({
} }
}, },
handleSystem : function(system, e){
if(e.target.checked){
this.props.metadata.systems.push(system);
} else {
this.props.metadata.systems = _.without(this.props.metadata.systems, system);
}
this.props.onChange(this.props.metadata);
},
handleRenderer : function(renderer, e){ handleRenderer : function(renderer, e){
if(e.target.checked){ if(e.target.checked){
this.props.metadata.renderer = renderer; this.props.metadata.renderer = renderer;
@@ -155,18 +143,6 @@ const MetadataEditor = createReactClass({
}); });
}, },
renderSystems : function(){
return _.map(SYSTEMS, (val)=>{
return <label key={val}>
<input
type='checkbox'
checked={_.includes(this.props.metadata.systems, val)}
onChange={(e)=>this.handleSystem(val, e)} />
{val}
</label>;
});
},
renderPublish : function(){ renderPublish : function(){
if(this.props.metadata.published){ if(this.props.metadata.published){
return <button className='unpublish' onClick={()=>this.handlePublish(false)}> return <button className='unpublish' onClick={()=>this.handlePublish(false)}>
@@ -304,7 +280,7 @@ const MetadataEditor = createReactClass({
}, },
renderRenderOptions : function(){ renderRenderOptions : function(){
return <div className='field systems'> return <div className='field renderers'>
<label>Renderer</label> <label>Renderer</label>
<div className='value'> <div className='value'>
<label key='legacy'> <label key='legacy'>
@@ -363,19 +339,12 @@ const MetadataEditor = createReactClass({
{this.renderThumbnail()} {this.renderThumbnail()}
</div> </div>
<TagInput label='tags' valuePatterns={[/^(?:(?:group|meta|system|type):)?[A-Za-z0-9][A-Za-z0-9 \/.\-]{0,40}$/]} <TagInput label='tags' valuePatterns={/^(?:(?:group|meta|system|type):)?[A-Za-z0-9][A-Za-z0-9 \/.\-]{0,40}$/}
placeholder='add tag' unique={true} placeholder='add tag' unique={true}
values={this.props.metadata.tags} values={this.props.metadata.tags}
onChange={(e)=>this.handleFieldChange('tags', e)} onChange={(e)=>this.handleFieldChange('tags', e)}
/> />
<div className='field systems'>
<label>systems</label>
<div className='value'>
{this.renderSystems()}
</div>
</div>
{this.renderLanguageDropdown()} {this.renderLanguageDropdown()}
{this.renderThemeDropdown()} {this.renderThemeDropdown()}
@@ -386,7 +355,7 @@ const MetadataEditor = createReactClass({
{this.renderAuthors()} {this.renderAuthors()}
<TagInput label='invited authors' valuePatterns={[/.+/]} <TagInput label='invited authors' valuePatterns={/.+/}
validators={[(v)=>!this.props.metadata.authors?.includes(v)]} validators={[(v)=>!this.props.metadata.authors?.includes(v)]}
placeholder='invite author' unique={true} placeholder='invite author' unique={true}
values={this.props.metadata.invitedAuthors} values={this.props.metadata.invitedAuthors}

View File

@@ -134,7 +134,7 @@
background-color : #AAAAAA; background-color : #AAAAAA;
} }
.systems.field .value { .renderers.field .value {
label { label {
display : inline-flex; display : inline-flex;
align-items : center; align-items : center;

View File

@@ -4,7 +4,7 @@ import Combobox from "../../../components/combobox.jsx";
import tagSuggestionList from "./curatedTagSuggestionList.js"; import tagSuggestionList from "./curatedTagSuggestionList.js";
const TagInput = ({ label, unique = true, values = [], placeholder = "", onChange }) => { const TagInput = ({ label, valuePatterns, values = [], unique = true, placeholder = "", onChange }) => {
const [tagList, setTagList] = useState( const [tagList, setTagList] = useState(
values.map((value) => ({ values.map((value) => ({
value, value,
@@ -51,19 +51,27 @@ const TagInput = ({ label, unique = true, values = [], placeholder = "", onChang
const normalizeValue = (input) => { const normalizeValue = (input) => {
const lowerInput = input.toLowerCase(); const lowerInput = input.toLowerCase();
const group = duplicateGroups.find((grp) => grp.some((tag) => tag && lowerInput.includes(tag.toLowerCase())));
return group ? group[0] : input;
};
const regexPattern = for (const group of duplicateGroups) {
label === "tags" for (const tag of group) {
? /^[-A-Za-z0-9&_.()]+$/ // only allowed chars for tags if (!tag) continue;
: /^.*$/; // allow all characters otherwise
const index = lowerInput.indexOf(tag.toLowerCase());
if (index !== -1) {
return input.slice(0, index) + group[0] + input.slice(index + tag.length);
}
}
}
return input;
};
const submitTag = (newValue, index = null) => { const submitTag = (newValue, index = null) => {
const trimmed = newValue?.trim(); const trimmed = newValue?.trim();
console.log(newValue, trimmed);
if (!trimmed) return; if (!trimmed) return;
if (!regexPattern.test(trimmed)) return; console.log(valuePatterns.test(trimmed));
if (!valuePatterns.test(trimmed)) return;
const canonical = normalizeValue(trimmed); const canonical = normalizeValue(trimmed);
@@ -117,12 +125,7 @@ const TagInput = ({ label, unique = true, values = [], placeholder = "", onChang
} }
return ( return (
<div <div className={classes} key={`tag-${tag}`} value={tag} data={tag} title={tag}>
className={classes}
key={`tag-${tag}`} // unique key
value={tag}
data={tag}
title={tag}>
{tag} {tag}
</div> </div>
); );
@@ -140,7 +143,7 @@ const TagInput = ({ label, unique = true, values = [], placeholder = "", onChang
key={i} key={i}
type="text" type="text"
value={t.display} value={t.display}
pattern="[-A-Za-z0-9&_.()]+" pattern={valuePatterns.source}
onChange={(e) => { onChange={(e) => {
const val = e.target.value; const val = e.target.value;
setTagList((prev) => setTagList((prev) =>
@@ -186,9 +189,11 @@ const TagInput = ({ label, unique = true, values = [], placeholder = "", onChang
} }
: { suggestMethod: "includes", clearAutoSuggestOnClick: true, filterOn: [] } // empty filter : { suggestMethod: "includes", clearAutoSuggestOnClick: true, filterOn: [] } // empty filter
} }
valuePatterns={valuePatterns.source}
onSelect={(value) => submitTag(value)} onSelect={(value) => submitTag(value)}
onEntry={(e) => { onEntry={(e) => {
if (e.key === "Enter") { if (e.key === "Enter") {
console.log("submit");
e.preventDefault(); e.preventDefault();
submitTag(e.target.value); submitTag(e.target.value);
} }