From 904548521ef0e34c2be7f533927602a2efe363cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Losada=20Hern=C3=A1ndez?= Date: Thu, 19 Feb 2026 11:32:49 +0100 Subject: [PATCH 1/8] small changes --- client/homebrew/editor/tagInput/tagInput.jsx | 5 +- client/homebrew/editor/tagInput/tagInput.less | 37 +++++---- package-lock.json | 78 +++++++++---------- 3 files changed, 60 insertions(+), 60 deletions(-) diff --git a/client/homebrew/editor/tagInput/tagInput.jsx b/client/homebrew/editor/tagInput/tagInput.jsx index 9f7f71498..e9923eb6a 100644 --- a/client/homebrew/editor/tagInput/tagInput.jsx +++ b/client/homebrew/editor/tagInput/tagInput.jsx @@ -146,9 +146,7 @@ const TagInput = ({ label, valuePatterns, values = [], unique = true, placeholde type='text' value={t.draft} // always use draft pattern={valuePatterns.source} - onChange={(e)=>setTagList((prev)=>prev.map((tag, idx)=>(idx === i ? { ...tag, draft: e.target.value } : tag)), - ) - } + onChange={(e)=>setTagList((prev)=>prev.map((tag, idx)=>(idx === i ? { ...tag, draft: e.target.value } : tag)))} onKeyDown={(e)=>{ if(e.key === 'Enter') { e.preventDefault(); @@ -198,7 +196,6 @@ const TagInput = ({ label, valuePatterns, values = [], unique = true, placeholde onSelect={(value)=>submitTag(value)} onEntry={(e)=>{ if(e.key === 'Enter') { - console.log('submit'); e.preventDefault(); submitTag(e.target.value); } diff --git a/client/homebrew/editor/tagInput/tagInput.less b/client/homebrew/editor/tagInput/tagInput.less index 3165b3935..8680bcd79 100644 --- a/client/homebrew/editor/tagInput/tagInput.less +++ b/client/homebrew/editor/tagInput/tagInput.less @@ -1,21 +1,24 @@ -.list input { - border-radius: 5px; -} +.tags { -.tagInput-dropdown { - .dropdown-options { - .item { - &.type { - background-color: #00800035; - } - &.group { - background-color: #50505035; - } - &.meta { - background-color: #00008035; - } - &.system { - background-color: #80000035; + .list input { + border-radius: 5px; + } + + .tagInput-dropdown { + .dropdown-options { + .item { + &.type { + background-color: #00800035; + } + &.group { + background-color: #50505035; + } + &.meta { + background-color: #00008035; + } + &.system { + background-color: #80000035; + } } } } diff --git a/package-lock.json b/package-lock.json index db6143f52..2b3892c88 100644 --- a/package-lock.json +++ b/package-lock.json @@ -73,7 +73,7 @@ "globals": "^16.4.0", "jest": "^30.2.0", "jest-expect-message": "^1.1.3", - "jsdom": "^28.0.0", + "jsdom": "^28.1.0", "jsdom-global": "^3.0.2", "postcss-less": "^6.0.0", "stylelint": "^16.25.0", @@ -3245,13 +3245,13 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "25.2.3", - "resolved": "https://registry.npmjs.org/@types/node/-/node-25.2.3.tgz", - "integrity": "sha512-m0jEgYlYz+mDJZ2+F4v8D1AyQb+QzsNqRuI7xg1VQX/KlKS0qT9r1Mo16yo5F/MtifXFgaofIFsdFMox2SxIbQ==", + "version": "25.3.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-25.3.0.tgz", + "integrity": "sha512-4K3bqJpXpqfg2XKGK9bpDTc6xO/xoUP/RBWS7AtRMug6zZFaRekiLzjVtAoZMquxoAbzBvy5nxQ7veS5eYzf8A==", "dev": true, "license": "MIT", "dependencies": { - "undici-types": "~7.16.0" + "undici-types": "~7.18.0" } }, "node_modules/@types/stack-utils": { @@ -4121,9 +4121,9 @@ } }, "node_modules/asn1.js/node_modules/bn.js": { - "version": "4.12.2", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.2.tgz", - "integrity": "sha512-n4DSx829VRTRByMRGdjQ9iqsN0Bh4OolPsFnaZBLcbi8iXcB+kJ9s7EnRt4wILZNV3kPLHkRVfOc/HvhC3ovDw==", + "version": "4.12.3", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.3.tgz", + "integrity": "sha512-fGTi3gxV/23FTYdAoUtLYp6qySe2KE3teyZitipKNRuVYcBkoP/bB3guXN/XVKUe9mxCHXnc9C4ocyz8OmgN0g==", "license": "MIT" }, "node_modules/assert": { @@ -4497,9 +4497,9 @@ } }, "node_modules/bn.js": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.2.tgz", - "integrity": "sha512-v2YAxEmKaBLahNwE1mjp4WON6huMNeuDvagFZW+ASCuA/ku0bXR9hSMw0XpiqMoA3+rmnyck/tPRSFQkoC9Cuw==", + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.3.tgz", + "integrity": "sha512-EAcmnPkxpntVL+DS7bO1zhcZNvCkxqtkd0ZY53h06GNQ3DEkkGZ/gKgmDv6DdZQGj9BgfSPKtJJ7Dp1GPP8f7w==", "license": "MIT" }, "node_modules/body-parser": { @@ -5511,9 +5511,9 @@ } }, "node_modules/create-ecdh/node_modules/bn.js": { - "version": "4.12.2", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.2.tgz", - "integrity": "sha512-n4DSx829VRTRByMRGdjQ9iqsN0Bh4OolPsFnaZBLcbi8iXcB+kJ9s7EnRt4wILZNV3kPLHkRVfOc/HvhC3ovDw==", + "version": "4.12.3", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.3.tgz", + "integrity": "sha512-fGTi3gxV/23FTYdAoUtLYp6qySe2KE3teyZitipKNRuVYcBkoP/bB3guXN/XVKUe9mxCHXnc9C4ocyz8OmgN0g==", "license": "MIT" }, "node_modules/create-hash": { @@ -5960,9 +5960,9 @@ } }, "node_modules/diffie-hellman/node_modules/bn.js": { - "version": "4.12.2", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.2.tgz", - "integrity": "sha512-n4DSx829VRTRByMRGdjQ9iqsN0Bh4OolPsFnaZBLcbi8iXcB+kJ9s7EnRt4wILZNV3kPLHkRVfOc/HvhC3ovDw==", + "version": "4.12.3", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.3.tgz", + "integrity": "sha512-fGTi3gxV/23FTYdAoUtLYp6qySe2KE3teyZitipKNRuVYcBkoP/bB3guXN/XVKUe9mxCHXnc9C4ocyz8OmgN0g==", "license": "MIT" }, "node_modules/dir-glob": { @@ -6067,9 +6067,9 @@ } }, "node_modules/elliptic/node_modules/bn.js": { - "version": "4.12.2", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.2.tgz", - "integrity": "sha512-n4DSx829VRTRByMRGdjQ9iqsN0Bh4OolPsFnaZBLcbi8iXcB+kJ9s7EnRt4wILZNV3kPLHkRVfOc/HvhC3ovDw==", + "version": "4.12.3", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.3.tgz", + "integrity": "sha512-fGTi3gxV/23FTYdAoUtLYp6qySe2KE3teyZitipKNRuVYcBkoP/bB3guXN/XVKUe9mxCHXnc9C4ocyz8OmgN0g==", "license": "MIT" }, "node_modules/emittery": { @@ -7913,9 +7913,9 @@ } }, "node_modules/hashery": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/hashery/-/hashery-1.4.0.tgz", - "integrity": "sha512-Wn2i1In6XFxl8Az55kkgnFRiAlIAushzh26PTjL2AKtQcEfXrcLa7Hn5QOWGZEf3LU057P9TwwZjFyxfS1VuvQ==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/hashery/-/hashery-1.5.0.tgz", + "integrity": "sha512-nhQ6ExaOIqti2FDWoEMWARUqIKyjr2VcZzXShrI+A3zpeiuPWzx6iPftt44LhP74E5sW36B75N6VHbvRtpvO6Q==", "dev": true, "license": "MIT", "dependencies": { @@ -10326,9 +10326,9 @@ } }, "node_modules/miller-rabin/node_modules/bn.js": { - "version": "4.12.2", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.2.tgz", - "integrity": "sha512-n4DSx829VRTRByMRGdjQ9iqsN0Bh4OolPsFnaZBLcbi8iXcB+kJ9s7EnRt4wILZNV3kPLHkRVfOc/HvhC3ovDw==", + "version": "4.12.3", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.3.tgz", + "integrity": "sha512-fGTi3gxV/23FTYdAoUtLYp6qySe2KE3teyZitipKNRuVYcBkoP/bB3guXN/XVKUe9mxCHXnc9C4ocyz8OmgN0g==", "license": "MIT" }, "node_modules/mime": { @@ -10413,10 +10413,10 @@ } }, "node_modules/minipass": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", - "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", - "license": "ISC", + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.3.tgz", + "integrity": "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==", + "license": "BlueOak-1.0.0", "engines": { "node": ">=16 || 14 >=14.17" } @@ -11911,9 +11911,9 @@ } }, "node_modules/public-encrypt/node_modules/bn.js": { - "version": "4.12.2", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.2.tgz", - "integrity": "sha512-n4DSx829VRTRByMRGdjQ9iqsN0Bh4OolPsFnaZBLcbi8iXcB+kJ9s7EnRt4wILZNV3kPLHkRVfOc/HvhC3ovDw==", + "version": "4.12.3", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.3.tgz", + "integrity": "sha512-fGTi3gxV/23FTYdAoUtLYp6qySe2KE3teyZitipKNRuVYcBkoP/bB3guXN/XVKUe9mxCHXnc9C4ocyz8OmgN0g==", "license": "MIT" }, "node_modules/punycode": { @@ -14636,9 +14636,9 @@ } }, "node_modules/undici-types": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz", - "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==", + "version": "7.18.2", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.18.2.tgz", + "integrity": "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==", "dev": true, "license": "MIT" }, @@ -15360,9 +15360,9 @@ } }, "node_modules/whatwg-url": { - "version": "16.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-16.0.0.tgz", - "integrity": "sha512-9CcxtEKsf53UFwkSUZjG+9vydAsFO4lFHBpJUtjBcoJOCJpKnSJNwCw813zrYJHpCJ7sgfbtOe0V5Ku7Pa1XMQ==", + "version": "16.0.1", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-16.0.1.tgz", + "integrity": "sha512-1to4zXBxmXHV3IiSSEInrreIlu02vUOvrhxJJH5vcxYTBDAx51cqZiKdyTxlecdKNSjj8EcxGBxNf6Vg+945gw==", "dev": true, "license": "MIT", "dependencies": { From ba4b30228a94484c3f19f68bc1e3b1858ecf9667 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Losada=20Hern=C3=A1ndez?= Date: Thu, 19 Feb 2026 14:04:54 +0100 Subject: [PATCH 2/8] proper tooltips --- client/components/combobox.jsx | 4 +- .../editor/metadataEditor/metadataEditor.jsx | 50 +++-- .../editor/metadataEditor/metadataEditor.less | 7 +- client/homebrew/editor/tagInput/tagInput.jsx | 209 +++++++++--------- client/homebrew/editor/tagInput/tagInput.less | 6 + shared/naturalcrit/styles/tooltip.less | 13 +- 6 files changed, 160 insertions(+), 129 deletions(-) diff --git a/client/components/combobox.jsx b/client/components/combobox.jsx index 16122eafd..82f5c2ab2 100644 --- a/client/components/combobox.jsx +++ b/client/components/combobox.jsx @@ -11,6 +11,7 @@ const Combobox = createReactClass({ trigger : 'hover', default : '', placeholder : '', + tooltip: '', autoSuggest : { clearAutoSuggestOnClick : true, suggestMethod : 'includes', @@ -70,7 +71,8 @@ const Combobox = createReactClass({ return (
{this.handleDropdown(true);} : undefined} - onClick= {this.props.trigger == 'click' ? ()=>{this.handleDropdown(true);} : undefined}> + onClick= {this.props.trigger == 'click' ? ()=>{this.handleDropdown(true);} : undefined} + {...(this.props.tooltip ? { 'data-tooltip-bottom': this.props.tooltip } : {})}> this.handleInput(e)} diff --git a/client/homebrew/editor/metadataEditor/metadataEditor.jsx b/client/homebrew/editor/metadataEditor/metadataEditor.jsx index 721340079..301c088b7 100644 --- a/client/homebrew/editor/metadataEditor/metadataEditor.jsx +++ b/client/homebrew/editor/metadataEditor/metadataEditor.jsx @@ -256,7 +256,7 @@ const MetadataEditor = createReactClass({ return
-
+
- Sets the HTML Lang property for your brew. May affect hyphenation or spellcheck.
; @@ -339,14 +338,20 @@ const MetadataEditor = createReactClass({ {this.renderThumbnail()}
- this.handleFieldChange('tags', e)} - /> +
+ +
+ this.handleFieldChange('tags', e)} + tooltip='You may start tags with "type", "system", "group" or "meta" followed by a colon ":", these will be colored in your userpage.' + /> +
+
+ {this.renderLanguageDropdown()} @@ -358,15 +363,22 @@ const MetadataEditor = createReactClass({ {this.renderAuthors()} - !this.props.metadata.authors?.includes(v)]} - placeholder='invite author' unique={true} - values={this.props.metadata.invitedAuthors} - smallText='Invited author usernames are case sensitive. After adding an invited author, send them the edit link. There, they can choose to accept or decline the invitation.' - onChange={(e)=>this.handleFieldChange('invitedAuthors', e)} - /> +
+ +
+ !this.props.metadata.authors?.includes(v)]} + placeholder='invite author' unique={true} + tooltip={`Invited author usernames are case sensitive. + After adding an invited author, send them the edit link. There, they can choose to accept or decline the invitation.`} + values={this.props.metadata.invitedAuthors} + onChange={(e)=>this.handleFieldChange('invitedAuthors', e)} + /> +
+
+

