검색 기능 추가(Add search function to my blog)

Posted by Eun JongHyeok on April 17, 2022
  1. Create search.json
  2. Preparing the plugin
    1. Usage

블로그 꾸미다 검색기능이 있으면 좋을꺼 같다 생각했는데 오픈소스 라이브러리가 있어 사용하기로 했습니다.
일단 깃헙에서 설명문을 보며 필요한 부분만 찾아보도록 합시다.

Create search.json

search.json 파일을 만들어 블로그의 루트파일에 넣어주어야 합니다.
이 파일을 통해 정렬에 사용할 객체를 생성해줍니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
---
layout: none
---
[  
  {% for post in site.posts %}
    {
      "title"    : "{{ post.title | escape }}",
      "category" : "{{ post.category }}",
      "tags"     : "{{ post.tags | join: ', ' }}",
      "url"      : "{{ site.baseurl }}{{ post.url }}",
      "date"     : "{{ post.date | date: '%m/%d/%Y' }}"
    } {% unless forloop.last %},{% endunless %}
  {% endfor %} 
]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
---
layout: none
---
[
  {% for post in site.posts %}
    {
      "title"    : "{{ post.title | escape }}",
      "category" : "{{ post.category }}",
      "tags"     : "{{ post.tags | join: ', ' }}",
      "url"      : "{{ site.baseurl }}{{ post.url }}",
      "date"     : "{{ post.date }}",
      "content"  : "{{ post.content | remove_chars | escape | strip_html | strip_newlines | remove: '\' }}"
    } {% unless forloop.last %},{% endunless %}
  {% endfor %}
  ,
  {% for page in site.pages %}
   {
     {% if page.title != nil %}
        "title"    : "{{ page.title | escape }}",
        "category" : "{{ page.category }}",
        "tags"     : "{{ page.tags | join: ', ' }}",
        "url"      : "{{ site.baseurl }}{{ page.url }}",
        "date"     : "{{ page.date }}",
        "content"  : "{{ page.content | remove_chars | escape | strip_html | strip_newlines | remove: '\' }}"
     {% endif %}
   } {% unless forloop.last %},{% endunless %}
  {% endfor %}
]

모든 텍스트에서 찾기위해서 처음에는 두번째처럼 설정했었는데 검색 결과가 만족스럽지 않아 첫번째 코드를 사용하려합니다.
두번째 코드에서 remove: ‘\‘를 추가한 이유는 content 텍스트에 해당 단어가 포함되어 있으면 json파일이 깨지기 때문입니다.
또한 Mac 환경과 Windows 환경을 왔다갔다해서 그런지 일부 텍스트 중 Tab과 스페이스가 혼합되어 json을 제대로 못 만드는 경우가 있어 Tab을 모두 space로 변경해주었습니다.

Preparing the plugin

다음으로 해줄 일은 플러그인에 필요한 DOM(문서 객체 모델)을 만들어주어야 합니다.
필요한 DOM은

  • 검색 인풋 필드
  • 검색 결과를 담을 컨테이너

입니다.
직접 구현해줄 수도 있고 라이브러리에서 제공하는 js파일을 사용할 수 있습니다.

1
2
3
4
5
6
<!-- HTML elements for search -->
<input type="text" id="search-input" placeholder="Search blog posts..">
<ul id="results-container"></ul>

<!-- or without installing anything -->
<script src="https://unpkg.com/simple-jekyll-search@latest/dest/simple-jekyll-search.min.js"></script>

저는 기본으로 제공하는 스타일보다 다른 스타일을 적용하도록 하겠습니다.

검색 인풋 필드에 Material Design 적용하기

https://material.io/components/text-fields를 적용해보려 합니다.
cdn을 이용해서 다음과 같이 빠르게 적용해볼 수 있습니다.
link를 해주고

1
2
3
<link href="https://unpkg.com/material-components-web@latest/dist/material-components-web.min.css" rel="stylesheet">
<script src="https://unpkg.com/material-components-web@latest/dist/material-components-web.min.js"></script>
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons">

자신이 원하는 모양을 적용해줍니다.

