Compare commits

...

12 Commits

Author SHA1 Message Date
aewing ccb239c84b Restructure attachment menu with submenus and adjust container sizing/positioning
- Reorganize attachment menu: main menu shows Attach Image, Attach Video, Attach File
- Clicking Attach Image/Video opens submenus with take photo/video and select file options
- Move menu to open to the right of attach button instead of below
- Apply same submenu structure to both note and conversation containers
- Decrease height of notesListContainer and noteContainer for compact layout
- Center containers vertically on page
- Move attachments section and submit button up 30px within noteContainer
- Adjust vertical padding and margins for optimal spacing
- Reduce noteContainer height by 15px and move down 4px
- Increase notesListContainer height by 2px and move down 4px
- Fine-tune noteContainer height and positioning (py-[8px], mt-4)
2026-01-11 03:30:40 +00:00
aewing 8a70038b64 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
2026-01-11 03:03:12 +00:00
aewing d7c42de0d7 Add capture attribute to image and video inputs for camera access
- Add capture="environment" to imageInput and videoInput
- Add capture="environment" to conversationImageInput and conversationVideoInput
- Enables camera/video capture on mobile and desktop devices
- Falls back to file picker on devices without camera capability
2026-01-11 02:44:48 +00:00
aewing af0fef4f08 Simplify attachment menu: keep only image, video, file options
- Remove Record Video option and related MediaRecorder implementation
- Remove Take Picture option and camera input handling
- Update both note and conversation attachment menus
- Remove unused event listeners and variable declarations
- Simplify file input arrays to 3 inputs instead of 4
2026-01-11 02:41:51 +00:00
aewing 8009ad1eb3 recording working righ, but menu is not correct yet 2026-01-11 02:38:28 +00:00
aewing a19a4495f4 Add zoom in/out controls to attachment preview
- Add zoom in (+), zoom out (−), reset, and close buttons to preview panel
- Zoom buttons only show for images (other media types don't need zoom)
- Zoom level indicator shows current zoom percentage
- Support zoom levels: 100% to 400% in 25% increments
- Image zoom uses CSS transform scale for smooth performance
- Click on image to toggle between 100% and 150% zoom (quick toggle)
- Reset button appears when zoomed in, allows quick return to original
- Zoom out button only appears when zoomed in
- Preview panel has scrollable content area (max-height 600px)
- Maintains aspect ratio and smooth transitions during zoom
2026-01-11 02:32:11 +00:00
aewing 649d9652b6 Fix container overflow: constrain height and reduce bottom padding
- Add max-h-[calc(100vh-120px)] and overflow-y-auto to note and conversation containers
- Reduce bottom padding from pb-32 (128px) to pb-16 (64px)
- Prevents form containers from expanding beyond viewport bounds
- Keeps header buttons (New Note, Conversations) visible at all times
- Allows scrolling within form when content exceeds viewport height
2026-01-10 23:07:02 +00:00
aewing 26092b314b Add video recording UI and preview functionality
- Show visible 'Recording Video...' indicator with pulsing red dot when recording starts
- Add 'Stop Recording' button for easy access (not just text feedback)
- Display video preview player after recording completes
- Add 'Use Video' button to attach recorded video to form
- Add 'Remove Video' button to discard recording without attaching
- Implement separate video recording for note and conversation containers
- Store video blob in window.noteVideoBlob and window.conversationVideoBlob
- Video player shows up to 300px height with full controls
- Red/green color scheme for visual feedback (recording = red, actions = green)
2026-01-10 23:02:34 +00:00
aewing 7282c920bf Update session log: document attachment menu system completion 2026-01-10 22:54:47 +00:00
aewing b889e48325 Add menu-driven attachment system with video recording
- Replace single file input with paper clip icon button and dropdown menu
- Add 5 attachment options: image, video, file, video recording, picture capture
- Implement video recording with MediaRecorder API (5 min auto-stop)
- Support multiple file input interactions accumulating in pending array
- Add same menu system to conversation container (separate attachment array)
- Add render functions for displaying selected attachment summaries
- Fix CSS positioning for menu with relative parent and top-full positioning
- Menu closes on outside click and when file is selected
2026-01-10 22:54:33 +00:00
aewing 4bb4e546c1 Prevent horizontal scrolling in card view - allow vertical scroll only 2026-01-10 22:42:01 +00:00
aewing 0dc0ffba2f Keep button group beside Notes heading on all screen sizes 2026-01-10 22:38:53 +00:00
2 changed files with 375 additions and 37 deletions
+375 -20
View File
@@ -52,9 +52,9 @@
</div>
<!-- Notes List Container -->
<div id="notesListContainer" class="hidden flex flex-col bg-purple-100 rounded-2xl shadow-2xl border border-purple-200 max-w-5xl w-full p-6 gap-4 flex-1 overflow-hidden mt-2.5 mb-3">
<div id="notesListContainer" class="hidden flex flex-col bg-purple-100 rounded-2xl shadow-2xl border border-purple-200 max-w-5xl w-full p-6 gap-4 max-h-[calc(100vh-136px)] overflow-hidden mt-6 mb-3">
<div class="flex-shrink-0">
<div class="flex flex-col sm:flex-row sm:items-center sm:justify-between gap-3">
<div class="flex flex-row items-center justify-between gap-3">
<div>
<h2 class="text-lg sm:text-2xl font-bold text-gray-800">Notes</h2>
</div>
@@ -87,7 +87,7 @@
<div id="notesAttachmentPreviewContent" class="space-y-2"></div>
</div>
</div>
<div class="flex-1 overflow-y-auto">
<div class="flex-1 overflow-x-hidden overflow-y-auto">
<div id="notesListStatus" class="text-sm text-gray-600"></div>
<div id="notesEmpty" class="hidden text-sm text-gray-500">No notes yet. Click New Note to create one.</div>
<div id="notesGrid" class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-2 w-full"></div>
@@ -122,7 +122,7 @@
</div>
<!-- Note + Audio Container -->
<div id="noteContainer" class="hidden self-center bg-white rounded-2xl shadow-2xl max-w-xl w-full p-8 space-y-6">
<div id="noteContainer" class="hidden self-center bg-white rounded-2xl shadow-2xl max-w-xl w-full py-[8px] px-8 space-y-6 mt-4">
<div class="flex items-center gap-2 flex-wrap">
<button id="backToListBtn" class="px-2 sm:px-3 py-1 sm:py-2 text-xs sm:text-sm rounded border border-gray-200 text-gray-700 hover:bg-gray-100">Back to Notes</button>
<h2 class="text-lg sm:text-2xl font-bold text-gray-800">New Note</h2>
@@ -210,16 +210,91 @@
</div>
<div id="recordStatus" class="text-xs text-gray-500"></div>
</div>
<div class="space-y-2">
<div class="space-y-2 -mt-8">
<label class="block text-sm font-medium text-gray-700">Attachments</label>
<input id="noteAttachmentsInput" type="file" multiple class="w-full text-sm" accept="image/*,video/*,.pdf,.doc,.docx,.xls,.xlsx,.ppt,.pptx,.txt">
<div class="flex items-center gap-2">
<button id="clearAttachmentsBtn" class="px-3 py-1 rounded border border-gray-200 text-gray-700 hover:bg-gray-100 text-sm" type="button">Clear</button>
<div id="noteAttachmentsSummary" class="text-xs text-gray-600">No attachments selected.</div>
<div class="relative">
<div class="flex items-center gap-2">
<button id="attachmentMenuBtn" class="px-3 py-2 rounded border border-gray-300 text-gray-700 hover:bg-gray-100 transition flex items-center gap-2" type="button" title="Add attachment">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" class="w-5 h-5">
<path d="M21.5 2v6h-6M2.5 22v-6h6M2 11.5a10 10 0 0 1 18.8-4.3M22 12.5a10 10 0 0 1-18.8 4.2"/>
</svg>
Attach
</button>
<button id="clearAttachmentsBtn" class="px-3 py-1 rounded border border-gray-200 text-gray-700 hover:bg-gray-100 text-sm" type="button">Clear</button>
<div id="noteAttachmentsSummary" class="text-xs text-gray-600">No attachments selected.</div>
</div>
<!-- Attachment Menu -->
<div id="attachmentMenu" class="hidden absolute top-0 left-0 ml-28 w-48 rounded border border-gray-300 bg-white shadow-lg z-10">
<button id="attachImageBtn" class="w-full text-left px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 flex items-center justify-between gap-2" type="button">
<span class="flex items-center gap-2">
<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">
<rect x="3" y="3" width="18" height="18" rx="2" ry="2"/><circle cx="8.5" cy="8.5" r="1.5"/><polyline points="21 15 16 10 5 21"/>
</svg>
Attach Image
</span>
<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">
<polyline points="9 18 15 12 9 6"/>
</svg>
</button>
<div id="imageSubmenu" class="hidden bg-gray-50 border-t border-gray-200">
<button id="takePhotoBtn" class="w-full text-left px-6 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="selectImageBtn" class="w-full text-left px-6 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="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"/>
</svg>
Select Image
</button>
</div>
<button id="attachVideoBtn" class="w-full text-left px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 flex items-center justify-between gap-2" type="button">
<span class="flex items-center gap-2">
<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"/>
</svg>
Attach Video
</span>
<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">
<polyline points="9 18 15 12 9 6"/>
</svg>
</button>
<div id="videoSubmenu" class="hidden bg-gray-50 border-t border-gray-200">
<button id="recordVideoBtn" class="w-full text-left px-6 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>
Take Video
</button>
<button id="selectVideoBtn" class="w-full text-left px-6 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="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"/>
</svg>
Select Video
</button>
</div>
<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">
<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"/>
</svg>
Attach File
</button>
</div>
<!-- Hidden file inputs -->
<input id="imageInput" type="file" class="hidden" accept="image/*" multiple>
<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">
<div id="noteAttachmentsList" class="space-y-1"></div>
</div>
</div>
<div class="flex items-center gap-3">
<div class="flex items-center gap-3 -mt-8">
<button id="submitNoteBtn" class="px-4 py-2 rounded bg-secondary text-white font-semibold">Submit Note</button>
<div id="submitStatus" class="text-sm text-gray-600"></div>
</div>
@@ -228,7 +303,7 @@
<!-- Conversations List Container -->
<div id="conversationsContainer" class="hidden flex flex-col bg-purple-100 rounded-2xl shadow-2xl border border-purple-200 max-w-5xl w-full p-6 gap-4 flex-1 overflow-hidden mt-2.5 mb-3">
<div class="flex-shrink-0">
<div class="flex flex-col sm:flex-row sm:items-center sm:justify-between gap-3">
<div class="flex flex-row items-center justify-between gap-3">
<div>
<h2 class="text-lg sm:text-2xl font-bold text-gray-800">Conversations</h2>
</div>
@@ -238,7 +313,7 @@
</div>
</div>
</div>
<div class="flex-1 overflow-y-auto">
<div class="flex-1 overflow-x-hidden overflow-y-auto">
<div id="conversationsListStatus" class="text-sm text-gray-600"></div>
<div id="conversationsEmpty" class="hidden text-sm text-gray-500">No conversations yet. Click New Conversation to start one.</div>
<div id="conversationsGrid" class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-2 w-full"></div>
@@ -340,6 +415,91 @@
<div id="conversationRecordStatus" class="text-xs text-gray-500"></div>
</div>
<div class="space-y-2">
<label class="block text-sm font-medium text-gray-700">Attachments</label>
<div class="relative">
<div class="flex items-center gap-2">
<button id="conversationAttachmentMenuBtn" class="px-3 py-2 rounded border border-gray-300 text-gray-700 hover:bg-gray-100 transition flex items-center gap-2" type="button" title="Add attachment">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" class="w-5 h-5">
<path d="M21.5 2v6h-6M2.5 22v-6h6M2 11.5a10 10 0 0 1 18.8-4.3M22 12.5a10 10 0 0 1-18.8 4.2"/>
</svg>
Attach
</button>
<button id="conversationClearAttachmentsBtn" class="px-3 py-1 rounded border border-gray-200 text-gray-700 hover:bg-gray-100 text-sm" type="button">Clear</button>
<div id="conversationAttachmentsSummary" class="text-xs text-gray-600">No attachments selected.</div>
</div>
<!-- Conversation Attachment Menu -->
<div id="conversationAttachmentMenu" class="hidden absolute top-0 left-0 ml-28 w-48 rounded border border-gray-300 bg-white shadow-lg z-10">
<button id="conversationAttachImageBtn" class="w-full text-left px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 flex items-center justify-between gap-2" type="button">
<span class="flex items-center gap-2">
<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">
<rect x="3" y="3" width="18" height="18" rx="2" ry="2"/><circle cx="8.5" cy="8.5" r="1.5"/><polyline points="21 15 16 10 5 21"/>
</svg>
Attach Image
</span>
<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">
<polyline points="9 18 15 12 9 6"/>
</svg>
</button>
<div id="conversationImageSubmenu" class="hidden bg-gray-50 border-t border-gray-200">
<button id="conversationTakePhotoBtn" class="w-full text-left px-6 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="conversationSelectImageBtn" class="w-full text-left px-6 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="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"/>
</svg>
Select Image
</button>
</div>
<button id="conversationAttachVideoBtn" class="w-full text-left px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 flex items-center justify-between gap-2" type="button">
<span class="flex items-center gap-2">
<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"/>
</svg>
Attach Video
</span>
<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">
<polyline points="9 18 15 12 9 6"/>
</svg>
</button>
<div id="conversationVideoSubmenu" class="hidden bg-gray-50 border-t border-gray-200">
<button id="conversationRecordVideoBtn" class="w-full text-left px-6 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>
Take Video
</button>
<button id="conversationSelectVideoBtn" class="w-full text-left px-6 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="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"/>
</svg>
Select Video
</button>
</div>
<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">
<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"/>
</svg>
Attach File
</button>
</div>
<!-- Hidden file inputs for conversation -->
<input id="conversationImageInput" type="file" class="hidden" accept="image/*" multiple>
<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">
<div id="conversationAttachmentsList" class="space-y-1"></div>
</div>
</div>
<div class="flex items-center gap-3">
<button id="submitConversationBtn" class="px-4 py-2 rounded bg-secondary text-white font-semibold">Submit Conversation</button>
<div id="conversationSubmitStatus" class="text-sm text-gray-600"></div>
@@ -371,6 +531,7 @@
let silenceTimer = null;
let searchSilenceTimer = null;
let pendingNoteAttachments = [];
let pendingConversationAttachments = [];
// --- Voice Recognition Setup with auto-stop ---
function setupTitleVoiceRecognition() {
@@ -1269,6 +1430,33 @@
listEl.appendChild(frag);
}
function renderConversationAttachmentsList() {
const listEl = document.getElementById('conversationAttachmentsList');
const summaryEl = document.getElementById('conversationAttachmentsSummary');
listEl.innerHTML = '';
if (!pendingConversationAttachments.length) {
summaryEl.textContent = 'No attachments selected.';
return;
}
summaryEl.textContent = `${pendingConversationAttachments.length} file(s) selected`;
const frag = document.createDocumentFragment();
pendingConversationAttachments.forEach((file) => {
const row = document.createElement('div');
row.className = 'flex items-center gap-2 text-sm text-gray-800';
const kind = attachmentKindFromName(file.name);
const badge = document.createElement('span');
badge.className = 'px-2 py-0.5 rounded-full text-xs border border-gray-200 text-gray-700 bg-gray-50';
badge.textContent = kind;
const label = document.createElement('span');
const size = formatBytes(file.size);
label.textContent = size ? `${file.name} (${size})` : file.name;
row.appendChild(badge);
row.appendChild(label);
frag.appendChild(row);
});
listEl.appendChild(frag);
}
function resetNoteForm() {
document.getElementById('noteTitle').value = '';
document.getElementById('noteText').value = '';
@@ -1292,6 +1480,11 @@
document.getElementById('conversationJobNumberContainer').classList.add('hidden');
document.getElementById('conversationAudioPreview').src = '';
document.getElementById('conversationAudioPlayer').classList.add('hidden');
pendingConversationAttachments = [];
document.getElementById('conversationImageInput').value = '';
document.getElementById('conversationVideoInput').value = '';
document.getElementById('conversationFileInput').value = '';
renderConversationAttachmentsList();
}
function renderNotesList(items) {
@@ -1592,18 +1785,178 @@
showNoteForm();
});
document.getElementById('noteAttachmentsInput').addEventListener('change', (e) => {
pendingNoteAttachments = Array.from(e.target.files || []);
renderNoteAttachmentsList();
// Attachment menu handling
const attachmentMenuBtn = document.getElementById('attachmentMenuBtn');
const attachmentMenu = document.getElementById('attachmentMenu');
const imageInput = document.getElementById('imageInput');
const imageCameraInput = document.getElementById('imageCameraInput');
const videoInput = document.getElementById('videoInput');
const videoCameraInput = document.getElementById('videoCameraInput');
const fileInput = document.getElementById('fileInput');
attachmentMenuBtn.addEventListener('click', (e) => {
e.preventDefault();
attachmentMenu.classList.toggle('hidden');
});
const imageSubmenu = document.getElementById('imageSubmenu');
const videoSubmenu = document.getElementById('videoSubmenu');
document.getElementById('attachImageBtn').addEventListener('click', () => {
imageSubmenu.classList.toggle('hidden');
videoSubmenu.classList.add('hidden');
});
document.getElementById('takePhotoBtn').addEventListener('click', () => {
attachmentMenu.classList.add('hidden');
imageSubmenu.classList.add('hidden');
imageCameraInput.click();
});
document.getElementById('selectImageBtn').addEventListener('click', () => {
attachmentMenu.classList.add('hidden');
imageSubmenu.classList.add('hidden');
imageInput.click();
});
document.getElementById('attachVideoBtn').addEventListener('click', () => {
videoSubmenu.classList.toggle('hidden');
imageSubmenu.classList.add('hidden');
});
document.getElementById('recordVideoBtn').addEventListener('click', () => {
attachmentMenu.classList.add('hidden');
videoSubmenu.classList.add('hidden');
videoCameraInput.click();
});
document.getElementById('selectVideoBtn').addEventListener('click', () => {
attachmentMenu.classList.add('hidden');
videoSubmenu.classList.add('hidden');
videoInput.click();
});
document.getElementById('attachFileBtn').addEventListener('click', () => {
attachmentMenu.classList.add('hidden');
imageSubmenu.classList.add('hidden');
videoSubmenu.classList.add('hidden');
fileInput.click();
});
// File input change handlers
[imageInput, imageCameraInput, videoInput, videoCameraInput, fileInput].forEach(input => {
input.addEventListener('change', (e) => {
pendingNoteAttachments.push(...Array.from(e.target.files || []));
renderNoteAttachmentsList();
});
});
document.getElementById('clearAttachmentsBtn').addEventListener('click', (e) => {
e.preventDefault();
pendingNoteAttachments = [];
document.getElementById('noteAttachmentsInput').value = '';
imageInput.value = '';
imageCameraInput.value = '';
videoInput.value = '';
videoCameraInput.value = '';
fileInput.value = '';
renderNoteAttachmentsList();
});
// Close menu on outside click
document.addEventListener('click', (e) => {
if (!attachmentMenuBtn.contains(e.target) && !attachmentMenu.contains(e.target)) {
attachmentMenu.classList.add('hidden');
imageSubmenu.classList.add('hidden');
videoSubmenu.classList.add('hidden');
}
});
// Conversation attachment menu setup
const conversationAttachmentMenuBtn = document.getElementById('conversationAttachmentMenuBtn');
const conversationAttachmentMenu = document.getElementById('conversationAttachmentMenu');
const conversationImageInput = document.getElementById('conversationImageInput');
const conversationImageCameraInput = document.getElementById('conversationImageCameraInput');
const conversationVideoInput = document.getElementById('conversationVideoInput');
const conversationVideoCameraInput = document.getElementById('conversationVideoCameraInput');
const conversationFileInput = document.getElementById('conversationFileInput');
conversationAttachmentMenuBtn.addEventListener('click', (e) => {
e.preventDefault();
conversationAttachmentMenu.classList.toggle('hidden');
});
const conversationImageSubmenu = document.getElementById('conversationImageSubmenu');
const conversationVideoSubmenu = document.getElementById('conversationVideoSubmenu');
document.getElementById('conversationAttachImageBtn').addEventListener('click', () => {
conversationImageSubmenu.classList.toggle('hidden');
conversationVideoSubmenu.classList.add('hidden');
});
document.getElementById('conversationTakePhotoBtn').addEventListener('click', () => {
conversationAttachmentMenu.classList.add('hidden');
conversationImageSubmenu.classList.add('hidden');
conversationImageCameraInput.click();
});
document.getElementById('conversationSelectImageBtn').addEventListener('click', () => {
conversationAttachmentMenu.classList.add('hidden');
conversationImageSubmenu.classList.add('hidden');
conversationImageInput.click();
});
document.getElementById('conversationAttachVideoBtn').addEventListener('click', () => {
conversationVideoSubmenu.classList.toggle('hidden');
conversationImageSubmenu.classList.add('hidden');
});
document.getElementById('conversationRecordVideoBtn').addEventListener('click', () => {
conversationAttachmentMenu.classList.add('hidden');
conversationVideoSubmenu.classList.add('hidden');
conversationVideoCameraInput.click();
});
document.getElementById('conversationSelectVideoBtn').addEventListener('click', () => {
conversationAttachmentMenu.classList.add('hidden');
conversationVideoSubmenu.classList.add('hidden');
conversationVideoInput.click();
});
document.getElementById('conversationAttachFileBtn').addEventListener('click', () => {
conversationAttachmentMenu.classList.add('hidden');
conversationImageSubmenu.classList.add('hidden');
conversationVideoSubmenu.classList.add('hidden');
conversationFileInput.click();
});
// File input change handlers for conversation
[conversationImageInput, conversationImageCameraInput, conversationVideoInput, conversationVideoCameraInput, conversationFileInput].forEach(input => {
input.addEventListener('change', (e) => {
pendingConversationAttachments.push(...Array.from(e.target.files || []));
renderConversationAttachmentsList();
});
});
document.getElementById('conversationClearAttachmentsBtn').addEventListener('click', (e) => {
e.preventDefault();
pendingConversationAttachments = [];
conversationImageInput.value = '';
conversationImageCameraInput.value = '';
conversationVideoInput.value = '';
conversationVideoCameraInput.value = '';
conversationFileInput.value = '';
renderConversationAttachmentsList();
});
// Close conversation menu on outside click
document.addEventListener('click', (e) => {
if (!conversationAttachmentMenuBtn.contains(e.target) && !conversationAttachmentMenu.contains(e.target)) {
conversationAttachmentMenu.classList.add('hidden');
conversationImageSubmenu.classList.add('hidden');
conversationVideoSubmenu.classList.add('hidden');
}
});
// Search input + voice
const notesSearchInput = document.getElementById('notesSearch');
const searchVoiceBtn = document.getElementById('searchVoiceBtn');
@@ -1758,9 +2111,7 @@
const createdAtt = await pb.collection(ATTACHMENTS_COLLECTION).create(fd);
attachmentRecords.push(createdAtt);
}
const inputEl = document.getElementById('noteAttachmentsInput');
const filesFromInput = Array.from(inputEl?.files || []);
const filesToUpload = (pendingNoteAttachments && pendingNoteAttachments.length) ? pendingNoteAttachments : filesFromInput;
const filesToUpload = (pendingNoteAttachments && pendingNoteAttachments.length) ? pendingNoteAttachments : [];
if (filesToUpload && filesToUpload.length) {
const fdFiles = new FormData();
for (let i = 0; i < filesToUpload.length; i++) {
@@ -1784,7 +2135,11 @@
statusEl.textContent = `Saved note ${noteRecord.id}${attachmentMsg}`;
await clearAudio();
pendingNoteAttachments = [];
document.getElementById('noteAttachmentsInput').value = '';
document.getElementById('imageInput').value = '';
document.getElementById('imageCameraInput').value = '';
document.getElementById('videoInput').value = '';
document.getElementById('videoCameraInput').value = '';
document.getElementById('fileInput').value = '';
renderNoteAttachmentsList();
document.getElementById('noteText').value = '';
document.getElementById('noteTitle').value = '';
-17
View File
@@ -3,23 +3,6 @@ PRISM NOTES - SESSION LOG
Project history, decisions, and architectural milestones
================================================================================
[2026-01-10 20:45] MONICA SESSION: UI Refinements & Polish
- Changes Applied:
* Centered all main containers (body: flex items-center justify-center)
* Reduced card spacing dramatically for compact dense layout
- Grid gap: gap-5 → gap-2 (between cards)
- Card padding: p-5 sm:p-6 → px-2 py-0.5 (internal spacing)
- Internal spacing: space-y-3 → space-y-0 (elements in cards)
* Improved attachment indicator icons with outline strokes instead of fills
- Image: mountain/landscape icon (clearer than grid pattern)
- Video: play button with frame (recognizable)
- Audio: speaker icon (listening/playback, not microphone which is for recording)
- File: document with corner fold (standard file representation)
* Fixed mobile view icon visibility by increasing size to 24px and adding flex-shrink-0
* Replaced purple badges with subtle hover-on-gray style for icons
- Result: Cleaner, more compact UI with better visual hierarchy
- Status: Fixed and committed (a168fe2)
[2026-01-10 20:10] MONICA SESSION: Fixed Container Injection Bug
- Issue: Refactor commit (cee9157) had CONTAINERS + initializeContainers() code
but ALSO kept all old HTML in DOM, creating duplicates and preventing injection