mirror of
https://github.com/fofolee/uTools-quickcommand.git
synced 2025-07-01 13:32:45 +08:00
编辑器语言栏组件化
This commit is contained in:
parent
16f907567e
commit
b191cca77e
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="absolute-full container" style="overflow: hidden">
|
<div class="absolute-full command-editor-container">
|
||||||
<!-- 命令设置栏 -->
|
<!-- 命令设置栏 -->
|
||||||
<CommandSideBar
|
<CommandSideBar
|
||||||
ref="sidebar"
|
ref="sidebar"
|
||||||
@ -17,7 +17,7 @@
|
|||||||
></CommandSideBar>
|
></CommandSideBar>
|
||||||
|
|
||||||
<!-- 编程语言栏 -->
|
<!-- 编程语言栏 -->
|
||||||
<div
|
<CommandLanguageBar
|
||||||
class="absolute-top"
|
class="absolute-top"
|
||||||
:style="{
|
:style="{
|
||||||
left: showSidebar ? sideBarWidth + 'px' : 65,
|
left: showSidebar ? sideBarWidth + 'px' : 65,
|
||||||
@ -26,183 +26,15 @@
|
|||||||
opacity: isFullscreen ? 0 : 1,
|
opacity: isFullscreen ? 0 : 1,
|
||||||
transition: 'all 0.3s cubic-bezier(0.4, 0, 0.2, 1)',
|
transition: 'all 0.3s cubic-bezier(0.4, 0, 0.2, 1)',
|
||||||
}"
|
}"
|
||||||
>
|
v-model="quickcommandInfo"
|
||||||
<div class="row" v-show="!!languageBarHeight">
|
:height="languageBarHeight"
|
||||||
<!-- 去掉收起侧栏功能,处理侧栏宽度变化时,Monaco调整大小导致ResizeObserver loop limit exceeded错误 -->
|
:canCommandSave="canCommandSave"
|
||||||
<!-- <div class="col-auto flex">
|
:isRunCodePage="isRunCodePage"
|
||||||
<q-btn v-if="!isRunCodePage" flat dense color="primary" class="menuBtn" icon="menu"
|
@program-changed="programChanged"
|
||||||
@click="toggleSideBarWidth"><q-tooltip>{{ !!sideBarWidth ? "收起" : "展开" }}侧栏</q-tooltip></q-btn>
|
@run="runCurrentCommand"
|
||||||
</div> -->
|
@save="saveCurrentCommand"
|
||||||
<div class="col">
|
@add-action="insertText"
|
||||||
<div>
|
/>
|
||||||
<q-select
|
|
||||||
dense
|
|
||||||
standout="bg-primary text-white"
|
|
||||||
square
|
|
||||||
hide-bottom-space
|
|
||||||
color="primary"
|
|
||||||
transition-show="jump-down"
|
|
||||||
transition-hide="jump-up"
|
|
||||||
@update:model-value="programChanged"
|
|
||||||
v-model="quickcommandInfo.program"
|
|
||||||
:options="programLanguages"
|
|
||||||
label="环境"
|
|
||||||
>
|
|
||||||
<template v-slot:append>
|
|
||||||
<q-avatar size="lg" square>
|
|
||||||
<img :src="$root.programs[quickcommandInfo.program].icon" />
|
|
||||||
</q-avatar>
|
|
||||||
</template>
|
|
||||||
<template v-slot:option="scope">
|
|
||||||
<q-item v-bind="scope.itemProps">
|
|
||||||
<q-item-section avatar>
|
|
||||||
<img width="32" :src="$root.programs[scope.opt].icon" />
|
|
||||||
</q-item-section>
|
|
||||||
<q-item-section>
|
|
||||||
<q-item-label v-html="scope.opt" />
|
|
||||||
</q-item-section>
|
|
||||||
</q-item>
|
|
||||||
</template>
|
|
||||||
</q-select>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<q-separator vertical />
|
|
||||||
<div class="col-auto justify-end flex">
|
|
||||||
<q-btn-group unelevated>
|
|
||||||
<q-btn-dropdown
|
|
||||||
v-show="quickcommandInfo.program !== 'html'"
|
|
||||||
style="padding: 0 10px"
|
|
||||||
dense
|
|
||||||
flat
|
|
||||||
ref="settings"
|
|
||||||
color="primary"
|
|
||||||
:icon="
|
|
||||||
quickcommandInfo.program === 'quickcommand'
|
|
||||||
? 'insights'
|
|
||||||
: 'settings'
|
|
||||||
"
|
|
||||||
>
|
|
||||||
<q-list>
|
|
||||||
<!-- quickcommand系列按键 -->
|
|
||||||
<q-item
|
|
||||||
clickable
|
|
||||||
v-for="(item, index) in ['keyboard', 'ads_click', 'help']"
|
|
||||||
:key="index"
|
|
||||||
@click="
|
|
||||||
[
|
|
||||||
() => (showRecorder = true),
|
|
||||||
() => (showActions = true),
|
|
||||||
showHelp,
|
|
||||||
][index]
|
|
||||||
"
|
|
||||||
v-show="quickcommandInfo.program === 'quickcommand'"
|
|
||||||
>
|
|
||||||
<q-item-section avatar>
|
|
||||||
<q-icon :name="item" />
|
|
||||||
</q-item-section>
|
|
||||||
<q-item-section>{{
|
|
||||||
["录制按键", "快捷动作", "查看文档"][index]
|
|
||||||
}}</q-item-section>
|
|
||||||
</q-item>
|
|
||||||
<!-- 自定义解释器 -->
|
|
||||||
<q-item
|
|
||||||
v-for="(item, index) in Object.keys(
|
|
||||||
quickcommandInfo.customOptions
|
|
||||||
)"
|
|
||||||
:key="index"
|
|
||||||
v-show="quickcommandInfo.program === 'custom'"
|
|
||||||
>
|
|
||||||
<q-input
|
|
||||||
stack-label
|
|
||||||
autofocus
|
|
||||||
dense
|
|
||||||
outlined
|
|
||||||
class="full-width"
|
|
||||||
@blur="matchLanguage"
|
|
||||||
:label="
|
|
||||||
[
|
|
||||||
'解释器路径,如:/opt/python',
|
|
||||||
'运行参数,如:-u',
|
|
||||||
'脚本后缀,不含点,如:py',
|
|
||||||
][index]
|
|
||||||
"
|
|
||||||
v-model="quickcommandInfo.customOptions[item]"
|
|
||||||
>
|
|
||||||
<template v-slot:prepend>
|
|
||||||
<q-icon name="code" />
|
|
||||||
</template>
|
|
||||||
</q-input>
|
|
||||||
</q-item>
|
|
||||||
<!-- 脚本参数 -->
|
|
||||||
<q-item v-show="quickcommandInfo.program !== 'quickcommand'">
|
|
||||||
<q-input
|
|
||||||
dense
|
|
||||||
stack-label
|
|
||||||
outlined
|
|
||||||
label="脚本参数"
|
|
||||||
class="full-width"
|
|
||||||
v-model="quickcommandInfo.scptarg"
|
|
||||||
>
|
|
||||||
<template v-slot:prepend>
|
|
||||||
<q-icon name="input" />
|
|
||||||
</template>
|
|
||||||
</q-input>
|
|
||||||
</q-item>
|
|
||||||
<!-- 编码设置 -->
|
|
||||||
<q-item
|
|
||||||
v-for="(item, index) in Object.keys(quickcommandInfo.charset)"
|
|
||||||
:key="index"
|
|
||||||
v-show="quickcommandInfo.program !== 'quickcommand'"
|
|
||||||
>
|
|
||||||
<q-select
|
|
||||||
dense
|
|
||||||
outlined
|
|
||||||
stack-label
|
|
||||||
clearable
|
|
||||||
class="full-width"
|
|
||||||
:label="['脚本编码', '输出编码'][index]"
|
|
||||||
v-model="quickcommandInfo.charset[item]"
|
|
||||||
:options="['GBK', 'utf8', 'Big5']"
|
|
||||||
type="text"
|
|
||||||
>
|
|
||||||
<template v-slot:prepend>
|
|
||||||
<q-icon :name="['format_size', 'output'][index]" />
|
|
||||||
</template>
|
|
||||||
</q-select>
|
|
||||||
</q-item>
|
|
||||||
</q-list>
|
|
||||||
</q-btn-dropdown>
|
|
||||||
<q-separator vertical inset />
|
|
||||||
<q-btn
|
|
||||||
style="padding: 0 10px"
|
|
||||||
dense
|
|
||||||
flat
|
|
||||||
color="primary"
|
|
||||||
icon="play_arrow"
|
|
||||||
label="运行"
|
|
||||||
@click="runCurrentCommand()"
|
|
||||||
></q-btn>
|
|
||||||
<q-btn
|
|
||||||
flat
|
|
||||||
style="padding: 0 10px"
|
|
||||||
dense
|
|
||||||
v-if="!isRunCodePage"
|
|
||||||
:disable="!canCommandSave"
|
|
||||||
:color="canCommandSave ? 'primary' : 'grey'"
|
|
||||||
icon="save"
|
|
||||||
label="保存"
|
|
||||||
@click="saveCurrentCommand()"
|
|
||||||
></q-btn>
|
|
||||||
</q-btn-group>
|
|
||||||
</div>
|
|
||||||
<q-dialog v-model="showActions">
|
|
||||||
<QuickAction @addAction="insertText" />
|
|
||||||
</q-dialog>
|
|
||||||
<q-dialog v-model="showRecorder" position="bottom">
|
|
||||||
<KeyRecorder @sendKeys="insertText" />
|
|
||||||
</q-dialog>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 编辑器 -->
|
<!-- 编辑器 -->
|
||||||
<MonacoEditor
|
<MonacoEditor
|
||||||
@ -226,28 +58,13 @@
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
<!-- 编辑器工具按钮组 -->
|
<!-- 编辑器工具按钮组 -->
|
||||||
<div class="editor-tools">
|
<EditorTools
|
||||||
<!-- 历史记录组件 -->
|
ref="editorTools"
|
||||||
<EditorHistory
|
:commandCode="quickcommandInfo?.features?.code || 'temp'"
|
||||||
ref="history"
|
:isFullscreen="isFullscreen"
|
||||||
:commandCode="quickcommandInfo?.features?.code || 'temp'"
|
@restore="restoreHistory"
|
||||||
@restore="restoreHistory"
|
@toggle-fullscreen="toggleFullscreen"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<!-- 全屏按钮 -->
|
|
||||||
<q-btn
|
|
||||||
round
|
|
||||||
dense
|
|
||||||
:icon="isFullscreen ? 'fullscreen_exit' : 'fullscreen'"
|
|
||||||
@click="toggleFullscreen"
|
|
||||||
class="fullscreen-btn"
|
|
||||||
:class="{ 'btn-fullscreen': isFullscreen }"
|
|
||||||
>
|
|
||||||
<q-tooltip>{{
|
|
||||||
isFullscreen ? "退出全屏 (F11)" : "全屏编辑 (F11)"
|
|
||||||
}}</q-tooltip>
|
|
||||||
</q-btn>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 运行结果 -->
|
<!-- 运行结果 -->
|
||||||
<CommandRunResult :action="action" ref="result"></CommandRunResult>
|
<CommandRunResult :action="action" ref="result"></CommandRunResult>
|
||||||
@ -258,34 +75,27 @@
|
|||||||
import { defineAsyncComponent } from "vue";
|
import { defineAsyncComponent } from "vue";
|
||||||
import CommandSideBar from "components/CommandSideBar";
|
import CommandSideBar from "components/CommandSideBar";
|
||||||
import CommandRunResult from "components/CommandRunResult";
|
import CommandRunResult from "components/CommandRunResult";
|
||||||
import QuickAction from "components/popup/QuickAction";
|
import CommandLanguageBar from "components/CommandLanguageBar";
|
||||||
import KeyRecorder from "components/popup/KeyRecorder";
|
import EditorTools from "components/EditorTools";
|
||||||
import EditorHistory from "components/popup/EditorHistory.vue";
|
|
||||||
// Performance Scripting > 500ms
|
// Performance Scripting > 500ms
|
||||||
const MonacoEditor = defineAsyncComponent(() =>
|
const MonacoEditor = defineAsyncComponent(() =>
|
||||||
import("components/MonacoEditor")
|
import("components/MonacoEditor")
|
||||||
);
|
);
|
||||||
|
|
||||||
const defaultSideBarWidth = 200;
|
|
||||||
const defaultlanguageBarHeight = 40;
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
MonacoEditor,
|
MonacoEditor,
|
||||||
CommandSideBar,
|
CommandSideBar,
|
||||||
CommandRunResult,
|
CommandRunResult,
|
||||||
QuickAction,
|
CommandLanguageBar,
|
||||||
KeyRecorder,
|
EditorTools,
|
||||||
EditorHistory,
|
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
programLanguages: Object.keys(this.$root.programs),
|
programLanguages: Object.keys(this.$root.programs),
|
||||||
sideBarWidth: defaultSideBarWidth,
|
sideBarWidth: 200,
|
||||||
languageBarHeight: defaultlanguageBarHeight,
|
languageBarHeight: 40,
|
||||||
canCommandSave: this.action.type === "code" ? false : true,
|
canCommandSave: this.action.type === "code" ? false : true,
|
||||||
showActions: false,
|
|
||||||
showRecorder: false,
|
|
||||||
quickcommandInfo: {
|
quickcommandInfo: {
|
||||||
program: "quickcommand",
|
program: "quickcommand",
|
||||||
cmd: "",
|
cmd: "",
|
||||||
@ -382,14 +192,6 @@ export default {
|
|||||||
insertText(text) {
|
insertText(text) {
|
||||||
this.$refs.editor.repacleEditorSelection(text);
|
this.$refs.editor.repacleEditorSelection(text);
|
||||||
},
|
},
|
||||||
// 打开文档
|
|
||||||
showHelp() {
|
|
||||||
window.showUb.docs();
|
|
||||||
},
|
|
||||||
// 展开收起侧栏
|
|
||||||
toggleSideBarWidth() {
|
|
||||||
this.sideBarWidth = !!this.sideBarWidth ? 0 : defaultSideBarWidth;
|
|
||||||
},
|
|
||||||
// 保存
|
// 保存
|
||||||
saveCurrentCommand(message = "保存成功") {
|
saveCurrentCommand(message = "保存成功") {
|
||||||
let updatedData = this.$refs.sidebar?.SaveMenuData();
|
let updatedData = this.$refs.sidebar?.SaveMenuData();
|
||||||
@ -447,17 +249,6 @@ export default {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
getFullscreenScale() {
|
|
||||||
const currentWidth = window.innerWidth - this.sideBarWidth;
|
|
||||||
const currentHeight = window.innerHeight - this.languageBarHeight;
|
|
||||||
const fullWidth = window.innerWidth;
|
|
||||||
const fullHeight = window.innerHeight;
|
|
||||||
|
|
||||||
const scaleX = fullWidth / currentWidth;
|
|
||||||
const scaleY = fullHeight / currentHeight;
|
|
||||||
|
|
||||||
return Math.max(scaleX, scaleY);
|
|
||||||
},
|
|
||||||
toggleFullscreen() {
|
toggleFullscreen() {
|
||||||
this.isFullscreen = !this.isFullscreen;
|
this.isFullscreen = !this.isFullscreen;
|
||||||
|
|
||||||
@ -466,11 +257,8 @@ export default {
|
|||||||
this.$refs.editor.resizeEditor();
|
this.$refs.editor.resizeEditor();
|
||||||
}, 300);
|
}, 300);
|
||||||
},
|
},
|
||||||
showHistory() {
|
|
||||||
this.$refs.history.open();
|
|
||||||
},
|
|
||||||
saveToHistory() {
|
saveToHistory() {
|
||||||
this.$refs.history.tryToSave(
|
this.$refs.editorTools.tryToSave(
|
||||||
this.$refs.editor.getEditorValue(),
|
this.$refs.editor.getEditorValue(),
|
||||||
this.quickcommandInfo.program
|
this.quickcommandInfo.program
|
||||||
);
|
);
|
||||||
@ -487,100 +275,27 @@ export default {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
.menuBtn {
|
|
||||||
background: rgba(0, 0, 0, 0.05);
|
|
||||||
border-radius: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.body--dark .menuBtn {
|
|
||||||
background: rgba(255, 255, 255, 0.07);
|
|
||||||
}
|
|
||||||
|
|
||||||
.fullscreen-btn {
|
|
||||||
z-index: 1000;
|
|
||||||
transform-origin: center;
|
|
||||||
color: #666;
|
|
||||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
|
||||||
transition: all 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
.fullscreen-btn:hover {
|
|
||||||
transform: scale(1.1) translateY(-2px);
|
|
||||||
}
|
|
||||||
|
|
||||||
.fullscreen-btn:active {
|
|
||||||
transform: scale(0.95);
|
|
||||||
transition-duration: 0.1s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-fullscreen {
|
|
||||||
transform: rotate(180deg);
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-fullscreen:hover {
|
|
||||||
transform: rotate(180deg) scale(1.1);
|
|
||||||
}
|
|
||||||
|
|
||||||
.body--dark .fullscreen-btn {
|
|
||||||
background: rgba(255, 255, 255, 0.1);
|
|
||||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2);
|
|
||||||
color: #bbb;
|
|
||||||
}
|
|
||||||
|
|
||||||
.body--dark .fullscreen-btn:hover {
|
|
||||||
background: rgba(255, 255, 255, 0.15);
|
|
||||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 统一过渡效果 */
|
/* 统一过渡效果 */
|
||||||
.sidebar-transition,
|
.sidebar-transition,
|
||||||
.language-bar-transition,
|
.language-bar-transition {
|
||||||
.editor-transition {
|
|
||||||
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
||||||
will-change: transform, left, top, opacity;
|
will-change: transform, left, top, opacity;
|
||||||
}
|
}
|
||||||
|
|
||||||
.editor-container {
|
/* 编辑器动画不一致,可以产生一个回弹效果 */
|
||||||
position: relative;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
.editor-wrapper {
|
|
||||||
position: absolute;
|
|
||||||
right: 0;
|
|
||||||
bottom: 0;
|
|
||||||
height: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.monaco-editor {
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.editor-fullscreen {
|
|
||||||
left: 0 !important;
|
|
||||||
top: 0 !important;
|
|
||||||
z-index: 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
.editor-transition {
|
.editor-transition {
|
||||||
transition: all 0.4s cubic-bezier(0.34, 1.56, 0.64, 1);
|
transition: all 0.4s cubic-bezier(0.34, 1.56, 0.64, 1);
|
||||||
will-change: transform, left, top, opacity;
|
will-change: transform, left, top, opacity;
|
||||||
}
|
}
|
||||||
|
|
||||||
.editor-tools {
|
.command-editor-container {
|
||||||
position: fixed;
|
color: black;
|
||||||
right: 24px;
|
background: white;
|
||||||
bottom: 24px;
|
overflow: hidden
|
||||||
z-index: 1000;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
gap: 12px;
|
|
||||||
transition: all 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.isFullscreen .editor-tools {
|
.body--dark .command-editor-container {
|
||||||
right: 32px;
|
color: white;
|
||||||
bottom: 32px;
|
background: var(--q-dark-page);
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
268
src/components/CommandLanguageBar.vue
Normal file
268
src/components/CommandLanguageBar.vue
Normal file
@ -0,0 +1,268 @@
|
|||||||
|
<template>
|
||||||
|
<div class="row" v-show="!!height">
|
||||||
|
<div class="col">
|
||||||
|
<div>
|
||||||
|
<q-select
|
||||||
|
dense
|
||||||
|
standout="bg-primary text-white"
|
||||||
|
square
|
||||||
|
hide-bottom-space
|
||||||
|
color="primary"
|
||||||
|
transition-show="jump-down"
|
||||||
|
transition-hide="jump-up"
|
||||||
|
@update:model-value="updateProgram"
|
||||||
|
:model-value="modelValue.program"
|
||||||
|
:options="programLanguages"
|
||||||
|
label="环境"
|
||||||
|
>
|
||||||
|
<template v-slot:append>
|
||||||
|
<q-avatar size="lg" square>
|
||||||
|
<img :src="$root.programs[modelValue.program].icon" />
|
||||||
|
</q-avatar>
|
||||||
|
</template>
|
||||||
|
<template v-slot:option="scope">
|
||||||
|
<q-item v-bind="scope.itemProps">
|
||||||
|
<q-item-section avatar>
|
||||||
|
<img width="32" :src="$root.programs[scope.opt].icon" />
|
||||||
|
</q-item-section>
|
||||||
|
<q-item-section>
|
||||||
|
<q-item-label v-html="scope.opt" />
|
||||||
|
</q-item-section>
|
||||||
|
</q-item>
|
||||||
|
</template>
|
||||||
|
</q-select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<q-separator vertical />
|
||||||
|
<div class="col-auto justify-end flex">
|
||||||
|
<q-btn-group unelevated>
|
||||||
|
<q-btn-dropdown
|
||||||
|
v-show="modelValue.program !== 'html'"
|
||||||
|
style="padding: 0 10px"
|
||||||
|
dense
|
||||||
|
flat
|
||||||
|
ref="settings"
|
||||||
|
color="primary"
|
||||||
|
:icon="modelValue.program === 'quickcommand' ? 'insights' : 'settings'"
|
||||||
|
>
|
||||||
|
<q-list>
|
||||||
|
<!-- quickcommand系列按键 -->
|
||||||
|
<q-item
|
||||||
|
clickable
|
||||||
|
v-for="(item, index) in ['keyboard', 'ads_click', 'help']"
|
||||||
|
:key="index"
|
||||||
|
@click="handleQuickCommandAction(index)"
|
||||||
|
v-show="modelValue.program === 'quickcommand'"
|
||||||
|
>
|
||||||
|
<q-item-section avatar>
|
||||||
|
<q-icon :name="item" />
|
||||||
|
</q-item-section>
|
||||||
|
<q-item-section>{{
|
||||||
|
["录制按键", "快捷动作", "查看文档"][index]
|
||||||
|
}}</q-item-section>
|
||||||
|
</q-item>
|
||||||
|
<!-- 自定义解释器 -->
|
||||||
|
<q-item
|
||||||
|
v-for="(item, index) in Object.keys(modelValue.customOptions)"
|
||||||
|
:key="index"
|
||||||
|
v-show="modelValue.program === 'custom'"
|
||||||
|
>
|
||||||
|
<q-input
|
||||||
|
stack-label
|
||||||
|
autofocus
|
||||||
|
dense
|
||||||
|
outlined
|
||||||
|
class="full-width"
|
||||||
|
@blur="matchLanguage"
|
||||||
|
:label="[
|
||||||
|
'解释器路径,如:/opt/python',
|
||||||
|
'运行参数,如:-u',
|
||||||
|
'脚本后缀,不含点,如:py',
|
||||||
|
][index]"
|
||||||
|
:model-value="modelValue.customOptions[item]"
|
||||||
|
@update:model-value="(val) => updateCustomOption(item, val)"
|
||||||
|
>
|
||||||
|
<template v-slot:prepend>
|
||||||
|
<q-icon name="code" />
|
||||||
|
</template>
|
||||||
|
</q-input>
|
||||||
|
</q-item>
|
||||||
|
<!-- 脚本参数 -->
|
||||||
|
<q-item v-show="modelValue.program !== 'quickcommand'">
|
||||||
|
<q-input
|
||||||
|
dense
|
||||||
|
stack-label
|
||||||
|
outlined
|
||||||
|
label="脚本参数"
|
||||||
|
class="full-width"
|
||||||
|
:model-value="modelValue.scptarg"
|
||||||
|
@update:model-value="updateScptarg"
|
||||||
|
>
|
||||||
|
<template v-slot:prepend>
|
||||||
|
<q-icon name="input" />
|
||||||
|
</template>
|
||||||
|
</q-input>
|
||||||
|
</q-item>
|
||||||
|
<!-- 编码设置 -->
|
||||||
|
<q-item
|
||||||
|
v-for="(item, index) in Object.keys(modelValue.charset)"
|
||||||
|
:key="index"
|
||||||
|
v-show="modelValue.program !== 'quickcommand'"
|
||||||
|
>
|
||||||
|
<q-select
|
||||||
|
dense
|
||||||
|
outlined
|
||||||
|
stack-label
|
||||||
|
clearable
|
||||||
|
class="full-width"
|
||||||
|
:label="['脚本编码', '输出编码'][index]"
|
||||||
|
:model-value="modelValue.charset[item]"
|
||||||
|
@update:model-value="(val) => updateCharset(item, val)"
|
||||||
|
:options="['GBK', 'utf8', 'Big5']"
|
||||||
|
type="text"
|
||||||
|
>
|
||||||
|
<template v-slot:prepend>
|
||||||
|
<q-icon :name="['format_size', 'output'][index]" />
|
||||||
|
</template>
|
||||||
|
</q-select>
|
||||||
|
</q-item>
|
||||||
|
</q-list>
|
||||||
|
</q-btn-dropdown>
|
||||||
|
<q-separator vertical inset />
|
||||||
|
<q-btn
|
||||||
|
style="padding: 0 10px"
|
||||||
|
dense
|
||||||
|
flat
|
||||||
|
color="primary"
|
||||||
|
icon="play_arrow"
|
||||||
|
label="运行"
|
||||||
|
@click="$emit('run')"
|
||||||
|
></q-btn>
|
||||||
|
<q-btn
|
||||||
|
flat
|
||||||
|
style="padding: 0 10px"
|
||||||
|
dense
|
||||||
|
v-if="!isRunCodePage"
|
||||||
|
:disable="!canCommandSave"
|
||||||
|
:color="canCommandSave ? 'primary' : 'grey'"
|
||||||
|
icon="save"
|
||||||
|
label="保存"
|
||||||
|
@click="$emit('save')"
|
||||||
|
></q-btn>
|
||||||
|
</q-btn-group>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 移动对话框到这里 -->
|
||||||
|
<q-dialog v-model="showActions">
|
||||||
|
<QuickAction @addAction="addAction" />
|
||||||
|
</q-dialog>
|
||||||
|
<q-dialog v-model="showRecorder" position="bottom">
|
||||||
|
<KeyRecorder @sendKeys="addAction" />
|
||||||
|
</q-dialog>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import QuickAction from "components/popup/QuickAction";
|
||||||
|
import KeyRecorder from "components/popup/KeyRecorder";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'CommandLanguageBar',
|
||||||
|
components: {
|
||||||
|
QuickAction,
|
||||||
|
KeyRecorder,
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
modelValue: {
|
||||||
|
type: Object,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
height: {
|
||||||
|
type: Number,
|
||||||
|
default: 40
|
||||||
|
},
|
||||||
|
canCommandSave: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
isRunCodePage: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
showActions: false,
|
||||||
|
showRecorder: false,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
emits: ['update:modelValue', 'program-changed', 'run', 'save', 'show-recorder', 'show-actions', 'show-help', 'add-action'],
|
||||||
|
computed: {
|
||||||
|
programLanguages() {
|
||||||
|
return Object.keys(this.$root.programs)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
updateProgram(value) {
|
||||||
|
this.$emit('update:modelValue', {
|
||||||
|
...this.modelValue,
|
||||||
|
program: value
|
||||||
|
})
|
||||||
|
this.programChanged(value)
|
||||||
|
},
|
||||||
|
updateCustomOption(key, value) {
|
||||||
|
this.$emit('update:modelValue', {
|
||||||
|
...this.modelValue,
|
||||||
|
customOptions: {
|
||||||
|
...this.modelValue.customOptions,
|
||||||
|
[key]: value
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
updateScptarg(value) {
|
||||||
|
this.$emit('update:modelValue', {
|
||||||
|
...this.modelValue,
|
||||||
|
scptarg: value
|
||||||
|
})
|
||||||
|
},
|
||||||
|
updateCharset(key, value) {
|
||||||
|
this.$emit('update:modelValue', {
|
||||||
|
...this.modelValue,
|
||||||
|
charset: {
|
||||||
|
...this.modelValue.charset,
|
||||||
|
[key]: value
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
programChanged(value) {
|
||||||
|
this.$emit('program-changed', value)
|
||||||
|
if (value === 'custom') {
|
||||||
|
this.$refs.settings.show()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
matchLanguage() {
|
||||||
|
if (!this.modelValue.customOptions.ext) return
|
||||||
|
let language = Object.values(this.$root.programs).filter(
|
||||||
|
program => program.ext === this.modelValue.customOptions.ext
|
||||||
|
)
|
||||||
|
if (language.length) {
|
||||||
|
this.$emit('program-changed', language[0].name)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
handleQuickCommandAction(index) {
|
||||||
|
const actions = [
|
||||||
|
() => this.showRecorder = true,
|
||||||
|
() => this.showActions = true,
|
||||||
|
() => this.showHelp()
|
||||||
|
]
|
||||||
|
actions[index]()
|
||||||
|
},
|
||||||
|
addAction(text) {
|
||||||
|
this.$emit('add-action', text)
|
||||||
|
},
|
||||||
|
showHelp() {
|
||||||
|
window.showUb.docs()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
103
src/components/EditorTools.vue
Normal file
103
src/components/EditorTools.vue
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
<template>
|
||||||
|
<div class="editor-tools">
|
||||||
|
<!-- 历史记录组件 -->
|
||||||
|
<EditorHistory
|
||||||
|
ref="history"
|
||||||
|
:commandCode="commandCode"
|
||||||
|
@restore="$emit('restore', $event)"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<!-- 全屏按钮 -->
|
||||||
|
<q-btn
|
||||||
|
round
|
||||||
|
dense
|
||||||
|
:icon="isFullscreen ? 'fullscreen_exit' : 'fullscreen'"
|
||||||
|
@click="$emit('toggle-fullscreen')"
|
||||||
|
class="fullscreen-btn"
|
||||||
|
:class="{ 'btn-fullscreen': isFullscreen }"
|
||||||
|
>
|
||||||
|
<q-tooltip>{{
|
||||||
|
isFullscreen ? "退出全屏 (F11)" : "全屏编辑 (F11)"
|
||||||
|
}}</q-tooltip>
|
||||||
|
</q-btn>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import EditorHistory from "components/popup/EditorHistory.vue";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'EditorTools',
|
||||||
|
components: {
|
||||||
|
EditorHistory
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
commandCode: {
|
||||||
|
type: String,
|
||||||
|
default: 'temp'
|
||||||
|
},
|
||||||
|
isFullscreen: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
emits: ['restore', 'toggle-fullscreen'],
|
||||||
|
methods: {
|
||||||
|
showHistory() {
|
||||||
|
this.$refs.history.open();
|
||||||
|
},
|
||||||
|
tryToSave(content, program) {
|
||||||
|
this.$refs.history.tryToSave(content, program);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.editor-tools {
|
||||||
|
position: fixed;
|
||||||
|
right: 24px;
|
||||||
|
bottom: 24px;
|
||||||
|
z-index: 1000;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 12px;
|
||||||
|
transition: all 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.fullscreen-btn {
|
||||||
|
z-index: 1000;
|
||||||
|
transform-origin: center;
|
||||||
|
color: #666;
|
||||||
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
||||||
|
transition: all 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.fullscreen-btn:hover {
|
||||||
|
transform: scale(1.1) translateY(-2px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.fullscreen-btn:active {
|
||||||
|
transform: scale(0.95);
|
||||||
|
transition-duration: 0.1s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-fullscreen {
|
||||||
|
transform: rotate(180deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-fullscreen:hover {
|
||||||
|
transform: rotate(180deg) scale(1.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.body--dark .fullscreen-btn {
|
||||||
|
background: rgba(255, 255, 255, 0.1);
|
||||||
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2);
|
||||||
|
color: #bbb;
|
||||||
|
}
|
||||||
|
|
||||||
|
.body--dark .fullscreen-btn:hover {
|
||||||
|
background: rgba(255, 255, 255, 0.15);
|
||||||
|
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
|
||||||
|
}
|
||||||
|
</style>
|
@ -35,21 +35,11 @@
|
|||||||
background: var(--q-dark-page);
|
background: var(--q-dark-page);
|
||||||
}
|
}
|
||||||
|
|
||||||
.container {
|
|
||||||
color: black;
|
|
||||||
background: white;
|
|
||||||
}
|
|
||||||
|
|
||||||
body {
|
body {
|
||||||
background: #f4f4f4;
|
background: #f4f4f4;
|
||||||
color: #333;
|
color: #333;
|
||||||
}
|
}
|
||||||
|
|
||||||
.body--dark .container {
|
|
||||||
color: white;
|
|
||||||
background: var(--q-dark-page);
|
|
||||||
}
|
|
||||||
|
|
||||||
.q-tooltip {
|
.q-tooltip {
|
||||||
font-size: 11px;
|
font-size: 11px;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user