From 195ea5508b1495179b1b135f05c1e87d756fa19b Mon Sep 17 00:00:00 2001 From: eater <=@eater.me> Date: Wed, 20 May 2020 02:11:04 +0200 Subject: [PATCH] Initial commit --- .gitignore | 2 + composer.json | 23 + composer.lock | 982 +++++++++++++++++++++++++++++++ data/config.toml | 44 ++ data/pages/about.md | 9 + data/posts/blog-speedrun-anyp.md | 35 ++ public/css/main.css | 187 ++++++ public/index.php | 11 + src/Blog.php | 297 ++++++++++ views/base.html.twig | 44 ++ views/game.html.twig | 16 + views/games.html.twig | 17 + views/macros.html.twig | 35 ++ views/main.html.twig | 9 + views/page.html.twig | 12 + views/post.html.twig | 26 + views/rss.xml.twig | 18 + views/tag.html.twig | 11 + 18 files changed, 1778 insertions(+) create mode 100644 .gitignore create mode 100644 composer.json create mode 100644 composer.lock create mode 100644 data/config.toml create mode 100644 data/pages/about.md create mode 100644 data/posts/blog-speedrun-anyp.md create mode 100644 public/css/main.css create mode 100644 public/index.php create mode 100644 src/Blog.php create mode 100644 views/base.html.twig create mode 100644 views/game.html.twig create mode 100644 views/games.html.twig create mode 100644 views/macros.html.twig create mode 100644 views/main.html.twig create mode 100644 views/page.html.twig create mode 100644 views/post.html.twig create mode 100644 views/rss.xml.twig create mode 100644 views/tag.html.twig diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1011914 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +vendor +var/cache diff --git a/composer.json b/composer.json new file mode 100644 index 0000000..d85aab8 --- /dev/null +++ b/composer.json @@ -0,0 +1,23 @@ +{ + "name": "eater/blog-eater", + "type": "project", + "require": { + "slim/slim": "^4.1", + "slim/psr7": "^1.1", + "league/commonmark": "^1.4", + "yosymfony/toml": "^1.0", + "twig/twig": "^3.0", + "ext-json": "*" + }, + "authors": [ + { + "name": "eater", + "email": "=@eater.me" + } + ], + "autoload": { + "psr-4": { + "Eater\\": "src" + } + } +} diff --git a/composer.lock b/composer.lock new file mode 100644 index 0000000..a46486d --- /dev/null +++ b/composer.lock @@ -0,0 +1,982 @@ +{ + "_readme": [ + "This file locks the dependencies of your project to a known state", + "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", + "This file is @generated automatically" + ], + "content-hash": "cb1bcd865d190652150546ba6be7fcf6", + "packages": [ + { + "name": "fig/http-message-util", + "version": "1.1.4", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-message-util.git", + "reference": "3242caa9da7221a304b8f84eb9eaddae0a7cf422" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-message-util/zipball/3242caa9da7221a304b8f84eb9eaddae0a7cf422", + "reference": "3242caa9da7221a304b8f84eb9eaddae0a7cf422", + "shasum": "" + }, + "require": { + "php": "^5.3 || ^7.0" + }, + "suggest": { + "psr/http-message": "The package containing the PSR-7 interfaces" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Fig\\Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Utility classes and constants for use with PSR-7 (psr/http-message)", + "keywords": [ + "http", + "http-message", + "psr", + "psr-7", + "request", + "response" + ], + "time": "2020-02-05T20:36:27+00:00" + }, + { + "name": "league/commonmark", + "version": "1.4.3", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/commonmark.git", + "reference": "412639f7cfbc0b31ad2455b2fe965095f66ae505" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/commonmark/zipball/412639f7cfbc0b31ad2455b2fe965095f66ae505", + "reference": "412639f7cfbc0b31ad2455b2fe965095f66ae505", + "shasum": "" + }, + "require": { + "ext-mbstring": "*", + "php": "^7.1" + }, + "conflict": { + "scrutinizer/ocular": "1.7.*" + }, + "require-dev": { + "cebe/markdown": "~1.0", + "commonmark/commonmark.js": "0.29.1", + "erusev/parsedown": "~1.0", + "ext-json": "*", + "github/gfm": "0.29.0", + "michelf/php-markdown": "~1.4", + "mikehaertl/php-shellcommand": "^1.4", + "phpstan/phpstan": "^0.12", + "phpunit/phpunit": "^7.5", + "scrutinizer/ocular": "^1.5", + "symfony/finder": "^4.2" + }, + "bin": [ + "bin/commonmark" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.4-dev" + } + }, + "autoload": { + "psr-4": { + "League\\CommonMark\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Colin O'Dell", + "email": "colinodell@gmail.com", + "homepage": "https://www.colinodell.com", + "role": "Lead Developer" + } + ], + "description": "Highly-extensible PHP Markdown parser which fully supports the CommonMark spec and Github-Flavored Markdown (GFM)", + "homepage": "https://commonmark.thephpleague.com", + "keywords": [ + "commonmark", + "flavored", + "gfm", + "github", + "github-flavored", + "markdown", + "md", + "parser" + ], + "time": "2020-05-04T22:15:21+00:00" + }, + { + "name": "nikic/fast-route", + "version": "v1.3.0", + "source": { + "type": "git", + "url": "https://github.com/nikic/FastRoute.git", + "reference": "181d480e08d9476e61381e04a71b34dc0432e812" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nikic/FastRoute/zipball/181d480e08d9476e61381e04a71b34dc0432e812", + "reference": "181d480e08d9476e61381e04a71b34dc0432e812", + "shasum": "" + }, + "require": { + "php": ">=5.4.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.8.35|~5.7" + }, + "type": "library", + "autoload": { + "psr-4": { + "FastRoute\\": "src/" + }, + "files": [ + "src/functions.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Nikita Popov", + "email": "nikic@php.net" + } + ], + "description": "Fast request router for PHP", + "keywords": [ + "router", + "routing" + ], + "time": "2018-02-13T20:26:39+00:00" + }, + { + "name": "psr/container", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/container.git", + "reference": "b7ce3b176482dbbc1245ebf52b181af44c2cf55f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/container/zipball/b7ce3b176482dbbc1245ebf52b181af44c2cf55f", + "reference": "b7ce3b176482dbbc1245ebf52b181af44c2cf55f", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Container\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common Container Interface (PHP FIG PSR-11)", + "homepage": "https://github.com/php-fig/container", + "keywords": [ + "PSR-11", + "container", + "container-interface", + "container-interop", + "psr" + ], + "time": "2017-02-14T16:28:37+00:00" + }, + { + "name": "psr/http-factory", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-factory.git", + "reference": "12ac7fcd07e5b077433f5f2bee95b3a771bf61be" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-factory/zipball/12ac7fcd07e5b077433f5f2bee95b3a771bf61be", + "reference": "12ac7fcd07e5b077433f5f2bee95b3a771bf61be", + "shasum": "" + }, + "require": { + "php": ">=7.0.0", + "psr/http-message": "^1.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interfaces for PSR-7 HTTP message factories", + "keywords": [ + "factory", + "http", + "message", + "psr", + "psr-17", + "psr-7", + "request", + "response" + ], + "time": "2019-04-30T12:38:16+00:00" + }, + { + "name": "psr/http-message", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-message.git", + "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-message/zipball/f6561bf28d520154e4b0ec72be95418abe6d9363", + "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interface for HTTP messages", + "homepage": "https://github.com/php-fig/http-message", + "keywords": [ + "http", + "http-message", + "psr", + "psr-7", + "request", + "response" + ], + "time": "2016-08-06T14:39:51+00:00" + }, + { + "name": "psr/http-server-handler", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-server-handler.git", + "reference": "aff2f80e33b7f026ec96bb42f63242dc50ffcae7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-server-handler/zipball/aff2f80e33b7f026ec96bb42f63242dc50ffcae7", + "reference": "aff2f80e33b7f026ec96bb42f63242dc50ffcae7", + "shasum": "" + }, + "require": { + "php": ">=7.0", + "psr/http-message": "^1.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Server\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interface for HTTP server-side request handler", + "keywords": [ + "handler", + "http", + "http-interop", + "psr", + "psr-15", + "psr-7", + "request", + "response", + "server" + ], + "time": "2018-10-30T16:46:14+00:00" + }, + { + "name": "psr/http-server-middleware", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-server-middleware.git", + "reference": "2296f45510945530b9dceb8bcedb5cb84d40c5f5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-server-middleware/zipball/2296f45510945530b9dceb8bcedb5cb84d40c5f5", + "reference": "2296f45510945530b9dceb8bcedb5cb84d40c5f5", + "shasum": "" + }, + "require": { + "php": ">=7.0", + "psr/http-message": "^1.0", + "psr/http-server-handler": "^1.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Server\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interface for HTTP server-side middleware", + "keywords": [ + "http", + "http-interop", + "middleware", + "psr", + "psr-15", + "psr-7", + "request", + "response" + ], + "time": "2018-10-30T17:12:04+00:00" + }, + { + "name": "psr/log", + "version": "1.1.3", + "source": { + "type": "git", + "url": "https://github.com/php-fig/log.git", + "reference": "0f73288fd15629204f9d42b7055f72dacbe811fc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/log/zipball/0f73288fd15629204f9d42b7055f72dacbe811fc", + "reference": "0f73288fd15629204f9d42b7055f72dacbe811fc", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Log\\": "Psr/Log/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interface for logging libraries", + "homepage": "https://github.com/php-fig/log", + "keywords": [ + "log", + "psr", + "psr-3" + ], + "time": "2020-03-23T09:12:05+00:00" + }, + { + "name": "ralouphie/getallheaders", + "version": "3.0.3", + "source": { + "type": "git", + "url": "https://github.com/ralouphie/getallheaders.git", + "reference": "120b605dfeb996808c31b6477290a714d356e822" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ralouphie/getallheaders/zipball/120b605dfeb996808c31b6477290a714d356e822", + "reference": "120b605dfeb996808c31b6477290a714d356e822", + "shasum": "" + }, + "require": { + "php": ">=5.6" + }, + "require-dev": { + "php-coveralls/php-coveralls": "^2.1", + "phpunit/phpunit": "^5 || ^6.5" + }, + "type": "library", + "autoload": { + "files": [ + "src/getallheaders.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ralph Khattar", + "email": "ralph.khattar@gmail.com" + } + ], + "description": "A polyfill for getallheaders.", + "time": "2019-03-08T08:55:37+00:00" + }, + { + "name": "slim/psr7", + "version": "1.1.0", + "source": { + "type": "git", + "url": "https://github.com/slimphp/Slim-Psr7.git", + "reference": "3c76899e707910779f13d7af95fde12310b0a5ae" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/slimphp/Slim-Psr7/zipball/3c76899e707910779f13d7af95fde12310b0a5ae", + "reference": "3c76899e707910779f13d7af95fde12310b0a5ae", + "shasum": "" + }, + "require": { + "fig/http-message-util": "^1.1.2", + "php": "^7.2", + "psr/http-factory": "^1.0", + "psr/http-message": "^1.0", + "ralouphie/getallheaders": "^3" + }, + "provide": { + "psr/http-message-implementation": "1.0" + }, + "require-dev": { + "adriansuter/php-autoload-override": "^1.0", + "ext-json": "*", + "http-interop/http-factory-tests": "^0.6.0", + "php-http/psr7-integration-tests": "dev-master", + "phpstan/phpstan": "^0.12", + "phpunit/phpunit": "^8.5", + "squizlabs/php_codesniffer": "^3.5" + }, + "type": "library", + "autoload": { + "psr-4": { + "Slim\\Psr7\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Josh Lockhart", + "email": "hello@joshlockhart.com", + "homepage": "http://joshlockhart.com" + }, + { + "name": "Andrew Smith", + "email": "a.smith@silentworks.co.uk", + "homepage": "http://silentworks.co.uk" + }, + { + "name": "Rob Allen", + "email": "rob@akrabat.com", + "homepage": "http://akrabat.com" + }, + { + "name": "Pierre Berube", + "email": "pierre@lgse.com", + "homepage": "http://www.lgse.com" + } + ], + "description": "Strict PSR-7 implementation", + "homepage": "https://www.slimframework.com", + "keywords": [ + "http", + "psr-7", + "psr7" + ], + "time": "2020-05-01T14:24:20+00:00" + }, + { + "name": "slim/slim", + "version": "4.5.0", + "source": { + "type": "git", + "url": "https://github.com/slimphp/Slim.git", + "reference": "5613cbb521081ed676d5d7eb3e44f2b80a818c24" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/slimphp/Slim/zipball/5613cbb521081ed676d5d7eb3e44f2b80a818c24", + "reference": "5613cbb521081ed676d5d7eb3e44f2b80a818c24", + "shasum": "" + }, + "require": { + "ext-json": "*", + "nikic/fast-route": "^1.3", + "php": "^7.2", + "psr/container": "^1.0", + "psr/http-factory": "^1.0", + "psr/http-message": "^1.0", + "psr/http-server-handler": "^1.0", + "psr/http-server-middleware": "^1.0", + "psr/log": "^1.1" + }, + "require-dev": { + "adriansuter/php-autoload-override": "^1.0", + "ext-simplexml": "*", + "guzzlehttp/psr7": "^1.5", + "http-interop/http-factory-guzzle": "^1.0", + "laminas/laminas-diactoros": "^2.1", + "nyholm/psr7": "^1.1", + "nyholm/psr7-server": "^0.3.0", + "phpspec/prophecy": "^1.10", + "phpstan/phpstan": "^0.11.5", + "phpunit/phpunit": "^8.5", + "slim/http": "^1.0", + "slim/psr7": "^1.0", + "squizlabs/php_codesniffer": "^3.5" + }, + "suggest": { + "ext-simplexml": "Needed to support XML format in BodyParsingMiddleware", + "ext-xml": "Needed to support XML format in BodyParsingMiddleware", + "php-di/php-di": "PHP-DI is the recommended container library to be used with Slim", + "slim/psr7": "Slim PSR-7 implementation. See https://www.slimframework.com/docs/v4/start/installation.html for more information." + }, + "type": "library", + "autoload": { + "psr-4": { + "Slim\\": "Slim" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Josh Lockhart", + "email": "hello@joshlockhart.com", + "homepage": "https://joshlockhart.com" + }, + { + "name": "Andrew Smith", + "email": "a.smith@silentworks.co.uk", + "homepage": "http://silentworks.co.uk" + }, + { + "name": "Rob Allen", + "email": "rob@akrabat.com", + "homepage": "http://akrabat.com" + }, + { + "name": "Pierre Berube", + "email": "pierre@lgse.com", + "homepage": "http://www.lgse.com" + }, + { + "name": "Gabriel Manricks", + "email": "gmanricks@me.com", + "homepage": "http://gabrielmanricks.com" + } + ], + "description": "Slim is a PHP micro framework that helps you quickly write simple yet powerful web applications and APIs", + "homepage": "https://www.slimframework.com", + "keywords": [ + "api", + "framework", + "micro", + "router" + ], + "time": "2020-04-14T20:49:48+00:00" + }, + { + "name": "symfony/polyfill-ctype", + "version": "v1.17.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-ctype.git", + "reference": "e94c8b1bbe2bc77507a1056cdb06451c75b427f9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/e94c8b1bbe2bc77507a1056cdb06451c75b427f9", + "reference": "e94c8b1bbe2bc77507a1056cdb06451c75b427f9", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "suggest": { + "ext-ctype": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.17-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Ctype\\": "" + }, + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Gert de Pagter", + "email": "BackEndTea@gmail.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for ctype functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "ctype", + "polyfill", + "portable" + ], + "time": "2020-05-12T16:14:59+00:00" + }, + { + "name": "symfony/polyfill-mbstring", + "version": "v1.17.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-mbstring.git", + "reference": "fa79b11539418b02fc5e1897267673ba2c19419c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/fa79b11539418b02fc5e1897267673ba2c19419c", + "reference": "fa79b11539418b02fc5e1897267673ba2c19419c", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "suggest": { + "ext-mbstring": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.17-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Mbstring\\": "" + }, + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for the Mbstring extension", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "mbstring", + "polyfill", + "portable", + "shim" + ], + "time": "2020-05-12T16:47:27+00:00" + }, + { + "name": "twig/twig", + "version": "v3.0.3", + "source": { + "type": "git", + "url": "https://github.com/twigphp/Twig.git", + "reference": "3b88ccd180a6b61ebb517aea3b1a8906762a1dc2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/twigphp/Twig/zipball/3b88ccd180a6b61ebb517aea3b1a8906762a1dc2", + "reference": "3b88ccd180a6b61ebb517aea3b1a8906762a1dc2", + "shasum": "" + }, + "require": { + "php": "^7.2.5", + "symfony/polyfill-ctype": "^1.8", + "symfony/polyfill-mbstring": "^1.3" + }, + "require-dev": { + "psr/container": "^1.0", + "symfony/phpunit-bridge": "^4.4|^5.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0-dev" + } + }, + "autoload": { + "psr-4": { + "Twig\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com", + "homepage": "http://fabien.potencier.org", + "role": "Lead Developer" + }, + { + "name": "Twig Team", + "role": "Contributors" + }, + { + "name": "Armin Ronacher", + "email": "armin.ronacher@active-4.com", + "role": "Project Founder" + } + ], + "description": "Twig, the flexible, fast, and secure template language for PHP", + "homepage": "https://twig.symfony.com", + "keywords": [ + "templating" + ], + "time": "2020-02-11T15:33:47+00:00" + }, + { + "name": "yosymfony/parser-utils", + "version": "v2.0.0", + "source": { + "type": "git", + "url": "https://github.com/yosymfony/parser-utils.git", + "reference": "00bec9a12722b21f2baf7f9db35f127e90c162c9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/yosymfony/parser-utils/zipball/00bec9a12722b21f2baf7f9db35f127e90c162c9", + "reference": "00bec9a12722b21f2baf7f9db35f127e90c162c9", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "require-dev": { + "phpunit/phpunit": "^6" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0-dev" + } + }, + "autoload": { + "psr-4": { + "Yosymfony\\ParserUtils\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Victor Puertas", + "email": "vpgugr@gmail.com", + "homepage": "http://yosymfony.com" + } + ], + "description": "Parser utilities", + "homepage": "http://github.com/yosymfony/toml", + "keywords": [ + "lexer", + "parser" + ], + "time": "2018-06-29T15:31:11+00:00" + }, + { + "name": "yosymfony/toml", + "version": "v1.0.4", + "source": { + "type": "git", + "url": "https://github.com/yosymfony/toml.git", + "reference": "bdab92ad920d0e36810a3a3e4a998d23f3498f8e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/yosymfony/toml/zipball/bdab92ad920d0e36810a3a3e4a998d23f3498f8e", + "reference": "bdab92ad920d0e36810a3a3e4a998d23f3498f8e", + "shasum": "" + }, + "require": { + "php": ">=7.1", + "yosymfony/parser-utils": "^2.0" + }, + "require-dev": { + "phpunit/phpunit": "^7.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "autoload": { + "psr-4": { + "Yosymfony\\Toml\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Victor Puertas", + "email": "vpgugr@gmail.com", + "homepage": "http://yosymfony.com" + } + ], + "description": "A PHP parser for TOML compatible with specification 0.4.0", + "homepage": "http://github.com/yosymfony/toml", + "keywords": [ + "mojombo", + "parser", + "toml" + ], + "time": "2018-08-08T15:08:14+00:00" + } + ], + "packages-dev": [], + "aliases": [], + "minimum-stability": "stable", + "stability-flags": [], + "prefer-stable": false, + "prefer-lowest": false, + "platform": [], + "platform-dev": [] +} diff --git a/data/config.toml b/data/config.toml new file mode 100644 index 0000000..841b6dc --- /dev/null +++ b/data/config.toml @@ -0,0 +1,44 @@ +[blog] +title = "eater" +description = "it's normal i swear" +link = "https://blog.eater.me/" + +[[nav]] +name = "Posts" +link = "/" +before = true + +[[nav]] +type = "divider" +before = true + +# pages + +[[nav]] +type = "divider" + +[[nav]] +name = "Games" +link = "/games" + +[[nav]] +type = "divider" + +[[nav]] +name = "Monster" +link = "/tag/monster" + +[[nav]] +name = "Eroge" +link = "/tag/eroge" + +[[nav]] +name = "VR" +link = "/tag/VR" + +[[nav]] +type = "divider" + +[[nav]] +name = "RSS" +link = "/rss.xml" \ No newline at end of file diff --git a/data/pages/about.md b/data/pages/about.md new file mode 100644 index 0000000..4ef4ad5 --- /dev/null +++ b/data/pages/about.md @@ -0,0 +1,9 @@ +title = "About" +--- +Hey, I am eater + + +and I write blog posts + + +[Twitter](https://twitter.com/__eater__) \ No newline at end of file diff --git a/data/posts/blog-speedrun-anyp.md b/data/posts/blog-speedrun-anyp.md new file mode 100644 index 0000000..e8cc050 --- /dev/null +++ b/data/posts/blog-speedrun-anyp.md @@ -0,0 +1,35 @@ +title = "Blog speedrun any%" +description = "Writing a blog in like 4 hours" +date = 2020-05-19T23:11:00Z +tags = ["dev"] +--- +This is it, this is the start. + +My very own blog, with blog software written by myself, because of course I want features that's not in any other software. + +This whole blog is a single PHP class (300 lines of code!), which reads a `config.toml`, `games/*.md`, `posts/*.md`, and `pages/*.md` +and builds the whole "database" of this blog in-memory. and this all in _\*checks notes\*_ 22ms. + +Of course this won't scale, so for that reason I have added "cache", if no `listing.json` is found, +it will write this whole in-memory database to disk in JSON, and when it exists it will use this +instead of reading all markdown files. + +The markdown files are split in 2 parts, split by `---`, the top part contains the metadata in toml, +and the bottom part is Just Markdown™, see the following example: + +```markdown +title = "Lorem ipsum" +description = "I know about 2 latin" +date = 1997-02-01T13:37:00 +tags = ["latin", "why"] +--- +Hey click [here](https://blog.eater.me/) +``` + +Outside that, all pages are rendered in Twig, because twig is nice. + +Well, see ya soon for as [Turtle](https://twitter.com/Threetle) coined it, *eater's Ero Evaluations* aka, *E3*. + +Also might review all the monster I bought, idk. just see this as me tweeting, but it's way over the 280 character limit. + +All the source, including the blog posts, are available at: [git.cijber.net/eater/blog](https://git.cijber.net/eater/blog) \ No newline at end of file diff --git a/public/css/main.css b/public/css/main.css new file mode 100644 index 0000000..c6dd8e9 --- /dev/null +++ b/public/css/main.css @@ -0,0 +1,187 @@ +:root { + --color: #F5EDF0; + --background: #424C55; + --accent: #886F68; + --max-width: 800px; +} + +* { + box-sizing: border-box; +} + +html, body { + padding: 0; + margin: 0; + min-height: 100%; + font-family: sans-serif; + background-color: var(--background); + color: var(--color); + font-weight: 100; +} + +a { + color: var(--color); +} + +a:hover { + text-decoration: underline var(--accent) !important; +} + +* { + margin: 0; + padding: 0; +} + +header { + padding-top: 1em; +} + +header > .title { + max-width: var(--max-width); + margin: 0 auto; +} + + +header > .title > h1 { + display: inline-block; + font-weight: 100; + margin-left: 1rem; + margin-bottom: 1rem; +} + +header > .title > span { + vertical-align: bottom; + text-align: left; + display: inline-block; + margin-bottom: 1rem; +} + +header > nav { + width: 100%; + background-color: var(--color); + +} + +header > nav > ul { + list-style: none; + padding: 0; + max-width: var(--max-width); + margin: 0 auto; +} + +header > nav > ul > li:first-child { + margin-left: -.5em; +} + +header > nav > ul > li { + margin: 0; + display: inline-block; + color: var(--background); +} + + +header > nav > ul > li.divider + li { + border-left: 1px solid var(--accent); +} + +header > nav > ul > li > a { + color: var(--background); + text-decoration: none; + display: inline-block; + padding: .5em; +} + +header > nav > ul > li:hover, +header > nav > ul > li a:hover { + color: var(--color); + background-color: var(--accent); +} + +main { + max-width: var(--max-width); + margin: 0 auto; + padding-top: 1em; +} + +.meta { + font-size: 0.9em; + padding: 0.5em 0; +} + +.post-listing { + margin-bottom: 1em; +} + +.post-listing .title a { + text-decoration: none; +} + +.meta .tag { + border-left: 1px var(--color) solid; + padding: 0 0.4em; +} + +@media (max-width: 799px) { + main { + margin: 0 1rem; + } + + header > nav > ul > li:first-child { + margin-left: 0.5rem; + } +} + +iframe { + width: 100%; + height: 200px; + border: none; +} + +iframe.itch-widget { + height: 175px; +} + +.content { + margin: 1em 0; +} + +.content pre { + margin: 1em 0; +} + +.tag-title { + margin-bottom: 1rem; + font-size: 2em; +} + +main > h2, hr { + margin-bottom: .5em; +} + +.post-game { + margin-top: 1em; +} + +.post-game > h4 { + margin-bottom: 0.5em; +} + +.game-listing { + display: flex; + align-items: center; + margin-bottom: 1em; +} + +.game-listing > *:nth-child(2) { + margin-left: 1em; +} + +@media (min-width: 800px) { + header > .title > h1 { + margin-left: 0; + } +} + +p { + margin: inherit; +} \ No newline at end of file diff --git a/public/index.php b/public/index.php new file mode 100644 index 0000000..920a365 --- /dev/null +++ b/public/index.php @@ -0,0 +1,11 @@ +run(); \ No newline at end of file diff --git a/src/Blog.php b/src/Blog.php new file mode 100644 index 0000000..1580f34 --- /dev/null +++ b/src/Blog.php @@ -0,0 +1,297 @@ +app = AppFactory::create(); + $this->twig = new Environment( + new FilesystemLoader([__DIR__."/../views"]), [ + 'cache' => __DIR__."/../var/cache/twig", + 'debug' => $this->debug, + ] + ); + + $this->routes(); + $this->makeListing(); + } + + public function run() + { + $this->app->run(); + } + + public function routes() + { + $app = $this->app; + $app->get( + '/', + function (Request $request, Response $response, $args) { + $response->getBody()->write( + $this->twig->render( + "main.html.twig", + $this->context() + ) + ); + + return $response; + } + ); + + $app->get( + '/tag/{tag}', + function (Request $request, Response $response, $args) { + $tag = $args['tag']; + $posts = array_filter( + $this->posts, + function ($post) use ($tag) { + return in_array($tag, $post['meta']['tags'] ?: []); + } + ); + + $response->getBody()->write( + $this->twig->render( + "tag.html.twig", + $this->context( + [ + 'tag' => $tag, + 'posts' => $posts, + ] + ) + ) + ); + + return $response; + } + ); + + $app->get( + '/game/{game}', + function (Request $request, Response $response, $args) { + $game = $this->games[$args['game']] ?? false; + if ( ! $game) { + return $response->withStatus(404); + } + + $posts = array_filter( + $this->posts, + function ($post) use ($game) { + return in_array($game['slug'], $post['meta']['games'] ?: []); + } + ); + + $response->getBody()->write( + $this->twig->render( + "game.html.twig", + $this->context( + [ + 'posts' => $posts, + 'game' => $game, + 'game_body' => $this->parseMarkdown($game['markdown']), + ] + ) + ) + ); + + return $response; + } + ); + + $app->get( + '/post/{post}', + function (Request $request, Response $response, $args) { + $post = $this->posts[$args['post']] ?? false; + if ( ! $post) { + return $response->withStatus(404); + } + + $response->getBody()->write( + $this->twig->render( + "post.html.twig", + $this->context( + [ + 'post' => $post, + 'post_body' => $this->parseMarkdown($post['markdown']), + ] + ) + ) + ); + + return $response; + } + ); + + $app->get( + '/rss.xml', + function (Request $request, Response $response) { + $response->getBody()->write( + $this->twig->render( + "rss.xml.twig", + $this->context() + ) + ); + + return $response->withHeader("Content-Type", "application/rss+xml"); + } + ); + + $app->get( + '/games', + function (Request $request, Response $response) { + $response->getBody()->write( + $this->twig->render( + "games.html.twig", + $this->context() + ) + ); + + return $response; + } + ); + + $app->get( + '/{page}', + function (Request $request, Response $response, $args) { + $page = $this->pages[$args['page']] ?? false; + if ( ! $page) { + return $response->withStatus(404); + } + + $response->getBody()->write( + $this->twig->render( + "page.html.twig", + $this->context( + [ + 'page' => $page, + 'page_body' => $this->parseMarkdown($page['markdown']), + ] + ) + ) + ); + + return $response; + } + ); + } + + private function context($context = []) + { + return array_merge( + [ + 'pages' => $this->pages, + 'posts' => $this->posts, + 'config' => $this->config, + 'games' => $this->games, + 'tags' => $this->tags, + ], + $context + ); + } + + private function parseObjects($path, $registerTags = false) + { + $objectBase = realpath($path); + $objects = glob($objectBase."/*.md"); + + $objectsColl = []; + foreach ($objects as $object) { + $objectSource = file_get_contents($object); + $parts = explode('---', $objectSource, 2); + if (count($parts) !== 2) { + continue; + } + + $meta = Toml::parse($parts[0]); + $md = $parts[1]; + + $slug = ltrim(substr($object, strlen($objectBase)), '/'); + $objectsColl[$slug] = [ + "markdown" => $md, + "meta" => $meta, + "slug" => $slug, + ]; + + if ($registerTags) { + $this->tags = array_merge($meta['tags'] ?: [], $this->tags); + } + } + + return $objectsColl; + } + + private function makeListing() + { + $cacheFile = __DIR__."/../var/cache/listing.json"; + if (file_exists($cacheFile) && ! $this->debug) { + $data = json_decode(file_get_contents($cacheFile), true); + + $this->posts = $data['posts']; + $this->pages = $data['pages']; + $this->tags = $data['tags']; + $this->config = $data['config']; + $this->games = $data['games']; + + foreach ($this->posts as &$post) { + if (isset($post['meta']['date'])) { + $post['meta']['date'] = new DateTime($post['meta']['date']['date']); + } + } + + return; + } + + $this->posts = $this->parseObjects(__DIR__."/../data/posts", true); + $this->pages = $this->parseObjects(__DIR__."/../data/pages"); + $this->games = $this->parseObjects(__DIR__."/../data/games"); + + $this->config = Toml::parse(file_get_contents(__DIR__."/../data/config.toml")); + $this->tags = array_unique($this->tags); + + $cacheDir = __DIR__."/../var/cache/"; + if ( ! is_dir($cacheDir)) { + mkdir($cacheDir, 0777, true); + } + + file_put_contents( + __DIR__."/../var/cache/listing.json", + json_encode( + [ + "pages" => $this->pages, + "posts" => $this->posts, + "tags" => $this->tags, + "games" => $this->games, + "config" => $this->config, + ] + ) + ); + } + + private function parseMarkdown($markdown) + { + $converter = new CommonMarkConverter(); + + return $converter->convertToHtml($markdown); + } +} \ No newline at end of file diff --git a/views/base.html.twig b/views/base.html.twig new file mode 100644 index 0000000..c1b4856 --- /dev/null +++ b/views/base.html.twig @@ -0,0 +1,44 @@ + + + + + + + + {% block title %}{{ config.blog.title }}{% endblock %} + + +
+
+

{{ config.blog.title }}

+ {{ config.blog.description }} +
+ +
+
+ {% block body %}{% endblock %} +
+ + + \ No newline at end of file diff --git a/views/game.html.twig b/views/game.html.twig new file mode 100644 index 0000000..4df8043 --- /dev/null +++ b/views/game.html.twig @@ -0,0 +1,16 @@ +{% extends "base.html.twig" %} +{% import "macros.html.twig" as macros %} +{% block title %}{{ parent() }} — game: {{ game.meta.title }}{% endblock %} + +{% block body %} +

{{ game.meta.title }}

+
+ {{ game_body|raw }} +
+
+ {{ macros.embed(game) }} +
+ {% for post in posts %} + {{ macros.post_listing(post) }} + {% endfor %} +{% endblock %} \ No newline at end of file diff --git a/views/games.html.twig b/views/games.html.twig new file mode 100644 index 0000000..e7c0334 --- /dev/null +++ b/views/games.html.twig @@ -0,0 +1,17 @@ +{% extends "base.html.twig" %} +{% import "macros.html.twig" as macros %} +{% block title %}{{ parent() }} — games{% endblock %} + +{% block body %} +

games

+ {% for game in games %} + + {% if game.meta.icon %} + + {% elseif game.meta.steam %} + + {% endif %} +

{{ game.meta.title }}

+
+ {% endfor %} +{% endblock %} \ No newline at end of file diff --git a/views/macros.html.twig b/views/macros.html.twig new file mode 100644 index 0000000..9d642c0 --- /dev/null +++ b/views/macros.html.twig @@ -0,0 +1,35 @@ +{% macro post_listing(post) %} +
+

{{ post.meta.title }}

+ {{ _self.meta(post) }} +
{{ post.meta.description }}
+
+{% endmacro %} + +{% macro meta(post) -%} +
+ {{ post.meta.date.format("Y-m-d") }} + + {% for tag in post.meta.tags -%} + {{ tag }} + {%- endfor %} + +
+{%- endmacro %} + +{% macro embed(game) %} + {% if game.meta.steam %} + {{ _self.steamwidget(game.meta.steam) }} + {% endif %} + {% if game.meta.itch %} + {{ _self.itchwidget(game.meta.itch) }} + {% endif %} +{% endmacro %} + +{% macro steamwidget(steam_id) %} + +{% endmacro %} + +{% macro itchwidget(itch_id) %} + +{% endmacro %} \ No newline at end of file diff --git a/views/main.html.twig b/views/main.html.twig new file mode 100644 index 0000000..5e949ee --- /dev/null +++ b/views/main.html.twig @@ -0,0 +1,9 @@ +{% extends "base.html.twig" %} +{% import "macros.html.twig" as macros %} + + +{% block body %} + {% for post in posts %} + {{ macros.post_listing(post) }} + {% endfor %} +{% endblock %} \ No newline at end of file diff --git a/views/page.html.twig b/views/page.html.twig new file mode 100644 index 0000000..a9c6463 --- /dev/null +++ b/views/page.html.twig @@ -0,0 +1,12 @@ +{% extends "base.html.twig" %} + +{% block title %}{{ parent() }} — {{ page.meta.title }}{% endblock %} + +{% block body %} +
+

{{ page.meta.title }}

+
+ {{ page_body|raw }} +
+
+{% endblock %} \ No newline at end of file diff --git a/views/post.html.twig b/views/post.html.twig new file mode 100644 index 0000000..f5c7fb3 --- /dev/null +++ b/views/post.html.twig @@ -0,0 +1,26 @@ +{% extends "base.html.twig" %} +{% import "macros.html.twig" as macros %} + +{% block title %}{{ parent() }} — {{ post.meta.title }}{% endblock %} + +{% block body %} + +

{{ post.meta.title }}

+ {{ macros.meta(post) }} + +
+ {{ post_body|raw }} +
+ {% if post.meta.games %} + {% set games = post.meta.games|filter(g => games[g])|map(g => games[g]) %} + {% if games|length > 0 %} +

games

+ {% for game in games %} +
+

{{ game.meta.title }}

+ {{ macros.embed(game) }} +
+ {% endfor %} + {% endif %} + {% endif %} +{% endblock %} \ No newline at end of file diff --git a/views/rss.xml.twig b/views/rss.xml.twig new file mode 100644 index 0000000..0e3f9a7 --- /dev/null +++ b/views/rss.xml.twig @@ -0,0 +1,18 @@ + + + + {{ config.blog.title }} + {{ config.blog.description }} + {{ config.blog.link }} + 1800 + {% for post in posts %} + + {{ post.meta.title }} + {{ post.meta.description }} + {{ config.blog.link }}/post/{{ post.slug }} + {{ post.slug }} + {{ post.meta.date.format('r') }} + + {% endfor %} + + diff --git a/views/tag.html.twig b/views/tag.html.twig new file mode 100644 index 0000000..18c3fff --- /dev/null +++ b/views/tag.html.twig @@ -0,0 +1,11 @@ +{% extends "base.html.twig" %} +{% import "macros.html.twig" as macros %} + +{% block title %}{{ parent() }} — tag: {{ tag }}{% endblock %} + +{% block body %} +

tag: {{ tag }}

+ {% for post in posts %} + {{ macros.post_listing(post) }} + {% endfor %} +{% endblock %} \ No newline at end of file