initial commit with existing content

This commit is contained in:
Triston Armstrong 2024-03-24 21:26:32 -05:00
commit f0860b52a2
19 changed files with 3637 additions and 0 deletions

3
.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
/target
.shuttle-storage
Secrets*.toml

1
.prettierrc.toml Normal file
View File

@ -0,0 +1 @@
tabWidth = 4

3184
Cargo.lock generated Normal file

File diff suppressed because it is too large Load Diff

17
Cargo.toml Normal file
View File

@ -0,0 +1,17 @@
[package]
name = "htmx-portfolio"
version = "0.1.0"
edition = "2021"
[dependencies]
askama = { version = "0.12.1", features = ["with-axum"] }
askama_axum = "0.4.0"
axum = "0.7.4"
serde = { version = "1.0.189", features = ["derive"] }
serde_json = "1.0.107"
shuttle-axum = "0.42.0"
shuttle-runtime = "0.42.0"
shuttle-shared-db = { version = "0.42.0", features = ["postgres", "sqlx"] }
sqlx = { version = "0.7.2", features = ["runtime-tokio-rustls", "postgres"] }
tokio = "1.28.2"
tokio-stream = { version = "0.1.14", features = ["sync"] }

3
README.md Normal file
View File

@ -0,0 +1,3 @@
# Axum + htmx
This is an example of how you can use Shuttle with Axum, Askama and htmx to create a frontend that's easily extendable and requires zero framework knowledge, while being able to easily inject variables from the backend into the frontend.

BIN
assets/favicon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 106 KiB

4
migrations/0000_init.sql Normal file
View File

@ -0,0 +1,4 @@
CREATE TABLE IF NOT EXISTS todos (
id SERIAL PRIMARY KEY,
description TEXT NOT NULL
);

34
src/errors.rs Normal file
View File

@ -0,0 +1,34 @@
use axum::http::StatusCode;
use axum::response::{IntoResponse, Response};
pub enum ApiError {
SQLError(sqlx::Error),
HTTPError(axum::http::Error),
}
impl IntoResponse for ApiError {
fn into_response(self) -> Response {
match self {
Self::SQLError(e) => {
(StatusCode::INTERNAL_SERVER_ERROR, format!("SQL error: {e}")).into_response()
}
Self::HTTPError(e) => (
StatusCode::INTERNAL_SERVER_ERROR,
format!("HTTP error: {e}"),
)
.into_response(),
}
}
}
impl From<sqlx::Error> for ApiError {
fn from(e: sqlx::Error) -> Self {
Self::SQLError(e)
}
}
impl From<axum::http::Error> for ApiError {
fn from(e: axum::http::Error) -> Self {
Self::HTTPError(e)
}
}

12
src/main.rs Normal file
View File

@ -0,0 +1,12 @@
mod errors;
mod models;
mod router;
mod routes;
mod templates;
#[shuttle_runtime::main]
async fn main() -> shuttle_axum::ShuttleAxum {
let router = router::init_router();
Ok(router.into())
}

2
src/models.rs Normal file
View File

@ -0,0 +1,2 @@
// use serde::{Deserialize, Serialize};
// put models here

32
src/router.rs Normal file
View File

@ -0,0 +1,32 @@
use axum::{routing::get, Router};
use crate::routes;
#[derive(Clone)]
pub struct AppState {}
// put all notes routes here
pub fn init_notes_routes() -> Router {
Router::new().route("/", get(routes::notes))
}
// put all tutorial routes here
pub fn init_tuts_routes() -> Router {
Router::new().route("/", get(routes::tuts))
}
// put any non nested routes here
pub fn init_utily_routes() -> Router {
Router::new()
.route("/", get(routes::portfolio))
.route("/styles.css", get(routes::styles))
}
pub fn init_router() -> Router {
let routes: Router<()> = Router::<()>::new()
.nest("/tuts", init_tuts_routes())
.nest("/notes", init_notes_routes())
.nest("/", init_utily_routes());
Router::new().nest("/", routes)
}

27
src/routes.rs Normal file
View File

@ -0,0 +1,27 @@
use axum::{
http::StatusCode,
response::{IntoResponse, Response},
};
use crate::{errors::ApiError, templates};
pub async fn portfolio() -> impl IntoResponse {
templates::Portfolio
}
pub async fn notes() -> impl IntoResponse {
templates::Notes
}
pub async fn tuts() -> impl IntoResponse {
templates::Tuts
}
pub async fn styles() -> Result<impl IntoResponse, ApiError> {
let response = Response::builder()
.status(StatusCode::OK)
.header("Content-Type", "text/css")
.body(include_str!("../templates/styles.css").to_owned())?;
Ok(response)
}

