Skip to content

Commit ab845ac

Browse files
authored
rules-ui-fixes (#9667)
* update header and conte menu styles * feat: improve rule filters UI and toggle filter menu behavior * feat(ui): add add-to-list and remove-from-list icons and update branch icon * fix(ui): move helperText outside inner div and remove margin-top * refactor(rule): migrate tree status to file status support Refactored rule.ts to replace TreeStatus with FileStatus for better consistency with UI components. Updated related functions to map file status correctly and improved semantic type strings. * fix(utils): update computeChangeStatus to return string file statuses Updated utility function computeChangeStatus to return string statuses consistent with new FileStatus types: 'addition', 'deletion', 'modification', 'rename'. * test(stories): add extensive textbox component stories Added multiple stories to showcase Textbox component with various input types, icons, emojis, sizes, states, and custom behaviors for comprehensive documentation and testing. * test(stories): update storybook files for file status and select enhancements Updated storybook stories to use new file status values and added new select component stories with icons, emojis, and mixed icon types for better testing coverage. * feat(ui): enhance Textbox icons and disabled state styles Added support for separate left and right icons in Textbox component with custom snippets. Improved disabled state styling and button disables for count action buttons and show/hide icon. * refactor(file): update FileStatusBadge and types with descriptive statuses Changed FileStatus type to descriptive string literals and updated FileStatusBadge component to reflect this new naming scheme including tooltip and color mappings. * fix(ui): update RuleFiltersEditor for file status support and UI improvements Updated RuleFiltersEditor to use new file status options, added file status badge integration, refined UI behaviors such as icon placement and filter toggle improvements. * feat(select): add icon support and refine select UI components Added support for icon props in Select and SelectItem components. Updated styling and added stories to enhance UI appearance and usability. * test(stories): add long options story for select component Added a new story in Select.stories.svelte to test long option labels and verify text overflow and ellipsis behavior in the UI select component. * fix(ui): add branch icon and ellipsis to branch selector placeholder * refactor: update Rule component UI and fix RulesList mode order * feat(rules): add 'add' mode for creating new rules and improve UI state handling * fix(ui): update RuleFiltersEditor inputs to use oninput for live updates * feat(ui): add autofocus support in Select component Added autofocus prop to Select.svelte and updated keyboard handling for list opening and navigation to improve accessibility and usability. fix(ui): add autofocus to filter inputs for better UX Added autofocus attribute to filter inputs in RuleFiltersEditor.svelte for improved user experience during filtering. * fix(ui): simplify Textbox usage in EmojiPicker header Replaced multiline Textbox component with simpler inline self-closing Textbox in EmojiPicker.svelte. fix(config): update onDisk method to await Promise Modified onDisk method in appSettings.ts to properly await the promise returned by get(writable) for consistency. fix(ui): cleanup unused imports in Minimap.svelte Removed extra blank line in imports section in Minimap.svelte for code cleanliness. fix(ui): correct typo in openAddRuleContextMenu function Fixed a typo in the function name from openAddRuleContextMenut to openAddRuleContextMenu in RulesList.svelte. chore(pkg): add esm-env dependency and update vitest version in pnpm lock Added esm-env dependency to pnpm-lock.yaml and updated jsdom version in vitest optional dependencies. * chore: remove enableSourcemap and reorder dependencies for cleanup * fix(logging): use esm-env DEV constant for environment check Replaced import.meta.env.MODE check with esm-env DEV constant in logging.ts for better environment detection.
1 parent 724e85c commit ab845ac

31 files changed

+995
-195
lines changed

apps/desktop/src/components/NewRuleMenu.svelte

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,12 +27,12 @@
2727
contextMenu?.close();
2828
}
2929
30-
export function open(e: MouseEvent) {
31-
contextMenu?.open(e);
30+
export function toggle(e: MouseEvent) {
31+
contextMenu?.toggle(e);
3232
}
3333
</script>
3434

35-
<ContextMenu bind:this={contextMenu} rightClickTrigger={trigger}>
35+
<ContextMenu bind:this={contextMenu} leftClickTrigger={trigger}>
3636
<ContextMenuSection>
3737
<ContextMenuItem
3838
icon="folder"
@@ -69,7 +69,7 @@
6969
</ContextMenuSection>
7070
{#if addEmpty}
7171
<ContextMenuSection>
72-
<ContextMenuItem label="Assign all to branch" onclick={handleAddEmpty} />
72+
<ContextMenuItem icon="arrow-right" label="Assign all to branch" onclick={handleAddEmpty} />
7373
</ContextMenuSection>
7474
{/if}
7575
</ContextMenu>

apps/desktop/src/components/Rule.svelte

Lines changed: 34 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
import { getStackName } from '$lib/stacks/stack';
1111
import { STACK_SERVICE } from '$lib/stacks/stackService.svelte';
1212
import { inject } from '@gitbutler/shared/context';
13-
import { Button, Icon, Modal, Tooltip } from '@gitbutler/ui';
13+
import { Button, FileStatusBadge, Icon, Modal, Tooltip } from '@gitbutler/ui';
1414
1515
type Props = {
1616
projectId: string;
@@ -66,7 +66,7 @@
6666
<Icon name="text-width" opacity={0.6} />
6767
<span class="text-12 truncate" title={filter.subject}>{filter.subject}</span>
6868
{:else if filter.type === 'fileChangeType'}
69-
<Icon name="file-changes" opacity={0.6} />
69+
<FileStatusBadge status={filter.subject} style="dot" />
7070
<span class="text-12 truncate">{treeStatusToShortString(filter.subject)}</span>
7171
{:else if filter.type === 'semanticType'}
7272
<Icon name="tag" opacity={0.6} />
@@ -76,7 +76,7 @@
7676
{/snippet}
7777

7878
{#snippet assignChip()}
79-
<div class="rule__chip">
79+
<div class="rule__action-chip">
8080
<Icon name="arrow-right" />
8181
</div>
8282
{/snippet}
@@ -85,7 +85,13 @@
8585
<div class="rule__actions">
8686
<div class="rule__actions-buttons">
8787
<Button icon="edit-text" size="tag" kind="ghost" onclick={editRule} />
88-
<Button icon="bin" size="tag" kind="ghost" onclick={() => confirmationModal?.show()} />
88+
<Button
89+
icon="remove-from-list"
90+
style="error"
91+
size="tag"
92+
kind="ghost"
93+
onclick={() => confirmationModal?.show()}
94+
/>
8995
</div>
9096
</div>
9197
{/snippet}
@@ -134,7 +140,8 @@
134140
.rule {
135141
display: flex;
136142
position: relative;
137-
padding: 12px;
143+
flex-wrap: wrap;
144+
padding: 12px 10px;
138145
overflow: hidden;
139146
gap: 4px;
140147
@@ -143,6 +150,7 @@
143150
}
144151
145152
&:hover .rule__actions {
153+
transform: scale(1);
146154
opacity: 1;
147155
pointer-events: auto;
148156
}
@@ -151,43 +159,48 @@
151159
.rule__actions {
152160
display: flex;
153161
position: absolute;
154-
top: 9px;
155-
right: 9px;
162+
top: 8px;
163+
right: 8px;
156164
align-items: center;
157-
background-color: var(--clr-bg-1);
158-
box-shadow: 0 0 34px 30px var(--clr-bg-1);
159-
160165
/* Initial state is hidden */
166+
transform: scale(0.9);
167+
transform-origin: top right;
168+
background-color: var(--clr-bg-1);
169+
box-shadow: 0 0 30px 30px var(--clr-bg-1);
161170
opacity: 0;
162171
pointer-events: none;
163-
transition: opacity var(--transition-slow);
172+
transition:
173+
opacity var(--transition-fast),
174+
transform var(--transition-medium);
164175
}
165176
166177
.rule__actions-buttons {
167178
display: flex;
168-
padding: 2px 4px;
169-
gap: 4px;
179+
padding: 3px;
180+
gap: 2px;
170181
border: 1px solid var(--clr-border-2);
171182
border-radius: var(--radius-ml);
172183
}
173184
174-
.rule__chip {
185+
.rule__action-chip {
175186
display: flex;
176187
align-items: center;
177188
justify-content: center;
178-
width: 24px;
179-
height: 24px;
180-
border-radius: 46px;
189+
height: var(--size-tag);
190+
padding: 0 4px;
191+
border-radius: 100px;
181192
background: var(--clr-bg-2);
193+
color: var(--clr-text-2);
182194
}
183195
184196
.rule__pill {
185197
display: flex;
186198
align-items: center;
187-
padding: 4px 6px;
188-
gap: 4px;
189-
border: 1px solid var(--clr-btn-ntrl-outline);
190-
border-radius: 46px;
199+
height: var(--size-tag);
200+
padding: 0 6px;
201+
gap: 6px;
202+
border: 1px solid var(--clr-border-2);
203+
border-radius: 100px;
191204
192205
&.error {
193206
border: 1px solid var(--clr-theme-err-element);

apps/desktop/src/components/RuleFiltersEditor.svelte

Lines changed: 43 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,7 @@
22
import NewRuleMenu from '$components/NewRuleMenu.svelte';
33
import {
44
type SemanticType,
5-
type TreeStatus,
65
type RuleFilterType,
7-
RULE_FILTER_TREE_STATUS,
86
SEMANTIC_TYPES,
97
type RuleFilter,
108
treeStatusToString,
@@ -13,7 +11,10 @@
1311
type RuleFilterMap
1412
} from '$lib/rules/rule';
1513
import { typedKeys } from '$lib/utils/object';
16-
import { Button, Select, SelectItem, Textbox } from '@gitbutler/ui';
14+
import { Button, Select, SelectItem, Textbox, FileStatusBadge } from '@gitbutler/ui';
15+
import type { FileStatus } from '@gitbutler/ui/components/file/types';
16+
17+
const FILE_STATUS_OPTIONS: FileStatus[] = ['addition', 'modification', 'deletion', 'rename'];
1718
1819
type Props = {
1920
initialFilterValues: Partial<RuleFilterMap>;
@@ -30,7 +31,7 @@
3031
let contentRegex = $state<string | undefined>(
3132
initialFilterValues.contentMatchesRegex ?? undefined
3233
);
33-
let treeChangeType = $state<TreeStatus | undefined>(
34+
let treeChangeType = $state<FileStatus | undefined>(
3435
initialFilterValues.fileChangeType ?? undefined
3536
);
3637
let semanticType = $state<SemanticType | undefined>(initialFilterValues.semanticType?.type);
@@ -66,7 +67,7 @@
6667
6768
function handleAddFilter(e: MouseEvent) {
6869
e.stopPropagation();
69-
newFilterContextMenu?.open(e);
70+
newFilterContextMenu?.toggle(e);
7071
}
7172
7273
export function getRuleFilters(): RuleFilter[] | undefined {
@@ -107,42 +108,49 @@
107108
<!-- Path filter -->
108109
{#snippet pathMatchesRegex()}
109110
<Textbox
110-
icon="folder"
111+
iconLeft="folder"
111112
wide
112113
value={pathRegex}
113-
onchange={(v) => (pathRegex = v)}
114+
oninput={(v) => (pathRegex = v)}
114115
placeholder="Path: e.g. src/components"
116+
autofocus
115117
/>
116118
{/snippet}
117119

118120
<!-- Content filter -->
119121
{#snippet contentMatchesRegex()}
120122
<Textbox
121-
icon="text-width"
123+
iconLeft="text-width"
122124
wide
123125
value={contentRegex}
124-
onchange={(v) => (contentRegex = v)}
126+
oninput={(v) => (contentRegex = v)}
125127
placeholder="Contains: e.g. TODO"
128+
autofocus
126129
/>
127130
{/snippet}
128131

129132
<!-- File change type filter -->
130133
{#snippet fileChangeType()}
131134
<Select
132135
value={treeChangeType}
133-
options={RULE_FILTER_TREE_STATUS.map((type) => ({
136+
options={FILE_STATUS_OPTIONS.map((type) => ({
134137
label: treeStatusToString(type),
135138
value: type
136139
}))}
137140
placeholder="Change type..."
138141
flex="1"
142+
icon="file-changes"
143+
autofocus
139144
onselect={(selected) => {
140-
treeChangeType = selected as TreeStatus;
145+
treeChangeType = selected as FileStatus;
141146
}}
142147
>
143148
{#snippet itemSnippet({ item, highlighted })}
144149
<SelectItem selected={item.value === treeChangeType} {highlighted}>
145150
{item.label}
151+
{#snippet iconSnippet()}
152+
<FileStatusBadge style="dot" status={item.value as FileStatus} />
153+
{/snippet}
146154
</SelectItem>
147155
{/snippet}
148156
</Select>
@@ -156,6 +164,8 @@
156164
placeholder="Work category..."
157165
flex="1"
158166
searchable
167+
icon="tag"
168+
autofocus
159169
onselect={(selected) => {
160170
semanticType = selected as SemanticType;
161171
}}
@@ -185,16 +195,24 @@
185195
<div class="rule-filter-row__actions">
186196
<Button
187197
icon="bin"
188-
size="icon"
198+
size="cta"
199+
class="rule-filter-row__button"
189200
kind="ghost"
201+
width="auto"
190202
onclick={() => {
191203
deleteFilter(type);
192204
}}
193205
/>
194206
{#if isLastFilterType(type) && canAddMore}
195-
<div bind:this={addFilterButton}>
196-
<Button icon="plus" size="icon" kind="ghost" onclick={handleAddFilter} />
197-
</div>
207+
<Button
208+
bind:el={addFilterButton}
209+
class="rule-filter-row__button"
210+
width="auto"
211+
icon="plus"
212+
size="cta"
213+
kind="ghost"
214+
onclick={handleAddFilter}
215+
/>
198216
{/if}
199217
</div>
200218
</div>
@@ -228,13 +246,21 @@
228246
<style lang="postcss">
229247
.rule-filter-row {
230248
display: flex;
231-
align-items: center;
249+
margin-bottom: 8px;
232250
gap: 8px;
251+
252+
&:last-child {
253+
margin-bottom: 0;
254+
}
233255
}
234256
235257
.rule-filter-row__actions {
236258
display: flex;
237259
align-items: center;
238-
gap: 4px;
260+
/* gap: 2px; */
261+
}
262+
263+
:global(.rule-filter-row .rule-filter-row__button) {
264+
padding: 0 6px;
239265
}
240266
</style>

0 commit comments

Comments
 (0)