lv 2 týždňov pred
rodič
commit
80662f677d

+ 12 - 0
import.html

@@ -0,0 +1,12 @@
+<!doctype html>
+<html lang="zh-CN">
+  <head>
+    <meta charset="UTF-8" />
+    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+    <title>导入 URL</title>
+  </head>
+  <body>
+    <div id="root"></div>
+    <script type="module" src="/src/import/main.tsx"></script>
+  </body>
+</html>

+ 1 - 0
package.json

@@ -13,6 +13,7 @@
     "@ant-design/icons": "6.x",
     "@tauri-apps/api": "^2",
     "@tauri-apps/plugin-opener": "^2",
+    "@tauri-apps/plugin-sql": "^2",
     "antd": "^6.4.0",
     "react": "^19.1.0",
     "react-dom": "^19.1.0"

Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 796 - 21
src-tauri/Cargo.lock


+ 2 - 0
src-tauri/Cargo.toml

@@ -24,6 +24,8 @@ tauri = { version = "2", features = ["protocol-asset", "unstable"] }
 tauri-plugin-opener = "2"
 # 全局快捷键:F9/F10/F11 控制录制开始/暂停/停止
 tauri-plugin-global-shortcut = "2"
+# SQLite 持久化任务列表(前端通过 @tauri-apps/plugin-sql 调用)
+tauri-plugin-sql = { version = "2", features = ["sqlite"] }
 serde = { version = "1", features = ["derive"] }
 serde_json = "1"
 # 用于解析前端传来的 url 字符串后再交给 webview.navigate

+ 17 - 2
src-tauri/capabilities/default.json

@@ -3,7 +3,8 @@
   "identifier": "default",
   "description": "Capability for the main window",
   "windows": [
-    "main"
+    "main",
+    "import"
   ],
   "permissions": [
     "core:default",
@@ -17,6 +18,20 @@
     "core:window:allow-set-focus",
     "core:window:allow-is-maximized",
     "core:window:allow-start-dragging",
-    "core:window:allow-toggle-maximize"
+    "core:window:allow-toggle-maximize",
+    "core:webview:allow-create-webview-window",
+    "core:event:default",
+    {
+      "identifier": "sql:default",
+      "allow": [
+        {
+          "path": "sqlite:autorecord.db"
+        }
+      ]
+    },
+    "sql:allow-execute",
+    "sql:allow-select",
+    "sql:allow-load",
+    "sql:allow-close"
   ]
 }

+ 14 - 0
src-tauri/src/lib.rs

