refactor: 分离终端配置.

This commit is contained in:
lijiahangmax
2024-01-11 00:43:18 +08:00
parent b5cdd0b362
commit 7f9a97180e
21 changed files with 225 additions and 423 deletions

View File

@@ -31,7 +31,6 @@ import com.orion.ops.module.asset.enums.HostSshAuthTypeEnum;
import com.orion.ops.module.asset.handler.host.config.model.HostSshConfigModel;
import com.orion.ops.module.asset.handler.host.extra.model.HostSshExtraModel;
import com.orion.ops.module.asset.service.HostConfigService;
import com.orion.ops.module.asset.service.HostConnectLogService;
import com.orion.ops.module.asset.service.HostExtraService;
import com.orion.ops.module.asset.service.HostTerminalService;
import com.orion.ops.module.infra.api.DataPermissionApi;
@@ -57,7 +56,7 @@ import java.util.Optional;
@Service
public class HostTerminalServiceImpl implements HostTerminalService {
private static final String TERMINAL_PATH = "/template/theme/terminal.theme.json";
private static final String TERMINAL_PATH = "/theme/terminal.theme.json";
@Resource
private HostConfigService hostConfigService;
@@ -68,9 +67,6 @@ public class HostTerminalServiceImpl implements HostTerminalService {
@Resource
private AssetAuthorizedDataServiceImpl assetAuthorizedDataService;
@Resource
private HostConnectLogService hostConnectLogService;
@Resource
private HostDAO hostDAO;
@@ -89,6 +85,7 @@ public class HostTerminalServiceImpl implements HostTerminalService {
@Override
public JSONArray getTerminalThemes() {
try (InputStream in = HostTerminalService.class.getResourceAsStream(TERMINAL_PATH)) {
Valid.notNull(in, ErrorMessage.CONFIG_ABSENT);
byte[] bytes = StreamReaders.readAllBytes(in);
return JSONArray.parseArray(new String(bytes));
} catch (Exception e) {

View File

@@ -126,7 +126,7 @@
"background": "#212121",
"foreground": "#F8F8F2",
"cursor": "#ECEFF4",
"selectionBackground": "#F8F8F2",
"selectionBackground": "#44475A",
"black": "#21222C",
"red": "#FF5555",
"green": "#50FA7B",
@@ -286,5 +286,53 @@
"brightCyan": "#3AD5CE",
"brightWhite": "#EEEEEC"
}
},
{
"name": "Calamity",
"dark": true,
"schema": {
"background": "#2F2833",
"foreground": "#D5CED9",
"cursor": "#D5CED9",
"selectionBackground": "#7E6C88",
"black": "#2F2833",
"red": "#FC644D",
"green": "#A5F69C",
"yellow": "#E9D7A5",
"blue": "#3B79C7",
"cyan": "#74D3DE",
"white": "#D5CED9",
"brightBlack": "#7E6C88",
"brightRed": "#FC644D",
"brightGreen": "#A5F69C",
"brightYellow": "#E9D7A5",
"brightBlue": "#3B79C7",
"brightCyan": "#74D3DE",
"brightWhite": "#FFFFFF"
}
},
{
"name": "Tomorrow",
"dark": false,
"schema": {
"background": "#FFFFFF",
"foreground": "#4D4D4C",
"cursor": "#4D4D4C",
"selectionBackground": "#D6D6D6",
"black": "#000000",
"red": "#C82829",
"green": "#718C00",
"yellow": "#EAB700",
"blue": "#4271AE",
"cyan": "#3E999F",
"white": "#FFFFFF",
"brightBlack": "#000000",
"brightRed": "#C82829",
"brightGreen": "#718C00",
"brightYellow": "#EAB700",
"brightBlue": "#4271AE",
"brightCyan": "#3E999F",
"brightWhite": "#FFFFFF"
}
}
]
]

View File

@@ -16,13 +16,13 @@ import java.util.List;
import java.util.stream.Collectors;
/**
* 终端主题拉取 __META__
* 终端主题生成 __META__
*
* @author Jiahang Li
* @version 1.0.0
* @since 2023/12/7 10:52
*/
public class TerminalThemeFetcher {
public class TerminalThemeGenerator {
public static void main(String[] args) {
List<File> files = Files1.listFiles("D:\\idea-project\\iTerm2-Color-Schemes\\vhs");
@@ -33,7 +33,8 @@ public class TerminalThemeFetcher {
"Dracula", "Dracula+",
"Apple System Colors", "Builtin Tango Light",
"Duotone Dark", "BlulocoLight",
"Chester", "CLRS"
"Chester", "CLRS",
"Calamity", "Tomorrow"
);
// 颜色大写
ValueFilter colorFilter = (Object object, String name, Object value) -> {

View File

@@ -13,6 +13,7 @@ import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import java.util.List;
import java.util.Map;
/**
@@ -50,8 +51,10 @@ public class PreferenceController {
@GetMapping("/get")
@Operation(summary = "查询用户偏好")
@Parameter(name = "type", description = "type", required = true)
public Map<String, Object> getPreference(@RequestParam("type") String type) {
return preferenceService.getPreferenceByType(type);
@Parameter(name = "items", description = "items")
public Map<String, Object> getPreference(@RequestParam("type") String type,
@RequestParam(name = "items", required = false) List<String> items) {
return preferenceService.getPreferenceByType(type, items);
}
}

View File

@@ -4,6 +4,7 @@ import com.orion.ops.module.infra.entity.request.preference.PreferenceUpdatePart
import com.orion.ops.module.infra.entity.request.preference.PreferenceUpdateRequest;
import com.orion.ops.module.infra.enums.PreferenceTypeEnum;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Future;
@@ -34,10 +35,11 @@ public interface PreferenceService {
/**
* 查询用户偏好
*
* @param type type
* @param type type
* @param items items
* @return rows
*/
Map<String, Object> getPreferenceByType(String type);
Map<String, Object> getPreferenceByType(String type, List<String> items);
/**
* 获取用户偏好

View File

@@ -3,6 +3,7 @@ package com.orion.ops.module.infra.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.orion.lang.function.Functions;
import com.orion.lang.utils.Refs;
import com.orion.lang.utils.collect.Lists;
import com.orion.lang.utils.collect.Maps;
import com.orion.ops.framework.common.utils.Valid;
import com.orion.ops.framework.redis.core.utils.RedisMaps;
@@ -125,10 +126,17 @@ public class PreferenceServiceImpl implements PreferenceService {
}
@Override
public Map<String, Object> getPreferenceByType(String type) {
public Map<String, Object> getPreferenceByType(String type, List<String> items) {
Long userId = SecurityUtils.getLoginUserId();
PreferenceTypeEnum typeEnum = Valid.valid(PreferenceTypeEnum::of, type);
return this.getPreferenceByCache(userId, typeEnum);
// 查询缓存
Map<String, Object> preference = this.getPreferenceByCache(userId, typeEnum);
if (Lists.isEmpty(items)) {
return preference;
}
Map<String, Object> partial = Maps.newMap();
items.forEach(s -> partial.put(s, preference.get(s)));
return partial;
}
@Override

View File

@@ -1,4 +1,5 @@
import axios from 'axios';
import qs from 'query-string';
type PreferenceType = 'SYSTEM' | 'TERMINAL'
@@ -36,7 +37,15 @@ export function updatePreferencePartial(request: PreferenceUpdatePartialRequest)
/**
* 查询用户偏好
*/
export function getPreference<T>(type: PreferenceType) {
return axios.get<T>('/infra/preference/get', { params: { type } });
export function getPreference<T>(type: PreferenceType, items: Array<string> | undefined = undefined) {
return axios.get<T>('/infra/preference/get', {
params: {
type,
items
},
paramsSerializer: params => {
return qs.stringify(params, { arrayFormat: 'comma' });
}
});
}

View File

@@ -1,35 +1,27 @@
import type { TerminalDisplaySetting, TerminalPreference, TerminalState, TerminalThemeSchema } from './types';
import type { TerminalDisplaySetting, TerminalPreference, TerminalState } from './types';
import type { TerminalTheme } from '@/api/asset/host-terminal';
import { getTerminalThemes } from '@/api/asset/host-terminal';
import { defineStore } from 'pinia';
import { getPreference, updatePreference } from '@/api/user/preference';
import { Message } from '@arco-design/web-vue';
import { useDark } from '@vueuse/core';
import TerminalTabManager from '@/views/host/terminal/handler/terminal-tab-manager';
import TerminalSessionManager from '@/views/host/terminal/handler/terminal-session-manager';
import type { TerminalTheme } from '@/api/asset/host-terminal';
import { getTerminalThemes } from '@/api/asset/host-terminal';
// 暗色主题
export const DarkTheme = {
DARK: 'dark',
LIGHT: 'light',
AUTO: 'auto'
// 偏好项
export const PreferenceItem = {
// 新建连接类型
NEW_CONNECTION_TYPE: 'newConnectionType',
// 终端主题
THEME: 'theme',
// 显示设置
DISPLAY_SETTING: 'displaySetting',
};
export default defineStore('terminal', {
state: (): TerminalState => ({
isDarkTheme: useDark({
selector: 'body',
attribute: 'terminal-theme',
valueDark: DarkTheme.DARK,
valueLight: DarkTheme.LIGHT,
initialValue: DarkTheme.DARK as any,
storageKey: null
}),
preference: {
darkTheme: 'auto',
newConnectionType: 'group',
displaySetting: {} as TerminalDisplaySetting,
themeSchema: {} as TerminalThemeSchema,
theme: {} as TerminalTheme
},
tabManager: new TerminalTabManager(),
@@ -46,6 +38,8 @@ export default defineStore('terminal', {
if (!data.theme) {
const { data: themes } = await getTerminalThemes();
data.theme = themes[0];
// 更新默认主题偏好
await this.updateTerminalPreference(PreferenceItem.THEME, data.theme);
}
this.preference = data;
} catch (e) {
@@ -53,51 +47,11 @@ export default defineStore('terminal', {
}
},
// 修改暗色主题
// FIXME 删除 terminalDarkTheme
async changeDarkTheme(darkTheme: string) {
this.preference.darkTheme = darkTheme;
if (darkTheme === DarkTheme.DARK) {
// 暗色
this.isDarkTheme = true;
} else if (darkTheme === DarkTheme.LIGHT) {
// 亮色
this.isDarkTheme = false;
} else if (darkTheme === DarkTheme.AUTO) {
// 自动配色
this.isDarkTheme = this.preference.themeSchema.dark;
}
// 同步配置
await this.updateTerminalPreference('darkTheme', darkTheme);
},
// 修改显示配置
async changeDisplaySetting(displaySetting: TerminalDisplaySetting) {
this.preference.displaySetting = displaySetting;
// 同步配置
await this.updateTerminalPreference('displaySetting', displaySetting);
},
// 选择终端主题
async changeThemeSchema(themeSchema: TerminalThemeSchema) {
this.preference.themeSchema = themeSchema;
// 切换主题配色
if (this.preference.darkTheme === DarkTheme.AUTO) {
this.isDarkTheme = themeSchema.dark;
}
// 同步配置
await this.updateTerminalPreference('themeSchema', themeSchema);
},
// 切换新建连接类型
async changeNewConnectionType(newConnectionType: string) {
this.preference.newConnectionType = newConnectionType;
// 同步配置
await this.updateTerminalPreference('newConnectionType', newConnectionType);
},
// 更新终端偏好
async updateTerminalPreference(item: string, value: any) {
async updateTerminalPreference(item: string, value: any, setLocal = false) {
if (setLocal) {
this.preference[item as keyof TerminalPreference] = value;
}
try {
// 修改配置
await updatePreference({

View File

@@ -1,9 +1,7 @@
import type { Ref } from 'vue';
import type { ITerminalSessionManager, ITerminalTabManager } from '@/views/host/terminal/types/terminal.type';
import type { TerminalTheme } from '@/api/asset/host-terminal';
export interface TerminalState {
isDarkTheme: Ref<boolean>;
preference: TerminalPreference;
tabManager: ITerminalTabManager;
sessionManager: ITerminalSessionManager;
@@ -11,11 +9,9 @@ export interface TerminalState {
// 终端配置
export interface TerminalPreference {
darkTheme: string;
newConnectionType: string;
displaySetting: TerminalDisplaySetting;
theme: TerminalTheme;
themeSchema: TerminalThemeSchema;
}
// 显示设置
@@ -29,34 +25,3 @@ export interface TerminalDisplaySetting {
cursorBlink?: boolean;
}
// 终端主题
export interface TerminalThemeSchema {
name: string;
dark: boolean;
background: string;
foreground: string;
cursor: string;
cursorAccent?: string;
selectionBackground?: string;
selectionForeground?: string;
selectionInactiveBackground?: string;
black: string;
red: string;
green: string;
yellow: string;
blue: string;
magenta: string;
cyan: string;
white: string;
brightBlack: string;
brightRed: string;
brightGreen: string;
brightYellow: string;
brightBlue: string;
brightMagenta: string;
brightCyan: string;
brightWhite: string;
[key: string]: unknown;
}

View File

@@ -9,8 +9,8 @@
<template v-if="tab.type === TabType.SETTING">
<!-- 新建连接 -->
<new-connection-view v-if="tab.key === InnerTabs.NEW_CONNECTION.key" />
<!-- 显示设置 -->
<terminal-view-setting v-else-if="tab.key === InnerTabs.VIEW_SETTING.key" />
<!-- 主题设置 -->
<terminal-theme-setting v-else-if="tab.key === InnerTabs.THEME_SETTING.key" />
</template>
<!-- 终端 -->
<template v-else-if="tab.type === TabType.TERMINAL">
@@ -31,10 +31,10 @@
import { TabType, InnerTabs } from '../../types/terminal.const';
import { useTerminalStore } from '@/store';
import { watch } from 'vue';
import TerminalViewSetting from '../view-setting/terminal-view-setting.vue';
import TerminalThemeSetting from '../view-setting/terminal-theme-setting.vue';
import NewConnectionView from '../new-connection/new-connection-view.vue';
import TerminalView from '../xterm/terminal-view.vue';
const { tabManager, sessionManager } = useTerminalStore();
// 监听 tab 修改

View File

@@ -29,7 +29,7 @@
const topActions: Array<SidebarAction> = [
{
icon: 'icon-plus',
content: '新建连接',
content: InnerTabs.NEW_CONNECTION.title,
click: () => tabManager.openTab(InnerTabs.NEW_CONNECTION)
},
];
@@ -38,13 +38,19 @@
const bottomActions: Array<SidebarAction> = [
{
icon: 'icon-command',
content: '快捷键设置',
content: InnerTabs.SHORTCUT_SETTING.title,
visible: false,
click: () => tabManager.openTab(InnerTabs.SHORTCUT_SETTING)
},
{
icon: 'icon-tool',
content: InnerTabs.TOOL_SETTING.title,
click: () => tabManager.openTab(InnerTabs.TOOL_SETTING)
},
{
icon: 'icon-palette',
content: '外观设置',
click: () => tabManager.openTab(InnerTabs.VIEW_SETTING)
content: InnerTabs.THEME_SETTING.title,
click: () => tabManager.openTab(InnerTabs.THEME_SETTING)
},
];

View File

@@ -10,7 +10,7 @@
type="button"
class="usn"
:options="toRadioOptions(newConnectionTypeKey)"
@change="s => changeNewConnectionType(s as string)" />
@change="s => updateTerminalPreference(PreferenceItem.NEW_CONNECTION_TYPE, s as string, true)" />
<!-- 过滤 -->
<a-auto-complete v-model="filterValue"
class="host-filter"
@@ -82,6 +82,7 @@
import { NewConnectionType, newConnectionTypeKey } from '../../types/terminal.const';
import useLoading from '@/hooks/loading';
import { useAppStore, useDictStore, useTerminalStore } from '@/store';
import { PreferenceItem } from '@/store/modules/terminal';
import { dataColor } from '@/utils';
import { tagColor } from '@/views/asset/host-list/types/const';
import { getLatestConnectHostId } from '@/api/asset/host-connect-log';
@@ -89,7 +90,7 @@
const { loading, setLoading } = useLoading();
const { toRadioOptions } = useDictStore();
const { preference, changeNewConnectionType } = useTerminalStore();
const { preference, updateTerminalPreference } = useTerminalStore();
const newConnectionType = ref(preference.newConnectionType || NewConnectionType.GROUP);
const filterValue = ref('');

View File

@@ -79,8 +79,8 @@
<div class="terminal-example">
<span class="terminal-example-label">预览效果</span>
<div class="terminal-example-wrapper"
:style="{ background: preference.themeSchema?.background }">
<terminal-example :theme="preference.themeSchema"
:style="{ background: preference.theme.schema.background }">
<terminal-example :schema="preference.theme.schema"
ref="previewTerminal" />
</div>
</div>
@@ -100,16 +100,17 @@
import { useDictStore, useTerminalStore } from '@/store';
import { fontFamilyKey, fontSizeKey, fontWeightKey, fontFamilySuffix, cursorStyleKey } from '../../types/terminal.const';
import { labelFilter } from '@/types/form';
import { PreferenceItem } from '@/store/modules/terminal';
import TerminalExample from '../view-setting/terminal-example.vue';
const { toOptions, toRadioOptions } = useDictStore();
const { preference, changeDisplaySetting } = useTerminalStore();
const { preference, updateTerminalPreference } = useTerminalStore();
const previewTerminal = ref();
const formModel = ref<TerminalDisplaySetting>({ ...preference.displaySetting });
// 监听主题变化 动态修改预览样式
watch(() => preference.themeSchema, (v) => {
watch(() => preference.theme, (v) => {
if (!v) {
return;
}
@@ -135,7 +136,7 @@
}
});
// 同步
changeDisplaySetting(formModel.value);
updateTerminalPreference(PreferenceItem.DISPLAY_SETTING, formModel.value);
// 聚焦
previewTerminal.value.term.focus();
}, { deep: true });

View File

@@ -9,12 +9,12 @@
</script>
<script lang="ts" setup>
import type { TerminalThemeSchema } from '@/store/modules/terminal/types';
import type { TerminalThemeSchema } from '@/api/asset/host-terminal';
import { Terminal } from 'xterm';
import { onMounted, onUnmounted, ref } from 'vue';
const props = defineProps<{
theme: TerminalThemeSchema | Record<string, any>
schema: TerminalThemeSchema | Record<string, any>
}>();
const terminal = ref();
@@ -22,7 +22,7 @@
onMounted(() => {
term.value = new Terminal({
theme: props.theme,
theme: { ...props.schema, cursor: props.schema.background },
cols: 42,
rows: 6,
fontSize: 15,
@@ -33,9 +33,8 @@
'[root@OrionServer usr]#\r\n' +
'dr-xr-xr-x. 2 root root bin\r\n' +
'dr-xr-xr-x. 2 root root sbin\r\n' +
'drwxr-xr-x. 89 root root share\r\n' +
'drwxr-xr-x. 4 root root src\r\n' +
'lrwxrwxrwx. 1 root root tmp -> ../var/tmp'
'lrwxrwxrwx. 1 root root tmp -> ../var/tmp '
);
});

View File

@@ -5,41 +5,42 @@
<h3 class="terminal-setting-subtitle">
主题设置
</h3>
<!-- 暗色选择 -->
<a-radio-group v-model="preference.darkTheme"
class="usn"
size="mini"
type="button"
:options="toRadioOptions(darkThemeKey)"
@change="s => changeDarkTheme(s as string)">
</a-radio-group>
</div>
<!-- 加载中 -->
<a-skeleton v-if="loading"
class="skeleton-wrapper"
:animation="true">
<a-skeleton-line :rows="8" />
</a-skeleton>
<!-- 内容区域 -->
<div class="terminal-setting-body terminal-theme-container">
<div v-else class="terminal-setting-body terminal-theme-container">
<!-- 提示 -->
<a-alert class="mb16">选择后会立刻保存, 刷新页面生效</a-alert>
<!-- 终端主题 -->
<div class="theme-row"
v-for="rowIndex in ThemeSchema.length / 2"
v-for="rowIndex in themes.length / 2"
:key="rowIndex">
<a-card v-for="(theme, colIndex) in [ThemeSchema[(rowIndex - 1) * 2], ThemeSchema[(rowIndex - 1) * 2 + 1]]"
<a-card v-for="(theme, colIndex) in [themes[(rowIndex - 1) * 2], themes[(rowIndex - 1) * 2 + 1]]"
:key="theme.name"
class="terminal-theme-card simple-card"
:class="{
'terminal-theme-card-check': theme.name === preference.themeSchema.name
'terminal-theme-card-check': theme.name === currentThemeName
}"
:title="theme.name"
:style="{
background: theme.background,
background: theme.schema.background,
marginRight: colIndex === 0 ? '16px' : 0
}"
:header-style="{
color: theme.dark ? 'rgba(255, 255, 255, .8)' : 'rgba(0, 0, 0, .8)',
userSelect: 'none'
}"
@click="changeThemeSchema(theme)">
@click="selectTheme(theme)">
<!-- 样例 -->
<terminal-example :theme="{ ...theme, cursor: theme.background }" />
<terminal-example :schema="theme.schema" />
<!-- 选中按钮 -->
<icon-check class="theme-check-icon"
v-show="theme.name === preference.themeSchema.name" />
v-show="theme.name === currentThemeName" />
</a-card>
</div>
</div>
@@ -53,13 +54,48 @@
</script>
<script lang="ts" setup>
import { darkThemeKey } from '../../types/terminal.const';
import ThemeSchema from '../../types/terminal.theme';
import { useDictStore, useTerminalStore } from '@/store';
import type { TerminalTheme } from '@/api/asset/host-terminal';
import { useTerminalStore } from '@/store';
import { PreferenceItem } from '@/store/modules/terminal';
import { onMounted, ref } from 'vue';
import { getTerminalThemes } from '@/api/asset/host-terminal';
import TerminalExample from './terminal-example.vue';
import { getPreference } from '@/api/user/preference';
import useLoading from '@/hooks/loading';
const { changeThemeSchema, changeDarkTheme, preference } = useTerminalStore();
const { toRadioOptions } = useDictStore();
const { updateTerminalPreference } = useTerminalStore();
const { loading, setLoading } = useLoading();
const currentThemeName = ref();
const themes = ref<Array<TerminalTheme>>([]);
// 选择主题
const selectTheme = async (theme: TerminalTheme) => {
currentThemeName.value = theme.name;
await updateTerminalPreference(PreferenceItem.THEME, theme);
};
// 加载用户主题
onMounted(async () => {
try {
const { data } = await getPreference<Record<string, any>>('TERMINAL', [PreferenceItem.THEME]);
currentThemeName.value = data[PreferenceItem.THEME]?.name;
} catch (e) {
}
});
// 加载主题列表
onMounted(async () => {
setLoading(true);
try {
// 加载全部主题
const { data } = await getTerminalThemes();
themes.value = data;
} catch (e) {
} finally {
setLoading(false);
}
});
</script>

View File

@@ -0,0 +1,25 @@
<template>
<div class="terminal-setting-container">
<div class="terminal-setting-wrapper">
<!-- 主标题 -->
<h2 class="terminal-setting-title">主题设置</h2>
<!-- 主题设置 -->
<terminal-theme-block />
</div>
</div>
</template>
<script lang="ts">
export default {
name: 'TerminalThemeSetting'
};
</script>
<script lang="ts" setup>
import TerminalThemeBlock from './terminal-theme-block.vue';
</script>
<style lang="less" scoped>
</style>

View File

@@ -5,8 +5,6 @@
<h2 class="terminal-setting-title">外观设置</h2>
<!-- 显示设置 -->
<terminal-display-block />
<!-- 主题设置 -->
<terminal-theme-block />
</div>
</div>
</template>
@@ -19,7 +17,6 @@
<script lang="ts" setup>
import TerminalDisplayBlock from './terminal-display-block.vue';
import TerminalThemeBlock from './terminal-theme-block.vue';
</script>

View File

@@ -37,7 +37,7 @@
<!-- 终端 -->
<div class="terminal-wrapper"
:style="{
background: themeSchema.background
background: preference.theme.schema.background
}">
<div class="terminal-inst" ref="terminalRef" />
</div>
@@ -45,7 +45,7 @@
<shell-editor-modal ref="modal"
:closable="false"
:body-style="{ padding: '16px 16px 16px 0' }"
:dark="themeSchema.dark"
:dark="preference.theme.dark"
cancel-text="关闭"
@ok="writeCommand(modal.getValue())"
@cancel="focus" />
@@ -64,9 +64,9 @@
import { computed, onMounted, onUnmounted, ref } from 'vue';
import { useDictStore, useTerminalStore } from '@/store';
import useCopy from '@/hooks/copy';
import IconActions from '@/views/host/terminal/components/layout/icon-actions.vue';
import { connectStatusKey } from '../../types/terminal.const';
import { adjustColor } from '@/utils';
import IconActions from '../layout/icon-actions.vue';
import ShellEditorModal from '@/components/view/shell-editor/shell-editor-modal.vue';
const props = defineProps<{
@@ -79,7 +79,6 @@
const modal = ref();
const commandInput = ref();
const themeSchema = preference.themeSchema;
const terminalRef = ref();
const session = ref<ITerminalSession>();

View File

@@ -47,7 +47,7 @@ export default class TerminalSession implements ITerminalSession {
// 初始化实例
this.inst = new Terminal({
...(preference.displaySetting as any),
theme: preference.themeSchema,
theme: preference.theme.schema,
fastScrollModifier: 'shift',
fontFamily: preference.displaySetting.fontFamily + fontFamilySuffix,
});

View File

@@ -29,9 +29,14 @@ export const InnerTabs = {
title: '快捷键设置',
type: TabType.SETTING
},
VIEW_SETTING: {
key: 'viewSetting',
title: '外观设置',
TOOL_SETTING: {
key: 'toolSetting',
title: '终端设置',
type: TabType.SETTING
},
THEME_SETTING: {
key: 'themeSetting',
title: '主题设置',
type: TabType.SETTING
},
};
@@ -83,9 +88,6 @@ export const openSshModalKey = Symbol();
// 字体后缀 兜底
export const fontFamilySuffix = ',courier-new, courier, monospace';
// 终端暗色模式 字典项
export const darkThemeKey = 'terminalDarkTheme';
// 终端字体样式
export const fontFamilyKey = 'terminalFontFamily';
@@ -109,7 +111,7 @@ export const connectStatusKey = 'terminalConnectStatus';
// 加载的字典值
export const dictKeys = [
darkThemeKey, fontFamilyKey,
fontFamilyKey,
fontSizeKey, fontWeightKey,
cursorStyleKey, newConnectionTypeKey,
extraSshAuthTypeKey, connectStatusKey

View File

@@ -1,251 +0,0 @@
import type { TerminalThemeSchema } from '@/store/modules/terminal/types';
// 默认配色
export const DEFAULT_SCHEMA = {
name: 'Frappe',
dark: true,
background: '#303446',
foreground: '#C6D0F5',
cursor: '#F2D5CF',
cursorAccent: '#232634',
selectionBackground: '#C9DDF0',
selectionForeground: '#303446',
// selectionInactiveBackground: 'rgba(98, 104, 128, 0.30078125)',
black: '#51576D',
red: '#E78284',
green: '#A6D189',
yellow: '#E5C890',
blue: '#8CAAEE',
magenta: '#F4B8E4',
cyan: '#81C8BE',
white: '#B5BFE2',
brightBlack: '#626880',
brightRed: '#E78284',
brightGreen: '#A6D189',
brightYellow: '#E5C890',
brightBlue: '#8CAAEE',
brightMagenta: '#F4B8E4',
brightCyan: '#81C8BE',
brightWhite: '#A5ADCE'
};
export default [
DEFAULT_SCHEMA,
{
name: 'Latte',
dark: false,
background: '#EFF1F5',
foreground: '#4C4F69',
cursor: '#DC8A78',
cursorAccent: '#EFF1F5',
selectionBackground: '#6C6F85',
selectionForeground: '#EFF1F5',
// selectionInactiveBackground: 'rgba(172, 176, 190, 0.30078125)',
black: '#5C5F77',
red: '#D20F39',
green: '#40A02B',
yellow: '#DF8E1D',
blue: '#1E66F5',
magenta: '#EA76CB',
cyan: '#179299',
white: '#ACB0BE',
brightBlack: '#6C6F85',
brightRed: '#D20F39',
brightGreen: '#40A02B',
brightYellow: '#DF8E1D',
brightBlue: '#1E66F5',
brightMagenta: '#EA76CB',
brightCyan: '#179299',
brightWhite: '#BCC0CC'
},
{
name: 'Macchiato',
dark: true,
background: '#24273A',
foreground: '#CAD3F5',
cursor: '#F4DBD6',
cursorAccent: '#181926',
selectionBackground: '#A5ADCB',
selectionForeground: '#24273A',
// selectionInactiveBackground: 'rgba(91, 96, 120, 0.30078125)',
black: '#494D64',
red: '#ED8796',
green: '#A6DA95',
yellow: '#EED49F',
blue: '#8AADF4',
magenta: '#F5BDE6',
cyan: '#8BD5CA',
white: '#B8C0E0',
brightBlack: '#5B6078',
brightRed: '#ED8796',
brightGreen: '#A6DA95',
brightYellow: '#EED49F',
brightBlue: '#8AADF4',
brightMagenta: '#F5BDE6',
brightCyan: '#8BD5CA',
brightWhite: '#A5ADCB'
},
{
name: 'Mocha',
dark: true,
background: '#1E1E2E',
foreground: '#CDD6F4',
cursor: '#F5E0DC',
cursorAccent: '#11111B',
selectionBackground: '#A6ADC8',
selectionForeground: '#1E1E2E',
// selectionInactiveBackground: 'rgba(88, 91, 112, 0.30078125)',
black: '#45475A',
red: '#F38BA8',
green: '#A6E3A1',
yellow: '#F9E2AF',
blue: '#89B4FA',
magenta: '#F5C2E7',
cyan: '#94E2D5',
white: '#BAC2DE',
brightBlack: '#585B70',
brightRed: '#F38BA8',
brightGreen: '#A6E3A1',
brightYellow: '#F9E2AF',
brightBlue: '#89B4FA',
brightMagenta: '#F5C2E7',
brightCyan: '#94E2D5',
brightWhite: '#A6ADC8'
},
{
name: 'Atom One Light',
dark: false,
background: '#F9F9F9',
foreground: '#2A2C33',
cursor: '#BBBBBB',
selectionBackground: '#EDEDED',
black: '#000000',
red: '#DE3E35',
green: '#3F953A',
yellow: '#D2B67C',
blue: '#2F5AF3',
cyan: '#3F953A',
white: '#BBBBBB',
brightBlack: '#000000',
brightRed: '#DE3E35',
brightGreen: '#3F953A',
brightYellow: '#D2B67C',
brightBlue: '#2F5AF3',
brightCyan: '#3F953A',
brightWhite: '#FFFFFF'
},
{
name: 'One Half Dark',
dark: true,
background: '#282C34',
foreground: '#DCDFE4',
cursor: '#A3B3CC',
selectionBackground: '#474E5D',
black: '#282C34',
red: '#E06C75',
green: '#98C379',
yellow: '#E5C07B',
blue: '#61AFEF',
cyan: '#56B6C2',
white: '#DCDFE4',
brightBlack: '#282C34',
brightRed: '#E06C75',
brightGreen: '#98C379',
brightYellow: '#E5C07B',
brightBlue: '#61AFEF',
brightCyan: '#56B6C2',
brightWhite: '#DCDFE4'
},
{
name: 'Dracula',
dark: true,
background: '#282A36',
foreground: '#F8F8F2',
cursor: '#F8F8F2',
cursorAccent: '#282A36',
selectionBackground: '#50FA7B',
selectionForeground: '#44475A',
black: '#21222C',
red: '#FF5555',
green: '#50FA7B',
yellow: '#F1FA8C',
blue: '#BD93F9',
magenta: '#FF79C6',
cyan: '#8BE9FD',
white: '#F8F8F2',
brightBlack: '#6272A4',
brightRed: '#FF6E6E',
brightGreen: '#69FF94',
brightYellow: '#FFFFA5',
brightBlue: '#D6ACFF',
brightMagenta: '#FF92DF',
brightCyan: '#A4FFFF',
brightWhite: '#FFFFFF'
},
{
name: 'Solarized Light',
dark: false,
background: '#FDF6E3',
foreground: '#657B83',
cursor: '#657B83',
selectionBackground: '#E6DDC3',
black: '#073642',
red: '#DC322F',
green: '#859900',
yellow: '#B58900',
blue: '#268BD2',
cyan: '#2AA198',
white: '#EEE8D5',
brightBlack: '#002B36',
brightRed: '#CB4B16',
brightGreen: '#586E75',
brightYellow: '#657B83',
brightBlue: '#839496',
brightCyan: '#93A1A1',
brightWhite: '#FDF6E3'
},
{
name: 'Material Design',
dark: true,
background: '#1D262A',
foreground: '#E7EBED',
cursor: '#EAEAEA',
selectionBackground: '#4E6A78',
black: '#435B67',
red: '#FC3841',
green: '#5CF19E',
yellow: '#FED032',
blue: '#37B6FF',
cyan: '#59FFD1',
white: '#FFFFFF',
brightBlack: '#A1B0B8',
brightRed: '#FC746D',
brightGreen: '#ADF7BE',
brightYellow: '#FEE16C',
brightBlue: '#70CFFF',
brightCyan: '#9AFFE6',
brightWhite: '#FFFFFF'
},
{
name: 'Duotone Dark',
dark: true,
background: '#1F1D27',
foreground: '#B7A1FF',
cursor: '#FF9839',
selectionBackground: '#353147',
black: '#1F1D27',
red: '#D9393E',
green: '#2DCD73',
yellow: '#D9B76E',
blue: '#FFC284',
cyan: '#2488FF',
white: '#B7A1FF',
brightBlack: '#353147',
brightRed: '#D9393E',
brightGreen: '#2DCD73',
brightYellow: '#D9B76E',
brightBlue: '#FFC284',
brightCyan: '#2488FF',
brightWhite: '#EAE5FF'
}
] as Array<TerminalThemeSchema>;