admin
This commit is contained in:
224
app/templates/admin/dashboard.html
Normal file
224
app/templates/admin/dashboard.html
Normal file
@@ -0,0 +1,224 @@
|
||||
{% extends 'base.html' %}
|
||||
|
||||
{% block title %}Admin Dashboard - Game Tracker{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="admin-header">
|
||||
<div class="admin-title">
|
||||
<h1>Admin Dashboard</h1>
|
||||
<p class="subtitle">Manage tracked games</p>
|
||||
</div>
|
||||
<div class="admin-actions">
|
||||
<a href="{{ url_for('main.admin_search') }}" class="btn btn-primary">
|
||||
<i class="fas fa-search"></i> Search New Games
|
||||
</a>
|
||||
<a href="{{ url_for('main.admin_logout') }}" class="btn btn-secondary">
|
||||
<i class="fas fa-sign-out-alt"></i> Logout
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% if games %}
|
||||
<div class="admin-games">
|
||||
<h2>Currently Tracked Games</h2>
|
||||
<table class="admin-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Cover</th>
|
||||
<th>Game</th>
|
||||
<th>Status</th>
|
||||
<th>Progress</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for game in games %}
|
||||
<tr>
|
||||
<td class="game-cover-cell">
|
||||
{% if game.cover_url %}
|
||||
<img src="{{ game.cover_url }}" alt="{{ game.name }} cover">
|
||||
{% else %}
|
||||
<div class="no-cover-small">
|
||||
<i class="fas fa-gamepad"></i>
|
||||
</div>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
<strong>{{ game.name }}</strong>
|
||||
<div class="game-details-row">
|
||||
{% if game.developer %}
|
||||
<small><i class="fas fa-code"></i> {{ game.developer }}</small>
|
||||
{% endif %}
|
||||
{% if game.platform %}
|
||||
<small><i class="fas fa-desktop"></i> {{ game.platform }}</small>
|
||||
{% endif %}
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<span class="status-badge status-{{ game.status|lower|replace(' ', '-') }}">{{ game.status }}</span>
|
||||
</td>
|
||||
<td>
|
||||
<div class="progress-bar-small">
|
||||
<div class="progress-fill progress-{{ game.progress }}"></div>
|
||||
<span class="progress-text">{{ game.progress }}%</span>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<div class="action-buttons">
|
||||
<button class="btn btn-small btn-secondary edit-button" data-id="{{ game.id }}">
|
||||
<i class="fas fa-edit"></i> Edit
|
||||
</button>
|
||||
<button class="btn btn-small btn-danger delete-button" data-id="{{ game.id }}"
|
||||
data-name="{{ game.name }}">
|
||||
<i class="fas fa-trash"></i> Remove
|
||||
</button>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<!-- Edit form row -->
|
||||
<tr class="edit-row" id="edit-row-{{ game.id }}">
|
||||
<td colspan="5">
|
||||
<form action="{{ url_for('main.admin_update_game', game_id=game.id) }}" method="POST" class="admin-edit-form">
|
||||
<div class="form-group-row">
|
||||
<div class="form-group">
|
||||
<label for="status-{{ game.id }}">Status:</label>
|
||||
<select name="status" id="status-{{ game.id }}">
|
||||
<option value="Playing" {% if game.status == 'Playing' %}selected{% endif %}>Playing</option>
|
||||
<option value="Completed" {% if game.status == 'Completed' %}selected{% endif %}>Completed</option>
|
||||
<option value="On Hold" {% if game.status == 'On Hold' %}selected{% endif %}>On Hold</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="progress-{{ game.id }}">Progress:</label>
|
||||
<div class="progress-input">
|
||||
<input type="range" name="progress" id="progress-{{ game.id }}" min="0" max="100" value="{{ game.progress }}" class="progress-slider">
|
||||
<span class="range-value">{{ game.progress }}%</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="notes-{{ game.id }}">Notes:</label>
|
||||
<textarea name="notes" id="notes-{{ game.id }}" rows="2">{{ game.notes or '' }}</textarea>
|
||||
</div>
|
||||
|
||||
<div class="form-actions">
|
||||
<button type="submit" class="btn btn-primary">Update</button>
|
||||
<button type="button" class="btn btn-secondary cancel-edit">Cancel</button>
|
||||
</div>
|
||||
</form>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
{% else %}
|
||||
<div class="empty-state">
|
||||
<div class="empty-icon">
|
||||
<i class="fas fa-gamepad"></i>
|
||||
</div>
|
||||
<h2>No games being tracked yet</h2>
|
||||
<p>Use the button below to search and add games to track!</p>
|
||||
<a href="{{ url_for('main.admin_search') }}" class="btn btn-primary">
|
||||
<i class="fas fa-plus"></i> Add Your First Game
|
||||
</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<!-- Delete confirmation modal -->
|
||||
<div class="modal" id="delete-modal">
|
||||
<div class="modal-content">
|
||||
<h3>Remove Game</h3>
|
||||
<p>Are you sure you want to remove <strong id="delete-game-name"></strong> from the tracking list?</p>
|
||||
<div class="modal-actions">
|
||||
<button class="btn btn-secondary close-modal">Cancel</button>
|
||||
<form id="delete-form" method="POST">
|
||||
<button type="submit" class="btn btn-danger">Remove</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
// Range slider handling
|
||||
const sliders = document.querySelectorAll('.progress-slider');
|
||||
sliders.forEach(slider => {
|
||||
const valueDisplay = slider.nextElementSibling;
|
||||
|
||||
slider.addEventListener('input', function() {
|
||||
valueDisplay.textContent = this.value + '%';
|
||||
});
|
||||
});
|
||||
|
||||
// Edit row handling
|
||||
const editButtons = document.querySelectorAll('.edit-button');
|
||||
const editRows = document.querySelectorAll('.edit-row');
|
||||
const cancelButtons = document.querySelectorAll('.cancel-edit');
|
||||
|
||||
// Hide all edit rows initially
|
||||
editRows.forEach(row => {
|
||||
row.style.display = 'none';
|
||||
});
|
||||
|
||||
editButtons.forEach(btn => {
|
||||
btn.addEventListener('click', function() {
|
||||
const gameId = this.getAttribute('data-id');
|
||||
const editRow = document.getElementById(`edit-row-${gameId}`);
|
||||
|
||||
// Hide any other open edit rows
|
||||
editRows.forEach(row => {
|
||||
if (row.id !== `edit-row-${gameId}`) {
|
||||
row.style.display = 'none';
|
||||
}
|
||||
});
|
||||
|
||||
// Toggle the clicked row
|
||||
if (editRow.style.display === 'none' || !editRow.style.display) {
|
||||
editRow.style.display = 'table-row';
|
||||
} else {
|
||||
editRow.style.display = 'none';
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
cancelButtons.forEach(btn => {
|
||||
btn.addEventListener('click', function() {
|
||||
const editRow = this.closest('.edit-row');
|
||||
editRow.style.display = 'none';
|
||||
});
|
||||
});
|
||||
|
||||
// Delete modal handling
|
||||
const deleteModal = document.getElementById('delete-modal');
|
||||
const deleteButtons = document.querySelectorAll('.delete-button');
|
||||
const closeModalBtn = document.querySelector('.close-modal');
|
||||
const deleteForm = document.getElementById('delete-form');
|
||||
const deleteGameName = document.getElementById('delete-game-name');
|
||||
|
||||
deleteButtons.forEach(btn => {
|
||||
btn.addEventListener('click', function() {
|
||||
const gameId = this.getAttribute('data-id');
|
||||
const gameName = this.getAttribute('data-name');
|
||||
|
||||
deleteForm.action = `/admin/remove_game/${gameId}`;
|
||||
deleteGameName.textContent = gameName;
|
||||
deleteModal.classList.add('active');
|
||||
});
|
||||
});
|
||||
|
||||
closeModalBtn.addEventListener('click', function() {
|
||||
deleteModal.classList.remove('active');
|
||||
});
|
||||
|
||||
window.addEventListener('click', function(e) {
|
||||
if (e.target === deleteModal) {
|
||||
deleteModal.classList.remove('active');
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
35
app/templates/admin/login.html
Normal file
35
app/templates/admin/login.html
Normal file
@@ -0,0 +1,35 @@
|
||||
{% extends 'base.html' %}
|
||||
|
||||
{% block title %}Admin Login - Game Tracker{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="page-header">
|
||||
<h1>Admin Login</h1>
|
||||
{% if admin_exists %}
|
||||
<p class="subtitle">Enter your password to access the admin area</p>
|
||||
{% else %}
|
||||
<p class="subtitle">First time setup - Create an admin password</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<div class="login-container">
|
||||
<form class="login-form" method="POST">
|
||||
<div class="form-group">
|
||||
<label for="password">
|
||||
{% if admin_exists %}Password:{% else %}Create Password:{% endif %}
|
||||
</label>
|
||||
<input type="password" id="password" name="password" required>
|
||||
</div>
|
||||
|
||||
<button type="submit" class="btn btn-primary btn-wide">
|
||||
{% if admin_exists %}Login{% else %}Create Admin Account{% endif %}
|
||||
</button>
|
||||
</form>
|
||||
|
||||
<div class="login-footer">
|
||||
<a href="{{ url_for('main.index') }}" class="back-link">
|
||||
<i class="fas fa-arrow-left"></i> Back to Game Tracker
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
99
app/templates/admin/search.html
Normal file
99
app/templates/admin/search.html
Normal file
@@ -0,0 +1,99 @@
|
||||
{% extends 'base.html' %}
|
||||
|
||||
{% block title %}Admin Search - Game Tracker{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="admin-header">
|
||||
<div class="admin-title">
|
||||
<h1>Admin Game Search</h1>
|
||||
<p class="subtitle">Find games to add to the tracking list</p>
|
||||
</div>
|
||||
<div class="admin-actions">
|
||||
<a href="{{ url_for('main.admin_dashboard') }}" class="btn btn-secondary">
|
||||
<i class="fas fa-arrow-left"></i> Back to Dashboard
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="search-container">
|
||||
<form action="{{ url_for('main.admin_search') }}" method="POST" class="search-form">
|
||||
<div class="search-input">
|
||||
<input type="text" name="query" placeholder="Enter game name..." value="{{ query }}" required>
|
||||
<button type="submit" class="btn btn-primary">
|
||||
<i class="fas fa-search"></i> Search
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
{% if results %}
|
||||
<div class="results-info">
|
||||
<h2>Search Results</h2>
|
||||
<p>Found {{ results|length }} games matching "{{ query }}"</p>
|
||||
</div>
|
||||
|
||||
<div class="search-results">
|
||||
{% for game in results %}
|
||||
<div class="search-result-card">
|
||||
<div class="game-cover">
|
||||
{% if game.cover_url %}
|
||||
<img src="{{ game.cover_url }}" alt="{{ game.name }} cover">
|
||||
{% else %}
|
||||
<div class="no-cover">
|
||||
<i class="fas fa-gamepad"></i>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="game-info">
|
||||
<h3>{{ game.name }}</h3>
|
||||
|
||||
<div class="game-meta">
|
||||
{% if game.release_date %}
|
||||
<span><i class="fas fa-calendar-alt"></i> {{ game.release_date }}</span>
|
||||
{% endif %}
|
||||
|
||||
{% if game.platforms %}
|
||||
<span><i class="fas fa-desktop"></i>
|
||||
{% if game.platforms|length > 2 %}
|
||||
{{ game.platforms[0] }} + {{ game.platforms|length - 1 }} more
|
||||
{% else %}
|
||||
{{ game.platforms|join(', ') }}
|
||||
{% endif %}
|
||||
</span>
|
||||
{% endif %}
|
||||
|
||||
{% if game.developer %}
|
||||
<span><i class="fas fa-code"></i> {{ game.developer }}</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
{% if game.description %}
|
||||
<div class="game-description">
|
||||
<p>{{ game.description|truncate(150) }}</p>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<div class="search-actions">
|
||||
<form action="{{ url_for('main.admin_add_game', igdb_id=game.id) }}" method="POST">
|
||||
<button type="submit" class="btn btn-primary">
|
||||
<i class="fas fa-plus"></i> Add to Tracking List
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
{% elif query %}
|
||||
<div class="empty-search">
|
||||
<div class="empty-icon">
|
||||
<i class="fas fa-search"></i>
|
||||
</div>
|
||||
<h2>No games found</h2>
|
||||
<p>We couldn't find any games matching "{{ query }}"</p>
|
||||
<p>Try a different search term!</p>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% endblock %}
|
||||
Reference in New Issue
Block a user