Fossil SCM

Initial go at a "bottom-up" (mobile-like) layout for chat, but it is only active in chat-only mode where we have more control over the layout. The default mode works like before, top-down. There are still minor usability/scrolling issues left to resolve but it seems to essentially work.

stephan 2020-12-26 01:31 trunk
Commit cffd66ffe9ed970d831383df282397ace7b61addade191e076ae4eb098658893
2 files changed +78 -48 +28 -23
+78 -48
--- src/chat.js
+++ src/chat.js
@@ -7,10 +7,11 @@
77
const E1 = function(selector){
88
const e = document.querySelector(selector);
99
if(!e) throw new Error("missing required DOM element: "+selector);
1010
return e;
1111
};
12
+ //document.body.classList.add('chat-only-mode');
1213
const Chat = (function(){
1314
const cs = {
1415
e:{/*map of certain DOM elements.*/
1516
messageInjectPoint: E1('#message-inject-point'),
1617
pageTitle: E1('head title'),
@@ -112,17 +113,60 @@
112113
injectMessageElem: function f(e, atEnd){
113114
const mip = atEnd ? this.e.loadToolbar : this.e.messageInjectPoint;
114115
if(atEnd){
115116
mip.parentNode.insertBefore(e, mip);
116117
}else{
117
- if(mip.nextSibling){
118
- mip.parentNode.insertBefore(e, mip.nextSibling);
118
+ if(mip.nextSibling) mip.parentNode.insertBefore(e, mip.nextSibling);
119
+ else mip.parentNode.appendChild(e);
120
+ if(this.isChatOnlyMode()){
121
+ e.scrollIntoView();
119122
}else{
120
- mip.parentNode.appendChild(e);
123
+ //const rect = e.getBoundingClientRect();
124
+ //const rect = this.e.inputWrapper.getBoundingClientRect();
125
+ //window.scrollBy(0, -cs.height);
126
+ //console.debug("rect =",rect);
127
+ //window.scrollBy(0,rect.height);
128
+ //window.scrollTo(0,rect.top);
129
+ //e.querySelector('.message-widget-tab').scrollIntoView();
121130
}
122131
}
123132
},
133
+ isChatOnlyMode: function(){
134
+ return document.body.classList.contains('chat-only-mode');
135
+ },
136
+ chatOnlyMode: function f(yes){
137
+ if(undefined === f.elemsToToggle){
138
+ f.elemsToToggle = [];
139
+ document.body.childNodes.forEach(function(e){
140
+ if(!e.classList) return/*TEXT nodes and such*/;
141
+ else if(!e.classList.contains('content')
142
+ && !e.classList.contains('fossil-PopupWidget')
143
+ /*kludge^^^ for settingsPopup click handling!*/){
144
+ f.elemsToToggle.push(e);
145
+ }
146
+ });
147
+ }
148
+ if(!arguments.length) yes = true;
149
+ if(yes === this.isChatOnlyMode()) return this;
150
+ if(yes){
151
+ D.addClass(f.elemsToToggle, 'hidden');
152
+ D.addClass(document.body, 'chat-only-mode');
153
+ document.body.scroll(0,document.body.height);
154
+ }else{
155
+ D.removeClass(f.elemsToToggle, 'hidden');
156
+ D.removeClass(document.body, 'chat-only-mode');
157
+ setTimeout(()=>document.body.scrollIntoView(
158
+ /*moves to (0,0), whereas scrollTo(0,0) does not!*/
159
+ ), 0);
160
+ }
161
+ const msg = document.querySelector('.message-widget');
162
+ if(msg) msg.scrollIntoView();
163
+ return this;
164
+ },
165
+ toggleChatOnlyMode: function(){
166
+ return this.chatOnlyMode(!this.isChatOnlyMode());
167
+ },
124168
settings:{
125169
get: (k,dflt)=>F.storage.get(k,dflt),
126170
getBool: (k,dflt)=>F.storage.getBool(k,dflt),
127171
set: (k,v)=>F.storage.set(k,v),
128172
defaults:{
@@ -145,10 +189,28 @@
145189
if(cs.settings.getBool('monospace-messages',false)){
146190
document.body.classList.add('monospace-messages');
147191
}
148192
cs.e.inputCurrent = cs.e.inputSingle;
149193
cs.pageTitleOrig = cs.e.pageTitle.innerText;
194
+
195
+ if(true){
196
+ /* In order to make the input area opaque, such that the message
197
+ list scrolls under it without being visible, we have to
198
+ ensure that the input area has a non-transparent background
199
+ color. Ideally we'd select the color of div.content, but that
200
+ is not necessarily set, so we fall back to using the body's
201
+ background color and hope it's been explicitly set
202
+ somewhere. If we rely on the input area having its own color
203
+ specified in CSS then all skins would have to define an
204
+ appropriate color. Thus our selection of the body color,
205
+ while slightly unfortunate, is in the interest of keeping
206
+ skins from being forced to define an opaque bg color.
207
+ */
208
+ const bodyStyle = window.getComputedStyle(document.body);
209
+ cs.e.inputWrapper.style.backgroundColor = bodyStyle.backgroundColor;
210
+ }
211
+
150212
const qs = (e)=>document.querySelector(e);
151213
const argsToArray = function(args){
152214
return Array.prototype.slice.call(args,0);
153215
};
154216
cs.reportError = function(/*msg args*/){
@@ -517,15 +579,11 @@
517579
518580
(function(){/*Set up #chat-settings-button */
519581
const settingsButton = document.querySelector('#chat-settings-button');
520582
var popupSize = undefined/*placement workaround*/;
521583
const settingsPopup = new F.PopupWidget({
522
- cssClass: ['fossil-tooltip', 'chat-settings-popup'],
523
- adjustY: function(y){
524
- const rect = settingsButton.getBoundingClientRect();
525
- return rect.top + rect.height + 2;
526
- }
584
+ cssClass: ['fossil-tooltip', 'chat-settings-popup']
527585
});
528586
/* Settings menu entries... */
529587
const settingsOps = [{
530588
label: "Multi-line input",
531589
boolValue: ()=>Chat.inputElement()===Chat.e.inputMulti,
@@ -540,49 +598,13 @@
540598
Chat.settings.set('monospace-messages',
541599
document.body.classList.contains('monospace-messages'));
542600
}
543601
},{
544602
label: "Chat-only mode",
545
- boolValue: ()=>!!document.body.classList.contains('chat-only-mode'),
546
- callback: function f(){
547
- if(undefined === f.isHidden){
548
- f.isHidden = false;
549
- f.elemsToToggle = [];
550
- document.body.childNodes.forEach(function(e){
551
- if(!e.classList) return/*TEXT nodes and such*/;
552
- else if(!e.classList.contains('content')
553
- && !e.classList.contains('fossil-PopupWidget')
554
- /*kludge^^^ for settingsPopup click handling!*/){
555
- f.elemsToToggle.push(e);
556
- }
557
- });
558
- /* In order to make the input area opaque, such that the
559
- message list scrolls under it without being visible, we
560
- have to ensure that the input area has a non-inherited
561
- background color. Ideally we'd select the color of
562
- div.content, but that is not necessarily set, so we fall
563
- back to using the body's background color. If we rely on
564
- the input area having its own color specified in CSS then
565
- all skins would have to define an appropriate color.
566
- Thus our selection of the body color, while slightly unfortunate,
567
- is in the interest of keeping skins from being forced to
568
- define an opaque bg color.
569
- */
570
- f.initialBg = Chat.e.messagesWrapper.style.backgroundColor;
571
- const cs = window.getComputedStyle(document.body);
572
- f.inheritedBg = cs.backgroundColor;
573
- }
574
- const iws = Chat.e.inputWrapper.style;
575
- if((f.isHidden = !f.isHidden)){
576
- D.addClass(f.elemsToToggle, 'hidden');
577
- D.addClass(document.body, 'chat-only-mode');
578
- iws.backgroundColor = f.inheritedBg;
579
- }else{
580
- D.removeClass(f.elemsToToggle, 'hidden');
581
- D.removeClass(document.body, 'chat-only-mode');
582
- iws.backgroundColor = f.initialBg;
583
- }
603
+ boolValue: ()=>Chat.isChatOnlyMode(),
604
+ callback: function(){
605
+ Chat.toggleChatOnlyMode();
584606
}
585607
},{
586608
label: "Left-align my posts",
587609
boolValue: ()=>!document.body.classList.contains('my-messages-right'),
588610
callback: function f(){
@@ -635,18 +657,26 @@
635657
else settingsPopup.show(settingsButton);
636658
/* Reminder: we cannot toggle the visibility from her
637659
*/
638660
}, false);
639661
640
- /* Find an ideal X position for the popup, directly under the settings
662
+ /* Find an ideal X/Y position for the popup, directly above the settings
641663
button, based on the size of the popup... */
642664
settingsPopup.show(document.body);
643665
popupSize = settingsPopup.e.getBoundingClientRect();
644666
settingsPopup.hide();
645667
settingsPopup.options.adjustX = function(x){
646668
const rect = settingsButton.getBoundingClientRect();
647669
return rect.right - popupSize.width;
670
+ };
671
+ settingsPopup.options.adjustY = function(y){
672
+ const rect = settingsButton.getBoundingClientRect();
673
+ if(Chat.isChatOnlyMode()){
674
+ return rect.top - popupSize.height -2;
675
+ }else{
676
+ return rect.bottom + 2;
677
+ }
648678
};
649679
})()/*#chat-settings-button setup*/;
650680
651681
652682
/** Callback for poll() to inject new content into the page. jx ==
653683
--- src/chat.js
+++ src/chat.js
@@ -7,10 +7,11 @@
7 const E1 = function(selector){
8 const e = document.querySelector(selector);
9 if(!e) throw new Error("missing required DOM element: "+selector);
10 return e;
11 };
 
12 const Chat = (function(){
13 const cs = {
14 e:{/*map of certain DOM elements.*/
15 messageInjectPoint: E1('#message-inject-point'),
16 pageTitle: E1('head title'),
@@ -112,17 +113,60 @@
112 injectMessageElem: function f(e, atEnd){
113 const mip = atEnd ? this.e.loadToolbar : this.e.messageInjectPoint;
114 if(atEnd){
115 mip.parentNode.insertBefore(e, mip);
116 }else{
117 if(mip.nextSibling){
118 mip.parentNode.insertBefore(e, mip.nextSibling);
 
 
119 }else{
120 mip.parentNode.appendChild(e);
 
 
 
 
 
 
121 }
122 }
123 },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
124 settings:{
125 get: (k,dflt)=>F.storage.get(k,dflt),
126 getBool: (k,dflt)=>F.storage.getBool(k,dflt),
127 set: (k,v)=>F.storage.set(k,v),
128 defaults:{
@@ -145,10 +189,28 @@
145 if(cs.settings.getBool('monospace-messages',false)){
146 document.body.classList.add('monospace-messages');
147 }
148 cs.e.inputCurrent = cs.e.inputSingle;
149 cs.pageTitleOrig = cs.e.pageTitle.innerText;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
150 const qs = (e)=>document.querySelector(e);
151 const argsToArray = function(args){
152 return Array.prototype.slice.call(args,0);
153 };
154 cs.reportError = function(/*msg args*/){
@@ -517,15 +579,11 @@
517
518 (function(){/*Set up #chat-settings-button */
519 const settingsButton = document.querySelector('#chat-settings-button');
520 var popupSize = undefined/*placement workaround*/;
521 const settingsPopup = new F.PopupWidget({
522 cssClass: ['fossil-tooltip', 'chat-settings-popup'],
523 adjustY: function(y){
524 const rect = settingsButton.getBoundingClientRect();
525 return rect.top + rect.height + 2;
526 }
527 });
528 /* Settings menu entries... */
529 const settingsOps = [{
530 label: "Multi-line input",
531 boolValue: ()=>Chat.inputElement()===Chat.e.inputMulti,
@@ -540,49 +598,13 @@
540 Chat.settings.set('monospace-messages',
541 document.body.classList.contains('monospace-messages'));
542 }
543 },{
544 label: "Chat-only mode",
545 boolValue: ()=>!!document.body.classList.contains('chat-only-mode'),
546 callback: function f(){
547 if(undefined === f.isHidden){
548 f.isHidden = false;
549 f.elemsToToggle = [];
550 document.body.childNodes.forEach(function(e){
551 if(!e.classList) return/*TEXT nodes and such*/;
552 else if(!e.classList.contains('content')
553 && !e.classList.contains('fossil-PopupWidget')
554 /*kludge^^^ for settingsPopup click handling!*/){
555 f.elemsToToggle.push(e);
556 }
557 });
558 /* In order to make the input area opaque, such that the
559 message list scrolls under it without being visible, we
560 have to ensure that the input area has a non-inherited
561 background color. Ideally we'd select the color of
562 div.content, but that is not necessarily set, so we fall
563 back to using the body's background color. If we rely on
564 the input area having its own color specified in CSS then
565 all skins would have to define an appropriate color.
566 Thus our selection of the body color, while slightly unfortunate,
567 is in the interest of keeping skins from being forced to
568 define an opaque bg color.
569 */
570 f.initialBg = Chat.e.messagesWrapper.style.backgroundColor;
571 const cs = window.getComputedStyle(document.body);
572 f.inheritedBg = cs.backgroundColor;
573 }
574 const iws = Chat.e.inputWrapper.style;
575 if((f.isHidden = !f.isHidden)){
576 D.addClass(f.elemsToToggle, 'hidden');
577 D.addClass(document.body, 'chat-only-mode');
578 iws.backgroundColor = f.inheritedBg;
579 }else{
580 D.removeClass(f.elemsToToggle, 'hidden');
581 D.removeClass(document.body, 'chat-only-mode');
582 iws.backgroundColor = f.initialBg;
583 }
584 }
585 },{
586 label: "Left-align my posts",
587 boolValue: ()=>!document.body.classList.contains('my-messages-right'),
588 callback: function f(){
@@ -635,18 +657,26 @@
635 else settingsPopup.show(settingsButton);
636 /* Reminder: we cannot toggle the visibility from her
637 */
638 }, false);
639
640 /* Find an ideal X position for the popup, directly under the settings
641 button, based on the size of the popup... */
642 settingsPopup.show(document.body);
643 popupSize = settingsPopup.e.getBoundingClientRect();
644 settingsPopup.hide();
645 settingsPopup.options.adjustX = function(x){
646 const rect = settingsButton.getBoundingClientRect();
647 return rect.right - popupSize.width;
 
 
 
 
 
 
 
 
648 };
649 })()/*#chat-settings-button setup*/;
650
651
652 /** Callback for poll() to inject new content into the page. jx ==
653
--- src/chat.js
+++ src/chat.js
@@ -7,10 +7,11 @@
7 const E1 = function(selector){
8 const e = document.querySelector(selector);
9 if(!e) throw new Error("missing required DOM element: "+selector);
10 return e;
11 };
12 //document.body.classList.add('chat-only-mode');
13 const Chat = (function(){
14 const cs = {
15 e:{/*map of certain DOM elements.*/
16 messageInjectPoint: E1('#message-inject-point'),
17 pageTitle: E1('head title'),
@@ -112,17 +113,60 @@
113 injectMessageElem: function f(e, atEnd){
114 const mip = atEnd ? this.e.loadToolbar : this.e.messageInjectPoint;
115 if(atEnd){
116 mip.parentNode.insertBefore(e, mip);
117 }else{
118 if(mip.nextSibling) mip.parentNode.insertBefore(e, mip.nextSibling);
119 else mip.parentNode.appendChild(e);
120 if(this.isChatOnlyMode()){
121 e.scrollIntoView();
122 }else{
123 //const rect = e.getBoundingClientRect();
124 //const rect = this.e.inputWrapper.getBoundingClientRect();
125 //window.scrollBy(0, -cs.height);
126 //console.debug("rect =",rect);
127 //window.scrollBy(0,rect.height);
128 //window.scrollTo(0,rect.top);
129 //e.querySelector('.message-widget-tab').scrollIntoView();
130 }
131 }
132 },
133 isChatOnlyMode: function(){
134 return document.body.classList.contains('chat-only-mode');
135 },
136 chatOnlyMode: function f(yes){
137 if(undefined === f.elemsToToggle){
138 f.elemsToToggle = [];
139 document.body.childNodes.forEach(function(e){
140 if(!e.classList) return/*TEXT nodes and such*/;
141 else if(!e.classList.contains('content')
142 && !e.classList.contains('fossil-PopupWidget')
143 /*kludge^^^ for settingsPopup click handling!*/){
144 f.elemsToToggle.push(e);
145 }
146 });
147 }
148 if(!arguments.length) yes = true;
149 if(yes === this.isChatOnlyMode()) return this;
150 if(yes){
151 D.addClass(f.elemsToToggle, 'hidden');
152 D.addClass(document.body, 'chat-only-mode');
153 document.body.scroll(0,document.body.height);
154 }else{
155 D.removeClass(f.elemsToToggle, 'hidden');
156 D.removeClass(document.body, 'chat-only-mode');
157 setTimeout(()=>document.body.scrollIntoView(
158 /*moves to (0,0), whereas scrollTo(0,0) does not!*/
159 ), 0);
160 }
161 const msg = document.querySelector('.message-widget');
162 if(msg) msg.scrollIntoView();
163 return this;
164 },
165 toggleChatOnlyMode: function(){
166 return this.chatOnlyMode(!this.isChatOnlyMode());
167 },
168 settings:{
169 get: (k,dflt)=>F.storage.get(k,dflt),
170 getBool: (k,dflt)=>F.storage.getBool(k,dflt),
171 set: (k,v)=>F.storage.set(k,v),
172 defaults:{
@@ -145,10 +189,28 @@
189 if(cs.settings.getBool('monospace-messages',false)){
190 document.body.classList.add('monospace-messages');
191 }
192 cs.e.inputCurrent = cs.e.inputSingle;
193 cs.pageTitleOrig = cs.e.pageTitle.innerText;
194
195 if(true){
196 /* In order to make the input area opaque, such that the message
197 list scrolls under it without being visible, we have to
198 ensure that the input area has a non-transparent background
199 color. Ideally we'd select the color of div.content, but that
200 is not necessarily set, so we fall back to using the body's
201 background color and hope it's been explicitly set
202 somewhere. If we rely on the input area having its own color
203 specified in CSS then all skins would have to define an
204 appropriate color. Thus our selection of the body color,
205 while slightly unfortunate, is in the interest of keeping
206 skins from being forced to define an opaque bg color.
207 */
208 const bodyStyle = window.getComputedStyle(document.body);
209 cs.e.inputWrapper.style.backgroundColor = bodyStyle.backgroundColor;
210 }
211
212 const qs = (e)=>document.querySelector(e);
213 const argsToArray = function(args){
214 return Array.prototype.slice.call(args,0);
215 };
216 cs.reportError = function(/*msg args*/){
@@ -517,15 +579,11 @@
579
580 (function(){/*Set up #chat-settings-button */
581 const settingsButton = document.querySelector('#chat-settings-button');
582 var popupSize = undefined/*placement workaround*/;
583 const settingsPopup = new F.PopupWidget({
584 cssClass: ['fossil-tooltip', 'chat-settings-popup']
 
 
 
 
585 });
586 /* Settings menu entries... */
587 const settingsOps = [{
588 label: "Multi-line input",
589 boolValue: ()=>Chat.inputElement()===Chat.e.inputMulti,
@@ -540,49 +598,13 @@
598 Chat.settings.set('monospace-messages',
599 document.body.classList.contains('monospace-messages'));
600 }
601 },{
602 label: "Chat-only mode",
603 boolValue: ()=>Chat.isChatOnlyMode(),
604 callback: function(){
605 Chat.toggleChatOnlyMode();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
606 }
607 },{
608 label: "Left-align my posts",
609 boolValue: ()=>!document.body.classList.contains('my-messages-right'),
610 callback: function f(){
@@ -635,18 +657,26 @@
657 else settingsPopup.show(settingsButton);
658 /* Reminder: we cannot toggle the visibility from her
659 */
660 }, false);
661
662 /* Find an ideal X/Y position for the popup, directly above the settings
663 button, based on the size of the popup... */
664 settingsPopup.show(document.body);
665 popupSize = settingsPopup.e.getBoundingClientRect();
666 settingsPopup.hide();
667 settingsPopup.options.adjustX = function(x){
668 const rect = settingsButton.getBoundingClientRect();
669 return rect.right - popupSize.width;
670 };
671 settingsPopup.options.adjustY = function(y){
672 const rect = settingsButton.getBoundingClientRect();
673 if(Chat.isChatOnlyMode()){
674 return rect.top - popupSize.height -2;
675 }else{
676 return rect.bottom + 2;
677 }
678 };
679 })()/*#chat-settings-button setup*/;
680
681
682 /** Callback for poll() to inject new content into the page. jx ==
683
+28 -23
--- src/default.css
+++ src/default.css
@@ -1597,10 +1597,14 @@
15971597
.settings-icon:hover {
15981598
border: 1px outset rgba(127,127,127,1);
15991599
}
16001600
body.fossil-dark-style .settings-icon {
16011601
filter: invert(100%);
1602
+}
1603
+/* "Chat-only mode" hides the site header/footer, showing only
1604
+ the chat app. */
1605
+body.chat.chat-only-mode{
16021606
}
16031607
body.chat #chat-settings-button {
16041608
}
16051609
/** Popup widget for the /chat settings. */
16061610
body.chat .chat-settings-popup {
@@ -1640,48 +1644,49 @@
16401644
/** Container for the list of /chat messages. */
16411645
body.chat #chat-messages-wrapper {
16421646
display: flex;
16431647
flex-direction: column;
16441648
}
1645
-/* "Chat-only mode" hides the site header/footer, showing only
1646
- the chat app. */
1647
-body.chat.chat-only-mode{
1649
+body.chat.chat-only-mode #chat-messages-wrapper {
1650
+ flex-direction: column-reverse;
1651
+ position: relative;
1652
+ top: 0;
1653
+ z-index: 99 /* so that it scrolls under input area. If it's
1654
+ lower than div.content then mouse events to it
1655
+ are blocked!*/;
16481656
}
16491657
body.chat.chat-only-mode > div.content {
16501658
margin: 0;
16511659
padding: 0;
16521660
display: flex;
16531661
flex-direction: column;
16541662
align-items: stretch;
16551663
}
1656
-body.chat.chat-only-mode #chat-input-area {
1657
- /* would like to pin this to the top so that it stays in place when
1658
- scrolling, but doing so causes #chat-messages-wrapper to scroll
1659
- behind it visibly, which is really ugly. Only current workaround is
1660
- to force an opaque background color on this element, but that's not
1661
- skin-friendly. */
1662
- position: sticky;
1663
- position: -webkit-sticky /* supposedly some versions of Safari */;
1664
- top: 0;
1665
- padding: 0.5em 1em;
1666
- z-index: 100
1667
- /* see notes in #chat-messages-wrapper. The various popups require a
1668
- z-index higher than this one. */
1669
-}
1670
-body.chat.chat-only-mode #chat-messages-wrapper {
1671
- position: relative;
1672
- top: 0;
1673
- z-index: 99 /* so that it scrolls under input area. If it's
1674
- lower than div.content then mouse events to it
1675
- are blocked!*/;
1664
+body.chat.chat-only-mode > div.content {
1665
+ flex-direction: column-reverse;
16761666
}
16771667
/* Wrapper for /chat user input controls */
16781668
body.chat #chat-input-area {
16791669
display: flex;
16801670
flex-direction: column;
16811671
border-bottom: 1px solid black;
1672
+ padding: 0.5em 1em;
16821673
margin-bottom: 0.5em;
1674
+ /*position: sticky; top: 0;*/
1675
+ /*position: -webkit-sticky*/ /* supposedly some versions of Safari */;
1676
+}
1677
+body.chat.chat-only-mode #chat-input-area {
1678
+ z-index: 100
1679
+ /* see notes in #chat-messages-wrapper. The various popups require a
1680
+ z-index higher than this one. */;
1681
+ border-bottom: none;
1682
+ border-top: 1px solid black;
1683
+ margin-bottom: 0;
1684
+ margin-top: 0.5em;
1685
+ position: sticky;
1686
+ position: -webkit-sticky/* supposedly some versions of Safari */;
1687
+ bottom: 0;
16831688
}
16841689
body.chat #chat-input-line {
16851690
display: flex;
16861691
flex-direction: row;
16871692
margin-bottom: 0.25em;
16881693
--- src/default.css
+++ src/default.css
@@ -1597,10 +1597,14 @@
1597 .settings-icon:hover {
1598 border: 1px outset rgba(127,127,127,1);
1599 }
1600 body.fossil-dark-style .settings-icon {
1601 filter: invert(100%);
 
 
 
 
1602 }
1603 body.chat #chat-settings-button {
1604 }
1605 /** Popup widget for the /chat settings. */
1606 body.chat .chat-settings-popup {
@@ -1640,48 +1644,49 @@
1640 /** Container for the list of /chat messages. */
1641 body.chat #chat-messages-wrapper {
1642 display: flex;
1643 flex-direction: column;
1644 }
1645 /* "Chat-only mode" hides the site header/footer, showing only
1646 the chat app. */
1647 body.chat.chat-only-mode{
 
 
 
 
1648 }
1649 body.chat.chat-only-mode > div.content {
1650 margin: 0;
1651 padding: 0;
1652 display: flex;
1653 flex-direction: column;
1654 align-items: stretch;
1655 }
1656 body.chat.chat-only-mode #chat-input-area {
1657 /* would like to pin this to the top so that it stays in place when
1658 scrolling, but doing so causes #chat-messages-wrapper to scroll
1659 behind it visibly, which is really ugly. Only current workaround is
1660 to force an opaque background color on this element, but that's not
1661 skin-friendly. */
1662 position: sticky;
1663 position: -webkit-sticky /* supposedly some versions of Safari */;
1664 top: 0;
1665 padding: 0.5em 1em;
1666 z-index: 100
1667 /* see notes in #chat-messages-wrapper. The various popups require a
1668 z-index higher than this one. */
1669 }
1670 body.chat.chat-only-mode #chat-messages-wrapper {
1671 position: relative;
1672 top: 0;
1673 z-index: 99 /* so that it scrolls under input area. If it's
1674 lower than div.content then mouse events to it
1675 are blocked!*/;
1676 }
1677 /* Wrapper for /chat user input controls */
1678 body.chat #chat-input-area {
1679 display: flex;
1680 flex-direction: column;
1681 border-bottom: 1px solid black;
 
1682 margin-bottom: 0.5em;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1683 }
1684 body.chat #chat-input-line {
1685 display: flex;
1686 flex-direction: row;
1687 margin-bottom: 0.25em;
1688
--- src/default.css
+++ src/default.css
@@ -1597,10 +1597,14 @@
1597 .settings-icon:hover {
1598 border: 1px outset rgba(127,127,127,1);
1599 }
1600 body.fossil-dark-style .settings-icon {
1601 filter: invert(100%);
1602 }
1603 /* "Chat-only mode" hides the site header/footer, showing only
1604 the chat app. */
1605 body.chat.chat-only-mode{
1606 }
1607 body.chat #chat-settings-button {
1608 }
1609 /** Popup widget for the /chat settings. */
1610 body.chat .chat-settings-popup {
@@ -1640,48 +1644,49 @@
1644 /** Container for the list of /chat messages. */
1645 body.chat #chat-messages-wrapper {
1646 display: flex;
1647 flex-direction: column;
1648 }
1649 body.chat.chat-only-mode #chat-messages-wrapper {
1650 flex-direction: column-reverse;
1651 position: relative;
1652 top: 0;
1653 z-index: 99 /* so that it scrolls under input area. If it's
1654 lower than div.content then mouse events to it
1655 are blocked!*/;
1656 }
1657 body.chat.chat-only-mode > div.content {
1658 margin: 0;
1659 padding: 0;
1660 display: flex;
1661 flex-direction: column;
1662 align-items: stretch;
1663 }
1664 body.chat.chat-only-mode > div.content {
1665 flex-direction: column-reverse;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1666 }
1667 /* Wrapper for /chat user input controls */
1668 body.chat #chat-input-area {
1669 display: flex;
1670 flex-direction: column;
1671 border-bottom: 1px solid black;
1672 padding: 0.5em 1em;
1673 margin-bottom: 0.5em;
1674 /*position: sticky; top: 0;*/
1675 /*position: -webkit-sticky*/ /* supposedly some versions of Safari */;
1676 }
1677 body.chat.chat-only-mode #chat-input-area {
1678 z-index: 100
1679 /* see notes in #chat-messages-wrapper. The various popups require a
1680 z-index higher than this one. */;
1681 border-bottom: none;
1682 border-top: 1px solid black;
1683 margin-bottom: 0;
1684 margin-top: 0.5em;
1685 position: sticky;
1686 position: -webkit-sticky/* supposedly some versions of Safari */;
1687 bottom: 0;
1688 }
1689 body.chat #chat-input-line {
1690 display: flex;
1691 flex-direction: row;
1692 margin-bottom: 0.25em;
1693

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button