HRT tracker page works, but with the caveat of being on the UTC time offset. This needs to be fixed eventually.

This commit is contained in:
Ada Werefox 2024-03-25 20:42:59 -05:00
parent 31c59114ac
commit 9dde7cd945
8 changed files with 246 additions and 48 deletions

View File

@ -11,6 +11,7 @@ dioxus-autofmt = "0.5.0-alpha.0"
console_error_panic_hook = "0.1.7" console_error_panic_hook = "0.1.7"
log = "0.4.17" log = "0.4.17"
manganis = "*" manganis = "*"
serde = "*"
[dependencies.dioxus-router] [dependencies.dioxus-router]
version = "0.5.0-alpha.0" version = "0.5.0-alpha.0"
@ -24,3 +25,7 @@ features = ["web", "fullstack"]
default = [] default = []
server = ["dioxus/axum"] server = ["dioxus/axum"]
web = ["dioxus/web"] web = ["dioxus/web"]
[dependencies.time]
verison = "0.3.34"
features = ["wasm-bindgen", "macros", "local-offset"]

View File

@ -592,6 +592,14 @@ video {
position: relative; position: relative;
} }
.order-1 {
order: 1;
}
.order-2 {
order: 2;
}
.mx-auto { .mx-auto {
margin-left: auto; margin-left: auto;
margin-right: auto; margin-right: auto;
@ -633,6 +641,10 @@ video {
display: inline-block; display: inline-block;
} }
.inline {
display: inline;
}
.flex { .flex {
display: flex; display: flex;
} }
@ -657,10 +669,22 @@ video {
height: 2rem; height: 2rem;
} }
.h-full {
height: 100%;
}
.min-h-full {
min-height: 100%;
}
.min-h-screen { .min-h-screen {
min-height: 100vh; min-height: 100vh;
} }
.w-16 {
width: 4rem;
}
.w-4 { .w-4 {
width: 1rem; width: 1rem;
} }
@ -698,6 +722,10 @@ video {
flex: 1 1 0%; flex: 1 1 0%;
} }
.flex-shrink-0 {
flex-shrink: 0;
}
.basis-full { .basis-full {
flex-basis: 100%; flex-basis: 100%;
} }
@ -759,6 +787,10 @@ video {
grid-template-columns: repeat(1, minmax(0, 1fr)); grid-template-columns: repeat(1, minmax(0, 1fr));
} }
.grid-rows-4 {
grid-template-rows: repeat(4, minmax(0, 1fr));
}
.grid-rows-9 { .grid-rows-9 {
grid-template-rows: repeat(9, minmax(0, 1fr)); grid-template-rows: repeat(9, minmax(0, 1fr));
} }
@ -783,6 +815,10 @@ video {
gap: 0px; gap: 0px;
} }
.gap-2 {
gap: 0.5rem;
}
.space-y-2 > :not([hidden]) ~ :not([hidden]) { .space-y-2 > :not([hidden]) ~ :not([hidden]) {
--tw-space-y-reverse: 0; --tw-space-y-reverse: 0;
margin-top: calc(0.5rem * calc(1 - var(--tw-space-y-reverse))); margin-top: calc(0.5rem * calc(1 - var(--tw-space-y-reverse)));
@ -795,6 +831,10 @@ video {
margin-bottom: calc(1rem * var(--tw-space-y-reverse)); margin-bottom: calc(1rem * var(--tw-space-y-reverse));
} }
.overflow-auto {
overflow: auto;
}
.overflow-visible { .overflow-visible {
overflow: visible; overflow: visible;
} }
@ -866,6 +906,10 @@ video {
padding-left: 0.5rem; padding-left: 0.5rem;
} }
.pl-4 {
padding-left: 1rem;
}
.pr-2 { .pr-2 {
padding-right: 0.5rem; padding-right: 0.5rem;
} }
@ -918,6 +962,11 @@ video {
line-height: 1rem; line-height: 1rem;
} }
.text-alice-werefox-blue-dark {
--tw-text-opacity: 1;
color: rgb(51 0 255 / var(--tw-text-opacity));
}
.text-alice-werefox-grey-dark { .text-alice-werefox-grey-dark {
--tw-text-opacity: 1; --tw-text-opacity: 1;
color: rgb(18 18 18 / var(--tw-text-opacity)); color: rgb(18 18 18 / var(--tw-text-opacity));
@ -950,6 +999,11 @@ video {
box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000); box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000);
} }
.ring-alice-werefox-blue-dark {
--tw-ring-opacity: 1;
--tw-ring-color: rgb(51 0 255 / var(--tw-ring-opacity));
}
.ring-alice-werefox-grey { .ring-alice-werefox-grey {
--tw-ring-opacity: 1; --tw-ring-opacity: 1;
--tw-ring-color: rgb(36 36 36 / var(--tw-ring-opacity)); --tw-ring-color: rgb(36 36 36 / var(--tw-ring-opacity));
@ -1039,6 +1093,14 @@ video {
height: 1.5rem; height: 1.5rem;
} }
.sm\:min-h-full {
min-height: 100%;
}
.sm\:w-32 {
width: 8rem;
}
.sm\:w-6 { .sm\:w-6 {
width: 1.5rem; width: 1.5rem;
} }
@ -1059,6 +1121,11 @@ video {
font-size: 1.125rem; font-size: 1.125rem;
line-height: 1.75rem; line-height: 1.75rem;
} }
.sm\:text-xl {
font-size: 1.25rem;
line-height: 1.75rem;
}
} }
@media (min-width: 768px) { @media (min-width: 768px) {
@ -1107,6 +1174,11 @@ video {
background-color: rgb(18 18 18 / var(--tw-bg-opacity)); background-color: rgb(18 18 18 / var(--tw-bg-opacity));
} }
.dark\:text-alice-werefox-blue-light {
--tw-text-opacity: 1;
color: rgb(145 151 243 / var(--tw-text-opacity));
}
.dark\:text-alice-werefox-grey-light { .dark\:text-alice-werefox-grey-light {
--tw-text-opacity: 1; --tw-text-opacity: 1;
color: rgb(204 204 204 / var(--tw-text-opacity)); color: rgb(204 204 204 / var(--tw-text-opacity));
@ -1122,6 +1194,11 @@ video {
color: rgb(224 133 135 / var(--tw-text-opacity)); color: rgb(224 133 135 / var(--tw-text-opacity));
} }
.dark\:ring-alice-werefox-blue {
--tw-ring-opacity: 1;
--tw-ring-color: rgb(27 41 224 / var(--tw-ring-opacity));
}
.dark\:ring-alice-werefox-grey-darker { .dark\:ring-alice-werefox-grey-darker {
--tw-ring-opacity: 1; --tw-ring-opacity: 1;
--tw-ring-color: rgb(0 0 0 / var(--tw-ring-opacity)); --tw-ring-color: rgb(0 0 0 / var(--tw-ring-opacity));

View File

@ -11,3 +11,4 @@ pub mod identity_button;
pub mod project_card; pub mod project_card;
pub mod back_button; pub mod back_button;
pub mod project_foldable; pub mod project_foldable;
pub mod faq_card;

View File

@ -1,4 +1,4 @@
use crate::{info_app::Route, utils::prop_structs::ImageProps}; use crate::info_app::Route;
use dioxus::prelude::*; use dioxus::prelude::*;
use dioxus_router::prelude::*; use dioxus_router::prelude::*;

View File

@ -2,7 +2,6 @@ use crate::components::footer_card::*;
use crate::components::title_card::*; use crate::components::title_card::*;
use crate::components::back_button::*; use crate::components::back_button::*;
use crate::info_app::Route; use crate::info_app::Route;
use crate::utils::prop_structs::ImageProps;
use dioxus::prelude::*; use dioxus::prelude::*;
#[component] #[component]

View File

@ -0,0 +1,32 @@
use crate::utils::prop_structs::ImageProps;
use dioxus::prelude::*;
#[component]
pub fn FaqCard(question: String, answer: String, image_props: ImageProps) -> Element {
rsx! {
div { class: "space-y-2",
div { class: "ring-2 ring-alice-werefox-blue-dark dark:ring-alice-werefox-blue",
p { class: "p-8 text-center text-lg sm:text-xl text-alice-werefox-blue-dark dark:text-alice-werefox-blue-light",
"{question}"
}
}
div { class: " ring-2 ring-alice-werefox-red-dark dark:ring-alice-werefox-red hover:ring-alice-werefox-blue-dark dark:hover:ring-alice-werefox-blue text-alice-werefox-red-dark dark:text-alice-werefox-red-light hover:text-alice-werefox-blue-dark dark:hover:text-alice-werefox-blue-light hover:animate-yip transition",
a { href: "https://bark.lgbt/@alicew", target: "_blank",
div { class: "p-2 flex",
div { class: "order-1 flex-shrink-0 relative inline sm:w-32 w-16 min-h-full items-center justify-center align-middle pt-4 pb-4 pl-4",
img {
alt: "{image_props.alt}",
src: "{image_props.src}"
}
}
div { class: "order-2 flex overflow-auto items-center justify-center animate-wiggle p-4 sm:text-lg text-xs text-center sm:min-h-full h-full",
"{answer}"
br {}
"{\"- @alice\"}"
}
}
}
}
}
}
}

View File

@ -7,7 +7,7 @@ pub fn FooterCard() -> Element {
footer { class: "p-4 space-y-2 rounded-lg ring-2 ring-alice-werefox-grey dark:ring-alice-werefox-grey-darker bg-alice-werefox-grey-lightest dark:bg-alice-werefox-grey-dark", footer { class: "p-4 space-y-2 rounded-lg ring-2 ring-alice-werefox-grey dark:ring-alice-werefox-grey-darker bg-alice-werefox-grey-lightest dark:bg-alice-werefox-grey-dark",
div { class: "flex text-alice-werefox-red-darker dark:text-alice-werefox-red-light", div { class: "flex text-alice-werefox-red-darker dark:text-alice-werefox-red-light",
div { class: "flex-1" } div { class: "flex-1" }
FooterButton { url: "https://info.werefox.cafe/contacts", inner_text: "Contact" } FooterButton { url: "https://werefox.cafe/", inner_text: "Contact" }
FooterButton { url: "https://gitea.werefox.cafe/ada/werefox-cafe", inner_text: " /src" } FooterButton { url: "https://gitea.werefox.cafe/ada/werefox-cafe", inner_text: " /src" }
div { class: "flex-1" } div { class: "flex-1" }
} }

View File

@ -16,15 +16,17 @@ pub mod info_app {
// import the prelude to get access to the `rsx!` macro and the `Scope` and `Element` types // import the prelude to get access to the `rsx!` macro and the `Scope` and `Element` types
pub use dioxus::prelude::*; pub use dioxus::prelude::*;
use serde::{Deserialize, Serialize};
use crate::components::basic_page::*; use crate::components::basic_page::*;
use crate::components::faq_card::*;
use crate::components::home_page::*; use crate::components::home_page::*;
use crate::components::identity_button::*; use crate::components::identity_button::*;
use crate::components::introduction_card::*; use crate::components::introduction_card::*;
use crate::components::page_button::*; use crate::components::page_button::*;
use crate::components::project_card::*; use crate::components::project_card::*;
use crate::components::werefox_card::*;
use crate::components::project_foldable::*; use crate::components::project_foldable::*;
use crate::components::werefox_card::*;
use crate::utils::prop_structs::*; use crate::utils::prop_structs::*;
use dioxus_router::prelude::*; use dioxus_router::prelude::*;
@ -42,8 +44,6 @@ pub mod info_app {
Hrt {}, Hrt {},
#[route("/faq")] #[route("/faq")]
Faq {}, Faq {},
#[route("/support")]
Support {},
} }
pub fn DioxusApp() -> Element { pub fn DioxusApp() -> Element {
rsx! { Router::<Route> {} } rsx! { Router::<Route> {} }
@ -129,14 +129,6 @@ pub mod info_app {
alt: "Red question mark emoji".to_string(), alt: "Red question mark emoji".to_string(),
}, },
), ),
(
"Support Me?",
Route::Support {},
ImageProps {
src: "/emoji/green_money.svg".to_string(),
alt: "Green money emoji".to_string(),
},
),
]; ];
rsx! { rsx! {
HomePage { page_title: "About a Werefox", card_title: "Hi! I'm Alice Werefox!", HomePage { page_title: "About a Werefox", card_title: "Hi! I'm Alice Werefox!",
@ -318,24 +310,31 @@ pub mod info_app {
for project in project_list { for project in project_list {
ProjectCard { project_title: project.0, project_description: project.1, project_link: project.2, image_props: project.3 } ProjectCard { project_title: project.0, project_description: project.1, project_link: project.2, image_props: project.3 }
} }
ProjectFoldable { project_title: "Services", ProjectFoldable {
project_title: "Services",
project_description: "Click here for a list of the services I host.", project_description: "Click here for a list of the services I host.",
image_props: ImageProps { image_props: ImageProps {
src: "/emoji/crt_blue_screen.svg".to_string(), src: "/emoji/crt_blue_screen.svg".to_string(),
alt: "A CRT blue screen emoji.".to_string(), alt: "A CRT blue screen emoji.".to_string(),
} },
for service in service_list { for service in service_list {
ProjectCard { project_title: service.0, project_description: service.1, project_link: service.2, image_props: service.3 } ProjectCard { project_title: service.0, project_description: service.1, project_link: service.2, image_props: service.3 }
} }
} }
ProjectFoldable { project_title: "Personal Use", ProjectFoldable {
project_title: "Personal Use",
project_description: "Click here for a list of services I have set up for just me.", project_description: "Click here for a list of services I have set up for just me.",
image_props: ImageProps { image_props: ImageProps {
src: "/emoji/crt_blue_screen.svg".to_string(), src: "/emoji/crt_blue_screen.svg".to_string(),
alt: "A CRT blue screen emoji.".to_string(), alt: "A CRT blue screen emoji.".to_string(),
} },
for personal in personal_list { for personal in personal_list {
ProjectCard { project_title: personal.0, project_description: personal.1, project_link: personal.2, image_props: personal.3 } ProjectCard {
project_title: personal.0,
project_description: personal.1,
project_link: personal.2,
image_props: personal.3
}
} }
} }
} }
@ -351,16 +350,101 @@ pub mod info_app {
#[component] #[component]
pub fn Hrt() -> Element { pub fn Hrt() -> Element {
rsx! { div {} } // let time_elapsed: TimeElapsed = GetHrtTime().await();
// let mut test = get_hrt_time();
let time_elapsed = use_signal(|| TimeElapsed {
days: 0,
hours: 0,
minutes: 0,
seconds: 0,
});
use_coroutine(|_rx: UnboundedReceiver<()>| {
to_owned![time_elapsed];
async move {
loop {
time_elapsed.set(get_hrt_time().await.unwrap());
}
}
});
rsx! {
BasicPage { page_title: "Track my HRT progress!",
WerefoxCard { card_title: "I'm so glad you're interested!!",
div { class: "p-2 sm:text-xl text-lg text-center text-alice-werefox-red-dark dark:text-alice-werefox-red-light grid grid-cols-1 grid-rows-4 gap-2",
p { "I've been on HRT for:" }
p { "{time_elapsed.read().days} days" }
p { "{time_elapsed.read().hours} hours" }
p { "{time_elapsed.read().minutes} minutes" }
p { "{time_elapsed.read().seconds} seconds" }
}
}
}
}
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
pub struct TimeElapsed {
days: i64,
hours: i64,
minutes: i64,
seconds: i64,
}
#[server]
async fn get_hrt_time() -> Result<TimeElapsed, ServerFnError> {
use time::{macros::datetime, Duration, OffsetDateTime, UtcOffset};
let mut hrt_start_date: OffsetDateTime = datetime!(2020-12-11 0:00 UTC);
// TODO: Fix this so that the offset time total matches the server's UTC offset.
// let hrt_start_date_offset: UtcOffset = UtcOffset::local_offset_at(hrt_start_date).unwrap();
// hrt_start_date = hrt_start_date.replace_offset(hrt_start_date_offset);
let now: OffsetDateTime = OffsetDateTime::now_utc();
let duration: Duration = now - hrt_start_date;
Ok(TimeElapsed {
days: duration.whole_days(),
hours: duration.whole_hours() % 24,
minutes: duration.whole_minutes() % 60,
seconds: duration.whole_seconds() % 60,
})
} }
#[component] #[component]
pub fn Faq() -> Element { pub fn Faq() -> Element {
rsx! { div {} } let faq_list = [(
} "So is Werefox like a species or...?",
"That's a good question! No, my fursona's full name is Alice Icehart Werefox, Werefox is just a last name. I got it from playing Second Life back in the day.",
#[component] ImageProps {
pub fn Support() -> Element { src: "/images/AliceDefault.png".to_string(),
rsx! { div {} } alt: "Alice as an emoji".to_string(),
},
),(
"How can you be Pansexual and a Lesbian?",
"I believe I've been told the proper term is \"sapphic\", it just means I *am* Pansexual, but I tend to prefer those who identify more femme.",
ImageProps {
src: "/images/AliceHeartRainbow.png".to_string(),
alt: "Alice with a gay pride heart".to_string(),
},
),(
"How do I get those Xenia stickers?",
"Yeah, about that. So, I've made a few posts about this, but when I first started giving those out, I was in a good financial position, among other things. Now I'm not! I will get to it when I do.",
ImageProps {
src: "/images/alice_Sweatdrop.svg".to_string(),
alt: "Alice with a sweatdrop".to_string(),
},
),(
"What do you do?",
"Lots of things! If you want to know more about what I do, you can check out \"Stuff I do!\" from the main page, or \"Support Me?\" if you wanna toss a donation! I'm currently still unemployed, so any extra funds would be appreciated!",
ImageProps {
src: "/images/AliceEmojiAliceYay.png".to_string(),
alt: "Happy Alice emoji".to_string(),
},
)];
rsx! {
BasicPage { page_title: "Here are some FAQs",
div { class: "p-4 space-y-4 rounded-lg ring-2 ring-alice-werefox-grey dark:ring-alice-werefox-grey-darker bg-alice-werefox-grey-lightest dark:bg-alice-werefox-grey-dark",
for faq in faq_list {
FaqCard { question: faq.0, answer: faq.1, image_props: faq.2 }
}
}
}
}
} }
} }