Skip to content

Commit

Permalink
feat: update
Browse files Browse the repository at this point in the history
  • Loading branch information
antfu committed Apr 8, 2024
1 parent 9b1a126 commit 9c42d63
Show file tree
Hide file tree
Showing 5 changed files with 93 additions and 154 deletions.
39 changes: 28 additions & 11 deletions src/components/IconDetail.vue
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { getIconSnippet, toComponentName } from '../utils/icons'
import { collections } from '../data'
import { activeMode, copyPreviewColor, getTransformedId, inBag, preferredCase, previewColor, pushRecentIcon, showCaseSelect, showHelp, toggleBag } from '../store'
import { Download } from '../utils/pack'
import { copyPng } from '../utils/copyPng'
import { dataUrlToBlob } from '../utils/dataUrlToBlob'
import { idCases } from '../utils/case'
const props = defineProps({
Expand Down Expand Up @@ -53,21 +53,32 @@ async function copyText(text?: string) {
return false
}
async function copyPng(dataUrl: string): Promise<boolean> {
try {
const blob = dataUrlToBlob(dataUrl)
const item = new ClipboardItem({ 'image/png': blob })
await navigator.clipboard.write([item])
return true
}
catch (e) {
console.error('Failed to copy png error', e)
return false
}
}
async function copy(type: string) {
pushRecentIcon(props.icon)
const svg = await getIconSnippet(
props.icon,
type === 'png' ? 'svg' : type,
true,
color.value,
)
const svg = await getIconSnippet(props.icon, type, true, color.value)
if (!svg)
return
emit('copy', type === 'png'
? await copyPng(svg, color.value)
: await copyText(svg))
emit(
'copy',
type === 'png'
? await copyPng(svg)
: await copyText(svg),
)
}
async function download(type: string) {
Expand All @@ -77,7 +88,9 @@ async function download(type: string) {
return
const ext = (type === 'solid' || type === 'qwik') ? 'tsx' : type
const name = `${toComponentName(props.icon)}.${ext}`
const blob = new Blob([text], { type: 'text/plain;charset=utf-8' })
const blob = type === 'png'
? dataUrlToBlob(text)
: new Blob([text], { type: 'text/plain;charset=utf-8' })
Download(blob, name)
}
Expand Down Expand Up @@ -276,6 +289,9 @@ const collection = computed(() => {
<button class="btn small mr-1 mb-1 opacity-75" @click="download('svg')">
SVG
</button>
<button class="btn small mr-1 mb-1 opacity-75" @click="download('png')">
PNG
</button>
<button class="btn small mr-1 mb-1 opacity-75" @click="download('vue')">
Vue
</button>
Expand Down Expand Up @@ -324,3 +340,4 @@ const collection = computed(() => {
</div>
</template>
../utils/copyPng
../utils/svgToPng
143 changes: 0 additions & 143 deletions src/utils/copyPng.ts

This file was deleted.

9 changes: 9 additions & 0 deletions src/utils/dataUrlToBlob.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
export function dataUrlToBlob(dataurl: string) {
const parts = dataurl.split(',')
const type = parts[0].split(':')[1].split(';')[0]
const base64 = atob(parts[1])
const arr = new Uint8Array(base64.length)
for (let i = 0; i < base64.length; i++)
arr[i] = base64.charCodeAt(i)
return new Blob([arr], { type })
}
3 changes: 3 additions & 0 deletions src/utils/icons.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { getTransformedId } from '../store'
import Base64 from './base64'
import { HtmlToJSX } from './htmlToJsx'
import { prettierCode } from './prettier'
import { svgToPngDataUrl } from './svgToPng'

const API_ENTRY = 'https://api.iconify.design'

Expand Down Expand Up @@ -151,6 +152,8 @@ export async function getIconSnippet(icon: string, type: string, snippet = true,
return `background: url('${url}') no-repeat center center / contain;`
case 'svg':
return await getSvg(icon, '32', color)
case 'png':
return await svgToPngDataUrl(await getSvg(icon, '32', color))
case 'svg-symbol':
return await getSvgSymbol(icon, '32', color)
case 'data_url':
Expand Down
53 changes: 53 additions & 0 deletions src/utils/svgToPng.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import { dataUrlToBlob } from './dataUrlToBlob'

Check failure on line 1 in src/utils/svgToPng.ts

View workflow job for this annotation

GitHub Actions / typecheck

'dataUrlToBlob' is declared but its value is never read.

Check failure on line 1 in src/utils/svgToPng.ts

View workflow job for this annotation

GitHub Actions / lint

'dataUrlToBlob' is defined but never used

export async function svgToPngDataUrl(svg: string) {
const scaleFactor = 16

const canvas = document.createElement('canvas')
const imgPreview = document.createElement('img')
imgPreview.setAttribute('style', 'position: absolute; top: -9999px')
document.body.appendChild(imgPreview)
const canvasCtx = canvas.getContext('2d')!

const svgBlob: Blob = new Blob([svg], { type: 'image/svg+xml;charset=utf-8' })
const svgDataUrl = URL.createObjectURL(svgBlob)

return new Promise<string>((resolve) => {
imgPreview.onload = async () => {
const img = new Image()
const dimensions: { width: number, height: number } = await getDimensions(imgPreview.src)

Object.assign(canvas, {
width: dimensions.width * scaleFactor,
height: dimensions.height * scaleFactor,
})

img.crossOrigin = 'anonymous'
img.src = imgPreview.src
img.onload = () => {
canvasCtx.drawImage(img, 0, 0, canvas.width, canvas.height)
const imgData = canvas.toDataURL('image/png')
resolve(imgData)
}

function getDimensions(
src: string,
): Promise<{ width: number, height: number }> {
return new Promise((resolve) => {
const _img = new Image()
_img.src = src
_img.onload = () => {
resolve({
width: _img.naturalWidth,
height: _img.naturalHeight,
})
}
})
}
}
imgPreview.src = svgDataUrl
})
.finally(() => {
document.body.removeChild(imgPreview)
})
}

0 comments on commit 9c42d63

Please sign in to comment.