mirror of
https://github.com/antfu-collective/icones.git
synced 2026-01-09 07:40:49 +08:00
feat: svg download
This commit is contained in:
parent
5363cdffca
commit
0d191ee16f
@ -3,6 +3,7 @@
|
||||
"@antfu/eslint-config-vue"
|
||||
],
|
||||
"rules": {
|
||||
"vue/valid-v-model": "off"
|
||||
"vue/valid-v-model": "off",
|
||||
"vue/singleline-html-element-content-newline": "off"
|
||||
}
|
||||
}
|
||||
@ -6,6 +6,7 @@
|
||||
<title>Iconify Explorer</title>
|
||||
<script src="/lib/iconify.min.js"></script>
|
||||
<script src="/lib/svg-packer.js" defer></script>
|
||||
<script src="/lib/jszip.min.js" defer></script>
|
||||
</head>
|
||||
<body class="dragging">
|
||||
<div id="app"></div>
|
||||
|
||||
@ -17,14 +17,16 @@
|
||||
"vue-router": "next"
|
||||
},
|
||||
"devDependencies": {
|
||||
"svg-packer": "^0.0.3",
|
||||
"@iconify/iconify": "^1.0.7",
|
||||
"@antfu/eslint-config-vue": "^0.2.13",
|
||||
"@iconify/iconify": "^1.0.7",
|
||||
"@iconify/json": "^1.1.186",
|
||||
"@types/fs-extra": "^9.0.1",
|
||||
"@typescript-eslint/eslint-plugin": "^3.6.1",
|
||||
"@vue/compiler-sfc": "^3.0.0-beta.20",
|
||||
"eslint": "^7.4.0",
|
||||
"fs-extra": "^9.0.1",
|
||||
"jszip": "^3.5.0",
|
||||
"svg-packer": "^0.0.3",
|
||||
"tailwindcss-dark-mode": "^1.1.4",
|
||||
"ts-node": "^8.10.2",
|
||||
"typescript": "3.9.3",
|
||||
|
||||
51
pnpm-lock.yaml
generated
51
pnpm-lock.yaml
generated
@ -11,9 +11,11 @@ importers:
|
||||
'@iconify/iconify': 1.0.7
|
||||
'@iconify/json': 1.1.189
|
||||
'@types/fs-extra': 9.0.1
|
||||
'@typescript-eslint/eslint-plugin': 3.6.1_eslint@7.4.0+typescript@3.9.3
|
||||
'@vue/compiler-sfc': 3.0.0-beta.24_vue@3.0.0-beta.24
|
||||
eslint: 7.4.0
|
||||
fs-extra: 9.0.1
|
||||
jszip: 3.5.0
|
||||
svg-packer: 0.0.3
|
||||
tailwindcss-dark-mode: 1.1.5
|
||||
ts-node: 8.10.2_typescript@3.9.3
|
||||
@ -24,11 +26,13 @@ importers:
|
||||
'@iconify/iconify': ^1.0.7
|
||||
'@iconify/json': ^1.1.186
|
||||
'@types/fs-extra': ^9.0.1
|
||||
'@typescript-eslint/eslint-plugin': ^3.6.1
|
||||
'@vue/compiler-sfc': ^3.0.0-beta.20
|
||||
'@vueuse/core': ^4.0.0-beta.2
|
||||
eslint: ^7.4.0
|
||||
fs-extra: ^9.0.1
|
||||
fuse.js: ^6.3.0
|
||||
jszip: ^3.5.0
|
||||
svg-packer: ^0.0.3
|
||||
tailwindcss: ^1.4.6
|
||||
tailwindcss-dark-mode: ^1.1.4
|
||||
@ -1372,6 +1376,28 @@ packages:
|
||||
optional: true
|
||||
resolution:
|
||||
integrity: sha512-D52KwdgkjYc+fmTZKW7CZpH5ZBJREJKZXRrveMiRCmlzZ+Rw9wRVJ1JAmHQ9b/+Ehy1ZeaylofDB9wwXUt83wg==
|
||||
/@typescript-eslint/eslint-plugin/3.6.1_eslint@7.4.0+typescript@3.9.3:
|
||||
dependencies:
|
||||
'@typescript-eslint/experimental-utils': 3.6.1_eslint@7.4.0+typescript@3.9.3
|
||||
debug: 4.1.1
|
||||
eslint: 7.4.0
|
||||
functional-red-black-tree: 1.0.1
|
||||
regexpp: 3.1.0
|
||||
semver: 7.3.2
|
||||
tsutils: 3.17.1_typescript@3.9.3
|
||||
typescript: 3.9.3
|
||||
dev: true
|
||||
engines:
|
||||
node: ^10.12.0 || >=12.0.0
|
||||
peerDependencies:
|
||||
'@typescript-eslint/parser': ^3.0.0
|
||||
eslint: ^5.0.0 || ^6.0.0 || ^7.0.0
|
||||
typescript: '*'
|
||||
peerDependenciesMeta:
|
||||
typescript:
|
||||
optional: true
|
||||
resolution:
|
||||
integrity: sha512-06lfjo76naNeOMDl+mWG9Fh/a0UHKLGhin+mGaIw72FUMbMGBkdi/FEJmgEDzh4eE73KIYzHWvOCYJ0ak7nrJQ==
|
||||
/@typescript-eslint/experimental-utils/3.1.0_eslint@7.4.0+typescript@3.9.3:
|
||||
dependencies:
|
||||
'@types/json-schema': 7.0.5
|
||||
@ -5184,6 +5210,10 @@ packages:
|
||||
node: '>= 4'
|
||||
resolution:
|
||||
integrity: sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==
|
||||
/immediate/3.0.6:
|
||||
dev: true
|
||||
resolution:
|
||||
integrity: sha1-nbHb0Pr43m++D13V5Wu2BigN5ps=
|
||||
/import-cwd/2.1.0:
|
||||
dependencies:
|
||||
import-from: 2.1.0
|
||||
@ -5799,6 +5829,15 @@ packages:
|
||||
dev: true
|
||||
resolution:
|
||||
integrity: sha1-dET9hVHd8+XacZj+oMkbyDCMwnQ=
|
||||
/jszip/3.5.0:
|
||||
dependencies:
|
||||
lie: 3.3.0
|
||||
pako: 1.0.11
|
||||
readable-stream: 2.3.7
|
||||
set-immediate-shim: 1.0.1
|
||||
dev: true
|
||||
resolution:
|
||||
integrity: sha512-WRtu7TPCmYePR1nazfrtuF216cIVon/3GWOvHS9QR5bIwSbnxtdpma6un3jyGGNhHsKCSzn5Ypk+EkDRvTGiFA==
|
||||
/keyboardevent-from-electron-accelerator/2.0.0:
|
||||
dev: false
|
||||
resolution:
|
||||
@ -5973,6 +6012,12 @@ packages:
|
||||
node: '>= 0.8.0'
|
||||
resolution:
|
||||
integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==
|
||||
/lie/3.3.0:
|
||||
dependencies:
|
||||
immediate: 3.0.6
|
||||
dev: true
|
||||
resolution:
|
||||
integrity: sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==
|
||||
/lines-and-columns/1.1.6:
|
||||
dev: true
|
||||
resolution:
|
||||
@ -8173,6 +8218,12 @@ packages:
|
||||
dev: true
|
||||
resolution:
|
||||
integrity: sha1-BF+XgtARrppoA93TgrJDkrPYkPc=
|
||||
/set-immediate-shim/1.0.1:
|
||||
dev: true
|
||||
engines:
|
||||
node: '>=0.10.0'
|
||||
resolution:
|
||||
integrity: sha1-SysbJ+uAip+NzEgaWOXlb1mfP2E=
|
||||
/set-value/2.0.1:
|
||||
dependencies:
|
||||
extend-shallow: 2.0.1
|
||||
|
||||
@ -56,11 +56,16 @@ async function copyLibs() {
|
||||
path.join(modules, 'svg-packer/dist/index.browser.js'),
|
||||
path.join(out, 'lib/svg-packer.js')
|
||||
)
|
||||
|
||||
await fs.copy(
|
||||
path.join(modules, 'jszip/dist/jszip.min.js'),
|
||||
path.join(out, 'lib/jszip.min.js')
|
||||
)
|
||||
}
|
||||
|
||||
async function prepare() {
|
||||
await prepareJSON()
|
||||
await copyLibs()
|
||||
await prepareJSON()
|
||||
}
|
||||
|
||||
prepare()
|
||||
|
||||
111
src/components/ActionsMenu.vue
Normal file
111
src/components/ActionsMenu.vue
Normal file
@ -0,0 +1,111 @@
|
||||
<template>
|
||||
<div class="px-1 text-xl text-gray-800 flex">
|
||||
<div class="relative w-4">
|
||||
<IconButton class="ml-3 text-xl" active icon="carbon:overflow-menu-vertical" title="Menu" />
|
||||
<select v-model="menu" class="absolute text-base top-0 bottom-0 left-0 right-0 opacity-0">
|
||||
<optgroup label="Size">
|
||||
<option value="large">Large Icons</option>
|
||||
<option value="small">Small Icons</option>
|
||||
<option value="list">List</option>
|
||||
</optgroup>
|
||||
<optgroup label="Actions">
|
||||
<option value="select">Select mutiple</option>
|
||||
</optgroup>
|
||||
<optgroup label="Downloads">
|
||||
<option value="download_iconfont">Iconfont</option>
|
||||
<option value="download_svgs">SVGs Zip</option>
|
||||
</optgroup>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang='ts'>
|
||||
import { defineComponent, PropType, ref, watch, nextTick } from 'vue'
|
||||
import { iconSize, listType, selectingMode } from '../store'
|
||||
import { CollectionMeta, install } from '../data'
|
||||
import { PackIconFont, PackSvgZip } from '../utils/pack'
|
||||
|
||||
export default defineComponent({
|
||||
props: {
|
||||
collection: {
|
||||
type: Object as PropType<CollectionMeta>,
|
||||
},
|
||||
},
|
||||
setup(props) {
|
||||
const menu = ref(
|
||||
listType.value === 'list'
|
||||
? 'list'
|
||||
: iconSize.value === '2xl'
|
||||
? 'small'
|
||||
: 'large',
|
||||
)
|
||||
|
||||
const packIconFont = async() => {
|
||||
if (!props.collection)
|
||||
return
|
||||
|
||||
// TODO: prompt user about size and time
|
||||
// TODO: loading status
|
||||
await install(props.collection.id)
|
||||
await PackIconFont(
|
||||
props.collection.icons.map(i => `${props.collection!.id}:${i}`),
|
||||
{ fontName: props.collection.name, fileName: props.collection.id },
|
||||
)
|
||||
}
|
||||
|
||||
const packSvgs = async() => {
|
||||
if (!props.collection)
|
||||
return
|
||||
|
||||
// TODO: prompt user about size and time
|
||||
// TODO: loading status
|
||||
await install(props.collection.id)
|
||||
await PackSvgZip(
|
||||
props.collection.icons,
|
||||
props.collection.id,
|
||||
)
|
||||
}
|
||||
|
||||
watch(
|
||||
menu,
|
||||
async(current, prev) => {
|
||||
switch (current) {
|
||||
case 'small':
|
||||
iconSize.value = '2xl'
|
||||
listType.value = 'grid'
|
||||
return
|
||||
case 'large':
|
||||
iconSize.value = '4xl'
|
||||
listType.value = 'grid'
|
||||
return
|
||||
case 'list':
|
||||
iconSize.value = '3xl'
|
||||
listType.value = 'list'
|
||||
return
|
||||
case 'select':
|
||||
selectingMode.value = !selectingMode.value
|
||||
break
|
||||
case 'download_iconfont':
|
||||
packIconFont()
|
||||
break
|
||||
case 'download_svgs':
|
||||
packSvgs()
|
||||
break
|
||||
}
|
||||
|
||||
await nextTick()
|
||||
menu.value = prev
|
||||
},
|
||||
{ flush: 'pre' },
|
||||
)
|
||||
|
||||
return {
|
||||
menu,
|
||||
listType,
|
||||
iconSize,
|
||||
selectingMode,
|
||||
}
|
||||
},
|
||||
})
|
||||
</script>
|
||||
@ -11,16 +11,16 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex-auto" />
|
||||
<IconButton v-if='bags.length' class="text-xl mr-4 flex-none" icon="carbon:delete" @click="clear" />
|
||||
<IconButton v-if="bags.length" class="text-xl mr-4 flex-none" icon="carbon:delete" @click="clear" />
|
||||
<IconButton class="text-2xl flex-none" icon="carbon:close" @click="$emit('close')" />
|
||||
</div>
|
||||
<template v-if="bags.length">
|
||||
<div class="flex-auto overflow-y-auto py-3 px-1">
|
||||
<Icons :icons="bags" />
|
||||
<Icons :icons="bags" style="color: #666" />
|
||||
</div>
|
||||
<div class="flex-none border-t border-gray-200 py-3 px-6 text-2xl text-gray-700">
|
||||
<IconButton class="p-1 cursor-pointer" icon="carbon:function" text="Generate Icon Fonts" :active="true" @click="pack()" />
|
||||
<IconButton class="p-1 cursor-pointer" icon="carbon:download" text="Download All SVGs" :active="true" @click="wip" />
|
||||
<IconButton class="p-1 cursor-pointer" icon="carbon:function" text="Generate Icon Fonts" :active="true" @click="packIconFont" />
|
||||
<IconButton class="p-1 cursor-pointer" icon="carbon:download" text="Download SVGs Zip" :active="true" @click="packSvgs" />
|
||||
</div>
|
||||
</template>
|
||||
<template v-else>
|
||||
@ -34,7 +34,7 @@
|
||||
<script lang='ts'>
|
||||
import { defineComponent } from 'vue'
|
||||
import { bags, clearBag } from '../store'
|
||||
import { PackIconsInBag } from '../utils/pack'
|
||||
import { PackIconFont, PackSvgZip } from '../utils/pack'
|
||||
|
||||
export default defineComponent({
|
||||
setup() {
|
||||
@ -44,12 +44,26 @@ export default defineComponent({
|
||||
clearBag()
|
||||
}
|
||||
|
||||
const packIconFont = async() => {
|
||||
// TODO: customzie
|
||||
await PackIconFont(
|
||||
bags.value,
|
||||
)
|
||||
}
|
||||
|
||||
const packSvgs = async() => {
|
||||
// TODO: customzie
|
||||
await PackSvgZip(
|
||||
bags.value.map(i => i.replace(':', '-')),
|
||||
'iconify-bags',
|
||||
)
|
||||
}
|
||||
|
||||
return {
|
||||
clear,
|
||||
bags,
|
||||
pack: PackIconsInBag,
|
||||
// eslint-disable-next-line no-alert
|
||||
wip: () => alert('WIP'),
|
||||
packIconFont,
|
||||
packSvgs,
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div class="border-r border-gray-200">
|
||||
<NavPlaceholder/>
|
||||
<NavPlaceholder class="mb-4"/>
|
||||
<!-- Collections -->
|
||||
<router-link
|
||||
v-for="collection in collections"
|
||||
|
||||
@ -8,7 +8,7 @@
|
||||
/>
|
||||
<h1 class="text-base font-light py-2 m-auto flex-auto text-center">
|
||||
<span v-if="collection"></span>
|
||||
<template v-show="$route.path === '/'">
|
||||
<template v-if="$route.path === '/'">
|
||||
<b class="font-bold">Iconify</b>Explorer
|
||||
</template>
|
||||
</h1>
|
||||
|
||||
@ -1,70 +0,0 @@
|
||||
<template>
|
||||
<div class="px-1 text-xl text-gray-800 flex">
|
||||
<IconButton
|
||||
class="ml-3"
|
||||
icon="carbon:checkbox-checked"
|
||||
:active="selectingMode"
|
||||
@click="selectingMode = !selectingMode"
|
||||
/>
|
||||
<div class="mr-1 ml-4 h-full m-auto bg-gray-200 hidden sm:block" style="width:1px;" />
|
||||
<IconButton
|
||||
class="ml-3 hidden sm:block"
|
||||
icon="carbon:hinton-plot"
|
||||
title="Small"
|
||||
:active="listType === 'grid' && iconSize === '2xl'"
|
||||
@click="()=>setGrid('small')"
|
||||
/>
|
||||
<IconButton
|
||||
class="ml-3 hidden sm:block"
|
||||
icon="carbon:app-switcher"
|
||||
title="Large"
|
||||
:active="listType === 'grid' && iconSize === '4xl'"
|
||||
@click="()=>setGrid('large')"
|
||||
/>
|
||||
<IconButton
|
||||
class="ml-3 hidden sm:block"
|
||||
icon="carbon:list"
|
||||
title="List View"
|
||||
:active="listType === 'list'"
|
||||
@click="()=>setGrid('list')"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang='ts'>
|
||||
import { defineComponent, PropType } from 'vue'
|
||||
import { iconSize, listType, selectingMode } from '../store'
|
||||
import { CollectionMeta } from '../data'
|
||||
|
||||
export default defineComponent({
|
||||
props: {
|
||||
collection: {
|
||||
type: Object as PropType<CollectionMeta>
|
||||
}
|
||||
},
|
||||
setup() {
|
||||
const setGrid = (type: string) => {
|
||||
switch (type) {
|
||||
case 'small':
|
||||
iconSize.value = '2xl'
|
||||
listType.value = 'grid'
|
||||
break
|
||||
case 'large':
|
||||
iconSize.value = '4xl'
|
||||
listType.value = 'grid'
|
||||
break
|
||||
default:
|
||||
iconSize.value = '3xl'
|
||||
listType.value = 'list'
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
setGrid,
|
||||
listType,
|
||||
iconSize,
|
||||
selectingMode
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
15
src/global.d.ts
vendored
15
src/global.d.ts
vendored
@ -1,8 +1,11 @@
|
||||
interface Window {
|
||||
Iconify: {
|
||||
getSVG: (icon: string) => string | false
|
||||
getSVGObject: (icon: string) => any
|
||||
addCollection: (data: any) => void
|
||||
/* eslint-disable no-undef */
|
||||
import type JSZip from 'jszip'
|
||||
import type Iconify from '@iconify/iconify'
|
||||
|
||||
declare global {
|
||||
interface Window {
|
||||
Iconify: typeof Iconify
|
||||
JSZip: JSZip
|
||||
SvgPacker: (options: any) => Promise<any>
|
||||
}
|
||||
SvgPacker: (options: any) => Promise<any>
|
||||
}
|
||||
|
||||
@ -16,7 +16,7 @@ import Footer from './components/Footer.vue'
|
||||
import FAB from './components/FAB.vue'
|
||||
import Drawer from './components/Drawer.vue'
|
||||
import Bag from './components/Bag.vue'
|
||||
import ViewControls from './components/ViewControls.vue'
|
||||
import ActionsMenu from './components/ActionsMenu.vue'
|
||||
import './main.css'
|
||||
|
||||
const app = createApp(App)
|
||||
@ -54,7 +54,7 @@ app.component('Footer', Footer)
|
||||
app.component('Drawer', Drawer)
|
||||
app.component('FAB', FAB)
|
||||
app.component('Bag', Bag)
|
||||
app.component('ViewControls', ViewControls)
|
||||
app.component('ActionsMenu', ActionsMenu)
|
||||
app.component('NavPlaceholder', NavPlaceholder)
|
||||
|
||||
app.mount('#app')
|
||||
|
||||
@ -30,27 +30,27 @@ export async function setCurrentCollection(id: string) {
|
||||
loaded.value = false
|
||||
installed.value = false
|
||||
collection.value = null
|
||||
return collection.value
|
||||
return collection.value
|
||||
}
|
||||
|
||||
loaded.value = isMetaLoaded(id)
|
||||
installed.value = isInstalled(id)
|
||||
|
||||
if (!installed.value) {
|
||||
if (!installed.value)
|
||||
installed.value = await install(id)
|
||||
}
|
||||
|
||||
if (id === 'all') {
|
||||
const meta = await getFullMeta()
|
||||
collection.value = {
|
||||
id: 'all',
|
||||
name: 'All',
|
||||
icons: meta.flatMap((c) => c.icons.map((i) => `${c.id}:${i}`)),
|
||||
icons: meta.flatMap(c => c.icons.map(i => `${c.id}:${i}`)),
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
collection.value = await getMeta(id)
|
||||
loaded.value = true
|
||||
}
|
||||
|
||||
return collection.value
|
||||
return collection.value
|
||||
}
|
||||
|
||||
@ -1,2 +1,2 @@
|
||||
export * from './localstorage'
|
||||
export * from './collection'
|
||||
export * from './collection'
|
||||
|
||||
@ -3,7 +3,7 @@ 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()) || ''
|
||||
return window.Iconify.getSVG(icon, undefined) || 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> {
|
||||
|
||||
@ -1,28 +1,50 @@
|
||||
import { bags } from '../store'
|
||||
import { getSvg } from './icons'
|
||||
|
||||
export async function PackIconsInBag(options: any = {}) {
|
||||
if (!bags.value.length)
|
||||
return
|
||||
export async function LoadIconSvgs(icons: string[]) {
|
||||
return await Promise.all(
|
||||
icons
|
||||
.filter(Boolean)
|
||||
.sort()
|
||||
.map(async(name) => {
|
||||
return {
|
||||
name,
|
||||
svg: await getSvg(name),
|
||||
}
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
const icons = await Promise.all(bags.value.filter(Boolean).sort().map(async(name) => {
|
||||
return {
|
||||
name,
|
||||
svg: await getSvg(name),
|
||||
}
|
||||
}))
|
||||
export async function Download(url: string, name: string) {
|
||||
const a = document.createElement('a')
|
||||
a.href = url
|
||||
a.download = name
|
||||
a.click()
|
||||
a.remove()
|
||||
}
|
||||
|
||||
export async function PackIconFont(icons: string[], options: any = {}) {
|
||||
if (!icons.length) return
|
||||
const data = await LoadIconSvgs(icons)
|
||||
const result = await window.SvgPacker({
|
||||
fontName: 'Iconfiy Explorer Font',
|
||||
fileName: 'iconfont',
|
||||
cssPrefix: 'i',
|
||||
...options,
|
||||
icons,
|
||||
icons: data,
|
||||
})
|
||||
|
||||
const a = document.createElement('a')
|
||||
a.href = result.zip.url
|
||||
a.download = result.zip.name
|
||||
a.click()
|
||||
a.remove()
|
||||
Download(result.zip.url, result.zip.name)
|
||||
}
|
||||
|
||||
export async function PackSvgZip(icons: string[], name: string) {
|
||||
if (!icons.length) return
|
||||
const data = await LoadIconSvgs(icons)
|
||||
|
||||
const zip = new window.JSZip()
|
||||
for (const { name, svg } of data)
|
||||
zip.file(`${name}.svg`, svg)
|
||||
|
||||
const blob = await zip.generateAsync({ type: 'blob' })
|
||||
const url = URL.createObjectURL(blob)
|
||||
Download(url, `${name}.zip`)
|
||||
}
|
||||
|
||||
@ -1,32 +1,26 @@
|
||||
<template>
|
||||
<WithNavbar v-if="!collection">
|
||||
<div class="py-8 px-4 text-gray-700 text-center">Loading...</div>
|
||||
<div class="py-8 px-4 text-gray-700 text-center">
|
||||
Loading...
|
||||
</div>
|
||||
</WithNavbar>
|
||||
<IconSet v-else :collection="collection"/>
|
||||
<IconSet v-else :collection="collection" />
|
||||
</template>
|
||||
|
||||
<script lang='ts'>
|
||||
import { defineComponent, ref, watch, onUnmounted } from 'vue'
|
||||
import {
|
||||
isMetaLoaded,
|
||||
isInstalled,
|
||||
getFullMeta,
|
||||
install,
|
||||
getMeta,
|
||||
CollectionMeta
|
||||
} from '../data'
|
||||
import IconSet from './IconSet.vue'
|
||||
import { defineComponent, watch, onUnmounted } from 'vue'
|
||||
import { useCurrentCollection, setCurrentCollection } from '../store'
|
||||
import IconSet from './IconSet.vue'
|
||||
|
||||
export default defineComponent({
|
||||
components: {
|
||||
IconSet
|
||||
IconSet,
|
||||
},
|
||||
props: {
|
||||
id: {
|
||||
type: String,
|
||||
required: true
|
||||
}
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
setup(props) {
|
||||
watch(
|
||||
@ -34,7 +28,7 @@ export default defineComponent({
|
||||
() => {
|
||||
setCurrentCollection(props.id)
|
||||
},
|
||||
{ immediate: true }
|
||||
{ immediate: true },
|
||||
)
|
||||
|
||||
onUnmounted(() => {
|
||||
@ -42,8 +36,8 @@ export default defineComponent({
|
||||
})
|
||||
|
||||
return {
|
||||
collection: useCurrentCollection()
|
||||
collection: useCurrentCollection(),
|
||||
}
|
||||
}
|
||||
},
|
||||
})
|
||||
</script>
|
||||
|
||||
@ -2,14 +2,16 @@
|
||||
<WithNavbar>
|
||||
<div class="flex flex-auto h-full overflow-hidden">
|
||||
<Drawer class="h-full overflow-auto flex-none hidden md:block" style="width:280px" />
|
||||
<div class="py-5 px-5 md:px-8 h-full overflow-y-auto" v-if='collection'>
|
||||
<div class="flex">
|
||||
<div v-if="collection" class="py-5 px-5 md:px-8 h-full overflow-y-auto flex-auto overflow-x-hidden">
|
||||
<div class="flex px-2">
|
||||
<!-- Left -->
|
||||
<div class="flex-auto px-2">
|
||||
<NavPlaceholder class="md:hidden"/>
|
||||
<NavPlaceholder class="md:hidden" />
|
||||
|
||||
<div class="text-gray-900 text-xl flex">
|
||||
{{ collection.name }}
|
||||
<div class="text-gray-900 text-xl flex select-none">
|
||||
<div class="whitespace-no-wrap overflow-hidden">
|
||||
{{ collection.name }}
|
||||
</div>
|
||||
<a
|
||||
v-if="collection.url"
|
||||
class="text-gray-500 hover:text-gray-900 mt-1 text-base"
|
||||
@ -20,7 +22,9 @@
|
||||
</a>
|
||||
<div class="flex-auto" />
|
||||
</div>
|
||||
<div class="text-gray-500 text-xs block">{{ collection.author }}</div>
|
||||
<div class="text-gray-500 text-xs block">
|
||||
{{ collection.author }}
|
||||
</div>
|
||||
<div>
|
||||
<a
|
||||
class="text-gray-500 text-xs hover:text-gray-900"
|
||||
@ -32,13 +36,13 @@
|
||||
|
||||
<!-- Right -->
|
||||
<div class="flex flex-col">
|
||||
<ViewControls :collection="collection" />
|
||||
<ActionsMenu :collection="collection" />
|
||||
<div class="flex-auto" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Categories -->
|
||||
<div class="py-2 pr-3 overflow-x-auto flex flex-no-wrap select-none">
|
||||
<div class="py-2 px-1 pr-3 overflow-x-auto flex flex-no-wrap select-none">
|
||||
<template v-if="collection.categories">
|
||||
<div
|
||||
v-for="c of Object.keys(collection.categories)"
|
||||
@ -46,7 +50,9 @@
|
||||
class="whitespace-no-wrap text-sm inline-block px-2 border border-gray-200 text-gray-500 rounded-full m-1 hover:bg-gray-100 cursor-pointer"
|
||||
:class="c === category ? 'text-primary border-primary' : ''"
|
||||
@click="toggleCategory(c)"
|
||||
>{{ c }}</div>
|
||||
>
|
||||
{{ c }}
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
|
||||
@ -62,8 +68,12 @@
|
||||
style="color: #666"
|
||||
@select="onSelect"
|
||||
/>
|
||||
<button v-if="icons.length > max" class="btn m-2" @click="loadMore">Load More</button>
|
||||
<p class="text-gray-500 text-sm pt-4">{{ icons.length }} icons</p>
|
||||
<button v-if="icons.length > max" class="btn m-2" @click="loadMore">
|
||||
Load More
|
||||
</button>
|
||||
<p class="text-gray-500 text-sm pt-4">
|
||||
{{ icons.length }} icons
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<Footer />
|
||||
@ -101,26 +111,17 @@
|
||||
</template>
|
||||
|
||||
<script lang='ts'>
|
||||
import { defineComponent, ref, toRefs, computed, PropType } from 'vue'
|
||||
import {
|
||||
iconSize,
|
||||
listType,
|
||||
selectingMode,
|
||||
bags,
|
||||
toggleBag
|
||||
} from '../store'
|
||||
import {CollectionMeta} from '../data'
|
||||
import { useSearch } from '../hooks'
|
||||
import { useRoute } from 'vue-router'
|
||||
import { defineComponent, ref, computed, PropType } from 'vue'
|
||||
import { iconSize, listType, selectingMode, bags, toggleBag, getSearchResults } from '../store'
|
||||
import { CollectionMeta } from '../data'
|
||||
import { isElectron } from '../env'
|
||||
import { getSearchResults } from '../store'
|
||||
|
||||
export default defineComponent({
|
||||
props: {
|
||||
collection: {
|
||||
type: Object as PropType<CollectionMeta>,
|
||||
required: true
|
||||
}
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
setup(props) {
|
||||
const { search, icons, category, collection } = getSearchResults()
|
||||
@ -135,7 +136,9 @@ export default defineComponent({
|
||||
}
|
||||
|
||||
const namespace = computed(() => {
|
||||
return !collection.value || collection.value.id === 'all' ? '' : `${collection.value.id}:`
|
||||
return !collection.value || collection.value.id === 'all'
|
||||
? ''
|
||||
: `${collection.value.id}:`
|
||||
})
|
||||
|
||||
const onSelect = (icon: string) => {
|
||||
@ -172,8 +175,8 @@ export default defineComponent({
|
||||
// bags
|
||||
showBag,
|
||||
bags,
|
||||
selectingMode
|
||||
selectingMode,
|
||||
}
|
||||
}
|
||||
},
|
||||
})
|
||||
</script>
|
||||
|
||||
@ -4,10 +4,10 @@
|
||||
<div
|
||||
v-for="collection in collections"
|
||||
:key="collection.id"
|
||||
class="px-2 py-4 border-r border-b border-gray-200"
|
||||
class="px-2 py-4 border-r border-b border-gray-200 relative"
|
||||
>
|
||||
<router-link
|
||||
class="flex flex-col relative transition-all duration-300 text-gray-900 text-center justify-center hover:text-primary"
|
||||
class="flex flex-col transition-all duration-300 text-gray-900 text-center justify-center hover:text-primary"
|
||||
:to="`/collection/${collection.id}`"
|
||||
>
|
||||
<div class="flex-auto text-lg">{{ collection.name }}</div>
|
||||
@ -25,12 +25,12 @@
|
||||
spacing="m-1"
|
||||
class="mt-2 mb-1 justify-center opacity-75 overflow-hidden flex-none pointer-events-none"
|
||||
/>
|
||||
<IconButton
|
||||
</router-link>
|
||||
<IconButton
|
||||
v-if="isFavorited(collection.id)"
|
||||
class="absolute top-0 right-0 p-2 text-lg"
|
||||
icon="carbon:bookmark"
|
||||
/>
|
||||
</router-link>
|
||||
</div>
|
||||
</div>
|
||||
<Footer />
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user