@salism3/dsh-latex-editor 1.0.1 → 1.1.7

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.
Files changed (3) hide show
  1. package/README.md +2 -1
  2. package/client.js +414 -31
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -8,7 +8,8 @@ Plugin resmi untuk mengubah **DeepSeek Harness** menjadi lingkungan kerja **LaTe
8
8
 
9
9
  ## Fitur Utama
10
10
 
11
- - **Layar Terpisah (Split Screen)**: Sisi kiri percakapan AI, sisi kanan panel pratinjau dokumen PDF live dan responsif.
11
+ - **Layar Terpisah (Split Screen)**: Sisi kiri percakapan AI, sisi kanan panel pratinjau dokumen PDF live dan responsif di layar desktop.
12
+ - **Mode Mobile Responsif**: Tombol toggle cepat (`📄 PDF` ⟷ `💬 Chat`) dan tombol melayang (FAB) untuk beralih instan antara layar chat dan pratinjau PDF pada perangkat seluler/smartphone.
12
13
  - **Entry Point Baku (`main.tex`)**: Menetapkan `main.tex` di root direktori workspace sebagai titik masuk dokumen tunggal.
13
14
  - **Injeksi Soul (System Prompt)**: AI Harness secara otomatis menyusun dan memperbarui struktur dokumen lengkap dalam `main.tex`.
14
15
  - **Kompilasi Cepat**: Dilengkapi engine `xelatex` (default) dan `pdflatex` dengan panel error log interaktif.
