merge with forntend and add category to main category slug genrator

This commit is contained in:
Parsa Nazer
2025-05-24 19:24:19 +03:30
8 changed files with 85 additions and 88 deletions
@@ -18,7 +18,7 @@ const isMobile = useMediaQuery('(max-width: 1024px)');
</script>
<template>
<div class="columns-1 xs:columns-2 xl:columns-3 gap-6 sm:gap-8 w-full space-y-8">
<div class="grid grid-cols-1 xs:grid-cols-2 xl:grid-cols-3 gap-6 sm:gap-8 w-full space-y-8">
<BlogPost
v-for="article in articles"
:key="article.id"
+69 -71
View File
@@ -29,85 +29,83 @@ const createdAt = usePersianTimeAgo(new Date(date.value));
</script>
<template>
<div>
<NuxtLink
:to="`/article/${slug}`"
:class="variant === 'lg' ? 'aspect-square rounded-150 overflow-hidden' : 'h-fit'"
class="group w-full relative block"
<NuxtLink
:to="`/article/${slug}`"
:class="variant === 'lg' ? 'aspect-square rounded-150 overflow-hidden' : 'h-fit'"
class="group w-full relative block"
>
<Tag
v-if="variant === 'lg'"
class="bg-slate-950 absolute left-6 top-6 z-20"
>
<Tag
v-if="variant === 'lg'"
class="bg-slate-950 absolute left-6 top-6 z-20"
>
{{ category.name }}
</Tag>
<div
v-if="variant === 'sm'"
class="aspect-square w-full rounded-150 overflow-hidden relative"
>
<Tag class="bg-slate-950 absolute z-20 left-4 sm:left-6 top-4 sm:top-6 max-sm:text-xs">
{{ category.name }}
</Tag>
<div
v-if="variant === 'sm'"
class="aspect-square w-full rounded-150 overflow-hidden relative"
>
<Tag class="bg-slate-950 absolute z-20 left-4 sm:left-6 top-4 sm:top-6 max-sm:text-xs">
{{ category.name }}
</Tag>
<NuxtImg
:src="image"
class="group-hover:scale-105 transition-transform duration-200 absolute size-full object-cover z-10"
alt=""
/>
</div>
<div
:class="variant === 'lg' ? 'absolute px-6' : 'invert mt-6'"
class="bottom-6 lg:bottom-8 flex flex-col gap-4 z-20"
>
<div class="flex items-center gap-4 lg:gap-6">
<div class="flex items-center gap-2">
<Icon
name="ci:comment"
class="**:stroke-white size-3 md:size-3.5"
/>
<span class="typo-p-xs md:typo-p-sm text-white"> ۰ نظر </span>
</div>
<div class="flex items-center gap-2">
<Icon
name="ci:calendar"
class="**:stroke-white size-3 md:size-3.5"
/>
<span class="typo-p-xs md:typo-p-sm text-white">
{{ createdAt }}
</span>
</div>
</div>
<div class="flex gap-4 flex-col">
<span
:class="variant === 'lg' ? 'line-clamp-2' : ''"
class="text-base md:text-lg font-medium lg:typo-h-6 text-white"
>
{{ title }}
</span>
<p
v-if="variant === 'sm'"
class="text-white typo-p-xs max-sm:!leading-[175%] sm:typo-p-sm md:typo-p-md line-clamp-3"
>
تا با نرم افزارها شناخت بیشتری را برای طراحان رایانه ای علی الخصوص طراحان خلاقی، و فرهنگ پیشرو
در زبان فارسی ایجاد کرد، در این صورت می توان امید داشت که تمام و دشواری موجود در ارائه راهکارها
</p>
</div>
</div>
<NuxtImg
v-if="variant === 'lg'"
:src="image"
class="group-hover:scale-105 transition-transform duration-200 absolute size-full object-cover z-10"
alt=""
/>
</div>
<div
v-if="variant === 'lg'"
class="w-full h-full bg-linear-to-t from-black to-transparent absolute inset-0 z-15"
/>
</NuxtLink>
</div>
<div
:class="variant === 'lg' ? 'absolute px-6' : 'invert mt-6'"
class="bottom-6 lg:bottom-8 flex flex-col gap-4 z-20"
>
<div class="flex items-center gap-4 lg:gap-6">
<div class="flex items-center gap-2">
<Icon
name="ci:comment"
class="**:stroke-white size-3 md:size-3.5"
/>
<span class="typo-p-xs md:typo-p-sm text-white"> ۰ نظر </span>
</div>
<div class="flex items-center gap-2">
<Icon
name="ci:calendar"
class="**:stroke-white size-3 md:size-3.5"
/>
<span class="typo-p-xs md:typo-p-sm text-white">
{{ createdAt }}
</span>
</div>
</div>
<div class="flex gap-4 flex-col">
<span
:class="variant === 'lg' ? 'line-clamp-2' : ''"
class="text-base md:text-lg font-medium lg:typo-h-6 text-white"
>
{{ title }}
</span>
<p
v-if="variant === 'sm'"
class="text-white typo-p-xs max-sm:!leading-[175%] sm:typo-p-sm md:typo-p-md line-clamp-3"
>
تا با نرم افزارها شناخت بیشتری را برای طراحان رایانه ای علی الخصوص طراحان خلاقی، و فرهنگ پیشرو در
زبان فارسی ایجاد کرد، در این صورت می توان امید داشت که تمام و دشواری موجود در ارائه راهکارها
</p>
</div>
</div>
<NuxtImg
v-if="variant === 'lg'"
:src="image"
class="group-hover:scale-105 transition-transform duration-200 absolute size-full object-cover z-10"
alt=""
/>
<div
v-if="variant === 'lg'"
class="w-full h-full bg-linear-to-t from-black to-transparent absolute inset-0 z-15"
/>
</NuxtLink>
</template>
+2 -4
View File
@@ -18,15 +18,13 @@ await suspense();
<NuxtLink to="/articles">
<Button
variant="primary"
class="rounded-full max-sm:typo-label-sm max-sm:py-2"
class="rounded-full max-md:h-[38px] max-md:text-xs"
end-icon="ci:arrow-left"
>
نمایش همه
</Button>
</NuxtLink>
</div>
<ArticlesList
:articles="[...articles!.results,...articles!.results,...articles!.results,...articles!.results,...articles!.results,...articles!.results]"
/>
<ArticlesList :articles="articles!.results" />
</section>
</template>
@@ -38,15 +38,18 @@ const submitComment = async () => {
const limitedComments = computed(() => {
if (showMoreComments.value) {
return comments.value!.results;
return comments.value?.results;
}
return comments.value!.results.slice(0, 3);
return comments.value?.results.slice(0, 3);
});
</script>
<template>
<section class="bg-slate-50">
<section
v-if="!!comments"
class="bg-slate-50"
>
<div class="flex relative gap-8 my-42 container max-lg:flex-col">
<div
class="sticky top-0 flex flex-col gap-6 lg:min-w-[400px] h-fit bg-white p-8 rounded-xl border-[0.5px] border-slate-200"
@@ -99,13 +102,13 @@ const limitedComments = computed(() => {
/>
<div
v-if="comments!.count > 0"
v-if="comments.count > 0"
class="flex items-center justify-center w-full"
>
<Pagination
v-if="showMoreComments"
:total="comments!.count"
:items="comments!.results.map((item, i) => ({ type: 'page', value: i }))"
:total="comments.count"
:items="comments.results.map((item, i) => ({ type: 'page', value: i }))"
/>
<Button
v-else
@@ -17,7 +17,7 @@ const useGetProduct = (id: string | number | undefined) => {
// methods
const handleGetProduct = async (id: string | number | undefined) => {
const { data } = await axios.get<GetProductResponse>(`${API_ENDPOINTS.product.get}/${id}`);
const { data } = await axios.get<GetProductResponse>(`${API_ENDPOINTS.product.get}/${id}/`);
return data;
};
+1
View File
@@ -65,6 +65,7 @@ export default defineNuxtConfig({
"@vite-pwa/nuxt",
"@nuxt/image",
"@nuxtjs/seo",
"motion-v/nuxt",
],
sitemap: {
+1
View File
@@ -35,6 +35,7 @@
"gsap": "^3.12.7",
"highlight.js": "^11.11.1",
"jalali-ts": "^8.0.0",
"motion-v": "^1.1.1",
"nuxt": "^3.15.4",
"reka-ui": "^1.0.0-alpha.6",
"sanitize-html": "^2.15.0",
+1 -5
View File
@@ -3,7 +3,6 @@
import ChatButton from "~/components/product/ChatBox/ChatButton.vue";
import useGetProduct from "~/composables/api/product/useGetProduct";
import useGetComments from "~/composables/api/product/useGetComments";
import ProductsSlider from "~/components/global/product-detail/ProductsSlider.vue";
// state
@@ -11,10 +10,8 @@ import ProductsSlider from "~/components/global/product-detail/ProductsSlider.vu
const route = useRoute();
const id = route.params.id as string | undefined;
const page = ref(1);
const { suspense: suspenseProduct, data: product } = useGetProduct(id);
const { suspense: suspenseComments } = useGetComments(id, page);
useSeoMeta({
title: `محصول ${product.value?.name}`,
@@ -45,9 +42,8 @@ provide("productVariant", {
// ssr
const productResponse = await suspenseProduct();
const commentsResponse = await suspenseComments();
if (productResponse.isError || commentsResponse.isError) {
if (productResponse.isError ) {
throw createError({
statusCode: 404,
statusMessage: `error : product ${id} prefetch error`,