initial commit
This commit is contained in:
30
templates/admin.html
Normal file
30
templates/admin.html
Normal file
@@ -0,0 +1,30 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block content %}
|
||||
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||
<h2>Recipe Management</h2>
|
||||
<a href="{{ url_for('add_recipe') }}" class="btn btn-success">Add New Recipe</a>
|
||||
</div>
|
||||
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Title</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for recipe in recipes %}
|
||||
<tr>
|
||||
<td>{{ recipe.title }}</td>
|
||||
<td>
|
||||
<a href="{{ url_for('edit_recipe', recipe_id=recipe.id) }}" class="btn btn-primary btn-sm">Edit</a>
|
||||
<a href="{{ url_for('delete_recipe', recipe_id=recipe.id) }}" class="btn btn-danger btn-sm" onclick="return confirm('Are you sure you want to delete this recipe?')">Delete</a>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{% endblock %}
|
||||
46
templates/base.html
Normal file
46
templates/base.html
Normal file
@@ -0,0 +1,46 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>{% block title %}Recipe Database{% endblock %}</title>
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/main.css') }}">
|
||||
<script src="{{ url_for('static', filename='js/htmx.min.js') }}"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div class="layout">
|
||||
<nav class="sidebar">
|
||||
<div class="sidebar-content">
|
||||
<div class="brand">
|
||||
<a href="{{ url_for('index') }}">Butter Garden</a>
|
||||
</div>
|
||||
<div class="nav-links">
|
||||
<a class="nav-link" href="{{ url_for('index') }}">Home</a>
|
||||
{% if current_user.is_authenticated and current_user.is_admin %}
|
||||
<a class="nav-link" href="{{ url_for('admin') }}">Admin</a>
|
||||
{% endif %}
|
||||
{% if current_user.is_authenticated %}
|
||||
<a class="nav-link" href="{{ url_for('logout') }}">Logout</a>
|
||||
{% else %}
|
||||
<a class="nav-link" href="{{ url_for('login') }}">Login</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<main class="main-content">
|
||||
{% with messages = get_flashed_messages() %}
|
||||
{% if messages %}
|
||||
{% for message in messages %}
|
||||
<div class="alert alert-info">
|
||||
{{ message }}
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
|
||||
{% block content %}{% endblock %}
|
||||
</main>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
21
templates/index.html
Normal file
21
templates/index.html
Normal file
@@ -0,0 +1,21 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block content %}
|
||||
<div class="row mb-4">
|
||||
<div class="col-md-6 offset-md-3">
|
||||
<input type="text"
|
||||
name="query"
|
||||
class="form-control"
|
||||
placeholder="Search recipes..."
|
||||
hx-get="{{ url_for('search_recipes') }}"
|
||||
hx-trigger="keyup changed delay:500ms"
|
||||
hx-target="#recipe-list"
|
||||
value="{{ search_query if search_query }}">
|
||||
<div class="htmx-indicator">Searching...</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="recipe-list" class="row">
|
||||
{% include 'partials/recipe_list.html' %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
26
templates/login.html
Normal file
26
templates/login.html
Normal file
@@ -0,0 +1,26 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block content %}
|
||||
<div class="row">
|
||||
<div class="col-md-6 offset-md-3">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<h2 class="card-title text-center mb-4">Login</h2>
|
||||
<form method="POST">
|
||||
<div class="mb-3">
|
||||
<label for="username" class="form-label">Username</label>
|
||||
<input type="text" class="form-control" id="username" name="username" required>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="password" class="form-label">Password</label>
|
||||
<input type="password" class="form-control" id="password" name="password" required>
|
||||
</div>
|
||||
<div class="d-grid">
|
||||
<button type="submit" class="btn btn-primary">Login</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
22
templates/partials/recipe_list.html
Normal file
22
templates/partials/recipe_list.html
Normal file
@@ -0,0 +1,22 @@
|
||||
{% for recipe in recipes %}
|
||||
<div class="col">
|
||||
<div class="recipe-card">
|
||||
<h5 class="card-title">{{ recipe.title }}</h5>
|
||||
<p class="card-text">{{ recipe.ingredients.split('\n')[0] }}...</p>
|
||||
<a href="{{ url_for('recipe_detail', recipe_id=recipe.id) }}" class="btn btn-primary">View Recipe</a>
|
||||
{% if current_user.is_authenticated and current_user.is_admin %}
|
||||
<button class="btn btn-danger"
|
||||
hx-delete="{{ url_for('delete_recipe_htmx', recipe_id=recipe.id) }}"
|
||||
hx-target="closest .recipe-card"
|
||||
hx-swap="outerHTML"
|
||||
hx-confirm="Are you sure you want to delete this recipe?">
|
||||
Delete
|
||||
</button>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="col-12 text-center">
|
||||
<p>No recipes found.</p>
|
||||
</div>
|
||||
{% endfor %}
|
||||
25
templates/recipe_detail.html
Normal file
25
templates/recipe_detail.html
Normal file
@@ -0,0 +1,25 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block content %}
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<h1 class="card-title mb-4">{{ recipe.title }}</h1>
|
||||
|
||||
<h4 class="mb-3">Ingredients</h4>
|
||||
<div class="mb-4">
|
||||
{% for ingredient in recipe.ingredients.split('\n') %}
|
||||
<div>{{ ingredient }}</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
<h4 class="mb-3">Instructions</h4>
|
||||
<div class="mb-4">
|
||||
{% for step in recipe.instructions.split('\n') %}
|
||||
<p>{{ step }}</p>
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
<a href="{{ url_for('index') }}" class="btn btn-primary">Back to Recipes</a>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
27
templates/recipe_form.html
Normal file
27
templates/recipe_form.html
Normal file
@@ -0,0 +1,27 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block content %}
|
||||
<div class="row">
|
||||
<div class="col-md-8 offset-md-2">
|
||||
<h2 class="mb-4">{% if recipe %}Edit{% else %}Add New{% endif %} Recipe</h2>
|
||||
<form method="POST">
|
||||
<div class="mb-3">
|
||||
<label for="title" class="form-label">Title</label>
|
||||
<input type="text" class="form-control" id="title" name="title" required value="{{ recipe.title if recipe }}">
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="ingredients" class="form-label">Ingredients (one per line)</label>
|
||||
<textarea class="form-control" id="ingredients" name="ingredients" rows="5" required>{{ recipe.ingredients if recipe }}</textarea>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="instructions" class="form-label">Instructions (one step per line)</label>
|
||||
<textarea class="form-control" id="instructions" name="instructions" rows="8" required>{{ recipe.instructions if recipe }}</textarea>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<button type="submit" class="btn btn-primary">Save Recipe</button>
|
||||
<a href="{{ url_for('admin') }}" class="btn btn-secondary">Cancel</a>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
Reference in New Issue
Block a user