Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,5 @@ pod2htm*.tmp
/MYMETA.*
/t/tmp
/xt/tmp
CLAUDE.md
./claude
16 changes: 16 additions & 0 deletions Changes
Original file line number Diff line number Diff line change
@@ -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
105 changes: 7 additions & 98 deletions MANIFEST
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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
4 changes: 2 additions & 2 deletions Makefile.PL
Original file line number Diff line number Diff line change
Expand Up @@ -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;
6 changes: 3 additions & 3 deletions README
Original file line number Diff line number Diff line change
Expand Up @@ -10,21 +10,21 @@ DESCRIPTION
this theme on the Best Practical blog <https://bestpractical.com/blog>.

RT VERSION
Works with RT 5.
Works with RT 6.

INSTALLATION
perl Makefile.PL
make
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

Expand Down
Original file line number Diff line number Diff line change
@@ -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";
</%INIT>

<%ARGS>
Expand Down
23 changes: 23 additions & 0 deletions html/NoAuth/css/terminal/AfterMenus
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<script type="text/javascript">
var initMenus = function() {
if ( !jQuery("#page-menu").length ) return;

var originalOffset = jQuery("#page-menu").offset().top;
var floatMenu = function () {
jQuery(".page-menu").toggleClass("pinned", jQuery(document).scrollTop() > originalOffset);
if ( jQuery(document).scrollTop() > originalOffset ) {
jQuery('#li-page-actions > ul').css('max-height', jQuery(window).height() - jQuery('#page-menu').height());
}
else {
jQuery('#li-page-actions > ul').css('max-height', jQuery(window).height() - jQuery('#rt-header-container').height());
}
};
floatMenu();
jQuery(window).scroll(floatMenu);

jQuery('#li-overflow-will_be_deleted').remove();
jQuery('#li-page-overflow-will_be_deleted').remove();
};

jQuery(initMenus);
</script>
118 changes: 118 additions & 0 deletions html/NoAuth/css/terminal/BeforeNav
Original file line number Diff line number Diff line change
@@ -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 => '');
</%INIT>
<script type="text/javascript">
var rebalanceOverflowBuffer = 10;

var rebalanceOverflowMenu = function (menuId, overflowId) {
var toplevelMenu = jQuery(menuId);
var overflowMenu = jQuery(overflowId);
var availableWidth = jQuery(window).width();

if ( menuId === '#main-navigation' ) {
const logo = document.querySelector('#logo');
if ( logo.offsetWidth == 0 ) {
return;
}
document.querySelector('#topactions').style.right = 'calc(' + [logo.offsetWidth + 'px', window.getComputedStyle(logo).right, '1em'].join(' + ') + ')';
availableWidth -= jQuery('#topactions').width() + jQuery('#logo').width();;
}
else if ( menuId === '#page-navigation' ) {
availableWidth -= parseFloat(jQuery('#header h1').css('padding-left'));
availableWidth -= parseFloat(jQuery('#page-navigation').css('right'));
var fullWidth = availableWidth;
jQuery('#header h1').css('width', 'auto');
var subjectWidth = jQuery('#header h1').width();
availableWidth -= subjectWidth;

if (availableWidth < fullWidth * 0.5) {
availableWidth = fullWidth * 0.5;
subjectWidth = fullWidth * 0.5;
jQuery('#header h1').css('width', subjectWidth);
}
}

availableWidth -= rebalanceOverflowBuffer;

while (toplevelMenu.width() > availableWidth) {
var item = toplevelMenu.find('li.nav-item:not('+overflowId+')').get(-1);
if (!item) { break; }

jQuery(item).remove();
item.classList.remove('nav-item');
item.classList.add('menu-item');
item.classList.remove('dropdown');
item.classList.add('dropend');
const link = item.querySelector('a.nav-link');
link.classList.remove('nav-link');
link.classList.add('dropdown-item');

overflowMenu.children('ul').prepend(item);
overflowMenu.addClass('has-overflow');
}

while (1) {
var item = overflowMenu.find('li').get(0);
if (!item) { break; }
item = jQuery(item);

var clone = item.clone();
overflowMenu.before(clone);
var prospectiveWidth = toplevelMenu.width();
clone.remove();

if (prospectiveWidth > availableWidth) { break; }

item.remove();
overflowMenu.before(item);

item = item.get(0);
item.classList.remove('dropend');
item.classList.add('dropdown');
item.classList.remove('menu-item');
item.classList.add('nav-item');
const link = item.querySelector('a.dropdown-item');
link.classList.remove('dropdown-item');
link.classList.add('nav-link');

if (overflowMenu.find('li').length == 0) {
overflowMenu.removeClass('has-overflow');
}
}

if ( menuId === '#main-navigation' ) {
if ( jQuery(window).width() - jQuery('#topactions').width() - toplevelMenu.width() - jQuery('#logo').width() > 80 ) {
jQuery('#topactions input[type=search]:not(.expand)').addClass('expand');
}
else {
jQuery('#topactions input[type=search].expand').removeClass('expand');
}
}
};

jQuery(function() {
jQuery(window).resize(function () {
rebalanceOverflowMenu('#main-navigation', '#li-overflow');
rebalanceOverflowMenu('#page-navigation', '#li-page-overflow');
});

document.querySelectorAll('#logo img').forEach(function(img) {
img.addEventListener('load', function() {
if ( this.offsetWidth > 0 ) {
rebalanceOverflowMenu('#main-navigation', '#li-overflow');
}
});
});
});

registerLoadListener(function (evt) {
if ( evt.detail.elt.classList.contains('main-container') ) {
rebalanceOverflowMenu('#main-navigation', '#li-overflow');
rebalanceOverflowMenu('#page-navigation', '#li-page-overflow');
}
});
</script>
4 changes: 4 additions & 0 deletions html/NoAuth/css/terminal/InHeader
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0">
% if ( $m->request_path eq '/Dashboards/Render.html' && !$m->request_args->{Preview} ) {
<link rel="stylesheet" href="<% RT->Config->Get('WebPath') %>/static/css/elevator/mail.css" type="text/css" media="all" />
% }
26 changes: 16 additions & 10 deletions lib/RT/Extension/TerminalTheme.pm
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,21 @@ use strict;
use warnings;
package RT::Extension::TerminalTheme;

our $VERSION = '0.01';
our $VERSION = '0.02';

=head1 NAME

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<read more|https://bestpractical.com/blog/2021/1/terminal-theme-for-rt5> about
this theme on the L<Best Practical blog|https://bestpractical.com/blog>.
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<data-bs-theme> mechanism.

=head1 RT VERSION

Works with RT 5.
Works with RT 6.

=head1 INSTALLATION

Expand All @@ -31,15 +30,22 @@ Works with RT 5.

May need root permissions.

=item Edit your F</opt/rt5/etc/RT_SiteConfig.pm>
=item Edit your F</opt/rt6/etc/RT_SiteConfig.pm>

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

Expand All @@ -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:

Expand Down
Loading