feat(master): added backend project, fixed dixous 2.0.1, css and added dockerhub option to project card

This commit is contained in:
darkicewolf50 2025-05-26 18:33:01 -06:00
parent 2806d654a7
commit 5e52c6dea1
12 changed files with 101 additions and 76 deletions

2
Cargo.lock generated
View File

@ -3179,7 +3179,7 @@ checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e"
[[package]] [[package]]
name = "personal_site" name = "personal_site"
version = "1.6.0" version = "2.0.1"
dependencies = [ dependencies = [
"dioxus", "dioxus",
"reqwest", "reqwest",

View File

@ -1,6 +1,6 @@
[package] [package]
name = "personal_site" name = "personal_site"
version = "1.6.0" version = "2.0.1"
authors = ["darkicewolf50 <brock.tomlinson@ucalgary.ca>"] authors = ["darkicewolf50 <brock.tomlinson@ucalgary.ca>"]
edition = "2021" edition = "2021"

View File

@ -45,6 +45,7 @@
border-radius: 1rem; border-radius: 1rem;
padding: 0.25svh 8px; padding: 0.25svh 8px;
margin: 0svh 0.25svh; margin: 0svh 0.25svh;
text-align: center;
} }
#blog a { #blog a {
@ -65,13 +66,17 @@ h3 {
margin: 0px; margin: 0px;
padding: 1svh 0svw; padding: 1svh 0svw;
border-bottom: none; border-bottom: none;
/* border-bottom: var(--underlineTitle);
border-radius: var(--underlineTitleBorderRadius); */
} }
#blog_content p { #blog_content p {
padding: 1svh 0svw; padding: 1svh 0svw;
margin: 0px; margin: 0px;
text-wrap: wrap;
max-width: 25rem;
}
#blog #blog_content p {
max-width: max-content;
} }
#blogs { #blogs {
@ -132,12 +137,19 @@ h3 {
border: 2px solid rgba(145, 164, 210, 0.4); border: 2px solid rgba(145, 164, 210, 0.4);
border-radius: var(--card-border-radius); border-radius: var(--card-border-radius);
font-size: medium; font-size: medium;
margin-top: auto;
margin-bottom: 4svh;
} }
#blogs .blog-preview #blog_info div p:last-child { #blogs .blog-preview #blog_info div p:last-child {
margin-right: 0svh; margin-right: 0svh;
margin-left: 2svw; margin-left: 2svw;
} }
#blogs .blog-preview #blog_info div div p:last-child {
margin: 0svh 0.25svh;
padding: 0.25svh 8px;
}
#blogs-title { #blogs-title {
display: flex; display: flex;
flex-direction: column; flex-direction: column;

View File

@ -2,6 +2,8 @@
display: flex; display: flex;
flex-direction: column; flex-direction: column;
flex-wrap: wrap; flex-wrap: wrap;
background-color: var(--card-background-color);
border-radius: var(--card-border-radius);
/* flex-basis: 50%; */ /* flex-basis: 50%; */
} }

View File

@ -63,15 +63,11 @@
display: flex; display: flex;
flex-direction: column; flex-direction: column;
margin-bottom: 4svh; margin-bottom: 4svh;
background-color: var(--card-background-color);
border-radius: var(--card-border-radius);
} }
#experience div { #experience div {
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
justify-content: space-evenly; justify-content: space-evenly;
background-color: var(--card-background-color);
border-radius: var(--card-border-radius);
margin: 4svh 0px; margin: 4svh 0px;
} }

View File

