Initial CV lib commit

This commit is contained in:
2025-03-07 16:59:01 +02:00
commit 9fbc7d6f81
54 changed files with 812 additions and 0 deletions

11
.cargo/config.toml Normal file
View File

@@ -0,0 +1,11 @@
[unstable]
codegen-backend = true
build-std = ["std", "panic_abort", "core", "alloc"]
build-std-features = ["panic_immediate_abort"]
[profile.server-dev]
codegen-backend = "cranelift"
[build]
rustflags = ["--cfg=has_std", "-Z", "threads=8"]
target = "x86_64-unknown-linux-gnu"

103
.gitignore vendored Normal file
View File

@@ -0,0 +1,103 @@
# Rust / Leptos
target/
dist/
debug/
Cargo.lock
**/*.rs.bk
*.pdb
# Ides
.idea
.vscode/settings.json
*.sublime*
# runtime data
pids
*.pid
*.seed
*.pid.lock
# miscellaneous
/.vs
.DS_Store
.Thumbs.db
debug.log
TODO.md
### Javascript
.npm/
.yarn/
package-lock.json
node_modules
yarn.lock
bun.lockb
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
*.tgz
# dotenv environment variables file
.env
# Android
# Gradle files
.gradle/
build/
# Local configuration file (sdk path, etc)
local.properties
# Log/OS Files
*.log
# Android Studio generated files and folders
captures/
.externalNativeBuild/
.cxx/
*.apk
output.json
# IntelliJ
*.iml
.idea/
misc.xml
deploymentTargetDropDown.xml
render.experimental.xml
# Keystore files
*.jks
*.keystore
# Google Services (e.g. APIs or Firebase)
google-services.json
# Android Profiling
*.hprof
# Compiled class file
*.class
# Log file
*.log
# BlueJ files
*.ctxt
# Mobile Tools for Java (J2ME)
.mtj.tmp/
# Package Files #
*.jar
*.war
*.nar
*.ear
*.zip
*.tar.gz
*.rar
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid*
replay_pid*

4
.ignore Normal file
View File

@@ -0,0 +1,4 @@
frontend/assets/fonts/*
src-tauri/icons/*
src-tauri/gen/*
target/*

45
Cargo.toml Normal file
View File

@@ -0,0 +1,45 @@
[package]
name = "portfolio_website"
version = "0.1.0"
authors = ["Stephen Power"]
categories = ["wasm", "web-programming"]
edition = "2021"
keywords = ["leptos", "cv", "portfolio"]
license = "AGPL-3.0"
readme = "README.md"
repository = "https://github.com/opensourcecheemsburgers/portfolio-website"
rust-version = "1.75"
description = "My CV built with Leptos and Tailwind."
[lints.rust]
unsafe_code = "forbid"
[lints.clippy]
all = "warn"
pedantic = "warn"
nursery = "warn"
cargo = "warn"
[profile.release]
panic = "abort"
codegen-units = 1
lto = "fat"
opt-level = "z"
strip = true
[profile.dev]
panic = "abort"
opt-level = 0
codegen-units = 256
lto = "off"
incremental = true
debug = false # Enable if debugging is necessary.
[target.x86_64-unknown-linux-gnu]
linker = "clang"
rustflags = ["-C", "link-arg=-fuse-ld=/usr/bin/mold"]
[dependencies]
leptos = { version = "0.6.12", features = ["csr", "nightly"] }
leptos_router = { version = "0.6.12", features = ["csr", "nightly"] }
phosphor-leptos = "0.5.0"

25
Trunk.toml Normal file
View File

@@ -0,0 +1,25 @@
[build]
release = false
dist = "./dist"
filehash = true
target = "./index.html"
# [watch]
# watch = ["./src", "./index.html", "./assets"]
# ignore = ["../target", "./dist", "../src-tauri"]
[serve]
addresses = ["127.0.0.1"]
port = 42069
open = false
no_autoreload = false
ws_protocol = "ws"
[clean]
dist = "./dist"
cargo = false
[tools]
wasm_bindgen = "0.2.99"
wasm_opt = "version_118"
tailwindcss = "3.4.10"

342
css/input.css Normal file
View File

@@ -0,0 +1,342 @@
@tailwind base;
@tailwind components;
@tailwind utilities;
@layer base {
.crisp-edges {
image-rendering: -webkit-optimize-contrast;
image-rendering: -moz-crisp-edges;
}
/* comfortaa-300 - latin */
@font-face {
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
font-family: "Comfortaa";
font-style: normal;
font-weight: 300;
src: url("../../fonts/comfortaa/comfortaa-v45-latin-300.woff2")
format("woff2"); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
}
/* comfortaa-regular - latin */
@font-face {
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
font-family: "Comfortaa";
font-style: normal;
font-weight: 400;
src: url("../../fonts/comfortaa/comfortaa-v45-latin-regular.woff2")
format("woff2"); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
}
/* comfortaa-500 - latin */
@font-face {
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
font-family: "Comfortaa";
font-style: normal;
font-weight: 500;
src: url("../../fonts/comfortaa/comfortaa-v45-latin-500.woff2")
format("woff2"); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
}
/* comfortaa-600 - latin */
@font-face {
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
font-family: "Comfortaa";
font-style: normal;
font-weight: 600;
src: url("../../fonts/comfortaa/comfortaa-v45-latin-600.woff2")
format("woff2"); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
}
/* comfortaa-700 - latin */
@font-face {
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
font-family: "Comfortaa";
font-style: normal;
font-weight: 700;
src: url("../../fonts/comfortaa/comfortaa-v45-latin-700.woff2")
format("woff2"); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
}
/* figtree-300 - latin */
@font-face {
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
font-family: "Figtree";
font-style: normal;
font-weight: 300;
src: url("../../fonts/figtree/figtree-v5-latin-300.woff2") format("woff2"); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
}
/* figtree-300italic - latin */
@font-face {
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
font-family: "Figtree";
font-style: italic;
font-weight: 300;
src: url("../../fonts/figtree/figtree-v5-latin-300italic.woff2")
format("woff2"); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
}
/* figtree-regular - latin */
@font-face {
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
font-family: "Figtree";
font-style: normal;
font-weight: 400;
src: url("../../fonts/figtree/figtree-v5-latin-regular.woff2")
format("woff2"); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
}
/* figtree-italic - latin */
@font-face {
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
font-family: "Figtree";
font-style: italic;
font-weight: 400;
src: url("../../fonts/figtree/figtree-v5-latin-italic.woff2")
format("woff2"); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
}
/* figtree-500 - latin */
@font-face {
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
font-family: "Figtree";
font-style: normal;
font-weight: 500;
src: url("../../fonts/figtree/figtree-v5-latin-500.woff2") format("woff2"); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
}
/* figtree-500italic - latin */
@font-face {
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
font-family: "Figtree";
font-style: italic;
font-weight: 500;
src: url("../../fonts/figtree/figtree-v5-latin-500italic.woff2")
format("woff2"); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
}
/* figtree-600 - latin */
@font-face {
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
font-family: "Figtree";
font-style: normal;
font-weight: 600;
src: url("../../fonts/figtree/figtree-v5-latin-600.woff2") format("woff2"); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
}
/* figtree-600italic - latin */
@font-face {
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
font-family: "Figtree";
font-style: italic;
font-weight: 600;
src: url("../../fonts/figtree/figtree-v5-latin-600italic.woff2")
format("woff2"); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
}
/* figtree-700 - latin */
@font-face {
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
font-family: "Figtree";
font-style: normal;
font-weight: 700;
src: url("../../fonts/figtree/figtree-v5-latin-700.woff2") format("woff2"); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
}
/* figtree-700italic - latin */
@font-face {
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
font-family: "Figtree";
font-style: italic;
font-weight: 700;
src: url("../../fonts/figtree/figtree-v5-latin-700italic.woff2")
format("woff2"); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
}
/* figtree-800 - latin */
@font-face {
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
font-family: "Figtree";
font-style: normal;
font-weight: 800;
src: url("../../fonts/figtree/figtree-v5-latin-800.woff2") format("woff2"); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
}
/* figtree-800italic - latin */
@font-face {
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
font-family: "Figtree";
font-style: italic;
font-weight: 800;
src: url("../../fonts/figtree/figtree-v5-latin-800italic.woff2")
format("woff2"); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
}
/* figtree-900 - latin */
@font-face {
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
font-family: "Figtree";
font-style: normal;
font-weight: 900;
src: url("../../fonts/figtree/figtree-v5-latin-900.woff2") format("woff2"); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
}
/* figtree-900italic - latin */
@font-face {
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
font-family: "Figtree";
font-style: italic;
font-weight: 900;
src: url("../../fonts/figtree/figtree-v5-latin-900italic.woff2")
format("woff2"); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
}
/* cousine-regular - latin */
@font-face {
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
font-family: "Cousine";
font-style: normal;
font-weight: 400;
src: url("../../fonts/cousine/cousine-v27-latin-regular.woff2")
format("woff2"); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
}
/* cousine-italic - latin */
@font-face {
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
font-family: "Cousine";
font-style: italic;
font-weight: 400;
src: url("../../fonts/cousine/cousine-v27-latin-italic.woff2")
format("woff2"); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
}
/* cousine-700 - latin */
@font-face {
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
font-family: "Cousine";
font-style: normal;
font-weight: 700;
src: url("../../fonts/cousine/cousine-v27-latin-700.woff2") format("woff2"); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
}
/* cousine-700italic - latin */
@font-face {
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
font-family: "Cousine";
font-style: italic;
font-weight: 700;
src: url("../../fonts/cousine/cousine-v27-latin-700italic.woff2")
format("woff2"); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
}
/* open-sans-300 - latin */
@font-face {
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
font-family: "Open Sans";
font-style: normal;
font-weight: 300;
src: url("../../fonts/open-sans/open-sans-v40-latin-300.woff2")
format("woff2"); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
}
/* open-sans-300italic - latin */
@font-face {
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
font-family: "Open Sans";
font-style: italic;
font-weight: 300;
src: url("../../fonts/open-sans/open-sans-v40-latin-300italic.woff2")
format("woff2"); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
}
/* open-sans-regular - latin */
@font-face {
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
font-family: "Open Sans";
font-style: normal;
font-weight: 400;
src: url("../../fonts/open-sans/open-sans-v40-latin-regular.woff2")
format("woff2"); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
}
/* open-sans-italic - latin */
@font-face {
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
font-family: "Open Sans";
font-style: italic;
font-weight: 400;
src: url("../../fonts/open-sans/open-sans-v40-latin-italic.woff2")
format("woff2"); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
}
/* open-sans-500 - latin */
@font-face {
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
font-family: "Open Sans";
font-style: normal;
font-weight: 500;
src: url("../../fonts/open-sans/open-sans-v40-latin-500.woff2")
format("woff2"); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
}
/* open-sans-500italic - latin */
@font-face {
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
font-family: "Open Sans";
font-style: italic;
font-weight: 500;
src: url("../../fonts/open-sans/open-sans-v40-latin-500italic.woff2")
format("woff2"); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
}
/* open-sans-600 - latin */
@font-face {
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
font-family: "Open Sans";
font-style: normal;
font-weight: 600;
src: url("../../fonts/open-sans/open-sans-v40-latin-600.woff2")
format("woff2"); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
}
/* open-sans-600italic - latin */
@font-face {
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
font-family: "Open Sans";
font-style: italic;
font-weight: 600;
src: url("../../fonts/open-sans/open-sans-v40-latin-600italic.woff2")
format("woff2"); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
}
/* open-sans-700italic - latin */
@font-face {
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
font-family: "Open Sans";
font-style: italic;
font-weight: 700;
src: url("../../fonts/open-sans/open-sans-v40-latin-700italic.woff2")
format("woff2"); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
}
/* open-sans-800 - latin */
@font-face {
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
font-family: "Open Sans";
font-style: normal;
font-weight: 800;
src: url("../../fonts/open-sans/open-sans-v40-latin-800.woff2")
format("woff2"); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
}
/* open-sans-800italic - latin */
@font-face {
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
font-family: "Open Sans";
font-style: italic;
font-weight: 800;
src: url("../../fonts/open-sans/open-sans-v40-latin-800italic.woff2")
format("woff2"); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
}
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

