2
0
mirror of https://github.com/acepanel/panel.git synced 2026-02-08 15:24:28 +08:00
Files
panel/web/src/components/file-editor/EditorStatusBar.vue
2026-01-12 06:05:08 +08:00

193 lines
4.5 KiB
Vue

<script setup lang="ts">
import { useEditorStore } from '@/store'
import { useThemeVars } from 'naive-ui'
import { useGettext } from 'vue3-gettext'
const { $gettext } = useGettext()
const editorStore = useEditorStore()
const themeVars = useThemeVars()
// 支持的语言列表
const languages = [
'plaintext',
'javascript',
'typescript',
'html',
'css',
'scss',
'less',
'json',
'xml',
'yaml',
'markdown',
'python',
'go',
'java',
'php',
'ruby',
'rust',
'c',
'cpp',
'csharp',
'shell',
'sql',
'nginx',
'dockerfile'
]
// 支持的编码列表
const encodings = ['utf-8', 'gbk', 'gb2312', 'iso-8859-1', 'utf-16', 'utf-16le', 'utf-16be']
// 缩进选项
const indentOptions = computed(() => [
{ label: `${$gettext('Spaces')}: 2`, value: { tabSize: 2, insertSpaces: true } },
{ label: `${$gettext('Spaces')}: 4`, value: { tabSize: 4, insertSpaces: true } },
{ label: `${$gettext('Tabs')}: 2`, value: { tabSize: 2, insertSpaces: false } },
{ label: `${$gettext('Tabs')}: 4`, value: { tabSize: 4, insertSpaces: false } }
])
// 当前缩进显示
const currentIndent = computed(() => {
const { tabSize, insertSpaces } = editorStore.settings
return insertSpaces ? `${$gettext('Spaces')}: ${tabSize}` : `${$gettext('Tabs')}: ${tabSize}`
})
// 更新行分隔符
function handleLineEndingChange(value: 'LF' | 'CRLF') {
if (editorStore.activeTab) {
editorStore.updateLineEnding(editorStore.activeTab.path, value)
}
}
// 更新编码
function handleEncodingChange(value: string) {
if (editorStore.activeTab) {
editorStore.updateEncoding(editorStore.activeTab.path, value)
}
}
// 更新语言
function handleLanguageChange(value: string) {
if (editorStore.activeTab) {
editorStore.updateLanguage(editorStore.activeTab.path, value)
}
}
// 更新缩进
function handleIndentChange(value: { tabSize: number; insertSpaces: boolean }) {
editorStore.updateSettings(value)
}
</script>
<template>
<div class="editor-status-bar" v-if="editorStore.activeTab">
<!-- 文件路径 -->
<div class="status-item path">
<n-ellipsis style="max-width: 400px">
{{ editorStore.activeTab.path }}
</n-ellipsis>
</div>
<div class="status-spacer" />
<!-- 行分隔符 -->
<n-popselect
:value="editorStore.activeTab.lineEnding"
:options="[
{ label: 'LF', value: 'LF' },
{ label: 'CRLF', value: 'CRLF' }
]"
@update:value="handleLineEndingChange"
>
<div class="status-item clickable">
{{ editorStore.activeTab.lineEnding }}
</div>
</n-popselect>
<!-- 光标位置 -->
<div class="status-item">
{{ $gettext('Ln') }} {{ editorStore.activeTab.cursorLine }}, {{ $gettext('Col') }}
{{ editorStore.activeTab.cursorColumn }}
</div>
<!-- 缩进 -->
<n-popselect :options="indentOptions" @update:value="handleIndentChange">
<div class="status-item clickable">
{{ currentIndent }}
</div>
</n-popselect>
<!-- 编码 -->
<n-popselect
:value="editorStore.activeTab.encoding"
:options="encodings.map((e) => ({ label: e.toUpperCase(), value: e }))"
@update:value="handleEncodingChange"
scrollable
>
<div class="status-item clickable">
{{ $gettext('Encoding') }}: {{ editorStore.activeTab.encoding }}
</div>
</n-popselect>
<!-- 语言 -->
<n-popselect
:value="editorStore.activeTab.language"
:options="languages.map((l) => ({ label: l, value: l }))"
@update:value="handleLanguageChange"
scrollable
>
<div class="status-item clickable">
{{ $gettext('Language') }}: {{ editorStore.activeTab.language }}
</div>
</n-popselect>
</div>
<div class="editor-status-bar empty" v-else>
<span class="status-item">{{ $gettext('No file open') }}</span>
</div>
</template>
<style scoped lang="scss">
.editor-status-bar {
display: flex;
align-items: center;
gap: 4px;
padding: 0 12px;
font-size: 12px;
background: v-bind('themeVars.cardColor');
border-top: 1px solid v-bind('themeVars.borderColor');
flex-shrink: 0;
height: 26px;
line-height: 26px;
&.empty {
color: v-bind('themeVars.textColor3');
}
}
.status-item {
display: flex;
align-items: center;
gap: 4px;
padding: 2px 8px;
border-radius: 4px;
white-space: nowrap;
&.clickable {
cursor: pointer;
&:hover {
background: v-bind('themeVars.buttonColor2Hover');
}
}
&.path {
min-width: 0;
flex-shrink: 1;
}
}
.status-spacer {
flex: 1;
}
</style>