Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
120 changes: 120 additions & 0 deletions icons/brand-aistudio-icon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
import { forwardRef, useImperativeHandle, useCallback, useRef } from "react";
import type { AnimatedIconHandle, AnimatedIconProps } from "./types";
import { motion, useAnimate } from "motion/react";

const BrandAiStudioIcon = forwardRef<AnimatedIconHandle, AnimatedIconProps>(
({ size = 24, color = "currentColor", className = "" }, ref) => {
const [scope, animate] = useAnimate();

const frameRef = useRef<SVGGElement | null>(null);
const sparkRef = useRef<SVGGElement | null>(null);

const getSparkCenterOffset = () => {
if (!frameRef.current || !sparkRef.current) return { x: 0, y: 0 };

const frame = frameRef.current.getBBox();
const spark = sparkRef.current.getBBox();

const frameCenterX = frame.x + frame.width / 2;
const frameCenterY = frame.y + frame.height / 2;

const sparkCenterX = spark.x + spark.width / 2;
const sparkCenterY = spark.y + spark.height / 2;

return {
x: frameCenterX - sparkCenterX,
y: frameCenterY - sparkCenterY,
};
};

const start = useCallback(() => {
const { x, y } = getSparkCenterOffset();

// Move Gemini into the IDE
animate(
".google-spark",
{ x, y, scale: 0.9 },
{ duration: 0.35, ease: "easeInOut" },
);

// Pull the frame inward slightly so it "closes"
animate(
".google-frame",
{ scale: 0.94 },
{ duration: 0.35, ease: "easeInOut" },
);
}, [animate]);

const stop = useCallback(() => {
animate(
".google-spark",
{ x: 0, y: 0, scale: 1 },
{ duration: 0.3, ease: "easeInOut" },
);

animate(
".google-frame",
{ scale: 1 },
{ duration: 0.3, ease: "easeInOut" },
);
}, [animate]);

useImperativeHandle(
ref,
() => ({
startAnimation: start,
stopAnimation: stop,
}),
[start, stop],
);

return (
<motion.svg
ref={scope}
width={size}
height={size}
viewBox="0 0 24 24"
fill={color}
className={className}
xmlns="http://www.w3.org/2000/svg"
onHoverStart={start}
onHoverEnd={stop}
>
<title>Google AI Studio</title>

{/* Frame */}
<motion.g
ref={frameRef}
className="google-frame"
style={{
transformBox: "fill-box",
transformOrigin: "center",
}}
>
<path
fillRule="evenodd"
d="M9.921 4.196H6.328A2.705 2.705 0 003.623 6.9v11.362a2.705 2.705 0 002.705 2.705h11.363a2.705 2.705 0 002.705-2.705v-4.756l1.623-1.113v5.87a4.329 4.329 0 01-4.328 4.328H6.328A4.329 4.329 0 012 18.263V6.901a4.328 4.328 0 014.328-4.329h4.545l-.952 1.624z"
/>
</motion.g>

{/* Gemini sparkle */}
<motion.g
ref={sparkRef}
className="google-spark"
style={{
transformBox: "fill-box",
transformOrigin: "center",
}}
>
<path
fillRule="evenodd"
d="M17.82 0c.145 0 .268.104.299.246a7 7 0 001.9 3.484 7 7 0 003.485 1.901c.142.031.246.154.246.3a.308.308 0 01-.246.298A7 7 0 0020.02 8.13a7 7 0 00-1.912 3.535.297.297 0 01-.288.238.297.297 0 01-.288-.238A7 7 0 0015.62 8.13a7 7 0 00-3.535-1.912.297.297 0 01-.238-.288c0-.14.1-.26.238-.288A7 7 0 0015.62 3.73 7.001 7.001 0 0017.521.246.308.308 0 0117.82 0z"
/>
</motion.g>
</motion.svg>
);
},
);

