Create project and documents #1
11 changed files with 380 additions and 1080 deletions
116
Cargo.lock
generated
116
Cargo.lock
generated
|
@ -341,6 +341,15 @@ dependencies = [
|
|||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bincode"
|
||||
version = "1.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.3.2"
|
||||
|
@ -611,6 +620,15 @@ version = "2.4.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5"
|
||||
|
||||
[[package]]
|
||||
name = "crc32fast"
|
||||
version = "1.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b3855a8a784b474f333699ef2bbca9db2c4a1f6d9088a90a2d25b1eb53111eaa"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-channel"
|
||||
version = "0.5.12"
|
||||
|
@ -792,7 +810,7 @@ checksum = "1ee447700ac8aa0b2f2bd7bc4462ad686ba06baa6727ac149a2d6277f0d240fd"
|
|||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"redox_syscall",
|
||||
"redox_syscall 0.4.1",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
|
@ -828,6 +846,16 @@ dependencies = [
|
|||
"percent-encoding",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fs2"
|
||||
version = "0.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9564fc758e15025b46aa6643b1b77d047d1a56a1aea6e01002ac0c7026876213"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fsevent-sys"
|
||||
version = "4.1.0"
|
||||
|
@ -892,7 +920,7 @@ checksum = "1d930c203dd0b6ff06e0201a4a2fe9149b43c684fd4420555b26d21b1a02956f"
|
|||
dependencies = [
|
||||
"futures-core",
|
||||
"lock_api",
|
||||
"parking_lot",
|
||||
"parking_lot 0.12.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -942,6 +970,15 @@ dependencies = [
|
|||
"slab",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fxhash"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "generic-array"
|
||||
version = "0.14.7"
|
||||
|
@ -1244,6 +1281,15 @@ dependencies = [
|
|||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "instant"
|
||||
version = "0.1.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itertools"
|
||||
version = "0.12.1"
|
||||
|
@ -1457,7 +1503,7 @@ dependencies = [
|
|||
"crossbeam-utils",
|
||||
"futures-util",
|
||||
"once_cell",
|
||||
"parking_lot",
|
||||
"parking_lot 0.12.1",
|
||||
"quanta",
|
||||
"rustc_version",
|
||||
"skeptic",
|
||||
|
@ -1633,6 +1679,17 @@ version = "0.1.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39"
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot"
|
||||
version = "0.11.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99"
|
||||
dependencies = [
|
||||
"instant",
|
||||
"lock_api",
|
||||
"parking_lot_core 0.8.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot"
|
||||
version = "0.12.1"
|
||||
|
@ -1640,7 +1697,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f"
|
||||
dependencies = [
|
||||
"lock_api",
|
||||
"parking_lot_core",
|
||||
"parking_lot_core 0.9.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot_core"
|
||||
version = "0.8.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "60a2cfe6f0ad2bfc16aefa463b497d5c7a5ecd44a23efa72aa342d90177356dc"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"instant",
|
||||
"libc",
|
||||
"redox_syscall 0.2.16",
|
||||
"smallvec",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1651,7 +1722,7 @@ checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e"
|
|||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"redox_syscall",
|
||||
"redox_syscall 0.4.1",
|
||||
"smallvec",
|
||||
"windows-targets 0.48.5",
|
||||
]
|
||||
|
@ -1730,6 +1801,7 @@ dependencies = [
|
|||
"axum",
|
||||
"axum-htmx",
|
||||
"axum-login",
|
||||
"bincode",
|
||||
"clap",
|
||||
"dotenvy",
|
||||
"env_logger",
|
||||
|
@ -1738,6 +1810,7 @@ dependencies = [
|
|||
"rand",
|
||||
"sea-orm",
|
||||
"serde",
|
||||
"sled",
|
||||
"thiserror",
|
||||
"tokio",
|
||||
"tower-http",
|
||||
|
@ -1929,6 +2002,15 @@ dependencies = [
|
|||
"bitflags 2.4.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.2.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a"
|
||||
dependencies = [
|
||||
"bitflags 1.3.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.4.1"
|
||||
|
@ -2430,6 +2512,22 @@ dependencies = [
|
|||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sled"
|
||||
version = "0.34.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7f96b4737c2ce5987354855aed3797279def4ebf734436c6aa4552cf8e169935"
|
||||
dependencies = [
|
||||
"crc32fast",
|
||||
"crossbeam-epoch",
|
||||
"crossbeam-utils",
|
||||
"fs2",
|
||||
"fxhash",
|
||||
"libc",
|
||||
"log",
|
||||
"parking_lot 0.11.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "smallvec"
|
||||
version = "1.13.1"
|
||||
|
@ -2884,7 +2982,7 @@ dependencies = [
|
|||
"libc",
|
||||
"mio",
|
||||
"num_cpus",
|
||||
"parking_lot",
|
||||
"parking_lot 0.12.1",
|
||||
"pin-project-lite",
|
||||
"signal-hook-registry",
|
||||
"socket2",
|
||||
|
@ -2972,7 +3070,7 @@ dependencies = [
|
|||
"cookie",
|
||||
"futures-util",
|
||||
"http",
|
||||
"parking_lot",
|
||||
"parking_lot 0.12.1",
|
||||
"pin-project-lite",
|
||||
"tower-layer",
|
||||
"tower-service",
|
||||
|
@ -3044,7 +3142,7 @@ dependencies = [
|
|||
"base64 0.22.0",
|
||||
"futures",
|
||||
"http",
|
||||
"parking_lot",
|
||||
"parking_lot 0.12.1",
|
||||
"rand",
|
||||
"serde",
|
||||
"serde_json",
|
||||
|
@ -3363,7 +3461,7 @@ version = "1.5.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a44ab49fad634e88f55bf8f9bb3abd2f27d7204172a112c7c9987e01c1c94ea9"
|
||||
dependencies = [
|
||||
"redox_syscall",
|
||||
"redox_syscall 0.4.1",
|
||||
"wasite",
|
||||
]
|
||||
|
||||
|
|
|
@ -13,6 +13,7 @@ async-trait = "0.1.78"
|
|||
axum = "0.7.4"
|
||||
axum-htmx = { version = "0.5.0", features = ["guards", "serde"] }
|
||||
axum-login = "0.14.0"
|
||||
bincode = "1.3.3"
|
||||
clap = { version = "4.5.3", features = ["derive", "env"] }
|
||||
dotenvy = "0.15.7"
|
||||
env_logger = "0.11.3"
|
||||
|
@ -21,6 +22,7 @@ minijinja-autoreload = "1.0.14"
|
|||
rand = "0.8.5"
|
||||
sea-orm = { version = "0.12.15", features = ["sqlx-sqlite", "macros", "runtime-tokio-rustls"] }
|
||||
serde = { version = "1.0.197", features = ["derive"] }
|
||||
sled = "0.34.7"
|
||||
thiserror = "1.0.58"
|
||||
tokio = { version = "1.36.0", features = ["rt", "full"] }
|
||||
tower-http = { version = "0.5.2", features = ["fs", "trace"] }
|
||||
|
|
|
@ -1,12 +1,28 @@
|
|||
use axum::response::Redirect;
|
||||
use axum_login::AuthSession;
|
||||
|
||||
use crate::prelude::*;
|
||||
use crate::{models::Project, prelude::*};
|
||||
|
||||
pub async fn home_page(State(ctx): State<Context>, auth_session: AuthSession<Context>) -> Response {
|
||||
if let Some(user) = auth_session.user {
|
||||
let projects: Vec<Project> = vec![
|
||||
Project {
|
||||
id: 1,
|
||||
owner_id: 1,
|
||||
name: "Blog posts".to_owned(),
|
||||
key: "BLOG".to_owned(),
|
||||
},
|
||||
Project {
|
||||
id: 2,
|
||||
owner_id: 1,
|
||||
name: "Bugs (Pique)".to_owned(),
|
||||
key: "BUG".to_owned(),
|
||||
},
|
||||
];
|
||||
|
||||
let values = context! {
|
||||
user => user,
|
||||
projects => projects,
|
||||
};
|
||||
|
||||
ctx.render_resp("home.html", values)
|
||||
|
|
|
@ -4,8 +4,10 @@ pub mod db;
|
|||
pub mod entity;
|
||||
pub mod handler;
|
||||
pub mod logging;
|
||||
pub mod models;
|
||||
pub mod password;
|
||||
pub mod prelude;
|
||||
pub mod serialize;
|
||||
pub mod server;
|
||||
pub mod session;
|
||||
pub mod templates;
|
||||
|
|
23
src/models.rs
Normal file
23
src/models.rs
Normal file
|
@ -0,0 +1,23 @@
|
|||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, PartialEq)]
|
||||
pub struct Project {
|
||||
pub id: u64,
|
||||
pub owner_id: i32,
|
||||
|
||||
pub name: String,
|
||||
|
||||
// The key is the short code, like BUG, which is used to refer to a project
|
||||
// quickly and to display it more compactly. This must be unique across the
|
||||
// projects a user owns.
|
||||
pub key: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, PartialEq)]
|
||||
pub struct Document {
|
||||
pub id: u64,
|
||||
pub project_id: u64,
|
||||
|
||||
pub title: String,
|
||||
pub content: String,
|
||||
}
|
16
src/serialize.rs
Normal file
16
src/serialize.rs
Normal file
|
@ -0,0 +1,16 @@
|
|||
use bincode::{DefaultOptions, Options};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
fn bincode_options() -> impl Options {
|
||||
DefaultOptions::new().with_big_endian()
|
||||
}
|
||||
|
||||
pub fn serialize<T: ?Sized + Serialize>(value: &T) -> Result<Vec<u8>, bincode::Error> {
|
||||
let options = bincode_options();
|
||||
options.serialize(value)
|
||||
}
|
||||
|
||||
pub fn deserialize<'a, T: Deserialize<'a>>(bytes: &'a [u8]) -> Result<T, bincode::Error> {
|
||||
let options = bincode_options();
|
||||
options.deserialize(bytes)
|
||||
}
|
993
static/main.css
993
static/main.css
File diff suppressed because it is too large
Load diff
|
@ -1,46 +1,46 @@
|
|||
let mobile_open_button = document.getElementById("mobile-menu-open-button");
|
||||
let mobile_close_button = document.getElementById("mobile-menu-close-button");
|
||||
let mobile_menu = document.getElementById("mobile-menu");
|
||||
|
||||
const profile_button = document.getElementById("profile-menu-button");
|
||||
let profile_dropdown = document.getElementById("profile-dropdown");
|
||||
|
||||
function toggle_mobile_menu() {
|
||||
|
||||
if (mobile_open_button.classList.contains("block")) {
|
||||
mobile_menu.classList.remove("hidden");
|
||||
mobile_open_button.classList.remove("block");
|
||||
mobile_open_button.classList.add("hidden");
|
||||
mobile_close_button.classList.remove("hidden");
|
||||
mobile_close_button.classList.add("block");
|
||||
} else {
|
||||
mobile_menu.classList.add("hidden");
|
||||
mobile_close_button.classList.remove("block");
|
||||
mobile_close_button.classList.add("hidden");
|
||||
mobile_open_button.classList.remove("hidden");
|
||||
mobile_open_button.classList.add("block");
|
||||
}
|
||||
}
|
||||
|
||||
function toggle_profile_dropdown() {
|
||||
|
||||
if (profile_dropdown.classList.contains("hidden")) {
|
||||
profile_dropdown.classList.remove("hidden");
|
||||
} else {
|
||||
profile_dropdown.classList.add("hidden");
|
||||
}
|
||||
}
|
||||
|
||||
function hide_profile_dropdown() {
|
||||
let profile_dropdown = document.getElementById("profile-dropdown");
|
||||
|
||||
if (!profile_dropdown.classList.contains("hidden")) {
|
||||
profile_dropdown.classList.add("hidden");
|
||||
}
|
||||
}
|
||||
|
||||
document.addEventListener("click", (event) => {
|
||||
if (!profile_button.contains(event.target) && !profile_dropdown.contains(event.target)) {
|
||||
profile_dropdown.classList.add("hidden");
|
||||
}
|
||||
});
|
||||
//let mobile_open_button = document.getElementById("mobile-menu-open-button");
|
||||
//let mobile_close_button = document.getElementById("mobile-menu-close-button");
|
||||
//let mobile_menu = document.getElementById("mobile-menu");
|
||||
//
|
||||
//const profile_button = document.getElementById("profile-menu-button");
|
||||
//let profile_dropdown = document.getElementById("profile-dropdown");
|
||||
//
|
||||
//function toggle_mobile_menu() {
|
||||
//
|
||||
// if (mobile_open_button.classList.contains("block")) {
|
||||
// mobile_menu.classList.remove("hidden");
|
||||
// mobile_open_button.classList.remove("block");
|
||||
// mobile_open_button.classList.add("hidden");
|
||||
// mobile_close_button.classList.remove("hidden");
|
||||
// mobile_close_button.classList.add("block");
|
||||
// } else {
|
||||
// mobile_menu.classList.add("hidden");
|
||||
// mobile_close_button.classList.remove("block");
|
||||
// mobile_close_button.classList.add("hidden");
|
||||
// mobile_open_button.classList.remove("hidden");
|
||||
// mobile_open_button.classList.add("block");
|
||||
// }
|
||||
//}
|
||||
//
|
||||
//function toggle_profile_dropdown() {
|
||||
//
|
||||
// if (profile_dropdown.classList.contains("hidden")) {
|
||||
// profile_dropdown.classList.remove("hidden");
|
||||
// } else {
|
||||
// profile_dropdown.classList.add("hidden");
|
||||
// }
|
||||
//}
|
||||
//
|
||||
//function hide_profile_dropdown() {
|
||||
// let profile_dropdown = document.getElementById("profile-dropdown");
|
||||
//
|
||||
// if (!profile_dropdown.classList.contains("hidden")) {
|
||||
// profile_dropdown.classList.add("hidden");
|
||||
// }
|
||||
//}
|
||||
//
|
||||
//document.addEventListener("click", (event) => {
|
||||
// if (!profile_button.contains(event.target) && !profile_dropdown.contains(event.target)) {
|
||||
// profile_dropdown.classList.add("hidden");
|
||||
// }
|
||||
//});
|
||||
|
|
85
templates/components/sidebar.html
Normal file
85
templates/components/sidebar.html
Normal file
|
@ -0,0 +1,85 @@
|
|||
<div class="fixed inset-y-0 z-50 flex w-72 flex-col">
|
||||
<div class="flex grow flex-col gap-y-5 overflow-y-auto border-r border-gray-20 bg-white px-6">
|
||||
|
||||
<div class="flex h-16 shrink-0 items-center">
|
||||
<span class="h-8 w-auto text-xl">⛰️</span>
|
||||
</div>
|
||||
|
||||
<nav class="flex flex-1 flex-col">
|
||||
<ul role="list" class="flex flex-1 flex-col gap-y-7">
|
||||
|
||||
<li>
|
||||
<ul role="list" class="-mx-2 space-y-1">
|
||||
<li>
|
||||
<!-- Current: "bg-gray-50 text-indigo-600", Default: "text-gray-700 hover:text-indigo-600 hover:bg-gray-50" -->
|
||||
<a href="#" class="bg-gray-50 text-indigo-600 group flex gap-x-3 rounded-md p-2 text-sm leading-6 font-semibold">
|
||||
<svg class="h-6 w-6 shrink-0 text-indigo-600" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" aria-hidden="true">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M2.25 12l8.954-8.955c.44-.439 1.152-.439 1.591 0L21.75 12M4.5 9.75v10.125c0 .621.504 1.125 1.125 1.125H9.75v-4.875c0-.621.504-1.125 1.125-1.125h2.25c.621 0 1.125.504 1.125 1.125V21h4.125c.621 0 1.125-.504 1.125-1.125V9.75M8.25 21h8.25" />
|
||||
</svg>
|
||||
Dashboard
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="#" class="text-gray-700 hover:text-indigo-600 hover:bg-gray-50 group flex gap-x-3 rounded-md p-2 text-sm leading-6 font-semibold">
|
||||
<svg class="h-6 w-6 shrink-0 text-gray-400 group-hover:text-indigo-600" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" aria-hidden="true">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M2.25 12.75V12A2.25 2.25 0 014.5 9.75h15A2.25 2.25 0 0121.75 12v.75m-8.69-6.44l-2.12-2.12a1.5 1.5 0 00-1.061-.44H4.5A2.25 2.25 0 002.25 6v12a2.25 2.25 0 002.25 2.25h15A2.25 2.25 0 0021.75 18V9a2.25 2.25 0 00-2.25-2.25h-5.379a1.5 1.5 0 01-1.06-.44z" />
|
||||
</svg>
|
||||
Projects
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#" class="text-gray-700 hover:text-indigo-600 hover:bg-gray-50 group flex gap-x-3 rounded-md p-2 text-sm leading-6 font-semibold">
|
||||
<svg class="h-6 w-6 shrink-0 text-gray-400 group-hover:text-indigo-600" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" aria-hidden="true">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M15.75 17.25v3.375c0 .621-.504 1.125-1.125 1.125h-9.75a1.125 1.125 0 01-1.125-1.125V7.875c0-.621.504-1.125 1.125-1.125H6.75a9.06 9.06 0 011.5.124m7.5 10.376h3.375c.621 0 1.125-.504 1.125-1.125V11.25c0-4.46-3.243-8.161-7.5-8.876a9.06 9.06 0 00-1.5-.124H9.375c-.621 0-1.125.504-1.125 1.125v3.5m7.5 10.375H9.375a1.125 1.125 0 01-1.125-1.125v-9.25m12 6.625v-1.875a3.375 3.375 0 00-3.375-3.375h-1.5a1.125 1.125 0 01-1.125-1.125v-1.5a3.375 3.375 0 00-3.375-3.375H9.75" />
|
||||
</svg>
|
||||
Documents
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#" class="text-gray-700 hover:text-indigo-600 hover:bg-gray-50 group flex gap-x-3 rounded-md p-2 text-sm leading-6 font-semibold">
|
||||
<svg class="h-6 w-6 shrink-0 text-gray-400 group-hover:text-indigo-600" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" aria-hidden="true">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M20.25 8.511c.884.284 1.5 1.128 1.5 2.097v4.286c0 1.136-.847 2.1-1.98 2.193-.34.027-.68.052-1.02.072v3.091l-3-3c-1.354 0-2.694-.055-4.02-.163a2.115 2.115 0 0 1-.825-.242m9.345-8.334a2.126 2.126 0 0 0-.476-.095 48.64 48.64 0 0 0-8.048 0c-1.131.094-1.976 1.057-1.976 2.192v4.286c0 .837.46 1.58 1.155 1.951m9.345-8.334V6.637c0-1.621-1.152-3.026-2.76-3.235A48.455 48.455 0 0 0 11.25 3c-2.115 0-4.198.137-6.24.402-1.608.209-2.76 1.614-2.76 3.235v6.226c0 1.621 1.152 3.026 2.76 3.235.577.075 1.157.14 1.74.194V21l4.155-4.155" />
|
||||
</svg>
|
||||
Chats
|
||||
</a>
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<div class="text-xs font-semibold leading-6 text-gray-400">Your projects</div>
|
||||
<ul role="list" class="-mx-2 mt-2 space-y-1">
|
||||
|
||||
{% for project in projects %}
|
||||
<li>
|
||||
<!-- Current: "bg-gray-50 text-indigo-600", Default: "text-gray-700 hover:text-indigo-600 hover:bg-gray-50" -->
|
||||
<a href="#" class="text-gray-700 hover:text-indigo-600 hover:bg-gray-50 group flex gap-x-3 rounded-md p-2 text-sm leading-6 font-semibold">
|
||||
<span class="flex h-6 w-10 shrink-0 items-center justify-center rounded-lg border text-[0.625rem] font-medium bg-white text-gray-400 border-gray-200 group-hover:border-indigo-600 group-hover:text-indigo-600">{{ project.key }}</span>
|
||||
<span class="truncate">{{ project.name }}</span>
|
||||
</a>
|
||||
</li>
|
||||
{% endfor %}
|
||||
|
||||
</ul>
|
||||
</li>
|
||||
|
||||
<li class="-mx-6 mt-auto">
|
||||
<a href="/profile" class="flex items-center gap-x-4 px-6 py-3 text-sm font-semibold leading-6 text-gray-900 hover:bg-gray-50">
|
||||
<div class="h-8 w-8 rounded-full bg-gray-50">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-8 h-8">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M17.982 18.725A7.488 7.488 0 0 0 12 15.75a7.488 7.488 0 0 0-5.982 2.975m11.963 0a9 9 0 1 0-11.963 0m11.963 0A8.966 8.966 0 0 1 12 21a8.966 8.966 0 0 1-5.982-2.275M15 9.75a3 3 0 1 1-6 0 3 3 0 0 1 6 0Z" />
|
||||
</svg>
|
||||
</div>
|
||||
|
||||
<span class="sr-only">Your profile</span>
|
||||
<span aria-hidden="true">{{ user.full_name }}</span>
|
||||
</a>
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
</div>
|
||||
</div>
|
|
@ -4,5 +4,5 @@
|
|||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Pique</title>
|
||||
<link rel="stylesheet" href="/static/main.css">
|
||||
<link rel="icon" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'><text y='.9em' font-size='90'>👀</text></svg>"/>
|
||||
<link rel="icon" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'><text y='.9em' font-size='90'>⛰️</text></svg>"/>
|
||||
</head>
|
||||
|
|
|
@ -2,115 +2,16 @@
|
|||
<html lang="en" class="h-full bg-white">
|
||||
{% include "head.html" %}
|
||||
<body class="h-full">
|
||||
<!--
|
||||
This example requires updating your template:
|
||||
|
||||
```
|
||||
<html class="h-full bg-gray-100">
|
||||
<body class="h-full">
|
||||
```
|
||||
-->
|
||||
<div class="min-h-full">
|
||||
<nav class="bg-purple-200">
|
||||
<div class="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8">
|
||||
<div class="flex h-16 items-center justify-between">
|
||||
<div class="flex items-center">
|
||||
<div class="flex-shrink-0">
|
||||
👀
|
||||
</div>
|
||||
<div class="hidden md:block">
|
||||
<div class="ml-10 flex items-baseline space-x-4">
|
||||
<!-- Current: "bg-purple-700 text-white", Default: "text-gray-700 hover:bg-purple-500 hover:bg-opacity-75" -->
|
||||
<a href="#" class="bg-purple-700 text-white rounded-md px-3 py-2 text-sm font-medium" aria-current="page">Dashboard</a>
|
||||
<a href="#" class="text-gray-700 hover:text-white hover:bg-purple-500 hover:bg-opacity-75 rounded-md px-3 py-2 text-sm font-medium">Placeholder</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="hidden md:block">
|
||||
<div class="ml-4 flex items-center md:ml-6">
|
||||
<!-- Profile dropdown -->
|
||||
<div class="relative ml-3">
|
||||
<div>
|
||||
<button type="button" class="relative flex max-w-xs items-center rounded-full bg-purple-600 text-sm focus:outline-none focus:ring-2 focus:ring-white focus:ring-offset-2 focus:ring-offset-purple-600" id="profile-menu-button" aria-expanded="false" aria-haspopup="true" onClick="toggle_profile_dropdown()">
|
||||
<span class="absolute -inset-1.5"></span>
|
||||
<span class="sr-only">Open user menu</span>
|
||||
|
||||
<!-- placeholder icon -->
|
||||
<span class="inline-block h-6 w-6 overflow-hidden rounded-full bg-gray-200">
|
||||
<svg class="h-full w-full text-gray-400" fill="currentColor" viewBox="0 0 24 24">
|
||||
<path d="M24 20.993V24H0v-2.996A14.977 14.977 0 0112.004 15c4.904 0 9.26 2.354 11.996 5.993zM16.002 8.999a4 4 0 11-8 0 4 4 0 018 0z" />
|
||||
</svg>
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="hidden absolute right-0 z-10 mt-2 w-48 origin-top-right rounded-md bg-white py-1 shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none" role="menu" aria-orientation="vertical" aria-labelledby="user-menu-button" tabindex="-1" id="profile-dropdown">
|
||||
|
||||
<div class="ml-3">
|
||||
<div class="text-base font-medium text-gray-600">{{ user.full_name }}</div>
|
||||
<div class="text-sm font-medium text-gray-400">{{ user.email }}</div>
|
||||
</div>
|
||||
<!-- Active: "bg-gray-100", Not Active: "" -->
|
||||
<a href="/logout" class="block px-4 py-2 text-sm text-gray-700" role="menuitem" tabindex="-1" id="user-menu-item-2">Sign out</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="-mr-2 flex md:hidden">
|
||||
<!-- Mobile menu button -->
|
||||
<button type="button" class="relative inline-flex items-center justify-center rounded-md bg-purple-600 p-2 text-purple-200 hover:bg-purple-500 hover:bg-opacity-75 hover:text-white focus:outline-none focus:ring-2 focus:ring-white focus:ring-offset-2 focus:ring-offset-purple-600" aria-controls="mobile-menu" aria-expanded="false" onClick="toggle_mobile_menu()">
|
||||
<span class="absolute -inset-0.5"></span>
|
||||
<span class="sr-only">Open main menu</span>
|
||||
<!-- Menu open: "hidden", Menu closed: "block" -->
|
||||
<svg class="block h-6 w-6" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" aria-hidden="true" id="mobile-menu-open-button">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M3.75 6.75h16.5M3.75 12h16.5m-16.5 5.25h16.5" />
|
||||
</svg>
|
||||
<!-- Menu open: "block", Menu closed: "hidden" -->
|
||||
<svg class="hidden h-6 w-6" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" aria-hidden="true" id="mobile-menu-close-button">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M6 18L18 6M6 6l12 12" />
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Mobile menu, show/hide based on menu state. -->
|
||||
<div class="md:hidden hidden" id="mobile-menu">
|
||||
<div class="space-y-1 px-2 pb-3 pt-2 sm:px-3">
|
||||
<!-- Current: "bg-purple-700 text-white", Default: "text-white hover:bg-purple-500 hover:bg-opacity-75" -->
|
||||
<a href="#" class="bg-purple-700 text-white block rounded-md px-3 py-2 text-base font-medium" aria-current="page">Dashboard</a>
|
||||
<a href="#" class="text-gray-700 hover:text-white hover:bg-purple-500 hover:bg-opacity-75 block rounded-md px-3 py-2 text-base font-medium">Placeholder</a>
|
||||
</div>
|
||||
<div class="border-t border-purple-700 pb-3 pt-4">
|
||||
<div class="flex items-center px-5">
|
||||
<div class="flex-shrink-0">
|
||||
<!-- placeholder icon -->
|
||||
<span class="inline-block h-6 w-6 overflow-hidden rounded-full bg-gray-200">
|
||||
<svg class="h-full w-full text-gray-400" fill="currentColor" viewBox="0 0 24 24">
|
||||
<path d="M24 20.993V24H0v-2.996A14.977 14.977 0 0112.004 15c4.904 0 9.26 2.354 11.996 5.993zM16.002 8.999a4 4 0 11-8 0 4 4 0 018 0z" />
|
||||
</svg>
|
||||
</span>
|
||||
</div>
|
||||
<div class="ml-3">
|
||||
<div class="text-base font-medium text-gray-600">{{ user.full_name }}</div>
|
||||
<div class="text-sm font-medium text-gray-400">{{ user.email }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-3 space-y-1 px-2">
|
||||
<a href="/logout" class="block rounded-md px-3 py-2 text-base font-medium text-gray-700 hover:bg-purple-500 hover:bg-opacity-75">Sign out</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<main>
|
||||
<div class="mx-auto max-w-7xl py-6 sm:px-6 lg:px-8">
|
||||
|
||||
Hi there!
|
||||
{% include "components/sidebar.html" %}
|
||||
|
||||
<main class="py-10 pl-72">
|
||||
<div class="px-8">
|
||||
Main content.
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
|
||||
|
||||
<script type="text/javascript" src="/static/main.js"></script>
|
||||
</body>
|
||||
|
|
Loading…
Reference in a new issue