Skip to content

Commit cf057a0

Browse files
navidshadclaude
andcommitted
fix(console-crane): align bundle selector height with the Save button
The pilotui Select renders its visible trigger button at the bottom of a 4-level wrapper chain, two links of which are display:block, so the bundle selector field rendered a few px shorter than the adjacent lg Save button in SaveWordSectionV2. Lay the SelectPhraseBundleV2 root out as a flex row and stretch every link of the chain so the trigger fills the row height and lines up with Save, in both the plain and freemium (InputGroup) save layouts. (Also carries an in-progress justify-center tweak + reformatting in the same component.) Ref #86exw6kme Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent c76121e commit cf057a0

1 file changed

Lines changed: 81 additions & 47 deletions

File tree

src/console-crane/components/SelectPhraseBundleV2.vue

Lines changed: 81 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -2,53 +2,54 @@
22
<div class="relative w-full">
33
<Select v-model="selected" :options="options" multiple custom labelKey="title" valueKey="_id"
44
:placeholder="showSuggestion ? '' : 'Select Phrase Bundles to save...'">
5-
<template #selected="{
6-
selectedOption,
7-
selectedOptions,
8-
multiple,
9-
getOptionLabel,
10-
selectedCount,
11-
}">
12-
<div v-if="multiple && selectedOptions.length > 0" class="flex items-center gap-2 flex-wrap">
13-
<span class="text-xs text-gray-500 dark:text-gray-400">Selected:</span>
14-
<div class="flex items-center gap-1 flex-wrap">
15-
<span v-for="(option, index) in selectedOptions" :key="index"
16-
class="inline-flex items-center gap-1 pl-2 pr-1 py-0.5 text-xs font-medium bg-blue-100 dark:bg-blue-500/20 text-blue-800 dark:text-blue-300 rounded">
17-
{{ resolveTitle(option, getOptionLabel) }}
18-
<span role="button" tabindex="0" title="Remove"
19-
class="inline-flex items-center justify-center rounded-full p-0.5 hover:bg-blue-200 dark:hover:bg-blue-500/30 transition-colors cursor-pointer"
20-
@click.stop.prevent="removeSelected(option)"
21-
@mousedown.stop.prevent
22-
@keyup.enter.stop="removeSelected(option)">
23-
<i class="i-mdi-close text-[11px]" />
5+
<template #selected="{
6+
selectedOption,
7+
selectedOptions,
8+
multiple,
9+
getOptionLabel,
10+
selectedCount,
11+
}">
12+
<div v-if="multiple && selectedOptions.length > 0" class="flex items-center gap-2 flex-wrap">
13+
<span class="text-xs text-gray-500 dark:text-gray-400">Selected:</span>
14+
<div class="flex items-center gap-1 flex-wrap">
15+
<span v-for="(option, index) in selectedOptions" :key="index"
16+
class="inline-flex items-center gap-1 pl-2 pr-1 py-0.5 text-xs font-medium bg-blue-100 dark:bg-blue-500/20 text-blue-800 dark:text-blue-300 rounded">
17+
{{ resolveTitle(option, getOptionLabel) }}
18+
<span role="button" tabindex="0" title="Remove"
19+
class="inline-flex items-center justify-center rounded-full p-0.5 hover:bg-blue-200 dark:hover:bg-blue-500/30 transition-colors cursor-pointer"
20+
@click.stop.prevent="removeSelected(option)" @mousedown.stop.prevent
21+
@keyup.enter.stop="removeSelected(option)">
22+
<i class="i-mdi-close text-[11px]" />
23+
</span>
2424
</span>
25-
</span>
25+
</div>
2626
</div>
27-
</div>
28-
<span v-else-if="!multiple" class="flex items-center gap-2">
29-
<span class="inline-flex items-center justify-center w-5 h-5 text-xs text-blue-600">
30-
27+
28+
<span v-else-if="!multiple" class="flex items-center gap-2">
29+
<span class="inline-flex items-center justify-center w-5 h-5 text-xs text-blue-600">
30+
31+
</span>
32+
<span class="font-medium">{{ resolveTitle(selectedOption, getOptionLabel) }}</span>
3133
</span>
32-
<span class="font-medium">{{ resolveTitle(selectedOption, getOptionLabel) }}</span>
33-
</span>
34-
</template>
35-
<template #header>
36-
<InputGroup class="w-full p-2">
37-
<Input v-model="searchedBundleName" tabindex="0" :disabled="isFetching" placeholder="Search bundles..." />
38-
<Button label="Create" color="secondary" :disabled="!isCreateNewAllowed || isFetching || isCreating"
39-
:is-loading="isCreating" @click="createNewBundle" />
40-
</InputGroup>
41-
</template>
42-
<template #each="{ option, isSelected, setSelected }">
43-
<div :class="[
44-
'px-3 py-2 text-sm cursor-pointer hover:bg-gray-100 dark:hover:bg-gray-700 transition-colors duration-150',
45-
isSelected
46-
? 'bg-primary text-white hover:bg-primary/90'
47-
: 'text-gray-900 dark:text-gray-100',
48-
]" role="option" :aria-selected="isSelected" @click="setSelected">
49-
{{ (option as unknown as PhraseBundleType).title }}
50-
</div>
51-
</template>
34+
35+
</template>
36+
<template #header>
37+
<InputGroup class="w-full p-2 justify-center">
38+
<Input v-model="searchedBundleName" tabindex="0" :disabled="isFetching" placeholder="Search bundles..." />
39+
<Button label="Create" color="secondary" :disabled="!isCreateNewAllowed || isFetching || isCreating"
40+
:is-loading="isCreating" @click="createNewBundle" />
41+
</InputGroup>
42+
</template>
43+
<template #each="{ option, isSelected, setSelected }">
44+
<div :class="[
45+
'px-3 py-2 text-sm cursor-pointer hover:bg-gray-100 dark:hover:bg-gray-700 transition-colors duration-150',
46+
isSelected
47+
? 'bg-primary text-white hover:bg-primary/90'
48+
: 'text-gray-900 dark:text-gray-100',
49+
]" role="option" :aria-selected="isSelected" @click="setSelected">
50+
{{ (option as unknown as PhraseBundleType).title }}
51+
</div>
52+
</template>
5253
</Select>
5354

