Feature(custom): add guide page for first time use

This commit is contained in:
Kuingsmile
2026-01-16 13:41:52 +08:00
parent c7e34420d1
commit fa4ef9f507
14 changed files with 795 additions and 2 deletions

View File

@@ -13,6 +13,7 @@ UPLOADING: Uploading
QUICK_UPLOAD: Quick Upload
UPLOAD_BY_CLIPBOARD: Upload by Clipboard
SHOW_PICBED_QRCODE: Show Picbed Qrcode
SHOW_FIRST_TIME_GUIDE: Show First-Time Guide
ENABLE: Enable
DISABLE: Disable
CONFIG_THING: Config ${c}

View File

@@ -13,6 +13,7 @@ UPLOADING: 正在上传
QUICK_UPLOAD: 快捷上传
UPLOAD_BY_CLIPBOARD: 剪贴板图片上传
SHOW_PICBED_QRCODE: 生成图床配置二维码
SHOW_FIRST_TIME_GUIDE: 显示新手指南
ENABLE: 启用
DISABLE: 禁用
CONFIG_THING: 配置${c}

View File

@@ -13,6 +13,7 @@ UPLOADING: 正在上傳
QUICK_UPLOAD: 快速上傳
UPLOAD_BY_CLIPBOARD: 剪貼簿圖片上傳
SHOW_PICBED_QRCODE: 產生圖床配置 QRCODE
SHOW_FIRST_TIME_GUIDE: 顯示新手指南
ENABLE: 啟用
DISABLE: 禁用
CONFIG_THING: 設定${c}

View File

@@ -10,6 +10,7 @@ export const PICGO_TOGGLE_PLUGIN = 'PICGO_TOGGLE_PLUGIN'
export const RENAME_FILE_NAME = 'RENAME_FILE_NAME'
export const GET_RENAME_FILE_NAME = 'GET_RENAME_FILE_NAME'
export const SHOW_MAIN_PAGE_QRCODE = 'SHOW_MAIN_PAGE_QRCODE'
export const SHOW_FIRST_TIME_GUIDE = 'SHOW_FIRST_TIME_GUIDE'
// rpc
export const RPC_ACTIONS = 'RPC_ACTIONS'
export const RPC_ACTIONS_INVOKE = 'RPC_ACTIONS_INVOKE'

View File

