Compare commits

...

35 Commits
0.1.0 ... main

Author SHA1 Message Date
Mossfet b14ff40a29 Update docs 2024-05-06 00:20:59 +01:00
TakeV 6cc291ead2 Merge pull request 'Package meowy-webring with guix' (#10) from guix into main
Reviewed-on: #10
2023-12-29 01:49:34 +00:00
TakeV 415d947c10
Remove nonguix specific bug stuff 2023-12-28 18:01:42 -05:00
TakeV 70f7c6719c
Fix alignment issue 2023-12-28 17:59:28 -05:00
TakeV 3cc2c764ea
Remove extra debug packages
Also fix that typo wtf
2023-12-28 17:52:59 -05:00
TakeV 0aad698bb8
Skip packaging phase 2023-12-28 17:48:50 -05:00
TakeV 200797c414
Enable working build for meowy-webring
Unfortunately, it fails during packaging. :(
2023-12-28 17:35:20 -05:00
TakeV c6444ab666
Add rust embed 6 2023-12-28 17:35:20 -05:00
TakeV 16eed250ca
Add simple_logger 6 2023-12-28 17:35:20 -05:00
TakeV 29865c7352
Add notify 6 2023-12-28 17:35:20 -05:00
TakeV e9f26e3b7a
Add rust-directories-5 2023-12-28 17:35:20 -05:00
TakeV 4ea0872ef1
Add askama-rocket 2023-12-28 17:35:20 -05:00
TakeV 7e8650744b
Add rocket-0.5 2023-12-28 17:35:19 -05:00
TakeV 2990f45d11
Update manifest to only use dev tools 2023-12-28 17:34:53 -05:00
TakeV 0b9abd61dc
I have no idea 2023-12-28 13:01:31 -05:00
TakeV 9bc7a2fb74
Add dir-local.el 2023-08-20 20:56:39 -07:00
TakeV 9f9d695611
Add guix channel 2023-08-20 20:56:32 -07:00
TakeV 486ffacbef
Add manifest.scm 2023-08-20 20:56:23 -07:00
TakeV 6bc2801044
Add meowy-webring guix file 2023-08-20 20:56:08 -07:00
TakeV d5b719a909
Add crates-io, for packages not yet imported into guix 2023-08-20 20:55:27 -07:00
TakeV ca779e67f7
Backport rust 1.71 from Fries' patch 2023-08-20 20:54:45 -07:00
mossfet 075dd95c03 Merge pull request 'seperate the hyperlegible font face out into a template and organize the crate structure' (#8) from font-style into main
Reviewed-on: #8
2023-07-13 13:09:34 +00:00
Fries 10caf581ad remove the sus println 2023-07-12 23:38:39 -07:00
Fries 60c2ac15e7 move asset stuff to its own crate
this should seperate out the asset handling code, which was practically
its own module inside the main codebase, into a little crate.
2023-07-12 22:10:08 -07:00
Fries f4e9ef6af9 seperate the hyperlegible font-face to a template
this lets me make the base html code cleaner and it lets me keep using a
seperate file for font-face stuff so the style.css is cleaner. this is
implemented by using the askama template engine with the same syntax
that was used in the style tag in base.html, but i render the template
to text instead of directly to a rocket responder and i hash it with the
sha2 crate. this hashing should only run once, at startup, so it
shouldn't be much of a performance hit.
2023-07-12 18:41:39 -07:00
Fries 0e3ffc0991 move crates out to a folder
this should make the code cleaner if we need to add more crates as it
can get messy if we keep stacking crates in the root directory
2023-07-12 17:36:39 -07:00
Fries a23a71f39f remove the md5 dependency from Cargo.toml
this never was used so it shouldn't need to be here.
2023-07-11 17:21:47 -07:00
mossfet 50d92e998a Merge pull request 'add an index page and add name functions to the API and cache busting' (#7) from index-page into main
Reviewed-on: #7
2023-07-11 11:08:07 +00:00
Fries 70bb0691d3 implement a CachedResponse Responder struct
this adds a Cache-Control header to existing responses so they can be
cached in the browser. cache busting means this cache can be immutable
as if the file changes, the filename changes, so the browser will get
new files.
2023-07-11 02:37:31 -07:00
Fries 53193d84b8 add cache busting filenames and split off assets
i abstraced the file handling out to a global static struct called
"Files" that is only written to once, in main inside a OnceLock. i also
split out asset handling into its own module folder called assets which
has all the asset handling code.

i also have a new crate called "proc_macros" which provides a attribute macro
that adds the base_template field to each struct i decorate with it
using the syn and quote crates.
2023-07-11 01:04:53 -07:00
Fries 1654821763 bump version number to 0.2.0 2023-07-09 23:31:53 -07:00
Fries 4e17ef7dff update stylesheet and clean up asset code
the stylesheet got a new update from my websites stylesheet with the
bigger font sizes and i split the hyperlegible font face css into its
own file and made the asset code cleaner.
2023-07-09 22:09:07 -07:00
Fries 74f3cd1cb4 fix a bug with the next_name function
looks like i used the previous_name logic for element of the vector i
used which is wrong.
2023-07-07 23:03:29 -07:00
Fries 6e9bbe1d60 add cors and previous and next name functions 2023-07-05 02:10:31 -07:00
Fries 79e88cb2f4 add a WIP index page 2023-07-03 23:59:56 -07:00
47 changed files with 6419 additions and 279 deletions

95
.dir-locals.el Normal file
View File

@ -0,0 +1,95 @@
;;; SPDX-License-Identifier: GPL-3.0-or-later
;; Per-directory local variables for GNU Emacs 23 and later.
((nil
. ((fill-column . 78)
(tab-width . 8)
(sentence-end-double-space . t)))
(c-mode . ((c-file-style . "gnu")))
(scheme-mode
.
((indent-tabs-mode . nil)
(eval . (put 'eval-when 'scheme-indent-function 1))
(eval . (put 'call-with-prompt 'scheme-indent-function 1))
(eval . (put 'test-assert 'scheme-indent-function 1))
(eval . (put 'test-assertm 'scheme-indent-function 1))
(eval . (put 'test-equalm 'scheme-indent-function 1))
(eval . (put 'test-equal 'scheme-indent-function 1))
(eval . (put 'test-eq 'scheme-indent-function 1))
(eval . (put 'call-with-input-string 'scheme-indent-function 1))
(eval . (put 'guard 'scheme-indent-function 1))
(eval . (put 'lambda* 'scheme-indent-function 1))
(eval . (put 'substitute* 'scheme-indent-function 1))
(eval . (put 'match-record 'scheme-indent-function 2))
;; 'modify-phases' and its keywords.
(eval . (put 'modify-phases 'scheme-indent-function 1))
(eval . (put 'replace 'scheme-indent-function 1))
(eval . (put 'add-before 'scheme-indent-function 2))
(eval . (put 'add-after 'scheme-indent-function 2))
(eval . (put 'modify-services 'scheme-indent-function 1))
(eval . (put 'with-directory-excursion 'scheme-indent-function 1))
(eval . (put 'package 'scheme-indent-function 0))
(eval . (put 'origin 'scheme-indent-function 0))
(eval . (put 'build-system 'scheme-indent-function 0))
(eval . (put 'bag 'scheme-indent-function 0))
(eval . (put 'graft 'scheme-indent-function 0))
(eval . (put 'operating-system 'scheme-indent-function 0))
(eval . (put 'file-system 'scheme-indent-function 0))
(eval . (put 'manifest-entry 'scheme-indent-function 0))
(eval . (put 'manifest-pattern 'scheme-indent-function 0))
(eval . (put 'substitute-keyword-arguments 'scheme-indent-function 1))
(eval . (put 'with-store 'scheme-indent-function 1))
(eval . (put 'with-external-store 'scheme-indent-function 1))
(eval . (put 'with-error-handling 'scheme-indent-function 0))
(eval . (put 'with-mutex 'scheme-indent-function 1))
(eval . (put 'with-atomic-file-output 'scheme-indent-function 1))
(eval . (put 'call-with-compressed-output-port 'scheme-indent-function 2))
(eval . (put 'call-with-decompressed-port 'scheme-indent-function 2))
(eval . (put 'call-with-gzip-input-port 'scheme-indent-function 1))
(eval . (put 'call-with-gzip-output-port 'scheme-indent-function 1))
(eval . (put 'call-with-lzip-input-port 'scheme-indent-function 1))
(eval . (put 'call-with-lzip-output-port 'scheme-indent-function 1))
(eval . (put 'signature-case 'scheme-indent-function 1))
(eval . (put 'emacs-batch-eval 'scheme-indent-function 0))
(eval . (put 'emacs-batch-edit-file 'scheme-indent-function 1))
(eval . (put 'emacs-substitute-sexps 'scheme-indent-function 1))
(eval . (put 'emacs-substitute-variables 'scheme-indent-function 1))
(eval . (put 'with-derivation-narinfo 'scheme-indent-function 1))
(eval . (put 'with-derivation-substitute 'scheme-indent-function 2))
(eval . (put 'with-status-report 'scheme-indent-function 1))
(eval . (put 'with-status-verbosity 'scheme-indent-function 1))
(eval . (put 'mlambda 'scheme-indent-function 1))
(eval . (put 'mlambdaq 'scheme-indent-function 1))
(eval . (put 'syntax-parameterize 'scheme-indent-function 1))
(eval . (put 'with-monad 'scheme-indent-function 1))
(eval . (put 'mbegin 'scheme-indent-function 1))
(eval . (put 'mwhen 'scheme-indent-function 1))
(eval . (put 'munless 'scheme-indent-function 1))
(eval . (put 'mlet* 'scheme-indent-function 2))
(eval . (put 'mlet 'scheme-indent-function 2))
(eval . (put 'run-with-store 'scheme-indent-function 1))
(eval . (put 'run-with-state 'scheme-indent-function 1))
(eval . (put 'wrap-program 'scheme-indent-function 1))
(eval . (put 'with-imported-modules 'scheme-indent-function 1))
(eval . (put 'with-extensions 'scheme-indent-function 1))
(eval . (put 'with-database 'scheme-indent-function 2))
(eval . (put 'call-with-transaction 'scheme-indent-function 2))
(eval . (put 'call-with-container 'scheme-indent-function 1))
(eval . (put 'container-excursion 'scheme-indent-function 1))
(eval . (put 'eventually 'scheme-indent-function 1))
(eval . (put 'call-with-progress-reporter 'scheme-indent-function 1))
;; This notably allows '(' in Paredit to not insert a space when the
;; preceding symbol is one of these.
(eval . (modify-syntax-entry ?~ "'"))
(eval . (modify-syntax-entry ?$ "'"))
(eval . (modify-syntax-entry ?+ "'"))))
(emacs-lisp-mode . ((indent-tabs-mode . nil)))
(texinfo-mode . ((indent-tabs-mode . nil)
(fill-column . 72))))

9
.guix-channel Normal file
View File

@ -0,0 +1,9 @@
(channel
(version 0)
(directory ".guix/modules"))
;;; Local Variables:
;;; mode: scheme
;;; End:

5393
.guix/modules/crates-io.scm Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,42 @@
(load "crates-io.scm")
(define-module (meowy-webring)
#:use-module (crates-io)
#:use-module (guix)
#:use-module (guix build-system cargo)
#:use-module (guix git-download)
#:use-module ((guix licenses) #:prefix license:)
#:use-module (gnu packages)
#:use-module (gnu packages crates-io)
#:use-module (srfi srfi-1))
(define (keep-file? file stat)
(or (git-predicate (current-source-directory))
(const #t)))
(define-public meowy-webring
(package
(name "meowy-webring")
(version "0.1.0-git")
(source (local-file "../.." "meowy-webring-checkout"
#:recursive? #t
#:select? keep-file?))
(build-system cargo-build-system)
(arguments (list #:cargo-inputs `(("rust-askama-rocket" ,rust-askama-rocket-0.12)
("rust-askama" ,rust-askama-0.12)
("rust-directories" ,rust-directories-5)
("rust-embed" ,rust-embed-6)
("rust-hex" ,rust-hex-0.4)
("rust-notify" ,rust-notify-6)
("rust-rocket" ,rust-rocket-0.5)
("rust-serde" ,rust-serde-1)
("rust-serde-json" ,rust-serde-json-1)
("rust-simple-logger" ,rust-simple-logger-4))
#:install-source? #f
#:phases #~(modify-phases %standard-phases
(delete 'package))))
(synopsis "")
(description "")
(home-page "")
(license license:cc0)))
meowy-webring

215
Cargo.lock generated
View File

@ -68,8 +68,9 @@ dependencies = [
[[package]]
name = "askama"
version = "0.12.0"
source = "git+https://github.com/djc/askama.git?rev=b9e51601560398766eac445517fb17c35090a952#b9e51601560398766eac445517fb17c35090a952"
version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b79091df18a97caea757e28cd2d5fda49c6cd4bd01ddffd7ff01ace0c0ad2c28"
dependencies = [
"askama_derive",
"askama_escape",
@ -77,12 +78,13 @@ dependencies = [
[[package]]
name = "askama_derive"
version = "0.12.1"
source = "git+https://github.com/djc/askama.git?rev=b9e51601560398766eac445517fb17c35090a952#b9e51601560398766eac445517fb17c35090a952"
version = "0.12.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "19fe8d6cb13c4714962c072ea496f3392015f0989b1a2847bb4b2d9effd71d83"
dependencies = [
"askama_parser",
"mime",
"mime_guess",
"nom",
"proc-macro2",
"quote",
"syn",
@ -91,12 +93,23 @@ dependencies = [
[[package]]
name = "askama_escape"
version = "0.10.3"
source = "git+https://github.com/djc/askama.git?rev=b9e51601560398766eac445517fb17c35090a952#b9e51601560398766eac445517fb17c35090a952"
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 = "askama_rocket"
version = "0.12.0"
source = "git+https://github.com/djc/askama.git?rev=b9e51601560398766eac445517fb17c35090a952#b9e51601560398766eac445517fb17c35090a952"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ebf814a0f98928b2ea4a0625ad7563d737ecf0707260b8360f4ad2a4b51918e6"
dependencies = [
"askama",
"rocket",
@ -268,9 +281,9 @@ checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7"
[[package]]
name = "cookie"
version = "0.17.0"
version = "0.18.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7efb37c3e1ccb1ff97164ad95ac1606e8ccd35b3fa0a7d99a304c7f4a428cc24"
checksum = "4ddef33a339a91ea89fb53151bd0a4689cfce27055c291dfa69945475d22c747"
dependencies = [
"percent-encoding",
"time",
@ -563,12 +576,6 @@ version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b"
[[package]]
name = "hashbrown"
version = "0.12.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
[[package]]
name = "hashbrown"
version = "0.14.0"
@ -596,6 +603,12 @@ version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286"
[[package]]
name = "hex"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
[[package]]
name = "http"
version = "0.2.9"
@ -653,17 +666,6 @@ dependencies = [
"want",
]
[[package]]
name = "indexmap"
version = "1.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99"
dependencies = [
"autocfg",
"hashbrown 0.12.3",
"serde",
]
[[package]]
name = "indexmap"
version = "2.0.0"
@ -671,7 +673,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d5477fe2230a79769d8dc68e0eabf5437907c0457a5614a9e8dddb67f65eb65d"
dependencies = [
"equivalent",
"hashbrown 0.14.0",
"hashbrown",
"serde",
]
[[package]]
@ -722,14 +725,13 @@ dependencies = [
[[package]]
name = "is-terminal"
version = "0.4.7"
version = "0.4.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "adcf93614601c8129ddf72e2d5633df827ba6551541c6d8c59520a371475be1f"
checksum = "f23ff5ef2b80d608d61efee834934d862cd92461afc0560dedf493e4c033738b"
dependencies = [
"hermit-abi 0.3.1",
"io-lifetimes",
"rustix",
"windows-sys 0.48.0",
"libc",
"windows-sys 0.52.0",
]
[[package]]
@ -823,15 +825,26 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
[[package]]
name = "meowy-webring"
name = "meowy-assets"
version = "0.1.0"
dependencies = [
"askama",
"askama_rocket",
"log",
"notify",
"hex",
"proc_macros",
"rocket",
"rust-embed",
"sha2",
"shared",
]
[[package]]
name = "meowy-webring"
version = "0.2.0"
dependencies = [
"meowy-assets",
"notify",
"rocket",
"serde",
"serde_json",
"shared",
@ -1006,7 +1019,7 @@ checksum = "0ec95680a7087503575284e5063e14b694b7a9c0b065e5dceec661e0497127e8"
dependencies = [
"inlinable_string",
"pear_codegen",
"yansi",
"yansi 0.5.1",
]
[[package]]
@ -1064,7 +1077,15 @@ dependencies = [
"quote",
"syn",
"version_check",
"yansi",
"yansi 0.5.1",
]
[[package]]
name = "proc_macros"
version = "0.1.0"
dependencies = [
"quote",
"syn",
]
[[package]]
@ -1187,9 +1208,9 @@ checksum = "436b050e76ed2903236f032a59761c1eb99e1b0aead2c257922771dab1fc8c78"
[[package]]
name = "rocket"
version = "0.5.0-rc.3"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "58734f7401ae5cfd129685b48f61182331745b357b96f2367f01aebaf1cc9cc9"
checksum = "9e7bb57ccb26670d73b6a47396c83139447b9e7878cab627fdfe9ea8da489150"
dependencies = [
"async-stream",
"async-trait",
@ -1199,8 +1220,7 @@ dependencies = [
"either",
"figment",
"futures",
"indexmap 1.9.3",
"is-terminal",
"indexmap",
"log",
"memchr",
"multer",
@ -1221,37 +1241,38 @@ dependencies = [
"tokio-util",
"ubyte",
"version_check",
"yansi",
"yansi 1.0.1",
]
[[package]]
name = "rocket_codegen"
version = "0.5.0-rc.3"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7093353f14228c744982e409259fb54878ba9563d08214f2d880d59ff2fc508b"
checksum = "a2238066abf75f21be6cd7dc1a09d5414a671f4246e384e49fe3f8a4936bd04c"
dependencies = [
"devise",
"glob",
"indexmap 1.9.3",
"indexmap",
"proc-macro2",
"quote",
"rocket_http",
"syn",
"unicode-xid",
"version_check",
]
[[package]]
name = "rocket_http"
version = "0.5.0-rc.3"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "936012c99162a03a67f37f9836d5f938f662e26f2717809761a9ac46432090f4"
checksum = "37a1663694d059fe5f943ea5481363e48050acedd241d46deb2e27f71110389e"
dependencies = [
"cookie",
"either",
"futures",
"http",
"hyper",
"indexmap 1.9.3",
"indexmap",
"log",
"memchr",
"pear",
@ -1403,6 +1424,16 @@ dependencies = [
"cfg-if",
"cpufeatures",
"digest",
"sha2-asm",
]
[[package]]
name = "sha2-asm"
version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bf27176fb5d15398e3a479c652c20459d9dac830dedd1fa55b42a77dbcdbfcea"
dependencies = [
"cc",
]
[[package]]
@ -1485,9 +1516,9 @@ dependencies = [
[[package]]
name = "state"
version = "0.5.3"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dbe866e1e51e8260c9eed836a042a5e7f6726bb2b411dffeaa712e19c388f23b"
checksum = "2b8c4a4445d81357df8b1a650d0d0d6fbbbfe99d064aa5e02f3e4022061476d8"
dependencies = [
"loom",
]
@ -1660,7 +1691,7 @@ version = "0.19.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "266f016b7f039eec8a1a80dfe6156b633d208b9fccca5e4db1d6775b0c4e34a7"
dependencies = [
"indexmap 2.0.0",
"indexmap",
"serde",
"serde_spanned",
"toml_datetime",
@ -1903,6 +1934,15 @@ dependencies = [
"windows-targets 0.48.1",
]
[[package]]
name = "windows-sys"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
dependencies = [
"windows-targets 0.52.5",
]
[[package]]
name = "windows-targets"
version = "0.42.2"
@ -1933,6 +1973,22 @@ dependencies = [
"windows_x86_64_msvc 0.48.0",
]
[[package]]
name = "windows-targets"
version = "0.52.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb"
dependencies = [
"windows_aarch64_gnullvm 0.52.5",
"windows_aarch64_msvc 0.52.5",
"windows_i686_gnu 0.52.5",
"windows_i686_gnullvm",
"windows_i686_msvc 0.52.5",
"windows_x86_64_gnu 0.52.5",
"windows_x86_64_gnullvm 0.52.5",
"windows_x86_64_msvc 0.52.5",
]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.42.2"
@ -1945,6 +2001,12 @@ version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc"
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.52.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263"
[[package]]
name = "windows_aarch64_msvc"
version = "0.42.2"
@ -1957,6 +2019,12 @@ version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3"
[[package]]
name = "windows_aarch64_msvc"
version = "0.52.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6"
[[package]]
name = "windows_i686_gnu"
version = "0.42.2"
@ -1969,6 +2037,18 @@ version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241"
[[package]]
name = "windows_i686_gnu"
version = "0.52.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670"
[[package]]
name = "windows_i686_gnullvm"
version = "0.52.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9"
[[package]]
name = "windows_i686_msvc"
version = "0.42.2"
@ -1981,6 +2061,12 @@ version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00"
[[package]]
name = "windows_i686_msvc"
version = "0.52.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf"
[[package]]
name = "windows_x86_64_gnu"
version = "0.42.2"
@ -1993,6 +2079,12 @@ version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1"
[[package]]
name = "windows_x86_64_gnu"
version = "0.52.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.42.2"
@ -2005,6 +2097,12 @@ version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.52.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596"
[[package]]
name = "windows_x86_64_msvc"
version = "0.42.2"
@ -2017,6 +2115,12 @@ version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a"
[[package]]
name = "windows_x86_64_msvc"
version = "0.52.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0"
[[package]]
name = "winnow"
version = "0.4.7"
@ -2031,3 +2135,12 @@ name = "yansi"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec"
[[package]]
name = "yansi"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049"
dependencies = [
"is-terminal",
]

View File

@ -1,47 +1,30 @@
[workspace]
members = ["cli", "shared"]
members = ["crates/*"]
[package]
name = "meowy-webring"
version = "0.1.0"
version = "0.2.0"
edition = "2021"
rust-version = "1.70"
[profile.release]
lto = "thin"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
log = "0.4"
[dependencies.rocket]
version = "=0.5.0-rc.3"
default_features = false
version = "0.5.0"
default-features = false
features = ["json"]
[dependencies.rust-embed]
version = "6"
features = ["debug-embed"]
[dependencies.serde]
version = "1.0"
[dependencies.serde_json]
version = "1.0"
[dependencies.askama_rocket]
git = "https://github.com/djc/askama.git"
package = "askama_rocket"
rev = "b9e51601560398766eac445517fb17c35090a952"
default-features = false
[dependencies.askama]
git = "https://github.com/djc/askama.git"
package = "askama"
rev = "b9e51601560398766eac445517fb17c35090a952"
version = "0.12"
default-features = false
[dependencies.shared]
path = "./shared"
path = "./crates/shared"
[dependencies.simple_logger]
version = "4"
@ -51,3 +34,6 @@ default-features = false
version = "6"
default-features = false
features = ["macos_fsevent"]
[dependencies.meowy-assets]
path = "./crates/meowy-assets"

64
LICENSE
View File

@ -2,14 +2,14 @@ Creative Commons Legal Code
CC0 1.0 Universal
CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE
LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN
ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS
INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES
REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS
PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM
THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED
HEREUNDER.
CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE
LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN
ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS
INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES
REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS
PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM
THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED
HEREUNDER.
Statement of Purpose
@ -43,22 +43,22 @@ Related Rights"). Copyright and Related Rights include, but are not
limited to, the following:
i. the right to reproduce, adapt, distribute, perform, display,
communicate, and translate a Work;
communicate, and translate a Work;
ii. moral rights retained by the original author(s) and/or performer(s);
iii. publicity and privacy rights pertaining to a person's image or
likeness depicted in a Work;
likeness depicted in a Work;
iv. rights protecting against unfair competition in regards to a Work,
subject to the limitations in paragraph 4(a), below;
subject to the limitations in paragraph 4(a), below;
v. rights protecting the extraction, dissemination, use and reuse of data
in a Work;
in a Work;
vi. database rights (such as those arising under Directive 96/9/EC of the
European Parliament and of the Council of 11 March 1996 on the legal
protection of databases, and under any national implementation
thereof, including any amended or successor version of such
directive); and
European Parliament and of the Council of 11 March 1996 on the legal
protection of databases, and under any national implementation
thereof, including any amended or successor version of such
directive); and
vii. other similar, equivalent or corresponding rights throughout the
world based on applicable law or treaty, and any national
implementations thereof.
world based on applicable law or treaty, and any national
implementations thereof.
2. Waiver. To the greatest extent permitted by, but not in contravention
of, applicable law, Affirmer hereby overtly, fully, permanently,
@ -102,20 +102,20 @@ express Statement of Purpose.
4. Limitations and Disclaimers.
a. No trademark or patent rights held by Affirmer are waived, abandoned,
surrendered, licensed or otherwise affected by this document.
surrendered, licensed or otherwise affected by this document.
b. Affirmer offers the Work as-is and makes no representations or
warranties of any kind concerning the Work, express, implied,
statutory or otherwise, including without limitation warranties of
title, merchantability, fitness for a particular purpose, non
infringement, or the absence of latent or other defects, accuracy, or
the present or absence of errors, whether or not discoverable, all to
the greatest extent permissible under applicable law.
warranties of any kind concerning the Work, express, implied,
statutory or otherwise, including without limitation warranties of
title, merchantability, fitness for a particular purpose, non
infringement, or the absence of latent or other defects, accuracy, or
the present or absence of errors, whether or not discoverable, all to
the greatest extent permissible under applicable law.
c. Affirmer disclaims responsibility for clearing rights of other persons
that may apply to the Work or any use thereof, including without
limitation any person's Copyright and Related Rights in the Work.
Further, Affirmer disclaims responsibility for obtaining any necessary
consents, permissions or other rights required for any use of the
Work.
that may apply to the Work or any use thereof, including without
limitation any person's Copyright and Related Rights in the Work.
Further, Affirmer disclaims responsibility for obtaining any necessary
consents, permissions or other rights required for any use of the
Work.
d. Affirmer understands and acknowledges that Creative Commons is not a
party to this document and has no duty or obligation with respect to
this CC0 or use of the Work.
party to this document and has no duty or obligation with respect to
this CC0 or use of the Work.

View File

@ -0,0 +1,37 @@
[package]
name = "meowy-assets"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
hex = "0.4"
[dependencies.rocket]
version = "=0.5.0"
default-features = false
[dependencies.askama_rocket]
package = "askama_rocket"
version = "0.12"
default-features = false
[dependencies.askama]
package = "askama"
version = "0.12"
default-features = false
[dependencies.rust-embed]
version = "6"
features = ["debug-embed"]
[dependencies.sha2]
version = "0.10"
features = ["asm"]
[dependencies.shared]
path = "../shared"
[dependencies.proc_macros]
path = "../proc-macros"

View File

@ -0,0 +1,64 @@
@media (prefers-color-scheme: light) {
:root {
--background-color: #f6f5f4;
--text-color: black;
--link-color: darkblue;
}
}
@media (prefers-color-scheme: dark) {
:root {
--background-color: #191919;
--text-color: #E9E9E9;
--link-color: cyan;
}
}
:root {
--h1-font-size: 3.225rem;
--h2-font-size: 2.825rem;
--h3-font-size: 2.225rem;
--h4-font-size: 1.665rem;
--default-font-size: 1.375rem;
--h6-font-size: 1.185rem;
}
body {
font-family: "Atkinson Hyperlegible", sans-serif;
text-align: center;
font-size: var(--default-font-size);
max-width: 600px;
margin: auto;
background-color: var(--background-color);
color: var(--text-color)
}
a {
font-size: var(--default-font-size);
color: var(--link-color);
}
h1 {
font-size: var(--h1-font-size);
}
h2 {
font-size: var(--h2-font-size);
}
h3 {
font-size: var(--h3-font-size);
}
h4 {
font-size: var(--h4-font-size);
}
h5 {
font-size: var(--default-font-size);
}
h6 {
font-size: var(--h6-font-size);
}

View File

@ -0,0 +1,148 @@
use super::templates::HyperlegibleTemplate;
use askama::Template;
use rocket::http::Status;
use rust_embed::RustEmbed;
use sha2::{Digest, Sha256};
use std::{borrow::Cow, sync::OnceLock};
#[derive(RustEmbed)]
#[folder = "public/"]
struct Assets;
#[derive(Debug)]
pub struct Files {
pub style: TextFile,
pub hyperlegible: TextFile,
pub atkinson_latin_woff2: BinaryFile,
pub atkinson_latin_ext_woff2: BinaryFile,
pub atkinson_all_woff: BinaryFile,
}
#[derive(Debug, Clone)]
pub struct FileMetadata {
pub filename: String,
pub extension: String,
pub hash: String,
}
impl FileMetadata {
pub fn get_hash_filename(&self) -> String {
let mut hash = self.hash.clone();
hash.truncate(8);
format!("{}.{}.{}", self.filename, hash, self.extension)
}
}
#[derive(Debug)]
pub struct BinaryFile {
pub data: Cow<'static, [u8]>,
pub metadata: FileMetadata,
}
#[derive(Debug, Clone)]
pub struct TextFile {
pub text: String,
pub metadata: FileMetadata,
}
trait GetFile {
fn get(filename: &str, extension: &str) -> Option<Self>
where
Self: Sized;
}
impl GetFile for BinaryFile {
fn get(filename: &str, extension: &str) -> Option<Self> {
match Assets::get(&format!("{}.{}", filename, extension)) {
Some(file) => {
let metadata = FileMetadata {
filename: filename.into(),
extension: extension.into(),
hash: hex::encode(file.metadata.sha256_hash()),
};
Some(BinaryFile {
data: file.data,
metadata,
})
}
None => None,
}
}
}
impl GetFile for TextFile {
fn get(filename: &str, extension: &str) -> Option<Self> {
let file = BinaryFile::get(filename, extension)?;
match std::str::from_utf8(&file.data) {
Ok(string) => Some(TextFile {
text: string.into(),
metadata: file.metadata,
}),
Err(_) => None,
}
}
}
pub static FILES: OnceLock<Files> = OnceLock::new();
pub fn get_file_wrapper() -> Result<&'static Files, Status> {
match FILES.get() {
Some(files) => Ok(files),
None => Err(Status::InternalServerError),
}
}
fn get_sha256_hash(string: &String) -> String {
let mut hasher = Sha256::new();
hasher.update(string);
let result = hasher.finalize();
hex::encode(result)
}
fn get_hyperlegible(
latin_woff2_filename: String,
latin_ext_woff2_filename: String,
all_woff_filename: String,
) -> TextFile {
let hyperlegible_template = HyperlegibleTemplate {
atkinson_latin_woff2_filename: latin_woff2_filename,
atkinson_latin_ext_woff2_filename: latin_ext_woff2_filename,
atkinson_all_woff_filename: all_woff_filename,
};
let rendered_template = hyperlegible_template.render().unwrap();
let hash = get_sha256_hash(&rendered_template);
let metadata = FileMetadata {
filename: "hyperlegible".into(),
extension: "css".into(),
hash,
};
TextFile {
text: rendered_template,
metadata,
}
}
pub fn initialize_files() {
let atkinson_latin_woff2 =
BinaryFile::get("atkinson-hyperlegible-latin-400-normal", "woff2").unwrap();
let atkinson_latin_ext_woff2 =
BinaryFile::get("atkinson-hyperlegible-latin-ext-400-normal", "woff2").unwrap();
let atkinson_all_woff =
BinaryFile::get("atkinson-hyperlegible-all-400-normal", "woff").unwrap();
let files = Files {
style: TextFile::get("style", "css").unwrap(),
hyperlegible: get_hyperlegible(
atkinson_latin_woff2.metadata.get_hash_filename(),
atkinson_latin_ext_woff2.metadata.get_hash_filename(),
atkinson_all_woff.metadata.get_hash_filename(),
),
atkinson_latin_woff2,
atkinson_latin_ext_woff2,
atkinson_all_woff,
};
FILES.set(files).unwrap();
}

View File

@ -0,0 +1,11 @@
pub mod files;
mod responders;
mod routes;
pub mod templates;
#[macro_use]
extern crate rocket;
pub use routes::style;
pub use routes::woff2_font;
pub use routes::woff_font;

View File

@ -0,0 +1,44 @@
use super::templates::ErrorTemplate;
use rocket::{
http::Header,
response::{self, Responder},
Response,
};
use std::borrow::Cow;
#[derive(Responder)]
#[response(status = 200, content_type = "font/woff2")]
pub struct RawWoff2Font(pub Cow<'static, [u8]>);
#[derive(Responder)]
#[response(status = 200, content_type = "font/woff")]
pub struct RawWoffFont(pub Cow<'static, [u8]>);
#[derive(Responder)]
pub struct ErrorTemplateResponder<'a> {
template: ErrorTemplate<'a>,
}
pub struct CachedResponse<T> {
inner: T,
}
impl<'r, T> Responder<'r, 'static> for CachedResponse<T>
where
T: Responder<'r, 'static>,
{
fn respond_to(self, request: &'r rocket::Request<'_>) -> response::Result<'static> {
Response::build_from(self.inner.respond_to(request)?)
.header(Header::new("Cache-Control", "max-age=31536000, immutable"))
.ok()
}
}
impl<'r, T> From<T> for CachedResponse<T>
where
T: Responder<'r, 'static>,
{
fn from(value: T) -> Self {
Self { inner: value }
}
}

View File

@ -0,0 +1,51 @@
use crate::{
files::get_file_wrapper,
responders::{CachedResponse, RawWoff2Font, RawWoffFont},
};
use rocket::{http::Status, response::content::RawCss};
#[get("/css/<style>")]
pub fn style(style: &str) -> Result<CachedResponse<RawCss<String>>, Status> {
let style_file = &get_file_wrapper()?.style;
let hyperlegible_file = &get_file_wrapper()?.hyperlegible;
let style_name = style_file.metadata.get_hash_filename();
let hyperlegible_name = hyperlegible_file.metadata.get_hash_filename();
if style == style_name {
Ok(RawCss::<String>(style_file.text.clone()).into())
} else if style == hyperlegible_name {
Ok(RawCss::<String>(hyperlegible_file.text.clone()).into())
} else {
Err(Status::NotFound)
}
}
#[get("/woff2/<font>")]
pub fn woff2_font(font: &str) -> Result<CachedResponse<RawWoff2Font>, Status> {
let latin_file = &get_file_wrapper()?.atkinson_latin_woff2;
let latin_ext_file = &get_file_wrapper()?.atkinson_latin_ext_woff2;
let latin = latin_file.metadata.get_hash_filename();
let latin_ext = latin_file.metadata.get_hash_filename();
if font == latin {
Ok(RawWoff2Font(latin_file.data.clone()).into())
} else if font == latin_ext {
Ok(RawWoff2Font(latin_ext_file.data.clone()).into())
} else {
Err(Status::NotFound)
}
}
#[get("/woff/<font>")]
pub fn woff_font(font: &str) -> Result<CachedResponse<RawWoffFont>, Status> {
let all_file = &get_file_wrapper()?.atkinson_all_woff;
let all = all_file.metadata.get_hash_filename();
if font == all {
Ok(RawWoffFont(all_file.data.clone()).into())
} else {
Err(Status::NotFound)
}
}

View File

@ -0,0 +1,31 @@
use askama::Template;
use proc_macros::uses_base_template;
use shared::names::Site;
pub struct BaseTemplate {
pub hyperlegible_filename: String,
pub style_filename: String,
}
#[derive(Template)]
#[template(path = "hyperlegible.css", escape = "none")]
pub(super) struct HyperlegibleTemplate {
pub atkinson_latin_woff2_filename: String,
pub atkinson_latin_ext_woff2_filename: String,
pub atkinson_all_woff_filename: String,
}
#[derive(Template)]
#[template(path = "error.html")]
#[uses_base_template]
pub struct ErrorTemplate<'a> {
pub error: &'a str,
pub error_description: &'a str,
}
#[derive(Template)]
#[template(path = "index.html")]
#[uses_base_template]
pub struct IndexTemplate {
pub sites: Vec<Site>,
}

View File

@ -0,0 +1,16 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>Meowy Webring{% block title %}{% endblock %}</title>
{% block head %}
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width">
<link rel="stylesheet" href="/public/css/{{ base_template.hyperlegible_filename }}" />
<link rel="stylesheet" href="/public/css/{{ base_template.style_filename }}" />
{% endblock %}
</head>
<body>
{% block content %}
{% endblock %}
</body>
</html>

View File

@ -0,0 +1,10 @@
{% extends "base.html" %}
{% block title %} - {{ error }}{% endblock %}
{% block content %}
<main>
<h1>{{ error }}</h1>
<p>{{ error_description }}</p>
</main>
{% endblock %}

View File

@ -0,0 +1,43 @@
@font-face {
font-family: Atkinson Hyperlegible;
font-style: normal;
font-display: swap;
font-weight: 400;
src: url("/public/woff2/{{ atkinson_latin_ext_woff2_filename }}") format("woff2"),
url("/public/woff/{{ atkinson_all_woff_filename }}") format("woff");
unicode-range: U+0100-024F,
U+0259,
U+1E00-1EFF,
U+2020,
U+20A0-20AB,
U+20AD-20CF,
U+2113,
U+2C60-2C7F,
U+A720-A7FF
}
@font-face {
font-family: Atkinson Hyperlegible;
font-style: normal;
font-display: swap;
font-weight: 400;
src: url("/public/woff2/{{ atkinson_latin_woff2_filename }}") format("woff2"),
url("/public/woff/{{ atkinson_all_woff_filename }}") format("woff");
unicode-range: U+0000-00FF,
U+0131,
U+0152-0153,
U+02BB-02BC,
U+02C6,
U+02DA,
U+02DC,
U+2000-206F,
U+2074,
U+20AC,
U+2122,
U+2191,
U+2193,
U+2212,
U+2215,
U+FEFF,
U+FFFD
}

View File

@ -0,0 +1,16 @@
{% extends "base.html" %}
{% block content %}
<main>
<h1>Meowy Webring</h1>
<h2>Sites</h2>
{% for site in sites %}
{% match site.name %}
{% when Some with (value) %}
<p><a href="https://{{ site.url }}">{{ value }}</a></p>
{% when None %}
<p><a href="https://{{ site.url }}">{{ site.url }}</a></p>
{% endmatch %}
{% endfor %}
</main>
{% endblock %}

View File

@ -0,0 +1,13 @@
[package]
name = "proc_macros"
version = "0.1.0"
edition = "2021"
[lib]
proc-macro = true
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
syn = "2.0"
quote = "1.0"

View File

@ -0,0 +1,26 @@
use proc_macro::TokenStream;
use quote::quote;
use syn::{parse::Parser, parse_macro_input, DeriveInput};
#[proc_macro_attribute]
pub fn uses_base_template(_attr: TokenStream, item: TokenStream) -> TokenStream {
let mut input = parse_macro_input!(item as DeriveInput);
let base_template_field = syn::Field::parse_named
.parse2(quote! {
pub base_template: BaseTemplate
})
.unwrap();
if let syn::Data::Struct(ref mut struct_data) = &mut input.data {
if let syn::Fields::Named(fields) = &mut struct_data.fields {
fields.named.push(base_template_field);
}
quote! {
#input
}
.into()
} else {
panic!("bad")
}
}

View File

@ -6,7 +6,7 @@ pub enum ErrorStatus {
LoggerInitializationError,
NotFoundError,
AlreadyExistsError,
GenericError
GenericError,
}
pub struct Error {

View File

@ -1,3 +1,3 @@
pub mod names;
pub mod errors;
pub mod directories;
pub mod errors;
pub mod names;

42
docs/meowy-cli.1 Normal file
View File

@ -0,0 +1,42 @@
.\" Manpage for meowy-cli
.TH man 1 "05 May 2024" "0.1.0" "meowy-cli man page"
.SH NAME
meowy-cli \- configure the entries in the meowy-webring sites list
.SH SYNOPSIS
meowy-cli [options] <command>
.SH DESCRIPTION
meowy-cli is a program for adding and removing entries in the list of URLs used by the meowy-webring webring software
.SH OPTIONS
.TP
.B -p, --path <PATH>
The path to the names.json file
.TP
.B -s, --separator <SEPARATOR>
A separator string to separate the URL from the name. Defaults to ": ".
.TP
.B -h, --help
Print help
.TP
.B -v, --version
Print version
.SH SUBCOMMANDS
.TP
.B print
Print the current webring sites and their names
.TP
.B add
Add a site to the webring
.TP
.B remove
Remove a site from the webring
.TP
.B help
Print the output of -h or the help of the given subcommand(s)
.SH EXIT STATUS
.TP
.B
0
Success

1
guix.scm Symbolic link
View File

@ -0,0 +1 @@
.guix/modules/meowy-webring.scm

10
manifest.scm Normal file
View File

@ -0,0 +1,10 @@
;; What follows is a "manifest" equivalent to the command line you gave.
;; You can store it in a file that you may then pass to any 'guix' command
;; that accepts a '--manifest' (or '-m') option.
(specifications->manifest
(list "gcc-toolchain"
"git"
"git-lfs"
"rust-cargo"
"rust"))

View File

@ -1,72 +0,0 @@
@media (prefers-color-scheme: light) {
:root {
--background-color: #f6f5f4;
--text-color: black;
--link-color: darkblue;
}
}
@media (prefers-color-scheme: dark) {
:root {
--background-color: #191919;
--text-color: #E9E9E9;
--link-color: cyan;
}
}
body {
font-family: "Atkinson Hyperlegible", sans-serif;
text-align: center;
max-width: 600px;
margin: auto;
background-color: var(--background-color);
color: var(--text-color)
}
p {
font-size: 22px;
}
@font-face {
font-family: Atkinson Hyperlegible;
font-style: normal;
font-display: swap;
font-weight: 400;
src: url(/public/woff2/atkinson-hyperlegible-latin-ext-400-normal.woff2) format("woff2"),
url(/public/woff/atkinson-hyperlegible-all-400-normal.woff) format("woff");
unicode-range: U+0100-024F,
U+0259,
U+1E00-1EFF,
U+2020,
U+20A0-20AB,
U+20AD-20CF,
U+2113,
U+2C60-2C7F,
U+A720-A7FF
}
@font-face {
font-family: Atkinson Hyperlegible;
font-style: normal;
font-display: swap;
font-weight: 400;
src: url(/public/woff2/atkinson-hyperlegible-latin-400-normal.woff2) format("woff2"),
url(/public/woff/atkinson-hyperlegible-all-400-normal.woff) format("woff");
unicode-range: U+0000-00FF,
U+0131,
U+0152-0153,
U+02BB-02BC,
U+02C6,
U+02DA,
U+02DC,
U+2000-206F,
U+2074,
U+20AC,
U+2122,
U+2191,
U+2193,
U+2212,
U+2215,
U+FEFF,
U+FFFD
}

View File

@ -1,63 +0,0 @@
use std::borrow::Cow;
use askama_rocket::Template;
use rocket::http::Status;
use rust_embed::RustEmbed;
#[derive(RustEmbed)]
#[folder = "public/"]
pub struct PublicAssets;
#[derive(Responder)]
#[response(status = 200, content_type = "font/woff2")]
pub struct RawWoff2Font(pub Cow<'static, [u8]>);
#[derive(Responder)]
#[response(status = 200, content_type = "font/woff")]
pub struct RawWoffFont(pub Cow<'static, [u8]>);
#[derive(Template)]
#[template(path = "error.html")]
pub struct ErrorTemplate<'a> {
pub error: &'a str,
pub error_description: &'a str
}
#[derive(Responder)]
pub struct ErrorTemplateResponder<'a> {
template: ErrorTemplate<'a>
}
#[get("/style.css")]
pub fn style() -> Result<rocket::response::content::RawCss<String>, Status> {
let style = PublicAssets::get("style.css").unwrap();
match std::str::from_utf8(&style.data) {
Ok(style) => Ok(rocket::response::content::RawCss::<String>(style.to_string())),
Err(_) => Err(Status::InternalServerError),
}
}
#[get("/woff2/<font>")]
pub fn woff2_font(font: &str) -> Result<RawWoff2Font, Status> {
let latin = "atkinson-hyperlegible-latin-400-normal.woff2";
let latin_ext = "atkinson-hyperlegible-latin-ext-400-normal.woff2";
if font == latin {
Ok(RawWoff2Font(PublicAssets::get(latin).unwrap().data))
} else if font == latin_ext {
Ok(RawWoff2Font(PublicAssets::get(latin_ext).unwrap().data))
} else {
Err(Status::NotFound)
}
}
#[get("/woff/<font>")]
pub fn woff_font(font: &str) -> Result<RawWoffFont, Status> {
let all = "atkinson-hyperlegible-all-400-normal.woff";
if font == all {
Ok(RawWoffFont(PublicAssets::get(all).unwrap().data))
} else {
Err(Status::NotFound)
}
}

View File

@ -17,4 +17,30 @@ pub fn next_url(source_url: &String, names: &Vec<Site>) -> Option<String> {
}
}
// TODO: previous_name, next_name
pub fn previous_name(source_url: &String, names: &Vec<Site>) -> Option<String> {
match names.iter().position(|r| &r.url == source_url) {
Some(index) if index == 0 => match &names[names.len() - 1].name {
Some(name) => Some(name.clone()),
None => previous_url(source_url, names),
},
Some(index) => match &names[index - 1].name {
Some(name) => Some(name.clone()),
None => previous_url(source_url, names),
},
None => None,
}
}
pub fn next_name(source_url: &String, names: &Vec<Site>) -> Option<String> {
match names.iter().position(|r| &r.url == source_url) {
Some(index) if index == names.len() - 1 => match &names[0].name {
Some(name) => Some(name.clone()),
None => next_url(source_url, names),
},
Some(index) => match &names[index + 1].name {
Some(name) => Some(name.clone()),
None => next_url(source_url, names),
},
None => None,
}
}

View File

@ -1,12 +1,13 @@
use crate::watcher::hot_reloading;
use meowy_assets::files::initialize_files;
use rocket::tokio;
use sites::init_names;
#[macro_use]
extern crate rocket;
mod assets;
mod links;
mod responders;
mod routes;
mod sites;
mod watcher;
@ -14,6 +15,7 @@ mod watcher;
#[launch]
async fn rocket() -> _ {
init_names().unwrap();
initialize_files();
tokio::task::spawn_blocking(hot_reloading);
rocket::build()
@ -24,6 +26,10 @@ async fn rocket() -> _ {
.register("/", catchers![routes::not_found])
.mount(
"/public",
routes![assets::style, assets::woff2_font, assets::woff_font],
routes![
meowy_assets::style,
meowy_assets::woff2_font,
meowy_assets::woff_font
],
)
}

25
src/responders.rs Normal file
View File

@ -0,0 +1,25 @@
use rocket::{http::Header, response::Responder, Response};
pub struct CorsResponse<T> {
pub inner: T,
}
impl<'r, T> Responder<'r, 'static> for CorsResponse<T>
where
T: Responder<'r, 'static>,
{
fn respond_to(self, request: &'r rocket::Request<'_>) -> rocket::response::Result<'static> {
Response::build_from(self.inner.respond_to(request)?)
.header(Header::new("Access-Control-Allow-Origin", "*"))
.ok()
}
}
impl<'r, T> From<T> for CorsResponse<T>
where
T: Responder<'r, 'static>,
{
fn from(value: T) -> Self {
Self { inner: value }
}
}

View File

@ -1,19 +1,45 @@
use crate::{
assets::ErrorTemplate,
links::{next_url, previous_url},
links::{next_name, next_url, previous_name, previous_url},
responders::CorsResponse,
sites::get_global_names,
};
use meowy_assets::{
files::{get_file_wrapper, FileMetadata},
templates::{BaseTemplate, ErrorTemplate, IndexTemplate},
};
use rocket::{
http::Status,
response::Redirect,
serde::{json::Json, Serialize},
};
const NOT_FOUND_ERROR: ErrorTemplate = ErrorTemplate {
error: "Not Found",
error_description: "this URL could not be found on the webring.",
};
fn get_hash_filename(metadata: &FileMetadata) -> Result<String, Status> {
Ok(metadata.get_hash_filename())
}
fn get_base_template() -> Result<BaseTemplate, Status> {
let files = get_file_wrapper()?;
let hyperlegible_filename = get_hash_filename(&files.hyperlegible.metadata)?;
let style_filename = get_hash_filename(&files.style.metadata)?;
let template = BaseTemplate {
hyperlegible_filename,
style_filename,
};
Ok(template)
}
fn not_found_error() -> Result<ErrorTemplate<'static>, Status> {
let base_template = get_base_template()?;
let template = ErrorTemplate {
error: "Not Found",
error_description: "this URL could not be found on the webring.",
base_template,
};
Ok(template)
}
#[derive(Serialize)]
#[serde(crate = "rocket::serde")]
@ -23,8 +49,13 @@ pub struct JsonResponse {
}
#[get("/")]
pub fn index() -> &'static str {
"Like, this is a webring, meow!"
pub async fn index() -> Result<IndexTemplate, Status> {
let base_template = get_base_template()?;
let template = IndexTemplate {
sites: get_global_names().await,
base_template,
};
Ok(template)
}
#[get("/previous?<source_url>")]
@ -44,9 +75,9 @@ pub async fn next(source_url: String) -> Result<Redirect, Status> {
}
#[get("/name?<source_url>")]
pub async fn name(source_url: String) -> Result<Json<JsonResponse>, Status> {
let previous_site_name = previous_url(&source_url, &get_global_names().await);
let next_site_name = next_url(&source_url, &get_global_names().await);
pub async fn name(source_url: String) -> Result<CorsResponse<Json<JsonResponse>>, Status> {
let previous_site_name = previous_name(&source_url, &get_global_names().await);
let next_site_name = next_name(&source_url, &get_global_names().await);
if previous_site_name.is_none() && next_site_name.is_none() {
return Err(Status::NotFound);
@ -55,10 +86,11 @@ pub async fn name(source_url: String) -> Result<Json<JsonResponse>, Status> {
Ok(Json(JsonResponse {
previous_site_name,
next_site_name,
}))
})
.into())
}
#[catch(404)]
pub fn not_found() -> ErrorTemplate<'static> {
NOT_FOUND_ERROR
pub fn not_found() -> Result<ErrorTemplate<'static>, Status> {
not_found_error()
}

View File

@ -1,15 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width">
<title>Meowy Webring - {{ error }}</title>
<link rel="stylesheet" href="/public/style.css" />
</head>
<body>
<main>
<h1>{{ error }}</h1>
<p>{{ error_description }}</p>
</main>
</body>
</html>