13
src/templates.rs Normal file
View File

@ -0,0 +1,13 @@
use askama::Template;
#[derive(Template)]
#[template(path = "portfolio.html")]
pub struct Portfolio;
#[derive(Template)]
#[template(path = "notes.html")]
pub struct Notes;
#[derive(Template)]
#[template(path = "tuts.html")]
pub struct Tuts;

23
templates/base.html Normal file
View File

@ -0,0 +1,23 @@
<!doctype html>
<html lang="en">
<head>
<script
src="https://unpkg.com/htmx.org@1.9.6"
integrity="sha384-FhXw7b6AlE/jyjlZH5iHa/tTe9EpJ1Y55RjcgPbjeWMskSxZt1v9qkxLJWNJaGni"
crossorigin="anonymous"
></script>
<link rel="stylesheet" href="/styles.css" />
<link rel="stylesheet" href="https://rsms.me/inter/inter.css" />
<link
rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/water.css@2/out/water.css"
/>
<title>{% block title %}{{ title }} - My Site{% endblock %}</title>
{% block head %}{% endblock %}
</head>
<body>
{% block content %}
<p>Placeholder content</p>
{% endblock %}
</body>
</html>

31
templates/index.html Normal file
View File

@ -0,0 +1,31 @@
{% extends "base.html" %} {% block title %}Index{% endblock %} {% block content
%}
<h1>Shuttle Todos - Home</h1>
<a href="/stream">Event stream</a>
<h1>Shuttle Todos</h1>
<form id="add-form">
<input
placeholder="Your todo description..."
required
type="text"
name="description"
/>
<button
hx-post="/todos"
hx-trigger="click"
hx-target="#todos-content"
hx-swap="beforeend"
>
Add
</button>
</form>
<div
id="list"
hx-get="/todos"
hx-target="this"
hx-trigger="load"
hx-swap="outerHTML"
>
Loading...
</div>
{% endblock %}

12
templates/notes.html Normal file
View File

@ -0,0 +1,12 @@
{% extends "base.html" %} {% block title %}Notes{% endblock %} {% block content
%}
<nav>
<small>
<a href="/"><~ back</a>
</small>
</nav>
<hr />
<h1>Notes</h1>
<p>Here all my notes go</p>
{% endblock content%}

211
templates/portfolio.html Normal file
View File

