forked from fediversity/fediversity
		
	move things to more appropriate places
This commit is contained in:
		
							parent
							
								
									6f90db7193
								
							
						
					
					
						commit
						f71bc89921
					
				
					 7 changed files with 200 additions and 188 deletions
				
			
		|  | @ -4,19 +4,10 @@ let | |||
|     mkOption | ||||
|     types | ||||
|     ; | ||||
|   templates = import ./templates.nix { inherit lib; }; | ||||
|   # TODO: optionally run the whole thing through the validator | ||||
|   # https://github.com/validator/validator | ||||
|   render-html = document: | ||||
|     let | ||||
|       eval = lib.evalModules { | ||||
|         class = "DOM"; | ||||
|         modules = [ document (import ./dom.nix) ]; | ||||
|       }; | ||||
|     in | ||||
|     toString eval.config; | ||||
| in | ||||
| { | ||||
|   imports = lib.nixFiles ./.; | ||||
| 
 | ||||
|   options.templates = | ||||
|     let | ||||
|       # arbitrarily nested attribute set where the leaves are of type `type` | ||||
|  | @ -33,65 +24,15 @@ in | |||
|       type = recursiveAttrs (with types; functionTo (coercedTo attrs toString str)); | ||||
|     }; | ||||
| 
 | ||||
|   config.templates.html = { | ||||
|     markdown = { name, body }: | ||||
|       let | ||||
|         commonmark = pkgs.runCommand "${name}.html" | ||||
|           { | ||||
|             buildInputs = [ pkgs.cmark ]; | ||||
|           } '' | ||||
|           cmark ${builtins.toFile "${name}.md" body} > $out | ||||
|         ''; | ||||
|       in | ||||
|       builtins.readFile commonmark; | ||||
|     nav = { menu, page }: | ||||
|       let | ||||
|         render-item = item: | ||||
|           if item ? menu then '' | ||||
|             <li>${item.menu.label} | ||||
|               ${lib.indent "  " (item.menu.outputs.html page)} | ||||
|             </li> | ||||
|           '' | ||||
|           else if item ? page then ''<li><a href="${page.link item.page}">${item.page.title}</a></li>'' | ||||
|           else ''<li><a href="${item.link.url}">${item.link.label}</a></li>'' | ||||
|         ; | ||||
|       in | ||||
|       '' | ||||
|         <nav> | ||||
|           <ul> | ||||
|             ${with lib; indent "    " (join "\n" (map render-item menu.items))} | ||||
|           </ul> | ||||
|         </nav> | ||||
|       ''; | ||||
| 
 | ||||
|   }; | ||||
| 
 | ||||
|   options.files = mkOption { | ||||
|     description = '' | ||||
|       Files that make up the site, mapping from output path to contents | ||||
| 
 | ||||
|       By default, all elements in `option`{pages} are converted to files using their template or the default template. | ||||
|       Add more files to the output by assigning to this attribute set. | ||||
|     ''; | ||||
|     # TODO: this should be attrsOf string-coercible instead. | ||||
|     #       we can convert this to file at the very end. | ||||
|     type = with types; attrsOf path; | ||||
|   }; | ||||
| 
 | ||||
|   config.files = | ||||
|     # TODO: create static redirects from `tail page.locations` | ||||
|     let | ||||
|       pages = lib.attrValues config.pages; | ||||
|       collections = with lib; concatMap (collection: collection.entry) (attrValues config.collections); | ||||
|     in | ||||
|     with lib; foldl | ||||
|       (acc: elem: acc // { | ||||
|         # TODO: we may or may not want to enforce the mapping of file types to output file name suffixes | ||||
|         "${head elem.locations}.html" = builtins.toFile "${elem.name}.html" elem.outputs.html; | ||||
|       }) | ||||
|       { } | ||||
|       (pages ++ collections); | ||||
| 
 | ||||