5455
<!--
@@ -58,13 +59,15 @@
5859
existing bundle, which clears the suggestion.
5960
-->
6061
<div v-if="showSuggestion" class="absolute inset-y-0 left-0 right-12 flex items-center pl-3 pointer-events-none">
61-
<div class="pointer-events-auto inline-flex items-center gap-1.5 min-w-0 max-w-full rounded-full bg-purple-100 dark:bg-purple-900/40 text-purple-800 dark:text-purple-200 ring-1 ring-purple-300 dark:ring-purple-700 px-2.5 py-1"
62+
<div
63+
class="pointer-events-auto inline-flex items-center gap-1.5 min-w-0 max-w-full rounded-full bg-purple-100 dark:bg-purple-900/40 text-purple-800 dark:text-purple-200 ring-1 ring-purple-300 dark:ring-purple-700 px-2.5 py-1"
6264
@click.stop>
6365
<i class="i-mdi-auto-fix text-sm opacity-80 shrink-0" />
6466
<span class="text-[10px] uppercase tracking-wide font-semibold opacity-70 shrink-0">Suggested</span>
6567
<template v-if="!isEditingSuggested">
6668
<span class="text-sm font-medium whitespace-nowrap">{{ suggestedName }}</span>
67-
<button type="button" class="shrink-0 opacity-70 hover:opacity-100" title="Edit name" @click.stop="startEditSuggested">
69+
<button type="button" class="shrink-0 opacity-70 hover:opacity-100" title="Edit name"
70+
@click.stop="startEditSuggested">
6871
<i class="i-mdi-pencil text-xs" />
6972
</button>
7073
</template>
@@ -289,5 +292,36 @@ defineExpose({
289292
</script>
290293

291294
<style scoped>
292-
/* No special styles needed; PilotUI components include styling */
295+
/*
296+
SelectPhraseBundleV2 sits next to the lg "Save" button in SaveWordSectionV2.
297+
The pilotui Select renders its visible trigger button at the bottom of a
298+
4-level wrapper chain, two links of which are display:block — so without help
299+
the trigger lands a few px shorter than Save and the selector field looks
300+
smaller (ClickUp 86exw6kme follow-up). Lay the root out as a flex row and
301+
stretch every link of the chain so the trigger fills the full row height and
302+
lines up with Save, in both the plain and freemium (InputGroup) save layouts.
303+
The suggested-bundle chip is position:absolute, so flex layout doesn't move it.
304+
305+
The chain selectors lean on pilotui's internal markup (Select root → .relative
306+
→ .relative.w-full → button); if a pilotui upgrade changes that nesting this is
307+
a cosmetic few-px regression, not a functional break.
308+
*/
309+
.relative.w-full {
310+
display: flex;
311+
}
312+
313+
/* Select root (already a column flex box) + the two block wrappers below it:
314+
grow to the row height and pass that height down as column flex boxes. */
315+
.relative.w-full > :deep(.flex.flex-col),
316+
.relative.w-full :deep(.flex.flex-col > .relative),
317+
.relative.w-full :deep(.flex.flex-col > .relative > .relative) {
318+
display: flex;
319+
flex-direction: column;
320+
flex: 1 1 auto;
321+
}
322+
323+
/* The visible trigger button fills the stretched chain. */
324+
.relative.w-full :deep(.flex.flex-col > .relative > .relative > button) {
325+
flex: 1 1 auto;
326+
}
293327
</style>

0 commit comments

Comments
 (0)