BrandAiStudioIcon.displayName = "BrandAiStudioIcon";
export default BrandAiStudioIcon;
70 changes: 70 additions & 0 deletions icons/brand-anthropic-icon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import { forwardRef, useImperativeHandle, useCallback } from "react";
import type { AnimatedIconHandle, AnimatedIconProps } from "./types";
import { motion, useAnimate } from "motion/react";

const BrandAnthropicIcon = forwardRef<AnimatedIconHandle, AnimatedIconProps>(
({ size = 24, color = "currentColor", className = "" }, ref) => {
const [scope, animate] = useAnimate();

const start = useCallback(() => {
// Simple scale pulse on the slash
animate(
".anthropic-i",
{ rotateX: 22, skewX: -22, scaleY: 1.09 },
{ duration: 0.2, ease: "easeInOut" },
);
}, [animate]);

const stop = useCallback(() => {
animate(
".anthropic-i",
{ rotateX: 0, skewX: 0, scaleY: 1 },
{ duration: 0.2 },
);
}, [animate]);

useImperativeHandle(
ref,
() => ({
startAnimation: start,
stopAnimation: stop,
}),
[start, stop],
);

return (
<motion.svg
ref={scope}
width={size}
height={size}
viewBox="0 0 24 24"
fill={color}
className={className}
xmlns="http://www.w3.org/2000/svg"
onHoverStart={start}
onHoverEnd={stop}
>
<title>Anthropic</title>

{/* A */}
<motion.g
className="anthropic-a"
style={{ transformBox: "fill-box", transformOrigin: "center" }}
>
<path d="M6.57 3.52h3.767L16.906 20h-3.674l-1.343-3.461H5.017L3.673 20H0L6.57 3.522zm4.132 9.959L8.453 7.687 6.205 13.48H10.7z" />
</motion.g>

{/* Backslash */}
<motion.g
className="anthropic-i"
style={{ transformBox: "fill-box", transformOrigin: "center" }}
>
<path d="M13.827 3.52h3.603L24 20h-3.603l-6.57-16.48z" />
</motion.g>
</motion.svg>
);
},
);

BrandAnthropicIcon.displayName = "BrandAnthropicIcon";
export default BrandAnthropicIcon;
112 changes: 112 additions & 0 deletions icons/brand-lmstudio-icon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
import { forwardRef, useImperativeHandle, useCallback } from "react";
import type { AnimatedIconHandle, AnimatedIconProps } from "./types";
import { motion, useAnimate } from "motion/react";

