MaCH repo

This commit is contained in:
2025-07-24 12:46:01 -05:00
committed by Nick Ricketts
commit aed05c63c9
75 changed files with 6508 additions and 0 deletions

View File

@@ -0,0 +1 @@
compare to https://github.com/t3dotgg/1app5stacks

View File

@@ -0,0 +1,7 @@
CREATE TABLE IF NOT EXISTS pokemons (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
sprite TEXT NOT NULL,
wins INTEGER NOT NULL DEFAULT 0,
loses INTEGER NOT NULL DEFAULT 0
);

View File

@@ -0,0 +1,4 @@
select id, name, sprite
from pokemons
order by random()
limit 2;

View File

@@ -0,0 +1,5 @@
select id, name, sprite, wins, loses,
cast(wins as real) / nullif(loses, 0) as ratio_of_wins_to_loses,
row_number() over (order by (cast(wins as real) / nullif(loses, 0)) desc) as rank
from pokemons
order by ratio_of_wins_to_loses desc;

View File

@@ -0,0 +1,53 @@
<!DOCTYPE html>
<html>
<head>
<title>Roundest (MaCH Version)</title>
{{> htmx_script}}
{{> tailwind_script}}
</head>
<body hx-boost='true'>
<div class='bg-gray-950 text-white flex flex-col justify-between font-geist min-h-screen border-t-2 border-red-300'>
<nav class='flex flex-row justify-between items-center py-4 px-8'>
<div class='flex items-baseline'>
<a href='{{url:home}}' class='font-bold text-3xl'>
Round<span class='text-red-300'>est</span>
</a>
<p class='text-gray-400 font-extralight pl-2 text-2xl'>
(MaCH Version)
</p>
</div>
<div class='flex flex-row items-center gap-8'>
<a href='{{url:results}}' class='hover:underline text-lg'>Results</a>
</div>
</nav>
<main>
{{$body}}
<div class='container mx-auto px-4'>
<h1 class='text-3xl font-bold text-center mb-8'>Vote for which is roundest</h1>
<div class='flex justify-center gap-16 items-center min-h-[80vh]'>
{{#challengers}}
<form action='{{url:home}}' method='post'>
<div class='flex flex-col items-center gap-4'>
<img src='{{sprite}}' alt='{{name}}' class='w-64 h-64 sprite'>
<div class='text-center'>
<span class='text-gray-500 text-lg'>#{{id}}</span>
<h2 class='text-2xl font-bold capitalize'>{{name}}</h2>
<input type='hidden' name='winner' value='{{id}}'>
<input type='hidden' name='loser' value='{{opponent_id}}'>
<button class='mt-4 px-8 py-3 bg-blue-500 text-white rounded-lg text-lg font-semibold hover:bg-blue-600 transition-colors'>
Vote
</button>
</div>
</div>
</form>
{{/challengers}}
</div>
</div>
{{/body}}
</main>
<footer class='font-light text-center py-3 text-gray-500'>
<a href='https://code.nightshadecoder.dev/nightshade/mach_examples' target='_blank'>GitHub</a>
</footer>
</div>
</body>
</html>

View File

@@ -0,0 +1,83 @@
#include <mach.h>
#include <htmx.h>
#include <sqlite.h>
#include <tailwind.h>
config mach(){
return (config) {
.resources = {
{"home", "/",
.get = {
query({"get_challengers",
.set_key = "challengers",
.db = "pokemon_db"
}),
exec(^(){
auto const t = get("challengers");
auto const p0 = table_get(t, 0);
auto const p1 = table_get(t, 1);
record_set(p0, "opponent_id", record_get(p1, "id"));
record_set(p1, "opponent_id", record_get(p0, "id"));
}),
render("home")
},
.post = {
validate(
{"winner",
.validation = "^\\d{1,8}$",
.message = "must be 1-99999999"
},
{"loser",
.validation = "^\\d{1,8}$",
.message = "must be 1-99999999"
}
),
find({"vote",
.db = "pokemon_db"
}),
reroute("home")
}
},
{"result", "/results",
.get = {
query({"get_results",
.set_key = "results",
.db = "pokemon_db"
}),
render("results")
}
}
},
.context = {
{"home", (asset){
#embed "home.mustache.html"
}},
{"results", (asset){
#embed "results.mustache.html"
}},
{"get_challengers", (asset){
#embed "get_challengers.sql"
}},
{"vote", (asset){
#embed "vote.sql"
}},
{"get_results", (asset){
#embed "get_results.sql"
}}
},
.databases = {{
.name = "pokemon_db",
.engine = sqlite_db,
.connect = "file::memory:?cache=shared",
.migrations = {(asset){
#embed "create_pokemons_table.sql"
}}
}},
.modules = {htmx, sqlite, tailwind}
};
}

View File

@@ -0,0 +1,28 @@
{{< home}}
{{$body}}
<div class='container mx-auto px-4 py-8 text-white'>
<div class='grid gap-4'>
{{#results}}
<div class='flex items-center gap-6 p-6 bg-gray-800/40 rounded-lg shadow hover:shadow-md transition-shadow'>
<div class='text-2xl font-bold text-gray-400 w-8'>
{{rank}}
</div>
<img src='{{sprite}}' alt='{{name}}' loading='lazy' class='w-20 h-20'>
<div class='flex-grow'>
<div class='text-gray-400 text-sm'>#{{id}}</div>
<h2 class='text-xl font-semibold capitalize'>{{name}}</h2>
</div>
<div class='text-right'>
<div class='text-2xl font-bold text-blue-400'>
{{ratio_of_wins_to_loses}}
</div>
<div class='text-sm text-gray-400'>
{{wins}}W - {{loses}}L
</div>
</div>
</div>
{{/results}}
</div>
</div>
{{/body}}
{{/home}}

View File

@@ -0,0 +1,8 @@
begin transaction;
update pokemons
set wins = wins + 1
where id = {{winner}};
update pokemons
set loses = loses + 1
where id = {{loser}};
commit;