# ╔══════════════════════════════════════════════════════════════════╗ # ║ ANKET — KabaLang ile canlı anket ║ # ║ ║ # ║ · Oy: POST /oy/{id} — gövdesiz form, kimlik yolda ║ # ║ · Aynı adresten ikinci oy veritabanı kısıtıyla engellenir ║ # ║ · Sonuç grafiği sunucuda KabaLang ile SVG olarak çizilir ║ # ║ · /sonuc.svg tek başına gömülebilir · /api/sonuclar JSON ║ # ╚══════════════════════════════════════════════════════════════════╝ # # Çalıştır: kabalang calistir web/anket/anket.kbl # Aç: http://127.0.0.1:8473 kullan kaba.web kullan kaba.json kullan kaba.veritabani kullan kaba.sistem SORU = "Bir sonraki KabaLang örneği ne olsun?" PORT = 8473 # Barındıran ortam (ör. Online IDE) portu PORT ortam değişkeniyle verir. port_ortam = cevre.al("PORT") eger port_ortam != "": PORT = sayi(port_ortam) db = cevre.al("ANKET_DB") eger db == "": db = "anket.db" yapi Secenek: kimlik: sayi = 0 ad: metin = "" renk: metin = "" oy: sayi = 0 # ── Veritabanı ────────────────────────────────────────────────────── fonksiyon hazirla(db): # `adres UNIQUE`: aynı istemciden ikinci oy veritabanı düzeyinde reddedilir. veritabani.sqlite(db, "CREATE TABLE IF NOT EXISTS secenek(id INTEGER PRIMARY KEY, ad TEXT, renk TEXT); CREATE TABLE IF NOT EXISTS oy(secenek INTEGER, adres TEXT UNIQUE, zaman TEXT);") eger veritabani.sqlite(db, "SELECT count(*) FROM secenek") != "0": don 0 adlar = ["2B oyun", "Yapay zekâ asistanı", "Veri panosu", "Sohbet uygulaması", "Sistem servisi"] renkler = ["#377ef4", "#22d3ee", "#a78bfa", "#34d399", "#fbbf24"] ornek_oy = [18, 27, 12, 21, 7] dongu i icinde 0..adlar.uzunluk() - 1: veritabani.sqlite(db, "INSERT INTO secenek(id, ad, renk) VALUES (?, ?, ?)", [metin(i + 1), adlar[i], renkler[i]]) # Tanıtım için önceden verilmiş oylar (adres alanı uydurma ve benzersiz). dongu n icinde 1..ornek_oy[i]: veritabani.sqlite(db, "INSERT INTO oy(secenek, adres, zaman) VALUES (?, ?, datetime('now', 'localtime'))", [metin(i + 1), "ornek-" + metin(i) + "-" + metin(n)]) don 1 fonksiyon secenekler(db) -> liste: sonuc = [Secenek()] sonuc.sil(0) ham = veritabani.sqlite(db, "SELECT s.id, s.renk, (SELECT count(*) FROM oy WHERE oy.secenek = s.id), s.ad FROM secenek s ORDER BY s.id") dongu satir icinde ham.bol("\n"): p = satir.bol("|") sonuc.ekle(Secenek(sayi(p[0]), p.dilim(3, p.uzunluk() - 3).birlestir("|"), p[1], sayi(p[2]))) don sonuc fonksiyon toplam_oy(liste): t = 0 dongu s icinde liste: t = t + s.oy don t fonksiyon verdigi_oy(db, adres): don veritabani.sqlite(db, "SELECT secenek FROM oy WHERE adres = ?", [adres]) # ── SVG grafik: tamamen KabaLang ile ──────────────────────────────── # `gen`: çizim genişliği. Sayfa aynı grafiği iki genişlikte üretir # (masaüstü / telefon) ki yazılar küçülmesin. fonksiyon grafik_svg(liste, isaretli, gen): toplam = toplam_oy(liste) eger toplam == 0: toplam = 1 # Çubuk boyu en çok oy alana göre ölçeklenir: lider tam dolar. en_cok = 1 dongu sec icinde liste: eger sec.oy > en_cok: en_cok = sec.oy satir_yuk = 64 yuk = liste.uzunluk() * satir_yuk + 10 s = "" i = 0 dongu sec icinde liste: y = i * satir_yuk + 8 yuzde = sec.oy * 100 // toplam cubuk = (gen - 120) * sec.oy // en_cok eger cubuk < 6: cubuk = 6 kalinlik = "500" eger metin(sec.kimlik) == isaretli: kalinlik = "800" # Ad metni kullanıcıdan gelmiyor ama yine de kaçırılır: alışkanlık. s = s + "" + web.kacir(sec.ad) + "" s = s + "" s = s + "" s = s + "%" + metin(yuzde) + "" s = s + "" + metin(sec.oy) + "" i = i + 1 don s + "" # ── Sayfa iskeleti ────────────────────────────────────────────────── STIL = """ :root { --zemin:#0a0d15; --yuzey:#121826; --yuzey2:#182033; --cizgi:#232c42; --metin:#e6ebf5; --soluk:#8a94ab; --mavi:#377ef4; --cam:#22d3ee; } * { box-sizing: border-box; } body { margin:0; min-height:100vh; color:var(--metin); font:15px/1.55 Inter, system-ui, -apple-system, "Segoe UI", sans-serif; background: radial-gradient(800px 460px at 20% -10%, #377ef430, transparent 60%), radial-gradient(700px 420px at 90% 110%, #a78bfa22, transparent 60%), var(--zemin); display:grid; place-items:center; padding: 32px 16px; } .kart { width: 100%; max-width: 820px; background: #121826e6; border:1px solid var(--cizgi); border-radius: 24px; padding: 34px 38px; box-shadow: 0 30px 80px #0009; } .ust { display:flex; align-items:center; gap:10px; color: var(--soluk); font-size: 13px; margin-bottom: 18px; } .canli { display:inline-flex; align-items:center; gap:7px; color:#34d399; margin-left:auto; } .canli::before { content:''; width:8px; height:8px; border-radius:50%; background:#34d399; box-shadow:0 0 0 4px #34d39928; } h1 { font-size: clamp(24px, 4vw, 34px); line-height: 1.15; letter-spacing: -.02em; margin: 0 0 24px; } .secenekler { display:grid; gap: 10px; } .secenekler form { margin:0; } .secenekler button { width:100%; display:flex; align-items:center; gap:14px; text-align:left; font:inherit; font-size:16px; color: var(--metin); background: var(--yuzey2); border:1px solid var(--cizgi); border-radius: 14px; padding: 15px 18px; cursor:pointer; transition: border-color .15s, transform .15s; } .secenekler button:hover { border-color: var(--mavi); transform: translateX(4px); } .top { width: 14px; height: 14px; border-radius: 50%; flex: none; } .alt { display:flex; justify-content: space-between; color: var(--soluk); font-size: 13px; margin-top: 22px; flex-wrap: wrap; gap: 8px; } .alt a { color: var(--cam); text-decoration:none; } .bilgi { background: #377ef414; border:1px solid #377ef444; color:#bcd3ff; border-radius: 12px; padding: 10px 14px; margin-bottom: 20px; font-size: 14px; } svg { width:100%; height:auto; display:block; } .dar { display: none; } @media (max-width: 600px) { .kart { padding: 24px 18px; border-radius: 20px; } .genis { display: none; } .dar { display: block; } } """ fonksiyon sayfa(govde, yenile): ek = "" eger yenile: # "Canlı": sonuç sayfası 5 saniyede bir kendini tazeler. ek = "" don "" + ek + "Anket · KabaLang
" + govde + "
" fonksiyon ust_bant(toplam): don "
KabaLang Anket · " + metin(toplam) + " oycanlı
" # ── Uçlar ─────────────────────────────────────────────────────────── hazirla(db) fonksiyon sonuc_sayfasi(istek): liste = secenekler(db) benim = verdigi_oy(db, istek.adres()) g = ust_bant(toplam_oy(liste)) + "

" + web.kacir(SORU) + "

" eger istek.sorgu("zaten") == "1": g = g + "
Bu adresten zaten oy verilmiş — ikinci oy sayılmadı.
" degilse eger benim != "": g = g + "
✓ Oyunuz kaydedildi. Sonuçlar 5 saniyede bir tazelenir.
" g = g + "
" + grafik_svg(liste, benim, 760) + "
" g = g + "
" + grafik_svg(liste, benim, 380) + "
" g = g + "
Grafik sunucuda KabaLang ile çizildi · sonuc.svg · JSON← ankete dön
" don web.html(sayfa(g, dogru)) fonksiyon ana_sayfa(istek): # Daha önce oy verdiyse doğrudan sonuçları göster. eger verdigi_oy(db, istek.adres()) != "": don sonuc_sayfasi(istek) liste = secenekler(db) g = ust_bant(toplam_oy(liste)) + "

" + web.kacir(SORU) + "

" dongu s icinde liste: g = g + "
" g = g + "
Her adres bir kez oy verebilir.sonuçları gör →
" don web.html(sayfa(g, yanlis)) fonksiyon oy_ver(istek): kimlik = istek.parametre("id") # Kimlik gerçekten var olan bir seçenek mi? (parametre bağlamalı) eger veritabani.sqlite(db, "SELECT count(*) FROM secenek WHERE id = ?", [kimlik]) != "1": don web.html(sayfa("

Böyle bir seçenek yok

← ankete dön
", yanlis), 404) adres = istek.adres() eger verdigi_oy(db, adres) != "": don web.yanit("", 303).baslik("Location", "/sonuc?zaten=1") veritabani.sqlite(db, "INSERT OR IGNORE INTO oy(secenek, adres, zaman) VALUES (?, ?, datetime('now', 'localtime'))", [kimlik, adres]) # POST → 303 → GET: sayfa yenilenince oy ikinci kez gönderilmez. don web.yanit("", 303).baslik("Location", "/sonuc") fonksiyon sonuc_svg(istek): don web.yanit(grafik_svg(secenekler(db), verdigi_oy(db, istek.adres()), 760)).tip("image/svg+xml; charset=utf-8") fonksiyon sonuc_json(_istek): don web.json(veritabani.sqlite(db, "SELECT json_object('soru', ?, 'toplam', (SELECT count(*) FROM oy), 'secenekler', (SELECT json_group_array(json_object('id', s.id, 'ad', s.ad, 'oy', (SELECT count(*) FROM oy WHERE oy.secenek = s.id))) FROM secenek s))", [SORU])) # Tek iş parçacığı: "oy verdi mi?" denetimi ile kayıt arasında yarış olmasın. sunucu = web.sunucu(PORT, "127.0.0.1", 1) sunucu.al("/", ana_sayfa) sunucu.al("/sonuc", sonuc_sayfasi) sunucu.al("/sonuc.svg", sonuc_svg) sunucu.al("/api/sonuclar", sonuc_json) sunucu.gonder("/oy/{id}", oy_ver) yazdir("🗳 Anket hazır — http://127.0.0.1:" + metin(PORT)) sunucu.basla()