@@ -151,9 +151,23 @@ fn set_window_size(
 
 #[cfg_attr(mobile, tauri::mobile_entry_point)]
 pub fn run() {
+    // tauri-plugin-sql 的 schema 迁移定义
+    // db 名固定为 sqlite:autorecord.db,落在 APPDATA 目录
+    let sql_migrations = vec![tauri_plugin_sql::Migration {
+        version: 1,
+        description: "create_tasks_table",
+        sql: "CREATE TABLE IF NOT EXISTS tasks (\n            id TEXT PRIMARY KEY,\n            url TEXT NOT NULL,\n            status INTEGER NOT NULL DEFAULT 0,\n            desc TEXT NOT NULL DEFAULT ''\n        );",
+        kind: tauri_plugin_sql::MigrationKind::Up,
+    }];
+
     tauri::Builder::default()
         .plugin(tauri_plugin_opener::init())
         .plugin(shortcuts::record_shortcut_plugin())
+        .plugin(
+            tauri_plugin_sql::Builder::default()
+                .add_migrations("sqlite:autorecord.db", sql_migrations)
+                .build(),
+        )
         .manage(AppState::default())
         .setup(|app| {
             // 注册 F9/F10/F11 全局快捷键。注册失败仅打日志,不阻塞应用启动

+ 187 - 8
src/App.tsx

@@ -1,15 +1,23 @@
-import { useCallback, useEffect, useRef, useState } from "react";
+import { useCallback, useEffect, useMemo, useRef, useState } from "react";
 import { invoke } from "@tauri-apps/api/core";
 import { listen, type UnlistenFn } from "@tauri-apps/api/event";
+import { getCurrentWindow } from "@tauri-apps/api/window";
+import { WebviewWindow } from "@tauri-apps/api/webviewWindow";
 import { openUrl, revealItemInDir } from "@tauri-apps/plugin-opener";
 import { Button, ConfigProvider, Divider, InputNumber, Layout, Menu, notification, Space, theme, Tooltip } from "antd";
-import { mockTasks } from "./mocks/tasks";
+import {
+  countPendingTasks,
+  listPendingTasks,
+  markTaskDone,
+  type Task,
+} from "./lib/tasks";
 import {
   EVT_RECORDING_FAILED,
   EVT_RECORDING_FINISHED,
   EVT_RECORD_SHORTCUT,
   EVT_SCREENSHOT_FAILED,
   EVT_SCREENSHOT_FINISHED,
+  EVT_TASKS_IMPORTED,
   type RecordingFailedPayload,
   type RecordingFinishedPayload,
   type RecordShortcutPayload,
@@ -29,6 +37,7 @@ import {
 import "./App.css";
 import {
   BankOutlined,
+  CheckCircleOutlined,
   CloseOutlined,
   FileImageOutlined,
   FolderOpenOutlined,
@@ -81,6 +90,9 @@ function App() {
   // 当前激活的任务 id(仅用于左栏视觉高亮)
   const [activeId, setActiveId] = useState<string | null>(null);
 
+  // 待处理任务(status=0)的真实列表,来自 sqlite
+  const [tasks, setTasks] = useState<Task[]>([]);
+
   const [contentSize, setContentSize] = useState<{ w: number; h: number }>({ w: 1280, h: 720 });
   const contentSizeRef = useRef(contentSize);
   const [customMode, setCustomMode] = useState(false);
@@ -103,8 +115,62 @@ function App() {
   // antd 6 notification 必须用 hook + contextHolder 才能正确取到主题
   const [notifyApi, notifyContext] = notification.useNotification();
 
+  /**
+   * 重新拉取 sqlite 中 status=0 的任务列表。
+   * 调用场景:
+   *   - 首次挂载
+   *   - 监听到 EVT_TASKS_IMPORTED(导入窗口写入完)
+   *   - "完成" 按钮把当前任务标记为已完成后
+   */
+  const reloadTasks = useCallback(async (): Promise<Task[]> => {
+    try {
+      const list = await listPendingTasks();
+      setTasks(list);
+      return list;
+    } catch (e) {
+      console.error("加载任务列表失败:", e);
+      notifyApi.error({
+        message: "加载任务失败",
+        description: String(e),
+        duration: 6,
+      });
+      return [];
+    }
+  }, [notifyApi]);
+
+  /** 启动「批量导入 URL」窗口(独立 WebviewWindow,label = "import") */
+  const openImportWindow = useCallback(async () => {
+    try {
+      // 若已存在直接 setFocus,避免重复创建
+      const existing = await WebviewWindow.getByLabel("import");
+      if (existing) {
+        await existing.setFocus();
+        return;
+      }
+      const w = new WebviewWindow("import", {
+        url: "import.html",
+        title: "导入 URL",
+        width: 560,
+        height: 480,
+        resizable: true,
+        // 主窗口是 decorations: false,这里给原生标题栏方便用户拖动/关闭
+        decorations: true,
+      });
+      w.once("tauri://error", (e) => {
+        console.error("导入窗口创建失败:", e);
+      });
+    } catch (e) {
+      console.error("openImportWindow 失败:", e);
+      notifyApi.error({
+        message: "无法打开导入窗口",
+        description: String(e),
+        duration: 6,
+      });
+    }
+  }, [notifyApi]);
+
   function handleSelectTask({ key }: { key: string }) {
-    const t = mockTasks.find((v) => v.id == key);
+    const t = tasks.find((v) => v.id == key);
     if (!t) {
       return;
     }
@@ -132,6 +198,67 @@ function App() {
     void refreshAssets(activeId);
   }, [activeId, refreshAssets]);
 
+  // 首次挂载:从 sqlite 加载待处理任务;若为空则拉起「批量导入 URL」窗口。
+  // 依赖项故意只放 reloadTasks / openImportWindow(都用 useCallback 稳定引用),
+  // 避免 tasks 变化导致再次拉起导入窗口。
+  useEffect(() => {
+    (async () => {
+      const pending = await countPendingTasks().catch(() => 0);
+      const list = await reloadTasks();
+      if (pending === 0 && list.length === 0) {
+        await openImportWindow();
+      }
+    })();
+    // eslint-disable-next-line react-hooks/exhaustive-deps
+  }, []);
+
+  // 监听导入窗口发出的 tasks-imported 事件,刷新主列表
+  useEffect(() => {
+    let unlisten: UnlistenFn | null = null;
+    let disposed = false;
+    (async () => {
+      const u = await listen<{ count: number }>(EVT_TASKS_IMPORTED, (e) => {
+        notifyApi.success({
+          message: "导入完成",
+          description: `已写入 ${e.payload.count} 条任务`,
+          duration: 3,
+        });
+        void reloadTasks();
+      });
+      if (disposed) u();
+      else unlisten = u;
+    })();
+    return () => {
+      disposed = true;
+      unlisten?.();
+    };
+  }, [notifyApi, reloadTasks]);
+
+  /** 工具栏 "完成" 按钮:把当前激活任务标记为已完成(status=1)→ 刷新 → 清空选中 */
+  const handleCompleteTask = useCallback(async () => {
+    if (!activeId) return;
+    try {
+      await markTaskDone(activeId);
+      notifyApi.success({
+        message: "任务已完成",
+        description: `任务 ${activeId} 已从列表移除`,
+        duration: 3,
+      });
+      setActiveId(null);
+      const list = await reloadTasks();
+      // 若已无任务,自动再拉起一次导入窗口(用户可继续粘贴)
+      if (list.length === 0) {
+        await openImportWindow();
+      }
+    } catch (e) {
+      notifyApi.error({
+        message: "标记完成失败",
+        description: String(e),
+        duration: 6,
+      });
+    }
+  }, [activeId, reloadTasks, openImportWindow, notifyApi]);
+
   /** 手动截图:交给 Rust 命令,结果通过事件回推(统一与自动截图的提示路径) */
   const handleManualCapture = useCallback(async () => {
     if (!activeId) return;
@@ -444,14 +571,54 @@ function App() {
 
   const [statusColor, setStatusColor] = useState("#888");
   const [statusText, setStatusText] = useState("请选择任务");
+
+  // 当前窗口句柄,用于自定义标题栏的最小化 / 关闭
+  const appWindow = useMemo(() => getCurrentWindow(), []);
+
+  const handleAppClose = useCallback(async () => {
+    try {
+      await appWindow.close();
+    } catch (e) {
+      console.error("appWindow.close 失败:", e);
+    }
+  }, [appWindow]);
+
+  const handleAppMinimize = useCallback(async () => {
+    try {
+      await appWindow.minimize();
+    } catch (e) {
+      console.error("appWindow.minimize 失败:", e);
+    }
+  }, [appWindow]);
+
   return (
     <Layout className="m-0 p-0 h-full overflow-hidden">
-      <Header className="app-title h-8 select-none" style={{ paddingLeft: 8 }} >
-        <div className="flex h-full flex-row items-center">
+      {/* data-tauri-drag-region:Tauri 2 原生支持,webview 层会自动 hook mousedown
+       *   触发系统级拖窗,比手写 startDragging 更稳定(Windows 尤其如此)。 */}
+      <Header
+        className="app-title h-8 select-none"
+        style={{ paddingLeft: 8 }}
+        data-tauri-drag-region
+      >
+        <div className="flex h-full flex-row items-center" data-tauri-drag-region>
           <Space size={4}>
-            <Button className="app-close" icon={<CloseOutlined />} size="large" type="text" />
+            <Button
+              className="app-close"
+              icon={<CloseOutlined />}
+              size="large"
+              type="text"
+              data-tauri-drag-region="no-drag"
+              onClick={handleAppClose}
+            />
             <Button icon={<BankOutlined />} disabled size="large" type="text" />
-            <Button className="app-minimize" icon={<MinusOutlined />} size="large" type="text" />
+            <Button
+              className="app-minimize"
+              icon={<MinusOutlined />}
+              size="large"
+              type="text"
+              data-tauri-drag-region="no-drag"
+              onClick={handleAppMinimize}
+            />
           </Space>
           <div className="w-32" />
           <Tooltip title={activeId ? "截图整页(覆盖之前的自动截图)" : "请先选择任务"} placement="right">
@@ -491,6 +658,18 @@ function App() {
               onClick={() => void handleStopRecord()}
             />
           </Tooltip>
+          {/* 完成按钮:把当前任务在 sqlite 标记为 status=1,从主列表移除 */}
+          <Tooltip
+            title={activeId ? "标记当前任务为已完成" : "请先选择任务"}
+            placement="right"
+          >
+            <Button
+              shape="circle"
+              icon={<CheckCircleOutlined />}
+              disabled={!activeId}
+              onClick={() => void handleCompleteTask()}
+            />
+          </Tooltip>
           <Divider orientation="vertical" />
           {/* 打开文件夹:reveal mp4 → png → 兜底 screenshots 目录 */}
           <Tooltip
@@ -618,7 +797,7 @@ function App() {
             onClick={handleSelectTask}
 
           >
-            {mockTasks.map((t) => <Menu.Item icon={<LinkOutlined />} key={t.id}>
+            {tasks.map((t) => <Menu.Item icon={<LinkOutlined />} key={t.id}>
               {t.id}
             </Menu.Item>
             )}

+ 90 - 0
src/import/ImportApp.tsx

@@ -0,0 +1,90 @@
+import { useState } from "react";
+import { Alert, Button, Input, Typography } from "antd";
+import { getCurrentWindow } from "@tauri-apps/api/window";
+import { emit } from "@tauri-apps/api/event";
+import { insertTasksFromUrls } from "../lib/tasks";
+import { EVT_TASKS_IMPORTED } from "../types/ipc";
+
+/**
+ * 「批量导入 URL」窗口。
+ *
+ * 行为:
+ * - 用户在 textarea 里粘贴多行 URL,每行一个
+ * - 点 "保存":调 insertTasksFromUrls 把非空行写入 sqlite,desc 全留空
+ * - 写入成功后 emit EVT_TASKS_IMPORTED,主窗口监听并刷新列表
+ * - 然后关闭本窗口
+ */
+export default function ImportApp() {
+  const [text, setText] = useState("");
+  const [submitting, setSubmitting] = useState(false);
+  const [error, setError] = useState<string | null>(null);
+
+  // 非空行数量,给保存按钮显示个提示
+  const previewCount = text
+    .split(/\r?\n/)
+    .map((s) => s.trim())
+    .filter((s) => s.length > 0).length;
+
+  const handleSave = async () => {
+    if (previewCount === 0 || submitting) return;
+    setSubmitting(true);
+    setError(null);
+    try {
+      const urls = text.split(/\r?\n/);
+      const inserted = await insertTasksFromUrls(urls);
+      // 通知主窗口刷新(payload 暂只携带条数,方便后续 toast)
+      await emit(EVT_TASKS_IMPORTED, { count: inserted });
+      // 关闭本窗口
+      await getCurrentWindow().close();
+    } catch (e) {
+      console.error("批量导入失败:", e);
+      setError(String(e));
+      setSubmitting(false);
+    }
+  };
+
+  const handleCancel = async () => {
+    await getCurrentWindow().close();
+  };
+
+  return (
+    <div className="flex flex-col h-screen w-screen p-4 gap-3 overflow-hidden">
+      <Typography.Title level={5} style={{ margin: 0 }}>
+        批量导入 URL
+      </Typography.Title>
+      <Typography.Text type="secondary">
+        每行一个 URL,空行会被忽略。保存后会以「未完成」状态写入任务列表。
+      </Typography.Text>
+
+      {error && (
+        <Alert type="error" message="导入失败" description={error} showIcon />
+      )}
+
+      <Input.TextArea
+        autoFocus
+        value={text}
+        onChange={(e) => setText(e.target.value)}
+        placeholder={"https://example.com/a\nhttps://example.com/b"}
+        style={{ flex: 1, resize: "none", fontFamily: "monospace" }}
+        disabled={submitting}
+      />
+
+      <div className="flex items-center justify-end gap-2">
+        <Typography.Text type="secondary" style={{ marginRight: "auto" }}>
+          检测到 {previewCount} 条 URL
+        </Typography.Text>
+        <Button onClick={handleCancel} disabled={submitting}>
+          取消
+        </Button>
+        <Button
+          type="primary"
+          onClick={handleSave}
+          disabled={previewCount === 0}
+          loading={submitting}
+        >
+          保存 ({previewCount})
+        </Button>
+      </div>
+    </div>
+  );
+}

+ 17 - 0
src/import/main.tsx

@@ -0,0 +1,17 @@
+import React from "react";
+import ReactDOM from "react-dom/client";
+import { ConfigProvider, theme } from "antd";
+import ImportApp from "./ImportApp";
+import "../App.css";
+
+// 「批量导入 URL」独立窗口入口
+// 与主窗口共用同一套 antd 暗色主题,UI 风格保持一致。
+ReactDOM.createRoot(document.getElementById("root") as HTMLElement).render(
+  <React.StrictMode>
+    <ConfigProvider
+      theme={{ algorithm: [theme.darkAlgorithm, theme.compactAlgorithm] }}
+    >
+      <ImportApp />
+    </ConfigProvider>
+  </React.StrictMode>,
+);

+ 87 - 0
src/lib/tasks.ts

@@ -0,0 +1,87 @@
+// 任务数据访问层
+//
+// 替代之前的 src/mocks/tasks.ts,所有数据落 SQLite(@tauri-apps/plugin-sql)。
+// 数据库名与 src-tauri/src/lib.rs 中的 migration 一致:sqlite:autorecord.db
+//
+// 表结构(migration v1):
+//   id      TEXT  PRIMARY KEY     -- uuid 缩短到 12 位
+//   url     TEXT  NOT NULL
+//   status  INT   NOT NULL DEFAULT 0   -- 0=待处理, 1=已完成
+//   "desc"  TEXT  NOT NULL DEFAULT ''  -- DESC 是 SQLite 关键字,列名要带引号
+
+import Database from "@tauri-apps/plugin-sql";
+
+const DB_URI = "sqlite:autorecord.db";
+
+/** 任务行结构(与 SQLite 表一一对应) */
+export interface Task {
+  /** 任务唯一标识(uuid 截短 12 位) */
+  id: string;
+  /** 目标网页 url */
+  url: string;
+  /** 0=待处理(出现在主列表),1=已完成(隐藏) */
+  status: number;
+  /** 备注(当前导入流程统一留空,后续可补) */
+  desc: string;
+}
+
+let _dbPromise: Promise<Database> | null = null;
+
+/** 单例:第一次调用时打开 DB,后续复用同一个连接 */
+function getDb(): Promise<Database> {
+  if (!_dbPromise) {
+    _dbPromise = Database.load(DB_URI);
+  }
+  return _dbPromise;
+}
+
+/** 生成 12 位的短 uuid(去掉连字符后取前 12 位) */
+export function genTaskId(): string {
+  // crypto.randomUUID 在所有现代 WebView2/WKWebView 上都可用
+  return crypto.randomUUID().replace(/-/g, "").slice(0, 12);
+}
+
+/** 列出所有 status=0 的待处理任务,按 rowid 升序(= 插入顺序) */
+export async function listPendingTasks(): Promise<Task[]> {
+  const db = await getDb();
+  return await db.select<Task[]>(
+    'SELECT id, url, status, "desc" FROM tasks WHERE status = 0 ORDER BY rowid ASC',
+  );
+}
+
+/** 统计 status=0 的任务数量,供「空表 → 拉起导入窗口」判断 */
+export async function countPendingTasks(): Promise<number> {
+  const db = await getDb();
+  const rows = await db.select<{ n: number }[]>(
+    "SELECT COUNT(*) AS n FROM tasks WHERE status = 0",
+  );
+  return rows[0]?.n ?? 0;
+}
+
+/**
+ * 批量插入 url(desc 全部留空)。
+ * - 自动去除空白行
+ * - 自动去除 url 两端空白
+ * - id 用 12 位短 uuid
+ * 返回实际插入的条数。
+ */
+export async function insertTasksFromUrls(rawUrls: string[]): Promise<number> {
+  const urls = rawUrls.map((s) => s.trim()).filter((s) => s.length > 0);
+  if (urls.length === 0) return 0;
+
+  const db = await getDb();
+  // plugin-sql 不直接暴露事务,循环 execute 即可。批量量不大,性能足够。
+  for (const url of urls) {
+    await db.execute(
+      'INSERT INTO tasks (id, url, status, "desc") VALUES ($1, $2, 0, \'\')',
+      [genTaskId(), url],
+    );
+  }
+  return urls.length;
+}
+
+/** 把指定任务标记为完成(status=1),不再出现在主列表 */
+export async function markTaskDone(id: string): Promise<void> {
+  const db = await getDb();
+  await db.execute("UPDATE tasks SET status = 1 WHERE id = $1", [id]);
+}

+ 0 - 52
src/mocks/tasks.ts

@@ -1,52 +0,0 @@
-// Mock 任务数据
-//
-// 后期接入真数据时,只需替换数据源(如改为从后端读取),
-// 保持 Task 的字段形状即可,前端组件不用变。
-
-export interface Task {
-  /** 任务唯一标识,列表中可见 */
-  id: string;
-  /** 任务对应的目标网页 url,列表中不显示 */
-  url: string;
-}
-
-export const mockTasks: Task[] = `https://www.baidu.com
-https://www.awwwards.com/sites/reasonal
-https://www.awwwards.com/sites/percare-mobile-visualizers
-https://www.awwwards.com/sites/edwin-le-portfolio
-https://www.awwwards.com/sites/funy-ai-video-image
-https://www.awwwards.com/sites/2manybooks-com
-https://www.awwwards.com/sites/linearity-2
-https://www.awwwards.com/sites/reelmuse-ai
-https://www.awwwards.com/sites/nectar-ai
-https://www.awwwards.com/sites/postcards
-https://www.awwwards.com/sites/animal-face
-https://www.awwwards.com/sites/helm-modern-web-app
-https://www.awwwards.com/sites/bart-andrzejewski-ships-fast
-https://www.awwwards.com/sites/vandslab
-https://www.awwwards.com/sites/facilpay
-https://www.awwwards.com/sites/sinqlo
-https://www.awwwards.com/sites/gtpinf
-https://www.awwwards.com/sites/mathical
-https://www.awwwards.com/sites/anima
-https://www.awwwards.com/sites/avalon-platforms
-https://www.awwwards.com/sites/mockupper
-https://www.awwwards.com/sites/minitap-ai
-https://www.awwwards.com/sites/time-garden
-https://www.awwwards.com/sites/ligue-nationale-de-basket
-https://www.awwwards.com/sites/unstructured
-https://www.awwwards.com/sites/barn-til-bords
-https://www.awwwards.com/sites/xinyi-zhaos-portfolio
-https://www.awwwards.com/sites/tuyo-banking-from-the-future
-https://www.awwwards.com/sites/things-inc
-https://www.awwwards.com/sites/maggie
-https://www.awwwards.com/sites/newform
-https://www.awwwards.com/sites/murphycares-com
-https://www.awwwards.com/sites/wa-solutions
-https://www.awwwards.com/sites/patio
-https://www.awwwards.com/sites/pagegrid
-https://www.awwwards.com/sites/auger-dubord
-https://www.awwwards.com/sites/ulf-online`.split("\n").map((item, idx) => ({
-  id: idx + "",
-  url: item.replace(/\s+/g, ''),
-}));

+ 8 - 0
src/types/ipc.ts

@@ -36,6 +36,14 @@ export const EVT_RECORDING_FINISHED = "recording-finished";
 export const EVT_RECORDING_FAILED = "recording-failed";
 /** Rust 端注册的全局快捷键 (F9/F10/F11) 按下时发出的事件名 */
 export const EVT_RECORD_SHORTCUT = "record-shortcut";
+/** 「批量导入 URL」窗口写入完成后通知主窗口刷新列表 */
+export const EVT_TASKS_IMPORTED = "tasks-imported";
+
+/** 批量导入完成事件 payload */
+export interface TasksImportedPayload {
+  /** 本次实际写入 sqlite 的条数 */
+  count: number;
+}
 
 /** 全局快捷键事件 payload(对应 Rust emit 的 record-shortcut) */
 export interface RecordShortcutPayload {

+ 10 - 0
vite.config.ts

@@ -9,6 +9,16 @@ const host = process.env.TAURI_DEV_HOST;
 export default defineConfig(async () => ({
   plugins: [react(), tailwindcss()],
 
+  // 多入口构建:主窗口 (index.html) + URL 批量导入窗口 (import.html)
+  build: {
+    rollupOptions: {
+      input: {
+        main: "index.html",
+        import: "import.html",
+      },
+    },
+  },
+
   // Vite options tailored for Tauri development and only applied in `tauri dev` or `tauri build`
   //
   // 1. prevent Vite from obscuring rust errors

Niektoré súbory nie sú zobrazené, pretože je v týchto rozdielových dátach zmenené mnoho súborov