115 lines
3.3 KiB
Vue

<template>
<span
v-if="v && svgs[v as string] !== undefined"
v-html="svgs[v as string]"
></span>
<img
v-else-if="iconSource"
:src="iconSource"
:style="`height: ${size}em; width: ${size}em; display: inline;`"
alt=""
:class="['icon', $attrs.class]"
@error="fallBack"
>
<span v-else aria-hidden="true" :class="[`fa${iconSet}`, `fa-${icon}`, 'fa-fw', hover ? 'fa-hover' : '']" :style></span>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
import type { PropType } from 'vue';
import BlueSky from '~/public/img/bluesky.svg';
const svgDataToHtml = (svgDataString: string): string => decodeURI(svgDataString).replace(/^.*<svg /, '<svg class="icon" ');
const buildQueue = (v: string | (string | undefined)[] | null): { value: string; fallbacks: string[]; svgs: Record<string, any> } => {
const rawValues = Array.isArray(v) ? v : [v];
let values = rawValues.filter((x) => !!x) as string[];
if (!values.length) {
values = ['spacer'];
}
return {
value: values.shift()!,
fallbacks: values,
svgs: {
bluesky: svgDataToHtml(BlueSky),
},
};
};
export default defineComponent({
props: {
v: { required: true, type: [String, Array] as PropType<string | (string | undefined)[] | null> },
set: { default: 'l', type: String as PropType<'l' | 's' | 'b'> },
size: { default: 1, type: Number },
inverse: { type: Boolean },
hover: { type: Boolean },
},
data() {
return buildQueue(this.v);
},
computed: {
valueParts(): string[] {
return this.value.split(':');
},
icon(): string {
const icon = this.valueParts[this.valueParts.length - 1];
if (icon === 'neutrum') {
return 'neuter';
}
return icon;
},
iconSet(): string {
return this.valueParts.length > 1 ? this.valueParts[0] : this.set;
},
iconSource(): string | null {
if (this.value.startsWith('https://')) {
return this.value;
}
if (this.value.endsWith('.svg')) {
return `/img/${this.inverse ? this.value.replace('.svg', '-inverse.svg') : this.value}`;
}
if (this.value.endsWith('.png')) {
return `/img/${this.inverse ? this.value.replace('.png', '-inverse.png') : this.value}`;
}
return null;
},
style(): string {
const properties = [];
if (this.size !== 1) {
properties.push(`font-size: ${this.size}em`);
}
if (this.v === 'neutrum') {
properties.push('transform: rotate(225deg)');
}
return properties.join(';');
},
},
watch: {
v(v) {
const { value, fallbacks } = buildQueue(v);
this.value = value;
this.fallbacks = fallbacks;
},
},
methods: {
fallBack() {
if (!this.fallbacks.length) {
return;
}
this.value = this.fallbacks.shift()!;
},
},
});
</script>
<style lang="scss">
.fa-hover:hover {
font-weight: 900;
}
</style>