当然, 我们可以使用 Next. Js 框架来重写这个 Tauri 应用。以下是使用 Next. Js 和 Bun 的步骤:

  1. 首先, 创建一个新的 Next. Js 项目:
bun create next-app calculator-app
cd calculator-app
  1. 安装必要的依赖:
bun add @tauri-apps/api @tauri-apps/cli unocss
bun add -d @types/node @types/react @types/react-dom typescript
  1. 在项目根目录创建 src-tauri 文件夹, 并在其中创建 src/main.rs:
#![cfg_attr(
  all(not(debug_assertions), target_os = "windows"),
  windows_subsystem = "windows"
)]
 
use tauri::Manager;
use serde::{Deserialize, Serialize};
 
#[derive(Serialize, Deserialize)]
struct CalculationResult {
    result: f64,
}
 
#[tauri::command]
fn calculate(operation: String, values: Vec<f64>) -> CalculationResult {
    let result = match operation.as_str() {
        "sin" => values[0].sin(),
        "cos" => values[0].cos(),
        "tan" => values[0].tan(),
        "mean" => values.iter().sum::<f64>() / values.len() as f64,
        "median" => {
            let mut sorted = values.clone();
            sorted.sort_by(|a, b| a.partial_cmp(b).unwrap());
            let mid = sorted.len() / 2;
            if sorted.len() % 2 == 0 {
                (sorted[mid - 1] + sorted[mid]) / 2.0
            } else {
                sorted[mid]
            }
        },
        _ => 0.0,
    };
 
    CalculationResult { result }
}
 
fn main() {
    tauri::Builder::default()
        .setup(|app| {
            #[cfg(debug_assertions)]
            {
                let window = app.get_window("main").unwrap();
                window.open_devtools();
            }
            Ok(())
        })
        .invoke_handler(tauri::generate_handler![calculate])
        .run(tauri::generate_context!())
        .expect("error while running tauri application");
}
  1. 修改 src/pages/index.tsx:
import React, { useState } from 'react';
import { invoke } from '@tauri-apps/api/tauri';
 
const themes = {
  light: 'bg-white text-black',
  dark: 'bg-gray-800 text-white',
  colorful: 'bg-gradient-to-r from-purple-400 via-pink-500 to-red-500 text-white',
};
 
export default function Home() {
  const [operation, setOperation] = useState('');
  const [values, setValues] = useState('');
  const [result, setResult] = useState<number | null>(null);
  const [theme, setTheme] = useState('light');
  const [layout, setLayout] = useState('vertical');
 
  const handleSubmit = async (e: React.FormEvent) => {
    e.preventDefault();
    try {
      const res: { result: number } = await invoke('calculate', {
        operation,
        values: values.split(',').map(Number),
      });
      setResult(res.result);
    } catch (error) {
      console.error('Calculation error:', error);
    }
  };
 
  const handleNumberClick = (num: number) => {
    setValues(prev => prev + (prev ? ',' : '') + num);
  };
 
  const handleClear = () => {
    setValues('');
    setResult(null);
  };
 
  return (
    <div className={`p-4 ${themes[theme as keyof typeof themes]} ${layout === 'vertical' ? 'flex flex-col' : 'flex flex-row'}`}>
      <div className="flex-1">
        <h1 className="text-2xl font-bold mb-4">Complex Calculator</h1>
        <form onSubmit={handleSubmit} className="mb-4">
          <select 
            value={operation} 
            onChange={(e) => setOperation (e.target. Value)}
            ClassName="w-full p-2 mb-2 border rounded"
          >
            <option value="">Select operation</option>
            <option value="sin">Sin</option>
            <option value="cos">Cos</option>
            <option value="tan">Tan</option>
            <option value="mean">Mean</option>
            <option value="median">Median</option>
          </select>
          <input
            type="text"
            value={values}
            onChange={(e) => setValues(e.target.value)}
            placeholder="Enter values (comma-separated)"
            className="w-full p-2 mb-2 border rounded"
          />
          <button type="submit" className="w-full p-2 bg-blue-500 text-white rounded hover:bg-blue-600">Calculate</button>
        </form>
        {result !== null && <p className="text-xl">Result: {result}</p>}
        
        <div className="grid grid-cols-3 gap-2 mt-4">
          {[1, 2, 3, 4, 5, 6, 7, 8, 9, 0].map((num) => (
            <button
              key={num}
              onClick={() => handleNumberClick(num)}
              className="p-2 bg-gray-200 rounded hover:bg-gray-300"
            >
              {num}
            </button>
          ))}
          <button
            onClick={handleClear}
            className="p-2 bg-red-500 text-white rounded hover:bg-red-600 col-span-3"
          >
            Clear
          </button>
        </div>
      </div>
      
      <div className={`${layout === 'vertical' ? 'mt-4' : 'ml-4'}`}>
        <h2 className="text-xl font-bold mb-2">Customize</h2>
        <select 
          value={theme} 
          onChange={(e) => setTheme(e.target.value)}
          className="w-full p-2 mb-2 border rounded"
        >
          <option value="light">Light Theme</option>
          <option value="dark">Dark Theme</option>
          <option value="colorful">Colorful Theme</option>
        </select>
        <select 
          value={layout} 
          onChange={(e) => setLayout(e.target.value)}
          className="w-full p-2 mb-2 border rounded"
        >
          <option value="vertical">Vertical Layout</option>
          <option value="horizontal">Horizontal Layout</option>
        </select>
      </div>
    </div>
  );
}
  1. 配置 UnoCSS:

创建 uno.config.ts:

import { defineConfig } from 'unocss'
import presetUno from '@unocss/preset-uno'
 
export default defineConfig({
  presets: [presetUno()],
})
  1. 修改 next.config.js:
const UnoCSS = require('@unocss/webpack').default
 
/** @type {import('next').NextConfig} */
const nextConfig = {
  reactStrictMode: true,
  webpack: (config) => {
    config.plugins.push(UnoCSS())
    return config
  },
}
 
module.exports = nextConfig
  1. src/pages/_app.tsx 中导入 UnoCSS:
import '@unocss/reset/tailwind.css'
import 'uno.css'
import type { AppProps } from 'next/app'
 
function MyApp({ Component, pageProps }: AppProps) {
  return <Component {...pageProps} />
}
 
export default MyApp
  1. 更新 package.json:
{
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start",
    "lint": "next lint",
    "tauri": "tauri"
  },
  "dependencies": {
    "@tauri-apps/api": "^1.0.0",
    "next": "12.0.0",
    "react": "17.0.2",
    "react-dom": "17.0.2"
  },
  "devDependencies": {
    "@tauri-apps/cli": "^1.0.0",
    "@types/node": "^14.14.31",
    "@types/react": "^17.0.0",
    "@types/react-dom": "^17.0.0",
    "typescript": "^4.3.2",
    "unocss": "^0.53.0"
  }
}
  1. 运行应用:
Bun run tauri dev
  1. 构建应用:
Bun run tauri build

这个版本将计算器应用改写成了一个使用 Next. Js 框架的 Tauri 桌面应用。主要变化包括:

  1. 使用 Next. Js 替代了 Vite 作为前端框架。
  2. 配置了 UnoCSS 以在 Next. Js 中使用。
  3. 调整了项目结构以适应 Next. Js 的约定。

注意, 虽然我们使用了 Next. Js, 但在 Tauri 应用中, 我们实际上并不会使用 Next. Js 的服务器端渲染功能。这里使用 Next. Js 主要是为了利用其提供的开发体验和工具链。