Zach Goethel

This Site

My portfolio site is written in my own reactive declarative markup language, serving as a testbed for new source generation features.

Some demos:

Count: 0
state {
	int count
}

interface {
	Increment(),
	Decrement()
}

div(| class = {"d-flex flex-row"} |
	div(| class = {"my-auto"} |
		{"Count: " + count}
	)
	button(|
		class = {"btn btn-danger ms-2"},
		onclick = {"dispatch(this, 'Decrement');"}
		|
		<">-</">
	)
	button(|
		class = {"btn btn-success ms-2"},
		onclick = {"dispatch(this, 'Increment');"}
		|
		<">+</">
	)
)
namespace TestApp.Views;

using Generated;

public class UpDownDemo : UpDownDemoBase
{
    public UpDownDemo(IServiceProvider sp) : base(sp)
    {
    }

    public override void Decrement()
    {
        count--;
    }

    public override void Increment()
    {
        count++;
    }
}

Serverside code is generated to render HTML for the component. Controller endpoints are also generated corresponding to any actions within the component interface.

Some minimal JS swaps out DOM elements to reactively update the page to reflect its latest state.

ValueActions
Row 1
Row 2
state {
	List<string> rows = {new() { "Row 1", "Row 2" }}
}

interface {
	Add(string row),
	Remove(int index),
	MoveUp(int index),
	MoveDown(int index)
}

table(| class = {"table table-striped table-bordered"} |
	colgroup(
		col(| style = {"width: 70%;"} |)
		col(| style = {"width: 30%;"} |)
	)
	thead(
		tr(
			th(<">Value</">)
			th(<">Actions</">)
		)
	)
	tbody(
		tr(
			td(
				input(|
					type = {"text"},
					id = {"table-add"},
					class = {"form-control"},
					value = {rows.Count >= 5 ? "Max 5 rows" : ""},
					disabled = {rows.Count >= 5}
					|)
			)
			td(
				button(|
					type = {"button"},
					class = {"btn btn-outline-primary"},
					onclick = {"dispatch(this, 'Add', { row: $('#table-add').val() });"},
					disabled = {rows.Count >= 5}
					|
					<">Add</">
				)
			)
		)
		foreach({var (row, i) in rows.Select((it, i) => (it, i))}

			tr(
				td({string.IsNullOrEmpty(row) ? "Blank!" : row})
				td(
					i(|
						class = {"fa fa-arrow-up me-2"},
						style = {"cursor: pointer;"},
						onclick = {"dispatch(this, 'MoveUp', { index: " + i + " });"}
						|)
					i(|
						class = {"fa fa-arrow-down me-2"},
						style = {"cursor: pointer;"},
						onclick = {"dispatch(this, 'MoveDown', { index: " + i + " });"}
						|)
					i(|
						class = {"fa fa-trash me-2"},
						style = {"cursor: pointer;"},
						onclick = {"dispatch(this, 'Remove', { index: " + i + " });"}
						|)
				)
			)
		)
	)
)
namespace TestApp.Views;

using Generated;

public class TableRowDemo : TableRowDemoBase
{
    public TableRowDemo(IServiceProvider sp) : base(sp)
    {
    }

    public override void Add(string row)
    {
        if (rows.Count < 5)
        {
            rows.Add(row);
        }
    }

    public override void MoveDown(int index)
    {
        if (index >= rows.Count - 1)
        {
            return;
        }
        var temp = rows[index];
        rows[index] = rows[index + 1];
        rows[index + 1] = temp;
    }

    public override void MoveUp(int index)
    {
        if (index <= 0)
        {
            return;
        }
        var temp = rows[index];
        rows[index] = rows[index - 1];
        rows[index - 1] = temp;
    }

    public override void Remove(int index)
    {
        rows.RemoveAt(index);
    }
}

Recent Gists

JS drag-and-drop polyfillEnables dragging and dropping relying on fewer browser events
RAID 5 and 6 calculations in C#Demonstrates the algorithms use to calculate the parities P and Q used in RAID
Simple implementation of regexSingle-file FSA builder, token search, NFA to DFA algorithm, and state minimizer
String buffer writer in CAllows efficient concatenation of numerous strings (e.g., to build a source file)
Least bottlenecked route finderBrute-force search for the least bottlenecked path through a graph
Centrifugal Sort joke algorithm"Sorts" items based on "weights" and loosely simulated inertia
Created by Zach Goethel. Have a wonderful day!