Fix RTL not working
This commit is contained in:
parent
aed1e416a5
commit
66423fc98f
@ -5,15 +5,25 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { onMounted } from "vue";
|
||||
import { onMounted, watch } from "vue";
|
||||
import { useI18n } from "vue-i18n";
|
||||
import { setHtmlLocale } from "./i18n";
|
||||
|
||||
const { locale } = useI18n();
|
||||
|
||||
onMounted(() => {
|
||||
// we can safely assume non-nullity here
|
||||
const loading = document.getElementById("loading")!;
|
||||
loading.classList.add("done");
|
||||
setHtmlLocale(locale.value);
|
||||
// this might be null during HMR
|
||||
const loading = document.getElementById("loading");
|
||||
loading?.classList.add("done");
|
||||
|
||||
setTimeout(function () {
|
||||
loading.parentNode!.removeChild(loading);
|
||||
loading?.parentNode?.removeChild(loading);
|
||||
}, 200);
|
||||
});
|
||||
|
||||
// handles ltr/rtl changes
|
||||
watch(locale, (newValue) => {
|
||||
newValue && setHtmlLocale(newValue);
|
||||
});
|
||||
</script>
|
||||
|
||||
@ -16,10 +16,6 @@
|
||||
transition: 0.2s ease transform;
|
||||
}
|
||||
|
||||
body.rtl .shell {
|
||||
direction: ltr;
|
||||
}
|
||||
|
||||
.shell__result {
|
||||
display: flex;
|
||||
padding: 0.5em;
|
||||
|
||||
@ -5,10 +5,6 @@ body {
|
||||
color: #333333;
|
||||
}
|
||||
|
||||
body.rtl {
|
||||
direction: rtl;
|
||||
}
|
||||
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
@ -62,8 +58,8 @@ nav {
|
||||
left: 0;
|
||||
}
|
||||
|
||||
body.rtl nav {
|
||||
left: unset;
|
||||
html[dir="rtl"] nav {
|
||||
left: initial;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
@ -78,8 +74,7 @@ nav .action {
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
body.rtl .action {
|
||||
direction: rtl;
|
||||
html[dir="rtl"] nav .action {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
@ -115,7 +110,7 @@ main {
|
||||
border-radius: 0.125em;
|
||||
}
|
||||
|
||||
body.rtl .breadcrumbs a {
|
||||
html[dir="rtl"] .breadcrumbs a {
|
||||
transform: translateX(-16em);
|
||||
}
|
||||
|
||||
|
||||
@ -8,7 +8,7 @@
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
body.rtl .dashboard .row {
|
||||
html[dir="rtl"] .dashboard .row {
|
||||
margin-right: 16em;
|
||||
}
|
||||
|
||||
@ -64,7 +64,7 @@ p code {
|
||||
border-bottom: 2px solid rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
body.rtl #nav .wrapper {
|
||||
html[dir="rtl"] .dashboard #nav .wrapper {
|
||||
margin-right: 16em;
|
||||
}
|
||||
|
||||
@ -145,7 +145,7 @@ table tr > *:first-child {
|
||||
padding-left: 1em;
|
||||
}
|
||||
|
||||
body.rtl table tr > * {
|
||||
html[dir="rtl"] table tr > * {
|
||||
padding-left: unset;
|
||||
padding-right: 1em;
|
||||
text-align: right;
|
||||
@ -197,7 +197,7 @@ table tr > *:last-child {
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
body.rtl .card .card-title > *:first-child {
|
||||
html[dir="rtl"] .card .card-title > *:first-child {
|
||||
margin-right: 0;
|
||||
text-align: right;
|
||||
}
|
||||
@ -486,7 +486,7 @@ body.rtl .card .card-title > *:first-child {
|
||||
}
|
||||
|
||||
/*** RTL - Fix disk usage information (in english) ***/
|
||||
body.rtl .credits {
|
||||
html[dir="rtl"] .credits {
|
||||
text-align: right;
|
||||
direction: ltr;
|
||||
}
|
||||
|
||||
@ -137,7 +137,7 @@ header .menu-button {
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
body.rtl #search #result {
|
||||
html[dir="rtl"] #search #result {
|
||||
direction: ltr;
|
||||
}
|
||||
|
||||
@ -145,13 +145,13 @@ body.rtl #search #result {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
body.rtl #search #result {
|
||||
html[dir="rtl"] #search #result {
|
||||
direction: rtl;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
/*** RTL - Keep search result LTR because it has paths (in english) ***/
|
||||
body.rtl #search #result ul > * {
|
||||
html[dir="rtl"] #search #result ul > * {
|
||||
direction: ltr;
|
||||
text-align: left;
|
||||
}
|
||||
@ -241,7 +241,7 @@ body.rtl #search #result ul > * {
|
||||
padding: 0.5em;
|
||||
}
|
||||
|
||||
body.rtl #search .boxes h3 {
|
||||
html[dir="rtl"] #search .boxes h3 {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
--item-selected: white;
|
||||
}
|
||||
|
||||
body.rtl #listing {
|
||||
html[dir="rtl"] #listing {
|
||||
margin-right: 16em;
|
||||
}
|
||||
|
||||
|
||||
@ -45,7 +45,7 @@
|
||||
z-index: 99999;
|
||||
}
|
||||
|
||||
body.rtl #dropdown {
|
||||
html[dir="rtl"] #dropdown {
|
||||
right: unset;
|
||||
left: 1em;
|
||||
transform-origin: top left;
|
||||
@ -109,7 +109,7 @@
|
||||
left: -17em;
|
||||
}
|
||||
|
||||
body.rtl nav {
|
||||
html[dir="rtl"] nav {
|
||||
left: unset;
|
||||
right: -17em;
|
||||
}
|
||||
@ -117,7 +117,7 @@
|
||||
left: 0;
|
||||
}
|
||||
|
||||
body.rtl nav.active {
|
||||
html[dir="rtl"] nav.active {
|
||||
left: unset;
|
||||
right: 0;
|
||||
}
|
||||
@ -133,19 +133,19 @@
|
||||
margin-bottom: 5em;
|
||||
}
|
||||
|
||||
body.rtl #listing {
|
||||
html[dir="rtl"] #listing {
|
||||
margin-right: unset;
|
||||
}
|
||||
|
||||
body.rtl .breadcrumbs {
|
||||
html[dir="rtl"] .breadcrumbs {
|
||||
transform: translateX(16em);
|
||||
}
|
||||
|
||||
body.rtl #nav .wrapper {
|
||||
html[dir="rtl"] #nav .wrapper {
|
||||
margin-right: unset;
|
||||
}
|
||||
|
||||
body.rtl .dashboard .row {
|
||||
html[dir="rtl"] .dashboard .row {
|
||||
margin-right: unset;
|
||||
}
|
||||
|
||||
|
||||
@ -315,7 +315,7 @@ main .spinner .bounce2 {
|
||||
}
|
||||
|
||||
/*** RTL - flip and position arrow of path ***/
|
||||
body.rtl .breadcrumbs .chevron {
|
||||
html[dir="rtl"] .breadcrumbs .chevron {
|
||||
transform: scaleX(-1) translateX(16em);
|
||||
}
|
||||
|
||||
@ -420,17 +420,17 @@ body.rtl .breadcrumbs .chevron {
|
||||
* RTL overrides *
|
||||
* * * * * * * * * * * * * * * */
|
||||
|
||||
body.rtl .card-content textarea {
|
||||
html[dir="rtl"] .card-content textarea {
|
||||
direction: ltr;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
body.rtl .card-content .small + input {
|
||||
html[dir="rtl"] .card-content .small + input {
|
||||
direction: ltr;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
body.rtl .card.floating .card-content .file-list {
|
||||
html[dir="rtl"] .card.floating .card-content .file-list {
|
||||
direction: ltr;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
import dayjs from "dayjs";
|
||||
import { createI18n } from "vue-i18n";
|
||||
|
||||
import("dayjs/locale/ar");
|
||||
@ -135,4 +136,23 @@ export const i18n = createI18n({
|
||||
legacy: true,
|
||||
});
|
||||
|
||||
export const isRtl = (locale?: string) => {
|
||||
return rtlLanguages.includes(locale || i18n.global.locale);
|
||||
};
|
||||
|
||||
export function setLocale(locale: string) {
|
||||
dayjs.locale(locale);
|
||||
// according to doc u only need .value if legacy: false but they lied
|
||||
// https://vue-i18n.intlify.dev/guide/essentials/scope.html#local-scope-1
|
||||
//@ts-ignore
|
||||
i18n.global.locale.value = locale;
|
||||
}
|
||||
|
||||
export function setHtmlLocale(locale: string) {
|
||||
const html = document.documentElement;
|
||||
html.lang = locale;
|
||||
if (isRtl(locale)) html.dir = "rtl";
|
||||
else html.dir = "ltr";
|
||||
}
|
||||
|
||||
export default i18n;
|
||||
|
||||
@ -8,7 +8,7 @@ import {
|
||||
} from "vue-toastification/dist/types/types";
|
||||
import createPinia from "@/stores";
|
||||
import router from "@/router";
|
||||
import i18n, { rtlLanguages } from "@/i18n";
|
||||
import i18n, { isRtl } from "@/i18n";
|
||||
import App from "@/App.vue";
|
||||
import CustomToast from "@/components/CustomToast.vue";
|
||||
|
||||
@ -77,7 +77,7 @@ app.provide("$showSuccess", (message: string) => {
|
||||
message: message,
|
||||
},
|
||||
},
|
||||
{ ...toastConfig, rtl: rtlLanguages.includes(i18n.global.locale) }
|
||||
{ ...toastConfig, rtl: isRtl() }
|
||||
);
|
||||
});
|
||||
|
||||
@ -96,7 +96,7 @@ app.provide("$showError", (error: Error | string, displayReport = true) => {
|
||||
{
|
||||
...toastConfig,
|
||||
timeout: 0,
|
||||
rtl: rtlLanguages.includes(i18n.global.locale),
|
||||
rtl: isRtl(),
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
@ -12,7 +12,7 @@ import Shares from "@/views/settings/Shares.vue";
|
||||
import Errors from "@/views/Errors.vue";
|
||||
import { useAuthStore } from "@/stores/auth";
|
||||
import { baseURL, name } from "@/utils/constants";
|
||||
import { i18n, rtlLanguages } from "@/i18n";
|
||||
import { i18n, isRtl, rtlLanguages } from "@/i18n";
|
||||
import { recaptcha, loginPage } from "@/utils/constants";
|
||||
import { login, validateLogin } from "@/utils/auth";
|
||||
|
||||
@ -186,18 +186,6 @@ router.beforeResolve(async (to, from, next) => {
|
||||
// const title = titles[to.name];
|
||||
document.title = title + " - " + name;
|
||||
|
||||
/*** RTL related settings per route ****/
|
||||
const rtlSet = document.querySelector("body")?.classList.contains("rtl");
|
||||
const shouldSetRtl = rtlLanguages.includes(i18n.global.locale);
|
||||
switch (true) {
|
||||
case shouldSetRtl && !rtlSet:
|
||||
document.querySelector("body")?.classList.add("rtl");
|
||||
break;
|
||||
case !shouldSetRtl && rtlSet:
|
||||
document.querySelector("body")?.classList.remove("rtl");
|
||||
break;
|
||||
}
|
||||
|
||||
const authStore = useAuthStore();
|
||||
|
||||
// this will only be null on first route
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import { defineStore } from "pinia";
|
||||
import dayjs from "dayjs";
|
||||
import i18n, { detectLocale } from "@/i18n";
|
||||
import i18n, { detectLocale, setLocale } from "@/i18n";
|
||||
import { cloneDeep } from "lodash-es";
|
||||
|
||||
export const useAuthStore = defineStore("auth", {
|
||||
@ -24,20 +24,12 @@ export const useAuthStore = defineStore("auth", {
|
||||
return;
|
||||
}
|
||||
|
||||
const locale = user.locale || detectLocale();
|
||||
dayjs.locale(locale);
|
||||
// according to doc u only need .value if legacy: false but they lied
|
||||
// https://vue-i18n.intlify.dev/guide/essentials/scope.html#local-scope-1
|
||||
//@ts-ignore
|
||||
i18n.global.locale.value = locale;
|
||||
setLocale(user.locale || detectLocale());
|
||||
this.user = user;
|
||||
},
|
||||
updateUser(user: Partial<IUser>) {
|
||||
if (user.locale) {
|
||||
dayjs.locale(user.locale);
|
||||
// see above
|
||||
//@ts-ignore
|
||||
i18n.global.locale.value = user.locale;
|
||||
setLocale(user.locale);
|
||||
}
|
||||
|
||||
this.user = { ...this.user, ...cloneDeep(user) } as IUser;
|
||||
|
||||
@ -161,9 +161,7 @@ const updateSettings = async (event: Event) => {
|
||||
singleClick: singleClick.value,
|
||||
dateFormat: dateFormat.value,
|
||||
};
|
||||
const shouldReload =
|
||||
rtlLanguages.includes(data.locale) !==
|
||||
rtlLanguages.includes(i18n.global.locale);
|
||||
|
||||
await api.update(data, [
|
||||
"locale",
|
||||
"hideDotfiles",
|
||||
@ -171,9 +169,6 @@ const updateSettings = async (event: Event) => {
|
||||
"dateFormat",
|
||||
]);
|
||||
authStore.updateUser(data);
|
||||
if (shouldReload) {
|
||||
location.reload();
|
||||
}
|
||||
$showSuccess(t("settings.settingsUpdated"));
|
||||
} catch (err) {
|
||||
if (err instanceof Error) {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user