diff --git a/app/Build/File.php b/app/Build/File.php new file mode 100644 index 0000000..f0d9706 --- /dev/null +++ b/app/Build/File.php @@ -0,0 +1,13 @@ +targetDisk = Storage::disk('build_local'); } - protected function readSite() + /** + * Get all the pages from the source directory + * + * @return Collection + */ + public function getPages(): Collection { $files = $this->sourceDisk->files(recursive: true); foreach (self::IGNORED_DIRECTORIES as $ignore) { $files = array_filter($files, fn($path) => !str_starts_with($path, $ignore)); } - $pages = []; + + $pages = collect(); // Set up a structure foreach ($files as $f) { - $pages[] = [ - 'path' => $f, - 'name' => basename($f), - 'source' => Storage::disk('source')->path($f), - 'output_path' => $this->getOutputPath($f), - 'extension' => $this->getFileExtension($f) - ]; + $pages->push(new Page($f)); } + + return $pages; } - public function getOutputPath(string $filename): string + public function slugFromFilename(string $filename): string { - $indexFiles = ['index.md', 'index.blade.php']; - - $baseDirectory = Str::of($filename)->remove(basename($filename))->trim('/')->toString(); - if (in_array(basename($filename), $indexFiles)) { - return join_paths($baseDirectory, "index.html"); - } - - return join_paths($baseDirectory, "{$this->slugFromFilename($filename)}", "index.html"); + return Str::of(basename($filename))->remove(".md")->remove(".blade.php")->slug()->toString(); } - public function getFileExtension($filename): string - { - // Check for .blade.php first - if (str_ends_with($filename, '.blade.php')) { - return 'blade.php'; - } + public function getOutputPath(string $filename): string {} - // Fall back to regular extension - return pathinfo($filename, PATHINFO_EXTENSION); - } /** * Parse all content collections and sub collections. @@ -80,5 +71,5 @@ class SiteParser * * @return Collection */ - public function collections(): Collection {} + // public function collections(): Collection {} } diff --git a/app/Commands/BuildCommand.php b/app/Commands/BuildCommand.php index 9429be4..e3b849b 100644 --- a/app/Commands/BuildCommand.php +++ b/app/Commands/BuildCommand.php @@ -2,11 +2,13 @@ namespace App\Commands; +use App\Build\SiteParser; use Exception; use Illuminate\Console\Scheduling\Schedule; use Illuminate\Contracts\Cache\Store; use Illuminate\Support\Facades\Blade; use Illuminate\Support\Facades\Storage; +use Illuminate\Support\Facades\View; use LaravelZero\Framework\Commands\Command; use Illuminate\Support\Str; use Parsedown; @@ -38,42 +40,20 @@ class BuildCommand extends Command // Storage::delete(Storage::disk('build_local')->files()); // Storage::delete(Storage::disk('build_local')->directories()); - $ignored = [ - "assets", - "_" - ]; - - $files = Storage::disk('source')->files(recursive: true); - foreach ($ignored as $ignore) { - $files = array_filter($files, fn($path) => !str_starts_with($path, $ignore)); - } - $pages = []; - - // Set up a structure - foreach ($files as $f) { - $pages[] = [ - 'path' => $f, - 'name' => basename($f), - 'source' => Storage::disk('source')->path($f), - 'output_path' => $this->getOutputPath($f), - 'extension' => $this->getFileExtension($f) - ]; - } + $siteParser = new SiteParser; + $pages = $siteParser->getPages(); // Parse and output foreach ($pages as $p) { + View::share('page', $p); try { - - if ($p['extension'] == 'blade.php') { - $rendered = $this->renderBlade($p); - } else { - $rendered = $this->renderMarkdown($p); - } + $rendered = $p->render(); } catch (Exception $e) { - $this->error("Failed on: " . $p['path']); + $this->error("Failed on: " . $p->path); throw $e; } - Storage::disk('build_local')->put($p['output_path'], $rendered); + + Storage::disk('build_local')->put($p->outputPath(), $rendered); } // Copy static assets folder @@ -88,65 +68,4 @@ class BuildCommand extends Command $this->info("Site built"); $this->notify("Site Zapped", "Your site has been built"); } - - public function renderBlade(array $page): string - { - $blade = file_get_contents($page['source']); - return Blade::render($blade, []); - } - - public function renderMarkdown(array $page): string - { - $parser = new Parsedown(); - $md = file_get_contents($page['source']); - $parsed = $parser->text($md); - $tmpBlade = << - $parsed - - HTML; - $rendered = Blade::render($tmpBlade, []); - return $rendered; - } - - public function getFileExtension($filename): string - { - // Check for .blade.php first - if (str_ends_with($filename, '.blade.php')) { - return 'blade.php'; - } - - // Fall back to regular extension - return pathinfo($filename, PATHINFO_EXTENSION); - } - - public function slugFromFilename(string $filename): string - { - return Str::of(basename($filename))->remove(".md")->remove(".blade.php")->slug()->toString(); - } - - public function titleFromFilename(string $filename): string - { - return Str::of(basename($filename))->remove(".md")->remove(".blade.php")->replace('-', ' ')->title()->toString(); - } - - public function getOutputPath(string $filename): string - { - $indexFiles = ['index.md', 'index.blade.php']; - - $baseDirectory = Str::of($filename)->remove(basename($filename))->trim('/')->toString(); - if (in_array(basename($filename), $indexFiles)) { - return join_paths($baseDirectory, "index.html"); - } - - return join_paths($baseDirectory, "{$this->slugFromFilename($filename)}", "index.html"); - } - - /** - * Define the command's schedule. - */ - public function schedule(Schedule $schedule): void - { - // $schedule->command(static::class)->everyMinute(); - } } diff --git a/app/Models/Page.php b/app/Models/Page.php index a1796ec..354f367 100644 --- a/app/Models/Page.php +++ b/app/Models/Page.php @@ -2,12 +2,108 @@ namespace App\Models; +use App\Render\BladeRenderer; +use App\Render\MarkdownRenderer; +use App\Render\Renderer; +use Illuminate\Contracts\Filesystem\Filesystem; +use Illuminate\Support\Facades\Storage; +use League\CommonMark\Environment\Environment; +use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension; +use League\CommonMark\Extension\FrontMatter\FrontMatterExtension; +use League\CommonMark\Extension\FrontMatter\Output\RenderedContentWithFrontMatter; +use League\CommonMark\MarkdownConverter; + +use function Illuminate\Filesystem\join_paths; + +// TODO: Load page's frontmatter and replace things like +// title and layout from it. Also set any default, +// values for things like layout from the config +// if they're not present on the page. class Page { - public function __construct( - protected string $title, - protected string $path, - protected string $outputPath, - protected string $content, - ) {} + public string $filename; + public string $fileExtension; + public string $directory; + public string $title; + public string $slug; + public bool $isIndex; + public string $key; + protected Filesystem $sourceDisk; + public ?string $layout; + protected string $content; + + public function __construct(public string $path) + { + $this->sourceDisk = Storage::disk('source'); + + $this->filename = basename($this->path); + $this->fileExtension = (str_ends_with($this->filename, '.blade.php')) ? 'blade.php' : pathinfo($this->filename, PATHINFO_EXTENSION); + $this->fileExtension = str($this->fileExtension)->trim('.')->toString(); + $this->title = str($this->filename)->remove("." . $this->fileExtension)->title()->toString(); + $this->slug = str($this->title)->slug(); + $this->isIndex = str($this->filename)->remove("." . $this->fileExtension)->toString() == "index"; + $this->directory = dirname($this->path); + $this->key = str($this->path)->remove("." . $this->fileExtension)->replace("/", ".")->lower()->toString(); + + $this->fillAdditionalData(); + } + + /** + * Grab data from the file's front matter + * as well as the config and overwrite + * or fill in any missing attributes. + * + * @return void + */ + public function fillAdditionalData() + { + // Grab front matter data if any + if ($this->fileExtension == 'md') { + // Build the markdown parser + $mdEnvironment = new Environment(); + $mdEnvironment->addExtension(new CommonMarkCoreExtension); + $mdEnvironment->addExtension(new FrontMatterExtension); + + $parser = new MarkdownConverter($mdEnvironment); + $parsed = $parser->convert($this->content()); + if ($parsed instanceof RenderedContentWithFrontMatter) { + $frontMatter = $parsed->getFrontMatter(); + foreach ($frontMatter as $field => $value) { + $this->$field = $value; + } + } + } + } + + public function renderer(): Renderer + { + return ($this->fileExtension == 'blade.php') ? new BladeRenderer : new MarkdownRenderer; + } + + public function render(): string + { + return $this->renderer()->render($this); + } + + public function outputPath(): string + { + + $baseDirectory = $this->directory; + if ($this->isIndex) { + return join_paths($baseDirectory, "index.html"); + } + + return join_paths($baseDirectory, "{$this->slug}", "index.html"); + } + + public function content(): string + { + if (!empty($this->content)) { + return $this->content; + } + + $content = Storage::disk('source')->get($this->path); + $this->content = $content; + return $content; + } } diff --git a/app/Render/BladeRenderer.php b/app/Render/BladeRenderer.php new file mode 100644 index 0000000..29653be --- /dev/null +++ b/app/Render/BladeRenderer.php @@ -0,0 +1,14 @@ +content(), []); + } +} diff --git a/app/Render/MarkdownRenderer.php b/app/Render/MarkdownRenderer.php new file mode 100644 index 0000000..6579ebf --- /dev/null +++ b/app/Render/MarkdownRenderer.php @@ -0,0 +1,33 @@ +addExtension(new CommonMarkCoreExtension); + $mdEnvironment->addExtension(new GithubFlavoredMarkdownExtension); + + $parser = new MarkdownConverter($mdEnvironment); + $parsed = $parser->convert($p->content()); + $tmpBlade = << + $parsed + + HTML; + $rendered = Blade::render($tmpBlade, []); + + return $rendered; + } +} diff --git a/app/Render/Renderer.php b/app/Render/Renderer.php new file mode 100644 index 0000000..6c3f6ba --- /dev/null +++ b/app/Render/Renderer.php @@ -0,0 +1,10 @@ +