mirror of
https://github.com/OpenListTeam/OpenList-Desktop.git
synced 2025-11-25 03:14:56 +08:00
feat: add option to open links in external browser and fix app setting css error
This commit is contained in:
@@ -61,6 +61,17 @@ pub async fn open_url(url: String) -> Result<bool, String> {
|
||||
Ok(true)
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn open_url_in_browser(url: String, app_handle: AppHandle) -> Result<bool, String> {
|
||||
use tauri_plugin_opener::OpenerExt;
|
||||
|
||||
app_handle
|
||||
.opener()
|
||||
.open_url(url, None::<&str>)
|
||||
.map_err(|e| e.to_string())?;
|
||||
Ok(true)
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub fn select_directory(title: String, app_handle: AppHandle) -> Result<Option<String>, String> {
|
||||
use tauri_plugin_dialog::DialogExt;
|
||||
|
||||
@@ -7,6 +7,7 @@ pub struct AppConfig {
|
||||
pub auto_update_enabled: Option<bool>,
|
||||
pub gh_proxy: Option<String>,
|
||||
pub gh_proxy_api: Option<bool>,
|
||||
pub open_links_in_browser: Option<bool>,
|
||||
}
|
||||
|
||||
impl AppConfig {
|
||||
@@ -17,6 +18,7 @@ impl AppConfig {
|
||||
auto_update_enabled: Some(true),
|
||||
gh_proxy: None,
|
||||
gh_proxy_api: Some(false),
|
||||
open_links_in_browser: Some(false),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,8 +19,8 @@ use cmd::http_api::{
|
||||
use cmd::logs::{clear_logs, get_admin_password, get_logs};
|
||||
use cmd::openlist_core::{create_openlist_core_process, get_openlist_core_status};
|
||||
use cmd::os_operate::{
|
||||
get_available_versions, list_files, open_file, open_folder, open_url, select_directory,
|
||||
update_tool_version,
|
||||
get_available_versions, list_files, open_file, open_folder, open_url, open_url_in_browser,
|
||||
select_directory, update_tool_version,
|
||||
};
|
||||
use cmd::rclone_core::{
|
||||
create_and_start_rclone_backend, create_rclone_backend_process, get_rclone_backend_status,
|
||||
@@ -139,6 +139,7 @@ pub fn run() {
|
||||
open_file,
|
||||
open_folder,
|
||||
open_url,
|
||||
open_url_in_browser,
|
||||
save_settings,
|
||||
save_settings_with_update_port,
|
||||
load_settings,
|
||||
|
||||
@@ -60,7 +60,8 @@ export class TauriAPI {
|
||||
list: (path: string): Promise<FileItem[]> => call('list_files', { path }),
|
||||
open: (path: string): Promise<boolean> => call('open_file', { path }),
|
||||
folder: (path: string): Promise<boolean> => call('open_folder', { path }),
|
||||
url: (path: string): Promise<boolean> => call('open_url', { path })
|
||||
url: (path: string): Promise<boolean> => call('open_url', { path }),
|
||||
urlInBrowser: (url: string): Promise<boolean> => call('open_url_in_browser', { url })
|
||||
}
|
||||
|
||||
// --- Settings management ---
|
||||
|
||||
@@ -27,7 +27,13 @@ const navigationItems = computed(() => [
|
||||
|
||||
const openLink = async (url: string) => {
|
||||
try {
|
||||
await TauriAPI.files.url(url)
|
||||
const openInBrowser = appStore.settings.app.open_links_in_browser ?? false
|
||||
|
||||
if (openInBrowser) {
|
||||
await TauriAPI.files.urlInBrowser(url)
|
||||
} else {
|
||||
await TauriAPI.files.url(url)
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Failed to open link:', error)
|
||||
window.open(url, '_blank')
|
||||
|
||||
@@ -79,8 +79,10 @@ import { useTranslation } from '../../composables/useI18n'
|
||||
import { ExternalLink, Github, BookOpen, Cloud, Code, Terminal, HelpCircle, MessageCircle } from 'lucide-vue-next'
|
||||
import Card from '../ui/Card.vue'
|
||||
import { TauriAPI } from '../../api/tauri'
|
||||
import { useAppStore } from '../../stores/app'
|
||||
|
||||
const { t } = useTranslation()
|
||||
const appStore = useAppStore()
|
||||
|
||||
const openOpenListDocs = () => {
|
||||
openLink('https://docs.oplist.org/')
|
||||
@@ -100,7 +102,13 @@ const openRcloneGitHub = () => {
|
||||
|
||||
const openLink = async (url: string) => {
|
||||
try {
|
||||
await TauriAPI.files.url(url)
|
||||
const openInBrowser = appStore.settings.app.open_links_in_browser ?? false
|
||||
|
||||
if (openInBrowser) {
|
||||
await TauriAPI.files.urlInBrowser(url)
|
||||
} else {
|
||||
await TauriAPI.files.url(url)
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Failed to open link:', error)
|
||||
window.open(url, '_blank')
|
||||
|
||||
@@ -183,6 +183,14 @@
|
||||
"description": "Also use proxy for api.github.com URLs "
|
||||
}
|
||||
},
|
||||
"links": {
|
||||
"title": "Link Handling",
|
||||
"subtitle": "Configure how links are opened",
|
||||
"openInBrowser": {
|
||||
"title": "Open links in external browser",
|
||||
"description": "Use system default browser instead of built-in window"
|
||||
}
|
||||
},
|
||||
"tutorial": {
|
||||
"title": "Tutorial",
|
||||
"subtitle": "Learn how to use OpenList Desktop",
|
||||
|
||||
@@ -183,6 +183,14 @@
|
||||
"description": "同时为 api.github.com 地址使用代理"
|
||||
}
|
||||
},
|
||||
"links": {
|
||||
"title": "链接处理",
|
||||
"subtitle": "配置链接的打开方式",
|
||||
"openInBrowser": {
|
||||
"title": "在外部浏览器中打开链接",
|
||||
"description": "使用系统默认浏览器而不是内置窗口"
|
||||
}
|
||||
},
|
||||
"tutorial": {
|
||||
"title": "教程",
|
||||
"subtitle": "学习如何使用 OpenList 桌面版",
|
||||
|
||||
1
src/types/types.d.ts
vendored
1
src/types/types.d.ts
vendored
@@ -49,6 +49,7 @@ interface AppConfig {
|
||||
auto_update_enabled?: boolean
|
||||
gh_proxy?: string
|
||||
gh_proxy_api?: boolean
|
||||
open_links_in_browser?: boolean
|
||||
}
|
||||
|
||||
interface MergedSettings {
|
||||
|
||||
@@ -72,6 +72,7 @@ onMounted(async () => {
|
||||
if (appSettings.auto_update_enabled === undefined) appSettings.auto_update_enabled = true
|
||||
if (!appSettings.gh_proxy) appSettings.gh_proxy = ''
|
||||
if (appSettings.gh_proxy_api === undefined) appSettings.gh_proxy_api = false
|
||||
if (appSettings.open_links_in_browser === undefined) appSettings.open_links_in_browser = false
|
||||
originalOpenlistPort = openlistCoreSettings.port || 5244
|
||||
})
|
||||
|
||||
@@ -378,6 +379,22 @@ const handleReset = async () => {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="settings-section">
|
||||
<h2>{{ t('settings.app.links.title') }}</h2>
|
||||
<p>{{ t('settings.app.links.subtitle') }}</p>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="switch-label">
|
||||
<input v-model="appSettings.open_links_in_browser" type="checkbox" class="switch-input" />
|
||||
<span class="switch-slider"></span>
|
||||
<div class="switch-content">
|
||||
<span class="switch-title">{{ t('settings.app.links.openInBrowser.title') }}</span>
|
||||
<span class="switch-description">{{ t('settings.app.links.openInBrowser.description') }}</span>
|
||||
</div>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="settings-section">
|
||||
<h2>{{ t('settings.app.tutorial.title') }}</h2>
|
||||
<p>{{ t('settings.app.tutorial.subtitle') }}</p>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
.settings-container {
|
||||
padding: 2rem;
|
||||
height: 100vh;
|
||||
min-height: 100vh;
|
||||
background: var(--color-background-secondary);
|
||||
color: var(--color-text-primary);
|
||||
overflow-y: auto;
|
||||
@@ -229,6 +229,7 @@
|
||||
border-radius: 12px;
|
||||
overflow: hidden;
|
||||
box-shadow: var(--shadow-sm);
|
||||
min-height: fit-content;
|
||||
}
|
||||
|
||||
:root.dark .settings-content,
|
||||
@@ -239,6 +240,7 @@
|
||||
|
||||
.tab-content {
|
||||
padding: 2rem;
|
||||
min-height: fit-content;
|
||||
}
|
||||
|
||||
.settings-section {
|
||||
@@ -390,7 +392,7 @@
|
||||
/* Switch */
|
||||
.switch-label {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
align-items: center;
|
||||
gap: 0.75rem;
|
||||
cursor: pointer;
|
||||
padding: 1rem;
|
||||
@@ -398,22 +400,24 @@
|
||||
border-radius: 8px;
|
||||
background: var(--color-background-tertiary);
|
||||
transition: all 0.2s ease;
|
||||
min-height: auto;
|
||||
}
|
||||
|
||||
.switch-label:hover {
|
||||
background: rgb(243 244 246);
|
||||
border-color: rgb(209 213 219);
|
||||
background: var(--color-background-secondary);
|
||||
border-color: var(--color-border);
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
.switch-label {
|
||||
background: rgb(55 65 81);
|
||||
border-color: rgb(75 85 99);
|
||||
}
|
||||
:root.dark .switch-label,
|
||||
:root.auto.dark .switch-label {
|
||||
background: var(--color-background-tertiary);
|
||||
border-color: var(--color-border);
|
||||
}
|
||||
|
||||
.switch-label:hover {
|
||||
background: rgb(75 85 99);
|
||||
}
|
||||
:root.dark .switch-label:hover,
|
||||
:root.auto.dark .switch-label:hover {
|
||||
background: var(--color-background-secondary);
|
||||
border-color: var(--color-border);
|
||||
}
|
||||
|
||||
.switch-input {
|
||||
@@ -426,11 +430,10 @@
|
||||
position: relative;
|
||||
width: 44px;
|
||||
height: 24px;
|
||||
background: rgb(209 213 219);
|
||||
background: var(--color-border);
|
||||
border-radius: 12px;
|
||||
transition: all 0.2s ease;
|
||||
flex-shrink: 0;
|
||||
margin-top: 2px;
|
||||
}
|
||||
|
||||
.switch-slider::before {
|
||||
@@ -447,7 +450,7 @@
|
||||
}
|
||||
|
||||
.switch-input:checked + .switch-slider {
|
||||
background: rgb(59 130 246);
|
||||
background: var(--color-accent);
|
||||
}
|
||||
|
||||
.switch-input:checked + .switch-slider::before {
|
||||
@@ -458,23 +461,30 @@
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.125rem;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.switch-title {
|
||||
font-weight: 500;
|
||||
color: rgb(55 65 81);
|
||||
color: var(--color-text-primary);
|
||||
font-size: 0.875rem;
|
||||
line-height: 1.25;
|
||||
}
|
||||
|
||||
.switch-description {
|
||||
font-size: 0.75rem;
|
||||
color: rgb(107 114 128);
|
||||
color: var(--color-text-secondary);
|
||||
line-height: 1.25;
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
.switch-title {
|
||||
color: rgb(209 213 219);
|
||||
}
|
||||
:root.dark .switch-title,
|
||||
:root.auto.dark .switch-title {
|
||||
color: var(--color-text-primary);
|
||||
}
|
||||
|
||||
:root.dark .switch-description,
|
||||
:root.auto.dark .switch-description {
|
||||
color: var(--color-text-secondary);
|
||||
}
|
||||
|
||||
/* Flags */
|
||||
|
||||
Reference in New Issue
Block a user