diff options
51 files changed, 954 insertions, 797 deletions
@@ -1,5 +1,3 @@ /out/ -/www/ .tmp* -.var* !/out/ @@ -1,83 +1,33 @@ -SHELL = bash -o pipefail +MAKEFLAGS += -j1 -RUBYLIB=$(realpath .)/bin -export RUBYLIB +# Default target +all: out/index.html out/main.css +phony += all -# Usage: $(call patsubst,PATTERN1 PATTERN2...,REPLACEMENT,TEXT) -# -# Like $(patsubst), but takes multiple patterns that are all replaced -# with the same replacement. -patsubst-all = $(if $1,$(call patsubst-all,$(wordlist 2,$(words $1),$1),$2,$(patsubst $(firstword $1),$2,$3)),$3) - -# Which suffixes can we turn in to HTML? -html.suffixes = md org -# Find all source files with those suffixes -html.src = $(shell find src -type f \( -false $(foreach s,$(html.suffixes), -o -name '*.$s' ) \)) -# Translate the source filenames into output filenames -html.out = $(call patsubst-all,$(addprefix src/%.,$(html.suffixes)),out/%.html,$(html.src)) -html.dirs = $(sort $(patsubst src%,out%, \ - $(patsubst %/,%,$(dir $(html.src))) \ - $(shell find src -name index.yaml -printf '%h\n'))) -html.out += out/index.atom $(addsuffix /index.html,$(html.dirs)) - -all: $(html.out) out/main.css -.PHONY: all - -bin/page = bin/page bin/util.rb bin/pandoc.rb -bin/index = bin/index bin/util.rb bin/pandoc.rb - -out/%.html: src/%.md $(bin/page) bin/page.html.erb bin/write-atomic - @mkdir -p $(@D) - bin/page html $< | bin/write-atomic $@ -out/%.html: out/%.md $(bin/page) bin/page.html.erb bin/write-atomic - bin/page html $< | bin/write-atomic $@ - -out/%.html: src/%.org $(bin/page) bin/page.html.erb bin/write-atomic - @mkdir -p $(@D) - bin/page html $< | bin/write-atomic $@ -out/%.html: out/%.org $(bin/page) bin/page.html.erb bin/write-atomic - bin/page html $< | bin/write-atomic $@ - -out/%.css: src/%.scss - @mkdir -p $(@D) - scss --stdin < $< > $@ -out/%.css: out/%.scss - scss --stdin < $< > $@ - -index.all = $(filter-out %/ChangeLog.md %/index.md,$(html.src) $(shell find src -type f -name index.yaml)) -index.filter = $(filter-out %/index.yaml,$(filter $(@D)/% $(patsubst out%,src%,$(@D))/%,$1)) -index.cmd = bin/index $(patsubst .%,%,$(suffix $@)) $(@D) $(call index.filter,$^) | bin/write-atomic $@ -index.dep = $(bin/index) bin/index.$1.erb .var.index.all $(index.all) bin/write-atomic Makefile -out/index.md : $(call index.dep,md) - @mkdir -p $(@D) - $(index.cmd) -out/%/index.md : $(call index.dep,md) - @mkdir -p $(@D) - $(index.cmd) -out/index.atom : $(call index.dep,atom) - @mkdir -p $(@D) - $(index.cmd) -out/%/index.atom : $(call index.dep,atom) - @mkdir -p $(@D) - $(index.cmd) +# Boilerplate +phony += FORCE +.DELETE_ON_ERROR: +.SECONDARY: +# Development server serve: serve-8000 serve-%: all dir=$$(mktemp -d -t) && trap 'fusermount -u "$$dir"; rmdir "$$dir"' EXIT && unionfs -o ro out:src "$$dir" && (cd "$$dir" && python3 -m http.server $*) -.PHONY: serve serve-% +phony += serve serve-% -.var.%: FORCE bin/write-ifchanged - @printf '%s' $(call quote.shell,$($*)) | sed 's/^/#/' | bin/write-ifchanged $@ --include $(wildcard .var.*) +# Clean +clean: + rm -rf out +phony += clean -.PHONY: FORCE -.DELETE_ON_ERROR: -.SECONDARY: - -define nl +# Real file rules +out/%.css: src/%.scss + @mkdir -p $(@D) + scss --stdin < $< > $@ +targets = $(phony) %.css +$(sort $(filter-out $(targets),out/index.html $(MAKECMDGOALS))): FORCE + ./make -endef -# I put this as the last line in the file because it confuses Emacs syntax -# highlighting and makes the remainder of the file difficult to edit. -quote.shell = $(subst $(nl),'$$'\n'','$(subst ','\'',$1)') +# Boilerplate +.PHONY: $(phony) @@ -61,8 +61,8 @@ generator: | html_head_extra | "" | Org-mode | string | | class | "" | no | string (CSS class to apply to ~<body>~) | | tags | "" | LaTeX, kinda[fn:1] | string ("ES HB") or list (["ES", "HB"]) | -| published[fn:2] | most recent git commit for file | no | string (Ruby ~Date.parse()~) or date[fn:3] | -| updated[fn:2] | first git commit for file | no | string (Ruby ~Date.parse()~) or date[fn:3] | +| published[fn:2] | most recent git commit for file | no | string (Ruby ~DateTime::parse()~) or date[fn:3] | +| updated[fn:2] | first git commit for file | no | string (Ruby ~DateTime::parse()~) or date[fn:3] | [fn:1] The ~tags~ attribute is normally a list, but because I don't know how to do a list in Org-mode, I made it take a @@ -76,7 +76,7 @@ with two distinct dates. [fn:3] At various times there have been bugs in the YAML parser library that Pandoc uses, causing it to fail to parse dates, so I just -always put the date in quotes now, and let Ruby ~Date.parse()~ take +always put the date in quotes now, and let Ruby ~DateTime::parse()~ take care of it. * Make targets diff --git a/benchmark b/benchmark deleted file mode 100755 index b06c621..0000000 --- a/benchmark +++ /dev/null @@ -1,7 +0,0 @@ -#!/usr/bin/env bash -rm -rf out -thing='start up' -{ make -j1; echo done;}|ts -i '%.s'|sed 's/ .* / /' |while read -r time newthing; do - echo $time $thing - thing=$newthing -done | sort -n diff --git a/bin/index b/bin/index deleted file mode 100755 index c04618d..0000000 --- a/bin/index +++ /dev/null @@ -1,61 +0,0 @@ -#!/usr/bin/env ruby -# -*- coding: utf-8 -*- -load 'util.rb' -require 'yaml' - -# ARGV[0] -type = ARGV.shift -template = "bin/index.#{type}.erb" -erb = ERB.new(File.read(template)); -erb.filename = template - -# ARGV[1] -@path = ARGV.shift -webpath = (@path+'/').sub(/^(src|out)\//, '/') -if type == 'atom' - webpath += 'index.atom' -end -@url = URI::parse('https://www.andrewdm.me/') + webpath - -indexyaml = @path.sub('out', 'src')+'/index.yaml' -if File.exists?(indexyaml) - metadata = YAML::load(File.read(indexyaml)) -else - metadata = {} -end - -@pages = [] -for data in metadata['external'] - @pages.push(ExternPage.new(data)) -end - -# ARGV[2..] -for filename in ARGV do - @pages.push(Page.new(filename)) -end - -# main -@title = metadata['title'] || @path.sub('out', '') - -def guess_section(page) - for path in @sections.keys do - if @url.route_to(page.url).to_s.start_with?(path+'/') - return path - end - end - return '' -end - -@sections = { '' => {'head' => '', 'body' => []} } -(metadata['sections'] || []).each do |path, name| - @sections[path] = { - 'head' => name, - 'body' => [] - } -end -for page in @pages do - section = page.section || guess_section(page) - @sections[section]['body'].push(page) -end - -erb.run() diff --git a/bin/index.atom.erb b/bin/index.atom.erb deleted file mode 100644 index 5b0ef36..0000000 --- a/bin/index.atom.erb +++ /dev/null @@ -1,26 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<feed xmlns="http://www.w3.org/2005/Atom"> - - <title>AndrewDM.me <%= @title %></title> - <link rel="self" type="application/atom+xml" href="./index.atom"/> - <link rel="alternate" type="text/html" href="./"/> - <link rel="alternate" type="text/markdown" href="./index.md"/> - <updated><%= @pages.map{|p|p.updated}.sort.last.rfc3339 %></updated> - <author><%= Person.new("Andrew Murrell").atom %></author> - <id><%= $url %></id> - - <% @pages.sort_by{|p| p.updated}.reverse.each do |page| %> - <entry xmlns="http://www.w3.org/2005/Atom"> - <link rel="alternate" type="text/html" href="<%= page.url %>"/> - <id><%= page.url %></id> - <updated><%= page.updated.rfc3339 %></updated> - <published><%= page.published.rfc3339 %></published> - <title><%= page.title %></title> - <author><%= page.author.atom %></author> -<% if page.content %> - <content type="html"><%= html_escape(page.content) %></content> - <rights type="html"><%= html_escape(page.rights) %></rights> -<% end %> - </entry> - <% end %> -</feed> diff --git a/bin/page b/bin/page deleted file mode 100755 index ee62a95..0000000 --- a/bin/page +++ /dev/null @@ -1,12 +0,0 @@ -#!/usr/bin/env ruby -# -*- coding: utf-8 -*- -load 'util.rb' -require 'uri' - -template = "bin/page.#{ARGV[0]}.erb" -@page = Page.new(ARGV[1]) -@url = URI::parse('https://www.andrewdm.me/') + @page.absoutpath - -erb = ERB.new(File.read(template)); -erb.filename = template -erb.run() diff --git a/bin/util.rb b/bin/util.rb deleted file mode 100644 index cd7974b..0000000 --- a/bin/util.rb +++ /dev/null @@ -1,302 +0,0 @@ -# coding: utf-8 -load 'pandoc.rb' -require 'erb' -require 'date' -require 'set' -require 'uri' - -$license_urls = { - "CC BY-SA-3.0" => 'https://creativecommons.org/licenses/by-sa/3.0/', - 'WTFPL-2' => "http://www.wtfpl.net/txt/copying/", -} -$person_uris = { - "Luke Shumaker" => "https://lukeshu.com/", - "Andrew Murrell" => "https://andrewdm.me/", -} -$person_emails = { - "Luke Shumaker" => "lukeshu@parabola.nu", - "Andrew Murrell" => "ImFromNASA@gmail.com", -} - -$tag_names = { - "DM" => "DMing Resource", - "ES" => "Essay", - "FF" => "Flash Fiction", - "HB" => "Homebrew", - "SS" => "Short Story", - "WP" => "WIP", -} - -$url = URI::parse('https://www.andrewdm.me') - -class Tag - def initialize(abbr) - @abbr = abbr - end - def abbr - @abbr - end - def name - $tag_names[@abbr] - end - def html - return "<a class=\"tag #{abbr}\" href=\"/tags/#{abbr}.html\">#{name}</a>" - end -end - -class Person - def initialize(name) - @name = name - end - def name - @name - end - def uri - $person_uris[@name] - end - def email - $person_emails[@name] - end - def html - if not email.nil? - return "<a href=\"mailto:#{email}\">#{name}</a>" - elsif not uri.nil? - return "<a href=\"#{uri}\">#{name}</a>" - else - return @name - end - end - def atom - ret = "" - ret += "<name>#{name}</name>" unless name.nil? - ret += "<uri>#{uri}</uri>" unless uri.nil? - ret += "<email>#{email}</email>" unless email.nil? - end -end - -class License - def initialize(name) - @name = name - end - def name - @name - end - def url - $license_urls[@name] - end - def html - "<a href=\"#{url}\">#{name}</a>" - end -end - -class Page - def initialize(infile) - @infile = infile - end - - def infile ; @infile ; end - def input ; @input ||= File.read(infile) ; end - def pandoc - if @pandoc.nil? - types = { - 'md' => 'markdown' - } - - ext = File.extname(infile).gsub(/^[.]/, '') - type = types[ext] || ext - @pandoc = Pandoc::load(type, input) - - if @pandoc['pandoc_format'] - @pandoc = Pandoc::load(@pandoc['pandoc_format'], input) - end - end - @pandoc - end - - def title ; @title ||= pandoc['title'] || input.split("\n",2).first ; end - def showtitle ; @showtitle ||= ! pandoc['title'].nil? ; end - - def author ; @author ||= Person.new( pandoc['author'] || "Andrew Murrell") ; end - def license ; @license ||= License.new(pandoc['license'] || "CC BY-SA-3.0") ; end - def content ; @content ||= pandoc.to('html5 '+(pandoc['pandoc_flags']||'')) ; end - def head ; @head ||= pandoc['html_head_extra'] ; end - def class ; @class ||= pandoc['class'] ; end - - def tags - if @tags.nil? - raw = pandoc['tags'] || [] - if raw.is_a?(String) - raw = raw.split - end - @tags = raw.map{|tag|Tag.new(tag)} - end - @tags - end - - def _published - if @_published.nil? - raw = pandoc['published'] - @_published = Date.parse(raw) unless raw.nil? - end - if @_published.nil? - raw = `git log -n1 --reverse --format='%cI' -- #{infile}` - @_published = DateTime.iso8601(raw) unless raw.empty? - end - @_published - end - - def _updated - if @_updated.nil? - raw = pandoc['updated'] - @_updated = Date.parse(raw) unless raw.nil? - end - if @_updated.nil? - raw = `git log -n1 --format='%cI' -- #{infile}` - @_updated = DateTime.iso8601(raw) unless raw.empty? - end - @_updated - end - - def published - if @published.nil? - unless _published.nil? - @published = _published - else - unless _updated.nil? - @published = _updated - end - end - # sanity check - unless _published.nil? or _updated.nil? - if _updated < _published - @published = _updated - end - end - end - @published - end - - def updated - if @updated.nil? - unless _updated.nil? - @updated = _updated - else - unless _published.nil? - @updated = _published - end - end - end - @updated - end - - def rights - if published.nil? || updated.nil? - years = '' - else - first = published.year - last = updated.year - - years = `git log --date=format:'%Y' --format='%cd' -- .config/login.sh`.split('\n').map{|s|s.to_i} - years.unshift(first) - years.unshift(last) - - # Remove dups and git years outside of [first,last] - # TODO: simplify year spans - years = Set[*years.select{|i|i > first && i < last}].sort.join(', ') - end - @rights ||= "<p>The content of this page is Copyright © #{years} #{author.html}.</p>\n" + - "<p>This page is licensed under the #{license.html} license.</p>" - end - - def abssrcpath - @srcpath ||= infile.sub(/^(src|out)\//, '/') - end - def absoutpath - @outpath ||= abssrcpath.sub(/\.[^\/.]*$/, '.html').sub(/\/index[.]html$/, '') - end - - def url - @url ||= $url + absoutpath - end - def srcurl - @srcurl ||= $url + abssrcpath - end - - def breadcrumbs - if @breadcrumbs.nil? - bc = [] - u = url.path - u = "/" if u == "" - while u != "/" - bc.unshift("<a href=\"#{u}\">#{File.basename(u, File.extname(u))}</a>") - u = File.dirname(u) - end - bc.unshift("<a href=\"/\">Andrew D. Murrell</a>") - @breadcrumbs = bc.join(' » ') - end - @breadcrumbs - end - - def section - return nil - end -end - -def html_escape(html) - html - .gsub('&', '&') - .gsub('>', '>') - .gsub('<', '<') -end - -class ExternPage - def initialize(metadata) - @metadata = metadata - end - - def title - @metadata['title'] - end - - def content - nil - end - - def tags - if @tags.nil? - raw = @metadata['tags'] || [] - if raw.is_a?(String) - raw = raw.split - end - @tags = raw.map{|tag|Tag.new(tag)} - end - return @tags - end - - def url - return $url + @metadata['url'] - end - - def author - Person.new(@metadata['author'] || "Andrew Murrell") - end - - def published - str = @metadata['published'] - if str.nil? and ! @metadata['updated'].nil? - str = @metadata['updated'] - end - return Date.parse(str) - end - def updated - str = @metadata['updated'] - if str.nil? and ! @metadata['published'].nil? - str = @metadata['published'] - end - return Date.parse(str) - end - - def section - return @metadata['section'] - end -end diff --git a/bin/write-atomic b/bin/write-atomic deleted file mode 100755 index efb2551..0000000 --- a/bin/write-atomic +++ /dev/null @@ -1,21 +0,0 @@ -#!/usr/bin/env bash -# Copyright (C) 2015-2016 Luke Shumaker -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. - -outfile=$1 -tmpfile="$(dirname "$outfile")/.tmp${outfile##*/}" - -cat > "$tmpfile" || { r=$?; rm -f "$tmpfile"; exit $r; } -mv -f "$tmpfile" "$outfile" diff --git a/bin/write-ifchanged b/bin/write-ifchanged deleted file mode 100755 index 185ceb0..0000000 --- a/bin/write-ifchanged +++ /dev/null @@ -1,25 +0,0 @@ -#!/usr/bin/env bash -# Copyright (C) 2015 Luke Shumaker -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. - -outfile=$1 -tmpfile="$(dirname "$outfile")/.tmp${outfile##*/}" - -cat > "$tmpfile" || exit $? -if cmp -s "$tmpfile" "$outfile"; then - rm -f "$tmpfile" || : -else - mv -f "$tmpfile" "$outfile" -fi diff --git a/config.yaml b/config.yaml new file mode 100644 index 0000000..267ccb0 --- /dev/null +++ b/config.yaml @@ -0,0 +1,26 @@ +url: "https://www.andrewdm.me/" +html_suffixes: ["md", "org"] + +# Licenses +default_license: "CC BS-SA-3.0" +license_uris: + "CC BY-SA-3.0": "https://creativecommons.org/licenses/by-sa/3.0/" + "WTFPL-2": "http://www.wtfpl.net/txt/copying/" + +# People +default_author: "Andrew Murrell" +person_uris: + "Luke Shumaker": "https://lukeshu.com/" + "Andrew Murrell": "https://andrewdm.me/" +person_emails: + "Luke Shumaker": "lukeshu@parabola.nu" + "Andrew Murrell": "ImFromNASA@gmail.com" + +# Categories +categories: + "DM": "DMing Resource" + "ES": "Essay" + "FF": "Flash Fiction" + "HB": "Homebrew" + "SS": "Short Story" + "WP": "WIP" diff --git a/lib/category.rb b/lib/category.rb new file mode 100644 index 0000000..b60c82e --- /dev/null +++ b/lib/category.rb @@ -0,0 +1,20 @@ +# coding: utf-8 +require 'config' + +class Category + def initialize(abbr) + @abbr = abbr + end + def abbr + @abbr + end + def name + Config::get.category_name(@abbr) + end + def html + return "<a class=\"tag #{abbr}\" href=\"/tags/#{abbr}.html\">#{name}</a>" + end + def atom + return "<category term=\"#{abbr}\" label=\"#{name}\" />" + end +end diff --git a/lib/config.rb b/lib/config.rb new file mode 100644 index 0000000..4690559 --- /dev/null +++ b/lib/config.rb @@ -0,0 +1,51 @@ +# coding: utf-8 +require 'yaml' + +require 'uri' + +class Config + def self.get + return @config ||= Config::new('config.yaml') + end + def initialize(filename) + @data = YAML::load(File::read(filename)) + end + def url + return @url ||= URI::parse(@data['url']) + end + def html_suffixes + return @data['html_suffixes'] + end + # Licenses + def default_license + return @default_license ||= @data['default_license'] + end + def license_uri(name) + str = @data['license_uris'][name] + if str.nil? + return nil + end + return URI::parse(str) + end + # People + def default_author + return @default_person ||= @data['default_author'] + end + def person_uri(name) + str = @data['person_uris'][name] + if str.nil? + return nil + end + return URI::parse(str) + end + def person_email(name) + return @data['person_emails'][name] + end + # Categories + def categories + return @data['categories'].keys + end + def category_name(abbr) + return @data['categories'][abbr] + end +end diff --git a/lib/license.rb b/lib/license.rb new file mode 100644 index 0000000..da68f30 --- /dev/null +++ b/lib/license.rb @@ -0,0 +1,17 @@ +# coding: utf-8 +require 'config' + +class License + def initialize(name) + @name = name + end + def name + @name + end + def url + Config::get.license_uri(@name) + end + def html + "<a href=\"#{url}\">#{name}</a>" + end +end diff --git a/lib/page.rb b/lib/page.rb new file mode 100644 index 0000000..20f9701 --- /dev/null +++ b/lib/page.rb @@ -0,0 +1,103 @@ +# coding: utf-8 +require 'erb' +require 'set' + +require 'category' + +class Page + # Page is an abstract class. + # + # Implementors must implement several methods: + # + # def url => URI + # def atom_title => String + # def atom_author => Person + # def atom_content => html | nil + # def atom_rights => html | nil + # + # def page_categories => String | Enumerable<String> + # + # def page_published => Time | nil + # def page_updated => Time | nil + # def page_years => Enumerable<Fixnum> + + def atom_categories # => Enumerable<Category> + if @categories.nil? + raw = page_categories + if raw.is_a?(String) + raw = raw.split + end + @categories = raw.map{|abbr|Category.new(abbr)} + end + @categories + end + + def atom_published # => Time | nil + if @published.nil? + unless page_published.nil? + @published = page_published + else + unless page_updated.nil? + @published = page_updated + end + end + # sanity check + unless page_published.nil? or page_updated.nil? + if page_updated < page_published + @published = page_updated + end + end + end + @published + end + + def atom_updated # => Time | nil + if @updated.nil? + unless page_updated.nil? + @updated = page_updated + else + unless page_published.nil? + @updated = page_published + end + end + end + @updated + end + + def years # => Enumerable<Fixnum> + if @years.nil? + if atom_published.nil? || atom_updated.nil? + @years = Set[] + else + first = atom_published.year + last = atom_updated.year + + years = page_years + years.add(first) + years.add(last) + + @years = Set[*years.select{|i|i >= first && i <= last}] + end + end + @years + end + + def index_class + return '' + end + def index_link(cururl, depth) + # FIXME: This code is super gross. + ret = " * <span><a class=\"#{index_class}\" href=\"#{cururl.route_to(url)}\" title=\"Published on #{atom_published.strftime('%Y-%m-%d')}" + if atom_updated != atom_published + ret += " (updated on #{atom_updated.strftime('%Y-%m-%d')})" + end + ret += "\">#{atom_title}</a></span><span>" + atom_categories.each do |t| + ret += t.html + end + ret += "</span>\n" + end +end + +ERB::new(File::read("tmpl/page.atom.erb")).def_method(Page, 'atom()', "tmpl/page.atom.erb") +ERB::new(File::read("tmpl/page.html.erb")).def_method(Page, 'html()', "tmpl/page.html.erb") diff --git a/lib/page_index.rb b/lib/page_index.rb new file mode 100644 index 0000000..66b528a --- /dev/null +++ b/lib/page_index.rb @@ -0,0 +1,121 @@ +# coding: utf-8 +require 'erb' +require 'set' +require 'yaml' + +require 'config' +require 'page_local' +require 'page_remote' +require 'person' + +class IndexPage < LocalPage + def initialize(dirname) + super(dirname) + end + + def _metadata + if @metadata.nil? + yamlfile = local_infile+"/index.yaml" + if File::exist?(yamlfile) + @metadata = YAML::load(File::read(yamlfile)) + else + @metadata = {} + end + end + @metadata + end + def _ls + @ls ||= Dir::entries(local_infile) + .select{|fname|not fname.start_with?(".")} + .map{|fname|"#{local_infile}/#{fname}"} + .select{|path|Dir::exist?(path) or Config::get.html_suffixes.include?(File::extname(path).gsub(/^[.]/, ''))} + end + def index_pages + if @pages.nil? + @pages = Set[] + for path in _ls + @pages.add( Dir::exist?(path) ? IndexPage::new(path) : LocalPage::new(path) ) + end + for data in (_metadata['external'] || []) + @pages.add(RemotePage::new(data)) + end + end + @pages + end + def index_pages_leaves + ret = Set[] + index_pages.each do |page| + if page.is_a?(IndexPage) + ret.merge(page.index_pages) + else + ret.add(page) + end + end + return ret + end + + def index_link(cururl, depth) + ret = '' + unless depth <= 1 + ret += "<h#{depth}>[#{atom_title}](#{cururl.route_to(url)})</h#{depth}>\n\n" + end + for page in index_pages.select{|page|not page.is_a?(IndexPage)}.sort_by{|page|page.atom_published} + ret += page.index_link(cururl, depth+1) + end + ret += "\n" + for page in index_pages.select{|page|page.is_a?(IndexPage)}.sort_by{|page|page.atom_title} + ret += page.index_link(cururl, depth+1) + end + ret += "\n" + return ret.gsub(/\n\n+/, "\n\n") + end + def atom_title + _metadata['title'] + end + def atom_author + Person::new(_metadata['author'] || Config::get.default_author) + end + + def local_intype + return 'markdown' + end + def local_outfile + local_infile.sub(/^src/, 'out')+"/index.html" + end + def local_depends + if @depends.nil? + basename = local_infile.sub(/^src/, 'out') + deps = Set[local_infile] + yamlfile = local_infile+"/index.yaml" + if File::exist?(yamlfile) + deps.add(yamlfile) + end + index_pages.select{|p|!p.is_a?(RemotePage)}.each{|p|deps.merge(p.local_depends[''])} + @depends = { + '' => deps, + "#{basename}/index.html" => deps.clone.merge(["tmpl/index.md.erb", "tmpl/page.html.erb"]), + "#{basename}/index.atom" => deps.clone.merge(["tmpl/index.atom.erb", "tmpl/page.atom.erb"]), + } + end + @depends + end + def url + @outurl ||= Config::get.url + local_outfile.sub(/^out/, '').sub(/\/index\.html$/, '/') + end + def local_srcurl + return nil + end + + def page_published + return nil + end + def page_updated + return nil + end + def page_years + return Set[] + end +end + +ERB::new(File::read("tmpl/index.atom.erb")).def_method(IndexPage, 'atom()', "tmpl/index.atom.erb") +ERB::new(File::read("tmpl/index.md.erb")).def_method(IndexPage, 'local_input()', "tmpl/index.md.erb") diff --git a/lib/page_local.rb b/lib/page_local.rb new file mode 100644 index 0000000..7121c8e --- /dev/null +++ b/lib/page_local.rb @@ -0,0 +1,122 @@ +# coding: utf-8 +require 'date' +require 'set' + +require 'config' +require 'license' +require 'page' +require 'pandoc' +require 'person' +require 'sitegen' + +class LocalPage < Page + def initialize(infile) + @infile = infile + Sitegen::add(self) + end + + # Some of this code looks a little weird because it is + # super-aggressively lazy-evaluated and cached. + + def local_infile ; @infile ; end + def local_input ; @input ||= File::read(local_infile); end + def local_intype + types = { + 'md' => 'markdown' + } + ext = File::extname(local_infile).gsub(/^[.]/, '') + return types[ext] || ext + end + def _pandoc + if @pandoc.nil? + @pandoc = Pandoc::load(local_intype, local_input) + + if @pandoc['pandoc_format'] + @pandoc = Pandoc::load(@pandoc['pandoc_format'], local_input) + end + end + @pandoc + end + + # Query simple document metadata + def atom_author ; @author ||= Person::new( _pandoc['author'] || Config::get.default_author) ; end + def atom_title ; @title ||= _pandoc['title'] || local_input.split("\n",2).first ; end + def html_class ; @class ||= _pandoc['class'] ; end + def html_head_extra ; @head ||= _pandoc['html_head_extra'] ; end + def local_license ; @license ||= License::new(_pandoc['license'] || Config::get.default_license); end + def page_categories ; @cats ||= _pandoc['categories'] || [] ; end + + def atom_content + if @content.nil? + @content = '' + # Only insert the title if it came from Pandoc metadata; + # if the title was inferred from the the body content, + # then it is already in the page. + unless _pandoc['title'].nil? + @content += "<h1 class=title>#{atom_title}</h1>\n" + end + + # Insert the body + @content = _pandoc.to('html5 '+(_pandoc['pandoc_flags']||'')) + end + @content + end + + def atom_rights + # TODO: simplify year spans + @rights ||= "<p>The content of this page is Copyright © #{years.sort.join(', ')} #{atom_author.html}.</p>\n" + + "<p>This page is licensed under the #{local_license.html} license.</p>" + end + + def _gitdates + @gitdates ||= `git log --format='%cI' -- #{local_infile}`.split("\n").select{|s|!s.empty?}.map{|s|DateTime::iso8601(s).to_time} + end + + def page_published + if @_published.nil? + raw = _pandoc['published'] + @_published = DateTime::parse(raw).to_time unless raw.nil? + end + if @_published.nil? + @_published = _gitdates.sort.first + end + @_published + end + + def page_updated + if @_updated.nil? + raw = _pandoc['updated'] + @_updated = DateTime::parse(raw).to_time unless raw.nil? + end + if @_updated.nil? + @updated = _gitdates.sort.last + end + @_updated + end + + def page_years + @years ||= Set[*_gitdates.map{|dt|dt.year}] + end + + def local_outfile + local_infile.sub(/^src/, 'out').sub(/\.[^\/.]*$/, '.html') + end + def local_depends + if @depends.nil? + basename = local_infile.sub(/^src/, 'out').sub(/\.[^\/.]*$/, '') + @depends = { + '' => Set[local_infile], + "#{basename}.html" => Set[local_infile, "tmpl/page.html.erb"], + #"#{basename}.atom" => Set[local_infile, "tmpl/page.atom.erb"] + } + end + @depends + end + + def local_srcurl + @srcurl ||= Config::get.url + local_infile.sub(/^src/, '') + end + def url + @outurl ||= Config::get.url + local_outfile.sub(/^out/, '') + end +end diff --git a/lib/page_remote.rb b/lib/page_remote.rb new file mode 100644 index 0000000..5425944 --- /dev/null +++ b/lib/page_remote.rb @@ -0,0 +1,59 @@ +# coding: utf-8 +require 'date' + +require 'config' +require 'page' + +class RemotePage < Page + def initialize(metadata) + @metadata = metadata + end + + def url + return Config::get.url + @metadata['url'] + end + + def atom_title + @metadata['title'] + end + + def atom_author + Person::new(@metadata['author'] || Config::get.default_author) + end + + def atom_content + return nil + end + + def atom_rights + return nil + end + + def page_categories + @metadata['categories'] || [] + end + + def page_published + str = @metadata['published'] + if str.nil? + return nil + end + return DateTime::parse(str).to_time + end + + def page_updated + str = @metadata['updated'] + if str.nil? + return nil + end + return DateTime::parse(str).to_time + end + + def page_years + return [] + end + + def index_class + return 'external' + end +end diff --git a/bin/pandoc.rb b/lib/pandoc.rb index 155ddde..f0bf3f6 100644 --- a/bin/pandoc.rb +++ b/lib/pandoc.rb @@ -1,3 +1,4 @@ +# coding: utf-8 require 'open3' require 'json' diff --git a/lib/person.rb b/lib/person.rb new file mode 100644 index 0000000..6ad1569 --- /dev/null +++ b/lib/person.rb @@ -0,0 +1,32 @@ +# coding: utf-8 +require 'config' + +class Person + def initialize(name) + @name = name + end + def name + @name + end + def uri + Config::get.person_uri(@name) + end + def email + Config::get.person_email(@name) + end + def html + if not email.nil? + return "<a href=\"mailto:#{email}\">#{name}</a>" + elsif not uri.nil? + return "<a href=\"#{uri}\">#{name}</a>" + else + return name + end + end + def atom + ret = "" + ret += "<name>#{name}</name>" unless name.nil? + ret += "<uri>#{uri}</uri>" unless uri.nil? + ret += "<email>#{email}</email>" unless email.nil? + end +end diff --git a/lib/sitegen.rb b/lib/sitegen.rb new file mode 100644 index 0000000..ca0c4bf --- /dev/null +++ b/lib/sitegen.rb @@ -0,0 +1,98 @@ +# coding: utf-8 +require 'date' +require 'fileutils' +require 'set' + +module Sitegen + def self.init + @mk = {} + @want = Set[] + end + def self.add(page) + @deps = nil + page.local_depends.keys.each do |filename| + @mk[filename] = page unless filename.empty? + end + end + def self.pages + @mk.values.to_set + end + def self.want(filename) + @deps = nil + @want.add(filename) + end + def self.dependencies + if @deps.nil? + libfiles = Dir::entries('lib').select{|s|s!='..'}.map{|s|"lib/#{s}"}.to_set + ret = {} + ret[:all] = @want + @want.each do |filename| + ret[filename] = libfiles.clone.merge(@mk[filename].local_depends[filename]) + end + @deps = ret + end + @deps + end + def self.Makefile() + str = '' + dependencies.each do |target, deps| + str += "#{target.to_s}: #{deps.sort.join(' ')}\n" + end + return str + end + + def self.make(target) + newest = Time::new(0) + (dependencies[target] || []).each do |dep| + ts = make(dep) + newest = ts if ts > newest + end + unless target.is_a?(String) + return Time::now + end + if File::exist?(target) + ctime = File::ctime(target) + if ctime > newest + return ctime + end + end + generate(target) + return File::ctime(target) + end + + def self.generate(target) + case + when @mk[target].nil? + raise "No rule to make target '#{target}'. Stop." + when target.end_with?(".atom") + puts "atom #{target}" + write_atomic(target) do |file| + file.puts('<?xml version="1.0" encoding="utf-8"?>') + file.print(@mk[target].atom) + end + when target.end_with?(".html") + puts "html #{target}" + write_atomic(target) do |file| + file.print(@mk[target].html) + end + else + raise "No rule to make target '#{target}'. Stop." + end + end + + def self.write_atomic(outfilename) + tmpfilename = "#{File::dirname(outfilename)}/.tmp#{File::basename(outfilename)}" + + FileUtils::mkdir_p(File::dirname(tmpfilename)) + tmpfile = File::new(tmpfilename, 'wb') + begin + yield tmpfile + rescue Exception => e + tmpfile.close + File::unlink(tmpfilename) + raise e + end + tmpfile.close + File::rename(tmpfilename, outfilename) + end +end diff --git a/lib/siteutil.rb b/lib/siteutil.rb new file mode 100644 index 0000000..3f36ff2 --- /dev/null +++ b/lib/siteutil.rb @@ -0,0 +1,27 @@ +# coding: utf-8 +require 'config' +require 'sitegen' + +module Sitegen + def self.html_escape(html) + html + .gsub('&', '&') + .gsub('>', '>') + .gsub('<', '<') + end + + def self.breadcrumbs(url) + path = url.path + path = "/" if path == "" + bc = [] + while true + a = 'out'+path + b = ('out'+path+'/index.html').gsub('//', '/') + page = @mk[a] || @mk[b] + bc.unshift("<a href=\"#{url.route_to(page.url)}\">#{page.atom_title}</a>") + break if path == "/" + path = File::dirname(path) + end + return bc.join(' » ') + end +end @@ -0,0 +1,22 @@ +#!/usr/bin/env ruby +$:.unshift('lib') +require 'sitegen' +require 'page_index' + +# Initialize the site generator +Sitegen::init + +# Load all pages +def crawl(page) + page.index_pages.select{|p|p.is_a?(IndexPage)}.each{|p|crawl(p)} +end +crawl(IndexPage::new('src')) + +# Tell the sitegen which files we want +Sitegen.pages.each do |page| + Sitegen::want(page.local_outfile) +end +Sitegen::want('out/index.atom') + +# Make! +Sitegen::make(:all) diff --git a/notes.org b/notes.org new file mode 100644 index 0000000..5b00a25 --- /dev/null +++ b/notes.org @@ -0,0 +1,3 @@ +I need to insert this on all XML output: + +<?xml version="1.0" encoding="utf-8"?> diff --git a/out/Andrew.html b/out/Andrew.html index c32a90e..8001210 100644 --- a/out/Andrew.html +++ b/out/Andrew.html @@ -7,9 +7,9 @@ <link rel="alternate" type="application/atom+xml" href="/index.atom" /> </head> - <body> + <body class=""> <header> - <h1>AndrewDM</h1> + <h1 class=breadcrumbs><a href="./">AndrewDM</a> » <a href="">Hello Internet Person!</a></h1> <nav> <ul> <li><a href="/">Projects</a> @@ -21,19 +21,17 @@ </form> </ul> </nav> - <p class=breadcrumbs><a href="/">Andrew D. Murrell</a> » <a href="/Andrew.html">Andrew</a></p> </header> <article> - <p>Hello Internet Person!</p> <p>I'm Andrew D. Murrell, and I'm a DM.</p> <p>Though I hold a degree in Physics, am currently working as a manager and editor at a small tech firm. I write, mostly to teach my players about the whatever they want to know about the Forgotten Realms, but also because I think stories make the world a better place. I can be contacted at ImFromNASA@gmail.com and would love to hear from you!</p> </article> <footer> - <p>The content of this page is Copyright © <a href="mailto:ImFromNASA@gmail.com">Andrew Murrell</a>.</p> -<p>This page is licensed under the <a href="https://creativecommons.org/licenses/by-sa/3.0/">CC BY-SA-3.0</a> license.</p> + <p>The content of this page is Copyright © 2016 <a href="mailto:ImFromNASA@gmail.com">Andrew Murrell</a>.</p> +<p>This page is licensed under the <a href="">CC BS-SA-3.0</a> license.</p> <p>Page source: <a href="Andrew.md">Andrew.md</a></p> <p>Website source: <a href="https://git.andrewdm.me/www.git">www.git</a></p> </footer> diff --git a/out/ChangeLog.html b/out/ChangeLog.html index 34eec58..9842ff2 100644 --- a/out/ChangeLog.html +++ b/out/ChangeLog.html @@ -7,9 +7,9 @@ <link rel="alternate" type="application/atom+xml" href="/index.atom" /> </head> - <body> + <body class=""> <header> - <h1>AndrewDM</h1> + <h1 class=breadcrumbs><a href="./">AndrewDM</a> » <a href="">ChangeLog</a></h1> <nav> <ul> <li><a href="/">Projects</a> @@ -21,11 +21,9 @@ </form> </ul> </nav> - <p class=breadcrumbs><a href="/">Andrew D. Murrell</a> » <a href="/ChangeLog.html">ChangeLog</a></p> </header> <article> - <h1 id="changelog">ChangeLog</h1> <h2 id="luke-shumaker-lukeshusbcglobal.net">2017-01-04 Luke Shumaker <lukeshu@sbcglobal.net></h2> <p>Change the title of "Psionist" -> "Psionist Class [5e]"</p> @@ -40,8 +38,8 @@ </article> <footer> - <p>The content of this page is Copyright © <a href="mailto:ImFromNASA@gmail.com">Andrew Murrell</a>.</p> -<p>This page is licensed under the <a href="https://creativecommons.org/licenses/by-sa/3.0/">CC BY-SA-3.0</a> license.</p> + <p>The content of this page is Copyright © 2017 <a href="mailto:ImFromNASA@gmail.com">Andrew Murrell</a>.</p> +<p>This page is licensed under the <a href="">CC BS-SA-3.0</a> license.</p> <p>Page source: <a href="ChangeLog.md">ChangeLog.md</a></p> <p>Website source: <a href="https://git.andrewdm.me/www.git">www.git</a></p> </footer> diff --git a/out/dnd/PsionicSchools.html b/out/dnd/PsionicSchools.html index 2b8c07c..4ea9d6d 100644 --- a/out/dnd/PsionicSchools.html +++ b/out/dnd/PsionicSchools.html @@ -9,7 +9,7 @@ </head> <body class="dnd"> <header> - <h1>AndrewDM</h1> + <h1 class=breadcrumbs><a href="../">AndrewDM</a> » <a href="./">Dungeons & Dragons</a> » <a href="">Schools of Psionics</a></h1> <nav> <ul> <li><a href="/">Projects</a> @@ -21,11 +21,9 @@ </form> </ul> </nav> - <p class=breadcrumbs><a href="/">Andrew D. Murrell</a> » <a href="/dnd">dnd</a> » <a href="/dnd/PsionicSchools.html">PsionicSchools</a></p> </header> <article> <p>Tags: <a class="tag ES" href="/tags/ES.html">Essay</a><a class="tag HB" href="/tags/HB.html">Homebrew</a></p> - <h1 class=title>Schools of Psionics</h1> <p>From what I've seen, the most recent few 5e Unearthed Arcana dealing with "Psionics and the Mystic" have been getting somewhat mixed reviews. I don't think this is because of the mechanics--or rather not COMPLETELY because of the mechanics. Mechanics for psionics have always been weird, and the 5e style is good for D&D, so maintaining that is good and won't get any gripes from me.</p> <p>But I think that no matter what purely mechanical tweaks the UA team has planned for the Mystic, the general lukewarm reception isn't going to change unless we get something else squared away first. Something a little deeper--something that helps us grasp Psionics in the same way we grasp Magic: with a complete and intuitive system.</p> <p>With Weave-based magic there are schools which somewhat delineate magical effects (conjuration, divination, etc), but that's not exactly what I mean. Not to bash the magical schools (any system will have inconsistencies--mine notwithstanding), but few people really understand what it means to be a wizard by what school of magic they specialize in. An enchantment wizard isn't fundamentally different from an evocation one. But a wizard is different than a bard or a warlock. These "Schools of Psionics" are as much about the state of mind of the manifester and the method for manifestation as they are about the outcome of the manifestation (there are several of my Psionic "schools" that may each manifest effects in the transmutation school of magic for instance, but each according to its own particular rules).</p> @@ -100,8 +98,8 @@ </article> <footer> - <p>The content of this page is Copyright © <a href="mailto:ImFromNASA@gmail.com">Andrew Murrell</a>.</p> -<p>This page is licensed under the <a href="https://creativecommons.org/licenses/by-sa/3.0/">CC BY-SA-3.0</a> license.</p> + <p>The content of this page is Copyright © 2017 <a href="mailto:ImFromNASA@gmail.com">Andrew Murrell</a>.</p> +<p>This page is licensed under the <a href="">CC BS-SA-3.0</a> license.</p> <p>Page source: <a href="PsionicSchools.org">PsionicSchools.org</a></p> <p>Website source: <a href="https://git.andrewdm.me/www.git">www.git</a></p> </footer> diff --git a/out/dnd/Psionist.html b/out/dnd/Psionist.html index de40730..5c16483 100644 --- a/out/dnd/Psionist.html +++ b/out/dnd/Psionist.html @@ -9,7 +9,7 @@ </head> <body class="dnd"> <header> - <h1>AndrewDM</h1> + <h1 class=breadcrumbs><a href="../">AndrewDM</a> » <a href="./">Dungeons & Dragons</a> » <a href="">Psionist Class [5e]</a></h1> <nav> <ul> <li><a href="/">Projects</a> @@ -21,11 +21,9 @@ </form> </ul> </nav> - <p class=breadcrumbs><a href="/">Andrew D. Murrell</a> » <a href="/dnd">dnd</a> » <a href="/dnd/Psionist.html">Psionist</a></p> </header> <article> <p>Tags: <a class="tag ES" href="/tags/ES.html">Essay</a><a class="tag HB" href="/tags/HB.html">Homebrew</a></p> - <h1 class=title>Psionist Class [5e]</h1> <div id="table-of-contents"> <h2> Table of Contents @@ -2520,8 +2518,8 @@ Footnotes: </article> <footer> - <p>The content of this page is Copyright © <a href="mailto:ImFromNASA@gmail.com">Andrew Murrell</a>.</p> -<p>This page is licensed under the <a href="https://creativecommons.org/licenses/by-sa/3.0/">CC BY-SA-3.0</a> license.</p> + <p>The content of this page is Copyright © 2016 <a href="mailto:ImFromNASA@gmail.com">Andrew Murrell</a>.</p> +<p>This page is licensed under the <a href="">CC BS-SA-3.0</a> license.</p> <p>Page source: <a href="Psionist.md">Psionist.md</a></p> <p>Website source: <a href="https://git.andrewdm.me/www.git">www.git</a></p> </footer> diff --git a/out/dnd/SpellGauntlet.html b/out/dnd/SpellGauntlet.html index 9c2563a..b58029d 100644 --- a/out/dnd/SpellGauntlet.html +++ b/out/dnd/SpellGauntlet.html @@ -9,7 +9,7 @@ </head> <body class="dnd"> <header> - <h1>AndrewDM</h1> + <h1 class=breadcrumbs><a href="../">AndrewDM</a> » <a href="./">Dungeons & Dragons</a> » <a href="">Spell Gauntlet: Practical Spellcasting</a></h1> <nav> <ul> <li><a href="/">Projects</a> @@ -21,11 +21,9 @@ </form> </ul> </nav> - <p class=breadcrumbs><a href="/">Andrew D. Murrell</a> » <a href="/dnd">dnd</a> » <a href="/dnd/SpellGauntlet.html">SpellGauntlet</a></p> </header> <article> <p>Tags: <a class="tag FF" href="/tags/FF.html">Flash Fiction</a><a class="tag SS" href="/tags/SS.html">Short Story</a><a class="tag WP" href="/tags/WP.html">WIP</a></p> - <h1 class=title>Spell Gauntlet: Practical Spellcasting</h1> <h1 id="teleport">Teleport</h1> <h2 id="wizard---ft.-ula-mindis">Wizard - ft. Ula Mindis</h2> <p>The young Wizard Ula Mindis awoke to the smell of steeping tea.</p> @@ -203,8 +201,8 @@ </article> <footer> - <p>The content of this page is Copyright © <a href="mailto:ImFromNASA@gmail.com">Andrew Murrell</a>.</p> -<p>This page is licensed under the <a href="https://creativecommons.org/licenses/by-sa/3.0/">CC BY-SA-3.0</a> license.</p> + <p>The content of this page is Copyright © 2017 <a href="mailto:ImFromNASA@gmail.com">Andrew Murrell</a>.</p> +<p>This page is licensed under the <a href="">CC BS-SA-3.0</a> license.</p> <p>Page source: <a href="SpellGauntlet.org">SpellGauntlet.org</a></p> <p>Website source: <a href="https://git.andrewdm.me/www.git">www.git</a></p> </footer> diff --git a/out/dnd/Tastavi.html b/out/dnd/Tastavi.html index d9fd64f..02d7087 100644 --- a/out/dnd/Tastavi.html +++ b/out/dnd/Tastavi.html @@ -9,7 +9,7 @@ </head> <body class="dnd"> <header> - <h1>AndrewDM</h1> + <h1 class=breadcrumbs><a href="../">AndrewDM</a> » <a href="./">Dungeons & Dragons</a> » <a href="">Tastavi D'Maelnor of Llolethane</a></h1> <nav> <ul> <li><a href="/">Projects</a> @@ -21,11 +21,9 @@ </form> </ul> </nav> - <p class=breadcrumbs><a href="/">Andrew D. Murrell</a> » <a href="/dnd">dnd</a> » <a href="/dnd/Tastavi.html">Tastavi</a></p> </header> <article> <p>Tags: <a class="tag SS" href="/tags/SS.html">Short Story</a></p> - <h1 class=title>Tastavi D'Maelnor of Llolethane</h1> <p> When I DM, I try to allow players to have as many options for character creation as I can. Usually, this manifests in pretty interesting, but stable, characters. And other times… you get Tastavi. </p> @@ -1390,8 +1388,8 @@ He lay upon the ground thinking it maybe better he have died quickly in the tunn </article> <footer> - <p>The content of this page is Copyright © <a href="mailto:ImFromNASA@gmail.com">Andrew Murrell</a>.</p> -<p>This page is licensed under the <a href="https://creativecommons.org/licenses/by-sa/3.0/">CC BY-SA-3.0</a> license.</p> + <p>The content of this page is Copyright © 2016 <a href="mailto:ImFromNASA@gmail.com">Andrew Murrell</a>.</p> +<p>This page is licensed under the <a href="">CC BS-SA-3.0</a> license.</p> <p>Page source: <a href="Tastavi.md">Tastavi.md</a></p> <p>Website source: <a href="https://git.andrewdm.me/www.git">www.git</a></p> </footer> diff --git a/out/dnd/index.html b/out/dnd/index.html index f18372c..3469f1e 100644 --- a/out/dnd/index.html +++ b/out/dnd/index.html @@ -9,7 +9,7 @@ </head> <body class="index"> <header> - <h1>AndrewDM</h1> + <h1 class=breadcrumbs><a href="../">AndrewDM</a> » <a href="">Dungeons & Dragons</a></h1> <nav> <ul> <li><a href="/">Projects</a> @@ -21,24 +21,22 @@ </form> </ul> </nav> - <p class=breadcrumbs><a href="/">Andrew D. Murrell</a> » <a href="/dnd">dnd</a></p> </header> <article> - <h1 class=title>Dungeons & Dragons</h1> <ul> -<li><span><a href="PsionicSchools.html" title="Published on 2017-01-03">Schools of Psionics</a></span><span><a class="tag ES" href="/tags/ES.html">Essay</a><a class="tag HB" href="/tags/HB.html">Homebrew</a></span></li> -<li><span><a href="SpellGauntlet.html" title="Published on 2017-01-03">Spell Gauntlet: Practical Spellcasting</a></span><span><a class="tag FF" href="/tags/FF.html">Flash Fiction</a><a class="tag SS" href="/tags/SS.html">Short Story</a><a class="tag WP" href="/tags/WP.html">WIP</a></span></li> -<li><span><a href="Tastavi.html" title="Published on 2016-08-30">Tastavi D'Maelnor of Llolethane</a></span><span><a class="tag SS" href="/tags/SS.html">Short Story</a></span></li> -<li><span><a href="Psionist.html" title="Published on 2016-07-16">Psionist Class [5e]</a></span><span><a class="tag ES" href="/tags/ES.html">Essay</a><a class="tag HB" href="/tags/HB.html">Homebrew</a></span></li> -<li><span><a class="external" href="WaterdeepBazaar/WaterdeepBazaar.html" title="Published on 2015-12-14">Waterdeep Bazaar: Marketplace Generator</a></span><span><a class="tag DM" href="/tags/DM.html">DMing Resource</a><a class="tag WP" href="/tags/WP.html">WIP</a></span></li> +<li><span><a class="external" href="WaterdeepBazaar/WaterdeepBazaar.html" title="Published on 2015-12-13">Waterdeep Bazaar: Marketplace Generator</a></span><span><a class="tag DM" href="/tags/DM.html">DMing Resource</a><a class="tag WP" href="/tags/WP.html">WIP</a></span></li> +<li><span><a class="" href="Psionist.html" title="Published on 2016-07-16">Psionist Class [5e]</a></span><span><a class="tag ES" href="/tags/ES.html">Essay</a><a class="tag HB" href="/tags/HB.html">Homebrew</a></span></li> +<li><span><a class="" href="Tastavi.html" title="Published on 2016-08-30">Tastavi D'Maelnor of Llolethane</a></span><span><a class="tag SS" href="/tags/SS.html">Short Story</a></span></li> +<li><span><a class="" href="SpellGauntlet.html" title="Published on 2017-01-03 (updated on 2017-01-06)">Spell Gauntlet: Practical Spellcasting</a></span><span><a class="tag FF" href="/tags/FF.html">Flash Fiction</a><a class="tag SS" href="/tags/SS.html">Short Story</a><a class="tag WP" href="/tags/WP.html">WIP</a></span></li> +<li><span><a class="" href="PsionicSchools.html" title="Published on 2017-01-03 (updated on 2017-01-06)">Schools of Psionics</a></span><span><a class="tag ES" href="/tags/ES.html">Essay</a><a class="tag HB" href="/tags/HB.html">Homebrew</a></span></li> </ul> </article> <footer> <p>The content of this page is Copyright © <a href="mailto:ImFromNASA@gmail.com">Andrew Murrell</a>.</p> -<p>This page is licensed under the <a href="https://creativecommons.org/licenses/by-sa/3.0/">CC BY-SA-3.0</a> license.</p> - <p>Page source: <a href="dnd/index.md">index.md</a></p> +<p>This page is licensed under the <a href="">CC BS-SA-3.0</a> license.</p> + <p>Website source: <a href="https://git.andrewdm.me/www.git">www.git</a></p> </footer> </body> diff --git a/out/dnd/index.md b/out/dnd/index.md deleted file mode 100644 index 7df02e7..0000000 --- a/out/dnd/index.md +++ /dev/null @@ -1,16 +0,0 @@ ---- -title: "Dungeons & Dragons" -class: "index" ---- - - - - - - * <span><a href="PsionicSchools.html" title="Published on 2017-01-03">Schools of Psionics</a></span><span><a class="tag ES" href="/tags/ES.html">Essay</a><a class="tag HB" href="/tags/HB.html">Homebrew</a></span> - * <span><a href="SpellGauntlet.html" title="Published on 2017-01-03">Spell Gauntlet: Practical Spellcasting</a></span><span><a class="tag FF" href="/tags/FF.html">Flash Fiction</a><a class="tag SS" href="/tags/SS.html">Short Story</a><a class="tag WP" href="/tags/WP.html">WIP</a></span> - * <span><a href="Tastavi.html" title="Published on 2016-08-30">Tastavi D'Maelnor of Llolethane</a></span><span><a class="tag SS" href="/tags/SS.html">Short Story</a></span> - * <span><a href="Psionist.html" title="Published on 2016-07-16">Psionist Class [5e]</a></span><span><a class="tag ES" href="/tags/ES.html">Essay</a><a class="tag HB" href="/tags/HB.html">Homebrew</a></span> - * <span><a class="external" href="WaterdeepBazaar/WaterdeepBazaar.html" title="Published on 2015-12-14">Waterdeep Bazaar: Marketplace Generator</a></span><span><a class="tag DM" href="/tags/DM.html">DMing Resource</a><a class="tag WP" href="/tags/WP.html">WIP</a></span> - - diff --git a/out/index.atom b/out/index.atom index bfe1544..d8e5103 100644 --- a/out/index.atom +++ b/out/index.atom @@ -1,24 +1,23 @@ <?xml version="1.0" encoding="utf-8"?> <feed xmlns="http://www.w3.org/2005/Atom"> - <title>AndrewDM.me </title> + <title>AndrewDM</title> <link rel="self" type="application/atom+xml" href="./index.atom"/> <link rel="alternate" type="text/html" href="./"/> <link rel="alternate" type="text/markdown" href="./index.md"/> - <updated>2017-01-03T19:05:27-05:00</updated> + <updated>2017-01-06T23:53:07-05:00</updated> <author><name>Andrew Murrell</name><uri>https://andrewdm.me/</uri><email>ImFromNASA@gmail.com</email></author> - <id>https://www.andrewdm.me</id> + <id>https://www.andrewdm.me/</id> - <entry xmlns="http://www.w3.org/2005/Atom"> - <link rel="alternate" type="text/html" href="https://www.andrewdm.me/dnd/PsionicSchools.html"/> - <id>https://www.andrewdm.me/dnd/PsionicSchools.html</id> - <updated>2017-01-03T19:05:27-05:00</updated> - <published>2017-01-03T19:05:27-05:00</published> - <title>Schools of Psionics</title> - <author><name>Andrew Murrell</name><uri>https://andrewdm.me/</uri><email>ImFromNASA@gmail.com</email></author> - - <content type="html"><p>From what I've seen, the most recent few 5e Unearthed Arcana dealing with &quot;Psionics and the Mystic&quot; have been getting somewhat mixed reviews. I don't think this is because of the mechanics--or rather not COMPLETELY because of the mechanics. Mechanics for psionics have always been weird, and the 5e style is good for D&amp;D, so maintaining that is good and won't get any gripes from me.</p> + <link rel="alternate" type="text/html" href="https://www.andrewdm.me/dnd/PsionicSchools.html"/> + <id>https://www.andrewdm.me/dnd/PsionicSchools.html</id> + <updated>2017-01-06T23:53:07-05:00</updated> + <published>2017-01-03T18:31:41-05:00</published> + <title>Schools of Psionics</title> + <author><name>Andrew Murrell</name><uri>https://andrewdm.me/</uri><email>ImFromNASA@gmail.com</email></author> + <category term="ES" label="Essay" /><category term="HB" label="Homebrew" /> + <content type="html"><p>From what I've seen, the most recent few 5e Unearthed Arcana dealing with &quot;Psionics and the Mystic&quot; have been getting somewhat mixed reviews. I don't think this is because of the mechanics--or rather not COMPLETELY because of the mechanics. Mechanics for psionics have always been weird, and the 5e style is good for D&amp;D, so maintaining that is good and won't get any gripes from me.</p> <p>But I think that no matter what purely mechanical tweaks the UA team has planned for the Mystic, the general lukewarm reception isn't going to change unless we get something else squared away first. Something a little deeper--something that helps us grasp Psionics in the same way we grasp Magic: with a complete and intuitive system.</p> <p>With Weave-based magic there are schools which somewhat delineate magical effects (conjuration, divination, etc), but that's not exactly what I mean. Not to bash the magical schools (any system will have inconsistencies--mine notwithstanding), but few people really understand what it means to be a wizard by what school of magic they specialize in. An enchantment wizard isn't fundamentally different from an evocation one. But a wizard is different than a bard or a warlock. These &quot;Schools of Psionics&quot; are as much about the state of mind of the manifester and the method for manifestation as they are about the outcome of the manifestation (there are several of my Psionic &quot;schools&quot; that may each manifest effects in the transmutation school of magic for instance, but each according to its own particular rules).</p> <p>What I mean is this:</p> @@ -90,20 +89,18 @@ <p><strong>Whitefire Portal</strong>: You burn a temporary hole through the Astral Plane and into another plane of your choice. Once per long rest, centered on a point within 300 ft of you, you summon raw Astral ectoplasm which burns with hellish, white-hot fury. Any creature standing within 20 feet of the whitefire must make a Dexterity saving throw or take 12d10 fire damage or half on a successful save. Inanimate objects in the area also take the damage and flammable objects may catch on fire. A portal then opens to the chosen plane as with a Gate spell and remains open for 1 minute as the planes slowly knit themselves back together. Alternatively, instead of a specific location on a plane of your choice, you may choose to have your portal open into a generally inhospitable location in one of the elemental planes or the planes of positive or negative energy. If you do so, creatures who enter or begin their turns within 20 feet of the portal take 6d10 damage of the appropriate elemental or energy type.</p> <p>I'm actually working on an entire Psionist class for eventual publication on the Dungeon Master's Guild (or as part of my &quot;MagnumOpis-MagicOfTheMultiverse&quot; which covers EVERYTHING magical as I understand it). Of course if somebody #wotcstaff wants to buy it and/or hire me, I'd be totally up for #theorycrafting for a living.</p> </content> - <rights type="html"><p>The content of this page is Copyright © <a href="mailto:ImFromNASA@gmail.com">Andrew Murrell</a>.</p> -<p>This page is licensed under the <a href="https://creativecommons.org/licenses/by-sa/3.0/">CC BY-SA-3.0</a> license.</p></rights> - - </entry> - - <entry xmlns="http://www.w3.org/2005/Atom"> - <link rel="alternate" type="text/html" href="https://www.andrewdm.me/dnd/SpellGauntlet.html"/> - <id>https://www.andrewdm.me/dnd/SpellGauntlet.html</id> - <updated>2017-01-03T19:05:27-05:00</updated> - <published>2017-01-03T19:05:27-05:00</published> - <title>Spell Gauntlet: Practical Spellcasting</title> - <author><name>Andrew Murrell</name><uri>https://andrewdm.me/</uri><email>ImFromNASA@gmail.com</email></author> - - <content type="html"><h1 id="teleport">Teleport</h1> + <rights type="html"><p>The content of this page is Copyright © 2017 <a href="mailto:ImFromNASA@gmail.com">Andrew Murrell</a>.</p> +<p>This page is licensed under the <a href="">CC BS-SA-3.0</a> license.</p></rights> +</entry> +<entry xmlns="http://www.w3.org/2005/Atom"> + <link rel="alternate" type="text/html" href="https://www.andrewdm.me/dnd/SpellGauntlet.html"/> + <id>https://www.andrewdm.me/dnd/SpellGauntlet.html</id> + <updated>2017-01-06T23:53:07-05:00</updated> + <published>2017-01-03T18:31:41-05:00</published> + <title>Spell Gauntlet: Practical Spellcasting</title> + <author><name>Andrew Murrell</name><uri>https://andrewdm.me/</uri><email>ImFromNASA@gmail.com</email></author> + <category term="FF" label="Flash Fiction" /><category term="SS" label="Short Story" /><category term="WP" label="WIP" /> + <content type="html"><h1 id="teleport">Teleport</h1> <h2 id="wizard---ft.-ula-mindis">Wizard - ft. Ula Mindis</h2> <p>The young Wizard Ula Mindis awoke to the smell of steeping tea.</p> <p>She sighed, opened her sleep-encrusted eyes, and yawned. Another day. Another attempt. She rolled out of bed and drifted over to the window. It was cracked open, but she threw it wide to welcome the morning air and golden sunrise into her bedroom, or study rather. She'd recently moved her most used bookcases in here for easy access. Her spellbook sat open at its usual spot, turned to the page she'd most recently been studying. This particular spell she'd attempted half a dozen times to no avail, but this morning felt somehow auspicious for it.</p> @@ -278,37 +275,56 @@ <p>Everything is blurry, especially your memory. Standing around you are your adventuring companions. It feels like you just saw them moments ago? Was there a battle? What's going on? You can't remember anything... it's all just indistinct and gray.</p> <p>Faust and the Fugue Plane -Andrew Murrell</p> </content> - <rights type="html"><p>The content of this page is Copyright © <a href="mailto:ImFromNASA@gmail.com">Andrew Murrell</a>.</p> -<p>This page is licensed under the <a href="https://creativecommons.org/licenses/by-sa/3.0/">CC BY-SA-3.0</a> license.</p></rights> - - </entry> + <rights type="html"><p>The content of this page is Copyright © 2017 <a href="mailto:ImFromNASA@gmail.com">Andrew Murrell</a>.</p> +<p>This page is licensed under the <a href="">CC BS-SA-3.0</a> license.</p></rights> +</entry> +<entry xmlns="http://www.w3.org/2005/Atom"> + <link rel="alternate" type="text/html" href="https://www.andrewdm.me/ChangeLog.html"/> + <id>https://www.andrewdm.me/ChangeLog.html</id> + <updated>2017-01-04T19:28:25-05:00</updated> + <published>2017-01-03T23:02:19-05:00</published> + <title>ChangeLog</title> + <author><name>Andrew Murrell</name><uri>https://andrewdm.me/</uri><email>ImFromNASA@gmail.com</email></author> - <entry xmlns="http://www.w3.org/2005/Atom"> - <link rel="alternate" type="text/html" href="https://www.andrewdm.me/Andrew.html"/> - <id>https://www.andrewdm.me/Andrew.html</id> - <updated>2016-12-31T17:43:33-07:00</updated> - <published>2016-12-31T17:43:33-07:00</published> - <title>Hello Internet Person!</title> - <author><name>Andrew Murrell</name><uri>https://andrewdm.me/</uri><email>ImFromNASA@gmail.com</email></author> - - <content type="html"><p>Hello Internet Person!</p> + <content type="html"><h1 id="changelog">ChangeLog</h1> +<h2 id="luke-shumaker-lukeshusbcglobal.net">2017-01-04 Luke Shumaker &lt;lukeshu@sbcglobal.net&gt;</h2> +<p>Change the title of &quot;Psionist&quot; -&gt; &quot;Psionist Class [5e]&quot;</p> +<pre><code>src/dnd/Psionist.md | 2 +- +1 file changed, 1 insertion(+), 1 deletion(-)</code></pre> +<h2 id="august-2016">31 August 2016</h2> +<p>Decided that the 1/5th of 'Magic is Magic' that was 'finished' was actually trash.</p> +<p>Worked on &quot;Harvey's Adventure&quot; for a pair of paragraphs.</p> +<h2 id="august-2016-1">30 August 2016</h2> +<p>Updated Tastavi with my introduction and 'Andrew Stamp of Approval'™ rewrite.</p> +<p>Decided that there are not enough hours in a day.</p> +</content> + <rights type="html"><p>The content of this page is Copyright © 2017 <a href="mailto:ImFromNASA@gmail.com">Andrew Murrell</a>.</p> +<p>This page is licensed under the <a href="">CC BS-SA-3.0</a> license.</p></rights> +</entry> +<entry xmlns="http://www.w3.org/2005/Atom"> + <link rel="alternate" type="text/html" href="https://www.andrewdm.me/Andrew.html"/> + <id>https://www.andrewdm.me/Andrew.html</id> + <updated>2016-12-31T19:43:33-05:00</updated> + <published>2016-12-31T19:43:33-05:00</published> + <title>Hello Internet Person!</title> + <author><name>Andrew Murrell</name><uri>https://andrewdm.me/</uri><email>ImFromNASA@gmail.com</email></author> + + <content type="html"><p>Hello Internet Person!</p> <p>I'm Andrew D. Murrell, and I'm a DM.</p> <p>Though I hold a degree in Physics, am currently working as a manager and editor at a small tech firm. I write, mostly to teach my players about the whatever they want to know about the Forgotten Realms, but also because I think stories make the world a better place. I can be contacted at ImFromNASA@gmail.com and would love to hear from you!</p> </content> - <rights type="html"><p>The content of this page is Copyright © <a href="mailto:ImFromNASA@gmail.com">Andrew Murrell</a>.</p> -<p>This page is licensed under the <a href="https://creativecommons.org/licenses/by-sa/3.0/">CC BY-SA-3.0</a> license.</p></rights> - - </entry> - - <entry xmlns="http://www.w3.org/2005/Atom"> - <link rel="alternate" type="text/html" href="https://www.andrewdm.me/dnd/Tastavi.html"/> - <id>https://www.andrewdm.me/dnd/Tastavi.html</id> - <updated>2016-08-30T00:00:00+00:00</updated> - <published>2016-08-30T00:00:00+00:00</published> - <title>Tastavi D'Maelnor of Llolethane</title> - <author><name>Andrew Murrell</name><uri>https://andrewdm.me/</uri><email>ImFromNASA@gmail.com</email></author> - - <content type="html"><p> + <rights type="html"><p>The content of this page is Copyright © 2016 <a href="mailto:ImFromNASA@gmail.com">Andrew Murrell</a>.</p> +<p>This page is licensed under the <a href="">CC BS-SA-3.0</a> license.</p></rights> +</entry> +<entry xmlns="http://www.w3.org/2005/Atom"> + <link rel="alternate" type="text/html" href="https://www.andrewdm.me/dnd/Tastavi.html"/> + <id>https://www.andrewdm.me/dnd/Tastavi.html</id> + <updated>2016-08-30T19:56:00-04:00</updated> + <published>2016-08-30T19:56:00-04:00</published> + <title>Tastavi D'Maelnor of Llolethane</title> + <author><name>Andrew Murrell</name><uri>https://andrewdm.me/</uri><email>ImFromNASA@gmail.com</email></author> + <category term="SS" label="Short Story" /> + <content type="html"><p> When I DM, I try to allow players to have as many options for character creation as I can. Usually, this manifests in pretty interesting, but stable, characters. And other times… you get Tastavi. </p> <p> @@ -1670,20 +1686,18 @@ He lay upon the ground thinking it maybe better he have died quickly in the tunn </div> </div> </content> - <rights type="html"><p>The content of this page is Copyright © <a href="mailto:ImFromNASA@gmail.com">Andrew Murrell</a>.</p> -<p>This page is licensed under the <a href="https://creativecommons.org/licenses/by-sa/3.0/">CC BY-SA-3.0</a> license.</p></rights> - - </entry> - - <entry xmlns="http://www.w3.org/2005/Atom"> - <link rel="alternate" type="text/html" href="https://www.andrewdm.me/dnd/Psionist.html"/> - <id>https://www.andrewdm.me/dnd/Psionist.html</id> - <updated>2016-07-16T00:00:00+00:00</updated> - <published>2016-07-16T00:00:00+00:00</published> - <title>Psionist Class [5e]</title> - <author><name>Andrew Murrell</name><uri>https://andrewdm.me/</uri><email>ImFromNASA@gmail.com</email></author> - - <content type="html"><div id="table-of-contents"> + <rights type="html"><p>The content of this page is Copyright © 2016 <a href="mailto:ImFromNASA@gmail.com">Andrew Murrell</a>.</p> +<p>This page is licensed under the <a href="">CC BS-SA-3.0</a> license.</p></rights> +</entry> +<entry xmlns="http://www.w3.org/2005/Atom"> + <link rel="alternate" type="text/html" href="https://www.andrewdm.me/dnd/Psionist.html"/> + <id>https://www.andrewdm.me/dnd/Psionist.html</id> + <updated>2016-07-16T21:01:00-04:00</updated> + <published>2016-07-16T21:01:00-04:00</published> + <title>Psionist Class [5e]</title> + <author><name>Andrew Murrell</name><uri>https://andrewdm.me/</uri><email>ImFromNASA@gmail.com</email></author> + <category term="ES" label="Essay" /><category term="HB" label="Homebrew" /> + <content type="html"><div id="table-of-contents"> <h2> Table of Contents </h2> @@ -4175,29 +4189,30 @@ Footnotes: </div> </div> </content> - <rights type="html"><p>The content of this page is Copyright © <a href="mailto:ImFromNASA@gmail.com">Andrew Murrell</a>.</p> -<p>This page is licensed under the <a href="https://creativecommons.org/licenses/by-sa/3.0/">CC BY-SA-3.0</a> license.</p></rights> - - </entry> + <rights type="html"><p>The content of this page is Copyright © 2016 <a href="mailto:ImFromNASA@gmail.com">Andrew Murrell</a>.</p> +<p>This page is licensed under the <a href="">CC BS-SA-3.0</a> license.</p></rights> +</entry> +<entry xmlns="http://www.w3.org/2005/Atom"> + <link rel="alternate" type="text/html" href="https://www.andrewdm.me/dnd/WaterdeepBazaar/WaterdeepBazaar.html"/> + <id>https://www.andrewdm.me/dnd/WaterdeepBazaar/WaterdeepBazaar.html</id> + <updated>2015-12-13T19:00:00-05:00</updated> + <published>2015-12-13T19:00:00-05:00</published> + <title>Waterdeep Bazaar: Marketplace Generator</title> + <author><name>Andrew Murrell</name><uri>https://andrewdm.me/</uri><email>ImFromNASA@gmail.com</email></author> + <category term="DM" label="DMing Resource" /><category term="WP" label="WIP" /> - <entry xmlns="http://www.w3.org/2005/Atom"> - <link rel="alternate" type="text/html" href="https://www.andrewdm.me/dnd/WaterdeepBazaar/WaterdeepBazaar.html"/> - <id>https://www.andrewdm.me/dnd/WaterdeepBazaar/WaterdeepBazaar.html</id> - <updated>2015-12-14T00:00:00+00:00</updated> - <published>2015-12-14T00:00:00+00:00</published> - <title>Waterdeep Bazaar: Marketplace Generator</title> - <author><name>Andrew Murrell</name><uri>https://andrewdm.me/</uri><email>ImFromNASA@gmail.com</email></author> - - </entry> - <entry xmlns="http://www.w3.org/2005/Atom"> - <link rel="alternate" type="text/html" href="http://365tomorrows.com/12/03/a-simple-lament/"/> - <id>http://365tomorrows.com/12/03/a-simple-lament/</id> - <updated>2013-12-03T00:00:00+00:00</updated> - <published>2013-12-03T00:00:00+00:00</published> - <title>365 Tomorrows: A Simple Lament</title> - <author><name>Andrew Murrell</name><uri>https://andrewdm.me/</uri><email>ImFromNASA@gmail.com</email></author> - - </entry> +</entry> +<entry xmlns="http://www.w3.org/2005/Atom"> + <link rel="alternate" type="text/html" href="http://365tomorrows.com/12/03/a-simple-lament/"/> + <id>http://365tomorrows.com/12/03/a-simple-lament/</id> + <updated>2013-12-02T19:00:00-05:00</updated> + <published>2013-12-02T19:00:00-05:00</published> + <title>365 Tomorrows: A Simple Lament</title> + <author><name>Andrew Murrell</name><uri>https://andrewdm.me/</uri><email>ImFromNASA@gmail.com</email></author> + <category term="FF" label="Flash Fiction" /> + +</entry> + </feed> diff --git a/out/index.html b/out/index.html index 1994d05..e4b0af8 100644 --- a/out/index.html +++ b/out/index.html @@ -2,14 +2,14 @@ <html lang="en"> <head> <meta charset="utf-8"> - <title>AndrewDM</title> + <title>AndrewDM — AndrewDM</title> <link rel="stylesheet" href="/main.css"> <link rel="alternate" type="application/atom+xml" href="/index.atom" /> </head> <body class="index"> <header> - <h1>AndrewDM</h1> + <h1 class=breadcrumbs><a href="">AndrewDM</a></h1> <nav> <ul> <li><a href="/">Projects</a> @@ -21,33 +21,35 @@ </form> </ul> </nav> - <p class=breadcrumbs><a href="/">Andrew D. Murrell</a></p> </header> <article> - <h1 class=title></h1> <ul> -<li><span><a href="Andrew.html" title="Published on 2016-12-31">Hello Internet Person!</a></span><span></span></li> +<li><span><a class="" href="Andrew.html" title="Published on 2016-12-31">Hello Internet Person!</a></span><span></span></li> +<li><span><a class="" href="ChangeLog.html" title="Published on 2017-01-03 (updated on 2017-01-04)">ChangeLog</a></span><span></span></li> </ul> -<h2 id="dungeons-dragons"><a href="dnd">Dungeons & Dragons</a></h2> +<h2> +<a href="dnd/">Dungeons & Dragons</a> +</h2> <ul> -<li><span><a href="dnd/PsionicSchools.html" title="Published on 2017-01-03">Schools of Psionics</a></span><span><a class="tag ES" href="/tags/ES.html">Essay</a><a class="tag HB" href="/tags/HB.html">Homebrew</a></span></li> -<li><span><a href="dnd/SpellGauntlet.html" title="Published on 2017-01-03">Spell Gauntlet: Practical Spellcasting</a></span><span><a class="tag FF" href="/tags/FF.html">Flash Fiction</a><a class="tag SS" href="/tags/SS.html">Short Story</a><a class="tag WP" href="/tags/WP.html">WIP</a></span></li> -<li><span><a href="dnd/Tastavi.html" title="Published on 2016-08-30">Tastavi D'Maelnor of Llolethane</a></span><span><a class="tag SS" href="/tags/SS.html">Short Story</a></span></li> -<li><span><a href="dnd/Psionist.html" title="Published on 2016-07-16">Psionist Class [5e]</a></span><span><a class="tag ES" href="/tags/ES.html">Essay</a><a class="tag HB" href="/tags/HB.html">Homebrew</a></span></li> -<li><span><a class="external" href="dnd/WaterdeepBazaar/WaterdeepBazaar.html" title="Published on 2015-12-14">Waterdeep Bazaar: Marketplace Generator</a></span><span><a class="tag DM" href="/tags/DM.html">DMing Resource</a><a class="tag WP" href="/tags/WP.html">WIP</a></span></li> +<li><span><a class="external" href="dnd/WaterdeepBazaar/WaterdeepBazaar.html" title="Published on 2015-12-13">Waterdeep Bazaar: Marketplace Generator</a></span><span><a class="tag DM" href="/tags/DM.html">DMing Resource</a><a class="tag WP" href="/tags/WP.html">WIP</a></span></li> +<li><span><a class="" href="dnd/Psionist.html" title="Published on 2016-07-16">Psionist Class [5e]</a></span><span><a class="tag ES" href="/tags/ES.html">Essay</a><a class="tag HB" href="/tags/HB.html">Homebrew</a></span></li> +<li><span><a class="" href="dnd/Tastavi.html" title="Published on 2016-08-30">Tastavi D'Maelnor of Llolethane</a></span><span><a class="tag SS" href="/tags/SS.html">Short Story</a></span></li> +<li><span><a class="" href="dnd/SpellGauntlet.html" title="Published on 2017-01-03 (updated on 2017-01-06)">Spell Gauntlet: Practical Spellcasting</a></span><span><a class="tag FF" href="/tags/FF.html">Flash Fiction</a><a class="tag SS" href="/tags/SS.html">Short Story</a><a class="tag WP" href="/tags/WP.html">WIP</a></span></li> +<li><span><a class="" href="dnd/PsionicSchools.html" title="Published on 2017-01-03 (updated on 2017-01-06)">Schools of Psionics</a></span><span><a class="tag ES" href="/tags/ES.html">Essay</a><a class="tag HB" href="/tags/HB.html">Homebrew</a></span></li> </ul> -<h2 id="programming"><a href="prog">Programming</a></h2> -<h2 id="writing"><a href="writing">Writing</a></h2> +<h2> +<a href="writing/">Writing</a> +</h2> <ul> -<li><span><a class="external" href="http://365tomorrows.com/12/03/a-simple-lament/" title="Published on 2013-12-03">365 Tomorrows: A Simple Lament</a></span><span><a class="tag FF" href="/tags/FF.html">Flash Fiction</a></span></li> +<li><span><a class="external" href="http://365tomorrows.com/12/03/a-simple-lament/" title="Published on 2013-12-02">365 Tomorrows: A Simple Lament</a></span><span><a class="tag FF" href="/tags/FF.html">Flash Fiction</a></span></li> </ul> </article> <footer> <p>The content of this page is Copyright © <a href="mailto:ImFromNASA@gmail.com">Andrew Murrell</a>.</p> -<p>This page is licensed under the <a href="https://creativecommons.org/licenses/by-sa/3.0/">CC BY-SA-3.0</a> license.</p> - <p>Page source: <a href="index.md">index.md</a></p> +<p>This page is licensed under the <a href="">CC BS-SA-3.0</a> license.</p> + <p>Website source: <a href="https://git.andrewdm.me/www.git">www.git</a></p> </footer> </body> diff --git a/out/index.md b/out/index.md deleted file mode 100644 index f4458ab..0000000 --- a/out/index.md +++ /dev/null @@ -1,33 +0,0 @@ ---- -title: "" -class: "index" ---- - - - - - - * <span><a href="Andrew.html" title="Published on 2016-12-31">Hello Internet Person!</a></span><span></span> - - -## [Dungeons & Dragons](dnd) - - - * <span><a href="dnd/PsionicSchools.html" title="Published on 2017-01-03">Schools of Psionics</a></span><span><a class="tag ES" href="/tags/ES.html">Essay</a><a class="tag HB" href="/tags/HB.html">Homebrew</a></span> - * <span><a href="dnd/SpellGauntlet.html" title="Published on 2017-01-03">Spell Gauntlet: Practical Spellcasting</a></span><span><a class="tag FF" href="/tags/FF.html">Flash Fiction</a><a class="tag SS" href="/tags/SS.html">Short Story</a><a class="tag WP" href="/tags/WP.html">WIP</a></span> - * <span><a href="dnd/Tastavi.html" title="Published on 2016-08-30">Tastavi D'Maelnor of Llolethane</a></span><span><a class="tag SS" href="/tags/SS.html">Short Story</a></span> - * <span><a href="dnd/Psionist.html" title="Published on 2016-07-16">Psionist Class [5e]</a></span><span><a class="tag ES" href="/tags/ES.html">Essay</a><a class="tag HB" href="/tags/HB.html">Homebrew</a></span> - * <span><a class="external" href="dnd/WaterdeepBazaar/WaterdeepBazaar.html" title="Published on 2015-12-14">Waterdeep Bazaar: Marketplace Generator</a></span><span><a class="tag DM" href="/tags/DM.html">DMing Resource</a><a class="tag WP" href="/tags/WP.html">WIP</a></span> - - -## [Programming](prog) - - - - -## [Writing](writing) - - - * <span><a class="external" href="http://365tomorrows.com/12/03/a-simple-lament/" title="Published on 2013-12-03">365 Tomorrows: A Simple Lament</a></span><span><a class="tag FF" href="/tags/FF.html">Flash Fiction</a></span> - - diff --git a/out/main.css b/out/main.css index 1589673..d01c617 100644 --- a/out/main.css +++ b/out/main.css @@ -5,19 +5,22 @@ body { header { width: 100%; } header h1 { - font-size: 50px; margin: 0; background-color: rgba(0, 0, 0, 0.6); - color: white; padding: 4px; - padding-bottom: 0; } - header p.breadcrumbs { - background-color: rgba(0, 0, 0, 0.6); - margin: 0; - color: white; - padding: 4px; } - header p.breadcrumbs a { - color: GoldenRod; } + padding-bottom: 0; + text-align: middle; } + header h1 a:first-child { + font-size: 50px; + color: white; } + header h1, header h1 a:not(:first-child) { + color: white; + font-size: 15px; + color: white; } + header h1 a { + text-decoration: none; } + header h1 a:hover, header h1 a:focus { + text-decoration: underline; } header nav { /* layout */ line-height: 1; diff --git a/out/writing/index.html b/out/writing/index.html index ec94298..36117af 100644 --- a/out/writing/index.html +++ b/out/writing/index.html @@ -9,7 +9,7 @@ </head> <body class="index"> <header> - <h1>AndrewDM</h1> + <h1 class=breadcrumbs><a href="../">AndrewDM</a> » <a href="">Writing</a></h1> <nav> <ul> <li><a href="/">Projects</a> @@ -21,20 +21,18 @@ </form> </ul> </nav> - <p class=breadcrumbs><a href="/">Andrew D. Murrell</a> » <a href="/writing">writing</a></p> </header> <article> - <h1 class=title>Writing</h1> <ul> -<li><span><a class="external" href="http://365tomorrows.com/12/03/a-simple-lament/" title="Published on 2013-12-03">365 Tomorrows: A Simple Lament</a></span><span><a class="tag FF" href="/tags/FF.html">Flash Fiction</a></span></li> +<li><span><a class="external" href="http://365tomorrows.com/12/03/a-simple-lament/" title="Published on 2013-12-02">365 Tomorrows: A Simple Lament</a></span><span><a class="tag FF" href="/tags/FF.html">Flash Fiction</a></span></li> </ul> </article> <footer> <p>The content of this page is Copyright © <a href="mailto:ImFromNASA@gmail.com">Andrew Murrell</a>.</p> -<p>This page is licensed under the <a href="https://creativecommons.org/licenses/by-sa/3.0/">CC BY-SA-3.0</a> license.</p> - <p>Page source: <a href="writing/index.md">index.md</a></p> +<p>This page is licensed under the <a href="">CC BS-SA-3.0</a> license.</p> + <p>Website source: <a href="https://git.andrewdm.me/www.git">www.git</a></p> </footer> </body> diff --git a/out/writing/index.md b/out/writing/index.md deleted file mode 100644 index 6d253e8..0000000 --- a/out/writing/index.md +++ /dev/null @@ -1,12 +0,0 @@ ---- -title: "Writing" -class: "index" ---- - - - - - - * <span><a class="external" href="http://365tomorrows.com/12/03/a-simple-lament/" title="Published on 2013-12-03">365 Tomorrows: A Simple Lament</a></span><span><a class="tag FF" href="/tags/FF.html">Flash Fiction</a></span> - - diff --git a/src/dnd/PsionicSchools.org b/src/dnd/PsionicSchools.org index bd3ab60..9f71b15 100644 --- a/src/dnd/PsionicSchools.org +++ b/src/dnd/PsionicSchools.org @@ -1,6 +1,6 @@ #+TITLE: Schools of Psionics
#+CLASS: dnd
-#+TAGS: ES HB
+#+CATEGORIES: ES HB
From what I've seen, the most recent few 5e Unearthed Arcana dealing
with "Psionics and the Mystic" have been getting somewhat mixed
diff --git a/src/dnd/Psionist.md b/src/dnd/Psionist.md index 3d21f58..66869db 100644 --- a/src/dnd/Psionist.md +++ b/src/dnd/Psionist.md @@ -2,7 +2,7 @@ title: "Psionist Class [5e]" updated: "2016-07-16T21:01-0400" class: "dnd" -tags: ES HB +categories: ES HB --- <div id="table-of-contents"> diff --git a/src/dnd/SpellGauntlet.org b/src/dnd/SpellGauntlet.org index 8cf1c0d..9eb030d 100644 --- a/src/dnd/SpellGauntlet.org +++ b/src/dnd/SpellGauntlet.org @@ -1,6 +1,6 @@ #+TITLE: Spell Gauntlet: Practical Spellcasting #+CLASS: dnd -#+TAGS: FF SS WP +#+CATEGORIES: FF SS WP * Teleport diff --git a/src/dnd/Tastavi.md b/src/dnd/Tastavi.md index d9b7e86..77efda6 100644 --- a/src/dnd/Tastavi.md +++ b/src/dnd/Tastavi.md @@ -2,7 +2,7 @@ title: "Tastavi D'Maelnor of Llolethane" updated: "2016-08-30 Tue 23:56" class: "dnd" -tags: SS +categories: SS --- <p> diff --git a/src/dnd/index.yaml b/src/dnd/index.yaml index 339274b..248d91f 100644 --- a/src/dnd/index.yaml +++ b/src/dnd/index.yaml @@ -3,4 +3,4 @@ external: - title: "Waterdeep Bazaar: Marketplace Generator" url: "/dnd/WaterdeepBazaar/WaterdeepBazaar.html" published: "2015-12-14" - tags: [DM, WP] + categories: [DM, WP] diff --git a/src/index.yaml b/src/index.yaml index 535f810..4106fdf 100644 --- a/src/index.yaml +++ b/src/index.yaml @@ -1,15 +1 @@ -title: "" -sections: - "writing": "Writing" - "dnd": "Dungeons & Dragons" - "prog": "Programming" -external: - - title: "365 Tomorrows: A Simple Lament" - url: "http://365tomorrows.com/12/03/a-simple-lament/" - published: "2013-12-03" - tags: [FF] - section: "writing" - - title: "Waterdeep Bazaar: Marketplace Generator" - url: "/dnd/WaterdeepBazaar/WaterdeepBazaar.html" - published: "2015-12-14" - tags: [DM, WP] +title: "AndrewDM" diff --git a/src/main.scss b/src/main.scss index e143892..9a75c62 100644 --- a/src/main.scss +++ b/src/main.scss @@ -7,21 +7,26 @@ header { width: 100%; h1 { - font-size: 50px; margin: 0; background-color: rgba(0, 0, 0, 0.6); - color: white; padding: 4px; padding-bottom: 0; - } - p.breadcrumbs { - background-color: rgba(0, 0, 0, 0.6); - margin: 0; - color: white; - padding: 4px; + text-align: middle; + a:first-child { + font-size: 50px; + color: white; + } + &, a:not(:first-child) { + color: white; + font-size: 15px; + color: white; + } a { - color: GoldenRod; + text-decoration: none; + } + a:hover, a:focus { + text-decoration: underline; } } diff --git a/src/writing/index.yaml b/src/writing/index.yaml index a04bb2d..498038e 100644 --- a/src/writing/index.yaml +++ b/src/writing/index.yaml @@ -3,4 +3,4 @@ external: - title: "365 Tomorrows: A Simple Lament" url: "http://365tomorrows.com/12/03/a-simple-lament/" published: "2013-12-03" - tags: [FF] + categories: [FF] diff --git a/tmpl/index.atom.erb b/tmpl/index.atom.erb new file mode 100644 index 0000000..390c02a --- /dev/null +++ b/tmpl/index.atom.erb @@ -0,0 +1,12 @@ +<feed xmlns="http://www.w3.org/2005/Atom"> + + <title><%= atom_title %></title> + <link rel="self" type="application/atom+xml" href="./index.atom"/> + <link rel="alternate" type="text/html" href="./"/> + <link rel="alternate" type="text/markdown" href="./index.md"/> + <updated><%= index_pages_leaves.map{|p|p.atom_updated}.sort.last.to_datetime.rfc3339 %></updated> + <author><%= atom_author.atom %></author> + <id><%= url %></id> + + <% index_pages_leaves.sort_by{|p|p.atom_updated}.reverse.each do |page| %><%= page.atom %><% end %> +</feed> diff --git a/tmpl/index.md.erb b/tmpl/index.md.erb new file mode 100644 index 0000000..2febcb5 --- /dev/null +++ b/tmpl/index.md.erb @@ -0,0 +1,6 @@ +--- +title: "<%= atom_title %>" +class: "index" +--- + +<%= index_link(url, 1) %> diff --git a/bin/index.md.erb b/tmpl/index.md.erb.bak index a3ec547..a3ec547 100644 --- a/bin/index.md.erb +++ b/tmpl/index.md.erb.bak diff --git a/tmpl/page.atom.erb b/tmpl/page.atom.erb new file mode 100644 index 0000000..e4957e3 --- /dev/null +++ b/tmpl/page.atom.erb @@ -0,0 +1,11 @@ +<% require 'siteutil' %><entry xmlns="http://www.w3.org/2005/Atom"> + <link rel="alternate" type="text/html" href="<%= url %>"/> + <id><%= url %></id> + <updated><%= atom_updated.to_datetime.rfc3339 %></updated> + <published><%= atom_published.to_datetime.rfc3339 %></published> + <title><%= atom_title %></title> + <author><%= atom_author.atom %></author> + <% atom_categories.each do |c| %><%= c.atom %><% end %> + <% if atom_content %><content type="html"><%= Sitegen::html_escape(atom_content) %></content><% end %> + <% if atom_rights %><rights type="html"><%= Sitegen::html_escape(atom_rights) %></rights><% end %> +</entry> diff --git a/bin/page.html.erb b/tmpl/page.html.erb index e2dc9fe..5dc95ea 100644 --- a/bin/page.html.erb +++ b/tmpl/page.html.erb @@ -1,15 +1,15 @@ -<!DOCTYPE html> +<% require 'siteutil' %><!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> - <title><%= @page.title %><% unless @page.title.empty? %> — <% end %>AndrewDM</title> + <title><%= atom_title %> — AndrewDM</title> <link rel="stylesheet" href="/main.css"> <link rel="alternate" type="application/atom+xml" href="/index.atom" /> - <%= @page.head %> + <%= html_head_extra %> </head> - <body<% if @page.class %> class="<%= @page.class %>"<% end %>> + <body class="<%= html_class %>"> <header> - <h1>AndrewDM</h1> + <h1 class=breadcrumbs><%= Sitegen::breadcrumbs(url) %></h1> <nav> <ul> <li><a href="/">Projects</a> @@ -21,16 +21,14 @@ </form> </ul> </nav> - <p class=breadcrumbs><%= @page.breadcrumbs %></p> </header> <article> - <% if @page.tags.count > 0 %><p>Tags: <% @page.tags.each do |t| %><%= t.html %><% end %></p><% end %> - <% if @page.showtitle %><h1 class=title><%= @page.title %></h1><% end %> - <%= @page.content %> + <% if atom_categories.count > 0 %><p>Tags: <% atom_categories.each do |t| %><%= t.html %><% end %></p><% end %> + <%= atom_content %> </article> <footer> - <%= @page.rights %> - <p>Page source: <a href="<%= @url.route_to(@page.srcurl) %>"><%= File.basename(@page.srcurl.to_s) %></a></p> + <%= atom_rights %> + <% if local_srcurl %><p>Page source: <a href="<%= url.route_to(local_srcurl) %>"><%= File.basename(local_srcurl.to_s) %></a></p><% end %> <p>Website source: <a href="https://git.andrewdm.me/www.git">www.git</a></p> </footer> </body> |