feat: add WinFSP installation tips for Windows users close #37

This commit is contained in:
Kuingsmile
2025-07-04 13:46:35 +08:00
parent 4d2229c628
commit 9b85453ed0
5 changed files with 176 additions and 22 deletions

2
src-tauri/Cargo.lock generated
View File

@@ -2887,7 +2887,7 @@ dependencies = [
[[package]] [[package]]
name = "openlist-desktop" name = "openlist-desktop"
version = "0.1.0" version = "0.2.0"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"base64 0.22.1", "base64 0.22.1",

View File

@@ -358,6 +358,8 @@
"tip": { "tip": {
"webdavTitle": "Enable WebDAV Management Required", "webdavTitle": "Enable WebDAV Management Required",
"webdavMessage": "Before mounting remotes, please ensure WebDAV management for specific user is enabled in OpenList Core.", "webdavMessage": "Before mounting remotes, please ensure WebDAV management for specific user is enabled in OpenList Core.",
"winfspTitle": "WinFSP Installation Required",
"winfspMessage": "On Windows, you need to install WinFSP first to use mount functionality. Please download and install it from GitHub: https://github.com/winfsp/winfsp/releases",
"dismissForever": "Dismiss forever" "dismissForever": "Dismiss forever"
} }
}, },

View File

@@ -358,6 +358,8 @@
"tip": { "tip": {
"webdavTitle": "需要启用 WebDAV 管理功能", "webdavTitle": "需要启用 WebDAV 管理功能",
"webdavMessage": "在挂载远程存储之前,请确保在 OpenList 核心中为用户启用了 WebDAV 管理功能", "webdavMessage": "在挂载远程存储之前,请确保在 OpenList 核心中为用户启用了 WebDAV 管理功能",
"winfspTitle": "需要安装 WinFSP",
"winfspMessage": "在 Windows 系统上,您需要先安装 WinFSP 才能使用挂载功能。请从 GitHub 下载并安装https://github.com/winfsp/winfsp/releases",
"dismissForever": "永久关闭" "dismissForever": "永久关闭"
} }
}, },

View File

