mirror of
https://github.com/lucide-icons/lucide.git
synced 2026-11-14 13:58:21 +00:00
Try optimizing for categories
This commit is contained in:
@@ -8,6 +8,7 @@ const props = defineProps<{
|
||||
icons: IconEntity[]
|
||||
activeIcon?: string
|
||||
overlayMode?: boolean
|
||||
hideIcons?: boolean
|
||||
}>()
|
||||
|
||||
function setActiveIcon(name: string) {
|
||||
@@ -25,6 +26,7 @@ function setActiveIcon(name: string) {
|
||||
:active="activeIcon === icon.name"
|
||||
customizable
|
||||
:overlayMode="overlayMode"
|
||||
:hideIcon="hideIcons"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -15,6 +15,7 @@ const props = defineProps<{
|
||||
active: boolean;
|
||||
customizable?: boolean;
|
||||
overlayMode?: boolean
|
||||
hideIcon?: boolean
|
||||
}>()
|
||||
|
||||
const emit = defineEmits(['setActiveIcon'])
|
||||
@@ -45,7 +46,12 @@ function navigateToIcon() {
|
||||
:href="`/icons/${props.name}`"
|
||||
>
|
||||
<KeepAlive>
|
||||
<component :is="icon" class="lucide-icon" :class="{ customizable }" />
|
||||
<component
|
||||
v-if="!hideIcon"
|
||||
:is="icon"
|
||||
class="lucide-icon"
|
||||
:class="{ customizable }"
|
||||
/>
|
||||
</KeepAlive>
|
||||
</button>
|
||||
</template>
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue';
|
||||
import { Category } from '../../types';
|
||||
import IconGrid from './IconGrid.vue'
|
||||
import { vIntersectionObserver } from '@vueuse/components'
|
||||
|
||||
defineProps<{
|
||||
activeIconName: string
|
||||
category: Category
|
||||
}>()
|
||||
|
||||
|
||||
const emit = defineEmits(['setActiveIcon'])
|
||||
|
||||
const showIcons = ref(false)
|
||||
|
||||
// Added intersection observer to improve performance
|
||||
const onIntersectionObserver: IntersectionObserverCallback = ([{ isIntersecting }]) => {
|
||||
showIcons.value = isIntersecting
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<section
|
||||
class="category"
|
||||
:key="category.name"
|
||||
:id="category.name"
|
||||
v-intersection-observer="onIntersectionObserver"
|
||||
>
|
||||
<h2 class="title" >
|
||||
<a class="header-anchor" :href="`#${category.name}`" :aria-label="`Permalink to "${category.title}"`">​</a>
|
||||
{{ category.title }}
|
||||
</h2>
|
||||
<IconGrid
|
||||
:activeIcon="activeIconName"
|
||||
:icons="category.icons"
|
||||
@setActiveIcon="$event => $emit('setActiveIcon', $event)"
|
||||
overlayMode
|
||||
:hideIcons="!showIcons"
|
||||
/>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.title {
|
||||
margin-bottom: 24px;
|
||||
font-size: 19px;
|
||||
font-weight: 500;
|
||||
padding-top: 86px;
|
||||
/* scroll-padding-top: 240px; */
|
||||
}
|
||||
|
||||
.category {
|
||||
margin-bottom: calc(-86px + 32px);
|
||||
}
|
||||
</style>
|
||||
@@ -2,11 +2,11 @@
|
||||
import { ref, computed, defineAsyncComponent } from 'vue'
|
||||
import type { IconEntity, Category } from '../../types'
|
||||
import IconDetailOverlay from './IconDetailOverlay.vue'
|
||||
import IconGrid from './IconGrid.vue'
|
||||
import useSearch from '../../composables/useSearch'
|
||||
import InputSearch from '../base/InputSearch.vue'
|
||||
import useSearchInput from '../../composables/useSearchInput'
|
||||
import StickyBar from './StickyBar.vue'
|
||||
import IconsCategory from './IconsCategory.vue'
|
||||
|
||||
const props = defineProps<{
|
||||
icons: IconEntity[]
|
||||
@@ -58,7 +58,7 @@ const NoResults = defineAsyncComponent(() =>
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<StickyBar>
|
||||
<StickyBar class="search-bar">
|
||||
<InputSearch
|
||||
:placeholder="`Search ${icons.length} icons ...`"
|
||||
v-model="searchQuery"
|
||||
@@ -71,41 +71,22 @@ const NoResults = defineAsyncComponent(() =>
|
||||
:searchQuery="searchQuery"
|
||||
@clear="searchQuery = ''"
|
||||
/>
|
||||
<section class="category" v-for="category in categories" :key="category.name">
|
||||
<h2 class="title" :id="category.name">
|
||||
<a class="header-anchor" :href="`#${category.name}`" :aria-label="`Permalink to "${category.title}"`">​</a>
|
||||
{{ category.title }}
|
||||
</h2>
|
||||
<IconGrid
|
||||
:activeIcon="activeIconName"
|
||||
:icons="category.icons"
|
||||
@setActiveIcon="setActiveIconName"
|
||||
overlayMode
|
||||
/>
|
||||
</section>
|
||||
<IconsCategory
|
||||
v-for="category in categories"
|
||||
:key="category.name"
|
||||
:category="category"
|
||||
:activeIconName="activeIconName"
|
||||
@setActiveIcon="setActiveIconName"
|
||||
/>
|
||||
<IconDetailOverlay :icon="activeIcon" @close="setActiveIconName('')"/>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.icon {
|
||||
aspect-ratio: 1/1;
|
||||
}
|
||||
|
||||
.title {
|
||||
margin-bottom: 24px;
|
||||
font-size: 19px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.category {
|
||||
margin-bottom: 32px;
|
||||
}
|
||||
|
||||
.input-wrapper {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/* .input-wrapper {
|
||||
margin-bottom: 32px;
|
||||
} */
|
||||
.search-bar {
|
||||
margin-bottom: -54px;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -8,13 +8,13 @@
|
||||
.search-bar {
|
||||
margin-bottom: 16px;
|
||||
position: sticky;
|
||||
z-index: 70;
|
||||
z-index: 30;
|
||||
top: 48px;
|
||||
padding-top: 24px;
|
||||
margin-top: -32px;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
margin-bottom: 32px;;
|
||||
margin-bottom: 32px;
|
||||
background: var(--vp-c-bg);
|
||||
box-shadow: 0 16px 24px var(--vp-c-bg);
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ export interface Category {
|
||||
title: string
|
||||
icon?: string
|
||||
iconCount: number
|
||||
icons?: IconEntity[]
|
||||
}
|
||||
|
||||
interface Shield {
|
||||
|
||||
Reference in New Issue
Block a user