diff --git a/.gitignore b/.gitignore
index dc6ef01..c09cea9 100644
--- a/.gitignore
+++ b/.gitignore
@@ -13,6 +13,7 @@ out
src-tauri/target
src-tauri/Cargo.lock
src-tauri/gen
+.cargo-local/
# Database
data.sql
diff --git a/src/components/ContentArea.tsx b/src/components/ContentArea.tsx
index b175d49..b968003 100644
--- a/src/components/ContentArea.tsx
+++ b/src/components/ContentArea.tsx
@@ -2,6 +2,7 @@ import React, { Suspense, lazy } from "react"
import { Layout, Space, Button, Tag, Spin } from "antd"
import { Routes, Route, Navigate } from "react-router-dom"
import { useTranslation } from "react-i18next"
+import { WindowControls } from "./WindowControls"
const Home = lazy(() => import("./Home").then((m) => ({ default: m.Home })))
const StudentManager = lazy(() =>
@@ -67,6 +68,7 @@ export function ContentArea({
background: "var(--ss-header-bg)",
borderBottom: "1px solid var(--ss-border-color)",
flexShrink: 0,
+ WebkitAppRegion: "drag",
} as React.CSSProperties
}
>
@@ -76,7 +78,8 @@ export function ContentArea({
{
display: "flex",
alignItems: "center",
- paddingRight: "12px",
+ paddingRight: "8px",
+ WebkitAppRegion: "no-drag",
} as React.CSSProperties
}
>
@@ -94,6 +97,7 @@ export function ContentArea({
)}
+
diff --git a/src/components/WindowControls.tsx b/src/components/WindowControls.tsx
index b6c4596..b5eeba9 100644
--- a/src/components/WindowControls.tsx
+++ b/src/components/WindowControls.tsx
@@ -11,13 +11,28 @@ export function WindowControls(): React.JSX.Element {
const [isMaximized, setIsMaximized] = useState(false)
useEffect(() => {
- if (!(window as any).api) return
- ;(window as any).api.windowIsMaximized().then((v: boolean) => setIsMaximized(v))
+ const api = (window as any).api
+ if (!api) return
- const cleanup = (window as any).api.onWindowMaximizedChanged((maximized: boolean) => {
- setIsMaximized(maximized)
- })
- return cleanup
+ let unlisten: (() => void) | null = null
+
+ api
+ .windowIsMaximized()
+ .then((v: boolean) => setIsMaximized(v))
+ .catch(() => void 0)
+
+ api
+ .onWindowMaximizedChanged((maximized: boolean) => {
+ setIsMaximized(maximized)
+ })
+ .then((fn: () => void) => {
+ unlisten = fn
+ })
+ .catch(() => void 0)
+
+ return () => {
+ if (unlisten) unlisten()
+ }
}, [])
const minimize = () => {
diff --git a/src/main.tsx b/src/main.tsx
index 0f8455c..03fb68f 100644
--- a/src/main.tsx
+++ b/src/main.tsx
@@ -7,6 +7,11 @@ import App from "./App"
import { ClientContext } from "./ClientContext"
import { StudentService } from "./services/StudentService"
import { ServiceProvider } from "./contexts/ServiceContext"
+import { api } from "./preload/types"
+
+if (!(window as any).api) {
+ ;(window as any).api = api
+}
const ctx = new ClientContext()
new StudentService(ctx)
diff --git a/src/preload/types.ts b/src/preload/types.ts
index 8179ae5..3d97cf4 100644
--- a/src/preload/types.ts
+++ b/src/preload/types.ts
@@ -173,6 +173,9 @@ const api = {
windowMaximize: (): Promise => invoke("window_maximize"),
windowClose: (): Promise => invoke("window_close"),
windowIsMaximized: (): Promise => invoke("window_is_maximized"),
+ toggleDevTools: (): Promise => invoke("toggle_devtools"),
+ windowResize: (width: number, height: number): Promise =>
+ invoke("window_resize", { width, height }),
onWindowMaximizedChanged: (callback: (maximized: boolean) => void): Promise => {
return listen("window:maximized-changed", (event) => {
callback(event.payload)
@@ -291,6 +294,28 @@ const api = {
ruleIds: number[]
): Promise<{ success: boolean; data?: boolean; message?: string }> =>
invoke("auto_score_sort_rules", { ruleIds }),
+
+ // Generic invoke wrapper for backward compatibility with callers using `api.invoke`
+ invoke: async (channel: string, ...args: any[]): Promise => {
+ switch (channel) {
+ case "auto-score:getRules":
+ return api.autoScoreGetRules()
+ case "auto-score:addRule":
+ return api.autoScoreAddRule(args[0])
+ case "auto-score:updateRule":
+ return api.autoScoreUpdateRule(args[0])
+ case "auto-score:deleteRule":
+ return api.autoScoreDeleteRule(args[0])
+ case "auto-score:toggleRule":
+ return api.autoScoreToggleRule(args[0])
+ case "auto-score:sortRules":
+ return api.autoScoreSortRules(args[0])
+ case "auto-score:getStatus":
+ return api.autoScoreGetStatus()
+ default:
+ throw new Error(`Unsupported legacy invoke channel: ${channel}`)
+ }
+ },
}
export default api