commit a76f50d3ecae354b06c82ec6aa8ac850353421c7 Author: MeowcaTheoRange Date: Thu Nov 23 02:53:28 2023 -0600 New main site, maybe? diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..6ff4797 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +node_modules/ +package-lock.json +output/ \ No newline at end of file diff --git a/debug.js b/debug.js new file mode 100644 index 0000000..3216270 --- /dev/null +++ b/debug.js @@ -0,0 +1,12 @@ +const express = require("express"); +const app = express(); + +app.use( + express.static("output", { + extensions: ["html"], + index: "index.html", + redirect: true, + }) +); + +app.listen(3000); diff --git a/embeds/loader.html b/embeds/loader.html new file mode 100644 index 0000000..9876d6d --- /dev/null +++ b/embeds/loader.html @@ -0,0 +1,30 @@ +
+
+

Loading...

+

Please wait.

+

If this page does not load, try enabling JavaScript.

+ (This site won't work well without it.) + +
+
diff --git a/embeds/nav.html b/embeds/nav.html new file mode 100644 index 0000000..198f9df --- /dev/null +++ b/embeds/nav.html @@ -0,0 +1,7 @@ +
+

+ Home - Projects - + About - + Site Information +

+
diff --git a/gulpfile.js b/gulpfile.js new file mode 100644 index 0000000..120ec10 --- /dev/null +++ b/gulpfile.js @@ -0,0 +1,25 @@ +const { src, dest } = require("gulp"); +const through2 = require("through2"); +const fs = require("fs"); +const path = require("path"); + +exports.default = () => { + return src("views/**/*") + .pipe( + through2.obj(function (file, _, cb) { + if (file.isBuffer()) { + file.contents = Buffer.from( + file.contents + .toString() + .replace(/<\$ (.*?) \$>/gm, function (m, g1) { + return fs.readFileSync(path.join(__dirname, "embeds", g1), { + encoding: "utf-8", + }); + }) + ); + } + cb(null, file); + }) + ) + .pipe(dest("output/")); +}; diff --git a/package.json b/package.json new file mode 100644 index 0000000..8147253 --- /dev/null +++ b/package.json @@ -0,0 +1,14 @@ +{ + "name": "projects-windowed", + "version": "1.0.0", + "scripts": { + "dev": "nodemon --exec 'gulp;node debug.js' --ext '*' --ignore 'output/*'" + }, + "devDependencies": { + "gulp": "^4.0.2" + }, + "dependencies": { + "express": "^4.18.2", + "through2": "^4.0.2" + } +} diff --git a/views/about/index.html b/views/about/index.html new file mode 100644 index 0000000..f6085b6 --- /dev/null +++ b/views/about/index.html @@ -0,0 +1,41 @@ + + + + + MeowcaTheoRange + + + + + + +
+
+

About

+

More about me.

+
+ <$ nav.html $> +
+
+
+

WIP

+
+
+
+ + + + diff --git a/views/index.html b/views/index.html new file mode 100755 index 0000000..6286a2d --- /dev/null +++ b/views/index.html @@ -0,0 +1,80 @@ + + + + + MeowcaTheoRange + + + + + + +
+
+

ABTMTR.LINK

+
+ <$ nav.html $> +
+
+
+

Welcome! 👋

+

I'm MeowcaTheoRange.

+

+ I'm a web developer, Fediverse enthusiast, and compulsory Minnesotan. +

+

I run this domain and all of the services on it!

+
+
+

What I like doing

+

+ My favourite hobbies are programming, drawing, + occasionally making small bits of music, + obsessing over fonts, and being pedantic. +

+
+
+

What I'd like you to know about me

+
    +
  • Please be patient with me.
  • +
  • + Please be understanding! Ask me for clarification if required. +
  • +
  • + I don't really like small talk - keep if brief if you want to check + up on me, please. +
  • +
  • + I'm not one to pick sides at first, usually. Being an "all or + nothing" kind of person isn't my thing, and if you don't like that, + feel free to tell me why your side is good. +
  • +
  • + I like getting tangled up in drama, but I'm not a spiteful person - + I'm usually only in it for the correlations. +
  • +
  • + You may see me hyperfixate on random stuff, like + certain fonts + or public transit. +
  • +
+
+
+
+ + + + diff --git a/views/projects/hex/index.html b/views/projects/hex/index.html new file mode 100755 index 0000000..2715325 --- /dev/null +++ b/views/projects/hex/index.html @@ -0,0 +1,80 @@ + + + + + HexFlagGen + + + + + + + <$ loader.html $> +
+

HexFlagGen

+

Make a flag out of the hexadecimal bytes of your choice.

+
+
+
+
+
+ +
+
+ +
+ +
+ + +
+
+
+

+ Hex: ... +

+ +
+
+ + + + + diff --git a/views/projects/hex/scripts/index.js b/views/projects/hex/scripts/index.js new file mode 100755 index 0000000..f483e62 --- /dev/null +++ b/views/projects/hex/scripts/index.js @@ -0,0 +1,117 @@ +const canvas = document.getElementById("canvas"); +const data = document.getElementById("data"); +const generateButton = document.getElementById("generateButton"); +const hexdisplay = document.getElementById("hexdisplay"); + +const size_width = document.getElementById("size_width"); +const size_height = document.getElementById("size_height"); +const flag_type = document.getElementById("flag_type"); + +const root = document.querySelector(":root"); + +const ctx = canvas.getContext("2d"); + +function getData() { + data.value = data.value.toUpperCase().replace(/[^0-9A-F]*/g, ""); + + var hexValue = data.value.match(/.{1,2}/g).map((x) => x.padStart(2, "0")); + + hexdisplay.innerHTML = hexValue.join(" "); + + createFlag( + hexValue.join("").match(/.{1,6}/g), + size_width.value, + size_height.value, + flag_type.value + ); + var ac = averageColors(hexValue); + console.log(ac); + root.style.setProperty( + "--background-color", + arrayToColor(darkenColor(ac, 70)) + ); + root.style.setProperty("--color", arrayToColor(lightenColor(ac, 70))); + root.style.setProperty("--accent-color", arrayToColor(ac)); + root.style.setProperty( + "--accent-color-fg", + arrayToColor(lightenColor(ac, 90)) + ); + + propagateStyles(getComputedStyle(root)); +} +generateButton.addEventListener("click", getData); + +function averageColors(hex) { + var averageSet = [[], [], []]; + hex.forEach((number, index) => { + averageSet[index % 3].push(parseInt(number, 16)); + }); + return averageSet.map((array) => + Math.floor(array.reduce((a, b) => a + b) / array.length) + ); +} + +function createFlag(hex, w, h, type) { + canvas.width = w; + canvas.height = h; + + // Initialize stuff + + var width = ctx.canvas.width; + var height = ctx.canvas.height; + var textHeight = 24; + ctx.font = `${textHeight}px "Lexend Deca"`; + + ctx.clearRect(0, 0, width, height); + + console.log(hex); + + var hexColors = []; + var excessHex = ""; + + hex.forEach((compound) => { + if (compound.length < 6) excessHex = compound; + else hexColors.push(compound); + }); + + var rectWidth = width / hexColors.length; + var rectHeight = height / hexColors.length; + for (color in hexColors) { + ctx.fillStyle = "#" + hexColors[color]; + if (type === "horiz") ctx.fillRect(rectWidth * color, 0, rectWidth, height); + else if (type === "vert") + ctx.fillRect(0, rectHeight * color, width, rectHeight); + } + if (excessHex.length > 0) { + var text = "+ " + excessHex.match(/.{1,2}/g).join(" "); + var textWidth = ctx.measureText(text).width; + ctx.strokeStyle = "black"; + ctx.lineWidth = 4; + ctx.fillStyle = "white"; + ctx.strokeText(text, width - (textWidth + 8), height - textHeight / 2); + ctx.fillText(text, width - (textWidth + 8), height - textHeight / 2); + } +} + +const clamp = (n, mi, ma) => Math.max(mi, Math.min(n, ma)); + +function lightenColor(color, mult) { + return [ + clamp(color[0] + (mult / 100) * (255 - color[0]), 0, 255), + clamp(color[1] + (mult / 100) * (255 - color[1]), 0, 255), + clamp(color[2] + (mult / 100) * (255 - color[2]), 0, 255), + ]; +} +function darkenColor(color, mult) { + return [ + clamp(color[0] - (mult / 100) * color[0], 0, 255), + clamp(color[1] - (mult / 100) * color[1], 0, 255), + clamp(color[2] - (mult / 100) * color[2], 0, 255), + ]; +} + +function arrayToColor(color) { + return ( + "#" + color.map((x) => Math.floor(x).toString(16).padStart(2, "0")).join("") + ); +} diff --git a/views/projects/index.html b/views/projects/index.html new file mode 100755 index 0000000..8d804ab --- /dev/null +++ b/views/projects/index.html @@ -0,0 +1,51 @@ + + + + + Project Windows + + + + + + + + <$ loader.html $> +
+

Projects

+

Various projects I've made.

+
+ <$ nav.html $> +
+ + +
+
+
+ + + + diff --git a/views/projects/woz/index.html b/views/projects/woz/index.html new file mode 100755 index 0000000..66dbe26 --- /dev/null +++ b/views/projects/woz/index.html @@ -0,0 +1,82 @@ + + + + + WozSteamGem + + + + + + + <$ loader.html $> +
+

WozSteamGem

+

Make a Scott The Woz thumbnail out of any Steam game.

+
+
+
+ +
+ +
+
+
+ + + +
+ + +
+
+
+ +
+
+ + + + + diff --git a/views/projects/woz/public/woz0.png b/views/projects/woz/public/woz0.png new file mode 100755 index 0000000..124690b Binary files /dev/null and b/views/projects/woz/public/woz0.png differ diff --git a/views/projects/woz/public/woz1.png b/views/projects/woz/public/woz1.png new file mode 100755 index 0000000..b7e2849 Binary files /dev/null and b/views/projects/woz/public/woz1.png differ diff --git a/views/projects/woz/public/woz2.png b/views/projects/woz/public/woz2.png new file mode 100755 index 0000000..5dde1b0 Binary files /dev/null and b/views/projects/woz/public/woz2.png differ diff --git a/views/projects/woz/public/woz3.png b/views/projects/woz/public/woz3.png new file mode 100755 index 0000000..1fb567e Binary files /dev/null and b/views/projects/woz/public/woz3.png differ diff --git a/views/projects/woz/public/woz4.png b/views/projects/woz/public/woz4.png new file mode 100755 index 0000000..0911dbe Binary files /dev/null and b/views/projects/woz/public/woz4.png differ diff --git a/views/projects/woz/public/woz5.png b/views/projects/woz/public/woz5.png new file mode 100755 index 0000000..f2ebe73 Binary files /dev/null and b/views/projects/woz/public/woz5.png differ diff --git a/views/projects/woz/public/woz6.png b/views/projects/woz/public/woz6.png new file mode 100755 index 0000000..b2dbd7b Binary files /dev/null and b/views/projects/woz/public/woz6.png differ diff --git a/views/projects/woz/public/woz7.png b/views/projects/woz/public/woz7.png new file mode 100755 index 0000000..7e29f70 Binary files /dev/null and b/views/projects/woz/public/woz7.png differ diff --git a/views/projects/woz/public/woz8.png b/views/projects/woz/public/woz8.png new file mode 100755 index 0000000..6b311bf Binary files /dev/null and b/views/projects/woz/public/woz8.png differ diff --git a/views/projects/woz/public/woz9.png b/views/projects/woz/public/woz9.png new file mode 100755 index 0000000..a8a253b Binary files /dev/null and b/views/projects/woz/public/woz9.png differ diff --git a/views/projects/woz/public/wozstash.png b/views/projects/woz/public/wozstash.png new file mode 100755 index 0000000..4d91e4f Binary files /dev/null and b/views/projects/woz/public/wozstash.png differ diff --git a/views/projects/woz/scripts/index.js b/views/projects/woz/scripts/index.js new file mode 100755 index 0000000..48a4b1a --- /dev/null +++ b/views/projects/woz/scripts/index.js @@ -0,0 +1,81 @@ +const canvas = document.getElementById("canvas"); +const data = document.getElementById("data"); +const generateButton = document.getElementById("generateButton"); +const hexdisplay = document.getElementById("hexdisplay"); + +const steam_game = document.getElementById("steam_game"); +const scott_index = document.getElementById("scott_index"); +const stash = document.getElementById("stash"); +const align = document.getElementById("align"); + +const root = document.querySelector(":root"); + +const ctx = canvas.getContext("2d"); + +async function loadImage(url) { + return new Promise((r) => { + let img = new Image(); + img.onload = () => r(img); + img.src = url; + }); +} + +async function getScott() { + var gameID = steam_game.value; + var scottID = scott_index.value; + var alignment = align.value; + + const ctx = canvas.getContext("2d"); + + var hero = await loadImage( + `https://cdn.cloudflare.steamstatic.com/steam/apps/${gameID}/library_hero.jpg` + ).catch(() => "404"); + var scott = await loadImage( + stash.checked ? `public/wozstash.png` : `public/woz${scottID}.png` + ).catch(() => "404"); + var logo = await loadImage( + `https://cdn.cloudflare.steamstatic.com/steam/apps/${gameID}/logo.png` + ).catch(() => "404"); + + if (scott === "404") { + console.log("Scott error: " + scottID); + return `Scott ID ${scottID} does not exist.`; + } + if (hero === "404" || logo === "404") { + console.log("404 error: " + gameID); + return `Steam ID ${gameID} does not have logo, hero image, or does not exist.`; + } + var xalign; + switch (alignment) { + case "left": + xalign = 0; + break; + case "right": + xalign = -950; + break; + default: + xalign = -505; + break; + } + console.log("Generating: " + gameID); + ctx.drawImage(hero, xalign, 0, 2229, 720); + ctx.drawImage(scott, 0, 0, 1280, 720); + + const newHeight = 800 / (logo.width / logo.height); + ctx.fillStyle = "#000"; + ctx.shadowColor = "#000"; + ctx.shadowBlur = 16; + + if (stash.checked) + ctx.drawImage( + logo, + 400, + Math.min(560 - newHeight / 2, 669 - newHeight), + 800, + newHeight + ); + else + ctx.drawImage(logo, 64, Math.max(240 - newHeight / 2, 32), 800, newHeight); +} + +generateButton.addEventListener("click", getScott); diff --git a/views/scripts/accessibility.js b/views/scripts/accessibility.js new file mode 100755 index 0000000..93f27ef --- /dev/null +++ b/views/scripts/accessibility.js @@ -0,0 +1,68 @@ +var accScale; +var accBase; + +function createAccessibilityNodes() { + document.querySelector("#accessibility").innerHTML = `
+ Accessibility controls +
+ +
`; + + accScale = document.getElementById("acc-scale"); + accBase = document.getElementById("acc-base"); + + accScale.addEventListener("change", function (e) { + window.localStorage.setItem("acc-scale", e.target.value); + changeScale(e.target.value); + }); + + accBase.addEventListener("change", function (e) { + window.localStorage.setItem("acc-base", e.target.checked); + window.location.reload(); + }); +} + +window.addEventListener("load", (e) => initializeChanges(e, true)); + +// on localStorage change +window.addEventListener("storage", initializeChanges); + +let prevBase; // previous base, for reload check + +function initializeChanges(_, loading) { + if (window.frameElement == null) createAccessibilityNodes(); + + const scale = window.localStorage.getItem("acc-scale"); + const base = window.localStorage.getItem("acc-base"); + changeScale(scale); + + if (loading) { + prevBase = base; + changeBase(base === "true"); + } else if (base != prevBase) window.location.reload(); + + if (scale != null && accScale != null) accScale.value = scale; + if (base != null && accBase != null) accBase.checked = base === "true"; +} + +function changeScale(scale) { + document.documentElement.style.setProperty("--base-scale", scale + "px"); +} + +function changeBase(base) { + if (base) document.documentElement.classList.add("base"); + else document.documentElement.classList.remove("base"); +} diff --git a/views/scripts/interface.js b/views/scripts/interface.js new file mode 100755 index 0000000..c68dcf8 --- /dev/null +++ b/views/scripts/interface.js @@ -0,0 +1,22 @@ +function propagateStyles(rootStyles) { + if (window.frameElement == null) return; + const wfParent = window.frameElement.parentElement; + wfParent.style.setProperty( + "--background-color", + rootStyles.getPropertyValue("--background-color") + ); + wfParent.style.setProperty("--color", rootStyles.getPropertyValue("--color")); + wfParent.style.setProperty( + "--accent-color", + rootStyles.getPropertyValue("--accent-color") + ); + wfParent.style.setProperty( + "--accent-color-fg", + rootStyles.getPropertyValue("--accent-color-fg") + ); + wfParent.style.setProperty("--border-style", "0.0625em solid var(--color)"); +} + +window.addEventListener("load", () => { + propagateStyles(getComputedStyle(document.documentElement)); +}); diff --git a/views/scripts/windows.js b/views/scripts/windows.js new file mode 100755 index 0000000..e3773ef --- /dev/null +++ b/views/scripts/windows.js @@ -0,0 +1,223 @@ +class WindowObject { + windowObject; + + windowManager; + windowManagerLabel; + windowContent; + + #orig_mousePosX; + #orig_mousePosY; + #orig_selfPosX; + #orig_selfPosY; + #isDragging; + + constructor(parent, content) { + this.parentElement = parent; + this.windowObject = WindowObject.createWindow(this, content); + this.parentElement.appendChild(this.windowObject); + + WindowObject.raiseWindow(this.windowObject); + + this.windowManager = this.windowObject.querySelector(".window-manager"); + this.windowManagerLabel = this.windowObject.querySelector( + ".window-manager-label" + ); + this.windowContent = this.windowObject.querySelector(".window-content"); + + this.windowManager.addEventListener("mousedown", (e) => + this.event__dragMouseDown(e) + ); + this.windowManager.addEventListener("mousemove", (e) => + this.event__dragMouseMove(e) + ); + this.windowManager.addEventListener("mouseup", (e) => + this.event__dragMouseUp(e) + ); + this.windowManager.addEventListener("mouseout", (e) => + this.event__dragMouseMove(e) + ); + + this.windowObject.addEventListener("mousedown", (e) => + WindowObject.raiseWindow(this.windowObject) + ); + + this.windowContent.addEventListener("load", () => { + this.title = this.windowContent.contentWindow.document.title; + this.windowManager + .querySelector(".window-new-button") + .addEventListener("click", () => { + window.open(this.content); + }); + }); + } + + get title() { + return this.windowManagerLabel.textContent; + } + + get content() { + return this.windowContent.src; + } + + set title(content) { + this.windowManagerLabel.textContent = content; + } + + set content(src) { + this.windowContent.src = src; + } + + minimizeWindow() { + if (this.windowObject.classList.contains("minimized")) { + this.windowObject.classList.remove("minimized"); + + WindowObject.raiseWindow(this.windowObject); + } else { + this.windowObject.classList.add("minimized"); + this.windowObject.style.zIndex = 50; + } + } + + maximizeWindow() { + this.windowObject.classList.toggle("maximized"); + + WindowObject.raiseWindow(this.windowObject); + } + + destroy() { + this.windowObject.classList.add("closed"); + setTimeout(() => { + this.windowObject.remove(); + var someWindow = this.parentElement.querySelector( + `.window-object:last-child` + ); + if (someWindow != null) WindowObject.raiseWindow(someWindow); + }, 250); + } + + event__dragMouseDown(e) { + e.preventDefault(); + + this.#orig_mousePosX = e.clientX; + this.#orig_mousePosY = e.clientY; + this.#orig_selfPosX = this.windowObject.offsetLeft; + this.#orig_selfPosY = this.windowObject.offsetTop; + this.windowContent.style.userSelect = "none"; + this.windowContent.style.pointerEvents = "none"; + this.windowManager.style.cursor = "move"; + this.#isDragging = true; + if (this.windowObject.style.zIndex != 100) + WindowObject.raiseWindow(this.windowObject); + } + + event__dragMouseUp(e) { + e.preventDefault(); + + this.#orig_mousePosX = 0; + this.#orig_mousePosY = 0; + this.windowContent.style.userSelect = "auto"; + this.windowContent.style.pointerEvents = "auto"; + this.windowManager.style.cursor = "default"; + this.#isDragging = false; + } + + event__dragMouseMove(e) { + e.preventDefault(); + + if (this.#isDragging) { + this.windowObject.style.left = + this.#orig_selfPosX - (this.#orig_mousePosX - e.clientX) + "px"; + this.windowObject.style.top = + this.#orig_selfPosY - (this.#orig_mousePosY - e.clientY) + "px"; + } + } + + static raiseWindow(windowObj) { + windowObj.parentElement.querySelectorAll(".window-object").forEach((x) => { + if (x.style.zIndex > 50) x.style.zIndex -= 1; + x.classList.add("unfocused"); + }); + windowObj.style.zIndex = 100; + windowObj.classList.remove("unfocused"); + windowObj.focus(); + } + + static createWindow(windowRef, content) { + const windowObject = document.createElement("div"); + windowObject.classList.add("window-object"); + + { + const windowManager = document.createElement("div"); + windowManager.classList.add("window-manager"); + + { + const windowManagerStart = document.createElement("div"); + windowManagerStart.classList.add("window-manager-start"); + + { + const windowManagerLabel = document.createElement("span"); + windowManagerLabel.textContent = ""; + windowManagerLabel.classList.add("window-manager-label"); + + windowManagerStart.appendChild(windowManagerLabel); + } + + windowManager.appendChild(windowManagerStart); + } + + { + const windowManagerEnd = document.createElement("div"); + windowManagerEnd.classList.add("window-manager-end"); + + { + const windowNewButton = document.createElement("button"); + windowNewButton.innerHTML = "open_in_new"; + windowNewButton.classList.add("window-new-button"); + + windowManagerEnd.appendChild(windowNewButton); + } + + { + const windowMaximizeButton = document.createElement("button"); + windowMaximizeButton.innerHTML = "maximize"; + windowMaximizeButton.classList.add("window-maximize-button"); + windowMaximizeButton.ariaHidden = true; // esoteric operation to screen-reader users + windowMaximizeButton.addEventListener("click", () => + windowRef.maximizeWindow() + ); + + windowManagerEnd.appendChild(windowMaximizeButton); + } + + { + const windowDestroyButton = document.createElement("button"); + windowDestroyButton.innerHTML = "close"; + windowDestroyButton.classList.add("window-destroy-button"); + windowDestroyButton.ariaHidden = true; + windowDestroyButton.addEventListener("click", () => + windowRef.destroy() + ); + + windowManagerEnd.appendChild(windowDestroyButton); + } + + windowManager.appendChild(windowManagerEnd); + } + + windowObject.appendChild(windowManager); + } + + { + const windowContent = document.createElement("iframe"); + windowContent.classList.add("window-content"); + + { + windowContent.src = content; + } + + windowObject.appendChild(windowContent); + } + + return windowObject; + } +} diff --git a/views/site/index.html b/views/site/index.html new file mode 100644 index 0000000..3a2673c --- /dev/null +++ b/views/site/index.html @@ -0,0 +1,64 @@ + + + + + MeowcaTheoRange + + + + + + +
+
+

Site Information

+
+ <$ nav.html $> +
+
+
+

What happened to the previous site?

+

+ The previous site kinda sucked. It depended on client-side React for + the most basic of things, and was just overall kind of a mess of TSX + everywhere. +

+

+ This site is represented semi-statically, which means there's nothing + new being generated on the backend.
+ This site does not use React either, so everything the frontend runs + is vanilla JavaScript. +

+

+ What's with the accessibility controls on every page of the + site? +

+

+ Just because. If you want to make the text bigger or get rid of the + colors, you have that panel. +

+

What font are you using for this site?

+

+ Lexend Deca, or your system's default sans-serif font, + depending on if you're using Base style. +

+
+
+
+ + + + diff --git a/views/styles/normal.css b/views/styles/normal.css new file mode 100755 index 0000000..83c2afe --- /dev/null +++ b/views/styles/normal.css @@ -0,0 +1,260 @@ +@import url("https://necolas.github.io/normalize.css/8.0.1/normalize.css"); + +/* Document form */ + +:root { + --base-scale: 16px; + + --background-color: hsl(0, 0%, 15%); + --color: hsl(0, 0%, 85%); + --accent-color: #808080; + --accent-color-fg: hsl(0, 0%, 95%); + --font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, + Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", + "Segoe UI Symbol"; + --document-width: 40em; + + --border-style: 0.0625em solid var(--color); +} + +body { + width: 100vw; + max-width: var(--document-width); + margin: auto; + padding-inline: 0.5em; + padding-block: 0.5em; +} + +html.base { + --background-color: #fff !important; + --color: #000 !important; + --accent-color: #000 !important; + --accent-color-fg: #fff !important; + --font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, + Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", + "Segoe UI Symbol" !important; + --document-width: 40em; + + --border-style: 0.0625em solid var(--color); +} + +html.base body { + margin: 0; +} + +/* Size and type normalize */ + +html { + font-size: var(--base-scale); + background-color: var(--background-color); + color: var(--color); +} + +main { + margin-block: 1em; +} + +h1 { + font-size: 2em; + line-height: 1.5em; + margin: 0; + margin-block: 0.125em; +} + +h2 { + font-size: 1.5em; + line-height: 1.25em; + margin: 0; + margin-block: 0.25em; +} + +h3 { + font-size: 1.1em; + line-height: 1.25em; + margin: 0; + margin-block: 0.25em; +} + +p { + font-size: 1em; + line-height: 1.25em; + margin-inline: 0; + margin-block: 0.5em; +} + +ul, +ol { + padding: 0; + padding-inline-start: 1em; + margin: 0; + margin-block: 0.5em; +} + +li { + margin-inline: 0; + margin-block: 0.5em; +} + +small { + font-size: 0.75em; +} + +big { + font-size: 1.5em; +} + +code { + font-size: 1em; + line-height: 1.25em; + font-family: monospace; +} + +hr { + border: none; + border-top: var(--border-style); + background-color: transparent; + margin-inline: 0; + margin-block: 0.25em; +} + +/* Form normalize */ + +html { + font-family: var(--font-family); +} + +* { + box-sizing: border-box; +} + +*:focus { + outline: 2px solid var(--accent-color-fg); +} + +fieldset { + border: var(--border-style); + padding-inline: 0.5em; + padding-block: 0.25em; + margin-inline: 0; + margin-block: 0.5em; + font-size: 1em; + background-color: var(--background-color); + color: var(--color); +} + +/* Interactive normalize */ + +a { + color: var(--accent-color); +} + +a:hover, +a:focus { + opacity: 0.8; +} + +a:active { + opacity: 0.5; +} + +input, +select, +textarea { + font-family: inherit; + border: var(--border-style); + padding-inline: 0.5em; + padding-block: 0.25em; + margin-inline: 0; + margin-block: 0.25em; + font-size: 1em; + background-color: var(--background-color); + color: var(--color); +} + +input:disabled { + opacity: 0.5; +} + +button, +input[type="button"], +input[type="submit"], +input[type="reset"] { + border: var(--border-style); + padding-inline: 0.5em; + padding-block: 0.25em; + margin-inline: 0; + margin-block: 0.25em; + font-size: 1em; + font-family: inherit; + background-color: var(--accent-color); + color: var(--accent-color-fg); +} + +button[data-outlined], +input[type="button"][data-outlined], +input[type="submit"][data-outlined], +input[type="reset"][data-outlined] { + border: var(--border-style); + background-color: var(--background-color); + color: var(--accent-color); +} + +button:hover, +input[type="button"]:hover, +input[type="submit"]:hover, +input[type="reset"]:hover, +button:focus, +input[type="button"]:focus, +input[type="submit"]:focus, +input[type="reset"]:focus { + opacity: 0.8; +} +button:active, +input[type="button"]:active, +input[type="submit"]:active, +input[type="reset"]:active { + opacity: 0.5; +} + +/* -- Checkbox styling */ + +label.checkbox { + display: inline-block; + position: relative; + margin-inline: 0; + margin-block: 0.25em; +} + +label.checkbox input[type="checkbox"] { + /* visibility: hidden; */ + opacity: 0; + width: 0; + height: 0; + position: absolute; + top: 0; + left: 0; +} + +label.checkbox input[type="checkbox"] + span.checkbox { + display: inline-block; + width: 1em; + height: 1em; + line-height: 1em; + padding-inline: 0.25em; + padding-block: 0.25em; + box-sizing: content-box; + border: var(--border-style); + color: transparent; + text-align: center; + user-select: none; +} + +label.checkbox input[type="checkbox"]:focus + span.checkbox { + outline: 2px solid var(--accent-color-fg); +} + +label.checkbox input[type="checkbox"]:checked + span.checkbox { + background-color: var(--accent-color); + border: var(--border-style); + color: var(--accent-color-fg); +} diff --git a/views/styles/style.css b/views/styles/style.css new file mode 100644 index 0000000..fdb5649 --- /dev/null +++ b/views/styles/style.css @@ -0,0 +1,11 @@ +#accessibility { + position: sticky; + bottom: 1em; + left: 1em; + background-color: var(--background-color); + padding: 0.5em; +} + +#accessibility fieldset { + margin-block: 0; +} diff --git a/views/styles/windows.css b/views/styles/windows.css new file mode 100755 index 0000000..f77a14f --- /dev/null +++ b/views/styles/windows.css @@ -0,0 +1,147 @@ +@import url("https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@24,400,0,0"); + +@keyframes appear { + from { + scale: 0; + opacity: 0; + } + to { + scale: 1; + opacity: 1; + } +} + +div.window-object { + display: grid; + grid-template-rows: max-content auto; + grid-gap: 0.25em; + position: fixed; + top: calc(50vh - 150px); + left: calc(50vw - 200px); + width: 400px; + height: 300px; + + min-width: 10em; + min-height: 2em; + background-color: var(--accent-color); + color: var(--accent-color-fg); + border: var(--border-style); + resize: both; + overflow: hidden; + padding: 0.25em; + /* padding: 0.5em; */ + transition: opacity 0.25s, scale 0.25s; + + scale: 1; + opacity: 1; + animation-name: appear; + animation-duration: 0.25s; +} + +div.window-object.unfocused { + opacity: 0.5; +} + +div.window-object.closed { + scale: 0; + opacity: 0; +} + +div.window-object.minimized { + top: auto !important; + bottom: 0; + left: 0 !important; + max-width: 20em !important; + width: 20em !important; + min-width: 20em !important; + max-height: 2.5em !important; + height: 2.5em !important; + min-height: 2.5em !important; + resize: none; +} + +div.window-object.minimized > div.window-manager { + cursor: default !important; +} + +div.window-object.minimized > iframe.window-content { + display: none; +} + +div.window-object.maximized { + top: 0 !important; + left: 0 !important; + max-width: 100vw !important; + width: 100vw !important; + min-width: 100vw !important; + max-height: 100vh !important; + height: 100vh !important; + min-height: 100vh !important; + resize: none; +} + +div.window-object.maximized > div.window-manager { + cursor: default !important; +} + +div.window-object > div.window-manager { + display: grid; + width: 100%; + grid-template-columns: auto max-content; + vertical-align: middle; + height: 1.5em; + overflow: hidden; + user-select: none; +} + +div.window-object > div.window-manager > div { + overflow: hidden; + width: 100%; + vertical-align: middle; + height: 100%; + box-sizing: content-box; +} + +div.window-object > div.window-manager > div.window-manager-start { + text-align: start; +} + +div.window-object + > div.window-manager + > div.window-manager-start + > span.window-manager-label { + display: inline-block; + height: 100%; + width: 100%; + line-height: 1.5em; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; +} + +div.window-object > div.window-manager > div.window-manager-end { + text-align: end; +} + +div.window-object > div.window-manager > div > button { + height: 1.5em; + width: 1.5em; + padding: 0; + margin: 0; + margin-inline-start: 0.25em; + box-sizing: border-box; + border: var(--border-style); + background-color: var(--accent-color); + color: var(--accent-color-fg); + font-family: "Material Symbols Outlined"; + text-align: center; + vertical-align: middle; + font-size: 1em; + line-height: 0.5em; +} + +div.window-object > iframe.window-content { + height: 100%; + width: 100%; + border: none; +}