fix(webui): right to left compatibility

enabled for arabic
This commit is contained in:
Gauthier Roebroeck 2021-02-19 19:34:39 +08:00
parent 71534b41f7
commit 9420010cae
28 changed files with 141 additions and 107 deletions

View file

@ -15,6 +15,7 @@ export default Vue.extend({
const locale = this.$cookies.get(cookieLocale)
if (this.$i18n.availableLocales.includes(locale)) {
this.$i18n.locale = locale
this.$vuetify.rtl = (this.$t('common.locale_rtl') === 'true')
}
}
},

View file

@ -1,7 +1,7 @@
<template>
<v-navigation-drawer
v-model="display"
right
:right="!$vuetify.rtl"
fixed
temporary
disable-route-watcher

View file

@ -9,7 +9,7 @@
<v-icon
color="secondary"
style="max-width: 24px"
class="mr-2"
class="mx-2"
@click.stop="clear(key)"
>{{ groupActive(key) ? 'mdi-checkbox-marked' : '' }}
</v-icon>

View file

@ -3,16 +3,18 @@
<div style="min-height: 36px">
<slot name="prepend"/>
</div>
<div style="position: absolute; top: 0; right: 0">
<div :style="'position: absolute; top: 0;' + ($vuetify.rtl ? 'left: 0' : 'right: 0')">
<v-btn icon
:disabled="!canScrollLeft"
@click="doScroll('left')">
<v-icon>mdi-chevron-left</v-icon>
:disabled="!canScrollBackward"
@click="doScroll('backward')">
<v-icon v-if="$vuetify.rtl">mdi-chevron-right</v-icon>
<v-icon v-else>mdi-chevron-left</v-icon>
</v-btn>
<v-btn icon
:disabled="!canScrollRight"
@click="doScroll('right')">
<v-icon>mdi-chevron-right</v-icon>
:disabled="!canScrollForward"
@click="doScroll('forward')">
<v-icon v-if="$vuetify.rtl">mdi-chevron-left</v-icon>
<v-icon v-else>mdi-chevron-right</v-icon>
</v-btn>
</div>
@ -36,30 +38,44 @@ export default Vue.extend({
const uniqueId = this.$_.uniqueId()
return {
id: uniqueId,
canScrollLeft: false,
canScrollRight: true,
canScrollBackward: false,
canScrollForward: true,
container: this.$refs[uniqueId] as HTMLElement,
adjustment: 100,
}
},
mounted () {
mounted() {
this.container = this.$refs[this.id] as HTMLElement
this.computeScrollability()
},
methods: {
computeScrollability () {
computeScrollability() {
if (this.container !== undefined) {
this.canScrollLeft = Math.round(this.container.scrollLeft) > 0
this.canScrollRight = (Math.round(this.container.scrollLeft) + this.container.clientWidth) < this.container.scrollWidth
if (this.$vuetify.rtl) {
this.canScrollBackward = Math.round(this.container.scrollLeft) < 0
this.canScrollForward = (Math.round(this.container.scrollLeft) - this.container.clientWidth) > -this.container.scrollWidth
} else {
this.canScrollBackward = Math.round(this.container.scrollLeft) > 0
this.canScrollForward = (Math.round(this.container.scrollLeft) + this.container.clientWidth) < this.container.scrollWidth
}
}
},
doScroll (direction: string) {
doScroll(direction: string) {
if (this.container !== undefined) {
let target = Math.round(this.container.scrollLeft) + (this.container.clientWidth - this.adjustment)
if (direction === 'left') {
target = Math.round(this.container.scrollLeft) - (this.container.clientWidth - this.adjustment)
let increment = (this.container.clientWidth - this.adjustment)
let scrollLeft = Math.round(this.container.scrollLeft)
let target
if (this.$vuetify.rtl){
if (direction === 'backward')
target = scrollLeft + increment
else
target = scrollLeft - increment
} else {
if (direction === 'backward')
target = scrollLeft - increment
else
target = scrollLeft + increment
}
const scrollMax = this.container.clientWidth
this.container.scrollTo({
top: 0,
left: target,

View file

@ -36,7 +36,7 @@
<!-- Circle icon for selection (top left) -->
<v-icon v-if="onSelected"
:color="selected ? 'secondary' : ''"
style="position: absolute; top: 5px; left: 10px"
:style="'position: absolute; top: 5px; ' + ($vuetify.rtl ? 'right' : 'left') + ': 10px'"
@click.stop="selectItem"
>
{{ selected || (preselect && hover) ? 'mdi-checkbox-marked-circle' : 'mdi-checkbox-blank-circle-outline'
@ -58,7 +58,7 @@
<!-- Pen icon for edition (bottom left) -->
<v-btn icon
v-if="!selected && !preselect && onEdit"
style="position: absolute; bottom: 5px; left: 5px"
:style="'position: absolute; bottom: 5px; ' + ($vuetify.rtl ? 'right' : 'left' ) +': 5px'"
@click.stop="editItem"
>
<v-icon>mdi-pencil</v-icon>
@ -66,7 +66,7 @@
<!-- Action menu (bottom right) -->
<div v-if="!selected && !preselect && actionMenu"
style="position: absolute; bottom: 5px; right: 5px"
:style="'position: absolute; bottom: 5px; ' + ($vuetify.rtl ? 'left' : 'right') +': 5px'"
>
<book-actions-menu v-if="computedItem.type() === ItemTypes.BOOK"
:book="item"
@ -118,13 +118,13 @@
import BookActionsMenu from '@/components/menus/BookActionsMenu.vue'
import CollectionActionsMenu from '@/components/menus/CollectionActionsMenu.vue'
import SeriesActionsMenu from '@/components/menus/SeriesActionsMenu.vue'
import { getReadProgress, getReadProgressPercentage } from '@/functions/book-progress'
import { ReadStatus } from '@/types/enum-books'
import { createItem, Item, ItemTypes } from '@/types/items'
import {getReadProgress, getReadProgressPercentage} from '@/functions/book-progress'
import {ReadStatus} from '@/types/enum-books'
import {createItem, Item, ItemTypes} from '@/types/items'
import Vue from 'vue'
import { RawLocation } from 'vue-router'
import {RawLocation} from 'vue-router'
import ReadListActionsMenu from '@/components/menus/ReadListActionsMenu.vue'
import { BookDto } from '@/types/komga-books'
import {BookDto} from '@/types/komga-books'
import {SeriesDto} from "@/types/komga-series";
export default Vue.extend({

View file

@ -34,7 +34,7 @@
<v-img :src="seriesThumbnailUrl(item.id)"
height="50"
max-width="35"
class="ma-1 mr-3"
class="my-1 mx-3"
/>
<v-list-item-content>
<v-list-item-title v-text="item.metadata.title"/>
@ -52,7 +52,7 @@
<v-img :src="bookThumbnailUrl(item.id)"
height="50"
max-width="35"
class="ma-1 mr-3"
class="my-1 mx-3"
/>
<v-list-item-content>
<v-list-item-title v-text="item.metadata.title"/>
@ -70,7 +70,7 @@
<v-img :src="collectionThumbnailUrl(item.id)"
height="50"
max-width="35"
class="ma-1 mr-3"
class="my-1 mx-3"
/>
<v-list-item-content>
<v-list-item-title v-text="item.name"/>
@ -88,7 +88,7 @@
<v-img :src="readListThumbnailUrl(item.id)"
height="50"
max-width="35"
class="ma-1 mr-3"
class="my-1 mx-3"
/>
<v-list-item-content>
<v-list-item-title v-text="item.name"/>

View file

@ -19,7 +19,7 @@
</v-toolbar>
<v-card-title class="hidden-xs-only">
<v-icon class="mr-4">mdi-pencil</v-icon>
<v-icon class="mx-4">mdi-pencil</v-icon>
{{ dialogTitle }}
</v-card-title>

View file

@ -19,7 +19,7 @@
</v-toolbar>
<v-card-title class="hidden-xs-only">
<v-icon class="mr-4">mdi-pencil</v-icon>
<v-icon class="mx-4">mdi-pencil</v-icon>
{{ dialogTitle }}
</v-card-title>

View file

@ -102,6 +102,7 @@
"genre": "نوع",
"go_to_library": "اذهب إلى المكتبة",
"locale_name": "اللغة العربية",
"locale_rtl": "true",
"n_selected": "{count} مختار",
"nothing_to_show": "لا شيء للعرض",
"pages": "صفحات",

View file

@ -117,6 +117,7 @@
"genre": "Genre/Gattung",
"go_to_library": "Gehe zu Bibliothek",
"locale_name": "Deutsch",
"locale_rtl" : "false",
"n_selected": "{count} markiert",
"nothing_to_show": "Keine Treffer gefunden die angezeigt werden könnten",
"pages": "Seiten",

View file

@ -117,6 +117,7 @@
"genre": "Genre",
"go_to_library": "Go to library",
"locale_name": "English",
"locale_rtl" : "false",
"n_selected": "{count} selected",
"nothing_to_show": "Nothing to show",
"pages": "pages",

View file

@ -1,56 +1,57 @@
{
"account_settings": {
"account_settings": "Configuración de cuenta",
"change_password": "Cambiar contraseña"
},
"bookreader": {
"beginning_of_book": "Estás al inicio del libro.",
"changing_reading_direction": "Cambiar dirección de lectura a",
"end_of_book": "Had llegado al final del libro.",
"move_next": "Has click o presiona siguiente de nuevo para moverte al siguiente libro.",
"move_next_exit": "Has click o presiona siguiente de nuevo para salir del lector.",
"move_previous": "Has click o presiona anterior de nuevo para moverte al libro anterior.",
"reader_settings": "Configuraciones del lector",
"settings": {
"animate_page_transitions": "Animar transición de página",
"background_color": "Color de fondo",
"general": "General",
"gestures": "Gestos",
"reading_mode": "Modo de lectura",
"scale_type": "Tipo de escala"
}
},
"common": {
"locale_name": "Español",
"all_libraries": "Todas las bibliotecas",
"books": "Libros",
"books_n": "Sin libros | 1 libro | {count} libros",
"cancel": "Cancelar",
"close": "Cerrar",
"collections": "Colecciones",
"create": "Crear",
"delete": "Borrar",
"email": "Email",
"filter_no_matches": "Los filtros activos no tienen ninguna coincidencia",
"genre": "Género",
"go_to_library": "Ir a la biblioteca",
"n_selected": "{count} seleccionado",
"nothing_to_show": "Nada que mostrar",
"pages": "páginas",
"pages_n": "Sin páginas | 1 página | {count} páginas",
"password": "Contraseña",
"publisher": "Editor",
"readlists": "Listas de lectura",
"required": "Requerido",
"roles": "Rol",
"series": "Series",
"tags": "Etiquetas",
"use_filter_panel_to_change_filter": "Uso el panel de filtros para cambiar los filtros activos"
},
"dashboard": {
"keep_reading": "Seguir leyendo",
"recently_added_books": "Libros recién agregados",
"recently_added_series": "Series agregadas recientemente",
"recently_updated_series": "Series recientemente actualizadas"
"account_settings": {
"account_settings": "Configuración de cuenta",
"change_password": "Cambiar contraseña"
},
"bookreader": {
"beginning_of_book": "Estás al inicio del libro.",
"changing_reading_direction": "Cambiar dirección de lectura a",
"end_of_book": "Had llegado al final del libro.",
"move_next": "Has click o presiona siguiente de nuevo para moverte al siguiente libro.",
"move_next_exit": "Has click o presiona siguiente de nuevo para salir del lector.",
"move_previous": "Has click o presiona anterior de nuevo para moverte al libro anterior.",
"reader_settings": "Configuraciones del lector",
"settings": {
"animate_page_transitions": "Animar transición de página",
"background_color": "Color de fondo",
"general": "General",
"gestures": "Gestos",
"reading_mode": "Modo de lectura",
"scale_type": "Tipo de escala"
}
},
"common": {
"locale_name": "Español",
"locale_rtl": "false",
"all_libraries": "Todas las bibliotecas",
"books": "Libros",
"books_n": "Sin libros | 1 libro | {count} libros",
"cancel": "Cancelar",
"close": "Cerrar",
"collections": "Colecciones",
"create": "Crear",
"delete": "Borrar",
"email": "Email",
"filter_no_matches": "Los filtros activos no tienen ninguna coincidencia",
"genre": "Género",
"go_to_library": "Ir a la biblioteca",
"n_selected": "{count} seleccionado",
"nothing_to_show": "Nada que mostrar",
"pages": "páginas",
"pages_n": "Sin páginas | 1 página | {count} páginas",
"password": "Contraseña",
"publisher": "Editor",
"readlists": "Listas de lectura",
"required": "Requerido",
"roles": "Rol",
"series": "Series",
"tags": "Etiquetas",
"use_filter_panel_to_change_filter": "Uso el panel de filtros para cambiar los filtros activos"
},
"dashboard": {
"keep_reading": "Seguir leyendo",
"recently_added_books": "Libros recién agregados",
"recently_added_series": "Series agregadas recientemente",
"recently_updated_series": "Series recientemente actualizadas"
}
}

View file

@ -117,6 +117,7 @@
"genre": "Genre",
"go_to_library": "Aller à la bibliothèque",
"locale_name": "Français",
"locale_rtl" : "false",
"n_selected": "{count} sélectionné | {count} sélectionnés",
"nothing_to_show": "Rien à afficher",
"pages": "pages",

View file

@ -95,6 +95,7 @@
"genre": "장르",
"go_to_library": "서재로 가기",
"locale_name": "한국어",
"locale_rtl" : "false",
"n_selected": "{count}선택 됨",
"nothing_to_show": "내용 없음",
"pages": "페이지",

View file

@ -67,6 +67,7 @@
"genre": "Sjanger",
"go_to_library": "Gå til bibliotek",
"locale_name": "Norsk bokmål",
"locale_rtl" : "false",
"n_selected": "{count} valgt",
"nothing_to_show": "Ingenting å vise",
"pages": "sider",

View file

@ -117,6 +117,7 @@
"genre": "Gênero",
"go_to_library": "Ir para biblioteca",
"locale_name": "Português",
"locale_rtl" : "false",
"n_selected": "{count} selecionados",
"nothing_to_show": "Nada para exibir",
"pages": "páginas",

View file

@ -41,6 +41,7 @@
"genre": "Жанр",
"go_to_library": "Вернуться к библиотеке",
"locale_name": "Русский",
"locale_rtl" : "false",
"n_selected": "{count} выбрано",
"pages": "страниц",
"password": "Пароль",

View file

@ -377,6 +377,7 @@ export default Vue.extend({
}
},
created () {
this.$vuetify.rtl = false
checkWebpFeature('lossy', (feature, isSupported) => {
if (isSupported) {
this.supportedMediaTypes.push('image/webp')
@ -414,6 +415,7 @@ export default Vue.extend({
this.setup(this.bookId, Number(this.$route.query.page))
},
destroyed () {
this.$vuetify.rtl = (this.$t('common.locale_rtl') === 'true')
window.removeEventListener('keydown', this.keyPressed)
},
props: {

View file

@ -28,7 +28,8 @@
:disabled="$_.isEmpty(siblingPrevious)"
:to="{ name: 'browse-book', params: { bookId: previousId }, query: { context: context.origin, contextId: context.id} }"
>
<v-icon>mdi-chevron-left</v-icon>
<v-icon v-if="$vuetify.rtl">mdi-chevron-right</v-icon>
<v-icon v-else>mdi-chevron-left</v-icon>
</v-btn>
<!-- List of all books in context (series/readlist) for navigation -->
@ -65,7 +66,8 @@
:disabled="$_.isEmpty(siblingNext)"
:to="{ name: 'browse-book', params: { bookId: nextId }, query: { context: context.origin, contextId: context.id} }"
>
<v-icon>mdi-chevron-right</v-icon>
<v-icon v-if="$vuetify.rtl">mdi-chevron-left</v-icon>
<v-icon v-else>mdi-chevron-right</v-icon>
</v-btn>
</toolbar-sticky>
@ -98,7 +100,7 @@
<v-row class="text-body-2">
<v-col>
<span class="mr-3">#{{ book.metadata.number }}</span>
<span class="mx-3">#{{ book.metadata.number }}</span>
</v-col>
<v-col cols="auto" v-if="book.metadata.releaseDate">
{{ book.metadata.releaseDate | moment('MMMM DD, YYYY') }}
@ -128,7 +130,7 @@
<v-col class="text-body-2 text-capitalize py-1">
<v-chip v-for="(t, i) in book.metadata.tags"
:key="i"
class="mr-2"
:class="$vuetify.rtl ? 'ml-2' : 'mr-2'"
label
small
outlined
@ -173,7 +175,7 @@
</v-btn>
</v-col>
<v-col cols="auto">
<v-icon class="mr-2 pb-1">mdi-book-open</v-icon>
<v-icon class="mx-2 pb-1">mdi-book-open</v-icon>
<span class="text-body-2">{{ book.media.pagesCount }} {{ $t('common.pages') }}</span>
</v-col>
</v-row>

View file

@ -8,7 +8,7 @@
<v-toolbar-title v-if="collection">
<span>{{ collection.name }}</span>
<v-chip label class="ml-4">
<v-chip label class="mx-4">
<span style="font-size: 1.1rem">{{ collection.seriesIds.length }}</span>
</v-chip>
<span v-if="collection.ordered"

View file

@ -7,7 +7,7 @@
<v-toolbar-title>
<span>{{ library ? library.name : $t('common.all_libraries') }}</span>
<v-chip label class="ml-4" v-if="totalElements">
<v-chip label class="mx-4" v-if="totalElements">
<span style="font-size: 1.1rem">{{ totalElements }}</span>
</v-chip>
</v-toolbar-title>

View file

@ -7,7 +7,7 @@
<v-toolbar-title>
<span>{{ library ? library.name : $t('common.all_libraries') }}</span>
<v-chip label class="ml-4" v-if="totalElements">
<v-chip label class="mx-4" v-if="totalElements">
<span style="font-size: 1.1rem">{{ totalElements }}</span>
</v-chip>
</v-toolbar-title>

View file

@ -8,7 +8,7 @@
<v-toolbar-title v-if="readList">
<span>{{ readList.name }}</span>
<v-chip label class="ml-4">
<v-chip label class="mx-4">
<span style="font-size: 1.1rem">{{ readList.bookIds.length }}</span>
</v-chip>
</v-toolbar-title>

View file

@ -7,7 +7,7 @@
<v-toolbar-title>
<span>{{ library ? library.name : $t('common.all_libraries') }}</span>
<v-chip label class="ml-4" v-if="totalElements">
<v-chip label class="mx-4" v-if="totalElements">
<span style="font-size: 1.1rem">{{ totalElements }}</span>
</v-chip>
</v-toolbar-title>

View file

@ -15,7 +15,7 @@
<v-toolbar-title>
<span v-if="$_.get(series, 'metadata.title')">{{ series.metadata.title }}</span>
<v-chip label class="ml-4" v-if="totalElements">
<v-chip label class="mx-4" v-if="totalElements">
<span style="font-size: 1.1rem">{{ totalElements }}</span>
</v-chip>
</v-toolbar-title>
@ -93,12 +93,12 @@
:text-color="statusChip.text"
>{{ $t(`enums.series_status.${series.metadata.status}`) }}
</v-chip>
<v-chip label small v-if="series.metadata.ageRating" class="ml-2">{{
<v-chip label small v-if="series.metadata.ageRating" class="mx-1">{{
series.metadata.ageRating
}}+
</v-chip>
<v-chip label small v-if="series.metadata.language" class="ml-2">{{ languageDisplay }}</v-chip>
<v-chip label small v-if="series.metadata.readingDirection" class="ml-2">{{ $t(`enums.reading_direction.${series.metadata.readingDirection}`) }}</v-chip>
<v-chip label small v-if="series.metadata.language" class="mx-1">{{ languageDisplay }}</v-chip>
<v-chip label small v-if="series.metadata.readingDirection" class="mx-1">{{ $t(`enums.reading_direction.${series.metadata.readingDirection}`) }}</v-chip>
</v-col>
</v-row>
@ -146,7 +146,7 @@
<v-col class="text-body-2 text-capitalize py-1">
<v-chip v-for="(t, i) in series.metadata.genres"
:key="i"
class="mr-2"
:class="$vuetify.rtl ? 'ml-2' : 'mr-2'"
label
small
outlined
@ -160,7 +160,7 @@
<v-col class="text-body-2 text-capitalize py-1">
<v-chip v-for="(t, i) in series.metadata.tags"
:key="i"
class="mr-2"
:class="$vuetify.rtl ? 'ml-2' : 'mr-2'"
label
small
outlined

View file

@ -9,7 +9,7 @@
</v-app-bar>
<v-navigation-drawer app v-model="drawerVisible">
<v-navigation-drawer app v-model="drawerVisible" :right="$vuetify.rtl">
<v-list-item @click="$router.push({name: 'home'})" inactive class="pb-2">
<v-list-item-avatar>
<v-img src="../assets/logo.svg"/>
@ -221,6 +221,7 @@ export default Vue.extend({
if (this.$i18n.availableLocales.includes(locale)) {
this.$i18n.locale = locale
this.$cookies.set(cookieLocale, locale, Infinity)
this.$vuetify.rtl = (this.$t('common.locale_rtl') === 'true')
}
},
},

View file

@ -50,7 +50,7 @@
>{{ $t('login.login') }}
</v-btn>
<v-btn v-if="unclaimed"
class="ml-4"
class="mx-4"
color="primary"
@click="claim"
>{{ $t('login.create_user_account') }}
@ -130,6 +130,7 @@ export default Vue.extend({
if (this.$i18n.availableLocales.includes(locale)) {
this.$i18n.locale = locale
this.$cookies.set(cookieLocale, locale, Infinity)
this.$vuetify.rtl = (this.$t('common.locale_rtl') === 'true')
}
},
},

View file

@ -64,8 +64,10 @@
</div>
</v-list>
<v-btn fab absolute bottom right color="primary"
class="mr-6"
<v-btn fab absolute bottom color="primary"
:right="!$vuetify.rtl"
:left="$vuetify.rtl"
class="mx-6"
small
:to="{name: 'settings-users-add'}">
<v-icon>mdi-plus</v-icon>