Webapp scripts and apps for fortune telling at the beginning of the year (Year of the Horse), wishing a Happy New Year and all your wishes come true.

📁 Project type: Google Sheets / WebApp
🛠 Technology: Google sheet, Apps script, Html, CSS
📅 Update: 12/02/2026
👨‍💻 Author: NetMedia CCTV

Introduce

🧧 LÌ XÌ 4.0 - KHÔNG LO TIỀN LẺ, CHỈ LO... BUG! 🧧 Tết Bính Ngọ 2026 sắp gõ cửa rồi! Năm nay kinh tế khó khăn, tiền mặt thì thiếu nhưng "code" thì mình có thừa. 😂 Ngồi buồn tay chân, mình (Admin NetMediaCCTV) có làm cái Web App nhỏ nhỏ: "Gieo Quẻ Đầu Năm". Không có tiền tươi thóc thật đâu, nhưng có những lời chúc "chất như nước cất" dành riêng cho anh em hệ kỹ thuật, văn phòng và cả... người qua đường. 👉 Mời bà con vào bốc quẻ lấy hên tại đây: [Dán Link Web App Của Bạn Vào Đây] 📌 Luật chơi: 1️⃣ Bấm vào link. 2️⃣ Bấm vào bao lì xì để xem vũ trụ gửi thông điệp gì. 3️⃣ Chụp màn hình quẻ của bạn và thả vào comment xem ai "số đỏ" nhất năm nay nhé! Ông nào bốc được quẻ "Bug tự fix, Lương tự tăng" thì nhớ khao cafe nha! ☕️ #Tet2026 #CodeLiXi #NetMediaCCTV #LapTrinhVui #GieoQueDauNam

Key features

  • Animation "Rung Lắc": Sử dụng CSS3 Animation tạo hiệu ứng bao lì xì rung lắc y như thật trước khi mở, tạo cảm giác hồi hộp cho người chơi.
  • Hiệu ứng Hoa Rơi (Particle Effect): Script JS nhẹ nhàng tạo mưa hoa mai/đào hoặc pháo giấy rơi ngẫu nhiên, giúp website không bị tĩnh mà rất sinh động.
  • Popup (Modal) Hiện Đại: Lời chúc xuất hiện dưới dạng thẻ nổi (Popup) sang trọng, tập trung sự chú ý vào nội dung.

Source code (Snippet)

Below is the main Apps Script code for processing the data:

/**
 * Hàm xử lý yêu cầu GET khi người dùng truy cập Web App
 */
function doGet() {
  // Tạo template từ file index.html
  var template = HtmlService.createTemplateFromFile('index');
  
  // Trả về giao diện, set tiêu đề và meta tag để hiển thị tốt trên điện thoại
  return template.evaluate()
      .setTitle('Gieo Quẻ Đầu Năm 2026 - NetMediaCCTV')
      .setSandboxMode(HtmlService.SandboxMode.IFRAME)
      .addMetaTag('viewport', 'width=device-width, initial-scale=1');
}

/**
 * Hàm lấy danh sách lời chúc (nếu muốn mở rộng load từ Google Sheet sau này)
 * Hiện tại ta xử lý trực tiếp bên client cho nhanh gọn.
 */
function logVisit() {
  // Có thể thêm code ghi log vào Google Sheet ở đây nếu cần thống kê ai đã vào
  Logger.log("Có người vừa truy cập gieo quẻ!");
}






