From faf9aec11bf8a462ec33c690cb831a6badef6106 Mon Sep 17 00:00:00 2001
From: Frederik Vanrenterghem <frederik@vanrenterghem.biz>
Date: Thu, 15 Jun 2023 21:09:48 +0800
Subject: [PATCH] Add ikistrap plugin for ikistrap theme.

Source: https://github.com/gsliepen/ikistrap/blob/master/lib/IkiWiki/Plugin/ikistrap.pm
---
 IkiWiki/Plugin/ikistrap.pm | 120 +++++++++++++++++++++++++++++++++++++
 1 file changed, 120 insertions(+)
 create mode 100644 IkiWiki/Plugin/ikistrap.pm

diff --git a/IkiWiki/Plugin/ikistrap.pm b/IkiWiki/Plugin/ikistrap.pm
new file mode 100644
index 000000000..c67d83003
--- /dev/null
+++ b/IkiWiki/Plugin/ikistrap.pm
@@ -0,0 +1,120 @@
+#!/usr/bin/perl
+package IkiWiki::Plugin::ikistrap;
+
+use warnings;
+use strict;
+use IkiWiki 3.00;
+
+sub import {
+	hook(type => "checkconfig", id => "ikistrap", call => \&checkconfig);
+	hook(type => "getsetup", id => "ikistrap", call => \&getsetup);
+	hook(type => "refresh", id => "ikistrap", call => \&refresh);
+	hook(type => "pagetemplate", id => "ikistrap", call => \&pagetemplate);
+	hook(type => "preprocess", id => "progress", call => \&progress);
+}
+
+sub checkconfig() {
+        if (! defined $config{bootstrap_js}) {
+                $config{bootstrap_js} = 1;
+        }
+}
+
+sub getsetup() {
+	return
+		plugin => {
+			description => "Bootstrap 5 theme support",
+			section => "web",
+			safe => 1,
+		},
+		bootstrap_local => {
+			description => "Install Bootstrap css and js files locally instead of using jsDelivr?",
+			example => 0,
+			type => "boolean",
+			default => 0,
+			rebuild => 1,
+		},
+		bootstrap_js => {
+			description => "Load Bootstrap's Javascript helpers?",
+			example => 0,
+			type => "boolean",
+			default => 1,
+			rebuild => 1,
+		}
+}
+
+sub check($$) {
+	my($basename, $href) = @_;
+	my $filename = "$config{destdir}/$basename";
+	return if(-e $filename);
+	debug("Fetching missing $basename...");
+	system("/usr/bin/curl -# \"$href\" -o \"$filename\"");
+}
+
+sub refresh() {
+	return 0 unless($config{bootstrap_local});
+	mkdir("$config{destdir}");
+
+	# CSS
+	mkdir("$config{destdir}/css");
+	check("css/bootstrap.min.css", "https://cdn.jsdelivr.net/npm/bootstrap\@5.0.0/dist/css/bootstrap.min.css");
+        check("css/bootstrap-icons.css", "https://cdn.jsdelivr.net/npm/bootstrap-icons\@1.4.1/font/bootstrap-icons.css");
+
+	# Fonts
+	mkdir("$config{destdir}/css/fonts");
+	check("css/fonts/bootstrap-icons.woff2", "https://cdn.jsdelivr.net/npm/bootstrap-icons\@1.4.1/font/fonts/bootstrap-icons.woff2");
+
+	# JavaScript (if enabled)
+	return 0 unless($config{bootstrap_js});
+	mkdir("$config{destdir}/js");
+	check("js/bootstrap.bundle.min.js", "https://cdn.jsdelivr.net/npm/bootstrap\@5.0.0/dist/js/bootstrap.bundle.min.js");
+}
+
+sub pagetemplate(@) {
+	my %params = @_;
+	my $template = $params{template};
+
+	$template->param(bootstrap_js => $config{bootstrap_js});
+	$template->param(bootstrap_local => $config{bootstrap_local});
+}
+
+# Emulate the progress plugin, but do it the HTML5 + Bootstrap way.
+# Also allow setting an extra class attribute.
+sub progress(@) {
+	my %params = @_;
+	my $percentage_pattern = qr/[0-9]+\%?/; # pattern to validate percentages
+	my ($fill, $value, $max);
+
+	if (defined $params{percent}) {
+		$fill = $params{percent};
+		($fill) = $fill =~ m/($percentage_pattern)/; # fill is untainted now
+		$fill =~ s/%$//;
+		if (! defined $fill || ! length $fill || $fill > 100 || $fill < 0) {
+			error(sprintf(gettext("illegal percent value %s"), $params{percent}));
+		}
+		$value = $fill;
+		$max = "100";
+		$fill .= "%";
+	} elsif (defined $params{totalpages} and defined $params{donepages}) {
+		$max = pagespec_match_list($params{page}, $params{totalpages}, deptype => deptype("presence"));
+		$value = pagespec_match_list($params{page}, $params{donepages}, deptype => deptype("presence"));
+
+		if ($max == 0) {
+			$fill = "100%";
+		} else {
+			$fill = sprintf("%u%%", $value / $max * 100);
+		}
+	} else {
+		error(gettext("need either `percent` or `totalpages` and `donepages` parameters"));
+	}
+
+	my $class = "progress-bar";
+	if (defined $params{class}) {
+		$class .= " $params{class}";
+	}
+
+	return <<EODIV
+<p><div class="progress"><div class="$class" role="progressbar" style="width: $value%" aria-valuenow="$value" aria-valuemin="0" aria-valuemax="$max">$fill</div></div></p>
+EODIV
+}
+
+1
-- 
2.39.5