Dialogs and Vuetify styling changes

This commit is contained in:
N-Pex 2025-05-08 11:52:39 +02:00
parent 2ba0d57aa8
commit a97211afdf
45 changed files with 320 additions and 346 deletions

View file

@ -22,6 +22,15 @@ body {
}
}
.v-input.no-underline {
.v-field__outline {
/* Remove text underline */
color: transparent !important;
min-height: 20px;
overflow: hidden;
}
}
.home {
.v-card {
background-color: white;
@ -312,7 +321,20 @@ body {
font-family: "Inter", sans-serif;
font-weight: 300;
font-size: 18 * $chat-text-size;
.v-input__slot {
.v-field__overlay {
display: none;
}
.v-field__input {
padding: 0;
min-height: 32px;
mask-image: none;
-webkit-mask-image: none;
font-family: "Inter", sans-serif;
font-weight: 300;
font-size: 18 * $chat-text-size;
}
.v-field__outline {
/* Remove text underline */
color: transparent !important;
min-height: 20px;

View file

@ -131,21 +131,28 @@ body { position:absolute; top:0; bottom:0; right:0; left:0; }
}
}
.v-dialog {
.v-dialog-rounded > * {
border-radius: 20px !important;
}
.v-dialog {
.dialog-content {
border-radius: 20px !important;
padding: 20px;
background-color: white;
}
.dialog-title {
word-break: break-word;
text-align: center;
padding: 16px 24px 10px 24px;
margin-bottom: 20px;
}
.dialog-text {
text-align: left;
word-break: break-word;
a {
color: black;
text-decoration: underline;

View file

@ -70,9 +70,8 @@
<div class="load-later">
<div style="align-self: flex-end;">
<v-btn class="clap-button clickable" text elevation="0" v-blur @click.stop="clapButtonClicked()">👏</v-btn>
<v-btn :class="{'mic-button': true, 'dimmed': !canRecordAudio}" ref="mic_button" fab small elevation="0" v-blur
<v-btn icon="mic" :class="{'mic-button': true, 'dimmed': !canRecordAudio}" ref="mic_button" theme="dark" size="small" elevation="0" v-blur
@click.stop="micButtonClicked()">
<v-icon color="white">mic</v-icon>
</v-btn>
</div>
<v-icon class="clickable" @click="loadNext" color="white" size="28">expand_more</v-icon>
@ -92,6 +91,7 @@ import emitter from 'tiny-emitter/instance';
export default {
mixins: [messageMixin],
components: { AuthedImage },
emits: ['mark-read','loadprevious','loadnext','start-recording','sendclap'],
props: {
autoplay: {
type: Boolean,

View file

@ -18,15 +18,13 @@
:style="{ top: `${isMove ? y : calcY()}px` }"
>
<v-btn
fab
x-small
size="small"
elevation="0"
color="black"
@click.stop="onBackgroundClick"
class="bottom-sheet-close"
v-if="showCloseButton"
icon="cancel"
>
<v-icon color="white" >cancel</v-icon>
</v-btn>
<div class="bottom-sheet-handle"><div class="bottom-sheet-handle-decoration" /></div>
<div ref="sheetContent" class="sheetContent">
@ -220,8 +218,8 @@ export default {
.bottom-sheet-close {
position: absolute;
right: 0;
top: 0;
right: 4px;
top: 4px;
z-index: 1;
}

View file

@ -117,9 +117,8 @@
<NoHistoryRoomWelcomeHeader v-if="showNoHistoryRoomWelcomeHeader" />
<!-- "Scroll to end"-button -->
<v-btn v-if="!useVoiceMode" :class="{'scroll-to-end': true, 'reversed': reverseOrder}" v-show="showScrollToEnd" fab x-small elevation="0" color="black"
<v-btn v-if="!useVoiceMode" icon="arrow_downward" :class="{'scroll-to-end': true, 'reversed': reverseOrder}" v-show="showScrollToEnd" theme="dark" size="x-small" elevation="0" color="black"
@click.stop="scrollToEndOfTimeline">
<v-icon color="white">arrow_downward</v-icon>
</v-btn>
@ -133,7 +132,7 @@
<div class="col">
<div class="font-weight-medium">{{ $t("message.replying_to", { user: senderDisplayName }) }}</div>
<div v-if="replyToContentType === 'm.text'" class="reply-text" :title="replyToEvent.getContent().body">
{{ replyToEvent.getContent().body | latestReply }}
{{ latestReply }}
</div>
<div v-if="replyToContentType === 'm.thread' || replyToContentType === 'io.element.thread'">{{ replyToThreadMessage }}</div>
<div v-if="replyToContentType === 'm.image'">{{ $t("message.reply_image") }}</div>
@ -146,11 +145,10 @@
class="rounded" />
<v-img v-if="replyToContentType === 'm.audio'" src="@/assets/icons/audio_message.svg" />
<v-img v-if="replyToContentType === 'm.video'" src="@/assets/icons/video_message.svg" />
<v-icon v-if="replyToContentType === 'm.poll'" light>$vuetify.icons.poll</v-icon>
<v-icon v-if="replyToContentType === 'm.poll'" theme="light">$vuetify.icons.poll</v-icon>
</div>
<div class="col col-auto">
<v-btn fab x-small elevation="0" color="black" @click.stop="cancelEditReply">
<v-icon color="white">cancel</v-icon>
<v-btn icon="cancel" size="default" elevation="0" color="black" @click.stop="cancelEditReply">
</v-btn>
</div>
</div>
@ -163,7 +161,7 @@
<v-row class="input-area-inner align-center" v-show="!showRecorder" v-if="$matrix.userCanSendMessageInCurrentRoom">
<v-col class="flex-grow-1 flex-shrink-1 ma-0 pa-0">
<v-textarea height="undefined" ref="messageInput" full-width auto-grow rows="1" v-model="currentInput"
no-resize class="input-area-text" :placeholder="$t('message.your_message')" hide-details
no-resize class="input-area-text input-plain" :placeholder="$t('message.your_message')" hide-details
background-color="white" v-on:keydown.enter.prevent="
() => {
sendCurrentTextMessage();
@ -172,58 +170,52 @@
</v-col>
<v-col class="input-area-button text-center flex-grow-0 flex-shrink-1" v-if="editedEvent">
<v-btn fab small elevation="0" color="black" @click.stop="cancelEditReply">
<v-icon color="white">cancel</v-icon>
<v-btn icon="cancel" elevation="0" color="black" @click.stop="cancelEditReply">
</v-btn>
</v-col>
<v-col v-if="(!currentInput || currentInput.length == 0) && canCreatePoll && !replyToEvent"
class="input-area-button text-center flex-grow-0 flex-shrink-1">
<v-btn icon large color="black" @click="showCreatePollDialog = true">
<v-icon dark>$vuetify.icons.poll</v-icon>
<v-btn icon @click="showCreatePollDialog = true">
<v-icon size="24">$vuetify.icons.poll</v-icon>
</v-btn>
</v-col>
<v-col class="input-area-button text-center flex-grow-0 flex-shrink-1"
v-if="!$config.disableMediaSharing && (!currentInput || currentInput.length == 0 || showRecorder)">
<v-btn v-if="canRecordAudio" class="mic-button" ref="mic_button" fab small elevation="0" v-blur
<v-btn icon="mic" :color="showRecorder ? 'black' : 'white'" v-if="canRecordAudio" class="mic-button" ref="mic_button" elevation="0" v-blur
v-longTap:250="[showRecordingUI, startRecording]">
<v-icon :color="showRecorder ? 'white' : 'black'">mic</v-icon>
</v-btn>
<v-btn v-else class="mic-button" ref="mic_button" fab small elevation="0" v-blur
<v-btn icon="mic" :color="showRecorder ? 'black' : 'white'" v-else class="mic-button" ref="mic_button" elevation="0" v-blur
@click.stop="showNoRecordingAvailableDialog = true">
<v-icon :color="showRecorder ? 'white' : 'black'">mic</v-icon>
</v-btn>
</v-col>
<v-col class="input-area-button text-center flex-grow-0 flex-shrink-1" v-else-if="currentInput && currentInput.length > 0">
<v-btn fab small elevation="0" color="black" @click.stop="sendCurrentTextMessage"
<v-btn :icon="editedEvent ? 'save' : 'arrow_upward'" size="default" elevation="0" color="black" @click.stop="sendCurrentTextMessage"
:disabled="sendButtonDisabled">
<v-icon color="white">{{ editedEvent ? "save" : "arrow_upward" }}</v-icon>
</v-btn>
</v-col>
<v-col class="input-area-button text-center flex-grow-0 flex-shrink-1 input-more-icon">
<v-btn fab small elevation="0" v-blur @click.stop="
<v-btn size="small" elevation="0" v-blur @click.stop="
isEmojiQuickReaction = false;
showMoreMessageOperations($event)
">
<v-icon>$vuetify.icons.addReaction</v-icon>
" icon="$vuetify.icons.addReaction">
</v-btn>
</v-col>
<v-col v-if="$config.shortCodeStickers" class="input-area-button text-center flex-grow-0 flex-shrink-1">
<v-btn id="btn-attach" icon large color="black" @click="showStickerPicker"
<v-btn id="btn-stickers" icon="face" @click="showStickerPicker"
:disabled="attachButtonDisabled">
<v-icon large>face</v-icon>
</v-btn>
</v-col>
<v-col v-if="!$config.disableMediaSharing" class="input-area-button text-center flex-grow-0 flex-shrink-1">
<label icon flat ref="attachmentLabel">
<v-btn icon large color="black" @click="showAttachmentPicker"
<v-btn icon @click="showAttachmentPicker"
:disabled="attachButtonDisabled">
<v-icon x-large>add_circle_outline</v-icon>
<v-icon size="36">add_circle_outline</v-icon>
</v-btn>
</label>
</v-col>
@ -296,7 +288,7 @@
</template>
<v-divider></v-divider>
<v-textarea v-if="showAttachmentCaptionInput" v-model="attachmentCaption" ref="attachmentCaption" color="black" background-color="transparent"
solo full-width auto-grow rows="1" no-resize hide-details :placeholder="$t('file_mode.add_a_message')"></v-textarea>
variant="solo" full-width auto-grow rows="1" no-resize hide-details :placeholder="$t('file_mode.add_a_message')"></v-textarea>
<v-card-actions>
<v-spacer>
<div v-if="currentSendError">{{ currentSendError }}</div>
@ -347,14 +339,13 @@
<CreatePollDialog :show="showCreatePollDialog" @close="showCreatePollDialog = false" />
<UserProfileDialog
:show="showProfileDialog"
v-model="showProfileDialog"
:activeMember="compActiveMember"
:room="room"
@close="showProfileDialog = false"
/>
<!-- PURGE ROOM POPUP -->
<PurgeRoomDialog :show="showPurgeConfirmation" :room="room" @close="showPurgeConfirmation = false" />
<PurgeRoomDialog v-model="showPurgeConfirmation" :room="room" />
<RoomExport :room="room" v-if="downloadingChat" v-on:close="downloadingChat = false" />
@ -552,16 +543,6 @@ export default {
};
},
filters: {
latestReply(contents) {
const contentArr = contents.split("\n").reverse();
if (contentArr[0] === "") {
contentArr.shift();
}
return (contentArr && contentArr.length > 0) ? contentArr[0].replace(/^> (<.*> )?/g, "") : "";
},
},
mounted() {
emitter.on('audio-playback-ended', this.audioPlaybackEnded);
const container = this.chatContainer;
@ -589,6 +570,14 @@ export default {
},
computed: {
latestReply() {
const contents = this.replyToEvent ? this.replyToEvent.getContent().body : "";
const contentArr = contents.split("\n").reverse();
if (contentArr[0] === "") {
contentArr.shift();
}
return (contentArr && contentArr.length > 0) ? contentArr[0].replace(/^> (<.*> )?/g, "") : "";
},
heartEmoji() {
return this.$refs.emojiPicker.mapEmojis["Symbols"].find(({ aliases }) => aliases.includes('heart')).data;
},
@ -800,20 +789,20 @@ export default {
roomWelcomeHeader() {
if (!this.hideRoomWelcomeHeader && this.roomCreatedByUsRecently) {
if (this.roomDisplayType == ROOM_TYPE_CHANNEL) {
return WelcomeHeaderChannel;
return markRaw(WelcomeHeaderChannel);
}
if (this.isDirectRoom) {
return WelcomeHeaderDirectChat;
return markRaw(WelcomeHeaderDirectChat);
}
return WelcomeHeaderRoom;
return markRaw(WelcomeHeaderRoom);
}
return null;
},
messageOperationsComponent() {
if (this.room.displayType == ROOM_TYPE_CHANNEL) {
return MessageOperationsChannel;
return markRaw(MessageOperationsChannel);
}
return MessageOperations;
return markRaw(MessageOperations);
},
chatContainerStyle() {
if (this.$config.chat_backgrounds && this.room && this.roomId) {

View file

@ -38,17 +38,15 @@
</v-avatar>
</v-col>
<v-col cols="auto" class="text-end ma-0 pa-0 ms-1">
<v-btn id="btn-purge-room" v-if="userCanPurgeRoom" class="mx-2 box-shadow-none" fab dark small color="red"
<v-btn id="btn-purge-room" v-if="userCanPurgeRoom" icon="$vuetify.icons.ic_moderator-delete" class="mx-2 box-shadow-none" theme="light" size="small" color="red"
@click.stop="$emit('purge')">
<v-icon light>$vuetify.icons.ic_moderator-delete</v-icon>
</v-btn>
<v-btn id="btn-leave-room" class="mx-2 box-shadow-none" fab dark small color="red" @click.stop="leaveRoom" v-else>
<v-icon color="white">$vuetify.icons.ic_member-leave</v-icon>
<v-btn id="btn-leave-room" v-else icon="$vuetify.icons.ic_member-leave" class="mx-2 box-shadow-none" theme="light" size="small" color="red" @click.stop="leaveRoom">
</v-btn>
</v-col>
<v-col cols="auto" class="text-end ma-0 pa-0 ms-1 clickable close-button more-menu-button">
<div :class="{ 'popup-open': showMoreMenu }">
<v-btn class="mx-2 box-shadow-none" fab dark small color="transparent" @click.stop="onShowMoreMenu">
<v-btn class="mx-2 box-shadow-none" icon theme="dark" size="small" color="transparent" @click.stop="onShowMoreMenu">
<v-icon size="15">$vuetify.icons.ic_more</v-icon>
</v-btn>
</div>
@ -56,7 +54,7 @@
</v-row>
<!-- "REALLY LEAVE?" dialog -->
<LeaveRoomDialog :show="showLeaveConfirmation" :room="room" @close="showLeaveConfirmation = false" />
<LeaveRoomDialog v-model="showLeaveConfirmation" :room="room" />
<!-- PROFILE INFO POPUP -->
<ProfileInfoPopup :show="showProfileInfo" @close="showProfileInfo = false" />
@ -79,6 +77,7 @@ import roomInfoMixin from "./roomInfoMixin";
export default {
name: "ChatHeader",
mixins: [profileInfoMixin, roomInfoMixin],
emits: ['download','view-room-details','header-click'],
components: {
LeaveRoomDialog,
ProfileInfoPopup,

View file

@ -43,22 +43,20 @@
</v-col>
<v-col cols="auto" class="text-end ma-0 pa-0 ms-1">
<v-btn id="btn-purge-room" v-if="userCanPurgeRoom" class="mx-2 box-shadow-none" fab dark small color="red"
<v-btn id="btn-purge-room" v-if="userCanPurgeRoom" icon="$vuetify.icons.ic_moderator-delete" class="mx-2 box-shadow-none" theme="light" size="small" color="red"
@click.stop="$emit('purge')">
<v-icon light>$vuetify.icons.ic_moderator-delete</v-icon>
</v-btn>
<template v-else>
<v-btn v-if="$matrix.joinedRooms.length == 1" id="btn-leave-room" class="box-shadow-none leave-button" color="red" @click.stop="leaveRoom">
<v-icon color="white">$vuetify.icons.ic_member-leave</v-icon>{{ $t('room.leave') }}
<v-btn v-if="$matrix.joinedRooms.length == 1" id="btn-leave-room" class="box-shadow-none leave-button" theme="dark" color="red" @click.stop="leaveRoom">
<v-icon color="white"></v-icon>{{ $t('room.leave') }}
</v-btn>
<v-btn id="btn-leave-room" class="mx-2 box-shadow-none" fab dark small color="red" @click.stop="leaveRoom" v-else>
<v-icon color="white">$vuetify.icons.ic_member-leave</v-icon>
<v-btn v-else id="btn-leave-room" icon="$vuetify.icons.ic_member-leave" class="mx-2 box-shadow-none" theme="dark" size="small" color="red" @click.stop="leaveRoom">
</v-btn>
</template>
</v-col>
<v-col v-if="$matrix.joinedRooms.length > 1" cols="auto" class="text-end ma-0 pa-0 ms-1 clickable close-button more-menu-button">
<div :class="{ 'popup-open': showMoreMenu }">
<v-btn class="mx-2 box-shadow-none" fab dark small color="transparent" @click.stop="onShowMoreMenu">
<v-btn class="mx-2 box-shadow-none" icon theme="dark" size="small" color="transparent" @click.stop="onShowMoreMenu">
<v-icon size="15">$vuetify.icons.ic_more</v-icon>
</v-btn>
</div>
@ -66,7 +64,7 @@
</v-row>
<!-- "REALLY LEAVE?" dialog -->
<LeaveRoomDialog :show="showLeaveConfirmation" :room="room" @close="showLeaveConfirmation = false" />
<LeaveRoomDialog v-model="showLeaveConfirmation" :room="room" />
<!-- PROFILE INFO POPUP -->
<ProfileInfoPopup :show="showProfileInfo" @close="showProfileInfo = false" />

View file

@ -1,7 +1,6 @@
<template>
<v-dialog
v-model="showDialog"
v-show="room"
scrollable
class="ma-0 pa-0"
:width="$vuetify.display.smAndUp ? '940px' : '95%'"
@ -101,34 +100,18 @@
</v-dialog>
</template>
<script>
import roomInfoMixin from "./roomInfoMixin";
import util from "../plugins/utils";
import InputControl from "./InputControl.vue";
import RoomDialogBase from "./RoomDialogBase.vue";
export default {
name: "CreatePollDialog",
mixins: [roomInfoMixin],
props: {
show: {
type: Boolean,
default: function() {
return false;
},
},
},
extends: RoomDialogBase,
data() {
return this.defaultData();
},
watch: {
show: {
handler(newVal, ignoredOldVal) {
this.showDialog = newVal;
},
},
showDialog() {
if (!this.showDialog) {
this.$emit("close");
} else {
methods: {
onOpenDialog() {
// Reset values
let defaults = this.defaultData();
this.isValid = defaults.isValid;
@ -142,13 +125,9 @@ export default {
if (this.$refs.pollcreateform) {
this.$refs.pollcreateform.resetValidation();
}
}
},
},
methods: {
defaultData() {
return {
showDialog: false,
isValid: true,
isCreating: false,
status: String.fromCharCode(160),

View file

@ -76,11 +76,11 @@
<v-row class="align-center">
<v-col class="py-0">
<div class="text-start font-weight-bold">{{ $t("join.choose_name") }}</div>
<v-select ref="avatar" :items="availableAvatars" cache-items outlined dense @change="selectAvatar"
<v-select ref="avatar" :items="availableAvatars" variant="outlined" dense @change="selectAvatar"
:value="selectedProfile">
<template v-slot:selection>
<v-text-field background-color="transparent" solo flat hide-details
@click.native.stop="(event) => event.target.focus()" @focus="$event.target.select()"
<v-text-field background-color="transparent" variant="solo" flat hide-details
@click.stop="(event) => event.target.focus()" @focus="$event.target.select()"
v-model="selectedProfile.name"></v-text-field>
</template>
<template v-slot:item="data">
@ -124,8 +124,10 @@
</v-card>
</v-dialog>
<MessageRetentionDialog :initialValue="limitHistoryMilliseconds" :show="selectRetentionDialog"
v-on:close="selectRetentionDialog = false" v-on:message-retention-update="onUpdateHistoryLimit" />
<MessageRetentionDialog
v-model="selectRetentionDialog"
:initialValue="limitHistoryMilliseconds"
v-on:message-retention-update="onUpdateHistoryLimit" />
</div>
</template>

View file

@ -5,12 +5,12 @@
:key="device.deviceId"
:value="device.deviceId"
>
<template v-slot:default="{ active }">
<template v-slot:default="{ isActive }">
<v-list-item-title>{{ displayName(device) }}</v-list-item-title>
<v-list-item-subtitle>{{
verificationStatus(device)
}}</v-list-item-subtitle>
<v-list-item-action v-if="active">
<v-list-item-action v-if="isActive">
<v-btn icon>
<v-icon
:color="
@ -18,7 +18,7 @@
? 'red'
: device.isVerified()
? 'green'
: 'grey lighten-1'
: 'grey-lighten-1'
"
>verified_user</v-icon
>

View file

@ -7,7 +7,7 @@
<div color="rgba(255,255,255,0.1)" class="text-center">
<v-form v-model="isValid" ref="form">
<v-text-field v-model="user.user_id" :label="$t('getlink.username')" color="black" background-color="white"
solo :rules="[(v) => !!v || $t('login.username_required')]" :error="userErrorMessage != null"
variant="solo" :rules="[(v) => !!v || $t('login.username_required')]" :error="userErrorMessage != null"
:error-messages="userErrorMessage" required v-on:keyup.enter="onUsernameEnter"
v-on:keydown="hasError = false"></v-text-field>

View file

@ -23,6 +23,7 @@ export default {
prop: "modelValue",
event: "update:modelValue",
},
emits: ['update:modelValue'],
props: {
label: {
type: String,

View file

@ -10,7 +10,7 @@
<v-col sm="8" align="center">
<div class="text-start font-weight-light">{{ $t("login.email") }}</div>
<v-text-field v-model="email" color="black" :rules="emailRules" type="email" maxlength="200"
background-color="white" v-on:keyup.enter="onEmailEntered(email)" autofocus solo></v-text-field>
background-color="white" v-on:keyup.enter="onEmailEntered(email)" autofocus variant="solo"></v-text-field>
<v-btn :disabled="!emailIsValid" color="black" depressed class="filled-button"
@click.stop="onEmailEntered(email)">
{{ $t("login.send_verification") }}
@ -67,7 +67,7 @@
<v-col sm="8" align="center">
<div class="text-start font-weight-light">{{ $t("login.registration_token") }}</div>
<v-text-field v-model="token" color="black" :rules="tokenRules" type="text" maxlength="64"
background-color="white" v-on:keyup.enter="onTokenEntered(token)" autofocus solo></v-text-field>
background-color="white" v-on:keyup.enter="onTokenEntered(token)" autofocus variant="solo"></v-text-field>
<v-btn :disabled="!tokenIsValid" color="black" depressed class="filled-button"
@click.stop="onTokenEntered(token)">
{{ $t("login.send_token") }}

View file

@ -16,7 +16,7 @@
<div class="flex-grow-0 flex-shrink-0 chip-group-wrapper">
<div class="h4">{{$t('invite.send_invites_to')}}</div>
<div>{{ status }}</div>
<v-chip-group active-class="primary--text" column>
<v-chip-group selected-class="primary--text" column>
<v-chip
v-for="member in selectedMembers"
:key="member.userId"
@ -43,14 +43,14 @@
}}</span>
</v-avatar>
</template>
<template v-slot:default="{ active }">
<template v-slot:default="{ isActive }">
<v-list-item-title>{{ memberName(member) }}</v-list-item-title>
<v-list-item-subtitle
v-text="member.userId"
></v-list-item-subtitle>
<v-list-item-action>
<v-btn icon v-if="active">
<v-icon color="grey lighten-1">check</v-icon>
<v-btn icon v-if="isActive">
<v-icon color="grey-lighten-1">check</v-icon>
</v-btn>
</v-list-item-action>
</template>

View file

@ -22,11 +22,11 @@
<v-row v-if="canEditProfile">
<v-col cols="10" sm="7" class="py-0">
<v-select ref="avatar" :items="availableAvatars" cache-items outlined dense @change="selectAvatar"
<v-select ref="avatar" :items="availableAvatars" variant="outlined" dense @change="selectAvatar"
:value="selectedProfile" single-line autofocus>
<template v-slot:selection>
<v-text-field background-color="transparent" solo flat hide-details
@click.native.stop="(event) => event.target.focus()" @focus="$event.target.select()"
<v-text-field background-color="transparent" variant="solo" flat hide-details
@click.stop="(event) => event.target.focus()" @focus="$event.target.select()"
v-model="selectedProfile.name"></v-text-field>
</template>
<template v-slot:item="data">
@ -70,11 +70,11 @@
<interactive-auth ref="interactiveAuth" />
<v-btn id="btn-join" class="btn-dark" :disabled="!acceptUA || (room && room.selfMembership == 'ban')" large
<v-btn id="btn-join" class="btn-dark" :disabled="!acceptUA || (room && room.selfMembership == 'ban')" size="large"
@click.stop="handleJoin" :loading="loading" v-if="!currentUser">{{
roomId && roomId.startsWith("@") ? $t("join.enter_room_user") : $t("join.enter_room")
}}</v-btn>
<v-btn id="btn-join" class="btn-dark" :disabled="!acceptUA || (room && room.selfMembership == 'ban')" large
<v-btn id="btn-join" class="btn-dark" :disabled="!acceptUA || (room && room.selfMembership == 'ban')" size="large"
block @click.stop="handleJoin" :loading="loading" v-else>{{
roomId && roomId.startsWith("@") ? $t("join.join_user") : $t("join.join")
}}</v-btn>

View file

@ -1,7 +1,6 @@
<template>
<v-dialog
v-model="showDialog"
v-show="room"
class="ma-0 pa-0"
:width="$vuetify.display.smAndUp ? '688px' : '95%'"
>
@ -69,41 +68,21 @@
</v-dialog>
</template>
<script>
import RoomDialogBase from "./RoomDialogBase.vue";
import roomInfoMixin from "./roomInfoMixin";
export default {
name: "LeaveRoomDialog",
mixins: [roomInfoMixin],
props: {
show: {
type: Boolean,
default: function () {
return false;
},
},
},
extends: RoomDialogBase,
data() {
return {
showDialog: false,
lastRoom: false,
};
},
watch: {
show: {
handler(newVal, ignoredOldVal) {
this.showDialog = newVal;
},
},
showDialog() {
if (!this.showDialog) {
this.$emit("close");
} else {
this.lastRoom = this.onlyJoinedToThisRoom();
}
},
},
methods: {
onOpenDialog() {
this.lastRoom = this.onlyJoinedToThisRoom();
},
onlyJoinedToThisRoom() {
const joinedRooms = this.$matrix.joinedRooms;
if (

View file

@ -32,7 +32,7 @@
:label="$t('login.username')"
color="black"
background-color="white"
solo
variant="solo"
:rules="[(v) => !!v || $t('login.username_required')]"
:error="userErrorMessage != null"
:error-messages="userErrorMessage"
@ -52,7 +52,7 @@
:label="$t('login.password')"
color="black"
background-color="#f5f5f5"
filled
variant="filled"
type="password"
:rules="[(v) => !!v || $t('login.password_required')]"
:error="passErrorMessage != null"

View file

@ -16,14 +16,12 @@
>
<slot></slot>
<v-btn
fab
x-small
icon="cancel"
size="small"
elevation="0"
color="black"
@click.stop="backgroundClick"
class="bottom-sheet-close"
>
<v-icon color="white" >cancel</v-icon>
</v-btn>
</SwipeableBottomSheet>
</div>
@ -91,8 +89,8 @@ export default {
.message-operations-bottom-sheet {
.bottom-sheet-close {
position: absolute;
right: 0;
top: 0;
right: 4px;
top: 4px;
}
.transition-bg {

View file

@ -1,5 +1,8 @@
<template>
<v-dialog v-model="showDialog" v-show="room" class="ma-0 pa-0" :width="$vuetify.display.smAndUp ? '688px' : '95%'">
<v-dialog
v-model="showDialog"
class="ma-0 pa-0"
:width="$vuetify.display.smAndUp ? '688px' : '95%'">
<div class="dialog-content text-center">
<template>
<h2>{{ $t("room_info.message_retention") }}</h2>
@ -27,18 +30,12 @@
</v-dialog>
</template>
<script>
import roomInfoMixin from "./roomInfoMixin";
import RoomDialogBase from "./RoomDialogBase.vue";
export default {
name: "MessageRetentionDialog",
mixins: [roomInfoMixin],
extends: RoomDialogBase,
props: {
show: {
type: Boolean,
default: function () {
return false;
},
},
initialValue: {
type: Number,
default: function () {
@ -48,32 +45,20 @@ export default {
},
data() {
return {
showDialog: false,
isValid: true,
retention: 0,
retentionMinValue: 60,
retentionMaxValue: 60 * 60 * 24 * 500
};
},
watch: {
show: {
handler(newVal, ignoredOldVal) {
this.showDialog = newVal;
},
},
showDialog(val, oldVal) {
if (!val && oldVal) {
this.$emit("close");
} else if (val && !oldVal) {
// Showing, reset
this.setInitialValue();
}
}
},
mounted() {
this.setInitialValue();
},
methods: {
onOpenDialog() {
// Showing, reset
this.setInitialValue();
},
setInitialValue() {
this.isValid = true;
if (this.room) {

View file

@ -113,9 +113,9 @@
class="ma-0 pa-0"
:width="$vuetify.display.smAndUp ? '940px' : '80%'"
>
<v-card :disabled="settingPassword">
<v-card-title>{{ $matrix.currentUser.is_guest ? $t("profile.set_password") : $t("profile.change_password") }}</v-card-title>
<v-card-text>
<v-card :disabled="settingPassword" class="dialog-content">
<h2 class="dialog-title">{{ $matrix.currentUser.is_guest ? $t("profile.set_password") : $t("profile.change_password") }}</h2>
<div class="dialog-text">
<v-text-field
v-if="!$matrix.currentUser.is_guest"
v-model="password"
@ -147,7 +147,7 @@
<div class="text-red" v-if="passwordErrorMessage">
{{ passwordErrorMessage }}
</div>
</v-card-text>
</div>
<v-divider></v-divider>
<v-card-actions>
<v-spacer></v-spacer>
@ -174,7 +174,7 @@
</v-dialog>
<!-- edit display name dialog -->
<v-dialog
<RoundedDialog
v-model="showEditDisplaynameDialog"
class="ma-0 pa-0"
:width="$vuetify.display.smAndUp ? '940px' : '80%'"
@ -207,7 +207,7 @@
>
</v-card-actions>
</v-card>
</v-dialog>
</RoundedDialog>
<SelectLanguageDialog
v-model="showSelectLanguageDialog"
@ -265,6 +265,7 @@ import AuthedImage from "./AuthedImage.vue";
import CopyLink from "./CopyLink.vue"
import { requestNotificationPermission, windowNotificationPermission } from "../plugins/notificationAndServiceWorker.js"
import { mapState } from 'vuex'
import RoundedDialog from "./RoundedDialog.vue";
export default {
name: "Profile",
@ -274,7 +275,8 @@ export default {
SelectLanguageDialog,
LogoutRoomDialog,
CopyLink,
AuthedImage
AuthedImage,
RoundedDialog
},
data() {
return {

View file

@ -2,7 +2,7 @@
<v-dialog
persistent
v-model="showDialog"
v-show="room" class="ma-0 pa-0"
class="ma-0 pa-0"
:width="$vuetify.display.smAndUp ? '688px' : '95%'"
>
<div v-if="timeout == -1" class="dialog-content text-center">
@ -96,47 +96,25 @@
</v-dialog>
</template>
<script>
import roomInfoMixin from "./roomInfoMixin";
import { STATE_EVENT_ROOM_DELETION_NOTICE } from "../plugins/utils";
import RoomDialogBase from "./RoomDialogBase.vue";
export default {
name: "LeaveRoomDialog",
mixins: [roomInfoMixin],
props: {
show: {
type: Boolean,
default: function () {
return false;
},
},
},
name: "PurgeRoomDialog",
extends: RoomDialogBase,
data() {
return {
timeout: -1,
timeoutTimer: null,
showDialog: false,
isPurging: false,
status: null,
};
},
watch: {
show: {
handler(newVal, ignoredOldVal) {
this.showDialog = newVal;
},
},
showDialog(val, oldVal) {
if (!val && oldVal) {
this.undo();
this.$emit("close");
} else if (val && !oldVal) {
// Showing, reset
this.status = null;
}
},
},
methods: {
onOpenDialog() {
// Showing, reset
this.status = null;
},
undo() {
if (this.timeoutTimer) {
clearInterval(this.timeoutTimer);

View file

@ -1,7 +1,6 @@
<template>
<v-dialog
v-model="showDialog"
v-show="room"
class="ma-0 pa-0"
:width="$vuetify.display.smAndUp ? '688px' : '95%'"
>
@ -39,37 +38,16 @@
</v-dialog>
</template>
<script>
import roomInfoMixin from "./roomInfoMixin";
import RoomDialogBase from "./RoomDialogBase.vue";
export default {
name: "ReportRoomDialog",
mixins: [roomInfoMixin],
props: {
show: {
type: Boolean,
default: function () {
return false;
},
},
},
extends: RoomDialogBase,
data() {
return {
showDialog: false,
reason: ""
};
},
watch: {
show: {
handler(newVal, ignoredOldVal) {
this.showDialog = newVal;
},
},
showDialog() {
if (!this.showDialog) {
this.$emit("close");
}
},
},
methods: {
onReport() {

View file

@ -0,0 +1,43 @@
<template><div></div></template>
<script>
import roomInfoMixin from "./roomInfoMixin";
export default {
name: "RoomDialogBase",
mixins: [roomInfoMixin],
props: ['modelValue'],
emits: ['update:modelValue'],
data() {
return {
showDialog: false,
};
},
watch: {
room() {
this.showDialog = this.shouldShow();
},
modelValue() {
this.showDialog = this.shouldShow();
},
showDialog() {
if (!this.showDialog) {
this.$emit('update:modelValue', false)
} else {
this.onOpenDialog();
}
},
},
methods: {
shouldShow() {
return this.modelValue && this.room ? true : false;
},
onOpenDialog() {
}
},
};
</script>
<style lang="scss">
@import "@/assets/css/chat.scss";
</style>

View file

@ -101,6 +101,7 @@ import "../services/filesaver.cjs";
export default {
name: "RoomExport",
mixins: [chatMixin],
emits: ["close"],
components: {
ChatHeader,
MessageIncomingText,

View file

@ -58,7 +58,7 @@
maxlength="50"
@blur="updateRoomName()"
@keyup.enter="updateRoomName()"
solo
variant="solo"
></v-text-field>
</div>
<div :class="{'topic':true,'cursor-default':!userCanPurgeRoom}">
@ -81,7 +81,7 @@
autofocus
@blur="updateRoomTopic()"
@keyup.enter="updateRoomTopic()"
solo
variant="solo"
>
</v-text-field>
</div>
@ -108,36 +108,26 @@
{{ item.text }}
</template>
<template v-slot:item="{ item, attrs, on }">
<v-list-item v-on="on" v-bind="attrs" #default="{ active }">
<v-list-item v-on="on" v-bind="attrs">
<template v-slot:prepend>
<v-avatar color="grey">
<v-icon color="black">{{ item.icon }}</v-icon>
</v-avatar>
</template>
<v-list-item-title v-text="item.text"></v-list-item-title>
<v-list-item-action>
<v-btn icon v-if="active">
<v-icon color="grey lighten-1">check</v-icon>
</v-btn>
</v-list-item-action>
<v-list-item-title>{{ item.text }}</v-list-item-title>
<template v-slot:append="{ isActive }">
<v-list-item-action>
<v-btn icon v-if="isActive">
<v-icon color="grey-lighten-1">check</v-icon>
</v-btn>
</v-list-item-action>
</template>
</v-list-item>
</template>
</v-select>
<!-- <div v-if="anyoneCanJoin">
<div>Anyone with a link can join.</div>
<v-text-field
:value="publicRoomLink"
readonly
append-icon="content_copy"
filled
type="text"
@click:append="copyRoomLink"
></v-text-field>
</div> -->
</v-card-text>
</v-card>
<v-card class="account ma-3" flat>
<v-card-title class="h2">{{ $t("room_info.message_retention") }}</v-card-title>
<v-card-text v-if="canViewRetentionPolicy">
@ -168,7 +158,7 @@
</v-card-text>
</v-card>
<v-card class="account ma-3" flat v-if="canChangeReadOnly()">
<v-card-title class="h2">{{ $t("room_info.moderation") }}</v-card-title>
<v-card-text class="" v-if="canChangeReadOnly()">
@ -179,7 +169,7 @@
<div class="option-text">{{ $t('room_info.read_only_room_info') }}</div>
</v-card-text>
</v-card>
<v-card class="account ma-3" flat>
<v-card-title class="h2">{{ $t("room_info.report") }}</v-card-title>
<v-card-text class="">
@ -188,21 +178,21 @@
<v-btn
color="black"
depressed
small
size="small"
class="outlined-button"
@click.stop="report"
>{{ $t("room_info.report") }}</v-btn>
</div>
</v-card-text>
</v-card>
<v-card class="members ma-3" flat>
<v-card-title class="h2"
>{{ $t("room_info.members") }}<v-spacer></v-spacer>
<div>{{ members.length }}</div></v-card-title
>
<v-list>
<template v-for="(member, index) in members" :key="member.userId">
<template v-for="(member, index) in members" :key="member.userId">
<v-list-item
class="member"
v-show="showAllMembers || index < SHOW_MEMBER_LIMIT"
@ -266,35 +256,30 @@
</div>
<UserProfileDialog
:show="showMemberActionConfirmation"
v-model="showMemberActionConfirmation"
:activeMember="activeMember || members[0]"
:room="room"
@close="showMemberActionConfirmation = false"
/>
<LeaveRoomDialog
:show="showLeaveConfirmation"
v-model="showLeaveConfirmation"
:room="room"
@close="showLeaveConfirmation = false"
/>
<PurgeRoomDialog
:show="showPurgeConfirmation"
v-model="showPurgeConfirmation"
:room="room"
@close="showPurgeConfirmation = false"
/>
<MessageRetentionDialog
:show="showMessageRetentionDialog"
v-model="showMessageRetentionDialog"
:room="room"
@close="showMessageRetentionDialog = false"
v-on:message-retention-update="onMessageRetention"
/>
<ReportRoomDialog
:show="showReportDialog"
v-model="showReportDialog"
:room="room"
@close="showReportDialog = false"
/>
<RoomExport :room="room" v-if="exporting" v-on:close="exporting = false" />

View file

@ -26,13 +26,15 @@
<v-list-item-title class="room-list-name">{{ room.name }}</v-list-item-title>
<v-list-item-subtitle>{{ room.topic }}</v-list-item-subtitle>
<v-list-item-action>
<v-btn id="btn-accept" class="filled-button" depressed color="black" @click.stop="acceptInvitation(room)">{{
$t("menu.join") }}</v-btn>
<v-btn v-if="!room.isServiceNoticeRoom" id="btn-reject" class="filled-button" color="black"
@click.stop="rejectInvitation(room)" text>{{
$t("menu.ignore") }}</v-btn>
</v-list-item-action>
<template v-slot:append>
<v-list-item-action>
<v-btn id="btn-accept" class="filled-button" depressed color="black" @click.stop="acceptInvitation(room)">{{
$t("menu.join") }}</v-btn>
<v-btn v-if="!room.isServiceNoticeRoom" id="btn-reject" class="filled-button" color="black"
@click.stop="rejectInvitation(room)" text>{{
$t("menu.ignore") }}</v-btn>
</v-list-item-action>
</template>
</v-list-item>
<v-list-item v-for="room in joinedRooms" :key="room.roomId" :value="room.roomId"
@ -51,10 +53,12 @@
<v-list-item-subtitle class="room-list-new-messages" v-if="notificationCount(room) > 0">
{{ $t("room.room_list_new_messages", { count: notificationCount(room) }) }}
</v-list-item-subtitle>
<v-list-item-action>
<v-icon size="16" v-if="room.roomId == $matrix.currentRoomId">$vuetify.icons.ic_circle_filled</v-icon>
<v-icon size="16" v-else>$vuetify.icons.ic_circle</v-icon>
</v-list-item-action>
<template v-slot:append>
<v-list-item-action>
<v-icon size="16" v-if="room.roomId == $matrix.currentRoomId">$vuetify.icons.ic_circle_filled</v-icon>
<v-icon size="16" v-else>$vuetify.icons.ic_circle</v-icon>
</v-list-item-action>
</template>
</v-list-item>
</v-list>
</template>

View file

@ -1,5 +1,5 @@
<template>
<v-select outlined dense :items="availableRoomTypes"
<v-select variant="outlined" dense :items="availableRoomTypes"
:value="modelValue"
@change="$emit('update:modelValue', $event)"
:reduce="(obj) => obj.value">

View file

@ -0,0 +1,14 @@
<template>
<v-dialog v-bind="{ ...$props, ...$attrs }" content-class="v-dialog-rounded">
<slot></slot>
</v-dialog>
</template>
<script>
export default {
};
</script>
<style lang="scss">
@import "@/assets/css/chat.scss";
</style>

View file

@ -1,5 +1,5 @@
<template>
<v-dialog
<RoundedDialog
class="ma-0 pa-0"
v-bind="{ ...$props, ...$attrs }"
:width="$vuetify.display.smAndUp ? '940px' : '90%'"
@ -17,7 +17,7 @@
<v-select
v-model="$i18n.locale"
:items="languages"
menu-props="auto"
:menu-props="{ auto: true }"
:label="$t('profile.select_language')"
v-on:change="$store.commit('setLanguage', $i18n.locale)"
hide-details
@ -28,7 +28,6 @@
<v-card-actions>
<v-btn
id="btn-done"
color="black"
depressed
block
class="btn-dark"
@ -37,14 +36,16 @@
>
</v-card-actions>
</v-card>
</v-dialog>
</RoundedDialog>
</template>
<script>
import LanguageMixin from "./languageMixin";
import RoundedDialog from "./RoundedDialog.vue";
export default {
mixins: [LanguageMixin],
components: { RoundedDialog }
};
</script>

View file

@ -5,17 +5,14 @@
centered
class="tabs"
show-arrows
slider-color="primary"
>
<v-tabs-slider></v-tabs-slider>
<v-tab v-for="pack in packs" :key="pack">
<v-tab v-for="(pack,ipack) in packs" :key="'pack-' + ipack" :value="'pack-' + ipack">
{{ pack }}
<v-icon>mdi-phone</v-icon>
</v-tab>
</v-tabs>
<v-tabs-items v-model="currentStickerPack" class="tab-items">
<v-tab-item v-for="pack in packs" :key="pack">
<v-tabs-window v-model="currentStickerPack">
<v-window-item v-for="(pack,ipack) in packs" :key="'pack-content-' + ipack" :value="'pack-' + ipack">
<v-card flat>
<v-container fluid>
<v-row>
@ -25,8 +22,8 @@
</v-row>
</v-container>
</v-card>
</v-tab-item>
</v-tabs-items>
</v-window-item>
</v-tabs-window>
</BottomSheet>
</template>
@ -40,17 +37,14 @@ export default {
},
data() {
return {
currentStickerPack: 'tab-0',
currentStickerPack: 'pack-0',
packs: [],
};
},
computed: {
packs() {
return stickers.getPacks();
}
},
mounted() {},
methods: {
open() {
this.packs = stickers.getPacks();
this.$refs.sheet.open();
},
stickersInPack(pack) {
@ -69,6 +63,10 @@ export default {
</style>
<style lang="scss">
.sheetContent {
top: 40px !important;
padding: 0 20px 20px 20px !important;
}
.sticker-picker {
z-index: 10;
@ -76,6 +74,7 @@ export default {
position: sticky;
top: 0px;
z-index: 1;
background: white;
}
}
</style>

View file

@ -1,10 +1,9 @@
<template>
<v-dialog
v-if="activeMember"
v-model="showDialog"
v-show="room"
class="ma-0 pa-0"
:width="$vuetify.display.smAndUp ? '688px' : '95%'"
v-if="showDialog"
>
<div class="dialog-content text-center member-action-dialog">
<div class="pt-4">
@ -39,7 +38,7 @@
</div>
<DeviceList :member="activeMember" />
<div class="py-3" v-if="activeMember.userId != $matrix.currentUserId">
<v-btn text x-large block v-if="activeMember.userId != $matrix.currentUserId && !$matrix.isDirectRoomWith(room, activeMember.userId)" class="start-private-chat clickable d-block text-none justify-start" @click="startPrivateChat(activeMember.userId)">
<v-btn text size="x-large" block v-if="activeMember.userId != $matrix.currentUserId && !$matrix.isDirectRoomWith(room, activeMember.userId)" class="start-private-chat clickable d-block text-none justify-start" @click="startPrivateChat(activeMember.userId)">
<v-icon left>$vuetify.icons.direct_chat</v-icon> {{ $t("menu.direct_chat") }}
</v-btn>
<div v-if="canBanUserComp">
@ -47,13 +46,13 @@
<v-icon left>$vuetify.icons.kickout</v-icon> {{ $t("menu.user_kick_and_ban") }}
</v-btn>
</div>
<v-btn text x-large block v-if="activeMember.userId != $matrix.currentUserId && !isAdminComp && canMakeAdminComp" class="start-private-chat clickable d-block text-none justify-start" @click="makeAdmin(activeMember)">
<v-btn text size="x-large" block v-if="activeMember.userId != $matrix.currentUserId && !isAdminComp && canMakeAdminComp" class="start-private-chat clickable d-block text-none justify-start" @click="makeAdmin(activeMember)">
<v-icon left>$vuetify.icons.make_admin</v-icon> {{ $t("menu.user_make_admin") }}
</v-btn>
<v-btn text x-large block v-if="activeMember.userId != $matrix.currentUserId && !isModeratorComp && !isAdminComp && canMakeModeratorComp" class="start-private-chat clickable d-block text-none justify-start" @click="makeModerator(activeMember)">
<v-btn text size="x-large" block v-if="activeMember.userId != $matrix.currentUserId && !isModeratorComp && !isAdminComp && canMakeModeratorComp" class="start-private-chat clickable d-block text-none justify-start" @click="makeModerator(activeMember)">
<v-icon left>$vuetify.icons.make_moderator</v-icon> {{ $t("menu.user_make_moderator") }}
</v-btn>
<v-btn text x-large block v-if="activeMember.userId != $matrix.currentUserId && isModeratorComp && canRevokeModeratorComp" class="start-private-chat clickable d-block text-none justify-start" @click="revokeModerator(activeMember)">
<v-btn text size="x-large" block v-if="activeMember.userId != $matrix.currentUserId && isModeratorComp && canRevokeModeratorComp" class="start-private-chat clickable d-block text-none justify-start" @click="revokeModerator(activeMember)">
<v-icon left>$vuetify.icons.revoke</v-icon> {{ $t("menu.user_revoke_moderator") }}
</v-btn>
</div>
@ -73,8 +72,9 @@ export default {
DeviceList,
AuthedImage
},
emits: ['update:modelValue'],
props: {
show: {
modelValue: {
type: Boolean,
default: function () {
return false;
@ -141,14 +141,20 @@ export default {
}
},
watch: {
activeMember() {
this.showDialog = this.show && this.activeMember && this.room;
},
room() {
this.showDialog = this.show && this.activeMember && this.room;
},
show: {
handler(newVal, ignoredOldVal) {
this.showDialog = newVal;
this.showDialog = newVal && this.activeMember && this.room;
}
},
showDialog() {
if (!this.showDialog) {
this.$emit("close");
this.$emit('update:modelValue', false);
}
},
},

View file

@ -5,7 +5,7 @@
class="ma-2 white-space-pre"
:color="dark ? 'black' : '#ededed'"
:text-color="dark ? 'white' : 'black'"
:outlined="!dark"
:variant="!dark ? 'ouelined' : 'tonal'"
>{{ $t("profile_info_popup.you_are") }}&nbsp;
<span v-if="$matrix.currentUser.is_guest">
<i18n-t keypath="profile_info_popup.identity_temporary" tag="span">

View file

@ -29,7 +29,7 @@ export default {
"background-color": "white",
disabled: this.creatingRoom,
//autofocus: true,
solo: true,
variant: "solo",
required: true,
};
},
@ -50,8 +50,9 @@ export default {
rules: this.roomTopicRules,
maxLength: "500",
disabled: this.creatingRoom,
filled: true,
rounded: true,
variant: "filled",
class: "no-underline",
//rounded: true,
"hide-details": true,
};
},

View file

@ -38,7 +38,7 @@
</div>
</div>
<div class="file-drop-input-container">
<v-textarea ref="input" full-width solo flat auto-grow v-model="messageInput" no-resize class="input-area-text"
<v-textarea ref="input" full-width variant="solo" flat auto-grow v-model="messageInput" no-resize class="input-area-text"
rows="1" :placeholder="$t('file_mode.add_a_message')" hide-details background-color="transparent"
v-on:keydown.enter.prevent="() => {
sendCurrentTextMessage();
@ -82,14 +82,14 @@
<div class="file-drop-files-sent">{{ $t((this.messageInput && this.messageInput.length > 0) ?
"file_mode.files_sent_with_note" : "file_mode.files_sent", attachmentsSent.length) }}</div>
<div class="file-drop-section">
<v-textarea disabled full-width solo flat auto-grow v-model="messageInput" no-resize class="input-area-text"
<v-textarea disabled full-width variant="solo" flat auto-grow v-model="messageInput" no-resize class="input-area-text"
rows="1" hide-details background-color="transparent" />
</div>
</div>
<!-- Bottom section -->
<div v-if="status == mainStatuses.SENDING" class="file-drop-sending-input-container">
<v-textarea disabled full-width solo flat auto-grow v-model="messageInput" no-resize class="input-area-text"
<v-textarea disabled full-width variant="solo" flat auto-grow v-model="messageInput" no-resize class="input-area-text"
rows="1" :placeholder="$t('file_mode.add_a_message')" hide-details background-color="transparent" />
<v-btn>{{ $t("file_mode.sending") }}<v-progress-circular indeterminate size="18" width="2"
color="#4642F1"></v-progress-circular></v-btn>

View file

@ -19,6 +19,7 @@ export default {
const context = this
for (const locale of Object.keys(this.$i18n.messages)) {
this.languages.push({
title: this.$i18n.messages[locale].language_display_name || locale,
text: this.$i18n.messages[locale].language_display_name || locale,
value: locale,
display: context.displayLanguage.includes(locale)

View file

@ -2,7 +2,7 @@
<message-incoming v-bind="{ ...$props, ...$attrs }">
<div class="bubble poll-bubble">
<div class="poll-icon">
<v-icon dark>$vuetify.icons.poll</v-icon>
<v-icon theme="dark">$vuetify.icons.poll</v-icon>
</div>
<div class="poll-question">{{ pollQuestion }}</div>

View file

@ -1,24 +1,24 @@
<template>
<div :class="{'message-operations':true,'incoming':incoming,'outgoing':!incoming}">
<template v-for="(item,index) in getEmojis">
<v-btn v-if="userCanSendReactionAndAnswerPoll && index < maxRecents" :key="item.data" id="btn-quick-reaction" icon @click.stop="addQuickReaction(item.data)" class="ma-0 pa-0" dense>
<template v-for="(item,index) in getEmojis" :key="item.data">
<v-btn v-if="userCanSendReactionAndAnswerPoll && index < maxRecents" id="btn-quick-reaction" icon @click.stop="addQuickReaction(item.data)" class="ma-0 pa-0" dense>
<span class="recent-emoji">{{ item.data }}</span>
</v-btn>
</template>
<v-btn v-if="userCanSendReactionAndAnswerPoll" id="btn-more" icon @click.stop="more" class="ma-0 pa-0">
<v-icon small> $vuetify.icons.addReaction </v-icon>
<v-icon size="small"> $vuetify.icons.addReaction </v-icon>
</v-btn>
<v-btn v-if="userCanSendMessage" id="btn-reply" icon @click.stop="addReply" class="ma-0 pa-0">
<v-icon>reply</v-icon>
</v-btn>
<v-btn id="btn-edit" icon @click.stop="edit" class="ma-0 pa-0" v-if="isEditable">
<v-icon small>edit</v-icon>
<v-icon size="small">edit</v-icon>
</v-btn>
<v-btn id="btn-redact" icon @click.stop="redact" class="ma-0 pa-0" v-if="isRedactable">
<v-icon small>delete</v-icon>
<v-icon size="small">delete</v-icon>
</v-btn>
<v-btn id="btn-download" icon @click.stop="download" class="ma-0 pa-0" v-if="isDownloadable">
<v-icon small>get_app</v-icon>
<v-icon size="small">get_app</v-icon>
</v-btn>
</div>
</template>

View file

@ -30,7 +30,7 @@
<span v-else class="text-white headline">{{ userAvatarLetter }}</span>
</v-avatar>
<QuickReactionsChannel v-if="room.displayType == ROOM_TYPE_CHANNEL" :event="eventForReactions" :timelineSet="timelineSet" v-bind="$attrs"/>
<QuickReactions v-else :event="eventForReactions" :timelineSet="timelineSet" v-bin="$attrs"/>
<QuickReactions v-else :event="eventForReactions" :timelineSet="timelineSet" v-bind="$attrs"/>
<SeenBy v-if="room.displayType != ROOM_TYPE_CHANNEL" :room="room" :event="event"/>
</div>
</template>

View file

@ -2,7 +2,7 @@
<message-outgoing v-bind="{ ...$props, ...$attrs }">
<div class="bubble poll-bubble">
<div class="poll-icon">
<v-icon light>$vuetify.icons.poll</v-icon>
<v-icon theme="light">$vuetify.icons.poll</v-icon>
</div>
<div class="poll-question">{{ pollQuestion }}</div>

View file

@ -10,8 +10,8 @@
<template v-slot:activator="{ on, attrs }">
<v-chip
class="pa-2 ma-1 ml-0"
outlined
small
variant="outlined"
size="small"
v-bind="attrs"
v-on="on"
@click="onClickEmoji(name)"
@ -24,8 +24,8 @@
<v-chip
v-else
class="pa-2 ma-1 ml-0"
outlined
small
variant="outlined"
size="small"
>
{{ name }} {{ value.length }}
</v-chip>
@ -34,22 +34,22 @@
v-if="totalReaction > REACTION_LIMIT"
@click="showAllReaction = !showAllReaction"
class="pa-2 ma-1 ml-0"
outlined
small
variant="outlined"
size="small"
>
{{ otherReactionText }}
</v-chip>
<v-tooltip top v-if="!!totalReaction">
<template v-slot:activator="{ on, attrs }">
<v-chip
outlined
small
variant="outlined"
size="small"
class="pa-2 ma-1 ml-0"
v-bind="attrs"
v-on="on"
@click="more"
>
<v-icon small> $vuetify.icons.addReaction </v-icon>
<v-icon size="small"> $vuetify.icons.addReaction </v-icon>
</v-chip>
</template>
<span>{{ $t("global.add_reaction") }}</span>

View file

@ -24,16 +24,16 @@
ref="seenByListBottomSheet"
>
<v-list>
<v-subheader class="text-uppercase"> {{ $t("message.seen_by") }}</v-subheader>
<v-list-subheader class="text-uppercase"> {{ $t("message.seen_by") }}</v-list-subheader>
<v-list-item v-for="(member, index) in seenBy" :key="index" class="text-left">
<v-list-item-icon>
<template v-slot:prepend>
<v-avatar size="40" color="grey">
<AuthedImage v-if="memberAvatar(member.roomMember)" :src="memberAvatar(member.roomMember)" />
<span v-else class="text-white headline">{{
member.roomMember.name.substring(0, 1).toUpperCase()
}}</span>
</v-avatar>
</v-list-item-icon>
</template>
<v-list-item-title>{{member.roomMember.name}}</v-list-item-title>
<v-list-item-subtitle>{{ seenByTimeStamp(member.readTimestamp) }}</v-list-item-subtitle>
</v-list-item>

View file

@ -2,19 +2,19 @@
<div :class="{ 'message-operations': true, 'incoming': incoming, 'outgoing': !incoming }">
<v-list dense>
<v-list-item key="edit" v-if="isEditable" @click.stop="edit">
<v-list-item-icon><v-icon>$vuetify.icons.ic_edit</v-icon></v-list-item-icon>
<template v-slot:prepend><v-icon>$vuetify.icons.ic_edit</v-icon></template>
<v-list-item-title>{{ $t("menu.edit") }}</v-list-item-title>
</v-list-item>
<v-list-item key="pin" v-if="userCanPin && !event.isPinned" @click.stop="pin">
<v-list-item-icon><v-icon>$vuetify.icons.ic_pin</v-icon></v-list-item-icon>
<template v-slot:prepend><v-icon>$vuetify.icons.ic_pin</v-icon></template>
<v-list-item-title>{{ $t("menu.pin") }}</v-list-item-title>
</v-list-item>
<v-list-item key="unpin" v-if="userCanPin && event.isPinned" @click.stop="unpin">
<v-list-item-icon><v-icon>$vuetify.icons.ic_pin</v-icon></v-list-item-icon>
<template v-slot:prepend><v-icon>$vuetify.icons.ic_pin</v-icon></template>
<v-list-item-title>{{ $t("menu.unpin") }}</v-list-item-title>
</v-list-item>
<v-list-item key="redact" v-if="isRedactable" @click.stop="redact">
<v-list-item-icon><v-icon color="#222222">delete_outline</v-icon></v-list-item-icon>
<template v-slot:prepend><v-icon color="#222222">delete_outline</v-icon></template>
<v-list-item-title>{{ $t("menu.delete") }}</v-list-item-title>
</v-list-item>
</v-list>

View file

@ -29,7 +29,9 @@
</v-btn>
</div>
<MessageRetentionDialog :show="showMessageRetentionDialog" :room="room" @close="showMessageRetentionDialog = false"
<MessageRetentionDialog
v-model="showMessageRetentionDialog"
:room="room"
v-on:message-retention-update="onMessageRetention" />
</div>
</template>

View file

@ -22,11 +22,12 @@ const custom = {
component: (props) => {
const {
icon,
tag,
...rest
} = props;
const stringIcon = icon;
if (icons[stringIcon]) {
return h(props.tag, rest, [h(icons[stringIcon].component)]);
return h(tag, rest, [h(icons[stringIcon].component, { style: "width:100%;height:100%" })]);
}
return md.component(props);
}

View file

@ -11,6 +11,7 @@ import CreateFileDrop from '../components/CreateFileDrop.vue'
import User from '../models/user'
import util from '../plugins/utils'
import { createRouter, createWebHashHistory } from 'vue-router'
import { defineAsyncComponent } from 'vue'
const routes = [
{
@ -30,7 +31,7 @@ const routes = [
{
path: '/info',
name: 'RoomInfo',
component: () => import('../components/RoomInfo.vue'),
component: defineAsyncComponent(() => import('../components/RoomInfo.vue')),
props: true,
meta: {
title: 'Info',
@ -94,7 +95,7 @@ const routes = [
{
path: '/invite/:roomId?',
name: 'Invite',
component: () => import('../components/Invite.vue'),
component: defineAsyncComponent(() => import('../components/Invite.vue')),
meta: {
title: 'Add Friends'
}
@ -102,7 +103,7 @@ const routes = [
{
path: '/goodbye',
name: 'Goodbye',
component: () => import('../components/QuoteView.vue'),
component: defineAsyncComponent(() => import('../components/QuoteView.vue')),
props: true
}
]