Add a search to the showcase
tests / feature (8.5) (push) Successful in 1m14s
tests / lint (push) Successful in 1m1s
tests / feature (8.4) (push) Successful in 1m9s
tests / browser (chrome, chromium) (push) Successful in 3m22s
tests / browser (firefox, firefox) (push) Successful in 4m37s
tests / browser (safari, webkit) (push) Successful in 5m4s
tests / feature (8.5) (push) Successful in 1m14s
tests / lint (push) Successful in 1m1s
tests / feature (8.4) (push) Successful in 1m9s
tests / browser (chrome, chromium) (push) Successful in 3m22s
tests / browser (firefox, firefox) (push) Successful in 4m37s
tests / browser (safari, webkit) (push) Successful in 5m4s
A search app bar looks through every section, example and component, opens the section, or the example at its anchor on its page, and is reached from anywhere with / or Ctrl+K. Section pages now carry their own heading. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01V9NnLxnPp8vaaurb3Z1MFy
This commit is contained in:
co-authored by
Claude Opus 5
parent
7ebcb0565f
commit
51bf034b74
@@ -3,6 +3,7 @@
|
||||
namespace NoNameWeb\LivewireMaterial\Http\Controllers;
|
||||
|
||||
use Illuminate\Contracts\View\View;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use NoNameWeb\LivewireMaterial\Showcase\Sections;
|
||||
|
||||
/**
|
||||
@@ -22,4 +23,12 @@ class ShowcaseController
|
||||
'section' => $section,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* The search's index, fetched when the search is first focused rather than written into every page.
|
||||
*/
|
||||
public function search(): JsonResponse
|
||||
{
|
||||
return response()->json(Sections::index());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,11 +2,80 @@
|
||||
|
||||
namespace NoNameWeb\LivewireMaterial\Showcase;
|
||||
|
||||
use Illuminate\Support\Str;
|
||||
use NoNameWeb\LivewireMaterial\LivewireMaterialServiceProvider;
|
||||
|
||||
/**
|
||||
* The showcase's pages: one per section, grouped as the rail groups them.
|
||||
*/
|
||||
class Sections
|
||||
{
|
||||
/**
|
||||
* What the showcase's search looks through: every section, every example in it (linked to the
|
||||
* example's anchor), and every component, linked to the first section that introduces it.
|
||||
*
|
||||
* @return list<array{title: string, kind: string, context: string, url: string, keywords: string}>
|
||||
*/
|
||||
public static function index(): array
|
||||
{
|
||||
$sections = static::all();
|
||||
$components = collect(glob(LivewireMaterialServiceProvider::componentPath().'/*.blade.php'))
|
||||
->map(fn (string $path): string => basename($path, '.blade.php'))
|
||||
->all();
|
||||
$sources = collect($sections)->map(fn (array $section, string $key): string => (string) file_get_contents(static::path($key)));
|
||||
|
||||
$entries = [];
|
||||
$homes = [];
|
||||
|
||||
foreach ($sections as $key => $section) {
|
||||
$url = route('livewire-material.section', $key, false);
|
||||
|
||||
$entries[] = ['title' => $section['title'], 'kind' => 'Section', 'context' => $section['group'], 'url' => $url, 'keywords' => $section['description']];
|
||||
|
||||
preg_match_all("/^\\s*'((?:[^'\\\\]|\\\\.)*)'\\s*=>\\s*<<<'BLADE'/m", $sources[$key], $examples);
|
||||
|
||||
foreach ($examples[1] as $title) {
|
||||
$title = stripslashes($title);
|
||||
$entries[] = ['title' => $title, 'kind' => 'Example', 'context' => $section['title'], 'url' => $url.'#'.static::anchor($title), 'keywords' => ''];
|
||||
}
|
||||
}
|
||||
|
||||
// A section that names a component in its introduction is its home; otherwise the first that uses it.
|
||||
foreach (['/<x-([a-z0-9-]+)>/', '/<x-(?:livewire-material::)?([a-z0-9-]+)(?=[\\s\\/>])/'] as $pattern) {
|
||||
foreach ($sources as $key => $source) {
|
||||
preg_match_all($pattern, $source, $tags);
|
||||
|
||||
foreach ($tags[1] as $tag) {
|
||||
if (in_array($tag, $components, true)) {
|
||||
$homes[$tag] ??= $key;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($homes as $tag => $key) {
|
||||
$entries[] = ['title' => "<x-{$tag}>", 'kind' => 'Component', 'context' => $sections[$key]['title'], 'url' => route('livewire-material.section', $key, false), 'keywords' => str_replace('-', ' ', $tag)];
|
||||
}
|
||||
|
||||
return $entries;
|
||||
}
|
||||
|
||||
/**
|
||||
* The anchor of an example on its section's page.
|
||||
*/
|
||||
public static function anchor(string $title): string
|
||||
{
|
||||
return 'example-'.Str::slug($title);
|
||||
}
|
||||
|
||||
/**
|
||||
* A section's view file.
|
||||
*/
|
||||
public static function path(string $key): string
|
||||
{
|
||||
return dirname(__DIR__, 2).'/resources/views/showcase/sections/'.$key.'.blade.php';
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, array{title: string, icon: string, group: string, description: string}>
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user