refactor: better code

This commit is contained in:
purocean
2024-11-24 23:42:58 +08:00
parent 77d89a4637
commit f1b82567e8
5 changed files with 335 additions and 227 deletions
-1
View File
@@ -49,7 +49,6 @@ function handleCommand (e: MouseEvent) {
<style lang="scss" scoped>
.indexer-status {
width: 300px;
position: relative;
& > p {
+1
View File
@@ -54,6 +54,7 @@ const icons: { [key: string]: string } = {
'print-solid': '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="currentColor" d="M128 0C92.7 0 64 28.7 64 64v96h64V64H354.7L384 93.3V160h64V93.3c0-17-6.7-33.3-18.7-45.3L400 18.7C388 6.7 371.7 0 354.7 0H128zM384 352v32 64H128V384 368 352H384zm64 32h32c17.7 0 32-14.3 32-32V256c0-35.3-28.7-64-64-64H64c-35.3 0-64 28.7-64 64v96c0 17.7 14.3 32 32 32H64v64c0 35.3 28.7 64 64 64H384c35.3 0 64-28.7 64-64V384zm-16-88c-13.3 0-24-10.7-24-24s10.7-24 24-24s24 10.7 24 24s-10.7 24-24 24z"/></svg>',
'file-export-solid': '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="currentColor" d="M32 64C32 28.7 60.7 0 96 0H256V128c0 17.7 14.3 32 32 32H416V288H248c-13.3 0-24 10.7-24 24s10.7 24 24 24H416V448c0 35.3-28.7 64-64 64H96c-35.3 0-64-28.7-64-64V64zM416 336V288H526.1l-39-39c-9.4-9.4-9.4-24.6 0-33.9s24.6-9.4 33.9 0l80 80c9.4 9.4 9.4 24.6 0 33.9l-80 80c-9.4 9.4-24.6 9.4-33.9 0s-9.4-24.6 0-33.9l39-39H416zm0-208H288V0L416 128z"/></svg>',
'link-solid': '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="currentColor" d="M326.6 185.4c59.7 59.8 58.9 155.7 .4 214.6-.1 .1-.2 .3-.4 .4l-67.2 67.2c-59.3 59.3-155.7 59.3-215 0-59.3-59.3-59.3-155.7 0-215l37.1-37.1c9.8-9.8 26.8-3.3 27.3 10.6 .6 17.7 3.8 35.5 9.7 52.7 2 5.8 .6 12.3-3.8 16.6l-13.1 13.1c-28 28-28.9 73.7-1.2 102 28 28.6 74.1 28.7 102.3 .5l67.2-67.2c28.2-28.2 28.1-73.8 0-101.8-3.7-3.7-7.4-6.6-10.3-8.6a16 16 0 0 1 -6.9-12.6c-.4-10.6 3.3-21.5 11.7-29.8l21.1-21.1c5.5-5.5 14.2-6.2 20.6-1.7a152.5 152.5 0 0 1 20.5 17.2zM467.5 44.4c-59.3-59.3-155.7-59.3-215 0l-67.2 67.2c-.1 .1-.3 .3-.4 .4-58.6 58.9-59.4 154.8 .4 214.6a152.5 152.5 0 0 0 20.5 17.2c6.4 4.5 15.1 3.8 20.6-1.7l21.1-21.1c8.4-8.4 12.1-19.2 11.7-29.8a16 16 0 0 0 -6.9-12.6c-2.9-2-6.6-4.9-10.3-8.6-28.1-28.1-28.2-73.6 0-101.8l67.2-67.2c28.2-28.2 74.3-28.1 102.3 .5 27.8 28.3 26.9 73.9-1.2 102l-13.1 13.1c-4.4 4.4-5.8 10.8-3.8 16.6 5.9 17.2 9 35 9.7 52.7 .5 13.9 17.5 20.4 27.3 10.6l37.1-37.1c59.3-59.3 59.3-155.7 0-215z"/></svg>',
'location-crosshairs-solid': '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="currentColor" d="M256 0c17.7 0 32 14.3 32 32l0 34.7C368.4 80.1 431.9 143.6 445.3 224l34.7 0c17.7 0 32 14.3 32 32s-14.3 32-32 32l-34.7 0C431.9 368.4 368.4 431.9 288 445.3l0 34.7c0 17.7-14.3 32-32 32s-32-14.3-32-32l0-34.7C143.6 431.9 80.1 368.4 66.7 288L32 288c-17.7 0-32-14.3-32-32s14.3-32 32-32l34.7 0C80.1 143.6 143.6 80.1 224 66.7L224 32c0-17.7 14.3-32 32-32zM128 256a128 128 0 1 0 256 0 128 128 0 1 0 -256 0zm128-80a80 80 0 1 1 0 160 80 80 0 1 1 0-160z"/></svg>',
'codicon-regex': '<svg viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" fill="currentColor"><path fill-rule="evenodd" clip-rule="evenodd" d="M10.012 2h.976v3.113l2.56-1.557.486.885L11.47 6l2.564 1.559-.485.885-2.561-1.557V10h-.976V6.887l-2.56 1.557-.486-.885L9.53 6 6.966 4.441l.485-.885 2.561 1.557V2zM2 10h4v4H2v-4z"/></svg>',
'codicon-case-sensitive': '<svg viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" fill="currentColor"><path d="M8.85352 11.7021H7.85449L7.03809 9.54297H3.77246L3.00439 11.7021H2L4.9541 4H5.88867L8.85352 11.7021ZM6.74268 8.73193L5.53418 5.4502C5.49479 5.34277 5.4554 5.1709 5.41602 4.93457H5.39453C5.35872 5.15299 5.31755 5.32487 5.271 5.4502L4.07324 8.73193H6.74268Z"/><path d="M13.756 11.7021H12.8752V10.8428H12.8537C12.4706 11.5016 11.9066 11.8311 11.1618 11.8311C10.6139 11.8311 10.1843 11.686 9.87273 11.396C9.56479 11.106 9.41082 10.721 9.41082 10.2412C9.41082 9.21354 10.016 8.61556 11.2262 8.44727L12.8752 8.21631C12.8752 7.28174 12.4974 6.81445 11.7419 6.81445C11.0794 6.81445 10.4815 7.04004 9.94793 7.49121V6.58887C10.4886 6.24512 11.1117 6.07324 11.8171 6.07324C13.1097 6.07324 13.756 6.75716 13.756 8.125V11.7021ZM12.8752 8.91992L11.5485 9.10254C11.1403 9.15983 10.8324 9.26188 10.6247 9.40869C10.417 9.55192 10.3132 9.80794 10.3132 10.1768C10.3132 10.4453 10.4081 10.6655 10.5978 10.8374C10.7912 11.0057 11.0472 11.0898 11.3659 11.0898C11.8027 11.0898 12.1626 10.9377 12.4455 10.6333C12.7319 10.3254 12.8752 9.93685 12.8752 9.46777V8.91992Z"/></svg>',
'codicon-whole-word': '<svg viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" fill="currentColor"><path fill-rule="evenodd" clip-rule="evenodd" d="M0 11H1V13H15V11H16V14H15H1H0V11Z"/><path d="M6.84048 11H5.95963V10.1406H5.93814C5.555 10.7995 4.99104 11.1289 4.24625 11.1289C3.69839 11.1289 3.26871 10.9839 2.95718 10.6938C2.64924 10.4038 2.49527 10.0189 2.49527 9.53906C2.49527 8.51139 3.10041 7.91341 4.3107 7.74512L5.95963 7.51416C5.95963 6.57959 5.58186 6.1123 4.82632 6.1123C4.16389 6.1123 3.56591 6.33789 3.03238 6.78906V5.88672C3.57307 5.54297 4.19612 5.37109 4.90152 5.37109C6.19416 5.37109 6.84048 6.05501 6.84048 7.42285V11ZM5.95963 8.21777L4.63297 8.40039C4.22476 8.45768 3.91682 8.55973 3.70914 8.70654C3.50145 8.84977 3.39761 9.10579 3.39761 9.47461C3.39761 9.74316 3.4925 9.96338 3.68228 10.1353C3.87564 10.3035 4.13166 10.3877 4.45035 10.3877C4.8872 10.3877 5.24706 10.2355 5.52994 9.93115C5.8164 9.62321 5.95963 9.2347 5.95963 8.76562V8.21777Z"/><path d="M9.3475 10.2051H9.32601V11H8.44515V2.85742H9.32601V6.4668H9.3475C9.78076 5.73633 10.4146 5.37109 11.2489 5.37109C11.9543 5.37109 12.5057 5.61816 12.9032 6.1123C13.3042 6.60286 13.5047 7.26172 13.5047 8.08887C13.5047 9.00911 13.2809 9.74674 12.8333 10.3018C12.3857 10.8532 11.7734 11.1289 10.9964 11.1289C10.2695 11.1289 9.71989 10.821 9.3475 10.2051ZM9.32601 7.98682V8.75488C9.32601 9.20964 9.47282 9.59635 9.76644 9.91504C10.0636 10.2301 10.4396 10.3877 10.8944 10.3877C11.4279 10.3877 11.8451 10.1836 12.1458 9.77539C12.4502 9.36719 12.6024 8.79964 12.6024 8.07275C12.6024 7.46045 12.4609 6.98063 12.1781 6.6333C11.8952 6.28597 11.512 6.1123 11.0286 6.1123C10.5166 6.1123 10.1048 6.29134 9.7933 6.64941C9.48177 7.00391 9.32601 7.44971 9.32601 7.98682Z"/></svg>',
-226
View File
@@ -1,226 +0,0 @@
import { ROOT_REPO_NAME_PREFIX } from '@share/misc'
import IndexStatus from '@fe/components/IndexStatus.vue'
import GroupTabs from '@fe/components/GroupTabs.vue'
import SvgIcon from '@fe/components/SvgIcon.vue'
import type { Plugin } from '@fe/context'
import type { Doc, PositionState } from '@fe/types'
export default {
name: 'view-links',
register: (ctx) => {
const actionName = 'plugin.view-links.view-document-links'
const ViewLinksComponent = ctx.lib.vue.defineComponent(() => {
type TabItemValue = 'links' | 'back-links'
type ListItem = {doc: Doc, position?: PositionState | null}
const currentTab = ctx.lib.vue.ref<TabItemValue>('links')
const title = ctx.lib.vue.ref('')
const list = ctx.lib.vue.ref<(ListItem[] | null)>(null)
const { $t } = ctx.i18n.useI18n()
const currentFileRepo = ctx.store.state.currentFile?.repo
const currentFilePath = ctx.store.state.currentFile?.path
const currentFileName = ctx.store.state.currentFile?.name
const buildList = (type: TabItemValue) => {
list.value = null
title.value = currentFileName ? {
links: $t.value('view-links.links-in', currentFileName),
'back-links': $t.value('view-links.back-links-for', currentFileName),
}[type] : ''
if (!ctx.store.state.currentRepoIndexStatus?.status.ready || currentFileRepo !== ctx.store.state.currentRepoIndexStatus?.repo || !currentFilePath) {
list.value = []
return
}
const dm = ctx.indexer.getDocumentsManager()
if (type === 'links') {
dm.findByRepoAndPath(currentFileRepo, currentFilePath).then(doc => {
if (currentTab.value === 'links') {
list.value = doc ? doc.links.filter(link => !!link.internal).map(link => ({
doc: { type: 'file', repo: currentFileRepo, path: link.internal!, name: ctx.utils.path.basename(link.internal!) },
position: link.position
})) : []
}
})
} else if (type === 'back-links') {
const data: ListItem[] = []
dm.getTable().where({ repo: currentFileRepo }).each(doc => {
doc.links.forEach(link => {
if (link.internal === currentFilePath) {
const position: PositionState = { line: link.blockMap[0] + 1 }
data.push({ doc: { type: 'file', repo: currentFileRepo, path: doc.path, name: ctx.utils.path.basename(doc.path) }, position })
}
})
}).then(() => {
if (currentTab.value === 'back-links') {
list.value = data
}
})
}
}
const close = () => {
ctx.ui.useFixedFloat().hide()
}
const handleKeyDown = (e: KeyboardEvent) => {
if (e.key === 'Escape') {
close()
}
}
ctx.lib.vue.watch(() => currentTab.value, buildList)
ctx.lib.vue.watch(() => ctx.store.state.currentRepoIndexStatus?.status.ready, () => buildList(currentTab.value))
ctx.lib.vue.watch(() => [ctx.store.state.currentFile?.repo, ctx.store.state.currentRepo?.name], (val) => {
if (val[0] !== currentFileRepo || val[1] !== currentFileRepo) {
close()
}
}, { flush: 'post' })
ctx.lib.vue.onMounted(() => {
buildList(currentTab.value)
ctx.registerHook('GLOBAL_KEYDOWN', handleKeyDown)
})
ctx.lib.vue.onBeforeUnmount(() => {
ctx.removeHook('GLOBAL_KEYDOWN', handleKeyDown)
})
return () => <IndexStatus>
<div class="view-links-close-btn" onClick={close} title={$t.value('close') + ' ' + ctx.keybinding.getKeyLabel(ctx.keybinding.Escape)}>
<SvgIcon name="times" width="14px" height='14px' />
</div>
<div style={{ display: 'flex', justifyContent: 'center', borderBottom: '1px solid var(--g-color-85)', padding: '5px 0' }}>
<GroupTabs tabs={[
{ value: 'links', label: $t.value('view-links.links') },
{ value: 'back-links', label: $t.value('view-links.back-links') },
]} size="small" modelValue={currentTab.value} onUpdate:model-value={(v: any) => { currentTab.value = v }} />
</div>
{(list.value && list.value.length) ? <ol style={{ maxHeight: '60vh', overflowY: 'auto', margin: '0', padding: '8px 10px 8px 40px', backgroundColor: ' rgba(var(--g-foreground-color-rgb), 0.025)', overflowWrap: 'break-word' }}>
{list.value.map(item => {
return <li class="view-links-ol-li">
<a href="javascript:void(0)" onClick={e => {
e.preventDefault()
ctx.doc.switchDoc(item.doc, { source: 'view-links', position: item.position })
}} title={item.doc.path}>{item.doc.name}</a>
</li>
})}
</ol> : <div style={{ textAlign: 'center', fontStyle: 'italic', color: 'var(--g-color-45)', padding: '20px 0 10px', fontSize: '14px' }}>
{list.value ? <span>{$t.value('view-links.no-result')}</span> : <span>Loading...</span>}
</div>}
{title && <div class="view-links-footer">
{title.value} &nbsp;
<a class="view-links-re-index-btn" href="javascript:void(0)" onClick={e => {
e.preventDefault()
ctx.indexer.rebuildCurrentRepo()
}} title={`Indexed: ${ctx.store.state.currentRepoIndexStatus?.status?.indexed}, Total: ${ctx.store.state.currentRepoIndexStatus?.status?.total}, Cost: ${ctx.store.state.currentRepoIndexStatus?.status?.cost}ms`}>
{$t.value('view-links.re-index')}
</a>
</div>}
</IndexStatus>
})
function showLinks () {
ctx.ui.useFixedFloat().show({
right: '20px',
top: ctx.env.isElectron ? '66px' : '36px',
component: ViewLinksComponent,
closeOnBlur: false,
onBlur (byClickSelf) {
if (!byClickSelf && ctx.store.state.currentRepoIndexStatus?.repo !== ctx.store.state.currentFile?.repo) {
ctx.ui.useFixedFloat().hide()
}
},
})
}
function when () {
const currentRepoName = ctx.store.state.currentRepo?.name
const currentFileRepoName = ctx.store.state.currentFile?.repo
const result = !ctx.args.FLAG_DEMO && // not in demo mode
ctx.args.MODE === 'normal' && // in normal mode
currentRepoName && // has current repo
currentFileRepoName && // has current file
currentFileRepoName !== ctx.args.HELP_REPO_NAME && // current file is not in help repo
!currentFileRepoName.startsWith(ROOT_REPO_NAME_PREFIX) // current file is not in root repo
return !!result
}
ctx.action.registerAction({
name: actionName,
forUser: true,
description: ctx.i18n.t('command-desc.plugin_view-links_view-document-links'),
handler: showLinks,
when,
})
ctx.workbench.FileTabs.tapActionBtns(btns => {
if (when()) {
btns.push({ type: 'separator' })
btns.push({
type: 'normal',
icon: 'link-solid',
title: 'Links',
onClick: () => {
ctx.action.getActionHandler(actionName)()
},
})
btns.push({ type: 'separator' })
}
})
ctx.theme.addStyles(`
.view-links-close-btn {
position: absolute;
right: 3px;
top: 3px;
width: 20px;
height: 20px;
display: flex;
justify-content: center;
align-items: center;
color: var(--g-color-30);
}
.view-links-close-btn:hover {
color: var(--g-color-0);
background-color: var(--g-color-80);
border-radius: 50%;
}
.view-links-ol-li {
line-height: 1.4;
}
.view-links-ol-li::marker {
font-size: 12px
}
.view-links-footer {
text-align: center;
color: var(--g-color-30);
padding: 10px;
font-size: 13px;
border-top: 1px solid var(--g-color-85);
overflow-wrap: break-word;
}
.view-links-re-index-btn {
display: none
}
.view-links-footer:hover .view-links-re-index-btn {
display: inline;
color: var(--g-color-30);
}
`)
}
} as Plugin
@@ -0,0 +1,273 @@
<template>
<index-status style="width: 300px">
<div class="close-btn" @click="close" :title="$t('close') + ' ' + getKeyLabel(Escape)">
<svg-icon name="times" width="14px" height="14px" />
</div>
<div class="header">
<group-tabs :tabs="[
{ value: 'links', label: $t('view-links.links') },
{ value: 'back-links', label: $t('view-links.back-links') },
]" size="small" v-model="currentTab" />
</div>
<ol v-if="list && list.length" class="list">
<li v-for="item in list" :key="item.title" class="item" :data-type="currentTab">
<span v-if="item.location" class="item-icon-location" @click="switchDoc(item.location.doc, { source: 'view-links', position: item.location.position })">
<SvgIcon name="location-crosshairs-solid" width="10px" height="10px" />
</span>
<a
href="#"
@click.prevent="switchDoc(item.doc, { source: 'view-links', position: item.position })">
{{ item.title }}
</a>
</li>
</ol>
<div v-else class="tips">
<span v-if="list">{{ $t('view-links.no-result') }}</span>
<span v-else>Loading...</span>
</div>
<div v-if="title" class="footer">
{{ title }} &nbsp;
<a class="re-index-btn" href="#" @click.prevent="rebuildCurrentRepo()" :title="`Indexed: ${store.state.currentRepoIndexStatus?.status?.indexed}, Total: ${store.state.currentRepoIndexStatus?.status?.total}, Cost: ${store.state.currentRepoIndexStatus?.status?.cost}ms`">
{{ $t('view-links.re-index') }}
</a>
</div>
</index-status>
</template>
<script setup lang="ts">
import { ref, watch, onMounted, onBeforeUnmount } from 'vue'
import { basename } from '@fe/utils/path'
import { registerHook, removeHook } from '@fe/core/hook'
import { Escape, getKeyLabel } from '@fe/core/keybinding'
import { useFixedFloat } from '@fe/support/ui/fixed-float'
import { getDocumentsManager, rebuildCurrentRepo } from '@fe/services/indexer'
import { switchDoc } from '@fe/services/document'
import { useI18n } from '@fe/services/i18n'
import store from '@fe/support/store'
import type { Doc, PositionState } from '@fe/types'
import SvgIcon from '@fe/components/SvgIcon.vue'
import GroupTabs from '@fe/components/GroupTabs.vue'
import IndexStatus from '@fe/components/IndexStatus.vue'
type TabItemValue = 'links' | 'back-links'
type ListItem = { title: string, doc: Doc, position?: PositionState | null, location?: { doc: Doc, position: { line: number } } }
const currentTab = ref<TabItemValue>('links')
const title = ref('')
const list = ref<(ListItem[] | null)>(null)
const { t: $t } = useI18n()
const currentFileRepo = store.state.currentFile?.repo
const currentFilePath = store.state.currentFile?.path
const currentFileName = store.state.currentFile?.name
const buildList = (type: TabItemValue) => {
list.value = null
title.value = currentFileName ? {
links: $t('view-links.links-in', currentFileName),
'back-links': $t('view-links.back-links-for', currentFileName),
}[type] : ''
if (!store.state.currentRepoIndexStatus?.status.ready || currentFileRepo !== store.state.currentRepoIndexStatus?.repo || !currentFilePath) {
list.value = []
return
}
const buildTitle = (name: string, position?: PositionState | null) => {
name = name.replace(/^\/|\.md$/gi, '')
if (!position) {
return name
}
let pos = ''
if ('anchor' in position) {
pos = `#${position.anchor}`
} else if ('line' in position) {
pos = `:${position.line}`
}
return name + pos
}
const dm = getDocumentsManager()
if (type === 'links') {
dm.findByRepoAndPath(currentFileRepo, currentFilePath).then(doc => {
if (currentTab.value === 'links') {
list.value = doc ? doc.links.filter(link => !!link.internal).map(link => ({
title: buildTitle(link.internal!, link.position),
doc: { type: 'file' as const, repo: currentFileRepo, path: link.internal!, name: basename(link.internal!), },
position: link.position,
location: {
doc: {
type: 'file' as const,
repo: currentFileRepo,
path: currentFilePath,
name: currentFileName!,
},
position: { line: link.blockMap[0] + 1 },
}
})) : []
}
})
} else if (type === 'back-links') {
const data: ListItem[] = []
dm.getTable().where({ repo: currentFileRepo }).each(doc => {
doc.links.forEach(link => {
if (link.internal === currentFilePath) {
const position: PositionState = { line: link.blockMap[0] + 1 }
data.push({
title: buildTitle(doc.path, position),
doc: { type: 'file', repo: currentFileRepo, path: doc.path, name: basename(doc.path) },
position
})
}
})
}).then(() => {
if (currentTab.value === 'back-links') {
list.value = data
}
})
}
}
const close = () => {
useFixedFloat().hide()
}
const handleKeyDown = (e: KeyboardEvent) => {
if (e.key === 'Escape') {
close()
}
}
watch(() => currentTab.value, buildList)
watch(() => store.state.currentRepoIndexStatus?.status.ready, () => buildList(currentTab.value))
watch(() => [store.state.currentFile?.repo, store.state.currentRepo?.name], (val) => {
if (val[0] !== currentFileRepo || val[1] !== currentFileRepo) {
close()
}
}, { flush: 'post' })
onMounted(() => {
buildList(currentTab.value)
registerHook('GLOBAL_KEYDOWN', handleKeyDown)
})
onBeforeUnmount(() => {
removeHook('GLOBAL_KEYDOWN', handleKeyDown)
})
</script>
<style lang="scss" scoped>
.header {
display: flex;
justify-content: center;
border-bottom: 1px solid var(--g-color-85);
padding: 5px 0;
}
.tips {
text-align: center;
font-style: italic;
color: var(--g-color-45);
padding: 20px 0 10px;
font-size: 14px;
}
.close-btn {
position: absolute;
right: 3px;
top: 3px;
width: 20px;
height: 20px;
padding: 3px;
box-sizing: border-box;
color: var(--g-color-30);
&:hover {
color: var(--g-color-0);
background-color: var(--g-color-80);
border-radius: 50%;
}
.svg-icon {
display: block;
}
}
.list {
max-height: 60vh;
overflow-y: auto;
margin: 0;
padding: 8px 10px 8px 40px;
background-color: rgba(var(--g-foreground-color-rgb), 0.025);
overflow-wrap: break-word;
.item {
line-height: 1.2;
margin: 4px 0;
font-size: 14px;
position: relative;
&::marker {
font-size: 12px;
}
.item-icon-location {
display: none;
box-sizing: border-box;
color: var(--g-color-30);
width: 16px;
height: 16px;
padding: 3px;
position: absolute;
left: -18px;
top: 2px;
&:hover {
color: var(--g-color-0);
background-color: var(--g-color-80);
border-radius: 50%;
}
.svg-icon {
display: block;
}
}
&[data-type="links"]:hover {
&::marker {
color: transparent;
}
.item-icon-location {
display: inline;
}
}
}
}
.footer {
text-align: center;
color: var(--g-color-30);
padding: 10px;
font-size: 13px;
border-top: 1px solid var(--g-color-85);
overflow-wrap: break-word;
.re-index-btn {
display: none;
white-space: nowrap;
}
&:hover .re-index-btn {
display: inline;
color: var(--g-color-30);
}
}
</style>
+61
View File
@@ -0,0 +1,61 @@
import { ROOT_REPO_NAME_PREFIX } from '@share/misc'
import type { Plugin } from '@fe/context'
import ViewLinksComponent from './ViewLinksComponent.vue'
export default {
name: 'view-links',
register: (ctx) => {
const actionName = 'plugin.view-links.view-document-links'
function showLinks () {
ctx.ui.useFixedFloat().show({
right: '20px',
top: ctx.env.isElectron ? '66px' : '36px',
component: ViewLinksComponent,
closeOnBlur: false,
onBlur (byClickSelf) {
if (!byClickSelf && ctx.store.state.currentRepoIndexStatus?.repo !== ctx.store.state.currentFile?.repo) {
ctx.ui.useFixedFloat().hide()
}
},
})
}
function when () {
const currentRepoName = ctx.store.state.currentRepo?.name
const currentFileRepoName = ctx.store.state.currentFile?.repo
const result = !ctx.args.FLAG_DEMO && // not in demo mode
ctx.args.MODE === 'normal' && // in normal mode
currentRepoName && // has current repo
currentFileRepoName && // has current file
currentFileRepoName !== ctx.args.HELP_REPO_NAME && // current file is not in help repo
!currentFileRepoName.startsWith(ROOT_REPO_NAME_PREFIX) // current file is not in root repo
return !!result
}
ctx.action.registerAction({
name: actionName,
forUser: true,
description: ctx.i18n.t('command-desc.plugin_view-links_view-document-links'),
handler: showLinks,
when,
})
ctx.workbench.FileTabs.tapActionBtns(btns => {
if (when()) {
btns.push({ type: 'separator' })
btns.push({
type: 'normal',
icon: 'link-solid',
title: 'Links',
onClick: () => {
ctx.action.getActionHandler(actionName)()
},
})
btns.push({ type: 'separator' })
}
})
}
} as Plugin