nuxt / icon

The <Icon> component, supporting Iconify, Emojis and custom components.
https://stackblitz.com/edit/nuxt-icon-playground?file=app.vue
MIT License
868 stars 37 forks source link

fill propery is breaking SVGs #106

Closed MrScriptX closed 8 months ago

MrScriptX commented 9 months ago

The following code snippet from nuxt-icon.svg is breaking SVG by rendering them all black.

&.nuxt-icon--fill, &.nuxt-icon--fill * { fill: currentColor; }

The following bug is happening when using svg with nuxt-svgo module. For some reason, some of the svg get the class nuxt-icon--fill attach to them even though they are not rendered using nuxt-icon.

arunanshub commented 9 months ago

@MrScriptX how do you use nuxt-icon with nuxt-svgo?

RuSaG0 commented 8 months ago

@MrScriptX Hi! I had the same problem and i start use next solution: <nuxt-icon filled="none" /> try it, maybe it'll help you.

AchrafFaddoul commented 6 months ago

@MrScriptX Hi! I had the same problem and i start use next solution: <nuxt-icon filled="none" /> try it, maybe it'll help you.

Thanks, this works for me, where can I find all the props, cause the filled param isn't mentioned in the docs

RuSaG0 commented 6 months ago

@afaddoul Hi! I just read the source code from node_modules.

Here is nuxt-icon (.nuxt-icons/dist/runtime/components/nuxt-icon.vue)

<template>
  <span class="icon" :class="{ 'icon--fill': !filled, 'icon--stroke': hasStroke && !filled }" v-html="icon" />
</template>

<script setup lang="ts">
const props = withDefaults(
  defineProps<{
    name: string
    filled?: boolean
    width?: string | number
    height?: string | number
  }>(),
  {
    filled: false,
    width: '1em',
    height: '1em',
  },
)

const getSizeValue = (parameter: number | string) => (typeof parameter === 'number' ? `${parameter}px` : parameter)

const getWidth = computed(() => {
  return getSizeValue(props.width)
})

const getHeight = computed(() => {
  return getSizeValue(props.height)
})

const icon = ref<string | Record<string, any>>('')
let hasStroke = false

async function getIcon() {
  try {
    const iconsImport = import.meta.glob('assets/icons/**/**.svg', {
      as: 'raw',
      eager: false,
    })
    const rawIcon = await iconsImport[`/assets/icons/${props.name}.svg`]()
    if (rawIcon.includes('stroke')) {
      hasStroke = true
    }
    icon.value = rawIcon
  } catch {
    console.error(`[icons] Icon '${props.name}' doesn't exist in 'assets/icons'`)
  }
}

await getIcon()

watchEffect(getIcon)
</script>

<style lang="scss" scoped>
.icon {
  svg {
    width: v-bind(getWidth);
    height: v-bind(getHeight);
  }
}

.icon--fill {
  fill: currentColor;
}

.icon--stroke {
  stroke: currentColor;
}
</style>

But i change this to solution, which is more suitable for me (delete important from field). For more easiest way to work with Figma & SVG's I use "SVG Export" plugin with currentColor as fill

<template>
  <span class="icon" :class="{ 'icon--fill': !filled, 'icon--stroke': hasStroke && !filled }" v-html="icon" />
</template>

<script setup lang="ts">
const props = withDefaults(
  defineProps<{
    name: string
    filled?: boolean
    width?: string | number
    height?: string | number
  }>(),
  {
    filled: false,
    width: '1em',
    height: '1em',
  },
)

const getSizeValue = (parameter: number | string) => (typeof parameter === 'number' ? `${parameter}px` : parameter)

const getWidth = computed(() => {
  return getSizeValue(props.width)
})

const getHeight = computed(() => {
  return getSizeValue(props.height)
})

const icon = ref<string | Record<string, any>>('')
let hasStroke = false

async function getIcon() {
  try {
    const iconsImport = import.meta.glob('assets/icons/**/**.svg', {
      as: 'raw',
      eager: false,
    })
    const rawIcon = await iconsImport[`/assets/icons/${props.name}.svg`]()
    if (rawIcon.includes('stroke')) {
      hasStroke = true
    }
    icon.value = rawIcon
  } catch {
    console.error(`[icons] Icon '${props.name}' doesn't exist in 'assets/icons'`)
  }
}

await getIcon()

watchEffect(getIcon)
</script>

<style lang="scss" scoped>
.icon {
  svg {
    width: v-bind(getWidth);
    height: v-bind(getHeight);
  }
}

.icon--fill {
  fill: currentColor;
}

.icon--stroke {
  stroke: currentColor;
}
</style>