12
index.html Normal file
View File

@@ -0,0 +1,12 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>CV</title>
<link data-trunk rel="tailwind-css" href="./css/input.css" />
<link data-trunk rel="copy-dir" href="./fonts" />
<link data-trunk rel="copy-dir" href="./images" />
<link data-trunk rel="rust"/>
</head>
</html>

7
package.json Normal file
View File

@@ -0,0 +1,7 @@
{
"dependencies": {
"daisyui": "^4.12.23",
"picocolors": "^1.1.1",
"tailwindcss": "3.4.10"
}
}

29
src/education.rs Normal file
View File

@@ -0,0 +1,29 @@
use crate::section::Section;
use leptos::{component, view, Children, IntoView};
#[component]
#[must_use]
pub fn EducationExperience(children: Children) -> impl IntoView {
view! { <Section title="Education">{children()}</Section> }
}
#[component]
#[must_use]
pub fn Education(
institution: &'static str,
degree: &'static str,
time_period: &'static str,
) -> impl IntoView {
view! {
<div class="flex flex-col space-y-1">
<div class="flex flex-row justify-between w-full text-sm">
<div class="flex flex-row font-sans text-black">
<h4>{institution} {" - "} {degree}</h4>
</div>
<div class="flex flex-row font-sans text-gray-500">
<p>{time_period}</p>
</div>
</div>
</div>
}
}

