| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328 |
- <template>
- <main class="models--page">
- <div class="type--carousel">
- <!-- 필터 -->
- <div class="models--filter--section">
- <div class="filter--group">
- <!-- 연료 타입 필터 -->
- <div class="filter--dropdown--list">
- <div class="filter--dropdown">
- <button
- v-for="fuel in filters.fuelType"
- :key="fuel.id"
- :class="['filter--btn', { active: activeFuelTypes.includes(fuel.id) }]"
- @click="toggleFuelType(fuel.id)"
- >
- <svg
- v-if="fuel.id == 'etron'"
- fill="none"
- xmlns="http://www.w3.org/2000/svg"
- aria-hidden="true"
- width="16px"
- height="16px"
- class=""
- >
- <use
- v-if="activeFuelTypes.includes(fuel.id)"
- href="/img/select-xs.svg#main"
- ></use>
- <use v-else href="/img/charging-xs.svg#main"></use>
- </svg>
- <svg
- v-else-if="activeFuelTypes.includes(fuel.id)"
- fill="none"
- xmlns="http://www.w3.org/2000/svg"
- aria-hidden="true"
- width="16px"
- height="16px"
- class=""
- >
- <use href="/img/select-xs.svg#main"></use>
- </svg>
- {{ fuel.name }}
- </button>
- <button
- v-for="body in filters.bodyType"
- :key="body.id"
- :class="['filter--btn', { active: activeBodyTypes.includes(body.id) }]"
- @click="toggleBodyType(body.id)"
- >
- <svg
- v-if="activeBodyTypes.includes(body.id)"
- fill="none"
- xmlns="http://www.w3.org/2000/svg"
- aria-hidden="true"
- width="16px"
- height="16px"
- class="sc-AxhUy kMyssS sc-fzoant LAaNs"
- >
- <use href="/img/select-xs.svg#main"></use>
- </svg>
- {{ body.name }}
- </button>
- </div>
- </div>
- </div>
- </div>
- <!-- 차량 그리드 (항상 표시) -->
- <div class="models--list--wrap">
- <div class="all--models--wrap">
- <div class="all--models">Model 보기 ({{ filteredModels.length }})</div>
- <div class="nav--btn--wrap">
- <button class="nav--prev--btn">
- <svg
- fill="none"
- xmlns="http://www.w3.org/2000/svg"
- aria-hidden="true"
- width="24px"
- height="24px"
- class=""
- >
- <use href="/img/forward-s.svg#main"></use>
- </svg>
- </button>
- <button class="nav--next--btn">
- <svg
- fill="none"
- xmlns="http://www.w3.org/2000/svg"
- aria-hidden="true"
- width="24px"
- height="24px"
- class=""
- >
- <use href="/img/forward-s.svg#main"></use>
- </svg>
- </button>
- </div>
- </div>
- <div class="models--list">
- <Swiper
- :slides-per-view="'auto'"
- :space-between="8"
- :navigation="{
- nextEl: '.nav--next--btn',
- prevEl: '.nav--prev--btn',
- }"
- :centered-slides="false"
- :modules="modules"
- class="models--swiper"
- >
- <SwiperSlide
- v-for="model in filteredModels"
- :key="model.id"
- :class="['model--item', { active: selectedGroupName === model.groupName }]"
- >
- <div @click="handleModelClick(model)">
- <!-- 이미지 -->
- <h2 class="model--name">
- {{ model.groupName }}
- <div class="etron--wrap" v-if="model.fuelType === 'etron'">
- <div class="etron">
- <svg
- fill="none"
- xmlns="http://www.w3.org/2000/svg"
- aria-hidden="true"
- width="16px"
- height="16px"
- class="sc-AxhUy kMyssS sc-fzoant LAaNs"
- >
- <use href="/img/charging-xs.svg#main"></use>
- </svg>
- </div>
- </div>
- </h2>
- <div class="model--image--wrap">
- <img :src="model.image" :alt="model.name" />
- </div>
- <!-- 정보 -->
- <div class="model--info--wrap">
- Model 보기 {{ getGroupModelCount(model.groupName) }}
- <i class="ico"></i>
- </div>
- </div>
- </SwiperSlide>
- </Swiper>
- </div>
- <!-- 모든 차량 리스트 (Swiper 차량 클릭 시 드롭다운 표시) -->
- <div class="models--list--car" :class="{ active: selectedGroupName }">
- <div class="car--list">
- <div v-for="car in filteredCars" :key="car.id" class="car--item">
- <div class="bedge--wrap">
- <div class="etron--wrap" v-if="car.fuelType === 'etron'">
- <div class="etron">
- <svg
- fill="none"
- xmlns="http://www.w3.org/2000/svg"
- aria-hidden="true"
- width="16px"
- height="16px"
- class="sc-AxhUy kMyssS sc-fzoant LAaNs"
- >
- <use href="/img/charging-xs.svg#main"></use>
- </svg>
- Electrified
- </div>
- </div>
- </div>
- <div class="car--image">
- <NuxtLink :to="car.link">
- <img :src="car.image" :alt="car.name" />
- </NuxtLink>
- </div>
- <div class="car--info">
- <h3 class="car--name">{{ car.fullName }}</h3>
- <NuxtLink :to="car.link" class="car--link">자세히 보기</NuxtLink>
- </div>
- </div>
- </div>
- </div>
- </div>
- </div>
- </main>
- </template>
- <script setup>
- import { Swiper, SwiperSlide } from "swiper/vue";
- import { Navigation } from "swiper/modules";
- import "swiper/css";
- import "swiper/css/navigation";
- const modules = [Navigation];
- const modelsData = ref({
- models: [],
- filters: { fuelType: [], bodyType: [] },
- });
- const activeFuelTypes = ref([]);
- const activeBodyTypes = ref([]);
- const selectedGroupName = ref(null); // Swiper에서 클릭한 그룹
- // 필터 옵션
- const filters = computed(() => modelsData.value.filters);
- // 필터 토글 함수
- const toggleFuelType = (value) => {
- const index = activeFuelTypes.value.indexOf(value);
- if (index > -1) {
- activeFuelTypes.value.splice(index, 1);
- } else {
- activeFuelTypes.value.push(value);
- }
- // 필터 버튼 클릭 시 선택된 그룹 초기화
- selectedGroupName.value = null;
- };
- const toggleBodyType = (value) => {
- const index = activeBodyTypes.value.indexOf(value);
- if (index > -1) {
- activeBodyTypes.value.splice(index, 1);
- } else {
- activeBodyTypes.value.push(value);
- }
- // 필터 버튼 클릭 시 선택된 그룹 초기화
- selectedGroupName.value = null;
- };
- // groupName별 모델 개수를 계산하는 함수
- const getGroupModelCount = (groupName) => {
- return modelsData.value.models.filter((model) => model.groupName === groupName)
- .length;
- };
- // 연료 타입 이름 가져오기
- const getFuelTypeName = (fuelType) => {
- const fuelTypes = {
- etron: "전기차",
- hybrid: "하이브리드",
- "gas-diesel": "가솔린/디젤",
- };
- return fuelTypes[fuelType] || fuelType;
- };
- // 모델 그룹 클릭 핸들러 (Swiper에서 차량 클릭 - 토글)
- const handleModelClick = (model) => {
- // 같은 그룹을 다시 클릭하면 토글 (숨김)
- if (selectedGroupName.value === model.groupName) {
- selectedGroupName.value = null;
- } else {
- // 다른 그룹을 클릭하면 변경
- selectedGroupName.value = model.groupName;
- }
- };
- // 필터링된 차량 리스트 (모든 차량)
- const filteredCars = computed(() => {
- // Swiper에서 차량을 클릭한 경우 - groupName으로 필터링
- if (selectedGroupName.value) {
- return modelsData.value.models.filter(
- (model) => model.groupName === selectedGroupName.value
- );
- }
- return [];
- });
- // 필터링된 모델 계산 (그룹화된 모델)
- const filteredModels = computed(() => {
- let filtered = modelsData.value.models;
- // 연료 타입 필터 (OR 조건 - 선택된 연료 타입 중 하나라도 일치하면 포함)
- if (activeFuelTypes.value.length > 0) {
- filtered = filtered.filter((model) =>
- activeFuelTypes.value.includes(model.fuelType)
- );
- }
- // 바디 타입 필터 (OR 조건 - 선택된 바디 타입 중 하나라도 일치하면 포함)
- if (activeBodyTypes.value.length > 0) {
- filtered = filtered.filter((model) =>
- model.bodyType.some((type) => activeBodyTypes.value.includes(type))
- );
- }
- // groupName별로 그룹화하고 각 그룹의 첫 번째 모델만 추출
- const groupedByName = {};
- filtered.forEach((model) => {
- // groupName을 키로 사용
- const groupName = model.groupName;
- // 해당 groupName 그룹이 없으면 생성하고 첫 번째 모델 저장
- if (!groupedByName[groupName]) {
- groupedByName[groupName] = model;
- }
- });
- // 그룹화된 객체에서 값(첫 번째 모델들)만 배열로 반환
- return Object.values(groupedByName);
- });
- onMounted(async () => {
- try {
- const response = await fetch("/models.json");
- const data = await response.json();
- modelsData.value = data;
- console.log("Models data loaded:", data);
- } catch (error) {
- console.error("Failed to load models data:", error);
- }
- });
- </script>
- <style scoped lang="scss">
- .type--carousel {
- .models--list {
- position: relative;
- }
- .models--list--car {
- transition: all 0.3s ease-in-out;
- }
- }
- </style>
|