Browse Source

Merge pull request #4390 from nocodb/fix/rtl-style

fix(nc-gui): apply ltr/rtl direction on language switch
pull/4297/merge
navi 2 years ago committed by GitHub
parent
commit
393e8be645
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 19
      packages/nc-gui/components/general/language/Menu.vue
  2. 23
      packages/nc-gui/components/smartsheet/toolbar/ShareView.vue
  3. 1
      packages/nc-gui/lib/types.ts
  4. 8
      packages/nc-gui/pages/[projectType]/form/[viewId].vue
  5. 5
      packages/nc-gui/plugins/a.i18n.ts
  6. 14
      packages/nc-gui/utils/viewUtils.ts

19
packages/nc-gui/components/general/language/Menu.vue

@ -1,6 +1,6 @@
<script lang="ts" setup> <script lang="ts" setup>
import { Language } from '~/lib' import { Language } from '~/lib'
import { onMounted, useGlobal, useI18n, useNuxtApp } from '#imports' import { useGlobal, useI18n, useNuxtApp } from '#imports'
import { setI18nLanguage } from '~/plugins/a.i18n' import { setI18nLanguage } from '~/plugins/a.i18n'
const { $e } = useNuxtApp() const { $e } = useNuxtApp()
@ -11,31 +11,14 @@ const { locale } = useI18n()
const languages = $computed(() => Object.entries(Language).sort() as [keyof typeof Language, Language][]) const languages = $computed(() => Object.entries(Language).sort() as [keyof typeof Language, Language][])
const isRtlLang = $computed(() => ['fa', 'ar'].includes(currentLang.value))
function applyDirection() {
const targetDirection = isRtlLang ? 'rtl' : 'ltr'
const oppositeDirection = targetDirection === 'ltr' ? 'rtl' : 'ltr'
document.body.classList.remove(oppositeDirection)
document.body.classList.add(targetDirection)
document.body.style.direction = targetDirection
}
async function changeLanguage(lang: string) { async function changeLanguage(lang: string) {
const nextLang = lang as keyof typeof Language const nextLang = lang as keyof typeof Language
await setI18nLanguage(nextLang) await setI18nLanguage(nextLang)
currentLang.value = nextLang currentLang.value = nextLang
applyDirection()
$e('c:navbar:lang', { lang }) $e('c:navbar:lang', { lang })
} }
onMounted(() => {
applyDirection()
})
</script> </script>
<template> <template>

23
packages/nc-gui/components/smartsheet/toolbar/ShareView.vue