<!DOCTYPE html>
<html>
  <head>
    <base target="_top">
    <link href="https://fonts.googleapis.com/css2?family=Dancing+Script:wght@700&family=Roboto:wght@400;500&display=swap" rel="stylesheet">
    <style>
      /* --- CSS Styles --- */
      :root {
        --tet-red: #d32f2f;
        --tet-gold: #ffeb3b;
        --dark-overlay: rgba(0,0,0,0.6);
      }

      body {
        margin: 0;
        padding: 0;
        background: linear-gradient(135deg, #8E0E00, #1F1C18);
        height: 100vh;
        display: flex;
        flex-direction: column;
        align-items: center;
        justify-content: center;
        font-family: 'Roboto', sans-serif;
        color: white;
        overflow: hidden;
        text-align: center;
      }

      h1 {
        font-family: 'Dancing Script', cursive;
        color: var(--tet-gold);
        font-size: 3rem;
        margin-bottom: 20px;
        text-shadow: 2px 2px 4px #000;
        z-index: 10;
      }

      /* Bao Lì Xì Styles */
      .lixi-container {
        cursor: pointer;
        position: relative;
        z-index: 10;
        transition: transform 0.2s;
      }
      
      .lixi-container:hover {
        transform: scale(1.05);
      }

      .lixi-body {
        width: 200px;
        height: 300px;
        background-color: var(--tet-red);
        border: 2px solid var(--tet-gold);
        border-radius: 10px;
        position: relative;
        box-shadow: 0 10px 20px rgba(0,0,0,0.5);
        display: flex;
        align-items: center;
        justify-content: center;
        flex-direction: column;
      }

      .lixi-flap {
        position: absolute;
        top: 0;
        width: 0; 
        height: 0; 
        border-left: 100px solid transparent;
        border-right: 100px solid transparent;
        border-top: 80px solid #b71c1c; /* Darker red */
        z-index: 2;
      }

      .chu-tet {
        font-family: 'Dancing Script', cursive;
        font-size: 4rem;
        color: var(--tet-gold);
        background: #b71c1c;
        width: 120px;
        height: 120px;
        border-radius: 50%;
        display: flex;
        align-items: center;
        justify-content: center;
        border: 2px solid var(--tet-gold);
      }

      .instruction {
        margin-top: 20px;
        font-size: 1.1rem;
        color: #eee;
        z-index: 10;
        animation: blink 2s infinite;
      }

      /* Animation Rung Lắc */
      .shake {
        animation: shake 0.5s cubic-bezier(.36,.07,.19,.97) both;
      }

      @keyframes shake {
        10%, 90% { transform: translate3d(-1px, 0, 0) rotate(-1deg); }
        20%, 80% { transform: translate3d(2px, 0, 0) rotate(2deg); }
        30%, 50%, 70% { transform: translate3d(-4px, 0, 0) rotate(-4deg); }
        40%, 60% { transform: translate3d(4px, 0, 0) rotate(4deg); }
      }

      @keyframes blink {
        0%, 100% { opacity: 1; }
        50% { opacity: 0.5; }
      }

      /* Modal Kết Quả */
      .modal {
        display: none;
        position: fixed;
        top: 0; left: 0;
        width: 100%; height: 100%;
        background-color: var(--dark-overlay);
        z-index: 100;
        justify-content: center;
        align-items: center;
        backdrop-filter: blur(5px);
      }

      .modal-content {
        background: white;
        color: #b71c1c;
        padding: 30px;
        border-radius: 15px;
        width: 80%;
        max-width: 400px;
        text-align: center;
        box-shadow: 0 0 20px var(--tet-gold);
        animation: popUp 0.3s ease-out;
        border: 2px solid var(--tet-gold);
      }

      .wish-text {
        font-size: 1.3rem;
        margin: 20px 0;
        line-height: 1.5;
        font-weight: 500;
      }

      .btn-close {
        background-color: var(--tet-red);
        color: white;
        border: none;
        padding: 10px 20px;
        font-size: 1rem;
        border-radius: 20px;
        cursor: pointer;
        font-weight: bold;
      }
      
      .btn-close:hover {
        background-color: #b71c1c;
      }

      @keyframes popUp {
        from { transform: scale(0); opacity: 0; }
        to { transform: scale(1); opacity: 1; }
      }

      /* Footer */
      .footer {
        position: absolute;
        bottom: 10px;
        font-size: 0.8rem;
        color: #aaa;
        z-index: 10;
      }

    </style>
  </head>
  <body>

    <h1>Gieo Quẻ Đầu Năm</h1>

    <div class="lixi-container" id="lixiBtn" onclick="openLixi()">
      <div class="lixi-body">
        <div class="lixi-flap"></div>
        <div class="chu-tet">Tết</div>
      </div>
    </div>

    <div class="instruction">👇 Bấm vào bao lì xì để nhận quẻ! 👇</div>

    <div class="modal" id="resultModal">
      <div class="modal-content">
        <h2 style="color: #d32f2f; margin-top: 0;">🎉 Quẻ của bạn 🎉</h2>
        <div class="wish-text" id="wishContent">...</div>
        <button class="btn-close" onclick="closeModal()">Nhận Lộc</button>
      </div>
    </div>

    <div class="footer">Dev by NetMediaCCTV | Xuân Bính Ngọ 2026</div>

    <script>
      // --- Dữ Liệu Lời Chúc (Có thể thêm/sửa tùy ý) ---
      const loiChuc = [
        "Năm mới code 'một phát ăn ngay', không warning, không error!",
        "Render video tốc độ ánh sáng, khách duyệt ngay lần đầu.",
        "Sóng livestream căng đét, tín hiệu mượt mà, không drop frame nào.",
        "Tiền về tài khoản: Ting! Ting! Ting! Ngập tràn hạnh phúc.",
        "Server đời đời ấm no, băng thông rộng mở, KPI đạt đỉnh.",
        "Sức khỏe dẻo dai như cáp quang biển, tinh thần thép như tường lửa.",
        "Vợ hiền con ngoan, gia đình êm ấm, hậu phương vững chắc.",
        "Bug tự fix, deadline tự dời, lương tự tăng!",
        "Tâm bất biến giữa dòng đời vạn biến, nhưng biến nào cũng debug được."
      ];

      const lixiBtn = document.getElementById('lixiBtn');
      const modal = document.getElementById('resultModal');
      const wishContent = document.getElementById('wishContent');

      function openLixi() {
        // 1. Thêm class rung lắc
        lixiBtn.classList.add('shake');

        // 2. Chờ hiệu ứng rung xong (500ms) thì hiện kết quả
        setTimeout(() => {
          lixiBtn.classList.remove('shake');
          showWish();
        }, 500);
      }

      function showWish() {
        // Chọn ngẫu nhiên lời chúc
        const randomWish = loiChuc[Math.floor(Math.random() * loiChuc.length)];
        
        // Gán nội dung và hiện modal
        wishContent.innerText = randomWish;
        modal.style.display = 'flex';
      }

      function closeModal() {
        modal.style.display = 'none';
      }

      // --- Hiệu ứng Hoa Rơi (Đơn giản bằng JS tạo thẻ div) ---
      function createPetal() {
        const petal = document.createElement('div');
        petal.style.position = 'fixed';
        petal.style.top = '-10px';
        petal.style.left = Math.random() * 100 + 'vw';
        petal.style.width = '10px';
        petal.style.height = '10px';
        petal.style.backgroundColor = Math.random() > 0.5 ? '#ffeb3b' : '#ffcdd2'; // Vàng hoặc hồng nhạt
        petal.style.borderRadius = '50% 0 50% 0';
        petal.style.opacity = Math.random();
        petal.style.zIndex = '1';
        petal.style.transform = `rotate(${Math.random() * 360}deg)`;
        
        // Animation rơi
        const duration = Math.random() * 3 + 2; // 2s đến 5s
        petal.style.transition = `top ${duration}s linear, opacity ${duration}s ease-out`;
        
        document.body.appendChild(petal);

        // Kích hoạt animation
        setTimeout(() => {
          petal.style.top = '105vh';
          petal.style.opacity = '0';
        }, 50);

        // Xóa thẻ sau khi rơi xong
        setTimeout(() => {
          petal.remove();
        }, duration * 1000);
      }

      // Tạo hoa rơi liên tục mỗi 300ms
      setInterval(createPetal, 300);

    </script>
  </body>
</html>

Post a Comment

Previous Post Next Post