mirror of
https://github.com/Kuingsmile/PicList.git
synced 2026-06-09 01:30:15 +08:00
✨ Feature(custom): imporve page loading performance and remove duplicated init call
This commit is contained in:
@@ -21,26 +21,6 @@
|
||||
<transition name="fade-slide" mode="out-in">
|
||||
<!-- General Settings Tab -->
|
||||
<div v-if="activeTab === 'general'" key="general" class="tab-content">
|
||||
<div class="settings-section">
|
||||
<div class="section-header">
|
||||
<div class="section-icon">
|
||||
<FileText :size="20" />
|
||||
</div>
|
||||
<div class="section-title-group">
|
||||
<h2>{{ $t('pages.imageProcess.general.skipProcessExtList') }}</h2>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<textarea
|
||||
v-model="skipProcessForm.skipProcessExtList"
|
||||
class="form-textarea"
|
||||
rows="3"
|
||||
:placeholder="'zip,rar,7z,tar,gz'"
|
||||
/>
|
||||
<small>{{ $t('pages.imageProcess.general.skipProcessExtListPlaceholder') }}</small>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="settings-section">
|
||||
<div class="section-header">
|
||||
<div class="section-icon">
|
||||
@@ -62,6 +42,7 @@
|
||||
</label>
|
||||
|
||||
<PerPicbedSetting
|
||||
v-if="!configId"
|
||||
:map-field="compressForm.isRemoveExifMap"
|
||||
:default-value="defaultCompressSetting.isRemoveExif"
|
||||
field-name="isRemoveExif"
|
||||
@@ -892,6 +873,29 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Skip Process Tab -->
|
||||
<div v-else-if="activeTab === 'skipProcess'" key="skipProcess" class="tab-content">
|
||||
<div class="settings-section">
|
||||
<div class="section-header">
|
||||
<div class="section-icon">
|
||||
<FileText :size="20" />
|
||||
</div>
|
||||
<div class="section-title-group">
|
||||
<h2>{{ $t('pages.imageProcess.general.skipProcessExtList') }}</h2>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<textarea
|
||||
v-model="skipProcessForm.skipProcessExtList"
|
||||
class="form-textarea"
|
||||
rows="3"
|
||||
:placeholder="'zip,rar,7z,tar,gz'"
|
||||
/>
|
||||
<small>{{ $t('pages.imageProcess.general.skipProcessExtListPlaceholder') }}</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</transition>
|
||||
</div>
|
||||
</div>
|
||||
@@ -933,7 +937,6 @@ import { useI18n } from 'vue-i18n'
|
||||
|
||||
import { configPaths } from '@/utils/configPaths'
|
||||
import { getConfig, saveConfig } from '@/utils/dataSender'
|
||||
import { updatePicBedGlobal } from '@/utils/global'
|
||||
|
||||
import PerPicbedSetting from './PerPicbedSetting.vue'
|
||||
|
||||
@@ -944,6 +947,13 @@ const activeTab = ref('general')
|
||||
const tabRefs = useTemplateRef('tabRefs')
|
||||
const tabIndicatorStyle = ref<Record<string, string>>({})
|
||||
|
||||
interface IProps {
|
||||
// 传递配置ID以加载特定配置
|
||||
configId: string
|
||||
}
|
||||
|
||||
const { configId } = defineProps<IProps>()
|
||||
|
||||
function updateTabIndicator() {
|
||||
if (!tabRefs.value || tabRefs.value.length === 0) return
|
||||
const activeIndex = tabs.value.findIndex(tab => tab.id === activeTab.value)
|
||||
@@ -985,6 +995,16 @@ const tabs = computed(() => [
|
||||
label: t('pages.imageProcess.transformSettings'),
|
||||
icon: RotateCw,
|
||||
},
|
||||
{
|
||||
id: 'skipProcess',
|
||||
label: t('pages.imageProcess.skipProcessSettings'),
|
||||
icon: FileText,
|
||||
},
|
||||
{
|
||||
id: 'rename',
|
||||
label: t('pages.imageProcess.renameSettings'),
|
||||
icon: Sliders,
|
||||
},
|
||||
])
|
||||
|
||||
const waterMarkPositionMap = new Map([
|
||||
@@ -1193,13 +1213,10 @@ function safeSetMapValue(form: any, fieldName: string, picbedType: string, value
|
||||
}
|
||||
}
|
||||
|
||||
onBeforeMount(async () => {
|
||||
await updatePicBedGlobal()
|
||||
await initData()
|
||||
|
||||
setTimeout(() => {
|
||||
onBeforeMount(() => {
|
||||
initData().then(() => {
|
||||
isInitialized.value = true
|
||||
}, 100)
|
||||
})
|
||||
})
|
||||
|
||||
watch(
|
||||
|
||||
@@ -120,7 +120,7 @@
|
||||
>
|
||||
<ListboxOptions class="listbox-options">
|
||||
<ListboxOption
|
||||
v-for="picbed in picBedGlobal"
|
||||
v-for="picbed in picBedG"
|
||||
:key="picbed.type"
|
||||
v-slot="{ active, selected }"
|
||||
:value="picbed.type"
|
||||
@@ -173,6 +173,7 @@ import {
|
||||
TransitionChild,
|
||||
TransitionRoot,
|
||||
} from '@headlessui/vue'
|
||||
import { useStorage } from '@vueuse/core'
|
||||
import { pick } from 'lodash-es'
|
||||
import {
|
||||
BriefcaseBusiness,
|
||||
@@ -194,21 +195,23 @@ import { computed, nextTick, onBeforeMount, onBeforeUnmount, reactive, Ref, ref,
|
||||
import { useI18n } from 'vue-i18n'
|
||||
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 { getConfig } from '@/utils/dataSender'
|
||||
import { IRPCActionType } from '@/utils/enum'
|
||||
import { picBedGlobal, updatePicBedGlobal } from '@/utils/global'
|
||||
|
||||
import ThemeSwitcher from './ui/ThemeSwitcher.vue'
|
||||
const version = ref(pkg.version)
|
||||
const isCollapsed = ref(false)
|
||||
const isCollapsed = useStorage('navigation-collapsed', false)
|
||||
|
||||
const { t } = useI18n()
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
const message = useMessage()
|
||||
const { picBedG } = usePicBed()
|
||||
|
||||
const routerConfig = reactive(config)
|
||||
const qrcodeVisible = ref(false)
|
||||
const choosedPicBedForQRCode: Ref<string[]> = ref([])
|
||||
@@ -216,11 +219,6 @@ const picBedConfigString = ref('')
|
||||
|
||||
let removeIpcListener: () => void = () => {}
|
||||
|
||||
// Save collapsed state to localStorage when it changes
|
||||
watch(isCollapsed, newValue => {
|
||||
localStorage.setItem('navigation-collapsed', JSON.stringify(newValue))
|
||||
})
|
||||
|
||||
watch(
|
||||
() => choosedPicBedForQRCode,
|
||||
val => {
|
||||
@@ -235,7 +233,7 @@ watch(
|
||||
{ deep: true },
|
||||
)
|
||||
|
||||
const visiblePicBeds = computed(() => picBedGlobal.value.filter(item => item.visible))
|
||||
const visiblePicBeds = computed(() => picBedG.value.filter(item => item.visible))
|
||||
|
||||
const qrCodeHandler = () => {
|
||||
qrcodeVisible.value = true
|
||||
@@ -279,13 +277,6 @@ function openGithubPage() {
|
||||
}
|
||||
|
||||
onBeforeMount(() => {
|
||||
// Load collapsed state from localStorage
|
||||
const savedState = localStorage.getItem('navigation-collapsed')
|
||||
if (savedState !== null) {
|
||||
isCollapsed.value = JSON.parse(savedState)
|
||||
}
|
||||
|
||||
updatePicBedGlobal()
|
||||
removeIpcListener = window.electron.ipcRendererOn(SHOW_MAIN_PAGE_QRCODE, qrCodeHandler)
|
||||
})
|
||||
|
||||
@@ -294,523 +285,4 @@ onBeforeUnmount(() => {
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.navigation {
|
||||
display: flex;
|
||||
overflow: hidden;
|
||||
border-right: 1px solid rgb(229 231 235);
|
||||
width: 150px;
|
||||
height: 100vh;
|
||||
background: var(--color-background-secondary);
|
||||
transition: width 0.3s ease;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.navigation.collapsed {
|
||||
width: 60px;
|
||||
}
|
||||
|
||||
:root.dark .navigation,
|
||||
:root.auto.dark .navigation {
|
||||
border-right-color: var(--color-background-secondary);
|
||||
background: var(--color-background-secondary);
|
||||
}
|
||||
|
||||
.title-bar {
|
||||
position: relative;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
border-bottom: 1px solid var(--color-border);
|
||||
padding: 1.25rem 1rem;
|
||||
background: var(--color-background-secondary);
|
||||
}
|
||||
|
||||
.navigation.collapsed .title-bar {
|
||||
padding: 1rem 0.5rem;
|
||||
}
|
||||
|
||||
.collapse-button {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
right: 8px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
padding: 4px;
|
||||
color: var(--color-text-primary);
|
||||
background: transparent;
|
||||
transition: all 0.2s ease;
|
||||
transform: translateY(-50%);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.collapse-button:hover {
|
||||
color: var(--color-text-primary);
|
||||
background: var(--color-surface-elevated);
|
||||
}
|
||||
|
||||
.navigation.collapsed .collapse-button {
|
||||
position: static;
|
||||
transform: none;
|
||||
}
|
||||
|
||||
:root.dark .title-bar,
|
||||
:root.auto.dark .title-bar {
|
||||
border-bottom-color: var(--color-border);
|
||||
background: var(--color-background-secondary);
|
||||
}
|
||||
|
||||
.app-title {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 0.25rem;
|
||||
}
|
||||
|
||||
.app-text {
|
||||
font-size: 16px;
|
||||
font-weight: 700;
|
||||
color: var(--color-text-primary);
|
||||
letter-spacing: -0.025em;
|
||||
}
|
||||
|
||||
.app-text:hover {
|
||||
cursor: pointer;
|
||||
color: var(--color-blue-common);
|
||||
}
|
||||
|
||||
.app-version {
|
||||
border: 1px solid var(--color-border);
|
||||
border-radius: 12px;
|
||||
padding: 3px 8px;
|
||||
font-size: 10px;
|
||||
font-weight: 500;
|
||||
color: var(--color-text-secondary);
|
||||
background: var(--color-surface-elevated);
|
||||
}
|
||||
|
||||
.theme-section {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
border-bottom: 1px solid var(--color-border);
|
||||
padding: 0.75rem;
|
||||
}
|
||||
|
||||
:root.dark .theme-section,
|
||||
:root.auto.dark .theme-section {
|
||||
border-bottom-color: var(--color-border);
|
||||
}
|
||||
|
||||
.nav-menu {
|
||||
overflow-y: auto;
|
||||
padding: 1rem 0;
|
||||
min-height: 0;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.nav-item {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
padding: 0.75rem 1rem;
|
||||
font-size: 0.875rem;
|
||||
font-weight: 500;
|
||||
text-decoration: none;
|
||||
color: rgb(75 85 99);
|
||||
transition: all 0.2s ease;
|
||||
gap: 0.75rem;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.navigation.collapsed .nav-item {
|
||||
justify-content: center;
|
||||
padding: 0.75rem 0.5rem;
|
||||
gap: 0;
|
||||
}
|
||||
|
||||
.navigation.collapsed .nav-label {
|
||||
display: none;
|
||||
}
|
||||
|
||||
:root.dark .nav-item,
|
||||
:root.auto.dark .nav-item {
|
||||
color: rgb(209 213 219);
|
||||
}
|
||||
|
||||
.nav-item:hover {
|
||||
color: rgb(17 24 39);
|
||||
background: rgb(243 244 246);
|
||||
}
|
||||
|
||||
:root.dark .nav-item:hover,
|
||||
:root.auto.dark .nav-item:hover {
|
||||
color: rgb(243 244 246);
|
||||
background: rgb(55 65 81);
|
||||
}
|
||||
|
||||
.nav-item.router-link-active {
|
||||
border-right: 3px solid rgb(99 102 241);
|
||||
color: rgb(99 102 241);
|
||||
background: rgb(239 246 255);
|
||||
}
|
||||
|
||||
:root.dark .nav-item.router-link-active,
|
||||
:root.auto.dark .nav-item.router-link-active {
|
||||
border-right-color: rgb(129 140 248);
|
||||
color: rgb(129 140 248);
|
||||
background: rgb(30 58 138 / 20%);
|
||||
}
|
||||
|
||||
.nav-icon-container {
|
||||
position: relative;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.sidebar-footer {
|
||||
border-top: 1px solid var(--color-border);
|
||||
padding: 12px;
|
||||
}
|
||||
|
||||
.footer-button {
|
||||
position: fixed;
|
||||
bottom: 4px;
|
||||
left: 4px;
|
||||
border: none;
|
||||
border-radius: 6px;
|
||||
padding: 8px;
|
||||
color: var(--color-text-secondary);
|
||||
background: transparent;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.footer-button:hover {
|
||||
color: var(--color-text-primary);
|
||||
background: var(--color-surface-elevated);
|
||||
}
|
||||
|
||||
.nav-submenu {
|
||||
position: relative;
|
||||
justify-content: center;
|
||||
margin-top: 4px;
|
||||
}
|
||||
|
||||
.submenu-trigger {
|
||||
position: relative;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
border: none;
|
||||
padding: 0.75rem 1rem;
|
||||
width: 100%;
|
||||
font-size: 0.875rem;
|
||||
font-weight: 500;
|
||||
text-decoration: none;
|
||||
color: rgb(75 85 99);
|
||||
background: transparent;
|
||||
transition: all 0.2s ease;
|
||||
gap: 0.75rem;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
:root.dark .submenu-trigger,
|
||||
:root.auto.dark .submenu-trigger {
|
||||
color: rgb(209 213 219);
|
||||
}
|
||||
|
||||
.submenu-trigger:hover {
|
||||
color: rgb(17 24 39);
|
||||
background: rgb(243 244 246);
|
||||
}
|
||||
|
||||
:root.dark .submenu-trigger:hover,
|
||||
:root.auto.dark .submenu-trigger:hover {
|
||||
color: rgb(243 244 246);
|
||||
background: rgb(55 65 81);
|
||||
}
|
||||
|
||||
.submenu-trigger .nav-icon-container {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.submenu-trigger span {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.submenu-arrow {
|
||||
position: absolute;
|
||||
right: 1rem;
|
||||
transition: transform 0.2s ease;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.rotate-180 {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
|
||||
.submenu-panel {
|
||||
display: flex;
|
||||
margin-top: 2px;
|
||||
padding-left: 2.75rem;
|
||||
flex-direction: column;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.submenu-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
border-radius: 6px;
|
||||
padding: 0.5rem 1rem;
|
||||
font-size: 0.8125rem;
|
||||
font-weight: 500;
|
||||
text-decoration: none;
|
||||
color: var(--color-text-secondary);
|
||||
transition: all 0.2s ease;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.submenu-item:hover {
|
||||
color: var(--color-text-primary);
|
||||
background: var(--color-surface-elevated);
|
||||
}
|
||||
|
||||
.collapsed-picbed {
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.collapsed-picbed:hover {
|
||||
color: rgb(17 24 39);
|
||||
background: rgb(243 244 246);
|
||||
}
|
||||
|
||||
:root.dark .collapsed-picbed:hover,
|
||||
:root.auto.dark .collapsed-picbed:hover {
|
||||
color: rgb(243 244 246);
|
||||
background: rgb(55 65 81);
|
||||
}
|
||||
|
||||
.qr-dialog {
|
||||
position: fixed;
|
||||
z-index: 50;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
overflow-y: auto;
|
||||
inset: 0;
|
||||
}
|
||||
|
||||
.dialog-container {
|
||||
position: fixed;
|
||||
z-index: 50;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
overflow-y: auto;
|
||||
padding: 16px;
|
||||
min-height: 100vh;
|
||||
inset: 0;
|
||||
}
|
||||
|
||||
.dialog-panel {
|
||||
overflow: hidden;
|
||||
border: 1px solid var(--color-border);
|
||||
border-radius: 16px;
|
||||
width: 100%;
|
||||
max-width: 500px;
|
||||
background: var(--color-background-primary);
|
||||
box-shadow: var(--shadow-md);
|
||||
}
|
||||
|
||||
.dialog-title {
|
||||
margin: 0;
|
||||
padding: 20px 24px 0;
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
color: var(--color-text-primary);
|
||||
}
|
||||
|
||||
.dialog-content {
|
||||
padding: 20px 24px;
|
||||
}
|
||||
|
||||
.form-group {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.form-label {
|
||||
display: block;
|
||||
margin-bottom: 8px;
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
color: var(--color-text-primary);
|
||||
}
|
||||
|
||||
.listbox-container {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.listbox-button {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
border: 1px solid var(--color-border);
|
||||
border-radius: var(--border-radius);
|
||||
padding: 12px 16px;
|
||||
width: 100%;
|
||||
font-size: 14px;
|
||||
color: var(--color-text-primary);
|
||||
background: var(--color-surface);
|
||||
transition: var(--transition);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.listbox-button:hover {
|
||||
border-color: var(--color-accent);
|
||||
}
|
||||
|
||||
.placeholder {
|
||||
color: var(--color-text-secondary);
|
||||
}
|
||||
|
||||
.selected-count {
|
||||
color: var(--color-text-primary);
|
||||
}
|
||||
|
||||
.listbox-arrow {
|
||||
color: var(--color-text-secondary);
|
||||
}
|
||||
|
||||
.listbox-options {
|
||||
position: absolute;
|
||||
top: 100%;
|
||||
right: 0;
|
||||
left: 0;
|
||||
z-index: 10;
|
||||
overflow-y: auto;
|
||||
margin-top: 4px;
|
||||
border: 1px solid var(--color-border);
|
||||
border-radius: var(--border-radius);
|
||||
max-height: 300px;
|
||||
background: var(--color-background-primary);
|
||||
box-shadow: var(--shadow-md);
|
||||
}
|
||||
|
||||
.listbox-option {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 12px 16px;
|
||||
font-size: 14px;
|
||||
color: var(--color-text-primary);
|
||||
transition: var(--transition);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.listbox-option.active {
|
||||
background: var(--color-surface-elevated);
|
||||
}
|
||||
|
||||
.listbox-option.selected {
|
||||
color: white;
|
||||
background: var(--color-accent);
|
||||
}
|
||||
|
||||
.copy-button {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-top: 12px;
|
||||
border: none;
|
||||
border-radius: var(--border-radius);
|
||||
padding: 10px 16px;
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
color: white;
|
||||
background: var(--color-accent);
|
||||
transition: var(--transition);
|
||||
gap: 8px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.copy-button:hover {
|
||||
background: var(--color-accent-hover);
|
||||
}
|
||||
|
||||
.qr-container {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
padding: 20px 0;
|
||||
}
|
||||
|
||||
.qr-code {
|
||||
overflow: hidden;
|
||||
border-radius: var(--border-radius);
|
||||
box-shadow: var(--shadow-sm);
|
||||
}
|
||||
|
||||
.dialog-actions {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
padding: 0 24px 20px;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.cancel-button {
|
||||
border: 1px solid var(--color-border);
|
||||
border-radius: var(--border-radius);
|
||||
padding: 10px 20px;
|
||||
font-size: 14px;
|
||||
color: var(--color-text-primary);
|
||||
background: var(--color-surface-elevated);
|
||||
transition: var(--transition);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.cancel-button:hover {
|
||||
background: var(--color-border);
|
||||
}
|
||||
|
||||
/* Responsive Design */
|
||||
@media (width <= 768px) {
|
||||
.navigation {
|
||||
width: 60px;
|
||||
}
|
||||
|
||||
.nav-label {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.app-title {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.collapse-button {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
/* Scrollbar Styling */
|
||||
::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-track {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb {
|
||||
border-radius: 0;
|
||||
background: var(--color-border);
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb:hover {
|
||||
background: var(--color-text-secondary);
|
||||
}
|
||||
</style>
|
||||
<style scoped src="./css/NavigationPage.css"></style>
|
||||
|
||||
@@ -112,9 +112,10 @@ import { Settings } from 'lucide-vue-next'
|
||||
import { computed, ref } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
|
||||
import { picBedGlobal } from '@/utils/global'
|
||||
import { usePicBed } from '@/hooks/useGlobal'
|
||||
|
||||
const { t } = useI18n()
|
||||
const { picBedG } = usePicBed()
|
||||
|
||||
interface SelectOption {
|
||||
value: string | number
|
||||
@@ -166,7 +167,7 @@ const emit = defineEmits<{
|
||||
const showSettings = ref(false)
|
||||
|
||||
const availablePicbeds = computed(() => {
|
||||
return picBedGlobal.value.map(picbed => ({
|
||||
return picBedG.value.map(picbed => ({
|
||||
type: picbed.type,
|
||||
name: picbed.name,
|
||||
}))
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<!-- eslint-disable vue/no-v-html -->
|
||||
<template>
|
||||
<div id="config-form" :class="[{ white: props.colorMode === 'white' }]">
|
||||
<div id="config-form" :class="[{ white: colorMode === 'white' }]">
|
||||
<form class="config-form" @submit.prevent>
|
||||
<!-- Config Name Field -->
|
||||
<div class="form-group required">
|
||||
@@ -125,14 +125,14 @@
|
||||
import { cloneDeep, union } from 'lodash-es'
|
||||
import { ChevronDownIcon, Info } from 'lucide-vue-next'
|
||||
import { marked } from 'marked'
|
||||
import { reactive, ref, toRefs, watch } from 'vue'
|
||||
import { reactive, ref, watch } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { useRoute } from 'vue-router'
|
||||
|
||||
import { getConfig } from '@/utils/dataSender'
|
||||
|
||||
interface IProps {
|
||||
config: any[]
|
||||
config: IPicGoPluginConfig[]
|
||||
type: 'uploader' | 'transformer' | 'plugin'
|
||||
id: string
|
||||
colorMode?: 'white' | 'dark'
|
||||
@@ -140,11 +140,14 @@ interface IProps {
|
||||
showTooltips?: boolean
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<IProps>(), {
|
||||
colorMode: undefined,
|
||||
mode: 'picbed',
|
||||
showTooltips: true,
|
||||
})
|
||||
const {
|
||||
config: configProp,
|
||||
type,
|
||||
id,
|
||||
colorMode = undefined,
|
||||
mode = 'picbed',
|
||||
showTooltips = true,
|
||||
} = defineProps<IProps>()
|
||||
|
||||
const $route = useRoute()
|
||||
const { t } = useI18n()
|
||||
@@ -156,9 +159,9 @@ const visibleTooltips = reactive<Record<string, boolean>>({})
|
||||
|
||||
// Watch for config changes
|
||||
watch(
|
||||
toRefs(props.config),
|
||||
(val: IPicGoPluginConfig[]) => {
|
||||
handleConfig(val)
|
||||
() => configProp,
|
||||
newVal => {
|
||||
handleConfig(newVal)
|
||||
},
|
||||
{
|
||||
deep: true,
|
||||
@@ -191,10 +194,7 @@ function validateForm(): boolean {
|
||||
errors[config.name] = error
|
||||
}
|
||||
})
|
||||
|
||||
Object.keys(validationErrors).forEach(key => {
|
||||
delete validationErrors[key]
|
||||
})
|
||||
for (const key in validationErrors) delete validationErrors[key]
|
||||
|
||||
Object.assign(validationErrors, errors)
|
||||
|
||||
@@ -256,15 +256,15 @@ function transformMarkdownToHTML(markdown: string) {
|
||||
}
|
||||
|
||||
function getConfigType() {
|
||||
switch (props.type) {
|
||||
switch (type) {
|
||||
case 'plugin': {
|
||||
return props.id
|
||||
return id
|
||||
}
|
||||
case 'uploader': {
|
||||
return `picBed.${props.id}`
|
||||
return `picBed.${id}`
|
||||
}
|
||||
case 'transformer': {
|
||||
return `transformer.${props.id}`
|
||||
return `transformer.${id}`
|
||||
}
|
||||
default:
|
||||
return 'unknown'
|
||||
@@ -273,14 +273,14 @@ function getConfigType() {
|
||||
|
||||
async function handleConfig(val: IPicGoPluginConfig[]) {
|
||||
const config = await getCurConfigFormData()
|
||||
const configId = props.mode === 'picbed' ? $route.params.configId : null
|
||||
const configId = mode === 'picbed' ? $route.params.configId : null
|
||||
|
||||
Object.assign(ruleForm, config)
|
||||
|
||||
if (val.length > 0) {
|
||||
configList.value = cloneDeep(val).map(item => {
|
||||
// For plugin mode, don't check configId
|
||||
if (props.mode === 'plugin' || !configId) {
|
||||
if (mode === 'plugin' || !configId) {
|
||||
let defaultValue = item.default !== undefined ? item.default : item.type === 'checkbox' ? [] : null
|
||||
|
||||
if (item.type === 'checkbox') {
|
||||
@@ -314,11 +314,11 @@ async function handleConfig(val: IPicGoPluginConfig[]) {
|
||||
}
|
||||
|
||||
async function getCurConfigFormData() {
|
||||
if (props.mode === 'plugin') {
|
||||
return (await getConfig<IStringKeyMap>(`${props.id}`)) || {}
|
||||
if (mode === 'plugin') {
|
||||
return (await getConfig<IStringKeyMap>(`${id}`)) || {}
|
||||
} else {
|
||||
const configId = $route.params.configId
|
||||
const curTypeConfigList = (await getConfig<IStringKeyMap[]>(`uploader.${props.id}.configList`)) || []
|
||||
const curTypeConfigList = (await getConfig<IStringKeyMap[]>(`uploader.${id}.configList`)) || []
|
||||
return curTypeConfigList.find(i => i._id === configId) || {}
|
||||
}
|
||||
}
|
||||
@@ -339,386 +339,4 @@ defineExpose({
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
#config-form {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.config-form {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 1.5rem;
|
||||
}
|
||||
|
||||
/* Form Groups */
|
||||
.form-group {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
.form-group.required .form-label::after {
|
||||
content: ' *';
|
||||
color: var(--color-error, #ef4444);
|
||||
}
|
||||
|
||||
.form-label-wrapper {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
.form-label {
|
||||
font-size: 0.875rem;
|
||||
font-weight: 500;
|
||||
color: var(--color-text-primary);
|
||||
line-height: 1.25;
|
||||
}
|
||||
|
||||
.form-control {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
/* Tooltip Styles */
|
||||
.tooltip-wrapper {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.info-icon {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
border-radius: 50%;
|
||||
padding: 2px;
|
||||
color: var(--color-text-secondary);
|
||||
transition: var(--transition-fast);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.info-icon:hover {
|
||||
color: var(--color-accent);
|
||||
background: rgb(0 122 255 / 10%);
|
||||
}
|
||||
|
||||
.tooltip-content {
|
||||
position: absolute;
|
||||
top: 100%;
|
||||
left: 0;
|
||||
z-index: 1000;
|
||||
border: 1px solid var(--color-border);
|
||||
border-radius: var(--radius-md);
|
||||
padding: 0.75rem;
|
||||
min-width: 200px;
|
||||
max-width: 300px;
|
||||
font-size: 0.75rem;
|
||||
color: var(--color-text-primary);
|
||||
background: var(--color-surface-elevated);
|
||||
box-shadow: var(--shadow-lg);
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
/* Input Styles */
|
||||
.form-input {
|
||||
border: 1px solid var(--color-border);
|
||||
border-radius: var(--radius-md);
|
||||
padding: 0.75rem 1rem;
|
||||
width: 100%;
|
||||
font-size: 0.875rem;
|
||||
font-family: inherit;
|
||||
color: var(--color-text-primary);
|
||||
background: var(--color-surface-elevated);
|
||||
transition: var(--transition-fast);
|
||||
}
|
||||
|
||||
.form-input:focus {
|
||||
border-color: var(--color-accent);
|
||||
outline: none;
|
||||
box-shadow: 0 0 0 2px rgb(0 122 255 / 20%);
|
||||
}
|
||||
|
||||
.form-input::placeholder {
|
||||
color: var(--color-text-secondary);
|
||||
}
|
||||
|
||||
.form-input.error {
|
||||
border-color: var(--color-error, #ef4444);
|
||||
}
|
||||
|
||||
.form-input.error:focus {
|
||||
box-shadow: 0 0 0 2px rgb(239 68 68 / 20%);
|
||||
}
|
||||
|
||||
/* Select Styles */
|
||||
.select-wrapper {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.form-select {
|
||||
border: 1px solid var(--color-border);
|
||||
border-radius: var(--radius-md);
|
||||
padding: 0.75rem 2.5rem 0.75rem 1rem;
|
||||
width: 100%;
|
||||
font-size: 0.875rem;
|
||||
font-family: inherit;
|
||||
color: var(--color-text-primary);
|
||||
background: var(--color-surface-elevated);
|
||||
transition: var(--transition-fast);
|
||||
appearance: none;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.form-select:focus {
|
||||
border-color: var(--color-accent);
|
||||
outline: none;
|
||||
box-shadow: 0 0 0 2px rgb(0 122 255 / 20%);
|
||||
}
|
||||
|
||||
.form-select.error {
|
||||
border-color: var(--color-error, #ef4444);
|
||||
}
|
||||
|
||||
.form-select.error:focus {
|
||||
box-shadow: 0 0 0 2px rgb(239 68 68 / 20%);
|
||||
}
|
||||
|
||||
.select-arrow {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
right: 1rem;
|
||||
color: var(--color-text-secondary);
|
||||
transition: var(--transition-fast);
|
||||
transform: translateY(-50%);
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.select-wrapper:hover .select-arrow,
|
||||
.form-select:focus + .select-arrow {
|
||||
color: var(--color-accent);
|
||||
}
|
||||
|
||||
/* Checkbox Group Styles */
|
||||
.checkbox-group {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.75rem;
|
||||
padding: 0.5rem 0;
|
||||
}
|
||||
|
||||
.checkbox-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.checkbox-label {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.75rem;
|
||||
cursor: pointer;
|
||||
font-size: 0.875rem;
|
||||
color: var(--color-text-primary);
|
||||
transition: var(--transition-fast);
|
||||
}
|
||||
|
||||
.checkbox-label:hover {
|
||||
color: var(--color-accent);
|
||||
}
|
||||
|
||||
.checkbox-input {
|
||||
position: absolute;
|
||||
opacity: 0;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.checkbox-custom {
|
||||
position: relative;
|
||||
border: 2px solid var(--color-border);
|
||||
border-radius: var(--radius-sm);
|
||||
width: 1.25rem;
|
||||
height: 1.25rem;
|
||||
background: var(--color-surface-elevated);
|
||||
transition: var(--transition-fast);
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.checkbox-custom::after {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 3px;
|
||||
border: solid white;
|
||||
border-width: 0 2px 2px 0;
|
||||
width: 6px;
|
||||
height: 10px;
|
||||
opacity: 0;
|
||||
transition: var(--transition-fast);
|
||||
content: '';
|
||||
transform: rotate(45deg);
|
||||
}
|
||||
|
||||
.checkbox-input:checked + .checkbox-custom {
|
||||
border-color: var(--color-accent);
|
||||
background: var(--color-accent);
|
||||
}
|
||||
|
||||
.checkbox-input:checked + .checkbox-custom::after {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.checkbox-input:focus + .checkbox-custom {
|
||||
box-shadow: 0 0 0 2px rgb(0 122 255 / 20%);
|
||||
}
|
||||
|
||||
.checkbox-text {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
/* Switch Styles */
|
||||
.switch-label {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 1rem;
|
||||
cursor: pointer;
|
||||
font-size: 0.875rem;
|
||||
color: var(--color-text-primary);
|
||||
}
|
||||
|
||||
.switch-input {
|
||||
position: absolute;
|
||||
opacity: 0;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.switch-slider {
|
||||
position: relative;
|
||||
border-radius: 0.75rem;
|
||||
width: 3rem;
|
||||
height: 1.5rem;
|
||||
background: var(--color-border);
|
||||
transition: var(--transition-fast);
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.switch-button {
|
||||
position: absolute;
|
||||
top: 2px;
|
||||
left: 2px;
|
||||
border-radius: 50%;
|
||||
width: 1.25rem;
|
||||
height: 1.25rem;
|
||||
background: white;
|
||||
box-shadow: var(--shadow-sm);
|
||||
transition: var(--transition-fast);
|
||||
}
|
||||
|
||||
.switch-input:checked + .switch-slider {
|
||||
background: var(--color-accent);
|
||||
}
|
||||
|
||||
.switch-input:checked + .switch-slider .switch-button {
|
||||
transform: translateX(1.5rem);
|
||||
}
|
||||
|
||||
.switch-input:focus + .switch-slider {
|
||||
box-shadow: 0 0 0 2px rgb(0 122 255 / 20%);
|
||||
}
|
||||
|
||||
.switch-text {
|
||||
font-weight: 500;
|
||||
color: var(--color-text-secondary);
|
||||
}
|
||||
|
||||
.switch-input:checked ~ .switch-text {
|
||||
color: var(--color-accent);
|
||||
}
|
||||
|
||||
/* Error Message */
|
||||
.error-message {
|
||||
margin-top: 0.25rem;
|
||||
font-size: 0.75rem;
|
||||
color: var(--color-error, #ef4444);
|
||||
}
|
||||
|
||||
/* White theme adjustments */
|
||||
.white .form-input,
|
||||
.white .form-select {
|
||||
border-color: #dddddd;
|
||||
background: white;
|
||||
}
|
||||
|
||||
.white .form-input:focus,
|
||||
.white .form-select:focus {
|
||||
border-color: var(--color-accent);
|
||||
}
|
||||
|
||||
.white .checkbox-custom {
|
||||
border-color: #dddddd;
|
||||
background: white;
|
||||
}
|
||||
|
||||
.white .switch-slider {
|
||||
background: #dddddd;
|
||||
}
|
||||
|
||||
.white .tooltip-content {
|
||||
border-color: #dddddd;
|
||||
background: white;
|
||||
}
|
||||
|
||||
/* Responsive Design */
|
||||
@media (width <= 768px) {
|
||||
.config-form {
|
||||
gap: 1.25rem;
|
||||
}
|
||||
|
||||
.form-input,
|
||||
.form-select {
|
||||
padding: 0.625rem 0.875rem;
|
||||
}
|
||||
|
||||
.form-select {
|
||||
padding-right: 2.25rem;
|
||||
}
|
||||
|
||||
.tooltip-content {
|
||||
min-width: 150px;
|
||||
max-width: 250px;
|
||||
}
|
||||
}
|
||||
|
||||
/* Dark mode adjustments */
|
||||
:root.dark .form-input,
|
||||
:root.auto.dark .form-input,
|
||||
:root.dark .form-select,
|
||||
:root.auto.dark .form-select {
|
||||
border-color: var(--color-border);
|
||||
background: var(--color-surface-elevated);
|
||||
}
|
||||
|
||||
:root.dark .checkbox-custom,
|
||||
:root.auto.dark .checkbox-custom {
|
||||
border-color: var(--color-border);
|
||||
background: var(--color-surface-elevated);
|
||||
}
|
||||
|
||||
:root.dark .switch-slider,
|
||||
:root.auto.dark .switch-slider {
|
||||
background: var(--color-border);
|
||||
}
|
||||
|
||||
:root.dark .tooltip-content,
|
||||
:root.auto.dark .tooltip-content {
|
||||
border-color: var(--color-border);
|
||||
background: var(--color-surface-elevated);
|
||||
}
|
||||
|
||||
/* Focus styles for accessibility */
|
||||
.form-input:focus-visible,
|
||||
.form-select:focus-visible,
|
||||
.checkbox-input:focus-visible + .checkbox-custom,
|
||||
.switch-input:focus-visible + .switch-slider,
|
||||
.info-icon:focus-visible {
|
||||
outline: 2px solid var(--color-accent);
|
||||
outline-offset: 2px;
|
||||
}
|
||||
</style>
|
||||
<style scoped src="./css/UnifiedConfigForm.css"></style>
|
||||
|
||||
518
src/renderer/components/css/NavigationPage.css
Normal file
518
src/renderer/components/css/NavigationPage.css
Normal file
@@ -0,0 +1,518 @@
|
||||
.navigation {
|
||||
display: flex;
|
||||
overflow: hidden;
|
||||
border-right: 1px solid rgb(229 231 235);
|
||||
width: 150px;
|
||||
height: 100vh;
|
||||
background: var(--color-background-secondary);
|
||||
transition: width 0.3s ease;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.navigation.collapsed {
|
||||
width: 60px;
|
||||
}
|
||||
|
||||
:root.dark .navigation,
|
||||
:root.auto.dark .navigation {
|
||||
border-right-color: var(--color-background-secondary);
|
||||
background: var(--color-background-secondary);
|
||||
}
|
||||
|
||||
.title-bar {
|
||||
position: relative;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
border-bottom: 1px solid var(--color-border);
|
||||
padding: 1.25rem 1rem;
|
||||
background: var(--color-background-secondary);
|
||||
}
|
||||
|
||||
.navigation.collapsed .title-bar {
|
||||
padding: 1rem 0.5rem;
|
||||
}
|
||||
|
||||
.collapse-button {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
right: 8px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
padding: 4px;
|
||||
color: var(--color-text-primary);
|
||||
background: transparent;
|
||||
transition: all 0.2s ease;
|
||||
transform: translateY(-50%);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.collapse-button:hover {
|
||||
color: var(--color-text-primary);
|
||||
background: var(--color-surface-elevated);
|
||||
}
|
||||
|
||||
.navigation.collapsed .collapse-button {
|
||||
position: static;
|
||||
transform: none;
|
||||
}
|
||||
|
||||
:root.dark .title-bar,
|
||||
:root.auto.dark .title-bar {
|
||||
border-bottom-color: var(--color-border);
|
||||
background: var(--color-background-secondary);
|
||||
}
|
||||
|
||||
.app-title {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 0.25rem;
|
||||
}
|
||||
|
||||
.app-text {
|
||||
font-size: 16px;
|
||||
font-weight: 700;
|
||||
color: var(--color-text-primary);
|
||||
letter-spacing: -0.025em;
|
||||
}
|
||||
|
||||
.app-text:hover {
|
||||
cursor: pointer;
|
||||
color: var(--color-blue-common);
|
||||
}
|
||||
|
||||
.app-version {
|
||||
border: 1px solid var(--color-border);
|
||||
border-radius: 12px;
|
||||
padding: 3px 8px;
|
||||
font-size: 10px;
|
||||
font-weight: 500;
|
||||
color: var(--color-text-secondary);
|
||||
background: var(--color-surface-elevated);
|
||||
}
|
||||
|
||||
.theme-section {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
border-bottom: 1px solid var(--color-border);
|
||||
padding: 0.75rem;
|
||||
}
|
||||
|
||||
:root.dark .theme-section,
|
||||
:root.auto.dark .theme-section {
|
||||
border-bottom-color: var(--color-border);
|
||||
}
|
||||
|
||||
.nav-menu {
|
||||
overflow-y: auto;
|
||||
padding: 1rem 0;
|
||||
min-height: 0;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.nav-item {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
padding: 0.75rem 1rem;
|
||||
font-size: 0.875rem;
|
||||
font-weight: 500;
|
||||
text-decoration: none;
|
||||
color: rgb(75 85 99);
|
||||
transition: all 0.2s ease;
|
||||
gap: 0.75rem;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.navigation.collapsed .nav-item {
|
||||
justify-content: center;
|
||||
padding: 0.75rem 0.5rem;
|
||||
gap: 0;
|
||||
}
|
||||
|
||||
.navigation.collapsed .nav-label {
|
||||
display: none;
|
||||
}
|
||||
|
||||
:root.dark .nav-item,
|
||||
:root.auto.dark .nav-item {
|
||||
color: rgb(209 213 219);
|
||||
}
|
||||
|
||||
.nav-item:hover {
|
||||
color: rgb(17 24 39);
|
||||
background: rgb(243 244 246);
|
||||
}
|
||||
|
||||
:root.dark .nav-item:hover,
|
||||
:root.auto.dark .nav-item:hover {
|
||||
color: rgb(243 244 246);
|
||||
background: rgb(55 65 81);
|
||||
}
|
||||
|
||||
.nav-item.router-link-active {
|
||||
border-right: 3px solid rgb(99 102 241);
|
||||
color: rgb(99 102 241);
|
||||
background: rgb(239 246 255);
|
||||
}
|
||||
|
||||
:root.dark .nav-item.router-link-active,
|
||||
:root.auto.dark .nav-item.router-link-active {
|
||||
border-right-color: rgb(129 140 248);
|
||||
color: rgb(129 140 248);
|
||||
background: rgb(30 58 138 / 20%);
|
||||
}
|
||||
|
||||
.nav-icon-container {
|
||||
position: relative;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.sidebar-footer {
|
||||
border-top: 1px solid var(--color-border);
|
||||
padding: 12px;
|
||||
}
|
||||
|
||||
.footer-button {
|
||||
position: fixed;
|
||||
bottom: 4px;
|
||||
left: 4px;
|
||||
border: none;
|
||||
border-radius: 6px;
|
||||
padding: 8px;
|
||||
color: var(--color-text-secondary);
|
||||
background: transparent;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.footer-button:hover {
|
||||
color: var(--color-text-primary);
|
||||
background: var(--color-surface-elevated);
|
||||
}
|
||||
|
||||
.nav-submenu {
|
||||
position: relative;
|
||||
justify-content: center;
|
||||
margin-top: 4px;
|
||||
}
|
||||
|
||||
.submenu-trigger {
|
||||
position: relative;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
border: none;
|
||||
padding: 0.75rem 1rem;
|
||||
width: 100%;
|
||||
font-size: 0.875rem;
|
||||
font-weight: 500;
|
||||
text-decoration: none;
|
||||
color: rgb(75 85 99);
|
||||
background: transparent;
|
||||
transition: all 0.2s ease;
|
||||
gap: 0.75rem;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
:root.dark .submenu-trigger,
|
||||
:root.auto.dark .submenu-trigger {
|
||||
color: rgb(209 213 219);
|
||||
}
|
||||
|
||||
.submenu-trigger:hover {
|
||||
color: rgb(17 24 39);
|
||||
background: rgb(243 244 246);
|
||||
}
|
||||
|
||||
:root.dark .submenu-trigger:hover,
|
||||
:root.auto.dark .submenu-trigger:hover {
|
||||
color: rgb(243 244 246);
|
||||
background: rgb(55 65 81);
|
||||
}
|
||||
|
||||
.submenu-trigger .nav-icon-container {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.submenu-trigger span {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.submenu-arrow {
|
||||
position: absolute;
|
||||
right: 1rem;
|
||||
transition: transform 0.2s ease;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.rotate-180 {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
|
||||
.submenu-panel {
|
||||
display: flex;
|
||||
margin-top: 2px;
|
||||
padding-left: 2.75rem;
|
||||
flex-direction: column;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.submenu-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
border-radius: 6px;
|
||||
padding: 0.5rem 1rem;
|
||||
font-size: 0.8125rem;
|
||||
font-weight: 500;
|
||||
text-decoration: none;
|
||||
color: var(--color-text-secondary);
|
||||
transition: all 0.2s ease;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.submenu-item:hover {
|
||||
color: var(--color-text-primary);
|
||||
background: var(--color-surface-elevated);
|
||||
}
|
||||
|
||||
.collapsed-picbed {
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.collapsed-picbed:hover {
|
||||
color: rgb(17 24 39);
|
||||
background: rgb(243 244 246);
|
||||
}
|
||||
|
||||
:root.dark .collapsed-picbed:hover,
|
||||
:root.auto.dark .collapsed-picbed:hover {
|
||||
color: rgb(243 244 246);
|
||||
background: rgb(55 65 81);
|
||||
}
|
||||
|
||||
.qr-dialog {
|
||||
position: fixed;
|
||||
z-index: 50;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
overflow-y: auto;
|
||||
inset: 0;
|
||||
}
|
||||
|
||||
.dialog-container {
|
||||
position: fixed;
|
||||
z-index: 50;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
overflow-y: auto;
|
||||
padding: 16px;
|
||||
min-height: 100vh;
|
||||
inset: 0;
|
||||
}
|
||||
|
||||
.dialog-panel {
|
||||
overflow: hidden;
|
||||
border: 1px solid var(--color-border);
|
||||
border-radius: 16px;
|
||||
width: 100%;
|
||||
max-width: 500px;
|
||||
background: var(--color-background-primary);
|
||||
box-shadow: var(--shadow-md);
|
||||
}
|
||||
|
||||
.dialog-title {
|
||||
margin: 0;
|
||||
padding: 20px 24px 0;
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
color: var(--color-text-primary);
|
||||
}
|
||||
|
||||
.dialog-content {
|
||||
padding: 20px 24px;
|
||||
}
|
||||
|
||||
.form-group {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.form-label {
|
||||
display: block;
|
||||
margin-bottom: 8px;
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
color: var(--color-text-primary);
|
||||
}
|
||||
|
||||
.listbox-container {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.listbox-button {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
border: 1px solid var(--color-border);
|
||||
border-radius: var(--border-radius);
|
||||
padding: 12px 16px;
|
||||
width: 100%;
|
||||
font-size: 14px;
|
||||
color: var(--color-text-primary);
|
||||
background: var(--color-surface);
|
||||
transition: var(--transition);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.listbox-button:hover {
|
||||
border-color: var(--color-accent);
|
||||
}
|
||||
|
||||
.placeholder {
|
||||
color: var(--color-text-secondary);
|
||||
}
|
||||
|
||||
.selected-count {
|
||||
color: var(--color-text-primary);
|
||||
}
|
||||
|
||||
.listbox-arrow {
|
||||
color: var(--color-text-secondary);
|
||||
}
|
||||
|
||||
.listbox-options {
|
||||
position: absolute;
|
||||
top: 100%;
|
||||
right: 0;
|
||||
left: 0;
|
||||
z-index: 10;
|
||||
overflow-y: auto;
|
||||
margin-top: 4px;
|
||||
border: 1px solid var(--color-border);
|
||||
border-radius: var(--border-radius);
|
||||
max-height: 300px;
|
||||
background: var(--color-background-primary);
|
||||
box-shadow: var(--shadow-md);
|
||||
}
|
||||
|
||||
.listbox-option {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 12px 16px;
|
||||
font-size: 14px;
|
||||
color: var(--color-text-primary);
|
||||
transition: var(--transition);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.listbox-option.active {
|
||||
background: var(--color-surface-elevated);
|
||||
}
|
||||
|
||||
.listbox-option.selected {
|
||||
color: white;
|
||||
background: var(--color-accent);
|
||||
}
|
||||
|
||||
.copy-button {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-top: 12px;
|
||||
border: none;
|
||||
border-radius: var(--border-radius);
|
||||
padding: 10px 16px;
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
color: white;
|
||||
background: var(--color-accent);
|
||||
transition: var(--transition);
|
||||
gap: 8px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.copy-button:hover {
|
||||
background: var(--color-accent-hover);
|
||||
}
|
||||
|
||||
.qr-container {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
padding: 20px 0;
|
||||
}
|
||||
|
||||
.qr-code {
|
||||
overflow: hidden;
|
||||
border-radius: var(--border-radius);
|
||||
box-shadow: var(--shadow-sm);
|
||||
}
|
||||
|
||||
.dialog-actions {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
padding: 0 24px 20px;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.cancel-button {
|
||||
border: 1px solid var(--color-border);
|
||||
border-radius: var(--border-radius);
|
||||
padding: 10px 20px;
|
||||
font-size: 14px;
|
||||
color: var(--color-text-primary);
|
||||
background: var(--color-surface-elevated);
|
||||
transition: var(--transition);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.cancel-button:hover {
|
||||
background: var(--color-border);
|
||||
}
|
||||
|
||||
/* Responsive Design */
|
||||
@media (width <= 768px) {
|
||||
.navigation {
|
||||
width: 60px;
|
||||
}
|
||||
|
||||
.nav-label {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.app-title {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.collapse-button {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
/* Scrollbar Styling */
|
||||
::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-track {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb {
|
||||
border-radius: 0;
|
||||
background: var(--color-border);
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb:hover {
|
||||
background: var(--color-text-secondary);
|
||||
}
|
||||
381
src/renderer/components/css/UnifiedConfigForm.css
Normal file
381
src/renderer/components/css/UnifiedConfigForm.css
Normal file
@@ -0,0 +1,381 @@
|
||||
#config-form {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.config-form {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 1.5rem;
|
||||
}
|
||||
|
||||
/* Form Groups */
|
||||
.form-group {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
.form-group.required .form-label::after {
|
||||
content: ' *';
|
||||
color: var(--color-error, #ef4444);
|
||||
}
|
||||
|
||||
.form-label-wrapper {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
.form-label {
|
||||
font-size: 0.875rem;
|
||||
font-weight: 500;
|
||||
color: var(--color-text-primary);
|
||||
line-height: 1.25;
|
||||
}
|
||||
|
||||
.form-control {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
/* Tooltip Styles */
|
||||
.tooltip-wrapper {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.info-icon {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
border-radius: 50%;
|
||||
padding: 2px;
|
||||
color: var(--color-text-secondary);
|
||||
transition: var(--transition-fast);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.info-icon:hover {
|
||||
color: var(--color-accent);
|
||||
background: rgb(0 122 255 / 10%);
|
||||
}
|
||||
|
||||
.tooltip-content {
|
||||
position: absolute;
|
||||
top: 100%;
|
||||
left: 0;
|
||||
z-index: 1000;
|
||||
border: 1px solid var(--color-border);
|
||||
border-radius: var(--radius-md);
|
||||
padding: 0.75rem;
|
||||
min-width: 200px;
|
||||
max-width: 300px;
|
||||
font-size: 0.75rem;
|
||||
color: var(--color-text-primary);
|
||||
background: var(--color-surface-elevated);
|
||||
box-shadow: var(--shadow-lg);
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
/* Input Styles */
|
||||
.form-input {
|
||||
border: 1px solid var(--color-border);
|
||||
border-radius: var(--radius-md);
|
||||
padding: 0.75rem 1rem;
|
||||
width: 100%;
|
||||
font-size: 0.875rem;
|
||||
font-family: inherit;
|
||||
color: var(--color-text-primary);
|
||||
background: var(--color-surface-elevated);
|
||||
transition: var(--transition-fast);
|
||||
}
|
||||
|
||||
.form-input:focus {
|
||||
border-color: var(--color-accent);
|
||||
outline: none;
|
||||
box-shadow: 0 0 0 2px rgb(0 122 255 / 20%);
|
||||
}
|
||||
|
||||
.form-input::placeholder {
|
||||
color: var(--color-text-secondary);
|
||||
}
|
||||
|
||||
.form-input.error {
|
||||
border-color: var(--color-error, #ef4444);
|
||||
}
|
||||
|
||||
.form-input.error:focus {
|
||||
box-shadow: 0 0 0 2px rgb(239 68 68 / 20%);
|
||||
}
|
||||
|
||||
/* Select Styles */
|
||||
.select-wrapper {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.form-select {
|
||||
border: 1px solid var(--color-border);
|
||||
border-radius: var(--radius-md);
|
||||
padding: 0.75rem 2.5rem 0.75rem 1rem;
|
||||
width: 100%;
|
||||
font-size: 0.875rem;
|
||||
font-family: inherit;
|
||||
color: var(--color-text-primary);
|
||||
background: var(--color-surface-elevated);
|
||||
transition: var(--transition-fast);
|
||||
appearance: none;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.form-select:focus {
|
||||
border-color: var(--color-accent);
|
||||
outline: none;
|
||||
box-shadow: 0 0 0 2px rgb(0 122 255 / 20%);
|
||||
}
|
||||
|
||||
.form-select.error {
|
||||
border-color: var(--color-error, #ef4444);
|
||||
}
|
||||
|
||||
.form-select.error:focus {
|
||||
box-shadow: 0 0 0 2px rgb(239 68 68 / 20%);
|
||||
}
|
||||
|
||||
.select-arrow {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
right: 1rem;
|
||||
color: var(--color-text-secondary);
|
||||
transition: var(--transition-fast);
|
||||
transform: translateY(-50%);
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.select-wrapper:hover .select-arrow,
|
||||
.form-select:focus + .select-arrow {
|
||||
color: var(--color-accent);
|
||||
}
|
||||
|
||||
/* Checkbox Group Styles */
|
||||
.checkbox-group {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.75rem;
|
||||
padding: 0.5rem 0;
|
||||
}
|
||||
|
||||
.checkbox-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.checkbox-label {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.75rem;
|
||||
cursor: pointer;
|
||||
font-size: 0.875rem;
|
||||
color: var(--color-text-primary);
|
||||
transition: var(--transition-fast);
|
||||
}
|
||||
|
||||
.checkbox-label:hover {
|
||||
color: var(--color-accent);
|
||||
}
|
||||
|
||||
.checkbox-input {
|
||||
position: absolute;
|
||||
opacity: 0;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.checkbox-custom {
|
||||
position: relative;
|
||||
border: 2px solid var(--color-border);
|
||||
border-radius: var(--radius-sm);
|
||||
width: 1.25rem;
|
||||
height: 1.25rem;
|
||||
background: var(--color-surface-elevated);
|
||||
transition: var(--transition-fast);
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.checkbox-custom::after {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 3px;
|
||||
border: solid white;
|
||||
border-width: 0 2px 2px 0;
|
||||
width: 6px;
|
||||
height: 10px;
|
||||
opacity: 0;
|
||||
transition: var(--transition-fast);
|
||||
content: '';
|
||||
transform: rotate(45deg);
|
||||
}
|
||||
|
||||
.checkbox-input:checked + .checkbox-custom {
|
||||
border-color: var(--color-accent);
|
||||
background: var(--color-accent);
|
||||
}
|
||||
|
||||
.checkbox-input:checked + .checkbox-custom::after {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.checkbox-input:focus + .checkbox-custom {
|
||||
box-shadow: 0 0 0 2px rgb(0 122 255 / 20%);
|
||||
}
|
||||
|
||||
.checkbox-text {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
/* Switch Styles */
|
||||
.switch-label {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 1rem;
|
||||
cursor: pointer;
|
||||
font-size: 0.875rem;
|
||||
color: var(--color-text-primary);
|
||||
}
|
||||
|
||||
.switch-input {
|
||||
position: absolute;
|
||||
opacity: 0;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.switch-slider {
|
||||
position: relative;
|
||||
border-radius: 0.75rem;
|
||||
width: 3rem;
|
||||
height: 1.5rem;
|
||||
background: var(--color-border);
|
||||
transition: var(--transition-fast);
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.switch-button {
|
||||
position: absolute;
|
||||
top: 2px;
|
||||
left: 2px;
|
||||
border-radius: 50%;
|
||||
width: 1.25rem;
|
||||
height: 1.25rem;
|
||||
background: white;
|
||||
box-shadow: var(--shadow-sm);
|
||||
transition: var(--transition-fast);
|
||||
}
|
||||
|
||||
.switch-input:checked + .switch-slider {
|
||||
background: var(--color-accent);
|
||||
}
|
||||
|
||||
.switch-input:checked + .switch-slider .switch-button {
|
||||
transform: translateX(1.5rem);
|
||||
}
|
||||
|
||||
.switch-input:focus + .switch-slider {
|
||||
box-shadow: 0 0 0 2px rgb(0 122 255 / 20%);
|
||||
}
|
||||
|
||||
.switch-text {
|
||||
font-weight: 500;
|
||||
color: var(--color-text-secondary);
|
||||
}
|
||||
|
||||
.switch-input:checked ~ .switch-text {
|
||||
color: var(--color-accent);
|
||||
}
|
||||
|
||||
/* Error Message */
|
||||
.error-message {
|
||||
margin-top: 0.25rem;
|
||||
font-size: 0.75rem;
|
||||
color: var(--color-error, #ef4444);
|
||||
}
|
||||
|
||||
/* White theme adjustments */
|
||||
.white .form-input,
|
||||
.white .form-select {
|
||||
border-color: #dddddd;
|
||||
background: white;
|
||||
}
|
||||
|
||||
.white .form-input:focus,
|
||||
.white .form-select:focus {
|
||||
border-color: var(--color-accent);
|
||||
}
|
||||
|
||||
.white .checkbox-custom {
|
||||
border-color: #dddddd;
|
||||
background: white;
|
||||
}
|
||||
|
||||
.white .switch-slider {
|
||||
background: #dddddd;
|
||||
}
|
||||
|
||||
.white .tooltip-content {
|
||||
border-color: #dddddd;
|
||||
background: white;
|
||||
}
|
||||
|
||||
/* Responsive Design */
|
||||
@media (width <= 768px) {
|
||||
.config-form {
|
||||
gap: 1.25rem;
|
||||
}
|
||||
|
||||
.form-input,
|
||||
.form-select {
|
||||
padding: 0.625rem 0.875rem;
|
||||
}
|
||||
|
||||
.form-select {
|
||||
padding-right: 2.25rem;
|
||||
}
|
||||
|
||||
.tooltip-content {
|
||||
min-width: 150px;
|
||||
max-width: 250px;
|
||||
}
|
||||
}
|
||||
|
||||
/* Dark mode adjustments */
|
||||
:root.dark .form-input,
|
||||
:root.auto.dark .form-input,
|
||||
:root.dark .form-select,
|
||||
:root.auto.dark .form-select {
|
||||
border-color: var(--color-border);
|
||||
background: var(--color-surface-elevated);
|
||||
}
|
||||
|
||||
:root.dark .checkbox-custom,
|
||||
:root.auto.dark .checkbox-custom {
|
||||
border-color: var(--color-border);
|
||||
background: var(--color-surface-elevated);
|
||||
}
|
||||
|
||||
:root.dark .switch-slider,
|
||||
:root.auto.dark .switch-slider {
|
||||
background: var(--color-border);
|
||||
}
|
||||
|
||||
:root.dark .tooltip-content,
|
||||
:root.auto.dark .tooltip-content {
|
||||
border-color: var(--color-border);
|
||||
background: var(--color-surface-elevated);
|
||||
}
|
||||
|
||||
/* Focus styles for accessibility */
|
||||
.form-input:focus-visible,
|
||||
.form-select:focus-visible,
|
||||
.checkbox-input:focus-visible + .checkbox-custom,
|
||||
.switch-input:focus-visible + .switch-slider,
|
||||
.info-icon:focus-visible {
|
||||
outline: 2px solid var(--color-accent);
|
||||
outline-offset: 2px;
|
||||
}
|
||||
@@ -43,8 +43,8 @@
|
||||
import { MinusIcon, PinIcon, ShrinkIcon, XIcon } from 'lucide-vue-next'
|
||||
import { computed, onBeforeMount, onBeforeUnmount, ref } from 'vue'
|
||||
|
||||
import { osGlobal } from '@/hooks/useGlobal'
|
||||
import { IRPCActionType } from '@/utils/enum'
|
||||
import { osGlobal } from '@/utils/global'
|
||||
|
||||
const isShowprogress = ref(false)
|
||||
const progress = ref(0)
|
||||
|
||||
Reference in New Issue
Block a user