commit cbc59222c245636e8c22a7013b8b140179276dcb Author: AyrisAI Date: Sun Jul 12 20:18:55 2026 +0300 first commit diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..430f1b2 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,9 @@ +.next +node_modules +.env +.env.*.local +.git +.vscode +docs +README.md +AGENTS.md diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5ef6a52 --- /dev/null +++ b/.gitignore @@ -0,0 +1,41 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +/node_modules +/.pnp +.pnp.* +.yarn/* +!.yarn/patches +!.yarn/plugins +!.yarn/releases +!.yarn/versions + +# testing +/coverage + +# next.js +/.next/ +/out/ + +# production +/build + +# misc +.DS_Store +*.pem + +# debug +npm-debug.log* +yarn-debug.log* +yarn-error.log* +.pnpm-debug.log* + +# env files (can opt-in for committing if needed) +.env* + +# vercel +.vercel + +# typescript +*.tsbuildinfo +next-env.d.ts diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..f7f0cbb --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,42 @@ +# AGENTS.md + +## Stack +- Framework: Next.js 16, App Router, TypeScript strict +- Styling: Tailwind CSS v4 +- UI: shadcn/ui (new-york style, OKLCH) +- Animation: Framer Motion +- Icons: Lucide React +- i18n: next-intl +- ORM: Prisma + PostgreSQL +- Auth: NextAuth.js v5 +- Media: Cloudinary +- Deploy: Coolify (Docker, standalone output) + +## Sabit Tercihler +- Mock data: USE_MOCK=true (demo aşaması) +- proxy.ts kullan — middleware.ts deprecated (Next.js 15.3+) +- İletişim formu sadece /iletisim sayfasında — ana sayfada olmaz +- Footer'da "Created by ayris.tech" linki zorunlu +- Dockerfile'da dummy DATABASE_URL (prisma generate için) + +## Altyapı +- Gitea: https://git.ayris.tech (kullanıcı: ayrisdev) +- Coolify: https://client2.ayris.tech +- Cloudflare zone: ayris.tech +- Server IP: 188.245.175.169 + +## docs/ Klasörü +- docs/prd.md → ana içerik kaynağı +- docs/*.html → varsa mevcut site içeriği +- docs/*.md → ek belgeler + +## Aktif Skill'ler +- nextjs-seo → sitemap, metadata, robots.txt +- next-best-practices → kod kalitesi +- nextjs-app-router-patterns → Server Actions, Suspense +- demo-site → komple site üretimi +- design-demo → görsel kalite +- coolify-deploy → deploy pipeline + +## Proje Özel Notlar + diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..43c994c --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1 @@ +@AGENTS.md diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..20dd2ca --- /dev/null +++ b/Dockerfile @@ -0,0 +1,34 @@ +FROM node:22-alpine AS base + +FROM base AS deps +RUN apk add --no-cache libc6-compat +WORKDIR /app +COPY package.json package-lock.json* ./ +RUN npm ci --legacy-peer-deps + +FROM base AS builder +WORKDIR /app +COPY --from=deps /app/node_modules ./node_modules +COPY . . +ENV NEXT_TELEMETRY_DISABLED=1 +# Prisma generate için dummy URL — build sırasında gerçek DB gerekmez +ARG DATABASE_URL=postgresql://dummy:dummy@localhost:5432/dummy +ENV DATABASE_URL=$DATABASE_URL +RUN npx prisma generate +RUN npm run build + +FROM base AS runner +WORKDIR /app +ENV NODE_ENV=production +ENV NEXT_TELEMETRY_DISABLED=1 +RUN addgroup --system --gid 1001 nodejs +RUN adduser --system --uid 1001 nextjs +COPY --from=builder /app/public ./public +RUN mkdir .next && chown nextjs:nodejs .next +COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./ +COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static +USER nextjs +EXPOSE 3000 +ENV PORT=3000 +ENV HOSTNAME="0.0.0.0" +CMD ["node", "server.js"] diff --git a/README.md b/README.md new file mode 100644 index 0000000..e215bc4 --- /dev/null +++ b/README.md @@ -0,0 +1,36 @@ +This is a [Next.js](https://nextjs.org) project bootstrapped with [`create-next-app`](https://nextjs.org/docs/app/api-reference/cli/create-next-app). + +## Getting Started + +First, run the development server: + +```bash +npm run dev +# or +yarn dev +# or +pnpm dev +# or +bun dev +``` + +Open [http://localhost:3000](http://localhost:3000) with your browser to see the result. + +You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file. + +This project uses [`next/font`](https://nextjs.org/docs/app/building-your-application/optimizing/fonts) to automatically optimize and load [Geist](https://vercel.com/font), a new font family for Vercel. + +## Learn More + +To learn more about Next.js, take a look at the following resources: + +- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API. +- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial. + +You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js) - your feedback and contributions are welcome! + +## Deploy on Vercel + +The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js. + +Check out our [Next.js deployment documentation](https://nextjs.org/docs/app/building-your-application/deploying) for more details. diff --git a/app/[locale]/[category]/[slug]/page.tsx b/app/[locale]/[category]/[slug]/page.tsx new file mode 100644 index 0000000..f9661b7 --- /dev/null +++ b/app/[locale]/[category]/[slug]/page.tsx @@ -0,0 +1,272 @@ +import { getTranslations, setRequestLocale } from 'next-intl/server' +import { mockDb } from '@/lib/mockDb' +import Navbar from '@/components/Navbar' +import Footer from '@/components/Footer' +import ListingCard from '@/components/ListingCard' +import { notFound } from 'next/navigation' +import Image from 'next/image' +import { Phone, Globe, MapPin, Clock, Star, MessageSquare } from 'lucide-react' + +interface DetailPageProps { + params: Promise<{ locale: string; category: string; slug: string }> +} + +export default async function ListingDetailPage({ params }: DetailPageProps) { + const { locale, category, slug } = await params + setRequestLocale(locale) + + const t = await getTranslations('detail') + + const listing = await mockDb.getListingBySlug(slug) + if (!listing) { + notFound() + } + + // Fetch similar listings in same category (limit to 3, excluding current) + const allCategoryListings = await mockDb.getListings({ + categoryId: listing.categoryId + }) + const relatedListings = allCategoryListings + .filter(l => l.id !== listing.id) + .slice(0, 3) + + // Localized values + const name = + locale === 'ru' + ? listing.nameRu + : locale === 'en' + ? listing.nameEn + : listing.nameTr + + const description = + locale === 'ru' + ? listing.descriptionRu + : locale === 'en' + ? listing.descriptionEn + : listing.descriptionTr + + const priceSymbols = '₺'.repeat(listing.priceRange) + + // Format WhatsApp Link + const getWhatsAppLink = (number: string) => { + // Clean spaces, parenthesis, plus sign + const cleanNum = number.replace(/\D/g, '') + return `https://wa.me/${cleanNum}` + } + + return ( +
+ + +
+ + {/* Breadcrumb / Category Link */} +
+ marmaris local + / + + {locale === 'ru' ? listing.category?.nameRu : locale === 'en' ? listing.category?.nameEn : listing.category?.nameTr} + + / + {name} +
+ + {/* Hero Details Block */} +
+ +
+ + {/* Left: Gallery Panel */} +
+
+ 0 ? listing.images[0].url : 'https://images.unsplash.com/photo-1555396273-367ea4eb4db5?w=800&auto=format&fit=crop&q=80'} + alt={name} + fill + priority + className="object-cover" + /> +
+ + {/* Thumbnails if multiple images exist */} + {listing.images && listing.images.length > 1 && ( +
+ {listing.images.slice(1, 5).map((img, idx) => ( +
+ {`${name} +
+ ))} +
+ )} +
+ + {/* Right: Info Panel */} +
+ + {/* Badge & Title */} +
+
+ + {locale === 'ru' ? listing.category?.nameRu : locale === 'en' ? listing.category?.nameEn : listing.category?.nameTr} + + + {listing.isLocalApproved && ( + + ★ {t('approved')} + + )} +
+ +

+ {name} +

+ + {/* Stars and Price level */} +
+ {listing.rating && ( +
+ + {t('rating')}: {listing.rating.toFixed(1)} +
+ )} +
+ {t('price')}: {priceSymbols} +
+
+
+ + {/* Description */} +
+ {description} +
+ + {/* Contact Actions */} +
+

{t('contact')}

+ +
+ {listing.phone && ( + + + {t('call')} + + )} + + {listing.whatsapp && ( + + + {t('whatsapp')} + + )} +
+ + {/* External links */} +
+ {listing.website && ( + + + {t('website')} + + )} + + {listing.instagram && ( + + + {t('instagram')} + + )} +
+
+ +
+ +
+ + {/* Details footer (Hours & Location map) */} +
+ + {/* Address */} +
+
+ + {t('address')} +
+

+ {listing.address} +

+
+ + {/* Hours */} +
+
+ + {t('hours')} +
+
+ {listing.openingHours ? ( +

{(listing.openingHours as any).all || t('noHours')}

+ ) : ( +

{t('noHours')}

+ )} +
+
+ + {/* Map Frame */} + {listing.latitude && listing.longitude && ( +
+
+ + {t('location')} +
+
+