Skip to content

Instantly share code, notes, and snippets.

@sammyaxe
Last active November 9, 2025 17:11
Show Gist options
  • Select an option

  • Save sammyaxe/cb8e0475be6417257344962d192ac956 to your computer and use it in GitHub Desktop.

Select an option

Save sammyaxe/cb8e0475be6417257344962d192ac956 to your computer and use it in GitHub Desktop.
Import FontAwesome Pro Icons into Flux. Must have downloaded the Font Awesome icons as SVG (improved based on @wojt-janowski gist)
<?php
declare(strict_types=1);
namespace App\Console\Commands;
use Illuminate\Console\Command;
use Illuminate\Filesystem\Filesystem;
use function Laravel\Prompts\confirm;
use function Laravel\Prompts\error;
use function Laravel\Prompts\info;
use function Laravel\Prompts\intro;
use function Laravel\Prompts\search;
use function Laravel\Prompts\select;
use function Laravel\Prompts\text;
use function Laravel\Prompts\warning;
class PublishFontAwesomeIconCommand extends Command
{
protected $signature = 'flux:fa-icon {icons?*} {--family=} {--manual : Manually type icon name instead of searching}';
protected $description = 'Import third-party icons from Font Awesome Pro.';
public function handle(): void
{
if (! $this->isFontAwesomeProInstalled()) {
error('Font Awesome Pro is not installed.');
warning('Please install Font Awesome Pro package: npm install @fortawesome/fontawesome-pro');
return;
}
$availableFamilies = $this->getAvailableFamilies();
if (empty($availableFamilies)) {
error('No Font Awesome icon families found in '.$this->getFontAwesomePath());
return;
}
$family = $this->option('family') ?: $this->selectFamily($availableFamilies);
if (! in_array($family, $availableFamilies)) {
error("Invalid family '{$family}'. Available families: ".implode(', ', $availableFamilies));
return;
}
if (count($icons = $this->argument('icons')) > 0) {
foreach ($icons as $icon) {
$this->publishIcon($icon, $family);
}
return;
}
intro('Need an icon not included in Heroicons?');
info('Search for the perfect icon at: https://fontawesome.com/icons');
info('Selected family: '.$family);
prompt:
if ($this->option('manual')) {
$icon = text(
label: 'Which icon would you like to import from Font Awesome Pro?',
required: 'An icon name is required.',
placeholder: 'e.g. arrow-left',
);
} else {
$icon = $this->searchIcon($family);
}
if ($icon) {
$this->publishIcon($icon, $family);
}
if (confirm('Would you like to import another icon?')) {
goto prompt;
}
}
protected function isFontAwesomeProInstalled(): bool
{
$basePath = base_path(config('services.fontawesome.path'));
return file_exists($basePath) && is_dir($basePath);
}
protected function getFontAwesomePath(): string
{
return base_path(config('services.fontawesome.path'));
}
protected function getAvailableFamilies(): array
{
$path = $this->getFontAwesomePath();
if (! is_dir($path)) {
return [];
}
$directories = array_filter(
scandir($path),
fn ($item) => $item !== '.' && $item !== '..' && is_dir($path.'/'.$item)
);
return array_values($directories);
}
protected function selectFamily(array $families): string
{
return select(
label: 'Which icon family would you like to use?',
options: $families,
default: in_array('regular', $families) ? 'regular' : $families[0]
);
}
protected function getAvailableIcons(string $family): array
{
$path = $this->getFontAwesomePath().'/'.$family;
if (! is_dir($path)) {
return [];
}
$files = array_filter(
scandir($path),
fn ($item) => str_ends_with($item, '.svg')
);
return array_map(
fn ($file) => str_replace('.svg', '', $file),
array_values($files)
);
}
protected function searchIcon(string $family): ?string
{
$icons = $this->getAvailableIcons($family);
if (empty($icons)) {
error('No icons found in '.$family.' family.');
return null;
}
info('Found '.count($icons).' icons in '.$family.' family.');
return search(
label: 'Search for an icon',
options: fn (string $value) => strlen($value) > 0
? array_values(array_filter($icons, fn ($icon) => str_contains($icon, $value)))
: $icons,
placeholder: 'Type to search...',
scroll: 15
);
}
protected function publishIcon(string $icon, string $pack): void
{
$filePath = base_path(config('services.fontawesome.path'))."/{$pack}/{$icon}.svg";
if (! file_exists($filePath)) {
error('Icon not found: '.$icon.' at path '.$filePath);
return;
}
$svg = file_get_contents($filePath);
$packDirectory = resource_path('views/flux/icon/'.$pack);
(new Filesystem)->ensureDirectoryExists($packDirectory);
$destinationAsFile = $packDirectory.'/'.$icon.'.blade.php';
file_put_contents($destinationAsFile, $this->generateIconBlade($svg));
info('Published icon: '.$destinationAsFile);
info('Usage: <flux:icon.'.str_replace('/', '.', $pack.'.'.$icon).'" />');
}
protected function generateIconBlade($svg)
{
$viewBox = '0 0 512 512'; // Default fallback
if (preg_match('/viewBox="([^"]+)"/', $svg, $matches)) {
$viewBox = $matches[1];
}
$svg = str($svg)
->replaceMatches('/<svg.*?>/s', <<<SVG
<svg
{{ \$attributes->class(\$classes) }}
data-flux-icon
xmlns="http://www.w3.org/2000/svg"
viewBox="{$viewBox}"
fill="currentColor"
stroke="none"
aria-hidden="true"
data-slot="icon"
>
SVG)->toString();
$stub = <<<'HTML'
{{-- Credit: Font Awesome (https://fontawesome.com) --}}
@props([
'variant' => 'outline',
])
@php
$classes = Flux::classes('shrink-0')
->add(match($variant) {
'outline' => '[:where(&)]:size-6',
'solid' => '[:where(&)]:size-6',
'mini' => '[:where(&)]:size-5',
'micro' => '[:where(&)]:size-4',
});
@endphp
[[INJECT:SVG]]
HTML;
return (string) str($stub)->replace('[[INJECT:SVG]]', $svg);
}
}
// ...specify the path where fontawsome svgs can be found, in my case I used NPM to install fontawesome pro
'fontawesome' => [
'path' => 'node_modules/@fortawesome/fontawesome-pro/svgs-full'
]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment