cat << 'EOF' > setup.sh #!/bin/bash set -e echo "🚀 Keşif Atlası projesi kuruluyor..." # 1. Klasörleri oluştur mkdir -p data assets/css assets/js # 2. package.json cat << 'FILE' > package.json { "name": "kesif-atlasi", "version": "1.0.0", "description": "Türkiye'nin 81 İli Gezi Rehberi - Statik Site", "main": "generate.js", "scripts": { "build": "node generate.js && node build-blog.js && node build-pages.js" }, "keywords": ["gezi-rehberi", "turkiye", "81-il", "static-site-generator"], "author": "", "license": "MIT" } FILE # 3. .gitignore cat << 'FILE' > .gitignore node_modules/ .DS_Store *.log FILE # 4. build.sh cat << 'FILE' > build.sh #!/bin/bash set -e echo "▶ Keşif Atlası derleniyor..." node generate.js node build-blog.js node build-pages.js echo "" echo "✔ Site hazır! index.html, iller/, blog/, sitemap.xml ve robots.txt güncellendi." FILE chmod +x build.sh # 5. data/iller.json cat << 'FILE' > data/iller.json [ { "isim": "İstanbul", "slug": "istanbul", "plaka": "34", "bolge": "Marmara", "ozet": "İki kıtayı birbirine bağlayan, tarih ve modern yaşamı boğaz manzarasıyla harmanlayan metropol.", "en_iyi_zaman": "Nisan - Mayıs ve Eylül - Ekim", "gezilecek": ["Tarihi Yarımada", "Galata Kulesi", "Boğaz Turu", "Adalar"], "lezzet": ["Balık Ekmek", "Sultanahmet Köftesi", "Sarıyer Böreği", "Kanlıca Yoğurdu"] }, { "isim": "Nevşehir", "slug": "nevsehir", "plaka": "50", "bolge": "İç Anadolu", "ozet": "Peribacaları ve yeraltı şehirleriyle Kapadokya'nın kalbi; balon turlarının başkenti.", "en_iyi_zaman": "Nisan - Haziran ve Eylül - Kasım", "gezilecek": ["Göreme Açık Hava Müzesi", "Derinkuyu Yeraltı Şehri", "Uçhisar Kalesi", "Paşabağları"], "lezzet": ["Testi Kebabı", "Nevşehir Tavası", "Köftür", "Kuru Kaymak"] }, { "isim": "Antalya", "slug": "antalya", "plaka": "07", "bolge": "Akdeniz", "ozet": "Türkiye turizminin başkenti; antik kentleri, plajları ve Toros manzarasıyla dört mevsim canlı.", "en_iyi_zaman": "Nisan - Haziran ve Eylül - Kasım", "gezilecek": ["Kaleiçi", "Düden Şelalesi", "Aspendos Antik Tiyatrosu", "Olimpos"], "lezzet": ["Antalya Piyazı", "Hibeş", "Yanık Dondurma", "Şiş Köfte"] }, { "isim": "İzmir", "slug": "izmir", "plaka": "35", "bolge": "Ege", "ozet": "Ege'nin incisi; sahil şeridi, antik kentleri ve özgür ruhuyla yıl boyu canlı bir liman şehri.", "en_iyi_zaman": "Mayıs - Haziran ve Eylül - Ekim", "gezilecek": ["Kordon", "Efes Antik Kenti", "Şirince Köyü", "Tarihi Asansör"], "lezzet": ["Boyoz", "İzmir Kumrusu", "İzmir Köftesi", "Bomba Tatlısı"] }, { "isim": "Trabzon", "slug": "trabzon", "plaka": "61", "bolge": "Karadeniz", "ozet": "Sümela Manastırı'nın kayalara oyulduğu, yeşille denizin iç içe geçtiği Doğu Karadeniz merkezi.", "en_iyi_zaman": "Haziran - Eylül", "gezilecek": ["Sümela Manastırı", "Uzungöl", "Atatürk Köşkü", "Hamsiköy"], "lezzet": ["Akçaabat Köftesi", "Kuymak (Muhlama)", "Karadeniz Pidesi", "Hamsili Pilav"] }, { "isim": "Şanlıurfa", "slug": "sanliurfa", "plaka": "63", "bolge": "Güneydoğu Anadolu", "ozet": "Peygamberler şehri; Göbeklitepe ile insanlık tarihini yeniden yazan Mezopotamya kenti.", "en_iyi_zaman": "Mart - Mayıs ve Ekim - Kasım", "gezilecek": ["Göbeklitepe", "Balıklıgöl", "Harran Evleri", "Şanlıurfa Arkeoloji Müzesi"], "lezzet": ["Urfa Kebabı", "Çiğ Köfte", "Lahmacun", "Şıllık Tatlısı"] }, { "isim": "Kars", "slug": "kars", "plaka": "36", "bolge": "Doğu Anadolu", "ozet": "Baltık mimarisi, Ani Harabeleri ve kış manzaralarıyla Doğu Ekspresi'nin büyüleyici son durağı.", "en_iyi_zaman": "Aralık - Mart ve Haziran - Ağustos", "gezilecek": ["Ani Harabeleri", "Çıldır Gölü", "Kars Kalesi", "Katherina Sarayı"], "lezzet": ["Kars Kaşarı", "Kaz Eti", "Hangel", "Gravyer Peyniri"] } ] FILE # 6. data/blog.json cat << 'FILE' > data/blog.json [ { "slug": "karadeniz-yayla-turizmi-rehberi", "baslik": "Karadeniz Yaylalarında Bir Gün: Yayla Turizmi Rehberi", "etiket": "Doğa & Yayla", "tarih": "2026-06-15", "ozet": "Sisin arasından süzülen güneş ışığı, taze muhlama kokusu ve bulutların altında bir çadır... Karadeniz yaylalarını ziyaret etmeden önce bilmeniz gerekenler.", "govde": [ { "h2": "Yaylaya Çıkarken Bilinmesi Gerekenler", "p": "Karadeniz'in yüksek rakımlı yaylalarında hava koşulları dakikalar içinde değişebilir. Sis, yağmur ve aniden bastıran soğuk için yanınızda mutlaka rüzgarlık ve termal giysiler bulundurmalısınız." }, { "h2": "Öne Çıkan Yaylalar", "p": "Pokut, Sal, Huser ve Ayder gibi popüler noktalar hem eşsiz bulut denizi manzaraları sunar hem de yöresel ahşap mimariyi yakından görme fırsatı verir." } ] }, { "slug": "ege-kiyisinda-az-bilinen-5-koy", "baslik": "Ege Kıyısında Az Bilinen 5 Koy", "etiket": "Sahil & Doğa", "tarih": "2026-07-20", "ozet": "Bodrum ve Fethiye'nin kalabalığından uzak, sakin bir Ege tatili arıyorsanız, bu 5 koy tam size göre.", "govde": [ { "h2": "Kalabalıktan Uzak Ege Kaçamakları", "p": "Ege kıyılarında bakir kalmış koylar genellikle stabilize yolların veya patikaların ardında gizlidir. Doğayla baş başa kalmak isteyenler için Datça ve Karaburun yarımadaları benzersiz rotalar sunar." } ] }, { "slug": "ipek-yolu-guzergahinda-gezilecek-sehirler", "baslik": "Tarihin İzinde: İpek Yolu Güzergahında Gezilecek Şehirler", "etiket": "Tarih & Kültür", "tarih": "2026-08-10", "ozet": "Kervanların yüzyıllar önce geçtiği yolları takip ederek Anadolu'nun ticaret ve kültür mirasını keşfedin.", "govde": [ { "h2": "Kervansaraylar ve Taş Köprüler", "p": "Anadolu Selçuklu döneminden kalan hanlar, kervansaraylar ve çarşılar, ticaretin kalbinin attığı şehirleri günümüzde de açık hava müzesine dönüştürmektedir." } ] } ] FILE # 7. assets/css/style.css cat << 'FILE' > assets/css/style.css :root { --primary: #1F3A34; --primary-dark: #12241F; --accent: #C9A227; --accent-light: #EAE2C8; --bg: #F9F8F5; --surface: #FFFFFF; --text-main: #2C3531; --text-muted: #5C6561; --border: #E5E2DA; --radius: 12px; --shadow-sm: 0 2px 8px rgba(31, 58, 52, 0.05); --shadow-md: 0 8px 24px rgba(31, 58, 52, 0.08); --font-serif: 'Fraunces', Georgia, serif; --font-sans: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; } *, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; } body { font-family: var(--font-sans); background-color: var(--bg); color: var(--text-main); line-height: 1.65; display: flex; flex-direction: column; min-height: 100vh; } a { color: var(--primary); text-decoration: none; transition: color 0.2s ease; } a:hover { color: var(--accent); } .wrap { width: 100%; max-width: 1180px; margin: 0 auto; padding: 0 24px; } .skip-link { position: absolute; top: -100px; left: 20px; background: var(--accent); color: var(--primary-dark); padding: 8px 16px; border-radius: 4px; font-weight: 600; z-index: 999; } .skip-link:focus { top: 16px; } .site-header { background: rgba(255, 255, 255, 0.95); border-bottom: 1px solid var(--border); position: sticky; top: 0; z-index: 100; backdrop-filter: blur(10px); } .site-header .wrap { display: flex; justify-content: space-between; align-items: center; height: 72px; } .brand { display: flex; align-items: center; gap: 12px; font-family: var(--font-serif); font-size: 1.4rem; font-weight: 700; color: var(--primary-dark); } .main-nav ul { display: flex; list-style: none; gap: 28px; } .main-nav a { font-weight: 500; font-size: 0.98rem; color: var(--text-main); } .main-nav a:hover { color: var(--primary); } .hero { background: linear-gradient(135deg, var(--primary) 0%, var(--primary-dark) 100%); color: #FFFFFF; padding: 80px 0; text-align: center; } .hero-eyebrow { color: var(--accent); text-transform: uppercase; letter-spacing: 2px; font-size: 0.85rem; font-weight: 600; margin-bottom: 16px; } .hero h1 { font-family: var(--font-serif); font-size: 2.8rem; line-height: 1.2; margin-bottom: 20px; font-weight: 700; } .hero .lede { font-size: 1.15rem; max-width: 650px; margin: 0 auto 36px; color: var(--accent-light); opacity: 0.9; } .hero-search { max-width: 580px; margin: 0 auto; display: flex; gap: 8px; background: var(--surface); padding: 6px; border-radius: 50px; box-shadow: 0 10px 25px rgba(0,0,0,0.2); } .hero-search input { flex: 1; border: none; padding: 14px 24px; font-size: 1rem; outline: none; border-radius: 50px; background: transparent; color: var(--text-main); } .hero-search button { background: var(--accent); color: var(--primary-dark); border: none; padding: 0 32px; border-radius: 50px; font-weight: 600; font-size: 0.95rem; cursor: pointer; } .il-hero { background: var(--primary); color: #FFFFFF; position: relative; overflow: hidden; } .il-hero-media { position: relative; min-height: 340px; } .il-hero-svg { position: absolute; top: 0; left: 0; width: 100%; height: 100%; object-fit: cover; } .il-hero-overlay { position: relative; z-index: 2; padding: 60px 0; background: linear-gradient(to top, rgba(18, 36, 31, 0.95) 0%, rgba(31, 58, 52, 0.4) 100%); } .breadcrumb { font-size: 0.88rem; margin-bottom: 16px; } .badges { display: flex; gap: 10px; margin-bottom: 16px; } .badge { background: rgba(201, 162, 39, 0.25); color: var(--accent-light); border: 1px solid var(--accent); padding: 4px 12px; border-radius: 20px; font-size: 0.8rem; font-weight: 600; } .il-hero h1 { font-family: var(--font-serif); font-size: 2.6rem; margin-bottom: 12px; } .il-hero .lede { font-size: 1.1rem; max-width: 700px; color: var(--accent-light); } .section { padding: 60px 0; } .section-head { margin-bottom: 36px; } .section-head h2 { font-family: var(--font-serif); font-size: 1.9rem; color: var(--primary-dark); margin-bottom: 6px; } .section-head p { color: var(--text-muted); } .region-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); gap: 24px; } .region-card { background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius); padding: 24px; position: relative; box-shadow: var(--shadow-sm); } .region-card .count { position: absolute; top: 24px; right: 24px; font-size: 0.8rem; background: var(--bg); padding: 2px 10px; border-radius: 12px; color: var(--text-muted); font-weight: 600; } .region-card h3 { font-family: var(--font-serif); font-size: 1.3rem; margin-bottom: 16px; color: var(--primary); } .region-card ul { list-style: none; display: flex; flex-direction: column; gap: 8px; } .region-card li a { color: var(--text-main); font-size: 0.94rem; } .il-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(320px, 1fr)); gap: 24px; } .il-card { background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius); padding: 28px; display: flex; flex-direction: column; box-shadow: var(--shadow-sm); transition: transform 0.2s, box-shadow 0.2s; } .il-card:hover { transform: translateY(-4px); box-shadow: var(--shadow-md); } .plaka-badge { display: inline-flex; align-items: center; justify-content: center; width: 36px; height: 36px; background: var(--bg); border: 1px solid var(--border); border-radius: 8px; font-weight: 700; font-size: 0.9rem; color: var(--primary); margin-bottom: 16px; } .il-card h3 { font-family: var(--font-serif); font-size: 1.4rem; margin-bottom: 10px; color: var(--primary-dark); } .il-card p { color: var(--text-muted); font-size: 0.94rem; line-height: 1.55; margin-bottom: 20px; flex: 1; } .il-link { font-weight: 600; font-size: 0.92rem; color: var(--primary); display: inline-flex; align-items: center; gap: 6px; } .blog-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(320px, 1fr)); gap: 24px; } .blog-card { background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius); padding: 28px; display: flex; flex-direction: column; } .blog-card .tag { display: inline-block; font-size: 0.75rem; text-transform: uppercase; letter-spacing: 1px; color: var(--accent); font-weight: 700; margin-bottom: 12px; } .blog-card h3 { font-family: var(--font-serif); font-size: 1.25rem; margin-bottom: 12px; line-height: 1.4; } .blog-card h3 a { color: var(--primary-dark); } .blog-card p { color: var(--text-muted); font-size: 0.93rem; margin-bottom: 20px; flex: 1; } .content-grid { display: grid; grid-template-columns: 1fr 340px; gap: 48px; align-items: start; } .content-main article section { margin-bottom: 44px; } .content-main h2 { font-family: var(--font-serif); font-size: 1.7rem; color: var(--primary-dark); margin-bottom: 18px; border-bottom: 2px solid var(--border); padding-bottom: 10px; } .content-main h3 { font-size: 1.15rem; color: var(--primary); margin: 20px 0 8px; } .content-main p { margin-bottom: 16px; font-size: 1.02rem; } .tip-box { background: #FFFDF5; border-left: 4px solid var(--accent); padding: 18px 22px; border-radius: 0 var(--radius) var(--radius) 0; margin: 24px 0; } .tip-box strong { display: block; color: var(--primary-dark); margin-bottom: 6px; font-size: 0.92rem; text-transform: uppercase; } .info-list { list-style: none; display: flex; flex-direction: column; gap: 12px; margin-top: 12px; } .info-list li { position: relative; padding-left: 28px; } .info-list li::before { content: '→'; position: absolute; left: 0; color: var(--accent); font-weight: bold; } .sidebar { position: sticky; top: 96px; } .fact-box { background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius); padding: 24px; box-shadow: var(--shadow-sm); } .fact-box h3 { font-family: var(--font-serif); font-size: 1.15rem; color: var(--primary-dark); margin-bottom: 18px; padding-bottom: 10px; border-bottom: 1px solid var(--border); } .fact-box dl { display: grid; grid-template-columns: auto 1fr; gap: 12px 16px; font-size: 0.92rem; } .fact-box dt { color: var(--text-muted); } .fact-box dd { font-weight: 600; color: var(--primary); text-align: right; } .related-list { list-style: none; display: grid; grid-template-columns: repeat(2, 1fr); gap: 10px; } .related-list a { display: block; padding: 8px 12px; background: var(--bg); border-radius: 6px; font-size: 0.88rem; color: var(--text-main); text-align: center; } .related-list a:hover { background: var(--primary); color: #FFFFFF; } .simple-page { max-width: 780px; margin: 0 auto; background: var(--surface); padding: 48px; border-radius: var(--radius); border: 1px solid var(--border); box-shadow: var(--shadow-sm); } .simple-page h1 { font-family: var(--font-serif); font-size: 2.4rem; color: var(--primary-dark); margin-bottom: 24px; } .simple-page h2 { font-family: var(--font-serif); font-size: 1.4rem; color: var(--primary); margin: 32px 0 12px; } .simple-page p { margin-bottom: 16px; } .site-footer { background: var(--primary-dark); color: #FFFFFF; margin-top: auto; padding: 64px 0 32px; } .footer-grid { display: grid; grid-template-columns: 2fr 1fr 1fr; gap: 48px; margin-bottom: 48px; } .footer-grid h4 { color: var(--accent); font-size: 1.05rem; margin-bottom: 18px; } .footer-grid ul { list-style: none; display: flex; flex-direction: column; gap: 10px; } .footer-grid a { color: var(--accent-light); font-size: 0.92rem; opacity: 0.85; } .footer-grid a:hover { opacity: 1; color: #FFFFFF; } .footer-bottom { border-top: 1px solid rgba(255, 255, 255, 0.1); padding-top: 24px; display: flex; justify-content: space-between; font-size: 0.85rem; color: var(--accent-light); opacity: 0.7; } @media (max-width: 900px) { .content-grid { grid-template-columns: 1fr; } .sidebar { position: static; } .footer-grid { grid-template-columns: 1fr; gap: 32px; } } @media (max-width: 600px) { .hero h1 { font-size: 2.2rem; } .hero-search { flex-direction: column; border-radius: var(--radius); } .hero-search button { padding: 12px; border-radius: var(--radius); } .main-nav ul { gap: 14px; } .simple-page { padding: 24px; } .footer-bottom { flex-direction: column; gap: 8px; } } FILE # 8. assets/js/search.js cat << 'FILE' > assets/js/search.js document.addEventListener('DOMContentLoaded', () => { const params = new URLSearchParams(window.location.search); const initialQuery = params.get('q') || ''; const searchInput = document.getElementById('il-ara') || document.querySelector('.hero-search input'); const ilCards = document.querySelectorAll('.il-card'); function filterCards(query) { const q = query.toLocaleLowerCase('tr').trim(); ilCards.forEach(card => { const title = card.querySelector('h3').textContent.toLocaleLowerCase('tr'); const desc = card.querySelector('p').textContent.toLocaleLowerCase('tr'); const isMatch = title.includes(q) || desc.includes(q); card.style.display = isMatch ? 'flex' : 'none'; }); } if (searchInput && ilCards.length > 0) { if (initialQuery) { searchInput.value = initialQuery; filterCards(initialQuery); } searchInput.addEventListener('input', (e) => filterCards(e.target.value)); } }); FILE # 9. generate.js cat << 'FILE' > generate.js const fs = require('fs'); const path = require('path'); const SITE_URL = 'https://kesifatlasi.com'; const iller = require('./data/iller.json'); const root = __dirname; const bolgeSira = ['Marmara','Ege','Akdeniz','İç Anadolu','Karadeniz','Doğu Anadolu','Güneydoğu Anadolu']; const bolgeRenk = { 'Marmara':'#2E5E52', 'Ege':'#7A6B2E', 'Akdeniz':'#1F5A6B', 'İç Anadolu':'#6B4A2E', 'Karadeniz':'#1F3A34', 'Doğu Anadolu':'#4A3A6B', 'Güneydoğu Anadolu':'#6B2E2E' }; function heroSvg(il) { const c = bolgeRenk[il.bolge] || '#1F3A34'; const seed = il.slug.split('').reduce((a,ch)=>a+ch.charCodeAt(0),0); const off1 = 40 + (seed % 30); const off2 = 90 + (seed % 40); const off3 = 150 + (seed % 25); return ` ${il.plaka} `; } function relPrefix(canonicalPath) { const depth = canonicalPath.split('/').filter(Boolean).length - (canonicalPath.endsWith('/') ? 0 : 1); return depth > 0 ? '../'.repeat(depth) : './'; } function head(title, description, canonicalPath, extraJsonLd) { const p = relPrefix(canonicalPath); return ` ${title} ${extraJsonLd || ''} `; } function header(canonicalPath) { const p = relPrefix(canonicalPath); return ` `; } function footer(canonicalPath) { const p = relPrefix(canonicalPath); const year = new Date().getFullYear(); return ` `; } function page({title, description, canonicalPath, bodyHtml, jsonLd}) { return head(title, description, canonicalPath, jsonLd ? `` : '') + ` ${header(canonicalPath)}
${bodyHtml}
${footer(canonicalPath)} `; } function slugSort(list){ return [...list].sort((a,b)=>a.isim.localeCompare(b.isim,'tr')); } function buildIlPage(il) { const canonicalPath = `/iller/${il.slug}.html`; const sameRegion = iller.filter(x => x.bolge === il.bolge && x.slug !== il.slug); const related = slugSort(sameRegion).slice(0, 6); const gezilecekHtml = il.gezilecek.map((y,i) => `
  • ${y} — ${il.isim} gezisinde mutlaka görülmesi gereken önemli noktalardan biridir.
  • `).join('\n'); const lezzetHtml = il.lezzet.map(y => `
  • ${y}
  • `).join('\n'); const relatedHtml = related.map(r => `
  • ${r.isim}
  • `).join('\n'); const heroSvgMarkup = heroSvg(il); const bodyHtml = `
    ${heroSvgMarkup}
    Plaka: ${il.plaka} ${il.bolge} Bölgesi

    ${il.isim} Gezi Rehberi

    ${il.ozet}

    ${il.isim} Hakkında

    ${il.isim}, ${il.bolge} Bölgesi'nde yer alan ve plaka kodu ${il.plaka} olan bir ilimizdir. ${il.ozet}

    Gezi İpucu ${il.isim}'de zamanınız kısıtlıysa önce ${il.gezilecek[0]}'ü ziyaret edip günü ${il.lezzet[0]} tadarak kapatabilirsiniz.

    ${il.isim}'de Gezilecek Yerler

      ${gezilecekHtml}

    ${il.isim} Mutfağından Lezzetler

      ${lezzetHtml}

    Ne Zaman Gidilmeli?

    ${il.isim} için önerilen ziyaret dönemi ${il.en_iyi_zaman} olarak öne çıkmaktadır.

    `; return page({ title: `${il.isim} Gezi Rehberi | Keşif Atlası`, description: `${il.isim}: ${il.ozet}`, canonicalPath, bodyHtml }); } function buildIllerIndex() { const canonicalPath = '/iller/index.html'; const byRegion = {}; iller.forEach(il => { (byRegion[il.bolge] = byRegion[il.bolge] || []).push(il); }); const sections = bolgeSira.map(bolge => { const list = slugSort(byRegion[bolge] || []); if (list.length === 0) return ''; const cards = list.map(il => `
    ${il.plaka}

    ${il.isim}

    ${il.ozet}

    Rehberi oku →
    `).join('\n'); return `

    ${bolge} Bölgesi

    ${cards}
    `; }).filter(Boolean).join('\n'); const bodyHtml = `

    Türkiye'nin 81 İli

    Marmara'dan Doğu Anadolu'ya tüm illerin gezi rehberleri.

    ${sections}
    `; return page({ title: `Türkiye'nin 81 İli — Gezi Rehberleri | Keşif Atlası`, description: `Türkiye'nin illerine ait detaylı gezi rehberleri.`, canonicalPath, bodyHtml }); } function buildHome() { const canonicalPath = '/index.html'; const byRegion = {}; iller.forEach(il => { (byRegion[il.bolge] = byRegion[il.bolge] || []).push(il); }); const regionCards = bolgeSira.map(bolge => { const list = slugSort(byRegion[bolge] || []); if (list.length === 0) return ''; const items = list.slice(0,6).map(il => `
  • ${il.isim}
  • `).join(''); return `
    ${list.length} il

    ${bolge}

    `; }).filter(Boolean).join('\n'); const oneCikanCards = iller.slice(0, 6).map(il => `
    ${il.plaka}

    ${il.isim}

    ${il.ozet}

    Rehberi oku →
    `).join('\n'); const bodyHtml = `

    81 il, tek adres

    Türkiye'yi baştan sona keşfedin

    Kapadokya'nın peribacalarından Karadeniz'in yaylalarına, bağımsız gezi atlası.

    Bölgeler

    ${regionCards}

    Öne Çıkan Rehberler

    ${oneCikanCards}

    Blog'dan Son Yazılar

    `; return { canonicalPath, bodyHtml }; } fs.mkdirSync(path.join(root,'iller'), {recursive:true}); iller.forEach(il => { fs.writeFileSync(path.join(root,'iller',`${il.slug}.html`), buildIlPage(il)); }); fs.writeFileSync(path.join(root,'iller','index.html'), buildIllerIndex()); console.log(`✔ ${iller.length} il sayfası üretildi.`); module.exports = { page, header, footer, head, relPrefix, SITE_URL, bolgeSira, buildHome, iller }; FILE # 10. build-blog.js cat << 'FILE' > build-blog.js const fs = require('fs'); const path = require('path'); const { page, relPrefix } = require('./generate.js'); const posts = require('./data/blog.json'); const root = __dirname; function formatDate(isoStr) { const d = new Date(isoStr); return d.toLocaleDateString('tr-TR', { day: 'numeric', month: 'long', year: 'numeric' }); } function buildPostPage(post) { const canonicalPath = `/blog/${post.slug}.html`; const p = relPrefix(canonicalPath); const govdeHtml = post.govde.map(item => `

    ${item.h2}

    ${item.p}

    `).join('\n'); const bodyHtml = `
    ${post.etiket}

    ${post.baslik}

    Yayınlanma: ${formatDate(post.tarih)}

    ${govdeHtml}
    ← Tüm Blog Yazılarına Dön
    `; return page({ title: `${post.baslik} | Keşif Atlası Blog`, description: post.ozet, canonicalPath, bodyHtml }); } function buildBlogIndex() { const canonicalPath = '/blog/index.html'; const cards = posts.map(p => `
    ${p.etiket}

    ${p.baslik}

    ${p.ozet}

    ${formatDate(p.tarih)} Yazıyı oku →
    `).join('\n'); const bodyHtml = `

    Gezi Rehberi Blogu

    Rotanıza ilham verecek seyahat notları ve öneriler.

    ${cards}
    `; return page({ title: `Blog & Gezi Notları | Keşif Atlası`, description: `Seyahat ipuçları ve rotalar.`, canonicalPath, bodyHtml }); } fs.mkdirSync(path.join(root, 'blog'), { recursive: true }); posts.forEach(post => { fs.writeFileSync(path.join(root, 'blog', `${post.slug}.html`), buildPostPage(post)); }); fs.writeFileSync(path.join(root, 'blog', 'index.html'), buildBlogIndex()); console.log(`✔ ${posts.length} blog yazısı üretildi.`); module.exports = { posts, formatDate }; FILE # 11. build-pages.js cat << 'FILE' > build-pages.js const fs = require('fs'); const path = require('path'); const { page, buildHome, SITE_URL } = require('./generate.js'); const { posts } = require('./build-blog.js'); const iller = require('./data/iller.json'); const root = __dirname; const home = buildHome(); const latestPosts = posts.slice().sort((a,b)=> new Date(b.tarih)-new Date(a.tarih)).slice(0,3); const blogCardsHtml = latestPosts.map(p => `
    ${p.etiket}

    ${p.baslik}

    ${p.ozet}

    Yazıyı oku →
    `).join('\n'); const homeBody = home.bodyHtml.replace('', blogCardsHtml); fs.writeFileSync(path.join(root,'index.html'), page({ title: `Keşif Atlası — Türkiye'nin 81 İli Gezi Rehberi`, description: `Türkiye'nin illerini tarihi, mutfağı ve gezilecek yerleriyle keşfedin.`, canonicalPath: home.canonicalPath, bodyHtml: homeBody })); // Hakkımızda fs.writeFileSync(path.join(root,'hakkimizda.html'), page({ title: `Hakkımızda | Keşif Atlası`, description: `Keşif Atlası'nın hikayesi ve amacı.`, canonicalPath: '/hakkimizda.html', bodyHtml: `

    Hakkımızda

    Keşif Atlası, Türkiye'nin 81 ilini tek tek tanıtan bağımsız bir gezi rehberi platformudur.

    ` })); // İletişim fs.writeFileSync(path.join(root,'iletisim.html'), page({ title: `İletişim | Keşif Atlası`, description: `Bizimle iletişime geçin.`, canonicalPath: '/iletisim.html', bodyHtml: `

    İletişim

    Sorularınız için: info@kesifatlasi.com

    ` })); // Gizlilik Politikası fs.writeFileSync(path.join(root,'gizlilik-politikasi.html'), page({ title: `Gizlilik Politikası | Keşif Atlası`, description: `Gizlilik politikası.`, canonicalPath: '/gizlilik-politikasi.html', bodyHtml: `

    Gizlilik Politikası

    Sitemiz çerezler ve analitik araçlar kullanabilir.

    ` })); // Kullanım Şartları fs.writeFileSync(path.join(root,'kullanim-sartlari.html'), page({ title: `Kullanım Şartları | Keşif Atlası`, description: `Kullanım şartları.`, canonicalPath: '/kullanim-sartlari.html', bodyHtml: `

    Kullanım Şartları

    Sitedeki içerikler bilgilendirme amaçlıdır.

    ` })); // robots.txt fs.writeFileSync(path.join(root,'robots.txt'), `User-agent: *\nAllow: /\n\nSitemap: ${SITE_URL}/sitemap.xml\n`); // sitemap.xml const staticUrls = ['/', '/iller/index.html', '/blog/index.html', '/hakkimizda.html', '/iletisim.html', '/gizlilik-politikasi.html', '/kullanim-sartlari.html']; const ilUrls = iller.map(il => `/iller/${il.slug}.html`); const blogUrls = posts.map(p => `/blog/${p.slug}.html`); const allUrls = [...staticUrls, ...ilUrls, ...blogUrls]; const sitemap = ` ${allUrls.map(u => ` ${SITE_URL}${u}`).join('\n')} `; fs.writeFileSync(path.join(root,'sitemap.xml'), sitemap); console.log('✔ Tüm statik sayfalar, robots.txt ve sitemap.xml üretildi.'); FILE # 12. Derlemeyi çalıştır ./build.sh echo "" echo "🎉 Tebrikler! Tüm dosyalar oluşturuldu ve site başarıyla derlendi." EOF # Betiği çalıştır chmod +x setup.sh ./setup.sh