Fossil SCM

Split ctrl-enter/enter input modes and combat/spacious layout to two independent settings.

stephan 2021-09-30 03:14 chat-input-rework
Commit a83defad3a950b159631c275262624d5f6c94298658dbe55323776a0f673f07e
--- src/fossil.page.chat.js
+++ src/fossil.page.chat.js
@@ -375,11 +375,12 @@
375375
if(ev.detail.key===setting) f(ev.detail);
376376
}, false);
377377
},
378378
defaults:{
379379
"images-inline": !!F.config.chat.imagesInline,
380
- "edit-multiline": false,
380
+ "edit-ctrl-send": false,
381
+ "edit-compact-mode": true,
381382
"monospace-messages": false,
382383
"chat-only-mode": false,
383384
"audible-alert": true,
384385
"active-user-list": false,
385386
"active-user-list-timestamps": false
@@ -1044,20 +1045,21 @@
10441045
};
10451046
/** Updates the paste/drop zone with details of the pasted/dropped
10461047
data. The argument must be a Blob or Blob-like object (File) or
10471048
it can be falsy to reset/clear that state.*/
10481049
const updateDropZoneContent = function(blob){
1050
+ console.debug("updateDropZoneContent()",blob);
10491051
const dd = bxs.dropDetails;
10501052
bxs.blob = blob;
10511053
D.clearElement(dd);
10521054
if(!blob){
10531055
Chat.e.inputFile.value = '';
10541056
return;
10551057
}
10561058
D.append(dd, "Name: ", blob.name,
10571059
D.br(), "Size: ",blob.size);
1058
- if(blob.type && blob.type.startsWith("image/")){
1060
+ if(blob.type && (blob.type.startsWith("image/") || blob.type==='BITMAP')){
10591061
const img = D.img();
10601062
D.append(dd, D.br(), img);
10611063
const reader = new FileReader();
10621064
reader.onload = (e)=>img.setAttribute('src', e.target.result);
10631065
reader.readAsDataURL(blob);
@@ -1070,19 +1072,39 @@
10701072
updateDropZoneContent(this.files && this.files[0] ? this.files[0] : undefined)
10711073
});
10721074
/* Handle image paste from clipboard. TODO: figure out how we can
10731075
paste non-image binary data as if it had been selected via the
10741076
file selection element. */
1075
- document.addEventListener('paste', function(event){
1077
+ const pasteListener = function(event){
10761078
const items = event.clipboardData.items,
10771079
item = items[0];
1078
- if(!item || !item.type) return;
1079
- else if('file'===item.kind){
1080
+ //console.debug("paste event",event.target,item,event);
1081
+ //console.debug("paste event item",item);
1082
+ if(item && item.type && ('file'===item.kind || 'BITMAP'===item.type)){
10801083
updateDropZoneContent(false/*clear prev state*/);
10811084
updateDropZoneContent(item.getAsFile());
1085
+ event.stopPropagation();
1086
+ event.preventDefault(true);
1087
+ return false;
10821088
}
1083
- }, false);
1089
+ /* else continue propagating */
1090
+ };
1091
+ document.addEventListener('paste', pasteListener, true);
1092
+ if(0){
1093
+ const onPastePlainText = function(ev){
1094
+ var pastedText = undefined;
1095
+ if (window.clipboardData && window.clipboardData.getData) { // IE
1096
+ pastedText = window.clipboardData.getData('Text');
1097
+ }else if (ev.clipboardData && ev.clipboardData.getData) {
1098
+ pastedText = ev.clipboardData.getData('text/plain');
1099
+ }
1100
+ ev.target.textContent += pastedText;
1101
+ ev.preventDefault();
1102
+ return false;
1103
+ };
1104
+ Chat.e.inputField.addEventListener('paste', onPastePlainText, false);
1105
+ }
10841106
/* Add help button for drag/drop/paste zone */
10851107
Chat.e.inputFile.parentNode.insertBefore(
10861108
F.helpButtonlets.create(
10871109
Chat.e.fileSelectWrapper.querySelector('.help-buttonlet')
10881110
), Chat.e.inputFile
@@ -1170,36 +1192,45 @@
11701192
BlobXferState.clear();
11711193
Chat.inputValue("").inputFocus();
11721194
};
11731195
11741196
const inputWidgetKeydown = function f(ev){
1175
- if(!f.$toggle){
1176
- f.$toggle = function(currentMode){
1197
+ if(!f.$toggleCtrl){
1198
+ f.$toggleCtrl = function(currentMode){
1199
+ currentMode = !currentMode;
1200
+ Chat.settings.set('edit-ctrl-send', currentMode);
1201
+ };
1202
+ f.$toggleCompact = function(currentMode){
11771203
currentMode = !currentMode;
1178
- Chat.settings.set('edit-multiline', currentMode);
1204
+ Chat.settings.set('edit-compact-mode', currentMode);
11791205
};
11801206
}
11811207
if(13 === ev.keyCode){
1182
- const multi = Chat.settings.getBool('edit-multiline', false);
1208
+ const ctrlMode = Chat.settings.getBool('edit-ctrl-send', false);
11831209
if(ev.shiftKey){
1210
+ const compactMode = Chat.settings.getBool('edit-compact-mode', false);
11841211
ev.preventDefault();
11851212
ev.stopPropagation();
11861213
/* Shift-enter will run preview mode UNLESS preview mode is
11871214
active AND the input field is empty, in which case it will
11881215
switch back to message view. */
11891216
const text = Chat.inputValue().trim();
1190
- if(Chat.e.currentView===Chat.e.viewPreview && !text) Chat.setCurrentView(Chat.e.viewMessages);
1191
- else if(!text) f.$toggle(multi);
1217
+ if(Chat.e.currentView===Chat.e.viewPreview && !text){
1218
+ Chat.setCurrentView(Chat.e.viewMessages);
1219
+ }
1220
+ else if(!text){
1221
+ f.$toggleCompact(compactMode);
1222
+ }
11921223
else Chat.e.btnPreview.click();
11931224
return false;
1194
- }else if(!multi || (ev.ctrlKey && multi)){
1225
+ }else if(!ctrlMode || (ev.ctrlKey && ctrlMode)){
11951226
/* ^^^ note that it is intended that both ctrl-enter and enter
1196
- work for single-line input mode. */
1227
+ work for compact input mode. */
11971228
ev.preventDefault();
11981229
ev.stopPropagation();
11991230
const text = Chat.inputValue().trim();
1200
- if(!text) f.$toggle(multi);
1231
+ if(!text) f.$toggleCtrl(ctrlMode);
12011232
else Chat.submitMessage();
12021233
return false;
12031234
}
12041235
}
12051236
};
@@ -1277,17 +1308,22 @@
12771308
sync with external changes to that setting. Various Chat UI
12781309
elements stay in sync with the config UI via those settings
12791310
events.
12801311
*/
12811312
const settingsOps = [{
1282
- label: "Multi-line input",
1283
- hint: [
1284
- "When the input field is empty, Ctrl-Enter or Shift-Enter will toggle this.",
1285
- "In multi-line mode, Ctrl-Enter sends messages. In single-line mode, "
1286
- +"Enter or Ctrl-Enter sends messages."
1287
- ].join('\n'),
1288
- boolValue: 'edit-multiline'
1313
+ label: "Ctrl-enter to Send",
1314
+ hint: "When on, only Ctrl-Enter will send messages. "+
1315
+ "When off, both Enter and Ctrl-Enter send. "+
1316
+ "When the input field has focus, is empty, and preview "+
1317
+ "mode is NOT active then Ctrl-Enter toggles this setting.",
1318
+ boolValue: 'edit-ctrl-send'
1319
+ },{
1320
+ label: "Compact mode",
1321
+ hint: "Toggle between a space-saving and more spacious writing area. "+
1322
+ "When the input field has focus, is empty, and preview mode "+
1323
+ "is NOT active then Shift-Enter toggles this setting.",
1324
+ boolValue: 'edit-compact-mode'
12891325
},{
12901326
label: "Left-align my posts",
12911327
hint: "Default alignment of your own messages is selected "
12921328
+"based window width/height relationship.",
12931329
boolValue: ()=>!document.body.classList.contains('my-messages-right'),
@@ -1426,14 +1462,14 @@
14261462
Chat.showActiveUserTimestamps(s.value);
14271463
});
14281464
Chat.settings.addListener('chat-only-mode',function(s){
14291465
Chat.chatOnlyMode(s.value);
14301466
});
1431
- Chat.settings.addListener('edit-multiline',function(s){
1467
+ Chat.settings.addListener('edit-compact-mode',function(s){
14321468
Chat.e.inputLine.classList[
1433
- s.value ? 'remove' : 'add'
1434
- ]('single-line');
1469
+ s.value ? 'add' : 'remove'
1470
+ ]('compact');
14351471
});
14361472
const valueKludges = {
14371473
/* Convert certain string-format values to other types... */
14381474
"false": false,
14391475
"true": true
14401476
--- src/fossil.page.chat.js
+++ src/fossil.page.chat.js
@@ -375,11 +375,12 @@
375 if(ev.detail.key===setting) f(ev.detail);
376 }, false);
377 },
378 defaults:{
379 "images-inline": !!F.config.chat.imagesInline,
380 "edit-multiline": false,
 
381 "monospace-messages": false,
382 "chat-only-mode": false,
383 "audible-alert": true,
384 "active-user-list": false,
385 "active-user-list-timestamps": false
@@ -1044,20 +1045,21 @@
1044 };
1045 /** Updates the paste/drop zone with details of the pasted/dropped
1046 data. The argument must be a Blob or Blob-like object (File) or
1047 it can be falsy to reset/clear that state.*/
1048 const updateDropZoneContent = function(blob){
 
1049 const dd = bxs.dropDetails;
1050 bxs.blob = blob;
1051 D.clearElement(dd);
1052 if(!blob){
1053 Chat.e.inputFile.value = '';
1054 return;
1055 }
1056 D.append(dd, "Name: ", blob.name,
1057 D.br(), "Size: ",blob.size);
1058 if(blob.type && blob.type.startsWith("image/")){
1059 const img = D.img();
1060 D.append(dd, D.br(), img);
1061 const reader = new FileReader();
1062 reader.onload = (e)=>img.setAttribute('src', e.target.result);
1063 reader.readAsDataURL(blob);
@@ -1070,19 +1072,39 @@
1070 updateDropZoneContent(this.files && this.files[0] ? this.files[0] : undefined)
1071 });
1072 /* Handle image paste from clipboard. TODO: figure out how we can
1073 paste non-image binary data as if it had been selected via the
1074 file selection element. */
1075 document.addEventListener('paste', function(event){
1076 const items = event.clipboardData.items,
1077 item = items[0];
1078 if(!item || !item.type) return;
1079 else if('file'===item.kind){
 
1080 updateDropZoneContent(false/*clear prev state*/);
1081 updateDropZoneContent(item.getAsFile());
 
 
 
1082 }
1083 }, false);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1084 /* Add help button for drag/drop/paste zone */
1085 Chat.e.inputFile.parentNode.insertBefore(
1086 F.helpButtonlets.create(
1087 Chat.e.fileSelectWrapper.querySelector('.help-buttonlet')
1088 ), Chat.e.inputFile
@@ -1170,36 +1192,45 @@
1170 BlobXferState.clear();
1171 Chat.inputValue("").inputFocus();
1172 };
1173
1174 const inputWidgetKeydown = function f(ev){
1175 if(!f.$toggle){
1176 f.$toggle = function(currentMode){
 
 
 
 
1177 currentMode = !currentMode;
1178 Chat.settings.set('edit-multiline', currentMode);
1179 };
1180 }
1181 if(13 === ev.keyCode){
1182 const multi = Chat.settings.getBool('edit-multiline', false);
1183 if(ev.shiftKey){
 
1184 ev.preventDefault();
1185 ev.stopPropagation();
1186 /* Shift-enter will run preview mode UNLESS preview mode is
1187 active AND the input field is empty, in which case it will
1188 switch back to message view. */
1189 const text = Chat.inputValue().trim();
1190 if(Chat.e.currentView===Chat.e.viewPreview && !text) Chat.setCurrentView(Chat.e.viewMessages);
1191 else if(!text) f.$toggle(multi);
 
 
 
 
1192 else Chat.e.btnPreview.click();
1193 return false;
1194 }else if(!multi || (ev.ctrlKey && multi)){
1195 /* ^^^ note that it is intended that both ctrl-enter and enter
1196 work for single-line input mode. */
1197 ev.preventDefault();
1198 ev.stopPropagation();
1199 const text = Chat.inputValue().trim();
1200 if(!text) f.$toggle(multi);
1201 else Chat.submitMessage();
1202 return false;
1203 }
1204 }
1205 };
@@ -1277,17 +1308,22 @@
1277 sync with external changes to that setting. Various Chat UI
1278 elements stay in sync with the config UI via those settings
1279 events.
1280 */
1281 const settingsOps = [{
1282 label: "Multi-line input",
1283 hint: [
1284 "When the input field is empty, Ctrl-Enter or Shift-Enter will toggle this.",
1285 "In multi-line mode, Ctrl-Enter sends messages. In single-line mode, "
1286 +"Enter or Ctrl-Enter sends messages."
1287 ].join('\n'),
1288 boolValue: 'edit-multiline'
 
 
 
 
 
1289 },{
1290 label: "Left-align my posts",
1291 hint: "Default alignment of your own messages is selected "
1292 +"based window width/height relationship.",
1293 boolValue: ()=>!document.body.classList.contains('my-messages-right'),
@@ -1426,14 +1462,14 @@
1426 Chat.showActiveUserTimestamps(s.value);
1427 });
1428 Chat.settings.addListener('chat-only-mode',function(s){
1429 Chat.chatOnlyMode(s.value);
1430 });
1431 Chat.settings.addListener('edit-multiline',function(s){
1432 Chat.e.inputLine.classList[
1433 s.value ? 'remove' : 'add'
1434 ]('single-line');
1435 });
1436 const valueKludges = {
1437 /* Convert certain string-format values to other types... */
1438 "false": false,
1439 "true": true
1440
--- src/fossil.page.chat.js
+++ src/fossil.page.chat.js
@@ -375,11 +375,12 @@
375 if(ev.detail.key===setting) f(ev.detail);
376 }, false);
377 },
378 defaults:{
379 "images-inline": !!F.config.chat.imagesInline,
380 "edit-ctrl-send": false,
381 "edit-compact-mode": true,
382 "monospace-messages": false,
383 "chat-only-mode": false,
384 "audible-alert": true,
385 "active-user-list": false,
386 "active-user-list-timestamps": false
@@ -1044,20 +1045,21 @@
1045 };
1046 /** Updates the paste/drop zone with details of the pasted/dropped
1047 data. The argument must be a Blob or Blob-like object (File) or
1048 it can be falsy to reset/clear that state.*/
1049 const updateDropZoneContent = function(blob){
1050 console.debug("updateDropZoneContent()",blob);
1051 const dd = bxs.dropDetails;
1052 bxs.blob = blob;
1053 D.clearElement(dd);
1054 if(!blob){
1055 Chat.e.inputFile.value = '';
1056 return;
1057 }
1058 D.append(dd, "Name: ", blob.name,
1059 D.br(), "Size: ",blob.size);
1060 if(blob.type && (blob.type.startsWith("image/") || blob.type==='BITMAP')){
1061 const img = D.img();
1062 D.append(dd, D.br(), img);
1063 const reader = new FileReader();
1064 reader.onload = (e)=>img.setAttribute('src', e.target.result);
1065 reader.readAsDataURL(blob);
@@ -1070,19 +1072,39 @@
1072 updateDropZoneContent(this.files && this.files[0] ? this.files[0] : undefined)
1073 });
1074 /* Handle image paste from clipboard. TODO: figure out how we can
1075 paste non-image binary data as if it had been selected via the
1076 file selection element. */
1077 const pasteListener = function(event){
1078 const items = event.clipboardData.items,
1079 item = items[0];
1080 //console.debug("paste event",event.target,item,event);
1081 //console.debug("paste event item",item);
1082 if(item && item.type && ('file'===item.kind || 'BITMAP'===item.type)){
1083 updateDropZoneContent(false/*clear prev state*/);
1084 updateDropZoneContent(item.getAsFile());
1085 event.stopPropagation();
1086 event.preventDefault(true);
1087 return false;
1088 }
1089 /* else continue propagating */
1090 };
1091 document.addEventListener('paste', pasteListener, true);
1092 if(0){
1093 const onPastePlainText = function(ev){
1094 var pastedText = undefined;
1095 if (window.clipboardData && window.clipboardData.getData) { // IE
1096 pastedText = window.clipboardData.getData('Text');
1097 }else if (ev.clipboardData && ev.clipboardData.getData) {
1098 pastedText = ev.clipboardData.getData('text/plain');
1099 }
1100 ev.target.textContent += pastedText;
1101 ev.preventDefault();
1102 return false;
1103 };
1104 Chat.e.inputField.addEventListener('paste', onPastePlainText, false);
1105 }
1106 /* Add help button for drag/drop/paste zone */
1107 Chat.e.inputFile.parentNode.insertBefore(
1108 F.helpButtonlets.create(
1109 Chat.e.fileSelectWrapper.querySelector('.help-buttonlet')
1110 ), Chat.e.inputFile
@@ -1170,36 +1192,45 @@
1192 BlobXferState.clear();
1193 Chat.inputValue("").inputFocus();
1194 };
1195
1196 const inputWidgetKeydown = function f(ev){
1197 if(!f.$toggleCtrl){
1198 f.$toggleCtrl = function(currentMode){
1199 currentMode = !currentMode;
1200 Chat.settings.set('edit-ctrl-send', currentMode);
1201 };
1202 f.$toggleCompact = function(currentMode){
1203 currentMode = !currentMode;
1204 Chat.settings.set('edit-compact-mode', currentMode);
1205 };
1206 }
1207 if(13 === ev.keyCode){
1208 const ctrlMode = Chat.settings.getBool('edit-ctrl-send', false);
1209 if(ev.shiftKey){
1210 const compactMode = Chat.settings.getBool('edit-compact-mode', false);
1211 ev.preventDefault();
1212 ev.stopPropagation();
1213 /* Shift-enter will run preview mode UNLESS preview mode is
1214 active AND the input field is empty, in which case it will
1215 switch back to message view. */
1216 const text = Chat.inputValue().trim();
1217 if(Chat.e.currentView===Chat.e.viewPreview && !text){
1218 Chat.setCurrentView(Chat.e.viewMessages);
1219 }
1220 else if(!text){
1221 f.$toggleCompact(compactMode);
1222 }
1223 else Chat.e.btnPreview.click();
1224 return false;
1225 }else if(!ctrlMode || (ev.ctrlKey && ctrlMode)){
1226 /* ^^^ note that it is intended that both ctrl-enter and enter
1227 work for compact input mode. */
1228 ev.preventDefault();
1229 ev.stopPropagation();
1230 const text = Chat.inputValue().trim();
1231 if(!text) f.$toggleCtrl(ctrlMode);
1232 else Chat.submitMessage();
1233 return false;
1234 }
1235 }
1236 };
@@ -1277,17 +1308,22 @@
1308 sync with external changes to that setting. Various Chat UI
1309 elements stay in sync with the config UI via those settings
1310 events.
1311 */
1312 const settingsOps = [{
1313 label: "Ctrl-enter to Send",
1314 hint: "When on, only Ctrl-Enter will send messages. "+
1315 "When off, both Enter and Ctrl-Enter send. "+
1316 "When the input field has focus, is empty, and preview "+
1317 "mode is NOT active then Ctrl-Enter toggles this setting.",
1318 boolValue: 'edit-ctrl-send'
1319 },{
1320 label: "Compact mode",
1321 hint: "Toggle between a space-saving and more spacious writing area. "+
1322 "When the input field has focus, is empty, and preview mode "+
1323 "is NOT active then Shift-Enter toggles this setting.",
1324 boolValue: 'edit-compact-mode'
1325 },{
1326 label: "Left-align my posts",
1327 hint: "Default alignment of your own messages is selected "
1328 +"based window width/height relationship.",
1329 boolValue: ()=>!document.body.classList.contains('my-messages-right'),
@@ -1426,14 +1462,14 @@
1462 Chat.showActiveUserTimestamps(s.value);
1463 });
1464 Chat.settings.addListener('chat-only-mode',function(s){
1465 Chat.chatOnlyMode(s.value);
1466 });
1467 Chat.settings.addListener('edit-compact-mode',function(s){
1468 Chat.e.inputLine.classList[
1469 s.value ? 'add' : 'remove'
1470 ]('compact');
1471 });
1472 const valueKludges = {
1473 /* Convert certain string-format values to other types... */
1474 "false": false,
1475 "true": true
1476
--- src/style.chat.css
+++ src/style.chat.css
@@ -206,14 +206,14 @@
206206
display: flex;
207207
flex-direction: row;
208208
align-items: stretch;
209209
flex-wrap: nowrap;
210210
}
211
-/*body.chat #chat-input-line:not(.single-line) {
211
+/*body.chat #chat-input-line:not(.compact) {
212212
flex-wrap: nowrap;
213213
}*/
214
-body.chat #chat-input-line.single-line #chat-input-field {
214
+body.chat #chat-input-line.compact #chat-input-field {
215215
max-height: 2rem /*arbitrary*/;
216216
}
217217
218218
body.chat #chat-edit-buttons {
219219
flex: 1 1 auto;
@@ -221,31 +221,31 @@
221221
flex-direction: column;
222222
justify-content: space-between;
223223
min-width: 4em;
224224
min-height: 1.5em;
225225
}
226
-body.chat #chat-input-line.single-line #chat-edit-buttons {
226
+body.chat #chat-input-line.compact #chat-edit-buttons {
227227
flex-direction: row;
228228
margin-top: 0.25em;
229229
}
230230
body.chat #chat-edit-buttons > * {
231231
flex: 1 1 auto;
232232
padding: initial/*some skins mess this up for buttons*/;
233233
}
234
-body.chat #chat-input-line:not(.single-line) #chat-edit-buttons > * {
234
+body.chat #chat-input-line:not(.compact) #chat-edit-buttons > * {
235235
max-width: 4em;
236236
margin: 0.25em;
237237
min-height: 2em;
238238
}
239
-body.chat #chat-input-line:not(.single-line) #chat-input-field {
239
+body.chat #chat-input-line:not(.compact) #chat-input-field {
240240
/*border-left-style: double;
241241
border-left-width: 3px;
242242
border-right-style: double;
243243
border-right-width: 3px;*/
244244
}
245245
246
-body.chat #chat-input-line.single-line #chat-edit-buttons > * {
246
+body.chat #chat-input-line.compact #chat-edit-buttons > * {
247247
margin: 0 0.25em;
248248
min-width: 2em;
249249
}
250250
251251
body.chat #chat-input-line > button {
@@ -259,11 +259,11 @@
259259
body.chat #chat-input-line > textarea {
260260
flex: 20 1 auto;
261261
max-width: revert;
262262
min-width: 20em;
263263
}
264
-body.chat #chat-input-line.single-line > input[type=text] {
264
+body.chat #chat-input-line.compact > input[type=text] {
265265
margin: 0 0 0.25em 0/* gap for if/when buttons wrap*/;
266266
}
267267
/* Widget holding the file selection control and preview */
268268
body.chat #chat-input-file-area {
269269
display: flex;
270270
--- src/style.chat.css
+++ src/style.chat.css
@@ -206,14 +206,14 @@
206 display: flex;
207 flex-direction: row;
208 align-items: stretch;
209 flex-wrap: nowrap;
210 }
211 /*body.chat #chat-input-line:not(.single-line) {
212 flex-wrap: nowrap;
213 }*/
214 body.chat #chat-input-line.single-line #chat-input-field {
215 max-height: 2rem /*arbitrary*/;
216 }
217
218 body.chat #chat-edit-buttons {
219 flex: 1 1 auto;
@@ -221,31 +221,31 @@
221 flex-direction: column;
222 justify-content: space-between;
223 min-width: 4em;
224 min-height: 1.5em;
225 }
226 body.chat #chat-input-line.single-line #chat-edit-buttons {
227 flex-direction: row;
228 margin-top: 0.25em;
229 }
230 body.chat #chat-edit-buttons > * {
231 flex: 1 1 auto;
232 padding: initial/*some skins mess this up for buttons*/;
233 }
234 body.chat #chat-input-line:not(.single-line) #chat-edit-buttons > * {
235 max-width: 4em;
236 margin: 0.25em;
237 min-height: 2em;
238 }
239 body.chat #chat-input-line:not(.single-line) #chat-input-field {
240 /*border-left-style: double;
241 border-left-width: 3px;
242 border-right-style: double;
243 border-right-width: 3px;*/
244 }
245
246 body.chat #chat-input-line.single-line #chat-edit-buttons > * {
247 margin: 0 0.25em;
248 min-width: 2em;
249 }
250
251 body.chat #chat-input-line > button {
@@ -259,11 +259,11 @@
259 body.chat #chat-input-line > textarea {
260 flex: 20 1 auto;
261 max-width: revert;
262 min-width: 20em;
263 }
264 body.chat #chat-input-line.single-line > input[type=text] {
265 margin: 0 0 0.25em 0/* gap for if/when buttons wrap*/;
266 }
267 /* Widget holding the file selection control and preview */
268 body.chat #chat-input-file-area {
269 display: flex;
270
--- src/style.chat.css
+++ src/style.chat.css
@@ -206,14 +206,14 @@
206 display: flex;
207 flex-direction: row;
208 align-items: stretch;
209 flex-wrap: nowrap;
210 }
211 /*body.chat #chat-input-line:not(.compact) {
212 flex-wrap: nowrap;
213 }*/
214 body.chat #chat-input-line.compact #chat-input-field {
215 max-height: 2rem /*arbitrary*/;
216 }
217
218 body.chat #chat-edit-buttons {
219 flex: 1 1 auto;
@@ -221,31 +221,31 @@
221 flex-direction: column;
222 justify-content: space-between;
223 min-width: 4em;
224 min-height: 1.5em;
225 }
226 body.chat #chat-input-line.compact #chat-edit-buttons {
227 flex-direction: row;
228 margin-top: 0.25em;
229 }
230 body.chat #chat-edit-buttons > * {
231 flex: 1 1 auto;
232 padding: initial/*some skins mess this up for buttons*/;
233 }
234 body.chat #chat-input-line:not(.compact) #chat-edit-buttons > * {
235 max-width: 4em;
236 margin: 0.25em;
237 min-height: 2em;
238 }
239 body.chat #chat-input-line:not(.compact) #chat-input-field {
240 /*border-left-style: double;
241 border-left-width: 3px;
242 border-right-style: double;
243 border-right-width: 3px;*/
244 }
245
246 body.chat #chat-input-line.compact #chat-edit-buttons > * {
247 margin: 0 0.25em;
248 min-width: 2em;
249 }
250
251 body.chat #chat-input-line > button {
@@ -259,11 +259,11 @@
259 body.chat #chat-input-line > textarea {
260 flex: 20 1 auto;
261 max-width: revert;
262 min-width: 20em;
263 }
264 body.chat #chat-input-line.compact > input[type=text] {
265 margin: 0 0 0.25em 0/* gap for if/when buttons wrap*/;
266 }
267 /* Widget holding the file selection control and preview */
268 body.chat #chat-input-file-area {
269 display: flex;
270

Keyboard Shortcuts

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