@design.estate/dees-catalog 3.35.1 → 3.37.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.
Files changed (29) hide show
  1. package/dist_bundle/bundle.js +1391 -247
  2. package/dist_ts_web/00_commitinfo_data.js +1 -1
  3. package/dist_ts_web/elements/00group-button/dees-button/dees-button.d.ts +6 -0
  4. package/dist_ts_web/elements/00group-button/dees-button/dees-button.demo.js +69 -29
  5. package/dist_ts_web/elements/00group-button/dees-button/dees-button.js +75 -6
  6. package/dist_ts_web/elements/00group-chart/dees-chart-log/dees-chart-log.d.ts +104 -6
  7. package/dist_ts_web/elements/00group-chart/dees-chart-log/dees-chart-log.demo.js +153 -54
  8. package/dist_ts_web/elements/00group-chart/dees-chart-log/dees-chart-log.js +716 -153
  9. package/dist_ts_web/elements/dees-statsgrid/dees-statsgrid.d.ts +22 -1
  10. package/dist_ts_web/elements/dees-statsgrid/dees-statsgrid.demo.js +130 -2
  11. package/dist_ts_web/elements/dees-statsgrid/dees-statsgrid.js +322 -1
  12. package/dist_ts_web/services/DeesServiceLibLoader.d.ts +34 -1
  13. package/dist_ts_web/services/DeesServiceLibLoader.js +27 -1
  14. package/dist_ts_web/services/index.d.ts +1 -1
  15. package/dist_ts_web/services/versions.d.ts +1 -0
  16. package/dist_ts_web/services/versions.js +2 -1
  17. package/dist_watch/bundle.js +1389 -245
  18. package/dist_watch/bundle.js.map +3 -3
  19. package/package.json +1 -1
  20. package/ts_web/00_commitinfo_data.ts +1 -1
  21. package/ts_web/elements/00group-button/dees-button/dees-button.demo.ts +68 -28
  22. package/ts_web/elements/00group-button/dees-button/dees-button.ts +78 -6
  23. package/ts_web/elements/00group-chart/dees-chart-log/dees-chart-log.demo.ts +163 -56
  24. package/ts_web/elements/00group-chart/dees-chart-log/dees-chart-log.ts +756 -161
  25. package/ts_web/elements/dees-statsgrid/dees-statsgrid.demo.ts +130 -2
  26. package/ts_web/elements/dees-statsgrid/dees-statsgrid.ts +352 -1
  27. package/ts_web/services/DeesServiceLibLoader.ts +50 -1
  28. package/ts_web/services/index.ts +1 -1
  29. package/ts_web/services/versions.ts +1 -0
@@ -1,7 +1,7 @@
1
1
  import { html, css, cssManager } from '@design.estate/dees-element';
2
2
  import '@design.estate/dees-wcctools/demotools';
3
3
  import '../dees-panel/dees-panel.js';
4
- import type { IStatsTile, ICpuCore } from '../dees-statsgrid/dees-statsgrid.js';
4
+ import type { IStatsTile, ICpuCore, IPartitionData, IDiskData } from '../dees-statsgrid/dees-statsgrid.js';
5
5
 
6
6
  // Helper function to generate random CPU core data
7
7
  const generateCpuCores = (count: number): ICpuCore[] => {
@@ -601,8 +601,136 @@ html\`
601
601
  ></dees-statsgrid>
602
602
  \`;`}</div>
603
603
  </dees-panel>
