build: migrate to Dioxus 0.6 (#61)
This commit is contained in:
		| @@ -1,7 +1,6 @@ | ||||
| /.dioxus/ | ||||
| /.git/ | ||||
| /.github/ | ||||
| /dist/ | ||||
| /debug/ | ||||
| /node_modules/ | ||||
| /static/ | ||||
|   | ||||
							
								
								
									
										2
									
								
								.idea/dataSources.local.xml
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										2
									
								
								.idea/dataSources.local.xml
									
									
									
										generated
									
									
									
								
							| @@ -1,6 +1,6 @@ | ||||
| <?xml version="1.0" encoding="UTF-8"?> | ||||
| <project version="4"> | ||||
|   <component name="dataSourceStorageLocal" created-in="RR-242.21829.114"> | ||||
|   <component name="dataSourceStorageLocal" created-in="RR-243.21565.245"> | ||||
|     <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"> | ||||
|         <identifier-quote-string>"</identifier-quote-string> | ||||
|   | ||||
							
								
								
									
										3818
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										3818
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										49
									
								
								Cargo.toml
									
									
									
									
									
								
							
							
						
						
									
										49
									
								
								Cargo.toml
									
									
									
									
									
								
							| @@ -7,30 +7,39 @@ edition = "2021" | ||||
| # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html | ||||
|  | ||||
| [dependencies] | ||||
| dioxus = { version = "0.6.0", features = ["fullstack", "router"] } | ||||
| dioxus-query = "0.6.0" | ||||
| dioxus-i18n = "0.3.0" | ||||
|  | ||||
| async-std = "1.12.0" | ||||
| chrono = { version = "0.4.38", features = ["serde", "unstable-locales"] } | ||||
| diesel = { version = "2.2.2", features = ["chrono", "postgres", "postgres_backend", "serde_json"] } | ||||
|  | ||||
| dioxus = { version = "0.5", features = ["fullstack", "router"] } | ||||
|  | ||||
| # Debug | ||||
| dioxus-logger = "0.5.1" | ||||
| dotenvy = "0.15.7" | ||||
| serde = "1.0.208" | ||||
| validator = { version = "0.18.1", features = ["derive"] } | ||||
| serde_json = "1.0.125" | ||||
| tracing = "0.1.40" | ||||
| tracing-wasm = "0.2.1" | ||||
| serde_with = { version = "3.9.0", features = ["chrono_0_4"] } | ||||
| async-std = "1.12.0" | ||||
| dioxus-query = "0.5.1" | ||||
| time = "0.3.36" | ||||
| dioxus-sdk = { version = "0.5.0", features = ["i18n"] } | ||||
| unic-langid-impl = "0.9.5" | ||||
| voca_rs = "1.15.2" | ||||
| diesel_migrations = { version = "2.2.0", features = ["postgres"] } | ||||
| dotenvy = "0.15.7" | ||||
| feruca = "0.10.0" | ||||
| serde = "1.0.208" | ||||
| serde_json = "1.0.125" | ||||
| serde_with = { version = "3.9.0", features = ["chrono_0_4"] } | ||||
| time = "0.3.36" | ||||
| tracing = "0.1.40" | ||||
| unic-langid-impl = { version = "0.9.5", features = ["serde"] } | ||||
| validator = { version = "0.19.0", features = ["derive"] } | ||||
| voca_rs = "1.15.2" | ||||
|  | ||||
| [features] | ||||
| default = [] | ||||
| server = ["dioxus/axum"] | ||||
| default = ["web"] | ||||
| desktop = ["dioxus/desktop"] | ||||
| mobile = ["dioxus/mobile"] | ||||
| web = ["dioxus/web"] | ||||
|  | ||||
| [profile] | ||||
|  | ||||
| [profile.wasm-dev] | ||||
| inherits = "dev" | ||||
| opt-level = 1 | ||||
|  | ||||
| [profile.server-dev] | ||||
| inherits = "dev" | ||||
|  | ||||
| [profile.android-dev] | ||||
| inherits = "dev" | ||||
|   | ||||
| @@ -30,13 +30,7 @@ watch_path = ["src", "assets"] | ||||
| [web.resource] | ||||
|  | ||||
| # CSS style file | ||||
|  | ||||
| style = [ | ||||
|     "/styles/tailwind_output.css", | ||||
|     "/styles/fonts.css", | ||||
|     "/styles/input_number_arrows.css", | ||||
|     "/styles/input_range.css" | ||||
| ] | ||||
| style = [] | ||||
|  | ||||
| # Javascript code file | ||||
| script = ["https://kit.fontawesome.com/3c1b409f8f.js"] | ||||
|   | ||||
| @@ -4,7 +4,7 @@ | ||||
|         font-style: normal; | ||||
|         font-weight: 100 900; | ||||
|         font-display: swap; | ||||
|         src: url("/fonts/inter_variable.woff2") format("woff2"); | ||||
|         src: url("/assets/fonts/inter_variable.woff2") format("woff2"); | ||||
|     } | ||||
|  | ||||
|     @font-face { | ||||
| @@ -12,6 +12,6 @@ | ||||
|         font-style: italic; | ||||
|         font-weight: 100 900; | ||||
|         font-display: swap; | ||||
|         src: url("/fonts/inter_variable_italic.woff2") format("woff2"); | ||||
|         src: url("/assets/fonts/inter_variable_italic.woff2") format("woff2"); | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -11,7 +11,6 @@ services: | ||||
|       - ./Cargo.toml:/srv/app/Cargo.toml | ||||
|       - ./diesel.toml:/srv/app/diesel.toml | ||||
|       - ./Dioxus.toml:/srv/app/Dioxus.toml | ||||
|       - ./index.html:/srv/app/index.html | ||||
|       - ./package.json:/srv/app/package.json | ||||
|       - ./package-lock.json:/srv/app/package-lock.json | ||||
|     restart: always | ||||
|   | ||||
| @@ -1,4 +1,4 @@ | ||||
| FROM rust:1.80-bookworm | ||||
| FROM rust:1.83-bookworm | ||||
|  | ||||
| RUN rustup target add wasm32-unknown-unknown && \ | ||||
|     cargo install dioxus-cli diesel_cli && \ | ||||
| @@ -16,7 +16,7 @@ RUN chown -R 1000:1000 /srv/app && \ | ||||
|     mkdir -p /.local/share/dioxus && \ | ||||
|     chown -R 1000:1000 /.local/share/dioxus | ||||
|  | ||||
| HEALTHCHECK CMD curl --fail http://localhost:8000 || exit 1 | ||||
| HEALTHCHECK CMD curl --fail -H "Accept: text/html" http://localhost:8000 || exit 1 | ||||
|  | ||||
| USER 1000:1000 | ||||
|  | ||||
|   | ||||
| @@ -14,7 +14,7 @@ stdout_logfile_maxbytes=0 | ||||
| redirect_stderr=true | ||||
|  | ||||
| [program:dx] | ||||
| command=dx serve | ||||
| command=dx serve --addr 0.0.0.0 --port 8000 | ||||
| directory=/srv/app | ||||
| autostart=true | ||||
| autorestart=true | ||||
|   | ||||
| @@ -1,4 +1,4 @@ | ||||
| FROM rust:1.80-bookworm AS builder | ||||
| FROM rust:1.83-bookworm AS builder | ||||
|  | ||||
| RUN rustup target add wasm32-unknown-unknown && \ | ||||
|     cargo install dioxus-cli diesel_cli && \ | ||||
| @@ -15,15 +15,17 @@ FROM debian:bookworm-slim AS runner | ||||
|  | ||||
| RUN apt-get update && apt-get install -y libpq5=15.8-0+deb12u1 | ||||
|  | ||||
| COPY --from=builder /srv/app/dist /srv/app/dist | ||||
| COPY --from=builder /srv/app/target/dx/todo-baggins/release/web /srv/app | ||||
| COPY .env /srv/app/.env | ||||
|  | ||||
| RUN chown -R 1000:1000 /srv/app | ||||
|  | ||||
| WORKDIR /srv/app | ||||
|  | ||||
| HEALTHCHECK CMD curl --fail http://localhost:8000 || exit 1 | ||||
| HEALTHCHECK CMD curl --fail -H "Accept: text/html" http://localhost || exit 1 | ||||
|  | ||||
| USER 1000:1000 | ||||
|  | ||||
| CMD ["./dist/todo-baggins"] | ||||
| ENV IP="0.0.0.0" | ||||
| ENV PORT="80" | ||||
| CMD ["./server"] | ||||
|   | ||||
							
								
								
									
										24
									
								
								index.html
									
									
									
									
									
								
							
							
						
						
									
										24
									
								
								index.html
									
									
									
									
									
								
							| @@ -1,24 +0,0 @@ | ||||
| <!DOCTYPE html> | ||||
| <html class="min-h-screen"> | ||||
| <head> | ||||
|     <title>{app_title}</title> | ||||
|     <link rel="manifest" href="manifest.json"> | ||||
|     <meta content="text/html;charset=utf-8" http-equiv="Content-Type"/> | ||||
|     <meta name="viewport" content="width=device-width, initial-scale=1"> | ||||
|     <meta charset="UTF-8"/> | ||||
|     {style_include} | ||||
| </head> | ||||
| <body class="min-h-screen"> | ||||
| <div id="main" class="min-h-screen"></div> | ||||
| <script type="module"> | ||||
|     import init from "/{base_path}/assets/dioxus/{app_name}.js"; | ||||
|  | ||||
|     init("/{base_path}/assets/dioxus/{app_name}_bg.wasm").then(wasm => { | ||||
|         if (wasm.__wbindgen_start == undefined) { | ||||
|             wasm.main(); | ||||
|         } | ||||
|     }); | ||||
| </script> | ||||
| {script_include} | ||||
| </body> | ||||
| </html> | ||||
| @@ -1,21 +1,45 @@ | ||||
| use crate::query::{QueryErrors, QueryKey, QueryValue}; | ||||
| use crate::route::Route; | ||||
| use crate::server::internationalization::get_language_identifier; | ||||
| use dioxus::core_macro::rsx; | ||||
| use dioxus::dioxus_core::Element; | ||||
| use dioxus::prelude::*; | ||||
| use dioxus_query::prelude::{use_init_query_client}; | ||||
| use crate::query::{QueryErrors, QueryKey, QueryValue}; | ||||
| use dioxus_sdk::i18n::{use_init_i18n}; | ||||
| use crate::internationalization::get_languages; | ||||
| use crate::server::internationalization::get_language_identifier; | ||||
| use dioxus_i18n::prelude::*; | ||||
| use dioxus_i18n::unic_langid::langid; | ||||
| use dioxus_query::prelude::use_init_query_client; | ||||
|  | ||||
| const FAVICON: Asset = asset!("/assets/favicon.ico"); | ||||
| const TAILWIND_CSS: Asset = asset!("/assets/styles/tailwind_output.css"); | ||||
| const FONTS_CSS: Asset = asset!("/assets/styles/fonts.css"); | ||||
| const INPUT_NUMBER_ARROWS_CSS: Asset = asset!("/assets/styles/input_number_arrows.css"); | ||||
| const INPUT_RANGE_CSS: Asset = asset!("/assets/styles/input_range.css"); | ||||
|  | ||||
| #[component] | ||||
| pub(crate) fn App() -> Element { | ||||
|     use_init_query_client::<QueryValue, QueryErrors, QueryKey>(); | ||||
|  | ||||
|     let language_identifier = use_server_future(get_language_identifier)?.unwrap().unwrap(); | ||||
|     use_init_i18n(language_identifier.clone(), language_identifier, get_languages); | ||||
|     let language_identifier = use_server_future(get_language_identifier)? | ||||
|         .unwrap() | ||||
|         .unwrap(); | ||||
|     use_init_i18n(|| { | ||||
|         I18nConfig::new(language_identifier) | ||||
|             .with_locale(Locale::new_static( | ||||
|                 langid!("cs-CZ"), | ||||
|                 include_str!("../internationalization/cs_cz.ftl"), | ||||
|             )) | ||||
|             .with_locale(Locale::new_static( | ||||
|                 langid!("en-US"), | ||||
|                 include_str!("../internationalization/en_us.ftl"), | ||||
|             )) | ||||
|     }); | ||||
|  | ||||
|     rsx! { | ||||
|         document::Link { rel: "icon", href: FAVICON } | ||||
|         document::Link { rel: "stylesheet", href: TAILWIND_CSS } | ||||
|         document::Link { rel: "stylesheet", href: FONTS_CSS } | ||||
|         document::Link { rel: "stylesheet", href: INPUT_NUMBER_ARROWS_CSS } | ||||
|         document::Link { rel: "stylesheet", href: INPUT_RANGE_CSS } | ||||
|  | ||||
|         div { | ||||
|             class: "min-h-screen text-zinc-200 bg-zinc-800 pt-4 pb-36", | ||||
|             Router::<Route> {} | ||||
|   | ||||
| @@ -75,7 +75,7 @@ pub(crate) fn Navigation(expanded: Signal<bool>) -> Element { | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|             } else { None }} | ||||
|             } else { VNode::empty() }} | ||||
|         } | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -8,9 +8,9 @@ use chrono::{Datelike, Local}; | ||||
| use dioxus::core_macro::rsx; | ||||
| use dioxus::dioxus_core::Element; | ||||
| use dioxus::prelude::*; | ||||
| use dioxus_i18n::prelude::i18n; | ||||
| use dioxus_i18n::t; | ||||
| use dioxus_query::prelude::QueryResult; | ||||
| use dioxus_sdk::i18n::use_i18; | ||||
| use dioxus_sdk::translate; | ||||
|  | ||||
| const CALENDAR_LENGTH_DAYS: usize = 366 * 3; | ||||
|  | ||||
| @@ -23,8 +23,6 @@ pub(crate) fn CategoryCalendarPage() -> Element { | ||||
|     }); | ||||
|     let tasks_query_result = tasks.result(); | ||||
|  | ||||
|     let i18 = use_i18(); | ||||
|  | ||||
|     rsx! { | ||||
|         match tasks_query_result.value() { | ||||
|             QueryResult::Ok(QueryValue::TasksWithSubtasks(tasks)) | ||||
| @@ -42,16 +40,15 @@ pub(crate) fn CategoryCalendarPage() -> Element { | ||||
|                                     div { | ||||
|                                         class: "pt-1", | ||||
|                                         { | ||||
|                                             date_current.format_localized(translate!( | ||||
|                                                     i18, | ||||
|                                             date_current.format_localized(t!( | ||||
|                                                     if date_current.year() == Local::now().year() { | ||||
|                                                         "formats.date_weekday_format" | ||||
|                                                         "date-weekday-format" | ||||
|                                                     } else { | ||||
|                                                         "formats.date_weekday_year_format" | ||||
|                                                         "date-weekday-year-format" | ||||
|                                                     } | ||||
|                                                 ).as_str(), | ||||
|                                                 LocaleFromLanguageIdentifier::from( | ||||
|                                                     &(i18.selected_language)() | ||||
|                                                     &i18n().language() | ||||
|                                                 ).into() | ||||
|                                             ) | ||||
|                                             .to_string() | ||||
|   | ||||
| @@ -7,9 +7,9 @@ use crate::query::tasks::use_tasks_with_subtasks_in_category_query; | ||||
| use crate::query::QueryValue; | ||||
| use chrono::Local; | ||||
| use dioxus::prelude::*; | ||||
| use dioxus_i18n::t; | ||||
| use dioxus_i18n::use_i18n::i18n; | ||||
| use dioxus_query::prelude::QueryResult; | ||||
| use dioxus_sdk::i18n::use_i18; | ||||
| use dioxus_sdk::translate; | ||||
| use voca_rs::Voca; | ||||
|  | ||||
| #[component] | ||||
| @@ -26,8 +26,6 @@ pub(crate) fn CategoryTodayPage() -> Element { | ||||
|     let long_term_tasks_query = use_tasks_with_subtasks_in_category_query(Category::LongTerm); | ||||
|     let long_term_tasks_query_result = long_term_tasks_query.result(); | ||||
|      | ||||
|     let i18 = use_i18(); | ||||
|  | ||||
|     rsx! { | ||||
|         div { | ||||
|             class: "pt-4 flex flex-col gap-8", | ||||
| @@ -46,7 +44,7 @@ pub(crate) fn CategoryTodayPage() -> Element { | ||||
|                                 } | ||||
|                                 div { | ||||
|                                     class: "mt-1", | ||||
|                                     {translate!(i18, "long_term")._upper_first()} | ||||
|                                     {t!("long-term")._upper_first()} | ||||
|                                 } | ||||
|                             } | ||||
|                             div { | ||||
| @@ -109,7 +107,7 @@ pub(crate) fn CategoryTodayPage() -> Element { | ||||
|                                     } | ||||
|                                     div { | ||||
|                                         class: "mt-1", | ||||
|                                         {translate!(i18, "overdue")._upper_first()} | ||||
|                                         {t!("overdue")._upper_first()} | ||||
|                                     } | ||||
|                                 } | ||||
|                                 TaskList { | ||||
| @@ -128,18 +126,17 @@ pub(crate) fn CategoryTodayPage() -> Element { | ||||
|                                 div { | ||||
|                                     class: "mt-1", | ||||
|                                     { | ||||
|                                         let format = translate!(i18, "formats.date_weekday_format"); | ||||
|                                         let format = t!("date-weekday-format"); | ||||
|                                         let today_date = today_date.format_localized( | ||||
|                                             format.as_str(), | ||||
|                                             LocaleFromLanguageIdentifier::from( | ||||
|                                                 &(i18.selected_language)() | ||||
|                                                 &i18n().language() | ||||
|                                             ).into() | ||||
|                                         ).to_string(); | ||||
|                                         format!( | ||||
|                                             "{} – {}", | ||||
|                                             translate!(i18, "today")._upper_first(), | ||||
|                                             if translate!(i18, "formats.weekday_lowercase_first") | ||||
|                                                 .parse().unwrap() { | ||||
|                                             t!("today")._upper_first(), | ||||
|                                             if t!("weekday-lowercase-first").parse().unwrap() { | ||||
|                                                 today_date._lower_first() | ||||
|                                             } else { | ||||
|                                                 today_date | ||||
|   | ||||
| @@ -116,7 +116,7 @@ pub(crate) fn SubtasksForm(task: Task) -> Element { | ||||
|                                     onchange: { | ||||
|                                         let subtask = subtask.clone(); | ||||
|                                         let task = task.clone(); | ||||
|                                         move |event| { | ||||
|                                         move |event: Event<FormData>| { | ||||
|                                             let subtask = subtask.clone(); | ||||
|                                             let task = task.clone(); | ||||
|                                             async move { | ||||
|   | ||||
| @@ -11,9 +11,8 @@ use chrono::Duration; | ||||
| use dioxus::core_macro::{component, rsx}; | ||||
| use dioxus::dioxus_core::Element; | ||||
| use dioxus::prelude::*; | ||||
| use dioxus_i18n::t; | ||||
| use dioxus_query::prelude::{use_query_client, QueryResult}; | ||||
| use dioxus_sdk::i18n::use_i18; | ||||
| use dioxus_sdk::translate; | ||||
| use crate::query::projects::use_projects_query; | ||||
|  | ||||
| const REMINDER_OFFSETS: [Option<Duration>; 17] = [ | ||||
| @@ -81,8 +80,6 @@ pub(crate) fn TaskForm(task: Option<Task>, on_successful_submit: EventHandler<() | ||||
|     let query_client = use_query_client::<QueryValue, QueryErrors, QueryKey>(); | ||||
|     let task_for_submit = task.clone(); | ||||
|  | ||||
|     let i18 = use_i18(); | ||||
|  | ||||
|     rsx! { | ||||
|         div { | ||||
|             class: "p-4 flex flex-col gap-4", | ||||
| @@ -176,7 +173,7 @@ pub(crate) fn TaskForm(task: Option<Task>, on_successful_submit: EventHandler<() | ||||
|                         id: "input_project", | ||||
|                         option { | ||||
|                             value: 0, | ||||
|                             {translate!(i18, "none")} | ||||
|                             {t!("none")} | ||||
|                         }, | ||||
|                         match projects_query.result().value() { | ||||
|                             QueryResult::Ok(QueryValue::Projects(projects)) | ||||
| @@ -359,12 +356,12 @@ pub(crate) fn TaskForm(task: Option<Task>, on_successful_submit: EventHandler<() | ||||
|                                             } else { | ||||
|                                                 format!("{} h", offset.num_hours()) | ||||
|                                             } | ||||
|                                         ).unwrap_or_else(|| translate!(i18, "none"))} | ||||
|                                         ).unwrap_or_else(|| t!("none"))} | ||||
|                                 } | ||||
|                             } | ||||
|                         } | ||||
|                     }, | ||||
|                     _ => None | ||||
|                     _ => VNode::empty() | ||||
|                 } | ||||
|             }, | ||||
|             if let Some(task) = task.as_ref() { | ||||
|   | ||||
| @@ -4,6 +4,7 @@ use dioxus::core_macro::rsx; | ||||
| use dioxus::dioxus_core::Element; | ||||
| use dioxus::prelude::*; | ||||
| use dioxus_query::prelude::use_query_client; | ||||
| use tracing::info; | ||||
| use crate::components::task_list_item::TaskListItem; | ||||
| use crate::query::{QueryErrors, QueryKey, QueryValue}; | ||||
| use crate::server::tasks::complete_task; | ||||
| @@ -22,17 +23,17 @@ pub(crate) fn TaskList(tasks: Vec<TaskWithSubtasks>, class: Option<&'static str> | ||||
|                 div { | ||||
|                     key: "{task.task().id()}", | ||||
|                     class: format!( | ||||
|                         "px-8 pt-5 {} flex flex-row gap-4 select-none {}", | ||||
|                         "px-8 pt-4 {} flex flex-row gap-4 select-none {}", | ||||
|                         if task.task().deadline().is_some() || !task.subtasks().is_empty() { | ||||
|                             "pb-0.5" | ||||
|                         } else if let Category::Calendar { time, .. } = task.task().category() { | ||||
|                             if time.is_some() { | ||||
|                                 "pb-0.5" | ||||
|                             } else { | ||||
|                                 "pb-5" | ||||
|                                 "pb-4" | ||||
|                             } | ||||
|                         } else { | ||||
|                             "pb-5" | ||||
|                             "pb-4" | ||||
|                         }, | ||||
|                         if task_being_edited().is_some_and(|t| t.id() == task.task().id()) { | ||||
|                             "bg-zinc-700" | ||||
| @@ -44,7 +45,7 @@ pub(crate) fn TaskList(tasks: Vec<TaskWithSubtasks>, class: Option<&'static str> | ||||
|                     }, | ||||
|                     i { | ||||
|                         class: format!( | ||||
|                             "{} text-3xl text-zinc-500", | ||||
|                             "{} text-3xl align-middle h-9 text-zinc-500", | ||||
|                             if *(task.task().category()) == Category::Done { | ||||
|                                 "fa solid fa-square-check" | ||||
|                             } else { | ||||
| @@ -53,12 +54,13 @@ pub(crate) fn TaskList(tasks: Vec<TaskWithSubtasks>, class: Option<&'static str> | ||||
|                         ), | ||||
|                         onclick: { | ||||
|                             let task = task.clone(); | ||||
|                             move |event| { | ||||
|                             move |event: Event<MouseData>| { | ||||
|                                 // To prevent editing the task. | ||||
|                                 event.stop_propagation(); | ||||
|                                 let task = task.clone(); | ||||
|                                 async move { | ||||
|                                     let completed_task = complete_task(task.task().id()).await.unwrap(); | ||||
|                                     let completed_task = complete_task(task.task().id()).await | ||||
|                                         .unwrap(); | ||||
|                                     let mut query_keys = vec![ | ||||
|                                         QueryKey::Tasks, | ||||
|                                         QueryKey::TasksInCategory( | ||||
|   | ||||
| @@ -1,3 +1,4 @@ | ||||
| use dioxus_i18n::prelude::i18n; | ||||
| use crate::internationalization::LocaleFromLanguageIdentifier; | ||||
| use crate::models::category::Category; | ||||
| use crate::models::task::TaskWithSubtasks; | ||||
| @@ -5,19 +6,16 @@ use chrono::{Datelike, Local}; | ||||
| use dioxus::core_macro::rsx; | ||||
| use dioxus::dioxus_core::Element; | ||||
| use dioxus::prelude::*; | ||||
| use dioxus_sdk::i18n::use_i18; | ||||
| use dioxus_sdk::translate; | ||||
| use dioxus_i18n::t; | ||||
| use voca_rs::Voca; | ||||
|  | ||||
| #[component] | ||||
| pub(crate) fn TaskListItem(task: TaskWithSubtasks) -> Element { | ||||
|     let i18 = use_i18(); | ||||
|  | ||||
|     rsx! { | ||||
|         div { | ||||
|             class: "flex flex-col", | ||||
|             div { | ||||
|                 class: "mt-1 grow font-medium", | ||||
|                 class: "mt-2 grow font-medium", | ||||
|                 {task.task().title()} | ||||
|             }, | ||||
|             div { | ||||
| @@ -33,37 +31,37 @@ pub(crate) fn TaskListItem(task: TaskWithSubtasks) -> Element { | ||||
|                             format!( | ||||
|                                 " {}", | ||||
|                                 if deadline == today_date - chrono::Days::new(1) { | ||||
|                                     translate!(i18, "yesterday") | ||||
|                                     t!("yesterday") | ||||
|                                 } else if deadline == today_date { | ||||
|                                     translate!(i18, "today") | ||||
|                                     t!("today") | ||||
|                                 } else if deadline == today_date + chrono::Days::new(1) { | ||||
|                                     translate!(i18, "tomorrow") | ||||
|                                     t!("tomorrow") | ||||
|                                 } else if deadline > today_date | ||||
|                                     && deadline <= today_date + chrono::Days::new(7) { | ||||
|                                     let deadline = deadline.format_localized( | ||||
|                                         "%A", | ||||
|                                         LocaleFromLanguageIdentifier::from( | ||||
|                                             &(i18.selected_language)() | ||||
|                                             &i18n().language() | ||||
|                                         ).into() | ||||
|                                     ).to_string(); | ||||
|                                     if translate!(i18, "formats.weekday_lowercase_first") | ||||
|                                     if t!("weekday-lowercase-first") | ||||
|                                         .parse().unwrap() { | ||||
|                                         deadline._lower_first() | ||||
|                                     } else { | ||||
|                                         deadline | ||||
|                                     } | ||||
|                                 } else { | ||||
|                                     let format = translate!(i18, | ||||
|                                     let format = t!( | ||||
|                                         if deadline.year() == today_date.year() { | ||||
|                                             "formats.date_format" | ||||
|                                             "date-format" | ||||
|                                         } else { | ||||
|                                             "formats.date_year_format" | ||||
|                                             "date-year-format" | ||||
|                                         } | ||||
|                                     ); | ||||
|                                     deadline.format_localized( | ||||
|                                         format.as_str(), | ||||
|                                         LocaleFromLanguageIdentifier::from( | ||||
|                                             &(i18.selected_language)() | ||||
|                                             &i18n().language() | ||||
|                                         ).into() | ||||
|                                     ).to_string() | ||||
|                                 } | ||||
| @@ -79,7 +77,7 @@ pub(crate) fn TaskListItem(task: TaskWithSubtasks) -> Element { | ||||
|                                 class: "fa-solid fa-clock" | ||||
|                             }, | ||||
|                             { | ||||
|                                 let format = translate!(i18, "formats.time_format"); | ||||
|                                 let format = t!("time-format"); | ||||
|                                 format!(" {}", calendar_time.time().format(format.as_str())) | ||||
|                             } | ||||
|                         } | ||||
|   | ||||
							
								
								
									
										14
									
								
								src/internationalization/cs_cz.ftl
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								src/internationalization/cs_cz.ftl
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,14 @@ | ||||
| none = žádný | ||||
| long-term = dlouhodobé | ||||
| yesterday = včera | ||||
| today = dnes | ||||
| tomorrow = zítra | ||||
| overdue = zpožděné | ||||
|  | ||||
| ## Date and time formats | ||||
| date-format = %-d. %B | ||||
| date-year-format = %-d. %B %Y | ||||
| date-weekday-format = %A %-d. %B | ||||
| date-weekday-year-format = %A %-d. %B %Y | ||||
| weekday-lowercase-first = true | ||||
| time-format = %-H:%M | ||||
| @@ -1,19 +0,0 @@ | ||||
| { | ||||
|   "id": "cs-CZ", | ||||
|   "texts": { | ||||
|     "none": "žádný", | ||||
|     "long_term": "dlouhodobé", | ||||
|     "yesterday": "včera", | ||||
|     "today": "dnes", | ||||
|     "tomorrow": "zítra", | ||||
|     "overdue": "zpožděné", | ||||
|     "formats": { | ||||
|       "date_format": "%-d. %B", | ||||
|       "date_year_format": "%-d. %B %Y", | ||||
|       "date_weekday_format": "%A %-d. %B", | ||||
|       "date_weekday_year_format": "%A %-d. %B %Y", | ||||
|       "weekday_lowercase_first": "true", | ||||
|       "time_format": "%-H:%M" | ||||
|     } | ||||
|   } | ||||
| } | ||||
							
								
								
									
										14
									
								
								src/internationalization/en_us.ftl
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								src/internationalization/en_us.ftl
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,14 @@ | ||||
| none = none | ||||
| long-term = long-term | ||||
| yesterday = yesterday | ||||
| today = today | ||||
| tomorrow = tomorrow | ||||
| overdue = overdue | ||||
|  | ||||
| ## Date and time formats | ||||
| date-format = %B %-d | ||||
| date-year-format = %B %-d, %Y | ||||
| date-weekday-format = %A, %B %-d | ||||
| date-weekday-year-format = %A, %B %-d, %Y | ||||
| weekday-lowercase-first = false | ||||
| time-format = %-I:%M %P | ||||
| @@ -1,19 +0,0 @@ | ||||
| { | ||||
|   "id": "en-US", | ||||
|   "texts": { | ||||
|     "none": "none", | ||||
|     "long_term": "long-term", | ||||
|     "yesterday": "yesterday", | ||||
|     "today": "today", | ||||
|     "tomorrow": "tomorrow", | ||||
|     "overdue": "overdue", | ||||
|     "formats": { | ||||
|       "date_format": "%B %-d", | ||||
|       "date_year_format": "%B %-d, %Y", | ||||
|       "date_weekday_format": "%A, %B %-d", | ||||
|       "date_weekday_year_format": "%A, %B %-d, %Y", | ||||
|       "weekday_lowercase_first": "false", | ||||
|       "time_format": "%-I:%M %P" | ||||
|     } | ||||
|   } | ||||
| } | ||||
| @@ -1,21 +1,12 @@ | ||||
| use std::ops::Deref; | ||||
| use std::str::FromStr; | ||||
| use std::sync::Mutex; | ||||
| use chrono::Locale; | ||||
| use dioxus::fullstack::once_cell::sync::Lazy; | ||||
| use dioxus_sdk::i18n::Language; | ||||
| use feruca::Collator; | ||||
| use unic_langid_impl::LanguageIdentifier; | ||||
|  | ||||
| const EN_US: &str = include_str!("en_us.json"); | ||||
| const CS_CZ: &str = include_str!("cs_cz.json"); | ||||
|  | ||||
| pub(crate) static COLLATOR: Lazy<Mutex<Collator>> = Lazy::new(|| Mutex::new(Collator::default())); | ||||
|  | ||||
| pub(crate) fn get_languages() -> Vec<Language> { | ||||
|     Vec::from([EN_US, CS_CZ]).into_iter().map(|texts| Language::from_str(texts).unwrap()).collect() | ||||
| } | ||||
|  | ||||
| pub(crate) struct LocaleFromLanguageIdentifier<'a>(&'a LanguageIdentifier); | ||||
|  | ||||
| impl<'a> Deref for LocaleFromLanguageIdentifier<'a> { | ||||
|   | ||||
| @@ -11,19 +11,14 @@ mod migrations; | ||||
|  | ||||
| use components::app::App; | ||||
| use dioxus::prelude::*; | ||||
| use dioxus_logger::tracing::{info, Level}; | ||||
| use tracing::info; | ||||
|  | ||||
| fn main() { | ||||
|     dioxus_logger::init(Level::INFO).expect("Failed to initialize the logger."); | ||||
|  | ||||
|     info!("Running migrations."); | ||||
|     server_only!( | ||||
|         migrations::run_migrations().expect("Failed to run migrations."); | ||||
|     ); | ||||
|  | ||||
|     info!("Starting app."); | ||||
|     let cfg = server_only!( | ||||
|         dioxus::fullstack::Config::new().addr(std::net::SocketAddr::from(([0, 0, 0, 0], 8000))) | ||||
|     ); | ||||
|     LaunchBuilder::fullstack().with_cfg(cfg).launch(App); | ||||
|     launch(App); | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user