LICENSE => 'AGPL_3',
SIGN => 1,
clean => {
- FILES => 'static/css/ static/js.js static/js.js.gz css/logos.css static/logos.png static/js.map static/js/'
- FILES => 'static/css/ static/js/'
++ FILES => 'static/css/ static/js/ css/logos.css static/logos.png'
},
BUILD_REQUIRES => {
qw/CSS::Minifier::XS 0
+ CSS::SpriteMaker 0
File::Slurp 0
- JavaScript::Minifier::XS 0
Test::MockTime 0
Test::More 0
Test::WWW::Mechanize::PSGI 0/,
word-break: break-all;
}
- ul.list-inline {
- display: inline-block;
+ #themes {
+ margin-left: 0;
+ }
+
+ #themes:before {
+ content: " Themes: ";
-}
+}
- (function(){
- 'use strict';
-
- $( document ).ready(function(){
- if(window.innerWidth >= 768)
- return;
- $('#title').before('<div class="text-center">Tap title to toggle menu</div>');
- $('nav').addClass('hidden');
- $('#title,#logo').on('click', function () {
- $('nav').toggleClass('hidden');
- });
- });
- })();
+ $(function(){
+ if(window.innerWidth >= 768)
+ return;
+ $('#title')[0].insertAdjacentHTML('beforebegin', '<div class="text-center">Tap title to toggle menu</div>');
+ $('nav')[0].classList.add('hidden');
- $('#title').on('click', () => $('nav')[0].classList.toggle('hidden'));
++ $('#title,#logo').on('click', () => $('nav')[0].classList.toggle('hidden'));
+ });
--- /dev/null
- (function(){
- 'use strict';
-
- $( document ).ready(function(){
- $('#sponsors').detach().appendTo($('#sidebar'));
- });
- })();
++$(() => $('#sidebar')[0].appendChild($('#sponsors')[0]));
- (function(){
- 'use strict';
+ const NAVS = {
+ home: /^\/$/,
+ pb: /^\/(?:pb|sol)\//,
+ ct: /^\/(?:ct|st|ed)\//,
+ log: /^\/log\//,
+ us: /^\/us\//,
+ account: /^\/account$/,
+ contribute: /^\/contribute$/,
++ about: /^\/about$/,
+ };
- var NAVS = {
- 'home': /^\/$/,
- 'pb': /^\/(?:pb|sol)\//,
- 'ct': /^\/(?:ct|st|ed)\//,
- 'log': /^\/log\//,
- 'us': /^\/us\//,
- 'account': /^\/account$/,
- 'contribute': /^\/contribute$/,
- 'about': /^\/about$/,
- };
-
- $( document ).ready(function(){
- var path = location.pathname;
- for (var nav in NAVS)
- if(path.match(NAVS[nav])) {
- $('#nav-' + nav).addClass('active');
- break;
- }
- });
- })();
+ $(function(){
+ let path = location.pathname;
+ for (let nav in NAVS)
+ if(path.match(NAVS[nav]))
+ $('#nav-' + nav)[0].classList.add('active');
+ });
- (function(){
- 'use strict';
- function set_style(name){
- $('link[rel~="stylesheet"]').prop('disabled', true);
- $('link[title="' + name + '"]').prop('disabled', false);
- localStorage.setItem("theme", name);
- $(document).ready(function() {
- if(name == 'slate' || name == 'cyborg')
- $('.logo').removeClass('logo-light');
- else
- $('.logo').addClass('logo-light');
- });
- }
-
- var selector;
-
- function add_themelink(theme, text) {
- var link = $('<a role="button">' + text + '</a>');
- link.appendTo(selector.find('ul')).wrap('<li>').on('click', function () { set_style(theme) });
- }
-
- $( document ).ready(function() {
- selector = $('<div>Themes: <ul class="list-inline"></ul></div>');
- add_themelink('cyborg', 'Black');
- add_themelink('slate', 'Grey');
- add_themelink('readable', 'White');
- $('#sidebar').prepend(selector);
+ function set_style(name){
+ $('link[rel~="stylesheet"]').each(e => e.disabled = true);
+ $('link[title="' + name + '"]')[0].disabled = false;
+ localStorage.setItem("theme", name);
++ $(function() {
++ if(name == 'slate' || name == 'cyborg')
++ $('.logo').each(e => e.classList.remove('logo-light'));
++ else
++ $('.logo').each(e => e.classList.add('logo-light'));
+ });
+ }
+
+ $(function() {
+ var theme_ul = '<ul class="list-inline" id="themes">' +
+ '<li><a role="button" data-theme="cyborg">Black</a>' +
+ '<li><a role="button" data-theme="slate">Grey</a>' +
+ '<li><a role="button" data-theme="readable">White</a></ul>';
+ var sidebar = $('#sidebar')[0];
+ sidebar.insertBefore(m(theme_ul), sidebar.firstChild);
+ $('#themes a').on('click', e => set_style(e.target.dataset.theme));
+ });
- var theme = localStorage.getItem("theme");
- if(theme) {
- if(theme == "cerulean" || theme == "cosmo")
- theme = "readable";
- set_style(theme);
- }
- })();
+ let theme = localStorage.getItem("theme");
+ if(theme) {
+ if(theme == "cerulean" || theme == "cosmo")
+ theme = "readable";
+ set_style(theme);
+ }
--- /dev/null
- (function(){
- 'use strict';
-
- $( document ).ready(function() {
- $('#webchat').prependTo('#sidebar');
- });
- })();
++$(() => $('#sidebar')[0].insertBefore($('#webchat')[0], $('#sidebar')[0].firstChild));
use warnings;
use CSS::Minifier::XS qw//;
- use JavaScript::Minifier::XS qw//;
+use CSS::SpriteMaker;
+ use Digest::SHA qw/sha256_base64/;
use IO::Compress::Gzip qw/gzip/;
- use File::Slurp qw/read_file write_file/;
+ use File::Slurp qw/read_file write_file edit_file_lines/;
mkdir 'static';
mkdir 'static/css';
+ mkdir 'static/js';
+sub make_sprite {
+ my $maker = Local::CSS::SpriteMaker->new(
+ css_class_prefix => 'logo-',
+ rc_override_classname => sub {
+ my ($name) = @_;
+ $name =~ s/-light/.logo-light/r;
+ }
+ );
+
+ $maker->make_sprite(
+ source_images => ['logos/'],
+ target_file => 'static/logos.png',
+ add_extra_padding => 10,
+ );
+
+ $maker->print_css(
+ filename => 'css/logos.css',
+ sprite_filename => '/static/logos.png',
+ );
+
+ system 'pngnq-s9', '-s1', 'static/logos.png';
+ system 'optipng', '-o7', '-zm1-9', 'static/logos-nq8.png';
+ rename 'static/logos-nq8.png', 'static/logos.png';
+}
+
sub gzip_file {
my ($file) = @_;
gzip $file => "$file.gz", -Level => 9, Minimal => 1;
}
sub make_js {
- if (-f 'compiler.jar') {
- system java => -jar => 'compiler.jar', qw,-O SIMPLE --create_source_map static/js.map --js_output_file static/js.js --language_in ECMASCRIPT5_STRICT --source_map_location_mapping js/|/static/js/,, <js/*>;
- my $js = read_file 'static/js.js';
- write_file 'static/js.js', '//# sourceMappingURL=/static/js.map', "\n", $js;
- system 'cp', '-rp', 'js', 'static/';
- } else {
- my $js;
- $js .= read_file $_ for <js/*.js>;
- write_file 'static/js.js', JavaScript::Minifier::XS::minify $js;
- }
- gzip_file 'static/js.js';
+ system java => -jar => 'compiler.jar', qw,-O SIMPLE --create_source_map static/js/js.map --js_output_file static/js/all.js --language_in ECMASCRIPT6_STRICT --language_out ECMASCRIPT5_STRICT --source_map_location_mapping js/|/static/js/,, <js/*>;
+ my $js = read_file 'static/js/all.js';
+ write_file 'static/js/all.js', '//# sourceMappingURL=/static/js/js.map', "\n", $js;
+ system 'cp', '-rp', 'js', 'static/';
+ gzip_file 'static/js/all.js';
}
+my $sprite_mtime = -M 'static/logos.png' // 0;
+for (<logos/*>) {
+ if (!$sprite_mtime || $sprite_mtime > -M) {
+ make_sprite;
+ last
+ }
+}
+
my $css_mtime = -M 'static/css/slate.css' // 0;
for (<css/*>, <css/themes/*>) {
if (!$css_mtime || $css_mtime > -M) {
}
}
-} 'tmpl/skel.en'
+ edit_file_lines {
+ my ($file) = m,(static.*\.(?:css|js)),;
+ return unless $file;
+ my $hash = sha256_base64 scalar read_file $file;
+ s/integrity=".*"/integrity="sha256-$hash="/;
++} 'tmpl/skel.en';
++
+package
+ Local::CSS::SpriteMaker;
+
+use parent qw/CSS::SpriteMaker/;
+
+sub _get_stylesheet_string {
+ my $self = shift;
+ my @ret = split "\n", $self->SUPER::_get_stylesheet_string(@_);
+ shift @ret;
+ @ret = sort @ret;
+ unshift @ret, <<EOF;
+a.logo {
+ background-image: url("/static/logos.png");
+ background-repeat: no-repeat;
+ display: inline-block;
+ vertical-align: middle;
+}
+EOF
+ join "\n", @ret;
+}
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
-<link href="/static/css/cyborg.css" title="cyborg" rel="stylesheet" integrity="x">
-<link href="/static/css/slate.css" title="slate" rel="alternate stylesheet" integrity="x">
+<link href="/static/favicon.png" rel="shortcut icon">
- <link href="/static/css/cyborg.css" title="cyborg" rel="alternate stylesheet">
- <link href="/static/css/slate.css" title="slate" rel="stylesheet">
- <link href="/static/css/readable.css" title="readable" rel="alternate stylesheet">
- <script src="/static/js.js" type="text/javascript" async defer></script>
++<link href="/static/css/cyborg.css" title="cyborg" rel="alternate stylesheet" integrity="x">
++<link href="/static/css/slate.css" title="slate" rel="stylesheet" integrity="x">
+ <link href="/static/css/readable.css" title="readable" rel="alternate stylesheet" integrity="x">
+ <script src="/static/js/all.js" type="text/javascript" async defer integrity="x"></script>
<body>
<div class="container-fluid">