mirror of
https://github.com/perstarkse/minne.git
synced 2026-06-08 07:22:46 +02:00
hero page, ingress form
This commit is contained in:
+1
-1
File diff suppressed because one or more lines are too long
@@ -13,6 +13,7 @@
|
|||||||
packages = [
|
packages = [
|
||||||
pkgs.openssl
|
pkgs.openssl
|
||||||
pkgs.nodejs
|
pkgs.nodejs
|
||||||
|
pkgs.vscode-langservers-extracted
|
||||||
];
|
];
|
||||||
|
|
||||||
# https://devenv.sh/languages/
|
# https://devenv.sh/languages/
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ use zettle_db::{
|
|||||||
html::{
|
html::{
|
||||||
account::{delete_account, set_api_key, show_account_page},
|
account::{delete_account, set_api_key, show_account_page},
|
||||||
index::index_handler,
|
index::index_handler,
|
||||||
|
ingress::{process_ingress_form, show_ingress_form},
|
||||||
search_result::search_result_handler,
|
search_result::search_result_handler,
|
||||||
signin::{authenticate_user, show_signin_form},
|
signin::{authenticate_user, show_signin_form},
|
||||||
signout::sign_out_user,
|
signout::sign_out_user,
|
||||||
@@ -152,6 +153,10 @@ fn html_routes(
|
|||||||
.route("/search", get(search_result_handler))
|
.route("/search", get(search_result_handler))
|
||||||
.route("/signout", get(sign_out_user))
|
.route("/signout", get(sign_out_user))
|
||||||
.route("/signin", get(show_signin_form).post(authenticate_user))
|
.route("/signin", get(show_signin_form).post(authenticate_user))
|
||||||
|
.route(
|
||||||
|
"/ingress",
|
||||||
|
get(show_ingress_form).post(process_ingress_form),
|
||||||
|
)
|
||||||
.route("/account", get(show_account_page))
|
.route("/account", get(show_account_page))
|
||||||
.route("/set-api-key", post(set_api_key))
|
.route("/set-api-key", post(set_api_key))
|
||||||
.route("/delete-account", delete(delete_account))
|
.route("/delete-account", delete(delete_account))
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ use crate::{
|
|||||||
storage::types::user::User,
|
storage::types::user::User,
|
||||||
};
|
};
|
||||||
|
|
||||||
page_data!(IndexData, "index.html", {
|
page_data!(IndexData, "index/index.html", {
|
||||||
queue_length: u32,
|
queue_length: u32,
|
||||||
user: Option<User>
|
user: Option<User>
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -0,0 +1,71 @@
|
|||||||
|
use axum::{
|
||||||
|
extract::State,
|
||||||
|
http::{StatusCode, Uri},
|
||||||
|
response::{Html, IntoResponse, Redirect},
|
||||||
|
Form,
|
||||||
|
};
|
||||||
|
use axum_htmx::{HxBoosted, HxRedirect};
|
||||||
|
use axum_session_auth::AuthSession;
|
||||||
|
use axum_session_surreal::SessionSurrealPool;
|
||||||
|
use axum_typed_multipart::{FieldData, TryFromMultipart, TypedMultipart};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use surrealdb::{engine::any::Any, Surreal};
|
||||||
|
use tempfile::NamedTempFile;
|
||||||
|
use tracing::info;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
error::ApiError,
|
||||||
|
server::AppState,
|
||||||
|
storage::types::{file_info::FileInfo, user::User},
|
||||||
|
};
|
||||||
|
|
||||||
|
use super::{render_block, render_template};
|
||||||
|
|
||||||
|
#[derive(Serialize)]
|
||||||
|
struct PageData {
|
||||||
|
// name: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn show_ingress_form(
|
||||||
|
State(state): State<AppState>,
|
||||||
|
auth: AuthSession<User, String, SessionSurrealPool<Any>, Surreal<Any>>,
|
||||||
|
) -> Result<impl IntoResponse, ApiError> {
|
||||||
|
if !auth.is_authenticated() {
|
||||||
|
return Ok(Redirect::to("/").into_response());
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(render_template("ingress_form.html", PageData {}, state.templates)?.into_response())
|
||||||
|
}
|
||||||
|
#[derive(Debug, TryFromMultipart)]
|
||||||
|
pub struct IngressParams {
|
||||||
|
pub content: Option<String>,
|
||||||
|
pub instructions: String,
|
||||||
|
pub category: String,
|
||||||
|
#[form_data(limit = "10000000")] // Adjust limit as needed
|
||||||
|
pub files: Vec<FieldData<NamedTempFile>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn process_ingress_form(
|
||||||
|
State(state): State<AppState>,
|
||||||
|
auth: AuthSession<User, String, SessionSurrealPool<Any>, Surreal<Any>>,
|
||||||
|
TypedMultipart(input): TypedMultipart<IngressParams>,
|
||||||
|
) -> Result<impl IntoResponse, ApiError> {
|
||||||
|
let user = match auth.current_user {
|
||||||
|
Some(user) => user,
|
||||||
|
None => return Ok(Redirect::to("/").into_response()),
|
||||||
|
};
|
||||||
|
|
||||||
|
info!("{:?}", input);
|
||||||
|
|
||||||
|
// Process files and create FileInfo objects
|
||||||
|
let mut file_infos = Vec::new();
|
||||||
|
for file in input.files {
|
||||||
|
let file_info = FileInfo::new(file, &state.surreal_db_client).await?;
|
||||||
|
file_infos.push(file_info);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process the ingress (implement your logic here)
|
||||||
|
|
||||||
|
Ok(Html("SuccessBRO!").into_response())
|
||||||
|
// Ok((HxRedirect::from(Uri::from_static("/")), StatusCode::OK).into_response())
|
||||||
|
}
|
||||||
@@ -5,6 +5,7 @@ use minijinja_autoreload::AutoReloader;
|
|||||||
|
|
||||||
pub mod account;
|
pub mod account;
|
||||||
pub mod index;
|
pub mod index;
|
||||||
|
pub mod ingress;
|
||||||
pub mod search_result;
|
pub mod search_result;
|
||||||
pub mod signin;
|
pub mod signin;
|
||||||
pub mod signout;
|
pub mod signout;
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ pub async fn search_result_handler(
|
|||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
Ok(Html("Hello".to_string()))
|
Ok(Html(answer.content))
|
||||||
// let output = state
|
// let output = state
|
||||||
// .tera
|
// .tera
|
||||||
// .render(
|
// .render(
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<div class="min-h-screen container mx-auto max-w-md flex justify-center flex-col">
|
<div class="min-h-screen container mx-auto px-4 sm:px-0 sm:max-w-md flex justify-center flex-col">
|
||||||
<h2 class="text-2xl font-bold text-center mb-8">Login to your account</h2>
|
<h2 class="text-2xl font-bold text-center mb-8">Login to your account</h2>
|
||||||
|
|
||||||
<form hx-post="/signin" hx-target="#login-result">
|
<form hx-post="/signin" hx-target="#login-result">
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<div class="min-h-screen container mx-auto max-w-md flex justify-center flex-col">
|
<div class="min-h-screen container mx-auto px-4 sm:px-0 sm:max-w-md flex justify-center flex-col">
|
||||||
<h2 class="text-2xl font-bold text-center mb-8">Create your account</h2>
|
<h2 class="text-2xl font-bold text-center mb-8">Create your account</h2>
|
||||||
|
|
||||||
<form hx-post="/signup" hx-target="#signup-result" class="">
|
<form hx-post="/signup" hx-target="#signup-result" class="">
|
||||||
|
|||||||
@@ -6,16 +6,16 @@
|
|||||||
<!-- Navbar -->
|
<!-- Navbar -->
|
||||||
<nav class="navbar bg-base-200">
|
<nav class="navbar bg-base-200">
|
||||||
<div class="flex-1">
|
<div class="flex-1">
|
||||||
<a class="btn text-xl border-transparent btn-outline btn-primary" href="/">Minne</a>
|
<a class="btn text-2xl border-transparent btn-outline btn-primary" href="/">Minne</a>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<ul class="menu menu-horizontal px-1">
|
<ul class="menu menu-horizontal px-1">
|
||||||
{% if user %}
|
{% if user %}
|
||||||
<li><a hx-boost="true" href="/account">Account</a></li>
|
<li><a hx-boost="true" class="" href="/account">Account</a></li>
|
||||||
<li><a hx-boost="true" href="/signout">Sign out</a></li>
|
<li><a hx-boost="true" href="/signout">Sign out</a></li>
|
||||||
{% else %}
|
{% else %}
|
||||||
<li><a hx-boost="true" href="/signin">Login</a></li>
|
<li><a hx-boost="true" class="" href="/signin">Login</a></li>
|
||||||
<li><a hx-boost="true" href="/signup">Sign up</a></li>
|
<li><a hx-boost="true" class="" href="/signup">Sign up</a></li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,27 +0,0 @@
|
|||||||
{% extends "head_base.html" %}
|
|
||||||
|
|
||||||
{% block body %}
|
|
||||||
|
|
||||||
<body class="min-h-screen">
|
|
||||||
<nav class="navbar bg-base-200">
|
|
||||||
<div class="flex-1">
|
|
||||||
<a class="btn text-xl border-transparent btn-outline btn-primary" href="/">Minne</a>
|
|
||||||
</div>
|
|
||||||
<div class="flex-none">
|
|
||||||
<ul class="menu menu-horizontal px-1">
|
|
||||||
{% if user %}
|
|
||||||
<li><a hx-boost="true" href="/account">Account</a></li>
|
|
||||||
<li><a hx-boost="true" href="/signout">Sign out</a></li>
|
|
||||||
{% else %}
|
|
||||||
<li><a hx-boost="true" href="/signin">Login</a></li>
|
|
||||||
<li><a hx-boost="true" href="/signup">Sign up</a></li>
|
|
||||||
{% endif %}
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
<main class="container mx-auto ">
|
|
||||||
{% block content %}{% endblock %}
|
|
||||||
</main>
|
|
||||||
</body>
|
|
||||||
{% endblock %}
|
|
||||||
@@ -1,34 +0,0 @@
|
|||||||
{% extends "body_base.html" %}
|
|
||||||
{% block main %}
|
|
||||||
{% if user %}
|
|
||||||
<p class="text-blue-950">HI</p>
|
|
||||||
{% else %}
|
|
||||||
<div class="flex flex-col items-center justify-center min-h-[80vh] space-y-8">
|
|
||||||
<!-- Hero Section -->
|
|
||||||
<div class="text-center space-y-4 mb-8">
|
|
||||||
<h1
|
|
||||||
class="text-5xl font-bold bg-gradient-to-r from-blue-400 via-purple-500 to-pink-500 text-transparent bg-clip-text">
|
|
||||||
Welcome to minne
|
|
||||||
</h1>
|
|
||||||
<p class="text-gray-400 text-xl">
|
|
||||||
An experiment in creating a second brain
|
|
||||||
</p>
|
|
||||||
<p class="text-gray-400 text-lg">
|
|
||||||
There are {{queue_length}} messages queued for ingression.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Search Bar -->
|
|
||||||
<div class="w-full max-w-2xl">
|
|
||||||
<input type="text" placeholder="Enter your search query" class="input input-bordered w-full" name="query"
|
|
||||||
hx-get="/search" hx-target="#search-results" />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Search Results -->
|
|
||||||
<div id="search-results" class="w-full max-w-2xl mt-4">
|
|
||||||
<!-- Results will be populated here by HTMX -->
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
{% endblock %}
|
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
<div class="hero">
|
||||||
|
<div class="hero-content text-center">
|
||||||
|
<div class="max-w-4xl space-y-8">
|
||||||
|
<!-- Hero Section -->
|
||||||
|
<h1
|
||||||
|
class="text-5xl sm:text-6xl py-4 pt-10 font-bold bg-gradient-to-r from-primary to-secondary text-transparent bg-clip-text">
|
||||||
|
Simplify Your Knowledge Management
|
||||||
|
</h1>
|
||||||
|
<p class="text-xl text-base-content/70">
|
||||||
|
Capture, connect, and retrieve your knowledge effortlessly with Minne
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<!-- Features Grid -->
|
||||||
|
<div class="grid grid-cols-1 md:grid-cols-3 gap-6 my-12">
|
||||||
|
<div class="card bg-base-100 shadow-hover">
|
||||||
|
<div class="card-body items-center">
|
||||||
|
<div class="skeleton h-32 w-32 rounded-full"></div>
|
||||||
|
<h3 class="card-title">Easy Capture</h3>
|
||||||
|
<p>Save anything instantly - texts, links, images, and more</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="card bg-base-100 shadow-hover">
|
||||||
|
<div class="card-body items-center">
|
||||||
|
<div class="skeleton h-32 w-32 rounded-full"></div>
|
||||||
|
<h3 class="card-title">Smart Analysis</h3>
|
||||||
|
<p>AI-powered content analysis and organization</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="card bg-base-100 shadow-hover">
|
||||||
|
<div class="card-body items-center">
|
||||||
|
<div class="skeleton h-32 w-32 rounded-full"></div>
|
||||||
|
<h3 class="card-title">Knowledge Graph</h3>
|
||||||
|
<p>Visualize connections between your ideas</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- CTA -->
|
||||||
|
<div class="space-y-4">
|
||||||
|
<div class="flex justify-center gap-4">
|
||||||
|
<button class="btn btn-primary btn-lg">Get Started</button>
|
||||||
|
<button class="btn btn-outline btn-lg">Learn More</button>
|
||||||
|
</div>
|
||||||
|
<p class="text-sm text-base-content/60">
|
||||||
|
Currently processing {{queue_length}} items in queue
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
{% extends "body_base.html" %}
|
||||||
|
{% block main %}
|
||||||
|
{% if user %}
|
||||||
|
{% include 'index/signed_in_view.html' %}
|
||||||
|
{% else %}
|
||||||
|
{% include 'index/hero.html' %}
|
||||||
|
{% endif %}
|
||||||
|
{% endblock %}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
<div class="container mx-auto p-4 max-w-screen-lg flex-col flex justify-center gap-6">
|
||||||
|
<!-- Search Bar -->
|
||||||
|
<div class="form-control w-full mx-auto mt-8">
|
||||||
|
<h1 class="textl-lg text-center pb-5">So here you can search all your ingressed documents</h1>
|
||||||
|
<input type="text" placeholder="Search your knowledge base" class="input input-bordered w-full" name="query"
|
||||||
|
hx-get="/search" hx-target="#search-results" />
|
||||||
|
<div id="search-results" class="mt-4">
|
||||||
|
<!-- Results will be populated here by HTMX -->
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Recent Activity -->
|
||||||
|
<div class="card bg-base-100 shadow-xl">
|
||||||
|
<div class="card-body">
|
||||||
|
<h2 class="card-title">Recent Activity</h2>
|
||||||
|
<div class="skeleton h-32 w-full"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Quick Actions - Modified button to link to ingress form -->
|
||||||
|
<div class="card bg-base-100 shadow-xl">
|
||||||
|
<div class="card-body">
|
||||||
|
<h2 class="card-title">Quick Actions</h2>
|
||||||
|
<div class="flex gap-4">
|
||||||
|
<a class="btn btn-primary" href="/ingress" hx-boost="true">Add Content</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
{% extends "body_base.html" %}
|
||||||
|
{% block main %}
|
||||||
|
<div class="container px-4 max-w-screen-lg">
|
||||||
|
<form class="space-y-2" hx-post="/ingress" enctype="multipart/form-data">
|
||||||
|
<h1 class="text-2xl">Add content to the database </h1>
|
||||||
|
<label class="label label-text">Instructions</label>
|
||||||
|
<textarea name="instructions" class="textarea w-full input-bordered"
|
||||||
|
placeholder="Enter instructions for the AI here, help it understand what its seeing or how it should relate to the database"></textarea>
|
||||||
|
<label class="label label-text">Content (optional)</label>
|
||||||
|
<textarea name="content" class="textarea w-full input-bordered" placeholder="Additional content"></textarea>
|
||||||
|
<label class="label label-text">Category</label>
|
||||||
|
<input type="text" name="category" class="input input-bordered" placeholder="Category for ingress">
|
||||||
|
|
||||||
|
<label class="label label-text">Files</label>
|
||||||
|
<input type="file" name="files" multiple class="file-input file-input-bordered" />
|
||||||
|
<button type="submit" class="btn btn-primary">Submit</button>
|
||||||
|
</form>
|
||||||
|
<div id="ingress-result"></div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
@@ -3,5 +3,6 @@
|
|||||||
\[x\] templating
|
\[x\] templating
|
||||||
\[x\] redirects
|
\[x\] redirects
|
||||||
\[\] hx-redirect
|
\[\] hx-redirect
|
||||||
\[\] macro for pagedata?
|
\[x\] macro for pagedata?
|
||||||
\[\] add more config structs for clarity
|
\[\] add more config structs for clarity
|
||||||
|
\[\] user id to fileinfo and data path?
|
||||||
|
|||||||
Reference in New Issue
Block a user