mirror of
https://github.com/rzmk/learnhouse.git
synced 2025-12-19 04:19:25 +00:00
feat: enhance hero section editor with tabbed interface and improved content management
This commit is contained in:
parent
570d6d61bb
commit
f45adf53e0
1 changed files with 556 additions and 529 deletions
|
|
@ -1,7 +1,7 @@
|
||||||
'use client'
|
'use client'
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import { LandingObject, LandingSection, LandingHeroSection, LandingTextAndImageSection, LandingLogos, LandingPeople, LandingBackground, LandingButton, LandingHeading, LandingImage, LandingFeaturedCourses } from './landing_types'
|
import { LandingObject, LandingSection, LandingHeroSection, LandingTextAndImageSection, LandingLogos, LandingPeople, LandingBackground, LandingButton, LandingHeading, LandingImage, LandingFeaturedCourses } from './landing_types'
|
||||||
import { Plus, Eye, ArrowUpDown, Trash2, GripVertical, LayoutTemplate, ImageIcon, Users, Award, ArrowRight, Edit, Link, Upload, Save, BookOpen } from 'lucide-react'
|
import { Plus, Eye, ArrowUpDown, Trash2, GripVertical, LayoutTemplate, ImageIcon, Users, Award, ArrowRight, Edit, Link, Upload, Save, BookOpen, TextIcon } from 'lucide-react'
|
||||||
import { DragDropContext, Droppable, Draggable } from 'react-beautiful-dnd'
|
import { DragDropContext, Droppable, Draggable } from 'react-beautiful-dnd'
|
||||||
import { Input } from "@components/ui/input"
|
import { Input } from "@components/ui/input"
|
||||||
import { Textarea } from "@components/ui/textarea"
|
import { Textarea } from "@components/ui/textarea"
|
||||||
|
|
@ -15,6 +15,7 @@ import { getOrgLandingMediaDirectory } from '@services/media/media'
|
||||||
import { getOrgCourses } from '@services/courses/courses'
|
import { getOrgCourses } from '@services/courses/courses'
|
||||||
import toast from 'react-hot-toast'
|
import toast from 'react-hot-toast'
|
||||||
import useSWR from 'swr'
|
import useSWR from 'swr'
|
||||||
|
import { Tabs, TabsList, TabsTrigger, TabsContent } from "@components/ui/tabs"
|
||||||
|
|
||||||
const SECTION_TYPES = {
|
const SECTION_TYPES = {
|
||||||
hero: {
|
hero: {
|
||||||
|
|
@ -504,7 +505,7 @@ const HeroSectionEditor: React.FC<{
|
||||||
<div className="space-y-4">
|
<div className="space-y-4">
|
||||||
{/* Title */}
|
{/* Title */}
|
||||||
<div>
|
<div>
|
||||||
<Label htmlFor="title">Title</Label>
|
<Label htmlFor="title">Section Title</Label>
|
||||||
<Input
|
<Input
|
||||||
id="title"
|
id="title"
|
||||||
value={section.title}
|
value={section.title}
|
||||||
|
|
@ -513,8 +514,109 @@ const HeroSectionEditor: React.FC<{
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Background */}
|
<Tabs defaultValue="content" className="w-full">
|
||||||
|
<TabsList className="grid w-full grid-cols-4 p-1 bg-gray-100 rounded-lg">
|
||||||
|
<TabsTrigger value="content" className="flex items-center space-x-2">
|
||||||
|
<TextIcon className="h-4 w-4" />
|
||||||
|
<span>Content</span>
|
||||||
|
</TabsTrigger>
|
||||||
|
<TabsTrigger value="background" className="flex items-center space-x-2">
|
||||||
|
<LayoutTemplate className="h-4 w-4" />
|
||||||
|
<span>Background</span>
|
||||||
|
</TabsTrigger>
|
||||||
|
<TabsTrigger value="buttons" className="flex items-center space-x-2">
|
||||||
|
<Button className="h-4 w-4" />
|
||||||
|
<span>Buttons</span>
|
||||||
|
</TabsTrigger>
|
||||||
|
<TabsTrigger value="illustration" className="flex items-center space-x-2">
|
||||||
|
<ImageIcon className="h-4 w-4" />
|
||||||
|
<span>Illustration</span>
|
||||||
|
</TabsTrigger>
|
||||||
|
</TabsList>
|
||||||
|
|
||||||
|
<TabsContent value="content" className="space-y-4 mt-4">
|
||||||
|
{/* Heading */}
|
||||||
<div className="space-y-4">
|
<div className="space-y-4">
|
||||||
|
<div>
|
||||||
|
<Label htmlFor="heading">Heading</Label>
|
||||||
|
<Input
|
||||||
|
id="heading"
|
||||||
|
value={section.heading.text}
|
||||||
|
onChange={(e) => onChange({
|
||||||
|
...section,
|
||||||
|
heading: { ...section.heading, text: e.target.value }
|
||||||
|
})}
|
||||||
|
placeholder="Enter heading text"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<Label htmlFor="headingColor">Heading Color</Label>
|
||||||
|
<div className="flex items-center space-x-2">
|
||||||
|
<Input
|
||||||
|
id="headingColor"
|
||||||
|
type="color"
|
||||||
|
value={section.heading.color}
|
||||||
|
onChange={(e) => onChange({
|
||||||
|
...section,
|
||||||
|
heading: { ...section.heading, color: e.target.value }
|
||||||
|
})}
|
||||||
|
className="w-20 h-10 p-1"
|
||||||
|
/>
|
||||||
|
<Input
|
||||||
|
value={section.heading.color}
|
||||||
|
onChange={(e) => onChange({
|
||||||
|
...section,
|
||||||
|
heading: { ...section.heading, color: e.target.value }
|
||||||
|
})}
|
||||||
|
placeholder="#000000"
|
||||||
|
className="font-mono"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Subheading */}
|
||||||
|
<div className="space-y-4">
|
||||||
|
<div>
|
||||||
|
<Label htmlFor="subheading">Subheading</Label>
|
||||||
|
<Input
|
||||||
|
id="subheading"
|
||||||
|
value={section.subheading.text}
|
||||||
|
onChange={(e) => onChange({
|
||||||
|
...section,
|
||||||
|
subheading: { ...section.subheading, text: e.target.value }
|
||||||
|
})}
|
||||||
|
placeholder="Enter subheading text"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<Label htmlFor="subheadingColor">Subheading Color</Label>
|
||||||
|
<div className="flex items-center space-x-2">
|
||||||
|
<Input
|
||||||
|
id="subheadingColor"
|
||||||
|
type="color"
|
||||||
|
value={section.subheading.color}
|
||||||
|
onChange={(e) => onChange({
|
||||||
|
...section,
|
||||||
|
subheading: { ...section.subheading, color: e.target.value }
|
||||||
|
})}
|
||||||
|
className="w-20 h-10 p-1"
|
||||||
|
/>
|
||||||
|
<Input
|
||||||
|
value={section.subheading.color}
|
||||||
|
onChange={(e) => onChange({
|
||||||
|
...section,
|
||||||
|
subheading: { ...section.subheading, color: e.target.value }
|
||||||
|
})}
|
||||||
|
placeholder="#666666"
|
||||||
|
className="font-mono"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</TabsContent>
|
||||||
|
|
||||||
|
<TabsContent value="background" className="space-y-4 mt-4">
|
||||||
<div>
|
<div>
|
||||||
<Label htmlFor="background">Background Type</Label>
|
<Label htmlFor="background">Background Type</Label>
|
||||||
<Select
|
<Select
|
||||||
|
|
@ -781,95 +883,14 @@ const HeroSectionEditor: React.FC<{
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</TabsContent>
|
||||||
|
|
||||||
{/* Heading */}
|
<TabsContent value="buttons" className="space-y-4 mt-4">
|
||||||
<div className="space-y-4">
|
<div className="space-y-3">
|
||||||
<div>
|
|
||||||
<Label htmlFor="heading">Heading</Label>
|
|
||||||
<Input
|
|
||||||
id="heading"
|
|
||||||
value={section.heading.text}
|
|
||||||
onChange={(e) => onChange({
|
|
||||||
...section,
|
|
||||||
heading: { ...section.heading, text: e.target.value }
|
|
||||||
})}
|
|
||||||
placeholder="Enter heading text"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<Label htmlFor="headingColor">Heading Color</Label>
|
|
||||||
<div className="flex items-center space-x-2">
|
|
||||||
<Input
|
|
||||||
id="headingColor"
|
|
||||||
type="color"
|
|
||||||
value={section.heading.color}
|
|
||||||
onChange={(e) => onChange({
|
|
||||||
...section,
|
|
||||||
heading: { ...section.heading, color: e.target.value }
|
|
||||||
})}
|
|
||||||
className="w-20 h-10 p-1"
|
|
||||||
/>
|
|
||||||
<Input
|
|
||||||
value={section.heading.color}
|
|
||||||
onChange={(e) => onChange({
|
|
||||||
...section,
|
|
||||||
heading: { ...section.heading, color: e.target.value }
|
|
||||||
})}
|
|
||||||
placeholder="#000000"
|
|
||||||
className="font-mono"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Subheading */}
|
|
||||||
<div className="space-y-4">
|
|
||||||
<div>
|
|
||||||
<Label htmlFor="subheading">Subheading</Label>
|
|
||||||
<Input
|
|
||||||
id="subheading"
|
|
||||||
value={section.subheading.text}
|
|
||||||
onChange={(e) => onChange({
|
|
||||||
...section,
|
|
||||||
subheading: { ...section.subheading, text: e.target.value }
|
|
||||||
})}
|
|
||||||
placeholder="Enter subheading text"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<Label htmlFor="subheadingColor">Subheading Color</Label>
|
|
||||||
<div className="flex items-center space-x-2">
|
|
||||||
<Input
|
|
||||||
id="subheadingColor"
|
|
||||||
type="color"
|
|
||||||
value={section.subheading.color}
|
|
||||||
onChange={(e) => onChange({
|
|
||||||
...section,
|
|
||||||
subheading: { ...section.subheading, color: e.target.value }
|
|
||||||
})}
|
|
||||||
className="w-20 h-10 p-1"
|
|
||||||
/>
|
|
||||||
<Input
|
|
||||||
value={section.subheading.color}
|
|
||||||
onChange={(e) => onChange({
|
|
||||||
...section,
|
|
||||||
subheading: { ...section.subheading, color: e.target.value }
|
|
||||||
})}
|
|
||||||
placeholder="#666666"
|
|
||||||
className="font-mono"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Buttons */}
|
|
||||||
<div>
|
|
||||||
<Label>Buttons (Max 2)</Label>
|
|
||||||
<div className="space-y-3 mt-2">
|
|
||||||
{section.buttons.map((button, index) => (
|
{section.buttons.map((button, index) => (
|
||||||
<div key={index} className="grid grid-cols-[1fr,1fr,auto] gap-2">
|
<div key={index} className="grid grid-cols-[1fr,1fr,auto] gap-2 p-4 border rounded-lg">
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
|
<Label>Button Text & Colors</Label>
|
||||||
<Input
|
<Input
|
||||||
value={button.text}
|
value={button.text}
|
||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
|
|
@ -880,6 +901,8 @@ const HeroSectionEditor: React.FC<{
|
||||||
placeholder="Button text"
|
placeholder="Button text"
|
||||||
/>
|
/>
|
||||||
<div className="flex items-center space-x-2">
|
<div className="flex items-center space-x-2">
|
||||||
|
<div className="space-y-1">
|
||||||
|
<Label className="text-xs">Text</Label>
|
||||||
<Input
|
<Input
|
||||||
type="color"
|
type="color"
|
||||||
value={button.color}
|
value={button.color}
|
||||||
|
|
@ -888,8 +911,11 @@ const HeroSectionEditor: React.FC<{
|
||||||
newButtons[index] = { ...button, color: e.target.value }
|
newButtons[index] = { ...button, color: e.target.value }
|
||||||
onChange({ ...section, buttons: newButtons })
|
onChange({ ...section, buttons: newButtons })
|
||||||
}}
|
}}
|
||||||
className="w-10 h-8 p-1"
|
className="w-full h-8 p-1"
|
||||||
/>
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="space-y-1">
|
||||||
|
<Label className="text-xs">Background</Label>
|
||||||
<Input
|
<Input
|
||||||
type="color"
|
type="color"
|
||||||
value={button.background}
|
value={button.background}
|
||||||
|
|
@ -898,11 +924,13 @@ const HeroSectionEditor: React.FC<{
|
||||||
newButtons[index] = { ...button, background: e.target.value }
|
newButtons[index] = { ...button, background: e.target.value }
|
||||||
onChange({ ...section, buttons: newButtons })
|
onChange({ ...section, buttons: newButtons })
|
||||||
}}
|
}}
|
||||||
className="w-10 h-8 p-1"
|
className="w-full h-8 p-1"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
|
<Label>Button Link</Label>
|
||||||
<div className="flex items-center space-x-2">
|
<div className="flex items-center space-x-2">
|
||||||
<Link className="h-4 w-4 text-gray-500" />
|
<Link className="h-4 w-4 text-gray-500" />
|
||||||
<Input
|
<Input
|
||||||
|
|
@ -923,7 +951,7 @@ const HeroSectionEditor: React.FC<{
|
||||||
const newButtons = section.buttons.filter((_, i) => i !== index)
|
const newButtons = section.buttons.filter((_, i) => i !== index)
|
||||||
onChange({ ...section, buttons: newButtons })
|
onChange({ ...section, buttons: newButtons })
|
||||||
}}
|
}}
|
||||||
className="text-red-500 hover:text-red-600 hover:bg-red-50"
|
className="text-red-500 hover:text-red-600 hover:bg-red-50 self-start mt-8"
|
||||||
>
|
>
|
||||||
<Trash2 className="h-4 w-4" />
|
<Trash2 className="h-4 w-4" />
|
||||||
</Button>
|
</Button>
|
||||||
|
|
@ -951,12 +979,10 @@ const HeroSectionEditor: React.FC<{
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</TabsContent>
|
||||||
|
|
||||||
{/* Illustration */}
|
<TabsContent value="illustration" className="space-y-4 mt-4">
|
||||||
<div className="space-y-4">
|
<div className="space-y-4">
|
||||||
<Label>Illustration</Label>
|
|
||||||
<div className="border rounded-lg p-4 space-y-4">
|
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<Label>Illustration Image</Label>
|
<Label>Illustration Image</Label>
|
||||||
<Input
|
<Input
|
||||||
|
|
@ -1080,7 +1106,8 @@ const HeroSectionEditor: React.FC<{
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</TabsContent>
|
||||||
|
</Tabs>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue