feat. 终端主题设置.
This commit is contained in:
@@ -0,0 +1,167 @@
|
||||
package com.orion.ops.module.asset.meta;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.alibaba.fastjson.annotation.JSONField;
|
||||
import com.alibaba.fastjson.serializer.ValueFilter;
|
||||
import com.orion.lang.utils.Colors;
|
||||
import com.orion.lang.utils.awt.Clipboards;
|
||||
import com.orion.lang.utils.collect.Lists;
|
||||
import com.orion.lang.utils.io.FileReaders;
|
||||
import com.orion.lang.utils.io.Files1;
|
||||
import com.orion.lang.utils.reflect.Fields;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.File;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 终端主题拉取 __META__
|
||||
*
|
||||
* @author Jiahang Li
|
||||
* @version 1.0.0
|
||||
* @since 2023/12/7 10:52
|
||||
*/
|
||||
public class TerminalThemeFetcher {
|
||||
|
||||
public static void main(String[] args) {
|
||||
List<File> files = Files1.listFiles("D:\\idea-project\\iTerm2-Color-Schemes\\vhs");
|
||||
// 过滤的 theme
|
||||
List<String> schemaFilter = new ArrayList<>();
|
||||
// List<String> schemaFilter = Lists.of("oneHalf", "material", "github", "iTerm2", "JetBrains");
|
||||
// List<String> schemaFilter = Lists.of("catppuccin", "3024", "OneHalfDark", "OneHalfLight", "MaterialDesignColors", "MaterialOcean", "Solarized Light");
|
||||
// 颜色大写
|
||||
ValueFilter colorFilter = (Object object, String name, Object value) -> {
|
||||
if (value instanceof String && value.toString().contains("#")) {
|
||||
return ((String) value).toUpperCase();
|
||||
} else {
|
||||
return value;
|
||||
}
|
||||
};
|
||||
// 转换
|
||||
List<TerminalTheme> arr = files.stream()
|
||||
.filter(f -> Lists.isEmpty(schemaFilter) || schemaFilter.stream()
|
||||
.anyMatch(s -> f.getName().toLowerCase().contains(s.toLowerCase())))
|
||||
.limit(200)
|
||||
.map(f -> {
|
||||
JSONObject schema = JSONObject.parseObject(new String(FileReaders.readAllBytes(f)));
|
||||
schema.put("dark", isDarkColor(schema.getString("background")));
|
||||
schema.put("selectionBackground", schema.getString("selection"));
|
||||
// 转为对象
|
||||
return JSON.parseObject(JSON.toJSONString(schema, colorFilter), TerminalTheme.class);
|
||||
}).collect(Collectors.toList());
|
||||
|
||||
// 打印 json
|
||||
String json = JSON.toJSONString(arr, colorFilter);
|
||||
System.out.println("\n\n" + json);
|
||||
// 转为 jsCode
|
||||
List<String> formatter = Fields.getFields(TerminalTheme.class)
|
||||
.stream()
|
||||
.map(Field::getName)
|
||||
.collect(Collectors.toList());
|
||||
for (String s : formatter) {
|
||||
json = json.replaceAll("\"" + s + "\"", s);
|
||||
}
|
||||
Clipboards.setString(json);
|
||||
System.out.println("\n\njsCode 已复制到剪切板");
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO kit
|
||||
* 是否为深色
|
||||
* 亮度值 < 128 ? 深色 : 128
|
||||
*
|
||||
* @param hex hex
|
||||
* @return 是否为深色
|
||||
*/
|
||||
public static boolean isDarkColor(String hex) {
|
||||
int[] rgb = Colors.toRgbColor(hex);
|
||||
return (rgb[0] * 299 + rgb[1] * 587 + rgb[2] * 114) / 1000 < 128;
|
||||
}
|
||||
|
||||
//
|
||||
/*
|
||||
var term = new Terminal();
|
||||
var doc = document.getElementById('themes');
|
||||
for (let t of themes) {
|
||||
var span = document.createElement('span');
|
||||
span.innerHTML = t.name;
|
||||
span.style.display = 'inline-block';
|
||||
span.style.padding = '4px 8px';
|
||||
span.style.margin = '4px';
|
||||
span.style.border = '1px solid green';
|
||||
if(t.dark) {
|
||||
span.style.background = '#000';
|
||||
span.style.color = '#FFF';
|
||||
}
|
||||
span.addEventListener('click', function() {
|
||||
term.setOption('theme', t);
|
||||
term.reset();
|
||||
for (let i = 0; i < 9; i++) {
|
||||
term.write('[' + (30 + i) + 'm');
|
||||
term.write(' ' + i + 'orion ops pro');
|
||||
term.write('[0m\r\n');
|
||||
}
|
||||
for (let i = 0; i < 9; i++) {
|
||||
term.write('[' + (90 + i) + 'm');
|
||||
term.write(' ' + i + 'orion ops pro');
|
||||
term.write('[0m\r\n');
|
||||
}
|
||||
});
|
||||
doc.append(span);
|
||||
}
|
||||
term.open(document.getElementById('terminal'));
|
||||
*/
|
||||
|
||||
@Data
|
||||
public static class TerminalTheme {
|
||||
@JSONField(ordinal = 0)
|
||||
private String name;
|
||||
@JSONField(ordinal = 1)
|
||||
private Boolean dark;
|
||||
@JSONField(ordinal = 2)
|
||||
private String background;
|
||||
@JSONField(ordinal = 3)
|
||||
private String foreground;
|
||||
@JSONField(ordinal = 4)
|
||||
private String cursor;
|
||||
@JSONField(ordinal = 5)
|
||||
private String selectionBackground;
|
||||
@JSONField(ordinal = 6)
|
||||
private String black;
|
||||
@JSONField(ordinal = 7)
|
||||
private String red;
|
||||
@JSONField(ordinal = 8)
|
||||
private String green;
|
||||
@JSONField(ordinal = 9)
|
||||
private String yellow;
|
||||
@JSONField(ordinal = 10)
|
||||
private String blue;
|
||||
@JSONField(ordinal = 11)
|
||||
private String magenta;
|
||||
@JSONField(ordinal = 12)
|
||||
private String cyan;
|
||||
@JSONField(ordinal = 13)
|
||||
private String white;
|
||||
@JSONField(ordinal = 14)
|
||||
private String brightBlack;
|
||||
@JSONField(ordinal = 15)
|
||||
private String brightRed;
|
||||
@JSONField(ordinal = 16)
|
||||
private String brightGreen;
|
||||
@JSONField(ordinal = 17)
|
||||
private String brightYellow;
|
||||
@JSONField(ordinal = 18)
|
||||
private String brightBlue;
|
||||
@JSONField(ordinal = 19)
|
||||
private String brightMagenta;
|
||||
@JSONField(ordinal = 20)
|
||||
private String brightCyan;
|
||||
@JSONField(ordinal = 21)
|
||||
private String brightWhite;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -33,6 +33,12 @@
|
||||
"@dangojs/a-query-header": "^0.0.31",
|
||||
"@sanqi377/arco-vue-icon-picker": "^1.0.7",
|
||||
"@vueuse/core": "^9.3.0",
|
||||
"@xterm/addon-canvas": "0.6.0-beta.14",
|
||||
"@xterm/addon-fit": "0.9.0-beta.14",
|
||||
"@xterm/addon-search": "0.14.0-beta.14",
|
||||
"@xterm/addon-web-links": "0.10.0-beta.1",
|
||||
"@xterm/addon-webgl": "0.17.0-beta.14",
|
||||
"@xterm/xterm": "5.4.0-beta.14",
|
||||
"axios": "^0.24.0",
|
||||
"dayjs": "^1.11.5",
|
||||
"echarts": "^5.4.0",
|
||||
|
||||
11303
orion-ops-ui/pnpm-lock.yaml
generated
11303
orion-ops-ui/pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
||||
import axios from 'axios';
|
||||
|
||||
type Preference = 'SYSTEM'
|
||||
type Preference = 'SYSTEM' | 'TERMINAL'
|
||||
|
||||
/**
|
||||
* 用户偏好更新请求
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// 亮色主题配色常量
|
||||
body[terminal-theme='light'] {
|
||||
body {
|
||||
--color-bg-header: #232323;
|
||||
--color-bg-sidebar: #F2F3F5;
|
||||
--color-bg-content: #FEFEFE;
|
||||
@@ -7,6 +7,9 @@ body[terminal-theme='light'] {
|
||||
--color-sidebar-icon-bg: #D7D8DB;
|
||||
--color-sidebar-tooltip-text: rgba(255, 255, 255, .9);
|
||||
--color-sidebar-tooltip-bg: rgb(29, 33, 41);
|
||||
--color-content-text-1: rgba(0, 0, 0, .8);
|
||||
--color-content-text-2: rgba(0, 0, 0, .85);
|
||||
--color-content-text-3: rgba(0, 0, 0, .95);
|
||||
}
|
||||
|
||||
// 暗色主题配色常量
|
||||
@@ -18,6 +21,9 @@ body[terminal-theme='dark'] {
|
||||
--color-sidebar-icon-bg: #43444C;
|
||||
--color-sidebar-tooltip-text: rgba(255, 255, 255, .9);
|
||||
--color-sidebar-tooltip-bg: var(--color-sidebar-icon-bg);
|
||||
--color-content-text-1: rgba(255, 255, 255, .8);
|
||||
--color-content-text-2: rgba(255, 255, 255, .85);
|
||||
--color-content-text-3: rgba(255, 255, 255, .95);
|
||||
}
|
||||
|
||||
// 布局常量
|
||||
@@ -29,42 +35,160 @@ body[terminal-theme='dark'] {
|
||||
--sidebar-icon-font-size: 22px;
|
||||
|
||||
--color-bg-header-icon-1: #434343;
|
||||
--color-header-tabs-sp: #4B4B4B;
|
||||
--color-header-tabs-bg: var(--color-bg-header);
|
||||
--color-header-tabs-bg-hover: #434343;
|
||||
--color-header-text-1: rgba(255, 255, 255, .9);
|
||||
--color-header-text-2: rgba(255, 255, 255, .75);
|
||||
--color-gradient-start: rgba(46, 46, 46, 1);
|
||||
--color-gradient-end: rgba(46, 46, 46, 0);
|
||||
--color-gradient-hover-start: rgba(88, 88, 88, 1);
|
||||
--color-gradient-hover-end: rgba(88, 88, 88, 0);
|
||||
--color-header-text-1: rgba(255, 255, 255, .75);
|
||||
--color-header-text-2: rgba(255, 255, 255, .9);
|
||||
--color-gradient-start: rgba(38, 38, 38, 1);
|
||||
--color-gradient-end: rgba(38, 38, 38, 0);
|
||||
}
|
||||
|
||||
// 侧栏图标 wrapper
|
||||
// arco 亮色配色
|
||||
body .host-layout {
|
||||
--color-white: #ffffff;
|
||||
--color-black: #000000;
|
||||
--color-border: rgb(var(--gray-3));
|
||||
--color-bg-popup: var(--color-bg-5);
|
||||
--color-bg-1: #fff;
|
||||
--color-bg-2: #fff;
|
||||
--color-bg-3: #fff;
|
||||
--color-bg-4: #fff;
|
||||
--color-bg-5: #fff;
|
||||
--color-bg-white: #fff;
|
||||
--color-neutral-1: rgb(var(--gray-1));
|
||||
--color-neutral-2: rgb(var(--gray-2));
|
||||
--color-neutral-3: rgb(var(--gray-3));
|
||||
--color-neutral-4: rgb(var(--gray-4));
|
||||
--color-neutral-5: rgb(var(--gray-5));
|
||||
--color-neutral-6: rgb(var(--gray-6));
|
||||
--color-neutral-7: rgb(var(--gray-7));
|
||||
--color-neutral-8: rgb(var(--gray-8));
|
||||
--color-neutral-9: rgb(var(--gray-9));
|
||||
--color-neutral-10: rgb(var(--gray-10));
|
||||
--color-text-1: var(--color-neutral-10);
|
||||
--color-text-2: var(--color-neutral-8);
|
||||
--color-text-3: var(--color-neutral-6);
|
||||
--color-text-4: var(--color-neutral-4);
|
||||
--color-border-1: var(--color-neutral-2);
|
||||
--color-border-2: var(--color-neutral-3);
|
||||
--color-border-3: var(--color-neutral-4);
|
||||
--color-border-4: var(--color-neutral-6);
|
||||
--color-fill-1: var(--color-neutral-1);
|
||||
--color-fill-2: var(--color-neutral-2);
|
||||
--color-fill-3: var(--color-neutral-3);
|
||||
--color-fill-4: var(--color-neutral-4);
|
||||
--color-primary-light-1: rgb(var(--primary-1));
|
||||
--color-primary-light-2: rgb(var(--primary-2));
|
||||
--color-primary-light-3: rgb(var(--primary-3));
|
||||
--color-primary-light-4: rgb(var(--primary-4));
|
||||
--color-link-light-1: rgb(var(--link-1));
|
||||
--color-link-light-2: rgb(var(--link-2));
|
||||
--color-link-light-3: rgb(var(--link-3));
|
||||
--color-link-light-4: rgb(var(--link-4));
|
||||
--color-secondary: var(--color-neutral-2);
|
||||
--color-secondary-hover: var(--color-neutral-3);
|
||||
--color-secondary-active: var(--color-neutral-4);
|
||||
--color-secondary-disabled: var(--color-neutral-1);
|
||||
--color-danger-light-1: rgb(var(--danger-1));
|
||||
--color-danger-light-2: rgb(var(--danger-2));
|
||||
--color-danger-light-3: rgb(var(--danger-3));
|
||||
--color-danger-light-4: rgb(var(--danger-4));
|
||||
--color-success-light-1: rgb(var(--success-1));
|
||||
--color-success-light-2: rgb(var(--success-2));
|
||||
--color-success-light-3: rgb(var(--success-3));
|
||||
--color-success-light-4: rgb(var(--success-4));
|
||||
--color-warning-light-1: rgb(var(--warning-1));
|
||||
--color-warning-light-2: rgb(var(--warning-2));
|
||||
--color-warning-light-3: rgb(var(--warning-3));
|
||||
--color-warning-light-4: rgb(var(--warning-4));
|
||||
--border-radius-none: 0;
|
||||
--border-radius-small: 2px;
|
||||
--border-radius-medium: 4px;
|
||||
--border-radius-large: 8px;
|
||||
--border-radius-circle: 50%;
|
||||
--color-tooltip-bg: rgb(var(--gray-10));
|
||||
--color-spin-layer-bg: rgba(255, 255, 255, 0.6);
|
||||
--color-menu-dark-bg: #232324;
|
||||
--color-menu-light-bg: #ffffff;
|
||||
--color-menu-dark-hover: rgba(255, 255, 255, 0.04);
|
||||
--color-mask-bg: rgba(29, 33, 41, 0.6);
|
||||
}
|
||||
|
||||
// arco 暗色配色
|
||||
body[terminal-theme='dark'] .host-layout {
|
||||
--color-white: rgba(255, 255, 255, 0.9);
|
||||
--color-black: #000000;
|
||||
--color-border: #333335;
|
||||
--color-bg-1: #17171a;
|
||||
--color-bg-2: #232324;
|
||||
--color-bg-3: #2a2a2b;
|
||||
--color-bg-4: #313132;
|
||||
--color-bg-5: #373739;
|
||||
--color-bg-white: #f6f6f6;
|
||||
--color-text-1: rgba(255, 255, 255, 0.9);
|
||||
--color-text-2: rgba(255, 255, 255, 0.7);
|
||||
--color-text-3: rgba(255, 255, 255, 0.5);
|
||||
--color-text-4: rgba(255, 255, 255, 0.3);
|
||||
--color-fill-1: rgba(255, 255, 255, 0.04);
|
||||
--color-fill-2: rgba(255, 255, 255, 0.08);
|
||||
--color-fill-3: rgba(255, 255, 255, 0.12);
|
||||
--color-fill-4: rgba(255, 255, 255, 0.16);
|
||||
--color-primary-light-1: rgba(var(--primary-6), 0.2);
|
||||
--color-primary-light-2: rgba(var(--primary-6), 0.35);
|
||||
--color-primary-light-3: rgba(var(--primary-6), 0.5);
|
||||
--color-primary-light-4: rgba(var(--primary-6), 0.65);
|
||||
--color-secondary: rgba(var(--gray-9), 0.08);
|
||||
--color-secondary-hover: rgba(var(--gray-8), 0.16);
|
||||
--color-secondary-active: rgba(var(--gray-7), 0.24);
|
||||
--color-secondary-disabled: rgba(var(--gray-9), 0.08);
|
||||
--color-danger-light-1: rgba(var(--danger-6), 0.2);
|
||||
--color-danger-light-2: rgba(var(--danger-6), 0.35);
|
||||
--color-danger-light-3: rgba(var(--danger-6), 0.5);
|
||||
--color-danger-light-4: rgba(var(--danger-6), 0.65);
|
||||
--color-success-light-1: rgb(var(--success-6), 0.2);
|
||||
--color-success-light-2: rgb(var(--success-6), 0.35);
|
||||
--color-success-light-3: rgb(var(--success-6), 0.5);
|
||||
--color-success-light-4: rgb(var(--success-6), 0.65);
|
||||
--color-warning-light-1: rgb(var(--warning-6), 0.2);
|
||||
--color-warning-light-2: rgb(var(--warning-6), 0.35);
|
||||
--color-warning-light-3: rgb(var(--warning-6), 0.5);
|
||||
--color-warning-light-4: rgb(var(--warning-6), 0.65);
|
||||
--color-link-light-1: rgb(var(--link-6), 0.2);
|
||||
--color-link-light-2: rgb(var(--link-6), 0.35);
|
||||
--color-link-light-3: rgb(var(--link-6), 0.5);
|
||||
--color-link-light-4: rgb(var(--link-6), 0.65);
|
||||
--color-tooltip-bg: #373739;
|
||||
--color-spin-layer-bg: rgba(51, 51, 51, 0.6);
|
||||
--color-menu-dark-bg: #232324;
|
||||
--color-menu-light-bg: #232324;
|
||||
--color-menu-dark-hover: var(--color-fill-2);
|
||||
--color-mask-bg: rgba(23, 23, 26, 0.6);
|
||||
}
|
||||
|
||||
// 侧栏图标
|
||||
.terminal-sidebar-icon-wrapper {
|
||||
width: var(--sidebar-icon-wrapper-size);
|
||||
height: var(--sidebar-icon-wrapper-size);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
// 侧栏图标
|
||||
.terminal-sidebar-icon {
|
||||
width: var(--sidebar-icon-size);
|
||||
height: var(--sidebar-icon-size);
|
||||
font-size: var(--sidebar-icon-font-size);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: var(--color-sidebar-icon);
|
||||
border-radius: 4px;
|
||||
border: 1px solid transparent;
|
||||
transition: 0.1s cubic-bezier(0, 0, 1, 1);
|
||||
cursor: pointer;
|
||||
.terminal-sidebar-icon {
|
||||
width: var(--sidebar-icon-size);
|
||||
height: var(--sidebar-icon-size);
|
||||
font-size: var(--sidebar-icon-font-size);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: var(--color-sidebar-icon);
|
||||
border-radius: 4px;
|
||||
border: 1px solid transparent;
|
||||
transition: 0.1s cubic-bezier(0, 0, 1, 1);
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
background: var(--color-sidebar-icon-bg);
|
||||
&:hover {
|
||||
background: var(--color-sidebar-icon-bg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -78,3 +202,28 @@ body[terminal-theme='dark'] {
|
||||
.terminal-tooltip-arrow {
|
||||
display: none;
|
||||
}
|
||||
|
||||
// 终端设置容器
|
||||
@setting-container-width: 1180px;
|
||||
.terminal-setting-container {
|
||||
padding: 32px 16px;
|
||||
width: @setting-container-width;
|
||||
margin: auto;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.terminal-setting-title {
|
||||
margin: 0 0 24px 0;
|
||||
color: var(--color-content-text-3);
|
||||
}
|
||||
|
||||
.terminal-setting-block {
|
||||
color: var(--color-content-text-2);
|
||||
margin-bottom: 18px;
|
||||
}
|
||||
|
||||
.terminal-setting-subtitle {
|
||||
margin: 0 0 16px 0;
|
||||
color: var(--color-content-text-3);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,94 @@
|
||||
<template>
|
||||
<div class="terminal-content">
|
||||
<!-- 内容 tabs -->
|
||||
<a-tabs v-model:active-key="activeKey">
|
||||
<a-tab-pane v-for="tab in tabs"
|
||||
:key="tab.key"
|
||||
:title="tab.title">
|
||||
<!-- 设置 -->
|
||||
<template v-if="tab.type === TabType.SETTING">
|
||||
<!-- 主题设置 -->
|
||||
<terminal-theme-setting v-if="tab.key === InnerTabs.THEME_SETTING.key"
|
||||
@emitter="dispatchEmitter" />
|
||||
<span v-else>
|
||||
{{ tab.title }}
|
||||
</span>
|
||||
</template>
|
||||
<!-- 终端 -->
|
||||
<template v-else-if="tab.type === TabType.TERMINAL">
|
||||
终端 {{ tab.key }}
|
||||
<div v-for="i in 1000" :key="i">
|
||||
{{ tab.title }}
|
||||
</div>
|
||||
</template>
|
||||
</a-tab-pane>
|
||||
</a-tabs>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
export default {
|
||||
name: 'TerminalContent'
|
||||
};
|
||||
</script>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import type { PropType } from 'vue';
|
||||
import type { TabItem } from '../../types/terminal.type';
|
||||
import { computed } from 'vue';
|
||||
import { TabType, InnerTabs } from '../../types/terminal.type';
|
||||
import TerminalThemeSetting from '../terminal-theme-setting.vue';
|
||||
import useEmitter from '@/hooks/emitter';
|
||||
|
||||
const props = defineProps({
|
||||
modelValue: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
tabs: {
|
||||
type: Array as PropType<Array<TabItem>>,
|
||||
required: true
|
||||
}
|
||||
});
|
||||
|
||||
const emits = defineEmits(['changeDarkTheme']);
|
||||
|
||||
const { dispatchEmitter } = useEmitter(emits);
|
||||
|
||||
const activeKey = computed<String>({
|
||||
get() {
|
||||
return props.modelValue;
|
||||
},
|
||||
set() {
|
||||
}
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.terminal-content {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: relative;
|
||||
|
||||
:deep(.arco-tabs) {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
.arco-tabs-nav {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.arco-tabs-content {
|
||||
padding: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: auto;
|
||||
|
||||
&::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -6,7 +6,16 @@
|
||||
</div>
|
||||
<!-- 左侧 tabs -->
|
||||
<div class="terminal-header-tabs">
|
||||
<slot />
|
||||
<a-tabs v-model:active-key="activeKey"
|
||||
:editable="true"
|
||||
:hide-content="true"
|
||||
:auto-switch="true"
|
||||
@tab-click="e => emits('clickTab', e)"
|
||||
@delete="e => emits('deleteTab', e)">
|
||||
<a-tab-pane v-for="tab in tabs"
|
||||
:key="tab.key"
|
||||
:title="tab.title" />
|
||||
</a-tabs>
|
||||
</div>
|
||||
<!-- 右侧操作 -->
|
||||
<div class="terminal-header-right">
|
||||
@@ -37,13 +46,26 @@
|
||||
</script>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import type { SidebarAction } from '../../types/terminal.type';
|
||||
import type { SidebarAction, TabItem } from '../../types/terminal.type';
|
||||
import type { PropType } from 'vue';
|
||||
import { useFullscreen } from '@vueuse/core';
|
||||
import { computed } from 'vue';
|
||||
import IconActions from '@/views/host-ops/terminal/components/layout/icon-actions.vue';
|
||||
import IconActions from '../layout/icon-actions.vue';
|
||||
|
||||
const props = defineProps({
|
||||
modelValue: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
tabs: {
|
||||
type: Array as PropType<Array<TabItem>>,
|
||||
required: true
|
||||
}
|
||||
});
|
||||
|
||||
const emits = defineEmits(['update:modelValue', 'clickTab', 'deleteTab', 'split', 'share']);
|
||||
|
||||
const { isFullscreen, toggle: toggleFullScreen } = useFullscreen();
|
||||
const emits = defineEmits(['split', 'share']);
|
||||
|
||||
// 顶部操作
|
||||
const actions = computed<Array<SidebarAction>>(() => [
|
||||
@@ -66,6 +88,19 @@
|
||||
},
|
||||
]);
|
||||
|
||||
const activeKey = computed<String>({
|
||||
get() {
|
||||
return props.modelValue;
|
||||
},
|
||||
set(e) {
|
||||
if (e) {
|
||||
emits('update:modelValue', e);
|
||||
} else {
|
||||
emits('update:modelValue', null);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
@@ -77,7 +112,7 @@
|
||||
|
||||
.terminal-header {
|
||||
height: 100%;
|
||||
color: var(--color-header-text-1);
|
||||
color: var(--color-header-text-2);
|
||||
display: flex;
|
||||
user-select: none;
|
||||
|
||||
@@ -118,11 +153,11 @@
|
||||
}
|
||||
}
|
||||
|
||||
&-icon {
|
||||
color: var(--color-header-text-1);
|
||||
:deep(&-icon) {
|
||||
color: var(--color-header-text-2) !important;
|
||||
|
||||
&:hover {
|
||||
background: var(--color-bg-header-icon-1);
|
||||
background: var(--color-bg-header-icon-1) !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -143,7 +178,7 @@
|
||||
}
|
||||
|
||||
&-button .arco-icon-hover:hover {
|
||||
color: var(--color-header-text-1);
|
||||
color: var(--color-header-text-2);
|
||||
|
||||
&::before {
|
||||
background: var(--color-bg-header-icon-1);
|
||||
@@ -159,16 +194,12 @@
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
color: var(--color-header-text-2);
|
||||
color: var(--color-header-text-1);
|
||||
background: var(--color-header-tabs-bg);
|
||||
position: relative;
|
||||
|
||||
&:not(:first-child) {
|
||||
border-left: 1px solid var(--color-header-tabs-sp);
|
||||
}
|
||||
|
||||
&:hover {
|
||||
color: var(--color-header-text-1);
|
||||
color: var(--color-header-text-2);
|
||||
transition: .2s;
|
||||
}
|
||||
|
||||
@@ -212,7 +243,7 @@
|
||||
right: 0;
|
||||
z-index: 4;
|
||||
display: none;
|
||||
color: var(--color-header-text-1);
|
||||
color: var(--color-header-text-2);
|
||||
|
||||
&:hover {
|
||||
transition: .2s;
|
||||
@@ -227,14 +258,14 @@
|
||||
|
||||
:deep(.arco-tabs-tab-active) {
|
||||
background: var(--color-header-tabs-bg-hover);
|
||||
color: var(--color-header-text-1) !important;
|
||||
color: var(--color-header-text-2) !important;
|
||||
|
||||
.arco-tabs-tab-title {
|
||||
background: var(--color-header-tabs-bg-hover);
|
||||
}
|
||||
|
||||
&:hover::after {
|
||||
background: linear-gradient(270deg, var(--color-gradient-hover-start) 45%, var(--color-gradient-hover-end) 120%);
|
||||
background: linear-gradient(270deg, var(--color-gradient-start) 45%, var(--color-gradient-end) 120%);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -18,17 +18,18 @@
|
||||
</script>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { SidebarAction } from '../../types/terminal.type';
|
||||
import type { SidebarAction, } from '../../types/terminal.type';
|
||||
import { InnerTabs } from '../../types/terminal.type';
|
||||
import IconActions from './icon-actions.vue';
|
||||
|
||||
const emits = defineEmits(['openAdd', 'copyAddress', 'openShortcutSetting', 'openViewSetting', 'openThemeSetting']);
|
||||
const emits = defineEmits(['switchTab', 'copyAddress']);
|
||||
|
||||
// 顶部操作
|
||||
const topActions: Array<SidebarAction> = [
|
||||
{
|
||||
icon: 'icon-plus',
|
||||
content: '新建连接',
|
||||
click: () => emits('openAdd')
|
||||
click: () => emits('switchTab', InnerTabs.HOST_LIST)
|
||||
},
|
||||
{
|
||||
icon: 'icon-copy',
|
||||
@@ -42,17 +43,17 @@
|
||||
{
|
||||
icon: 'icon-command',
|
||||
content: '快捷键设置',
|
||||
click: () => emits('openShortcutSetting')
|
||||
click: () => emits('switchTab', InnerTabs.SHORTCUT_SETTING)
|
||||
},
|
||||
{
|
||||
icon: 'icon-palette',
|
||||
content: '主题设置',
|
||||
click: () => emits('openThemeSetting')
|
||||
click: () => emits('switchTab', InnerTabs.THEME_SETTING)
|
||||
},
|
||||
{
|
||||
icon: 'icon-tool',
|
||||
content: '显示设置',
|
||||
click: () => emits('openViewSetting')
|
||||
click: () => emits('switchTab', InnerTabs.VIEW_SETTING)
|
||||
},
|
||||
];
|
||||
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
<template>
|
||||
<div class="terminal-right-sidebar">
|
||||
<!-- 操作按钮 -->
|
||||
<icon-actions class="terminal-actions"
|
||||
:actions="actions"
|
||||
<!-- 顶部操作按钮 -->
|
||||
<icon-actions class="top-actions"
|
||||
:actions="topActions"
|
||||
position="left" />
|
||||
<!-- 底部操作按钮 -->
|
||||
<icon-actions class="bottom-actions"
|
||||
:actions="bottomActions"
|
||||
position="left" />
|
||||
</div>
|
||||
</template>
|
||||
@@ -14,13 +18,13 @@
|
||||
</script>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { SidebarAction } from '../../types/terminal.type';
|
||||
import type { SidebarAction } from '../../types/terminal.type';
|
||||
import IconActions from './icon-actions.vue';
|
||||
|
||||
const emits = defineEmits(['openSnippet', 'openSftp', 'openTransfer', 'openHistory']);
|
||||
const emits = defineEmits(['openSnippet', 'openSftp', 'openTransfer', 'openHistory', 'screenshot']);
|
||||
|
||||
// 操作
|
||||
const actions: Array<SidebarAction> = [
|
||||
// 顶部操作
|
||||
const topActions: Array<SidebarAction> = [
|
||||
{
|
||||
icon: 'icon-code-block',
|
||||
content: '打开命令片段',
|
||||
@@ -49,10 +53,23 @@
|
||||
},
|
||||
];
|
||||
|
||||
// 底部操作
|
||||
const bottomActions: Array<SidebarAction> = [
|
||||
{
|
||||
icon: 'icon-camera',
|
||||
content: '截图',
|
||||
style: {},
|
||||
click: () => emits('screenshot')
|
||||
},
|
||||
];
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.terminal-right-sidebar {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
<template>
|
||||
<div class="terminal-content">
|
||||
<slot />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
export default {
|
||||
name: 'TerminalContent'
|
||||
};
|
||||
</script>
|
||||
|
||||
<script lang="ts" setup>
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.terminal-content {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: relative;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,56 @@
|
||||
<template>
|
||||
<div id="" class="terminal-example" ref="terminal"></div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
export default {
|
||||
name: 'terminalExample'
|
||||
};
|
||||
</script>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { Terminal } from '@xterm/xterm';
|
||||
import { onMounted, ref } from 'vue';
|
||||
import { TerminalTheme } from '../types/terminal.theme';
|
||||
|
||||
const props = defineProps<{
|
||||
theme: TerminalTheme
|
||||
}>();
|
||||
|
||||
const terminal = ref();
|
||||
|
||||
onMounted(() => {
|
||||
const term = new Terminal({
|
||||
theme: props.theme,
|
||||
cols: 47,
|
||||
rows: 6,
|
||||
fontSize: 15,
|
||||
convertEol: true,
|
||||
cursorBlink: false,
|
||||
cursorInactiveStyle: 'none'
|
||||
});
|
||||
term.open(terminal.value);
|
||||
|
||||
term.write(
|
||||
'[94m[root[0m@[96mOrionServer usr]#[0m\n' +
|
||||
'[92mdr-xr-xr-x.[0m 2 root root [96mbin[0m\n' +
|
||||
'[92mdr-xr-xr-x.[0m 2 root root [96msbin[0m\n' +
|
||||
'[92mdr-xr-xr-x.[0m 43 root root [96mlib[0m\n' +
|
||||
'[92mdr-xr-xr-x.[0m 62 root root [96mlib64[0m\n' +
|
||||
'[92mlrwxrwxrwx.[0m 1 root root [90;42mtmp[0m'
|
||||
);
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.terminal-example {
|
||||
padding: 16px;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
:deep(.xterm-viewport) {
|
||||
overflow: hidden !important;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,210 @@
|
||||
<template>
|
||||
<div class="terminal-setting-container theme-setting-container">
|
||||
<div class="theme-setting-wrapper">
|
||||
<!-- 大标题 -->
|
||||
<h2 class="terminal-setting-title">
|
||||
主题设置
|
||||
</h2>
|
||||
<!-- 切换主题 -->
|
||||
<div class="terminal-setting-block">
|
||||
<!-- 顶部 -->
|
||||
<div class="theme-subtitle-wrapper">
|
||||
<h3 class="terminal-setting-subtitle">
|
||||
主题选择
|
||||
</h3>
|
||||
<a-radio-group v-model="userDarkTheme"
|
||||
size="mini"
|
||||
type="button"
|
||||
@change="changeDarkTheme">
|
||||
<a-radio v-for="theme in DarkTheme" :key="theme.value" :value="theme.value">
|
||||
{{ theme.label }}
|
||||
</a-radio>
|
||||
</a-radio-group>
|
||||
</div>
|
||||
<!-- 内容区域 -->
|
||||
<div class="theme-list">
|
||||
<div class="theme-row"
|
||||
v-for="index in ThemeSchema.length / 2"
|
||||
:key="index">
|
||||
<a-card v-for="(theme, index) in [ThemeSchema[(index - 1) * 2], ThemeSchema[(index - 1) * 2 + 1]]"
|
||||
:key="theme.name"
|
||||
class="terminal-theme-card simple-card"
|
||||
:class="{
|
||||
'terminal-theme-card-check': theme.name === userTerminalTheme.name
|
||||
}"
|
||||
:title="theme.name"
|
||||
:style="{
|
||||
background: theme.background,
|
||||
marginRight: index === 0 ? '16px' : 0
|
||||
}"
|
||||
:header-style="{
|
||||
color: theme.dark ? 'rgba(255, 255, 255, .8)' : 'rgba(0, 0, 0, .8)'
|
||||
}"
|
||||
@click="checkTheme(theme)">
|
||||
<!-- 样例 -->
|
||||
<terminal-example :theme="theme" />
|
||||
<icon-check class="theme-check-icon" :style="{
|
||||
display: theme.name === userTerminalTheme.name ? 'flex': 'none'
|
||||
}" />
|
||||
</a-card>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
export default {
|
||||
name: 'TerminalThemeSetting'
|
||||
};
|
||||
</script>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import type { TerminalTheme } from '../types/terminal.theme';
|
||||
import { DarkTheme } from '../types/terminal.type';
|
||||
import ThemeSchema, { FRAPPE } from '../types/terminal.theme';
|
||||
import useEmitter from '@/hooks/emitter';
|
||||
import { onBeforeMount, ref } from 'vue';
|
||||
import TerminalExample from './terminal-example.vue';
|
||||
import { useDebounceFn } from '@vueuse/core';
|
||||
import { Message } from '@arco-design/web-vue';
|
||||
|
||||
defineProps();
|
||||
|
||||
const emits = defineEmits(['emitter']);
|
||||
|
||||
const { bubblesEmitter } = useEmitter(emits);
|
||||
|
||||
interface TerminalPreference {
|
||||
darkTheme: string,
|
||||
terminalTheme: TerminalTheme
|
||||
}
|
||||
|
||||
const userDarkTheme = ref(DarkTheme.DARK.value);
|
||||
const userTerminalTheme = ref<TerminalTheme>(FRAPPE);
|
||||
|
||||
// 修改暗色主题
|
||||
const changeDarkTheme = (value: string) => {
|
||||
if (value === DarkTheme.DARK.value) {
|
||||
// 暗色
|
||||
bubblesEmitter('changeDarkTheme', true);
|
||||
} else if (value === DarkTheme.LIGHT.value) {
|
||||
// 亮色
|
||||
bubblesEmitter('changeDarkTheme', false);
|
||||
} else if (value === DarkTheme.AUTO.value) {
|
||||
// 自动配色
|
||||
bubblesEmitter('changeDarkTheme', userTerminalTheme.value.dark ? DarkTheme.DARK.value : DarkTheme.LIGHT.value);
|
||||
}
|
||||
sync();
|
||||
};
|
||||
|
||||
// 选择终端主题
|
||||
const checkTheme = (theme: TerminalTheme) => {
|
||||
userTerminalTheme.value = theme;
|
||||
// 切换主题配色
|
||||
if (userDarkTheme.value === DarkTheme.AUTO.value) {
|
||||
changeDarkTheme(theme.dark ? DarkTheme.DARK.value : DarkTheme.LIGHT.value);
|
||||
} else {
|
||||
sync();
|
||||
}
|
||||
};
|
||||
|
||||
// 同步用户偏好
|
||||
const syncUserPreference = async () => {
|
||||
try {
|
||||
// FIXME 同步用户配置
|
||||
|
||||
Message.success('同步成功');
|
||||
} catch (e) {
|
||||
Message.error('同步失败');
|
||||
}
|
||||
};
|
||||
// 同步用户偏好防抖
|
||||
const sync = useDebounceFn(syncUserPreference, 1500);
|
||||
|
||||
onBeforeMount(() => {
|
||||
// FIXME 加载用户配置
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
@terminal-width: 458px;
|
||||
@terminal-height: 182px;
|
||||
@wrapper-width: @terminal-width * 2 + 16;
|
||||
|
||||
.theme-setting-wrapper {
|
||||
width: @wrapper-width;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.theme-subtitle-wrapper {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: flex-start;
|
||||
|
||||
.terminal-setting-subtitle {
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.theme-list {
|
||||
margin-top: 16px;
|
||||
|
||||
.theme-row {
|
||||
display: flex;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
.terminal-theme-card {
|
||||
width: @terminal-width;
|
||||
height: @terminal-height;
|
||||
border: 2px solid var(--color-border);
|
||||
cursor: pointer;
|
||||
|
||||
:deep(.arco-card-header) {
|
||||
padding: 4px 16px;
|
||||
height: 40px;
|
||||
border-bottom: .5px solid #DEDEDE;
|
||||
|
||||
&-title {
|
||||
color: unset;
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
}
|
||||
}
|
||||
|
||||
:deep(.arco-card-body) {
|
||||
height: calc(@terminal-height - 44px);
|
||||
padding: 0;
|
||||
display: flex;
|
||||
position: relative;
|
||||
|
||||
.theme-check-icon {
|
||||
position: absolute;
|
||||
color: #FFF;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
z-index: 10;
|
||||
}
|
||||
}
|
||||
|
||||
&-check, &:hover {
|
||||
border: 2px solid rgb(var(--blue-6));
|
||||
}
|
||||
|
||||
&-check::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
width: 0;
|
||||
height: 0;
|
||||
border-bottom: 28px solid rgb(var(--blue-6));
|
||||
border-left: 28px solid transparent;
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
@@ -2,33 +2,22 @@
|
||||
<div class="host-layout">
|
||||
<!-- 头部区域 -->
|
||||
<header class="host-layout-header">
|
||||
<terminal-header>
|
||||
<!-- 主机 tabs -->
|
||||
<a-tabs :editable="true"
|
||||
:hide-content="true"
|
||||
@tab-click="clickTab"
|
||||
@delete="deleteTab">
|
||||
<a-tab-pane v-for="i in 30"
|
||||
:key="i"
|
||||
:title="'主机主机主机'+i+''" />
|
||||
</a-tabs>
|
||||
</terminal-header>
|
||||
<terminal-header v-model="activeKey"
|
||||
:tabs="tabs"
|
||||
@click-tab="clickTab"
|
||||
@deleteTab="deleteTab" />
|
||||
</header>
|
||||
<!-- 主体区域 -->
|
||||
<main class="host-layout-main">
|
||||
<!-- 左侧操作栏 -->
|
||||
<div class="host-layout-left">
|
||||
<terminal-left-sidebar />
|
||||
<terminal-left-sidebar @switch-tab="switchTab" />
|
||||
</div>
|
||||
<!-- 内容区域 -->
|
||||
<div class="host-layout-content">
|
||||
<terminal-content>
|
||||
<div class="my16 mx16">
|
||||
<a-button @click="changeTheme">
|
||||
{{ darkTheme }}
|
||||
</a-button>
|
||||
</div>
|
||||
</terminal-content>
|
||||
<terminal-content v-model="activeKey"
|
||||
:tabs="tabs"
|
||||
@change-dark-theme="changeLayoutTheme" />
|
||||
</div>
|
||||
<!-- 右侧操作栏 -->
|
||||
<div class="host-layout-right">
|
||||
@@ -45,36 +34,72 @@
|
||||
</script>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import type { TabItem } from './types/terminal.type';
|
||||
import { ref } from 'vue';
|
||||
import { useDark } from '@vueuse/core';
|
||||
import { TabType, InnerTabs, DarkTheme } from './types/terminal.type';
|
||||
import TerminalHeader from './components/layout/terminal-header.vue';
|
||||
import TerminalLeftSidebar from './components/layout/terminal-left-sidebar.vue';
|
||||
import TerminalRightSidebar from './components/layout/terminal-right-sidebar.vue';
|
||||
import TerminalContent from './components/terminal-content.vue';
|
||||
import { useDark } from '@vueuse/core';
|
||||
import TerminalContent from './components/layout/terminal-content.vue';
|
||||
import './assets/styles/layout.less';
|
||||
import '@xterm/xterm/css/xterm.css';
|
||||
import { onBeforeMount } from 'vue/dist/vue';
|
||||
|
||||
// 主题
|
||||
// 系统主题
|
||||
const darkTheme = useDark({
|
||||
selector: 'body',
|
||||
attribute: 'terminal-theme',
|
||||
valueDark: 'dark',
|
||||
valueLight: 'light',
|
||||
initialValue: 'dark',
|
||||
valueDark: DarkTheme.DARK.value,
|
||||
valueLight: DarkTheme.LIGHT.value,
|
||||
initialValue: DarkTheme.DARK.value as any,
|
||||
storageKey: null
|
||||
});
|
||||
|
||||
const changeTheme = () => {
|
||||
console.log('current', darkTheme.value);
|
||||
darkTheme.value = !darkTheme.value;
|
||||
const activeKey = ref(InnerTabs.THEME_SETTING.key);
|
||||
const tabs = ref<Array<TabItem>>([InnerTabs.THEME_SETTING]);
|
||||
for (let i = 0; i < 3; i++) {
|
||||
tabs.value.push({
|
||||
key: `host${i}`,
|
||||
title: `主机name ${i}`,
|
||||
type: TabType.TERMINAL
|
||||
});
|
||||
}
|
||||
|
||||
// 切换系统主题
|
||||
const changeLayoutTheme = (dark: boolean) => {
|
||||
darkTheme.value = dark;
|
||||
};
|
||||
changeLayoutTheme(false);
|
||||
|
||||
// 点击 tab
|
||||
const clickTab = (key: string) => {
|
||||
activeKey.value = key;
|
||||
};
|
||||
|
||||
const clickTab = (v: any) => {
|
||||
console.log('click', v);
|
||||
// 删除 tab
|
||||
const deleteTab = (key: string) => {
|
||||
const tabIndex = tabs.value.findIndex(s => s.key === key);
|
||||
tabs.value.splice(tabIndex, 1);
|
||||
if (key === activeKey.value && tabs.value.length !== 0) {
|
||||
// 切换为前一个 tab
|
||||
activeKey.value = tabs.value[Math.max(tabIndex - 1, 0)].key;
|
||||
}
|
||||
};
|
||||
|
||||
const deleteTab = (v: any) => {
|
||||
console.log('delete', v);
|
||||
// 切换 tab
|
||||
const switchTab = (tab: TabItem) => {
|
||||
// 不存在则创建tab
|
||||
if (!tabs.value.find(s => s.key === tab.key)) {
|
||||
tabs.value.push(tab);
|
||||
}
|
||||
activeKey.value = tab.key;
|
||||
};
|
||||
|
||||
onBeforeMount(() => {
|
||||
// FIXME 加载用户配置
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
@@ -92,7 +117,6 @@
|
||||
&-main {
|
||||
width: 100%;
|
||||
height: calc(100% - var(--sidebar-width));
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
@@ -103,12 +127,15 @@
|
||||
height: 100%;
|
||||
background: var(--color-bg-sidebar);
|
||||
border-top: 1px solid var(--color-bg-content);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
&-content {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: var(--color-bg-content);
|
||||
overflow: auto;
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
280
orion-ops-ui/src/views/host-ops/terminal/types/terminal.theme.ts
Normal file
280
orion-ops-ui/src/views/host-ops/terminal/types/terminal.theme.ts
Normal file
@@ -0,0 +1,280 @@
|
||||
// 主题
|
||||
export interface TerminalTheme {
|
||||
name: string;
|
||||
dark: boolean;
|
||||
background: string;
|
||||
foreground: string;
|
||||
cursor: string;
|
||||
cursorAccent?: string;
|
||||
selectionInactiveBackground?: string;
|
||||
selectionBackground?: string;
|
||||
selectionForeground?: 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;
|
||||
}
|
||||
|
||||
// 默认配色
|
||||
export const FRAPPE = {
|
||||
name: 'frappe',
|
||||
dark: true,
|
||||
background: '#303446',
|
||||
foreground: '#C6D0F5',
|
||||
cursor: '#F2D5CF',
|
||||
cursorAccent: '#232634',
|
||||
// selectionInactiveBackground: 'rgba(98, 104, 128, 0.30078125)',
|
||||
selectionBackground: '#C9DDF0',
|
||||
selectionForeground: '#303446',
|
||||
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 [
|
||||
FRAPPE,
|
||||
{
|
||||
name: 'latte',
|
||||
dark: false,
|
||||
background: '#EFF1F5',
|
||||
foreground: '#4C4F69',
|
||||
cursor: '#DC8A78',
|
||||
cursorAccent: '#EFF1F5',
|
||||
// selectionInactiveBackground: 'rgba(172, 176, 190, 0.30078125)',
|
||||
selectionForeground: '#EFF1F5',
|
||||
selectionBackground: '#6C6F85',
|
||||
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',
|
||||
// selectionInactiveBackground: 'rgba(91, 96, 120, 0.30078125)',
|
||||
selectionForeground: '#24273A',
|
||||
selectionBackground: '#A5ADCB',
|
||||
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',
|
||||
// selectionInactiveBackground: 'rgba(88, 91, 112, 0.30078125)',
|
||||
selectionForeground: '#1E1E2E',
|
||||
selectionBackground: '#A6ADC8',
|
||||
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: 'AtomOneLight',
|
||||
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: 'OneHalfDark',
|
||||
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',
|
||||
selectionForeground: '#44475A',
|
||||
selectionBackground: '#50FA7B',
|
||||
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<TerminalTheme>;
|
||||
@@ -1,5 +1,21 @@
|
||||
import type { CSSProperties } from 'vue';
|
||||
|
||||
// 暗色主题
|
||||
export const DarkTheme = {
|
||||
DARK: {
|
||||
value: 'dark',
|
||||
label: '暗色'
|
||||
},
|
||||
LIGHT: {
|
||||
value: 'light',
|
||||
label: '亮色'
|
||||
},
|
||||
AUTO: {
|
||||
value: 'auto',
|
||||
label: '自动'
|
||||
}
|
||||
};
|
||||
|
||||
// sidebar 操作类型
|
||||
export interface SidebarAction {
|
||||
icon: string;
|
||||
@@ -8,3 +24,42 @@ export interface SidebarAction {
|
||||
visible?: boolean;
|
||||
click: () => void;
|
||||
}
|
||||
|
||||
// tab 类型
|
||||
export const TabType = {
|
||||
SETTING: 'setting',
|
||||
TERMINAL: 'terminal',
|
||||
};
|
||||
|
||||
// 内置 tab
|
||||
export const InnerTabs = {
|
||||
HOST_LIST: {
|
||||
key: 'hostList',
|
||||
title: '新建连接',
|
||||
type: TabType.SETTING
|
||||
},
|
||||
SHORTCUT_SETTING: {
|
||||
key: 'shortcutSetting',
|
||||
title: '快捷键设置',
|
||||
type: TabType.SETTING
|
||||
},
|
||||
THEME_SETTING: {
|
||||
key: 'themeSetting',
|
||||
title: '主题设置',
|
||||
type: TabType.SETTING
|
||||
},
|
||||
VIEW_SETTING: {
|
||||
key: 'viewSetting',
|
||||
title: '显示设置',
|
||||
type: TabType.SETTING
|
||||
},
|
||||
};
|
||||
|
||||
// tab 元素
|
||||
export interface TabItem {
|
||||
key: string;
|
||||
title: string;
|
||||
type: string;
|
||||
|
||||
[key: string]: unknown;
|
||||
}
|
||||
|
||||
@@ -1,409 +0,0 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<link rel="stylesheet" href="./xterm.css" />
|
||||
<script src="./theme.js"></script>
|
||||
<script src="./xterm.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="themes">
|
||||
|
||||
</div>
|
||||
<div id="terminal"></div>
|
||||
|
||||
<script>
|
||||
|
||||
// 冰咖啡配色
|
||||
const frappe = {
|
||||
background: '#303446',
|
||||
foreground: '#c6d0f5',
|
||||
cursor: '#f2d5cf',
|
||||
cursorAccent: '#232634',
|
||||
selectionInactiveBackground: 'rgba(98, 104, 128, 0.30078125)',
|
||||
selectionBackground: '#303446',
|
||||
selectionForeground: '#A5ADCE',
|
||||
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'
|
||||
};
|
||||
|
||||
// 拿铁配色
|
||||
const latte = {
|
||||
background: '#eff1f5',
|
||||
foreground: '#4c4f69',
|
||||
cursor: '#dc8a78',
|
||||
cursorAccent: '#EFF1F5',
|
||||
selectionInactiveBackground: 'rgba(172, 176, 190, 0.30078125)',
|
||||
selectionForeground: '#EFF1F5',
|
||||
selectionBackground: '#6C6F85',
|
||||
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'
|
||||
};
|
||||
|
||||
// 玛奇朵
|
||||
const macchiato = {
|
||||
background: '#24273a',
|
||||
foreground: '#cad3f5',
|
||||
cursor: '#f4dbd6',
|
||||
cursorAccent: '#181926',
|
||||
selectionInactiveBackground: 'rgba(91, 96, 120, 0.30078125)',
|
||||
selectionForeground: '#24273A',
|
||||
selectionBackground: '#A5ADCB',
|
||||
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'
|
||||
};
|
||||
|
||||
// 摩卡配色
|
||||
const mocha = {
|
||||
background: '#1e1e2e',
|
||||
foreground: '#cdd6f4',
|
||||
cursor: '#f5e0dc',
|
||||
cursorAccent: '#11111B',
|
||||
selection: 'rgba(88, 91, 112, 0.30078125)',
|
||||
selectionForeground: '#1E1E2E',
|
||||
selectionBackground: '#A6ADC8',
|
||||
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',
|
||||
};
|
||||
|
||||
const a = {
|
||||
'iceberg-dark': {
|
||||
'cursor': '#c6c8d1',
|
||||
'brightYellow': '#e9b189',
|
||||
'brightPurple': '#ada0d3',
|
||||
'green': '#b4be82',
|
||||
'black': '#1e2132',
|
||||
'yellow': '#e2a478',
|
||||
'brightGreen': '#c0ca8e',
|
||||
'foreground': '#c6c8d1',
|
||||
'cyan': '#89b8c2',
|
||||
'brightRed': '#e98989',
|
||||
'brightWhite': '#d2d4de',
|
||||
'red': '#e27878',
|
||||
'brightCyan': '#95c4ce',
|
||||
'blue': '#84a0c6',
|
||||
'white': '#c6c8d1',
|
||||
'selection': '#c6c8d1',
|
||||
'background': '#161821',
|
||||
'name': 'iceberg-dark',
|
||||
'dark': true,
|
||||
'purple': '#a093c7',
|
||||
'brightBlue': '#91acd1', 'theme': 'iceberg-dark',
|
||||
'brightBlack': '#6b7089'
|
||||
},
|
||||
};
|
||||
|
||||
// 吸血鬼配色
|
||||
const dracula = {
|
||||
background: '#282a36',
|
||||
foreground: '#f8f8f2',
|
||||
selectionForeground: '#44475a',
|
||||
selectionBackground: '#50fa7b',
|
||||
cursor: '#f8f8f2',
|
||||
cursorAccent: '#282a36',
|
||||
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',
|
||||
};
|
||||
|
||||
const themes = {
|
||||
gray: {
|
||||
foreground: '#A9B7C6', background: '#2b2b2b', cursor: '#A9B7C6',
|
||||
|
||||
black: '#1b1b1b', brightBlack: '#626262',
|
||||
|
||||
red: '#bb5653', brightRed: '#bb5653',
|
||||
|
||||
green: '#909d62', brightGreen: '#909d62',
|
||||
|
||||
yellow: '#eac179', brightYellow: '#eac179',
|
||||
|
||||
blue: '#7da9c7', brightBlue: '#7da9c7',
|
||||
|
||||
magenta: '#b06597', brightMagenta: '#b06597',
|
||||
|
||||
cyan: '#8cdcd8', brightCyan: '#8cdcd8',
|
||||
|
||||
white: '#d8d8d8', brightWhite: '#f7f7f7'
|
||||
}, dark: {
|
||||
foreground: '#c7c7c7', background: '#000000', cursor: '#c7c7c7',
|
||||
|
||||
black: '#000000', brightBlack: '#676767',
|
||||
|
||||
red: '#c91b00', brightRed: '#ff6d67',
|
||||
|
||||
green: '#00c200', brightGreen: '#5ff967',
|
||||
|
||||
yellow: '#c7c400', brightYellow: '#fefb67',
|
||||
|
||||
blue: '#0225c7', brightBlue: '#6871ff',
|
||||
|
||||
magenta: '#c930c7', brightMagenta: '#ff76ff',
|
||||
|
||||
cyan: '#00c5c7', brightCyan: '#5ffdff',
|
||||
|
||||
white: '#c7c7c7', brightWhite: '#fffefe'
|
||||
}, ubuntu: {
|
||||
foreground: '#f1f1ef', background: '#3f0e2f', cursor: '#c7c7c7',
|
||||
|
||||
black: '#3c4345', brightBlack: '#676965',
|
||||
|
||||
red: '#d71e00', brightRed: '#f44135',
|
||||
|
||||
green: '#5da602', brightGreen: '#98e342',
|
||||
|
||||
yellow: '#cfad00', brightYellow: '#fcea60',
|
||||
|
||||
blue: '#417ab3', brightBlue: '#83afd8',
|
||||
|
||||
magenta: '#88658d', brightMagenta: '#bc93b6',
|
||||
|
||||
cyan: '#00a7aa', brightCyan: '#37e5e7',
|
||||
|
||||
white: '#dbded8', brightWhite: '#f1f1ef'
|
||||
}, light: {
|
||||
foreground: '#000000', background: '#fffefe', cursor: '#000000',
|
||||
|
||||
black: '#000000', brightBlack: '#676767',
|
||||
|
||||
red: '#c91b00', brightRed: '#ff6d67',
|
||||
|
||||
green: '#00c200', brightGreen: '#5ff967',
|
||||
|
||||
yellow: '#c7c400', brightYellow: '#fefb67',
|
||||
|
||||
blue: '#0225c7', brightBlue: '#6871ff',
|
||||
|
||||
magenta: '#c930c7', brightMagenta: '#ff76ff',
|
||||
|
||||
cyan: '#00c5c7', brightCyan: '#5ffdff',
|
||||
|
||||
white: '#c7c7c7', brightWhite: '#fffefe'
|
||||
}, solarized_light: {
|
||||
foreground: '#657b83', background: '#fdf6e3', cursor: '#657b83',
|
||||
|
||||
black: '#073642', brightBlack: '#002b36',
|
||||
|
||||
red: '#dc322f', brightRed: '#cb4b16',
|
||||
|
||||
green: '#859900', brightGreen: '#586e75',
|
||||
|
||||
yellow: '#b58900', brightYellow: '#657b83',
|
||||
|
||||
blue: '#268bd2', brightBlue: '#839496',
|
||||
|
||||
magenta: '#d33682', brightMagenta: '#6c71c4',
|
||||
|
||||
cyan: '#2aa198', brightCyan: '#93a1a1',
|
||||
|
||||
white: '#eee8d5', brightWhite: '#fdf6e3'
|
||||
}, material: {
|
||||
foreground: '#2e2d2c', background: '#eeeeee', cursor: '#2e2d2c',
|
||||
|
||||
black: '#2c2c2c', brightBlack: '#535353',
|
||||
|
||||
red: '#c52728', brightRed: '#ee524f',
|
||||
|
||||
green: '#558a2f', brightGreen: '#8bc24a',
|
||||
|
||||
yellow: '#f8a725', brightYellow: '#ffea3b',
|
||||
|
||||
blue: '#1564bf', brightBlue: '#64b4f5',
|
||||
|
||||
magenta: '#691e99', brightMagenta: '#b967c7',
|
||||
|
||||
cyan: '#00828e', brightCyan: '#26c5d9',
|
||||
|
||||
white: '#f2f1f1', brightWhite: '#e0dfdf'
|
||||
},
|
||||
frappe, latte, mocha, macchiato, dracula,
|
||||
...themes1
|
||||
};
|
||||
|
||||
var term = new Terminal({
|
||||
theme: dracula
|
||||
});
|
||||
|
||||
var doc = document.getElementById('themes');
|
||||
for (let themesKey in themes) {
|
||||
var buc = document.createElement('button');
|
||||
buc.innerHTML = themesKey;
|
||||
var dark = isDarkColor(themes[themesKey].background);
|
||||
if(dark) {
|
||||
buc.style.background = '#000';
|
||||
buc.style.color = '#FFF';
|
||||
}
|
||||
console.log(dark);
|
||||
buc.addEventListener('click', function () {
|
||||
console.log(themesKey);
|
||||
term.setOption('theme', themes[themesKey]);
|
||||
c();
|
||||
r();
|
||||
});
|
||||
doc.append(buc);
|
||||
}
|
||||
|
||||
function isDarkColor(hexColor) {
|
||||
// 将16进制颜色转换为RGB颜色
|
||||
var rgbColor = hexToRgb(hexColor);
|
||||
// 计算RGB颜色的亮度值
|
||||
var brightness = (rgbColor.r * 299 + rgbColor.g * 587 + rgbColor.b * 114) / 1000;
|
||||
// 判断亮度值是否小于128,小于128则为深色,大于等于128则为浅色
|
||||
if(brightness < 128) {
|
||||
return true; // 深色
|
||||
} else {
|
||||
return false; // 浅色
|
||||
}
|
||||
}
|
||||
|
||||
// 将16进制颜色转换为RGB颜色
|
||||
function hexToRgb(hexColor) {
|
||||
// 去除#号
|
||||
hexColor = hexColor.replace('#', '');
|
||||
|
||||
// 将16进制颜色转换为RGB颜色
|
||||
var r = parseInt(hexColor.substring(0, 2), 16);
|
||||
var g = parseInt(hexColor.substring(2, 4), 16);
|
||||
var b = parseInt(hexColor.substring(4, 6), 16);
|
||||
|
||||
return { r: r, g: g, b: b };
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
https://draculatheme.com/windows-terminal
|
||||
https://github.com/morhetz/gruvbox
|
||||
https://github.com/dracula/dracula-theme
|
||||
|
||||
https://github.com/mbadolato/iTerm2-Color-Schemes
|
||||
|
||||
public static void main(String[] args) {
|
||||
List<File> files = Files1.listFiles("D:\\Work\\idea-project\\iTerm2-Color-Schemes\\vhs");
|
||||
HashMap<String, Object> maps = new HashMap<>();
|
||||
files.stream().forEach(f -> {
|
||||
String fileName = f.getName();
|
||||
String theme = fileName.substring(0, fileName.lastIndexOf("."));
|
||||
String field = theme.replaceAll(" ", "_");
|
||||
byte[] bytes = FileReaders.readAllBytes(f);
|
||||
JSONObject themeJson = JSONObject.parseObject(new String(bytes));
|
||||
themeJson.put("theme", theme);
|
||||
themeJson.put("dark", true);
|
||||
maps.put(field, themeJson);
|
||||
});
|
||||
System.out.println(JSON.toJSONString(maps));
|
||||
}
|
||||
|
||||
|
||||
*/
|
||||
|
||||
term.open(document.getElementById('terminal'));
|
||||
|
||||
function w(s) {
|
||||
term.write(s);
|
||||
}
|
||||
|
||||
function wc(s) {
|
||||
term.reset();
|
||||
term.write(s);
|
||||
}
|
||||
|
||||
function c() {
|
||||
term.reset();
|
||||
}
|
||||
|
||||
function r() {
|
||||
for (let i = 0; i < 9; i++) {
|
||||
term.write('[' + (30 + i) + 'm');
|
||||
term.write(i + ' this visibility cellpadding capitalize separate getElementById');
|
||||
term.write('[0m\r\n');
|
||||
}
|
||||
for (let i = 0; i < 9; i++) {
|
||||
term.write('[' + (90 + i) + 'm');
|
||||
term.write(i + ' this visibility cellpadding capitalize separate getElementById');
|
||||
term.write('[0m\r\n');
|
||||
}
|
||||
for (let i = 0; i < 9; i++) {
|
||||
term.write('[' + (40 + i) + 'm');
|
||||
term.write(i + ' this visibility cellpadding capitalize separate getElementById');
|
||||
term.write('[0m\r\n');
|
||||
}
|
||||
for (let i = 0; i < 9; i++) {
|
||||
term.write('[' + (100 + i) + 'm');
|
||||
term.write(i + ' this visibility cellpadding capitalize separate getElementById');
|
||||
term.write('[0m\r\n');
|
||||
}
|
||||
}
|
||||
|
||||
r();
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,174 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2014 The xterm.js authors. All rights reserved.
|
||||
* Copyright (c) 2012-2013, Christopher Jeffrey (MIT License)
|
||||
* https://github.com/chjj/term.js
|
||||
* @license MIT
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* Originally forked from (with the author's permission):
|
||||
* Fabrice Bellard's javascript vt100 for jslinux:
|
||||
* http://bellard.org/jslinux/
|
||||
* Copyright (c) 2011 Fabrice Bellard
|
||||
* The original design remains. The terminal itself
|
||||
* has been extended to include xterm CSI codes, among
|
||||
* other features.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Default styles for xterm.js
|
||||
*/
|
||||
|
||||
.xterm {
|
||||
position: relative;
|
||||
user-select: none;
|
||||
-ms-user-select: none;
|
||||
-webkit-user-select: none;
|
||||
}
|
||||
|
||||
.xterm.focus,
|
||||
.xterm:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.xterm .xterm-helpers {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
/**
|
||||
* The z-index of the helpers must be higher than the canvases in order for
|
||||
* IMEs to appear on top.
|
||||
*/
|
||||
z-index: 5;
|
||||
}
|
||||
|
||||
.xterm .xterm-helper-textarea {
|
||||
padding: 0;
|
||||
border: 0;
|
||||
margin: 0;
|
||||
/* Move textarea out of the screen to the far left, so that the cursor is not visible */
|
||||
position: absolute;
|
||||
opacity: 0;
|
||||
left: -9999em;
|
||||
top: 0;
|
||||
width: 0;
|
||||
height: 0;
|
||||
z-index: -5;
|
||||
/** Prevent wrapping so the IME appears against the textarea at the correct position */
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
resize: none;
|
||||
}
|
||||
|
||||
.xterm .composition-view {
|
||||
/* TODO: Composition position got messed up somewhere */
|
||||
background: #000;
|
||||
color: #FFF;
|
||||
display: none;
|
||||
position: absolute;
|
||||
white-space: nowrap;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.xterm .composition-view.active {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.xterm .xterm-viewport {
|
||||
/* On OS X this is required in order for the scroll bar to appear fully opaque */
|
||||
background-color: #000;
|
||||
overflow-y: scroll;
|
||||
cursor: default;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
left: 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
.xterm .xterm-screen {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.xterm .xterm-screen canvas {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
}
|
||||
|
||||
.xterm .xterm-scroll-area {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
.xterm-char-measure-element {
|
||||
display: inline-block;
|
||||
visibility: hidden;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: -9999em;
|
||||
line-height: normal;
|
||||
}
|
||||
|
||||
.xterm {
|
||||
cursor: text;
|
||||
}
|
||||
|
||||
.xterm.enable-mouse-events {
|
||||
/* When mouse events are enabled (eg. tmux), revert to the standard pointer cursor */
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.xterm.xterm-cursor-pointer {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.xterm.column-select.focus {
|
||||
/* Column selection mode */
|
||||
cursor: crosshair;
|
||||
}
|
||||
|
||||
.xterm .xterm-accessibility,
|
||||
.xterm .xterm-message {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
z-index: 10;
|
||||
color: transparent;
|
||||
}
|
||||
|
||||
.xterm .live-region {
|
||||
position: absolute;
|
||||
left: -9999px;
|
||||
width: 1px;
|
||||
height: 1px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.xterm-dim {
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.xterm-underline {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.xterm-strikethrough {
|
||||
text-decoration: line-through;
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user