604
+
605
+ <dees-panel .title=${'7. Disk & Storage Tiles'} .subtitle=${'Partition and physical disk visualization tiles'}>
606
+ <dees-statsgrid
607
+ .tiles=${[
608
+ {
609
+ id: 'root-partition',
610
+ title: 'Root Partition',
611
+ value: 0,
612
+ type: 'partition',
613
+ icon: 'lucide:folder-root',
614
+ partitionData: {
615
+ used: 698_341_425_152, // ~650 GB
616
+ total: 1_073_741_824_000, // ~1 TB
617
+ filesystem: 'ext4',
618
+ mountPoint: '/'
619
+ }
620
+ },
621
+ {
622
+ id: 'home-partition',
623
+ title: 'Home Partition',
624
+ value: 0,
625
+ type: 'partition',
626
+ icon: 'lucide:home',
627
+ partitionData: {
628
+ used: 214_748_364_800, // ~200 GB
629
+ total: 536_870_912_000, // ~500 GB
630
+ filesystem: 'ext4',
631
+ mountPoint: '/home'
632
+ }
633
+ },
634
+ {
635
+ id: 'data-partition',
636
+ title: 'Data Partition',
637
+ value: 0,
638
+ type: 'partition',
639
+ icon: 'lucide:database',
640
+ partitionData: {
641
+ used: 1_932_735_283_200, // ~1.8 TB (90% - critical)
642
+ total: 2_147_483_648_000, // ~2 TB
643
+ filesystem: 'xfs',
644
+ mountPoint: '/data'
645
+ }
646
+ },
647
+ {
648
+ id: 'nvme-ssd',
649
+ title: 'Primary NVMe',
650
+ value: 0,
651
+ type: 'disk',
652
+ icon: 'lucide:hard-drive',
653
+ columnSpan: 2,
654
+ diskData: {
655
+ capacity: 2_000_000_000_000, // 2 TB
656
+ model: 'Samsung 990 Pro',
657
+ type: 'nvme',
658
+ iops: {
659
+ read: 7450,
660
+ write: 6900
661
+ },
662
+ health: 98
663
+ }
664
+ },
665
+ {
666
+ id: 'sata-ssd',
667
+ title: 'Secondary SSD',
668
+ value: 0,
669
+ type: 'disk',
670
+ icon: 'lucide:hard-drive',
671
+ diskData: {
672
+ capacity: 1_000_000_000_000, // 1 TB
673
+ model: 'Crucial MX500',
674
+ type: 'ssd',
675
+ iops: {
676
+ read: 560,
677
+ write: 510
678
+ },
679
+ health: 85
680
+ }
681
+ },
682
+ {
683
+ id: 'hdd-storage',
684
+ title: 'Backup HDD',
685
+ value: 0,
686
+ type: 'disk',
687
+ icon: 'lucide:archive',
688
+ diskData: {
689
+ capacity: 8_000_000_000_000, // 8 TB
690
+ model: 'Seagate IronWolf',
691
+ type: 'hdd',
692
+ iops: {
693
+ read: 210,
694
+ write: 195
695
+ },
696
+ health: 42
697
+ }
698
+ }
699
+ ]}
700
+ .minTileWidth=${280}
701
+ .gap=${16}
702
+ ></dees-statsgrid>
703
+
704
+ <div class="tile-config">
705
+ <div class="config-section">
706
+ <div class="config-title">Partition Tile Properties</div>
707
+ <div class="config-description">
708
+ <ul style="margin: 8px 0; padding-left: 20px;">
709
+ <li><strong>partitionData.used:</strong> Used space in bytes (auto-formatted)</li>
710
+ <li><strong>partitionData.total:</strong> Total capacity in bytes</li>
711
+ <li><strong>partitionData.filesystem:</strong> Filesystem type (ext4, xfs, ntfs)</li>
712
+ <li><strong>partitionData.mountPoint:</strong> Mount point path (optional)</li>
713
+ </ul>
714
+ Color thresholds: Normal (&lt;75%), Warning (75-90%), Critical (&gt;90%)
715
+ </div>
716
+ </div>
717
+ <div class="config-section">
718
+ <div class="config-title">Disk Tile Properties</div>
719
+ <div class="config-description">
720
+ <ul style="margin: 8px 0; padding-left: 20px;">
721
+ <li><strong>diskData.capacity:</strong> Total capacity in bytes</li>
722
+ <li><strong>diskData.model:</strong> Disk model name (optional)</li>
723
+ <li><strong>diskData.type:</strong> Disk type: 'ssd', 'hdd', or 'nvme'</li>
724
+ <li><strong>diskData.iops:</strong> Read/write IOPS (optional)</li>
725
+ <li><strong>diskData.health:</strong> Health percentage 0-100 (optional)</li>
726
+ </ul>
727
+ Health thresholds: Good (70-100%), Warning (30-70%), Critical (&lt;30%)
728
+ </div>
729
+ </div>
730
+ </div>
731
+ </dees-panel>
604
732
  </div>
605
-
733
+
606
734
  <script>
607
735
  // Cleanup live updates on page unload
