diff --git a/client/components/combobox.jsx b/client/components/combobox.jsx index 16122eafd..5060b8ecf 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,11 +71,13 @@ 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-right': this.props.tooltip } : {})}> this.handleInput(e)} value={this.state.value || ''} + title='' pattern={this.props.valuePatterns} placeholder={this.props.placeholder} onBlur={(e)=>{ diff --git a/client/components/combobox.less b/client/components/combobox.less index 27f78356b..a3c7527f2 100644 --- a/client/components/combobox.less +++ b/client/components/combobox.less @@ -10,6 +10,7 @@ position : absolute; z-index : 100; width : 100%; + height : max-content; max-height : 200px; overflow-y : auto; background-color : white; diff --git a/client/homebrew/brewRenderer/toolBar/toolBar.jsx b/client/homebrew/brewRenderer/toolBar/toolBar.jsx index be0842f33..97d996633 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 (
; } else { dropdown = -
+
- 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.
; } @@ -256,7 +255,7 @@ const MetadataEditor = createReactClass({ return
-
+
- Sets the HTML Lang property for your brew. May affect hyphenation or spellcheck.
; @@ -339,14 +337,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 +362,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..e684037e2 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,7 @@ & > .value { flex : 1 1 auto; width : 50px; + &[data-tooltip-right] { max-width : 380px; } &:invalid { background : #FFB9B9; } small { display : block; @@ -74,6 +73,16 @@ border : 1px solid gray; &:focus { outline : 1px solid #444444; } } + + &.description { + flex : 1; + textarea.value { + height : auto; + font-family : 'Open Sans', sans-serif; + resize : none; + } + } + &.thumbnail, &.themes { label { line-height : 2.0em; } .value { @@ -90,6 +99,15 @@ } } + &.tags .tagInput-dropdown { + z-index : 400; + max-width : 200px; + } + &.language .value { + z-index : 300; + max-width : 150px; + } + &.themes { .value { overflow : visible; @@ -101,27 +119,13 @@ } } - &.description { - flex : 1; - textarea.value { - height : auto; - font-family : 'Open Sans', sans-serif; - resize : none; - } - } - - &.language .language-dropdown { - z-index : 200; - max-width : 150px; - } - - &.tags .tagInput-dropdown { - z-index : 201; - max-width : 200px; + &.invitedAuthors .value { + z-index : 100; + + .tagInput-dropdown { max-width : 200px; } } } - .thumbnail-preview { position : relative; flex : 1 1; @@ -174,7 +178,7 @@ .themes.field { & .dropdown-container { position : relative; - z-index : 100; + z-index : 200; background-color : white; } & .dropdown-options { overflow-y : visible; } diff --git a/client/homebrew/editor/tagInput/tagInput.jsx b/client/homebrew/editor/tagInput/tagInput.jsx index 9f7f71498..7f4a3a77f 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,88 +75,114 @@ 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 ( -
+
{tag}
); }); 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)), - ) + onChange={(e) => + setTagList((prev) => + prev.map((tag, idx) => (idx === i ? { ...tag, draft: e.target.value } : tag)), + ) } - onKeyDown={(e)=>{ - if(e.key === 'Enter') { + 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(); } @@ -164,48 +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') { - console.log('submit'); - 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 3165b3935..e986c6cc7 100644 --- a/client/homebrew/editor/tagInput/tagInput.less +++ b/client/homebrew/editor/tagInput/tagInput.less @@ -1,21 +1,30 @@ -.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; + .tagInputWrap { + display:grid; + grid-template-columns: 200px 3fr; + gap:10px; + } + + .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": { diff --git a/shared/naturalcrit/styles/tooltip.less b/shared/naturalcrit/styles/tooltip.less index b21439486..3150aa789 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) { @@ -30,6 +35,7 @@ &::before, &::after { bottom : 100%; left : 50%; + translate: -50% 0; } &:hover::after, &:hover::before, &:focus::after, &:focus::before { .transform(translateY(-(@arrowSize + 2))); @@ -45,6 +51,7 @@ &::before, &::after { top : 100%; left : 50%; + translate: -50% 0; } &:hover::after, &:hover::before, &:focus::after, &:focus::before { .transform(translateY(@arrowSize + 2)); @@ -57,7 +64,10 @@ margin-bottom : -@arrowSize; border-left-color : @tooltipColor; } - &::after { margin-bottom : -14px;} + &::after { + margin-bottom : -14px; + max-width : 50ch; + } &::before, &::after { right : 100%; bottom : 50%; @@ -73,10 +83,14 @@ margin-left : -@arrowSize * 2; border-right-color : @tooltipColor; } - &::after { margin-bottom : -14px;} + &::after { + margin-bottom : -14px; + max-width : 50ch; + } &::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 +120,12 @@ font-size : 12px; line-height : 12px; color : white; - white-space : nowrap; content : @content; background : @tooltipColor; + max-width : 60ch; + width :max-content; + word-break : break-word; + overflow-wrap : break-word; } &:hover::before, &:hover::after { visibility : visible;