This commit is contained in:
hex
2025-04-29 13:54:11 -07:00
commit 0c38bf894c
32 changed files with 1431 additions and 0 deletions

View File

@@ -0,0 +1,16 @@
{% extends "admin/base.html" %}
{% block title %}Add Category - Digital Garage Sale{% endblock %}
{% block content %}
<h2>Add New Category</h2>
<form method="post" action="{{ url_for('admin.add_category') }}">
<div class="form-group">
<label for="name">Category Name</label>
<input type="text" id="name" name="name" class="form-control" required>
</div>
<button type="submit" class="btn btn-primary">Add Category</button>
<a href="{{ url_for('admin.categories') }}" class="btn" style="margin-left: 0.5rem;">Cancel</a>
</form>
{% endblock %}

View File

@@ -0,0 +1,52 @@
{% extends "admin/base.html" %}
{% block title %}Add Item - Digital Garage Sale{% endblock %}
{% block content %}
<h2>Add New Item</h2>
<form method="post" action="{{ url_for('admin.add_item') }}" enctype="multipart/form-data">
<div class="form-group">
<label for="title">Item Title</label>
<input type="text" id="title" name="title" class="form-control" required>
</div>
<div class="form-group">
<label for="description">Description</label>
<textarea id="description" name="description" class="form-control" rows="4" required></textarea>
</div>
<div class="form-group">
<label for="price">Price ($)</label>
<input type="number" id="price" name="price" class="form-control" step="0.01" min="0" required>
</div>
<div class="form-group">
<label for="category_id">Category</label>
<select id="category_id" name="category_id" class="form-control" required>
<option value="">Select a category</option>
{% for category in categories %}
<option value="{{ category.id }}">{{ category.name }}</option>
{% endfor %}
</select>
</div>
<div class="form-group">
<label for="status">Status</label>
<select id="status" name="status" class="form-control" required>
<option value="For Sale">For Sale</option>
<option value="On Hold">On Hold</option>
<option value="Sold">Sold</option>
</select>
</div>
<div class="form-group">
<label for="image">Item Image</label>
<input type="file" id="image" name="image" class="form-control">
<small>Optional. Accepted formats: JPG, PNG, GIF</small>
</div>
<button type="submit" class="btn btn-primary">Add Item</button>
<a href="{{ url_for('admin.items') }}" class="btn" style="margin-left: 0.5rem;">Cancel</a>
</form>
{% endblock %}

View File

@@ -0,0 +1,47 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{% block title %}Admin - Digital Garage Sale{% endblock %}</title>
<link rel="stylesheet" href="{{ url_for('static', filename='css/style.css') }}">
</head>
<body>
<header class="admin-header">
<div class="container">
<h1 class="admin-title">Digital Garage Sale Admin</h1>
{% if session.get('admin_authenticated') %}
<nav class="nav">
<ul class="nav-list">
<li class="nav-item"><a href="{{ url_for('main.index') }}">View Site</a></li>
<li class="nav-item"><a href="{{ url_for('admin.dashboard') }}">Dashboard</a></li>
<li class="nav-item"><a href="{{ url_for('admin.categories') }}">Categories</a></li>
<li class="nav-item"><a href="{{ url_for('admin.items') }}">Items</a></li>
<li class="nav-item"><a href="{{ url_for('admin.edit_contact') }}">Contact Info</a></li>
</ul>
</nav>
{% endif %}
</div>
</header>
<main class="container">
{% with messages = get_flashed_messages(with_categories=true) %}
{% if messages %}
{% for category, message in messages %}
<div class="alert alert-{{ category }}">
{{ message }}
</div>
{% endfor %}
{% endif %}
{% endwith %}
{% block content %}{% endblock %}
</main>
<footer class="site-footer">
<div class="container">
<p>&copy; 2025 Digital Garage Sale Admin</p>
</div>
</footer>
</body>
</html>

View File

