From 8aa5c39ed8b0a9c6210f4fd2a9c7fc7e651662e3 Mon Sep 17 00:00:00 2001 From: Jared Vititoe Date: Tue, 6 Jan 2026 23:22:25 -0500 Subject: [PATCH] Implement complete ANSI art terminal redesign MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Transform entire UI into retro terminal aesthetic with ASCII/ANSI art: Visual Changes: - Add large ASCII art "TINKER TICKETS" banner with typewriter animation - Terminal black background (#0a0a0a) with matrix green text (#00ff41) - ASCII borders throughout using box-drawing characters (┌─┐│└─┘╔═╗║╚╝) - Monospace fonts (Courier New, Consolas, Monaco) everywhere - All rounded corners removed (border-radius: 0) - Text glow effects on important elements - Terminal prompts (>, $) and brackets ([]) on all UI elements Dashboard: - Table with ASCII corner decorations and terminal green borders - Headers with > prefix and amber glow - Priority badges: [P1] [P2] format with colored glows - Status badges: [OPEN] [CLOSED] with borders and glows - Search box with $ SEARCH prompt - All buttons in [ BRACKET ] format Ticket View: - Ticket container with double ASCII borders (╔╗╚╝) - Priority-colored corner characters - UUID display: [UUID: xxx] format - Comments section: ╔═══ COMMENTS ═══╗ header - Activity timeline with ASCII tree (├──, │, └──) - Tabs with [ ] brackets and ▼ active indicator Components: - Modals with ╔═══ TITLE ═══╗ headers and ASCII corners - Hamburger menu with MENU SYSTEM box decoration - Settings modal with terminal styling - All inputs with green borders and amber focus glow - Checkboxes with ✓ characters Technical: - New file: ascii-banner.js with banner artwork and typewriter renderer - Comprehensive responsive design (1024px, 768px, 480px breakpoints) - Mobile: simplified ASCII, hidden decorations, full-width menu - Print styles for clean black/white output - All functionality preserved, purely visual transformation Colors preserved: - Priority: P1=red, P2=orange, P3=blue, P4=green, P5=gray - Status: Open=green, In Progress=yellow, Closed=red - Accents: Terminal green, amber, cyan 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 --- assets/css/dashboard.css | 1074 ++++++++++++++++++++++++++++++++----- assets/css/ticket.css | 547 ++++++++++++++++--- assets/js/ascii-banner.js | 197 +++++++ views/DashboardView.php | 11 + 4 files changed, 1620 insertions(+), 209 deletions(-) create mode 100644 assets/js/ascii-banner.js diff --git a/assets/css/dashboard.css b/assets/css/dashboard.css index 8fc3391..471e47e 100644 --- a/assets/css/dashboard.css +++ b/assets/css/dashboard.css @@ -1,47 +1,75 @@ -/* ===== CSS VARIABLES ===== */ +/* ===== CSS VARIABLES - TERMINAL EDITION ===== */ :root { - --bg-primary: #f5f7fa; - --bg-secondary: #ffffff; - --text-primary: #2c3e50; - --text-secondary: #4a5568; - --border-color: #eee; - --shadow: 0 2px 4px rgba(0,0,0,0.1); - --hover-bg: #f8f9fa; + /* Terminal Dark Backgrounds */ + --bg-primary: #0a0a0a; + --bg-secondary: #1a1a1a; + --bg-tertiary: #2a2a2a; + + /* Terminal Colors */ + --terminal-green: #00ff41; + --terminal-amber: #ffb000; + --terminal-cyan: #00ffff; + --text-primary: #00ff41; + --text-secondary: #00cc33; + --text-muted: #008822; + + /* Border & UI */ + --border-color: #00ff41; + --shadow: none; + --hover-bg: rgba(0, 255, 65, 0.1); + --border-radius: 0; + + /* Priority Colors (Keep existing) */ --priority-1: #ff4d4d; --priority-2: #ffa726; --priority-3: #42a5f5; --priority-4: #66bb6a; --priority-5: #9e9e9e; - - /* Status Colors */ + + /* Status Colors (Keep existing) */ --status-open: #28a745; --status-in-progress: #ffc107; --status-closed: #dc3545; - + + /* Terminal Font Stack */ + --font-mono: 'Courier New', 'Consolas', 'Monaco', 'Menlo', monospace; + + /* Glow Effects */ + --glow-green: 0 0 5px #00ff41, 0 0 10px #00ff41; + --glow-red: 0 0 5px #ff4d4d, 0 0 10px #ff4d4d; + --glow-blue: 0 0 5px #42a5f5, 0 0 10px #42a5f5; + --glow-amber: 0 0 5px #ffb000, 0 0 10px #ffb000; + --glow-priority-1: 0 0 5px #ff4d4d, 0 0 10px #ff4d4d; + --glow-priority-2: 0 0 5px #ffa726, 0 0 10px #ffa726; + --glow-priority-3: 0 0 5px #42a5f5, 0 0 10px #42a5f5; + --glow-priority-4: 0 0 5px #66bb6a, 0 0 10px #66bb6a; + --glow-priority-5: 0 0 5px #9e9e9e, 0 0 10px #9e9e9e; + /* Spacing */ --spacing-xs: 0.5rem; --spacing-sm: 1rem; --spacing-md: 1.5rem; --spacing-lg: 2rem; - + /* Transitions */ --transition-default: all 0.3s ease; } -/* Dark theme */ +/* Dark theme (now same as light for terminal aesthetic) */ [data-theme="dark"] { - --bg-primary: #1a202c; - --bg-secondary: #2d3748; - --text-primary: #f7fafc; - --text-secondary: #e2e8f0; - --border-color: #4a5568; - --shadow: 0 2px 4px rgba(0,0,0,0.3); - --hover-bg: #374151; + --bg-primary: #0a0a0a; + --bg-secondary: #1a1a1a; + --bg-tertiary: #2a2a2a; + --text-primary: #00ff41; + --text-secondary: #00cc33; + --border-color: #00ff41; + --shadow: none; + --hover-bg: rgba(0, 255, 65, 0.1); } -/* ===== BASE ELEMENTS ===== */ +/* ===== BASE ELEMENTS - TERMINAL STYLE ===== */ body { - font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; + font-family: var(--font-mono); margin: 0; padding: var(--spacing-md); background-color: var(--bg-primary); @@ -58,6 +86,250 @@ h1 { margin: 0; } +/* ===== ASCII BORDER SYSTEM ===== */ +.ascii-box { + position: relative; + border: 2px solid var(--terminal-green); + border-radius: 0; + padding: 1rem; + background: var(--bg-secondary); + font-family: var(--font-mono); +} + +.ascii-box-heavy { + border: 3px double var(--terminal-green); +} + +.ascii-title { + position: relative; + padding: 0.5rem 1rem; + background: var(--bg-primary); + border-bottom: 2px solid var(--terminal-green); + font-family: var(--font-mono); + font-weight: bold; + color: var(--terminal-green); + text-shadow: var(--glow-green); +} + +.ascii-title::before { + content: '═══ '; +} + +.ascii-title::after { + content: ' ═══'; +} + +/* Priority-specific border colors */ +.ascii-box[data-priority="1"] { border-color: var(--priority-1); } +.ascii-box[data-priority="2"] { border-color: var(--priority-2); } +.ascii-box[data-priority="3"] { border-color: var(--priority-3); } +.ascii-box[data-priority="4"] { border-color: var(--priority-4); } +.ascii-box[data-priority="5"] { border-color: var(--priority-5); } + +/* ===== TERMINAL PROMPT STYLES ===== */ +.terminal-prompt::before { + content: '> '; + color: var(--terminal-green); + font-weight: bold; +} + +.terminal-command::before { + content: '$ '; + color: var(--terminal-amber); + font-weight: bold; +} + +.terminal-checkbox-checked::before { + content: '[✓] '; + color: var(--terminal-green); +} + +.terminal-checkbox-unchecked::before { + content: '[ ] '; + color: var(--text-secondary); +} + +.terminal-status-active::before { + content: '[●] '; + color: var(--status-open); +} + +.terminal-status-inactive::before { + content: '[○] '; + color: var(--text-secondary); +} + +/* ===== TEXT GLOW EFFECTS ===== */ +.glow-text { + text-shadow: var(--glow-green); +} + +.glow-priority-1 { text-shadow: var(--glow-priority-1); } +.glow-priority-2 { text-shadow: var(--glow-priority-2); } +.glow-priority-3 { text-shadow: var(--glow-priority-3); } +.glow-priority-4 { text-shadow: var(--glow-priority-4); } +.glow-priority-5 { text-shadow: var(--glow-priority-5); } + +.glow-status-open { + text-shadow: 0 0 5px var(--status-open), 0 0 10px var(--status-open); +} + +.glow-status-progress { + text-shadow: 0 0 5px var(--status-in-progress), 0 0 10px var(--status-in-progress); +} + +.glow-status-closed { + text-shadow: 0 0 5px var(--status-closed), 0 0 10px var(--status-closed); +} + +@keyframes pulse-glow { + 0%, 100% { + text-shadow: 0 0 5px currentColor, 0 0 10px currentColor; + } + 50% { + text-shadow: 0 0 10px currentColor, 0 0 20px currentColor, 0 0 30px currentColor; + } +} + +.pulse-glow { + animation: pulse-glow 2s ease-in-out infinite; +} + +/* ===== TYPEWRITER ANIMATION ===== */ +@keyframes typewriter { + from { width: 0; } + to { width: 100%; } +} + +@keyframes blink-caret { + from, to { border-color: transparent; } + 50% { border-color: var(--terminal-green); } +} + +.typewriter { + overflow: hidden; + white-space: nowrap; + border-right: 3px solid var(--terminal-green); + animation: + typewriter 2s steps(40, end), + blink-caret 0.75s step-end infinite; +} + +.typewriter-slow { animation-duration: 4s; } +.typewriter-fast { animation-duration: 1s; } + +.typewriter-multi-line { + overflow: hidden; + animation: reveal-lines 3s steps(20, end) forwards; +} + +@keyframes reveal-lines { + from { max-height: 0; } + to { max-height: 500px; } +} + +/* ===== LOADING STATES ===== */ +.loading-terminal { + display: inline-block; + font-family: var(--font-mono); + color: var(--terminal-green); +} + +.loading-terminal::after { + content: '...'; + animation: loading-dots 1.5s steps(4, end) infinite; +} + +@keyframes loading-dots { + 0%, 20% { content: '.'; } + 40% { content: '..'; } + 60%, 100% { content: '...'; } +} + +.spinner-terminal { + display: inline-block; + font-family: var(--font-mono); + color: var(--terminal-green); +} + +.spinner-terminal::before { content: '['; } +.spinner-terminal::after { + content: ']'; + animation: spinner-rotate 1s linear infinite; +} + +@keyframes spinner-rotate { + 0% { content: '|]'; } + 25% { content: '/]'; } + 50% { content: '─]'; } + 75% { content: '\\]'; } + 100% { content: '|]'; } +} + +/* ===== MESSAGE STYLES ===== */ +.error-message { + padding: 15px 20px; + background: rgba(255, 77, 77, 0.1); + border: 2px solid var(--priority-1); + border-radius: 0; + font-family: var(--font-mono); + color: var(--priority-1); + margin: 20px 0; +} + +.error-message::before { + content: '[!] ERROR: '; + font-weight: bold; +} + +.success-message { + padding: 15px 20px; + background: rgba(40, 167, 69, 0.1); + border: 2px solid var(--status-open); + border-radius: 0; + font-family: var(--font-mono); + color: var(--status-open); + margin: 20px 0; +} + +.success-message::before { + content: '[✓] SUCCESS: '; + font-weight: bold; +} + +.info-message { + padding: 15px 20px; + background: rgba(66, 165, 245, 0.1); + border: 2px solid var(--priority-3); + border-radius: 0; + font-family: var(--font-mono); + color: var(--priority-3); + margin: 20px 0; +} + +.info-message::before { + content: '[i] INFO: '; + font-weight: bold; +} + +/* ===== EMPTY STATES ===== */ +.empty-state { + text-align: center; + padding: 60px 20px; + font-family: var(--font-mono); + color: var(--terminal-green); +} + +.empty-state::before { + content: '\A╔════════════════════════════╗\A║ ║\A║ NO DATA FOUND ║\A║ ║\A╚════════════════════════════╝\A'; + white-space: pre; + display: block; + font-size: 0.9rem; + line-height: 1.2; + margin-bottom: 20px; + opacity: 0.7; +} + /* ===== LAYOUT COMPONENTS ===== */ .dashboard-header { display: flex; @@ -89,66 +361,151 @@ h1 { align-items: center; } -/* ===== BUTTON STYLES ===== */ -.btn-base { - padding: var(--spacing-sm) var(--spacing-md); - border-radius: 6px; - border: none; +/* ===== BUTTON STYLES - TERMINAL EDITION ===== */ +.btn, +.btn-base, +button { + font-family: var(--font-mono); + background: transparent; + color: var(--terminal-green); + border: 2px solid var(--terminal-green); + border-radius: 0; + padding: 10px 20px; cursor: pointer; - transition: var(--transition-default); + text-transform: uppercase; + font-weight: bold; + position: relative; + transition: all 0.3s ease; } -.btn-primary { - background: #3b82f6; - color: white; +.btn::before, +.btn-base::before, +button::before { + content: '[ '; } +.btn::after, +.btn-base::after, +button::after { + content: ' ]'; +} + +.btn:hover, +.btn-base:hover, +button:hover { + background: rgba(0, 255, 65, 0.1); + color: var(--terminal-amber); + border-color: var(--terminal-amber); + text-shadow: var(--glow-amber); + transform: translateY(-2px); +} + +.btn:active, +.btn-base:active, +button:active { + transform: translateY(0); + box-shadow: 0 0 20px rgba(0, 255, 65, 0.5); +} + +.btn-primary, .create-ticket { - background: #3b82f6; - color: white; + background: transparent; + color: var(--terminal-amber); + border: 2px solid var(--terminal-amber); padding: 0.625rem 1.25rem; - border-radius: 0.375rem; - border: none; + border-radius: 0; cursor: pointer; - font-weight: 500; - transition: background-color 0.3s ease; + font-weight: bold; + font-family: var(--font-mono); + text-transform: uppercase; + transition: all 0.3s ease; margin-right: 3.75rem; + text-shadow: var(--glow-amber); } +.btn-primary::before, +.create-ticket::before { + content: '[ '; +} + +.btn-primary::after, +.create-ticket::after { + content: ' ]'; +} + +.btn-primary:hover, .create-ticket:hover { - background: #2563eb; + background: rgba(255, 176, 0, 0.1); + color: var(--terminal-green); + border-color: var(--terminal-green); + text-shadow: var(--glow-green); + transform: translateY(-2px); } -/* ===== TABLE STYLES ===== */ +/* ===== TABLE STYLES - TERMINAL EDITION ===== */ table { width: 100%; - border-collapse: separate; - border-spacing: 0; + border-collapse: collapse; background: var(--bg-secondary); - border-radius: 12px; - box-shadow: var(--shadow); - overflow: hidden; + border: 2px solid var(--terminal-green); + border-radius: 0; + box-shadow: none; + font-family: var(--font-mono); + position: relative; +} + +/* ASCII corner decorations */ +table::before { + content: '┌'; + position: absolute; + top: -2px; + left: -2px; + font-size: 1.2rem; + color: var(--terminal-green); + line-height: 1; + z-index: 10; +} + +table::after { + content: '┐'; + position: absolute; + top: -2px; + right: -2px; + font-size: 1.2rem; + color: var(--terminal-green); + line-height: 1; + z-index: 10; } th, td { - padding: 16px; + padding: 12px 16px; text-align: left; - border-bottom: 1px solid var(--border-color); - color: var(--text-primary); + border: 1px solid var(--terminal-green); + color: var(--terminal-green); + font-family: var(--font-mono); } th { - background-color: var(--bg-secondary); - font-weight: 600; + background-color: var(--bg-primary); + font-weight: bold; text-transform: uppercase; - font-size: 0.9em; - letter-spacing: 0.05em; + font-size: 0.85em; + letter-spacing: 0.1em; position: relative; cursor: pointer; + color: var(--terminal-amber); + text-shadow: var(--glow-amber); +} + +/* Add terminal prompt to headers */ +th::before { + content: '> '; + color: var(--terminal-green); + margin-right: 4px; } tr:hover { - background-color: var(--hover-bg); + background-color: rgba(0, 255, 65, 0.05); } tbody tr td:first-child { @@ -162,71 +519,172 @@ tbody tr.priority-3 td:first-child { border-left-color: var(--priority-3); } tbody tr.priority-4 td:first-child { border-left-color: var(--priority-4); } tbody tr.priority-5 td:first-child { border-left-color: var(--priority-5); } -/* Priority number styling */ +/* Priority number styling - TERMINAL STYLE */ td:nth-child(2) { text-align: center; } td:nth-child(2) span { font-weight: bold; - font-family: 'Courier New', monospace; + font-family: var(--font-mono); padding: 4px 8px; - border-radius: 4px; + border-radius: 0; display: inline-block; - background: var(--hover-bg); + background: transparent; } -.priority-1 td:nth-child(2) { color: var(--priority-1); } -.priority-2 td:nth-child(2) { color: var(--priority-2); } -.priority-3 td:nth-child(2) { color: var(--priority-3); } -.priority-4 td:nth-child(2) { color: var(--priority-4); } -.priority-5 td:nth-child(2) { color: var(--priority-5); } +/* Add brackets to priority badges */ +td:nth-child(2) span::before { + content: '['; + color: var(--terminal-green); + margin-right: 2px; +} -/* ===== STATUS STYLES ===== */ +td:nth-child(2) span::after { + content: ']'; + color: var(--terminal-green); + margin-left: 2px; +} + +.priority-1 td:nth-child(2) { + color: var(--priority-1); + text-shadow: var(--glow-priority-1); +} +.priority-2 td:nth-child(2) { + color: var(--priority-2); + text-shadow: var(--glow-priority-2); +} +.priority-3 td:nth-child(2) { + color: var(--priority-3); + text-shadow: var(--glow-priority-3); +} +.priority-4 td:nth-child(2) { + color: var(--priority-4); + text-shadow: var(--glow-priority-4); +} +.priority-5 td:nth-child(2) { + color: var(--priority-5); + text-shadow: var(--glow-priority-5); +} + +/* ===== STATUS STYLES - TERMINAL EDITION ===== */ .status-Open { - background-color: var(--status-open) !important; - color: white !important; - padding: 4px 8px; - border-radius: 4px; + background-color: transparent !important; + color: var(--status-open) !important; + padding: 4px 12px; + border-radius: 0 !important; + border: 2px solid var(--status-open) !important; font-size: 0.875rem; font-weight: 500; + font-family: var(--font-mono); + text-shadow: 0 0 5px var(--status-open), 0 0 10px var(--status-open); +} + +.status-Open::before { + content: '['; + margin-right: 4px; +} + +.status-Open::after { + content: ']'; + margin-left: 4px; } .status-In-Progress { - background-color: var(--status-in-progress) !important; - color: #212529 !important; - padding: 4px 8px; - border-radius: 4px; + background-color: transparent !important; + color: var(--status-in-progress) !important; + padding: 4px 12px; + border-radius: 0 !important; + border: 2px solid var(--status-in-progress) !important; font-size: 0.875rem; font-weight: 500; min-width: 100px; - overflow: none; + font-family: var(--font-mono); + text-shadow: 0 0 5px var(--status-in-progress), 0 0 10px var(--status-in-progress); +} + +.status-In-Progress::before { + content: '['; + margin-right: 4px; +} + +.status-In-Progress::after { + content: ']'; + margin-left: 4px; } .status-Closed { - background-color: var(--status-closed) !important; - color: white !important; - padding: 4px 8px; - border-radius: 4px; + background-color: transparent !important; + color: var(--status-closed) !important; + padding: 4px 12px; + border-radius: 0 !important; + border: 2px solid var(--status-closed) !important; font-size: 0.875rem; font-weight: 500; + font-family: var(--font-mono); + text-shadow: 0 0 5px var(--status-closed), 0 0 10px var(--status-closed); +} + +.status-Closed::before { + content: '['; + margin-right: 4px; +} + +.status-Closed::after { + content: ']'; + margin-left: 4px; +} + +.status-Resolved { + background-color: transparent !important; + color: var(--status-open) !important; + padding: 4px 12px; + border-radius: 0 !important; + border: 2px solid var(--status-open) !important; + font-size: 0.875rem; + font-weight: 500; + font-family: var(--font-mono); + text-shadow: 0 0 5px var(--status-open), 0 0 10px var(--status-open); +} + +.status-Resolved::before { + content: '['; + margin-right: 4px; +} + +.status-Resolved::after { + content: ']'; + margin-left: 4px; +} + +/* ===== SEARCH AND FILTER STYLES - TERMINAL EDITION ===== */ +.search-box, +input[type="text"], +input[type="search"], +textarea, +select { + font-family: var(--font-mono); + background: var(--bg-primary); + color: var(--terminal-green); + border: 2px solid var(--terminal-green); + border-radius: 0; + padding: 8px 12px; + transition: all 0.3s ease; } -/* ===== SEARCH AND FILTER STYLES ===== */ .search-box { - padding: 0.5rem 0.75rem; - border: 1px solid var(--border-color); - border-radius: 0.375rem; - background: var(--bg-secondary); - color: var(--text-primary); margin-left: 1.25rem; width: 40%; } +input:focus, +textarea:focus, +select:focus, .search-box:focus { outline: none; - border-color: #3b82f6; - box-shadow: 0 0 0 2px rgba(59, 130, 246, 0.1); + border-color: var(--terminal-amber); + box-shadow: 0 0 10px rgba(255, 176, 0, 0.3); + text-shadow: var(--glow-green); } .search-container { @@ -241,14 +699,40 @@ td:nth-child(2) span { flex-wrap: wrap; } -.search-box { - flex: 1; - min-width: 300px; - padding: 10px 15px; - border: 2px solid #ddd; - border-radius: 5px; - font-size: 16px; - transition: border-color 0.3s; +/* Terminal prompt before search box */ +.search-form::before { + content: '$ SEARCH'; + font-family: var(--font-mono); + color: var(--terminal-amber); + font-weight: bold; + text-shadow: var(--glow-amber); +} + +/* Checkbox styling */ +input[type="checkbox"] { + appearance: none; + width: 18px; + height: 18px; + border: 2px solid var(--terminal-green); + background: var(--bg-primary); + position: relative; + cursor: pointer; + border-radius: 0; +} + +input[type="checkbox"]:checked::before { + content: '✓'; + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + color: var(--terminal-green); + font-size: 14px; + font-weight: bold; +} + +input[type="checkbox"]:checked { + background: rgba(0, 255, 65, 0.1); } .search-box:focus { @@ -355,7 +839,7 @@ td:nth-child(2) span { cursor: pointer; } -/* ===== HAMBURGER MENU STYLES ===== */ +/* ===== HAMBURGER MENU STYLES - TERMINAL EDITION ===== */ .hamburger-menu { position: absolute; top: 20px; @@ -367,42 +851,100 @@ td:nth-child(2) span { cursor: pointer; font-size: 24px; background: var(--bg-secondary); - padding: 10px; - border-radius: 4px; - box-shadow: var(--shadow); + padding: 12px; + border: 2px solid var(--terminal-green); + border-radius: 0; + box-shadow: none; + font-family: var(--font-mono); + color: var(--terminal-green); +} + +.hamburger-icon::before { + content: '['; + margin-right: 4px; +} + +.hamburger-icon::after { + content: ']'; + margin-left: 4px; } .hamburger-content { position: fixed; top: 0; - left: -250px; - width: 200px; + left: -300px; + width: 250px; height: 100%; - background: var(--bg-secondary); - box-shadow: 2px 0 5px rgba(0,0,0,0.1); + background: var(--bg-primary); + border-right: 3px double var(--terminal-green); transition: left 0.3s ease; - padding: 40px 20px 20px; + padding: 20px; overflow-y: auto; z-index: 99; + font-family: var(--font-mono); + box-shadow: 0 0 30px rgba(0, 255, 65, 0.3); +} + +/* ASCII decoration at top */ +.hamburger-content::before { + content: '╔═══════════════════╗\A║ MENU SYSTEM ║\A╚═══════════════════╝'; + white-space: pre; + display: block; + color: var(--terminal-green); + font-family: var(--font-mono); + font-size: 0.8rem; + margin-bottom: 20px; + line-height: 1.2; } .hamburger-content.open { left: 0; } +.hamburger-content h3 { + color: var(--terminal-amber); + text-shadow: var(--glow-amber); + font-family: var(--font-mono); + text-transform: uppercase; + margin-top: 20px; + margin-bottom: 10px; +} + +.hamburger-content h3::before { + content: '> '; + color: var(--terminal-green); +} + .close-hamburger { position: absolute; top: 10px; right: 10px; cursor: pointer; font-size: 24px; - background: var(--bg-secondary); + background: transparent; padding: 10px; - border-radius: 4px; - box-shadow: var(--shadow); + border: 2px solid var(--terminal-green); + border-radius: 0; + box-shadow: none; + color: var(--terminal-green); + font-family: var(--font-mono); } -/* Hamburger menu inline editing styles */ +.close-hamburger::before { + content: '['; +} + +.close-hamburger::after { + content: ']'; +} + +.close-hamburger:hover { + color: var(--priority-1); + border-color: var(--priority-1); + text-shadow: var(--glow-red); +} + +/* Hamburger menu inline editing styles - TERMINAL */ .ticket-info-editable { padding: 10px 0; } @@ -411,13 +953,18 @@ td:nth-child(2) span { display: flex; justify-content: space-between; align-items: center; - margin-bottom: 12px; + margin-bottom: 15px; position: relative; + padding: 10px; + border: 1px solid var(--terminal-green); + background: rgba(0, 255, 65, 0.03); } .editable-field label, .info-field label { flex: 0 0 auto; margin-right: 10px; + color: var(--terminal-green); + font-family: var(--font-mono); } .editable-value { @@ -427,12 +974,24 @@ td:nth-child(2) span { display: inline-block; cursor: pointer; padding: 4px 8px; - border-radius: 4px; - transition: background-color 0.2s; + border-radius: 0; + transition: all 0.2s; + color: var(--terminal-amber); +} + +.editable-value::before { + content: '[ '; + color: var(--terminal-green); +} + +.editable-value::after { + content: ' ]'; + color: var(--terminal-green); } .editable-value:hover { - background-color: var(--hover-bg) !important; + background-color: rgba(0, 255, 65, 0.1) !important; + text-shadow: var(--glow-amber); } .edit-dropdown { @@ -440,10 +999,10 @@ td:nth-child(2) span { top: 100%; right: 0; background: var(--bg-primary); - border: 1px solid var(--border-color); - border-radius: 4px; + border: 2px solid var(--terminal-green); + border-radius: 0; padding: 8px; - box-shadow: 0 2px 8px rgba(0,0,0,0.1); + box-shadow: 0 0 20px rgba(0, 255, 65, 0.3); z-index: 1000; min-width: 150px; } @@ -451,10 +1010,12 @@ td:nth-child(2) span { .field-select { width: 100%; padding: 4px 8px; - border: 1px solid var(--border-color); - border-radius: 4px; + border: 2px solid var(--terminal-green); + border-radius: 0; margin-bottom: 8px; background: var(--bg-primary); + color: var(--terminal-green); + font-family: var(--font-mono); color: var(--text-primary); } @@ -583,14 +1144,14 @@ th.sort-desc::after { opacity: 1; } -/* ===== SETTINGS MODAL STYLES ===== */ +/* ===== SETTINGS MODAL STYLES - TERMINAL EDITION ===== */ .settings-modal-backdrop { position: fixed; top: 0; left: 0; width: 100%; height: 100%; - background: rgba(0, 0, 0, 0.5); + background: rgba(0, 0, 0, 0.85); display: flex; justify-content: center; align-items: center; @@ -598,26 +1159,64 @@ th.sort-desc::after { } .settings-modal { - background: var(--bg-secondary); - border-radius: 12px; + background: var(--bg-primary); + border: 3px double var(--terminal-green); + border-radius: 0; width: 500px; max-width: 90%; - box-shadow: var(--shadow); - padding: 20px; + box-shadow: 0 0 30px rgba(0, 255, 65, 0.3); + padding: 0; + position: relative; + font-family: var(--font-mono); +} + +/* ASCII corners for modal */ +.settings-modal::before { + content: '╔'; + position: absolute; + top: -3px; + left: -3px; + font-size: 1.5rem; + color: var(--terminal-green); + line-height: 1; +} + +.settings-modal::after { + content: '╗'; + position: absolute; + top: -3px; + right: -3px; + font-size: 1.5rem; + color: var(--terminal-green); + line-height: 1; } .settings-modal-header { display: flex; justify-content: space-between; align-items: center; - border-bottom: 1px solid var(--border-color); - padding-bottom: 15px; - margin-bottom: 15px; + border-bottom: 2px solid var(--terminal-green); + padding: 15px 20px; + margin: 0; + background: var(--bg-secondary); } .settings-modal-header h2 { margin: 0; - color: var(--text-primary); + color: var(--terminal-amber); + text-shadow: var(--glow-amber); + font-family: var(--font-mono); + text-transform: uppercase; +} + +.settings-modal-header h2::before { + content: '═══ '; + color: var(--terminal-green); +} + +.settings-modal-header h2::after { + content: ' ═══'; + color: var(--terminal-green); } .close-modal { @@ -625,42 +1224,91 @@ th.sort-desc::after { border: none; font-size: 24px; cursor: pointer; - color: var(--text-secondary); + color: var(--terminal-green); + font-family: var(--font-mono); +} + +.close-modal::before { + content: '['; +} + +.close-modal::after { + content: ']'; +} + +.close-modal:hover { + color: var(--priority-1); + text-shadow: var(--glow-red); } .setting-group { margin-bottom: 15px; + padding: 0 20px; } .setting-group label { display: block; margin-bottom: 8px; - color: var(--text-primary); + color: var(--terminal-green); + font-family: var(--font-mono); +} + +.setting-group label::before { + content: '> '; + color: var(--terminal-amber); } .setting-group select { width: 100%; padding: 10px; - border: 1px solid var(--border-color); - border-radius: 6px; + border: 2px solid var(--terminal-green); + border-radius: 0; background: var(--bg-primary); - color: var(--text-primary); + color: var(--terminal-green); + font-family: var(--font-mono); } .settings-modal-footer { display: flex; justify-content: flex-end; gap: 10px; - border-top: 1px solid var(--border-color); - padding-top: 15px; + border-top: 2px solid var(--terminal-green); + padding: 15px 20px; + background: var(--bg-secondary); } .save-settings, .cancel-settings { padding: 10px 20px; - border-radius: 6px; - border: none; + border-radius: 0; + border: 2px solid var(--terminal-green); + background: transparent; + color: var(--terminal-green); cursor: pointer; - transition: background-color 0.3s ease; + transition: all 0.3s ease; + font-family: var(--font-mono); + font-weight: bold; + text-transform: uppercase; +} + +.save-settings::before, +.cancel-settings::before { + content: '[ '; +} + +.save-settings::after, +.cancel-settings::after { + content: ' ]'; +} + +.save-settings { + color: var(--terminal-amber); + border-color: var(--terminal-amber); +} + +.save-settings:hover, +.cancel-settings:hover { + background: rgba(0, 255, 65, 0.1); + text-shadow: var(--glow-green); } .save-settings { @@ -902,3 +1550,163 @@ body.dark-mode select option { background: #2d3748 !important; color: #e2e8f0 !important; } + +/* ===== RESPONSIVE DESIGN - TERMINAL EDITION ===== */ + +/* Tablet and smaller */ +@media (max-width: 1024px) { + /* Smaller ASCII banner */ + .ascii-banner { + font-size: 0.6rem !important; + } + + /* Reduce table padding */ + th, td { + padding: 8px 12px; + } + + /* Stack bulk actions */ + .bulk-actions-buttons { + flex-direction: column; + } +} + +/* Mobile */ +@media (max-width: 768px) { + /* Use compact ASCII banner */ + .ascii-banner { + font-size: 0.5rem !important; + } + + /* Hide decorative ASCII corners on small screens */ + table::before, + table::after, + .ticket-container::before, + .ticket-container::after, + .settings-modal::before, + .settings-modal::after { + display: none; + } + + /* Simplify borders */ + .ticket-header::before { + display: none; + } + + /* Full-width hamburger menu */ + .hamburger-content { + width: 100%; + left: -100%; + } + + .hamburger-content.open { + left: 0; + } + + /* Reduce padding everywhere */ + .ascii-box, + .terminal-form-group, + .comment, + .timeline-content { + padding: 10px; + } + + /* Smaller glow effects */ + .glow-text, + [class*="glow-"] { + text-shadow: 0 0 3px currentColor; + } + + /* Stack buttons vertically */ + .btn, + button { + width: 100%; + margin: 5px 0; + } + + /* Reduce font size slightly */ + body { + font-size: 14px; + } + + /* Smaller table text */ + th, td { + font-size: 0.85rem; + padding: 6px 8px; + } + + /* Hide some table columns on mobile */ + th:nth-child(n+6), + td:nth-child(n+6) { + display: none; + } +} + +/* Very small mobile */ +@media (max-width: 480px) { + /* Minimal ASCII banner */ + .ascii-banner { + font-size: 0.4rem !important; + } + + /* Remove all pseudo-element decorations */ + *::before, + *::after { + content: none !important; + } + + /* Re-enable essential pseudo-elements */ + .search-form::before { + content: '$ ' !important; + } + + /* Simplify modals */ + .settings-modal, + .modal-content { + width: 95%; + max-width: 95%; + } + + /* Reduce ticket container size */ + .ticket-container { + width: 95%; + min-width: unset; + margin: 20px auto; + } + + /* Stack tabs vertically */ + .ticket-tabs { + flex-direction: column; + } + + .tab-btn { + width: 100%; + margin-bottom: 5px; + } +} + +/* Print styles - terminal aesthetic */ +@media print { + body { + background: white; + color: black; + } + + .ascii-banner, + .theme-toggle, + .hamburger-menu, + .bulk-actions-toolbar { + display: none; + } + + table, + .ticket-container { + border-color: black; + } + + /* Remove glows for print */ + * { + text-shadow: none !important; + box-shadow: none !important; + } +} diff --git a/assets/css/ticket.css b/assets/css/ticket.css index f2e180b..2ba1e99 100644 --- a/assets/css/ticket.css +++ b/assets/css/ticket.css @@ -1,43 +1,115 @@ -/* ===== TICKET PAGE SPECIFIC STYLES ===== */ +/* ===== TICKET PAGE SPECIFIC STYLES - TERMINAL EDITION ===== */ -/* Status colors for ticket page */ -.status-Open, +/* Import terminal variables (should be loaded from dashboard.css globally) */ +/* This file uses the same CSS variables defined in dashboard.css */ + +/* Status colors for ticket page - TERMINAL STYLE */ +.status-Open, [id="statusDisplay"].status-Open { - background-color: var(--status-open) !important; - color: white !important; + background-color: transparent !important; + color: var(--status-open) !important; padding: 8px 16px; - border-radius: 6px; + border-radius: 0 !important; + border: 2px solid var(--status-open) !important; font-weight: 500; text-transform: uppercase; font-size: 0.9em; letter-spacing: 0.5px; + font-family: var(--font-mono); + text-shadow: 0 0 5px var(--status-open), 0 0 10px var(--status-open); +} + +.status-Open::before, +[id="statusDisplay"].status-Open::before { + content: '['; + margin-right: 4px; +} + +.status-Open::after, +[id="statusDisplay"].status-Open::after { + content: ']'; + margin-left: 4px; } .status-In-Progress, [id="statusDisplay"].status-In-Progress { - background-color: var(--status-in-progress) !important; - color: #212529 !important; + background-color: transparent !important; + color: var(--status-in-progress) !important; padding: 8px 16px; - border-radius: 6px; + border-radius: 0 !important; + border: 2px solid var(--status-in-progress) !important; font-weight: 500; text-transform: uppercase; font-size: 0.9em; letter-spacing: 0.5px; + font-family: var(--font-mono); + text-shadow: 0 0 5px var(--status-in-progress), 0 0 10px var(--status-in-progress); +} + +.status-In-Progress::before, +[id="statusDisplay"].status-In-Progress::before { + content: '['; + margin-right: 4px; +} + +.status-In-Progress::after, +[id="statusDisplay"].status-In-Progress::after { + content: ']'; + margin-left: 4px; } .status-Closed, [id="statusDisplay"].status-Closed { - background-color: var(--status-closed) !important; - color: white !important; + background-color: transparent !important; + color: var(--status-closed) !important; padding: 8px 16px; - border-radius: 6px; + border-radius: 0 !important; + border: 2px solid var(--status-closed) !important; font-weight: 500; text-transform: uppercase; font-size: 0.9em; letter-spacing: 0.5px; + font-family: var(--font-mono); + text-shadow: 0 0 5px var(--status-closed), 0 0 10px var(--status-closed); } -/* Base Layout Components */ +.status-Closed::before, +[id="statusDisplay"].status-Closed::before { + content: '['; + margin-right: 4px; +} + +.status-Closed::after, +[id="statusDisplay"].status-Closed::after { + content: ']'; + margin-left: 4px; +} + +.status-Resolved { + background-color: transparent !important; + color: var(--status-open) !important; + padding: 8px 16px; + border-radius: 0 !important; + border: 2px solid var(--status-open) !important; + font-weight: 500; + text-transform: uppercase; + font-size: 0.9em; + letter-spacing: 0.5px; + font-family: var(--font-mono); + text-shadow: 0 0 5px var(--status-open), 0 0 10px var(--status-open); +} + +.status-Resolved::before { + content: '['; + margin-right: 4px; +} + +.status-Resolved::after { + content: ']'; + margin-left: 4px; +} + +/* Base Layout Components - TERMINAL STYLE */ .ticket-container { width: 90%; height: auto !important; @@ -45,28 +117,101 @@ min-width: 800px; max-width: 1800px; margin: 40px auto; - padding: 20px; - background: var(--bg-secondary); - border-radius: 12px; - box-shadow: var(--shadow); - border-left: 6px solid; + padding: 0; + background: var(--bg-primary); + border: 3px double var(--terminal-green); + border-radius: 0; + box-shadow: none; transition: border-color 0.3s ease; + position: relative; + font-family: var(--font-mono); } -/* Priority border colors */ -[data-priority="1"] { border-color: var(--priority-1); } -[data-priority="2"] { border-color: var(--priority-2); } -[data-priority="3"] { border-color: var(--priority-3); } -[data-priority="4"] { border-color: var(--priority-4); } -[data-priority="5"] { border-color: var(--priority-5); } +/* ASCII corner decorations */ +.ticket-container::before { + content: '╔'; + position: absolute; + top: -3px; + left: -3px; + font-size: 1.5rem; + color: var(--terminal-green); + line-height: 1; + z-index: 10; +} -/* Header Components */ +.ticket-container::after { + content: '╗'; + position: absolute; + top: -3px; + right: -3px; + font-size: 1.5rem; + color: var(--terminal-green); + line-height: 1; + z-index: 10; +} + +/* Priority-based border colors */ +[data-priority="1"] { + border-color: var(--priority-1); +} +[data-priority="1"]::before, +[data-priority="1"]::after { + color: var(--priority-1); +} + +[data-priority="2"] { + border-color: var(--priority-2); +} +[data-priority="2"]::before, +[data-priority="2"]::after { + color: var(--priority-2); +} + +[data-priority="3"] { + border-color: var(--priority-3); +} +[data-priority="3"]::before, +[data-priority="3"]::after { + color: var(--priority-3); +} + +[data-priority="4"] { + border-color: var(--priority-4); +} +[data-priority="4"]::before, +[data-priority="4"]::after { + color: var(--priority-4); +} + +[data-priority="5"] { + border-color: var(--priority-5); +} +[data-priority="5"]::before, +[data-priority="5"]::after { + color: var(--priority-5); +} + +/* Header Components - TERMINAL STYLE */ .ticket-header { display: flex; flex-direction: column; margin-bottom: 30px; width: 100%; overflow-wrap: break-word; + padding: 20px; + border-bottom: 2px solid var(--terminal-green); + background: var(--bg-secondary); + position: relative; +} + +.ticket-header::before { + content: '═══════════════════════════════════════════════════════'; + display: block; + color: var(--terminal-green); + font-family: var(--font-mono); + font-size: 0.8rem; + margin-bottom: 10px; + opacity: 0.5; } .ticket-subheader { @@ -79,8 +224,9 @@ .ticket-details { margin-top: 30px; padding: 20px; - background: var(--bg-primary); - border-radius: 8px; + background: var(--bg-secondary); + border: 2px solid var(--terminal-green); + border-radius: 0; } .header-controls { @@ -90,8 +236,20 @@ } .ticket-id { - font-family: 'Courier New', monospace; + font-family: var(--font-mono); margin-right: 20px; + color: var(--terminal-amber); + text-shadow: var(--glow-amber); +} + +.ticket-id::before { + content: '[UUID: '; + color: var(--terminal-green); +} + +.ticket-id::after { + content: ']'; + color: var(--terminal-green); } .status-priority-group { @@ -103,23 +261,39 @@ .priority-indicator { padding: 4px 8px; - border-radius: 4px; + border: 2px solid; + border-radius: 0; font-weight: bold; + font-family: var(--font-mono); } -/* Title Input Styles */ +.priority-indicator::before { + content: '['; + margin-right: 2px; +} + +.priority-indicator::after { + content: ']'; + margin-left: 2px; +} + +/* Title Input Styles - TERMINAL */ .title-input { - font-size: 1em; + font-size: 1.2em; font-weight: bold; + font-family: var(--font-mono); width: 100%; - border: 2px solid transparent; - border-radius: 4px; - padding: 12px; - margin: -4px; + border: none; + border-bottom: 2px solid transparent; + border-radius: 0; + padding: 8px 0; + margin: 0; word-break: break-word; overflow-wrap: break-word; white-space: pre-wrap; display: block; + background: transparent; + color: var(--terminal-green); line-height: 1.4; min-height: fit-content; height: auto; @@ -220,12 +394,29 @@ textarea.editable { box-shadow: 0 2px 4px rgba(0,0,0,0.1); } -/* Comments Section */ +/* Comments Section - TERMINAL STYLE */ .comments-section { margin-top: 40px; - padding: 25px; + padding: 20px; background: var(--bg-secondary); - border-radius: 8px; + border: 2px solid var(--terminal-green); + border-radius: 0; +} + +.comments-section h2 { + font-family: var(--font-mono); + color: var(--terminal-amber); + text-shadow: var(--glow-amber); + text-transform: uppercase; + letter-spacing: 0.1em; +} + +.comments-section h2::before { + content: '╔═══ '; +} + +.comments-section h2::after { + content: ' ═══╗'; } .comment-form { @@ -234,41 +425,68 @@ textarea.editable { .comment-form textarea { width: calc(100% - 20px); - min-height: 80px; + min-height: 100px; margin-bottom: 10px; padding: 10px; - border-radius: 6px; - border: 1px solid var(--border-color); + border-radius: 0; + border: 2px solid var(--terminal-green); background: var(--bg-primary); - color: var(--text-primary); + color: var(--terminal-green); + font-family: var(--font-mono); +} + +.comment-form textarea::placeholder { + color: rgba(0, 255, 65, 0.5); } .comment { background: var(--bg-primary); - padding: 20px; - border-radius: 8px; - margin-bottom: 20px; - box-shadow: 0 2px 4px rgba(0,0,0,0.1); + padding: 15px; + border: 2px solid var(--terminal-green); + border-radius: 0; + margin-bottom: 15px; + position: relative; + box-shadow: none; } .comment-header { display: flex; justify-content: space-between; - margin-bottom: 8px; + margin-bottom: 10px; + padding-bottom: 8px; + border-bottom: 1px solid var(--terminal-green); + font-family: var(--font-mono); font-size: 0.9em; } .comment-user { font-weight: bold; - color: var(--text-primary); + color: var(--terminal-amber); +} + +.comment-user::before { + content: '> '; + color: var(--terminal-green); } .comment-date { - color: var(--text-secondary); + color: var(--terminal-cyan); + font-size: 0.85em; +} + +.comment-date::before { + content: '['; + color: var(--terminal-green); +} + +.comment-date::after { + content: ']'; + color: var(--terminal-green); } .comment-text { - color: var(--text-primary); + color: var(--terminal-green); + font-family: var(--font-mono); line-height: 1.6; word-wrap: break-word; margin: 0; @@ -295,37 +513,64 @@ textarea.editable { margin: 10px 0; } -/* Comment Tabs */ +/* Comment Tabs - TERMINAL STYLE */ .ticket-tabs { display: flex; - gap: 10px; + gap: 0; margin: 20px 0; + border-bottom: 2px solid var(--terminal-green); } .tab-btn { padding: 12px 24px; - border: 1px solid var(--border-color); - background: var(--bg-secondary); - border-radius: 6px; + border: 2px solid var(--terminal-green); + border-bottom: none; + background: var(--bg-primary); + border-radius: 0; cursor: pointer; - font-weight: 500; - font-size: 1.1em; + font-weight: bold; + font-size: 1em; + font-family: var(--font-mono); + color: var(--terminal-green); + transition: all 0.3s ease; + position: relative; + margin-right: -2px; transition: all 0.3s ease; } +.tab-btn::before { + content: '[ '; + color: var(--terminal-green); +} + +.tab-btn::after { + content: ' ]'; + color: var(--terminal-green); +} + .tab-btn:hover { - transform: translateY(-2px); - box-shadow: 0 2px 4px rgba(0,0,0,0.1); + background: rgba(0, 255, 65, 0.05); + color: var(--terminal-amber); } .tab-btn.active { - background: #3b82f6; - color: white; - border-color: #3b82f6; + background: var(--bg-secondary); + color: var(--terminal-amber); + border-color: var(--terminal-amber); + text-shadow: var(--glow-amber); + z-index: 1; +} + +.tab-btn.active::after { + content: ' ▼ ]'; } .tab-content { display: none; + padding: 20px; + border: 2px solid var(--terminal-green); + border-top: none; + background: var(--bg-secondary); } .tab-content.active { @@ -443,10 +688,11 @@ input:checked + .slider:before { background: var(--border-color); } -/* Activity Timeline Styles */ +/* Activity Timeline Styles - ASCII TREE */ .timeline-container { padding: 1rem; max-width: 800px; + font-family: var(--font-mono); } .timeline-event { @@ -456,32 +702,61 @@ input:checked + .slider:before { position: relative; } +/* ASCII tree connector */ .timeline-event:not(:last-child)::before { - content: ''; + content: '│'; position: absolute; left: 12px; top: 30px; bottom: -24px; - width: 2px; - background: var(--border-color, #ddd); + color: var(--terminal-green); + font-family: var(--font-mono); + font-size: 1.2rem; + line-height: 1.5rem; +} + +/* Branch connector */ +.timeline-event::after { + content: '├──'; + position: absolute; + left: 0; + top: 12px; + color: var(--terminal-green); + font-family: var(--font-mono); +} + +.timeline-event:last-child::after { + content: '└──'; } .timeline-icon { - font-size: 1.5rem; + font-size: 1.2rem; flex-shrink: 0; width: 24px; height: 24px; display: flex; align-items: center; justify-content: center; + margin-left: 30px; } .timeline-content { flex: 1; - background: var(--card-bg, #f8f9fa); - padding: 0.75rem 1rem; - border-radius: 8px; - border: 1px solid var(--border-color, #ddd); + background: var(--bg-primary); + padding: 12px 16px; + border: 2px solid var(--terminal-green); + border-radius: 0; + position: relative; +} + +/* Terminal box corner */ +.timeline-content::before { + content: '┌─'; + position: absolute; + top: -2px; + left: -2px; + color: var(--terminal-green); + font-family: var(--font-mono); } .timeline-header { @@ -489,25 +764,40 @@ input:checked + .slider:before { gap: 0.5rem; align-items: center; margin-bottom: 0.5rem; - flex-wrap: wrap; + font-family: var(--font-mono); +} + +.timeline-header strong { + color: var(--terminal-amber); +} + +.timeline-header strong::before { + content: '['; + color: var(--terminal-green); +} + +.timeline-header strong::after { + content: ']'; + color: var(--terminal-green); } .timeline-action { - color: var(--text-muted, #666); + color: var(--terminal-green); font-size: 0.9rem; } .timeline-date { margin-left: auto; - color: var(--text-muted, #999); + color: var(--terminal-cyan); font-size: 0.85rem; } .timeline-details { font-size: 0.9rem; - color: var(--text-secondary, #555); + color: var(--terminal-green); padding-top: 0.5rem; - border-top: 1px solid var(--border-color, #eee); + border-top: 1px solid var(--terminal-green); + font-family: var(--font-mono); } body.dark-mode .timeline-content { @@ -676,3 +966,108 @@ body.dark-mode .editable { color: #e2e8f0 !important; border-color: #4a5568 !important; } + +/* ===== RESPONSIVE DESIGN - TERMINAL EDITION ===== */ + +/* Tablet and smaller */ +@media (max-width: 1024px) { + .ticket-container { + width: 95%; + min-width: 600px; + } + + /* Reduce timeline spacing */ + .timeline-event { + margin-bottom: 1rem; + } +} + +/* Mobile */ +@media (max-width: 768px) { + .ticket-container { + width: 98%; + min-width: unset; + margin: 20px auto; + padding: 0; + } + + /* Hide ASCII corner decorations on mobile */ + .ticket-container::before, + .ticket-container::after { + display: none; + } + + /* Simplify ticket header */ + .ticket-header::before { + display: none; + } + + .ticket-header { + padding: 15px; + } + + /* Stack header controls */ + .header-controls { + flex-direction: column; + align-items: flex-start; + } + + /* Reduce comment padding */ + .comment { + padding: 10px; + } + + /* Simplify timeline on mobile */ + .timeline-icon { + margin-left: 20px; + } + + .timeline-event::after { + font-size: 0.9rem; + } + + /* Smaller tabs */ + .tab-btn { + padding: 8px 16px; + font-size: 0.9em; + } + + /* Reduce glow effects */ + .glow-text, + [class*="glow-"] { + text-shadow: 0 0 3px currentColor; + } +} + +/* Very small mobile */ +@media (max-width: 480px) { + .ticket-container { + width: 100%; + margin: 10px 0; + } + + /* Remove timeline connectors on very small screens */ + .timeline-event::before, + .timeline-event::after { + display: none; + } + + .timeline-content::before { + display: none; + } + + .timeline-icon { + margin-left: 0; + } + + /* Stack tabs vertically */ + .ticket-tabs { + flex-direction: column; + } + + .tab-btn { + width: 100%; + border: 2px solid var(--terminal-green); + margin-bottom: 5px; + } +} diff --git a/assets/js/ascii-banner.js b/assets/js/ascii-banner.js new file mode 100644 index 0000000..316af59 --- /dev/null +++ b/assets/js/ascii-banner.js @@ -0,0 +1,197 @@ +/** + * ASCII Art Banners for Tinker Tickets - Terminal Edition + * + * This file contains ASCII art banners and rendering functions + * for the retro terminal aesthetic redesign. + */ + +// ASCII Art Banner Definitions +const ASCII_BANNERS = { + // Main large banner for desktop + main: ` +╔══════════════════════════════════════════════════════════════════════════╗ +║ ║ +║ ████████╗██╗███╗ ██╗██╗ ██╗███████╗██████╗ ║ +║ ╚══██╔══╝██║████╗ ██║██║ ██╔╝██╔════╝██╔══██╗ ║ +║ ██║ ██║██╔██╗ ██║█████╔╝ █████╗ ██████╔╝ ║ +║ ██║ ██║██║╚██╗██║██╔═██╗ ██╔══╝ ██╔══██╗ ║ +║ ██║ ██║██║ ╚████║██║ ██╗███████╗██║ ██║ ║ +║ ╚═╝ ╚═╝╚═╝ ╚═══╝╚═╝ ╚═╝╚══════╝╚═╝ ╚═╝ ║ +║ ║ +║ ████████╗██╗ ██████╗██╗ ██╗███████╗████████╗███████╗ ║ +║ ╚══██╔══╝██║██╔════╝██║ ██╔╝██╔════╝╚══██╔══╝██╔════╝ ║ +║ ██║ ██║██║ █████╔╝ █████╗ ██║ ███████╗ ║ +║ ██║ ██║██║ ██╔═██╗ ██╔══╝ ██║ ╚════██║ ║ +║ ██║ ██║╚██████╗██║ ██╗███████╗ ██║ ███████║ ║ +║ ╚═╝ ╚═╝ ╚═════╝╚═╝ ╚═╝╚══════╝ ╚═╝ ╚══════╝ ║ +║ ║ +║ >> RETRO TERMINAL TICKETING SYSTEM v1.0 << ║ +║ ║ +╚══════════════════════════════════════════════════════════════════════════╝ +`, + + // Compact version for smaller screens + compact: ` +┌──────────────────────────────────────────────────────────┐ +│ ▀█▀ █ █▄ █ █▄▀ █▀▀ █▀█ ▀█▀ █ █▀▀ █▄▀ █▀▀ ▀█▀ █▀ │ +│ █ █ █ ▀█ █ █ ██▄ █▀▄ █ █ █▄▄ █ █ ██▄ █ ▄█ │ +│ Terminal Ticketing System v1.0 │ +└──────────────────────────────────────────────────────────┘ +`, + + // Minimal version for mobile + minimal: ` + ╔════════════════════════════╗ + ║ TINKER TICKETS v1.0 ║ + ╚════════════════════════════╝ +` +}; + +/** + * Renders ASCII banner with optional typewriter effect + * + * @param {string} bannerId - ID of banner to render ('main', 'compact', or 'minimal') + * @param {string} containerSelector - CSS selector for container element + * @param {number} speed - Speed of typewriter effect in milliseconds (0 = instant) + * @param {boolean} addGlow - Whether to add text glow effect + */ +function renderASCIIBanner(bannerId, containerSelector, speed = 5, addGlow = true) { + const banner = ASCII_BANNERS[bannerId]; + const container = document.querySelector(containerSelector); + + if (!container || !banner) { + console.error('ASCII Banner: Container or banner not found', { bannerId, containerSelector }); + return; + } + + // Create pre element for ASCII art + const pre = document.createElement('pre'); + pre.className = 'ascii-banner'; + pre.style.margin = '0'; + pre.style.fontFamily = 'var(--font-mono)'; + pre.style.color = 'var(--terminal-green)'; + + if (addGlow) { + pre.style.textShadow = 'var(--glow-green)'; + } + + pre.style.fontSize = getBannerFontSize(bannerId); + pre.style.lineHeight = '1.2'; + pre.style.whiteSpace = 'pre'; + pre.style.overflow = 'visible'; + pre.style.textAlign = 'center'; + + container.appendChild(pre); + + // Instant render or typewriter effect + if (speed === 0) { + pre.textContent = banner; + } else { + renderWithTypewriter(pre, banner, speed); + } +} + +/** + * Get appropriate font size for banner type + * + * @param {string} bannerId - Banner ID + * @returns {string} - CSS font size + */ +function getBannerFontSize(bannerId) { + const width = window.innerWidth; + + if (bannerId === 'main') { + if (width < 768) return '0.4rem'; + if (width < 1024) return '0.6rem'; + return '0.8rem'; + } else if (bannerId === 'compact') { + if (width < 768) return '0.6rem'; + return '0.8rem'; + } else { + return '0.8rem'; + } +} + +/** + * Renders text with typewriter effect + * + * @param {HTMLElement} element - Element to render into + * @param {string} text - Text to render + * @param {number} speed - Speed in milliseconds per character + */ +function renderWithTypewriter(element, text, speed) { + let index = 0; + + const typeInterval = setInterval(() => { + element.textContent = text.substring(0, index); + index++; + + if (index > text.length) { + clearInterval(typeInterval); + // Trigger completion event + const event = new CustomEvent('bannerComplete'); + element.dispatchEvent(event); + } + }, speed); +} + +/** + * Renders responsive banner based on screen size + * + * @param {string} containerSelector - CSS selector for container + * @param {number} speed - Typewriter speed (0 = instant) + */ +function renderResponsiveBanner(containerSelector, speed = 5) { + const width = window.innerWidth; + + let bannerId; + if (width < 480) { + bannerId = 'minimal'; + } else if (width < 1024) { + bannerId = 'compact'; + } else { + bannerId = 'main'; + } + + renderASCIIBanner(bannerId, containerSelector, speed, true); +} + +/** + * Animated welcome sequence + * Shows banner followed by a blinking cursor effect + * + * @param {string} containerSelector - CSS selector for container + */ +function animatedWelcome(containerSelector) { + const container = document.querySelector(containerSelector); + + if (!container) return; + + // Clear container + container.innerHTML = ''; + + // Render banner + renderResponsiveBanner(containerSelector, 3); + + // Add blinking cursor after banner + const banner = container.querySelector('.ascii-banner'); + if (banner) { + banner.addEventListener('bannerComplete', () => { + const cursor = document.createElement('span'); + cursor.textContent = '█'; + cursor.style.animation = 'blink-caret 0.75s step-end infinite'; + cursor.style.marginLeft = '5px'; + banner.appendChild(cursor); + }); + } +} + +// Export functions for use in other scripts +if (typeof module !== 'undefined' && module.exports) { + module.exports = { + ASCII_BANNERS, + renderASCIIBanner, + renderResponsiveBanner, + animatedWelcome + }; +} diff --git a/views/DashboardView.php b/views/DashboardView.php index 528deb0..79a47e4 100644 --- a/views/DashboardView.php +++ b/views/DashboardView.php @@ -10,6 +10,7 @@ Ticket Dashboard + @@ -90,6 +91,16 @@ } } + + +
+ +

Ticket Dashboard