Skip to content

cs256306-netizen/web2

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 

Repository files navigation

<title>Team Spade - 가상 베팅 사이트 (발표 자료)</title> <script src="https://cdn.tailwindcss.com"></script>
<style>
    /* --- CSS 스타일 --- */
    :root {
        --accent-color: #A855F7; /* Violet-500: 강조색 */
        --bg-dark: #121212; /* 배경 */
        --card-bg: #1F1F1F; /* 카드 배경 */
    }
    body {
        font-family: 'Inter', 'Noto Sans KR', sans-serif;
        background-color: var(--bg-dark);
        color: #E0E0E0;
        display: flex;
        justify-content: center;
        align-items: flex-start; /* 콘텐츠를 상단에 배치 */
        min-height: 100vh;
        padding: 20px; /* PC/태블릿 환경에서 적절한 여백 */
        box-sizing: border-box;
    }
    
    /* 앱 컨테이너: PC/태블릿 환경을 위해 최대 너비를 700px로 증가 */
    .app-container {
        max-width: 700px; /* PC/태블릿에서 더 넓게 */
        width: 100%;
        background: var(--bg-dark);
        border-radius: 20px;
        box-shadow: 0 10px 25px rgba(0, 0, 0, 0.5);
        padding: 24px;
        margin-top: 40px; /* 상단 여백 추가 */
        margin-bottom: 40px; /* 하단 여백 추가 */
    }

    /* 미디어 쿼리: 작은 화면 (모바일)에서 상/하단 여백 줄이고, 최대 너비 제거(화면 꽉 채움) */
    @media (max-width: 480px) {
        body {
            padding: 0; /* 모바일에서 좌우 패딩 제거 */
        }
        .app-container {
            max-width: none; /* 모바일에서 최대 너비 제한 제거 */
            min-height: 100vh; /* 모바일에서 세로 꽉 채움 */
            border-radius: 0;
            margin: 0;
        }
    }
    
    /* 이하 기존 스타일 유지 */
    .fade-in-out {
        opacity: 0;
        transform: translateY(10px);
        animation: fadeIn 0.5s forwards;
    }
    @keyframes fadeIn {
        to { opacity: 1; transform: translateY(0); }
    }

    .click-effect {
        transition: transform 0.1s ease;
    }
    .click-effect:active {
        transform: scale(0.98);
    }

    .hype-text {
        font-size: 2.5rem;
        font-weight: 800;
        color: var(--accent-color);
        position: absolute;
        top: 50%;
        left: 50%;
        transform: translate(-50%, -50%);
        opacity: 0;
        white-space: nowrap;
    }

    .spade-icon::before {
        content: '\2660'; 
        line-height: 1;
    }
    .choice-icon {
        font-family: 'Inter', sans-serif;
        font-weight: 900;
        color: var(--accent-color);
        display: block;
    }

    .choice-card {
        background-color: var(--card-bg);
        border: 2px solid #333;
        padding: 20px;
        border-radius: 15px;
        cursor: pointer;
        transition: all 0.2s ease-in-out;
        text-align: center;
    }
    .choice-card:hover {
        border-color: var(--accent-color);
        transform: translateY(-5px);
        box-shadow: 0 5px 15px rgba(168, 85, 247, 0.3);
    }
    .choice-card.selected {
        border-color: #4ADE80; /* Green */
        box-shadow: 0 0 20px rgba(74, 222, 128, 0.5);
        transform: scale(1.05);
    }

    .fade-out {
        opacity: 0 !important;
        transform: translateY(10px) !important;
        transition: opacity 0.3s, transform 0.3s;
    }

    #loginScreen .app-container {
        animation: none; 
        box-shadow: 0 20px 50px rgba(0, 0, 0, 0.7);
        margin: auto; /* 중앙 정렬 유지 */
    }
    #loginScreen {
        padding: 20px;
    }
</style>

