Xlera8

Cách tôi tạo ứng dụng Focus bằng React và Rust

Xin chào 👋,

Trong bài viết này, tôi sẽ mô tả các bước tôi đã thực hiện để tạo một ứng dụng nhỏ trên máy tính để giúp tôi tập trung vào các công việc hàng ngày của mình.

Một trong những mục tiêu của tôi là tạo ra công cụ quản lý thời gian tối ưu có thể giải quyết tất cả các vấn đề về năng suất của tôi, nhưng bây giờ hãy bắt đầu với một vấn đề nhỏ.
Khi tôi đang làm một nhiệm vụ, tôi thường bị gián đoạn bởi những nhiệm vụ khác nên được thực hiện (một nhiệm vụ mới được giao cho tôi, tôi nhớ ra điều gì đó mà tôi nên làm,…), hầu hết thời gian, nhiệm vụ mới không phải là điều đó. khẩn cấp và có thể đợi cho đến khi tôi hoàn thành công việc hiện tại của mình. Nhưng nó khiến tôi bị phân tâm và đôi khi tôi thấy mình ưu tiên nó hơn nhiệm vụ hiện tại chỉ để không quên nó. Sau đó, việc tiếp tục nhiệm vụ ban đầu trở nên khó khăn vì tôi mất tập trung. Để giải quyết vấn đề này, tôi cần một cách để nhanh chóng ghi nhật ký các tác vụ gây gián đoạn khi chúng bật lên và quên chúng đi cho đến khi tôi hoàn thành tác vụ hiện tại của mình.

  • Tôi đang làm gì đó… một ý tưởng/nhiệm vụ làm gián đoạn xuất hiện.
  • Tôi nhấn một phím tắt tùy chỉnh trên bàn phím của mình, sau đó một kiểu nhập văn bản xuất hiện ở giữa màn hình.
  • Tôi nhập mô tả nhanh về ý tưởng/nhiệm vụ đang làm gián đoạn, nhấn enter và dòng nhập văn bản biến mất.
  • Tôi vẫn tiếp tục công việc của mình bình thường.
    ...
  • Khi tôi hoàn thành, tôi mở một tệp được xác định trước và tìm thấy tất cả các ý tưởng/nhiệm vụ mà tôi đã nhập được viết bên trong tệp đó.

Những gì tôi đang cố gắng xây dựng ở đây là một ứng dụng dành cho máy tính để bàn, nhưng tôi muốn sử dụng các công nghệ web (ít nhất là cho giao diện người dùng). Công cụ phổ biến để làm điều đó là điện tử, nhưng gần đây tôi đã bắt đầu học Rust và chòm sao Kim Ngưu có vẻ như là một công cụ tốt để thử. Vì vậy, tôi sẽ sử dụng nó với React cho giao diện người dùng và Tailwind để tạo kiểu.

Tôi đã làm theo hướng dẫn trên Trang điều kiện tiên quyết của Tauri để thiết lập Rust và Node trên hệ thống của tôi, sau đó tôi chạy yarn create tauri-app để tạo dự án. Tôi đặt tên cho dự án focus và chọn create-vite biên nhận giao diện người dùng và đồng ý cài đặt @tauri-apps/api. Sau đó chọn react-ts mẫu của create-vite:

1-tạo-dự án.gif

Tauri đã tạo dự án và cài đặt các phụ thuộc. Hãy xem cấu trúc tệp:

src/ main.tsx <- entry point of JS/TS ... other UI files here
src-tauri/ icons/ <- icons of different sizes src/ main.rs <- entry point for the application target/ <- the compiled and bundles files Cargo.toml <- like package.json for Rust Cargo.lock <- like yarn.lock tauri.conf.json <- config file for Tauri
index.html <- entry point of the UI
package.json
yarn.lock
tsconfig.json
vite.config.ts <- config file for Vite

Bây giờ đang chạy yarn tauri dev nên khởi động ứng dụng. Điều này sẽ mất một chút thời gian vì Rust biên dịch mã lần đầu tiên, các lần thực thi sau sẽ nhanh chóng.

Bước cuối cùng của quá trình thiết lập là thêm Tailwind vào dự án, tôi đã làm điều đó bằng cách làm theo tài liệu chính thức

Đối với giao diện người dùng, tất cả những gì tôi cần là nhập văn bản, nơi tôi sẽ nhập tác vụ rồi nhấn Enter để lưu. Vì vậy, tôi đã thay đổi App mã thành phần như sau:

function App() { return <input type="text" className="w-[800px] h-[80px] bg-[#222] text-2xl text-white px-6" />
}

Lưu ý rằng tôi đang sử dụng Tailwind's giá trị tùy ý cú pháp để có một màu xám đậm 800px/80px đầu vào.

Khi tôi nhập một số văn bản vào đầu vào này, sau đó nhấn Enter, tôi muốn văn bản đó được thêm vào một tệp ở đâu đó. Hãy bắt đầu bằng cách lưu văn bản ở trạng thái và ghi nhật ký khi Enter bị ép buộc:

function App() { const [content, setContent] = React.useState('') return ( <input type="text" value={content} onChange={e => setContent(e.target.value)} onKeyDown={e => e.key === 'Enter' && console.log(content)} className="w-[800px] h-[80px] bg-[#222] text-2xl text-white px-6" /> )
}

2-add-state.gif

Bước tiếp theo là viết một hàm Rust sẽ nhận nội dung đầu vào và nối nó vào một tệp. Sau khi đọc Gọi Rust từ frontend trang tài liệu, tôi đã thay đổi src-tauri/src/main.rs theo sau:

