refactor: extract logic

This commit is contained in:
Anthony Fu 2020-07-15 13:34:38 +08:00
parent 1c48271b1e
commit 68aef90254
7 changed files with 106 additions and 82 deletions

View File

@ -17,11 +17,11 @@
- Direct download
- Mobile friendly
- Powered by [Vite](https://github.com/vitejs/vite)
- Bookmarks
- Collection bookmarks
- Categories filters
### TODOs
- Tags filter
- Dark mode
- Full-offline mode - pack all the icons
- Electron client

View File

@ -44,7 +44,7 @@
<script lang='ts'>
import { defineComponent, ref, computed } from 'vue'
import Base64 from '../utils/base64'
import { getIconSnippet, getIconDownloadLink } from '../utils/icons'
import { previewColor } from '../store'
export default defineComponent({
@ -57,44 +57,19 @@ export default defineComponent({
setup(props) {
const copied = ref(false)
const getSvg = () =>
fetch(`https://api.iconify.design/${props.icon}.svg?inline=false&height=auto`)
.then(r => r.text())
const copy = async(type: string) => {
if (!props.icon) return
let text = props.icon
switch (type) {
case 'url':
text = `https://api.iconify.design/${props.icon}.svg`
break
case 'html':
text = `<span class="iconify" data-icon="${props.icon}" data-inline="false"></span>`
break
case 'css':
text = `background: url('https://api.iconify.design/${props.icon}.svg') no-repeat center center / contain;`
break
case 'svg':
text = await getSvg()
break
case 'data_url':
text = `data:image/svg+xml;base64,${Base64.encode(await getSvg())}`
break
}
const text = await getIconSnippet(props.icon, type)
if (!text)
return
await navigator.clipboard.writeText(text)
copied.value = true
setTimeout(() => {
copied.value = false
}, 2000)
}
const downlodUrl = computed(
() =>
`https://api.iconify.design/${props.icon}.svg?download=true&inline=false&height=auto`,
)
const downlodUrl = computed(() => getIconDownloadLink(props.icon))
return {
copy,

6
src/global.d.ts vendored Normal file
View File

@ -0,0 +1,6 @@
interface Window {
Iconify: {
getSVG: (icon: string) => string | false
getSVGObject: (icon: string) => any
}
}

49
src/hooks/search.ts Normal file
View File

@ -0,0 +1,49 @@
import Fuse from 'fuse.js'
import { ref, computed, markRaw, Ref, watch } from 'vue'
import { useThrottle } from '@vueuse/core'
import { collections, all } from '../data'
import { showCategories } from '../store'
export function useSearch(id: Ref<string>, defaultCategory = '', defaultSearch = '') {
const category = ref(defaultCategory)
const search = ref(defaultSearch)
const throttledSearch = useThrottle(search, 150)
const collection = computed(() => {
return id.value === 'all'
? all
: collections.find(c => c.id === id.value)!
})
const iconSource = computed(() => {
if (category.value && showCategories.value)
return collection.value.categories?.[category.value] || []
else
return collection.value.icons
})
const fuse = computed(() => {
const icons = iconSource.value.map(icon => ({ icon }))
return markRaw(new Fuse(icons, {
includeScore: false,
keys: ['icon'],
}))
})
const icons = computed(() => {
const searchString = throttledSearch.value.trim().toLowerCase()
if (!searchString)
return iconSource.value
else
return fuse.value.search(searchString).map(i => i.item.icon)
})
watch(id, () => { category.value = defaultCategory })
return {
collection,
search,
category,
icons,
}
}

View File

@ -6,6 +6,7 @@ export const previewColor = useStorage('explorer-preview-color', '#888')
export const listType = useStorage('explorer-list-type', 'grid')
export const showCategories = useStorage('explorer-show-categories', true)
export const favoritedCollections = useStorage<string[]>('explorer-fav-collections', [])
export const iconsCart = useStorage<string[]>('explorer-cart', [])
export function isFavorited(id: string) {
return favoritedCollections.value.includes(id)
@ -17,16 +18,15 @@ export function toggleFavorite(id: string) {
favoritedCollections.value.splice(index, 1)
else
favoritedCollections.value.push(id)
// eslint-disable-next-line no-self-assign
favoritedCollections.value = [...favoritedCollections.value]
}
export default {
themeColor,
iconSize,
previewColor,
listType,
favoritedCollections,
showCategories,
export function addToCart(id: string) {
if (!favoritedCollections.value.includes(id))
favoritedCollections.value.push(id)
}
export function removeFromCart(id: string) {
const index = favoritedCollections.value.indexOf(id)
if (index >= 0)
favoritedCollections.value.splice(index, 1)
}

29
src/utils/icons.ts Normal file
View File

@ -0,0 +1,29 @@
import Base64 from './base64'
const API_ENTRY = 'https://api.iconify.design'
export async function getSvg(icon: string) {
return window.Iconify.getSVG(icon) || await fetch(`${API_ENTRY}/${icon}.svg?inline=false&height=auto`).then(r => r.text()) || ''
}
export async function getIconSnippet(icon: string, type: string): Promise<string | undefined> {
if (!icon)
return
switch (type) {
case 'url':
return `${API_ENTRY}/${icon}.svg`
case 'html':
return `<span class="iconify" data-icon="${icon}" data-inline="false"></span>`
case 'css':
return `background: url('${API_ENTRY}/${icon}.svg') no-repeat center center / contain;`
case 'svg':
return await getSvg(icon)
case 'data_url':
return `data:image/svg+xml;base64,${Base64.encode(await getSvg(icon))}`
}
}
export function getIconDownloadLink(icon: string) {
return `${API_ENTRY}/${icon}.svg?download=true&inline=false&height=auto`
}

View File

@ -113,11 +113,9 @@
</template>
<script lang='ts'>
import { defineComponent, ref, computed, markRaw, watch } from 'vue'
import Fuse from 'fuse.js'
import { useThrottle } from '@vueuse/core'
import { collections, all } from '../data'
import { defineComponent, ref, toRefs } from 'vue'
import { iconSize, listType, showCategories } from '../store'
import { useSearch } from '../utils/search'
export default defineComponent({
props: {
@ -127,11 +125,11 @@ export default defineComponent({
},
},
setup(props) {
const search = ref('')
const throttledSearch = useThrottle(search, 150)
const { id } = toRefs(props)
const { search, icons, collection, category } = useSearch(id)
const selected = ref<string | null>(null)
const max = ref(200)
const category = ref('')
const toggleCategory = (cat: string) => {
if (category.value === cat)
@ -140,39 +138,6 @@ export default defineComponent({
category.value = cat
}
const collection = computed(() => {
return props.id === 'all'
? all
: collections.find(c => c.id === props.id)!
})
const iconSource = computed(() => {
if (category.value && showCategories.value)
return collection.value.categories?.[category.value] || []
else
return collection.value.icons
})
const fuse = computed(() => {
const icons = iconSource.value.map(icon => ({ icon }))
return markRaw(new Fuse(icons, {
includeScore: false,
keys: ['icon'],
}))
})
const icons = computed(() => {
const searchString = throttledSearch.value.trim().toLowerCase()
if (!searchString)
return iconSource.value
else
return fuse.value.search(searchString).map(i => i.item.icon)
})
watch(() => props.id, () => {
category.value = ''
})
const onSelect = (icon: string) => {
selected.value = icon
}