Add Font Awesome icons and refactor tech icon handling

- Added Font Awesome dependencies for enhanced icon support.
- Refactored tech icon components to utilize Font Awesome icons instead of custom SVGs.
- Updated skill data files to include icon properties for various technologies.
- Removed obsolete tech icon files to streamline the codebase.
This commit is contained in:
Julien Froidefond
2025-08-20 16:24:07 +02:00
parent e6d4bbe13d
commit f74d4d3e87
27 changed files with 793 additions and 539 deletions

View File

@@ -1,77 +1,263 @@
"use client";
import Image from "next/image";
import { useState } from "react";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { IconDefinition } from "@fortawesome/fontawesome-svg-core";
import {
faReact,
faVuejs,
faJs,
faNodeJs,
faPython,
faJava,
faPhp,
faGolang,
faRust,
faDocker,
faAws,
faGoogle,
faMicrosoft,
faGitAlt,
faLinux,
faApple,
faWindows,
faAndroid,
faSwift,
faGithub,
faGitlab,
faBitbucket,
faFigma,
faSketch,
faWordpress,
faShopify,
faSlack,
faDiscord,
faDropbox,
faGoogle as faGoogleBrands,
faYarn,
faNpm,
faConfluence,
faJira,
faNotion,
} from "@fortawesome/free-brands-svg-icons";
interface TechIconExternalProps {
techId: string;
techName: string;
import {
faServer,
faDatabase,
faCloud,
faCode,
faCog,
faDesktop,
faMobile,
faShield,
faPalette,
faRocket,
faCube,
faPlug,
faTools,
faNetworkWired,
faLock,
faEye,
faSearch,
faBug,
faFlask,
faLayerGroup,
faSync,
faBolt,
faGlobe,
faHdd,
faMemory,
faSignal,
faTerminal,
faFileCode,
faPuzzlePiece,
faAtom,
faWrench,
faCodeBranch,
faBroadcastTower,
faInfinity,
faChartLine,
faUserShield,
faKey,
faSitemap,
faClipboardCheck,
faUsers,
faComment,
faHeadset,
faBookOpen,
faLightbulb,
faSpinner,
faBoxes,
faStream,
} from "@fortawesome/free-solid-svg-icons";
import {
Monitor,
Smartphone,
Shield,
BarChart3,
Palette,
Server,
} from "lucide-react";
interface TechIconProps {
iconName?: string;
className?: string;
size?: number;
fallbackText?: string;
}
// Service Simple Icons pour récupérer les icônes SVG
export function TechIconExternal({
techId,
techName,
className = "w-6 h-6",
size = 24,
}: TechIconExternalProps) {
const [imageError, setImageError] = useState(false);
// Mapping des icônes par nom
const ICON_MAP: Record<string, IconDefinition | React.ComponentType<any>> = {
// Brands
"fab-react": faReact,
"fab-vue": faVuejs,
"fab-js": faJs,
"fab-node": faNodeJs,
"fab-python": faPython,
"fab-java": faJava,
"fab-php": faPhp,
"fab-golang": faGolang,
"fab-rust": faRust,
"fab-docker": faDocker,
"fab-aws": faAws,
"fab-google": faGoogle,
"fab-microsoft": faMicrosoft,
"fab-git": faGitAlt,
"fab-linux": faLinux,
"fab-apple": faApple,
"fab-windows": faWindows,
"fab-android": faAndroid,
"fab-swift": faSwift,
"fab-github": faGithub,
"fab-gitlab": faGitlab,
"fab-bitbucket": faBitbucket,
"fab-figma": faFigma,
"fab-sketch": faSketch,
// URL pour Simple Icons
const simpleIconUrl = `https://cdn.jsdelivr.net/npm/simple-icons@v9/${techId}.svg`;
"fab-wordpress": faWordpress,
"fab-shopify": faShopify,
"fab-slack": faSlack,
"fab-discord": faDiscord,
"fab-dropbox": faDropbox,
"fab-yarn": faYarn,
"fab-npm": faNpm,
"fab-confluence": faConfluence,
"fab-jira": faJira,
"fab-notion": faNotion,
// URL pour DevIcons
const devIconUrl = `https://cdn.jsdelivr.net/gh/devicons/devicon/icons/${techId}/${techId}-original.svg`;
// Solid icons
"fas-server": faServer,
"fas-database": faDatabase,
"fas-cloud": faCloud,
"fas-code": faCode,
"fas-cog": faCog,
"fas-desktop": faDesktop,
"fas-mobile": faMobile,
"fas-shield": faShield,
if (imageError) {
// Fallback vers initiale si l'icône n'existe pas
"fas-palette": faPalette,
"fas-rocket": faRocket,
"fas-cube": faCube,
"fas-plug": faPlug,
"fas-tools": faTools,
"fas-network": faNetworkWired,
"fas-lock": faLock,
"fas-eye": faEye,
"fas-search": faSearch,
"fas-bug": faBug,
"fas-flask": faFlask,
"fas-layers": faLayerGroup,
"fas-sync": faSync,
"fas-bolt": faBolt,
"fas-globe": faGlobe,
"fas-hdd": faHdd,
"fas-memory": faMemory,
"fas-signal": faSignal,
"fas-terminal": faTerminal,
"fas-file-code": faFileCode,
"fas-puzzle": faPuzzlePiece,
"fas-atom": faAtom,
"fas-wrench": faWrench,
"fas-code-branch": faCodeBranch,
"fas-broadcast": faBroadcastTower,
"fas-infinity": faInfinity,
"fas-chart-line": faChartLine,
"fas-user-shield": faUserShield,
"fas-key": faKey,
"fas-sitemap": faSitemap,
"fas-check": faClipboardCheck,
"fas-users": faUsers,
"fas-comment": faComment,
"fas-headset": faHeadset,
"fas-book": faBookOpen,
"fas-lightbulb": faLightbulb,
"fas-spinner": faSpinner,
"fas-boxes": faBoxes,
"fas-stream": faStream,
// Lucide icons (pour certaines catégories ou icônes spéciales)
"lucide-monitor": Monitor,
"lucide-smartphone": Smartphone,
"lucide-shield": Shield,
"lucide-bar-chart": BarChart3,
"lucide-palette": Palette,
"lucide-server": Server,
};
export const TechIcon: React.FC<TechIconProps> = ({
iconName,
className = "w-5 h-5",
fallbackText,
}) => {
if (!iconName) {
return (
<div
className={`${className} bg-muted rounded flex items-center justify-center text-xs font-bold`}
>
{techName.charAt(0).toUpperCase()}
{fallbackText ? fallbackText.charAt(0).toUpperCase() : "?"}
</div>
);
}
return (
<Image
src={simpleIconUrl}
alt={`${techName} icon`}
width={size}
height={size}
className={className}
onError={() => setImageError(true)}
style={{ filter: "brightness(0) saturate(100%) invert(0.5)" }} // Pour s'adapter au thème
/>
);
}
const IconComponent = ICON_MAP[iconName];
// Mapping des IDs pour Simple Icons (ils utilisent parfois des noms différents)
export const SIMPLE_ICONS_MAPPING: Record<string, string> = {
react: "react",
vue: "vuedotjs",
typescript: "typescript",
nextjs: "nextdotjs",
nodejs: "nodedotjs",
python: "python",
express: "express",
postgresql: "postgresql",
mongodb: "mongodb",
redis: "redis",
docker: "docker",
kubernetes: "kubernetes",
aws: "amazonwebservices",
terraform: "terraform",
jenkins: "jenkins",
githubactions: "githubactions",
reactnative: "react",
flutter: "flutter",
swift: "swift",
kotlin: "kotlin",
expo: "expo",
tailwindcss: "tailwindcss",
webpack: "webpack",
if (!IconComponent) {
return (
<div
className={`${className} bg-muted rounded flex items-center justify-center text-xs font-bold`}
>
{fallbackText
? fallbackText.charAt(0).toUpperCase()
: iconName.charAt(0).toUpperCase()}
</div>
);
}
// Font Awesome icon (IconDefinition has prefix, iconName, and icon properties)
if (typeof IconComponent === "object" && "prefix" in IconComponent && "iconName" in IconComponent) {
return (
<FontAwesomeIcon
icon={IconComponent as IconDefinition}
className={className}
/>
);
}
// Lucide icon (React component)
if (typeof IconComponent === "function") {
const LucideIcon = IconComponent as React.ComponentType<any>;
return <LucideIcon className={className} />;
}
// Fallback if something goes wrong
return (
<div
className={`${className} bg-muted rounded flex items-center justify-center text-xs font-bold`}
>
{fallbackText
? fallbackText.charAt(0).toUpperCase()
: iconName.charAt(0).toUpperCase()}
</div>
);
};
export default TechIcon;