From 8d66fe6f5ff55b349236c6ead6a68a296e12b7e8 Mon Sep 17 00:00:00 2001 From: Blitblank Date: Wed, 26 Aug 2026 23:03:58 -0500 Subject: [PATCH] scaffold markup --- client/src/app/app.html | 2 + client/src/app/app.ts | 3 +- client/src/app/markleft/markleft.html | 1 + client/src/app/markleft/markleft.scss | 12 +++ client/src/app/markleft/markleft.spec.ts | 22 ++++ client/src/app/markleft/markleft.ts | 124 +++++++++++++++++++++++ 6 files changed, 163 insertions(+), 1 deletion(-) create mode 100644 client/src/app/markleft/markleft.html create mode 100644 client/src/app/markleft/markleft.scss create mode 100644 client/src/app/markleft/markleft.spec.ts create mode 100644 client/src/app/markleft/markleft.ts diff --git a/client/src/app/app.html b/client/src/app/app.html index 5ced12f..c44dc77 100644 --- a/client/src/app/app.html +++ b/client/src/app/app.html @@ -8,4 +8,6 @@

2. automated dynamic themes. a theme based on a good color palette can rotate the hues around so the colors can change but maintain the same distance apart

3. world of text is goated, its like a chat room but infinite

+ + diff --git a/client/src/app/app.ts b/client/src/app/app.ts index 0c570e3..7808db9 100644 --- a/client/src/app/app.ts +++ b/client/src/app/app.ts @@ -1,9 +1,10 @@ import { Component, signal } from '@angular/core'; import { RouterOutlet } from '@angular/router'; +import { Markleft } from './markleft/markleft' @Component({ selector: 'app-root', - imports: [RouterOutlet], + imports: [Markleft, RouterOutlet], templateUrl: './app.html', styleUrl: './app.scss' }) diff --git a/client/src/app/markleft/markleft.html b/client/src/app/markleft/markleft.html new file mode 100644 index 0000000..849e4d8 --- /dev/null +++ b/client/src/app/markleft/markleft.html @@ -0,0 +1 @@ +

markleft works!

diff --git a/client/src/app/markleft/markleft.scss b/client/src/app/markleft/markleft.scss new file mode 100644 index 0000000..4ee8220 --- /dev/null +++ b/client/src/app/markleft/markleft.scss @@ -0,0 +1,12 @@ + +.format-bold { + font-weight: bold; +} + +.format-italic { + font-style: italic; +} + +.format-underline { + text-decoration: underline solid #000000 3px; +} diff --git a/client/src/app/markleft/markleft.spec.ts b/client/src/app/markleft/markleft.spec.ts new file mode 100644 index 0000000..68b817b --- /dev/null +++ b/client/src/app/markleft/markleft.spec.ts @@ -0,0 +1,22 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { Markleft } from './markleft'; + +describe('Markleft', () => { + let component: Markleft; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [Markleft], + }).compileComponents(); + + fixture = TestBed.createComponent(Markleft); + component = fixture.componentInstance; + await fixture.whenStable(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/client/src/app/markleft/markleft.ts b/client/src/app/markleft/markleft.ts new file mode 100644 index 0000000..47b7522 --- /dev/null +++ b/client/src/app/markleft/markleft.ts @@ -0,0 +1,124 @@ +import { Component } from '@angular/core'; + +// type descriptions + +interface formatDescriptor { + className: string; +}; + +interface textNode { + type: string; + text: string; + styles: formatDescriptor[] +} + +interface blockNode { + type: string; + kind: string; + children: (blockNode | textNode)[] +} + +// styles registry: this maps format specifiers to css classes +const styles: Record = { + B: { + className: "format-bold" + }, + I: { + className: "format-italic" + }, + U: { + className: "format-underline" + }, +}; // i.e. %B{...} will apply "format-bold" + +@Component({ + selector: 'app-markleft', + imports: [], + templateUrl: './markleft.html', + styleUrl: './markleft.scss', +}) +export class Markleft { + + plaintext: String = ` + #H1{Hello World!} + #P{ + This is some markleft text. This is %I{italic} and this is %B{bold}. Some might %I{even be %B{both}}. + } + This should be plain and unstylized. + `; + + parsePlaintext(input: string): /*structureNode[]*/ void { + + /* pseudocode (c lol) + + int index = 0; + + void parse(char endChar = null, formatDescriptor[]) { + const nodes = []; // start with an empty list of nodes + + while(index < input.length) { // iterate over the input string + // break if } encountered, step forward (this format block has exited) + if(endChar && (input[pos] == endChar)) { + index++; + break; + } + + if(input[index] == "%") { + nodes.push(parseStyle(...)); + } else if(input[index] == "#") { + nodes.push(parseBlock(...)); + } else { + nodes.push(parseText(...)); + } + + return mergeAdjacentText(nodes); + } + + } + + void parseStyle(parentStyle) { + index++; // step onto specifier + char code = readIdentifier(input[index]) + index++; + expect("{"); // parsing error if not + const styles = [...parentStyles, code] // append style code to styles list of this node + const children = parseUntil("}", styles); // recursion probably + + return children + } + ... and so on for parseBlock and parseText + + */ + return; + } + + renderNode(node: (textNode | blockNode)): void { + + /* + if(node.type == "text") { // text nodes only need span elements + + element span = html.createElement("span"); // or whatever it is + + // add styles + foreach(style style in node.styles) { + span.classes.add(styles[style].className); + } + return span; + + } else if(node.type == "block") { + + element block = html.createElement(node.kind); // or whatever it is + + // recursion + foreach(nodeType child in node.children) { + block.children.add(renderNode(child)); + } + return block; + + } + + */ + + return; + } +}