Compare commits
No commits in common. "b3be5fa90d9d9f5057a5257d9607377d9ebed0b1" and "7514e6bb228e58c1e60eaaeb71261b8f1b19e428" have entirely different histories.
b3be5fa90d
...
7514e6bb22
153
recipe.py
153
recipe.py
@ -1,153 +0,0 @@
|
|||||||
import json
|
|
||||||
|
|
||||||
from anytree.importer import DictImporter
|
|
||||||
from sys import argv
|
|
||||||
|
|
||||||
|
|
||||||
class TableCell:
|
|
||||||
def __init__(self, name, rowspan="", colspan="", description="", is_header=False):
|
|
||||||
self.name = name
|
|
||||||
self.rowspan = rowspan
|
|
||||||
self.colspan = colspan
|
|
||||||
self.description = description
|
|
||||||
self.is_header = is_header
|
|
||||||
|
|
||||||
def to_html(self):
|
|
||||||
if self.is_header:
|
|
||||||
html = f"<th title={self.description}>{self.name}</th>"
|
|
||||||
elif not self.name:
|
|
||||||
html = f'<td colspan="{self.colspan}" class="filler"></td>'
|
|
||||||
else:
|
|
||||||
html = f"<td rowspan='{self.rowspan}' colspan='{self.colspan}' title='{self.description}'>{self.name}</td>"
|
|
||||||
|
|
||||||
return html
|
|
||||||
|
|
||||||
|
|
||||||
class Recipe:
|
|
||||||
def __init__(self, json_filename: str):
|
|
||||||
with open(json_filename, 'r') as f:
|
|
||||||
recipe_dict = json.loads(f.read())
|
|
||||||
|
|
||||||
self.name = recipe_dict.get("name")
|
|
||||||
self.desc = recipe_dict.get("description")
|
|
||||||
importer = DictImporter()
|
|
||||||
self.sub_recipes = [importer.import_(data) for data in recipe_dict["sub_recipes"]]
|
|
||||||
|
|
||||||
def generate_ingredient_list(self):
|
|
||||||
ingredients = []
|
|
||||||
|
|
||||||
for sub_recipe in self.sub_recipes:
|
|
||||||
for ingredient in sub_recipe.leaves:
|
|
||||||
if ingredient.description:
|
|
||||||
ingredients.append(f"{ingredient.name} -- {ingredient.description}")
|
|
||||||
else:
|
|
||||||
ingredients.append(ingredient.name)
|
|
||||||
|
|
||||||
return ingredients
|
|
||||||
|
|
||||||
def generate_task_list(self):
|
|
||||||
tasks = []
|
|
||||||
|
|
||||||
for sub_recipe in self.sub_recipes:
|
|
||||||
tasks.extend(self.generate_steps_depth_first(sub_recipe, steps=[]))
|
|
||||||
|
|
||||||
return tasks
|
|
||||||
|
|
||||||
def generate_steps_depth_first(self, node, steps=[]):
|
|
||||||
for child in sorted(node.children, key=lambda x: x.height, reverse=True):
|
|
||||||
steps = self.generate_steps_depth_first(child, steps)
|
|
||||||
|
|
||||||
if not node.is_leaf:
|
|
||||||
steps.append(node.description if node.description else node.name)
|
|
||||||
|
|
||||||
return steps
|
|
||||||
|
|
||||||
def generate_tables(self):
|
|
||||||
tables = []
|
|
||||||
|
|
||||||
for sub_recipe in self.sub_recipes:
|
|
||||||
tables.append(self.build_table_rows_depth_first(sub_recipe))
|
|
||||||
|
|
||||||
return tables
|
|
||||||
|
|
||||||
def build_table_rows_depth_first(self, node, rows=None):
|
|
||||||
if rows is None:
|
|
||||||
rows = []
|
|
||||||
|
|
||||||
for child in sorted(node.children, key=lambda x: x.height, reverse=True):
|
|
||||||
rows = self.build_table_rows_depth_first(child, rows)
|
|
||||||
|
|
||||||
colspan = 0
|
|
||||||
if node.siblings:
|
|
||||||
max_sibling_height = max([s.height for s in node.siblings])
|
|
||||||
|
|
||||||
if max_sibling_height > node.height:
|
|
||||||
colspan = max_sibling_height - node.height + 1
|
|
||||||
|
|
||||||
if node.is_leaf:
|
|
||||||
rows.append([TableCell(node.name, description=node.description, is_header=True)])
|
|
||||||
|
|
||||||
if colspan > 1:
|
|
||||||
rows[-1].append(TableCell("", colspan=colspan-1))
|
|
||||||
|
|
||||||
else:
|
|
||||||
child_leaves = len(node.leaves)
|
|
||||||
cur_row = len(rows) - child_leaves
|
|
||||||
rows[cur_row].append(TableCell(node.name, rowspan=child_leaves, colspan=colspan, description=node.description))
|
|
||||||
|
|
||||||
return rows
|
|
||||||
|
|
||||||
def to_html(self):
|
|
||||||
return f"""<!DOCTYPE html>
|
|
||||||
<html lang='en'>
|
|
||||||
<head><title>{self.name}</title>
|
|
||||||
<link rel='stylesheet' type='text/css' href='style.css'>
|
|
||||||
<meta name='viewport' content='width=device-width, initial-scale=1, maximum-scale=1'>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
|
|
||||||
<header>
|
|
||||||
<nav><a href='./'>Recipe Index</a></nav>
|
|
||||||
<h1>{self.name}</h1>
|
|
||||||
<p>{self.desc}</p>
|
|
||||||
</header>
|
|
||||||
|
|
||||||
<main>
|
|
||||||
<div id='needs'>
|
|
||||||
<h2>Needs</h2>
|
|
||||||
<ul>
|
|
||||||
{"\n".join([f" <li>{ingredient}</li>" for ingredient in self.generate_ingredient_list()])}
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id='preparation'>
|
|
||||||
<h2>Preparation</h2>
|
|
||||||
<ol>
|
|
||||||
{"\n".join([f" <li>{task}</li>" for task in self.generate_task_list()])}
|
|
||||||
</ol>
|
|
||||||
</div>
|
|
||||||
</main>
|
|
||||||
|
|
||||||
<summary>
|
|
||||||
<h2>Tabular Layout</h2>
|
|
||||||
{"\n".join(
|
|
||||||
[f"<table cellspacing=0 border=true>\n{"".join(
|
|
||||||
[f"<tr>\n{"".join(
|
|
||||||
[f" {cell.to_html()}\n" for cell in row]
|
|
||||||
)}</tr>\n" for row in table]
|
|
||||||
)}</table>" for table in self.generate_tables()]
|
|
||||||
)}
|
|
||||||
</summary>
|
|
||||||
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
"""
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
if len(argv) < 2:
|
|
||||||
print(f"usage: {argv[0]} <json file>")
|
|
||||||
exit(1)
|
|
||||||
|
|
||||||
print(Recipe(argv[1]).to_html())
|
|
||||||
|
|
125
recipe_json_to_html.py
Normal file
125
recipe_json_to_html.py
Normal file
@ -0,0 +1,125 @@
|
|||||||
|
import json
|
||||||
|
|
||||||
|
from anytree.importer import DictImporter
|
||||||
|
from sys import argv
|
||||||
|
|
||||||
|
|
||||||
|
def build_table_depth_first(node, rows=None):
|
||||||
|
|
||||||
|
if rows is None:
|
||||||
|
rows = []
|
||||||
|
|
||||||
|
for child in sorted(node.children, key=lambda x: x.height, reverse=True):
|
||||||
|
rows = build_table_depth_first(child, rows)
|
||||||
|
|
||||||
|
colspan = 0
|
||||||
|
if node.siblings:
|
||||||
|
max_sibling_height = max([s.height for s in node.siblings])
|
||||||
|
|
||||||
|
if max_sibling_height > node.height:
|
||||||
|
colspan = max_sibling_height - node.height + 1
|
||||||
|
|
||||||
|
if node.is_leaf:
|
||||||
|
rows.append([f'<th>{node.name}</th>'])
|
||||||
|
|
||||||
|
if colspan > 1:
|
||||||
|
rows[-1].append(f'<td colspan="{colspan-1}" class="filler"></td>')
|
||||||
|
|
||||||
|
else:
|
||||||
|
child_leaves = len(node.leaves)
|
||||||
|
cur_row = len(rows) - child_leaves
|
||||||
|
rows[cur_row].append(f"<td rowspan='{child_leaves}' colspan='{colspan}' title='{node.description}'>{node.name}</td>")
|
||||||
|
|
||||||
|
return rows
|
||||||
|
|
||||||
|
|
||||||
|
def generate_steps_depth_first(node, steps=[]):
|
||||||
|
for child in sorted(node.children, key=lambda x: x.height, reverse=True):
|
||||||
|
steps = generate_steps_depth_first(child, steps)
|
||||||
|
|
||||||
|
if not node.is_leaf:
|
||||||
|
steps.append(node.description if node.description else node.name)
|
||||||
|
|
||||||
|
return steps
|
||||||
|
|
||||||
|
|
||||||
|
if len(argv) < 2:
|
||||||
|
print(f"usage: {argv[0]} <json file>")
|
||||||
|
exit()
|
||||||
|
|
||||||
|
with open(argv[1], 'r') as f:
|
||||||
|
recipe = json.loads(f.read())
|
||||||
|
|
||||||
|
recipe_name = recipe.get("name")
|
||||||
|
recipe_desc = recipe.get("description")
|
||||||
|
importer = DictImporter()
|
||||||
|
sub_recipes = [importer.import_(data) for data in recipe["sub_recipes"]]
|
||||||
|
|
||||||
|
print("<!DOCTYPE html>")
|
||||||
|
print("<html lang='en'>")
|
||||||
|
print(f"<head><title>{recipe_name}</title>")
|
||||||
|
print("<link rel='stylesheet' type='text/css' href='style.css'>")
|
||||||
|
print("<meta name='viewport' content='width=device-width, initial-scale=1, maximum-scale=1'>")
|
||||||
|
print("</head>")
|
||||||
|
print("<body>")
|
||||||
|
|
||||||
|
print("<header>")
|
||||||
|
print("<div id='title'>")
|
||||||
|
print(f"<h1>{recipe_name}</h1>")
|
||||||
|
print("</div>")
|
||||||
|
|
||||||
|
print("<div id='description'>")
|
||||||
|
print(f"<p>{recipe_desc}</p>")
|
||||||
|
print("</div>")
|
||||||
|
print("</header>")
|
||||||
|
|
||||||
|
print("<main>")
|
||||||
|
print("<div id='needs'>")
|
||||||
|
print("<h2>Needs</h2>")
|
||||||
|
print("<ul>")
|
||||||
|
|
||||||
|
for sub_recipe in sub_recipes:
|
||||||
|
for ingredient in sub_recipe.leaves:
|
||||||
|
if ingredient.description:
|
||||||
|
print(f" <li>{ingredient.name} -- {ingredient.description}</li>")
|
||||||
|
else:
|
||||||
|
print(f" <li>{ingredient.name}</li>")
|
||||||
|
|
||||||
|
print("</ul>")
|
||||||
|
print("</div>")
|
||||||
|
|
||||||
|
print("<div id='preparation'>")
|
||||||
|
print("<h2>Preparation</h2>")
|
||||||
|
print("<ol>")
|
||||||
|
|
||||||
|
for sub_recipe in sub_recipes:
|
||||||
|
tasks = generate_steps_depth_first(sub_recipe, steps=[])
|
||||||
|
for task in tasks:
|
||||||
|
print(f" <li>{task}</li>")
|
||||||
|
|
||||||
|
print("</ol>")
|
||||||
|
print("</div>")
|
||||||
|
print("</main>")
|
||||||
|
|
||||||
|
print("<summary>")
|
||||||
|
print("<h2>Tabular Layout</h2>")
|
||||||
|
|
||||||
|
for sub_recipe in sub_recipes:
|
||||||
|
print("<p>")
|
||||||
|
print("<table cellspacing='0' border=true>")
|
||||||
|
|
||||||
|
output_rows = build_table_depth_first(sub_recipe)
|
||||||
|
|
||||||
|
for row in output_rows:
|
||||||
|
print("<tr>")
|
||||||
|
for cell in row:
|
||||||
|
print(f" {cell}")
|
||||||
|
print("</tr>")
|
||||||
|
|
||||||
|
print("</table>")
|
||||||
|
print("</p>")
|
||||||
|
|
||||||
|
print("</summary>")
|
||||||
|
|
||||||
|
print("</body>")
|
||||||
|
print("</html>")
|
Loading…
x
Reference in New Issue
Block a user