lavender.software webring #2
					 7 changed files with 230 additions and 24 deletions
				
			
		|  | @ -30,3 +30,5 @@ dist/ $ git pull --rebase | ||||||
| dist/ $ git push | dist/ $ git push | ||||||
| dist/ $ # Your changes should now be live at lavender.software | dist/ $ # Your changes should now be live at lavender.software | ||||||
| ``` | ``` | ||||||
|  | 
 | ||||||
|  | If deploying this site, you may also want to examine the sample `nginx-site.conf` file. | ||||||
|  |  | ||||||
|  | @ -1,21 +1,5 @@ | ||||||
| use std::{fs, path::Path}; |  | ||||||
| 
 |  | ||||||
| use crate::*; | use crate::*; | ||||||
| 
 | 
 | ||||||
| fn copy_dir_recursive(src: impl AsRef<Path>, dst: impl AsRef<Path>) -> std::io::Result<()> { |  | ||||||
|     fs::create_dir_all(&dst)?; |  | ||||||
|     for entry in fs::read_dir(src)? { |  | ||||||
|         let entry = entry?; |  | ||||||
|         let ty = entry.file_type()?; |  | ||||||
|         if ty.is_dir() { |  | ||||||
|             copy_dir_recursive(entry.path(), dst.as_ref().join(entry.file_name()))?; |  | ||||||
|         } else { |  | ||||||
|             fs::copy(entry.path(), dst.as_ref().join(entry.file_name()))?; |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|     Ok(()) |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| pub fn copy_assets(ctx: &BuildContext) -> Result<()> { | pub fn copy_assets(ctx: &BuildContext) -> Result<()> { | ||||||
|     log_info("Copying assets…"); |     log_info("Copying assets…"); | ||||||
|     copy_dir_recursive(ctx.source_dir.join("assets"), ctx.output_dir.join("assets"))?; |     copy_dir_recursive(ctx.source_dir.join("assets"), ctx.output_dir.join("assets"))?; | ||||||
|  |  | ||||||
|  | @ -1,10 +1,11 @@ | ||||||
| use siru::prelude::*; | use siru::prelude::*; | ||||||
| use std::{convert::TryInto, path::PathBuf, sync::Arc, time::Duration}; | use std::{convert::TryInto, fs, path::Path, path::PathBuf, sync::Arc, time::Duration}; | ||||||
| 
 | 
 | ||||||
| type Result<T> = std::result::Result<T, Box<dyn std::error::Error>>; | type Result<T> = std::result::Result<T, Box<dyn std::error::Error>>; | ||||||
| 
 | 
 | ||||||
| mod assets; | mod assets; | ||||||
| mod main_page; | mod main_page; | ||||||
|  | mod webring; | ||||||
| 
 | 
 | ||||||
| pub struct BuildContext { | pub struct BuildContext { | ||||||
|     source_dir: PathBuf, |     source_dir: PathBuf, | ||||||
|  | @ -26,6 +27,20 @@ impl SiruFS for BuildContext { | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | pub fn copy_dir_recursive(src: impl AsRef<Path>, dst: impl AsRef<Path>) -> std::io::Result<()> { | ||||||
|  |     fs::create_dir_all(&dst)?; | ||||||
|  |     for entry in fs::read_dir(src)? { | ||||||
|  |         let entry = entry?; | ||||||
|  |         let ty = entry.file_type()?; | ||||||
|  |         if ty.is_dir() { | ||||||
|  |             copy_dir_recursive(entry.path(), dst.as_ref().join(entry.file_name()))?; | ||||||
|  |         } else { | ||||||
|  |             fs::copy(entry.path(), dst.as_ref().join(entry.file_name()))?; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     Ok(()) | ||||||
|  | } | ||||||
|  | 
 | ||||||
| fn build() { | fn build() { | ||||||
|     let ctx = BuildContext { |     let ctx = BuildContext { | ||||||
|         source_dir: "src".try_into().unwrap(), |         source_dir: "src".try_into().unwrap(), | ||||||
|  | @ -35,7 +50,11 @@ fn build() { | ||||||
| 
 | 
 | ||||||
|     let ctx = Arc::new(ctx); |     let ctx = Arc::new(ctx); | ||||||
| 
 | 
 | ||||||
|     [main_page::main_page, assets::copy_assets] |     [ | ||||||
|  |         main_page::main_page, | ||||||
|  |         assets::copy_assets, | ||||||
|  |         webring::copy_webring, | ||||||
|  |     ] | ||||||
|     .iter() |     .iter() | ||||||
|     .map(|f| { |     .map(|f| { | ||||||
|         let ctx = Arc::clone(&ctx); |         let ctx = Arc::clone(&ctx); | ||||||
|  |  | ||||||
							
								
								
									
										11
									
								
								build_src/webring.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								build_src/webring.rs
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,11 @@ | ||||||
|  | use crate::*; | ||||||
|  | 
 | ||||||
|  | pub fn copy_webring(ctx: &BuildContext) -> Result<()> { | ||||||
|  |     log_info("Copying webring…"); | ||||||
|  |     copy_dir_recursive( | ||||||
|  |         ctx.source_dir.join("webring"), | ||||||
|  |         ctx.output_dir.join("webring"), | ||||||
|  |     )?; | ||||||
|  | 
 | ||||||
|  |     Ok(()) | ||||||
|  | } | ||||||
							
								
								
									
										11
									
								
								nginx-site.conf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								nginx-site.conf
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,11 @@ | ||||||
|  | # assuming the dist repo lives at /srv/http/lavender.software | ||||||
|  | 
 | ||||||
|  | location / { | ||||||
|  |   alias /srv/http/lavender.software/; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | error_page 404 /404.html | ||||||
|  | 
 | ||||||
|  | location = /webring/data.json { | ||||||
|  |   add_header Access-Control-Allow-Origin *; | ||||||
|  | } | ||||||
							
								
								
									
										17
									
								
								src/webring/data.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								src/webring/data.json
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,17 @@ | ||||||
|  | [ | ||||||
|  |     { | ||||||
|  |         "id": "annie", | ||||||
|  |         "name": "annieversary", | ||||||
|  |         "url": "https://versary.town/" | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |         "id": "charlotte", | ||||||
|  |         "name": "charlotte", | ||||||
|  |         "url": "https://char.lt/" | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |         "id": "mira", | ||||||
|  |         "name": "mira", | ||||||
|  |         "url": "https://boxin.space/" | ||||||
|  |     } | ||||||
|  | ] | ||||||
							
								
								
									
										162
									
								
								src/webring/webring-0.1.0.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										162
									
								
								src/webring/webring-0.1.0.js
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,162 @@ | ||||||
|  | (function () { | ||||||
|  |   function getUID() { | ||||||
|  |     var array = new Uint8Array(8); | ||||||
|  |     window.crypto.getRandomValues(array); | ||||||
|  |     return Array.from(array) | ||||||
|  |       .map((b) => b.toString(16).padStart(2, "0")) | ||||||
|  |       .join(""); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   const params = document.currentScript.dataset; | ||||||
|  |   const UID = getUID(); | ||||||
|  | 
 | ||||||
|  |   const css = ` | ||||||
|  | #--lavender-cssreset-${UID} { | ||||||
|  | 	all: unset; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #--lavender-webring-container-${UID} { | ||||||
|  | 	background-color: rgb(28, 23, 36); | ||||||
|  | 	background-blend-mode: multiply; | ||||||
|  | 	position: relative; | ||||||
|  | 
 | ||||||
|  | 	background-color: ${params.backgroundColor || "purple"}; | ||||||
|  | 	color: ${params.textColor || "white"}; | ||||||
|  | 	text-shadow: 0px 1px 1px ${params.textShadowColor || "black"}; | ||||||
|  | 	padding: 1px; | ||||||
|  | 	font-size: 16px; | ||||||
|  | 	font-family: sans-serif; | ||||||
|  | 
 | ||||||
|  | 	margin: 10px 0px; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #--lavender-webring-container-${UID} a { | ||||||
|  | 	color: inherit !important; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #--lavender-webring-container-${UID}::before { | ||||||
|  | 	display: block; | ||||||
|  | 	content: ' '; | ||||||
|  | 	top: 0; left: 0; bottom: 0; right: 0; | ||||||
|  | 	position: absolute; | ||||||
|  | 	box-sizing: border-box; | ||||||
|  | 	pointer-events: none; | ||||||
|  | 	border: 5px outset; | ||||||
|  | 	opacity: 0.25; | ||||||
|  | 	border-color: white black black white; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #--lavender-webring-container-${UID} #--lavender-webring-title-${UID} { | ||||||
|  | 	margin: 10px 10px 0px; | ||||||
|  | 	text-align: center; | ||||||
|  | 	font-style: italic; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #--lavender-webring-container-${UID} #--lavender-webring-item-container-${UID} { | ||||||
|  | 	display: flex; | ||||||
|  | 	justify-content: space-around; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | @media (max-width: 600px) { | ||||||
|  | 	#--lavender-webring-container-${UID} #--lavender-webring-item-container-${UID} { | ||||||
|  | 		flex-direction: column; | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #--lavender-webring-container-${UID} .--lavender-webring-items-${UID} { | ||||||
|  | 	font-size: 14px; | ||||||
|  | 	display: block; | ||||||
|  | 	text-align: center; | ||||||
|  | 	padding: 0px; | ||||||
|  | 	margin: 10px 10px 8px; | ||||||
|  | 	flex: 1; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #--lavender-webring-container-${UID} #--lavender-webring-item-1-${UID}::before { | ||||||
|  | 	display: inline; | ||||||
|  | 	content: '\\2190\\00a0'; | ||||||
|  | } | ||||||
|  | #--lavender-webring-container-${UID} #--lavender-webring-item-3-${UID}::after { | ||||||
|  | 	display: inline; | ||||||
|  | 	content: '\\00a0\\2192'; | ||||||
|  | } | ||||||
|  | `;
 | ||||||
|  | 
 | ||||||
|  |   const webring_content = ` | ||||||
|  | <div id="--lavender-cssreset-${UID}"> | ||||||
|  | <div id="--lavender-webring-container-${UID}"> | ||||||
|  | 	<p id="--lavender-webring-title-${UID}">This website is a part of the Lavender Software webring</p> | ||||||
|  | 	<div id="--lavender-webring-item-container-${UID}"> | ||||||
|  | 		<a class="--lavender-webring-items-${UID}" id="--lavender-webring-item-1-${UID}"></a> | ||||||
|  | 		<a class="--lavender-webring-items-${UID}" id="--lavender-webring-item-2-${UID}"></a> | ||||||
|  | 		<a class="--lavender-webring-items-${UID}" id="--lavender-webring-item-3-${UID}"></a> | ||||||
|  | 	</div> | ||||||
|  | </div> | ||||||
|  | </div> | ||||||
|  | `;
 | ||||||
|  | 
 | ||||||
|  |   function renderIdx(data, element, idx) { | ||||||
|  |     idx = (idx + data.length) % data.length; | ||||||
|  | 
 | ||||||
|  |     datum = data[idx]; | ||||||
|  |     element.textContent = datum.name; | ||||||
|  |     element.href = datum.url; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   function getElementByPostfixedId(path) { | ||||||
|  |     return document.getElementById(path + "-" + UID); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   function renderContent(currentScript, data) { | ||||||
|  |     const params = currentScript.dataset; | ||||||
|  | 
 | ||||||
|  |     var headstyle = document.createElement("style"); | ||||||
|  |     headstyle.innerHTML = css; | ||||||
|  |     document.head.appendChild(headstyle); | ||||||
|  | 
 | ||||||
|  |     currentScript.insertAdjacentHTML("afterend", webring_content); | ||||||
|  | 
 | ||||||
|  |     const container = getElementByPostfixedId("--lavender-webring-container"); | ||||||
|  | 
 | ||||||
|  |     const item1 = getElementByPostfixedId("--lavender-webring-item-1"); | ||||||
|  |     const item2 = getElementByPostfixedId("--lavender-webring-item-2"); | ||||||
|  |     const item3 = getElementByPostfixedId("--lavender-webring-item-3"); | ||||||
|  | 
 | ||||||
|  |     const id = params.siteId; | ||||||
|  |     var idindex = -1; | ||||||
|  | 
 | ||||||
|  |     for (var i = 0; i < data.length; i++) { | ||||||
|  |       if (data[i].id == id) { | ||||||
|  |         idindex = i; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     if (idindex == -1) { | ||||||
|  |       item2.textContent = | ||||||
|  |         "this site was not found in the list. please check that you don't have any typos in the id!"; | ||||||
|  |       return; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     if ("hideTitle" in params) { | ||||||
|  |       getElementByPostfixedId("--lavender-webring-title").style.display = | ||||||
|  |         "none"; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     renderIdx(data, item1, idindex - 1); | ||||||
|  |     renderIdx(data, item2, idindex); | ||||||
|  |     renderIdx(data, item3, idindex + 1); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   const currentScript = document.currentScript; | ||||||
|  |   if (currentScript) { | ||||||
|  |     fetch("https://lavender.software/webring/data.json") | ||||||
|  |       .then(function (response) { | ||||||
|  |         return response.json(); | ||||||
|  |       }) | ||||||
|  |       .then(function (data) { | ||||||
|  |         renderContent(currentScript, data); | ||||||
|  |       }); | ||||||
|  |   } else { | ||||||
|  |     console.log("cannot locate document.currentScript element. aborting..."); | ||||||
|  |   } | ||||||
|  | })(); | ||||||
		Loading…
	
		Reference in a new issue