From 34d13d163f48ca2dbdae8ce9704ed7140634a73d Mon Sep 17 00:00:00 2001 From: Torsten Brumm Date: Fri, 24 Apr 2026 20:02:56 +0200 Subject: [PATCH 1/9] First draft for RT6 and Bootstrap First version to bring this extension to RT6 --- CLAUDE.md | 65 +++ Changes | 16 + MANIFEST | 105 +---- Makefile.PL | 4 +- .../Elements/Header/Head | 5 +- html/NoAuth/css/terminal/AfterMenus | 23 ++ html/NoAuth/css/terminal/BeforeNav | 118 ++++++ html/NoAuth/css/terminal/InHeader | 4 + lib/RT/Extension/TerminalTheme.pm | 26 +- static/css/terminal/main.css | 3 + static/css/terminal/terminal.css | 381 ++++++++++++++++++ 11 files changed, 638 insertions(+), 112 deletions(-) create mode 100644 CLAUDE.md create mode 100644 html/NoAuth/css/terminal/AfterMenus create mode 100644 html/NoAuth/css/terminal/BeforeNav create mode 100644 html/NoAuth/css/terminal/InHeader create mode 100644 static/css/terminal/main.css create mode 100644 static/css/terminal/terminal.css diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..b4cfddf --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,65 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## What this is + +An RT (Request Tracker) 6.x extension that provides a classic CRT "green screen" terminal theme. It ships a single stylesheet named `terminal` with both light (pale-green) and dark (phosphor-green) modes, controlled by RT6's standard `WebDefaultThemeMode` mechanism. + +## Build & install + +```bash +perl Makefile.PL # generates Makefile +make +make install # may need root; installs into RT's directory tree +``` + +After install, enable in `/opt/rt6/etc/RT_SiteConfig.pm`: +```perl +Plugin('RT::Extension::TerminalTheme'); +Set($WebDefaultStylesheet, 'terminal'); +# Optional — defaults to 'auto' (browser preference): +Set($WebDefaultThemeMode, 'dark'); # or 'light' +``` + +Then clear the Mason cache and restart the webserver: +```bash +rm -rf /opt/rt6/var/mason_data/obj +sudo systemctl restart apache2 # or nginx/starman depending on setup +``` + +There are no automated tests in this extension. + +## Architecture + +RT6 extensions hook into RT's Mason-based rendering pipeline. This extension uses three mechanisms: + +**Callback** (`html/Callbacks/RT-Extension-TerminalTheme/Elements/Header/Head`): Runs during `` rendering. If the active stylesheet is `terminal`, injects the custom SVG logo into `LogoURL` and `SmallLogoURL` args (which are passed through to `/Elements/Logo`). + +**CSS delivery via Mason** (`html/NoAuth/css/terminal/`): RT serves CSS through Mason templates. Three callback files: +- `InHeader` — injects `` and (on dashboard render) the mail layout stylesheet +- `BeforeNav` — Bootstrap 5 overflow-menu JavaScript for `#main-navigation` and `#page-navigation`, including HTMX `registerLoadListener` for partial-page reloads +- `AfterMenus` — sticky page-menu initialization + +**Static CSS** (`static/css/terminal/`): +- `main.css` — entry point; `@import`s the full elevator theme, then `terminal.css` +- `terminal.css` — all terminal visual overrides using Bootstrap 5 CSS custom properties and `[data-bs-theme=light]` / `[data-bs-theme=dark]` selectors + +## CSS strategy + +The terminal theme does **not** duplicate elevator's CSS files. Instead `main.css` imports `../elevator/main.css` as the complete base (Bootstrap 5, all RT6 components) and `terminal.css` overrides only colors, fonts, and a few layout details. + +Key CSS variable overrides are grouped by theme mode inside `[data-bs-theme=light]` and `[data-bs-theme=dark]` selectors. Bootstrap 5 picks up the `--bs-*` variable changes automatically, so most component styling (forms, tables, buttons) just works without per-component rules. + +The monospace font (`Courier New` / system fallbacks) is applied at the `body` level and to form elements. + +## RT6 vs RT5 differences handled here + +| Area | RT5 | RT6 | +|------|-----|-----| +| Theme name | `terminal-light`, `terminal-dark` | `terminal` (single) | +| Dark mode | separate stylesheet | `data-bs-theme` attribute | +| CSS framework | Bootstrap 3/4 | Bootstrap 5 CSS variables | +| Nav IDs | `#app-nav`, `#page-menu` | `#main-navigation`, `#page-navigation` | +| Dynamic loading | none | HTMX `registerLoadListener` | +| Menu JS | Superfish | plain Bootstrap 5 dropdowns | diff --git a/Changes b/Changes index e7510fa..a446b6a 100644 --- a/Changes +++ b/Changes @@ -1,4 +1,20 @@ Revision history for RT-Extension-TerminalTheme +0.02 2025-04-24 + - Port to RT 6 (requires_rt 6.0.0, rt_too_new 7.0.0) + - Replace terminal-light/terminal-dark dual stylesheet with a single + "terminal" stylesheet; light/dark mode now controlled via the standard + RT6 WebDefaultThemeMode config option (Bootstrap 5 data-bs-theme) + - Rewrite all CSS as Bootstrap 5 overrides using CSS custom properties; + the theme inherits the full elevator stylesheet and applies only delta + overrides for colours, fonts, and layout + - Apply monospace font (Courier New/system fallbacks) throughout + - Update Mason templates (InHeader, BeforeNav, AfterMenus) for RT6: + new navigation IDs (#main-navigation, #page-navigation), Bootstrap 5 + class manipulations, and HTMX registerLoadListener support + - Add SmallLogoURL injection for responsive logo display + - Drop bundled Inter font files and RT5 CSS copies (inherited from elevator) + - Drop Superfish menu JS (not used in RT6) + 0.01 2021-03-11 - Initial version diff --git a/MANIFEST b/MANIFEST index 05a4d30..bb6947d 100644 --- a/MANIFEST +++ b/MANIFEST @@ -1,10 +1,8 @@ Changes -html/NoAuth/css/terminal-dark/AfterMenus -html/NoAuth/css/terminal-dark/BeforeNav -html/NoAuth/css/terminal-dark/InHeader -html/NoAuth/css/terminal-light/AfterMenus -html/NoAuth/css/terminal-light/BeforeNav -html/NoAuth/css/terminal-light/InHeader +html/Callbacks/RT-Extension-TerminalTheme/Elements/Header/Head +html/NoAuth/css/terminal/AfterMenus +html/NoAuth/css/terminal/BeforeNav +html/NoAuth/css/terminal/InHeader inc/Module/Install.pm inc/Module/Install/Base.pm inc/Module/Install/Can.pm @@ -23,95 +21,6 @@ Makefile.PL MANIFEST This list of files META.yml README -static/css/fonts/inter/Inter-Black.woff -static/css/fonts/inter/Inter-Black.woff2 -static/css/fonts/inter/Inter-BlackItalic.woff -static/css/fonts/inter/Inter-BlackItalic.woff2 -static/css/fonts/inter/Inter-Bold.woff -static/css/fonts/inter/Inter-Bold.woff2 -static/css/fonts/inter/Inter-BoldItalic.woff -static/css/fonts/inter/Inter-BoldItalic.woff2 -static/css/fonts/inter/Inter-ExtraBold.woff -static/css/fonts/inter/Inter-ExtraBold.woff2 -static/css/fonts/inter/Inter-ExtraBoldItalic.woff -static/css/fonts/inter/Inter-ExtraBoldItalic.woff2 -static/css/fonts/inter/Inter-ExtraLight-BETA.woff -static/css/fonts/inter/Inter-ExtraLight-BETA.woff2 -static/css/fonts/inter/Inter-ExtraLightItalic-BETA.woff -static/css/fonts/inter/Inter-ExtraLightItalic-BETA.woff2 -static/css/fonts/inter/Inter-Italic.woff -static/css/fonts/inter/Inter-Italic.woff2 -static/css/fonts/inter/Inter-Light-BETA.woff -static/css/fonts/inter/Inter-Light-BETA.woff2 -static/css/fonts/inter/Inter-LightItalic-BETA.woff -static/css/fonts/inter/Inter-LightItalic-BETA.woff2 -static/css/fonts/inter/Inter-Medium.woff -static/css/fonts/inter/Inter-Medium.woff2 -static/css/fonts/inter/Inter-MediumItalic.woff -static/css/fonts/inter/Inter-MediumItalic.woff2 -static/css/fonts/inter/Inter-Regular.woff -static/css/fonts/inter/Inter-Regular.woff2 -static/css/fonts/inter/Inter-SemiBold.woff -static/css/fonts/inter/Inter-SemiBold.woff2 -static/css/fonts/inter/Inter-SemiBoldItalic.woff -static/css/fonts/inter/Inter-SemiBoldItalic.woff2 -static/css/fonts/inter/Inter-Thin-BETA.woff -static/css/fonts/inter/Inter-Thin-BETA.woff2 -static/css/fonts/inter/Inter-ThinItalic-BETA.woff -static/css/fonts/inter/Inter-ThinItalic-BETA.woff2 -static/css/fonts/inter/LICENSE.txt -static/css/mobile.css -static/css/terminal-dark/main.css -static/css/terminal-light/accordion.css -static/css/terminal-light/admin.css -static/css/terminal-light/articles.css -static/css/terminal-light/assets.css -static/css/terminal-light/base.css -static/css/terminal-light/bootstrap-combobox.css -static/css/terminal-light/bootstrap-select.css -static/css/terminal-light/bootstrap.css -static/css/terminal-light/boxes.css -static/css/terminal-light/Chart.css -static/css/terminal-light/charts.css -static/css/terminal-light/chosen.css -static/css/terminal-light/collection.css -static/css/terminal-light/dashboards.css -static/css/terminal-light/dropzone.css -static/css/terminal-light/dropzone.customized.css -static/css/terminal-light/farbtastic.css -static/css/terminal-light/forms.css -static/css/terminal-light/history-folding.css -static/css/terminal-light/history.css -static/css/terminal-light/inline-edit.css -static/css/terminal-light/inter.css -static/css/terminal-light/jquery-ui-timepicker-addon.css -static/css/terminal-light/jquery-ui.css -static/css/terminal-light/jquery-ui.custom.modified.css -static/css/terminal-light/jquery.jgrowl.min.css -static/css/terminal-light/keyboard-shortcuts.css -static/css/terminal-light/layout.css -static/css/terminal-light/lifecycleui.css -static/css/terminal-light/login.css -static/css/terminal-light/main-orig.css -static/css/terminal-light/main.css -static/css/terminal-light/misc.css -static/css/terminal-light/nav.css -static/css/terminal-light/portlets.css -static/css/terminal-light/print.css -static/css/terminal-light/record.css -static/css/terminal-light/rights-editor.css -static/css/terminal-light/selectize.customized.css -static/css/terminal-light/selectize.default.css -static/css/terminal-light/shredder.css -static/css/terminal-light/superfish-navbar.css -static/css/terminal-light/superfish-vertical.css -static/css/terminal-light/superfish.css -static/css/terminal-light/tablesorter.css -static/css/terminal-light/theme-editor.css -static/css/terminal-light/ticket-form.css -static/css/terminal-light/ticket-forms.css -static/css/terminal-light/ticket-lists.css -static/css/terminal-light/ticket-search.css -static/css/terminal-light/ticket-timer.css -static/css/terminal-light/ticket.css -static/images/request-tracker-logo.svg +static/css/terminal/main.css +static/css/terminal/terminal.css +static/images/terminal-request-tracker-logo.svg diff --git a/Makefile.PL b/Makefile.PL index c12018d..7adefe0 100644 --- a/Makefile.PL +++ b/Makefile.PL @@ -5,8 +5,8 @@ RTx 'RT-Extension-TerminalTheme'; license 'gpl_2'; repository 'https://github.com/bestpractical/rt-extension-terminaltheme'; -requires_rt '5.0.0'; -rt_too_new '6.0.0'; +requires_rt '6.0.0'; +rt_too_new '7.0.0'; sign; WriteAll; diff --git a/html/Callbacks/RT-Extension-TerminalTheme/Elements/Header/Head b/html/Callbacks/RT-Extension-TerminalTheme/Elements/Header/Head index 81ac4a4..5d4c64c 100644 --- a/html/Callbacks/RT-Extension-TerminalTheme/Elements/Header/Head +++ b/html/Callbacks/RT-Extension-TerminalTheme/Elements/Header/Head @@ -1,6 +1,7 @@ <%INIT> -return unless RT->Config->Get( 'WebDefaultStylesheet', $session{CurrentUser} ) =~ /^terminal-(?:light|dark)$/; -$ARGSRef->{LogoURL} = RT->Config->Get('WebImagesURL') . "terminal-request-tracker-logo.svg"; +return unless RT->Config->Get( 'WebDefaultStylesheet', $session{CurrentUser} ) eq 'terminal'; +$ARGSRef->{LogoURL} = RT->Config->Get('WebImagesURL') . "terminal-request-tracker-logo.svg"; +$ARGSRef->{SmallLogoURL} = RT->Config->Get('WebImagesURL') . "terminal-request-tracker-logo.svg"; <%ARGS> diff --git a/html/NoAuth/css/terminal/AfterMenus b/html/NoAuth/css/terminal/AfterMenus new file mode 100644 index 0000000..e763c9d --- /dev/null +++ b/html/NoAuth/css/terminal/AfterMenus @@ -0,0 +1,23 @@ + diff --git a/html/NoAuth/css/terminal/BeforeNav b/html/NoAuth/css/terminal/BeforeNav new file mode 100644 index 0000000..2accf6a --- /dev/null +++ b/html/NoAuth/css/terminal/BeforeNav @@ -0,0 +1,118 @@ +<%INIT> +return unless Menu; # In case we are in Installer mode + +my $page_overflow = PageMenu->child( overflow => title => loc('More'), sort_order => 99999); +# add a child element to make sure we get a dropdown indicator +$page_overflow->child(will_be_deleted => raw_html => ''); + + diff --git a/html/NoAuth/css/terminal/InHeader b/html/NoAuth/css/terminal/InHeader new file mode 100644 index 0000000..1803d71 --- /dev/null +++ b/html/NoAuth/css/terminal/InHeader @@ -0,0 +1,4 @@ + +% if ( $m->request_path eq '/Dashboards/Render.html' && !$m->request_args->{Preview} ) { + +% } diff --git a/lib/RT/Extension/TerminalTheme.pm b/lib/RT/Extension/TerminalTheme.pm index 4539f77..08cc5aa 100644 --- a/lib/RT/Extension/TerminalTheme.pm +++ b/lib/RT/Extension/TerminalTheme.pm @@ -2,7 +2,7 @@ use strict; use warnings; package RT::Extension::TerminalTheme; -our $VERSION = '0.01'; +our $VERSION = '0.02'; =head1 NAME @@ -10,14 +10,13 @@ RT-Extension-TerminalTheme - Classic "green screen" terminal theme for RT =head1 DESCRIPTION -Provides a theme with light and dark modes that resemble a classic CRT "green -screen" terminal and serve as a good example of how to theme Request Tracker. -You can L about -this theme on the L. +Provides a theme that resembles a classic CRT "green screen" terminal. +Supports both light (pale-green tinted) and dark (phosphor-green on black) +modes via Bootstrap 5's C mechanism. =head1 RT VERSION -Works with RT 5. +Works with RT 6. =head1 INSTALLATION @@ -31,15 +30,22 @@ Works with RT 5. May need root permissions. -=item Edit your F +=item Edit your F -Add this line: +Add these lines: Plugin('RT::Extension::TerminalTheme'); + Set($WebDefaultStylesheet, 'terminal'); + +To default to dark (phosphor-green) mode, also add: + + Set($WebDefaultThemeMode, 'dark'); + +Users can still override the theme mode in their personal preferences. =item Clear your mason cache - rm -rf /opt/rt5/var/mason_data/obj + rm -rf /opt/rt6/var/mason_data/obj =item Restart your webserver @@ -62,7 +68,7 @@ href="http://rt.cpan.org/Public/Dist/Display.html?Name=RT-Extension-TerminalThem =head1 LICENSE AND COPYRIGHT -This software is Copyright (c) 2021 by Best Practical Solutions, LLC +This software is Copyright (c) 2021-2025 by Best Practical Solutions, LLC This is free software, licensed under: diff --git a/static/css/terminal/main.css b/static/css/terminal/main.css new file mode 100644 index 0000000..9d6b5f1 --- /dev/null +++ b/static/css/terminal/main.css @@ -0,0 +1,3 @@ +/* RT Terminal Theme — inherits elevator (Bootstrap 5 base) then applies overrides */ +@import "elevator/main.css"; +@import "terminal/terminal.css"; diff --git a/static/css/terminal/terminal.css b/static/css/terminal/terminal.css new file mode 100644 index 0000000..72e58cf --- /dev/null +++ b/static/css/terminal/terminal.css @@ -0,0 +1,381 @@ +/* =================================================================== + * RT Terminal Theme — Bootstrap 5 color & style overrides for RT6 + * + * Light mode: pale-green CRT screen aesthetic + * Dark mode: classic phosphor green on near-black + * =================================================================== */ + +/* --- CSS custom properties used throughout the theme -------------- */ +:root { + --terminal-green-bright: #33ff33; + --terminal-green-mid: #22cc22; + --terminal-green-dim: #1a8a1a; + --terminal-green-dark: #0d4a0d; + --terminal-near-black: #050f05; + --terminal-font: 'Courier New', 'DejaVu Sans Mono', 'Lucida Console', Courier, monospace; +} + +/* Apply monospace font globally for the terminal aesthetic */ +body, +button, +input, +select, +textarea, +.form-control, +.form-select, +.btn, +.badge, +.titlebox .titlebox-title .left { + font-family: var(--terminal-font); +} + + +/* =================================================================== + * LIGHT MODE — pale-green tinted screen + * =================================================================== */ +[data-bs-theme=light] { + /* Bootstrap 5 core */ + --bs-body-color: #0d2b0d; + --bs-body-color-rgb: 13, 43, 13; + --bs-body-bg: #f2f7ed; + --bs-body-bg-rgb: 242, 247, 237; + + --bs-primary: #2d7a2d; + --bs-primary-rgb: 45, 122, 45; + + --bs-link-color: #145214; + --bs-link-color-rgb: 20, 82, 20; + --bs-link-hover-color: #0a2a0a; + --bs-link-hover-color-rgb: 10, 42, 10; + --bs-link-decoration: none; + + --bs-border-color: #8ab58a; + --bs-border-color-translucent: rgba(138, 181, 138, 0.18); + + --bs-card-bg: #eaf2e4; + --bs-card-border-color: #8ab58a; + + --bs-secondary-bg: #e2eedb; + --bs-tertiary-bg: #d5e8cc; + + /* Gray scale shifted to greens */ + --bs-gray-100: #eef5e8; + --bs-gray-200: #deecd6; + --bs-gray-300: #bdd9b5; + --bs-gray-400: #8ab58a; + --bs-gray-500: #5a9a5a; + --bs-gray-600: #3d7a3d; + --bs-gray-700: #2a602a; + --bs-gray-800: #1a4a1a; + --bs-gray-900: #0a2200; +} + +[data-bs-theme=light] { + h1, h2, h3, h4 { color: #0a2200; } + + a:not(.btn):visited { color: #4a8a4a; } + + /* ----- Header bar & logo area --------------------------------- */ + div#quickbar { + background-color: #0a1a0a; + border-bottom-color: #22aa22; + } + + div#footer { + background-color: #0a1a0a; + } + div#footer p, + div#footer a { color: #22cc22; } + + div#header { border-bottom-color: #2d7a2d; } + + /* ----- Main navigation (dark bar with green text) ------------- */ + .navbar { background-color: #0a1a0a; } + + .navbar a.nav-link, + .navbar li a { color: #22cc22 !important; } + + .navbar a.nav-link:hover, + #app-nav > li > a:hover { + background-color: #1a3a1a; + color: #44ff44 !important; + } + + body.keyboard-nav-active #app-nav > li > a.menu-item:focus, + body.keyboard-nav-active .page-menu > li > a.menu-item:focus { + background: #1a3a1a; + } + + /* ----- Dropdown menus ----------------------------------------- */ + .dropdown-menu { + background-color: #0f2a0f; + border-color: #2d7a2d; + } + + .dropdown-item, + a.dropdown-item { color: #22cc22; background-color: #0f2a0f; } + + a.dropdown-item.hovered, + .dropdown-item:hover, + .dropdown-item:focus { background-color: #1a3a1a; color: #44ff44; } + + .dropdown-divider { border-color: #1a4a1a; } + + /* ----- Page menu pinned to top --------------------------------- */ + .page-menu.pinned { + background-color: #f2f7ed; + border-left-color: #8ab58a; + border-bottom-color: #8ab58a; + box-shadow: 0 0 10px rgba(0, 80, 0, 0.2); + } + + .page-menu.pinned li:hover ul { + border-left-color: #8ab58a; + border-right-color: #8ab58a; + } + + /* ----- TitleBox (card component) ------------------------------ */ + .titlebox { border-color: #8ab58a; } + + .titlebox .titlebox-title { background-color: #2d7a2d; } + + .titlebox .titlebox-title .left { color: #f2f7ed; } + + .titlebox .titlebox-title .right a { color: #d0f0d0; } + + /* ----- Tables -------------------------------------------------- */ + .table { --bs-table-hover-bg: #deecd6; } + + .table-active { --bs-table-bg-state: #deecd6; } + + /* ----- Buttons ------------------------------------------------- */ + .btn-primary, + input[type=submit].btn-primary { + background-color: #2d7a2d; + border-color: #1a4a1a; + color: #f2f7ed; + } + .btn-primary:hover { + background-color: #1a6a1a; + border-color: #0a2a0a; + } + + #topactions form input.btn { border-color: #2d7a2d; } + + /* ----- Login page --------------------------------------------- */ + #login-box { border-color: #2d7a2d; } + + /* ----- Alerts -------------------------------------------------- */ + .alert-info { + background-color: #deecd6; + border-color: #8ab58a; + color: #0d2b0d; + } +} + + +/* =================================================================== + * DARK MODE — classic phosphor green on near-black + * =================================================================== */ +[data-bs-theme=dark] { + /* Bootstrap 5 core */ + --bs-body-color: #33ff33; + --bs-body-color-rgb: 51, 255, 51; + --bs-body-bg: #050f05; + --bs-body-bg-rgb: 5, 15, 5; + + --bs-primary: #00cc44; + --bs-primary-rgb: 0, 204, 68; + + --bs-link-color: #00ff66; + --bs-link-color-rgb: 0, 255, 102; + --bs-link-hover-color: #66ff99; + --bs-link-hover-color-rgb: 102, 255, 153; + --bs-link-decoration: none; + + --bs-border-color: #1a5a1a; + --bs-border-color-translucent: rgba(26, 90, 26, 0.18); + + --bs-card-bg: #0a1a0a; + --bs-card-border-color: #1a5a1a; + + --bs-secondary-color: rgba(26, 170, 26, 0.75); + --bs-secondary-bg: #0a1a0a; + --bs-tertiary-bg: #081208; + + /* Gray scale shifted to dark greens */ + --bs-gray-100: #0d1a0d; + --bs-gray-200: #112211; + --bs-gray-300: #1a3a1a; + --bs-gray-400: #225522; + --bs-gray-500: #2a6e2a; + --bs-gray-600: #338833; + --bs-gray-700: #44aa44; + --bs-gray-800: #55cc55; + --bs-gray-900: #66ee66; +} + +[data-bs-theme=dark] { + p, li span { color: #33ff33; } + + h1, h2, h3, h4 { color: #44ff44; } + + /* Subtle glow on large headings for phosphor effect */ + h1 { text-shadow: 0 0 10px rgba(0, 255, 51, 0.35); } + h2 { text-shadow: 0 0 8px rgba(0, 255, 51, 0.25); } + + svg { fill: #33ff33; } + + a:not(.btn):visited { color: #22aa22; } + + /* ----- Header bar & logo area --------------------------------- */ + div#quickbar { + background-color: #030803; + border-bottom-color: #1a5a1a; + } + + div#footer { + background-color: #030803; + border-top: 1px solid #1a5a1a; + } + div#footer p, + div#footer a { color: #1aaa1a; } + + div#header { border-bottom-color: #00cc44; } + + /* ----- Main navigation ---------------------------------------- */ + .navbar { background-color: #030803; } + + .navbar li a { color: #22cc22 !important; } + + #app-nav > li > a.menu-item:hover, + .navbar a.nav-link:hover { + background: #0a2a0a; + color: #44ff44 !important; + } + + body.keyboard-nav-active #app-nav > li > a.menu-item:focus, + body.keyboard-nav-active .page-menu > li > a.menu-item:focus { + background: #0a2a0a; + } + + /* ----- Dropdown menus ----------------------------------------- */ + .dropdown-menu { background: #0a1a0a; border-color: #1a5a1a; } + + .dropdown-item, + .dropdown-item *, + a.dropdown-item { background: #0a1a0a; color: #22cc22; } + + .dropdown-divider { border-color: #1a2a1a; } + + .dropdown-item.hovered, + .dropdown-item:hover, + .dropdown-item:focus { background: #112211; color: #44ff44; } + + /* ----- Page menu pinned --------------------------------------- */ + .page-menu.pinned { + background-color: #0a1a0a; + box-shadow: 0 0 10px rgba(0, 204, 68, 0.12); + } + .page-menu.pinned ul { + border-color: #1a5a1a; + } + .page-menu.pinned li:hover ul { + border-left-color: #1a5a1a; + border-right-color: #1a5a1a; + } + + /* ----- Tables -------------------------------------------------- */ + .table td { color: #33ff33; } + table.table th { border: none; color: #44ff44; } + .table th, .table td { border-top: 1px solid #1a5a1a; } + table a:visited { color: #22aa22; } + .table { --bs-table-hover-bg: #0f2a0f; } + .table-active { --bs-table-bg-state: #0f2a0f; } + + /* ----- Nav tabs / pills --------------------------------------- */ + .nav-tabs { border-bottom: 1px solid #1a5a1a; } + + .nav-tabs .nav-link:hover, + .nav-tabs .nav-link.active { + border-color: #1a5a1a; + background-color: #0a1a0a; + color: #44ff44; + } + + .nav-pills .nav-link.active { background-color: #1a3a1a !important; } + + /* ----- Forms --------------------------------------------------- */ + .form-control, + .form-select { + background-color: #0a1a0a; + color: #33ff33; + border-color: #1a5a1a; + } + + .form-control:focus, + .form-select:focus { + background-color: #0a1a0a; + color: #44ff44; + border-color: #2d7a2d; + box-shadow: 0 0 0 0.25rem rgba(0, 204, 68, 0.2); + } + + .form-control::placeholder { color: #1a5a1a; } + + .input-group-text { + background-color: #0d2a0d; + color: #22cc22; + border-color: #1a5a1a; + } + + /* ----- Buttons ------------------------------------------------ */ + .btn-primary { + background-color: #0d3d0d; + color: #33ff33; + border-color: #1a5a1a; + } + .btn-primary:hover { + background-color: #1a5a1a; + border-color: #2d7a2d; + color: #44ff44; + } + + .btn-secondary, + .btn-default { + background-color: #0a1a0a; + color: #22cc22; + border-color: #1a5a1a; + } + .btn-secondary:hover, + .btn-default:hover { + background-color: #112211; + color: #44ff44; + } + + /* ----- Cards / TitleBox --------------------------------------- */ + .card { + background-color: #0a1a0a; + border-color: #1a5a1a; + } + .titlebox { border-color: #1a5a1a; } + + /* ----- Badges ------------------------------------------------- */ + .badge { font-family: var(--terminal-font); } + + /* ----- Login page --------------------------------------------- */ + #login-box { border-color: #1a5a1a; } + + /* ----- jGrowl notifications ----------------------------------- */ + .jGrowl-notification { + background-color: #0a1a0a; + color: #33ff33; + border: 1px solid #1a5a1a; + } + + /* ----- Custom scrollbar (WebKit) ------------------------------ */ + ::-webkit-scrollbar { width: 8px; background-color: #050f05; } + ::-webkit-scrollbar-thumb { background-color: #1a5a1a; border-radius: 4px; } + ::-webkit-scrollbar-thumb:hover { background-color: #2d7a2d; } + ::-webkit-scrollbar-track { background-color: #050f05; } +} From e4eafef216239ab15b5e9a0fbbab4e0cd13e56be Mon Sep 17 00:00:00 2001 From: Torsten Brumm Date: Fri, 24 Apr 2026 20:04:26 +0200 Subject: [PATCH 2/9] Update README mentioned rt6 as new default --- README | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README b/README index 8ae9bfa..a147d0e 100644 --- a/README +++ b/README @@ -10,7 +10,7 @@ DESCRIPTION this theme on the Best Practical blog . RT VERSION - Works with RT 5. + Works with RT 6. INSTALLATION perl Makefile.PL @@ -18,13 +18,13 @@ INSTALLATION make install May need root permissions. - Edit your /opt/rt5/etc/RT_SiteConfig.pm + Edit your /opt/rt6/etc/RT_SiteConfig.pm Add this line: Plugin('RT::Extension::TerminalTheme'); Clear your mason cache - rm -rf /opt/rt5/var/mason_data/obj + rm -rf /opt/rt6/var/mason_data/obj Restart your webserver From 8ff5e77aaf6b878e11f470eb30aa3e7985474a73 Mon Sep 17 00:00:00 2001 From: Torsten Brumm Date: Fri, 24 Apr 2026 20:11:31 +0200 Subject: [PATCH 3/9] Update .gitignore Ignore some more files --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 6f1df1b..643e082 100644 --- a/.gitignore +++ b/.gitignore @@ -12,3 +12,4 @@ pod2htm*.tmp /MYMETA.* /t/tmp /xt/tmp +CLAUDE.md From d376ea1d46e30725858636b9aa49704c2e6b48e0 Mon Sep 17 00:00:00 2001 From: Torsten Brumm Date: Fri, 24 Apr 2026 20:12:05 +0200 Subject: [PATCH 4/9] Delete CLAUDE.md --- CLAUDE.md | 65 ------------------------------------------------------- 1 file changed, 65 deletions(-) delete mode 100644 CLAUDE.md diff --git a/CLAUDE.md b/CLAUDE.md deleted file mode 100644 index b4cfddf..0000000 --- a/CLAUDE.md +++ /dev/null @@ -1,65 +0,0 @@ -# CLAUDE.md - -This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. - -## What this is - -An RT (Request Tracker) 6.x extension that provides a classic CRT "green screen" terminal theme. It ships a single stylesheet named `terminal` with both light (pale-green) and dark (phosphor-green) modes, controlled by RT6's standard `WebDefaultThemeMode` mechanism. - -## Build & install - -```bash -perl Makefile.PL # generates Makefile -make -make install # may need root; installs into RT's directory tree -``` - -After install, enable in `/opt/rt6/etc/RT_SiteConfig.pm`: -```perl -Plugin('RT::Extension::TerminalTheme'); -Set($WebDefaultStylesheet, 'terminal'); -# Optional — defaults to 'auto' (browser preference): -Set($WebDefaultThemeMode, 'dark'); # or 'light' -``` - -Then clear the Mason cache and restart the webserver: -```bash -rm -rf /opt/rt6/var/mason_data/obj -sudo systemctl restart apache2 # or nginx/starman depending on setup -``` - -There are no automated tests in this extension. - -## Architecture - -RT6 extensions hook into RT's Mason-based rendering pipeline. This extension uses three mechanisms: - -**Callback** (`html/Callbacks/RT-Extension-TerminalTheme/Elements/Header/Head`): Runs during `` rendering. If the active stylesheet is `terminal`, injects the custom SVG logo into `LogoURL` and `SmallLogoURL` args (which are passed through to `/Elements/Logo`). - -**CSS delivery via Mason** (`html/NoAuth/css/terminal/`): RT serves CSS through Mason templates. Three callback files: -- `InHeader` — injects `` and (on dashboard render) the mail layout stylesheet -- `BeforeNav` — Bootstrap 5 overflow-menu JavaScript for `#main-navigation` and `#page-navigation`, including HTMX `registerLoadListener` for partial-page reloads -- `AfterMenus` — sticky page-menu initialization - -**Static CSS** (`static/css/terminal/`): -- `main.css` — entry point; `@import`s the full elevator theme, then `terminal.css` -- `terminal.css` — all terminal visual overrides using Bootstrap 5 CSS custom properties and `[data-bs-theme=light]` / `[data-bs-theme=dark]` selectors - -## CSS strategy - -The terminal theme does **not** duplicate elevator's CSS files. Instead `main.css` imports `../elevator/main.css` as the complete base (Bootstrap 5, all RT6 components) and `terminal.css` overrides only colors, fonts, and a few layout details. - -Key CSS variable overrides are grouped by theme mode inside `[data-bs-theme=light]` and `[data-bs-theme=dark]` selectors. Bootstrap 5 picks up the `--bs-*` variable changes automatically, so most component styling (forms, tables, buttons) just works without per-component rules. - -The monospace font (`Courier New` / system fallbacks) is applied at the `body` level and to form elements. - -## RT6 vs RT5 differences handled here - -| Area | RT5 | RT6 | -|------|-----|-----| -| Theme name | `terminal-light`, `terminal-dark` | `terminal` (single) | -| Dark mode | separate stylesheet | `data-bs-theme` attribute | -| CSS framework | Bootstrap 3/4 | Bootstrap 5 CSS variables | -| Nav IDs | `#app-nav`, `#page-menu` | `#main-navigation`, `#page-navigation` | -| Dynamic loading | none | HTMX `registerLoadListener` | -| Menu JS | Superfish | plain Bootstrap 5 dropdowns | From 48fe5d697e515c7576b7a806a91da5e4d256a67d Mon Sep 17 00:00:00 2001 From: Torsten Brumm Date: Fri, 24 Apr 2026 21:29:41 +0200 Subject: [PATCH 5/9] Update .gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 643e082..993b8aa 100644 --- a/.gitignore +++ b/.gitignore @@ -13,3 +13,4 @@ pod2htm*.tmp /t/tmp /xt/tmp CLAUDE.md +./claude From 3f3156f5698761616ac58cabe0aa0da6220042fe Mon Sep 17 00:00:00 2001 From: Torsten Brumm Date: Fri, 24 Apr 2026 21:59:53 +0200 Subject: [PATCH 6/9] Fix CSS import path, logo aspect-ratio, and navbar font overflow MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - main.css: fix @import paths (remove leading comment blocking CSS::Squish, correct relative path to ../elevator/main.css) - terminal.css: exclude button/input/select from monospace font to prevent navbar overflow on "Create new ticket" and search controls - terminal.css: fix terminal SVG logo aspect-ratio (viewBox 858×144 vs wrong width/height attrs) - terminal.css: add light-mode btn-secondary, topactions button styles, form-control focus state, and status badge overrides Co-Authored-By: Claude Sonnet 4.6 --- static/css/terminal/main.css | 5 +-- static/css/terminal/terminal.css | 67 +++++++++++++++++++++++++++----- 2 files changed, 60 insertions(+), 12 deletions(-) diff --git a/static/css/terminal/main.css b/static/css/terminal/main.css index 9d6b5f1..62ffd3d 100644 --- a/static/css/terminal/main.css +++ b/static/css/terminal/main.css @@ -1,3 +1,2 @@ -/* RT Terminal Theme — inherits elevator (Bootstrap 5 base) then applies overrides */ -@import "elevator/main.css"; -@import "terminal/terminal.css"; +@import "../elevator/main.css"; +@import "terminal.css"; diff --git a/static/css/terminal/terminal.css b/static/css/terminal/terminal.css index 72e58cf..f63c5ef 100644 --- a/static/css/terminal/terminal.css +++ b/static/css/terminal/terminal.css @@ -15,20 +15,25 @@ --terminal-font: 'Courier New', 'DejaVu Sans Mono', 'Lucida Console', Courier, monospace; } -/* Apply monospace font globally for the terminal aesthetic */ +/* Monospace font for content areas — not navbar (would break layout/overflow calc) */ body, -button, -input, -select, -textarea, +.titlebox .titlebox-title .left, .form-control, .form-select, -.btn, +textarea, +table, .badge, -.titlebox .titlebox-title .left { +pre, code, tt { font-family: var(--terminal-font); } +/* Fix terminal logo aspect ratio (SVG has wrong width/height vs viewBox 858×144) */ +div#logo a img { + aspect-ratio: 858 / 144 !important; + height: 100% !important; + width: auto !important; +} + /* =================================================================== * LIGHT MODE — pale-green tinted screen @@ -150,7 +155,8 @@ textarea, /* ----- Buttons ------------------------------------------------- */ .btn-primary, - input[type=submit].btn-primary { + input[type=submit].btn-primary, + input[type=button].btn-primary { background-color: #2d7a2d; border-color: #1a4a1a; color: #f2f7ed; @@ -160,7 +166,40 @@ textarea, border-color: #0a2a0a; } - #topactions form input.btn { border-color: #2d7a2d; } + .btn-secondary, + .btn-default { + border-color: #8ab58a; + color: #0d2b0d; + } + + /* Topactions: "Create new ticket" and search */ + #topactions form input.btn, + #topactions .btn { + border-color: #2d7a2d; + background-color: #1a4a1a; + color: #d0f0d0; + } + #topactions form input.btn:hover, + #topactions .btn:hover { + background-color: #2d7a2d; + color: #f2f7ed; + } + + /* Form inputs */ + .form-control, + .form-select, + input[type=text], + input[type=search], + input[type=email] { + background-color: #f8fdf5; + color: #0d2b0d; + border-color: #8ab58a; + } + .form-control:focus, + .form-select:focus { + border-color: #2d7a2d; + box-shadow: 0 0 0 0.25rem rgba(45, 122, 45, 0.2); + } /* ----- Login page --------------------------------------------- */ #login-box { border-color: #2d7a2d; } @@ -171,6 +210,16 @@ textarea, border-color: #8ab58a; color: #0d2b0d; } + + /* ----- Status badges — make them terminal-green -------------- */ + .badge.bg-success, + .badge.bg-primary { background-color: #2d7a2d !important; } + + .badge.bg-secondary { background-color: #5a9a5a !important; } + + /* RT status color overrides for ticket status badges */ + span.rt-status-new, + .label-status-new { background-color: #1a4a1a !important; color: #d0f0d0 !important; } } From 95a6417e9fbc2fee5f41e2d45a62511cbb0bc55f Mon Sep 17 00:00:00 2001 From: Torsten Brumm Date: Fri, 24 Apr 2026 22:03:03 +0200 Subject: [PATCH 7/9] Fix light mode titlebox heading color visibility Headings (h2/h3) inside .titlebox-title were getting color: #0a2200 from the global h1-h4 rule, making them invisible on the #2d7a2d background. Override to #f2f7ed inside the title bar. Co-Authored-By: Claude Sonnet 4.6 --- static/css/terminal/terminal.css | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/static/css/terminal/terminal.css b/static/css/terminal/terminal.css index f63c5ef..cd5fd46 100644 --- a/static/css/terminal/terminal.css +++ b/static/css/terminal/terminal.css @@ -142,10 +142,17 @@ div#logo a img { /* ----- TitleBox (card component) ------------------------------ */ .titlebox { border-color: #8ab58a; } - .titlebox .titlebox-title { background-color: #2d7a2d; } + .titlebox .titlebox-title { background-color: #2d7a2d; color: #f2f7ed; } .titlebox .titlebox-title .left { color: #f2f7ed; } + /* Headings inside title bar get dark green from the h1-h4 rule above; + override to keep them readable on the dark green background */ + .titlebox .titlebox-title h1, + .titlebox .titlebox-title h2, + .titlebox .titlebox-title h3, + .titlebox .titlebox-title h4 { color: #f2f7ed; } + .titlebox .titlebox-title .right a { color: #d0f0d0; } /* ----- Tables -------------------------------------------------- */ From 7aac3b4445bc84a0ecddba4328835c9aba85c4ad Mon Sep 17 00:00:00 2001 From: Torsten Brumm Date: Fri, 24 Apr 2026 22:06:09 +0200 Subject: [PATCH 8/9] Fix titlebox title link color in light mode Titlebox titles that are saved-search links use inside .left, which gets --bs-link-color (#145214, dark green) overriding the .left color rule. Explicitly target .left a and .left a:visited with #f2f7ed. Co-Authored-By: Claude Sonnet 4.6 --- static/css/terminal/terminal.css | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/static/css/terminal/terminal.css b/static/css/terminal/terminal.css index cd5fd46..cbd7fd4 100644 --- a/static/css/terminal/terminal.css +++ b/static/css/terminal/terminal.css @@ -144,7 +144,9 @@ div#logo a img { .titlebox .titlebox-title { background-color: #2d7a2d; color: #f2f7ed; } - .titlebox .titlebox-title .left { color: #f2f7ed; } + .titlebox .titlebox-title .left, + .titlebox .titlebox-title .left a, + .titlebox .titlebox-title .left a:visited { color: #f2f7ed; } /* Headings inside title bar get dark green from the h1-h4 rule above; override to keep them readable on the dark green background */ @@ -153,7 +155,8 @@ div#logo a img { .titlebox .titlebox-title h3, .titlebox .titlebox-title h4 { color: #f2f7ed; } - .titlebox .titlebox-title .right a { color: #d0f0d0; } + .titlebox .titlebox-title .right a, + .titlebox .titlebox-title .right a:visited { color: #d0f0d0; } /* ----- Tables -------------------------------------------------- */ .table { --bs-table-hover-bg: #deecd6; } From cdcea5a0112d62741b68db1692fb764d1f2eead4 Mon Sep 17 00:00:00 2001 From: Torsten Brumm Date: Fri, 24 Apr 2026 22:09:33 +0200 Subject: [PATCH 9/9] Reduce titlebox card-header font-size to counter elevator compounding elevator/boxes.css sets .titlebox .card-header to font-size:larger, then .left adds another 1.1em on top. With a monospace font this produces oversized headers, especially visible on narrow chart widgets. Reset card-header to 1rem so the .left 1.1em resolves to a normal 1.1rem. Co-Authored-By: Claude Sonnet 4.6 --- static/css/terminal/terminal.css | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/static/css/terminal/terminal.css b/static/css/terminal/terminal.css index cbd7fd4..304ffbc 100644 --- a/static/css/terminal/terminal.css +++ b/static/css/terminal/terminal.css @@ -142,6 +142,10 @@ div#logo a img { /* ----- TitleBox (card component) ------------------------------ */ .titlebox { border-color: #8ab58a; } + /* elevator sets card-header to font-size:larger and .left to 1.1em on top; + reset to 1rem so the monospace font doesn't compound into oversized headers */ + .titlebox .card-header { font-size: 1rem; } + .titlebox .titlebox-title { background-color: #2d7a2d; color: #f2f7ed; } .titlebox .titlebox-title .left,