mirror of
https://github.com/purocean/yn.git
synced 2026-10-13 07:38:54 +08:00
增加状态栏菜单
This commit is contained in:
@@ -1,125 +0,0 @@
|
||||
<template>
|
||||
<div class="repository-switch">
|
||||
<div class="current" v-if="currentRepo">仓库:{{currentRepo.name}}</div>
|
||||
<div class="current" v-else>未选择仓库</div>
|
||||
<ul class="list">
|
||||
<li v-for="(path, name) in repositories" :key="name" :title="path" @click="choose({name, path})">{{name}}</li>
|
||||
</ul>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, onBeforeMount, onBeforeUnmount, toRefs, watch } from 'vue'
|
||||
import { useStore } from 'vuex'
|
||||
import file from '../useful/file'
|
||||
import { useBus } from '../useful/bus'
|
||||
import { $args } from '../useful/global-args'
|
||||
|
||||
export default defineComponent({
|
||||
name: 'repository-switch',
|
||||
setup () {
|
||||
const store = useStore()
|
||||
const bus = useBus()
|
||||
|
||||
const { currentRepo, repositories } = toRefs(store.state)
|
||||
|
||||
function choose (repo: any) {
|
||||
if (repo.name !== currentRepo.value?.name) {
|
||||
store.commit('setCurrentRepo', repo)
|
||||
}
|
||||
}
|
||||
|
||||
function chooseRepoByName (name?: string) {
|
||||
if (name && repositories.value[name]) {
|
||||
choose({ name, path: repositories.value[name] })
|
||||
}
|
||||
}
|
||||
|
||||
function initRepo () {
|
||||
const initRepoName = $args().get('init-repo')
|
||||
const initFilePath = $args().get('init-file')
|
||||
|
||||
if (initRepoName) {
|
||||
chooseRepoByName(initRepoName)
|
||||
}
|
||||
|
||||
if (initFilePath) {
|
||||
store.commit('setCurrentFile', { repo: currentRepo.value.name, name: file.basename(initFilePath), path: initFilePath })
|
||||
}
|
||||
}
|
||||
|
||||
onBeforeMount(() => {
|
||||
bus.on('switch-repo-by-name', chooseRepoByName)
|
||||
bus.on('editor-ready', initRepo)
|
||||
store.dispatch('fetchRepositories')
|
||||
})
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
bus.off('switch-repo-by-name', chooseRepoByName)
|
||||
bus.off('editor-ready', initRepo)
|
||||
})
|
||||
|
||||
watch(repositories, val => {
|
||||
const keys = Object.keys(val)
|
||||
if (!currentRepo.value || keys.indexOf(currentRepo.value.name) < 0) {
|
||||
if (keys.length > 0) {
|
||||
const name = keys[0]
|
||||
store.commit('setCurrentRepo', { name, path: val[name] })
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
return {
|
||||
currentRepo,
|
||||
repositories,
|
||||
choose,
|
||||
}
|
||||
},
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.repository-switch {
|
||||
width: 100px;
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.current {
|
||||
padding: 0 .3em;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.repository-switch:hover {
|
||||
background: #333030;
|
||||
}
|
||||
|
||||
.repository-switch:hover .list {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.list {
|
||||
width: 100px;
|
||||
margin: 0;
|
||||
list-style: none;
|
||||
background: #333030;
|
||||
padding: 4px 0;
|
||||
display: none;
|
||||
position: fixed;
|
||||
bottom: 20px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.list li {
|
||||
padding: 4px .6em;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.list li:hover {
|
||||
background: #252525;
|
||||
}
|
||||
</style>
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div class="status-bar">
|
||||
<RepositorySwitch class="left"></RepositorySwitch>
|
||||
<StatusBarMenu class="left" />
|
||||
<div class="right">
|
||||
<div class="document-info">
|
||||
<span>行:{{documentInfo.line}}</span>
|
||||
@@ -25,13 +25,13 @@
|
||||
import { defineComponent, onBeforeUnmount, onMounted, toRefs } from 'vue'
|
||||
import { useStore } from 'vuex'
|
||||
import { useBus } from '../useful/bus'
|
||||
import RepositorySwitch from './RepositorySwitch.vue'
|
||||
import StatusBarMenu from './StatusBarMenu.vue'
|
||||
import SvgIcon from '../components/SvgIcon.vue'
|
||||
import { isAction, getActionLabel } from '../useful/shortcut'
|
||||
|
||||
export default defineComponent({
|
||||
name: 'status-bar',
|
||||
components: { RepositorySwitch, SvgIcon },
|
||||
components: { StatusBarMenu, SvgIcon },
|
||||
setup () {
|
||||
const bus = useBus()
|
||||
const store = useStore()
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
<template>
|
||||
<div class="status-bar-menu-wrapper">
|
||||
<div class="status-bar-menu" v-for="menu in list" :key="menu.id">
|
||||
<div class="title">{{menu.title}}</div>
|
||||
<ul class="list" v-if="showList">
|
||||
<li v-for="item in menu.list" :key="item.id" :title="item.tips" @click="handleItemClick(item)">{{item.title}}</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, nextTick, onBeforeUnmount, ref } from 'vue'
|
||||
import { useBus } from '../useful/bus'
|
||||
import { getStatusBarMenus, StatusBarMenuItem } from '../useful/plugin'
|
||||
|
||||
export default defineComponent({
|
||||
name: 'status-bar-menu',
|
||||
setup () {
|
||||
const bus = useBus()
|
||||
const list = ref(getStatusBarMenus())
|
||||
const showList = ref(true)
|
||||
|
||||
const handleItemClick = (item: StatusBarMenuItem) => {
|
||||
item.onClick && item.onClick(item)
|
||||
showList.value = false
|
||||
nextTick(() => {
|
||||
showList.value = true
|
||||
})
|
||||
}
|
||||
|
||||
const updateMenu = () => {
|
||||
list.value = getStatusBarMenus()
|
||||
console.log('rest', getStatusBarMenus())
|
||||
}
|
||||
|
||||
bus.on('status-bar-menu-update', updateMenu)
|
||||
onBeforeUnmount(() => {
|
||||
bus.off('status-bar-menu-update', updateMenu)
|
||||
})
|
||||
|
||||
return {
|
||||
list,
|
||||
showList,
|
||||
handleItemClick
|
||||
}
|
||||
},
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.status-bar-menu {
|
||||
width: 100px;
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.title {
|
||||
padding: 0 .3em;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.status-bar-menu:hover {
|
||||
background: #2f3031;
|
||||
}
|
||||
|
||||
.status-bar-menu:hover .list {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.list {
|
||||
width: 100px;
|
||||
margin: 0;
|
||||
list-style: none;
|
||||
background: #37393a;
|
||||
padding: 4px 0;
|
||||
display: none;
|
||||
position: fixed;
|
||||
bottom: 20px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.list li {
|
||||
padding: 4px .6em;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.list li:hover {
|
||||
background: #2f3031;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,78 @@
|
||||
import { Plugin } from '@/useful/plugin'
|
||||
import store from '@/store'
|
||||
import { useBus } from '@/useful/bus'
|
||||
import { $args } from '@/useful/global-args'
|
||||
import file from '@/useful/file'
|
||||
|
||||
export default {
|
||||
name: 'repository-switch',
|
||||
register: ctx => {
|
||||
const bus = useBus()
|
||||
|
||||
function choose (repo: any) {
|
||||
const { currentRepo } = store.state
|
||||
if (repo.name !== currentRepo.name) {
|
||||
store.commit('setCurrentRepo', repo)
|
||||
}
|
||||
}
|
||||
|
||||
function chooseRepoByName (name?: string) {
|
||||
const { repositories } = store.state
|
||||
if (name && repositories[name]) {
|
||||
choose({ name, path: repositories[name] })
|
||||
}
|
||||
}
|
||||
|
||||
function initRepo () {
|
||||
const { currentRepo } = store.state
|
||||
|
||||
const initRepoName = $args().get('init-repo')
|
||||
const initFilePath = $args().get('init-file')
|
||||
|
||||
if (initRepoName) {
|
||||
chooseRepoByName(initRepoName)
|
||||
}
|
||||
|
||||
if (initFilePath) {
|
||||
store.commit('setCurrentFile', { repo: currentRepo.name, name: file.basename(initFilePath), path: initFilePath })
|
||||
}
|
||||
}
|
||||
|
||||
function updateMenu () {
|
||||
const { currentRepo, repositories } = store.state
|
||||
ctx.updateStatusBarMenu({
|
||||
id: 'repository-switch',
|
||||
title: currentRepo ? `仓库: ${currentRepo.name}` : '未选择仓库',
|
||||
list: Object.keys(repositories).map(name => {
|
||||
const path = repositories[name]
|
||||
|
||||
return {
|
||||
id: name,
|
||||
type: 'normal',
|
||||
title: name,
|
||||
tips: path,
|
||||
onClick: () => choose({ name, path })
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
bus.on('switch-repo-by-name', chooseRepoByName)
|
||||
bus.on('editor-ready', initRepo)
|
||||
store.dispatch('fetchRepositories')
|
||||
|
||||
store.watch(() => store.state.repositories, updateMenu)
|
||||
store.watch(() => store.state.currentRepo, updateMenu)
|
||||
|
||||
store.watch(() => store.state.repositories, val => {
|
||||
const { currentRepo } = store.state
|
||||
const keys = Object.keys(val)
|
||||
if (!currentRepo || keys.indexOf(currentRepo.name) < 0) {
|
||||
if (keys.length > 0) {
|
||||
const name = keys[0]
|
||||
store.commit('setCurrentRepo', { name, path: val[name] })
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
} as Plugin
|
||||
@@ -36,7 +36,7 @@ const getLastOpenFile = (repoName?: string) => {
|
||||
|
||||
export default createStore({
|
||||
state: {
|
||||
repositories: {},
|
||||
repositories: {} as any,
|
||||
tree: null,
|
||||
showSide: Storage.get('showSide', true),
|
||||
showView: Storage.get('showView', true),
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { addAction } from './shortcut'
|
||||
import { getLogger } from './utils'
|
||||
import Markdown from 'markdown-it'
|
||||
import { useBus } from './bus'
|
||||
|
||||
export type HookType = 'ON_STARTUP'
|
||||
| 'ON_VIEW_ELEMENT_CLICK'
|
||||
@@ -17,15 +18,31 @@ export interface Plugin {
|
||||
register?: (ctx: Ctx) => void;
|
||||
}
|
||||
|
||||
type HookFun = (...args: any[]) => boolean | void | Promise<boolean | void>
|
||||
export type HookFun = (...args: any[]) => boolean | void | Promise<boolean | void>
|
||||
|
||||
export type StatusBarMenuItem = {
|
||||
id: string;
|
||||
type: 'normal';
|
||||
title: string;
|
||||
tips?: string;
|
||||
onClick?: (item: StatusBarMenuItem) => void;
|
||||
}
|
||||
|
||||
export interface StatusBarMenu {
|
||||
id: string;
|
||||
title: string;
|
||||
tips?: string;
|
||||
onClick?: (menu: StatusBarMenu) => void;
|
||||
list?: (StatusBarMenuItem | { type: 'separator' })[];
|
||||
}
|
||||
|
||||
const logger = getLogger('plugin')
|
||||
const bus = useBus()
|
||||
|
||||
const plugins: {[name: string]: Plugin} = {}
|
||||
|
||||
const hooks: { [key in HookType]?: {fun: HookFun; once: boolean}[] } = {}
|
||||
|
||||
const markdownItPlugins: {plugin: any; params: any}[] = []
|
||||
const statusBarMenus: { [key: string]: StatusBarMenu } = {}
|
||||
|
||||
const ctx = {
|
||||
registerShortcutAction (name: string, keys: (string | number)[]) {
|
||||
@@ -45,6 +62,14 @@ const ctx = {
|
||||
},
|
||||
registerMarkdownItPlugin: (plugin: (md: Markdown, ...args: any) => void, params?: any) => {
|
||||
markdownItPlugins.push({ plugin, params })
|
||||
},
|
||||
updateStatusBarMenu: (menu: StatusBarMenu) => {
|
||||
statusBarMenus[menu.id] = menu
|
||||
bus.emit('status-bar-menu-update', menu)
|
||||
},
|
||||
removeStatusBarMenu: (id: string) => {
|
||||
delete statusBarMenus[id]
|
||||
bus.emit('status-bar-menu-update')
|
||||
}
|
||||
}
|
||||
|
||||
@@ -60,6 +85,7 @@ export const init = () => {
|
||||
logger.debug('init')
|
||||
|
||||
const localPlugins = [
|
||||
require('@/plugins/repository-switch'),
|
||||
require('@/plugins/markdown-source-line'),
|
||||
require('@/plugins/markdown-toc'),
|
||||
require('@/plugins/markdown-code'),
|
||||
@@ -100,5 +126,6 @@ export const triggerHook = async (type: HookType, ...args: any[]) => {
|
||||
}
|
||||
|
||||
export const getMarkdownItPlugins = () => markdownItPlugins
|
||||
export const getStatusBarMenus = () => Object.values(statusBarMenus)
|
||||
|
||||
init()
|
||||
|
||||
Reference in New Issue
Block a user