Add copy name

This commit is contained in:
Eric Fennis
2023-05-12 12:53:40 +02:00
parent e6c9f29055
commit 3da2a61464
11 changed files with 115 additions and 53 deletions
@@ -36,15 +36,12 @@ const selectionOptionAction = computed(() => props.options.find(option => option
function onClick(event) {
selectionOptionAction.value()
console.log(event);
emit('click', event)
}
function onOptionClick(event, option) {
console.log(event, option);
if(!props.callOptionOnClick) {
return
}
@@ -3,13 +3,14 @@ import { computed, ref } from 'vue';
import { startCase, camelCase } from 'lodash-es'
import ButtonMenu from '../base/ButtonMenu.vue'
import { useIconStyleContext } from '../../composables/useIconStyle';
import useConfetti from '../../composables/useConfetti';
const props = defineProps<{
name: string
popoverPosition?: 'top' | 'bottom'
}>()
const { size, color, strokeWidth } = useIconStyleContext()
const animate = ref(false)
const { animate, confetti } = useConfetti()
const componentName = computed(() => {
return startCase(camelCase(props.name)).replace(/\s/g, '')
})
@@ -75,14 +76,6 @@ function copyAngular() {
navigator.clipboard.writeText(code)
}
function confetti(e) {
animate.value = true;
setTimeout(function () {
animate.value = false;
}, 1000);
}
</script>
<template>
@@ -2,6 +2,7 @@
import { ref } from 'vue';
import ButtonMenu from '../base/ButtonMenu.vue'
import { useIconStyleContext } from '../../composables/useIconStyle';
import useConfetti from '../../composables/useConfetti';
const allowedAttrs = [
'xmlns',
@@ -25,15 +26,7 @@ const props = defineProps<{
const { size } = useIconStyleContext()
const animate = ref(false)
function confetti() {
animate.value = true;
setTimeout(function () {
animate.value = false;
}, 1000);
}
const { animate, confetti } = useConfetti()
function getSVGIcon() {
const svg = document.querySelector('#previewer svg')
@@ -1,6 +1,31 @@
<script setup lang="ts">
import { computed, useSlots } from 'vue';
import createLucideIcon from 'lucide-vue-next/src/createLucideIcon'
import { copy } from '../../../data/iconNodes'
import useConfetti from '../../composables/useConfetti';
const { animate, confetti } = useConfetti()
const slots = useSlots()
const copiedText = computed(() => slots.default?.()[0].children)
function copyText() {
navigator.clipboard.writeText(copiedText.value)
confetti()
}
const Copy = createLucideIcon('ChevronUp', copy)
</script>
<template>
<h1 class="icon-name">
<h1
class="icon-name confetti-button"
:class="{animate}"
data-confetti-text="Copied!"
@click="copyText"
>
<slot />
<Copy :size="20" class="copy-icon"/>
</h1>
</template>
@@ -13,11 +38,38 @@
padding: 2px 8px;
border-radius: 8px;
width: auto;
display: inline-block;
display: inline-flex;
margin-left: -8px;
}
.icon-name:hover {
background-color: var(--vp-c-bg-alt);
}
.icon-name:hover .copy-icon {
opacity: .9;
}
.icon-name:before,
.icon-name:after {
left: unset !important;
right: -20%;
}
.icon-name:before {
text-align: center;
}
.copy-icon {
opacity: 0;
margin-left: 12px;
margin-top: 6px;
transition:ease .3s opacity;
}
.icon-name:hover .copy-icon:hover {
opacity: .6;
}
</style>
<style src="./confetti.css" />
@@ -28,7 +28,7 @@
</script>
<template>
<Transition name="drawer">
<Transition name="drawer" appear>
<div class="overlay-container" v-if="props.icon">
<div class="overlay-panel">
<nav class="overlay-menu">
@@ -1,7 +1,6 @@
<script setup lang="ts">
import { ref, computed, defineAsyncComponent } from 'vue'
import type { IconEntity, Category } from '../../types'
import IconDetailOverlay from './IconDetailOverlay.vue'
import useSearch from '../../composables/useSearch'
import InputSearch from '../base/InputSearch.vue'
import useSearchInput from '../../composables/useSearchInput'
@@ -13,7 +12,7 @@ const props = defineProps<{
categories: Category[]
}>()
const activeIconName = ref('')
const activeIconName = ref(null)
const { searchInput, searchQuery, searchQueryThrottled } = useSearchInput()
const isSearching = computed(() => !!searchQuery.value)
@@ -55,6 +54,10 @@ const activeIcon = computed(() =>
const NoResults = defineAsyncComponent(() =>
import('./NoResults.vue')
)
const IconDetailOverlay = defineAsyncComponent(() =>
import('./IconDetailOverlay.vue')
)
</script>
<template>
@@ -78,7 +81,11 @@ const NoResults = defineAsyncComponent(() =>
:activeIconName="activeIconName"
@setActiveIcon="setActiveIconName"
/>
<IconDetailOverlay :icon="activeIcon" @close="setActiveIconName('')"/>
<IconDetailOverlay
v-if="activeIconName != null"
:icon="activeIcon"
@close="setActiveIconName('')"
/>
</template>
<style scoped>
@@ -2,7 +2,6 @@
import { ref, computed, watch, defineAsyncComponent } from 'vue'
import type { IconEntity } from '../../types'
import { useMediaQuery, useOffsetPagination } from '@vueuse/core'
import IconDetailOverlay from './IconDetailOverlay.vue'
import IconGrid from './IconGrid.vue'
import InputSearch from '../base/InputSearch.vue'
import useSearch from '../../composables/useSearch'
@@ -14,7 +13,7 @@ const props = defineProps<{
icons: IconEntity[]
}>()
const activeIconName = ref('')
const activeIconName = ref(null)
const isExtraLargeScreen = useMediaQuery('(min-width: 1440px)');
const isLargeScreen = useMediaQuery('(min-width: 1280px)');
@@ -59,9 +58,7 @@ function setActiveIconName(name: string) {
activeIconName.value = name
}
const activeIcon = computed(() =>
props.icons.find((icon) => icon.name === activeIconName.value)
)
const activeIcon = computed(() => props.icons.find((icon) => icon.name === activeIconName.value))
watch(searchQueryThrottled, (searchString) => {
currentPage.value = 1
@@ -70,6 +67,11 @@ watch(searchQueryThrottled, (searchString) => {
const NoResults = defineAsyncComponent(() =>
import('./NoResults.vue')
)
const IconDetailOverlay = defineAsyncComponent(() =>
import('./IconDetailOverlay.vue')
)
</script>
<template>
@@ -93,7 +95,11 @@ const NoResults = defineAsyncComponent(() =>
@setActiveIcon="setActiveIconName"
/>
<EndOfPage @end-of-page="next" class="bottom-page"/>
<IconDetailOverlay :icon="activeIcon" @close="setActiveIconName('')"/>
<IconDetailOverlay
v-if="activeIconName != null"
:icon="activeIcon"
@close="setActiveIconName('')"
/>
</template>
<style>
@@ -8,7 +8,7 @@
.search-bar {
margin-bottom: 16px;
position: sticky;
z-index: 30;
z-index: 10;
top: 48px;
padding-top: 24px;
margin-top: -32px;
@@ -15,11 +15,13 @@
content: "";
display: block;
width: 140%;
max-width: 160px;
height: 100%;
left: -20%;
z-index: -1000;
transition: all ease-in-out 0.5s;
background-repeat: no-repeat;
font-size: 14px;
}
.confetti-button:before {
@@ -0,0 +1,18 @@
import { ref } from "vue";
export default function useConfetti() {
const animate = ref(false)
function confetti() {
animate.value = true;
setTimeout(function () {
animate.value = false;
}, 1000);
}
return {
animate,
confetti
}
}
+13 -19
View File
@@ -2,25 +2,19 @@ import Fuse from "fuse.js";
import { getAllData } from "../.vitepress/lib/icons";
import { IconEntity } from "../.vitepress/theme/types";
const getRelatedIcons = (name:string, icons: IconEntity[]) => {
const index = new Fuse(icons, {
threshold: 1,
keys: [
{ name: 'name', weight: 3 },
{ name: 'tags', weight: 2 },
{ name: 'categories', weight: 1 },
],
// TODO: This should be ordered by relevance
const getRelatedIcons = (currentIcon:IconEntity, icons: IconEntity[]) => {
return icons.filter((icon) => {
const { name: iconName, tags, categories } = icon;
const isNameRelated = iconName.includes(currentIcon.name);
const hasRelatedTags = tags?.some((tag) => currentIcon?.tags?.includes(tag));
const hasRelatedCategories = categories?.some((category) =>
currentIcon?.categories?.includes(category)
);
return isNameRelated || hasRelatedTags || hasRelatedCategories;
});
return index
.search(name)
.map((result) => result.item)
.slice(0, 85)
.map(({ name, iconNode }: IconEntity) => ({
name,
iconNode
}))
}
export default {
@@ -28,7 +22,7 @@ export default {
const icons = await getAllData()
return icons.map((iconEntity) => {
const relatedIcons = getRelatedIcons(iconEntity.name, icons)
const relatedIcons = getRelatedIcons(iconEntity, icons)
const params = {
...iconEntity,
relatedIcons