Skip to content

Commit

Permalink
feat: add icon to makeswift
Browse files Browse the repository at this point in the history
  • Loading branch information
apledger committed Nov 10, 2024
1 parent ef3a240 commit 6ae2c2a
Show file tree
Hide file tree
Showing 3 changed files with 84 additions and 14 deletions.
7 changes: 4 additions & 3 deletions core/lib/makeswift/components.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import '~/makeswift/components/product-card/product-card.makeswift';
import '~/makeswift/components/featured-products-carousel/featured-products-carousel.makeswift';
import '~/makeswift/components/featured-products-list/featured-products-list.makeswift';
// import '~/makeswift/components/featured-products-carousel/featured-products-carousel.makeswift';
// import '~/makeswift/components/featured-products-list/featured-products-list.makeswift';
import '~/makeswift/components/header/register';
import '~/makeswift/components/footer/register';
import '~/makeswift/components/accordions/accordions.makeswift';
Expand All @@ -11,7 +11,8 @@ import '~/makeswift/components/card-carousel/card-carousel.makeswift';
import '~/makeswift/components/product-description/register';
import '~/makeswift/components/products-carousel/products-carousel.makeswift';
import '~/makeswift/components/products-list/products-list.makeswift';
import '~/makeswift/components/inline-email-form/inline-email-form.makeswift';
// import '~/makeswift/components/inline-email-form/inline-email-form.makeswift';
import '~/makeswift/components/icon/icon.makeswift';

import '~/makeswift/components/slideshow/slideshow.makeswift';
import '~/makeswift/components/featured-image/featured-image.makeswift';
Expand Down
51 changes: 51 additions & 0 deletions core/makeswift/components/icon/icon.makeswift.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { Checkbox, Color, Combobox, Number, Style } from '@makeswift/runtime/controls';

import { Icon, IconNames } from '@/vibes/soul/primitives/icon';
import { runtime } from '~/lib/makeswift/runtime';

// Helper function to convert kebab-case to Title Case
function toTitleCase(str: string): string {
return str
.split('-')
.map((word) => word.charAt(0).toUpperCase() + word.slice(1))
.join(' ');
}

runtime.registerComponent(
function MSIcon({ name = 'star', ...rest }) {
return <Icon {...rest} name={name} />;
},
{
type: 'icon',
label: 'Primitives / Icon',
props: {
className: Style({ properties: [Style.Margin] }),
size: Number({
label: 'Size',
defaultValue: 24,
}),
color: Color(),
name: Combobox({
label: 'Icon name',
getOptions(query) {
return IconNames.map((name) => ({
id: name,
value: name,
label: toTitleCase(name),
})).filter(
(option) => !query || option.label.toLowerCase().includes(query.toLowerCase()),
);
},
}),
strokeWidth: Number({
label: 'Stroke width',
defaultValue: 2,
step: 0.1,
}),
absoluteStrokeWidth: Checkbox({
label: 'Absolute stroke width',
defaultValue: false,
}),
},
},
);
40 changes: 29 additions & 11 deletions core/vibes/soul/primitives/icon/index.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,32 @@
import { icons } from 'lucide-react';
import clsx from 'clsx';
import { LucideProps } from 'lucide-react';
import dynamicIconImports from 'lucide-react/dynamicIconImports';
import { ComponentRef, forwardRef, lazy, Suspense, useMemo } from 'react';

export type IconProps = {
name: keyof typeof icons;
color?: string;
size?: number;
className?: string;
};
export type IconName = keyof typeof dynamicIconImports;

export const Icon = function Icon({ name, color, size, className }: IconProps) {
const LucideIcon = icons[name];
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
export const IconNames = Object.keys(dynamicIconImports) as IconName[];

return <LucideIcon color={color} size={size} strokeWidth={1} className={className} />;
};
type IconProps = Omit<LucideProps, 'ref'> & { name: IconName };

export const Icon = forwardRef<ComponentRef<'svg'>, IconProps>(
({ className, name, size = 24, ...props }, ref) => {
const LucideIcon = useMemo(() => lazy(dynamicIconImports[name]), [name]);

return (
<Suspense
fallback={
<div
className={clsx('animate-pulse rounded-full bg-contrast-100', className)}
style={{ width: size, height: size }}
/>
}
>
<LucideIcon ref={ref} {...props} className={className} size={size} />
</Suspense>
);
},
);

export default Icon;

0 comments on commit 6ae2c2a

Please sign in to comment.