Switched to rinja and stable rust + basic recipes list for KH3

master
Wynd 2025-01-27 14:55:10 +02:00
parent 88777f82a2
commit 62be9ca44f
10 changed files with 502 additions and 6 deletions

View File

@ -4,7 +4,7 @@ version = "1.1.0"
edition = "2021"
[dependencies]
askama = "0.12.1"
rinja = "0.3.5"
serde = { version = "1.0.203", features = ["derive"] }
serde_json = "1.0.118"
toml = "0.8.19"

View File

@ -0,0 +1,217 @@
[[starters]]
name = "Mushroom Terrine"
is_special = false
ingredients = ["Morel", "Chanterelle", "King Oyster Mushroom", "Black Trumpet"]
normal = { str = 0, mag = 0, def = 0, hp = 2, mp = 8 }
plus = { str = 0, mag = 0, def = 0, hp = 4, mp = 10 }
[[starters]]
name = "Scallop Poêlé"
is_special = false
ingredients = ["Scallop", "Olive Oil"]
normal = { str = 0, mag = 0, def = 0, hp = 4, mp = 10 }
plus = { str = 0, mag = 0, def = 0, hp = 6, mp = 12 }
[[starters]]
name = "Ratatouille"
is_special = false
ingredients = ["Zucchini", "Eggplant", "Tomato", "Garlic", "Bay Leaf"]
normal = { str = 0, mag = 0, def = 0, hp = 6, mp = 12 }
plus = { str = 0, mag = 0, def = 0, hp = 8, mp = 14 }
[[starters]]
name = "Lobster Mousse"
is_special = false
ingredients = ["Lobster", "Scallop", "Dill"]
normal = { str = 0, mag = 0, def = 1, hp = 2, mp = 18 }
plus = { str = 0, mag = 0, def = 1, hp = 4, mp = 20 }
[[starters]]
name = "Caprese Salad"
is_special = true
ingredients = ["Strawberry", "Tomato", "Cheese", "Basil"]
normal = { str = 0, mag = 1, def = 0, hp = 0, mp = 14 }
plus = { str = 0, mag = 1, def = 0, hp = 2, mp = 16 }
[[soups]]
name = "Consommé"
is_special = false
ingredients = ["Celery", "Onion", "Cloves"]
normal = { str = 0, mag = 0, def = 0, hp = 10, mp = 0 }
plus = { str = 0, mag = 0, def = 0, hp = 12, mp = 2 }
[[soups]]
name = "Pumpkin Velouté"
is_special = false
ingredients = ["Pumpkin", "Black Truffle"]
normal = { str = 0, mag = 0, def = 0, hp = 8, mp = 2 }
plus = { str = 0, mag = 0, def = 0, hp = 10, mp = 4 }
[[soups]]
name = "Carrot Potage"
is_special = false
ingredients = ["Carrot", "Onion", "Rice", "Butter"]
normal = { str = 0, mag = 0, def = 0, hp = 16, mp = 3 }
plus = { str = 0, mag = 0, def = 0, hp = 18, mp = 5 }
[[soups]]
name = "Crab Bisque"
is_special = false
ingredients = ["Crab", "Tomato", "Carrot", "Celery", "Olive Oil"]
normal = { str = 0, mag = 1, def = 0, hp = 18, mp = 0 }
plus = { str = 0, mag = 1, def = 0, hp = 20, mp = 2 }
[[soups]]
name = "Cold Tomato Soup"
is_special = true
ingredients = ["Watermelon", "Tomato", "Dill"]
normal = { str = 0, mag = 1, def = 0, hp = 18, mp = 3 }
plus = { str = 0, mag = 1, def = 0, hp = 20, mp = 5 }
[[fish]]
name = "Sole Meunière"
is_special = false
ingredients = ["Sole", "Caviar"]
normal = { str = 0, mag = 0, def = 1, hp = 2, mp = 0 }
plus = { str = 0, mag = 0, def = 1, hp = 4, mp = 2 }
[[fish]]
name = "Eel Matelote"
is_special = false
ingredients = ["Eel", "Bay Leaf", "Parsley"]
normal = { str = 0, mag = 0, def = 1, hp = 4, mp = 2 }
plus = { str = 0, mag = 0, def = 1, hp = 6, mp = 4 }
[[fish]]
name = "Bouillabaisse"
is_special = false
ingredients = ["Mussel", "Lobster", "Cod", "Garlic", "Saffron"]
normal = { str = 0, mag = 0, def = 2, hp = 6, mp = 3 }
plus = { str = 0, mag = 0, def = 2, hp = 8, mp = 5 }
[[fish]]
name = "Sea Bass en Papillote"
is_special = false
ingredients = ["Sea Bass", "Basil", "Thyme", "Olive Oil"]
normal = { str = 0, mag = 0, def = 2, hp = 8, mp = 2 }
plus = { str = 0, mag = 0, def = 2, hp = 10, mp = 4 }
[[fish]]
name = "Seafood Tartare"
is_special = true
ingredients = ["Blood Orange", "Lobster", "Sea Bass", "Olive Oil"]
normal = { str = 1, mag = 0, def = 1, hp = 2, mp = 3 }
plus = { str = 1, mag = 0, def = 1, hp = 4, mp = 5 }
[[fish]]
name = "Sea Bass Poêlé"
is_special = true
ingredients = ["Grapes", "Sea Bass", "Zucchini", "Chanterelle", "Parsley"]
normal = { str = 1, mag = 0, def = 1, hp = 4, mp = 3 }
plus = { str = 1, mag = 0, def = 1, hp = 6, mp = 5 }
[[meat]]
name = "Sweetbread Poêlé"
is_special = false
ingredients = ["Porcini", "Lemon", "Veal"]
normal = { str = 1, mag = 0, def = 0, hp = 4, mp = 0 }
plus = { str = 1, mag = 0, def = 0, hp = 6, mp = 0 }
[[meat]]
name = "Beef Sauté"
is_special = false
ingredients = ["Cornichon", "Eggplant", "Zucchini", "Beef"]
normal = { str = 1, mag = 0, def = 0, hp = 6, mp = 0 }
plus = { str = 1, mag = 0, def = 0, hp = 8, mp = 0 }
[[meat]]
name = "Beef Bourguignon"
is_special = false
ingredients = ["Rosemary", "Bay Leaf", "Thyme", "Garlic", "Beef"]
normal = { str = 1, mag = 0, def = 0, hp = 8, mp = 0 }
plus = { str = 1, mag = 0, def = 0, hp = 10, mp = 0 }
[[meat]]
name = "Stuffed Quail"
is_special = false
ingredients = [
"Rice",
"Portobello",
"Porcini",
"Miller Mushroom",
"Parsley",
"Quail",
]
normal = { str = 2, mag = 0, def = 1, hp = 10, mp = 0 }
plus = { str = 2, mag = 0, def = 1, hp = 12, mp = 0 }
[[meat]]
name = "Filet Mignon Poêlé"
is_special = true
ingredients = [
"Sour Cherry",
"Butter",
"Black Truffle",
"Rosemary",
"Cloves",
"Filet Mignon",
]
normal = { str = 1, mag = 0, def = 1, hp = 4, mp = 0 }
plus = { str = 1, mag = 0, def = 1, hp = 6, mp = 0 }
[[deserts]]
name = "Chocolate Mousse"
is_special = false
ingredients = ["Chocolate", "Lemon", "Butter"]
normal = { str = 0, mag = 1, def = 0, hp = 0, mp = 2 }
plus = { str = 0, mag = 1, def = 0, hp = 0, mp = 4 }
[[deserts]]
name = "Fresh Fruit Compote"
is_special = false
ingredients = ["Pear", "Apple", "Apricot"]
normal = { str = 0, mag = 1, def = 0, hp = 0, mp = 6 }
plus = { str = 0, mag = 1, def = 0, hp = 0, mp = 8 }
[[deserts]]
name = "Crêpes Suzette"
is_special = false
ingredients = ["Orange", "Butter", "Honey"]
normal = { str = 0, mag = 2, def = 0, hp = 0, mp = 4 }
plus = { str = 0, mag = 2, def = 0, hp = 0, mp = 6 }
[[deserts]]
name = "Berries au Fromage"
is_special = false
ingredients = ["Cheese", "Lemon", "Gooseberry", "Raspberry", "Blackberry"]
normal = { str = 0, mag = 2, def = 0, hp = 0, mp = 8 }
plus = { str = 0, mag = 2, def = 0, hp = 0, mp = 10 }
[[deserts]]
name = "Warm Banana Soufflé"
is_special = true
ingredients = ["Banana", "Butter", "Honey"]
normal = { str = 1, mag = 1, def = 0, hp = 0, mp = 4 }
plus = { str = 1, mag = 1, def = 0, hp = 0, mp = 6 }
[[deserts]]
name = "Fruit Gelée"
is_special = true
ingredients = ["Melon", "Pear", "Gooseberry"]
normal = { str = 1, mag = 2, def = 0, hp = 0, mp = 4 }
plus = { str = 1, mag = 2, def = 0, hp = 0, mp = 6 }
[[deserts]]
name = "Tarte aux Fruits"
is_special = true
ingredients = [
"Sour Cherry",
"Strawberry",
"Blood Orange",
"Banana",
"Grapes",
"Melon",
"Watermelon",
]
normal = { str = 1, mag = 2, def = 0, hp = 0, mp = 8 }
plus = { str = 1, mag = 2, def = 0, hp = 0, mp = 10 }

