This commit is contained in:
303
src/utils/terminal/fs.ts
Normal file
303
src/utils/terminal/fs.ts
Normal file
@@ -0,0 +1,303 @@
|
||||
import type { FileSystemNode, ResumeData } from './types';
|
||||
import { talks, projects, socialLinks, techLinks } from '../../config/data';
|
||||
|
||||
export async function buildFileSystem(): Promise<{ [key: string]: FileSystemNode }> {
|
||||
try {
|
||||
const response = await fetch('/files/resume.json');
|
||||
const resumeData: ResumeData = await response.json();
|
||||
|
||||
// Fetch blog posts
|
||||
const postsResponse = await fetch('/api/posts.json');
|
||||
let postsData = [];
|
||||
try {
|
||||
postsData = await postsResponse.json();
|
||||
} catch (error) {
|
||||
console.log('Could not fetch posts data:', error);
|
||||
}
|
||||
|
||||
// Build resume files from rxresume json
|
||||
const resumeFiles = buildResumeFiles(resumeData);
|
||||
const postsFiles = buildPostsFiles(postsData);
|
||||
const talksFiles = buildTalksFiles();
|
||||
const projectsFiles = buildProjectsFiles();
|
||||
const socialFiles = buildSocialFiles();
|
||||
const techFiles = buildTechFiles();
|
||||
const contactContent = buildContactContent(resumeData);
|
||||
|
||||
const fs: { [key: string]: FileSystemNode } = {
|
||||
'/': {
|
||||
type: 'directory',
|
||||
name: '/',
|
||||
children: {
|
||||
'about.txt': {
|
||||
type: 'file',
|
||||
name: 'about.txt',
|
||||
content: `${resumeData.basics.name}\nResearcher, Full-Stack Developer, and IT Professional.\n\nExplore the directories:\n- /resume - Professional experience and skills\n- /posts - Blog posts and articles\n- /talks - Conference presentations\n- /projects - Personal and professional projects\n- /social - Social media and contact links\n- /tech - Technologies and tools I use\n\nType "ls" to see all available files and directories.`
|
||||
},
|
||||
'resume': {
|
||||
type: 'directory',
|
||||
name: 'resume',
|
||||
children: resumeFiles
|
||||
},
|
||||
'posts': {
|
||||
type: 'directory',
|
||||
name: 'posts',
|
||||
children: postsFiles
|
||||
},
|
||||
'talks': {
|
||||
type: 'directory',
|
||||
name: 'talks',
|
||||
children: talksFiles
|
||||
},
|
||||
'projects': {
|
||||
type: 'directory',
|
||||
name: 'projects',
|
||||
children: projectsFiles
|
||||
},
|
||||
'social': {
|
||||
type: 'directory',
|
||||
name: 'social',
|
||||
children: socialFiles
|
||||
},
|
||||
'tech': {
|
||||
type: 'directory',
|
||||
name: 'tech',
|
||||
children: techFiles
|
||||
},
|
||||
'contact.txt': {
|
||||
type: 'file',
|
||||
name: 'contact.txt',
|
||||
content: contactContent
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return fs;
|
||||
} catch (error) {
|
||||
console.error('Error loading resume data:', error);
|
||||
return buildFallbackFileSystem();
|
||||
}
|
||||
}
|
||||
|
||||
function buildResumeFiles(resumeData: ResumeData): { [key: string]: FileSystemNode } {
|
||||
const resumeFiles: { [key: string]: FileSystemNode } = {};
|
||||
|
||||
if (resumeData.sections.summary) {
|
||||
resumeFiles['summary.txt'] = {
|
||||
type: 'file',
|
||||
name: 'summary.txt',
|
||||
content: resumeData.sections.summary.content.replace(/<[^>]*>/g, '')
|
||||
};
|
||||
}
|
||||
|
||||
if (resumeData.sections.skills?.items) {
|
||||
const skillsContent = resumeData.sections.skills.items
|
||||
.map(skill => `${skill.name} (Level: ${skill.level}/5)`)
|
||||
.join('\n');
|
||||
resumeFiles['skills.txt'] = {
|
||||
type: 'file',
|
||||
name: 'skills.txt',
|
||||
content: skillsContent
|
||||
};
|
||||
}
|
||||
|
||||
if (resumeData.sections.experience?.items) {
|
||||
const experienceContent = resumeData.sections.experience.items
|
||||
.map(exp => {
|
||||
const summary = exp.summary.replace(/<[^>]*>/g, '').replace(/ /g, ' ');
|
||||
return `${exp.position} at ${exp.company}\n${exp.date} | ${exp.location}\n${summary}\n${exp.url?.href ? `URL: ${exp.url.href}` : ''}\n`;
|
||||
})
|
||||
.join('\n---\n\n');
|
||||
resumeFiles['experience.txt'] = {
|
||||
type: 'file',
|
||||
name: 'experience.txt',
|
||||
content: experienceContent
|
||||
};
|
||||
}
|
||||
|
||||
if (resumeData.sections.education?.items) {
|
||||
const educationContent = resumeData.sections.education.items
|
||||
.map(edu => `${edu.institution}\n${edu.studyType} - ${edu.area}\n${edu.date}\n${edu.summary ? edu.summary.replace(/<[^>]*>/g, '') : ''}`)
|
||||
.join('\n\n---\n\n');
|
||||
resumeFiles['education.txt'] = {
|
||||
type: 'file',
|
||||
name: 'education.txt',
|
||||
content: educationContent
|
||||
};
|
||||
}
|
||||
|
||||
if (resumeData.sections.volunteer?.items) {
|
||||
const volunteerContent = resumeData.sections.volunteer.items
|
||||
.map(vol => `${vol.organization}\n${vol.position}\n${vol.date}`)
|
||||
.join('\n\n---\n\n');
|
||||
resumeFiles['volunteer.txt'] = {
|
||||
type: 'file',
|
||||
name: 'volunteer.txt',
|
||||
content: volunteerContent
|
||||
};
|
||||
}
|
||||
|
||||
return resumeFiles;
|
||||
}
|
||||
|
||||
function buildPostsFiles(postsData: any[]): { [key: string]: FileSystemNode } {
|
||||
const postsFiles: { [key: string]: FileSystemNode } = {};
|
||||
|
||||
postsData.forEach((post: any) => {
|
||||
const fileName = `${post.slug}.md`;
|
||||
let content = `---
|
||||
title: "${post.title}"
|
||||
description: "${post.description}"
|
||||
pubDate: "${post.pubDate}"
|
||||
tags: [${post.tags.map((tag: string) => `"${tag}"`).join(', ')}]
|
||||
---
|
||||
|
||||
${post.content}`;
|
||||
|
||||
postsFiles[fileName] = {
|
||||
type: 'file',
|
||||
name: fileName,
|
||||
content
|
||||
};
|
||||
});
|
||||
|
||||
return postsFiles;
|
||||
}
|
||||
|
||||
function buildTalksFiles(): { [key: string]: FileSystemNode } {
|
||||
const talksFiles: { [key: string]: FileSystemNode } = {};
|
||||
|
||||
talks.forEach(talk => {
|
||||
const fileName = `${talk.id}.txt`;
|
||||
let content = `${talk.name}
|
||||
${talk.description}
|
||||
${talk.venue || ''}
|
||||
${talk.date || ''}
|
||||
${talk.link}`;
|
||||
|
||||
talksFiles[fileName] = {
|
||||
type: 'file',
|
||||
name: fileName,
|
||||
content
|
||||
};
|
||||
});
|
||||
|
||||
return talksFiles;
|
||||
}
|
||||
|
||||
function buildProjectsFiles(): { [key: string]: FileSystemNode } {
|
||||
const projectsFiles: { [key: string]: FileSystemNode } = {};
|
||||
|
||||
projects.forEach(project => {
|
||||
const fileName = `${project.id}.txt`;
|
||||
let content = `${project.name}
|
||||
${project.description}
|
||||
${project.status || ''}
|
||||
${project.technologies ? project.technologies.join(', ') : ''}
|
||||
${project.link}`;
|
||||
|
||||
projectsFiles[fileName] = {
|
||||
type: 'file',
|
||||
name: fileName,
|
||||
content
|
||||
};
|
||||
});
|
||||
|
||||
return projectsFiles;
|
||||
}
|
||||
|
||||
function buildSocialFiles(): { [key: string]: FileSystemNode } {
|
||||
const socialFiles: { [key: string]: FileSystemNode } = {};
|
||||
|
||||
socialLinks.forEach(link => {
|
||||
const fileName = `${link.id}.txt`;
|
||||
let content = `${link.name}
|
||||
${link.url}`;
|
||||
|
||||
socialFiles[fileName] = {
|
||||
type: 'file',
|
||||
name: fileName,
|
||||
content
|
||||
};
|
||||
});
|
||||
|
||||
return socialFiles;
|
||||
}
|
||||
|
||||
function buildTechFiles(): { [key: string]: FileSystemNode } {
|
||||
const techFiles: { [key: string]: FileSystemNode } = {};
|
||||
|
||||
techLinks.forEach(link => {
|
||||
const fileName = `${link.id}.txt`;
|
||||
let content = `${link.name}
|
||||
${link.url}`;
|
||||
|
||||
techFiles[fileName] = {
|
||||
type: 'file',
|
||||
name: fileName,
|
||||
content
|
||||
};
|
||||
});
|
||||
|
||||
return techFiles;
|
||||
}
|
||||
|
||||
function buildContactContent(resumeData: ResumeData): string {
|
||||
return [
|
||||
`Email: ${resumeData.basics.email}`,
|
||||
'',
|
||||
'Social Profiles:',
|
||||
...resumeData.sections.profiles.items.map(profile =>
|
||||
`${profile.network}: ${profile.url.href}`
|
||||
)
|
||||
].join('\n');
|
||||
}
|
||||
|
||||
function buildFallbackFileSystem(): { [key: string]: FileSystemNode } {
|
||||
return {
|
||||
'/': {
|
||||
type: 'directory',
|
||||
name: '/',
|
||||
children: {
|
||||
'about.txt': {
|
||||
type: 'file',
|
||||
name: 'about.txt',
|
||||
content: 'Atridad Lahiji\nResearcher, Full-Stack Developer, and IT Professional.\n\nError loading detailed information. Please check the website directly.'
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function getCurrentDirectory(fileSystem: { [key: string]: FileSystemNode }, currentPath: string): FileSystemNode {
|
||||
const pathParts = currentPath.split('/').filter((part: string) => part !== '');
|
||||
let current = fileSystem['/'];
|
||||
|
||||
for (const part of pathParts) {
|
||||
if (current?.children && current.children[part] && current.children[part].type === 'directory') {
|
||||
current = current.children[part];
|
||||
}
|
||||
}
|
||||
|
||||
return current;
|
||||
}
|
||||
|
||||
export function resolvePath(currentPath: string, path: string): string {
|
||||
if (path.startsWith('/')) {
|
||||
return path;
|
||||
}
|
||||
|
||||
const currentParts = currentPath.split('/').filter((part: string) => part !== '');
|
||||
const pathParts = path.split('/');
|
||||
|
||||
for (const part of pathParts) {
|
||||
if (part === '..') {
|
||||
currentParts.pop();
|
||||
} else if (part !== '.' && part !== '') {
|
||||
currentParts.push(part);
|
||||
}
|
||||
}
|
||||
|
||||
return '/' + currentParts.join('/');
|
||||
}
|
||||
Reference in New Issue
Block a user