feat: add filter input to browser pane

This commit is contained in:
Lykin 2023-11-29 16:16:13 +08:00
parent 379bb5e623
commit 8201004478
6 changed files with 133 additions and 51 deletions

View File

@ -25,6 +25,7 @@ const props = defineProps({
border: Boolean,
disabled: Boolean,
buttonStyle: [String, Object],
buttonClass: [String, Object],
})
const hasTooltip = computed(() => {
@ -36,6 +37,7 @@ const hasTooltip = computed(() => {
<n-tooltip v-if="hasTooltip" :show-arrow="false">
<template #trigger>
<n-button
:class="props.buttonClass"
:color="props.color"
:disabled="disabled"
:focusable="false"
@ -57,10 +59,12 @@ const hasTooltip = computed(() => {
</n-tooltip>
<n-button
v-else
:class="props.buttonClass"
:color="props.color"
:disabled="disabled"
:focusable="false"
:loading="loading"
:style="props.buttonStyle"
:text="!border"
:type="type"
@click.prevent="emit('click')">

View File

@ -94,26 +94,13 @@ const viewLanguage = computed(() => {
}
})
const btnStyle = computed(() => ({
padding: '3px',
border: 'solid 1px #0000',
borderRadius: '3px',
}))
const pinBtnStyle = computed(() => ({
padding: '3px',
border: `solid 1px ${themeVars.value.borderColor}`,
borderRadius: '3px',
backgroundColor: themeVars.value.borderColor,
}))
/**
*
* @param {decodeTypes} decode
* @param {formatTypes} format
* @param {decodeTypes|null} decode
* @param {formatTypes|null} format
* @return {Promise<void>}
*/
const onFormatChanged = async (decode = '', format = '') => {
const onFormatChanged = async (decode = null, format = null) => {
try {
loading.value = true
const {
@ -196,21 +183,21 @@ const onSave = () => {
<template #header-extra>
<n-space :size="5">
<icon-button
:button-style="isPin ? pinBtnStyle : btnStyle"
:button-class="{ 'pinable-btn': true, 'unpin-btn': !isPin, 'pin-btn': isPin }"
:icon="Pin"
:size="19"
:t-tooltip="isPin ? 'interface.unpin_edit' : 'interface.pin_edit'"
stroke-width="4"
@click="isPin = !isPin" />
<icon-button
:button-style="btnStyle"
:button-class="['pinable-btn', 'unpin-btn']"
:icon="props.fullscreen ? OffScreen : FullScreen"
:size="18"
stroke-width="5"
t-tooltip="interface.fullscreen"
@click="onToggleFullscreen" />
<icon-button
:button-style="btnStyle"
:button-class="['pinable-btn', 'unpin-btn']"
:icon="WindowClose"
:size="18"
stroke-width="5"
@ -267,6 +254,22 @@ const onSave = () => {
background-color: unset;
}
:deep(.pinable-btn) {
padding: 3px;
border-style: solid;
border-width: 1px;
border-radius: 3px;
}
:deep(.unpin-btn) {
border-color: #0000;
}
:deep(.pin-btn) {
border-color: v-bind('themeVars.borderColor');
background-color: v-bind('themeVars.borderColor');
}
//:deep(.n-card--bordered) {
// border-radius: 0;
//}

View File

@ -2,6 +2,14 @@
import { computed, reactive } from 'vue'
import { debounce, isEmpty, trim } from 'lodash'
import { NButton, NInput } from 'naive-ui'
import IconButton from '@/components/common/IconButton.vue'
const props = defineProps({
fullSearchIcon: {
type: [String, Object],
default: null,
},
})
const emit = defineEmits(['filterChanged', 'matchChanged'])
@ -58,6 +66,7 @@ defineExpose({
<template>
<n-input-group>
<slot name="prepend" />
<n-input
v-model:value="inputData.filter"
:placeholder="$t('interface.filter')"
@ -75,9 +84,17 @@ defineExpose({
</n-tooltip>
</template>
</n-input>
<n-button :disabled="hasMatch && !hasFilter" :focusable="false" @click="onFullSearch">
<icon-button
v-if="props.fullSearchIcon"
:disabled="hasMatch && !hasFilter"
:icon="props.fullSearchIcon"
border
t-tooltip="interface.full_search"
@click="onFullSearch" />
<n-button v-else :disabled="hasMatch && !hasFilter" :focusable="false" @click="onFullSearch">
{{ $t('interface.full_search') }}
</n-button>
<slot name="append" />
</n-input-group>
</template>

View File

@ -1,5 +1,5 @@
<script setup>
import { NIcon, useThemeVars } from 'naive-ui'
import { useThemeVars } from 'naive-ui'
import BrowserTree from './BrowserTree.vue'
import IconButton from '@/components/common/IconButton.vue'
import useTabStore from 'stores/tab.js'
@ -11,6 +11,8 @@ import { useI18n } from 'vue-i18n'
import { types } from '@/consts/support_redis_type.js'
import Search from '@/components/icons/Search.vue'
import Unlink from '@/components/icons/Unlink.vue'
import Filter from '@/components/icons/Filter.vue'
import ContentSearchInput from '@/components/content_value/ContentSearchInput.vue'
const themeVars = useThemeVars()
const dialogStore = useDialogStore()
@ -60,24 +62,9 @@ const filterTypeOptions = computed(() => {
<template>
<div class="nav-pane-container flex-box-v">
<browser-tree ref="browserTreeRef" :server="currentName" />
<div v-if="filterForm.showFilter" class="nav-pane-bottom flex-box-h">
<n-input-group>
<n-select
v-model:value="filterForm.type"
:consistent-menu-width="false"
:options="filterTypeOptions"
style="width: 120px" />
<n-input clearable placeholder="" />
<n-button :focusable="false" ghost>
<template #icon>
<n-icon :component="Search" />
</template>
</n-button>
</n-input-group>
</div>
s
<!-- bottom function bar -->
<div class="nav-pane-bottom flex-box-h">
<div class="nav-pane-bottom flex-box-v">
<!-- <switch-button-->
<!-- v-model:value="viewType"-->
<!-- :icons="[TreeView, ListView]"-->
@ -86,19 +73,83 @@ const filterTypeOptions = computed(() => {
<!-- unselect-stroke-width="3"-->
<!-- @update:value="onSwitchView" />-->
<!-- <icon-button :icon="Status" size="20" stroke-width="4" t-tooltip="interface.status" @click="onInfo" />-->
<icon-button :icon="Refresh" size="20" stroke-width="4" t-tooltip="interface.reload" @click="onRefresh" />
<div class="flex-item-expand" />
<icon-button
:icon="Unlink"
size="20"
stroke-width="4"
t-tooltip="interface.disconnect"
@click="onDisconnect" />
<div
v-show="filterForm.showFilter"
class="flex-box-h nav-pane-func"
style="padding-left: 3px; padding-right: 3px">
<!-- <n-input-group v-show="filterForm.showFilter">-->
<!-- <n-select-->
<!-- v-model:value="filterForm.type"-->
<!-- :consistent-menu-width="false"-->
<!-- :options="filterTypeOptions"-->
<!-- style="width: 120px" />-->
<!-- <n-input clearable placeholder="">-->
<!-- <template #prefix></template>-->
<!-- </n-input>-->
<!-- <n-button :focusable="false" ghost>-->
<!-- <template #icon>-->
<!-- <n-icon :component="Search" />-->
<!-- </template>-->
<!-- </n-button>-->
<!-- </n-input-group>-->
<content-search-input :full-search-icon="Search">
<template #prepend>
<n-select
v-model:value="filterForm.type"
:consistent-menu-width="false"
:options="filterTypeOptions"
style="width: 120px" />
</template>
</content-search-input>
</div>
<div class="flex-box-h nav-pane-func">
<icon-button
:button-class="{
'filter-on': filterForm.showFilter,
'filter-off': !filterForm.showFilter,
'toggle-btn': true,
'nav-pane-func-btn': true,
}"
:icon="Filter"
size="20"
stroke-width="4"
t-tooltip="interface.filter_key"
@click="filterForm.showFilter = !filterForm.showFilter" />
<icon-button
:button-class="['nav-pane-func-btn']"
:icon="Refresh"
size="20"
stroke-width="4"
t-tooltip="interface.reload"
@click="onRefresh" />
<div class="flex-item-expand" />
<icon-button
:button-class="['nav-pane-func-btn']"
:icon="Unlink"
size="20"
stroke-width="4"
t-tooltip="interface.disconnect"
@click="onDisconnect" />
</div>
</div>
</div>
</template>
<style lang="scss" scoped>
:deep(.toggle-btn) {
border-style: solid;
border-width: 1px;
}
:deep(.filter-on) {
border-color: v-bind('themeVars.borderColor');
background-color: v-bind('themeVars.borderColor');
}
:deep(.filter-off) {
border-color: #0000;
}
.nav-pane-bottom {
color: v-bind('themeVars.iconColor');
border-top: v-bind('themeVars.borderColor') 1px solid;

View File

@ -18,14 +18,16 @@ const filterPattern = ref('')
<connection-tree :filter-pattern="filterPattern" />
<!-- bottom function bar -->
<div class="nav-pane-bottom flex-box-h">
<div class="nav-pane-bottom nav-pane-func flex-box-h">
<icon-button
:button-class="['nav-pane-func-btn']"
:icon="AddLink"
size="20"
stroke-width="4"
t-tooltip="interface.new_conn"
@click="dialogStore.openNewDialog()" />
<icon-button
:button-class="['nav-pane-func-btn']"
:icon="AddGroup"
size="20"
stroke-width="4"

View File

@ -130,12 +130,17 @@ body {
.nav-pane-container {
overflow: hidden;
.nav-pane-bottom {
.nav-pane-func {
align-items: center;
gap: 8px;
padding: 3px 10px 3px 10px;
gap: 3px;
padding: 3px 8px;
min-height: 30px;
//border-top: v-bind('themeVars.borderColor') 1px solid;
.nav-pane-func-btn {
padding: 3px;
border-radius: 3px;
box-sizing: border-box;
}
}
}