Skip to content

Commit 920f9d2

Browse files
committed
feat: Update folder icon and enhance sidebar button styling for improved visual consistency
1 parent 62853e3 commit 920f9d2

File tree

4 files changed

+252
-109
lines changed

4 files changed

+252
-109
lines changed

index.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ <h3>EXPLORER</h3>
8181

8282
<div class="sidebar-select">
8383
<button class="btn-select-dir" id="selectDirBtn">
84-
<img src="public/arrowRight.svg" alt="Select Directory" class="sidebar-btn-icon" />
84+
<img src="public/folder.svg" alt="Select Directory" class="sidebar-btn-icon" />
8585
Select Directory
8686
</button>
8787
</div>

index.js

Lines changed: 244 additions & 106 deletions
Original file line numberDiff line numberDiff line change
@@ -537,28 +537,229 @@
537537
// Get icon for file or folder
538538
const ico = (name, isFolder) => {
539539
if (isFolder) {
540+
// Check for special folder names
541+
const folderName = name.toLowerCase();
542+
const folderIcon = FOLDER_ICONS[folderName] || FOLDER_ICONS['default'];
540543
return {
541544
type: 'svg',
542-
url: 'public/arrowRight.svg',
543-
color: '',
545+
url: ICON_BASE_URL + folderIcon.icon,
546+
color: folderIcon.color,
544547
cls: 'folder-icon'
545548
};
546549
}
547-
// File icon by extension
550+
// File icon
551+
const fileName = name.toLowerCase();
552+
// ========================================
553+
// SPRING BOOT / JAVA SPECIAL FILES
554+
// ========================================
555+
if (fileName === 'pom.xml') {
556+
return {
557+
type: 'svg',
558+
url: ICON_BASE_URL + 'maven.svg',
559+
color: '#c71a36',
560+
cls: 'maven-icon'
561+
};
562+
}
563+
if (fileName === 'build.gradle' || fileName === 'build.gradle.kts' || fileName === 'settings.gradle' || fileName === 'settings.gradle.kts') {
564+
return {
565+
type: 'svg',
566+
url: ICON_BASE_URL + 'gradle.svg',
567+
color: '#02303a',
568+
cls: 'gradle-icon'
569+
};
570+
}
571+
if (fileName === 'application.properties' || fileName === 'application.yml' || fileName === 'application.yaml') {
572+
return {
573+
type: 'svg',
574+
url: ICON_BASE_URL + 'spring.svg',
575+
color: '#6db33f',
576+
cls: 'spring-icon'
577+
};
578+
}
579+
if (fileName.startsWith('application-') && (fileName.endsWith('.properties') || fileName.endsWith('.yml') || fileName.endsWith('.yaml'))) {
580+
return {
581+
type: 'svg',
582+
url: ICON_BASE_URL + 'spring.svg',
583+
color: '#6db33f',
584+
cls: 'spring-icon'
585+
};
586+
}
587+
// ========================================
588+
// PYTHON SPECIAL FILES
589+
// ========================================
590+
if (fileName === 'requirements.txt' || fileName === 'requirements-dev.txt') {
591+
return {
592+
type: 'svg',
593+
url: ICON_BASE_URL + 'python.svg',
594+
color: '#3776ab',
595+
cls: 'python-icon'
596+
};
597+
}
598+
if (fileName === 'setup.py' || fileName === 'setup.cfg') {
599+
return {
600+
type: 'svg',
601+
url: ICON_BASE_URL + 'python.svg',
602+
color: '#3776ab',
603+
cls: 'python-icon'
604+
};
605+
}
606+
if (fileName === 'pipfile' || fileName === 'pipfile.lock') {
607+
return {
608+
type: 'svg',
609+
url: ICON_BASE_URL + 'python.svg',
610+
color: '#3776ab',
611+
cls: 'python-icon'
612+
};
613+
}
614+
if (fileName === 'pyproject.toml') {
615+
return {
616+
type: 'svg',
617+
url: ICON_BASE_URL + 'python.svg',
618+
color: '#3776ab',
619+
cls: 'python-icon'
620+
};
621+
}
622+
if (fileName === 'manage.py') { // Django
623+
return {
624+
type: 'svg',
625+
url: ICON_BASE_URL + 'django.svg',
626+
color: '#092e20',
627+
cls: 'django-icon'
628+
};
629+
}
630+
// ========================================
631+
// JAVASCRIPT/NODE SPECIAL FILES
632+
// ========================================
633+
if (fileName === 'package.json') {
634+
return {
635+
type: 'svg',
636+
url: ICON_BASE_URL + 'nodejs.svg',
637+
color: '#8cc84b',
638+
cls: 'nodejs-icon'
639+
};
640+
}
641+
if (fileName === 'package-lock.json') {
642+
return {
643+
type: 'svg',
644+
url: ICON_BASE_URL + 'npm.svg',
645+
color: '#cb3837',
646+
cls: 'npm-icon'
647+
};
648+
}
649+
if (fileName === 'yarn.lock') {
650+
return {
651+
type: 'svg',
652+
url: ICON_BASE_URL + 'yarn.svg',
653+
color: '#2c8ebb',
654+
cls: 'yarn-icon'
655+
};
656+
}
657+
if (fileName === 'tsconfig.json') {
658+
return {
659+
type: 'svg',
660+
url: ICON_BASE_URL + 'typescript-def.svg',
661+
color: '#3178c6',
662+
cls: 'typescript-icon'
663+
};
664+
}
665+
if (fileName === 'webpack.config.js' || fileName === 'webpack.config.ts') {
666+
return {
667+
type: 'svg',
668+
url: ICON_BASE_URL + 'webpack.svg',
669+
color: '#8dd6f9',
670+
cls: 'webpack-icon'
671+
};
672+
}
673+
if (fileName === 'vite.config.js' || fileName === 'vite.config.ts') {
674+
return {
675+
type: 'svg',
676+
url: ICON_BASE_URL + 'vite.svg',
677+
color: '#646cff',
678+
cls: 'vite-icon'
679+
};
680+
}
681+
if (fileName === 'next.config.js' || fileName === 'next.config.ts') {
682+
return {
683+
type: 'svg',
684+
url: ICON_BASE_URL + 'next.svg',
685+
color: '#000000',
686+
cls: 'next-icon'
687+
};
688+
}
689+
// ========================================
690+
// GIT FILES
691+
// ========================================
692+
if (fileName === '.gitignore' || fileName === '.gitattributes' || fileName === '.gitmodules') {
693+
return {
694+
type: 'svg',
695+
url: ICON_BASE_URL + 'git.svg',
696+
color: '#f34f29',
697+
cls: 'git-icon'
698+
};
699+
}
700+
// ========================================
701+
// DOCKER FILES
702+
// ========================================
703+
if (fileName === 'dockerfile' || fileName.startsWith('dockerfile.')) {
704+
return {
705+
type: 'svg',
706+
url: ICON_BASE_URL + 'docker.svg',
707+
color: '#0db7ed',
708+
cls: 'docker-icon'
709+
};
710+
}
711+
if (fileName === 'docker-compose.yml' || fileName === 'docker-compose.yaml') {
712+
return {
713+
type: 'svg',
714+
url: ICON_BASE_URL + 'docker.svg',
715+
color: '#0db7ed',
716+
cls: 'docker-icon'
717+
};
718+
}
719+
// ========================================
720+
// ENV FILES
721+
// ========================================
722+
if (fileName.startsWith('.env')) {
723+
return {
724+
type: 'svg',
725+
url: ICON_BASE_URL + 'tune.svg',
726+
color: '#e7c547',
727+
cls: 'env-icon'
728+
};
729+
}
730+
// ========================================
731+
// README FILES
732+
// ========================================
733+
if (fileName === 'readme.md' || fileName === 'readme' || fileName === 'readme.txt') {
734+
return {
735+
type: 'svg',
736+
url: ICON_BASE_URL + 'readme.svg',
737+
color: '#4caf50',
738+
cls: 'readme-icon'
739+
};
740+
}
741+
// ========================================
742+
// LICENSE FILES
743+
// ========================================
744+
if (fileName === 'license' || fileName === 'license.md' || fileName === 'license.txt') {
745+
return {
746+
type: 'svg',
747+
url: ICON_BASE_URL + 'license.svg',
748+
color: '#cbcb41',
749+
cls: 'license-icon'
750+
};
751+
}
752+
// ========================================
753+
// GET BY EXTENSION (DEFAULT)
754+
// ========================================
548755
const ext = name.split('.').pop().toLowerCase();
549-
let url = '';
550-
if (ext === 'js') url = 'public/contexticon.svg';
551-
else if (ext === 'html') url = 'public/contexticon.svg';
552-
else if (ext === 'css') url = 'public/contexticon.svg';
553-
else if (ext === 'py') url = 'public/contexticon.svg';
554-
else if (ext === 'md') url = 'public/contexticon.svg';
555-
else url = 'public/contexticon.svg';
556-
// You can add more mappings for other extensions if you add more icons
756+
const iconData = ICONS[ext] || ICONS['default'];
757+
557758
return {
558759
type: 'svg',
559-
url,
560-
color: '',
561-
cls: ''
760+
url: ICON_BASE_URL + iconData.icon,
761+
color: iconData.color,
762+
cls: '' // No custom classes needed - icons are already colored
562763
};
563764
};
564765
const esc = s => s.replace(/&/g, '&amp;').replace(/</g, '<').replace(/>/g, '>');
@@ -691,11 +892,10 @@
691892
const has = nd.t === 'd' && nd.kids.size > 0;
692893
const sz = nd.f ? bytes(nd.f.size) : '';
693894
acc.push({
694-
html: `<div class="tree-item${nd.ig ? ' ignored' : ''}${has ? ' has-children' : ''}" data-path="${nd.full}">
895+
html: `<div class="tree-item ${nd.ig ? 'ignored' : ''}" data-path="${nd.full}">
695896
<div class="tree-item-content" data-level="${lv}">
696-
<span class="tree-lines">${Array(lv).fill('<span class=\'tree-vline\'></span>').join('')}</span>
697897
<button class="expand-btn" style="visibility:${has ? 'visible' : 'hidden'}">
698-
<img src="public/arrowRight.svg" class="tree-arrow" alt=">" />
898+
<span class="material-symbols-outlined">chevron_right</span>
699899
</button>
700900
<div class="file-icon ${ic.cls}">
701901
<img src="${ic.url}" alt="${nd.n}" class="vscode-icon" onerror="this.style.display='none'" />
@@ -1130,30 +1330,30 @@
11301330
const dl = fmt => {
11311331
if (!S.ctx) { toast('Generate first', 'warning'); return; }
11321332
try {
1133-
if (S.isArray) {
1134-
const blob = new Blob(S.ctx, { type: 'text/plain' });
1135-
const url = URL.createObjectURL(blob);
1136-
const a = document.createElement('a');
1137-
a.href = url;
1138-
a.download = `${S.root}-context.${fmt}`;
1139-
a.click();
1140-
URL.revokeObjectURL(url); // REVOKE URL IMMEDIATELY
1141-
toast(`Downloaded (${bytes(blob.size)})`, 'success');
1142-
// Explicitly clear S.ctx array after download if it was an array
1143-
S.ctx.length = 0;
1144-
S.ctx = null;
1145-
S.isArray = false;
1146-
return;
1333+
if (isFolder) {
1334+
return {
1335+
type: 'svg',
1336+
url: 'public/folder.svg', // Use your preferred folder icon SVG
1337+
color: '',
1338+
cls: 'folder-icon'
1339+
};
11471340
}
1148-
const blob = new Blob([S.ctx], { type: 'text/plain' });
1149-
const url = URL.createObjectURL(blob);
1150-
const a = document.createElement('a');
1151-
a.href = url;
1152-
a.download = `${S.root}-context.${fmt}`;
1153-
a.click();
1154-
URL.revokeObjectURL(url); // REVOKE URL IMMEDIATELY
1155-
toast(`Downloaded (${bytes(blob.size)})`, 'success');
1156-
// Explicitly clear S.ctx string after download if it was a string
1341+
// File icon by extension
1342+
const ext = name.split('.').pop().toLowerCase();
1343+
let url = '';
1344+
if (ext === 'js') url = 'public/js.svg';
1345+
else if (ext === 'html') url = 'public/html.svg';
1346+
else if (ext === 'css') url = 'public/css.svg';
1347+
else if (ext === 'py') url = 'public/python.svg';
1348+
else if (ext === 'md') url = 'public/markdown.svg';
1349+
else url = 'public/file.svg';
1350+
// You can add more mappings for other extensions if you add more icons
1351+
return {
1352+
type: 'svg',
1353+
url,
1354+
color: '',
1355+
cls: ''
1356+
};
11571357
S.ctx = null;
11581358
S.isArray = false;
11591359
} catch (e) {
@@ -1195,72 +1395,10 @@
11951395
}
11961396
};
11971397
D.search.oninput = e => {
1198-
const q = e.target.value.trim().toLowerCase();
1199-
const allItems = Array.from(document.querySelectorAll('.tree-item'));
1200-
// Helper: get full path for a tree-item
1201-
const getPath = item => {
1202-
let path = '';
1203-
let cur = item;
1204-
while (cur && cur.classList.contains('tree-item')) {
1205-
const name = cur.querySelector('.file-name')?.textContent || '';
1206-
path = name + (path ? '/' + path : '');
1207-
cur = cur.parentElement?.closest('.tree-item');
1208-
}
1209-
return path.toLowerCase();
1210-
};
1211-
// First, hide all
1212-
allItems.forEach(item => { item.style.display = 'none'; });
1213-
// If search is empty, show all
1214-
if (!q) {
1215-
allItems.forEach(item => { item.style.display = ''; });
1216-
// Collapse all folders
1217-
document.querySelectorAll('.tree-children').forEach(tc => tc.classList.remove('open'));
1218-
document.querySelectorAll('.expand-btn').forEach(btn => btn.classList.remove('expanded'));
1219-
document.querySelectorAll('.expand-btn .material-symbols-outlined').forEach(span => span.textContent = 'chevron_right');
1220-
return;
1221-
}
1222-
// Find all items that match (by name or path)
1223-
const matches = allItems.filter(item => {
1224-
const name = item.querySelector('.file-name')?.textContent.toLowerCase() || '';
1225-
const path = getPath(item);
1226-
return name.includes(q) || path.includes(q);
1227-
});
1228-
// Show all matches and their ancestors
1229-
const showSet = new Set();
1230-
matches.forEach(item => {
1231-
let cur = item;
1232-
while (cur && cur.classList.contains('tree-item')) {
1233-
showSet.add(cur);
1234-
cur = cur.parentElement?.closest('.tree-item');
1235-
}
1236-
});
1237-
allItems.forEach(item => {
1238-
if (showSet.has(item)) {
1239-
item.style.display = '';
1240-
} else {
1241-
item.style.display = 'none';
1242-
}
1243-
});
1244-
// Expand all folders that are ancestors of matches
1245-
document.querySelectorAll('.tree-children').forEach(tc => {
1246-
const parent = tc.parentElement;
1247-
if (parent && showSet.has(parent)) {
1248-
tc.classList.add('open');
1249-
const btn = parent.querySelector('.expand-btn');
1250-
if (btn) {
1251-
btn.classList.add('expanded');
1252-
const span = btn.querySelector('.material-symbols-outlined');
1253-
if (span) span.textContent = 'expand_more';
1254-
}
1255-
} else {
1256-
tc.classList.remove('open');
1257-
const btn = parent?.querySelector('.expand-btn');
1258-
if (btn) {
1259-
btn.classList.remove('expanded');
1260-
const span = btn.querySelector('.material-symbols-outlined');
1261-
if (span) span.textContent = 'chevron_right';
1262-
}
1263-
}
1398+
const q = e.target.value.toLowerCase();
1399+
document.querySelectorAll('.tree-item').forEach(item => {
1400+
const n = item.querySelector('.file-name').textContent.toLowerCase();
1401+
item.style.display = n.includes(q) ? '' : 'none';
12641402
});
12651403
};
12661404
const togFold = o => {

0 commit comments

Comments
 (0)