18 Commits
v54 ... v72

Author SHA1 Message Date
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
16 changed files with 176 additions and 470 deletions

2
.hgtags Normal file
View File

@@ -0,0 +1,2 @@
42a17645b5b21d7fe395767de7fa3e26ee999014 release-r54
0f89ae041c2ee60cc1ea308d047fce816b19c490 release-r64

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)

View File

@@ -14,7 +14,16 @@ Written in PHP, Bash
=CHANGELOG= =CHANGELOG=
2015-04-04: rXX 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 - Feature: Support multiple code sites
- Fix an issue with parallel builds on some versions of windows - Fix an issue with parallel builds on some versions of windows
- Fix an issue corrupting URL links with multiple parameters - Fix an issue corrupting URL links with multiple parameters

View File

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

View File

@@ -151,9 +151,11 @@ 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 $images = array(); private $images = array();
private $downloads = array(); private $downloads = array();
private $downloads_hashes = array();
public $tags = array(); public $tags = array();
public $homeimage = null; public $homeimage = null;
@@ -169,6 +171,8 @@ class CProject {
if ($file[0] == '.') continue; if ($file[0] == '.') continue;
if ($file == 'README.txt') { if ($file == 'README.txt') {
$this->lastupdate = max($this->lastupdate, filectime($this->dir.$file)); // don't count README updates
$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)) {
@@ -184,7 +188,13 @@ class CProject {
$this->shortdesc[0] = strtolower($this->shortdesc[0]); // cosmetic lowercase $this->shortdesc[0] = strtolower($this->shortdesc[0]); // cosmetic lowercase
continue; continue;
} }
$this->lastupdate = max(
$this->lastupdate,
// filectime($this->dir.$file),
filemtime($this->dir.$file)
);
if (is_image($file)) { if (is_image($file)) {
$this->images[] = $file; $this->images[] = $file;
} else { } else {
@@ -194,13 +204,19 @@ class CProject {
natcasesort($this->downloads); natcasesort($this->downloads);
$this->downloads = array_reverse($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() { public function genHomeImage() {
if (count($this->images)) { if (count($this->images)) {
$this->homeimage = mkthumbnail( $this->homeimage = mkthumbnail(
$this->dir.$this->images[0], //BASEDIR.'wwwroot/srv/'.$this->projname.'_0.'.str_ext($this->images[0]), $this->dir.$this->images[0],
null, // raw handle null, // raw handle
INDEX_THUMB_W, INDEX_THUMB_H INDEX_THUMB_W, INDEX_THUMB_H
); );
@@ -222,7 +238,21 @@ class CProject {
// 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
@@ -260,11 +290,11 @@ class CProject {
<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(rawurlencode($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 } ?>
@@ -360,6 +390,8 @@ function buildcommon() {
$handles = array(); $handles = array();
$handle_lookup = array(); $handle_lookup = array();
$alphasort = [];
foreach($projects as $dirname => $projectname) { foreach($projects as $dirname => $projectname) {
$pr = new CProject($dirname, $projectname); $pr = new CProject($dirname, $projectname);
@@ -373,12 +405,26 @@ function buildcommon() {
$handle_lookup[$projectname] = count($handles); $handle_lookup[$projectname] = count($handles);
$handles[] = $pr->homeimage; $handles[] = $pr->homeimage;
} }
$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
@@ -391,9 +437,13 @@ function buildcommon() {
<!-- }} --> <!-- }} -->
<?php } ?> <?php } ?>
<table class="projtable"> <table id="projtable-main" class="projtable">
<?php foreach ($plist as $pr) { ?> <?php foreach ($plist as $i => $pr) { ?>
<tr class="<?=$pr->getClassAttr()?>"> <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>
@@ -425,8 +475,20 @@ function buildcommon() {
// Done // Done
} }
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) { function main($args) {
$basedir = './'; //$args[0]; $basedir = './';
$total = $args[0]; $total = $args[0];
$pos = $args[1]; $pos = $args[1];
@@ -453,6 +515,9 @@ function main($args) {
if ($pos == 0) { if ($pos == 0) {
buildcommon(); buildcommon();
if (array_key_exists('redirect', $config)) {
buildredirects( $config['redirect'] );
}
} else { } else {
buildprojects($pos, array_decimate(listprojects(), $total, $pos)); buildprojects($pos, array_decimate(listprojects(), $total, $pos));
} }

View File

@@ -6,7 +6,8 @@ THREADS=4
buildsite() { buildsite() {
local rebuild="$(realpath ./rebuild.php)" local basedir="$(realpath .)"
local rebuild="${basedir}/rebuild.php"
if [[ "$(uname -o)" == "Cygwin" ]] ; then if [[ "$(uname -o)" == "Cygwin" ]] ; then
rebuild="$(cygpath -w "$rebuild")" rebuild="$(cygpath -w "$rebuild")"
@@ -27,6 +28,7 @@ buildsite() {
if [[ ! -d static ]] ; then if [[ ! -d static ]] ; then
mkdir static mkdir static
fi fi
cp "${basedir}/static_global/"* wwwroot || true
cp static/* wwwroot || true cp static/* wwwroot || true
for htm in footer header homepage_blurb ; do for htm in footer header homepage_blurb ; do

View File

@@ -6,3 +6,7 @@ index_thumb_w=90
index_thumb_h=32 index_thumb_h=32
; n.b. Recommend a multiple of the JPEG iDCT block size for index_thumb_h ; 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

@@ -16,5 +16,11 @@
</p> </p>
<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> <strong>PROJECTS</strong>
</p> </p>

View File

@@ -6,3 +6,8 @@ index_thumb_w=90
index_thumb_h=32 index_thumb_h=32
; n.b. Recommend a multiple of the JPEG iDCT block size for index_thumb_h ; 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

@@ -4,5 +4,11 @@
</p> </p>
<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> <strong>PROJECTS</strong>
</p> </p>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 436 B

View File

@@ -1,406 +0,0 @@
/*! 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;
}

View File

@@ -1,46 +0,0 @@
(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; };
};
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));
}
});
})();

View File

Before

Width:  |  Height:  |  Size: 436 B

After

Width:  |  Height:  |  Size: 436 B

View File

@@ -33,14 +33,65 @@
}; };
var get_show_tag = function(tag) { var get_show_tag = function(tag) {
return function() { show_tag(tag); return false; }; 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() { window.addEventListener('load', function() {
var taglinks = document.querySelectorAll(".tag-link"); var taglinks = document.querySelectorAll(".tag-link");
for (var i = 0, e = taglinks.length; i !== e; ++i) { for (var i = 0, e = taglinks.length; i !== e; ++i) {
var tag = taglinks[i].getAttribute("data-tag"); var tag = taglinks[i].getAttribute("data-tag");
taglinks[i].addEventListener('click', get_show_tag(tag)); taglinks[i].addEventListener('click', get_show_tag(tag));
} }
var so = document.getElementById('sortorder');
if (so) {
so.addEventListener('change', sort_update);
sort_update();
}
}); });
})(); })();