81 Commits
v13 ... v97

Author SHA1 Message Date
138a3c3342 improve update-time detection 2015-11-08 11:49:18 +13:00
fc28e8c5c8 improve newline handling, remove redundant newlines 2015-11-08 11:35:43 +13:00
d67c7fc926 style: use bullets for unordered lists 2015-11-08 11:35:29 +13:00
8a9b36d3db style: multiline code blocks 2015-11-08 11:35:07 +13:00
deea763923 style: mobile css 2015-11-08 11:34:58 +13:00
8f34df0cbd patch halfw width 2015-11-07 18:41:08 +13:00
87f6da2957 fix viewport width value+syntax 2015-11-07 18:38:53 +13:00
766fee12d5 switch background pattern 2015-11-07 18:37:33 +13:00
6488bed03c more github-like CSS theme 2015-11-07 18:33:58 +13:00
ea7092ebef remove redundant html tags 2015-11-07 18:26:46 +13:00
ac79051db4 definitively shunt shields to top 2015-11-07 18:25:48 +13:00
1194223ddd shunt shields (almost) to the top 2015-11-07 18:22:10 +13:00
ad76f6fb7a config flag "shields_prefix" to add a "build:success" shield to everything 2015-11-07 18:20:17 +13:00
f39a05ba59 replace 'written in' with a shields.io SVG 2015-11-07 18:15:01 +13:00
67f20f4379 fix extra space near project titles 2015-11-01 13:50:25 +13:00
2c857250c0 update paths for now using cygwin php 2015-10-11 15:25:36 +13:00
931b6e0208 validate only load directories from /data/ directories 2015-09-06 11:59:08 +12:00
8ea9ca2b2f hgignore drafts for the storytime.ivysaur.me site 2015-09-06 11:56:18 +12:00
9def31abeb track static elements for the storytime.ivysaur.me site 2015-09-06 11:55:57 +12:00
1878d023bf add css class to 'more...' links to allow customising in stylesheet 2015-09-06 11:49:09 +12:00
fef327ec61 replace underscores with spaces in titles 2015-09-06 11:48:54 +12:00
5ddd86e4aa support [b], [i], [spoiler], and [entry] bbcode tags in formatting 2015-09-06 11:48:40 +12:00
87dd96adbd optional 'article_header={string}' directive in site's config.ini file 2015-09-06 11:48:26 +12:00
9de0095c8d optional 'blurbs=off' directive in site's config.ini file 2015-09-06 11:01:13 +12:00
7480da7568 Added tag release-r72 for changeset d4733a95c342 2015-04-05 16:59:38 +12:00
81c65b3cce changelog pre release 2015-04-05 16:59:13 +12:00
441c05f096 if no projects have any images, don't generate spritesheet 2015-04-05 16:51:52 +12:00
671573bc2e sha1 hashes for files, to prevent overwriting srv with same name (e.g. 'screenshot.jpg') 2015-04-05 16:49:17 +12:00
17b0bea213 TODO: switchable CSS 2015-04-05 16:36:31 +12:00
0ad96058d5 TODO: update completed items 2015-04-05 16:36:13 +12:00
092efca34d support redirects 2015-04-05 16:35:54 +12:00
0303019641 only count filemtime, not filectime 2015-04-05 16:29:28 +12:00
8efff11ac2 Added tag release-r64 for changeset 0f89ae041c2e 2015-04-05 16:25:06 +12:00
4a6f8d90d8 tweaks pre release 2015-04-05 16:25:01 +12:00
b572d957fc update changelog 2015-04-05 16:24:23 +12:00
0f70fc7bf0 support sorting 2015-04-05 16:22:46 +12:00
a38b0dbea5 drop dead code 2015-04-05 16:07:50 +12:00
42f4bca8ba drop dead code 2015-04-05 15:50:03 +12:00
2f254fd355 move common static files to /static_global/ 2015-04-05 15:44:32 +12:00
f54c388b1a TODO: update 2015-04-04 19:53:53 +13:00
ee66a10fc3 TODO.txt 2015-04-04 19:47:38 +13:00
d52f58ecae commit version into readme 2015-04-04 19:47:32 +13:00
376745b825 Added tag release-r54 for changeset 42a17645b5b2 2015-04-04 19:45:07 +13:00
1c432afdbf readme: update for r54 2015-04-04 19:44:53 +13:00
df731a8171 readme: track current/original readme file 2015-04-04 19:42:18 +13:00
503bdbd527 mkdist: check in tarballer script 2015-04-04 19:41:09 +13:00
8b153119ea deploy.sh fixes for new file locations 2015-04-04 19:37:12 +13:00
de3e1f1210 hgignore 2015-04-04 19:37:05 +13:00
e693abc079 work on sample site 2015-04-04 19:34:19 +13:00
72bf8d9410 merge example site into main branch 2015-04-04 19:30:20 +13:00
8736cc97b4 move to multisite-model 2015-04-04 19:29:33 +13:00
2eac27a439 rebuild.sh: convert to cygwin 2015-04-04 19:03:14 +13:00
bbbfba2e8f deployscript assert permissions 2015-02-08 16:19:18 +13:00
97c06514eb hgignore dist 2015-02-06 17:11:49 +13:00
4c3e285547 patches for new windows install 2015-02-06 17:11:38 +13:00
40a86b41c7 fix code white-space 2014-08-23 22:22:34 +12:00
301d81a637 fix page overflow 2014-08-23 22:19:02 +12:00
dc260a27d6 fix corrupting urls with multiple params 2014-07-03 22:31:13 +12:00
6801e99164 hgignore 2014-07-03 21:55:41 +12:00
e672d60008 fix previous 2014-06-17 18:21:51 +12:00
a87bfdf687 text2html formatter support raw <html> sections 2014-06-08 20:07:24 +12:00
79c07edb4d reverse sort downloads 2014-05-24 17:55:58 +12:00
542453939e fix clicking tags when already filtered 2014-05-10 15:14:10 +12:00
84d24471b2 fix clearing tag selection on IE 2014-05-10 15:11:27 +12:00
3a8891979a launch in parallel (windows bat doesn't have a good way to wait until complete..) 2014-05-10 14:51:03 +12:00
4d37930689 split up work into multiple processes 2014-05-10 14:47:26 +12:00
1a0251071d tag support 2/2: javascript handling 2014-05-10 14:19:25 +12:00
d440ccc1b3 tag icons 2014-05-10 13:54:10 +12:00
bf7b18fd1f tag support 1/X: parse tags from readme, add classes to html 2014-05-10 11:12:14 +12:00
4c43510c44 fix location of static files following previous 2014-05-10 11:11:53 +12:00
73a5044ef2 move cleaning into bat file 2014-05-10 10:57:03 +12:00
6d8c943976 fix urls for spaces in filenames 2014-01-09 18:20:42 +13:00
32cbbebe97 tweak footer text 2013-11-09 13:46:28 +13:00
85ec3ee5c9 replace favicon 2013-11-09 13:38:23 +13:00
ff6d4f242b always display scrollbar to prevent horizontal lurch 2013-11-09 13:36:34 +13:00
a78cf9f6bb transparent image thumbnails have white background instead of black 2013-11-09 13:36:24 +13:00
80d95d09f9 css: add normalize.css, cosmetic fix header link 2013-11-09 13:36:04 +13:00
7942000d96 separate template header/footer ; new header logo 2013-11-09 13:35:38 +13:00
6d2160aa26 explicit fonts in css 2013-10-21 20:36:08 +13:00
9c9f514752 tweak text2html to fix html generation error. for some reason anchors arn't working in the header? 2013-10-19 22:45:50 +13:00
e732aa8b10 clean destination directory during deploy 2013-10-19 13:33:55 +13:00
42 changed files with 1510 additions and 125 deletions

View File

@@ -1,2 +1,6 @@
wwwroot/* mode:regex
nbproject/* ^_dist/
^sites/[^/]+/data/
^sites/[^/]+/wwwroot/
^shields_cache/

3
.hgtags Normal file
View File

@@ -0,0 +1,3 @@
42a17645b5b21d7fe395767de7fa3e26ee999014 release-r54
0f89ae041c2ee60cc1ea308d047fce816b19c490 release-r64
d4733a95c3428db8722ce0d0350d17bbbabc8720 release-r72

8
TODO.txt Normal file
View File

@@ -0,0 +1,8 @@
- Merge "written in" and "tags"
- RSS for recent changes
- RSS for all projects
- Switchable CSS (reddit theme, 4chan theme, HN theme)

46
_dist/README.txt Normal file
View File

@@ -0,0 +1,46 @@
A static site generator for a portfolio website.
The scripts used to generate the code.ivysaur.me website.
Written in PHP, Bash
=FEATURES=
- Generates static website, minimising server load and decreasing attack surface compared to dynamic server-side PHP
- Automatic thumbnailing and sprite sheet generation
- Download file attachments per-project
- One-click rebuild, one-click deploy
- Parallel generation
=CHANGELOG=
2015-04-05: r72
- Feature: Support redirecting old project names
- Feature: Add file hash in download URLs to prevent filename collisions
- Fix an issue generating spritesheets even if no project images are present
- Don't include `ctime` when estimating project update time
2015-04-05: r64
- Feature: Support sorting projects
2015-04-04: r54
- Feature: Support multiple code sites
- Fix an issue with parallel builds on some versions of windows
- Fix an issue corrupting URL links with multiple parameters
- Fix a cosmetic issue with page overflow
- Fix a cosmetic issue with whitespace on code elements
2014-07-02: r39
- Feature: Tags
- Feature: Generate pages in parallel
- Enhancement: Support raw HTML sections in page content
- Fix an issue with URLs containing spaces
- Fix a cosmetic issue with image thumbnail backgrounds
- Fix a cosmetic issue with download sort order
- Fix a cosmetic issue with page layout
2013-09-28: r13
- Initial public source code release
2013-09-21: r3
- Initial deployment

View File

@@ -1,3 +0,0 @@
@echo off
start C:\path\to\cygwin\bin\mintty.exe /bin/bash -l -c "rsync -avz -e ""ssh -i /cygdrive/c/path/to/deploy_key"" --progress /cygdrive/c/path/to/code/wwwroot www-data@your-web-server:/var/www/path/to/code-site/"

16
deploy.sh Normal file
View File

@@ -0,0 +1,16 @@
#!/bin/bash
set -eu
LOCALDIR=/cygdrive/c/www/m6/code/sites/code.ivysaur.me/wwwroot
chmod -R 644 "$LOCALDIR"
chmod -R a+X "$LOCALDIR"
rsync --delete -avz -e "ssh -i /cygdrive/c/www/ms1_deploy_key -p 2222" --progress \
"$LOCALDIR" \
www-data@ms1.ivysaur.me:~/code.ivysaur.me/
# n.b. set chmod -R a+rX remote side?
read -p "Press any key to continue..."

View File

@@ -1,8 +0,0 @@
<p>
Homepage blurb goes here.
</p>
<p>
<strong>PROJECTS</strong>
</p>

9
mkdist.sh Normal file
View File

@@ -0,0 +1,9 @@
#!/bin/bash
set -eu
tar cJvf "codesite-$(date +%s).tar.xz" \
rebuild.php rebuild.sh sites/codesite.example.com static_global \
--owner=0 --group=0
read -p "Press any key to continue..."

View File

@@ -1,3 +0,0 @@
@echo off
C:\path\to\php_54\php.exe rebuild.php
pause

View File

@@ -3,15 +3,20 @@
// Code-hosting website // Code-hosting website
// ```````````````````` // ````````````````````
// CONFIGURATION function mkshield($left_str, $right_str, $color_str) {
// ````````````` $filename = rawurlencode(str_replace('-', '--', $left_str)).'-'.rawurlencode(str_replace('-', '--', $right_str)).'-'.rawurlencode($color_str).'.svg';
$cache_path = __DIR__.'/../../shields_cache/'.$filename;
define('BASEDIR', __DIR__.'\\'); if (file_exists($cache_path)) {
define('SITE_TITLE', 'codesite'); return file_get_contents($cache_path);
define('PAGE_THUMB_W', 60);
define('PAGE_THUMB_H', 60); } else {
define('INDEX_THUMB_W', 90); $retn = file_get_contents('https://img.shields.io/badge/'.$filename);
define('INDEX_THUMB_H', 32); // recommend a multiple of the jpg iDCT block size file_put_contents($cache_path, $retn);
return $retn;
}
}
/** /**
* Create a thumbnail of an image. It overscales, centers, and crops to fit the * Create a thumbnail of an image. It overscales, centers, and crops to fit the
@@ -29,6 +34,7 @@ function mkthumbnail($src_file, $dest_file, $width, $height) {
$im = imagecreatefromstring(file_get_contents($src_file)); $im = imagecreatefromstring(file_get_contents($src_file));
$dest = imagecreatetruecolor($width, $height); $dest = imagecreatetruecolor($width, $height);
imagefilledrectangle($dest, 0, 0, $width, $height, imagecolorallocate($dest, 0xFF, 0xFF, 0xFF));
$scale = max( $width/$src_width, $height/$src_height ); // overscale + crop $scale = max( $width/$src_width, $height/$src_height ); // overscale + crop
@@ -68,25 +74,6 @@ function mkspritesheet(array $handles, $dest_file, $width, $height) {
} }
} }
/**
* Remove a directory tree and all its contents.
*
* @author http://www.php.net/manual/en/function.rmdir.php#110489
* @param string $dir
* @return boolean
*/
function rmdir_recursive($dir) {
$files = array_diff(scandir($dir), array('.','..'));
foreach ($files as $file) {
if (is_dir("$dir/$file")) {
rmdir_recursive("$dir/$file");
} else {
unlink("$dir/$file");
}
}
return rmdir($dir);
}
function fbytes($size, $suffixes='B|KiB|MiB|GiB|TiB') { function fbytes($size, $suffixes='B|KiB|MiB|GiB|TiB') {
$sxlist = explode('|', $suffixes); $sxlist = explode('|', $suffixes);
if ($size < 1024) { if ($size < 1024) {
@@ -114,20 +101,69 @@ function hesc($sz) {
} }
function text2html($sz) { function text2html($sz) {
$base = hesc($sz);
$base = preg_replace('~(https?://[^ \\r\\n\\t]+)~i', '<a href="\\1">\\1</a>', $base);
$base = preg_replace('~=+(.+)=+~', '<strong>\\1</strong>', $base); $identity = function($sz) {
return $sz;
};
$btparts = explode('`', $base); $splitInside = function($begin, $end, $sz) {
if (count($btparts) > 1 && (count($btparts) % 2)) { $parts = explode($begin, $sz);
for ($i = 1, $e = count($btparts); $i < $e; $i += 2) { if (count($parts) == 1) return [$sz];
$btparts[$i] = '<span class="code">'.$btparts[$i].'</span>';
$ret = [$parts[0]];
for($i = 1, $e = count($parts); $i !== $e; ++$i) {
$inner = explode($end, $parts[$i], 2);
$ret = array_merge($ret, $inner);
} }
$base = implode('', $btparts); return $ret;
} };
return nl2br($base); $oddEven = function(array $parts, $odd, $even, $join='') {
$ret = [];
for($i = 0, $e = count($parts); $i != $e; ++$i) {
$ret[] = ($i % 2) ? $odd($parts[$i]) : $even($parts[$i]);
}
return implode($join, $ret);
};
$sectionFmt = function($sz) use($oddEven, $identity) {
$base = hesc($sz);
$base = preg_replace('~^=+(.+)=+~m', '<strong>\\1</strong>', $base);
$base = preg_replace('~(https?://[^ \\r\\n\\t]+)~i', '<a href="\\1">\\1</a>', $base);
$base = preg_replace('~\\[b\\](.+?)\\[/b\\]~m', '<strong>\\1</strong>', $base);
$base = preg_replace('~\\[i\\](.+?)\\[/i\\]~m', '<i>\\1</i>', $base);
$base = preg_replace('~\\[spoiler\\](.+?)\\[/spoiler\\]~m', '<span class="spoiler">\\1</span>', $base);
$base = preg_replace('~\\[entry=([^\\]]+?)\\](.+?)\\[/entry\\]~m', '<a href="\\1.html">\\2</a>', $base);
$base = preg_replace('~\n- ~ms', "\n&bull; ", $base);
$btparts = explode('`', $base);
if (count($btparts) > 1 && (count($btparts) % 2)) {
for ($i = 1, $e = count($btparts); $i < $e; $i += 2) {
$class = 'code';
if (strpos($btparts[$i], "\n") !== false) {
$class .= ' code-multiline';
}
$btparts[$i] = '<span class="'.$class.'">'.$btparts[$i].'</span>';
}
}
return $oddEven($btparts, $identity, 'nl2br');
};
$htmlSections = $splitInside('<html>', '</html>', $sz);
return $oddEven($htmlSections, $identity, $sectionFmt);
}
function array_decimate($array, $total, $partno) {
$ct = 0;
$ret = [];
foreach($array as $k => $v) {
if (++$ct % $total == ($partno - 1)) {
$ret[$k] = $v;
}
}
return $ret;
} }
/** /**
@@ -139,9 +175,13 @@ class CProject {
public $projname; public $projname;
public $shortdesc = '(no description)'; public $shortdesc = '(no description)';
public $subtag = ''; public $subtag = '';
public $lastupdate = 0;
private $longdesc = ''; private $longdesc = '';
private $prefix_html = '';
private $images = array(); private $images = array();
private $downloads = array(); private $downloads = array();
private $downloads_hashes = array();
public $tags = array();
public $homeimage = null; public $homeimage = null;
@@ -152,27 +192,93 @@ class CProject {
// Identify resources in folder // Identify resources in folder
$ls = scandir($this->dir); $ls = scandir($this->dir);
$found_real_lastupdate = false;
foreach($ls as $file) { foreach($ls as $file) {
if ($file[0] == '.') continue; if ($file[0] == '.') continue;
if ($file == 'README.txt') { if ($file == 'README.txt') {
// Guess 'last update' time
$matches = [];
if (preg_match('~\n(\d\d\d\d-\d\d-\d\d)~', $this->longdesc, $matches)) {
// Use first date entry (assumed to be a CHANGELOG)
$this->lastupdate = strtotime($matches[1]);
$found_real_lastupdate = true;
}
$this->longdesc = file_get_contents($this->dir.'README.txt'); $this->longdesc = file_get_contents($this->dir.'README.txt');
$matches = array(); $matches = array();
if (preg_match('~Written in ([^\\r\\n]+)~', $this->longdesc, $matches)) { if (preg_match('~Written in ([^\\r\\n]+)~', $this->longdesc, $matches)) {
$this->subtag = rtrim($matches[1], ' .'); $this->subtag = rtrim($matches[1], ' .');
} }
$this->shortdesc = array_shift(explode("\n", $this->longdesc)); if (preg_match('~Tags: ([^\\r\\n]+)~', $this->longdesc, $matches)) {
$this->tags = array_map('trim', explode(',', $matches[1]));
}
$parts = explode("\n", $this->longdesc);
$this->shortdesc = array_shift($parts);
$this->shortdesc[0] = strtolower($this->shortdesc[0]); // cosmetic lowercase $this->shortdesc[0] = strtolower($this->shortdesc[0]); // cosmetic lowercase
// Filter longdesc
$this->longdesc = str_replace("\r", "", $this->longdesc); // filter windows CR
$prefix_html = '';
$this->longdesc = preg_replace_callback('~\r?\nWritten in ([^\\n]+)~ms', function($matches) use (&$prefix_html) {
$prefix_html .= (
(SHIELDS_PREFIX ? mkshield('build', 'success', 'brightgreen').'&nbsp;' : '').
mkshield('written in', $matches[1], 'blue')
);
return '';
}, $this->longdesc);
while(strpos($this->longdesc, "\n\n\n") !== false) {
$this->longdesc = str_replace("\n\n\n", "\n\n", $this->longdesc);
}
$this->longdesc = rtrim($this->longdesc, "\n");
$this->prefix_html = $prefix_html;
continue; continue;
} }
if (! $found_real_lastupdate) {
$this->lastupdate = max(
$this->lastupdate,
// filectime($this->dir.$file),
($file == 'README.txt' ? filectime($this->dir.$file) : filemtime($this->dir.$file)) // Don't count README updates
);
}
if (is_image($file)) { if (is_image($file)) {
$this->images[] = $file; $this->images[] = $file;
} else { } else {
$this->downloads[] = $file; $this->downloads[] = $file;
} }
} }
natcasesort($this->downloads);
$this->downloads = array_reverse($this->downloads);
for($i = 0, $e = count($this->downloads); $i !== $e; ++$i) {
$this->downloads_hashes[] = (
sha1_file($this->dir.$this->downloads[$i])
);
}
}
public function genHomeImage() {
if (count($this->images)) {
$this->homeimage = mkthumbnail(
$this->dir.$this->images[0],
null, // raw handle
INDEX_THUMB_W, INDEX_THUMB_H
);
}
} }
public function write() { public function write() {
@@ -186,18 +292,24 @@ class CProject {
mkthumbnail($outfile.'.'.str_ext($image), $outfile.'_thumb.jpg', PAGE_THUMB_W, PAGE_THUMB_H); mkthumbnail($outfile.'.'.str_ext($image), $outfile.'_thumb.jpg', PAGE_THUMB_W, PAGE_THUMB_H);
} }
if (count($this->images)) {
$this->homeimage = mkthumbnail(
BASEDIR.'wwwroot/srv/'.$this->projname.'_0.'.str_ext($this->images[0]),
null, // raw handle
INDEX_THUMB_W, INDEX_THUMB_H
);
}
// Copy downloads to wwwroot // Copy downloads to wwwroot
foreach($this->downloads as $idx => $filename) { foreach($this->downloads as $idx => $filename) {
copy($this->dir.$filename, BASEDIR.'wwwroot/srv/'.$filename); $cmkdir = @mkdir( BASEDIR.'wwwroot/srv/'.$this->downloads_hashes[$idx] );
if (! $cmkdir) {
fputs(
STDOUT,
"WARNING: Couldn't create directory ".$this->downloads_hashes[$idx].
" for file '${filename}'".
" in project '".$this->projname."'!\n"
);
}
copy(
$this->dir.$filename,
BASEDIR.'wwwroot/srv/'.$this->downloads_hashes[$idx].'/'.$filename
);
} }
// Generate index page // Generate index page
@@ -208,28 +320,42 @@ class CProject {
file_put_contents(BASEDIR.'wwwroot/'.$this->projname.'.html', $idxfile); file_put_contents(BASEDIR.'wwwroot/'.$this->projname.'.html', $idxfile);
} }
public function getClassAttr() {
if (count($this->tags)) {
return 'taggedWith-'.implode(' taggedWith-', $this->tags);
} else {
return '';
}
}
public function index() { public function index() {
?> ?>
<h2><?=hesc($this->projname)?></h2> <h2><?=hesc(str_replace('_', ' ', $this->projname))?></h2>
<div class="projinfo"> <div class="projinfo">
<div class="projbody projbody_<?=(count($this->images) ? 'half' : 'full')?>w"> <div class="projbody projbody_<?=(count($this->images) ? 'half' : 'full')?>w">
<strong>ABOUT</strong> <?php if (strlen($this->prefix_html)) { ?>
<p style="margin-top:0;"><?=$this->prefix_html?></p>
<?php } ?>
<strong><?=hesc(strtoupper(ARTICLE_HEADER))?></strong>
<p><?=text2html($this->longdesc)?></p> <p><?=text2html($this->longdesc)?></p>
<?=file_get_contents(BASEDIR.'/footer.htm')?>
<?php if (count($this->downloads)) { ?> <?php if (count($this->downloads)) { ?>
<strong>DOWNLOAD</strong> <strong>DOWNLOAD</strong>
<ul> <ul>
<?php foreach($this->downloads as $filename) { ?> <?php foreach($this->downloads as $idx => $filename) { ?>
<li> <li>
<a href="srv/<?=hesc(urlencode($filename))?>"><?=hesc($filename)?></a> <a href="srv/<?=hesc($this->downloads_hashes[$idx])?>/<?=hesc(rawurlencode($filename))?>"><?=hesc($filename)?></a>
<small> <small>
<?=hesc(fbytes(filesize(BASEDIR.'wwwroot/srv/'.$filename)))?> <?=hesc(fbytes(filesize(BASEDIR.'wwwroot/srv/'.$this->downloads_hashes[$idx].'/'.$filename)))?>
</small> </small>
</li> </li>
<?php } ?> <?php } ?>
@@ -243,6 +369,9 @@ class CProject {
<a href="srv/<?=hesc(urlencode($this->projname))?>_<?=$idx?>.<?=str_ext($origname)?>"><img src="srv/<?=hesc(urlencode($this->projname))?>_<?=$idx?>_thumb.jpg" class="thumbimage"></a> <a href="srv/<?=hesc(urlencode($this->projname))?>_<?=$idx?>.<?=str_ext($origname)?>"><img src="srv/<?=hesc(urlencode($this->projname))?>_<?=$idx?>_thumb.jpg" class="thumbimage"></a>
<?php } ?> <?php } ?>
</div> </div>
<div style="clear:both;"></div>
<?php } ?> <?php } ?>
</div> </div>
@@ -260,14 +389,16 @@ function template($title, $content) {
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" > <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" >
<meta name="viewport" content="width=768px" > <meta name="viewport" content="width=960" >
<link type="text/css" rel="stylesheet" href="normalize.css">
<link type="text/css" rel="stylesheet" href="style.css"> <link type="text/css" rel="stylesheet" href="style.css">
<script type="text/javascript" src="site.js"></script>
<title><?=hesc($title)?></title> <title><?=hesc($title)?></title>
</head> </head>
<body> <body>
<div id="container"> <div id="container">
<div id="content"> <div id="content">
<a href="index.html"><div id="bannerlogo"></div></a> <?=file_get_contents(BASEDIR.'/header.htm')?>
<?=$content?> <?=$content?>
</div> </div>
</div> </div>
@@ -277,26 +408,7 @@ function template($title, $content) {
return ob_get_clean(); return ob_get_clean();
} }
function buildall() { function listprojects() {
// Clean up webroot
if (file_exists(BASEDIR.'wwwroot')) {
rmdir_recursive(BASEDIR.'wwwroot');
}
echo "Creating directories...\n";
mkdir(BASEDIR.'wwwroot');
mkdir(BASEDIR.'wwwroot/srv');
// Copy in static files
foreach(scandir(BASEDIR.'static') as $static) {
if ($static[0] == '.' || is_dir($static) /* fixme */) continue;
copy(BASEDIR.'static/'.$static, BASEDIR.'wwwroot/'.$static);
}
// List projects // List projects
$ls = scandir(BASEDIR.'data'); $ls = scandir(BASEDIR.'data');
@@ -304,6 +416,7 @@ function buildall() {
$projects = array(); $projects = array();
foreach($ls as $dirname) { foreach($ls as $dirname) {
if ($dirname[0] == '.') continue; if ($dirname[0] == '.') continue;
if (! is_dir(BASEDIR.'data/'.$dirname)) continue;
$matches = array(); $matches = array();
if (preg_match('~(?:\d+-)?(.+)~', $dirname, $matches)) { if (preg_match('~(?:\d+-)?(.+)~', $dirname, $matches)) {
@@ -311,20 +424,41 @@ function buildall() {
} }
} }
return $projects;
}
function buildprojects($id, $projects) {
$count = 0;
foreach($projects as $dirname => $projectname) {
echo sprintf("@%1d [%3d/%3d] ".$projectname."...\n", $id, ++$count, count($projects));
$pr = new CProject($dirname, $projectname);
$pr->write();
}
}
function buildcommon() {
echo "@0 [ 0/ ?] Common files...\n";
$projects = listprojects();
// Build all projects // Build all projects
$plist = array(); $plist = array();
$count = 0;
$handles = array(); $handles = array();
$handle_lookup = array(); $handle_lookup = array();
$alphasort = [];
foreach($projects as $dirname => $projectname) { foreach($projects as $dirname => $projectname) {
echo sprintf("[%3d/%3d] ".$projectname."...", ++$count, count($projects));
$pr = new CProject($dirname, $projectname); $pr = new CProject($dirname, $projectname);
$pr->write(); $pr->genHomeImage(); // thumbnail
$plist[] = $pr; $plist[] = $pr;
if (is_null($pr->homeimage)) { if (is_null($pr->homeimage)) {
@@ -334,13 +468,25 @@ function buildall() {
$handles[] = $pr->homeimage; $handles[] = $pr->homeimage;
} }
echo " done\n"; $alphasort[] = [$pr->projname, count($plist)-1];
}
usort($alphasort, function($a, $b) {
return strcasecmp($a[0], $b[0]);
});
$alphaidx = [];
foreach($alphasort as $a) {
$alphaidx[ $a[1] ] = count($alphaidx);
} }
// Build homepage spritesheet // Build homepage spritesheet
mkspritesheet($handles, BASEDIR.'wwwroot/logos.jpg', INDEX_THUMB_W, INDEX_THUMB_H); if (count($handles)) {
array_map('imagedestroy', $handles); // free mkspritesheet($handles, BASEDIR.'wwwroot/logos.jpg', INDEX_THUMB_W, INDEX_THUMB_H);
array_map('imagedestroy', $handles); // free
}
// Build index page // Build index page
@@ -353,19 +499,32 @@ function buildall() {
<!-- }} --> <!-- }} -->
<?php } ?> <?php } ?>
<table class="projtable"> <table id="projtable-main" class="projtable">
<?php foreach ($plist as $pr) { ?> <?php foreach ($plist as $i => $pr) { ?>
<tr> <tr class="<?=$pr->getClassAttr()?>"
data-sort-mt="-<?=$pr->lastupdate?>"
data-sort-ct="<?=$i?>"
data-sort-al="<?=$alphaidx[$i]?>"
>
<td> <td>
<a href="<?=hesc(urlencode($pr->projname))?>.html"><?=(is_null($handle_lookup[$pr->projname]) ? '<div class="no-image"></div>' : '<div class="homeimage homeimage-sprite" style="background-position:0 -'.($handle_lookup[$pr->projname]*INDEX_THUMB_H).'px"></div>')?></a> <a href="<?=hesc(urlencode($pr->projname))?>.html"><?=(is_null($handle_lookup[$pr->projname]) ? '<div class="no-image"></div>' : '<div class="homeimage homeimage-sprite" style="background-position:0 -'.($handle_lookup[$pr->projname]*INDEX_THUMB_H).'px"></div>')?></a>
</td> </td>
<td> <td>
<strong><?=hesc($pr->projname)?></strong>, <strong><?=hesc(str_replace('_', ' ', $pr->projname))?></strong><?php if (SHOW_BLURBS) { ?>,
<?=hesc($pr->shortdesc)?> <?=hesc($pr->shortdesc)?>
<a href="<?=hesc(urlencode($pr->projname))?>.html">more...</a> <?php } ?>
<?php if (strlen($pr->subtag)) { ?> <a href="<?=hesc(urlencode($pr->projname))?>.html" class="article-read-more">more...</a>
<?php if (strlen($pr->subtag) || count($pr->tags)) { ?>
<br> <br>
<small><?=hesc($pr->subtag)?></small> <small>
<?=hesc($pr->subtag)?>
<?php if (strlen($pr->subtag) && count($pr->tags)) { ?>
::
<?php } ?>
<?php foreach($pr->tags as $tag) { ?>
<a class="tag tag-link" data-tag="<?=hesc($tag)?>"><?=hesc($tag)?></a>
<?php } ?>
</small>
<?php } ?> <?php } ?>
</td> </td>
</tr> </tr>
@@ -376,8 +535,65 @@ function buildall() {
$index = template(SITE_TITLE, ob_get_clean()); $index = template(SITE_TITLE, ob_get_clean());
file_put_contents(BASEDIR.'wwwroot/index.html', $index); file_put_contents(BASEDIR.'wwwroot/index.html', $index);
echo "All processes complete.\n"; // Done
} }
buildall(); function buildredirects($redirects) {
foreach($redirects as $oldname => $newname) {
ob_start();
?>
<meta http-equiv="refresh" content="0; url=<?=hesc($newname)?>.html">
<a href="<?=hesc($newname)?>.html">Moved &raquo;</a>
<?php
$page = ob_get_clean();
file_put_contents(BASEDIR.'wwwroot/'.$oldname.'.html', $page);
}
}
function main($args) {
$basedir = './';
$total = $args[0];
$pos = $args[1];
// Parse configuration
$config = @parse_ini_file(
$basedir . 'config.ini',
true,
INI_SCANNER_RAW
);
if ($config === false) {
die("[FATAL] Couldn't load '${basedir}/config.ini'!\n");
}
define('BASEDIR', $basedir);
define('SITE_TITLE', trim($config['codesite']['title']));
define('PAGE_THUMB_W', intval($config['codesite']['page_thumb_w']));
define('PAGE_THUMB_H', intval($config['codesite']['page_thumb_h']));
define('INDEX_THUMB_W', intval($config['codesite']['index_thumb_w']));
define('INDEX_THUMB_H', intval($config['codesite']['index_thumb_h']));
define('SHOW_BLURBS', !(isset($config['codesite']['blurbs']) && $config['codesite']['blurbs'] === 'off') );
define('ARTICLE_HEADER', (isset($config['codesite']['article_header']) ? $config['codesite']['article_header'] : 'ABOUT') );
define('SHIELDS_PREFIX', isset($config['codesite']['shields_prefix']));
// Perform build tasks
if ($pos == 0) {
buildcommon();
if (array_key_exists('redirect', $config)) {
buildredirects( $config['redirect'] );
}
} else {
buildprojects($pos, array_decimate(listprojects(), $total, $pos));
}
}
// Entry point
//
ini_set('display_errors', 'On');
date_default_timezone_set('Etc/UTC');
error_reporting(E_ALL);
main(array_slice($_SERVER['argv'], 1));

60
rebuild.sh Normal file
View File

@@ -0,0 +1,60 @@
#!/bin/bash
set -eu
THREADS=4
buildsite() {
local basedir="$(realpath .)"
local rebuild="${basedir}/rebuild.php"
if [[ "$(uname -o)" == "Cygwin" ]] ; then
rebuild="$(cygpath -w "$rebuild")"
fi
echo "Site: ${1}"
pushd "$1" >/dev/null
echo "Cleaning target directory..."
if [[ -d wwwroot ]] ; then
rm -r wwwroot
fi
mkdir -p wwwroot/srv
if [[ ! -d static ]] ; then
mkdir static
fi
cp "${basedir}/static_global/"* wwwroot || true
cp static/* wwwroot || true
for htm in footer header homepage_blurb ; do
if [[ ! -f "${htm}.htm" ]] ; then
touch "${htm}.htm"
fi
done
echo "Building pages..."
for i in $(seq 0 "$THREADS") ; do
php "$rebuild" "$THREADS" "$i" &
done
wait
echo "Site: ${1} finished."
echo ""
popd >/dev/null
}
main() {
for site in sites/* ; do
buildsite "$site"
done
}
main "$@"
read -p "Press any key to continue..."

View File

@@ -0,0 +1,14 @@
[codesite]
title=code.ivysaur.me
page_thumb_w=60
page_thumb_h=60
index_thumb_w=90
index_thumb_h=32
shields_prefix=true
; n.b. Recommend a multiple of the JPEG iDCT block size for index_thumb_h
[redirect]
; old project name = new project name
code.ivysaur.me=codesite

View File

@@ -0,0 +1,11 @@
<p>
<strong>CONTACT</strong>
</p>
<p>
For bug reports, feature requests, or if you need any help, please
<a
href="http://www.google.com/recaptcha/mailhide/d?k=01GuAWzMc9JjSdooo-2KCMQA==&amp;c=kgR3dBrP39yhPIy8FvLFbuBLmWqorQBDc_Zjbw6NAmU="
onclick="window.open('http://www.google.com/recaptcha/mailhide/d?k\07501GuAWzMc9JjSdooo-2KCMQA\75\75\46c\75kgR3dBrP39yhPIy8FvLFbuBLmWqorQBDc_Zjbw6NAmU\075', '', 'toolbar=0,scrollbars=0,location=0,statusbar=0,menubar=0,resizable=0,width=500,height=300'); return false;"
title="Reveal this e-mail address"
>click here</a> to email me.
</p>

View File

@@ -0,0 +1 @@
<h1><a href="index.html"><div id="ivylogo"></div>code.ivysaur.me</a></h1>

View File

@@ -0,0 +1,26 @@
<p>
It's said that if you're not disgusted by code you wrote six months ago, you've stopped learning.
</p>
<p>
<strong>OVERVIEW</strong>
</p>
<p>
This page contains several assorted spare-time projects, which no longer have any relation. They are listed in roughly chronological order (newest first). <strong>Unless specified otherwise</strong>, you may feel free to use and modify both the binaries and any source code, for any purpose, on the general condition you do not misrepresent who the author is (BSD license).
</p>
<p>
Some of these projects formerly appeared on Google Code <a href="https://code.google.com/p/mappy/">here</a>, but were moved following the discontinuation of the Google Code binary download system.
</p>
<p>
<select id="sortorder" style="float:right;">
<option value="a">Youngest project first</option>
<option value="b">Recent updates first</option>
<option value="c">Alphabetical</option>
</select>
<strong>PROJECTS</strong>
</p>

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@@ -0,0 +1,198 @@
/* style.css */
html {
overflow-y:scroll; /* always display scrollbar to prevent horizontal lurch */
}
img {
border:0;
}
a {
color:#4078c0;
text-decoration:none;
}
a:hover {
cursor:pointer;
text-decoration:underline;
}
h1 a {
color:black;
text-decoration:none;
}
h1 a:hover {
color:black;
}
h1,h2,h3 {
margin-top:0;
}
.code {
background: #F8F8F8;
font-family:Consolas,monospace;
white-space:pre;
}
.code-multiline {
display:inline-block;
padding:8px;
border-radius:8px;
}
/* */
html, body {
/* structural */
height:100%;
min-height:100%;
margin:0;
border:0;
padding:0;
/* cosmetic */
font-family:"Helvetica Neue","Segoe UI",Arial,sans-serif;
font-size:13px;
line-height:1.4;
background:#DDD url('greyzz.png'); /* thanks subtlepatterns.com ! */
color:#333;
}
#container {
margin:0 auto;
width:960px;
position:relative;
height:auto !important;
height:100%; /* oldIE */
min-height:100%;
/* cosmetic */
background:white;
}
#content {
padding:14px;
background:white;
}
/* */
.tag::before {
content:"";
display:inline-block;
width:7px;
height:7px;
margin-right:2px;
background:transparent url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAcAAAAHCAYAAADEUlfTAAAAZUlEQVQI12P4//8/Awyrqqp6KSkp/QdhFRWV7cgS+kDBN0B8RVlZuRikACahB+T8ger6BMTXwJJAiTwg4xvMOCj+ART3ZwCa3YYm8QcopgsyEWasDVT3W5AVMHcgO6gViNORXQ8A84NToxbSsJcAAAAASUVORK5CYII=') no-repeat 0 0;
}
.tag-filter-warn {
position:fixed;
top:0;
right:0;
padding:4px;
background:lightyellow;
border-bottom: 1px solid #888;
border-left:1px solid #888;
}
/* */
.projtable {
border-collapse: collapse;
width:100%;
}
.projtable tr {
transition:0.2s linear;
}
.projtable tr:hover {
background:#F8F8F8;
}
.projtable td {
padding: 2px 4px;
}
.projtable small {
color:grey;
font-style:italic;
}
.projtable tr td:first-child {
width:95px;
}
.projinfo {
}
.projbody {
}
.projbody_halfw {
float:left;
width: 860px; /* 740px full - 60px rhs column - 2px border */
}
.projbody_fullw {
}
.projimg {
float:right;
width:62px; /* 60px + 2px border */
}
/* */
@media screen and (max-width:960px) {
#container {
width:100%;
}
.projimg {
float:clear;
width:100%;
}
.projbody_halfw {
float:clear;
width:100%;
}
}
/* */
#ivylogo {
background:transparent url('ivysaur24.png') no-repeat 0 0;
width:24px;
height:24px;
display:inline-block;
*display:block;
*zoom:1;
margin-right:4px;
position:relative;
top:4px;
}
/* */
.homeimage {
width:90px;
height:32px;
}
.homeimage-sprite {
background: white url('logos.jpg') no-repeat 0 0;
}
.thumbimage {
width:60px;
height:60px;
opacity: 0.8;
transition:0.2s opacity;
border:1px solid lightgrey;
}
.thumbimage:hover {
opacity:1.0;
}
.no-image {
width:90px;
height:32px;
display:block;
background: white url('no_image.png') no-repeat 0 0;
}