@ -67,6 +67,10 @@
filter: grayscale(100%) invert(100%) brightness(2.5); filter: grayscale(100%) invert(100%) brightness(2.5);
} }
.project-title-info #dockerhub img {
filter: grayscale(100%) invert(100%) brightness(2.5);
}
.project-title-info img:hover { .project-title-info img:hover {
filter: brightness(0) saturate(100%) invert(65%) sepia(13%) saturate(733%) filter: brightness(0) saturate(100%) invert(65%) sepia(13%) saturate(733%)
hue-rotate(187deg) brightness(95%) contrast(90%); hue-rotate(187deg) brightness(95%) contrast(90%);
@ -77,6 +81,11 @@
hue-rotate(185deg) brightness(1.3) contrast(90%) saturate(100%); hue-rotate(185deg) brightness(1.3) contrast(90%) saturate(100%);
} }
.project-title-info #dockerhub img:hover {
filter: grayscale(100%) invert(165%) sepia(15%) saturate(733%)
hue-rotate(185deg) brightness(1.3) contrast(90%) saturate(100%);
}
.project-title-info div { .project-title-info div {
display: flex; display: flex;
gap: 1svw; gap: 1svw;

View File

@ -1,6 +1,5 @@
use dioxus::prelude::*; use dioxus::prelude::*;
pub use helper_fun::set_meta_tags;
// use components::Hero; // use components::Hero;
use views::{Blog, Blogs, ContactMe, Home, Navbar, NewHome, Projects}; use views::{Blog, Blogs, ContactMe, Home, Navbar, NewHome, Projects};
@ -55,7 +54,6 @@ fn PageNotFound(route: Vec<String>) -> Element {
rsx! { rsx! {
document::Stylesheet { href: asset!("/assets/styling/notFound.css") } document::Stylesheet { href: asset!("/assets/styling/notFound.css") }
document::Title { "Brock Tomlinson - Not Found" } document::Title { "Brock Tomlinson - Not Found" }
set_meta_tags { description: "This is not a valid page", keywords: "404 Nothing" }
div { id: "not-found", div { id: "not-found",
h1 { "Page not found" } h1 { "Page not found" }
p { "We are terribly sorry, but the page you requested doesn't exist." } p { "We are terribly sorry, but the page you requested doesn't exist." }
@ -65,15 +63,3 @@ fn PageNotFound(route: Vec<String>) -> Element {
} }
} }
} }
// The server function at the endpoint "static_routes" will be called by the CLI to generate the list of static
// routes. You must explicitly set the endpoint to `"static_routes"` in the server function attribute instead of
// the default randomly generated endpoint.
// #[server(endpoint = "static_routes", output = server_fn::codec::Json)]
// async fn static_routes() -> Result<Vec<String>, ServerFnError> {
// // The `Routable` trait has a `static_routes` method that returns all static routes in the enum
// Ok(Route::static_routes()
// .iter()
// .map(ToString::to_string)
// .collect())
// }

View File

@ -13,6 +13,30 @@ fn main() {
// The `launch` function is the main entry point for a dioxus app. It takes a component and renders it with the platform feature // The `launch` function is the main entry point for a dioxus app. It takes a component and renders it with the platform feature
// you have enabled // you have enabled
dioxus::launch(App); dioxus::launch(App);
// for compiling the app
// dioxus::LaunchBuilder::new()
// // Set the server config only if we are building the server target
// .with_cfg(server_only! {
// ServeConfig::builder()
// // Enable incremental rendering
// .incremental(
// IncrementalRendererConfig::new()
// // Store static files in the public directory where other static assets like wasm are stored
// .static_dir(
// std::env::current_exe()
// .unwrap()
// .parent()
// .unwrap()
// .join("public")
// )
// // Don't clear the public folder on every build. The public folder has other files including the wasm
// // binary and static assets required for the app to run
// .clear_cache(false)
// )
// .enable_out_of_order_streaming()
// })
// .launch(App);
} }
/// App is the main component of our app. Components are the building blocks of dioxus apps. Each component is a function /// App is the main component of our app. Components are the building blocks of dioxus apps. Each component is a function
@ -35,25 +59,14 @@ fn App() -> Element {
} }
} }
#[cfg(feature = "ssg")] // The server function at the endpoint "static_routes" will be called by the CLI to generate the list of static
fn main() { // routes. You must explicitly set the endpoint to `"static_routes"` in the server function attribute instead of
use dioxus_fullstack::{incremental::IncrementalRendererConfig, prelude::*}; // the default randomly generated endpoint.
// #[server(endpoint = "static_routes", output = server_fn::codec::Json)]
LaunchBuilder::new() // async fn static_routes() -> Result<Vec<String>, ServerFnError> {
.with_cfg( // // The `Routable` trait has a `static_routes` method that returns all static routes in the enum
ServeConfig::builder() // Ok(Route::static_routes()
.incremental( // .iter()
IncrementalRendererConfig::new() // .map(ToString::to_string)
.static_dir( // .collect())
std::env::current_exe() // }
.unwrap()
.parent()
.unwrap()
.join("public"),
)
.clear_cache(false),
)
.enable_out_of_order_streaming(),
)
.launch(app);
}