@@ -0,0 +1,118 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Garage Sale Catalog</title>
<style>
body {
font-family: 'Times New Roman', serif;
line-height: 1.6;
margin: 0;
padding: 0;
color: #000;
}
.container {
width: 90%;
margin: 0 auto;
padding: 1rem;
}
h1, h2, h3 {
margin-top: 0;
}
.header {
text-align: center;
margin-bottom: 2rem;
border-bottom: 1px solid #000;
padding-bottom: 1rem;
}
.category {
margin-bottom: 2rem;
page-break-inside: avoid;
}
.category-title {
border-bottom: 1px solid #000;
padding-bottom: 0.5rem;
}
.items-grid {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 1rem;
}
.item {
border: 1px solid #000;
padding: 1rem;
margin-bottom: 1rem;
page-break-inside: avoid;
}
.item-title {
margin-top: 0;
margin-bottom: 0.5rem;
}
.item-price {
font-weight: bold;
margin-bottom: 0.5rem;
}
.item-status {
font-style: italic;
margin-bottom: 0.5rem;
}
.footer {
margin-top: 2rem;
text-align: center;
border-top: 1px solid #000;
padding-top: 1rem;
}
.page-break {
page-break-after: always;
}
</style>
</head>
<body>
<div class="container">
<div class="header">
<h1>Digital Garage Sale Catalog</h1>
<p>Printed on {{ now.strftime('%B %d, %Y') }}</p>
</div>
<div class="contact-info">
<h2>Contact Information</h2>
<p><strong>Email:</strong> {{ contact_info.email }}</p>
{% if contact_info.signal %}
<p><strong>Signal:</strong> {{ contact_info.signal }}</p>
{% endif %}
{% if contact_info.donation_link %}
<p><strong>Donations:</strong> {{ contact_info.donation_link }}</p>
{% endif %}
</div>
<div class="page-break"></div>
<h2>Items For Sale</h2>
{% for category in categories %}
<div class="category">
<h3 class="category-title">{{ category.name }}</h3>
<div class="items-grid">
{% for item in items if item.category_id == category.id %}
<div class="item">
<h4 class="item-title">{{ item.title }}</h4>
<p class="item-price">${{ "%.2f"|format(item.price) }}</p>
<p class="item-status">Status: {{ item.status }}</p>
<p>{{ item.description }}</p>
</div>
{% endfor %}
</div>
</div>
{% if not loop.last %}
<div class="page-break"></div>
{% endif %}
{% endfor %}
<div class="footer">
<p>All items are sold as-is. Please contact for more information.</p>
</div>
</div>
</body>
</html>

View File

@@ -0,0 +1,38 @@
{% extends "admin/base.html" %}
{% block title %}Manage Categories - Digital Garage Sale{% endblock %}
{% block content %}
<h2>Manage Categories</h2>
<a href="{{ url_for('admin.add_category') }}" class="btn btn-primary" style="margin-bottom: 1rem;">Add New Category</a>
<table style="width: 100%; border-collapse: collapse; margin-top: 1rem;">
<thead>
<tr>
<th style="border: 1px solid #ddd; padding: 0.5rem; text-align: left;">ID</th>
<th style="border: 1px solid #ddd; padding: 0.5rem; text-align: left;">Name</th>
<th style="border: 1px solid #ddd; padding: 0.5rem; text-align: left;">Items Count</th>
<th style="border: 1px solid #ddd; padding: 0.5rem; text-align: left;">Actions</th>
</tr>
</thead>
<tbody>
{% for category in categories %}
<tr>
<td style="border: 1px solid #ddd; padding: 0.5rem;">{{ category.id }}</td>
<td style="border: 1px solid #ddd; padding: 0.5rem;">{{ category.name }}</td>
<td style="border: 1px solid #ddd; padding: 0.5rem;">{{ category.items.count() }}</td>
<td style="border: 1px solid #ddd; padding: 0.5rem;">
<form method="post" action="{{ url_for('admin.delete_category', id=category.id) }}" style="display: inline;" onsubmit="return confirm('Are you sure you want to delete this category? All items in this category will also be deleted.');">
<button type="submit" class="btn btn-danger">Delete</button>
</form>
</td>
</tr>
{% else %}
<tr>
<td colspan="4" style="border: 1px solid #ddd; padding: 0.5rem; text-align: center;">No categories found</td>
</tr>
{% endfor %}
</tbody>
</table>
{% endblock %}

View File

