initial commit
This commit is contained in:
commit
6e470cd78f
8 changed files with 223 additions and 0 deletions
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
icon-cache/
|
||||||
|
links.json
|
||||||
|
newtab.html
|
15
README.md
Normal file
15
README.md
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
## NewTabber
|
||||||
|
|
||||||
|
Simple script I use to generate my [static new tab page](https://static.sitosis.com/newtab.html).
|
||||||
|
|
||||||
|
### Usage
|
||||||
|
|
||||||
|
Create a `links.json` containing the links you want. See `links.json.example` for an example. The `icon` attribute is the name of the [Bootstrap icon](https://icons.getbootstrap.com/) to use. Each icon used is initially fetched from the web and then cached locally in an `icon-cache` directory for future uses.
|
||||||
|
|
||||||
|
You can also edit the files in `templates` and some of the variables defined at the top of `generate.pl` to customize the look and behavior of the page.
|
||||||
|
|
||||||
|
Then simply run the `generate.pl` script. It will create or overwrite an existing `newtab.html` in the same directory.
|
||||||
|
|
||||||
|
### Installation
|
||||||
|
|
||||||
|
You'll need to install Perl, plus the Perl modules `utf8`, `JSON`, `LWP::UserAgent`, `LWP::Protocol::https`, and `Storable` either from CPAN or using your distribution's package manager.
|
80
generate.pl
Executable file
80
generate.pl
Executable file
|
@ -0,0 +1,80 @@
|
||||||
|
#!/usr/bin/env perl
|
||||||
|
|
||||||
|
use utf8;
|
||||||
|
use strict;
|
||||||
|
use warnings;
|
||||||
|
use open qw(:std :utf8);
|
||||||
|
use JSON qw(decode_json);
|
||||||
|
use LWP::UserAgent;
|
||||||
|
use Storable qw(store retrieve);
|
||||||
|
|
||||||
|
## CONFIG
|
||||||
|
my $icons_per_line = 5;
|
||||||
|
## END CONFIG
|
||||||
|
|
||||||
|
open my $links_file, '<', 'links.json';
|
||||||
|
my $links = decode_json(join('', <$links_file>));
|
||||||
|
close $links_file;
|
||||||
|
|
||||||
|
open my $newtab, '>', 'newtab.html';
|
||||||
|
|
||||||
|
open my $header, '<', 'template/header.html'
|
||||||
|
or die "couldn't open template/header.html";
|
||||||
|
print $newtab join('', <$header>);
|
||||||
|
close $header;
|
||||||
|
|
||||||
|
open my $link_template_file, '<', 'template/link.html'
|
||||||
|
or die "couldn't open template/link.html";
|
||||||
|
my $link_template = join('', <$link_template_file>);
|
||||||
|
close $link_template_file;
|
||||||
|
|
||||||
|
my $ua = LWP::UserAgent->new();
|
||||||
|
$ua->agent('Mozilla/5.0 (X11; Linux x86_64; rv:107.0) Gecko/20100101 Firefox/107.0');
|
||||||
|
|
||||||
|
my $link_counter = 0;
|
||||||
|
foreach my $link(@{$links}) {
|
||||||
|
my $link_html = $link_template;
|
||||||
|
$link_html =~ s/\{\{title\}\}/$link->{title}/g;
|
||||||
|
$link_html =~ s/\{\{url\}\}/$link->{url}/g;
|
||||||
|
|
||||||
|
if(! -d 'icon-cache') {
|
||||||
|
mkdir 'icon-cache';
|
||||||
|
}
|
||||||
|
if (! -e "icon-cache/$link->{icon}") {
|
||||||
|
my $icon_url = "https://icons.getbootstrap.com/icons/$link->{icon}/";
|
||||||
|
my $resp = $ua->get($icon_url);
|
||||||
|
if(!$resp->is_success) {
|
||||||
|
my $status = $resp->status_line;
|
||||||
|
die "couldn't fetch icon $icon_url\n$status";
|
||||||
|
}
|
||||||
|
my $icon_full_html = $resp->decoded_content;
|
||||||
|
if($icon_full_html =~ /<div class="icon-demo [^>]+>[^<]*<svg [^>]+viewBox="([^"]+)"[^>]*>(.*?)<\/svg/s) {
|
||||||
|
my $icon = {viewBox => $1, paths => $2};
|
||||||
|
store($icon, "icon-cache/$link->{icon}")
|
||||||
|
or die "couldn't save icon-cache/$link->{icon}";
|
||||||
|
} else {
|
||||||
|
die "couldn't parse icon $link->{icon}";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
my $icon = retrieve("icon-cache/$link->{icon}");
|
||||||
|
|
||||||
|
$link_html =~ s/\{\{viewBox\}\}/$icon->{viewBox}/g;
|
||||||
|
$link_html =~ s/\{\{icon\}\}/$icon->{paths}/g;
|
||||||
|
|
||||||
|
print $newtab $link_html;
|
||||||
|
|
||||||
|
if(++$link_counter == $icons_per_line) {
|
||||||
|
open my $line_separator, '<', 'template/link_line_separator.html'
|
||||||
|
or die "couldn't open template/link_line_separator.html";
|
||||||
|
print $newtab join('', <$line_separator>);
|
||||||
|
close $line_separator;
|
||||||
|
$link_counter = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
open my $footer, '<', 'template/footer.html'
|
||||||
|
or die "couldn't open template/footer.html";
|
||||||
|
print $newtab join('', <$footer>);
|
||||||
|
close $footer;
|
||||||
|
|
||||||
|
close $newtab;
|
27
links.json.example
Normal file
27
links.json.example
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"title": "Hacker News",
|
||||||
|
"url": "https://hckrnews.com/",
|
||||||
|
"icon": "newspaper"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "Tildes",
|
||||||
|
"url": "https://tildes.net/",
|
||||||
|
"icon": "chat-dots"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "Nebula",
|
||||||
|
"url": "https://nebula.app/myshows",
|
||||||
|
"icon": "film"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "Twitch",
|
||||||
|
"url": "https://twitch.tv/",
|
||||||
|
"icon": "twitch"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "YouTube",
|
||||||
|
"url": "https://www.youtube.com/feed/subscriptions",
|
||||||
|
"icon": "youtube"
|
||||||
|
}
|
||||||
|
]
|
26
template/footer.html
Normal file
26
template/footer.html
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
</ul>
|
||||||
|
</section>
|
||||||
|
<section>
|
||||||
|
<form id='sform' method='post' action='https://s.rdsm.ca/search'>
|
||||||
|
<input type='text' id='search' name='q' placeholder='Search'>
|
||||||
|
</form>
|
||||||
|
</section>
|
||||||
|
</main>
|
||||||
|
<script>
|
||||||
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
|
const s = document.getElementById('search');
|
||||||
|
document.getElementById('sform').addEventListener('submit', (e) => {
|
||||||
|
let term = s.value;
|
||||||
|
if (/^[^\s]+\.(com|net|org|ca|us|io|cr|gov)(\/[^\s]*)?$/.test(term)) {
|
||||||
|
e.preventDefault();
|
||||||
|
if (!/^https?:\/\//.test(term)) {
|
||||||
|
term = 'https://' + term;
|
||||||
|
}
|
||||||
|
window.location.replace(term);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
s.focus();
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
60
template/header.html
Normal file
60
template/header.html
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
<!doctype html>
|
||||||
|
<html lang='en'>
|
||||||
|
<head>
|
||||||
|
<title>New Tab</title>
|
||||||
|
<meta charset='utf-8'>
|
||||||
|
<style>
|
||||||
|
html, body, main, section, ul, li, a, span, form, input {
|
||||||
|
border: none;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
ul {
|
||||||
|
list-style-type: none;
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
li {
|
||||||
|
float: left;
|
||||||
|
margin: 5px 10px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
li a {
|
||||||
|
text-decoration: none;
|
||||||
|
color: #313244;
|
||||||
|
}
|
||||||
|
li a span {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
li a svg {
|
||||||
|
height: 64px;
|
||||||
|
width: 64px;
|
||||||
|
}
|
||||||
|
body {
|
||||||
|
background-color: #11111b;
|
||||||
|
}
|
||||||
|
#container {
|
||||||
|
position: fixed;
|
||||||
|
display: block;
|
||||||
|
top: 50%;
|
||||||
|
left: 50%;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
}
|
||||||
|
input {
|
||||||
|
width: 100%;
|
||||||
|
background-color: #11111b;
|
||||||
|
border: 1px solid #313244;
|
||||||
|
border-radius: 5px;
|
||||||
|
line-height: 32px;
|
||||||
|
font-family: monospace;
|
||||||
|
font-size: 20px;
|
||||||
|
color: #313244;
|
||||||
|
margin-top: 20px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<main id='container'>
|
||||||
|
<section>
|
||||||
|
<ul>
|
8
template/link.html
Normal file
8
template/link.html
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
<li>
|
||||||
|
<a href='{{url}}' title='{{title}}'>
|
||||||
|
<svg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='currentColor' viewBox='{{viewBox}}'>
|
||||||
|
{{icon}}
|
||||||
|
</svg>
|
||||||
|
<span>{{title}}</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
4
template/link_line_separator.html
Normal file
4
template/link_line_separator.html
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
</ul>
|
||||||
|
</section>
|
||||||
|
<section>
|
||||||
|
<ul>
|
Reference in a new issue