diff --git a/assets/stylesheets/App.css b/assets/stylesheets/App.css index 33216362..bf2f21f2 100644 --- a/assets/stylesheets/App.css +++ b/assets/stylesheets/App.css @@ -1780,6 +1780,11 @@ body.objectKanbanColumnResizing * { box-shadow: -2px -1px 8px 4px rgba(253, 253, 253, 0.12); } +.light-mode .objectTimelineShadow .objectTimelineRowLabel, +.light-mode .objectTimelineShadow .objectTimelineRowHeaderLabel { + box-shadow: -2px -1px 8px 4px rgba(5, 5, 5, 0.06); +} + .objectTimelineRow:hover, .objectTimelineRow:hover .objectTimelineRowLabel { background-color: var(--color-table-header-bg); @@ -2822,6 +2827,11 @@ body.objectKanbanColumnResizing * { opacity: 0.5; } +.filter-input-quote, +[data-quote] { + color: color-mix(in srgb, var(--color-text) 40%, transparent); +} + .filter-input-operand-tag { margin-inline-end: 0; margin-right: 0; diff --git a/src/components/Dashboard/common/FilterInput.jsx b/src/components/Dashboard/common/FilterInput.jsx index 68e150b4..4a3c2892 100644 --- a/src/components/Dashboard/common/FilterInput.jsx +++ b/src/components/Dashboard/common/FilterInput.jsx @@ -33,6 +33,7 @@ const PROPERTY_FILTER_PANEL_MAX_HEIGHT = 220 // Longer symbols first so ".." / "<>" / ">=" match before "." / "<" / ">". // Wildcards (* ?) are highlighted in place; @ stays as plain text — none are operands. const WILDCARDS = new Set(['*', '?']) +const QUOTE = "'" const OPERANDS = [ { @@ -138,6 +139,11 @@ const tokenize = (raw = '') => { text = '' tokens.push({ type: 'wildcard', value: value[i] }) i += 1 + } else if (value[i] === QUOTE) { + pushText(text) + text = '' + tokens.push({ type: 'quote', value: QUOTE }) + i += 1 } else { text += value[i] i += 1 @@ -164,6 +170,14 @@ const renderDateUnitNode = (value) => { return span } +const renderQuoteNode = () => { + const span = document.createElement('span') + span.setAttribute('data-quote', QUOTE) + span.className = 'filter-input-quote' + span.textContent = QUOTE + return span +} + const normalize = (raw = '') => tokenize(raw) .map((token) => token.value) @@ -414,7 +428,8 @@ const domMatchesTokens = (root, raw) => { return ( node.getAttribute?.('data-operand') != null || node.getAttribute?.('data-wildcard') != null || - node.getAttribute?.('data-date-unit') != null + node.getAttribute?.('data-date-unit') != null || + node.getAttribute?.('data-quote') != null ) }) @@ -449,6 +464,12 @@ const domMatchesTokens = (root, raw) => { (child.textContent ?? '') === token.value ) } + if (token.type === 'quote') { + return ( + child.getAttribute?.('data-quote') === token.value && + (child.textContent ?? '') === token.value + ) + } return child.getAttribute?.('data-operand') === token.value }) } @@ -645,6 +666,8 @@ const FilterInput = ({ nextChildren.push(renderWildcardNode(item.value)) } else if (item.type === 'dateUnit') { nextChildren.push(renderDateUnitNode(item.value)) + } else if (item.type === 'quote') { + nextChildren.push(renderQuoteNode()) } else { nextChildren.push(takeChip(item.value)) } diff --git a/src/components/Dashboard/common/ObjectTimelineItem.jsx b/src/components/Dashboard/common/ObjectTimelineItem.jsx index 2689b292..31c004e8 100644 --- a/src/components/Dashboard/common/ObjectTimelineItem.jsx +++ b/src/components/Dashboard/common/ObjectTimelineItem.jsx @@ -58,15 +58,13 @@ const ObjectTimelineItem = ({ minWidth: position.isPoint ? undefined : 28, maxWidth: `calc(${100 - position.left}% - 4px)`, height: 30, - padding: '0 10px', + padding: '0 11px', overflow: 'visible', whiteSpace: 'nowrap', flex: '0 0 auto', borderRadius: 8, color: 'white', - background: color, - boxShadow: - '0 1px 3px color-mix(in srgb, var(--color-primary) 35%, transparent)' + background: color }} >