Skip to content

Commit bdd8a54

Browse files
authored
Create files.js
New beginnings, new Claude AI code! 🤖
1 parent aae177a commit bdd8a54

File tree

1 file changed

+175
-0
lines changed

1 file changed

+175
-0
lines changed

js/components/files.js

Lines changed: 175 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,175 @@
1+
/**
2+
3+
- File Management Component
4+
- Handles file uploads, attachments, and media processing
5+
*/
6+
7+
class FileManager {
8+
constructor() {
9+
this.allowedTypes = [
10+
‘image/jpeg’, ‘image/png’, ‘image/gif’, ‘image/webp’,
11+
‘video/mp4’, ‘video/webm’, ‘application/pdf’,
12+
‘application/msword’, ‘application/vnd.openxmlformats-officedocument.wordprocessingml.document’
13+
];
14+
this.maxFileSize = 10 * 1024 * 1024; // 10MB
15+
16+
```
17+
this.bindEventHandlers();
18+
}
19+
20+
bindEventHandlers() {
21+
this.attach = this.attach.bind(this);
22+
}
23+
24+
attach() {
25+
const input = document.createElement('input');
26+
input.type = 'file';
27+
input.multiple = true;
28+
input.accept = this.allowedTypes.join(',');
29+
30+
input.onchange = (e) => {
31+
const files = Array.from(e.target.files);
32+
files.forEach(file => this.processFile(file));
33+
};
34+
35+
input.click();
36+
}
37+
38+
processFile(file) {
39+
if (!this.validateFile(file)) return;
40+
41+
if (file.type.startsWith('image/')) {
42+
this.handleImageFile(file);
43+
} else if (file.type.startsWith('video/')) {
44+
this.handleVideoFile(file);
45+
} else {
46+
this.handleDocumentFile(file);
47+
}
48+
}
49+
50+
validateFile(file) {
51+
if (file.size > this.maxFileSize) {
52+
this.showError(`File too large: ${file.name}. Maximum size is 10MB.`);
53+
return false;
54+
}
55+
56+
if (!this.allowedTypes.includes(file.type)) {
57+
this.showError(`File type not supported: ${file.type}`);
58+
return false;
59+
}
60+
61+
return true;
62+
}
63+
64+
handleImageFile(file) {
65+
const reader = new FileReader();
66+
reader.onload = (e) => {
67+
this.addFileMessage(file.name, e.target.result, 'image');
68+
};
69+
reader.readAsDataURL(file);
70+
}
71+
72+
handleVideoFile(file) {
73+
const reader = new FileReader();
74+
reader.onload = (e) => {
75+
this.addFileMessage(file.name, e.target.result, 'video');
76+
};
77+
reader.readAsDataURL(file);
78+
}
79+
80+
handleDocumentFile(file) {
81+
this.addFileMessage(file.name, null, 'document');
82+
}
83+
84+
addFileMessage(fileName, dataUrl, type) {
85+
const messagesContainer = document.getElementById('chatMessages');
86+
if (!messagesContainer) return;
87+
88+
const fileSize = this.formatFileSize(dataUrl ? dataUrl.length : 0);
89+
const fileIcon = this.getFileIcon(type);
90+
91+
let content = '';
92+
if (type === 'image' && dataUrl) {
93+
content = `
94+
<div class="file-preview">
95+
<img src="${dataUrl}" alt="${fileName}" style="max-width: 200px; border-radius: 8px;">
96+
<div style="margin-top: 5px; font-size: 12px; color: #666;">${fileName}</div>
97+
</div>
98+
`;
99+
} else if (type === 'video' && dataUrl) {
100+
content = `
101+
<div class="file-preview">
102+
<video controls style="max-width: 200px; border-radius: 8px;">
103+
<source src="${dataUrl}" type="video/mp4">
104+
</video>
105+
<div style="margin-top: 5px; font-size: 12px; color: #666;">${fileName}</div>
106+
</div>
107+
`;
108+
} else {
109+
content = `
110+
<div class="file-preview">
111+
<span class="file-icon">${fileIcon}</span>
112+
<div style="display: inline-block;">
113+
<div style="font-weight: bold;">${fileName}</div>
114+
<div style="font-size: 12px; color: #666;">${fileSize}</div>
115+
</div>
116+
</div>
117+
`;
118+
}
119+
120+
const messageDiv = document.createElement('div');
121+
messageDiv.className = 'message own';
122+
messageDiv.innerHTML = `
123+
<div class="message-bubble">
124+
${content}
125+
<div class="message-status">✓</div>
126+
</div>
127+
`;
128+
129+
messagesContainer.appendChild(messageDiv);
130+
messagesContainer.scrollTop = messagesContainer.scrollHeight;
131+
}
132+
133+
getFileIcon(type) {
134+
switch (type) {
135+
case 'image': return '🖼️';
136+
case 'video': return '🎥';
137+
case 'document': return '📄';
138+
default: return '📎';
139+
}
140+
}
141+
142+
formatFileSize(bytes) {
143+
if (bytes === 0) return '0 Bytes';
144+
const k = 1024;
145+
const sizes = ['Bytes', 'KB', 'MB', 'GB'];
146+
const i = Math.floor(Math.log(bytes) / Math.log(k));
147+
return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
148+
}
149+
150+
showError(message) {
151+
const errorDiv = document.createElement('div');
152+
errorDiv.style.cssText = `
153+
position: fixed; top: 20px; right: 20px; background: #ff4757;
154+
color: white; padding: 10px 20px; border-radius: 5px; z-index: 10000;
155+
`;
156+
errorDiv.textContent = message;
157+
document.body.appendChild(errorDiv);
158+
setTimeout(() => errorDiv.remove(), 3000);
159+
}
160+
```
161+
162+
}
163+
164+
const fileManager = new FileManager();
165+
166+
window.Files = {
167+
attach: fileManager.attach
168+
};
169+
170+
if (typeof module !== ‘undefined’ && module.exports) {
171+
module.exports = { FileManager, fileManager };
172+
} else if (typeof window !== ‘undefined’) {
173+
window.FileManager = FileManager;
174+
window.fileManager = fileManager;
175+
}

0 commit comments

Comments
 (0)