jupyterlab_vscode_icons_extension 1.0.69 → 1.0.77

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/lib/index.js +128 -7
  2. package/package.json +1 -1
  3. package/src/index.ts +129 -6
package/lib/index.js CHANGED
@@ -229,6 +229,21 @@ const fileTypeConfigs = [
229
229
  iconName: 'file-type-pdf',
230
230
  group: 'enableDocIcons'
231
231
  },
232
+ {
233
+ extensions: ['.doc', '.docx'],
234
+ iconName: 'file-type-word',
235
+ group: 'enableDocIcons'
236
+ },
237
+ {
238
+ extensions: ['.xls', '.xlsx'],
239
+ iconName: 'file-type-excel',
240
+ group: 'enableDocIcons'
241
+ },
242
+ {
243
+ extensions: ['.ppt', '.pptx'],
244
+ iconName: 'file-type-powerpoint',
245
+ group: 'enableDocIcons'
246
+ },
232
247
  // Config Files
233
248
  {
234
249
  extensions: ['.env'],
@@ -337,12 +352,32 @@ const plugin = {
337
352
  const { docRegistry } = app;
338
353
  // Function to inject CSS that overrides Jupytext icons
339
354
  const injectIconOverrideCSS = () => {
340
- // Get icons: Python (custom SVG), Markdown (custom SVG), Claude (VSCode), README (custom)
355
+ // Get icons: Claude (VSCode), Office (VSCode)
341
356
  const claudeIcon = createLabIcon('file-type-claude');
357
+ const wordIcon = createLabIcon('file-type-word');
358
+ const excelIcon = createLabIcon('file-type-excel');
359
+ const powerpointIcon = createLabIcon('file-type-powerpoint');
342
360
  // Custom Markdown icon (from markdown.svg - purple M with arrow, darker #7a2491)
343
361
  const markdownSvg = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 309 327">
344
362
  <path fill="#7a2491" opacity="1" stroke="none" d="m 138.68393,230.48651 c 36.58836,3.1e-4 72.68422,3.1e-4 108.78008,3.1e-4 0.13988,0.49669 0.0821,0.12537 -3.34406,3.81472 -27.34165,24.16766 -54.43119,49.41695 -81.72391,73.62893 -2.65146,2.35216 -4.5582,3.21609 -7.64686,0.37229 -26.89754,-24.76539 -75.191307,-68.40096 -80.889724,-74.12425 -0.744118,-0.74735 -1.274501,-1.57204 -2.95867,-3.69233 23.309236,0 45.299954,0 67.783144,3.3e-4 z"/>
345
363
  <path fill="#7a2491" d="m 61.156397,14.443673 h 69.176263 q 14.81059,56.661581 23.29958,97.452667 l 5.96036,-27.150338 q 3.61233,-15.870486 7.76652,-30.954008 l 10.6564,-39.348321 H 248.6367 L 276.09047,189.5437 H 221.90541 L 207.27544,69.137838 173.50009,189.5437 H 136.47364 L 101.07273,68.875516 86.984609,189.5437 H 35.147571 Z"/>
364
+ </svg>`;
365
+ // Custom PDF icon (document with folded corner and red PDF banner)
366
+ const pdfSvg = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 14 16">
367
+ <g transform="matrix(.046 0 0 .046 -.67 -.73)">
368
+ <polygon points="52 357 52 24 205 24 283 102 283 357" fill="#e8e8e8"/>
369
+ <path d="m198 32v76h76v240H52V32h146m10-16H36v365h247V98z"/>
370
+ <polygon points="258 88 220 88 220 49 258 86"/>
371
+ </g>
372
+ <g transform="matrix(.046 0 0 .046 -.67 -.73)">
373
+ <polygon points="312 284 23 284 23 168 37 153 37 171 297 171 297 153 312 168" fill="#ed1c24"/>
374
+ <path d="m304 169l2 2v108H24V171l2-2v9h278v-9m-13-31v28H43v-28l-28 28v126h302V166z"/>
375
+ </g>
376
+ <g transform="matrix(.046 0 0 .046 1.72 11.73)" fill="#fff">
377
+ <path d="M9-83h30q7 0 13 1 6 1 11 5 5 3 7 9 3 5 3 13 0 8-3 13-3 6-7 9-5 4-11 5-6 2-13 2h-9v26H9zm22 39h8q7 0 10-3 3-3 3-9t-4-8-10-2h-7z"/>
378
+ <path d="M87-83h25q9 0 17 2 8 3 14 8 6 5 9 13 3 8 3 19t-3 19-9 13q-6 5-13 8-8 2-17 2H87zm22 66h1q5 0 9-1 4-1 7-4 3-3 5-8 2-4 2-12t-2-12-5-7q-3-3-7-4-4-1-9-1h-1z"/>
379
+ <path d="M169-83h54v18h-32v16h28v18h-28v31h-22z"/>
380
+ </g>
346
381
  </svg>`;
347
382
  // Custom Python icon (simplified official logo - 50% reduced fidelity)
348
383
  const pythonSvg = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 110 110">
@@ -363,13 +398,20 @@ const plugin = {
363
398
  const readmeSvg = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
364
399
  <path fill="#912bac" d="m 9.5247234,11.42511 v 76.943619 l 2.1166666,2.116667 h 77.809717 l 2.116667,-2.116667 v -76.94362 l -2.116667,-2.1166662 -77.809717,0 z m 36.2115596,9.141612 h 11.01003 l 2.116667,2.116667 0,7.619586 -2.116667,2.116667 h -11.01003 l -2.116667,-2.116667 v -7.619586 z m -6.168542,19.478681 h 23.084596 l 2.116667,2.116667 v 5.700733 l -2.116597,2.09951 -3.175139,-0.02574 -2.116597,2.09951 V 67.32187 l 2.116667,2.116667 h 4.211629 l 2.116667,2.116667 v 5.567219 L 63.688967,79.23909 H 38.509408 l -2.116667,-2.116667 v -6.096386 l 2.116667,-2.116667 h 4.968955 L 45.59503,66.792703 V 52.096294 l -2.116667,-2.116667 h -3.910622 l -2.116667,-2.116667 0,-5.70089 z"/>
365
400
  </svg>`;
366
- // Get SVG content
401
+ // Get SVG content from VSCode icons
367
402
  const claudeSvg = claudeIcon.svgstr;
403
+ const wordSvg = (wordIcon === null || wordIcon === void 0 ? void 0 : wordIcon.svgstr) || '';
404
+ const excelSvg = (excelIcon === null || excelIcon === void 0 ? void 0 : excelIcon.svgstr) || '';
405
+ const powerpointSvg = (powerpointIcon === null || powerpointIcon === void 0 ? void 0 : powerpointIcon.svgstr) || '';
368
406
  // Create base64 encoded data URIs
369
407
  const pythonDataUri = `data:image/svg+xml;base64,${btoa(pythonSvg)}`;
370
408
  const markdownDataUri = `data:image/svg+xml;base64,${btoa(markdownSvg)}`;
371
409
  const claudeDataUri = `data:image/svg+xml;base64,${btoa(claudeSvg)}`;
372
410
  const readmeDataUri = `data:image/svg+xml;base64,${btoa(readmeSvg)}`;
411
+ const pdfDataUri = `data:image/svg+xml;base64,${btoa(pdfSvg)}`;
412
+ const wordDataUri = wordSvg ? `data:image/svg+xml;base64,${btoa(wordSvg)}` : '';
413
+ const excelDataUri = excelSvg ? `data:image/svg+xml;base64,${btoa(excelSvg)}` : '';
414
+ const powerpointDataUri = powerpointSvg ? `data:image/svg+xml;base64,${btoa(powerpointSvg)}` : '';
373
415
  // Inject CSS that overrides icons for .py and .md files
374
416
  // Note: Jupytext marks .py and .md files as type="notebook", so we need to
375
417
  // use JavaScript to detect and mark these files for CSS targeting
@@ -445,6 +487,70 @@ const plugin = {
445
487
  background-repeat: no-repeat;
446
488
  background-position: center;
447
489
  }
490
+
491
+ /* Override PDF file icon with VSCode PDF icon */
492
+ .jp-DirListing-item[data-vscode-pdf] .jp-DirListing-itemIcon svg,
493
+ .jp-DirListing-item[data-vscode-pdf] .jp-DirListing-itemIcon img {
494
+ display: none !important;
495
+ }
496
+ .jp-DirListing-item[data-vscode-pdf] .jp-DirListing-itemIcon::before {
497
+ content: '';
498
+ display: inline-block;
499
+ width: calc(var(--jp-ui-font-size1, 13px) * var(--jp-custom-icon-scale, 1.5));
500
+ height: calc(var(--jp-ui-font-size1, 13px) * var(--jp-custom-icon-scale, 1.5));
501
+ background-image: url('${pdfDataUri}');
502
+ background-size: contain;
503
+ background-repeat: no-repeat;
504
+ background-position: center;
505
+ }
506
+
507
+ /* Override Word file icon with VSCode Word icon */
508
+ .jp-DirListing-item[data-vscode-word] .jp-DirListing-itemIcon svg,
509
+ .jp-DirListing-item[data-vscode-word] .jp-DirListing-itemIcon img {
510
+ display: none !important;
511
+ }
512
+ .jp-DirListing-item[data-vscode-word] .jp-DirListing-itemIcon::before {
513
+ content: '';
514
+ display: inline-block;
515
+ width: calc(var(--jp-ui-font-size1, 13px) * var(--jp-custom-icon-scale, 1.5));
516
+ height: calc(var(--jp-ui-font-size1, 13px) * var(--jp-custom-icon-scale, 1.5));
517
+ background-image: url('${wordDataUri}');
518
+ background-size: contain;
519
+ background-repeat: no-repeat;
520
+ background-position: center;
521
+ }
522
+
523
+ /* Override Excel file icon with VSCode Excel icon */
524
+ .jp-DirListing-item[data-vscode-excel] .jp-DirListing-itemIcon svg,
525
+ .jp-DirListing-item[data-vscode-excel] .jp-DirListing-itemIcon img {
526
+ display: none !important;
527
+ }
528
+ .jp-DirListing-item[data-vscode-excel] .jp-DirListing-itemIcon::before {
529
+ content: '';
530
+ display: inline-block;
531
+ width: calc(var(--jp-ui-font-size1, 13px) * var(--jp-custom-icon-scale, 1.5));
532
+ height: calc(var(--jp-ui-font-size1, 13px) * var(--jp-custom-icon-scale, 1.5));
533
+ background-image: url('${excelDataUri}');
534
+ background-size: contain;
535
+ background-repeat: no-repeat;
536
+ background-position: center;
537
+ }
538
+
539
+ /* Override PowerPoint file icon with VSCode PowerPoint icon */
540
+ .jp-DirListing-item[data-vscode-powerpoint] .jp-DirListing-itemIcon svg,
541
+ .jp-DirListing-item[data-vscode-powerpoint] .jp-DirListing-itemIcon img {
542
+ display: none !important;
543
+ }
544
+ .jp-DirListing-item[data-vscode-powerpoint] .jp-DirListing-itemIcon::before {
545
+ content: '';
546
+ display: inline-block;
547
+ width: calc(var(--jp-ui-font-size1, 13px) * var(--jp-custom-icon-scale, 1.5));
548
+ height: calc(var(--jp-ui-font-size1, 13px) * var(--jp-custom-icon-scale, 1.5));
549
+ background-image: url('${powerpointDataUri}');
550
+ background-size: contain;
551
+ background-repeat: no-repeat;
552
+ background-position: center;
553
+ }
448
554
  `;
449
555
  // Add CSS to make JavaScript and .env icons less bright
450
556
  style.textContent += `
@@ -531,6 +637,26 @@ const plugin = {
531
637
  // Not a shell file - always clear shell-type attribute
532
638
  item.removeAttribute('data-shell-type');
533
639
  }
640
+ // Handle PDF and Office files by extension (override native JupyterLab icons)
641
+ const nameLower = name.toLowerCase();
642
+ // Clear all office/pdf attributes first
643
+ item.removeAttribute('data-vscode-pdf');
644
+ item.removeAttribute('data-vscode-word');
645
+ item.removeAttribute('data-vscode-excel');
646
+ item.removeAttribute('data-vscode-powerpoint');
647
+ // Set the correct attribute based on extension
648
+ if (nameLower.endsWith('.pdf')) {
649
+ item.setAttribute('data-vscode-pdf', 'true');
650
+ }
651
+ else if (nameLower.endsWith('.doc') || nameLower.endsWith('.docx')) {
652
+ item.setAttribute('data-vscode-word', 'true');
653
+ }
654
+ else if (nameLower.endsWith('.xls') || nameLower.endsWith('.xlsx')) {
655
+ item.setAttribute('data-vscode-excel', 'true');
656
+ }
657
+ else if (nameLower.endsWith('.ppt') || nameLower.endsWith('.pptx')) {
658
+ item.setAttribute('data-vscode-powerpoint', 'true');
659
+ }
534
660
  });
535
661
  };
536
662
  // Watch for changes in the file browser
@@ -570,7 +696,6 @@ const plugin = {
570
696
  };
571
697
  // Function to register file types based on settings
572
698
  const registerFileTypes = () => {
573
- var _a;
574
699
  // Clear existing registrations by re-registering
575
700
  fileTypeConfigs.forEach(config => {
576
701
  // Check if this group is enabled
@@ -631,9 +756,7 @@ const plugin = {
631
756
  });
632
757
  // Register CLAUDE.md with Claude icon (always register, not conditional on settings)
633
758
  const claudeIcon = createLabIcon('file-type-claude');
634
- console.log('[VSCode Icons] CLAUDE.md icon created:', !!claudeIcon);
635
759
  if (claudeIcon) {
636
- console.log('[VSCode Icons] CLAUDE.md icon svgstr length:', ((_a = claudeIcon.svgstr) === null || _a === void 0 ? void 0 : _a.length) || 0);
637
760
  docRegistry.addFileType({
638
761
  name: 'vscode-claude-md',
639
762
  displayName: 'Claude Configuration',
@@ -642,7 +765,6 @@ const plugin = {
642
765
  contentType: 'file',
643
766
  icon: claudeIcon
644
767
  });
645
- console.log('[VSCode Icons] CLAUDE.md file type registered with pattern: ^CLAUDE\\.md$');
646
768
  }
647
769
  else {
648
770
  console.error('[VSCode Icons] Failed to create CLAUDE.md icon');
@@ -664,7 +786,6 @@ const plugin = {
664
786
  contentType: 'file',
665
787
  icon: readmeIcon
666
788
  });
667
- console.log('[VSCode Icons] README.md file type registered with pattern: ^README\\.md$');
668
789
  };
669
790
  // Debounce timer for settings change alert
670
791
  let settingsChangeTimeout = null;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jupyterlab_vscode_icons_extension",
3
- "version": "1.0.69",
3
+ "version": "1.0.77",
4
4
  "description": "Jupyterlab extension with a shameless rip-off of the vscode-icons into our beloved environment",
5
5
  "keywords": [
6
6
  "jupyter",
package/src/index.ts CHANGED
@@ -260,6 +260,21 @@ const fileTypeConfigs: IFileTypeConfig[] = [
260
260
  iconName: 'file-type-pdf',
261
261
  group: 'enableDocIcons'
262
262
  },
263
+ {
264
+ extensions: ['.doc', '.docx'],
265
+ iconName: 'file-type-word',
266
+ group: 'enableDocIcons'
267
+ },
268
+ {
269
+ extensions: ['.xls', '.xlsx'],
270
+ iconName: 'file-type-excel',
271
+ group: 'enableDocIcons'
272
+ },
273
+ {
274
+ extensions: ['.ppt', '.pptx'],
275
+ iconName: 'file-type-powerpoint',
276
+ group: 'enableDocIcons'
277
+ },
263
278
 
264
279
  // Config Files
265
280
  {
@@ -378,8 +393,11 @@ const plugin: JupyterFrontEndPlugin<void> = {
378
393
  // Function to inject CSS that overrides Jupytext icons
379
394
  const injectIconOverrideCSS = () => {
380
395
 
381
- // Get icons: Python (custom SVG), Markdown (custom SVG), Claude (VSCode), README (custom)
396
+ // Get icons: Claude (VSCode), Office (VSCode)
382
397
  const claudeIcon = createLabIcon('file-type-claude');
398
+ const wordIcon = createLabIcon('file-type-word');
399
+ const excelIcon = createLabIcon('file-type-excel');
400
+ const powerpointIcon = createLabIcon('file-type-powerpoint');
383
401
 
384
402
  // Custom Markdown icon (from markdown.svg - purple M with arrow, darker #7a2491)
385
403
  const markdownSvg = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 309 327">
@@ -387,6 +405,24 @@ const plugin: JupyterFrontEndPlugin<void> = {
387
405
  <path fill="#7a2491" d="m 61.156397,14.443673 h 69.176263 q 14.81059,56.661581 23.29958,97.452667 l 5.96036,-27.150338 q 3.61233,-15.870486 7.76652,-30.954008 l 10.6564,-39.348321 H 248.6367 L 276.09047,189.5437 H 221.90541 L 207.27544,69.137838 173.50009,189.5437 H 136.47364 L 101.07273,68.875516 86.984609,189.5437 H 35.147571 Z"/>
388
406
  </svg>`;
389
407
 
408
+ // Custom PDF icon (document with folded corner and red PDF banner)
409
+ const pdfSvg = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 14 16">
410
+ <g transform="matrix(.046 0 0 .046 -.67 -.73)">
411
+ <polygon points="52 357 52 24 205 24 283 102 283 357" fill="#e8e8e8"/>
412
+ <path d="m198 32v76h76v240H52V32h146m10-16H36v365h247V98z"/>
413
+ <polygon points="258 88 220 88 220 49 258 86"/>
414
+ </g>
415
+ <g transform="matrix(.046 0 0 .046 -.67 -.73)">
416
+ <polygon points="312 284 23 284 23 168 37 153 37 171 297 171 297 153 312 168" fill="#ed1c24"/>
417
+ <path d="m304 169l2 2v108H24V171l2-2v9h278v-9m-13-31v28H43v-28l-28 28v126h302V166z"/>
418
+ </g>
419
+ <g transform="matrix(.046 0 0 .046 1.72 11.73)" fill="#fff">
420
+ <path d="M9-83h30q7 0 13 1 6 1 11 5 5 3 7 9 3 5 3 13 0 8-3 13-3 6-7 9-5 4-11 5-6 2-13 2h-9v26H9zm22 39h8q7 0 10-3 3-3 3-9t-4-8-10-2h-7z"/>
421
+ <path d="M87-83h25q9 0 17 2 8 3 14 8 6 5 9 13 3 8 3 19t-3 19-9 13q-6 5-13 8-8 2-17 2H87zm22 66h1q5 0 9-1 4-1 7-4 3-3 5-8 2-4 2-12t-2-12-5-7q-3-3-7-4-4-1-9-1h-1z"/>
422
+ <path d="M169-83h54v18h-32v16h28v18h-28v31h-22z"/>
423
+ </g>
424
+ </svg>`;
425
+
390
426
  // Custom Python icon (simplified official logo - 50% reduced fidelity)
391
427
  const pythonSvg = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 110 110">
392
428
  <defs>
@@ -408,14 +444,21 @@ const plugin: JupyterFrontEndPlugin<void> = {
408
444
  <path fill="#912bac" d="m 9.5247234,11.42511 v 76.943619 l 2.1166666,2.116667 h 77.809717 l 2.116667,-2.116667 v -76.94362 l -2.116667,-2.1166662 -77.809717,0 z m 36.2115596,9.141612 h 11.01003 l 2.116667,2.116667 0,7.619586 -2.116667,2.116667 h -11.01003 l -2.116667,-2.116667 v -7.619586 z m -6.168542,19.478681 h 23.084596 l 2.116667,2.116667 v 5.700733 l -2.116597,2.09951 -3.175139,-0.02574 -2.116597,2.09951 V 67.32187 l 2.116667,2.116667 h 4.211629 l 2.116667,2.116667 v 5.567219 L 63.688967,79.23909 H 38.509408 l -2.116667,-2.116667 v -6.096386 l 2.116667,-2.116667 h 4.968955 L 45.59503,66.792703 V 52.096294 l -2.116667,-2.116667 h -3.910622 l -2.116667,-2.116667 0,-5.70089 z"/>
409
445
  </svg>`;
410
446
 
411
- // Get SVG content
447
+ // Get SVG content from VSCode icons
412
448
  const claudeSvg = claudeIcon.svgstr;
449
+ const wordSvg = wordIcon?.svgstr || '';
450
+ const excelSvg = excelIcon?.svgstr || '';
451
+ const powerpointSvg = powerpointIcon?.svgstr || '';
413
452
 
414
453
  // Create base64 encoded data URIs
415
454
  const pythonDataUri = `data:image/svg+xml;base64,${btoa(pythonSvg)}`;
416
455
  const markdownDataUri = `data:image/svg+xml;base64,${btoa(markdownSvg)}`;
417
456
  const claudeDataUri = `data:image/svg+xml;base64,${btoa(claudeSvg)}`;
418
457
  const readmeDataUri = `data:image/svg+xml;base64,${btoa(readmeSvg)}`;
458
+ const pdfDataUri = `data:image/svg+xml;base64,${btoa(pdfSvg)}`;
459
+ const wordDataUri = wordSvg ? `data:image/svg+xml;base64,${btoa(wordSvg)}` : '';
460
+ const excelDataUri = excelSvg ? `data:image/svg+xml;base64,${btoa(excelSvg)}` : '';
461
+ const powerpointDataUri = powerpointSvg ? `data:image/svg+xml;base64,${btoa(powerpointSvg)}` : '';
419
462
 
420
463
  // Inject CSS that overrides icons for .py and .md files
421
464
  // Note: Jupytext marks .py and .md files as type="notebook", so we need to
@@ -492,6 +535,70 @@ const plugin: JupyterFrontEndPlugin<void> = {
492
535
  background-repeat: no-repeat;
493
536
  background-position: center;
494
537
  }
538
+
539
+ /* Override PDF file icon with VSCode PDF icon */
540
+ .jp-DirListing-item[data-vscode-pdf] .jp-DirListing-itemIcon svg,
541
+ .jp-DirListing-item[data-vscode-pdf] .jp-DirListing-itemIcon img {
542
+ display: none !important;
543
+ }
544
+ .jp-DirListing-item[data-vscode-pdf] .jp-DirListing-itemIcon::before {
545
+ content: '';
546
+ display: inline-block;
547
+ width: calc(var(--jp-ui-font-size1, 13px) * var(--jp-custom-icon-scale, 1.5));
548
+ height: calc(var(--jp-ui-font-size1, 13px) * var(--jp-custom-icon-scale, 1.5));
549
+ background-image: url('${pdfDataUri}');
550
+ background-size: contain;
551
+ background-repeat: no-repeat;
552
+ background-position: center;
553
+ }
554
+
555
+ /* Override Word file icon with VSCode Word icon */
556
+ .jp-DirListing-item[data-vscode-word] .jp-DirListing-itemIcon svg,
557
+ .jp-DirListing-item[data-vscode-word] .jp-DirListing-itemIcon img {
558
+ display: none !important;
559
+ }
560
+ .jp-DirListing-item[data-vscode-word] .jp-DirListing-itemIcon::before {
561
+ content: '';
562
+ display: inline-block;
563
+ width: calc(var(--jp-ui-font-size1, 13px) * var(--jp-custom-icon-scale, 1.5));
564
+ height: calc(var(--jp-ui-font-size1, 13px) * var(--jp-custom-icon-scale, 1.5));
565
+ background-image: url('${wordDataUri}');
566
+ background-size: contain;
567
+ background-repeat: no-repeat;
568
+ background-position: center;
569
+ }
570
+
571
+ /* Override Excel file icon with VSCode Excel icon */
572
+ .jp-DirListing-item[data-vscode-excel] .jp-DirListing-itemIcon svg,
573
+ .jp-DirListing-item[data-vscode-excel] .jp-DirListing-itemIcon img {
574
+ display: none !important;
575
+ }
576
+ .jp-DirListing-item[data-vscode-excel] .jp-DirListing-itemIcon::before {
577
+ content: '';
578
+ display: inline-block;
579
+ width: calc(var(--jp-ui-font-size1, 13px) * var(--jp-custom-icon-scale, 1.5));
580
+ height: calc(var(--jp-ui-font-size1, 13px) * var(--jp-custom-icon-scale, 1.5));
581
+ background-image: url('${excelDataUri}');
582
+ background-size: contain;
583
+ background-repeat: no-repeat;
584
+ background-position: center;
585
+ }
586
+
587
+ /* Override PowerPoint file icon with VSCode PowerPoint icon */
588
+ .jp-DirListing-item[data-vscode-powerpoint] .jp-DirListing-itemIcon svg,
589
+ .jp-DirListing-item[data-vscode-powerpoint] .jp-DirListing-itemIcon img {
590
+ display: none !important;
591
+ }
592
+ .jp-DirListing-item[data-vscode-powerpoint] .jp-DirListing-itemIcon::before {
593
+ content: '';
594
+ display: inline-block;
595
+ width: calc(var(--jp-ui-font-size1, 13px) * var(--jp-custom-icon-scale, 1.5));
596
+ height: calc(var(--jp-ui-font-size1, 13px) * var(--jp-custom-icon-scale, 1.5));
597
+ background-image: url('${powerpointDataUri}');
598
+ background-size: contain;
599
+ background-repeat: no-repeat;
600
+ background-position: center;
601
+ }
495
602
  `;
496
603
 
497
604
  // Add CSS to make JavaScript and .env icons less bright
@@ -580,6 +687,26 @@ const plugin: JupyterFrontEndPlugin<void> = {
580
687
  // Not a shell file - always clear shell-type attribute
581
688
  item.removeAttribute('data-shell-type');
582
689
  }
690
+
691
+ // Handle PDF and Office files by extension (override native JupyterLab icons)
692
+ const nameLower = name.toLowerCase();
693
+
694
+ // Clear all office/pdf attributes first
695
+ item.removeAttribute('data-vscode-pdf');
696
+ item.removeAttribute('data-vscode-word');
697
+ item.removeAttribute('data-vscode-excel');
698
+ item.removeAttribute('data-vscode-powerpoint');
699
+
700
+ // Set the correct attribute based on extension
701
+ if (nameLower.endsWith('.pdf')) {
702
+ item.setAttribute('data-vscode-pdf', 'true');
703
+ } else if (nameLower.endsWith('.doc') || nameLower.endsWith('.docx')) {
704
+ item.setAttribute('data-vscode-word', 'true');
705
+ } else if (nameLower.endsWith('.xls') || nameLower.endsWith('.xlsx')) {
706
+ item.setAttribute('data-vscode-excel', 'true');
707
+ } else if (nameLower.endsWith('.ppt') || nameLower.endsWith('.pptx')) {
708
+ item.setAttribute('data-vscode-powerpoint', 'true');
709
+ }
583
710
  });
584
711
  };
585
712
 
@@ -700,9 +827,7 @@ const plugin: JupyterFrontEndPlugin<void> = {
700
827
 
701
828
  // Register CLAUDE.md with Claude icon (always register, not conditional on settings)
702
829
  const claudeIcon = createLabIcon('file-type-claude');
703
- console.log('[VSCode Icons] CLAUDE.md icon created:', !!claudeIcon);
704
830
  if (claudeIcon) {
705
- console.log('[VSCode Icons] CLAUDE.md icon svgstr length:', claudeIcon.svgstr?.length || 0);
706
831
  docRegistry.addFileType({
707
832
  name: 'vscode-claude-md',
708
833
  displayName: 'Claude Configuration',
@@ -711,7 +836,6 @@ const plugin: JupyterFrontEndPlugin<void> = {
711
836
  contentType: 'file',
712
837
  icon: claudeIcon
713
838
  });
714
- console.log('[VSCode Icons] CLAUDE.md file type registered with pattern: ^CLAUDE\\.md$');
715
839
  } else {
716
840
  console.error('[VSCode Icons] Failed to create CLAUDE.md icon');
717
841
  }
@@ -735,7 +859,6 @@ const plugin: JupyterFrontEndPlugin<void> = {
735
859
  contentType: 'file',
736
860
  icon: readmeIcon
737
861
  });
738
- console.log('[VSCode Icons] README.md file type registered with pattern: ^README\\.md$');
739
862
  };
740
863
 
741
864
  // Debounce timer for settings change alert