x
This commit is contained in:
1 parent
64bcd6388a
commit
4f8fa1ae09
8 files changed
+400
-120
No files matched your search
@@ -9,7 +9,7 @@ interface HeroFormProps {
|
||||
getLocalizedValue: (payload: any, field: string) => string;
|
||||
updateLocalizedValue: (field: string, value: string) => void;
|
||||
updatePayloadValue: (field: string, value: any) => void;
|
||||
setUploadTarget: (target: { type: 'main' | 'slide'; index?: number } | null) => void;
|
||||
setUploadTarget: (target: { type: 'main' | 'slide' | 'gallery' | 'tile' | 'seoOgImage' | 'mobileImage'; index?: number } | null) => void;
|
||||
setIsMediaModalOpen: (open: boolean) => void;
|
||||
}
|
||||
|
||||
@@ -31,12 +31,104 @@ export default function HeroForm({
|
||||
}: HeroFormProps) {
|
||||
const currentOverlayStyle = editingSection.payload?.overlayStyle || 'gradient';
|
||||
const currentOverlayOpacity = editingSection.payload?.overlayOpacity !== undefined ? editingSection.payload.overlayOpacity : 45;
|
||||
const payload = editingSection.payload || {};
|
||||
|
||||
return (
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
|
||||
{/* Hero image uploading */}
|
||||
<div className="md:col-span-2 space-y-2">
|
||||
<label className="text-[10px] uppercase font-bold tracking-widest text-slate-400">Background Image</label>
|
||||
{/* Global Dimension & Display Settings */}
|
||||
<div className="md:col-span-2 p-4 rounded-2xl bg-slate-900/60 border border-white/5 space-y-4">
|
||||
<div className="flex items-center gap-2 text-xs font-bold text-cyan-glow uppercase tracking-wider">
|
||||
<Sliders className="w-3.5 h-3.5" />
|
||||
<span>Carousel Dimension & Display Settings</span>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
<div className="space-y-1.5">
|
||||
<label className="text-[10px] uppercase font-bold tracking-widest text-slate-400">
|
||||
Desktop Aspect Ratio (Wide & Short)
|
||||
</label>
|
||||
<select
|
||||
value={payload.aspectRatio || '21/7'}
|
||||
onChange={(e) => updatePayloadValue('aspectRatio', e.target.value)}
|
||||
className="admin-input w-full text-xs"
|
||||
>
|
||||
<option value="21/6">21:6 (Ultra Wide / Extra Short ~320px)</option>
|
||||
<option value="21/7">21:7 (Wide Compact - Beautrium Style ~380px)</option>
|
||||
<option value="21/9">21:9 (Standard Cinematic Wide ~450px)</option>
|
||||
<option value="16/5">16:5 (Wide Banner)</option>
|
||||
<option value="16/6">16:6 (Compact Banner)</option>
|
||||
<option value="4/1">4:1 (Panoramic Ultra Slim)</option>
|
||||
<option value="5/1">5:1 (Ultra Slim Ribbon)</option>
|
||||
<option value="full_screen">Full Screen / Original Hero (~90vh)</option>
|
||||
</select>
|
||||
<p className="text-[9px] text-slate-500">BEAUTRIUM style uses 21:7 or 21:6 for wide banners without eating vertical screen space.</p>
|
||||
</div>
|
||||
|
||||
<div className="space-y-1.5">
|
||||
<label className="text-[10px] uppercase font-bold tracking-widest text-slate-400">
|
||||
Mobile Aspect Ratio
|
||||
</label>
|
||||
<select
|
||||
value={payload.mobileAspectRatio || '16/9'}
|
||||
onChange={(e) => updatePayloadValue('mobileAspectRatio', e.target.value)}
|
||||
className="admin-input w-full text-xs"
|
||||
>
|
||||
<option value="16/9">16:9 (Standard Mobile Widescreen)</option>
|
||||
<option value="4/3">4:3 (Taller Mobile View)</option>
|
||||
<option value="1/1">1:1 (Square Mobile Banner)</option>
|
||||
<option value="21/9">21:9 (Compact Mobile Strip)</option>
|
||||
<option value="full_screen">Full Screen Mobile (~85vh)</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div className="space-y-1.5 md:col-span-2">
|
||||
<label className="text-[10px] uppercase font-bold tracking-widest text-slate-400">
|
||||
Header Spacing (ตำแหน่งเทียบกับ Header Menu เมื่ออยู่บล็อกแรก)
|
||||
</label>
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 gap-3">
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => updatePayloadValue('headerSpacing', 'below_header')}
|
||||
className={`p-3 rounded-xl border text-left transition cursor-pointer flex flex-col gap-1 ${
|
||||
(payload.headerSpacing || 'below_header') === 'below_header'
|
||||
? 'border-cyan-glow bg-cyan-glow/10 text-white'
|
||||
: 'border-white/10 bg-white/5 text-slate-400 hover:border-white/20'
|
||||
}`}
|
||||
>
|
||||
<div className="flex items-center justify-between">
|
||||
<span className="text-xs font-bold text-white">ต่อจาก Header Menu (แนะนำ)</span>
|
||||
{(payload.headerSpacing || 'below_header') === 'below_header' && (
|
||||
<span className="text-[10px] font-bold text-cyan-glow uppercase">Selected</span>
|
||||
)}
|
||||
</div>
|
||||
<p className="text-[10px] text-slate-400">เว้นระยะด้านบนอัตโนมัติ ไม่โดน Header Menu ลอยทับแถบแบนเนอร์</p>
|
||||
</button>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => updatePayloadValue('headerSpacing', 'under_header')}
|
||||
className={`p-3 rounded-xl border text-left transition cursor-pointer flex flex-col gap-1 ${
|
||||
payload.headerSpacing === 'under_header'
|
||||
? 'border-cyan-glow bg-cyan-glow/10 text-white'
|
||||
: 'border-white/10 bg-white/5 text-slate-400 hover:border-white/20'
|
||||
}`}
|
||||
>
|
||||
<div className="flex items-center justify-between">
|
||||
<span className="text-xs font-bold text-white">อยู่ใต้ Header Menu (Overlay)</span>
|
||||
{payload.headerSpacing === 'under_header' && (
|
||||
<span className="text-[10px] font-bold text-cyan-glow uppercase">Selected</span>
|
||||
)}
|
||||
</div>
|
||||
<p className="text-[10px] text-slate-400">Header เมนูจะโปร่งแสงและลอยทับรูปภาพแบนเนอร์ส่วนบนสุด</p>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Hero Desktop Image */}
|
||||
<div className="space-y-2">
|
||||
<label className="text-[10px] uppercase font-bold tracking-widest text-slate-400">Background Image (Desktop)</label>
|
||||
<div
|
||||
className="relative h-40 w-full rounded-2xl overflow-hidden border-2 border-dashed border-white/10 bg-night-950/50 flex flex-col items-center justify-center group cursor-pointer hover:border-cyan-glow/30 transition-all"
|
||||
onClick={() => {
|
||||
@@ -60,6 +152,51 @@ export default function HeroForm({
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Hero Mobile Image (Optional) */}
|
||||
<div className="space-y-2">
|
||||
<div className="flex items-center justify-between">
|
||||
<label className="text-[10px] uppercase font-bold tracking-widest text-slate-400">
|
||||
Mobile Image (จอมือถือ - เว้นว่างได้)
|
||||
</label>
|
||||
{editingSection.payload?.mobileImageUrl && (
|
||||
<button
|
||||
type="button"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
updatePayloadValue('mobileImageUrl', '');
|
||||
}}
|
||||
className="text-[10px] text-rose-400 hover:text-rose-300 transition cursor-pointer"
|
||||
>
|
||||
ลบรูปโมบาย
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
<div
|
||||
className="relative h-40 w-full rounded-2xl overflow-hidden border-2 border-dashed border-white/10 bg-night-950/50 flex flex-col items-center justify-center group cursor-pointer hover:border-cyan-glow/30 transition-all"
|
||||
onClick={() => {
|
||||
setUploadTarget({ type: 'mobileImage' });
|
||||
setIsMediaModalOpen(true);
|
||||
}}
|
||||
>
|
||||
{editingSection.payload?.mobileImageUrl ? (
|
||||
<>
|
||||
<img src={editingSection.payload.mobileImageUrl} className="w-full h-full object-cover" alt="Hero Mobile Background" />
|
||||
<div className="absolute inset-0 bg-night-950/40 opacity-0 group-hover:opacity-100 transition-opacity flex items-center justify-center backdrop-blur-sm">
|
||||
<UploadCloud className="w-10 h-10 text-white" />
|
||||
</div>
|
||||
</>
|
||||
) : (
|
||||
<div className="text-center space-y-2">
|
||||
<ImageIcon className="w-10 h-10 text-slate-700 mx-auto" />
|
||||
<p className="text-xs text-slate-500 font-bold uppercase tracking-widest">
|
||||
{editingSection.payload?.imageUrl ? 'ใช้รูปเดียวกับ Desktop' : 'Select Mobile Image'}
|
||||
</p>
|
||||
<p className="text-[9px] text-slate-500">แนะนำสำหรับสัดส่วน 1:1 หรือ 4:3 บนมือถือ</p>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{editingSection.payload?.imageUrl && (
|
||||
<div className="md:col-span-2">
|
||||
<FocalPointPicker
|
||||
|
||||
@@ -147,7 +147,7 @@ export default function PageBuilderPage() {
|
||||
const [brands, setBrands] = useState<Brand[]>([]);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [editingSection, setEditingSection] = useState<Partial<PageSection> | null>(null);
|
||||
const [uploadTarget, setUploadTarget] = useState<{ type: 'main' | 'slide' | 'gallery' | 'tile' | 'seoOgImage'; index?: number } | null>(null);
|
||||
const [uploadTarget, setUploadTarget] = useState<{ type: 'main' | 'slide' | 'gallery' | 'tile' | 'seoOgImage' | 'mobileImage'; index?: number } | null>(null);
|
||||
const [saveStatus, setSaveStatus] = useState<'idle' | 'saving' | 'saved' | 'error'>('idle');
|
||||
const [isSavingPageSettings, setIsSavingPageSettings] = useState(false);
|
||||
const [isCopied, setIsCopied] = useState(false);
|
||||
@@ -160,6 +160,11 @@ export default function PageBuilderPage() {
|
||||
const handleMediaSelect = (url: string) => {
|
||||
if (uploadTarget?.type === 'seoOgImage') {
|
||||
setPage(prev => (prev ? { ...prev, ogImageUrl: url } : prev));
|
||||
} else if (uploadTarget?.type === 'mobileImage') {
|
||||
setEditingSection(prev => {
|
||||
if (!prev) return null;
|
||||
return { ...prev, payload: { ...(prev.payload || {}), mobileImageUrl: url } };
|
||||
});
|
||||
} else if (uploadTarget?.type === 'tile' && typeof uploadTarget.index === 'number') {
|
||||
const idx = uploadTarget.index;
|
||||
setEditingSection(prev => {
|
||||
@@ -733,7 +738,10 @@ export default function PageBuilderPage() {
|
||||
description: 'Transform your room into a peaceful escape.',
|
||||
imageUrl: '/images/hero.png',
|
||||
buttonText: 'Explore',
|
||||
buttonLink: '/shop'
|
||||
buttonLink: '/shop',
|
||||
aspectRatio: '21/7',
|
||||
mobileAspectRatio: '16/9',
|
||||
headerSpacing: 'below_header'
|
||||
};
|
||||
break;
|
||||
case 'HERO_CAROUSEL':
|
||||
|
||||
@@ -95,8 +95,8 @@ const PAGE_BLOCK_METADATA: Record<string, BlockMetadata> = {
|
||||
HERO: {
|
||||
type: "HERO",
|
||||
requiredFields: ["tagline", "title", "description", "imageUrl", "buttonText", "buttonLink"],
|
||||
optionalFields: ["focalPoint", "contentWidth", "textColorScheme", "buttonPosition", "mobileButtonPosition", "overlayStyle", "overlayOpacity", "titleSize"],
|
||||
renderedFields: ["tagline", "title", "description", "imageUrl", "buttonText", "buttonLink", "focalPoint", "contentWidth", "textColorScheme", "buttonPosition", "mobileButtonPosition", "overlayStyle", "overlayOpacity", "titleSize"],
|
||||
optionalFields: ["focalPoint", "contentWidth", "textColorScheme", "buttonPosition", "mobileButtonPosition", "overlayStyle", "overlayOpacity", "titleSize", "aspectRatio", "mobileAspectRatio", "headerSpacing", "mobileImageUrl"],
|
||||
renderedFields: ["tagline", "title", "description", "imageUrl", "buttonText", "buttonLink", "focalPoint", "contentWidth", "textColorScheme", "buttonPosition", "mobileButtonPosition", "overlayStyle", "overlayOpacity", "titleSize", "aspectRatio", "mobileAspectRatio", "headerSpacing", "mobileImageUrl"],
|
||||
storedOnlyFields: [],
|
||||
discoveryToolsNeeded: [],
|
||||
warnings: ["Replace sample image URLs with this tenant's approved media URLs before writing. The website must allow the media host."],
|
||||
|
||||
@@ -258,23 +258,71 @@ export default function DynamicHero({ payload }: DynamicHeroProps) {
|
||||
const titleSizeClass = getHeroTitleSizeClass(titleSize);
|
||||
const textWrapperWidthClass = titleSize === 'sm' || contentWidth === 'compact' ? 'max-w-xl' : titleSize === 'md' ? 'max-w-2xl' : 'max-w-3xl';
|
||||
|
||||
const aspectRatio = (payload as any).aspectRatio;
|
||||
const mobileAspectRatio = (payload as any).mobileAspectRatio;
|
||||
const mobileImageUrl = (payload as any).mobileImageUrl;
|
||||
const isFullScreen = !aspectRatio || aspectRatio === 'full_screen';
|
||||
|
||||
const getAspectClass = () => {
|
||||
switch (aspectRatio) {
|
||||
case '21/6': return 'md:aspect-[21/6]';
|
||||
case '21/7': return 'md:aspect-[21/7]';
|
||||
case '21/9': return 'md:aspect-[21/9]';
|
||||
case '16/5': return 'md:aspect-[16/5]';
|
||||
case '16/6': return 'md:aspect-[16/6]';
|
||||
case '4/1': return 'md:aspect-[4/1]';
|
||||
case '5/1': return 'md:aspect-[5/1]';
|
||||
case 'full_screen': return 'md:h-[90vh] md:aspect-[21/9]';
|
||||
default: return 'md:aspect-[21/7]';
|
||||
}
|
||||
};
|
||||
|
||||
const getMobileAspectClass = () => {
|
||||
switch (mobileAspectRatio) {
|
||||
case '16/9': return 'aspect-[16/9]';
|
||||
case '4/3': return 'aspect-[4/3]';
|
||||
case '1/1': return 'aspect-[1/1]';
|
||||
case '21/9': return 'aspect-[21/9]';
|
||||
case 'full_screen': return 'min-h-[85vh]';
|
||||
default: return 'aspect-[16/9]';
|
||||
}
|
||||
};
|
||||
|
||||
const sectionHeightClass = isFullScreen
|
||||
? 'min-h-[85vh] sm:min-h-[90vh] md:h-[90vh] md:aspect-[21/9]'
|
||||
: `${getMobileAspectClass()} ${getAspectClass()}`;
|
||||
const innerHeightClass = isFullScreen
|
||||
? 'min-h-[85vh] sm:min-h-[90vh] md:min-h-full'
|
||||
: 'h-full justify-center';
|
||||
|
||||
return (
|
||||
<section className={`relative w-full min-h-[85vh] sm:min-h-[90vh] md:h-[90vh] md:aspect-[21/9] flex overflow-hidden ${isDarkText ? 'bg-surface-page' : 'bg-night-950'}`}>
|
||||
<section className={`relative w-full ${sectionHeightClass} flex overflow-hidden ${isDarkText ? 'bg-surface-page' : 'bg-night-950'}`}>
|
||||
<div className="absolute inset-0 w-full h-full z-0">
|
||||
<img
|
||||
src={imageUrl || `${import.meta.env.VITE_API_URL.replace('/api', '')}/assets/hero.png`}
|
||||
className="w-full h-full object-cover"
|
||||
className={`w-full h-full object-cover ${mobileImageUrl ? 'hidden md:block' : ''}`}
|
||||
alt="Hero Background"
|
||||
style={{ objectPosition: focalPoint ? `${focalPoint.x} ${focalPoint.y}` : undefined }}
|
||||
onError={(e) => {
|
||||
(e.target as HTMLImageElement).style.display = 'none';
|
||||
}}
|
||||
/>
|
||||
{mobileImageUrl && (
|
||||
<img
|
||||
src={mobileImageUrl}
|
||||
className="w-full h-full object-cover block md:hidden"
|
||||
alt="Hero Background Mobile"
|
||||
style={{ objectPosition: focalPoint ? `${focalPoint.x} ${focalPoint.y}` : undefined }}
|
||||
onError={(e) => {
|
||||
(e.target as HTMLImageElement).style.display = 'none';
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
{/* Dynamic Dark / Light Gradient / Solid Overlay */}
|
||||
{renderOverlay()}
|
||||
</div>
|
||||
|
||||
<div className={`relative z-10 min-h-[85vh] sm:min-h-[90vh] md:min-h-full flex flex-col ${containerClasses} ${wrapperClasses} animate-fade-in`}>
|
||||
<div className={`relative z-10 ${innerHeightClass} flex flex-col ${containerClasses} ${wrapperClasses} animate-fade-in`}>
|
||||
<div className={`w-full ${textWrapperWidthClass} flex flex-col space-y-5 ${contentClasses}`}>
|
||||
{tagline && (
|
||||
<p className={`${isDarkText ? 'text-pop-pink' : 'text-pop-yellow'} font-semibold tracking-[0.3em] text-xs md:text-sm uppercase drop-shadow-md`}>
|
||||
|
||||
@@ -21,6 +21,7 @@ function aspectClasses(
|
||||
'4/3': 'aspect-[4/3]',
|
||||
'1/1': 'aspect-square',
|
||||
'21/9': 'aspect-[21/9]',
|
||||
full_screen: 'min-h-[85vh]',
|
||||
auto: 'min-h-[22rem]',
|
||||
}[mobile ?? '16/9']
|
||||
|
||||
@@ -32,6 +33,7 @@ function aspectClasses(
|
||||
'16/6': 'md:aspect-[16/6]',
|
||||
'4/1': 'md:aspect-[4/1]',
|
||||
'5/1': 'md:aspect-[5/1]',
|
||||
full_screen: 'md:aspect-auto md:min-h-[90vh]',
|
||||
auto: 'md:aspect-auto md:min-h-[30rem]',
|
||||
}[desktop ?? '21/7']
|
||||
|
||||
|
||||
@@ -374,21 +374,74 @@ function HeroSection({ payload, lang }: { payload: Record<string, unknown>, lang
|
||||
)
|
||||
}
|
||||
|
||||
const aspectRatio = typeof payload.aspectRatio === 'string' ? payload.aspectRatio : undefined
|
||||
const mobileAspectRatio = typeof payload.mobileAspectRatio === 'string' ? payload.mobileAspectRatio : undefined
|
||||
const mobileImageUrl = typeof payload.mobileImageUrl === 'string' && payload.mobileImageUrl ? payload.mobileImageUrl : imageUrl
|
||||
const isFullScreen = !aspectRatio || aspectRatio === 'full_screen'
|
||||
|
||||
const getAspectClass = () => {
|
||||
switch (aspectRatio) {
|
||||
case '21/6': return 'md:aspect-[21/6]'
|
||||
case '21/7': return 'md:aspect-[21/7]'
|
||||
case '21/9': return 'md:aspect-[21/9]'
|
||||
case '16/5': return 'md:aspect-[16/5]'
|
||||
case '16/6': return 'md:aspect-[16/6]'
|
||||
case '4/1': return 'md:aspect-[4/1]'
|
||||
case '5/1': return 'md:aspect-[5/1]'
|
||||
case 'full_screen': return 'md:h-[90vh] md:aspect-[21/9]'
|
||||
default: return 'md:aspect-[21/7]'
|
||||
}
|
||||
}
|
||||
|
||||
const getMobileAspectClass = () => {
|
||||
switch (mobileAspectRatio) {
|
||||
case '16/9': return 'aspect-[16/9]'
|
||||
case '4/3': return 'aspect-[4/3]'
|
||||
case '1/1': return 'aspect-[1/1]'
|
||||
case '21/9': return 'aspect-[21/9]'
|
||||
case 'full_screen': return 'min-h-[85vh]'
|
||||
default: return 'aspect-[16/9]'
|
||||
}
|
||||
}
|
||||
|
||||
const sectionHeightClass = isFullScreen
|
||||
? 'min-h-[85vh] sm:min-h-[90vh] md:h-[90vh] md:aspect-[21/9]'
|
||||
: `${getMobileAspectClass()} ${getAspectClass()}`
|
||||
const innerHeightClass = isFullScreen
|
||||
? 'min-h-[85vh] sm:min-h-[90vh] md:min-h-full'
|
||||
: 'h-full justify-center'
|
||||
|
||||
return (
|
||||
<section className={`relative w-full min-h-[85vh] sm:min-h-[90vh] md:h-[90vh] md:aspect-[21/9] flex overflow-hidden ${isDarkText ? 'bg-surface-page' : 'bg-night-950'}`}>
|
||||
<section className={`relative w-full ${sectionHeightClass} flex overflow-hidden ${isDarkText ? 'bg-surface-page' : 'bg-night-950'}`}>
|
||||
<div className="absolute inset-0 w-full h-full z-0">
|
||||
<Image
|
||||
src={imageUrl}
|
||||
alt={title || ''}
|
||||
fill
|
||||
unoptimized
|
||||
className="object-cover md:scale-[1.02]"
|
||||
style={{ objectPosition: focalPoint ? `${focalPoint.x} ${focalPoint.y}` : undefined }}
|
||||
/>
|
||||
{/* Desktop Image */}
|
||||
<div className={`w-full h-full ${mobileImageUrl !== imageUrl ? 'hidden md:block' : ''}`}>
|
||||
<Image
|
||||
src={imageUrl}
|
||||
alt={title || ''}
|
||||
fill
|
||||
unoptimized
|
||||
className="object-cover md:scale-[1.02]"
|
||||
style={{ objectPosition: focalPoint ? `${focalPoint.x} ${focalPoint.y}` : undefined }}
|
||||
/>
|
||||
</div>
|
||||
{/* Mobile Image (if provided) */}
|
||||
{mobileImageUrl !== imageUrl && (
|
||||
<div className="block md:hidden w-full h-full relative">
|
||||
<Image
|
||||
src={mobileImageUrl}
|
||||
alt={title || ''}
|
||||
fill
|
||||
unoptimized
|
||||
className="object-cover"
|
||||
style={{ objectPosition: focalPoint ? `${focalPoint.x} ${focalPoint.y}` : undefined }}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
{/* Dynamic Dark / Light Gradient / Solid Overlay */}
|
||||
{renderOverlay()}
|
||||
</div>
|
||||
<div className={`relative z-10 min-h-[85vh] sm:min-h-[90vh] md:min-h-full flex flex-col ${containerClasses} ${wrapperClasses}`}>
|
||||
<div className={`relative z-10 ${innerHeightClass} flex flex-col ${containerClasses} ${wrapperClasses}`}>
|
||||
<div className={`w-full ${textWrapperWidthClass} flex flex-col space-y-5 ${contentClasses}`}>
|
||||
{tagline && (
|
||||
<p className={`text-xs font-semibold uppercase tracking-[0.3em] drop-shadow-md md:text-sm ${isDarkText ? 'text-brand-primary' : 'text-brand-accent'}`}>
|
||||
|
||||
@@ -694,6 +694,7 @@ export const HeroSectionPayloadSchema = z.object({
|
||||
title: LocalizedStringSchema.optional(),
|
||||
description: LocalizedStringSchema.optional(),
|
||||
imageUrl: z.string().min(1),
|
||||
mobileImageUrl: z.string().optional(),
|
||||
buttonText: LocalizedStringSchema.optional(),
|
||||
buttonLink: z.string().optional(),
|
||||
focalPoint: z.object({ x: z.string(), y: z.string() }).optional(),
|
||||
@@ -704,6 +705,9 @@ export const HeroSectionPayloadSchema = z.object({
|
||||
titleSize: DefaultTitleSizeSchema('xl'),
|
||||
overlayStyle: z.enum(['gradient', 'solid', 'none']).optional().default('gradient'),
|
||||
overlayOpacity: z.number().min(0).max(100).optional(),
|
||||
aspectRatio: z.enum(['21/6', '21/7', '21/9', '16/5', '16/6', '4/1', '5/1', 'auto', 'full_screen']).optional().default('21/7'),
|
||||
mobileAspectRatio: z.enum(['16/9', '4/3', '1/1', '21/9', 'auto', 'full_screen']).optional().default('16/9'),
|
||||
headerSpacing: z.enum(['below_header', 'under_header']).optional(),
|
||||
});
|
||||
export type HeroSectionPayload = z.infer<typeof HeroSectionPayloadSchema>;
|
||||
|
||||
@@ -874,11 +878,12 @@ export const HeroCarouselSectionPayloadSchema = z.object({
|
||||
slides: z.array(HeroCarouselSlideSchema).min(1),
|
||||
autoplay: z.boolean().optional().default(true),
|
||||
interval: z.number().optional().default(4500),
|
||||
aspectRatio: z.enum(['21/6', '21/7', '21/9', '16/5', '16/6', '4/1', '5/1', 'auto']).optional().default('21/7'),
|
||||
mobileAspectRatio: z.enum(['16/9', '4/3', '1/1', '21/9', 'auto']).optional().default('16/9'),
|
||||
aspectRatio: z.enum(['21/6', '21/7', '21/9', '16/5', '16/6', '4/1', '5/1', 'auto', 'full_screen']).optional().default('21/7'),
|
||||
mobileAspectRatio: z.enum(['16/9', '4/3', '1/1', '21/9', 'auto', 'full_screen']).optional().default('16/9'),
|
||||
showArrows: z.boolean().optional().default(true),
|
||||
showDots: z.boolean().optional().default(true),
|
||||
backgroundColor: z.string().optional(),
|
||||
headerSpacing: z.enum(['below_header', 'under_header']).optional(),
|
||||
});
|
||||
export type HeroCarouselSectionPayload = z.infer<typeof HeroCarouselSectionPayloadSchema>;
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
[
|
||||
{
|
||||
"name": "TOBAKI DRIVE CHAIN",
|
||||
"categoryName": "TOBAKI",
|
||||
"categoryName": "Drive Chain & Sprockets",
|
||||
"brandName": "TOBAKI",
|
||||
"options": [
|
||||
{
|
||||
@@ -84,7 +84,7 @@
|
||||
},
|
||||
{
|
||||
"name": "TOBAKI X CVT SYSTEM PULLEY SPRING RACING",
|
||||
"categoryName": "TOBAKI RACING",
|
||||
"categoryName": "Transmission & Clutch",
|
||||
"brandName": "TOBAKI",
|
||||
"options": [
|
||||
{
|
||||
@@ -186,7 +186,7 @@
|
||||
},
|
||||
{
|
||||
"name": "TOBAKI ECU(STD) | MODEL HONDA",
|
||||
"categoryName": "TOBAKI",
|
||||
"categoryName": "Electrical & Ignition",
|
||||
"brandName": "TOBAKI",
|
||||
"options": [
|
||||
{
|
||||
@@ -290,7 +290,7 @@
|
||||
},
|
||||
{
|
||||
"name": "TOBAKI RACING CRANKSHAFT NVX155 NMAX155",
|
||||
"categoryName": "TOBAKI RACING",
|
||||
"categoryName": "Engine & Cylinder",
|
||||
"brandName": "TOBAKI RACING",
|
||||
"options": [
|
||||
{
|
||||
@@ -338,7 +338,7 @@
|
||||
},
|
||||
{
|
||||
"name": "TOBAKI X CVT SYSTEM CERAMIC PULLEY PIN RACING",
|
||||
"categoryName": "TOBAKI RACING",
|
||||
"categoryName": "Transmission & Clutch",
|
||||
"brandName": "TOBAKI",
|
||||
"options": [
|
||||
{
|
||||
@@ -476,7 +476,7 @@
|
||||
},
|
||||
{
|
||||
"name": "TOBAKI X SUPER CLUTCH PLATE(IRON)",
|
||||
"categoryName": "TOBAKI",
|
||||
"categoryName": "Transmission & Clutch",
|
||||
"brandName": "TOBAKI",
|
||||
"options": [
|
||||
{
|
||||
@@ -531,7 +531,7 @@
|
||||
},
|
||||
{
|
||||
"name": "TOBAKI X CVT ROLLER",
|
||||
"categoryName": "TOBAKI",
|
||||
"categoryName": "Transmission & Clutch",
|
||||
"brandName": "TOBAKI",
|
||||
"options": [
|
||||
{
|
||||
@@ -1719,7 +1719,7 @@
|
||||
},
|
||||
{
|
||||
"name": "TOBAKI X WATER PUMP IMPELLER SHAFT ASSY",
|
||||
"categoryName": "TOBAKI",
|
||||
"categoryName": "Cooling System",
|
||||
"brandName": "TOBAKI RACING",
|
||||
"options": [
|
||||
{
|
||||
@@ -1759,7 +1759,7 @@
|
||||
},
|
||||
{
|
||||
"name": "TOBAKI FUEL COCK",
|
||||
"categoryName": "TOBAKI",
|
||||
"categoryName": "Fuel & Air Intake",
|
||||
"brandName": "TOBAKI",
|
||||
"options": [
|
||||
{
|
||||
@@ -1932,7 +1932,7 @@
|
||||
},
|
||||
{
|
||||
"name": "TOBAKI x RIKEN PISTON RING SET (2)",
|
||||
"categoryName": "TOBAKI",
|
||||
"categoryName": "Engine & Cylinder",
|
||||
"brandName": "TOBAKI",
|
||||
"options": [
|
||||
{
|
||||
@@ -2011,7 +2011,7 @@
|
||||
},
|
||||
{
|
||||
"name": "TOBAKI CAMSHAFT STD CHILLED CAST IRON",
|
||||
"categoryName": "TOBAKI",
|
||||
"categoryName": "Engine & Cylinder",
|
||||
"brandName": "TOBAKI",
|
||||
"options": [
|
||||
{
|
||||
@@ -2280,7 +2280,7 @@
|
||||
},
|
||||
{
|
||||
"name": "TOBAKI X PREMIUM DRIVE CHAIN(H) GOLD",
|
||||
"categoryName": "TOBAKI",
|
||||
"categoryName": "Drive Chain & Sprockets",
|
||||
"brandName": "TOBAKI",
|
||||
"options": [
|
||||
{
|
||||
@@ -2370,7 +2370,7 @@
|
||||
},
|
||||
{
|
||||
"name": "TOBAKI DRUM GEARSHIFT TRANSMISSION ASSY(FULL SET)",
|
||||
"categoryName": "TOBAKI",
|
||||
"categoryName": "Transmission & Clutch",
|
||||
"brandName": "TOBAKI",
|
||||
"options": [
|
||||
{
|
||||
@@ -2444,7 +2444,7 @@
|
||||
},
|
||||
{
|
||||
"name": "TOBAKI X FORK SPRING",
|
||||
"categoryName": "TOBAKI",
|
||||
"categoryName": "Suspension & Chassis",
|
||||
"brandName": "TOBAKI",
|
||||
"options": [
|
||||
{
|
||||
@@ -2624,7 +2624,7 @@
|
||||
},
|
||||
{
|
||||
"name": "TOBAKI X Fork Lay Pro Spring",
|
||||
"categoryName": "TOBAKI",
|
||||
"categoryName": "Suspension & Chassis",
|
||||
"brandName": "TOBAKI RACING",
|
||||
"options": [
|
||||
{
|
||||
@@ -2684,7 +2684,7 @@
|
||||
},
|
||||
{
|
||||
"name": "TOBAKI STATOR COMP",
|
||||
"categoryName": "TOBAKI",
|
||||
"categoryName": "Electrical & Ignition",
|
||||
"brandName": "TOBAKI",
|
||||
"options": [
|
||||
{
|
||||
@@ -2823,7 +2823,7 @@
|
||||
},
|
||||
{
|
||||
"name": "TOBAKI DIGITAL METER",
|
||||
"categoryName": "TOBAKI",
|
||||
"categoryName": "Electrical & Ignition",
|
||||
"brandName": "TOBAKI",
|
||||
"options": [
|
||||
{
|
||||
@@ -2878,7 +2878,7 @@
|
||||
},
|
||||
{
|
||||
"name": "TOBAKI | CABLE THROTTLE",
|
||||
"categoryName": "TOBAKI",
|
||||
"categoryName": "Fuel & Air Intake",
|
||||
"brandName": "TOBAKI",
|
||||
"options": [
|
||||
{
|
||||
@@ -3268,7 +3268,7 @@
|
||||
},
|
||||
{
|
||||
"name": "TOBAKI FUEL PUMP SENSOR",
|
||||
"categoryName": "TOBAKI",
|
||||
"categoryName": "Fuel & Air Intake",
|
||||
"brandName": "TOBAKI",
|
||||
"price": 10.7,
|
||||
"stock": 50,
|
||||
@@ -3291,11 +3291,20 @@
|
||||
"description": "Y15ZR/FZ150 NEW/NVX155/EGO LC/EGO AVANTIZ/EGO'S FI/NMAX",
|
||||
"details": "AVAILABLE MODEL:\nY15ZR/FZ150 NEW/NVX155/EGO LC/EGO AVANTIZ/EGO'S FI/NMAX"
|
||||
}
|
||||
}
|
||||
},
|
||||
"options": [],
|
||||
"variants": [
|
||||
{
|
||||
"option1": "",
|
||||
"price": 10.7,
|
||||
"stock": 50,
|
||||
"sku": "TBK-TSY01-589901234-01"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "TOBAKI KEVLAR DRIVE BELT WITH CVT ROLLER SET",
|
||||
"categoryName": "TOBAKI",
|
||||
"categoryName": "Transmission & Clutch",
|
||||
"brandName": "TOBAKI",
|
||||
"options": [
|
||||
{
|
||||
@@ -3469,7 +3478,7 @@
|
||||
},
|
||||
{
|
||||
"name": "TOBAKI RACING ECU(NO CUT)",
|
||||
"categoryName": "TOBAKI RACING",
|
||||
"categoryName": "Electrical & Ignition",
|
||||
"brandName": "TOBAKI",
|
||||
"options": [
|
||||
{
|
||||
@@ -3570,7 +3579,7 @@
|
||||
},
|
||||
{
|
||||
"name": "TOBAKI X THERMO SENSOR RACING",
|
||||
"categoryName": "TOBAKI RACING",
|
||||
"categoryName": "Electrical & Ignition",
|
||||
"brandName": "TOBAKI RACING",
|
||||
"options": [
|
||||
{
|
||||
@@ -3618,7 +3627,7 @@
|
||||
},
|
||||
{
|
||||
"name": "TEAMTOBAKI T01 POLO TEE",
|
||||
"categoryName": "#TEAMTOBAKI MERCHANDISE",
|
||||
"categoryName": "Apparel & Merchandise",
|
||||
"brandName": "TOBAKI",
|
||||
"options": [
|
||||
{
|
||||
@@ -3693,7 +3702,7 @@
|
||||
},
|
||||
{
|
||||
"name": "TOBAKI TIMING CHAIN RACING- EX5 DREAM | EX5 CLASS",
|
||||
"categoryName": "TOBAKI RACING",
|
||||
"categoryName": "Engine & Cylinder",
|
||||
"brandName": "TOBAKI RACING",
|
||||
"options": [
|
||||
{
|
||||
@@ -3738,7 +3747,7 @@
|
||||
},
|
||||
{
|
||||
"name": "TEAMTOBAKI T01 ROUND NECK TEE",
|
||||
"categoryName": "#TEAMTOBAKI MERCHANDISE",
|
||||
"categoryName": "Apparel & Merchandise",
|
||||
"brandName": "TOBAKI",
|
||||
"options": [
|
||||
{
|
||||
@@ -3813,7 +3822,7 @@
|
||||
},
|
||||
{
|
||||
"name": "TOBAKI X KEVLAR CLUTCH DISC",
|
||||
"categoryName": "TOBAKI RACING",
|
||||
"categoryName": "Transmission & Clutch",
|
||||
"brandName": "TOBAKI",
|
||||
"options": [
|
||||
{
|
||||
@@ -4045,7 +4054,7 @@
|
||||
},
|
||||
{
|
||||
"name": "TOBAKI AUTO SHOE",
|
||||
"categoryName": "TOBAKI",
|
||||
"categoryName": "Transmission & Clutch",
|
||||
"brandName": "TOBAKI",
|
||||
"options": [
|
||||
{
|
||||
@@ -4198,7 +4207,7 @@
|
||||
},
|
||||
{
|
||||
"name": "TOBAKI X PLUG COIL NON-FUEL INJECTION UNIVERSAL",
|
||||
"categoryName": "TOBAKI RACING",
|
||||
"categoryName": "Electrical & Ignition",
|
||||
"brandName": "TOBAKI",
|
||||
"price": 12.7,
|
||||
"stock": 50,
|
||||
@@ -4221,11 +4230,20 @@
|
||||
"description": "TOBAKI® X PLUG COIL UNIVERSAL ⚡️",
|
||||
"details": "TOBAKI® X PLUG COIL UNIVERSAL ⚡️\n NON FUEL INJECTION (CARBURETOR)\n High Voltage To Increase Power\n Used Of Premium Grade Copper Wire\n Used Of Highly Efficient Conductor\n Suitable For All Std & Racing Spec Motorcycle\n Plug & Play To Elevate Horse Power"
|
||||
}
|
||||
}
|
||||
},
|
||||
"options": [],
|
||||
"variants": [
|
||||
{
|
||||
"option1": "",
|
||||
"price": 12.7,
|
||||
"stock": 50,
|
||||
"sku": "TBK-TPC02-261912691-01"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "TOBAKI X CNC LAY FORK ASSY",
|
||||
"categoryName": "SHOP BY BIKE",
|
||||
"categoryName": "Suspension & Chassis",
|
||||
"brandName": "TOBAKI",
|
||||
"options": [
|
||||
{
|
||||
@@ -4369,7 +4387,7 @@
|
||||
},
|
||||
{
|
||||
"name": "TOBAKI X GAS MONOSHOCK Y16ZR/Y15ZR/LC135 (ROTATABLE 360°)(GREY TANK)",
|
||||
"categoryName": "SHOP BY BIKE",
|
||||
"categoryName": "Suspension & Chassis",
|
||||
"brandName": "TOBAKI RACING",
|
||||
"options": [
|
||||
{
|
||||
@@ -4441,7 +4459,7 @@
|
||||
},
|
||||
{
|
||||
"name": "TOBAKI RACING LC135 CERAMIC SUPERBLOCK+FORGED PISTON SUPERHEAD FULL SET",
|
||||
"categoryName": "SHOP BY BIKE",
|
||||
"categoryName": "Engine & Cylinder",
|
||||
"brandName": "TOBAKI RACING",
|
||||
"options": [
|
||||
{
|
||||
@@ -4553,7 +4571,7 @@
|
||||
},
|
||||
{
|
||||
"name": "TOBAKI X HYPER CLUTCH",
|
||||
"categoryName": "TOBAKI RACING",
|
||||
"categoryName": "Transmission & Clutch",
|
||||
"brandName": "TOBAKI",
|
||||
"options": [
|
||||
{
|
||||
@@ -4712,7 +4730,7 @@
|
||||
},
|
||||
{
|
||||
"name": "TOBAKI AUTO CLUTCH HOUSING COMP",
|
||||
"categoryName": "TOBAKI",
|
||||
"categoryName": "Transmission & Clutch",
|
||||
"brandName": "TOBAKI",
|
||||
"options": [
|
||||
{
|
||||
@@ -4865,7 +4883,7 @@
|
||||
},
|
||||
{
|
||||
"name": "TOBAKI VALVE RACING IN & EX",
|
||||
"categoryName": "TOBAKI RACING",
|
||||
"categoryName": "Engine & Cylinder",
|
||||
"brandName": "TOBAKI RACING",
|
||||
"options": [
|
||||
{
|
||||
@@ -5178,7 +5196,7 @@
|
||||
},
|
||||
{
|
||||
"name": "TOBAKI X MONOSHOCK Y15ZR/Y16ZR | 205MM",
|
||||
"categoryName": "TOBAKI RACING",
|
||||
"categoryName": "Suspension & Chassis",
|
||||
"brandName": "TOBAKI RACING",
|
||||
"options": [
|
||||
{
|
||||
@@ -5270,7 +5288,7 @@
|
||||
},
|
||||
{
|
||||
"name": "TOBAKI RACING GEAR EX5/EX5 DREAM",
|
||||
"categoryName": "SHOP BY BIKE",
|
||||
"categoryName": "Transmission & Clutch",
|
||||
"brandName": "TOBAKI RACING",
|
||||
"options": [
|
||||
{
|
||||
@@ -5365,7 +5383,7 @@
|
||||
},
|
||||
{
|
||||
"name": "TOBAKI X AIR FILTER UNIVERSAL",
|
||||
"categoryName": "TOBAKI",
|
||||
"categoryName": "Fuel & Air Intake",
|
||||
"brandName": "TOBAKI",
|
||||
"options": [
|
||||
{
|
||||
@@ -5632,7 +5650,7 @@
|
||||
},
|
||||
{
|
||||
"name": "TOBAKI X ADJUSTABLE TENSIONER MANUAL",
|
||||
"categoryName": "SHOP BY BIKE",
|
||||
"categoryName": "Engine & Cylinder",
|
||||
"brandName": "TOBAKI RACING",
|
||||
"options": [
|
||||
{
|
||||
@@ -5778,7 +5796,7 @@
|
||||
},
|
||||
{
|
||||
"name": "TOBAKI X WATER PUMP",
|
||||
"categoryName": "TOBAKI RACING",
|
||||
"categoryName": "Cooling System",
|
||||
"brandName": "TOBAKI",
|
||||
"options": [
|
||||
{
|
||||
@@ -5843,7 +5861,7 @@
|
||||
},
|
||||
{
|
||||
"name": "TOBAKI IRON PLATE RACING",
|
||||
"categoryName": "TOBAKI RACING",
|
||||
"categoryName": "Transmission & Clutch",
|
||||
"brandName": "TOBAKI",
|
||||
"options": [
|
||||
{
|
||||
@@ -6016,7 +6034,7 @@
|
||||
},
|
||||
{
|
||||
"name": "TOBAKI X SUPERHEAD ROCKER ARM",
|
||||
"categoryName": "TOBAKI RACING",
|
||||
"categoryName": "Engine & Cylinder",
|
||||
"brandName": "TOBAKI",
|
||||
"options": [
|
||||
{
|
||||
@@ -6095,7 +6113,7 @@
|
||||
},
|
||||
{
|
||||
"name": "TOBAKI FORK ASSY",
|
||||
"categoryName": "TOBAKI",
|
||||
"categoryName": "Suspension & Chassis",
|
||||
"brandName": "TOBAKI",
|
||||
"options": [
|
||||
{
|
||||
@@ -6591,7 +6609,7 @@
|
||||
},
|
||||
{
|
||||
"name": "TOBAKI KEVLAR CLUTCH DISC",
|
||||
"categoryName": "TOBAKI RACING",
|
||||
"categoryName": "Transmission & Clutch",
|
||||
"brandName": "TOBAKI",
|
||||
"options": [
|
||||
{
|
||||
@@ -6799,7 +6817,7 @@
|
||||
},
|
||||
{
|
||||
"name": "TOBAKI RACING CERAMIC BLOCK SETS LC135 | MX135 | EXCITER135 | SPARK135 | CRYPTON X 135",
|
||||
"categoryName": "SHOP BY BIKE",
|
||||
"categoryName": "Engine & Cylinder",
|
||||
"brandName": "TOBAKI RACING",
|
||||
"options": [
|
||||
{
|
||||
@@ -6979,7 +6997,7 @@
|
||||
},
|
||||
{
|
||||
"name": "TOBAKI X TIMING BOLT",
|
||||
"categoryName": "TOBAKI",
|
||||
"categoryName": "Engine & Cylinder",
|
||||
"brandName": "TOBAKI",
|
||||
"options": [
|
||||
{
|
||||
@@ -7028,7 +7046,7 @@
|
||||
},
|
||||
{
|
||||
"name": "TOBAKI X STARTER ONE WAY CLUTCH /w GEAR",
|
||||
"categoryName": "SHOP BY BIKE",
|
||||
"categoryName": "Transmission & Clutch",
|
||||
"brandName": "TOBAKI",
|
||||
"options": [
|
||||
{
|
||||
@@ -7079,7 +7097,7 @@
|
||||
},
|
||||
{
|
||||
"name": "TOBAKI X PLUG COIL FUEL INJECTION UNIVERSAL",
|
||||
"categoryName": "TOBAKI RACING",
|
||||
"categoryName": "Electrical & Ignition",
|
||||
"brandName": "TOBAKI",
|
||||
"price": 14,
|
||||
"stock": 50,
|
||||
@@ -7102,11 +7120,20 @@
|
||||
"description": "TOBAKI® X PLUG COIL UNIVERSAL ⚡️",
|
||||
"details": "TOBAKI® X PLUG COIL UNIVERSAL ⚡️\nFUEL INJECTION \n High Voltage To Increase Power\n Used Of Premium Grade Copper Wire\n Used Of Highly Efficient Conductor\n Suitable For All Std & Racing Spec Motorcycle\n Plug & Play To Elevate Horse Power"
|
||||
}
|
||||
}
|
||||
},
|
||||
"options": [],
|
||||
"variants": [
|
||||
{
|
||||
"option1": "",
|
||||
"price": 14,
|
||||
"stock": 50,
|
||||
"sku": "TBK-TPC01-261900875-01"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "TOBAKI X GAS MONOSHOCK Y15ZR/LC135 (GREY TANK)",
|
||||
"categoryName": "TOBAKI RACING",
|
||||
"categoryName": "Suspension & Chassis",
|
||||
"brandName": "TOBAKI RACING",
|
||||
"options": [
|
||||
{
|
||||
@@ -7173,7 +7200,7 @@
|
||||
},
|
||||
{
|
||||
"name": "TOBAKI X GAS MONOSHOCK Y16ZR/Y15ZR/LC135 (ROTATABLE 360°)(GOLD TANK)",
|
||||
"categoryName": "SHOP BY BIKE",
|
||||
"categoryName": "Suspension & Chassis",
|
||||
"brandName": "TOBAKI RACING",
|
||||
"options": [
|
||||
{
|
||||
@@ -7252,7 +7279,7 @@
|
||||
},
|
||||
{
|
||||
"name": "TOBAKI X GAS MONOSHOCK RS150R (ROTATABLE 360°)(GOLD TANK)",
|
||||
"categoryName": "SHOP BY BIKE",
|
||||
"categoryName": "Suspension & Chassis",
|
||||
"brandName": "TOBAKI RACING",
|
||||
"options": [
|
||||
{
|
||||
@@ -7324,7 +7351,7 @@
|
||||
},
|
||||
{
|
||||
"name": "TOBAKI X GAS MONOSHOCK RS150R (ROTATABLE 360°)(GREY TANK)",
|
||||
"categoryName": "SHOP BY BIKE",
|
||||
"categoryName": "Suspension & Chassis",
|
||||
"brandName": "TOBAKI RACING",
|
||||
"options": [
|
||||
{
|
||||
@@ -7396,7 +7423,7 @@
|
||||
},
|
||||
{
|
||||
"name": "TOBAKI X GAS MONOSHOCK Y15ZR/LC135 (GOLD TANK)",
|
||||
"categoryName": "TOBAKI RACING",
|
||||
"categoryName": "Suspension & Chassis",
|
||||
"brandName": "TOBAKI RACING",
|
||||
"options": [
|
||||
{
|
||||
@@ -7456,7 +7483,7 @@
|
||||
},
|
||||
{
|
||||
"name": "TOBAKI X CARBURETOR WAVE125 /W INLET PIPE",
|
||||
"categoryName": "SHOP BY BIKE",
|
||||
"categoryName": "Fuel & Air Intake",
|
||||
"brandName": "TOBAKI",
|
||||
"options": [
|
||||
{
|
||||
@@ -7534,7 +7561,7 @@
|
||||
},
|
||||
{
|
||||
"name": "TOBAKI X CARBURETOR RXZ",
|
||||
"categoryName": "SHOP BY BIKE",
|
||||
"categoryName": "Fuel & Air Intake",
|
||||
"brandName": "TOBAKI",
|
||||
"options": [
|
||||
{
|
||||
@@ -7580,7 +7607,7 @@
|
||||
},
|
||||
{
|
||||
"name": "TOBAKI X CARBURETOR PWK (SQUARE)",
|
||||
"categoryName": "SHOP BY BIKE",
|
||||
"categoryName": "Fuel & Air Intake",
|
||||
"brandName": "TOBAKI",
|
||||
"options": [
|
||||
{
|
||||
@@ -7658,7 +7685,7 @@
|
||||
},
|
||||
{
|
||||
"name": "TOBAKI FUEL PUMP",
|
||||
"categoryName": "TOBAKI",
|
||||
"categoryName": "Fuel & Air Intake",
|
||||
"brandName": "TOBAKI",
|
||||
"options": [
|
||||
{
|
||||
@@ -7901,7 +7928,7 @@
|
||||
},
|
||||
{
|
||||
"name": "TOBAKI RACING TIMING CHAIN - LC135 | Y15ZR",
|
||||
"categoryName": "SHOP BY BIKE",
|
||||
"categoryName": "Engine & Cylinder",
|
||||
"brandName": "TOBAKI RACING",
|
||||
"options": [
|
||||
{
|
||||
@@ -8004,7 +8031,7 @@
|
||||
},
|
||||
{
|
||||
"name": "TOBAKI RACING CNC ADJUSTABLE UNIVERSAL THROTTLE BODY TRUMPET",
|
||||
"categoryName": "TOBAKI RACING",
|
||||
"categoryName": "Fuel & Air Intake",
|
||||
"brandName": "TOBAKI",
|
||||
"options": [
|
||||
{
|
||||
@@ -8064,7 +8091,7 @@
|
||||
},
|
||||
{
|
||||
"name": "TOBAKI X CONNECTING ROD RS150R Y16ZR R15 V3",
|
||||
"categoryName": "TOBAKI",
|
||||
"categoryName": "Engine & Cylinder",
|
||||
"brandName": "TOBAKI",
|
||||
"options": [
|
||||
{
|
||||
@@ -8113,7 +8140,7 @@
|
||||
},
|
||||
{
|
||||
"name": "TOBAKI RACING THROTTLE BODY /W INLET PIPE Y16ZR",
|
||||
"categoryName": "TOBAKI RACING",
|
||||
"categoryName": "Fuel & Air Intake",
|
||||
"brandName": "TOBAKI RACING",
|
||||
"options": [
|
||||
{
|
||||
@@ -8172,7 +8199,7 @@
|
||||
},
|
||||
{
|
||||
"name": "TOBAKI CYLINDER HEAD WITH VALVES RACING",
|
||||
"categoryName": "TOBAKI RACING",
|
||||
"categoryName": "Engine & Cylinder",
|
||||
"brandName": "TOBAKI RACING",
|
||||
"options": [
|
||||
{
|
||||
@@ -8337,7 +8364,7 @@
|
||||
},
|
||||
{
|
||||
"name": "TOBAKI X STARTER MOTOR",
|
||||
"categoryName": "TOBAKI RACING",
|
||||
"categoryName": "Electrical & Ignition",
|
||||
"brandName": "TOBAKI",
|
||||
"options": [
|
||||
{
|
||||
@@ -8390,7 +8417,7 @@
|
||||
},
|
||||
{
|
||||
"name": "TOBAKI RACING MAGNET ROTOR",
|
||||
"categoryName": "TOBAKI RACING",
|
||||
"categoryName": "Electrical & Ignition",
|
||||
"brandName": "TOBAKI RACING",
|
||||
"options": [
|
||||
{
|
||||
@@ -8429,7 +8456,7 @@
|
||||
},
|
||||
{
|
||||
"name": "TOBAKI X CDI UNIT",
|
||||
"categoryName": "TOBAKI RACING",
|
||||
"categoryName": "Electrical & Ignition",
|
||||
"brandName": "TOBAKI RACING",
|
||||
"options": [
|
||||
{
|
||||
@@ -8511,7 +8538,7 @@
|
||||
},
|
||||
{
|
||||
"name": "TOBAKI X TPS THROTTLE BODY SENSOR",
|
||||
"categoryName": "TOBAKI RACING",
|
||||
"categoryName": "Fuel & Air Intake",
|
||||
"brandName": "TOBAKI RACING",
|
||||
"options": [
|
||||
{
|
||||
@@ -8587,7 +8614,7 @@
|
||||
},
|
||||
{
|
||||
"name": "TOBAKI X ADJUSTABLE TIMING GEAR",
|
||||
"categoryName": "TOBAKI RACING",
|
||||
"categoryName": "Engine & Cylinder",
|
||||
"brandName": "TOBAKI RACING",
|
||||
"options": [
|
||||
{
|
||||
@@ -8717,7 +8744,7 @@
|
||||
},
|
||||
{
|
||||
"name": "TOBAKI RACING FORGED ROD Y15ZR/LC135 5S",
|
||||
"categoryName": "TOBAKI RACING",
|
||||
"categoryName": "Engine & Cylinder",
|
||||
"brandName": "TOBAKI RACING",
|
||||
"options": [
|
||||
{
|
||||
@@ -8791,7 +8818,7 @@
|
||||
},
|
||||
{
|
||||
"name": "TOBAKI RACING SUPERHEAD VALVE SEAT",
|
||||
"categoryName": "TOBAKI RACING",
|
||||
"categoryName": "Engine & Cylinder",
|
||||
"brandName": "TOBAKI RACING",
|
||||
"options": [
|
||||
{
|
||||
@@ -8837,7 +8864,7 @@
|
||||
},
|
||||
{
|
||||
"name": "TOBAKI X CLUTCH PUSH ROD",
|
||||
"categoryName": "TOBAKI RACING",
|
||||
"categoryName": "Transmission & Clutch",
|
||||
"brandName": "TOBAKI",
|
||||
"options": [
|
||||
{
|
||||
@@ -8877,7 +8904,7 @@
|
||||
},
|
||||
{
|
||||
"name": "TOBAKI X CAMSHAFT VR SERIES",
|
||||
"categoryName": "TOBAKI RACING",
|
||||
"categoryName": "Engine & Cylinder",
|
||||
"brandName": "TOBAKI RACING",
|
||||
"options": [
|
||||
{
|
||||
@@ -8987,7 +9014,7 @@
|
||||
},
|
||||
{
|
||||
"name": "TOBAKI X CAMSHAFT VR PRO SERIES",
|
||||
"categoryName": "TOBAKI RACING",
|
||||
"categoryName": "Engine & Cylinder",
|
||||
"brandName": "TOBAKI RACING",
|
||||
"options": [
|
||||
{
|
||||
@@ -9025,7 +9052,7 @@
|
||||
},
|
||||
{
|
||||
"name": "TOBAKI X FORGED PISTON Y15ZR/LC135",
|
||||
"categoryName": "TOBAKI RACING",
|
||||
"categoryName": "Engine & Cylinder",
|
||||
"brandName": "TOBAKI RACING",
|
||||
"options": [
|
||||
{
|
||||
@@ -9134,7 +9161,7 @@
|
||||
},
|
||||
{
|
||||
"name": "TOBAKI RACING FORGED PISTON RS150R",
|
||||
"categoryName": "TOBAKI RACING",
|
||||
"categoryName": "Engine & Cylinder",
|
||||
"brandName": "TOBAKI RACING",
|
||||
"options": [
|
||||
{
|
||||
@@ -9194,7 +9221,7 @@
|
||||
},
|
||||
{
|
||||
"name": "TOBAKI X CLUTCH SPRING SWOSC-V",
|
||||
"categoryName": "TOBAKI RACING",
|
||||
"categoryName": "Transmission & Clutch",
|
||||
"brandName": "TOBAKI RACING",
|
||||
"options": [
|
||||
{
|
||||
@@ -9352,7 +9379,7 @@
|
||||
},
|
||||
{
|
||||
"name": "TOBAKI VALVE RACING (IN27/EX23) (IN28/EX24)",
|
||||
"categoryName": "TOBAKI RACING",
|
||||
"categoryName": "Engine & Cylinder",
|
||||
"brandName": "TOBAKI RACING",
|
||||
"options": [
|
||||
{
|
||||
@@ -9477,7 +9504,7 @@
|
||||
},
|
||||
{
|
||||
"name": "TOBAKI VALVE INTAKE EXHAUST SET -INTAKE 1PCS EXHAUST 1PCS",
|
||||
"categoryName": "TOBAKI",
|
||||
"categoryName": "Engine & Cylinder",
|
||||
"brandName": "TOBAKI",
|
||||
"options": [
|
||||
{
|
||||
@@ -9832,7 +9859,7 @@
|
||||
},
|
||||
{
|
||||
"name": "TOBAKI VALVE GUIDE",
|
||||
"categoryName": "TOBAKI",
|
||||
"categoryName": "Engine & Cylinder",
|
||||
"brandName": "TOBAKI",
|
||||
"options": [
|
||||
{
|
||||
@@ -9933,7 +9960,7 @@
|
||||
},
|
||||
{
|
||||
"name": "FUEL INJECTOR ASSY",
|
||||
"categoryName": "TOBAKI",
|
||||
"categoryName": "Fuel & Air Intake",
|
||||
"brandName": "TOBAKI",
|
||||
"options": [
|
||||
{
|
||||
@@ -10142,7 +10169,7 @@
|
||||
},
|
||||
{
|
||||
"name": "TOBAKI FUEL PUMP CORE",
|
||||
"categoryName": "TOBAKI",
|
||||
"categoryName": "Fuel & Air Intake",
|
||||
"brandName": "TOBAKI",
|
||||
"options": [
|
||||
{
|
||||
@@ -10371,7 +10398,7 @@
|
||||
},
|
||||
{
|
||||
"name": "TOBAKI THERMO SENSOR",
|
||||
"categoryName": "TOBAKI",
|
||||
"categoryName": "Electrical & Ignition",
|
||||
"brandName": "TOBAKI",
|
||||
"options": [
|
||||
{
|
||||
@@ -10462,7 +10489,7 @@
|
||||
},
|
||||
{
|
||||
"name": "TOBAKI FORK OIL SEAL SET 1 BOX 10PCS",
|
||||
"categoryName": "TOBAKI",
|
||||
"categoryName": "Suspension & Chassis",
|
||||
"brandName": "TOBAKI",
|
||||
"options": [
|
||||
{
|
||||
@@ -10544,7 +10571,7 @@
|
||||
},
|
||||
{
|
||||
"name": "TOBAKI X O-RING PREMIUM DRIVE CHAIN (H)",
|
||||
"categoryName": "TOBAKI",
|
||||
"categoryName": "Drive Chain & Sprockets",
|
||||
"brandName": "TOBAKI",
|
||||
"options": [
|
||||
{
|
||||
@@ -10625,7 +10652,7 @@
|
||||
},
|
||||
{
|
||||
"name": "TOBAKI X HAND CLUTCH CONVERSION KIT (COMPLETE SET)",
|
||||
"categoryName": "TOBAKI",
|
||||
"categoryName": "Transmission & Clutch",
|
||||
"brandName": "TOBAKI",
|
||||
"options": [
|
||||
{
|
||||
@@ -10708,7 +10735,7 @@
|
||||
},
|
||||
{
|
||||
"name": "TOBAKI STANDARD BLOCK SET",
|
||||
"categoryName": "TOBAKI",
|
||||
"categoryName": "Engine & Cylinder",
|
||||
"brandName": "TOBAKI",
|
||||
"options": [
|
||||
{
|
||||
@@ -11057,7 +11084,7 @@
|
||||
},
|
||||
{
|
||||
"name": "TOBAKI STEPPING MOTOR",
|
||||
"categoryName": "TOBAKI",
|
||||
"categoryName": "Electrical & Ignition",
|
||||
"brandName": "TOBAKI",
|
||||
"options": [
|
||||
{
|
||||
@@ -11175,7 +11202,7 @@
|
||||
},
|
||||
{
|
||||
"name": "TOBAKI SPROCKET TIMING CRANKSHAFT",
|
||||
"categoryName": "TOBAKI",
|
||||
"categoryName": "Engine & Cylinder",
|
||||
"brandName": "TOBAKI",
|
||||
"options": [
|
||||
{
|
||||
@@ -11357,7 +11384,7 @@
|
||||
},
|
||||
{
|
||||
"name": "TOBAKI VALVE SEAL STANDARD",
|
||||
"categoryName": "TOBAKI",
|
||||
"categoryName": "Engine & Cylinder",
|
||||
"brandName": "TOBAKI",
|
||||
"options": [
|
||||
{
|
||||
@@ -11462,7 +11489,7 @@
|
||||
},
|
||||
{
|
||||
"name": "TOBAKI x RIKEN PISTON RING SET",
|
||||
"categoryName": "TOBAKI",
|
||||
"categoryName": "Engine & Cylinder",
|
||||
"brandName": "TOBAKI",
|
||||
"options": [
|
||||
{
|
||||
@@ -11829,7 +11856,7 @@
|
||||
},
|
||||
{
|
||||
"name": "TOBAKI RAINCOAT WITH PANTS",
|
||||
"categoryName": "TOBAKI",
|
||||
"categoryName": "Apparel & Merchandise",
|
||||
"brandName": "TOBAKI",
|
||||
"options": [
|
||||
{
|
||||
@@ -11923,7 +11950,7 @@
|
||||
},
|
||||
{
|
||||
"name": "TOBAKI RACING CERAMIC BLOCK SETS Y16ZR NMAX NVX155 R15 V3",
|
||||
"categoryName": "SHOP BY BIKE",
|
||||
"categoryName": "Engine & Cylinder",
|
||||
"brandName": "TOBAKI RACING",
|
||||
"options": [
|
||||
{
|
||||
@@ -12040,7 +12067,7 @@
|
||||
},
|
||||
{
|
||||
"name": "TOBAKI X SUPER CLUTCH SET",
|
||||
"categoryName": "SHOP BY BIKE",
|
||||
"categoryName": "Transmission & Clutch",
|
||||
"brandName": "TOBAKI",
|
||||
"options": [
|
||||
{
|
||||
@@ -12109,7 +12136,7 @@
|
||||
},
|
||||
{
|
||||
"name": "TOBAKI X GUIDE STOPPER FOR JACK ROD USE",
|
||||
"categoryName": "SHOP BY BIKE",
|
||||
"categoryName": "Engine & Cylinder",
|
||||
"brandName": "TOBAKI RACING",
|
||||
"options": [
|
||||
{
|
||||
@@ -12150,7 +12177,7 @@
|
||||
},
|
||||
{
|
||||
"name": "TOBAKI X OVAL VALVE SPRING",
|
||||
"categoryName": "SHOP BY BIKE",
|
||||
"categoryName": "Engine & Cylinder",
|
||||
"brandName": "TOBAKI",
|
||||
"options": [
|
||||
{
|
||||
@@ -12219,7 +12246,7 @@
|
||||
},
|
||||
{
|
||||
"name": "TOBAKI X AIR FILTER",
|
||||
"categoryName": "SHOP BY BIKE",
|
||||
"categoryName": "Fuel & Air Intake",
|
||||
"brandName": "TOBAKI",
|
||||
"options": [
|
||||
{
|
||||
|
||||
Reference in new issue
Block a user