refactor: integrate Remix Icon catalog for improved icon selection in NavbarLinkResource

This commit is contained in:
2025-12-03 20:03:57 -05:00
parent ab1ac20f57
commit 1b5b51d183
3 changed files with 120 additions and 0 deletions

18
.cursor/rules/core.mdc Normal file
View File

@@ -0,0 +1,18 @@
---
description:
globs:
alwaysApply: true
---
## Core Rules
You have two modes of operation:
1. Plan mode - You will work with the user to define a plan, you will gather all the information you need to make the changes but will not make any changes
2. Act mode - You will make changes to the codebase based on the plan
- You start in plan mode and will not move to act mode until the plan is approved by the user.
- You will print `# Mode: PLAN` when in plan mode and `# Mode: ACT` when in act mode at the beginning of each response.
- Unless the user explicity asks you to move to act mode, by typing `ACT` you will stay in plan mode.
- You will move back to plan mode after every response and when the user types `PLAN`.
- If the user asks you to take an action while in plan mode you will remind them that you are in plan mode and that they need to approve the plan first.
- When in plan mode always output the full updated plan in every response.

View File

@@ -4,6 +4,7 @@ namespace Paymenter\Extensions\Others\NavbarManager\Admin\Resources;
use Paymenter\Extensions\Others\NavbarManager\Models\NavbarLink; use Paymenter\Extensions\Others\NavbarManager\Models\NavbarLink;
use Paymenter\Extensions\Others\NavbarManager\Admin\Resources\NavbarLinkResource\Pages; use Paymenter\Extensions\Others\NavbarManager\Admin\Resources\NavbarLinkResource\Pages;
use Paymenter\Extensions\Others\NavbarManager\Support\RemixIconCatalog;
use Filament\Forms; use Filament\Forms;
use Filament\Forms\Form; use Filament\Forms\Form;
use Filament\Forms\Get; use Filament\Forms\Get;
@@ -272,6 +273,7 @@ class NavbarLinkResource extends Resource
->helperText('Use any Remix Icon (see https://github.com/Remix-Design/RemixIcon/blob/master/tags.json). Prefix is optional—we will auto-add `ri-`.') ->helperText('Use any Remix Icon (see https://github.com/Remix-Design/RemixIcon/blob/master/tags.json). Prefix is optional—we will auto-add `ri-`.')
->regex('/^(?:ri-)?[a-z0-9-]+$/i') ->regex('/^(?:ri-)?[a-z0-9-]+$/i')
->maxLength(80) ->maxLength(80)
->datalist(array_values(RemixIconCatalog::all()))
->dehydrateStateUsing(fn ($state) => self::normalizeIcon($state)), ->dehydrateStateUsing(fn ($state) => self::normalizeIcon($state)),
Forms\Components\Select::make('condition') Forms\Components\Select::make('condition')

View File

@@ -0,0 +1,100 @@
<?php
namespace Paymenter\Extensions\Others\NavbarManager\Support;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Str;
class RemixIconCatalog
{
protected const CACHE_KEY = 'navbar_manager_remix_icon_catalog';
protected const REMIX_TAGS_URL = 'https://raw.githubusercontent.com/Remix-Design/RemixIcon/master/tags.json';
/**
* @return array<string, string>
*/
public static function all(): array
{
return Cache::remember(self::CACHE_KEY, now()->addDay(), function () {
try {
$response = Http::timeout(8)->get(self::REMIX_TAGS_URL);
if (! $response->successful()) {
return self::fallback();
}
$json = $response->json();
if (! is_array($json)) {
return self::fallback();
}
$icons = [];
foreach ($json as $group) {
if (! is_array($group)) {
continue;
}
foreach ($group as $iconName => $unusedTags) {
if (! is_string($iconName)) {
continue;
}
$normalized = self::normalizeIconName($iconName);
$icons[$normalized] = $normalized;
}
}
ksort($icons);
return ! empty($icons) ? $icons : self::fallback();
} catch (\Throwable $e) {
\Log::warning('NavbarManager: Failed to load Remix icon catalog', [
'error' => $e->getMessage(),
]);
return self::fallback();
}
});
}
public static function clearCache(): void
{
Cache::forget(self::CACHE_KEY);
}
protected static function fallback(): array
{
$icons = [
'ri-home-line',
'ri-user-line',
'ri-settings-3-line',
'ri-dashboard-line',
'ri-menu-line',
'ri-link',
'ri-folder-line',
'ri-shopping-bag-3-line',
'ri-megaphone-line',
'ri-book-open-line',
'ri-file-text-line',
'ri-customer-service-2-line',
'ri-questionnaire-line',
'ri-information-line',
'ri-lock-line',
'ri-server-line',
];
return array_combine($icons, $icons);
}
protected static function normalizeIconName(string $icon): string
{
$icon = Str::lower(trim($icon));
if (! Str::startsWith($icon, 'ri-')) {
$icon = 'ri-' . ltrim($icon, '-');
}
return $icon;
}
}