2
rinja.toml 100644
View File

@ -0,0 +1,2 @@
[general]
whitespace = "suppress"

View File

@ -1,2 +1,2 @@
[toolchain]
channel = "nightly"
channel = "stable"

View File

@ -1,7 +1,7 @@
use std::collections::HashMap;
use askama::Template;
use itertools::Itertools;
use rinja::Template;
use serde::Deserialize;
#[derive(Debug, Deserialize, PartialEq, Eq)]
@ -119,7 +119,7 @@ struct Finisher {
}
#[derive(Template)]
#[template(path = "pages/bbs-commands.html", whitespace = "suppress")]
#[template(path = "pages/bbs-commands.html")]
struct CommandsTemplate {
pub commands: Vec<Command>,
pub crystals: Vec<String>,

View File

@ -1,7 +1,7 @@
use std::{fmt::Display, panic, path::PathBuf};
use askama::Template;
use itertools::Itertools;
use rinja::Template;
use serde::{Deserialize, Deserializer};
#[derive(Debug, Deserialize, PartialEq, Eq)]
@ -323,7 +323,7 @@ impl Display for Interaction {
}
#[derive(Template)]
#[template(path = "pages/ddd-abilities.html", whitespace = "suppress")]
#[template(path = "pages/ddd-abilities.html")]
struct AbilitiesTemplate {
pub boards: Vec<Board>,
}

74
src/kh3.rs 100644
View File

@ -0,0 +1,74 @@
use std::fmt::Display;
use rinja::Template;
use serde::Deserialize;
#[derive(Debug, Deserialize, PartialEq, Eq)]
struct Recipes {
starters: Vec<Recipe>,
soups: Vec<Recipe>,
fish: Vec<Recipe>,
meat: Vec<Recipe>,
deserts: Vec<Recipe>,
}
#[derive(Debug, Deserialize, PartialEq, Eq)]
struct Recipe {
name: String,
is_special: bool,
ingredients: Vec<String>,
normal: FoodStats,
plus: FoodStats,
}
impl Recipe {
fn stats(&self, is_plus: &bool) -> &FoodStats {
if *is_plus {
&self.normal
} else {
&self.plus
}
}
}
#[derive(Debug, Deserialize, PartialEq, Eq)]
struct FoodStats {
str: u8,
mag: u8,
def: u8,
hp: u8,
mp: u8,
}
impl Display for FoodStats {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let val = serde_json::json!({
"str": self.str,
"mag": self.mag,
"def": self.def,
"hp": self.hp,
"mp": self.mp
});
f.write_str(&val.to_string())?;
Ok(())
}
}
#[derive(Template)]
#[template(path = "pages/kh3-recipes.html")]
struct RecipesTemplate {
pub recipes: Recipes,
}
const RECIPES_PATH: &str = "./input/kh3/recipes.toml";
pub fn init() {
tracing::info!("Loading recipes data from {}", RECIPES_PATH);
let recipes_str = std::fs::read_to_string(RECIPES_PATH).unwrap();
let recipes = toml::from_str::<Recipes>(&recipes_str).unwrap();
tracing::info!("Generating the KH3 recipes template");
let template = RecipesTemplate { recipes };
std::fs::write("./out/kh3-recipes.html", template.render().unwrap()).unwrap();
}