67
src/header.rs Normal file
View File

@@ -0,0 +1,67 @@
use leptos::{component, view, IntoView};
use phosphor_leptos::{Browser, IconWeight, Mailbox, MapPin, Phone};
#[component]
#[must_use]
pub fn Header(
name: &'static str,
job_title: &'static str,
location: &'static str,
location_osm_link: &'static str,
phone_number: &'static str,
email: &'static str,
website: &'static str,
) -> impl IntoView {
view! {
<div class="flex flex-row justify-between w-full">
<HeaderLeft name=name job_title=job_title />
<HeaderRight
location=location
location_osm_link=location_osm_link
phone_number
email=email
website=website
/>
</div>
}
}
#[component]
fn HeaderLeft(name: &'static str, job_title: &'static str) -> impl IntoView {
view! {
<div class="flex flex-col space-y-4">
<h1 class="font-serif text-3xl font-semibold text-black">{name}</h1>
<h2 class="font-sans text-xl text-gray-500">{job_title}</h2>
</div>
}
}
#[component]
fn HeaderRight(
location: &'static str,
location_osm_link: &'static str,
phone_number: &'static str,
email: &'static str,
website: &'static str,
) -> impl IntoView {
view! {
<div class="flex flex-col space-y-0.5 font-sans text-gray-600 text-[11px]">
<div class="flex flex-row gap-2 items-center hover:cursor-pointer hover:text-info">
<MapPin weight=IconWeight::Fill class="fill-gray-300 w-[18px] h-[18px]" />
<a href=location_osm_link>{location}</a>
</div>
<div class="flex flex-row gap-2 items-center hover:cursor-pointer fill-gray-400 hover:text-info">
<Phone weight=IconWeight::Fill class="fill-gray-300 w-[18px] h-[18px]" />
<a href=format!("tel:{}", phone_number)>{phone_number}</a>
</div>
<div class="flex flex-row gap-2 items-center hover:cursor-pointer fill-gray-400 hover:text-info">
<Mailbox weight=IconWeight::Fill class="fill-gray-300 w-[18px] h-[18px]" />
<a href=format!("mailto:{}", email)>{email}</a>
</div>
<div class="flex flex-row gap-2 items-center hover:text-info">
<Browser weight=IconWeight::Fill class="fill-gray-300 w-[18px] h-[18px]" />
<a href=format!("https://{}", website)>{website}</a>
</div>
</div>
}
}

