Usage with Laravel
Before we you proceed make sure you have read the documentation for
Generating an API key
To generate an API key, see this section
For new projects
Starter kit
You can either use our Laravel - Tailwind CSS starter kit to get started or create a new project from scratch.
npx @lumenharbor/garchi-starter-kit -k laravel
From scratch
Create new Laravel app
composer create-project laravel/laravel garchi-app
Creating components
Let's create a simple page with sections (components) HeroContainer and Paragraph
<!-- resources/views/components/garchi/HeroContainer.blade.php -->
@props([
"title" => "",
"sub_heading" => "",
"image" => "",
"children" => []
])
<div {{$attributes->merge([
'class' => "relative bg-white"
])}}>
<div class="mx-auto max-w-7xl lg:grid lg:grid-cols-12 lg:gap-x-8 lg:px-8">
<div class="px-6 pb-24 pt-10 sm:pb-32 lg:col-span-7 lg:px-0 lg:pb-56 lg:pt-48 xl:col-span-6">
<div class="mx-auto max-w-2xl lg:mx-0">
<h1 class="mt-24 text-4xl font-bold tracking-tight text-gray-900 sm:mt-10 sm:text-6xl">
{{$title}}
</h1>
<p class="mt-6 text-lg leading-8 text-gray-600">
{{ $sub_heading }}
</p>
<div class="mt-10 flex items-center gap-x-6">
<!-- cta button to render component/garchi/LinkButton -->
<!-- this way you can render nested components -->
@foreach($children as $child)
<x-garchi.GarchiComponent :section="$child" />
@endforeach
</div>
</div>
</div>
<div class="relative lg:col-span-5 lg:-mr-8 xl:absolute xl:inset-0 xl:left-1/2 xl:mr-0">
<img class="aspect-[3/2] w-full bg-gray-50 object-cover lg:absolute lg:inset-0 lg:aspect-auto lg:h-full" src="{{ $image }}" alt="image" />
</div>
</div>
</div>
<!-- resources/views/components/garchi/Paragraph.blade.php -->
@props([
'content' => ""
])
<p {{$attributes->merge([
'class' => "text-gray-800"
])}}>
{{ $content }}
</p>
Create a GarchiComponent that will render all the components dynamically
<!-- resources/views/components/garchi/GarchiComponent.blade.php -->
@props([
'section' => null
])
@if(view()->exists($section['description']))
@include($section['description'], [
...$section['props'],
'children' => $section['children'],
'attributes' => new \Illuminate\View\ComponentAttributeBag($section['props'] ?? []),
])
@endif
Two things are worth pointing out here.
The view is resolved from the section template's description, so set that field to the view path of the component it belongs to - components.garchi.HeroContainer. See Section Template.
The attributes line is what makes the live editor work. Garchi sends data-garchi-* attributes along with your content in props, and they have to end up on the element your component renders - which is what {{ $attributes }} on the root tag does. A partial included with @include has no attribute bag of its own, so we build one and pass it in.
Every prop is put in the bag, so they all appear as attributes on the root element. If you would rather only the Garchi ones did, build the bag from those keys:
'attributes' => new \Illuminate\View\ComponentAttributeBag(
collect($section['props'])
->filter(fn ($value, $key) => str_starts_with($key, 'data-garchi-'))
->all()
),
In your route.php
If you want to catch all the routes, then add below in your routes/web.php
Route::get('{slug?}', [PageController::class, 'getPage'])->where('slug', '.*');
In your PageController.php
The PageController might look like this:
// App\Http\Controllers\PageController.php
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Http;
class PageController extends Controller
{
public function getPage(string $slug = "/")
{
$response = Http::withHeaders([
"Content-Type" => "application/json",
"Authorization" => "Bearer your_api_key"
])->post('https://garchi.co.uk/api/v2/page', [
"space_uid" => "c7ba17eb-4004-45ef-b5b3-1d557c5c85f4c34f4a69-3d08-444f-86e0-852b",
"mode" => "draft",
"slug" => $slug
]);
$page = $response->json();
return view('page', compact('page'));
}
}
Finally in your page.blade.php
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
@vite('resources/css/app.css')
<title>
{{$page['title']}}
</title>
</head>
<body>
<main>
<!-- Iterate throught each section and pass it to GarchiComponent to render
them dynamically -->
@foreach($page['sections'] as $section)
<x-garchi.GarchiComponent :section="$section" />
@endforeach
</main>
<script src="https://garchi.co.uk/script/index.es.js"></script>
</body>
</html>
If you notice, I have added a script tag. This makes the editor on the dashboard talk with your website: sections are outlined as you move over them, clicking one opens its fields, and what you type appears on the page. Without this script, the editor won't be able to talk with your website.
Garchi sends data-garchi-* attributes along with your content, so make sure each component puts them on the element it renders - {{ $attributes }} on the root tag.
See the live editor guide for the whole setup.
Now this page's content could be edited from the dashboard.
⚠️ You can also add inline CSS styles. You need to add them as a prop value to the section but it won't be responsive.
You can add HTML class attribute as a prop for a section with a value of a base class and combine it with inline CSS. Sky is the limit 🚀