From 26ba5c90e642eb932e673bb6e8e7be024c0ecc0f Mon Sep 17 00:00:00 2001 From: jutty Date: Thu, 4 Jun 2026 22:26:08 -0300 Subject: [PATCH 1/5] Update README for v0.5 node structure --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 960f996..2416d37 100644 --- a/README.md +++ b/README.md @@ -10,10 +10,10 @@ You can learn more and see what en looks like by visiting the [homepage](https:/ ## Install and run -See the [Documentation](https://en.jutty.dev/node/Documentation) page for instructions and how to install and start using en. +See the [Get Started](https://en.jutty.dev/node/GetStarted) page for instructions and how to install and start using en. ## Roadmap -For a high-level view of what's in the future for en, see the [What's ahead section](https://en.jutty.dev/node/Introduction/#What's) of the docs Introduction. +For a high-level view of what's in the future for en, see the [What's ahead section](https://en.jutty.dev/node/Introduction#What's) of the docs Introduction. For a more detailed outline of what's planned, along with what's already been completed, see the [roadmap](https://en.jutty.dev/node/Roadmap). From a38d93ba2ac0b3eb4e0c2d10be770493550f58fa Mon Sep 17 00:00:00 2001 From: jutty Date: Fri, 5 Jun 2026 21:31:43 -0300 Subject: [PATCH 2/5] schema: Move node schema to $defs --- static/graph-schema.json | 56 ++++++++++++++++++++-------------------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/static/graph-schema.json b/static/graph-schema.json index bbf6cc3..95c177a 100644 --- a/static/graph-schema.json +++ b/static/graph-schema.json @@ -6,7 +6,33 @@ "type": "object", "$defs": { "node": { - + "type": "object", + "title": "Node", + "description": "A node object.", + "example": "[nodes.Earth]\ntext = \"Earth is a planet of the solar system.\"", + "default": null, + "properties": { + "text": { + "type": "string", + "description": "The text content of this node." + }, + "title": { + "type": "string", + "description": "The node display title, useful to make it distinct from the ID.", + "default": "The node's ID." + }, + "listed": { + "type": "boolean", + "description": "Whether this node is shown in listing pages.", + "default": true + }, + "redirect": { + "type": "string", + "description": "A node ID to where any requests for this node will be redirected.", + "default": null + } + }, + "additionalProperties": false } }, "properties": { @@ -23,33 +49,7 @@ "default": null, "type": "object", "additionalProperties": { - "type": "object", - "title": "Node", - "description": "A node object.", - "example": "[nodes.Earth]\ntext = \"Earth is a planet of the solar system.\"", - "default": null, - "properties": { - "text": { - "type": "string", - "description": "The text content of this node." - }, - "title": { - "type": "string", - "description": "The node display title, useful to make it distinct from the ID.", - "default": "The node's ID." - }, - "listed": { - "type": "boolean", - "description": "Whether this node is shown in listing pages.", - "default": true - }, - "redirect": { - "type": "string", - "description": "A node ID to where any requests for this node will be redirected.", - "default": null - } - }, - "additionalProperties": false + "$ref": "#/$defs/node" }, "propertyNames": { "pattern": "^[^-][^!@#$%^&*;:/~| \\]\\[()\\\\]*$" From 0987269307d59a95c57803e5f2ae2607686edea7 Mon Sep 17 00:00:00 2001 From: jutty Date: Sun, 7 Jun 2026 04:00:36 -0300 Subject: [PATCH 3/5] Add flake.nix --- .gitignore | 1 + Cargo.lock | 8 +++--- flake.lock | 26 ++++++++++++++++++ flake.nix | 80 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 111 insertions(+), 4 deletions(-) create mode 100644 flake.lock create mode 100644 flake.nix diff --git a/.gitignore b/.gitignore index ea8c4bf..d787b70 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ /target +/result diff --git a/Cargo.lock b/Cargo.lock index d0133a5..06b5d60 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -86,9 +86,9 @@ dependencies = [ [[package]] name = "bitflags" -version = "2.12.1" +version = "2.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84d7ced0ae9557296835c32bf1b1e02b44c746701f898460fb000d7eaa84f00a" +checksum = "b4388bee8683e3d04af747c73422af53102d2bd24d9eadb6cbc100baef4b43f8" [[package]] name = "block-buffer" @@ -469,9 +469,9 @@ dependencies = [ [[package]] name = "ignore" -version = "0.4.25" +version = "0.4.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3d782a365a015e0f5c04902246139249abf769125006fbe7649e2ee88169b4a" +checksum = "b915661dd01db3f05050265b2477bcc6527b3792388e2749b41623cc592be67d" dependencies = [ "crossbeam-deque", "globset", diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000..8f095cd --- /dev/null +++ b/flake.lock @@ -0,0 +1,26 @@ +{ + "nodes": { + "nixpkgs": { + "locked": { + "lastModified": 1780453794, + "narHash": "sha256-bXMRa9VTsHSPXL4Cw8R6JJLQeY3Y/IP4+YJCYVmQ7FY=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "6b316287bae2ee04c9b93c8c858d930fd07d7338", + "type": "github" + }, + "original": { + "id": "nixpkgs", + "ref": "nixos-26.05", + "type": "indirect" + } + }, + "root": { + "inputs": { + "nixpkgs": "nixpkgs" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..bfac211 --- /dev/null +++ b/flake.nix @@ -0,0 +1,80 @@ +{ + description = "A non-linear writing instrument."; + + inputs.nixpkgs.url = "nixpkgs/nixos-26.05"; + + outputs = { nixpkgs, self }: let + name = "en"; + version = "0.4.0"; + + supportedSystems = [ + "x86_64-linux" + "aarch64-linux" + ]; + + forAllSystems = nixpkgs.lib.genAttrs supportedSystems; + + nixpkgsFor = forAllSystems (system: import nixpkgs { + inherit system; + }); + + in { + packages = forAllSystems (system: let + pkgs = nixpkgsFor.${system}; + in { + default = pkgs.rustPlatform.buildRustPackage { + inherit name version; + src = ./.; + + cargoHash = + "sha256-" + + "em229cShq/IShRnxlp5mgcIu7pIOf0LflV8Pw0lLUEY="; + }; + }); + + apps = forAllSystems (system: { + default = { + type = "app"; + program = + "${self.packages.${system}.default}/bin/en"; + }; + }); + + devShells = forAllSystems (system: + let pkgs = nixpkgsFor.${system}; in { + default = pkgs.mkShell { + buildInputs = with pkgs; [ + rustup + just + watchexec + cargo-deny + cargo-llvm-cov + cargo-mutants + go-tools + typos + taplo + ]; + }; + } + ); + + + nixosModules.bot = { config, lib, system, ... }: { + options.within.services.en.enable = + lib.mkEnableOption "enable en server"; + + config = lib.mkIf config.within.services.en.enable { + systemd.services.en = { + wantedBy = [ "multi-user.target" ]; + serviceConfig = { + Restart = "always"; + ExecStart = + "${self.packages."${system}".default}/bin/en"; + }; + }; + }; + }; + + + }; +} From 1aef9d6ee6a778fdcff142799ee70156e4880dbc Mon Sep 17 00:00:00 2001 From: jutty Date: Sun, 7 Jun 2026 05:19:25 -0300 Subject: [PATCH 4/5] Draft customization docs --- static/graph.toml | 58 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/static/graph.toml b/static/graph.toml index bc51702..df35c11 100644 --- a/static/graph.toml +++ b/static/graph.toml @@ -842,6 +842,64 @@ en must differentiate node anchors from outgoing URLs: It does this by looking at the destination and checking if it contains a `/` or `:`. That's one more reason to avoid these characters in your node IDs. """ +[nodes.Customization] +text = """ +You can customize several aspects of en by overriding its default templates, styles and other assets. + +## The `public` directory + +The `static/public` directory is searched by en in the current working directory and can also be |passed as a command line option|CLI. All files placed inside this directory will be served by the en server as static files. You can create directories and organize files as you see fit, and then reference them through custom templates and includes. + +If you place a file in a default path, it will override the default. Namely: + +- `static/public/assets/favicon.svg`: Website icon as seen on tabs and other UI elements +- `static/public/assets/style.css`: Main CSS stylesheet +- `static/public/assets/fonts/fonts.css`: Fonts CSS index mapping the default families `sans`, `serifed`, `mono`, `prose` and `title`. The `prose` family is used for paragraphs such as in the node text content, while the `sans` family is used for UI elements such as the navigation bar and footer. + +The en server supports a variety of file types including plain text; data formats such as CSV, TOML and JSON; various font and image formats; and document formats such as PDF and EPUB. If you want to serve a file with a mimetype that is not included among the |builtin ones|https://codeberg.org/jutty/en/src/branch/main/src/router/handlers/mime.rs|, you can use the `mimes` |configuration option|Configuration#mimes|. If you don't, the file will be served with mimetype `application/octet-stream`, which may or may not work depending on what you are actually serving and how it's being consumed. + +## Styles + +You can override the default CSS and fonts using custom CSS files. + +To completely override the default style, you can place your replacement at the default path as explained in the previous section. + +If you just want to add small customizations, this can be better accomplished by adding a CSS file as part of a custom headers include, as explained in the next section. + +## Templates + +en uses the Tera|https://keats.github.io/tera templating engine, which provides several features for creating your own templates. + +When starting up, en will look for a `templates` directory in the current working directory. For each template, it looks up the corresponding filename inside this directory. If it can't find one, it will fallback to a default template. + +For a list of templates along with their names, see the |templates directory|https://codeberg.org/jutty/en/src/branch/main/templates| in the source code repository. + +See the |Tera documentation|https://keats.github.io/tera/docs for a more extensive description of the available features for writing templates. + +### Includes + +Overriding an entire template can be very verbose, considering the default templates attempt to handle various edge cases. + +To make it easier to override the most common use cases, the following templates are consumed as "includes" in specific parts of the main templates if placed inside the `templates` directory with the suffix `.include.html`: + +- `header`: Included at the end of the default templates' base header +- `post-body`: Included after the body in the default base template +- `favicon`: Replaces the default favicon code +- `styles`: Replaces the default CSS links +- `footer`: Replaces the footer +- `navigation`: Replaces the navigation bar +- `index-header`: Replaces the block showing the title and subtitle of the website in the index page +- `index-list`: Replaces the block showing the list of nodes in the index page + +For example, to override the block in the header of all pages that globally sets the CSS stylesheets, you can drop a file at `templates/styles.include.html` containing something like: + +` + + +` + +""" + [nodes.Graph] text = """ A graph is a data structure composed of connected (and disconnected) nodes. From f8708f2500e5154c1ea4adb5214ae6e95056b314 Mon Sep 17 00:00:00 2001 From: jutty Date: Mon, 8 Jun 2026 00:52:48 -0300 Subject: [PATCH 5/5] Add several new lints from latest Clippy versions --- Cargo.toml | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/Cargo.toml b/Cargo.toml index 5c79e7d..833205b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -54,6 +54,7 @@ cast_sign_loss = "warn" checked_conversions = "warn" clear_with_drain = "warn" cloned_instead_of_copied = "warn" +cmp_owned = "warn" coerce_container_to_any = "warn" collapsible_else_if = "allow" collapsible_if = "allow" @@ -70,6 +71,7 @@ doc_link_code = "warn" doc_link_with_quotes = "warn" doc_markdown = "warn" doc_paragraphs_missing_punctuation = "warn" +double_must_use = "warn" duration_suboptimal_units = "warn" empty_drop = "warn" empty_enum_variants_with_brackets = "warn" @@ -80,6 +82,7 @@ error_impl_error = "warn" exit = "warn" expect_used = "warn" expl_impl_clone_on_copy = "warn" +explicit_counter_loop = "warn" explicit_deref_methods = "warn" explicit_into_iter_loop = "warn" explicit_iter_loop = "warn" @@ -107,6 +110,7 @@ index_refutable_slice = "warn" indexing_slicing = "warn" inefficient_to_string = "warn" infinite_loop = "warn" +int_plus_one = "warn" integer_division = "warn" integer_division_remainder_used = "warn" into_iter_without_iter = "warn" @@ -114,6 +118,7 @@ invalid_upcast_comparisons = "warn" ip_constant = "warn" iter_filter_is_ok = "warn" iter_filter_is_some = "warn" +iter_kv_map = "warn" iter_not_returning_iterator = "warn" iter_on_empty_collections = "warn" iter_on_single_items = "warn" @@ -129,14 +134,19 @@ literal_string_with_formatting_args = "warn" lossy_float_literal = "warn" macro_use_imports = "warn" manual_assert = "warn" +manual_checked_ops = "warn" manual_ilog2 = "warn" manual_instant_elapsed = "warn" +manual_is_multiple_of = "warn" manual_is_power_of_two = "warn" manual_is_variant_and = "warn" manual_let_else = "warn" manual_midpoint = "warn" manual_non_exhaustive = "allow" +manual_option_zip = "warn" +manual_pop_if = "warn" manual_string_new = "warn" +manual_take = "warn" many_single_char_names = "warn" map_err_ignore = "warn" map_with_unused_argument_over_ranges = "warn" @@ -179,15 +189,19 @@ option_option = "warn" panic_in_result_fn = "warn" path_buf_push_overwrite = "warn" pathbuf_init_then_push = "warn" +possible_missing_else = "warn" pub_underscore_fields = "warn" pub_without_shorthand = "warn" +question_mark = "warn" range_minus_one = "warn" range_plus_one = "warn" rc_buffer = "warn" rc_mutex = "warn" read_zero_byte_vec = "warn" redundant_clone = "warn" +redundant_closure = "warn" redundant_closure_for_method_calls = "warn" +redundant_iter_cloned = "warn" redundant_pub_crate = "warn" redundant_test_prefix = "warn" redundant_type_annotations = "warn" @@ -195,6 +209,7 @@ ref_binding_to_reference = "warn" ref_option = "warn" ref_option_ref = "warn" renamed_function_params = "warn" +replace_box = "warn" rest_pat_in_fully_bound_structs = "warn" return_and_then = "warn" return_self_not_must_use = "warn" @@ -235,12 +250,17 @@ unchecked_time_subtraction = "warn" unicode_not_nfc = "warn" uninlined_format_args = "warn" unnecessary_box_returns = "warn" +unnecessary_cast = "warn" unnecessary_debug_formatting = "warn" +unnecessary_fold = "warn" unnecessary_join = "warn" unnecessary_literal_bound = "warn" +unnecessary_option_map_or_else = "warn" +unnecessary_result_map_or_else = "warn" unnecessary_self_imports = "warn" unnecessary_semicolon = "warn" unnecessary_struct_initialization = "warn" +unnecessary_trailing_comma = "warn" unnecessary_wraps = "warn" unneeded_field_pattern = "warn" unnested_or_patterns = "warn" @@ -257,6 +277,8 @@ unwrap_in_result = "warn" unwrap_used = "warn" used_underscore_binding = "warn" used_underscore_items = "warn" +useless_concat = "warn" +useless_conversion = "warn" useless_let_if_seq = "warn" verbose_file_reads = "warn" volatile_composites = "warn"