Skip to content

Commit

Permalink
flags
Browse files Browse the repository at this point in the history
  • Loading branch information
arily committed Jul 26, 2023
1 parent 5cfe3ea commit 4ce7368
Show file tree
Hide file tree
Showing 14 changed files with 448 additions and 27 deletions.
1 change: 1 addition & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{
"cSpell.words": [
"antfu",
"anticheat",
"Atropos",
"autoincrement",
Expand Down
15 changes: 15 additions & 0 deletions src/common/utils/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { CountryCode } from '~/def/country-code'

export * from './asserts'
export * from './guards'
export * from './map'
Expand Down Expand Up @@ -34,3 +36,16 @@ export function lazySingleton<TArg, TRet, TFac extends (...args: readonly TArg[]
return singleton
}) as TFac
}

const reverseCountryCode = Object.fromEntries(Object.entries(CountryCode).map(([k, v]) => [v, k.replace(/([A-Z])/g, ' $1').trim()]))
export function toCountryCode(country: string): CountryCode {
const uppercase = country.toUpperCase()
if (uppercase in reverseCountryCode) {
return uppercase as CountryCode
}
throw new Error('unknown country code')
}

export function toCountryName(country: CountryCode): string {
return reverseCountryCode[country]
}
104 changes: 104 additions & 0 deletions src/components/T/combo-box.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
<script setup lang="ts" generic="T extends string | number | symbol">
import { computed, ref } from 'vue'
import {
Combobox,
ComboboxButton,
ComboboxInput,
ComboboxOption,
ComboboxOptions,
TransitionRoot,
} from '@headlessui/vue'
// import { CheckIcon, ChevronUpDownIcon } from '@heroicons/vue/20/solid'
interface Option {
value: T
label: string
}
const props = defineProps<{
options: Option[]
modelValue: T
}>()
const selected = ref(props.options.find(opt => opt.value === props.modelValue))
const query = ref('')
const filtered = computed(() =>
query.value === ''
? props.options
: props.options.filter(person =>
person.label
.toLowerCase()
.replace(/\s+/g, '')
.includes(query.value.toLowerCase().replace(/\s+/g, ''))
)
)
</script>

<template>
<Combobox v-model="selected" class="z-40">
<div class="relative mt-1">
<ComboboxInput
class="w-full border-none py-2 pl-3 pr-10 text-sm leading-5 text-gray-900 focus:ring-0"
:display-value="(value) => (value as Option)?.label"
@change="query = $event.target.value"
/>
<ComboboxButton
class="absolute inset-y-0 right-0 flex items-center pr-2"
>
<ChevronUpDownIcon
class="h-5 w-5 text-gray-400"
aria-hidden="true"
/>
</ComboboxButton>
<TransitionRoot
leave="transition ease-in duration-100"
leave-from="opacity-100"
leave-to="opacity-0"
@after-leave="query = ''"
>
<ComboboxOptions
class="absolute mt-1 max-h-60 w-full overflow-auto rounded-md bg-white py-1 text-base shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none sm:text-sm"
>
<div
v-if="filtered.length === 0 && query !== ''"
class="relative cursor-default select-none py-2 px-4 text-gray-700"
>
Nothing found.
</div>

<ComboboxOption
v-for="entry in filtered"
:key="entry.value"
v-slot="{ selected, active }"
as="template"
:value="entry"
>
<li
class="relative cursor-default select-none py-2 pl-10 pr-4"
:class="{
'bg-teal-600 text-white': active,
'text-gray-900': !active,
}"
>
<span
class="block truncate"
:class="{ 'font-medium': selected, 'font-normal': !selected }"
>
{{ entry.label }}
</span>
<span
v-if="selected"
class="absolute inset-y-0 left-0 flex items-center pl-3"
:class="{ 'text-white': active, 'text-teal-600': !active }"
>
<CheckIcon class="h-5 w-5" aria-hidden="true" />
</span>
</li>
</ComboboxOption>
</ComboboxOptions>
</TransitionRoot>
</div>
</Combobox>
</template>
8 changes: 4 additions & 4 deletions src/components/T/single-select.vue
Original file line number Diff line number Diff line change
Expand Up @@ -9,20 +9,20 @@ import {
interface Option {
label: string | number
value: any
value: unknown
disabled?: boolean
}
const props = defineProps<{
size?: 'xs' | 'sm' | 'lg'
options: Option[]
modelValue?: Option
modelValue?: Option['value']
}>()
const e = defineEmits<{
(e: 'update:modelValue', value: Option): void
(e: 'update:modelValue', value: Option['value']): void
}>()
const selected = computed(() => props.options.find((value) => {
return value.label === props.modelValue?.label
return value.value === props.modelValue
}))
const root = ref<InstanceType<typeof Listbox>>()
defineExpose({
Expand Down
Loading

0 comments on commit 4ce7368

Please sign in to comment.