diff --git a/app/Http/Controllers/Admin/System/GeneralSettingController.php b/app/Http/Controllers/Admin/System/GeneralSettingController.php index 1a374b0..50ae7c8 100644 --- a/app/Http/Controllers/Admin/System/GeneralSettingController.php +++ b/app/Http/Controllers/Admin/System/GeneralSettingController.php @@ -29,12 +29,20 @@ public function update(GeneralSettingRequest $request): RedirectResponse $setting = GeneralSetting::create($validated); } - if ($request->hasFile('logo')) { - $setting->addMediaFromRequest('logo')->toMediaCollection('logo'); + if ($request->hasFile('logo_light')) { + $setting->addMediaFromRequest('logo_light')->toMediaCollection('logo_light'); } - if ($request->hasFile('icon')) { - $setting->addMediaFromRequest('icon')->toMediaCollection('icon'); + if ($request->hasFile('logo_dark')) { + $setting->addMediaFromRequest('logo_dark')->toMediaCollection('logo_dark'); + } + + if ($request->hasFile('icon_light')) { + $setting->addMediaFromRequest('icon_light')->toMediaCollection('icon_light'); + } + + if ($request->hasFile('icon_dark')) { + $setting->addMediaFromRequest('icon_dark')->toMediaCollection('icon_dark'); } return redirect()->back()->with('success', 'Pengaturan berhasil diperbarui'); diff --git a/app/Http/Middleware/HandleInertiaRequests.php b/app/Http/Middleware/HandleInertiaRequests.php index 77ac6a3..89f6f09 100644 --- a/app/Http/Middleware/HandleInertiaRequests.php +++ b/app/Http/Middleware/HandleInertiaRequests.php @@ -2,6 +2,7 @@ namespace App\Http\Middleware; +use App\Models\GeneralSetting; use Illuminate\Http\Request; use Inertia\Middleware; @@ -38,6 +39,7 @@ public function share(Request $request): array return [ ...parent::share($request), 'name' => config('app.name'), + 'setting' => GeneralSetting::first(), 'auth' => [ 'user' => $request->user() ? $request->user()->load('profile') : null, 'roles' => $request->user() ? $request->user()->getRoleNames() : [], diff --git a/app/Http/Requests/Admin/System/GeneralSettingRequest.php b/app/Http/Requests/Admin/System/GeneralSettingRequest.php index c670ed0..1cd51eb 100644 --- a/app/Http/Requests/Admin/System/GeneralSettingRequest.php +++ b/app/Http/Requests/Admin/System/GeneralSettingRequest.php @@ -30,8 +30,10 @@ public function rules(): array 'description' => ['required', 'string'], 'address' => ['required', 'string'], 'phone' => ['required', 'string', 'max:20'], - 'logo' => [$settingExists ? 'nullable' : 'required', 'image', 'max:2048'], - 'icon' => [$settingExists ? 'nullable' : 'required', 'image', 'max:1024'], + 'logo_light' => [$settingExists ? 'nullable' : 'required', 'image', 'max:2048'], + 'logo_dark' => ['nullable', 'image', 'max:2048'], + 'icon_light' => [$settingExists ? 'nullable' : 'required', 'image', 'max:1024'], + 'icon_dark' => ['nullable', 'image', 'max:1024'], ]; } } diff --git a/app/Models/GeneralSetting.php b/app/Models/GeneralSetting.php index aff5e07..222c0ea 100644 --- a/app/Models/GeneralSetting.php +++ b/app/Models/GeneralSetting.php @@ -14,31 +14,51 @@ use Spatie\MediaLibrary\InteractsWithMedia; #[Guarded(['id'])] -#[Appends(['logo_url', 'icon_url'])] +#[Appends(['logo_light_url', 'logo_dark_url', 'icon_light_url', 'icon_dark_url'])] class GeneralSetting extends Model implements HasMedia { use HasFactory, InteractsWithMedia, LogsActivity; public function registerMediaCollections(): void { - $this->addMediaCollection('logo') + $this->addMediaCollection('logo_light') ->singleFile(); - $this->addMediaCollection('icon') + $this->addMediaCollection('logo_dark') + ->singleFile(); + + $this->addMediaCollection('icon_light') + ->singleFile(); + + $this->addMediaCollection('icon_dark') ->singleFile(); } - protected function logoUrl(): Attribute + protected function logoLightUrl(): Attribute { return Attribute::make( - get: fn () => $this->getFirstMediaUrl('logo') ?: null, + get: fn () => $this->getFirstMediaUrl('logo_light') ?: null, ); } - protected function iconUrl(): Attribute + protected function logoDarkUrl(): Attribute { return Attribute::make( - get: fn () => $this->getFirstMediaUrl('icon') ?: null, + get: fn () => $this->getFirstMediaUrl('logo_dark') ?: null, + ); + } + + protected function iconLightUrl(): Attribute + { + return Attribute::make( + get: fn () => $this->getFirstMediaUrl('icon_light') ?: null, + ); + } + + protected function iconDarkUrl(): Attribute + { + return Attribute::make( + get: fn () => $this->getFirstMediaUrl('icon_dark') ?: null, ); } diff --git a/resources/js/components/app-logo-icon.tsx b/resources/js/components/app-logo-icon.tsx index 7e9fcf1..f046842 100644 --- a/resources/js/components/app-logo-icon.tsx +++ b/resources/js/components/app-logo-icon.tsx @@ -1,3 +1,32 @@ -export default function AppLogoIcon() { - return Logo; +import { cn } from '@/lib/utils'; +import { usePage } from '@inertiajs/react'; +import type { GeneralSetting } from '@/types'; + +export default function AppLogoIcon({ className }: { className?: string }) { + const { setting } = usePage<{ setting: GeneralSetting }>().props; + + if (!setting?.icon_light_url && !setting?.icon_dark_url) { + return ( + Logo + ); + } + + return ( + <> + {setting?.icon_light_url && ( + Logo Light + )} + {setting?.icon_dark_url && ( + Logo Dark + )} + + ); } diff --git a/resources/js/components/app-logo.tsx b/resources/js/components/app-logo.tsx index 9bac283..845ef14 100644 --- a/resources/js/components/app-logo.tsx +++ b/resources/js/components/app-logo.tsx @@ -1,11 +1,30 @@ +import { usePage } from '@inertiajs/react'; +import type { GeneralSetting } from '@/types'; + export default function AppLogo() { + const { setting } = usePage<{ setting: GeneralSetting }>().props; + return ( - <> -
- - VN Grup +
+ {setting?.logo_light_url ? ( + {setting.name} + ) : null} + {setting?.logo_dark_url ? ( + {setting.name} + ) : null} + {!setting?.logo_light_url && !setting?.logo_dark_url && ( + + {setting?.name || 'VN Grup'} -
- + )} +
); } diff --git a/resources/js/pages/admin/system/settings/index.tsx b/resources/js/pages/admin/system/settings/index.tsx index b7f8f05..105a98a 100644 --- a/resources/js/pages/admin/system/settings/index.tsx +++ b/resources/js/pages/admin/system/settings/index.tsx @@ -21,61 +21,57 @@ export default function SettingIndex({ description: setting?.description || '', address: setting?.address || '', phone: setting?.phone || '', - logo: null as File | null, - icon: null as File | null, + logo_light: null as File | null, + logo_dark: null as File | null, + icon_light: null as File | null, + icon_dark: null as File | null, }); - const logoInputRef = useRef(null); - const iconInputRef = useRef(null); + const logoLightInputRef = useRef(null); + const logoDarkInputRef = useRef(null); + const iconLightInputRef = useRef(null); + const iconDarkInputRef = useRef(null); - const [logoPreview, setLogoPreview] = useState( - setting?.logo_url || null, + const [logoLightPreview, setLogoLightPreview] = useState( + setting?.logo_light_url || null, ); - const [iconPreview, setIconPreview] = useState( - setting?.icon_url || null, + const [logoDarkPreview, setLogoDarkPreview] = useState( + setting?.logo_dark_url || null, + ); + const [iconLightPreview, setIconLightPreview] = useState( + setting?.icon_light_url || null, + ); + const [iconDarkPreview, setIconDarkPreview] = useState( + setting?.icon_dark_url || null, ); - const handleLogoChange = (e: React.ChangeEvent) => { + const handleFileChange = ( + e: React.ChangeEvent, + field: 'logo_light' | 'logo_dark' | 'icon_light' | 'icon_dark', + setPreview: React.Dispatch>, + ) => { const file = e.target.files?.[0]; if (!file) { return; } - setData('logo', file); + setData(field, file); const reader = new FileReader(); - reader.onloadend = () => setLogoPreview(reader.result as string); + reader.onloadend = () => setPreview(reader.result as string); reader.readAsDataURL(file); }; - const removeLogo = () => { - setData('logo', null); - setLogoPreview(null); + const removeFile = ( + field: 'logo_light' | 'logo_dark' | 'icon_light' | 'icon_dark', + setPreview: React.Dispatch>, + inputRef: React.RefObject, + ) => { + setData(field, null); + setPreview(null); - if (logoInputRef.current) { - logoInputRef.current.value = ''; - } - }; - - const handleIconChange = (e: React.ChangeEvent) => { - const file = e.target.files?.[0]; - - if (!file) { - return; - } - - setData('icon', file); - const reader = new FileReader(); - reader.onloadend = () => setIconPreview(reader.result as string); - reader.readAsDataURL(file); - }; - - const removeIcon = () => { - setData('icon', null); - setIconPreview(null); - - if (iconInputRef.current) { - iconInputRef.current.value = ''; + if (inputRef.current) { + inputRef.current.value = ''; } }; @@ -203,51 +199,118 @@ export default function SettingIndex({ Logo Aplikasi - - {logoPreview ? ( -
- Logo preview + +
+ + {logoLightPreview ? ( +
+ Logo Light preview + +
+ ) : ( -
- ) : ( - - )} - - + /> + +
+ +
+ + {logoDarkPreview ? ( +
+ Logo Dark preview + +
+ ) : ( + + )} + + handleFileChange( + e, + 'logo_dark', + setLogoDarkPreview, + ) + } + /> + +
@@ -255,53 +318,118 @@ export default function SettingIndex({ Favicon / Icon - - {iconPreview ? ( -
-
+ +
+ + {iconLightPreview ? ( +
Icon preview
-
- ) : ( - + )} + + handleFileChange( + e, + 'icon_light', + setIconLightPreview, + ) } - className="group flex h-32 w-full cursor-pointer flex-col items-center justify-center rounded-xl border-2 border-dashed border-border transition-all hover:border-primary hover:bg-primary/5" - > - - - Klik untuk upload icon - - - ICO, PNG — maks. 1MB - - - )} - - + /> + +
+ +
+ + {iconDarkPreview ? ( +
+ Icon Dark preview + +
+ ) : ( + + )} + + handleFileChange( + e, + 'icon_dark', + setIconDarkPreview, + ) + } + /> + +
diff --git a/resources/js/pages/homepage.tsx b/resources/js/pages/homepage.tsx index d45f4cf..8b811a3 100644 --- a/resources/js/pages/homepage.tsx +++ b/resources/js/pages/homepage.tsx @@ -138,7 +138,15 @@ export default function Homepage({ categories = [], bestSellers, topSellingProdu }`}>
- VN Grup + {setting?.logo_light_url ? ( + {setting.name} + ) : ( + setting?.name || 'VN Grup' + )}