fix: load lazily the app icons

This commit is contained in:
Ruben Fiszel
2024-04-11 14:57:48 +02:00
parent 1b0a4f1cd6
commit cd5b023033
5 changed files with 1517 additions and 42 deletions
@@ -70,20 +70,32 @@
let beforeIconComponent: any
let afterIconComponent: any
$: resolvedConfig.beforeIcon && handleBeforeIcon()
$: resolvedConfig.afterIcon && handleAfterIcon()
$: resolvedConfig.beforeIcon && beforeIconComponent && handleBeforeIcon()
$: resolvedConfig.afterIcon && afterIconComponent && handleAfterIcon()
let confirmedCallback: (() => void) | undefined = undefined
async function handleBeforeIcon() {
if (resolvedConfig.beforeIcon) {
beforeIconComponent = await loadIcon(resolvedConfig.beforeIcon)
beforeIconComponent = await loadIcon(
resolvedConfig.beforeIcon,
beforeIconComponent,
14,
undefined,
undefined
)
}
}
async function handleAfterIcon() {
if (resolvedConfig.afterIcon) {
afterIconComponent = await loadIcon(resolvedConfig.afterIcon)
afterIconComponent = await loadIcon(
resolvedConfig.afterIcon,
afterIconComponent,
14,
undefined,
undefined
)
}
}
@@ -210,17 +222,17 @@
on:click={handleClick}
size={resolvedConfig.size}
color={resolvedConfig.color}
startIcon={{
icon: resolvedConfig.beforeIcon ? beforeIconComponent : undefined
}}
endIcon={{
icon: resolvedConfig.afterIcon ? afterIconComponent : undefined
}}
{loading}
>
{#if resolvedConfig.beforeIcon}
<div class="min-w-4" bind:this={beforeIconComponent} />
{/if}
{#if resolvedConfig.label?.toString() && resolvedConfig.label?.toString()?.length > 0}
<div>{resolvedConfig.label.toString()}</div>
{/if}
{#if resolvedConfig.afterIcon}
<div class="min-w-4" bind:this={afterIconComponent} />
{/if}
</Button>
{/key}
</AlignWrapper>
@@ -29,10 +29,12 @@
let iconComponent: any
$: handleIcon(resolvedConfig.icon)
$: handleIcon(resolvedConfig, iconComponent)
async function handleIcon(i?: string) {
iconComponent = i ? await loadIcon(i) : undefined
async function handleIcon(conf, comp) {
if (conf.icon && comp) {
await loadIcon(conf.icon, iconComponent, conf.size, conf.strokeWidth, conf.color)
}
}
let css = initCss($app.css?.iconcomponent, customCss)
@@ -66,12 +68,9 @@
class={twMerge(css?.container?.class, 'wm-icon-container')}
style={css?.container?.style ?? ''}
>
{#if resolvedConfig.icon && iconComponent}
<svelte:component
this={iconComponent}
size={resolvedConfig.size || 24}
color={resolvedConfig.color || 'currentColor'}
strokeWidth={resolvedConfig.strokeWidth || 2}
{#if resolvedConfig.icon}
<div
bind:this={iconComponent}
class={twMerge(css?.icon?.class, 'wm-icon')}
style={css?.icon?.style ?? ''}
/>
@@ -6,21 +6,34 @@ function toKebabCase(str: string): string {
.toLowerCase()
}
export async function loadIcon(name: string): Promise<any> {
let iconComponent: any
export async function loadIcon(
name: string,
parent: HTMLElement,
size: number | undefined,
strokeWidth: number | undefined,
color: string | undefined
): Promise<any> {
try {
if (name) {
iconComponent = (
await import(
`../../../../../node_modules/lucide-svelte/dist/svelte/icons/${toKebabCase(name)}.svelte`
)
).default
return iconComponent
await fetch(
`https://cdn.jsdelivr.net/npm/lucide-static@0.367.0/icons/${toKebabCase(name)}.svg`
)
.then((response) => response.text())
.then((svg) => (parent.innerHTML = svg))
let elem = parent.children?.[0]
if (elem) {
elem.setAttribute('width', size?.toString() ?? '24')
elem.setAttribute('height', size?.toString() ?? '24')
if (strokeWidth) {
elem.setAttribute('stroke-width', strokeWidth.toString())
}
if (color) {
elem.setAttribute('stroke', color)
}
}
} else {
iconComponent = undefined
}
} catch (error) {
console.error(error)
iconComponent = undefined
}
}
@@ -2,32 +2,26 @@
import type { StaticInput } from '../../../inputType'
import { Loader2 } from 'lucide-svelte'
import { ClearableInput, Popup } from '../../../../common'
import { AllIcons } from './icons'
export let componentInput: StaticInput<string>
let loading = false
let items: { label: string; icon: any }[]
let filteredItems: { label: string; icon: any }[]
let items: string[]
let filteredItems: string[]
let search = ''
$: if (search) {
filteredItems = items.filter((item) => {
return item.label.toLowerCase().includes(search.toLowerCase())
return item.toLowerCase().includes(search.toLowerCase())
})
} else {
filteredItems = items
}
async function getData() {
if (items) {
}
loading = true
// @ts-ignore
const data = await import('lucide-svelte/icons')
filteredItems = items = Object.entries(data)
.filter(([key]) => !(key.endsWith('Icon') || key.startsWith('Lucide')))
.map(([key, icon]) => ({ label: key, icon }))
items = AllIcons
loading = false
}
@@ -80,7 +74,7 @@
class="col-span-4 mb-2"
/>
<div class="grid gap-1 grid-cols-4 max-h-[300px] overflow-auto">
{#each filteredItems as { label, icon }}
{#each filteredItems as label}
<button
type="button"
title={label}
@@ -92,7 +86,10 @@
hover:bg-gray-100 focus:bg-gray-100 rounded duration-200 dark:hover:bg-frost-900 dark:focus:bg-frost-900
{label === componentInput.value ? 'text-blue-600 bg-blue-50 pointer-events-none' : ''}"
>
<svelte:component this={icon} size={22} />
<img
loading="lazy"
src="https://cdn.jsdelivr.net/npm/lucide-static@0.367.0/icons/{label}.svg"
/>
<span class="inline-block w-full text-[10px] ellipsize pt-0.5">
{label}
</span>
File diff suppressed because it is too large Load Diff