mirror of
https://github.com/HiMeditator/auto-caption.git
synced 2026-03-06 19:37:30 +08:00
feat(renderer): 添加界面主题颜色功能,添加复制最新字幕选项(#13)
- 新增界面主题颜色功能,支持自定义主题颜色 - 使用 antd 滑块替代原生 input 元素 - 添加复制字幕记录功能,可选择复制最近的字幕记录
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -10,3 +10,5 @@ test.py
|
|||||||
engine/build
|
engine/build
|
||||||
engine/models
|
engine/models
|
||||||
engine/notebook
|
engine/notebook
|
||||||
|
.repomap
|
||||||
|
.virtualme
|
||||||
|
|||||||
@@ -18,9 +18,13 @@
|
|||||||
- [x] 添加字幕记录按时间降序排列选择 *2025/07/26*
|
- [x] 添加字幕记录按时间降序排列选择 *2025/07/26*
|
||||||
- [x] 重构字幕引擎 *2025/07/28*
|
- [x] 重构字幕引擎 *2025/07/28*
|
||||||
- [x] 优化前端界面提示消息 *2025/07/29*
|
- [x] 优化前端界面提示消息 *2025/07/29*
|
||||||
|
- [x] 复制字幕记录可选择只复制最近的字幕记录 *2025/08/18*
|
||||||
|
- [x] 添加颜色主题设置 *2025/08/18*
|
||||||
|
|
||||||
## 待完成
|
## 待完成
|
||||||
|
|
||||||
|
- [ ] 前端页面添加日志内容展示
|
||||||
|
- [ ] 调研更多的云端模型(火山、OpenAI、Google等)
|
||||||
- [ ] 验证 / 添加基于 sherpa-onnx 的字幕引擎
|
- [ ] 验证 / 添加基于 sherpa-onnx 的字幕引擎
|
||||||
|
|
||||||
## 后续计划
|
## 后续计划
|
||||||
|
|||||||
@@ -84,7 +84,7 @@
|
|||||||
|
|
||||||
### `control.uiTheme.change`
|
### `control.uiTheme.change`
|
||||||
|
|
||||||
**介绍:** 前端修改字界面主题,将修改同步给后端
|
**介绍:** 前端修改界面主题,将修改同步给后端
|
||||||
|
|
||||||
**发起方:** 前端控制窗口
|
**发起方:** 前端控制窗口
|
||||||
|
|
||||||
@@ -92,6 +92,16 @@
|
|||||||
|
|
||||||
**数据类型:** `UITheme`
|
**数据类型:** `UITheme`
|
||||||
|
|
||||||
|
### `control.uiColor.change`
|
||||||
|
|
||||||
|
**介绍:** 前端修改界面主题颜色,将修改同步给后端
|
||||||
|
|
||||||
|
**发起方:** 前端控制窗口
|
||||||
|
|
||||||
|
**接收方:** 后端控制窗口实例
|
||||||
|
|
||||||
|
**数据类型:** `string`
|
||||||
|
|
||||||
### `control.leftBarWidth.change`
|
### `control.leftBarWidth.change`
|
||||||
|
|
||||||
**介绍:** 前端修改边栏宽度,将修改同步给后端
|
**介绍:** 前端修改边栏宽度,将修改同步给后端
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ def resample_chunk_mono(chunk: bytes, channels: int, orig_sr: int, target_sr: in
|
|||||||
return chunk_mono_r.tobytes()
|
return chunk_mono_r.tobytes()
|
||||||
|
|
||||||
|
|
||||||
def resample_chunk_mono_np(chunk: bytes, channels: int, orig_sr: int, target_sr: int, mode="sinc_best") -> np.ndarray:
|
def resample_chunk_mono_np(chunk: bytes, channels: int, orig_sr: int, target_sr: int, mode="sinc_best", dtype=np.float32) -> np.ndarray:
|
||||||
"""
|
"""
|
||||||
将当前多通道音频数据块转换成单通道音频数据块,然后进行重采样,返回 Numpy 数组
|
将当前多通道音频数据块转换成单通道音频数据块,然后进行重采样,返回 Numpy 数组
|
||||||
|
|
||||||
@@ -65,6 +65,7 @@ def resample_chunk_mono_np(chunk: bytes, channels: int, orig_sr: int, target_sr:
|
|||||||
orig_sr: 原始采样率
|
orig_sr: 原始采样率
|
||||||
target_sr: 目标采样率
|
target_sr: 目标采样率
|
||||||
mode: 重采样模式,可选:'sinc_best' | 'sinc_medium' | 'sinc_fastest' | 'zero_order_hold' | 'linear'
|
mode: 重采样模式,可选:'sinc_best' | 'sinc_medium' | 'sinc_fastest' | 'zero_order_hold' | 'linear'
|
||||||
|
dtype: 返回 Numpy 数组的数据类型
|
||||||
|
|
||||||
Return:
|
Return:
|
||||||
单通道音频数据块
|
单通道音频数据块
|
||||||
@@ -82,7 +83,7 @@ def resample_chunk_mono_np(chunk: bytes, channels: int, orig_sr: int, target_sr:
|
|||||||
|
|
||||||
ratio = target_sr / orig_sr
|
ratio = target_sr / orig_sr
|
||||||
chunk_mono_r = samplerate.resample(chunk_mono, ratio, converter_type=mode)
|
chunk_mono_r = samplerate.resample(chunk_mono, ratio, converter_type=mode)
|
||||||
chunk_mono_r = np.round(chunk_mono_r).astype(np.int16)
|
chunk_mono_r = chunk_mono_r.astype(dtype)
|
||||||
return chunk_mono_r
|
return chunk_mono_r
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -109,6 +109,10 @@ class ControlWindow {
|
|||||||
allConfig.uiTheme = args
|
allConfig.uiTheme = args
|
||||||
})
|
})
|
||||||
|
|
||||||
|
ipcMain.on('control.uiColor.change', (_, args) => {
|
||||||
|
allConfig.uiColor = args
|
||||||
|
})
|
||||||
|
|
||||||
ipcMain.on('control.leftBarWidth.change', (_, args) => {
|
ipcMain.on('control.leftBarWidth.change', (_, args) => {
|
||||||
allConfig.leftBarWidth = args
|
allConfig.leftBarWidth = args
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -49,6 +49,7 @@ export interface FullConfig {
|
|||||||
platform: string,
|
platform: string,
|
||||||
uiLanguage: UILanguage,
|
uiLanguage: UILanguage,
|
||||||
uiTheme: UITheme,
|
uiTheme: UITheme,
|
||||||
|
uiColor: string,
|
||||||
leftBarWidth: number,
|
leftBarWidth: number,
|
||||||
styles: Styles,
|
styles: Styles,
|
||||||
controls: Controls,
|
controls: Controls,
|
||||||
|
|||||||
@@ -49,6 +49,7 @@ class AllConfig {
|
|||||||
uiLanguage: UILanguage = 'zh';
|
uiLanguage: UILanguage = 'zh';
|
||||||
leftBarWidth: number = 8;
|
leftBarWidth: number = 8;
|
||||||
uiTheme: UITheme = 'system';
|
uiTheme: UITheme = 'system';
|
||||||
|
uiColor: string = '#1677ff';
|
||||||
styles: Styles = {...defaultStyles};
|
styles: Styles = {...defaultStyles};
|
||||||
controls: Controls = {...defaultControls};
|
controls: Controls = {...defaultControls};
|
||||||
|
|
||||||
@@ -64,6 +65,7 @@ class AllConfig {
|
|||||||
if(config.captionWindowWidth) this.captionWindowWidth = config.captionWindowWidth
|
if(config.captionWindowWidth) this.captionWindowWidth = config.captionWindowWidth
|
||||||
if(config.uiLanguage) this.uiLanguage = config.uiLanguage
|
if(config.uiLanguage) this.uiLanguage = config.uiLanguage
|
||||||
if(config.uiTheme) this.uiTheme = config.uiTheme
|
if(config.uiTheme) this.uiTheme = config.uiTheme
|
||||||
|
if(config.uiColor) this.uiColor = config.uiColor
|
||||||
if(config.leftBarWidth) this.leftBarWidth = config.leftBarWidth
|
if(config.leftBarWidth) this.leftBarWidth = config.leftBarWidth
|
||||||
if(config.styles) this.setStyles(config.styles)
|
if(config.styles) this.setStyles(config.styles)
|
||||||
if(config.controls) this.setControls(config.controls)
|
if(config.controls) this.setControls(config.controls)
|
||||||
@@ -76,6 +78,7 @@ class AllConfig {
|
|||||||
captionWindowWidth: this.captionWindowWidth,
|
captionWindowWidth: this.captionWindowWidth,
|
||||||
uiLanguage: this.uiLanguage,
|
uiLanguage: this.uiLanguage,
|
||||||
uiTheme: this.uiTheme,
|
uiTheme: this.uiTheme,
|
||||||
|
uiColor: this.uiColor,
|
||||||
leftBarWidth: this.leftBarWidth,
|
leftBarWidth: this.leftBarWidth,
|
||||||
controls: this.controls,
|
controls: this.controls,
|
||||||
styles: this.styles
|
styles: this.styles
|
||||||
@@ -90,6 +93,7 @@ class AllConfig {
|
|||||||
platform: process.platform,
|
platform: process.platform,
|
||||||
uiLanguage: this.uiLanguage,
|
uiLanguage: this.uiLanguage,
|
||||||
uiTheme: this.uiTheme,
|
uiTheme: this.uiTheme,
|
||||||
|
uiColor: this.uiColor,
|
||||||
leftBarWidth: this.leftBarWidth,
|
leftBarWidth: this.leftBarWidth,
|
||||||
styles: this.styles,
|
styles: this.styles,
|
||||||
controls: this.controls,
|
controls: this.controls,
|
||||||
@@ -123,7 +127,9 @@ class AllConfig {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.controls.engineEnabled = engineEnabled
|
this.controls.engineEnabled = engineEnabled
|
||||||
Log.info('Set Controls:', this.controls)
|
let _controls = {...this.controls}
|
||||||
|
_controls.API_KEY = _controls.API_KEY.replace(/./g, '*')
|
||||||
|
Log.info('Set Controls:', _controls)
|
||||||
}
|
}
|
||||||
|
|
||||||
public sendControls(window: BrowserWindow, info = true) {
|
public sendControls(window: BrowserWindow, info = true) {
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ onMounted(() => {
|
|||||||
window.electron.ipcRenderer.invoke('both.window.mounted').then((data: FullConfig) => {
|
window.electron.ipcRenderer.invoke('both.window.mounted').then((data: FullConfig) => {
|
||||||
useGeneralSettingStore().uiLanguage = data.uiLanguage
|
useGeneralSettingStore().uiLanguage = data.uiLanguage
|
||||||
useGeneralSettingStore().uiTheme = data.uiTheme
|
useGeneralSettingStore().uiTheme = data.uiTheme
|
||||||
|
useGeneralSettingStore().uiColor = data.uiColor
|
||||||
useGeneralSettingStore().leftBarWidth = data.leftBarWidth
|
useGeneralSettingStore().leftBarWidth = data.leftBarWidth
|
||||||
useCaptionStyleStore().setStyles(data.styles)
|
useCaptionStyleStore().setStyles(data.styles)
|
||||||
useEngineControlStore().platform = data.platform
|
useEngineControlStore().platform = data.platform
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.input-area {
|
.input-area {
|
||||||
|
display: inline-block;
|
||||||
width: calc(100% - 100px);
|
width: calc(100% - 100px);
|
||||||
min-width: 100px;
|
min-width: 100px;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -55,8 +55,8 @@
|
|||||||
<div class="input-item">
|
<div class="input-item">
|
||||||
<span class="input-label">{{ $t('log.exportFormat') }}</span>
|
<span class="input-label">{{ $t('log.exportFormat') }}</span>
|
||||||
<a-radio-group v-model:value="exportFormat">
|
<a-radio-group v-model:value="exportFormat">
|
||||||
<a-radio-button value="srt">.srt</a-radio-button>
|
<a-radio-button value="srt"><code>.srt</code></a-radio-button>
|
||||||
<a-radio-button value="json">.json</a-radio-button>
|
<a-radio-button value="json"><code>.json</code></a-radio-button>
|
||||||
</a-radio-group>
|
</a-radio-group>
|
||||||
</div>
|
</div>
|
||||||
<div class="input-item">
|
<div class="input-item">
|
||||||
@@ -90,6 +90,15 @@
|
|||||||
<a-radio-button value="target">{{ $t('log.translation') }}</a-radio-button>
|
<a-radio-button value="target">{{ $t('log.translation') }}</a-radio-button>
|
||||||
</a-radio-group>
|
</a-radio-group>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="input-item">
|
||||||
|
<span class="input-label">{{ $t('log.copyNum') }}</span>
|
||||||
|
<a-radio-group v-model:value="copyNum">
|
||||||
|
<a-radio-button :value="0"><code>[:]</code></a-radio-button>
|
||||||
|
<a-radio-button :value="1"><code>[-1:]</code></a-radio-button>
|
||||||
|
<a-radio-button :value="2"><code>[-2:]</code></a-radio-button>
|
||||||
|
<a-radio-button :value="3"><code>[-3:]</code></a-radio-button>
|
||||||
|
</a-radio-group>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<a-button
|
<a-button
|
||||||
style="margin-right: 20px;"
|
style="margin-right: 20px;"
|
||||||
@@ -147,6 +156,7 @@ const exportFormat = ref('srt')
|
|||||||
const showIndex = ref(true)
|
const showIndex = ref(true)
|
||||||
const copyTime = ref(true)
|
const copyTime = ref(true)
|
||||||
const contentOption = ref('both')
|
const contentOption = ref('both')
|
||||||
|
const copyNum = ref(0)
|
||||||
|
|
||||||
const baseHH = ref<number>(0)
|
const baseHH = ref<number>(0)
|
||||||
const baseMM = ref<number>(0)
|
const baseMM = ref<number>(0)
|
||||||
@@ -255,7 +265,12 @@ function getExportData() {
|
|||||||
|
|
||||||
function copyCaptions() {
|
function copyCaptions() {
|
||||||
let content = ''
|
let content = ''
|
||||||
for(let i = 0; i < captionData.value.length; i++){
|
let start = 0
|
||||||
|
if(copyNum.value > 0) {
|
||||||
|
start = captionData.value.length - copyNum.value
|
||||||
|
if(start < 0) start = 0
|
||||||
|
}
|
||||||
|
for(let i = start; i < captionData.value.length; i++){
|
||||||
const item = captionData.value[i]
|
const item = captionData.value[i]
|
||||||
if(showIndex.value) content += `${i+1}\n`
|
if(showIndex.value) content += `${i+1}\n`
|
||||||
if(copyTime.value) content += `${item.time_s} --> ${item.time_t}\n`.replace(/\./g, ',')
|
if(copyTime.value) content += `${item.time_s} --> ${item.time_t}\n`.replace(/\./g, ',')
|
||||||
|
|||||||
@@ -34,20 +34,18 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="input-item">
|
<div class="input-item">
|
||||||
<span class="input-label">{{ $t('style.fontSize') }}</span>
|
<span class="input-label">{{ $t('style.fontSize') }}</span>
|
||||||
<a-input
|
<a-slider
|
||||||
class="input-area"
|
class="input-area"
|
||||||
type="range"
|
:min="0" :max="72"
|
||||||
min="0" max="72"
|
|
||||||
v-model:value="currentFontSize"
|
v-model:value="currentFontSize"
|
||||||
/>
|
/>
|
||||||
<div class="input-item-value">{{ currentFontSize }}px</div>
|
<div class="input-item-value">{{ currentFontSize }}px</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="input-item">
|
<div class="input-item">
|
||||||
<span class="input-label">{{ $t('style.fontWeight') }}</span>
|
<span class="input-label">{{ $t('style.fontWeight') }}</span>
|
||||||
<a-input
|
<a-slider
|
||||||
class="input-area"
|
class="input-area"
|
||||||
type="range"
|
:min="1" :max="9"
|
||||||
min="1" max="9"
|
|
||||||
v-model:value="currentFontWeight"
|
v-model:value="currentFontWeight"
|
||||||
/>
|
/>
|
||||||
<div class="input-item-value">{{ currentFontWeight*100 }}</div>
|
<div class="input-item-value">{{ currentFontWeight*100 }}</div>
|
||||||
@@ -63,11 +61,10 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="input-item">
|
<div class="input-item">
|
||||||
<span class="input-label">{{ $t('style.opacity') }}</span>
|
<span class="input-label">{{ $t('style.opacity') }}</span>
|
||||||
<a-input
|
<a-slider
|
||||||
class="input-area"
|
class="input-area"
|
||||||
type="range"
|
:min="0"
|
||||||
min="0"
|
:max="100"
|
||||||
max="100"
|
|
||||||
v-model:value="currentOpacity"
|
v-model:value="currentOpacity"
|
||||||
/>
|
/>
|
||||||
<div class="input-item-value">{{ currentOpacity }}%</div>
|
<div class="input-item-value">{{ currentOpacity }}%</div>
|
||||||
@@ -111,20 +108,18 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="input-item">
|
<div class="input-item">
|
||||||
<span class="input-label">{{ $t('style.fontSize') }}</span>
|
<span class="input-label">{{ $t('style.fontSize') }}</span>
|
||||||
<a-input
|
<a-slider
|
||||||
class="input-area"
|
class="input-area"
|
||||||
type="range"
|
:min="0" :max="72"
|
||||||
min="0" max="72"
|
|
||||||
v-model:value="currentTransFontSize"
|
v-model:value="currentTransFontSize"
|
||||||
/>
|
/>
|
||||||
<div class="input-item-value">{{ currentTransFontSize }}px</div>
|
<div class="input-item-value">{{ currentTransFontSize }}px</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="input-item">
|
<div class="input-item">
|
||||||
<span class="input-label">{{ $t('style.fontWeight') }}</span>
|
<span class="input-label">{{ $t('style.fontWeight') }}</span>
|
||||||
<a-input
|
<a-slider
|
||||||
class="input-area"
|
class="input-area"
|
||||||
type="range"
|
:min="1" :max="9"
|
||||||
min="1" max="9"
|
|
||||||
v-model:value="currentTransFontWeight"
|
v-model:value="currentTransFontWeight"
|
||||||
/>
|
/>
|
||||||
<div class="input-item-value">{{ currentTransFontWeight*100 }}</div>
|
<div class="input-item-value">{{ currentTransFontWeight*100 }}</div>
|
||||||
@@ -136,30 +131,27 @@
|
|||||||
<a-card size="small" :title="$t('style.shadow.title')">
|
<a-card size="small" :title="$t('style.shadow.title')">
|
||||||
<div class="input-item">
|
<div class="input-item">
|
||||||
<span class="input-label">{{ $t('style.shadow.offsetX') }}</span>
|
<span class="input-label">{{ $t('style.shadow.offsetX') }}</span>
|
||||||
<a-input
|
<a-slider
|
||||||
class="input-area"
|
class="input-area"
|
||||||
type="range"
|
:min="-10" :max="10"
|
||||||
min="-10" max="10"
|
|
||||||
v-model:value="currentOffsetX"
|
v-model:value="currentOffsetX"
|
||||||
/>
|
/>
|
||||||
<div class="input-item-value">{{ currentOffsetX }}px</div>
|
<div class="input-item-value">{{ currentOffsetX }}px</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="input-item">
|
<div class="input-item">
|
||||||
<span class="input-label">{{ $t('style.shadow.offsetY') }}</span>
|
<span class="input-label">{{ $t('style.shadow.offsetY') }}</span>
|
||||||
<a-input
|
<a-slider
|
||||||
class="input-area"
|
class="input-area"
|
||||||
type="range"
|
:min="-10" :max="10"
|
||||||
min="-10" max="10"
|
|
||||||
v-model:value="currentOffsetY"
|
v-model:value="currentOffsetY"
|
||||||
/>
|
/>
|
||||||
<div class="input-item-value">{{ currentOffsetY }}px</div>
|
<div class="input-item-value">{{ currentOffsetY }}px</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="input-item">
|
<div class="input-item">
|
||||||
<span class="input-label">{{ $t('style.shadow.blur') }}</span>
|
<span class="input-label">{{ $t('style.shadow.blur') }}</span>
|
||||||
<a-input
|
<a-slider
|
||||||
class="input-area"
|
class="input-area"
|
||||||
type="range"
|
:min="0" :max="12"
|
||||||
min="0" max="12"
|
|
||||||
v-model:value="currentBlur"
|
v-model:value="currentBlur"
|
||||||
/>
|
/>
|
||||||
<div class="input-item-value">{{ currentBlur }}px</div>
|
<div class="input-item-value">{{ currentBlur }}px</div>
|
||||||
@@ -315,7 +307,7 @@ function resetStyle() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
watch(changeSignal, (val) => {
|
watch(changeSignal, (val) => {
|
||||||
if(val == true) {
|
if(val === true) {
|
||||||
backStyle();
|
backStyle();
|
||||||
captionStyle.changeSignal = false;
|
captionStyle.changeSignal = false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,11 +28,23 @@
|
|||||||
</a-radio-group>
|
</a-radio-group>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="input-item">
|
||||||
|
<span class="input-label">{{ $t('general.color') }}</span>
|
||||||
|
<a-radio-group v-model:value="uiColor">
|
||||||
|
<template v-for="color in colorList" :key="color">
|
||||||
|
<a-radio-button :value="color"
|
||||||
|
:style="{
|
||||||
|
backgroundColor: color
|
||||||
|
}"
|
||||||
|
> </a-radio-button>
|
||||||
|
</template>
|
||||||
|
</a-radio-group>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="input-item">
|
<div class="input-item">
|
||||||
<span class="input-label">{{ $t('general.barWidth') }}</span>
|
<span class="input-label">{{ $t('general.barWidth') }}</span>
|
||||||
<a-input
|
<a-slider class="span-input"
|
||||||
type="range" class="span-input"
|
:min="6" :max="12" v-model:value="leftBarWidth"
|
||||||
min="6" max="12" v-model:value="leftBarWidth"
|
|
||||||
/>
|
/>
|
||||||
<div class="input-item-value">{{ (leftBarWidth * 100 / 24).toFixed(0) }}%</div>
|
<div class="input-item-value">{{ (leftBarWidth * 100 / 24).toFixed(0) }}%</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -45,15 +57,26 @@ import { storeToRefs } from 'pinia'
|
|||||||
import { useGeneralSettingStore } from '@renderer/stores/generalSetting'
|
import { useGeneralSettingStore } from '@renderer/stores/generalSetting'
|
||||||
import { InfoCircleOutlined } from '@ant-design/icons-vue';
|
import { InfoCircleOutlined } from '@ant-design/icons-vue';
|
||||||
|
|
||||||
|
const colorList = [
|
||||||
|
'#1677ff',
|
||||||
|
'#00b96b',
|
||||||
|
'#fa8c16',
|
||||||
|
'#722ed1',
|
||||||
|
'#eb2f96',
|
||||||
|
'#000000'
|
||||||
|
]
|
||||||
|
|
||||||
const generalSettingStore = useGeneralSettingStore()
|
const generalSettingStore = useGeneralSettingStore()
|
||||||
const { uiLanguage, uiTheme, leftBarWidth } = storeToRefs(generalSettingStore)
|
const { uiLanguage, uiTheme, uiColor, leftBarWidth } = storeToRefs(generalSettingStore)
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
@import url(../assets/input.css);
|
@import url(../assets/input.css);
|
||||||
|
|
||||||
.span-input {
|
.span-input {
|
||||||
|
display: inline-block;
|
||||||
width: 100px;
|
width: 100px;
|
||||||
|
margin: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.general-note {
|
.general-note {
|
||||||
|
|||||||
@@ -1,10 +1,29 @@
|
|||||||
import { theme } from 'ant-design-vue';
|
import { theme } from 'ant-design-vue';
|
||||||
|
|
||||||
export const antDesignTheme = {
|
let isLight = true
|
||||||
light: {
|
let themeColor = '#1677ff'
|
||||||
token: {}
|
|
||||||
},
|
export function setThemeColor(color: string) {
|
||||||
dark: {
|
themeColor = color
|
||||||
algorithm: theme.darkAlgorithm,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getTheme(curIsLight?: boolean) {
|
||||||
|
const lightTheme = {
|
||||||
|
token: {
|
||||||
|
colorPrimary: themeColor,
|
||||||
|
colorInfo: themeColor
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const darkTheme = {
|
||||||
|
algorithm: theme.darkAlgorithm,
|
||||||
|
token: {
|
||||||
|
colorPrimary: themeColor,
|
||||||
|
colorInfo: themeColor
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(curIsLight !== undefined){
|
||||||
|
isLight = curIsLight
|
||||||
|
}
|
||||||
|
return isLight ? lightTheme : darkTheme
|
||||||
|
}
|
||||||
@@ -37,7 +37,8 @@ export default {
|
|||||||
"theme": "Theme",
|
"theme": "Theme",
|
||||||
"light": "light",
|
"light": "light",
|
||||||
"dark": "dark",
|
"dark": "dark",
|
||||||
"system": "system"
|
"system": "system",
|
||||||
|
"color": "Color"
|
||||||
},
|
},
|
||||||
engine: {
|
engine: {
|
||||||
"title": "Caption Engine Settings",
|
"title": "Caption Engine Settings",
|
||||||
@@ -142,6 +143,8 @@ export default {
|
|||||||
"both": "Both",
|
"both": "Both",
|
||||||
"source": "Original",
|
"source": "Original",
|
||||||
"translation": "Translation",
|
"translation": "Translation",
|
||||||
|
"copyNum": "Copy Count",
|
||||||
|
"all": "All",
|
||||||
"copySuccess": "Subtitle copied to clipboard",
|
"copySuccess": "Subtitle copied to clipboard",
|
||||||
"clear": "Clear Log"
|
"clear": "Clear Log"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,7 +37,8 @@ export default {
|
|||||||
"theme": "テーマ",
|
"theme": "テーマ",
|
||||||
"light": "明るい",
|
"light": "明るい",
|
||||||
"dark": "暗い",
|
"dark": "暗い",
|
||||||
"system": "システム"
|
"system": "システム",
|
||||||
|
"color": "カラー"
|
||||||
},
|
},
|
||||||
engine: {
|
engine: {
|
||||||
"title": "字幕エンジン設定",
|
"title": "字幕エンジン設定",
|
||||||
@@ -142,6 +143,8 @@ export default {
|
|||||||
"both": "すべて",
|
"both": "すべて",
|
||||||
"source": "原文",
|
"source": "原文",
|
||||||
"translation": "翻訳",
|
"translation": "翻訳",
|
||||||
|
"copyNum": "コピー数",
|
||||||
|
"all": "すべて",
|
||||||
"copySuccess": "字幕がクリップボードにコピーされました",
|
"copySuccess": "字幕がクリップボードにコピーされました",
|
||||||
"clear": "ログをクリア"
|
"clear": "ログをクリア"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,7 +37,8 @@ export default {
|
|||||||
"theme": "主题",
|
"theme": "主题",
|
||||||
"light": "浅色",
|
"light": "浅色",
|
||||||
"dark": "深色",
|
"dark": "深色",
|
||||||
"system": "系统"
|
"system": "系统",
|
||||||
|
"color": "颜色"
|
||||||
},
|
},
|
||||||
engine: {
|
engine: {
|
||||||
"title": "字幕引擎设置",
|
"title": "字幕引擎设置",
|
||||||
@@ -142,6 +143,8 @@ export default {
|
|||||||
"both": "全部",
|
"both": "全部",
|
||||||
"source": "原文",
|
"source": "原文",
|
||||||
"translation": "翻译",
|
"translation": "翻译",
|
||||||
|
"copyNum": "复制数量",
|
||||||
|
"all": "全部",
|
||||||
"copySuccess": "字幕已复制到剪贴板",
|
"copySuccess": "字幕已复制到剪贴板",
|
||||||
"clear": "清空记录"
|
"clear": "清空记录"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,16 +3,17 @@ import { defineStore } from 'pinia'
|
|||||||
import { i18n } from '../i18n'
|
import { i18n } from '../i18n'
|
||||||
import type { UILanguage, UITheme } from '../types'
|
import type { UILanguage, UITheme } from '../types'
|
||||||
|
|
||||||
import { engines, audioTypes, antDesignTheme, breakOptions } from '../i18n'
|
import { engines, audioTypes, breakOptions, setThemeColor, getTheme } from '../i18n'
|
||||||
import { useEngineControlStore } from './engineControl'
|
import { useEngineControlStore } from './engineControl'
|
||||||
import { useCaptionStyleStore } from './captionStyle'
|
import { useCaptionStyleStore } from './captionStyle'
|
||||||
|
|
||||||
export const useGeneralSettingStore = defineStore('generalSetting', () => {
|
export const useGeneralSettingStore = defineStore('generalSetting', () => {
|
||||||
const uiLanguage = ref<UILanguage>('zh')
|
const uiLanguage = ref<UILanguage>('zh')
|
||||||
const uiTheme = ref<UITheme>('system')
|
const uiTheme = ref<UITheme>('system')
|
||||||
|
const uiColor = ref<string>('#1677ff')
|
||||||
const leftBarWidth = ref<number>(8)
|
const leftBarWidth = ref<number>(8)
|
||||||
|
|
||||||
const antdTheme = ref<Object>(antDesignTheme['light'])
|
const antdTheme = ref<Object>(getTheme())
|
||||||
|
|
||||||
window.electron.ipcRenderer.invoke('control.nativeTheme.get').then((theme) => {
|
window.electron.ipcRenderer.invoke('control.nativeTheme.get').then((theme) => {
|
||||||
if(theme === 'light') setLightTheme()
|
if(theme === 'light') setLightTheme()
|
||||||
@@ -39,6 +40,12 @@ export const useGeneralSettingStore = defineStore('generalSetting', () => {
|
|||||||
else if(newValue === 'dark') setDarkTheme()
|
else if(newValue === 'dark') setDarkTheme()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
watch(uiColor, (newValue) => {
|
||||||
|
setThemeColor(newValue)
|
||||||
|
antdTheme.value = getTheme()
|
||||||
|
window.electron.ipcRenderer.send('control.uiColor.change', newValue)
|
||||||
|
})
|
||||||
|
|
||||||
watch(leftBarWidth, (newValue) => {
|
watch(leftBarWidth, (newValue) => {
|
||||||
window.electron.ipcRenderer.send('control.leftBarWidth.change', newValue)
|
window.electron.ipcRenderer.send('control.leftBarWidth.change', newValue)
|
||||||
})
|
})
|
||||||
@@ -53,7 +60,7 @@ export const useGeneralSettingStore = defineStore('generalSetting', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
function setLightTheme(){
|
function setLightTheme(){
|
||||||
antdTheme.value = antDesignTheme.light
|
antdTheme.value = getTheme(true)
|
||||||
const root = document.documentElement
|
const root = document.documentElement
|
||||||
root.style.setProperty('--control-background', '#fff')
|
root.style.setProperty('--control-background', '#fff')
|
||||||
root.style.setProperty('--tag-color', 'rgba(0, 0, 0, 0.45)')
|
root.style.setProperty('--tag-color', 'rgba(0, 0, 0, 0.45)')
|
||||||
@@ -61,7 +68,7 @@ export const useGeneralSettingStore = defineStore('generalSetting', () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function setDarkTheme(){
|
function setDarkTheme(){
|
||||||
antdTheme.value = antDesignTheme.dark
|
antdTheme.value = getTheme(false)
|
||||||
const root = document.documentElement
|
const root = document.documentElement
|
||||||
root.style.setProperty('--control-background', '#000')
|
root.style.setProperty('--control-background', '#000')
|
||||||
root.style.setProperty('--tag-color', 'rgba(255, 255, 255, 0.45)')
|
root.style.setProperty('--tag-color', 'rgba(255, 255, 255, 0.45)')
|
||||||
@@ -71,6 +78,7 @@ export const useGeneralSettingStore = defineStore('generalSetting', () => {
|
|||||||
return {
|
return {
|
||||||
uiLanguage,
|
uiLanguage,
|
||||||
uiTheme,
|
uiTheme,
|
||||||
|
uiColor,
|
||||||
leftBarWidth,
|
leftBarWidth,
|
||||||
antdTheme
|
antdTheme
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -49,6 +49,7 @@ export interface FullConfig {
|
|||||||
platform: string,
|
platform: string,
|
||||||
uiLanguage: UILanguage,
|
uiLanguage: UILanguage,
|
||||||
uiTheme: UITheme,
|
uiTheme: UITheme,
|
||||||
|
uiColor: string,
|
||||||
leftBarWidth: number,
|
leftBarWidth: number,
|
||||||
styles: Styles,
|
styles: Styles,
|
||||||
controls: Controls,
|
controls: Controls,
|
||||||
|
|||||||
Reference in New Issue
Block a user