@mjasano/devtunnel 1.4.0 → 1.5.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.
@@ -16,7 +16,8 @@
16
16
  "Bash(git add:*)",
17
17
  "Bash(git commit:*)",
18
18
  "Bash(git push:*)",
19
- "Bash(gh release create:*)"
19
+ "Bash(gh release create:*)",
20
+ "Bash(PORT=3099 node:*)"
20
21
  ]
21
22
  }
22
23
  }
package/CHANGELOG.md CHANGED
@@ -5,6 +5,19 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [1.5.0] - 2026-01-02
9
+
10
+ ### Added
11
+ - Mobile-responsive UI with touch-friendly design
12
+ - Sidebar close button for mobile devices
13
+ - Full-width sidebar on small screens (480px and below)
14
+
15
+ ### Changed
16
+ - Improved touch targets (minimum 44px for buttons/tabs)
17
+ - Dynamic terminal height using flex layout
18
+ - Input font-size set to 16px to prevent iOS auto-zoom
19
+ - Smoother sidebar slide animation with overlay
20
+
8
21
  ## [1.4.0] - 2026-01-02
9
22
 
10
23
  ### Added
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mjasano/devtunnel",
3
- "version": "1.4.0",
3
+ "version": "1.5.0",
4
4
  "description": "Web terminal with code editor and tunnel manager - access your dev environment from anywhere",
5
5
  "main": "server.js",