const BrandLmStudioIcon = forwardRef<AnimatedIconHandle, AnimatedIconProps>(
(
{ size = 24, color = "currentColor", strokeWidth = 1, className = "" },
ref,
) => {
const [scope, animate] = useAnimate();

const lines = [
".lm-line-1",
".lm-line-2",
".lm-line-3",
".lm-line-4",
".lm-line-5",
".lm-line-6",
];

const start = useCallback(() => {
lines.forEach((line, i) => {
const strength = 1 + i * 0.06;
animate(
line,
{
scaleX: [1, strength, 0.9, strength * 0.95, 1],
},
{
duration: 1.4,
delay: i * 0.08,
ease: "easeInOut",
repeat: Infinity,
},
);
});
}, [animate]);

Check warning on line 37 in icons/brand-lmstudio-icon.tsx

View workflow job for this annotation

GitHub Actions / build

React Hook useCallback has a missing dependency: 'lines'. Either include it or remove the dependency array

const stop = useCallback(() => {
animate(
lines.join(", "),
{ scaleX: 1 },
{ duration: 0.2, ease: "easeOut" },
);
}, [animate]);

Check warning on line 45 in icons/brand-lmstudio-icon.tsx

View workflow job for this annotation

GitHub Actions / build

React Hook useCallback has a missing dependency: 'lines'. Either include it or remove the dependency array

useImperativeHandle(
ref,
() => ({
startAnimation: start,
stopAnimation: stop,
}),
[start, stop],
);

return (
<motion.svg
ref={scope}
width={size}
height={size}
viewBox="0 0 24 24"
fill={color}
strokeWidth={strokeWidth}
className={className}
xmlns="http://www.w3.org/2000/svg"
onHoverStart={start}
onHoverEnd={stop}
>
<title>LM Studio</title>

<motion.path
className="lm-line-1"
style={{ transformBox: "fill-box", transformOrigin: "center" }}
d="M2.84 2a1.273 1.273 0 100 2.547h10.287a1.274 1.274 0 000-2.547H2.84z"
/>

<motion.path
className="lm-line-2"
style={{ transformBox: "fill-box", transformOrigin: "center" }}
d="M7.935 5.33a1.273 1.273 0 000 2.548H18.22a1.274 1.274 0 000-2.547H7.935z"
/>

<motion.path
className="lm-line-3"
style={{ transformBox: "fill-box", transformOrigin: "center" }}
d="M3.624 9.935c0-.704.57-1.274 1.274-1.274h10.286a1.273 1.273 0 010 2.547H4.898c-.703 0-1.274-.57-1.274-1.273z"
/>

<motion.path
className="lm-line-4"
style={{ transformBox: "fill-box", transformOrigin: "center" }}
d="M1.273 12.188a1.273 1.273 0 100 2.547H11.56a1.274 1.274 0 000-2.547H1.273z"
/>

<motion.path
className="lm-line-5"
style={{ transformBox: "fill-box", transformOrigin: "center" }}
d="M3.624 16.792c0-.704.57-1.274 1.274-1.274h10.286a1.273 1.273 0 110 2.547H4.898c-.703 0-1.274-.57-1.274-1.273z"
/>

<motion.path
className="lm-line-6"
style={{ transformBox: "fill-box", transformOrigin: "center" }}
d="M13.029 18.849a1.273 1.273 0 100 2.547h5.78a1.273 1.273 0 100-2.547h-5.78z"
/>
</motion.svg>
);
},
);

BrandLmStudioIcon.displayName = "BrandLmStudioIcon";
export default BrandLmStudioIcon;
76 changes: 76 additions & 0 deletions icons/brand-midjourney-icon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import { forwardRef, useImperativeHandle, useCallback } from "react";
import type { AnimatedIconHandle, AnimatedIconProps } from "./types";
import { motion, useAnimate } from "motion/react";

