feat: add custom title bar
This commit is contained in:
parent
b580fedade
commit
1a4622cfd0
|
@ -63,7 +63,7 @@ watch(
|
||||||
class="fill-height">
|
class="fill-height">
|
||||||
<n-global-style />
|
<n-global-style />
|
||||||
<n-dialog-provider>
|
<n-dialog-provider>
|
||||||
<n-spin v-show="initializing" :theme-overrides="{ opacitySpinning: 0 }">
|
<n-spin v-show="initializing" :theme-overrides="{ opacitySpinning: 0 }" style="--wails-draggable: drag">
|
||||||
<div id="launch-container" />
|
<div id="launch-container" />
|
||||||
</n-spin>
|
</n-spin>
|
||||||
<app-content v-if="!initializing" class="flex-item-expand" />
|
<app-content v-if="!initializing" class="flex-item-expand" />
|
||||||
|
|
|
@ -11,6 +11,11 @@ import useTabStore from './stores/tab.js'
|
||||||
import usePreferencesStore from './stores/preferences.js'
|
import usePreferencesStore from './stores/preferences.js'
|
||||||
import useConnectionStore from './stores/connections.js'
|
import useConnectionStore from './stores/connections.js'
|
||||||
import ContentLogPane from './components/content/ContentLogPane.vue'
|
import ContentLogPane from './components/content/ContentLogPane.vue'
|
||||||
|
import ContentValueTab from '@/components/content/ContentValueTab.vue'
|
||||||
|
import ToolbarControlWidget from '@/components/common/ToolbarControlWidget.vue'
|
||||||
|
import { WindowToggleMaximise } from 'wailsjs/runtime/runtime.js'
|
||||||
|
import { isMacOS } from '@/utils/platform.js'
|
||||||
|
import iconUrl from '@/assets/images/icon.png'
|
||||||
|
|
||||||
const themeVars = useThemeVars()
|
const themeVars = useThemeVars()
|
||||||
|
|
||||||
|
@ -19,6 +24,7 @@ const data = reactive({
|
||||||
navMenuWidth: 60,
|
navMenuWidth: 60,
|
||||||
hoverResize: false,
|
hoverResize: false,
|
||||||
resizing: false,
|
resizing: false,
|
||||||
|
toolbarHeight: 45,
|
||||||
})
|
})
|
||||||
|
|
||||||
const tabStore = useTabStore()
|
const tabStore = useTabStore()
|
||||||
|
@ -69,49 +75,85 @@ watch(
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<!-- app content-->
|
<!-- app content-->
|
||||||
<div id="app-content-wrapper" :class="{ dragging }" :style="prefStore.generalFont" class="flex-box-h">
|
<div id="app-content-wrapper" class="flex-box-v">
|
||||||
<nav-menu v-model:value="tabStore.nav" :width="data.navMenuWidth" />
|
<!-- title bar -->
|
||||||
<!-- browser page-->
|
<div
|
||||||
<div v-show="tabStore.nav === 'browser'" class="flex-box-h flex-item-expand">
|
id="app-toolbar"
|
||||||
<div id="app-side" :style="{ width: asideWidthVal }" class="flex-box-h flex-item">
|
class="flex-box-h"
|
||||||
<browser-pane
|
style="--wails-draggable: drag"
|
||||||
v-for="t in tabStore.tabs"
|
:style="{ height: data.toolbarHeight + 'px' }"
|
||||||
v-show="get(tabStore.currentTab, 'name') === t.name"
|
@dblclick="WindowToggleMaximise">
|
||||||
:key="t.name"
|
<!-- title -->
|
||||||
class="flex-item-expand" />
|
<div
|
||||||
<div
|
id="app-toolbar-title"
|
||||||
:class="{
|
:style="{
|
||||||
'resize-divider-hover': data.hoverResize,
|
width: `${data.navMenuWidth + prefStore.general.asideWidth}px`,
|
||||||
'resize-divider-drag': data.resizing,
|
paddingLeft: isMacOS() ? '70px' : '10px',
|
||||||
}"
|
}">
|
||||||
class="resize-divider"
|
<n-space align="center" :wrap-item="false" :wrap="false" :size="3">
|
||||||
@mousedown="startResize"
|
<n-avatar :src="iconUrl" color="#0000" :size="35" style="min-width: 35px" />
|
||||||
@mouseout="data.hoverResize = false"
|
<div style="min-width: 68px; font-weight: 800">Tiny RDM</div>
|
||||||
@mouseover="data.hoverResize = true" />
|
<transition name="fade">
|
||||||
|
<n-text v-if="tabStore.nav === 'browser'" strong class="ellipsis" style="font-size: 13px">
|
||||||
|
- {{ get(tabStore.currentTab, 'name') }}
|
||||||
|
</n-text>
|
||||||
|
</transition>
|
||||||
|
</n-space>
|
||||||
</div>
|
</div>
|
||||||
<content-pane class="flex-item-expand" />
|
<!-- browser tabs -->
|
||||||
|
<div v-show="tabStore.nav === 'browser'" class="app-toolbar-tab flex-item-expand">
|
||||||
|
<content-value-tab />
|
||||||
|
</div>
|
||||||
|
<div class="flex-item-expand"></div>
|
||||||
|
<!-- simulate window control buttons -->
|
||||||
|
<toolbar-control-widget v-if="!isMacOS()" :size="data.toolbarHeight" style="align-self: flex-start" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- server list page -->
|
<!-- content -->
|
||||||
<div v-show="tabStore.nav === 'server'" class="flex-box-h flex-item-expand">
|
<div id="app-content" :style="prefStore.generalFont" class="flex-box-h flex-item-expand">
|
||||||
<div id="app-side" :style="{ width: asideWidthVal }" class="flex-box-h flex-item">
|
<nav-menu v-model:value="tabStore.nav" :width="data.navMenuWidth" />
|
||||||
<connection-pane class="flex-item-expand" />
|
<!-- browser page-->
|
||||||
<div
|
<div v-show="tabStore.nav === 'browser'" :class="{ dragging }" class="flex-box-h flex-item-expand">
|
||||||
:class="{
|
<div id="app-side" :style="{ width: asideWidthVal }" class="flex-box-h flex-item">
|
||||||
'resize-divider-hover': data.hoverResize,
|
<browser-pane
|
||||||
'resize-divider-drag': data.resizing,
|
v-for="t in tabStore.tabs"
|
||||||
}"
|
v-show="get(tabStore.currentTab, 'name') === t.name"
|
||||||
class="resize-divider"
|
:key="t.name"
|
||||||
@mousedown="startResize"
|
class="flex-item-expand" />
|
||||||
@mouseout="data.hoverResize = false"
|
<div
|
||||||
@mouseover="data.hoverResize = true" />
|
:class="{
|
||||||
|
'resize-divider-hover': data.hoverResize,
|
||||||
|
'resize-divider-drag': data.resizing,
|
||||||
|
}"
|
||||||
|
class="resize-divider"
|
||||||
|
@mousedown="startResize"
|
||||||
|
@mouseout="data.hoverResize = false"
|
||||||
|
@mouseover="data.hoverResize = true" />
|
||||||
|
</div>
|
||||||
|
<content-pane class="flex-item-expand" />
|
||||||
</div>
|
</div>
|
||||||
<content-server-pane class="flex-item-expand" />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- log page -->
|
<!-- server list page -->
|
||||||
<div v-show="tabStore.nav === 'log'" class="flex-box-h flex-item-expand">
|
<div v-show="tabStore.nav === 'server'" :class="{ dragging }" class="flex-box-h flex-item-expand">
|
||||||
<content-log-pane ref="logPaneRef" class="flex-item-expand" />
|
<div id="app-side" :style="{ width: asideWidthVal }" class="flex-box-h flex-item">
|
||||||
|
<connection-pane class="flex-item-expand" />
|
||||||
|
<div
|
||||||
|
:class="{
|
||||||
|
'resize-divider-hover': data.hoverResize,
|
||||||
|
'resize-divider-drag': data.resizing,
|
||||||
|
}"
|
||||||
|
class="resize-divider"
|
||||||
|
@mousedown="startResize"
|
||||||
|
@mouseout="data.hoverResize = false"
|
||||||
|
@mouseover="data.hoverResize = true" />
|
||||||
|
</div>
|
||||||
|
<content-server-pane class="flex-item-expand" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- log page -->
|
||||||
|
<div v-show="tabStore.nav === 'log'" class="flex-box-h flex-item-expand">
|
||||||
|
<content-log-pane ref="logPaneRef" class="flex-item-expand" />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
@ -120,12 +162,28 @@ watch(
|
||||||
#app-content-wrapper {
|
#app-content-wrapper {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
border-top: v-bind('themeVars.borderColor') 1px solid;
|
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
|
|
||||||
#app-toolbar {
|
#app-toolbar {
|
||||||
height: 40px;
|
background-color: v-bind('themeVars.tabColor');
|
||||||
border-bottom: v-bind('themeVars.borderColor') 1px solid;
|
border-bottom: 1px solid v-bind('themeVars.borderColor');
|
||||||
|
|
||||||
|
&-title {
|
||||||
|
padding-left: 10px;
|
||||||
|
padding-right: 10px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
align-self: center;
|
||||||
|
align-items: baseline;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.app-toolbar-tab {
|
||||||
|
align-self: flex-end;
|
||||||
|
margin-bottom: -1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#app-content {
|
||||||
|
height: calc(100% - 60px);
|
||||||
}
|
}
|
||||||
|
|
||||||
#app-side {
|
#app-side {
|
||||||
|
@ -157,4 +215,14 @@ watch(
|
||||||
.dragging {
|
.dragging {
|
||||||
cursor: col-resize !important;
|
cursor: col-resize !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.fade-enter-from,
|
||||||
|
.fade-leave-to {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fade-enter-active,
|
||||||
|
.fade-leave-active {
|
||||||
|
transition: opacity 0.3s ease;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
Binary file not shown.
After Width: | Height: | Size: 8.4 KiB |
|
@ -0,0 +1,82 @@
|
||||||
|
<script setup>
|
||||||
|
import WindowMin from '@/components/icons/WindowMin.vue'
|
||||||
|
import WindowMax from '@/components/icons/WindowMax.vue'
|
||||||
|
import WindowClose from '@/components/icons/WindowClose.vue'
|
||||||
|
import { computed } from 'vue'
|
||||||
|
import { useThemeVars } from 'naive-ui'
|
||||||
|
import { Quit, WindowMinimise, WindowToggleMaximise } from 'wailsjs/runtime/runtime.js'
|
||||||
|
|
||||||
|
const themeVars = useThemeVars()
|
||||||
|
const props = defineProps({
|
||||||
|
size: {
|
||||||
|
type: Number,
|
||||||
|
default: 35,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const buttonSize = computed(() => {
|
||||||
|
return props.size + 'px'
|
||||||
|
})
|
||||||
|
|
||||||
|
const handleMinimise = async () => {
|
||||||
|
WindowMinimise()
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleMaximise = () => {
|
||||||
|
WindowToggleMaximise()
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleClose = () => {
|
||||||
|
Quit()
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<n-space :wrap-item="false" align="center" justify="center" :size="0">
|
||||||
|
<div class="btn-wrapper" @click="handleMinimise">
|
||||||
|
<window-min />
|
||||||
|
</div>
|
||||||
|
<div class="btn-wrapper" @click="handleMaximise">
|
||||||
|
<window-max />
|
||||||
|
</div>
|
||||||
|
<div class="btn-wrapper" @click="handleClose">
|
||||||
|
<window-close />
|
||||||
|
</div>
|
||||||
|
</n-space>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.btn-wrapper {
|
||||||
|
width: v-bind('buttonSize');
|
||||||
|
height: v-bind('buttonSize');
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
--wails-draggable: none;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:not(:last-child) {
|
||||||
|
&:hover {
|
||||||
|
background-color: v-bind('themeVars.closeColorHover');
|
||||||
|
}
|
||||||
|
|
||||||
|
&:active {
|
||||||
|
background-color: v-bind('themeVars.closeColorPressed');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&:last-child {
|
||||||
|
&:hover {
|
||||||
|
background-color: v-bind('themeVars.primaryColorHover');
|
||||||
|
}
|
||||||
|
|
||||||
|
&:active {
|
||||||
|
background-color: v-bind('themeVars.primaryColorPressed');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -90,7 +90,7 @@ defineExpose({
|
||||||
<icon-button :icon="Delete" border t-tooltip="clean_log" @click="cleanHistory" />
|
<icon-button :icon="Delete" border t-tooltip="clean_log" @click="cleanHistory" />
|
||||||
</n-form-item>
|
</n-form-item>
|
||||||
</n-form>
|
</n-form>
|
||||||
<div class="fill-height flex-box-h" style="user-select: text">
|
<div class="content-value fill-height flex-box-h">
|
||||||
<n-data-table
|
<n-data-table
|
||||||
ref="tableRef"
|
ref="tableRef"
|
||||||
:columns="[
|
:columns="[
|
||||||
|
|
|
@ -121,34 +121,10 @@ const onReloadKey = async () => {
|
||||||
}
|
}
|
||||||
await connectionStore.loadKeyValue(tab.name, tab.db, tab.key)
|
await connectionStore.loadKeyValue(tab.name, tab.db, tab.key)
|
||||||
}
|
}
|
||||||
|
|
||||||
const i18n = useI18n()
|
|
||||||
const onCloseTab = (tabIndex) => {
|
|
||||||
$dialog.warning(i18n.t('close_confirm'), () => {
|
|
||||||
const tab = get(tabStore.tabs, tabIndex)
|
|
||||||
if (tab != null) {
|
|
||||||
connectionStore.closeConnection(tab.name)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="content-container flex-box-v">
|
<div class="content-container flex-box-v">
|
||||||
<!-- <content-value-tab :tabs="tab" />-->
|
|
||||||
<n-tabs
|
|
||||||
v-model:value="tabStore.activatedIndex"
|
|
||||||
:closable="true"
|
|
||||||
size="small"
|
|
||||||
type="card"
|
|
||||||
@close="onCloseTab"
|
|
||||||
@update:value="onUpdateValue">
|
|
||||||
<n-tab v-for="(t, i) in tab" :key="i" :name="i">
|
|
||||||
<n-ellipsis style="max-width: 150px">{{ t.label }}</n-ellipsis>
|
|
||||||
</n-tab>
|
|
||||||
</n-tabs>
|
|
||||||
<!-- TODO: add loading status -->
|
|
||||||
|
|
||||||
<div v-if="showServerStatus" class="content-container flex-item-expand flex-box-v">
|
<div v-if="showServerStatus" class="content-container flex-item-expand flex-box-v">
|
||||||
<!-- select nothing or select server node, display server status -->
|
<!-- select nothing or select server node, display server status -->
|
||||||
<content-server-status
|
<content-server-status
|
||||||
|
|
|
@ -1,136 +1,88 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref } from 'vue'
|
import ToggleServer from '@/components/icons/ToggleServer.vue'
|
||||||
import { ConnectionType } from '@/consts/connection_type.js'
|
import useTabStore from 'stores/tab.js'
|
||||||
import Close from '@/components/icons/Close.vue'
|
import { computed } from 'vue'
|
||||||
import useConnectionStore from 'stores/connections.js'
|
import { useI18n } from 'vue-i18n'
|
||||||
|
import { get, map } from 'lodash'
|
||||||
import { useThemeVars } from 'naive-ui'
|
import { useThemeVars } from 'naive-ui'
|
||||||
|
import useConnectionStore from 'stores/connections.js'
|
||||||
const emit = defineEmits(['switchTab', 'closeTab', 'update:modelValue'])
|
|
||||||
|
|
||||||
const themeVars = useThemeVars()
|
const themeVars = useThemeVars()
|
||||||
|
const i18n = useI18n()
|
||||||
|
const tabStore = useTabStore()
|
||||||
|
const connectionStore = useConnectionStore()
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
selectedIndex: {
|
backgroundColor: String,
|
||||||
type: Number,
|
|
||||||
default: 0,
|
|
||||||
},
|
|
||||||
modelValue: {
|
|
||||||
type: Object,
|
|
||||||
default: [
|
|
||||||
{
|
|
||||||
// label: 'tab1',
|
|
||||||
// key: 'key',
|
|
||||||
// bgColor: 'white',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
tabs: {
|
|
||||||
type: Array,
|
|
||||||
default: [
|
|
||||||
{
|
|
||||||
// label: 'tab1',
|
|
||||||
// key: 'key',
|
|
||||||
// bgColor: 'white',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
})
|
})
|
||||||
|
|
||||||
const connectionStore = useConnectionStore()
|
const onCloseTab = (tabIndex) => {
|
||||||
const onCurrentSelectChange = ({ type, group = '', server = '', db = 0, key = '' }) => {
|
$dialog.warning(i18n.t('close_confirm'), () => {
|
||||||
console.log(`group: ${group}\n server: ${server}\n db: ${db}\n key: ${key}`)
|
const tab = get(tabStore.tabs, tabIndex)
|
||||||
if (type === ConnectionType.RedisValue) {
|
if (tab != null) {
|
||||||
// load and update content value
|
connectionStore.closeConnection(tab.name)
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
// watch(() => databaseStore.currentSelect, throttle(onCurrentSelectChange, 1000))
|
|
||||||
|
|
||||||
const items = ref(props.modelValue)
|
|
||||||
const selIndex = ref(props.selectedIndex)
|
|
||||||
|
|
||||||
const onClickTab = (idx, key) => {
|
|
||||||
if (idx !== selIndex.value) {
|
|
||||||
selIndex.value = idx
|
|
||||||
emit('update:modelValue', idx, key)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const onCloseTab = (idx, key) => {
|
const activeTabStyle = computed(() => ({
|
||||||
emit('closeTab', idx, key)
|
backgroundColor: themeVars.value.baseColor,
|
||||||
}
|
borderTopWidth: '1px',
|
||||||
|
borderTopColor: themeVars.value.borderColor,
|
||||||
|
borderBottomColor: themeVars.value.baseColor,
|
||||||
|
borderTopLeftRadius: themeVars.value.borderRadius,
|
||||||
|
borderTopRightRadius: themeVars.value.borderRadius,
|
||||||
|
}))
|
||||||
|
const inactiveTabStyle = computed(() => ({
|
||||||
|
borderWidth: '0 0 1px',
|
||||||
|
borderBottomColor: themeVars.value.borderColor,
|
||||||
|
borderTopLeftRadius: themeVars.value.borderRadius,
|
||||||
|
borderTopRightRadius: themeVars.value.borderRadius,
|
||||||
|
}))
|
||||||
|
|
||||||
|
const tab = computed(() =>
|
||||||
|
map(tabStore.tabs, (item) => ({
|
||||||
|
key: item.name,
|
||||||
|
label: item.title,
|
||||||
|
})),
|
||||||
|
)
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<!-- TODO: 检查标签是否太多, 左右两边显示左右切换翻页按钮 -->
|
<n-tabs
|
||||||
<div class="content-tab flex-box-h">
|
v-model:value="tabStore.activatedIndex"
|
||||||
<div
|
:closable="true"
|
||||||
v-for="(item, i) in props.tabs"
|
:tab-style="{
|
||||||
:key="item.key"
|
borderStyle: 'solid',
|
||||||
:class="{ 'content-tab_selected': selIndex === i }"
|
borderWidth: '1px',
|
||||||
:style="{ backgroundColor: item.bgColor || '' }"
|
}"
|
||||||
:title="item.label"
|
size="small"
|
||||||
class="content-tab_item flex-item-expand icon-btn flex-box-h"
|
type="card"
|
||||||
@click="onClickTab(i, item.key)">
|
@close="onCloseTab"
|
||||||
<n-icon :component="Close" class="content-tab_item-close" size="20" @click.stop="onCloseTab(i, item.key)" />
|
@update:value="(tabIndex) => tabStore.switchTab(tabIndex)"
|
||||||
<div class="content-tab_item-label ellipsis flex-item-expand">
|
:theme-overrides="{
|
||||||
{{ item.label }}
|
tabFontWeightActive: 800,
|
||||||
</div>
|
tabBorderRadius: 0,
|
||||||
</div>
|
tabGapSmallCard: 0,
|
||||||
</div>
|
tabGapMediumCard: 0,
|
||||||
|
tabGapLargeCard: 0,
|
||||||
|
tabColor: '#0000',
|
||||||
|
tabBorderColor: themeVars.borderColor,
|
||||||
|
}">
|
||||||
|
<n-tab
|
||||||
|
v-for="(t, i) in tab"
|
||||||
|
:key="i"
|
||||||
|
:name="i"
|
||||||
|
:closable="tabStore.activatedIndex === i"
|
||||||
|
:style="tabStore.activatedIndex === i ? activeTabStyle : inactiveTabStyle"
|
||||||
|
style="--wails-draggable: none"
|
||||||
|
@dblclick.stop="() => {}">
|
||||||
|
<n-space align="center" justify="center" :wrap-item="false" :size="5" inline>
|
||||||
|
<n-icon :component="ToggleServer" size="18" />
|
||||||
|
<n-ellipsis style="max-width: 150px">{{ t.label }}</n-ellipsis>
|
||||||
|
</n-space>
|
||||||
|
</n-tab>
|
||||||
|
</n-tabs>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style scoped lang="scss"></style>
|
||||||
.content-tab {
|
|
||||||
align-items: center;
|
|
||||||
//justify-content: center;
|
|
||||||
width: 100%;
|
|
||||||
height: 40px;
|
|
||||||
overflow: hidden;
|
|
||||||
font-size: 14px;
|
|
||||||
|
|
||||||
&_item {
|
|
||||||
flex: 1 0;
|
|
||||||
overflow: hidden;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
gap: 3px;
|
|
||||||
height: 100%;
|
|
||||||
box-sizing: border-box;
|
|
||||||
background-color: var(--bg-color-page);
|
|
||||||
color: var(--text-color-secondary);
|
|
||||||
padding: 0 5px;
|
|
||||||
|
|
||||||
//border-top: var(--el-border-color) 1px solid;
|
|
||||||
border-right: var(--border-color) 1px solid;
|
|
||||||
transition: all var(--transition-duration-fast) var(--transition-function-ease-in-out-bezier);
|
|
||||||
|
|
||||||
&-label {
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
&-close {
|
|
||||||
//display: none;
|
|
||||||
display: inline-flex;
|
|
||||||
width: 0;
|
|
||||||
transition: width 0.3s;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
background-color: rgb(176, 177, 182, 0.4);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
.content-tab_item-close {
|
|
||||||
//display: block;
|
|
||||||
width: 20px;
|
|
||||||
transition: width 0.3s;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&_selected {
|
|
||||||
border-top: v-bind('themeVars.primaryColor') 4px solid !important;
|
|
||||||
background-color: #ffffff;
|
|
||||||
color: #303133;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
|
@ -265,13 +265,15 @@ const onUpdateFilter = (filters, sourceColumn) => {
|
||||||
{{ $t('add_row') }}
|
{{ $t('add_row') }}
|
||||||
</n-button>
|
</n-button>
|
||||||
</div>
|
</div>
|
||||||
<div class="fill-height flex-box-h" style="user-select: text">
|
<div class="value-wrapper fill-height flex-box-h">
|
||||||
<n-data-table
|
<n-data-table
|
||||||
:key="(row) => row.no"
|
:key="(row) => row.no"
|
||||||
:columns="columns"
|
:columns="columns"
|
||||||
:data="tableData"
|
:data="tableData"
|
||||||
:single-column="true"
|
:single-column="true"
|
||||||
:single-line="false"
|
:single-line="false"
|
||||||
|
:bordered="false"
|
||||||
|
:bottom-bordered="false"
|
||||||
flex-height
|
flex-height
|
||||||
max-height="100%"
|
max-height="100%"
|
||||||
size="small"
|
size="small"
|
||||||
|
|
|
@ -189,13 +189,15 @@ const onUpdateFilter = (filters, sourceColumn) => {
|
||||||
{{ $t('add_row') }}
|
{{ $t('add_row') }}
|
||||||
</n-button>
|
</n-button>
|
||||||
</div>
|
</div>
|
||||||
<div class="fill-height flex-box-h" style="user-select: text">
|
<div class="value-wrapper fill-height flex-box-h">
|
||||||
<n-data-table
|
<n-data-table
|
||||||
:key="(row) => row.no"
|
:key="(row) => row.no"
|
||||||
:columns="columns"
|
:columns="columns"
|
||||||
:data="tableData"
|
:data="tableData"
|
||||||
:single-column="true"
|
:single-column="true"
|
||||||
:single-line="false"
|
:single-line="false"
|
||||||
|
:bordered="false"
|
||||||
|
:bottom-bordered="false"
|
||||||
flex-height
|
flex-height
|
||||||
max-height="100%"
|
max-height="100%"
|
||||||
size="small"
|
size="small"
|
||||||
|
|
|
@ -185,13 +185,15 @@ const onUpdateFilter = (filters, sourceColumn) => {
|
||||||
{{ $t('add_row') }}
|
{{ $t('add_row') }}
|
||||||
</n-button>
|
</n-button>
|
||||||
</div>
|
</div>
|
||||||
<div class="fill-height flex-box-h" style="user-select: text">
|
<div class="value-wrapper fill-height flex-box-h">
|
||||||
<n-data-table
|
<n-data-table
|
||||||
:key="(row) => row.no"
|
:key="(row) => row.no"
|
||||||
:columns="columns"
|
:columns="columns"
|
||||||
:data="tableData"
|
:data="tableData"
|
||||||
:single-column="true"
|
:single-column="true"
|
||||||
:single-line="false"
|
:single-line="false"
|
||||||
|
:bordered="false"
|
||||||
|
:bottom-bordered="false"
|
||||||
flex-height
|
flex-height
|
||||||
max-height="100%"
|
max-height="100%"
|
||||||
size="small"
|
size="small"
|
||||||
|
|
|
@ -178,13 +178,15 @@ const onUpdateFilter = (filters, sourceColumn) => {
|
||||||
{{ $t('add_row') }}
|
{{ $t('add_row') }}
|
||||||
</n-button>
|
</n-button>
|
||||||
</div>
|
</div>
|
||||||
<div class="fill-height flex-box-h" style="user-select: text">
|
<div class="value-wrapper fill-height flex-box-h">
|
||||||
<n-data-table
|
<n-data-table
|
||||||
:key="(row) => row.id"
|
:key="(row) => row.id"
|
||||||
:columns="columns"
|
:columns="columns"
|
||||||
:data="tableData"
|
:data="tableData"
|
||||||
:single-column="true"
|
:single-column="true"
|
||||||
:single-line="false"
|
:single-line="false"
|
||||||
|
:bordered="false"
|
||||||
|
:bottom-bordered="false"
|
||||||
flex-height
|
flex-height
|
||||||
max-height="100%"
|
max-height="100%"
|
||||||
size="small"
|
size="small"
|
||||||
|
|
|
@ -220,5 +220,6 @@ const onSaveValue = async () => {
|
||||||
.value-wrapper {
|
.value-wrapper {
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
border-top: v-bind('themeVars.borderColor') 1px solid;
|
border-top: v-bind('themeVars.borderColor') 1px solid;
|
||||||
|
padding: 5px;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -296,13 +296,15 @@ const onUpdateFilter = (filters, sourceColumn) => {
|
||||||
{{ $t('add_row') }}
|
{{ $t('add_row') }}
|
||||||
</n-button>
|
</n-button>
|
||||||
</div>
|
</div>
|
||||||
<div class="fill-height flex-box-h" style="user-select: text">
|
<div class="value-wrapper fill-height flex-box-h">
|
||||||
<n-data-table
|
<n-data-table
|
||||||
:key="(row) => row.no"
|
:key="(row) => row.no"
|
||||||
:columns="columns"
|
:columns="columns"
|
||||||
:data="tableData"
|
:data="tableData"
|
||||||
:single-column="true"
|
:single-column="true"
|
||||||
:single-line="false"
|
:single-line="false"
|
||||||
|
:bordered="false"
|
||||||
|
:bottom-bordered="false"
|
||||||
flex-height
|
flex-height
|
||||||
max-height="100%"
|
max-height="100%"
|
||||||
size="small"
|
size="small"
|
||||||
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
<script setup>
|
||||||
|
const props = defineProps({
|
||||||
|
size: {
|
||||||
|
type: [Number, String],
|
||||||
|
default: 12,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<svg aria-hidden="false" :width="props.size" :height="props.size" viewBox="0 0 12 12">
|
||||||
|
<polygon
|
||||||
|
fill="currentColor"
|
||||||
|
fill-rule="evenodd"
|
||||||
|
points="11 1.576 6.583 6 11 10.424 10.424 11 6 6.583 1.576 11 1 10.424 5.417 6 1 1.576 1.576 1 6 5.417 10.424 1"></polygon>
|
||||||
|
</svg>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="scss" scoped></style>
|
|
@ -0,0 +1,16 @@
|
||||||
|
<script setup>
|
||||||
|
const props = defineProps({
|
||||||
|
size: {
|
||||||
|
type: [Number, String],
|
||||||
|
default: 12,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<svg aria-hidden="false" :width="props.size" :height="props.size" viewBox="0 0 12 12">
|
||||||
|
<rect width="9" height="9" x="1.5" y="1.5" fill="none" stroke="currentColor"></rect>
|
||||||
|
</svg>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="scss" scoped></style>
|
|
@ -0,0 +1,16 @@
|
||||||
|
<script setup>
|
||||||
|
const props = defineProps({
|
||||||
|
size: {
|
||||||
|
type: [Number, String],
|
||||||
|
default: 12,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<svg aria-hidden="false" :width="props.size" :height="props.size" viewBox="0 0 12 12">
|
||||||
|
<rect fill="currentColor" width="10" height="1" x="1" y="6"></rect>
|
||||||
|
</svg>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="scss" scoped></style>
|
|
@ -50,14 +50,15 @@ const selectedKeys = computed(() => {
|
||||||
|
|
||||||
const data = computed(() => {
|
const data = computed(() => {
|
||||||
const dbs = get(connectionStore.databases, props.server, [])
|
const dbs = get(connectionStore.databases, props.server, [])
|
||||||
return [
|
return dbs
|
||||||
{
|
// return [
|
||||||
key: `${props.server}`,
|
// {
|
||||||
label: props.server,
|
// key: `${props.server}`,
|
||||||
type: ConnectionType.Server,
|
// label: props.server,
|
||||||
children: dbs,
|
// type: ConnectionType.Server,
|
||||||
},
|
// children: dbs,
|
||||||
]
|
// },
|
||||||
|
// ]
|
||||||
})
|
})
|
||||||
|
|
||||||
const backgroundColor = computed(() => {
|
const backgroundColor = computed(() => {
|
||||||
|
@ -368,6 +369,8 @@ const renderPrefix = ({ option }) => {
|
||||||
// render tree item label
|
// render tree item label
|
||||||
const renderLabel = ({ option }) => {
|
const renderLabel = ({ option }) => {
|
||||||
switch (option.type) {
|
switch (option.type) {
|
||||||
|
case ConnectionType.Server:
|
||||||
|
return h('b', {}, { default: () => option.label })
|
||||||
case ConnectionType.RedisDB:
|
case ConnectionType.RedisDB:
|
||||||
const { name: server, db } = option
|
const { name: server, db } = option
|
||||||
let { match: matchPattern, type: typeFilter } = connectionStore.getKeyFilter(server, db)
|
let { match: matchPattern, type: typeFilter } = connectionStore.getKeyFilter(server, db)
|
||||||
|
|
|
@ -32,7 +32,7 @@ const emit = defineEmits(['update:value'])
|
||||||
|
|
||||||
const iconSize = computed(() => Math.floor(props.width * 0.4))
|
const iconSize = computed(() => Math.floor(props.width * 0.4))
|
||||||
const renderIcon = (icon) => {
|
const renderIcon = (icon) => {
|
||||||
return () => h(NIcon, null, { default: () => h(icon, { strokeWidth: 4 }) })
|
return () => h(NIcon, null, { default: () => h(icon, { strokeWidth: 3 }) })
|
||||||
}
|
}
|
||||||
|
|
||||||
const connectionStore = useConnectionStore()
|
const connectionStore = useConnectionStore()
|
||||||
|
@ -122,7 +122,7 @@ const openGithub = () => {
|
||||||
:render-label="renderContextLabel"
|
:render-label="renderContextLabel"
|
||||||
trigger="click"
|
trigger="click"
|
||||||
@select="onSelectPreferenceMenu">
|
@select="onSelectPreferenceMenu">
|
||||||
<icon-button :icon="Config" :size="iconSize" stroke-width="4" class="nav-menu-button" />
|
<icon-button :icon="Config" :size="iconSize" :stroke-width="3" class="nav-menu-button" />
|
||||||
</n-dropdown>
|
</n-dropdown>
|
||||||
<icon-button :icon="Github" :size="iconSize" class="nav-menu-button" @click="openGithub" />
|
<icon-button :icon="Github" :size="iconSize" class="nav-menu-button" @click="openGithub" />
|
||||||
</div>
|
</div>
|
||||||
|
@ -131,7 +131,7 @@ const openGithub = () => {
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
#app-nav-menu {
|
#app-nav-menu {
|
||||||
height: 100vh;
|
//height: 100vh;
|
||||||
//border-right: v-bind('themeVars.borderColor') solid 1px;
|
//border-right: v-bind('themeVars.borderColor') solid 1px;
|
||||||
|
|
||||||
.nav-menu-item {
|
.nav-menu-item {
|
||||||
|
|
|
@ -8,6 +8,7 @@ import relativeTime from 'dayjs/plugin/relativeTime'
|
||||||
import { i18n } from '@/utils/i18n.js'
|
import { i18n } from '@/utils/i18n.js'
|
||||||
import { setupDiscreteApi } from '@/utils/discrete.js'
|
import { setupDiscreteApi } from '@/utils/discrete.js'
|
||||||
import usePreferencesStore from 'stores/preferences.js'
|
import usePreferencesStore from 'stores/preferences.js'
|
||||||
|
import { loadEnvironment } from '@/utils/platform.js'
|
||||||
|
|
||||||
dayjs.extend(duration)
|
dayjs.extend(duration)
|
||||||
dayjs.extend(relativeTime)
|
dayjs.extend(relativeTime)
|
||||||
|
@ -17,6 +18,7 @@ async function setupApp() {
|
||||||
app.use(i18n)
|
app.use(i18n)
|
||||||
app.use(createPinia())
|
app.use(createPinia())
|
||||||
|
|
||||||
|
await loadEnvironment()
|
||||||
const prefStore = usePreferencesStore()
|
const prefStore = usePreferencesStore()
|
||||||
await prefStore.loadPreferences()
|
await prefStore.loadPreferences()
|
||||||
await setupDiscreteApi()
|
await setupDiscreteApi()
|
||||||
|
|
|
@ -11,5 +11,9 @@
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.content-value {
|
||||||
|
user-select: text;
|
||||||
|
}
|
||||||
|
|
||||||
.tab-content {
|
.tab-content {
|
||||||
}
|
}
|
||||||
|
|
|
@ -96,7 +96,6 @@ body {
|
||||||
|
|
||||||
.value-wrapper {
|
.value-wrapper {
|
||||||
//border-top: v-bind('themeVars.borderColor') 1px solid;
|
//border-top: v-bind('themeVars.borderColor') 1px solid;
|
||||||
padding: 5px;
|
|
||||||
user-select: text;
|
user-select: text;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
import { Environment } from 'wailsjs/runtime/runtime.js'
|
||||||
|
|
||||||
|
let os = ''
|
||||||
|
|
||||||
|
export async function loadEnvironment() {
|
||||||
|
const env = await Environment()
|
||||||
|
os = env.platform
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isMacOS() {
|
||||||
|
return os === 'darwin'
|
||||||
|
}
|
|
@ -20,6 +20,7 @@ export const themeOverrides = {
|
||||||
tabGapSmallCard: '2px',
|
tabGapSmallCard: '2px',
|
||||||
tabGapMediumCard: '2px',
|
tabGapMediumCard: '2px',
|
||||||
tabGapLargeCard: '2px',
|
tabGapLargeCard: '2px',
|
||||||
|
tabFontWeightActive: 450,
|
||||||
},
|
},
|
||||||
Form: {
|
Form: {
|
||||||
labelFontSizeTopSmall: '12px',
|
labelFontSizeTopSmall: '12px',
|
||||||
|
|
10
main.go
10
main.go
|
@ -41,6 +41,7 @@ func main() {
|
||||||
Height: 768,
|
Height: 768,
|
||||||
MinWidth: 1024,
|
MinWidth: 1024,
|
||||||
MinHeight: 768,
|
MinHeight: 768,
|
||||||
|
Frameless: runtime.GOOS != "darwin",
|
||||||
Menu: appMenu,
|
Menu: appMenu,
|
||||||
AssetServer: &assetserver.Options{
|
AssetServer: &assetserver.Options{
|
||||||
Assets: assets,
|
Assets: assets,
|
||||||
|
@ -59,14 +60,7 @@ func main() {
|
||||||
prefSvc,
|
prefSvc,
|
||||||
},
|
},
|
||||||
Mac: &mac.Options{
|
Mac: &mac.Options{
|
||||||
TitleBar: &mac.TitleBar{
|
TitleBar: mac.TitleBarHiddenInset(),
|
||||||
TitlebarAppearsTransparent: false,
|
|
||||||
HideTitle: false,
|
|
||||||
HideTitleBar: false,
|
|
||||||
FullSizeContent: false,
|
|
||||||
UseToolbar: false,
|
|
||||||
HideToolbarSeparator: true,
|
|
||||||
},
|
|
||||||
About: &mac.AboutInfo{
|
About: &mac.AboutInfo{
|
||||||
Title: "Tiny RDM " + version,
|
Title: "Tiny RDM " + version,
|
||||||
Message: "A modern lightweight cross-platform Redis desktop client.\n\nCopyright © 2023",
|
Message: "A modern lightweight cross-platform Redis desktop client.\n\nCopyright © 2023",
|
||||||
|
|
Loading…
Reference in New Issue