Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(BuildCommand.php): add lifecycle hooks for prehtml and prepdf #14

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 28 additions & 4 deletions readme.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
<p align="center">
<img src="https://raw.githubusercontent.com/themsaid/ibis/master/art/cover.png" alt="Ibis logo" width="480">

Artwork by <a href="https://twitter.com/ericlbarnes">Eric L. Barnes</a> and <a href="https://twitter.com/Caneco">Caneco</a> from <a href="https://laravel-news.com/ibis-book-maker">Laravel News</a> ❤️.
</p>

---

This PHP tool helps you write eBooks in markdown. Run `ibis build` and an eBook will be generated with:

1. A cover photo.
2. Clickable auto-generated table of contents.
3. Code syntax highlighting.
Expand Down Expand Up @@ -45,7 +45,7 @@ You may configure your book by editing the `/ibis.php` configuration file.

## Writing Your eBook

The `init` command will create sample .md files inside the content folder. You can explore those files to see how you can write your book. This sample content is taken from [Laravel Queues in Action](https://learn-laravel-queues.com).
The `init` command will create sample .md files inside the content folder. You can explore those files to see how you can write your book. This sample content is taken from [Laravel Queues in Action](https://learn-laravel-queues.com).

Inside the content directory, you can write multiple `.md` files. Ibis uses the headings to divide the book into parts and chapters:

Expand All @@ -61,7 +61,7 @@ Inside the content directory, you can write multiple `.md` files. Ibis uses the
### Starting with Ibis

<h3> tags define different titles inside a chapter.
```
```

## Using Fonts

Expand Down Expand Up @@ -91,6 +91,30 @@ ibis sample dark

This command will use the generated files from the `ibis build` command to generate samples from your PDF eBook. You can configure which pages to include in the sample by updating the `/ibis.php` file.


## Extending Ibis

### Build lifecycle hooks

You can customize your Ibis build process by defining lifecycle hook function(s) in your `ibis.php` config;

```php
return [

'prehtml' => function($markdown) {
// preprocesses markdown content before converting to HTML
return $markdown;
},

'prepdf' => function($html) {
// preprocesses converted markdown HTML content before writing to PDF
return $html;
},

// .. rest of ibis.php config
];
```

## Credits

- [Mohamed Said](https://github.com/themsaid)
Expand Down
98 changes: 67 additions & 31 deletions src/Commands/BuildCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ class BuildCommand extends Command
* @var string|string[]|null
*/
public $themeName;

/**
* @var OutputInterface
*/
Expand All @@ -33,6 +34,27 @@ class BuildCommand extends Command
*/
private $disk;

/**
* @var string
*/
private $currentPath;

/**
* User ibis.php config settings
* @var array
*/
private $config;


public function __construct()
{
parent::__construct();

$this->currentPath = getcwd();
$this->config = require $this->currentPath.'/ibis.php';
}


/**
* Configure the command.
*
Expand All @@ -46,6 +68,7 @@ protected function configure()
->setDescription('Generate the book.');
}


/**
* Execute the command.
*
Expand All @@ -61,19 +84,13 @@ public function execute(InputInterface $input, OutputInterface $output)
$this->output = $output;
$this->themeName = $input->getArgument('theme');

$currentPath = getcwd();
$config = require $currentPath.'/ibis.php';

$this->ensureExportDirectoryExists(
$currentPath = getcwd()
);
$this->ensureExportDirectoryExists();

$theme = $this->getTheme($currentPath, $this->themeName);
$theme = $this->getTheme($this->themeName);

$this->buildPdf(
$this->buildHtml($currentPath.'/content'),
$config,
$currentPath,
$this->buildHtml($this->currentPath.'/content'),
$theme
);

Expand All @@ -83,22 +100,24 @@ public function execute(InputInterface $input, OutputInterface $output)
return 0;
}


/**
* @param string $currentPath
*
*/
protected function ensureExportDirectoryExists(string $currentPath): void
protected function ensureExportDirectoryExists(): void
{
$this->output->writeln('<fg=yellow>==></> Preparing Export Directory ...');

if (! $this->disk->isDirectory($currentPath.'/export')) {
if (! $this->disk->isDirectory($this->currentPath.'/export')) {
$this->disk->makeDirectory(
$currentPath.'/export',
$this->currentPath.'/export',
0755,
true
);
}
}


/**
* @param string $path
* @return string
Expand All @@ -107,6 +126,10 @@ protected function buildHtml(string $path)
{
$this->output->writeln('<fg=yellow>==></> Parsing Markdown ...');

if (is_callable($this->config['prehtml'] ?? null)) {
bmcminn marked this conversation as resolved.
Show resolved Hide resolved
$this->output->writeln('<fg=yellow>==></> Pre-processing Markdown ...');
}

$environment = Environment::createCommonMarkEnvironment();

$environment->addBlockRenderer(FencedCode::class, new FencedCodeRenderer([
Expand All @@ -125,6 +148,12 @@ protected function buildHtml(string $path)
$file->getPathname()
);


if (is_callable($this->config['prehtml'] ?? null)) {
$markdown = $this->config['prehtml']($markdown);
}


return $this->prepareForPdf(
$converter->convertToHtml($markdown),
$i + 1
Expand All @@ -133,6 +162,7 @@ protected function buildHtml(string $path)
->implode(' ');
}


/**
* @param string $html
* @param $file
Expand All @@ -158,15 +188,14 @@ private function prepareForPdf(string $html, $file)
return $html;
}


/**
* @param string $html
* @param array $config
* @param string $currentPath
* @param string $theme
* @throws \Illuminate\Contracts\Filesystem\FileNotFoundException
* @throws \Mpdf\MpdfException
*/
protected function buildPdf(string $html, array $config, string $currentPath, string $theme)
protected function buildPdf(string $html, string $theme)
{
$defaultConfig = (new ConfigVariables())->getDefaults();
$fontDirs = $defaultConfig['fontDir'];
Expand All @@ -176,13 +205,13 @@ protected function buildPdf(string $html, array $config, string $currentPath, st

$pdf = new Mpdf([
'mode' => 'utf-8',
'format' => $config['document']['format'] ?? [210, 297],
'margin_left' => $config['document']['margin_left'] ?? 27,
'margin_right' => $config['document']['margin_right'] ?? 27,
'margin_bottom' => $config['document']['margin_bottom'] ?? 14,
'margin_top' => $config['document']['margin_top'] ?? 14,
'format' => $this->config['document']['format'] ?? [210, 297],
'margin_left' => $this->config['document']['margin_left'] ?? 27,
'margin_right' => $this->config['document']['margin_right'] ?? 27,
'margin_bottom' => $this->config['document']['margin_bottom'] ?? 14,
'margin_top' => $this->config['document']['margin_top'] ?? 14,
'fontDir' => array_merge($fontDirs, [getcwd().'/assets/fonts']),
'fontdata' => $this->fonts($config, $fontData),
'fontdata' => $this->fonts($fontData),
]);

$pdf->SetTitle(Ibis::title());
Expand All @@ -202,13 +231,13 @@ protected function buildPdf(string $html, array $config, string $currentPath, st

$pdf->SetMargins(400, 100, 12);

if (! $this->disk->isFile($currentPath.'/assets/cover.jpg')) {
if (! $this->disk->isFile($this->currentPath.'/assets/cover.jpg')) {
$this->output->writeln('<fg=red>==></> No assets/cover.jpg File Found. Skipping ...');
} else {
$this->output->writeln('<fg=yellow>==></> Adding Book Cover ...');

$coverPosition = $config['cover']['position'] ?? 'position: absolute; left:0; right: 0; top: -.2; bottom: 0;';
$coverDimensions = $config['cover']['dimensions'] ?? 'width: 210mm; height: 297mm; margin: 0;';
$coverPosition = $this->config['cover']['position'] ?? 'position: absolute; left:0; right: 0; top: -.2; bottom: 0;';
$coverDimensions = $this->config['cover']['dimensions'] ?? 'width: 210mm; height: 297mm; margin: 0;';

$pdf->WriteHTML(
<<<HTML
Expand All @@ -223,6 +252,12 @@ protected function buildPdf(string $html, array $config, string $currentPath, st

$pdf->SetHTMLFooter('<div id="footer" style="text-align: center">{PAGENO}</div>');


if (is_callable($this->config['prepdf'] ?? null)) {
$this->output->writeln('<fg=yellow>==></> Pre-processing PDF ...');
$html = $this->config['prepdf']($html);
}

$this->output->writeln('<fg=yellow>==></> Building PDF ...');

$pdf->WriteHTML(
Expand All @@ -235,28 +270,29 @@ protected function buildPdf(string $html, array $config, string $currentPath, st
$this->output->writeln('✨✨ '.$pdf->page.' PDF pages ✨✨');

$pdf->Output(
$currentPath.'/export/'.Ibis::outputFileName().'-'.$this->themeName.'.pdf'
$this->currentPath.'/export/'.Ibis::outputFileName().'-'.$this->themeName.'.pdf'
);
}


/**
* @param $currentPath
* @param $themeName
* @return string
* @throws \Illuminate\Contracts\Filesystem\FileNotFoundException
*/
private function getTheme($currentPath, $themeName)
private function getTheme($themeName)
{
return $this->disk->get($currentPath."/assets/theme-$themeName.html");
return $this->disk->get($this->currentPath."/assets/theme-$themeName.html");
}


/**
* @param $fontData
* @return array
*/
protected function fonts($config, $fontData)
protected function fonts($fontData)
{
return $fontData + collect($config['fonts'])->mapWithKeys(function ($file, $name) {
return $fontData + collect($this->config['fonts'])->mapWithKeys(function ($file, $name) {
return [
$name => [
'R' => $file
Expand Down
16 changes: 15 additions & 1 deletion stubs/ibis.php
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,20 @@
/**
* A notice printed at the final page of a generated sample.
*/
'sample_notice' => 'This is a sample from "Laravel Queues in Action" by Mohamed Said. <br>
'sample_notice' => 'This is a sample from "Laravel Queues in Action" by Mohamed Said. <br>
For more information, <a href="https://www.learn-laravel-queues.com/">Click here</a>.',


// 'prehtml' => function($markdown) {
// // preprocesses markdown content before converting to HTML
// return $markdown;
// },


// 'prepdf' => function($html) {
// // preprocesses converted markdown HTML content before writing to PDF
// return $html;
// },


];