Cảnh báo: Tôi chưa quen với Rust, vì vậy tôi có thể làm sai nhiều điều trong đoạn mã này

#![cfg_attr( all(not(debug_assertions), target_os = "windows"), windows_subsystem = "windows"
)] use std::fs::OpenOptions;
use std::io::prelude::*; #[tauri::command]
fn add_task(content: String) { let mut file = OpenOptions::new() .create(true) .append(true) .open("../tasks.txt") .expect("Error while opening the tasks file"); writeln!(file, "{}", content).expect("Error while writing in the tasks file");
} fn main() { tauri::Builder::default() .invoke_handler(tauri::generate_handler![add_task]) .run(tauri::generate_context!()) .expect("error while running tauri application");
}

Sau đó, tôi đã sửa đổi App thành phần để gọi chức năng đó khi Enter bị ép buộc:

function App() { const [content, setContent] = React.useState('') const handleKeyDown = async (e: React.KeyboardEvent) => { if (e.key === 'Enter') { await invoke('add_task', { content }) } } return ( <input type="text" value={content} onChange={e => setContent(e.target.value)} onKeyDown={handleKeyDown} className="w-[800px] h-[80px] bg-[#222] text-2xl text-white px-6" /> )
}

Bây giờ khi gõ một số văn bản và nhấn Enter, văn bản đã nhập được thêm vào tasks.txt tập tin.

3-append-to-file.gif

Lưu ý rằng tệp này được tạo trong thư mục gốc của dự án trong khi đường dẫn trong mã Rust là ../tasks.txt, điều này là do ứng dụng được thực thi bên trong src-tauri thư mục, vì vậy mọi đường dẫn tương đối sẽ liên quan đến thư mục đó. Sẽ tốt hơn nếu sử dụng một đường dẫn tuyệt đối và để người dùng xác định nó. Cách dễ nhất tôi có thể nghĩ ra để xác định nó là thông qua một biến môi trường, hãy gọi nó là FOCUS_TASKS_PATH.

Vì vậy, tôi đã thêm biến này vào .zshrc sau đó cập nhật mã Rust:


use std::env; #[tauri::command]
fn add_task(content: String) { let path = env::var("FOCUS_TASKS_PATH") .expect("The 'FOCUS_TASKS_PATH' env variable was not found!"); let mut file = OpenOptions::new() .create(true) .append(true) .open(path) .expect("Error while opening the tasks file"); writeln!(file, "{}", content).expect("Error while writing in the tasks file")
}

Ý tưởng ban đầu là có một cửa sổ bật lên, giống như Spotlight trên macOS, nhưng những gì chúng tôi có bây giờ trong cửa sổ trình duyệt! May mắn thay, Tauri cho phép chúng tôi điều chỉnh cửa sổ bằng cách sử dụng src-tauri/tauri.conf.json tài liệu. Cấu hình cửa sổ ban đầu là:

{ "fullscreen": false, "height": 600, "resizable": true, "title": "Focus", "width": 800
}

Tôi đã thay thế nó bằng

{ "fullscreen": false, "width": 800, "height": 80, "title": "Focus", "resizable": false, "center": true, "decorations": false }

Kết quả có vẻ tốt 😃

4-popup.gif

Bây giờ tôi muốn cửa sổ bật lên biến mất khi tôi nhấn Enter, vì vậy hãy thêm một process.exit() trong App thành phần (Điều này cũng có thể được thêm vào add_task Chức năng rỉ sét).

import { process } from '@tauri-apps/api' function App() { const [content, setContent] = React.useState('') const handleKeyDown = async (e: React.KeyboardEvent) => { if (e.key === 'Enter') { await invoke('add_task', { content }) process.exit() } } }

Bây giờ cửa sổ bật lên đã đóng khi Enter bị ép buộc 😃

Tôi nghĩ rằng chúng tôi đã có phiên bản alpha của ứng dụng ngay bây giờ, hãy xây dựng nó

yarn tauri build

Đầu tiên lệnh thất bại với thông báo này

Error You must change the bundle identifier in `tauri.conf.json > tauri > bundle > identifier`. The default value `com.tauri.dev` is not allowed as it must be unique across applications.

Đặt mã định danh thành dev.webneat.focus Đã giải quyết vấn đề.

Quá trình biên dịch mất một lúc sau đó tôi đã tạo các tệp sau (Tôi đang sử dụng Ubuntu):

src-tauri/target/release/bundle/ deb/focus_0.1.0_amd64.deb appimage/focus_0.1.0_amd64.AppImage

Vì AppImage dễ sử dụng hơn (không cần cài đặt), tôi chỉ cần chuyển nó sang bin thư mục và đặt tên cho nó focus:

sudo mv src-tauri/target/release/bundle/appimage/focus_0.1.0_amd64.AppImage /usr/bin/focus

Bây giờ chạy lệnh focus trên terminal sẽ mở cửa sổ bật lên 😄

Trên Ubuntu, tôi có thể thiết lập một phím tắt tùy chỉnh mới trên cài đặt Bàn phím. Bây giờ khi tôi nhấn phím tắt đó ở bất kỳ đâu, Cửa sổ bật lên xuất hiện, tôi nhập những gì tôi nghĩ và nhấn Enter sau đó tiếp tục những gì tôi đang làm 🎉

Kiểm tra kho lưu trữ tại đây https://github.com/webNeat/focus

Trò chuyện trực tiếp với chúng tôi (chat)

Chào bạn! Làm thế nào để tôi giúp bạn?