Merge branch 'animations'

This commit is contained in:
Bryce
2025-08-12 23:03:16 -07:00
6 changed files with 127 additions and 4 deletions

View File

@@ -11,10 +11,33 @@ login_manager.login_view = 'auth.login'
login_manager.login_message = 'Please log in to access this page.'
login_manager.login_message_category = 'warning'
from flask import Flask, request, make_response
from flask_sqlalchemy import SQLAlchemy
from flask_login import LoginManager
from config import config
from app.models import db, Base, User
from flask_migrate import Migrate
# Initialize Flask-Login
login_manager = LoginManager()
login_manager.login_view = 'auth.login'
login_manager.login_message = 'Please log in to access this page.'
login_manager.login_message_category = 'warning'
def create_app(config_name='default'):
app = Flask(__name__, static_folder='static', static_url_path='/static')
app.config.from_object(config[config_name])
# Add middleware to simulate 500 errors
@app.before_request
def check_for_simulate_500():
# Check if the X-Simulate-500 header is present
if request.headers.get('X-Simulate-500'):
response = make_response({'error': 'Simulated server error'}, 500)
response.headers['Content-Type'] = 'application/json'
return response
# Initialize extensions
db.init_app(app)
migrate = Migrate(app, db)

View File

@@ -13,6 +13,37 @@
<script src="https://cdn.jsdelivr.net/npm/@ryangjchandler/alpine-tooltip@1.x.x/dist/cdn.min.js" defer></script>
<link rel="stylesheet" href="https://unpkg.com/tippy.js@6/dist/tippy.css" />
<script defer src="https://cdn.jsdelivr.net/npm/alpinejs@3.x.x/dist/cdn.min.js"></script>
<script>
document.addEventListener('alpine:init', () => {
Alpine.store('errorToast', {
show: false,
message: '',
hide() {
this.show = false;
},
handleError(detail) {
if (detail.xhr.status >= 500 && detail.xhr.status < 600) {
// Extract error message from response
let errorMessage = 'Server Error';
try {
const responseJson = JSON.parse(detail.xhr.response);
if (responseJson.error) {
errorMessage = responseJson.error;
}
} catch (e) {
// If not JSON, use the raw response
errorMessage = detail.xhr.response || 'Server Error';
}
// Set error message and show toast using Alpine store
this.message = errorMessage;
this.show = true;
}
}
});
});
</script>
<style>
@keyframes shake {
0%, 100% { transform: translateX(0); }
@@ -48,14 +79,33 @@
</style>
{% block head %}{% endblock %}
</head>
<body class="min-h-screen flex flex-col" x-data="{}" x-on:open-modal.window="$refs.modal.showModal()"
x-on:close-modal.window="$refs.modal.close()"
hx-ext="loading-states"
data-loading-delay="200">
<body
x-on:htmx:response-error.camel="$store.errorToast.handleError($event.detail)"
class="min-h-screen flex flex-col" x-data="{}" x-on:open-modal.window="$refs.modal.showModal()"
x-on:close-modal.window="$refs.modal.close()" hx-ext="loading-states" data-loading-delay="200">
{% block header %}{% endblock %}
{% block content %}{% endblock %}
{% block modal %}{% endblock %}
<!-- Toast for 5xx errors -->
<div id="error-toast" class="toast toast-top toast-end w-full z-100" x-show="$store.errorToast.show" x-transition.duration.200ms>
<div class="alert alert-warning backdrop-blur-md bg-error/30 border border-error/20 relative">
<span id="error-message" x-text="$store.errorToast.message"></span>
<button class="btn btn-sm btn-ghost absolute top-2 right-2" @click="$store.errorToast.hide()">
<i class="fas fa-times"></i>
</button>
</div>
</div>
<script>
// Check for global variable to set X-Simulate-500 header
document.addEventListener('htmx:configRequest', function (evt) {
if (typeof window.simulate500 === 'boolean' && window.simulate500) {
evt.detail.headers['X-Simulate-500'] = 'true';
}
});
</script>
</body>
</html>