mirror of
https://github.com/nocodb/nocodb.git
synced 2026-05-02 12:27:04 +00:00
136 lines
3.1 KiB
Vue
136 lines
3.1 KiB
Vue
<script lang="ts" setup>
|
|
interface Props {
|
|
label?: string
|
|
tooltip?: string
|
|
disableTooltip?: boolean
|
|
icon?: string
|
|
activeIcon?: string
|
|
active?: boolean
|
|
disabled?: boolean
|
|
/** Dropdown trigger — active state shows hover bg only, no indicator or text color */
|
|
isDropdown?: boolean
|
|
panelKey?: string
|
|
}
|
|
|
|
const props = withDefaults(defineProps<Props>(), {
|
|
label: '',
|
|
tooltip: '',
|
|
icon: undefined,
|
|
activeIcon: undefined,
|
|
active: false,
|
|
disabled: false,
|
|
isDropdown: false,
|
|
panelKey: undefined,
|
|
})
|
|
|
|
const emits = defineEmits<{
|
|
(e: 'click'): void
|
|
}>()
|
|
|
|
const tooltipText = computed(() => props.tooltip || props.label)
|
|
|
|
const currentIcon = computed(() => {
|
|
if (props.active && props.activeIcon) return props.activeIcon
|
|
return props.icon
|
|
})
|
|
</script>
|
|
|
|
<template>
|
|
<NcTooltip
|
|
class="w-full flex justify-center relative"
|
|
placement="right"
|
|
:arrow="false"
|
|
:disabled="!tooltipText || disableTooltip"
|
|
>
|
|
<template #title>{{ tooltipText }}</template>
|
|
|
|
<div
|
|
class="nc-rail-item"
|
|
:class="{ active, disabled, 'is-dropdown': isDropdown }"
|
|
:data-panel="panelKey"
|
|
@click="!disabled && emits('click')"
|
|
>
|
|
<!-- Active indicator bar -->
|
|
<span class="nc-rail-item-indicator" />
|
|
|
|
<slot v-if="$slots.default" />
|
|
|
|
<template v-else>
|
|
<slot name="icon">
|
|
<GeneralIcon v-if="currentIcon" :icon="(currentIcon as any)" class="nc-rail-item-icon" />
|
|
</slot>
|
|
</template>
|
|
|
|
<span v-if="label || $slots.label" class="nc-rail-item-label">
|
|
<slot name="label">{{ label }}</slot>
|
|
</span>
|
|
</div>
|
|
</NcTooltip>
|
|
</template>
|
|
|
|
<style lang="scss" scoped>
|
|
.nc-rail-item {
|
|
@apply flex flex-col gap-1.5 items-center justify-center pt-2.5 pb-1.5 cursor-pointer transition-all duration-150 rounded-[10px];
|
|
width: 53px;
|
|
|
|
&:not(.active) {
|
|
@apply text-nc-content-gray-muted;
|
|
}
|
|
|
|
.nc-rail-item-indicator {
|
|
@apply absolute left-0 top-1/2 transform -translate-y-1/2 w-[3px] h-[36px] opacity-0 pointer-events-none rounded-r-sm;
|
|
@apply bg-nc-content-brand;
|
|
transition: opacity 0.2s;
|
|
}
|
|
|
|
.nc-rail-item-icon {
|
|
@apply h-4 w-4 flex items-center justify-center;
|
|
}
|
|
|
|
.nc-rail-item-label {
|
|
@apply select-none text-captionXs text-[9px] font-medium leading-tight tracking-tight opacity-85;
|
|
}
|
|
|
|
&:hover:not(.active):not(.disabled) {
|
|
@apply text-nc-content-subtle2;
|
|
background: rgba(0, 0, 0, 0.05);
|
|
|
|
:root[theme='dark'] & {
|
|
background: rgba(255, 255, 255, 0.05);
|
|
}
|
|
}
|
|
|
|
// Normal active state: brand color text + indicator
|
|
&.active:not(.is-dropdown) {
|
|
@apply text-nc-content-brand;
|
|
background: rgba(0, 0, 0, 0.08);
|
|
|
|
:root[theme='dark'] & {
|
|
background: rgba(255, 255, 255, 0.08);
|
|
}
|
|
|
|
.nc-rail-item-indicator {
|
|
opacity: 1;
|
|
}
|
|
|
|
.nc-rail-item-label {
|
|
opacity: 1;
|
|
}
|
|
}
|
|
|
|
// Dropdown active state: hover bg only, no indicator or text color change
|
|
&.is-dropdown.active {
|
|
@apply text-nc-content-gray-muted;
|
|
background: rgba(0, 0, 0, 0.05);
|
|
|
|
:root[theme='dark'] & {
|
|
background: rgba(255, 255, 255, 0.05);
|
|
}
|
|
}
|
|
|
|
&.disabled {
|
|
@apply opacity-40 cursor-not-allowed;
|
|
}
|
|
}
|
|
</style>
|