@jacksontian/mwt 1.0.0 → 1.2.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.
- package/README.md +24 -6
- package/lib/pty-manager.js +40 -0
- package/lib/ring-buffer.js +1 -1
- package/lib/server.js +145 -159
- package/lib/session-manager.js +66 -0
- package/package.json +8 -3
- package/public/css/style.css +378 -13
- package/public/index.html +77 -12
- package/public/js/app.js +203 -95
- package/public/js/drag-manager.js +42 -0
- package/public/js/font-manager.js +43 -0
- package/public/js/i18n.js +176 -0
- package/public/js/layout-manager.js +99 -15
- package/public/js/shortcut-manager.js +102 -0
- package/public/js/terminal-manager.js +149 -26
- package/public/js/theme-manager.js +6 -6
- package/public/js/ws-client.js +27 -6
package/public/css/style.css
CHANGED
|
@@ -21,9 +21,10 @@
|
|
|
21
21
|
--accent: #6c8cff;
|
|
22
22
|
--accent-hover: #8aa4ff;
|
|
23
23
|
--text-primary: #d4d8e8;
|
|
24
|
-
--text-secondary: #
|
|
25
|
-
--text-dim: #
|
|
24
|
+
--text-secondary: #9aa3bc;
|
|
25
|
+
--text-dim: #6f788f;
|
|
26
26
|
--border: #252a3d;
|
|
27
|
+
--pane-border-idle: #1e2333;
|
|
27
28
|
--danger: #e05560;
|
|
28
29
|
--danger-hover: #ff6b76;
|
|
29
30
|
--terminal-bg: #0a0c12;
|
|
@@ -43,6 +44,7 @@
|
|
|
43
44
|
--text-secondary: #5a6178;
|
|
44
45
|
--text-dim: #9098b0;
|
|
45
46
|
--border: #d0d5e0;
|
|
47
|
+
--pane-border-idle: #c5cad6;
|
|
46
48
|
--danger: #d43d4e;
|
|
47
49
|
--danger-hover: #c02838;
|
|
48
50
|
--terminal-bg: #ffffff;
|
|
@@ -83,16 +85,14 @@ body {
|
|
|
83
85
|
-webkit-app-region: no-drag;
|
|
84
86
|
}
|
|
85
87
|
|
|
88
|
+
.toolbar-left, .toolbar-right {
|
|
89
|
+
flex: 1;
|
|
90
|
+
}
|
|
91
|
+
|
|
86
92
|
.toolbar-right {
|
|
87
|
-
min-width: 100px;
|
|
88
93
|
justify-content: flex-end;
|
|
89
94
|
}
|
|
90
95
|
|
|
91
|
-
#terminal-count {
|
|
92
|
-
color: var(--text-dim);
|
|
93
|
-
font-size: 12px;
|
|
94
|
-
font-variant-numeric: tabular-nums;
|
|
95
|
-
}
|
|
96
96
|
|
|
97
97
|
#btn-new-terminal {
|
|
98
98
|
display: flex;
|
|
@@ -132,8 +132,10 @@ body {
|
|
|
132
132
|
.layout-btn {
|
|
133
133
|
display: flex;
|
|
134
134
|
align-items: center;
|
|
135
|
+
justify-content: center;
|
|
135
136
|
gap: 5px;
|
|
136
|
-
|
|
137
|
+
width: 80px;
|
|
138
|
+
padding: 5px 0;
|
|
137
139
|
background: transparent;
|
|
138
140
|
color: var(--text-secondary);
|
|
139
141
|
border: none;
|
|
@@ -291,12 +293,30 @@ body {
|
|
|
291
293
|
.terminal-pane {
|
|
292
294
|
display: flex;
|
|
293
295
|
flex-direction: column;
|
|
296
|
+
position: relative;
|
|
294
297
|
background: var(--terminal-bg);
|
|
295
|
-
border: 1px solid var(--border);
|
|
298
|
+
border: 1px solid var(--pane-border-idle);
|
|
296
299
|
border-radius: var(--radius-sm);
|
|
297
300
|
overflow: hidden;
|
|
298
301
|
min-width: 0;
|
|
299
302
|
min-height: 0;
|
|
303
|
+
transition: border-color var(--transition), box-shadow var(--transition);
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
.terminal-pane.pane-focused {
|
|
307
|
+
border-color: var(--accent);
|
|
308
|
+
box-shadow: 0 0 0 1px color-mix(in srgb, var(--accent) 55%, transparent);
|
|
309
|
+
z-index: 1;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
.terminal-pane.pane-focused .pane-header {
|
|
313
|
+
background: color-mix(in srgb, var(--accent) 12%, var(--pane-header));
|
|
314
|
+
border-bottom-color: color-mix(in srgb, var(--accent) 35%, var(--border));
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
.terminal-pane.pane-focused .pane-title {
|
|
318
|
+
color: var(--text-primary);
|
|
319
|
+
font-weight: 500;
|
|
300
320
|
}
|
|
301
321
|
|
|
302
322
|
.pane-header {
|
|
@@ -309,11 +329,13 @@ body {
|
|
|
309
329
|
border-bottom: 1px solid var(--border);
|
|
310
330
|
flex-shrink: 0;
|
|
311
331
|
user-select: none;
|
|
332
|
+
transition: background var(--transition), border-color var(--transition);
|
|
312
333
|
}
|
|
313
334
|
|
|
314
335
|
.pane-title {
|
|
315
336
|
font-size: 11px;
|
|
316
337
|
color: var(--text-secondary);
|
|
338
|
+
transition: color var(--transition), font-weight var(--transition);
|
|
317
339
|
overflow: hidden;
|
|
318
340
|
text-overflow: ellipsis;
|
|
319
341
|
white-space: nowrap;
|
|
@@ -387,6 +409,8 @@ body {
|
|
|
387
409
|
flex: 1 !important;
|
|
388
410
|
min-width: 0 !important;
|
|
389
411
|
min-height: 0 !important;
|
|
412
|
+
grid-column: 1 / -1;
|
|
413
|
+
grid-row: 1 / -1;
|
|
390
414
|
}
|
|
391
415
|
|
|
392
416
|
.terminal-body {
|
|
@@ -402,27 +426,43 @@ body {
|
|
|
402
426
|
|
|
403
427
|
.terminal-body .xterm-viewport {
|
|
404
428
|
overflow-y: auto !important;
|
|
429
|
+
/* 与 theme 背景一致,避免 vendor 默认 #000 与画布色差导致边缘发闷 */
|
|
430
|
+
background-color: var(--terminal-bg) !important;
|
|
405
431
|
}
|
|
406
432
|
|
|
407
|
-
/* ========== Layout:
|
|
408
|
-
.layout-
|
|
433
|
+
/* ========== Layout: Columns ========== */
|
|
434
|
+
.layout-columns {
|
|
409
435
|
display: flex;
|
|
410
436
|
flex-direction: row;
|
|
411
437
|
gap: 2px;
|
|
412
438
|
padding: 2px;
|
|
413
439
|
}
|
|
414
440
|
|
|
415
|
-
.layout-
|
|
441
|
+
.layout-columns .terminal-pane {
|
|
416
442
|
flex: 1;
|
|
417
443
|
min-width: 200px;
|
|
418
444
|
}
|
|
419
445
|
|
|
446
|
+
/* ========== Layout: Rows ========== */
|
|
447
|
+
.layout-rows {
|
|
448
|
+
display: flex;
|
|
449
|
+
flex-direction: column;
|
|
450
|
+
gap: 2px;
|
|
451
|
+
padding: 2px;
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
.layout-rows .terminal-pane {
|
|
455
|
+
flex: 1;
|
|
456
|
+
min-height: 100px;
|
|
457
|
+
}
|
|
458
|
+
|
|
420
459
|
/* ========== Layout: Grid ========== */
|
|
421
460
|
.layout-grid {
|
|
422
461
|
display: grid;
|
|
423
462
|
gap: 2px;
|
|
424
463
|
padding: 2px;
|
|
425
464
|
grid-template-columns: 1fr;
|
|
465
|
+
grid-auto-rows: 1fr;
|
|
426
466
|
}
|
|
427
467
|
|
|
428
468
|
.layout-grid .terminal-pane {
|
|
@@ -441,6 +481,11 @@ body {
|
|
|
441
481
|
inset: 0;
|
|
442
482
|
border-radius: 0;
|
|
443
483
|
border: none;
|
|
484
|
+
box-shadow: none;
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
.layout-tabs .terminal-pane.pane-focused.active {
|
|
488
|
+
box-shadow: inset 0 0 0 1px var(--accent);
|
|
444
489
|
}
|
|
445
490
|
|
|
446
491
|
.layout-tabs .terminal-pane.active {
|
|
@@ -533,6 +578,96 @@ body {
|
|
|
533
578
|
display: block;
|
|
534
579
|
}
|
|
535
580
|
|
|
581
|
+
/* ========== Language Dropdown ========== */
|
|
582
|
+
#lang-dropdown {
|
|
583
|
+
position: relative;
|
|
584
|
+
margin-right: 4px;
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
#btn-lang {
|
|
588
|
+
display: flex;
|
|
589
|
+
align-items: center;
|
|
590
|
+
justify-content: center;
|
|
591
|
+
height: 30px;
|
|
592
|
+
padding: 0 8px;
|
|
593
|
+
background: var(--bg-secondary);
|
|
594
|
+
border: 1px solid var(--border);
|
|
595
|
+
border-radius: var(--radius);
|
|
596
|
+
color: var(--text-secondary);
|
|
597
|
+
cursor: pointer;
|
|
598
|
+
transition: all var(--transition);
|
|
599
|
+
font-size: 11px;
|
|
600
|
+
font-weight: 600;
|
|
601
|
+
letter-spacing: 0.02em;
|
|
602
|
+
gap: 4px;
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
#btn-lang:hover, #lang-dropdown.open #btn-lang {
|
|
606
|
+
background: var(--bg-hover);
|
|
607
|
+
color: var(--text-primary);
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
#btn-lang .lang-chevron {
|
|
611
|
+
width: 8px;
|
|
612
|
+
height: 8px;
|
|
613
|
+
transition: transform var(--transition);
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
#lang-dropdown.open .lang-chevron {
|
|
617
|
+
transform: rotate(180deg);
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
#lang-menu {
|
|
621
|
+
display: none;
|
|
622
|
+
position: absolute;
|
|
623
|
+
top: calc(100% + 4px);
|
|
624
|
+
right: 0;
|
|
625
|
+
min-width: 110px;
|
|
626
|
+
background: var(--bg-secondary);
|
|
627
|
+
border: 1px solid var(--border);
|
|
628
|
+
border-radius: var(--radius);
|
|
629
|
+
box-shadow: 0 4px 12px rgba(0,0,0,0.25);
|
|
630
|
+
z-index: 1000;
|
|
631
|
+
overflow: hidden;
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
#lang-dropdown.open #lang-menu {
|
|
635
|
+
display: block;
|
|
636
|
+
}
|
|
637
|
+
|
|
638
|
+
.lang-option {
|
|
639
|
+
display: flex;
|
|
640
|
+
align-items: center;
|
|
641
|
+
justify-content: space-between;
|
|
642
|
+
width: 100%;
|
|
643
|
+
padding: 7px 12px;
|
|
644
|
+
background: none;
|
|
645
|
+
border: none;
|
|
646
|
+
color: var(--text-secondary);
|
|
647
|
+
cursor: pointer;
|
|
648
|
+
font-size: 12px;
|
|
649
|
+
text-align: left;
|
|
650
|
+
transition: background var(--transition), color var(--transition);
|
|
651
|
+
}
|
|
652
|
+
|
|
653
|
+
.lang-option:hover {
|
|
654
|
+
background: var(--bg-hover);
|
|
655
|
+
color: var(--text-primary);
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
.lang-option.active {
|
|
659
|
+
color: var(--accent);
|
|
660
|
+
}
|
|
661
|
+
|
|
662
|
+
.lang-option .lang-check {
|
|
663
|
+
opacity: 0;
|
|
664
|
+
color: var(--accent);
|
|
665
|
+
}
|
|
666
|
+
|
|
667
|
+
.lang-option.active .lang-check {
|
|
668
|
+
opacity: 1;
|
|
669
|
+
}
|
|
670
|
+
|
|
536
671
|
/* ========== Theme Toggle ========== */
|
|
537
672
|
#btn-theme-toggle {
|
|
538
673
|
display: flex;
|
|
@@ -568,6 +703,236 @@ body {
|
|
|
568
703
|
display: block;
|
|
569
704
|
}
|
|
570
705
|
|
|
706
|
+
/* ========== Drag to swap ========== */
|
|
707
|
+
.pane-header.dragging-source {
|
|
708
|
+
opacity: 0.5;
|
|
709
|
+
}
|
|
710
|
+
|
|
711
|
+
.terminal-pane.drag-over {
|
|
712
|
+
outline: 2px solid var(--accent);
|
|
713
|
+
outline-offset: -2px;
|
|
714
|
+
}
|
|
715
|
+
|
|
716
|
+
.pane-header[draggable="true"] {
|
|
717
|
+
cursor: grab;
|
|
718
|
+
}
|
|
719
|
+
|
|
720
|
+
.pane-header[draggable="true"]:active {
|
|
721
|
+
cursor: grabbing;
|
|
722
|
+
}
|
|
723
|
+
|
|
724
|
+
.tab[draggable="true"] {
|
|
725
|
+
cursor: grab;
|
|
726
|
+
}
|
|
727
|
+
|
|
728
|
+
.tab[draggable="true"]:active {
|
|
729
|
+
cursor: grabbing;
|
|
730
|
+
}
|
|
731
|
+
|
|
732
|
+
.tab.drag-over {
|
|
733
|
+
outline: 2px solid var(--accent);
|
|
734
|
+
outline-offset: -2px;
|
|
735
|
+
border-radius: var(--radius-sm) var(--radius-sm) 0 0;
|
|
736
|
+
}
|
|
737
|
+
|
|
738
|
+
/* ========== Shortcuts Button ========== */
|
|
739
|
+
#btn-shortcuts {
|
|
740
|
+
display: flex;
|
|
741
|
+
align-items: center;
|
|
742
|
+
justify-content: center;
|
|
743
|
+
width: 30px;
|
|
744
|
+
height: 30px;
|
|
745
|
+
background: var(--bg-secondary);
|
|
746
|
+
border: 1px solid var(--border);
|
|
747
|
+
border-radius: var(--radius);
|
|
748
|
+
color: var(--text-secondary);
|
|
749
|
+
cursor: pointer;
|
|
750
|
+
transition: all var(--transition);
|
|
751
|
+
margin-right: 4px;
|
|
752
|
+
}
|
|
753
|
+
|
|
754
|
+
#btn-shortcuts:hover {
|
|
755
|
+
background: var(--bg-hover);
|
|
756
|
+
color: var(--text-primary);
|
|
757
|
+
}
|
|
758
|
+
|
|
759
|
+
/* ========== Shortcuts Modal ========== */
|
|
760
|
+
.modal-overlay {
|
|
761
|
+
position: fixed;
|
|
762
|
+
inset: 0;
|
|
763
|
+
background: rgba(0, 0, 0, 0.5);
|
|
764
|
+
display: flex;
|
|
765
|
+
align-items: center;
|
|
766
|
+
justify-content: center;
|
|
767
|
+
z-index: 1000;
|
|
768
|
+
}
|
|
769
|
+
|
|
770
|
+
.modal-overlay.hidden {
|
|
771
|
+
display: none;
|
|
772
|
+
}
|
|
773
|
+
|
|
774
|
+
.modal {
|
|
775
|
+
background: var(--bg-secondary);
|
|
776
|
+
border: 1px solid var(--border);
|
|
777
|
+
border-radius: var(--radius);
|
|
778
|
+
width: 400px;
|
|
779
|
+
max-width: calc(100vw - 32px);
|
|
780
|
+
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.4);
|
|
781
|
+
}
|
|
782
|
+
|
|
783
|
+
.modal-header {
|
|
784
|
+
display: flex;
|
|
785
|
+
align-items: center;
|
|
786
|
+
justify-content: space-between;
|
|
787
|
+
padding: 14px 16px 12px;
|
|
788
|
+
border-bottom: 1px solid var(--border);
|
|
789
|
+
}
|
|
790
|
+
|
|
791
|
+
.modal-title {
|
|
792
|
+
font-size: 13px;
|
|
793
|
+
font-weight: 600;
|
|
794
|
+
color: var(--text-primary);
|
|
795
|
+
}
|
|
796
|
+
|
|
797
|
+
.modal-close {
|
|
798
|
+
display: flex;
|
|
799
|
+
align-items: center;
|
|
800
|
+
justify-content: center;
|
|
801
|
+
width: 22px;
|
|
802
|
+
height: 22px;
|
|
803
|
+
background: transparent;
|
|
804
|
+
border: none;
|
|
805
|
+
border-radius: var(--radius-sm);
|
|
806
|
+
color: var(--text-dim);
|
|
807
|
+
font-size: 18px;
|
|
808
|
+
cursor: pointer;
|
|
809
|
+
line-height: 1;
|
|
810
|
+
transition: all var(--transition);
|
|
811
|
+
}
|
|
812
|
+
|
|
813
|
+
.modal-close:hover {
|
|
814
|
+
background: var(--bg-hover);
|
|
815
|
+
color: var(--text-primary);
|
|
816
|
+
}
|
|
817
|
+
|
|
818
|
+
.modal-body {
|
|
819
|
+
padding: 12px 16px 16px;
|
|
820
|
+
display: flex;
|
|
821
|
+
flex-direction: column;
|
|
822
|
+
gap: 16px;
|
|
823
|
+
}
|
|
824
|
+
|
|
825
|
+
.shortcut-group {
|
|
826
|
+
display: flex;
|
|
827
|
+
flex-direction: column;
|
|
828
|
+
gap: 6px;
|
|
829
|
+
}
|
|
830
|
+
|
|
831
|
+
.shortcut-group-title {
|
|
832
|
+
font-size: 11px;
|
|
833
|
+
font-weight: 600;
|
|
834
|
+
color: var(--text-dim);
|
|
835
|
+
text-transform: uppercase;
|
|
836
|
+
letter-spacing: 0.06em;
|
|
837
|
+
margin-bottom: 2px;
|
|
838
|
+
}
|
|
839
|
+
|
|
840
|
+
.shortcut-row {
|
|
841
|
+
display: flex;
|
|
842
|
+
align-items: center;
|
|
843
|
+
justify-content: space-between;
|
|
844
|
+
gap: 12px;
|
|
845
|
+
}
|
|
846
|
+
|
|
847
|
+
.shortcut-desc {
|
|
848
|
+
font-size: 12px;
|
|
849
|
+
color: var(--text-secondary);
|
|
850
|
+
}
|
|
851
|
+
|
|
852
|
+
.shortcut-key {
|
|
853
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif;
|
|
854
|
+
font-size: 11px;
|
|
855
|
+
color: var(--text-secondary);
|
|
856
|
+
background: var(--bg-tertiary);
|
|
857
|
+
border: 1px solid var(--border);
|
|
858
|
+
border-radius: var(--radius-sm);
|
|
859
|
+
padding: 2px 7px;
|
|
860
|
+
white-space: nowrap;
|
|
861
|
+
flex-shrink: 0;
|
|
862
|
+
}
|
|
863
|
+
|
|
864
|
+
/* ========== Settings Modal ========== */
|
|
865
|
+
#btn-settings {
|
|
866
|
+
display: flex;
|
|
867
|
+
align-items: center;
|
|
868
|
+
justify-content: center;
|
|
869
|
+
width: 30px;
|
|
870
|
+
height: 30px;
|
|
871
|
+
background: var(--bg-secondary);
|
|
872
|
+
border: 1px solid var(--border);
|
|
873
|
+
border-radius: var(--radius);
|
|
874
|
+
color: var(--text-secondary);
|
|
875
|
+
cursor: pointer;
|
|
876
|
+
transition: all var(--transition);
|
|
877
|
+
margin-right: 4px;
|
|
878
|
+
}
|
|
879
|
+
|
|
880
|
+
#btn-settings:hover {
|
|
881
|
+
background: var(--bg-hover);
|
|
882
|
+
color: var(--text-primary);
|
|
883
|
+
}
|
|
884
|
+
|
|
885
|
+
.settings-group {
|
|
886
|
+
display: flex;
|
|
887
|
+
flex-direction: column;
|
|
888
|
+
gap: 12px;
|
|
889
|
+
}
|
|
890
|
+
|
|
891
|
+
.settings-group-title {
|
|
892
|
+
font-size: 11px;
|
|
893
|
+
font-weight: 600;
|
|
894
|
+
text-transform: uppercase;
|
|
895
|
+
letter-spacing: 0.06em;
|
|
896
|
+
color: var(--text-dim);
|
|
897
|
+
margin-bottom: 2px;
|
|
898
|
+
}
|
|
899
|
+
|
|
900
|
+
.settings-row {
|
|
901
|
+
display: flex;
|
|
902
|
+
align-items: center;
|
|
903
|
+
justify-content: space-between;
|
|
904
|
+
gap: 12px;
|
|
905
|
+
}
|
|
906
|
+
|
|
907
|
+
.settings-label {
|
|
908
|
+
font-size: 12px;
|
|
909
|
+
color: var(--text-secondary);
|
|
910
|
+
white-space: nowrap;
|
|
911
|
+
min-width: 70px;
|
|
912
|
+
}
|
|
913
|
+
|
|
914
|
+
input[type="range"]#input-font-size {
|
|
915
|
+
flex: 1;
|
|
916
|
+
accent-color: var(--accent);
|
|
917
|
+
cursor: pointer;
|
|
918
|
+
}
|
|
919
|
+
|
|
920
|
+
.settings-text-input {
|
|
921
|
+
flex: 1;
|
|
922
|
+
background: var(--bg-tertiary);
|
|
923
|
+
border: 1px solid var(--border);
|
|
924
|
+
border-radius: var(--radius-sm);
|
|
925
|
+
color: var(--text-primary);
|
|
926
|
+
font-size: 12px;
|
|
927
|
+
padding: 4px 8px;
|
|
928
|
+
outline: none;
|
|
929
|
+
transition: border-color var(--transition);
|
|
930
|
+
}
|
|
931
|
+
|
|
932
|
+
.settings-text-input:focus {
|
|
933
|
+
border-color: var(--accent);
|
|
934
|
+
}
|
|
935
|
+
|
|
571
936
|
/* ========== Keyboard shortcut hint ========== */
|
|
572
937
|
@media (max-width: 600px) {
|
|
573
938
|
.layout-btn span {
|
package/public/index.html
CHANGED
|
@@ -11,43 +11,108 @@
|
|
|
11
11
|
<body>
|
|
12
12
|
<div id="toolbar">
|
|
13
13
|
<div class="toolbar-left">
|
|
14
|
-
<button id="btn-new-terminal" title="
|
|
15
|
-
<span class="btn-icon">+</span> New Terminal
|
|
14
|
+
<button id="btn-new-terminal" data-i18n-title="newTerminalTooltip">
|
|
15
|
+
<span class="btn-icon">+</span> <span data-i18n="newTerminal">New Terminal</span>
|
|
16
16
|
</button>
|
|
17
17
|
</div>
|
|
18
18
|
<div class="toolbar-center">
|
|
19
19
|
<div class="layout-switcher">
|
|
20
|
-
<button class="layout-btn active" data-layout="
|
|
20
|
+
<button class="layout-btn active" data-layout="columns" data-i18n-title="columns">
|
|
21
21
|
<svg width="16" height="16" viewBox="0 0 16 16"><rect x="1" y="2" width="6" height="12" rx="1" fill="currentColor" opacity="0.8"/><rect x="9" y="2" width="6" height="12" rx="1" fill="currentColor" opacity="0.5"/></svg>
|
|
22
|
-
<span>
|
|
22
|
+
<span data-i18n="columns">Columns</span>
|
|
23
23
|
</button>
|
|
24
|
-
<button class="layout-btn" data-layout="
|
|
24
|
+
<button class="layout-btn" data-layout="rows" data-i18n-title="rows">
|
|
25
|
+
<svg width="16" height="16" viewBox="0 0 16 16"><rect x="1" y="2" width="14" height="5" rx="1" fill="currentColor" opacity="0.8"/><rect x="1" y="9" width="14" height="5" rx="1" fill="currentColor" opacity="0.5"/></svg>
|
|
26
|
+
<span data-i18n="rows">Rows</span>
|
|
27
|
+
</button>
|
|
28
|
+
<button class="layout-btn" data-layout="grid" data-i18n-title="grid">
|
|
25
29
|
<svg width="16" height="16" viewBox="0 0 16 16"><rect x="1" y="1" width="6" height="6" rx="1" fill="currentColor" opacity="0.8"/><rect x="9" y="1" width="6" height="6" rx="1" fill="currentColor" opacity="0.5"/><rect x="1" y="9" width="6" height="6" rx="1" fill="currentColor" opacity="0.5"/><rect x="9" y="9" width="6" height="6" rx="1" fill="currentColor" opacity="0.3"/></svg>
|
|
26
|
-
<span>Grid</span>
|
|
30
|
+
<span data-i18n="grid">Grid</span>
|
|
27
31
|
</button>
|
|
28
|
-
<button class="layout-btn" data-layout="tabs" title="
|
|
32
|
+
<button class="layout-btn" data-layout="tabs" data-i18n-title="tabs">
|
|
29
33
|
<svg width="16" height="16" viewBox="0 0 16 16"><rect x="1" y="4" width="14" height="11" rx="1" fill="currentColor" opacity="0.3"/><rect x="1" y="2" width="6" height="4" rx="1" fill="currentColor" opacity="0.8"/><rect x="8" y="2" width="4" height="4" rx="1" fill="currentColor" opacity="0.4"/></svg>
|
|
30
|
-
<span>Tabs</span>
|
|
34
|
+
<span data-i18n="tabs">Tabs</span>
|
|
31
35
|
</button>
|
|
32
36
|
</div>
|
|
33
37
|
</div>
|
|
34
38
|
<div class="toolbar-right">
|
|
35
|
-
<
|
|
39
|
+
<div id="lang-dropdown">
|
|
40
|
+
<button id="btn-lang" title="Language">
|
|
41
|
+
<span id="btn-lang-label"></span>
|
|
42
|
+
<svg class="lang-chevron" viewBox="0 0 8 8" fill="none"><path d="M1 2.5l3 3 3-3" stroke="currentColor" stroke-width="1.4" stroke-linecap="round" stroke-linejoin="round"/></svg>
|
|
43
|
+
</button>
|
|
44
|
+
<div id="lang-menu"></div>
|
|
45
|
+
</div>
|
|
46
|
+
<button id="btn-shortcuts" data-i18n-title="shortcutsTooltip">
|
|
47
|
+
<svg width="16" height="16" viewBox="0 0 16 16" fill="none"><rect x="1" y="3" width="14" height="10" rx="1.5" stroke="currentColor" stroke-width="1.5"/><path d="M4 7h1M7 7h1M10 7h1M4 9.5h8" stroke="currentColor" stroke-width="1.2" stroke-linecap="round"/></svg>
|
|
48
|
+
</button>
|
|
49
|
+
<button id="btn-fullscreen" data-i18n-title="fullscreenTooltip">
|
|
36
50
|
<svg class="icon-enter-fs" width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M2 6V2h4M10 2h4v4M14 10v4h-4M6 14H2v-4" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg>
|
|
37
51
|
<svg class="icon-exit-fs" width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M6 2v4H2M10 6h4V2M10 14v-4h4M6 10H2v4" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg>
|
|
38
52
|
</button>
|
|
39
|
-
<button id="btn-theme-toggle" title="
|
|
53
|
+
<button id="btn-theme-toggle" data-i18n-title="toggleTheme">
|
|
40
54
|
<svg class="icon-sun" width="16" height="16" viewBox="0 0 16 16" fill="none"><circle cx="8" cy="8" r="3.5" stroke="currentColor" stroke-width="1.5"/><path d="M8 1.5v1.5M8 13v1.5M1.5 8H3M13 8h1.5M3.17 3.17l1.06 1.06M11.77 11.77l1.06 1.06M3.17 12.83l1.06-1.06M11.77 4.23l1.06-1.06" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg>
|
|
41
55
|
<svg class="icon-moon" width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M13.36 10.06A5.5 5.5 0 015.94 2.64a6 6 0 107.42 7.42z" stroke="currentColor" stroke-width="1.5" stroke-linejoin="round"/></svg>
|
|
42
56
|
</button>
|
|
43
|
-
<
|
|
57
|
+
<button id="btn-settings" data-i18n-title="settings">
|
|
58
|
+
<svg width="16" height="16" viewBox="0 0 16 16" fill="none"><line x1="1" y1="4" x2="15" y2="4" stroke="currentColor" stroke-width="1.4" stroke-linecap="round"/><line x1="1" y1="8" x2="15" y2="8" stroke="currentColor" stroke-width="1.4" stroke-linecap="round"/><line x1="1" y1="12" x2="15" y2="12" stroke="currentColor" stroke-width="1.4" stroke-linecap="round"/><circle cx="5" cy="4" r="1.8" fill="currentColor" stroke="none"/><circle cx="10" cy="8" r="1.8" fill="currentColor" stroke="none"/><circle cx="6" cy="12" r="1.8" fill="currentColor" stroke="none"/></svg>
|
|
59
|
+
</button>
|
|
44
60
|
</div>
|
|
45
61
|
</div>
|
|
46
62
|
|
|
47
63
|
<div id="tab-bar" class="hidden"></div>
|
|
48
64
|
|
|
49
65
|
<div id="main-content">
|
|
50
|
-
<div id="terminal-container" class="layout-
|
|
66
|
+
<div id="terminal-container" class="layout-columns"></div>
|
|
67
|
+
</div>
|
|
68
|
+
|
|
69
|
+
<div id="settings-modal" class="modal-overlay hidden">
|
|
70
|
+
<div class="modal">
|
|
71
|
+
<div class="modal-header">
|
|
72
|
+
<span class="modal-title" data-i18n="settingsTitle">Settings</span>
|
|
73
|
+
<button id="btn-settings-close" class="modal-close">×</button>
|
|
74
|
+
</div>
|
|
75
|
+
<div class="modal-body">
|
|
76
|
+
<div class="settings-group">
|
|
77
|
+
<div class="settings-group-title" data-i18n="settingsFont">Font</div>
|
|
78
|
+
<div class="settings-row">
|
|
79
|
+
<label class="settings-label" for="input-font-size"><span data-i18n="settingsFontSize">Size</span> <span id="font-size-value"></span></label>
|
|
80
|
+
<input type="range" id="input-font-size" min="8" max="32" step="1">
|
|
81
|
+
</div>
|
|
82
|
+
<div class="settings-row">
|
|
83
|
+
<label class="settings-label" for="input-font-family" data-i18n="settingsFontFamily">Family</label>
|
|
84
|
+
<input type="text" id="input-font-family" class="settings-text-input" data-i18n-placeholder="settingsFontFamilyPlaceholder" placeholder="e.g. Menlo, monospace">
|
|
85
|
+
</div>
|
|
86
|
+
</div>
|
|
87
|
+
</div>
|
|
88
|
+
</div>
|
|
89
|
+
</div>
|
|
90
|
+
|
|
91
|
+
<div id="shortcuts-modal" class="modal-overlay hidden">
|
|
92
|
+
<div class="modal">
|
|
93
|
+
<div class="modal-header">
|
|
94
|
+
<span class="modal-title" data-i18n="shortcutsTitle">Keyboard Shortcuts</span>
|
|
95
|
+
<button id="btn-shortcuts-close" class="modal-close">×</button>
|
|
96
|
+
</div>
|
|
97
|
+
<div class="modal-body">
|
|
98
|
+
<div class="shortcut-group">
|
|
99
|
+
<div class="shortcut-group-title" data-i18n="shortcutsGroupTerminals">Terminals</div>
|
|
100
|
+
<div class="shortcut-row"><span class="shortcut-desc" data-i18n="shortcutsNewTerminal">New Terminal</span><kbd class="shortcut-key" data-shortcut="ctrl+alt+N"></kbd></div>
|
|
101
|
+
<div class="shortcut-row"><span class="shortcut-desc" data-i18n="shortcutsCloseTerminal">Close Terminal</span><kbd class="shortcut-key" data-shortcut="ctrl+alt+W"></kbd></div>
|
|
102
|
+
<div class="shortcut-row"><span class="shortcut-desc" data-i18n="shortcutsMaximizeTerminal">Maximize / Restore Terminal</span><kbd class="shortcut-key" data-shortcut="ctrl+alt+M"></kbd></div>
|
|
103
|
+
</div>
|
|
104
|
+
<div class="shortcut-group">
|
|
105
|
+
<div class="shortcut-group-title" data-i18n="shortcutsGroupNavigation">Navigation</div>
|
|
106
|
+
<div class="shortcut-row"><span class="shortcut-desc" data-i18n="shortcutsNextTerminal">Next Terminal</span><kbd class="shortcut-key" data-shortcut="ctrl+alt+→"></kbd></div>
|
|
107
|
+
<div class="shortcut-row"><span class="shortcut-desc" data-i18n="shortcutsPrevTerminal">Previous Terminal</span><kbd class="shortcut-key" data-shortcut="ctrl+alt+←"></kbd></div>
|
|
108
|
+
<div class="shortcut-row"><span class="shortcut-desc" data-i18n="shortcutsSwitchTerminal">Switch to Terminal 1–9</span><kbd class="shortcut-key" data-shortcut="alt+1~9"></kbd></div>
|
|
109
|
+
</div>
|
|
110
|
+
<div class="shortcut-group">
|
|
111
|
+
<div class="shortcut-group-title" data-i18n="shortcutsGroupWindow">Window</div>
|
|
112
|
+
<div class="shortcut-row"><span class="shortcut-desc" data-i18n="shortcutsToggleFullscreen">Toggle Fullscreen</span><kbd class="shortcut-key" data-shortcut="F11"></kbd></div>
|
|
113
|
+
</div>
|
|
114
|
+
</div>
|
|
115
|
+
</div>
|
|
51
116
|
</div>
|
|
52
117
|
|
|
53
118
|
<script src="/vendor/xterm/xterm.js"></script>
|