@ -0,0 +1,211 @@
{% extends "base.html" %} {% block title %}Portfolio{% endblock %} {% block
content %}
<nav>
<small>
<a href="/tuts">Micro Tuts</a> / <a href="/notes">Notes</a> /
<a href="https://tristonarmstrong.com/social" target="_blank">Social</a>
</small>
</nav>
<hr />
<h1>Triston Armstrong 🫰</h1>
<p>
Full Stack Software Developer
<a target="_blank" href="https://ventrahealth.com">@VentraHealth</a>
</p>
<p>
I am a self taught Full Stack Software Developer with an unhealthy addiction
to solving problems using code.
</p>
<h2>🤹 Skills</h2>
<p>
<a
href="https://www.typescriptlang.org/docs/handbook/intro.html"
target="_blank"
style="text-decoration: none !important"
>Typescript</a
>
|
<a
href="https://docs.python.org/3/"
target="_blank"
style="text-decoration: none !important"
>Python</a
>
|
<a
href="https://doc.rust-lang.org/std/index.html"
target="_blank"
style="text-decoration: none !important"
>Rust</a
>
|
<a
href="https://developer.mozilla.org/en-US/docs/Web/javascript#reference"
target="_blank"
style="text-decoration: none !important"
>Javascript</a
>
</p>
<h2>💼 Jobs</h2>
<div>
<h3>
Ventra Health
<small style="font-weight: normal"><i> / May '23 - Present</i></small>
</h3>
<p>Maintaining and iterating on an internal web application</p>
</div>
<div>
<h3>
Randstad Technologies<small style="font-weight: normal"
><i> / May '22 - May '23</i></small
>
</h3>
<p>Built Web Applications for external clients</p>
</div>
<div>
<h3>
Damiano Global Corporation<small style="font-weight: normal"
><i> / July '20 - Nov. '21</i></small
>
</h3>
<p>Built Web Applications for external clients</p>
</div>
<div>
<h3>
Makers Ladder LLC<small style="font-weight: normal"
><i> / Dec. '19 - Apr. '22</i></small
>
</h3>
<p>Did some thangs</p>
</div>
<h2>🚧 Projects</h2>
<p>
<a
href="https://github.com/tristonarmstrong/SolarBatteryMonitorApi"
target="_blank"
>Solar Battery Monitor API</a
>
|
<a
href="https://github.com/tristonarmstrong/armstrong-editor"
target="_blank"
>Armstrong Editor</a
>
|
<a
href="https://github.com/tristonarmstrong/web-window-manager"
target="_blank"
>Web Window Manager</a
>
|
<a
href="https://github.com/tristonarmstrong/component-test-helper"
target="_blank"
>Component Test Helper</a
>
|
<a href="https://github.com/tristonarmstrong/hive-dapp" target="_blank"
>Hive DAPP</a
>
|
<a
href="https://github.com/tristonarmstrong/KivyTwistedInputCapture"
target="_blank"
>Kivy Twisted Input Capture</a
>
|
<a
href="https://github.com/tristonarmstrong/PlantMonitorNodeMCU"
target="_blank"
>Plant Monitor Node MCU</a
>
|
<a
href="https://github.com/tristonarmstrong/oppo_bdp_103_CLI"
target="_blank"
>Oppo BDP 103 CLI</a
>
|
<a
href="https://github.com/tristonarmstrong/sony_bravia_pro_display_mock_server"
target="_blank"
>Sony Bravia Pro Server</a
>
|
<a href="https://github.com/tristonarmstrong/chat.io" target="_blank"
>Chat IO</a
>
|
<a href="https://github.com/tristonarmstrong/zipapp" target="_blank"
>Zip Code Distance App</a
>
</p>
<h2>🧰 Tools</h2>
<p>
<a href="" target="_blank">CSS-Tricks</a>
|
<a href="" target="_blank">Indie Hackers</a>
|
<a href="" target="_blank">W3Schools</a>
|
<a href="https://simpleicons.org" target="_blank">Simple Icons</a>
|
<a href="https://heroicons.com" target="_blank">Hero Icons</a>
|
<a href="https://nerdcave.com/tailwind-cheat-sheet" target="_blank"
>Tailwind Cheatsheet</a
>
|
<a href="https://tw-elements.com" target="_blank">Tailwind Elements</a>
|
<a href="https://tailwindcomponents.com" target="_blank"
>Tailwind Components</a
>
</p>
<h2>🎨 NoCss</h2>
<p>
<a href="https://watercss.kognise.dev" target="_blank">Water CSS</a>
|
<a href="https://andybrewer.github.io/mvp/" target="_blank">MPV CSS</a>
|
<a href="https://hakanalpay.com/bahunya/" target="_blank">Bahunya</a>
|
<a href="https://mblode.github.io/marx/" target="_blank">Marx</a>
|
<a href="https://oxal.org/projects/sakura/" target="_blank">Sakura</a>
|
<a href="https://yegor256.github.io/tacit/" target="_blank">Tacit</a>
|
<a href="https://newcss.net" target="_blank">New CSS</a>
|
<a href="https://marcop135.github.io/bullframe.css/" target="_blank"
>Bullframe CSS</a
>
|
<a href="https://markdowncss.github.io/modest/" target="_blank"
>Markdown CSS (modest)</a
>
</p>
<footer>
<a href="https://github.com/tristonarmstrong">Github</a>
|
<a href="https://www.linkedin.com/in/triston95strong/">LinkedIn</a>
|
<a href="https://gitlab.com/Tarmstrong95">GitLab</a>
|
<a href="https://twitter.com/triston_armstr">Twitter</a>
|
<a href="https://fosstodon.org/@TristonArmstrong">Fosstodon</a>
<p><small>©2023-2024 Triston Armstrong. All rights reserved.</small></p>
</footer>
{% endblock %}

17
templates/styles.css Normal file
View File

@ -0,0 +1,17 @@
:root {
--background-body: #0d1117 !important;
}
#content {
display: flex;
flex-direction: column;
align-items: center;
gap: 1rem;
}
table,
th,
td {
border: 1px solid black;
padding: 0.25rem;
}

11
templates/tuts.html Normal file
View File

@ -0,0 +1,11 @@
{% extends "base.html" %} {% block title %}Micro Tuts{% endblock %} {% block
content %}
<nav>
<small>
<a href="/"><~ back</a>
</small>
</nav>
<h1>Notes</h1>
<p>Here all my Micro Tuts go</p>
{% endblock content%}