add 'adding content' chapter

This commit is contained in:
lubiana 2022-04-05 19:09:40 +02:00 committed by Andre Lubian
parent ab3227b75f
commit eb20213b94
20 changed files with 884 additions and 251 deletions

View file

@ -13,7 +13,8 @@
"middlewares/whoops": "^2.0",
"erusev/parsedown": "^1.7",
"symfony/cache": "^6.0",
"doctrine/orm": "^2.11"
"doctrine/orm": "^2.11",
"league/commonmark": "^2.2"
},
"autoload": {
"psr-4": {

460
app/composer.lock generated
View file

@ -4,8 +4,83 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "a3762dd11bab0c9e948d3a73b7f252b9",
"content-hash": "1e8469bfebe6479a139b946b8aba49de",
"packages": [
{
"name": "dflydev/dot-access-data",
"version": "v3.0.1",
"source": {
"type": "git",
"url": "https://github.com/dflydev/dflydev-dot-access-data.git",
"reference": "0992cc19268b259a39e86f296da5f0677841f42c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/dflydev/dflydev-dot-access-data/zipball/0992cc19268b259a39e86f296da5f0677841f42c",
"reference": "0992cc19268b259a39e86f296da5f0677841f42c",
"shasum": ""
},
"require": {
"php": "^7.1 || ^8.0"
},
"require-dev": {
"phpstan/phpstan": "^0.12.42",
"phpunit/phpunit": "^7.5 || ^8.5 || ^9.3",
"scrutinizer/ocular": "1.6.0",
"squizlabs/php_codesniffer": "^3.5",
"vimeo/psalm": "^3.14"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "3.x-dev"
}
},
"autoload": {
"psr-4": {
"Dflydev\\DotAccessData\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Dragonfly Development Inc.",
"email": "info@dflydev.com",
"homepage": "http://dflydev.com"
},
{
"name": "Beau Simensen",
"email": "beau@dflydev.com",
"homepage": "http://beausimensen.com"
},
{
"name": "Carlos Frutos",
"email": "carlos@kiwing.it",
"homepage": "https://github.com/cfrutos"
},
{
"name": "Colin O'Dell",
"email": "colinodell@gmail.com",
"homepage": "https://www.colinodell.com"
}
],
"description": "Given a deep data structure, access data by dot notation.",
"homepage": "https://github.com/dflydev/dflydev-dot-access-data",
"keywords": [
"access",
"data",
"dot",
"notation"
],
"support": {
"issues": "https://github.com/dflydev/dflydev-dot-access-data/issues",
"source": "https://github.com/dflydev/dflydev-dot-access-data/tree/v3.0.1"
},
"time": "2021-08-13T13:06:58+00:00"
},
{
"name": "doctrine/cache",
"version": "2.1.1",
@ -1155,6 +1230,192 @@
],
"time": "2022-03-29T20:12:16+00:00"
},
{
"name": "league/commonmark",
"version": "2.2.3",
"source": {
"type": "git",
"url": "https://github.com/thephpleague/commonmark.git",
"reference": "47b015bc4e50fd4438c1ffef6139a1fb65d2ab71"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/thephpleague/commonmark/zipball/47b015bc4e50fd4438c1ffef6139a1fb65d2ab71",
"reference": "47b015bc4e50fd4438c1ffef6139a1fb65d2ab71",
"shasum": ""
},
"require": {
"ext-mbstring": "*",
"league/config": "^1.1.1",
"php": "^7.4 || ^8.0",
"psr/event-dispatcher": "^1.0",
"symfony/deprecation-contracts": "^2.1 || ^3.0",
"symfony/polyfill-php80": "^1.15"
},
"require-dev": {
"cebe/markdown": "^1.0",
"commonmark/cmark": "0.30.0",
"commonmark/commonmark.js": "0.30.0",
"composer/package-versions-deprecated": "^1.8",
"erusev/parsedown": "^1.0",
"ext-json": "*",
"github/gfm": "0.29.0",
"michelf/php-markdown": "^1.4",
"phpstan/phpstan": "^0.12.88 || ^1.0.0",
"phpunit/phpunit": "^9.5.5",
"scrutinizer/ocular": "^1.8.1",
"symfony/finder": "^5.3",
"symfony/yaml": "^2.3 | ^3.0 | ^4.0 | ^5.0 | ^6.0",
"unleashedtech/php-coding-standard": "^3.1",
"vimeo/psalm": "^4.7.3"
},
"suggest": {
"symfony/yaml": "v2.3+ required if using the Front Matter extension"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "2.3-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"
],
"support": {
"docs": "https://commonmark.thephpleague.com/",
"forum": "https://github.com/thephpleague/commonmark/discussions",
"issues": "https://github.com/thephpleague/commonmark/issues",
"rss": "https://github.com/thephpleague/commonmark/releases.atom",
"source": "https://github.com/thephpleague/commonmark"
},
"funding": [
{
"url": "https://www.colinodell.com/sponsor",
"type": "custom"
},
{
"url": "https://www.paypal.me/colinpodell/10.00",
"type": "custom"
},
{
"url": "https://github.com/colinodell",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/league/commonmark",
"type": "tidelift"
}
],
"time": "2022-02-26T21:24:45+00:00"
},
{
"name": "league/config",
"version": "v1.1.1",
"source": {
"type": "git",
"url": "https://github.com/thephpleague/config.git",
"reference": "a9d39eeeb6cc49d10a6e6c36f22c4c1f4a767f3e"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/thephpleague/config/zipball/a9d39eeeb6cc49d10a6e6c36f22c4c1f4a767f3e",
"reference": "a9d39eeeb6cc49d10a6e6c36f22c4c1f4a767f3e",
"shasum": ""
},
"require": {
"dflydev/dot-access-data": "^3.0.1",
"nette/schema": "^1.2",
"php": "^7.4 || ^8.0"
},
"require-dev": {
"phpstan/phpstan": "^0.12.90",
"phpunit/phpunit": "^9.5.5",
"scrutinizer/ocular": "^1.8.1",
"unleashedtech/php-coding-standard": "^3.1",
"vimeo/psalm": "^4.7.3"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "1.2-dev"
}
},
"autoload": {
"psr-4": {
"League\\Config\\": "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": "Define configuration arrays with strict schemas and access values with dot notation",
"homepage": "https://config.thephpleague.com",
"keywords": [
"array",
"config",
"configuration",
"dot",
"dot-access",
"nested",
"schema"
],
"support": {
"docs": "https://config.thephpleague.com/",
"issues": "https://github.com/thephpleague/config/issues",
"rss": "https://github.com/thephpleague/config/releases.atom",
"source": "https://github.com/thephpleague/config"
},
"funding": [
{
"url": "https://www.colinodell.com/sponsor",
"type": "custom"
},
{
"url": "https://www.paypal.me/colinpodell/10.00",
"type": "custom"
},
{
"url": "https://github.com/colinodell",
"type": "github"
}
],
"time": "2021-08-14T12:15:32+00:00"
},
{
"name": "middlewares/trailing-slash",
"version": "v2.0.1",
@ -1378,6 +1639,153 @@
},
"time": "2022-01-21T06:08:36+00:00"
},
{
"name": "nette/schema",
"version": "v1.2.2",
"source": {
"type": "git",
"url": "https://github.com/nette/schema.git",
"reference": "9a39cef03a5b34c7de64f551538cbba05c2be5df"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/nette/schema/zipball/9a39cef03a5b34c7de64f551538cbba05c2be5df",
"reference": "9a39cef03a5b34c7de64f551538cbba05c2be5df",
"shasum": ""
},
"require": {
"nette/utils": "^2.5.7 || ^3.1.5 || ^4.0",
"php": ">=7.1 <8.2"
},
"require-dev": {
"nette/tester": "^2.3 || ^2.4",
"phpstan/phpstan-nette": "^0.12",
"tracy/tracy": "^2.7"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.2-dev"
}
},
"autoload": {
"classmap": [
"src/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause",
"GPL-2.0-only",
"GPL-3.0-only"
],
"authors": [
{
"name": "David Grudl",
"homepage": "https://davidgrudl.com"
},
{
"name": "Nette Community",
"homepage": "https://nette.org/contributors"
}
],
"description": "📐 Nette Schema: validating data structures against a given Schema.",
"homepage": "https://nette.org",
"keywords": [
"config",
"nette"
],
"support": {
"issues": "https://github.com/nette/schema/issues",
"source": "https://github.com/nette/schema/tree/v1.2.2"
},
"time": "2021-10-15T11:40:02+00:00"
},
{
"name": "nette/utils",
"version": "v3.2.7",
"source": {
"type": "git",
"url": "https://github.com/nette/utils.git",
"reference": "0af4e3de4df9f1543534beab255ccf459e7a2c99"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/nette/utils/zipball/0af4e3de4df9f1543534beab255ccf459e7a2c99",
"reference": "0af4e3de4df9f1543534beab255ccf459e7a2c99",
"shasum": ""
},
"require": {
"php": ">=7.2 <8.2"
},
"conflict": {
"nette/di": "<3.0.6"
},
"require-dev": {
"nette/tester": "~2.0",
"phpstan/phpstan": "^1.0",
"tracy/tracy": "^2.3"
},
"suggest": {
"ext-gd": "to use Image",
"ext-iconv": "to use Strings::webalize(), toAscii(), chr() and reverse()",
"ext-intl": "to use Strings::webalize(), toAscii(), normalize() and compare()",
"ext-json": "to use Nette\\Utils\\Json",
"ext-mbstring": "to use Strings::lower() etc...",
"ext-tokenizer": "to use Nette\\Utils\\Reflection::getUseStatements()",
"ext-xml": "to use Strings::length() etc. when mbstring is not available"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "3.2-dev"
}
},
"autoload": {
"classmap": [
"src/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause",
"GPL-2.0-only",
"GPL-3.0-only"
],
"authors": [
{
"name": "David Grudl",
"homepage": "https://davidgrudl.com"
},
{
"name": "Nette Community",
"homepage": "https://nette.org/contributors"
}
],
"description": "🛠 Nette Utils: lightweight utilities for string & array manipulation, image handling, safe JSON encoding/decoding, validation, slug or strong password generating etc.",
"homepage": "https://nette.org",
"keywords": [
"array",
"core",
"datetime",
"images",
"json",
"nette",
"paginator",
"password",
"slugify",
"string",
"unicode",
"utf-8",
"utility",
"validation"
],
"support": {
"issues": "https://github.com/nette/utils/issues",
"source": "https://github.com/nette/utils/tree/v3.2.7"
},
"time": "2022-01-24T11:29:14+00:00"
},
{
"name": "nikic/fast-route",
"version": "v1.3.0",
@ -1763,6 +2171,56 @@
},
"time": "2021-11-05T16:50:12+00:00"
},
{
"name": "psr/event-dispatcher",
"version": "1.0.0",
"source": {
"type": "git",
"url": "https://github.com/php-fig/event-dispatcher.git",
"reference": "dbefd12671e8a14ec7f180cab83036ed26714bb0"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-fig/event-dispatcher/zipball/dbefd12671e8a14ec7f180cab83036ed26714bb0",
"reference": "dbefd12671e8a14ec7f180cab83036ed26714bb0",
"shasum": ""
},
"require": {
"php": ">=7.2.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.0.x-dev"
}
},
"autoload": {
"psr-4": {
"Psr\\EventDispatcher\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "PHP-FIG",
"homepage": "http://www.php-fig.org/"
}
],
"description": "Standard interfaces for event handling.",
"keywords": [
"events",
"psr",
"psr-14"
],
"support": {
"issues": "https://github.com/php-fig/event-dispatcher/issues",
"source": "https://github.com/php-fig/event-dispatcher/tree/1.0.0"
},
"time": "2019-01-08T18:20:26+00:00"
},
{
"name": "psr/http-factory",
"version": "1.0.1",

View file

@ -14,13 +14,14 @@ use Lubian\NoFramework\Http\Pipeline;
use Lubian\NoFramework\Http\RoutedRequestHandler;
use Lubian\NoFramework\Http\RouteMiddleware;
use Lubian\NoFramework\Repository\CachedMarkdownPageRepo;
use Lubian\NoFramework\Repository\DoctrineMarkdownPageRepo;
use Lubian\NoFramework\Repository\MarkdownPageFilesystem;
use Lubian\NoFramework\Repository\MarkdownPageRepo;
use Lubian\NoFramework\Service\Time\Now;
use Lubian\NoFramework\Service\Time\SystemClockNow;
use Lubian\NoFramework\Settings;
use Lubian\NoFramework\Template\MarkdownParser;
use Lubian\NoFramework\Template\MustacheRenderer;
use Lubian\NoFramework\Template\ParsedownParser;
use Lubian\NoFramework\Template\Renderer;
use Mustache_Engine as ME;
use Mustache_Loader_FilesystemLoader as MLF;
@ -43,6 +44,7 @@ return [
RequestFactory::class => fn (DiactorosRequestFactory $rf) => $rf,
CacheInterface::class => fn (FilesystemAdapter $a) => $a,
MarkdownPageRepo::class => fn (CachedMarkdownPageRepo $r) => $r,
MarkdownParser::class => fn (ParsedownParser $p) => $p,
// Factories
ResponseInterface::class => fn (ResponseFactory $rf) => $rf->createResponse(),

View file

@ -1,13 +1,11 @@
<?php declare(strict_types=1);
use Lubian\NoFramework\Http\RouteMiddleware;
use Lubian\NoFramework\Middleware\CacheMiddleware;
use Middlewares\TrailingSlash;
use Middlewares\Whoops;
return [
Whoops::class,
TrailingSlash::class,
CacheMiddleware::class,
RouteMiddleware::class,
];

View file

@ -2,18 +2,15 @@
namespace Lubian\NoFramework\Action;
use Lubian\NoFramework\Template\MarkdownParser;
use Psr\Http\Message\ResponseInterface;
final class Other
{
public function someFunctionName(ResponseInterface $response): ResponseInterface
public function someFunctionName(ResponseInterface $response, MarkdownParser $parser): ResponseInterface
{
$body = $response->getBody();
$body->write('This works too!');
return $response
->withStatus(200)
->withBody($body);
$html = $parser->parse('This *works* **too!**');
$response->getBody()->write($html);
return $response->withStatus(200);
}
}

View file

@ -2,50 +2,79 @@
namespace Lubian\NoFramework\Action;
use Lubian\NoFramework\Model\MarkdownPage;
use Lubian\NoFramework\Repository\MarkdownPageFilesystem;
use Lubian\NoFramework\Repository\MarkdownPageRepo;
use Lubian\NoFramework\Exception\InternalServerError;
use Lubian\NoFramework\Template\MarkdownParser;
use Lubian\NoFramework\Template\Renderer;
use Parsedown;
use Psr\Http\Message\ResponseInterface;
use function array_filter;
use function array_map;
use function array_values;
use function file_get_contents;
use function glob;
use function preg_replace;
use function str_contains;
use function str_replace;
use function substr;
class Page
{
public function __construct(
private ResponseInterface $response,
private MarkdownPageRepo $repo,
private Parsedown $parsedown,
private MarkdownParser $parser,
private Renderer $renderer,
){}
private string $pagesPath = __DIR__ . '/../../data/pages/'
) {
}
public function show(
string $page,
): ResponseInterface {
$page = $this->repo->byTitle($page);
$content = $this->linkFilter($page->content);
$content = $this->parsedown->parse($content);
$html = $this->renderer->render('page', ['content' => $content, 'title' => $page->title]);
$page = array_values(
array_filter(
$this->getPages(),
fn (string $filename) => str_contains($filename, $page)
)
)[0];
$markdown = file_get_contents($page);
// fix the next and previous buttons to work with our routing
$markdown = preg_replace('/\(\d\d-/m', '(', $markdown);
$markdown = str_replace('.md)', ')', $markdown);
$page = str_replace([$this->pagesPath, '.md'], ['', ''], $page);
$data = [
'title' => substr($page, 3),
'content' => $this->parser->parse($markdown),
];
$html = $this->renderer->render('page/show', $data);
$this->response->getBody()->write($html);
return $this->response;
}
public function list(): ResponseInterface
{
$pages = array_map(
fn (MarkdownPage $p) => ['title' => $p->title, 'id' => $p->id],
$this->repo->all()
);
$html = $this->renderer->render('pagelist', ['pages' => $pages]);
$pages = array_map(function (string $page) {
$page = str_replace([$this->pagesPath, '.md'], ['', ''], $page);
return [
'id' => substr($page, 0, 2),
'title' => substr($page, 3),
];
}, $this->getPages());
$html = $this->renderer->render('page/list', ['pages' => $pages]);
$this->response->getBody()->write($html);
return $this->response;
}
private function linkFilter(string $content): string
/**
* @return string[]
*/
private function getPages(): array
{
$content = preg_replace('/\(\d\d-/m', '(', $content);
return str_replace('.md)', ')', $content);
$files = glob($this->pagesPath . '*.md');
if ($files === false) {
throw new InternalServerError('cannot read pages');
}
return $files;
}
}

View file

@ -1,7 +1,4 @@
<?php
declare(strict_types=1);
<?php declare(strict_types=1);
namespace Lubian\NoFramework\Factory;
@ -13,7 +10,10 @@ use Lubian\NoFramework\Settings;
final class DoctrineEm
{
public function __construct(private Settings $settings){}
public function __construct(private Settings $settings)
{
}
public function create(): EntityManagerInterface
{
$config = Setup::createConfiguration($this->settings->doctrine['devMode']);
@ -29,4 +29,4 @@ final class DoctrineEm
$config,
);
}
}
}

