Compare commits

...

3 Commits

Author SHA1 Message Date
5545328e53 Fix deploy.sh to also sync web_template to server
base.js and base.css were returning 404 because /var/www/html/web_template
did not exist on the server. Now rsyncs /root/code/web_template/ to
/var/www/html/web_template/ before deploying the app.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-17 23:36:55 -04:00
8bb43c14db Guard lt.* calls when base.js unavailable to prevent crash
Wraps all lt.keys.initDefaults() calls in `if (window.lt)` guards across
6 view files. Adds `if (!window.lt) return` bail-out in keyboard-shortcuts.js
and `if (window.lt)` guard in settings.js DOMContentLoaded handler.

This prevents TypeError crashes when /web_template/base.js returns 404,
which was causing the admin menu click delegation to never register.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-17 23:34:59 -04:00
92544d60ce Fix lt-modal-overlay not hidden without base.css
Add lt-modal-overlay, lt-modal, lt-btn fallback styles to dashboard.css
so modals are properly hidden (display:none) and styled even when
/web_template/base.css is not yet served. Mirrors the rules from base.css.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-17 23:29:20 -04:00
10 changed files with 110 additions and 8 deletions

View File

@@ -3458,6 +3458,100 @@ body.dark-mode select option {
box-shadow: var(--glow-green); box-shadow: var(--glow-green);
} }
/* lt-modal-overlay: hidden by default, shown via .show class (mirrors base.css rules) */
/* lt-btn: fallback styles when base.css is unavailable */
.lt-btn {
display: inline-flex;
align-items: center;
background: transparent;
color: var(--terminal-green);
border: 2px solid var(--terminal-green);
padding: 8px 16px;
cursor: pointer;
font-family: var(--font-mono);
font-size: 0.9rem;
font-weight: bold;
text-transform: uppercase;
letter-spacing: 0.05em;
text-decoration: none;
white-space: nowrap;
}
.lt-btn::before { content: '[ '; flex-shrink: 0; }
.lt-btn::after { content: ' ]'; flex-shrink: 0; }
.lt-btn-primary { color: var(--terminal-amber); border-color: var(--terminal-amber); }
.lt-btn-primary::before { content: '> '; }
.lt-btn-ghost { border-color: var(--border-color); color: var(--text-muted); }
.lt-btn-danger { color: var(--status-closed); border-color: var(--status-closed); }
.lt-select, .lt-input {
background: var(--bg-primary);
color: var(--terminal-green);
border: 1px solid var(--terminal-green);
font-family: var(--font-mono);
padding: 0.4rem 0.5rem;
width: 100%;
}
/* lt-modal-overlay: hidden by default, shown via .show class (mirrors base.css rules) */
.lt-modal-overlay {
position: fixed;
inset: 0;
background: rgba(0, 0, 0, 0.88);
z-index: var(--z-modal);
display: none;
align-items: center;
justify-content: center;
backdrop-filter: blur(2px);
}
.lt-modal-overlay.show {
display: flex;
}
.lt-modal {
position: relative;
background: var(--bg-secondary);
border: 3px double var(--terminal-green);
box-shadow: 0 0 30px rgba(0, 255, 65, 0.2), 0 8px 40px rgba(0, 0, 0, 0.8);
width: 560px;
max-width: 95vw;
max-height: 90vh;
overflow-y: auto;
}
.lt-modal-header {
display: flex;
align-items: center;
justify-content: space-between;
padding: 1rem 1.5rem;
border-bottom: 2px solid var(--terminal-green);
background: var(--bg-primary);
}
.lt-modal-title {
font-size: 0.9rem;
font-weight: bold;
color: var(--terminal-amber);
text-transform: uppercase;
letter-spacing: 0.08em;
}
.lt-modal-title::before { content: '>> '; color: var(--terminal-green); }
.lt-modal-close {
background: transparent;
border: 1px solid var(--border-color);
color: var(--text-muted);
cursor: pointer;
font-family: var(--font-mono);
font-size: 0.85rem;
padding: 2px 8px;
}
.lt-modal-close::before, .lt-modal-close::after { content: ''; }
.lt-modal-close:hover { color: var(--terminal-red); border-color: var(--terminal-red); }
.lt-modal-body { padding: 1.5rem; }
.lt-modal-footer {
display: flex;
gap: 0.5rem;
justify-content: flex-end;
padding: 1rem 1.5rem;
border-top: 1px solid var(--border-color);
background: var(--bg-primary);
}
/* Settings Modal Container - acts as backdrop */ /* Settings Modal Container - acts as backdrop */
.settings-modal { .settings-modal {
position: fixed; position: fixed;

View File

@@ -78,6 +78,8 @@ function showKeyboardHelp() {
} }
document.addEventListener('DOMContentLoaded', function() { document.addEventListener('DOMContentLoaded', function() {
if (!window.lt) return;
// Ctrl+E: Toggle edit mode (ticket pages) // Ctrl+E: Toggle edit mode (ticket pages)
lt.keys.on('ctrl+e', function() { lt.keys.on('ctrl+e', function() {
const editButton = document.getElementById('editButton'); const editButton = document.getElementById('editButton');

View File

@@ -131,4 +131,6 @@ document.addEventListener('keydown', (e) => {
}); });
// Initialize on page load // Initialize on page load
document.addEventListener('DOMContentLoaded', loadUserPreferences); document.addEventListener('DOMContentLoaded', function() {
if (window.lt) loadUserPreferences();
});

View File

@@ -3,13 +3,17 @@ set -e
echo "Deploying tinker_tickets to web server..." echo "Deploying tinker_tickets to web server..."
# Deploy web_template (shared UI framework)
echo "Syncing web_template to web server..."
rsync -avz --delete --exclude='.git' --exclude='node' --exclude='php' --exclude='python' --exclude='README.md' --exclude='Claude.md' /root/code/web_template/ root@10.10.10.45:/var/www/html/web_template/
# Deploy to web server # Deploy to web server
echo "Syncing to web server (10.10.10.45)..." echo "Syncing to web server (10.10.10.45)..."
rsync -avz --delete --exclude='.git' --exclude='deploy.sh' --exclude='.env' ./ root@10.10.10.45:/var/www/html/tinkertickets/ rsync -avz --delete --exclude='.git' --exclude='deploy.sh' --exclude='.env' ./ root@10.10.10.45:/var/www/html/tinkertickets/
# Set proper permissions on the web server # Set proper permissions on the web server
echo "Setting proper file permissions..." echo "Setting proper file permissions..."
ssh root@10.10.10.45 "chown -R www-data:www-data /var/www/html/tinkertickets && find /var/www/html/tinkertickets -type f -exec chmod 644 {} \; && find /var/www/html/tinkertickets -type d -exec chmod 755 {} \;" ssh root@10.10.10.45 "chown -R www-data:www-data /var/www/html/web_template /var/www/html/tinkertickets && find /var/www/html/web_template /var/www/html/tinkertickets -type f -exec chmod 644 {} \; && find /var/www/html/web_template /var/www/html/tinkertickets -type d -exec chmod 755 {} \;"
echo "Deployment to web server complete!" echo "Deployment to web server complete!"
echo "Don't forget to commit and push your changes via VS Code when ready." echo "Don't forget to commit and push your changes via VS Code when ready."

View File

@@ -854,7 +854,7 @@ $nonce = SecurityHeadersMiddleware::getNonce();
<script nonce="<?php echo $nonce; ?>" src="<?php echo $GLOBALS['config']['ASSETS_URL']; ?>/js/advanced-search.js"></script> <script nonce="<?php echo $nonce; ?>" src="<?php echo $GLOBALS['config']['ASSETS_URL']; ?>/js/advanced-search.js"></script>
<script nonce="<?php echo $nonce; ?>"> <script nonce="<?php echo $nonce; ?>">
// Initialize lt keyboard defaults (ESC closes modals, Ctrl+K focuses search, ? shows help) // Initialize lt keyboard defaults (ESC closes modals, Ctrl+K focuses search, ? shows help)
lt.keys.initDefaults(); if (window.lt) lt.keys.initDefaults();
// Event delegation for all data-action handlers // Event delegation for all data-action handlers
document.addEventListener('click', function(event) { document.addEventListener('click', function(event) {
const target = event.target.closest('[data-action]'); const target = event.target.closest('[data-action]');

View File

@@ -816,6 +816,6 @@ $nonce = SecurityHeadersMiddleware::getNonce();
<script nonce="<?php echo $nonce; ?>" src="<?php echo $GLOBALS['config']['ASSETS_URL']; ?>/js/keyboard-shortcuts.js"></script> <script nonce="<?php echo $nonce; ?>" src="<?php echo $GLOBALS['config']['ASSETS_URL']; ?>/js/keyboard-shortcuts.js"></script>
<script nonce="<?php echo $nonce; ?>" src="<?php echo $GLOBALS['config']['ASSETS_URL']; ?>/js/settings.js"></script> <script nonce="<?php echo $nonce; ?>" src="<?php echo $GLOBALS['config']['ASSETS_URL']; ?>/js/settings.js"></script>
<script nonce="<?php echo $nonce; ?>">lt.keys.initDefaults();</script> <script nonce="<?php echo $nonce; ?>">if (window.lt) lt.keys.initDefaults();</script>
</body> </body>
</html> </html>

View File

@@ -204,7 +204,7 @@ $nonce = SecurityHeadersMiddleware::getNonce();
saveField(e); saveField(e);
}); });
lt.keys.initDefaults(); if (window.lt) lt.keys.initDefaults();
function toggleOptionsField() { function toggleOptionsField() {
const type = document.getElementById('field_type').value; const type = document.getElementById('field_type').value;

View File

@@ -241,7 +241,7 @@ $nonce = SecurityHeadersMiddleware::getNonce();
saveRecurring(e); saveRecurring(e);
}); });
lt.keys.initDefaults(); if (window.lt) lt.keys.initDefaults();
function updateScheduleOptions() { function updateScheduleOptions() {
const type = document.getElementById('schedule_type').value; const type = document.getElementById('schedule_type').value;

View File

@@ -202,7 +202,7 @@ $nonce = SecurityHeadersMiddleware::getNonce();
saveTemplate(e); saveTemplate(e);
}); });
lt.keys.initDefaults(); if (window.lt) lt.keys.initDefaults();
function saveTemplate(e) { function saveTemplate(e) {
e.preventDefault(); e.preventDefault();

View File

@@ -219,7 +219,7 @@ $nonce = SecurityHeadersMiddleware::getNonce();
saveTransition(e); saveTransition(e);
}); });
lt.keys.initDefaults(); if (window.lt) lt.keys.initDefaults();
function saveTransition(e) { function saveTransition(e) {
e.preventDefault(); e.preventDefault();