refactor: website files are now templated and compiled

This commit is contained in:
Kenneth Jao 2025-05-26 01:22:21 -04:00
parent 2deabf2dcc
commit e460f88a7f
22 changed files with 627 additions and 376 deletions

8
.gitignore vendored
View File

@ -1,4 +1,6 @@
upload
data.db
target/*
logs/*
pack.yml
upload/
target/
logs/
static/

67
Cargo.lock generated
View File

@ -32,6 +32,48 @@ version = "1.0.98"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487"
[[package]]
name = "askama"
version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f75363874b771be265f4ffe307ca705ef6f3baa19011c149da8674a87f1b75c4"
dependencies = [
"askama_derive",
"itoa",
"percent-encoding",
"serde",
"serde_json",
]
[[package]]
name = "askama_derive"
version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "129397200fe83088e8a68407a8e2b1f826cf0086b21ccdb866a722c8bcd3a94f"
dependencies = [
"askama_parser",
"basic-toml",
"memchr",
"proc-macro2",
"quote",
"rustc-hash",
"serde",
"serde_derive",
"syn 2.0.100",
]
[[package]]
name = "askama_parser"
version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d6ab5630b3d5eaf232620167977f95eb51f3432fc76852328774afbd242d4358"
dependencies = [
"memchr",
"serde",
"serde_derive",
"winnow",
]
[[package]]
name = "atomic-waker"
version = "1.1.2"
@ -120,6 +162,15 @@ version = "0.22.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
[[package]]
name = "basic-toml"
version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ba62675e8242a4c4e806d12f11d136e626e6c8361d6b829310732241652a178a"
dependencies = [
"serde",
]
[[package]]
name = "bitflags"
version = "2.9.0"
@ -871,6 +922,7 @@ name = "pack"
version = "0.0.1"
dependencies = [
"anyhow",
"askama",
"axum",
"bytes",
"env_filter",
@ -1093,6 +1145,12 @@ version = "0.1.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f"
[[package]]
name = "rustc-hash"
version = "2.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d"
[[package]]
name = "rustix"
version = "1.0.5"
@ -2099,6 +2157,15 @@ version = "0.53.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486"
[[package]]
name = "winnow"
version = "0.7.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c06928c8748d81b05c9be96aad92e1b6ff01833332f281e8cfca3be4b35fc9ec"
dependencies = [
"memchr",
]
[[package]]
name = "wit-bindgen-rt"
version = "0.39.0"

View File

@ -6,6 +6,7 @@ authors = ["Kenneth Jao"]
[dependencies]
anyhow = "1.0.98"
askama = { version = "0.14.0", features = ["blocks"] }
axum = { version = "0.8.1", features = ["multipart"] }
bytes = "1.10.1"
env_filter = "0.1.3"

View File

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 15 KiB

View File

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

Before

Width:  |  Height:  |  Size: 5.7 KiB

After

Width:  |  Height:  |  Size: 5.7 KiB

View File

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 13 KiB

View File

Before

Width:  |  Height:  |  Size: 5.3 KiB

After

Width:  |  Height:  |  Size: 5.3 KiB

10
pack.yml.template Normal file
View File

@ -0,0 +1,10 @@
---
host: "127.0.0.1"
port: "3000"
domain:
db_path: "data.db"
log_path: "logs"
upload_path: "upload"
gitea_host:
client_id:
client_secret:

View File

@ -1,4 +1,4 @@
use std::{fs, path, slice::Iter};
use std::{fs, fmt, path, slice::Iter};
use bytes::Bytes;
use std::process::Command;
use rand::distr::{Alphanumeric, SampleString};
@ -17,9 +17,9 @@ use serde_json::Value;
use crate::{query, ServerState};
#[derive(Clone, Copy)]
#[derive(Debug, Clone, Copy)]
#[repr(u8)]
enum RepoFeature {
pub enum RepoFeature {
Docs = 0,
Builds = 1,
Nightly = 2,
@ -35,6 +35,32 @@ impl RepoFeature {
}
}
impl fmt::Display for RepoFeature {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Debug::fmt(self, f)
}
}
impl From<RepoFeature> for String {
fn from(value: RepoFeature) -> Self {
value.to_string().to_lowercase()
}
}
impl TryFrom<&str> for RepoFeature {
type Error = APIError;
fn try_from(value: &str) -> Result<Self> {
for feature in RepoFeature::iter() {
if feature.to_string().to_lowercase() == value.to_lowercase() {
return Ok(*feature);
}
}
Err(APIError::InvalidFeature { feature: value.to_owned() })
}
}
#[derive(Error, Debug)]
pub enum APIError {
#[error("Request error: {0}")]
@ -105,37 +131,12 @@ impl IntoResponse for APIError {
}
}
impl From<RepoFeature> for &str {
fn from(value: RepoFeature) -> Self {
match value {
RepoFeature::Docs => "docs",
RepoFeature::Builds => "builds",
RepoFeature::Nightly => "nightly",
RepoFeature::PreProd => "preprod",
}
}
}
impl TryFrom<&str> for RepoFeature {
type Error = APIError;
fn try_from(value: &str) -> Result<Self> {
match value.to_lowercase().as_str() {
"docs" => Ok(RepoFeature::Docs),
"builds" => Ok(RepoFeature::Builds),
"nightly" => Ok(RepoFeature::Nightly),
"preprod" => Ok(RepoFeature::PreProd),
other => Err(APIError::InvalidFeature { feature: other.to_owned() }),
}
}
}
fn as_feature_list(value: u64) -> FeatureList {
let mut v: Vec<String> = Vec::new();
for feature in RepoFeature::iter() {
let feat_num = 1 << (*feature as u64);
if (value & feat_num) == feat_num {
v.push(Into::<&str>::into(*feature).to_owned());
v.push(Into::<String>::into(*feature).to_owned());
}
}
v

104
src/compile.rs Normal file
View File

@ -0,0 +1,104 @@
use anyhow::{Context, Result};
use askama::Template;
use std::{fs, io, path::Path};
#[derive(Clone, Copy)]
struct WebStates<'a> {
auth: &'a str,
error: &'a str,
loading: &'a str,
repo_selected: &'a str,
repo_created: &'a str,
button_on: &'a str,
feature_on: &'a str,
confirm_on: &'a str,
}
#[derive(Template)]
#[template(
ext = "html",
path = "html/contentDefault.html",
whitespace = "suppress"
)]
struct Default<'a> {
config: crate::ServerConfig,
features: Vec<String>,
content_text: String,
state: WebStates<'a>,
}
#[derive(Template)]
#[template(ext = "html", path = "html/base.html", whitespace = "suppress")]
struct NotFound {
config: crate::ServerConfig,
content_text: String,
}
#[derive(Template)]
#[template(path = "index.css", escape = "txt", whitespace = "suppress")]
struct Css<'a> {
state: WebStates<'a>,
}
pub fn make_templates(config: &crate::ServerConfig) -> Result<()> {
let states = WebStates {
auth: "auth",
error: "error",
loading: "loading",
repo_selected: "repoSelected",
repo_created: "repoCreated",
button_on: "enabled",
feature_on: "fEnabled",
confirm_on: "enabled",
};
let default = Default {
config: config.clone(),
features: crate::api::RepoFeature::iter()
.map(|f| f.to_string())
.collect(),
content_text: "awaiting authorization...".to_owned(),
state: states,
}
.render()
.context("Unable to process 'Default' template")?;
fs::write("static/index.html", default).context("Could not write to static/index.html")?;
let not_found = NotFound {
config: config.clone(),
content_text: "404: not found...".to_owned(),
}
.render()
.context("Unable to process 'NotFound' template.")?;
fs::write("static/404.html", not_found).context("Could not write to static/404.html")?;
let css = Css { state: states }
.render()
.context("Unable to process 'CSS' template.")?;
fs::write("static/index.css", css).context("Could not write to static/index.css")?;
Ok(())
}
fn copy_dir_all(src: impl AsRef<Path>, dst: impl AsRef<Path>) -> io::Result<()> {
fs::create_dir_all(&dst)?;
for entry in fs::read_dir(src)? {
let entry = entry?;
let ty = entry.file_type()?;
if ty.is_dir() {
copy_dir_all(entry.path(), dst.as_ref().join(entry.file_name()))?;
} else {
fs::copy(entry.path(), dst.as_ref().join(entry.file_name()))?;
}
}
Ok(())
}
pub fn copy_assets() -> Result<()> {
fs::create_dir("static").context("Could not create directory 'static'.")?;
copy_dir_all("assets", "static").context("Could not copy 'assets' into 'static'.")?;
Ok(())
}

View File

@ -24,6 +24,7 @@ use tracing_appender::rolling;
use serde::Deserialize;
mod api;
mod compile;
mod util;
type SQLConn = sqlite::ConnectionThreadSafe;
@ -34,6 +35,7 @@ type SQLConn = sqlite::ConnectionThreadSafe;
struct ServerConfig {
host: String,
port: String,
domain: String,
db_path: String,
log_path: String,
upload_path: String,
@ -81,9 +83,12 @@ async fn main() -> Result<()> {
.context(format!("Failed to setup SQLite database at '{}'.", &config.db_path))?;
// Make file upload folder.
fs::create_dir_all(&config.upload_path)?;
fs::create_dir_all(&config.upload_path)
.context(format!("Unable to make directory at '{}'.", &config.upload_path))?;
let log_file = rolling::daily(&config.log_path, "");
let upload_path = config.upload_path.clone();
compile::copy_assets()?;
compile::make_templates(&config)?;
let sql: &'static sqlite::ConnectionThreadSafe = Box::leak(Box::new(sql));
let server_state = ServerState { config, sql };
@ -118,10 +123,8 @@ async fn main() -> Result<()> {
method = format!("{}", request.method()),
version = format!("{:?}", request.version()),
remote_ip = addr,
)
});
// Build routes
let api_routes = Router::new()

View File

@ -1,191 +0,0 @@
<!DOCTYPE html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="chrome=1">
<title>Pack</title>
<link rel="icon" href="assets/favicon.ico?v=2">
<link rel="stylesheet" href="assets/index.css">
<link href="https://fonts.googleapis.com/css?family=Quicksand:300,400" rel="stylesheet">
<!-- <link href="https://fonts.googleapis.com/css?family=Roboto+Slab:100,300" rel="stylesheet"> -->
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no">
<!-- <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script> -->
<!-- <script src="https://use.fontawesome.com/c8d5486cd8.js"></script> -->
</head>
<body>
<div id="themeSwitchContainer">
<input type="checkbox" id="themeSwitch">
<span></span><span></span><span></span>
</div>
<div id="package">
<img src="assets/fragile.svg">
<img src="assets/keep_dry.svg">
<img src="assets/recycle.svg">
<img src="assets/qr_code.svg">
</div>
<svg id="packageTape" viewbox="0 0 100 10">
<rect width="100" height="0.3" x="0" y="4.85" style="fill:#483320;fill-opacity:0.8" />
<rect width="100" height="10" x="0" y="0" style="fill:#111;fill-opacity:0.8" />
<polygon points="21,0.0 20,0.625 21,1.25 20,1.875 21,2.5 20,3.125 21,3.75 20,4.375 21,5.0 20,5.625 21,6.25 20,6.875 21,7.5 20,8.125 21,8.75 20,9.375 21,10.0 100,10 100,0" style="fill:#111;fill-opacity:0.5"/>
<text><textPath href="#packTape0">PACK.PACK.PACK.PACK.</textPath><textPath href="#packTape1">PACK.PACK.PACK.PACK.</textPath><textPath href="#packTape2">PACK.PACK.PACK.PACK.</textPath><textPath href="#packTape3">PACK.PACK.PACK.PACK.</textPath><textPath href="#packTape4">PACK.PACK.PACK.PACK.</textPath><textPath href="#packTape5">PACK.PACK.PACK.PACK.</textPath><textPath href="#packTape6">PACK.PACK.PACK.PACK.</textPath><textPath href="#packTape7">PACK.PACK.PACK.PACK.</textPath><textPath href="#packTape8">PACK.PACK.PACK.PACK.</textPath><textPath href="#packTape9">PACK.PACK.PACK.PACK.</textPath><textPath href="#packTape10">PACK.PACK.PACK.PACK.</textPath><textPath href="#packTape11">PACK.PACK.PACK.PACK.</textPath><textPath href="#packTape12">PACK.PACK.PACK.PACK.</textPath><textPath href="#packTape13">PACK.PACK.PACK.PACK.</textPath><textPath href="#packTape14">PACK.PACK.PACK.PACK.</textPath><textPath href="#packTape15">PACK.PACK.PACK.PACK.</textPath><textPath href="#packTape16">PACK.PACK.PACK.PACK.</textPath><textPath href="#packTape17">PACK.PACK.PACK.PACK.</textPath><textPath href="#packTape18">PACK.PACK.PACK.PACK.</textPath><textPath href="#packTape19">PACK.PACK.PACK.PACK.</textPath><textPath href="#packTape20">PACK.PACK.PACK.PACK.</textPath><textPath href="#packTape21">PACK.PACK.PACK.PACK.</textPath><textPath href="#packTape22">PACK.PACK.PACK.PACK.</textPath><textPath href="#packTape23">PACK.PACK.PACK.PACK.</textPath><textPath href="#packTape24">PACK.PACK.PACK.PACK.</textPath><textPath href="#packTape25">PACK.PACK.PACK.PACK.</textPath><textPath href="#packTape26">PACK.PACK.PACK.PACK.</textPath><textPath href="#packTape27">PACK.PACK.PACK.PACK.</textPath><textPath href="#packTape28">PACK.PACK.PACK.PACK.</textPath><textPath href="#packTape29">PACK.PACK.PACK.PACK.</textPath><textPath href="#packTape30">PACK.PACK.PACK.PACK.</textPath><textPath href="#packTape31">PACK.PACK.PACK.PACK.</textPath><textPath href="#packTape32">PACK.PACK.PACK.PACK.</textPath><textPath href="#packTape33">PACK.PACK.PACK.PACK.</textPath><textPath href="#packTape34">PACK.PACK.PACK.PACK.</textPath></text>
<path id="packTape0" fill="none" stroke="none" d="M-3.00 -0.00 l6 20"><path id="packTape1" fill="none" stroke="none" d="M-0.60 -2.00 l6 20"><path id="packTape2" fill="none" stroke="none" d="M1.80 -4.00 l6 20"><path id="packTape3" fill="none" stroke="none" d="M6.00 -0.00 l6 20"><path id="packTape4" fill="none" stroke="none" d="M8.40 -2.00 l6 20"><path id="packTape5" fill="none" stroke="none" d="M10.80 -4.00 l6 20"><path id="packTape6" fill="none" stroke="none" d="M15.00 -0.00 l6 20"><path id="packTape7" fill="none" stroke="none" d="M17.40 -2.00 l6 20"><path id="packTape8" fill="none" stroke="none" d="M19.80 -4.00 l6 20"><path id="packTape9" fill="none" stroke="none" d="M24.00 -0.00 l6 20"><path id="packTape10" fill="none" stroke="none" d="M26.40 -2.00 l6 20"><path id="packTape11" fill="none" stroke="none" d="M28.80 -4.00 l6 20"><path id="packTape12" fill="none" stroke="none" d="M33.00 -0.00 l6 20"><path id="packTape13" fill="none" stroke="none" d="M35.40 -2.00 l6 20"><path id="packTape14" fill="none" stroke="none" d="M37.80 -4.00 l6 20"><path id="packTape15" fill="none" stroke="none" d="M42.00 -0.00 l6 20"><path id="packTape16" fill="none" stroke="none" d="M44.40 -2.00 l6 20"><path id="packTape17" fill="none" stroke="none" d="M46.80 -4.00 l6 20"><path id="packTape18" fill="none" stroke="none" d="M51.00 -0.00 l6 20"><path id="packTape19" fill="none" stroke="none" d="M53.40 -2.00 l6 20"><path id="packTape20" fill="none" stroke="none" d="M55.80 -4.00 l6 20"><path id="packTape21" fill="none" stroke="none" d="M60.00 -0.00 l6 20"><path id="packTape22" fill="none" stroke="none" d="M62.40 -2.00 l6 20"><path id="packTape23" fill="none" stroke="none" d="M64.80 -4.00 l6 20"><path id="packTape24" fill="none" stroke="none" d="M69.00 -0.00 l6 20"><path id="packTape25" fill="none" stroke="none" d="M71.40 -2.00 l6 20"><path id="packTape26" fill="none" stroke="none" d="M73.80 -4.00 l6 20"><path id="packTape27" fill="none" stroke="none" d="M78.00 -0.00 l6 20"><path id="packTape28" fill="none" stroke="none" d="M80.40 -2.00 l6 20"><path id="packTape29" fill="none" stroke="none" d="M82.80 -4.00 l6 20"><path id="packTape30" fill="none" stroke="none" d="M87.00 -0.00 l6 20"><path id="packTape31" fill="none" stroke="none" d="M89.40 -2.00 l6 20"><path id="packTape32" fill="none" stroke="none" d="M91.80 -4.00 l6 20"><path id="packTape33" fill="none" stroke="none" d="M96.00 -0.00 l6 20"><path id="packTape34" fill="none" stroke="none" d="M98.40 -2.00 l6 20">
</svg>
<div id="packageLabel">
<div id="packageLabelTop">
<div>
<svg width="48" height="48" viewBox="0 0 12.7 12.7" version="1.1">
<defs id="defs2" />
<path d="m 12.323869,4.1992062 -6.2301843,2.5959093 -1e-7,0.095169 6.3500004,-2.6458336 z" />
<path d="M 12.443685,4.2444508 V 4.3735617 L 9.2686845,4.925839 V 4.7967281 Z" />
<path d="M 6.0936845,1.6003079 12.443177,4.2450847 9.2686845,4.796728 2.9191918,2.1519511 Z" />
<path d="m 9.2686845,3.8880996 0.062387,0.1201924 -3.237387,3.0585598 2e-7,-0.17699 z" />
<path d="M 9.2686845,4.7967281 V 4.925839 L 8.6378103,4.6632589 8.7123025,4.564976 Z" />
<rect width="6.8791666" height="5.8977885" x="-13.480659" y="9.4293194" transform="matrix(-0.92307692,0.3846154,0,1,0,0)" />
<rect width="6.8791666" height="5.8977885" x="-0.27767482" y="4.3512492" transform="matrix(0.92307692,0.3846154,0,1,0,0)" />
<path d="M 2.9186843,1.2431113 9.2686845,3.8880996 6.0936849,6.8898618 -0.2563155,4.2448735 Z" />
</svg>
</div>
<div>
<div>
<p><b>BYTE TRANSIT FEES PAID</b></p>
<p>64 OF 64</p>
<p>6.28 TB FIBRE OPTIC EXPRESS RATE</p>
<p>ACCEPTS TAR.GZ, ZIP</p>
</div>
<div>
<svg width="618" height="124" viewBox="0 0 618 124" version="1.1">
<path d="M 2.1999999e-6,0 H 41.200002 V 123.6 H 2.1999999e-6 Z M 46.350002,0 h 5.15 v 123.6 h -5.15 z m 10.3,0 h 5.15 v 123.6 h -5.15 z m 10.3,0 h 5.15 v 123.6 h -5.15 z m 20.6,0 H 113.3 v 15.45 h 5.15 V 30.9 h -5.15 v 15.45 h -5.15 V 30.9 H 103 V 46.35 H 97.850002 V 30.9 h -5.15 v 15.45 h 5.15 V 61.8 H 103 v 15.450002 h 5.15 V 61.8 h 5.15 v 61.8 H 87.550002 Z M 118.45,0 h 5.15 v 15.45 h -5.15 z m 10.3,0 h 5.15 v 15.45 h -5.15 z m 10.3,0 h 25.75 v 15.45 h 5.15 V 30.9 H 154.5 V 15.45 h -15.45 z m 36.05,0 h 15.45 v 30.9 h -5.15 v 30.9 h 5.15 v 15.450002 h -5.15 v 15.45 h -5.15 V 108.15 h 10.3 V 123.6 H 175.1 Z m 20.6,0 h 5.15 V 15.45 H 195.7 Z M 206,0 h 10.3 v 15.45 h -5.15 V 30.9 h 5.15 V 15.45 h 10.3 V 30.9 h -5.15 v 15.45 h 5.15 V 61.8 h 5.15 v 15.450002 h -5.15 v 15.45 h 5.15 V 108.15 H 226.6 V 123.6 H 216.3 V 92.700002 H 206 V 123.6 h -5.15 V 108.15 H 195.7 V 92.700002 h 5.15 v -15.45 H 206 V 61.8 h 5.15 v 15.450002 h 10.3 V 61.8 H 216.3 V 46.35 H 206 V 61.8 H 190.55 V 46.35 h 5.15 V 30.9 H 206 Z m 20.6,0 h 20.6 v 46.35 h -5.15 V 15.45 H 226.6 Z m 36.05,0 h 10.3 v 30.9 h -5.15 v 15.45 h 5.15 v 30.900002 h -5.15 v 15.45 h 10.3 V 108.15 h 5.15 v 15.45 h -10.3 v -15.45 h -5.15 v 15.45 h -5.15 z m 30.9,0 h 10.3 V 30.9 H 309 V 0 h 5.15 v 30.9 h 5.15 v 15.45 h -5.15 V 61.8 h 5.15 v 15.450002 h 5.15 v 15.45 h -10.3 v -15.45 h -10.3 v 15.45 H 298.7 V 108.15 H 288.4 V 77.250002 h 10.3 V 61.8 h 5.15 V 46.35 H 298.7 V 30.9 h -10.3 v 30.9 h -5.15 V 15.45 h 10.3 z m 25.75,0 h 5.15 v 15.45 h 20.6 V 30.9 H 319.3 Z m 30.9,0 h 5.15 v 15.45 h 5.15 V 0 h 15.45 v 15.45 h -10.3 V 30.9 h -10.3 v 15.45 h 5.15 v 46.350002 h 5.15 V 108.15 h 5.15 v 15.45 h -20.6 z m 46.35,0 H 412 v 15.45 h 5.15 v 30.9 H 412 V 61.8 h 5.15 v 15.450002 h 5.15 V 61.8 h 10.3 v 15.450002 h -5.15 v 15.45 h -20.6 v -15.45 h -10.3 V 61.8 h 10.3 V 46.35 h -10.3 V 30.9 h 5.15 V 15.45 h -5.15 z m 20.6,0 h 5.15 v 15.45 h -5.15 z m 20.6,0 h 25.75 v 15.45 h -5.15 V 30.9 h -5.15 v 15.45 h -5.15 V 61.8 h 5.15 V 46.35 h 5.15 V 77.250002 H 453.2 V 123.6 h -5.15 v -15.45 h -5.15 v 15.45 h -5.15 z m 30.9,0 h 5.15 v 15.45 h -5.15 z m 10.3,0 h 5.15 v 15.45 h -5.15 z m 10.3,0 H 515 V 15.45 H 494.4 V 30.9 h 25.75 V 61.8 H 515 v 15.450002 h -10.3 v 15.45 h 15.45 V 108.15 h -10.3 V 123.6 H 494.4 V 92.700002 h 5.15 V 61.8 H 494.4 V 46.35 h -5.15 z m 36.05,0 h 36.05 V 123.6 H 525.3 Z m 41.2,0 h 5.15 v 123.6 h -5.15 z m 20.6,0 h 5.15 v 123.6 h -5.15 z m 10.3,0 h 5.15 v 123.6 h -5.15 z m 15.45,0 H 618 v 123.6 h -5.15 z M 123.6,15.45 h 5.15 V 30.9 h 5.15 V 15.45 h 5.15 V 30.9 h 5.15 v 15.45 h -10.3 v 30.900002 h 15.45 v 15.45 h 5.15 V 61.8 H 144.2 V 46.35 h 25.75 V 61.8 h -5.15 v 30.900002 h 5.15 V 108.15 H 154.5 V 123.6 H 144.2 V 92.700002 h -5.15 V 123.6 H 133.9 V 108.15 H 123.6 V 92.700002 h 5.15 v -15.45 h -5.15 v 15.45 h -5.15 V 61.8 H 113.3 V 46.35 h 10.3 z m 257.5,0 h 5.15 V 30.9 h -5.15 z m 41.2,0 h 10.3 V 30.9 h -10.3 z m 41.2,0 h 5.15 V 30.9 h -5.15 z m 10.3,0 h 5.15 V 30.9 H 473.8 Z M 231.75,30.9 h 5.15 v 15.45 h -5.15 z m 41.2,0 h 5.15 v 15.45 h -5.15 z m 97.85,0 h 5.15 v 15.45 h 5.15 v 30.900002 h -5.15 V 61.8 h -5.15 z m 15.45,0 h 5.15 v 15.45 h -5.15 z m 72.1,0 h 5.15 v 15.45 h -5.15 z m 10.3,0 h 5.15 v 15.45 h 10.3 V 61.8 h 5.15 v 15.450002 h 5.15 v 15.45 h -5.15 V 123.6 h -30.9 V 77.250002 h 5.15 V 108.15 h 10.3 V 92.700002 h -5.15 v -15.45 h 5.15 V 61.8 h -5.15 V 77.250002 H 463.5 V 46.35 h 5.15 z M 103,46.35 h 5.15 V 61.8 H 103 Z m 149.35,0 h 5.15 v 77.25 h -5.15 V 108.15 H 247.2 V 92.700002 h 5.15 z m 77.25,0 h 15.45 V 61.8 h -10.3 v 15.450002 h 10.3 v 15.45 H 339.9 V 108.15 H 329.6 V 123.6 H 303.85 V 92.700002 h 10.3 V 108.15 h 10.3 V 92.700002 h 5.15 v -15.45 h -5.15 V 61.8 h 5.15 z m 61.8,0 h 5.15 V 61.8 H 391.4 Z M 278.1,61.8 h 5.15 v 15.450002 h -5.15 z m -41.2,15.450002 h 5.15 v 15.45 h -5.15 z m 128.75,0 h 10.3 v 15.45 h 5.15 v -15.45 h 5.15 v 15.45 h 5.15 V 108.15 h -5.15 v 15.45 h -10.3 V 108.15 H 370.8 V 92.700002 h -5.15 z M 103,92.700002 V 108.15 h 5.15 V 92.700002 Z m 293.55,0 h 10.3 V 108.15 h -10.3 z m 30.9,0 h 5.15 V 123.6 h -5.15 z M 118.45,108.15 h 5.15 v 15.45 h -5.15 z m 221.45,0 h 5.15 v 15.45 h -5.15 z m 66.95,0 h 10.3 v 15.45 h -10.3 z" fill-rule="evenodd" style="stroke-width:0.858333" />
</svg>
<h1 id="login"></h1>
</div>
</div>
</div>
<div id="packageLabelTitle">
<h1><b></b></h1>
</div>
<div id="packageLabelContent">
<h1>AWAITING AUTHORIZATION...</h1>
<div>
<div id="repoSelect">
<h1>REPOSITORY:</h1>
<input id="repoSelectInput" type="text" size="32" placeholder="<user>/<repository>">
<input class="enabled" id="repoSelectButton" type="submit" value="Select">
<p id="repoSelectError"></p>
</div>
<div id="repoInfo">
<h1>ACTIONS:</h1>
<div id="repoActions">
<input class="enabled" id="repoCreate" type="submit" value="Create">
<input id="repoDelete" type="submit" value="Delete">
<input id="repoSecret" type="submit" value="Regenerate Secret">
</div>
<div id="repoFeatures">
<h1>LINK:</h1>
<input id="repoLinkInput" type="text" size="32" readonly>
<input class="enabled" id="repoLinkButton" type="submit" value="Copy">
<h1>FEATURES:</h1>
<div id="featureBox">
<input class="feature" type="submit" data-tag="docs" value="Docs">
<input class="feature" type="submit" data-tag="builds" value="Builds">
<input class="feature" type="submit" data-tag="nightly" value="Nightly">
<input class="feature" type="submit" data-tag="preprod" value="PreProd">
</div>
</div>
</div>
</div>
<div id="confirmOverlay">
<div>
<div>
<h1>CONFIRMATION:</h1>
<input id="confirmInput" type="text" size="32" placeholder="<user>/<repository>">
<input class="enabled" id="confirmButtonYes" type="submit" value="Confirm">
<input class="enabled" id="confirmButtonNo" type="submit" value="Cancel">
<p>This will (irreversibly) delete all associated files! Please type in the full repository name to confirm.</p>
</div>
</div>
</div>
</div>
<div id="packageLabelBot">
<svg width="1596" height="432" viewBox="0 0 1596 432" version="1.1">
<path d="M 0,432 H 12 V 0 H 0 Z" />
<path d="m 18,432 h 6 V 0 h -6 z" />
<path d="m 36,432 h 6 V 0 h -6 z" />
<path d="m 66,432 h 6 V 0 h -6 z" />
<path d="M 84,432 H 96 V 0 H 84 Z" />
<path d="m 120,432 h 6 V 0 h -6 z" />
<path d="m 132,432 h 6 V 0 h -6 z" />
<path d="m 150,432 h 24 V 0 h -24 z" />
<path d="m 180,432 h 6 V 0 h -6 z" />
<path d="m 198,432 h 6 V 0 h -6 z" />
<path d="m 216,432 h 24 V 0 h -24 z" />
<path d="m 246,432 h 6 V 0 h -6 z" />
<path d="m 264,432 h 6 V 0 h -6 z" />
<path d="m 276,432 h 6 V 0 h -6 z" />
<path d="m 294,432 h 24 V 0 h -24 z" />
<path d="m 330,432 h 6 V 0 h -6 z" />
<path d="m 342,432 h 24 V 0 h -24 z" />
<path d="m 378,432 h 6 V 0 h -6 z" />
<path d="m 396,432 h 18 V 0 h -18 z" />
<path d="m 426,432 h 6 V 0 h -6 z" />
<path d="m 444,432 h 12 V 0 h -12 z" />
<path d="m 462,432 h 6 V 0 h -6 z" />
<path d="m 474,432 h 18 V 0 h -18 z" />
<path d="m 504,432 h 12 V 0 h -12 z" />
<path d="m 528,432 h 6 V 0 h -6 z" />
<path d="m 540,432 h 18 V 0 h -18 z" />
<path d="m 570,432 h 12 V 0 h -12 z" />
<path d="m 594,432 h 6 V 0 h -6 z" />
<path d="m 606,432 h 6 V 0 h -6 z" />
<path d="m 624,432 h 24 V 0 h -24 z" />
<path d="m 660,432 h 6 V 0 h -6 z" />
<path d="m 678,432 h 6 V 0 h -6 z" />
<path d="m 690,432 h 12 V 0 h -12 z" />
<path d="m 726,432 h 6 V 0 h -6 z" />
<path d="m 756,432 h 6 V 0 h -6 z" />
<path d="m 768,432 h 12 V 0 h -12 z" />
<path d="m 792,432 h 12 V 0 h -12 z" />
<path d="m 828,432 h 6 V 0 h -6 z" />
<path d="m 846,432 h 6 V 0 h -6 z" />
<path d="m 858,432 h 6 V 0 h -6 z" />
<path d="m 876,432 h 12 V 0 h -12 z" />
<path d="m 900,432 h 18 V 0 h -18 z" />
<path d="m 924,432 h 12 V 0 h -12 z" />
<path d="m 960,432 h 6 V 0 h -6 z" />
<path d="m 978,432 h 6 V 0 h -6 z" />
<path d="m 990,432 h 6 V 0 h -6 z" />
<path d="m 1020,432 h 12 V 0 h -12 z" />
<path d="m 1044,432 h 6 V 0 h -6 z" />
<path d="m 1056,432 h 6 V 0 h -6 z" />
<path d="m 1074,432 h 6 V 0 h -6 z" />
<path d="m 1086,432 h 12 V 0 h -12 z" />
<path d="m 1122,432 h 6 V 0 h -6 z" />
<path d="m 1146,432 h 24 V 0 h -24 z" />
<path d="m 1176,432 h 6 V 0 h -6 z" />
<path d="m 1188,432 h 6 V 0 h -6 z" />
<path d="m 1206,432 h 12 V 0 h -12 z" />
<path d="m 1230,432 h 18 V 0 h -18 z" />
<path d="m 1254,432 h 24 V 0 h -24 z" />
<path d="m 1284,432 h 18 V 0 h -18 z" />
<path d="m 1308,432 h 6 V 0 h -6 z" />
<path d="m 1320,432 h 6 V 0 h -6 z" />
<path d="m 1332,432 h 12 V 0 h -12 z" />
<path d="m 1356,432 h 6 V 0 h -6 z" />
<path d="m 1386,432 h 6 V 0 h -6 z" />
<path d="m 1398,432 h 18 V 0 h -18 z" />
<path d="m 1428,432 h 12 V 0 h -12 z" />
<path d="m 1452,432 h 6 V 0 h -6 z" />
<path d="m 1470,432 h 6 V 0 h -6 z" />
<path d="m 1488,432 h 24 V 0 h -24 z" />
<path d="m 1518,432 h 12 V 0 h -12 z" />
<path d="m 1548,432 h 18 V 0 h -18 z" />
<path d="m 1572,432 h 6 V 0 h -6 z" />
<path d="m 1584,432 h 12 V 0 h -12 z" />
</svg>
<a href="/">https://pack.kjao.me/</a>
</div>
</div>
</body>
<script src="assets/index.js"></script>
</html>

42
templates/html/base.html Normal file
View File

@ -0,0 +1,42 @@
<!DOCTYPE html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="chrome=1">
<title>Pack</title>
<link rel="icon" href="assets/favicon.ico?v=2">
<link rel="stylesheet" href="assets/index.css">
<link href="https://fonts.googleapis.com/css?family=Quicksand:300,400" rel="stylesheet">
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no">
</head>
<body>
<div id="themeSwitchContainer">
<input type="checkbox" id="themeSwitch">
<span></span><span></span><span></span>
</div>
<div id="package">
<img src="assets/fragile.svg">
<img src="assets/keep_dry.svg">
<img src="assets/recycle.svg">
<img src="assets/qr_code.svg">
</div>
{% include "svgTape.svg" %}
<div id="packageLabel">
<div id="packageLabelTop">{% include "labelTop.html" %}</div>
<div id="packageLabelTitle">
<h1><b></b></h1>
</div>
<div id="packageLabelContent">
<h1>{{ content_text | upper }}</h1>
{% block content %}{% endblock %}
</div>
<div id="packageLabelBot">
{% include "labelBot.svg" %}
<a href="/">{{ config.domain }}</a>
</div>
</div>
</body>
<script>
{% include "js/base.js" %}
{% block script %}{% endblock %}
</script>
</html>

View File

@ -0,0 +1,47 @@
{% extends "base.html" %}
{% block content %}
<div>
<div id="repoSelect">
<h1>REPOSITORY:</h1>
<input id="repoSelectInput" type="text" size="32" placeholder="<user>/<repository>">
<input class="enabled" id="repoSelectButton" type="submit" value="Select">
<p id="repoSelectError"></p>
</div>
<div id="repoInfo">
<h1>ACTIONS:</h1>
<div id="repoActions">
<input class="enabled" id="repoCreate" type="submit" value="Create">
<input id="repoDelete" type="submit" value="Delete">
<input id="repoSecret" type="submit" value="Regenerate Secret">
</div>
<div id="repoFeatures">
<h1>LINK:</h1>
<input id="repoLinkInput" type="text" size="32" readonly>
<input class="enabled" id="repoLinkButton" type="submit" value="Copy">
<h1>FEATURES:</h1>
<div id="featureBox">
{% for feature in features %}
<input class="feature" type="submit" data-tag="{{ feature | lower }}" value="{{ feature }}">
{% endfor %}
</div>
</div>
</div>
</div>
<div id="confirmOverlay">
<div>
<div>
<h1>CONFIRMATION:</h1>
<input id="confirmInput" type="text" size="32" placeholder="<user>/<repository>">
<input class="enabled" id="confirmButtonYes" type="submit" value="Confirm">
<input class="enabled" id="confirmButtonNo" type="submit" value="Cancel">
<p>This will (irreversibly) delete all associated files! Please type in the full repository name to confirm.</p>
</div>
</div>
</div>
{% endblock %}
{% block script %}
{% include "js/token.js" %}
{% include "js/default.js" %}
{% endblock %}

View File

@ -0,0 +1,75 @@
<svg width="1596" height="432" viewBox="0 0 1596 432" version="1.1">
<path d="M 0,432 H 12 V 0 H 0 Z" />
<path d="m 18,432 h 6 V 0 h -6 z" />
<path d="m 36,432 h 6 V 0 h -6 z" />
<path d="m 66,432 h 6 V 0 h -6 z" />
<path d="M 84,432 H 96 V 0 H 84 Z" />
<path d="m 120,432 h 6 V 0 h -6 z" />
<path d="m 132,432 h 6 V 0 h -6 z" />
<path d="m 150,432 h 24 V 0 h -24 z" />
<path d="m 180,432 h 6 V 0 h -6 z" />
<path d="m 198,432 h 6 V 0 h -6 z" />
<path d="m 216,432 h 24 V 0 h -24 z" />
<path d="m 246,432 h 6 V 0 h -6 z" />
<path d="m 264,432 h 6 V 0 h -6 z" />
<path d="m 276,432 h 6 V 0 h -6 z" />
<path d="m 294,432 h 24 V 0 h -24 z" />
<path d="m 330,432 h 6 V 0 h -6 z" />
<path d="m 342,432 h 24 V 0 h -24 z" />
<path d="m 378,432 h 6 V 0 h -6 z" />
<path d="m 396,432 h 18 V 0 h -18 z" />
<path d="m 426,432 h 6 V 0 h -6 z" />
<path d="m 444,432 h 12 V 0 h -12 z" />
<path d="m 462,432 h 6 V 0 h -6 z" />
<path d="m 474,432 h 18 V 0 h -18 z" />
<path d="m 504,432 h 12 V 0 h -12 z" />
<path d="m 528,432 h 6 V 0 h -6 z" />
<path d="m 540,432 h 18 V 0 h -18 z" />
<path d="m 570,432 h 12 V 0 h -12 z" />
<path d="m 594,432 h 6 V 0 h -6 z" />
<path d="m 606,432 h 6 V 0 h -6 z" />
<path d="m 624,432 h 24 V 0 h -24 z" />
<path d="m 660,432 h 6 V 0 h -6 z" />
<path d="m 678,432 h 6 V 0 h -6 z" />
<path d="m 690,432 h 12 V 0 h -12 z" />
<path d="m 726,432 h 6 V 0 h -6 z" />
<path d="m 756,432 h 6 V 0 h -6 z" />
<path d="m 768,432 h 12 V 0 h -12 z" />
<path d="m 792,432 h 12 V 0 h -12 z" />
<path d="m 828,432 h 6 V 0 h -6 z" />
<path d="m 846,432 h 6 V 0 h -6 z" />
<path d="m 858,432 h 6 V 0 h -6 z" />
<path d="m 876,432 h 12 V 0 h -12 z" />
<path d="m 900,432 h 18 V 0 h -18 z" />
<path d="m 924,432 h 12 V 0 h -12 z" />
<path d="m 960,432 h 6 V 0 h -6 z" />
<path d="m 978,432 h 6 V 0 h -6 z" />
<path d="m 990,432 h 6 V 0 h -6 z" />
<path d="m 1020,432 h 12 V 0 h -12 z" />
<path d="m 1044,432 h 6 V 0 h -6 z" />
<path d="m 1056,432 h 6 V 0 h -6 z" />
<path d="m 1074,432 h 6 V 0 h -6 z" />
<path d="m 1086,432 h 12 V 0 h -12 z" />
<path d="m 1122,432 h 6 V 0 h -6 z" />
<path d="m 1146,432 h 24 V 0 h -24 z" />
<path d="m 1176,432 h 6 V 0 h -6 z" />
<path d="m 1188,432 h 6 V 0 h -6 z" />
<path d="m 1206,432 h 12 V 0 h -12 z" />
<path d="m 1230,432 h 18 V 0 h -18 z" />
<path d="m 1254,432 h 24 V 0 h -24 z" />
<path d="m 1284,432 h 18 V 0 h -18 z" />
<path d="m 1308,432 h 6 V 0 h -6 z" />
<path d="m 1320,432 h 6 V 0 h -6 z" />
<path d="m 1332,432 h 12 V 0 h -12 z" />
<path d="m 1356,432 h 6 V 0 h -6 z" />
<path d="m 1386,432 h 6 V 0 h -6 z" />
<path d="m 1398,432 h 18 V 0 h -18 z" />
<path d="m 1428,432 h 12 V 0 h -12 z" />
<path d="m 1452,432 h 6 V 0 h -6 z" />
<path d="m 1470,432 h 6 V 0 h -6 z" />
<path d="m 1488,432 h 24 V 0 h -24 z" />
<path d="m 1518,432 h 12 V 0 h -12 z" />
<path d="m 1548,432 h 18 V 0 h -18 z" />
<path d="m 1572,432 h 6 V 0 h -6 z" />
<path d="m 1584,432 h 12 V 0 h -12 z" />
</svg>

After

Width:  |  Height:  |  Size: 3.2 KiB

View File

@ -0,0 +1,27 @@
<div>
<svg width="48" height="48" viewBox="0 0 12.7 12.7" version="1.1">
<defs id="defs2" />
<path d="m 12.323869,4.1992062 -6.2301843,2.5959093 -1e-7,0.095169 6.3500004,-2.6458336 z" />
<path d="M 12.443685,4.2444508 V 4.3735617 L 9.2686845,4.925839 V 4.7967281 Z" />
<path d="M 6.0936845,1.6003079 12.443177,4.2450847 9.2686845,4.796728 2.9191918,2.1519511 Z" />
<path d="m 9.2686845,3.8880996 0.062387,0.1201924 -3.237387,3.0585598 2e-7,-0.17699 z" />
<path d="M 9.2686845,4.7967281 V 4.925839 L 8.6378103,4.6632589 8.7123025,4.564976 Z" />
<rect width="6.8791666" height="5.8977885" x="-13.480659" y="9.4293194" transform="matrix(-0.92307692,0.3846154,0,1,0,0)" />
<rect width="6.8791666" height="5.8977885" x="-0.27767482" y="4.3512492" transform="matrix(0.92307692,0.3846154,0,1,0,0)" />
<path d="M 2.9186843,1.2431113 9.2686845,3.8880996 6.0936849,6.8898618 -0.2563155,4.2448735 Z" />
</svg>
</div>
<div>
<div>
<p><b>BYTE TRANSIT FEES PAID</b></p>
<p>64 OF 64</p>
<p>6.28 TB FIBRE OPTIC EXPRESS RATE</p>
<p>ACCEPTS TAR.GZ, ZIP</p>
</div>
<div>
<svg width="618" height="124" viewBox="0 0 618 124" version="1.1">
<path d="M 2.1999999e-6,0 H 41.200002 V 123.6 H 2.1999999e-6 Z M 46.350002,0 h 5.15 v 123.6 h -5.15 z m 10.3,0 h 5.15 v 123.6 h -5.15 z m 10.3,0 h 5.15 v 123.6 h -5.15 z m 20.6,0 H 113.3 v 15.45 h 5.15 V 30.9 h -5.15 v 15.45 h -5.15 V 30.9 H 103 V 46.35 H 97.850002 V 30.9 h -5.15 v 15.45 h 5.15 V 61.8 H 103 v 15.450002 h 5.15 V 61.8 h 5.15 v 61.8 H 87.550002 Z M 118.45,0 h 5.15 v 15.45 h -5.15 z m 10.3,0 h 5.15 v 15.45 h -5.15 z m 10.3,0 h 25.75 v 15.45 h 5.15 V 30.9 H 154.5 V 15.45 h -15.45 z m 36.05,0 h 15.45 v 30.9 h -5.15 v 30.9 h 5.15 v 15.450002 h -5.15 v 15.45 h -5.15 V 108.15 h 10.3 V 123.6 H 175.1 Z m 20.6,0 h 5.15 V 15.45 H 195.7 Z M 206,0 h 10.3 v 15.45 h -5.15 V 30.9 h 5.15 V 15.45 h 10.3 V 30.9 h -5.15 v 15.45 h 5.15 V 61.8 h 5.15 v 15.450002 h -5.15 v 15.45 h 5.15 V 108.15 H 226.6 V 123.6 H 216.3 V 92.700002 H 206 V 123.6 h -5.15 V 108.15 H 195.7 V 92.700002 h 5.15 v -15.45 H 206 V 61.8 h 5.15 v 15.450002 h 10.3 V 61.8 H 216.3 V 46.35 H 206 V 61.8 H 190.55 V 46.35 h 5.15 V 30.9 H 206 Z m 20.6,0 h 20.6 v 46.35 h -5.15 V 15.45 H 226.6 Z m 36.05,0 h 10.3 v 30.9 h -5.15 v 15.45 h 5.15 v 30.900002 h -5.15 v 15.45 h 10.3 V 108.15 h 5.15 v 15.45 h -10.3 v -15.45 h -5.15 v 15.45 h -5.15 z m 30.9,0 h 10.3 V 30.9 H 309 V 0 h 5.15 v 30.9 h 5.15 v 15.45 h -5.15 V 61.8 h 5.15 v 15.450002 h 5.15 v 15.45 h -10.3 v -15.45 h -10.3 v 15.45 H 298.7 V 108.15 H 288.4 V 77.250002 h 10.3 V 61.8 h 5.15 V 46.35 H 298.7 V 30.9 h -10.3 v 30.9 h -5.15 V 15.45 h 10.3 z m 25.75,0 h 5.15 v 15.45 h 20.6 V 30.9 H 319.3 Z m 30.9,0 h 5.15 v 15.45 h 5.15 V 0 h 15.45 v 15.45 h -10.3 V 30.9 h -10.3 v 15.45 h 5.15 v 46.350002 h 5.15 V 108.15 h 5.15 v 15.45 h -20.6 z m 46.35,0 H 412 v 15.45 h 5.15 v 30.9 H 412 V 61.8 h 5.15 v 15.450002 h 5.15 V 61.8 h 10.3 v 15.450002 h -5.15 v 15.45 h -20.6 v -15.45 h -10.3 V 61.8 h 10.3 V 46.35 h -10.3 V 30.9 h 5.15 V 15.45 h -5.15 z m 20.6,0 h 5.15 v 15.45 h -5.15 z m 20.6,0 h 25.75 v 15.45 h -5.15 V 30.9 h -5.15 v 15.45 h -5.15 V 61.8 h 5.15 V 46.35 h 5.15 V 77.250002 H 453.2 V 123.6 h -5.15 v -15.45 h -5.15 v 15.45 h -5.15 z m 30.9,0 h 5.15 v 15.45 h -5.15 z m 10.3,0 h 5.15 v 15.45 h -5.15 z m 10.3,0 H 515 V 15.45 H 494.4 V 30.9 h 25.75 V 61.8 H 515 v 15.450002 h -10.3 v 15.45 h 15.45 V 108.15 h -10.3 V 123.6 H 494.4 V 92.700002 h 5.15 V 61.8 H 494.4 V 46.35 h -5.15 z m 36.05,0 h 36.05 V 123.6 H 525.3 Z m 41.2,0 h 5.15 v 123.6 h -5.15 z m 20.6,0 h 5.15 v 123.6 h -5.15 z m 10.3,0 h 5.15 v 123.6 h -5.15 z m 15.45,0 H 618 v 123.6 h -5.15 z M 123.6,15.45 h 5.15 V 30.9 h 5.15 V 15.45 h 5.15 V 30.9 h 5.15 v 15.45 h -10.3 v 30.900002 h 15.45 v 15.45 h 5.15 V 61.8 H 144.2 V 46.35 h 25.75 V 61.8 h -5.15 v 30.900002 h 5.15 V 108.15 H 154.5 V 123.6 H 144.2 V 92.700002 h -5.15 V 123.6 H 133.9 V 108.15 H 123.6 V 92.700002 h 5.15 v -15.45 h -5.15 v 15.45 h -5.15 V 61.8 H 113.3 V 46.35 h 10.3 z m 257.5,0 h 5.15 V 30.9 h -5.15 z m 41.2,0 h 10.3 V 30.9 h -10.3 z m 41.2,0 h 5.15 V 30.9 h -5.15 z m 10.3,0 h 5.15 V 30.9 H 473.8 Z M 231.75,30.9 h 5.15 v 15.45 h -5.15 z m 41.2,0 h 5.15 v 15.45 h -5.15 z m 97.85,0 h 5.15 v 15.45 h 5.15 v 30.900002 h -5.15 V 61.8 h -5.15 z m 15.45,0 h 5.15 v 15.45 h -5.15 z m 72.1,0 h 5.15 v 15.45 h -5.15 z m 10.3,0 h 5.15 v 15.45 h 10.3 V 61.8 h 5.15 v 15.450002 h 5.15 v 15.45 h -5.15 V 123.6 h -30.9 V 77.250002 h 5.15 V 108.15 h 10.3 V 92.700002 h -5.15 v -15.45 h 5.15 V 61.8 h -5.15 V 77.250002 H 463.5 V 46.35 h 5.15 z M 103,46.35 h 5.15 V 61.8 H 103 Z m 149.35,0 h 5.15 v 77.25 h -5.15 V 108.15 H 247.2 V 92.700002 h 5.15 z m 77.25,0 h 15.45 V 61.8 h -10.3 v 15.450002 h 10.3 v 15.45 H 339.9 V 108.15 H 329.6 V 123.6 H 303.85 V 92.700002 h 10.3 V 108.15 h 10.3 V 92.700002 h 5.15 v -15.45 h -5.15 V 61.8 h 5.15 z m 61.8,0 h 5.15 V 61.8 H 391.4 Z M 278.1,61.8 h 5.15 v 15.450002 h -5.15 z m -41.2,15.450002 h 5.15 v 15.45 h -5.15 z m 128.75,0 h 10.3 v 15.45 h 5.15 v -15.45 h 5.15 v 15.45 h 5.15 V 108.15 h -5.15 v 15.45 h -10.3 V 108.15 H 370.8 V 92.700002 h -5.15 z M 103,92.700002 V 108.15 h 5.15 V 92.700002 Z m 293.55,0 h 10.3 V 108.15 h -10.3 z m 30.9,0 h 5.15 V 123.6 h -5.15 z M 118.45,108.15 h 5.15 v 15.45 h -5.15 z m 221.45,0 h 5.15 v 15.45 h -5.15 z m 66.95,0 h 10.3 v 15.45 h -10.3 z" fill-rule="evenodd" style="stroke-width:0.858333" />
</svg>
<h1 id="login"></h1>
</div>
</div>

View File

@ -0,0 +1,78 @@
<svg id="packageTape" viewbox="0 0 100 10">
<rect width="100" height="0.3" x="0" y="4.85" style="fill:#483320;fill-opacity:0.8" />
<rect width="100" height="10" x="0" y="0" style="fill:#111;fill-opacity:0.8" />
<polygon points="21,0.0 20,0.625 21,1.25 20,1.875 21,2.5 20,3.125 21,3.75 20,4.375 21,5.0 20,5.625 21,6.25 20,6.875 21,7.5 20,8.125 21,8.75 20,9.375 21,10.0 100,10 100,0" style="fill:#111;fill-opacity:0.5"/>
<text>
<textPath href="#packTape0">PACK.PACK.PACK.PACK.</textPath>
<textPath href="#packTape1">PACK.PACK.PACK.PACK.</textPath>
<textPath href="#packTape2">PACK.PACK.PACK.PACK.</textPath>
<textPath href="#packTape3">PACK.PACK.PACK.PACK.</textPath>
<textPath href="#packTape4">PACK.PACK.PACK.PACK.</textPath>
<textPath href="#packTape5">PACK.PACK.PACK.PACK.</textPath>
<textPath href="#packTape6">PACK.PACK.PACK.PACK.</textPath>
<textPath href="#packTape7">PACK.PACK.PACK.PACK.</textPath>
<textPath href="#packTape8">PACK.PACK.PACK.PACK.</textPath>
<textPath href="#packTape9">PACK.PACK.PACK.PACK.</textPath>
<textPath href="#packTape10">PACK.PACK.PACK.PACK.</textPath>
<textPath href="#packTape11">PACK.PACK.PACK.PACK.</textPath>
<textPath href="#packTape12">PACK.PACK.PACK.PACK.</textPath>
<textPath href="#packTape13">PACK.PACK.PACK.PACK.</textPath>
<textPath href="#packTape14">PACK.PACK.PACK.PACK.</textPath>
<textPath href="#packTape15">PACK.PACK.PACK.PACK.</textPath>
<textPath href="#packTape16">PACK.PACK.PACK.PACK.</textPath>
<textPath href="#packTape17">PACK.PACK.PACK.PACK.</textPath>
<textPath href="#packTape18">PACK.PACK.PACK.PACK.</textPath>
<textPath href="#packTape19">PACK.PACK.PACK.PACK.</textPath>
<textPath href="#packTape20">PACK.PACK.PACK.PACK.</textPath>
<textPath href="#packTape21">PACK.PACK.PACK.PACK.</textPath>
<textPath href="#packTape22">PACK.PACK.PACK.PACK.</textPath>
<textPath href="#packTape23">PACK.PACK.PACK.PACK.</textPath>
<textPath href="#packTape24">PACK.PACK.PACK.PACK.</textPath>
<textPath href="#packTape25">PACK.PACK.PACK.PACK.</textPath>
<textPath href="#packTape26">PACK.PACK.PACK.PACK.</textPath>
<textPath href="#packTape27">PACK.PACK.PACK.PACK.</textPath>
<textPath href="#packTape28">PACK.PACK.PACK.PACK.</textPath>
<textPath href="#packTape29">PACK.PACK.PACK.PACK.</textPath>
<textPath href="#packTape30">PACK.PACK.PACK.PACK.</textPath>
<textPath href="#packTape31">PACK.PACK.PACK.PACK.</textPath>
<textPath href="#packTape32">PACK.PACK.PACK.PACK.</textPath>
<textPath href="#packTape33">PACK.PACK.PACK.PACK.</textPath>
<textPath href="#packTape34">PACK.PACK.PACK.PACK.</textPath>
</text>
<path id="packTape0" fill="none" stroke="none" d="M-3.00 -0.00 l6 20"/>
<path id="packTape1" fill="none" stroke="none" d="M-0.60 -2.00 l6 20"/>
<path id="packTape2" fill="none" stroke="none" d="M1.80 -4.00 l6 20"/>
<path id="packTape3" fill="none" stroke="none" d="M6.00 -0.00 l6 20"/>
<path id="packTape4" fill="none" stroke="none" d="M8.40 -2.00 l6 20"/>
<path id="packTape5" fill="none" stroke="none" d="M10.80 -4.00 l6 20"/>
<path id="packTape6" fill="none" stroke="none" d="M15.00 -0.00 l6 20"/>
<path id="packTape7" fill="none" stroke="none" d="M17.40 -2.00 l6 20"/>
<path id="packTape8" fill="none" stroke="none" d="M19.80 -4.00 l6 20"/>
<path id="packTape9" fill="none" stroke="none" d="M24.00 -0.00 l6 20"/>
<path id="packTape10" fill="none" stroke="none" d="M26.40 -2.00 l6 20"/>
<path id="packTape11" fill="none" stroke="none" d="M28.80 -4.00 l6 20"/>
<path id="packTape12" fill="none" stroke="none" d="M33.00 -0.00 l6 20"/>
<path id="packTape13" fill="none" stroke="none" d="M35.40 -2.00 l6 20"/>
<path id="packTape14" fill="none" stroke="none" d="M37.80 -4.00 l6 20"/>
<path id="packTape15" fill="none" stroke="none" d="M42.00 -0.00 l6 20"/>
<path id="packTape16" fill="none" stroke="none" d="M44.40 -2.00 l6 20"/>
<path id="packTape17" fill="none" stroke="none" d="M46.80 -4.00 l6 20"/>
<path id="packTape18" fill="none" stroke="none" d="M51.00 -0.00 l6 20"/>
<path id="packTape19" fill="none" stroke="none" d="M53.40 -2.00 l6 20"/>
<path id="packTape20" fill="none" stroke="none" d="M55.80 -4.00 l6 20"/>
<path id="packTape21" fill="none" stroke="none" d="M60.00 -0.00 l6 20"/>
<path id="packTape22" fill="none" stroke="none" d="M62.40 -2.00 l6 20"/>
<path id="packTape23" fill="none" stroke="none" d="M64.80 -4.00 l6 20"/>
<path id="packTape24" fill="none" stroke="none" d="M69.00 -0.00 l6 20"/>
<path id="packTape25" fill="none" stroke="none" d="M71.40 -2.00 l6 20"/>
<path id="packTape26" fill="none" stroke="none" d="M73.80 -4.00 l6 20"/>
<path id="packTape27" fill="none" stroke="none" d="M78.00 -0.00 l6 20"/>
<path id="packTape28" fill="none" stroke="none" d="M80.40 -2.00 l6 20"/>
<path id="packTape29" fill="none" stroke="none" d="M82.80 -4.00 l6 20"/>
<path id="packTape30" fill="none" stroke="none" d="M87.00 -0.00 l6 20"/>
<path id="packTape31" fill="none" stroke="none" d="M89.40 -2.00 l6 20"/>
<path id="packTape32" fill="none" stroke="none" d="M91.80 -4.00 l6 20"/>
<path id="packTape33" fill="none" stroke="none" d="M96.00 -0.00 l6 20"/>
<path id="packTape34" fill="none" stroke="none" d="M98.40 -2.00 l6 20"/>
</svg>

After

Width:  |  Height:  |  Size: 5.4 KiB

View File

@ -438,7 +438,7 @@ body {
font-family: 'Courier';
}
input.error {
input.{{ state.error }} {
outline: 2px solid red !important;
}
@ -454,7 +454,7 @@ body {
pointer-events: none;
}
input[type=submit].enabled {
input[type=submit].{{ state.button_on }} {
color: var(--c-text);
border-style: solid;
pointer-events: auto;
@ -468,7 +468,7 @@ body {
outline: none;
}
input[type=submit].loading {
input[type=submit].{{ state.loading }} {
border: 1px solid transparent;
background: linear-gradient(var(--c-label), var(--c-label)) padding-box, conic-gradient(
from var(--angle),
@ -537,19 +537,6 @@ body {
font-weight: 800;
pointer-events: auto;
}
/* .feature { */
/* border: 1px solid var(--c-lines); */
/* padding: 2%; */
/* margin-right: 2%; */
/* font-size: 150%; */
/* cursor: pointer; */
/* user-select: none; */
/* transition: background-color 0.15s ease-in-out; */
/* } */
/* .feature:hover { */
/* background-color: var(--c-login-hover); */
/* } */
/* Feature states. */
.feature {
@ -557,7 +544,7 @@ body {
border-style: dashed;
}
.feature.fEnabled {
.feature.{{ state.feature_on }} {
color: var(--c-text);
border-style: solid;
@ -611,7 +598,7 @@ body {
opacity: 0;
}
#confirmOverlay.enabled {
#confirmOverlay.{{ state.confirm_on }} {
pointer-events: auto;
top: 0;
opacity: 1;
@ -622,7 +609,7 @@ body {
opacity: 0;
}
#repoInfo.repoSelected, #repoFeatures.repoCreated {
#repoInfo.{{ state.repo_selected }}, #repoFeatures.{{ state.repo_created }} {
opacity: 1
}
}
@ -674,7 +661,7 @@ body { /* Default no authentication */
}
}
body.auth {
body.{{ state.auth }} {
#packageLabelTitle h1::before {
content: "PACKAGE INFO"
}

63
templates/js/base.js Normal file
View File

@ -0,0 +1,63 @@
const CONFIG = {
client_id: "{{ config.client_id }}",
redirect_uri: "{{ config.domain }}",
authorization_endpoint: "{{ config.gitea_host }}/login/oauth/authorize",
token_endpoint: "{{ config.gitea_host }}/login/oauth/access_token",
requested_scopes: "read:repository,write:repository"
};
var G_AUTH = window.localStorage.getItem("token") !== null;
document.on = document.addEventListener;
function sugar(obj) {
obj.on = obj.addEventListener;
obj.addClass = (x) => obj.classList.add(x);
obj.delClass = (x) => obj.classList.remove(x);
obj.hasClass = (x) => obj.classList.contains(x);
obj.setClass = (x, y) => obj.classList.toggle(x, y);
return obj;
}
function get(s) {
let x = [...document.querySelectorAll(s)].map(sugar);
return (x.length === 1) ? x[0] : x;
}
// Check if object is empty.
function isEmpty(obj) {
for (const prop in obj) {
if (Object.hasOwn(obj, prop)) {
return false;
}
}
return true;
}
// Returns error and resolves promise if necessary.
function getErr(f) {
return (err) => {
if (err instanceof Promise) {
return err.then(f);
} else {
return err;
}
}
}
get("#login").on("click", async (e) => {
e.preventDefault();
if (G_AUTH) {
window.localStorage.clear();
window.location = "/";
} else {
// Build the authorization URL
let url = CONFIG.authorization_endpoint
+ "?response_type=code"
+ "&client_id="+encodeURIComponent(CONFIG.client_id)
+ "&scope="+encodeURIComponent(CONFIG.requested_scopes)
+ "&redirect_uri="+encodeURIComponent(CONFIG.redirect_uri);
// Redirect to the authorization server
window.location = url;
}
});

View File

@ -1,20 +1,12 @@
const CONFIG = {
client_id: "3d463405-d098-4038-8b25-a44ca5b9ab9c",
redirect_uri: "http://127.0.0.1:3000/",
authorization_endpoint: "https://git.kjao.me/login/oauth/authorize",
token_endpoint: "https://git.kjao.me/login/oauth/access_token",
requested_scopes: "read:repository,write:repository"
};
const STATES = { // Either the non-d
auth: "auth",
error: "error",
loading: "loading",
repoSelected: "repoSelected",
repoCreated: "repoCreated",
buttonOn: "enabled",
featureOn: "fEnabled",
confirmOn: "enabled",
auth: "{{ state.auth }}",
error: "{{ state.error }}",
loading: "{{ state.loading }}",
repoSelected: "{{ state.repo_selected }}",
repoCreated: "{{ state.repo_created }}",
buttonOn: "{{ state.button_on }}",
featureOn: "{{ state.feature_on }}",
confirmOn: "{{ state.confirm_on }}",
}
var G_REPO_VALUE = "",
@ -23,108 +15,15 @@ var G_REPO_VALUE = "",
// UTILITY //
document.on = document.addEventListener;
function sugar(obj) {
obj.on = obj.addEventListener;
obj.addClass = (x) => obj.classList.add(x);
obj.delClass = (x) => obj.classList.remove(x);
obj.hasClass = (x) => obj.classList.contains(x);
obj.setClass = (x, y) => obj.classList.toggle(x, y);
return obj;
}
function get(s) {
let x = [...document.querySelectorAll(s)].map(sugar);
return (x.length === 1) ? x[0] : x;
}
// Check if object is empty.
function isEmpty(obj) {
for (const prop in obj) {
if (Object.hasOwn(obj, prop)) {
return false;
}
}
return true;
}
// Returns error and resolves promise if necessary.
function getErr(f) {
return (err) => {
if (err instanceof Promise) {
return err.then(f);
} else {
return err;
}
}
}
// Parse a query string into an object
function parseQueryString(string) {
if(string == "") { return {}; }
var segments = string.split("&").map(s => s.split("=") );
var queryString = {};
segments.forEach(s => G_QUERYString[s[0]] = s[1]);
segments.forEach(s => queryString[s[0]] = s[1]);
return queryString;
}
// Fetch function for applet use case.
async function jfetch(url, method, obj={}) {
let request = {
headers: {
"Content-Type": "application/json",
"Authorization": window.localStorage.getItem("token"),
},
method: method,
};
if (!isEmpty(obj)) request["body"] = JSON.stringify(obj);
return fetch(url, request)
.then((response) => {
let contentType = response.headers.get("Content-Type");
let json;
if (contentType && contentType.indexOf("application/json" !== -1)) {
json = response.json();
} else { // Reprocess non-json into json.
json = response.text().then((text) => {
return { status: response.status, "message": text };
});
}
if (!response.ok) { throw json; }
return json;
});
}
// OAUTH //
async function getToken() {
let response;
if (G_QUERY.code) {
response = await jfetch("/api/token", "POST", { code: G_QUERY.code });
} else {
response = await jfetch("/api/token", "PATCH", { code: window.localStorage.getItem("refresh_token") });
}
window.localStorage.setItem("token", response.access_token);
window.localStorage.setItem("token_expiry", (Date.now() + response.expires_in*1000).toString());
window.localStorage.setItem("refresh_token", response.refresh_token);
}
async function tryRefresh() {
if (Date.now() < parseInt(window.localStorage.getItem("token_expiry"))) return; // Not expired.
await getToken().catch((err) => {
let json = err.json();
if (json.status == 401 && json.code === 0) { // Could not refresh, so refresh token expired.
window.localStorage.clear();
alert(`Could not get new session, did you remove access from Gitea?`);
window.location = "/";
} else {
throw json;
}
});
}
// BUTTON ONCLICK MIDDLEWARE //
// Refresh token if necessary.
@ -137,7 +36,6 @@ function tryAuth(f) {
}
}
// Adds loading classes for UI while awaiting.
function doLoading(f) {
return async (e) => {
@ -188,24 +86,6 @@ document.on("keydown", (e) => {
// BUTTON ONCLICK FUNCTIONS //
get("#login").on("click", async (e) => {
e.preventDefault();
if (G_AUTH) {
window.localStorage.clear();
window.location = "/";
} else {
// Build the authorization URL
let url = CONFIG.authorization_endpoint
+ "?response_type=code"
+ "&client_id="+encodeURIComponent(CONFIG.client_id)
+ "&scope="+encodeURIComponent(CONFIG.requested_scopes)
+ "&redirect_uri="+encodeURIComponent(CONFIG.redirect_uri);
// Redirect to the authorization server
window.location = url;
}
});
get("#repoSelectInput").on("keydown", (e) => {
if (e.keyCode === 13) {
get("#repoSelectButton").click();
@ -364,5 +244,4 @@ async function init() {
}
var G_QUERY = parseQueryString(window.location.search.substring(1));
var G_AUTH = window.localStorage.getItem("token") !== null;
init();

56
templates/js/token.js Normal file
View File

@ -0,0 +1,56 @@
// Fetch function for applet use case.
async function jfetch(url, method, obj={}) {
let request = {
headers: {
"Content-Type": "application/json",
"Authorization": window.localStorage.getItem("token"),
},
method: method,
};
if (!isEmpty(obj)) request["body"] = JSON.stringify(obj);
return fetch(url, request)
.then((response) => {
let contentType = response.headers.get("Content-Type");
let json;
if (contentType && contentType.indexOf("application/json" !== -1)) {
json = response.json();
} else { // Reprocess non-json into json.
json = response.text().then((text) => {
return { status: response.status, "message": text };
});
}
if (!response.ok) { throw json; }
return json;
});
}
// OAUTH //
async function getToken() {
let response;
if (G_QUERY.code) {
response = await jfetch("/api/token", "POST", { code: G_QUERY.code });
} else {
response = await jfetch("/api/token", "PATCH", { code: window.localStorage.getItem("refresh_token") });
}
window.localStorage.setItem("token", response.access_token);
window.localStorage.setItem("token_expiry", (Date.now() + response.expires_in*1000).toString());
window.localStorage.setItem("refresh_token", response.refresh_token);
}
async function tryRefresh() {
if (Date.now() < parseInt(window.localStorage.getItem("token_expiry"))) return; // Not expired.
await getToken().catch((err) => {
let json = err.json();
if (json.status == 401 && json.code === 0) { // Could not refresh, so refresh token expired.
window.localStorage.clear();
alert(`Could not get new session, did you remove access from Gitea?`);
window.location = "/";
} else {
throw json;
}
});
}