Compare commits

..

4 Commits

Author SHA1 Message Date
chelsea
52cf5c0092 Standardize admin panel styling inconsistencies
- Added missing form classes to admin base template
- Standardized button styles across all admin templates
- Added modal styling with consistent spacing and colors
- Added form input, select, and label styling
- Added utility classes for add-source forms
- Removed duplicate CSS classes from individual templates
- Improved button hover states and disabled states

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-12 15:27:53 -05:00
chelsea
efabac7fd5 Fix community settings page 500 error
- Added comprehensive error handling for platform config loading
- Added validation for collection_targets structure
- Added defensive programming for community data processing
- Added logging for debugging community list building
- Prevents crashes when config files are missing or malformed

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-12 15:22:53 -05:00
chelsea
b438762758 Fix post detail page navigation issues
- Updated back button to use JavaScript function instead of direct href
- Added URL parameter preservation when navigating back to feed
- Improved fallback logic to handle browser history properly

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-12 15:16:38 -05:00
chelsea
301c2b33f0 Re-enable community filtering for logged-in users
Restores the user's community preference filtering that was temporarily
disabled to fix an urgent feed issue for logged-in users.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-12 15:14:44 -05:00
3 changed files with 235 additions and 46 deletions

67
app.py
View File

@@ -449,24 +449,23 @@ def api_posts():
continue continue
# Apply user's community preferences (before filterset) # Apply user's community preferences (before filterset)
# Temporarily disabled to fix urgent feed issue for logged in users if user_communities:
# if user_communities: post_source = post_data.get('source', '').lower()
# post_source = post_data.get('source', '').lower() post_platform = post_data.get('platform', '').lower()
# post_platform = post_data.get('platform', '').lower()
# # Check if this post matches any of the user's selected communities
# # Check if this post matches any of the user's selected communities matches_community = False
# matches_community = False for selected_community in user_communities:
# for selected_community in user_communities: selected_community = selected_community.lower()
# selected_community = selected_community.lower() # Match by exact source name or platform name
# # Match by exact source name or platform name if (post_source == selected_community or
# if (post_source == selected_community or post_platform == selected_community or
# post_platform == selected_community or selected_community in post_source):
# selected_community in post_source): matches_community = True
# matches_community = True break
# break
# if not matches_community:
# if not matches_community: continue
# continue
# Apply search filter (before filterset) # Apply search filter (before filterset)
if search_query: if search_query:
@@ -1400,17 +1399,38 @@ def settings_communities():
# Get available communities from platform config and collection targets # Get available communities from platform config and collection targets
available_communities = [] available_communities = []
# Load platform configuration # Load platform configuration with error handling
try:
platform_config = load_platform_config() platform_config = load_platform_config()
if not platform_config:
platform_config = {"platforms": {}, "collection_targets": []}
except Exception as e:
logger.error(f"Error loading platform config: {e}")
platform_config = {"platforms": {}, "collection_targets": []}
# Get enabled communities from collection_targets (what's actually being crawled) # Get enabled communities from collection_targets (what's actually being crawled)
enabled_communities = set() enabled_communities = set()
try:
for target in platform_config.get('collection_targets', []): for target in platform_config.get('collection_targets', []):
if 'platform' in target and 'community' in target:
enabled_communities.add((target['platform'], target['community'])) enabled_communities.add((target['platform'], target['community']))
except Exception as e:
logger.error(f"Error processing collection_targets: {e}")
# Build community list from platform config for communities that are enabled # Build community list from platform config for communities that are enabled
try:
for platform_name, platform_info in platform_config.get('platforms', {}).items(): for platform_name, platform_info in platform_config.get('platforms', {}).items():
for community_info in platform_info.get('communities', []): if not isinstance(platform_info, dict):
continue
communities = platform_info.get('communities', [])
if not isinstance(communities, list):
continue
for community_info in communities:
try:
if not isinstance(community_info, dict):
continue
# Only include communities that are in collection_targets # Only include communities that are in collection_targets
if (platform_name, community_info['id']) in enabled_communities: if (platform_name, community_info['id']) in enabled_communities:
available_communities.append({ available_communities.append({
@@ -1421,6 +1441,13 @@ def settings_communities():
'icon': community_info.get('icon', platform_info.get('icon', '📄')), 'icon': community_info.get('icon', platform_info.get('icon', '📄')),
'description': community_info.get('description', '') 'description': community_info.get('description', '')
}) })
except Exception as e:
logger.error(f"Error processing community {community_info}: {e}")
continue
except Exception as e:
logger.error(f"Error building community list: {e}")
logger.info(f"Found {len(available_communities)} available communities")
return render_template('settings_communities.html', return render_template('settings_communities.html',
user=current_user, user=current_user,

View File

@@ -84,7 +84,9 @@
} }
/* ===== BUTTONS ===== */ /* ===== BUTTONS ===== */
.btn { .btn,
.btn-primary,
.btn-secondary {
padding: 8px 16px; padding: 8px 16px;
border: none; border: none;
border-radius: 6px; border-radius: 6px;
@@ -94,25 +96,43 @@
transition: all 0.2s; transition: all 0.2s;
text-decoration: none; text-decoration: none;
display: inline-block; display: inline-block;
text-align: center;
border: 1px solid transparent;
} }
.btn-primary { .btn-primary {
background: var(--primary-color); background: var(--primary-color);
color: white; color: white;
border-color: var(--primary-color);
} }
.btn-primary:hover { .btn-primary:hover {
background: var(--primary-hover); background: var(--primary-hover);
border-color: var(--primary-hover);
transform: translateY(-1px);
} }
.btn-secondary { .btn-secondary {
background: var(--surface-elevation-1); background: var(--surface-elevation-1);
color: var(--text-primary); color: var(--text-primary);
border: 1px solid var(--divider-color); border-color: var(--divider-color);
} }
.btn-secondary:hover { .btn-secondary:hover {
background: var(--surface-elevation-2); background: var(--surface-elevation-2);
border-color: var(--divider-color);
transform: translateY(-1px);
}
.btn:disabled {
opacity: 0.6;
cursor: not-allowed;
transform: none !important;
}
.btn:disabled:hover {
background: var(--primary-color) !important;
border-color: var(--primary-color) !important;
} }
.action-btn { .action-btn {
@@ -331,20 +351,152 @@
color: var(--text-primary); color: var(--text-primary);
} }
.form-control { .form-control,
.form-input {
width: 100%; width: 100%;
padding: 8px 12px; padding: 8px 12px;
border: 1px solid var(--divider-color); border: 1px solid var(--divider-color);
border-radius: 6px; border-radius: 6px;
font-size: 0.9rem; font-size: 0.9rem;
transition: border-color 0.2s ease;
} }
.form-control:focus { .form-control:focus,
.form-input:focus {
outline: none; outline: none;
border-color: var(--primary-color); border-color: var(--primary-color);
box-shadow: 0 0 0 2px rgba(37, 99, 235, 0.1); box-shadow: 0 0 0 2px rgba(37, 99, 235, 0.1);
} }
.form-select {
width: 100%;
padding: 8px 12px;
border: 1px solid var(--divider-color);
border-radius: 6px;
font-size: 0.9rem;
background-color: var(--surface-color);
cursor: pointer;
transition: border-color 0.2s ease;
}
.form-select:focus {
outline: none;
border-color: var(--primary-color);
box-shadow: 0 0 0 2px rgba(37, 99, 235, 0.1);
}
.form-label {
display: block;
margin-bottom: 4px;
font-weight: 500;
color: var(--text-primary);
}
.help-text {
margin-top: 4px;
font-size: 0.85rem;
color: var(--text-secondary);
}
.add-source-form {
background: var(--surface-color);
border-radius: 12px;
padding: 24px;
margin-bottom: 24px;
border: 1px solid var(--divider-color);
}
.add-source-form h3 {
margin: 0 0 20px 0;
color: var(--text-primary);
font-size: 1.2rem;
}
/* ===== MODALS ===== */
.modal-overlay {
display: none;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.5);
z-index: 1000;
backdrop-filter: blur(2px);
}
.modal-overlay.active {
display: flex;
align-items: center;
justify-content: center;
}
.modal {
background: var(--surface-color);
border-radius: 12px;
padding: 24px;
max-width: 500px;
width: 90%;
box-shadow: 0 10px 40px rgba(0, 0, 0, 0.2);
border: 1px solid var(--divider-color);
max-height: 80vh;
overflow-y: auto;
}
.modal-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20px;
padding-bottom: 16px;
border-bottom: 1px solid var(--divider-color);
}
.modal-title {
font-size: 1.25rem;
font-weight: 600;
color: var(--text-primary);
margin: 0;
}
.modal-close {
background: none;
border: none;
font-size: 1.5rem;
cursor: pointer;
color: var(--text-secondary);
padding: 4px;
border-radius: 4px;
transition: all 0.2s ease;
}
.modal-close:hover {
background: var(--surface-elevation-1);
color: var(--text-primary);
}
.modal-body {
margin-bottom: 20px;
}
.modal-footer {
display: flex;
gap: 12px;
justify-content: flex-end;
padding-top: 16px;
border-top: 1px solid var(--divider-color);
}
.modal-alert {
background: #fff3cd;
border: 1px solid #ffeaa7;
border-radius: 8px;
padding: 12px;
margin-bottom: 16px;
color: #856404;
font-size: 0.9rem;
}
/* ===== UTILITIES ===== */ /* ===== UTILITIES ===== */
.back-link { .back-link {
display: inline-block; display: inline-block;

View File

@@ -9,7 +9,7 @@
<main class="main-content single-post"> <main class="main-content single-post">
<!-- Back Button --> <!-- Back Button -->
<div class="back-section"> <div class="back-section">
<a href="{{ url_for('index') }}" class="back-btn">← Back to Feed</a> <a href="#" onclick="goBackToFeed(event)" class="back-btn">← Back to Feed</a>
</div> </div>
<!-- Post Content --> <!-- Post Content -->
@@ -657,13 +657,23 @@
</style> </style>
<script> <script>
function goBackToFeed() { function goBackToFeed(event) {
event.preventDefault();
// Try to go back in browser history first // Try to go back in browser history first
if (window.history.length > 1 && document.referrer && document.referrer.includes(window.location.origin)) { if (window.history.length > 1 && document.referrer && document.referrer.includes(window.location.origin)) {
window.history.back(); window.history.back();
} else { } else {
// Fallback to dashboard - use the proper URL // Fallback to dashboard - construct URL with current query parameters
window.location.href = {{ url_for('index')|tojson }}; const urlParams = new URLSearchParams(window.location.search);
const baseUrl = {{ url_for('index')|tojson }};
// Add query parameters if they exist
if (urlParams.toString()) {
window.location.href = baseUrl + '?' + urlParams.toString();
} else {
window.location.href = baseUrl;
}
} }
} }