init: kovakemlak-crm project scaffold
- Next.js 16 + Appwrite multi-tenant emlak CRM - Database: kovakemlak-db (properties, customers, customer_searches, property_matches, presentations, investors, activities, tenant_settings) - Same stack as isletmem-kovakcrm (shadcn/ui template base) - Modules: portföy, müşteri takibi, arama kriterleri, otomatik eşleştirme, sunum linki, yatırımcı portalı
This commit is contained in:
@@ -0,0 +1,290 @@
|
||||
"use client"
|
||||
|
||||
import { Dices, Upload, Sun, Moon } from 'lucide-react'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { Label } from '@/components/ui/label'
|
||||
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'
|
||||
import { Separator } from '@/components/ui/separator'
|
||||
import { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from '@/components/ui/accordion'
|
||||
import { useThemeManager } from '@/hooks/use-theme-manager'
|
||||
import { useCircularTransition } from '@/hooks/use-circular-transition'
|
||||
import { colorThemes, tweakcnThemes } from '@/config/theme-data'
|
||||
import { radiusOptions, baseColors } from '@/config/theme-customizer-constants'
|
||||
import { ColorPicker } from '@/components/color-picker'
|
||||
import type { ImportedTheme } from '@/types/theme-customizer'
|
||||
import React from 'react'
|
||||
import "./circular-transition.css"
|
||||
|
||||
interface ThemeTabProps {
|
||||
selectedTheme: string
|
||||
setSelectedTheme: (theme: string) => void
|
||||
selectedTweakcnTheme: string
|
||||
setSelectedTweakcnTheme: (theme: string) => void
|
||||
selectedRadius: string
|
||||
setSelectedRadius: (radius: string) => void
|
||||
setImportedTheme: (theme: ImportedTheme | null) => void
|
||||
onImportClick: () => void
|
||||
}
|
||||
|
||||
export function ThemeTab({
|
||||
selectedTheme,
|
||||
setSelectedTheme,
|
||||
selectedTweakcnTheme,
|
||||
setSelectedTweakcnTheme,
|
||||
selectedRadius,
|
||||
setSelectedRadius,
|
||||
setImportedTheme,
|
||||
onImportClick
|
||||
}: ThemeTabProps) {
|
||||
const {
|
||||
isDarkMode,
|
||||
brandColorsValues,
|
||||
setBrandColorsValues,
|
||||
applyTheme,
|
||||
applyTweakcnTheme,
|
||||
applyRadius,
|
||||
handleColorChange
|
||||
} = useThemeManager()
|
||||
|
||||
const { toggleTheme } = useCircularTransition()
|
||||
|
||||
const handleRandomShadcn = () => {
|
||||
// Apply a random shadcn theme
|
||||
const randomTheme = colorThemes[Math.floor(Math.random() * colorThemes.length)]
|
||||
setSelectedTheme(randomTheme.value)
|
||||
setSelectedTweakcnTheme("") // Clear tweakcn selection
|
||||
setBrandColorsValues({}) // Clear brand colors state
|
||||
setImportedTheme(null) // Clear imported theme
|
||||
applyTheme(randomTheme.value, isDarkMode)
|
||||
}
|
||||
|
||||
const handleRandomTweakcn = () => {
|
||||
// Apply a random tweakcn theme
|
||||
const randomTheme = tweakcnThemes[Math.floor(Math.random() * tweakcnThemes.length)]
|
||||
setSelectedTweakcnTheme(randomTheme.value)
|
||||
setSelectedTheme("") // Clear shadcn selection
|
||||
setBrandColorsValues({}) // Clear brand colors state
|
||||
setImportedTheme(null) // Clear imported theme
|
||||
applyTweakcnTheme(randomTheme.preset, isDarkMode)
|
||||
}
|
||||
|
||||
const handleRadiusSelect = (radius: string) => {
|
||||
setSelectedRadius(radius)
|
||||
applyRadius(radius)
|
||||
}
|
||||
|
||||
const handleLightMode = (event: React.MouseEvent<HTMLButtonElement>) => {
|
||||
if (isDarkMode === false) return
|
||||
toggleTheme(event)
|
||||
}
|
||||
|
||||
const handleDarkMode = (event: React.MouseEvent<HTMLButtonElement>) => {
|
||||
if (isDarkMode === true) return
|
||||
toggleTheme(event)
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="p-4 space-y-6">
|
||||
|
||||
|
||||
{/* Hazır temalar */}
|
||||
<div className="space-y-3">
|
||||
<div className="flex items-center justify-between">
|
||||
<Label className="text-sm font-medium">Hazır temalar</Label>
|
||||
<Button variant="outline" size="sm" onClick={handleRandomShadcn} className="cursor-pointer">
|
||||
<Dices className="h-3.5 w-3.5 mr-1.5" />
|
||||
Rastgele
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<Select value={selectedTheme} onValueChange={(value) => {
|
||||
setSelectedTheme(value)
|
||||
setSelectedTweakcnTheme("") // Clear other selection
|
||||
setBrandColorsValues({}) // Clear brand colors state
|
||||
setImportedTheme(null) // Clear imported theme
|
||||
applyTheme(value, isDarkMode)
|
||||
}}>
|
||||
<SelectTrigger className="w-full cursor-pointer">
|
||||
<SelectValue placeholder="Tema seçin" />
|
||||
</SelectTrigger>
|
||||
<SelectContent className="max-h-60">
|
||||
<div className="p-2">
|
||||
{colorThemes.map((theme) => (
|
||||
<SelectItem key={theme.value} value={theme.value} className="cursor-pointer">
|
||||
<div className="flex items-center gap-2">
|
||||
<div className="flex gap-1">
|
||||
<div
|
||||
className="w-3 h-3 rounded-full border border-border/20"
|
||||
style={{ backgroundColor: theme.preset.styles.light.primary }}
|
||||
/>
|
||||
<div
|
||||
className="w-3 h-3 rounded-full border border-border/20"
|
||||
style={{ backgroundColor: theme.preset.styles.light.secondary }}
|
||||
/>
|
||||
<div
|
||||
className="w-3 h-3 rounded-full border border-border/20"
|
||||
style={{ backgroundColor: theme.preset.styles.light.accent }}
|
||||
/>
|
||||
<div
|
||||
className="w-3 h-3 rounded-full border border-border/20"
|
||||
style={{ backgroundColor: theme.preset.styles.light.muted }}
|
||||
/>
|
||||
</div>
|
||||
<span>{theme.name}</span>
|
||||
</div>
|
||||
</SelectItem>
|
||||
))}
|
||||
</div>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
|
||||
<Separator />
|
||||
|
||||
{/* Genişletilmiş temalar */}
|
||||
<div className="space-y-3">
|
||||
<div className="flex items-center justify-between">
|
||||
<Label className="text-sm font-medium">Genişletilmiş temalar</Label>
|
||||
<Button variant="outline" size="sm" onClick={handleRandomTweakcn} className="cursor-pointer">
|
||||
<Dices className="h-3.5 w-3.5 mr-1.5" />
|
||||
Rastgele
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<Select value={selectedTweakcnTheme} onValueChange={(value) => {
|
||||
setSelectedTweakcnTheme(value)
|
||||
setSelectedTheme("") // Clear other selection
|
||||
setBrandColorsValues({}) // Clear brand colors state
|
||||
setImportedTheme(null) // Clear imported theme
|
||||
const selectedPreset = tweakcnThemes.find(t => t.value === value)?.preset
|
||||
if (selectedPreset) {
|
||||
applyTweakcnTheme(selectedPreset, isDarkMode)
|
||||
}
|
||||
}}>
|
||||
<SelectTrigger className="w-full cursor-pointer">
|
||||
<SelectValue placeholder="Tema seçin" />
|
||||
</SelectTrigger>
|
||||
<SelectContent className="max-h-60">
|
||||
<div className="p-2">
|
||||
{tweakcnThemes.map((theme) => (
|
||||
<SelectItem key={theme.value} value={theme.value} className="cursor-pointer">
|
||||
<div className="flex items-center gap-2">
|
||||
<div className="flex gap-1">
|
||||
<div
|
||||
className="w-3 h-3 rounded-full border border-border/20"
|
||||
style={{ backgroundColor: theme.preset.styles.light.primary }}
|
||||
/>
|
||||
<div
|
||||
className="w-3 h-3 rounded-full border border-border/20"
|
||||
style={{ backgroundColor: theme.preset.styles.light.secondary }}
|
||||
/>
|
||||
<div
|
||||
className="w-3 h-3 rounded-full border border-border/20"
|
||||
style={{ backgroundColor: theme.preset.styles.light.accent }}
|
||||
/>
|
||||
<div
|
||||
className="w-3 h-3 rounded-full border border-border/20"
|
||||
style={{ backgroundColor: theme.preset.styles.light.muted }}
|
||||
/>
|
||||
</div>
|
||||
<span>{theme.name}</span>
|
||||
</div>
|
||||
</SelectItem>
|
||||
))}
|
||||
</div>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
|
||||
<Separator />
|
||||
|
||||
{/* Köşe yuvarlama */}
|
||||
<div className="space-y-3">
|
||||
<Label className="text-sm font-medium">Köşe yuvarlama</Label>
|
||||
<div className="grid grid-cols-5 gap-2">
|
||||
{radiusOptions.map((option) => (
|
||||
<div
|
||||
key={option.value}
|
||||
className={`relative cursor-pointer rounded-md p-3 border transition-colors ${
|
||||
selectedRadius === option.value
|
||||
? "border-primary"
|
||||
: "border-border hover:border-border/60"
|
||||
}`}
|
||||
onClick={() => handleRadiusSelect(option.value)}
|
||||
>
|
||||
<div className="text-center">
|
||||
<div className="text-xs font-medium">{option.name}</div>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Separator />
|
||||
|
||||
{/* Görünüm modu */}
|
||||
<div className="space-y-3">
|
||||
<Label className="text-sm font-medium">Görünüm modu</Label>
|
||||
<div className="grid grid-cols-2 gap-2">
|
||||
<Button
|
||||
variant={!isDarkMode ? "secondary" : "outline"}
|
||||
size="sm"
|
||||
onClick={handleLightMode}
|
||||
className="cursor-pointer"
|
||||
>
|
||||
<Sun className="h-4 w-4 mr-1" />
|
||||
Açık
|
||||
</Button>
|
||||
<Button
|
||||
variant={isDarkMode ? "secondary" : "outline"}
|
||||
size="sm"
|
||||
onClick={handleDarkMode}
|
||||
className="cursor-pointer"
|
||||
>
|
||||
<Moon className="h-4 w-4 mr-1" />
|
||||
Koyu
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Separator />
|
||||
|
||||
{/* Tema içe aktar */}
|
||||
<div className="space-y-3">
|
||||
<Button
|
||||
variant="outline"
|
||||
size="lg"
|
||||
onClick={onImportClick}
|
||||
className="w-full cursor-pointer"
|
||||
>
|
||||
<Upload className="h-3.5 w-3.5 mr-1.5" />
|
||||
Tema içe aktar
|
||||
</Button>
|
||||
<p className="text-muted-foreground text-xs">
|
||||
tweakcn.com gibi araçlardan dışa aktardığınız JSON tema dosyasını yükleyebilirsiniz.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* Marka renkleri */}
|
||||
<Accordion type="single" collapsible className="w-full border-b rounded-lg">
|
||||
<AccordionItem value="brand-colors" className="border border-border rounded-lg overflow-hidden">
|
||||
<AccordionTrigger className="px-4 py-3 hover:no-underline hover:bg-muted/50 transition-colors">
|
||||
<Label className="text-sm font-medium cursor-pointer">Marka renkleri</Label>
|
||||
</AccordionTrigger>
|
||||
<AccordionContent className="px-4 pb-4 pt-2 space-y-3 border-t border-border bg-muted/20">
|
||||
{baseColors.map((color) => (
|
||||
<div key={color.cssVar} className="flex items-center justify-between">
|
||||
<ColorPicker
|
||||
label={color.name}
|
||||
cssVar={color.cssVar}
|
||||
value={brandColorsValues[color.cssVar] || ""}
|
||||
onChange={handleColorChange}
|
||||
/>
|
||||
</div>
|
||||
))}
|
||||
</AccordionContent>
|
||||
</AccordionItem>
|
||||
</Accordion>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user