instbyte 1.9.3 → 1.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -651,6 +651,38 @@ input[type=text]:focus {
651
651
  padding-left: 20px;
652
652
  }
653
653
 
654
+ .item-text-collapsed {
655
+ position: relative;
656
+ max-height: 9em;
657
+ overflow: hidden;
658
+ }
659
+
660
+ .item-text-collapsed::after {
661
+ content: "";
662
+ position: absolute;
663
+ bottom: 0;
664
+ left: 0;
665
+ right: 0;
666
+ height: 3em;
667
+ background: linear-gradient(to bottom, transparent, #ffffff);
668
+ pointer-events: none;
669
+ }
670
+
671
+ .item-text-expand-btn {
672
+ display: block;
673
+ margin-top: 4px;
674
+ font-size: 12px;
675
+ color: var(--color-secondary);
676
+ background: none;
677
+ border: none;
678
+ padding: 2px 0;
679
+ cursor: pointer;
680
+ text-align: left;
681
+ }
682
+
683
+ .item-text-expand-btn:hover {
684
+ color: var(--color-primary);
685
+ }
654
686
 
655
687
  /* ============================================================
656
688
  PREVIEW PANEL
@@ -1047,6 +1079,264 @@ input[type=text]:focus {
1047
1079
  transition: background 1.5s ease, border-color 1.5s ease;
1048
1080
  }
1049
1081
 
1082
+ /* ============================================================
1083
+ BROADCAST
1084
+ ============================================================ */
1085
+
1086
+ /* Bar — sits below header, visible to all when live */
1087
+ .broadcast-bar {
1088
+ background: #111827;
1089
+ color: #fff;
1090
+ padding: 8px 20px;
1091
+ position: sticky;
1092
+ top: 0;
1093
+ z-index: 100;
1094
+ border-bottom: 1px solid #1f2937;
1095
+ }
1096
+
1097
+ .broadcast-bar-inner {
1098
+ max-width: 900px;
1099
+ margin: 0 auto;
1100
+ display: flex;
1101
+ align-items: center;
1102
+ gap: 10px;
1103
+ }
1104
+
1105
+ .broadcast-pulse {
1106
+ display: inline-block;
1107
+ width: 8px;
1108
+ height: 8px;
1109
+ background: #ef4444;
1110
+ border-radius: 50%;
1111
+ flex-shrink: 0;
1112
+ animation: broadcastPulse 1.5s ease-in-out infinite;
1113
+ }
1114
+
1115
+ @keyframes broadcastPulse {
1116
+
1117
+ 0%,
1118
+ 100% {
1119
+ opacity: 1;
1120
+ transform: scale(1);
1121
+ }
1122
+
1123
+ 50% {
1124
+ opacity: 0.4;
1125
+ transform: scale(0.85);
1126
+ }
1127
+ }
1128
+
1129
+ #broadcastLabel {
1130
+ font-size: 13px;
1131
+ font-weight: 500;
1132
+ flex: 1;
1133
+ }
1134
+
1135
+ .broadcast-viewers {
1136
+ font-size: 12px;
1137
+ color: #9ca3af;
1138
+ }
1139
+
1140
+ .broadcast-bar-actions {
1141
+ display: flex;
1142
+ gap: 8px;
1143
+ }
1144
+
1145
+ .broadcast-join-btn {
1146
+ background: #2563eb;
1147
+ color: #fff;
1148
+ border: none;
1149
+ border-radius: 6px;
1150
+ padding: 5px 14px;
1151
+ font-size: 13px;
1152
+ cursor: pointer;
1153
+ }
1154
+
1155
+ .broadcast-join-btn:hover {
1156
+ background: #1d4ed8;
1157
+ }
1158
+
1159
+ .broadcast-end-btn {
1160
+ background: #ef4444;
1161
+ color: #fff;
1162
+ border: none;
1163
+ border-radius: 6px;
1164
+ padding: 5px 14px;
1165
+ font-size: 13px;
1166
+ cursor: pointer;
1167
+ }
1168
+
1169
+ .broadcast-end-btn:hover {
1170
+ background: #dc2626;
1171
+ }
1172
+
1173
+ /* Start button in composer */
1174
+ .broadcast-start-btn {
1175
+ background: #374151;
1176
+ color: #fff;
1177
+ border: none;
1178
+ border-radius: 6px;
1179
+ padding: 10px 14px;
1180
+ font-size: 13px;
1181
+ cursor: pointer;
1182
+ white-space: nowrap;
1183
+ }
1184
+
1185
+ .broadcast-start-btn:hover {
1186
+ background: #4b5563;
1187
+ }
1188
+
1189
+ .broadcast-start-btn.is-live {
1190
+ background: #ef4444;
1191
+ }
1192
+
1193
+ .broadcast-start-btn.is-live:hover {
1194
+ background: #dc2626;
1195
+ }
1196
+
1197
+ /* ─── VIEWER PANEL ─────────────────────────────────────────── */
1198
+
1199
+ .viewer-panel {
1200
+ position: fixed;
1201
+ top: 60px;
1202
+ right: 20px;
1203
+ width: 480px;
1204
+ max-width: calc(100vw - 40px);
1205
+ background: #fff;
1206
+ border: 1px solid #e5e7eb;
1207
+ border-radius: 12px;
1208
+ box-shadow: 0 8px 32px rgba(0, 0, 0, 0.15);
1209
+ z-index: 500;
1210
+ display: flex;
1211
+ flex-direction: column;
1212
+ overflow: auto;
1213
+ resize: both;
1214
+ min-width: 280px;
1215
+ min-height: 200px;
1216
+ }
1217
+
1218
+ .viewer-panel-header {
1219
+ display: flex;
1220
+ align-items: center;
1221
+ justify-content: space-between;
1222
+ padding: 10px 14px;
1223
+ background: #f9fafb;
1224
+ border-bottom: 1px solid #e5e7eb;
1225
+ flex-shrink: 0;
1226
+ cursor: grab;
1227
+ user-select: none;
1228
+ }
1229
+
1230
+ .viewer-panel-header:active {
1231
+ cursor: grabbing;
1232
+ }
1233
+
1234
+ .viewer-minimize-btn {
1235
+ background: #f3f4f6;
1236
+ border: 1px solid #e5e7eb;
1237
+ border-radius: 6px;
1238
+ padding: 4px 10px;
1239
+ font-size: 12px;
1240
+ cursor: pointer;
1241
+ color: #374151;
1242
+ }
1243
+
1244
+ .viewer-minimize-btn:hover {
1245
+ background: #fef9c3;
1246
+ border-color: #fde68a;
1247
+ color: #92400e;
1248
+ }
1249
+
1250
+ .viewer-panel.minimized .viewer-frame,
1251
+ .viewer-panel.minimized .viewer-panel-actions .viewer-capture-btn,
1252
+ .viewer-panel.minimized .viewer-panel-actions .viewer-raise-btn,
1253
+ .viewer-panel.minimized .viewer-panel-actions .viewer-close-btn {
1254
+ display: none;
1255
+ }
1256
+
1257
+ .viewer-panel.minimized {
1258
+ min-height: unset;
1259
+ resize: none;
1260
+ }
1261
+
1262
+ #viewerLabel {
1263
+ font-size: 13px;
1264
+ font-weight: 600;
1265
+ color: #111827;
1266
+ }
1267
+
1268
+ .viewer-panel-actions {
1269
+ display: flex;
1270
+ gap: 6px;
1271
+ }
1272
+
1273
+ .viewer-capture-btn,
1274
+ .viewer-raise-btn,
1275
+ .viewer-close-btn {
1276
+ background: #f3f4f6;
1277
+ border: 1px solid #e5e7eb;
1278
+ border-radius: 6px;
1279
+ padding: 4px 10px;
1280
+ font-size: 12px;
1281
+ cursor: pointer;
1282
+ color: #374151;
1283
+ }
1284
+
1285
+ .viewer-capture-btn:hover {
1286
+ background: #dbeafe;
1287
+ border-color: #bfdbfe;
1288
+ color: #1d4ed8;
1289
+ }
1290
+
1291
+ .viewer-raise-btn:hover {
1292
+ background: #fef9c3;
1293
+ border-color: #fde68a;
1294
+ color: #92400e;
1295
+ }
1296
+
1297
+ .viewer-close-btn:hover {
1298
+ background: #fee2e2;
1299
+ border-color: #fecaca;
1300
+ color: #b91c1c;
1301
+ }
1302
+
1303
+ .viewer-frame {
1304
+ width: 100%;
1305
+ display: block;
1306
+ background: #0f1117;
1307
+ min-height: 180px;
1308
+ object-fit: contain;
1309
+ }
1310
+
1311
+ /* ─── RAISE HAND TOAST ─────────────────────────────────────── */
1312
+
1313
+ .raise-hand-toast {
1314
+ position: fixed;
1315
+ bottom: 80px;
1316
+ left: 50%;
1317
+ transform: translateX(-50%);
1318
+ background: #111827;
1319
+ color: #fff;
1320
+ padding: 8px 16px;
1321
+ border-radius: 20px;
1322
+ font-size: 13px;
1323
+ z-index: 9999;
1324
+ pointer-events: none;
1325
+ animation: raiseHandIn 0.2s ease;
1326
+ }
1327
+
1328
+ @keyframes raiseHandIn {
1329
+ from {
1330
+ opacity: 0;
1331
+ transform: translateX(-50%) translateY(8px);
1332
+ }
1333
+
1334
+ to {
1335
+ opacity: 1;
1336
+ transform: translateX(-50%) translateY(0);
1337
+ }
1338
+ }
1339
+
1050
1340
  /* ============================================================
1051
1341
  MOBILE
1052
1342
  ============================================================ */
