🚀 Add copy as web component + use new `templates` utils

This commit is contained in:
pheralb 2025-02-04 23:36:47 +00:00
parent b9db482f0c
commit 313d293ba6

View File

@ -9,19 +9,24 @@
import { buttonStyles } from '@/ui/styles'; import { buttonStyles } from '@/ui/styles';
// Utils: // Utils:
import { getSvgContent } from '@/utils/getSvgContent'; import { cn } from '@/utils/cn';
import { getReactComponentCode } from '@/utils/getReactComponentCode';
import { clipboard } from '@/utils/clipboard'; import { clipboard } from '@/utils/clipboard';
import { copyToClipboard as figmaCopyToClipboard } from '@/figma/copy-to-clipboard'; import { copyToClipboard as figmaCopyToClipboard } from '@/figma/copy-to-clipboard';
import { cn } from '@/utils/cn';
import { componentTemplate } from '@/utils/componentTemplate'; // Templates:
import { generateAngularComponent } from '@/utils/generateAngularComponent'; import { getSource } from '@/templates/getSource';
import { getReactCode } from '@/templates/getReactCode';
import { getVueCode } from '@/templates/getVueCode';
import { getSvelteCode } from '@/templates/getSvelteCode';
import { getAngularCode } from '@/templates/getAngularCode';
import { getWebComponent } from '@/templates/getWebComponent';
//Icons: //Icons:
import ReactIcon from '@/components/icons/reactIcon.svelte'; import ReactIcon from '@/components/icons/reactIcon.svelte';
import VueIcon from '@/components/icons/vueIcon.svelte'; import VueIcon from '@/components/icons/vueIcon.svelte';
import SvelteIcon from '@/components/icons/svelteIcon.svelte'; import SvelteIcon from '@/components/icons/svelteIcon.svelte';
import AngularIcon from '@/components/icons/angularIcon.svelte'; import AngularIcon from '@/components/icons/angularIcon.svelte';
import WebComponentIcon from './icons/webComponentIcon.svelte';
// Props: // Props:
interface CopySVG { interface CopySVG {
@ -87,7 +92,9 @@
const svgUrlToCopy = getSvgUrl(); const svgUrlToCopy = getSvgUrl();
optionsOpen = false; optionsOpen = false;
const content = await getSvgContent(svgUrlToCopy); const content = await getSource({
url: svgUrlToCopy
});
if (isInFigma) { if (isInFigma) {
figmaCopyToClipboard(content); figmaCopyToClipboard(content);
@ -126,9 +133,11 @@
isLoading = true; isLoading = true;
const title = svgInfo.title.split(' ').join(''); const title = svgInfo.title.split(' ').join('');
const content = await getSvgContent(svgUrlToCopy); const content = await getSource({
url: svgUrlToCopy
});
const dataComponent = { code: content, typescript: tsx, name: title }; const dataComponent = { code: content, typescript: tsx, name: title };
const { data, error } = await getReactComponentCode(dataComponent); const { data, error } = await getReactCode(dataComponent);
if (error || !data) { if (error || !data) {
toast.error('Failed to fetch React component', { toast.error('Failed to fetch React component', {
@ -148,16 +157,21 @@
isLoading = false; isLoading = false;
}; };
// Copy as either Vue or Svelte component: // Copy SVG as Vue Component:
const copySvgComponent = async (ts: boolean, framework: 'Vue' | 'Svelte') => { const convertSvgVueComponent = async (ts: boolean) => {
try { try {
const svgUrlToCopy = getSvgUrl(); const svgUrlToCopy = getSvgUrl();
optionsOpen = false; optionsOpen = false;
const content = await getSvgContent(svgUrlToCopy); const content = await getSource({
url: svgUrlToCopy
});
const copyCode = componentTemplate(ts ? 'ts' : '', content, framework); const copyCode = getVueCode({
content: content,
lang: ts ? 'ts' : 'js'
});
if (copyCode) { if (copyCode) {
await clipboard(copyCode); await clipboard(copyCode);
@ -167,12 +181,45 @@
? svgInfo.category.sort().join(' - ') ? svgInfo.category.sort().join(' - ')
: svgInfo.category; : svgInfo.category;
toast.success(`Copied as ${framework} ${ts ? 'TS' : 'JS'} component`, { toast.success(`Copied as Vue ${ts ? 'TS' : 'JS'} component`, {
description: `${svgInfo?.title} - ${category}` description: `${svgInfo?.title} - ${category}`
}); });
} catch (err) { } catch (err) {
console.error(`Error copying ${framework} component:`, err); console.error(`Error copying Vue component:`, err);
toast.error(`Failed to copy ${framework} component`); toast.error(`Failed to copy Vue component`);
}
};
// Copy SVG as Svelte Component:
const convertSvgSvelteComponent = async (ts: boolean) => {
try {
const svgUrlToCopy = getSvgUrl();
optionsOpen = false;
const content = await getSource({
url: svgUrlToCopy
});
const copyCode = getSvelteCode({
content: content,
lang: ts ? 'ts' : 'js'
});
if (copyCode) {
await clipboard(copyCode);
}
const category = Array.isArray(svgInfo?.category)
? svgInfo.category.sort().join(' - ')
: svgInfo.category;
toast.success(`Copied as Svelte ${ts ? 'TS' : 'JS'} component`, {
description: `${svgInfo?.title} - ${category}`
});
} catch (err) {
console.error(`Error copying Svelte component:`, err);
toast.error(`Failed to copy Svelte component`);
} }
}; };
@ -183,7 +230,9 @@
const title = svgInfo.title.split(' ').join(''); const title = svgInfo.title.split(' ').join('');
const svgUrlToCopy = getSvgUrl(); const svgUrlToCopy = getSvgUrl();
const content = await getSvgContent(svgUrlToCopy); const content = await getSource({
url: svgUrlToCopy
});
if (!content) { if (!content) {
toast.error('Failed to fetch the SVG content', { toast.error('Failed to fetch the SVG content', {
@ -193,7 +242,11 @@
return; return;
} }
const angularComponent = generateAngularComponent(content, title); const angularComponent = getAngularCode({
componentName: title,
svgContent: content
});
await clipboard(angularComponent); await clipboard(angularComponent);
toast.success(`Copied as Standalone Angular component`, { toast.success(`Copied as Standalone Angular component`, {
@ -202,6 +255,39 @@
isLoading = false; isLoading = false;
}; };
// Copy SVG as Standalone Angular component:
const convertSvgWebComponent = async () => {
isLoading = true;
optionsOpen = false;
const title = svgInfo.title.split(' ').join('');
const svgUrlToCopy = getSvgUrl();
const content = await getSource({
url: svgUrlToCopy
});
if (!content) {
toast.error('Failed to fetch the SVG content', {
duration: 5000
});
isLoading = false;
return;
}
const webComponentCode = getWebComponent({
name: title,
content: content
});
await clipboard(webComponentCode);
toast.success(`Copied as Web Component`, {
description: `${svgInfo.title} - ${svgInfo.category}`
});
isLoading = false;
};
</script> </script>
<Popover.Root open={optionsOpen} onOpenChange={(isOpen) => (optionsOpen = isOpen)}> <Popover.Root open={optionsOpen} onOpenChange={(isOpen) => (optionsOpen = isOpen)}>
@ -218,13 +304,14 @@
{/if} {/if}
</Popover.Trigger> </Popover.Trigger>
<Popover.Content class="flex flex-col space-y-2 p-3" sideOffset={2}> <Popover.Content class="flex flex-col space-y-2 p-3" sideOffset={2}>
<Tabs.Root value="source" class="w-full"> <Tabs.Root value="source">
<Tabs.List> <Tabs.List>
<Tabs.Trigger value="source">Source</Tabs.Trigger> <Tabs.Trigger value="source">Source</Tabs.Trigger>
<Tabs.Trigger value="react">React</Tabs.Trigger> <Tabs.Trigger value="react">React</Tabs.Trigger>
<Tabs.Trigger value="vue">Vue</Tabs.Trigger> <Tabs.Trigger value="vue">Vue</Tabs.Trigger>
<Tabs.Trigger value="svelte">Svelte</Tabs.Trigger> <Tabs.Trigger value="svelte">Svelte</Tabs.Trigger>
<Tabs.Trigger value="angular">Angular</Tabs.Trigger> <Tabs.Trigger value="angular">Angular</Tabs.Trigger>
<Tabs.Trigger value="webcomponent">Web Component</Tabs.Trigger>
</Tabs.List> </Tabs.List>
<Tabs.Content value="source"> <Tabs.Content value="source">
<section class="flex flex-col space-y-2"> <section class="flex flex-col space-y-2">
@ -266,7 +353,7 @@
class={cn(buttonStyles, 'w-full rounded-md')} class={cn(buttonStyles, 'w-full rounded-md')}
title="Copy as Svelte component" title="Copy as Svelte component"
disabled={isLoading} disabled={isLoading}
onclick={() => copySvgComponent(false, 'Svelte')} onclick={() => convertSvgSvelteComponent(false)}
> >
<SvelteIcon iconSize={18} /> <SvelteIcon iconSize={18} />
<span>Copy JS</span> <span>Copy JS</span>
@ -276,7 +363,7 @@
class={cn(buttonStyles, 'w-full rounded-md')} class={cn(buttonStyles, 'w-full rounded-md')}
title="Copy as Svelte component" title="Copy as Svelte component"
disabled={isLoading} disabled={isLoading}
onclick={() => copySvgComponent(true, 'Svelte')} onclick={() => convertSvgSvelteComponent(true)}
> >
<SvelteIcon iconSize={18} /> <SvelteIcon iconSize={18} />
<span>Copy TS</span> <span>Copy TS</span>
@ -289,7 +376,7 @@
class={cn(buttonStyles, 'w-full rounded-md')} class={cn(buttonStyles, 'w-full rounded-md')}
title="Copy as Vue component" title="Copy as Vue component"
disabled={isLoading} disabled={isLoading}
onclick={() => copySvgComponent(false, 'Vue')} onclick={() => convertSvgVueComponent(false)}
> >
<VueIcon iconSize={18} /> <VueIcon iconSize={18} />
<span>Copy JS</span> <span>Copy JS</span>
@ -298,7 +385,7 @@
class={cn(buttonStyles, 'w-full rounded-md')} class={cn(buttonStyles, 'w-full rounded-md')}
title="Copy as Vue component" title="Copy as Vue component"
disabled={isLoading} disabled={isLoading}
onclick={() => copySvgComponent(true, 'Vue')} onclick={() => convertSvgVueComponent(true)}
> >
<VueIcon iconSize={18} /> <VueIcon iconSize={18} />
<span>Copy TS</span> <span>Copy TS</span>
@ -318,6 +405,19 @@
</button> </button>
</section> </section>
</Tabs.Content> </Tabs.Content>
<Tabs.Content value="webcomponent">
<section class="flex flex-col space-y-2">
<button
class={cn(buttonStyles, 'w-full rounded-md')}
title="Copy Web Component"
disabled={isLoading}
onclick={() => convertSvgWebComponent()}
>
<WebComponentIcon iconSize={18} />
<span>Copy Web Component</span>
</button>
</section>
</Tabs.Content>
</Tabs.Root> </Tabs.Root>
<div <div
class="mt-1 flex w-full items-center text-center text-[12px] text-neutral-600 dark:text-neutral-400" class="mt-1 flex w-full items-center text-center text-[12px] text-neutral-600 dark:text-neutral-400"