View File

@@ -0,0 +1,13 @@
[codesite]
title=codesite.example.com
page_thumb_w=60
page_thumb_h=60
index_thumb_w=90
index_thumb_h=32
; n.b. Recommend a multiple of the JPEG iDCT block size for index_thumb_h
[redirect]
; old project name = new project name
old-project-name=example-project

View File

@@ -0,0 +1,6 @@
<p>
<strong>FOOTER</strong>
</p>
<p>
Content here.
</p>

View File

@@ -0,0 +1 @@
<h1>HEADER</h1>

View File

@@ -0,0 +1,14 @@
<p>
Homepage blurb goes here.
</p>
<p>
<select id="sortorder" style="float:right;">
<option value="a">Youngest project first</option>
<option value="b">Recent updates first</option>
<option value="c">Alphabetical</option>
</select>
<strong>PROJECTS</strong>
</p>

View File

Before

Width:  |  Height:  |  Size: 233 B

After

Width:  |  Height:  |  Size: 233 B

View File

Before

Width:  |  Height:  |  Size: 264 B

After

Width:  |  Height:  |  Size: 264 B

View File

@@ -1,13 +1,24 @@
/* style.css */ /* style.css */
html {
overflow-y:scroll; /* always display scrollbar to prevent horizontal lurch */
}
img { img {
border:0; border:0;
} }
a { a {
color:black; color:black;
text-decoration:underline;
} }
a:hover { a:hover {
color:blue; color:blue;
cursor:pointer;
}
h1 a {
text-decoration:none;
}
h1 a:hover {
color:black;
} }
h1,h2,h3 { h1,h2,h3 {
margin-top:0; margin-top:0;
@@ -27,6 +38,8 @@ html, body {
padding:0; padding:0;
/* cosmetic */ /* cosmetic */
font-family:"Helvetica Neue","Segoe UI",Arial,sans-serif;
font-size:12px;
background:#DDD url('pixel_weave.png'); /* thanks subtlepatterns.com ! */ background:#DDD url('pixel_weave.png'); /* thanks subtlepatterns.com ! */
color:#333; color:#333;
} }
@@ -51,6 +64,32 @@ html, body {
/* */ /* */
.tag::before {
content:"";
display:inline-block;
width:7px;
height:7px;
margin-right:2px;
background:transparent url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAcAAAAHCAYAAADEUlfTAAAAZUlEQVQI12P4//8/Awyrqqp6KSkp/QdhFRWV7cgS+kDBN0B8RVlZuRikACahB+T8ger6BMTXwJJAiTwg4xvMOCj+ART3ZwCa3YYm8QcopgsyEWasDVT3W5AVMHcgO6gViNORXQ8A84NToxbSsJcAAAAASUVORK5CYII=') no-repeat 0 0;
}
.tag-filter-warn {
position:fixed;
top:0;
right:0;
padding:4px;
background:lightyellow;
border-bottom: 1px solid #888;
border-left:1px solid #888;
}
/* */
.projtable { .projtable {
border-collapse: collapse; border-collapse: collapse;
width:100%; width:100%;
@@ -68,6 +107,9 @@ html, body {
color:grey; color:grey;
font-style:italic; font-style:italic;
} }
.projtable tr td:first-child {
width:95px;
}
.projinfo { .projinfo {
position:relative; position:relative;
@@ -91,19 +133,6 @@ html, body {
/* */ /* */
#bannerlogo {
width:631px;
height:35px;
margin:0 auto;
background: white url('header.png') no-repeat 0 0;
padding:8px;
}
.headimg {
width:310px;
height:62px;
}
.homeimage { .homeimage {
width:90px; width:90px;
height:32px; height:32px;

View File

@@ -0,0 +1,11 @@
[codesite]
title=storytime.ivysaur.me
page_thumb_w=60
page_thumb_h=60
index_thumb_w=90
index_thumb_h=32
blurbs=off
article_header=ARTICLE
; n.b. Recommend a multiple of the JPEG iDCT block size for index_thumb_h

View File

@@ -0,0 +1,10 @@
<p>
<strong>CONTACT</strong>
</p>
<p>
<a
href="http://www.google.com/recaptcha/mailhide/d?k=01GuAWzMc9JjSdooo-2KCMQA==&amp;c=kgR3dBrP39yhPIy8FvLFbuBLmWqorQBDc_Zjbw6NAmU="
onclick="window.open('http://www.google.com/recaptcha/mailhide/d?k\07501GuAWzMc9JjSdooo-2KCMQA\75\75\46c\75kgR3dBrP39yhPIy8FvLFbuBLmWqorQBDc_Zjbw6NAmU\075', '', 'toolbar=0,scrollbars=0,location=0,statusbar=0,menubar=0,resizable=0,width=500,height=300'); return false;"
title="Reveal this e-mail address"
>Click here</a> to email me.
</p>

View File

@@ -0,0 +1 @@
<h1><a href="index.html"><div id="ivylogo"></div>storytime.ivysaur.me</a></h1>

View File

@@ -0,0 +1,12 @@
<p>
The stories and information posted here are artistic works of fiction and falsehood. Only a fool would take anything posted here as fact.
</p>
<p>
<strong>LICENSE</strong>
</p>
<p>
Please consider all articles on this page to be under the <a rel="license" href="http://creativecommons.org/licenses/by-sa/4.0/">CC-BY-SA 4.0 International license</a> unless otherwise specified.
</p>
<p>
<strong>ARTICLES</strong>
</p>

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 416 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 233 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 264 B

View File

@@ -0,0 +1,187 @@
/* style.css */
html {
overflow-y:scroll; /* always display scrollbar to prevent horizontal lurch */
}
img {
border:0;
}
a {
color:black;
text-decoration:underline;
}
a:hover {
color:blue;
cursor:pointer;
}
h1 a {
text-decoration:none;
}
h1 a:hover {
color:black;
}
h1,h2,h3 {
margin-top:0;
}
.code {
background: #F8F8F8;
font-family:Consolas,monospace;
white-space:pre;
}
/* */
html, body {
/* structural */
height:100%;
min-height:100%;
margin:0;
border:0;
padding:0;
/* cosmetic */
font-family:"Helvetica Neue","Segoe UI",Arial,sans-serif;
font-size:12px;
background:#DDD url('pixel_weave.png'); /* thanks subtlepatterns.com ! */
color:#333;
}
#container {
margin:0 auto;
width:768px;
position:relative;
height:auto !important;
height:100%; /* oldIE */
min-height:100%;
/* cosmetic */
background:white;
}
#content {
padding:14px;
background:white;
}
/* */
.tag::before {
content:"";
display:inline-block;
width:7px;
height:7px;
margin-right:2px;
background:transparent url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAcAAAAHCAYAAADEUlfTAAAAZUlEQVQI12P4//8/Awyrqqp6KSkp/QdhFRWV7cgS+kDBN0B8RVlZuRikACahB+T8ger6BMTXwJJAiTwg4xvMOCj+ART3ZwCa3YYm8QcopgsyEWasDVT3W5AVMHcgO6gViNORXQ8A84NToxbSsJcAAAAASUVORK5CYII=') no-repeat 0 0;
}
.tag-filter-warn {
position:fixed;
top:0;
right:0;
padding:4px;
background:lightyellow;
border-bottom: 1px solid #888;
border-left:1px solid #888;
}
/* */
.projtable {
border-collapse: collapse;
width:100%;
}
.projtable tr {
transition:0.2s linear;
}
.projtable tr:hover {
background:#F8F8F8;
}
.projtable td {
padding: 2px 4px;
}
.projtable small {
color:grey;
font-style:italic;
}
.projtable tr td:first-child {
width:95px;
}
.projinfo {
}
.projbody {
}
.projbody_halfw {
float:left;
width: 678px; /* 740px full - 60px rhs column - 2px border */
}
.projbody_fullw {
}
.projimg {
float:right;
width:62px; /* 60px + 2px border */
}
/* */
#ivylogo {
background:transparent url('ivysaur24.png') no-repeat 0 0;
width:24px;
height:24px;
display:inline-block;
*display:block;
*zoom:1;
margin-right:4px;
position:relative;
top:4px;
}
/* */
.homeimage {
width:90px;
height:32px;
}
.homeimage-sprite {
background: white url('logos.jpg') no-repeat 0 0;
}
.thumbimage {
width:60px;
height:60px;
opacity: 0.8;
transition:0.2s opacity;
border:1px solid lightgrey;
}
.thumbimage:hover {
opacity:1.0;
}
.no-image {
width:90px;
height:32px;
display:block;
background: white url('no_image.png') no-repeat 0 0;
}
/* */
.spoiler {
color:black;
background:black;
}
.spoiler:hover {
color:white;
}
.article-read-more {
display:none;
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

View File

Before

Width:  |  Height:  |  Size: 436 B

After

Width:  |  Height:  |  Size: 436 B

406
static_global/normalize.css vendored Normal file
View File

@@ -0,0 +1,406 @@
/*! normalize.css v2.1.3 | MIT License | git.io/normalize */
/* ==========================================================================
HTML5 display definitions
========================================================================== */
/**
* Correct `block` display not defined in IE 8/9.
*/
article,
aside,
details,
figcaption,
figure,
footer,
header,
hgroup,
main,
nav,
section,
summary {
display: block;
}
/**
* Correct `inline-block` display not defined in IE 8/9.
*/
audio,
canvas,
video {
display: inline-block;
}
/**
* Prevent modern browsers from displaying `audio` without controls.
* Remove excess height in iOS 5 devices.
*/
audio:not([controls]) {
display: none;
height: 0;
}
/**
* Address `[hidden]` styling not present in IE 8/9.
* Hide the `template` element in IE, Safari, and Firefox < 22.
*/
[hidden],
template {
display: none;
}
/* ==========================================================================
Base
========================================================================== */
/**
* 1. Set default font family to sans-serif.
* 2. Prevent iOS text size adjust after orientation change, without disabling
* user zoom.
*/
html {
font-family: sans-serif; /* 1 */
-ms-text-size-adjust: 100%; /* 2 */
-webkit-text-size-adjust: 100%; /* 2 */
}
/**
* Remove default margin.
*/
body {
margin: 0;
}
/* ==========================================================================
Links
========================================================================== */
/**
* Remove the gray background color from active links in IE 10.
*/
a {
background: transparent;
}
/**
* Address `outline` inconsistency between Chrome and other browsers.
*/
a:focus {
outline: thin dotted;
}
/**
* Improve readability when focused and also mouse hovered in all browsers.
*/
a:active,
a:hover {
outline: 0;
}
/* ==========================================================================
Typography
========================================================================== */
/**
* Address variable `h1` font-size and margin within `section` and `article`
* contexts in Firefox 4+, Safari 5, and Chrome.
*/
h1 {
font-size: 2em;
margin: 0.67em 0;
}
/**
* Address styling not present in IE 8/9, Safari 5, and Chrome.
*/
abbr[title] {
border-bottom: 1px dotted;
}
/**
* Address style set to `bolder` in Firefox 4+, Safari 5, and Chrome.
*/
b,
strong {
font-weight: bold;
}
/**
* Address styling not present in Safari 5 and Chrome.
*/
dfn {
font-style: italic;
}
/**
* Address differences between Firefox and other browsers.
*/
hr {
-moz-box-sizing: content-box;
box-sizing: content-box;
height: 0;
}
/**
* Address styling not present in IE 8/9.
*/
mark {
background: #ff0;
color: #000;
}
/**
* Correct font family set oddly in Safari 5 and Chrome.
*/
code,
kbd,
pre,
samp {
font-family: monospace, serif;
font-size: 1em;
}
/**
* Improve readability of pre-formatted text in all browsers.
*/
pre {
white-space: pre-wrap;
}
/**
* Set consistent quote types.
*/
q {
quotes: "\201C" "\201D" "\2018" "\2019";
}
/**
* Address inconsistent and variable font size in all browsers.
*/
small {
font-size: 80%;
}
/**
* Prevent `sub` and `sup` affecting `line-height` in all browsers.
*/
sub,
sup {
font-size: 75%;
line-height: 0;
position: relative;
vertical-align: baseline;
}
sup {
top: -0.5em;
}
sub {
bottom: -0.25em;
}
/* ==========================================================================
Embedded content
========================================================================== */
/**
* Remove border when inside `a` element in IE 8/9.
*/
img {
border: 0;
}
/**
* Correct overflow displayed oddly in IE 9.
*/
svg:not(:root) {
overflow: hidden;
}
/* ==========================================================================
Figures
========================================================================== */
/**
* Address margin not present in IE 8/9 and Safari 5.
*/
figure {
margin: 0;
}
/* ==========================================================================
Forms
========================================================================== */
/**
* Define consistent border, margin, and padding.
*/
fieldset {
border: 1px solid #c0c0c0;
margin: 0 2px;
padding: 0.35em 0.625em 0.75em;
}
/**
* 1. Correct `color` not being inherited in IE 8/9.
* 2. Remove padding so people aren't caught out if they zero out fieldsets.
*/
legend {
border: 0; /* 1 */
padding: 0; /* 2 */
}
/**
* 1. Correct font family not being inherited in all browsers.
* 2. Correct font size not being inherited in all browsers.
* 3. Address margins set differently in Firefox 4+, Safari 5, and Chrome.
*/
button,
input,
select,
textarea {
font-family: inherit; /* 1 */
font-size: 100%; /* 2 */
margin: 0; /* 3 */
}
/**
* Address Firefox 4+ setting `line-height` on `input` using `!important` in
* the UA stylesheet.
*/
button,
input {
line-height: normal;
}
/**
* Address inconsistent `text-transform` inheritance for `button` and `select`.
* All other form control elements do not inherit `text-transform` values.
* Correct `button` style inheritance in Chrome, Safari 5+, and IE 8+.
* Correct `select` style inheritance in Firefox 4+ and Opera.
*/
button,
select {
text-transform: none;
}
/**
* 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio`
* and `video` controls.
* 2. Correct inability to style clickable `input` types in iOS.
* 3. Improve usability and consistency of cursor style between image-type
* `input` and others.
*/
button,
html input[type="button"], /* 1 */
input[type="reset"],
input[type="submit"] {
-webkit-appearance: button; /* 2 */
cursor: pointer; /* 3 */
}
/**
* Re-set default cursor for disabled elements.
*/
button[disabled],
html input[disabled] {
cursor: default;
}
/**
* 1. Address box sizing set to `content-box` in IE 8/9/10.
* 2. Remove excess padding in IE 8/9/10.
*/
input[type="checkbox"],
input[type="radio"] {
box-sizing: border-box; /* 1 */
padding: 0; /* 2 */
}
/**
* 1. Address `appearance` set to `searchfield` in Safari 5 and Chrome.
* 2. Address `box-sizing` set to `border-box` in Safari 5 and Chrome
* (include `-moz` to future-proof).
*/
input[type="search"] {
-webkit-appearance: textfield; /* 1 */
-moz-box-sizing: content-box;
-webkit-box-sizing: content-box; /* 2 */
box-sizing: content-box;
}
/**
* Remove inner padding and search cancel button in Safari 5 and Chrome
* on OS X.
*/
input[type="search"]::-webkit-search-cancel-button,
input[type="search"]::-webkit-search-decoration {
-webkit-appearance: none;
}
/**
* Remove inner padding and border in Firefox 4+.
*/
button::-moz-focus-inner,
input::-moz-focus-inner {
border: 0;
padding: 0;
}
/**
* 1. Remove default vertical scrollbar in IE 8/9.
* 2. Improve readability and alignment in all browsers.
*/
textarea {
overflow: auto; /* 1 */
vertical-align: top; /* 2 */
}
/* ==========================================================================
Tables
========================================================================== */
/**
* Remove most spacing between table cells.
*/
table {
border-collapse: collapse;
border-spacing: 0;
}

97
static_global/site.js Normal file
View File

@@ -0,0 +1,97 @@
(function() {
"use strict";
var show_all = function() {
var tr = document.querySelectorAll(".projtable tr");
for (var i = 0, e = tr.length; i !== e; ++i) {
tr[i].style.display = "table-row";
}
var warn = document.querySelector(".tag-filter-warn");
warn.parentNode.removeChild(warn);
};
var show_tag = function(tag) {
if (document.querySelector(".tag-filter-warn") !== null) {
show_all();
}
var tr = document.querySelectorAll(".projtable tr");
for (var i = 0, e = tr.length; i !== e; ++i) {
tr[i].style.display = (tr[i].className.split(" ").indexOf("taggedWith-"+tag) === -1) ? "none" : "table-row";
}
var div = document.createElement("div");
div.className = "tag-filter-warn";
div.innerHTML = "Filtering by tag. <a>reset</a>";
document.body.appendChild(div);
document.querySelector(".tag-filter-warn a").addEventListener('click', function() {
show_all();
return false;
});
};
var get_show_tag = function(tag) {
return function() {
show_tag(tag);
return false;
};
};
var sort_rows = function(cb) {
var tr = document.querySelectorAll(".projtable tr");
var items = [];
for (var i = 0, e = tr.length; i !== e; ++i) {
items.push([i, cb(tr[i])]);
}
items.sort(function(a, b) {
return (a[1] - b[1]);
});
for (var i = 0, e = items.length; i !== e; ++i) {
var el = tr[items[i][0]];
var parent = el.parentElement;
parent.removeChild(el);
parent.appendChild(el);
}
};
var sort_update = function() {
var cb;
switch(document.getElementById('sortorder').value) {
case 'a':
default: {
cb = function(el) {
return el.getAttribute('data-sort-ct');
};
} break;
case 'b': {
cb = function(el) {
return el.getAttribute('data-sort-mt');
}
} break;
case 'c': {
cb = function(el) {
return el.getAttribute('data-sort-al');
}
} break;
};
sort_rows(cb);
};
window.addEventListener('load', function() {
var taglinks = document.querySelectorAll(".tag-link");
for (var i = 0, e = taglinks.length; i !== e; ++i) {
var tag = taglinks[i].getAttribute("data-tag");
taglinks[i].addEventListener('click', get_show_tag(tag));
}
var so = document.getElementById('sortorder');
if (so) {
so.addEventListener('change', sort_update);
sort_update();
}
});
})();