fix: RTL support in call view

Signed-off-by: Dorra Jaouad <dorra.jaoued7@gmail.com>
Signed-off-by: Maksim Sukharev <antreesy.web@gmail.com>
This commit is contained in:
Dorra Jaouad 2025-01-29 15:14:03 +01:00 committed by Maksim Sukharev
parent 9815309a80
commit d19a764143
11 changed files with 77 additions and 59 deletions

View file

@ -806,7 +806,7 @@ export default {
<style lang="scss" scoped>
@import '../../assets/variables';
/* stylelint-disable csstools/use-logical */
#call-container {
width: 100%;
height: 100%;
@ -867,7 +867,7 @@ export default {
.local-video {
position: absolute;
right: 0;
inset-inline-end: 0;
bottom: 0;
width: 300px;
height: 250px;

View file

@ -12,10 +12,10 @@
:aria-label="stripeButtonTitle"
@click="handleClickStripeCollapse">
<template #icon>
<ChevronDown v-if="stripeOpen"
<IconChevronDown v-if="stripeOpen"
fill-color="#ffffff"
:size="20" />
<ChevronUp v-else
<IconChevronUp v-else
fill-color="#ffffff"
:size="20" />
</template>
@ -29,7 +29,8 @@
:aria-label="t('spreed', 'Previous page of videos')"
@click="handleClickPrevious">
<template #icon>
<ChevronLeft fill-color="#ffffff"
<IconChevronLeft class="bidirectional-icon"
fill-color="#ffffff"
:size="20" />
</template>
</NcButton>
@ -90,7 +91,8 @@
:aria-label="t('spreed', 'Next page of videos')"
@click="handleClickNext">
<template #icon>
<ChevronRight fill-color="#ffffff"
<IconChevronRight class="bidirectional-icon"
fill-color="#ffffff"
:size="20" />
</template>
</NcButton>
@ -111,7 +113,10 @@
aria-label="Toggle screenshot mode"
@click="screenshotMode = !screenshotMode">
<template #icon>
<ChevronLeft v-if="!screenshotMode" fill-color="#00FF41" :size="20" />
<IconChevronLeft v-if="!screenshotMode"
class="bidirectional-icon"
fill-color="#00FF41"
:size="20" />
</template>
</NcButton>
<div v-if="!screenshotMode" class="dev-mode__data">
@ -143,10 +148,10 @@
import debounce from 'debounce'
import { inject, ref } from 'vue'
import ChevronDown from 'vue-material-design-icons/ChevronDown.vue'
import ChevronLeft from 'vue-material-design-icons/ChevronLeft.vue'
import ChevronRight from 'vue-material-design-icons/ChevronRight.vue'
import ChevronUp from 'vue-material-design-icons/ChevronUp.vue'
import IconChevronDown from 'vue-material-design-icons/ChevronDown.vue'
import IconChevronLeft from 'vue-material-design-icons/ChevronLeft.vue'
import IconChevronRight from 'vue-material-design-icons/ChevronRight.vue'
import IconChevronUp from 'vue-material-design-icons/ChevronUp.vue'
import { subscribe, unsubscribe } from '@nextcloud/event-bus'
import { loadState } from '@nextcloud/initial-state'
@ -179,10 +184,10 @@ export default {
NcButton,
TransitionWrapper,
VideoBottomBar,
ChevronRight,
ChevronLeft,
ChevronUp,
ChevronDown,
IconChevronDown,
IconChevronLeft,
IconChevronRight,
IconChevronUp,
},
props: {
@ -958,7 +963,6 @@ export default {
</script>
<style lang="scss" scoped>
/* stylelint-disable csstools/use-logical */
.grid-main-wrapper {
--navigation-position: calc(var(--default-grid-baseline) * 2);
position: relative;
@ -978,7 +982,7 @@ export default {
display: flex;
position: relative;
bottom: 0;
left: 0;
inset-inline-start: 0;
}
.grid {
@ -1028,6 +1032,7 @@ export default {
.dev-mode__title {
position: absolute;
/* stylelint-disable-next-line csstools/use-logical */
left: var(--default-clickable-area);
color: #00FF41;
z-index: 100;
@ -1040,14 +1045,17 @@ export default {
.dev-mode__toggle {
position: fixed !important;
/* stylelint-disable-next-line csstools/use-logical */
left: 20px;
top: calc(2 * var(--header-height));
}
.dev-mode__data {
direction: ltr;
font-family: monospace;
position: fixed;
color: #00FF41;
/* stylelint-disable-next-line csstools/use-logical */
left: 20px;
top: calc(2 * var(--header-height) + 40px);
padding: 5px;
@ -1082,11 +1090,11 @@ export default {
top: calc(50% - var(--default-clickable-area) / 2);
&__previous {
left: calc(var(--default-grid-baseline) * 2);
inset-inline-start: calc(var(--default-grid-baseline) * 2);
}
&__next {
right: calc(var(--default-grid-baseline) * 2);
inset-inline-end: calc(var(--default-grid-baseline) * 2);
}
}
@ -1095,11 +1103,11 @@ export default {
top: calc(var(--navigation-position) + var(--grid-gap));
&__previous {
left: var(--navigation-position);
inset-inline-start: var(--navigation-position);
}
&__next {
right: calc(var(--navigation-position) + var(--grid-gap));
inset-inline-end: calc(var(--navigation-position) + var(--grid-gap));
}
}
}
@ -1107,7 +1115,7 @@ export default {
.stripe--collapse {
position: absolute !important;
top: calc(-1 * (var(--default-clickable-area) + var(--navigation-position) / 2));
right: calc(var(--navigation-position) / 2) ;
inset-inline-end: calc(var(--navigation-position) / 2) ;
}
.stripe--collapse,

View file

@ -218,6 +218,6 @@ export default {
.popover-hint {
padding: calc(3 * var(--default-grid-baseline));
max-width: 300px;
text-align: left;
text-align: start;
}
</style>

View file

@ -360,7 +360,6 @@ export default {
</script>
<style lang="scss" scoped>
/* stylelint-disable csstools/use-logical */
.not-connected {
video,
.avatar-container {
@ -422,7 +421,7 @@ export default {
.video-loading {
position: absolute;
top: 0;
right: 0;
inset-inline-end: 0;
height: 100%;
width: 100%;
}
@ -451,7 +450,7 @@ export default {
height: 100%;
width: 100%;
top: 0;
left: 0;
inset-inline-start: 0;
border-radius: var(--border-radius-element, calc(var(--default-clickable-area) / 2));
}
@ -508,7 +507,7 @@ export default {
.presenter-icon__hide {
position: absolute;
color: white;
left: calc(50% - var(--default-clickable-area) / 2);
inset-inline-start: calc(50% - var(--default-clickable-area) / 2);
top: calc(100% - var(--default-grid-baseline) - var(--default-clickable-area));
opacity: 0.7;
background-color: rgba(0, 0, 0, 0.5);

View file

@ -10,7 +10,7 @@
:resizable="false"
:h="presenterOverlaySize"
:w="presenterOverlaySize"
:x="10"
:x="isRTL ? parentWidth - presenterOverlaySize - 10 : 10"
:y="10"
@dragging="isDragging = true"
@dragstop="isDragging = false">
@ -50,11 +50,12 @@
<script>
import { ref } from 'vue'
import VueDraggableResizable from 'vue-draggable-resizable'
import AccountBox from 'vue-material-design-icons/AccountBoxOutline.vue'
import { t } from '@nextcloud/l10n'
import { t, isRTL } from '@nextcloud/l10n'
import NcButton from '@nextcloud/vue/dist/Components/NcButton.js'
@ -106,6 +107,14 @@ export default {
emits: ['click'],
setup() {
const parentWidth = ref(document.getElementById('videos').getBoundingClientRect().width)
return {
parentWidth,
isRTL,
}
},
data() {
return {
resizeObserver: null,
@ -150,10 +159,10 @@ export default {
</script>
<style lang="scss" scoped>
/* stylelint-disable csstools/use-logical */
.presenter-overlay {
position: absolute;
top: 0;
/* stylelint-disable-next-line csstools/use-logical */
left: 0;
}
@ -181,7 +190,7 @@ export default {
position: absolute !important;
opacity: .7;
bottom: 48px;
right: 0;
inset-inline-end: 0;
#call-container:hover & {
background-color: rgba(0, 0, 0, 0.1) !important;

View file

@ -216,11 +216,10 @@ export default {
</script>
<style lang="scss" scoped>
/* stylelint-disable csstools/use-logical */
.toaster {
position: absolute;
bottom: 20px;
left: 0;
inset-inline-start: 0;
display: flex;
flex-direction: column;
gap: 20px;
@ -231,7 +230,7 @@ export default {
.toast {
position: absolute;
bottom: 0;
left: var(--horizontal-offset, 0);
inset-inline-start: var(--horizontal-offset, 0);
display: flex;
align-items: center;
gap: 8px;

View file

@ -204,7 +204,6 @@ export default {
</script>
<style lang="scss" scoped>
/* stylelint-disable csstools/use-logical */
.screenContainer {
width: 100%;
height: 100%;
@ -215,7 +214,7 @@ export default {
height: 100%;
position: absolute;
top: 0;
left: 0;
inset-inline-start: 0;
&--fit {
object-fit: contain;
}

View file

@ -40,10 +40,9 @@ export default {
</script>
<style lang="scss" scoped>
/* stylelint-disable csstools/use-logical */
.video-background {
position: absolute;
left: 0;
inset-inline-start: 0;
top: 0;
height: 100%;
width: 100%;
@ -55,7 +54,7 @@ export default {
width: 100%;
height: 100%;
top: 0;
left: 0;
inset-inline-start: 0;
}
}
</style>

View file

@ -628,7 +628,6 @@ export default {
</script>
<style lang="scss" scoped>
/* stylelint-disable csstools/use-logical */
.not-connected {
video,
.avatar-container {
@ -693,7 +692,7 @@ export default {
& > .dev-mode-video--presenter {
position: absolute;
top: 0;
left: 0;
inset-inline-start: 0;
height: 100%;
width: 100%;
object-fit: cover;
@ -704,7 +703,7 @@ export default {
.video-loading {
position: absolute;
top: 0;
right: 0;
inset-inline-end: 0;
height: 100%;
width: 100%;
}
@ -742,7 +741,7 @@ export default {
height: 100%;
width: 100%;
top: 0;
left: 0;
inset-inline-start: 0;
border-radius: var(--border-radius-element, calc(var(--default-clickable-area) / 2));
}
@ -765,7 +764,7 @@ export default {
.presenter-icon__hide {
position: absolute;
color: white;
left: calc(50% - var(--default-clickable-area) / 2);
inset-inline-start: calc(50% - var(--default-clickable-area) / 2);
top: calc(100% - var(--default-grid-baseline) - var(--default-clickable-area));
opacity: 0.7;
background-color: rgba(0, 0, 0, 0.5);

View file

@ -8,10 +8,7 @@
<Portal>
<!-- Add .app-talk to use Talk icon classes outside of #content-vue -->
<div class="viewer-overlay app-talk"
:style="{
right: position.right + 'px',
bottom: position.bottom + 'px'
}">
:style="computedStyle">
<div class="viewer-overlay__collapse"
:class="{ collapsed: isCollapsed }">
<NcButton type="secondary"
@ -105,7 +102,7 @@ import ArrowExpand from 'vue-material-design-icons/ArrowExpand.vue'
import ChevronDown from 'vue-material-design-icons/ChevronDown.vue'
import ChevronUp from 'vue-material-design-icons/ChevronUp.vue'
import { t } from '@nextcloud/l10n'
import { t, isRTL } from '@nextcloud/l10n'
import NcButton from '@nextcloud/vue/dist/Components/NcButton.js'
@ -194,6 +191,7 @@ export default {
observer: null,
position: {
right: 0,
left: 0,
bottom: 0,
},
}
@ -211,6 +209,13 @@ export default {
showLocalScreen() {
return this.hasLocalScreen && this.screens[0] === localCallParticipantModel.attributes.peerId
},
computedStyle() {
return {
[isRTL() ? 'left' : 'right']: this.position[isRTL() ? 'left' : 'right'] + 'px',
bottom: this.position.bottom + 'px'
}
},
},
mounted() {
@ -233,8 +238,12 @@ export default {
},
updatePosition() {
const { right, bottom } = this.$refs.ghost.getBoundingClientRect()
this.position.right = window.innerWidth - right
const { left, right, bottom } = this.$refs.ghost.getBoundingClientRect()
if (isRTL()) {
this.position.left = left
} else {
this.position.right = window.innerWidth - right
}
this.position.bottom = window.innerHeight - bottom
},
},
@ -242,12 +251,10 @@ export default {
</script>
<style lang="scss" scoped>
/* stylelint-disable csstools/use-logical */
.viewer-overlay-ghost {
position: absolute;
bottom: 8px;
right: 8px;
left: 0;
inset-inline: 0 8px;
}
.viewer-overlay {
@ -270,7 +277,7 @@ export default {
.viewer-overlay__collapse {
position: absolute;
top: 8px;
right: 8px;
inset-inline-end: 8px;
z-index: 100;
}
@ -286,7 +293,7 @@ export default {
.video-overlay__top-bar {
position: absolute;
top: 8px;
left: 8px;
inset-inline-start: 8px;
z-index: 100;
}
@ -309,13 +316,13 @@ export default {
max-height: calc(var(--max-width) * var(--aspect-ratio));
/* Note: because of transition it always has position absolute on animation */
bottom: 0;
right: 0;
inset-inline-end: 0;
}
.viewer-overlay__local-video {
position: absolute;
bottom: 8px;
right: 8px;
inset-inline-end: 8px;
width: 25%;
height: 25%;
overflow: hidden;

View file

@ -18,7 +18,6 @@ stylelintConfig.plugins.push('stylelint-use-logical')
stylelintConfig.rules['csstools/use-logical'] = [
'always',
{
severity: 'warning',
// Only lint LTR-RTL properties for now
except: [
// Position properties