@@ -1174,6 +1464,152 @@ input[type=text]:focus {
1174
1464
  padding: 6px 12px;
1175
1465
  font-size: 12px;
1176
1466
  }
1467
+
1468
+ /* Backdrop */
1469
+ .bottom-sheet-backdrop {
1470
+ position: fixed;
1471
+ inset: 0;
1472
+ background: rgba(0, 0, 0, 0.4);
1473
+ z-index: 9998;
1474
+ display: none;
1475
+ animation: fadeInBackdrop 0.2s ease;
1476
+ }
1477
+
1478
+ .bottom-sheet-backdrop.open {
1479
+ display: block;
1480
+ }
1481
+
1482
+ @keyframes fadeInBackdrop {
1483
+ from {
1484
+ opacity: 0;
1485
+ }
1486
+
1487
+ to {
1488
+ opacity: 1;
1489
+ }
1490
+ }
1491
+
1492
+ /* Context menu becomes a bottom sheet */
1493
+ .context-menu {
1494
+ position: fixed;
1495
+ top: auto !important;
1496
+ left: 0 !important;
1497
+ right: 0;
1498
+ bottom: 0;
1499
+ width: 100%;
1500
+ max-width: 100%;
1501
+ border-radius: 16px 16px 0 0;
1502
+ padding: 8px 0 calc(8px + env(safe-area-inset-bottom));
1503
+ z-index: 9999;
1504
+ animation: slideUpSheet 0.25s ease;
1505
+ box-sizing: border-box;
1506
+ }
1507
+
1508
+ /* Drag handle */
1509
+ .context-menu::before {
1510
+ content: "";
1511
+ display: block;
1512
+ width: 36px;
1513
+ height: 4px;
1514
+ background: #d1d5db;
1515
+ border-radius: 2px;
1516
+ margin: 0 auto 10px;
1517
+ }
1518
+
1519
+ .context-menu button {
1520
+ padding: 14px 20px;
1521
+ font-size: 15px;
1522
+ border-radius: 0;
1523
+ }
1524
+
1525
+ /* Move dropdown becomes a bottom sheet */
1526
+ .move-dropdown {
1527
+ position: fixed !important;
1528
+ top: auto !important;
1529
+ bottom: 0 !important;
1530
+ left: 0 !important;
1531
+ right: 0 !important;
1532
+ width: 100% !important;
1533
+ min-width: 100% !important;
1534
+ border-radius: 16px 16px 0 0;
1535
+ padding: 8px 0 calc(8px + env(safe-area-inset-bottom));
1536
+ z-index: 9999;
1537
+ animation: slideUpSheet 0.25s ease;
1538
+ box-sizing: border-box;
1539
+ }
1540
+
1541
+ .move-dropdown::before {
1542
+ content: "";
1543
+ display: block;
1544
+ width: 36px;
1545
+ height: 4px;
1546
+ background: #d1d5db;
1547
+ border-radius: 2px;
1548
+ margin: 0 auto 10px;
1549
+ }
1550
+
1551
+ .move-dropdown button {
1552
+ padding: 14px 20px;
1553
+ font-size: 15px;
1554
+ border-radius: 0;
1555
+ }
1556
+
1557
+ .move-dropdown .dropdown-label {
1558
+ padding: 8px 20px 6px;
1559
+ font-size: 12px;
1560
+ }
1561
+
1562
+ .preview-panel pre {
1563
+ overflow-x: scroll;
1564
+ -webkit-overflow-scrolling: touch;
1565
+ max-height: 300px;
1566
+ font-size: 11px;
1567
+ }
1568
+
1569
+ .markdown-body pre {
1570
+ overflow-x: scroll;
1571
+ -webkit-overflow-scrolling: touch;
1572
+ }
1573
+
1574
+ @keyframes slideUpSheet {
1575
+ from {
1576
+ transform: translateY(100%);
1577
+ }
1578
+
1579
+ to {
1580
+ transform: translateY(0);
1581
+ }
1582
+ }
1583
+
1584
+ .broadcast-bar {
1585
+ padding: 8px 12px;
1586
+ }
1587
+
1588
+ .broadcast-bar-inner {
1589
+ gap: 8px;
1590
+ }
1591
+
1592
+ #broadcastLabel {
1593
+ font-size: 12px;
1594
+ }
1595
+
1596
+ .broadcast-start-btn {
1597
+ display: none;
1598
+ }
1599
+
1600
+ .viewer-panel {
1601
+ position: fixed;
1602
+ top: auto;
1603
+ bottom: 0;
1604
+ left: 0;
1605
+ right: 0;
1606
+ width: 100%;
1607
+ max-width: 100%;
1608
+ border-radius: 16px 16px 0 0;
1609
+ resize: none;
1610
+ max-height: 85vh;
1611
+ }
1612
+
1177
1613
  }
