feat: doc pages, finished refactor of ingress

This commit is contained in:
Per Stark
2025-01-05 23:20:34 +01:00
parent 5bd44f745a
commit 669875094b
18 changed files with 232 additions and 82 deletions

File diff suppressed because one or more lines are too long

52
package-lock.json generated
View File

@@ -5,6 +5,7 @@
"packages": {
"": {
"devDependencies": {
"@tailwindcss/typography": "^0.5.15",
"autoprefixer": "^10.4.20",
"cssnano": "^7.0.6",
"daisyui": "^4.12.23",
@@ -160,6 +161,36 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/@tailwindcss/typography": {
"version": "0.5.15",
"resolved": "https://registry.npmjs.org/@tailwindcss/typography/-/typography-0.5.15.tgz",
"integrity": "sha512-AqhlCXl+8grUz8uqExv5OTtgpjuVIwFTSXTrh8y9/pw6q2ek7fJ+Y8ZEVw7EB2DCcuCOtEjf9w3+J3rzts01uA==",
"dev": true,
"license": "MIT",
"dependencies": {
"lodash.castarray": "^4.4.0",
"lodash.isplainobject": "^4.0.6",
"lodash.merge": "^4.6.2",
"postcss-selector-parser": "6.0.10"
},
"peerDependencies": {
"tailwindcss": ">=3.0.0 || insiders || >=4.0.0-alpha.20"
}
},
"node_modules/@tailwindcss/typography/node_modules/postcss-selector-parser": {
"version": "6.0.10",
"resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.10.tgz",
"integrity": "sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==",
"dev": true,
"license": "MIT",
"dependencies": {
"cssesc": "^3.0.0",
"util-deprecate": "^1.0.2"
},
"engines": {
"node": ">=4"
}
},
"node_modules/@trysound/sax": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/@trysound/sax/-/sax-0.2.0.tgz",
@@ -2275,6 +2306,20 @@
"node": ">=4"
}
},
"node_modules/lodash.castarray": {
"version": "4.4.0",
"resolved": "https://registry.npmjs.org/lodash.castarray/-/lodash.castarray-4.4.0.tgz",
"integrity": "sha512-aVx8ztPv7/2ULbArGJ2Y42bG1mEQ5mGjpdvrbJcJFU3TbYybe+QlLS4pst9zV52ymy2in1KpFPiZnAOATxD4+Q==",
"dev": true,
"license": "MIT"
},
"node_modules/lodash.isplainobject": {
"version": "4.0.6",
"resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz",
"integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==",
"dev": true,
"license": "MIT"
},
"node_modules/lodash.memoize": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz",
@@ -2282,6 +2327,13 @@
"dev": true,
"license": "MIT"
},
"node_modules/lodash.merge": {
"version": "4.6.2",
"resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
"integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==",
"dev": true,
"license": "MIT"
},
"node_modules/lodash.uniq": {
"version": "4.5.0",
"resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz",

View File

@@ -7,6 +7,7 @@
"dev": "npm-run-all --parallel watch:css watch:tailwind"
},
"devDependencies": {
"@tailwindcss/typography": "^0.5.15",
"autoprefixer": "^10.4.20",
"cssnano": "^7.0.6",
"daisyui": "^4.12.23",

View File

@@ -24,6 +24,7 @@ use zettle_db::{
},
html::{
account::{delete_account, set_api_key, show_account_page},
documentation::index::show_documentation_index,
gdpr::{accept_gdpr, deny_gdpr},
index::index_handler,
ingress::{process_ingress_form, show_ingress_form},
@@ -164,6 +165,7 @@ fn html_routes(
"/signup",
get(show_signup_form).post(process_signup_and_show_verification),
)
.route("/documentation", get(show_documentation_index))
.nest_service("/assets", ServeDir::new("assets/"))
.layer(
AuthSessionLayer::<User, String, SessionSurrealPool<Any>, Surreal<Any>>::new(Some(

View File

@@ -1,11 +1,5 @@
use super::ingress_object::IngressObject;
use crate::{
error::AppError,
storage::{
db::{get_item, SurrealDbClient},
types::file_info::FileInfo,
},
};
use crate::{error::AppError, storage::types::file_info::FileInfo};
use serde::{Deserialize, Serialize};
use tracing::info;
use url::Url;

View File

@@ -1,13 +1,10 @@
use crate::{
error::{ApiError, AppError},
ingress::types::{
ingress_input::{create_ingress_objects, IngressInput},
ingress_object,
},
ingress::types::ingress_input::{create_ingress_objects, IngressInput},
server::AppState,
storage::types::{file_info::FileInfo, user::User},
};
use axum::{extract::State, http::StatusCode, response::IntoResponse, Extension, Json};
use axum::{extract::State, http::StatusCode, response::IntoResponse, Extension};
use axum_typed_multipart::{FieldData, TryFromMultipart, TypedMultipart};
use futures::{future::try_join_all, TryFutureExt};
use tempfile::NamedTempFile;
@@ -31,7 +28,7 @@ pub async fn ingress_data(
info!("Received input: {:?}", input);
let file_infos = try_join_all(input.files.into_iter().map(|file| {
FileInfo::new(file, &state.surreal_db_client, &user.id).map_err(|e| AppError::from(e))
FileInfo::new(file, &state.surreal_db_client, &user.id).map_err(AppError::from)
}))
.await?;

View File

@@ -0,0 +1,31 @@
use axum::{extract::State, response::IntoResponse};
use axum_session_auth::AuthSession;
use axum_session_surreal::SessionSurrealPool;
use surrealdb::{engine::any::Any, Surreal};
use crate::{
error::HtmlError,
page_data,
server::{routes::html::render_template, AppState},
storage::types::user::User,
};
page_data!(IndexData, "documentation/index.html", {
user: Option<User>
});
pub async fn show_documentation_index(
State(state): State<AppState>,
auth: AuthSession<User, String, SessionSurrealPool<Any>, Surreal<Any>>,
) -> Result<impl IntoResponse, HtmlError> {
let output = render_template(
IndexData::template_name(),
IndexData {
user: auth.current_user,
},
state.templates.clone(),
)
.map_err(|e| HtmlError::from_template_error(e, state.templates.clone()))?;
Ok(output.into_response())
}

View File

@@ -0,0 +1 @@
pub mod index;

View File

@@ -76,7 +76,7 @@ pub async fn process_ingress_form(
},
user.id.as_str(),
)
.map_err(|e| HtmlError::new(AppError::from(e), state.templates.clone()))?;
.map_err(|e| HtmlError::new(e, state.templates.clone()))?;
let futures: Vec<_> = ingress_objects
.into_iter()
@@ -86,9 +86,7 @@ pub async fn process_ingress_form(
try_join_all(futures)
.await
.map_err(AppError::from)
.map_err(|e| HtmlError::new(AppError::from(e), state.templates.clone()))?;
// Process the ingress (implement your logic here)
.map_err(|e| HtmlError::new(e, state.templates.clone()))?;
Ok(Html("SuccessBRO!").into_response())
// Ok((HxRedirect::from(Uri::from_static("/")), StatusCode::OK).into_response())
}

View File

@@ -4,6 +4,7 @@ use axum::response::Html;
use minijinja_autoreload::AutoReloader;
pub mod account;
pub mod documentation;
pub mod gdpr;
pub mod index;
pub mod ingress;

View File

@@ -4,10 +4,20 @@ module.exports = {
'./templates/**/*',
'!./templates/email/**/*'
],
theme: {
extend: {},
theme: {
extend: {
typography: {
DEFAULT: {
css: {
maxWidth: '90ch', // Override max-width for all prose instances
},
},
},
},
},
plugins: [require('daisyui')],
plugins: [
require("@tailwindcss/typography"),
require('daisyui')],
daisyui: {
themes: ["light", "dark"],
},

View File

@@ -5,45 +5,47 @@
opacity: 0.5;
}
</style>
<div class="max-w-lg w-full">
<h2 class="text-2xl font-bold text-center mb-8">Account Settings</h2>
<div class="form-control">
<label class="label">
<span class="label-text">Email</span>
</label>
<input type="email" name="email" value="{{ user.email }}" class="input input-bordered w-full" disabled />
<main class="flex-grow flex justify-center items-center">
<div class="max-w-lg w-full">
<h2 class="text-2xl font-bold text-center mb-8">Account Settings</h2>
<div class="form-control">
<label class="label">
<span class="label-text">Email</span>
</label>
<input type="email" name="email" value="{{ user.email }}" class="input input-bordered w-full" disabled />
</div>
<div class="form-control">
<label class="label">
<span class="label-text">API key</span>
</label>
{% block api_key_section %}
{% if user.api_key %}
<input type="text" name="api-key" value="{{ user.api_key }}" class="input input-bordered w-full" disabled />
{% else %}
<button hx-post="/set-api-key" class="btn btn-secondary w-full" hx-swap="outerHTML">
Create API-Key
</button>
{% endif %}
{% endblock %}
</div>
<div class="form-control mt-4">
<button hx-post="/verify-email" class="btn btn-secondary w-full">
Verify Email
</button>
</div>
<div class="form-control mt-4">
<button hx-get="/change-password" class="btn btn-primary w-full">
Change Password
</button>
</div>
<div class="form-control mt-4">
<button hx-delete="/delete-account"
hx-confirm="This action will permanently delete your account and all data associated. Are you sure you want to continue?"
class="btn btn-error w-full">
Delete Account
</button>
</div>
<div id="account-result" class="mt-4"></div>
</div>
<div class="form-control">
<label class="label">
<span class="label-text">API key</span>
</label>
{% block api_key_section %}
{% if user.api_key %}
<input type="text" name="api-key" value="{{ user.api_key }}" class="input input-bordered w-full" disabled />
{% else %}
<button hx-post="/set-api-key" class="btn btn-secondary w-full" hx-swap="outerHTML">
Create API-Key
</button>
{% endif %}
{% endblock %}
</div>
<div class="form-control mt-4">
<button hx-post="/verify-email" class="btn btn-secondary w-full">
Verify Email
</button>
</div>
<div class="form-control mt-4">
<button hx-get="/change-password" class="btn btn-primary w-full">
Change Password
</button>
</div>
<div class="form-control mt-4">
<button hx-delete="/delete-account"
hx-confirm="This action will permanently delete your account and all data associated. Are you sure you want to continue?"
class="btn btn-error w-full">
Delete Account
</button>
</div>
<div id="account-result" class="mt-4"></div>
</div>
</main>
{% endblock %}

View File

@@ -5,26 +5,27 @@
<div class="min-h-screen flex flex-col">
<!-- Navbar -->
<nav class="navbar bg-base-200">
<div class="flex-1">
<a class="btn text-2xl border-transparent btn-outline btn-primary" href="/" hx-boost="true">Minne</a>
</div>
<div>
<ul class="menu menu-horizontal px-1">
{% if user %}
<li><a hx-boost="true" class="" href="/account">Account</a></li>
<li><a hx-boost="true" href="/signout">Sign out</a></li>
{% else %}
<li><a hx-boost="true" class="" href="/signin">Login</a></li>
<li><a hx-boost="true" class="" href="/signup">Sign up</a></li>
{% endif %}
</ul>
<div class="container mx-auto">
<div class="flex-1">
<a class="btn text-2xl border-transparent btn-outline btn-primary" href="/" hx-boost="true">Minne</a>
</div>
<div>
<ul class="menu menu-horizontal px-1">
<li><a hx-boost="true" class="" href="/documentation">Docs</a></li>
{% if user %}
<li><a hx-boost="true" class="" href="/account">Account</a></li>
<li><a hx-boost="true" href="/signout">Sign out</a></li>
{% else %}
<li><a hx-boost="true" class="" href="/signin">Login</a></li>
<li><a hx-boost="true" class="" href="/signup">Sign up</a></li>
{% endif %}
</ul>
</div>
</div>
</nav>
<!-- Main Content -->
<main class="flex-grow flex items-center justify-center">
{% block main %}{% endblock %}
</main>
{% block main %}{% endblock %}
</div>
</body>
{% endblock %}

View File

@@ -0,0 +1,35 @@
{% extends "body_base.html" %}
{% block main %}
<div class="flex justify-center flex-grow mt-0 sm:mt-4">
<div class="container">
<div class="grid grid-cols-1 lg:grid-cols-[auto,1fr] gap-4 p-4">
<!-- Documentation Menu -->
<aside class="bg-base-200 rounded-lg p-4">
{% include "documentation/menu.html" %}
</aside>
<!-- Main Content -->
<article class="prose flex mx-auto justify-center flex-col">
<h1 class="">Personalised Knowledge Management (PKM)</h1>
<p class="">
Personalised Knowledge Management (PKM) is a system designed to help individuals organise, store, and retrieve
information effectively. It empowers users to create a personalised workflow for managing knowledge, enabling
better decision-making and productivity.
</p>
<p class="">
This documentation will guide you through the core concepts, tools, and best practices for building and
maintaining your own PKM system.
</p>
<div class="card p-6 rounded-lg shadow-md">
<h2 class="">Getting Started</h2>
<p class="">
To begin, explore the sections in the navigation menu. Each section provides detailed insights into
different
aspects of PKM, from foundational principles to advanced techniques.
</p>
<a href="/documentation/submenu1" class="btn btn-primary" hx-boost="true">Learn More</a>
</div>
</article>
</div>
</div>
</div>
{% endblock %}

View File

@@ -0,0 +1,22 @@
<ul class="menu bg-base-200 rounded-box">
<li><a hx-boost="true" href="/documentation">Start</a></li>
<li>
<details open>
<summary>Core Concepts</summary>
<ul>
<li><a hx-boost="true" href="/documentation/submenu1">What is PKM?</a></li>
<li><a hx-boost="true" href="/documentation/submenu2">Benefits of PKM</a></li>
</ul>
</details>
</li>
<li>
<details>
<summary>Tools & Techniques</summary>
<ul>
<li><a hx-boost="true" href="/documentation/tools">Tools for PKM</a></li>
<li><a hx-boost="true" href="/documentation/techniques">Effective Techniques</a></li>
</ul>
</details>
</li>
<li><a hx-boost="true" href="/documentation/faq">FAQ</a></li>
</ul>

View File

@@ -1,12 +1,13 @@
<div id="gdpr-banner" class="fixed card mx-auto max-w-screen-sm bg-neutral text-neutral-content bottom-0">
<div id="gdpr-banner" class="fixed card mx-auto max-w-screen-sm mb-2 bg-neutral text-neutral-content bottom-0">
<div class="card-body items-center text-center">
<p class="text-sm"> We use cookies to enhance your experience. By continuing to visit this site, you agree to
our use cookies.
<a href="/privacy-policy" class="link link-primary">Learn more</a>
</p>
<div class="card-actions justify-end">
<button class="btn btn-ghost" hx-post="/gdpr/deny" hx-target="#gdpr-banner" hx-swap="outerHTML">Deny</button>
<button class="btn btn-primary" hx-post="/gdpr/accept" hx-target="#gdpr-banner"
<div class="card-actions justify-end mt-2">
<button class="btn btn-ghost btn-sm" hx-post="/gdpr/deny" hx-target="#gdpr-banner"
hx-swap="outerHTML">Deny</button>
<button class="btn btn-primary btn-sm" hx-post="/gdpr/accept" hx-target="#gdpr-banner"
hx-swap="outerHTML">Accept</button>
</div>
</div>

View File

@@ -6,6 +6,8 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{% block title %}Minne{% endblock %}</title>
<!-- <meta http-equiv="refresh" content="4"> -->
<!-- Preload critical assets -->
<link rel="preload" href="assets/htmx.min.js" as="script">
<link rel="preload" href="assets/style.css" as="style">

View File

@@ -1,4 +1,4 @@
<div class="hero">
<div class="hero flex-grow flex justify-center ">
<div class="hero-content text-center">
<div class="max-w-4xl space-y-8">
<!-- Hero Section -->