팀 스페이드 (TEAM SPADE)

    <h2 class="text-xl font-bold mb-6 text-gray-300 text-center">계정 접속</h2>
    
    <input type="text" id="userId" placeholder="아이디" class="w-full p-4 bg-zinc-800 rounded-lg mb-4 text-white focus:outline-none focus:ring-2 focus:ring-violet-500 border border-transparent hover:border-violet-500 transition">
    <input type="password" id="userPin" placeholder="PIN 번호 (4자리 이상)" maxlength="4" class="w-full p-4 bg-zinc-800 rounded-lg mb-6 text-white focus:outline-none focus:ring-2 focus:ring-violet-500 border border-transparent hover:border-violet-500 transition">

    <button id="loginButton" class="w-full py-4 bg-violet-600 hover:bg-violet-700 text-white font-extrabold rounded-xl transition-all click-effect shadow-violet-500/50 shadow-lg">
        접속하기
    </button>
    <p class="text-xs text-center mt-4 text-gray-500">발표 자료용 가상 로그인 (PIN: 1234)</p>
</div>

팀 스페이드 (TEAM SPADE)

50,000 RBX

잔액 (가상)

<main id="mainGame" class="fade-in-out" style="animation-delay: 0.1s;">
    <h2 class="text-3xl font-extrabold mb-8 text-center">가위바위보 활동 💰</h2> <div class="p-5 bg-zinc-800 rounded-xl mb-6 shadow-lg">
        <label for="betAmount" class="block text-sm font-semibold mb-2 text-gray-300">활동 금액 (RBX)</label> <div class="flex items-center">
            <input type="number" id="betAmount" value="1000" min="1000" step="1000" class="w-full text-2xl p-2 bg-transparent border-b-2 border-violet-500 focus:outline-none focus:border-violet-300 transition-colors click-effect text-white">
            <span class="text-xl ml-2 text-violet-400">RBX</span>
        </div>
        <p class="text-xs text-red-400 mt-2 hidden" id="balanceError">잔액이 부족합니다.</p>
    </div>

    <div id="choiceSelection" class="grid grid-cols-3 gap-4 mb-8">
        <div class="choice-card click-effect fade-in-out" data-choice="rock" style="animation-delay: 0.2s;">
            <span class="text-5xl choice-icon">R</span>
            <p class="font-bold mt-2">바위</p>
        </div>
        <div class="choice-card click-effect fade-in-out" data-choice="scissors" style="animation-delay: 0.3s;">
            <span class="text-5xl choice-icon">S</span>
            <p class="font-bold mt-2">가위</p>
        </div>
        <div class="choice-card click-effect fade-in-out" data-choice="paper" style="animation-delay: 0.4s;">
            <span class="text-5xl choice-icon">P</span>
            <p class="font-bold mt-2">보</p>
        </div>
    </div>

    <div class="text-center">
        <button id="betButton" class="w-full py-4 bg-violet-600 hover:bg-violet-700 text-white font-extrabold rounded-xl transition-all click-effect shadow-violet-500/50 shadow-lg" disabled>
            활동할 선택지를 고르세요
        </button> <p id="resultMessage" class="mt-4 text-lg font-semibold text-center hidden"></p>
    </div>

</main>

RBX 송금/잔액 확인 (가상)

현재 잔액: 50,000 RBX

    <label for="transferId" class="block text-sm font-semibold mb-1 text-gray-300">받는 사람 ID</label>
    <input type="text" id="transferId" placeholder="ID를 입력하세요" class="w-full p-3 bg-zinc-700 rounded-lg mb-4 text-white focus:outline-none focus:ring-2 focus:ring-violet-500">
    
    <label for="transferAmount" class="block text-sm font-semibold mb-1 text-gray-300">송금 금액 (RBX)</label>
    <input type="number" id="transferAmount" value="0" min="1" class="w-full p-3 bg-zinc-700 rounded-lg mb-6 text-white focus:outline-none focus:ring-2 focus:ring-violet-500">
    
    <div class="flex justify-end space-x-3">
        <button class="py-2 px-4 bg-gray-600 hover:bg-gray-700 rounded-lg text-white font-semibold click-effect" onclick="closeTransferModal()">취소</button>
        <button class="py-2 px-4 bg-violet-600 hover:bg-violet-700 rounded-lg text-white font-semibold click-effect" onclick="handleTransfer()">송금 실행</button>
    </div>