1178
1614
 
1179
1615
 
@@ -1572,10 +2008,53 @@ input[type=text]:focus {
1572
2008
  background: #052e16;
1573
2009
  }
1574
2010
 
2011
+ .item-text-collapsed::after {
2012
+ background: linear-gradient(to bottom, transparent, #1e2433);
2013
+ }
2014
+
1575
2015
  #uploadStatus {
1576
2016
  background: #1a1d27 !important;
1577
2017
  color: #e5e7eb !important;
1578
2018
  }
2019
+
2020
+ .broadcast-bar {
2021
+ background: #0f1117;
2022
+ border-bottom-color: #1f2937;
2023
+ }
2024
+
2025
+ .broadcast-start-btn {
2026
+ background: #1f2937;
2027
+ }
2028
+
2029
+ .broadcast-start-btn:hover {
2030
+ background: #374151;
2031
+ }
2032
+
2033
+ .viewer-panel {
2034
+ background: #1e2433;
2035
+ border-color: #2d3748;
2036
+ }
2037
+
2038
+ .viewer-panel-header {
2039
+ background: #161b27;
2040
+ border-bottom-color: #2d3748;
2041
+ }
2042
+
2043
+ #viewerLabel {
2044
+ color: #f9fafb;
2045
+ }
2046
+
2047
+ .viewer-capture-btn,
2048
+ .viewer-raise-btn,
2049
+ .viewer-close-btn {
2050
+ background: #2d3748;
2051
+ border-color: #374151;
2052
+ color: #d1d5db;
2053
+ }
2054
+
2055
+ .raise-hand-toast {
2056
+ background: #1f2937;
2057
+ }
1579
2058
  }
