mirror of
https://github.com/enso-org/enso.git
synced 2024-10-05 17:17:50 +03:00
Fix searchbar visuals (#10436)
https://github.com/enso-org/enso/assets/61194245/27ea6c4a-e8cb-4e03-8932-f5d75918af0c
This commit is contained in:
parent
ee39fd7f53
commit
3de873f97c
@ -74,9 +74,11 @@ export const BUTTON_STYLES = twv.tv({
|
||||
'group',
|
||||
// we need to set the height to max-content to prevent the button from growing in flex containers
|
||||
'h-[max-content]',
|
||||
// basic outline
|
||||
'outline-offset-[1px] outline-transparent',
|
||||
// buttons always have borders
|
||||
// so keep them in mind when setting paddings
|
||||
'border border-transparent',
|
||||
'border-0.5 border-transparent',
|
||||
// button reset styles
|
||||
'whitespace-nowrap cursor-pointer select-none appearance-none',
|
||||
// Align the content by the center
|
||||
@ -87,7 +89,7 @@ export const BUTTON_STYLES = twv.tv({
|
||||
variants: {
|
||||
isDisabled: { true: 'disabled:opacity-50 disabled:cursor-not-allowed' },
|
||||
isFocused: {
|
||||
true: 'focus:outline-none focus-visible:outline focus-visible:outline-primary focus-visible:outline-offset-2',
|
||||
true: 'focus:outline-none focus-visible:outline-2 focus-visible:outline-black focus-visible:outline-offset-[-2px]',
|
||||
},
|
||||
isActive: {
|
||||
none: '',
|
||||
@ -107,10 +109,10 @@ export const BUTTON_STYLES = twv.tv({
|
||||
variant: 'body',
|
||||
color: 'custom',
|
||||
weight: 'semibold',
|
||||
className: 'flex px-[11px] py-[5px]',
|
||||
className: 'flex px-[11px] py-[5.5px]',
|
||||
}),
|
||||
content: 'gap-2',
|
||||
icon: 'mb-[-0.3cap]',
|
||||
icon: 'mb-[-0.1cap] h-4.5 w-4.5',
|
||||
extraClickZone: 'after:inset-[-6px]',
|
||||
},
|
||||
medium: {
|
||||
@ -118,9 +120,9 @@ export const BUTTON_STYLES = twv.tv({
|
||||
variant: 'body',
|
||||
color: 'custom',
|
||||
weight: 'semibold',
|
||||
className: 'flex px-[9px] py-[3px]',
|
||||
className: 'flex px-[9px] py-[3.5px]',
|
||||
}),
|
||||
icon: 'mb-[-0.3cap]',
|
||||
icon: 'mb-[-0.1cap] h-4 w-4',
|
||||
content: 'gap-2',
|
||||
extraClickZone: 'after:inset-[-8px]',
|
||||
},
|
||||
@ -129,9 +131,9 @@ export const BUTTON_STYLES = twv.tv({
|
||||
variant: 'body',
|
||||
color: 'custom',
|
||||
weight: 'medium',
|
||||
className: 'flex px-[7px] py-[1px]',
|
||||
className: 'flex px-[7px] py-[1.5px]',
|
||||
}),
|
||||
icon: 'mb-[-0.3cap]',
|
||||
icon: 'mb-[-0.1cap] h-3.5 w-3.5',
|
||||
content: 'gap-1',
|
||||
extraClickZone: 'after:inset-[-10px]',
|
||||
},
|
||||
@ -140,9 +142,10 @@ export const BUTTON_STYLES = twv.tv({
|
||||
variant: 'body',
|
||||
color: 'custom',
|
||||
weight: 'medium',
|
||||
className: 'flex px-[5px] py-[1px]',
|
||||
disableLineHeightCompensation: true,
|
||||
className: 'flex px-[5px] pt-[0.5px] pb-[2.5px]',
|
||||
}),
|
||||
icon: 'mb-[-0.3cap]',
|
||||
icon: 'mb-[-0.2cap] h-3 w-3',
|
||||
content: 'gap-1',
|
||||
extraClickZone: 'after:inset-[-12px]',
|
||||
},
|
||||
@ -150,17 +153,24 @@ export const BUTTON_STYLES = twv.tv({
|
||||
base: text.TEXT_STYLE({
|
||||
variant: 'body',
|
||||
color: 'custom',
|
||||
className: 'flex px-[3px] py-[0px]',
|
||||
className: 'flex px-[3px] pt-[0.5px] pb-[2.5px] leading-[16px]',
|
||||
// we need to disable line height compensation for this size
|
||||
// because otherwise the text will be too high in the button
|
||||
disableLineHeightCompensation: true,
|
||||
}),
|
||||
content: 'gap-0.5',
|
||||
icon: 'mb-[-0.1cap]',
|
||||
extraClickZone: 'after:inset-[-12px]',
|
||||
},
|
||||
},
|
||||
iconOnly: {
|
||||
true: { base: text.TEXT_STYLE({ disableLineHeightCompensation: true }), icon: 'mb-[unset]' },
|
||||
true: {
|
||||
base: text.TEXT_STYLE({
|
||||
disableLineHeightCompensation: true,
|
||||
className: 'border-0 outline-offset-[5px]',
|
||||
}),
|
||||
icon: 'mb-[unset]',
|
||||
},
|
||||
},
|
||||
rounded: {
|
||||
full: 'rounded-full',
|
||||
@ -173,10 +183,11 @@ export const BUTTON_STYLES = twv.tv({
|
||||
xxxlarge: 'rounded-3xl',
|
||||
},
|
||||
variant: {
|
||||
custom: 'focus-visible:outline-offset-2',
|
||||
custom: '',
|
||||
link: {
|
||||
base: 'inline-block px-0 py-0 rounded-sm text-primary/50 underline hover:text-primary border-none',
|
||||
icon: 'h-[1.25cap] mt-[0.25cap]',
|
||||
base: 'inline-block px-0 py-0 rounded-sm text-primary/50 underline hover:text-primary border-0',
|
||||
content: 'gap-1.5',
|
||||
icon: 'h-[1.25cap] w-[1.25cap] mt-[0.25cap]',
|
||||
},
|
||||
primary: 'bg-primary text-white hover:bg-primary/70',
|
||||
tertiary: 'bg-accent text-white hover:bg-accent-dark',
|
||||
@ -184,17 +195,16 @@ export const BUTTON_STYLES = twv.tv({
|
||||
delete:
|
||||
'bg-danger/80 hover:bg-danger text-white focus-visible:outline-danger focus-visible:bg-danger',
|
||||
icon: {
|
||||
base: 'border-0 opacity-80 hover:opacity-100 focus-visible:opacity-100 text-primary',
|
||||
base: 'opacity-80 hover:opacity-100 focus-visible:opacity-100',
|
||||
wrapper: 'w-full h-full',
|
||||
content: 'w-full h-full',
|
||||
extraClickZone: 'w-full h-full',
|
||||
},
|
||||
ghost:
|
||||
'text-primary hover:text-primary/80 hover:bg-white focus-visible:text-primary/80 focus-visible:bg-white',
|
||||
submit: 'bg-invite text-white opacity-80 hover:opacity-100 focus-visible:outline-offset-2',
|
||||
outline:
|
||||
'border-primary/40 text-primary hover:border-primary focus-visible:outline-offset-2 hover:bg-primary/10',
|
||||
bar: 'rounded-full border-0.5 border-primary/20 transition-colors hover:bg-primary/10',
|
||||
submit: 'bg-invite text-white opacity-80 hover:opacity-100',
|
||||
outline: 'border-primary/40 text-primary hover:border-primary hover:bg-primary/5',
|
||||
bar: 'border-primary/20 hover:bg-primary/5',
|
||||
},
|
||||
iconPosition: {
|
||||
start: { content: '' },
|
||||
@ -230,7 +240,7 @@ export const BUTTON_STYLES = twv.tv({
|
||||
loader: 'absolute inset-0 flex items-center justify-center',
|
||||
content: 'flex items-center gap-[0.5em]',
|
||||
text: 'inline-flex items-center justify-center gap-1',
|
||||
icon: 'h-[2cap] flex-none aspect-square',
|
||||
icon: 'h-[1.906cap] w-[1.906cap] flex-none aspect-square flex items-center justify-center',
|
||||
},
|
||||
defaultVariants: {
|
||||
isActive: 'none',
|
||||
@ -243,42 +253,16 @@ export const BUTTON_STYLES = twv.tv({
|
||||
showIconOnHover: false,
|
||||
},
|
||||
compoundVariants: [
|
||||
{ isFocused: true, iconOnly: true, class: 'focus-visible:outline-offset-3' },
|
||||
{
|
||||
variant: 'link',
|
||||
isFocused: true,
|
||||
class: 'focus-visible:outline-offset-1',
|
||||
},
|
||||
{
|
||||
size: 'xxsmall',
|
||||
iconOnly: true,
|
||||
class: { base: 'p-0 rounded-full', icon: 'h-[1.25cap] -mt-[0.1cap]' },
|
||||
},
|
||||
{
|
||||
size: 'xsmall',
|
||||
iconOnly: true,
|
||||
class: { base: 'p-0 rounded-full', icon: 'h-[1.45cap] -mt-[0.1cap]' },
|
||||
},
|
||||
{
|
||||
size: 'small',
|
||||
iconOnly: true,
|
||||
class: { base: 'p-0 rounded-full', icon: 'h-[1.65cap] -mt-[0.1cap]' },
|
||||
},
|
||||
{
|
||||
size: 'medium',
|
||||
iconOnly: true,
|
||||
class: { base: 'p-0 rounded-full', icon: 'h-[2cap] -mt-[0.1cap]' },
|
||||
},
|
||||
{
|
||||
size: 'large',
|
||||
iconOnly: true,
|
||||
class: { base: 'p-0 rounded-full', icon: 'h-[3.65cap]' },
|
||||
},
|
||||
{
|
||||
size: 'hero',
|
||||
class: { base: 'p-0 rounded-full', icon: 'h-[5.5cap]' },
|
||||
iconOnly: true,
|
||||
},
|
||||
{ isFocused: true, iconOnly: true, class: 'focus-visible:outline-offset-[3px]' },
|
||||
{ size: 'custom', iconOnly: true, class: { icon: 'w-full h-full' } },
|
||||
{ size: 'xxsmall', iconOnly: true, class: { base: 'p-0 rounded-full', icon: 'w-2.5 h-2.5' } },
|
||||
{ size: 'xsmall', iconOnly: true, class: { base: 'p-0 rounded-full', icon: 'w-3 h-3' } },
|
||||
{ size: 'small', iconOnly: true, class: { base: 'p-0 rounded-full', icon: 'w-3.5 h-3.5' } },
|
||||
{ size: 'medium', iconOnly: true, class: { base: 'p-0 rounded-full', icon: 'w-4 h-4' } },
|
||||
{ size: 'large', iconOnly: true, class: { base: 'p-0 rounded-full', icon: 'w-4.5 h-4.5' } },
|
||||
{ size: 'hero', iconOnly: true, class: { base: 'p-0 rounded-full', icon: 'w-12 h-12' } },
|
||||
|
||||
{ variant: 'link', isFocused: true, class: 'focus-visible:outline-offset-1' },
|
||||
{ variant: 'link', size: 'xxsmall', class: 'font-medium' },
|
||||
{ variant: 'link', size: 'xsmall', class: 'font-medium' },
|
||||
{ variant: 'link', size: 'small', class: 'font-medium' },
|
||||
|
@ -36,7 +36,7 @@ export function CloseButton(props: CloseButtonProps) {
|
||||
variant="icon"
|
||||
className={values =>
|
||||
tailwindMerge.twMerge(
|
||||
'h-3 w-3 bg-primary/30 hover:bg-red-500/80 focus-visible:bg-red-500/80 focus-visible:outline-offset-1',
|
||||
'bg-primary/30 hover:bg-red-500/80 focus-visible:bg-red-500/80 focus-visible:outline-offset-1',
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
||||
// @ts-expect-error ts fails to infer the type of the className prop
|
||||
typeof className === 'function' ? className(values) : className
|
||||
@ -44,7 +44,7 @@ export function CloseButton(props: CloseButtonProps) {
|
||||
}
|
||||
tooltip={tooltip}
|
||||
showIconOnHover
|
||||
size="custom"
|
||||
size="xsmall"
|
||||
rounded="full"
|
||||
extraClickZone="medium"
|
||||
icon={icon}
|
||||
|
@ -27,11 +27,12 @@ export const TEXT_STYLE = twv.tv({
|
||||
variants: {
|
||||
color: {
|
||||
custom: '',
|
||||
primary: 'text-primary/90',
|
||||
primary: 'text-primary',
|
||||
danger: 'text-danger',
|
||||
success: 'text-share',
|
||||
disabled: 'text-primary/30',
|
||||
invert: 'text-white/80',
|
||||
invert: 'text-white',
|
||||
inherit: 'text-inherit',
|
||||
},
|
||||
font: {
|
||||
default: '',
|
||||
|
@ -44,7 +44,7 @@ export default function SvgMask(props: SvgMaskProps) {
|
||||
...(invert ? { WebkitMaskComposite: 'exclude, exclude' } : {}),
|
||||
/* eslint-enable @typescript-eslint/naming-convention */
|
||||
}}
|
||||
className={tailwindMerge.twMerge('inline-block size-max', className)}
|
||||
className={tailwindMerge.twMerge('inline-block h-max w-max', className)}
|
||||
>
|
||||
{/* This is required for this component to have the right size. */}
|
||||
<img alt={alt} src={src} className="pointer-events-none opacity-0" draggable={false} />
|
||||
|
@ -53,7 +53,7 @@ export default function Label(props: InternalLabelProps) {
|
||||
typeof childrenRaw !== 'string' ? (
|
||||
childrenRaw
|
||||
) : (
|
||||
<ariaComponents.Text truncate="1" className="max-w-24 text-inherit">
|
||||
<ariaComponents.Text truncate="1" className="max-w-24" color="invert" variant="body">
|
||||
{childrenRaw}
|
||||
</ariaComponents.Text>
|
||||
)
|
||||
@ -75,7 +75,7 @@ export default function Label(props: InternalLabelProps) {
|
||||
title={title}
|
||||
disabled={isDisabled}
|
||||
className={tailwindMerge.twMerge(
|
||||
'focus-child relative flex h-text items-center whitespace-nowrap rounded-inherit px-label-x transition-all selectable after:pointer-events-none after:absolute after:inset after:rounded-full',
|
||||
'focus-child relative flex items-center whitespace-nowrap rounded-inherit px-[7px] opacity-75 transition-all after:pointer-events-none after:absolute after:inset after:rounded-full hover:opacity-100 focus:opacity-100',
|
||||
active && 'active',
|
||||
negated && 'after:border-2 after:border-delete',
|
||||
className,
|
||||
|
@ -10,6 +10,7 @@ import * as modalProvider from '#/providers/ModalProvider'
|
||||
import * as textProvider from '#/providers/TextProvider'
|
||||
|
||||
import * as aria from '#/components/aria'
|
||||
import * as ariaComponents from '#/components/AriaComponents'
|
||||
import Label from '#/components/dashboard/Label'
|
||||
import FocusArea from '#/components/styled/FocusArea'
|
||||
import FocusRing from '#/components/styled/FocusRing'
|
||||
@ -82,7 +83,7 @@ function Tags(props: InternalTagsProps) {
|
||||
return (
|
||||
<div
|
||||
data-testid="asset-search-tag-names"
|
||||
className="pointer-events-auto flex flex-wrap gap-2 whitespace-nowrap px-search-suggestions"
|
||||
className="pointer-events-auto flex flex-wrap gap-2 whitespace-nowrap px-1.5"
|
||||
>
|
||||
{(isCloud ? AssetQuery.tagNames : AssetQuery.localTagNames).flatMap(entry => {
|
||||
const [key, tag] = entry
|
||||
@ -90,15 +91,17 @@ function Tags(props: InternalTagsProps) {
|
||||
? []
|
||||
: [
|
||||
<FocusRing key={key}>
|
||||
<aria.Button
|
||||
className="h-text rounded-full bg-frame px-button-x transition-all hover:bg-selected-frame"
|
||||
<ariaComponents.Button
|
||||
variant="bar"
|
||||
size="xsmall"
|
||||
className="min-w-12"
|
||||
onPress={() => {
|
||||
querySource.current = QuerySource.internal
|
||||
setQuery(query.add({ [key]: [[]] }))
|
||||
}}
|
||||
>
|
||||
{tag + ':'}
|
||||
</aria.Button>
|
||||
</ariaComponents.Button>
|
||||
</FocusRing>,
|
||||
]
|
||||
})}
|
||||
@ -280,7 +283,7 @@ export default function AssetSearchBar(props: AssetSearchBarProps) {
|
||||
data-testid="asset-search-bar"
|
||||
{...aria.mergeProps<aria.LabelProps>()(innerProps, {
|
||||
className:
|
||||
'z-1 group relative flex h-row grow max-w-[60em] items-center gap-asset-search-bar rounded-full px-3 text-primary',
|
||||
'z-1 group relative flex grow max-w-[60em] items-center gap-asset-search-bar rounded-full px-1.5 py-1 text-primary',
|
||||
ref: rootRef,
|
||||
onFocus: () => {
|
||||
setAreSuggestionsVisible(true)
|
||||
@ -297,14 +300,17 @@ export default function AssetSearchBar(props: AssetSearchBarProps) {
|
||||
>
|
||||
<div className="relative size-4 placeholder" />
|
||||
<div
|
||||
className={tailwindMerge.twMerge(
|
||||
'pointer-events-none absolute left top z-1 flex w-full flex-col overflow-hidden rounded-default border-0.5 border-primary/20 -outline-offset-1 outline-primary transition-colors before:absolute before:inset before:backdrop-blur-default group-focus-within:outline group-focus-within:outline-2 hover:before:bg-frame',
|
||||
areSuggestionsVisible && 'before:bg-frame'
|
||||
)}
|
||||
className={ariaComponents.DIALOG_BACKGROUND({
|
||||
className: tailwindMerge.twMerge(
|
||||
'absolute left-0 top-0 z-1 flex w-full flex-col overflow-hidden rounded-default border-0.5 border-primary/20 -outline-offset-1 outline-primary transition-colors',
|
||||
areSuggestionsVisible ? '' : 'bg-transparent'
|
||||
),
|
||||
})}
|
||||
>
|
||||
<div className="padding relative h-[30px]" />
|
||||
<div className="h-[32px]" />
|
||||
|
||||
{areSuggestionsVisible && (
|
||||
<div className="relative flex flex-col gap-search-suggestions">
|
||||
<div className="relative mt-3 flex flex-col gap-3">
|
||||
{/* Tags (`name:`, `modified:`, etc.) */}
|
||||
<Tags
|
||||
isCloud={isCloud}
|
||||
@ -316,7 +322,7 @@ export default function AssetSearchBar(props: AssetSearchBarProps) {
|
||||
{isCloud && labels.length !== 0 && (
|
||||
<div
|
||||
data-testid="asset-search-labels"
|
||||
className="pointer-events-auto flex gap-2 p-search-suggestions"
|
||||
className="pointer-events-auto flex gap-2 px-1.5"
|
||||
>
|
||||
{[...labels]
|
||||
.sort((a, b) => string.compareCaseInsensitive(a.value, b.value))
|
||||
@ -354,7 +360,7 @@ export default function AssetSearchBar(props: AssetSearchBarProps) {
|
||||
</div>
|
||||
)}
|
||||
{/* Suggestions */}
|
||||
<div className="flex max-h-search-suggestions-list flex-col overflow-y-auto">
|
||||
<div className="flex max-h-search-suggestions-list flex-col overflow-y-auto overflow-x-hidden pb-0.5 pl-0.5">
|
||||
{suggestions.map((suggestion, index) => (
|
||||
// This should not be a `<button>`, since `render()` may output a
|
||||
// tree containing a button.
|
||||
@ -367,8 +373,8 @@ export default function AssetSearchBar(props: AssetSearchBarProps) {
|
||||
}
|
||||
}}
|
||||
className={tailwindMerge.twMerge(
|
||||
'pointer-events-auto mx-search-suggestion cursor-pointer rounded-default px-search-suggestions py-search-suggestion-y text-left transition-colors last:mb-search-suggestion hover:bg-selected-frame',
|
||||
selectedIndices.has(index) && 'bg-frame',
|
||||
'flex cursor-pointer rounded-l-default rounded-r-sm px-[7px] py-0.5 text-left transition-[background-color] hover:bg-primary/5',
|
||||
selectedIndices.has(index) && 'bg-primary/10',
|
||||
index === selectedIndex && 'bg-selected-frame'
|
||||
)}
|
||||
onPress={event => {
|
||||
@ -391,14 +397,19 @@ export default function AssetSearchBar(props: AssetSearchBarProps) {
|
||||
}
|
||||
}}
|
||||
>
|
||||
{suggestion.render()}
|
||||
<ariaComponents.Text variant="body" truncate="1" className="w-full">
|
||||
{suggestion.render()}
|
||||
</ariaComponents.Text>
|
||||
</aria.Button>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<SvgMask src={FindIcon} className="absolute left-3 z-1 text-primary/30" />
|
||||
<SvgMask
|
||||
src={FindIcon}
|
||||
className="absolute left-2 top-[50%] z-1 mt-[1px] -translate-y-1/2 text-primary/40"
|
||||
/>
|
||||
<FocusRing placement="before">
|
||||
<aria.SearchField
|
||||
aria-label={getText('assetSearchFieldLabel')}
|
||||
@ -419,7 +430,7 @@ export default function AssetSearchBar(props: AssetSearchBarProps) {
|
||||
: getText('remoteBackendSearchPlaceholder')
|
||||
: getText('localBackendSearchPlaceholder')
|
||||
}
|
||||
className="focus-child peer text relative z-1 w-full bg-transparent placeholder-primary/20"
|
||||
className="focus-child peer text relative z-1 w-full bg-transparent placeholder-primary/40"
|
||||
onChange={event => {
|
||||
if (querySource.current !== QuerySource.internal) {
|
||||
querySource.current = QuerySource.typing
|
||||
|
@ -9,7 +9,6 @@ import * as backendHooks from '#/hooks/backendHooks'
|
||||
import * as modalProvider from '#/providers/ModalProvider'
|
||||
import * as textProvider from '#/providers/TextProvider'
|
||||
|
||||
import * as aria from '#/components/aria'
|
||||
import * as ariaComponents from '#/components/AriaComponents'
|
||||
import Label from '#/components/dashboard/Label'
|
||||
import Button from '#/components/styled/Button'
|
||||
@ -132,20 +131,18 @@ export default function Labels(props: LabelsProps) {
|
||||
)
|
||||
})}
|
||||
<ariaComponents.Button
|
||||
size="custom"
|
||||
variant="bar"
|
||||
className="px-2"
|
||||
isActive={false}
|
||||
size="xsmall"
|
||||
variant="outline"
|
||||
className="pl-1 pr-2"
|
||||
/* eslint-disable-next-line no-restricted-syntax */
|
||||
icon={<img src={PlusIcon} alt="" className="ml-auto mt-[1px] size-[8px]" />}
|
||||
onPress={event => {
|
||||
if (event.target instanceof HTMLElement) {
|
||||
setModal(<NewLabelModal backend={backend} eventTarget={event.target} />)
|
||||
}
|
||||
}}
|
||||
>
|
||||
{/* This is a non-standard-sized icon. */}
|
||||
{/* eslint-disable-next-line no-restricted-syntax */}
|
||||
<img src={PlusIcon} className="mr-[6px] size-[6px]" />
|
||||
<aria.Text className="text-header">{getText('newLabelButtonLabel')}</aria.Text>
|
||||
{getText('newLabelButtonLabel')}
|
||||
</ariaComponents.Button>
|
||||
</div>
|
||||
</div>
|
||||
|
Loading…
Reference in New Issue
Block a user