View File

@ -4,6 +4,7 @@ use tracing_subscriber::EnvFilter;
mod bbs;
mod ddd;
mod kh3;
pub const VERSION: &str = env!("CARGO_PKG_VERSION");
@ -16,4 +17,5 @@ fn main() {
bbs::init();
ddd::init();
kh3::init();
}

View File

@ -0,0 +1,39 @@
{% for i in 0..2 %}
{% let stats = recipe.stats(i == 1) %}
<div class="recipe" data-stats="{{ stats }}">
<h1 class="title">{{ recipe.name }} {% if loop.last %}+{% endif %}</h1>
<div class="ingredients">
<h2>Ingredients</h2>
<ul>
{% for ingredient in recipe.ingredients %}
<li>{{ ingredient }}</li>
{% endfor %}
</ul>
</div>
<div class="stats">
<h2>Stats</h2>
<table>
<thead>
<tr>
<th scope="col">STR</th>
<th scope="col">MAG</th>
<th scope="col">DEF</th>
<th scope="col">HP</th>
<th scope="col">MP</th>
</tr>
</thead>
<tbody>
<tr>
<td>{{ stats.str }}</td>
<td>{{ stats.mag }}</td>
<td>{{ stats.def }}</td>
<td>{{ stats.hp }}</td>
<td>{{ stats.mp }}</td>
</tr>
</tbody>
</table>
</div>
</div>
{% endfor %}

