From e0ea0e9ca03f7494e6e8490dde96f56ede0ea463 Mon Sep 17 00:00:00 2001 From: Junha Date: Fri, 9 May 2025 20:26:08 +0900 Subject: [PATCH 1/2] =?UTF-8?q?fix:=20=EC=84=A0=ED=83=9D=EB=90=9C=20?= =?UTF-8?q?=EB=82=A0=EC=A7=9C=EC=9D=98=20=ED=8F=B0=ED=8A=B8=EB=8A=94=20?= =?UTF-8?q?=ED=9D=B0=EC=83=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/resources/static/css/date.css | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/main/resources/static/css/date.css b/src/main/resources/static/css/date.css index 5eb5689..d3f318f 100644 --- a/src/main/resources/static/css/date.css +++ b/src/main/resources/static/css/date.css @@ -70,7 +70,6 @@ color: black; } - /* 토요일: 파란색 */ .date-buttons button.day.saturday .day-date, .date-buttons button.day.saturday .day-week { @@ -83,10 +82,19 @@ color: #ff0000; } -/* 선택된 날짜 버튼 스타일 */ +/* 선택된 날짜 버튼 스타일 (파란색 배경 + 흰색 텍스트)*/ .date-buttons button.day.selected { - background-color: #007bff; /* 파란색 배경 */ - color: white; /* 텍스트 흰색 */ + background-color: #007bff; +} +.date-buttons button.day.selected .day-date, +.date-buttons button.day.selected .day-week { + color: white; +} +.date-buttons button.day.saturday.selected .day-date, +.date-buttons button.day.saturday.selected .day-week, +.date-buttons button.day.sunday.selected .day-date, +.date-buttons button.day.sunday.selected .day-week { + color: white; } /* 좌우 화살표 버튼 */ From 71d75ad23983cf4ad51664bc9adc00a37ebd7ad5 Mon Sep 17 00:00:00 2001 From: Junha Date: Fri, 9 May 2025 22:23:07 +0900 Subject: [PATCH 2/2] =?UTF-8?q?feat:=20=EC=9E=94=EC=97=AC=EC=9D=B8?= =?UTF-8?q?=EC=9B=90=20=ED=95=84=ED=84=B0=EB=A7=81=20=EA=B8=B0=EB=8A=A5=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/deploy.yml | 2 +- src/main/resources/static/css/filter.css | 30 ++++++++++ src/main/resources/static/js/filter.js | 71 ++++++++++++++++-------- src/main/resources/static/js/home.js | 3 +- src/main/resources/templates/index.html | 29 +++++++++- 5 files changed, 108 insertions(+), 27 deletions(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 8e39034..2a86c92 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -3,7 +3,7 @@ name: Deploy To EC2 on: push: branches: - - integrate-fe-be + - feat/filter-vacancy jobs: deploy: diff --git a/src/main/resources/static/css/filter.css b/src/main/resources/static/css/filter.css index b474b8b..a0a17bf 100644 --- a/src/main/resources/static/css/filter.css +++ b/src/main/resources/static/css/filter.css @@ -111,4 +111,34 @@ border: none; border-radius: 12px; cursor: pointer; +} + +#vacancyRange { + width: 100%; /* 부모 영역 다 채우기 */ + max-width: 300px; /* 너무 길어지지 않도록 제한 */ + margin-top: 8px; + +} + +/* 슬라이더 트랙 (크롬, 사파리 등) */ +#vacancyRange::-webkit-slider-thumb { + -webkit-appearance: none; + appearance: none; + width: 20px; + height: 20px; + border-radius: 50%; + background: #007bff; + cursor: pointer; + border: none; + box-shadow: 0 0 2px rgba(0, 0, 0, 0.3); +} + +/* 파이어폭스 대응 */ +#vacancyRange::-moz-range-thumb { + width: 20px; + height: 20px; + border-radius: 50%; + background: #007bff; + border: none; + cursor: pointer; } \ No newline at end of file diff --git a/src/main/resources/static/js/filter.js b/src/main/resources/static/js/filter.js index 6944f83..9bbe7c4 100644 --- a/src/main/resources/static/js/filter.js +++ b/src/main/resources/static/js/filter.js @@ -1,4 +1,12 @@ const filterState = {}; // ex: { gender: { all: [...], unchecked: [...] }, platform: { ... } } +let minVacancy = 0 + +const vacancySlider = document.getElementById("vacancyRange"); +const vacancyDisplay = document.getElementById("vacancyValue"); + +vacancySlider.addEventListener("input", () => { + vacancyDisplay.textContent = vacancySlider.value === "0" ? "모든 매치" : `${vacancySlider.value}인 이상 신청 가능`; +}) // 필터 상태 초기화 (최초 1회), 전역 필터링 상태 저장 -> renderMatches() 호출 시 전역 필터 상태 기반 필터링 function initFilterState(modalId) { @@ -37,9 +45,14 @@ function saveFilterState(modalId) { document.addEventListener("DOMContentLoaded", () => { // 필터 모달 초기화 (모달 id 기준) - // 모든 .modal-overlay를 자동 탐색하여 초기화 - document.querySelectorAll(".modal-overlay").forEach(modal => { - initFilterState(modal.id); + + // 멀티 필터 초기화 + document.querySelectorAll('[data-multifilter][data-modal-target]').forEach(btn => { + const modalSelector = btn.getAttribute("data-modal-target"); // ex: "#genderModal" + const modal = document.querySelector(modalSelector); + if (modal) { + initFilterState(modal.id); + } }); // 모달 열기 버튼 @@ -47,12 +60,21 @@ document.addEventListener("DOMContentLoaded", () => { btn.addEventListener("click", () => { const selector = btn.getAttribute("data-modal-target"); const modal = document.querySelector(selector); - if (modal) { + if(!modal) return; + + //멀티 필터 모달일 시, + if (btn.hasAttribute("data-multi-filter")) { renderFilterState(modal.id); // 상태 복원 - modal.classList.add("active"); - //CSS .modal-overlay.active -> 화면에 display 되도록, modal-overlay는 선택시 나타나는 전체 회색배경. - //이 배경이 active 되면 내부 modal-content도 함께 나타난다. } + + if (modal.id === "vacancyModal") { + vacancySlider.value = minVacancy; + vacancyDisplay.textContent = vacancySlider.value === "0" ? "모든 매치" : `${vacancySlider.value}인 이상 신청 가능`; + } + + //CSS .modal-overlay.active -> 화면에 display 되도록, modal-overlay는 선택시 나타나는 전체 회색배경. + //이 배경이 active 되면 내부 modal-content도 함께 나타난다. + modal.classList.add("active"); }); }); @@ -61,7 +83,7 @@ document.addEventListener("DOMContentLoaded", () => { btn.addEventListener("click", () => { const modal = btn.closest(".modal-overlay"); if (modal) { - //닫기 버튼 클릭시 체크 박스 상태는 저장하지 않는다. + //닫기 버튼 클릭시 상태는 저장하지 않는다. modal.classList.remove("active"); } }); @@ -71,7 +93,7 @@ document.addEventListener("DOMContentLoaded", () => { document.querySelectorAll(".modal-overlay").forEach(modal => { modal.addEventListener("click", (e) => { if (e.target === modal) { - //바깥 클릭으로 닫을시 체크 박스 상태는 저장하지 않는다. + //바깥 클릭으로 닫을시 상태는 저장하지 않는다. modal.classList.remove("active"); } }); @@ -81,20 +103,24 @@ document.addEventListener("DOMContentLoaded", () => { document.querySelectorAll(".modal-overlay .apply-btn").forEach(btn => { btn.addEventListener("click", () => { const modal = btn.closest(".modal-overlay"); - if (modal) { - saveFilterState(modal.id); // 상태 저장 - modal.classList.remove("active"); + if(!modal) return; + + const triggerBtn = document.querySelector(`[data-modal-target="#${modal.id}"]`); + if(!triggerBtn) return; + + let isFiltered = false; + if(triggerBtn.hasAttribute("data-multifilter")) { + saveFilterState(modal.id); + isFiltered = filterState[modal.id]?.unchecked?.length > 0; + } else if(modal.id === "vacancyModal") { + minVacancy = vacancySlider.value; + isFiltered = minVacancy > 0; + } - // 필터링 선택 버튼 활성화 (적용 사항 있을시) - const triggerBtn = document.querySelector(`[data-modal-target="#${modal.id}"]`); - const isFiltered = filterState[modal.id].unchecked.length > 0 - if (triggerBtn) { - triggerBtn.classList.toggle("active", isFiltered); - } + modal.classList.remove("active"); + triggerBtn.classList.toggle("active", isFiltered); - renderMatches(); - console.log(`[${modal.id}] 필터 적용됨:`, getActiveValues(modal.id)); - } + renderMatches(); }); }); }) @@ -109,7 +135,8 @@ function applyFilters(matchList) { return matchList .filter(match => activeGenders.includes(match.sex)) .filter(match => activePlatforms.includes(match.platform)) - .filter(match => !(hideFull && match.isFull)); //마감가리기 활성화 && 마감된 매치일 시 필터링 + .filter(match => !(hideFull && match.vacancy === 0)) //마감가리기 활성화 && 마감된 매치일 시 필터링 + .filter(match => match.vacancy >= minVacancy); } // 현재 적용된 항목만 가져오는 헬퍼 함수 diff --git a/src/main/resources/static/js/home.js b/src/main/resources/static/js/home.js index 8acfdcd..0d845e1 100644 --- a/src/main/resources/static/js/home.js +++ b/src/main/resources/static/js/home.js @@ -19,7 +19,8 @@ function fetchMatches(date) { .then(data => { allMatches = data.map(match => ({ ...match, - isFull: parseInt(match.cur_player) >= parseInt(match.max_player) //마감 여부 추가. '마감가리기' 필터용 + vacancy: parseInt(match.max_player ?? "999") - parseInt(match.cur_player ?? "0") + //인원 정보가 없을 경우, 잔여인원을 크게 설정하여 필터링 되지 않도록 한다. })); renderMatches(); }) diff --git a/src/main/resources/templates/index.html b/src/main/resources/templates/index.html index 60ae5f6..fdddc99 100644 --- a/src/main/resources/templates/index.html +++ b/src/main/resources/templates/index.html @@ -44,12 +44,18 @@ - - + + + + - + +