mirror of https://github.com/kcal-app/kcal.git
Refactor Quill handling as a separate database column
This commit is contained in:
parent
99300d1b2d
commit
053c8305a1
|
@ -154,6 +154,7 @@ class RecipeController extends Controller
|
|||
$input = $request->validate([
|
||||
'name' => ['required', 'string'],
|
||||
'description' => ['nullable', 'string'],
|
||||
'description_delta' => ['nullable', 'string'],
|
||||
'servings' => ['required', 'numeric'],
|
||||
'time_prep' => ['nullable', 'numeric'],
|
||||
'time_active' => ['nullable', 'numeric'],
|
||||
|
@ -186,6 +187,7 @@ class RecipeController extends Controller
|
|||
$recipe->fill([
|
||||
'name' => Str::lower($input['name']),
|
||||
'description' => $input['description'],
|
||||
'description_delta' => $input['description_delta'],
|
||||
'servings' => (int) $input['servings'],
|
||||
'weight' => $input['weight'],
|
||||
'time_prep' => (int) $input['time_prep'],
|
||||
|
|
|
@ -28,7 +28,7 @@ class RecipeSchema extends SchemaProvider
|
|||
return [
|
||||
'slug' => $resource->slug,
|
||||
'name' => $resource->name,
|
||||
'description' => $resource->description_html,
|
||||
'description' => $resource->description,
|
||||
'time_prep' => $resource->time_prep,
|
||||
'time_active' => $resource->time_active,
|
||||
'time_total' => $resource->time_total,
|
||||
|
|
|
@ -62,7 +62,8 @@ use Spatie\Tags\HasTags;
|
|||
* @method static \Illuminate\Database\Eloquent\Builder|Recipe whereTimeActive($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|Recipe whereTimePrep($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|Recipe withUniqueSlugConstraints(\Illuminate\Database\Eloquent\Model $model, string $attribute, array $config, string $slug)
|
||||
* @property-read string $description_html
|
||||
* @property string|null $description_delta
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|Recipe whereDescriptionDelta($value)
|
||||
*/
|
||||
final class Recipe extends Model
|
||||
{
|
||||
|
@ -81,6 +82,7 @@ final class Recipe extends Model
|
|||
protected $fillable = [
|
||||
'name',
|
||||
'description',
|
||||
'description_delta',
|
||||
'time_prep',
|
||||
'time_active',
|
||||
'source',
|
||||
|
@ -114,7 +116,6 @@ final class Recipe extends Model
|
|||
* @inheritdoc
|
||||
*/
|
||||
protected $appends = [
|
||||
'description_html',
|
||||
'serving_weight',
|
||||
'time_total',
|
||||
];
|
||||
|
@ -127,30 +128,13 @@ final class Recipe extends Model
|
|||
return [
|
||||
'name' => $this->name,
|
||||
'tags' => $this->tags->pluck('name')->toArray(),
|
||||
'description' => $this->description_html,
|
||||
'description' => $this->description,
|
||||
'source' => $this->source,
|
||||
'created_at' => $this->created_at,
|
||||
'updated_at' => $this->updated_at,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get description as an HTML string.
|
||||
*/
|
||||
public function getDescriptionHtmlAttribute(): ?string {
|
||||
$description = $this->description;
|
||||
if (!empty($description)) {
|
||||
try {
|
||||
$quill = new Render($this->description);
|
||||
$description = $quill->render();
|
||||
} catch (\Exception $e) {
|
||||
// TODO: Log this or something.
|
||||
$description = null;
|
||||
}
|
||||
}
|
||||
return $description;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get total recipe time.
|
||||
*/
|
||||
|
|
|
@ -18,6 +18,7 @@ class CreateRecipesTable extends Migration
|
|||
$table->string('name');
|
||||
$table->string('slug')->unique();
|
||||
$table->longText('description')->nullable();
|
||||
$table->longText('description_delta')->nullable();
|
||||
$table->integer('time_prep')->nullable();
|
||||
$table->integer('time_active')->nullable();
|
||||
$table->string('source')->nullable();
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
<?php
|
||||
|
||||
use App\Models\Recipe;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class AddDescriptionDeltaToRecipes extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::table('recipes', function (Blueprint $table) {
|
||||
$table->longText('description_delta')->nullable()->after('description');
|
||||
});
|
||||
|
||||
foreach (Recipe::all() as $recipe) {
|
||||
if (empty($recipe->description)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Format as a basic Quill Delta.
|
||||
// See: https://quilljs.com/docs/delta/
|
||||
$delta = ['ops' => [['insert' => "{$recipe->description}\n"]]];
|
||||
$recipe->description_delta = json_encode($delta);
|
||||
$recipe->save();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::table('recipes', function (Blueprint $table) {
|
||||
$table->dropColumn('description_delta');
|
||||
});
|
||||
}
|
||||
}
|
|
@ -76,6 +76,10 @@
|
|||
:value="old('description', $recipe->description)" />
|
||||
|
||||
<div class="quill-editor"></div>
|
||||
|
||||
<x-inputs.input name="description_delta"
|
||||
type="hidden"
|
||||
:value="old('description_delta', $recipe->description_delta)" />
|
||||
</div>
|
||||
|
||||
<!-- Source -->
|
||||
|
@ -152,7 +156,7 @@
|
|||
theme: 'snow'
|
||||
});
|
||||
try {
|
||||
description.setContents(JSON.parse(document.querySelector('input[name="description"]').value));
|
||||
description.setContents(JSON.parse(document.querySelector('input[name="description_delta"]').value));
|
||||
} catch (e) {}
|
||||
|
||||
new Draggable.Sortable(document.querySelector('.ingredients'), {
|
||||
|
@ -195,8 +199,11 @@
|
|||
// Remove any hidden templates before form submit.
|
||||
document.querySelectorAll(':scope .entry-template').forEach(e => e.remove());
|
||||
|
||||
// Add description value to hidden field.
|
||||
document.querySelector('input[name="description"]').value = JSON.stringify(description.getContents());
|
||||
// Add description values to hidden fields.
|
||||
document.querySelector('input[name="description_delta"]').value = JSON.stringify(description.getContents());
|
||||
document.querySelector('input[name="description"]').value = description.root.innerHTML
|
||||
// Remove extraneous spaces from rendered result.
|
||||
.replaceAll('<p><br></p>', '');
|
||||
}
|
||||
</script>
|
||||
@endpush
|
||||
|
|
|
@ -20,15 +20,9 @@
|
|||
</x-slot>
|
||||
<div class="flex flex-col-reverse justify-between pb-4 sm:flex-row">
|
||||
<div x-data="{showNutrientsSummary: false}">
|
||||
@if($recipe->description_html)
|
||||
@if($recipe->description)
|
||||
<section class="mb-2 prose prose-lg md:prose-xl">
|
||||
{!! $recipe->description_html !!}
|
||||
</section>
|
||||
@endif
|
||||
@if(!$recipe->tags->isEmpty())
|
||||
<section class="mb-2 text-gray-700 text-sm">
|
||||
<h1 class="font-extrabold inline">Tags:</h1>
|
||||
{{ implode(', ', $recipe->tags->pluck('name')->all()) }}
|
||||
{!! $recipe->description !!}
|
||||
</section>
|
||||
@endif
|
||||
@if($recipe->time_total > 0)
|
||||
|
@ -138,4 +132,10 @@
|
|||
@endif
|
||||
</footer>
|
||||
@endif
|
||||
@if(!$recipe->tags->isEmpty())
|
||||
<section class="mb-2 text-gray-500 text-sm">
|
||||
<h1 class="font-extrabold inline">Tags:</h1>
|
||||
{{ implode(', ', $recipe->tags->pluck('name')->all()) }}
|
||||
</section>
|
||||
@endif
|
||||
</x-app-layout>
|
||||
|
|
Loading…
Reference in New Issue