Improved UI
This commit is contained in:
@@ -10,6 +10,7 @@ A web application for sorting and organizing images using swipe gestures, simila
|
||||
- **NSFW Filtering**: Toggle to include/exclude NSFW images on both the main swiper and history pages
|
||||
- **NSFW Blur**: Optional blur for NSFW thumbnails on the history page with a toolbar toggle
|
||||
- **Orientation & Action Filters**: Filter results by orientation (portrait/landscape/square) and by action taken
|
||||
- **Image Sorting**: Choose to display images in random order (default), oldest first, or newest first
|
||||
- **Database Storage**: All selections are saved in a SQLite database
|
||||
- **Reset Functionality**: Option to clear all selections and start fresh
|
||||
|
||||
@@ -29,6 +30,10 @@ A web application for sorting and organizing images using swipe gestures, simila
|
||||
|
||||
1. Run the server: `python server.py`
|
||||
2. Open a web browser and navigate to `http://localhost:8000`
|
||||
|
||||
### Main Page Features
|
||||
- **Sort Order**: Use the dropdown in the sidebar to select image display order (Random, Oldest to Newest, or Newest to Oldest)
|
||||
- **Mobile View**: On smaller screens, action buttons appear directly below the swipe window for easy access
|
||||
3. Use the on-screen buttons or swipe gestures to categorize images:
|
||||
- Left: Discard
|
||||
- Right: Keep
|
||||
|
||||
12
handler.py
12
handler.py
@@ -157,6 +157,7 @@ class ImageSwipeHandler(BaseHTTPRequestHandler):
|
||||
search_keywords = [kw.strip() for kw in search_keywords_str.split(',') if kw.strip()]
|
||||
actions_str = query_params.get("actions", ["Unactioned"])[0]
|
||||
actions = [a.strip() for a in actions_str.split(',') if a.strip()]
|
||||
sort_order = query_params.get("sort", ["random"])[0] # Get sort order parameter
|
||||
|
||||
conn = sqlite3.connect(DB_PATH)
|
||||
conn.row_factory = sqlite3.Row # Important to access columns by name
|
||||
@@ -209,6 +210,12 @@ class ImageSwipeHandler(BaseHTTPRequestHandler):
|
||||
if where_clauses:
|
||||
query += " WHERE " + " AND ".join(where_clauses)
|
||||
|
||||
# Add sorting based on sort_order
|
||||
if sort_order == "oldest":
|
||||
query += " ORDER BY meta.creation_date ASC"
|
||||
elif sort_order == "newest":
|
||||
query += " ORDER BY meta.creation_date DESC"
|
||||
|
||||
cur.execute(query, params)
|
||||
rows = cur.fetchall()
|
||||
conn.close()
|
||||
@@ -217,7 +224,12 @@ class ImageSwipeHandler(BaseHTTPRequestHandler):
|
||||
self._json_response({"message": "No more images available for this filter."})
|
||||
return
|
||||
|
||||
# For random order, select a random row from the results
|
||||
if sort_order == "random":
|
||||
row = random.choice(rows)
|
||||
else:
|
||||
# For oldest/newest, use the first row in the sorted results
|
||||
row = rows[0]
|
||||
# Convert row to a dictionary for easier access
|
||||
row_dict = dict(row)
|
||||
|
||||
|
||||
11
index.html
11
index.html
@@ -36,6 +36,15 @@
|
||||
<div id="keyword-pills-container" class="keyword-pills-container"></div>
|
||||
</div>
|
||||
|
||||
<div class="sort-controls card">
|
||||
<label for="sort-order">Sort Order:</label>
|
||||
<select id="sort-order">
|
||||
<option value="random">Random (default)</option>
|
||||
<option value="oldest">Oldest to Newest</option>
|
||||
<option value="newest">Newest to Oldest</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="filter-controls card">
|
||||
|
||||
<div class="filter-buttons orientation-filters">
|
||||
@@ -68,11 +77,11 @@
|
||||
<button id="btn-down" class="action-btn" aria-label="Review">
|
||||
<img src="static/icons/review.svg" alt="Review" class="action">
|
||||
</button>
|
||||
</div>
|
||||
<!-- History button -->
|
||||
<a href="/history.html" id="btn-history" class="action-btn" aria-label="History">
|
||||
<img src="static/icons/history.svg" alt="History" class="action">
|
||||
</a>
|
||||
</div>
|
||||
<div class="status-area" aria-live="polite">
|
||||
|
||||
<p id="image-resolution">Resolution: Loading...</p>
|
||||
|
||||
10
js/main.js
10
js/main.js
@@ -8,6 +8,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
previousOrientation: ['all'],
|
||||
allowNsfw: false,
|
||||
searchKeywords: [],
|
||||
sortOrder: 'random', // Added sortOrder to state
|
||||
isLoading: false,
|
||||
isDragging: false,
|
||||
startX: 0,
|
||||
@@ -92,6 +93,9 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
params.append('actions', state.currentActions.join(','));
|
||||
}
|
||||
|
||||
// Add sort order parameter
|
||||
params.append('sort', state.sortOrder);
|
||||
|
||||
fetch(`/random-image?${params.toString()}`)
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
@@ -400,5 +404,11 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
loadNewImage();
|
||||
});
|
||||
|
||||
// Add event listener for sort order change
|
||||
document.getElementById('sort-order').addEventListener('change', (e) => {
|
||||
state.sortOrder = e.target.value;
|
||||
loadNewImage();
|
||||
});
|
||||
|
||||
loadNewImage(); // Always load an image on startup
|
||||
});
|
||||
|
||||
24
styles.css
24
styles.css
@@ -810,7 +810,7 @@ html, body {
|
||||
}
|
||||
}
|
||||
/* ---------------- MOBILE VIEW TWEAKS ---------------- */
|
||||
@media (max-width: 767px) {
|
||||
@media (max-width: 991px) {
|
||||
/* tighter spacing between panels */
|
||||
.side-panel {
|
||||
gap: 10px;
|
||||
@@ -824,17 +824,39 @@ html, body {
|
||||
.action-buttons {
|
||||
flex-direction: row;
|
||||
gap: 0;
|
||||
order: 1; /* First element in side panel */
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
.action-buttons .action-btn {
|
||||
flex: 1;
|
||||
min-width: 25%;
|
||||
border-radius: 0;
|
||||
padding: 16px 0;
|
||||
}
|
||||
/* Ensure all other elements come after action buttons */
|
||||
.search-controls,
|
||||
.sort-controls,
|
||||
.filter-controls,
|
||||
.status-area,
|
||||
#btn-history {
|
||||
order: 2;
|
||||
}
|
||||
/* minimal spacing between blocks */
|
||||
.side-panel > * + * {
|
||||
margin-top: 4px;
|
||||
border-top: 1px solid #ccc;
|
||||
}
|
||||
|
||||
/* Move action buttons below swipe window */
|
||||
.main-section {
|
||||
flex-direction: column;
|
||||
}
|
||||
.swipe-container {
|
||||
order: 1;
|
||||
}
|
||||
.side-panel {
|
||||
order: 2;
|
||||
}
|
||||
}
|
||||
/* ---------------- DESKTOP 2x2 ACTION GRID ---------------- */
|
||||
@media (min-width: 992px) {
|
||||
|
||||
Reference in New Issue
Block a user