feat: zmena farby pozadia produktov a editovatelne nazvy modulov
This commit is contained in:
1 parent
4e4e5e5af3
commit
00d681bec2
7 files changed
+325
-87
No files matched your search
@@ -2,10 +2,19 @@
|
||||
|
||||
import React from 'react';
|
||||
import { NewsletterModule, ProductItem, BadgeTemplate } from '@/types/newsletter';
|
||||
import { Plus, Trash2, Image as ImageIcon, Tag, Store, Globe } from 'lucide-react';
|
||||
import { Plus, Trash2, Image as ImageIcon, Tag, Store, Globe, Palette, Check } from 'lucide-react';
|
||||
import { SUPABASE_ASSETS_BASE } from '@/lib/defaultCampaign';
|
||||
import { ImageUploadInput } from './ImageUploadInput';
|
||||
|
||||
const PRODUCT_BG_PRESETS = [
|
||||
{ label: 'Červená', sub: 'Fantasticky', color: '#feeaea', border: '#f5d4d4' },
|
||||
{ label: 'Žltá', sub: 'Domáce', color: '#fef0c7', border: '#e6d49a' },
|
||||
{ label: 'Hnedá', sub: 'Gril', color: '#dcb085', border: '#c49a6c' },
|
||||
{ label: 'Sivá', sub: 'Neutrálna', color: '#e6e1d9', border: '#d5cfc5' },
|
||||
{ label: 'Zelená', sub: 'Bio', color: '#e8f5e9', border: '#c8e6c9' },
|
||||
{ label: 'Biela', sub: 'Čistá', color: '#ffffff', border: '#e5e7eb' },
|
||||
];
|
||||
|
||||
interface ConfigPanelProps {
|
||||
module: NewsletterModule | null;
|
||||
onUpdateModule: (updated: NewsletterModule) => void;
|
||||
@@ -40,11 +49,20 @@ export const ConfigPanel: React.FC<ConfigPanelProps> = ({
|
||||
|
||||
return (
|
||||
<div className="h-full overflow-y-auto p-5 space-y-6 bg-white border-l border-gray-200">
|
||||
<div className="border-b border-gray-100 pb-3">
|
||||
<span className="text-[10px] font-bold uppercase tracking-wider text-red-600 bg-red-50 px-2 py-0.5 rounded">
|
||||
{module.type}
|
||||
</span>
|
||||
<h2 className="text-base font-bold text-gray-900 mt-1">{module.title}</h2>
|
||||
<div className="border-b border-gray-100 pb-3 space-y-1.5">
|
||||
<div className="flex items-center justify-between">
|
||||
<span className="text-[10px] font-bold uppercase tracking-wider text-red-600 bg-red-50 px-2 py-0.5 rounded">
|
||||
{module.type}
|
||||
</span>
|
||||
<span className="text-[10px] text-gray-400 font-medium">Názov modulu v editore</span>
|
||||
</div>
|
||||
<input
|
||||
type="text"
|
||||
value={module.title}
|
||||
onChange={(e) => onUpdateModule({ ...module, title: e.target.value })}
|
||||
placeholder="Názov modulu..."
|
||||
className="w-full text-base font-bold text-gray-900 border border-gray-200 hover:border-gray-300 focus:border-red-500 rounded-lg px-2.5 py-1.5 bg-gray-50/50 hover:bg-white focus:bg-white focus:outline-none focus:ring-1 focus:ring-red-500 transition-all"
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* TOP ANNOUNCEMENT */}
|
||||
@@ -307,6 +325,99 @@ export const ConfigPanel: React.FC<ConfigPanelProps> = ({
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Farba pozadia skupiny produktov */}
|
||||
<div className="bg-gray-50 p-3.5 rounded-xl border border-gray-200 space-y-2.5">
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="flex items-center gap-1.5">
|
||||
<Palette className="w-3.5 h-3.5 text-gray-700" />
|
||||
<label className="text-xs font-bold text-gray-800">Farba pozadia produktov</label>
|
||||
</div>
|
||||
<span className="text-[10px] font-mono font-bold px-1.5 py-0.5 bg-white border border-gray-200 rounded text-gray-700 uppercase">
|
||||
{module.data.cardBgColor || '#feeaea'}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
{/* Rýchle predvoľby */}
|
||||
<div className="grid grid-cols-3 gap-1.5">
|
||||
{PRODUCT_BG_PRESETS.map((preset) => {
|
||||
const currentBg = (module.data.cardBgColor || '#feeaea').toLowerCase();
|
||||
const isSelected = currentBg === preset.color.toLowerCase();
|
||||
return (
|
||||
<button
|
||||
key={preset.color}
|
||||
type="button"
|
||||
onClick={() => {
|
||||
const newColor = preset.color;
|
||||
const newBorder = preset.border;
|
||||
const updatedProducts = (module.data.products || []).map((p: ProductItem) => ({
|
||||
...p,
|
||||
cardBgColor: newColor,
|
||||
}));
|
||||
updateData({
|
||||
cardBgColor: newColor,
|
||||
cardBorderColor: newBorder,
|
||||
products: updatedProducts,
|
||||
});
|
||||
}}
|
||||
className={`flex items-center gap-1.5 px-2 py-1.5 rounded-lg border text-[11px] font-medium transition-all text-left ${
|
||||
isSelected
|
||||
? 'border-red-600 bg-white shadow-xs ring-1 ring-red-500 font-bold'
|
||||
: 'border-gray-200 bg-white hover:border-gray-300 text-gray-700'
|
||||
}`}
|
||||
>
|
||||
<span
|
||||
className="w-3.5 h-3.5 rounded-full border border-black/15 shrink-0 flex items-center justify-center"
|
||||
style={{ backgroundColor: preset.color }}
|
||||
>
|
||||
{isSelected && <Check className="w-2.5 h-2.5 text-gray-800" />}
|
||||
</span>
|
||||
<span className="truncate">{preset.label}</span>
|
||||
</button>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
|
||||
{/* Vlastná farba (Color Picker + HEX input) */}
|
||||
<div className="flex items-center gap-2 pt-2 border-t border-gray-200">
|
||||
<span className="text-[10px] text-gray-500 font-semibold shrink-0">Vlastná:</span>
|
||||
<div className="flex items-center gap-1.5 flex-1">
|
||||
<input
|
||||
type="color"
|
||||
value={module.data.cardBgColor || '#feeaea'}
|
||||
onChange={(e) => {
|
||||
const newColor = e.target.value;
|
||||
const updatedProducts = (module.data.products || []).map((p: ProductItem) => ({
|
||||
...p,
|
||||
cardBgColor: newColor,
|
||||
}));
|
||||
updateData({
|
||||
cardBgColor: newColor,
|
||||
products: updatedProducts,
|
||||
});
|
||||
}}
|
||||
className="w-7 h-7 rounded border border-gray-300 cursor-pointer p-0.5 bg-white shrink-0"
|
||||
/>
|
||||
<input
|
||||
type="text"
|
||||
value={module.data.cardBgColor || '#feeaea'}
|
||||
onChange={(e) => {
|
||||
const newColor = e.target.value;
|
||||
const updatedProducts = (module.data.products || []).map((p: ProductItem) => ({
|
||||
...p,
|
||||
cardBgColor: newColor,
|
||||
}));
|
||||
updateData({
|
||||
cardBgColor: newColor,
|
||||
products: updatedProducts,
|
||||
});
|
||||
}}
|
||||
placeholder="#feeaea"
|
||||
className="w-full text-xs font-mono border border-gray-300 rounded px-2 py-1 bg-white uppercase text-gray-800 font-bold"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Zoznam produktov */}
|
||||
<div className="space-y-4 pt-2">
|
||||
<div className="flex items-center justify-between">
|
||||
@@ -324,7 +435,7 @@ export const ConfigPanel: React.FC<ConfigPanelProps> = ({
|
||||
unitPrice: '1kg = 4,99 €',
|
||||
discountText: '20%',
|
||||
badgeText: 'zľava',
|
||||
cardBgColor: '#feeaea',
|
||||
cardBgColor: module.data.cardBgColor || '#feeaea',
|
||||
stores: { potraviny: true, supermarket: true, tempo: true }
|
||||
};
|
||||
updateData({ products: [...(module.data.products || []), newP] });
|
||||
@@ -791,6 +902,97 @@ export const ConfigPanel: React.FC<ConfigPanelProps> = ({
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Farba pozadia vernostných kariet */}
|
||||
<div className="bg-gray-50 p-3.5 rounded-xl border border-gray-200 space-y-2.5">
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="flex items-center gap-1.5">
|
||||
<Palette className="w-3.5 h-3.5 text-gray-700" />
|
||||
<label className="text-xs font-bold text-gray-800">Farba pozadia produktov</label>
|
||||
</div>
|
||||
<span className="text-[10px] font-mono font-bold px-1.5 py-0.5 bg-white border border-gray-200 rounded text-gray-700 uppercase">
|
||||
{module.data.cardBgColor || '#e6e1d9'}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
{/* Rýchle predvoľby */}
|
||||
<div className="grid grid-cols-3 gap-1.5">
|
||||
{PRODUCT_BG_PRESETS.map((preset) => {
|
||||
const currentBg = (module.data.cardBgColor || '#e6e1d9').toLowerCase();
|
||||
const isSelected = currentBg === preset.color.toLowerCase();
|
||||
return (
|
||||
<button
|
||||
key={preset.color}
|
||||
type="button"
|
||||
onClick={() => {
|
||||
const newColor = preset.color;
|
||||
const updatedProducts = (module.data.products || []).map((p: any) => ({
|
||||
...p,
|
||||
cardBgColor: newColor,
|
||||
}));
|
||||
updateData({
|
||||
cardBgColor: newColor,
|
||||
products: updatedProducts,
|
||||
});
|
||||
}}
|
||||
className={`flex items-center gap-1.5 px-2 py-1.5 rounded-lg border text-[11px] font-medium transition-all text-left ${
|
||||
isSelected
|
||||
? 'border-red-600 bg-white shadow-xs ring-1 ring-red-500 font-bold'
|
||||
: 'border-gray-200 bg-white hover:border-gray-300 text-gray-700'
|
||||
}`}
|
||||
>
|
||||
<span
|
||||
className="w-3.5 h-3.5 rounded-full border border-black/15 shrink-0 flex items-center justify-center"
|
||||
style={{ backgroundColor: preset.color }}
|
||||
>
|
||||
{isSelected && <Check className="w-2.5 h-2.5 text-gray-800" />}
|
||||
</span>
|
||||
<span className="truncate">{preset.label}</span>
|
||||
</button>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
|
||||
{/* Vlastná farba (Color Picker + HEX input) */}
|
||||
<div className="flex items-center gap-2 pt-2 border-t border-gray-200">
|
||||
<span className="text-[10px] text-gray-500 font-semibold shrink-0">Vlastná:</span>
|
||||
<div className="flex items-center gap-1.5 flex-1">
|
||||
<input
|
||||
type="color"
|
||||
value={module.data.cardBgColor || '#e6e1d9'}
|
||||
onChange={(e) => {
|
||||
const newColor = e.target.value;
|
||||
const updatedProducts = (module.data.products || []).map((p: any) => ({
|
||||
...p,
|
||||
cardBgColor: newColor,
|
||||
}));
|
||||
updateData({
|
||||
cardBgColor: newColor,
|
||||
products: updatedProducts,
|
||||
});
|
||||
}}
|
||||
className="w-7 h-7 rounded border border-gray-300 cursor-pointer p-0.5 bg-white shrink-0"
|
||||
/>
|
||||
<input
|
||||
type="text"
|
||||
value={module.data.cardBgColor || '#e6e1d9'}
|
||||
onChange={(e) => {
|
||||
const newColor = e.target.value;
|
||||
const updatedProducts = (module.data.products || []).map((p: any) => ({
|
||||
...p,
|
||||
cardBgColor: newColor,
|
||||
}));
|
||||
updateData({
|
||||
cardBgColor: newColor,
|
||||
products: updatedProducts,
|
||||
});
|
||||
}}
|
||||
placeholder="#e6e1d9"
|
||||
className="w-full text-xs font-mono border border-gray-300 rounded px-2 py-1 bg-white uppercase text-gray-800 font-bold"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 2 Vernostné produkty */}
|
||||
<div className="space-y-4 pt-2">
|
||||
<span className="text-xs font-bold text-gray-800 uppercase tracking-wider block">
|
||||
|
||||
Reference in new issue
Block a user