용어집 수정정

This commit is contained in:
khj0414 2025-03-14 13:16:47 +09:00
parent e9f7b5d358
commit fe8abc7f7c
4 changed files with 101 additions and 68 deletions

View File

@ -1,29 +1,18 @@
<template> <template>
<ul class="d-flex p-0 mb-0"> <!-- <ul class="d-flex p-0 mb-0 flex-wrap">
<li class="d-flex"> <li class="d-flex">
<button <button
type="button" type="button"
class="alphabet-btn" class="alphabet-btn"
:class="{ active: selectedAl === 'all' }" :class="{ active: selectedAl === 'all' }"
@click="selectAlphabet('all')" @click="selectAlphabet('all')"
> 전체 ({{ totalCount}}) > 전체 ({{ totalCount }})
</button> </button>
<span class="divider">|</span> </li>
</li> </ul> -->
<li v-for="(char, index) in koreanChars" :key="char.CHARACTER_" class="d-flex"> <div v-for="(group, groupIndex) in chunkedKoreanChars" :key="'ko-group-' + groupIndex">
<button
type="button"
class="alphabet-btn"
:class="{ active: selectedAl === char.CHARACTER_ }"
@click="selectAlphabet(char.CHARACTER_)"
>
{{ char.CHARACTER_ }} ({{ char.COUNT }})
</button>
<span v-if="index !== koreanChars.length - 1" class="divider">|</span>
</li>
</ul>
<ul class="d-flex p-0 mb-0"> <ul class="d-flex p-0 mb-0">
<li v-for="(char, index) in englishChars" :key="char.CHARACTER_" class="d-flex"> <li v-for="(char, index) in group" :key="char.CHARACTER_" class="d-flex">
<button <button
type="button" type="button"
class="alphabet-btn" class="alphabet-btn"
@ -32,9 +21,25 @@
> >
{{ char.CHARACTER_ }} ({{ char.COUNT }}) {{ char.CHARACTER_ }} ({{ char.COUNT }})
</button> </button>
<span v-if="index !== englishChars.length - 1" class="divider">|</span> <span v-if="index !== group.length - 1" class="divider">|</span>
</li> </li>
</ul> </ul>
</div>
<div v-for="(group, groupIndex) in chunkedEnglishChars" :key="'en-group-' + groupIndex">
<ul class="d-flex p-0 mb-0">
<li v-for="(char, index) in group" :key="char.CHARACTER_" class="d-flex">
<button
type="button"
class="alphabet-btn"
:class="{ active: selectedAl === char.CHARACTER_ }"
@click="selectAlphabet(char.CHARACTER_)"
>
{{ char.CHARACTER_ }} ({{ char.COUNT }})
</button>
<span v-if="index !== group.length - 1" class="divider">|</span>
</li>
</ul>
</div>
</template> </template>
<script setup> <script setup>
@ -47,7 +52,7 @@ const props = defineProps({
}, },
selectedAl: { selectedAl: {
type: String, type: String,
default : '', default: '',
required: false, required: false,
}, },
}); });
@ -56,14 +61,24 @@ const selectedAlphabet = ref(props.selectedAl);
const totalCount = computed(() => { const totalCount = computed(() => {
return props.indexCategory.reduce((sum, item) => sum + item.COUNT, 0); return props.indexCategory.reduce((sum, item) => sum + item.COUNT, 0);
}); });
const chunkArray = (arr, size) => {
return arr.reduce((acc, _, i) => {
if (i % size === 0) acc.push(arr.slice(i, i + size));
return acc;
}, []);
};
const koreanChars = computed(() => { const koreanChars = computed(() => {
return props.indexCategory.filter(char => /[-ㅎ가-]/.test(char.CHARACTER_)); return props.indexCategory.filter(char => /[-ㅎ가-]/.test(char.CHARACTER_));
}); });
const englishChars = computed(() => { const englishChars = computed(() => {
return props.indexCategory.filter(char => /^[a-zA-Z]$/.test(char.CHARACTER_)); return props.indexCategory.filter(char => /^[a-zA-Z]$/.test(char.CHARACTER_));
}); });
const chunkedKoreanChars = computed(() => chunkArray(koreanChars.value, 5));
const chunkedEnglishChars = computed(() => chunkArray(englishChars.value, 5));
const emit = defineEmits(); const emit = defineEmits();
const selectAlphabet = (alphabet) => { const selectAlphabet = (alphabet) => {
selectedAlphabet.value = selectedAlphabet.value === alphabet ? null : alphabet; selectedAlphabet.value = selectedAlphabet.value === alphabet ? null : alphabet;
@ -81,6 +96,7 @@ const selectAlphabet = (alphabet) => {
cursor: pointer; cursor: pointer;
width: 70%; width: 70%;
height: 40px; height: 40px;
transition: color 0.3s ease, font-size 0.3s ease; /* Smooth transition for color */
} }
.alphabet-btn:hover { .alphabet-btn:hover {
@ -90,10 +106,16 @@ const selectAlphabet = (alphabet) => {
.alphabet-btn.active { .alphabet-btn.active {
color: #0d6efd; color: #0d6efd;
text-decoration: underline; text-decoration: underline;
font-size: 13px; /* Keep font size fixed in active state */
} }
.divider { .divider {
color: #bbb; color: #bbb;
font-size: 14px; font-size: 14px;
font-weight: bold; font-weight: bold;
} }
.flex-wrap {
flex-wrap: wrap;
}
</style> </style>

View File

@ -1,5 +1,5 @@
<template> <template>
<li class="mt-5 card p-5"> <li class="card p-5 mb-2">
<DictWrite <DictWrite
v-if="writeStore.isItemActive(item.WRDDICSEQ)" v-if="writeStore.isItemActive(item.WRDDICSEQ)"
@close="writeStore.closeAll();" @close="writeStore.closeAll();"
@ -64,7 +64,7 @@
</div> </div>
</div> </div>
<div class="edit-btn" v-if="userStore.user.role !== 'ROLE_ADMIN'"> <div class="edit-btn">
<EditBtn ref="writeButton" @click="writeStore.toggleItem(item.WRDDICSEQ)" :isToggleEnabled="true" <EditBtn ref="writeButton" @click="writeStore.toggleItem(item.WRDDICSEQ)" :isToggleEnabled="true"
:isActive="writeStore.activeItemId === item.WRDDICSEQ"/> :isActive="writeStore.activeItemId === item.WRDDICSEQ"/>
</div> </div>

View File

@ -4,13 +4,12 @@
<div class="col-10"> <div class="col-10">
<FormSelect <FormSelect
name="cate" name="cate"
title="카테고리 선택" title="카테고리"
:data="dataList" :data="dataList"
:is-common="true" :is-common="true"
@update:data="selectCategory = $event" @update:data="selectCategory = $event"
@change="onChange" @change="onChange"
:value="formValue" :value="formValue"
:disabled="isDisabled"
:is-essential="false" :is-essential="false"
/> />
</div> </div>
@ -23,7 +22,7 @@
<div class="col-10"> <div class="col-10">
<FormInput <FormInput
ref="categoryInputRef" ref="categoryInputRef"
title="카테고리 입력" title="카테고리"
name="카테고리" name="카테고리"
@update:modelValue="addCategory = $event" @update:modelValue="addCategory = $event"
:is-cate-alert="addCategoryAlert" :is-cate-alert="addCategoryAlert"

View File

@ -1,48 +1,57 @@
<template> <template>
<div class="container-xxl flex-grow-1 container-p-y"> <div class="container-xxl flex-grow-1 container-p-y d-flex">
<div > <!-- 메인 컨텐츠 -->
<!-- 타이틀, 검색 --> <div class="flex-grow-1">
<SearchBar @update:data="search"/> <!-- 타이틀, 검색 -->
<!-- 단어 갯수, 작성하기 --> <SearchBar @update:data="search"/>
<WriteButton ref="writeButton" @click="writeStore.toggleItem(999999)" :isToggleEnabled="true"/> <div class="d-flex">
<!-- --> <!-- 단어 갯수, 작성하기 -->
<DictAlphabetFilter @update:data="handleSelectedAlphabetChange" :indexCategory="indexCategory" :selectedAl="selectedAlphabet" /> <!-- 왼쪽 사이드바 -->
<!-- 카테고리 --> <div class="sidebar position-sticky" style="top: 100px; max-width: 250px; min-width: 250px;">
<div v-if="cateList.length"> <WriteButton ref="writeButton" @click="writeStore.toggleItem(999999)" :isToggleEnabled="true"/>
<CategoryBtn :lists="cateList" @update:data="handleSelectedCategoryChange" :showAll="true" :selectedCategory="selectedCategory" /> <!-- -->
<DictAlphabetFilter @update:data="handleSelectedAlphabetChange" :indexCategory="indexCategory" :selectedAl="selectedAlphabet" />
<!-- 카테고리 -->
<div v-if="cateList.length" class="mt-3">
<CategoryBtn :lists="cateList" @update:data="handleSelectedCategoryChange" :showAll="true" :selectedCategory="selectedCategory" />
</div>
</div> </div>
<!-- 작성 -->
<div v-if="writeStore.isItemActive(999999)" class="mt-5 card p-5"> <!-- 용어 리스트 컨텐츠 -->
<DictWrite @close="writeStore.closeAll()" :dataList="cateList" @addWord="addWord"/> <div class="flex-grow-1">
<!-- 작성 -->
<div v-if="writeStore.isItemActive(999999)" class="ms-3 card p-5">
<DictWrite @close="writeStore.closeAll()" :dataList="cateList" @addWord="addWord"/>
</div>
<!-- 용어 리스트 -->
<div>
<!-- 로딩 중일 -->
<LoadingSpinner v-if="loading"/>
<!-- 에러 메시지 -->
<div v-if="error" class="error">{{ error }}</div>
<!-- 단어 목록 -->
<ul v-if="total > 0" class="ms-3 list-unstyled">
<DictCard
v-for="item in wordList"
:key="item.WRDDICSEQ"
:item="item"
v-model:cateList="cateList"
@refreshWordList="refreshWordList"
@updateChecked="updateCheckedItems"
/>
</ul>
<!-- 데이터가 없을 -->
<div v-if="total == 0" class="text-center mt-5">용어를 선택 / 작성해 주세요</div>
</div>
</div> </div>
</div> </div>
<!-- 용어 리스트 -->
<div >
<!-- 로딩 중일 -->
<LoadingSpinner v-if="loading"/>
<!-- 에러 메시지 -->
<div v-if="error" class="error">{{ error }}</div>
<!-- 단어 목록 -->
<ul v-if="total > 0" class="px-0 list-unstyled">
<DictCard
v-for="item in wordList"
:key="item.WRDDICSEQ"
:item="item"
v-model:cateList="cateList"
@refreshWordList="refreshWordList"
@updateChecked="updateCheckedItems"
/>
</ul>
<!-- 데이터가 없을 -->
<div v-if="total == 0" class="text-center mt-5">용어를 선택 / 작성해 주세요 </div>
</div>
</div> </div>
</div>
<button v-if="isAnyChecked" class="btn btn-danger admin-del-btn" @click="deleteCheckedItems"> <button v-if="isAnyChecked" class="btn btn-danger admin-del-btn" @click="deleteCheckedItems">
<i class="bx bx-trash"></i> <i class="bx bx-trash"></i>
</button> </button>
</template> </template>
@ -255,7 +264,6 @@
</script> </script>
<style scoped> <style scoped>
.admin-del-btn { .admin-del-btn {
position: fixed; position: fixed;
right: 1.5rem; right: 1.5rem;
@ -263,11 +271,15 @@
width: 3rem; width: 3rem;
height: 3rem; height: 3rem;
} }
.error { .error {
color: red; color: red;
font-weight: bold; font-weight: bold;
} }
.sidebar {
position: sticky;
top: 5px;
height: fit-content;
}
@media (max-width: 768px) { @media (max-width: 768px) {
.title { .title {