Refactor forms and uploader components UI with Card layout
Updated color, font, and asset forms to use Card and CardContent for improved structure and consistency. Enhanced input styles and hover effects for better user experience. Adjusted the image uploader background for a more cohesive design.
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
// src/components/themes/event-theme-assets-uploader.tsx
|
||||
// src/components/event-themes/event-theme-assets-uploader.tsx
|
||||
"use client";
|
||||
|
||||
import React, { useState } from "react";
|
||||
@@ -7,6 +7,7 @@ import { Button } from "@/components/ui/button";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Label } from "@/components/ui/label";
|
||||
import { ImageUploader } from "@/components/ui/image-uploader";
|
||||
import { Card, CardContent } from "@/components/ui/card";
|
||||
|
||||
interface AssetImage {
|
||||
key: string;
|
||||
@@ -76,69 +77,73 @@ export function EventThemeAssetsUploader({
|
||||
|
||||
return (
|
||||
<div className="space-y-4">
|
||||
<div className="flex items-center justify-between">
|
||||
<Label className="text-base">Theme Assets</Label>
|
||||
<div className="flex items-center justify-between mb-3">
|
||||
<Label className="text-base font-semibold text-gray-900">
|
||||
Theme Assets
|
||||
</Label>
|
||||
<Button
|
||||
type="button"
|
||||
variant="outline"
|
||||
size="sm"
|
||||
className="flex items-center gap-1.5 text-sm font-medium"
|
||||
onClick={handleAddAsset}
|
||||
>
|
||||
<PlusCircle className="h-4 w-4 mr-2" />
|
||||
<PlusCircle className="h-4 w-4" />
|
||||
Add Asset
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<div className="space-y-4">
|
||||
<div className="space-y-3">
|
||||
{assets.map((asset, index) => (
|
||||
<div
|
||||
<Card
|
||||
key={index}
|
||||
className="grid grid-cols-1 md:grid-cols-[1fr,2fr,auto] gap-4 items-start p-4 border rounded-md bg-gray-50"
|
||||
className="overflow-hidden hover:shadow-md transition-shadow"
|
||||
>
|
||||
<div>
|
||||
<Label htmlFor={`asset-key-${index}`} className="mb-2 block">
|
||||
Asset Key
|
||||
</Label>
|
||||
<Input
|
||||
id={`asset-key-${index}`}
|
||||
value={asset.key}
|
||||
onChange={(e) => handleKeyChange(index, e.target.value)}
|
||||
placeholder="E.g., 'animal1', 'balloon', etc."
|
||||
<CardContent className="grid grid-cols-1 md:grid-cols-[1fr,2fr,auto] gap-4 items-start p-4 pt-4">
|
||||
<div>
|
||||
<Label
|
||||
htmlFor={`asset-key-${index}`}
|
||||
className="mb-2 block text-sm font-medium text-gray-700"
|
||||
>
|
||||
Asset Key
|
||||
</Label>
|
||||
<Input
|
||||
id={`asset-key-${index}`}
|
||||
value={asset.key}
|
||||
onChange={(e) => handleKeyChange(index, e.target.value)}
|
||||
placeholder="E.g., 'animal1', 'balloon', etc."
|
||||
className="focus:ring-2 focus:ring-primary/20"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<ImageUploader
|
||||
id={`asset-url-${index}`}
|
||||
label="Asset Image"
|
||||
imageUrl={asset.url}
|
||||
purpose="theme-asset"
|
||||
onChange={(url) => handleUrlChange(index, url)}
|
||||
aspectRatio="square"
|
||||
maxWidth={400}
|
||||
maxHeight={400}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<ImageUploader
|
||||
id={`asset-url-${index}`}
|
||||
label="Asset Image"
|
||||
imageUrl={asset.url}
|
||||
purpose="theme-asset"
|
||||
onChange={(url) => handleUrlChange(index, url)}
|
||||
aspectRatio="square"
|
||||
maxWidth={400}
|
||||
maxHeight={400}
|
||||
/>
|
||||
|
||||
<div className="flex items-end h-full pb-2">
|
||||
<Button
|
||||
type="button"
|
||||
variant="destructive"
|
||||
size="icon"
|
||||
onClick={() => handleRemoveAsset(index)}
|
||||
disabled={assets.length === 1}
|
||||
title="Remove Asset"
|
||||
>
|
||||
<Trash2 className="h-4 w-4" />
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex items-end h-full pb-2">
|
||||
<Button
|
||||
type="button"
|
||||
variant="destructive"
|
||||
size="icon"
|
||||
onClick={() => handleRemoveAsset(index)}
|
||||
disabled={assets.length === 1}
|
||||
title="Remove Asset"
|
||||
className="hover:bg-red-600/90 transition-colors"
|
||||
>
|
||||
<Trash2 className="h-4 w-4" />
|
||||
</Button>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{assets.length === 0 && (
|
||||
<p className="text-sm text-gray-500 italic">
|
||||
No assets added. Click "Add Asset" to add theme assets.
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -327,56 +327,64 @@ export function EventThemeForm({ theme, mode }: ThemeFormProps) {
|
||||
|
||||
<div className="grid grid-cols-1 gap-4">
|
||||
{colorInputs.map((input, index) => (
|
||||
<div
|
||||
key={index}
|
||||
className="flex items-center space-x-4 p-3 border rounded-md bg-gray-50"
|
||||
>
|
||||
<div className="flex-1">
|
||||
<Label htmlFor={`color-name-${index}`} className="sr-only">
|
||||
Color Name
|
||||
</Label>
|
||||
<Input
|
||||
id={`color-name-${index}`}
|
||||
value={input.name}
|
||||
onChange={(e) =>
|
||||
updateColorInput(index, "name", e.target.value)
|
||||
}
|
||||
placeholder="Color name (e.g., primary, secondary)"
|
||||
/>
|
||||
</div>
|
||||
<Card key={index} className="p-0 border overflow-hidden">
|
||||
<CardContent className="flex items-center space-x-4 p-3">
|
||||
<div className="flex-1">
|
||||
<Label
|
||||
htmlFor={`color-name-${index}`}
|
||||
className="sr-only"
|
||||
>
|
||||
Color Name
|
||||
</Label>
|
||||
<Input
|
||||
id={`color-name-${index}`}
|
||||
value={input.name}
|
||||
onChange={(e) =>
|
||||
updateColorInput(index, "name", e.target.value)
|
||||
}
|
||||
placeholder="Color name (e.g., primary, secondary)"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="flex-1 flex items-center space-x-2">
|
||||
<Input
|
||||
type="color"
|
||||
id={`color-value-${index}`}
|
||||
value={input.value}
|
||||
onChange={(e) =>
|
||||
updateColorInput(index, "value", e.target.value)
|
||||
}
|
||||
className="w-16 h-10 p-1"
|
||||
/>
|
||||
<Input
|
||||
type="text"
|
||||
value={input.value}
|
||||
onChange={(e) =>
|
||||
updateColorInput(index, "value", e.target.value)
|
||||
}
|
||||
placeholder="#RRGGBB"
|
||||
className="flex-1"
|
||||
/>
|
||||
</div>
|
||||
<div className="flex-1 flex items-center space-x-2">
|
||||
<div className="relative w-16 h-10 overflow-hidden rounded-md border border-input">
|
||||
<Input
|
||||
type="color"
|
||||
id={`color-value-${index}`}
|
||||
value={input.value}
|
||||
onChange={(e) =>
|
||||
updateColorInput(index, "value", e.target.value)
|
||||
}
|
||||
className="absolute inset-0 opacity-0 w-full h-full cursor-pointer"
|
||||
/>
|
||||
<div
|
||||
className="w-full h-full"
|
||||
style={{ backgroundColor: input.value }}
|
||||
/>
|
||||
</div>
|
||||
<Input
|
||||
type="text"
|
||||
value={input.value}
|
||||
onChange={(e) =>
|
||||
updateColorInput(index, "value", e.target.value)
|
||||
}
|
||||
placeholder="#RRGGBB"
|
||||
className="flex-1"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<Button
|
||||
type="button"
|
||||
variant="destructive"
|
||||
size="icon"
|
||||
onClick={() => removeColorInput(index)}
|
||||
disabled={colorInputs.length <= 1}
|
||||
title="Remove Color"
|
||||
>
|
||||
<Trash2 className="h-4 w-4" />
|
||||
</Button>
|
||||
</div>
|
||||
<Button
|
||||
type="button"
|
||||
variant="destructive"
|
||||
size="icon"
|
||||
onClick={() => removeColorInput(index)}
|
||||
disabled={colorInputs.length <= 1}
|
||||
title="Remove Color"
|
||||
>
|
||||
<Trash2 className="h-4 w-4" />
|
||||
</Button>
|
||||
</CardContent>
|
||||
</Card>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
@@ -398,49 +406,51 @@ export function EventThemeForm({ theme, mode }: ThemeFormProps) {
|
||||
|
||||
<div className="grid grid-cols-1 gap-4">
|
||||
{fontInputs.map((input, index) => (
|
||||
<div
|
||||
key={index}
|
||||
className="flex items-center space-x-4 p-3 border rounded-md bg-gray-50"
|
||||
>
|
||||
<div className="flex-1">
|
||||
<Label htmlFor={`font-name-${index}`} className="sr-only">
|
||||
Font Purpose
|
||||
</Label>
|
||||
<Input
|
||||
id={`font-name-${index}`}
|
||||
value={input.name}
|
||||
onChange={(e) =>
|
||||
updateFontInput(index, "name", e.target.value)
|
||||
}
|
||||
placeholder="Font purpose (e.g., heading, body)"
|
||||
/>
|
||||
</div>
|
||||
<Card key={index} className="p-0 border overflow-hidden">
|
||||
<CardContent className="flex items-center space-x-4 p-3">
|
||||
<div className="flex-1">
|
||||
<Label htmlFor={`font-name-${index}`} className="sr-only">
|
||||
Font Purpose
|
||||
</Label>
|
||||
<Input
|
||||
id={`font-name-${index}`}
|
||||
value={input.name}
|
||||
onChange={(e) =>
|
||||
updateFontInput(index, "name", e.target.value)
|
||||
}
|
||||
placeholder="Font purpose (e.g., heading, body)"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="flex-1">
|
||||
<Label htmlFor={`font-value-${index}`} className="sr-only">
|
||||
Font Name
|
||||
</Label>
|
||||
<Input
|
||||
id={`font-value-${index}`}
|
||||
value={input.value}
|
||||
onChange={(e) =>
|
||||
updateFontInput(index, "value", e.target.value)
|
||||
}
|
||||
placeholder="Font name (e.g., Inter, Roboto)"
|
||||
/>
|
||||
</div>
|
||||
<div className="flex-1">
|
||||
<Label
|
||||
htmlFor={`font-value-${index}`}
|
||||
className="sr-only"
|
||||
>
|
||||
Font Name
|
||||
</Label>
|
||||
<Input
|
||||
id={`font-value-${index}`}
|
||||
value={input.value}
|
||||
onChange={(e) =>
|
||||
updateFontInput(index, "value", e.target.value)
|
||||
}
|
||||
placeholder="Font name (e.g., Inter, Roboto)"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<Button
|
||||
type="button"
|
||||
variant="destructive"
|
||||
size="icon"
|
||||
onClick={() => removeFontInput(index)}
|
||||
disabled={fontInputs.length <= 1}
|
||||
title="Remove Font"
|
||||
>
|
||||
<Trash2 className="h-4 w-4" />
|
||||
</Button>
|
||||
</div>
|
||||
<Button
|
||||
type="button"
|
||||
variant="destructive"
|
||||
size="icon"
|
||||
onClick={() => removeFontInput(index)}
|
||||
disabled={fontInputs.length <= 1}
|
||||
title="Remove Font"
|
||||
>
|
||||
<Trash2 className="h-4 w-4" />
|
||||
</Button>
|
||||
</CardContent>
|
||||
</Card>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -123,7 +123,8 @@ export function ImageUploader({
|
||||
)}
|
||||
|
||||
<div
|
||||
className={`relative border-2 border-dashed border-gray-300 rounded-md ${getAspectRatioClass()} overflow-hidden bg-gray-50 hover:bg-gray-100 transition-colors`}
|
||||
className={`relative border-2 border-dashed border-border rounded-md ${getAspectRatioClass()}
|
||||
overflow-hidden bg-muted/30 hover:bg-muted/50 transition-colors`}
|
||||
>
|
||||
{/* Hidden file input */}
|
||||
<input
|
||||
|
||||
Reference in New Issue
Block a user