327 lines
12 KiB
Vue
327 lines
12 KiB
Vue
<script setup>
|
|
definePageMeta({
|
|
layout: "admin",
|
|
title: "Settings",
|
|
});
|
|
|
|
const layoutStore = useLayoutStore();
|
|
const { getAdminNavigation } = useNavigation();
|
|
|
|
// Get settings navigation items
|
|
const settingsNavigation = computed(() => {
|
|
const adminNav = getAdminNavigation();
|
|
const settingsSection = adminNav.find(
|
|
(section) => section.title === "Setting"
|
|
);
|
|
return settingsSection?.items[0]?.children || [];
|
|
});
|
|
|
|
// Set active state for current route
|
|
const route = useRoute();
|
|
const isActiveRoute = (path) => route.path === path;
|
|
|
|
// Font options
|
|
const fonts = [
|
|
{ value: "inter", label: "Inter" },
|
|
{ value: "roboto", label: "Roboto" },
|
|
{ value: "poppins", label: "Poppins" },
|
|
];
|
|
|
|
const selectedFont = ref("inter");
|
|
|
|
// Theme handling
|
|
const { currentTheme, setTheme } = useTheme();
|
|
const selectedTheme = computed({
|
|
get: () => currentTheme.value === "dark",
|
|
set: (value) => {
|
|
setTheme(value ? "dark" : "default");
|
|
},
|
|
});
|
|
|
|
const handleThemeChange = (isDark) => {
|
|
selectedTheme.value = isDark;
|
|
};
|
|
|
|
const updatePreferences = () => {
|
|
// Update font and theme preferences
|
|
setTheme(selectedTheme.value ? "dark" : "default");
|
|
// You might want to add font updating logic here
|
|
|
|
// Show success toast
|
|
const toast = useToast();
|
|
toast.add({
|
|
title: "Preferences Updated",
|
|
description: "Your theme settings have been saved successfully.",
|
|
type: "success",
|
|
});
|
|
};
|
|
|
|
const layoutOptions = [
|
|
{
|
|
id: "vertical",
|
|
title: "Vertical Menu",
|
|
description: "Traditional vertical sidebar navigation",
|
|
icon: "mdi:view-split-vertical",
|
|
preview: "/images/layouts/vertical.svg",
|
|
},
|
|
{
|
|
id: "horizontal",
|
|
title: "Horizontal Menu",
|
|
description: "Modern horizontal top navigation",
|
|
icon: "mdi:view-split-horizontal",
|
|
preview: "/images/layouts/horizontal.svg",
|
|
},
|
|
];
|
|
|
|
const directionOptions = [
|
|
{
|
|
id: "ltr",
|
|
title: "Left to Right (LTR)",
|
|
description: "Default layout direction",
|
|
icon: "mdi:format-horizontal-align-left",
|
|
},
|
|
{
|
|
id: "rtl",
|
|
title: "Right to Left (RTL)",
|
|
description: "For RTL languages support",
|
|
icon: "mdi:format-horizontal-align-right",
|
|
},
|
|
];
|
|
|
|
const handleLayoutChange = (layoutId) => {
|
|
if (layoutStore.sidebarLayout !== layoutId) {
|
|
layoutStore.toggleSidebarLayout();
|
|
}
|
|
};
|
|
|
|
const handleDirectionChange = () => {
|
|
layoutStore.toggleDirection();
|
|
};
|
|
</script>
|
|
|
|
<template>
|
|
<div>
|
|
<div class="mb-6">
|
|
<h1 class="text-2xl font-semibold">Settings (Appearance)</h1>
|
|
<p class="text-gray-600">
|
|
Customize your admin interface layout and direction
|
|
</p>
|
|
</div>
|
|
|
|
<div class="flex flex-col lg:flex-row gap-8">
|
|
<!-- Settings Sidebar -->
|
|
<div class="lg:w-56">
|
|
<nav class="flex flex-col space-y-1">
|
|
<NuxtLink
|
|
v-for="item in settingsNavigation"
|
|
:key="item.name"
|
|
:to="item.path"
|
|
class="flex items-center gap-3 px-3 py-2 rounded-md transition-colors relative"
|
|
:class="[
|
|
isActiveRoute(item.path)
|
|
? 'bg-accent text-foreground font-medium'
|
|
: 'text-muted-foreground hover:text-foreground hover:bg-accent/50',
|
|
]"
|
|
>
|
|
<div class="flex items-center gap-3 flex-1">
|
|
<Icon :name="item.icon" class="w-4 h-4" />
|
|
{{ item.name }}
|
|
</div>
|
|
</NuxtLink>
|
|
</nav>
|
|
</div>
|
|
|
|
<!-- Settings Content -->
|
|
<div class="flex-1">
|
|
<!-- Combined Settings Card -->
|
|
<Card>
|
|
<CardHeader>
|
|
<CardTitle>Appearance Settings</CardTitle>
|
|
<CardDescription>Customize the look and feel of your dashboard</CardDescription>
|
|
</CardHeader>
|
|
<CardContent>
|
|
<div class="space-y-8">
|
|
<!-- Font Section -->
|
|
<div>
|
|
<h3 class="text-lg font-medium mb-2">Font</h3>
|
|
<p class="text-sm text-muted-foreground mb-4">Set the font you want to use in the dashboard.</p>
|
|
<div class="max-w-xl">
|
|
<FormKit
|
|
type="select"
|
|
name="font"
|
|
v-model="selectedFont"
|
|
:options="fonts"
|
|
placeholder="Select a font"
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
<Separator />
|
|
|
|
<!-- Theme Section -->
|
|
<div>
|
|
<h3 class="text-lg font-medium mb-2">Theme</h3>
|
|
<p class="text-sm text-muted-foreground mb-4">Select the theme for the dashboard.</p>
|
|
<div class="grid grid-cols-2 gap-4 max-w-xl">
|
|
<!-- Light Theme Option -->
|
|
<button
|
|
class="relative aspect-[1.2/1] rounded-lg border-2 overflow-hidden hover:border-primary transition-colors"
|
|
:class="!selectedTheme ? 'border-primary' : 'border-border'"
|
|
@click="handleThemeChange(false)"
|
|
>
|
|
<div class="absolute inset-0 bg-white p-4">
|
|
<div class="flex flex-col h-full">
|
|
<!-- Header -->
|
|
<div class="flex items-center gap-2 mb-4">
|
|
<Skeleton class="h-8 w-8 rounded-full border" />
|
|
<div class="space-y-1.5">
|
|
<Skeleton class="h-2.5 w-24 border" />
|
|
<Skeleton class="h-2 w-16 border" />
|
|
</div>
|
|
</div>
|
|
<!-- Content -->
|
|
<div class="flex-1 space-y-4">
|
|
<!-- Navigation -->
|
|
<div class="flex gap-2 mb-4">
|
|
<Skeleton class="h-2 w-12 border" />
|
|
<Skeleton class="h-2 w-12 border" />
|
|
<Skeleton class="h-2 w-12 border" />
|
|
</div>
|
|
<!-- Cards -->
|
|
<div class="grid grid-cols-2 gap-2">
|
|
<Skeleton class="h-12 w-full border rounded" />
|
|
<Skeleton class="h-12 w-full border rounded" />
|
|
</div>
|
|
<div class="space-y-2">
|
|
<Skeleton class="h-2 w-3/4 border" />
|
|
<Skeleton class="h-2 w-1/2 border" />
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<span class="absolute bottom-2 left-2 text-sm font-medium text-gray-900">Light</span>
|
|
<div class="absolute top-2 right-2">
|
|
<Icon v-if="!selectedTheme" name="ph:check-circle-fill" class="w-5 h-5 text-primary" />
|
|
</div>
|
|
</button>
|
|
|
|
<!-- Dark Theme Option -->
|
|
<button
|
|
class="relative aspect-[1.2/1] rounded-lg border-2 overflow-hidden hover:border-primary transition-colors"
|
|
:class="selectedTheme ? 'border-primary' : 'border-border'"
|
|
@click="handleThemeChange(true)"
|
|
>
|
|
<div class="absolute inset-0 bg-[#09090B] p-4">
|
|
<div class="flex flex-col h-full">
|
|
<!-- Header -->
|
|
<div class="flex items-center gap-2 mb-4">
|
|
<Skeleton class="h-8 w-8 rounded-full bg-[#18181B]" />
|
|
<div class="space-y-1.5">
|
|
<Skeleton class="h-2.5 w-24 bg-[#18181B]" />
|
|
<Skeleton class="h-2 w-16 bg-[#18181B]" />
|
|
</div>
|
|
</div>
|
|
<!-- Content -->
|
|
<div class="flex-1 space-y-4">
|
|
<!-- Navigation -->
|
|
<div class="flex gap-2 mb-4">
|
|
<Skeleton class="h-2 w-12 bg-[#18181B]" />
|
|
<Skeleton class="h-2 w-12 bg-[#18181B]" />
|
|
<Skeleton class="h-2 w-12 bg-[#18181B]" />
|
|
</div>
|
|
<!-- Cards -->
|
|
<div class="grid grid-cols-2 gap-2">
|
|
<Skeleton class="h-12 w-full bg-[#18181B] rounded" />
|
|
<Skeleton class="h-12 w-full bg-[#18181B] rounded" />
|
|
</div>
|
|
<div class="space-y-2">
|
|
<Skeleton class="h-2 w-3/4 bg-[#18181B]" />
|
|
<Skeleton class="h-2 w-1/2 bg-[#18181B]" />
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<span class="absolute bottom-2 left-2 text-sm font-medium text-white">Dark</span>
|
|
<div class="absolute top-2 right-2">
|
|
<Icon v-if="selectedTheme" name="ph:check-circle-fill" class="w-5 h-5 text-primary" />
|
|
</div>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<Separator />
|
|
|
|
<!-- Layout Configuration -->
|
|
<div>
|
|
<h3 class="text-lg font-medium mb-2">Layout Configuration</h3>
|
|
<p class="text-sm text-muted-foreground mb-4">Choose the layout style for your dashboard navigation.</p>
|
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
|
<button
|
|
v-for="option in layoutOptions"
|
|
:key="option.id"
|
|
class="relative flex flex-col items-start rounded-lg border-2 p-4 hover:border-primary transition-colors"
|
|
:class="layoutStore.sidebarLayout === option.id ? 'border-primary' : 'border-border'"
|
|
@click="handleLayoutChange(option.id)"
|
|
>
|
|
<div class="mb-4 rounded-lg border bg-card p-2">
|
|
<Icon :name="option.icon" class="h-6 w-6" />
|
|
</div>
|
|
<div class="mb-1 text-lg font-medium">{{ option.title }}</div>
|
|
<div class="text-sm text-muted-foreground">{{ option.description }}</div>
|
|
<div class="absolute top-2 right-2">
|
|
<Icon
|
|
v-if="layoutStore.sidebarLayout === option.id"
|
|
name="ph:check-circle-fill"
|
|
class="w-5 h-5 text-primary"
|
|
/>
|
|
</div>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<Separator />
|
|
|
|
<!-- Direction Configuration -->
|
|
<div>
|
|
<h3 class="text-lg font-medium mb-2">Direction Configuration</h3>
|
|
<p class="text-sm text-muted-foreground mb-4">Set the text direction for your dashboard interface.</p>
|
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
|
<button
|
|
v-for="option in directionOptions"
|
|
:key="option.id"
|
|
class="relative flex flex-col items-start rounded-lg border-2 p-4 hover:border-primary transition-colors"
|
|
:class="(layoutStore.isRTL ? 'rtl' : 'ltr') === option.id ? 'border-primary' : 'border-border'"
|
|
@click="handleDirectionChange"
|
|
>
|
|
<div class="mb-4 rounded-lg border bg-card p-2">
|
|
<Icon :name="option.icon" class="h-6 w-6" />
|
|
</div>
|
|
<div class="mb-1 text-lg font-medium">{{ option.title }}</div>
|
|
<div class="text-sm text-muted-foreground">{{ option.description }}</div>
|
|
<div class="absolute top-2 right-2">
|
|
<Icon
|
|
v-if="(layoutStore.isRTL ? 'rtl' : 'ltr') === option.id"
|
|
name="ph:check-circle-fill"
|
|
class="w-5 h-5 text-primary"
|
|
/>
|
|
</div>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</CardContent>
|
|
<CardFooter>
|
|
<Button @click="updatePreferences">Update preferences</Button>
|
|
</CardFooter>
|
|
</Card>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<style scoped>
|
|
.router-link-active {
|
|
@apply text-foreground font-medium;
|
|
}
|
|
</style>
|