finally another commit
This commit is contained in:
Generated
+667
-2
@@ -112,6 +112,15 @@ dependencies = [
|
||||
"winit",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "addr2line"
|
||||
version = "0.24.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1"
|
||||
dependencies = [
|
||||
"gimli",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "adler2"
|
||||
version = "2.0.1"
|
||||
@@ -462,6 +471,27 @@ dependencies = [
|
||||
"arrayvec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "backtrace"
|
||||
version = "0.3.75"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6806a6321ec58106fea15becdad98371e28d92ccbc7c8f1b3b6dd724fe8f1002"
|
||||
dependencies = [
|
||||
"addr2line",
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"miniz_oxide",
|
||||
"object",
|
||||
"rustc-demangle",
|
||||
"windows-targets 0.52.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "base64"
|
||||
version = "0.22.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
|
||||
|
||||
[[package]]
|
||||
name = "bit-set"
|
||||
version = "0.8.0"
|
||||
@@ -739,7 +769,7 @@ dependencies = [
|
||||
"bitflags 1.3.2",
|
||||
"core-foundation 0.9.4",
|
||||
"core-graphics-types",
|
||||
"foreign-types",
|
||||
"foreign-types 0.5.0",
|
||||
"libc",
|
||||
]
|
||||
|
||||
@@ -1067,6 +1097,15 @@ dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "encoding_rs"
|
||||
version = "0.8.35"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "endi"
|
||||
version = "1.1.0"
|
||||
@@ -1253,12 +1292,27 @@ dependencies = [
|
||||
"miniz_oxide",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fnv"
|
||||
version = "1.0.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
|
||||
|
||||
[[package]]
|
||||
name = "foldhash"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2"
|
||||
|
||||
[[package]]
|
||||
name = "foreign-types"
|
||||
version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1"
|
||||
dependencies = [
|
||||
"foreign-types-shared 0.1.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "foreign-types"
|
||||
version = "0.5.0"
|
||||
@@ -1266,7 +1320,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d737d9aa519fb7b749cbc3b962edcf310a8dd1f4b67c91c4f83975dbdd17d965"
|
||||
dependencies = [
|
||||
"foreign-types-macros",
|
||||
"foreign-types-shared",
|
||||
"foreign-types-shared 0.3.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1280,6 +1334,12 @@ dependencies = [
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "foreign-types-shared"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
|
||||
|
||||
[[package]]
|
||||
name = "foreign-types-shared"
|
||||
version = "0.3.1"
|
||||
@@ -1295,6 +1355,16 @@ dependencies = [
|
||||
"percent-encoding",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-channel"
|
||||
version = "0.3.31"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"futures-sink",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-core"
|
||||
version = "0.3.31"
|
||||
@@ -1331,6 +1401,12 @@ dependencies = [
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-sink"
|
||||
version = "0.3.31"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7"
|
||||
|
||||
[[package]]
|
||||
name = "futures-task"
|
||||
version = "0.3.31"
|
||||
@@ -1344,8 +1420,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"futures-io",
|
||||
"futures-macro",
|
||||
"futures-sink",
|
||||
"futures-task",
|
||||
"memchr",
|
||||
"pin-project-lite",
|
||||
"pin-utils",
|
||||
"slab",
|
||||
@@ -1394,6 +1473,12 @@ dependencies = [
|
||||
"weezl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gimli"
|
||||
version = "0.31.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f"
|
||||
|
||||
[[package]]
|
||||
name = "gl_generator"
|
||||
version = "0.14.0"
|
||||
@@ -1483,6 +1568,25 @@ dependencies = [
|
||||
"gl_generator",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "h2"
|
||||
version = "0.4.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "17da50a276f1e01e0ba6c029e47b7100754904ee8a278f886546e98575380785"
|
||||
dependencies = [
|
||||
"atomic-waker",
|
||||
"bytes",
|
||||
"fnv",
|
||||
"futures-core",
|
||||
"futures-sink",
|
||||
"http",
|
||||
"indexmap",
|
||||
"slab",
|
||||
"tokio",
|
||||
"tokio-util",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "half"
|
||||
version = "2.6.0"
|
||||
@@ -1527,6 +1631,124 @@ version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dfa686283ad6dd069f105e5ab091b04c62850d3e4cf5d67debad1933f55023df"
|
||||
|
||||
[[package]]
|
||||
name = "http"
|
||||
version = "1.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f4a85d31aea989eead29a3aaf9e1115a180df8282431156e533de47660892565"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"fnv",
|
||||
"itoa",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "http-body"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"http",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "http-body-util"
|
||||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"futures-core",
|
||||
"http",
|
||||
"http-body",
|
||||
"pin-project-lite",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "httparse"
|
||||
version = "1.10.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87"
|
||||
|
||||
[[package]]
|
||||
name = "hyper"
|
||||
version = "1.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cc2b571658e38e0c01b1fdca3bbbe93c00d3d71693ff2770043f8c29bc7d6f80"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"futures-channel",
|
||||
"futures-util",
|
||||
"h2",
|
||||
"http",
|
||||
"http-body",
|
||||
"httparse",
|
||||
"itoa",
|
||||
"pin-project-lite",
|
||||
"smallvec",
|
||||
"tokio",
|
||||
"want",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hyper-rustls"
|
||||
version = "0.27.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e3c93eb611681b207e1fe55d5a71ecf91572ec8a6705cdb6857f7d8d5242cf58"
|
||||
dependencies = [
|
||||
"http",
|
||||
"hyper",
|
||||
"hyper-util",
|
||||
"rustls",
|
||||
"rustls-pki-types",
|
||||
"tokio",
|
||||
"tokio-rustls",
|
||||
"tower-service",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hyper-tls"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"http-body-util",
|
||||
"hyper",
|
||||
"hyper-util",
|
||||
"native-tls",
|
||||
"tokio",
|
||||
"tokio-native-tls",
|
||||
"tower-service",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hyper-util"
|
||||
version = "0.1.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8d9b05277c7e8da2c93a568989bb6207bef0112e8d17df7a6eda4a3cf143bc5e"
|
||||
dependencies = [
|
||||
"base64",
|
||||
"bytes",
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
"futures-util",
|
||||
"http",
|
||||
"http-body",
|
||||
"hyper",
|
||||
"ipnet",
|
||||
"libc",
|
||||
"percent-encoding",
|
||||
"pin-project-lite",
|
||||
"socket2 0.6.0",
|
||||
"system-configuration",
|
||||
"tokio",
|
||||
"tower-service",
|
||||
"tracing",
|
||||
"windows-registry",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "iana-time-zone"
|
||||
version = "0.1.63"
|
||||
@@ -1718,6 +1940,33 @@ dependencies = [
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "io-uring"
|
||||
version = "0.7.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d93587f37623a1a17d94ef2bc9ada592f5465fe7732084ab7beefabe5c77c0c4"
|
||||
dependencies = [
|
||||
"bitflags 2.9.1",
|
||||
"cfg-if",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ipnet"
|
||||
version = "2.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130"
|
||||
|
||||
[[package]]
|
||||
name = "iri-string"
|
||||
version = "0.7.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dbc5ebe9c3a1a7a5127f920a418f7585e9e758e911d0466ed004f393b0e380b2"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itertools"
|
||||
version = "0.12.1"
|
||||
@@ -1953,6 +2202,17 @@ dependencies = [
|
||||
"simd-adler32",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mio"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "78bed444cc8a2160f01cbcf811ef18cac863ad68ae8ca62092e8db51d51c761c"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"wasi 0.11.1+wasi-snapshot-preview1",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "naga"
|
||||
version = "25.0.1"
|
||||
@@ -1977,6 +2237,23 @@ dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "native-tls"
|
||||
version = "0.2.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "87de3442987e9dbec73158d5c715e7ad9072fda936bb03d19d7fa10e00520f0e"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"log",
|
||||
"openssl",
|
||||
"openssl-probe",
|
||||
"openssl-sys",
|
||||
"schannel",
|
||||
"security-framework",
|
||||
"security-framework-sys",
|
||||
"tempfile",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ndk"
|
||||
version = "0.9.0"
|
||||
@@ -2392,12 +2669,65 @@ dependencies = [
|
||||
"objc2-foundation 0.2.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "object"
|
||||
version = "0.36.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.21.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
|
||||
|
||||
[[package]]
|
||||
name = "openssl"
|
||||
version = "0.10.73"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8505734d46c8ab1e19a1dce3aef597ad87dcb4c37e7188231769bd6bd51cebf8"
|
||||
dependencies = [
|
||||
"bitflags 2.9.1",
|
||||
"cfg-if",
|
||||
"foreign-types 0.3.2",
|
||||
"libc",
|
||||
"once_cell",
|
||||
"openssl-macros",
|
||||
"openssl-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "openssl-macros"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "openssl-probe"
|
||||
version = "0.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e"
|
||||
|
||||
[[package]]
|
||||
name = "openssl-sys"
|
||||
version = "0.9.109"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "90096e2e47630d78b7d1c20952dc621f957103f8bc2c8359ec81290d75238571"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"libc",
|
||||
"pkg-config",
|
||||
"vcpkg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "orbclient"
|
||||
version = "0.3.48"
|
||||
@@ -2839,12 +3169,74 @@ version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "19b30a45b0cd0bcca8037f3d0dc3421eaf95327a17cad11964fb8179b4fc4832"
|
||||
|
||||
[[package]]
|
||||
name = "reqwest"
|
||||
version = "0.12.22"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cbc931937e6ca3a06e3b6c0aa7841849b160a90351d6ab467a8b9b9959767531"
|
||||
dependencies = [
|
||||
"base64",
|
||||
"bytes",
|
||||
"encoding_rs",
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
"futures-util",
|
||||
"h2",
|
||||
"http",
|
||||
"http-body",
|
||||
"http-body-util",
|
||||
"hyper",
|
||||
"hyper-rustls",
|
||||
"hyper-tls",
|
||||
"hyper-util",
|
||||
"js-sys",
|
||||
"log",
|
||||
"mime",
|
||||
"native-tls",
|
||||
"percent-encoding",
|
||||
"pin-project-lite",
|
||||
"rustls-pki-types",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serde_urlencoded",
|
||||
"sync_wrapper",
|
||||
"tokio",
|
||||
"tokio-native-tls",
|
||||
"tower",
|
||||
"tower-http",
|
||||
"tower-service",
|
||||
"url",
|
||||
"wasm-bindgen",
|
||||
"wasm-bindgen-futures",
|
||||
"web-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rgb"
|
||||
version = "0.8.51"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a457e416a0f90d246a4c3288bd7a25b2304ca727f253f95be383dd17af56be8f"
|
||||
|
||||
[[package]]
|
||||
name = "ring"
|
||||
version = "0.17.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"cfg-if",
|
||||
"getrandom 0.2.16",
|
||||
"libc",
|
||||
"untrusted",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc-demangle"
|
||||
version = "0.1.25"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "989e6739f80c4ad5b13e0fd7fe89531180375b18520cc8c82080e4dc4035b84f"
|
||||
|
||||
[[package]]
|
||||
name = "rustc-hash"
|
||||
version = "1.1.0"
|
||||
@@ -2883,6 +3275,39 @@ dependencies = [
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustls"
|
||||
version = "0.23.29"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2491382039b29b9b11ff08b76ff6c97cf287671dbb74f0be44bda389fffe9bd1"
|
||||
dependencies = [
|
||||
"once_cell",
|
||||
"rustls-pki-types",
|
||||
"rustls-webpki",
|
||||
"subtle",
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustls-pki-types"
|
||||
version = "1.12.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "229a4a4c221013e7e1f1a043678c5cc39fe5171437c88fb47151a21e6f5b5c79"
|
||||
dependencies = [
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustls-webpki"
|
||||
version = "0.103.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0a17884ae0c1b773f1ccd2bd4a8c72f16da897310a98b0e84bf349ad5ead92fc"
|
||||
dependencies = [
|
||||
"ring",
|
||||
"rustls-pki-types",
|
||||
"untrusted",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustversion"
|
||||
version = "1.0.21"
|
||||
@@ -2904,6 +3329,15 @@ dependencies = [
|
||||
"winapi-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "schannel"
|
||||
version = "0.1.27"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1f29ebaa345f945cec9fbbc532eb307f0fdad8161f281b6369539c8d84876b3d"
|
||||
dependencies = [
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "scoped-tls"
|
||||
version = "1.0.1"
|
||||
@@ -2929,6 +3363,29 @@ dependencies = [
|
||||
"tiny-skia",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "security-framework"
|
||||
version = "2.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02"
|
||||
dependencies = [
|
||||
"bitflags 2.9.1",
|
||||
"core-foundation 0.9.4",
|
||||
"core-foundation-sys",
|
||||
"libc",
|
||||
"security-framework-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "security-framework-sys"
|
||||
version = "2.14.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "49db231d56a190491cb4aeda9527f1ad45345af50b0851622a7adb8c03b01c32"
|
||||
dependencies = [
|
||||
"core-foundation-sys",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.219"
|
||||
@@ -2981,6 +3438,18 @@ dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_urlencoded"
|
||||
version = "0.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd"
|
||||
dependencies = [
|
||||
"form_urlencoded",
|
||||
"itoa",
|
||||
"ryu",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "shlex"
|
||||
version = "1.3.0"
|
||||
@@ -3083,6 +3552,26 @@ dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "socket2"
|
||||
version = "0.5.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e22376abed350d73dd1cd119b57ffccad95b4e585a7cda43e286245ce23c0678"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "socket2"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "233504af464074f9d066d7b5416c5f9b894a5862a6506e306f7b816cdd6f1807"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "somewhatusefultool"
|
||||
version = "0.1.0"
|
||||
@@ -3095,6 +3584,7 @@ dependencies = [
|
||||
"egui_extras",
|
||||
"egui_file",
|
||||
"image",
|
||||
"reqwest",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"thiserror 2.0.12",
|
||||
@@ -3142,6 +3632,12 @@ dependencies = [
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "subtle"
|
||||
version = "2.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.104"
|
||||
@@ -3153,6 +3649,15 @@ dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sync_wrapper"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "synstructure"
|
||||
version = "0.13.2"
|
||||
@@ -3164,6 +3669,27 @@ dependencies = [
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "system-configuration"
|
||||
version = "0.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b"
|
||||
dependencies = [
|
||||
"bitflags 2.9.1",
|
||||
"core-foundation 0.9.4",
|
||||
"system-configuration-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "system-configuration-sys"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8e1d1b10ced5ca923a1fcb8d03e96b8d3268065d724548c0211415ff6ac6bac4"
|
||||
dependencies = [
|
||||
"core-foundation-sys",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "system-deps"
|
||||
version = "6.2.2"
|
||||
@@ -3291,6 +3817,56 @@ dependencies = [
|
||||
"zerovec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio"
|
||||
version = "1.46.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0cc3a2344dafbe23a245241fe8b09735b521110d30fcefbbd5feb1797ca35d17"
|
||||
dependencies = [
|
||||
"backtrace",
|
||||
"bytes",
|
||||
"io-uring",
|
||||
"libc",
|
||||
"mio",
|
||||
"pin-project-lite",
|
||||
"slab",
|
||||
"socket2 0.5.10",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-native-tls"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2"
|
||||
dependencies = [
|
||||
"native-tls",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-rustls"
|
||||
version = "0.26.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8e727b36a1a0e8b74c376ac2211e40c2c8af09fb4013c60d910495810f008e9b"
|
||||
dependencies = [
|
||||
"rustls",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-util"
|
||||
version = "0.7.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "66a539a9ad6d5d281510d5bd368c973d636c02dbf8a67300bfb6b950696ad7df"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"futures-core",
|
||||
"futures-sink",
|
||||
"pin-project-lite",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml"
|
||||
version = "0.8.23"
|
||||
@@ -3325,6 +3901,51 @@ dependencies = [
|
||||
"winnow",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tower"
|
||||
version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"futures-util",
|
||||
"pin-project-lite",
|
||||
"sync_wrapper",
|
||||
"tokio",
|
||||
"tower-layer",
|
||||
"tower-service",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tower-http"
|
||||
version = "0.6.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "adc82fd73de2a9722ac5da747f12383d2bfdb93591ee6c58486e0097890f05f2"
|
||||
dependencies = [
|
||||
"bitflags 2.9.1",
|
||||
"bytes",
|
||||
"futures-util",
|
||||
"http",
|
||||
"http-body",
|
||||
"iri-string",
|
||||
"pin-project-lite",
|
||||
"tower",
|
||||
"tower-layer",
|
||||
"tower-service",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tower-layer"
|
||||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e"
|
||||
|
||||
[[package]]
|
||||
name = "tower-service"
|
||||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3"
|
||||
|
||||
[[package]]
|
||||
name = "tracing"
|
||||
version = "0.1.41"
|
||||
@@ -3356,6 +3977,12 @@ dependencies = [
|
||||
"once_cell",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "try-lock"
|
||||
version = "0.2.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b"
|
||||
|
||||
[[package]]
|
||||
name = "ttf-parser"
|
||||
version = "0.25.1"
|
||||
@@ -3406,6 +4033,12 @@ version = "0.1.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af"
|
||||
|
||||
[[package]]
|
||||
name = "untrusted"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1"
|
||||
|
||||
[[package]]
|
||||
name = "url"
|
||||
version = "2.5.4"
|
||||
@@ -3445,6 +4078,12 @@ dependencies = [
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "vcpkg"
|
||||
version = "0.2.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
|
||||
|
||||
[[package]]
|
||||
name = "version-compare"
|
||||
version = "0.2.0"
|
||||
@@ -3467,6 +4106,15 @@ dependencies = [
|
||||
"winapi-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "want"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e"
|
||||
dependencies = [
|
||||
"try-lock",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasi"
|
||||
version = "0.11.1+wasi-snapshot-preview1"
|
||||
@@ -3916,6 +4564,17 @@ dependencies = [
|
||||
"windows-link",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-registry"
|
||||
version = "0.5.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5b8a9ed28765efc97bbc954883f4e6796c33a06546ebafacbabee9696967499e"
|
||||
dependencies = [
|
||||
"windows-link",
|
||||
"windows-result",
|
||||
"windows-strings",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-result"
|
||||
version = "0.3.4"
|
||||
@@ -4522,6 +5181,12 @@ dependencies = [
|
||||
"synstructure",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zeroize"
|
||||
version = "1.8.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde"
|
||||
|
||||
[[package]]
|
||||
name = "zerotrie"
|
||||
version = "0.2.2"
|
||||
|
||||
@@ -22,6 +22,7 @@ thiserror = "2.0.12"
|
||||
egui_commonmark = { version = "0.21.1", features = ["embedded_image"] }
|
||||
walkdir = "2.5.0"
|
||||
uuid = { version = "1.17.0", features = ["v4"] }
|
||||
reqwest = { version = "0.12.22", features = ["blocking", "json"] }
|
||||
|
||||
|
||||
[target.x86_64-pc-windows-gnu]
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 1.5 MiB |
Binary file not shown.
|
After Width: | Height: | Size: 20 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 254 KiB |
|
Before Width: | Height: | Size: 145 KiB After Width: | Height: | Size: 145 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 157 KiB |
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"date": "2025-07-17",
|
||||
"project_name": "New Project",
|
||||
"project_author": "Your Name",
|
||||
"project_description": "Description of your project"
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"title": "test",
|
||||
"id": "83592caa-f97d-427e-9d6a-50a586c30e6e",
|
||||
"description": "ee",
|
||||
"tags": [],
|
||||
"content": "# Test project\n\n- this project is a test to ensure that this tool can be integrated with AI models correctly\n- I’m testing various prompts and parameters to evaluate its capabilities. The initial focus is on simple tasks like list generation, text summarization, and question answering. More complex scenarios involving code generation and creative writing will follow in subsequent phases. A key aspect of this test project involves documenting all interactions – both the prompts used and the AI’s responses – for later analysis. This allows us to identify patterns, biases, and areas where the tool can be improved. ",
|
||||
"parent": null
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"id": "161227ef-ba29-41a7-b40a-ed4ac550a8ea",
|
||||
"template_id": "69cf7e1d-96a1-4d2a-9f08-bd3386d4bc69",
|
||||
"name": "nucleus",
|
||||
"fields": {
|
||||
"age": {
|
||||
"Number": 0.0
|
||||
},
|
||||
"parent": {
|
||||
"Link": ""
|
||||
},
|
||||
"dob": {
|
||||
"Date": "1970-01-01"
|
||||
},
|
||||
"pfp": {
|
||||
"Image": "characters/nucleus.png"
|
||||
},
|
||||
"description": {
|
||||
"MultiLine": "an AI"
|
||||
}
|
||||
},
|
||||
"tags": []
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"id": "3ce0e977-9f65-4f4c-a036-67f3d5c25fdc",
|
||||
"template_id": "69cf7e1d-96a1-4d2a-9f08-bd3386d4bc69",
|
||||
"name": "ZXQ5",
|
||||
"fields": {
|
||||
"dob": {
|
||||
"Date": "1970-01-01"
|
||||
},
|
||||
"description": {
|
||||
"MultiLine": "yes"
|
||||
},
|
||||
"age": {
|
||||
"Number": 19.1
|
||||
},
|
||||
"parent": {
|
||||
"Link": ""
|
||||
},
|
||||
"pfp": {
|
||||
"Image": "characters/zxq5.png"
|
||||
}
|
||||
},
|
||||
"tags": []
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"id": "57429207-5fc1-4bab-a524-c550773c3d45",
|
||||
"template_id": "69cf7e1d-96a1-4d2a-9f08-bd3386d4bc69",
|
||||
"name": "Tayles",
|
||||
"fields": {
|
||||
"pfp": {
|
||||
"Image": "characters/tayles.png"
|
||||
},
|
||||
"parent": {
|
||||
"Link": ""
|
||||
},
|
||||
"description": {
|
||||
"MultiLine": "trainspotter"
|
||||
},
|
||||
"age": {
|
||||
"Number": 17.5
|
||||
},
|
||||
"dob": {
|
||||
"Date": "1970-01-01"
|
||||
}
|
||||
},
|
||||
"tags": []
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
{
|
||||
"id": "8d76fdcd-0c3e-41a9-abc4-66fe21c0cb73",
|
||||
"template_id": "d1223e6b-ade0-405a-8c3b-657c743a21cc",
|
||||
"name": "Prophet",
|
||||
"fields": {
|
||||
"Age": {
|
||||
"value": ""
|
||||
},
|
||||
"Appearance": {
|
||||
"value": ""
|
||||
},
|
||||
"Species": {
|
||||
"value": ""
|
||||
},
|
||||
"DOB": {
|
||||
"value": ""
|
||||
},
|
||||
"PFP": {
|
||||
"value": "./project/assets/the prophet.png"
|
||||
}
|
||||
},
|
||||
"tags": []
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
{
|
||||
"id": "be24e58f-3f79-4c5a-9224-9037eea5f51f",
|
||||
"template_id": "69cf7e1d-96a1-4d2a-9f08-bd3386d4bc69",
|
||||
"name": "The Order",
|
||||
"fields": {
|
||||
"pfp": {
|
||||
"Image": "characters/the order.png"
|
||||
},
|
||||
"description": {
|
||||
"MultiLine": "yes"
|
||||
},
|
||||
"dob": {
|
||||
"Date": "1970-01-29"
|
||||
},
|
||||
"parent": {
|
||||
"Link": ""
|
||||
},
|
||||
"age": {
|
||||
"Number": 20.6
|
||||
}
|
||||
},
|
||||
"tags": [
|
||||
"bbeddabd-914c-4648-8262-bf14bfcf8fff"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
{
|
||||
"id": "deeaee92-bdec-4eb3-bb3b-ee760fc83d45",
|
||||
"template_id": "69cf7e1d-96a1-4d2a-9f08-bd3386d4bc69",
|
||||
"name": "The Chancellor",
|
||||
"fields": {
|
||||
"age": {
|
||||
"Number": 37.0
|
||||
},
|
||||
"parent": {
|
||||
"Link": ""
|
||||
},
|
||||
"dob": {
|
||||
"Date": "1970-01-01"
|
||||
},
|
||||
"description": {
|
||||
"MultiLine": "a tall ahh american"
|
||||
},
|
||||
"pfp": {
|
||||
"Image": "characters/the chancellor.jpg"
|
||||
}
|
||||
},
|
||||
"tags": [
|
||||
"bbeddabd-914c-4648-8262-bf14bfcf8fff"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"id": "bbeddabd-914c-4648-8262-bf14bfcf8fff",
|
||||
"name": "American",
|
||||
"description": "an american smh",
|
||||
"color": [
|
||||
0,
|
||||
32,
|
||||
207,
|
||||
255
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
{
|
||||
"name": "Species",
|
||||
"id": "353649f9-e1f3-46d9-b723-8e56b510b2cc",
|
||||
"description": "A classification system for living or digital entities.",
|
||||
"fields": [
|
||||
{
|
||||
"name": "Diverged from",
|
||||
"field_type": {
|
||||
"Link": {
|
||||
"template_id": null
|
||||
}
|
||||
},
|
||||
"required": false,
|
||||
"on_preview": false,
|
||||
"description": "did this diverge from another documented species?"
|
||||
},
|
||||
{
|
||||
"name": "Appearance / Features",
|
||||
"field_type": "MultiLine",
|
||||
"required": true,
|
||||
"on_preview": true,
|
||||
"description": "anatomy etc."
|
||||
},
|
||||
{
|
||||
"name": "behaviour",
|
||||
"field_type": "MultiLine",
|
||||
"required": true,
|
||||
"on_preview": true,
|
||||
"description": "aggressive, collaborative, etc.."
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
{
|
||||
"name": "Character",
|
||||
"id": "69cf7e1d-96a1-4d2a-9f08-bd3386d4bc69",
|
||||
"description": "a character",
|
||||
"fields": [
|
||||
{
|
||||
"name": "description",
|
||||
"field_type": "MultiLine",
|
||||
"required": true,
|
||||
"on_preview": true,
|
||||
"description": "yes"
|
||||
},
|
||||
{
|
||||
"name": "age",
|
||||
"field_type": "Number",
|
||||
"required": true,
|
||||
"on_preview": false,
|
||||
"description": "yes"
|
||||
},
|
||||
{
|
||||
"name": "dob",
|
||||
"field_type": "Date",
|
||||
"required": true,
|
||||
"on_preview": false,
|
||||
"description": "yes"
|
||||
},
|
||||
{
|
||||
"name": "parent",
|
||||
"field_type": {
|
||||
"Link": {
|
||||
"template_id": null
|
||||
}
|
||||
},
|
||||
"required": true,
|
||||
"on_preview": false,
|
||||
"description": "yes"
|
||||
},
|
||||
{
|
||||
"name": "pfp",
|
||||
"field_type": "Image",
|
||||
"required": true,
|
||||
"on_preview": true,
|
||||
"description": "yes"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
{
|
||||
"name": "Character",
|
||||
"id": "d1223e6b-ade0-405a-8c3b-657c743a21cc",
|
||||
"description": "desc",
|
||||
"fields": [
|
||||
{
|
||||
"name": "Appearance",
|
||||
"field_type": "MultiLine",
|
||||
"required": true,
|
||||
"description": "app"
|
||||
},
|
||||
{
|
||||
"name": "Age",
|
||||
"field_type": "Number",
|
||||
"required": true,
|
||||
"description": "age"
|
||||
},
|
||||
{
|
||||
"name": "DOB",
|
||||
"field_type": "Date",
|
||||
"required": false,
|
||||
"description": "dob"
|
||||
},
|
||||
{
|
||||
"name": "PFP",
|
||||
"field_type": "Image",
|
||||
"required": true,
|
||||
"description": ""
|
||||
},
|
||||
{
|
||||
"name": "Species",
|
||||
"field_type": "Link",
|
||||
"required": false,
|
||||
"description": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
+24
-10
@@ -4,37 +4,51 @@ use crate::{PROJECT_FOLDER, util};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Asset {
|
||||
pub new_name: String,
|
||||
pub name: String,
|
||||
pub old_name: String,
|
||||
pub saved: bool,
|
||||
}
|
||||
|
||||
impl Asset {
|
||||
pub fn open(name: String) -> Self {
|
||||
Self {
|
||||
old_name: name.clone(),
|
||||
new_name: name.clone(),
|
||||
name,
|
||||
saved: false,
|
||||
saved: true,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn save(&mut self) {
|
||||
let old_path = Self::path(&self.old_name);
|
||||
let new_path = Self::path(&self.name);
|
||||
let old_path = Self::path(&self.name);
|
||||
let new_path = Self::path(&self.new_name);
|
||||
|
||||
println!("old_path: {old_path:?}");
|
||||
println!("new_path: {new_path:?}");
|
||||
|
||||
// move from src dir to name path
|
||||
std::fs::rename(&old_path, &new_path).unwrap();
|
||||
if let Err(err) = std::fs::rename(&old_path, &new_path) {
|
||||
match err.kind() {
|
||||
std::io::ErrorKind::NotFound => {
|
||||
let dir = new_path.parent().unwrap();
|
||||
if !dir.exists() {
|
||||
std::fs::create_dir_all(dir).unwrap();
|
||||
}
|
||||
std::fs::rename(&old_path, &new_path).unwrap();
|
||||
}
|
||||
_ => panic!("Failed to rename file: {err}"),
|
||||
}
|
||||
}
|
||||
self.saved = true;
|
||||
self.old_name = self.name.clone();
|
||||
self.name = self.new_name.clone();
|
||||
}
|
||||
|
||||
pub fn path(name: &str) -> std::path::PathBuf {
|
||||
PROJECT_FOLDER.join("assets").join(format!("{name}.png"))
|
||||
PROJECT_FOLDER.join("assets").join(name)
|
||||
}
|
||||
|
||||
pub fn ui(&mut self, ui: &mut egui::Ui) {
|
||||
ui.vertical(|ui| {
|
||||
util::saved_status(ui, self.saved, &self.name, &self.name);
|
||||
util::saved_status(ui, self.saved, &self.name, &self.new_name);
|
||||
|
||||
if ui.input(|i| i.key_pressed(egui::Key::S) && i.modifiers.ctrl)
|
||||
|| ui.button("Save").clicked()
|
||||
@@ -46,7 +60,7 @@ impl Asset {
|
||||
|
||||
ui.horizontal(|ui| {
|
||||
ui.strong("Filename:");
|
||||
if TextEdit::singleline(&mut self.name)
|
||||
if TextEdit::singleline(&mut self.new_name)
|
||||
.desired_width(f32::INFINITY)
|
||||
.frame(false)
|
||||
.show(ui)
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
use egui::TextEdit;
|
||||
use egui::{TextEdit, text};
|
||||
use egui_commonmark::{CommonMarkCache, CommonMarkViewer};
|
||||
use serde::{self, Deserialize, Serialize};
|
||||
|
||||
use crate::{PROJECT_FOLDER, editors::tags::Tag, util};
|
||||
use crate::{PROJECT_FOLDER, editors::tags::Tag, llm_integration::content_llm::ai_enabled, util};
|
||||
|
||||
pub struct MainEditor {
|
||||
pub content: ContentSection,
|
||||
@@ -95,7 +95,7 @@ impl MainEditor {
|
||||
Self {
|
||||
content: ContentSection::new(),
|
||||
show_editor: false, // Start with editor hidden
|
||||
show_preview: true,
|
||||
show_preview: false,
|
||||
preview_cache: CommonMarkCache::default(),
|
||||
}
|
||||
}
|
||||
@@ -104,7 +104,7 @@ impl MainEditor {
|
||||
Self {
|
||||
content,
|
||||
show_editor: true,
|
||||
show_preview: true,
|
||||
show_preview: false,
|
||||
preview_cache: CommonMarkCache::default(),
|
||||
}
|
||||
}
|
||||
@@ -264,7 +264,7 @@ impl MainEditor {
|
||||
}
|
||||
|
||||
fn editor_ui(&mut self, ui: &mut egui::Ui) {
|
||||
egui::ScrollArea::both()
|
||||
let response = egui::ScrollArea::both()
|
||||
.auto_shrink([false, false])
|
||||
.id_salt("editor_scroll")
|
||||
.show(ui, |ui| {
|
||||
@@ -290,14 +290,39 @@ impl MainEditor {
|
||||
.hint_text("Type here...")
|
||||
.desired_width(max_width as f32);
|
||||
|
||||
if ui
|
||||
let mut ctx_menu = false;
|
||||
let response = ui
|
||||
.add_sized(
|
||||
egui::vec2(max_width as f32 - 30.0, ui.available_height()),
|
||||
text_edit,
|
||||
)
|
||||
.changed()
|
||||
{
|
||||
self.content.saved = false;
|
||||
.on_hover_text("Right click to open context menu")
|
||||
.context_menu(|ui| {
|
||||
ctx_menu = true;
|
||||
|
||||
ui.menu_button("AI Actions", |ui| {
|
||||
ui.add_enabled_ui(ai_enabled(), |ui| {
|
||||
if ui.button("Summarise").clicked() {
|
||||
println!("Summarise");
|
||||
}
|
||||
|
||||
if ui.button("Continue").clicked() {
|
||||
let content = self.content.content.clone();
|
||||
let response =
|
||||
crate::llm_integration::content_llm::continue_content(
|
||||
&content, "", 1024,
|
||||
)
|
||||
.unwrap();
|
||||
self.content.content.push_str(&response);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
if let Some(response) = response {
|
||||
if response.response.changed() || ctx_menu {
|
||||
self.content.saved = false;
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
use std::io::Read;
|
||||
|
||||
use chrono::NaiveDate;
|
||||
use egui_extras::DatePickerButton;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::PROJECT_FOLDER;
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct ProjectContext {
|
||||
date: NaiveDate,
|
||||
project_name: String,
|
||||
project_author: String,
|
||||
project_description: String,
|
||||
}
|
||||
|
||||
impl ProjectContext {
|
||||
pub fn new() -> Self {
|
||||
Self::default()
|
||||
}
|
||||
|
||||
pub fn load() -> Self {
|
||||
let path = PROJECT_FOLDER.join("context.json");
|
||||
if let Ok(mut file) = std::fs::File::open(path) {
|
||||
let mut contents = String::new();
|
||||
file.read_to_string(&mut contents).unwrap();
|
||||
if let Ok(proj) = serde_json::from_str(&contents) {
|
||||
return proj;
|
||||
}
|
||||
}
|
||||
Self::default()
|
||||
}
|
||||
|
||||
pub fn save(&self) {
|
||||
let path = PROJECT_FOLDER.join("context.json");
|
||||
let content = serde_json::to_string_pretty(self).unwrap();
|
||||
std::fs::write(path, content).unwrap();
|
||||
}
|
||||
|
||||
pub fn ui(&mut self, ui: &mut egui::Ui) {
|
||||
// table
|
||||
egui::Grid::new("context_editor")
|
||||
.striped(true)
|
||||
.num_columns(2)
|
||||
.show(ui, |ui| {
|
||||
ui.label("Project Name");
|
||||
ui.text_edit_singleline(&mut self.project_name);
|
||||
|
||||
ui.end_row();
|
||||
|
||||
ui.label("Project Author");
|
||||
ui.text_edit_singleline(&mut self.project_author);
|
||||
|
||||
ui.end_row();
|
||||
|
||||
ui.label("Project Description");
|
||||
ui.text_edit_singleline(&mut self.project_description);
|
||||
|
||||
ui.end_row();
|
||||
|
||||
ui.label("Date");
|
||||
ui.add(DatePickerButton::new(&mut self.date));
|
||||
|
||||
ui.end_row();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for ProjectContext {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
date: chrono::Local::now().naive_local().into(),
|
||||
project_name: "New Project".to_string(),
|
||||
project_author: "Your Name".to_string(),
|
||||
project_description: "Description of your project".to_string(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
pub mod asset_editor;
|
||||
pub mod content_editor;
|
||||
pub mod context_editor;
|
||||
pub mod note_editor;
|
||||
pub mod object_editor;
|
||||
pub mod tags;
|
||||
|
||||
@@ -1,23 +1,22 @@
|
||||
use core::f32;
|
||||
use std::path::Path;
|
||||
|
||||
use chrono::NaiveDate;
|
||||
use egui::{CollapsingHeader, Response, RichText, Sense, TextEdit, Ui, UiBuilder, vec2};
|
||||
use egui::{CollapsingHeader, RichText, Sense, TextEdit, Ui, UiBuilder, vec2};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{
|
||||
PROJECT_FOLDER, RightPanelContent,
|
||||
editors::{
|
||||
tags::Tag,
|
||||
template_editor::{FieldDefinition, FieldType, FieldValue, Template},
|
||||
template_editor::{FieldValue, Template},
|
||||
},
|
||||
util,
|
||||
};
|
||||
|
||||
pub type ObjectId = String;
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct ObjectInstance {
|
||||
// template info
|
||||
pub id: String,
|
||||
pub id: ObjectId,
|
||||
pub template_id: String,
|
||||
|
||||
// instance info
|
||||
@@ -67,7 +66,7 @@ impl ObjectInstance {
|
||||
let mut fields = std::collections::HashMap::new();
|
||||
|
||||
for field in &template.fields {
|
||||
fields.insert(field.name.clone(), FieldValue::default());
|
||||
fields.insert(field.name.clone(), FieldValue::from_type(&field.field_type));
|
||||
}
|
||||
|
||||
Self {
|
||||
@@ -106,7 +105,7 @@ impl ObjectInstance {
|
||||
ui: &mut Ui,
|
||||
template: &Template,
|
||||
right_panel: &mut Option<RightPanelContent>,
|
||||
objects: &mut Vec<ObjectInstance>,
|
||||
objects: &mut [ObjectInstance],
|
||||
) {
|
||||
let _ = right_panel;
|
||||
if ui.input(|i| i.key_pressed(egui::Key::S) && i.modifiers.ctrl) {
|
||||
@@ -193,13 +192,7 @@ impl ObjectInstance {
|
||||
|
||||
ui.separator();
|
||||
|
||||
Self::render_field(
|
||||
field_def,
|
||||
field_value,
|
||||
ui,
|
||||
&mut self.saved,
|
||||
objects,
|
||||
);
|
||||
Self::render_field(field_value, ui, &mut self.saved, objects);
|
||||
|
||||
ui.separator();
|
||||
});
|
||||
@@ -210,27 +203,25 @@ impl ObjectInstance {
|
||||
}
|
||||
|
||||
fn render_field(
|
||||
field_def: &FieldDefinition,
|
||||
field_value: &mut FieldValue,
|
||||
ui: &mut egui::Ui,
|
||||
saved: &mut bool,
|
||||
objects: &mut Vec<ObjectInstance>,
|
||||
objects: &mut [ObjectInstance],
|
||||
) {
|
||||
match field_def.field_type {
|
||||
FieldType::SingleLine => {
|
||||
if TextEdit::singleline(&mut field_value.value)
|
||||
match field_value {
|
||||
FieldValue::SingleLine(value) => {
|
||||
if TextEdit::singleline(value)
|
||||
.desired_width(f32::INFINITY)
|
||||
.frame(false)
|
||||
.show(ui)
|
||||
.response
|
||||
.changed()
|
||||
{
|
||||
field_value.modified = true;
|
||||
*saved = false;
|
||||
}
|
||||
}
|
||||
FieldType::MultiLine => {
|
||||
if TextEdit::multiline(&mut field_value.value)
|
||||
FieldValue::MultiLine(value) => {
|
||||
if TextEdit::multiline(value)
|
||||
.desired_width(f32::INFINITY)
|
||||
.desired_rows(5)
|
||||
.frame(false)
|
||||
@@ -238,51 +229,39 @@ impl ObjectInstance {
|
||||
.response
|
||||
.changed()
|
||||
{
|
||||
field_value.modified = true;
|
||||
*saved = false;
|
||||
}
|
||||
}
|
||||
FieldType::Date => {
|
||||
let date_str = &field_value.value;
|
||||
let mut date = NaiveDate::parse_from_str(date_str, "%Y-%m-%d")
|
||||
.unwrap_or_else(|_| chrono::Local::now().date_naive());
|
||||
|
||||
let response = ui.add(egui_extras::DatePickerButton::new(&mut date));
|
||||
|
||||
FieldValue::Date(value) => {
|
||||
let response = ui.add(egui_extras::DatePickerButton::new(value));
|
||||
if response.changed() {
|
||||
field_value.value = date.format("%Y-%m-%d").to_string();
|
||||
field_value.modified = true;
|
||||
*saved = false;
|
||||
}
|
||||
}
|
||||
FieldType::Number => {
|
||||
let mut num = field_value.value.parse::<f64>().unwrap_or(0.0);
|
||||
let response = ui.add(egui::DragValue::new(&mut num).speed(0.1));
|
||||
|
||||
FieldValue::Number(value) => {
|
||||
let response = ui.add(egui::DragValue::new(value).speed(0.1));
|
||||
if response.changed() {
|
||||
field_value.value = num.to_string();
|
||||
field_value.modified = true;
|
||||
*saved = false;
|
||||
}
|
||||
}
|
||||
FieldType::Image => {
|
||||
FieldValue::Image(value) => {
|
||||
ui.scope_builder(UiBuilder::new().sense(Sense::HOVER), |ui| {
|
||||
let id = ui.make_persistent_id("is_hovered");
|
||||
let should_show = field_value.value.is_empty()
|
||||
let should_show = value.is_empty()
|
||||
|| ui.response().hovered()
|
||||
|| ui.memory(|mem| mem.data.get_temp(id).unwrap_or(false));
|
||||
|| ui.memory(|mem| mem.data.get_temp(id).unwrap_or(false))
|
||||
|| !PROJECT_FOLDER.join("assets").join(&value).exists();
|
||||
|
||||
// Simple path input for now
|
||||
if should_show {
|
||||
let response = TextEdit::singleline(&mut field_value.value)
|
||||
.hint_text("Path to image")
|
||||
let response = TextEdit::singleline(value)
|
||||
.hint_text("Asset name (ignore file extension)")
|
||||
.desired_width(f32::INFINITY)
|
||||
.frame(false)
|
||||
.show(ui)
|
||||
.response;
|
||||
|
||||
if response.changed() {
|
||||
field_value.modified = true;
|
||||
*saved = false;
|
||||
}
|
||||
|
||||
@@ -292,10 +271,10 @@ impl ObjectInstance {
|
||||
}
|
||||
|
||||
// If we have a valid path, try to display a preview
|
||||
if !field_value.value.is_empty() {
|
||||
if let Ok(bytes) = std::fs::read(&field_value.value) {
|
||||
let path = PROJECT_FOLDER.join(&field_value.value);
|
||||
if !value.is_empty() {
|
||||
let path = PROJECT_FOLDER.join("assets").join(&value);
|
||||
|
||||
if let Ok(bytes) = std::fs::read(&path) {
|
||||
let image_source = egui::ImageSource::Bytes {
|
||||
uri: std::borrow::Cow::Owned(path.to_str().unwrap().to_string()),
|
||||
bytes: bytes.into(),
|
||||
@@ -307,10 +286,12 @@ impl ObjectInstance {
|
||||
}
|
||||
});
|
||||
}
|
||||
FieldType::Link => ObjectInstance::selector_ui(field_value, objects, ui, saved),
|
||||
FieldType::Links => {
|
||||
if ui.text_edit_singleline(&mut field_value.value).changed() {
|
||||
field_value.modified = true;
|
||||
FieldValue::Link(template_id) => {
|
||||
ObjectInstance::selector_ui(template_id, objects, ui, saved)
|
||||
}
|
||||
FieldValue::Links(_template_ids) => {
|
||||
let mut value = String::new();
|
||||
if ui.text_edit_singleline(&mut value).changed() {
|
||||
*saved = false;
|
||||
}
|
||||
}
|
||||
@@ -318,13 +299,13 @@ impl ObjectInstance {
|
||||
}
|
||||
|
||||
fn selector_ui(
|
||||
field_value: &mut FieldValue,
|
||||
objects: &mut Vec<ObjectInstance>,
|
||||
selected: &mut ObjectId,
|
||||
objects: &mut [ObjectInstance],
|
||||
ui: &mut egui::Ui,
|
||||
saved: &mut bool,
|
||||
) {
|
||||
if !field_value.value.is_empty() {
|
||||
if let Ok(object) = ObjectInstance::load(&field_value.value) {
|
||||
if !selected.is_empty() {
|
||||
if let Ok(object) = ObjectInstance::load(selected) {
|
||||
ui.strong(&object.name);
|
||||
}
|
||||
}
|
||||
@@ -334,7 +315,7 @@ impl ObjectInstance {
|
||||
|
||||
let ctx = ui.ctx();
|
||||
let mut object_selection: usize =
|
||||
ctx.memory_mut(|mem| *mem.data.get_temp_mut_or_default::<usize>(id));
|
||||
ctx.memory(|mem| mem.data.get_temp::<usize>(id).unwrap_or(0));
|
||||
|
||||
if objects.is_empty() {
|
||||
ui.label("No objects available");
|
||||
@@ -348,15 +329,18 @@ impl ObjectInstance {
|
||||
});
|
||||
}
|
||||
|
||||
let ctx = ui.ctx();
|
||||
ctx.memory_mut(|mem| {
|
||||
*mem.data.get_temp_mut_or_default::<usize>(id) = object_selection;
|
||||
});
|
||||
|
||||
if ui.button("Set").clicked() && object_selection < objects.len() {
|
||||
field_value.value = objects[object_selection].id.clone();
|
||||
field_value.modified = true;
|
||||
*selected = objects[object_selection].id.clone();
|
||||
*saved = false;
|
||||
}
|
||||
|
||||
if ui.button("Remove").clicked() {
|
||||
field_value.value.clear();
|
||||
field_value.modified = true;
|
||||
*selected = String::new();
|
||||
*saved = false;
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
use core::fmt;
|
||||
|
||||
use chrono::NaiveDate;
|
||||
use egui::ScrollArea;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
@@ -16,7 +17,7 @@ pub enum FieldType {
|
||||
MultiLine,
|
||||
Date,
|
||||
Number,
|
||||
Link,
|
||||
Link { template_id: Option<String> },
|
||||
Links,
|
||||
}
|
||||
|
||||
@@ -34,17 +35,54 @@ impl FieldType {
|
||||
FieldType::MultiLine,
|
||||
FieldType::Date,
|
||||
FieldType::Number,
|
||||
FieldType::Link,
|
||||
FieldType::Link { template_id: None },
|
||||
FieldType::Links,
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub enum FieldValue {
|
||||
Image(String),
|
||||
SingleLine(String),
|
||||
MultiLine(String),
|
||||
Date(NaiveDate),
|
||||
Number(f64),
|
||||
Link(String),
|
||||
Links(Vec<String>),
|
||||
}
|
||||
|
||||
impl FieldValue {
|
||||
pub fn from_type(_type: &FieldType) -> Self {
|
||||
match _type {
|
||||
FieldType::Image => Self::Image(String::new()),
|
||||
FieldType::SingleLine => Self::SingleLine(String::new()),
|
||||
FieldType::MultiLine => Self::MultiLine(String::new()),
|
||||
FieldType::Date => Self::Date(NaiveDate::from_ymd_opt(1970, 1, 1).unwrap()),
|
||||
FieldType::Number => Self::Number(0.0),
|
||||
FieldType::Link { template_id: None } => Self::Link(String::new()),
|
||||
FieldType::Link {
|
||||
template_id: Some(template_id),
|
||||
} => Self::Link(template_id.clone()),
|
||||
FieldType::Links => Self::Links(Vec::new()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for FieldValue {
|
||||
fn default() -> Self {
|
||||
Self::SingleLine(String::new())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct FieldDefinition {
|
||||
pub name: String,
|
||||
pub field_type: FieldType,
|
||||
pub required: bool,
|
||||
|
||||
#[serde(default)]
|
||||
pub on_preview: bool,
|
||||
pub description: Option<String>,
|
||||
}
|
||||
|
||||
@@ -73,6 +111,9 @@ pub struct Template {
|
||||
|
||||
#[serde(skip)]
|
||||
pub new_field_description: String,
|
||||
|
||||
#[serde(skip)]
|
||||
pub new_field_on_preview: bool,
|
||||
}
|
||||
|
||||
impl fmt::Debug for Template {
|
||||
@@ -105,6 +146,7 @@ impl Clone for Template {
|
||||
new_field_type: FieldType::default(),
|
||||
new_field_required: false,
|
||||
new_field_description: "".to_string(),
|
||||
new_field_on_preview: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -123,6 +165,7 @@ impl Default for Template {
|
||||
new_field_type: FieldType::default(),
|
||||
new_field_required: false,
|
||||
new_field_description: "".to_string(),
|
||||
new_field_on_preview: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -325,6 +368,12 @@ impl Template {
|
||||
}
|
||||
ui.end_row();
|
||||
|
||||
ui.label("On Preview:");
|
||||
if ui.checkbox(&mut field.on_preview, "").clicked() {
|
||||
self.saved = false;
|
||||
}
|
||||
ui.end_row();
|
||||
|
||||
ui.label("Description:");
|
||||
if ui
|
||||
.text_edit_singleline(
|
||||
@@ -377,6 +426,10 @@ impl Template {
|
||||
ui.checkbox(&mut self.new_field_required, "");
|
||||
ui.end_row();
|
||||
|
||||
ui.label("On Preview:");
|
||||
ui.checkbox(&mut self.new_field_on_preview, "");
|
||||
ui.end_row();
|
||||
|
||||
ui.label("Description:");
|
||||
ui.text_edit_singleline(&mut self.new_field_description);
|
||||
ui.end_row();
|
||||
@@ -385,6 +438,7 @@ impl Template {
|
||||
self.fields.push(FieldDefinition {
|
||||
name: self.new_field_name.clone(),
|
||||
field_type: self.new_field_type.clone(),
|
||||
on_preview: self.new_field_on_preview,
|
||||
required: self.new_field_required,
|
||||
description: if self.new_field_description.is_empty() {
|
||||
None
|
||||
@@ -404,10 +458,3 @@ impl Template {
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
|
||||
pub struct FieldValue {
|
||||
pub value: String,
|
||||
#[serde(skip)]
|
||||
pub modified: bool,
|
||||
}
|
||||
|
||||
+239
-155
@@ -1,3 +1,5 @@
|
||||
use walkdir::{DirEntry, WalkDir};
|
||||
|
||||
use crate::{
|
||||
PROJECT_FOLDER, RightPanelContent,
|
||||
content_editor::MainEditor,
|
||||
@@ -14,7 +16,6 @@ pub struct Explorer {
|
||||
notes: Vec<Note>,
|
||||
documents: Vec<MainEditor>,
|
||||
tags: Vec<Tag>,
|
||||
assets: Vec<Asset>,
|
||||
}
|
||||
|
||||
impl Explorer {
|
||||
@@ -25,7 +26,6 @@ impl Explorer {
|
||||
notes: Vec::new(),
|
||||
documents: Vec::new(),
|
||||
tags: Vec::new(),
|
||||
assets: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,161 +43,122 @@ impl Explorer {
|
||||
self.load_objects().expect("Failed to load objects");
|
||||
self.load_notes().expect("Failed to load notes");
|
||||
self.load_documents().expect("Failed to load documents");
|
||||
self.load_assets().expect("Failed to load assets");
|
||||
self.load_tags().expect("Failed to load tags");
|
||||
|
||||
ui.vertical(|ui| {
|
||||
egui::collapsing_header::CollapsingState::load_with_default_open(
|
||||
ui.ctx(),
|
||||
ui.make_persistent_id("templates"),
|
||||
true,
|
||||
)
|
||||
.show_header(ui, |ui| {
|
||||
ui.horizontal(|ui| {
|
||||
ui.label("Templates");
|
||||
if ui.button("+").clicked() {
|
||||
*to_load = Some(RightPanelContent::template(Some(Template::default())));
|
||||
}
|
||||
});
|
||||
})
|
||||
.body(|ui| {
|
||||
for template in &self.templates {
|
||||
let id = ui.make_persistent_id(template.name.clone());
|
||||
egui::collapsing_header::CollapsingState::load_with_default_open(
|
||||
ui.ctx(),
|
||||
id,
|
||||
true,
|
||||
)
|
||||
.show_header(ui, |ui| {
|
||||
// load the template
|
||||
if ui.selectable_label(false, template.name.clone()).clicked() {
|
||||
*to_load = Some(RightPanelContent::template(Some(template.clone())));
|
||||
}
|
||||
self.render_templates(ui, to_load);
|
||||
self.render_notes(ui, to_load);
|
||||
self.render_doc_root(ui, load_doc);
|
||||
self.render_tags(ui, to_load);
|
||||
self.render_assets(ui, to_load);
|
||||
});
|
||||
}
|
||||
|
||||
// create a new object based on this template
|
||||
if ui.button("+").clicked() {
|
||||
*to_load = Some(RightPanelContent::object(Some(ObjectInstance::new(
|
||||
template,
|
||||
))));
|
||||
}
|
||||
})
|
||||
.body(|ui| {
|
||||
for object in &self.objects {
|
||||
if object.template_id == template.id {
|
||||
ui.horizontal(|ui| {
|
||||
ui.add_space(10.0);
|
||||
|
||||
// load the object
|
||||
if ui.selectable_label(false, &object.name).clicked() {
|
||||
*to_load =
|
||||
Some(RightPanelContent::object(Some(object.clone())));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
fn render_templates(&mut self, ui: &mut egui::Ui, to_load: &mut Option<RightPanelContent>) {
|
||||
egui::collapsing_header::CollapsingState::load_with_default_open(
|
||||
ui.ctx(),
|
||||
ui.make_persistent_id("templates"),
|
||||
true,
|
||||
)
|
||||
.show_header(ui, |ui| {
|
||||
ui.horizontal(|ui| {
|
||||
ui.label("Templates");
|
||||
if ui.button("+").clicked() {
|
||||
*to_load = Some(RightPanelContent::template(Some(Template::default())));
|
||||
}
|
||||
});
|
||||
})
|
||||
.body(|ui| {
|
||||
for template in &self.templates {
|
||||
let id = ui.make_persistent_id(template.name.clone());
|
||||
egui::collapsing_header::CollapsingState::load_with_default_open(
|
||||
ui.ctx(),
|
||||
id,
|
||||
true,
|
||||
)
|
||||
.show_header(ui, |ui| {
|
||||
// load the template
|
||||
if ui.selectable_label(false, template.name.clone()).clicked() {
|
||||
*to_load = Some(RightPanelContent::template(Some(template.clone())));
|
||||
}
|
||||
|
||||
egui::collapsing_header::CollapsingState::load_with_default_open(
|
||||
ui.ctx(),
|
||||
ui.make_persistent_id("notes"),
|
||||
true,
|
||||
)
|
||||
.show_header(ui, |ui| {
|
||||
ui.horizontal(|ui| {
|
||||
ui.label("Notes");
|
||||
// create a new object based on this template
|
||||
if ui.button("+").clicked() {
|
||||
*to_load = Some(RightPanelContent::note(Some(Note::default())));
|
||||
*to_load = Some(RightPanelContent::object(Some(ObjectInstance::new(
|
||||
template,
|
||||
))));
|
||||
}
|
||||
})
|
||||
.body(|ui| {
|
||||
for object in &self.objects {
|
||||
if object.template_id == template.id {
|
||||
ui.horizontal(|ui| {
|
||||
ui.add_space(10.0);
|
||||
|
||||
// load the object
|
||||
if ui.selectable_label(false, &object.name).clicked() {
|
||||
*to_load =
|
||||
Some(RightPanelContent::object(Some(object.clone())));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
})
|
||||
.body(|ui| {
|
||||
for note in &self.notes {
|
||||
ui.horizontal(|ui| {
|
||||
ui.add_space(10.0);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// load the note
|
||||
if ui.selectable_label(false, ¬e.name).clicked() {
|
||||
*to_load = Some(RightPanelContent::note(Some(note.clone())));
|
||||
}
|
||||
});
|
||||
fn render_notes(&mut self, ui: &mut egui::Ui, to_load: &mut Option<RightPanelContent>) {
|
||||
egui::collapsing_header::CollapsingState::load_with_default_open(
|
||||
ui.ctx(),
|
||||
ui.make_persistent_id("notes"),
|
||||
true,
|
||||
)
|
||||
.show_header(ui, |ui| {
|
||||
ui.horizontal(|ui| {
|
||||
ui.label("Notes");
|
||||
if ui.button("+").clicked() {
|
||||
*to_load = Some(RightPanelContent::note(Some(Note::default())));
|
||||
}
|
||||
});
|
||||
|
||||
egui::collapsing_header::CollapsingState::load_with_default_open(
|
||||
ui.ctx(),
|
||||
ui.make_persistent_id("projects"),
|
||||
true,
|
||||
)
|
||||
.show_header(ui, |ui| {
|
||||
})
|
||||
.body(|ui| {
|
||||
for note in &self.notes {
|
||||
ui.horizontal(|ui| {
|
||||
ui.label("Projects");
|
||||
if ui.button("+").clicked() {
|
||||
*load_doc = Some(MainEditor::open(ContentSection::new()));
|
||||
ui.add_space(10.0);
|
||||
|
||||
// load the note
|
||||
if ui.selectable_label(false, ¬e.name).clicked() {
|
||||
*to_load = Some(RightPanelContent::note(Some(note.clone())));
|
||||
}
|
||||
});
|
||||
})
|
||||
.body(|ui| {
|
||||
// Convert MainEditor vec to ContentSection vec
|
||||
let content_sections: Vec<ContentSection> = self
|
||||
.documents
|
||||
.iter()
|
||||
.map(|doc| doc.content.clone())
|
||||
.collect();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Self::render_document_tree(ui, &content_sections, None, load_doc);
|
||||
});
|
||||
|
||||
self.tags = Tag::load_all();
|
||||
|
||||
egui::collapsing_header::CollapsingState::load_with_default_open(
|
||||
ui.ctx(),
|
||||
ui.make_persistent_id("tags"),
|
||||
true,
|
||||
)
|
||||
.show_header(ui, |ui| {
|
||||
ui.horizontal(|ui| {
|
||||
ui.label("Tags");
|
||||
if ui.button("+").clicked() {
|
||||
*to_load = Some(RightPanelContent::Tag(Tag::default()));
|
||||
}
|
||||
});
|
||||
})
|
||||
.body(|ui| {
|
||||
for tag in &mut self.tags {
|
||||
ui.horizontal(|ui| {
|
||||
ui.add_space(10.0);
|
||||
|
||||
// load the tag
|
||||
if tag.list_ui(ui).clicked() {
|
||||
*to_load = Some(RightPanelContent::Tag(tag.clone()));
|
||||
}
|
||||
});
|
||||
fn render_doc_root(&self, ui: &mut egui::Ui, load_doc: &mut Option<MainEditor>) {
|
||||
egui::collapsing_header::CollapsingState::load_with_default_open(
|
||||
ui.ctx(),
|
||||
ui.make_persistent_id("projects"),
|
||||
true,
|
||||
)
|
||||
.show_header(ui, |ui| {
|
||||
ui.horizontal(|ui| {
|
||||
ui.label("Projects");
|
||||
if ui.button("+").clicked() {
|
||||
*load_doc = Some(MainEditor::open(ContentSection::new()));
|
||||
}
|
||||
});
|
||||
})
|
||||
.body(|ui| {
|
||||
// Convert MainEditor vec to ContentSection vec
|
||||
let content_sections: Vec<ContentSection> = self
|
||||
.documents
|
||||
.iter()
|
||||
.map(|doc| doc.content.clone())
|
||||
.collect();
|
||||
|
||||
egui::collapsing_header::CollapsingState::load_with_default_open(
|
||||
ui.ctx(),
|
||||
ui.make_persistent_id("assets"),
|
||||
true,
|
||||
)
|
||||
.show_header(ui, |ui| {
|
||||
ui.horizontal(|ui| {
|
||||
ui.label("Assets");
|
||||
});
|
||||
})
|
||||
.body(|ui| {
|
||||
for asset in &mut self.assets {
|
||||
ui.horizontal(|ui| {
|
||||
ui.add_space(10.0);
|
||||
|
||||
// load the asset
|
||||
if ui.selectable_label(false, &asset.name).clicked() {
|
||||
*to_load = Some(RightPanelContent::Asset(Box::new(asset.clone())));
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
Self::render_doc_branch(ui, &content_sections, None, load_doc);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -209,7 +170,7 @@ impl Explorer {
|
||||
///
|
||||
/// `load_doc` is a mutable reference to a `MainEditor`. When a document is clicked, it
|
||||
/// is loaded into the `MainEditor` and returned as `Some`.
|
||||
fn render_document_tree(
|
||||
fn render_doc_branch(
|
||||
ui: &mut egui::Ui,
|
||||
documents: &[ContentSection],
|
||||
parent_id: Option<&str>,
|
||||
@@ -243,15 +204,135 @@ impl Explorer {
|
||||
})
|
||||
.body(|ui| {
|
||||
// recursive call to render the next level of documents
|
||||
Self::render_document_tree(ui, documents, Some(&doc.id), load_doc);
|
||||
Self::render_doc_branch(ui, documents, Some(&doc.id), load_doc);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
fn render_tags(&mut self, ui: &mut egui::Ui, to_load: &mut Option<RightPanelContent>) {
|
||||
egui::collapsing_header::CollapsingState::load_with_default_open(
|
||||
ui.ctx(),
|
||||
ui.make_persistent_id("tags"),
|
||||
true,
|
||||
)
|
||||
.show_header(ui, |ui| {
|
||||
ui.horizontal(|ui| {
|
||||
ui.label("Tags");
|
||||
if ui.button("+").clicked() {
|
||||
*to_load = Some(RightPanelContent::Tag(Tag::default()));
|
||||
}
|
||||
});
|
||||
})
|
||||
.body(|ui| {
|
||||
for tag in &mut self.tags {
|
||||
ui.horizontal(|ui| {
|
||||
ui.add_space(10.0);
|
||||
|
||||
// load the tag
|
||||
if tag.list_ui(ui).clicked() {
|
||||
*to_load = Some(RightPanelContent::Tag(tag.clone()));
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
fn render_assets(&mut self, ui: &mut egui::Ui, to_load: &mut Option<RightPanelContent>) {
|
||||
egui::collapsing_header::CollapsingState::load_with_default_open(
|
||||
ui.ctx(),
|
||||
ui.make_persistent_id("assets"),
|
||||
true,
|
||||
)
|
||||
.show_header(ui, |ui| {
|
||||
ui.horizontal(|ui| {
|
||||
ui.label("Assets");
|
||||
});
|
||||
})
|
||||
.body(|ui| {
|
||||
let mut entries: Vec<_> = WalkDir::new(PROJECT_FOLDER.join("assets"))
|
||||
.min_depth(1)
|
||||
.max_depth(1) // Only immediate children
|
||||
.sort_by(|a, b| {
|
||||
// Directories first, then files
|
||||
let a_is_dir = a.file_type().is_dir();
|
||||
let b_is_dir = b.file_type().is_dir();
|
||||
if a_is_dir == b_is_dir {
|
||||
a.file_name().cmp(b.file_name())
|
||||
} else if a_is_dir {
|
||||
std::cmp::Ordering::Less
|
||||
} else {
|
||||
std::cmp::Ordering::Greater
|
||||
}
|
||||
})
|
||||
.into_iter()
|
||||
.filter_map(Result::ok)
|
||||
.collect();
|
||||
|
||||
for entry in entries {
|
||||
self.render_entry(ui, to_load, &entry);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
fn render_entry(
|
||||
&mut self,
|
||||
ui: &mut egui::Ui,
|
||||
to_load: &mut Option<RightPanelContent>,
|
||||
entry: &DirEntry,
|
||||
) {
|
||||
let file_type = entry.file_type();
|
||||
let is_dir = file_type.is_dir();
|
||||
let file_name = entry.file_name().to_string_lossy();
|
||||
let path = entry.path();
|
||||
|
||||
if is_dir {
|
||||
let entries: Vec<_> = WalkDir::new(path)
|
||||
.min_depth(1)
|
||||
.max_depth(1)
|
||||
.sort_by(|a, b| a.file_name().cmp(b.file_name()))
|
||||
.into_iter()
|
||||
.filter_map(Result::ok)
|
||||
.collect();
|
||||
|
||||
egui::collapsing_header::CollapsingState::load_with_default_open(
|
||||
ui.ctx(),
|
||||
ui.make_persistent_id(&file_name),
|
||||
false,
|
||||
)
|
||||
.show_header(ui, |ui| {
|
||||
ui.horizontal(|ui| {
|
||||
ui.label(file_name);
|
||||
let clicked = ui.button("+").on_hover_text("Add new item").clicked();
|
||||
});
|
||||
})
|
||||
.body(|ui| {
|
||||
// recursive call to render the next level of documents
|
||||
for entry in entries {
|
||||
self.render_entry(ui, to_load, &entry);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
// Handle file
|
||||
if ui
|
||||
.selectable_label(false, format!("📄 {file_name}"))
|
||||
.clicked()
|
||||
{
|
||||
// use asset::load to get the file at the path
|
||||
let asset_path = path.strip_prefix(PROJECT_FOLDER.join("assets")).unwrap();
|
||||
let asset = Asset::open(asset_path.to_string_lossy().to_string());
|
||||
*to_load = Some(RightPanelContent::Asset(Box::new(asset)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// load templates from the templates folder
|
||||
fn load_templates(&mut self) -> std::io::Result<()> {
|
||||
let templates_folder = PROJECT_FOLDER.join("templates");
|
||||
if !templates_folder.exists() {
|
||||
std::fs::create_dir_all(&templates_folder)?;
|
||||
}
|
||||
let mut templates = Vec::new();
|
||||
for entry in std::fs::read_dir(PROJECT_FOLDER.join("templates")).unwrap() {
|
||||
for entry in std::fs::read_dir(&templates_folder).unwrap() {
|
||||
let path = entry.unwrap().path();
|
||||
match Template::load(path.file_stem().unwrap().to_str().unwrap()) {
|
||||
Ok(t) => templates.push(t),
|
||||
@@ -265,8 +346,12 @@ impl Explorer {
|
||||
|
||||
// load objects from the objects folder
|
||||
fn load_objects(&mut self) -> std::io::Result<()> {
|
||||
let objects_folder = PROJECT_FOLDER.join("objects");
|
||||
if !objects_folder.exists() {
|
||||
std::fs::create_dir_all(&objects_folder)?;
|
||||
}
|
||||
let mut objects = Vec::new();
|
||||
for entry in std::fs::read_dir(PROJECT_FOLDER.join("objects")).unwrap() {
|
||||
for entry in std::fs::read_dir(&objects_folder).unwrap() {
|
||||
let path = entry.unwrap().path();
|
||||
match ObjectInstance::load(path.file_stem().unwrap().to_str().unwrap()) {
|
||||
Ok(o) => objects.push(o),
|
||||
@@ -280,9 +365,13 @@ impl Explorer {
|
||||
|
||||
// load notes from the notes folder
|
||||
fn load_notes(&mut self) -> std::io::Result<()> {
|
||||
let notes_folder = PROJECT_FOLDER.join("notes");
|
||||
if !notes_folder.exists() {
|
||||
std::fs::create_dir_all(¬es_folder)?;
|
||||
}
|
||||
let mut notes = Vec::new();
|
||||
|
||||
for entry in std::fs::read_dir(PROJECT_FOLDER.join("notes")).unwrap() {
|
||||
for entry in std::fs::read_dir(¬es_folder).unwrap() {
|
||||
let path = entry.unwrap().path();
|
||||
match Note::load(path.file_stem().unwrap().to_str().unwrap()) {
|
||||
Ok(note) => notes.push(note),
|
||||
@@ -297,9 +386,13 @@ impl Explorer {
|
||||
|
||||
// load documents from the documents folder
|
||||
fn load_documents(&mut self) -> std::io::Result<()> {
|
||||
let documents_folder = PROJECT_FOLDER.join("documents");
|
||||
if !documents_folder.exists() {
|
||||
std::fs::create_dir_all(&documents_folder)?;
|
||||
}
|
||||
let mut documents = Vec::new();
|
||||
|
||||
for entry in std::fs::read_dir(PROJECT_FOLDER.join("documents")).unwrap() {
|
||||
for entry in std::fs::read_dir(&documents_folder).unwrap() {
|
||||
let path = entry.unwrap().path();
|
||||
match ContentSection::load(path.file_stem().unwrap().to_str().unwrap()) {
|
||||
Ok(document) => documents.push(MainEditor::open(document)),
|
||||
@@ -312,17 +405,8 @@ impl Explorer {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn load_assets(&mut self) -> std::io::Result<()> {
|
||||
let mut assets = Vec::new();
|
||||
for entry in std::fs::read_dir(PROJECT_FOLDER.join("assets")).unwrap() {
|
||||
let path = entry.unwrap().path();
|
||||
assets.push(Asset::open(
|
||||
path.file_stem().unwrap().to_str().unwrap().to_string(),
|
||||
));
|
||||
}
|
||||
|
||||
self.assets = assets;
|
||||
|
||||
fn load_tags(&mut self) -> std::io::Result<()> {
|
||||
self.tags = Tag::load_all();
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
pub fn continue_content(
|
||||
context: &str,
|
||||
instruction: &str,
|
||||
max_tokens: usize,
|
||||
) -> Result<String, Box<dyn std::error::Error>> {
|
||||
let client = reqwest::blocking::Client::new();
|
||||
|
||||
let messages = vec![
|
||||
Message {
|
||||
role: "system".to_string(),
|
||||
content: "
|
||||
Please generate content that is a direct continuation of the given text.
|
||||
Your response should be a logical next step in the content and should not repeat any of the text from the instruction or the content.
|
||||
Do not generate any text that is not a direct continuation of the content.
|
||||
if extra instructions are provided, follow them exactly, otherwise continue the text in a logical way.
|
||||
".to_string(),
|
||||
},
|
||||
Message {
|
||||
role: "user".to_string(),
|
||||
content: context.to_string(),
|
||||
},
|
||||
Message {
|
||||
role: "user".to_string(),
|
||||
content: format!("Instructions: {instruction}"),
|
||||
},
|
||||
];
|
||||
|
||||
let request = ChatRequest {
|
||||
messages,
|
||||
temperature: 0.7,
|
||||
};
|
||||
|
||||
let response = client
|
||||
.post("http://localhost:1234/v1/chat/completions")
|
||||
.json(&request)
|
||||
.send()?;
|
||||
|
||||
if !response.status().is_success() {
|
||||
return Err(format!("Request failed: {}", response.text()?).into());
|
||||
}
|
||||
|
||||
let response: ChatResponse = response.json()?;
|
||||
|
||||
if let Some(choice) = response.choices.into_iter().next() {
|
||||
Ok(choice.message.content)
|
||||
} else {
|
||||
Err("No response from model".into())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn ai_enabled() -> bool {
|
||||
let client = reqwest::blocking::Client::new();
|
||||
client.get("http://localhost:1234/v1/models").send().is_ok()
|
||||
}
|
||||
|
||||
// Simple request structure
|
||||
#[derive(Serialize)]
|
||||
struct ChatRequest {
|
||||
messages: Vec<Message>,
|
||||
temperature: f32,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
struct Message {
|
||||
role: String,
|
||||
content: String,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
struct ChatResponse {
|
||||
choices: Vec<Choice>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
struct Choice {
|
||||
message: Message,
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
pub mod content_llm;
|
||||
+19
-7
@@ -4,14 +4,15 @@ use egui::ScrollArea;
|
||||
|
||||
mod editors;
|
||||
mod explorer;
|
||||
mod llm_integration;
|
||||
mod scene;
|
||||
|
||||
mod util;
|
||||
|
||||
use crate::{
|
||||
editors::{
|
||||
asset_editor::Asset, content_editor, note_editor, object_editor::ObjectInstance, tags::Tag,
|
||||
template_editor::Template,
|
||||
asset_editor::Asset, content_editor, context_editor::ProjectContext, note_editor,
|
||||
object_editor::ObjectInstance, tags::Tag, template_editor::Template,
|
||||
},
|
||||
explorer::Explorer,
|
||||
};
|
||||
@@ -39,6 +40,7 @@ pub struct Interface {
|
||||
editor: content_editor::MainEditor,
|
||||
scene: scene::EditorScene,
|
||||
explorer: Explorer,
|
||||
project: ProjectContext,
|
||||
}
|
||||
|
||||
impl eframe::App for Interface {
|
||||
@@ -84,6 +86,7 @@ impl Interface {
|
||||
editor: content_editor::MainEditor::new(),
|
||||
scene: scene::EditorScene::new(),
|
||||
explorer: Explorer::new(),
|
||||
project: ProjectContext::load(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -183,28 +186,31 @@ impl Interface {
|
||||
});
|
||||
}
|
||||
|
||||
// render main content area
|
||||
fn render_main_content(&mut self, ctx: &egui::Context) {
|
||||
self.editor.ui(ctx);
|
||||
self.scene.ui(ctx);
|
||||
self.scene.ui(ctx, &mut self.explorer.objects());
|
||||
}
|
||||
|
||||
// configure appearance of UI elements
|
||||
fn configure_appearance(&self, ctx: &egui::Context) {
|
||||
// configure appearance of UI elements
|
||||
let mut visuals = egui::Visuals::dark();
|
||||
visuals.window_fill = egui::Color32::from_rgb(20, 20, 20);
|
||||
visuals.panel_fill = egui::Color32::from_rgb(20, 20, 20);
|
||||
visuals.widgets.inactive.fg_stroke =
|
||||
egui::Stroke::from((2.0, egui::Color32::from_rgb(255, 255, 255)));
|
||||
egui::Stroke::from((1.0, egui::Color32::from_rgb(255, 255, 255)));
|
||||
visuals.widgets.inactive.bg_stroke =
|
||||
egui::Stroke::from((2.0, egui::Color32::from_rgb(60, 60, 60)));
|
||||
egui::Stroke::from((1.0, egui::Color32::from_rgb(60, 60, 60)));
|
||||
visuals.widgets.inactive.corner_radius = egui::CornerRadius::from(4);
|
||||
visuals.widgets.inactive.bg_fill = egui::Color32::from_rgb(20, 20, 20);
|
||||
visuals.widgets.inactive.weak_bg_fill = egui::Color32::from_rgb(20, 20, 20);
|
||||
visuals.widgets.inactive.expansion = 2.0;
|
||||
visuals.widgets.inactive.expansion = 1.0;
|
||||
|
||||
ctx.set_visuals(visuals);
|
||||
|
||||
// setup fonts.
|
||||
let mut fonts = egui::FontDefinitions::default();
|
||||
|
||||
fonts.font_data.insert(
|
||||
"JetBrains Mono Nerd Font".to_string(),
|
||||
std::sync::Arc::new(egui::FontData::from_static(include_bytes!(
|
||||
@@ -233,3 +239,9 @@ impl Default for Interface {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for Interface {
|
||||
fn drop(&mut self) {
|
||||
self.project.save();
|
||||
}
|
||||
}
|
||||
|
||||
+125
-5
@@ -1,3 +1,13 @@
|
||||
use egui::{RichText, vec2};
|
||||
|
||||
use crate::{
|
||||
PROJECT_FOLDER,
|
||||
editors::{
|
||||
object_editor::ObjectInstance,
|
||||
template_editor::{FieldType, FieldValue, Template},
|
||||
},
|
||||
};
|
||||
|
||||
pub struct EditorScene {
|
||||
rect: egui::Rect,
|
||||
}
|
||||
@@ -9,17 +19,127 @@ impl EditorScene {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn ui(&mut self, ctx: &egui::Context) {
|
||||
pub fn ui(&mut self, ctx: &egui::Context, objects: &mut [ObjectInstance]) {
|
||||
egui::CentralPanel::default()
|
||||
.frame(egui::Frame::NONE)
|
||||
.show(ctx, |ui| {
|
||||
egui::Scene::default()
|
||||
.zoom_range(0.1..=10.0)
|
||||
.show(ui, &mut self.rect, |ui| {
|
||||
egui::Resize::default().auto_sized().show(ui, |ui| {
|
||||
ui.group(|ui| {
|
||||
ui.label("Scene");
|
||||
});
|
||||
ui.horizontal_wrapped(|ui| {
|
||||
ui.set_max_width(5000.0);
|
||||
// Group objects by their template_id
|
||||
use std::collections::HashMap;
|
||||
let mut objects_by_template: HashMap<String, Vec<&ObjectInstance>> =
|
||||
HashMap::new();
|
||||
|
||||
for obj in objects {
|
||||
objects_by_template
|
||||
.entry(obj.template_id.clone())
|
||||
.or_default()
|
||||
.push(obj);
|
||||
}
|
||||
|
||||
// For each template with objects, create cards
|
||||
for (template_id, template_objects) in objects_by_template {
|
||||
// Try to load the template to get field definitions
|
||||
if let Ok(mut template) = Template::load(&template_id) {
|
||||
for obj in template_objects {
|
||||
// Create a card for each object
|
||||
egui::Frame::group(ui.style())
|
||||
.fill(egui::Color32::from_rgba_premultiplied(
|
||||
30, 30, 30, 200,
|
||||
))
|
||||
.corner_radius(4.0)
|
||||
.show(ui, |ui| {
|
||||
|
||||
ui.vertical(|ui| {
|
||||
ui.set_max_width(512.0);
|
||||
ui.set_min_width(512.0);
|
||||
|
||||
// Object name as header
|
||||
ui.heading(RichText::new(&obj.name).strong());
|
||||
|
||||
// Show fields with on_preview = true
|
||||
template.fields.sort_by_key(|field| field.field_type != FieldType::Image);
|
||||
for field_def in &template.fields {
|
||||
if field_def.on_preview {
|
||||
if let Some(field_value) =
|
||||
obj.fields.get(&field_def.name)
|
||||
{
|
||||
ui.separator();
|
||||
|
||||
match field_value {
|
||||
FieldValue::SingleLine(
|
||||
text,
|
||||
) => {
|
||||
ui.strong(&field_def.name);
|
||||
ui.label(text);
|
||||
}
|
||||
FieldValue::MultiLine(
|
||||
text,
|
||||
) => {
|
||||
ui.strong(&field_def.name);
|
||||
ui.label(text);
|
||||
}
|
||||
FieldValue::Number(n) => {
|
||||
ui.strong(&field_def.name);
|
||||
ui.label(n.to_string());
|
||||
}
|
||||
FieldValue::Date(date) => {
|
||||
ui.strong(&field_def.name);
|
||||
ui.label(
|
||||
date.format(
|
||||
"%Y-%m-%d",
|
||||
)
|
||||
.to_string(),
|
||||
);
|
||||
}
|
||||
FieldValue::Image(value) => {
|
||||
if !value.is_empty() {
|
||||
let path = PROJECT_FOLDER.join("assets").join(value);
|
||||
|
||||
if let Ok(bytes) = std::fs::read(&path) {
|
||||
let image_source = egui::ImageSource::Bytes {
|
||||
uri: std::borrow::Cow::Owned(path.to_str().unwrap().to_string()),
|
||||
bytes: bytes.into(),
|
||||
};
|
||||
ui.add(
|
||||
egui::Image::new(image_source).fit_to_exact_size(vec2(512.0, 512.0)),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
FieldValue::Link(
|
||||
target_id,
|
||||
) => {
|
||||
ui.strong(&field_def.name);
|
||||
ui.label(format!(
|
||||
"→ {target_id}"
|
||||
));
|
||||
}
|
||||
FieldValue::Links(
|
||||
links,
|
||||
) => {
|
||||
ui.strong(&field_def.name);
|
||||
ui.label(format!(
|
||||
"{} links",
|
||||
links.len()
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Add some spacing between cards
|
||||
ui.add_space(8.0);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user