122 lines
4.6 KiB
Vue
122 lines
4.6 KiB
Vue
<script setup lang="ts">
|
|
import { Head, useForm } from '@inertiajs/vue3';
|
|
import { Monitor, Moon, Save, Sun } from '@lucide/vue';
|
|
import { toast } from 'vue-sonner';
|
|
import { Button } from '@/components/ui/button';
|
|
import { Card, CardContent } from '@/components/ui/card';
|
|
import {
|
|
Field,
|
|
FieldError,
|
|
FieldGroup,
|
|
FieldLabel,
|
|
FieldSet,
|
|
} from '@/components/ui/field';
|
|
import { Label } from '@/components/ui/label';
|
|
import { RadioGroup, RadioGroupItem } from '@/components/ui/radio-group';
|
|
import { applyAppearance } from '@/composables/useAppearance';
|
|
import SettingsLayout from '@/layouts/SettingsLayout.vue';
|
|
import { cn } from '@/lib/utils';
|
|
import type { AppearanceFormData, AppearanceMode } from '@/types/settings';
|
|
|
|
const props = defineProps<{
|
|
appearance: AppearanceMode;
|
|
}>();
|
|
|
|
const form = useForm<AppearanceFormData>({
|
|
appearance: props.appearance,
|
|
});
|
|
|
|
const options: Array<{
|
|
value: AppearanceMode;
|
|
label: string;
|
|
description: string;
|
|
icon: typeof Sun;
|
|
}> = [
|
|
{
|
|
value: 'light',
|
|
label: 'Terang',
|
|
description: 'Tampilan terang untuk lingkungan yang cukup pencahayaan.',
|
|
icon: Sun,
|
|
},
|
|
{
|
|
value: 'dark',
|
|
label: 'Gelap',
|
|
description: 'Tampilan gelap yang nyaman di malam hari.',
|
|
icon: Moon,
|
|
},
|
|
{
|
|
value: 'system',
|
|
label: 'Sistem',
|
|
description: 'Mengikuti pengaturan tampilan perangkat Anda.',
|
|
icon: Monitor,
|
|
},
|
|
];
|
|
|
|
function onAppearanceChange(value: string) {
|
|
form.appearance = value as AppearanceMode;
|
|
applyAppearance(form.appearance);
|
|
}
|
|
|
|
function submit() {
|
|
form.put('/admin/setting/appearance', {
|
|
onError: () => {
|
|
toast.error('Gagal menyimpan tampilan.');
|
|
},
|
|
});
|
|
}
|
|
</script>
|
|
|
|
<template>
|
|
|
|
<Head title="Tampilan" />
|
|
|
|
<SettingsLayout>
|
|
<form @submit.prevent="submit">
|
|
<Card>
|
|
<CardContent>
|
|
<FieldSet>
|
|
<FieldGroup>
|
|
<Field>
|
|
<FieldLabel>Mode Tampilan</FieldLabel>
|
|
<RadioGroup :model-value="form.appearance" class="grid gap-3"
|
|
@update:model-value="onAppearanceChange">
|
|
<Label v-for="option in options" :key="option.value"
|
|
:for="`appearance-${option.value}`" :class="cn(
|
|
'flex cursor-pointer items-start gap-3 rounded-lg border p-4 transition-colors',
|
|
form.appearance === option.value
|
|
? 'border-primary bg-primary/5'
|
|
: 'hover:bg-accent/50',
|
|
)">
|
|
<RadioGroupItem :id="`appearance-${option.value}`" :value="option.value"
|
|
class="mt-0.5" />
|
|
<div class="flex flex-1 items-start gap-3">
|
|
<component :is="option.icon"
|
|
class="text-muted-foreground mt-0.5 size-5 shrink-0" />
|
|
<div class="space-y-1">
|
|
<p class="text-sm leading-none font-medium">
|
|
{{ option.label }}
|
|
</p>
|
|
<p class="text-muted-foreground text-sm">
|
|
{{ option.description }}
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</Label>
|
|
</RadioGroup>
|
|
<FieldError :errors="form.errors.appearance ? [form.errors.appearance] : []" />
|
|
</Field>
|
|
</FieldGroup>
|
|
</FieldSet>
|
|
|
|
<div class="mt-6 flex justify-end">
|
|
<Button type="submit" :disabled="form.processing">
|
|
<Save class="size-4" />
|
|
Simpan Tampilan
|
|
</Button>
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
</form>
|
|
</SettingsLayout>
|
|
</template>
|