feat: Flag icon component (#10564)

This commit is contained in:
Sivin Varghese
2024-12-10 11:53:24 +05:30
committed by GitHub
parent aebcbb63e4
commit 1b0e94ec95
7 changed files with 153 additions and 14 deletions

View File

@@ -6,6 +6,7 @@ import CardLayout from 'dashboard/components-next/CardLayout.vue';
import ContactsForm from 'dashboard/components-next/Contacts/ContactsForm/ContactsForm.vue';
import Button from 'dashboard/components-next/button/Button.vue';
import Avatar from 'dashboard/components-next/avatar/Avatar.vue';
import Flag from 'dashboard/components-next/flag/Flag.vue';
import countries from 'shared/constants/countries';
const props = defineProps({
@@ -56,13 +57,19 @@ const countryDetails = computed(() => {
if (!activeCountry) return null;
const parts = [
activeCountry.emoji,
city ? `${city},` : null,
activeCountry.name,
].filter(Boolean);
return {
countryCode: activeCountry.id,
city: city ? `${city},` : null,
name: activeCountry.name,
};
});
return parts.length ? parts.join(' ') : null;
const formattedLocation = computed(() => {
if (!countryDetails.value) return '';
return [countryDetails.value.city, countryDetails.value.name]
.filter(Boolean)
.join(' ');
});
const handleFormUpdate = updatedData => {
@@ -114,8 +121,12 @@ const onClickViewDetails = () => emit('showContact', props.id);
{{ phoneNumber }}
</span>
<div v-if="phoneNumber" class="w-px h-3 truncate bg-n-slate-6" />
<span v-if="countryDetails" class="text-sm truncate text-n-slate-11">
{{ countryDetails }}
<span
v-if="countryDetails"
class="inline-flex items-center gap-2 text-sm truncate text-n-slate-11"
>
<Flag :country="countryDetails.countryCode" class="size-3.5" />
{{ formattedLocation }}
</span>
<div v-if="countryDetails" class="w-px h-3 truncate bg-n-slate-6" />
<Button

View File

@@ -0,0 +1,24 @@
<script setup>
import { h, defineProps } from 'vue';
const props = defineProps({
country: { type: String, required: true },
squared: { type: Boolean, default: false },
});
const renderFlag = () => {
const classes = ['fi', `fi-${props.country.toLowerCase()}`, 'flex-shrink-0'];
if (props.squared) {
classes.push('fis');
}
return h('span', { class: classes });
};
</script>
<template>
<component :is="renderFlag" />
</template>
<style>
@import 'flag-icons/css/flag-icons.min.css';
</style>

View File

@@ -0,0 +1,93 @@
<script setup>
import { ref } from 'vue';
import Flag from '../Flag.vue';
import countries from 'shared/constants/countries';
const BasicTemplate = {
components: { Flag },
props: {
country: {
type: String,
default: 'us',
},
squared: {
type: Boolean,
default: false,
},
},
template: `
<div class="flex items-center gap-4 p-4 border rounded border-n-weak">
<Flag :country="country" :squared="squared" />
</div>
`,
};
const SizeVariants = {
components: { Flag },
setup() {
const isSquared = ref(false);
return { isSquared };
},
template: `
<div class="flex flex-col gap-4">
<label class="flex items-center gap-2">
<input type="checkbox" v-model="isSquared">
Squared flags
</label>
<div class="flex items-center gap-4 p-4 border rounded border-n-weak">
<Flag country="in" class="!size-4" :squared="isSquared" />
<Flag country="in" class="!size-6" :squared="isSquared" />
<Flag country="in" class="!size-8" :squared="isSquared" />
<Flag country="in" class="!size-10" :squared="isSquared" />
</div>
</div>
`,
};
const AllFlags = {
components: { Flag },
setup() {
const isSquared = ref(false);
return { countries, isSquared };
},
template: `
<div class="flex flex-col gap-4">
<label class="flex items-center gap-2">
<input type="checkbox" v-model="isSquared">
Squared flags
</label>
<div class="grid grid-cols-2 gap-4 p-4 border rounded border-n-strong md:grid-cols-3 lg:grid-cols-4">
<div
v-for="country in countries"
:key="country.id"
class="flex items-center gap-2 px-4 py-2 border rounded border-n-strong"
>
<Flag
:country="country.id"
:squared="isSquared"
class="size-6"
/>
<span class="text-sm">{{ country.name }}</span>
</div>
</div>
</div>
`,
};
</script>
<template>
<Story title="Components/Flag">
<Variant title="Basic Usage">
<BasicTemplate country="us" :squared="false" />
</Variant>
<Variant title="Size Variants">
<SizeVariants />
</Variant>
<Variant title="All Flags">
<AllFlags />
</Variant>
</Story>
</template>

View File

@@ -9,7 +9,6 @@ import SocialIcons from './SocialIcons.vue';
import EditContact from './EditContact.vue';
import NewConversation from './NewConversation.vue';
import ContactMergeModal from 'dashboard/modules/contact/ContactMergeModal.vue';
import { getCountryFlag } from 'dashboard/helper/flag';
import { BUS_EVENTS } from 'shared/constants/busEvents';
import {
isAConversationRoute,
@@ -127,8 +126,12 @@ export default {
},
findCountryFlag(countryCode, cityAndCountry) {
try {
const countryFlag = countryCode ? getCountryFlag(countryCode) : '🌎';
return `${cityAndCountry} ${countryFlag}`;
if (!countryCode) {
return `${cityAndCountry} 🌎`;
}
const code = countryCode?.toLowerCase();
return `${cityAndCountry} <span class="fi fi-${code} size-3.5"></span>`;
} catch (error) {
return '';
}

View File

@@ -87,10 +87,9 @@ export default {
/>
<span
v-if="value"
v-dompurify-html="value"
class="overflow-hidden text-sm whitespace-nowrap text-ellipsis"
>
{{ value }}
</span>
/>
<span v-else class="text-sm text-slate-300 dark:text-slate-600">{{
$t('CONTACT_PANEL.NOT_AVAILABLE')
}}</span>

View File

@@ -66,6 +66,7 @@
"date-fns": "2.21.1",
"date-fns-tz": "^1.3.3",
"dompurify": "3.1.6",
"flag-icons": "^7.2.3",
"floating-vue": "^5.2.2",
"highlight.js": "^11.10.0",
"idb": "^8.0.0",

8
pnpm-lock.yaml generated
View File

@@ -121,6 +121,9 @@ importers:
dompurify:
specifier: 3.1.6
version: 3.1.6
flag-icons:
specifier: ^7.2.3
version: 7.2.3
floating-vue:
specifier: ^5.2.2
version: 5.2.2(vue@3.5.12(typescript@5.6.2))
@@ -2854,6 +2857,9 @@ packages:
resolution: {integrity: sha512-v2ZsoEuVHYy8ZIlYqwPe/39Cy+cFDzp4dXPaxNvkEuouymu+2Jbz0PxpKarJHYJTmv2HWT3O382qY8l4jMWthw==}
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
flag-icons@7.2.3:
resolution: {integrity: sha512-X2gUdteNuqdNqob2KKTJTS+ZCvyWeLCtDz9Ty8uJP17Y4o82Y+U/Vd4JNrdwTAjagYsRznOn9DZ+E/Q52qbmqg==}
flat-cache@3.1.0:
resolution: {integrity: sha512-OHx4Qwrrt0E4jEIcI5/Xb+f+QmJYNj2rrK8wiIdQOIrB9WrrJL8cjZvXdXuBTkkEwEqLycb5BeZDV1o2i9bTew==}
engines: {node: '>=12.0.0'}
@@ -8159,6 +8165,8 @@ snapshots:
locate-path: 7.2.0
path-exists: 5.0.0
flag-icons@7.2.3: {}
flat-cache@3.1.0:
dependencies:
flatted: 3.2.9