theme changes, and accessibility htmlfor

This commit is contained in:
Víctor Losada Hernández
2026-09-05 23:24:47 +02:00
parent 99429c08cd
commit ff8bc69591
5 changed files with 86 additions and 67 deletions
+2
View File
@@ -7,6 +7,7 @@ const Combobox = createReactClass({
displayName : 'Combobox',
getDefaultProps : function() {
return {
id : '',
className : '',
trigger : 'hover',
default : '',
@@ -75,6 +76,7 @@ const Combobox = createReactClass({
onClick= {this.props.trigger == 'click' ? ()=>{this.handleDropdown(true);} : undefined}
{...(this.props.tooltip ? { 'data-tooltip-right': this.props.tooltip } : {})}>
<input
id={this.props.id}
type='text'
onChange={(e)=>this.handleInput(e)}
value={this.state.value || ''}
+1 -1
View File
@@ -4,7 +4,7 @@
.item i {
position : absolute;
right : 10px;
color : black;
color : inherit;
}
.dropdown-options {
position : absolute;
@@ -156,11 +156,11 @@ const MetadataEditor = createReactClass({
renderPublish : function(){
if(this.props.metadata.published){
return <button className='unpublish' onClick={()=>this.handlePublish(false)}>
return <button id='publish-button' className='unpublish' onClick={()=>this.handlePublish(false)}>
<i className='fas fa-ban' aria-hidden='true' /> unpublish
</button>;
} else {
return <button className='publish' onClick={()=>this.handlePublish(true)}>
return <button id='publish-button' className='publish' onClick={()=>this.handlePublish(true)}>
<i className='fas fa-globe' aria-hidden='true' /> publish
</button>;
}
@@ -170,9 +170,9 @@ const MetadataEditor = createReactClass({
if(!this.props.metadata.editId) return;
return <div className='field delete'>
<label>delete</label>
<label htmlFor='delete-button'>delete</label>
<div className='value'>
<button className='publish' onClick={this.handleDelete}>
<button id='delete-button' className='publish' onClick={this.handleDelete}>
<i className='fas fa-trash-alt' /> delete brew
</button>
</div>
@@ -264,6 +264,7 @@ const MetadataEditor = createReactClass({
dropdown =
<div className='value' data-tooltip-top='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.'>
<Combobox trigger='click'
id="combobox-themes"
className='themes-dropdown'
default={currentThemeDisplay}
placeholder='Select from below, or enter the Share URL or ID of a brew with the meta:theme tag'
@@ -284,7 +285,7 @@ const MetadataEditor = createReactClass({
}
return <div className='field themes'>
<label>theme</label>
<label htmlFor='combobox-themes'>theme</label>
{dropdown}
</div>;
},
@@ -303,9 +304,10 @@ const MetadataEditor = createReactClass({
};
return <div className='field language'>
<label>language</label>
<label htmlFor='combobox-language'>language</label>
<div className='value' data-tooltip-right='Sets the HTML Lang property for your brew. May affect hyphenation or spellcheck.'>
<Combobox trigger='click'
id='combobox-language'
className='language-dropdown'
default={this.props.metadata.lang || ''}
placeholder='en'
@@ -359,7 +361,7 @@ const MetadataEditor = createReactClass({
<h1>Properties Editor</h1>
<div className='field title'>
<label for='title_field'>title</label>
<label htmlFor='title_field'>title</label>
<input type='text' id='title_field' className='value'
defaultValue={this.props.metadata.title}
onChange={(e)=>this.handleFieldChange('title', e)} />
@@ -367,12 +369,12 @@ const MetadataEditor = createReactClass({
<div className='field-group'>
<div className='field-column'>
<div className='field description'>
<label for='description_field'>description</label>
<label htmlFor='description_field'>description</label>
<textarea id='description_field' defaultValue={this.props.metadata.description} className='value'
onChange={(e)=>this.handleFieldChange('description', e)} />
</div>
<div className='field thumbnail'>
<label for='thumbnail_field'>thumbnail</label>
<label htmlFor='thumbnail_field'>thumbnail</label>
<input type='text'
id='thumbnail_field'
defaultValue={this.props.metadata.thumbnail}
@@ -389,9 +391,10 @@ const MetadataEditor = createReactClass({
</div>
<div className='field tags'>
<label>Tags</label>
<label htmlFor='combobox-tags'>Tags</label>
<div className='value' >
<TagInput
id='combobox-tags'
label='tags'
valuePatterns={/^\s*(?:(?:group|meta|system|type)\s*:\s*)?[A-Za-z0-9][A-Za-z0-9 \/\\.&_\-]{0,40}\s*$/}
placeholder='add tag' unique={true}
@@ -414,9 +417,10 @@ const MetadataEditor = createReactClass({
{this.renderAuthors()}
<div className='field invitedAuthors'>
<label>Invited authors</label>
<label htmlFor='combobox-invited-authors'>Invited authors</label>
<div className='value'>
<TagInput
id='combobox-invited-authors'
label='invited authors'
valuePatterns={/.+/}
validators={[(v)=>!this.props.metadata.authors?.includes(v)]}
@@ -433,7 +437,7 @@ const MetadataEditor = createReactClass({
<h2>Privacy</h2>
<div className='field publish'>
<label>publish</label>
<label htmlFor='publish-button'>publish</label>
<div className='value'>
{this.renderPublish()}
<small>Published brews are searchable in <a href='/vault'>the Vault</a> and visible on your user page. Unpublished brews are not indexed in the Vault or visible on your user page, but can still be shared and indexed by search engines. You can unpublish a brew any time.</small>
@@ -7,6 +7,16 @@
}
.metadataEditor {
--bg-clr: white;
--bg-image: @backgroundImageAlt;
--h1-clr: black;
--h2-clr: #007;
--label-clr: black;
--input-bg: white;
--input-bg-hover:#ddd;
--input-text-clr: black;
--input-placeholder-clr: grey;
position : absolute;
box-sizing : border-box;
width : 100%;
@@ -14,23 +24,25 @@
padding : 25px;
overflow-y : auto;
font-size : 13px;
background-color : white;
background-image : @backgroundImageAlt;
background-color : var(--bg-clr);
background-image : var(--bg-image);
background-size : cover;
color: var(--label-clr);
h1 {
margin : 0 0 40px;
font-weight : bold;
font-size : 18px;
text-transform : uppercase;
color: var(--h1-clr);
}
h2 {
font-size:15px;
margin : 16px 0;
font-weight : bold;
color : #007;
border-bottom : 2px solid #007;
color : var(--h2-clr);
border-bottom : 2px solid currentColor;
}
& > div { margin-bottom : 10px; }
@@ -62,6 +74,7 @@
font-weight : 800;
line-height : 1.8em;
text-transform : capitalize;
color:inherit;
}
& > .value {
flex : 1 1 auto;
@@ -76,8 +89,11 @@
}
}
input[type='text'], textarea {
border : 1px solid gray;
&:focus { outline : 1px solid #444444; }
background-color: var(--input-bg);
color:var(--input-text-clr);
border : 1px solid var(--input-placeholder-clr);
&:hover, :focus { outline : 1px solid var(--input-placeholder-clr); background-color: var(--input-bg-hover); }
&::placeholder { color: var(--input-placeholder-clr); }
}
&.description {
@@ -88,7 +104,6 @@
resize : none;
}
}
&.thumbnail, &.themes {
label { line-height : 2.0em; }
.value {
@@ -98,22 +113,30 @@
button {
.colorButton();
padding : 0px 5px;
color : white;
background-color : black;
color : var(--input-text-clr);
background-color : var(--input-bg);
border : 1px solid #999999;
&:hover { background-color : #777777; }
}
}
&.tags .tagInput-dropdown {
z-index : 400;
max-width : 200px;
.dropdown-options {
background-color:var(--input-bg);
color: var(--input-text-clr);
.item:hover {
background-color: var(--input-text-clr);
color: var(--input-bg);
}
}
}
&.language .value {
z-index : 300;
max-width : 150px;
}
&.themes {
.value {
overflow : visible;
@@ -143,7 +166,6 @@
object-fit : contain;
background-color : #AAAAAA;
}
.renderers.field .value {
label {
display : inline-flex;
@@ -173,12 +195,16 @@
.colorButton(@silver);
}
}
.delete.field .value {
button {
.colorButton(@red);
}
}
.tag {
background:var(--input-text-clr);
color: var(--input-bg);
}
.authors.field {
.tag {
font-weight:300;
@@ -220,16 +246,12 @@
}
a {
color:black;
text-underline-offset:0.2em;
}
}
.themes.field {
& .dropdown-container {
position : relative;
z-index : 200;
background-color : white;
}
& .dropdown-options { overflow-y : visible; }
.disabled {
@@ -239,33 +261,37 @@
}
.item {
position : relative;
padding : 3px 3px;
overflow : visible;
background-color : white;
border-top : 1px solid rgb(118, 118, 118);
color:inherit;
background-color : var(--input-bg);
border-top : 1px solid #767676;
.preview {
position : absolute;
top : 0;
right : 0;
z-index : 1;
z-index : 10;
display : flex;
flex-direction : column;
width : 200px;
overflow : hidden;
color : black;
background : #CCCCCC;
color : var(--input-text-clr);
background : var(--input-bg);
border-radius : 5px;
box-shadow : 0 0 5px black;
box-shadow : 0 0 5px var(--input-text-clr);
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%);
border-bottom : 2px solid #666;
}
}
input {
padding-right: 25px;
}
.texture-container {
position : absolute;
top : 0;
@@ -285,15 +311,9 @@
}
}
&:hover {
color : white;
background-color : @blue;
filter : unset;
}
&:hover > .preview { opacity : 1; }
}
}
.field .list {
display : flex;
flex : 1 0;
@@ -328,13 +348,16 @@
padding : 0.35em;
margin : 2px;
font-size : 0.95em;
background-color : #DDDDDD;
border-radius : 0.5em;
.icon { #groupedIcon; }
button {
cursor : pointer;
&:hover {
color: @redLight;
}
}
}
@@ -380,28 +403,16 @@
}
.editor.darkMode .metadataEditor {
background-color: #555;
background-image: @backgroundImageAltDark;
color:#ddd;
--bg-clr: #555;
--bg-image: @backgroundImageAlt;
--h1-clr: white;
--h2-clr: #aaf;
--label-clr: #ddd;
--input-bg: #333;
--input-text-clr: #eee;
--input-placeholder-clr: #aaa;
h2 {
color:#aaf;
border-color: #aaf;
}
input, textarea, select {
background-color:#333;
color:#eee;
&::placeholder {
color:#aaa;
}
}
.dropdown-container, .item {
background-color: #333;
}
--bg-image: @backgroundImageAltDark;
a {
color: @blueLight;
+3 -1
View File
@@ -4,7 +4,7 @@ import Combobox from '@components/combobox.jsx';
import { tagSuggestionList, canonizationList } from './curatedTagSuggestionList.js';
const TagInput = ({ tooltip, label, valuePatterns, values = [], unique = true, placeholder = '', smallText = '', onChange })=>{
const TagInput = ({ id, tooltip, label, valuePatterns, values = [], unique = true, placeholder = '', smallText = '', onChange })=>{
const [tagList, setTagList] = useState(
values.map((value)=>({
value,
@@ -128,6 +128,7 @@ const TagInput = ({ tooltip, label, valuePatterns, values = [], unique = true, p
return (
<div className='tagInputWrap'>
<Combobox
id={id}
trigger='click'
className='tagInput-dropdown'
default=''
@@ -155,6 +156,7 @@ const TagInput = ({ tooltip, label, valuePatterns, values = [], unique = true, p
<ul className='list'>
{tagList.map((t, i)=>t.editing ? (
<input
id={`${id}-${i}`}
key={i}
type='text'
value={t.draft} // always use draft