608
736
  window.addEventListener('beforeunload', () => {
@@ -30,12 +30,30 @@ export interface ICpuCore {
30
30
  label?: string;
31
31
  }
32
32
 
33
+ export interface IPartitionData {
34
+ used: number; // bytes
35
+ total: number; // bytes
36
+ filesystem: string; // e.g., 'ext4', 'NTFS', 'btrfs'
37
+ mountPoint?: string; // e.g., '/', '/home', 'C:'
38
+ }
39
+
40
+ export interface IDiskData {
41
+ capacity: number; // bytes
42
+ model?: string; // e.g., 'Samsung 970 EVO Plus'
43
+ type?: 'ssd' | 'hdd' | 'nvme';
44
+ iops?: {
45
+ read: number;
46
+ write: number;
47
+ };
48
+ health?: number; // 0-100 (100 = new, 0 = end of life)
49
+ }
50
+
33
51
  export interface IStatsTile {
34
52
  id: string;
35
53
  title: string;
36
54
  value: number | string;
37
55
  unit?: string;
38
- type: 'number' | 'gauge' | 'percentage' | 'trend' | 'text' | 'multiPercentage' | 'cpuCores';
56
+ type: 'number' | 'gauge' | 'percentage' | 'trend' | 'text' | 'multiPercentage' | 'cpuCores' | 'partition' | 'disk';
39
57
 
40
58
  // Layout options
41
59
  columnSpan?: number; // Number of columns to span (default: 1)
@@ -60,6 +78,12 @@ export interface IStatsTile {
60
78
  // For cpuCores type
61
79
  coresData?: ICpuCore[];
62
80
 
81
+ // For partition type
82
+ partitionData?: IPartitionData;
83
+
84
+ // For disk type
85
+ diskData?: IDiskData;
86
+
63
87
  // Visual customization
64
88
  color?: string;
65
89
  icon?: string;
@@ -485,6 +509,219 @@ export class DeesStatsGrid extends DeesElement {
485
509
  max-width: 100%;
486
510
  }
487
511
 
512
+ /* Partition Styles */
513
+ .partition-wrapper {
514
+ width: 100%;
515
+ display: flex;
516
+ flex-direction: column;
517
+ flex: 1;
518
+ gap: 8px;
519
+ }
520
+
521
+ .partition-header {
522
+ display: flex;
523
+ align-items: baseline;
524
+ gap: 8px;
525
+ }
526
+
527
+ .partition-percentage {
528
+ font-size: var(--value-font-size);
529
+ font-weight: 600;
530
+ color: ${cssManager.bdTheme('hsl(215.3 25% 8.8%)', 'hsl(210 40% 98%)')};
531
+ line-height: 1.1;
532
+ letter-spacing: -0.025em;
533
+ }
534
+
535
+ .partition-bar {
536
+ width: 100%;
537
+ height: 6px;
538
+ background: ${cssManager.bdTheme('#e8e8e8', '#1a1a1a')};
539
+ border-radius: 3px;
540
+ overflow: hidden;
541
+ }
542
+
543
+ .partition-bar-fill {
544
+ height: 100%;
545
+ background: ${cssManager.bdTheme('#333333', '#e0e0e0')};
546
+ transition: width 0.6s cubic-bezier(0.4, 0, 0.2, 1);
547
+ border-radius: 3px;
548
+ }
549
+
550
+ .partition-bar-fill.warning {
551
+ background: ${cssManager.bdTheme('hsl(45.4 93.4% 47.5%)', 'hsl(45.4 93.4% 47.5%)')};
552
+ }
553
+
554
+ .partition-bar-fill.critical {
555
+ background: ${cssManager.bdTheme('hsl(0 84.2% 60.2%)', 'hsl(0 84.2% 60.2%)')};
556
+ }
557
+
558
+ .partition-stats {
559
+ display: flex;
560
+ justify-content: space-between;
561
+ align-items: center;
562
+ margin-top: auto;
563
+ }
564
+
565
+ .partition-stat {
566
+ display: flex;
567
+ flex-direction: column;
568
+ gap: 2px;
569
+ }
570
+
571
+ .partition-stat-label {
572
+ font-size: 10px;
573
+ font-weight: 500;
574
+ color: ${cssManager.bdTheme('hsl(215.4 16.3% 56.9%)', 'hsl(215 20.2% 55.1%)')};
575
+ text-transform: uppercase;
576
+ letter-spacing: 0.02em;
577
+ }
578
+
579
+ .partition-stat-value {
580
+ font-size: 13px;
581
+ font-weight: 600;
582
+ color: ${cssManager.bdTheme('hsl(215.3 25% 8.8%)', 'hsl(210 40% 98%)')};
583
+ letter-spacing: -0.01em;
584
+ }
585
+
586
+ .partition-meta {
587
+ display: flex;
588
+ align-items: center;
589
+ gap: 6px;
590
+ margin-top: 4px;
591
+ }
592
+
593
+ .partition-filesystem {
594
+ font-size: 11px;
595
+ font-weight: 500;
596
+ color: ${cssManager.bdTheme('hsl(215.4 16.3% 46.9%)', 'hsl(215 20.2% 65.1%)')};
597
+ background: ${cssManager.bdTheme('hsl(210 40% 96.1%)', 'hsl(215 20.2% 16.8%)')};
598
+ padding: 2px 6px;
599
+ border-radius: 3px;
600
+ }
601
+
602
+ .partition-mountpoint {
603
+ font-size: 11px;
604
+ color: ${cssManager.bdTheme('hsl(215.4 16.3% 56.9%)', 'hsl(215 20.2% 55.1%)')};
605
+ }
606
+
607
+ /* Disk Styles */
608
+ .disk-wrapper {
609
+ width: 100%;
610
+ display: flex;
611
+ flex-direction: column;
612
+ flex: 1;
613
+ gap: 8px;
614
+ }
615
+
616
+ .disk-capacity {
617
+ font-size: var(--value-font-size);
618
+ font-weight: 600;
619
+ color: ${cssManager.bdTheme('hsl(215.3 25% 8.8%)', 'hsl(210 40% 98%)')};
620
+ line-height: 1.1;
621
+ letter-spacing: -0.025em;
622
+ }
623
+
624
+ .disk-model {
625
+ font-size: 12px;
626
+ color: ${cssManager.bdTheme('hsl(215.4 16.3% 46.9%)', 'hsl(215 20.2% 65.1%)')};
627
+ display: flex;
628
+ align-items: center;
629
+ gap: 6px;
630
+ }
631
+
632
+ .disk-type-badge {
633
+ font-size: 10px;
634
+ font-weight: 600;
635
+ text-transform: uppercase;
636
+ color: ${cssManager.bdTheme('hsl(215.4 16.3% 46.9%)', 'hsl(215 20.2% 65.1%)')};
637
+ background: ${cssManager.bdTheme('hsl(210 40% 96.1%)', 'hsl(215 20.2% 16.8%)')};
638
+ padding: 2px 6px;
639
+ border-radius: 3px;
640
+ }
641
+
642
+ .disk-metrics {
643
+ display: flex;
644
+ flex-direction: column;
645
+ gap: 8px;
646
+ margin-top: auto;
647
+ }
648
+
649
+ .disk-iops {
650
+ display: flex;
651
+ align-items: center;
652
+ gap: 12px;
653
+ }
654
+
655
+ .disk-iops-item {
656
+ display: flex;
657
+ align-items: baseline;
658
+ gap: 4px;
659
+ }
660
+
661
+ .disk-iops-label {
662
+ font-size: 10px;
663
+ font-weight: 500;
664
+ color: ${cssManager.bdTheme('hsl(215.4 16.3% 56.9%)', 'hsl(215 20.2% 55.1%)')};
665
+ text-transform: uppercase;
666
+ }
667
+
668
+ .disk-iops-value {
669
+ font-size: 13px;
670
+ font-weight: 600;
671
+ color: ${cssManager.bdTheme('hsl(215.3 25% 8.8%)', 'hsl(210 40% 98%)')};
672
+ }
673
+
674
+ .disk-health {
675
+ display: flex;
676
+ flex-direction: column;
677
+ gap: 4px;
678
+ }
679
+
680
+ .disk-health-header {
681
+ display: flex;
682
+ justify-content: space-between;
683
+ align-items: baseline;
684
+ }
685
+
686
+ .disk-health-label {
687
+ font-size: 10px;
688
+ font-weight: 500;
689
+ color: ${cssManager.bdTheme('hsl(215.4 16.3% 56.9%)', 'hsl(215 20.2% 55.1%)')};
690
+ text-transform: uppercase;
691
+ }
692
+
693
+ .disk-health-value {
694
+ font-size: 12px;
695
+ font-weight: 600;
696
+ color: ${cssManager.bdTheme('hsl(215.3 25% 8.8%)', 'hsl(210 40% 98%)')};
697
+ }
698
+
699
+ .disk-health-bar {
700
+ width: 100%;
701
+ height: 4px;
702
+ background: ${cssManager.bdTheme('#e8e8e8', '#1a1a1a')};
703
+ border-radius: 2px;
704
+ overflow: hidden;
705
+ }
706
+
707
+ .disk-health-fill {
708
+ height: 100%;
709
+ transition: width 0.6s cubic-bezier(0.4, 0, 0.2, 1);
710
+ border-radius: 2px;
711
+ }
712
+
713
+ .disk-health-fill.good {
714
+ background: ${cssManager.bdTheme('hsl(142.1 76.2% 36.3%)', 'hsl(142.1 70.6% 45.3%)')};
715
+ }
716
+
717
+ .disk-health-fill.warning {
718
+ background: ${cssManager.bdTheme('hsl(45.4 93.4% 47.5%)', 'hsl(45.4 93.4% 47.5%)')};
719
+ }
720
+
721
+ .disk-health-fill.critical {
722
+ background: ${cssManager.bdTheme('hsl(0 84.2% 60.2%)', 'hsl(0 84.2% 60.2%)')};
723
+ }
724
+
488
725
  /* Trend Styles */
489
726
  .trend-container {
490
727
  width: 100%;
@@ -659,6 +896,12 @@ export class DeesStatsGrid extends DeesElement {
659
896
  case 'cpuCores':
660
897
  return this.renderCpuCores(tile);
661
898
 
899
+ case 'partition':
900
+ return this.renderPartition(tile);
901
+
902
+ case 'disk':
903
+ return this.renderDisk(tile);
904
+
662
905
  case 'text':
663
906
  return html`
664
907
  <div class="text-value" style="${tile.color ? `color: ${tile.color}` : ''}">
@@ -876,6 +1119,114 @@ export class DeesStatsGrid extends DeesElement {
876
1119
  `;
877
1120
  }
878
1121
 
1122
+ private formatBytes(bytes: number): string {
1123
+ if (bytes === 0) return '0 B';
1124
+ const k = 1024;
1125
+ const sizes = ['B', 'KB', 'MB', 'GB', 'TB', 'PB'];
1126
+ const i = Math.floor(Math.log(bytes) / Math.log(k));
1127
+ return parseFloat((bytes / Math.pow(k, i)).toFixed(1)) + ' ' + sizes[i];
1128
+ }
1129
+
1130
+ private renderPartition(tile: IStatsTile): TemplateResult {
1131
+ if (!tile.partitionData) {
1132
+ return html`<div class="tile-value">${tile.value}</div>`;
1133
+ }
1134
+
1135
+ const { used, total, filesystem, mountPoint } = tile.partitionData;
1136
+ const percentage = Math.min(100, Math.max(0, (used / total) * 100));
1137
+ const free = total - used;
1138
+
1139
+ // Determine color class based on usage
1140
+ const getColorClass = (): string => {
1141
+ if (percentage >= 90) return 'critical';
1142
+ if (percentage >= 75) return 'warning';
1143
+ return '';
1144
+ };
1145
+
1146
+ return html`
1147
+ <div class="partition-wrapper">
1148
+ <div class="partition-header">
1149
+ <span class="partition-percentage">${Math.round(percentage)}%</span>
1150
+ </div>
1151
+ <div class="partition-bar">
1152
+ <div
1153
+ class="partition-bar-fill ${getColorClass()}"
1154
+ style="width: ${percentage}%"
1155
+ ></div>
1156
+ </div>
1157
+ <div class="partition-stats">
1158
+ <div class="partition-stat">
1159
+ <span class="partition-stat-label">Used</span>
1160
+ <span class="partition-stat-value">${this.formatBytes(used)}</span>
1161
+ </div>
1162
+ <div class="partition-stat">
1163
+ <span class="partition-stat-label">Free</span>
1164
+ <span class="partition-stat-value">${this.formatBytes(free)}</span>
1165
+ </div>
1166
+ </div>
1167
+ <div class="partition-meta">
1168
+ <span class="partition-filesystem">${filesystem}</span>
1169
+ ${mountPoint ? html`<span class="partition-mountpoint">${mountPoint}</span>` : ''}
1170
+ </div>
1171
+ </div>
1172
+ `;
1173
+ }
1174
+
1175
+ private renderDisk(tile: IStatsTile): TemplateResult {
1176
+ if (!tile.diskData) {
1177
+ return html`<div class="tile-value">${tile.value}</div>`;
1178
+ }
1179
+
1180
+ const { capacity, model, type, iops, health } = tile.diskData;
1181
+
1182
+ // Determine health color class (inverted - high is good)
1183
+ const getHealthClass = (value: number): string => {
1184
+ if (value >= 70) return 'good';
1185
+ if (value >= 30) return 'warning';
1186
+ return 'critical';
1187
+ };
1188
+
1189
+ return html`
1190
+ <div class="disk-wrapper">
1191
+ <div class="disk-capacity">${this.formatBytes(capacity)}</div>
1192
+ ${model || type ? html`
1193
+ <div class="disk-model">
1194
+ ${model ? html`<span>${model}</span>` : ''}
1195
+ ${type ? html`<span class="disk-type-badge">${type}</span>` : ''}
1196
+ </div>
1197
+ ` : ''}
1198
+ <div class="disk-metrics">
1199
+ ${iops ? html`
1200
+ <div class="disk-iops">
1201
+ <div class="disk-iops-item">
1202
+ <span class="disk-iops-label">Read</span>
1203
+ <span class="disk-iops-value">${iops.read.toLocaleString()}</span>
1204
+ </div>
1205
+ <div class="disk-iops-item">
1206
+ <span class="disk-iops-label">Write</span>
1207
+ <span class="disk-iops-value">${iops.write.toLocaleString()}</span>
1208
+ </div>
1209
+ </div>
1210
+ ` : ''}
1211
+ ${health !== undefined ? html`
1212
+ <div class="disk-health">
1213
+ <div class="disk-health-header">
1214
+ <span class="disk-health-label">Health</span>
1215
+ <span class="disk-health-value">${health}%</span>
1216
+ </div>
1217
+ <div class="disk-health-bar">
1218
+ <div
1219
+ class="disk-health-fill ${getHealthClass(health)}"
1220
+ style="width: ${health}%"
1221
+ ></div>
1222
+ </div>
1223
+ </div>
1224
+ ` : ''}
1225
+ </div>
1226
+ </div>
1227
+ `;
1228
+ }
1229
+
879
1230
  private async handleGridAction(action: plugins.tsclass.website.IMenuItem) {
880
1231
  if (action.action) {
881
1232
  await action.action();
@@ -25,6 +25,24 @@ export interface IXtermFitAddonBundle {
25
25
  FitAddon: typeof FitAddon;
26
26
  }
27
27
 
28
+ /**
29
+ * Bundle type for xterm-addon-search
30
+ * SearchAddon is loaded from CDN, so we use a minimal interface
31
+ */
32
+ export interface IXtermSearchAddonBundle {
33
+ SearchAddon: new () => IXtermSearchAddon;
34
+ }
35
+
36
+ /**
37
+ * Minimal interface for xterm SearchAddon
38
+ */
39
+ export interface IXtermSearchAddon {
40
+ activate(terminal: Terminal): void;
41
+ dispose(): void;
42
+ findNext(term: string, searchOptions?: { regex?: boolean; wholeWord?: boolean; caseSensitive?: boolean; incremental?: boolean }): boolean;
43
+ findPrevious(term: string, searchOptions?: { regex?: boolean; wholeWord?: boolean; caseSensitive?: boolean; incremental?: boolean }): boolean;
44
+ }
45
+
28
46
  /**
29
47
  * Bundle type for Tiptap editor and extensions
30
48
  */
@@ -56,6 +74,7 @@ export class DeesServiceLibLoader {
56
74
  // Cached library references
57
75
  private xtermLib: IXtermBundle | null = null;
58
76
  private xtermFitAddonLib: IXtermFitAddonBundle | null = null;
77
+ private xtermSearchAddonLib: IXtermSearchAddonBundle | null = null;
59
78
  private highlightJsLib: HLJSApi | null = null;
60
79
  private apexChartsLib: typeof ApexChartsType | null = null;
61
80
  private tiptapLib: ITiptapBundle | null = null;
@@ -63,6 +82,7 @@ export class DeesServiceLibLoader {
63
82
  // Loading promises to prevent duplicate concurrent loads
64
83
  private xtermLoadingPromise: Promise<IXtermBundle> | null = null;
65
84
  private xtermFitAddonLoadingPromise: Promise<IXtermFitAddonBundle> | null = null;
85
+ private xtermSearchAddonLoadingPromise: Promise<IXtermSearchAddonBundle> | null = null;
66
86
  private highlightJsLoadingPromise: Promise<HLJSApi> | null = null;
67
87
  private apexChartsLoadingPromise: Promise<typeof ApexChartsType> | null = null;
68
88
  private tiptapLoadingPromise: Promise<ITiptapBundle> | null = null;
@@ -134,6 +154,32 @@ export class DeesServiceLibLoader {
134
154
  return this.xtermFitAddonLoadingPromise;
135
155
  }
136
156
 
157
+ /**
158
+ * Load xterm-addon-search from CDN
159
+ * @returns Promise resolving to SearchAddon class
160
+ */
161
+ public async loadXtermSearchAddon(): Promise<IXtermSearchAddonBundle> {
162
+ if (this.xtermSearchAddonLib) {
163
+ return this.xtermSearchAddonLib;
164
+ }
165
+
166
+ if (this.xtermSearchAddonLoadingPromise) {
167
+ return this.xtermSearchAddonLoadingPromise;
168
+ }
169
+
170
+ this.xtermSearchAddonLoadingPromise = (async () => {
171
+ const url = `${CDN_BASE}/xterm-addon-search@${CDN_VERSIONS.xtermAddonSearch}/+esm`;
172
+ const module = await import(/* @vite-ignore */ url);
173
+
174
+ this.xtermSearchAddonLib = {
175
+ SearchAddon: module.SearchAddon,
176
+ };
177
+ return this.xtermSearchAddonLib;
178
+ })();
179
+
180
+ return this.xtermSearchAddonLoadingPromise;
181
+ }
182
+
137
183
  /**
138
184
  * Inject xterm CSS styles into the document head
139
185
  */
@@ -257,6 +303,7 @@ export class DeesServiceLibLoader {
257
303
  await Promise.all([
258
304
  this.loadXterm(),
259
305
  this.loadXtermFitAddon(),
306
+ this.loadXtermSearchAddon(),
260
307
  this.loadHighlightJs(),
261
308
  this.loadApexCharts(),
262
309
  this.loadTiptap(),
@@ -266,12 +313,14 @@ export class DeesServiceLibLoader {
266
313
  /**
267
314
  * Check if a specific library is already loaded
268
315
  */
269
- public isLoaded(library: 'xterm' | 'xtermFitAddon' | 'highlightJs' | 'apexCharts' | 'tiptap'): boolean {
316
+ public isLoaded(library: 'xterm' | 'xtermFitAddon' | 'xtermSearchAddon' | 'highlightJs' | 'apexCharts' | 'tiptap'): boolean {
270
317
  switch (library) {
271
318
  case 'xterm':
272
319
  return this.xtermLib !== null;
273
320
  case 'xtermFitAddon':
274
321
  return this.xtermFitAddonLib !== null;
322
+ case 'xtermSearchAddon':
323
+ return this.xtermSearchAddonLib !== null;
275
324
  case 'highlightJs':
276
325
  return this.highlightJsLib !== null;
277
326
  case 'apexCharts':
@@ -1,3 +1,3 @@
1
1
  export { DeesServiceLibLoader } from './DeesServiceLibLoader.js';
2
- export type { IXtermBundle, IXtermFitAddonBundle, ITiptapBundle } from './DeesServiceLibLoader.js';
2
+ export type { IXtermBundle, IXtermFitAddonBundle, IXtermSearchAddonBundle, IXtermSearchAddon, ITiptapBundle } from './DeesServiceLibLoader.js';
3
3
  export { CDN_BASE, CDN_VERSIONS } from './versions.js';
@@ -5,6 +5,7 @@
5
5
  export const CDN_VERSIONS = {
6
6
  xterm: '5.3.0',
7
7
  xtermAddonFit: '0.8.0',
8
+ xtermAddonSearch: '0.13.0',
8
9
  highlightJs: '11.11.1',
9
10
  apexcharts: '5.3.6',
10
11
  tiptap: '2.23.0',