Add image upload fields, media edit/delete, blog seeds

This commit is contained in:
Noro Studio
2026-06-30 21:00:44 +03:30
parent 79491cd8ef
commit 493ee8105e
12 changed files with 985 additions and 36 deletions
+46
View File
@@ -57,6 +57,33 @@
</div>
</section>
<section class="card space-y-4">
<h3 class="font-semibold text-slate-800">تصاویر Hero</h3>
<ImageField v-model="hero.darkImageUrl" label="پس‌زمینه تم تیره" />
<ImageField v-model="hero.lightImageUrl" label="پس‌زمینه تم روشن" />
</section>
<section class="card space-y-4">
<div class="flex items-center justify-between">
<h3 class="font-semibold text-slate-800">پیام‌رسان‌ها</h3>
<button type="button" class="btn-secondary text-xs" @click="addMessenger">افزودن</button>
</div>
<div v-for="(messenger, i) in messengers" :key="messenger.id || i" class="space-y-4 rounded-xl border border-slate-100 p-4">
<div class="grid gap-4 sm:grid-cols-2">
<div>
<label class="label">نام</label>
<input v-model="messenger.name" class="input" />
</div>
<div>
<label class="label">لینک</label>
<input v-model="messenger.url" class="input" dir="ltr" />
</div>
</div>
<ImageField v-model="messenger.iconUrl" :label="`آیکون ${messenger.name || 'پیام‌رسان'}`" preview-class="h-12 w-12 object-contain p-1" />
<button type="button" class="text-sm text-red-500" @click="messengers.splice(i, 1)">حذف پیام‌رسان</button>
</div>
</section>
<section class="card space-y-4">
<h3 class="font-semibold text-slate-800">سئو پیش‌فرض</h3>
<div class="grid gap-4">
@@ -92,6 +119,7 @@
<script setup lang="ts">
import { onMounted, reactive, ref } from 'vue'
import { api, type NavItem, type SiteSettings } from '@/api/client'
import ImageField from '@/components/ImageField.vue'
const loading = ref(true)
const saving = ref(false)
@@ -102,6 +130,8 @@ const error = ref('')
const site = reactive<SiteSettings>({})
const seo = reactive({ defaultTitle: '', defaultDescription: '' })
const navigation = ref<NavItem[]>([])
const hero = reactive({ darkImageUrl: '', lightImageUrl: '' })
const messengers = ref<Array<{ id: string; name: string; url: string; iconUrl?: string }>>([])
onMounted(async () => {
try {
@@ -110,6 +140,11 @@ onMounted(async () => {
seo.defaultTitle = siteData.seo?.defaultTitle || ''
seo.defaultDescription = siteData.seo?.defaultDescription || ''
navigation.value = [...nav]
hero.darkImageUrl = siteData.hero?.darkImageUrl || ''
hero.lightImageUrl = siteData.hero?.lightImageUrl || ''
messengers.value = siteData.messengers?.length
? siteData.messengers.map((m) => ({ ...m }))
: []
} catch (e) {
error.value = e instanceof Error ? e.message : 'خطا در بارگذاری'
} finally {
@@ -121,12 +156,23 @@ function addNavItem() {
navigation.value.push({ label: '', to: '' })
}
function addMessenger() {
messengers.value.push({
id: `messenger-${Date.now()}`,
name: '',
url: '',
iconUrl: '',
})
}
async function save() {
saving.value = true
message.value = ''
error.value = ''
try {
site.seo = { defaultTitle: seo.defaultTitle, defaultDescription: seo.defaultDescription }
site.hero = { darkImageUrl: hero.darkImageUrl, lightImageUrl: hero.lightImageUrl }
site.messengers = messengers.value
await api.putSite({ ...site })
message.value = 'تنظیمات سایت ذخیره شد.'
} catch (e) {