8
src/lib.rs Normal file
View File

@@ -0,0 +1,8 @@
pub mod education;
pub mod header;
pub mod page;
pub mod projects;
pub mod section;
pub mod skills;
pub mod summary;
pub mod work;

13
src/page.rs Normal file
View File

@@ -0,0 +1,13 @@
use leptos::{component, view, Children, IntoView};
#[component]
#[must_use]
pub fn Page(children: Children) -> impl IntoView {
view! {
<div class="flex flex-col justify-center items-center place-content-center leading-[1.15]">
<div class="py-8 bg-white rounded px-[72px] px-18 h-a4 w-a4 inset-shadow-black inset-shadow-sm">
<div class="flex flex-col space-y-4 w-full h-full">{children()}</div>
</div>
</div>
}
}

27
src/projects.rs Normal file
View File

@@ -0,0 +1,27 @@
use crate::section::Section;
use leptos::{component, view, Children, For, IntoView};
#[component]
#[must_use]
pub fn PersonalExperience(children: Children) -> impl IntoView {
view! { <Section title="Personal Experience">{children()}</Section> }
}
#[component]
#[must_use]
pub fn Project(title: &'static str, achievements: Vec<&'static str>) -> impl IntoView {
view! {
<div class="flex flex-col space-y-1.5">
<div class="flex flex-row justify-between w-full text-sm">
<div class="flex flex-row font-sans font-medium text-black">
<h4>{title}</h4>
</div>
</div>
<ul class="space-y-1 font-sans list-disc list-inside">
<For each=move || achievements.clone() key=std::clone::Clone::clone let:achievement>
<li class="px-2">{achievement}</li>
</For>
</ul>
</div>
}
}

