diff options
-rw-r--r-- | .build.yml | 17 | ||||
-rw-r--r-- | .ruby-version | 1 | ||||
-rw-r--r-- | Makefile | 11 | ||||
-rw-r--r-- | README.md | 6 | ||||
-rw-r--r-- | _config.yml | 21 | ||||
-rwxr-xr-x | barf | 158 | ||||
-rw-r--r-- | footer.html | 5 | ||||
-rw-r--r-- | header.html | 5 | ||||
-rw-r--r-- | index.md | 2 | ||||
-rw-r--r-- | pages/browsers.md | 15 | ||||
-rw-r--r-- | pages/extras.md | 13 | ||||
-rw-r--r-- | pages/posts.md | 1 | ||||
-rw-r--r-- | pages/web-hosting.md | 5 | ||||
-rw-r--r-- | wruby.rb | 150 |
14 files changed, 228 insertions, 182 deletions
@@ -1,8 +1,8 @@ image: alpine/latest oauth: pages.sr.ht/PAGES:RW packages: -- rsync -- coreutils +- ruby +- ruby-dev - go - hut environment: @@ -10,16 +10,13 @@ site: jsfree.org sources: - https://git.sr.ht/~bt/jsfree.org tasks: -- install-smu: | - git clone https://git.sr.ht/~bt/smu - cd smu - sudo make - sudo make install +- install-gems: | + sudo gem install bundler 'kramdown:2.4.0' 'rss:0.3.0' - build: | - cd jsfree.org - make build + cd wruby + sudo make build - package: | cd jsfree.org/build tar -cvz . > ../../site.tar.gz - upload: | - hut pages publish -d jsfree.org site.tar.gz
\ No newline at end of file + hut pages publish -d jsfree.org site.tar.gz diff --git a/.ruby-version b/.ruby-version new file mode 100644 index 0000000..619b537 --- /dev/null +++ b/.ruby-version @@ -0,0 +1 @@ +3.3.3 @@ -1,13 +1,8 @@ build: - sh ./barf - rsync -r public/ build/public + rm -rf build && mkdir build + ruby wruby.rb clean: rm -rf build/* -watch: - while true; do \ - ls -d .git/* * posts/* pages/* header.html | entr -cd make ;\ - done - -.PHONY: build clean watch +.PHONY: build clean @@ -5,7 +5,9 @@ The main website and project for jsfree.org [jsfree.org](https://jsfree.org) -contributing +Built with [wruby](https://wruby.btxx.org) + +Contributing ------------ -Submit changes, patches or suggestions via email [here](mailto:jsfree@patches.btxx.org) +Submit changes, patches or suggestions [here](https://lists.sr.ht/~bt/jsfree-devel) diff --git a/_config.yml b/_config.yml new file mode 100644 index 0000000..ea5e802 --- /dev/null +++ b/_config.yml @@ -0,0 +1,21 @@ +site_url: 'https://jsfree.org' +site_name: 'jsfree.org' +author_name: 'Bradley Taunt' + +directories: + posts: 'posts' + pages: 'pages' + public: 'public' + output: 'build' + posts_output: 'build/posts' + pages_output: 'build/' + +files: + header: 'header.html' + footer: 'footer.html' + root_index: 'index.md' + posts_index: 'pages/posts.md' + rss: 'build/index.rss' + +misc: + post_count: 5 @@ -1,158 +0,0 @@ -#!/bin/sh - -domain="https://jsfree.org" - -# Check the operating system -os_name=$(uname -s) - -if [ "$os_name" = "OpenBSD" ]; then - alias sed=gsed - alias date=gdate - alias rsync=openrsync -elif [ "$os_name" = "Darwin" ]; then - alias sed=gsed - alias date=gdate -fi - -set -eu -MARKDOWN=smu -IFS=' ' - -# Create tab separated file with filename, title, creation date, last update -index_tsv() { - for f in "$1"/*.md - do - title=$(sed -n '/^# /{s/# //p; q}' "$f") - printf '%s\t%s\t%s\t%s\n' "$f" "${title:="No Title"}" - done -} - -index_html() { - # Print header - title=$(sed -n '/^# /{s/# //p; q}' index.md) - sed "s/{{TITLE}}/$title/" header.html - - # Intro text - $MARKDOWN index.md - - echo "<ul>" - - # Posts - while read -r f title created; do - link=$(echo "$f" | sed -E 's|.*/(.*).md|\1/|') - created=$(echo $(head -3 "$f" | tail -1)) - echo "<li>$created · <a href=\"$link\">$title</a></li>" - done < "$1" | sort -r - - echo "</ul>" - - # Print footer after post list - cat footer.html -} - -atom_xml() { - uri=$(sed -rn '/atom.xml/ s/.*href="([^"]*)".*/\1/ p' header.html) - first_commit_date=$(git log --pretty='format:%ai' . | cut -d ' ' -f1 | tail -1) - - cat <<EOF -<?xml version="1.0" encoding="utf-8"?> -<feed xmlns="http://www.w3.org/2005/Atom"> - <title>$(sed -n '/^# /{s/# //p; q}' index.md)</title> - <link href="$domain/atom.xml" rel="self" /> - <updated>$(date +%FT%TZ)</updated> - <author> - <name>$(git config user.name)</name> - </author> - <id>$domain,$first_commit_date:default-atom-feed/</id> -EOF - - while read -r f title created; do - - content=$($MARKDOWN "$f" | sed 's/&/\&/g; s/</\</g; s/>/\>/g; s/"/\"/g; s/'"'"'/\'/g') - post_link=$(echo "$f" | sed -E 's|posts/(.*).md|\1|') - basic_date=$(echo $(head -3 "$f" | tail -1)) - published_date=$(date -d $basic_date -u +%Y-%m-%dT10:%M:%SZ) - - cat <<EOF - <entry> - <title>$title</title> - <content type="html">$content</content> - <link href="$domain/$post_link"/> - <id>$domain/$post_link</id> - <updated>$published_date</updated> - <published>$published_date</published> - </entry> -EOF - done < "$1" - - echo '</feed>' -} - -rss_xml() { - uri=$(sed -rn '/rss.xml/ s/.*href="([^"]*)".*/\1/ p' header.html) - first_commit_date=$(git log --pretty='format:%ai' . | cut -d ' ' -f1 | tail -1) - - cat <<EOF -<?xml version="1.0" encoding="utf-8"?> -<rss version="2.0"> - <channel> - <title>$(sed -n '/^# /{s/# //p; q}' index.md)</title> - <link>$domain/rss.xml</link> - <description>Feed description here</description> - <lastBuildDate>$(date -u +"%a, %d %b %Y %H:%M:%S %z")</lastBuildDate> - <pubDate>$(date -u +"%a, %d %b %Y %H:%M:%S %z")</pubDate> - <generator>Custom RSS Generator</generator> - <ttl>1800</ttl> -EOF - - while read -r f title created; do - content=$($MARKDOWN "$f" | sed 's/&/\&/g; s/</\</g; s/>/\>/g; s/"/\"/g; s/'"'"'/\'/g') - post_link=$(echo "$f" | sed -E 's|posts/(.*).md|\1|') - basic_date=$(echo $(head -3 "$f" | tail -1)) - published_date=$(date -d "$basic_date" -u +"%a, %d %b %Y %H:%M:%S %z") - - cat <<EOF - <item> - <title>$title</title> - <description>$content</description> - <link>$domain/$post_link</link> - <guid isPermaLink="false">$domain/$post_link</guid> - <pubDate>$published_date</pubDate> - </item> -EOF - done < "$1" - - echo '</channel>' - echo '</rss>' -} - -write_page() { - filename=$1 - directory=$(echo $(basename "$filename" .md)) - $(mkdir -p build/$directory) - target=$(echo "$filename" | sed -r 's|\w+/(.*).md|build/\1/index.html|') - created=$(echo $(head -3 "$filename" | tail -1)) - title=$2 - - $MARKDOWN "$filename" | \ - cat header.html - |\ - sed "s|{{TITLE}}|$title|" \ - > "$target" && cat footer.html >> "$target" -} - -rm -rf build && mkdir build - -# Blog posts -index_tsv posts | sort -rt " " -k 3 > build/posts.tsv -index_html build/posts.tsv > build/index.html -atom_xml build/posts.tsv > build/atom.xml -rss_xml build/posts.tsv > build/rss.xml -while read -r f title created; do - write_page "$f" "$title" "$created" -done < build/posts.tsv - -# Pages -index_tsv pages > build/pages.tsv -while read -r f title created; do - write_page "$f" "$title" "$created" -done < build/pages.tsv diff --git a/footer.html b/footer.html index 894338a..2c8db87 100644 --- a/footer.html +++ b/footer.html @@ -1,7 +1,7 @@ <footer role="contentinfo"> <br> <hr> - <p>→ <a href="https://git.btxx.org/jsfree">Help edit or improve this project</a>.</p> + <p>→ <a href="https://git.sr.ht/~bt/jsfree.org">Help edit or improve this project</a>.</p> <hr> <h2 id="menu">Menu Navigation</h2> <ul> @@ -10,6 +10,7 @@ <li><a href="/code-forges">Code Forges</a></li> <li><a href="/domains">Domain Registrars</a></li> <li><a href="/email">Email</a></li> + <li><a href="/extras">Extras</a></li> <li><a href="/forums">Forums</a></li> <li><a href="/games">Games</a></li> <li><a href="/search-engines">Search Engines</a></li> @@ -19,7 +20,7 @@ <li><a href="/web-hosting">Web Hosting</a></li> </ul> <small> - Built with <a href="https://git.sr.ht/~bt/barf">barf</a>. <br> + Built with <a href="https://git.sr.ht/~bt/wruby">wruby</a>. <br> Hosted on <a href="https://sourcehut.org">sourcehut</a>. <br> The <a href="https://git.sr.ht/~bt/jsfree.org">code for this site</a> is <a href="https://git.sr.ht/~bt/jsfree.org/tree/master/item/LICENSE">MIT</a>. </small> diff --git a/header.html b/header.html index 197f71e..24e5d50 100644 --- a/header.html +++ b/header.html @@ -3,10 +3,13 @@ <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> + <meta name="color-scheme" content="dark light"> <link rel="icon" href="data:,"> <title>{{TITLE}}</title> <link href="https://jsfree.org/atom.xml" type="application/atom+xml" rel="alternate" title="Atom feed for blog posts" /> - <style>*{box-sizing:border-box;}body{font-family:sans-serif;line-height:1.33;margin:0 auto;max-width:650px;padding:1rem;}img{max-width:100%;}pre{overflow:auto;}abbr{background:yellow;color:blue;cursor:help;}nav a.menu{float:right;}.logo{display:block;max-width:60px;}</style> + <style>*{box-sizing:border-box;}body{font-family:sans-serif;line-height:1.33;margin:0 +auto;max-width:650px;padding:1rem;}blockquote{border-left:4px + solid;padding-left:5px;}img{max-width:100%;}pre{border:1px solid;overflow:auto;padding:5px;}table{text-align:left;width:100%;}.posts,#menu{list-style:none;padding:0;}.posts li{margin-bottom:8px;}.posts li span{display:block;font-size:90%;}#menu li{display:inline-block;margin-right:8px;}.footnotes{font-size:90%;}abbr{background:yellow;color:blue;cursor:help;}nav a.menu{float:right;}.logo{display:block;max-width:60px;}</style> </head> <nav> @@ -25,4 +25,4 @@ Things you can do to contribute to the project (in order of importance): ## News -You can keep up-to-date by following the <a href="/atom.xml">Atom feed</a>. +You can keep up-to-date by following the <a href="/index.rss">RSS feed</a>. diff --git a/pages/browsers.md b/pages/browsers.md index beed278..6002dea 100644 --- a/pages/browsers.md +++ b/pages/browsers.md @@ -24,6 +24,21 @@ This page is a collection of web browsers that have JavaScript disabled by defau </dl> <dl> + <dt><a href="https://github.com/acg/w3m">W3M</a></dt> + <dd>A text-based, TUI web browser.</dd> +</dl> + +<dl> + <dt><a href="https://lynx.browser.org/">Lynx</a></dt> + <dd>A text browser for the World Wide Web.</dd> +</dl> + +<dl> + <dt><a href="http://links.twibright.com/">Links</a></dt> + <dd>A text and graphic web browser.</dd> +</dl> + +<dl> <dt><a href="https://github.com/ocoufal/mothra">Mothra</a></dt> <dd>A lightweight web browser for Plan 9.</dd> </dl> diff --git a/pages/extras.md b/pages/extras.md new file mode 100644 index 0000000..a382e68 --- /dev/null +++ b/pages/extras.md @@ -0,0 +1,13 @@ +# Extras + +This page is a collection of software that falls outside the other main categories (that all work without JavaScript) + +<dl> + <dt><a href="https://plaintextsports.com/">Plain Text Sports</a></dt> + <dd>Sports scores rendered in plain text.</dd> +</dl> + +<dl> + <dt><a href="https://wttr.in/">wttr.in</a></dt> + <dd>Weather information rendered in plain text.</dd> +</dl>
\ No newline at end of file diff --git a/pages/posts.md b/pages/posts.md new file mode 100644 index 0000000..ef3567d --- /dev/null +++ b/pages/posts.md @@ -0,0 +1 @@ +# Posts diff --git a/pages/web-hosting.md b/pages/web-hosting.md index c329772..57f4d6b 100644 --- a/pages/web-hosting.md +++ b/pages/web-hosting.md @@ -6,3 +6,8 @@ This page is a collection of web hosting providers that work without JavaScript. <dt><a href="https://nearlyfreespeech.net">NearlyFreeSpeech.net</a></dt> <dd>The masters of only pay for what you use hosting since 2002.</dd> </dl> + +<dl> + <dt><a href="https://bitfolk.com/">bitfolk</a></dt> + <dd>No-nonsense VPS host. Reliable, feature-rich and affordable virtual private servers.</dd> +</dl> diff --git a/wruby.rb b/wruby.rb new file mode 100644 index 0000000..446d83f --- /dev/null +++ b/wruby.rb @@ -0,0 +1,150 @@ +require 'bundler/inline' +gemfile do + gem 'kramdown', '2.4.0' + gem 'rss', '0.3.0' +end + +require 'kramdown' +require 'fileutils' +require 'date' +require 'rss' +require 'find' +require 'yaml' + +# Load configuration +config = YAML.load_file('_config.yml') + +site_url = config['site_url'] +site_name = config['site_name'] +author_name = config['author_name'] + +posts_dir = config['directories']['posts'] +pages_dir = config['directories']['pages'] +public_dir = config['directories']['public'] +output_dir = config['directories']['output'] +posts_output_dir = config['directories']['posts_output'] +pages_output_dir = config['directories']['pages_output'] + +header_file = config['files']['header'] +footer_file = config['files']['footer'] +root_index_file = config['files']['root_index'] +posts_index_file = config['files']['posts_index'] +rss_file = config['files']['rss'] + +post_count = config['misc']['post_count'] + +# Make sure output directories exist +[posts_output_dir, pages_output_dir].each { |dir| FileUtils.mkdir_p(dir) } + +# Read the footer content +footer_content = File.read(footer_file) + +# Replace the title meta tag in the header.html +def replace_title_placeholder(header_content, title) + header_content.gsub('<title>{{TITLE}}</title>', "<title>#{title}</title>") +end + +# Grab the title from each markdown file +def extract_title_from_md(lines) + first_line = lines.first + first_line&.start_with?('# ') ? first_line[2..-1].strip : 'Blog Index' +end + +# Convert markdown files +def process_markdown_files(input_directory, output_directory, header_content, footer_content) + items = [] + + Find.find(input_directory) do |path| + next unless path =~ /\.md\z/ + + md_content = File.read(path) + lines = md_content.lines + + title = extract_title_from_md(lines) + date = Date.parse(lines[2]&.strip || '') rescue Date.today + html_content = Kramdown::Document.new(md_content).to_html + + relative_path = path.sub(input_directory + '/', '').sub('.md', '') + item_dir = File.join(output_directory, relative_path) + output_file = "#{item_dir}/index.html" + FileUtils.mkdir_p(item_dir) + + header = replace_title_placeholder(header_content, title) + File.write(output_file, header + html_content + footer_content) + + items << { title: title, date: date, link: relative_path + '/', content: html_content } + end + + items +end + +# Create the root index file +def generate_index(posts, header_content, footer_content, root_index_file, post_count, output_dir, posts_dir) + root_index_content = File.read(root_index_file) + root_title = extract_title_from_md(root_index_content.lines) + root_html = Kramdown::Document.new(root_index_content).to_html + + header = replace_title_placeholder(header_content, root_title) + + index_content = header + root_html + "<ul class=\"posts\">\n" + posts.first(post_count).each { |post| index_content << "<li><span>#{post[:date]}</span><a href='/#{posts_dir}/#{post[:link]}'>#{post[:title]}</a></li>\n" } + index_content << "</ul>\n<p><a href='/#{posts_dir}'>View all posts →</a></p>\n" + footer_content + + File.write("#{output_dir}/index.html", index_content) +end + +# Create the full posts list page +def generate_full_posts_list(posts, header_content, footer_content, posts_index_file, output_dir, posts_dir) + posts_index_content = File.read(posts_index_file) + posts_title = extract_title_from_md(posts_index_content.lines) + posts_html = Kramdown::Document.new(posts_index_content).to_html + + header = replace_title_placeholder(header_content, posts_title) + + list_content = header + posts_html + "<ul class=\"posts\">\n" + posts.each { |post| list_content << "<li><span>#{post[:date]}</span><a href='/#{posts_dir}/#{post[:link]}'>#{post[:title]}</a></li>\n" } + list_content << "</ul>\n" + footer_content + + File.write("#{output_dir}/posts/index.html", list_content) +end + +# Generate the RSS 2.0 feed +def generate_rss(posts, rss_file, author_name, site_name, site_url, posts_dir) + rss = RSS::Maker.make("2.0") do |maker| + maker.channel.author = author_name + maker.channel.updated = Time.now.to_s + maker.channel.title = "#{site_name} RSS Feed" + maker.channel.description = "The official RSS Feed for #{site_url}" + maker.channel.link = site_url + + posts.each do |post| + date = Date.parse(post[:date].to_s).to_time + 12*60*60 # Force time to midday + item_link = "#{site_url}/#{posts_dir}/#{post[:link]}" + item_title = post[:title] + item_content = post[:content] + + maker.items.new_item do |item| + item.link = item_link + item.title = item_title + item.updated = date.to_s + item.pubDate = date.rfc822 + item.description = item_content + end + end + end + + File.write(rss_file, rss) +end + +# Process header, posts, pages, etc. +header_content = File.read(header_file) + +posts = process_markdown_files(posts_dir, posts_output_dir, header_content, footer_content).sort_by { |post| -post[:date].to_time.to_i } +pages = process_markdown_files(pages_dir, pages_output_dir, header_content, footer_content) + +generate_index(posts, header_content, footer_content, root_index_file, post_count, output_dir, posts_dir) +generate_full_posts_list(posts, header_content, footer_content, posts_index_file, output_dir, posts_dir) +FileUtils.cp_r(public_dir, output_dir) +generate_rss(posts, rss_file, author_name, site_name, site_url, posts_dir) + +puts "Blog built successfully in '#{output_dir}' folder. Have a great day!" |