Redesign of language selector #100 (#101)

* feat: add new language selector in footer, add pirate language

* fix: translations in title bar not updating

* chore: refactor into separate component

* fix: update translate url

* fix: update pirate translation to use "ship" instead of "plank" for platform

a very very necessary change
This commit is contained in:
DecDuck
2025-06-08 10:33:41 +10:00
committed by GitHub
parent a199393e29
commit 0e023534a7
8 changed files with 633 additions and 91 deletions

View File

@ -0,0 +1,142 @@
<template>
<div>
<Listbox v-model="wiredLocale" as="div">
<ListboxLabel class="block text-sm/6 font-medium text-zinc-400">{{
$t("selectLanguage")
}}</ListboxLabel>
<div class="relative mt-2">
<ListboxButton
class="grid w-full cursor-default grid-cols-1 rounded-md bg-zinc-900 py-1.5 pr-2 pl-3 text-left text-zinc-300 outline-1 -outline-offset-1 outline-zinc-700 focus:outline-2 focus:-outline-offset-2 focus:outline-blue-600 sm:text-sm/6"
>
<span class="col-start-1 row-start-1 flex items-center gap-3 pr-6">
<span alt="" class="-mt-0.5 shrink-0 rounded-full">{{
localeToEmoji(wiredLocale)
}}</span>
<span class="block truncate">{{
currentLocaleInformation?.name ?? wiredLocale
}}</span>
</span>
<ChevronUpDownIcon
class="col-start-1 row-start-1 size-5 self-center justify-self-end text-gray-500 sm:size-4"
aria-hidden="true"
/>
</ListboxButton>
<transition
leave-active-class="transition ease-in duration-100"
leave-from-class="opacity-100"
leave-to-class="opacity-0"
>
<ListboxOptions
class="absolute z-10 mt-1 max-h-56 w-full overflow-auto rounded-md bg-zinc-900 py-1 text-base shadow-lg ring-1 ring-black/5 focus:outline-hidden sm:text-sm"
>
<ListboxOption
v-for="listLocale in locales"
:key="listLocale.code"
v-slot="{ active, selected }"
as="template"
:value="listLocale.code"
>
<li
:class="[
active
? 'bg-blue-600 text-white outline-hidden'
: 'text-zinc-300',
'relative cursor-default py-2 pr-9 pl-3 select-none',
]"
>
<div class="flex items-center">
<span class="-mt-0.5 shrink-0 rounded-full">
{{ localeToEmoji(listLocale.code) }}
</span>
<span
:class="[
selected ? 'font-semibold' : 'font-normal',
'ml-3 block truncate',
]"
>{{ listLocale.name }}</span
>
</div>
<span
v-if="selected"
:class="[
active ? 'text-white' : 'text-blue-600',
'absolute inset-y-0 right-0 flex items-center pr-4',
]"
>
<CheckIcon class="size-5" aria-hidden="true" />
</span>
</li>
</ListboxOption>
</ListboxOptions>
</transition>
</div>
</Listbox>
<NuxtLink
class="mt-1 transition text-blue-500 hover:text-blue-600 text-sm"
to="https://translate.droposs.org/projects/drop/"
target="_blank"
>
<i18n-t
keypath="helpUsTranslate"
tag="span"
scope="global"
class="inline-flex items-center gap-x-1 hover:underline"
>
<template #arrow>
<ArrowTopRightOnSquareIcon class="size-4" />
</template>
</i18n-t>
</NuxtLink>
<DevOnly
><h1 class="mt-3 text-sm text-gray-500">{{ $t("welcome") }}</h1>
</DevOnly>
</div>
</template>
<script setup lang="ts">
import {
Listbox,
ListboxButton,
ListboxLabel,
ListboxOption,
ListboxOptions,
} from "@headlessui/vue";
import { ChevronUpDownIcon } from "@heroicons/vue/16/solid";
import { ArrowTopRightOnSquareIcon } from "@heroicons/vue/24/outline";
const { locales, locale, setLocale } = useI18n();
function localeToEmoji(local: string): string {
switch (local) {
case "en":
case "en-gb":
case "en-ca":
case "en-au":
case "en-us": {
return "🇺🇸";
}
case "en-pirate": {
return "🏴‍☠️";
}
default: {
return "❓";
}
}
}
const wiredLocale = computed({
get() {
return locale.value;
},
set(v) {
setLocale(v);
},
});
const currentLocaleInformation = computed(() =>
locales.value.find((e) => e.code == wiredLocale.value),
);
</script>