1580
2059
  }
1581
2060
 
@@ -1966,8 +2445,51 @@ input[type=text]:focus {
1966
2445
  background: #052e16;
1967
2446
  }
1968
2447
 
2448
+ .item-text-collapsed::after {
2449
+ background: linear-gradient(to bottom, transparent, #1e2433);
2450
+ }
2451
+
1969
2452
  #uploadStatus {
1970
2453
  background: #1a1d27 !important;
1971
2454
  color: #e5e7eb !important;
1972
2455
  }
2456
+
2457
+ .broadcast-bar {
2458
+ background: #0f1117;
2459
+ border-bottom-color: #1f2937;
2460
+ }
2461
+
2462
+ .broadcast-start-btn {
2463
+ background: #1f2937;
2464
+ }
2465
+
2466
+ .broadcast-start-btn:hover {
2467
+ background: #374151;
2468
+ }
2469
+
2470
+ .viewer-panel {
2471
+ background: #1e2433;
2472
+ border-color: #2d3748;
2473
+ }
2474
+
2475
+ .viewer-panel-header {
2476
+ background: #161b27;
2477
+ border-bottom-color: #2d3748;
2478
+ }
2479
+
2480
+ #viewerLabel {
2481
+ color: #f9fafb;
2482
+ }
2483
+
2484
+ .viewer-capture-btn,
2485
+ .viewer-raise-btn,
2486
+ .viewer-close-btn {
2487
+ background: #2d3748;
2488
+ border-color: #374151;
2489
+ color: #d1d5db;
2490
+ }
2491
+
2492
+ .raise-hand-toast {
2493
+ background: #1f2937;
2494
+ }
1973
2495
  }
