mirror of
https://github.com/naturalcrit/homebrewery.git
synced 2026-03-22 08:58:11 +00:00
next stable
This commit is contained in:
@@ -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>
|
||||||
|
|||||||
@@ -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}
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user