import static files
This commit is contained in:
		
							
								
								
									
										
											BIN
										
									
								
								data/static/fonts/Cadman_Bold.woff2
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								data/static/fonts/Cadman_Bold.woff2
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								data/static/fonts/Cadman_BoldItalic.woff2
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								data/static/fonts/Cadman_BoldItalic.woff2
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								data/static/fonts/Cadman_Italic.woff2
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								data/static/fonts/Cadman_Italic.woff2
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								data/static/fonts/Cadman_Roman.woff2
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								data/static/fonts/Cadman_Roman.woff2
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								data/static/fonts/ChicagoFLF.woff2
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								data/static/fonts/ChicagoFLF.woff2
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										159
									
								
								data/static/js/babycode-editor.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										159
									
								
								data/static/js/babycode-editor.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,159 @@
 | 
			
		||||
{
 | 
			
		||||
  let ta = document.getElementById("babycode-content");
 | 
			
		||||
  
 | 
			
		||||
  ta.addEventListener("keydown", (e) => {
 | 
			
		||||
    if(e.key === "Enter" && e.ctrlKey) {
 | 
			
		||||
      // console.log(e.target.form)
 | 
			
		||||
      e.target.form?.submit();
 | 
			
		||||
    }
 | 
			
		||||
  })
 | 
			
		||||
  
 | 
			
		||||
  const inThread = () => {
 | 
			
		||||
    const scheme = window.location.pathname.split("/");
 | 
			
		||||
    return scheme[1] === "threads" && scheme[2] !== "create";
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
  ta.addEventListener("input", () => {
 | 
			
		||||
    if (!inThread()) return;
 | 
			
		||||
    
 | 
			
		||||
    localStorage.setItem(window.location.pathname, ta.value);
 | 
			
		||||
  })
 | 
			
		||||
  
 | 
			
		||||
  document.addEventListener("DOMContentLoaded", () => {
 | 
			
		||||
    if (!inThread()) return;
 | 
			
		||||
    const prevContent = localStorage.getItem(window.location.pathname);
 | 
			
		||||
    if (!prevContent) return;
 | 
			
		||||
    ta.value = prevContent;
 | 
			
		||||
  })
 | 
			
		||||
  
 | 
			
		||||
  const buttonBold = document.getElementById("post-editor-bold");
 | 
			
		||||
  const buttonItalics = document.getElementById("post-editor-italics");
 | 
			
		||||
  const buttonStrike = document.getElementById("post-editor-strike");
 | 
			
		||||
  const buttonUrl = document.getElementById("post-editor-url");
 | 
			
		||||
  const buttonCode = document.getElementById("post-editor-code");
 | 
			
		||||
  const buttonImg = document.getElementById("post-editor-img");
 | 
			
		||||
  const buttonOl = document.getElementById("post-editor-ol");
 | 
			
		||||
  const buttonUl = document.getElementById("post-editor-ul");
 | 
			
		||||
 | 
			
		||||
  function insertTag(tagStart, newline = false, prefill = "") {
 | 
			
		||||
    const hasAttr = tagStart[tagStart.length - 1] === "=";
 | 
			
		||||
    let tagEnd = tagStart;
 | 
			
		||||
    let tagInsertStart = `[${tagStart}]${newline ? "\n" : ""}`;
 | 
			
		||||
    if (hasAttr) {
 | 
			
		||||
      tagEnd = tagEnd.slice(0, -1);
 | 
			
		||||
    }
 | 
			
		||||
    const tagInsertEnd = `${newline ? "\n" : ""}[/${tagEnd}]`;
 | 
			
		||||
    const hasSelection = ta.selectionStart !== ta.selectionEnd;
 | 
			
		||||
    const text = ta.value;
 | 
			
		||||
    if (hasSelection) {
 | 
			
		||||
      const realStart = Math.min(ta.selectionStart, ta.selectionEnd);
 | 
			
		||||
      const realEnd = Math.max(ta.selectionStart, ta.selectionEnd);
 | 
			
		||||
      const selectionLength = realEnd - realStart;
 | 
			
		||||
      
 | 
			
		||||
      const strStart = text.slice(0, realStart);
 | 
			
		||||
      const strEnd = text.substring(realEnd);
 | 
			
		||||
      const frag = `${tagInsertStart}${text.slice(realStart, realEnd)}${tagInsertEnd}`;
 | 
			
		||||
      const reconst = `${strStart}${frag}${strEnd}`;
 | 
			
		||||
      ta.value = reconst;
 | 
			
		||||
      if (!hasAttr){
 | 
			
		||||
        ta.setSelectionRange(realStart + tagInsertStart.length, realStart + tagInsertStart.length + selectionLength);
 | 
			
		||||
      } else {
 | 
			
		||||
        ta.setSelectionRange(realStart + tagInsertEnd.length - 1, realStart + tagInsertEnd.length - 1); // cursor on attr
 | 
			
		||||
      }
 | 
			
		||||
      ta.focus()
 | 
			
		||||
    } else {
 | 
			
		||||
      if (hasAttr) {
 | 
			
		||||
        tagInsertStart += prefill;
 | 
			
		||||
      }
 | 
			
		||||
      const cursor = ta.selectionStart;
 | 
			
		||||
      const strStart = text.slice(0, cursor);
 | 
			
		||||
      const strEnd = text.substr(cursor);
 | 
			
		||||
      
 | 
			
		||||
      let newCursor = strStart.length + tagInsertStart.length;
 | 
			
		||||
      if (hasAttr) {
 | 
			
		||||
        newCursor = cursor + tagInsertStart.length - prefill.length - 1;
 | 
			
		||||
      }
 | 
			
		||||
      const reconst = `${strStart}${tagInsertStart}${tagInsertEnd}${strEnd}`;
 | 
			
		||||
      ta.value = reconst;
 | 
			
		||||
      ta.setSelectionRange(newCursor, newCursor);
 | 
			
		||||
      ta.focus()
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  buttonBold.addEventListener("click", (e) => {
 | 
			
		||||
    e.preventDefault();
 | 
			
		||||
    insertTag("b")
 | 
			
		||||
  })
 | 
			
		||||
  buttonItalics.addEventListener("click", (e) => {
 | 
			
		||||
    e.preventDefault();
 | 
			
		||||
    insertTag("i")
 | 
			
		||||
  })
 | 
			
		||||
  buttonStrike.addEventListener("click", (e) => {
 | 
			
		||||
    e.preventDefault();
 | 
			
		||||
    insertTag("s")
 | 
			
		||||
  })
 | 
			
		||||
  buttonUrl.addEventListener("click", (e) => {
 | 
			
		||||
    e.preventDefault();
 | 
			
		||||
    insertTag("url=", false, "link label");
 | 
			
		||||
  })
 | 
			
		||||
  buttonCode.addEventListener("click", (e) => {
 | 
			
		||||
    e.preventDefault();
 | 
			
		||||
    insertTag("code", true)
 | 
			
		||||
  })
 | 
			
		||||
  buttonImg.addEventListener("click", (e) => {
 | 
			
		||||
    e.preventDefault();
 | 
			
		||||
    insertTag("img=", false, "alt text");
 | 
			
		||||
  })
 | 
			
		||||
  buttonOl.addEventListener("click", (e) => {
 | 
			
		||||
    e.preventDefault();
 | 
			
		||||
    insertTag("ol", true);
 | 
			
		||||
  })
 | 
			
		||||
  buttonUl.addEventListener("click", (e) => {
 | 
			
		||||
    e.preventDefault();
 | 
			
		||||
    insertTag("ul", true);
 | 
			
		||||
  })
 | 
			
		||||
  
 | 
			
		||||
  const previewEndpoint = "/api/babycode-preview";
 | 
			
		||||
  let previousMarkup = "";
 | 
			
		||||
  const previewTab = document.getElementById("tab-preview");
 | 
			
		||||
  previewTab.addEventListener("tab-activated", async () => {
 | 
			
		||||
    const previewContainer = document.getElementById("babycode-preview-container");
 | 
			
		||||
    const previewErrorsContainer = document.getElementById("babycode-preview-errors-container");
 | 
			
		||||
    // previewErrorsContainer.textContent = "";
 | 
			
		||||
    const markup = ta.value.trim();
 | 
			
		||||
    if (markup === "" || markup === previousMarkup) {
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
    previousMarkup = markup;
 | 
			
		||||
      const req = await fetch(previewEndpoint, {
 | 
			
		||||
        method: "POST",
 | 
			
		||||
        headers: {
 | 
			
		||||
          "Content-Type": "application/json",
 | 
			
		||||
        },
 | 
			
		||||
        body: JSON.stringify({markup: markup})
 | 
			
		||||
      })
 | 
			
		||||
      if (!req.ok) {
 | 
			
		||||
        switch (req.status) {
 | 
			
		||||
          case 429:
 | 
			
		||||
            previewErrorsContainer.textContent = "(Old preview, try again in a few seconds.)"
 | 
			
		||||
            previousMarkup = "";
 | 
			
		||||
            break;
 | 
			
		||||
          case 400:
 | 
			
		||||
            previewErrorsContainer.textContent = "(Request got malformed.)"
 | 
			
		||||
            break;
 | 
			
		||||
          case 401:
 | 
			
		||||
            previewErrorsContainer.textContent = "(You are not logged in.)"
 | 
			
		||||
            break;
 | 
			
		||||
          default:
 | 
			
		||||
            previewErrorsContainer.textContent = "(Error. Check console.)"
 | 
			
		||||
            console.error(req.error);
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
        return;
 | 
			
		||||
      }
 | 
			
		||||
      
 | 
			
		||||
      const json_resp = await req.json();
 | 
			
		||||
      previewContainer.innerHTML = json_resp.html;
 | 
			
		||||
      previewErrorsContainer.textContent = "";
 | 
			
		||||
  });
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										7
									
								
								data/static/js/copy-code.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								data/static/js/copy-code.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,7 @@
 | 
			
		||||
for (let button of document.querySelectorAll(".copy-code")) {
 | 
			
		||||
  button.addEventListener("click", async () => {
 | 
			
		||||
    await navigator.clipboard.writeText(button.value)
 | 
			
		||||
    button.textContent = "Copied!"
 | 
			
		||||
    setTimeout(() => {button.textContent = "Copy"}, 1000.0)
 | 
			
		||||
  })
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										10
									
								
								data/static/js/date-fmt.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								data/static/js/date-fmt.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,10 @@
 | 
			
		||||
document.addEventListener("DOMContentLoaded", () => {
 | 
			
		||||
  const timestampSpans = document.getElementsByClassName("timestamp");
 | 
			
		||||
  for (let timestampSpan of timestampSpans) {
 | 
			
		||||
    const timestamp = parseInt(timestampSpan.dataset.utc);
 | 
			
		||||
    if (!isNaN(timestamp)) {
 | 
			
		||||
      const date = new Date(timestamp * 1000);
 | 
			
		||||
      timestampSpan.textContent = date.toLocaleString();
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
})
 | 
			
		||||
							
								
								
									
										45
									
								
								data/static/js/sort-topics.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								data/static/js/sort-topics.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,45 @@
 | 
			
		||||
// https://codepen.io/crouchingtigerhiddenadam/pen/qKXgap
 | 
			
		||||
let selected = null;
 | 
			
		||||
let container = document.getElementById("topics-container")
 | 
			
		||||
 | 
			
		||||
function isBefore(el1, el2) {
 | 
			
		||||
  let cur
 | 
			
		||||
  if (el2.parentNode === el1.parentNode) {
 | 
			
		||||
    for (cur = el1.previousSibling; cur; cur = cur.previousSibling) {
 | 
			
		||||
      if (cur === el2) return true
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function dragOver(e) {
 | 
			
		||||
  let target = e.target.closest(".draggable-topic")
 | 
			
		||||
  
 | 
			
		||||
  if (!target || target === selected) {
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
  if (isBefore(selected, target)) {
 | 
			
		||||
    container.insertBefore(selected, target)
 | 
			
		||||
  } else {
 | 
			
		||||
    container.insertBefore(selected, target.nextSibling)
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function dragEnd() {
 | 
			
		||||
  if (!selected) return;
 | 
			
		||||
  
 | 
			
		||||
  selected.classList.remove("dragged")
 | 
			
		||||
  selected = null;
 | 
			
		||||
  for (let i = 0; i < container.childElementCount - 1; i++) {
 | 
			
		||||
    let input = container.children[i].querySelector(".topic-input");
 | 
			
		||||
    input.value = i + 1;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function dragStart(e) {
 | 
			
		||||
  e.dataTransfer.effectAllowed = 'move'
 | 
			
		||||
  e.dataTransfer.setData('text/plain', null)
 | 
			
		||||
  selected = e.target
 | 
			
		||||
  selected.classList.add("dragged")
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										80
									
								
								data/static/js/thread.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										80
									
								
								data/static/js/thread.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,80 @@
 | 
			
		||||
{
 | 
			
		||||
  const ta = document.getElementById("babycode-content");
 | 
			
		||||
  
 | 
			
		||||
  for (let button of document.querySelectorAll(".reply-button")) {
 | 
			
		||||
    button.addEventListener("click", (e) => {
 | 
			
		||||
      ta.value += button.value;
 | 
			
		||||
      ta.scrollIntoView()
 | 
			
		||||
      ta.focus();
 | 
			
		||||
    })
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
  const deleteDialog = document.getElementById("delete-dialog");
 | 
			
		||||
  const deleteDialogCloseButton = document.getElementById("post-delete-dialog-close");
 | 
			
		||||
  let deletionTargetPostContainer;
 | 
			
		||||
  
 | 
			
		||||
  function closeDeleteDialog() {
 | 
			
		||||
    deletionTargetPostContainer.style.removeProperty("background-color");
 | 
			
		||||
    deleteDialog.close();
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
  deleteDialogCloseButton.addEventListener("click", (e) => {
 | 
			
		||||
    closeDeleteDialog();
 | 
			
		||||
  })
 | 
			
		||||
  deleteDialog.addEventListener("click", (e) => {
 | 
			
		||||
    if (e.target === deleteDialog) {
 | 
			
		||||
      closeDeleteDialog();
 | 
			
		||||
    }
 | 
			
		||||
  })
 | 
			
		||||
  for (let button of document.querySelectorAll(".post-delete-button")) {
 | 
			
		||||
    button.addEventListener("click", (e) => {
 | 
			
		||||
      deleteDialog.showModal();
 | 
			
		||||
      const postId = button.value;
 | 
			
		||||
      deletionTargetPostContainer = document.getElementById("post-" + postId).querySelector(".post-content-container");
 | 
			
		||||
      deletionTargetPostContainer.style.setProperty("background-color", "#fff");
 | 
			
		||||
      const form = document.getElementById("post-delete-form");
 | 
			
		||||
      form.action = `/post/${postId}/delete`
 | 
			
		||||
    })
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
  const threadEndpoint = document.getElementById("thread-subscribe-endpoint").value;
 | 
			
		||||
  let now = Math.floor(new Date() / 1000);
 | 
			
		||||
  function hideNotification() {
 | 
			
		||||
    const notification = document.getElementById('new-post-notification');
 | 
			
		||||
    notification.classList.add('hidden');
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
  function showNewPostNotification(url) {
 | 
			
		||||
    const notification = document.getElementById("new-post-notification");
 | 
			
		||||
    
 | 
			
		||||
    notification.classList.remove("hidden");
 | 
			
		||||
    
 | 
			
		||||
    document.getElementById("dismiss-new-post-button").onclick = () => {
 | 
			
		||||
      now = Math.floor(new Date() / 1000);
 | 
			
		||||
      hideNotification();
 | 
			
		||||
      tryFetchUpdate();
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    document.getElementById("go-to-new-post-button").href = url;
 | 
			
		||||
    
 | 
			
		||||
    document.getElementById("unsub-new-post-button").onclick = () => {
 | 
			
		||||
      hideNotification();
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function tryFetchUpdate() {
 | 
			
		||||
    if (!threadEndpoint) return;
 | 
			
		||||
    const body = JSON.stringify({since: now});
 | 
			
		||||
    fetch(threadEndpoint, {method: "POST", headers: {"Content-Type": "application/json"}, body: body})
 | 
			
		||||
      .then(res => res.json())
 | 
			
		||||
      .then(json => {
 | 
			
		||||
        if (json.status === "none") {
 | 
			
		||||
          setTimeout(tryFetchUpdate, 5000);
 | 
			
		||||
        } else if (json.status === "new_post") {
 | 
			
		||||
          showNewPostNotification(json.url);
 | 
			
		||||
        }
 | 
			
		||||
      })
 | 
			
		||||
      .catch(error => console.log(error))
 | 
			
		||||
  }
 | 
			
		||||
  tryFetchUpdate();
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										16
									
								
								data/static/js/topic.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								data/static/js/topic.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,16 @@
 | 
			
		||||
{
 | 
			
		||||
  const deleteDialog = document.getElementById("delete-dialog");
 | 
			
		||||
  const deleteDialogOpenButton = document.getElementById("topic-delete-dialog-open");
 | 
			
		||||
  deleteDialogOpenButton.addEventListener("click", (e) => {
 | 
			
		||||
    deleteDialog.showModal();
 | 
			
		||||
  });
 | 
			
		||||
  const deleteDialogCloseButton = document.getElementById("topic-delete-dialog-close");
 | 
			
		||||
  deleteDialogCloseButton.addEventListener("click", (e) => {
 | 
			
		||||
    deleteDialog.close();
 | 
			
		||||
  })
 | 
			
		||||
  deleteDialog.addEventListener("click", (e) => {
 | 
			
		||||
    if (e.target === deleteDialog) {
 | 
			
		||||
      deleteDialog.close();
 | 
			
		||||
    }
 | 
			
		||||
  })
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										147
									
								
								data/static/js/ui.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										147
									
								
								data/static/js/ui.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,147 @@
 | 
			
		||||
function activateSelfDeactivateSibs(button) {
 | 
			
		||||
  if (button.classList.contains("active")) return;
 | 
			
		||||
  
 | 
			
		||||
  Array.from(button.parentNode.children).forEach(s => {
 | 
			
		||||
    if (s === button){
 | 
			
		||||
      button.classList.add('active');
 | 
			
		||||
    } else {
 | 
			
		||||
      s.classList.remove('active');
 | 
			
		||||
    }
 | 
			
		||||
    const targetId = s.dataset.targetId;
 | 
			
		||||
    const target = document.getElementById(targetId);
 | 
			
		||||
    
 | 
			
		||||
    if (!target) return;
 | 
			
		||||
    
 | 
			
		||||
    if (s.classList.contains('active')) {
 | 
			
		||||
      target.classList.add('active');
 | 
			
		||||
      target.dispatchEvent(new CustomEvent("tab-activated", {bubbles: false}))
 | 
			
		||||
    } else {
 | 
			
		||||
      target.classList.remove('active');
 | 
			
		||||
    }
 | 
			
		||||
  });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function openLightbox(post, idx) {
 | 
			
		||||
  lightboxCurrentPost = post;
 | 
			
		||||
  lightboxCurrentIdx = idx;
 | 
			
		||||
  lightboxObj.img.src = lightboxImages.get(post)[idx].src;
 | 
			
		||||
  lightboxObj.openOriginalAnchor.href = lightboxImages.get(post)[idx].src
 | 
			
		||||
  lightboxObj.prevButton.disabled = lightboxImages.get(post).length === 1
 | 
			
		||||
  lightboxObj.nextButton.disabled = lightboxImages.get(post).length === 1
 | 
			
		||||
  lightboxObj.imageCount.textContent = `Image ${idx + 1} of ${lightboxImages.get(post).length}`
 | 
			
		||||
  
 | 
			
		||||
  if (!lightboxObj.dialog.open) {
 | 
			
		||||
    lightboxObj.dialog.showModal();
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const modulo = (n, m) => ((n % m) + m) % m
 | 
			
		||||
 | 
			
		||||
function lightboxNext() {
 | 
			
		||||
  const l = lightboxImages.get(lightboxCurrentPost).length;
 | 
			
		||||
  const target = modulo(lightboxCurrentIdx + 1, l);
 | 
			
		||||
  openLightbox(lightboxCurrentPost, target);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function lightboxPrev() {
 | 
			
		||||
  const l = lightboxImages.get(lightboxCurrentPost).length;
 | 
			
		||||
  const target = modulo(lightboxCurrentIdx - 1, l);
 | 
			
		||||
  openLightbox(lightboxCurrentPost, target);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function constructLightbox() {
 | 
			
		||||
  const dialog = document.createElement("dialog");
 | 
			
		||||
  dialog.classList.add("lightbox-dialog");
 | 
			
		||||
  dialog.addEventListener("click", (e) => {
 | 
			
		||||
    if (e.target === dialog) {
 | 
			
		||||
      dialog.close();
 | 
			
		||||
    }
 | 
			
		||||
  })
 | 
			
		||||
  const dialogInner = document.createElement("div");
 | 
			
		||||
  dialogInner.classList.add("lightbox-inner");
 | 
			
		||||
  dialog.appendChild(dialogInner);
 | 
			
		||||
  const img = document.createElement("img");
 | 
			
		||||
  img.classList.add("lightbox-image")
 | 
			
		||||
  dialogInner.appendChild(img);
 | 
			
		||||
  const openOriginalAnchor = document.createElement("a")
 | 
			
		||||
  openOriginalAnchor.text = "Open original in new window"
 | 
			
		||||
  openOriginalAnchor.target = "_blank"
 | 
			
		||||
  openOriginalAnchor.rel = "noopener noreferrer nofollow"
 | 
			
		||||
  dialogInner.appendChild(openOriginalAnchor);
 | 
			
		||||
  
 | 
			
		||||
  const navSpan = document.createElement("span");
 | 
			
		||||
  navSpan.classList.add("lightbox-nav");
 | 
			
		||||
  const prevButton = document.createElement("button");
 | 
			
		||||
  prevButton.type = "button";
 | 
			
		||||
  prevButton.textContent = "Previous";
 | 
			
		||||
  prevButton.addEventListener("click", lightboxPrev);
 | 
			
		||||
  const nextButton = document.createElement("button");
 | 
			
		||||
  nextButton.type = "button";
 | 
			
		||||
  nextButton.textContent = "Next";
 | 
			
		||||
  nextButton.addEventListener("click", lightboxNext);
 | 
			
		||||
  const imageCount = document.createElement("span");
 | 
			
		||||
  imageCount.textContent = "Image of ";
 | 
			
		||||
  navSpan.appendChild(prevButton);
 | 
			
		||||
  navSpan.appendChild(imageCount);
 | 
			
		||||
  navSpan.appendChild(nextButton);
 | 
			
		||||
  
 | 
			
		||||
  dialogInner.appendChild(navSpan);
 | 
			
		||||
  return {
 | 
			
		||||
    img: img,
 | 
			
		||||
    dialog: dialog,
 | 
			
		||||
    openOriginalAnchor: openOriginalAnchor,
 | 
			
		||||
    prevButton: prevButton,
 | 
			
		||||
    nextButton: nextButton,
 | 
			
		||||
    imageCount: imageCount,
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
let lightboxImages = new Map(); //.post-inner : Array<Object>
 | 
			
		||||
let lightboxObj = null;
 | 
			
		||||
let lightboxCurrentPost = null;
 | 
			
		||||
let lightboxCurrentIdx = -1;
 | 
			
		||||
 | 
			
		||||
document.addEventListener("DOMContentLoaded", () => {
 | 
			
		||||
  // tabs
 | 
			
		||||
  document.querySelectorAll(".tab-button").forEach(button => {
 | 
			
		||||
    button.addEventListener("click", () => {
 | 
			
		||||
      activateSelfDeactivateSibs(button);
 | 
			
		||||
    });
 | 
			
		||||
  });
 | 
			
		||||
  
 | 
			
		||||
  // accordions
 | 
			
		||||
  const accordions = document.querySelectorAll(".accordion");
 | 
			
		||||
  accordions.forEach(accordion => {
 | 
			
		||||
    const header = accordion.querySelector(".accordion-header");
 | 
			
		||||
    const toggleButton = header.querySelector(".accordion-toggle");
 | 
			
		||||
    const content = accordion.querySelector(".accordion-content");
 | 
			
		||||
    
 | 
			
		||||
    const toggle = (e) => {
 | 
			
		||||
      e.stopPropagation();
 | 
			
		||||
      accordion.classList.toggle("hidden");
 | 
			
		||||
      content.classList.toggle("hidden");
 | 
			
		||||
      toggleButton.textContent = content.classList.contains("hidden") ? "►" : "▼"
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    toggleButton.addEventListener("click", toggle);
 | 
			
		||||
  });
 | 
			
		||||
  
 | 
			
		||||
  //lightboxes
 | 
			
		||||
  lightboxObj = constructLightbox();
 | 
			
		||||
  document.body.appendChild(lightboxObj.dialog);
 | 
			
		||||
  const postImages = document.querySelectorAll(".post-inner img.block-img");
 | 
			
		||||
  postImages.forEach(postImage => {
 | 
			
		||||
    const belongingTo = postImage.closest(".post-inner");
 | 
			
		||||
    const images = lightboxImages.get(belongingTo) ?? [];
 | 
			
		||||
    images.push({
 | 
			
		||||
      src: postImage.src,
 | 
			
		||||
      alt: postImage.alt,
 | 
			
		||||
    });
 | 
			
		||||
    const idx = images.length - 1;
 | 
			
		||||
    lightboxImages.set(belongingTo, images);
 | 
			
		||||
    postImage.style.cursor = "pointer";
 | 
			
		||||
    postImage.addEventListener("click", () => {
 | 
			
		||||
      openLightbox(belongingTo, idx);
 | 
			
		||||
    });
 | 
			
		||||
  });
 | 
			
		||||
});
 | 
			
		||||
							
								
								
									
										735
									
								
								data/static/style.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										735
									
								
								data/static/style.css
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,735 @@
 | 
			
		||||
@font-face {
 | 
			
		||||
  font-family: "site-title";
 | 
			
		||||
  src: url("/static/fonts/ChicagoFLF.woff2");
 | 
			
		||||
}
 | 
			
		||||
@font-face {
 | 
			
		||||
  font-family: "Cadman";
 | 
			
		||||
  src: url("/static/fonts/Cadman_Roman.woff2");
 | 
			
		||||
  font-weight: normal;
 | 
			
		||||
  font-style: normal;
 | 
			
		||||
}
 | 
			
		||||
@font-face {
 | 
			
		||||
  font-family: "Cadman";
 | 
			
		||||
  src: url("/static/fonts/Cadman_Bold.woff2");
 | 
			
		||||
  font-weight: bold;
 | 
			
		||||
  font-style: normal;
 | 
			
		||||
}
 | 
			
		||||
@font-face {
 | 
			
		||||
  font-family: "Cadman";
 | 
			
		||||
  src: url("/static/fonts/Cadman_Italic.woff2");
 | 
			
		||||
  font-weight: normal;
 | 
			
		||||
  font-style: italic;
 | 
			
		||||
}
 | 
			
		||||
@font-face {
 | 
			
		||||
  font-family: "Cadman";
 | 
			
		||||
  src: url("/static/fonts/Cadman_BoldItalic.woff2");
 | 
			
		||||
  font-weight: bold;
 | 
			
		||||
  font-style: italic;
 | 
			
		||||
}
 | 
			
		||||
.tab-button, .currentpage, .pagebutton, input[type=file]::file-selector-button, button.warn, input[type=submit].warn, .linkbutton.warn, button.critical, input[type=submit].critical, .linkbutton.critical, button, input[type=submit], .linkbutton {
 | 
			
		||||
  cursor: default;
 | 
			
		||||
  color: black;
 | 
			
		||||
  font-size: 0.9em;
 | 
			
		||||
  font-family: "Cadman";
 | 
			
		||||
  text-decoration: none;
 | 
			
		||||
  border: 1px solid black;
 | 
			
		||||
  border-radius: 3px;
 | 
			
		||||
  padding: 5px 20px;
 | 
			
		||||
  margin: 10px 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
body {
 | 
			
		||||
  font-family: "Cadman";
 | 
			
		||||
  margin: 20px 100px;
 | 
			
		||||
  background-color: rgb(173.5214173228, 183.6737007874, 161.0262992126);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.big {
 | 
			
		||||
  font-size: 1.8rem;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#topnav {
 | 
			
		||||
  padding: 10px;
 | 
			
		||||
  display: flex;
 | 
			
		||||
  justify-content: end;
 | 
			
		||||
  background-color: #c1ceb1;
 | 
			
		||||
  justify-content: space-between;
 | 
			
		||||
  align-items: baseline;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#bottomnav {
 | 
			
		||||
  padding: 10px;
 | 
			
		||||
  display: flex;
 | 
			
		||||
  justify-content: end;
 | 
			
		||||
  background-color: rgb(143.7039271654, 144.3879625984, 142.8620374016);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.darkbg {
 | 
			
		||||
  padding-bottom: 10px;
 | 
			
		||||
  padding-left: 10px;
 | 
			
		||||
  padding-right: 10px;
 | 
			
		||||
  background-color: rgb(143.7039271654, 144.3879625984, 142.8620374016);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.user-actions {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  column-gap: 15px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.site-title {
 | 
			
		||||
  font-family: "site-title";
 | 
			
		||||
  font-size: 3rem;
 | 
			
		||||
  margin: 0 20px;
 | 
			
		||||
  text-decoration: none;
 | 
			
		||||
  color: black;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.thread-title {
 | 
			
		||||
  margin: 0;
 | 
			
		||||
  font-size: 1.5rem;
 | 
			
		||||
  font-weight: bold;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.post {
 | 
			
		||||
  display: grid;
 | 
			
		||||
  grid-template-columns: 200px 1fr;
 | 
			
		||||
  grid-template-rows: 1fr;
 | 
			
		||||
  gap: 0;
 | 
			
		||||
  grid-auto-flow: row;
 | 
			
		||||
  grid-template-areas: "usercard post-content-container";
 | 
			
		||||
  border: 2px outset rgb(135.1928346457, 145.0974015748, 123.0025984252);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.usercard {
 | 
			
		||||
  grid-area: usercard;
 | 
			
		||||
  padding: 20px 10px;
 | 
			
		||||
  border: 4px outset rgb(217.26, 220.38, 213.42);
 | 
			
		||||
  background-color: rgb(143.7039271654, 144.3879625984, 142.8620374016);
 | 
			
		||||
  border-right: solid 2px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.usercard-inner {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  flex-direction: column;
 | 
			
		||||
  align-items: center;
 | 
			
		||||
  top: 10px;
 | 
			
		||||
  position: sticky;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.post-content-container {
 | 
			
		||||
  display: grid;
 | 
			
		||||
  grid-template-columns: 1fr;
 | 
			
		||||
  grid-template-rows: 70px 2.5fr;
 | 
			
		||||
  gap: 0px 0px;
 | 
			
		||||
  grid-auto-flow: row;
 | 
			
		||||
  grid-template-areas: "post-info" "post-content";
 | 
			
		||||
  grid-area: post-content-container;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.post-info {
 | 
			
		||||
  grid-area: post-info;
 | 
			
		||||
  display: flex;
 | 
			
		||||
  justify-content: space-between;
 | 
			
		||||
  padding: 5px 20px;
 | 
			
		||||
  align-items: center;
 | 
			
		||||
  border-top: 1px solid black;
 | 
			
		||||
  border-bottom: 1px solid black;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.post-content {
 | 
			
		||||
  grid-area: post-content;
 | 
			
		||||
  padding: 20px;
 | 
			
		||||
  margin-right: 25%;
 | 
			
		||||
  display: flex;
 | 
			
		||||
  flex-direction: column;
 | 
			
		||||
  overflow: hidden;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.post-content.wider {
 | 
			
		||||
  margin-right: 12.5%;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.post-inner {
 | 
			
		||||
  height: 100%;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pre code {
 | 
			
		||||
  display: block;
 | 
			
		||||
  background-color: rgb(38.5714173228, 40.9237007874, 35.6762992126);
 | 
			
		||||
  font-size: 1rem;
 | 
			
		||||
  color: white;
 | 
			
		||||
  border-bottom-right-radius: 8px;
 | 
			
		||||
  border-bottom-left-radius: 8px;
 | 
			
		||||
  border-left: 10px solid rgb(229.84, 231.92, 227.28);
 | 
			
		||||
  padding: 20px;
 | 
			
		||||
  overflow: scroll;
 | 
			
		||||
  tab-size: 4;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.inline-code {
 | 
			
		||||
  background-color: rgb(38.5714173228, 40.9237007874, 35.6762992126);
 | 
			
		||||
  color: white;
 | 
			
		||||
  padding: 5px 10px;
 | 
			
		||||
  display: inline-block;
 | 
			
		||||
  margin: 4px;
 | 
			
		||||
  border-radius: 4px;
 | 
			
		||||
  font-size: 1rem;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#delete-dialog, .lightbox-dialog {
 | 
			
		||||
  padding: 0;
 | 
			
		||||
  border-radius: 4px;
 | 
			
		||||
  border: 2px solid black;
 | 
			
		||||
  box-shadow: 0 0 30px rgba(0, 0, 0, 0.25);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.delete-dialog-inner {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  flex-direction: column;
 | 
			
		||||
  align-items: center;
 | 
			
		||||
  padding: 20px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.lightbox-inner {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  flex-direction: column;
 | 
			
		||||
  padding: 20px;
 | 
			
		||||
  min-width: 400px;
 | 
			
		||||
  background-color: #c1ceb1;
 | 
			
		||||
  gap: 10px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.lightbox-image {
 | 
			
		||||
  max-width: 70vw;
 | 
			
		||||
  max-height: 70vh;
 | 
			
		||||
  object-fit: scale-down;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.lightbox-nav {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  justify-content: space-between;
 | 
			
		||||
  align-items: center;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.copy-code-container {
 | 
			
		||||
  position: sticky;
 | 
			
		||||
  width: calc(100% - 4px);
 | 
			
		||||
  display: flex;
 | 
			
		||||
  justify-content: space-between;
 | 
			
		||||
  align-items: last baseline;
 | 
			
		||||
  font-family: "Cadman";
 | 
			
		||||
  border-top-right-radius: 8px;
 | 
			
		||||
  border-top-left-radius: 8px;
 | 
			
		||||
  background-color: #c1ceb1;
 | 
			
		||||
  border-left: 2px solid black;
 | 
			
		||||
  border-right: 2px solid black;
 | 
			
		||||
  border-top: 2px solid black;
 | 
			
		||||
}
 | 
			
		||||
.copy-code-container::before {
 | 
			
		||||
  content: "code block";
 | 
			
		||||
  font-style: italic;
 | 
			
		||||
  margin-left: 10px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.copy-code {
 | 
			
		||||
  margin-right: 10px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
blockquote {
 | 
			
		||||
  padding: 10px 20px;
 | 
			
		||||
  margin: 10px;
 | 
			
		||||
  border-radius: 4px;
 | 
			
		||||
  border-left: 10px solid rgb(229.84, 231.92, 227.28);
 | 
			
		||||
  background-color: rgb(135.1928346457, 145.0974015748, 123.0025984252);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.user-info {
 | 
			
		||||
  display: grid;
 | 
			
		||||
  grid-template-columns: 300px 1fr;
 | 
			
		||||
  grid-template-rows: 1fr;
 | 
			
		||||
  gap: 0;
 | 
			
		||||
  grid-template-areas: "user-page-usercard user-page-stats";
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.user-page-usercard {
 | 
			
		||||
  grid-area: user-page-usercard;
 | 
			
		||||
  padding: 20px 10px;
 | 
			
		||||
  border: 4px outset rgb(217.26, 220.38, 213.42);
 | 
			
		||||
  background-color: rgb(143.7039271654, 144.3879625984, 142.8620374016);
 | 
			
		||||
  border-right: solid 2px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.user-page-stats {
 | 
			
		||||
  grid-area: user-page-stats;
 | 
			
		||||
  padding: 20px 30px;
 | 
			
		||||
  border: 1px solid black;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.user-stats-list {
 | 
			
		||||
  list-style: none;
 | 
			
		||||
  margin: 0 0 10px 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.user-page-posts {
 | 
			
		||||
  border-left: solid 1px black;
 | 
			
		||||
  border-right: solid 1px black;
 | 
			
		||||
  border-bottom: solid 1px black;
 | 
			
		||||
  background-color: #c1ceb1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.user-page-post-preview {
 | 
			
		||||
  max-height: 200px;
 | 
			
		||||
  mask-image: linear-gradient(180deg, #000 60%, transparent);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.avatar {
 | 
			
		||||
  width: 90%;
 | 
			
		||||
  height: 90%;
 | 
			
		||||
  object-fit: contain;
 | 
			
		||||
  margin-bottom: 10px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.username-link {
 | 
			
		||||
  overflow-wrap: anywhere;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.user-status {
 | 
			
		||||
  text-align: center;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
button, input[type=submit], .linkbutton {
 | 
			
		||||
  display: inline-block;
 | 
			
		||||
  background-color: rgb(177, 206, 204.5);
 | 
			
		||||
}
 | 
			
		||||
button:hover, input[type=submit]:hover, .linkbutton:hover {
 | 
			
		||||
  background-color: rgb(192.6, 215.8, 214.6);
 | 
			
		||||
}
 | 
			
		||||
button:active, input[type=submit]:active, .linkbutton:active {
 | 
			
		||||
  background-color: rgb(166.6881496063, 178.0118503937, 177.4261417323);
 | 
			
		||||
}
 | 
			
		||||
button:disabled, input[type=submit]:disabled, .linkbutton:disabled {
 | 
			
		||||
  background-color: rgb(209.535, 211.565, 211.46);
 | 
			
		||||
}
 | 
			
		||||
button.critical, input[type=submit].critical, .linkbutton.critical {
 | 
			
		||||
  color: white;
 | 
			
		||||
  background-color: red;
 | 
			
		||||
}
 | 
			
		||||
button.critical:hover, input[type=submit].critical:hover, .linkbutton.critical:hover {
 | 
			
		||||
  background-color: #ff3333;
 | 
			
		||||
}
 | 
			
		||||
button.critical:active, input[type=submit].critical:active, .linkbutton.critical:active {
 | 
			
		||||
  background-color: rgb(149.175, 80.325, 80.325);
 | 
			
		||||
}
 | 
			
		||||
button.critical:disabled, input[type=submit].critical:disabled, .linkbutton.critical:disabled {
 | 
			
		||||
  background-color: rgb(174.675, 156.825, 156.825);
 | 
			
		||||
}
 | 
			
		||||
button.warn, input[type=submit].warn, .linkbutton.warn {
 | 
			
		||||
  background-color: #fbfb8d;
 | 
			
		||||
}
 | 
			
		||||
button.warn:hover, input[type=submit].warn:hover, .linkbutton.warn:hover {
 | 
			
		||||
  background-color: rgb(251.8, 251.8, 163.8);
 | 
			
		||||
}
 | 
			
		||||
button.warn:active, input[type=submit].warn:active, .linkbutton.warn:active {
 | 
			
		||||
  background-color: rgb(198.3813559322, 198.3813559322, 154.4186440678);
 | 
			
		||||
}
 | 
			
		||||
button.warn:disabled, input[type=submit].warn:disabled, .linkbutton.warn:disabled {
 | 
			
		||||
  background-color: rgb(217.55, 217.55, 209.85);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
input[type=file]::file-selector-button {
 | 
			
		||||
  background-color: rgb(177, 206, 204.5);
 | 
			
		||||
  margin: 10px 10px;
 | 
			
		||||
}
 | 
			
		||||
input[type=file]::file-selector-button:hover {
 | 
			
		||||
  background-color: rgb(192.6, 215.8, 214.6);
 | 
			
		||||
}
 | 
			
		||||
input[type=file]::file-selector-button:active {
 | 
			
		||||
  background-color: rgb(166.6881496063, 178.0118503937, 177.4261417323);
 | 
			
		||||
}
 | 
			
		||||
input[type=file]::file-selector-button:disabled {
 | 
			
		||||
  background-color: rgb(209.535, 211.565, 211.46);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
p {
 | 
			
		||||
  margin: 15px 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.pagebutton {
 | 
			
		||||
  background-color: rgb(177, 206, 204.5);
 | 
			
		||||
  padding: 5px 5px;
 | 
			
		||||
  margin: 0;
 | 
			
		||||
  display: inline-block;
 | 
			
		||||
  min-width: 20px;
 | 
			
		||||
  text-align: center;
 | 
			
		||||
}
 | 
			
		||||
.pagebutton:hover {
 | 
			
		||||
  background-color: rgb(192.6, 215.8, 214.6);
 | 
			
		||||
}
 | 
			
		||||
.pagebutton:active {
 | 
			
		||||
  background-color: rgb(166.6881496063, 178.0118503937, 177.4261417323);
 | 
			
		||||
}
 | 
			
		||||
.pagebutton:disabled {
 | 
			
		||||
  background-color: rgb(209.535, 211.565, 211.46);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.currentpage {
 | 
			
		||||
  border: none;
 | 
			
		||||
  padding: 5px 5px;
 | 
			
		||||
  margin: 0;
 | 
			
		||||
  display: inline-block;
 | 
			
		||||
  min-width: 20px;
 | 
			
		||||
  text-align: center;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.modform {
 | 
			
		||||
  display: inline;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.login-container > * {
 | 
			
		||||
  width: 25%;
 | 
			
		||||
  margin: auto;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.settings-container > * {
 | 
			
		||||
  width: 40%;
 | 
			
		||||
  margin: auto;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.avatar-form {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  flex-direction: column;
 | 
			
		||||
  align-items: center;
 | 
			
		||||
  padding: 20px 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
input[type=text], input[type=password], textarea, select {
 | 
			
		||||
  border: 1px solid black;
 | 
			
		||||
  border-radius: 3px;
 | 
			
		||||
  padding: 7px 10px;
 | 
			
		||||
  width: 100%;
 | 
			
		||||
  box-sizing: border-box;
 | 
			
		||||
  resize: vertical;
 | 
			
		||||
  background-color: rgb(217.8, 225.6, 208.2);
 | 
			
		||||
}
 | 
			
		||||
input[type=text]:focus, input[type=password]:focus, textarea:focus, select:focus {
 | 
			
		||||
  background-color: rgb(230.2, 235.4, 223.8);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.infobox {
 | 
			
		||||
  border: 2px solid black;
 | 
			
		||||
  background-color: #81a3e6;
 | 
			
		||||
  padding: 20px 15px;
 | 
			
		||||
}
 | 
			
		||||
.infobox.critical {
 | 
			
		||||
  background-color: rgb(237, 129, 129);
 | 
			
		||||
}
 | 
			
		||||
.infobox.warn {
 | 
			
		||||
  background-color: #fbfb8d;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.infobox > span {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  align-items: center;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.infobox-icon-container {
 | 
			
		||||
  min-width: 60px;
 | 
			
		||||
  padding-right: 15px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.thread {
 | 
			
		||||
  display: grid;
 | 
			
		||||
  grid-template-columns: 96px 1.6fr 96px;
 | 
			
		||||
  grid-template-rows: 1fr;
 | 
			
		||||
  gap: 0px 0px;
 | 
			
		||||
  grid-auto-flow: row;
 | 
			
		||||
  min-height: 96px;
 | 
			
		||||
  grid-template-areas: "thread-sticky-container thread-info-container thread-locked-container";
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.thread-sticky-container {
 | 
			
		||||
  grid-area: thread-sticky-container;
 | 
			
		||||
  border: 2px outset rgb(217.26, 220.38, 213.42);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.thread-locked-container {
 | 
			
		||||
  grid-area: thread-locked-container;
 | 
			
		||||
  border: 2px outset rgb(217.26, 220.38, 213.42);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.contain-svg {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  align-items: center;
 | 
			
		||||
  justify-content: center;
 | 
			
		||||
  flex-direction: column;
 | 
			
		||||
}
 | 
			
		||||
.contain-svg:not(.full) > svg {
 | 
			
		||||
  height: 50%;
 | 
			
		||||
  width: 50%;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.block-img {
 | 
			
		||||
  object-fit: contain;
 | 
			
		||||
  max-width: 400px;
 | 
			
		||||
  max-height: 400px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.thread-info-container {
 | 
			
		||||
  grid-area: thread-info-container;
 | 
			
		||||
  background-color: #c1ceb1;
 | 
			
		||||
  padding: 5px 20px;
 | 
			
		||||
  border-top: 1px solid black;
 | 
			
		||||
  border-bottom: 1px solid black;
 | 
			
		||||
  display: flex;
 | 
			
		||||
  flex-direction: column;
 | 
			
		||||
  overflow: hidden;
 | 
			
		||||
  max-height: 110px;
 | 
			
		||||
  mask-image: linear-gradient(180deg, #000 60%, transparent);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.thread-info-post-preview {
 | 
			
		||||
  overflow: hidden;
 | 
			
		||||
  text-overflow: ellipsis;
 | 
			
		||||
  display: inline;
 | 
			
		||||
  margin-right: 25%;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.babycode-guide-section {
 | 
			
		||||
  background-color: #c1ceb1;
 | 
			
		||||
  padding: 5px 20px;
 | 
			
		||||
  border: 1px solid black;
 | 
			
		||||
  padding-right: 25%;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.babycode-guide-container {
 | 
			
		||||
  display: grid;
 | 
			
		||||
  grid-template-columns: 1.5fr 300px;
 | 
			
		||||
  grid-template-rows: 1fr;
 | 
			
		||||
  gap: 0px 0px;
 | 
			
		||||
  grid-auto-flow: row;
 | 
			
		||||
  grid-template-areas: "guide-topics guide-toc";
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.guide-topics {
 | 
			
		||||
  grid-area: guide-topics;
 | 
			
		||||
  overflow: hidden;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.guide-toc {
 | 
			
		||||
  grid-area: guide-toc;
 | 
			
		||||
  position: sticky;
 | 
			
		||||
  top: 100px;
 | 
			
		||||
  align-self: start;
 | 
			
		||||
  padding: 10px;
 | 
			
		||||
  border-bottom-right-radius: 8px;
 | 
			
		||||
  background-color: rgb(177, 206, 204.5);
 | 
			
		||||
  border-right: 1px solid black;
 | 
			
		||||
  border-top: 1px solid black;
 | 
			
		||||
  border-bottom: 1px solid black;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.emoji-table tr td {
 | 
			
		||||
  text-align: center;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.emoji-table tr th {
 | 
			
		||||
  padding-left: 50px;
 | 
			
		||||
  padding-right: 50px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.emoji-table {
 | 
			
		||||
  margin: auto;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.emoji-table, th, td {
 | 
			
		||||
  border: 1px solid black;
 | 
			
		||||
  border-collapse: collapse;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.topic {
 | 
			
		||||
  display: grid;
 | 
			
		||||
  grid-template-columns: 1.5fr 64px;
 | 
			
		||||
  grid-template-rows: 1fr;
 | 
			
		||||
  gap: 0px 0px;
 | 
			
		||||
  grid-auto-flow: row;
 | 
			
		||||
  grid-template-areas: "topic-info-container topic-locked-container";
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.topic-info-container {
 | 
			
		||||
  grid-area: topic-info-container;
 | 
			
		||||
  background-color: #c1ceb1;
 | 
			
		||||
  padding: 5px 20px;
 | 
			
		||||
  border: 1px solid black;
 | 
			
		||||
  display: flex;
 | 
			
		||||
  flex-direction: column;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.topic-locked-container {
 | 
			
		||||
  grid-area: topic-locked-container;
 | 
			
		||||
  border: 2px outset rgb(217.26, 220.38, 213.42);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.draggable-topic {
 | 
			
		||||
  cursor: pointer;
 | 
			
		||||
  user-select: none;
 | 
			
		||||
  background-color: #c1ceb1;
 | 
			
		||||
  padding: 20px;
 | 
			
		||||
  margin: 12px 0;
 | 
			
		||||
  border-top: 6px outset rgb(217.26, 220.38, 213.42);
 | 
			
		||||
  border-bottom: 6px outset rgb(135.1928346457, 145.0974015748, 123.0025984252);
 | 
			
		||||
}
 | 
			
		||||
.draggable-topic.dragged {
 | 
			
		||||
  background-color: rgb(177, 206, 204.5);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.editing {
 | 
			
		||||
  background-color: rgb(217.26, 220.38, 213.42);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.context-explain {
 | 
			
		||||
  margin: 20px 0;
 | 
			
		||||
  display: flex;
 | 
			
		||||
  justify-content: space-evenly;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.post-edit-form {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  flex-direction: column;
 | 
			
		||||
  align-items: baseline;
 | 
			
		||||
  height: 100%;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.babycode-editor {
 | 
			
		||||
  height: 150px;
 | 
			
		||||
  font-size: 1rem;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.babycode-editor-container {
 | 
			
		||||
  width: 100%;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.babycode-preview-errors-container {
 | 
			
		||||
  font-size: 0.8rem;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.tab-button {
 | 
			
		||||
  background-color: rgb(177, 206, 204.5);
 | 
			
		||||
  border-bottom: none;
 | 
			
		||||
  border-bottom-left-radius: 0;
 | 
			
		||||
  border-bottom-right-radius: 0;
 | 
			
		||||
  margin-bottom: 0;
 | 
			
		||||
}
 | 
			
		||||
.tab-button:hover {
 | 
			
		||||
  background-color: rgb(192.6, 215.8, 214.6);
 | 
			
		||||
}
 | 
			
		||||
.tab-button:active {
 | 
			
		||||
  background-color: rgb(166.6881496063, 178.0118503937, 177.4261417323);
 | 
			
		||||
}
 | 
			
		||||
.tab-button:disabled {
 | 
			
		||||
  background-color: rgb(209.535, 211.565, 211.46);
 | 
			
		||||
}
 | 
			
		||||
.tab-button.active {
 | 
			
		||||
  background-color: #beb1ce;
 | 
			
		||||
  padding-top: 8px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.tab-content {
 | 
			
		||||
  display: none;
 | 
			
		||||
}
 | 
			
		||||
.tab-content.active {
 | 
			
		||||
  min-height: 250px;
 | 
			
		||||
  display: block;
 | 
			
		||||
  background-color: rgb(191.3137931034, 189.7, 193.3);
 | 
			
		||||
  border: 1px solid black;
 | 
			
		||||
  padding: 10px;
 | 
			
		||||
  border-top-right-radius: 3px;
 | 
			
		||||
  border-bottom-right-radius: 3px;
 | 
			
		||||
  border-bottom-left-radius: 3px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ul, ol {
 | 
			
		||||
  margin: 10px 0 10px 30px;
 | 
			
		||||
  padding: 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.new-concept-notification.hidden {
 | 
			
		||||
  display: none;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.new-concept-notification {
 | 
			
		||||
  position: fixed;
 | 
			
		||||
  bottom: 80px;
 | 
			
		||||
  right: 80px;
 | 
			
		||||
  border: 2px solid black;
 | 
			
		||||
  background-color: #81a3e6;
 | 
			
		||||
  padding: 20px 15px;
 | 
			
		||||
  border-radius: 4px;
 | 
			
		||||
  box-shadow: 0 0 30px rgba(0, 0, 0, 0.25);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.emoji {
 | 
			
		||||
  max-width: 15px;
 | 
			
		||||
  max-height: 15px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.accordion {
 | 
			
		||||
  border-top-right-radius: 3px;
 | 
			
		||||
  border-top-left-radius: 3px;
 | 
			
		||||
  box-sizing: border-box;
 | 
			
		||||
  border: 1px solid black;
 | 
			
		||||
  margin: 10px 5px;
 | 
			
		||||
  overflow: hidden;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.accordion.hidden {
 | 
			
		||||
  border-bottom: none;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.accordion-header {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  align-items: center;
 | 
			
		||||
  background-color: rgb(159.0271653543, 162.0727712915, 172.9728346457);
 | 
			
		||||
  padding: 0 10px;
 | 
			
		||||
  gap: 10px;
 | 
			
		||||
  border-bottom: 1px solid black;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.accordion-toggle {
 | 
			
		||||
  padding: 0;
 | 
			
		||||
  width: 36px;
 | 
			
		||||
  height: 36px;
 | 
			
		||||
  min-width: 36px;
 | 
			
		||||
  min-height: 36px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.accordion-title {
 | 
			
		||||
  margin-right: auto;
 | 
			
		||||
  overflow: hidden;
 | 
			
		||||
  text-overflow: ellipsis;
 | 
			
		||||
  white-space: nowrap;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.accordion-content {
 | 
			
		||||
  padding: 0 15px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.accordion-content.hidden {
 | 
			
		||||
  display: none;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.inbox-container {
 | 
			
		||||
  padding: 10px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.babycode-button-container {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  gap: 10px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.babycode-button {
 | 
			
		||||
  padding: 5px 10px;
 | 
			
		||||
  min-width: 36px;
 | 
			
		||||
}
 | 
			
		||||
.babycode-button > * {
 | 
			
		||||
  font-size: 1rem;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										744
									
								
								sass/style.scss
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										744
									
								
								sass/style.scss
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,744 @@
 | 
			
		||||
@use "sass:color";
 | 
			
		||||
 | 
			
		||||
@font-face {
 | 
			
		||||
  font-family: "site-title";
 | 
			
		||||
  src: url("/static/fonts/ChicagoFLF.woff2");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@mixin cadman($var) {
 | 
			
		||||
  font-family: "Cadman";
 | 
			
		||||
  src: url("/static/fonts/Cadman_#{$var}.woff2");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@font-face {
 | 
			
		||||
  @include cadman("Roman");
 | 
			
		||||
  font-weight: normal;
 | 
			
		||||
  font-style: normal;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@font-face {
 | 
			
		||||
  @include cadman("Bold");
 | 
			
		||||
  font-weight: bold;
 | 
			
		||||
  font-style: normal;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@font-face {
 | 
			
		||||
  @include cadman("Italic");
 | 
			
		||||
  font-weight: normal;
 | 
			
		||||
  font-style: italic;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@font-face {
 | 
			
		||||
  @include cadman("BoldItalic");
 | 
			
		||||
  font-weight: bold;
 | 
			
		||||
  font-style: italic;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
$accent_color: #c1ceb1;
 | 
			
		||||
 | 
			
		||||
$dark_bg: color.scale($accent_color, $lightness: -25%, $saturation: -97%);
 | 
			
		||||
$dark2: color.scale($accent_color, $lightness: -30%, $saturation: -60%);
 | 
			
		||||
$verydark: color.scale($accent_color, $lightness: -80%, $saturation: -70%);
 | 
			
		||||
 | 
			
		||||
$light: color.scale($accent_color, $lightness: 40%, $saturation: -60%);
 | 
			
		||||
$lighter: color.scale($accent_color, $lightness: 60%, $saturation: -60%);
 | 
			
		||||
 | 
			
		||||
$main_bg: color.scale($accent_color, $lightness: -10%, $saturation: -40%);
 | 
			
		||||
$button_color: color.adjust($accent_color, $hue: 90);
 | 
			
		||||
$button_color2: color.adjust($accent_color, $hue: 180);
 | 
			
		||||
$accordion_color: color.adjust($accent_color, $hue: 140, $lightness: -10%, $saturation: -15%);
 | 
			
		||||
 | 
			
		||||
%button-base {
 | 
			
		||||
  cursor: default;
 | 
			
		||||
  color: black;
 | 
			
		||||
  font-size: 0.9em;
 | 
			
		||||
  font-family: "Cadman";
 | 
			
		||||
  text-decoration: none;
 | 
			
		||||
  border: 1px solid black;
 | 
			
		||||
  border-radius: 3px;
 | 
			
		||||
  padding: 5px 20px;
 | 
			
		||||
  margin: 10px 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@mixin button($color) {
 | 
			
		||||
  @extend %button-base;
 | 
			
		||||
  background-color: $color;
 | 
			
		||||
  
 | 
			
		||||
  &:hover {
 | 
			
		||||
    background-color: color.scale($color, $lightness: 20%);
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
  &:active {
 | 
			
		||||
    background-color: color.scale($color, $lightness: -10%, $saturation: -70%);
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
  &:disabled {
 | 
			
		||||
    background-color: color.scale($color, $lightness: 30%, $saturation: -90%);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@mixin navbar($color) {
 | 
			
		||||
  padding: 10px;
 | 
			
		||||
  display: flex;
 | 
			
		||||
  justify-content: end;
 | 
			
		||||
  background-color: $color;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
body {
 | 
			
		||||
  font-family: "Cadman";
 | 
			
		||||
  // font-size: 18px;
 | 
			
		||||
  margin: 20px 100px;
 | 
			
		||||
  background-color: $main_bg;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.big {
 | 
			
		||||
  font-size: 1.8rem;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#topnav {
 | 
			
		||||
  @include navbar($accent_color);
 | 
			
		||||
  justify-content: space-between;
 | 
			
		||||
  align-items: baseline;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#bottomnav {
 | 
			
		||||
  @include navbar($dark_bg);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.darkbg {
 | 
			
		||||
  padding-bottom: 10px;
 | 
			
		||||
  padding-left: 10px;
 | 
			
		||||
  padding-right: 10px;
 | 
			
		||||
  background-color: $dark_bg;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.user-actions {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  column-gap: 15px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.site-title {
 | 
			
		||||
  font-family: "site-title";
 | 
			
		||||
  font-size: 3rem;
 | 
			
		||||
  margin: 0 20px;
 | 
			
		||||
  text-decoration: none;
 | 
			
		||||
  color: black;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.thread-title {
 | 
			
		||||
  margin: 0;
 | 
			
		||||
  font-size: 1.5rem;
 | 
			
		||||
  font-weight: bold;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.post {
 | 
			
		||||
  display: grid;
 | 
			
		||||
  grid-template-columns: 200px 1fr;
 | 
			
		||||
  grid-template-rows: 1fr;
 | 
			
		||||
  gap: 0;
 | 
			
		||||
  grid-auto-flow: row;
 | 
			
		||||
  grid-template-areas:
 | 
			
		||||
    "usercard post-content-container";
 | 
			
		||||
  border: 2px outset $dark2;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.usercard {
 | 
			
		||||
  grid-area: usercard;
 | 
			
		||||
  padding: 20px 10px;
 | 
			
		||||
  border: 4px outset $light;
 | 
			
		||||
  background-color: $dark_bg;
 | 
			
		||||
  border-right: solid 2px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.usercard-inner {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  flex-direction: column;
 | 
			
		||||
  align-items: center;
 | 
			
		||||
  top: 10px;
 | 
			
		||||
  position: sticky;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.post-content-container {
 | 
			
		||||
  display: grid;
 | 
			
		||||
  grid-template-columns: 1fr;
 | 
			
		||||
  grid-template-rows: 70px 2.5fr;
 | 
			
		||||
  gap: 0px 0px;
 | 
			
		||||
  grid-auto-flow: row;
 | 
			
		||||
  grid-template-areas:
 | 
			
		||||
    "post-info"
 | 
			
		||||
    "post-content";
 | 
			
		||||
  grid-area: post-content-container;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.post-info {
 | 
			
		||||
  grid-area: post-info;
 | 
			
		||||
  display: flex;
 | 
			
		||||
  justify-content: space-between;
 | 
			
		||||
  padding: 5px 20px;
 | 
			
		||||
  align-items: center;
 | 
			
		||||
  border-top: 1px solid black;
 | 
			
		||||
  border-bottom: 1px solid black;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.post-content {
 | 
			
		||||
  grid-area: post-content;
 | 
			
		||||
  padding: 20px;
 | 
			
		||||
  margin-right: 25%;
 | 
			
		||||
  display: flex;
 | 
			
		||||
  flex-direction: column;
 | 
			
		||||
  overflow: hidden;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.post-content.wider {
 | 
			
		||||
  margin-right: 12.5%;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.post-inner {
 | 
			
		||||
  height: 100%;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pre code {
 | 
			
		||||
  display: block;
 | 
			
		||||
  background-color: $verydark;
 | 
			
		||||
  font-size: 1rem;
 | 
			
		||||
  color: white;
 | 
			
		||||
  border-bottom-right-radius: 8px;
 | 
			
		||||
  border-bottom-left-radius: 8px;
 | 
			
		||||
  border-left: 10px solid $lighter;
 | 
			
		||||
  padding: 20px;
 | 
			
		||||
  overflow: scroll;
 | 
			
		||||
  tab-size: 4;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.inline-code {
 | 
			
		||||
  background-color: $verydark;
 | 
			
		||||
  color: white;
 | 
			
		||||
  padding: 5px 10px;
 | 
			
		||||
  display: inline-block;
 | 
			
		||||
  margin: 4px;
 | 
			
		||||
  border-radius: 4px;
 | 
			
		||||
  font-size: 1rem;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#delete-dialog, .lightbox-dialog {
 | 
			
		||||
  padding: 0;
 | 
			
		||||
  border-radius: 4px;
 | 
			
		||||
  border: 2px solid black;
 | 
			
		||||
  box-shadow: 0 0 30px rgba(0, 0, 0, 0.25);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.delete-dialog-inner {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  flex-direction: column;
 | 
			
		||||
  align-items: center;
 | 
			
		||||
  padding: 20px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.lightbox-inner {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  flex-direction: column;
 | 
			
		||||
  padding: 20px;
 | 
			
		||||
  min-width: 400px;
 | 
			
		||||
  background-color: $accent_color;
 | 
			
		||||
  gap: 10px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.lightbox-image {
 | 
			
		||||
  max-width: 70vw;
 | 
			
		||||
  max-height: 70vh;
 | 
			
		||||
  object-fit: scale-down;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.lightbox-nav {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  justify-content: space-between;
 | 
			
		||||
  align-items: center;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.copy-code-container {
 | 
			
		||||
  position: sticky;
 | 
			
		||||
  // width: 100%;
 | 
			
		||||
  width: calc(100% - 4px);
 | 
			
		||||
  display: flex;
 | 
			
		||||
  justify-content: space-between;
 | 
			
		||||
  align-items: last baseline;
 | 
			
		||||
  font-family: "Cadman";
 | 
			
		||||
  border-top-right-radius: 8px;
 | 
			
		||||
  border-top-left-radius: 8px;
 | 
			
		||||
  background-color: $accent_color;
 | 
			
		||||
  border-left: 2px solid black;
 | 
			
		||||
  border-right: 2px solid black;
 | 
			
		||||
  border-top: 2px solid black;
 | 
			
		||||
  
 | 
			
		||||
  &::before {
 | 
			
		||||
    content: "code block";
 | 
			
		||||
    font-style: italic;
 | 
			
		||||
    margin-left: 10px;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.copy-code {
 | 
			
		||||
  margin-right: 10px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
blockquote {
 | 
			
		||||
  padding: 10px 20px;
 | 
			
		||||
  margin: 10px;
 | 
			
		||||
  border-radius: 4px;
 | 
			
		||||
  border-left: 10px solid $lighter;
 | 
			
		||||
  background-color: $dark2;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.user-info {
 | 
			
		||||
  display: grid;
 | 
			
		||||
  grid-template-columns: 300px 1fr;
 | 
			
		||||
  grid-template-rows: 1fr;
 | 
			
		||||
  gap: 0;
 | 
			
		||||
  grid-template-areas:
 | 
			
		||||
    "user-page-usercard user-page-stats";
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.user-page-usercard {
 | 
			
		||||
  grid-area: user-page-usercard;
 | 
			
		||||
  padding: 20px 10px;
 | 
			
		||||
  border: 4px outset $light;
 | 
			
		||||
  background-color: $dark_bg;
 | 
			
		||||
  border-right: solid 2px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.user-page-stats {
 | 
			
		||||
  grid-area: user-page-stats;
 | 
			
		||||
  padding: 20px 30px;
 | 
			
		||||
  border: 1px solid black;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.user-stats-list {
 | 
			
		||||
  list-style: none;
 | 
			
		||||
  margin: 0 0 10px 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.user-page-posts {
 | 
			
		||||
  border-left: solid 1px black;
 | 
			
		||||
  border-right: solid 1px black;
 | 
			
		||||
  border-bottom: solid 1px black;
 | 
			
		||||
  background-color: $accent_color;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.user-page-post-preview {
 | 
			
		||||
  max-height: 200px;
 | 
			
		||||
  mask-image: linear-gradient(180deg,#000 60%,transparent);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.avatar {
 | 
			
		||||
  width: 90%;
 | 
			
		||||
  height: 90%;
 | 
			
		||||
  object-fit: contain;
 | 
			
		||||
  margin-bottom: 10px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.username-link {
 | 
			
		||||
  overflow-wrap: anywhere;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.user-status {
 | 
			
		||||
  text-align: center;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
button, input[type="submit"], .linkbutton {
 | 
			
		||||
  display: inline-block;
 | 
			
		||||
  @include button($button_color);
 | 
			
		||||
  
 | 
			
		||||
  &.critical {
 | 
			
		||||
    color: white;
 | 
			
		||||
    @include button(red);
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
  &.warn {
 | 
			
		||||
    @include button(#fbfb8d);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// not sure why this one has to be separate, but if it's included in the rule above everything breaks
 | 
			
		||||
input[type="file"]::file-selector-button {
 | 
			
		||||
  @include button($button_color);
 | 
			
		||||
  margin: 10px 10px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
p {
 | 
			
		||||
  margin: 15px 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.pagebutton {
 | 
			
		||||
  @include button($button_color);
 | 
			
		||||
  padding: 5px 5px;
 | 
			
		||||
  margin: 0;
 | 
			
		||||
  display: inline-block;
 | 
			
		||||
  min-width: 20px;
 | 
			
		||||
  text-align: center;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.currentpage {
 | 
			
		||||
  @extend %button-base;
 | 
			
		||||
  border: none;
 | 
			
		||||
  padding: 5px 5px;
 | 
			
		||||
  margin: 0;
 | 
			
		||||
  display: inline-block;
 | 
			
		||||
  min-width: 20px;
 | 
			
		||||
  text-align: center;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.modform {
 | 
			
		||||
  display: inline;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.login-container > * {
 | 
			
		||||
  width: 25%;
 | 
			
		||||
  margin: auto;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.settings-container > * {
 | 
			
		||||
  width: 40%;
 | 
			
		||||
  margin: auto;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.avatar-form {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  flex-direction: column;
 | 
			
		||||
  align-items: center;
 | 
			
		||||
  padding: 20px 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
input[type="text"], input[type="password"], textarea, select {
 | 
			
		||||
  border: 1px solid black;
 | 
			
		||||
  border-radius: 3px;
 | 
			
		||||
  padding: 7px 10px;
 | 
			
		||||
  width: 100%;
 | 
			
		||||
  box-sizing: border-box;
 | 
			
		||||
  resize: vertical;
 | 
			
		||||
  background-color: color.scale($accent_color, $lightness: 40%);
 | 
			
		||||
  
 | 
			
		||||
  &:focus {
 | 
			
		||||
    background-color: color.scale($accent_color, $lightness: 60%);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.infobox {
 | 
			
		||||
  border: 2px solid black;
 | 
			
		||||
  background-color: #81a3e6;
 | 
			
		||||
  padding: 20px 15px;
 | 
			
		||||
  
 | 
			
		||||
  &.critical {
 | 
			
		||||
    background-color: rgb(237, 129, 129);
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
  &.warn {
 | 
			
		||||
    background-color: #fbfb8d;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.infobox > span {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  align-items: center;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.infobox-icon-container {
 | 
			
		||||
  min-width: 60px;
 | 
			
		||||
  padding-right: 15px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.thread {
 | 
			
		||||
  display: grid;
 | 
			
		||||
  grid-template-columns: 96px 1.6fr 96px;
 | 
			
		||||
  grid-template-rows: 1fr;
 | 
			
		||||
  gap: 0px 0px;
 | 
			
		||||
  grid-auto-flow: row;
 | 
			
		||||
  min-height: 96px;
 | 
			
		||||
  grid-template-areas:
 | 
			
		||||
    "thread-sticky-container thread-info-container thread-locked-container";
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.thread-sticky-container {
 | 
			
		||||
  grid-area: thread-sticky-container;
 | 
			
		||||
  border: 2px outset $light;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.thread-locked-container {
 | 
			
		||||
  grid-area: thread-locked-container;
 | 
			
		||||
  border: 2px outset $light;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.contain-svg {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  align-items: center;
 | 
			
		||||
  justify-content: center;
 | 
			
		||||
  flex-direction: column;
 | 
			
		||||
  &:not(.full) > svg {
 | 
			
		||||
    height: 50%;
 | 
			
		||||
    width: 50%;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.block-img {
 | 
			
		||||
  object-fit: contain;
 | 
			
		||||
  max-width: 400px;
 | 
			
		||||
  max-height: 400px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.thread-info-container {
 | 
			
		||||
  grid-area: thread-info-container;
 | 
			
		||||
  background-color: $accent_color;
 | 
			
		||||
  padding: 5px 20px;
 | 
			
		||||
  border-top: 1px solid black;
 | 
			
		||||
  border-bottom: 1px solid black;
 | 
			
		||||
  display: flex;
 | 
			
		||||
  flex-direction: column;
 | 
			
		||||
  overflow: hidden;
 | 
			
		||||
  max-height: 110px;
 | 
			
		||||
  mask-image: linear-gradient(180deg,#000 60%,transparent);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.thread-info-post-preview {
 | 
			
		||||
  overflow: hidden;
 | 
			
		||||
  text-overflow: ellipsis;
 | 
			
		||||
  display: inline;
 | 
			
		||||
  margin-right: 25%;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.babycode-guide-section {
 | 
			
		||||
  background-color: $accent_color;
 | 
			
		||||
  padding: 5px 20px;
 | 
			
		||||
  border: 1px solid black;
 | 
			
		||||
  padding-right: 25%;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.babycode-guide-container {
 | 
			
		||||
  display: grid;
 | 
			
		||||
  grid-template-columns: 1.5fr 300px;
 | 
			
		||||
  grid-template-rows: 1fr;
 | 
			
		||||
  gap: 0px 0px;
 | 
			
		||||
  grid-auto-flow: row;
 | 
			
		||||
  grid-template-areas:
 | 
			
		||||
    "guide-topics guide-toc";
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.guide-topics {
 | 
			
		||||
  grid-area: guide-topics;
 | 
			
		||||
  overflow: hidden;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.guide-toc {
 | 
			
		||||
  grid-area: guide-toc;
 | 
			
		||||
  position: sticky;
 | 
			
		||||
  top: 100px;
 | 
			
		||||
  align-self: start;
 | 
			
		||||
  padding: 10px;
 | 
			
		||||
  // border-top-right-radius: 16px;
 | 
			
		||||
  border-bottom-right-radius: 8px;
 | 
			
		||||
  background-color: $button_color;
 | 
			
		||||
  border-right: 1px solid black;
 | 
			
		||||
  border-top: 1px solid black;
 | 
			
		||||
  border-bottom: 1px solid black;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.emoji-table tr td {
 | 
			
		||||
  text-align: center;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.emoji-table tr th {
 | 
			
		||||
  padding-left: 50px;
 | 
			
		||||
  padding-right: 50px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.emoji-table {
 | 
			
		||||
  margin: auto;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.emoji-table, th, td {
 | 
			
		||||
  border: 1px solid black;
 | 
			
		||||
  border-collapse: collapse;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.topic {
 | 
			
		||||
  display: grid;
 | 
			
		||||
  grid-template-columns: 1.5fr 64px;
 | 
			
		||||
  grid-template-rows: 1fr;
 | 
			
		||||
  gap: 0px 0px;
 | 
			
		||||
  grid-auto-flow: row;
 | 
			
		||||
  grid-template-areas:
 | 
			
		||||
    "topic-info-container topic-locked-container";
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.topic-info-container {
 | 
			
		||||
  grid-area: topic-info-container;
 | 
			
		||||
  background-color: $accent_color;
 | 
			
		||||
  padding: 5px 20px;
 | 
			
		||||
  border: 1px solid black;
 | 
			
		||||
  display: flex;
 | 
			
		||||
  flex-direction: column;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.topic-locked-container {
 | 
			
		||||
  grid-area: topic-locked-container;
 | 
			
		||||
  border: 2px outset $light;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
.draggable-topic {
 | 
			
		||||
  cursor: pointer;
 | 
			
		||||
  user-select: none;
 | 
			
		||||
  background-color: $accent_color;
 | 
			
		||||
  padding: 20px;
 | 
			
		||||
  margin: 12px 0;
 | 
			
		||||
  border-top: 6px outset $light;
 | 
			
		||||
  border-bottom: 6px outset $dark2;
 | 
			
		||||
  
 | 
			
		||||
  &.dragged {
 | 
			
		||||
    background-color: $button_color;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.editing {
 | 
			
		||||
  background-color: $light;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.context-explain {
 | 
			
		||||
  margin: 20px 0;
 | 
			
		||||
  display: flex;
 | 
			
		||||
  justify-content: space-evenly;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.post-edit-form {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  flex-direction: column;
 | 
			
		||||
  align-items: baseline;
 | 
			
		||||
  height: 100%;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.babycode-editor {
 | 
			
		||||
  height: 150px;
 | 
			
		||||
  font-size: 1rem;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.babycode-editor-container {
 | 
			
		||||
  width: 100%;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.babycode-preview-errors-container {
 | 
			
		||||
  font-size: 0.8rem;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.tab-button {
 | 
			
		||||
  @include button($button_color);
 | 
			
		||||
  border-bottom: none;
 | 
			
		||||
  border-bottom-left-radius: 0;
 | 
			
		||||
  border-bottom-right-radius: 0;
 | 
			
		||||
  margin-bottom: 0;
 | 
			
		||||
  
 | 
			
		||||
  &.active {
 | 
			
		||||
    background-color: $button_color2;
 | 
			
		||||
    padding-top: 8px;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.tab-content {
 | 
			
		||||
  display: none;
 | 
			
		||||
  
 | 
			
		||||
  &.active {
 | 
			
		||||
    min-height: 250px;
 | 
			
		||||
    display: block;
 | 
			
		||||
    background-color: color.adjust($button_color2, $saturation: -20%);
 | 
			
		||||
    border: 1px solid black;
 | 
			
		||||
    padding: 10px;
 | 
			
		||||
    border-top-right-radius: 3px;
 | 
			
		||||
    border-bottom-right-radius: 3px;
 | 
			
		||||
    border-bottom-left-radius: 3px;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ul, ol {
 | 
			
		||||
  margin: 10px 0 10px 30px;
 | 
			
		||||
  padding: 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.new-concept-notification.hidden {
 | 
			
		||||
  display: none;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.new-concept-notification {
 | 
			
		||||
  position: fixed;
 | 
			
		||||
  bottom: 80px;
 | 
			
		||||
  right: 80px;
 | 
			
		||||
  border: 2px solid black;
 | 
			
		||||
  background-color: #81a3e6;
 | 
			
		||||
  padding: 20px 15px;
 | 
			
		||||
  border-radius: 4px;
 | 
			
		||||
  box-shadow: 0 0 30px rgba(0, 0, 0, 0.25);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.emoji {
 | 
			
		||||
  max-width: 15px;
 | 
			
		||||
  max-height: 15px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.accordion {
 | 
			
		||||
  border-top-right-radius: 3px;
 | 
			
		||||
  border-top-left-radius: 3px;
 | 
			
		||||
  box-sizing: border-box;
 | 
			
		||||
  border: 1px solid black;
 | 
			
		||||
  margin: 10px 5px;
 | 
			
		||||
  overflow: hidden;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.accordion.hidden {
 | 
			
		||||
  border-bottom: none;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.accordion-header {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  align-items: center;
 | 
			
		||||
  background-color: $accordion_color;
 | 
			
		||||
  padding: 0 10px;
 | 
			
		||||
  gap: 10px;
 | 
			
		||||
  border-bottom: 1px solid black;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.accordion-toggle {
 | 
			
		||||
  padding: 0;
 | 
			
		||||
  width: 36px;
 | 
			
		||||
  height: 36px;
 | 
			
		||||
  min-width: 36px;
 | 
			
		||||
  min-height: 36px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.accordion-title {
 | 
			
		||||
  margin-right: auto;
 | 
			
		||||
  overflow: hidden;
 | 
			
		||||
  text-overflow: ellipsis;
 | 
			
		||||
  white-space: nowrap;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.accordion-content {
 | 
			
		||||
  padding: 0 15px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.accordion-content.hidden {
 | 
			
		||||
  display: none;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.inbox-container {
 | 
			
		||||
  padding: 10px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.babycode-button-container {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  gap: 10px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.babycode-button {
 | 
			
		||||
  padding: 5px 10px;
 | 
			
		||||
  min-width: 36px;
 | 
			
		||||
  
 | 
			
		||||
  &> * {
 | 
			
		||||
    font-size: 1rem;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user