14
src/section.rs Normal file
View File

@@ -0,0 +1,14 @@
use leptos::{component, view, Children, IntoView};
#[component]
#[must_use]
pub fn Section(children: Children, title: &'static str) -> impl IntoView {
view! {
<div class="flex flex-col space-y-2 text-black text-[11px] text-pretty">
<div class="h-px divider divider-neutral divider-start">
<h3 class="font-sans text-lg font-medium text-black">{title}</h3>
</div>
<div class="flex flex-col space-y-3">{children()}</div>
</div>
}
}

34
src/skills.rs Normal file
View File

@@ -0,0 +1,34 @@
use leptos::{component, view, Children, For, IntoView};
use crate::section::Section;
#[component]
#[must_use]
pub fn Skills(children: Children) -> impl IntoView {
view! {
<Section title="Skills">
<div class="flex flex-row justify-between w-full">{children()}</div>
</Section>
}
}
#[component]
#[must_use]
pub fn Skill(title: &'static str, items: Vec<&'static str>) -> impl IntoView {
view! {
<div class="flex flex-col space-y-1">
<div class="flex flex-row justify-between w-full text-sm">
<div class="flex flex-row font-sans font-medium text-black">
<h4>{title}</h4>
</div>
</div>
<ul class="font-sans list-disc list-inside leading-[1.5]">
<For each=move || items.clone() key=std::clone::Clone::clone let:item>
<div class="flex flex-row gap-1 items-center">
<li class="text-[11px]">{item}</li>
</div>
</For>
</ul>
</div>
}
}

9
src/summary.rs Normal file
View File

@@ -0,0 +1,9 @@
use leptos::{component, view, IntoView};
#[component]
#[must_use]
pub fn Summary(summary: &'static str) -> impl IntoView {
view! {
<div class="pt-3 font-sans text-justify text-black text-[11px] text-pretty">{summary}</div>
}
}

35
src/work.rs Normal file
View File

@@ -0,0 +1,35 @@
use crate::section::Section;
use leptos::{component, view, Children, For, IntoView};
#[component]
#[must_use]
pub fn WorkExperience(children: Children) -> impl IntoView {
view! { <Section title="Work Experience">{children()}</Section> }
}
#[component]
#[must_use]
pub fn Job(
company: &'static str,
title: &'static str,
time_period: &'static str,
achievements: Vec<&'static str>,
) -> impl IntoView {
view! {
<div class="flex flex-col space-y-1">
<div class="flex flex-row justify-between w-full text-sm">
<div class="flex flex-row font-sans font-medium text-black">
<h4>{company} {" - "} {title}</h4>
</div>
<div class="flex flex-row font-sans text-gray-500">
<p>{time_period}</p>
</div>
</div>
<ul class="space-y-1 font-sans list-disc list-inside">
<For each=move || achievements.clone() key=std::clone::Clone::clone let:achievement>
<li class="px-2">{achievement}</li>
</For>
</ul>
</div>
}
}

27
tailwind.config.js Normal file
View File

@@ -0,0 +1,27 @@
/** @type {import('tailwindcss').Config} */
module.exports = {
mode: "jit",
content: [
"./css/*.{js,ts,jsx,tsx,css,scss,html}",
"./css/**/*.{js,ts,jsx,tsx}",
"./src/**/*.{js,ts,jsx,tsx,rs,scss,css,html}",
"./index.html",
"./src/main.rs",
],
plugins: [require("daisyui"), require("@tailwindcss/typography")],
theme: {
extend: {
fontFamily: {
sans: ["Figtree"],
serif: ["Rufina"],
mono: ["Cousine"],
},
width: {
a4: "210mm",
},
height: {
a4: "297mm",
},
},
},
};