Privacy

diff --git a/client/homebrew/editor/metadataEditor/metadataEditor.less b/client/homebrew/editor/metadataEditor/metadataEditor.less index 304b85d30..0a3d670fa 100644 --- a/client/homebrew/editor/metadataEditor/metadataEditor.less +++ b/client/homebrew/editor/metadataEditor/metadataEditor.less @@ -44,8 +44,6 @@ gap : 10px; } - - .field { position : relative; display : flex; @@ -62,6 +60,9 @@ & > .value { flex : 1 1 auto; width : 50px; + &[data-tooltip-right] { + max-width:380px; + } &:invalid { background : #FFB9B9; } small { display : block; @@ -110,7 +111,7 @@ } } - &.language .language-dropdown { + &.language .value { z-index : 200; max-width : 150px; } diff --git a/client/homebrew/editor/tagInput/tagInput.jsx b/client/homebrew/editor/tagInput/tagInput.jsx index e9923eb6a..a61aa4435 100644 --- a/client/homebrew/editor/tagInput/tagInput.jsx +++ b/client/homebrew/editor/tagInput/tagInput.jsx @@ -1,71 +1,71 @@ -import './tagInput.less'; -import React, { useState, useEffect } from 'react'; -import Combobox from '../../../components/combobox.jsx'; +import "./tagInput.less"; +import React, { useState, useEffect } from "react"; +import Combobox from "../../../components/combobox.jsx"; -import tagSuggestionList from './curatedTagSuggestionList.js'; +import tagSuggestionList from "./curatedTagSuggestionList.js"; -const TagInput = ({ label, valuePatterns, values = [], unique = true, placeholder = '', smallText = '', onChange })=>{ +const TagInput = ({tooltip, label, valuePatterns, values = [], unique = true, placeholder = "", smallText = "", onChange }) => { const [tagList, setTagList] = useState( - values.map((value)=>({ + values.map((value) => ({ value, - editing : false, - draft : '', + editing: false, + draft: "", })), ); - useEffect(()=>{ + useEffect(() => { const incoming = values || []; - const current = tagList.map((t)=>t.value); + const current = tagList.map((t) => t.value); - const changed = incoming.length !== current.length || incoming.some((v, i)=>v !== current[i]); + const changed = incoming.length !== current.length || incoming.some((v, i) => v !== current[i]); - if(changed) { + if (changed) { setTagList( - incoming.map((value)=>({ + incoming.map((value) => ({ value, - editing : false, + editing: false, })), ); } }, [values]); - useEffect(()=>{ + useEffect(() => { onChange?.({ - target : { value: tagList.map((t)=>t.value) }, + target: { value: tagList.map((t) => t.value) }, }); }, [tagList]); // substrings to be normalized to the first value on the array const duplicateGroups = [ - ['5e 2024', '5.5e', '5e\'24', '5.24', '5e24', '5.5'], - ['5e', '5th Edition'], - ['Dungeons & Dragons', 'Dungeons and Dragons', 'Dungeons n dragons'], - ['D&D', 'DnD', 'dnd', 'Dnd', 'dnD', 'd&d', 'd&D', 'D&d'], - ['P2e', 'p2e', 'P2E', 'Pathfinder 2e'], + ["5e 2024", "5.5e", "5e'24", "5.24", "5e24", "5.5"], + ["5e", "5th Edition"], + ["Dungeons & Dragons", "Dungeons and Dragons", "Dungeons n dragons"], + ["D&D", "DnD", "dnd", "Dnd", "dnD", "d&d", "d&D", "D&d"], + ["P2e", "p2e", "P2E", "Pathfinder 2e"], ]; - const normalizeValue = (input)=>{ + const normalizeValue = (input) => { const lowerInput = input.toLowerCase(); let normalizedTag = input; for (const group of duplicateGroups) { for (const tag of group) { - if(!tag) continue; + if (!tag) continue; const index = lowerInput.indexOf(tag.toLowerCase()); - if(index !== -1) { + if (index !== -1) { normalizedTag = input.slice(0, index) + group[0] + input.slice(index + tag.length); break; } } } - if(normalizedTag.includes(':')) { - const [rawType, rawValue = ''] = normalizedTag.split(':'); + if (normalizedTag.includes(":")) { + const [rawType, rawValue = ""] = normalizedTag.split(":"); const tagType = rawType.trim().toLowerCase(); const tagValue = rawValue.trim(); - if(tagValue.length > 0) { + if (tagValue.length > 0) { normalizedTag = `${tagType}:${tagValue[0].toUpperCase()}${tagValue.slice(1)}`; } //trims spaces around colon and capitalizes the first word after the colon @@ -75,56 +75,56 @@ const TagInput = ({ label, valuePatterns, values = [], unique = true, placeholde return normalizedTag; }; - const submitTag = (newValue, index = null)=>{ + const submitTag = (newValue, index = null) => { const trimmed = newValue?.trim(); - if(!trimmed) return; - if(!valuePatterns.test(trimmed)) return; + if (!trimmed) return; + if (!valuePatterns.test(trimmed)) return; const normalizedTag = normalizeValue(trimmed); - setTagList((prev)=>{ - const existsIndex = prev.findIndex((t)=>t.value.toLowerCase() === normalizedTag.toLowerCase()); - if(unique && existsIndex !== -1) return prev; - if(index !== null) { - return prev.map((t, i)=>(i === index ? { ...t, value: normalizedTag, editing: false } : t)); + setTagList((prev) => { + const existsIndex = prev.findIndex((t) => t.value.toLowerCase() === normalizedTag.toLowerCase()); + if (unique && existsIndex !== -1) return prev; + if (index !== null) { + return prev.map((t, i) => (i === index ? { ...t, value: normalizedTag, editing: false } : t)); } return [...prev, { value: normalizedTag, editing: false }]; }); }; - const removeTag = (index)=>{ - setTagList((prev)=>prev.filter((_, i)=>i !== index)); + const removeTag = (index) => { + setTagList((prev) => prev.filter((_, i) => i !== index)); }; - const editTag = (index)=>{ - setTagList((prev)=>prev.map((t, i)=>(i === index ? { ...t, editing: true, draft: t.value } : t))); + const editTag = (index) => { + setTagList((prev) => prev.map((t, i) => (i === index ? { ...t, editing: true, draft: t.value } : t))); }; - const stopEditing = (index)=>{ - setTagList((prev)=>prev.map((t, i)=>(i === index ? { ...t, editing: false, draft: '' } : t))); + const stopEditing = (index) => { + setTagList((prev) => prev.map((t, i) => (i === index ? { ...t, editing: false, draft: "" } : t))); }; - const suggestionOptions = tagSuggestionList.map((tag)=>{ - const tagType = tag.split(':'); + const suggestionOptions = tagSuggestionList.map((tag) => { + const tagType = tag.split(":"); - let classes = 'item'; + let classes = "item"; switch (tagType[0]) { - case 'type': - classes = 'item type'; - break; - case 'group': - classes = 'item group'; - break; - case 'meta': - classes = 'item meta'; - break; - case 'system': - classes = 'item system'; - break; - default: - classes = 'item'; - break; + case "type": + classes = "item type"; + break; + case "group": + classes = "item group"; + break; + case "meta": + classes = "item meta"; + break; + case "system": + classes = "item system"; + break; + default: + classes = "item"; + break; } return ( @@ -135,26 +135,54 @@ const TagInput = ({ label, valuePatterns, values = [], unique = true, placeholde }); return ( -
- {label && } - -
-
    - {tagList.map((t, i)=>t.editing ? ( +
    + submitTag(value)} + onEntry={(e) => { + if (e.key === "Enter") { + e.preventDefault(); + submitTag(e.target.value); + } + }} + /> +
      + {tagList.map((t, i) => + t.editing ? ( setTagList((prev)=>prev.map((tag, idx)=>(idx === i ? { ...tag, draft: e.target.value } : tag)))} - onKeyDown={(e)=>{ - if(e.key === 'Enter') { + onChange={(e) => + setTagList((prev) => + prev.map((tag, idx) => (idx === i ? { ...tag, draft: e.target.value } : tag)), + ) + } + onKeyDown={(e) => { + if (e.key === "Enter") { e.preventDefault(); submitTag(t.draft, i); // submit draft - setTagList((prev)=>prev.map((tag, idx)=>(idx === i ? { ...tag, draft: '' } : tag)), + setTagList((prev) => + prev.map((tag, idx) => (idx === i ? { ...tag, draft: "" } : tag)), ); } - if(e.key === 'Escape') { + if (e.key === "Escape") { stopEditing(i); e.target.blur(); } @@ -162,47 +190,20 @@ const TagInput = ({ label, valuePatterns, values = [], unique = true, placeholde autoFocus /> ) : ( -
    • editTag(i)}> +
    • editTag(i)}> {t.value}
    • ), - )} -
    - - submitTag(value)} - onEntry={(e)=>{ - if(e.key === 'Enter') { - e.preventDefault(); - submitTag(e.target.value); - } - }} - /> - {smallText.length !== 0 && {smallText}} -
    + )} +
); }; diff --git a/client/homebrew/editor/tagInput/tagInput.less b/client/homebrew/editor/tagInput/tagInput.less index 8680bcd79..e986c6cc7 100644 --- a/client/homebrew/editor/tagInput/tagInput.less +++ b/client/homebrew/editor/tagInput/tagInput.less @@ -1,5 +1,11 @@ .tags { + .tagInputWrap { + display:grid; + grid-template-columns: 200px 3fr; + gap:10px; + } + .list input { border-radius: 5px; } diff --git a/shared/naturalcrit/styles/tooltip.less b/shared/naturalcrit/styles/tooltip.less index b21439486..c99cbf116 100644 --- a/shared/naturalcrit/styles/tooltip.less +++ b/shared/naturalcrit/styles/tooltip.less @@ -3,18 +3,23 @@ @arrowSize : 6px; @arrowPosition : 18px; [data-tooltip] { + position:relative; .tooltip(attr(data-tooltip)); } [data-tooltip-top] { + position:relative; .tooltipTop(attr(data-tooltip-top)); } [data-tooltip-bottom] { + position:relative; .tooltipBottom(attr(data-tooltip-bottom)); } [data-tooltip-left] { + position:relative; .tooltipLeft(attr(data-tooltip-left)); } [data-tooltip-right] { + position:relative; .tooltipRight(attr(data-tooltip-right)); } .tooltip(@content) { @@ -75,8 +80,9 @@ } &::after { margin-bottom : -14px;} &::before, &::after { - bottom : 50%; + top : 50%; left : 100%; + translate:0 -50%; } &:hover::after, &:hover::before, &:focus::after, &:focus::before { .transform(translateX(@arrowSize + 2)); @@ -106,9 +112,12 @@ font-size : 12px; line-height : 12px; color : white; - white-space : nowrap; content : @content; background : @tooltipColor; + max-width : 50ch; + width :max-content; + word-break : break-word; + overflow-wrap : break-word; } &:hover::before, &:hover::after { visibility : visible; From fc44629842e62140f623b1d29a53b442f7bb6746 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Losada=20Hern=C3=A1ndez?= Date: Thu, 19 Feb 2026 14:13:51 +0100 Subject: [PATCH 3/8] tooltips instead of title attrib(not sure if good idea) --- .../homebrew/brewRenderer/toolBar/toolBar.jsx | 37 +++++++++---------- 1 file changed, 18 insertions(+), 19 deletions(-) diff --git a/client/homebrew/brewRenderer/toolBar/toolBar.jsx b/client/homebrew/brewRenderer/toolBar/toolBar.jsx index be0842f33..bde1b10dc 100644 --- a/client/homebrew/brewRenderer/toolBar/toolBar.jsx +++ b/client/homebrew/brewRenderer/toolBar/toolBar.jsx @@ -99,18 +99,18 @@ const ToolBar = ({ displayOptions, onDisplayOptionsChange, visiblePages, totalPa return ( - - + +

Options