treesap 0.1.9 → 0.1.11
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.
- package/dist/components/ChatInput.d.ts +7 -0
- package/dist/components/ChatInput.d.ts.map +1 -0
- package/dist/components/ChatInput.js +11 -0
- package/dist/components/ChatInput.js.map +1 -0
- package/dist/components/Sidebar.d.ts +8 -0
- package/dist/components/Sidebar.d.ts.map +1 -0
- package/dist/components/Sidebar.js +7 -0
- package/dist/components/Sidebar.js.map +1 -0
- package/dist/components/SimpleLivePreview.js +1 -1
- package/dist/components/SimpleLivePreview.js.map +1 -1
- package/dist/pages/Code.d.ts.map +1 -1
- package/dist/pages/Code.js +2 -2
- package/dist/pages/Code.js.map +1 -1
- package/dist/services/websocket.d.ts.map +1 -1
- package/dist/services/websocket.js +1 -2
- package/dist/services/websocket.js.map +1 -1
- package/dist/static/components/ChatInput.js +237 -0
- package/dist/static/components/Sidebar.js +225 -0
- package/dist/static/components/SimpleLivePreview.js +73 -53
- package/dist/static/components/Terminal.js +143 -61
- package/dist/static/signals/SidebarSignal.js +123 -0
- package/dist/static/signals/TerminalSignal.js +137 -2
- package/dist/static/styles/main.css +180 -0
- package/package.json +1 -1
- package/src/components/ChatInput.tsx +56 -0
- package/src/components/Sidebar.tsx +99 -0
- package/src/components/SimpleLivePreview.tsx +4 -4
- package/src/pages/Code.tsx +18 -55
- package/src/services/websocket.ts +1 -5
- package/src/static/components/ChatInput.js +237 -0
- package/src/static/components/Sidebar.js +225 -0
- package/src/static/components/SimpleLivePreview.js +73 -53
- package/src/static/components/Terminal.js +143 -61
- package/src/static/signals/SidebarSignal.js +123 -0
- package/src/static/signals/TerminalSignal.js +137 -2
- package/src/static/styles/main.css +180 -0
- package/tailwind.config.ts +10 -0
|
@@ -1093,6 +1093,10 @@ video {
|
|
|
1093
1093
|
margin-bottom: 0;
|
|
1094
1094
|
}
|
|
1095
1095
|
|
|
1096
|
+
.pointer-events-none {
|
|
1097
|
+
pointer-events: none;
|
|
1098
|
+
}
|
|
1099
|
+
|
|
1096
1100
|
.visible {
|
|
1097
1101
|
visibility: visible;
|
|
1098
1102
|
}
|
|
@@ -1101,6 +1105,10 @@ video {
|
|
|
1101
1105
|
position: static;
|
|
1102
1106
|
}
|
|
1103
1107
|
|
|
1108
|
+
.fixed {
|
|
1109
|
+
position: fixed;
|
|
1110
|
+
}
|
|
1111
|
+
|
|
1104
1112
|
.absolute {
|
|
1105
1113
|
position: absolute;
|
|
1106
1114
|
}
|
|
@@ -1109,10 +1117,38 @@ video {
|
|
|
1109
1117
|
position: relative;
|
|
1110
1118
|
}
|
|
1111
1119
|
|
|
1120
|
+
.inset-0 {
|
|
1121
|
+
inset: 0px;
|
|
1122
|
+
}
|
|
1123
|
+
|
|
1124
|
+
.left-0 {
|
|
1125
|
+
left: 0px;
|
|
1126
|
+
}
|
|
1127
|
+
|
|
1128
|
+
.left-4 {
|
|
1129
|
+
left: 1rem;
|
|
1130
|
+
}
|
|
1131
|
+
|
|
1132
|
+
.top-0 {
|
|
1133
|
+
top: 0px;
|
|
1134
|
+
}
|
|
1135
|
+
|
|
1136
|
+
.top-4 {
|
|
1137
|
+
top: 1rem;
|
|
1138
|
+
}
|
|
1139
|
+
|
|
1140
|
+
.z-40 {
|
|
1141
|
+
z-index: 40;
|
|
1142
|
+
}
|
|
1143
|
+
|
|
1112
1144
|
.z-50 {
|
|
1113
1145
|
z-index: 50;
|
|
1114
1146
|
}
|
|
1115
1147
|
|
|
1148
|
+
.z-60 {
|
|
1149
|
+
z-index: 60;
|
|
1150
|
+
}
|
|
1151
|
+
|
|
1116
1152
|
.mb-12 {
|
|
1117
1153
|
margin-bottom: 3rem;
|
|
1118
1154
|
}
|
|
@@ -1185,6 +1221,14 @@ video {
|
|
|
1185
1221
|
height: 100vh;
|
|
1186
1222
|
}
|
|
1187
1223
|
|
|
1224
|
+
.max-h-\[120px\] {
|
|
1225
|
+
max-height: 120px;
|
|
1226
|
+
}
|
|
1227
|
+
|
|
1228
|
+
.min-h-\[40px\] {
|
|
1229
|
+
min-height: 40px;
|
|
1230
|
+
}
|
|
1231
|
+
|
|
1188
1232
|
.min-h-screen {
|
|
1189
1233
|
min-height: 100vh;
|
|
1190
1234
|
}
|
|
@@ -1217,6 +1261,20 @@ video {
|
|
|
1217
1261
|
flex-shrink: 0;
|
|
1218
1262
|
}
|
|
1219
1263
|
|
|
1264
|
+
.-translate-x-full {
|
|
1265
|
+
--tw-translate-x: -100%;
|
|
1266
|
+
transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
|
|
1267
|
+
}
|
|
1268
|
+
|
|
1269
|
+
.translate-x-0 {
|
|
1270
|
+
--tw-translate-x: 0px;
|
|
1271
|
+
transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
|
|
1272
|
+
}
|
|
1273
|
+
|
|
1274
|
+
.transform {
|
|
1275
|
+
transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
|
|
1276
|
+
}
|
|
1277
|
+
|
|
1220
1278
|
@keyframes spin {
|
|
1221
1279
|
to {
|
|
1222
1280
|
transform: rotate(360deg);
|
|
@@ -1231,6 +1289,10 @@ video {
|
|
|
1231
1289
|
cursor: not-allowed;
|
|
1232
1290
|
}
|
|
1233
1291
|
|
|
1292
|
+
.resize-none {
|
|
1293
|
+
resize: none;
|
|
1294
|
+
}
|
|
1295
|
+
|
|
1234
1296
|
.resize {
|
|
1235
1297
|
resize: both;
|
|
1236
1298
|
}
|
|
@@ -1239,6 +1301,10 @@ video {
|
|
|
1239
1301
|
flex-direction: column;
|
|
1240
1302
|
}
|
|
1241
1303
|
|
|
1304
|
+
.items-end {
|
|
1305
|
+
align-items: flex-end;
|
|
1306
|
+
}
|
|
1307
|
+
|
|
1242
1308
|
.items-center {
|
|
1243
1309
|
align-items: center;
|
|
1244
1310
|
}
|
|
@@ -1296,6 +1362,10 @@ video {
|
|
|
1296
1362
|
border-right-width: 1px;
|
|
1297
1363
|
}
|
|
1298
1364
|
|
|
1365
|
+
.border-t {
|
|
1366
|
+
border-top-width: 1px;
|
|
1367
|
+
}
|
|
1368
|
+
|
|
1299
1369
|
.border-t-2 {
|
|
1300
1370
|
border-top-width: 2px;
|
|
1301
1371
|
}
|
|
@@ -1320,6 +1390,11 @@ video {
|
|
|
1320
1390
|
border-color: rgb(156 163 175 / var(--tw-border-opacity, 1));
|
|
1321
1391
|
}
|
|
1322
1392
|
|
|
1393
|
+
.bg-\[\#0e639c\] {
|
|
1394
|
+
--tw-bg-opacity: 1;
|
|
1395
|
+
background-color: rgb(14 99 156 / var(--tw-bg-opacity, 1));
|
|
1396
|
+
}
|
|
1397
|
+
|
|
1323
1398
|
.bg-\[\#1e1e1e\] {
|
|
1324
1399
|
--tw-bg-opacity: 1;
|
|
1325
1400
|
background-color: rgb(30 30 30 / var(--tw-bg-opacity, 1));
|
|
@@ -1330,6 +1405,11 @@ video {
|
|
|
1330
1405
|
background-color: rgb(37 37 38 / var(--tw-bg-opacity, 1));
|
|
1331
1406
|
}
|
|
1332
1407
|
|
|
1408
|
+
.bg-\[\#28a745\] {
|
|
1409
|
+
--tw-bg-opacity: 1;
|
|
1410
|
+
background-color: rgb(40 167 69 / var(--tw-bg-opacity, 1));
|
|
1411
|
+
}
|
|
1412
|
+
|
|
1333
1413
|
.bg-\[\#2a2a2a\] {
|
|
1334
1414
|
--tw-bg-opacity: 1;
|
|
1335
1415
|
background-color: rgb(42 42 42 / var(--tw-bg-opacity, 1));
|
|
@@ -1359,6 +1439,10 @@ video {
|
|
|
1359
1439
|
background-color: rgb(255 255 255 / var(--tw-bg-opacity, 1));
|
|
1360
1440
|
}
|
|
1361
1441
|
|
|
1442
|
+
.bg-opacity-50 {
|
|
1443
|
+
--tw-bg-opacity: 0.5;
|
|
1444
|
+
}
|
|
1445
|
+
|
|
1362
1446
|
.bg-gradient-to-br {
|
|
1363
1447
|
background-image: linear-gradient(to bottom right, var(--tw-gradient-stops));
|
|
1364
1448
|
}
|
|
@@ -1416,6 +1500,10 @@ video {
|
|
|
1416
1500
|
text-align: center;
|
|
1417
1501
|
}
|
|
1418
1502
|
|
|
1503
|
+
.font-mono {
|
|
1504
|
+
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
|
|
1505
|
+
}
|
|
1506
|
+
|
|
1419
1507
|
.font-sans {
|
|
1420
1508
|
font-family: ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
|
|
1421
1509
|
}
|
|
@@ -1491,6 +1579,24 @@ video {
|
|
|
1491
1579
|
color: rgb(255 255 255 / var(--tw-text-opacity, 1));
|
|
1492
1580
|
}
|
|
1493
1581
|
|
|
1582
|
+
.placeholder-\[\#888\]::-moz-placeholder {
|
|
1583
|
+
--tw-placeholder-opacity: 1;
|
|
1584
|
+
color: rgb(136 136 136 / var(--tw-placeholder-opacity, 1));
|
|
1585
|
+
}
|
|
1586
|
+
|
|
1587
|
+
.placeholder-\[\#888\]::placeholder {
|
|
1588
|
+
--tw-placeholder-opacity: 1;
|
|
1589
|
+
color: rgb(136 136 136 / var(--tw-placeholder-opacity, 1));
|
|
1590
|
+
}
|
|
1591
|
+
|
|
1592
|
+
.opacity-0 {
|
|
1593
|
+
opacity: 0;
|
|
1594
|
+
}
|
|
1595
|
+
|
|
1596
|
+
.opacity-100 {
|
|
1597
|
+
opacity: 1;
|
|
1598
|
+
}
|
|
1599
|
+
|
|
1494
1600
|
.opacity-50 {
|
|
1495
1601
|
opacity: 0.5;
|
|
1496
1602
|
}
|
|
@@ -1505,6 +1611,12 @@ video {
|
|
|
1505
1611
|
filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow);
|
|
1506
1612
|
}
|
|
1507
1613
|
|
|
1614
|
+
.backdrop-blur-sm {
|
|
1615
|
+
--tw-backdrop-blur: blur(4px);
|
|
1616
|
+
-webkit-backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia);
|
|
1617
|
+
backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia);
|
|
1618
|
+
}
|
|
1619
|
+
|
|
1508
1620
|
.transition-all {
|
|
1509
1621
|
transition-property: all;
|
|
1510
1622
|
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
|
|
@@ -1517,10 +1629,26 @@ video {
|
|
|
1517
1629
|
transition-duration: 150ms;
|
|
1518
1630
|
}
|
|
1519
1631
|
|
|
1632
|
+
.transition-opacity {
|
|
1633
|
+
transition-property: opacity;
|
|
1634
|
+
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
|
|
1635
|
+
transition-duration: 150ms;
|
|
1636
|
+
}
|
|
1637
|
+
|
|
1638
|
+
.transition-transform {
|
|
1639
|
+
transition-property: transform;
|
|
1640
|
+
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
|
|
1641
|
+
transition-duration: 150ms;
|
|
1642
|
+
}
|
|
1643
|
+
|
|
1520
1644
|
.duration-300 {
|
|
1521
1645
|
transition-duration: 300ms;
|
|
1522
1646
|
}
|
|
1523
1647
|
|
|
1648
|
+
.ease-in-out {
|
|
1649
|
+
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
|
|
1650
|
+
}
|
|
1651
|
+
|
|
1524
1652
|
.focus-within\:border-\[\#0e639c\]:focus-within {
|
|
1525
1653
|
--tw-border-opacity: 1;
|
|
1526
1654
|
border-color: rgb(14 99 156 / var(--tw-border-opacity, 1));
|
|
@@ -1531,6 +1659,16 @@ video {
|
|
|
1531
1659
|
border-color: rgb(14 99 156 / var(--tw-border-opacity, 1));
|
|
1532
1660
|
}
|
|
1533
1661
|
|
|
1662
|
+
.hover\:bg-\[\#1177bb\]:hover {
|
|
1663
|
+
--tw-bg-opacity: 1;
|
|
1664
|
+
background-color: rgb(17 119 187 / var(--tw-bg-opacity, 1));
|
|
1665
|
+
}
|
|
1666
|
+
|
|
1667
|
+
.hover\:bg-\[\#218838\]:hover {
|
|
1668
|
+
--tw-bg-opacity: 1;
|
|
1669
|
+
background-color: rgb(33 136 56 / var(--tw-bg-opacity, 1));
|
|
1670
|
+
}
|
|
1671
|
+
|
|
1534
1672
|
.hover\:bg-\[\#2d2d30\]:hover {
|
|
1535
1673
|
--tw-bg-opacity: 1;
|
|
1536
1674
|
background-color: rgb(45 45 48 / var(--tw-bg-opacity, 1));
|
|
@@ -1567,12 +1705,54 @@ video {
|
|
|
1567
1705
|
box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);
|
|
1568
1706
|
}
|
|
1569
1707
|
|
|
1708
|
+
.focus\:border-\[\#0e639c\]:focus {
|
|
1709
|
+
--tw-border-opacity: 1;
|
|
1710
|
+
border-color: rgb(14 99 156 / var(--tw-border-opacity, 1));
|
|
1711
|
+
}
|
|
1712
|
+
|
|
1570
1713
|
.focus\:outline-none:focus {
|
|
1571
1714
|
outline: 2px solid transparent;
|
|
1572
1715
|
outline-offset: 2px;
|
|
1573
1716
|
}
|
|
1574
1717
|
|
|
1718
|
+
.disabled\:bg-\[\#3c3c3c\]:disabled {
|
|
1719
|
+
--tw-bg-opacity: 1;
|
|
1720
|
+
background-color: rgb(60 60 60 / var(--tw-bg-opacity, 1));
|
|
1721
|
+
}
|
|
1722
|
+
|
|
1723
|
+
.disabled\:text-\[\#888\]:disabled {
|
|
1724
|
+
--tw-text-opacity: 1;
|
|
1725
|
+
color: rgb(136 136 136 / var(--tw-text-opacity, 1));
|
|
1726
|
+
}
|
|
1727
|
+
|
|
1575
1728
|
.group:hover .group-hover\:text-white {
|
|
1576
1729
|
--tw-text-opacity: 1;
|
|
1577
1730
|
color: rgb(255 255 255 / var(--tw-text-opacity, 1));
|
|
1578
1731
|
}
|
|
1732
|
+
|
|
1733
|
+
@media (min-width: 768px) {
|
|
1734
|
+
.md\:relative {
|
|
1735
|
+
position: relative;
|
|
1736
|
+
}
|
|
1737
|
+
|
|
1738
|
+
.md\:z-auto {
|
|
1739
|
+
z-index: auto;
|
|
1740
|
+
}
|
|
1741
|
+
|
|
1742
|
+
.md\:hidden {
|
|
1743
|
+
display: none;
|
|
1744
|
+
}
|
|
1745
|
+
|
|
1746
|
+
.md\:w-2\/5 {
|
|
1747
|
+
width: 40%;
|
|
1748
|
+
}
|
|
1749
|
+
|
|
1750
|
+
.md\:flex-1 {
|
|
1751
|
+
flex: 1 1 0%;
|
|
1752
|
+
}
|
|
1753
|
+
|
|
1754
|
+
.md\:translate-x-0 {
|
|
1755
|
+
--tw-translate-x: 0px;
|
|
1756
|
+
transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
|
|
1757
|
+
}
|
|
1758
|
+
}
|
package/package.json
CHANGED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
interface ChatInputProps {
|
|
2
|
+
id?: string;
|
|
3
|
+
terminalId?: string;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
export function ChatInput({ id = "chat-input", terminalId = "terminal-1" }: ChatInputProps) {
|
|
7
|
+
return (
|
|
8
|
+
<sapling-island loading="visible">
|
|
9
|
+
<template>
|
|
10
|
+
<script type="module" src="/components/ChatInput.js"></script>
|
|
11
|
+
</template>
|
|
12
|
+
|
|
13
|
+
<div id={id} class="border-t border-[#3c3c3c] bg-[#2d2d30] p-3">
|
|
14
|
+
<div class="flex items-end gap-2">
|
|
15
|
+
{/* Textarea for multi-line input */}
|
|
16
|
+
<div class="flex-1 relative">
|
|
17
|
+
<textarea
|
|
18
|
+
id={`${id}-textarea`}
|
|
19
|
+
placeholder="Type your command or message..."
|
|
20
|
+
class="w-full min-h-[40px] max-h-[120px] px-3 py-2 bg-[#1e1e1e] border border-[#3c3c3c] rounded-lg text-[#cccccc] placeholder-[#888] resize-none focus:outline-none focus:border-[#0e639c] transition-colors text-sm font-mono"
|
|
21
|
+
rows={1}
|
|
22
|
+
></textarea>
|
|
23
|
+
</div>
|
|
24
|
+
|
|
25
|
+
{/* Send to Input button */}
|
|
26
|
+
<button
|
|
27
|
+
type="button"
|
|
28
|
+
id={`${id}-send-btn`}
|
|
29
|
+
class="px-3 py-2 bg-[#0e639c] hover:bg-[#1177bb] disabled:bg-[#3c3c3c] disabled:text-[#888] text-white rounded-lg transition-colors flex-shrink-0 flex items-center justify-center min-h-[40px]"
|
|
30
|
+
title="Send to Input Field"
|
|
31
|
+
>
|
|
32
|
+
<iconify-icon icon="tabler:arrow-up" width="16" height="16"></iconify-icon>
|
|
33
|
+
</button>
|
|
34
|
+
|
|
35
|
+
{/* Execute button */}
|
|
36
|
+
<button
|
|
37
|
+
type="button"
|
|
38
|
+
id={`${id}-execute-btn`}
|
|
39
|
+
class="px-3 py-2 bg-[#28a745] hover:bg-[#218838] disabled:bg-[#3c3c3c] disabled:text-[#888] text-white rounded-lg transition-colors flex-shrink-0 flex items-center justify-center min-h-[40px]"
|
|
40
|
+
title="Execute Command"
|
|
41
|
+
>
|
|
42
|
+
<iconify-icon icon="tabler:player-play" width="16" height="16"></iconify-icon>
|
|
43
|
+
</button>
|
|
44
|
+
</div>
|
|
45
|
+
</div>
|
|
46
|
+
|
|
47
|
+
<script dangerouslySetInnerHTML={{__html: `
|
|
48
|
+
// Pass chat input data to JavaScript
|
|
49
|
+
window.chatInputData_${id.replace(/-/g, '_')} = {
|
|
50
|
+
chatInputId: '${id}',
|
|
51
|
+
terminalId: '${terminalId}'
|
|
52
|
+
};
|
|
53
|
+
`}}></script>
|
|
54
|
+
</sapling-island>
|
|
55
|
+
);
|
|
56
|
+
}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { Terminal as TerminalComponent } from "./Terminal.js";
|
|
2
|
+
import { ChatInput } from "./ChatInput.js";
|
|
3
|
+
|
|
4
|
+
interface SidebarProps {
|
|
5
|
+
id?: string;
|
|
6
|
+
previewPort?: number;
|
|
7
|
+
workingDirectory?: string;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export function Sidebar({ id = "sidebar", previewPort = 1234, workingDirectory }: SidebarProps) {
|
|
11
|
+
return (
|
|
12
|
+
<sapling-island loading="visible">
|
|
13
|
+
<template>
|
|
14
|
+
<script type="module" src="https://code.iconify.design/iconify-icon/2.0.0/iconify-icon.min.js"></script>
|
|
15
|
+
<script type="module" src="/components/Sidebar.js"></script>
|
|
16
|
+
</template>
|
|
17
|
+
|
|
18
|
+
{/* Mobile backdrop */}
|
|
19
|
+
<div
|
|
20
|
+
id={`${id}-backdrop`}
|
|
21
|
+
class="fixed inset-0 bg-black bg-opacity-50 backdrop-blur-sm z-40 transition-opacity duration-300 opacity-0 pointer-events-none md:hidden"
|
|
22
|
+
></div>
|
|
23
|
+
|
|
24
|
+
{/* Sidebar container */}
|
|
25
|
+
<div
|
|
26
|
+
id={`${id}-pane`}
|
|
27
|
+
class="fixed left-0 top-0 h-full w-full z-50 transform -translate-x-full transition-transform duration-300 ease-in-out md:relative md:translate-x-0 md:w-2/5 md:z-auto border-r border-[#3c3c3c] flex flex-col bg-[#252526]"
|
|
28
|
+
>
|
|
29
|
+
{/* Preview Controls */}
|
|
30
|
+
<div class="p-3 border-b border-[#3c3c3c] bg-[#2d2d30] flex-shrink-0">
|
|
31
|
+
<div class="flex items-center gap-2">
|
|
32
|
+
{/* Mobile close button */}
|
|
33
|
+
<button
|
|
34
|
+
type="button"
|
|
35
|
+
id={`${id}-close-btn`}
|
|
36
|
+
class="p-2 hover:bg-[#3c3c3c] rounded-md transition-colors flex-shrink-0 text-[#cccccc] hover:text-white md:hidden"
|
|
37
|
+
title="Close Sidebar"
|
|
38
|
+
>
|
|
39
|
+
<iconify-icon icon="tabler:x" width="16" height="16"></iconify-icon>
|
|
40
|
+
</button>
|
|
41
|
+
|
|
42
|
+
{/* Back to Home */}
|
|
43
|
+
<a
|
|
44
|
+
href="/"
|
|
45
|
+
class="p-2 hover:bg-[#3c3c3c] rounded-md transition-colors flex-shrink-0 text-[#cccccc] hover:text-white"
|
|
46
|
+
title="Back to Home"
|
|
47
|
+
>
|
|
48
|
+
<iconify-icon icon="tabler:arrow-left" width="16" height="16"></iconify-icon>
|
|
49
|
+
</a>
|
|
50
|
+
|
|
51
|
+
{/* Refresh button */}
|
|
52
|
+
<button
|
|
53
|
+
type="button"
|
|
54
|
+
id="live-preview-refresh-btn"
|
|
55
|
+
class="p-2 hover:bg-[#3c3c3c] rounded-md transition-colors flex-shrink-0 text-[#cccccc] hover:text-white"
|
|
56
|
+
title="Reload"
|
|
57
|
+
>
|
|
58
|
+
<iconify-icon icon="tabler:refresh" width="16" height="16"></iconify-icon>
|
|
59
|
+
</button>
|
|
60
|
+
|
|
61
|
+
{/* URL input */}
|
|
62
|
+
<div class="flex-1 flex items-center bg-[#1e1e1e] border border-[#3c3c3c] rounded px-3 py-2 hover:border-[#0e639c] focus-within:border-[#0e639c] transition-all">
|
|
63
|
+
<iconify-icon icon="tabler:world" width="16" height="16" class="text-[#cccccc] mr-2"></iconify-icon>
|
|
64
|
+
<span class="text-[#cccccc] text-sm">localhost:{previewPort}/</span>
|
|
65
|
+
<input
|
|
66
|
+
id="live-preview-url-input"
|
|
67
|
+
type="text"
|
|
68
|
+
placeholder="path"
|
|
69
|
+
defaultValue=""
|
|
70
|
+
class="flex-1 bg-transparent text-sm focus:outline-none text-[#cccccc] ml-1"
|
|
71
|
+
/>
|
|
72
|
+
<button
|
|
73
|
+
type="button"
|
|
74
|
+
id="live-preview-load-btn"
|
|
75
|
+
class="ml-2 p-1 hover:bg-[#3c3c3c] rounded transition-colors flex-shrink-0 text-[#cccccc] hover:text-white"
|
|
76
|
+
title="Go"
|
|
77
|
+
>
|
|
78
|
+
<iconify-icon icon="tabler:chevron-right" width="16" height="16"></iconify-icon>
|
|
79
|
+
</button>
|
|
80
|
+
</div>
|
|
81
|
+
</div>
|
|
82
|
+
</div>
|
|
83
|
+
|
|
84
|
+
{/* Terminal Content */}
|
|
85
|
+
<div class="flex-1 overflow-hidden bg-[#1e1e1e] flex flex-col">
|
|
86
|
+
{/* Terminal Display */}
|
|
87
|
+
<div class="flex-1 overflow-hidden">
|
|
88
|
+
<TerminalComponent index={1} />
|
|
89
|
+
</div>
|
|
90
|
+
|
|
91
|
+
{/* Chat Input */}
|
|
92
|
+
<div class="flex-shrink-0">
|
|
93
|
+
<ChatInput id="chat-input" terminalId="terminal-1" />
|
|
94
|
+
</div>
|
|
95
|
+
</div>
|
|
96
|
+
</div>
|
|
97
|
+
</sapling-island>
|
|
98
|
+
);
|
|
99
|
+
}
|
|
@@ -25,14 +25,14 @@ export function SimpleLivePreview({ id = "simple-preview", previewPort = 5173 }:
|
|
|
25
25
|
data-preview-port={previewPort}
|
|
26
26
|
></iframe>
|
|
27
27
|
|
|
28
|
-
{/* Floating Sidebar Toggle */}
|
|
28
|
+
{/* Floating Sidebar Toggle - Only show when sidebar is closed */}
|
|
29
29
|
<button
|
|
30
30
|
id={`${id}-floating-hide-sidebar-btn`}
|
|
31
|
-
class="absolute p-3 bg-white border-2 border-gray-400 rounded-lg shadow-xl hover:bg-gray-50 hover:shadow-2xl transition-all
|
|
32
|
-
title="
|
|
31
|
+
class="absolute p-3 bg-white border-2 border-gray-400 rounded-lg shadow-xl hover:bg-gray-50 hover:shadow-2xl transition-all items-center justify-center z-50 hidden"
|
|
32
|
+
title="Show Sidebar"
|
|
33
33
|
style="position: absolute !important; z-index: 9999 !important; bottom: 16px; left: 16px;"
|
|
34
34
|
>
|
|
35
|
-
<iconify-icon id={`${id}-floating-hide-sidebar-icon`} icon="ph:sidebar-simple" width="20" height="20" class="text-gray-800"></iconify-icon>
|
|
35
|
+
<iconify-icon id={`${id}-floating-hide-sidebar-icon`} icon="ph:sidebar-simple-fill" width="20" height="20" class="text-gray-800"></iconify-icon>
|
|
36
36
|
</button>
|
|
37
37
|
</div>
|
|
38
38
|
</sapling-island>
|
package/src/pages/Code.tsx
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import Layout from "../layouts/Layout.js";
|
|
2
|
-
import {
|
|
2
|
+
import { Sidebar } from "../components/Sidebar.js";
|
|
3
3
|
import { SimpleLivePreview } from "../components/SimpleLivePreview.js";
|
|
4
4
|
|
|
5
5
|
interface TerminalProps {
|
|
@@ -10,61 +10,24 @@ interface TerminalProps {
|
|
|
10
10
|
export function Code({ previewPort = 1234, workingDirectory }: TerminalProps) {
|
|
11
11
|
return (
|
|
12
12
|
<Layout title="Code Editor">
|
|
13
|
-
<div id="code-container" class="h-screen flex bg-[#1e1e1e]">
|
|
14
|
-
{/*
|
|
15
|
-
<
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
<button
|
|
27
|
-
type="button"
|
|
28
|
-
id="live-preview-refresh-btn"
|
|
29
|
-
class="p-2 hover:bg-[#3c3c3c] rounded-md transition-colors flex-shrink-0 text-[#cccccc] hover:text-white"
|
|
30
|
-
title="Reload"
|
|
31
|
-
>
|
|
32
|
-
<iconify-icon icon="tabler:refresh" width="16" height="16"></iconify-icon>
|
|
33
|
-
</button>
|
|
34
|
-
<div class="flex-1 flex items-center bg-[#1e1e1e] border border-[#3c3c3c] rounded px-3 py-2 hover:border-[#0e639c] focus-within:border-[#0e639c] transition-all">
|
|
35
|
-
<iconify-icon icon="tabler:world" width="16" height="16" class="text-[#cccccc] mr-2"></iconify-icon>
|
|
36
|
-
<span class="text-[#cccccc] text-sm">localhost:{previewPort}/</span>
|
|
37
|
-
<input
|
|
38
|
-
id="live-preview-url-input"
|
|
39
|
-
type="text"
|
|
40
|
-
placeholder="path"
|
|
41
|
-
defaultValue=""
|
|
42
|
-
class="flex-1 bg-transparent text-sm focus:outline-none text-[#cccccc] ml-1"
|
|
43
|
-
/>
|
|
44
|
-
<button
|
|
45
|
-
type="button"
|
|
46
|
-
id="live-preview-load-btn"
|
|
47
|
-
class="ml-2 p-1 hover:bg-[#3c3c3c] rounded transition-colors flex-shrink-0 text-[#cccccc] hover:text-white"
|
|
48
|
-
title="Go"
|
|
49
|
-
>
|
|
50
|
-
<iconify-icon icon="tabler:chevron-right" width="16" height="16"></iconify-icon>
|
|
51
|
-
</button>
|
|
52
|
-
</div>
|
|
53
|
-
</div>
|
|
54
|
-
</div>
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
{/* Tab Content */}
|
|
58
|
-
<div class="flex-1 overflow-hidden bg-[#1e1e1e]">
|
|
59
|
-
{/* Single Terminal Content */}
|
|
60
|
-
<div class="h-full">
|
|
61
|
-
<TerminalComponent index={1} />
|
|
62
|
-
</div>
|
|
63
|
-
</div>
|
|
64
|
-
</div>
|
|
13
|
+
<div id="code-container" class="h-screen flex bg-[#1e1e1e] relative">
|
|
14
|
+
{/* Mobile toggle button */}
|
|
15
|
+
<button
|
|
16
|
+
type="button"
|
|
17
|
+
id="mobile-sidebar-toggle"
|
|
18
|
+
class="fixed top-4 left-4 z-60 p-3 bg-[#2d2d30] border border-[#3c3c3c] rounded-lg shadow-xl hover:bg-[#3c3c3c] transition-all md:hidden"
|
|
19
|
+
title="Toggle Sidebar"
|
|
20
|
+
>
|
|
21
|
+
<iconify-icon icon="tabler:menu-2" width="20" height="20" class="text-[#cccccc]"></iconify-icon>
|
|
22
|
+
</button>
|
|
23
|
+
|
|
24
|
+
{/* Sidebar */}
|
|
25
|
+
<Sidebar id="sidebar" previewPort={previewPort} workingDirectory={workingDirectory} />
|
|
65
26
|
|
|
66
|
-
{/*
|
|
67
|
-
<
|
|
27
|
+
{/* Main Content - Live Preview */}
|
|
28
|
+
<div class="flex-1 md:flex-1">
|
|
29
|
+
<SimpleLivePreview id="live-preview" previewPort={previewPort} />
|
|
30
|
+
</div>
|
|
68
31
|
</div>
|
|
69
32
|
</Layout>
|
|
70
33
|
);
|
|
@@ -104,8 +104,6 @@ export class WebSocketTerminalService {
|
|
|
104
104
|
return;
|
|
105
105
|
}
|
|
106
106
|
|
|
107
|
-
console.log(`Received message from ${clientId}:`, message.type, message.sessionId);
|
|
108
|
-
|
|
109
107
|
switch (message.type) {
|
|
110
108
|
case 'join':
|
|
111
109
|
this.handleJoin(clientId, message);
|
|
@@ -186,9 +184,7 @@ export class WebSocketTerminalService {
|
|
|
186
184
|
|
|
187
185
|
private static handleInput(clientId: string, message: WebSocketMessage) {
|
|
188
186
|
const client = this.clients.get(clientId);
|
|
189
|
-
if (!client || !message.sessionId || message.data === undefined) return
|
|
190
|
-
|
|
191
|
-
console.log(`Input from client ${clientId} to session ${message.sessionId}`);
|
|
187
|
+
if (!client || !message.sessionId || message.data === undefined) return;;
|
|
192
188
|
|
|
193
189
|
// Get the terminal session
|
|
194
190
|
const session = TerminalService.getSession(message.sessionId);
|