1
2
3
4
5
<label class="mdc-text-field mdc-text-field--filled">
        <span class="mdc-text-field__ripple"></span>
        <input class="mdc-text-field__input" type="text" id="search-input" placeholder="Search Keyword" size="120" aria-label="Label"></textarea>
        <span class="mdc-line-ripple"></span>
</label>

결과를 담을 컨테이너에 Material Design 적용하기

결과 리스트도 통일성을 위해 material을 적용하도록 하겠습니다.
저는 https://material.io/components/lists를 사용하려 합니다.

1
<ul class="mdc-list mdc-list--two-line" id="results-container"></ul>

리스트를 담을 컨테이너만 선언해주고 템플릿은 이후 과정에서 추가해줍니다.

Usage

SimpleJekyllSearch 함수의 옵션들을 살펴보면서 사용해 봅니다.
searchInput
위에서 원하는 엘리먼트에 id="search-input"를 지정하고 document.getElementById('search-input')와 같이 선언하여 매칭합니다.

resultsContainer
일반적으로 <ul>을 사용합니다. searchInput처럼 document.getElementById('results-container')와 같이 선언하여 매칭합니다.

json
search.json로 설정해줍니다.

searchResultTemplate
이 부분이 위에서 설명한 results-container에 담을 리스트 형태를 지정해줍니다.
저는 이런식으로 사용하려합니다.

1
2
3
4
5
6
7
8
9
`
<li class="mdc-list-item">
    <span class="mdc-list-item__ripple"></span>
    <span class="mdc-list-item__text">
        <a href="{url}"><span class="mdc-list-item__primary-text">{title}</span></a>
        <span class="mdc-list-item__secondary-text"><i class="fa fa-tag"></i> {tags}</span>
    </span>
</li><hr>
`

templateMiddleware
템플릿에서 일치하는 항목이 발견될 때 호출하는 함수를 정의할 수 있습니다.
해당 속성의 이름, 값과 템플릿이 전달됩니다.
함수가 정의하지 않은 값을 반환하면 해당 값으로 템플릿에서 반환됩니다.
주로 URL 조작등에 사용한다고 합니다.

sortMiddleware
필터링된 결과를 정렬하는데 사용할 수 있는 함수입니다. 아마 우선순위를 세팅하는 것 같은데 정말 간단하게 날짜로 해봅니다.

noResultsText
결과가 없을때 출력할 텍스트입니다. 샘플과 동일하게 ‘No results found’ 를 추가하였습니다.

limit
결과 개수 제한입니다. 넉넉하게 30으로 하였습니다.

fuzzy
좀더 유연한 검색을 가능하게 해줍니다. 저는 false로 세팅하여 엄격하게 제한하도록 하려합니다.

exclude
제외하고 싶은 문구를 추가할 수 있습니다. 굳이 필요없어 보여 넘어가도록 하겠습니다.

success
데이터가 로드되었을 때 호출해주고 싶은 함수를 추가할 수 있습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<script src="/js/simple-jekyll-search.js"></script>

<script type="text/javascript">
        SimpleJekyllSearch({
          searchInput: document.getElementById('search-input'),
          resultsContainer: document.getElementById('results-container'),
          json: '/search.json',
          searchResultTemplate: `
              <li class="mdc-list-item">
                <span class="mdc-list-item__ripple"></span>
                <span class="mdc-list-item__text">
                  <a href="{url}"><span class="mdc-list-item__primary-text">{title}</span></a>
                  <span class="mdc-list-item__secondary-text">{date}, <i class="fa fa-tag"></i>{tags}</span>
                </span>
              </li><hr>
          `,
          sortMiddleware: function(a, b) {
            var adate = String(a.date);
            var bdate = String(b.date);
            return adate.localeCompare(bdate)
          },
          noResultsText: 'No results found',
          limit: 30,
          fuzzy: false
        })
</script>

제가 만들고 싶은대로 필요한부분만 채워보았습니다.
simple-jekyll-search.js는 샘플 프로젝트에서 그대로 가져왔습니다.
날짜순으로 정렬된 것도 확인하였고 결과가 그럭저럭 괜찮게 나왔습니다.
search.png


SimpleJekyllSearch
material_io

← Previous Post Next Post