@@ -0,0 +1,33 @@
{% extends "admin/base.html" %}
{% block title %}Admin Dashboard - Digital Garage Sale{% endblock %}
{% block content %}
<h2>Admin Dashboard</h2>
<div style="display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); gap: 1rem; margin-top: 2rem;">
<div style="border: 1px solid #ddd; padding: 1rem; text-align: center;">
<h3>Manage Categories</h3>
<p>Add, edit, or remove item categories</p>
<a href="{{ url_for('admin.categories') }}" class="btn btn-primary">Categories</a>
</div>
<div style="border: 1px solid #ddd; padding: 1rem; text-align: center;">
<h3>Manage Items</h3>
<p>Add, edit, or remove items for sale</p>
<a href="{{ url_for('admin.items') }}" class="btn btn-primary">Items</a>
</div>
<div style="border: 1px solid #ddd; padding: 1rem; text-align: center;">
<h3>Information</h3>
<p>Update information and contact details</p>
<a href="{{ url_for('admin.edit_contact') }}" class="btn btn-primary">Edit Information</a>
</div>
<div style="border: 1px solid #ddd; padding: 1rem; text-align: center;">
<h3>Generate Catalog</h3>
<p>Create a PDF catalog of all items</p>
<a href="{{ url_for('admin.generate_catalog') }}" class="btn btn-primary">Generate PDF</a>
</div>
</div>
{% endblock %}

View File

@@ -0,0 +1,35 @@
{% extends "admin/base.html" %}
{% block title %}Edit Information - Digital Garage Sale{% endblock %}
{% block content %}
<h2>Edit Information</h2>
<form method="post" action="{{ url_for('admin.edit_contact') }}">
<div class="form-group">
<label for="information">Information Text</label>
<textarea id="information" name="information" class="form-control" rows="6">{{ contact_info.information }}</textarea>
<small>Provide general information about your garage sale that will be displayed at the top of the page.</small>
</div>
<div class="form-group">
<label for="email">Email Address</label>
<input type="email" id="email" name="email" class="form-control" value="{{ contact_info.email }}" required>
</div>
<div class="form-group">
<label for="signal">Signal (Username or Phone Number)</label>
<input type="text" id="signal" name="signal" class="form-control" value="{{ contact_info.signal }}">
<small>Optional. Leave blank if you don't want to display Signal contact info.</small>
</div>
<div class="form-group">
<label for="donation_link">Donation Link</label>
<input type="url" id="donation_link" name="donation_link" class="form-control" value="{{ contact_info.donation_link }}">
<small>Optional. Full URL to your donation page.</small>
</div>
<button type="submit" class="btn btn-primary">Update Information</button>
<a href="{{ url_for('admin.dashboard') }}" class="btn" style="margin-left: 0.5rem;">Cancel</a>
</form>
{% endblock %}

View File

@@ -0,0 +1,56 @@
{% extends "admin/base.html" %}
{% block title %}Edit Item - Digital Garage Sale{% endblock %}
{% block content %}
<h2>Edit Item</h2>
<form method="post" action="{{ url_for('admin.edit_item', id=item.id) }}" enctype="multipart/form-data">
<div class="form-group">
<label for="title">Item Title</label>
<input type="text" id="title" name="title" class="form-control" value="{{ item.title }}" required>
</div>
<div class="form-group">
<label for="description">Description</label>
<textarea id="description" name="description" class="form-control" rows="4" required>{{ item.description }}</textarea>
</div>
<div class="form-group">
<label for="price">Price ($)</label>
<input type="number" id="price" name="price" class="form-control" step="0.01" min="0" value="{{ item.price }}" required>
</div>
<div class="form-group">
<label for="category_id">Category</label>
<select id="category_id" name="category_id" class="form-control" required>
{% for category in categories %}
<option value="{{ category.id }}" {% if category.id == item.category_id %}selected{% endif %}>{{ category.name }}</option>
{% endfor %}
</select>
</div>
<div class="form-group">
<label for="status">Status</label>
<select id="status" name="status" class="form-control" required>
<option value="For Sale" {% if item.status == 'For Sale' %}selected{% endif %}>For Sale</option>
<option value="On Hold" {% if item.status == 'On Hold' %}selected{% endif %}>On Hold</option>
<option value="Sold" {% if item.status == 'Sold' %}selected{% endif %}>Sold</option>
</select>
</div>
<div class="form-group">
{% if item.image_filename %}
<p>Current image:</p>
<img src="{{ url_for('static', filename='uploads/' + item.image_filename) }}" alt="{{ item.title }}" style="max-width: 200px; max-height: 200px; margin-bottom: 1rem;">
{% endif %}
<label for="image">Change Item Image</label>
<input type="file" id="image" name="image" class="form-control">
<small>Optional. Leave empty to keep current image. Accepted formats: JPG, PNG, GIF</small>
</div>
<button type="submit" class="btn btn-primary">Update Item</button>
<a href="{{ url_for('admin.items') }}" class="btn" style="margin-left: 0.5rem;">Cancel</a>
</form>
{% endblock %}

