mirror of
https://github.com/mountain-loop/yaak.git
synced 2026-02-18 16:47:48 +01:00
Compare commits
9 Commits
v2025.4.0-
...
v2025.4.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
aadfbfdfca | ||
|
|
383fd05c6c | ||
|
|
be0a8fc27a | ||
|
|
648a1ac53c | ||
|
|
9fab37fb17 | ||
|
|
e0aaa33ccb | ||
|
|
20f7d20031 | ||
|
|
4d90bc78b1 | ||
|
|
97763a1301 |
@@ -50,11 +50,9 @@ New migrations can be created from the `src-tauri/` directory:
|
||||
npm run migration
|
||||
```
|
||||
|
||||
Run the app to apply the migrations.
|
||||
Rerun the app to apply the migrations.
|
||||
|
||||
If nothing happens, try `cargo clean` and run the app again.
|
||||
|
||||
_Note: Development builds use a separate database location from production builds._
|
||||
_Note: For safety, development builds use a separate database location from production builds._
|
||||
|
||||
## Lezer Grammer Generation
|
||||
|
||||
|
||||
11
package-lock.json
generated
11
package-lock.json
generated
@@ -36,6 +36,7 @@
|
||||
"plugins/template-function-xml",
|
||||
"src-tauri/yaak-crypto",
|
||||
"src-tauri/yaak-git",
|
||||
"src-tauri/yaak-fonts",
|
||||
"src-tauri/yaak-license",
|
||||
"src-tauri/yaak-mac-window",
|
||||
"src-tauri/yaak-models",
|
||||
@@ -3606,6 +3607,10 @@
|
||||
"resolved": "src-tauri/yaak-crypto",
|
||||
"link": true
|
||||
},
|
||||
"node_modules/@yaakapp-internal/fonts": {
|
||||
"resolved": "src-tauri/yaak-fonts",
|
||||
"link": true
|
||||
},
|
||||
"node_modules/@yaakapp-internal/git": {
|
||||
"resolved": "src-tauri/yaak-git",
|
||||
"link": true
|
||||
@@ -17294,7 +17299,7 @@
|
||||
},
|
||||
"packages/plugin-runtime-types": {
|
||||
"name": "@yaakapp/api",
|
||||
"version": "0.6.0",
|
||||
"version": "0.6.4",
|
||||
"dependencies": {
|
||||
"@types/node": "^22.5.4"
|
||||
},
|
||||
@@ -17543,6 +17548,10 @@
|
||||
"name": "@yaakapp-internal/crypto",
|
||||
"version": "1.0.0"
|
||||
},
|
||||
"src-tauri/yaak-fonts": {
|
||||
"name": "@yaakapp-internal/fonts",
|
||||
"version": "1.0.0"
|
||||
},
|
||||
"src-tauri/yaak-git": {
|
||||
"name": "@yaakapp-internal/git",
|
||||
"version": "1.0.0"
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
"plugins/template-function-xml",
|
||||
"src-tauri/yaak-crypto",
|
||||
"src-tauri/yaak-git",
|
||||
"src-tauri/yaak-fonts",
|
||||
"src-tauri/yaak-license",
|
||||
"src-tauri/yaak-mac-window",
|
||||
"src-tauri/yaak-models",
|
||||
|
||||
28
packages/plugin-runtime-types/README.md
Normal file
28
packages/plugin-runtime-types/README.md
Normal file
@@ -0,0 +1,28 @@
|
||||
# Yaak Plugin API
|
||||
|
||||
Yaak is a desktop [API client](https://yaak.app/blog/yet-another-api-client) for
|
||||
interacting with REST, GraphQL, Server Sent Events (SSE), WebSocket, and gRPC APIs. It's
|
||||
built using Tauri, Rust, and ReactJS.
|
||||
|
||||
Plugins can be created in TypeScript, which are executed alongside Yaak in a NodeJS
|
||||
runtime. This package contains the TypeScript type definitions required to make building
|
||||
Yaak plugins a breeze.
|
||||
|
||||
## Quick Start
|
||||
|
||||
The easiest way to get started is by generating a plugin with the Yaak CLI:
|
||||
|
||||
```shell
|
||||
npx @yaakapp/cli generate
|
||||
```
|
||||
|
||||
For more details on creating plugins, check out
|
||||
the [Quick Start Guide](https://feedback.yaak.app/help/articles/6911763-plugins-quick-start)
|
||||
|
||||
## Installation
|
||||
|
||||
If you prefer starting from scratch, manually install the types package:
|
||||
|
||||
```shell
|
||||
npm install @yaakapp/api
|
||||
```
|
||||
@@ -1,6 +1,20 @@
|
||||
{
|
||||
"name": "@yaakapp/api",
|
||||
"version": "0.6.0",
|
||||
"version": "0.6.4",
|
||||
"keywords": [
|
||||
"api-client",
|
||||
"insomnia-alternative",
|
||||
"bruno-alternative",
|
||||
"postman-alternative"
|
||||
],
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/mountain-loop/yaak"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://feedback.yaak.app"
|
||||
},
|
||||
"homepage": "https://yaak.app",
|
||||
"main": "lib/index.js",
|
||||
"typings": "./lib/index.d.ts",
|
||||
"files": [
|
||||
|
||||
136
src-tauri/Cargo.lock
generated
136
src-tauri/Cargo.lock
generated
@@ -859,6 +859,15 @@ dependencies = [
|
||||
"error-code",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cmake"
|
||||
version = "0.1.54"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e7caa3f9de89ddbe2c607f4101924c5abec803763ae9534e4f4d7d8f84aa81f0"
|
||||
dependencies = [
|
||||
"cc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cocoa"
|
||||
version = "0.26.1"
|
||||
@@ -869,7 +878,7 @@ dependencies = [
|
||||
"block",
|
||||
"cocoa-foundation",
|
||||
"core-foundation 0.10.1",
|
||||
"core-graphics",
|
||||
"core-graphics 0.24.0",
|
||||
"foreign-types 0.5.0",
|
||||
"libc",
|
||||
"objc",
|
||||
@@ -884,7 +893,7 @@ dependencies = [
|
||||
"bitflags 2.9.1",
|
||||
"block",
|
||||
"core-foundation 0.10.1",
|
||||
"core-graphics-types",
|
||||
"core-graphics-types 0.2.0",
|
||||
"objc",
|
||||
]
|
||||
|
||||
@@ -978,6 +987,19 @@ version = "0.8.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
|
||||
|
||||
[[package]]
|
||||
name = "core-graphics"
|
||||
version = "0.22.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2581bbab3b8ffc6fcbd550bf46c355135d16e9ff2a6ea032ad6b9bf1d7efe4fb"
|
||||
dependencies = [
|
||||
"bitflags 1.3.2",
|
||||
"core-foundation 0.9.4",
|
||||
"core-graphics-types 0.1.3",
|
||||
"foreign-types 0.3.2",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "core-graphics"
|
||||
version = "0.24.0"
|
||||
@@ -986,11 +1008,22 @@ checksum = "fa95a34622365fa5bbf40b20b75dba8dfa8c94c734aea8ac9a5ca38af14316f1"
|
||||
dependencies = [
|
||||
"bitflags 2.9.1",
|
||||
"core-foundation 0.10.1",
|
||||
"core-graphics-types",
|
||||
"core-graphics-types 0.2.0",
|
||||
"foreign-types 0.5.0",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "core-graphics-types"
|
||||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "45390e6114f68f718cc7a830514a96f903cccd70d02a8f6d9f643ac4ba45afaf"
|
||||
dependencies = [
|
||||
"bitflags 1.3.2",
|
||||
"core-foundation 0.9.4",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "core-graphics-types"
|
||||
version = "0.2.0"
|
||||
@@ -1002,6 +1035,18 @@ dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "core-text"
|
||||
version = "19.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "99d74ada66e07c1cefa18f8abfba765b486f250de2e4a999e5727fc0dd4b4a25"
|
||||
dependencies = [
|
||||
"core-foundation 0.9.4",
|
||||
"core-graphics 0.22.3",
|
||||
"foreign-types 0.3.2",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cpufeatures"
|
||||
version = "0.2.17"
|
||||
@@ -1466,6 +1511,16 @@ dependencies = [
|
||||
"pin-project",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "expat-sys"
|
||||
version = "2.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "658f19728920138342f68408b7cf7644d90d4784353d8ebc32e7e8663dbe45fa"
|
||||
dependencies = [
|
||||
"cmake",
|
||||
"pkg-config",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fallible-iterator"
|
||||
version = "0.3.0"
|
||||
@@ -1547,6 +1602,19 @@ version = "1.0.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
|
||||
|
||||
[[package]]
|
||||
name = "font-loader"
|
||||
version = "0.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c49d6b4c11dca1a1dd931a34a9f397e2da91abe3de4110505f3530a80e560b52"
|
||||
dependencies = [
|
||||
"core-foundation 0.9.4",
|
||||
"core-text",
|
||||
"libc",
|
||||
"servo-fontconfig",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "foreign-types"
|
||||
version = "0.3.2"
|
||||
@@ -1598,6 +1666,17 @@ dependencies = [
|
||||
"percent-encoding",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "freetype-sys"
|
||||
version = "0.13.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a37d4011c0cc628dfa766fcc195454f4b068d7afdc2adfd28861191d866e731a"
|
||||
dependencies = [
|
||||
"cmake",
|
||||
"libc",
|
||||
"pkg-config",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fsevent-sys"
|
||||
version = "4.1.0"
|
||||
@@ -4517,6 +4596,7 @@ dependencies = [
|
||||
"tokio",
|
||||
"tokio-native-tls",
|
||||
"tokio-rustls",
|
||||
"tokio-socks",
|
||||
"tokio-util",
|
||||
"tower 0.5.2",
|
||||
"tower-http",
|
||||
@@ -5111,6 +5191,27 @@ dependencies = [
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "servo-fontconfig"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c7e3e22fe5fd73d04ebf0daa049d3efe3eae55369ce38ab16d07ddd9ac5c217c"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"servo-fontconfig-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "servo-fontconfig-sys"
|
||||
version = "5.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e36b879db9892dfa40f95da1c38a835d41634b825fbd8c4c418093d53c24b388"
|
||||
dependencies = [
|
||||
"expat-sys",
|
||||
"freetype-sys",
|
||||
"pkg-config",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "servo_arc"
|
||||
version = "0.1.1"
|
||||
@@ -5225,7 +5326,7 @@ checksum = "18051cdd562e792cad055119e0cdb2cfc137e44e3987532e0f9659a77931bb08"
|
||||
dependencies = [
|
||||
"bytemuck",
|
||||
"cfg_aliases",
|
||||
"core-graphics",
|
||||
"core-graphics 0.24.0",
|
||||
"foreign-types 0.5.0",
|
||||
"js-sys",
|
||||
"log",
|
||||
@@ -5418,7 +5519,7 @@ checksum = "1e59c1f38e657351a2e822eadf40d6a2ad4627b9c25557bc1180ec1b3295ef82"
|
||||
dependencies = [
|
||||
"bitflags 2.9.1",
|
||||
"core-foundation 0.10.1",
|
||||
"core-graphics",
|
||||
"core-graphics 0.24.0",
|
||||
"crossbeam-channel",
|
||||
"dispatch",
|
||||
"dlopen2",
|
||||
@@ -6110,6 +6211,18 @@ dependencies = [
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-socks"
|
||||
version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0d4770b8024672c1101b3f6733eab95b18007dbe0847a8afe341fcf79e06043f"
|
||||
dependencies = [
|
||||
"either",
|
||||
"futures-util",
|
||||
"thiserror 1.0.69",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-stream"
|
||||
version = "0.1.17"
|
||||
@@ -7546,6 +7659,7 @@ dependencies = [
|
||||
"uuid",
|
||||
"yaak-common",
|
||||
"yaak-crypto",
|
||||
"yaak-fonts",
|
||||
"yaak-git",
|
||||
"yaak-grpc",
|
||||
"yaak-http",
|
||||
@@ -7583,6 +7697,18 @@ dependencies = [
|
||||
"yaak-models",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "yaak-fonts"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"font-loader",
|
||||
"serde",
|
||||
"tauri",
|
||||
"tauri-plugin",
|
||||
"thiserror 2.0.12",
|
||||
"ts-rs",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "yaak-git"
|
||||
version = "0.1.0"
|
||||
|
||||
@@ -3,6 +3,7 @@ members = [
|
||||
"yaak-crypto",
|
||||
"yaak-git",
|
||||
"yaak-grpc",
|
||||
"yaak-fonts",
|
||||
"yaak-http",
|
||||
"yaak-license",
|
||||
"yaak-mac-window",
|
||||
@@ -48,7 +49,7 @@ log = "0.4.27"
|
||||
md5 = "0.7.0"
|
||||
mime_guess = "2.0.5"
|
||||
rand = "0.9.0"
|
||||
reqwest = { workspace = true, features = ["multipart", "cookies", "gzip", "brotli", "deflate", "json", "rustls-tls-manual-roots-no-provider"] }
|
||||
reqwest = { workspace = true, features = ["multipart", "cookies", "gzip", "brotli", "deflate", "json", "rustls-tls-manual-roots-no-provider", "socks"] }
|
||||
reqwest_cookie_store = "0.8.0"
|
||||
serde = { workspace = true, features = ["derive"] }
|
||||
serde_json = { workspace = true, features = ["raw_value"] }
|
||||
@@ -75,6 +76,7 @@ yaak-http = { workspace = true }
|
||||
yaak-license = { path = "yaak-license" }
|
||||
yaak-mac-window = { path = "yaak-mac-window" }
|
||||
yaak-models = { workspace = true }
|
||||
yaak-fonts = { workspace = true }
|
||||
yaak-plugins = { workspace = true }
|
||||
yaak-sse = { workspace = true }
|
||||
yaak-sync = { workspace = true }
|
||||
@@ -95,6 +97,7 @@ ts-rs = "11.0.1"
|
||||
rustls = { version = "0.23.27", default-features = false }
|
||||
rustls-platform-verifier = "0.6.0"
|
||||
yaak-common = { path = "yaak-common" }
|
||||
yaak-fonts = { path = "yaak-fonts" }
|
||||
yaak-http = { path = "yaak-http" }
|
||||
yaak-models = { path = "yaak-models" }
|
||||
yaak-plugins = { path = "yaak-plugins" }
|
||||
|
||||
@@ -53,6 +53,7 @@
|
||||
"shell:allow-open",
|
||||
"yaak-crypto:default",
|
||||
"yaak-git:default",
|
||||
"yaak-fonts:default",
|
||||
"yaak-license:default",
|
||||
"yaak-mac-window:default",
|
||||
"yaak-models:default",
|
||||
|
||||
@@ -7,7 +7,7 @@ use http::{HeaderMap, HeaderName, HeaderValue};
|
||||
use log::{debug, error, warn};
|
||||
use mime_guess::Mime;
|
||||
use reqwest::redirect::Policy;
|
||||
use reqwest::{Method, Response};
|
||||
use reqwest::{Method, NoProxy, Response};
|
||||
use reqwest::{Proxy, Url, multipart};
|
||||
use serde_json::Value;
|
||||
use std::collections::BTreeMap;
|
||||
@@ -120,25 +120,39 @@ pub async fn send_http_request<R: Runtime>(
|
||||
https,
|
||||
auth,
|
||||
disabled,
|
||||
bypass,
|
||||
}) if !disabled => {
|
||||
debug!("Using proxy http={http} https={https}");
|
||||
let mut proxy = Proxy::custom(move |url| {
|
||||
let http = if http.is_empty() { None } else { Some(http.to_owned()) };
|
||||
let https = if https.is_empty() { None } else { Some(https.to_owned()) };
|
||||
let proxy_url = match (url.scheme(), http, https) {
|
||||
("http", Some(proxy_url), _) => Some(proxy_url),
|
||||
("https", _, Some(proxy_url)) => Some(proxy_url),
|
||||
_ => None,
|
||||
debug!("Using proxy http={http} https={https} bypass={bypass}");
|
||||
if !http.is_empty() {
|
||||
match Proxy::http(http) {
|
||||
Ok(mut proxy) => {
|
||||
if let Some(ProxySettingAuth { user, password }) = auth.clone() {
|
||||
debug!("Using http proxy auth");
|
||||
proxy = proxy.basic_auth(user.as_str(), password.as_str());
|
||||
}
|
||||
proxy = proxy.no_proxy(NoProxy::from_string(&bypass));
|
||||
client_builder = client_builder.proxy(proxy);
|
||||
}
|
||||
Err(e) => {
|
||||
warn!("Failed to apply http proxy {e:?}");
|
||||
}
|
||||
};
|
||||
}
|
||||
if !https.is_empty() {
|
||||
match Proxy::https(https) {
|
||||
Ok(mut proxy) => {
|
||||
if let Some(ProxySettingAuth { user, password }) = auth {
|
||||
debug!("Using https proxy auth");
|
||||
proxy = proxy.basic_auth(user.as_str(), password.as_str());
|
||||
}
|
||||
proxy = proxy.no_proxy(NoProxy::from_string(&bypass));
|
||||
client_builder = client_builder.proxy(proxy);
|
||||
}
|
||||
Err(e) => {
|
||||
warn!("Failed to apply https proxy {e:?}");
|
||||
}
|
||||
};
|
||||
proxy_url
|
||||
});
|
||||
|
||||
if let Some(ProxySettingAuth { user, password }) = auth {
|
||||
debug!("Using proxy auth");
|
||||
proxy = proxy.basic_auth(user.as_str(), password.as_str());
|
||||
}
|
||||
|
||||
client_builder = client_builder.proxy(proxy);
|
||||
}
|
||||
_ => {} // Nothing to do for this one, as it is the default
|
||||
}
|
||||
|
||||
@@ -1265,6 +1265,7 @@ pub fn run() {
|
||||
.plugin(yaak_models::init())
|
||||
.plugin(yaak_plugins::init())
|
||||
.plugin(yaak_crypto::init())
|
||||
.plugin(yaak_fonts::init())
|
||||
.plugin(yaak_git::init())
|
||||
.plugin(yaak_ws::init())
|
||||
.plugin(yaak_sync::init());
|
||||
|
||||
16
src-tauri/yaak-fonts/Cargo.toml
Normal file
16
src-tauri/yaak-fonts/Cargo.toml
Normal file
@@ -0,0 +1,16 @@
|
||||
[package]
|
||||
name = "yaak-fonts"
|
||||
links = "yaak-fonts"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
publish = false
|
||||
|
||||
[dependencies]
|
||||
font-loader = "0.11.0"
|
||||
tauri = { workspace = true }
|
||||
ts-rs = { workspace = true }
|
||||
serde = "1.0"
|
||||
thiserror = { workspace = true }
|
||||
|
||||
[build-dependencies]
|
||||
tauri-plugin = { workspace = true, features = ["build"] }
|
||||
3
src-tauri/yaak-fonts/bindings/gen_fonts.ts
Normal file
3
src-tauri/yaak-fonts/bindings/gen_fonts.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
|
||||
export type Fonts = { editorFonts: Array<string>, uiFonts: Array<string>, };
|
||||
5
src-tauri/yaak-fonts/build.rs
Normal file
5
src-tauri/yaak-fonts/build.rs
Normal file
@@ -0,0 +1,5 @@
|
||||
const COMMANDS: &[&str] = &["list"];
|
||||
|
||||
fn main() {
|
||||
tauri_plugin::Builder::new(COMMANDS).build();
|
||||
}
|
||||
14
src-tauri/yaak-fonts/index.ts
Normal file
14
src-tauri/yaak-fonts/index.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import { invoke } from '@tauri-apps/api/core';
|
||||
import { Fonts } from './bindings/gen_fonts';
|
||||
|
||||
export async function listFonts() {
|
||||
return invoke<Fonts>('plugin:yaak-fonts|list', {});
|
||||
}
|
||||
|
||||
export function useFonts() {
|
||||
return useQuery({
|
||||
queryKey: ['list_fonts'],
|
||||
queryFn: () => listFonts(),
|
||||
});
|
||||
}
|
||||
6
src-tauri/yaak-fonts/package.json
Normal file
6
src-tauri/yaak-fonts/package.json
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"name": "@yaakapp-internal/fonts",
|
||||
"private": true,
|
||||
"version": "1.0.0",
|
||||
"main": "index.ts"
|
||||
}
|
||||
3
src-tauri/yaak-fonts/permissions/default.toml
Normal file
3
src-tauri/yaak-fonts/permissions/default.toml
Normal file
@@ -0,0 +1,3 @@
|
||||
[default]
|
||||
description = "Default permissions for the plugin"
|
||||
permissions = ["allow-list"]
|
||||
41
src-tauri/yaak-fonts/src/commands.rs
Normal file
41
src-tauri/yaak-fonts/src/commands.rs
Normal file
@@ -0,0 +1,41 @@
|
||||
use crate::Result;
|
||||
use font_loader::system_fonts;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::collections::HashSet;
|
||||
use tauri::command;
|
||||
use ts_rs::TS;
|
||||
|
||||
#[derive(Default, Debug, Clone, Serialize, Deserialize, TS, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export, export_to = "gen_fonts.ts")]
|
||||
pub struct Fonts {
|
||||
pub editor_fonts: Vec<String>,
|
||||
pub ui_fonts: Vec<String>,
|
||||
}
|
||||
|
||||
#[command]
|
||||
pub(crate) async fn list() -> Result<Fonts> {
|
||||
let mut ui_fonts = HashSet::new();
|
||||
let mut editor_fonts = HashSet::new();
|
||||
|
||||
let mut property = system_fonts::FontPropertyBuilder::new().monospace().build();
|
||||
for font in &system_fonts::query_specific(&mut property) {
|
||||
editor_fonts.insert(font.to_string());
|
||||
}
|
||||
for font in &system_fonts::query_all() {
|
||||
if !editor_fonts.contains(font) {
|
||||
ui_fonts.insert(font.to_string());
|
||||
}
|
||||
}
|
||||
|
||||
let mut ui_fonts: Vec<String> = ui_fonts.into_iter().collect();
|
||||
let mut editor_fonts: Vec<String> = editor_fonts.into_iter().collect();
|
||||
|
||||
ui_fonts.sort();
|
||||
editor_fonts.sort();
|
||||
|
||||
Ok(Fonts {
|
||||
ui_fonts,
|
||||
editor_fonts,
|
||||
})
|
||||
}
|
||||
15
src-tauri/yaak-fonts/src/error.rs
Normal file
15
src-tauri/yaak-fonts/src/error.rs
Normal file
@@ -0,0 +1,15 @@
|
||||
use serde::{ser::Serializer, Serialize};
|
||||
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
pub enum Error {}
|
||||
|
||||
impl Serialize for Error {
|
||||
fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
serializer.serialize_str(self.to_string().as_ref())
|
||||
}
|
||||
}
|
||||
|
||||
pub type Result<T> = std::result::Result<T, Error>;
|
||||
15
src-tauri/yaak-fonts/src/lib.rs
Normal file
15
src-tauri/yaak-fonts/src/lib.rs
Normal file
@@ -0,0 +1,15 @@
|
||||
use tauri::{
|
||||
generate_handler,
|
||||
plugin::{Builder, TauriPlugin},
|
||||
Runtime,
|
||||
};
|
||||
|
||||
mod commands;
|
||||
mod error;
|
||||
|
||||
use crate::commands::list;
|
||||
pub use error::{Error, Result};
|
||||
|
||||
pub fn init<R: Runtime>() -> TauriPlugin<R> {
|
||||
Builder::new("yaak-fonts").invoke_handler(generate_handler![list]).build()
|
||||
}
|
||||
@@ -58,11 +58,11 @@ export type Plugin = { model: "plugin", id: string, createdAt: string, updatedAt
|
||||
|
||||
export type PluginKeyValue = { model: "plugin_key_value", createdAt: string, updatedAt: string, pluginName: string, key: string, value: string, };
|
||||
|
||||
export type ProxySetting = { "type": "enabled", disabled: boolean, http: string, https: string, auth: ProxySettingAuth | null, } | { "type": "disabled" };
|
||||
export type ProxySetting = { "type": "enabled", disabled: boolean, http: string, https: string, auth: ProxySettingAuth | null, bypass: string, } | { "type": "disabled" };
|
||||
|
||||
export type ProxySettingAuth = { user: string, password: string, };
|
||||
|
||||
export type Settings = { model: "settings", id: string, createdAt: string, updatedAt: string, appearance: string, editorFontSize: number, editorSoftWrap: boolean, hideWindowControls: boolean, interfaceFontSize: number, interfaceScale: number, openWorkspaceNewWindow: boolean | null, proxy: ProxySetting | null, themeDark: string, themeLight: string, updateChannel: string, editorKeymap: EditorKeymap, coloredMethods: boolean, };
|
||||
export type Settings = { model: "settings", id: string, createdAt: string, updatedAt: string, appearance: string, coloredMethods: boolean, editorFont: string | null, editorFontSize: number, editorKeymap: EditorKeymap, editorSoftWrap: boolean, hideWindowControls: boolean, interfaceFont: string | null, interfaceFontSize: number, interfaceScale: number, openWorkspaceNewWindow: boolean | null, proxy: ProxySetting | null, themeDark: string, themeLight: string, updateChannel: string, };
|
||||
|
||||
export type SyncState = { model: "sync_state", id: string, workspaceId: string, createdAt: string, updatedAt: string, flushedAt: string, modelId: string, checksum: string, relPath: string, syncDir: string, };
|
||||
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
ALTER TABLE settings ADD COLUMN interface_font TEXT;
|
||||
ALTER TABLE settings ADD COLUMN editor_font TEXT;
|
||||
@@ -31,12 +31,15 @@ macro_rules! impl_model {
|
||||
#[ts(export, export_to = "gen_models.ts")]
|
||||
pub enum ProxySetting {
|
||||
Enabled {
|
||||
#[serde(default)]
|
||||
// This was added after on so give it a default to be able to deserialize older values
|
||||
disabled: bool,
|
||||
http: String,
|
||||
https: String,
|
||||
auth: Option<ProxySettingAuth>,
|
||||
|
||||
// These were added later, so give them defaults
|
||||
#[serde(default)]
|
||||
bypass: String,
|
||||
#[serde(default)]
|
||||
disabled: bool,
|
||||
},
|
||||
Disabled,
|
||||
}
|
||||
@@ -103,9 +106,13 @@ pub struct Settings {
|
||||
pub updated_at: NaiveDateTime,
|
||||
|
||||
pub appearance: String,
|
||||
pub colored_methods: bool,
|
||||
pub editor_font: Option<String>,
|
||||
pub editor_font_size: i32,
|
||||
pub editor_keymap: EditorKeymap,
|
||||
pub editor_soft_wrap: bool,
|
||||
pub hide_window_controls: bool,
|
||||
pub interface_font: Option<String>,
|
||||
pub interface_font_size: i32,
|
||||
pub interface_scale: f32,
|
||||
pub open_workspace_new_window: Option<bool>,
|
||||
@@ -113,8 +120,6 @@ pub struct Settings {
|
||||
pub theme_dark: String,
|
||||
pub theme_light: String,
|
||||
pub update_channel: String,
|
||||
pub editor_keymap: EditorKeymap,
|
||||
pub colored_methods: bool,
|
||||
}
|
||||
|
||||
impl UpsertModelInfo for Settings {
|
||||
@@ -154,6 +159,8 @@ impl UpsertModelInfo for Settings {
|
||||
(EditorFontSize, self.editor_font_size.into()),
|
||||
(EditorKeymap, self.editor_keymap.to_string().into()),
|
||||
(EditorSoftWrap, self.editor_soft_wrap.into()),
|
||||
(EditorFont, self.editor_font.into()),
|
||||
(InterfaceFont, self.interface_font.into()),
|
||||
(InterfaceFontSize, self.interface_font_size.into()),
|
||||
(InterfaceScale, self.interface_scale.into()),
|
||||
(HideWindowControls, self.hide_window_controls.into()),
|
||||
@@ -173,8 +180,10 @@ impl UpsertModelInfo for Settings {
|
||||
SettingsIden::EditorFontSize,
|
||||
SettingsIden::EditorKeymap,
|
||||
SettingsIden::EditorSoftWrap,
|
||||
SettingsIden::EditorFont,
|
||||
SettingsIden::InterfaceFontSize,
|
||||
SettingsIden::InterfaceScale,
|
||||
SettingsIden::InterfaceFont,
|
||||
SettingsIden::HideWindowControls,
|
||||
SettingsIden::OpenWorkspaceNewWindow,
|
||||
SettingsIden::Proxy,
|
||||
@@ -198,10 +207,12 @@ impl UpsertModelInfo for Settings {
|
||||
updated_at: row.get("updated_at")?,
|
||||
appearance: row.get("appearance")?,
|
||||
editor_font_size: row.get("editor_font_size")?,
|
||||
editor_font: row.get("editor_font")?,
|
||||
editor_keymap: EditorKeymap::from_str(editor_keymap.as_str()).unwrap(),
|
||||
editor_soft_wrap: row.get("editor_soft_wrap")?,
|
||||
interface_font_size: row.get("interface_font_size")?,
|
||||
interface_scale: row.get("interface_scale")?,
|
||||
interface_font: row.get("interface_font")?,
|
||||
open_workspace_new_window: row.get("open_workspace_new_window")?,
|
||||
proxy: proxy.map(|p| -> ProxySetting { serde_json::from_str(p.as_str()).unwrap() }),
|
||||
theme_dark: row.get("theme_dark")?,
|
||||
|
||||
@@ -19,10 +19,12 @@ impl<'a> DbContext<'a> {
|
||||
|
||||
appearance: "system".to_string(),
|
||||
editor_font_size: 13,
|
||||
editor_font: None,
|
||||
editor_keymap: EditorKeymap::Default,
|
||||
editor_soft_wrap: true,
|
||||
interface_font_size: 15,
|
||||
interface_scale: 1.0,
|
||||
interface_font: None,
|
||||
hide_window_controls: false,
|
||||
open_workspace_new_window: None,
|
||||
proxy: None,
|
||||
|
||||
@@ -8,22 +8,24 @@ import { capitalize } from '../../lib/capitalize';
|
||||
import { HStack } from '../core/Stacks';
|
||||
import { TabContent, Tabs } from '../core/Tabs/Tabs';
|
||||
import { HeaderSize } from '../HeaderSize';
|
||||
import { SettingsAppearance } from './SettingsAppearance';
|
||||
import { SettingsInterface } from './SettingsInterface';
|
||||
import { SettingsGeneral } from './SettingsGeneral';
|
||||
import { SettingsLicense } from './SettingsLicense';
|
||||
import { SettingsPlugins } from './SettingsPlugins';
|
||||
import { SettingsProxy } from './SettingsProxy';
|
||||
import { SettingsTheme } from './SettingsTheme';
|
||||
|
||||
interface Props {
|
||||
hide?: () => void;
|
||||
}
|
||||
|
||||
const TAB_GENERAL = 'general';
|
||||
const TAB_APPEARANCE = 'appearance';
|
||||
const TAB_INTERFACE = 'interface';
|
||||
const TAB_THEME = 'theme';
|
||||
const TAB_PROXY = 'proxy';
|
||||
const TAB_PLUGINS = 'plugins';
|
||||
const TAB_LICENSE = 'license';
|
||||
const tabs = [TAB_GENERAL, TAB_APPEARANCE, TAB_PROXY, TAB_PLUGINS, TAB_LICENSE] as const;
|
||||
const tabs = [TAB_GENERAL, TAB_THEME, TAB_INTERFACE, TAB_PROXY, TAB_PLUGINS, TAB_LICENSE] as const;
|
||||
export type SettingsTab = (typeof tabs)[number];
|
||||
|
||||
export default function Settings({ hide }: Props) {
|
||||
@@ -73,8 +75,11 @@ export default function Settings({ hide }: Props) {
|
||||
<TabContent value={TAB_GENERAL} className="pt-3 overflow-y-auto h-full px-4">
|
||||
<SettingsGeneral />
|
||||
</TabContent>
|
||||
<TabContent value={TAB_APPEARANCE} className="pt-3 overflow-y-auto h-full px-4">
|
||||
<SettingsAppearance />
|
||||
<TabContent value={TAB_INTERFACE} className="pt-3 overflow-y-auto h-full px-4">
|
||||
<SettingsInterface />
|
||||
</TabContent>
|
||||
<TabContent value={TAB_THEME} className="pt-3 overflow-y-auto h-full px-4">
|
||||
<SettingsTheme />
|
||||
</TabContent>
|
||||
<TabContent value={TAB_PLUGINS} className="pt-3 overflow-y-auto h-full px-4">
|
||||
<SettingsPlugins />
|
||||
|
||||
137
src-web/components/Settings/SettingsInterface.tsx
Normal file
137
src-web/components/Settings/SettingsInterface.tsx
Normal file
@@ -0,0 +1,137 @@
|
||||
import { type } from '@tauri-apps/plugin-os';
|
||||
import { useFonts } from '@yaakapp-internal/fonts';
|
||||
import type { EditorKeymap } from '@yaakapp-internal/models';
|
||||
import { patchModel, settingsAtom } from '@yaakapp-internal/models';
|
||||
import { useAtomValue } from 'jotai';
|
||||
import React from 'react';
|
||||
import { activeWorkspaceAtom } from '../../hooks/useActiveWorkspace';
|
||||
import { clamp } from '../../lib/clamp';
|
||||
import { Checkbox } from '../core/Checkbox';
|
||||
import { Icon } from '../core/Icon';
|
||||
import { Select } from '../core/Select';
|
||||
import { HStack, VStack } from '../core/Stacks';
|
||||
|
||||
const NULL_FONT_VALUE = '__NULL_FONT__';
|
||||
|
||||
const fontSizeOptions = [
|
||||
8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30,
|
||||
].map((n) => ({ label: `${n}`, value: `${n}` }));
|
||||
|
||||
const keymaps: { value: EditorKeymap; label: string }[] = [
|
||||
{ value: 'default', label: 'Default' },
|
||||
{ value: 'vim', label: 'Vim' },
|
||||
{ value: 'vscode', label: 'VSCode' },
|
||||
{ value: 'emacs', label: 'Emacs' },
|
||||
];
|
||||
|
||||
export function SettingsInterface() {
|
||||
const workspace = useAtomValue(activeWorkspaceAtom);
|
||||
const settings = useAtomValue(settingsAtom);
|
||||
const fonts = useFonts();
|
||||
|
||||
if (settings == null || workspace == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<VStack space={3} className="mb-4">
|
||||
<HStack space={2} alignItems="end">
|
||||
{fonts.data && (
|
||||
<Select
|
||||
size="sm"
|
||||
name="uiFont"
|
||||
label="Interface Font"
|
||||
value={settings.interfaceFont ?? NULL_FONT_VALUE}
|
||||
options={[
|
||||
{ label: 'System Default', value: NULL_FONT_VALUE },
|
||||
...(fonts.data.uiFonts.map((f) => ({
|
||||
label: f,
|
||||
value: f,
|
||||
})) ?? []),
|
||||
// Some people like monospace fonts for the UI
|
||||
...(fonts.data.editorFonts.map((f) => ({
|
||||
label: f,
|
||||
value: f,
|
||||
})) ?? []),
|
||||
]}
|
||||
onChange={async (v) => {
|
||||
const interfaceFont = v === NULL_FONT_VALUE ? null : v;
|
||||
await patchModel(settings, { interfaceFont });
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
<Select
|
||||
hideLabel
|
||||
size="sm"
|
||||
name="interfaceFontSize"
|
||||
label="Interface Font Size"
|
||||
defaultValue="15"
|
||||
value={`${settings.interfaceFontSize}`}
|
||||
options={fontSizeOptions}
|
||||
onChange={(v) => patchModel(settings, { interfaceFontSize: parseInt(v) })}
|
||||
/>
|
||||
</HStack>
|
||||
<HStack space={2} alignItems="end">
|
||||
{fonts.data && (
|
||||
<Select
|
||||
size="sm"
|
||||
name="editorFont"
|
||||
label="Editor Font"
|
||||
value={settings.editorFont ?? NULL_FONT_VALUE}
|
||||
options={[
|
||||
{ label: 'System Default', value: NULL_FONT_VALUE },
|
||||
...(fonts.data.editorFonts.map((f) => ({
|
||||
label: f,
|
||||
value: f,
|
||||
})) ?? []),
|
||||
]}
|
||||
onChange={async (v) => {
|
||||
const editorFont = v === NULL_FONT_VALUE ? null : v;
|
||||
await patchModel(settings, { editorFont });
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
<Select
|
||||
hideLabel
|
||||
size="sm"
|
||||
name="editorFontSize"
|
||||
label="Editor Font Size"
|
||||
defaultValue="13"
|
||||
value={`${settings.editorFontSize}`}
|
||||
options={fontSizeOptions}
|
||||
onChange={(v) =>
|
||||
patchModel(settings, { editorFontSize: clamp(parseInt(v) || 14, 8, 30) })
|
||||
}
|
||||
/>
|
||||
</HStack>
|
||||
<Select
|
||||
leftSlot={<Icon icon="keyboard" color="secondary" />}
|
||||
size="sm"
|
||||
name="editorKeymap"
|
||||
label="Editor Keymap"
|
||||
value={`${settings.editorKeymap}`}
|
||||
options={keymaps}
|
||||
onChange={(v) => patchModel(settings, { editorKeymap: v })}
|
||||
/>
|
||||
<Checkbox
|
||||
checked={settings.editorSoftWrap}
|
||||
title="Wrap Editor Lines"
|
||||
onChange={(editorSoftWrap) => patchModel(settings, { editorSoftWrap })}
|
||||
/>
|
||||
<Checkbox
|
||||
checked={settings.coloredMethods}
|
||||
title="Colorize Request Methods"
|
||||
onChange={(coloredMethods) => patchModel(settings, { coloredMethods })}
|
||||
/>
|
||||
|
||||
{type() !== 'macos' && (
|
||||
<Checkbox
|
||||
checked={settings.hideWindowControls}
|
||||
title="Hide Window Controls"
|
||||
help="Hide the close/maximize/minimize controls on Windows or Linux"
|
||||
onChange={(hideWindowControls) => patchModel(settings, { hideWindowControls })}
|
||||
/>
|
||||
)}
|
||||
</VStack>
|
||||
);
|
||||
}
|
||||
@@ -30,6 +30,7 @@ export function SettingsProxy() {
|
||||
http: '',
|
||||
https: '',
|
||||
auth: { user: '', password: '' },
|
||||
bypass: '',
|
||||
},
|
||||
});
|
||||
} else {
|
||||
@@ -53,10 +54,11 @@ export function SettingsProxy() {
|
||||
const { proxy } = settings;
|
||||
const http = proxy?.type === 'enabled' ? proxy.http : '';
|
||||
const https = proxy?.type === 'enabled' ? proxy.https : '';
|
||||
const bypass = proxy?.type === 'enabled' ? proxy.bypass : '';
|
||||
const auth = proxy?.type === 'enabled' ? proxy.auth : null;
|
||||
const disabled = !enabled;
|
||||
await patchModel(settings, {
|
||||
proxy: { type: 'enabled', http, https, auth, disabled },
|
||||
proxy: { type: 'enabled', http, https, auth, disabled, bypass },
|
||||
});
|
||||
}}
|
||||
/>
|
||||
@@ -73,6 +75,7 @@ export function SettingsProxy() {
|
||||
onChange={async (http) => {
|
||||
const { proxy } = settings;
|
||||
const https = proxy?.type === 'enabled' ? proxy.https : '';
|
||||
const bypass = proxy?.type === 'enabled' ? proxy.bypass : '';
|
||||
const auth = proxy?.type === 'enabled' ? proxy.auth : null;
|
||||
const disabled = proxy?.type === 'enabled' ? proxy.disabled : false;
|
||||
await patchModel(settings, {
|
||||
@@ -82,6 +85,7 @@ export function SettingsProxy() {
|
||||
https,
|
||||
auth,
|
||||
disabled,
|
||||
bypass,
|
||||
},
|
||||
});
|
||||
}}
|
||||
@@ -98,10 +102,11 @@ export function SettingsProxy() {
|
||||
onChange={async (https) => {
|
||||
const { proxy } = settings;
|
||||
const http = proxy?.type === 'enabled' ? proxy.http : '';
|
||||
const bypass = proxy?.type === 'enabled' ? proxy.bypass : '';
|
||||
const auth = proxy?.type === 'enabled' ? proxy.auth : null;
|
||||
const disabled = proxy?.type === 'enabled' ? proxy.disabled : false;
|
||||
await patchModel(settings, {
|
||||
proxy: { type: 'enabled', http, https, auth, disabled },
|
||||
proxy: { type: 'enabled', http, https, auth, disabled, bypass },
|
||||
});
|
||||
}}
|
||||
/>
|
||||
@@ -115,9 +120,10 @@ export function SettingsProxy() {
|
||||
const http = proxy?.type === 'enabled' ? proxy.http : '';
|
||||
const https = proxy?.type === 'enabled' ? proxy.https : '';
|
||||
const disabled = proxy?.type === 'enabled' ? proxy.disabled : false;
|
||||
const bypass = proxy?.type === 'enabled' ? proxy.bypass : '';
|
||||
const auth = enabled ? { user: '', password: '' } : null;
|
||||
await patchModel(settings, {
|
||||
proxy: { type: 'enabled', http, https, auth, disabled },
|
||||
proxy: { type: 'enabled', http, https, auth, disabled, bypass },
|
||||
});
|
||||
}}
|
||||
/>
|
||||
@@ -135,10 +141,11 @@ export function SettingsProxy() {
|
||||
const http = proxy?.type === 'enabled' ? proxy.http : '';
|
||||
const https = proxy?.type === 'enabled' ? proxy.https : '';
|
||||
const disabled = proxy?.type === 'enabled' ? proxy.disabled : false;
|
||||
const bypass = proxy?.type === 'enabled' ? proxy.bypass : '';
|
||||
const password = proxy?.type === 'enabled' ? (proxy.auth?.password ?? '') : '';
|
||||
const auth = { user, password };
|
||||
await patchModel(settings, {
|
||||
proxy: { type: 'enabled', http, https, auth, disabled },
|
||||
proxy: { type: 'enabled', http, https, auth, disabled, bypass },
|
||||
});
|
||||
}}
|
||||
/>
|
||||
@@ -153,15 +160,39 @@ export function SettingsProxy() {
|
||||
const http = proxy?.type === 'enabled' ? proxy.http : '';
|
||||
const https = proxy?.type === 'enabled' ? proxy.https : '';
|
||||
const disabled = proxy?.type === 'enabled' ? proxy.disabled : false;
|
||||
const bypass = proxy?.type === 'enabled' ? proxy.bypass : '';
|
||||
const user = proxy?.type === 'enabled' ? (proxy.auth?.user ?? '') : '';
|
||||
const auth = { user, password };
|
||||
await patchModel(settings, {
|
||||
proxy: { type: 'enabled', http, https, auth, disabled },
|
||||
proxy: { type: 'enabled', http, https, auth, disabled, bypass },
|
||||
});
|
||||
}}
|
||||
/>
|
||||
</HStack>
|
||||
)}
|
||||
{settings.proxy.type === 'enabled' && (
|
||||
<>
|
||||
<Separator className="my-6" />
|
||||
<PlainInput
|
||||
label="Proxy Bypass"
|
||||
help="Comma-separated list to bypass the proxy."
|
||||
defaultValue={settings.proxy.bypass}
|
||||
placeholder="127.0.0.1, *.example.com, localhost:3000"
|
||||
onChange={async (bypass) => {
|
||||
const { proxy } = settings;
|
||||
const http = proxy?.type === 'enabled' ? proxy.http : '';
|
||||
const https = proxy?.type === 'enabled' ? proxy.https : '';
|
||||
const disabled = proxy?.type === 'enabled' ? proxy.disabled : false;
|
||||
const user = proxy?.type === 'enabled' ? (proxy.auth?.user ?? '') : '';
|
||||
const password = proxy?.type === 'enabled' ? (proxy.auth?.password ?? '') : '';
|
||||
const auth = { user, password };
|
||||
await patchModel(settings, {
|
||||
proxy: { type: 'enabled', http, https, auth, disabled, bypass },
|
||||
});
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</VStack>
|
||||
)}
|
||||
</VStack>
|
||||
|
||||
@@ -1,35 +1,19 @@
|
||||
import type { EditorKeymap } from '@yaakapp-internal/models';
|
||||
import { patchModel, settingsAtom } from '@yaakapp-internal/models';
|
||||
import { useAtomValue } from 'jotai';
|
||||
import React from 'react';
|
||||
import { activeWorkspaceAtom } from '../../hooks/useActiveWorkspace';
|
||||
import { useResolvedAppearance } from '../../hooks/useResolvedAppearance';
|
||||
import { useResolvedTheme } from '../../hooks/useResolvedTheme';
|
||||
import { clamp } from '../../lib/clamp';
|
||||
import { getThemes } from '../../lib/theme/themes';
|
||||
import { isThemeDark } from '../../lib/theme/window';
|
||||
import type { ButtonProps } from '../core/Button';
|
||||
import { Checkbox } from '../core/Checkbox';
|
||||
import { Editor } from '../core/Editor/Editor';
|
||||
import type { IconProps } from '../core/Icon';
|
||||
import { Icon } from '../core/Icon';
|
||||
import { IconButton } from '../core/IconButton';
|
||||
import type { SelectProps } from '../core/Select';
|
||||
import { Select } from '../core/Select';
|
||||
import { Separator } from '../core/Separator';
|
||||
import type { SelectProps } from '../core/Select';
|
||||
import { HStack, VStack } from '../core/Stacks';
|
||||
import { type } from '@tauri-apps/plugin-os';
|
||||
|
||||
const fontSizeOptions = [
|
||||
8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30,
|
||||
].map((n) => ({ label: `${n}`, value: `${n}` }));
|
||||
|
||||
const keymaps: { value: EditorKeymap; label: string }[] = [
|
||||
{ value: 'default', label: 'Default' },
|
||||
{ value: 'vim', label: 'Vim' },
|
||||
{ value: 'vscode', label: 'VSCode' },
|
||||
{ value: 'emacs', label: 'Emacs' },
|
||||
];
|
||||
|
||||
const buttonColors: ButtonProps['color'][] = [
|
||||
'primary',
|
||||
@@ -62,7 +46,7 @@ const icons: IconProps['icon'][] = [
|
||||
|
||||
const { themes } = getThemes();
|
||||
|
||||
export function SettingsAppearance() {
|
||||
export function SettingsTheme() {
|
||||
const workspace = useAtomValue(activeWorkspaceAtom);
|
||||
const settings = useAtomValue(settingsAtom);
|
||||
const appearance = useResolvedAppearance();
|
||||
@@ -87,58 +71,7 @@ export function SettingsAppearance() {
|
||||
}));
|
||||
|
||||
return (
|
||||
<VStack space={2} className="mb-4">
|
||||
<Select
|
||||
size="sm"
|
||||
name="interfaceFontSize"
|
||||
label="Font Size"
|
||||
labelPosition="left"
|
||||
defaultValue="15"
|
||||
value={`${settings.interfaceFontSize}`}
|
||||
options={fontSizeOptions}
|
||||
onChange={(v) => patchModel(settings, { interfaceFontSize: parseInt(v) })}
|
||||
/>
|
||||
<Select
|
||||
size="sm"
|
||||
name="editorFontSize"
|
||||
label="Editor Font Size"
|
||||
labelPosition="left"
|
||||
defaultValue="13"
|
||||
value={`${settings.editorFontSize}`}
|
||||
options={fontSizeOptions}
|
||||
onChange={(v) => patchModel(settings, { editorFontSize: clamp(parseInt(v) || 14, 8, 30) })}
|
||||
/>
|
||||
<Select
|
||||
size="sm"
|
||||
name="editorKeymap"
|
||||
label="Editor Keymap"
|
||||
labelPosition="left"
|
||||
value={`${settings.editorKeymap}`}
|
||||
options={keymaps}
|
||||
onChange={(v) => patchModel(settings, { editorKeymap: v })}
|
||||
/>
|
||||
<Checkbox
|
||||
checked={settings.editorSoftWrap}
|
||||
title="Wrap Editor Lines"
|
||||
onChange={(editorSoftWrap) => patchModel(settings, { editorSoftWrap })}
|
||||
/>
|
||||
<Checkbox
|
||||
checked={settings.coloredMethods}
|
||||
title="Colorize Request Methods"
|
||||
onChange={(coloredMethods) => patchModel(settings, { coloredMethods })}
|
||||
/>
|
||||
|
||||
{type() !== 'macos' && (
|
||||
<Checkbox
|
||||
checked={settings.hideWindowControls}
|
||||
title="Hide Window Controls"
|
||||
help="Hide the close/maximize/minimize controls on Windows or Linux"
|
||||
onChange={(hideWindowControls) => patchModel(settings, { hideWindowControls })}
|
||||
/>
|
||||
)}
|
||||
|
||||
<Separator className="my-4" />
|
||||
|
||||
<VStack space={3} className="mb-4">
|
||||
<Select
|
||||
name="appearance"
|
||||
label="Appearance"
|
||||
@@ -156,7 +89,7 @@ export function SettingsAppearance() {
|
||||
{(settings.appearance === 'system' || settings.appearance === 'light') && (
|
||||
<Select
|
||||
hideLabel
|
||||
leftSlot={<Icon icon="sun" />}
|
||||
leftSlot={<Icon icon="sun" color="secondary" />}
|
||||
name="lightTheme"
|
||||
label="Light Theme"
|
||||
size="sm"
|
||||
@@ -172,7 +105,7 @@ export function SettingsAppearance() {
|
||||
name="darkTheme"
|
||||
className="flex-1"
|
||||
label="Dark Theme"
|
||||
leftSlot={<Icon icon="moon" />}
|
||||
leftSlot={<Icon icon="moon" color="secondary" />}
|
||||
size="sm"
|
||||
value={activeTheme.dark.id}
|
||||
options={darkThemes}
|
||||
@@ -119,7 +119,7 @@ export function Workspace() {
|
||||
if (activeEnvironment?.color == null) return undefined;
|
||||
const background = `linear-gradient(to right, ${activeEnvironment.color} 15%, transparent 40%)`;
|
||||
return { background };
|
||||
}, [activeEnvironment?.color ?? 'n/a']);
|
||||
}, [activeEnvironment?.color]);
|
||||
|
||||
// We're loading still
|
||||
if (workspaces.length === 0) {
|
||||
|
||||
19
src-web/font.ts
Normal file
19
src-web/font.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
// Listen for settings changes, the re-compute theme
|
||||
import { listen } from '@tauri-apps/api/event';
|
||||
import type { ModelPayload, Settings } from '@yaakapp-internal/models';
|
||||
import { getSettings } from './lib/settings';
|
||||
|
||||
function setFonts(settings: Settings) {
|
||||
document.documentElement.style.setProperty('--font-family-editor', settings.editorFont ?? '');
|
||||
document.documentElement.style.setProperty(
|
||||
'--font-family-interface',
|
||||
settings.interfaceFont ?? '',
|
||||
);
|
||||
}
|
||||
|
||||
listen<ModelPayload>('upserted_model', async (event) => {
|
||||
if (event.payload.model.model !== 'settings') return;
|
||||
setFonts(event.payload.model);
|
||||
}).catch(console.error);
|
||||
|
||||
getSettings().then((settings) => setFonts(settings));
|
||||
@@ -28,6 +28,7 @@
|
||||
<div id="radix-portal" class="cm-portal"></div>
|
||||
<script type="module" src="/theme.ts"></script>
|
||||
<script type="module" src="/font-size.ts"></script>
|
||||
<script type="module" src="/font.ts"></script>
|
||||
<script type="module" src="/main.tsx"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -9,6 +9,12 @@
|
||||
@apply w-full h-full overflow-hidden text-text bg-surface;
|
||||
}
|
||||
|
||||
:root {
|
||||
/* Must default these variables or the default will break */
|
||||
--font-family-interface: '';
|
||||
--font-family-editor: '';
|
||||
}
|
||||
|
||||
/* Never show ligatures */
|
||||
:root {
|
||||
font-variant-ligatures: none;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { QueryClientProvider } from '@tanstack/react-query';
|
||||
import { createRootRoute, Outlet } from '@tanstack/react-router';
|
||||
import { type } from '@tauri-apps/plugin-os';
|
||||
import classNames from 'classnames';
|
||||
import { Provider as JotaiProvider } from 'jotai';
|
||||
import { domAnimation, LazyMotion, MotionConfig } from 'motion/react';
|
||||
@@ -13,7 +14,6 @@ import RouteError from '../components/RouteError';
|
||||
import { Toasts } from '../components/Toasts';
|
||||
import { jotaiStore } from '../lib/jotai';
|
||||
import { queryClient } from '../lib/queryClient';
|
||||
import { type } from '@tauri-apps/plugin-os';
|
||||
|
||||
export const Route = createRootRoute({
|
||||
component: RouteComponent,
|
||||
@@ -32,14 +32,7 @@ function RouteComponent() {
|
||||
<GlobalHooks />
|
||||
<Toasts />
|
||||
<Dialogs />
|
||||
<div
|
||||
className={classNames(
|
||||
'w-full h-full',
|
||||
type() === 'linux' && 'border border-border-subtle',
|
||||
)}
|
||||
>
|
||||
<Outlet />
|
||||
</div>
|
||||
<Layout />
|
||||
</Suspense>
|
||||
</DndProvider>
|
||||
</HelmetProvider>
|
||||
@@ -49,3 +42,13 @@ function RouteComponent() {
|
||||
</JotaiProvider>
|
||||
);
|
||||
}
|
||||
|
||||
function Layout() {
|
||||
return (
|
||||
<div
|
||||
className={classNames('w-full h-full', type() === 'linux' && 'border border-border-subtle')}
|
||||
>
|
||||
<Outlet />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ const sizes = {
|
||||
md: '2.3rem',
|
||||
};
|
||||
|
||||
/** @type {import("tailwindcss").Config} */
|
||||
/** @type {import('tailwindcss').Config} */
|
||||
module.exports = {
|
||||
darkMode: ['class', '[data-resolved-appearance="dark"]'],
|
||||
content: [
|
||||
@@ -43,6 +43,7 @@ module.exports = {
|
||||
},
|
||||
fontFamily: {
|
||||
mono: [
|
||||
'var(--font-family-editor)',
|
||||
'JetBrains Mono',
|
||||
'ui-monospace',
|
||||
'SFMono-Regular',
|
||||
@@ -58,6 +59,7 @@ module.exports = {
|
||||
'monospace',
|
||||
],
|
||||
sans: [
|
||||
'var(--font-family-interface)',
|
||||
'Inter UI',
|
||||
'-apple-system',
|
||||
'BlinkMacSystemFont',
|
||||
|
||||
Reference in New Issue
Block a user