diff --git a/files/style/be.bastelstu.chat.scss b/files/style/be.bastelstu.chat.scss
index 0d0a4a2..331cc93 100644
--- a/files/style/be.bastelstu.chat.scss
+++ b/files/style/be.bastelstu.chat.scss
@@ -1,10 +1,10 @@
/*
- * Copyright (c) 2010-2021 Tim Düsterhus.
+ * Copyright (c) 2010-2022 Tim Düsterhus.
*
* Use of this software is governed by the Business Source License
* included in the LICENSE file.
*
- * Change Date: 2026-03-10
+ * Change Date: 2026-08-10
*
* On the date above, in accordance with the Business Source
* License, use of this software will be governed by version 2
@@ -70,17 +70,31 @@ #tpl_chat_log {
flex: 0.5 0 auto;
flex-direction: column;
margin-left: 10px;
- max-width: 310px;
+ max-width: min(310px, 35%);
> .boxContainer {
-webkit-columns: 1;
-moz-columns: 1;
columns: 1;
+
+ margin-bottom: 0;
+
+ > .box {
+ border-bottom: none;
+ }
}
}
}
- @include screen-lg {
+ @include screen-sm-up {
+ .layoutBoundary {
+ flex-wrap: nowrap;
+ }
+
+ .content + .sidebar.boxesSidebarRight {
+ margin-top: 0;
+ }
+
.boxesSidebarRight {
&,
> .boxContainer {
@@ -89,6 +103,7 @@ #tpl_chat_log {
}
> .boxContainer {
+ overflow: auto;
flex: 1 1 auto;
> .box {
@@ -96,15 +111,27 @@ #tpl_chat_log {
flex: 2 0 0px;
min-height: 15rem;
+ html.fullscreen & {
+ flex: 1 1 content;
+ }
+
> .boxContent {
flex-basis: 6rem;
}
}
&[data-box-identifier='be.bastelstu.chat.roomListSidebar'] {
- flex: 1 1 0px;
+ flex: 1 1 12rem;
min-height: 12rem;
+ html.fullscreen & {
+ flex: 1 1 content;
+ }
+
+ @media screen and (max-height: 440px) {
+ min-height: 120px;
+ }
+
.badge {
float: right;
padding-left: 7px;
@@ -128,7 +155,9 @@ #tpl_chat_log {
}
}
}
+ }
+ @include screen-lg {
#chatQuickSettings {
display: none;
}
@@ -157,6 +186,11 @@ #tpl_chat_log {
flex-direction: column;
flex: 1 1 auto;
width: 100%;
+
+ > .contentInteraction:first-child {
+ margin-top: 0;
+ margin-bottom: 20px;
+ }
}
#chatMessageStream > .scrollContainer,
@@ -257,7 +291,8 @@ #tpl_chat_log {
// Limit embedded images and videos to a reasonable size
img:not(.smiley):not(.userAvatarImage) {
- max-width: $chatEmbedMaxWidth;
+ // Workaround: `min` is an internal Sass function but we want the actual CSS function
+ max-width: min + unquote( '(' ) + "#{100%, $chatEmbedMaxWidth}" + unquote( ')' );
}
.videoContainer {
@@ -371,15 +406,18 @@ #tpl_chat_log {
#chatInputContainer {
margin-top: 10px;
+ margin-bottom: 1.48 * $wcfFontSizeDefault; // 1.48 is the default line height
clear: both;
- textarea {
- resize: none;
- }
.charCounter {
float: right;
color: $wcfContentDimmedText;
+ margin-bottom: -(1.48 * $wcfFontSizeDefault);
+ }
+
+ textarea {
+ resize: none;
}
> div {
@@ -489,30 +527,21 @@ #tpl_chat_log {
margin-left: 5px;
}
- #smileyPickerContainer {
- #smilies-text {
- @if variable_exists(wcfContentContainerBackground) {
- background-color: $wcfContentContainerBackground;
- } @else {
- // Compatibility with API_VERSION 3.0
- background-color: rgba(255, 255, 255, 1);
- }
+ #chatUserList,
+ [data-box-identifier='be.bastelstu.chat.roomListSidebar'] {
+ .modalCloseButton {
+ margin: 0 -10px -20px -10px;
+ }
+ }
- border: 1px solid $wcfContentBorderInner;
- padding: 20px;
- margin-top: 20px;
- margin-bottom: 20px;
-
- > .smileyList {
- overflow: auto;
- }
+ @include screen-md-down {
+ #smileyPickerContainer[data-show='true'] > div {
+ margin: 0;
}
- #smileyPickerCloseButton {
- display: none;
- }
-
- @include screen-md-down {
+ #smileyPickerContainer,
+ #chatUserList,
+ [data-box-identifier='be.bastelstu.chat.roomListSidebar'] {
&[data-show='true'] {
position: fixed;
top: 0;
@@ -524,7 +553,10 @@ #tpl_chat_log {
flex-direction: column;
pointer-events: all;
- #smileyPickerCloseButton {
+ background-color: $wcfContentBackground;
+
+ .modalCloseButton {
+ border-top: 1px solid $wcfContentBorderInner;
background-color: $wcfSidebarBackground;
color: $wcfSidebarLink;
display: block;
@@ -534,12 +566,9 @@ #tpl_chat_log {
cursor: pointer;
}
- #smilies-text {
- border-top: none;
- border-right: none;
- border-left: none;
+ > div {
+ border: none;
- margin: 0;
height: 0;
flex: 1 1 auto;
position: relative;
@@ -570,6 +599,24 @@ #tpl_chat_log {
}
}
+ #smileyPickerContainer {
+ > .messageTabMenuContent {
+ background-color: $wcfContentContainerBackground;
+ border: 1px solid $wcfContentBorderInner;
+ padding: 20px;
+ margin-top: 20px;
+ margin-bottom: 20px;
+
+ > .smileyList {
+ overflow: auto;
+ }
+ }
+
+ .modalCloseButton {
+ display: none;
+ }
+ }
+
#chatAttachmentUploadDialog {
.attachmentPreview {
text-align: center;
@@ -607,7 +654,9 @@ html.fullscreen {
.pageHeaderContainer,
.pageNavigation,
- .pageFooter {
+ .boxesFooterBoxes,
+ .pageFooter,
+ .contentInteraction {
display: none;
}
diff --git a/files_wcf/js/Bastelstu.be/Chat/Helper.js b/files_wcf/js/Bastelstu.be/Chat/Helper.js
index 392f1c3..97edbd2 100644
--- a/files_wcf/js/Bastelstu.be/Chat/Helper.js
+++ b/files_wcf/js/Bastelstu.be/Chat/Helper.js
@@ -1,10 +1,10 @@
/*
- * Copyright (c) 2010-2021 Tim Düsterhus.
+ * Copyright (c) 2010-2022 Tim Düsterhus.
*
* Use of this software is governed by the Business Source License
* included in the LICENSE file.
*
- * Change Date: 2026-03-10
+ * Change Date: 2026-08-10
*
* On the date above, in accordance with the Business Source
* License, use of this software will be governed by version 2
@@ -135,6 +135,7 @@ define(['WoltLabSuite/Core/Date/Util', 'WoltLabSuite/Core/Language'], function (
textarea.parentNode.classList.add('flexibleTextarea')
}
+ textarea.removeAttribute('rows')
textarea.classList.add('flexibleTextareaContent')
pre.classList.add('flexibleTextareaMirror')
@@ -377,6 +378,20 @@ define(['WoltLabSuite/Core/Date/Util', 'WoltLabSuite/Core/Language'], function (
return out
}
+
+ static getElementSiblings(element) {
+ if (!element || !element.parentNode) {
+ return
+ }
+
+ const children = [ ...element.parentNode.children ]
+ const index = children.indexOf(element);
+
+ return [
+ ...children.slice(0, index),
+ ...children.slice(index + 1)
+ ]
+ }
}
return Helper
diff --git a/files_wcf/js/Bastelstu.be/Chat/Ui/Settings/RoomListButton.js b/files_wcf/js/Bastelstu.be/Chat/Ui/Settings/RoomListButton.js
new file mode 100644
index 0000000..784ef40
--- /dev/null
+++ b/files_wcf/js/Bastelstu.be/Chat/Ui/Settings/RoomListButton.js
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2010-2022 Tim Düsterhus.
+ *
+ * Use of this software is governed by the Business Source License
+ * included in the LICENSE file.
+ *
+ * Change Date: 2026-08-10
+ *
+ * On the date above, in accordance with the Business Source
+ * License, use of this software will be governed by version 2
+ * or later of the General Public License.
+ */
+
+define([
+ '../../Helper',
+ './Button',
+ 'WoltLabSuite/Core/Dom/Util',
+ 'WoltLabSuite/Core/Language',
+ 'WoltLabSuite/Core/Ui/Screen'
+], function (
+ Helper,
+ Button,
+ DomUtil,
+ Language,
+ UiScreen
+) {
+ 'use strict'
+
+ const DEPENDENCIES = [].concat(Button.DEPENDENCIES || [])
+ class RoomListButton extends Button {
+ constructor(element, ...superDeps) {
+ super(element, ...superDeps)
+
+ this.roomList = document.querySelector(`[data-box-identifier='be.bastelstu.chat.roomListSidebar']`)
+ if (!this.roomList) {
+ element.remove()
+ return
+ }
+
+ this.mobile = false
+ this.open = false
+ this.sidebar = document.querySelector('.sidebar')
+
+ UiScreen.on('screen-xs', {
+ match: () => this.enableMobile(),
+ unmatch: () => this.disableMobile(),
+ setup: () => this.enableMobile(),
+ })
+ }
+
+ enableMobile() {
+ this.mobile = true
+ this.element.parentElement.hidden = false
+ }
+
+ disableMobile() {
+ if (this.open) {
+ this.show(false)
+ }
+
+ this.element.parentElement.hidden = true
+ this.mobile = false
+ }
+
+ show(doShow = true) {
+ if (doShow) {
+ this.open = true
+ this.sidebar.style.setProperty('display', 'contents', '');
+
+ for (let sibling of Helper.getElementSiblings(this.roomList)) {
+ DomUtil.hide(sibling)
+ }
+
+ this.closeButton = document.createElement('span')
+ this.closeButton.classList.add('modalCloseButton')
+ this.closeButton.innerText = Language.get('wcf.global.button.close')
+ this.closeButton.addEventListener('click', () => this.show(false))
+ this.roomList.appendChild(this.closeButton)
+
+ this.roomList.dataset.show = 'true'
+
+ if (this.mobile) {
+ UiScreen.scrollDisable()
+ }
+ }
+ else {
+ delete this.roomList.dataset.show
+ this.closeButton.remove()
+
+ for (let sibling of Helper.getElementSiblings(this.roomList)) {
+ DomUtil.show(sibling)
+ }
+
+ this.sidebar.style.removeProperty('display')
+ this.open = false
+
+ if (this.mobile) {
+ UiScreen.scrollEnable()
+ }
+ }
+ }
+
+ async onClick(event) {
+ super.onClick(event)
+
+ this.show(!this.open)
+ }
+ }
+ RoomListButton.DEPENDENCIES = DEPENDENCIES
+
+ return RoomListButton
+})
diff --git a/files_wcf/js/Bastelstu.be/Chat/Ui/Settings/SmiliesButton.js b/files_wcf/js/Bastelstu.be/Chat/Ui/Settings/SmiliesButton.js
index e2f1a20..c58280a 100644
--- a/files_wcf/js/Bastelstu.be/Chat/Ui/Settings/SmiliesButton.js
+++ b/files_wcf/js/Bastelstu.be/Chat/Ui/Settings/SmiliesButton.js
@@ -1,10 +1,10 @@
/*
- * Copyright (c) 2010-2021 Tim Düsterhus.
+ * Copyright (c) 2010-2022 Tim Düsterhus.
*
* Use of this software is governed by the Business Source License
* included in the LICENSE file.
*
- * Change Date: 2026-03-10
+ * Change Date: 2026-08-10
*
* On the date above, in accordance with the Business Source
* License, use of this software will be governed by version 2
@@ -97,7 +97,7 @@ define(['./ToggleButton', 'WoltLabSuite/Core/Ui/Screen'], function (
enableMobile() {
this.mobile = true
- elHide(this.element)
+ elHide(this.element.parentElement)
elShow(this.shadowToggleButton)
// Do not show the overlay when the viewport changes
@@ -114,7 +114,7 @@ define(['./ToggleButton', 'WoltLabSuite/Core/Ui/Screen'], function (
disableMobile() {
this.mobile = false
- elShow(this.element)
+ elShow(this.element.parentElement)
elHide(this.shadowToggleButton)
UiScreen.scrollEnable()
diff --git a/files_wcf/js/Bastelstu.be/Chat/Ui/Settings/UserListButton.js b/files_wcf/js/Bastelstu.be/Chat/Ui/Settings/UserListButton.js
new file mode 100644
index 0000000..cf7cb42
--- /dev/null
+++ b/files_wcf/js/Bastelstu.be/Chat/Ui/Settings/UserListButton.js
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2010-2022 Tim Düsterhus.
+ *
+ * Use of this software is governed by the Business Source License
+ * included in the LICENSE file.
+ *
+ * Change Date: 2026-08-10
+ *
+ * On the date above, in accordance with the Business Source
+ * License, use of this software will be governed by version 2
+ * or later of the General Public License.
+ */
+
+define([
+ '../../Helper',
+ './Button',
+ 'WoltLabSuite/Core/Dom/Util',
+ 'WoltLabSuite/Core/Language',
+ 'WoltLabSuite/Core/Ui/Screen'
+], function (
+ Helper,
+ Button,
+ DomUtil,
+ Language,
+ UiScreen
+) {
+ 'use strict'
+
+ const DEPENDENCIES = [].concat(Button.DEPENDENCIES || [])
+ class UserListButton extends Button {
+ constructor(element, ...superDeps) {
+ super(element, ...superDeps)
+
+ this.mobile = false
+ this.open = false
+ this.userList = document.getElementById('chatUserList')
+ this.sidebar = document.querySelector('.sidebar')
+
+ UiScreen.on('screen-xs', {
+ match: () => this.enableMobile(),
+ unmatch: () => this.disableMobile(),
+ setup: () => this.enableMobile(),
+ })
+ }
+
+ enableMobile() {
+ this.mobile = true
+ this.element.parentElement.hidden = false
+ }
+
+ disableMobile() {
+ if (this.open) {
+ this.show(false)
+ }
+
+ this.element.parentElement.hidden = true
+ this.mobile = false
+ }
+
+ show(doShow = true) {
+ if (doShow) {
+ this.open = true
+ this.sidebar.style.setProperty('display', 'contents', '');
+
+ for (let sibling of Helper.getElementSiblings(this.userList)) {
+ DomUtil.hide(sibling)
+ }
+
+ this.closeButton = document.createElement('span')
+ this.closeButton.classList.add('modalCloseButton')
+ this.closeButton.innerText = Language.get('wcf.global.button.close')
+ this.closeButton.addEventListener('click', () => this.show(false))
+ this.userList.appendChild(this.closeButton)
+
+ this.userList.dataset.show = 'true'
+
+ if (this.mobile) {
+ UiScreen.scrollDisable()
+ }
+ }
+ else {
+ delete this.userList.dataset.show
+ this.closeButton.remove()
+
+ for (let sibling of Helper.getElementSiblings(this.userList)) {
+ DomUtil.show(sibling)
+ }
+
+ this.sidebar.style.removeProperty('display')
+ this.open = false
+
+ if (this.mobile) {
+ UiScreen.scrollEnable()
+ }
+ }
+ }
+
+ async onClick(event) {
+ super.onClick(event)
+
+ this.show(!this.open)
+ }
+ }
+ UserListButton.DEPENDENCIES = DEPENDENCIES
+
+ return UserListButton
+})
diff --git a/language/de.xml b/language/de.xml
index 090c6a8..c0fa35b 100644
--- a/language/de.xml
+++ b/language/de.xml
@@ -124,6 +124,8 @@