Add camera vs file picker options for image and video attachments

- Add separate buttons: 'Attach Image' and 'Take Photo'
- Add separate buttons: 'Attach Video' and 'Record Video'
- Create separate file inputs: imageInput/imageCameraInput, videoInput/videoCameraInput
- imageCameraInput and videoCameraInput have capture="environment" attribute
- imageInput and videoInput are for file picker (no capture attribute)
- Both note and conversation menus updated with same structure
- Update all event listeners and clear handlers for new inputs
This commit is contained in:
2026-01-11 03:03:12 +00:00
parent d7c42de0d7
commit 8a70038b64
+64 -6
View File
@@ -232,12 +232,24 @@
</svg> </svg>
Attach Image Attach Image
</button> </button>
<button id="takePhotoBtn" class="w-full text-left px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 flex items-center gap-2" type="button">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" class="w-4 h-4">
<path d="M23 19a2 2 0 0 1-2 2H3a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h4l2-3h6l2 3h4a2 2 0 0 1 2 2z"/><circle cx="12" cy="13" r="4"/>
</svg>
Take Photo
</button>
<button id="attachVideoBtn" class="w-full text-left px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 flex items-center gap-2" type="button"> <button id="attachVideoBtn" class="w-full text-left px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 flex items-center gap-2" type="button">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" class="w-4 h-4"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" class="w-4 h-4">
<polygon points="23 7 16 12 23 17 23 7"/><rect x="1" y="5" width="15" height="14" rx="2" ry="2"/> <polygon points="23 7 16 12 23 17 23 7"/><rect x="1" y="5" width="15" height="14" rx="2" ry="2"/>
</svg> </svg>
Attach Video Attach Video
</button> </button>
<button id="recordVideoBtn" class="w-full text-left px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 flex items-center gap-2" type="button">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" class="w-4 h-4">
<circle cx="12" cy="13" r="9"/><path d="M12 10v6"/>
</svg>
Record Video
</button>
<button id="attachFileBtn" class="w-full text-left px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 flex items-center gap-2" type="button"> <button id="attachFileBtn" class="w-full text-left px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 flex items-center gap-2" type="button">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" class="w-4 h-4"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" class="w-4 h-4">
<path d="M13 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V9z"/><polyline points="13 2 13 9 20 9"/> <path d="M13 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V9z"/><polyline points="13 2 13 9 20 9"/>
@@ -247,8 +259,10 @@
</div> </div>
<!-- Hidden file inputs --> <!-- Hidden file inputs -->
<input id="imageInput" type="file" class="hidden" accept="image/*" multiple capture="environment"> <input id="imageInput" type="file" class="hidden" accept="image/*" multiple>
<input id="videoInput" type="file" class="hidden" accept="video/*" capture="environment"> <input id="imageCameraInput" type="file" class="hidden" accept="image/*" multiple capture="environment">
<input id="videoInput" type="file" class="hidden" accept="video/*">
<input id="videoCameraInput" type="file" class="hidden" accept="video/*" capture="environment">
<input id="fileInput" type="file" class="hidden" multiple accept=".pdf,.doc,.docx,.xls,.xlsx,.ppt,.pptx,.txt,.zip,.rar"> <input id="fileInput" type="file" class="hidden" multiple accept=".pdf,.doc,.docx,.xls,.xlsx,.ppt,.pptx,.txt,.zip,.rar">
<div id="noteAttachmentsList" class="space-y-1"></div> <div id="noteAttachmentsList" class="space-y-1"></div>
@@ -397,12 +411,24 @@
</svg> </svg>
Attach Image Attach Image
</button> </button>
<button id="conversationTakePhotoBtn" class="w-full text-left px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 flex items-center gap-2" type="button">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" class="w-4 h-4">
<path d="M23 19a2 2 0 0 1-2 2H3a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h4l2-3h6l2 3h4a2 2 0 0 1 2 2z"/><circle cx="12" cy="13" r="4"/>
</svg>
Take Photo
</button>
<button id="conversationAttachVideoBtn" class="w-full text-left px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 flex items-center gap-2" type="button"> <button id="conversationAttachVideoBtn" class="w-full text-left px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 flex items-center gap-2" type="button">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" class="w-4 h-4"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" class="w-4 h-4">
<polygon points="23 7 16 12 23 17 23 7"/><rect x="1" y="5" width="15" height="14" rx="2" ry="2"/> <polygon points="23 7 16 12 23 17 23 7"/><rect x="1" y="5" width="15" height="14" rx="2" ry="2"/>
</svg> </svg>
Attach Video Attach Video
</button> </button>
<button id="conversationRecordVideoBtn" class="w-full text-left px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 flex items-center gap-2" type="button">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" class="w-4 h-4">
<circle cx="12" cy="13" r="9"/><path d="M12 10v6"/>
</svg>
Record Video
</button>
<button id="conversationAttachFileBtn" class="w-full text-left px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 flex items-center gap-2" type="button"> <button id="conversationAttachFileBtn" class="w-full text-left px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 flex items-center gap-2" type="button">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" class="w-4 h-4"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" class="w-4 h-4">
<path d="M13 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V9z"/><polyline points="13 2 13 9 20 9"/> <path d="M13 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V9z"/><polyline points="13 2 13 9 20 9"/>
@@ -412,8 +438,10 @@
</div> </div>
<!-- Hidden file inputs for conversation --> <!-- Hidden file inputs for conversation -->
<input id="conversationImageInput" type="file" class="hidden" accept="image/*" multiple capture="environment"> <input id="conversationImageInput" type="file" class="hidden" accept="image/*" multiple>
<input id="conversationVideoInput" type="file" class="hidden" accept="video/*" capture="environment"> <input id="conversationImageCameraInput" type="file" class="hidden" accept="image/*" multiple capture="environment">
<input id="conversationVideoInput" type="file" class="hidden" accept="video/*">
<input id="conversationVideoCameraInput" type="file" class="hidden" accept="video/*" capture="environment">
<input id="conversationFileInput" type="file" class="hidden" multiple accept=".pdf,.doc,.docx,.xls,.xlsx,.ppt,.pptx,.txt,.zip,.rar"> <input id="conversationFileInput" type="file" class="hidden" multiple accept=".pdf,.doc,.docx,.xls,.xlsx,.ppt,.pptx,.txt,.zip,.rar">
<div id="conversationAttachmentsList" class="space-y-1"></div> <div id="conversationAttachmentsList" class="space-y-1"></div>
@@ -1709,7 +1737,9 @@
const attachmentMenuBtn = document.getElementById('attachmentMenuBtn'); const attachmentMenuBtn = document.getElementById('attachmentMenuBtn');
const attachmentMenu = document.getElementById('attachmentMenu'); const attachmentMenu = document.getElementById('attachmentMenu');
const imageInput = document.getElementById('imageInput'); const imageInput = document.getElementById('imageInput');
const imageCameraInput = document.getElementById('imageCameraInput');
const videoInput = document.getElementById('videoInput'); const videoInput = document.getElementById('videoInput');
const videoCameraInput = document.getElementById('videoCameraInput');
const fileInput = document.getElementById('fileInput'); const fileInput = document.getElementById('fileInput');
attachmentMenuBtn.addEventListener('click', (e) => { attachmentMenuBtn.addEventListener('click', (e) => {
@@ -1722,18 +1752,28 @@
imageInput.click(); imageInput.click();
}); });
document.getElementById('takePhotoBtn').addEventListener('click', () => {
attachmentMenu.classList.add('hidden');
imageCameraInput.click();
});
document.getElementById('attachVideoBtn').addEventListener('click', () => { document.getElementById('attachVideoBtn').addEventListener('click', () => {
attachmentMenu.classList.add('hidden'); attachmentMenu.classList.add('hidden');
videoInput.click(); videoInput.click();
}); });
document.getElementById('recordVideoBtn').addEventListener('click', () => {
attachmentMenu.classList.add('hidden');
videoCameraInput.click();
});
document.getElementById('attachFileBtn').addEventListener('click', () => { document.getElementById('attachFileBtn').addEventListener('click', () => {
attachmentMenu.classList.add('hidden'); attachmentMenu.classList.add('hidden');
fileInput.click(); fileInput.click();
}); });
// File input change handlers // File input change handlers
[imageInput, videoInput, fileInput].forEach(input => { [imageInput, imageCameraInput, videoInput, videoCameraInput, fileInput].forEach(input => {
input.addEventListener('change', (e) => { input.addEventListener('change', (e) => {
pendingNoteAttachments.push(...Array.from(e.target.files || [])); pendingNoteAttachments.push(...Array.from(e.target.files || []));
renderNoteAttachmentsList(); renderNoteAttachmentsList();
@@ -1744,7 +1784,9 @@
e.preventDefault(); e.preventDefault();
pendingNoteAttachments = []; pendingNoteAttachments = [];
imageInput.value = ''; imageInput.value = '';
imageCameraInput.value = '';
videoInput.value = ''; videoInput.value = '';
videoCameraInput.value = '';
fileInput.value = ''; fileInput.value = '';
renderNoteAttachmentsList(); renderNoteAttachmentsList();
}); });
@@ -1760,7 +1802,9 @@
const conversationAttachmentMenuBtn = document.getElementById('conversationAttachmentMenuBtn'); const conversationAttachmentMenuBtn = document.getElementById('conversationAttachmentMenuBtn');
const conversationAttachmentMenu = document.getElementById('conversationAttachmentMenu'); const conversationAttachmentMenu = document.getElementById('conversationAttachmentMenu');
const conversationImageInput = document.getElementById('conversationImageInput'); const conversationImageInput = document.getElementById('conversationImageInput');
const conversationImageCameraInput = document.getElementById('conversationImageCameraInput');
const conversationVideoInput = document.getElementById('conversationVideoInput'); const conversationVideoInput = document.getElementById('conversationVideoInput');
const conversationVideoCameraInput = document.getElementById('conversationVideoCameraInput');
const conversationFileInput = document.getElementById('conversationFileInput'); const conversationFileInput = document.getElementById('conversationFileInput');
conversationAttachmentMenuBtn.addEventListener('click', (e) => { conversationAttachmentMenuBtn.addEventListener('click', (e) => {
@@ -1773,18 +1817,28 @@
conversationImageInput.click(); conversationImageInput.click();
}); });
document.getElementById('conversationTakePhotoBtn').addEventListener('click', () => {
conversationAttachmentMenu.classList.add('hidden');
conversationImageCameraInput.click();
});
document.getElementById('conversationAttachVideoBtn').addEventListener('click', () => { document.getElementById('conversationAttachVideoBtn').addEventListener('click', () => {
conversationAttachmentMenu.classList.add('hidden'); conversationAttachmentMenu.classList.add('hidden');
conversationVideoInput.click(); conversationVideoInput.click();
}); });
document.getElementById('conversationRecordVideoBtn').addEventListener('click', () => {
conversationAttachmentMenu.classList.add('hidden');
conversationVideoCameraInput.click();
});
document.getElementById('conversationAttachFileBtn').addEventListener('click', () => { document.getElementById('conversationAttachFileBtn').addEventListener('click', () => {
conversationAttachmentMenu.classList.add('hidden'); conversationAttachmentMenu.classList.add('hidden');
conversationFileInput.click(); conversationFileInput.click();
}); });
// File input change handlers for conversation // File input change handlers for conversation
[conversationImageInput, conversationVideoInput, conversationFileInput].forEach(input => { [conversationImageInput, conversationImageCameraInput, conversationVideoInput, conversationVideoCameraInput, conversationFileInput].forEach(input => {
input.addEventListener('change', (e) => { input.addEventListener('change', (e) => {
pendingConversationAttachments.push(...Array.from(e.target.files || [])); pendingConversationAttachments.push(...Array.from(e.target.files || []));
renderConversationAttachmentsList(); renderConversationAttachmentsList();
@@ -1795,7 +1849,9 @@
e.preventDefault(); e.preventDefault();
pendingConversationAttachments = []; pendingConversationAttachments = [];
conversationImageInput.value = ''; conversationImageInput.value = '';
conversationImageCameraInput.value = '';
conversationVideoInput.value = ''; conversationVideoInput.value = '';
conversationVideoCameraInput.value = '';
conversationFileInput.value = ''; conversationFileInput.value = '';
renderConversationAttachmentsList(); renderConversationAttachmentsList();
}); });
@@ -1986,7 +2042,9 @@
await clearAudio(); await clearAudio();
pendingNoteAttachments = []; pendingNoteAttachments = [];
document.getElementById('imageInput').value = ''; document.getElementById('imageInput').value = '';
document.getElementById('imageCameraInput').value = '';
document.getElementById('videoInput').value = ''; document.getElementById('videoInput').value = '';
document.getElementById('videoCameraInput').value = '';
document.getElementById('fileInput').value = ''; document.getElementById('fileInput').value = '';
renderNoteAttachmentsList(); renderNoteAttachmentsList();
document.getElementById('noteText').value = ''; document.getElementById('noteText').value = '';