유저자료실

  • 유저자료실 포인트 정책
      글쓰기
      10P
      댓글
      5P
  • 전체 2건 / 1 페이지
      이미지가 없습니다.
  • PWA 앱 설치 이후 플로팅 버튼에 대한 수정 코드
  • 14일 전  기타
  • <?phpif (!defined('_GNUBOARD_')) exit;include_once("./_common.php");?><style type="text/css">/* 페이지 하단 여백 - 탭바 높이만큼 */body.pwa-mobile { padding-bottom: 60px;}/* 하단 고정 탭바 스타일 */.floating-tabbar { display: none; position: fixed; bottom: 0; left: 0; right: 0; height: 60px; background: rgba(0, 0, 0, 0.4); backdrop-filter: blur(20px); -webkit-backdrop-filter: blur(20px); border-top: 1px solid rgba(255, 255, 255, 0.2); z-index: 1000; padding: 0 10px; box-shadow: 0 -4px 16px rgba(0, 0, 0, 0.2); transition: background 0.3s ease;}/* 밝은 배경용 스타일 */.floating-tabbar.light-mode { background: rgba(255, 255, 255, 0.95); border-top: 1px solid rgba(0, 0, 0, 0.1); box-shadow: 0 -4px 16px rgba(0, 0, 0, 0.1);}.floating-tabbar-container { display: flex; align-items: center; justify-content: space-between; height: 100%; width: 100%;}/* 히스토리 네비게이션 */.floating-tabbar-history { display: flex; align-items: center; gap: 8px; margin-right: 3px;}.floating-tabbar-history-btn { display: flex; align-items: center; justify-content: center; width: 50px; height: 35px; cursor: pointer; transition: all 0.3s ease; position: relative; overflow: hidden;}.floating-tabbar-history-btn:disabled { opacity: 0.3; cursor: not-allowed;}.floating-tabbar-history-btn::before { content: ''; position: absolute; top: 0; left: 0; right: 0; bottom: 0; background: rgba(255, 255, 255, 0.2); border-radius: 8px; opacity: 0; transition: opacity 0.3s ease;}.floating-tabbar.light-mode .floating-tabbar-history-btn::before { background: rgba(0, 0, 0, 0.1);}.floating-tabbar-history-btn:not(:disabled):active::before { opacity: 1;}.floating-tabbar-history-btn:not(:disabled):active { transform: scale(0.9);}.floating-tabbar-history-icon { width: 24px; height: 24px; stroke: rgba(255, 255, 255, 0.9); transition: all 0.3s ease;}.floating-tabbar.light-mode .floating-tabbar-history-icon { stroke: rgba(0, 0, 0, 0.8);}.floating-tabbar-menu { display: flex; align-items: center; flex: 1;}.floating-tabbar-menu > div { flex: 1;}.floating-tabbar-item { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 4px; cursor: pointer; transition: all 0.3s ease; padding: 8px 12px; border-radius: 12px; user-select: none; position: relative; overflow: hidden; flex: 1; text-decoration: none;}.floating-tabbar-item::before { content: ''; position: absolute; top: 0; left: 0; right: 0; bottom: 0; background: rgba(255, 255, 255, 0.2); border-radius: 12px; opacity: 0; transition: opacity 0.3s ease;}.floating-tabbar.light-mode .floating-tabbar-item::before { background: rgba(0, 0, 0, 0.1);}.floating-tabbar-item:active::before { opacity: 1;}.floating-tabbar-icon { width: 20px; height: 20px; stroke: rgba(255, 255, 255, 0.9); transition: all 0.3s ease;}.floating-tabbar.light-mode .floating-tabbar-icon { stroke: rgba(0, 0, 0, 0.8);}.floating-tabbar-item:active .floating-tabbar-icon { transform: scale(0.9);}.floating-tabbar-label { font-size: 10px; color: rgba(255, 255, 255, 0.8); font-weight: 500; transition: color 0.3s ease;}.floating-tabbar.light-mode .floating-tabbar-label { color: rgba(0, 0, 0, 0.7);}.floating-tabbar-refresh { display: flex; align-items: center; justify-content: center; width: 44px; height: 44px; background: rgba(255, 255, 255, 0.3); border: 1px solid rgba(255, 255, 255, 0.4); border-radius: 50%; cursor: pointer; transition: all 0.3s ease; position: relative; overflow: hidden;}.floating-tabbar.light-mode .floating-tabbar-refresh { background: rgba(0, 0, 0, 0.1); border: 1px solid rgba(0, 0, 0, 0.2);}.floating-tabbar-refresh::before { content: ''; position: absolute; top: 0; left: 0; right: 0; bottom: 0; background: rgba(255, 255, 255, 0.2); border-radius: 50%; opacity: 0; transition: opacity 0.3s ease;}.floating-tabbar.light-mode .floating-tabbar-refresh::before { background: rgba(0, 0, 0, 0.1);}.floating-tabbar-refresh:active::before { opacity: 1;}.floating-tabbar-refresh:active { transform: scale(0.95);}.floating-tabbar-refresh-icon { width: 20px; height: 20px; stroke: #fff; stroke-width: 2; transition: transform 0.6s ease;}.floating-tabbar.light-mode .floating-tabbar-refresh-icon { stroke: #000;}.floating-tabbar-refresh.spinning .floating-tabbar-refresh-icon { transform: rotate(360deg);}/* PWA 모바일에서만 표시 */.pwa-mobile .floating-tabbar { display: block;}/* 매우 작은 화면에서 간격 조정 */@media (max-width: 400px) { .floating-tabbar { padding: 0 8px; } .floating-tabbar-item { padding: 6px 6px; } .floating-tabbar-refresh { width: 40px; height: 40px; } .floating-tabbar-history { margin-right: 4px; } .floating-tabbar-history-btn { width: 24px; height: 24px; } .floating-tabbar-history-icon { width: 12px; height: 12px; }}/* 안전 영역 대응 (iPhone X 이후) */@supports (bottom: env(safe-area-inset-bottom)) { .floating-tabbar { padding-bottom: env(safe-area-inset-bottom); height: calc(60px + env(safe-area-inset-bottom)); } body.pwa-mobile { padding-bottom: calc(60px + env(safe-area-inset-bottom)); }}</style><!-- 모바일 하단 고정 탭바 --><div class="floating-tabbar"> <div class="floating-tabbar-container"> <!-- 히스토리 네비게이션 --> <div class="floating-tabbar-history"> <button class="floating-tabbar-history-btn" id="historyBack" onclick="goBack()" disabled> <svg class="floating-tabbar-history-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <polyline points="15,18 9,12 15,6"/> </svg> </button> <button class="floating-tabbar-history-btn" id="historyForward" onclick="goForward()" disabled> <svg class="floating-tabbar-history-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <polyline points="9,18 15,12 9,6"/> </svg> </button> </div> <div class="floating-tabbar-menu"> <?php if (isset($is_member) ? $is_member : '') { ?> <!-- 회원용 탭바 --> <div><a href="<?php echo G5_URL ?>" class="floating-tabbar-item"> <svg class="floating-tabbar-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/> <polyline points="9,22 9,12 15,12 15,22"/> </svg> <span class="floating-tabbar-label">홈</span> </a></div> <div><a href="<?php echo G5_URL ?>/dashboard" class="floating-tabbar-item"> <svg class="floating-tabbar-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <rect x="3" y="3" width="7" height="7"/> <rect x="14" y="3" width="7" height="7"/> <rect x="14" y="14" width="7" height="7"/> <rect x="3" y="14" width="7" height="7"/> </svg> <span class="floating-tabbar-label">대시보드</span> </a></div> <div><a href="javascript:void(0);" onclick="toggleFloatingNotification()" class="floating-tabbar-item"> <svg class="floating-tabbar-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <path d="M4 4h16c1.1 0 2 .9 2 2v12c0 1.1-.9 2-2 2H4c-1.1 0-2-.9-2-2V6c0-1.1.9-2 2-2z"/> <polyline points="22,6 12,13 2,6"/> </svg> <span class="floating-tabbar-label">알림</span> </a></div> <div><a href="<?php echo G5_URL ?>/rb/home.php?mb_id=<?php echo $member['mb_id'] ?>" class="floating-tabbar-item"> <svg class="floating-tabbar-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"/> <circle cx="12" cy="7" r="4"/> </svg> <span class="floating-tabbar-label">마이페이지</span> </a></div> <?php } else { ?> <!-- 비회원용 탭바 --> <div><a href="<?php echo G5_URL ?>" class="floating-tabbar-item"> <svg class="floating-tabbar-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/> <polyline points="9,22 9,12 15,12 15,22"/> </svg> <span class="floating-tabbar-label">홈</span> </a></div> <div><a href="<?php echo G5_BBS_URL ?>/board.php?bo_table=free" class="floating-tabbar-item"> <svg class="floating-tabbar-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <path d="M3 3h18v18H3zM9 9h6m-6 4h6m-6 4h4"/> <line x1="9" y1="9" x2="15" y2="9"/> <line x1="9" y1="13" x2="15" y2="13"/> <line x1="9" y1="17" x2="13" y2="17"/> </svg> <span class="floating-tabbar-label">게시판</span> </a></div> <div><a href="<?php echo G5_BBS_URL ?>/board.php?bo_table=notice" class="floating-tabbar-item"> <svg class="floating-tabbar-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/> <polyline points="14,2 14,8 20,8"/> <line x1="16" y1="13" x2="8" y2="13"/> <line x1="16" y1="17" x2="8" y2="17"/> <polyline points="10,9 9,9 8,9"/> </svg> <span class="floating-tabbar-label">공지</span> </a></div> <div><a href="<?php echo G5_BBS_URL ?>/login.php" class="floating-tabbar-item"> <svg class="floating-tabbar-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <path d="M15 3h4a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2h-4"/> <polyline points="10,17 15,12 10,7"/> <line x1="15" y1="12" x2="3" y2="12"/> </svg> <span class="floating-tabbar-label">로그인</span> </a></div> <?php } ?> </div> <button class="floating-tabbar-refresh" onclick="floatingTabbarRefresh()"> <svg class="floating-tabbar-refresh-icon" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"> <path stroke-linecap="round" stroke-linejoin="round" d="M16.023 9.348h4.992v-.001M2.985 19.644v-4.992m0 0h4.992m-4.993 0 3.181 3.183a8.25 8.25 0 0 0 13.803-3.7M4.031 9.865a8.25 8.25 0 0 1 13.803-3.7l3.181 3.182m0-4.991v4.99" /> </svg> </button> </div></div><script>// 히스토리 네비게이션 함수들function updateHistoryButtons() { const backBtn = document.getElementById('historyBack'); const forwardBtn = document.getElementById('historyForward'); const currentIndex = parseInt(sessionStorage.getItem('historyIndex') || '0'); const maxIndex = parseInt(sessionStorage.getItem('maxHistoryIndex') || '0'); backBtn.disabled = currentIndex <= 0; forwardBtn.disabled = currentIndex >= maxIndex;}function goBack() { if (window.history.length > 1) { const currentIndex = parseInt(sessionStorage.getItem('historyIndex') || '0'); sessionStorage.setItem('historyIndex', Math.max(0, currentIndex - 1).toString()); window.history.back(); }}function goForward() { const currentIndex = parseInt(sessionStorage.getItem('historyIndex') || '0'); const maxIndex = parseInt(sessionStorage.getItem('maxHistoryIndex') || '0'); if (currentIndex < maxIndex) { sessionStorage.setItem('historyIndex', (currentIndex + 1).toString()); window.history.forward(); }}// 페이지 로드 시 히스토리 인덱스 업데이트function trackPageNavigation() { const currentIndex = parseInt(sessionStorage.getItem('historyIndex') || '0'); if (performance.navigation.type === 0) { const newIndex = currentIndex + 1; sessionStorage.setItem('historyIndex', newIndex.toString()); sessionStorage.setItem('maxHistoryIndex', newIndex.toString()); } updateHistoryButtons();}// 배경 밝기 감지 및 테마 자동 변경function detectFloatingTabbarBrightness() { const tabbar = document.querySelector('.floating-tabbar'); if (!tabbar) return; const footer = document.querySelector('footer'); if (footer) { const footerRect = footer.getBoundingClientRect(); const windowHeight = window.innerHeight; // 푸터가 화면 하단 근처에 있는지 확인 if (footerRect.top < windowHeight) { tabbar.classList.remove('light-mode'); } else { tabbar.classList.add('light-mode'); } } else { tabbar.classList.add('light-mode'); }}// 스크롤 시 배경 감지let floatingTabbarTicking = false;function updateFloatingTabbarTheme() { if (!floatingTabbarTicking) { requestAnimationFrame(() => { detectFloatingTabbarBrightness(); floatingTabbarTicking = false; }); floatingTabbarTicking = true; }}// 새로고침 버튼function floatingTabbarRefresh() { const refreshBtn = document.querySelector('.floating-tabbar-refresh'); refreshBtn.classList.add('spinning'); setTimeout(() => { location.reload(); }, 600);}// popstate 이벤트 리스너window.addEventListener('popstate', function(event) { setTimeout(updateHistoryButtons, 100);});// 초기화document.addEventListener('DOMContentLoaded', function() { trackPageNavigation(); window.addEventListener('scroll', updateFloatingTabbarTheme); window.addEventListener('resize', updateFloatingTabbarTheme); detectFloatingTabbarBrightness(); updateHistoryButtons(); // 터치 피드백 document.querySelectorAll('.floating-tabbar-item, .floating-tabbar-refresh, .floating-tabbar-history-btn').forEach(element => { element.addEventListener('touchstart', function() { if (!this.disabled) { this.style.transform = 'scale(0.95)'; } }); element.addEventListener('touchend', function() { setTimeout(() => { this.style.transform = ''; }, 150); }); });});</script>기존 플로팅 툴바를 하단에 고정하고 하단에 60px 여백을 줌
    • 토시아
    • 18
      이미지가 없습니다.
  • PWA 팝업 스킨 제작 가이드
  • 오래 전  PWA 팝업 스킨
  • 본 가이드는 추후 업데이트 될 0.0.5 버전에서 적용할 수 있습니다.기본 구조스킨은 두 개의 파일로 구성됩니다:popup.html - 팝업 구조popup.css - 디자인 스타일폴더 생성popup/내스킨이름/├── popup.html└── popup.cssHTML 파일 작성popup.html에 다음과 내용을 작성하세요:<div class="pwa-install-popup">    <div class="pwa-popup-content">        <button class="pwa-close-btn">{{closeIcon}}</button>                <h2 class="pwa-popup-title">{{title}}</h2>        <p class="pwa-popup-description">{{description}}</p>                <button class="pwa-install-btn">{{installButtonText}}</button>        <button class="pwa-later-btn">{{laterButtonText}}</button>    </div></div>필수 클래스반드시 포함해야 하는 클래스들:pwa-install-popup - 메인 컨테이너pwa-close-btn - 닫기 버튼pwa-install-btn - 설치 버튼pwa-later-btn - 나중에 버튼기본 CSS 작성popup.css에 최소한 이런 스타일이 필요합니다:css.pwa-install-popup {    position: fixed;    display: none;    z-index: 99999;}.pwa-install-popup.show {    display: block !important;}.pwa-close-btn,.pwa-install-btn,.pwa-later-btn {    cursor: pointer;    border: none;}모바일 대응css@media (max-width: 480px) {    .pwa-popup-content {        width: 100%;        padding: 20px;    }}스킨 적용하기JavaScript에서 스킨을 적용하려면:javascriptawait changePWAPopupSkin('내스킨이름');주의사항클래스 이름을 정확히 지켜주세요z-index는 99999 이상으로 설정모바일에서도 잘 보이도록 테스트다크모드를 고려하면 더 좋습니다간단한 예제하단 고정 스타일:css.pwa-install-popup {    position: fixed;    bottom: 0;    left: 0;    width: 100%;    background: white;    padding: 20px;    border-top: 1px solid #ddd;    display: none;    z-index: 99999;}.pwa-install-popup.show {    display: flex !important;    align-items: center;    justify-content: space-between;}.pwa-install-btn {    background: #007AFF;    color: white;    padding: 10px 20px;    border-radius: 5px;}.pwa-later-btn {    background: transparent;    color: #666;    padding: 10px 20px;}.pwa-close-btn {    background: none;    font-size: 20px;    color: #999;}
    • 최고관리자
    • 인기
    • 143

검색

게시물 검색