Skip to content

Commit 9af4188

Browse files
committed
Add recents tab for message attachment.
Add popup toolbars.
1 parent 45ad6bc commit 9af4188

21 files changed

Lines changed: 980 additions & 193 deletions

Public/app/css/common.css

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,7 @@ h1, h2, h3, h4, h5, h6 {
272272
font-size: 1rem;
273273
transition: border-color 0.3s ease;
274274
background: hsl(var(--muted));
275+
color: hsl(var(--foreground));
275276
font-family: inherit;
276277
}
277278

Public/app/css/main.css

Lines changed: 91 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,12 @@
4040
opacity: 0.5;
4141
}
4242

43+
.inline-button.small {
44+
width: 24px;
45+
height: 24px;
46+
border-radius: 4px;
47+
}
48+
4349
/* Input Component */
4450
input[type="text"], textarea {
4551
display: flex;
@@ -2384,6 +2390,34 @@ input[type="text"]:disabled, textarea:disabled {
23842390
position: relative;
23852391
}
23862392

2393+
/* Popup Toolbar */
2394+
.popup-toolbar {
2395+
position: fixed;
2396+
display: inline-flex;
2397+
align-items: center;
2398+
gap: 3px;
2399+
padding: 3px;
2400+
background-color: hsl(var(--popover));
2401+
border: none;
2402+
border-radius: 0.375rem;
2403+
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
2404+
z-index: 1000;
2405+
animation: context-menu-fade-in 0.18s ease forwards;
2406+
box-sizing: border-box;
2407+
}
2408+
2409+
.popup-toolbar .inline-button {
2410+
width: calc(2.25rem - 6px);
2411+
height: calc(2.25rem - 6px);
2412+
border-radius: calc(0.375rem - 2px);
2413+
flex-shrink: 0;
2414+
}
2415+
2416+
.popup-toolbar .inline-button svg {
2417+
width: 16px;
2418+
height: 16px;
2419+
}
2420+
23872421
/* Context Menu - Unified menu styles */
23882422
@keyframes context-menu-fade-in {
23892423
from {
@@ -2625,14 +2659,55 @@ input[type="text"]:disabled, textarea:disabled {
26252659
flex-direction: column;
26262660
}
26272661

2628-
#attachmentPreviewContainer {
2629-
padding: 6px 0;
2630-
margin-bottom: 6px;
2662+
#mediaPanelContainer {
2663+
margin-bottom: 10px;
2664+
width: 100%;
2665+
}
2666+
2667+
.media-panel-header {
2668+
display: flex;
2669+
align-items: center;
2670+
justify-content: space-between;
2671+
gap: 8px;
2672+
}
2673+
2674+
.media-panel-tabs {
2675+
display: flex;
2676+
gap: 12px;
2677+
}
2678+
2679+
.media-panel-tab {
2680+
font-size: 0.75rem;
2681+
font-weight: 600;
2682+
color: hsl(var(--muted-foreground) / 0.8);
2683+
text-transform: uppercase;
2684+
letter-spacing: 0.5px;
2685+
background: none;
2686+
border: none;
2687+
border-radius: 4px;
2688+
cursor: pointer;
2689+
transition: color 0.15s, background-color 0.15s;
2690+
}
2691+
2692+
.media-panel-tab.active {
2693+
color: hsl(var(--foreground) / 0.8);
2694+
}
2695+
2696+
.media-panel-items-row {
2697+
padding-top: 10px;
26312698
width: 100%;
26322699
display: flex;
26332700
flex-direction: row;
26342701
gap: 10px;
26352702
align-items: flex-end;
2703+
overflow-x: auto;
2704+
scrollbar-width: thin;
2705+
}
2706+
2707+
.media-panel-empty {
2708+
padding: 6px 0 10px 0;
2709+
font-size: 0.875rem;
2710+
color: hsl(var(--muted-foreground));
26362711
}
26372712

26382713
.attachment-preview-item {
@@ -2717,8 +2792,7 @@ input[type="text"]:disabled, textarea:disabled {
27172792
height: 24px;
27182793
z-index: 10;
27192794
pointer-events: none;
2720-
stroke: white;
2721-
filter: drop-shadow(0 1px 2px rgba(0, 0, 0, 0.5));
2795+
filter: drop-shadow(0 1px 3px rgba(0, 0, 0, 0.4));
27222796
}
27232797

27242798
.attachment-upload-checkmark svg {
@@ -2919,3 +2993,15 @@ input[type="text"]:disabled, textarea:disabled {
29192993
opacity: 0.5;
29202994
font-size: 0.9rem;
29212995
}
2996+
/* ── Media Panel (shared) ───────────────────────────────────────────────────── */
2997+
2998+
.recent-media-select-circle {
2999+
position: absolute;
3000+
bottom: 4px;
3001+
right: 4px;
3002+
width: 24px;
3003+
height: 24px;
3004+
pointer-events: none;
3005+
filter: drop-shadow(0 1px 2px rgba(0, 0, 0, 0.4));
3006+
z-index: 10;
3007+
}

Public/app/html/main.leaf

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -108,10 +108,10 @@
108108
<!-- Message Input -->
109109
<div class="px-4" id="messageInputContainer" style="display: none;">
110110
<div id="editPreviewContainer" style="display: none;"></div>
111-
<div id="attachmentPreviewContainer" style="display: none;"></div>
111+
<div id="mediaPanelContainer" style="display: none;"></div>
112112
<div class="flex items-center gap-2">
113113
<input type="file" id="attachmentInput" accept="image/*,video/*" multiple style="display: none;">
114-
<button class="inline-button" id="attachButton" onclick="openAttachmentDialog()">
114+
<button class="inline-button" id="attachButton" onclick="handleAttachButtonClick(event)" onmouseenter="handleAttachButtonHover(event)">
115115
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-paperclip">
116116
<path d="m16 6-8.414 8.586a2 2 0 0 0 2.829 2.829l8.414-8.586a4 4 0 1 0-5.657-5.657l-8.379 8.551a6 6 0 1 0 8.485 8.485l8.379-8.551"></path>
117117
</svg>

Public/app/js/api.js

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -635,3 +635,22 @@ async function apiDeleteUpload(fileName) {
635635
function getUploadUrl(fileId, fileType) {
636636
return `/uploads/${fileId}.${fileType}`;
637637
}
638+
639+
async function apiGetRecentMedia() {
640+
const accessToken = getAccessToken();
641+
if (!accessToken) throw new Error('No access token available');
642+
const response = await fetch('/media/recents', {
643+
headers: { 'Authorization': `Bearer ${accessToken}` }
644+
});
645+
return await handleResponse(response);
646+
}
647+
648+
async function apiDeleteMedia(mediaId) {
649+
const accessToken = getAccessToken();
650+
if (!accessToken) throw new Error('No access token available');
651+
const response = await fetch(`/media/${encodeURIComponent(mediaId)}`, {
652+
method: 'DELETE',
653+
headers: { 'Authorization': `Bearer ${accessToken}` }
654+
});
655+
return await handleResponse(response);
656+
}

0 commit comments

Comments
 (0)