6
6
  "bin": {
package/public/app.js CHANGED
@@ -712,6 +712,16 @@ function toggleSection(section) {
712
712
  content.style.display = content.style.display === 'none' ? 'block' : 'none';
713
713
  }
714
714
 
715
+ // Mobile sidebar toggle
716
+ function toggleMobileSidebar() {
717
+ const sidebar = document.querySelector('.sidebar');
718
+ const overlay = document.getElementById('sidebar-overlay');
719
+ sidebar.classList.toggle('open');
720
+ overlay.classList.toggle('show');
721
+ }
722
+
723
+ window.toggleMobileSidebar = toggleMobileSidebar;
724
+
715
725
  window.copyUrl = copyUrl;
716
726
  window.stopTunnel = stopTunnel;
717
727
  window.createNewSession = createNewSession;
package/public/index.html CHANGED
@@ -27,6 +27,7 @@
27
27
  <span id="status-text">Connecting...</span>
28
28
  </div>
29
29
  <button class="btn-logout" id="logout-btn" style="display: none;" onclick="logout()">Logout</button>
30
+ <button class="mobile-sidebar-toggle" id="sidebar-toggle" onclick="toggleMobileSidebar()">&#9776;</button>
30
31
  </div>
31
32
  </div>
32
33
 
@@ -42,6 +43,7 @@
42
43
  </div>
43
44
  </div>
44
45
 
46
+ <div class="sidebar-overlay" id="sidebar-overlay" onclick="toggleMobileSidebar()"></div>
45
47
  <div class="main-container">
46
48
  <div id="terminal-container">
47
49
  <div class="terminal-tabs" id="terminal-tabs">
@@ -63,6 +65,7 @@
63
65
  </div>
64
66
 
65
67
  <div class="sidebar">
68
+ <button class="sidebar-close" onclick="toggleMobileSidebar()">&times;</button>
66
69
  <!-- Files Section -->
67
70
  <div class="sidebar-section">
68
71
  <div class="sidebar-header" onclick="toggleSection('files')">
package/public/login.html CHANGED
@@ -141,6 +141,38 @@
141
141
  @keyframes spin {
142
142
  to { transform: rotate(360deg); }
143
143
  }
144
+
145
+ @media (max-width: 480px) {
146
+ .login-container {
147
+ margin: 16px;
148
+ padding: 24px;
149
+ }
150
+
151
+ .logo {
152
+ width: 48px;
153
+ height: 48px;
154
+ margin-bottom: 16px;
155
+ }
156
+
157
+ h1 {
158
+ font-size: 20px;
159
+ }
160
+
161
+ .subtitle {
162
+ font-size: 13px;
163
+ margin-bottom: 24px;
164
+ }
165
+
166
+ .form-group input {
167
+ padding: 14px 12px;
168
+ font-size: 18px;
169
+ }
170
+
171
+ .btn {
172
+ padding: 14px 24px;
173
+ font-size: 16px;
174
+ }
175
+ }
144
176
  </style>
145
177
  </head>
146
178
  <body>
package/public/styles.css CHANGED
@@ -143,6 +143,7 @@ body {
143
143
  }
144
144
 
145
145
  .sidebar {
146
+ position: relative;
146
147
  width: 320px;
147
148
  background-color: #161b22;
148
149
  border-left: 1px solid #30363d;
@@ -839,19 +840,373 @@ body {
839
840
  }
840
841
  }
841
842
 
843
+ /* Mobile Toggle Button */
844
+ .mobile-sidebar-toggle {
845
+ display: none;
846
+ width: 44px;
847
+ height: 44px;
848
+ background-color: #21262d;
849
+ border: 1px solid #30363d;
850
+ border-radius: 6px;
851
+ color: #8b949e;
852
+ font-size: 20px;
853
+ cursor: pointer;
854
+ align-items: center;
855
+ justify-content: center;
856
+ -webkit-tap-highlight-color: transparent;
857
+ }
858
+
859
+ .mobile-sidebar-toggle:hover,
860
+ .mobile-sidebar-toggle:active {
861
+ background-color: #30363d;
862
+ color: #c9d1d9;
863
+ }
864
+
865
+ /* Mobile Sidebar Close */
866
+ .sidebar-close {
867
+ display: none;
868
+ position: absolute;
869
+ top: 12px;
870
+ right: 12px;
871
+ width: 32px;
872
+ height: 32px;
873
+ background-color: transparent;
874
+ border: none;
875
+ border-radius: 6px;
876
+ color: #8b949e;
877
+ font-size: 20px;
878
+ cursor: pointer;
879
+ align-items: center;
880
+ justify-content: center;
881
+ }
882
+
883
+ .sidebar-close:hover {
884
+ background-color: #21262d;
885
+ color: #c9d1d9;
886
+ }
887
+
888
+ /* Mobile Styles */
842
889
  @media (max-width: 768px) {
890
+ .header {
891
+ padding: 10px 12px;
892
+ min-height: 56px;
893
+ }
894
+
895
+ .header h1 {
896
+ font-size: 16px;
897
+ gap: 8px;
898
+ }
899
+
900
+ .header h1 .logo {
901
+ width: 24px;
902
+ height: 24px;
903
+ }
904
+
905
+ .header-right {
906
+ gap: 10px;
907
+ }
908
+
909
+ .system-info {
910
+ display: none;
911
+ }
912
+
913
+ .session-indicator {
914
+ display: none !important;
915
+ }
916
+
917
+ .status {
918
+ gap: 6px;
919
+ }
920
+
921
+ .status span {
922
+ display: none;
923
+ }
924
+
925
+ .status-dot {
926
+ width: 10px;
927
+ height: 10px;
928
+ }
929
+
930
+ .btn-logout {
931
+ padding: 8px 12px;
932
+ font-size: 12px;
933
+ min-height: 36px;
934
+ }
935
+
936
+ .mobile-sidebar-toggle {
937
+ display: flex;
938
+ }
939
+
940
+ .tab-bar {
941
+ padding: 0;
942
+ overflow-x: auto;
943
+ -webkit-overflow-scrolling: touch;
944
+ }
945
+
946
+ .tab {
947
+ flex: 1;
948
+ padding: 12px 16px;
949
+ font-size: 13px;
950
+ justify-content: center;
951
+ min-height: 44px;
952
+ }
953
+
843
954
  .main-container {
844
955
  flex-direction: column;
956
+ position: relative;
957
+ flex: 1;
958
+ overflow: hidden;
959
+ }
960
+
961
+ #terminal-container {
962
+ padding: 4px;
963
+ flex: 1;
964
+ display: flex;
965
+ flex-direction: column;
966
+ overflow: hidden;
967
+ }
968
+
969
+ #terminal-container #terminal {
970
+ flex: 1;
971
+ min-height: 0;
972
+ }
973
+
974
+ #editor-container {
975
+ flex: 1;
976
+ overflow: hidden;
977
+ }
978
+
979
+ .terminal-tabs {
980
+ min-height: 40px;
981
+ flex-shrink: 0;
982
+ }
983
+
984
+ .terminal-tab {
985
+ padding: 10px 14px;
986
+ font-size: 12px;
987
+ min-height: 40px;
988
+ }
989
+
990
+ .terminal-tab-new {
991
+ width: 36px;
992
+ height: 36px;
993
+ font-size: 18px;
994
+ }
995
+
996
+ .terminal-tab-close {
997
+ width: 20px;
998
+ height: 20px;
999
+ font-size: 16px;
1000
+ }
1001
+
1002
+ .editor-tabs {
1003
+ min-height: 40px;
1004
+ overflow-x: auto;
1005
+ -webkit-overflow-scrolling: touch;
1006
+ flex-shrink: 0;
1007
+ }
1008
+
1009
+ .editor-tab {
1010
+ padding: 10px 14px;
1011
+ font-size: 12px;
1012
+ min-height: 40px;
1013
+ }
1014
+
1015
+ .editor-tab-close {
1016
+ width: 20px;
1017
+ height: 20px;
1018
+ font-size: 16px;
845
1019
  }
846
1020
 
