Compare commits
6 Commits
e63edda9ca
...
48d59b6f90
| Author | SHA1 | Date | |
|---|---|---|---|
| 48d59b6f90 | |||
| f01659ea50 | |||
| 2500fdc79b | |||
| 99ebee7f35 | |||
| 3e2987ad0c | |||
| bcd50d3a17 |
@@ -7,5 +7,6 @@ edition = "2024"
|
|||||||
actix-web = {version = "4.11.0"}
|
actix-web = {version = "4.11.0"}
|
||||||
serde = "1.0.228"
|
serde = "1.0.228"
|
||||||
serde_json = "1.0.145"
|
serde_json = "1.0.145"
|
||||||
|
toml = "0.9.7"
|
||||||
sqlx = {version = "0.8.6", features = ["postgres"]}
|
sqlx = {version = "0.8.6", features = ["postgres"]}
|
||||||
futures-util = "0.3.31"
|
futures-util = "0.3.31"
|
||||||
15
aindustries-be.service
Normal file
15
aindustries-be.service
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=aindustries.be website
|
||||||
|
After=network.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=simple
|
||||||
|
Restart=always
|
||||||
|
RestartSec=1
|
||||||
|
# Change with proper user to run the service
|
||||||
|
User=web
|
||||||
|
# Change with the installation location of the executable
|
||||||
|
ExecStart=/usr/share/bin/aindustries-be
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
@@ -11,6 +11,7 @@
|
|||||||
--clr-primary-a30: #c98bcc;
|
--clr-primary-a30: #c98bcc;
|
||||||
--clr-primary-a40: #d29ed4;
|
--clr-primary-a40: #d29ed4;
|
||||||
--clr-primary-a50: #dcb1dd;
|
--clr-primary-a50: #dcb1dd;
|
||||||
|
--clr-primary-a60: #e1d7e1;
|
||||||
|
|
||||||
/** Theme surface colors */
|
/** Theme surface colors */
|
||||||
--clr-surface-a0: #121212;
|
--clr-surface-a0: #121212;
|
||||||
|
|||||||
@@ -8,13 +8,13 @@
|
|||||||
h1 {
|
h1 {
|
||||||
font-size: 68px;
|
font-size: 68px;
|
||||||
font-family: 'Indie Flower', cursive;
|
font-family: 'Indie Flower', cursive;
|
||||||
color: var(--clr-primary-a50);
|
color: var(--clr-primary-a60);
|
||||||
}
|
}
|
||||||
|
|
||||||
h2 {
|
h2 {
|
||||||
font-size: 42px;
|
font-size: 42px;
|
||||||
font-family: 'Indie Flower', cursive;
|
font-family: 'Indie Flower', cursive;
|
||||||
color: var(--clr-primary-a50);
|
color: var(--clr-primary-a60);
|
||||||
}
|
}
|
||||||
|
|
||||||
@media screen and (width<700px) {
|
@media screen and (width<700px) {
|
||||||
|
|||||||
21
assets/css/project.css
Normal file
21
assets/css/project.css
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
h1 {
|
||||||
|
font-family: 'Indie Flower', cursive;
|
||||||
|
font-size: 75px;
|
||||||
|
text-align: center;
|
||||||
|
color: var(--clr-primary-a60);
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
font-family: Lexend, serif;
|
||||||
|
color: var(--clr-primary-a60);
|
||||||
|
width: fit-content;
|
||||||
|
margin: 8px auto 8px auto;
|
||||||
|
font-size: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (width <= 750px) {
|
||||||
|
p {
|
||||||
|
max-width: 90vw;
|
||||||
|
font-size: 20px;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,14 +1,66 @@
|
|||||||
.project {
|
.project {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
background-color: rgba(50,50,75,0.8);
|
background-image: radial-gradient(circle at top left, var(--clr-primary-a10), var(--clr-primary-a50));
|
||||||
border-radius: 12px;
|
border-radius: 12px;
|
||||||
|
max-width: 40vw;
|
||||||
|
height: 250px;
|
||||||
|
margin: 8px auto 8px auto;
|
||||||
|
padding: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.project-info {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-content: center;
|
||||||
|
margin: 0 4px 4px 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.project > h1 {
|
.project > h1 {
|
||||||
|
flex-grow: 1;
|
||||||
color: white;
|
color: white;
|
||||||
|
font-family: 'Indie Flower', cursive;
|
||||||
|
width: fit-content;
|
||||||
|
font-size: 40px;
|
||||||
|
margin: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.project-desc {
|
.project-desc {
|
||||||
color: white;
|
color: white;
|
||||||
|
font-family: Lexend, serif;
|
||||||
|
width: fit-content;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.project-view {
|
||||||
|
align-self: flex-end;
|
||||||
|
width: fit-content;
|
||||||
|
font-family: Lexend, serif;
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
font-family: 'Indie Flower', cursive;
|
||||||
|
font-size: 60px;
|
||||||
|
text-align: center;
|
||||||
|
color: var(--clr-primary-a60);
|
||||||
|
}
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
font-family: 'Indie Flower', cursive;
|
||||||
|
font-size: 40px;
|
||||||
|
text-align: center;
|
||||||
|
color: var(--clr-primary-a60);
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (width <= 750px) {
|
||||||
|
.project {
|
||||||
|
max-width: 80vw;
|
||||||
|
height: 150px;
|
||||||
|
}
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
font-size: 24px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
5
config.toml
Normal file
5
config.toml
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
[application]
|
||||||
|
# Change with actual location of assets
|
||||||
|
assets=""
|
||||||
|
# Set bind address
|
||||||
|
bind="127.0.0.1:8080"
|
||||||
@@ -12,8 +12,11 @@ impl Render for h1 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl h1 {
|
impl h1 {
|
||||||
pub(crate) fn new(text: String) -> Self {
|
pub(crate) fn new<T>(text: T) -> Self
|
||||||
Self { text }
|
where
|
||||||
|
T: Into<String>,
|
||||||
|
{
|
||||||
|
Self { text: text.into() }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -29,15 +32,18 @@ impl Render for h2 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl h2 {
|
impl h2 {
|
||||||
pub(crate) fn new(text: String) -> Self {
|
pub(crate) fn new<T>(text: T) -> Self
|
||||||
Self { text }
|
where
|
||||||
|
T: Into<String>,
|
||||||
|
{
|
||||||
|
Self { text: text.into() }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(non_camel_case_types)]
|
#[allow(non_camel_case_types)]
|
||||||
pub(crate) struct link {
|
pub(crate) struct link {
|
||||||
rel: &'static str,
|
rel: String,
|
||||||
href: &'static str,
|
href: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Render for link {
|
impl Render for link {
|
||||||
@@ -47,15 +53,22 @@ impl Render for link {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl link {
|
impl link {
|
||||||
pub(crate) fn new(rel: &'static str, href: &'static str) -> Self {
|
pub(crate) fn new<T, U>(rel: T, href: U) -> Self
|
||||||
Self { rel, href }
|
where
|
||||||
|
T: Into<String>,
|
||||||
|
U: Into<String>,
|
||||||
|
{
|
||||||
|
Self {
|
||||||
|
rel: rel.into(),
|
||||||
|
href: href.into(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(non_camel_case_types)]
|
#[allow(non_camel_case_types)]
|
||||||
pub(crate) struct div {
|
pub(crate) struct div {
|
||||||
id: &'static str,
|
id: String,
|
||||||
classes: Vec<&'static str>,
|
classes: Vec<String>,
|
||||||
content: Vec<Box<dyn Render>>,
|
content: Vec<Box<dyn Render>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -72,10 +85,14 @@ impl Render for div {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl div {
|
impl div {
|
||||||
pub(crate) fn new(id: &'static str, classes: Vec<&'static str>) -> Self {
|
pub(crate) fn new<T, U>(id: T, classes: Vec<U>) -> Self
|
||||||
|
where
|
||||||
|
T: Into<String>,
|
||||||
|
U: Into<String> + Clone,
|
||||||
|
{
|
||||||
Self {
|
Self {
|
||||||
id,
|
id: id.into(),
|
||||||
classes,
|
classes: classes.iter().map(|x| x.clone().into()).collect(),
|
||||||
content: vec![],
|
content: vec![],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -87,65 +104,99 @@ impl div {
|
|||||||
|
|
||||||
#[allow(non_camel_case_types)]
|
#[allow(non_camel_case_types)]
|
||||||
pub(crate) struct p {
|
pub(crate) struct p {
|
||||||
id: &'static str,
|
id: String,
|
||||||
classes: Vec<&'static str>,
|
classes: Vec<String>,
|
||||||
text: String
|
text: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Render for p {
|
impl Render for p {
|
||||||
fn render(&self) -> String {
|
fn render(&self) -> String {
|
||||||
let classes = self.classes.join(" ");
|
let classes = self.classes.join(" ");
|
||||||
format!("<p id=\"{}\" class=\"{}\">{}</p>", self.id, classes, self.text)
|
format!(
|
||||||
|
"<p id=\"{}\" class=\"{}\">{}</p>",
|
||||||
|
self.id, classes, self.text
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl p {
|
impl p {
|
||||||
pub(crate) fn new(id: &'static str, classes: Vec<&'static str>, text: String) -> Self {
|
pub(crate) fn new<T, U, V>(id: T, classes: Vec<U>, text: V) -> Self
|
||||||
|
where
|
||||||
|
T: Into<String>,
|
||||||
|
U: Into<String> + Clone,
|
||||||
|
V: Into<String>,
|
||||||
|
{
|
||||||
Self {
|
Self {
|
||||||
id,
|
id: id.into(),
|
||||||
classes,
|
classes: classes.iter().map(|x| x.clone().into()).collect(),
|
||||||
text
|
text: text.into(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(non_camel_case_types)]
|
#[allow(non_camel_case_types)]
|
||||||
pub(crate) struct img {
|
pub(crate) struct img {
|
||||||
id: &'static str,
|
id: String,
|
||||||
classes: Vec<&'static str>,
|
classes: Vec<String>,
|
||||||
src: &'static str,
|
src: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Render for img {
|
impl Render for img {
|
||||||
fn render(&self) -> String {
|
fn render(&self) -> String {
|
||||||
let classes = self.classes.join(" ");
|
let classes = self.classes.join(" ");
|
||||||
format!("<img id=\"{}\" class=\"{}\" src=\"{}\">", self.id, classes, self.src)
|
format!(
|
||||||
|
"<img id=\"{}\" class=\"{}\" src=\"{}\">",
|
||||||
|
self.id, classes, self.src
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl img {
|
impl img {
|
||||||
pub(crate) fn new(id: &'static str, classes: Vec<&'static str>, src: &'static str) -> Self {
|
pub(crate) fn new<T, U, V>(id: T, classes: Vec<U>, src: V) -> Self
|
||||||
Self { id, classes, src }
|
where
|
||||||
|
T: Into<String>,
|
||||||
|
U: Into<String> + Clone,
|
||||||
|
V: Into<String>,
|
||||||
|
{
|
||||||
|
Self {
|
||||||
|
id: id.into(),
|
||||||
|
classes: classes.iter().map(|x| x.clone().into()).collect(),
|
||||||
|
src: src.into(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(non_camel_case_types)]
|
#[allow(non_camel_case_types)]
|
||||||
pub(crate) struct a {
|
pub(crate) struct a {
|
||||||
id: &'static str,
|
id: String,
|
||||||
classes: Vec<&'static str>,
|
classes: Vec<String>,
|
||||||
href: &'static str,
|
href: String,
|
||||||
text: String,
|
text: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Render for a {
|
impl Render for a {
|
||||||
fn render(&self) -> String {
|
fn render(&self) -> String {
|
||||||
let classes = self.classes.join(" ");
|
let classes = self.classes.join(" ");
|
||||||
format!("<a id=\"{}\" class=\"{}\" href=\"{}\">{}</a>", self.id, classes, self.href, self.text)
|
format!(
|
||||||
|
"<a id=\"{}\" class=\"{}\" href=\"{}\">{}</a>",
|
||||||
|
self.id, classes, self.href, self.text
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl a {
|
impl a {
|
||||||
pub(crate) fn new(id: &'static str, classes: Vec<&'static str>, href: &'static str, text: String) -> Self {
|
pub(crate) fn new<T, U, V, W>(id: T, classes: Vec<U>, href: V, text: W) -> Self
|
||||||
Self { id, classes, href, text }
|
where
|
||||||
|
T: Into<String>,
|
||||||
|
U: Into<String> + Clone,
|
||||||
|
V: Into<String>,
|
||||||
|
W: Into<String>,
|
||||||
|
{
|
||||||
|
Self {
|
||||||
|
id: id.into(),
|
||||||
|
classes: classes.iter().map(|x| x.clone().into()).collect(),
|
||||||
|
href: href.into(),
|
||||||
|
text: text.into(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ pub(crate) trait Render {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct Page {
|
pub(crate) struct Page {
|
||||||
title: &'static str,
|
title: String,
|
||||||
head: Vec<Box<dyn Render>>,
|
head: Vec<Box<dyn Render>>,
|
||||||
body: Vec<Box<dyn Render>>,
|
body: Vec<Box<dyn Render>>,
|
||||||
}
|
}
|
||||||
@@ -45,9 +45,12 @@ impl Render for Page {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Page {
|
impl Page {
|
||||||
pub(crate) fn new(title: &'static str) -> Self {
|
pub(crate) fn new<T>(title: T) -> Self
|
||||||
|
where
|
||||||
|
T: Into<String>,
|
||||||
|
{
|
||||||
Page {
|
Page {
|
||||||
title,
|
title: title.into(),
|
||||||
head: vec![],
|
head: vec![],
|
||||||
body: vec![],
|
body: vec![],
|
||||||
}
|
}
|
||||||
|
|||||||
56
src/main.rs
56
src/main.rs
@@ -1,25 +1,57 @@
|
|||||||
mod html;
|
mod html;
|
||||||
mod pages;
|
|
||||||
mod middleware;
|
mod middleware;
|
||||||
|
mod pages;
|
||||||
|
|
||||||
use actix_web::{web, App, HttpServer};
|
use actix_web::{App, HttpServer, web};
|
||||||
|
use serde::Deserialize;
|
||||||
|
use std::fs::File;
|
||||||
|
use std::io::Read;
|
||||||
|
use toml::from_slice;
|
||||||
|
|
||||||
use pages::{files::file, index, projects::{projects, project}};
|
|
||||||
use middleware::MimeType;
|
use middleware::MimeType;
|
||||||
|
use pages::{
|
||||||
|
files::file,
|
||||||
|
index,
|
||||||
|
projects::{project, projects},
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
struct Config {
|
||||||
|
server: ServerConfig,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
struct ServerConfig {
|
||||||
|
assets: String,
|
||||||
|
bind: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
struct AppState {
|
||||||
|
assets: String,
|
||||||
|
}
|
||||||
|
|
||||||
#[actix_web::main]
|
#[actix_web::main]
|
||||||
async fn main() {
|
async fn main() {
|
||||||
let bind_address = "0.0.0.0:8080";
|
let mut config_file =
|
||||||
if let Ok(server) =
|
File::open("/etc/aindustries-be/config.toml").expect("Could not open config file");
|
||||||
HttpServer::new(|| App::new()
|
let mut buf = vec![];
|
||||||
.service(file)
|
config_file
|
||||||
.service(web::scope("")
|
.read_to_end(&mut buf)
|
||||||
.wrap(MimeType::new("text/html".to_string()))
|
.expect("Could not read config file");
|
||||||
|
let config: Config = from_slice(&buf).expect("Could not parse config");
|
||||||
|
let bind_address = config.server.bind;
|
||||||
|
let assets = config.server.assets;
|
||||||
|
let data = web::Data::new(AppState { assets });
|
||||||
|
if let Ok(server) = HttpServer::new(move || {
|
||||||
|
App::new().app_data(data.clone()).service(file).service(
|
||||||
|
web::scope("")
|
||||||
|
.wrap(MimeType::new("text/html"))
|
||||||
.service(index)
|
.service(index)
|
||||||
.service(projects)
|
.service(projects)
|
||||||
.service(project)
|
.service(project),
|
||||||
)
|
)
|
||||||
).bind(bind_address)
|
})
|
||||||
|
.bind(bind_address)
|
||||||
{
|
{
|
||||||
match server.run().await {
|
match server.run().await {
|
||||||
Ok(_) => {}
|
Ok(_) => {}
|
||||||
|
|||||||
@@ -1,24 +1,27 @@
|
|||||||
use std::future::{ready, Ready};
|
|
||||||
use actix_web::dev::{forward_ready, Service, ServiceRequest, ServiceResponse, Transform};
|
|
||||||
use actix_web::Error;
|
use actix_web::Error;
|
||||||
use actix_web::http::header::{HeaderValue, CONTENT_TYPE};
|
use actix_web::dev::{Service, ServiceRequest, ServiceResponse, Transform, forward_ready};
|
||||||
|
use actix_web::http::header::{CONTENT_TYPE, HeaderValue};
|
||||||
use futures_util::future::LocalBoxFuture;
|
use futures_util::future::LocalBoxFuture;
|
||||||
|
use std::future::{Ready, ready};
|
||||||
|
|
||||||
pub(crate) struct MimeType {
|
pub(crate) struct MimeType {
|
||||||
mime_type: String,
|
mime_type: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MimeType {
|
impl MimeType {
|
||||||
pub(crate) fn new(mime_type: String) -> Self {
|
pub(crate) fn new<T>(mime_type: T) -> Self
|
||||||
|
where
|
||||||
|
T: Into<String>,
|
||||||
|
{
|
||||||
Self {
|
Self {
|
||||||
mime_type
|
mime_type: mime_type.into(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S,B> Transform<S, ServiceRequest> for MimeType
|
impl<S, B> Transform<S, ServiceRequest> for MimeType
|
||||||
where
|
where
|
||||||
S: Service<ServiceRequest, Response=ServiceResponse<B>, Error=Error>,
|
S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
|
||||||
S::Future: 'static,
|
S::Future: 'static,
|
||||||
B: 'static,
|
B: 'static,
|
||||||
{
|
{
|
||||||
@@ -30,7 +33,7 @@ where
|
|||||||
|
|
||||||
fn new_transform(&self, service: S) -> Self::Future {
|
fn new_transform(&self, service: S) -> Self::Future {
|
||||||
let mime_type = self.mime_type.clone();
|
let mime_type = self.mime_type.clone();
|
||||||
ready(Ok(MimeTypeMiddleware{service, mime_type}))
|
ready(Ok(MimeTypeMiddleware { service, mime_type }))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -39,7 +42,7 @@ pub(crate) struct MimeTypeMiddleware<S> {
|
|||||||
mime_type: String,
|
mime_type: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S,B> Service<ServiceRequest> for MimeTypeMiddleware<S>
|
impl<S, B> Service<ServiceRequest> for MimeTypeMiddleware<S>
|
||||||
where
|
where
|
||||||
S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
|
S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
|
||||||
S::Future: 'static,
|
S::Future: 'static,
|
||||||
@@ -53,11 +56,11 @@ where
|
|||||||
|
|
||||||
fn call(&self, req: ServiceRequest) -> Self::Future {
|
fn call(&self, req: ServiceRequest) -> Self::Future {
|
||||||
let fut = self.service.call(req);
|
let fut = self.service.call(req);
|
||||||
let val = HeaderValue::from_str(self.mime_type.as_str()).unwrap_or_else(|_| HeaderValue::from_static("text/html"));
|
let val = HeaderValue::from_str(self.mime_type.as_str()).expect("Invalid MimeType");
|
||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
let mut res = fut.await?;
|
let mut res = fut.await?;
|
||||||
res.headers_mut().append(CONTENT_TYPE, val);
|
res.headers_mut().append(CONTENT_TYPE, val);
|
||||||
Ok(res)
|
Ok(res)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
|
use crate::AppState;
|
||||||
use actix_web::web::Path;
|
use actix_web::web::Path;
|
||||||
use actix_web::{HttpResponse, Responder, get};
|
use actix_web::{HttpResponse, Responder, get, web};
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::Read;
|
use std::io::Read;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
#[get("/static/{file_type}/{file_name}")]
|
#[get("/static/{file_type}/{file_name}")]
|
||||||
async fn file(file: Path<(String, String)>) -> impl Responder {
|
async fn file(file: Path<(String, String)>, data: web::Data<AppState>) -> impl Responder {
|
||||||
//TODO use assets dir
|
let mut path = PathBuf::from(&data.assets);
|
||||||
let mut path = PathBuf::from("assets");
|
|
||||||
path.push(&file.0.replace("/", ""));
|
path.push(&file.0.replace("/", ""));
|
||||||
path.push(&file.1.replace("/", ""));
|
path.push(&file.1.replace("/", ""));
|
||||||
let mut file = File::open(path).unwrap();
|
let mut file = File::open(path).unwrap();
|
||||||
|
|||||||
@@ -6,33 +6,38 @@ use crate::html::{Page, Render};
|
|||||||
use actix_web::{Responder, get};
|
use actix_web::{Responder, get};
|
||||||
|
|
||||||
pub(crate) struct BasePage {
|
pub(crate) struct BasePage {
|
||||||
page: Page
|
page: Page,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BasePage {
|
impl BasePage {
|
||||||
pub(crate) fn new(title: &'static str) -> Self {
|
pub(crate) fn new<T>(title: T) -> Self
|
||||||
|
where
|
||||||
|
T: Into<String>,
|
||||||
|
{
|
||||||
let mut page = Page::new(title);
|
let mut page = Page::new(title);
|
||||||
// header
|
// header
|
||||||
let mut header = div::new("header", vec!["header"]);
|
let mut header = div::new("header", vec!["header"]);
|
||||||
let name = p::new("name", vec!["name"], "AINDUSTRIES".to_string());
|
let name = p::new("name", vec!["name"], "AINDUSTRIES");
|
||||||
let mut buttons = div::new("buttons", vec!["nav-buttons"]);
|
let mut buttons = div::new("buttons", vec!["nav-buttons"]);
|
||||||
let home = a::new("home", vec!["nav-button"], "/", "Home".to_string());
|
let home = a::new("home", vec!["nav-button"], "/", "Home");
|
||||||
let projects = a::new("projects", vec!["nav-button"], "/projects", "Projects".to_string());
|
let projects = a::new("projects", vec!["nav-button"], "/projects", "Projects");
|
||||||
buttons.append_element(home);
|
buttons.append_element(home);
|
||||||
buttons.append_element(projects);
|
buttons.append_element(projects);
|
||||||
header.append_element(name);
|
header.append_element(name);
|
||||||
header.append_element(buttons);
|
header.append_element(buttons);
|
||||||
// background
|
// background
|
||||||
let image = img::new("background", vec!["background"], "static/img/background.png");
|
let image = img::new(
|
||||||
|
"background",
|
||||||
|
vec!["background"],
|
||||||
|
"/static/img/background.png",
|
||||||
|
);
|
||||||
// css
|
// css
|
||||||
let base = link::new("stylesheet", "static/css/base.css");
|
let base = link::new("stylesheet", "/static/css/base.css");
|
||||||
// add elements to the page in order
|
// add elements to the page in order
|
||||||
page.append_element_to_head(base);
|
page.append_element_to_head(base);
|
||||||
page.append_element_to_body(image);
|
page.append_element_to_body(image);
|
||||||
page.append_element_to_body(header);
|
page.append_element_to_body(header);
|
||||||
Self {
|
Self { page }
|
||||||
page
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn append_element_to_head(&mut self, element: impl Render + 'static) {
|
pub(crate) fn append_element_to_head(&mut self, element: impl Render + 'static) {
|
||||||
@@ -54,10 +59,12 @@ async fn index() -> impl Responder {
|
|||||||
let mut page = BasePage::new("AINDUSTRIES");
|
let mut page = BasePage::new("AINDUSTRIES");
|
||||||
// introduction
|
// introduction
|
||||||
let mut intro = div::new("intro", vec!["intro"]);
|
let mut intro = div::new("intro", vec!["intro"]);
|
||||||
let hi = h1::new("Hello and welcome!".to_string());
|
let hi = h1::new("Hello and welcome!");
|
||||||
let detail = h2::new("This here is a small website to show the passion I have for computers.<br>\
|
let detail = h2::new(
|
||||||
|
"This here is a small website to show the passion I have for computers.<br>\
|
||||||
I have always had a good time creating and discovering new things.<br>\
|
I have always had a good time creating and discovering new things.<br>\
|
||||||
Your may discover some of my projects here on this showcase.".to_string());
|
Your may discover some of my projects here on this showcase.",
|
||||||
|
);
|
||||||
intro.append_element(hi);
|
intro.append_element(hi);
|
||||||
intro.append_element(detail);
|
intro.append_element(detail);
|
||||||
// css
|
// css
|
||||||
|
|||||||
@@ -1,25 +1,64 @@
|
|||||||
use actix_web::{get, Responder};
|
|
||||||
use crate::html::elements::{div, h1, p, a, link};
|
|
||||||
use crate::html::{Render};
|
|
||||||
use super::BasePage;
|
use super::BasePage;
|
||||||
|
use crate::html::Render;
|
||||||
|
use crate::html::elements::{a, div, h1, h2, link, p};
|
||||||
|
use actix_web::{Responder, get, web};
|
||||||
|
|
||||||
#[get("/projects")]
|
#[get("/projects")]
|
||||||
async fn projects() -> impl Responder {
|
async fn projects() -> impl Responder {
|
||||||
let mut page = BasePage::new("Projects");
|
let mut page = BasePage::new("Projects");
|
||||||
|
let title = h1::new("My projects");
|
||||||
|
let desc = h2::new(
|
||||||
|
"Here you will find all my projects which deserve to be shown<br>\
|
||||||
|
(I've done a lot of small projects but they are not worth it.)",
|
||||||
|
);
|
||||||
let mut website = div::new("project-website", vec!["project"]);
|
let mut website = div::new("project-website", vec!["project"]);
|
||||||
let title = h1::new("Website".to_string());
|
let website_title = h1::new("Website");
|
||||||
let desc = p::new("website-desc", vec!["project-desc"], "This project is the website you are currently on.".to_string());
|
let mut info = div::new("project-website-info", vec!["project-info"]);
|
||||||
let view = a::new("website-view", vec!["project-view"], "website" , "View More".to_string());
|
let website_desc = p::new(
|
||||||
website.append_element(title);
|
"website-desc",
|
||||||
website.append_element(desc);
|
vec!["project-desc"],
|
||||||
website.append_element(view);
|
"This project is the website you currently are on.",
|
||||||
|
);
|
||||||
|
let view = a::new(
|
||||||
|
"website-view",
|
||||||
|
vec!["project-view"],
|
||||||
|
"/projects/website",
|
||||||
|
"Learn More",
|
||||||
|
);
|
||||||
|
info.append_element(website_desc);
|
||||||
|
info.append_element(view);
|
||||||
|
website.append_element(website_title);
|
||||||
|
website.append_element(info);
|
||||||
let css = link::new("stylesheet", "/static/css/projects.css");
|
let css = link::new("stylesheet", "/static/css/projects.css");
|
||||||
page.append_element_to_head(css);
|
page.append_element_to_head(css);
|
||||||
|
page.append_element_to_body(title);
|
||||||
|
page.append_element_to_body(desc);
|
||||||
page.append_element_to_body(website);
|
page.append_element_to_body(website);
|
||||||
page.render()
|
page.render()
|
||||||
}
|
}
|
||||||
#[get("/projects/{project}")]
|
#[get("/projects/{project}")]
|
||||||
async fn project() -> impl Responder {
|
async fn project(project: web::Path<String>) -> impl Responder {
|
||||||
let page = BasePage::new("Project");
|
let project = project.into_inner();
|
||||||
|
let mut page = BasePage::new(format!("Project-{}", project));
|
||||||
|
match project.as_str() {
|
||||||
|
"website" => {
|
||||||
|
let title = h1::new("Website");
|
||||||
|
let desc = p::new(
|
||||||
|
"description",
|
||||||
|
vec!["description"],
|
||||||
|
"This project, the website you are on, \
|
||||||
|
is made in Rust such that all the pages are generated by code.<br>\
|
||||||
|
That is that each html element is represented by a struct which implements the Render trait (as in render the element to html).<br>\
|
||||||
|
As it is right now the system is not that impressive but I believe it can do amazing things in the futur.<br>\
|
||||||
|
<br>\
|
||||||
|
Wish to see more? Check out the gitea repository: ",
|
||||||
|
);
|
||||||
|
page.append_element_to_body(title);
|
||||||
|
page.append_element_to_body(desc);
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
let css = link::new("stylesheet", "/static/css/project.css");
|
||||||
|
page.append_element_to_head(css);
|
||||||
page.render()
|
page.render()
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user