Skip to content

Commit 5c4f9bf

Browse files
d13ona-agent
andcommitted
Embeds autolink match toggles into the prefix field
Restores the cohesive single-row layout for autolink rules in the redesigned Settings. The Case-sensitive/Alphanumeric checkboxes wrapped to a second row and read as detached parts; folding them back into the prefix field as embedded Aa/a1 toggles (mirroring the gl-search-input field pattern) keeps the prefix and its options as one control and stops the row from wrapping. Keeps the corrected, non-inverted ignoreCase semantics with aria-pressed state plus aria-label/title tooltips for discoverability. Co-Authored-By: Ona <no-reply@ona.com>
1 parent ae8c2ef commit 5c4f9bf

1 file changed

Lines changed: 93 additions & 43 deletions

File tree

src/webviews/apps/settings/components/settings-autolinks.ts

Lines changed: 93 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ import type { SettingsActions } from '../actions.js';
1212
import type { SettingsState } from '../state.js';
1313
import { settingsStateContext } from '../state.js';
1414
import '../../shared/components/button.js';
15-
import '../../shared/components/checkbox/checkbox.js';
1615
import '../../shared/components/code-icon.js';
1716

1817
export const tagName = 'gl-settings-autolinks';
@@ -86,20 +85,67 @@ export class GlSettingsAutolinks extends SignalWatcher(LitElement) {
8685
${focusOutline}
8786
}
8887
89-
.rule__prefix {
88+
/* The prefix field embeds its match-option toggles, so the prefix + its
89+
options read as one control (mirrors gl-search-input's field pattern) */
90+
.rule__prefix-field {
91+
--toggle-size: 2rem;
92+
93+
position: relative;
9094
flex: none;
91-
width: 10rem;
95+
width: 16rem;
96+
}
97+
98+
.rule__prefix {
99+
width: 100%;
100+
101+
/* Reserve room so typed text never runs under the toggles */
102+
padding-inline-end: calc(2 * var(--toggle-size) + var(--gl-space-2) + 2 * var(--gl-space-4));
92103
}
93104
94105
.rule__url {
95106
flex: 1;
96107
min-width: 24rem;
97108
}
98109
99-
.rule__options {
100-
display: flex;
101-
gap: var(--gl-space-12);
110+
.rule__toggles {
111+
position: absolute;
112+
inset-block: var(--gl-space-2);
113+
inset-inline-end: var(--gl-space-4);
114+
z-index: 1;
115+
display: inline-flex;
116+
gap: var(--gl-space-2);
117+
align-items: stretch;
118+
}
119+
120+
.rule__toggle {
121+
display: inline-flex;
102122
align-items: center;
123+
justify-content: center;
124+
min-width: var(--toggle-size);
125+
padding-inline: var(--gl-space-2);
126+
font-family: var(--vscode-editor-font-family);
127+
font-size: 1.1rem;
128+
line-height: 1;
129+
color: var(--color-foreground--65);
130+
cursor: pointer;
131+
background: transparent;
132+
border: var(--gl-border-width) solid transparent;
133+
border-radius: var(--gl-radius-sm);
134+
}
135+
136+
.rule__toggle:hover {
137+
color: var(--color-foreground);
138+
background-color: var(--vscode-inputOption-hoverBackground);
139+
}
140+
141+
.rule__toggle[aria-pressed='true'] {
142+
color: var(--vscode-inputOption-activeForeground);
143+
background-color: var(--vscode-inputOption-activeBackground);
144+
border-color: var(--vscode-inputOption-activeBorder);
145+
}
146+
147+
.rule__toggle:focus-visible {
148+
${focusOutline}
103149
}
104150
105151
.rule__delete {
@@ -304,18 +350,48 @@ export class GlSettingsAutolinks extends SignalWatcher(LitElement) {
304350
// position, so deleting an earlier rule doesn't silently rename the rest
305351
const name = autolink.prefix?.trim() || 'New';
306352

353+
// `ignoreCase: false` IS case-sensitive (the config semantics are inverted
354+
// from the label), so the Case-sensitive toggle is pressed when ignoreCase
355+
// is false and toggling simply flips the flag.
356+
const caseSensitive = !(autolink.ignoreCase ?? false);
357+
const alphanumeric = autolink.alphanumeric ?? false;
358+
307359
return html`<div class="rule" data-index=${index}>
308-
<input
309-
class="rule__prefix ${invalid.prefix ? 'rule__prefix--invalid' : ''}"
310-
type="text"
311-
placeholder="TICKET-"
312-
spellcheck="false"
313-
aria-label="${name} autolink prefix"
314-
aria-invalid=${invalid.prefix ? 'true' : 'false'}
315-
aria-describedby=${invalid.prefix ? prefixErrorId : nothing}
316-
.value=${autolink.prefix ?? ''}
317-
@blur=${(e: FocusEvent) => this.commitRule(index, 'prefix', (e.target as HTMLInputElement).value)}
318-
/>
360+
<span class="rule__prefix-field">
361+
<input
362+
class="rule__prefix ${invalid.prefix ? 'rule__prefix--invalid' : ''}"
363+
type="text"
364+
placeholder="TICKET-"
365+
spellcheck="false"
366+
aria-label="${name} autolink prefix"
367+
aria-invalid=${invalid.prefix ? 'true' : 'false'}
368+
aria-describedby=${invalid.prefix ? prefixErrorId : nothing}
369+
.value=${autolink.prefix ?? ''}
370+
@blur=${(e: FocusEvent) => this.commitRule(index, 'prefix', (e.target as HTMLInputElement).value)}
371+
/>
372+
<span class="rule__toggles">
373+
<button
374+
type="button"
375+
class="rule__toggle"
376+
aria-pressed=${caseSensitive ? 'true' : 'false'}
377+
aria-label="Case-sensitive"
378+
title="Case-sensitive matching"
379+
@click=${() => this.commitRule(index, 'ignoreCase', caseSensitive)}
380+
>
381+
Aa
382+
</button>
383+
<button
384+
type="button"
385+
class="rule__toggle"
386+
aria-pressed=${alphanumeric ? 'true' : 'false'}
387+
aria-label="Alphanumeric"
388+
title="Match alphanumeric references"
389+
@click=${() => this.commitRule(index, 'alphanumeric', !alphanumeric)}
390+
>
391+
a1
392+
</button>
393+
</span>
394+
</span>
319395
<input
320396
class="rule__url ${invalid.url ? 'rule__url--invalid' : ''}"
321397
type="text"
@@ -327,32 +403,6 @@ export class GlSettingsAutolinks extends SignalWatcher(LitElement) {
327403
.value=${autolink.url ?? ''}
328404
@blur=${(e: FocusEvent) => this.commitRule(index, 'url', (e.target as HTMLInputElement).value)}
329405
/>
330-
<span class="rule__options">
331-
<gl-checkbox
332-
.checked=${!(autolink.ignoreCase ?? false)}
333-
@gl-change-value=${(e: Event) =>
334-
this.commitRule(
335-
index,
336-
'ignoreCase',
337-
// The config semantics are inverted from the label: `ignoreCase: false`
338-
// IS case-sensitive. The legacy view bound these directly — a
339-
// long-standing bug hidden behind an icon-only toggle — so bind
340-
// inverted to make the labeled checkbox tell the truth.
341-
!(e.target as HTMLElement & { checked: boolean }).checked,
342-
)}
343-
>Case-sensitive</gl-checkbox
344-
>
345-
<gl-checkbox
346-
.checked=${autolink.alphanumeric ?? false}
347-
@gl-change-value=${(e: Event) =>
348-
this.commitRule(
349-
index,
350-
'alphanumeric',
351-
(e.target as HTMLElement & { checked: boolean }).checked,
352-
)}
353-
>Alphanumeric</gl-checkbox
354-
>
355-
</span>
356406
<button
357407
type="button"
358408
class="rule__delete"

0 commit comments

Comments
 (0)