Skip to content

Commit

Permalink
Update iconify extension (#12942)
Browse files Browse the repository at this point in the history
- Feat: add copy svg file and color perference setting
- Initial commit
  • Loading branch information
kevinxo328 committed Jun 27, 2024
1 parent 637f64e commit 879655f
Show file tree
Hide file tree
Showing 7 changed files with 207 additions and 23 deletions.
7 changes: 7 additions & 0 deletions extensions/iconify/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
# Changelog

## [Improvements] - 2024-06-14

- Add "Copy SVG File" to actions and primaryActions
- Change "Copy SVG" to "Copy SVG String"
- Change "Paste SVG" to "Paste SVG String"
- Add "Monochromatic Icon Color" to primaryActions

## [Improvements] - 2024-03-27

- Add "Paste Name" to actions and primaryActions
Expand Down
19 changes: 18 additions & 1 deletion extensions/iconify/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

28 changes: 26 additions & 2 deletions extensions/iconify/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@
"contributors": [
"sxn",
"robert",
"kuddl"
"kuddl",
"kevinxo328"
],
"categories": [
"Design Tools",
Expand Down Expand Up @@ -53,17 +54,40 @@
"title": "Copy <svg> to Clipboard",
"value": "copy"
},
{
"title": "Copy Svg File to Clipboard",
"value": "copyFile"
},
{
"title": "Paste <name> to Active App",
"value": "pasteName"
}
]
},
{
"name": "iconColor",
"type": "dropdown",
"required": false,
"title": "Monochromatic Icon Color",
"description": "Icon color to use in monochromatic icons",
"default": "currentColor",
"data": [
{
"title": "Default",
"value": "currentColor"
},
{
"title": "White",
"value": "#ffffff"
}
]
}
],
"dependencies": {
"@raycast/api": "^1.48.0",
"axios": "^0.26.1",
"react-hooks-global-state": "^2.1.0"
"react-hooks-global-state": "^2.1.0",
"run-applescript": "^7.0.0"
},
"devDependencies": {
"@types/node": "^18.8.3",
Expand Down
53 changes: 43 additions & 10 deletions extensions/iconify/src/search-icons.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,21 @@ import {
Color,
Grid,
getPreferenceValues,
Icon as RaycastIcon,
showToast,
Toast,
} from '@raycast/api';
import { useState } from 'react';

import Service, { Icon } from './service';
import { toDataURI, toSvg, toURL } from './utils';
import { toDataURI, toSvg, toURL, copyToClipboard } from './utils';
import { primaryActionEnum, iconColorEnum } from './types/perferenceValues';

const { primaryAction } =
getPreferenceValues<{ primaryAction: 'paste' | 'copy' | 'pasteName' }>();
const { primaryAction } = getPreferenceValues<{
primaryAction: primaryActionEnum;
}>();

const { iconColor } = getPreferenceValues<{ iconColor: iconColorEnum }>();

const service = new Service();

Expand Down Expand Up @@ -50,14 +57,29 @@ function Command() {
{icons.map((icon) => {
const { set, id, body, width, height } = icon;
const { id: setId, title: setName } = set;
const svgIcon = toSvg(body, width, height);
const svgIcon = toSvg(body, width, height, iconColor);
const dataURIIcon = toDataURI(svgIcon);

const paste = <Action.Paste title="Paste SVG" content={svgIcon} />;
const paste = (
<Action.Paste title="Paste SVG String" content={svgIcon} />
);
const copy = (
<Action.CopyToClipboard title="Copy SVG" content={svgIcon} />
<Action.CopyToClipboard title="Copy SVG String" content={svgIcon} />
);
const copyFile = (
<Action
title="Copy SVG File"
icon={RaycastIcon.Clipboard}
onAction={async () => {
await copyToClipboard(svgIcon, id);
await showToast({
title: 'Copied to clipboard',
message: 'The SVG file has been copied to the clipboard.',
style: Toast.Style.Success,
});
}}
/>
);

const pasteName = setId && (
<Action.Paste title="Paste Name" content={`${setId}:${id}`} />
);
Expand All @@ -74,25 +96,36 @@ function Command() {
subtitle={setName}
actions={
<ActionPanel>
{primaryAction === 'paste' && (
{primaryAction === primaryActionEnum.paste && (
<>
{paste}
{copy}
{copyFile}
{pasteName}
</>
)}
{primaryAction === 'copy' && (
{primaryAction === primaryActionEnum.copy && (
<>
{copy}
{paste}
{copyFile}
{pasteName}
</>
)}
{primaryAction === 'pasteName' && (
{primaryAction === primaryActionEnum.pasteName && (
<>
{pasteName}
{paste}
{copy}
{copyFile}
</>
)}
{primaryAction === primaryActionEnum.copyFile && (
<>
{copyFile}
{copy}
{paste}
{pasteName}
</>
)}
<Action.CopyToClipboard
Expand Down
13 changes: 13 additions & 0 deletions extensions/iconify/src/types/perferenceValues.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
enum primaryActionEnum {
paste = 'paste',
copy = 'copy',
pasteName = 'pasteName',
copyFile = 'copyFile',
}

enum iconColorEnum {
default = 'currentColor',
white = '#ffffff',
}

export { primaryActionEnum, iconColorEnum };
57 changes: 55 additions & 2 deletions extensions/iconify/src/utils.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,17 @@
function toSvg(path: string, width: number, height: number): string {
import { Clipboard } from '@raycast/api';
import { runAppleScript } from 'run-applescript';
import { existsSync } from 'fs';
import os from 'os';

function toSvg(
path: string,
width: number,
height: number,
color: string,
): string {
// replace all currentColor pattern with the provided color
path = path.replace(/currentColor/g, color);

return `<svg width="${width}" height="${height}" viewBox="0 0 ${width} ${height}" xmlns="http://www.w3.org/2000/svg">${path}</svg>`;
}

Expand All @@ -10,4 +23,44 @@ function toURL(setId: string, id: string): string {
return `https://api.iconify.design/${setId}/${id}.svg`;
}

export { toSvg, toDataURI, toURL };
async function copyToClipboard(svgString: string, id: string) {
const osTempDirectory = os.tmpdir();
const fileTempDirectory = `${osTempDirectory}/raycast-iconify`;

if (!existsSync(fileTempDirectory)) {
await runAppleScript(`
set file_path to "${fileTempDirectory}"
set file_path to do shell script "echo " & quoted form of file_path & " | iconv -f utf-8 -t utf-8"
set file_path to file_path as text
do shell script "mkdir -p " & quoted form of file_path
`);
}
const selectedPath = fileTempDirectory;
const fixedPathName = selectedPath.endsWith('/')
? `${selectedPath}${id}.svg`
: `${selectedPath}/${id}.svg`;

const actualPath = fixedPathName;

const fixedSvgString = svgString.replace(/"/g, '\\"');
await runAppleScript(`
set svg to "${fixedSvgString}"
set svg to do shell script "echo " & quoted form of svg & " | iconv -f utf-8 -t utf-8"
set svg to svg as text
set file_path to "${actualPath}"
set file_path to do shell script "echo " & quoted form of file_path & " | iconv -f utf-8 -t utf-8"
set file_path to file_path as text
set fileRef to open for access file_path with write permission
write svg to fileRef
close access fileRef
`);

await Clipboard.copy({
file: actualPath,
});
}

export { toSvg, toDataURI, toURL, copyToClipboard };
53 changes: 45 additions & 8 deletions extensions/iconify/src/view-icons.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,22 @@ import {
Cache,
getPreferenceValues,
Icon as RaycastIcon,
showToast,
Toast,
} from '@raycast/api';
import { useEffect, useState } from 'react';
import { createGlobalState } from 'react-hooks-global-state';
import Service, { Icon, Set } from './service';
import { toDataURI, toSvg, toURL } from './utils';
import { copyToClipboard, toDataURI, toSvg, toURL } from './utils';
import { iconColorEnum, primaryActionEnum } from './types/perferenceValues';
import { promises } from 'dns';

const { primaryAction } = getPreferenceValues<{
primaryAction: 'paste' | 'copy' | 'pasteName';
primaryAction: primaryActionEnum;
}>();

const { iconColor } = getPreferenceValues<{ iconColor: iconColorEnum }>();

const service = new Service();
const cache = new Cache({
capacity: 50 * 1e6,
Expand Down Expand Up @@ -151,12 +157,31 @@ function Command() {
.slice(itemsPerPage * page, itemsPerPage * (page + 1))
.map((icon) => {
const { id, body, width, height } = icon;
const svgIcon = toSvg(body, width, height);
const svgIcon = toSvg(body, width, height, iconColor);
const dataURIIcon = toDataURI(svgIcon);

const paste = <Action.Paste title="Paste SVG" content={svgIcon} />;
const paste = (
<Action.Paste title="Paste SVG String" content={svgIcon} />
);
const copy = (
<Action.CopyToClipboard title="Copy SVG" content={svgIcon} />
<Action.CopyToClipboard
title="Copy SVG String"
content={svgIcon}
/>
);
const copyFile = (
<Action
title="Copy SVG File"
icon={RaycastIcon.Clipboard}
onAction={async () => {
await copyToClipboard(svgIcon, id);
await showToast({
title: 'Copied to clipboard',
message: 'The SVG file has been copied to the clipboard.',
style: Toast.Style.Success,
});
}}
/>
);
const pasteName = activeSetId && (
<Action.Paste
Expand All @@ -176,24 +201,36 @@ function Command() {
title={id}
actions={
<ActionPanel>
{primaryAction === 'paste' && (
{primaryAction === primaryActionEnum.paste && (
<>
{paste}
{copy}
{copyFile}
{pasteName}
</>
)}
{primaryAction === 'copy' && (
{primaryAction === primaryActionEnum.copy && (
<>
{copy}
{paste}
{copyFile}
{pasteName}
</>
)}
{primaryAction === 'pasteName' && (
{primaryAction === primaryActionEnum.pasteName && (
<>
{pasteName}
{paste}
{copy}
{copyFile}
</>
)}
{primaryAction === primaryActionEnum.copyFile && (
<>
{copyFile}
{copy}
{paste}
{pasteName}
</>
)}
{activeSetId && (
Expand Down

0 comments on commit 879655f

Please sign in to comment.