View File

@@ -0,0 +1,53 @@
{% extends "admin/base.html" %}
{% block title %}Manage Items - Digital Garage Sale{% endblock %}
{% block content %}
<h2>Manage Items</h2>
<a href="{{ url_for('admin.add_item') }}" class="btn btn-primary" style="margin-bottom: 1rem;">Add New Item</a>
<table style="width: 100%; border-collapse: collapse; margin-top: 1rem;">
<thead>
<tr>
<th style="border: 1px solid #ddd; padding: 0.5rem; text-align: left;">ID</th>
<th style="border: 1px solid #ddd; padding: 0.5rem; text-align: left;">Image</th>
<th style="border: 1px solid #ddd; padding: 0.5rem; text-align: left;">Title</th>
<th style="border: 1px solid #ddd; padding: 0.5rem; text-align: left;">Price</th>
<th style="border: 1px solid #ddd; padding: 0.5rem; text-align: left;">Category</th>
<th style="border: 1px solid #ddd; padding: 0.5rem; text-align: left;">Status</th>
<th style="border: 1px solid #ddd; padding: 0.5rem; text-align: left;">Actions</th>
</tr>
</thead>
<tbody>
{% for item in items %}
<tr>
<td style="border: 1px solid #ddd; padding: 0.5rem;">{{ item.id }}</td>
<td style="border: 1px solid #ddd; padding: 0.5rem;">
{% if item.image_filename %}
<img src="{{ url_for('static', filename='uploads/' + item.image_filename) }}" alt="{{ item.title }}" style="width: 50px; height: 50px; object-fit: cover;">
{% else %}
No Image
{% endif %}
</td>
<td style="border: 1px solid #ddd; padding: 0.5rem;">{{ item.title }}</td>
<td style="border: 1px solid #ddd; padding: 0.5rem;">${{ "%.2f"|format(item.price) }}</td>
<td style="border: 1px solid #ddd; padding: 0.5rem;">{{ item.category.name }}</td>
<td style="border: 1px solid #ddd; padding: 0.5rem;">
<span class="item-status status-{{ item.status|lower|replace(' ', '-') }}">{{ item.status }}</span>
</td>
<td style="border: 1px solid #ddd; padding: 0.5rem;">
<a href="{{ url_for('admin.edit_item', id=item.id) }}" class="btn">Edit</a>
<form method="post" action="{{ url_for('admin.delete_item', id=item.id) }}" style="display: inline;" onsubmit="return confirm('Are you sure you want to delete this item?');">
<button type="submit" class="btn btn-danger">Delete</button>
</form>
</td>
</tr>
{% else %}
<tr>
<td colspan="7" style="border: 1px solid #ddd; padding: 0.5rem; text-align: center;">No items found</td>
</tr>
{% endfor %}
</tbody>
</table>
{% endblock %}

View File

@@ -0,0 +1,21 @@
{% extends "admin/base.html" %}
{% block title %}Admin Login - Digital Garage Sale{% endblock %}
{% block content %}
<div style="max-width: 400px; margin: 0 auto;">
<h2>Admin Login</h2>
<form method="post" action="{{ url_for('admin.login') }}">
<div class="form-group">
<label for="password">Password</label>
<input type="password" id="password" name="password" class="form-control" required>
</div>
<button type="submit" class="btn btn-primary">Login</button>
</form>
<p style="margin-top: 20px;">
<a href="{{ url_for('main.index') }}">&larr; Back to site</a>
</p>
</div>
{% endblock %}

