commit 17db0285a0cca542fe7baf45937c8ba8e73b8b8d Author: Igor Támara Date: Sat Nov 9 00:48:42 2024 -0500 Initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..7c046b6 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +.zig-cache +zig-out \ No newline at end of file diff --git a/assets/css/index.css b/assets/css/index.css new file mode 100644 index 0000000..abddf45 --- /dev/null +++ b/assets/css/index.css @@ -0,0 +1,457 @@ +@import url('https://fonts.cdnfonts.com/css/jetbrains-mono-2'); + +:root { + --font-family: "JetBrains Mono", monospace; + --line-height: 1.20rem; + --border-thickness: 2px; + --text-color: #000; + --text-color-alt: #666; + --background-color: #fff; + --background-color-alt: #eee; + + --font-weight-normal: 500; + --font-weight-medium: 600; + --font-weight-bold: 800; + + font-family: var(--font-family); + font-optical-sizing: auto; + font-weight: var(--font-weight-normal); + font-style: normal; + font-variant-numeric: tabular-nums lining-nums; + font-size: 16px; +} + +@media (prefers-color-scheme: dark) { + :root { + --text-color: #fff; + --text-color-alt: #aaa; + --background-color: #000; + --background-color-alt: #111; + } +} + +* { + box-sizing: border-box; +} + + +* + * { + margin-top: var(--line-height); +} + +html { + display: flex; + width: 100%; + margin: 0; + padding: 0; + flex-direction: column; + align-items: center; + background: var(--background-color); + color: var(--text-color); +} + +body { + position: relative; + width: 100%; + margin: 0; + padding: var(--line-height) 2ch; + max-width: calc(min(80ch, round(down, 100%, 1ch))); + line-height: var(--line-height); + overflow-x: hidden; +} + +@media screen and (max-width: 480px) { + :root { + font-size: 14px; + } + body { + padding: var(--line-height) 1ch; + } +} + +h1, h2, h3, h4, h5, h6 { + font-weight: var(--font-weight-bold); + margin: calc(var(--line-height) * 2) 0 var(--line-height); + line-height: var(--line-height); +} + +h1 { + font-size: 2rem; + line-height: calc(2 * var(--line-height)); + margin-bottom: calc(var(--line-height) * 2); + text-transform: uppercase; +} +h2 { + font-size: 1rem; + text-transform: uppercase; +} + +hr { + position: relative; + display: block; + height: var(--line-height); + margin: calc(var(--line-height) * 1.5) 0; + border: none; + color: var(--text-color); +} +hr:after { + display: block; + content: ""; + position: absolute; + top: calc(var(--line-height) / 2 - var(--border-thickness)); + left: 0; + width: 100%; + border-top: calc(var(--border-thickness) * 3) double var(--text-color); + height: 0; +} + +a { + text-decoration-thickness: var(--border-thickness); +} + +a:link, a:visited { + color: var(--text-color); +} + +p { + margin-bottom: var(--line-height); +} + +strong { + font-weight: var(--font-weight-bold); +} +em { + font-style: italic; +} + +sub { + position: relative; + display: inline-block; + margin: 0; + vertical-align: sub; + line-height: 0; + width: calc(1ch / 0.75); + font-size: .75rem; +} + +table { + position: relative; + top: calc(var(--line-height) / 2); + width: calc(round(down, 100%, 1ch)); + border-collapse: collapse; + margin: 0 0 calc(var(--line-height) * 2); +} + +th, td { + border: var(--border-thickness) solid var(--text-color); + padding: + calc((var(--line-height) / 2)) + calc(1ch - var(--border-thickness) / 2) + calc((var(--line-height) / 2) - (var(--border-thickness))) + ; + line-height: var(--line-height); + vertical-align: top; + text-align: left; +} +table tbody tr:first-child > * { + padding-top: calc((var(--line-height) / 2) - var(--border-thickness)); +} + + +th { + font-weight: 700; +} +.width-min { + width: 0%; +} +.width-auto { + width: 100%; +} + +.header { + margin-bottom: calc(var(--line-height) * 2); +} +.header h1 { + margin: 0; +} +.header tr td:last-child { + text-align: right; +} + +p { + word-break: break-word; + word-wrap: break-word; + hyphens: auto; +} + +img, video { + display: block; + width: 100%; + object-fit: contain; + overflow: hidden; +} +img { + font-style: italic; + color: var(--text-color-alt); +} + +details { + border: var(--border-thickness) solid var(--text-color); + padding: calc(var(--line-height) - var(--border-thickness)) 1ch; + margin-bottom: var(--line-height); +} + +summary { + font-weight: var(--font-weight-medium); + cursor: pointer; +} +details[open] summary { + margin-bottom: var(--line-height); +} + +details ::marker { + display: inline-block; + content: '▶'; + margin: 0; +} +details[open] ::marker { + content: '▼'; +} + +details :last-child { + margin-bottom: 0; +} + +pre { + white-space: pre; + overflow-x: auto; + margin: var(--line-height) 0; + overflow-y: hidden; +} +figure pre { + margin: 0; +} + +pre, code { + font-family: var(--font-family); +} + +code { + font-weight: var(--font-weight-medium); +} + +figure { + margin: calc(var(--line-height) * 2) 3ch; + overflow-x: auto; + overflow-y: hidden; +} + +figcaption { + display: block; + font-style: italic; + margin-top: var(--line-height); +} + +ul, ol { + padding: 0; + margin: 0 0 var(--line-height); +} + +ul { + list-style-type: square; + padding: 0 0 0 2ch; +} +ol { + list-style-type: none; + counter-reset: item; + padding: 0; +} +ol ul, +ol ol, +ul ol, +ul ul { + padding: 0 0 0 3ch; + margin: 0; +} +ol li:before { + content: counters(item, ".") ". "; + counter-increment: item; + font-weight: var(--font-weight-medium); +} + +li { + margin: 0; + padding: 0; +} + +li::marker { + line-height: 0; +} + +::-webkit-scrollbar { + height: var(--line-height); +} + +input, button, textarea { + border: var(--border-thickness) solid var(--text-color); + padding: + calc(var(--line-height) / 2 - var(--border-thickness)) + calc(1ch - var(--border-thickness)); + margin: 0; + font: inherit; + font-weight: inherit; + height: calc(var(--line-height) * 2); + width: auto; + overflow: visible; + background: var(--background-color); + color: var(--text-color); + line-height: normal; + -webkit-font-smoothing: inherit; + -moz-osx-font-smoothing: inherit; + -webkit-appearance: none; +} + +input[type=checkbox] { + display: inline-grid; + place-content: center; + vertical-align: top; + width: 2ch; + height: var(--line-height); + cursor: pointer; +} +input[type=checkbox]:checked:before { + content: ""; + width: 1ch; + height: calc(var(--line-height) / 2); + background: var(--text-color); +} + +button:focus, input:focus { + --border-thickness: 3px; + outline: none; +} + +input { + width: calc(round(down, 100%, 1ch)); +} +::placeholder { + color: var(--text-color-alt); + opacity: 1; +} +::-ms-input-placeholder { + color: var(--text-color-alt); +} +button::-moz-focus-inner { + padding: 0; + border: 0 +} + +button { + text-transform: uppercase; + font-weight: var(--font-weight-medium); + cursor: pointer; +} + +button:hover { + background: var(--background-color-alt); +} +button:active { + transform: translate(2px, 2px); +} + +label { + display: block; + width: calc(round(down, 100%, 1ch)); + height: auto; + line-height: var(--line-height); + font-weight: var(--font-weight-medium); + margin: 0; +} + +label input { + width: 100%; +} + +.tree, .tree ul { + position: relative; + padding-left: 0; + list-style-type: none; + line-height: var(--line-height); +} +.tree ul { + margin: 0; +} +.tree ul li { + position: relative; + padding-left: 1.5ch; + margin-left: 1.5ch; + border-left: var(--border-thickness) solid var(--text-color); +} +.tree ul li:before { + position: absolute; + display: block; + top: calc(var(--line-height) / 2); + left: 0; + content: ""; + width: 1ch; + border-bottom: var(--border-thickness) solid var(--text-color); +} +.tree ul li:last-child { + border-left: none; +} +.tree ul li:last-child:after { + position: absolute; + display: block; + top: 0; + left: 0; + content: ""; + height: calc(var(--line-height) / 2); + border-left: var(--border-thickness) solid var(--text-color); +} + +.grid { + --grid-cells: 0; + display: flex; + gap: 1ch; + width: calc(round(down, 100%, (1ch * var(--grid-cells)) - (1ch * var(--grid-cells) - 1))); + margin-bottom: var(--line-height); +} + +.grid > *, +.grid > input { + flex: 0 0 calc(round(down, (100% - (1ch * (var(--grid-cells) - 1))) / var(--grid-cells), 1ch)); +} +.grid:has(> :last-child:nth-child(1)) { --grid-cells: 1; } +.grid:has(> :last-child:nth-child(2)) { --grid-cells: 2; } +.grid:has(> :last-child:nth-child(3)) { --grid-cells: 3; } +.grid:has(> :last-child:nth-child(4)) { --grid-cells: 4; } +.grid:has(> :last-child:nth-child(5)) { --grid-cells: 5; } +.grid:has(> :last-child:nth-child(6)) { --grid-cells: 6; } +.grid:has(> :last-child:nth-child(7)) { --grid-cells: 7; } +.grid:has(> :last-child:nth-child(8)) { --grid-cells: 8; } +.grid:has(> :last-child:nth-child(9)) { --grid-cells: 9; } + +/* DEBUG UTILITIES */ + +.debug .debug-grid { + --color: color-mix(in srgb, var(--text-color) 10%, var(--background-color) 90%); + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + z-index: -1; + background-image: + repeating-linear-gradient(var(--color) 0 1px, transparent 1px 100%), + repeating-linear-gradient(90deg, var(--color) 0 1px, transparent 1px 100%); + background-size: 1ch var(--line-height); + margin: 0; +} + +.debug .off-grid { + background: rgba(255, 0, 0, 0.1); +} + +.debug-toggle-label { + text-align: right; +} diff --git a/assets/css/reset.css b/assets/css/reset.css new file mode 100644 index 0000000..aabd759 --- /dev/null +++ b/assets/css/reset.css @@ -0,0 +1,48 @@ +/* http://meyerweb.com/eric/tools/css/reset/ + v2.0 | 20110126 + License: none (public domain) +*/ + +html, body, div, span, applet, object, iframe, +h1, h2, h3, h4, h5, h6, p, blockquote, pre, +a, abbr, acronym, address, big, cite, code, +del, dfn, em, img, ins, kbd, q, s, samp, +small, strike, strong, sub, sup, tt, var, +b, u, i, center, +dl, dt, dd, ol, ul, li, +fieldset, form, label, legend, +table, caption, tbody, tfoot, thead, tr, th, td, +article, aside, canvas, details, embed, +figure, figcaption, footer, header, hgroup, +menu, nav, output, ruby, section, summary, +time, mark, audio, video { + /*margin: 0;*/ + padding: 0; + border: 0; + font-size: 100%; + font: inherit; + vertical-align: baseline; +} +/* HTML5 display-role reset for older browsers */ +article, aside, details, figcaption, figure, +footer, header, hgroup, menu, nav, section { + display: block; +} +body { + line-height: 1; +} +ol, ul { + list-style: none; +} +blockquote, q { + quotes: none; +} +blockquote:before, blockquote:after, +q:before, q:after { + content: ''; + content: none; +} +table { + border-collapse: collapse; + border-spacing: 0; +} diff --git a/assets/js/index.js b/assets/js/index.js new file mode 100644 index 0000000..4379fc2 --- /dev/null +++ b/assets/js/index.js @@ -0,0 +1,120 @@ +function gridCellDimensions() { + const element = document.createElement("div"); + element.style.position = "fixed"; + element.style.height = "var(--line-height)"; + element.style.width = "1ch"; + document.body.appendChild(element); + const rect = element.getBoundingClientRect(); + document.body.removeChild(element); + return { width: rect.width, height: rect.height }; +} + +// Add padding to each media to maintain grid. +function adjustMediaPadding() { + const cell = gridCellDimensions(); + + function setHeightFromRatio(media, ratio) { + const rect = media.getBoundingClientRect(); + const realHeight = rect.width / ratio; + const diff = cell.height - (realHeight % cell.height); + media.style.setProperty("padding-bottom", `${diff}px`); + } + + function setFallbackHeight(media) { + const rect = media.getBoundingClientRect(); + const height = Math.round((rect.width / 2) / cell.height) * cell.height; + media.style.setProperty("height", `${height}px`); + } + + function onMediaLoaded(media) { + var width, height; + switch (media.tagName) { + case "IMG": + width = media.naturalWidth; + height = media.naturalHeight; + break; + case "VIDEO": + width = media.videoWidth; + height = media.videoHeight; + break; + } + if (width > 0 && height > 0) { + setHeightFromRatio(media, width / height); + } else { + setFallbackHeight(media); + } + } + + const medias = document.querySelectorAll("img, video"); + for (media of medias) { + switch (media.tagName) { + case "IMG": + if (media.complete) { + onMediaLoaded(media); + } else { + media.addEventListener("load", () => onMediaLoaded(media)); + media.addEventListener("error", function() { + setFallbackHeight(media); + }); + } + break; + case "VIDEO": + switch (media.readyState) { + case HTMLMediaElement.HAVE_CURRENT_DATA: + case HTMLMediaElement.HAVE_FUTURE_DATA: + case HTMLMediaElement.HAVE_ENOUGH_DATA: + onMediaLoaded(media); + break; + default: + media.addEventListener("loadeddata", () => onMediaLoaded(media)); + media.addEventListener("error", function() { + setFallbackHeight(media); + }); + break; + } + break; + } + } +} + +adjustMediaPadding(); +window.addEventListener("load", adjustMediaPadding); +window.addEventListener("resize", adjustMediaPadding); + +function checkOffsets() { + const ignoredTagNames = new Set([ + "THEAD", + "TBODY", + "TFOOT", + "TR", + "TD", + "TH", + ]); + const cell = gridCellDimensions(); + const elements = document.querySelectorAll("body :not(.debug-grid, .debug-toggle)"); + for (const element of elements) { + if (ignoredTagNames.has(element.tagName)) { + continue; + } + const rect = element.getBoundingClientRect(); + if (rect.width === 0 && rect.height === 0) { + continue; + } + const top = rect.top + window.scrollY; + const left = rect.left + window.scrollX; + const offset = top % (cell.height / 2); + if(offset > 0) { + element.classList.add("off-grid"); + console.error("Incorrect vertical offset for", element, "with remainder", top % cell.height, "when expecting divisible by", cell.height / 2); + } else { + element.classList.remove("off-grid"); + } + } +} + +const debugToggle = document.querySelector(".debug-toggle"); +function onDebugToggle() { + document.body.classList.toggle("debug", debugToggle.checked); +} +debugToggle.addEventListener("change", onDebugToggle); +onDebugToggle(); diff --git a/assets/video/flow-control.mp4 b/assets/video/flow-control.mp4 new file mode 100644 index 0000000..58940fa Binary files /dev/null and b/assets/video/flow-control.mp4 differ diff --git a/build.zig b/build.zig new file mode 100644 index 0000000..ff366f7 --- /dev/null +++ b/build.zig @@ -0,0 +1,15 @@ +const std = @import("std"); +const zine = @import("zine"); + +pub fn build(b: *std.Build) !void { + zine.website(b, .{ + .title = "Flow Editor", + .host_url = "https://flow-editor.github.io", + .content_dir_path = "content", + .layouts_dir_path = "layouts", + .assets_dir_path = "assets", + .static_assets = &.{ + "video/flow-control.mp4", + }, + }); +} \ No newline at end of file diff --git a/build.zig.zon b/build.zig.zon new file mode 100644 index 0000000..6096d27 --- /dev/null +++ b/build.zig.zon @@ -0,0 +1,11 @@ +.{ + .name = "Zine Website", + .version = "0.0.0", + .dependencies = .{ + .zine = .{ + .url = "git+https://github.com/kristoff-it/zine?ref=v0.8.0#ec0f549654a4f7183d4520227b6748bba7ade98e", + .hash = "122049c99f3faaaff159cdccb3792d1518b10534e8225e26e5b24a369d325b0ebdc5", + }, + }, + .paths = .{"."}, +} \ No newline at end of file diff --git a/content/docs/index.smd b/content/docs/index.smd new file mode 100644 index 0000000..836f07d --- /dev/null +++ b/content/docs/index.smd @@ -0,0 +1,27 @@ +--- +.title = "Flow Control - a programmer's text editor", +.date = @date("2020-07-06T00:00:00"), +.author = "Igor Támara", +.layout = "home.shtml", +.draft = false, +--- + +The terminal Editor that came to reallity + +## Features +We have keybindings + +We have modes + +We have syntax highlighting + +We have multiple cursors + +## Differential + +## What we have + +## Friendly Projects +* [Zig](https://ziglang.org/) +* [Zine](https://zine-ssg.io/) +* [Monospace Web](https://owickstrom.github.io/the-monospace-web/) \ No newline at end of file diff --git a/content/faq.smd b/content/faq.smd new file mode 100644 index 0000000..0043978 --- /dev/null +++ b/content/faq.smd @@ -0,0 +1,16 @@ +--- +.title = "FAQ", +.date = @date("2020-07-06T00:00:00"), +.author = "Igor Támara", +.layout = "home.shtml", +.draft = false, +--- + +## What are the next steps? +Join Discord or Download +## Can I have pane or windows? +Not at the moment +## Can I suspend? +Ctrl-z is reserved to Undo +## Can I run a shell command or do a pipe? +In the future \ No newline at end of file diff --git a/content/gems.smd b/content/gems.smd new file mode 100644 index 0000000..05dbe39 --- /dev/null +++ b/content/gems.smd @@ -0,0 +1,27 @@ +--- +.title = "Flow Control - a programmer's text editor", +.date = @date("2020-07-06T00:00:00"), +.author = "Igor Támara", +.layout = "gems.shtml", +.draft = false, +--- + +## We have hidden gems here + +A Rule + +--- + +### Lists + +* Flow +* Zig +* Zat + +### Numbered + +1. Egg +2. Chicken + 1. Raptor + 2. Mammals + diff --git a/content/index.smd b/content/index.smd new file mode 100644 index 0000000..1cf67b6 --- /dev/null +++ b/content/index.smd @@ -0,0 +1,26 @@ +--- +.title = "Flow Control - a programmer's text editor", +.date = @date("2020-07-06T00:00:00"), +.author = "Igor Támara", +.layout = "home.shtml", +.draft = false, +--- + +The terminal Editor that came to reallity +## Features +We have keybindings + +We have modes + +We have syntax highlighting + +We have multiple cursors + +## Differential + +## What we have + +## Friendly Projects +* [Zig](https://ziglang.org/) +* [Zine](https://zine-ssg.io/) +* [Monospace Web](https://owickstrom.github.io/the-monospace-web/) \ No newline at end of file diff --git a/layouts/gems.shtml b/layouts/gems.shtml new file mode 100644 index 0000000..7366158 --- /dev/null +++ b/layouts/gems.shtml @@ -0,0 +1,3 @@ + + + diff --git a/layouts/home.shtml b/layouts/home.shtml new file mode 100644 index 0000000..010d80a --- /dev/null +++ b/layouts/home.shtml @@ -0,0 +1 @@ + diff --git a/layouts/index.shtml b/layouts/index.shtml new file mode 100644 index 0000000..010d80a --- /dev/null +++ b/layouts/index.shtml @@ -0,0 +1 @@ + diff --git a/layouts/templates/base.shtml b/layouts/templates/base.shtml new file mode 100644 index 0000000..a2358aa --- /dev/null +++ b/layouts/templates/base.shtml @@ -0,0 +1,34 @@ + + + + + + + + + + + + + +

+
+ + + \ No newline at end of file