Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Finish and persist Profile #310

Merged
merged 12 commits into from
Feb 20, 2024
14 changes: 0 additions & 14 deletions components/ChangeLocale.vue

This file was deleted.

105 changes: 87 additions & 18 deletions components/ProfileMenu.vue
Original file line number Diff line number Diff line change
Expand Up @@ -44,11 +44,34 @@ const logout = async () => {
};

const { locale } = useI18n();
locale.value = profileStore.uiLanguage;
SimonSimCity marked this conversation as resolved.
Show resolved Hide resolved

const languageName = computed(() => getLocalizedLanguageName(locale));
const { contentLanguages } = contentLanguageStore();
const joinedContentLanguages = computed(() =>
getLocalizedList(contentLanguages),
const contentLanguages = ref(
contentLanguageStore().contentLanguages.filter((x) => x !== "zxx"),
);
const joinedContentLanguages = computed(() => {
const list = contentLanguages.value;
return getLocalizedList(list.map((x) => getLocalizedLanguageName(x)));
});
const nextUnusedContentLanguage = () =>
availableContentLanguages.filter(
(x) => !contentLanguages.value.includes(x),
)[0];

const closeInterfaceLanguageDialog = () => {
profileStore.uiLanguage = locale.value;
showInterfaceLanguageDialog.value = false;
};
const closeContentLanguageDialog = () => {
showContentLanguageDialog.value = false;
const newLanguages = contentLanguages.value.concat(["zxx"]);
if (
newLanguages.toString() !==
contentLanguageStore().contentLanguages.toString()
)
contentLanguageStore().contentLanguages = newLanguages;
};
</script>
<template>
<div>
Expand Down Expand Up @@ -80,7 +103,8 @@ const joinedContentLanguages = computed(() =>
class="absolute right-0 mt-2 w-56 origin-top-right divide-y divide-label-separator rounded-xl bg-background-3 text-sm shadow-lg ring-1 ring-label-separator focus-visible:outline-none -separator"
>
<div class="p-1">
<MenuItem v-slot="{ active }">
<!-- Todo: #284 implement autoplay behavior -->
<MenuItem v-if="false" v-slot="{ active }">
kkuepper marked this conversation as resolved.
Show resolved Hide resolved
<button
:class="{
'bg-label-separator -separator': active,
Expand Down Expand Up @@ -229,14 +253,26 @@ const joinedContentLanguages = computed(() =>
:show="showInterfaceLanguageDialog"
:title="$t('profile.interface-language')"
:description="$t('profile.interface-language-description')"
@close="showInterfaceLanguageDialog = false"
@close="closeInterfaceLanguageDialog()"
>
<div
class="bg-background-2 dark:bg-background-dark-2 rounded-2xl p-3 pl-5"
>
<div class="bg-background-2 text-label-2 rounded-2xl p-3">
<label class="self-center flex items-center gap-4 justify-between">
<span>{{ $t("profile.select-language") }}</span>
<ChangeLocale />
<div
class="text-label-1 bg-background-1 min-w-[100px] px-2 py-1.5 rounded-lg font-semibold shadow-[0_4px_12px_0_#0000000D,0_1px_4px_0_#0000000D,0_0_0_1px_#0000000D]"
>
<select v-model="$i18n.locale" class="py-1">
<option
v-for="(lang, i) in $i18n.availableLocales"
:key="`Lang${i}`"
:value="lang"
>
{{
`${languageDictionary[lang]?.NativeName} (${languageDictionary[lang]?.EnglishName})`
}}
</option>
</select>
</div>
</label>
</div>
</DialogBase>
Expand All @@ -245,20 +281,20 @@ const joinedContentLanguages = computed(() =>
:show="showContentLanguageDialog"
:title="$t('profile.content-language')"
:description="$t('profile.content-language-description')"
@close="showContentLanguageDialog = false"
@close="closeContentLanguageDialog()"
>
<VueDraggable
v-model="contentLanguages"
handle=".handle"
:animation="200"
class="bg-background-2 dark:bg-background-dark-2 rounded-2xl font-semibold divide-y divide-label-separator"
class="bg-background-2 rounded-2xl divide-y divide-label-separator"
>
<div
v-for="(lang, i) in contentLanguages"
:key="lang"
class="grid grid-cols-[24px_1fr_24px] items-center px-4 py-3 gap-4 w-full first:rounded-t-2xl last:rounded-b-2xl"
v-for="(item, i) in contentLanguages"
:key="item"
class="grid grid-cols-[24px_1fr_1.5fr_24px] items-center px-4 py-3 gap-4 w-full first:rounded-t-2xl last:rounded-b-2xl"
>
<button class="handle">
<button class="handle text-label-4">
<svg
width="24"
height="24"
Expand All @@ -270,16 +306,49 @@ const joinedContentLanguages = computed(() =>
<path d="M4 15H20" stroke="currentColor" stroke-width="2" />
</svg>
</button>
<div>
{{ t("profile.preference-language-" + Math.min(i + 1, 4), i + 1) }}
</div>
<div
class="text-black-1 bg-background-1 dark:bg-background-3 dark:text-black-1 min-w-[100px] pl-3 py-2.5 shadow ring-1 ring-label-separator rounded-lg"
class="text-label-1 bg-background-1 min-w-min px-2 py-1.5 rounded-lg font-semibold shadow-[0_4px_12px_0_#0000000D,0_1px_4px_0_#0000000D,0_0_0_1px_#0000000D]"
>
{{ lang }}
<select v-model="contentLanguages[i]" class="py-1 w-full">
<option
v-for="(lang, i) in availableContentLanguages
.filter((x) => !contentLanguages.includes(x))
.concat([item])"
:key="`Lang${i}`"
:value="lang"
>
{{
`${languageDictionary[lang]?.NativeName} (${getLocalizedLanguageName(lang)})`
}}
</option>
</select>
</div>
<button v-if="i > 0" class="text-2xl">

<button
v-if="i > 0"
class="text-2xl"
@click="contentLanguages.splice(i, 1)"
>
<NuxtIcon name="icon.close.small" />
</button>
</div>
</VueDraggable>
<div
v-if="nextUnusedContentLanguage()"
class="text-label-3 p-3 flex flex-row gap-2 mt-4"
@click="
kkuepper marked this conversation as resolved.
Show resolved Hide resolved
() => {
const next = nextUnusedContentLanguage();
if (next) contentLanguages.push(next);
}
"
>
<NuxtIcon name="icon.add"></NuxtIcon>
{{ t("profile.add-another-language") }}
</div>
</DialogBase>
</div>
</template>
2 changes: 1 addition & 1 deletion components/TileItem.vue
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ const weekDay = (date: Date) => {
>
<div class="opacity-70">{{ item.title }}</div>
<div class="font-semibold text-lg">{{ item.label }}</div>
<div v-if="item.date" class="text-sm">
<div v-if="item.date" class="text-sm whitespace-nowrap">
{{ weekDay(item.date) }}
<span class="opacity-70">{{ formatDate(item.date) }}</span>
</div>
Expand Down
4 changes: 2 additions & 2 deletions components/dialog/DialogBase.vue
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ const emit = defineEmits<{
leave-from="opacity-100"
leave-to="opacity-0"
>
<DialogBackdrop class="fixed inset-0 bg-background-4 opacity-40" />
<DialogBackdrop class="fixed z-30 inset-0 bg-background-4 opacity-40" />
</TransitionChild>

<div
Expand Down Expand Up @@ -66,7 +66,7 @@ const emit = defineEmits<{
class="bg-label-1 dark:bg-label-dark-1 h-[1px] opacity-10"
></div>
<div class="p-5 overflow-auto max-h-[80vh]">
<DialogDescription v-if="description" class="mb-4">
<DialogDescription v-if="description" class="mb-4 text-label-2">
{{ description }}
</DialogDescription>
<slot />
Expand Down
9 changes: 7 additions & 2 deletions locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,17 +24,22 @@
"theme-description": "Select the theme used for the interface.",
"app-language": "Language",
"interface-language": "Interface Language",
"interface-language-description": "The language used for the interface.",
"interface-language-description": "Select the language used for the interface.",
"select-language": "Select language",
"content-language": "Content Language",
"content-language-description": "The preferred language for the content you are listening to.",
"preference-language-1": "Preferred language",
"preference-language-2": "Second language",
"preference-language-3": "Third language",
"preference-language-4": "{count}th language",
"uservoice": "User Voice",
"contact": "Contact",
"logout": "Sign out",
"theme-dark": "Dark",
"theme-light": "Light",
"theme-system": "Same as system",
"done": "Done"
"done": "Done",
"add-another-language": "Add another language"
},
"error": {
"page-not-found": {
Expand Down
2 changes: 2 additions & 0 deletions stores/profile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@ export const useProfileStore = defineStore(
"profile",
() => {
const autoplay = ref(false);
const uiLanguage = ref("en");

return {
autoplay,
uiLanguage,
};
},
{
Expand Down
32 changes: 32 additions & 0 deletions utils/availableContentLanguages.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
const availableContentLanguages = [
"nb",
"en",
"de",
"af",
"bg",
"cs",
"da",
"el",
"es",
"et",
"fi",
"fr",
"he",
"hr",
"hu",
"it",
"nl",
"pl",
"pt",
"ro",
"ru",
"sl",
"ta",
"tr",
"zh",
"ml",
"yue",
"kha",
];
kkuepper marked this conversation as resolved.
Show resolved Hide resolved

export default availableContentLanguages;
3 changes: 2 additions & 1 deletion utils/getLocalizedLanguageName.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,6 @@ export default function getLocalizedLanguageName(key: MaybeRef<string>) {
const k = unref(key);
const intl = new Intl.DisplayNames([locale.value], { type: "language" });

return intl.of(k);
const translatedValue = intl.of(k) ?? "Unknown";
return translatedValue === "kha" ? "Khasi" : translatedValue;
}
38 changes: 38 additions & 0 deletions utils/languageDictionary.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
type ILanguageInfo = {
EnglishName: string;
NativeName: string;
};

const languageDictionary: { [key: string]: ILanguageInfo } = {
af: { EnglishName: "Afrikaans", NativeName: "Afrikaans" },
bg: { EnglishName: "Bulgarian", NativeName: "български" },
cs: { EnglishName: "Czech", NativeName: "čeština" },
da: { EnglishName: "Danish", NativeName: "dansk" },
de: { EnglishName: "German", NativeName: "Deutsch" },
en: { EnglishName: "English", NativeName: "English" },
el: { EnglishName: "Greek", NativeName: "Ελληνικά" },
es: { EnglishName: "Spanish", NativeName: "español" },
et: { EnglishName: "Estonian", NativeName: "eesti" },
fr: { EnglishName: "French", NativeName: "Français" },
fi: { EnglishName: "Finnish", NativeName: "suomi" },
he: { EnglishName: "Hebrew", NativeName: "עברית" },
hr: { EnglishName: "Croatian", NativeName: "hrvatski" },
hu: { EnglishName: "Hungarian", NativeName: "magyar" },
it: { EnglishName: "Italian", NativeName: "italiano" },
kha: { EnglishName: "Khasi", NativeName: "Khasi" },
nb: { EnglishName: "Norwegian", NativeName: "Norsk" },
nl: { EnglishName: "Dutch", NativeName: "Nederlands" },
ml: { EnglishName: "Malayalam", NativeName: "മലയ\u0D3Eള\u0D02" },
pl: { EnglishName: "Polish", NativeName: "polski" },
pt: { EnglishName: "Portuguese", NativeName: "português" },
ro: { EnglishName: "Romanian", NativeName: "română" },
ru: { EnglishName: "Russian", NativeName: "русский" },
sl: { EnglishName: "Slovenian", NativeName: "slovenščina" },
ta: { EnglishName: "Tamil", NativeName: "தம\u0BBFழ\u0BCD" },
tr: { EnglishName: "Turkish", NativeName: "Türkçe" },
zh: { EnglishName: "Chinese (Simplified)", NativeName: "中文" },
uk: { EnglishName: "Ukrainian", NativeName: "українська" },
yue: { EnglishName: "Cantonese", NativeName: "廣東話" },
};

export default languageDictionary;
Loading