46
app/templates/base.html Normal file
View 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 %}Digital Garage Sale{% endblock %}</title>
<link rel="stylesheet" href="{{ url_for('static', filename='css/style.css') }}">
</head>
<body>
<header class="site-header">
<div class="container">
<h1 class="site-title">Hex's Garage Sale Catalog</h1>
<nav class="nav">
<ul class="nav-list">
<li class="nav-item"><a href="{{ url_for('main.index') }}">Home</a></li>
{% if session.get('admin_authenticated') %}
<li class="nav-item"><a href="{{ url_for('admin.dashboard') }}">Admin</a></li>
{% else %}
<li class="nav-item"><a href="{{ url_for('admin.login') }}">Admin Login</a></li>
{% endif %}
</ul>
</nav>
</div>
</header>
<main class="container">
{% with messages = get_flashed_messages(with_categories=true) %}
{% if messages %}
{% for category, message in messages %}
<div class="alert alert-{{ category }}">
{{ message }}
</div>
{% endfor %}
{% endif %}
{% endwith %}
{% block content %}{% endblock %}
</main>
<footer class="site-footer">
<div class="container">
<p>Uncopyrighted software, free for public use! <3</p>
</div>
</footer>
</body>
</html>

View File

@@ -0,0 +1,44 @@
{% extends "base.html" %}
{% block title %}{{ title }}{% endblock %}
{% block content %}
<section class="information-section">
<h2>Information</h2>
{% if contact_info.information %}
<p>{{ contact_info.information }}</p>
{% endif %}
<p><strong>Email:</strong> {{ contact_info.email }}</p>
{% if contact_info.signal %}
<p><strong>Signal:</strong> {{ contact_info.signal }}</p>
{% endif %}
{% if contact_info.donation_link %}
<p><strong>Donations:</strong> <a href="{{ contact_info.donation_link }}" target="_blank">Support us</a></p>
{% endif %}
</section>
<h2>{{ category.name }}</h2>
<p><a href="{{ url_for('main.index') }}">&larr; Back to all categories</a></p>
<div class="items-grid">
{% for item in items %}
<div class="item-card">
{% if item.image_filename %}
<img src="{{ url_for('static', filename='uploads/' + item.image_filename) }}" alt="{{ item.title }}" class="item-image">
{% else %}
<div class="item-image" style="background-color: #eee; display: flex; align-items: center; justify-content: center;">
<span>No Image</span>
</div>
{% endif %}
<h3 class="item-title">{{ item.title }}</h3>
<p class="item-price">${{ "%.2f"|format(item.price) }}</p>
<p class="item-status status-{{ item.status|lower|replace(' ', '-') }}">{{ item.status }}</p>
<p>{{ item.description|truncate(100) }}</p>
</div>
{% else %}
<p>No items in this category</p>
{% endfor %}
</div>
{% endblock %}

54
app/templates/index.html Normal file
View File

@@ -0,0 +1,54 @@
{% extends "base.html" %}
{% block title %}{{ title }}{% endblock %}
{% block content %}
<section class="information-section">
<h2>Information</h2>
{% if contact_info.information %}
<p>{{ contact_info.information }}</p>
{% endif %}
<p><strong>Email:</strong> {{ contact_info.email }}</p>
{% if contact_info.signal %}
<p><strong>Signal:</strong> {{ contact_info.signal }}</p>
{% endif %}
{% if contact_info.donation_link %}
<p><strong>Donations:</strong> <a href="{{ contact_info.donation_link }}" target="_blank">Support us</a></p>
{% endif %}
</section>
<section class="category-list">
<h2 class="category-title">Item Categories</h2>
<ul>
{% for category in categories %}
<li><a href="{{ url_for('main.category', id=category.id) }}">{{ category.name }}</a></li>
{% else %}
<li>No categories available</li>
{% endfor %}
</ul>
</section>
<h2>Items For Sale</h2>
<div class="items-grid">
{% for item in items %}
<div class="item-card">
{% if item.image_filename %}
<img src="{{ url_for('static', filename='uploads/' + item.image_filename) }}" alt="{{ item.title }}" class="item-image">
{% else %}
<div class="item-image" style="background-color: #eee; display: flex; align-items: center; justify-content: center;">
<span>No Image</span>
</div>
{% endif %}
<h3 class="item-title">{{ item.title }}</h3>
<p class="item-price">${{ "%.2f"|format(item.price) }}</p>
<p class="item-status status-{{ item.status|lower|replace(' ', '-') }}">{{ item.status }}</p>
<p>{{ item.description|truncate(100) }}</p>
<p>Category: {{ item.category.name }}</p>
</div>
{% else %}
<p>No items available</p>
{% endfor %}
</div>
{% endblock %}