Category: Uncategorized

  • GS25 오늘의 운세

    :root{
    –gs-sky:#28B5F5; –gs-deep:#0FA3E1; –gs-orange:#FF7A00;
    –ink:#1f2937; –muted:#6b7280; –bg:#f6fbff; –card:#fff; –ring:rgba(40,181,245,.35);
    }
    *{box-sizing:border-box}
    html,body{margin:0;background:var(–bg);color:var(–ink);font-family:-apple-system,Segoe UI,Roboto,Pretendard,system-ui,sans-serif}
    .container{max-width:760px;margin:24px auto;padding:16px}
    .header{display:flex;align-items:center;gap:10px;margin-bottom:12px}
    .logo .gs{font-weight:800;font-size:24px}
    .logo .n25{font-weight:900;font-size:26px;color:var(–gs-sky)}
    .card{background:var(–card);border-radius:16px;border:1px solid rgba(15,163,225,.15);box-shadow:0 6px 18px rgba(15,163,225,.08);overflow:hidden}
    .hero{background:linear-gradient(135deg,var(–gs-sky),var(–gs-deep));color:#fff;padding:20px}
    .hero h1{margin:0 0 6px 0;font-size:22px}
    .hero p{margin:0;opacity:.95}
    .body{padding:16px}
    .badge{margin-left:auto;font-size:12px;color:var(–muted)}

    .pickers{display:grid;grid-template-columns:repeat(4,1fr);gap:10px}
    @media (max-width:640px){.pickers{grid-template-columns:repeat(2,1fr)}}
    .label{font-size:12px;color:var(–muted);margin:6px 0 2px 4px}
    .wheel{height:160px;overflow-y:auto;scroll-snap-type:y mandatory;background:#fff;border:1px solid #e5e7eb;border-radius:12px;position:relative}
    .wheel::-webkit-scrollbar{width:6px}
    .wheel::-webkit-scrollbar-thumb{background:#e5e7eb;border-radius:6px}
    .item{height:40px;display:flex;align-items:center;justify-content:center;scroll-snap-align:center;color:#374151}
    .item.sel{font-weight:800;color:#111}
    .highlight{position:absolute;left:6px;right:6px;top:calc(50% – 20px);height:40px;border-radius:10px;border:1px dashed rgba(15,163,225,.4);background:rgba(40,181,245,.06);pointer-events:none}

    .nameRow{display:flex;gap:8px;margin:12px 0}
    .nameRow input{flex:1;border:1px solid #e5e7eb;border-radius:12px;padding:12px 14px;font-size:15px;outline:none}
    .nameRow input:focus{border-color:var(–gs-sky);box-shadow:0 0 0 4px var(–ring)}
    .btnRow{display:flex;gap:8px;justify-content:flex-end}
    .btn{background:var(–gs-orange);color:#fff;border:0;border-radius:12px;padding:12px 16px;font-weight:800;cursor:pointer;box-shadow:0 6px 16px rgba(255,122,0,.2);transition:.15s}
    .btn.secondary{background:#fff;color:var(–gs-deep);border:1px solid rgba(15,163,225,.35);box-shadow:none}
    .btn:hover{transform:translateY(-1px)}

    .grid{display:grid;grid-template-columns:repeat(2,1fr);gap:10px;margin-top:12px}
    @media (max-width:640px){.grid{grid-template-columns:1fr}}
    .tile{border:1px solid #e5e7eb;border-radius:14px;padding:12px;background:#fff}
    .tile h3{margin:0 0 6px 0;font-size:14px;color:var(–muted);font-weight:700}
    .tile .val{font-size:16px;font-weight:800}
    .kv{display:flex;align-items:center;gap:8px}
    .kv .dot{width:14px;height:14px;border-radius:50%}
    .small{font-size:12px;color:var(–muted);margin-top:8px}

    오늘의 운세 (출생 연·월·일·시)

    휠에서 출생 정보를 고르고 이름을 입력한 뒤 운세 보기 버튼을 눌러보세요.

    출생 연도
    월
    일
    시간

    총운

    —
    —

    키워드

    —

    사랑/인연

    —

    금전/재물

    —

    일/사업

    —

    건강

    —

    럭키 아이템

    —

    럭키 컬러

    —

    럭키 넘버

    —

    럭키 타임

    —

    프로필

    —
    ※ 같은 출생 정보와 같은 날에는 결과가 고정됩니다. (API 시드 기반)

    // === 설정 ===
    const API_BASE = “https://gs25deocksu-fortune.t01040454570.workers.dev/api/fortune”;

    // 날짜 표시
    document.getElementById(“today”).textContent =
    new Date().toLocaleDateString(“ko-KR”,{year:”numeric”,month:”long”,day:”numeric”,weekday:”short”});

    // 휠 빌더
    function buildWheel(el, items, unit, selected){
    el.innerHTML = ‘

    ‘;
    items.forEach(v=>{
    const d=document.createElement(“div”);
    d.className=”item”; d.dataset.value=v; d.textContent=unit?`${v}${unit}`:v;
    el.appendChild(d);
    });
    const idx=Math.max(0, items.indexOf(selected));
    el.scrollTop = idx*40;
    el.addEventListener(“scroll”, ()=>{ clearTimeout(el._t); el._t=setTimeout(()=>snapTo(el),80); });
    snapTo(el);
    }
    function snapTo(el){
    const i = Math.round(el.scrollTop/40);
    el.scrollTo({ top:i*40, behavior:”smooth” });
    […el.querySelectorAll(“.item”)].forEach((n,ix)=> n.classList.toggle(“sel”, ix===i));
    }
    function getSelected(el){
    const i = Math.round(el.scrollTop/40);
    const items=[…el.querySelectorAll(“.item”)];
    return parseInt(items[i]?.dataset.value || items[0].dataset.value,10);
    }

    // 데이터
    const yearWheel = document.getElementById(“wheel-year”);
    const monthWheel= document.getElementById(“wheel-month”);
    const dayWheel = document.getElementById(“wheel-day”);
    const hourWheel = document.getElementById(“wheel-hour”);
    const now = new Date();
    const YEARS = Array.from({length:100},(_,i)=> now.getFullYear()-i);
    const MONTHS= Array.from({length:12},(_,i)=> i+1);
    function daysIn(y,m){ return new Date(y,m,0).getDate(); }
    function rebuildDays(){
    const y=getSelected(yearWheel), m=getSelected(monthWheel);
    const D=daysIn(y,m), cur=Math.min(getSelected(dayWheel)||1, D);
    buildWheel(dayWheel, Array.from({length:D},(_,i)=>i+1), “일”, cur);
    }

    // 초기화
    buildWheel(yearWheel, YEARS, “년”, now.getFullYear());
    buildWheel(monthWheel, MONTHS, “월”, now.getMonth()+1);
    rebuildDays();
    buildWheel(hourWheel, Array.from({length:24},(_,i)=>i), “시”, 9);
    [“wheel-year”,”wheel-month”].forEach(id=>{
    const el=document.getElementById(id);
    el.addEventListener(“scroll”, ()=>{ clearTimeout(el._re); el._re=setTimeout(rebuildDays,120); });
    });

    // API 호출
    async function fetchFortune(){
    const y=getSelected(yearWheel), m=getSelected(monthWheel), d=getSelected(dayWheel), h=getSelected(hourWheel);
    const name=document.getElementById(“name”).value.trim();
    const params = new URLSearchParams({ y,m,d,h, tz:”Asia/Seoul”, lang:”ko” });
    if (name) params.set(“name”, name);

    const res = await fetch(`${API_BASE}?${params.toString()}`, { cache:”no-store” });
    const j = await res.json();
    if (j.error) throw new Error(j.error);

    // 바인딩
    byId(“overall”).textContent = j.overall;
    byId(“tip”).textContent = j.tip;
    byId(“love”).textContent = j.love;
    byId(“money”).textContent = j.money;
    byId(“work”).textContent = j.work;
    byId(“health”).textContent = j.health;
    byId(“item”).textContent = j.item;
    byId(“colorDot”).style.background = j.color.hex;
    byId(“colorName”).textContent = `${j.color.name} (${j.color.hex})`;
    byId(“number”).textContent = j.number;
    byId(“time”).textContent = j.time;
    byId(“keywords”).textContent= j.keywords.join(” · “);
    byId(“profile”).textContent = `서양 별자리: ${j.profile.western} / 띠: ${j.profile.zodiac} / 시지: ${j.profile.hourSign}`;
    }
    function byId(id){ return document.getElementById(id); }

    document.getElementById(“btnGo”).addEventListener(“click”, async ()=>{
    try{ await fetchFortune(); } catch(e){ alert(“운세 호출 실패: “+e.message); }
    });
    document.getElementById(“btnCopy”).addEventListener(“click”, ()=>{
    const t=[
    `🌟 GS25 오늘의 운세 (${document.getElementById(‘today’).textContent})`,
    `총운: ${byId(‘overall’).textContent}`,
    `Tip: ${byId(‘tip’).textContent}`,
    `사랑: ${byId(‘love’).textContent}`,
    `금전: ${byId(‘money’).textContent}`,
    `일: ${byId(‘work’).textContent}`,
    `건강: ${byId(‘health’).textContent}`,
    `아이템: ${byId(‘item’).textContent}`,
    `컬러: ${byId(‘colorName’).textContent}`,
    `넘버: ${byId(‘number’).textContent}`,
    `럭키 타임: ${byId(‘time’).textContent}`,
    `키워드: ${byId(‘keywords’).textContent}`,
    `프로필: ${byId(‘profile’).textContent}`
    ].join(“n”);
    navigator.clipboard.writeText(t).then(()=> alert(“운세를 복사했어요!”));
    });