dweb v0.1

This commit is contained in:
Jacob Parker 2012-02-19 02:30:23 -05:00 committed by Jacob Parker
commit c3c1116e5f
10 changed files with 2043 additions and 0 deletions

3
.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
pub/*
srv/*
bin/web

4
.htaccess Normal file
View File

@ -0,0 +1,4 @@
RewriteEngine on
RewriteBase /~j3parker/
RewriteRule ^pub/(.*) - [L]
RewriteRule ^(.*) /users/j3parker/www/bin/web [L]

2
bin/.htaccess Normal file
View File

@ -0,0 +1,2 @@
Options +ExecCGI
SetHandler cgi-script

3
bin/changelog Executable file
View File

@ -0,0 +1,3 @@
echo "<ul>"
git log --pretty=format:'<li>%s - %aN (%ae) <b>(%cr)</b></li>' --abbrev-commit --date=relative
echo "</ul>"

1450
bin/contrib/Markdown.pl Executable file

File diff suppressed because it is too large Load Diff

335
pub/style/style.css Normal file
View File

@ -0,0 +1,335 @@
/* Default werc style */
/* General style guidelines:
- All font-size at least 14px (recommended 16px)
- Line-height: 1.5 for paragraph body, 1.1 for header
*/
body {
color: black;
background-color: white;
font-family: Helvetica, Verdana, Arial, 'Liberation Sans', FreeSans, sans-serif;
font-size: 84%; /* Enables font size scaling in MSIE */
margin: 0;
padding: 0;
}
/* # Header # */
.superHeader {
color: white;
background-color: rgb(100,135,220);
height: 1.6em;
}
.superHeader img { vertical-align: bottom; }
.superHeader a {
color: white;
background-color: transparent;
font-size: 91%;
margin: 0;
padding: 0 0.5ex 0 0.25ex;
}
a { text-decoration: none; }
a:hover { text-decoration: underline; }
.superHeader div {
position: absolute;
top: 0.40ex;
}
.superHeader .left { left: 0.4em; }
.superHeader .right { right: 0.4em; }
.midHeader {
color: rgb(39,78,144);
background-color: rgb(140,170,230);
background-color: #ff6d06;
border: solid 0 black;
border-width: 2px 0;
}
.headerTitle {
color: black;
font-size: 233%;
font-weight: normal;
margin: 0 0 0 4mm;
padding: 0.25ex 0;
}
#headerSubTitle {
font-size: 50%;
font-style: italic;
margin-left: 1em;
}
.headerTitle a { color: black; }
.headerTitle a:hover { text-decoration: none; }
.subHeader {
display: none;
color: white;
background-color: rgb(0,51,153);
margin: 0;
padding: 1ex 1ex 1ex 1.5mm;
}
.subHeader a {
color: white;
background-color: transparent;
font-weight: bold;
margin: 0;
padding: 0 0.75ex 0 0.5ex;
}
.superHeader .highlight, .subHeader .highlight {
color: rgb(253,160,91);
background-color: transparent;
}
/* # Side # */
#side-bar {
width: 16em;
float: left;
clear: left;
border-right: 1px solid #ddd;
}
#side-bar div {
border-bottom: 1px solid #ddd;
}
.sideBarTitle {
font-weight: bold;
margin: 0 0 0.5em 2mm;
padding: 1em 0 0 0;
}
#side-bar ul {
list-style-type: none;
list-style-position: outside;
margin: 0;
padding: 0 0 0.3em 0;
}
li ul {
padding-left: 0.6em !important;
}
#side-bar li {
margin: 0;
padding: 0.1ex 0; /* Circumvents a rendering bug (?) in MSIE 6.0 XXX should move to iehacks.css, this causes an ugly gap */
}
#side-bar a {
color: rgb(0,102,204);
background-color: transparent;
margin: 0;
padding: 0.25em 1ex 0.25em 2mm;
display: block;
text-transform: capitalize;
font-weight: bold!important;
font-size: 102%;
border-left: white solid 0.2em;
}
.thisPage, .thisPage a {
color: black!important;
background-color: white;
padding-left: 5mm;
}
#side-bar a:hover {
color: white;
background-color: rgb(100,135,220);
border-left: black solid 0.2em;
text-decoration: none;
}
.sideBarText {
line-height: 1.5em;
margin: 0 0 1em 0;
padding: 0 1.5ex 0 2.5mm;
display: block;
}
#side-bar .sideBarText a {
margin: 0;
padding: 0;
display: inline;
}
#side-bar .sideBarText a:hover {
color: rgb(0,102,204);
background-color: transparent;
text-decoration: none;
}
/* # Main Copy # */
#main-copy {
max-width: 70em;
color: black;
background-color: transparent;
text-align: justify;
line-height: 1.5em;
margin: 0em 0 0 16em;
padding: 0.5mm 5mm 5mm 5mm;
border-left: 1px solid #ddd;
}
#bodyText {
margin: 0 0 0 15.5em;
padding: 2mm 5mm 2mm 5mm;
}
#main-copy p {
margin: 1em 1ex 1em 1ex !important; /* Need !important so troff-generated pages don't look totally squezed */
padding: 0;
}
#main-copy a {
color: rgb(0,102,204);
background-color: transparent;
}
#main-copy a:hover {
color: rgb(100,135,220);
}
#main-copy h1, #main-copy h2 {
color: rgb(0,102,204);
background-color: transparent;
font-size: 145.5%;
font-weight: bold;
margin: 2em 0 0 0;
padding: 0.5ex 0 0.5ex 0.6ex;
border-bottom: 2px solid rgb(0,102,204);
}
#main-copy h2 {
font-size: 115.5%;
border-bottom: 1px solid rgb(0,102,204);
}
#main-copy .topOfPage {
color: rgb(0,102,204);
background-color: transparent;
font-size: 91%;
font-weight: bold;
text-decoration: none;
margin: 3ex 1ex 0 0;
padding: 0;
float: right;
}
dl {
margin: 1em 1ex 2em 1ex;
padding: 0;
}
dt {
font-weight: bold;
margin: 0 0 0 0;
padding: 0;
}
dd {
margin: 0 0 2em 2em;
padding: 0;
}
/* # Footer # */
#footer {
color: white;
background-color: rgb(100,135,220);
padding: 1em;
clear: both;
}
#footer .left {
text-align: left;
line-height: 1.55em;
float: left;
clear: left;
}
#footer .right {
text-align: right;
line-height: 1.45em;
}
#footer a {
color: white;
background-color: transparent;
}
/* GENERAL */
table {
border: solid 1px black;
}
th {
background-color: #abc;
border: solid 1px black;
text-align: center;
}
td {
background-color: #def;
border: solid 1px black;
}
hr {
border-width: 0px 0px 0.1em 0px;
border-color: black;
}
acronym, .titleTip {
border-bottom: 1px solid #ddd;
cursor: help;
margin: 0;
padding: 0 0 0.4px 0;
}
pre {
margin-left: 2em;
font-size: 1.2em;
}
blockquote {
border-left: 1px solid blue;
font-style: italic;
}
.smallCaps {
font-size: 110%;
font-variant: small-caps;
}
.doNotDisplay { display: none; }
.notify_errors,
.notify_notes,
.notify_success { padding: .8em; margin-bottom: 1em; border: 2px solid #ddd; }
.notify_errors { background: #FBE3E4; color: #8a1f11; border-color: #FBC2C4; }
.notify_notes { background: #FFF6BF; color: #514721; border-color: #FFD324; }
.notify_success { background: #E6EFC2; color: #264409; border-color: #C6D880; }
.notify_errors a { color: #8a1f11; }
.notify_notes a { color: #514721; }
.notify_success a { color: #264409; }
/* # Page/Handler specific # */
h1.dir-list-head, ul.dir-list {
text-transform: capitalize;
font-weight: bold;
}
ul.sitemap-list a {
text-transform: capitalize;
}

1
src/build Executable file
View File

@ -0,0 +1 @@
dmd config.d web.d -ofweb && rm web.o && mv web ../bin/

6
src/config.d Normal file
View File

@ -0,0 +1,6 @@
const string url_root = "/~j3parker/";
const string dweb_root = "/users/j3parker/www/";
const string site_root = dweb_root ~ "srv/";
const string site_title = "Test Title";
const string site_subtitle = "this is a subtitle";

186
src/web.d Executable file
View File

@ -0,0 +1,186 @@
//#!/usr/bin/rdmd
import std.stdio;
import std.process;
import std.file;
import std.array;
import std.string;
import std.algorithm;
import config;
string indent = "";
void html(string s) { writeln(indent ~ s); }
void html_pop(string s) { indent = indent[0..max(0, $-4)]; html(s); }
void html_push(string s) { html(s); indent ~= " "; }
void write_link(string root, string file, bool expand) {
bool isdir = dirExists(file);
html_push("<li>");
html("<a href=\"" ~ construct_rel_link(root, file) ~ "\"" ~
(expand? " class=\"thisPage\">&raquo; <i>" : ">&rsaquo; ")
~ last_in_path(file) ~ (isdir ? "/" : "")
~ (expand? "</i>" : "") ~ "</a>");
html_pop("</li>");
}
void nav_tree_r(string root, string cur_loc, string[] subdirs) {
html_push("<ul>");
foreach(string s; dir(cur_loc)) {
if (s[max(0,$-8)..$]=="index.md") continue;
bool hidden = last_in_path(s).length > 0 && last_in_path(s)[0] == '.';
bool expand = s[cur_loc.length..$] == (subdirs.length == 0 ? "" : subdirs[0]);
if (hidden && !expand) continue;
write_link(root, s, expand);
if (expand && isDir(cur_loc ~ subdirs[0])) {
html_push("<li>");
nav_tree_r(root, cur_loc ~ subdirs[0] ~ "/", subdirs[1..$]);
html_pop("</li>");
}
}
html_pop("</ul>");
}
// this could be better
string[] dir(string path) {
string[] files;
foreach(string s; dirEntries(path, SpanMode.shallow)) files ~= s;
sort(files);
return files;
}
void do_nav_tree(string path) {
try { if (isDir(path) && path[path.length - 1] != '/') { path = site_root; } }
catch (Exception e) { path = site_root; }
html_push("<div id=\"side-bar\">");
string root = get_root_dir(path);
string[] subdirs = explode_slashes(path[site_root.length..$]);
nav_tree_r(root, site_root, subdirs);
html_pop("</div>\n");
}
string last_in_path(string path) {
auto i = max(path.length,1) - 1;
while (i-- > 0) if (path[i] == '/') return path[min(i+1,$)..$];
return path;
}
string chomp_slashes(string path) { return chompPrefix(chomp(path, "/"), "/"); }
string[] explode_slashes(string path) { return split(chomp_slashes(path), "/"); }
string get_root_dir(string path) {
if (path == "") return "";
if (isDir(path)) return path[path.length - 1] == '/' ? path : path ~ "/";
auto i = path.length - 1;
while (--i > 0) if (path[i] == '/') return path[0..i];
return "/";
}
string construct_rel_link(string src, string dst) {
string rel = "";
string[] srcs = explode_slashes(src);
string[] dsts = explode_slashes(dst);
ulong i = 0;
while(i < srcs.length && i < dsts.length && srcs[i] == dsts[i]) i++;
if (i == srcs.length && i == dsts.length) return ".";
foreach (ulong j; 0..(srcs.length - i)) rel ~= "../";
foreach (string s; dsts[i..$]) rel ~= s ~ "/";
return isDir(dst) ? rel : rel[0..$-1];
}
void not_found(string path) {
html("The page <code>" ~ path ~ "</code> does not exist. (404)");
}
void do_header() {
html_push("<div id=\"header\">");
html_push("<div class=\"superHeader\">");
html_push("<div class=\"right\">");
html("<a href=\"" ~ url_root ~ "changelog\">changelog</a>");
html_pop("</div>");
html_pop("</div>");
html_push("<div class=\"midHeader\">");
html_push("<h1 class=\"headerTitle\">");
html("<a href=\"" ~ url_root ~ "\">" ~ site_title ~ " <span id=\"headerSubTitle\">" ~ site_subtitle ~ "</span></a>");
html_pop("</h1>");
html_pop("</div>");
html_push("<div class=\"subHeader\">");
html("<br>");
html_pop("</div>");
html_pop("</div>\n");
}
void do_markdown(string file) {
// sanity check file first?!?!?
html(shell("cat " ~ file ~ "|" ~ dweb_root ~ "bin/contrib/Markdown.pl"));
}
bool fileExists(string path) { try { if (isFile(path)) return true; else return false; } catch (Exception e) { return false; } }
bool dirExists(string path) { try { if (isDir(path)) return true; else return false; } catch (Exception e) { return false; } }
void do_content(string path) {
html_push("<div id=\"main-copy\">");
string url = path[site_root.length..$];
switch (url) {
case "changelog":
html(shell(dweb_root ~ "bin/changelog"));
break;
default:
try {
if (isDir(path) && fileExists(path ~ "index.md")) path ~= "index.md";
if (fileExists(path)) do_markdown(path);
} catch (Exception e) {
not_found(path);
}
}
html_pop("</div>\n");
}
void do_footer() {
html_push("<div id=\"footer\">");
html_push("<div class=\"left\">");
html("<a href=\"" ~ url_root ~ ".dweb\">Powered by dweb</a>");
html_pop("</div>");
html_push("<div class=\"right\">");
html("&nbsp;");
html_pop("</div>");
html_pop("</div>\n");
}
void main(string[] args) {
html("Content-type: text/html\n");
html("<!DOCTYPE html>");
html_push("<html>\n");
string url = getenv("SCRIPT_URL")[url_root.length..$];
string path = site_root ~ url;
string pagename = last_in_path(url);
if (pagename.length != 0) pagename = " - " ~ pagename;
pagename = site_title ~ pagename;
html_push("<head>");
html("<title>" ~ pagename ~ "</title>");
html("<link rel=\"stylesheet\" href=\"" ~ url_root ~ "pub/style/style.css\" type=\"text/css\" media=\"screen, handheld\" title=\"default\">");
html("<link rel=\"shortcut\" href=\"" ~ url_root ~ "pub/favicon.ico\" type=\"image/vnd.microsoft.icon\">");
html("<meta charset=\"UTF-8\">");
html("<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">");
html_pop("</head>\n");
html_push("<body>");
do_header();
do_nav_tree(path);
do_content(path);
do_footer();
html_pop("</body>\n");
html_pop("</html>");
}

53
srv/.dweb Normal file
View File

@ -0,0 +1,53 @@
dweb - A simple website written in D
=====
dweb is a simple website framework based off the [werc][werc] software.
Its principles are:
- Database free, uses files and directories instead.
- Written using the D programming language.
- Minimize tedious work: eg., no need to ever write HTML, use markdown instead.
- Very minimalist yet extensible codebase. Handlers for special things should be easy to add.
It was created because werc was annoying to deploy on UW Computer Science Club's Apache setup and because [Not Invented Here](http://en.wikipedia.org/wiki/Not_Invented_Here).
[werc]:http://werc.cat-v.org/
[md]:http://daringfireball.net/projects/markdown
Install Guide
------
You will need:
- An HTTP server with CGI support.
- The D compiler.
Extract the contents into the location you want to serve webpages from. Edit the following files:
- <code>$DWEB_ROOT/.htaccess</code>: make the paths work for your setup.
- <code>$DWEB_ROOT/src/config.d</code>: change these strings as necessary.
- <code>$DWEB_ROOT/src/web.d</code>: this is the main web code.
- <code>$DWEB_ROOT/pub/</code>: static content goes here.
- <code>$DWEB_ROOT/srv/</code>: directories, markdown webpages etc. go in here.
- <code>$DWEB_ROOT/bin/</code>: custom handlers go here.
Run <code>build</code> in <code>$DWEB_ROOT/src</code> to recompile the website software.
Source
--------
You can get the source code on [github](https://github.com/j3parker/dweb) or by running
git clone git://github.com/j3parker/Go-OpenGL.git
Contact
--------
For questions, suggestions, bug reports and contributing patches email [j3parker](mailto:j3parker@csclub.uwaterloo.ca)
License
-------
Public domain.
Credits
-------
The idea and css stolen from [werc][werc]. This page itself also plagarised.
Thanks to John Gruber for the [Markdown.pl][md] script.