diff --git a/.ai/hotwire.blade.php b/resources/boost/guidelines/core.blade.php
similarity index 68%
rename from .ai/hotwire.blade.php
rename to resources/boost/guidelines/core.blade.php
index 91d70f2..96cd948 100644
--- a/.ai/hotwire.blade.php
+++ b/resources/boost/guidelines/core.blade.php
@@ -1,40 +1,36 @@
## Hotwire/Turbo Core Principles
- For standard application development, use Hotwire (Turbo + Stimulus)
-- Send HTML over the wire instead of JSON. Keep complexity on the server side.
-- Use Turbo Drive for smooth page transitions without full page reloads.
-- Decompose pages with Turbo Frames for independent sections that update separately.
-- Use Turbo Streams for real-time updates and dynamic content changes.
+- For most interactions, use regular links and form submits (Turbo Drive will make them fast and dynamic)
+- Decompose pages with Turbo Frames for independent sections that update separately
+- Use Turbo Streams for real-time updates and dynamic content changes
- Leverage Stimulus for progressive JavaScript enhancement when Turbo isn't sufficient (if Stimulus is available)
-- Prefer server-side template rendering and state management over client-side frameworks.
-- Enable "morphing" for seamless page updates that preserve scroll position and focus.
-- Use data attributes for JavaScript hooks
-- For more complex JavaScript dependencies, use Importmap Laravel
+- Prefer server-side template rendering and state management over client-side frameworks and state
+- Use data attributes for JavaScript hooks and CSS styling for as much as possible
-## Turbo Setup & Base Helpers
+## Base Helpers
@verbatim
- Turbo automatically handles page navigation, form submissions, and CSRF protection
-- Enable morphing in your layout (preserves DOM state during page updates): ``
-- Configure scroll behavior in your layout: ``
-- Enable both morphing and scroll preservation with a single component: ``
-- Generate unique DOM IDs from models: use function `dom_id($model, 'optional_prefix')` or Blade directive `@domid($model, 'optional_prefix')`
-- Generate CSS classes from models: use function `dom_class($model, 'optional_prefix')` or Blade directive `@domclass($model, 'optional_prefix')`
+- You may configure morphing and scroll preservation for a page (or layout) with: ``
+- Generate unique DOM IDs from models: use the `dom_id($model, 'optional_prefix')` global function or Blade directive `@domid($model, 'optional_prefix')`
+- Generate CSS classes from models: use the `dom_class($model, 'optional_prefix')` global function or Blade directive `@domclass($model, 'optional_prefix')`
@endverbatim
## Turbo Frames Best Practices
-- Use frames to decompose pages into independent sections that can update without full page reloads:
+- Use frames to decompose pages into independent sections that can update without full page reloads
+- Forms and links inside frames automatically target their containing frame (no configuration needed)
+- You may override the default frame target of a link or form with `[data-turbo-frame]` attribute:
+ - Use a frame's DOM ID to target a specific frame
+ - Use the value `_top` to break out of frames and navigate the full page
+- The `[:id]` prop accepts models and automatically generates DOM IDs for them
+- The `[:src]` prop accepts a URL to lazy-load from content. Optionally, you may pair it with a `[loading=lazy]` so it only loads when the element is visible in the viewport
+
+Example:
@verbatim
```blade
{{ $post->title }}
{{ $post->content }}
- Edit
-
- ```
-@endverbatim
-- Forms and links inside frames automatically target their containing frame (no configuration needed):
-@verbatim
- ```blade
-
+ Edit
```
@endverbatim
-- Override default frame targeting with `data-turbo-frame` attribute:
- - Use a frame's DOM ID to target a specific frame
- - Use `_top` to break out of frames and navigate the full page:
-@verbatim
- ```blade
- View Full Post
- ```
-@endverbatim
## Turbo Streams for Dynamic Updates
-- Return Turbo Stream responses from controllers to update specific page elements without full page reload:
+
+- You may return Turbo Streams from controllers after form submissions to update specific page elements (always check if the request accepts Turbo Streams for resilience)
@verbatim
public function store(Request $request)
@@ -64,6 +53,11 @@ public function store(Request $request)
return turbo_stream([
turbo_stream()->append('posts', view('posts.partials.post', ['post' => $post])),
turbo_stream()->update('create_post', view('posts.partials.form', ['post' => new Post()])),
+ // turbo_stream()->prepend('some_dom_id', view('posts.partials.post', ['post' => $post])),
+ // turbo_stream()->before('some_dom_id', view('...'))
+ // turbo_stream()->after('some_dom_id', view('...'))
+ // turbo_stream()->replace('some_dom_id', view('...'))
+ // turbo_stream()->remove('some_dom_id')
]);
}
@@ -71,46 +65,18 @@ public function store(Request $request)
}
@endverbatim
-- Available Turbo Stream actions for manipulating DOM elements:
+- Turbo Streams can also be broadcasted using Laravel Echo for real-time updates to all users connected to a channel:
@verbatim
-
- // Append content
- turbo_stream()->append($comment, view('comments.partials.comment', [
- 'comment' => $comment,
- ]));
-
- // Prepend content
- turbo_stream()->prepend($comment, view('comments.partials.comment', [
- 'comment' => $comment,
- ]));
-
- // Insert before
- turbo_stream()->before($comment, view('comments.partials.comment', [
- 'comment' => $comment,
- ]));
-
- // Insert after
- turbo_stream()->after($comment, view('comments.partials.comment', [
- 'comment' => $comment,
- ]));
-
- // Replace content (swaps the target element)
- turbo_stream()->replace($comment, view('comments.partials.comment', [
- 'comment' => $comment,
- ]));
-
- // Update content (keeps the target element and only updates its contents)
- turbo_stream()->update($comment, view('comments.partials.comment', [
- 'comment' => $comment,
- ]));
-
- // Removes content
- turbo_stream()->remove($comment);
+
+
-@endverbatim
-- Broadcast Turbo Streams over WebSockets to push real-time updates to all connected users:
-@verbatim
+
+ // Ensure the channel is defined in `routes/channels.php`:
+ Broadcast::channel(Post::class, function (User $user, Post $post) {
+ return $user->belongsToProject($post->project);
+ });
+
// Add the trait to the model:
use HotwiredLaravel\TurboLaravel\Models\Broadcasts;
@@ -120,9 +86,9 @@ class Post extends Model
}
// When you want to trigger the broadcasting from anywhere (including model events)...
- $post->broadcastAppend()->to('posts');
$post->broadcastUpdate();
$post->broadcastRemove();
+ $post->broadcastAppend()->to('posts');
@endverbatim
diff --git a/src/Commands/PublishBoostGuidelineCommand.php b/src/Commands/PublishBoostGuidelineCommand.php
deleted file mode 100644
index 67dfb49..0000000
--- a/src/Commands/PublishBoostGuidelineCommand.php
+++ /dev/null
@@ -1,23 +0,0 @@
-info('Boost guideline was published!');
- }
-}
diff --git a/src/TurboServiceProvider.php b/src/TurboServiceProvider.php
index dd6e86e..85790ce 100644
--- a/src/TurboServiceProvider.php
+++ b/src/TurboServiceProvider.php
@@ -5,7 +5,6 @@
use HotwiredLaravel\TurboLaravel\Broadcasters\Broadcaster;
use HotwiredLaravel\TurboLaravel\Broadcasters\LaravelBroadcaster;
use HotwiredLaravel\TurboLaravel\Broadcasting\Limiter;
-use HotwiredLaravel\TurboLaravel\Commands\PublishBoostGuidelineCommand;
use HotwiredLaravel\TurboLaravel\Commands\TurboInstallCommand;
use HotwiredLaravel\TurboLaravel\Facades\Turbo as TurboFacade;
use HotwiredLaravel\TurboLaravel\Http\Middleware\TurboMiddleware;
@@ -77,7 +76,6 @@ private function configurePublications(): void
$this->commands([
TurboInstallCommand::class,
- PublishBoostGuidelineCommand::class,
]);
}