@@ -11,6 +11,7 @@ import {
PICGO_HANDLE_PLUGIN_DONE,
PICGO_HANDLE_PLUGIN_ING,
PICGO_TOGGLE_PLUGIN,
SHOW_FIRST_TIME_GUIDE,
SHOW_MAIN_PAGE_QRCODE,
} from '~/events/constant'
import { handlePluginUninstall, handlePluginUpdate } from '~/events/rpc/routes/plugin/utils'
@@ -111,6 +112,12 @@ const buildMainPageMenu = (win: BrowserWindow) => {
win?.webContents?.send(SHOW_MAIN_PAGE_QRCODE)
},
},
{
label: $t('SHOW_FIRST_TIME_GUIDE'),
click() {
win?.webContents?.send(SHOW_FIRST_TIME_GUIDE)
},
},
{
label: $t('OPEN_TOOLBOX'),
click() {

View File

@@ -0,0 +1,354 @@
<template>
<TransitionRoot appear :show="isVisible" as="template">
<div class="guide-overlay">
<div class="guide-backdrop" @click="handleClose" />
<div v-if="currentStepConfig.target" class="guide-spotlight" :style="spotlightStyle" />
<!-- Guide Card -->
<div class="guide-card" :style="cardStyle">
<div class="guide-header">
<div class="guide-header-left">
<h3 class="guide-title">{{ t('guide.title') }}</h3>
<span class="guide-step-indicator">
{{ t('guide.stepIndicator', { current: currentStep + 1, total: steps.length }) }}
</span>
</div>
<button class="guide-close" :title="t('guide.close')" @click="handleClose">
<XIcon :size="20" />
</button>
</div>
<div class="guide-content">
<div class="guide-icon">
<component :is="currentStepConfig.icon" :size="24" />
</div>
<div class="guide-text">
<h4 class="guide-content-title">{{ t(currentStepConfig.title) }}</h4>
<p class="guide-content-description">{{ t(currentStepConfig.description) }}</p>
</div>
</div>
<div class="guide-footer">
<div class="guide-progress">
<div
v-for="(_, index) in steps"
:key="index"
class="progress-dot"
:class="{ active: index === currentStep, completed: index < currentStep }"
/>
</div>
<div class="guide-actions">
<button v-if="currentStep > 0" class="guide-btn secondary" @click="handlePrevious">
<ChevronLeftIcon :size="16" />
{{ t('guide.previous') }}
</button>
<button class="guide-btn outline" @click="handleSkip">
{{ t('guide.skip') }}
</button>
<button v-if="currentStep < steps.length - 1" class="guide-btn primary" @click="handleNext">
{{ t('guide.next') }}
<ChevronRightIcon :size="16" />
</button>
<button v-else class="guide-btn success" @click="handleFinish">
<CheckCircleIcon :size="16" />
{{ t('guide.finish') }}
</button>
</div>
</div>
</div>
</div>
</TransitionRoot>
</template>
<script setup lang="ts">
import { TransitionRoot } from '@headlessui/vue'
import { useStorage } from '@vueuse/core'
import {
ArrowLeftRightIcon,
CheckCircleIcon,
ChevronLeftIcon,
ChevronRightIcon,
HelpCircleIcon,
ImageIcon,
PaletteIcon,
UploadCloudIcon,
XIcon,
} from 'lucide-vue-next'
import { computed, nextTick, onMounted, ref, watch } from 'vue'
import { useI18n } from 'vue-i18n'
import { useRoute, useRouter } from 'vue-router'
const { t } = useI18n()
const route = useRoute()
const router = useRouter()
const hasSeenGuide = useStorage('has-seen-first-time-guide', false)
const isVisible = ref(false)
const currentStep = ref(0)
const spotlightRect = ref<DOMRect | null>(null)
interface GuideStep {
id: string
title: string
description: string
additionalInfo?: string[]
target?: string
position?: 'top' | 'bottom' | 'left' | 'right' | 'center'
icon: any
action?: () => void
}
const steps: GuideStep[] = [
{
id: 'welcome',
title: 'guide.steps.welcome.title',
description: 'guide.steps.welcome.description',
position: 'center',
icon: HelpCircleIcon,
},
{
id: 'upload',
title: 'guide.steps.upload.title',
description: 'guide.steps.upload.description',
target: '#upload-area',
position: 'bottom',
icon: UploadCloudIcon,
},
{
id: 'picbed',
title: 'guide.steps.picbed.title',
description: 'guide.steps.picbed.description',
target: '.provider-button',
position: 'bottom',
icon: ArrowLeftRightIcon,
},
{
id: 'theme',
title: 'guide.steps.theme.title',
description: 'guide.steps.theme.description',
target: '.theme-switcher',
position: 'right',
icon: PaletteIcon,
},
{
id: 'themeSelection',
title: 'guide.steps.themeSelection.title',
description: 'guide.steps.themeSelection.description',
target: '.theme-dropdown',
position: 'bottom',
icon: PaletteIcon,
},
{
id: 'gallery',
title: 'guide.steps.gallery.title',
description: 'guide.steps.gallery.description',
target: 'nav .nav-item:nth-child(3)',
position: 'right',
icon: ImageIcon,
},
{
id: 'finish',
title: 'guide.steps.finish.title',
description: 'guide.steps.finish.description',
position: 'center',
icon: CheckCircleIcon,
},
]
const currentStepConfig = computed(() => steps[currentStep.value])
const updateSpotlight = async () => {
await nextTick()
const target = currentStepConfig.value.target
if (!target) {
spotlightRect.value = null
return
}
const element = document.querySelector(target)
if (element) {
spotlightRect.value = element.getBoundingClientRect()
} else {
spotlightRect.value = null
}
}
const spotlightStyle = computed(() => {
if (!spotlightRect.value) return {}
const padding = 8
return {
top: `${spotlightRect.value.top - padding}px`,
left: `${spotlightRect.value.left - padding}px`,
width: `${spotlightRect.value.width + padding * 2}px`,
height: `${spotlightRect.value.height + padding * 2}px`,
}
})
const cardStyle = computed(() => {
if (!spotlightRect.value || currentStepConfig.value.position === 'center') {
return {
top: '50%',
left: '50%',
transform: 'translate(-50%, -50%)',
}
}
const rect = spotlightRect.value
const position = currentStepConfig.value.position || 'bottom'
const offset = 16
const cardWidth = 420
const estimatedCardHeight = 260
const padding = 12
const style: Record<string, string> = {}
const centerX = rect.left + rect.width / 2
const halfCardWidth = cardWidth / 2
let adjustedCenterX = centerX
if (centerX - halfCardWidth < padding) {
adjustedCenterX = halfCardWidth + padding
} else if (centerX + halfCardWidth > window.innerWidth - padding) {
adjustedCenterX = window.innerWidth - halfCardWidth - padding
}
if (position === 'bottom') {
const spaceBelow = window.innerHeight - rect.bottom - offset - padding
const spaceAbove = rect.top - offset - padding
if (spaceBelow >= estimatedCardHeight || spaceBelow > spaceAbove) {
style.top = `${rect.bottom + offset}px`
style.left = `${adjustedCenterX}px`
style.transform = 'translateX(-50%)'
} else {
style.bottom = `${window.innerHeight - rect.top + offset}px`
style.left = `${adjustedCenterX}px`
style.transform = 'translateX(-50%)'
}
} else if (position === 'top') {
const spaceAbove = rect.top - offset - padding
const spaceBelow = window.innerHeight - rect.bottom - offset - padding
if (spaceAbove >= estimatedCardHeight || spaceAbove > spaceBelow) {
style.bottom = `${window.innerHeight - rect.top + offset}px`
style.left = `${adjustedCenterX}px`
style.transform = 'translateX(-50%)'
} else {
style.top = `${rect.bottom + offset}px`
style.left = `${adjustedCenterX}px`
style.transform = 'translateX(-50%)'
}
} else if (position === 'right') {
const spaceRight = window.innerWidth - rect.right - offset - padding
const spaceLeft = rect.left - offset - padding
const centerY = rect.top + rect.height / 2
const adjustedCenterY = Math.max(
estimatedCardHeight / 2 + padding,
Math.min(centerY, window.innerHeight - estimatedCardHeight / 2 - padding),
)
if (spaceRight >= cardWidth || spaceRight > spaceLeft) {
style.left = `${rect.right + offset}px`
style.top = `${adjustedCenterY}px`
style.transform = 'translateY(-50%)'
} else {
style.right = `${window.innerWidth - rect.left + offset}px`
style.top = `${adjustedCenterY}px`
style.transform = 'translateY(-50%)'
}
} else if (position === 'left') {
const spaceLeft = rect.left - offset - padding
const spaceRight = window.innerWidth - rect.right - offset - padding
const centerY = rect.top + rect.height / 2
const adjustedCenterY = Math.max(
estimatedCardHeight / 2 + padding,
Math.min(centerY, window.innerHeight - estimatedCardHeight / 2 - padding),
)
if (spaceLeft >= cardWidth || spaceLeft > spaceRight) {
style.right = `${window.innerWidth - rect.left + offset}px`
style.top = `${adjustedCenterY}px`
style.transform = 'translateY(-50%)'
} else {
style.left = `${rect.right + offset}px`
style.top = `${adjustedCenterY}px`
style.transform = 'translateY(-50%)'
}
}
return style
})
watch(currentStep, () => {
updateSpotlight()
})
watch(
() => route.path,
() => {
if (isVisible.value) {
updateSpotlight()
}
},
)
const handleNext = async () => {
if (currentStep.value < steps.length - 1) {
currentStep.value++
if (currentStep.value === 4) {
await router.push('/main-page/settings')
await new Promise(resolve => setTimeout(resolve, 400))
await updateSpotlight()
}
}
}
const handlePrevious = () => {
if (currentStep.value > 0) {
currentStep.value--
}
}
const handleSkip = () => {
isVisible.value = false
hasSeenGuide.value = true
}
const handleClose = () => {
isVisible.value = false
hasSeenGuide.value = true
}
const handleFinish = () => {
isVisible.value = false
hasSeenGuide.value = true
}
const restartGuide = () => {
currentStep.value = 0
isVisible.value = true
}
defineExpose({
restartGuide,
})
onMounted(async () => {
if (!hasSeenGuide.value) {
setTimeout(() => {
isVisible.value = true
updateSpotlight()
}, 500)
}
window.addEventListener('resize', updateSpotlight)
})
</script>
<style scoped src="./css/FirstTimeGuide.css"></style>

View File

@@ -85,6 +85,9 @@
</button>
</div>
</nav>
<FirstTimeGuide ref="guideRef" />
<TransitionRoot appear :show="qrcodeVisible" as="template">
<Dialog as="div" class="qr-dialog" @close="qrcodeVisible = false">
<div class="dialog-container">
@@ -202,11 +205,13 @@ import { useRoute, useRouter } from 'vue-router'
import { usePicBed } from '@/hooks/useGlobal'
import useMessage from '@/hooks/useMessage'
import * as config from '@/router/config'
import { SHOW_MAIN_PAGE_QRCODE } from '@/utils/constant'
import { SHOW_FIRST_TIME_GUIDE, SHOW_MAIN_PAGE_QRCODE } from '@/utils/constant'
import { getConfig } from '@/utils/dataSender'
import { IRPCActionType } from '@/utils/enum'
import FirstTimeGuide from './FirstTimeGuide.vue'
import ThemeSwitcher from './ui/ThemeSwitcher.vue'
const version = ref(pkg.version)
const isCollapsed = useStorage('navigation-collapsed', false)
@@ -220,6 +225,7 @@ const routerConfig = reactive(config)
const qrcodeVisible = ref(false)
const choosedPicBedForQRCode: Ref<string[]> = ref([])
const picBedConfigString = ref('')
const guideRef = ref<InstanceType<typeof FirstTimeGuide> | null>(null)
let removeIpcListener: () => void = () => {}
@@ -243,6 +249,10 @@ const qrCodeHandler = () => {
qrcodeVisible.value = true
}
const guideHandler = () => {
guideRef.value?.restartGuide()
}
function openMenu() {
window.electron.sendRPC(IRPCActionType.SHOW_MAIN_PAGE_MENU)
}
@@ -288,6 +298,13 @@ function openGithubPage() {
onBeforeMount(() => {
removeIpcListener = window.electron.ipcRendererOn(SHOW_MAIN_PAGE_QRCODE, qrCodeHandler)
const removeGuideListener = window.electron.ipcRendererOn(SHOW_FIRST_TIME_GUIDE, guideHandler)
const originalRemove = removeIpcListener
removeIpcListener = () => {
originalRemove()
removeGuideListener()
}
})
onBeforeUnmount(() => {

View File

@@ -0,0 +1,280 @@
.guide-overlay {
position: fixed;
inset: 0;
z-index: 9999;
pointer-events: auto;
}
.guide-backdrop {
position: absolute;
inset: 0;
background: rgb(0 0 0 / 10%);
transition: all 0.3s ease;
}
.guide-overlay.advancedAnimation .guide-backdrop {
animation: fade-in 0.3s ease;
}
.guide-spotlight {
position: absolute;
border: 2px solid var(--color-accent);
border-radius: 8px;
box-shadow:
0 0 0 9999px rgb(0 0 0 / 10%),
0 0 20px rgb(255 255 255 / 30%),
inset 0 0 20px rgb(255 255 255 / 10%);
transition: all 0.3s ease;
pointer-events: none;
z-index: 10000;
}
.guide-card {
position: absolute;
background: var(--color-background-tertiary);
border: 1px solid var(--color-border);
border-radius: 10px;
box-shadow: 0 10px 40px rgb(0 0 0 / 25%);
width: 420px;
max-width: 90vw;
max-height: 80vh;
overflow: auto;
z-index: 10001;
transition: all 0.3s ease;
}
.guide-overlay.advancedAnimation .guide-card {
animation: slide-up 0.4s cubic-bezier(0.34, 1.56, 0.64, 1);
}
.guide-header {
display: flex;
align-items: center;
justify-content: space-between;
padding: 12px 18px;
border-bottom: 1px solid var(--color-border);
}
.guide-header-left {
display: flex;
flex-direction: column;
gap: 2px;
}
.guide-title {
font-size: 15px;
font-weight: 600;
color: var(--color-text-primary);
margin: 0;
}
.guide-step-indicator {
font-size: 11px;
color: var(--color-text-tertiary);
}
.guide-close {
background: transparent;
border: none;
color: var(--color-text-secondary);
cursor: pointer;
padding: 4px;
border-radius: 6px;
display: flex;
align-items: center;
justify-content: center;
transition: all 0.2s;
}
.guide-close:hover {
background: var(--color-accent-hover);
color: var(--color-text-primary);
}
.guide-content {
padding: 14px 18px;
display: flex;
gap: 14px;
align-items: flex-start;
}
.guide-icon {
width: 40px;
height: 40px;
flex-shrink: 0;
border-radius: 10px;
background: var(--color-accent);
display: flex;
align-items: center;
justify-content: center;
color: white;
}
.guide-text {
flex: 1;
min-width: 0;
}
.guide-content-title {
font-size: 14px;
font-weight: 600;
color: var(--color-text-primary);
margin: 0 0 4px;
}
.guide-content-description {
font-size: 13px;
color: var(--color-text-secondary);
line-height: 1.5;
margin: 0;
}
.guide-additional-info {
background: var(--color-background-tertiary);
border-radius: 6px;
padding: 10px 12px;
margin-top: 10px;
}
.guide-additional-info p {
font-size: 12px;
color: var(--color-text-secondary);
line-height: 1.4;
margin: 6px 0;
}
.guide-additional-info p:first-child {
margin-top: 0;
}
.guide-additional-info p:last-child {
margin-bottom: 0;
}
.guide-footer {
padding: 10px 18px 12px;
border-top: 1px solid var(--color-border);
}
.guide-progress {
display: flex;
justify-content: center;
gap: 6px;
margin-bottom: 10px;
}
.progress-dot {
width: 6px;
height: 6px;
border-radius: 50%;
background: var(--color-border);
transition: all 0.3s;
}
.progress-dot.active {
background: var(--color-primary);
width: 20px;
border-radius: 3px;
}
.progress-dot.completed {
background: var(--color-success);
}
.guide-actions {
display: flex;
gap: 6px;
justify-content: flex-end;
}
.guide-btn {
padding: 6px 12px;
border-radius: 6px;
font-size: 13px;
font-weight: 500;
cursor: pointer;
border: none;
display: flex;
align-items: center;
gap: 4px;
transition: all 0.2s;
}
.guide-btn.primary {
background: var(--color-accent);
color: white;
}
.guide-btn.primary:hover {
background: var(--color-accent-hover);
transform: translateY(-1px);
}
.guide-btn.secondary {
background: var(--color-background-tertiary);
color: var(--color-text-primary);
}
.guide-btn.secondary:hover {
background: var(--color-accent-hover);
}
.guide-btn.outline {
background: transparent;
color: var(--color-text-primary);
border: 1px solid var(--color-border);
}
.guide-btn.outline:hover {
background: var(--color-accent);
color: var(--color-text-primary);
}
.guide-btn.success {
background: var(--color-success);
color: white;
}
.guide-btn.success:hover {
background: var(--color-success);
transform: translateY(-1px);
}
@keyframes fade-in {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
@keyframes slide-up {
from {
opacity: 0;
transform: translate(-50%, -40%) scale(0.95);
}
to {
opacity: 1;
transform: translate(-50%, -50%) scale(1);
}
}
/* Responsive */
@media (width <= 640px) {
.guide-card {
width: calc(100vw - 32px);
}
.guide-actions {
flex-wrap: wrap;
}
.guide-btn {
flex: 1;
min-width: calc(50% - 4px);
justify-content: center;
}
}

View File

@@ -9,6 +9,49 @@
"submit": "Submit",
"version": "Version"
},
"guide": {
"close": "Close",
"finish": "Get Started",
"next": "Next",
"previous": "Back",
"skip": "Skip Tour",
"stepIndicator": "Step {current} of {total}",
"steps": {
"finish": {
"description": "You're ready to start using PicList! You can always restart this guide from the menu.",
"title": "You're All Set! ✨"
},
"gallery": {
"description": "Access your uploaded images in the gallery. You can search, filter, and manage your image collection.",
"title": "View Your Gallery"
},
"picbed": {
"description": "Click here to view and configure your current image hosting service (PicBed).",
"title": "Choose Your Image Host"
},
"settings": {
"description": "Customize PicList to suit your needs. Configure upload settings, shortcuts, and more.",
"title": "Configure Settings"
},
"theme": {
"description": "Click the theme switcher in the sidebar to change the appearance of PicList.",
"title": "Customize Your Theme 🎨"
},
"themeSelection": {
"description": "Select a theme from the dropdown to customize PicList's appearance.",
"title": "Choose Your Theme"
},
"upload": {
"description": "You can upload images by dragging and dropping them here, or click to select files.",
"title": "Upload Your Images"
},
"welcome": {
"description": "Let's take a quick tour to help you get started with PicList.",
"title": "Welcome to PicList! 🎉"
}
},
"title": "Welcome to PicList"
},
"navigation": {
"choosePicBed": "Choose PicBed",
"close": "Close",

View File

@@ -9,6 +9,49 @@
"submit": "提交",
"version": "版本"
},
"guide": {
"close": "关闭",
"finish": "开始使用",
"next": "下一步",
"previous": "上一步",
"skip": "跳过教程",
"stepIndicator": "第 {current} 步,共 {total} 步",
"steps": {
"finish": {
"description": "您已经准备好开始使用 PicList 了!您可以随时从菜单重新启动本指南。",
"title": "一切就绪!✨"
},
"gallery": {
"description": "在相册中访问您上传的图片。您可以搜索、筛选和管理您的图片集。",
"title": "查看相册"
},
"picbed": {
"description": "点击这里查看和配置您当前使用的图床服务。",
"title": "选择图床服务"
},
"settings": {
"description": "自定义 PicList 以满足您的需求。配置上传设置、快捷键等。",
"title": "配置设置"
},
"theme": {
"description": "点击侧边栏中的主题切换器来改变 PicList 的外观。",
"title": "自定义主题 🎨"
},
"themeSelection": {
"description": "从下拉菜单中选择主题来自定义 PicList 的外观。",
"title": "选择主题"
},
"upload": {
"description": "您可以通过拖放图片到这里,或点击选择文件来上传图片。",
"title": "上传您的图片"
},
"welcome": {
"description": "让我们快速了解一下 PicList 的主要功能吧。",
"title": "欢迎使用 PicList🎉"
}
},
"title": "欢迎使用 PicList"
},
"navigation": {
"choosePicBed": "选择图床",
"close": "关闭",

View File

@@ -9,6 +9,49 @@
"submit": "提交",
"version": "版本"
},
"guide": {
"close": "關閉",
"finish": "開始使用",
"next": "下一步",
"previous": "上一步",
"skip": "跳過教學",
"stepIndicator": "第 {current} 步,共 {total} 步",
"steps": {
"finish": {
"description": "您已經準備好開始使用 PicList 了!您可以隨時從選單重新啟動本指南。",
"title": "一切就緒!✨"
},
"gallery": {
"description": "在相簿中存取您上傳的圖片。您可以搜尋、篩選和管理您的圖片集。",
"title": "檢視相簿"
},
"picbed": {
"description": "點擊這裡檢視和設定您目前使用的圖床服務。",
"title": "選擇圖床服務"
},
"settings": {
"description": "自訂 PicList 以滿足您的需求。設定上傳設定、快捷鍵等。",
"title": "設定偏好"
},
"theme": {
"description": "點擊側邊欄中的主題切換器來變更 PicList 的外觀。",
"title": "自訂主題 🎨"
},
"themeSelection": {
"description": "從下拉選單中選擇主題來自訂 PicList 的外觀。",
"title": "選擇主題"
},
"upload": {
"description": "您可以透過拖放圖片到這裡,或點擊選擇檔案來上傳圖片。",
"title": "上傳您的圖片"
},
"welcome": {
"description": "讓我們快速了解一下 PicList 的主要功能吧。",
"title": "歡迎使用 PicList🎉"
}
},
"title": "歡迎使用 PicList"
},
"navigation": {
"choosePicBed": "選擇圖床",
"close": "關閉",

View File

@@ -101,7 +101,7 @@
<ImageIcon :size="18" />
<span>{{ t('pages.settings.system.chooseTheme') }}</span>
</div>
<select v-model="currentTheme" class="form-select">
<select v-model="currentTheme" class="form-select theme-dropdown">
<option v-for="theme in themeList" :key="theme.key" :value="theme.key">
{{ theme.label }}
</option>

View File

@@ -9,6 +9,7 @@ export const PICGO_TOGGLE_PLUGIN = 'PICGO_TOGGLE_PLUGIN'
export const RENAME_FILE_NAME = 'RENAME_FILE_NAME'
export const GET_RENAME_FILE_NAME = 'GET_RENAME_FILE_NAME'
export const SHOW_MAIN_PAGE_QRCODE = 'SHOW_MAIN_PAGE_QRCODE'
export const SHOW_FIRST_TIME_GUIDE = 'SHOW_FIRST_TIME_GUIDE'
// update window
export const SHOW_UPDATE_INFO = 'SHOW_UPDATE_INFO'
export const UPDATE_PROGRESS = 'UPDATE_PROGRESS'

View File

@@ -14,6 +14,7 @@ export interface ILocales {
QUICK_UPLOAD: string
UPLOAD_BY_CLIPBOARD: string
SHOW_PICBED_QRCODE: string
SHOW_FIRST_TIME_GUIDE: string
ENABLE: string
DISABLE: string
CONFIG_THING: string