Skip to content
Merged
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
46 changes: 43 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,6 @@ Publish the config file:
php artisan vendor:publish --tag="ozu-client-config"
```

> [!IMPORTANT]
> As our beta builder only works with PHP 8.4 for now, your project must use PHP 8.4.

## Usage

### Models are Ozu collections
Expand Down Expand Up @@ -109,6 +106,49 @@ class Project extends Model
> [!NOTE]
> This configuration will be used by Ozu to properly display the collection in the content management tool. It has no effect in your local codebase.

### Configure your content editor
```php
public static function configureOzuCollectionForm(OzuCollectionFormConfig $config): OzuCollectionFormConfig
{
return $config
->configureContentField(fn(OzuEditorField $field) => $field
->setLabel('Contenu')
->setToolbar([
OzuEditorToolbarEnum::Heading1,
OzuEditorToolbarEnum::Heading2,
OzuEditorToolbarEnum::Separator,
OzuEditorToolbarEnum::Bold,
OzuEditorToolbarEnum::Italic,
OzuEditorToolbarEnum::Link,
OzuEditorToolbarEnum::Image,
OzuEditorToolbarEnum::Separator,
OzuEditorToolbarEnum::Iframe,
OzuEditorToolbarEnum::Quote,
OzuEditorToolbarEnum::Video,
OzuEditorToolbarEnum::Separator,
OzuEditorToolbarEnum::BulletList,
OzuEditorToolbarEnum::OrderedList,
OzuEditorToolbarEnum::Separator,
])
->setMaxFileSize(12)
->setCropRatio('1:1')
);
}
```

Ozu uses a supercharged version of the sharp editor field. You can declare multiple toolbar element to enrich your content, including :

- `OzuEditorToolbarEnum::Image` to embed images directly inside your content
- `OzuEditorToolbarEnum::Quote` to embed nice quotes with an (optional) author
- `OzuEditorToolbarEnum::Video` to embed videos from different providers (Youtube, Vimeo, Dailymotion)

Ozu will render very basically theses content but you can override the views by publishing them with:
```bash
php artisan vendor:publish --tag="ozu-views"
```
> [!WARNING]
> To allow ozu to renders rich content in your front, please use the `<x-ozu-content>` component.

### Handle `BelongsTo` relationships

A common use case is to have a `BelongsTo` relationship between two Ozu Models. There are two possibilities:
Expand Down
1 change: 1 addition & 0 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
],
"require": {
"php": "8.4.*",
"code16/embed": "^2.3",
"code16/laravel-content-renderer": "^1.1.0",
"guzzlehttp/guzzle": "^7.5",
"illuminate/contracts": "^11.0|^12.0",
Expand Down
14 changes: 14 additions & 0 deletions resources/views/components/embedded-image.blade.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
@php use Code16\OzuClient\Eloquent\Media; @endphp
@props([
/** @var Media $fileModel */
'fileModel',
'legend' => null,
])
<figure>
<img src="{{ $fileModel->thumbnail($thumbnailWidth, $thumbnailHeight) }}" {{ $attributes }}>
@if($legend)
<figcaption>
{{ $legend }}
</figcaption>
@endif
</figure>
12 changes: 12 additions & 0 deletions resources/views/components/quote.blade.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
@props([
'quote',
'author' => null,
])
<blockquote style="padding-left: 1rem; border-left: 3px solid #ccc;">
{{$quote}}
@if($author)
<cite style="display: block;">
<b>{{$author}}</b>
</cite>
@endif
</blockquote>
14 changes: 14 additions & 0 deletions resources/views/components/video.blade.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
@props([
'url',
'legend' => null,
])
<div>
<x-embed-video
:url="$url"
class=""
:autoplay="false"
/>
@if($legend)
<p>{{$legend}}</p>
@endif
</div>
7 changes: 7 additions & 0 deletions src/Exceptions/OzuClientException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<?php

namespace Code16\OzuClient\Exceptions;

use Exception;

class OzuClientException extends Exception {}
30 changes: 30 additions & 0 deletions src/OzuCms/Form/OzuEditorField.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

namespace Code16\OzuClient\OzuCms\Form;

use Code16\OzuClient\Exceptions\OzuClientException;

class OzuEditorField extends OzuField
{
private bool $withoutParagraphs = false;
Expand All @@ -20,6 +22,10 @@ class OzuEditorField extends OzuField

private ?int $maxHeight = null;

private int $maxFileSize = 5;

private ?string $cropRatio = null;

public function setWithoutParagraphs(): self
{
$this->withoutParagraphs = true;
Expand Down Expand Up @@ -49,6 +55,28 @@ public function setHeight(int $height, ?int $maxHeight = null): self
return $this;
}

public function setMaxFileSize(int $maxFileSize): self
{
if (! in_array(OzuEditorToolbarEnum::Image, $this->toolbar)) {
throw new OzuClientException('You should allow Image Uploads by adding OzuEditorToolbarEnum::Image in toolbar configuration before setting max file size');
}

$this->maxFileSize = $maxFileSize;

return $this;
}

public function setCropRatio(string $cropRatio): self
{
if (! in_array(OzuEditorToolbarEnum::Image, $this->toolbar)) {
throw new OzuClientException('You should allow Image Uploads by adding OzuEditorToolbarEnum::Image in toolbar configuration before setting image crop ratio');
}

$this->cropRatio = $cropRatio;

return $this;
}

public function type(): string
{
return 'editor';
Expand All @@ -62,6 +90,8 @@ public function toArray(): array
'toolbar' => collect($this->toolbar)->map(fn ($item) => $item->value)->toArray(),
'height' => $this->height,
'maxHeight' => $this->maxHeight,
'maxFileSize' => $this->maxFileSize,
'cropRatio' => $this->cropRatio,
]);
}
}
3 changes: 3 additions & 0 deletions src/OzuCms/Form/OzuEditorToolbarEnum.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,7 @@ enum OzuEditorToolbarEnum: string
case Heading1 = 'heading-1';
case Heading2 = 'heading-2';
case Iframe = 'iframe';
case Image = 'upload-image';
case Video = 'video';
case Quote = 'blockquote';
}
9 changes: 9 additions & 0 deletions src/OzuServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,11 @@
use Code16\OzuClient\Support\Thumbnails\LocalThumbnail;
use Code16\OzuClient\Support\Thumbnails\Thumbnail;
use Code16\OzuClient\View\Components\Content;
use Code16\OzuClient\View\Components\EmbeddedImage;
use Code16\OzuClient\View\Components\File;
use Code16\OzuClient\View\Components\Image;
use Code16\OzuClient\View\Components\Quote;
use Code16\OzuClient\View\Components\Video;
use Illuminate\Database\Eloquent\Relations\Relation;
use Illuminate\Pagination\LengthAwarePaginator;
use Illuminate\Pagination\Paginator;
Expand Down Expand Up @@ -70,12 +73,18 @@ public function boot()
$this->publishes([
__DIR__.'/../resources/views/components/file.blade.php' => resource_path('views/vendor/ozu/components/file.blade.php'),
__DIR__.'/../resources/views/components/image.blade.php' => resource_path('views/vendor/ozu/components/image.blade.php'),
__DIR__.'/../resources/views/components/embedded-image.blade.php' => resource_path('views/vendor/ozu/components/embedded-image.blade.php'),
__DIR__.'/../resources/views/components/video.blade.php' => resource_path('views/vendor/ozu/components/video.blade.php'),
__DIR__.'/../resources/views/components/quote.blade.php' => resource_path('views/vendor/ozu/components/quote.blade.php'),
], 'ozu-views');

Blade::componentNamespace('Code16\\OzuClient\\View\\Components\\Content', 'ozu-content');
Blade::component(Content::class, 'ozu-content');
Blade::component(Image::class, 'ozu-image');
Blade::component(EmbeddedImage::class, 'sharp-image');
Blade::component(File::class, 'ozu-file');
Blade::component(Video::class, 'ozu-content-video');
Blade::component(Quote::class, 'ozu-content-quote');

Paginator::currentPageResolver(function () {
return request()->route()->parameter('page');
Expand Down
44 changes: 44 additions & 0 deletions src/Support/Database/OzuSeeder.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace Code16\OzuClient\Support\Database;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Seeder;

class OzuSeeder extends Seeder
Expand All @@ -16,4 +17,47 @@ protected function clearMediaDirectory(): void
->each(fn ($file) => unlink($mediaDirectory.'/'.$file));
}
}

public function seedVideoEmbed(Model &$model, string $editorColumnName, ?string $videoUrl = null, ?string $legend = null): void
{
$editorContent = $model->$editorColumnName;
$randomVideoUrl = collect([
'https://www.youtube.com/watch?v=lXKDu6cdXLI',
'https://www.youtube.com/watch?v=ZBYZHeB67O4',
'https://www.youtube.com/watch?v=7nQ2oiVqKHw',
])->random();

$videoTag = sprintf(
'<x-ozu-content-video url="%s" %s ></x-ozu-content-video>',
$videoUrl ?? $randomVideoUrl,
$legend ? sprintf('legend="%s"', $legend) : ''
);

$model->$editorColumnName = $editorContent.' '.$videoTag;
if ($model->id !== null) {
$model->save();
}
}

public function seedQuoteEmbed(Model &$model, string $editorColumnName, ?string $quote = null, ?string $author = null): void
{
$editorContent = $model->$editorColumnName;
$randomQuote = collect([
['The only thing we have to fear is fear itself.', 'Franklin D. Roosevelt'],
['I think, therefore I am.', 'René Descartes'],
['Be the change that you wish to see in the world.', 'Gandhi'],
['In the middle of difficulty lies opportunity.', 'Albert Einstein'],
])->random();

$quoteTag = sprintf(
'<x-ozu-content-quote quote="%s" author="%s"></x-ozu-content-quote>',
$quote ?? $randomQuote[0],
$author ?? $randomQuote[1]
);

$model->$editorColumnName = $editorContent.' '.$quoteTag;
if ($model->id !== null) {
$model->save();
}
}
}
53 changes: 53 additions & 0 deletions src/View/Components/EmbeddedImage.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
<?php

namespace Code16\OzuClient\View\Components;

use Code16\OzuClient\Eloquent\Media;
use Code16\OzuClient\Exceptions\OzuClientException;
use Illuminate\Contracts\Filesystem\Filesystem;
use Illuminate\Support\Facades\Storage;
use Illuminate\View\Component;

class EmbeddedImage extends Component
{
public array $file;

public ?string $name = null;

public ?Media $fileModel = null;

public ?Filesystem $disk = null;

public bool $exists = false;

public function __construct(
string $file,
public ?string $legend = null,
public ?int $thumbnailWidth = null,
public ?int $thumbnailHeight = null,
) {
if ($this->file = json_decode(htmlspecialchars_decode($file), true)) {
$this->fileModel = Media::make([
'file_name' => $this->file['file_name'],
'disk' => $this->file['disk'] ?? null,
'filters' => $this->file['filters'] ?? null,
]);
$this->disk = Storage::disk($this->fileModel->disk);
$this->exists = $this->disk->exists($this->fileModel->file_name);
$this->name = $this->file['name'] ?? basename($this->fileModel->file_name);
}

if (! $this->thumbnailWidth && ! $this->thumbnailHeight) {
$this->thumbnailWidth = 500;
}
}

public function render(): \Illuminate\View\View
{
if (! $this->fileModel) {
throw new OzuClientException('Unable to render embedded image: invalid file');
}

return view('ozu::components.embedded-image');
}
}
24 changes: 24 additions & 0 deletions src/View/Components/Quote.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?php

namespace Code16\OzuClient\View\Components;

use Code16\Embed\ServiceContract;
use Illuminate\View\Component;

class Quote extends Component
{
protected ServiceContract $service;

public function __construct(
public string $quote,
public ?string $author = null,
) {}

public function render()
{
return view('ozu::components.quote', [
'quote' => $this->quote,
'author' => $this->author,
]);
}
}
29 changes: 29 additions & 0 deletions src/View/Components/Video.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?php

namespace Code16\OzuClient\View\Components;

use Code16\Embed\ServiceContract;
use Code16\Embed\ServiceFactory;
use Code16\Embed\ValueObjects\Url;
use Illuminate\View\Component;

class Video extends Component
{
protected ServiceContract $service;

public function __construct(
public string $url,
public ?string $legend = null,
) {
$url = new Url($this->url);
$this->service = ServiceFactory::getByUrl($url) ?: ServiceFactory::getFallback($url);
}

public function render()
{
return view('ozu::components.video', [
'url' => $this->url,
'legend' => $this->legend,
]);
}
}
Loading