@@ -330,6 +330,21 @@ const dismissWebdavTip = () => {
localStorage.setItem('webdav_tip_dismissed', 'true') localStorage.setItem('webdav_tip_dismissed', 'true')
} }
const isWindows = /win/i.test(navigator.platform) || /win/i.test(navigator.userAgent)
const showWinfspTip = ref(isWindows && !localStorage.getItem('winfsp_tip_dismissed'))
const dismissWinfspTip = () => {
showWinfspTip.value = false
localStorage.setItem('winfsp_tip_dismissed', 'true')
}
const shouldShowWebdavTip = computed(() => {
if (isWindows) {
return !showWinfspTip.value && showWebdavTip.value
}
return showWebdavTip.value
})
onMounted(async () => { onMounted(async () => {
document.addEventListener('keydown', handleKeydown) document.addEventListener('keydown', handleKeydown)
await rcloneStore.checkRcloneBackendStatus() await rcloneStore.checkRcloneBackendStatus()
@@ -408,7 +423,7 @@ onUnmounted(() => {
</div> </div>
</div> </div>
<div v-if="showWebdavTip" class="webdav-tip"> <div v-if="shouldShowWebdavTip" class="webdav-tip">
<div class="tip-content"> <div class="tip-content">
<div class="tip-icon"> <div class="tip-icon">
<Settings class="icon" /> <Settings class="icon" />
@@ -423,6 +438,21 @@ onUnmounted(() => {
</div> </div>
</div> </div>
<div v-if="showWinfspTip" class="winfsp-tip">
<div class="tip-content">
<div class="tip-icon">
<HardDrive class="icon" />
</div>
<div class="tip-message">
<h4 class="tip-title">{{ t('mount.tip.winfspTitle') }}</h4>
<p class="tip-description">{{ t('mount.tip.winfspMessage') }}</p>
</div>
<button @click="dismissWinfspTip" class="tip-close" :title="t('mount.tip.dismissForever')">
<X class="close-icon" />
</button>
</div>
</div>
<!-- Controls Section --> <!-- Controls Section -->
<div class="controls-section"> <div class="controls-section">
<div class="search-container"> <div class="search-container">

View File

@@ -1030,65 +1030,92 @@
.webdav-tip { .webdav-tip {
position: relative; position: relative;
z-index: 1; z-index: 1;
margin: 0 28px 20px; margin: 0 28px 12px;
background: linear-gradient(135deg, #fef3cd 0%, #fff3cd 100%); background: linear-gradient(135deg, #fef3cd 0%, #fff3cd 100%);
border: 1px solid #f9cc33; border: 1px solid #f9cc33;
border-radius: 12px; border-radius: 8px;
box-shadow: 0 2px 8px rgba(249, 204, 51, 0.1); box-shadow: 0 1px 4px rgba(249, 204, 51, 0.1);
overflow: hidden;
}
.winfsp-tip {
position: relative;
z-index: 1;
margin: 0 28px 12px;
background: linear-gradient(135deg, #dbeafe 0%, #e0f2fe 100%);
border: 1px solid #3b82f6;
border-radius: 8px;
box-shadow: 0 1px 4px rgba(59, 130, 246, 0.1);
overflow: hidden; overflow: hidden;
} }
.tip-content { .tip-content {
display: flex; display: flex;
align-items: flex-start; align-items: flex-start;
gap: 16px; gap: 12px;
padding: 16px 20px; padding: 12px 16px;
} }
.tip-icon { .tip-icon {
flex-shrink: 0; flex-shrink: 0;
width: 40px; width: 32px;
height: 40px; height: 32px;
background: rgba(249, 204, 51, 0.1); background: rgba(249, 204, 51, 0.1);
border-radius: 10px; border-radius: 6px;
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
} }
.winfsp-tip .tip-icon {
background: rgba(59, 130, 246, 0.1);
}
.tip-icon .icon { .tip-icon .icon {
width: 20px; width: 16px;
height: 20px; height: 16px;
color: #b45309; color: #b45309;
} }
.winfsp-tip .tip-icon .icon {
color: #1d4ed8;
}
.tip-message { .tip-message {
flex: 1; flex: 1;
min-width: 0; min-width: 0;
} }
.tip-title { .tip-title {
margin: 0 0 8px 0; margin: 0 0 4px 0;
font-size: 15px; font-size: 13px;
font-weight: 600; font-weight: 600;
color: #92400e; color: #92400e;
line-height: 1.3; line-height: 1.3;
} }
.winfsp-tip .tip-title {
color: #1e40af;
}
.tip-description { .tip-description {
margin: 0; margin: 0;
font-size: 14px; font-size: 12px;
color: #a16207; color: #a16207;
line-height: 1.5; line-height: 1.4;
}
.winfsp-tip .tip-description {
color: #1d4ed8;
} }
.tip-close { .tip-close {
flex-shrink: 0; flex-shrink: 0;
width: 32px; width: 28px;
height: 32px; height: 28px;
background: rgba(249, 204, 51, 0.1); background: rgba(249, 204, 51, 0.1);
border: none; border: none;
border-radius: 8px; border-radius: 6px;
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
@@ -1096,22 +1123,41 @@
transition: all 0.2s ease; transition: all 0.2s ease;
} }
.winfsp-tip .tip-close {
background: rgba(59, 130, 246, 0.1);
}
.tip-close:hover { .tip-close:hover {
background: rgba(249, 204, 51, 0.2); background: rgba(249, 204, 51, 0.2);
transform: scale(1.05); transform: scale(1.05);
} }
.winfsp-tip .tip-close:hover {
background: rgba(59, 130, 246, 0.2);
}
.tip-close .close-icon { .tip-close .close-icon {
width: 16px; width: 14px;
height: 16px; height: 14px;
color: #a16207; color: #a16207;
} }
.winfsp-tip .tip-close .close-icon {
color: #1d4ed8;
}
:root.dark .webdav-tip, :root.dark .webdav-tip,
:root.auto.dark .webdav-tip { :root.auto.dark .webdav-tip {
background: linear-gradient(135deg, #451a03 0%, #541c15 100%); background: linear-gradient(135deg, #451a03 0%, #541c15 100%);
border-color: #a16207; border-color: #a16207;
box-shadow: 0 2px 8px rgba(161, 98, 7, 0.1); box-shadow: 0 1px 4px rgba(161, 98, 7, 0.1);
}
:root.dark .winfsp-tip,
:root.auto.dark .winfsp-tip {
background: linear-gradient(135deg, #0f172a 0%, #1e293b 100%);
border-color: #3b82f6;
box-shadow: 0 1px 4px rgba(59, 130, 246, 0.1);
} }
:root.dark .tip-icon, :root.dark .tip-icon,
@@ -1119,36 +1165,71 @@
background: rgba(161, 98, 7, 0.1); background: rgba(161, 98, 7, 0.1);
} }
:root.dark .winfsp-tip .tip-icon,
:root.auto.dark .winfsp-tip .tip-icon {
background: rgba(59, 130, 246, 0.1);
}
:root.dark .tip-icon .icon, :root.dark .tip-icon .icon,
:root.auto.dark .tip-icon .icon { :root.auto.dark .tip-icon .icon {
color: #f59e0b; color: #f59e0b;
} }
:root.dark .winfsp-tip .tip-icon .icon,
:root.auto.dark .winfsp-tip .tip-icon .icon {
color: #60a5fa;
}
:root.dark .tip-title, :root.dark .tip-title,
:root.auto.dark .tip-title { :root.auto.dark .tip-title {
color: #fbbf24; color: #fbbf24;
} }
:root.dark .winfsp-tip .tip-title,
:root.auto.dark .winfsp-tip .tip-title {
color: #93c5fd;
}
:root.dark .tip-description, :root.dark .tip-description,
:root.auto.dark .tip-description { :root.auto.dark .tip-description {
color: #d97706; color: #d97706;
} }
:root.dark .winfsp-tip .tip-description,
:root.auto.dark .winfsp-tip .tip-description {
color: #60a5fa;
}
:root.dark .tip-close, :root.dark .tip-close,
:root.auto.dark .tip-close { :root.auto.dark .tip-close {
background: rgba(161, 98, 7, 0.1); background: rgba(161, 98, 7, 0.1);
} }
:root.dark .winfsp-tip .tip-close,
:root.auto.dark .winfsp-tip .tip-close {
background: rgba(59, 130, 246, 0.1);
}
:root.dark .tip-close:hover, :root.dark .tip-close:hover,
:root.auto.dark .tip-close:hover { :root.auto.dark .tip-close:hover {
background: rgba(161, 98, 7, 0.2); background: rgba(161, 98, 7, 0.2);
} }
:root.dark .winfsp-tip .tip-close:hover,
:root.auto.dark .winfsp-tip .tip-close:hover {
background: rgba(59, 130, 246, 0.2);
}
:root.dark .tip-close .close-icon, :root.dark .tip-close .close-icon,
:root.auto.dark .tip-close .close-icon { :root.auto.dark .tip-close .close-icon {
color: #d97706; color: #d97706;
} }
:root.dark .winfsp-tip .tip-close .close-icon,
:root.auto.dark .winfsp-tip .tip-close .close-icon {
color: #60a5fa;
}
@media (max-width: 1024px) { @media (max-width: 1024px) {
.header-content { .header-content {
grid-template-columns: 1fr; grid-template-columns: 1fr;
@@ -1197,6 +1278,45 @@
gap: 12px; gap: 12px;
} }
.webdav-tip,
.winfsp-tip {
margin: 0 16px 8px;
}
.tip-content {
padding: 10px 12px;
gap: 10px;
}
.tip-icon {
width: 28px;
height: 28px;
}
.tip-icon .icon {
width: 14px;
height: 14px;
}
.tip-title {
font-size: 12px;
margin-bottom: 2px;
}
.tip-description {
font-size: 11px;
}
.tip-close {
width: 24px;
height: 24px;
}
.tip-close .close-icon {
width: 12px;
height: 12px;
}
.config-grid { .config-grid {
grid-template-columns: 1fr; grid-template-columns: 1fr;
} }