</div>
⚙️ 더보기/설정 <script> /* --- JavaScript 코드 --- (주석만 번역) */ // --- Audio setup (files must be in the same folder!) --- let clickSound, winSound, loseSound; // Load audio after user interaction due to browser autoplay policy function initializeAudio() { // Skip if already loaded if (clickSound) return; clickSound = new Audio('click.mp3'); winSound = new Audio('win.mp3'); loseSound = new Audio('lose.mp3'); // Preload audio files to minimize delay clickSound.load(); winSound.load(); loseSound.load(); console.log("Audio initialized."); } // --- Balance Management --- const BALANCE_KEY = 'spade_rbs_balance'; // 초기 잔액을 스크린샷과 유사한 10만으로 설정 let balance = loadBalance(); function loadBalance() { let initialBalance = 100000; const storedBalance = localStorage.getItem(BALANCE_KEY); if (storedBalance) { return parseInt(storedBalance); } localStorage.setItem(BALANCE_KEY, initialBalance); return initialBalance; } function updateBalance(amount) { balance += amount; localStorage.setItem(BALANCE_KEY, balance); const formattedBalance = formatBalance(balance) + ' RBX'; const currentBalanceEl = document.getElementById('currentBalance'); if (currentBalanceEl) { currentBalanceEl.textContent = formattedBalance; } const modalBalanceEl = document.getElementById('modalBalance'); if (modalBalanceEl) { modalBalanceEl.textContent = formattedBalance; } if (balance <= 0) { if (currentBalanceEl) currentBalanceEl.classList.add('text-red-500'); if (currentBalanceEl) currentBalanceEl.classList.remove('text-white'); } else { if (currentBalanceEl) currentBalanceEl.classList.remove('text-red-500'); if (currentBalanceEl) currentBalanceEl.classList.add('text-white'); } } function formatBalance(num) { return Math.round(num).toString().replace(/\B(?=(\d{3})+(?!\d))/g, ","); } // 초기 잔액 표시 업데이트 updateBalance(0); // --- Login System Logic --- const loginScreen = document.getElementById('loginScreen'); const loginButton = document.getElementById('loginButton'); const mainApp = document.getElementById('app'); const transferButton = document.getElementById('transferButton'); const userPinInput = document.getElementById('userPin'); loginButton.addEventListener('click', () => { // Attempt audio initialization (first user interaction) initializeAudio(); if (userPinInput.value === '1234') { loginScreen.style.opacity = 0; loginScreen.style.transition = 'opacity 0.5s ease-out'; setTimeout(() => { loginScreen.classList.add('hidden'); mainApp.classList.remove('hidden'); transferButton.classList.remove('hidden'); updateBalance(0); }, 500); } else { alert("가상 PIN 번호 (1234)가 올바르지 않습니다."); } }); // --- UI/UX Feature (Click Sound Effect) --- document.querySelectorAll('.click-effect').forEach(element => { element.addEventListener('click', () => { if (clickSound) { clickSound.currentTime = 0; // Reset to play multiple times quickly clickSound.play().catch(e => console.log("Click sound blocked by browser policy.")); } }); }); // --- Betting Game Logic --- const choiceCards = document.querySelectorAll('.choice-card'); const betButton = document.getElementById('betButton'); const betAmountInput = document.getElementById('betAmount'); const resultMessage = document.getElementById('resultMessage'); let selectedChoice = null; // Handle rock-paper-scissors choice choiceCards.forEach(card => { card.addEventListener('click', () => { if (betButton.disabled === false && betButton.textContent.includes('베팅하기')) return; choiceCards.forEach(c => c.classList.remove('selected')); card.classList.add('selected'); selectedChoice = card.getAttribute('data-choice'); checkBetValidity(); }); }); // Validate bet amount and update button text function checkBetValidity() { const bet = parseInt(betAmountInput.value); const errorElement = document.getElementById('balanceError'); if (isNaN(bet) || bet < 100) { betAmountInput.value = 100; } if (bet > balance) { errorElement.classList.remove('hidden'); betButton.disabled = true; betButton.textContent = "잔액 부족"; return; } else { errorElement.classList.add('hidden'); } if (selectedChoice) { betButton.disabled = false; // 텍스트는 한국어 유지 betButton.textContent = `${formatBalance(parseInt(betAmountInput.value))} RBX 베팅하기`; } else { // 텍스트는 한국어 유지 betButton.disabled = true; betButton.textContent = "가위바위보를 선택하세요"; } } // Handle input change on bet amount betAmountInput.addEventListener('input', checkBetValidity); betAmountInput.addEventListener('change', checkBetValidity); // Execute final bet betButton.addEventListener('click', () => { if (!selectedChoice) return; const betAmount = parseInt(betAmountInput.value); if (betAmount > balance) return; betButton.disabled = true; betButton.textContent = "결과 대기 중..."; resultMessage.classList.add('hidden'); startHypeAnimation(selectedChoice, betAmount); }); // --- Core Game Logic (Animation, Result Processing) --- function startHypeAnimation(userChoice, betAmount) { const hypeText = document.getElementById('hypeText'); const hypeOverlay = document.getElementById('hypeOverlay'); const choices = ['rock', 'scissors', 'paper']; const textSequence = ['락!...', '시져!...', '페이퍼!...']; // 한국어 텍스트 유지 hypeOverlay.classList.remove('hidden'); let sequenceIndex = 0; function nextHype() { if (sequenceIndex < textSequence.length) { hypeText.textContent = textSequence[sequenceIndex]; hypeText.style.animation = 'none'; setTimeout(() => { hypeText.style.animation = 'fadeIn 0.5s forwards'; }, 10); setTimeout(() => { hypeText.style.opacity = 0; sequenceIndex++; nextHype(); }, 700); } else { hypeOverlay.classList.add('hidden'); processGameResult(userChoice, betAmount, choices); } } nextHype(); } function processGameResult(userChoice, betAmount, choices) { const computerChoice = choices[Math.floor(Math.random() * 3)]; let result = ''; if (userChoice === computerChoice) { result = 'draw'; } else if ( (userChoice === 'rock' && computerChoice === 'scissors') || (userChoice === 'scissors' && computerChoice === 'paper') || (userChoice === 'paper' && computerChoice === 'rock') ) { result = 'win'; } else { result = 'lose'; } displayResult(result, betAmount, computerChoice); } function displayResult(result, betAmount, computerChoice) { let message = ''; let sound = null; const choiceMap = { 'rock': '바위', 'scissors': '가위', 'paper': '보' }; // 결과 메시지 한국어 유지 if (result === 'win') { updateBalance(betAmount); message = `**[승리]** 컴퓨터: ${choiceMap[computerChoice]}. **+${formatBalance(betAmount)} RBX** 획득!`; resultMessage.className = 'mt-4 text-xl font-extrabold text-green-400 text-center fade-in-out'; sound = winSound; } else if (result === 'lose') { updateBalance(-betAmount); message = `**[패배]** 컴퓨터: ${choiceMap[computerChoice]}. **-${formatBalance(betAmount)} RBX** 차감.`; resultMessage.className = 'mt-4 text-xl font-extrabold text-red-500 text-center fade-in-out'; sound = loseSound; if (balance <= 0) { message += "
💸 **모든 잔액 소진!**"; } } else { message = `**[무승부]** 컴퓨터: ${choiceMap[computerChoice]}. 베팅금 유지.`; resultMessage.className = 'mt-4 text-xl font-extrabold text-yellow-400 text-center fade-in-out'; sound = clickSound; } resultMessage.innerHTML = message; resultMessage.classList.remove('hidden'); betButton.disabled = false; betButton.textContent = "다시 활동하기"; // 한국어 유지 selectedChoice = null; choiceCards.forEach(c => c.classList.remove('selected')); if (sound) { sound.currentTime = 0; sound.play().catch(e => console.log("Result sound blocked by browser policy.")); } } // --- Virtual Transfer Modal Feature (More/Settings) --- const transferModal = document.getElementById('transferModal'); const modalContent = document.getElementById('modalContent'); transferButton.addEventListener('click', openTransferModal); function openTransferModal() { updateBalance(0); transferModal.classList.remove('hidden'); transferModal.style.display = 'flex'; modalContent.classList.remove('fade-out'); modalContent.classList.add('fade-in-out'); } function closeTransferModal() { modalContent.classList.add('fade-out'); modalContent.classList.remove('fade-in-out'); setTimeout(() => { transferModal.classList.add('hidden'); transferModal.style.display = 'none'; }, 300); } function handleTransfer() { const amount = parseInt(document.getElementById('transferAmount').value); const id = document.getElementById('transferId').value; if (amount > 0 && id.length > 0) { if (amount > balance) { alert("송금 잔액이 부족합니다!"); return; } updateBalance(-amount); alert(`[가상 송금 완료] ${id}님에게 ${formatBalance(amount)} RBX 송금 완료되었습니다!`); closeTransferModal(); checkBetValidity(); } else { alert("받는 사람 ID와 송금 금액을 정확히 입력해주세요."); } } </script>

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published