feat: ability to view tasks in a category (#19)
This commit is contained in:
commit
b27f7d08c4
2
.idea/dataSources.local.xml
generated
2
.idea/dataSources.local.xml
generated
@ -1,6 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<project version="4">
|
<project version="4">
|
||||||
<component name="dataSourceStorageLocal" created-in="RR-242.20224.309">
|
<component name="dataSourceStorageLocal" created-in="RR-242.21829.114">
|
||||||
<data-source name="todo_baggins@localhost" uuid="1658668c-c2b8-426d-a22f-16fbad9eff0b">
|
<data-source name="todo_baggins@localhost" uuid="1658668c-c2b8-426d-a22f-16fbad9eff0b">
|
||||||
<database-info product="PostgreSQL" version="16.4 (Debian 16.4-1.pgdg120+1)" jdbc-version="4.2" driver-name="PostgreSQL JDBC Driver" driver-version="42.6.0" dbms="POSTGRES" exact-version="16.4" exact-driver-version="42.6">
|
<database-info product="PostgreSQL" version="16.4 (Debian 16.4-1.pgdg120+1)" jdbc-version="4.2" driver-name="PostgreSQL JDBC Driver" driver-version="42.6.0" dbms="POSTGRES" exact-version="16.4" exact-driver-version="42.6">
|
||||||
<identifier-quote-string>"</identifier-quote-string>
|
<identifier-quote-string>"</identifier-quote-string>
|
||||||
|
14
.idea/webResources.xml
generated
Normal file
14
.idea/webResources.xml
generated
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="WebResourcesPaths">
|
||||||
|
<contentEntries>
|
||||||
|
<entry url="file://$PROJECT_DIR$">
|
||||||
|
<entryData>
|
||||||
|
<resourceRoots>
|
||||||
|
<path value="file://$PROJECT_DIR$/assets" />
|
||||||
|
</resourceRoots>
|
||||||
|
</entryData>
|
||||||
|
</entry>
|
||||||
|
</contentEntries>
|
||||||
|
</component>
|
||||||
|
</project>
|
451
Cargo.lock
generated
451
Cargo.lock
generated
@ -77,6 +77,17 @@ version = "0.10.3"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "619743e34b5ba4e9703bba34deac3427c72507c7159f5fd030aea8cac0cfe341"
|
checksum = "619743e34b5ba4e9703bba34deac3427c72507c7159f5fd030aea8cac0cfe341"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "async-channel"
|
||||||
|
version = "1.9.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "81953c529336010edd6d8e358f886d9581267795c61b19475b71314bffa46d35"
|
||||||
|
dependencies = [
|
||||||
|
"concurrent-queue",
|
||||||
|
"event-listener 2.5.3",
|
||||||
|
"futures-core",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "async-channel"
|
name = "async-channel"
|
||||||
version = "2.3.1"
|
version = "2.3.1"
|
||||||
@ -89,6 +100,119 @@ dependencies = [
|
|||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "async-executor"
|
||||||
|
version = "1.13.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d7ebdfa2ebdab6b1760375fa7d6f382b9f486eac35fc994625a00e89280bdbb7"
|
||||||
|
dependencies = [
|
||||||
|
"async-task",
|
||||||
|
"concurrent-queue",
|
||||||
|
"fastrand 2.1.0",
|
||||||
|
"futures-lite 2.3.0",
|
||||||
|
"slab",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "async-global-executor"
|
||||||
|
version = "2.4.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "05b1b633a2115cd122d73b955eadd9916c18c8f510ec9cd1686404c60ad1c29c"
|
||||||
|
dependencies = [
|
||||||
|
"async-channel 2.3.1",
|
||||||
|
"async-executor",
|
||||||
|
"async-io 2.3.4",
|
||||||
|
"async-lock 3.4.0",
|
||||||
|
"blocking",
|
||||||
|
"futures-lite 2.3.0",
|
||||||
|
"once_cell",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "async-io"
|
||||||
|
version = "1.13.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0fc5b45d93ef0529756f812ca52e44c221b35341892d3dcc34132ac02f3dd2af"
|
||||||
|
dependencies = [
|
||||||
|
"async-lock 2.8.0",
|
||||||
|
"autocfg",
|
||||||
|
"cfg-if",
|
||||||
|
"concurrent-queue",
|
||||||
|
"futures-lite 1.13.0",
|
||||||
|
"log",
|
||||||
|
"parking",
|
||||||
|
"polling 2.8.0",
|
||||||
|
"rustix 0.37.27",
|
||||||
|
"slab",
|
||||||
|
"socket2 0.4.10",
|
||||||
|
"waker-fn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "async-io"
|
||||||
|
version = "2.3.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "444b0228950ee6501b3568d3c93bf1176a1fdbc3b758dcd9475046d30f4dc7e8"
|
||||||
|
dependencies = [
|
||||||
|
"async-lock 3.4.0",
|
||||||
|
"cfg-if",
|
||||||
|
"concurrent-queue",
|
||||||
|
"futures-io",
|
||||||
|
"futures-lite 2.3.0",
|
||||||
|
"parking",
|
||||||
|
"polling 3.7.3",
|
||||||
|
"rustix 0.38.34",
|
||||||
|
"slab",
|
||||||
|
"tracing",
|
||||||
|
"windows-sys 0.59.0",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "async-lock"
|
||||||
|
version = "2.8.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "287272293e9d8c41773cec55e365490fe034813a2f172f502d6ddcf75b2f582b"
|
||||||
|
dependencies = [
|
||||||
|
"event-listener 2.5.3",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "async-lock"
|
||||||
|
version = "3.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ff6e472cdea888a4bd64f342f09b3f50e1886d32afe8df3d663c01140b811b18"
|
||||||
|
dependencies = [
|
||||||
|
"event-listener 5.3.1",
|
||||||
|
"event-listener-strategy",
|
||||||
|
"pin-project-lite",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "async-std"
|
||||||
|
version = "1.12.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "62565bb4402e926b29953c785397c6dc0391b7b446e45008b0049eb43cec6f5d"
|
||||||
|
dependencies = [
|
||||||
|
"async-channel 1.9.0",
|
||||||
|
"async-global-executor",
|
||||||
|
"async-io 1.13.0",
|
||||||
|
"async-lock 2.8.0",
|
||||||
|
"crossbeam-utils",
|
||||||
|
"futures-channel",
|
||||||
|
"futures-core",
|
||||||
|
"futures-io",
|
||||||
|
"futures-lite 1.13.0",
|
||||||
|
"gloo-timers",
|
||||||
|
"kv-log-macro",
|
||||||
|
"log",
|
||||||
|
"memchr",
|
||||||
|
"once_cell",
|
||||||
|
"pin-project-lite",
|
||||||
|
"pin-utils",
|
||||||
|
"slab",
|
||||||
|
"wasm-bindgen-futures",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "async-task"
|
name = "async-task"
|
||||||
version = "4.7.1"
|
version = "4.7.1"
|
||||||
@ -226,6 +350,12 @@ dependencies = [
|
|||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bitflags"
|
||||||
|
version = "1.3.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bitflags"
|
name = "bitflags"
|
||||||
version = "2.6.0"
|
version = "2.6.0"
|
||||||
@ -250,10 +380,10 @@ version = "1.6.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "703f41c54fc768e63e091340b424302bb1c29ef4aa0c7f10fe849dfb114d29ea"
|
checksum = "703f41c54fc768e63e091340b424302bb1c29ef4aa0c7f10fe849dfb114d29ea"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-channel",
|
"async-channel 2.3.1",
|
||||||
"async-task",
|
"async-task",
|
||||||
"futures-io",
|
"futures-io",
|
||||||
"futures-lite",
|
"futures-lite 2.3.0",
|
||||||
"piper",
|
"piper",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -341,9 +471,10 @@ dependencies = [
|
|||||||
"iana-time-zone",
|
"iana-time-zone",
|
||||||
"js-sys",
|
"js-sys",
|
||||||
"num-traits",
|
"num-traits",
|
||||||
|
"pure-rust-locales",
|
||||||
"serde",
|
"serde",
|
||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
"windows-targets",
|
"windows-targets 0.52.6",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -534,7 +665,7 @@ version = "2.2.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "bf97ee7261bb708fa3402fa9c17a54b70e90e3cb98afb3dc8999d5512cb03f94"
|
checksum = "bf97ee7261bb708fa3402fa9c17a54b70e90e3cb98afb3dc8999d5512cb03f94"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags",
|
"bitflags 2.6.0",
|
||||||
"byteorder",
|
"byteorder",
|
||||||
"chrono",
|
"chrono",
|
||||||
"diesel_derives",
|
"diesel_derives",
|
||||||
@ -830,6 +961,17 @@ dependencies = [
|
|||||||
"tracing-wasm",
|
"tracing-wasm",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "dioxus-query"
|
||||||
|
version = "0.5.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2c84184c06ee2823957aa3ef939da6a04f0ab934f007745eb65dadb105bde241"
|
||||||
|
dependencies = [
|
||||||
|
"dioxus-lib",
|
||||||
|
"futures-util",
|
||||||
|
"instant",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dioxus-router"
|
name = "dioxus-router"
|
||||||
version = "0.5.6"
|
version = "0.5.6"
|
||||||
@ -1016,6 +1158,16 @@ version = "1.0.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
|
checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "errno"
|
||||||
|
version = "0.3.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"windows-sys 0.52.0",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "euclid"
|
name = "euclid"
|
||||||
version = "0.22.10"
|
version = "0.22.10"
|
||||||
@ -1026,6 +1178,12 @@ dependencies = [
|
|||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "event-listener"
|
||||||
|
version = "2.5.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "event-listener"
|
name = "event-listener"
|
||||||
version = "5.3.1"
|
version = "5.3.1"
|
||||||
@ -1043,10 +1201,19 @@ version = "0.5.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0f214dc438f977e6d4e3500aaa277f5ad94ca83fbbd9b1a15713ce2344ccc5a1"
|
checksum = "0f214dc438f977e6d4e3500aaa277f5ad94ca83fbbd9b1a15713ce2344ccc5a1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"event-listener",
|
"event-listener 5.3.1",
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "fastrand"
|
||||||
|
version = "1.9.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be"
|
||||||
|
dependencies = [
|
||||||
|
"instant",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fastrand"
|
name = "fastrand"
|
||||||
version = "2.1.0"
|
version = "2.1.0"
|
||||||
@ -1122,13 +1289,31 @@ version = "0.3.30"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1"
|
checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "futures-lite"
|
||||||
|
version = "1.13.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "49a9d51ce47660b1e808d3c990b4709f2f415d928835a17dfd16991515c46bce"
|
||||||
|
dependencies = [
|
||||||
|
"fastrand 1.9.0",
|
||||||
|
"futures-core",
|
||||||
|
"futures-io",
|
||||||
|
"memchr",
|
||||||
|
"parking",
|
||||||
|
"pin-project-lite",
|
||||||
|
"waker-fn",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "futures-lite"
|
name = "futures-lite"
|
||||||
version = "2.3.0"
|
version = "2.3.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "52527eb5074e35e9339c6b4e8d12600c7128b68fb25dcb9fa9dec18f7c25f3a5"
|
checksum = "52527eb5074e35e9339c6b4e8d12600c7128b68fb25dcb9fa9dec18f7c25f3a5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"fastrand 2.1.0",
|
||||||
"futures-core",
|
"futures-core",
|
||||||
|
"futures-io",
|
||||||
|
"parking",
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -1362,6 +1547,8 @@ version = "0.2.6"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9b995a66bb87bebce9a0f4a95aed01daca4872c050bfcb21653361c03bc35e5c"
|
checksum = "9b995a66bb87bebce9a0f4a95aed01daca4872c050bfcb21653361c03bc35e5c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"futures-channel",
|
||||||
|
"futures-core",
|
||||||
"js-sys",
|
"js-sys",
|
||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
]
|
]
|
||||||
@ -1453,6 +1640,12 @@ version = "0.3.9"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024"
|
checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hermit-abi"
|
||||||
|
version = "0.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hex"
|
name = "hex"
|
||||||
version = "0.4.3"
|
version = "0.4.3"
|
||||||
@ -1617,6 +1810,18 @@ dependencies = [
|
|||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "instant"
|
||||||
|
version = "0.1.13"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"js-sys",
|
||||||
|
"wasm-bindgen",
|
||||||
|
"web-sys",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "internment"
|
name = "internment"
|
||||||
version = "0.7.5"
|
version = "0.7.5"
|
||||||
@ -1659,6 +1864,17 @@ version = "0.3.15"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f958d3d68f4167080a18141e10381e7634563984a537f2a49a30fd8e53ac5767"
|
checksum = "f958d3d68f4167080a18141e10381e7634563984a537f2a49a30fd8e53ac5767"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "io-lifetimes"
|
||||||
|
version = "1.0.11"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2"
|
||||||
|
dependencies = [
|
||||||
|
"hermit-abi 0.3.9",
|
||||||
|
"libc",
|
||||||
|
"windows-sys 0.48.0",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "itoa"
|
name = "itoa"
|
||||||
version = "1.0.11"
|
version = "1.0.11"
|
||||||
@ -1680,7 +1896,7 @@ version = "0.7.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b750dcadc39a09dbadd74e118f6dd6598df77fa01df0cfcdc52c28dece74528a"
|
checksum = "b750dcadc39a09dbadd74e118f6dd6598df77fa01df0cfcdc52c28dece74528a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags",
|
"bitflags 2.6.0",
|
||||||
"serde",
|
"serde",
|
||||||
"unicode-segmentation",
|
"unicode-segmentation",
|
||||||
]
|
]
|
||||||
@ -1698,6 +1914,15 @@ dependencies = [
|
|||||||
"semver",
|
"semver",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "kv-log-macro"
|
||||||
|
version = "1.0.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0de8b303297635ad57c9f5059fd9cee7a47f8e8daa09df0fcd07dd39fb22977f"
|
||||||
|
dependencies = [
|
||||||
|
"log",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lazy_static"
|
name = "lazy_static"
|
||||||
version = "1.5.0"
|
version = "1.5.0"
|
||||||
@ -1710,6 +1935,18 @@ version = "0.2.155"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c"
|
checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "linux-raw-sys"
|
||||||
|
version = "0.3.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "linux-raw-sys"
|
||||||
|
version = "0.4.14"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lock_api"
|
name = "lock_api"
|
||||||
version = "0.4.12"
|
version = "0.4.12"
|
||||||
@ -1725,6 +1962,9 @@ name = "log"
|
|||||||
version = "0.4.22"
|
version = "0.4.22"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
|
checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
|
||||||
|
dependencies = [
|
||||||
|
"value-bag",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "longest-increasing-subsequence"
|
name = "longest-increasing-subsequence"
|
||||||
@ -1790,10 +2030,10 @@ version = "1.0.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec"
|
checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"hermit-abi",
|
"hermit-abi 0.3.9",
|
||||||
"libc",
|
"libc",
|
||||||
"wasi",
|
"wasi",
|
||||||
"windows-sys",
|
"windows-sys 0.52.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -1894,7 +2134,7 @@ dependencies = [
|
|||||||
"libc",
|
"libc",
|
||||||
"redox_syscall",
|
"redox_syscall",
|
||||||
"smallvec",
|
"smallvec",
|
||||||
"windows-targets",
|
"windows-targets 0.52.6",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -1952,10 +2192,41 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "96c8c490f422ef9a4efd2cb5b42b76c8613d7e7dfc1caf667b8a3350a5acc066"
|
checksum = "96c8c490f422ef9a4efd2cb5b42b76c8613d7e7dfc1caf667b8a3350a5acc066"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"atomic-waker",
|
"atomic-waker",
|
||||||
"fastrand",
|
"fastrand 2.1.0",
|
||||||
"futures-io",
|
"futures-io",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "polling"
|
||||||
|
version = "2.8.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4b2d323e8ca7996b3e23126511a523f7e62924d93ecd5ae73b333815b0eb3dce"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
"bitflags 1.3.2",
|
||||||
|
"cfg-if",
|
||||||
|
"concurrent-queue",
|
||||||
|
"libc",
|
||||||
|
"log",
|
||||||
|
"pin-project-lite",
|
||||||
|
"windows-sys 0.48.0",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "polling"
|
||||||
|
version = "3.7.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "cc2790cd301dec6cd3b7a025e4815cf825724a51c98dccfe6a3e55f05ffb6511"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"concurrent-queue",
|
||||||
|
"hermit-abi 0.4.0",
|
||||||
|
"pin-project-lite",
|
||||||
|
"rustix 0.38.34",
|
||||||
|
"tracing",
|
||||||
|
"windows-sys 0.59.0",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "powerfmt"
|
name = "powerfmt"
|
||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
@ -2023,6 +2294,12 @@ dependencies = [
|
|||||||
"unicode-ident",
|
"unicode-ident",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pure-rust-locales"
|
||||||
|
version = "0.8.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1190fd18ae6ce9e137184f207593877e70f39b015040156b1e05081cdfe3733a"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "quote"
|
name = "quote"
|
||||||
version = "1.0.36"
|
version = "1.0.36"
|
||||||
@ -2068,7 +2345,7 @@ version = "0.5.3"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2a908a6e00f1fdd0dfd9c0eb08ce85126f6d8bbda50017e74bc4a4b7d4a926a4"
|
checksum = "2a908a6e00f1fdd0dfd9c0eb08ce85126f6d8bbda50017e74bc4a4b7d4a926a4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags",
|
"bitflags 2.6.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -2121,6 +2398,33 @@ dependencies = [
|
|||||||
"semver",
|
"semver",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rustix"
|
||||||
|
version = "0.37.27"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "fea8ca367a3a01fe35e6943c400addf443c0f57670e6ec51196f71a4b8762dd2"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags 1.3.2",
|
||||||
|
"errno",
|
||||||
|
"io-lifetimes",
|
||||||
|
"libc",
|
||||||
|
"linux-raw-sys 0.3.8",
|
||||||
|
"windows-sys 0.48.0",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rustix"
|
||||||
|
version = "0.38.34"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags 2.6.0",
|
||||||
|
"errno",
|
||||||
|
"libc",
|
||||||
|
"linux-raw-sys 0.4.14",
|
||||||
|
"windows-sys 0.52.0",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustversion"
|
name = "rustversion"
|
||||||
version = "1.0.17"
|
version = "1.0.17"
|
||||||
@ -2433,6 +2737,16 @@ version = "1.13.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67"
|
checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "socket2"
|
||||||
|
version = "0.4.10"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9f7916fc008ca5542385b89a3d3ce689953c143e9304a9bf8beec1de48994c0d"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"winapi",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "socket2"
|
name = "socket2"
|
||||||
version = "0.5.7"
|
version = "0.5.7"
|
||||||
@ -2440,7 +2754,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c"
|
checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
"windows-sys",
|
"windows-sys 0.52.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -2583,10 +2897,12 @@ checksum = "c7c4ceeeca15c8384bbc3e011dbd8fccb7f068a440b752b7d9b32ceb0ca0e2e8"
|
|||||||
name = "todo-baggins"
|
name = "todo-baggins"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"async-std",
|
||||||
"chrono",
|
"chrono",
|
||||||
"diesel",
|
"diesel",
|
||||||
"dioxus",
|
"dioxus",
|
||||||
"dioxus-logger",
|
"dioxus-logger",
|
||||||
|
"dioxus-query",
|
||||||
"dotenvy",
|
"dotenvy",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
@ -2609,9 +2925,9 @@ dependencies = [
|
|||||||
"parking_lot",
|
"parking_lot",
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
"signal-hook-registry",
|
"signal-hook-registry",
|
||||||
"socket2",
|
"socket2 0.5.7",
|
||||||
"tokio-macros",
|
"tokio-macros",
|
||||||
"windows-sys",
|
"windows-sys 0.52.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -2686,7 +3002,7 @@ version = "0.5.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1e9cd434a998747dd2c4276bc96ee2e0c7a2eadf3cae88e52be55a05fa9053f5"
|
checksum = "1e9cd434a998747dd2c4276bc96ee2e0c7a2eadf3cae88e52be55a05fa9053f5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags",
|
"bitflags 2.6.0",
|
||||||
"bytes",
|
"bytes",
|
||||||
"futures-util",
|
"futures-util",
|
||||||
"http 1.1.0",
|
"http 1.1.0",
|
||||||
@ -2922,6 +3238,12 @@ version = "0.1.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d"
|
checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "value-bag"
|
||||||
|
version = "1.9.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5a84c137d37ab0142f0f2ddfe332651fdbf252e7b7dbb4e67b6c1f1b2e925101"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "vcpkg"
|
name = "vcpkg"
|
||||||
version = "0.2.15"
|
version = "0.2.15"
|
||||||
@ -2934,6 +3256,12 @@ version = "0.9.5"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
|
checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "waker-fn"
|
||||||
|
version = "1.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "317211a0dc0ceedd78fb2ca9a44aed3d7b9b26f81870d485c07122b4350673b7"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasi"
|
name = "wasi"
|
||||||
version = "0.11.0+wasi-snapshot-preview1"
|
version = "0.11.0+wasi-snapshot-preview1"
|
||||||
@ -3058,7 +3386,16 @@ version = "0.52.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9"
|
checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"windows-targets",
|
"windows-targets 0.52.6",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-sys"
|
||||||
|
version = "0.48.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
|
||||||
|
dependencies = [
|
||||||
|
"windows-targets 0.48.5",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -3067,7 +3404,31 @@ version = "0.52.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
|
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"windows-targets",
|
"windows-targets 0.52.6",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-sys"
|
||||||
|
version = "0.59.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
|
||||||
|
dependencies = [
|
||||||
|
"windows-targets 0.52.6",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-targets"
|
||||||
|
version = "0.48.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c"
|
||||||
|
dependencies = [
|
||||||
|
"windows_aarch64_gnullvm 0.48.5",
|
||||||
|
"windows_aarch64_msvc 0.48.5",
|
||||||
|
"windows_i686_gnu 0.48.5",
|
||||||
|
"windows_i686_msvc 0.48.5",
|
||||||
|
"windows_x86_64_gnu 0.48.5",
|
||||||
|
"windows_x86_64_gnullvm 0.48.5",
|
||||||
|
"windows_x86_64_msvc 0.48.5",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -3076,28 +3437,46 @@ version = "0.52.6"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
|
checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"windows_aarch64_gnullvm",
|
"windows_aarch64_gnullvm 0.52.6",
|
||||||
"windows_aarch64_msvc",
|
"windows_aarch64_msvc 0.52.6",
|
||||||
"windows_i686_gnu",
|
"windows_i686_gnu 0.52.6",
|
||||||
"windows_i686_gnullvm",
|
"windows_i686_gnullvm",
|
||||||
"windows_i686_msvc",
|
"windows_i686_msvc 0.52.6",
|
||||||
"windows_x86_64_gnu",
|
"windows_x86_64_gnu 0.52.6",
|
||||||
"windows_x86_64_gnullvm",
|
"windows_x86_64_gnullvm 0.52.6",
|
||||||
"windows_x86_64_msvc",
|
"windows_x86_64_msvc 0.52.6",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_aarch64_gnullvm"
|
||||||
|
version = "0.48.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_aarch64_gnullvm"
|
name = "windows_aarch64_gnullvm"
|
||||||
version = "0.52.6"
|
version = "0.52.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
|
checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_aarch64_msvc"
|
||||||
|
version = "0.48.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_aarch64_msvc"
|
name = "windows_aarch64_msvc"
|
||||||
version = "0.52.6"
|
version = "0.52.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
|
checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_i686_gnu"
|
||||||
|
version = "0.48.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_i686_gnu"
|
name = "windows_i686_gnu"
|
||||||
version = "0.52.6"
|
version = "0.52.6"
|
||||||
@ -3110,24 +3489,48 @@ version = "0.52.6"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
|
checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_i686_msvc"
|
||||||
|
version = "0.48.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_i686_msvc"
|
name = "windows_i686_msvc"
|
||||||
version = "0.52.6"
|
version = "0.52.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
|
checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_x86_64_gnu"
|
||||||
|
version = "0.48.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_x86_64_gnu"
|
name = "windows_x86_64_gnu"
|
||||||
version = "0.52.6"
|
version = "0.52.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
|
checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_x86_64_gnullvm"
|
||||||
|
version = "0.48.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_x86_64_gnullvm"
|
name = "windows_x86_64_gnullvm"
|
||||||
version = "0.52.6"
|
version = "0.52.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
|
checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_x86_64_msvc"
|
||||||
|
version = "0.48.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_x86_64_msvc"
|
name = "windows_x86_64_msvc"
|
||||||
version = "0.52.6"
|
version = "0.52.6"
|
||||||
|
@ -7,7 +7,7 @@ edition = "2021"
|
|||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
chrono = { version = "0.4.38", features = ["serde"] }
|
chrono = { version = "0.4.38", features = ["serde", "unstable-locales"] }
|
||||||
diesel = { version = "2.2.2", features = ["chrono", "postgres", "postgres_backend", "serde_json"] }
|
diesel = { version = "2.2.2", features = ["chrono", "postgres", "postgres_backend", "serde_json"] }
|
||||||
|
|
||||||
dioxus = { version = "0.5", features = ["fullstack", "router"] }
|
dioxus = { version = "0.5", features = ["fullstack", "router"] }
|
||||||
@ -21,6 +21,8 @@ serde_json = "1.0.125"
|
|||||||
tracing = "0.1.40"
|
tracing = "0.1.40"
|
||||||
tracing-wasm = "0.2.1"
|
tracing-wasm = "0.2.1"
|
||||||
serde_with = { version = "3.9.0", features = ["chrono_0_4"] }
|
serde_with = { version = "3.9.0", features = ["chrono_0_4"] }
|
||||||
|
async-std = "1.12.0"
|
||||||
|
dioxus-query = "0.5.1"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = []
|
default = []
|
||||||
|
@ -31,10 +31,15 @@ watch_path = ["src", "assets"]
|
|||||||
|
|
||||||
# CSS style file
|
# CSS style file
|
||||||
|
|
||||||
style = ["/styles/tailwind_output.css"]
|
style = [
|
||||||
|
"/styles/tailwind_output.css",
|
||||||
|
"/styles/fonts.css",
|
||||||
|
"/styles/input_number_arrows.css",
|
||||||
|
"/styles/input_range.css"
|
||||||
|
]
|
||||||
|
|
||||||
# Javascript code file
|
# Javascript code file
|
||||||
script = []
|
script = ["https://kit.fontawesome.com/3c1b409f8f.js"]
|
||||||
|
|
||||||
[web.resource.dev]
|
[web.resource.dev]
|
||||||
|
|
||||||
|
17
assets/styles/fonts.css
Normal file
17
assets/styles/fonts.css
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
@layer base {
|
||||||
|
@font-face {
|
||||||
|
font-family: Inter;
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 100 900;
|
||||||
|
font-display: swap;
|
||||||
|
src: url("/fonts/inter_variable.woff2") format("woff2");
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: Inter;
|
||||||
|
font-style: italic;
|
||||||
|
font-weight: 100 900;
|
||||||
|
font-display: swap;
|
||||||
|
src: url("/fonts/inter_variable_italic.woff2") format("woff2");
|
||||||
|
}
|
||||||
|
}
|
10
assets/styles/input_number_arrows.css
Normal file
10
assets/styles/input_number_arrows.css
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
input::-webkit-outer-spin-button,
|
||||||
|
input::-webkit-inner-spin-button {
|
||||||
|
display: none;
|
||||||
|
appearance: none;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type="number"] {
|
||||||
|
appearance:textfield;
|
||||||
|
}
|
63
assets/styles/input_range.css
Normal file
63
assets/styles/input_range.css
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
input[type="range"],
|
||||||
|
input[type="range"]::-webkit-slider-runnable-track,
|
||||||
|
input[type="range"]::-webkit-slider-thumb {
|
||||||
|
appearance: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type="range"] {
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type="range"]::-moz-range-thumb {
|
||||||
|
width: 1.25rem;
|
||||||
|
height: 1.25rem;
|
||||||
|
background: rgba(228 228 231);
|
||||||
|
border: 0;
|
||||||
|
border-radius: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type="range"]::-moz-range-progress {
|
||||||
|
background: #525259;
|
||||||
|
height: 0.5rem;
|
||||||
|
border-radius: 0.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type="range"]::-moz-range-track {
|
||||||
|
background: rgba(39 39 42 / 50%);
|
||||||
|
height: 0.5rem;
|
||||||
|
border-radius: 0.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type="range"].input-range-reverse::-moz-range-progress {
|
||||||
|
background: #2d2d31;
|
||||||
|
height: 0.5rem;
|
||||||
|
border-radius: 0.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type="range"].input-range-reverse::-moz-range-track {
|
||||||
|
background: rgba(113 113 122 / 50%);
|
||||||
|
height: 0.5rem;
|
||||||
|
border-radius: 0.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type="range"]::-webkit-slider-thumb {
|
||||||
|
width: 1.25rem;
|
||||||
|
height: 1.25rem;
|
||||||
|
background: rgba(228 228 231);
|
||||||
|
border: 0;
|
||||||
|
border-radius: 0.5rem;
|
||||||
|
position: relative;
|
||||||
|
top: -0.4rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type="range"]::-webkit-slider-runnable-track {
|
||||||
|
background: rgba(39 39 42 / 50%);
|
||||||
|
height: 0.5rem;
|
||||||
|
border-radius: 0.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type="range"].input-range-reverse::-webkit-slider-runnable-track {
|
||||||
|
background: rgba(39 39 42 / 50%);
|
||||||
|
height: 0.5rem;
|
||||||
|
border-radius: 0.25rem;
|
||||||
|
}
|
@ -2,12 +2,16 @@ use crate::route::Route;
|
|||||||
use dioxus::core_macro::rsx;
|
use dioxus::core_macro::rsx;
|
||||||
use dioxus::dioxus_core::Element;
|
use dioxus::dioxus_core::Element;
|
||||||
use dioxus::prelude::*;
|
use dioxus::prelude::*;
|
||||||
|
use dioxus_query::prelude::{use_init_query_client};
|
||||||
|
use crate::query::{QueryErrors, QueryKey, QueryValue};
|
||||||
|
|
||||||
#[component]
|
#[component]
|
||||||
pub(crate) fn App() -> Element {
|
pub(crate) fn App() -> Element {
|
||||||
|
use_init_query_client::<QueryValue, QueryErrors, QueryKey>();
|
||||||
|
|
||||||
rsx! {
|
rsx! {
|
||||||
div {
|
div {
|
||||||
class: "min-h-screen text-white bg-neutral-800",
|
class: "min-h-screen text-zinc-200 bg-zinc-800 pt-4 pb-36",
|
||||||
Router::<Route> {}
|
Router::<Route> {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
62
src/components/bottom_panel.rs
Normal file
62
src/components/bottom_panel.rs
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
use dioxus::prelude::*;
|
||||||
|
use crate::components::navigation::Navigation;
|
||||||
|
use crate::components::project_form::ProjectForm;
|
||||||
|
use crate::components::task_form::TaskForm;
|
||||||
|
use crate::route::Route;
|
||||||
|
|
||||||
|
#[component]
|
||||||
|
pub(crate) fn BottomPanel(display_form: Signal<bool>) -> Element {
|
||||||
|
// A signal for delaying the application of styles.
|
||||||
|
#[allow(clippy::redundant_closure)]
|
||||||
|
let mut expanded = use_signal(|| display_form());
|
||||||
|
let navigation_expanded = use_signal(|| false);
|
||||||
|
let current_route = use_route();
|
||||||
|
|
||||||
|
use_effect(use_reactive(&display_form, move |creating_task| {
|
||||||
|
if creating_task() {
|
||||||
|
expanded.set(true);
|
||||||
|
} else {
|
||||||
|
spawn(async move {
|
||||||
|
// Necessary for a smooth – not instant – height transition.
|
||||||
|
async_std::task::sleep(std::time::Duration::from_millis(500)).await;
|
||||||
|
expanded.set(false);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
|
rsx! {
|
||||||
|
div {
|
||||||
|
class: format!(
|
||||||
|
"bg-zinc-700/50 rounded-t-xl border-t-zinc-600 border-t backdrop-blur drop-shadow-[0_-5px_10px_rgba(0,0,0,0.2)] transition-[height] duration-[500ms] ease-[cubic-bezier(0.79,0.14,0.15,0.86)] {}",
|
||||||
|
match (display_form(), current_route, navigation_expanded()) {
|
||||||
|
(false, _, false) => "h-[64px]",
|
||||||
|
(false, _, true) => "h-[128px]",
|
||||||
|
(true, Route::ProjectsPage, _) => "h-[128px]",
|
||||||
|
(true, _, _) => "h-[448px]",
|
||||||
|
}
|
||||||
|
),
|
||||||
|
if expanded() {
|
||||||
|
match current_route {
|
||||||
|
Route::ProjectsPage => rsx! {
|
||||||
|
ProjectForm {
|
||||||
|
on_successful_submit: move |_| {
|
||||||
|
display_form.set(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_ => rsx! {
|
||||||
|
TaskForm {
|
||||||
|
on_successful_submit: move |_| {
|
||||||
|
display_form.set(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Navigation {
|
||||||
|
expanded: navigation_expanded,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
102
src/components/category_input.rs
Normal file
102
src/components/category_input.rs
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
use crate::models::category::Category;
|
||||||
|
use chrono::NaiveDate;
|
||||||
|
use dioxus::core_macro::rsx;
|
||||||
|
use dioxus::dioxus_core::Element;
|
||||||
|
use dioxus::prelude::*;
|
||||||
|
|
||||||
|
#[component]
|
||||||
|
pub(crate) fn CategoryInput(selected_category: Signal<Category>, class: Option<&'static str>) -> Element {
|
||||||
|
rsx! {
|
||||||
|
div {
|
||||||
|
class: format!("flex flex-row gap-2 {}", class.unwrap_or("")),
|
||||||
|
button {
|
||||||
|
r#type: "button",
|
||||||
|
class: format!(
|
||||||
|
"py-2 rounded-lg grow basis-0 {}",
|
||||||
|
if selected_category() == Category::SomedayMaybe { "bg-zinc-500/50" }
|
||||||
|
else { "bg-zinc-800/50" }
|
||||||
|
),
|
||||||
|
onclick: move |_| {
|
||||||
|
selected_category.set(Category::SomedayMaybe);
|
||||||
|
},
|
||||||
|
i {
|
||||||
|
class: "fa-solid fa-question"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
button {
|
||||||
|
r#type: "button",
|
||||||
|
class: format!(
|
||||||
|
"py-2 rounded-lg grow basis-0 {}",
|
||||||
|
if selected_category() == Category::LongTerm { "bg-zinc-500/50" }
|
||||||
|
else { "bg-zinc-800/50" }
|
||||||
|
),
|
||||||
|
onclick: move |_| {
|
||||||
|
selected_category.set(Category::LongTerm);
|
||||||
|
},
|
||||||
|
i {
|
||||||
|
class: "fa-solid fa-water"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
button {
|
||||||
|
r#type: "button",
|
||||||
|
class: format!(
|
||||||
|
"py-2 rounded-lg grow basis-0 {}",
|
||||||
|
if let Category::WaitingFor(_) = selected_category() { "bg-zinc-500/50" }
|
||||||
|
else { "bg-zinc-800/50" }
|
||||||
|
),
|
||||||
|
onclick: move |_| {
|
||||||
|
selected_category.set(Category::WaitingFor(String::new()));
|
||||||
|
},
|
||||||
|
i {
|
||||||
|
class: "fa-solid fa-hourglass-half"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
button {
|
||||||
|
r#type: "button",
|
||||||
|
class: format!(
|
||||||
|
"py-2 rounded-lg grow basis-0 {}",
|
||||||
|
if selected_category() == Category::NextSteps { "bg-zinc-500/50" }
|
||||||
|
else { "bg-zinc-800/50" }
|
||||||
|
),
|
||||||
|
onclick: move |_| {
|
||||||
|
selected_category.set(Category::NextSteps);
|
||||||
|
},
|
||||||
|
i {
|
||||||
|
class: "fa-solid fa-forward"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
button {
|
||||||
|
r#type: "button",
|
||||||
|
class: format!(
|
||||||
|
"py-2 rounded-lg grow basis-0 {}",
|
||||||
|
if let Category::Calendar { .. } = selected_category() { "bg-zinc-500/50" }
|
||||||
|
else { "bg-zinc-800/50" }
|
||||||
|
),
|
||||||
|
onclick: move |_| {
|
||||||
|
selected_category.set(Category::Calendar {
|
||||||
|
date: NaiveDate::default(),
|
||||||
|
reoccurrence: None,
|
||||||
|
time: None,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
i {
|
||||||
|
class: "fa-solid fa-calendar-days"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
button {
|
||||||
|
r#type: "button",
|
||||||
|
class: format!(
|
||||||
|
"py-2 rounded-lg grow basis-0 {}",
|
||||||
|
if selected_category() == Category::Inbox { "bg-zinc-500/50" }
|
||||||
|
else { "bg-zinc-800/50" }
|
||||||
|
),
|
||||||
|
onclick: move |_| {
|
||||||
|
selected_category.set(Category::Inbox);
|
||||||
|
},
|
||||||
|
i {
|
||||||
|
class: "fa-solid fa-inbox"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
16
src/components/create_task_button.rs
Normal file
16
src/components/create_task_button.rs
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
use dioxus::prelude::*;
|
||||||
|
|
||||||
|
#[component]
|
||||||
|
pub(crate) fn CreateButton(creating: Signal<bool>) -> Element {
|
||||||
|
rsx! {
|
||||||
|
button {
|
||||||
|
class: "m-4 py-3 px-5 self-end text-center bg-zinc-300/50 rounded-xl border-t-zinc-200 border-t backdrop-blur drop-shadow-[0_-5px_10px_rgba(0,0,0,0.2)] text-2xl text-zinc-200",
|
||||||
|
onclick: move |_| {
|
||||||
|
creating.set(!creating());
|
||||||
|
},
|
||||||
|
i {
|
||||||
|
class: format!("min-w-6 fa-solid {}", if creating() { "fa-xmark" } else { "fa-plus" }),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,13 +1,9 @@
|
|||||||
use crate::components::project_form::ProjectForm;
|
|
||||||
use dioxus::core_macro::rsx;
|
use dioxus::core_macro::rsx;
|
||||||
use dioxus::dioxus_core::Element;
|
use dioxus::dioxus_core::Element;
|
||||||
use dioxus::prelude::*;
|
use dioxus::prelude::*;
|
||||||
use crate::components::task_form::TaskForm;
|
|
||||||
|
|
||||||
#[component]
|
#[component]
|
||||||
pub(crate) fn Home() -> Element {
|
pub(crate) fn Home() -> Element {
|
||||||
rsx! {
|
rsx! {
|
||||||
ProjectForm {}
|
|
||||||
TaskForm {}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
24
src/components/layout.rs
Normal file
24
src/components/layout.rs
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
use crate::components::bottom_panel::BottomPanel;
|
||||||
|
use crate::route::Route;
|
||||||
|
use dioxus::core_macro::rsx;
|
||||||
|
use dioxus::dioxus_core::Element;
|
||||||
|
use dioxus::prelude::*;
|
||||||
|
use crate::components::create_task_button::CreateButton;
|
||||||
|
use crate::components::sticky_bottom::StickyBottom;
|
||||||
|
|
||||||
|
#[component]
|
||||||
|
pub(crate) fn Layout() -> Element {
|
||||||
|
let display_form = use_signal(|| false);
|
||||||
|
|
||||||
|
rsx! {
|
||||||
|
Outlet::<Route> {}
|
||||||
|
StickyBottom {
|
||||||
|
CreateButton {
|
||||||
|
creating: display_form,
|
||||||
|
}
|
||||||
|
BottomPanel {
|
||||||
|
display_form: display_form,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -2,3 +2,13 @@ pub(crate) mod app;
|
|||||||
pub(crate) mod home;
|
pub(crate) mod home;
|
||||||
pub(crate) mod project_form;
|
pub(crate) mod project_form;
|
||||||
pub(crate) mod task_form;
|
pub(crate) mod task_form;
|
||||||
|
pub(crate) mod task_list;
|
||||||
|
pub(crate) mod pages;
|
||||||
|
pub(crate) mod navigation;
|
||||||
|
pub(crate) mod create_task_button;
|
||||||
|
pub(crate) mod bottom_panel;
|
||||||
|
pub(crate) mod sticky_bottom;
|
||||||
|
pub(crate) mod category_input;
|
||||||
|
pub(crate) mod reoccurrence_input;
|
||||||
|
pub(crate) mod layout;
|
||||||
|
pub(crate) mod navigation_item;
|
||||||
|
81
src/components/navigation.rs
Normal file
81
src/components/navigation.rs
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
use crate::components::navigation_item::NavigationItem;
|
||||||
|
use crate::route::Route;
|
||||||
|
use dioxus::prelude::*;
|
||||||
|
|
||||||
|
#[component]
|
||||||
|
pub(crate) fn Navigation(expanded: Signal<bool>) -> Element {
|
||||||
|
rsx! {
|
||||||
|
div {
|
||||||
|
class: "grid grid-cols-5 justify-stretch",
|
||||||
|
button {
|
||||||
|
class: format!(
|
||||||
|
"py-4 text-center text-2xl {}",
|
||||||
|
if expanded() { "text-zinc-200" }
|
||||||
|
else { "text-zinc-500" }
|
||||||
|
),
|
||||||
|
onclick: move |_| expanded.set(!expanded()),
|
||||||
|
i {
|
||||||
|
class: "fa-solid fa-bars"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
NavigationItem {
|
||||||
|
route: Route::CategoryNextStepsPage,
|
||||||
|
i {
|
||||||
|
class: "fa-solid fa-forward"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
NavigationItem {
|
||||||
|
route: Route::CategoryCalendarPage,
|
||||||
|
i {
|
||||||
|
class: "fa-solid fa-calendar-days"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
NavigationItem {
|
||||||
|
route: Route::CategoryTodayPage,
|
||||||
|
i {
|
||||||
|
class: "fa-solid fa-calendar-day"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
NavigationItem {
|
||||||
|
route: Route::CategoryInboxPage,
|
||||||
|
i {
|
||||||
|
class: "fa-solid fa-inbox"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{if expanded() {
|
||||||
|
rsx! {
|
||||||
|
NavigationItem {
|
||||||
|
route: Route::ProjectsPage,
|
||||||
|
i {
|
||||||
|
class: "fa-solid fa-list"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
NavigationItem {
|
||||||
|
route: Route::CategoryTrashPage,
|
||||||
|
i {
|
||||||
|
class: "fa-solid fa-trash-can"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
NavigationItem {
|
||||||
|
route: Route::CategoryDonePage,
|
||||||
|
i {
|
||||||
|
class: "fa-solid fa-check"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
NavigationItem {
|
||||||
|
route: Route::CategoryLongTermPage,
|
||||||
|
i {
|
||||||
|
class: "fa-solid fa-water"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
NavigationItem {
|
||||||
|
route: Route::CategoryWaitingForPage,
|
||||||
|
i {
|
||||||
|
class: "fa-solid fa-hourglass-half"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else { None }}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
19
src/components/navigation_item.rs
Normal file
19
src/components/navigation_item.rs
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
use dioxus::prelude::*;
|
||||||
|
use crate::route::Route;
|
||||||
|
|
||||||
|
#[component]
|
||||||
|
pub(crate) fn NavigationItem(route: Route, children: Element) -> Element {
|
||||||
|
let current_route = use_route::<Route>();
|
||||||
|
|
||||||
|
rsx! {
|
||||||
|
Link {
|
||||||
|
to: route.clone(),
|
||||||
|
class: format!(
|
||||||
|
"py-4 text-center text-2xl {}",
|
||||||
|
if current_route == route { "text-zinc-200" }
|
||||||
|
else { "text-zinc-500" }
|
||||||
|
),
|
||||||
|
children
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
78
src/components/pages/category_calendar_page.rs
Normal file
78
src/components/pages/category_calendar_page.rs
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
use crate::models::category::Category;
|
||||||
|
use chrono::{Datelike, Local, Locale};
|
||||||
|
use dioxus::core_macro::rsx;
|
||||||
|
use dioxus::dioxus_core::Element;
|
||||||
|
use dioxus::prelude::*;
|
||||||
|
use dioxus_query::prelude::QueryResult;
|
||||||
|
use crate::components::task_list::TaskList;
|
||||||
|
use crate::query::QueryValue;
|
||||||
|
use crate::query::tasks::use_tasks_in_category_query;
|
||||||
|
use crate::models::task::Task;
|
||||||
|
|
||||||
|
const CALENDAR_LENGTH_DAYS: usize = 366 * 3;
|
||||||
|
|
||||||
|
#[component]
|
||||||
|
pub(crate) fn CategoryCalendarPage() -> Element {
|
||||||
|
let tasks = use_tasks_in_category_query(Category::Calendar {
|
||||||
|
date: Local::now().date_naive(),
|
||||||
|
reoccurrence: None,
|
||||||
|
time: None,
|
||||||
|
});
|
||||||
|
let tasks_query_result = tasks.result();
|
||||||
|
|
||||||
|
rsx! {
|
||||||
|
match tasks_query_result.value() {
|
||||||
|
QueryResult::Ok(QueryValue::Tasks(tasks))
|
||||||
|
| QueryResult::Loading(Some(QueryValue::Tasks(tasks))) => {
|
||||||
|
let today_date = Local::now().date_naive();
|
||||||
|
|
||||||
|
rsx! {
|
||||||
|
div {
|
||||||
|
class: "pt-4 flex flex-col gap-8",
|
||||||
|
for date_current in today_date.iter_days().take(CALENDAR_LENGTH_DAYS) {
|
||||||
|
div {
|
||||||
|
class: "flex flex-col gap-4",
|
||||||
|
div {
|
||||||
|
class: "px-8 flex flex-row items-center gap-2 font-bold",
|
||||||
|
div {
|
||||||
|
class: "pt-1",
|
||||||
|
{
|
||||||
|
date_current
|
||||||
|
.format_localized(
|
||||||
|
format!(
|
||||||
|
"%A %-d. %B{}",
|
||||||
|
if date_current.year() != today_date.year() {" %Y"}
|
||||||
|
else {""}
|
||||||
|
).as_str(),
|
||||||
|
Locale::en_US
|
||||||
|
)
|
||||||
|
.to_string()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
TaskList {
|
||||||
|
tasks: tasks.iter().filter(|task| {
|
||||||
|
if let Category::Calendar { date, .. } = task.category() {
|
||||||
|
*date == date_current
|
||||||
|
} else {
|
||||||
|
panic!("Unexpected category.");
|
||||||
|
}
|
||||||
|
}).cloned().collect::<Vec<Task>>()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
QueryResult::Loading(None) => rsx! {
|
||||||
|
// TODO: Add a loading indicator.
|
||||||
|
},
|
||||||
|
QueryResult::Err(errors) => rsx! {
|
||||||
|
div {
|
||||||
|
"Errors occurred: {errors:?}"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
value => panic!("Unexpected query result: {value:?}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
14
src/components/pages/category_done_page.rs
Normal file
14
src/components/pages/category_done_page.rs
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
use crate::models::category::Category;
|
||||||
|
use dioxus::core_macro::rsx;
|
||||||
|
use dioxus::dioxus_core::Element;
|
||||||
|
use dioxus::prelude::*;
|
||||||
|
use crate::components::pages::category_page::CategoryPage;
|
||||||
|
|
||||||
|
#[component]
|
||||||
|
pub(crate) fn CategoryDonePage() -> Element {
|
||||||
|
rsx! {
|
||||||
|
CategoryPage {
|
||||||
|
category: Category::Done,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
14
src/components/pages/category_inbox_page.rs
Normal file
14
src/components/pages/category_inbox_page.rs
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
use crate::models::category::Category;
|
||||||
|
use dioxus::core_macro::rsx;
|
||||||
|
use dioxus::dioxus_core::Element;
|
||||||
|
use dioxus::prelude::*;
|
||||||
|
use crate::components::pages::category_page::CategoryPage;
|
||||||
|
|
||||||
|
#[component]
|
||||||
|
pub(crate) fn CategoryInboxPage() -> Element {
|
||||||
|
rsx! {
|
||||||
|
CategoryPage {
|
||||||
|
category: Category::Inbox,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
14
src/components/pages/category_long_term_page.rs
Normal file
14
src/components/pages/category_long_term_page.rs
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
use crate::models::category::Category;
|
||||||
|
use dioxus::core_macro::rsx;
|
||||||
|
use dioxus::dioxus_core::Element;
|
||||||
|
use dioxus::prelude::*;
|
||||||
|
use crate::components::pages::category_page::CategoryPage;
|
||||||
|
|
||||||
|
#[component]
|
||||||
|
pub(crate) fn CategoryLongTermPage() -> Element {
|
||||||
|
rsx! {
|
||||||
|
CategoryPage {
|
||||||
|
category: Category::LongTerm,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
14
src/components/pages/category_next_steps_page.rs
Normal file
14
src/components/pages/category_next_steps_page.rs
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
use crate::models::category::Category;
|
||||||
|
use dioxus::core_macro::rsx;
|
||||||
|
use dioxus::dioxus_core::Element;
|
||||||
|
use dioxus::prelude::*;
|
||||||
|
use crate::components::pages::category_page::CategoryPage;
|
||||||
|
|
||||||
|
#[component]
|
||||||
|
pub(crate) fn CategoryNextStepsPage() -> Element {
|
||||||
|
rsx! {
|
||||||
|
CategoryPage {
|
||||||
|
category: Category::NextSteps,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
33
src/components/pages/category_page.rs
Normal file
33
src/components/pages/category_page.rs
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
use crate::components::task_list::TaskList;
|
||||||
|
use crate::models::category::Category;
|
||||||
|
use crate::query::tasks::use_tasks_in_category_query;
|
||||||
|
use crate::query::QueryValue;
|
||||||
|
use dioxus::core_macro::rsx;
|
||||||
|
use dioxus::dioxus_core::Element;
|
||||||
|
use dioxus::prelude::*;
|
||||||
|
use dioxus_query::prelude::QueryResult;
|
||||||
|
|
||||||
|
#[component]
|
||||||
|
pub(crate) fn CategoryPage(category: Category) -> Element {
|
||||||
|
let tasks_query = use_tasks_in_category_query(category);
|
||||||
|
let tasks_query_result = tasks_query.result();
|
||||||
|
|
||||||
|
match tasks_query_result.value() {
|
||||||
|
QueryResult::Ok(QueryValue::Tasks(tasks))
|
||||||
|
| QueryResult::Loading(Some(QueryValue::Tasks(tasks))) => rsx! {
|
||||||
|
TaskList {
|
||||||
|
tasks: tasks.clone(),
|
||||||
|
class: "pb-36"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
QueryResult::Loading(None) => rsx! {
|
||||||
|
// TODO: Add a loading indicator.
|
||||||
|
},
|
||||||
|
QueryResult::Err(errors) => rsx! {
|
||||||
|
div {
|
||||||
|
"Errors occurred: {errors:?}"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
value => panic!("Unexpected query result: {value:?}")
|
||||||
|
}
|
||||||
|
}
|
14
src/components/pages/category_someday_maybe_page.rs
Normal file
14
src/components/pages/category_someday_maybe_page.rs
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
use crate::models::category::Category;
|
||||||
|
use dioxus::core_macro::rsx;
|
||||||
|
use dioxus::dioxus_core::Element;
|
||||||
|
use dioxus::prelude::*;
|
||||||
|
use crate::components::pages::category_page::CategoryPage;
|
||||||
|
|
||||||
|
#[component]
|
||||||
|
pub(crate) fn CategorySomedayMaybePage() -> Element {
|
||||||
|
rsx! {
|
||||||
|
CategoryPage {
|
||||||
|
category: Category::SomedayMaybe,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
160
src/components/pages/category_today_page.rs
Normal file
160
src/components/pages/category_today_page.rs
Normal file
@ -0,0 +1,160 @@
|
|||||||
|
use crate::components::task_list::TaskList;
|
||||||
|
use crate::models::category::Category;
|
||||||
|
use crate::models::task::Task;
|
||||||
|
use crate::query::tasks::use_tasks_in_category_query;
|
||||||
|
use crate::query::QueryValue;
|
||||||
|
use chrono::{Local, Locale};
|
||||||
|
use dioxus::prelude::*;
|
||||||
|
use dioxus_query::prelude::QueryResult;
|
||||||
|
|
||||||
|
#[component]
|
||||||
|
pub(crate) fn CategoryTodayPage() -> Element {
|
||||||
|
let today_date = Local::now().date_naive();
|
||||||
|
|
||||||
|
let calendar_tasks_query = use_tasks_in_category_query(Category::Calendar {
|
||||||
|
date: today_date,
|
||||||
|
reoccurrence: None,
|
||||||
|
time: None,
|
||||||
|
});
|
||||||
|
let calendar_tasks_query_result = calendar_tasks_query.result();
|
||||||
|
|
||||||
|
let long_term_tasks_query = use_tasks_in_category_query(Category::LongTerm);
|
||||||
|
let long_term_tasks_query_result = long_term_tasks_query.result();
|
||||||
|
|
||||||
|
rsx! {
|
||||||
|
div {
|
||||||
|
class: "pt-4 flex flex-col gap-8",
|
||||||
|
match long_term_tasks_query_result.value() {
|
||||||
|
QueryResult::Ok(QueryValue::Tasks(tasks))
|
||||||
|
| QueryResult::Loading(Some(QueryValue::Tasks(tasks))) => rsx! {
|
||||||
|
div {
|
||||||
|
class: "flex flex-col gap-4",
|
||||||
|
div {
|
||||||
|
class: "px-8 flex flex-row items-center gap-2 font-bold",
|
||||||
|
i {
|
||||||
|
class: "fa-solid fa-water text-xl w-6 text-center"
|
||||||
|
}
|
||||||
|
div {
|
||||||
|
class: "mt-1",
|
||||||
|
"Long-term"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
div {
|
||||||
|
for task in tasks {
|
||||||
|
div {
|
||||||
|
key: "{task.id()}",
|
||||||
|
class: format!(
|
||||||
|
"px-8 pt-5 {} flex flex-row gap-4",
|
||||||
|
if task.deadline().is_some() {
|
||||||
|
"pb-0.5"
|
||||||
|
} else {
|
||||||
|
"pb-5"
|
||||||
|
}
|
||||||
|
),
|
||||||
|
div {
|
||||||
|
class: "flex flex-col",
|
||||||
|
div {
|
||||||
|
class: "mt grow font-medium",
|
||||||
|
{task.title()}
|
||||||
|
},
|
||||||
|
div {
|
||||||
|
class: "flex flex-row gap-3",
|
||||||
|
if let Some(deadline) = task.deadline() {
|
||||||
|
div {
|
||||||
|
class: "text-sm text-zinc-400",
|
||||||
|
i {
|
||||||
|
class: "fa-solid fa-bomb"
|
||||||
|
},
|
||||||
|
{deadline.format(" %m. %d.").to_string()}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
QueryResult::Loading(None) => rsx! {
|
||||||
|
// TODO: Add a loading indicator.
|
||||||
|
},
|
||||||
|
QueryResult::Err(errors) => rsx! {
|
||||||
|
div {
|
||||||
|
"Errors occurred: {errors:?}"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
value => panic!("Unexpected query result: {value:?}")
|
||||||
|
}
|
||||||
|
match calendar_tasks_query_result.value() {
|
||||||
|
QueryResult::Ok(QueryValue::Tasks(tasks))
|
||||||
|
| QueryResult::Loading(Some(QueryValue::Tasks(tasks))) => {
|
||||||
|
let today_tasks = tasks.iter().filter(|task| {
|
||||||
|
if let Category::Calendar { date, .. } = task.category() {
|
||||||
|
*date == today_date
|
||||||
|
} else {
|
||||||
|
panic!("Unexpected category.");
|
||||||
|
}
|
||||||
|
}).cloned().collect::<Vec<Task>>();
|
||||||
|
let overdue_tasks = tasks.iter().filter(|task| {
|
||||||
|
if let Category::Calendar { date, .. } = task.category() {
|
||||||
|
*date < today_date
|
||||||
|
} else {
|
||||||
|
panic!("Unexpected category.");
|
||||||
|
}
|
||||||
|
}).cloned().collect::<Vec<Task>>();
|
||||||
|
|
||||||
|
rsx! {
|
||||||
|
if !overdue_tasks.is_empty() {
|
||||||
|
div {
|
||||||
|
class: "flex flex-col gap-4",
|
||||||
|
div {
|
||||||
|
class: "px-8 flex flex-row items-center gap-2 font-bold",
|
||||||
|
i {
|
||||||
|
class: "fa-solid fa-calendar-xmark text-xl w-6 text-center"
|
||||||
|
}
|
||||||
|
div {
|
||||||
|
class: "mt-1",
|
||||||
|
"Overdue"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
TaskList {
|
||||||
|
tasks: overdue_tasks,
|
||||||
|
class: "pb-3"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
div {
|
||||||
|
class: "flex flex-col gap-4",
|
||||||
|
div {
|
||||||
|
class: "px-8 flex flex-row items-center gap-2 font-bold",
|
||||||
|
i {
|
||||||
|
class: "fa-solid fa-calendar-check text-xl w-6 text-center"
|
||||||
|
}
|
||||||
|
div {
|
||||||
|
class: "mt-1",
|
||||||
|
{
|
||||||
|
today_date
|
||||||
|
.format_localized("Today, %A %-d. %B", Locale::en_US)
|
||||||
|
.to_string()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
TaskList {
|
||||||
|
tasks: today_tasks
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
QueryResult::Loading(None) => rsx! {
|
||||||
|
// TODO: Add a loading indicator.
|
||||||
|
},
|
||||||
|
QueryResult::Err(errors) => rsx! {
|
||||||
|
div {
|
||||||
|
"Errors occurred: {errors:?}"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
value => panic!("Unexpected query result: {value:?}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
14
src/components/pages/category_trash_page.rs
Normal file
14
src/components/pages/category_trash_page.rs
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
use crate::models::category::Category;
|
||||||
|
use dioxus::core_macro::rsx;
|
||||||
|
use dioxus::dioxus_core::Element;
|
||||||
|
use dioxus::prelude::*;
|
||||||
|
use crate::components::pages::category_page::CategoryPage;
|
||||||
|
|
||||||
|
#[component]
|
||||||
|
pub(crate) fn CategoryTrashPage() -> Element {
|
||||||
|
rsx! {
|
||||||
|
CategoryPage {
|
||||||
|
category: Category::Trash,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
14
src/components/pages/category_waiting_for_page.rs
Normal file
14
src/components/pages/category_waiting_for_page.rs
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
use crate::models::category::Category;
|
||||||
|
use dioxus::core_macro::rsx;
|
||||||
|
use dioxus::dioxus_core::Element;
|
||||||
|
use dioxus::prelude::*;
|
||||||
|
use crate::components::pages::category_page::CategoryPage;
|
||||||
|
|
||||||
|
#[component]
|
||||||
|
pub(crate) fn CategoryWaitingForPage() -> Element {
|
||||||
|
rsx! {
|
||||||
|
CategoryPage {
|
||||||
|
category: Category::WaitingFor(String::new()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
12
src/components/pages/mod.rs
Normal file
12
src/components/pages/mod.rs
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
pub(crate) mod category_inbox_page;
|
||||||
|
pub(crate) mod category_calendar_page;
|
||||||
|
pub(crate) mod category_today_page;
|
||||||
|
pub(crate) mod category_waiting_for_page;
|
||||||
|
pub(crate) mod category_long_term_page;
|
||||||
|
pub(crate) mod category_next_steps_page;
|
||||||
|
pub(crate) mod category_someday_maybe_page;
|
||||||
|
pub(crate) mod category_done_page;
|
||||||
|
pub(crate) mod category_trash_page;
|
||||||
|
pub(crate) mod not_found_page;
|
||||||
|
pub(crate) mod projects_page;
|
||||||
|
pub(crate) mod category_page;
|
8
src/components/pages/not_found_page.rs
Normal file
8
src/components/pages/not_found_page.rs
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
use dioxus::prelude::*;
|
||||||
|
|
||||||
|
#[component]
|
||||||
|
pub(crate) fn NotFoundPage(route: Vec<String>) -> Element {
|
||||||
|
rsx! {
|
||||||
|
{"404"}
|
||||||
|
}
|
||||||
|
}
|
36
src/components/pages/projects_page.rs
Normal file
36
src/components/pages/projects_page.rs
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
use dioxus::prelude::*;
|
||||||
|
use dioxus_query::prelude::QueryResult;
|
||||||
|
use crate::query::projects::use_projects_query;
|
||||||
|
use crate::query::QueryValue;
|
||||||
|
|
||||||
|
#[component]
|
||||||
|
pub(crate) fn ProjectsPage() -> Element {
|
||||||
|
let projects_query = use_projects_query();
|
||||||
|
|
||||||
|
rsx! {
|
||||||
|
match projects_query.result().value() {
|
||||||
|
QueryResult::Ok(QueryValue::Projects(projects))
|
||||||
|
| QueryResult::Loading(Some(QueryValue::Projects(projects))) => rsx! {
|
||||||
|
div {
|
||||||
|
class: "flex flex-col",
|
||||||
|
for project in projects {
|
||||||
|
div {
|
||||||
|
key: "{project.id()}",
|
||||||
|
class: "px-8 py-4",
|
||||||
|
{project.title()}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
QueryResult::Loading(None) => rsx! {
|
||||||
|
// TODO: Add a loading indicator.
|
||||||
|
},
|
||||||
|
QueryResult::Err(errors) => rsx! {
|
||||||
|
div {
|
||||||
|
"Errors occurred: {errors:?}"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
value => panic!("Unexpected query result: {value:?}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -3,9 +3,13 @@ use crate::server::projects::create_project;
|
|||||||
use dioxus::core_macro::{component, rsx};
|
use dioxus::core_macro::{component, rsx};
|
||||||
use dioxus::dioxus_core::Element;
|
use dioxus::dioxus_core::Element;
|
||||||
use dioxus::prelude::*;
|
use dioxus::prelude::*;
|
||||||
|
use dioxus_query::prelude::use_query_client;
|
||||||
|
use crate::query::{QueryErrors, QueryKey, QueryValue};
|
||||||
|
|
||||||
#[component]
|
#[component]
|
||||||
pub(crate) fn ProjectForm() -> Element {
|
pub(crate) fn ProjectForm(on_successful_submit: EventHandler<()>) -> Element {
|
||||||
|
let query_client = use_query_client::<QueryValue, QueryErrors, QueryKey>();
|
||||||
|
|
||||||
rsx! {
|
rsx! {
|
||||||
form {
|
form {
|
||||||
onsubmit: move |event| {
|
onsubmit: move |event| {
|
||||||
@ -14,17 +18,39 @@ pub(crate) fn ProjectForm() -> Element {
|
|||||||
event.values().get("title").unwrap().as_value()
|
event.values().get("title").unwrap().as_value()
|
||||||
);
|
);
|
||||||
let _ = create_project(new_project).await;
|
let _ = create_project(new_project).await;
|
||||||
|
query_client.invalidate_queries(&[
|
||||||
|
QueryKey::Projects
|
||||||
|
]);
|
||||||
|
on_successful_submit.call(());
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
input {
|
class: "p-4 flex flex-col gap-4",
|
||||||
r#type: "text",
|
div {
|
||||||
name: "title",
|
class: "flex flex-row items-center gap-3",
|
||||||
required: true,
|
label {
|
||||||
placeholder: "title"
|
r#for: "input_title",
|
||||||
|
class: "min-w-6 text-center",
|
||||||
|
i {
|
||||||
|
class: "fa-solid fa-pen-clip text-zinc-400/50"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
input {
|
||||||
|
r#type: "text",
|
||||||
|
name: "title",
|
||||||
|
required: true,
|
||||||
|
class: "py-2 px-3 grow bg-zinc-800/50 rounded-lg",
|
||||||
|
id: "input_title"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
button {
|
div {
|
||||||
r#type: "submit",
|
class: "flex flex-row justify-end mt-auto",
|
||||||
"create"
|
button {
|
||||||
|
r#type: "submit",
|
||||||
|
class: "py-2 px-4 bg-zinc-300/50 rounded-lg",
|
||||||
|
i {
|
||||||
|
class: "fa-solid fa-floppy-disk"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
76
src/components/reoccurrence_input.rs
Normal file
76
src/components/reoccurrence_input.rs
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
use crate::models::category::ReoccurrenceInterval;
|
||||||
|
use dioxus::core_macro::rsx;
|
||||||
|
use dioxus::dioxus_core::Element;
|
||||||
|
use dioxus::prelude::*;
|
||||||
|
|
||||||
|
#[component]
|
||||||
|
pub(crate) fn ReoccurrenceIntervalInput(
|
||||||
|
reoccurrence_interval: Signal<Option<ReoccurrenceInterval>>,
|
||||||
|
class_buttons: Option<&'static str>
|
||||||
|
) -> Element {
|
||||||
|
rsx! {
|
||||||
|
button {
|
||||||
|
r#type: "button",
|
||||||
|
class: format!(
|
||||||
|
"py-2 rounded-lg {} {}",
|
||||||
|
class_buttons.unwrap_or(""),
|
||||||
|
if reoccurrence_interval().is_none() { "bg-zinc-500/50" }
|
||||||
|
else { "bg-zinc-800/50" }
|
||||||
|
),
|
||||||
|
onclick: move |_| {
|
||||||
|
reoccurrence_interval.set(None);
|
||||||
|
},
|
||||||
|
i {
|
||||||
|
class: "fa-solid fa-ban"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
button {
|
||||||
|
r#type: "button",
|
||||||
|
class: format!(
|
||||||
|
"py-2 rounded-lg {} {}",
|
||||||
|
class_buttons.unwrap_or(""),
|
||||||
|
if let Some(ReoccurrenceInterval::Day) = reoccurrence_interval()
|
||||||
|
{ "bg-zinc-500/50" }
|
||||||
|
else { "bg-zinc-800/50" }
|
||||||
|
),
|
||||||
|
onclick: move |_| {
|
||||||
|
reoccurrence_interval.set(Some(ReoccurrenceInterval::Day))
|
||||||
|
},
|
||||||
|
i {
|
||||||
|
class: "fa-solid fa-sun"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
button {
|
||||||
|
r#type: "button",
|
||||||
|
class: format!(
|
||||||
|
"py-2 rounded-lg {} {}",
|
||||||
|
class_buttons.unwrap_or(""),
|
||||||
|
if let Some(ReoccurrenceInterval::Month) = reoccurrence_interval()
|
||||||
|
{ "bg-zinc-500/50" }
|
||||||
|
else { "bg-zinc-800/50" }
|
||||||
|
),
|
||||||
|
onclick: move |_| {
|
||||||
|
reoccurrence_interval.set(Some(ReoccurrenceInterval::Month))
|
||||||
|
},
|
||||||
|
i {
|
||||||
|
class: "fa-solid fa-moon"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
button {
|
||||||
|
r#type: "button",
|
||||||
|
class: format!(
|
||||||
|
"py-2 rounded-lg {} {}",
|
||||||
|
class_buttons.unwrap_or(""),
|
||||||
|
if let Some(ReoccurrenceInterval::Year) = reoccurrence_interval()
|
||||||
|
{ "bg-zinc-500/50" }
|
||||||
|
else { "bg-zinc-800/50" }
|
||||||
|
),
|
||||||
|
onclick: move |_| {
|
||||||
|
reoccurrence_interval.set(Some(ReoccurrenceInterval::Year))
|
||||||
|
},
|
||||||
|
i {
|
||||||
|
class: "fa-solid fa-earth-europe"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
11
src/components/sticky_bottom.rs
Normal file
11
src/components/sticky_bottom.rs
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
use dioxus::prelude::*;
|
||||||
|
|
||||||
|
#[component]
|
||||||
|
pub(crate) fn StickyBottom(children: Element) -> Element {
|
||||||
|
rsx! {
|
||||||
|
div {
|
||||||
|
class: "fixed bottom-0 left-0 right-0 flex flex-col",
|
||||||
|
{children}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,45 +1,68 @@
|
|||||||
use chrono::Duration;
|
use crate::components::category_input::CategoryInput;
|
||||||
use crate::models::category::{CalendarTime, Category};
|
use crate::components::reoccurrence_input::ReoccurrenceIntervalInput;
|
||||||
|
use crate::models::category::{CalendarTime, Category, Reoccurrence};
|
||||||
use crate::models::task::NewTask;
|
use crate::models::task::NewTask;
|
||||||
use crate::server::projects::get_projects;
|
use crate::server::projects::get_projects;
|
||||||
use crate::server::tasks::create_task;
|
use crate::server::tasks::create_task;
|
||||||
|
use chrono::{Duration, NaiveDate};
|
||||||
use dioxus::core_macro::{component, rsx};
|
use dioxus::core_macro::{component, rsx};
|
||||||
use dioxus::dioxus_core::Element;
|
use dioxus::dioxus_core::Element;
|
||||||
use dioxus::prelude::*;
|
use dioxus::prelude::*;
|
||||||
|
use dioxus_query::prelude::use_query_client;
|
||||||
|
use crate::query::{QueryErrors, QueryKey, QueryValue};
|
||||||
|
use crate::route::Route;
|
||||||
|
|
||||||
|
const REMINDER_OFFSETS: [Option<Duration>; 17] = [
|
||||||
|
None,
|
||||||
|
Some(Duration::days(1)),
|
||||||
|
Some(Duration::hours(12)),
|
||||||
|
Some(Duration::hours(11)),
|
||||||
|
Some(Duration::hours(10)),
|
||||||
|
Some(Duration::hours(9)),
|
||||||
|
Some(Duration::hours(8)),
|
||||||
|
Some(Duration::hours(7)),
|
||||||
|
Some(Duration::hours(6)),
|
||||||
|
Some(Duration::hours(5)),
|
||||||
|
Some(Duration::hours(4)),
|
||||||
|
Some(Duration::hours(3)),
|
||||||
|
Some(Duration::hours(2)),
|
||||||
|
Some(Duration::hours(1)),
|
||||||
|
Some(Duration::minutes(30)),
|
||||||
|
Some(Duration::minutes(10)),
|
||||||
|
Some(Duration::zero()),
|
||||||
|
];
|
||||||
|
|
||||||
#[component]
|
#[component]
|
||||||
pub(crate) fn TaskForm() -> Element {
|
pub(crate) fn TaskForm(on_successful_submit: EventHandler<()>) -> Element {
|
||||||
let categories = vec![
|
|
||||||
Category::Inbox,
|
|
||||||
Category::SomedayMaybe,
|
|
||||||
Category::WaitingFor(String::new()),
|
|
||||||
Category::NextSteps,
|
|
||||||
Category::Calendar {
|
|
||||||
date: chrono::Local::now().date_naive(),
|
|
||||||
reoccurance_interval: None,
|
|
||||||
time: None,
|
|
||||||
},
|
|
||||||
Category::LongTerm,
|
|
||||||
];
|
|
||||||
let projects = use_server_future(get_projects)?.unwrap().unwrap();
|
let projects = use_server_future(get_projects)?.unwrap().unwrap();
|
||||||
|
|
||||||
let mut selected_category_index = use_signal::<usize>(|| 0);
|
let route = use_route::<Route>();
|
||||||
let mut category_calendar_is_reoccurring = use_signal::<bool>(|| false);
|
let selected_category = use_signal(|| match route {
|
||||||
let mut category_calendar_has_time = use_signal::<bool>(|| false);
|
Route::CategorySomedayMaybePage => Category::SomedayMaybe,
|
||||||
let mut category_calendar_has_reminder = use_signal::<bool>(|| false);
|
Route::CategoryWaitingForPage => Category::WaitingFor(String::new()),
|
||||||
|
Route::CategoryNextStepsPage => Category::NextSteps,
|
||||||
|
Route::CategoryCalendarPage | Route::CategoryTodayPage => Category::Calendar {
|
||||||
|
date: NaiveDate::default(),
|
||||||
|
reoccurrence: None,
|
||||||
|
time: None,
|
||||||
|
},
|
||||||
|
Route::CategoryLongTermPage => Category::LongTerm,
|
||||||
|
_ => Category::Inbox,
|
||||||
|
});
|
||||||
|
let category_calendar_reoccurrence_interval = use_signal(|| None);
|
||||||
|
let mut category_calendar_has_time = use_signal(|| false);
|
||||||
|
let mut category_calendar_reminder_offset_index = use_signal(|| REMINDER_OFFSETS.len() - 1);
|
||||||
|
|
||||||
|
let query_client = use_query_client::<QueryValue, QueryErrors, QueryKey>();
|
||||||
|
|
||||||
rsx! {
|
rsx! {
|
||||||
form {
|
form {
|
||||||
onsubmit: move |event| {
|
onsubmit: move |event| {
|
||||||
let categories = categories.clone();
|
|
||||||
async move {
|
async move {
|
||||||
let new_task = NewTask::new(
|
let new_task = NewTask::new(
|
||||||
event.values().get("title").unwrap().as_value(),
|
event.values().get("title").unwrap().as_value(),
|
||||||
event.values().get("deadline").unwrap().as_value().parse().ok(),
|
event.values().get("deadline").unwrap().as_value().parse().ok(),
|
||||||
match &categories[
|
match &selected_category() {
|
||||||
event.values().get("category_index").unwrap()
|
|
||||||
.as_value().parse::<usize>().unwrap()
|
|
||||||
] {
|
|
||||||
Category::WaitingFor(_) => Category::WaitingFor(
|
Category::WaitingFor(_) => Category::WaitingFor(
|
||||||
event.values().get("category_waiting_for").unwrap()
|
event.values().get("category_waiting_for").unwrap()
|
||||||
.as_value()
|
.as_value()
|
||||||
@ -47,24 +70,24 @@ pub(crate) fn TaskForm() -> Element {
|
|||||||
Category::Calendar { .. } => Category::Calendar {
|
Category::Calendar { .. } => Category::Calendar {
|
||||||
date: event.values().get("category_calendar_date").unwrap()
|
date: event.values().get("category_calendar_date").unwrap()
|
||||||
.as_value().parse().unwrap(),
|
.as_value().parse().unwrap(),
|
||||||
reoccurance_interval:
|
reoccurrence: category_calendar_reoccurrence_interval().map(
|
||||||
event.values().get("category_calendar_is_reoccurring").map(
|
|reoccurrence_interval| Reoccurrence::new(
|
||||||
|_| Duration::days(
|
event.values().get("category_calendar_date").unwrap()
|
||||||
event.values().get("category_calendar_reoccurance_interval")
|
.as_value().parse().unwrap(),
|
||||||
|
reoccurrence_interval,
|
||||||
|
event.values().get("category_calendar_reoccurrence_length")
|
||||||
.unwrap().as_value().parse().unwrap()
|
.unwrap().as_value().parse().unwrap()
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
time: event.values().get("category_calendar_time").unwrap()
|
time: event.values().get("category_calendar_time").unwrap()
|
||||||
.as_value().parse().ok().map(|time|
|
.as_value().parse().ok().map(|time|
|
||||||
CalendarTime::new(
|
CalendarTime::new(
|
||||||
time,
|
time,
|
||||||
event.values().get("category_calendar_has_reminder").map(
|
REMINDER_OFFSETS[
|
||||||
|_| Duration::minutes(
|
event.values()
|
||||||
event.values()
|
.get("category_calendar_reminder_offset_index").unwrap()
|
||||||
.get("category_calendar_reminder_offset").unwrap()
|
.as_value().parse::<usize>().unwrap()
|
||||||
.as_value().parse().unwrap()
|
]
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
@ -74,148 +97,215 @@ pub(crate) fn TaskForm() -> Element {
|
|||||||
.as_value().parse::<i32>().ok().filter(|&id| id > 0),
|
.as_value().parse::<i32>().ok().filter(|&id| id > 0),
|
||||||
);
|
);
|
||||||
let _ = create_task(new_task).await;
|
let _ = create_task(new_task).await;
|
||||||
|
query_client.invalidate_queries(&[
|
||||||
|
QueryKey::Tasks,
|
||||||
|
QueryKey::TasksInCategory(selected_category())
|
||||||
|
]);
|
||||||
|
on_successful_submit.call(());
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
class: "p-4 flex flex-col gap-4",
|
class: "p-4 flex flex-col gap-4",
|
||||||
input {
|
div {
|
||||||
r#type: "text",
|
class: "flex flex-row items-center gap-3",
|
||||||
name: "title",
|
label {
|
||||||
required: true,
|
r#for: "input_title",
|
||||||
placeholder: "title",
|
class: "min-w-6 text-center",
|
||||||
class: "p-2 bg-neutral-700 rounded",
|
i {
|
||||||
},
|
class: "fa-solid fa-pen-clip text-zinc-400/50"
|
||||||
select {
|
|
||||||
name: "category_index",
|
|
||||||
oninput: move |event| {
|
|
||||||
selected_category_index.set(event.value().parse().unwrap());
|
|
||||||
},
|
|
||||||
class: "p-2 bg-neutral-700 rounded",
|
|
||||||
option {
|
|
||||||
value: 0,
|
|
||||||
"inbox"
|
|
||||||
},
|
|
||||||
option {
|
|
||||||
value: 1,
|
|
||||||
"someday maybe"
|
|
||||||
},
|
|
||||||
option {
|
|
||||||
value: 2,
|
|
||||||
"waiting for"
|
|
||||||
},
|
|
||||||
option {
|
|
||||||
value: 3,
|
|
||||||
"next steps"
|
|
||||||
},
|
|
||||||
option {
|
|
||||||
value: 4,
|
|
||||||
"calendar"
|
|
||||||
},
|
|
||||||
option {
|
|
||||||
value: 5,
|
|
||||||
"long term"
|
|
||||||
},
|
|
||||||
},
|
|
||||||
match categories[selected_category_index()] {
|
|
||||||
Category::WaitingFor(_) => rsx !{
|
|
||||||
input {
|
|
||||||
r#type: "text",
|
|
||||||
name: "category_waiting_for",
|
|
||||||
required: true,
|
|
||||||
class: "p-2 bg-neutral-700 rounded",
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Category::Calendar { .. } => rsx !{
|
input {
|
||||||
input {
|
r#type: "text",
|
||||||
r#type: "date",
|
name: "title",
|
||||||
name: "category_calendar_date",
|
required: true,
|
||||||
required: true,
|
class: "py-2 px-3 grow bg-zinc-800/50 rounded-lg",
|
||||||
class: "p-2 bg-neutral-700 rounded",
|
id: "input_title"
|
||||||
|
},
|
||||||
|
},
|
||||||
|
div {
|
||||||
|
class: "flex flex-row items-center gap-3",
|
||||||
|
label {
|
||||||
|
r#for: "input_project",
|
||||||
|
class: "min-w-6 text-center",
|
||||||
|
i {
|
||||||
|
class: "fa-solid fa-list text-zinc-400/50"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
select {
|
||||||
|
name: "project_id",
|
||||||
|
class: "px-3.5 py-2.5 bg-zinc-800/50 rounded-lg grow",
|
||||||
|
id: "input_project",
|
||||||
|
option {
|
||||||
|
value: 0,
|
||||||
|
"None"
|
||||||
},
|
},
|
||||||
|
for project in projects {
|
||||||
|
option {
|
||||||
|
value: project.id().to_string(),
|
||||||
|
{project.title()}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
div {
|
||||||
|
class: "flex flex-row items-center gap-3",
|
||||||
|
label {
|
||||||
|
r#for: "input_deadline",
|
||||||
|
class: "min-w-6 text-center",
|
||||||
|
i {
|
||||||
|
class: "fa-solid fa-bomb text-zinc-400/50"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
input {
|
||||||
|
r#type: "date",
|
||||||
|
name: "deadline",
|
||||||
|
class: "py-2 px-3 bg-zinc-800/50 rounded-lg grow basis-0",
|
||||||
|
id: "input_deadline"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
div {
|
||||||
|
class: "flex flex-row items-center gap-3",
|
||||||
|
label {
|
||||||
|
class: "min-w-6 text-center",
|
||||||
|
i {
|
||||||
|
class: "fa-solid fa-layer-group text-zinc-400/50"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
CategoryInput {
|
||||||
|
selected_category: selected_category,
|
||||||
|
class: "grow"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
match selected_category() {
|
||||||
|
Category::WaitingFor(_) => rsx! {
|
||||||
div {
|
div {
|
||||||
input {
|
class: "flex flex-row items-center gap-3",
|
||||||
r#type: "checkbox",
|
label {
|
||||||
name: "category_calendar_is_reoccurring",
|
r#for: "input_deadline",
|
||||||
id: "category_calendar_is_reoccurring",
|
class: "min-w-6 text-center",
|
||||||
onchange: move |event| {
|
i {
|
||||||
category_calendar_is_reoccurring.set(event.checked());
|
class: "fa-solid fa-hourglass-end text-zinc-400/50"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
label {
|
|
||||||
r#for: "category_calendar_is_reoccurring",
|
|
||||||
" is reoccurring"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
if category_calendar_is_reoccurring() {
|
|
||||||
input {
|
input {
|
||||||
r#type: "number",
|
r#type: "text",
|
||||||
name: "category_calendar_reoccurance_interval",
|
name: "category_waiting_for",
|
||||||
required: true,
|
required: true,
|
||||||
min: 1,
|
class: "py-2 px-3 bg-zinc-800/50 rounded-lg grow",
|
||||||
placeholder: "reoccurance interval (days)",
|
id: "input_category_waiting_for"
|
||||||
class: "p-2 bg-neutral-700 rounded",
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Category::Calendar { .. } => rsx! {
|
||||||
|
div {
|
||||||
|
class: "flex flex-row items-center gap-3",
|
||||||
|
label {
|
||||||
|
r#for: "input_category_calendar_date",
|
||||||
|
class: "min-w-6 text-center",
|
||||||
|
i {
|
||||||
|
class: "fa-solid fa-clock text-zinc-400/50"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
div {
|
||||||
|
class: "grow flex flex-row gap-2",
|
||||||
|
input {
|
||||||
|
r#type: "date",
|
||||||
|
name: "category_calendar_date",
|
||||||
|
required: true,
|
||||||
|
initial_value: chrono::Local::now().format("%Y-%m-%d").to_string(),
|
||||||
|
class: "py-2 px-3 bg-zinc-800/50 rounded-lg grow",
|
||||||
|
id: "input_category_calendar_date"
|
||||||
|
},
|
||||||
|
input {
|
||||||
|
r#type: "time",
|
||||||
|
name: "category_calendar_time",
|
||||||
|
class: "py-2 px-3 bg-zinc-800/50 rounded-lg grow",
|
||||||
|
id: "input_category_calendar_time",
|
||||||
|
oninput: move |event| {
|
||||||
|
category_calendar_has_time.set(!event.value().is_empty());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
input {
|
div {
|
||||||
r#type: "time",
|
class: "flex flex-row items-center gap-3",
|
||||||
name: "category_calendar_time",
|
label {
|
||||||
class: "p-2 bg-neutral-700 rounded",
|
r#for: "category_calendar_reoccurrence_length",
|
||||||
oninput: move |event| {
|
class: "min-w-6 text-center",
|
||||||
category_calendar_has_time.set(!event.value().is_empty());
|
i {
|
||||||
|
class: "fa-solid fa-repeat text-zinc-400/50"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
div {
|
||||||
|
class: "grow grid grid-cols-6 gap-2",
|
||||||
|
ReoccurrenceIntervalInput {
|
||||||
|
reoccurrence_interval: category_calendar_reoccurrence_interval
|
||||||
|
},
|
||||||
|
input {
|
||||||
|
r#type: "number",
|
||||||
|
inputmode: "numeric",
|
||||||
|
name: "category_calendar_reoccurrence_length",
|
||||||
|
disabled: category_calendar_reoccurrence_interval().is_none(),
|
||||||
|
required: true,
|
||||||
|
min: 1,
|
||||||
|
initial_value:
|
||||||
|
if category_calendar_reoccurrence_interval().is_none() { "" }
|
||||||
|
else { "1" },
|
||||||
|
class: "py-2 px-3 bg-zinc-800/50 rounded-lg col-span-2 text-right",
|
||||||
|
id: "category_calendar_reoccurrence_length"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
if category_calendar_has_time() {
|
if category_calendar_has_time() {
|
||||||
div {
|
div {
|
||||||
|
class: "flex flex-row items-center gap-3",
|
||||||
|
label {
|
||||||
|
r#for: "category_calendar_reminder_offset_index",
|
||||||
|
class: "min-w-6 text-center",
|
||||||
|
i {
|
||||||
|
class: "fa-solid fa-bell text-zinc-400/50"
|
||||||
|
}
|
||||||
|
},
|
||||||
input {
|
input {
|
||||||
r#type: "checkbox",
|
r#type: "range",
|
||||||
name: "category_calendar_has_reminder",
|
name: "category_calendar_reminder_offset_index",
|
||||||
value: 0,
|
min: 0,
|
||||||
|
max: REMINDER_OFFSETS.len() as i64 - 1,
|
||||||
|
initial_value: REMINDER_OFFSETS.len() as i64 - 1,
|
||||||
|
class: "grow input-range-reverse",
|
||||||
id: "category_calendar_has_reminder",
|
id: "category_calendar_has_reminder",
|
||||||
onchange: move |event| {
|
oninput: move |event| {
|
||||||
category_calendar_has_reminder.set(event.checked());
|
category_calendar_reminder_offset_index.set(
|
||||||
|
event.value().parse().unwrap()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
label {
|
label {
|
||||||
r#for: "category_calendar_has_reminder",
|
r#for: "category_calendar_reminder_offset_index",
|
||||||
" set a reminder"
|
class: "pr-3 min-w-16 text-right",
|
||||||
|
{REMINDER_OFFSETS[category_calendar_reminder_offset_index()].map(
|
||||||
|
|offset| if offset.num_hours() < 1 {
|
||||||
|
format!("{} min", offset.num_minutes())
|
||||||
|
} else {
|
||||||
|
format!("{} h", offset.num_hours())
|
||||||
|
}
|
||||||
|
).unwrap_or_else(|| "none".to_string())}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if category_calendar_has_reminder() {
|
|
||||||
input {
|
|
||||||
r#type: "number",
|
|
||||||
name: "category_calendar_reminder_offset",
|
|
||||||
required: true,
|
|
||||||
min: 0,
|
|
||||||
placeholder: "reminder offset (minutes)",
|
|
||||||
class: "p-2 bg-neutral-700 rounded",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
_ => None
|
_ => None
|
||||||
},
|
},
|
||||||
input {
|
div {
|
||||||
r#type: "date",
|
class: "flex flex-row justify-end mt-auto",
|
||||||
name: "deadline",
|
button {
|
||||||
class: "p-2 bg-neutral-700 rounded",
|
r#type: "submit",
|
||||||
},
|
class: "py-2 px-4 bg-zinc-300/50 rounded-lg",
|
||||||
select {
|
i {
|
||||||
name: "project_id",
|
class: "fa-solid fa-floppy-disk"
|
||||||
class: "p-2 bg-neutral-700 rounded",
|
|
||||||
option {
|
|
||||||
value: 0,
|
|
||||||
"none"
|
|
||||||
},
|
|
||||||
for project in projects {
|
|
||||||
option {
|
|
||||||
value: project.id().to_string(),
|
|
||||||
{project.title()}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
|
||||||
button {
|
|
||||||
r#type: "submit",
|
|
||||||
"create"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
66
src/components/task_list.rs
Normal file
66
src/components/task_list.rs
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
use crate::models::category::Category;
|
||||||
|
use crate::models::task::Task;
|
||||||
|
use dioxus::core_macro::rsx;
|
||||||
|
use dioxus::dioxus_core::Element;
|
||||||
|
use dioxus::prelude::*;
|
||||||
|
|
||||||
|
#[component]
|
||||||
|
pub(crate) fn TaskList(tasks: Vec<Task>, class: Option<&'static str>) -> Element {
|
||||||
|
rsx! {
|
||||||
|
div {
|
||||||
|
class: format!("flex flex-col {}", class.unwrap_or("")),
|
||||||
|
for task in tasks {
|
||||||
|
div {
|
||||||
|
key: "{task.id()}",
|
||||||
|
class: format!(
|
||||||
|
"px-8 pt-5 {} flex flex-row gap-4",
|
||||||
|
if task.deadline().is_some() {
|
||||||
|
"pb-0.5"
|
||||||
|
} else if let Category::Calendar { time, .. } = task.category() {
|
||||||
|
if time.is_some() {
|
||||||
|
"pb-0.5"
|
||||||
|
} else {
|
||||||
|
"pb-5"
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
"pb-5"
|
||||||
|
}
|
||||||
|
),
|
||||||
|
i {
|
||||||
|
class: "fa-regular fa-square text-3xl text-zinc-600",
|
||||||
|
},
|
||||||
|
div {
|
||||||
|
class: "flex flex-col",
|
||||||
|
div {
|
||||||
|
class: "mt-1 grow font-medium",
|
||||||
|
{task.title()}
|
||||||
|
},
|
||||||
|
div {
|
||||||
|
class: "flex flex-row gap-3",
|
||||||
|
if let Some(deadline) = task.deadline() {
|
||||||
|
div {
|
||||||
|
class: "text-sm text-zinc-400",
|
||||||
|
i {
|
||||||
|
class: "fa-solid fa-bomb"
|
||||||
|
},
|
||||||
|
{deadline.format(" %m. %d.").to_string()}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Category::Calendar { time, .. } = task.category() {
|
||||||
|
if let Some(calendar_time) = time {
|
||||||
|
div {
|
||||||
|
class: "text-sm text-zinc-400",
|
||||||
|
i {
|
||||||
|
class: "fa-solid fa-clock"
|
||||||
|
},
|
||||||
|
{calendar_time.time().format(" %k:%M").to_string()}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -4,6 +4,7 @@ mod models;
|
|||||||
mod route;
|
mod route;
|
||||||
mod schema;
|
mod schema;
|
||||||
mod server;
|
mod server;
|
||||||
|
mod query;
|
||||||
|
|
||||||
use components::app::App;
|
use components::app::App;
|
||||||
use dioxus::prelude::*;
|
use dioxus::prelude::*;
|
||||||
|
@ -1,10 +1,13 @@
|
|||||||
|
use std::hash::Hash;
|
||||||
|
use crate::schema::tasks;
|
||||||
use chrono::{Duration, NaiveDate, NaiveTime};
|
use chrono::{Duration, NaiveDate, NaiveTime};
|
||||||
use diesel::deserialize::FromSql;
|
use diesel::deserialize::FromSql;
|
||||||
use diesel::pg::{Pg, PgValue};
|
use diesel::pg::{Pg, PgValue};
|
||||||
use diesel::serialize::{Output, ToSql};
|
use diesel::serialize::{Output, ToSql};
|
||||||
use diesel::sql_types::Jsonb;
|
use diesel::sql_types::{Bool, Jsonb};
|
||||||
use diesel::{AsExpression, FromSqlRow};
|
use diesel::{AsExpression, BoxableExpression, FromSqlRow, PgJsonbExpressionMethods};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
use serde_json::json;
|
||||||
use serde_with::DurationSeconds;
|
use serde_with::DurationSeconds;
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
|
|
||||||
@ -18,8 +21,7 @@ pub enum Category {
|
|||||||
NextSteps,
|
NextSteps,
|
||||||
Calendar {
|
Calendar {
|
||||||
date: NaiveDate,
|
date: NaiveDate,
|
||||||
#[serde_as(as = "Option<DurationSeconds<i64>>")]
|
reoccurrence: Option<Reoccurrence>,
|
||||||
reoccurance_interval: Option<Duration>,
|
|
||||||
time: Option<CalendarTime>,
|
time: Option<CalendarTime>,
|
||||||
},
|
},
|
||||||
LongTerm,
|
LongTerm,
|
||||||
@ -27,20 +29,37 @@ pub enum Category {
|
|||||||
Trash,
|
Trash,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[serde_with::serde_as]
|
impl Category {
|
||||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
pub fn eq_sql_predicate(&self) -> Box<dyn BoxableExpression<tasks::table, Pg, SqlType=Bool>> {
|
||||||
pub struct CalendarTime {
|
use crate::schema::tasks::dsl::*;
|
||||||
time: NaiveTime,
|
|
||||||
#[serde_as(as = "Option<DurationSeconds<i64>>")]
|
|
||||||
reminder_offset: Option<Duration>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CalendarTime {
|
match self {
|
||||||
pub fn new(time: NaiveTime, reminder_offset: Option<Duration>) -> Self {
|
Category::Inbox => Box::new(category.contains(json!("Inbox"))),
|
||||||
Self { time, reminder_offset }
|
Category::SomedayMaybe => Box::new(category.contains(json!("SomedayMaybe"))),
|
||||||
|
Category::WaitingFor(_) => Box::new(category.has_key("WaitingFor")),
|
||||||
|
Category::NextSteps => Box::new(category.contains(json!("NextSteps"))),
|
||||||
|
Category::Calendar { .. } => Box::new(category.has_key("Calendar")),
|
||||||
|
Category::LongTerm => Box::new(category.contains(json!("LongTerm"))),
|
||||||
|
Category::Done => Box::new(category.contains(json!("Done"))),
|
||||||
|
Category::Trash => Box::new(category.contains(json!("Trash"))),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Hash for Category {
|
||||||
|
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
||||||
|
std::mem::discriminant(self).hash(state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PartialEq for Category {
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
std::mem::discriminant(self) == std::mem::discriminant(other)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Eq for Category {}
|
||||||
|
|
||||||
impl ToSql<Jsonb, Pg> for Category {
|
impl ToSql<Jsonb, Pg> for Category {
|
||||||
fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, Pg>) -> diesel::serialize::Result {
|
fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, Pg>) -> diesel::serialize::Result {
|
||||||
let json = serde_json::to_string(self)?;
|
let json = serde_json::to_string(self)?;
|
||||||
@ -63,3 +82,53 @@ impl FromSql<Jsonb, Pg> for Category {
|
|||||||
serde_json::from_str(str).map_err(Into::into)
|
serde_json::from_str(str).map_err(Into::into)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Hash, Clone, Debug)]
|
||||||
|
pub enum ReoccurrenceInterval {
|
||||||
|
Day,
|
||||||
|
Month,
|
||||||
|
Year,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Hash, Clone, Debug)]
|
||||||
|
pub struct Reoccurrence {
|
||||||
|
start_date: NaiveDate,
|
||||||
|
interval: ReoccurrenceInterval,
|
||||||
|
length: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Reoccurrence {
|
||||||
|
pub fn new(start_date: NaiveDate, interval: ReoccurrenceInterval, length: u32) -> Self {
|
||||||
|
Self { start_date, interval, length }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn interval(&self) -> &ReoccurrenceInterval {
|
||||||
|
&self.interval
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn length(&self) -> u32 {
|
||||||
|
self.length
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[serde_with::serde_as]
|
||||||
|
#[derive(Serialize, Deserialize, Hash, Clone, Debug)]
|
||||||
|
pub struct CalendarTime {
|
||||||
|
time: NaiveTime,
|
||||||
|
#[serde_as(as = "Option<DurationSeconds<i64>>")]
|
||||||
|
reminder_offset: Option<Duration>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CalendarTime {
|
||||||
|
pub fn new(time: NaiveTime, reminder_offset: Option<Duration>) -> Self {
|
||||||
|
Self { time, reminder_offset }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn time(&self) -> NaiveTime {
|
||||||
|
self.time
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn reminder_offset(&self) -> Option<Duration> {
|
||||||
|
self.reminder_offset
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -6,7 +6,7 @@ use validator::Validate;
|
|||||||
const TITLE_LENGTH_MIN: u64 = 1;
|
const TITLE_LENGTH_MIN: u64 = 1;
|
||||||
const TITLE_LENGTH_MAX: u64 = 255;
|
const TITLE_LENGTH_MAX: u64 = 255;
|
||||||
|
|
||||||
#[derive(Queryable, Selectable, Serialize, Deserialize, Clone, Debug)]
|
#[derive(Queryable, Selectable, Serialize, Deserialize, PartialEq, Clone, Debug)]
|
||||||
#[diesel(table_name = crate::schema::projects)]
|
#[diesel(table_name = crate::schema::projects)]
|
||||||
#[diesel(check_for_backend(diesel::pg::Pg))]
|
#[diesel(check_for_backend(diesel::pg::Pg))]
|
||||||
pub struct Project {
|
pub struct Project {
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
|
use crate::models::category::Category;
|
||||||
|
use crate::schema::tasks;
|
||||||
use diesel::prelude::*;
|
use diesel::prelude::*;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use validator::Validate;
|
use validator::Validate;
|
||||||
use crate::models::category::Category;
|
|
||||||
use crate::schema::tasks;
|
|
||||||
|
|
||||||
const TITLE_LENGTH_MIN: u64 = 1;
|
const TITLE_LENGTH_MIN: u64 = 1;
|
||||||
const TITLE_LENGTH_MAX: u64 = 255;
|
const TITLE_LENGTH_MAX: u64 = 255;
|
||||||
|
|
||||||
#[derive(Queryable, Selectable, Serialize, Deserialize, Clone, Debug)]
|
#[derive(Queryable, Selectable, Serialize, Deserialize, PartialEq, Clone, Debug)]
|
||||||
#[diesel(table_name = crate::schema::tasks)]
|
#[diesel(table_name = crate::schema::tasks)]
|
||||||
#[diesel(check_for_backend(diesel::pg::Pg))]
|
#[diesel(check_for_backend(diesel::pg::Pg))]
|
||||||
pub struct Task {
|
pub struct Task {
|
||||||
|
26
src/query/mod.rs
Normal file
26
src/query/mod.rs
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
use crate::errors::error::Error;
|
||||||
|
use crate::errors::error_vec::ErrorVec;
|
||||||
|
use crate::models::category::Category;
|
||||||
|
use crate::models::project::Project;
|
||||||
|
use crate::models::task::Task;
|
||||||
|
|
||||||
|
pub(crate) mod tasks;
|
||||||
|
pub(crate) mod projects;
|
||||||
|
|
||||||
|
#[derive(PartialEq, Debug)]
|
||||||
|
pub(crate) enum QueryValue {
|
||||||
|
Tasks(Vec<Task>),
|
||||||
|
Projects(Vec<Project>),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub(crate) enum QueryErrors {
|
||||||
|
Error(ErrorVec<Error>),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(PartialEq, Eq, Hash, Clone, Debug)]
|
||||||
|
pub(crate) enum QueryKey {
|
||||||
|
Tasks,
|
||||||
|
TasksInCategory(Category),
|
||||||
|
Projects,
|
||||||
|
}
|
20
src/query/projects.rs
Normal file
20
src/query/projects.rs
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
use crate::query::{QueryErrors, QueryKey, QueryValue};
|
||||||
|
use crate::server::projects::get_projects;
|
||||||
|
use dioxus::prelude::ServerFnError;
|
||||||
|
use dioxus_query::prelude::{use_get_query, QueryResult, UseQuery};
|
||||||
|
|
||||||
|
pub(crate) fn use_projects_query() -> UseQuery<QueryValue, QueryErrors, QueryKey> {
|
||||||
|
use_get_query([QueryKey::Projects, QueryKey::Tasks], fetch_projects)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn fetch_projects(keys: Vec<QueryKey>) -> QueryResult<QueryValue, QueryErrors> {
|
||||||
|
if let Some(QueryKey::Projects) = keys.first() {
|
||||||
|
match get_projects().await {
|
||||||
|
Ok(projects) => Ok(QueryValue::Projects(projects)),
|
||||||
|
Err(ServerFnError::WrappedServerError(errors)) => Err(QueryErrors::Error(errors)),
|
||||||
|
Err(error) => panic!("Unexpected error: {:?}", error)
|
||||||
|
}.into()
|
||||||
|
} else {
|
||||||
|
panic!("Unexpected query keys: {:?}", keys);
|
||||||
|
}
|
||||||
|
}
|
24
src/query/tasks.rs
Normal file
24
src/query/tasks.rs
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
use dioxus::prelude::ServerFnError;
|
||||||
|
use dioxus_query::prelude::{use_get_query, QueryResult, UseQuery};
|
||||||
|
use crate::models::category::Category;
|
||||||
|
use crate::query::{QueryErrors, QueryKey, QueryValue};
|
||||||
|
use crate::server::tasks::get_tasks_in_category;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
pub(crate) fn use_tasks_in_category_query(category: Category)
|
||||||
|
-> UseQuery<QueryValue, QueryErrors, QueryKey> {
|
||||||
|
use_get_query([QueryKey::TasksInCategory(category), QueryKey::Tasks], fetch_tasks_in_category)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn fetch_tasks_in_category(keys: Vec<QueryKey>) -> QueryResult<QueryValue, QueryErrors> {
|
||||||
|
if let Some(QueryKey::TasksInCategory(category)) = keys.first() {
|
||||||
|
match get_tasks_in_category(category.clone()).await {
|
||||||
|
Ok(tasks) => Ok(QueryValue::Tasks(tasks)),
|
||||||
|
Err(ServerFnError::WrappedServerError(errors)) => Err(QueryErrors::Error(errors)),
|
||||||
|
Err(error) => panic!("Unexpected error: {:?}", error)
|
||||||
|
}.into()
|
||||||
|
} else {
|
||||||
|
panic!("Unexpected query keys: {:?}", keys);
|
||||||
|
}
|
||||||
|
}
|
@ -1,8 +1,48 @@
|
|||||||
use crate::components::home::Home;
|
use crate::components::pages::category_inbox_page::CategoryInboxPage;
|
||||||
|
use crate::components::pages::category_next_steps_page::CategoryNextStepsPage;
|
||||||
|
use crate::components::pages::category_today_page::CategoryTodayPage;
|
||||||
|
use crate::components::pages::category_trash_page::CategoryTrashPage;
|
||||||
|
use crate::components::pages::category_waiting_for_page::CategoryWaitingForPage;
|
||||||
|
use crate::components::pages::category_someday_maybe_page::CategorySomedayMaybePage;
|
||||||
|
use crate::components::pages::category_done_page::CategoryDonePage;
|
||||||
|
use crate::components::pages::category_calendar_page::CategoryCalendarPage;
|
||||||
|
use crate::components::pages::category_long_term_page::CategoryLongTermPage;
|
||||||
|
use crate::components::pages::projects_page::ProjectsPage;
|
||||||
|
use crate::components::pages::not_found_page::NotFoundPage;
|
||||||
|
use crate::components::layout::Layout;
|
||||||
use dioxus::prelude::*;
|
use dioxus::prelude::*;
|
||||||
|
|
||||||
|
// All variants have the same postfix because they have to match the component names.
|
||||||
|
#[allow(clippy::enum_variant_names)]
|
||||||
#[derive(Clone, Routable, Debug, PartialEq)]
|
#[derive(Clone, Routable, Debug, PartialEq)]
|
||||||
|
#[rustfmt::skip]
|
||||||
pub(crate) enum Route {
|
pub(crate) enum Route {
|
||||||
#[route("/")]
|
#[layout(Layout)]
|
||||||
Home {},
|
#[redirect("/", || Route::CategoryTodayPage {})]
|
||||||
|
#[route("/today")]
|
||||||
|
CategoryTodayPage,
|
||||||
|
#[route("/inbox")]
|
||||||
|
CategoryInboxPage,
|
||||||
|
#[route("/someday-maybe")]
|
||||||
|
CategorySomedayMaybePage,
|
||||||
|
#[route("/waiting-for")]
|
||||||
|
CategoryWaitingForPage,
|
||||||
|
#[route("/next-steps")]
|
||||||
|
CategoryNextStepsPage,
|
||||||
|
#[route("/calendar")]
|
||||||
|
CategoryCalendarPage,
|
||||||
|
#[route("/long-term")]
|
||||||
|
CategoryLongTermPage,
|
||||||
|
#[route("/done")]
|
||||||
|
CategoryDonePage,
|
||||||
|
#[route("/trash")]
|
||||||
|
CategoryTrashPage,
|
||||||
|
#[route("/projects")]
|
||||||
|
ProjectsPage,
|
||||||
|
#[end_layout]
|
||||||
|
#[redirect("/", || Route::CategoryTodayPage)]
|
||||||
|
#[route("/:..route")]
|
||||||
|
NotFoundPage {
|
||||||
|
route: Vec<String>,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
@ -2,10 +2,11 @@ use crate::errors::error::Error;
|
|||||||
use crate::errors::error_vec::ErrorVec;
|
use crate::errors::error_vec::ErrorVec;
|
||||||
use crate::models::task::{NewTask, Task};
|
use crate::models::task::{NewTask, Task};
|
||||||
use crate::server::database_connection::establish_database_connection;
|
use crate::server::database_connection::establish_database_connection;
|
||||||
use diesel::{RunQueryDsl, SelectableHelper};
|
use diesel::{QueryDsl, RunQueryDsl, SelectableHelper};
|
||||||
use dioxus::prelude::*;
|
use dioxus::prelude::*;
|
||||||
use validator::Validate;
|
use validator::Validate;
|
||||||
use crate::errors::task_create_error::TaskCreateError;
|
use crate::errors::task_create_error::TaskCreateError;
|
||||||
|
use crate::models::category::Category;
|
||||||
|
|
||||||
#[server]
|
#[server]
|
||||||
pub(crate) async fn create_task(new_task: NewTask)
|
pub(crate) async fn create_task(new_task: NewTask)
|
||||||
@ -43,3 +44,24 @@ pub(crate) async fn create_task(new_task: NewTask)
|
|||||||
|
|
||||||
Ok(new_task)
|
Ok(new_task)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[server]
|
||||||
|
pub(crate) async fn get_tasks_in_category(filtered_category: Category)
|
||||||
|
-> Result<Vec<Task>, ServerFnError<ErrorVec<Error>>> {
|
||||||
|
use crate::schema::tasks::dsl::*;
|
||||||
|
|
||||||
|
let mut connection = establish_database_connection()
|
||||||
|
.map_err::<ErrorVec<Error>, _>(
|
||||||
|
|_| vec![Error::ServerInternal].into()
|
||||||
|
)?;
|
||||||
|
|
||||||
|
let results = tasks
|
||||||
|
.select(Task::as_select())
|
||||||
|
.filter(filtered_category.eq_sql_predicate())
|
||||||
|
.load::<Task>(&mut connection)
|
||||||
|
.map_err::<ErrorVec<Error>, _>(
|
||||||
|
|_| vec![Error::ServerInternal].into()
|
||||||
|
)?;
|
||||||
|
|
||||||
|
Ok(results)
|
||||||
|
}
|
||||||
|
@ -13,21 +13,3 @@ html, body, #main {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* stylelint-enable */
|
/* stylelint-enable */
|
||||||
|
|
||||||
@layer base {
|
|
||||||
@font-face {
|
|
||||||
font-family: Inter;
|
|
||||||
font-style: normal;
|
|
||||||
font-weight: 100 900;
|
|
||||||
font-display: swap;
|
|
||||||
src: url("/fonts/inter_variable.woff2") format("woff2");
|
|
||||||
}
|
|
||||||
|
|
||||||
@font-face {
|
|
||||||
font-family: Inter;
|
|
||||||
font-style: italic;
|
|
||||||
font-weight: 100 900;
|
|
||||||
font-display: swap;
|
|
||||||
src: url("/fonts/inter_variable_italic.woff2") format("woff2");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user