[TikiWiki-commits] [Git][tikiwiki/tiki][master ] [ENH] Minichat UI improvement – updated chat bu bble style and message layout
Benoit Grégoire (@benoitg) via TikiWiki-cvs <[email protected]>
| Newsgroups | gmane.comp.cms.tiki.cvs |
|---|---|
| Message-ID | <68fcdfcb566e8_2cc7432e877021@gitlab-sidekiq-low-urgency-cpu-bound-v2-854849f664-jckhl.mail> |
Benoit Grégoire pushed to branch master at Tiki Wiki CMS Groupware / Tiki
Commits:
2904b01f by Yves Ngalamulume at 2025-10-25T14:26:00+00:00
[ENH] Minichat UI improvement – updated chat bubble style and message layout
---
* [ENH] Move remaining SCSS rules to appropriate partials
* [ENH][UI] Improve Minichat interface – message bubbles and layout update
* [ENH][UI] Minichat UI enhancement: message styles and animations
* [ENH] Minichat UI improvement – updated chat bubble style and message layout
See merge request tikiwiki/tiki!8801
- - - - -
6 changed files:
- templates/modules/mod-minichat.tpl
- themes/base_files/css/tiki_base.scss
- themes/base_files/scss/_tiki-menus.scss
- themes/base_files/scss/_tiki-tabs_and_tables.scss
- themes/quartz/scss/_bootswatch.scss
- tiki-minichat_ajax.php
Changes:
=====================================
templates/modules/mod-minichat.tpl
=====================================
@@ -1,18 +1,37 @@
{tikimodule error=$module_params.error title=$tpl_module_title name="minichat" flip=$module_params.flip decorations=$module_params.decorations nobox=$module_params.nobox notitle=$module_params.notitle}
{if $tiki_p_chat eq 'y'}
- <div id='minichatchans' class='btn-group minichatchans mb-2'{if $module_params.nochannelbar && $module_params.nochannelbar != "n"} style="height: 0; visibility: hidden"{/if}></div>
+ <div
+ id="minichatchans"
+ class="btn-group minichatchans mb-2"
+ {if $module_params.nochannelbar && $module_params.nochannelbar != "n"}
+ style="height:0;visibility:hidden"
+ {/if}>
+ </div>
- <div id='minichat' class='minichat well well-sm' style='overflow-x: hidden; overflow-y: auto; height: {$module_rows}em;'></div>
+ <div
+ id="minichat"
+ class="card card-body mb-2 overflow-auto"
+ style="height: {$module_rows}em;">
+ </div>
- <div class="minichatinputs">
- <form name='minichatinputform' action='javascript:minichatpost();'>
- <div class="input-group input-group-sm">
- <input class="form-control" name='minichatinput' id='minichatinput' type='text' autocomplete='off'>
- <input class="btn btn-primary" type='submit' value="{tr}OK{/tr}">
- </div>
- </form>
+ <div class="border-top pt-2 bg-body">
+ <form name="minichatinputform" onsubmit="minichatpost(); return false;">
+ <div class="input-group input-group-sm">
+ <input
+ id="minichatinput"
+ name="minichatinput"
+ type="text"
+ class="form-control rounded-pill"
+ autocomplete="off"
+ placeholder="{tr}Type a message...{/tr}">
+ <button type="submit" class="btn btn-primary rounded-pill">
+ {tr}Send{/tr}
+ </button>
</div>
- {else}
+ </form>
+ </div>
+
+{else}
{tr}You do not have the permission that is needed to use this feature.{/tr}
{/if}
{/tikimodule}
@@ -57,29 +76,37 @@
function minichat_loadJS(file) {
var head = document.getElementsByTagName('head').item(0);
var scriptTag = document.getElementById('minichat_loadJS');
+ const chat = document.getElementById('minichat');
if (scriptTag) head.removeChild(scriptTag);
script = document.createElement('script');
script.src = file;
script.type = 'text/javascript';
script.id = 'minichat_loadJS';
head.appendChild(script);
+
+ chat.scrollTop = chat.scrollHeight;
}
function minichat_update() {
var u=minichat_mkurl();
minichat_loadJS(u);
+ setTimeout(function() {
+ var chatDiv = document.getElementById('minichat');
+ if (chatDiv) chatDiv.scrollTop = chatDiv.scrollHeight;
+ }, 500);
}
function minichatpost() {
- var obj=document.getElementById('minichatinput');
- var value=minichat_urlencode(obj.value);
-
- var u=minichat_mkurl();
- if (minichat_selectedchan) u+="&msgon="+minichat_urlencode(minichat_selectedchan.name);
- u+="&msg="+value;
+ var obj = document.getElementById('minichatinput');
+ var value = minichat_urlencode(obj.value);
+ var u = minichat_mkurl();
+ if (minichat_selectedchan) u += "&msgon=" + minichat_urlencode(minichat_selectedchan.name);
+ u += "&msg_chat=" + value;
+
minichat_loadJS(u);
- obj.value='';
+ obj.value = '';
+
}
function minichat_newelem(type, vals) {
=====================================
themes/base_files/css/tiki_base.scss
=====================================
@@ -50,79 +50,4 @@
@import "../scss/_tiki-debugger_console.scss";
@import "../scss/_tiki-show_database_query_log.scss";
//@import "../scss/_pivot-tiki.scss";
-//@import "../scss/_conversejs-tiki.scss";
-//@import "../scss/_tiki-selectors.scss";
-
-// Sticky tables
-.tiki .table-sticky {
- overflow: visible !important;
-}
-.tiki .table-sticky thead {
- position: -webkit-sticky;
- /* for Safari */
- position: sticky;
- top: 0;
- z-index: 2;
-}
-.tiki .table-sticky tbody th {
- position: sticky;
- position: -webkit-sticky;
- width: 100px;
- min-width: 100px;
- max-width: 100px;
- left: 0px;
- z-index: 1;
-}
-// Icon to toggle table formatting for small devices
-.toggle-table-wrap .btn {
- font-family: 'Font Awesome 6 Free';
- font-weight: 600;
- font-size: 1.25rem;
-}
-
-li.highlight {
- background-color: var(--bs-secondary-bg-subtle);
- transition: all 0.3s ease;
-}
-
-.password-container {
- position: relative;
- display: inline-block;
- width: 100%;
-
- input {
- padding-right: 30px;
- }
-
- i {
- position: absolute;
- right: 10px;
- top: 50%;
- transform: translateY(-50%);
- cursor: pointer;
- visibility: hidden; /* Hidden by default */
- }
-}
-/* --- Force all dropdowns to open upwards ---*/
-.dropdown-menu-bottom {
- top: auto !important;
- bottom: 100% !important;
- margin-bottom: .5rem;
- margin-top: 0 !important;
- max-height: 65vh;
- overflow-y: auto;
- overflow-x: hidden;
-}
-
-.dropdown-menu-top,
-.dropdown-menu-end,
-.dropdown-menu-start {
- top: 100%;
- bottom: auto;
- max-height: 40vh;
- overflow-y: auto;
- overflow-x: hidden;
- z-index: 3000;
-}
-
-/* End of file */
+//@import "../scss/_conversejs-tiki.scss";
\ No newline at end of file
=====================================
themes/base_files/scss/_tiki-menus.scss
=====================================
@@ -153,3 +153,25 @@
text-rendering: auto;
-webkit-font-smoothing: antialiased;
}
+
+/* --- Force all dropdowns to open upwards ---*/
+.dropdown-menu-bottom {
+ top: auto !important;
+ bottom: 100% !important;
+ margin-bottom: .5rem;
+ margin-top: 0 !important;
+ max-height: 65vh;
+ overflow-y: auto;
+ overflow-x: hidden;
+}
+
+.dropdown-menu-top,
+.dropdown-menu-end,
+.dropdown-menu-start {
+ top: 100%;
+ bottom: auto;
+ max-height: 40vh;
+ overflow-y: auto;
+ overflow-x: hidden;
+ z-index: 3000;
+}
=====================================
themes/base_files/scss/_tiki-tabs_and_tables.scss
=====================================
@@ -234,3 +234,32 @@ td.url{
}
}
}
+
+// Sticky tables
+.tiki .table-sticky {
+ overflow: visible !important;
+}
+.tiki .table-sticky thead {
+ position: -webkit-sticky;
+ /* for Safari */
+ position: sticky;
+ top: 0;
+ z-index: 2;
+}
+.tiki .table-sticky tbody th {
+ position: sticky;
+ position: -webkit-sticky;
+ width: 100px;
+ min-width: 100px;
+ max-width: 100px;
+ left: 0px;
+ z-index: 1;
+}
+// Icon to toggle table formatting for small devices
+.toggle-table-wrap .btn {
+ font-family: 'Font Awesome 6 Free';
+ font-weight: 600;
+ font-size: 1.25rem;
+}
+
+
=====================================
themes/quartz/scss/_bootswatch.scss
=====================================
@@ -101,6 +101,30 @@ body {
border-right: none;
}
+li.highlight {
+ background-color: var(--bs-secondary-bg-subtle);
+ transition: all 0.3s ease;
+}
+
+.password-container {
+ position: relative;
+ display: inline-block;
+ width: 100%;
+
+ input {
+ padding-right: 30px;
+ }
+
+ i {
+ position: absolute;
+ right: 10px;
+ top: 50%;
+ transform: translateY(-50%);
+ cursor: pointer;
+ visibility: hidden; /* Hidden by default */
+ }
+}
+
.form-select:not([multiple]) {
transition: border-color .15s ease-in-out;
=====================================
tiki-minichat_ajax.php
=====================================
@@ -49,8 +49,8 @@ function initchannelssession($chans)
$_SESSION['minichat_channels'][] = $channel;
}
}
-if (isset($_REQUEST['msg'])) {
- $msg = $_REQUEST['msg'];
+if (isset($_REQUEST['msg_chat'])) {
+ $msg = $_REQUEST['msg_chat'];
$msg = strtr($msg, "\n\r\t", " ");
$msgon = $_REQUEST['msgon'] ?? null;
if (empty($msg)) {
@@ -124,14 +124,17 @@ foreach ($chans as $chan) {
}
if ($lastid == 0) {
$result = $tikilib->query("SELECT * FROM tiki_minichat WHERE channel=? ORDER by id desc LIMIT 100", [$channel]);
- $msgtotal = "";
+ // collect rows, reverse to chronological order (oldest first)
+ $rows = [];
while ($row = $result->fetchRow()) {
- if (! $lastid) {
- $lastid = $row['id'];
- echo "minichat_updatelastid('$channel', $lastid);\n";
- }
- # if timestamp corresponds to previous days than current, show date with display_order according to the global preference
- # daytmes = day from the time stamp of the message; daytnow = current day;
+ $rows[] = $row;
+ }
+ $rows = array_reverse($rows);
+
+ $msgtotal = "";
+ $prev_user = null;
+ foreach ($rows as $row) {
+ // compute time display (same logic as before)
$daytmes = date("d/m/y", $row['ts']);
$daytnow = date("d/m/y");
if ($daytmes == $daytnow) {
@@ -153,12 +156,39 @@ foreach ($chans as $chan) {
$t = date("H:i", $row['ts']);
}
}
- //TODO: improve matching and replace with better smileys + use global lib
- $msgtotal = "<span class='minichat_ts'>[$t]</span> <span class='minichat_nick'><" . ($row['nick'] == '' ? "<em>" . tra('Anonymous') . "</em>" : str_replace('"', '\"', smarty_modifier_userlink($row['user']))) . "></span> <span class='minichat_msg'>" . htmlentities($row['msg'], ENT_QUOTES, 'UTF-8') . "</span><br>" . $msgtotal;
+
+ $nick_html = ($row['nick'] == '' ? "<em>" . tra('Anonymous') . "</em>" : smarty_modifier_userlink($row['user']));
+ $msg_html = htmlentities($row['msg'], ENT_QUOTES, 'UTF-8');
+ $side_class = ($row['user'] == $user) ? 'mine' : 'other';
+
+ $show_header = ($prev_user !== $row['user']);
+
+ $align_class = ($side_class === 'mine') ? 'justify-content-end' : 'justify-content-start';
+ $card_classes = ($side_class === 'mine') ? 'card text-white bg-info' : 'card bg-light';
+
+ $bubble = "<div class='d-flex mb-2 {$align_class}'>";
+ $bubble .= "<div class='{$card_classes}' style='max-width:70%'>";
+ $bubble .= "<div class='card-body p-2'>";
+ if ($show_header) {
+ $bubble .= "<div class='fw-bold small'>" . $nick_html . "</div>";
+ }
+ $bubble .= "<div class='card-text'>{$msg_html}</div>";
+ $bubble .= "<div class='text-end'><small class='text-muted'>{$t}</small></div>";
+ $bubble .= "</div></div></div>";
+
+ $msgtotal .= $bubble; // append to keep chronological order top->bottom
+ $prev_user = $row['user'];
+ }
+
+ // update lastid with the newest message id (last element in $rows)
+ if (! empty($rows)) {
+ $newlast = $rows[count($rows) - 1]['id'];
+ $lastid = (int)$newlast;
+ echo "minichat_updatelastid(" . json_encode($channel) . ", $lastid);\n";
}
$editlib = TikiLib::lib('edit');
$msgtotal = $editlib->convertSmileysToUnicode($msgtotal);
- echo "document.getElementById('minichatdiv_'+minichat_getchanid('$channel')).innerHTML=\"$msgtotal\";\n";
+ echo "document.getElementById('minichatdiv_'+minichat_getchanid(" . json_encode($channel) . ")).innerHTML=" . json_encode($msgtotal) . ";\n";
echo "document.getElementById('minichat').scrollTop=99999;\n";
}
}
View it on GitLab: https://gitlab.com/tikiwiki/tiki/-/commit/2904b01ff48ad740231eacf86a95d8edf97863bd
--
View it on GitLab: https://gitlab.com/tikiwiki/tiki/-/commit/2904b01ff48ad740231eacf86a95d8edf97863bd
You're receiving this email because of your account on gitlab.com.
_______________________________________________
TikiWiki-cvs mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/tikiwiki-cvs