Switched templating to Sasae.
This commit is contained in:
parent
ada73c23bb
commit
7bd41f4e93
36 changed files with 587 additions and 777 deletions
|
@ -12,7 +12,7 @@ define('MKI_DIR_LIB', MKI_ROOT . '/lib');
|
||||||
define('MKI_DIR_PUB', MKI_ROOT . '/public');
|
define('MKI_DIR_PUB', MKI_ROOT . '/public');
|
||||||
define('MKI_DIR_PAGES', MKI_ROOT . '/pages');
|
define('MKI_DIR_PAGES', MKI_ROOT . '/pages');
|
||||||
define('MKI_DIR_CONFIG', MKI_ROOT . '/config');
|
define('MKI_DIR_CONFIG', MKI_ROOT . '/config');
|
||||||
define('MKI_DIR_TEMPLATES', MKI_ROOT . '/tpl');
|
define('MKI_DIR_TEMPLATES', MKI_ROOT . '/templates');
|
||||||
|
|
||||||
require_once MKI_ROOT . '/vendor/autoload.php';
|
require_once MKI_ROOT . '/vendor/autoload.php';
|
||||||
|
|
||||||
|
|
|
@ -52,14 +52,16 @@ $router = new HttpFx;
|
||||||
$router->setDefaultErrorHandler(function($response, $request, $code, $text) use ($ctx) {
|
$router->setDefaultErrorHandler(function($response, $request, $code, $text) use ($ctx) {
|
||||||
$path = 'errors/' . $code;
|
$path = 'errors/' . $code;
|
||||||
$tpl = $ctx->getTemplating();
|
$tpl = $ctx->getTemplating();
|
||||||
$response->setContent($tpl->render($tpl->exists($path) ? $path : 'errors/master', [
|
$name = is_file(sprintf('%s/errors/%s.twig', MKI_DIR_TEMPLATES, $code)) ? sprintf('errors/%s.twig', $code) : 'errors/master';
|
||||||
|
|
||||||
|
$response->setContent($tpl->render($name, [
|
||||||
'http_error_code' => $code,
|
'http_error_code' => $code,
|
||||||
'http_error_title' => $text,
|
'http_error_title' => $text,
|
||||||
]));
|
]));
|
||||||
});
|
});
|
||||||
|
|
||||||
$router->get('/error/:code', function($response, $request, $code) {
|
$router->get('/error/:code', function($response, $request, string $code) {
|
||||||
return intval($code);
|
return (int)$code;
|
||||||
});
|
});
|
||||||
|
|
||||||
foreach(MKI_REDIRS as $source => $target)
|
foreach(MKI_REDIRS as $source => $target)
|
||||||
|
@ -68,7 +70,7 @@ foreach(MKI_REDIRS as $source => $target)
|
||||||
});
|
});
|
||||||
|
|
||||||
$router->use('/', function($response) {
|
$router->use('/', function($response) {
|
||||||
$response->setPoweredBy('Makai+Index');
|
$response->setPoweredBy('Makai');
|
||||||
});
|
});
|
||||||
|
|
||||||
$router->get('/header-bgs.json', function() use ($ctx) {
|
$router->get('/header-bgs.json', function() use ($ctx) {
|
||||||
|
@ -123,12 +125,23 @@ $router->get('/', function() use ($ctx) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$db = $ctx->getDatabase();
|
$dbConn = $ctx->getDatabase();
|
||||||
|
|
||||||
|
$projectInfos = (new Projects($dbConn))->getFeatured();
|
||||||
|
$langs = new Languages($dbConn);
|
||||||
|
|
||||||
|
$projects = [];
|
||||||
|
foreach($projectInfos as $projectInfo)
|
||||||
|
$projects[] = [
|
||||||
|
'info' => $projectInfo,
|
||||||
|
'colour' => $projectInfo->hasColour() ? $projectInfo->getColour() : $langs->getProjectColour($projectInfo),
|
||||||
|
];
|
||||||
|
|
||||||
|
$contacts = (new Contacts($dbConn))->getHomePage();
|
||||||
|
|
||||||
return $ctx->getTemplating()->render('index', [
|
return $ctx->getTemplating()->render('index', [
|
||||||
'projects' => (new Projects($db))->getFeatured(),
|
'projects' => $projects,
|
||||||
'languages' => new Languages($db),
|
'contacts' => $contacts,
|
||||||
'contacts' => (new Contacts($db))->getHomePage(),
|
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -139,8 +152,17 @@ $router->get('/contact', function() use ($ctx) {
|
||||||
});
|
});
|
||||||
|
|
||||||
$router->get('/projects', function() use ($ctx) {
|
$router->get('/projects', function() use ($ctx) {
|
||||||
$db = $ctx->getDatabase();
|
$dbConn = $ctx->getDatabase();
|
||||||
$projects = (new Projects($db))->getAll();
|
$langs = new Languages($dbConn);
|
||||||
|
$projectInfos = (new Projects($dbConn))->getAll();
|
||||||
|
|
||||||
|
$projects = [];
|
||||||
|
foreach($projectInfos as $projectInfo)
|
||||||
|
$projects[] = [
|
||||||
|
'info' => $projectInfo,
|
||||||
|
'langs' => $langs->getByProject($projectInfo),
|
||||||
|
'colour' => $projectInfo->hasColour() ? $projectInfo->getColour() : $langs->getProjectColour($projectInfo),
|
||||||
|
];
|
||||||
|
|
||||||
$sections = [
|
$sections = [
|
||||||
'projects' => [
|
'projects' => [
|
||||||
|
@ -152,12 +174,16 @@ $router->get('/projects', function() use ($ctx) {
|
||||||
|
|
||||||
return $ctx->getTemplating()->render('projects', [
|
return $ctx->getTemplating()->render('projects', [
|
||||||
'sections' => $sections,
|
'sections' => $sections,
|
||||||
'languages' => new Languages($db),
|
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
$router->get('/ascii', function() use ($ctx) {
|
$router->get('/ascii', function() use ($ctx) {
|
||||||
return $ctx->getTemplating()->render('ascii');
|
$templating = $ctx->getTemplating();
|
||||||
|
$templating->addFilter('chr', 'chr');
|
||||||
|
$templating->addFilter('decoct', 'decoct');
|
||||||
|
$templating->addFilter('dechex', 'dechex');
|
||||||
|
|
||||||
|
return $templating->render('ascii');
|
||||||
});
|
});
|
||||||
|
|
||||||
$router->get('/rngstr', function($response, $request) {
|
$router->get('/rngstr', function($response, $request) {
|
||||||
|
|
|
@ -2,6 +2,8 @@
|
||||||
namespace Makai;
|
namespace Makai;
|
||||||
|
|
||||||
use Index\WString;
|
use Index\WString;
|
||||||
|
use Index\Colour\Colour;
|
||||||
|
use Index\Colour\ColourRGB;
|
||||||
|
|
||||||
class ContactInfo {
|
class ContactInfo {
|
||||||
private string $name;
|
private string $name;
|
||||||
|
@ -48,12 +50,12 @@ class ContactInfo {
|
||||||
return $this->icon;
|
return $this->icon;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getColour(): int {
|
public function getColour(): Colour {
|
||||||
return $this->colour;
|
return ColourRGB::fromRawRGB($this->colour);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getColourHex(): string {
|
public function getColourRaw(): int {
|
||||||
return '#' . str_pad(dechex($this->colour), 6, '0', STR_PAD_LEFT);
|
return $this->colour;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getDisplay(): WString {
|
public function getDisplay(): WString {
|
||||||
|
|
24
src/GitInfo.php
Normal file
24
src/GitInfo.php
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
<?php
|
||||||
|
namespace Makai;
|
||||||
|
|
||||||
|
final class GitInfo {
|
||||||
|
public static function log(string $format, string $args = ''): string {
|
||||||
|
return trim(shell_exec(sprintf('git log --pretty="%s" %s -n1 HEAD', $format, $args)));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function hash(bool $long = false): string {
|
||||||
|
return self::log($long ? '%H' : '%h');
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function branch(): string {
|
||||||
|
return trim(`git rev-parse --abbrev-ref HEAD`);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function tag(): string {
|
||||||
|
return trim(`git describe --abbrev=0 --tags`);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function version(): string {
|
||||||
|
return self::branch() === 'HEAD' ? self::tag() : self::hash();
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,6 +3,8 @@ namespace Makai;
|
||||||
|
|
||||||
use Index\AString;
|
use Index\AString;
|
||||||
use Index\WString;
|
use Index\WString;
|
||||||
|
use Index\Colour\Colour;
|
||||||
|
use Index\Colour\ColourRGB;
|
||||||
|
|
||||||
class LanguageInfo {
|
class LanguageInfo {
|
||||||
private string $id;
|
private string $id;
|
||||||
|
@ -31,7 +33,11 @@ class LanguageInfo {
|
||||||
return $this->colour !== null;
|
return $this->colour !== null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getColour(): ?int {
|
public function getColour(): Colour {
|
||||||
|
return $this->colour === null ? Colour::none() : ColourRGB::fromRawRGB($this->colour);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getColourRaw(): ?int {
|
||||||
return $this->colour;
|
return $this->colour;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
<?php
|
<?php
|
||||||
namespace Makai;
|
namespace Makai;
|
||||||
|
|
||||||
|
use Index\Colour\Colour;
|
||||||
|
use Index\Colour\ColourRGB;
|
||||||
use Index\Data\DbType;
|
use Index\Data\DbType;
|
||||||
use Index\Data\IDbConnection;
|
use Index\Data\IDbConnection;
|
||||||
use Index\Data\IDbResult;
|
use Index\Data\IDbResult;
|
||||||
|
@ -31,7 +33,15 @@ class Languages {
|
||||||
return $objs;
|
return $objs;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getProjectColour(ProjectInfo $project): ?int {
|
public function getProjectColour(ProjectInfo $project): Colour {
|
||||||
|
$raw = $this->getProjectColourRaw($project);
|
||||||
|
if($raw === null)
|
||||||
|
return Colour::none();
|
||||||
|
|
||||||
|
return ColourRGB::fromRawRGB($raw);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getProjectColourRaw(ProjectInfo $project): ?int {
|
||||||
$stmt = $this->conn->prepare(self::QUERY_PROJECT_COLOUR);
|
$stmt = $this->conn->prepare(self::QUERY_PROJECT_COLOUR);
|
||||||
$stmt->addParameter(1, $project->getId(), DbType::STRING);
|
$stmt->addParameter(1, $project->getId(), DbType::STRING);
|
||||||
$stmt->execute();
|
$stmt->execute();
|
||||||
|
@ -40,7 +50,7 @@ class Languages {
|
||||||
if(!$result->next())
|
if(!$result->next())
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
return $result->getInteger(0);
|
return $result->isNull(0) ? null : $result->getInteger(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static function createObject(IDbResult $result): LanguageInfo {
|
private static function createObject(IDbResult $result): LanguageInfo {
|
||||||
|
|
|
@ -1,30 +1,37 @@
|
||||||
<?php
|
<?php
|
||||||
namespace Makai;
|
namespace Makai;
|
||||||
|
|
||||||
|
use Index\Environment;
|
||||||
use Index\Data\IDbConnection;
|
use Index\Data\IDbConnection;
|
||||||
|
use Sasae\SasaeEnvironment;
|
||||||
|
|
||||||
final class MakaiContext {
|
final class MakaiContext {
|
||||||
private IDbConnection $db;
|
private IDbConnection $dbConn;
|
||||||
private ?TemplateContext $tpl = null;
|
private ?SasaeEnvironment $templating = null;
|
||||||
|
|
||||||
public function __construct(IDbConnection $db) {
|
public function __construct(IDbConnection $dbConn) {
|
||||||
$this->db = $db;
|
$this->dbConn = $dbConn;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getDatabase(): IDbConnection {
|
public function getDatabase(): IDbConnection {
|
||||||
return $this->db;
|
return $this->dbConn;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getTemplating(): TemplateContext {
|
public function getTemplating(): SasaeEnvironment {
|
||||||
if($this->tpl === null) {
|
if($this->templating === null) {
|
||||||
$this->tpl = new TemplateContext(MKI_DIR_TEMPLATES);
|
$isDebug = Environment::isDebug();
|
||||||
$this->tpl->setGlobal('makai', $this);
|
|
||||||
$this->tpl->setGlobal('header_nav', $this->getDefaultNavigation());
|
$this->templating = new SasaeEnvironment(
|
||||||
$this->tpl->setGlobal('header_bgs', $this->getDefaultHeaders());
|
MKI_DIR_TEMPLATES,
|
||||||
$this->tpl->setGlobal('footer_quotes', $this->getFooterQuotes());
|
cache: $isDebug ? null : ['Makai', GitInfo::hash(true)],
|
||||||
|
debug: $isDebug,
|
||||||
|
);
|
||||||
|
$this->templating->addGlobal('header_nav', $this->getDefaultNavigation());
|
||||||
|
$this->templating->addGlobal('header_bgs', $this->getDefaultHeaders());
|
||||||
|
$this->templating->addGlobal('footer_quotes', $this->getFooterQuotes());
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->tpl;
|
return $this->templating;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getDefaultNavigation(): array {
|
public function getDefaultNavigation(): array {
|
||||||
|
|
|
@ -4,6 +4,8 @@ namespace Makai;
|
||||||
use Index\AString;
|
use Index\AString;
|
||||||
use Index\WString;
|
use Index\WString;
|
||||||
use Index\DateTime;
|
use Index\DateTime;
|
||||||
|
use Index\Colour\Colour;
|
||||||
|
use Index\Colour\ColourRGB;
|
||||||
|
|
||||||
class ProjectInfo {
|
class ProjectInfo {
|
||||||
private string $id;
|
private string $id;
|
||||||
|
@ -86,7 +88,11 @@ class ProjectInfo {
|
||||||
return $this->colour !== null;
|
return $this->colour !== null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getColour(): ?int {
|
public function getColour(): Colour {
|
||||||
|
return $this->colour === null ? Colour::none() : ColourRGB::fromRawRGB($this->colour);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getColourRaw(): ?int {
|
||||||
return $this->colour;
|
return $this->colour;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,48 +0,0 @@
|
||||||
<?php
|
|
||||||
namespace Makai;
|
|
||||||
|
|
||||||
class Template {
|
|
||||||
public function __construct(
|
|
||||||
private TemplateContext $context,
|
|
||||||
private TemplateVars $vars,
|
|
||||||
private string $path
|
|
||||||
) {}
|
|
||||||
|
|
||||||
public function setVar(string $name, mixed $value): void {
|
|
||||||
$this->vars->setVar($name, $value);
|
|
||||||
}
|
|
||||||
public function removeVar(string $name): void {
|
|
||||||
$this->vars->removeVar($name);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function render(array $vars = [], ?TemplateSelf $self = null): string {
|
|
||||||
if(!is_file($this->path))
|
|
||||||
throw new \RuntimeException('Template file does not exist: ' . $this->path);
|
|
||||||
|
|
||||||
$self = new TemplateSelf($this->context->getFunctions() + $vars + $this->vars->getVars(), $self);
|
|
||||||
$self->tplPath = $this->path;
|
|
||||||
|
|
||||||
$self->var = fn(string $name, mixed $default = null) => $this->vars->getVar($name, $default);
|
|
||||||
$self->setVar = fn(string $name, mixed $value) => $this->vars->setVar($name, $value);
|
|
||||||
$self->remVar = fn(string $name) => $this->vars->removeVar($name);
|
|
||||||
|
|
||||||
$self->block = fn(string $name, mixed $contents) => $this->context->setBlock($name, new TemplateBlock($self, $contents));
|
|
||||||
$self->include = fn(string $name) => $this->context->render($name, [], $self);
|
|
||||||
|
|
||||||
$self->ctx = $this->context;
|
|
||||||
$self->extends = fn(string $name) => $self->extends = $name;
|
|
||||||
|
|
||||||
ob_start();
|
|
||||||
(static function() use ($self) { include $self->tplPath; })();
|
|
||||||
$buffer = ob_get_contents();
|
|
||||||
ob_end_clean();
|
|
||||||
|
|
||||||
if(is_string($self->extends)) {
|
|
||||||
if(!empty($buffer))
|
|
||||||
throw new \RuntimeException('You cannot output from templates that extend another.');
|
|
||||||
$buffer = $this->context->render($self->extends, [], $self);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $buffer;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,22 +0,0 @@
|
||||||
<?php
|
|
||||||
namespace Makai;
|
|
||||||
|
|
||||||
use Closure;
|
|
||||||
|
|
||||||
class TemplateBlock {
|
|
||||||
public function __construct(
|
|
||||||
private object $self,
|
|
||||||
private mixed $body
|
|
||||||
) {}
|
|
||||||
|
|
||||||
public function render(): string {
|
|
||||||
if(is_callable($this->body)) {
|
|
||||||
ob_start();
|
|
||||||
($this->body)($this->self);
|
|
||||||
$body = ob_get_contents();
|
|
||||||
ob_end_clean();
|
|
||||||
} else $body = strval($this->body);
|
|
||||||
|
|
||||||
return $body;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,56 +0,0 @@
|
||||||
<?php
|
|
||||||
namespace Makai;
|
|
||||||
|
|
||||||
use Closure;
|
|
||||||
|
|
||||||
class TemplateContext {
|
|
||||||
private const EXT = '.php';
|
|
||||||
|
|
||||||
private string $pathFormat = '%s' . self::EXT;
|
|
||||||
private TemplateVars $vars;
|
|
||||||
private array $blocks = [];
|
|
||||||
private array $functions = [];
|
|
||||||
|
|
||||||
public function __construct($path = '') {
|
|
||||||
if(!empty($path))
|
|
||||||
$this->pathFormat = rtrim($path, '\\/') . DIRECTORY_SEPARATOR . '%s' . self::EXT;
|
|
||||||
$this->vars = new TemplateVars;
|
|
||||||
$this->defineFunction('global', $this->vars->getVar(...));
|
|
||||||
$this->defineFunction('getBlock', $this->getBlock(...));
|
|
||||||
$this->defineFunction('x', fn(string $string) => htmlspecialchars($string, ENT_QUOTES, 'utf-8', true));
|
|
||||||
}
|
|
||||||
|
|
||||||
public function setGlobal(string $name, mixed $value): void {
|
|
||||||
$this->vars->setVar($name, $value);
|
|
||||||
}
|
|
||||||
public function removeGlobal(string $name): void {
|
|
||||||
$this->vars->removeVar($name);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function defineFunction(string $name, Closure|callable $function): void {
|
|
||||||
$this->functions[$name] = $function;
|
|
||||||
}
|
|
||||||
public function getFunctions(): array {
|
|
||||||
return $this->functions;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function create(string $path): Template {
|
|
||||||
return new Template($this, new TemplateVars($this->vars), sprintf($this->pathFormat, $path));
|
|
||||||
}
|
|
||||||
|
|
||||||
public function exists(string $path): bool {
|
|
||||||
return is_file(sprintf($this->pathFormat, $path));
|
|
||||||
}
|
|
||||||
|
|
||||||
public function render(string $path, array $vars = [], ?TemplateSelf $self = null): string {
|
|
||||||
return $this->create($path)->render($vars, $self);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getBlock(string $name, mixed $default = ''): string {
|
|
||||||
return ($this->blocks[$name] ?? new TemplateBlock(new \stdClass, $default))->render();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function setBlock(string $name, TemplateBlock $block): void {
|
|
||||||
$this->blocks[$name] = $block;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,32 +0,0 @@
|
||||||
<?php
|
|
||||||
namespace Makai;
|
|
||||||
|
|
||||||
class TemplateSelf {
|
|
||||||
public function __construct(
|
|
||||||
private array $members = [],
|
|
||||||
?TemplateSelf $inherit = null
|
|
||||||
) {
|
|
||||||
if($inherit !== null)
|
|
||||||
$this->members += $inherit->members;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function __get(string $name): mixed {
|
|
||||||
return $this->members[$name];
|
|
||||||
}
|
|
||||||
|
|
||||||
public function __set(string $name, mixed $value): void {
|
|
||||||
$this->members[$name] = $value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function __isset(string $name): bool {
|
|
||||||
return isset($this->members[$name]);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function __unset(string $name): void {
|
|
||||||
unset($this->members[$name]);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function __call(string $name, array $args): mixed {
|
|
||||||
return ($this->members[$name])(...$args);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,32 +0,0 @@
|
||||||
<?php
|
|
||||||
namespace Makai;
|
|
||||||
|
|
||||||
class TemplateVars {
|
|
||||||
public function __construct(
|
|
||||||
private ?TemplateVars $parent = null,
|
|
||||||
private array $vars = []
|
|
||||||
) {}
|
|
||||||
|
|
||||||
public function getVars(): array {
|
|
||||||
$vars = $this->vars;
|
|
||||||
if($this->parent !== null)
|
|
||||||
$vars += $this->parent->getVars();
|
|
||||||
return $vars;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getVar(string $name, mixed $default = null): mixed {
|
|
||||||
if(isset($this->vars[$name]))
|
|
||||||
return $this->vars[$name];
|
|
||||||
if($this->parent !== null)
|
|
||||||
return $this->parent->getVar($name, $default);
|
|
||||||
return $default;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function setVar(string $name, mixed $value): void {
|
|
||||||
$this->vars[$name] = $value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function removeVar(string $name): void {
|
|
||||||
unset($this->vars[$name]);
|
|
||||||
}
|
|
||||||
}
|
|
257
templates/ascii.twig
Normal file
257
templates/ascii.twig
Normal file
|
@ -0,0 +1,257 @@
|
||||||
|
{% extends 'master.twig' %}
|
||||||
|
|
||||||
|
{% set header_title = 'flash.moe / ascii table' %}
|
||||||
|
{% set header_minimal = true %}
|
||||||
|
|
||||||
|
{% set table = [
|
||||||
|
['Null character', 'NUL'],
|
||||||
|
['Start of heading', 'SOH'],
|
||||||
|
['Start of text', 'STX'],
|
||||||
|
['End of text', 'ETX'],
|
||||||
|
['End of transmission', 'EOT'],
|
||||||
|
['Enquiry', 'ENQ'],
|
||||||
|
['Acknowledgement', 'ACK'],
|
||||||
|
['Bell', 'BEL'],
|
||||||
|
['Backspace', 'BS' ],
|
||||||
|
['Horizontal tab', 'HT' ],
|
||||||
|
['Line feed', 'LF' ],
|
||||||
|
['Vertical tab', 'VT' ],
|
||||||
|
['Form feed', 'FF' ],
|
||||||
|
['Carriage return', 'CR' ],
|
||||||
|
['Shift out/X-On', 'SO' ],
|
||||||
|
['Shift in/X-Off', 'SI' ],
|
||||||
|
['Delta line escape', 'DLE'],
|
||||||
|
['Device control 1 (often XON)', 'DC1'],
|
||||||
|
['Device control 2', 'DC2'],
|
||||||
|
['Device control 3 (often XOFF)', 'DC3'],
|
||||||
|
['Device control 4', 'DC4'],
|
||||||
|
['Negative acknowledgement', 'NAK'],
|
||||||
|
['Synchronous idle', 'SYN'],
|
||||||
|
['End of transmit block', 'ETB'],
|
||||||
|
['Cancel', 'CAN'],
|
||||||
|
['End of medium', 'EM' ],
|
||||||
|
['Substitute', 'SUB'],
|
||||||
|
['Escape', 'ESC'],
|
||||||
|
['File separator', 'FS' ],
|
||||||
|
['Group separator', 'GS' ],
|
||||||
|
['Record separator', 'RS' ],
|
||||||
|
['Unit separator', 'US' ],
|
||||||
|
|
||||||
|
['Space'],
|
||||||
|
['Excalamation mark'],
|
||||||
|
['Double quotes', 'quot'],
|
||||||
|
['Hash'],
|
||||||
|
['Dollar'],
|
||||||
|
['Percent'],
|
||||||
|
['Ampersand', 'amp'],
|
||||||
|
['Single quote'],
|
||||||
|
['Open parenthesis'],
|
||||||
|
['Close parenthesis'],
|
||||||
|
['Asterisk'],
|
||||||
|
['Plus'],
|
||||||
|
['Comma'],
|
||||||
|
['Hyphen'],
|
||||||
|
['Period'],
|
||||||
|
['Slash'],
|
||||||
|
['Zero'],
|
||||||
|
['One'],
|
||||||
|
['Two'],
|
||||||
|
['Three'],
|
||||||
|
['Four'],
|
||||||
|
['Five'],
|
||||||
|
['Six'],
|
||||||
|
['Seven'],
|
||||||
|
['Eight'],
|
||||||
|
['Nine'],
|
||||||
|
['Colon'],
|
||||||
|
['Semicolon'],
|
||||||
|
['Less than', 'lt'],
|
||||||
|
['Equals'],
|
||||||
|
['Greater than', 'gt'],
|
||||||
|
['Question mark'],
|
||||||
|
['At symbol'],
|
||||||
|
['Uppercase A'],
|
||||||
|
['Uppercase B'],
|
||||||
|
['Uppercase C'],
|
||||||
|
['Uppercase D'],
|
||||||
|
['Uppercase E'],
|
||||||
|
['Uppercase F'],
|
||||||
|
['Uppercase G'],
|
||||||
|
['Uppercase H'],
|
||||||
|
['Uppercase I'],
|
||||||
|
['Uppercase J'],
|
||||||
|
['Uppercase K'],
|
||||||
|
['Uppercase L'],
|
||||||
|
['Uppercase M'],
|
||||||
|
['Uppercase N'],
|
||||||
|
['Uppercase O'],
|
||||||
|
['Uppercase P'],
|
||||||
|
['Uppercase Q'],
|
||||||
|
['Uppercase R'],
|
||||||
|
['Uppercase S'],
|
||||||
|
['Uppercase T'],
|
||||||
|
['Uppercase U'],
|
||||||
|
['Uppercase V'],
|
||||||
|
['Uppercase W'],
|
||||||
|
['Uppercase X'],
|
||||||
|
['Uppercase Y'],
|
||||||
|
['Uppercase Z'],
|
||||||
|
['Opening bracket'],
|
||||||
|
['Backslash'],
|
||||||
|
['Closing bracket'],
|
||||||
|
['Caret'],
|
||||||
|
['Underscore'],
|
||||||
|
['Accent grave'],
|
||||||
|
['Lowercase a'],
|
||||||
|
['Lowercase b'],
|
||||||
|
['Lowercase c'],
|
||||||
|
['Lowercase d'],
|
||||||
|
['Lowercase e'],
|
||||||
|
['Lowercase f'],
|
||||||
|
['Lowercase g'],
|
||||||
|
['Lowercase h'],
|
||||||
|
['Lowercase i'],
|
||||||
|
['Lowercase j'],
|
||||||
|
['Lowercase k'],
|
||||||
|
['Lowercase l'],
|
||||||
|
['Lowercase m'],
|
||||||
|
['Lowercase n'],
|
||||||
|
['Lowercase o'],
|
||||||
|
['Lowercase p'],
|
||||||
|
['Lowercase q'],
|
||||||
|
['Lowercase r'],
|
||||||
|
['Lowercase s'],
|
||||||
|
['Lowercase t'],
|
||||||
|
['Lowercase u'],
|
||||||
|
['Lowercase v'],
|
||||||
|
['Lowercase w'],
|
||||||
|
['Lowercase x'],
|
||||||
|
['Lowercase y'],
|
||||||
|
['Lowercase z'],
|
||||||
|
['Opening curly brace'],
|
||||||
|
['Vertical bar'],
|
||||||
|
['Closing curly brace'],
|
||||||
|
['Tilde'],
|
||||||
|
|
||||||
|
['Delete', 'DEL'],
|
||||||
|
] %}
|
||||||
|
|
||||||
|
{% block container %}
|
||||||
|
<div class="ascii-wrap">
|
||||||
|
<div class="ascii-search">
|
||||||
|
<div class="ascii-search-box">
|
||||||
|
<input type="search" id="search" placeholder="Filter..." autocomplete="off">
|
||||||
|
</div>
|
||||||
|
<div class="ascii-search-hint js-invisible-on-scroll">
|
||||||
|
Type <em><code>printable</code></em> for all printable characters, or <em><code>control</code></em> for all control characters.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="ascii-chars">
|
||||||
|
{% for code, info in table %}
|
||||||
|
{% set is_printable = code > 31 and code < 127 %}
|
||||||
|
{% set has_html = is_printable and info[1] is defined %}
|
||||||
|
{% set print = is_printable ? code|chr : info[1] %}
|
||||||
|
|
||||||
|
<div class="ascii-char" data-key-code="{{ code }}" data-key-desc="{{ info[0] }}" data-key-print="{{ print }}" data-copy="{{ print }}" {% if has_html %}data-key-html="{{ info[1] }}"{% endif %}>
|
||||||
|
<div class="ascii-char-print">{{ print }}</div>
|
||||||
|
<div class="ascii-char-desc">{{ info[0] }}</div>
|
||||||
|
<div class="ascii-char-misc">
|
||||||
|
<div class="ascii-char-misc-item" data-copy="{{ code }}">
|
||||||
|
<div class="ascii-char-misc-item-head">Decimal</div>
|
||||||
|
<div class="ascii-char-misc-item-value">{{ code }}</div>
|
||||||
|
</div>
|
||||||
|
<div class="ascii-char-misc-item" data-copy="{{ code|decoct }}">
|
||||||
|
<div class="ascii-char-misc-item-head">Octal</div>
|
||||||
|
<div class="ascii-char-misc-item-value">{{ code|decoct }}</div>
|
||||||
|
</div>
|
||||||
|
<div class="ascii-char-misc-item" data-copy="{{ code|dechex }}">
|
||||||
|
<div class="ascii-char-misc-item-head">Hex</div>
|
||||||
|
<div class="ascii-char-misc-item-value">{{ code|dechex }}</div>
|
||||||
|
</div>
|
||||||
|
{% if has_html %}
|
||||||
|
<div class="ascii-char-misc-item" data-copy="&{{ info[1] }};">
|
||||||
|
<div class="ascii-char-misc-item-head">HTML</div>
|
||||||
|
<div class="ascii-char-misc-item-value">&{{ info[1] }};</div>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<script type="text/javascript">
|
||||||
|
var chars = document.getElementsByClassName('ascii-char'),
|
||||||
|
search = document.getElementById('search');
|
||||||
|
|
||||||
|
function charsFilter(filter) {
|
||||||
|
if(!filter) {
|
||||||
|
for(var i = 0; i < chars.length; ++i)
|
||||||
|
chars[i].classList.remove('hidden');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
filter = filter.toLowerCase();
|
||||||
|
|
||||||
|
for(var i = 0; i < chars.length; ++i) {
|
||||||
|
var chr = chars[i],
|
||||||
|
code = (chr.dataset.keyCode || 0).toString().toLowerCase(),
|
||||||
|
print = (chr.dataset.keyPrint || "\0").toString().toLowerCase(),
|
||||||
|
desc = (chr.dataset.keyDesc || '').toString().toLowerCase(),
|
||||||
|
html = (chr.dataset.keyHtml || "\0").toString().toLowerCase(),
|
||||||
|
codeInt = parseInt(code),
|
||||||
|
isMatch = (filter === 'printable' && (codeInt > 31 && codeInt < 127))
|
||||||
|
|| (filter === 'control' && (codeInt < 32 || codeInt === 127))
|
||||||
|
|| code == filter || print == filter
|
||||||
|
|| html == filter || desc.indexOf(filter) >= 0;
|
||||||
|
chr.classList[isMatch ? 'remove' : 'add']('hidden');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
window.addEventListener('scroll', function() {
|
||||||
|
var hidden = document.getElementsByClassName('js-hidden-on-scroll'),
|
||||||
|
invisible = document.getElementsByClassName('js-invisible-on-scroll'),
|
||||||
|
atTop = window.scrollY === 0;
|
||||||
|
|
||||||
|
for(var i = 0; i < hidden.length; ++i)
|
||||||
|
hidden[i].classList[atTop ? 'remove' : 'add']('hidden');
|
||||||
|
for(var i = 0; i < invisible.length; ++i)
|
||||||
|
invisible[i].classList[atTop ? 'remove' : 'add']('invisible');
|
||||||
|
});
|
||||||
|
search.addEventListener('keyup', function() {
|
||||||
|
location.hash = search.value.trim();
|
||||||
|
});
|
||||||
|
window.addEventListener('hashchange', function() {
|
||||||
|
charsFilter(decodeURIComponent((location.hash || '#').substring(1)));
|
||||||
|
});
|
||||||
|
if(location.hash.length > 0) {
|
||||||
|
search.value = location.hash.substring(1).trim();
|
||||||
|
charsFilter(search.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
for(var i = 0; i < chars.length; ++i) {
|
||||||
|
chars[i].addEventListener('click', function(ev) {
|
||||||
|
var target = ev.target;
|
||||||
|
|
||||||
|
while(target !== null && typeof target.dataset.copy === 'undefined') {
|
||||||
|
target = target.parentNode || null;
|
||||||
|
|
||||||
|
if(target.classList.contains('char'))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(target === null || typeof target.dataset.copy === 'undefined')
|
||||||
|
return;
|
||||||
|
|
||||||
|
var doCopy = function() { navigator.clipboard.writeText(target.dataset.copy); };
|
||||||
|
|
||||||
|
if(typeof window.mozInnerScreenX !== 'undefined')
|
||||||
|
doCopy();
|
||||||
|
else
|
||||||
|
navigator.permissions.query({name: 'clipboard-write'}).then(function(res) {
|
||||||
|
if(res.state === 'granted' || res.state === 'prompt')
|
||||||
|
doCopy();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
{% endblock %}
|
29
templates/contact.twig
Normal file
29
templates/contact.twig
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
{% extends 'master.twig' %}
|
||||||
|
|
||||||
|
{% set header_title = 'flash.moe / contact' %}
|
||||||
|
|
||||||
|
{% block container %}
|
||||||
|
<div class="section">
|
||||||
|
<div class="section-content">
|
||||||
|
<div class="section-background"></div>
|
||||||
|
<h1>Contact</h1>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="socials">
|
||||||
|
{% for contact in contacts %}
|
||||||
|
<div class="social social-{{ contact.name }}" style="--social-colour: {{ contact.colour }}">
|
||||||
|
{% if contact.hasLink %}
|
||||||
|
<a href="{{ contact.link }}" class="social-background" target="_blank" rel="noopener"></a>
|
||||||
|
{% else %}
|
||||||
|
<div class="social-background" onclick="fm.selectTextInElement(this.parentNode.querySelector('.social-handle')); fm.copySelectedText();"></div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<div class="social-icon {{ contact.icon }}"></div>
|
||||||
|
<div class="social-content">
|
||||||
|
<div class="social-name">{{ contact.title }}</div>
|
||||||
|
<div class="social-handle">{{ contact.display }}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
4
templates/errors/403.twig
Normal file
4
templates/errors/403.twig
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
{% extends 'errors/master.twig' %}
|
||||||
|
|
||||||
|
{% set http_error_image = '/assets/errors/403.jpg' %}
|
||||||
|
{% set http_error_desc = 'You are not supposed to be here.' %}
|
4
templates/errors/404.twig
Normal file
4
templates/errors/404.twig
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
{% extends 'errors/master.twig' %}
|
||||||
|
|
||||||
|
{% set http_error_image = '/assets/errors/404.jpg' %}
|
||||||
|
{% set http_error_desc = 'Whatever you\'re looking for is no longer here, or might not have been here in the first place.' %}
|
4
templates/errors/405.twig
Normal file
4
templates/errors/405.twig
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
{% extends 'errors/master.twig' %}
|
||||||
|
|
||||||
|
{% set http_error_image = '/assets/errors/405.jpg' %}
|
||||||
|
{% set http_error_desc = 'You\'re up to something, aren\'t you?' %}
|
11
templates/errors/master.twig
Normal file
11
templates/errors/master.twig
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
{% extends 'master.twig' %}
|
||||||
|
|
||||||
|
{% block container %}
|
||||||
|
<div class="http-error">
|
||||||
|
<h2 class="http-error-head">{{ http_error_title|default('Unknown Error #' ~ http_error_code) }}</h2>
|
||||||
|
{% if http_error_image is defined %}
|
||||||
|
<img src="{{ http_error_image }}" alt="{{ http_error_image }}" class="http-error-image">
|
||||||
|
{% endif %}
|
||||||
|
<div class="http-error-desc">{{ http_error_desc|default('No additional information is available.') }}</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
|
@ -1,12 +1,10 @@
|
||||||
<?php
|
{% extends 'home/master.twig' %}
|
||||||
$self->extends('home/master');
|
|
||||||
|
|
||||||
$self->header_title = 'flash.moe / homepage';
|
{% set header_title = 'flash.moe / homepage' %}
|
||||||
$self->header_full = true;
|
{% set header_full = true %}
|
||||||
$self->footer_onload = [['fm.initClock'], ['fm.initIndex', 10]];
|
{% set footer_onload = [['fm.initClock'], ['fm.initIndex', 10]] %}
|
||||||
|
|
||||||
$self->block('container', function($self) {
|
{% block container %}
|
||||||
?>
|
|
||||||
<div class="php">
|
<div class="php">
|
||||||
<div class="php-time">
|
<div class="php-time">
|
||||||
<div class="php-time-analog">
|
<div class="php-time-analog">
|
||||||
|
@ -42,5 +40,4 @@ $self->block('container', function($self) {
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
<?php
|
{% endblock %}
|
||||||
});
|
|
1
templates/home/master.twig
Normal file
1
templates/home/master.twig
Normal file
|
@ -0,0 +1 @@
|
||||||
|
{% extends 'master.twig' %}
|
73
templates/index.twig
Normal file
73
templates/index.twig
Normal file
|
@ -0,0 +1,73 @@
|
||||||
|
{% extends 'master.twig' %}
|
||||||
|
|
||||||
|
{% set header_title = 'flash.moe' %}
|
||||||
|
{% set header_is_index = true %}
|
||||||
|
{% set footer_onload = [['fm.initIndex']] %}
|
||||||
|
|
||||||
|
{% block container %}
|
||||||
|
<div class="index-menu">
|
||||||
|
{% for link in header_nav|slice(1) %}
|
||||||
|
<a href="{{ link.link }}">{{ link.title }}</a>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="index-featured">
|
||||||
|
<div class="index-feature">
|
||||||
|
<div class="index-feature-header">
|
||||||
|
<a href="/projects" class="index-feature-header-link"></a>
|
||||||
|
<div class="index-feature-header-title">Projects</div>
|
||||||
|
<div class="index-feature-header-more">More</div>
|
||||||
|
</div>
|
||||||
|
{% for project in projects %}
|
||||||
|
<div class="index-project" style="background-color: {{ project.colour }};">
|
||||||
|
<a href="/projects#{{ project.info.cleanName }}" class="index-project-anchor"></a>
|
||||||
|
<div class="index-project-content">
|
||||||
|
<div class="index-project-name">{{ project.info.name }}</div>
|
||||||
|
{% if project.info.hasSummary %}
|
||||||
|
<div class="index-project-summary">{{ project.info.summary }}</div>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="index-project-links">
|
||||||
|
{% if project.info.hasHomePageUrl %}
|
||||||
|
<a class="index-project-link index-project-link-homepage" href="{{ project.info.homePageUrl }}" rel="noopener" target="_blank">Homepage</a>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if project.info.hasSourceUrl %}
|
||||||
|
<a class="index-project-link index-project-link-repository" href="{{ project.info.sourceUrl }}" rel="noopener" target="_blank">Source</a>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if project.info.hasDiscussionUrl %}
|
||||||
|
<a class="index-project-link index-project-link-forum" href="{{ project.info.discussionUrl }}" rel="noopener" target="_blank">Discussion</a>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="index-feature">
|
||||||
|
<div class="index-feature-header">
|
||||||
|
<a href="/contact" class="index-feature-header-link"></a>
|
||||||
|
<div class="index-feature-header-title">Contact</div>
|
||||||
|
<div class="index-feature-header-more">More</div>
|
||||||
|
</div>
|
||||||
|
<div class="index-contact">
|
||||||
|
{% for contact in contacts %}
|
||||||
|
<div class="social social-{{ contact.name }}" style="--social-colour: {{ contact.colour }}">
|
||||||
|
{% if contact.hasLink %}
|
||||||
|
<a href="{{ contact.link }}" class="social-background" target="_blank" rel="noopener"></a>
|
||||||
|
{% else %}
|
||||||
|
<div class="social-background" onclick="fm.selectTextInElement(this.parentNode.querySelector('.social-handle')); fm.copySelectedText();"></div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<div class="social-icon {{ contact.icon }}"></div>
|
||||||
|
<div class="social-content">
|
||||||
|
<div class="social-name">{{ contact.title }}</div>
|
||||||
|
<div class="social-handle">{{ contact.display }}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
|
@ -2,21 +2,21 @@
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<title><?=($self->header_title ?? 'flash.moe');?></title>
|
<title>{% if title is defined %}{{ title }} // {% endif %}flash.moe</title>
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
|
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
|
||||||
<link href="/assets/2021.css" type="text/css" rel="stylesheet">
|
<link href="/assets/2021.css" type="text/css" rel="stylesheet">
|
||||||
<link href="/assets/sprite.css" type="text/css" rel="stylesheet">
|
<link href="/assets/sprite.css" type="text/css" rel="stylesheet">
|
||||||
<link href="/assets/fonts/electrolize/style.css" type="text/css" rel="stylesheet">
|
<link href="/assets/fonts/electrolize/style.css" type="text/css" rel="stylesheet">
|
||||||
</head>
|
</head>
|
||||||
<body class="<?php if(isset($self->header_is_index)) { echo 'index ';} if(isset($self->header_full)) { echo 'fullscreen-header ';} if(isset($self->header_now_playing)) { echo 'now-playing ';} if(isset($self->header_minimal)) { echo 'header-minimal ';} ?>">
|
<body class="{{ html_classes({ 'index': header_is_index is defined, 'fullscreen-header': header_full is defined, 'now-playing': header_now_playing is defined, 'header-minimal': header_minimal is defined }) }}">
|
||||||
<div class="header">
|
<div class="header">
|
||||||
<div class="header-background">
|
<div class="header-background">
|
||||||
<img src="<?=($self->header_bgs[array_rand($self->header_bgs)]);?>" alt="">
|
<img src="{{ random(header_bgs) }}" alt="">
|
||||||
</div>
|
</div>
|
||||||
<div class="header-foreground"<?php if(isset($self->header_offset) && $self->header_offset > 0) echo " style=\"padding-bottom: {$self->header_offset}px\""; ?>>
|
<div class="header-foreground" {% if header_offset is defined and header_offset > 0 %}style="padding-bottom: {{ header_offset }}px"{% endif %}>
|
||||||
<a class="header-logo" href="/">
|
<a class="header-logo" href="/">
|
||||||
<div class="header-flash"><?=($self->header_logo_flash ?? 'flash');?></div>
|
<div class="header-flash">{{ header_logo_flash|default('flash') }}</div>
|
||||||
<div class="header-wave"><?=($self->header_logo_wave ?? 'wave');?></div>
|
<div class="header-wave">{{ header_logo_wave|default('wave') }}</div>
|
||||||
</a>
|
</a>
|
||||||
<div class="header-right">
|
<div class="header-right">
|
||||||
<div class="header-now-playing header-now-playing-hidden">
|
<div class="header-now-playing header-now-playing-hidden">
|
||||||
|
@ -32,24 +32,25 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="header-menu">
|
<div class="header-menu">
|
||||||
<?php foreach($self->header_nav as $link): ?>
|
{% for link in header_nav %}
|
||||||
<a href="<?=$link['link'];?>"<?php if($link['link'][0] === '/' && substr($link['link'], 0, 2) !== '//') { echo ''; } ?>><?=$link['title'];?></a>
|
<a href="{{ link.link }}">{{ link.title }}</a>
|
||||||
<?php endforeach; ?>
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<?=$self->getBlock('container');?>
|
{% block container %}
|
||||||
|
{% endblock %}
|
||||||
</div>
|
</div>
|
||||||
<div class="footer">
|
<div class="footer">
|
||||||
<div class="footer-text">© flashwave <?=($self->footer_copy_start ?? '2010');?>-<?=($self->footer_copy_end ?? date('Y'));?> - <?=($self->footer_quotes[array_rand($self->footer_quotes)]);?></div>
|
<div class="footer-text">© flashwave {{ footer_copy_start|default('2010') }}-{{ footer_copy_end|default(('now'|date('Y'))) }} - {{ random(footer_quotes) }}</div>
|
||||||
</div>
|
</div>
|
||||||
<?php if(isset($self->footer_onload) && is_array($self->footer_onload)): ?>
|
{% if footer_onload is defined %}
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
window.fm = { onload: <?=json_encode($self->footer_onload);?> };
|
window.fm = { onload: {{ footer_onload|json_encode|raw }} };
|
||||||
</script>
|
</script>
|
||||||
<?php endif; ?>
|
{% endif %}
|
||||||
<script src="/assets/2021.js" charset="utf-8" type="text/javascript"></script>
|
<script src="/assets/2021.js" charset="utf-8" type="text/javascript"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
6
templates/np.twig
Normal file
6
templates/np.twig
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
{% extends 'master.twig' %}
|
||||||
|
|
||||||
|
{% set header_title = 'flash.moe / now listening' %}
|
||||||
|
{% set header_full = true %}
|
||||||
|
{% set header_now_playing = true %}
|
||||||
|
{% set footer_onload = [['fm.initIndex', 10]] %}
|
54
templates/projects.twig
Normal file
54
templates/projects.twig
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
{% extends 'master.twig' %}
|
||||||
|
|
||||||
|
{% set header_title = 'flash.moe / projects' %}
|
||||||
|
|
||||||
|
{% block container %}
|
||||||
|
{% for sectionId, section in sections %}
|
||||||
|
<div class="section" id="section-{{ sectionId }}">
|
||||||
|
<div class="section-content">
|
||||||
|
<div class="section-background"></div>
|
||||||
|
<h1>{{ section.title }}</h1>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% for project in section.items %}
|
||||||
|
<div class="project project-type-{{ sectionId }}" id="{{ project.info.cleanName }}" style="--project-colour: {{ project.colour }};">
|
||||||
|
<div class="project-content">
|
||||||
|
<div class="project-details">
|
||||||
|
<h2>{{ project.info.name }}<div class="project-languages">
|
||||||
|
{% for lang in project.langs %}
|
||||||
|
<div class="project-language" style="--language-colour: {{ lang.colour }};">{{ lang.name }}</div>
|
||||||
|
{% endfor %}</div>
|
||||||
|
</h2>
|
||||||
|
|
||||||
|
{% if project.info.hasSummary %}
|
||||||
|
<p class="project-details-summary">{{ project.info.summary }}</p>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if project.info.hasDescription %}
|
||||||
|
{% set lines = project.info.description|split("\n") %}
|
||||||
|
{% for line in lines %}
|
||||||
|
<p>{{ line|trim }}</p>
|
||||||
|
{% endfor %}
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="project-links">
|
||||||
|
{% if project.info.hasHomePageUrl %}
|
||||||
|
<a class="project-link project-link-homepage" href="{{ project.info.homePageUrl }}" rel="noopener" target="_blank">Homepage</a>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if project.info.hasSourceUrl %}
|
||||||
|
<a class="project-link project-link-repository" href="{{ project.info.sourceUrl }}" rel="noopener" target="_blank">Source</a>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if project.info.hasDiscussionUrl %}
|
||||||
|
<a class="project-link project-link-forum" href="{{ project.info.discussionUrl }}" rel="noopener" target="_blank">Discussion</a>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
{% endfor %}
|
||||||
|
{% endblock %}
|
|
@ -1,14 +1,12 @@
|
||||||
<?php
|
{% extends 'master.twig' %}
|
||||||
$self->extends('master');
|
|
||||||
|
|
||||||
$self->header_title = 'flash.moe / whois';
|
{% set header_title = 'flash.moe / whois' %}
|
||||||
$self->header_logo_flash = 'flash.moe ';
|
{% set header_logo_flash = 'flash.moe ' %}
|
||||||
$self->header_logo_wave = 'whois';
|
{% set header_logo_wave = 'whois' %}
|
||||||
$self->header_minimal = true;
|
{% set header_minimal = true %}
|
||||||
$self->footer_copy_start = '2013';
|
{% set footer_copy_start = '2013' %}
|
||||||
|
|
||||||
$self->block('container', function($self) {
|
{% block container %}
|
||||||
?>
|
|
||||||
<div class="whois-container">
|
<div class="whois-container">
|
||||||
<form class="whois-lookup-form" method="get" action="">
|
<form class="whois-lookup-form" method="get" action="">
|
||||||
<input class="whois-lookup-form-input" type="text" name="domain" placeholder="Enter a domain or IP address to look up!" value="" id="lookup-input">
|
<input class="whois-lookup-form-input" type="text" name="domain" placeholder="Enter a domain or IP address to look up!" value="" id="lookup-input">
|
||||||
|
@ -24,5 +22,4 @@ $self->block('container', function($self) {
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script type="text/javascript" src="/assets/2021whois.js"></script>
|
<script type="text/javascript" src="/assets/2021whois.js"></script>
|
||||||
<?php
|
{% endblock %}
|
||||||
});
|
|
279
tpl/ascii.php
279
tpl/ascii.php
|
@ -1,279 +0,0 @@
|
||||||
<?php
|
|
||||||
$self->extends('master');
|
|
||||||
|
|
||||||
$self->header_title = 'flash.moe / ascii table';
|
|
||||||
$self->header_minimal = true;
|
|
||||||
|
|
||||||
$self->block('container', function($self) {
|
|
||||||
$table = [
|
|
||||||
// Control characters
|
|
||||||
['Null character', 'NUL'],
|
|
||||||
['Start of heading', 'SOH'],
|
|
||||||
['Start of text', 'STX'],
|
|
||||||
['End of text', 'ETX'],
|
|
||||||
['End of transmission', 'EOT'],
|
|
||||||
['Enquiry', 'ENQ'],
|
|
||||||
['Acknowledgement', 'ACK'],
|
|
||||||
['Bell', 'BEL'],
|
|
||||||
['Backspace', 'BS' ],
|
|
||||||
['Horizontal tab', 'HT' ],
|
|
||||||
['Line feed', 'LF' ],
|
|
||||||
['Vertical tab', 'VT' ],
|
|
||||||
['Form feed', 'FF' ],
|
|
||||||
['Carriage return', 'CR' ],
|
|
||||||
['Shift out/X-On', 'SO' ],
|
|
||||||
['Shift in/X-Off', 'SI' ],
|
|
||||||
['Delta line escape', 'DLE'],
|
|
||||||
['Device control 1 (often XON)', 'DC1'],
|
|
||||||
['Device control 2', 'DC2'],
|
|
||||||
['Device control 3 (often XOFF)', 'DC3'],
|
|
||||||
['Device control 4', 'DC4'],
|
|
||||||
['Negative acknowledgement', 'NAK'],
|
|
||||||
['Synchronous idle', 'SYN'],
|
|
||||||
['End of transmit block', 'ETB'],
|
|
||||||
['Cancel', 'CAN'],
|
|
||||||
['End of medium', 'EM' ],
|
|
||||||
['Substitute', 'SUB'],
|
|
||||||
['Escape', 'ESC'],
|
|
||||||
['File separator', 'FS' ],
|
|
||||||
['Group separator', 'GS' ],
|
|
||||||
['Record separator', 'RS' ],
|
|
||||||
['Unit separator', 'US' ],
|
|
||||||
|
|
||||||
// Printable characters
|
|
||||||
['Space'],
|
|
||||||
['Excalamation mark'],
|
|
||||||
['Double quotes', 'quot'],
|
|
||||||
['Hash'],
|
|
||||||
['Dollar'],
|
|
||||||
['Percent'],
|
|
||||||
['Ampersand', 'amp'],
|
|
||||||
['Single quote'],
|
|
||||||
['Open parenthesis'],
|
|
||||||
['Close parenthesis'],
|
|
||||||
['Asterisk'],
|
|
||||||
['Plus'],
|
|
||||||
['Comma'],
|
|
||||||
['Hyphen'],
|
|
||||||
['Period'],
|
|
||||||
['Slash'],
|
|
||||||
['Zero'],
|
|
||||||
['One'],
|
|
||||||
['Two'],
|
|
||||||
['Three'],
|
|
||||||
['Four'],
|
|
||||||
['Five'],
|
|
||||||
['Six'],
|
|
||||||
['Seven'],
|
|
||||||
['Eight'],
|
|
||||||
['Nine'],
|
|
||||||
['Colon'],
|
|
||||||
['Semicolon'],
|
|
||||||
['Less than', 'lt'],
|
|
||||||
['Equals'],
|
|
||||||
['Greater than', 'gt'],
|
|
||||||
['Question mark'],
|
|
||||||
['At symbol'],
|
|
||||||
['Uppercase A'],
|
|
||||||
['Uppercase B'],
|
|
||||||
['Uppercase C'],
|
|
||||||
['Uppercase D'],
|
|
||||||
['Uppercase E'],
|
|
||||||
['Uppercase F'],
|
|
||||||
['Uppercase G'],
|
|
||||||
['Uppercase H'],
|
|
||||||
['Uppercase I'],
|
|
||||||
['Uppercase J'],
|
|
||||||
['Uppercase K'],
|
|
||||||
['Uppercase L'],
|
|
||||||
['Uppercase M'],
|
|
||||||
['Uppercase N'],
|
|
||||||
['Uppercase O'],
|
|
||||||
['Uppercase P'],
|
|
||||||
['Uppercase Q'],
|
|
||||||
['Uppercase R'],
|
|
||||||
['Uppercase S'],
|
|
||||||
['Uppercase T'],
|
|
||||||
['Uppercase U'],
|
|
||||||
['Uppercase V'],
|
|
||||||
['Uppercase W'],
|
|
||||||
['Uppercase X'],
|
|
||||||
['Uppercase Y'],
|
|
||||||
['Uppercase Z'],
|
|
||||||
['Opening bracket'],
|
|
||||||
['Backslash'],
|
|
||||||
['Closing bracket'],
|
|
||||||
['Caret'],
|
|
||||||
['Underscore'],
|
|
||||||
['Accent grave'],
|
|
||||||
['Lowercase a'],
|
|
||||||
['Lowercase b'],
|
|
||||||
['Lowercase c'],
|
|
||||||
['Lowercase d'],
|
|
||||||
['Lowercase e'],
|
|
||||||
['Lowercase f'],
|
|
||||||
['Lowercase g'],
|
|
||||||
['Lowercase h'],
|
|
||||||
['Lowercase i'],
|
|
||||||
['Lowercase j'],
|
|
||||||
['Lowercase k'],
|
|
||||||
['Lowercase l'],
|
|
||||||
['Lowercase m'],
|
|
||||||
['Lowercase n'],
|
|
||||||
['Lowercase o'],
|
|
||||||
['Lowercase p'],
|
|
||||||
['Lowercase q'],
|
|
||||||
['Lowercase r'],
|
|
||||||
['Lowercase s'],
|
|
||||||
['Lowercase t'],
|
|
||||||
['Lowercase u'],
|
|
||||||
['Lowercase v'],
|
|
||||||
['Lowercase w'],
|
|
||||||
['Lowercase x'],
|
|
||||||
['Lowercase y'],
|
|
||||||
['Lowercase z'],
|
|
||||||
['Opening curly brace'],
|
|
||||||
['Vertical bar'],
|
|
||||||
['Closing curly brace'],
|
|
||||||
['Tilde'],
|
|
||||||
|
|
||||||
// Delete
|
|
||||||
['Delete', 'DEL'],
|
|
||||||
];
|
|
||||||
?>
|
|
||||||
<div class="ascii-wrap">
|
|
||||||
<div class="ascii-search">
|
|
||||||
<div class="ascii-search-box">
|
|
||||||
<input type="search" id="search" placeholder="Filter..." autocomplete="off">
|
|
||||||
</div>
|
|
||||||
<div class="ascii-search-hint js-invisible-on-scroll">
|
|
||||||
Type <em><code>printable</code></em> for all printable characters, or <em><code>control</code></em> for all control characters.
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="ascii-chars"><?php
|
|
||||||
foreach($table as $code => $info):
|
|
||||||
$isPrintable = ($code > 31 && $code < 127);
|
|
||||||
$print = $isPrintable ? chr($code) : $info[1];
|
|
||||||
$attrs = ['data-key-code' => $code, 'data-key-desc' => $info[0], 'data-key-print' => $print, 'data-copy' => $print];
|
|
||||||
$attrStr = '';
|
|
||||||
|
|
||||||
if($isPrintable && isset($info[1]))
|
|
||||||
$attrs['data-key-html'] = $info[1];
|
|
||||||
|
|
||||||
foreach($attrs as $name => $value)
|
|
||||||
$attrStr .= $name . '="' . htmlentities($value) . '" ';
|
|
||||||
?><div class="ascii-char" <?=trim($attrStr);?>>
|
|
||||||
<div class="ascii-char-print"><?=$print;?></div>
|
|
||||||
<div class="ascii-char-desc"><?=$info[0];?></div>
|
|
||||||
<div class="ascii-char-misc">
|
|
||||||
<div class="ascii-char-misc-item" data-copy="<?=$code;?>">
|
|
||||||
<div class="ascii-char-misc-item-head">Decimal</div>
|
|
||||||
<div class="ascii-char-misc-item-value"><?=$code;?></div>
|
|
||||||
</div>
|
|
||||||
<div class="ascii-char-misc-item" data-copy="<?=decoct($code);?>">
|
|
||||||
<div class="ascii-char-misc-item-head">Octal</div>
|
|
||||||
<div class="ascii-char-misc-item-value"><?=decoct($code);?></div>
|
|
||||||
</div>
|
|
||||||
<div class="ascii-char-misc-item" data-copy="<?=dechex($code);?>">
|
|
||||||
<div class="ascii-char-misc-item-head">Hex</div>
|
|
||||||
<div class="ascii-char-misc-item-value"><?=dechex($code);?></div>
|
|
||||||
</div>
|
|
||||||
<?php if(isset($attrs['data-key-html'])): ?>
|
|
||||||
<div class="ascii-char-misc-item" data-copy="&<?=$attrs['data-key-html'];?>;">
|
|
||||||
<div class="ascii-char-misc-item-head">HTML</div>
|
|
||||||
<div class="ascii-char-misc-item-value">&<?=$attrs['data-key-html'];?>;</div>
|
|
||||||
</div>
|
|
||||||
<?php endif; ?>
|
|
||||||
</div>
|
|
||||||
</div><?php endforeach; ?></div>
|
|
||||||
</div>
|
|
||||||
<script type="text/javascript">
|
|
||||||
var chars = document.getElementsByClassName('ascii-char'),
|
|
||||||
search = document.getElementById('search');
|
|
||||||
|
|
||||||
function charsFilter(filter) {
|
|
||||||
if(!filter) {
|
|
||||||
for(var i = 0; i < chars.length; ++i)
|
|
||||||
chars[i].classList.remove('hidden');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
filter = filter.toLowerCase();
|
|
||||||
|
|
||||||
for(var i = 0; i < chars.length; ++i) {
|
|
||||||
var chr = chars[i],
|
|
||||||
code = (chr.dataset.keyCode || 0).toString().toLowerCase(),
|
|
||||||
print = (chr.dataset.keyPrint || "\0").toString().toLowerCase(),
|
|
||||||
desc = (chr.dataset.keyDesc || '').toString().toLowerCase(),
|
|
||||||
html = (chr.dataset.keyHtml || "\0").toString().toLowerCase(),
|
|
||||||
codeInt = parseInt(code),
|
|
||||||
isMatch = (filter === 'printable' && (codeInt > 31 && codeInt < 127))
|
|
||||||
|| (filter === 'control' && (codeInt < 32 || codeInt === 127))
|
|
||||||
|| code == filter || print == filter
|
|
||||||
|| html == filter || desc.indexOf(filter) >= 0;
|
|
||||||
chr.classList[isMatch ? 'remove' : 'add']('hidden');
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
window.addEventListener('scroll', function() {
|
|
||||||
var hidden = document.getElementsByClassName('js-hidden-on-scroll'),
|
|
||||||
invisible = document.getElementsByClassName('js-invisible-on-scroll'),
|
|
||||||
atTop = window.scrollY === 0;
|
|
||||||
|
|
||||||
for(var i = 0; i < hidden.length; ++i)
|
|
||||||
hidden[i].classList[atTop ? 'remove' : 'add']('hidden');
|
|
||||||
for(var i = 0; i < invisible.length; ++i)
|
|
||||||
invisible[i].classList[atTop ? 'remove' : 'add']('invisible');
|
|
||||||
});
|
|
||||||
search.addEventListener('keyup', function() {
|
|
||||||
location.hash = search.value.trim();
|
|
||||||
});
|
|
||||||
window.addEventListener('hashchange', function() {
|
|
||||||
charsFilter(decodeURIComponent((location.hash || '#').substring(1)));
|
|
||||||
});
|
|
||||||
if(location.hash.length > 0) {
|
|
||||||
search.value = location.hash.substring(1).trim();
|
|
||||||
charsFilter(search.value);
|
|
||||||
}
|
|
||||||
|
|
||||||
for(var i = 0; i < chars.length; ++i) {
|
|
||||||
chars[i].addEventListener('click', function(ev) {
|
|
||||||
var target = ev.target;
|
|
||||||
|
|
||||||
while(target !== null && typeof target.dataset.copy === 'undefined') {
|
|
||||||
target = target.parentNode || null;
|
|
||||||
|
|
||||||
if(target.classList.contains('char'))
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(target === null || typeof target.dataset.copy === 'undefined')
|
|
||||||
return;
|
|
||||||
|
|
||||||
// Clipboard interactions are fucking horrendous
|
|
||||||
/*if(document.execCommand) {
|
|
||||||
/*var clipfriend = document.createElement('input');
|
|
||||||
clipfriend.type = 'text';
|
|
||||||
clipfriend.value = target.dataset.copy;
|
|
||||||
clipfriend.className = 'hidden';
|
|
||||||
document.body.appendChild(clipfriend);
|
|
||||||
clipfriend.select();
|
|
||||||
clipfriend.setSelectionRange(0, clipfriend.value.length);
|
|
||||||
document.execCommand('copy');
|
|
||||||
document.body.removeChild(clipfriend);
|
|
||||||
} else {*/
|
|
||||||
var doCopy = function() { navigator.clipboard.writeText(target.dataset.copy); };
|
|
||||||
|
|
||||||
if(typeof window.mozInnerScreenX !== 'undefined')
|
|
||||||
doCopy();
|
|
||||||
else
|
|
||||||
navigator.permissions.query({name: 'clipboard-write'}).then(function(res) {
|
|
||||||
if(res.state === 'granted' || res.state === 'prompt')
|
|
||||||
doCopy();
|
|
||||||
});
|
|
||||||
//}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
<?php
|
|
||||||
});
|
|
|
@ -1,33 +0,0 @@
|
||||||
<?php
|
|
||||||
$self->extends('master');
|
|
||||||
|
|
||||||
$self->header_title = 'flash.moe / contact';
|
|
||||||
|
|
||||||
$self->block('container', function($self) {
|
|
||||||
?>
|
|
||||||
<div class="section">
|
|
||||||
<div class="section-content">
|
|
||||||
<div class="section-background"></div>
|
|
||||||
<h1>Contact</h1>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="socials">
|
|
||||||
<?php foreach($self->contacts as $contact): ?>
|
|
||||||
<div class="social social-<?=$contact->getName();?>" style="--social-colour: <?=$contact->getColourHex();?>">
|
|
||||||
|
|
||||||
<?php if($contact->hasLink()): ?>
|
|
||||||
<a href="<?=$contact->getLink();?>" class="social-background" target="_blank" rel="noopener"></a>
|
|
||||||
<?php else: ?>
|
|
||||||
<div class="social-background" onclick="fm.selectTextInElement(this.parentNode.querySelector('.social-handle')); fm.copySelectedText();"></div>
|
|
||||||
<?php endif; ?>
|
|
||||||
|
|
||||||
<div class="social-icon <?=$contact->getIcon();?>"></div>
|
|
||||||
<div class="social-content">
|
|
||||||
<div class="social-name"><?=$contact->getTitle();?></div>
|
|
||||||
<div class="social-handle"><?=$contact->getDisplay();?></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<?php endforeach; ?>
|
|
||||||
</div>
|
|
||||||
<?php
|
|
||||||
});
|
|
|
@ -1,5 +0,0 @@
|
||||||
<?php
|
|
||||||
$self->extends('errors/master');
|
|
||||||
|
|
||||||
$self->http_error_image = '/assets/errors/403.jpg';
|
|
||||||
$self->http_error_desc = 'You are not supposed to be here.';
|
|
|
@ -1,5 +0,0 @@
|
||||||
<?php
|
|
||||||
$self->extends('errors/master');
|
|
||||||
|
|
||||||
$self->http_error_image = '/assets/errors/404.jpg';
|
|
||||||
$self->http_error_desc = 'Whatever you\'re looking for is no longer here, or might not have been here in the first place.';
|
|
|
@ -1,5 +0,0 @@
|
||||||
<?php
|
|
||||||
$self->extends('errors/master');
|
|
||||||
|
|
||||||
$self->http_error_image = '/assets/errors/405.jpg';
|
|
||||||
$self->http_error_desc = 'You\'re up to something, aren\'t you?';
|
|
|
@ -1,14 +0,0 @@
|
||||||
<?php
|
|
||||||
$self->extends('master');
|
|
||||||
|
|
||||||
$self->block('container', function($self) {
|
|
||||||
?>
|
|
||||||
<div class="http-error">
|
|
||||||
<h2 class="http-error-head"><?=($self->http_error_title ?? ('Unknown Error #' . $self->http_error_code));?></h2>
|
|
||||||
<?php if(isset($self->http_error_image)): ?>
|
|
||||||
<img src="<?=$self->http_error_image;?>" alt="<?=$self->http_error_image;?>" class="http-error-image">
|
|
||||||
<?php endif; ?>
|
|
||||||
<div class="http-error-desc"><?=($self->http_error_desc ?? 'No additional information is available.');?></div>
|
|
||||||
</div>
|
|
||||||
<?php
|
|
||||||
});
|
|
|
@ -1,2 +0,0 @@
|
||||||
<?php
|
|
||||||
$self->extends('master');
|
|
|
@ -1,85 +0,0 @@
|
||||||
<?php
|
|
||||||
$self->extends('master');
|
|
||||||
|
|
||||||
$self->header_title = 'flash.moe';
|
|
||||||
$self->header_is_index = true;
|
|
||||||
$self->footer_onload = [['fm.initIndex']];
|
|
||||||
|
|
||||||
$self->block('container', function($self) {
|
|
||||||
?>
|
|
||||||
<div class="index-menu">
|
|
||||||
<?php for($i = 1; $i < count($self->header_nav); ++$i): $link = $self->header_nav[$i]; ?>
|
|
||||||
<a href="<?=$link['link'];?>"><?=$link['title'];?></a>
|
|
||||||
<?php endfor; ?>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="index-featured">
|
|
||||||
|
|
||||||
<div class="index-feature">
|
|
||||||
<div class="index-feature-header">
|
|
||||||
<a href="/projects" class="index-feature-header-link"></a>
|
|
||||||
<div class="index-feature-header-title">Projects</div>
|
|
||||||
<div class="index-feature-header-more">More</div>
|
|
||||||
</div>
|
|
||||||
<?php
|
|
||||||
foreach($self->projects as $project):
|
|
||||||
$links = [];
|
|
||||||
if($project->hasHomePageUrl())
|
|
||||||
$links[] = ['class' => 'homepage', 'text' => 'Homepage', 'url' => $project->getHomePageUrl()];
|
|
||||||
if($project->hasSourceUrl())
|
|
||||||
$links[] = ['class' => 'repository', 'text' => 'Source', 'url' => $project->getSourceUrl()];
|
|
||||||
if($project->hasDiscussionUrl())
|
|
||||||
$links[] = ['class' => 'forum', 'text' => 'Discussion', 'url' => $project->getDiscussionUrl()];
|
|
||||||
|
|
||||||
$colour = $project->hasColour() ? $project->getColour() : $self->languages->getProjectColour($project);
|
|
||||||
$colour = str_pad(dechex($colour), 6, '0', STR_PAD_LEFT);
|
|
||||||
?>
|
|
||||||
<div class="index-project" style="background-color: #<?=$colour;?>;">
|
|
||||||
<a href="/projects#<?=$project->getCleanName();?>" class="index-project-anchor"></a>
|
|
||||||
<div class="index-project-content">
|
|
||||||
<div class="index-project-name"><?=$project->getName();?></div>
|
|
||||||
<?php if($project->hasSummary()): ?>
|
|
||||||
<div class="index-project-summary"><?=$project->getSummary();?></div>
|
|
||||||
<?php endif; ?>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<?php if(!empty($links)): ?>
|
|
||||||
<div class="index-project-links">
|
|
||||||
<?php foreach($links as $link): ?>
|
|
||||||
<a class="index-project-link index-project-link-<?=$link['class'];?>" href="<?=$link['url'];?>" rel="noopener" target="_blank"><?=$link['text'];?></a>
|
|
||||||
<?php endforeach; ?>
|
|
||||||
</div>
|
|
||||||
<?php endif; ?>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
<?php endforeach; ?>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="index-feature">
|
|
||||||
<div class="index-feature-header">
|
|
||||||
<a href="/contact" class="index-feature-header-link"></a>
|
|
||||||
<div class="index-feature-header-title">Contact</div>
|
|
||||||
<div class="index-feature-header-more">More</div>
|
|
||||||
</div>
|
|
||||||
<div class="index-contact">
|
|
||||||
<?php foreach($self->contacts as $contact): ?>
|
|
||||||
<div class="social social-<?=$contact->getName();?>" style="--social-colour: <?=$contact->getColourHex();?>">
|
|
||||||
<?php if($contact->hasLink()): ?>
|
|
||||||
<a href="<?=$contact->getLink();?>" class="social-background" target="_blank" rel="noopener"></a>
|
|
||||||
<?php else: ?>
|
|
||||||
<div class="social-background" onclick="fm.selectTextInElement(this.parentNode.querySelector('.social-handle')); fm.copySelectedText();"></div>
|
|
||||||
<?php endif; ?>
|
|
||||||
|
|
||||||
<div class="social-icon <?=$contact->getIcon();?>"></div>
|
|
||||||
<div class="social-content">
|
|
||||||
<div class="social-name"><?=$contact->getTitle();?></div>
|
|
||||||
<div class="social-handle"><?=$contact->getDisplay();?></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<?php endforeach; ?>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
<?php
|
|
||||||
});
|
|
|
@ -1,7 +0,0 @@
|
||||||
<?php
|
|
||||||
$self->extends('master');
|
|
||||||
|
|
||||||
$self->header_title = 'flash.moe / now listening';
|
|
||||||
$self->header_full = true;
|
|
||||||
$self->header_now_playing = true;
|
|
||||||
$self->footer_onload = [['fm.initIndex', 10]];
|
|
|
@ -1,84 +0,0 @@
|
||||||
<?php
|
|
||||||
$self->extends('master');
|
|
||||||
|
|
||||||
$self->header_title = 'flash.moe / projects';
|
|
||||||
|
|
||||||
$self->block('container', function($self) {
|
|
||||||
?>
|
|
||||||
<?php foreach($self->sections as $sectionId => $section): ?>
|
|
||||||
<div class="section" id="section-<?=$sectionId;?>">
|
|
||||||
<div class="section-content">
|
|
||||||
<div class="section-background"></div>
|
|
||||||
<h1><?=$section['title'];?></h1>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<?php
|
|
||||||
foreach($section['items'] as $project):
|
|
||||||
$links = [];
|
|
||||||
if($project->hasHomePageUrl())
|
|
||||||
$links[] = ['class' => 'homepage', 'text' => 'Homepage', 'url' => $project->getHomePageUrl()];
|
|
||||||
if($project->hasSourceUrl())
|
|
||||||
$links[] = ['class' => 'repository', 'text' => 'Source', 'url' => $project->getSourceUrl()];
|
|
||||||
if($project->hasDiscussionUrl())
|
|
||||||
$links[] = ['class' => 'forum', 'text' => 'Discussion', 'url' => $project->getDiscussionUrl()];
|
|
||||||
|
|
||||||
$descLines = $project->hasDescription() ? $project->getDescription()->trim()->split("\n") : [];
|
|
||||||
|
|
||||||
$langs = $self->languages->getByProject($project);
|
|
||||||
|
|
||||||
if($project->hasColour())
|
|
||||||
$colour = $project->getColour();
|
|
||||||
else
|
|
||||||
foreach($langs as $lang)
|
|
||||||
if($lang->hasColour()) {
|
|
||||||
$colour = $lang->getColour();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
$colour = str_pad(dechex($colour), 6, '0', STR_PAD_LEFT);
|
|
||||||
?>
|
|
||||||
|
|
||||||
<div class="project project-type-<?=$sectionId;?>" id="<?=$project->getCleanName();?>" style="--project-colour: #<?=$colour;?>;">
|
|
||||||
<div class="project-content">
|
|
||||||
<div class="project-details">
|
|
||||||
<h2><?=$project->getName();?><div class="project-languages">
|
|
||||||
<?php
|
|
||||||
foreach($langs as $lang):
|
|
||||||
$langColour = str_pad(dechex($lang->getColour() ?? 0), 6, '0', STR_PAD_LEFT);
|
|
||||||
?>
|
|
||||||
<div class="project-language" style="--language-colour: #<?=$langColour;?>;"><?=$lang->getName();?></div>
|
|
||||||
<?php endforeach; ?>
|
|
||||||
</div></h2>
|
|
||||||
|
|
||||||
<?php if($project->hasSummary()): ?>
|
|
||||||
<p class="project-details-summary"><?=$project->getSummary();?></p>
|
|
||||||
<?php endif; ?>
|
|
||||||
|
|
||||||
<?php
|
|
||||||
foreach($descLines as $line):
|
|
||||||
$line = $line->trim();
|
|
||||||
if($line->isEmpty())
|
|
||||||
continue;
|
|
||||||
?>
|
|
||||||
<p><?=$line;?></p>
|
|
||||||
<?php endforeach; ?>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<?php if(!empty($links)): ?>
|
|
||||||
<div class="project-links">
|
|
||||||
|
|
||||||
<?php foreach($links as $link): ?>
|
|
||||||
<a class="project-link project-link-<?=$link['class'];?>" href="<?=$link['url'];?>" rel="noopener" target="_blank"><?=$link['text'];?></a>
|
|
||||||
<?php endforeach; ?>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
<?php endif; ?>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<?php endforeach; ?>
|
|
||||||
<?php endforeach; ?>
|
|
||||||
<?php
|
|
||||||
});
|
|
Loading…
Reference in a new issue