feat: more optimize for electron

This commit is contained in:
Anthony Fu 2020-07-17 14:57:05 +08:00
parent 73c97b2768
commit c3cf4f048d
27 changed files with 10174 additions and 10762 deletions

3
.gitignore vendored
View File

@ -7,4 +7,5 @@ src/assets/collections.json
public/collections public/collections
public/collections-info.json public/collections-info.json
public/collections-meta.json public/collections-meta.json
public/lib

View File

@ -3,7 +3,7 @@
<p align="center">Explorer for <a href="https://iconify.design/" target="_blank">Iconify</a> with <b>Instant</b> searching.</p> <p align="center">Explorer for <a href="https://iconify.design/" target="_blank">Iconify</a> with <b>Instant</b> searching.</p>
<p align="center"> <p align="center">
<a href="https://iconify.antfu.me/">iconify.antfu.me</a> <a href="https://iconify.antfu.me/">iconify.antfu.me</a>
</p> </p>
![](./screenshots/1.png) ![](./screenshots/1.png)

View File

@ -1,5 +1,5 @@
{ {
"name": "electron-webpack-quick-start", "name": "iconify-explorer-electron",
"version": "0.0.0", "version": "0.0.0",
"license": "MIT", "license": "MIT",
"scripts": { "scripts": {
@ -9,6 +9,7 @@
"dist:dir": "yarn dist --dir -c.compression=store -c.mac.identity=null" "dist:dir": "yarn dist --dir -c.compression=store -c.mac.identity=null"
}, },
"dependencies": { "dependencies": {
"babel-loader": "^8.1.0",
"electron-debug": "^3.1.0", "electron-debug": "^3.1.0",
"electron-serve": "^1.0.0", "electron-serve": "^1.0.0",
"electron-util": "^0.14.2", "electron-util": "^0.14.2",

View File

@ -17,7 +17,7 @@ const createMainWindow = async() => {
height: 500, height: 500,
minWidth: 200, minWidth: 200,
minHeight: 200, minHeight: 200,
titleBarStyle: 'hidden', titleBarStyle: 'hiddenInset',
}) })
win.on('ready-to-show', () => { win.on('ready-to-show', () => {

File diff suppressed because it is too large Load Diff

View File

@ -4,9 +4,8 @@
<meta charset="UTF-8" /> <meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Iconify Explorer</title> <title>Iconify Explorer</title>
<script src="https://code.iconify.design/1/1.0.7/iconify.without-api.min.js"></script> <script src="/lib/iconify.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/svg-packer@latest/dist/index.browser.min.js" defer></script> <script src="/lib/svg-packer.js" defer></script>
<link href="https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500&display=swap" rel="stylesheet">
</head> </head>
<body class="dragging"> <body class="dragging">
<div id="app"></div> <div id="app"></div>

View File

@ -3,8 +3,10 @@
"version": "0.0.0", "version": "0.0.0",
"private": true, "private": true,
"scripts": { "scripts": {
"preinstall": "npx only-allow pnpm",
"postinstall": "ts-node -P tsconfig.tsnode.json scripts/prepare.ts", "postinstall": "ts-node -P tsconfig.tsnode.json scripts/prepare.ts",
"dev": "vite", "dev": "vite",
"dev:electron": "pnpm -C ./electron dev",
"build": "vite build" "build": "vite build"
}, },
"dependencies": { "dependencies": {
@ -15,6 +17,8 @@
"vue-router": "next" "vue-router": "next"
}, },
"devDependencies": { "devDependencies": {
"svg-packer": "^0.0.3",
"@iconify/iconify": "^1.0.7",
"@antfu/eslint-config-vue": "^0.2.13", "@antfu/eslint-config-vue": "^0.2.13",
"@iconify/json": "^1.1.186", "@iconify/json": "^1.1.186",
"@types/fs-extra": "^9.0.1", "@types/fs-extra": "^9.0.1",

9822
pnpm-lock.yaml generated Normal file

File diff suppressed because it is too large Load Diff

2
pnpm-workspace.yaml Normal file
View File

@ -0,0 +1,2 @@
packages:
- 'electron/'

View File

@ -1,11 +1,12 @@
import path from 'path' import path from 'path'
import fs from 'fs-extra' import fs from 'fs-extra'
const dir = path.resolve(__dirname, '../node_modules/@iconify/json')
const out = path.resolve(__dirname, '../public') const out = path.resolve(__dirname, '../public')
const collectionsDir = path.resolve(__dirname, '../public/collections')
async function prepare() { async function prepareJSON() {
const dir = path.resolve(__dirname, '../node_modules/@iconify/json')
const collectionsDir = path.resolve(__dirname, '../public/collections')
const raw = await fs.readJSON(path.join(dir, 'collections.json')) const raw = await fs.readJSON(path.join(dir, 'collections.json'))
await fs.ensureDir(collectionsDir) await fs.ensureDir(collectionsDir)
@ -21,9 +22,12 @@ async function prepare() {
const icons = Object.keys(setData.icons) const icons = Object.keys(setData.icons)
const categories = setData.categories const categories = setData.categories
const meta = {...info, icons, categories } const meta = { ...info, icons, categories }
await fs.writeJSON(path.join(collectionsDir, `${info.id}-raw.json`), setData) await fs.writeJSON(
path.join(collectionsDir, `${info.id}-raw.json`),
setData
)
await fs.writeJSON(path.join(collectionsDir, `${info.id}-meta.json`), meta) await fs.writeJSON(path.join(collectionsDir, `${info.id}-meta.json`), meta)
collectionsMeta.push(meta) collectionsMeta.push(meta)
@ -34,4 +38,29 @@ async function prepare() {
await fs.writeJSON(path.join(out, 'collections-info.json'), collections) await fs.writeJSON(path.join(out, 'collections-info.json'), collections)
} }
async function copyLibs() {
const modules = path.resolve(__dirname, '../node_modules')
await fs.copy(
path.join(modules, '@iconify/iconify/dist/'),
path.join(out, 'lib'),
{
filter: (src) => {
if (fs.lstatSync(src).isDirectory()) return true
const basename = path.basename(src)
return basename.startsWith('iconify') && basename.endsWith('.min.js')
}
}
)
await fs.copy(
path.join(modules, 'svg-packer/dist/index.browser.js'),
path.join(out, 'lib/svg-packer.js')
)
}
async function prepare() {
await prepareJSON()
await copyLibs()
}
prepare() prepare()

View File

@ -1,10 +1,7 @@
<template> <template>
<div class="flex flex-col h-screen overflow-hidden" :style="style"> <div class="flex flex-col h-screen overflow-hidden" :style="style">
<div class="flex flex-auto overflow-hidden"> <div class="h-full flex-auto overflow-auto">
<Drawer v-if="!isRoot" class="h-full overflow-auto flex-none hidden md:block" style="width:280px" /> <router-view />
<div class="h-full flex-auto overflow-auto">
<router-view />
</div>
</div> </div>
</div> </div>
</template> </template>
@ -16,17 +13,13 @@ import { themeColor } from './store'
export default defineComponent({ export default defineComponent({
setup() { setup() {
const route = useRoute()
const isRoot = computed(() => route.path === '/')
const style = computed(() => ({ const style = computed(() => ({
'--theme-color': themeColor.value, '--theme-color': themeColor.value
})) }))
return { return {
isRoot, style
style,
} }
}, }
}) })
</script> </script>

View File

@ -1,5 +1,5 @@
<template> <template>
<div class="h-full flex flex-col" style="width:40vw;"> <div class="h-full flex flex-col w-screen md:w-16">
<div class="flex-none border-b border-gray-200 py-3 px-6 flex"> <div class="flex-none border-b border-gray-200 py-3 px-6 flex">
<div> <div>
<div class="text-gray-700 text-lg"> <div class="text-gray-700 text-lg">
@ -10,7 +10,7 @@
</div> </div>
</div> </div>
<div class="flex-auto" /> <div class="flex-auto" />
<IconButton 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')" /> <IconButton class="text-2xl flex-none" icon="carbon:close" @click="$emit('close')" />
</div> </div>
<template v-if="bags.length"> <template v-if="bags.length">
@ -18,8 +18,8 @@
<Icons :icons="bags" /> <Icons :icons="bags" />
</div> </div>
<div class="flex-none border-t border-gray-200 py-3 px-6 text-2xl text-gray-700"> <div class="flex-none border-t border-gray-200 py-3 px-6 text-2xl text-gray-700">
<IconButton class="p-1" icon="carbon:function" text="Generate Icon Fonts" :active="true" @click="pack()" /> <IconButton class="p-1 cursor-pointer" icon="carbon:function" text="Generate Icon Fonts" :active="true" @click="pack()" />
<IconButton class="p-1" icon="carbon:download" text="Download All SVGs" :active="true" @click="wip" /> <IconButton class="p-1 cursor-pointer" icon="carbon:download" text="Download All SVGs" :active="true" @click="wip" />
</div> </div>
</template> </template>
<template v-else> <template v-else>

View File

@ -1,6 +1,8 @@
<template> <template>
<div class="border-r border-gray-200"> <div class="border-r border-gray-200">
<!-- Back button, Mobile Only -->
<div <div
v-if='!isElectron'
class="border-b border-gray-200" class="border-b border-gray-200"
> >
<IconButton <IconButton
@ -10,6 +12,8 @@
@click="$router.replace('/')" @click="$router.replace('/')"
/> />
</div> </div>
<!-- Collections -->
<router-link <router-link
v-for="collection in collections" v-for="collection in collections"
:key="collection.id" :key="collection.id"
@ -46,6 +50,7 @@ import { defineComponent, computed } from 'vue'
import { useRoute } from 'vue-router' import { useRoute } from 'vue-router'
import { sortedCollectionsInfo } from '../data' import { sortedCollectionsInfo } from '../data'
import { isFavorited, toggleFavorite } from '../store' import { isFavorited, toggleFavorite } from '../store'
import { isElectron } from '../env'
export default defineComponent({ export default defineComponent({
setup() { setup() {
@ -64,6 +69,7 @@ export default defineComponent({
current, current,
toggleFavorite, toggleFavorite,
isFavorited, isFavorited,
isElectron,
} }
}, },
}) })

View File

@ -0,0 +1,33 @@
<template>
<div class="electron-nav dragging md:border-b border-gray-200 flex-none flex justify-start">
<div class="mac-controls flex-none" />
<IconButton
v-show="$route.path !== '/'"
class="text-lg mx-1 px-3 flex-none"
icon="carbon:chevron-left"
@click="$router.replace('/')"
/>
<div class="inline-block text-sm text-gray-800 my-auto ml-3 font-light"><b class="font-bold">Iconify</b>Explorer</div>
<div class="flex-auto"></div>
</div>
</template>
<script lang='ts'>
import { defineComponent } from 'vue'
export default defineComponent({})
</script>
<style>
.electron-nav {
height: 37px
}
.mac-controls {
width: 70px;
}
.electron-nav .icon-button svg {
margin-top: -2px;
}
</style>

View File

@ -1,6 +1,6 @@
<template> <template>
<div class="hidden md:block p-4 m-6 fixed bottom-0 right-0 shadow-lg bg-white rounded-full text-2xl cursor-pointer hover:bg-gray-100"> <div class="p-4 m-6 fixed bottom-0 right-0 shadow-lg bg-white rounded-full text-2xl cursor-pointer hover:bg-gray-100">
<Icon class="text-gray-700" :icon="icon" /> <Icon class="text-gray-700" :icon="icon" />
<div <div
v-if="number" v-if="number"

View File

@ -1,6 +1,6 @@
<template> <template>
<div <div
class="m-auto cursor-pointer" class="icon-button m-auto"
:class="active ? 'opacity-100 hover:opacity-100 hover:text-primary' : 'opacity-25 hover:opacity-50' " :class="active ? 'opacity-100 hover:opacity-100 hover:text-primary' : 'opacity-25 hover:opacity-50' "
> >
<Icon <Icon

View File

@ -1,10 +1,10 @@
<template> <template>
<div class="non-dragging flex flex-wrap select-none justify-center" :class="`text-${size}`" :style="{ color }"> <div class="non-dragging flex flex-wrap select-none justify-center" :class="`text-${size}`">
<div <div
v-for="icon of icons" v-for="icon of icons"
:key="icon" :key="icon"
class="non-dragging icons-item cursor-pointer flex m-2" class="non-dragging icons-item flex"
:class="selected.includes(namespace+icon) ? 'active': ''" :class="[spacing, selected.includes(namespace+icon) ? 'active': '']"
@click="$emit('select', namespace+icon)" @click="$emit('select', namespace+icon)"
> >
<Icon class="non-dragging" :icon="namespace+icon" /> <Icon class="non-dragging" :icon="namespace+icon" />
@ -33,14 +33,14 @@ export default defineComponent({
type: String, type: String,
default: '2xl', default: '2xl',
}, },
spacing: {
type: String,
default: 'm-2'
},
search: { search: {
type: String, type: String,
default: '', default: '',
}, },
color: {
type: String,
default: '#555',
},
display: { display: {
type: String, type: String,
default: 'grid', default: 'grid',

View File

@ -6,7 +6,7 @@
@click="$emit('close')" @click="$emit('close')"
/> />
<div <div
class="bg-white absolute shadow-lg transition-all duration-200 ease-out border-gray-200" class="bg-white absolute transition-all duration-200 ease-out border-gray-200"
:class="positionClass" :class="positionClass"
:style="value ? {}: {transform}" :style="value ? {}: {transform}"
> >

View File

@ -0,0 +1,71 @@
<template>
<div class="px-1 text-xl text-gray-800 flex">
<IconButton
class="mr-3"
icon="carbon:checkbox-checked"
:active="selectingMode"
@click="selectingMode = !selectingMode"
/>
<div class="mx-1 h-full m-auto bg-gray-200" style="width:1px;" />
<IconButton
class="ml-3"
icon="carbon:hinton-plot"
title="Small"
:active="listType === 'grid' && iconSize === '2xl'"
@click="()=>setGrid('small')"
/>
<IconButton
class="ml-3"
icon="carbon:app-switcher"
title="Large"
:active="listType === 'grid' && iconSize === '4xl'"
@click="()=>setGrid('large')"
/>
<IconButton
class="ml-3"
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, showCategories, 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,
showCategories,
selectingMode
}
}
})
</script>

View File

@ -1,6 +1,7 @@
<template> <template>
<div class="flex h-screen flex-col overflow-hidden"> <div class="flex h-screen flex-col overflow-hidden">
<Navbar :class="navClass" /> <ElectronNav v-if='isElectron'/>
<Navbar v-else :class="navClass" />
<div class="flex-auto overflow-auto"> <div class="flex-auto overflow-auto">
<slot /> <slot />
</div> </div>
@ -9,13 +10,23 @@
<script lang='ts'> <script lang='ts'>
import { defineComponent } from 'vue' import { defineComponent } from 'vue'
import ElectronNav from './ElectronNav.vue'
import { isElectron } from '../env'
export default defineComponent({ export default defineComponent({
components: {
ElectronNav
},
props: { props: {
navClass: { navClass: {
type: String, type: String,
default: '', default: '',
}, },
}, },
setup(){
return {
isElectron,
}
}
}) })
</script> </script>

1
src/env.ts Normal file
View File

@ -0,0 +1 @@
export const isElectron = location.protocol === 'app:' || (process.env.NODE_ENV === 'development' && navigator.userAgent.indexOf('Electron') >= 0)

View File

@ -15,6 +15,7 @@ import Footer from './components/Footer.vue'
import FAB from './components/FAB.vue' import FAB from './components/FAB.vue'
import Drawer from './components/Drawer.vue' import Drawer from './components/Drawer.vue'
import Bag from './components/Bag.vue' import Bag from './components/Bag.vue'
import ViewControls from './components/ViewControls.vue'
import './main.css' import './main.css'
const app = createApp(App) const app = createApp(App)
@ -52,5 +53,6 @@ app.component('Footer', Footer)
app.component('Drawer', Drawer) app.component('Drawer', Drawer)
app.component('FAB', FAB) app.component('FAB', FAB)
app.component('Bag', Bag) app.component('Bag', Bag)
app.component('ViewControls', ViewControls)
app.mount('#app') app.mount('#app')

View File

@ -1,7 +1,7 @@
<template> <template>
<div v-if="!collection" class="p-4 text-gray-700"> <WithNavbar v-if="!collection">
Loading... <div class="py-8 px-4 text-gray-700 text-center">Loading...</div>
</div> </WithNavbar>
<IconSet v-else :collection="collection" :installed="installed" /> <IconSet v-else :collection="collection" :installed="installed" />
</template> </template>
@ -13,19 +13,19 @@ import {
getFullMeta, getFullMeta,
install, install,
getMeta, getMeta,
CollectionMeta, CollectionMeta
} from '../data' } from '../data'
import IconSet from './IconSet.vue' import IconSet from './IconSet.vue'
export default defineComponent({ export default defineComponent({
components: { components: {
IconSet, IconSet
}, },
props: { props: {
id: { id: {
type: String, type: String,
required: true, required: true
}, }
}, },
setup(props) { setup(props) {
const loaded = ref(isMetaLoaded(props.id)) const loaded = ref(isMetaLoaded(props.id))
@ -34,7 +34,7 @@ export default defineComponent({
watch( watch(
() => props.id, () => props.id,
async() => { async () => {
loaded.value = false loaded.value = false
if (props.id === 'all') { if (props.id === 'all') {
@ -42,23 +42,22 @@ export default defineComponent({
collection.value = { collection.value = {
id: 'all', id: 'all',
name: '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 {
await install(props.id) await install(props.id)
collection.value = await getMeta(props.id) collection.value = await getMeta(props.id)
} }
loaded.value = true loaded.value = true
}, },
{ immediate: true }, { immediate: true }
) )
return { return {
collection, collection,
loaded, loaded,
installed, installed
} }
}, }
}) })
</script> </script>

View File

@ -1,150 +1,107 @@
<template> <template>
<WithNavbar nav-class="md:hidden"> <WithNavbar nav-class="md:hidden">
<div class="py-5 px-5 md:px-8"> <div class="flex flex-auto h-full overflow-hidden">
<div class="flex"> <Drawer class="h-full overflow-auto flex-none hidden md:block" style="width:280px" />
<!-- Left --> <div class="py-5 px-5 md:px-8 h-full overflow-y-auto">
<div class="flex-auto"> <div class="flex">
<div class="text-gray-900 text-xl flex"> <!-- Left -->
{{ collection.name }} <div class="flex-auto">
<a <div class="text-gray-900 text-xl flex">
v-if="collection.url" {{ collection.name }}
class="text-gray-500 hover:text-gray-900 mt-1 text-base" <a
:href="collection.url" v-if="collection.url"
target="_blank" class="text-gray-500 hover:text-gray-900 mt-1 text-base"
> :href="collection.url"
<Icon icon="la:external-link-square-alt-solid" /> target="_blank"
</a> >
<Icon icon="la:external-link-square-alt-solid" />
</a>
<div class="flex-auto" />
</div>
<div class="text-gray-500 text-xs block">{{ collection.author }}</div>
<div>
<a
class="text-gray-500 text-xs hover:text-gray-900"
:href="collection.licenseURL"
target="_blank"
>{{ collection.license }}</a>
</div>
</div>
<!-- Right -->
<div class="flex flex-col">
<ViewControls :collection="collection" />
<div class="flex-auto" /> <div class="flex-auto" />
</div> </div>
<div class="text-gray-500 text-xs block">
{{ collection.author }}
</div>
<div>
<a
class="text-gray-500 text-xs hover:text-gray-900"
:href="collection.licenseURL"
target="_blank"
>{{ collection.license }}</a>
</div>
</div> </div>
<!-- Right --> <!-- Categories -->
<div class="flex flex-col"> <div class="py-3 pr-3 overflow-x-auto flex flex-no-wrap">
<div class="px-1 text-xl text-gray-800 flex"> <template v-if="collection.categories">
<IconButton <div
class="hidden md:block mr-3" v-for="c of Object.keys(collection.categories)"
icon="carbon:checkbox-checked" :key="c"
:active="selectingMode" 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"
@click="selectingMode = !selectingMode" :class="c === category ? 'text-primary border-primary' : ''"
/> @click="toggleCategory(c)"
<div class="hidden md:block mx-1 h-full m-auto bg-gray-200" style="width:1px;" /> >{{ c }}</div>
<template v-if="collection.categories"> </template>
<IconButton
class="mx-3"
icon="carbon:categories"
:active="showCategories"
title="Categories"
@click="showCategories = !showCategories"
/>
<div class="mx-1 m-auto h-full bg-gray-200" style="width:1px;" />
</template>
<IconButton
class="ml-3"
icon="carbon:hinton-plot"
title="Small"
:active="listType === 'grid' && iconSize === '2xl'"
@click="()=>setGrid('small')"
/>
<IconButton
class="ml-3"
icon="carbon:app-switcher"
title="Large"
:active="listType === 'grid' && iconSize === '4xl'"
@click="()=>setGrid('large')"
/>
<IconButton
class="ml-3"
icon="carbon:list"
title="List View"
:active="listType === 'list'"
@click="()=>setGrid('list')"
/>
</div>
<div class="flex-auto" />
</div> </div>
</div>
<!-- Categories --> <!-- Search -->
<div class="py-2"> <div class="flex">
<template v-if="collection.categories && showCategories"> <input
<div v-model="search"
v-for="c of Object.keys(collection.categories)" class="shadow rounded outline-none py-2 px-4 flex-auto"
:key="c" placeholder="Search..."
class="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' : ''" </div>
@click="toggleCategory(c)"
>
{{ c }}
</div>
</template>
</div>
<!-- Search --> <!-- Icons -->
<div class="flex"> <div class="py-4 text-center">
<input <Icons
v-model="search" :icons="icons.slice(0, max)"
class="shadow rounded outline-none py-2 px-4 flex-auto" :selected="selectedIcons"
placeholder="Search..." :size="iconSize"
> :display="listType"
</div> :search="search"
:namespace="namespace"
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>
</div>
<!-- Icons --> <Footer />
<div class="py-4 text-center">
<Icons <!-- Details -->
:icons="icons.slice(0, max)" <Modal :value="!!current" @close="current = null">
:selected="selectedIcons" <IconDetail :icon="current" />
:size="iconSize" </Modal>
:display="listType"
:search="search" <!-- Bag -->
:namespace="namespace" <Modal :value="showBag" direction="right" @close="showBag = false">
@select="onSelect" <Bag @close="showBag = false" />
</Modal>
<!-- Bag Fab -->
<FAB
v-if="bags.length"
icon="carbon:shopping-bag"
:number="bags.length"
@click="showBag = true"
/> />
<button v-if="icons.length > max" class="btn m-2" @click="loadMore">
Load More
</button>
<p class="text-gray-500 text-sm px-2">
{{ icons.length }} icons
</p>
</div>
<Footer /> <!-- Selecting Note -->
<div
<!-- Details --> class="fixed top-0 right-0 pl-4 pr-2 py-1 rounded-l-full bg-primary text-white shadow mt-16 cursor-pointer transition-transform duration-300 ease-in-out"
<Modal :value="!!current" @close="current = null"> :style="selectingMode ? {} : {transform: 'translateX(120%)'}"
<IconDetail :icon="current" /> @click="selectingMode = false"
</Modal> >
Selecting Mode
<!-- Bag --> <Icon icon="carbon:close" class="inline-block text-xl align-text-bottom" />
<Modal :value="showBag" direction="right" @close="showBag = false"> </div>
<Bag @close="showBag = false" />
</Modal>
<!-- Bag Fab -->
<FAB
v-if="bags.length"
icon="carbon:shopping-bag"
:number="bags.length"
@click="showBag = true"
/>
<!-- Selecting Note -->
<div
class="fixed top-0 right-0 pl-4 pr-2 py-1 rounded-l-full bg-primary text-white shadow mt-16 cursor-pointer transition-transform duration-300 ease-in-out"
:style="selectingMode ? {} : {transform: 'translateX(120%)'}"
@click="selectingMode = false"
>
Selecting Mode
<Icon icon="carbon:close" class="inline-block text-xl align-text-bottom" />
</div> </div>
</div> </div>
</WithNavbar> </WithNavbar>
@ -152,16 +109,25 @@
<script lang='ts'> <script lang='ts'>
import { defineComponent, ref, toRefs, computed, PropType } from 'vue' import { defineComponent, ref, toRefs, computed, PropType } from 'vue'
import { iconSize, listType, showCategories, selectingMode, bags, toggleBag } from '../store' import {
iconSize,
listType,
showCategories,
selectingMode,
bags,
toggleBag
} from '../store'
import { useSearch } from '../hooks/search' import { useSearch } from '../hooks/search'
import { CollectionMeta } from '../data' import { CollectionMeta } from '../data'
import { useRoute } from 'vue-router'
import { isElectron } from '../env'
export default defineComponent({ export default defineComponent({
props: { props: {
collection: { collection: {
type: Object as PropType<CollectionMeta>, type: Object as PropType<CollectionMeta>,
required: true, required: true
}, }
}, },
setup(props) { setup(props) {
const { collection } = toRefs(props) const { collection } = toRefs(props)
@ -169,13 +135,11 @@ export default defineComponent({
const showBag = ref(false) const showBag = ref(false)
const current = ref<string | null>(null) const current = ref<string | null>(null)
const max = ref(200) const max = ref(isElectron ? 500 : 200)
const toggleCategory = (cat: string) => { const toggleCategory = (cat: string) => {
if (category.value === cat) if (category.value === cat) category.value = ''
category.value = '' else category.value = cat
else
category.value = cat
} }
const namespace = computed(() => { const namespace = computed(() => {
@ -183,39 +147,19 @@ export default defineComponent({
}) })
const onSelect = (icon: string) => { const onSelect = (icon: string) => {
if (selectingMode.value) if (selectingMode.value) toggleBag(icon)
toggleBag(icon) else current.value = icon
else
current.value = icon
} }
const selectedIcons = computed(() => { const selectedIcons = computed(() => {
if (selectingMode.value) if (selectingMode.value) return bags.value
return bags.value else return current.value ? [] : [current.value]
else
return current.value ? [] : [current.value]
}) })
const loadMore = () => { const loadMore = () => {
max.value += 100 max.value += 100
} }
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 { return {
current, current,
search, search,
@ -227,7 +171,6 @@ export default defineComponent({
loadMore, loadMore,
iconSize, iconSize,
listType, listType,
setGrid,
namespace, namespace,
selectedIcons, selectedIcons,
@ -238,8 +181,8 @@ export default defineComponent({
// bags // bags
showBag, showBag,
bags, bags,
selectingMode, selectingMode
} }
}, }
}) })
</script> </script>

View File

@ -1,36 +1,35 @@
<template> <template>
<WithNavbar> <WithNavbar>
<div class=""> <div class="collections-list grid">
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4"> <div
v-for="collection in collections"
:key="collection.id"
class="px-2 py-4 border-r border-b border-gray-200"
>
<router-link <router-link
v-for="collection in collections" class="flex flex-col relative transition-all duration-300 text-gray-900 text-center justify-center hover:text-primary"
:key="collection.id"
:to="`/collection/${collection.id}`" :to="`/collection/${collection.id}`"
> >
<div class="flex flex-col py-4 relative border-r border-b border-gray-200 transition-all duration-300 text-gray-900 hover:text-primary"> <div class="flex-auto text-lg">{{ collection.name }}</div>
<div class="flex-auto bg-opacity-50 text-center"> <div class="flex-auto opacity-50 text-xs">
<div class="text-lg"> <span>{{ collection.author }}</span>
{{ collection.name }} <span class="px-1 opacity-25">/</span>
</div> <span>{{ collection.license }}</span>
<div class="text-gray-500 text-sm block leading-none"> <span class="px-1 opacity-25">/</span>
{{ collection.author }} <span>{{ collection.total }} icons</span>
</div>
</div>
<Icons
:icons="collection.sampleIcons"
:namespace="`${collection.id}:`"
class="py-2 justify-center overflow-hidden flex-none pointer-events-none"
/>
<div class="flex-auto bg-opacity-50 text-center">
<div class="text-gray-500 text-xs block">
{{ collection.license }}
</div>
<div class="text-gray-500 text-xs block">
{{ collection.total }} icons
</div>
</div>
<IconButton v-if="isFavorited(collection.id)" class="absolute top-0 right-0 p-2 text-lg" icon="carbon:bookmark" />
</div> </div>
<Icons
:icons="collection.sampleIcons"
:namespace="`${collection.id}:`"
size="xl"
spacing="m-1"
class="mt-2 mb-1 justify-center opacity-75 overflow-hidden flex-none pointer-events-none"
/>
<IconButton
v-if="isFavorited(collection.id)"
class="absolute top-0 right-0 p-2 text-lg"
icon="carbon:bookmark"
/>
</router-link> </router-link>
</div> </div>
</div> </div>
@ -49,8 +48,14 @@ export default defineComponent({
return { return {
collections: sortedCollectionsInfo, collections: sortedCollectionsInfo,
isFavorited, isFavorited,
sample, sample
} }
}, }
}) })
</script> </script>
<style>
.collections-list {
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
}
</style>

View File

@ -24,9 +24,6 @@ module.exports = {
}, },
theme: { theme: {
extend: { extend: {
fontFamily: {
sans: ['Roboto', ...defaultTheme.fontFamily.sans],
},
fontSize: { fontSize: {
'7xl': '5rem', '7xl': '5rem',
'8xl': '6rem', '8xl': '6rem',

3622
yarn.lock

File diff suppressed because it is too large Load Diff