View File

@ -13,7 +13,7 @@
name="search"
autocomplete="off"
class="block w-full rounded-md bg-zinc-900 py-2 pl-9 pr-2 text-sm text-zinc-100 outline outline-1 -outline-offset-1 outline-zinc-700 placeholder:text-gray-400 focus:outline focus:outline-2 focus:-outline-offset-2 focus:outline-blue-600"
placeholder="$t('library.search')"
:placeholder="$t('library.search')"
/>
<MagnifyingGlassIcon
class="pointer-events-none absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-zinc-400"

View File

@ -8,6 +8,9 @@
<p class="text-sm leading-6 text-zinc-300">
{{ $t("drop.desc") }}
</p>
<LanguageSelector />
<div class="flex space-x-6">
<NuxtLink
v-for="item in navigation.social"
@ -90,6 +93,7 @@
<script setup lang="ts">
import { IconsDiscordLogo, IconsGithubLogo } from "#components";
const { t } = useI18n();
const navigation = {

View File

@ -54,7 +54,6 @@
</transition>
</Menu>
</li>
<UserHeaderSelectLang />
<UserHeaderUserWidget />
</ol>
</div>
@ -176,9 +175,7 @@
</UserHeaderWidget>
</li>
<li class="w-full">
<UserHeaderWidget class="w-full">
<UserHeaderSelectLang />
</UserHeaderWidget>
<UserHeaderWidget class="w-full" />
</li>
</div>
</nav>
@ -209,7 +206,7 @@ const router = useRouter();
const { t } = useI18n();
const homepageURL = "/store";
const navigation: Array<NavigationItem> = [
const navigation: Ref<Array<NavigationItem>> = computed(() => [
{
prefix: "/store",
route: "/store",
@ -230,9 +227,9 @@ const navigation: Array<NavigationItem> = [
route: "/news",
label: t("userHeader.links.news"),
},
];
]);
const currentPageIndex = useCurrentNavigationIndex(navigation);
const currentPageIndex = useCurrentNavigationIndex(navigation.value);
const notifications = useNotifications();
const unreadNotifications = computed(() =>

View File

@ -1,78 +0,0 @@
<script setup lang="ts">
import { Menu, MenuButton, MenuItems, MenuItem } from "@headlessui/vue";
import { ChevronDownIcon } from "@heroicons/vue/16/solid";
const { locales, locale: currLocale, setLocale } = useI18n();
function localToEmoji(local: string): string {
switch (local) {
case "en":
case "en-gb":
case "en-ca":
case "en-au":
case "en-us": {
return "🇺🇸";
}
case "en-pirate": {
return "🏴‍☠️";
}
default: {
return "❓";
}
}
}
</script>
<template>
<Menu as="div" class="relative inline-block">
<MenuButton>
<UserHeaderWidget>
<div
class="inline-flex items-center text-zinc-300 hover:text-white h-5"
>
<EmojiText :emoji="localToEmoji(currLocale)" />
<!-- <span class="ml-2 text-sm font-bold">{{ locale }}</span> -->
<ChevronDownIcon class="ml-3 h-4" />
</div>
</UserHeaderWidget>
</MenuButton>
<transition
enter-active-class="transition ease-out duration-100"
enter-from-class="transform opacity-0 scale-95"
enter-to-class="transform opacity-100 scale-100"
leave-active-class="transition ease-in duration-75"
leave-from-class="transform opacity-100 scale-100"
leave-to-class="transform opacity-0 scale-95"
>
<MenuItems
class="absolute right-0 top-10 z-50 w-56 origin-top-right focus:outline-none shadow-md"
>
<PanelWidget class="flex-col gap-y-2">
<div class="flex flex-col">
<MenuItem
v-for="locale in locales"
:key="locale.code"
hydrate-on-visible
as="div"
>
<button @click="setLocale(locale.code)">
<EmojiText :emoji="localToEmoji(locale.code)" />
{{ locale.name }}
</button>
</MenuItem>
</div>
</PanelWidget>
</MenuItems>
</transition>
</Menu>
</template>
<style scoped>
img.emoji {
height: 1em;
width: 1em;
margin: 0 0.05em 0 0.1em;
vertical-align: -0.1em;
}
</style>