From 18251d7f005c1a977fcc2be16cbf090fc475c768 Mon Sep 17 00:00:00 2001 From: Honbra Date: Sun, 17 Nov 2024 22:52:17 +0100 Subject: [PATCH] It was like that when I got here --- ...812043f01e718143e028058614bfc1c9265c9.json | 14 + ...c7f9d71756f1ad47ce4d8a66fa77c83bd6fdc.json | 35 + ...8e7ad18447b27c87c9009f8d14e2a9046a3b4.json | 16 + ...f6a19ac454a4d2b79ed8aa3f79e507ca55f41.json | 16 + ...b733103086502d2a2c6dd696cd97493157ed7.json | 22 + Cargo.lock | 616 +++++++++--- Cargo.toml | 29 +- askama.toml | 2 + flake.lock | 24 +- flake.nix | 2 +- src/app/api/links.rs | 56 +- src/app/api/mod.rs | 14 +- src/app/api/pastes.rs | 144 +++ src/app/mod.rs | 1 + src/app/pages/admin/pastes.rs | 28 +- src/app/pages/pastes_public.rs | 44 +- src/app/resource.rs | 140 +++ src/error.rs | 32 + static/script.js | 6 + static/style.css | 895 +++--------------- static/style.css.map | 1 + styles/_theme.scss | 53 ++ styles/style.scss | 138 +++ styles/tailwind/_border-radius.scss | 10 + styles/tailwind/_colors.scss | 12 + styles/tailwind/_max-width.scss | 0 styles/tailwind/_screens.scss | 6 + styles/tailwind/_spacing.scss | 25 + styles/tailwind/_text.scss | 37 + tailwind.config.js | 34 - templates/admin/base.html | 12 + templates/admin/paste-new.html | 18 + templates/admin/pastes.html | 12 + templates/base.html | 23 + templates/paste.html | 16 + templates/test.html | 1 + 36 files changed, 1534 insertions(+), 1000 deletions(-) create mode 100644 .sqlx/query-8f568c34f779acebeb3ddec7193812043f01e718143e028058614bfc1c9265c9.json create mode 100644 .sqlx/query-a1945bd23b49ad7bf7aab90f624c7f9d71756f1ad47ce4d8a66fa77c83bd6fdc.json create mode 100644 .sqlx/query-b3a91e683e3a0edd655140eaf788e7ad18447b27c87c9009f8d14e2a9046a3b4.json create mode 100644 .sqlx/query-c1e8d4b7bc7e5e088a7a88bf0dcf6a19ac454a4d2b79ed8aa3f79e507ca55f41.json create mode 100644 .sqlx/query-ea3d1dd65be91a19d3ed1570cabb733103086502d2a2c6dd696cd97493157ed7.json create mode 100644 askama.toml create mode 100644 src/app/api/pastes.rs create mode 100644 src/app/resource.rs create mode 100644 static/style.css.map create mode 100644 styles/_theme.scss create mode 100644 styles/style.scss create mode 100644 styles/tailwind/_border-radius.scss create mode 100644 styles/tailwind/_colors.scss create mode 100644 styles/tailwind/_max-width.scss create mode 100644 styles/tailwind/_screens.scss create mode 100644 styles/tailwind/_spacing.scss create mode 100644 styles/tailwind/_text.scss delete mode 100644 tailwind.config.js create mode 100644 templates/admin/base.html create mode 100644 templates/admin/paste-new.html create mode 100644 templates/admin/pastes.html create mode 100644 templates/base.html create mode 100644 templates/paste.html create mode 100644 templates/test.html diff --git a/.sqlx/query-8f568c34f779acebeb3ddec7193812043f01e718143e028058614bfc1c9265c9.json b/.sqlx/query-8f568c34f779acebeb3ddec7193812043f01e718143e028058614bfc1c9265c9.json new file mode 100644 index 0000000..55ae77e --- /dev/null +++ b/.sqlx/query-8f568c34f779acebeb3ddec7193812043f01e718143e028058614bfc1c9265c9.json @@ -0,0 +1,14 @@ +{ + "db_name": "PostgreSQL", + "query": "DELETE FROM paste WHERE id = $1", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Uuid" + ] + }, + "nullable": [] + }, + "hash": "8f568c34f779acebeb3ddec7193812043f01e718143e028058614bfc1c9265c9" +} diff --git a/.sqlx/query-a1945bd23b49ad7bf7aab90f624c7f9d71756f1ad47ce4d8a66fa77c83bd6fdc.json b/.sqlx/query-a1945bd23b49ad7bf7aab90f624c7f9d71756f1ad47ce4d8a66fa77c83bd6fdc.json new file mode 100644 index 0000000..04f35eb --- /dev/null +++ b/.sqlx/query-a1945bd23b49ad7bf7aab90f624c7f9d71756f1ad47ce4d8a66fa77c83bd6fdc.json @@ -0,0 +1,35 @@ +{ + "db_name": "PostgreSQL", + "query": "SELECT id, title, content from paste LIMIT $1 OFFSET $2", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "id", + "type_info": "Uuid" + }, + { + "ordinal": 1, + "name": "title", + "type_info": "Text" + }, + { + "ordinal": 2, + "name": "content", + "type_info": "Text" + } + ], + "parameters": { + "Left": [ + "Int8", + "Int8" + ] + }, + "nullable": [ + false, + false, + false + ] + }, + "hash": "a1945bd23b49ad7bf7aab90f624c7f9d71756f1ad47ce4d8a66fa77c83bd6fdc" +} diff --git a/.sqlx/query-b3a91e683e3a0edd655140eaf788e7ad18447b27c87c9009f8d14e2a9046a3b4.json b/.sqlx/query-b3a91e683e3a0edd655140eaf788e7ad18447b27c87c9009f8d14e2a9046a3b4.json new file mode 100644 index 0000000..00fbb85 --- /dev/null +++ b/.sqlx/query-b3a91e683e3a0edd655140eaf788e7ad18447b27c87c9009f8d14e2a9046a3b4.json @@ -0,0 +1,16 @@ +{ + "db_name": "PostgreSQL", + "query": "INSERT INTO paste (id, title, content) VALUES ($1, $2, $3) ON CONFLICT DO NOTHING", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Uuid", + "Text", + "Text" + ] + }, + "nullable": [] + }, + "hash": "b3a91e683e3a0edd655140eaf788e7ad18447b27c87c9009f8d14e2a9046a3b4" +} diff --git a/.sqlx/query-c1e8d4b7bc7e5e088a7a88bf0dcf6a19ac454a4d2b79ed8aa3f79e507ca55f41.json b/.sqlx/query-c1e8d4b7bc7e5e088a7a88bf0dcf6a19ac454a4d2b79ed8aa3f79e507ca55f41.json new file mode 100644 index 0000000..0250da6 --- /dev/null +++ b/.sqlx/query-c1e8d4b7bc7e5e088a7a88bf0dcf6a19ac454a4d2b79ed8aa3f79e507ca55f41.json @@ -0,0 +1,16 @@ +{ + "db_name": "PostgreSQL", + "query": "UPDATE paste SET title = $2, content = $3 WHERE id = $1", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Uuid", + "Text", + "Text" + ] + }, + "nullable": [] + }, + "hash": "c1e8d4b7bc7e5e088a7a88bf0dcf6a19ac454a4d2b79ed8aa3f79e507ca55f41" +} diff --git a/.sqlx/query-ea3d1dd65be91a19d3ed1570cabb733103086502d2a2c6dd696cd97493157ed7.json b/.sqlx/query-ea3d1dd65be91a19d3ed1570cabb733103086502d2a2c6dd696cd97493157ed7.json new file mode 100644 index 0000000..f0f8bff --- /dev/null +++ b/.sqlx/query-ea3d1dd65be91a19d3ed1570cabb733103086502d2a2c6dd696cd97493157ed7.json @@ -0,0 +1,22 @@ +{ + "db_name": "PostgreSQL", + "query": "SELECT content FROM paste WHERE id = $1", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "content", + "type_info": "Text" + } + ], + "parameters": { + "Left": [ + "Uuid" + ] + }, + "nullable": [ + false + ] + }, + "hash": "ea3d1dd65be91a19d3ed1570cabb733103086502d2a2c6dd696cd97493157ed7" +} diff --git a/Cargo.lock b/Cargo.lock index 8bb577e..34e005a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -24,12 +24,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" dependencies = [ "cfg-if", - "getrandom", "once_cell", "version_check", "zerocopy", ] +[[package]] +name = "aho-corasick" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +dependencies = [ + "memchr", +] + [[package]] name = "alloc-no-stdlib" version = "2.0.4" @@ -67,10 +75,71 @@ dependencies = [ ] [[package]] -name = "async-trait" -version = "0.1.80" +name = "arrayvec" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6fa2087f2753a7da8cc1c0dbfcf89579dd57458e36769de5ac750b4671737ca" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" + +[[package]] +name = "askama" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b79091df18a97caea757e28cd2d5fda49c6cd4bd01ddffd7ff01ace0c0ad2c28" +dependencies = [ + "askama_derive", + "askama_escape", + "humansize", + "num-traits", + "percent-encoding", +] + +[[package]] +name = "askama_axum" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a41603f7cdbf5ac4af60760f17253eb6adf6ec5b6f14a7ed830cf687d375f163" +dependencies = [ + "askama", + "axum-core", + "http", +] + +[[package]] +name = "askama_derive" +version = "0.12.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19fe8d6cb13c4714962c072ea496f3392015f0989b1a2847bb4b2d9effd71d83" +dependencies = [ + "askama_parser", + "basic-toml", + "mime", + "mime_guess", + "proc-macro2", + "quote", + "serde", + "syn 2.0.63", +] + +[[package]] +name = "askama_escape" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "619743e34b5ba4e9703bba34deac3427c72507c7159f5fd030aea8cac0cfe341" + +[[package]] +name = "askama_parser" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acb1161c6b64d1c3d83108213c2a2533a342ac225aabd0bda218278c2ddb00c0" +dependencies = [ + "nom", +] + +[[package]] +name = "async-trait" +version = "0.1.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "721cae7de5c34fbb2acd27e21e6d2cf7b886dce0c27388d46c4e6c47ea4318dd" dependencies = [ "proc-macro2", "quote", @@ -103,9 +172,9 @@ checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" [[package]] name = "axum" -version = "0.7.5" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a6c9af12842a67734c9a2e355436e5d03b22383ed60cf13cd0c18fbfe3dcbcf" +checksum = "8f43644eed690f5374f1af436ecd6aea01cd201f6fbdf0178adaf6907afb2cec" dependencies = [ "async-trait", "axum-core", @@ -130,17 +199,47 @@ dependencies = [ "serde_urlencoded", "sync_wrapper 1.0.1", "tokio", - "tower", + "tower 0.5.1", "tower-layer", "tower-service", "tracing", ] [[package]] -name = "axum-core" -version = "0.4.3" +name = "axum-codec" +version = "0.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a15c63fd72d41492dc4f497196f5da1fb04fb7529e631d73630d1b491e47a2e3" +checksum = "df50a3095de4f11905b79dea6a8bb8f230e672d41af1fa20cee85ac4975a2306" +dependencies = [ + "axum", + "axum-codec-macros", + "bincode", + "bitcode", + "ciborium", + "mime", + "schemars", + "serde", + "serde_json", + "thiserror", + "validator", +] + +[[package]] +name = "axum-codec-macros" +version = "0.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51db8a0e64cdfb289b7cd10c9dc9237e7c4298dc9cebfe8776a847657968fc2a" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.63", +] + +[[package]] +name = "axum-core" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09f2bd6146b97ae3359fa0cc6d6b376d9539582c7b4220f041a33ec24c226199" dependencies = [ "async-trait", "bytes", @@ -151,7 +250,7 @@ dependencies = [ "mime", "pin-project-lite", "rustversion", - "sync_wrapper 0.1.2", + "sync_wrapper 1.0.1", "tower-layer", "tower-service", "tracing", @@ -159,9 +258,9 @@ dependencies = [ [[package]] name = "axum-extra" -version = "0.9.3" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0be6ea09c9b96cb5076af0de2e383bd2bc0c18f827cf1967bdd353e0b910d733" +checksum = "73c3220b188aea709cf1b6c5f9b01c3bd936bb08bd2b5184a12b35ac8131b1f9" dependencies = [ "axum", "axum-core", @@ -175,7 +274,7 @@ dependencies = [ "serde", "tokio", "tokio-util", - "tower", + "tower 0.5.1", "tower-layer", "tower-service", "tracing", @@ -183,11 +282,10 @@ dependencies = [ [[package]] name = "axum-macros" -version = "0.4.1" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00c055ee2d014ae5981ce1016374e8213682aa14d9bf40e48ab48b5f3ef20eaa" +checksum = "57d123550fa8d071b7255cb0cc04dc302baa6c8c4a79f55701552684d8399bce" dependencies = [ - "heck", "proc-macro2", "quote", "syn 2.0.63", @@ -210,9 +308,9 @@ dependencies = [ [[package]] name = "base64" -version = "0.21.7" +version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" [[package]] name = "base64ct" @@ -220,6 +318,58 @@ version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" +[[package]] +name = "basic-toml" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "823388e228f614e9558c6804262db37960ec8821856535f5c3f59913140558f8" +dependencies = [ + "serde", +] + +[[package]] +name = "bincode" +version = "2.0.0-rc.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f11ea1a0346b94ef188834a65c068a03aec181c94896d481d7a0a40d85b0ce95" +dependencies = [ + "bincode_derive", + "serde", +] + +[[package]] +name = "bincode_derive" +version = "2.0.0-rc.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e30759b3b99a1b802a7a3aa21c85c3ded5c28e1c83170d82d70f08bbf7f3e4c" +dependencies = [ + "virtue", +] + +[[package]] +name = "bitcode" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee1bce7608560cd4bf0296a4262d0dbf13e6bcec5ff2105724c8ab88cc7fc784" +dependencies = [ + "arrayvec", + "bitcode_derive", + "bytemuck", + "glam", + "serde", +] + +[[package]] +name = "bitcode_derive" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a539389a13af092cd345a2b47ae7dec12deb306d660b2223d25cd3419b253ebe" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.63", +] + [[package]] name = "bitflags" version = "1.3.2" @@ -246,9 +396,9 @@ dependencies = [ [[package]] name = "brotli" -version = "5.0.0" +version = "6.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19483b140a7ac7174d34b5a581b406c64f84da5409d3e09cf4fff604f9270e67" +checksum = "74f7971dbd9326d58187408ab83117d8ac1bb9c17b085fdacd1cf2f598719b6b" dependencies = [ "alloc-no-stdlib", "alloc-stdlib", @@ -285,15 +435,18 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.6.0" +version = "1.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9" +checksum = "428d9aa8fbc0670b7b8d6030a7fadd0f86151cae55e4dbbece15f3780a3dfaf3" [[package]] name = "cc" -version = "1.0.97" +version = "1.1.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "099a5357d84c4c61eb35fc8eafa9a79a902c2f76911e5747ced4e032edd8d9b4" +checksum = "07b1695e2c7e8fc85310cde85aeaab7e3097f593c91d209d3f9df76c928100f0" +dependencies = [ + "shlex", +] [[package]] name = "cfg-if" @@ -313,6 +466,42 @@ dependencies = [ "windows-targets 0.52.5", ] +[[package]] +name = "ciborium" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42e69ffd6f0917f5c029256a24d0161db17cea3997d185db0d35926308770f0e" +dependencies = [ + "ciborium-io", + "ciborium-ll", + "serde", +] + +[[package]] +name = "ciborium-io" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05afea1e0a06c9be33d539b876f1ce3692f4afea2cb41f740e7743225ed1c757" + +[[package]] +name = "ciborium-ll" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57663b653d948a338bfb3eeba9bb2fd5fcfaecb9e199e87e1eda4d9e8b240fd9" +dependencies = [ + "ciborium-io", + "half", +] + +[[package]] +name = "concurrent-queue" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" +dependencies = [ + "crossbeam-utils", +] + [[package]] name = "const-oid" version = "0.9.6" @@ -373,6 +562,12 @@ version = "0.8.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345" +[[package]] +name = "crunchy" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" + [[package]] name = "crypto-common" version = "0.1.6" @@ -383,6 +578,41 @@ dependencies = [ "typenum", ] +[[package]] +name = "darling" +version = "0.20.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f63b86c8a8826a49b8c21f08a2d07338eec8d900540f8630dc76284be802989" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.20.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95133861a8032aaea082871032f5815eb9e98cef03fa916ab4500513994df9e5" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn 2.0.63", +] + +[[package]] +name = "darling_macro" +version = "0.20.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" +dependencies = [ + "darling_core", + "quote", + "syn 2.0.63", +] + [[package]] name = "der" version = "0.7.9" @@ -412,6 +642,12 @@ version = "0.15.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b" +[[package]] +name = "dyn-clone" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d6ef0072f8a535281e4876be788938b528e9a1d43900b82c2569af7da799125" + [[package]] name = "either" version = "1.11.0" @@ -450,9 +686,14 @@ dependencies = [ [[package]] name = "event-listener" -version = "2.5.3" +version = "5.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" +checksum = "6032be9bd27023a771701cc49f9f053c751055f71efb2e0ae5c15809093675ba" +dependencies = [ + "concurrent-queue", + "parking", + "pin-project-lite", +] [[package]] name = "eyre" @@ -627,6 +868,22 @@ version = "0.28.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" +[[package]] +name = "glam" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c28091a37a5d09b555cb6628fd954da299b536433834f5b8e59eba78e0cbbf8a" + +[[package]] +name = "half" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dd08c532ae367adf81c312a4580bc67f1d0fe8bc9c460520283f4c0ff277888" +dependencies = [ + "cfg-if", + "crunchy", +] + [[package]] name = "hashbrown" version = "0.14.5" @@ -639,21 +896,18 @@ dependencies = [ [[package]] name = "hashlink" -version = "0.8.4" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8094feaf31ff591f651a2664fb9cfd92bba7a60ce3197265e9482ebe753c8f7" +checksum = "6ba4ff7128dee98c7dc9794b6a411377e1404dba1c97deb8d1a55297bd25d8af" dependencies = [ "hashbrown", ] [[package]] name = "heck" -version = "0.4.1" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" -dependencies = [ - "unicode-segmentation", -] +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" [[package]] name = "hermit-abi" @@ -746,6 +1000,15 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" +[[package]] +name = "humansize" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6cb51c9a029ddc91b07a787f1d86b53ccfa49b0e86688c946ebe8d3555685dd7" +dependencies = [ + "libm", +] + [[package]] name = "hyper" version = "1.3.1" @@ -779,6 +1042,8 @@ dependencies = [ "pin-project-lite", "socket2", "tokio", + "tower 0.4.13", + "tower-service", ] [[package]] @@ -804,6 +1069,12 @@ dependencies = [ "cc", ] +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + [[package]] name = "idna" version = "0.5.0" @@ -883,9 +1154,9 @@ checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" [[package]] name = "libsqlite3-sys" -version = "0.27.0" +version = "0.30.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf4e226dcd58b4be396f7bd3c20da8fdee2911400705297ba7d2d7cc2c30f716" +checksum = "2e99fb7a497b1e3339bc746195567ed8d3e24945ecd636e3619d20b9de9e9149" dependencies = [ "cc", "pkg-config", @@ -962,9 +1233,9 @@ checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" [[package]] name = "memory-serve" -version = "0.4.5" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d1f8b697424035812d76b87ce97cc06bf144eb569838ebc459f0edd6b473699" +checksum = "c173f042b9373765a43929acaec201a58696dfe78fccf833f1d860ce64b4da7d" dependencies = [ "axum", "brotli", @@ -976,9 +1247,9 @@ dependencies = [ [[package]] name = "memory-serve-macros" -version = "0.4.5" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9049d464b282ee8d87ed38a9144ad263a791e4451c1eb96456da2c00845337f8" +checksum = "fc43baf532501122643a988a2bbb8f9b85819d453d5a96fdb8fc87a5026bb576" dependencies = [ "brotli", "mime_guess", @@ -1024,27 +1295,35 @@ dependencies = [ [[package]] name = "mio" -version = "0.8.11" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" +checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec" dependencies = [ + "hermit-abi", "libc", "wasi", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] name = "ncpn" version = "0.1.0" dependencies = [ + "askama", + "askama_axum", + "async-trait", "axum", + "axum-codec", + "axum-core", "axum-extra", + "bytes", "chrono", "eyre", "figment", "http", "maud", "memory-serve", + "mime", "serde", "sqlx", "thiserror", @@ -1124,16 +1403,6 @@ dependencies = [ "libm", ] -[[package]] -name = "num_cpus" -version = "1.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" -dependencies = [ - "hermit-abi", - "libc", -] - [[package]] name = "object" version = "0.32.2" @@ -1155,6 +1424,12 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" +[[package]] +name = "parking" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" + [[package]] name = "parking_lot" version = "0.12.2" @@ -1296,6 +1571,7 @@ dependencies = [ "proc-macro-error-attr", "proc-macro2", "quote", + "syn 1.0.109", "version_check", ] @@ -1389,6 +1665,35 @@ dependencies = [ "bitflags 2.5.0", ] +[[package]] +name = "regex" +version = "1.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" + [[package]] name = "rsa" version = "0.9.6" @@ -1449,6 +1754,30 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "schemars" +version = "0.8.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09c024468a378b7e36765cd36702b7a90cc3cba11654f6685c8f233408e89e92" +dependencies = [ + "dyn-clone", + "schemars_derive", + "serde", + "serde_json", +] + +[[package]] +name = "schemars_derive" +version = "0.8.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1eee588578aff73f856ab961cd2f79e36bc45d7ded33a7562adba4667aecc0e" +dependencies = [ + "proc-macro2", + "quote", + "serde_derive_internals", + "syn 2.0.63", +] + [[package]] name = "scopeguard" version = "1.2.0" @@ -1457,18 +1786,29 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "serde" -version = "1.0.203" +version = "1.0.210" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7253ab4de971e72fb7be983802300c30b5a7f0c2e56fab8abfc6a214307c0094" +checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.203" +version = "1.0.210" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "500cbc0ebeb6f46627f50f3f5811ccf6bf00643be300b4c3eabc0ef55dc5b5ba" +checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.63", +] + +[[package]] +name = "serde_derive_internals" +version = "0.29.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711" dependencies = [ "proc-macro2", "quote", @@ -1477,11 +1817,12 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.117" +version = "1.0.128" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "455182ea6142b14f93f4bc5320a2b31c1f266b66a4a5c858b013302a5d8cbfc3" +checksum = "6ff5456707a1de34e7e37f2a6fd3d3f808c318259cbd01ab6377795054b483d8" dependencies = [ "itoa", + "memchr", "ryu", "serde", ] @@ -1561,6 +1902,12 @@ dependencies = [ "lazy_static", ] +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + [[package]] name = "signature" version = "2.2.0" @@ -1585,6 +1932,9 @@ name = "smallvec" version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" +dependencies = [ + "serde", +] [[package]] name = "socket2" @@ -1634,9 +1984,9 @@ dependencies = [ [[package]] name = "sqlx" -version = "0.7.4" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9a2ccff1a000a5a59cd33da541d9f2fdcd9e6e8229cc200565942bff36d0aaa" +checksum = "93334716a037193fac19df402f8571269c84a00852f6a7066b5d2616dcd64d3e" dependencies = [ "sqlx-core", "sqlx-macros", @@ -1647,11 +1997,10 @@ dependencies = [ [[package]] name = "sqlx-core" -version = "0.7.4" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24ba59a9342a3d9bab6c56c118be528b27c9b60e490080e9711a04dccac83ef6" +checksum = "d4d8060b456358185f7d50c55d9b5066ad956956fddec42ee2e8567134a8936e" dependencies = [ - "ahash", "atoi", "byteorder", "bytes", @@ -1664,6 +2013,7 @@ dependencies = [ "futures-intrusive", "futures-io", "futures-util", + "hashbrown", "hashlink", "hex", "indexmap", @@ -1687,22 +2037,22 @@ dependencies = [ [[package]] name = "sqlx-macros" -version = "0.7.4" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ea40e2345eb2faa9e1e5e326db8c34711317d2b5e08d0d5741619048a803127" +checksum = "cac0692bcc9de3b073e8d747391827297e075c7710ff6276d9f7a1f3d58c6657" dependencies = [ "proc-macro2", "quote", "sqlx-core", "sqlx-macros-core", - "syn 1.0.109", + "syn 2.0.63", ] [[package]] name = "sqlx-macros-core" -version = "0.7.4" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5833ef53aaa16d860e92123292f1f6a3d53c34ba8b1969f152ef1a7bb803f3c8" +checksum = "1804e8a7c7865599c9c79be146dc8a9fd8cc86935fa641d3ea58e5f0688abaa5" dependencies = [ "dotenvy", "either", @@ -1718,7 +2068,7 @@ dependencies = [ "sqlx-mysql", "sqlx-postgres", "sqlx-sqlite", - "syn 1.0.109", + "syn 2.0.63", "tempfile", "tokio", "url", @@ -1726,9 +2076,9 @@ dependencies = [ [[package]] name = "sqlx-mysql" -version = "0.7.4" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ed31390216d20e538e447a7a9b959e06ed9fc51c37b514b46eb758016ecd418" +checksum = "64bb4714269afa44aef2755150a0fc19d756fb580a67db8885608cf02f47d06a" dependencies = [ "atoi", "base64", @@ -1769,9 +2119,9 @@ dependencies = [ [[package]] name = "sqlx-postgres" -version = "0.7.4" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c824eb80b894f926f89a0b9da0c7f435d27cdd35b8c655b114e58223918577e" +checksum = "6fa91a732d854c5d7726349bb4bb879bb9478993ceb764247660aee25f67c2f8" dependencies = [ "atoi", "base64", @@ -1808,9 +2158,9 @@ dependencies = [ [[package]] name = "sqlx-sqlite" -version = "0.7.4" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b244ef0a8414da0bed4bb1910426e890b19e5e9bccc27ada6b797d05c55ae0aa" +checksum = "d5b2cf34a45953bfd3daaf3db0f7a7878ab9b7a6b91b422d24a7a9e4c857b680" dependencies = [ "atoi", "flume", @@ -1823,10 +2173,10 @@ dependencies = [ "log", "percent-encoding", "serde", + "serde_urlencoded", "sqlx-core", "tracing", "url", - "urlencoding", "uuid", ] @@ -1841,6 +2191,12 @@ dependencies = [ "unicode-normalization", ] +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + [[package]] name = "subtle" version = "2.5.0" @@ -1854,7 +2210,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" dependencies = [ "proc-macro2", - "quote", "unicode-ident", ] @@ -1895,18 +2250,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.61" +version = "1.0.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c546c80d6be4bc6a00c0f01730c08df82eaa7a7a61f11d656526506112cc1709" +checksum = "d50af8abc119fb8bb6dbabcfa89656f46f84aa0ac7688088608076ad2b459a84" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.61" +version = "1.0.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533" +checksum = "08904e7672f5eb876eaaf87e0ce17857500934f4981c4a0ab2b4aa98baac7fc3" dependencies = [ "proc-macro2", "quote", @@ -1940,26 +2295,25 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.38.0" +version = "1.40.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba4f4a02a7a80d6f274636f0aa95c7e383b912d41fe721a31f29e29698585a4a" +checksum = "e2b070231665d27ad9ec9b8df639893f46727666c6767db40317fbe920a5d998" dependencies = [ "backtrace", "bytes", "libc", "mio", - "num_cpus", "pin-project-lite", "socket2", "tokio-macros", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] name = "tokio-macros" -version = "2.3.0" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f5ae998a069d4b5aba8ee9dad856af7d520c3699e6159b185c2acd48155d39a" +checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" dependencies = [ "proc-macro2", "quote", @@ -2041,10 +2395,26 @@ dependencies = [ ] [[package]] -name = "tower-http" -version = "0.5.2" +name = "tower" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e9cd434a998747dd2c4276bc96ee2e0c7a2eadf3cae88e52be55a05fa9053f5" +checksum = "2873938d487c3cfb9aed7546dc9f2711d867c9f90c46b889989a2cb84eba6b4f" +dependencies = [ + "futures-core", + "futures-util", + "pin-project-lite", + "sync_wrapper 0.1.2", + "tokio", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tower-http" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8437150ab6bbc8c5f0f519e3d5ed4aa883a83dd4cdd3d1b21f9482936046cb97" dependencies = [ "bitflags 2.5.0", "bytes", @@ -2067,15 +2437,15 @@ dependencies = [ [[package]] name = "tower-layer" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c20c8dbed6283a09604c3e69b4b7eeb54e298b8a600d4d5ecb5ad39de609f1d0" +checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" [[package]] name = "tower-service" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" +checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" [[package]] name = "tracing" @@ -2143,9 +2513,9 @@ checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" [[package]] name = "ulid" -version = "1.1.2" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34778c17965aa2a08913b57e1f34db9b4a63f5de31768b55bf20d2795f921259" +checksum = "04f903f293d11f31c0c29e4148f6dc0d033a7f80cebc0282bea147611667d289" dependencies = [ "getrandom", "rand", @@ -2193,12 +2563,6 @@ dependencies = [ "tinyvec", ] -[[package]] -name = "unicode-segmentation" -version = "1.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202" - [[package]] name = "unicode_categories" version = "0.1.1" @@ -2207,9 +2571,9 @@ checksum = "39ec24b3121d976906ece63c9daad25b85969647682eee313cb5779fdd69e14e" [[package]] name = "url" -version = "2.5.0" +version = "2.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633" +checksum = "22784dbdf76fdde8af1aeda5622b546b422b6fc585325248a2bf9f5e41e94d6c" dependencies = [ "form_urlencoded", "idna", @@ -2218,16 +2582,40 @@ dependencies = [ ] [[package]] -name = "urlencoding" -version = "2.1.3" +name = "uuid" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da" +checksum = "81dfa00651efa65069b0b6b651f4aaa31ba9e3c3ce0137aaad053604ee7e0314" [[package]] -name = "uuid" -version = "1.8.0" +name = "validator" +version = "0.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a183cf7feeba97b4dd1c0d46788634f6221d87fa961b305bed08c851829efcc0" +checksum = "db79c75af171630a3148bd3e6d7c4f42b6a9a014c2945bc5ed0020cbb8d9478e" +dependencies = [ + "idna", + "once_cell", + "regex", + "serde", + "serde_derive", + "serde_json", + "url", + "validator_derive", +] + +[[package]] +name = "validator_derive" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df0bcf92720c40105ac4b2dda2a4ea3aa717d4d6a862cc217da653a4bd5c6b10" +dependencies = [ + "darling", + "once_cell", + "proc-macro-error", + "proc-macro2", + "quote", + "syn 2.0.63", +] [[package]] name = "valuable" @@ -2247,6 +2635,12 @@ version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +[[package]] +name = "virtue" +version = "0.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9dcc60c0624df774c82a0ef104151231d37da4962957d691c011c852b2473314" + [[package]] name = "walkdir" version = "2.5.0" diff --git a/Cargo.toml b/Cargo.toml index 30ab0d0..373da81 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,24 +4,31 @@ version = "0.1.0" edition = "2021" [dependencies] -axum = { version = "0.7.5", default-features = false, features = ["http1", "json", "macros", "matched-path", "tokio", "tower-log", "tracing", "query", "form"] } -axum-extra = { version = "0.9.3", features = ["async-read-body"] } +askama = "0.12.1" +askama_axum = "0.4.0" +async-trait = "0.1.83" +axum = { version = "0.7.6", default-features = false, features = ["http1", "json", "macros", "matched-path", "tokio", "tower-log", "tracing", "query", "form"] } +axum-codec = { version = "0.0.13", features = ["cbor"] } +axum-core = "0.4.5" +axum-extra = { version = "0.9.4", features = ["async-read-body"] } +bytes = "1.7.2" chrono = { version = "0.4.38", default-features = false, features = ["alloc", "clock"] } eyre = "0.6.12" figment = { version = "0.10.19", features = ["env", "toml"] } http = "1.1.0" maud = { version = "0.26.0", features = ["axum"] } -memory-serve = "0.4.5" -serde = { version = "1.0.203", features = ["derive"] } -sqlx = { version = "0.7.4", features = ["runtime-tokio", "postgres", "uuid"] } -thiserror = "1.0.61" -tokio = { version = "1.38.0", features = ["rt-multi-thread", "macros", "fs", "io-std"] } -tower-http = { version = "0.5.2", features = ["trace", "fs"] } +memory-serve = "0.6.0" +mime = "0.3.17" +serde = { version = "1.0.210", features = ["derive"] } +sqlx = { version = "0.8.2", features = ["runtime-tokio", "postgres", "uuid"] } +thiserror = "1.0.64" +tokio = { version = "1.40.0", features = ["rt-multi-thread", "macros", "fs", "io-std"] } +tower-http = { version = "0.6.1", features = ["trace", "fs"] } tracing = "0.1.40" tracing-subscriber = "0.3.18" -ulid = { version = "1.1.2", features = ["uuid", "serde"] } -url = { version = "2.5.0", features = ["serde"] } -uuid = "1.8.0" +ulid = { version = "1.1.3", features = ["uuid", "serde"] } +url = { version = "2.5.2", features = ["serde"] } +uuid = "1.10.0" [profile.release] strip = true diff --git a/askama.toml b/askama.toml new file mode 100644 index 0000000..991ecea --- /dev/null +++ b/askama.toml @@ -0,0 +1,2 @@ +[general] +whitespace = "minimize" diff --git a/flake.lock b/flake.lock index 5041ff9..dbe88ac 100644 --- a/flake.lock +++ b/flake.lock @@ -8,11 +8,11 @@ "rust-analyzer-src": "rust-analyzer-src" }, "locked": { - "lastModified": 1717741716, - "narHash": "sha256-v71DDu2gb02iBIAhUwu5mQZNtYD45QcbEqahqsOCCyU=", + "lastModified": 1727159616, + "narHash": "sha256-1VjZ+khJwZphRJZy2HvbMSCgi3OV7mu8RjVzqCxVi2k=", "owner": "nix-community", "repo": "fenix", - "rev": "05f2a8ae62c45637b20d162fa2dd450b79e71c27", + "rev": "4306d494985e00719573bbdeb863c27c6d83dc9c", "type": "github" }, "original": { @@ -26,11 +26,11 @@ "systems": "systems" }, "locked": { - "lastModified": 1710146030, - "narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=", + "lastModified": 1726560853, + "narHash": "sha256-X6rJYSESBVr3hBoH0WbKE5KvhPU5bloyZ2L4K60/fPQ=", "owner": "numtide", "repo": "flake-utils", - "rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a", + "rev": "c1dfcf08411b08f6b8615f7d8971a2bfa81d5e8a", "type": "github" }, "original": { @@ -41,11 +41,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1717602782, - "narHash": "sha256-pL9jeus5QpX5R+9rsp3hhZ+uplVHscNJh8n8VpqscM0=", + "lastModified": 1726937504, + "narHash": "sha256-bvGoiQBvponpZh8ClUcmJ6QnsNKw0EMrCQJARK3bI1c=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "e8057b67ebf307f01bdcc8fba94d94f75039d1f6", + "rev": "9357f4f23713673f310988025d9dc261c20e70c6", "type": "github" }, "original": { @@ -65,11 +65,11 @@ "rust-analyzer-src": { "flake": false, "locked": { - "lastModified": 1717583671, - "narHash": "sha256-+lRAmz92CNUxorqWusgJbL9VE1eKCnQQojglRemzwkw=", + "lastModified": 1727104575, + "narHash": "sha256-lB/ZS0SnHyE8Z3G8DIL/QJPg6w6x5ZhgVO2pBqnz89g=", "owner": "rust-lang", "repo": "rust-analyzer", - "rev": "48bbdd6a74f3176987d5c809894ac33957000d19", + "rev": "3d0343251fe084b335b55c17a52bb4a3527b1bd0", "type": "github" }, "original": { diff --git a/flake.nix b/flake.nix index ebeb760..0ebbe17 100644 --- a/flake.nix +++ b/flake.nix @@ -44,7 +44,7 @@ postgresql sqlfluff sqlx-cli - tailwindcss + dart-sass ]; }; } diff --git a/src/app/api/links.rs b/src/app/api/links.rs index 6be97f3..9db4148 100644 --- a/src/app/api/links.rs +++ b/src/app/api/links.rs @@ -15,38 +15,11 @@ use crate::{app::SharedState, error::AppError}; pub fn resource() -> Resource { Resource::named("links") .create(create_link) - .show(get_link_info) + .show(show_link) .update(update_link) .destroy(delete_link) } -#[derive(Serialize)] -struct Link { - id: Ulid, - slug: String, - destination: String, -} - -async fn get_link_info( - State(SharedState { db, .. }): State, - Path(id): Path, -) -> Result, AppError> { - match query!( - "SELECT id, slug, destination FROM link WHERE id = $1", - Uuid::from(id), - ) - .fetch_optional(&db) - .await? - { - Some(r) => Ok(Json(Link { - id: Ulid::from(r.id), - slug: r.slug, - destination: r.destination, - })), - None => Err(AppError::LinkNotFoundId(id)), - } -} - #[derive(Deserialize)] struct CreateLinkRequestBody { slug: String, @@ -79,6 +52,33 @@ async fn create_link( } } +#[derive(Serialize)] +struct Link { + id: Ulid, + slug: String, + destination: String, +} + +async fn show_link( + State(SharedState { db, .. }): State, + Path(id): Path, +) -> Result, AppError> { + match query!( + "SELECT id, slug, destination FROM link WHERE id = $1", + Uuid::from(id), + ) + .fetch_optional(&db) + .await? + { + Some(r) => Ok(Json(Link { + id: Ulid::from(r.id), + slug: r.slug, + destination: r.destination, + })), + None => Err(AppError::LinkNotFoundId(id)), + } +} + #[derive(Deserialize)] struct UpdateLinkRequestBody { destination: Url, diff --git a/src/app/api/mod.rs b/src/app/api/mod.rs index 00fd65c..a156280 100644 --- a/src/app/api/mod.rs +++ b/src/app/api/mod.rs @@ -1,9 +1,21 @@ mod links; +mod pastes; use axum::Router; +use serde::Deserialize; use super::SharedState; pub fn router() -> Router { - Router::new().merge(links::resource()) + Router::new() + .merge(links::resource()) + .merge(pastes::resource()) +} + +#[derive(Deserialize)] +struct Pagination { + #[serde(default)] + limit: Option, + #[serde(default)] + offset: i64, } diff --git a/src/app/api/pastes.rs b/src/app/api/pastes.rs new file mode 100644 index 0000000..c8c4cd6 --- /dev/null +++ b/src/app/api/pastes.rs @@ -0,0 +1,144 @@ +use axum::{ + extract::{Path, Query, State}, + Json, +}; +use axum_codec::Codec; +use http::StatusCode; +use serde::Deserialize; +use sqlx::query; +use ulid::Ulid; +use uuid::Uuid; + +use super::Pagination; +use crate::{ + app::{resource::Resource, SharedState}, + error::AppError, +}; + +pub fn resource() -> Resource { + Resource::named("pastes") + .index(list_pastes) + .create(create_paste) + .show(show_paste) + .update(update_paste) + .destroy(delete_paste) +} + +#[axum_codec::apply(encode)] +struct Paste { + id: Ulid, + title: String, + content: String, +} + +async fn list_pastes( + State(SharedState { db, .. }): State, + Query(Pagination { limit, offset }): Query, +) -> Result>, AppError> { + Ok(Codec( + query!( + "SELECT id, title, content from paste LIMIT $1 OFFSET $2", + limit, + offset, + ) + .fetch_all(&db) + .await? + .into_iter() + .map(|r| Paste { + id: Ulid::from(r.id), + title: r.title, + content: r.content, + }) + .collect(), + )) +} + +#[axum_codec::apply(decode)] +struct CreatePasteRequestBody { + title: String, + content: String, +} + +async fn create_paste( + State(SharedState { db, .. }): State, + Codec(CreatePasteRequestBody { title, content }): Codec, +) -> Result, AppError> { + let id = Ulid::new(); + + match query!( + "INSERT INTO paste (id, title, content) VALUES ($1, $2, $3) ON CONFLICT DO NOTHING", + Uuid::from(id), + title, + content, + ) + .execute(&db) + .await? + .rows_affected() + { + 1 => Ok(Codec(Paste { id, title, content })), + 0 => Err(AppError::UlidConflict(id)), + rows => Err(AppError::ImpossibleAffectedRows(rows)), + } +} + +async fn show_paste( + State(SharedState { db, .. }): State, + Path(id): Path, +) -> Result, AppError> { + match query!( + "SELECT title, content FROM paste WHERE id = $1", + Uuid::from(id), + ) + .fetch_optional(&db) + .await? + { + Some(r) => Ok(Codec(Paste { + id, + title: r.title, + content: r.content, + })), + None => Err(AppError::PasteNotFound(id)), + } +} + +#[derive(Deserialize)] +struct UpdatePasteRequestBody { + title: String, + content: String, +} + +async fn update_paste( + State(SharedState { db, .. }): State, + Path(id): Path, + Json(UpdatePasteRequestBody { title, content }): Json, +) -> Result { + match query!( + "UPDATE paste SET title = $2, content = $3 WHERE id = $1", + Uuid::from(id), + title, + content, + ) + .execute(&db) + .await? + .rows_affected() + { + 1 => Ok(StatusCode::NO_CONTENT), + 0 => Err(AppError::PasteNotFound(id)), + rows => Err(AppError::ImpossibleAffectedRows(rows)), + } +} + +async fn delete_paste( + State(SharedState { db, .. }): State, + Path(id): Path, +) -> Result { + match query!("DELETE FROM paste WHERE id = $1", Uuid::from(id)) + .execute(&db) + .await? + .rows_affected() + { + 1 => Ok(StatusCode::NO_CONTENT), + 0 => Err(AppError::PasteNotFound(id)), + rows => Err(AppError::ImpossibleAffectedRows(rows)), + } +} diff --git a/src/app/mod.rs b/src/app/mod.rs index 80b50f6..6140b26 100644 --- a/src/app/mod.rs +++ b/src/app/mod.rs @@ -1,5 +1,6 @@ mod api; mod pages; +mod resource; mod root; use std::sync::Arc; diff --git a/src/app/pages/admin/pastes.rs b/src/app/pages/admin/pastes.rs index 5055d64..24b6ebe 100644 --- a/src/app/pages/admin/pastes.rs +++ b/src/app/pages/admin/pastes.rs @@ -1,3 +1,4 @@ +use askama::Template; use axum::{ extract::{Query, State}, response::Redirect, @@ -61,6 +62,13 @@ async fn show_pastes( )) } +#[derive(Template)] +#[template(path = "admin/paste-new.html")] +struct CreatePasteTemplate { + paste_title: String, + paste_content: String, +} + #[derive(Deserialize)] struct CreatePasteFieldsOptional { title: Option, @@ -69,21 +77,11 @@ struct CreatePasteFieldsOptional { async fn show_create_paste( Query(CreatePasteFieldsOptional { title, content }): Query, -) -> Markup { - page( - "Create Paste", - &[BC_INDEX, BC_ADMIN, BC_PASTES], - html! { - form method="post" action="/admin/pastes" { - fieldset { - legend { "Paste" } - input class="w-full" type="text" name="title" placeholder="Paste title" required value=(title.unwrap_or_default()); - textarea class="w-full min-h-32" name="content" placeholder="Paste content" required { (content.unwrap_or_default()) } - input type="submit" value="Create"; - } - } - }, - ) +) -> CreatePasteTemplate { + CreatePasteTemplate { + paste_title: title.unwrap_or_default(), + paste_content: content.unwrap_or_default(), + } } #[derive(Deserialize)] diff --git a/src/app/pages/pastes_public.rs b/src/app/pages/pastes_public.rs index b863ac2..b678579 100644 --- a/src/app/pages/pastes_public.rs +++ b/src/app/pages/pastes_public.rs @@ -1,42 +1,60 @@ // 01HZT59RTH4R6P1TYE6NMAFYEP 018FF454-E351-260D-60EB-CE3568A7F9D6 +use askama_axum::Template; use axum::{ extract::{Path, State}, routing::get, Router, }; -use maud::{html, Markup}; use sqlx::query; use ulid::Ulid; use uuid::Uuid; -use super::{page, Breadcrumb, BC_INDEX}; use crate::{app::SharedState, error::AppError}; pub(super) fn router() -> Router { - Router::new().route("/:id", get(show_paste)) + Router::new() + .route("/:id", get(show_paste)) + .route("/:id/raw", get(show_paste_raw)) } -const BC_PASTES_PUBLIC: Breadcrumb = Breadcrumb::new_static("Pastes", "/p"); +#[derive(Template)] +#[template(path = "paste.html")] +struct PasteTemplate { + id: Ulid, + title: String, + content: String, +} async fn show_paste( Path(id): Path, State(SharedState { db, .. }): State, -) -> Result { +) -> Result { match query!( "SELECT title, content FROM paste WHERE id = $1", - Uuid::from(id) + Uuid::from(id), ) .fetch_optional(&db) .await? { - Some(r) => Ok(page( - &r.title, - &[BC_INDEX, BC_PASTES_PUBLIC], - html! { - pre class="p-4 border border-bd-base rounded-xl" { (r.content) } - }, - )), + Some(r) => Ok(PasteTemplate { + id, + title: r.title, + content: r.content, + }), + None => Err(AppError::PasteNotFound(id)), + } +} + +async fn show_paste_raw( + Path(id): Path, + State(SharedState { db, .. }): State, +) -> Result { + match query!("SELECT content FROM paste WHERE id = $1", Uuid::from(id)) + .fetch_optional(&db) + .await? + { + Some(r) => Ok(r.content), None => Err(AppError::PasteNotFound(id)), } } diff --git a/src/app/resource.rs b/src/app/resource.rs new file mode 100644 index 0000000..41984d6 --- /dev/null +++ b/src/app/resource.rs @@ -0,0 +1,140 @@ +use axum::{routing::MethodRouter, Router}; +use axum_codec::{ + handler::Input, + routing::{delete, get, post, put}, + CodecHandler, IntoCodecResponse, +}; + +/// A resource which defines a set of conventional CRUD routes. +#[derive(Debug)] +#[must_use] +pub struct Resource { + pub(crate) name: String, + pub(crate) router: Router, +} + +impl Resource +where + S: Clone + Send + Sync + 'static, +{ + /// Create a `Resource` with the given name. + /// + /// All routes will be nested at `/{resource_name}`. + pub fn named(resource_name: &str) -> Self { + Self { + name: resource_name.to_owned(), + router: Router::new(), + } + } + + /// Add a handler at `GET /{resource_name}`. + pub fn index(self, handler: H) -> Self + where + H: CodecHandler + Clone + Send + Sync + 'static, + I: Input + Send + 'static, + D: IntoCodecResponse + Send + Sync + 'static, + S: Clone + Send + Sync + 'static, + T: 'static, + { + let path = self.index_create_path(); + self.route(&path, get(handler).into()) + } + + /// Add a handler at `POST /{resource_name}`. + pub fn create(self, handler: H) -> Self + where + H: CodecHandler + Clone + Send + Sync + 'static, + I: Input + Send + 'static, + D: IntoCodecResponse + Send + Sync + 'static, + S: Clone + Send + Sync + 'static, + T: 'static, + { + let path = self.index_create_path(); + self.route(&path, post(handler).into()) + } + + /// Add a handler at `GET /{resource_name}/new`. + pub fn new(self, handler: H) -> Self + where + H: CodecHandler + Clone + Send + Sync + 'static, + I: Input + Send + 'static, + D: IntoCodecResponse + Send + Sync + 'static, + S: Clone + Send + Sync + 'static, + T: 'static, + { + let path = format!("/{}/new", self.name); + self.route(&path, get(handler).into()) + } + + /// Add a handler at `GET /{resource_name}/:{resource_name}_id`. + pub fn show(self, handler: H) -> Self + where + H: CodecHandler + Clone + Send + Sync + 'static, + I: Input + Send + 'static, + D: IntoCodecResponse + Send + Sync + 'static, + S: Clone + Send + Sync + 'static, + T: 'static, + { + let path = self.show_update_destroy_path(); + self.route(&path, get(handler).into()) + } + + /// Add a handler at `GET /{resource_name}/:{resource_name}_id/edit`. + pub fn edit(self, handler: H) -> Self + where + H: CodecHandler + Clone + Send + Sync + 'static, + I: Input + Send + 'static, + D: IntoCodecResponse + Send + Sync + 'static, + S: Clone + Send + Sync + 'static, + T: 'static, + { + let path = format!("/{0}/:{0}_id/edit", self.name); + self.route(&path, get(handler).into()) + } + + /// Add a handler at `PUT or PATCH /resource_name/:{resource_name}_id`. + pub fn update(self, handler: H) -> Self + where + H: CodecHandler + Clone + Send + Sync + 'static, + I: Input + Send + 'static, + D: IntoCodecResponse + Send + Sync + 'static, + S: Clone + Send + Sync + 'static, + T: 'static, + { + let path = self.show_update_destroy_path(); + // it's 12 AM and I don't know how to get `MethodFilter` to work + self.route(&path, put(handler.clone()).patch(handler).into()) + } + + /// Add a handler at `DELETE /{resource_name}/:{resource_name}_id`. + pub fn destroy(self, handler: H) -> Self + where + H: CodecHandler + Clone + Send + Sync + 'static, + I: Input + Send + 'static, + D: IntoCodecResponse + Send + Sync + 'static, + S: Clone + Send + Sync + 'static, + T: 'static, + { + let path = self.show_update_destroy_path(); + self.route(&path, delete(handler).into()) + } + + fn index_create_path(&self) -> String { + format!("/{}", self.name) + } + + fn show_update_destroy_path(&self) -> String { + format!("/{0}/:{0}_id", self.name) + } + + fn route(mut self, path: &str, method_router: MethodRouter) -> Self { + self.router = self.router.route(path, method_router); + self + } +} + +impl From> for Router { + fn from(resource: Resource) -> Self { + resource.router + } +} diff --git a/src/error.rs b/src/error.rs index dc245dd..a35da22 100644 --- a/src/error.rs +++ b/src/error.rs @@ -1,4 +1,5 @@ use axum::{body::Body, response::IntoResponse}; +use axum_codec::{ContentType, IntoCodecResponse}; use http::StatusCode; use tracing::{error, field}; use ulid::Ulid; @@ -55,3 +56,34 @@ impl IntoResponse for AppError { .into_response() } } + +impl IntoCodecResponse for AppError { + fn into_codec_response(self, content_type: ContentType) -> axum_core::response::Response { + error!(err = field::display(&self)); + match self { + Self::LinkExists(_) => (StatusCode::BAD_REQUEST, "Link already exists"), + Self::LinkNotFoundId(_) | Self::LinkNotFoundSlug(_) => { + (StatusCode::NOT_FOUND, "Link not found") + } + Self::PasteNotFound(_) => (StatusCode::NOT_FOUND, "Paste not found"), + Self::ImpossibleAffectedRows(_) => ( + StatusCode::INTERNAL_SERVER_ERROR, + "Database returned an impossible number of affected rows", + ), + Self::UlidConflict(_) => (StatusCode::INTERNAL_SERVER_ERROR, "ULID conflict real???"), + Self::Database(_) => ( + StatusCode::INTERNAL_SERVER_ERROR, + "A database error has occured", + ), + Self::Io(_) => ( + StatusCode::INTERNAL_SERVER_ERROR, + "An I/O error has occured", + ), + Self::Other(_) => ( + StatusCode::INTERNAL_SERVER_ERROR, + "An unknown error has occured", + ), + } + .into_codec_response(content_type) + } +} diff --git a/static/script.js b/static/script.js index 1d19834..92fa103 100644 --- a/static/script.js +++ b/static/script.js @@ -6,3 +6,9 @@ document e.getAttribute("datetime") ).toLocaleString()) ); + +function copyPasteContent() { + navigator.clipboard + .writeText(document.getElementById("paste-content").textContent) + .catch((e) => console.error(e)); +} diff --git a/static/style.css b/static/style.css index 4d6ded7..32a303e 100644 --- a/static/style.css +++ b/static/style.css @@ -1,795 +1,142 @@ -/* -! tailwindcss v3.4.3 | MIT License | https://tailwindcss.com -*/ +/* Tailwind palette */ +/* Yes, it's that simple. + * https://tailwindcss.com/docs/customizing-spacing#default-spacing-scale + * https://github.com/tailwindlabs/tailwindcss/blob/ac6d4a6e8e9ae7ca197bf98d933ae2f205be3635/packages/tailwindcss/src/compat/default-theme.ts#L909 */ +/* https://github.com/tailwindlabs/tailwindcss/blob/ac6d4a6e8e9ae7ca197bf98d933ae2f205be3635/packages/tailwindcss/src/compat/default-theme.ts#L715 */ +html { + color-scheme: light dark; +} -/* -1. Prevent padding and border from affecting element width. (https://github.com/mozdevs/cssremedy/issues/4) -2. Allow adding a border to an element by just adding a border-width. (https://github.com/tailwindcss/tailwindcss/pull/116) -*/ +/* These need switchable client-side */ +:root { + /* Foreground */ + --color-fg-base: #334155; + --color-fg-deemphasized: #475569; + --color-fg-headings: #0f172a; + /* Background */ + --color-bg-base: #f1f5f9; + --color-bg-raised-1: #e2e8f0; + --color-bg-raised-2: #cbd5e1; + /* Borders */ + --color-bd-base: #cbd5e1; + --color-bd-highlighted: #64748b; +} +@media (prefers-color-scheme: dark) { + :root { + /* Foreground */ + --color-fg-base: #cbd5e1; + --color-fg-deemphasized: #94a3b8; + --color-fg-headings: #f1f5f9; + /* Background */ + --color-bg-base: #0f172a; + --color-bg-raised-1: #1e293b; + --color-bg-raised-2: #334155; + /* Borders */ + --color-bd-base: #334155; + --color-bd-highlighted: #64748b; + } +} -*, -::before, -::after { +/* https://github.com/tailwindlabs/tailwindcss/blob/ac6d4a6e8e9ae7ca197bf98d933ae2f205be3635/packages/tailwindcss/src/compat/default-theme.ts#L162 */ +* { box-sizing: border-box; - /* 1 */ - border-width: 0; - /* 2 */ - border-style: solid; - /* 2 */ - border-color: #e5e7eb; - /* 2 */ } -::before, -::after { - --tw-content: ''; -} - -/* -1. Use a consistent sensible line-height in all browsers. -2. Prevent adjustments of font size after orientation changes in iOS. -3. Use a more readable tab size. -4. Use the user's configured `sans` font-family by default. -5. Use the user's configured `sans` font-feature-settings by default. -6. Use the user's configured `sans` font-variation-settings by default. -7. Disable tap highlights on iOS -*/ - -html, -:host { - line-height: 1.5; - /* 1 */ - -webkit-text-size-adjust: 100%; - /* 2 */ - -moz-tab-size: 4; - /* 3 */ - -o-tab-size: 4; - tab-size: 4; - /* 3 */ - font-family: sans-serif; - /* 4 */ - font-feature-settings: normal; - /* 5 */ - font-variation-settings: normal; - /* 6 */ - -webkit-tap-highlight-color: transparent; - /* 7 */ -} - -/* -1. Remove the margin in all browsers. -2. Inherit line-height from `html` so users can set them as a class directly on the `html` element. -*/ - body { + font-family: Inter, "Inter Variable", sans-serif; + color: var(--color-fg-base); + background-color: var(--color-bg-base); + padding: 4rem 2rem; + margin: 0 auto; + max-width: 56rem; +} +body.wide { + max-width: 72rem; +} +@media not all and (min-width: var(--max-width-lg)) { + body { + padding: 2rem; + } +} +body header { + margin-bottom: 2rem; +} +body header h1 { margin: 0; - /* 1 */ - line-height: inherit; - /* 2 */ + color: var(--color-fg-headings); + font-size: 1.875rem; + font-weight: 800; +} +body footer { + color: var(--color-fg-deemphasized); + margin-top: 2rem; + text-align: center; } -/* -1. Add the correct height in Firefox. -2. Correct the inheritance of border color in Firefox. (https://bugzilla.mozilla.org/show_bug.cgi?id=190655) -3. Ensure horizontal rules are visible by default. -*/ - -hr { - height: 0; - /* 1 */ - color: inherit; - /* 2 */ - border-top-width: 1px; - /* 3 */ -} - -/* -Add the correct text decoration in Chrome, Edge, and Safari. -*/ - -abbr:where([title]) { - -webkit-text-decoration: underline dotted; - text-decoration: underline dotted; -} - -/* -Remove the default font size and weight for headings. -*/ - -h1, -h2, -h3, -h4, -h5, -h6 { - font-size: inherit; - font-weight: inherit; -} - -/* -Reset links to optimize for opt-in styling instead of opt-out. -*/ - -a { - color: inherit; - text-decoration: inherit; -} - -/* -Add the correct font weight in Edge and Safari. -*/ - -b, -strong { - font-weight: bolder; -} - -/* -1. Use the user's configured `mono` font-family by default. -2. Use the user's configured `mono` font-feature-settings by default. -3. Use the user's configured `mono` font-variation-settings by default. -4. Correct the odd `em` font sizing in all browsers. -*/ - -code, -kbd, -samp, -pre { - font-family: monospace; - /* 1 */ - font-feature-settings: normal; - /* 2 */ - font-variation-settings: normal; - /* 3 */ - font-size: 1em; - /* 4 */ -} - -/* -Add the correct font size in all browsers. -*/ - -small { - font-size: 80%; -} - -/* -Prevent `sub` and `sup` elements from affecting the line height in all browsers. -*/ - -sub, -sup { - font-size: 75%; - line-height: 0; - position: relative; - vertical-align: baseline; -} - -sub { - bottom: -0.25em; -} - -sup { - top: -0.5em; -} - -/* -1. Remove text indentation from table contents in Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=999088, https://bugs.webkit.org/show_bug.cgi?id=201297) -2. Correct table border color inheritance in all Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=935729, https://bugs.webkit.org/show_bug.cgi?id=195016) -3. Remove gaps between table borders by default. -*/ - -table { - text-indent: 0; - /* 1 */ - border-color: inherit; - /* 2 */ - border-collapse: collapse; - /* 3 */ -} - -/* -1. Change the font styles in all browsers. -2. Remove the margin in Firefox and Safari. -3. Remove default padding in all browsers. -*/ - -button, -input, -optgroup, -select, -textarea { - font-family: inherit; - /* 1 */ - font-feature-settings: inherit; - /* 1 */ - font-variation-settings: inherit; - /* 1 */ - font-size: 100%; - /* 1 */ - font-weight: inherit; - /* 1 */ - line-height: inherit; - /* 1 */ - letter-spacing: inherit; - /* 1 */ - color: inherit; - /* 1 */ - margin: 0; - /* 2 */ - padding: 0; - /* 3 */ -} - -/* -Remove the inheritance of text transform in Edge and Firefox. -*/ - -button, -select { - text-transform: none; -} - -/* -1. Correct the inability to style clickable types in iOS and Safari. -2. Remove default button styles. -*/ - -button, -input:where([type='button']), -input:where([type='reset']), -input:where([type='submit']) { - -webkit-appearance: button; - /* 1 */ - background-color: transparent; - /* 2 */ - background-image: none; - /* 2 */ -} - -/* -Use the modern Firefox focus style for all focusable elements. -*/ - -:-moz-focusring { - outline: auto; -} - -/* -Remove the additional `:invalid` styles in Firefox. (https://github.com/mozilla/gecko-dev/blob/2f9eacd9d3d995c937b4251a5557d95d494c9be1/layout/style/res/forms.css#L728-L737) -*/ - -:-moz-ui-invalid { - box-shadow: none; -} - -/* -Add the correct vertical alignment in Chrome and Firefox. -*/ - -progress { - vertical-align: baseline; -} - -/* -Correct the cursor style of increment and decrement buttons in Safari. -*/ - -::-webkit-inner-spin-button, -::-webkit-outer-spin-button { - height: auto; -} - -/* -1. Correct the odd appearance in Chrome and Safari. -2. Correct the outline style in Safari. -*/ - -[type='search'] { - -webkit-appearance: textfield; - /* 1 */ - outline-offset: -2px; - /* 2 */ -} - -/* -Remove the inner padding in Chrome and Safari on macOS. -*/ - -::-webkit-search-decoration { - -webkit-appearance: none; -} - -/* -1. Correct the inability to style clickable types in iOS and Safari. -2. Change font properties to `inherit` in Safari. -*/ - -::-webkit-file-upload-button { - -webkit-appearance: button; - /* 1 */ - font: inherit; - /* 2 */ -} - -/* -Add the correct display in Chrome and Safari. -*/ - -summary { - display: list-item; -} - -/* -Removes the default spacing and border for appropriate elements. -*/ - -blockquote, -dl, -dd, -h1, -h2, -h3, -h4, -h5, -h6, -hr, -figure, -p, -pre { - margin: 0; -} - -fieldset { - margin: 0; - padding: 0; -} - -legend { - padding: 0; -} - -ol, -ul, -menu { - list-style: none; - margin: 0; - padding: 0; -} - -/* -Reset default styling for dialogs. -*/ - -dialog { - padding: 0; -} - -/* -Prevent resizing textareas horizontally by default. -*/ - -textarea { - resize: vertical; -} - -/* -1. Reset the default placeholder opacity in Firefox. (https://github.com/tailwindlabs/tailwindcss/issues/3300) -2. Set the default placeholder color to the user's configured gray 400 color. -*/ - -input::-moz-placeholder, textarea::-moz-placeholder { - opacity: 1; - /* 1 */ - color: #9ca3af; - /* 2 */ -} - -input::placeholder, -textarea::placeholder { - opacity: 1; - /* 1 */ - color: #9ca3af; - /* 2 */ -} - -/* -Set the default cursor for buttons. -*/ - -button, -[role="button"] { - cursor: pointer; -} - -/* -Make sure disabled buttons don't get the pointer cursor. -*/ - -:disabled { - cursor: default; -} - -/* -1. Make replaced elements `display: block` by default. (https://github.com/mozdevs/cssremedy/issues/14) -2. Add `vertical-align: middle` to align replaced elements more sensibly by default. (https://github.com/jensimmons/cssremedy/issues/14#issuecomment-634934210) - This can trigger a poorly considered lint error in some tools but is included by design. -*/ - -img, -svg, -video, -canvas, -audio, -iframe, -embed, -object { - display: block; - /* 1 */ - vertical-align: middle; - /* 2 */ -} - -/* -Constrain images and videos to the parent width and preserve their intrinsic aspect ratio. (https://github.com/mozdevs/cssremedy/issues/14) -*/ - -img, -video { - max-width: 100%; - height: auto; -} - -/* Make elements with the HTML hidden attribute stay hidden by default */ - -[hidden] { - display: none; -} - -*, ::before, ::after { - --tw-border-spacing-x: 0; - --tw-border-spacing-y: 0; - --tw-translate-x: 0; - --tw-translate-y: 0; - --tw-rotate: 0; - --tw-skew-x: 0; - --tw-skew-y: 0; - --tw-scale-x: 1; - --tw-scale-y: 1; - --tw-pan-x: ; - --tw-pan-y: ; - --tw-pinch-zoom: ; - --tw-scroll-snap-strictness: proximity; - --tw-gradient-from-position: ; - --tw-gradient-via-position: ; - --tw-gradient-to-position: ; - --tw-ordinal: ; - --tw-slashed-zero: ; - --tw-numeric-figure: ; - --tw-numeric-spacing: ; - --tw-numeric-fraction: ; - --tw-ring-inset: ; - --tw-ring-offset-width: 0px; - --tw-ring-offset-color: #fff; - --tw-ring-color: rgb(59 130 246 / 0.5); - --tw-ring-offset-shadow: 0 0 #0000; - --tw-ring-shadow: 0 0 #0000; - --tw-shadow: 0 0 #0000; - --tw-shadow-colored: 0 0 #0000; - --tw-blur: ; - --tw-brightness: ; - --tw-contrast: ; - --tw-grayscale: ; - --tw-hue-rotate: ; - --tw-invert: ; - --tw-saturate: ; - --tw-sepia: ; - --tw-drop-shadow: ; - --tw-backdrop-blur: ; - --tw-backdrop-brightness: ; - --tw-backdrop-contrast: ; - --tw-backdrop-grayscale: ; - --tw-backdrop-hue-rotate: ; - --tw-backdrop-invert: ; - --tw-backdrop-opacity: ; - --tw-backdrop-saturate: ; - --tw-backdrop-sepia: ; - --tw-contain-size: ; - --tw-contain-layout: ; - --tw-contain-paint: ; - --tw-contain-style: ; -} - -::backdrop { - --tw-border-spacing-x: 0; - --tw-border-spacing-y: 0; - --tw-translate-x: 0; - --tw-translate-y: 0; - --tw-rotate: 0; - --tw-skew-x: 0; - --tw-skew-y: 0; - --tw-scale-x: 1; - --tw-scale-y: 1; - --tw-pan-x: ; - --tw-pan-y: ; - --tw-pinch-zoom: ; - --tw-scroll-snap-strictness: proximity; - --tw-gradient-from-position: ; - --tw-gradient-via-position: ; - --tw-gradient-to-position: ; - --tw-ordinal: ; - --tw-slashed-zero: ; - --tw-numeric-figure: ; - --tw-numeric-spacing: ; - --tw-numeric-fraction: ; - --tw-ring-inset: ; - --tw-ring-offset-width: 0px; - --tw-ring-offset-color: #fff; - --tw-ring-color: rgb(59 130 246 / 0.5); - --tw-ring-offset-shadow: 0 0 #0000; - --tw-ring-shadow: 0 0 #0000; - --tw-shadow: 0 0 #0000; - --tw-shadow-colored: 0 0 #0000; - --tw-blur: ; - --tw-brightness: ; - --tw-contrast: ; - --tw-grayscale: ; - --tw-hue-rotate: ; - --tw-invert: ; - --tw-saturate: ; - --tw-sepia: ; - --tw-drop-shadow: ; - --tw-backdrop-blur: ; - --tw-backdrop-brightness: ; - --tw-backdrop-contrast: ; - --tw-backdrop-grayscale: ; - --tw-backdrop-hue-rotate: ; - --tw-backdrop-invert: ; - --tw-backdrop-opacity: ; - --tw-backdrop-saturate: ; - --tw-backdrop-sepia: ; - --tw-contain-size: ; - --tw-contain-layout: ; - --tw-contain-paint: ; - --tw-contain-style: ; -} - -.static { - position: static; -} - -.flex { +body.paste header { display: flex; + justify-content: space-between; + align-items: end; } - -.table { - display: table; -} - -.min-h-32 { - min-height: 8rem; -} - -.w-full { - width: 100%; -} - -.gap-2 { +body.paste header .action-buttons { + display: flex; + justify-content: end; gap: 0.5rem; } - -.rounded-xl { - border-radius: 0.75rem; +body.paste header .action-buttons button, +body.paste header .action-buttons [role=button] { + background-color: var(--color-bg-raised-1); + padding: 0.25rem 0.75rem; + border: 1px solid var(--color-bd-base); + border-radius: 0.5rem; + cursor: pointer; + color: inherit; + font-size: 0.875rem; + text-decoration: none; } - -.border { - border-width: 1px; +body.paste header .action-buttons button:hover, body.paste header .action-buttons button:focus-visible, +body.paste header .action-buttons [role=button]:hover, +body.paste header .action-buttons [role=button]:focus-visible { + background-color: var(--color-bg-raised-2); + border-color: var(--color-bd-highlighted); } - -.border-bd-base { - --tw-border-opacity: 1; - border-color: rgb(51 65 85 / var(--tw-border-opacity)); -} - -.p-4 { +body.paste main pre { + background-color: var(--color-bg-raised-1); padding: 1rem; + border: 1px solid var(--color-bd-base); + border-radius: 0.75rem; + margin: 0; } -body { +body.admin-pastes main form input[type=text], +body.admin-pastes main form textarea, +body.admin-pastes main form input[type=submit] { + padding: 0.5rem 0.75rem; + border-radius: 0.5rem; + background-color: var(--color-bg-raised-1); + border: 1px solid var(--color-bd-base); + font-size: inherit; +} +body.admin-pastes main form input[type=text]:hover, body.admin-pastes main form input[type=text]:focus-visible, +body.admin-pastes main form textarea:hover, +body.admin-pastes main form textarea:focus-visible, +body.admin-pastes main form input[type=submit]:hover, +body.admin-pastes main form input[type=submit]:focus-visible { + background-color: var(--color-bg-raised-2); + border-color: var(--color-bd-highlighted); +} +body.admin-pastes main form input[type=text], +body.admin-pastes main form textarea { + width: 100%; + margin-bottom: 1rem; +} +body.admin-pastes main form textarea { + min-height: 8rem; +} +body.admin-pastes main form input[type=submit] { + cursor: pointer; margin-left: auto; - margin-right: auto; - display: flex; - max-width: 56rem; - flex-direction: column; - gap: 2rem; - --tw-bg-opacity: 1; - background-color: rgb(15 23 42 / var(--tw-bg-opacity)); - padding-left: 1rem; - padding-right: 1rem; - padding-top: 4rem; - padding-bottom: 4rem; - --tw-text-opacity: 1; - color: rgb(203 213 225 / var(--tw-text-opacity)); + display: block; } -@media not all and (min-width: 1024px) { - body { - padding-top: 2rem; - padding-bottom: 2rem; - } -} - -header { - div { - margin-bottom: 0.25rem; - } - div { - display: flex; - } - div { - gap: 0.5rem; - } - div { - font-size: 1.125rem; - line-height: 1.75rem; - } - div { - --tw-text-opacity: 1; - color: rgb(148 163 184 / var(--tw-text-opacity)); - } - h1 { - font-size: 3rem; - line-height: 1; - } - h1 { - font-weight: 800; - } - h1 { - --tw-text-opacity: 1; - color: rgb(255 255 255 / var(--tw-text-opacity)); - } -} - -footer { - text-align: center; - --tw-text-opacity: 1; - color: rgb(148 163 184 / var(--tw-text-opacity)); -} - -a.tl { - text-decoration-line: underline; -} - -a.tl:hover { - --tw-text-opacity: 1; - color: rgb(255 255 255 / var(--tw-text-opacity)); - text-decoration-line: none; -} - -a.tl:focus-visible { - --tw-text-opacity: 1; - color: rgb(255 255 255 / var(--tw-text-opacity)); - text-decoration-line: none; -} - -table { - table-layout: auto; - border-collapse: collapse; - border-width: 1px; - --tw-border-opacity: 1; - border-color: rgb(51 65 85 / var(--tw-border-opacity)); - thead tr th { - border-width: 1px; - } - thead tr th { - --tw-border-opacity: 1; - border-color: rgb(51 65 85 / var(--tw-border-opacity)); - } - thead tr th { - padding-left: 0.5rem; - padding-right: 0.5rem; - } - thead tr th { - padding-top: 0.25rem; - padding-bottom: 0.25rem; - } - thead tr th { - text-align: left; - } - tbody tr td { - border-width: 1px; - } - tbody tr td { - --tw-border-opacity: 1; - border-color: rgb(51 65 85 / var(--tw-border-opacity)); - } - tbody tr td { - padding-left: 0.5rem; - padding-right: 0.5rem; - } - tbody tr td { - padding-top: 0.25rem; - padding-bottom: 0.25rem; - } -} - -form fieldset { - display: flex; - flex-direction: column; - gap: 1rem; - border-radius: 0.75rem; - border-width: 1px; - --tw-border-opacity: 1; - border-color: rgb(51 65 85 / var(--tw-border-opacity)); - padding: 1rem; - padding-top: 0.5rem; - input[type="text"], - textarea { - border-radius: 0.5rem; - } - input[type="text"], - textarea { - border-width: 1px; - } - input[type="text"], - textarea { - --tw-border-opacity: 1; - border-color: rgb(51 65 85 / var(--tw-border-opacity)); - } - input[type="text"], - textarea { - background-color: transparent; - } - input[type="text"], - textarea { - padding-left: 0.75rem; - padding-right: 0.75rem; - } - input[type="text"], - textarea { - padding-top: 0.5rem; - padding-bottom: 0.5rem; - } - input[type="text"]:hover, - textarea:hover { - --tw-border-opacity: 1; - border-color: rgb(100 116 139 / var(--tw-border-opacity)); - } - input[type="text"]:focus-visible, - textarea:focus-visible { - --tw-border-opacity: 1; - border-color: rgb(100 116 139 / var(--tw-border-opacity)); - } - input[type="submit"] { - margin-left: auto; - } - input[type="submit"] { - cursor: pointer; - } - input[type="submit"] { - border-radius: 0.5rem; - } - input[type="submit"] { - border-width: 1px; - } - input[type="submit"] { - --tw-border-opacity: 1; - border-color: rgb(51 65 85 / var(--tw-border-opacity)); - } - input[type="submit"] { - padding-left: 0.75rem; - padding-right: 0.75rem; - } - input[type="submit"] { - padding-top: 0.5rem; - padding-bottom: 0.5rem; - } - input[type="submit"]:hover { - --tw-border-opacity: 1; - border-color: rgb(100 116 139 / var(--tw-border-opacity)); - } - input[type="submit"]:focus-visible { - --tw-border-opacity: 1; - border-color: rgb(100 116 139 / var(--tw-border-opacity)); - } -} +/*# sourceMappingURL=style.css.map */ diff --git a/static/style.css.map b/static/style.css.map new file mode 100644 index 0000000..1846048 --- /dev/null +++ b/static/style.css.map @@ -0,0 +1 @@ +{"version":3,"sourceRoot":"","sources":["../styles/tailwind/_colors.scss","../styles/tailwind/_spacing.scss","../styles/_theme.scss","../styles/tailwind/_border-radius.scss","../styles/style.scss","../styles/tailwind/_text.scss"],"names":[],"mappings":"AAAA;ACAA;AAAA;AAAA;AAOA;ACHA;EACE;;;AAGF;AACA;AACE;EACA;EACA;EACA;AAEA;EACA;EACA;EACA;AAEA;EACA;EACA;;AAEA;EAfF;AAgBI;IACA;IACA;IACA;AAEA;IACA;IACA;IACA;AAEA;IACA;IACA;;;;ACrCJ;ACKA;EACI;;;AAGJ;EAEI;EACA;EACA;EACA;EACA;EACA;;AAEA;EACI,WHDQ;;AGIZ;EAbJ;IAcQ;;;AAGJ;EACI;;AAEA;EACI;EACA;EACA,WC1BI;ED2BJ,aCEY;;ADEpB;EACI;EACA;EACA;;;AAKJ;EACI;EACA;EACA;;AAEA;EACI;EACA;EACA;;AAEA;AAAA;EAEI;EACA;EACA;EACA,eDvDR;ECwDQ;EACA;EACA,WC9DD;ED+DC;;AAEA;AAAA;AAAA;EAEI;EACA;;AAOZ;EAEI;EACA;EACA;EACA,eD3EJ;EC4EI;;;AAOJ;AAAA;AAAA;EAGI;EACA,eDxFJ;ECyFI;EACA;EACA;;AAEA;AAAA;AAAA;AAAA;AAAA;EAEI;EACA;;AAIR;AAAA;EAEI;EACA;;AAGJ;EACI;;AAGJ;EACI;EACA;EACA","file":"style.css"} \ No newline at end of file diff --git a/styles/_theme.scss b/styles/_theme.scss new file mode 100644 index 0000000..13afbff --- /dev/null +++ b/styles/_theme.scss @@ -0,0 +1,53 @@ +@use "tailwind/colors"; +@use "tailwind/spacing"; +@use "tailwind/text"; + +html { + color-scheme: light dark; +} + +/* These need switchable client-side */ +:root { + /* Foreground */ + --color-fg-base: #{colors.$slate-700}; + --color-fg-deemphasized: #{colors.$slate-600}; + --color-fg-headings: #{colors.$slate-900}; + + /* Background */ + --color-bg-base: #{colors.$slate-100}; + --color-bg-raised-1: #{colors.$slate-200}; + --color-bg-raised-2: #{colors.$slate-300}; + + /* Borders */ + --color-bd-base: #{colors.$slate-300}; + --color-bd-highlighted: #{colors.$slate-500}; + + @media (prefers-color-scheme: dark) { + /* Foreground */ + --color-fg-base: #{colors.$slate-300}; + --color-fg-deemphasized: #{colors.$slate-400}; + --color-fg-headings: #{colors.$slate-100}; + + /* Background */ + --color-bg-base: #{colors.$slate-900}; + --color-bg-raised-1: #{colors.$slate-800}; + --color-bg-raised-2: #{colors.$slate-700}; + + /* Borders */ + --color-bd-base: #{colors.$slate-700}; + --color-bd-highlighted: #{colors.$slate-500}; + } +} + +@mixin heading($disable-margin: false) { + color: var(--color-fg-headings); + @if $disable-margin { + margin: 0; + } +} + +@mixin heading2($disable-margin: false) { + @include heading($disable-margin); + font-size: text.$font-size-4xl; + font-weight: text.$font-weight-bold; +} diff --git a/styles/style.scss b/styles/style.scss new file mode 100644 index 0000000..eb5f7b1 --- /dev/null +++ b/styles/style.scss @@ -0,0 +1,138 @@ +@use "theme"; +@use "tailwind/border-radius"; +@use "tailwind/spacing"; +@use "tailwind/text"; + +* { + box-sizing: border-box; +} + +body { + // @apply flex flex-col gap-8 px-4 py-16 mx-auto max-w-4xl bg-slate-900 text-fg-base max-lg:py-8; + font-family: Inter, "Inter Variable", sans-serif; + color: var(--color-fg-base); + background-color: var(--color-bg-base); + padding: spacing.s(16) spacing.s(8); + margin: 0 auto; + max-width: spacing.$max-width-4xl; + + &.wide { + max-width: spacing.$max-width-6xl; + } + + @media not all and (min-width: var(--max-width-lg)) { + padding: spacing.s(8); + } + + header { + margin-bottom: spacing.s(8); + + h1 { + margin: 0; + color: var(--color-fg-headings); + font-size: text.$font-size-3xl; + font-weight: text.$font-weight-extrabold; + } + } + + footer { + color: var(--color-fg-deemphasized); + margin-top: spacing.s(8); + text-align: center; + } +} + +body.paste { + header { + display: flex; + justify-content: space-between; + align-items: end; + + .action-buttons { + display: flex; + justify-content: end; + gap: spacing.s(2); + + button, + [role="button"] { + background-color: var(--color-bg-raised-1); + padding: spacing.s(1) spacing.s(3); + border: 1px solid var(--color-bd-base); + border-radius: border-radius.$br-lg; + cursor: pointer; + color: inherit; + font-size: text.$font-size-sm; + text-decoration: none; + + &:hover, + &:focus-visible { + background-color: var(--color-bg-raised-2); + border-color: var(--color-bd-highlighted); + } + } + } + } + + main { + pre { + // pre class="p-4 border border-bd-base rounded-xl" { (r.content) } + background-color: var(--color-bg-raised-1); + padding: spacing.s(4); + border: 1px solid var(--color-bd-base); + border-radius: border-radius.$br-xl; + margin: 0; + } + } +} + +body.admin-pastes { + main form { + input[type="text"], + textarea, + input[type="submit"] { + padding: spacing.s(2) spacing.s(3); + border-radius: border-radius.$br-lg; + background-color: var(--color-bg-raised-1); + border: 1px solid var(--color-bd-base); + font-size: inherit; + + &:hover, + &:focus-visible { + background-color: var(--color-bg-raised-2); + border-color: var(--color-bd-highlighted); + } + } + + input[type="text"], + textarea { + width: 100%; + margin-bottom: spacing.s(4); + } + + textarea { + min-height: spacing.s(32); + } + + input[type="submit"] { + cursor: pointer; + margin-left: auto; + display: block; + } + } +} + +a.tl { + // @apply underline hover:no-underline hover:text-white focus-visible:no-underline focus-visible:text-white; +} + +table { + // @apply table-auto border-collapse border border-bd-base; + + thead tr th { + // @apply border border-bd-base px-2 py-1 text-left; + } + + tbody tr td { + // @apply border border-bd-base px-2 py-1; + } +} diff --git a/styles/tailwind/_border-radius.scss b/styles/tailwind/_border-radius.scss new file mode 100644 index 0000000..bba9500 --- /dev/null +++ b/styles/tailwind/_border-radius.scss @@ -0,0 +1,10 @@ +/* https://github.com/tailwindlabs/tailwindcss/blob/ac6d4a6e8e9ae7ca197bf98d933ae2f205be3635/packages/tailwindcss/src/compat/default-theme.ts#L162 */ +$br-none: 0px; +$br-sm: 0.125rem; +$br-default: 0.25rem; +$br-md: 0.375rem; +$br-lg: 0.5rem; +$br-xl: 0.75rem; +$br-2xl: 1rem; +$br-3xl: 1.5rem; +$br-full: 9999px; diff --git a/styles/tailwind/_colors.scss b/styles/tailwind/_colors.scss new file mode 100644 index 0000000..a24d81e --- /dev/null +++ b/styles/tailwind/_colors.scss @@ -0,0 +1,12 @@ +/* Tailwind palette */ +$slate-50: #f8fafc; +$slate-100: #f1f5f9; +$slate-200: #e2e8f0; +$slate-300: #cbd5e1; +$slate-400: #94a3b8; +$slate-500: #64748b; +$slate-600: #475569; +$slate-700: #334155; +$slate-800: #1e293b; +$slate-900: #0f172a; +$slate-950: #020617; diff --git a/styles/tailwind/_max-width.scss b/styles/tailwind/_max-width.scss new file mode 100644 index 0000000..e69de29 diff --git a/styles/tailwind/_screens.scss b/styles/tailwind/_screens.scss new file mode 100644 index 0000000..f9d2bd2 --- /dev/null +++ b/styles/tailwind/_screens.scss @@ -0,0 +1,6 @@ +/* https://github.com/tailwindlabs/tailwindcss/blob/ac6d4a6e8e9ae7ca197bf98d933ae2f205be3635/packages/tailwindcss/src/compat/default-theme.ts#L885 */ +$screen-sm: 640px; +$screen-md: 768px; +$screen-lg: 1024px; +$screen-xl: 1280px; +$screen-2xl: 1536px; diff --git a/styles/tailwind/_spacing.scss b/styles/tailwind/_spacing.scss new file mode 100644 index 0000000..59697b6 --- /dev/null +++ b/styles/tailwind/_spacing.scss @@ -0,0 +1,25 @@ +/* Yes, it's that simple. + * https://tailwindcss.com/docs/customizing-spacing#default-spacing-scale + * https://github.com/tailwindlabs/tailwindcss/blob/ac6d4a6e8e9ae7ca197bf98d933ae2f205be3635/packages/tailwindcss/src/compat/default-theme.ts#L909 */ +@function s($n) { + @return 0.25rem * $n; +} + +/* https://github.com/tailwindlabs/tailwindcss/blob/ac6d4a6e8e9ae7ca197bf98d933ae2f205be3635/packages/tailwindcss/src/compat/default-theme.ts#L715 */ +$max-width-none: none; +$max-width-xs: 20rem; +$max-width-sm: 24rem; +$max-width-md: 28rem; +$max-width-lg: 32rem; +$max-width-xl: 36rem; +$max-width-2xl: 42rem; +$max-width-3xl: 48rem; +$max-width-4xl: 56rem; +$max-width-5xl: 64rem; +$max-width-6xl: 72rem; +$max-width-7xl: 80rem; +$max-width-full: 100%; +$max-width-min: min-content; +$max-width-max: max-content; +$max-width-fit: fit-content; +$max-width-prose: 65ch; diff --git a/styles/tailwind/_text.scss b/styles/tailwind/_text.scss new file mode 100644 index 0000000..e8047b4 --- /dev/null +++ b/styles/tailwind/_text.scss @@ -0,0 +1,37 @@ +$font-size-xs: 0.75rem; +$font-size-sm: 0.875rem; +$font-size-base: 1rem; +$font-size-lg: 1.125rem; +$font-size-xl: 1.25rem; +$font-size-2xl: 1.5rem; +$font-size-3xl: 1.875rem; +$font-size-4xl: 2.25rem; +$font-size-5xl: 3rem; +$font-size-6xl: 3.75rem; +$font-size-7xl: 4.5rem; +$font-size-8xl: 6rem; +$font-size-9xl: 8rem; + +$line-height-xs: 1rem; +$line-height-sm: 1.25rem; +$line-height-base: 1.5rem; +$line-height-lg: 1.75rem; +$line-height-xl: 1.75rem; +$line-height-2xl: 2rem; +$line-height-3xl: 2.25rem; +$line-height-4xl: 2.5rem; +$line-height-5xl: 1; +$line-height-6xl: 1; +$line-height-7xl: 1; +$line-height-8xl: 1; +$line-height-9xl: 1; + +$font-weight-thin: 100; +$font-weight-extralight: 200; +$font-weight-light: 300; +$font-weight-normal: 400; +$font-weight-medium: 500; +$font-weight-semibold: 600; +$font-weight-bold: 700; +$font-weight-extrabold: 800; +$font-weight-black: 900; diff --git a/tailwind.config.js b/tailwind.config.js deleted file mode 100644 index f33e954..0000000 --- a/tailwind.config.js +++ /dev/null @@ -1,34 +0,0 @@ -/** @type {import("tailwindcss/colors")} */ -const colors = require("tailwindcss/colors"); - -/** @type {import("tailwindcss").Config} */ -module.exports = { - content: ["./src/app/pages/**/*.rs"], - theme: { - fontFamily: { - sans: ["sans-serif"], - mono: ["monospace"], - }, - extend: { - colors: { - fg: { - base: colors.slate[300], - deemphasized: colors.slate[400], - headings: colors.white, - }, - bg: { - base: colors.slate[900], - raised: { - // backgrounds - 1: colors.slate[800], - 2: colors.slate[700], - }, - }, - bd: { - base: colors.slate[700], - highlighted: colors.slate[500], - }, - }, - }, - }, -}; diff --git a/templates/admin/base.html b/templates/admin/base.html new file mode 100644 index 0000000..bf36271 --- /dev/null +++ b/templates/admin/base.html @@ -0,0 +1,12 @@ +{% extends "../base.html" %} + +{% block bodyClass %}admin{% endblock %} + +{% block header %} +

{{title}}

+{% endblock %} + +{% block main %} +{{main}} +{% call super() %} +{% endblock %} diff --git a/templates/admin/paste-new.html b/templates/admin/paste-new.html new file mode 100644 index 0000000..18876c9 --- /dev/null +++ b/templates/admin/paste-new.html @@ -0,0 +1,18 @@ +{% extends "../base.html" %} + +{% block title %}Create Paste{% endblock %} + +{% block bodyClass %}admin-pastes{% endblock %} + +{% block header %} +

Create Paste

+{% endblock %} + +{% block main %} +
+ + + +
+{% call super() %} +{% endblock %} diff --git a/templates/admin/pastes.html b/templates/admin/pastes.html new file mode 100644 index 0000000..c5dafde --- /dev/null +++ b/templates/admin/pastes.html @@ -0,0 +1,12 @@ +{% extends "../base.html" %} + +{% block bodyClass %}admin-pastes{% endblock %} + +{% block header %} +

Pastes

+{% endblock %} + +{% block main %} + +{% call super() %} +{% endblock %} diff --git a/templates/base.html b/templates/base.html new file mode 100644 index 0000000..fec8387 --- /dev/null +++ b/templates/base.html @@ -0,0 +1,23 @@ + + + + + + {% block title %}{{title}}{% endblock %} | NCPN + + + + {% block head %}{% endblock %} + + +
{% block header %}{% endblock %}
+
{% block main %}{% endblock %}
+
Running NCPN v?.??
+ + diff --git a/templates/paste.html b/templates/paste.html new file mode 100644 index 0000000..3b11c05 --- /dev/null +++ b/templates/paste.html @@ -0,0 +1,16 @@ +{% extends "base.html" %} + +{% block bodyClass %}paste{% endblock %} + +{% block header %} +

{{title}}

+
+ Raw + +
+{% endblock %} + +{% block main %} +
{{content}}
+{% call super() %} +{% endblock %} diff --git a/templates/test.html b/templates/test.html new file mode 100644 index 0000000..8149be7 --- /dev/null +++ b/templates/test.html @@ -0,0 +1 @@ +Hello, {{ name }}!