package/client.js CHANGED
@@ -1,8 +1,6 @@
1
- window.__ModuleLoader__.load({
2
- id: '@salism3/dsh-latex-editor',
3
- factory(require) {
4
- const React = require('react');
5
- const h = React.createElement;
1
+ function defineLatexEditorPlugin(require) {
2
+ const React = require('react');
3
+ const h = React.createElement;
6
4
 
7
5
  const STYLE_ID = 'dsh-latex-editor-styles';
8
6
 
@@ -30,16 +28,77 @@ window.__ModuleLoader__.load({
30
28
  border-left: 1px solid var(--dsw-alias-border-l2, rgba(255, 255, 255, 0.12));
31
29
  }
32
30
 
31
+ .latex-btn-header-corner {
32
+ display: inline-flex !important;
33
+ align-items: center !important;
34
+ justify-content: center !important;
35
+ width: 30px !important;
36
+ height: 30px !important;
37
+ padding: 0 !important;
38
+ background: transparent !important;
39
+ color: var(--dsw-alias-text-secondary, #a6adc8) !important;
40
+ border: 1px solid transparent !important;
41
+ border-radius: 6px !important;
42
+ cursor: pointer !important;
43
+ transition: all 0.15s ease !important;
44
+ }
45
+
46
+ .latex-btn-header-corner:hover {
47
+ background: var(--dsw-alias-bg-hover, rgba(255, 255, 255, 0.08)) !important;
48
+ color: var(--dsw-alias-text-primary, #ffffff) !important;
49
+ }
50
+
51
+ .latex-btn-header-corner:active {
52
+ transform: scale(0.94) !important;
53
+ }
54
+
55
+ .latex-btn-close {
56
+ margin-left: auto !important;
57
+ color: #94a3b8 !important;
58
+ padding: 4px 8px !important;
59
+ font-size: 13px !important;
60
+ font-weight: 700 !important;
61
+ }
62
+
63
+ .latex-btn-close:hover {
64
+ color: #f87171 !important;
65
+ background: rgba(239, 68, 68, 0.15) !important;
66
+ }
67
+
68
+ /* Sembunyikan sisa tab Mulai / DockKit guide jika ada */
69
+ [data-sidebar-right-tab*="guide"],
70
+ [data-dockkit-tab*="guide"],
71
+ [data-dockkit-float-title*="Mulai"],
72
+ [class*="guideCard"] {
73
+ display: none !important;
74
+ }
75
+
33
76
  .latex-editor-header {
77
+ position: sticky !important;
78
+ top: 0 !important;
79
+ left: 0 !important;
80
+ right: 0 !important;
81
+ z-index: 1000 !important;
34
82
  display: flex;
35
83
  align-items: center;
36
84
  justify-content: space-between;
37
85
  padding: 8px 12px;
38
86
  gap: 8px;
39
- background: var(--dsw-alias-bg-elevated, #1e1e2e);
40
- border-bottom: 1px solid var(--dsw-alias-border-l2, rgba(255, 255, 255, 0.1));
87
+ background: var(--dsw-alias-bg-elevated, #1e1e2e) !important;
88
+ border-bottom: 1px solid var(--dsw-alias-border-l2, rgba(255, 255, 255, 0.15)) !important;
41
89
  flex-shrink: 0;
42
- box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);
90
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.4) !important;
91
+ }
92
+
93
+ /* Saat di conversation.view (misal di mobile): cegah scrollBody menggeser header */
94
+ [class*="viewArea"]:has(.latex-editor-container) {
95
+ height: 100% !important;
96
+ max-height: 100% !important;
97
+ overflow: hidden !important;
98
+ }
99
+
100
+ [class*="scrollBody"]:has(.latex-editor-container) {
101
+ overflow-y: hidden !important;
43
102
  }
44
103
 
45
104
  .latex-header-left {
@@ -452,15 +511,126 @@ window.__ModuleLoader__.load({
452
511
  display: none !important;
453
512
  }
454
513
 
455
- /* Pastikan track rightbar memiliki lebar yang pas untuk editor 50/50 */
456
- [data-rightbar-col] {
457
- min-width: 320px;
514
+ /* ==========================================================
515
+ 3. DESKTOP (>= 768px): 2 KOLOM SECTION TANPA TOMBOL PDF
516
+ ========================================================== */
517
+ @media (min-width: 768px) {
518
+ [data-rightbar-col] {
519
+ min-width: 300px;
520
+ }
521
+
522
+ /* Mode Desktop 2 Kolom: Sembunyikan tab / tombol PDF di header */
523
+ [role="tab"][data-tab-id="latex-pdf"],
524
+ button[role="tab"].latex-tab-pdf-button,
525
+ [role="tab"]:has([data-latex-tab="pdf"]),
526
+ [role="tab"]:has(.latex-tab-pdf) {
527
+ display: none !important;
528
+ }
529
+
530
+ /* Jika hanya tersisa Chat saat PDF disembunyikan, sembunyikan baris tabs */
531
+ [data-conversation-tabs]:has(> [role="tab"]:nth-of-type(2):is(.latex-tab-pdf-button, [data-tab-id="latex-pdf"], :has([data-latex-tab="pdf"]), :has(.latex-tab-pdf))):not(:has(> [role="tab"]:nth-of-type(3))) {
532
+ display: none !important;
533
+ }
534
+ }
535
+
536
+ /* ==========================================================
537
+ 4. MOBILE (< 768px): TAB PDF DI ATAS KANAN
538
+ ========================================================== */
539
+ @media (max-width: 767px) {
540
+ /* Di layar HP, sembunyikan handle resize dan rightbar bawaan */
541
+ [class*="handle"] {
542
+ display: none !important;
543
+ }
544
+ [data-rightbar-col] {
545
+ display: none !important;
546
+ }
547
+ [class*="centerCol"] {
548
+ display: flex !important;
549
+ width: 100vw !important;
550
+ max-width: 100vw !important;
551
+ min-width: 0 !important;
552
+ flex: 1 1 auto !important;
553
+ }
554
+
555
+ /* Header panel PDF di mobile agar tombol toolbar tetap rapi & sticky */
556
+ .latex-editor-header {
557
+ position: sticky !important;
558
+ top: 0 !important;
559
+ z-index: 1000 !important;
560
+ padding: 6px 10px !important;
561
+ gap: 5px !important;
562
+ flex-wrap: nowrap !important;
563
+ overflow-x: auto !important;
564
+ }
565
+
566
+ .latex-header-left {
567
+ gap: 5px !important;
568
+ }
569
+
570
+ .latex-btn-compile {
571
+ padding: 5px 9px !important;
572
+ font-size: 11px !important;
573
+ flex-shrink: 0 !important;
574
+ }
575
+
576
+ .latex-btn-icon {
577
+ padding: 5px 8px !important;
578
+ font-size: 11px !important;
579
+ flex-shrink: 0 !important;
580
+ }
581
+
582
+ .latex-scroll {
583
+ padding: 8px 6px 18px !important;
584
+ gap: 8px !important;
585
+ -webkit-overflow-scrolling: touch !important;
586
+ touch-action: pan-x pan-y pinch-zoom !important;
587
+ }
458
588
  }
459
589
  `;
460
590
  document.head.appendChild(style);
461
591
  }
462
592
 
463
593
  const SCROLL_STORE_KEY = 'dsh-latex-preview-scroll';
594
+ const MOBILE_VIEW_KEY = 'dsh-latex-mobile-view';
595
+
596
+ function getMobileView() {
597
+ if (typeof window === 'undefined') return 'chat';
598
+ try {
599
+ return window.sessionStorage.getItem(MOBILE_VIEW_KEY) === 'pdf' ? 'pdf' : 'chat';
600
+ } catch (e) {
601
+ return 'chat';
602
+ }
603
+ }
604
+
605
+ function setMobileView(view) {
606
+ if (typeof window === 'undefined') return;
607
+ const target = view === 'pdf' ? 'pdf' : 'chat';
608
+ try {
609
+ window.sessionStorage.setItem(MOBILE_VIEW_KEY, target);
610
+ } catch (e) {}
611
+ if (document && document.body) {
612
+ document.body.dataset.latexMobileView = target;
613
+ }
614
+ try {
615
+ window.dispatchEvent(new CustomEvent('latex-mobile-view-change', { detail: { view: target } }));
616
+ } catch (e) {}
617
+ }
618
+
619
+ function useMobileView() {
620
+ const [view, setViewState] = React.useState(getMobileView);
621
+ React.useEffect(() => {
622
+ const handler = (e) => {
623
+ if (e && e.detail && e.detail.view) {
624
+ setViewState(e.detail.view);
625
+ } else {
626
+ setViewState(getMobileView());
627
+ }
628
+ };
629
+ window.addEventListener('latex-mobile-view-change', handler);
630
+ return () => window.removeEventListener('latex-mobile-view-change', handler);
631
+ }, []);
632
+ return [view, setMobileView];
633
+ }
464
634
 
465
635
  function readStoredRatio() {
466
636
  try {
@@ -633,7 +803,7 @@ window.__ModuleLoader__.load({
633
803
  }, [hasPdf, pageCount, pdfMtime, activeWorkspace]);
634
804
 
635
805
  return h('div', { className: 'latex-editor-container' }, [
636
- // 1. Header Toolbar (Hanya compile, log, dan refresh)
806
+ // 1. Header Toolbar (Kompilasi, log, dan refresh)
637
807
  h('div', { className: 'latex-editor-header', key: 'header' }, [
638
808
  // Compile Button
639
809
  h(
@@ -673,6 +843,22 @@ window.__ModuleLoader__.load({
673
843
  },
674
844
  '🔄 Refresh'
675
845
  ),
846
+
847
+ // Tombol Tutup Panel Pratinjau
848
+ h(
849
+ 'button',
850
+ {
851
+ className: 'latex-btn-icon latex-btn-close',
852
+ onClick: () => {
853
+ if (typeof window !== 'undefined' && window.__dshLayout && typeof window.__dshLayout.closeRightbar === 'function') {
854
+ window.__dshLayout.closeRightbar();
855
+ }
856
+ },
857
+ title: 'Tutup Panel Pratinjau PDF',
858
+ key: 'btn-close-pdf',
859
+ },
860
+ '✕'
861
+ ),
676
862
  ]),
677
863
 
678
864
  // 2. Log Drawer (jika terbuka atau kompilasi gagal)
@@ -732,8 +918,16 @@ window.__ModuleLoader__.load({
732
918
  `Hal ${Math.min(currentPage, pageCount)} / ${pageCount}`
733
919
  ),
734
920
  ]
735
- : h('div', { className: 'latex-empty-state' }, [
736
- h(
921
+ : (status?.mainPdfExists
922
+ ? h('iframe', {
923
+ className: 'latex-pdf-iframe',
924
+ src: withWorkspace(`/api/latex/pdf?t=${pdfMtime}`),
925
+ style: { width: '100%', height: '100%', border: 'none', background: '#525659' },
926
+ title: 'Pratinjau PDF',
927
+ key: 'pdf-iframe-fallback',
928
+ })
929
+ : h('div', { className: 'latex-empty-state', key: 'empty' }, [
930
+ h(
737
931
  'svg',
738
932
  {
739
933
  className: 'latex-empty-icon',
@@ -770,7 +964,7 @@ window.__ModuleLoader__.load({
770
964
  },
771
965
  compiling ? 'Membuat & Mengompilasi...' : '📄 Buat Template main.tex & Compile'
772
966
  ),
773
- ])
967
+ ]))
774
968
  ),
775
969
 
776
970
  // 4. Footer Bar
@@ -787,30 +981,139 @@ window.__ModuleLoader__.load({
787
981
  ]);
788
982
  }
789
983
 
790
- return {
984
+ function LatexHeaderCornerToggle() {
985
+ const handleToggle = () => {
986
+ try {
987
+ const col = document.querySelector('[data-rightbar-col]');
988
+ const isOpen = col && col.offsetWidth > 40 && window.getComputedStyle(col).display !== 'none';
989
+ if (isOpen) {
990
+ if (ctx.layout && typeof ctx.layout.closeRightbar === 'function') {
991
+ ctx.layout.closeRightbar();
992
+ }
993
+ } else {
994
+ if (ctx.sidebarRight && typeof ctx.sidebarRight.openTab === 'function') {
995
+ ctx.sidebarRight.openTab('latex-preview');
996
+ } else if (ctx.layout && typeof ctx.layout.openRightbar === 'function') {
997
+ ctx.layout.openRightbar(true, false);
998
+ }
999
+ }
1000
+ } catch (e) {
1001
+ if (ctx.layout && typeof ctx.layout.openRightbar === 'function') {
1002
+ ctx.layout.openRightbar(true, false);
1003
+ }
1004
+ }
1005
+ };
1006
+
1007
+ return h(
1008
+ 'button',
1009
+ {
1010
+ type: 'button',
1011
+ className: 'latex-btn-header-corner',
1012
+ onClick: handleToggle,
1013
+ title: 'Buka / Tutup Pratinjau PDF',
1014
+ 'aria-label': 'Toggle Preview PDF',
1015
+ key: 'latex-corner-toggle',
1016
+ },
1017
+ h(
1018
+ 'svg',
1019
+ {
1020
+ width: 16,
1021
+ height: 16,
1022
+ viewBox: '0 0 24 24',
1023
+ fill: 'none',
1024
+ stroke: 'currentColor',
1025
+ strokeWidth: 2,
1026
+ strokeLinecap: 'round',
1027
+ strokeLinejoin: 'round',
1028
+ },
1029
+ [
1030
+ h('rect', { x: 3, y: 3, width: 18, height: 18, rx: 2, ry: 2, key: 'r' }),
1031
+ h('line', { x1: 15, y1: 3, x2: 15, y2: 21, key: 'l' }),
1032
+ ]
1033
+ )
1034
+ );
1035
+ }
1036
+
1037
+ const pluginInstance = {
791
1038
  inject: ['slots', 'layout'],
792
1039
  apply(ctx) {
793
- // 1. Suntikkan stylesheet kustom untuk layout split & pembersihan fitur non-essential
1040
+ // 1. Simpan layout helper ke window untuk interaksi UI
1041
+ if (typeof window !== 'undefined') {
1042
+ window.__dshLayout = ctx.layout;
1043
+ }
1044
+
1045
+ // 2. Suntikkan stylesheet kustom untuk layout split, responsive mobile, & pembersihan fitur non-essential
794
1046
  injectStyles();
795
1047
 
796
- // 2. Pastikan Rightbar selalu terbuka dengan track terpasang (Split Screen)
1048
+ // 3. Inisialisasi status tampilan mobile pada dokumen
1049
+ if (typeof document !== 'undefined' && document.body) {
1050
+ document.body.dataset.latexMobileView = getMobileView();
1051
+ }
1052
+
1053
+ // 4. Buka split screen di desktop saat pertama kali memuat
797
1054
  if (ctx.layout && typeof ctx.layout.openRightbar === 'function') {
798
- const ensureSplit = () => {
1055
+ try {
1056
+ ctx.layout.openRightbar(true, false);
1057
+ } catch (e) {}
1058
+ }
1059
+
1060
+ // 5. Daftarkan tab jenis 'latex-preview' ke dalam sistem sidebarRight bawaan DSH
1061
+ ctx.inject(['sidebarRightTabs', 'sidebarRight'], () => {
1062
+ try {
1063
+ ctx.sidebarRightTabs.register({
1064
+ id: '@salism3/dsh-latex-editor/tab',
1065
+ kind: 'latex-preview',
1066
+ title: () => 'Pratinjau PDF',
1067
+ guide: [
1068
+ {
1069
+ id: 'latex-pdf-entry',
1070
+ order: 1,
1071
+ title: () => 'Pratinjau PDF LaTeX',
1072
+ description: () => 'Buka pratinjau dokumen PDF secara langsung',
1073
+ icon: () => h('span', { style: { fontSize: '18px' } }, '📄'),
1074
+ },
1075
+ ],
1076
+ });
1077
+ } catch (e) {
1078
+ console.warn('[latex-editor] sidebarRightTabs.register error:', e);
1079
+ }
1080
+
1081
+ // Buka tab latex-preview sebagai tab aktif di panel kanan
1082
+ const activatePdfTab = () => {
799
1083
  try {
800
- ctx.layout.openRightbar(true, false);
1084
+ if (ctx.sidebarRight && typeof ctx.sidebarRight.openTab === 'function') {
1085
+ ctx.sidebarRight.openTab('latex-preview');
1086
+ }
801
1087
  } catch (e) {}
802
1088
  };
803
1089
 
804
- ensureSplit();
805
-
806
- // Pertahankan split screen aktif saat terjadi perpindahan view atau session
807
- const interval = setInterval(ensureSplit, 1500);
808
- ctx.effect(() => () => clearInterval(interval));
809
- }
1090
+ activatePdfTab();
1091
+ setTimeout(activatePdfTab, 400);
1092
+ });
810
1093
 
811
- // 3. Daftarkan panel pratinjau PDF ke dalam slot 'rightbar' dengan prioritas tertinggi (prioritas angka terendah menang)
1094
+ // 6. Daftarkan konten panel pratinjau PDF ke dalam slot 'sidebar.right.pane.tab'
812
1095
  if (ctx.slots && typeof ctx.slots.inject === 'function') {
813
- ctx.slots.inject('root', () =>
1096
+ ctx.slots.inject('sidebar.right.pane.tab', () =>
1097
+ ctx.slots.register(
1098
+ {
1099
+ name: 'sidebar.right.pane.tab',
1100
+ key: '@salism3/dsh-latex-editor/tab',
1101
+ },
1102
+ LatexPdfPreviewPane
1103
+ )
1104
+ );
1105
+
1106
+ ctx.slots.inject('sidebar.right.pane.tab.title', () =>
1107
+ ctx.slots.register(
1108
+ {
1109
+ name: 'sidebar.right.pane.tab.title',
1110
+ key: '@salism3/dsh-latex-editor/tab',
1111
+ },
1112
+ () => '📄 Pratinjau PDF'
1113
+ )
1114
+ );
1115
+
1116
+ ctx.slots.inject('rightbar', () =>
814
1117
  ctx.slots.register(
815
1118
  {
816
1119
  name: 'rightbar',
@@ -819,9 +1122,71 @@ window.__ModuleLoader__.load({
819
1122
  LatexPdfPreviewPane
820
1123
  )
821
1124
  );
1125
+
1126
+ // Override tombol toggle corner [|] di kanan atas sesi untuk buka/tutup PDF Preview
1127
+ ctx.slots.inject('conversation.session.header.corner', () =>
1128
+ ctx.slots.register(
1129
+ {
1130
+ name: 'conversation.session.header.corner',
1131
+ priority: -100,
1132
+ },
1133
+ LatexHeaderCornerToggle
1134
+ )
1135
+ );
1136
+
1137
+ // Daftarkan tab PDF ke dalam slot 'conversation.view' (untuk mode mobile)
1138
+ ctx.slots.inject('conversation.view', () =>
1139
+ ctx.slots.register(
1140
+ {
1141
+ name: 'conversation.view',
1142
+ id: 'latex-pdf',
1143
+ order: 20,
1144
+ label: () => 'PDF',
1145
+ },
1146
+ LatexPdfPreviewPane
1147
+ )
1148
+ );
822
1149
  }
823
1150
 
824
- // 4. Tambah workspace: sekali klik langsung membuat workspace + folder,
1151
+ // 6. Kontrol tombol PDF: sembunyikan saat mode desktop (>= 768px), tampilkan saat mobile (< 768px)
1152
+ if (typeof document !== 'undefined') {
1153
+ const updateDesktopPdfTab = () => {
1154
+ const isDesktop = typeof window !== 'undefined' && window.innerWidth >= 768;
1155
+ const tabs = document.querySelectorAll('[role="tab"]');
1156
+ for (const tab of tabs) {
1157
+ const text = (tab.textContent || '').trim();
1158
+ if (text === 'PDF' || text.includes('PDF') || tab.getAttribute('data-tab-id') === 'latex-pdf') {
1159
+ tab.classList.add('latex-tab-pdf-button');
1160
+ tab.setAttribute('data-tab-id', 'latex-pdf');
1161
+ if (isDesktop) {
1162
+ tab.style.setProperty('display', 'none', 'important');
1163
+ } else {
1164
+ tab.style.removeProperty('display');
1165
+ }
1166
+ }
1167
+ }
1168
+ };
1169
+
1170
+ updateDesktopPdfTab();
1171
+ const tabInterval = setInterval(updateDesktopPdfTab, 300);
1172
+ window.addEventListener('resize', updateDesktopPdfTab);
1173
+
1174
+ const removeOldButtons = () => {
1175
+ const old1 = document.getElementById('dsh-latex-top-toggle');
1176
+ if (old1 && old1.parentNode) old1.parentNode.removeChild(old1);
1177
+ const old2 = document.getElementById('dsh-latex-mobile-fab');
1178
+ if (old2 && old2.parentNode) old2.parentNode.removeChild(old2);
1179
+ };
1180
+ removeOldButtons();
1181
+
1182
+ ctx.effect(() => () => {
1183
+ clearInterval(tabInterval);
1184
+ window.removeEventListener('resize', updateDesktopPdfTab);
1185
+ removeOldButtons();
1186
+ });
1187
+ }
1188
+
1189
+ // 7. Tambah workspace: sekali klik langsung membuat workspace + folder,
825
1190
  // tanpa membuka dialog pemilih folder.
826
1191
  if (typeof document !== 'undefined') {
827
1192
  ctx.effect(() => {
@@ -867,5 +1232,23 @@ window.__ModuleLoader__.load({
867
1232
  }
868
1233
  },
869
1234
  };
870
- },
871
- });
1235
+
1236
+ return {
1237
+ __esModule: true,
1238
+ default: pluginInstance,
1239
+ inject: pluginInstance.inject,
1240
+ apply: pluginInstance.apply,
1241
+ };
1242
+ }
1243
+
1244
+ if (typeof window !== 'undefined' && window.__ModuleLoader__ && typeof window.__ModuleLoader__.load === 'function') {
1245
+ window.__ModuleLoader__.load({
1246
+ id: '@local/dsh-latex-editor',
1247
+ factory: defineLatexEditorPlugin,
1248
+ });
1249
+
1250
+ window.__ModuleLoader__.load({
1251
+ id: '@salism3/dsh-latex-editor',
1252
+ factory: defineLatexEditorPlugin,
1253
+ });
1254
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@salism3/dsh-latex-editor",
3
- "version": "1.0.1",
3
+ "version": "1.1.7",
4
4
  "description": "DeepSeek Harness LaTeX Editor with AI - Split screen chat & live PDF preview, main.tex compiler, and soul injection",
5
5
  "author": "salism3",
6
6
  "license": "MIT",