const BrandMidJourneyIcon = forwardRef<AnimatedIconHandle, AnimatedIconProps>(
({ size = 24, color = "currentColor", className = "" }, ref) => {
const [scope, animate] = useAnimate();

const start = useCallback(() => {
// Boat rocking on the waves
animate(
".midjourney-sails",
{
rotate: [0, 2, -2, 0],
y: [0, -0.5, 0.5, 0],
},
{ duration: 2, repeat: Infinity, ease: "easeInOut" },
);

// Waves undulating
animate(
".midjourney-waves",
{
y: [0, 0.5, -0.5, 0],
scaleY: [1, 0.98, 1.02, 1],
},
{ duration: 1.5, repeat: Infinity, ease: "easeInOut" },
);
}, [animate]);

const stop = useCallback(() => {
animate(".midjourney-sails", { rotate: 0, y: 0 }, { duration: 0.3 });
animate(".midjourney-waves", { y: 0, scaleY: 1 }, { duration: 0.3 });
}, [animate]);

useImperativeHandle(ref, () => ({
startAnimation: start,
stopAnimation: stop,
}));
Comment on lines +36 to +39
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Add dependency array to useImperativeHandle.

The useImperativeHandle hook is missing its dependency array. Other brand icon components in this PR (e.g., BrandAiStudioIcon, BrandXaiIcon) include [start, stop] as dependencies. This ensures the imperative handle stays in sync if the callbacks change.

Proposed fix
-    useImperativeHandle(ref, () => ({
-      startAnimation: start,
-      stopAnimation: stop,
-    }));
+    useImperativeHandle(
+      ref,
+      () => ({
+        startAnimation: start,
+        stopAnimation: stop,
+      }),
+      [start, stop],
+    );
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
useImperativeHandle(ref, () => ({
startAnimation: start,
stopAnimation: stop,
}));
useImperativeHandle(
ref,
() => ({
startAnimation: start,
stopAnimation: stop,
}),
[start, stop],
);
🤖 Prompt for AI Agents
In @icons/brand-midjourney-icon.tsx around lines 36 - 39, The
useImperativeHandle call for ref is missing its dependency array, so update the
hook invocation to include [start, stop] as the dependency array to ensure the
imperative handle (startAnimation/stopAnimation) stays in sync when the start or
stop callbacks change; locate the useImperativeHandle(ref, () => ({
startAnimation: start, stopAnimation: stop })) and add the dependency array
[start, stop].


return (
<motion.svg
ref={scope}
width={size}
height={size}
viewBox="0 0 24 24"
fill={color}
fillRule="evenodd"
className={className}
xmlns="http://www.w3.org/2000/svg"
onHoverStart={start}
onHoverEnd={stop}
>
<title>Midjourney</title>

{/* Boat with sails */}
<motion.g
className="midjourney-sails"
style={{ transformBox: "fill-box", transformOrigin: "center bottom" }}
>
<path d="M3.653 2.026C6.073 3.06 8.69 4.941 10.8 7.258c2.46 2.7 4.109 5.828 4.637 9.149a.31.31 0 01-.421.335c-2.348-.945-4.54-1.258-6.59-1.02-1.739.2-3.337.792-4.816 1.703-.294.182-.62-.182-.405-.454 1.856-2.355 2.581-4.99 2.343-7.794-.195-2.292-1.031-4.61-2.284-6.709a.31.31 0 01.388-.442zM10.04 4.45c1.778.543 3.892 2.102 5.782 4.243 1.984 2.248 3.552 4.934 4.347 7.582a.31.31 0 01-.401.38l-.022-.01-.386-.154a10.594 10.594 0 00-.291-.112l-.016-.006c-.68-.247-1.199-.291-1.944-.101a.31.31 0 01-.375-.218C15.378 11.123 13.073 7.276 9.775 5c-.291-.201-.072-.653.266-.55zM4.273 2.996l.008.015c1.028 1.94 1.708 4.031 1.885 6.113.213 2.513-.31 4.906-1.673 7.092l-.02.031.003-.001c1.198-.581 2.47-.969 3.825-1.132l.055-.006c1.981-.23 4.083.029 6.309.837l.066.025-.007-.039c-.593-2.95-2.108-5.737-4.31-8.179l-.07-.078c-1.785-1.96-3.944-3.6-6.014-4.65l-.057-.028zm7.92 3.238l.048.048c2.237 2.295 3.885 5.431 4.974 9.191l.038.132.022-.004c.71-.133 1.284-.063 1.963.18l.027.01.066.024.046.018-.025-.073c-.811-2.307-2.208-4.62-3.936-6.594l-.058-.065c-1.02-1.155-2.103-2.132-3.15-2.856l-.015-.011z" />
</motion.g>

{/* Animated waves */}
<motion.path
className="midjourney-waves"
style={{ transformBox: "fill-box", transformOrigin: "center" }}
d="M22.369 17.676c-1.387 1.259-3.17 2.378-5.332 3.417.044.03.086.057.13.083l.018.01.019.012c.216.123.42.184.641.184.222 0 .426-.061.642-.184l.018-.011.019-.011c.14-.084.266-.178.492-.366l.178-.148c.279-.232.426-.342.625-.456.304-.174.612-.266.949-.266.337 0 .645.092.949.266l.023.014c.188.109.334.219.602.442l.178.148c.221.184.346.278.483.36l.028.017.018.01c.21.12.407.181.62.185h.022a.31.31 0 110 .618c-.337 0-.645-.092-.95-.266a3.137 3.137 0 01-.09-.054l-.022-.014-.022-.013-.02-.014a5.356 5.356 0 01-.49-.377l-.159-.132a3.836 3.836 0 00-.483-.36l-.027-.017-.019-.01a1.256 1.256 0 00-.641-.185c-.222 0-.426.061-.641.184l-.02.011-.018.011c-.14.084-.266.178-.492.366l-.158.132a5.125 5.125 0 01-.51.39l-.022.014-.022.014-.09.054a1.868 1.868 0 01-.95.266c-.337 0-.644-.092-.949-.266a3.137 3.137 0 01-.09-.054l-.022-.014-.022-.013-.026-.017a4.881 4.881 0 01-.425-.325.308.308 0 01-.12-.1l-.098-.081a3.836 3.836 0 00-.483-.36l-.027-.017-.019-.01a1.256 1.256 0 00-.641-.185c-.222 0-.426.061-.642.184l-.018.011-.019.011c-.14.084-.266.178-.492.366l-.158.132a5.125 5.125 0 01-.51.39l-.023.014-.022.014-.09.054A1.868 1.868 0 0112 22c-.337 0-.645-.092-.949-.266a3.137 3.137 0 01-.09-.054l-.022-.014-.022-.013-.021-.014a5.356 5.356 0 01-.49-.377l-.158-.132a3.836 3.836 0 00-.483-.36l-.028-.017-.018-.01a1.256 1.256 0 00-.642-.185c-.221 0-.425.061-.641.184l-.019.011-.018.011c-.141.084-.266.178-.492.366l-.158.132a5.125 5.125 0 01-.511.39l-.022.014-.022.014-.09.054a1.868 1.868 0 01-.986.264c-.746-.09-1.319-.38-1.89-.866l-.035-.03c-.047-.041-.118-.106-.192-.174l-.196-.181-.107-.1-.011-.01a1.531 1.531 0 00-.336-.253.313.313 0 00-.095-.03h-.005c-.119.022-.238.059-.361.11a.308.308 0 01-.077.061l-.008.005a.309.309 0 01-.126.034 5.66 5.66 0 00-.774.518l-.416.324-.055.043a6.542 6.542 0 01-.324.236c-.305.207-.552.315-.8.315a.31.31 0 01-.01-.618h.01c.09 0 .235-.062.438-.198l.04-.027c.077-.054.163-.117.27-.199l.385-.301.06-.047c.268-.206.506-.373.73-.505l-.633-1.21a.309.309 0 01.254-.451l20.287-1.305a.309.309 0 01.228.537zm-1.118.14L2.369 19.03l.423.809c.128-.045.256-.078.388-.1a.31.31 0 01.052-.005c.132 0 .26.032.386.093.153.073.294.179.483.35l.016.015.092.086.144.134.097.089c.065.06.125.114.16.144.485.418.948.658 1.554.736h.011a1.25 1.25 0 00.6-.172l.021-.011.019-.011.018-.011c.141-.084.266-.178.492-.366l.178-.148c.279-.232.426-.342.625-.456.305-.174.612-.266.95-.266.336 0 .644.092.948.266l.023.014c.188.109.335.219.603.442l.177.148c.222.184.346.278.484.36l.027.017.019.01c.215.124.42.185.641.185.222 0 .426-.061.641-.184l.019-.011.018-.011c.141-.084.267-.178.493-.366l.177-.148c.28-.232.427-.342.626-.456.304-.174.612-.266.949-.266.337 0 .644.092.949.266l.025.015c.187.109.334.22.603.443 1.867-.878 3.448-1.811 4.73-2.832l.02-.016z"
/>
</motion.svg>
);
},
);

BrandMidJourneyIcon.displayName = "BrandMidJourneyIcon";
export default BrandMidJourneyIcon;
Loading