feat: add font style preferences support
This commit is contained in:
parent
dd88c617f9
commit
49435848ee
|
@ -1,9 +1,13 @@
|
||||||
package services
|
package services
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/adrg/sysfont"
|
||||||
|
"sort"
|
||||||
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
storage2 "tinyrdm/backend/storage"
|
storage2 "tinyrdm/backend/storage"
|
||||||
"tinyrdm/backend/types"
|
"tinyrdm/backend/types"
|
||||||
|
"tinyrdm/backend/utils/coll"
|
||||||
)
|
)
|
||||||
|
|
||||||
type preferencesService struct {
|
type preferencesService struct {
|
||||||
|
@ -49,3 +53,30 @@ func (p *preferencesService) RestorePreferences() (resp types.JSResp) {
|
||||||
resp.Success = true
|
resp.Success = true
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type FontItem struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Path string `json:"path"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *preferencesService) GetFontList() (resp types.JSResp) {
|
||||||
|
finder := sysfont.NewFinder(nil)
|
||||||
|
fontSet := coll.NewSet[string]()
|
||||||
|
var fontList []FontItem
|
||||||
|
for _, font := range finder.List() {
|
||||||
|
if len(font.Family) > 0 && !strings.HasPrefix(font.Family, ".") && fontSet.Add(font.Family) {
|
||||||
|
fontList = append(fontList, FontItem{
|
||||||
|
Name: font.Family,
|
||||||
|
Path: font.Filename,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sort.Slice(fontList, func(i, j int) bool {
|
||||||
|
return fontList[i].Name < fontList[j].Name
|
||||||
|
})
|
||||||
|
resp.Data = map[string]any{
|
||||||
|
"fonts": fontList,
|
||||||
|
}
|
||||||
|
resp.Success = true
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
|
@ -20,12 +20,13 @@ const data = reactive({
|
||||||
})
|
})
|
||||||
|
|
||||||
const tabStore = useTabStore()
|
const tabStore = useTabStore()
|
||||||
|
const prefStore = usePreferencesStore()
|
||||||
// const preferences = ref({})
|
// const preferences = ref({})
|
||||||
// provide('preferences', preferences)
|
// provide('preferences', preferences)
|
||||||
const i18n = useI18n()
|
const i18n = useI18n()
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
const prefStore = usePreferencesStore()
|
await prefStore.loadFontList()
|
||||||
await prefStore.loadPreferences()
|
await prefStore.loadPreferences()
|
||||||
await nextTick(() => {
|
await nextTick(() => {
|
||||||
i18n.locale.value = get(prefStore.general, 'language', 'en')
|
i18n.locale.value = get(prefStore.general, 'language', 'en')
|
||||||
|
@ -67,7 +68,7 @@ const dragging = computed(() => {
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<!-- app content-->
|
<!-- app content-->
|
||||||
<div id="app-container" :class="{ dragging }" class="flex-box-h">
|
<div id="app-container" :class="{ dragging }" class="flex-box-h" :style="prefStore.generalFont">
|
||||||
<nav-menu v-model:value="tabStore.nav" :width="data.navMenuWidth" />
|
<nav-menu v-model:value="tabStore.nav" :width="data.navMenuWidth" />
|
||||||
<!-- structure page-->
|
<!-- structure page-->
|
||||||
<div v-show="tabStore.nav === 'structure'" class="flex-box-h flex-item-expand">
|
<div v-show="tabStore.nav === 'structure'" class="flex-box-h flex-item-expand">
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import { reactive, ref, watch } from 'vue'
|
import { ref, watch } from 'vue'
|
||||||
import { useI18n } from 'vue-i18n'
|
import { useI18n } from 'vue-i18n'
|
||||||
import useDialog from '../../stores/dialog'
|
import useDialog from '../../stores/dialog'
|
||||||
import usePreferencesStore from '../../stores/preferences.js'
|
import usePreferencesStore from '../../stores/preferences.js'
|
||||||
|
@ -7,25 +7,30 @@ import { useMessage } from 'naive-ui'
|
||||||
|
|
||||||
const prefStore = usePreferencesStore()
|
const prefStore = usePreferencesStore()
|
||||||
|
|
||||||
const fontOption = [
|
|
||||||
{
|
|
||||||
label: 'JetBrains Mono',
|
|
||||||
value: 'JetBrains Mono',
|
|
||||||
},
|
|
||||||
]
|
|
||||||
|
|
||||||
const prevPreferences = ref({})
|
const prevPreferences = ref({})
|
||||||
const tab = ref('general')
|
const tab = ref('general')
|
||||||
const formLabelWidth = '80px'
|
const formLabelWidth = '80px'
|
||||||
const dialogStore = useDialog()
|
const dialogStore = useDialog()
|
||||||
const i18n = useI18n()
|
const i18n = useI18n()
|
||||||
const message = useMessage()
|
const message = useMessage()
|
||||||
|
const loading = ref(false)
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
() => dialogStore.preferencesDialogVisible,
|
() => dialogStore.preferencesDialogVisible,
|
||||||
(visible) => {
|
async (visible) => {
|
||||||
if (visible) {
|
if (visible) {
|
||||||
prefStore.loadPreferences()
|
try {
|
||||||
|
loading.value = true
|
||||||
|
tab.value = 'general'
|
||||||
|
await prefStore.loadFontList()
|
||||||
|
await prefStore.loadPreferences()
|
||||||
|
prevPreferences.value = {
|
||||||
|
general: prefStore.general,
|
||||||
|
editor: prefStore.editor,
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
loading.value = false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
@ -44,15 +49,10 @@ watch(
|
||||||
(lang) => (i18n.locale.value = lang)
|
(lang) => (i18n.locale.value = lang)
|
||||||
)
|
)
|
||||||
|
|
||||||
watch(
|
|
||||||
() => prefStore.general.font,
|
|
||||||
(font) => {}
|
|
||||||
)
|
|
||||||
|
|
||||||
const onClose = () => {
|
const onClose = () => {
|
||||||
dialogStore.closePreferencesDialog()
|
|
||||||
// restore to old preferences
|
// restore to old preferences
|
||||||
prefStore.restorePreferences()
|
prefStore.resetToLastPreferences()
|
||||||
|
dialogStore.closePreferencesDialog()
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
@ -84,7 +84,7 @@ const onClose = () => {
|
||||||
/>
|
/>
|
||||||
</n-form-item>
|
</n-form-item>
|
||||||
<n-form-item :label="$t('font')" required>
|
<n-form-item :label="$t('font')" required>
|
||||||
<n-select v-model:value="prefStore.general.font" :options="fontOption" filterable />
|
<n-select v-model:value="prefStore.general.font" :options="prefStore.fontOption" filterable />
|
||||||
</n-form-item>
|
</n-form-item>
|
||||||
<n-form-item :label="$t('font_size')">
|
<n-form-item :label="$t('font_size')">
|
||||||
<n-input-number v-model:value="prefStore.general.fontSize" :max="65535" :min="1" />
|
<n-input-number v-model:value="prefStore.general.fontSize" :max="65535" :min="1" />
|
||||||
|
@ -115,11 +115,11 @@ const onClose = () => {
|
||||||
label-align="right"
|
label-align="right"
|
||||||
label-placement="left"
|
label-placement="left"
|
||||||
>
|
>
|
||||||
<n-form-item :label="$t('font')" :label-width="formLabelWidth" required>
|
<n-form-item :label="$t('font')" required>
|
||||||
<n-select v-model="prefStore.editor.font" :options="fontOption" filterable />
|
<n-select v-model:value="prefStore.editor.font" :options="prefStore.fontOption" filterable />
|
||||||
</n-form-item>
|
</n-form-item>
|
||||||
<n-form-item :label="$t('font_size')" :label-width="formLabelWidth">
|
<n-form-item :label="$t('font_size')">
|
||||||
<n-input-number v-model="prefStore.editor.fontSize" :max="65535" :min="1" />
|
<n-input-number v-model:value="prefStore.editor.fontSize" :max="65535" :min="1" />
|
||||||
</n-form-item>
|
</n-form-item>
|
||||||
</n-form>
|
</n-form>
|
||||||
</n-tab-pane>
|
</n-tab-pane>
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
"success": "Success",
|
"success": "Success",
|
||||||
"warning": "Warning",
|
"warning": "Warning",
|
||||||
"save": "Save",
|
"save": "Save",
|
||||||
|
"none": "None",
|
||||||
"new_conn": "Add New Connection",
|
"new_conn": "Add New Connection",
|
||||||
"new_group": "Add New Group",
|
"new_group": "Add New Group",
|
||||||
"rename_group": "Rename Group",
|
"rename_group": "Rename Group",
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
"success": "成功",
|
"success": "成功",
|
||||||
"warning": "警告",
|
"warning": "警告",
|
||||||
"save": "保存",
|
"save": "保存",
|
||||||
|
"none": "无",
|
||||||
"new_conn": "添加新连接",
|
"new_conn": "添加新连接",
|
||||||
"new_group": "添加新分组",
|
"new_group": "添加新分组",
|
||||||
"rename_group": "重命名分组",
|
"rename_group": "重命名分组",
|
||||||
|
|
|
@ -1,9 +1,30 @@
|
||||||
import { defineStore } from 'pinia'
|
import { defineStore } from 'pinia'
|
||||||
import { lang } from '../langs/index.js'
|
import { lang } from '../langs/index.js'
|
||||||
import { camelCase, isObject, map, set, snakeCase, split } from 'lodash'
|
import { camelCase, clone, find, isEmpty, isObject, map, set, snakeCase, split } from 'lodash'
|
||||||
import { GetPreferences, RestorePreferences, SetPreferences } from '../../wailsjs/go/services/preferencesService.js'
|
import {
|
||||||
|
GetFontList,
|
||||||
|
GetPreferences,
|
||||||
|
RestorePreferences,
|
||||||
|
SetPreferences,
|
||||||
|
} from '../../wailsjs/go/services/preferencesService.js'
|
||||||
|
import { useI18n } from 'vue-i18n'
|
||||||
|
|
||||||
const usePreferencesStore = defineStore('preferences', {
|
const usePreferencesStore = defineStore('preferences', {
|
||||||
|
/**
|
||||||
|
* @typedef {Object} FontItem
|
||||||
|
* @property {string} name
|
||||||
|
* @property {string} path
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* @typedef {Object} Preferences
|
||||||
|
* @property {Object} general
|
||||||
|
* @property {Object} editor
|
||||||
|
* @property {FontItem[]} fontList
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @returns {Preferences}
|
||||||
|
*/
|
||||||
state: () => ({
|
state: () => ({
|
||||||
general: {
|
general: {
|
||||||
language: 'en',
|
language: 'en',
|
||||||
|
@ -17,6 +38,8 @@ const usePreferencesStore = defineStore('preferences', {
|
||||||
font: '',
|
font: '',
|
||||||
fontSize: 14,
|
fontSize: 14,
|
||||||
},
|
},
|
||||||
|
lastPref: {},
|
||||||
|
fontList: [],
|
||||||
}),
|
}),
|
||||||
getters: {
|
getters: {
|
||||||
getSeparator() {
|
getSeparator() {
|
||||||
|
@ -33,6 +56,34 @@ const usePreferencesStore = defineStore('preferences', {
|
||||||
label: `${value['lang_name']}`,
|
label: `${value['lang_name']}`,
|
||||||
}))
|
}))
|
||||||
},
|
},
|
||||||
|
|
||||||
|
fontOption() {
|
||||||
|
const i18n = useI18n()
|
||||||
|
const option = map(this.fontList, (font) => ({
|
||||||
|
value: font.name,
|
||||||
|
label: font.name,
|
||||||
|
path: font.path,
|
||||||
|
}))
|
||||||
|
option.splice(0, 0, {
|
||||||
|
value: '',
|
||||||
|
label: i18n.t('none'),
|
||||||
|
path: '',
|
||||||
|
})
|
||||||
|
return option
|
||||||
|
},
|
||||||
|
|
||||||
|
generalFont() {
|
||||||
|
const fontStyle = {
|
||||||
|
fontSize: this.general.fontSize + 'px',
|
||||||
|
}
|
||||||
|
if (!isEmpty(this.general.font) && this.general.font !== 'none') {
|
||||||
|
const font = find(this.fontList, { name: this.general.font })
|
||||||
|
if (font != null) {
|
||||||
|
fontStyle['fontFamily'] = `${font.name}`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return fontStyle
|
||||||
|
},
|
||||||
},
|
},
|
||||||
actions: {
|
actions: {
|
||||||
_applyPreferences(data) {
|
_applyPreferences(data) {
|
||||||
|
@ -49,10 +100,26 @@ const usePreferencesStore = defineStore('preferences', {
|
||||||
async loadPreferences() {
|
async loadPreferences() {
|
||||||
const { success, data } = await GetPreferences()
|
const { success, data } = await GetPreferences()
|
||||||
if (success) {
|
if (success) {
|
||||||
|
this.lastPref = clone(data)
|
||||||
this._applyPreferences(data)
|
this._applyPreferences(data)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* load system font list
|
||||||
|
* @returns {Promise<string[]>}
|
||||||
|
*/
|
||||||
|
async loadFontList() {
|
||||||
|
const { success, data } = await GetFontList()
|
||||||
|
if (success) {
|
||||||
|
const { fonts = [] } = data
|
||||||
|
this.fontList = fonts
|
||||||
|
} else {
|
||||||
|
this.fontList = []
|
||||||
|
}
|
||||||
|
return this.fontList
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* save preferences to local
|
* save preferences to local
|
||||||
* @returns {Promise<boolean>}
|
* @returns {Promise<boolean>}
|
||||||
|
@ -62,7 +129,8 @@ const usePreferencesStore = defineStore('preferences', {
|
||||||
const result = {}
|
const result = {}
|
||||||
for (const key in obj) {
|
for (const key in obj) {
|
||||||
if (isObject(obj[key])) {
|
if (isObject(obj[key])) {
|
||||||
// TODO: perform sub object
|
const subResult = obj2Map(`${prefix}.${snakeCase(key)}`, obj[key])
|
||||||
|
Object.assign(result, subResult)
|
||||||
} else {
|
} else {
|
||||||
result[`${prefix}.${snakeCase(key)}`] = obj[key]
|
result[`${prefix}.${snakeCase(key)}`] = obj[key]
|
||||||
}
|
}
|
||||||
|
@ -74,6 +142,16 @@ const usePreferencesStore = defineStore('preferences', {
|
||||||
return success === true
|
return success === true
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* reset to last loaded preferences
|
||||||
|
* @returns {Promise<void>}
|
||||||
|
*/
|
||||||
|
async resetToLastPreferences() {
|
||||||
|
if (!isEmpty(this.lastPref)) {
|
||||||
|
this._applyPreferences(this.lastPref)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* restore preferences to default
|
* restore preferences to default
|
||||||
* @returns {Promise<boolean>}
|
* @returns {Promise<boolean>}
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
|
||||||
|
// This file is automatically generated. DO NOT EDIT
|
||||||
|
import {types} from '../models';
|
||||||
|
|
||||||
|
export function GetFontList():Promise<types.JSResp>;
|
||||||
|
|
||||||
|
export function GetPreferences():Promise<types.JSResp>;
|
||||||
|
|
||||||
|
export function RestorePreferences():Promise<types.JSResp>;
|
||||||
|
|
||||||
|
export function SetPreferences(arg1:{[key: string]: any}):Promise<types.JSResp>;
|
|
@ -0,0 +1,19 @@
|
||||||
|
// @ts-check
|
||||||
|
// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
|
||||||
|
// This file is automatically generated. DO NOT EDIT
|
||||||
|
|
||||||
|
export function GetFontList() {
|
||||||
|
return window['go']['services']['preferencesService']['GetFontList']();
|
||||||
|
}
|
||||||
|
|
||||||
|
export function GetPreferences() {
|
||||||
|
return window['go']['services']['preferencesService']['GetPreferences']();
|
||||||
|
}
|
||||||
|
|
||||||
|
export function RestorePreferences() {
|
||||||
|
return window['go']['services']['preferencesService']['RestorePreferences']();
|
||||||
|
}
|
||||||
|
|
||||||
|
export function SetPreferences(arg1) {
|
||||||
|
return window['go']['services']['preferencesService']['SetPreferences'](arg1);
|
||||||
|
}
|
3
go.mod
3
go.mod
|
@ -3,6 +3,7 @@ module tinyrdm
|
||||||
go 1.20
|
go 1.20
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
github.com/adrg/sysfont v0.1.2
|
||||||
github.com/bytedance/sonic v1.9.2
|
github.com/bytedance/sonic v1.9.2
|
||||||
github.com/google/go-cmp v0.5.9
|
github.com/google/go-cmp v0.5.9
|
||||||
github.com/redis/go-redis/v9 v9.0.5
|
github.com/redis/go-redis/v9 v9.0.5
|
||||||
|
@ -12,6 +13,8 @@ require (
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
github.com/adrg/strutil v0.2.2 // indirect
|
||||||
|
github.com/adrg/xdg v0.3.0 // indirect
|
||||||
github.com/bep/debounce v1.2.1 // indirect
|
github.com/bep/debounce v1.2.1 // indirect
|
||||||
github.com/cespare/xxhash/v2 v2.2.0 // indirect
|
github.com/cespare/xxhash/v2 v2.2.0 // indirect
|
||||||
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect
|
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect
|
||||||
|
|
7
go.sum
7
go.sum
|
@ -1,3 +1,9 @@
|
||||||
|
github.com/adrg/strutil v0.2.2 h1:XSd9+o2xaOon2oRum0JymNT+f0nfLiAiDzGOcjcIsMI=
|
||||||
|
github.com/adrg/strutil v0.2.2/go.mod h1:EF2fjOFlGTepljfI+FzgTG13oXthR7ZAil9/aginnNQ=
|
||||||
|
github.com/adrg/sysfont v0.1.2 h1:MSU3KREM4RhsQ+7QgH7wPEPTgAgBIz0Hw6Nd4u7QgjE=
|
||||||
|
github.com/adrg/sysfont v0.1.2/go.mod h1:6d3l7/BSjX9VaeXWJt9fcrftFaD/t7l11xgSywCPZGk=
|
||||||
|
github.com/adrg/xdg v0.3.0 h1:BO+k4wFj0IoTolBF1Apn8oZrX3LQrEbBA8+/9vyW9J4=
|
||||||
|
github.com/adrg/xdg v0.3.0/go.mod h1:7I2hH/IT30IsupOpKZ5ue7/qNi3CoKzD6tL3HwpaRMQ=
|
||||||
github.com/bep/debounce v1.2.1 h1:v67fRdBA9UQu2NhLFXrSg0Brw7CexQekrBwDMM8bzeY=
|
github.com/bep/debounce v1.2.1 h1:v67fRdBA9UQu2NhLFXrSg0Brw7CexQekrBwDMM8bzeY=
|
||||||
github.com/bep/debounce v1.2.1/go.mod h1:H8yggRPQKLUhUoqrJC1bO2xNya7vanpDl7xR3ISbCJ0=
|
github.com/bep/debounce v1.2.1/go.mod h1:H8yggRPQKLUhUoqrJC1bO2xNya7vanpDl7xR3ISbCJ0=
|
||||||
github.com/bsm/ginkgo/v2 v2.7.0 h1:ItPMPH90RbmZJt5GtkcNvIRuGEdwlBItdNVoyzaNQao=
|
github.com/bsm/ginkgo/v2 v2.7.0 h1:ItPMPH90RbmZJt5GtkcNvIRuGEdwlBItdNVoyzaNQao=
|
||||||
|
@ -64,6 +70,7 @@ github.com/samber/lo v1.38.1/go.mod h1:+m/ZKRl6ClXCE2Lgf3MsQlWfh4bn1bz6CXEOxnEXn
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||||
|
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||||
|
|
Loading…
Reference in New Issue