View File

@ -1,11 +1,9 @@
use crate::{set_meta_tags, Route}; use crate::Route;
// use dioxus::logger::tracing::info; // use dioxus::logger::tracing::info;
use dioxus::prelude::*; use dioxus::prelude::*;
use reqwest; use reqwest;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
// const BLOG_CSS: Asset = asset!("/assets/styling/blog.css");
/// The Blog page component that will be rendered when the current route is `[Route::Blog]` /// The Blog page component that will be rendered when the current route is `[Route::Blog]`
/// ///
/// The component takes a `id` prop of type `i32` from the route enum. Whenever the id changes, the component function will be /// The component takes a `id` prop of type `i32` from the route enum. Whenever the id changes, the component function will be
@ -54,11 +52,6 @@ pub fn Blog(blog_title: String) -> Element {
// span { " <---> " } // span { " <---> " }
Link { to: Route::Blogs { page_num: 0 }, "Go Back" } Link { to: Route::Blogs { page_num: 0 }, "Go Back" }
if let Some(blog_content) = &*blog_resource.read() { if let Some(blog_content) = &*blog_resource.read() {
document::Meta { name: "description", content: "{blog_content.blog_title}" }
document::Meta {
name: "keywords",
content: "webdev software engineer fullstack",
}
div { id: "blog_info", div { id: "blog_info",
h1 { "{blog_content.blog_title}" } h1 { "{blog_content.blog_title}" }
div { div {
@ -85,7 +78,7 @@ async fn get_blog(blog_name: String) -> Result<BlogContent, reqwest::Error> {
let client = reqwest::Client::new(); let client = reqwest::Client::new();
let res = client let res = client
.get(format!("http://localhost:8000/blogs/blog/{}", blog_name)) .get(format!("/blogs/blog/{}", blog_name))
.timeout(std::time::Duration::from_secs(10)) .timeout(std::time::Duration::from_secs(10))
.send() .send()
.await? .await?
@ -137,10 +130,6 @@ pub fn Blogs(page_num: u32) -> Element {
document::Stylesheet { href: asset!("/assets/styling/blog.css") } document::Stylesheet { href: asset!("/assets/styling/blog.css") }
div { id: "blogs", div { id: "blogs",
document::Title { "Brock Tomlinson - Blogs" } document::Title { "Brock Tomlinson - Blogs" }
set_meta_tags {
description: "This is a collection of blog posts, ranging from tutorials, technologies I found interesting, and opinion pieces",
keywords: "blogs blog software engineer webdev",
}
div { id: "blogs-title", div { id: "blogs-title",
h1 { "Blogs" } h1 { "Blogs" }
p { p {
@ -239,10 +228,7 @@ async fn get_blogs_preview(
let client = reqwest::Client::new(); let client = reqwest::Client::new();
let res = client let res = client
.get(format!( .get(format!("blogs/{}/{}", _num_limit, page_num))
"http://localhost:8000/blogs/{}/{}",
_num_limit, page_num
))
.timeout(std::time::Duration::from_secs(10)) .timeout(std::time::Duration::from_secs(10))
.send() .send()
.await? .await?

View File

@ -4,7 +4,7 @@ use serde_json;
// use dioxus::logger::tracing; // use dioxus::logger::tracing;
use dioxus::prelude::*; use dioxus::prelude::*;
use crate::{helper_fun::set_meta_tags, views::Contact}; use crate::views::Contact;
#[component] #[component]
pub fn ContactMe() -> Element { pub fn ContactMe() -> Element {
@ -17,10 +17,6 @@ pub fn ContactMe() -> Element {
rsx! { rsx! {
document::Stylesheet { href: asset!("/assets/styling/contactme.css") } document::Stylesheet { href: asset!("/assets/styling/contactme.css") }
document::Title { "Brock Tomlinson - Contact" } document::Title { "Brock Tomlinson - Contact" }
set_meta_tags {
description: "Get in Touch, get in contact",
keywords: "contact software engineer webdev",
}
div { id: "ContactMe", div { id: "ContactMe",
div { div {
h2 { "Get in Touch" } h2 { "Get in Touch" }

View File

@ -38,7 +38,7 @@ pub fn Home() -> Element {
I am developing the language of how to design, develop, and create programs that are to industry standards and reasonably efficent. I am developing the language of how to design, develop, and create programs that are to industry standards and reasonably efficent.
I bring the lessons learned from each project I have completed, I bring the lessons learned from each project I have completed,
learning from the mistakes I have made and bringing improved versions forward into the next project.", learning from the mistakes I have made and bringing improved versions forward into the next project.",
keywords: "dev webdev Rust rust-lang software engineer", keywords: "webdev Rust software engineer projects blog darkicewol50",
} }
div { div {
div { id: "home-intro", div { id: "home-intro",

View File

@ -1,4 +1,4 @@
use crate::helper_fun::{get_tech_logos_from_str, set_meta_tags}; use crate::helper_fun::get_tech_logos_from_str;
use dioxus::prelude::*; use dioxus::prelude::*;
#[component] #[component]
@ -6,10 +6,6 @@ pub fn Projects(#[props(default = true)] independent_page: bool) -> Element {
rsx! { rsx! {
if independent_page { if independent_page {
document::Title { "Brock Tomlinson - Projects" } document::Title { "Brock Tomlinson - Projects" }
set_meta_tags {
description: "Top Featured and Recent Projects",
keywords: "projects Rust CSS HTML JavaScript Dioxus Gitea Git software engineer",
}
} }
div { div {
h2 { "Projects" } h2 { "Projects" }
@ -17,21 +13,43 @@ pub fn Projects(#[props(default = true)] independent_page: bool) -> Element {
} }
div { class: "project-section", div { class: "project-section",
ProjectCards { ProjectCards {
project_name: "Portfolio Site Version 1.1.0", project_name: "Personal Backend",
gitea_link: "https://gitea.bajacloud.duckdns.org/darkicewolf50/darkicewolf50Cloud",
dockerhub_link: "https://hub.docker.com/r/darkicewolf50/darkicewolf50cloud",
project_img: "https://actix.rs/img/logo.png",
techs_used: vec![
"Rust",
"Actix",
"Github Actions",
"Docker",
"Traefik",
"Gitea",
"Git",
"Github",
],
project_des: "I find that this is a much better option in compareision to FastAPI as it does not require a post request
to input data instead it give the option for the url to give the parameters it needs. I don't have any complains about using Actix, its mature stable and fairly popular.
This backend application also uses comrak to convert markdown blogs into html docuemnts that are then seen by you the user.
This honestly was a fun challenge getting the blogs previews, ensuring correctness and not allowing for any unknown states,
this will serve as a great basis for any future backend requirements that I may have.",
}
ProjectCards {
project_name: "Portfolio Site Version 2.0.1",
website_link: "https://darkicewolf50.pages.dev", website_link: "https://darkicewolf50.pages.dev",
gitea_link: "https://gitea.bajacloud.duckdns.org/darkicewolf50/personal_site", gitea_link: "https://gitea.bajacloud.duckdns.org/darkicewolf50/personal_site",
project_img: "https://res.cloudinary.com/dpgrgsh7g/image/upload/v1745630861/Portfolio_site_k4mhmj.png", project_img: "https://res.cloudinary.com/dpgrgsh7g/image/upload/v1745630861/Portfolio_site_k4mhmj.png",
techs_used: vec!["Rust", "CSS", "Dioxus", "Git", "Gitea"], techs_used: vec!["Rust", "CSS", "Dioxus", "Git", "Gitea"],
project_des: "This project was a great test of my newly learned Rust. project_des: "This project was a great test of my newly learned Rust.
This minor update added functionality for the contact me, the ground work for the blogs part of the site, as well as many minor This major update added functionality for the contact me, the blogs part of the site, as well as many minor
UI consistencies to ensure that all of the buttons and links felt like buttons and links. UI consistencies to ensure that all of the buttons and links felt like buttons and links.
I was surprise how easy it was to set up a discord webhook using the 'reqwest' crate. I was surprise how easy it was to set up a discord webhook using the 'reqwest' crate.
As I continue on I find myself struggling with how and why to use databases for content I generate. As I continue on I find myself struggling with how and why to use databases for content I generate.
I think using tools like disocrd webhooks and email notifications are great for users but certainly not great for reading data from. I think using tools like disocrd webhooks and email notifications are great for users but certainly not great for reading data from.
The part I am both excited for and deading is going to be the blogs component which I believe I have solved for now.", I was very satisfied with serde, and comrak for converting markdown fiels into html.
I use this extensively for the blogs search menu and the blog itself to display the blog itself in a consistent way without needing to write a whole library.",
} }
ProjectCards { ProjectCards {
project_name: "Portfolio Site", project_name: "Portfolio Site 1.0.0",
website_link: "https://darkicewolf50.github.io", website_link: "https://darkicewolf50.github.io",
github_link: "https://github.com/darkicewolf50/darkicewolf50.github.io", github_link: "https://github.com/darkicewolf50/darkicewolf50.github.io",
project_img: "https://res.cloudinary.com/dpgrgsh7g/image/upload/v1745630861/Portfolio_site_k4mhmj.png", project_img: "https://res.cloudinary.com/dpgrgsh7g/image/upload/v1745630861/Portfolio_site_k4mhmj.png",
@ -44,6 +62,7 @@ pub fn Projects(#[props(default = true)] independent_page: bool) -> Element {
ProjectCards { ProjectCards {
project_name: "UCalgary Baja Backend", project_name: "UCalgary Baja Backend",
project_img: "https://www.svgrepo.com/show/448221/docker.svg", project_img: "https://www.svgrepo.com/show/448221/docker.svg",
dockerhub_link: "https://hub.docker.com/r/darkicewolf50/uofcbajacloud",
techs_used: vec!["Python", "FastAPI", "Github Actions", "Docker", "Traefik", "Git", "Github"], techs_used: vec!["Python", "FastAPI", "Github Actions", "Docker", "Traefik", "Git", "Github"],
project_des: "This is going to be extremely cost saving for the non-profit club UCalgary Baja. project_des: "This is going to be extremely cost saving for the non-profit club UCalgary Baja.
Using automated uploads and linting to check the Python and FastAPI code was excellent for learning how to self-host a web server. Using automated uploads and linting to check the Python and FastAPI code was excellent for learning how to self-host a web server.
@ -83,6 +102,7 @@ pub fn ProjectCards(
website_link: Option<&'static str>, website_link: Option<&'static str>,
github_link: Option<&'static str>, github_link: Option<&'static str>,
gitea_link: Option<&'static str>, gitea_link: Option<&'static str>,
dockerhub_link: Option<&'static str>,
project_name: &'static str, project_name: &'static str,
techs_used: Vec<&'static str>, techs_used: Vec<&'static str>,
project_des: &'static str, project_des: &'static str,
@ -108,6 +128,11 @@ pub fn ProjectCards(
get_tech_logos_from_str { used_tech: "Gitea" } get_tech_logos_from_str { used_tech: "Gitea" }
} }
} }
if let Some(dockerhub) = dockerhub_link {
a { href: "{dockerhub}", id: "dockerhub",
get_tech_logos_from_str { used_tech: "Docker" }
}
}
if let Some(site) = website_link { if let Some(site) = website_link {
a { href: "{site}", a { href: "{site}",
get_tech_logos_from_str { used_tech: "Internet" } get_tech_logos_from_str { used_tech: "Internet" }