Skip to content

Commit

Permalink
♻️ 태그 실시간 검색 추가 및 소식 탭 디자인 수정 (#137)
Browse files Browse the repository at this point in the history
* design: 검색박스 디자인 수정

* fix: 태그 실시간 검색 추가

* desing: 세미나 검색창 디자인 수정

* deisgn: 세미나 목록 디자인 수정

* design: 검색창 자동완성 배경색수정
  • Loading branch information
Limchansol authored Feb 19, 2024
1 parent ad2c86c commit c35783c
Show file tree
Hide file tree
Showing 14 changed files with 142 additions and 176 deletions.
24 changes: 16 additions & 8 deletions components/common/Tags.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,19 @@ interface TagsProps {
tags: string[];
margin?: string;
searchPath?: string;
disabled?: boolean;
onClick?: (tag: string) => void;
onDelete?: (tag: string) => void;
}

export default function Tags({ tags, margin = '', searchPath }: TagsProps) {
export default function Tags({
tags,
margin = '',
searchPath,
disabled,
onClick,
onDelete,
}: TagsProps) {
return (
<div className={`flex flex-wrap items-center gap-2.5 ${margin}`}>
{searchPath
Expand All @@ -17,7 +27,9 @@ export default function Tags({ tags, margin = '', searchPath }: TagsProps) {
<Tag tag={tag} hoverStyle="fill" />
</Link>
))
: tags.map((tag) => <Tag key={tag} tag={tag} />)}
: tags.map((tag) => (
<Tag key={tag} tag={tag} disabled={disabled} onClick={onClick} onDelete={onDelete} />
))}
</div>
);
}
Expand Down Expand Up @@ -70,13 +82,9 @@ export function Tag({
<button
className={`flex items-center h-full pl-1 pr-2.5 text-main-orange enabled:hover:text-neutral-400 enabled:active:text-main-orange`}
disabled={disabled}
onClick={() => !disabled && onDelete(tag)}
>
<span
className="material-symbols-outlined text-xs"
onClick={() => !disabled && onDelete(tag)}
>
close
</span>
<span className="material-symbols-outlined text-xs">close</span>
</button>
)}
</span>
Expand Down
34 changes: 7 additions & 27 deletions components/common/search/KeywordInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ interface KeywordInputProps {

export default function KeywordInput({ keyword, setKeyword, disabled = false }: KeywordInputProps) {
return (
<div className="col-start-1 flex items-center">
<h5 className="font-yoon text-md font-bold mr-3 whitespace-nowrap tracking-wide">검색어</h5>
<div className="flex items-center">
<h5 className="text-md font-bold mr-7 whitespace-nowrap tracking-wide">검색</h5>
<Input keyword={keyword} disabled={disabled} onChange={setKeyword} />
</div>
);
Expand All @@ -24,40 +24,20 @@ interface InputProps {
function Input({ keyword, disabled, onChange }: InputProps) {
const inputRef = useRef<HTMLInputElement>(null);

const resetKeyword = () => {
onChange('');
inputRef.current?.focus();
};

return (
<div className="relative w-fit">
<div className="relative bg-white flex items-center justify-between h-[1.875rem] w-[13.5rem] rounded-sm pr-3">
<input
type="text"
id="search"
ref={inputRef}
className={`${
keyword ? 'pl-1.5 pr-6' : 'px-1.5'
} w-[13.5rem] h-[1.875rem] rounded-sm text-[13px] tracking-wide bg-white autofill-bg-white outline-none`}
className={`rounded-sm px-2 w-full text-sm tracking-wide bg-transparent autofill-bg-white outline-none`}
value={keyword}
disabled={disabled}
onChange={(e) => onChange(e.target.value)}
/>
{keyword && !disabled && <ResetKeywordButton onClick={resetKeyword} />}
<button className="material-symbols-rounded text-[1.25rem] font-light text-neutral-800 hover:text-neutral-500">
search
</button>
</div>
);
}

interface ResetKeywordButtonProps {
onClick: () => void;
}

function ResetKeywordButton({ onClick }: ResetKeywordButtonProps) {
return (
<span
className="material-symbols-outlined absolute top-[8px] right-1.5 text-neutral-400 hover:text-neutral-700 text-md cursor-pointer"
onClick={onClick}
>
close
</span>
);
}
31 changes: 6 additions & 25 deletions components/common/search/SearchBox.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { FormEvent, useState } from 'react';
import { useState } from 'react';

import { StraightNode } from '@/components/common/Nodes';

Expand All @@ -23,43 +23,24 @@ export default function SearchBox({
setSearchParams,
}: SearchBoxProps) {
const [keyword, setKeyword] = useState<string>(initKeyword);
const [selectedTags, setSelectedTags] = useState<string[]>(initTags);

const search = (e: FormEvent<HTMLFormElement>) => {
e.preventDefault();
const info: SearchInfo = { purpose: 'search', keyword, tag: selectedTags };
const search = (tags?: string[]) => {
const info: SearchInfo = { purpose: 'search', keyword, tag: tags ?? initTags };
setSearchParams(info);
};

const resetTags = () => {
setSelectedTags([]);
setSearchParams({ purpose: 'search', keyword });
};

const deleteTag = (targetTag: string) => {
const filteredTags = selectedTags.filter((tag) => tag !== targetTag);
setSelectedTags(filteredTags);
setSearchParams({ purpose: 'search', keyword, tag: filteredTags });
};

return (
<div className={`mb-9 w-full ${disabled && 'opacity-30'}`}>
<SearchForm
disabled={disabled}
onSubmit={search}
search={search}
tags={tags}
selectedTags={selectedTags}
setSelectedTags={setSelectedTags}
selectedTags={initTags}
keyword={keyword}
setKeyword={setKeyword}
/>
<StraightNode double={true} margin="mt-9 mb-3" />
<SelectedTags
tags={initTags}
deleteTag={deleteTag}
resetTags={resetTags}
disabled={disabled}
/>
<SelectedTags tags={initTags} search={search} disabled={disabled} />
</div>
);
}
34 changes: 9 additions & 25 deletions components/common/search/SearchForm.tsx
Original file line number Diff line number Diff line change
@@ -1,51 +1,35 @@
import { Dispatch, FormEvent, SetStateAction } from 'react';
import { Dispatch, SetStateAction } from 'react';

import KeywordInput from './KeywordInput';
import TagFilter from './TagFilter';

interface SearchFormProps {
disabled: boolean;
onSubmit: (e: FormEvent<HTMLFormElement>) => void;
search: (tags?: string[]) => void;
tags: string[];
selectedTags: string[];
setSelectedTags: Dispatch<SetStateAction<string[]>>;
keyword: string;
setKeyword: Dispatch<SetStateAction<string>>;
}

export default function SearchForm({
disabled,
onSubmit,
search,
tags,
selectedTags,
setSelectedTags,
keyword,
setKeyword,
}: SearchFormProps) {
return (
<form
className="grid grid-cols-[auto_1fr_auto] grid-rows-auto gap-y-5 p-6 min-w-max bg-neutral-100"
onSubmit={onSubmit}
className="flex flex-col gap-5 p-6 min-w-max bg-neutral-100"
onSubmit={(e) => {
e.preventDefault();
search();
}}
>
<TagFilter
tags={tags}
selectedTags={selectedTags}
setSelectedTags={setSelectedTags}
disabled={disabled}
/>
<TagFilter tags={tags} selectedTags={selectedTags} disabled={disabled} searchTags={search} />
<KeywordInput keyword={keyword} setKeyword={setKeyword} disabled={disabled} />
<SearchButton disabled={disabled} />
</form>
);
}

function SearchButton({ disabled }: { disabled: boolean }) {
return (
<button
className="col-start-3 px-3 py-[0.1875rem] rounded-[0.0625rem] bg-neutral-200 enabled:hover:bg-neutral-300 font-semibold text-xs tracking-wider"
disabled={disabled}
>
결과 보기
</button>
);
}
45 changes: 19 additions & 26 deletions components/common/search/SelectedTags.tsx
Original file line number Diff line number Diff line change
@@ -1,38 +1,31 @@
import { Tag } from '../Tags';
import Tags from '../Tags';

interface SelectedTagsProps {
tags: string[];
deleteTag: (tag: string) => void;
resetTags: () => void;
search: (tags: string[]) => void;
disabled: boolean;
}

export default function SelectedTags({ tags, deleteTag, resetTags, disabled }: SelectedTagsProps) {
return (
<div className="flex justify-between items-start gap-3 px-2.5">
<Tags tags={tags.length ? tags : ['전체']} deleteTag={deleteTag} disabled={disabled} />
{tags.length > 0 && <TagResetButton onClick={resetTags} disabled={disabled} />}
</div>
);
}
export default function SelectedTags({ tags, search, disabled }: SelectedTagsProps) {
const isTagExist = tags.length > 0;

interface TagsProps {
tags: string[];
disabled: boolean;
deleteTag: (tag: string) => void;
}
const deleteTag = (targetTag: string) => {
const filteredTags = tags.filter((tag) => tag !== targetTag);
search(filteredTags);
};

const resetTags = () => {
search([]);
};

function Tags({ tags, disabled, deleteTag }: TagsProps) {
return (
<div className={`flex flex-wrap items-center gap-2.5`}>
{tags.map((tag) => (
<Tag
key={tag}
tag={tag}
onDelete={tag === '전체' ? undefined : deleteTag}
disabled={disabled}
/>
))}
<div className="flex justify-between items-start gap-3 px-2.5">
<Tags
tags={isTagExist ? tags : ['전체']}
onDelete={isTagExist ? deleteTag : undefined}
disabled={disabled}
/>
{tags.length > 0 && <TagResetButton onClick={resetTags} disabled={disabled} />}
</div>
);
}
Expand Down
23 changes: 7 additions & 16 deletions components/common/search/TagFilter.tsx
Original file line number Diff line number Diff line change
@@ -1,35 +1,26 @@
import { SetStateAction } from 'react';

import Checkbox from '../Checkbox';

interface TagFilterProps {
tags: string[];
selectedTags: string[];
setSelectedTags: React.Dispatch<SetStateAction<string[]>>;
disabled: boolean;
searchTags: (tags: string[]) => void;
}

// TODO: 나중에 태그 확정되면 반응형 추가해서 수정
const gridStyle = 'grid-cols-[repeat(6,_max-content)]';

export default function TagFilter({
tags,
selectedTags,
setSelectedTags,
disabled,
}: TagFilterProps) {
export default function TagFilter({ tags, selectedTags, disabled, searchTags }: TagFilterProps) {
const toggleCheck = (tag: string, isChecked: boolean) => {
isChecked
? setSelectedTags((prev) => [...prev, tag])
: setSelectedTags(selectedTags.filter((t) => t !== tag));
? searchTags([...selectedTags, tag])
: searchTags(selectedTags.filter((t) => t !== tag));
};

return (
<div className="flex row-span-1 col-span-full">
<h5 className="text-md font-bold whitespace-nowrap mr-6 text-neutral-800 tracking-wide">
태그
</h5>
<div className={`grow grid ${gridStyle} gap-x-7 gap-y-2.5`}>
<div>
<h5 className="mb-3 mr-6 text-md font-bold whitespace-nowrap tracking-wide">태그</h5>
<div className={`grow grid ${gridStyle} gap-x-7 gap-y-2.5 pl-2.5`}>
{tags.map((tag) => (
<Checkbox
key={tag}
Expand Down
4 changes: 1 addition & 3 deletions components/news/NewsPageContent.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
'use client';

import Link from 'next/link';

import Pagination from '@/components/common/Pagination';
import SearchBox from '@/components/common/search/SearchBox';
import PageLayout from '@/components/layout/pageLayout/PageLayout';
Expand Down Expand Up @@ -42,7 +40,7 @@ export default function NewsPageContent({
initKeyword={keyword ?? ''}
setSearchParams={setSearchParams}
/>
<div className="flex flex-col gap-4 mt-10 mb-8 mx-2.5">
<div className="flex flex-col gap-4 mt-10 mb-8 mx-16">
{searchList.length > 0 ? (
searchList.map((post) => (
<NewsRow
Expand Down
26 changes: 15 additions & 11 deletions components/seminar/SearchBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,18 +23,22 @@ export default function SeminarSearchBar({ keyword, setSearchParams }: SeminarSe
};

return (
<form className="flex w-fit" onSubmit={searchText}>
<input
type="text"
id="search"
className="outline-none border border-neutral-300 rounded-l-sm text-xs w-[13.5rem] h-8 px-2 bg-transparent placeholder:text-neutral-300 tracking-[0.02em] autofill-bg-white"
placeholder="세미나 키워드"
value={text}
onChange={handleChange}
/>
<button className="flex justify-center items-center py-[.1875rem] px-3 h-8 border-y border-r border-neutral-300 rounded-r-sm font-bold text-xs tracking-[0.02em]">
<form className="flex w-fit gap-5 items-center" onSubmit={searchText}>
<label htmlFor="search" className="font-bold">
검색
</button>
</label>
<div className="rounded-sm bg-neutral-100 flex items-center w-60 h-[1.875rem] pr-3">
<input
type="text"
id="search"
className="outline-none rounded-sm w-full text-sm px-2 bg-transparent tracking-wide autofill-bg-neutral-100"
value={text}
onChange={handleChange}
/>
<button className="material-symbols-rounded text-[1.25rem] font-light text-neutral-800 hover:text-neutral-500">
search
</button>
</div>
</form>
);
}
Loading

0 comments on commit c35783c

Please sign in to comment.