1021
+ /* Sidebar as overlay on mobile */
847
1022
  .sidebar {
1023
+ position: fixed;
1024
+ top: 0;
1025
+ right: -100%;
1026
+ width: 85%;
1027
+ max-width: 320px;
1028
+ height: 100%;
1029
+ height: 100dvh;
1030
+ border-left: 1px solid #30363d;
1031
+ transition: right 0.25s ease-out;
1032
+ z-index: 100;
1033
+ overflow-y: auto;
1034
+ -webkit-overflow-scrolling: touch;
1035
+ padding-top: 50px;
1036
+ }
1037
+
1038
+ .sidebar.open {
1039
+ right: 0;
1040
+ }
1041
+
1042
+ .sidebar-close {
1043
+ display: flex;
1044
+ }
1045
+
1046
+ .sidebar-overlay {
1047
+ display: none;
1048
+ position: fixed;
1049
+ top: 0;
1050
+ left: 0;
1051
+ right: 0;
1052
+ bottom: 0;
1053
+ background-color: rgba(0, 0, 0, 0.6);
1054
+ z-index: 99;
1055
+ opacity: 0;
1056
+ transition: opacity 0.25s ease-out;
1057
+ }
1058
+
1059
+ .sidebar-overlay.show {
1060
+ display: block;
1061
+ opacity: 1;
1062
+ }
1063
+
1064
+ .sidebar-header {
1065
+ padding: 14px 16px;
1066
+ min-height: 48px;
1067
+ }
1068
+
1069
+ .sidebar-content {
1070
+ max-height: none;
1071
+ padding: 8px 12px;
1072
+ }
1073
+
1074
+ #files-content {
1075
+ max-height: 40vh !important;
1076
+ }
1077
+
1078
+ .tunnel-form {
1079
+ padding: 12px;
1080
+ flex-direction: column;
1081
+ gap: 10px;
1082
+ }
1083
+
1084
+ .tunnel-form input {
1085
+ width: 100%;
1086
+ padding: 12px;
1087
+ font-size: 16px;
1088
+ }
1089
+
1090
+ .tunnel-form .btn {
848
1091
  width: 100%;
849
- max-height: 250px;
850
- border-left: none;
851
- border-top: 1px solid #30363d;
1092
+ padding: 12px;
1093
+ min-height: 44px;
852
1094
  }
853
1095
 
854
1096
  .toast {
855
- right: 20px;
1097
+ right: 12px;
1098
+ left: 12px;
1099
+ bottom: 12px;
1100
+ }
1101
+
1102
+ .reconnect-box {
1103
+ margin: 20px;
1104
+ padding: 24px;
1105
+ width: calc(100% - 40px);
1106
+ }
1107
+
1108
+ .reconnect-btn {
1109
+ padding: 14px 24px;
1110
+ min-height: 48px;
1111
+ width: 100%;
1112
+ }
1113
+
1114
+ .breadcrumb {
1115
+ padding: 10px 12px;
1116
+ font-size: 12px;
1117
+ }
1118
+
1119
+ .breadcrumb-item {
1120
+ padding: 4px 8px;
1121
+ }
1122
+
1123
+ .file-search {
1124
+ padding: 10px 12px;
1125
+ }
1126
+
1127
+ .file-search input {
1128
+ padding: 10px 12px;
1129
+ font-size: 16px;
1130
+ }
1131
+
1132
+ .file-item {
1133
+ padding: 10px 12px;
1134
+ min-height: 44px;
1135
+ }
1136
+
1137
+ .item-card {
1138
+ padding: 12px;
1139
+ }
1140
+
1141
+ .item-url {
1142
+ flex-direction: column;
1143
+ gap: 8px;
1144
+ }
1145
+
1146
+ .item-url input {
1147
+ width: 100%;
1148
+ padding: 10px;
1149
+ font-size: 13px;
1150
+ }
1151
+
1152
+ .btn-copy {
1153
+ width: 100%;
1154
+ text-align: center;
1155
+ padding: 10px;
1156
+ min-height: 40px;
1157
+ }
1158
+
1159
+ .context-menu {
1160
+ min-width: 160px;
1161
+ }
1162
+
1163
+ .context-menu-item {
1164
+ padding: 12px 16px;
1165
+ min-height: 44px;
1166
+ }
1167
+
1168
+ .modal {
1169
+ width: calc(100% - 32px);
1170
+ margin: 16px;
1171
+ }
1172
+
1173
+ .modal input {
1174
+ padding: 12px;
1175
+ font-size: 16px;
1176
+ }
1177
+
1178
+ .modal-actions .btn {
1179
+ padding: 10px 16px;
1180
+ min-height: 40px;
1181
+ }
1182
+ }
1183
+
1184
+ /* Small mobile */
1185
+ @media (max-width: 480px) {
1186
+ .header h1 span {
1187
+ display: none;
1188
+ }
1189
+
1190
+ .header h1 .logo {
1191
+ width: 28px;
1192
+ height: 28px;
1193
+ }
1194
+
1195
+ .btn-logout {
1196
+ padding: 6px 10px;
1197
+ font-size: 11px;
1198
+ }
1199
+
1200
+ .tab-icon {
1201
+ display: none;
1202
+ }
1203
+
1204
+ .tab {
1205
+ font-size: 12px;
1206
+ }
1207
+
1208
+ .sidebar {
1209
+ width: 100%;
1210
+ max-width: none;
856
1211
  }
857
1212
  }