|   options.build = mkOption { | ||||
|     description = '' | ||||
|       The final output of the web site | ||||
|  |  | |||
							
								
								
									
										50
									
								
								website/presentation/templates.nix
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										50
									
								
								website/presentation/templates.nix
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,50 @@ | |||
| { config, options, lib, pkgs, ... }: | ||||
| let | ||||
|   inherit (lib) | ||||
|     mkOption | ||||
|     types | ||||
|     ; | ||||
|   # TODO: optionally run the whole thing through the validator | ||||
|   # https://github.com/validator/validator | ||||
|   render-html = document: | ||||
|     let | ||||
|       eval = lib.evalModules { | ||||
|         class = "DOM"; | ||||
|         modules = [ document (import ./dom.nix) ]; | ||||
|       }; | ||||
|     in | ||||
|     toString eval.config; | ||||
| in | ||||
| { | ||||
|   config.templates.html = { | ||||
|     markdown = { name, body }: | ||||
|       let | ||||
|         commonmark = pkgs.runCommand "${name}.html" | ||||
|           { | ||||
|             buildInputs = [ pkgs.cmark ]; | ||||
|           } '' | ||||
|           cmark ${builtins.toFile "${name}.md" body} > $out | ||||
|         ''; | ||||
|       in | ||||
|       builtins.readFile commonmark; | ||||
|     nav = { menu, page }: | ||||
|       let | ||||
|         render-item = item: | ||||
|           if item ? menu then '' | ||||
|             <li>${item.menu.label} | ||||
|               ${lib.indent "  " (item.menu.outputs.html page)} | ||||
|             </li> | ||||
|           '' | ||||
|           else if item ? page then ''<li><a href="${page.link item.page}">${item.page.title}</a></li>'' | ||||
|           else ''<li><a href="${item.link.url}">${item.link.label}</a></li>'' | ||||
|         ; | ||||
|       in | ||||
|       '' | ||||
|         <nav> | ||||
|           <ul> | ||||
|             ${with lib; indent "    " (join "\n" (map render-item menu.items))} | ||||
|           </ul> | ||||
|         </nav> | ||||
|       ''; | ||||
|   }; | ||||
| } | ||||
							
								
								
									
										75
									
								
								website/structure/collections.nix
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										75
									
								
								website/structure/collections.nix
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,75 @@ | |||
| { config, options, lib, pkgs, ... }: | ||||
| let | ||||
|   inherit (lib) | ||||
|     mkOption | ||||
|     types | ||||
|     ; | ||||
|   cfg = config; | ||||
| in | ||||
| { | ||||
|   options.collections = mkOption { | ||||
|     description = '' | ||||
|       Named collections of unnamed pages | ||||
| 
 | ||||
|       Define the content type of a new collection `example` to be `article`: | ||||
| 
 | ||||
|       ```nix | ||||
|       config.collections.example.type = config.types.article; | ||||
|       ``` | ||||
| 
 | ||||
|       Add a new entry to the `example` collection: | ||||
| 
 | ||||
|       ```nix | ||||
|       config.collections.example.entry = { | ||||
|         # contents here | ||||
|       } | ||||
|       ``` | ||||
|     ''; | ||||
|     type = with types; attrsOf (submodule ({ name, config, ... }: { | ||||
|       options = { | ||||
|         type = mkOption { | ||||
|           description = "Type of entries in the collection"; | ||||
|           type = types.deferredModule; | ||||
|         }; | ||||
|         name = mkOption { | ||||
|           description = "Symbolic name, used as a human-readable identifier"; | ||||
|           type = types.str; | ||||
|           default = name; | ||||
|         }; | ||||
|         prefixes = mkOption { | ||||
|           description = '' | ||||
|             List of historic output locations for files in the collection | ||||
| 
 | ||||
|             The first element is the canonical location. | ||||
|             All other elements are used to create redirects to the canonical location. | ||||
| 
 | ||||
|             The default entry is the symbolic name of the collection. | ||||
|             When changing the symbolic name, append the old one to your custom list and use `lib.mkForce` to make sure the default element will be overridden. | ||||
|           ''; | ||||
|           type = with types; nonEmptyListOf str; | ||||
|           example = [ "." ]; | ||||
|           default = [ config.name ]; | ||||
|         }; | ||||
|         entry = mkOption { | ||||
|           description = "An entry in the collection"; | ||||
|           type = types.collection (types.submodule ({ | ||||
|             imports = [ config.type ]; | ||||
|             _module.args.collection = config; | ||||
|             process-locations = ls: with lib; concatMap (l: map (p: "${p}/${l}") config.prefixes) ls; | ||||
|           })); | ||||
|         }; | ||||
|       }; | ||||
|     })); | ||||
|   }; | ||||
|   config.files = | ||||
|     # TODO: create static redirects from `tail <collection>.locations` | ||||
|     let | ||||
|       collections = with lib; concatMap (collection: collection.entry) (attrValues config.collections); | ||||
|     in | ||||
|     with lib; foldl | ||||
|       (acc: elem: acc // { | ||||
|         "${head elem.locations}.html" = builtins.toFile "${elem.name}.html" elem.outputs.html; | ||||
|       }) | ||||
|       { } | ||||
|       collections; | ||||
| } | ||||
|  | @ -14,73 +14,53 @@ in | |||
|     type = with types; attrsOf deferredModule; | ||||
|   }; | ||||
| 
 | ||||
|   # TODO: enable i18n, e.g. via a nested attribute for language-specific content | ||||
|   options.pages = mkOption { | ||||
|     description = '' | ||||
|       Collection of pages on the site | ||||
|     ''; | ||||
|     type = with types; attrsOf (submodule config.content-types.page); | ||||
|   }; | ||||
| 
 | ||||
