๐ [GithubPages] Jekyll hydejack Search bar ๊ตฌํ - 4
![๐ [GithubPages] Jekyll hydejack Search bar ๊ตฌํ - 4](/assets/img/thumbnail/githubpages-thumbnail.png)
[GithubPages] Jekyll hydejack Search bar ๊ตฌํ
- โ SimpleJekyllSearch ๊ตฌํ
- 1.
assets/search.json
download link - 2.
_includes/body/menu.html
์๋จ ๋ฉ๋ด search bar์ถ๊ฐ - 3.
_layout/search.html
๋ ์ด์์ ์์ฑ - 4.
search-init.js
์คํฌ๋ฆฝํธ ์์ฑ - 5.
_sass/my-style.css
_sass/_variables.scss
- 6.
search.md
์์ฑ - ๐ Reference
๋ธ๋ก๊ทธ๋ฅผ ์์ํ๋ฉด ์ฌ๋ฌ๊ฐ์ง ๊ธฐ๋ฅ๋ค์ ๊ตฌํํด๋ณด๋ฉด์ ์ฌ๋ฏธ๋ฅผ ๋ถ์ด๊ธฐ ์์ํ๋ค. ์์ผ๋ก study๋ dev๊ธฐ๋ก๋ค์ ํฌ์คํ ํ ์์ ์ด๋ค. ๊ธฐ๋ก๋ค์ด ๋์ด๋๋ค๋ฉด ๋ด๊ฐ ์ ์๋ ๊ธ๋ค์ ์ฝ๊ฒ ์ฐพ์๋ณด๊ธฐ ํ๋ค๊ฒ ๊ฐ์์ Search bar ๊ธฐ๋ฅ์ ๊ตฌํํด๋ณด์ ํ๋ ์๊ฐ์ ์ด ๊ธ์ ์์ฑํ๋ค. ๊ตฌ๊ธ์์ ๊ฒ์ํ๋ค๊ฐ ๋ฐ๊ฒฌํ SimpleJekyllSearch ์คํ ์์ค ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ด์ฉํ์ฌ ๊ฐ๋จํ๊ฒ ๊ตฌํ์ด ๊ฐ๋ฅํ๋ค.
โ SimpleJekyllSearch ๊ตฌํ
1. assets/search.json
download link
# file: `assets/js/search.json`
---
layout: none
---
[
{% for post in site.posts %}
{
"title" : "{{ post.title | escape }}",
"categories": "{{ post.categories | join: ' >> ' }}",
"tags" : "{{ post.tags | join: ', ' }}",
"url": "{{ post.url | prepend: site.baseurl }}",
"date": "{{ post.date | date: '%Y๋
%m์ %d์ผ' }}"
} {% unless forloop.last %},{% endunless %}
{% endfor %}
]
์ด ํ์ผ์ ๊ฒ์์ ์ํํ๊ธฐ ์ํ ๋ฐ์ดํฐ ์์ค๋ก ์ฌ์ฉ๋๋ค.
๊ฒ์ ๋ฐ์ดํฐ๊ฐ ๋ค์๊ณผ ๊ฐ์ format์ผ๋ก ํํ๋๋ฉฐ ์ํ๋ ํํ ๋ฐฉ์์ผ๋ก ์์ ํ๋ฉด ๋๋ค.
1-2. assets/js/simple-jekyll-search.min.js
download link
์ ๊ฒฝ๋ก์ ์ธํ ํด์ค๋ค.
2. _includes/body/menu.html
์๋จ ๋ฉ๋ด search bar์ถ๊ฐ
# file: `_includes/body/menu.html`
<!-- CSS -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.11.1/css/all.min.css" />
<div id="_navbar" class="navbar fixed-top">
<div class="content">
<span class="sr-only">{{ site.data.strings.jump_to | default:"Jump to" }}{{ site.data.strings.colon | default:":" }}</span>
<div class="nav-btn-bar">
<a id="_menu" class="nav-btn no-hover" href="#_drawer--opened">
<span class="sr-only">{{ site.data.strings.navigation | default:"Navigation" }}</span>
<span class="icon-menu"></span>
</a>
<div class="nav-span">
<a href="{{ '/search' | prepend: site.baseurl }}" class="nav-btn no-hover top-menu">
<i class="fas fa-fw fa-search"></i>
<!-- <span>Search</span> -->
</a>
</div>
</div>
</div>
</div>
<hr class="sr-only" hidden />
์๋จ ๋ฉ๋ด์ ๋๋ณด๊ธฐ ๋ชจ์์ด ์ถ๊ฐ๋์๋ค.
3. _layout/search.html
๋ ์ด์์ ์์ฑ
# file: `_layout/search.html`
---
layout: default
title: Search
permalink: /search/
---
<div class="search-page">
<div class="search-header">
<i class="fas fa-search fa-fw search-icon"></i>
<input id="search-input" type="search" placeholder="Search" />
</div>
<ul id="results-container" class="search-results"></ul>
</div>
<ul id="results-container"></ul>
<script src="{{ '/assets/js/simple-jekyll-search.min.js' | relative_url }}"></script>
<script src="{{ '/assets/js/search-init.js' | relative_url }}"></script>
<script>
document.addEventListener('DOMContentLoaded', initSimpleSearch);
document.addEventListener('hy-push-state-load', initSimpleSearch);
initSimpleSearch();
</script>
[!NOTE] /search ํ์ด์ง ์ด๋์ค template ํ์ฑ ์ค๋ฅ๊ฐ ๋ฐ์ํจ. Hydejack ํ ๋ง์์๋ ํ์ด์ง ๋ก๋ฉ์์ด ์ด๋ํ๋ฏ๋ก search.html์์ ์ง์ script๋ฅผ ์ฌ์ฉํ๋ฉด push-state๋ก ๋ก๋ฉ๋ ๋ js๊ฐ ํ์ฑ๋์ง ์๊ณ ์ค๋ฅ๊ฐ ๋ฐ์ํ๋๋ฏ ํ๋ค. ๋ฐ๋ผ์ js(search-init.js์์ฑ)๋ ๋ณ๋๋ก ๋ถ๋ฆฌํ๊ณ
DOMContentLoaded
๋ฐhy-push-state-load
์ด๋ฒคํธ๋ฅผ ๋ชจ๋ ์ฒ๋ฆฌํด์ค์ผ ํ๋ค.
4. search-init.js
์คํฌ๋ฆฝํธ ์์ฑ
# file: _assets/js/search-init.js
function initSimpleSearch() {
const input = document.getElementById('search-input');
const results = document.getElementById('results-container');
if (!input || !results) return;
if (window.simpleJekyllSearchInstance){
// ์ด์ ์ธ์คํด์ค๋ฅผ ์ ๊ฑฐ (๋์ผํ DOM์ ๋ ๋ฒ ์ด๊ธฐํ ๋ฐฉ์ง)
delete window.simpleJekyllSearchInstance;
}
SimpleJekyllSearch({
searchInput: document.getElementById('search-input'),
resultsContainer: document.getElementById('results-container'),
json: '/search.json', // ๋๋ '{{ "/search.json" | relative_url }}'
searchResultTemplate: `
<li class="content-item">
<div class="content-row">
<i class="fas fa-folder fa-fw"></i>
<a href="{url}">{categories}</a>
</div>
<div class="content-row">
<i class="fas fa-book fa-fw"></i>
<a href="{url}">{title}</a>
</div>
<div class="content-row">
<i class="fas fa-tags fa-fw"></i>
<a href="{url}">{tags}</a>
</div>
<div class="content-row">
<i class="fas fa-calendar-alt fa-fw"></i>
<a href="{url}">{date}</a>
</div>
</li>
`,
noResultsText: '๊ฒ์ ๊ฒฐ๊ณผ๊ฐ ์์ต๋๋ค.',
limit: 10,
fuzzy: false
});
}
searchInput
: input ํ๊ทธ์ text๋ฅผ ์ ๋ ฅ๋ฐ๋ ์์resultsContainer
: ๊ฒ์ ๊ฒฐ๊ณผ๊ฐ ๋ ๋๋ง๋์ด์ผ ํ๋ ์์json
: ๊ฒ์ ๋ฐ์ดํฐ๊ฐ json์ ์ง์ ์ ๋ฌ๋๋ค.searchResultTemplate
: ๊ฒ์ ๊ฒฐ๊ณผ ํ ํ๋ฆฟtemplateMiddleware
: ํ ํ๋ฆฟ์์ ์ผ์นํ๋ ํญ๋ชฉ์ด ๋ฐ๊ฒฌ๋ ๋ ํธ์ถ๋๋ ํจ์noResultsText
: ์ผ์นํ๋ ๊ฒ์ ๊ฒฐ๊ณผ๊ฐ ์์ ๊ฒฝ์ฐ ํ์limit
: ๊ฒ์๋ฌผ ์ ์ ํfuzzy
: ๋ ์ผ์นํ๋ ํญ๋ชฉ๋ ๊ฒ์ ์ ๋ false๋ฅผ ์คฌ์ต๋๋ค.exclude
: ๊ฒ์ ์ ์ธํญ๋ชฉ ์ถ๊ฐ
5. _sass/my-style.css
_sass/_variables.scss
๊ธฐ๋ณธ ๊ฒ์ ๋ ์ด์์ ๋์์ธ์ด ์ข์ง์์์ ๐คฃ ๋ณ๋๋ก css๋ฅผ ์ถ๊ฐํ์ต๋๋ค.
# file: `_sass/my-style.css`
.search-page {
max-width: 768px;
margin: 3rem auto;
padding: 2rem;
backdrop-filter: blur(8px);
background: var(--glass-bg);
border-radius: 16px;
box-shadow: 0 4px 24px rgba(0, 0, 0, 0.1);
}
.search-header {
display: flex;
align-items: center;
background-color: var(--card-bg);
padding: 0.8rem 1rem;
border-radius: 12px;
border: 1px solid var(--border);
margin-bottom: 2rem;
transition: border 0.3s ease;
}
.search-header:focus-within {
border-color: var(--accent);
}
.search-icon {
color: var(--icon-color);
font-size: 1.2rem;
margin-right: 0.8rem;
}
#search-input {
flex: 1;
border: none;
font-size: 1.1rem;
background: transparent;
color: var(--text);
outline: none;
}
.search-results {
list-style: none;
padding: 0;
margin: 0;
color: var(--text);
}
.search-results li {
background-color: var(--card-bg);
border: 1px solid var(--border);
border-radius: 10px;
margin-bottom: 1rem;
padding: 1rem;
transition: transform 0.2s ease, background 0.3s ease;
color: var(--text); // ๐ ๋ช
์์ ์ผ๋ก ์ถ๊ฐ
}
.search-results li.no-results {
color: var(--text);
font-style: italic;
opacity: 0.8;
}
.search-results li:hover {
background-color: var(--hover-bg);
transform: translateY(-2px);
}
.search-results a {
color: var(--link);
text-decoration: none;
font-weight: 600;
}
# file: `_sass/_variables.css`
:root {
--glass-bg: rgba(255, 255, 255, 0.8);
--card-bg: #ffffff;
--border: #ddd;
--hover-bg: #f0f0f0;
--text: #111;
--link: #007acc;
--icon-color: #666;
--accent: #007acc;
}
[data-theme="dark"] {
--glass-bg: rgba(30, 30, 30, 0.5);
--card-bg: #2a2a2a;
--border: #444;
--hover-bg: #3a3a3a;
--text: #ddd;
--link: #66ccff;
--icon-color: #aaa;
--accent: #66ccff;
}
hydejack ํ ๋ง๋ dark mode, light mode ์ง์ํ๊ธฐ ๋๋ฌธ์ ์์ ๋ชจ๋์ ๋ฐ๋ผ css๊ฐ ๋ค๋ฅด๊ฒ ์ ์ฉ๋๊ฒ ์ถ๊ฐํ๋ค.
6. search.md
์์ฑ
_pages
ํด๋ ์์ ์์ฑ- ๋ฃจํธ ๋๋ ํฐ๋ฆฌ์ ์์ฑํ๋ฉด ์๋์ธ์ ๋์ง๋ง
_pages
ํด๋ ์์ ๋ฃ์ด์ ๊ด๋ฆฌํ๊ณ ์ถ์ผ๋ฉด _config.yml
์์ collections์ pages ์ถ๊ฐ
# file: '_config.yml'
collections:
pages:
output: true
permalink: /:name/
# file: `_pages/search.md`
---
layout: search
title: Search
permalink: /search/
---
search.md ์์ฑํ์ฌ search.html ๋ ์ด์์์ ์ฐ๊ฒฐํ๋ค.
Search ๊ธฐ๋ฅ์ด ์ ์๋๋๋์ง ํ์ธ๐ค