View File

@ -0,0 +1,162 @@
{% extends "layouts/base.html" %}
{% block title %}Recipes{% endblock %}
{% block head %}
<style>
#content > h1 {
text-align: center;
}
.recipes {
font-size: 12px;
display: flex;
flex-wrap: wrap;
justify-content: center;
align-items: baseline;
gap: 16px;
}
.recipe {
width: 20%;
align-self: stretch;
box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.4);
padding: 16px;
cursor: pointer;
display: flex;
flex-direction: column;
justify-content: space-between;
.ingredients {
margin-left: 16px;
}
.stats {
table {
tr.plus {
color: gold;
}
th {
padding: 8px;
}
td {
background-color: #4d4d4d;
}
}
}
}
</style>
<script>
let globalStats = { str: 0, mag: 0, def: 0, hp: 0, mp: 0 };
const types = ["starters", "soups", "fish", "meat", "deserts"];
let typeItem = [];
let hasSelection = [false, false, false, false, false];
document.addEventListener("DOMContentLoaded", (event) => {
types.forEach(function (type, typeIdx) {
const recipes = document.querySelectorAll(
"div.recipes." + type + " .recipe",
);
recipes.forEach(function (item, index) {
item.addEventListener("click", function () {
if (!hasSelection[typeIdx]) {
hasSelection[typeIdx] = true;
selectRecipe(item, typeIdx);
} else {
if (typeItem[typeIdx] != item) {
unselectRecipe(typeIdx);
selectRecipe(item, typeIdx);
} else {
hasSelection[typeIdx] = false;
unselectRecipe(typeIdx);
}
}
});
});
});
function unselectRecipe(index) {
typeItem[index].style["box-shadow"] =
"0px 0px 10px rgba(0, 0, 0, 0.4)";
}
function selectRecipe(item, index) {
if (typeItem[index] != undefined) {
let prevStats = JSON.parse(
typeItem[index].dataset["stats"],
);
removeStats(prevStats);
}
typeItem[index] = item;
item.style["box-shadow"] = "0px 0px 10px rgba(0, 255, 0, 0.8)";
let stats = JSON.parse(item.dataset["stats"]);
addStats(stats);
}
function addStats(stats) {
globalStats.str += stats.str;
globalStats.mag += stats.mag;
globalStats.def += stats.def;
globalStats.hp += stats.hp;
globalStats.mp += stats.mp;
updateStats();
}
function removeStats(stats) {
globalStats.str -= stats.str;
globalStats.mag -= stats.mag;
globalStats.def -= stats.def;
globalStats.hp -= stats.hp;
globalStats.mp -= stats.mp;
}
function updateStats() {
const elem = document.getElementById("stats");
console.log(elem);
}
});
</script>
{% endblock %}
{% block content %}
<div id="stats"></div>
<h1>Starters</h1>
<div class="recipes starters">
{% for recipe in recipes.starters %}
{% include "components/kh3/recipe.html" %}
{% endfor %}
</div>
<h1>Soups</h1>
<div class="recipes soups">
{% for recipe in recipes.soups %}
{% include "components/kh3/recipe.html" %}
{% endfor %}
</div>
<h1>Fish Dishes</h1>
<div class="recipes fish">
{% for recipe in recipes.fish %}
{% include "components/kh3/recipe.html" %}
{% endfor %}
</div>
<h1>Meat Dishes</h1>
<div class="recipes meat">
{% for recipe in recipes.meat %}
{% include "components/kh3/recipe.html" %}
{% endfor %}
</div>
<h1>Deserts</h1>
<div class="recipes deserts">
{% for recipe in recipes.deserts %}
{% include "components/kh3/recipe.html" %}
{% endfor %}
</div>
{% endblock %}