|   options.collections = mkOption { | ||||
|     description = '' | ||||
|       Named collections of unnamed pages | ||||
| 
 | ||||
|       Define the content type of a new collection `example` to be `article`: | ||||
| 
 | ||||
|       ```nix | ||||
|       config.collections.example.type = config.types.article; | ||||
|       ``` | ||||
| 
 | ||||
|       Add a new entry to the `example` collection: | ||||
| 
 | ||||
|       ```nix | ||||
|       config.collections.example.entry = { | ||||
|         # contents here | ||||
|       } | ||||
|       ``` | ||||
|     ''; | ||||
|     type = with types; attrsOf (submodule ({ name, config, ... }: { | ||||
|       options = { | ||||
|         type = mkOption { | ||||
|           description = "Type of entries in the collection"; | ||||
|           type = types.deferredModule; | ||||
|         }; | ||||
|         name = mkOption { | ||||
|           description = "Symbolic name, used as a human-readable identifier"; | ||||
|           type = types.str; | ||||
|           default = name; | ||||
|         }; | ||||
|         prefixes = mkOption { | ||||
|           description = '' | ||||
|             List of historic output locations for files in the collection | ||||
| 
 | ||||
|             The first element is the canonical location. | ||||
|             All other elements are used to create redirects to the canonical location. | ||||
| 
 | ||||
|             The default entry is the symbolic name of the collection. | ||||
|             When changing the symbolic name, append the old one to your custom list and use `lib.mkForce` to make sure the default element will be overridden. | ||||
|           ''; | ||||
|           type = with types; nonEmptyListOf str; | ||||
|           example = [ "." ]; | ||||
|           default = [ config.name ]; | ||||
|         }; | ||||
|         entry = mkOption { | ||||
|           description = "An entry in the collection"; | ||||
|           type = types.collection (types.submodule ({ | ||||
|             imports = [ config.type ]; | ||||
|             _module.args.collection = config; | ||||
|             process-locations = ls: with lib; concatMap (l: map (p: "${p}/${l}") config.prefixes) ls; | ||||
|           })); | ||||
|         }; | ||||
|   config.content-types.document = { name, config, options, link, ... }: { | ||||
|     config._module.args.link = config.link; | ||||
|     options = { | ||||
|       name = mkOption { | ||||
|         description = "Symbolic name, used as a human-readable identifier"; | ||||
|         type = types.str; | ||||
|         default = name; | ||||
|       }; | ||||
|     })); | ||||
|   }; | ||||
|       locations = mkOption { | ||||
|         description = '' | ||||
|           List of historic output locations for the resulting file | ||||
| 
 | ||||
|   options.menus = mkOption { | ||||
|     description = '' | ||||
|       Collection navigation menus | ||||
|     ''; | ||||
|     type = with types; attrsOf (submodule config.content-types.navigation); | ||||
|           Elements are relative paths to output files, without suffix. | ||||
|           The suffix will be added depending on output file type. | ||||
| 
 | ||||
|           The first element is the canonical location. | ||||
|           All other elements are used to create redirects to the canonical location. | ||||
| 
 | ||||
|           The default entry is the symbolic name of the document. | ||||
|           When changing the symbolic name, append the old one to your custom list and use `lib.mkForce` to make sure the default element will be overridden. | ||||
|         ''; | ||||
|         type = with types; nonEmptyListOf str; | ||||
|         apply = config.process-locations; | ||||
|         example = [ "about/overview" "index" ]; | ||||
|         default = [ config.name ]; | ||||
|       }; | ||||
|       process-locations = mkOption { | ||||
|         description = "Function to post-process the output locations of contained document"; | ||||
|         type = types.functionTo options.locations.type; | ||||
|         default = lib.id; | ||||
|       }; | ||||
|       link = mkOption { | ||||
|         description = "Helper function for transparent linking to other pages"; | ||||
|         type = with types; functionTo str; | ||||
|         # TODO: we may want links to other representations, | ||||
|         #       and currently the mapping of output types to output file | ||||
|         #       names is soft. | ||||
|         default = target: with lib; "${relativePath (head config.locations) (head target.locations)}.html"; | ||||
|       }; | ||||
|       outputs.html = mkOption { | ||||
|         # TODO: make this of type DOM and convert to string at the output. | ||||
|         #       the output aggregator then only needs something string-coercible | ||||
|         description = '' | ||||
|           Representations of the document in different formats | ||||
|         ''; | ||||
|         type = with types; str; | ||||
|       }; | ||||
|     }; | ||||
|   }; | ||||
| } | ||||
|  |  | |||
|  | @ -1,58 +0,0 @@ | |||
| { lib, ... }: | ||||
| let | ||||
|   inherit (lib) | ||||
|     mkOption | ||||
|     types | ||||
|     ; | ||||
| in | ||||
| { | ||||
|   content-types.document = { name, config, options, link, ... }: { | ||||
|     config._module.args.link = config.link; | ||||
|     options = { | ||||
|       name = mkOption { | ||||
|         description = "Symbolic name, used as a human-readable identifier"; | ||||
|         type = types.str; | ||||
|         default = name; | ||||
|       }; | ||||
|       locations = mkOption { | ||||
|         description = '' | ||||
|           List of historic output locations for the resulting file | ||||
| 
 | ||||
|           Elements are relative paths to output files, without suffix. | ||||
|           The suffix will be added depending on output file type. | ||||
| 
 | ||||
|           The first element is the canonical location. | ||||
|           All other elements are used to create redirects to the canonical location. | ||||
| 
 | ||||
|           The default entry is the symbolic name of the document. | ||||
|           When changing the symbolic name, append the old one to your custom list and use `lib.mkForce` to make sure the default element will be overridden. | ||||
|         ''; | ||||
|         type = with types; nonEmptyListOf str; | ||||
|         apply = config.process-locations; | ||||
|         example = [ "about/overview" "index" ]; | ||||
|         default = [ config.name ]; | ||||
|       }; | ||||
|       process-locations = mkOption { | ||||
|         description = "Function to post-process the output locations of contained document"; | ||||
|         type = types.functionTo options.locations.type; | ||||
|         default = lib.id; | ||||
|       }; | ||||
|       link = mkOption { | ||||
|         description = "Helper function for transparent linking to other pages"; | ||||
|         type = with types; functionTo str; | ||||
|         # TODO: we may want links to other representations, | ||||
|         #       and currently the mapping of output types to output file | ||||
|         #       names is soft. | ||||
|         default = target: with lib; "${relativePath (head config.locations) (head target.locations)}.html"; | ||||
|       }; | ||||
|       outputs.html = mkOption { | ||||
|         # TODO: make this of type DOM and convert to string at the output. | ||||
|         #       the output aggregator then only needs something string-coercible | ||||
|         description = '' | ||||
|           Representations of the document in different formats | ||||
|         ''; | ||||
|         type = with types; str; | ||||
|       }; | ||||
|     }; | ||||
|   }; | ||||
| } | ||||
|  | @ -16,7 +16,14 @@ let | |||
|   ]; | ||||
| in | ||||
| { | ||||
|   content-types.named-link = { ... }: { | ||||
|   options.menus = mkOption { | ||||
|     description = '' | ||||
|       Collection navigation menus | ||||
|     ''; | ||||
|     type = with types; attrsOf (submodule config.content-types.navigation); | ||||
|   }; | ||||
| 
 | ||||
|   config.content-types.named-link = { ... }: { | ||||
|     options = { | ||||
|       label = mkOption { | ||||
|         description = "Link label"; | ||||
|  | @ -29,7 +36,7 @@ in | |||
|     }; | ||||
|   }; | ||||
| 
 | ||||
|   content-types.navigation = { name, config, ... }: { | ||||
|   config.content-types.navigation = { name, config, ... }: { | ||||
|     options = { | ||||
|       name = mkOption { | ||||
|         description = "Symbolic name, used as a human-readable identifier"; | ||||
|  |  | |||
|  | @ -15,7 +15,24 @@ let | |||
|     toString eval.config; | ||||
| in | ||||
| { | ||||
|   content-types.page = { name, config, ... }: { | ||||
|   # TODO: enable i18n, e.g. via a nested attribute for language-specific content | ||||
|   options.pages = mkOption { | ||||
|     description = '' | ||||
|       Collection of pages on the site | ||||
|     ''; | ||||
|     type = with types; attrsOf (submodule config.content-types.page); | ||||
|   }; | ||||
|   config.files = with lib; | ||||
|     foldl' | ||||
|       (acc: elem: acc // { | ||||
|         # TODO: create static redirects from `tail page.locations` | ||||
|         # TODO: the file name could correspond to the canonical location in the HTML representation | ||||
|         "${head elem.locations}.html" = builtins.toFile "${elem.name}.html" elem.outputs.html; | ||||
|       }) | ||||
|       { } | ||||
|       (attrValues config.pages); | ||||
| 
 | ||||
|   config.content-types.page = { name, config, ... }: { | ||||
|     imports = [ cfg.content-types.document ]; | ||||
|     options = { | ||||
|       title = mkOption { | ||||
|  |  | |||
		Loading…
	
	Add table
		
		Reference in a new issue
	
	 Valentin Gagarin
							Valentin Gagarin