Skip to content

Commit

Permalink
The stuff I needed in there for the EXACT documentation portal (#4)
Browse files Browse the repository at this point in the history
  • Loading branch information
edgrosvenor authored May 25, 2024
2 parents 4b77a29 + 253ab4c commit 388af68
Show file tree
Hide file tree
Showing 19 changed files with 377 additions and 6 deletions.
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,7 @@ phpunit.xml
phpstan.neon
testbench.yaml
vendor
node_modules
node_module
tests/md/.DS_Store
tests/.DS_Store

1 change: 1 addition & 0 deletions resources/views/components/docsidian.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
<title>Documentation</title>
<script src="https://cdn.tailwindcss.com"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/github-markdown-css/5.5.1/github-markdown.min.css" integrity="sha512-h/laqMqQKUXxFuu6aLAaSrXYwGYQ7qk4aYCQ+KJwHZMzAGaEoxMM6h8C+haeJTU1V6E9jrSUnjpEzX23OmV/Aw==" crossorigin="anonymous" referrerpolicy="no-referrer" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/mermaid/10.9.1/mermaid.min.js" integrity="sha512-6a80OTZVmEJhqYJUmYd5z8yHUCDlYnj6q9XwB/gKOEyNQV/Q8u+XeSG59a2ZKFEHGTYzgfOQKYEBtrZV7vBr+Q==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<style>
pre, code {
color: #393a34;
Expand Down
42 changes: 42 additions & 0 deletions src/Actions/EnableMermaid.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<?php

namespace ArtisanBuild\Docsidian\Actions;

use ArtisanBuild\Docsidian\DocumentationSite;
use Closure;

class EnableMermaid
{
public bool $mermaid = false;

public function __invoke(DocumentationSite $site, Closure $next)
{
$site->blade_files->each(
fn ($file) => $file->lines = $file->lines->map(fn ($line) => $this->enableMermaid($line)));

return $next($site);
}

protected function enableMermaid($line)
{
if (str_contains($line->content, '</code')) {
if ($this->mermaid) {
$line->content = str_replace('</code>', '', $line->content);
$this->mermaid = false;

return $line;
}
}
if (str_contains($line->content, 'class="language-mermaid"')) {
$this->mermaid = true;
}

if ($this->mermaid) {
$line->content = htmlspecialchars_decode($line->content);
$line->content = str_replace('<pre><code class="language-mermaid">', '<pre class="mermaid">', $line->content);
}

return $line;

}
}
44 changes: 44 additions & 0 deletions src/Actions/HandleWikiStyleImages.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<?php

namespace ArtisanBuild\Docsidian\Actions;

use ArtisanBuild\Docsidian\DocumentationLine;
use ArtisanBuild\Docsidian\DocumentationSite;
use ArtisanBuild\Docsidian\EmbeddedMedia;
use Closure;

class HandleWikiStyleImages
{
public string $image_path = '';

public function __invoke(DocumentationSite $site, Closure $next)
{
$this->image_path = $site->obsidian_configuration->attachment_path;

$site->blade_files->each(
fn ($file) => $file->lines = $file->lines->map(fn ($line) => $this->transformImages($line)));

return $next($site);
}

public function transformImages(DocumentationLine $line)
{
$line->content = $this->convertWikiImagesToHtml($line->content);

return $line;

}

public function convertWikiImagesToHtml($markdown): string
{
$pattern = '/!\[\[([^\]]+)\]\]/';
preg_match($pattern, $markdown, $matches);

if (isset($matches[1])) {
$image = app(EmbeddedMedia::class)->make($matches[1]);
$markdown = str_replace($matches[0], '<img src="{{ asset(\''.$image->uri.'\') }}" alt="">', $markdown);
}

return $markdown;
}
}
5 changes: 3 additions & 2 deletions src/Actions/HighlightCodeWithTempest.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ protected function enableCodeHighlighting(DocumentationLine $line): Documentatio
preg_match('/class="([^"]+)"/', $line->content, $matches);
$this->language = str_replace('language-', '', $matches[1]);
}
if ($this->language === 'live') {

if ($this->language === 'live' || $this->language === 'mermaid') {
$this->language = null;
}

Expand All @@ -39,7 +40,7 @@ protected function enableCodeHighlighting(DocumentationLine $line): Documentatio
$this->code_block = str_replace([
'<pre>',
'</pre>',
'</code>',
//'</code>',
'<code class="language-'.$this->language.'">',
], '', $this->code_block);

Expand Down
2 changes: 1 addition & 1 deletion src/Actions/RemoveEmptyParagraphs.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ class RemoveEmptyParagraphs
public function __invoke(DocumentationSite $site, Closure $next)
{
$site->blade_files->map(function ($page) {
$page->lines = $page->lines->filter(fn ($line) => ! blank(strip_tags($line->content)));
$page->lines = $page->lines->filter(fn ($line) => $line->content != '<p></p>');
});

return $next($site);
Expand Down
7 changes: 7 additions & 0 deletions src/Commands/GenerateCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@
use ArtisanBuild\Docsidian\Actions\BuildNavigation;
use ArtisanBuild\Docsidian\Actions\DecorateRemainingHashTags;
use ArtisanBuild\Docsidian\Actions\EnableLiveCode;
use ArtisanBuild\Docsidian\Actions\EnableMermaid;
use ArtisanBuild\Docsidian\Actions\EnsureAllHeadingsHaveAnId;
use ArtisanBuild\Docsidian\Actions\GenerateOnPageNavigation;
use ArtisanBuild\Docsidian\Actions\HandleWikiStyleImages;
use ArtisanBuild\Docsidian\Actions\RemoveEmptyParagraphs;
use ArtisanBuild\Docsidian\Actions\SetBlockVisibility;
use ArtisanBuild\Docsidian\Actions\SetPageVisibility;
Expand All @@ -16,6 +18,7 @@
use ArtisanBuild\Docsidian\Contracts\HighlightsCodeBlocks;
use ArtisanBuild\Docsidian\Contracts\IndexesSiteForSearch;
use ArtisanBuild\Docsidian\DocumentationSite;
use ArtisanBuild\Docsidian\EmbeddedMedia;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\File;
use Illuminate\Support\Facades\Pipeline;
Expand All @@ -35,17 +38,21 @@ public function handle(): int
File::ensureDirectoryExists($site['folio_path']);
File::put(implode('/', [$site['folio_path'], 'index.blade.php']), '<p>Please add an index.md file to your markdown directory.</p>');

app()->when(EmbeddedMedia::class)->needs('$config')->give($site);

Pipeline::send(new DocumentationSite($site))
->through([
BuildNavigation::class,
SetPageVisibility::class,
SetBlockVisibility::class,
EnableLiveCode::class,
EnableMermaid::class,
HighlightsCodeBlocks::class,
DecorateRemainingHashTags::class,
EnsureAllHeadingsHaveAnId::class,
GenerateOnPageNavigation::class, //todo
RemoveEmptyParagraphs::class,
HandleWikiStyleImages::class,
AddNavigationToAllRenderedFiles::class,
WrapEachFileInTheLayoutComponent::class,
WriteEachBladeFileToTheFolioPath::class,
Expand Down
19 changes: 19 additions & 0 deletions src/DocsidianServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,16 @@

namespace ArtisanBuild\Docsidian;

use ArtisanBuild\Docsidian\Actions\DoNotIndexForSearch;
use ArtisanBuild\Docsidian\Actions\GetDefinedAbilities;
use ArtisanBuild\Docsidian\Actions\HighlightCodeWithTempest;
use ArtisanBuild\Docsidian\Commands\GenerateCommand;
use ArtisanBuild\Docsidian\Commands\InstallCommand;
use ArtisanBuild\Docsidian\Contracts\HighlightsCodeBlocks;
use ArtisanBuild\Docsidian\Contracts\IndexesSiteForSearch;
use Illuminate\Contracts\Auth\Authenticatable;
use Illuminate\Support\Facades\Blade;
use Illuminate\Support\Facades\Gate;
use Laravel\Folio\Folio;
use Spatie\LaravelPackageTools\Package;
use Spatie\LaravelPackageTools\PackageServiceProvider;
Expand All @@ -27,6 +34,12 @@ public function configurePackage(Package $package): void
->hasCommand(GenerateCommand::class);
}

public function registeringPackage()
{
$this->app->bind(IndexesSiteForSearch::class, DoNotIndexForSearch::class);
$this->app->bind(HighlightsCodeBlocks::class, HighlightCodeWithTempest::class);
}

public function packageBooted(): void
{
if (! config('docsidian.installed')) {
Expand All @@ -41,5 +54,11 @@ public function packageBooted(): void
->middleware($site['folio_middleware']);
}

if (app(GetDefinedAbilities::class)()->isEmpty()) {
Gate::define('docsidian-public', fn (?Authenticatable $user) => true);
Gate::define('docsidian-protected', fn (?Authenticatable $user) => $user instanceof Authenticatable);
Gate::define('docsidian-private', fn (?Authenticatable $user) => false);
}

}
}
6 changes: 5 additions & 1 deletion src/DocumentationSite.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,15 @@ class DocumentationSite

public Collection $navigation;

public ObsidianConfiguration $obsidian_configuration;

public function __construct(public array $configuration)
{
$this->folio_path = $this->configuration['folio_path'];
$this->markdown_path = $this->configuration['md_path'];
$this->blade_files = collect(File::allFiles($this->configuration['md_path']))->map(function ($file) {

$this->obsidian_configuration = new ObsidianConfiguration($this->configuration);
$this->blade_files = collect(File::allFiles($this->configuration['md_path']))->filter(fn ($file) => str_ends_with($file->getFilename(), '.md'))->map(function ($file) {
return new DocumentationPage(site: $this, markdown_file: $file);
});
$this->navigation = collect();
Expand Down
51 changes: 51 additions & 0 deletions src/EmbeddedMedia.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
<?php

namespace ArtisanBuild\Docsidian;

use Illuminate\Support\Facades\File;

class EmbeddedMedia
{
public string $uri = '';

public string $path = '';

public string $source_path = '';

public bool $exists = false;

public ObsidianConfiguration $obsidian;

public function __construct(public array $config)
{
$this->obsidian = new ObsidianConfiguration($config);
}

public function make(string $path)
{
$this->path = implode('/', [
$this->config['media_path'],
$path,
]);

$this->source_path = implode('/', [
$this->obsidian->attachment_path,
$path,
]);

$this->uri = implode('/', [
str_replace(public_path(), '', rtrim($this->config['media_path'], '/')),
$path,
]);

throw_if(! file_exists($this->source_path), "{$this->source_path} does not exist");

$this->exists = file_exists($this->path);

File::ensureDirectoryExists(dirname($this->path));

File::copy($this->source_path, $this->path);

return $this;
}
}
32 changes: 32 additions & 0 deletions src/LineTransformers/EmbedRawImageUrls.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?php

namespace ArtisanBuild\Docsidian\LineTransformers;

use Closure;

class EmbedRawImageUrls
{
public function __invoke(string $line, Closure $next): string
{
if (! filter_var(trim(current($chunks = explode(' ', trim(strip_tags($line))))), FILTER_VALIDATE_URL)) {
return $next($line);
}

$headers = get_headers(current($chunks), true);

if (! str_contains(data_get($headers, 'Content-Type'), 'image')) {

return $next($line);
}

$line = count(array_filter($chunks)) === 1
? '<p><img class="object-contain md:object-scale-down" src="'.current($chunks).'" alt=""></p>'
: '<p><figure><img class="object-contain md:object-scale-down" src="'
.array_shift($chunks)
.'" alt=""><figcaption>'
.implode(' ', $chunks)
.'</figcaption></figure></p>';

return $next($line);
}
}
13 changes: 13 additions & 0 deletions src/LineTransformers/TransformWikiImages.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?php

namespace ArtisanBuild\Docsidian\LineTransformers;

use Closure;

class TransformWikiImages
{
public function __invoke(string $line, Closure $next): string
{
return $next($line);
}
}
39 changes: 39 additions & 0 deletions src/ObsidianConfiguration.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<?php

namespace ArtisanBuild\Docsidian;

class ObsidianConfiguration
{
public string $css;

public string $attachment_path;

/* TODO: It would be nice to let users use their Obsidian theme's CSS to style their documentation site. To
that end, I am populating $this->css with the full path to the CSS that is bundled with the theme. I am not
sure how much work it will take to create a template that has the correct classes in the correct places
and whether we might also have to grab or generate a base theme css file to make this work. It's very much
a seed of an idea at this point, but it would be nice to make it happen at some point if we can figure it out.
*/
public function __construct(array $configuration)
{
// Calculate the full path to the Obsidian configuration folder
$configuration_path = data_get($configuration, 'obsidian_config');

$config = [
'app' => json_decode(file_get_contents(implode('/', [$configuration_path, 'app.json'])), true),
'appearance' => json_decode(file_get_contents(implode('/', [$configuration_path, 'appearance.json'])), true),
];

$this->attachment_path = implode('/', array_filter([
data_get($configuration, 'md_path'),
str_replace('./', '', data_get($config, 'app.attachmentFolderPath')),
]));

$this->css = implode('/', [
$configuration_path,
'themes',
data_get($config, 'appearance.cssTheme'),
'theme.css',
]);
}
}
Loading

0 comments on commit 388af68

Please sign in to comment.