monacousa-portal/components/MultipleCountryFlags.vue

175 lines
4.0 KiB
Vue
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<span class="multiple-country-flags" :class="{ 'multiple-country-flags--small': size === 'small' }">
<ClientOnly>
<template v-if="countryCodes.length > 0">
<VueCountryFlag
v-for="(code, index) in countryCodes"
:key="`${code}-${index}`"
:country="code"
:size="flagSize"
:title="getCountryName(code)"
class="country-flag-item"
/>
</template>
<template v-else>
<span class="no-nationality">{{ fallbackText }}</span>
</template>
<template #fallback>
<span class="flag-placeholder" :style="placeholderStyle">🏳</span>
</template>
</ClientOnly>
<span v-if="showName && countryCodes.length > 0" class="country-names">
{{ countryNames }}
</span>
</span>
</template>
<script setup lang="ts">
import VueCountryFlag from 'vue-country-flag-next';
import { getCountryName, parseCountryInput } from '~/utils/countries';
interface Props {
nationality?: string; // Can be comma-separated like "FR,MC,US"
showName?: boolean;
size?: 'small' | 'medium' | 'large';
fallbackText?: string;
separator?: string; // For display names
}
const props = withDefaults(defineProps<Props>(), {
nationality: '',
showName: false,
size: 'medium',
fallbackText: 'Not specified',
separator: ', '
});
// Parse multiple nationalities
const countryCodes = computed(() => {
if (!props.nationality) return [];
// Split by comma and clean up
const codes = props.nationality
.split(',')
.map(code => code.trim())
.filter(code => code.length > 0)
.map(code => {
// If it's already a 2-letter code, use it
if (code.length === 2) {
return code.toUpperCase();
}
// Try to parse country name to get the code
return parseCountryInput(code) || '';
})
.filter(code => code.length === 2); // Only keep valid 2-letter codes
// Remove duplicates
return [...new Set(codes)];
});
const countryNames = computed(() => {
return countryCodes.value
.map(code => getCountryName(code))
.filter(name => name)
.join(props.separator);
});
const flagSize = computed(() => {
const sizeMap = {
small: 'sm',
medium: 'md',
large: 'lg'
};
return sizeMap[props.size];
});
const placeholderStyle = computed(() => {
const sizeMap = {
small: '1rem',
medium: '1.5rem',
large: '2rem'
};
return {
width: sizeMap[props.size],
height: `calc(${sizeMap[props.size]} * 0.75)`,
display: 'inline-flex',
alignItems: 'center',
justifyContent: 'center',
borderRadius: '2px',
backgroundColor: '#f5f5f5',
fontSize: '0.75rem'
};
});
</script>
<style scoped>
.multiple-country-flags {
display: inline-flex;
align-items: center;
gap: 0.5rem;
vertical-align: middle;
}
.multiple-country-flags--small {
gap: 0.25rem;
}
.country-flag-item {
border-radius: 2px;
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
flex-shrink: 0;
}
/* Add slight overlap for multiple flags to save space */
.country-flag-item:not(:first-child) {
margin-left: -0.25rem;
}
.multiple-country-flags--small .country-flag-item:not(:first-child) {
margin-left: -0.125rem;
}
.country-names {
font-size: 0.875rem;
color: inherit;
white-space: nowrap;
margin-left: 0.25rem;
}
.multiple-country-flags--small .country-names {
font-size: 0.75rem;
}
.no-nationality {
font-size: 0.875rem;
color: rgba(0, 0, 0, 0.6);
font-style: italic;
}
.multiple-country-flags--small .no-nationality {
font-size: 0.75rem;
}
.flag-placeholder {
border-radius: 2px;
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
flex-shrink: 0;
}
/* Ensure proper flag display */
:deep(.vue-country-flag) {
border-radius: 2px;
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
flex-shrink: 0;
position: relative;
z-index: 1;
}
/* Add hover effect to see all flags clearly */
.multiple-country-flags:hover .country-flag-item:not(:first-child) {
margin-left: 0.125rem;
transition: margin-left 0.2s ease;
}
</style>