package/client/index.html CHANGED
@@ -5,6 +5,8 @@
5
5
  <title>Instbyte</title>
6
6
  <link rel="icon" type="image/png" sizes="32x32" href="/favicon-dynamic.png">
7
7
  <link rel="icon" type="image/png" sizes="16x16" href="/favicon-dynamic.png">
8
+ <link rel="manifest" href="/manifest.json">
9
+ <meta name="theme-color" id="themeColorMeta" content="#111827">
8
10
  <meta name="viewport" content="width=device-width,initial-scale=1">
9
11
 
10
12
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/github.min.css">
@@ -35,6 +37,34 @@
35
37
  </div>
36
38
  </header>
37
39
 
40
+ <div id="broadcastBar" class="broadcast-bar" style="display:none">
41
+ <div class="broadcast-bar-inner">
42
+ <span class="broadcast-pulse"></span>
43
+ <span id="broadcastLabel">Someone is broadcasting</span>
44
+ <span id="broadcastViewers" class="broadcast-viewers"></span>
45
+ <div class="broadcast-bar-actions">
46
+ <button id="broadcastJoinBtn" class="broadcast-join-btn" onclick="joinBroadcast()">Join</button>
47
+ <button id="broadcastEndBtn" class="broadcast-end-btn" onclick="stopBroadcast()" style="display:none">End
48
+ broadcast</button>
49
+ </div>
50
+ </div>
51
+ </div>
52
+
53
+ <div id="viewerPanel" class="viewer-panel" style="display:none">
54
+ <div class="viewer-panel-header">
55
+ <span id="viewerLabel">Broadcast</span>
56
+ <div class="viewer-panel-actions">
57
+ <button onclick="captureToChannel()" class="viewer-capture-btn" title="Save frame to channel">📸
58
+ Capture</button>
59
+ <button onclick="raiseHand()" class="viewer-raise-btn" title="Raise hand">✋</button>
60
+ <button onclick="toggleAudio()" class="viewer-audio-btn" id="audioToggleBtn" title="Unmute audio">🔇</button>
61
+ <button onclick="toggleMinimize()" class="viewer-minimize-btn" title="Minimize">─</button>
62
+ <button onclick="leaveBroadcast()" class="viewer-close-btn" title="Leave broadcast">✕</button>
63
+ </div>
64
+ </div>
65
+ <video id="viewerFrame" class="viewer-frame" autoplay playsinline muted></video>
66
+ </div>
67
+
38
68
  <div class="container">
39
69
  <div class="channel-bar">
40
70
  <div class="channels" id="channels"></div>
@@ -47,6 +77,9 @@
47
77
  <button onclick="sendText()">Send</button>
48
78
  <input type="file" id="fileInput" hidden multiple>
49
79
  <button onclick="fileInput.click()">Upload</button>
80
+ <button id="startBroadcastBtn" onclick="startBroadcast()" class="broadcast-start-btn"
81
+ title="Start broadcasting your screen">📡 Broadcast</button>
82
+
50
83
  </div>
51
84
  <div class="drop" id="drop">Drag files anywhere to upload</div>
52
85
  <div id="uploadStatus"
@@ -89,7 +122,11 @@
89
122
  <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js"></script>
90
123
  <script src="/js/app.js?v=1.9.1.2"></script>
91
124
 
92
-
125
+ <script>
126
+ if ('serviceWorker' in navigator) {
127
+ navigator.serviceWorker.register('/sw.js').catch(() => { });
128
+ }
129
+ </script>
93
130
  </body>
94
131
 
95
132
  </html>