Skip to content

Commit cb4b994

Browse files
authored
feat(admin): integrate image upload into content editor (iflabx#288)
1 parent bc7e5ff commit cb4b994

1 file changed

Lines changed: 79 additions & 1 deletion

File tree

components/admin/content/context-menu.tsx

Lines changed: 79 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
'use client';
22

3+
import { ImageUploadDialog } from '@components/admin/content/image-upload-dialog';
34
import { Input } from '@components/ui/input';
45
import { Label } from '@components/ui/label';
56
import {
@@ -10,9 +11,10 @@ import {
1011
SelectValue,
1112
} from '@components/ui/select';
1213
import { Textarea } from '@components/ui/textarea';
14+
import { createClient } from '@lib/supabase/client';
1315
import { ComponentInstance } from '@lib/types/about-page-components';
1416
import { cn } from '@lib/utils';
15-
import { Plus, Trash2, X } from 'lucide-react';
17+
import { Plus, Trash2, Upload, X } from 'lucide-react';
1618

1719
import React, { useEffect, useRef, useState } from 'react';
1820

@@ -40,6 +42,8 @@ export const ContextMenu: React.FC<ContextMenuProps> = ({
4042
}) => {
4143
const modalRef = useRef<HTMLDivElement>(null);
4244
const [position, setPosition] = useState({ x, y });
45+
const [isUploadDialogOpen, setIsUploadDialogOpen] = useState(false);
46+
const [userId, setUserId] = useState<string | null>(null);
4347

4448
useEffect(() => {
4549
if (modalRef.current) {
@@ -79,6 +83,27 @@ export const ContextMenu: React.FC<ContextMenuProps> = ({
7983
};
8084
}, [onClose]);
8185

86+
// Fetch current user ID on mount
87+
useEffect(() => {
88+
let isMounted = true;
89+
90+
const fetchUserId = async () => {
91+
const supabase = createClient();
92+
const {
93+
data: { user },
94+
} = await supabase.auth.getUser();
95+
if (isMounted && user) {
96+
setUserId(user.id);
97+
}
98+
};
99+
100+
fetchUserId();
101+
102+
return () => {
103+
isMounted = false;
104+
};
105+
}, []);
106+
82107
/**
83108
* Validate if a value is a valid CSS dimension
84109
*
@@ -516,6 +541,46 @@ export const ContextMenu: React.FC<ContextMenuProps> = ({
516541
);
517542
}
518543

544+
// Special handling for src field in image component
545+
if (
546+
key === 'src' &&
547+
component.type === 'image' &&
548+
typeof value === 'string'
549+
) {
550+
return (
551+
<div key={key} className="space-y-2">
552+
<Label htmlFor={fieldId} className="text-sm capitalize">
553+
{key}
554+
</Label>
555+
<div className="flex gap-2">
556+
<Input
557+
id={fieldId}
558+
type="text"
559+
value={String(value || '')}
560+
onChange={e => handleInputChange(key, e.target.value)}
561+
placeholder="Enter image URL"
562+
className="h-8 flex-1 text-sm"
563+
/>
564+
<button
565+
type="button"
566+
onClick={() => setIsUploadDialogOpen(true)}
567+
disabled={!userId}
568+
className={cn(
569+
'flex h-8 items-center gap-1.5 rounded-md border px-3 text-xs font-medium transition-colors',
570+
'border-stone-300 bg-white text-stone-700 hover:bg-stone-50',
571+
'dark:border-stone-600 dark:bg-stone-800 dark:text-stone-200 dark:hover:bg-stone-700',
572+
'disabled:cursor-not-allowed disabled:opacity-50'
573+
)}
574+
title="Upload local image"
575+
>
576+
<Upload className="h-3.5 w-3.5" />
577+
<span>Upload</span>
578+
</button>
579+
</div>
580+
</div>
581+
);
582+
}
583+
519584
// String fields
520585
if (typeof value === 'string') {
521586
return (
@@ -591,6 +656,19 @@ export const ContextMenu: React.FC<ContextMenuProps> = ({
591656
renderPropertyField('secondaryButton', undefined)}
592657
</div>
593658
</div>
659+
660+
{/* Image Upload Dialog */}
661+
{userId && (
662+
<ImageUploadDialog
663+
isOpen={isUploadDialogOpen}
664+
onClose={() => setIsUploadDialogOpen(false)}
665+
onUploadSuccess={url => {
666+
// Auto-fill the uploaded image URL to src field
667+
handleInputChange('src', url);
668+
}}
669+
userId={userId}
670+
/>
671+
)}
594672
</>
595673
);
596674
};

0 commit comments

Comments
 (0)