Tauri(Rust+React+TypeScript) から始めるディスクトップアプリ #5[カストマイズWindowの実装]
はじめに
前回 TauriクレートによるMenuを実装しました。
簡単に実装できました。しかし、本当に残念なんですが、自分的に課題があることがわかりました。
個人的に感じたメリデメで解説します。(2023.09.06現在)
メリット
・簡単に実装!! <これは正義>
・制限があるが、マルチプラットフォーム対応できる(コピペのショートカットキーなど)
デメリット
・マウスレス操作を実現できない。(サブメニューをショートカットキーで開けない)
・テーマを選べない(白いメニューとなる)
・メニューバーに別の機能を載せられない。
ディスクトップアプリの場合、ネイティブ感を出す事が大事だと思っています。
ネイティブ感と表現していますが、操作手引やマニュアルを読まなくとも分かる操作であったりUIを実装している事です。WindowsならWindowsの操作ってあると思います。
そのため、操作性やわかりやすいUIデザインが重要となのですが、現状のクレートによるメニューは、機能不足と言わざる負えません。
手軽にサクッと実装できることは、非常に有意義で大事ですが・・・現状だとデメリットの方が大きいので機能改善に期待しましょう。
Electronと比較して、TauriはWindowのカストマイズに関してまだまだな印象があります。V2待ちところがありますが、Electronも最終的には、ヘッドレスで独自Windowデザインを採用すると思いますので、少し手間がかかりますがヘッドレスでWindowカストマイズしていこうと思います。
(注意事項として今回は、Window10 Window11をターゲットとしています。Macで挑戦する場合はこれ以上に設定が必要みたいです。)
カストマイズWindow
Tauriクレートによるタイトルバーやメニューバーを非表示にし、React側の独自実装します。
どんなデザインを目指すのか?
代表的なアプリから参考に考えます。
Excel :タイトルバーとメニューバーの2段構成 WindowsのレガシィなUI
VisualStadioCode :タイトルバーにすべて押込んだUI
今回は、VisualStadioCodeを参考に作成しようと思います。いきなり、全機能を載せられないので
まずは、タイトルバーにアプリアイコンとメニュー縮小アイコン(window-minimize)拡大アイコン(window-maximize)クローズアイコン(close)を表示します。
CSSで書くのはめんどくさいので、取り急ぎTailwindcssを導入します。
Tailwindcssの導入
下記を参考に実施してください。セットアップは難しくないので省略します。
DaisyUIの導入
Tailwindcssはカストマイズ性が高く好みですが、皆さん言っている様に
・学習コストが高い。
・お手軽ではない。
muiやChakraを利用することも考えましたが、UIコンポーネントにガッツリ依存することになるため、どれを利用するかは悩みます。選定に時間をかけてられないので、Tailwindowテンプレートで実装を進めます。
選択したのが、DaisyUI。UIコンポーネントような使い方もできますが、Tailwindowでオーバライトできますので、使い勝手が良いのかな?と思います。
Tauriメニューの非表示
Configを下記のように変更します。
"windows": [
{
+ "decorations": false,
"theme": "Dark",
"fullscreen": false,
"resizable": true,
"title": "D4DataStudio",
"width": 1280,
"height": 768,
+ "transparent": true
}
"decorations": false //メニューが非表示になります。
"transparent": true //Windowが透明になります。
transparentは、ここで指定するのですが、TailwindowやDaisyUIでIndex.htmlのスタイルを上書きしてしまうので、無効になってしまします。そこで、<style>を追記します。
<!doctype html>
<html lang="ja">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>TEXT</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>
<style>
html,
body {
+ background-color: transparent !important;
border-radius: 10px ;
overflow: hidden;
}
.element-inside-your-body {
overflow: auto;
}
</style>
<head>タグは、Tauriでは利用されませんので無視でOK。
background-color: transparent !important; tauriで表示されるWindowを透明にしています。
透明になったWindowにReactの画面を表示します。
DaisyUIで優先度が変更されるみたいなので、!importantをつけて強制的に非表示にしています。
タイトルバーの追記
tauriのWindowが透明になったので、独自のタイトルバーをReactで表示します。
ミニマムボタン マックスボタン クローズボタンを追加します。
import { appWindow } from "@tauri-apps/api/window";
import { output } from "./../components/output.ts";
function window_minimize() {
output("Debug", "window minimize");
appWindow.minimize();
}
function window_maximize() {
output("Debug", "window maximize");
appWindow.toggleMaximize();
}
function window_close() {
output("Debug", "window close");
appWindow.close();
}
function Header() {
return (
<div className="navbar min-h-8 px-0 py-2 rounded-t-lg h-8 dark:bg-neutral-800 flex">
<div data-tauri-drag-region className="flex-none">
<button className="btn btn-square btn-sm btn-ghost">
<span className="i-mdi-view-headline w-5 h-5"></span>
</button>
</div>
<div data-tauri-drag-region className="flex-1">
<a className="btn btn-ghost btn-sm normal-case">D4data</a>
</div>
<div data-tauri-drag-region className="flex-none">
<button
className="btn btn-ghost btn-sm btn-square"
onClick={() => window_minimize()}
>
<span className="i-mdi-window-minimize w-5 h-5"></span>
</button>
<button
className="btn btn-ghost btn-sm btn-square"
onClick={() => window_maximize()}
>
<span className="i-mdi-window-maximize w-5 h-5"></span>
</button>
<button
className="btn btn-ghost btn-sm btn-square"
onClick={() => window_close()}
>
<span className="i-mdi-close w-5 h-5"></span>
</button>
</div>
</div>
);
}
export default Header;
上記の結果がこんな感じです。
かなりさみしいですが、これから盛っていきましょう。
気づき
・tauri Menu:Bodyの下に表示されるみたいなので表示しないようにしましょう。
・ショートカット:標準のショートカットは定義済み。動作OK。
調査状況は、下記にまとめています。
終わりに
メニューの実装は、別途やりましょう。
Discussion