@@ -770,6 +803,9 @@ export default {
},
autoLimit: true,
+ toExpanded: false,
+ ccExpanded: false,
+ bccExpanded: false,
wantsSmimeSign: this.smimeSign,
wantsSmimeEncrypt: this.smimeEncrypt,
isPickerOpen: false,
@@ -1675,6 +1711,10 @@ export default {
this.showBCC = !(this.showBCC && this.selectBcc.length === 0 && this.autoLimit)
},
+ getRecipientIndex(recipients, option) {
+ return recipients.findIndex(r => r.email === option.email)
+ },
+
setEditorModeHtml() {
this.editorMode = EDITOR_MODE_HTML
},
@@ -1809,8 +1849,7 @@ export default {
z-index: 100;
display: flex;
flex-direction: column;
- height: 100%;
- max-height: 100%;
+ min-height: 100%;
}
.composer-actions {
@@ -1819,23 +1858,15 @@ export default {
}
.composer-fields {
- padding: var(--default-grid-baseline) calc(var(--default-grid-baseline) * 2) 0 calc(var(--default-grid-baseline) * 2);
-
- &__label {
- display: flex;
- flex-direction: row;
- justify-content: space-between;
- align-items: flex-end;
-
- /** NcButton does not allow font weight styling */
- :deep(.button-vue__text) {
- font-weight: normal;
- }
- }
+ display: flex;
+ flex-direction: row;
+ align-items: flex-start;
+ padding: 0 calc(var(--default-grid-baseline) * 2);
+ min-height: calc(var(--default-clickable-area) + calc(var(--default-grid-baseline) * 2));
&.mail-account {
border-top: none;
- padding-top: calc(var(--default-grid-baseline) * 2);
+ padding-top: var(--default-grid-baseline);
}
input,
@@ -1847,17 +1878,18 @@ export default {
}
.composer-fields--custom {
+ flex: 1;
+ min-width: 0;
display: flex;
align-items: flex-start;
justify-content: space-between;
- padding-top: calc(var(--default-grid-baseline) * 0.5);
+ padding: calc(var(--default-grid-baseline) * 1.5) 0;
button {
margin-top: 0;
margin-bottom: 0;
background-color: transparent;
border: none;
- opacity: 0.5;
padding: calc(var(--default-grid-baseline) * 2) calc(var(--default-grid-baseline) * 4);
}
@@ -1901,8 +1933,8 @@ export default {
// Make composer editor expand
.message-editor {
- flex: 1 1 100%;
- min-height: 0;
+ flex: 1 1 auto;
+ min-height: 200px;
border-top: 1px solid var(--color-border);
}
@@ -1915,26 +1947,80 @@ export default {
.from-label,
.to-label,
-.copy-toggle,
.cc-label,
.bcc-label {
+ width: calc(var(--default-grid-baseline) * 12);
+ flex-shrink: 0;
+ padding-top: calc(var(--default-grid-baseline) * 4 + 1px);
color: var(--color-text-maxcontrast);
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
-.bcc-label {
- top: initial;
- bottom: 0;
+
+// NcSelect caps the toggle at 100px with overflow-y:auto, preventing expanded
+// chips from pushing CC/BCC down. The no-wrap/select--no-wrap CSS already
+// controls whether chips wrap (flex-wrap:nowrap on vs__selected-options), so
+// removing the height cap here is safe for both collapsed and expanded states.
+:deep(.v-select.select .vs__dropdown-toggle) {
+ max-height: none;
+ overflow-y: visible;
+ border-radius: var(--border-radius-large);
+}
+
+// NcSelect adds a rectangular outline on focus/active/open — override with none
+// so the rounded border-radius is not broken by a sharp outline.
+:deep(.v-select.select:not(.vs--disabled, .vs--open) .vs__dropdown-toggle:active),
+:deep(.v-select.select:not(.vs--disabled, .vs--open) .vs__dropdown-toggle:focus-within),
+:deep(.v-select.select.vs--open .vs__dropdown-toggle) {
+ outline: none;
+}
+
+
+
+.recipient-overflow {
+ display: inline-flex;
+ align-items: center;
+ align-self: center;
+ padding: 0 calc(var(--default-grid-baseline) * 2);
+ height: calc(var(--default-clickable-area-small, 28px));
+ border-radius: var(--border-radius-pill);
+ background-color: var(--color-background-dark);
+ white-space: nowrap;
+ font-size: var(--default-font-size);
+ flex-shrink: 0;
+ border: none;
+ cursor: pointer;
+ color: var(--color-main-text);
+
+ &:hover {
+ background-color: var(--color-background-darker);
+ }
+}
+
+// Reserve space for the toggle only in the search row — chips on other rows fill full width
+.to-select :deep(.vs__search) {
+ padding-inline-end: calc(var(--default-grid-baseline) * 10);
}
.copy-toggle {
+ // Absolute so it overlays the bottom-right of the To field without affecting chip layout
+ position: absolute;
+ inset-inline-end: 0;
+ bottom: 0;
+ z-index: 1;
+ // Override the .composer-fields--custom button rule
+ opacity: 1;
cursor: pointer;
- width: initial;
- &:hover,
- &:focus {
+ :deep(.button-vue__text) {
+ font-weight: normal;
+ color: var(--color-text-maxcontrast);
+ }
+
+ &:hover :deep(.button-vue__text),
+ &:focus :deep(.button-vue__text) {
color: var(--color-main-text);
}
}
@@ -2014,7 +2100,7 @@ export default {
.composer-actions--secondary-actions {
display: flex;
flex-direction: row;
- padding: 12px;
+ padding: calc(var(--default-grid-baseline) * 2);
gap: 5px;
}
@@ -2027,7 +2113,7 @@ export default {
}
.composer-actions-draft-status {
- padding-inline-start: 10px;
+ padding-inline-start: 0;
}
:deep(.vs__selected-options .vs__dropdown-toggle .vs--multiple ){
diff --git a/src/components/NewMessageModal.vue b/src/components/NewMessageModal.vue
index 225e74ff57..4467a40a54 100644
--- a/src/components/NewMessageModal.vue
+++ b/src/components/NewMessageModal.vue
@@ -3,19 +3,24 @@
- SPDX-License-Identifier: AGPL-3.0-or-later
-->
-
-
-
+ ref="floatingPanel"
+ class="floating-composer"
+ :class="{
+ 'floating-composer--maximized': largerModal,
+ 'floating-composer--with-recipient': showRecipientPane && !error && !warning && recipientPaneOpen,
+ }"
+ @mousedown.stop>
+
+
+
+
+
+
+
+
+
+
+
- {{ error }}
+
+ {{ error }}
+
{{ t('mail', 'Go back') }}
@@ -66,8 +96,8 @@
-
-
-
-
-
-
+
diff --git a/src/components/RecipientInfo.vue b/src/components/RecipientInfo.vue
index ff53f9c1be..f7171000e7 100644
--- a/src/components/RecipientInfo.vue
+++ b/src/components/RecipientInfo.vue
@@ -6,19 +6,23 @@