View file

@ -20,7 +20,7 @@ final class SettingsContainerProvider implements ContainerProvider
$dependencies = require $settings->dependenciesFile;
$dependencies[Settings::class] = $settings;
$builder->addDefinitions($dependencies);
// $builder->enableCompilation('/tmp');
// $builder->enableCompilation('/tmp');
return $builder->build();
}
}

View file

@ -19,13 +19,12 @@ final class CacheMiddleware implements MiddlewareInterface
private CacheInterface $cache,
private Response\Serializer $serializer,
private Settings $settings,
)
{
) {
}
public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
{
if ($request->getMethod() === 'GET' && !$this->settings->isDev()) {
if ($request->getMethod() === 'GET' && ! $this->settings->isDev()) {
$key = (string) $request->getUri();
$key = base64_encode($key);
$callback = fn () => $handler->handle($request);

View file

@ -3,17 +3,15 @@
namespace Lubian\NoFramework\Model;
use Doctrine\DBAL\Types\Types;
use Doctrine\ORM\Mapping\Column;
use Doctrine\ORM\Mapping\Entity;
use Doctrine\ORM\Mapping\GeneratedValue;
use Doctrine\ORM\Mapping\Id;
#[Entity]
class MarkdownPage
{
public function __construct(
#[Id, Column, GeneratedValue]
public int|null $id = null,
#[Id,
Column,
GeneratedValue]
public int |null $id = null,
#[Column]
public string $title,
#[Column(type: Types::TEXT)]

View file

@ -1,7 +1,4 @@
<?php
declare(strict_types=1);
<?php declare(strict_types=1);
namespace Lubian\NoFramework\Repository;
@ -10,15 +7,17 @@ use Doctrine\ORM\EntityRepository;
use Lubian\NoFramework\Exception\NotFound;
use Lubian\NoFramework\Model\MarkdownPage;
use function random_int;
use function usleep;
final class DoctrineMarkdownPageRepo implements MarkdownPageRepo
{
/**
* @var EntityRepository<MarkdownPage>
*/
/** @var EntityRepository<MarkdownPage> */
private EntityRepository $repo;
public function __construct(
private EntityManagerInterface $entityManager
){
) {
$this->repo = $this->entityManager->getRepository(MarkdownPage::class);
}
@ -27,15 +26,15 @@ final class DoctrineMarkdownPageRepo implements MarkdownPageRepo
*/
public function all(): array
{
usleep(rand(500, 1500) * 1000);
usleep(random_int(500, 1500) * 1000);
return $this->repo->findAll();
}
public function byId(int $id): MarkdownPage
{
usleep(rand(500, 1500) * 1000);
usleep(random_int(500, 1500) * 1000);
$page = $this->repo->findOneBy(['id' => $id]);
if (!$page instanceof MarkdownPage){
if (! $page instanceof MarkdownPage) {
throw new NotFound;
}
return $page;
@ -43,9 +42,9 @@ final class DoctrineMarkdownPageRepo implements MarkdownPageRepo
public function byTitle(string $title): MarkdownPage
{
usleep(rand(500, 1500) * 1000);
usleep(random_int(500, 1500) * 1000);
$page = $this->repo->findOneBy(['title' => $title]);
if (!$page instanceof MarkdownPage){
if (! $page instanceof MarkdownPage) {
throw new NotFound;
}
return $page;
@ -57,4 +56,4 @@ final class DoctrineMarkdownPageRepo implements MarkdownPageRepo
$this->entityManager->flush();
return $page;
}
}
}

View file

@ -13,6 +13,7 @@ use function count;
use function file_get_contents;
use function glob;
use function is_array;
use function random_int;
use function str_replace;
use function substr;
use function usleep;
@ -31,7 +32,7 @@ final class MarkdownPageFilesystem implements MarkdownPageRepo
$fileNames = glob($this->dataPath . '*.md');
assert(is_array($fileNames));
return array_map(function (string $name): MarkdownPage {
usleep(rand(200, 500) * 1000);
usleep(random_int(200, 500) * 1000);
$content = file_get_contents($name);
$name = str_replace($this->dataPath, '', $name);
$name = str_replace('.md', '', $name);

View file

@ -0,0 +1,28 @@
<?php declare(strict_types=1);
namespace Lubian\NoFramework\Template;
use League\CommonMark\Environment\Environment;
use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
use League\CommonMark\Extension\GithubFlavoredMarkdownExtension;
use League\CommonMark\MarkdownConverter;
final class GithubMarkdownRenderer implements MarkdownRenderer
{
private MarkdownConverter $engine;
public function __construct(
CommonMarkCoreExtension $commonMarkCoreExtension,
GithubFlavoredMarkdownExtension $githubFlavoredMarkdownExtension,
) {
$environment = new Environment([]);
$environment->addExtension($commonMarkCoreExtension);
$environment->addExtension($githubFlavoredMarkdownExtension);
$this->engine = new MarkdownConverter($environment);
}
public function render(string $markdown): string
{
return (string) $this->engine->convert($markdown);
}
}

View file

@ -0,0 +1,8 @@
<?php declare(strict_types=1);
namespace Lubian\NoFramework\Template;
interface MarkdownParser
{
public function parse(string $markdown): string;
}

View file

@ -0,0 +1,17 @@
<?php declare(strict_types=1);
namespace Lubian\NoFramework\Template;
use Parsedown;
final class ParsedownParser implements MarkdownParser
{
public function __construct(private Parsedown $parser)
{
}
public function parse(string $markdown): string
{
return $this->parser->parse($markdown);
}
}

View file

@ -0,0 +1,19 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Pages</title>
<link rel="stylesheet" href="https://unpkg.com/@picocss/pico@latest/css/pico.classless.min.css">
</head>
<body>
<main>
<ul>
{{#pages}}
<li>
<a href="/page/{{title}}">{{id}}: {{title}}</a>
</li>
{{/pages}}
</ul>
</main>
</body>
</html>

View file

@ -0,0 +1,13 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>{{title}}</title>
<link rel="stylesheet" href="https://unpkg.com/@picocss/pico@latest/css/pico.classless.min.css">
</head>
<body>
<main>
{{{content}}}
</main>
</body>
</html>