请输入文本

This commit is contained in:
Fox_block
2026-01-27 10:05:25 +08:00
parent 6403795839
commit 487902141a
10 changed files with 14 additions and 426 deletions
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "secscore",
"version": "1.0.1",
"version": "1.0.0",
"description": "SecScore Your Education Points Management Expert",
"main": "./out/main/index.js",
"author": "example.com",
+2 -67
View File
@@ -87,7 +87,6 @@ const handleProtocolUrl = (rawUrl: string, ctx: MainContext) => {
}
const parts = s.split('/')
const head = parts[0]?.toLowerCase() ?? ''
const tail = parts.slice(1)
if (!head) {
openMainRoute(ctx, '/')
return
@@ -120,58 +119,6 @@ const handleProtocolUrl = (rawUrl: string, ctx: MainContext) => {
openMainRoute(ctx, '/settings')
return
}
if (head === 'sidebar') {
const action = tail[0]?.toLowerCase() ?? 'toggle'
const sidebarWin = ctx.windows.get('global-sidebar')
if (action === 'show') {
if (sidebarWin) {
sidebarWin.show()
sidebarWin.focus()
} else {
ctx.windows.open({
key: 'global-sidebar',
title: 'SecScore Sidebar',
route: '/global-sidebar',
options: {
transparent: true,
alwaysOnTop: true,
hasShadow: false,
type: 'toolbar'
}
})
}
return
}
if (action === 'hide') {
if (sidebarWin) {
sidebarWin.hide()
}
return
}
if (action === 'toggle') {
if (sidebarWin) {
if (sidebarWin.isVisible()) {
sidebarWin.hide()
} else {
sidebarWin.show()
sidebarWin.focus()
}
} else {
ctx.windows.open({
key: 'global-sidebar',
title: 'SecScore Sidebar',
route: '/global-sidebar',
options: {
transparent: true,
alwaysOnTop: true,
hasShadow: false,
type: 'toolbar'
}
})
}
return
}
}
}
const hasSingleInstanceLock = app.requestSingleInstanceLock()
@@ -307,7 +254,6 @@ app.whenReady().then(async () => {
})
.configure(async (_builderContext, appCtx) => {
const services = appCtx.services
const ctx = services.get(MainContext)
services.get(LoggerToken)
const db = services.get(DbManagerToken) as DbManager
await db.initialize()
@@ -325,19 +271,6 @@ app.whenReady().then(async () => {
services.get(WindowManagerToken)
const tray = services.get(TrayServiceToken) as TrayService
tray.initialize()
// Open Global Sidebar on startup
ctx.windows.open({
key: 'global-sidebar',
title: 'SecScore Sidebar',
route: '/global-sidebar',
options: {
transparent: true,
alwaysOnTop: true,
hasShadow: false,
type: 'toolbar'
}
})
})
const host = await builder.build()
@@ -366,6 +299,8 @@ app.whenReady().then(async () => {
if (pendingProtocolUrl) {
handleProtocolUrl(pendingProtocolUrl, ctx)
pendingProtocolUrl = null
} else {
openMainRoute(ctx, '/')
}
let disposing = false
+1 -22
View File
@@ -1,6 +1,6 @@
import { Service } from '../../shared/kernel'
import { MainContext } from '../context'
import { BrowserWindow, webContents, screen } from 'electron'
import { BrowserWindow, webContents } from 'electron'
import type { IpcMainInvokeEvent } from 'electron'
import type { settingsKey, settingsSpec, settingChange } from '../../preload/types'
import type { permissionLevel } from './PermissionService'
@@ -58,27 +58,6 @@ export class SettingsService extends Service {
webContents.getAllWebContents().forEach((wc: any) => {
wc.setZoomFactor(zoom)
})
const sidebarWindow = BrowserWindow.getAllWindows().find((win) => {
try {
return win.webContents.getURL().includes('#global-sidebar')
} catch {
return false
}
})
if (sidebarWindow && !sidebarWindow.isDestroyed()) {
const primaryDisplay = screen.getPrimaryDisplay()
const { width, height } = primaryDisplay.workAreaSize
const bounds = sidebarWindow.getBounds()
sidebarWindow.setBounds({
x: width - bounds.width,
y: Math.floor(height / 2 - bounds.height / 2),
width: bounds.width,
height: bounds.height
})
}
}
},
window_theme: {
-26
View File
@@ -28,32 +28,6 @@ export class TrayService extends Service {
this.showMainWindow()
}
},
{
label: '显隐悬浮侧边栏',
click: () => {
const sidebarWin = this.mainCtx.windows.get('global-sidebar')
if (sidebarWin) {
if (sidebarWin.isVisible()) {
sidebarWin.hide()
} else {
sidebarWin.show()
sidebarWin.focus()
}
} else {
this.mainCtx.windows.open({
key: 'global-sidebar',
title: 'SecScore Sidebar',
route: '/global-sidebar',
options: {
transparent: true,
alwaysOnTop: true,
hasShadow: false,
type: 'toolbar'
}
})
}
}
},
{ type: 'separator' },
{
label: '关闭应用',
+3 -21
View File
@@ -1,6 +1,6 @@
import { Service } from '../../shared/kernel'
import { MainContext } from '../context'
import { BrowserWindow, shell, screen } from 'electron'
import { BrowserWindow, shell } from 'electron'
import type { BrowserWindowConstructorOptions } from 'electron'
let micaElectron: typeof import('mica-electron') | null = null
@@ -117,24 +117,6 @@ export class WindowManager extends Service {
win = new BrowserWindow(baseOptions)
}
// Special positioning for global sidebar
if (input.key === 'global-sidebar') {
const primaryDisplay = screen.getPrimaryDisplay()
const { width, height } = primaryDisplay.workAreaSize
const winWidth = 84
const winHeight = 300
win.setBounds({
x: width - winWidth,
y: Math.floor(height / 2 - winHeight / 2),
width: winWidth,
height: winHeight
})
win.setAlwaysOnTop(true, 'screen-saver')
win.setVisibleOnAllWorkspaces(true)
win.setSkipTaskbar(true)
win.setResizable(false)
}
const zoomSettings = this.mainCtx.settings
const zoom = zoomSettings ? Number(zoomSettings.getValue('window_zoom')) || 1.0 : 1.0
win.webContents.setZoomFactor(zoom)
@@ -165,13 +147,13 @@ export class WindowManager extends Service {
})
win.on('blur', () => {
if (input.key === 'global-sidebar' || input.key === 'main') {
if (input.key === 'main') {
this.applyMicaEffect(win)
}
})
win.on('focus', () => {
if (input.key === 'global-sidebar' || input.key === 'main') {
if (input.key === 'main') {
this.applyMicaEffect(win)
}
})
-2
View File
@@ -6,7 +6,6 @@ import { ContentArea } from './components/ContentArea'
import { Wizard } from './components/Wizard'
import { ThemeProvider } from './contexts/ThemeContext'
import { ThemeEditorProvider } from './contexts/ThemeEditorContext'
import { GlobalSidebar } from './components/GlobalSidebar'
import { ThemeEditor } from './components/ThemeEditor'
function MainContent(): React.JSX.Element {
@@ -148,7 +147,6 @@ function App(): React.JSX.Element {
<ThemeEditorProvider>
<HashRouter>
<Routes>
<Route path="/global-sidebar" element={<GlobalSidebar />} />
<Route path="/*" element={<MainContent />} />
</Routes>
</HashRouter>
-67
View File
@@ -105,70 +105,3 @@ html[theme-mode='dark'] .ss-sidebar .t-menu__item.t-is-active svg:not([fill='non
text-align: center;
justify-content: center;
}
/* Global Sidebar Toggle Button */
.global-sidebar-toggle {
width: 100vw;
height: 100vh;
background-color: var(--ss-bg-color);
border-radius: 0px 0 0 0px;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
box-shadow: -2px 0 8px rgba(0,0,0,0.1);
border: 1px solid var(--ss-border-color);
border-right: none;
color: var(--ss-text-main);
z-index: 10;
flex-shrink: 0;
animation: twinkle-animation 3s infinite ease-in-out;
transition: opacity 0.07s ease, transform 0.15s ease;
}
.global-sidebar-toggle.hidden {
opacity: 0;
pointer-events: none;
transform: translateX(10px);
}
.sidebar-content-area {
display: flex;
flex-direction: column;
background-color: var(--ss-card-bg);
border-radius: 12px 0 0 12px;
box-shadow: -4px 0 16px rgba(0,0,0,0.15);
border: 1px solid var(--ss-border-color);
border-right: none;
padding: 12px 8px;
gap: 12px;
width: 60px;
transition: opacity 0.1s ease, transform 0.1s cubic-bezier(0.34, 1.56, 0.64, 1);
backface-visibility: hidden;
transform: translateZ(0);
contain: paint; /* 性能优化:限制重绘范围 */
}
.sidebar-content-area.hidden {
opacity: 0;
pointer-events: none;
transform: translateX(20px);
}
.sidebar-content-area.visible {
opacity: 1;
pointer-events: auto;
transform: translateX(0);
}
@keyframes twinkle-animation {
0%, 100% {
box-shadow: -2px 0 8px rgba(0,0,0,0.1);
filter: brightness(1);
}
50% {
box-shadow: -4px 0 12px var(--td-brand-color-light), 0 0 15px var(--td-brand-color-focus);
filter: brightness(1.2);
color: var(--td-brand-color);
}
}
@@ -1,188 +0,0 @@
import React, { useState, useEffect } from 'react'
import { Button, Tooltip } from 'tdesign-react'
import {
HomeIcon,
ViewListIcon,
UserAddIcon,
ChevronRightIcon,
ChevronLeftIcon,
SettingIcon,
CodeIcon
} from 'tdesign-icons-react'
export const GlobalSidebar: React.FC = () => {
const [expanded, setExpanded] = useState(false)
const [showToggle, setShowToggle] = useState(true)
const [zoom, setZoom] = useState(1.0)
useEffect(() => {
if (!(window as any).api) return
// 加载初始缩放值
const loadZoom = async () => {
const res = await (window as any).api.getSetting('window_zoom')
if (res.success && res.data) {
setZoom(res.data)
}
}
loadZoom()
// 监听缩放变化
const unsubscribe = (window as any).api.onSettingChanged((change: any) => {
if (change?.key === 'window_zoom') {
setZoom(change.value)
// 缩放变化时,重新应用当前展开/收缩状态的窗口大小
if ((window as any).api) {
if (expanded) {
const width = Math.round(84 * change.value)
const height = Math.round(300 * change.value)
;(window as any).api.windowResize(width, height)
} else {
const width = Math.round(24 * change.value)
const height = Math.round(300 * change.value)
;(window as any).api.windowResize(width, height)
}
}
}
})
return () => {
if (typeof unsubscribe === 'function') unsubscribe()
}
}, [expanded])
const handleExpand = () => {
// 1. 先隐藏三角
setShowToggle(false)
// 2. 稍后扩大窗口
setTimeout(() => {
if ((window as any).api) {
const width = Math.round(60 * zoom)
const height = Math.round(300 * zoom)
;(window as any).api.windowResize(width, height)
}
// 3. 最后显示侧边栏内容
setTimeout(() => {
setExpanded(true)
}, 20)
}, 100)
}
const handleCollapse = () => {
// 1. 先隐藏侧边栏内容
setExpanded(false)
// 2. 稍后缩小窗口
setTimeout(() => {
if ((window as any).api) {
const width = Math.round(24 * zoom)
const height = Math.round(58 * zoom)
;(window as any).api.windowResize(width, height)
}
// 3. 最后重新显示三角(等待透明度动画完成)
setTimeout(() => {
setShowToggle(true)
}, 150)
}, 150)
}
const openMain = () => {
if (!(window as any).api) return
;(window as any).api.openWindow({ key: 'main', route: '/' })
}
return (
<div
style={{
height: '100vh',
width: `84px`,
display: 'flex',
alignItems: 'center',
justifyContent: 'flex-start',
overflow: 'hidden',
background: 'transparent'
}}
>
{/* 日常展示的三角 */}
<div
onClick={handleExpand}
className={`global-sidebar-toggle ${!showToggle ? 'hidden' : ''}`}
style={{
willChange: 'opacity, transform',
width: `${!expanded ? '100vw' : '0px'}`,
height: `100vh`
}}
hidden={!expanded}
>
<ChevronLeftIcon />
</div>
{/* 侧边栏内容 */}
<div
className={`sidebar-content-area ${expanded ? 'visible' : 'hidden'}`}
style={{
backgroundColor: 'var(--ss-bg-color)',
height: 'fit-content',
willChange: 'opacity, transform',
width: `60px`,
gap: `12px`
}}
>
{/* 顶部的关闭/收起按钮 */}
<Button
shape="circle"
variant="text"
onClick={handleCollapse}
style={{ marginBottom: '8px', color: 'var(--td-brand-color)' }}
>
<ChevronRightIcon size="20px" />
</Button>
<Tooltip content="主界面" placement="top">
<Button shape="circle" variant="text" onClick={openMain}>
<HomeIcon size="24px" />
</Button>
</Tooltip>
<Tooltip content="积分操作" placement="top">
<Button shape="circle" variant="text" onClick={() => openMain()}>
<UserAddIcon size="24px" />
</Button>
</Tooltip>
<Tooltip content="排行榜" placement="top">
<Button
shape="circle"
variant="text"
onClick={() => (window as any).api.openWindow({ key: 'main', route: '/leaderboard' })}
>
<ViewListIcon size="24px" />
</Button>
</Tooltip>
<Tooltip content="设置" placement="top">
<Button
shape="circle"
variant="text"
onClick={() => (window as any).api.openWindow({ key: 'main', route: '/settings' })}
>
<SettingIcon size="24px" />
</Button>
</Tooltip>
{import.meta.env.DEV && (
<Tooltip content="开发者工具" placement="top">
<Button
shape="circle"
variant="text"
onClick={() => (window as any).api?.toggleDevTools()}
>
<CodeIcon size="24px" />
</Button>
</Tooltip>
)}
</div>
</div>
)
}
+7 -1
View File
@@ -543,7 +543,13 @@ export const Settings: React.FC<{ permission: permissionLevel }> = ({ permission
URL (secscore://)
</div>
<Divider />
<div style={{ marginBottom: '12px', fontSize: '13px', color: 'var(--ss-text-secondary)' }}>
<div
style={{
marginBottom: '12px',
fontSize: '13px',
color: 'var(--ss-text-secondary)'
}}
>
URL SecScore
</div>
<div
-31
View File
@@ -1,31 +0,0 @@
{
"name": "自定义",
"id": "custom",
"mode": "light",
"mica": {
"effect": "mica",
"theme": "auto",
"radius": "large"
},
"config": {
"tdesign": {
"brandColor": "#0052D9",
"warningColor": "#E37318",
"errorColor": "#D32029",
"successColor": "#248232"
},
"custom": {
"--ss-bg-color": "transparent",
"--ss-card-bg": "rgba(255, 255, 255, 0.7)",
"--ss-text-main": "#1a1a1a",
"--ss-text-secondary": "#5e5e5e",
"--ss-border-color": "rgba(0, 0, 0, 0.1)",
"--ss-header-bg": "transparent",
"--ss-sidebar-bg": "rgba(255, 255, 255, 0.85)",
"--ss-item-hover": "rgba(0, 0, 0, 0.05)",
"--ss-sidebar-text": "#1a1a1a",
"--ss-sidebar-active-bg": "rgba(0, 0, 0, 0.08)",
"--ss-sidebar-active-text": "#1a1a1a"
}
}
}