@ -40,6 +40,14 @@ const passwordProtected = ref(false)
const shared = ref<SharedView>({ id: '', meta: {}, password: undefined }) const shared = ref<SharedView>({ id: '', meta: {}, password: undefined })
const withRTL = computed({
get: () => !!shared.value.meta.rtl,
set: (rtl) => {
shared.value.meta = { ...shared.value.meta, rtl }
updateSharedViewMeta()
},
})
const transitionDuration = computed({ const transitionDuration = computed({
get: () => shared.value.meta.transitionDuration || 250, get: () => shared.value.meta.transitionDuration || 250,
set: (duration) => { set: (duration) => {
@ -105,7 +113,7 @@ const sharedViewUrl = computed(() => {
viewType = 'view' viewType = 'view'
} }
return `${dashboardUrl?.value}#/nc/${viewType}/${shared.value.uuid}` return encodeURI(`${dashboardUrl?.value}#/nc/${viewType}/${shared.value.uuid}`)
}) })
async function saveAllowCSVDownload() { async function saveAllowCSVDownload() {
@ -285,6 +293,19 @@ watch(passwordProtected, (value) => {
</Transition> </Transition>
</div> </div>
<div>
<!-- use RTL orientation in form - todo: i18n -->
<a-checkbox
v-if="shared.type === ViewTypes.FORM"
v-model:checked="withRTL"
data-testid="nc-modal-share-view__locale"
class="!text-sm"
>
<!-- todo i18n -->
RTL Orientation
</a-checkbox>
</div>
<div> <div>
<!-- Password Protection --> <!-- Password Protection -->
<a-checkbox <a-checkbox

1
packages/nc-gui/lib/types.ts

@ -86,6 +86,7 @@ export interface SharedViewMeta extends Record<string, any> {
withTheme?: boolean withTheme?: boolean
theme?: Partial<ThemeConfig> theme?: Partial<ThemeConfig>
allowCSVDownload?: boolean allowCSVDownload?: boolean
rtl?: boolean
} }
export interface SharedView { export interface SharedView {

8
packages/nc-gui/pages/[projectType]/form/[viewId].vue

@ -4,6 +4,7 @@ import {
IsPublicInj, IsPublicInj,
MetaInj, MetaInj,
ReloadViewDataHookInj, ReloadViewDataHookInj,
applyLanguageDirection,
createError, createError,
createEventHook, createEventHook,
definePageMeta, definePageMeta,
@ -26,9 +27,8 @@ useSidebar('nc-left-sidebar', { hasSidebar: false })
const route = useRoute() const route = useRoute()
const { loadSharedView, sharedView, meta, notFound, password, passwordDlg, passwordError } = useProvideSharedFormStore( const { loadSharedView, sharedView, sharedViewMeta, meta, notFound, password, passwordDlg, passwordError } =
route.params.viewId as string, useProvideSharedFormStore(route.params.viewId as string)
)
await loadSharedView() await loadSharedView()
@ -39,6 +39,8 @@ if (!notFound.value) {
provide(IsFormInj, ref(true)) provide(IsFormInj, ref(true))
useProvideSmartsheetStore(sharedView, meta, true) useProvideSmartsheetStore(sharedView, meta, true)
applyLanguageDirection(sharedViewMeta.value.rtl ? 'rtl' : 'ltr')
} else { } else {
navigateTo('/error/404') navigateTo('/error/404')
throw createError({ statusCode: 404, statusMessage: 'Page Not Found' }) throw createError({ statusCode: 404, statusMessage: 'Page Not Found' })

5
packages/nc-gui/plugins/a.i18n.ts

@ -1,5 +1,6 @@
import { createI18n } from 'vue-i18n' import { createI18n } from 'vue-i18n'
import { defineNuxtPlugin, nextTick } from '#imports' import { isClient } from '@vueuse/core'
import { applyLanguageDirection, defineNuxtPlugin, isRtlLang, nextTick } from '#imports'
import type { Language, NocoI18n } from '~/lib' import type { Language, NocoI18n } from '~/lib'
import { LanguageAlias } from '~/lib' import { LanguageAlias } from '~/lib'
@ -24,6 +25,8 @@ export async function setI18nLanguage(locale: keyof typeof Language, i18n = glob
} }
i18n.global.locale.value = locale i18n.global.locale.value = locale
if (isClient) applyLanguageDirection(isRtlLang(locale) ? 'rtl' : 'ltr')
} }
export async function loadLocaleMessages( export async function loadLocaleMessages(

14
packages/nc-gui/utils/viewUtils.ts

@ -7,6 +7,7 @@ import MdiCalendarIcon from '~icons/mdi/calendar'
import MdiGalleryIcon from '~icons/mdi/camera-image' import MdiGalleryIcon from '~icons/mdi/camera-image'
import MdiKanbanIcon from '~icons/mdi/tablet-dashboard' import MdiKanbanIcon from '~icons/mdi/tablet-dashboard'
import MdiEyeIcon from '~icons/mdi/eye-circle-outline' import MdiEyeIcon from '~icons/mdi/eye-circle-outline'
import type { Language } from '~/lib'
export const viewIcons: Record<number | string, { icon: any; color: string }> = { export const viewIcons: Record<number | string, { icon: any; color: string }> = {
[ViewTypes.GRID]: { icon: MdiGridIcon, color: '#8f96f2' }, [ViewTypes.GRID]: { icon: MdiGridIcon, color: '#8f96f2' },
@ -23,3 +24,16 @@ export const viewTypeAlias: Record<number, string> = {
[ViewTypes.GALLERY]: 'gallery', [ViewTypes.GALLERY]: 'gallery',
[ViewTypes.KANBAN]: 'kanban', [ViewTypes.KANBAN]: 'kanban',
} }
export const isRtlLang = (lang: keyof typeof Language) => ['fa', 'ar'].includes(lang)
const rtl = 'rtl' as const
const ltr = 'ltr' as const
export function applyLanguageDirection(dir: typeof rtl | typeof ltr) {
const oppositeDirection = dir === ltr ? rtl : ltr
document.body.classList.remove(oppositeDirection)
document.body.classList.add(dir)
document.body.style.direction = dir
}

Loading…
Cancel
Save