mirror of
https://github.com/yhirose/cpp-httplib.git
synced 2026-10-21 11:39:48 +00:00
Add search functionality across documentation pages
- Implemented a search button in the header of each documentation page. - Added a search modal that allows users to input search queries. - Integrated a JavaScript search feature that fetches and displays results from a new `pages-data.json` file. - Each documentation page now includes a search overlay for improved navigation. - Updated the main JavaScript file to handle search logic, including result highlighting and navigation. - Created a `pages-data.json` file containing metadata for all documentation pages to facilitate search functionality.
This commit is contained in:
1 parent
cda9680cdc
commit
843ad379c7
31 files changed
+1154
No files matched your search
@@ -450,3 +450,148 @@ a:hover {
|
|||||||
.theme-toggle:hover {
|
.theme-toggle:hover {
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Search button */
|
||||||
|
.search-btn {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
background: none;
|
||||||
|
border: none;
|
||||||
|
color: var(--text);
|
||||||
|
padding: 5px 6px;
|
||||||
|
border-radius: 4px;
|
||||||
|
cursor: pointer;
|
||||||
|
opacity: 0.8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-btn:hover {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Search overlay & modal */
|
||||||
|
.search-overlay {
|
||||||
|
display: none;
|
||||||
|
position: fixed;
|
||||||
|
inset: 0;
|
||||||
|
background: rgba(0, 0, 0, 0.5);
|
||||||
|
z-index: 300;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: flex-start;
|
||||||
|
padding-top: 12vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-overlay.open {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-modal {
|
||||||
|
background: var(--bg-secondary);
|
||||||
|
border: 1px solid var(--border);
|
||||||
|
border-radius: 8px;
|
||||||
|
width: 90%;
|
||||||
|
max-width: 560px;
|
||||||
|
box-shadow: 0 8px 30px rgba(0, 0, 0, 0.4);
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-input-wrap {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
padding: 12px 16px;
|
||||||
|
border-bottom: 1px solid var(--border);
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-input-wrap svg {
|
||||||
|
flex-shrink: 0;
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
#search-input {
|
||||||
|
flex: 1;
|
||||||
|
background: none;
|
||||||
|
border: none;
|
||||||
|
outline: none;
|
||||||
|
color: var(--text-bright);
|
||||||
|
font-size: 1rem;
|
||||||
|
font-family: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
#search-input::placeholder {
|
||||||
|
color: var(--text-muted);
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-esc {
|
||||||
|
background: var(--bg);
|
||||||
|
color: var(--text-muted);
|
||||||
|
padding: 2px 6px;
|
||||||
|
border-radius: 3px;
|
||||||
|
font-size: 0.7rem;
|
||||||
|
border: 1px solid var(--border);
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-results {
|
||||||
|
list-style: none;
|
||||||
|
max-height: 50vh;
|
||||||
|
overflow-y: auto;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-results:empty::after {
|
||||||
|
content: "";
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-results li {
|
||||||
|
padding: 10px 16px;
|
||||||
|
cursor: pointer;
|
||||||
|
border-bottom: 1px solid var(--border);
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-results li:last-child {
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-results li:hover,
|
||||||
|
.search-results li.active {
|
||||||
|
background: var(--bg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-results li .search-result-title {
|
||||||
|
color: var(--text-bright);
|
||||||
|
font-weight: 600;
|
||||||
|
font-size: 0.9rem;
|
||||||
|
margin-bottom: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-results li .search-result-snippet {
|
||||||
|
color: var(--text-muted);
|
||||||
|
font-size: 0.8rem;
|
||||||
|
line-height: 1.4;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
display: -webkit-box;
|
||||||
|
-webkit-line-clamp: 2;
|
||||||
|
-webkit-box-orient: vertical;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-results li .search-result-snippet mark {
|
||||||
|
background: rgba(255, 215, 0, 0.3);
|
||||||
|
color: var(--text-bright);
|
||||||
|
border-radius: 2px;
|
||||||
|
padding: 0 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-theme="light"] .search-results li .search-result-snippet mark {
|
||||||
|
background: rgba(255, 200, 0, 0.4);
|
||||||
|
color: var(--text);
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-no-results {
|
||||||
|
padding: 24px 16px;
|
||||||
|
text-align: center;
|
||||||
|
color: var(--text-muted);
|
||||||
|
font-size: 0.9rem;
|
||||||
|
}
|
||||||
@@ -78,3 +78,220 @@
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
})();
|
})();
|
||||||
|
|
||||||
|
// Site search (⌘K / Ctrl+K)
|
||||||
|
(function () {
|
||||||
|
var overlay = document.getElementById('search-overlay');
|
||||||
|
var input = document.getElementById('search-input');
|
||||||
|
var resultsList = document.getElementById('search-results');
|
||||||
|
if (!overlay || !input || !resultsList) return;
|
||||||
|
|
||||||
|
var searchBtn = document.querySelector('.search-btn');
|
||||||
|
var pagesData = null; // cached pages-data.json
|
||||||
|
var activeIndex = -1;
|
||||||
|
|
||||||
|
function getCurrentLang() {
|
||||||
|
return document.documentElement.getAttribute('lang') || 'en';
|
||||||
|
}
|
||||||
|
|
||||||
|
function getBasePath() {
|
||||||
|
return document.documentElement.getAttribute('data-base-path') || '';
|
||||||
|
}
|
||||||
|
|
||||||
|
function openSearch() {
|
||||||
|
overlay.classList.add('open');
|
||||||
|
input.value = '';
|
||||||
|
resultsList.innerHTML = '';
|
||||||
|
activeIndex = -1;
|
||||||
|
input.focus();
|
||||||
|
loadPagesData();
|
||||||
|
}
|
||||||
|
|
||||||
|
function closeSearch() {
|
||||||
|
overlay.classList.remove('open');
|
||||||
|
input.value = '';
|
||||||
|
resultsList.innerHTML = '';
|
||||||
|
activeIndex = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
function loadPagesData() {
|
||||||
|
if (pagesData) return;
|
||||||
|
var basePath = getBasePath();
|
||||||
|
fetch(basePath + '/pages-data.json')
|
||||||
|
.then(function (res) { return res.json(); })
|
||||||
|
.then(function (data) { pagesData = data; })
|
||||||
|
.catch(function () { pagesData = []; });
|
||||||
|
}
|
||||||
|
|
||||||
|
function escapeRegExp(s) {
|
||||||
|
return s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
||||||
|
}
|
||||||
|
|
||||||
|
function highlightText(text, query) {
|
||||||
|
if (!query) return text;
|
||||||
|
var escaped = escapeRegExp(query);
|
||||||
|
var re = new RegExp('(' + escaped + ')', 'gi');
|
||||||
|
return text.replace(re, '<mark>$1</mark>');
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildSnippet(body, query) {
|
||||||
|
if (!query || !body) return '';
|
||||||
|
var lower = body.toLowerCase();
|
||||||
|
var idx = lower.indexOf(query.toLowerCase());
|
||||||
|
var start, end, snippet;
|
||||||
|
if (idx === -1) {
|
||||||
|
snippet = body.substring(0, 120);
|
||||||
|
} else {
|
||||||
|
start = Math.max(0, idx - 40);
|
||||||
|
end = Math.min(body.length, idx + query.length + 80);
|
||||||
|
snippet = (start > 0 ? '...' : '') + body.substring(start, end) + (end < body.length ? '...' : '');
|
||||||
|
}
|
||||||
|
return highlightText(snippet, query);
|
||||||
|
}
|
||||||
|
|
||||||
|
function search(query) {
|
||||||
|
if (!pagesData || !query) {
|
||||||
|
resultsList.innerHTML = '';
|
||||||
|
activeIndex = -1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var lang = getCurrentLang();
|
||||||
|
var q = query.toLowerCase();
|
||||||
|
|
||||||
|
// Score and filter
|
||||||
|
var scored = [];
|
||||||
|
for (var i = 0; i < pagesData.length; i++) {
|
||||||
|
var page = pagesData[i];
|
||||||
|
if (page.lang !== lang) continue;
|
||||||
|
|
||||||
|
var score = 0;
|
||||||
|
var titleLower = page.title.toLowerCase();
|
||||||
|
var bodyLower = (page.body || '').toLowerCase();
|
||||||
|
|
||||||
|
if (titleLower.indexOf(q) !== -1) {
|
||||||
|
score += 10;
|
||||||
|
// Bonus for exact title match
|
||||||
|
if (titleLower === q) score += 5;
|
||||||
|
}
|
||||||
|
if (bodyLower.indexOf(q) !== -1) {
|
||||||
|
score += 3;
|
||||||
|
}
|
||||||
|
if (page.section.toLowerCase().indexOf(q) !== -1) {
|
||||||
|
score += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (score > 0) {
|
||||||
|
scored.push({ page: page, score: score });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sort by score descending
|
||||||
|
scored.sort(function (a, b) { return b.score - a.score; });
|
||||||
|
|
||||||
|
// Limit results
|
||||||
|
var results = scored.slice(0, 20);
|
||||||
|
|
||||||
|
if (results.length === 0) {
|
||||||
|
resultsList.innerHTML = '<li class="search-no-results">No results found.</li>';
|
||||||
|
activeIndex = -1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var html = '';
|
||||||
|
for (var j = 0; j < results.length; j++) {
|
||||||
|
var r = results[j];
|
||||||
|
var snippet = buildSnippet(r.page.body, query);
|
||||||
|
html += '<li data-url="' + r.page.url + '">'
|
||||||
|
+ '<div class="search-result-title">' + highlightText(r.page.title, query) + '</div>'
|
||||||
|
+ (snippet ? '<div class="search-result-snippet">' + snippet + '</div>' : '')
|
||||||
|
+ '</li>';
|
||||||
|
}
|
||||||
|
resultsList.innerHTML = html;
|
||||||
|
activeIndex = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
function setActive(index) {
|
||||||
|
var items = resultsList.querySelectorAll('li[data-url]');
|
||||||
|
if (items.length === 0) return;
|
||||||
|
// Remove previous active
|
||||||
|
for (var i = 0; i < items.length; i++) {
|
||||||
|
items[i].classList.remove('active');
|
||||||
|
}
|
||||||
|
if (index < 0) index = items.length - 1;
|
||||||
|
if (index >= items.length) index = 0;
|
||||||
|
activeIndex = index;
|
||||||
|
items[activeIndex].classList.add('active');
|
||||||
|
items[activeIndex].scrollIntoView({ block: 'nearest' });
|
||||||
|
}
|
||||||
|
|
||||||
|
function navigateToActive() {
|
||||||
|
var items = resultsList.querySelectorAll('li[data-url]');
|
||||||
|
if (activeIndex >= 0 && activeIndex < items.length) {
|
||||||
|
var url = items[activeIndex].getAttribute('data-url');
|
||||||
|
if (url) {
|
||||||
|
closeSearch();
|
||||||
|
window.location.href = url;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Event: search button
|
||||||
|
if (searchBtn) {
|
||||||
|
searchBtn.addEventListener('click', function (e) {
|
||||||
|
e.stopPropagation();
|
||||||
|
openSearch();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use capture phase to intercept keys before browser default behavior
|
||||||
|
// (e.g. ESC clearing input text in some browsers)
|
||||||
|
document.addEventListener('keydown', function (e) {
|
||||||
|
if ((e.metaKey || e.ctrlKey) && e.key === 'k') {
|
||||||
|
e.preventDefault();
|
||||||
|
overlay.classList.contains('open') ? closeSearch() : openSearch();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!overlay.classList.contains('open')) return;
|
||||||
|
if (e.key === 'Escape') {
|
||||||
|
e.preventDefault();
|
||||||
|
closeSearch();
|
||||||
|
} else if (e.key === 'ArrowDown') {
|
||||||
|
e.preventDefault();
|
||||||
|
setActive(activeIndex + 1);
|
||||||
|
} else if (e.key === 'ArrowUp') {
|
||||||
|
e.preventDefault();
|
||||||
|
setActive(activeIndex - 1);
|
||||||
|
} else if (e.key === 'Enter') {
|
||||||
|
e.preventDefault();
|
||||||
|
navigateToActive();
|
||||||
|
}
|
||||||
|
}, true); // capture phase
|
||||||
|
|
||||||
|
// Event: click overlay background to close
|
||||||
|
overlay.addEventListener('click', function (e) {
|
||||||
|
if (e.target === overlay) {
|
||||||
|
closeSearch();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Event: click result item
|
||||||
|
resultsList.addEventListener('click', function (e) {
|
||||||
|
var li = e.target.closest('li[data-url]');
|
||||||
|
if (!li) return;
|
||||||
|
var url = li.getAttribute('data-url');
|
||||||
|
if (url) {
|
||||||
|
closeSearch();
|
||||||
|
window.location.href = url;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Event: input for live search
|
||||||
|
var debounceTimer = null;
|
||||||
|
input.addEventListener('input', function () {
|
||||||
|
clearTimeout(debounceTimer);
|
||||||
|
debounceTimer = setTimeout(function () {
|
||||||
|
search(input.value.trim());
|
||||||
|
}, 150);
|
||||||
|
});
|
||||||
|
})();
|
||||||
@@ -39,6 +39,9 @@
|
|||||||
{% endfor %}
|
{% endfor %}
|
||||||
</nav>
|
</nav>
|
||||||
<div class="header-tools">
|
<div class="header-tools">
|
||||||
|
<button class="search-btn" aria-label="Search (⌘K)">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>
|
||||||
|
</button>
|
||||||
<button class="theme-toggle" aria-label="Toggle theme"></button>
|
<button class="theme-toggle" aria-label="Toggle theme"></button>
|
||||||
<div class="lang-selector">
|
<div class="lang-selector">
|
||||||
<button class="lang-btn" aria-label="Language">
|
<button class="lang-btn" aria-label="Language">
|
||||||
@@ -68,6 +71,18 @@
|
|||||||
© 2026 yhirose. All rights reserved.
|
© 2026 yhirose. All rights reserved.
|
||||||
</footer>
|
</footer>
|
||||||
|
|
||||||
|
<!-- Search modal -->
|
||||||
|
<div class="search-overlay" id="search-overlay">
|
||||||
|
<div class="search-modal">
|
||||||
|
<div class="search-input-wrap">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>
|
||||||
|
<input type="text" id="search-input" placeholder="Search..." autocomplete="off" spellcheck="false">
|
||||||
|
<kbd class="search-esc">ESC</kbd>
|
||||||
|
</div>
|
||||||
|
<ul class="search-results" id="search-results"></ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<script src="{{ site.base_path }}/js/main.js"></script>
|
<script src="{{ site.base_path }}/js/main.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
@@ -15,6 +15,17 @@ struct PageContext {
|
|||||||
status: Option<String>,
|
status: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Entry for pages-data.json used by client-side search.
|
||||||
|
#[derive(Debug, Serialize)]
|
||||||
|
struct PageDataEntry {
|
||||||
|
title: String,
|
||||||
|
url: String,
|
||||||
|
lang: String,
|
||||||
|
section: String,
|
||||||
|
/// Plain-text body with HTML tags stripped (truncated to ~500 chars).
|
||||||
|
body: String,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Clone)]
|
#[derive(Debug, Serialize, Clone)]
|
||||||
struct NavItem {
|
struct NavItem {
|
||||||
title: String,
|
title: String,
|
||||||
@@ -62,6 +73,9 @@ pub fn build(src: &Path, out: &Path) -> Result<()> {
|
|||||||
copy_dir_recursive(&static_dir, out)?;
|
copy_dir_recursive(&static_dir, out)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Collect page data entries for pages-data.json across all languages
|
||||||
|
let mut page_data_entries: Vec<PageDataEntry> = Vec::new();
|
||||||
|
|
||||||
// Build each language
|
// Build each language
|
||||||
for lang in &config.i18n.langs {
|
for lang in &config.i18n.langs {
|
||||||
let pages_dir = src.join("pages").join(lang);
|
let pages_dir = src.join("pages").join(lang);
|
||||||
@@ -74,6 +88,17 @@ pub fn build(src: &Path, out: &Path) -> Result<()> {
|
|||||||
let nav = build_nav(&pages);
|
let nav = build_nav(&pages);
|
||||||
|
|
||||||
for page in &pages {
|
for page in &pages {
|
||||||
|
// Collect search data for pages-data.json
|
||||||
|
let plain_body = strip_html_tags(&page.html_content);
|
||||||
|
let truncated_body: String = plain_body.chars().take(500).collect();
|
||||||
|
page_data_entries.push(PageDataEntry {
|
||||||
|
title: page.frontmatter.title.clone(),
|
||||||
|
url: page.url.clone(),
|
||||||
|
lang: lang.clone(),
|
||||||
|
section: page.section.clone(),
|
||||||
|
body: truncated_body,
|
||||||
|
});
|
||||||
|
|
||||||
let template_name = if page.section.is_empty() {
|
let template_name = if page.section.is_empty() {
|
||||||
"portal.html"
|
"portal.html"
|
||||||
} else {
|
} else {
|
||||||
@@ -136,6 +161,11 @@ pub fn build(src: &Path, out: &Path) -> Result<()> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Generate pages-data.json for client-side search
|
||||||
|
let pages_json = serde_json::to_string(&page_data_entries)
|
||||||
|
.context("Failed to serialize pages-data.json")?;
|
||||||
|
fs::write(out.join("pages-data.json"), pages_json)?;
|
||||||
|
|
||||||
// Generate root redirect
|
// Generate root redirect
|
||||||
generate_root_redirect(out, &config)?;
|
generate_root_redirect(out, &config)?;
|
||||||
|
|
||||||
@@ -392,3 +422,27 @@ fn copy_dir_recursive(src: &Path, dst: &Path) -> Result<()> {
|
|||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Strip HTML tags from a string and collapse whitespace into a single space,
|
||||||
|
/// producing a plain-text representation suitable for search indexing.
|
||||||
|
fn strip_html_tags(html: &str) -> String {
|
||||||
|
let mut result = String::with_capacity(html.len());
|
||||||
|
let mut in_tag = false;
|
||||||
|
|
||||||
|
for ch in html.chars() {
|
||||||
|
match ch {
|
||||||
|
'<' => in_tag = true,
|
||||||
|
'>' => {
|
||||||
|
in_tag = false;
|
||||||
|
// Insert a space to avoid words being glued across tags
|
||||||
|
result.push(' ');
|
||||||
|
}
|
||||||
|
_ if !in_tag => result.push(ch),
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Collapse whitespace
|
||||||
|
let collapsed: String = result.split_whitespace().collect::<Vec<_>>().join(" ");
|
||||||
|
collapsed
|
||||||
|
}
|
||||||
@@ -450,3 +450,148 @@ a:hover {
|
|||||||
.theme-toggle:hover {
|
.theme-toggle:hover {
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Search button */
|
||||||
|
.search-btn {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
background: none;
|
||||||
|
border: none;
|
||||||
|
color: var(--text);
|
||||||
|
padding: 5px 6px;
|
||||||
|
border-radius: 4px;
|
||||||
|
cursor: pointer;
|
||||||
|
opacity: 0.8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-btn:hover {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Search overlay & modal */
|
||||||
|
.search-overlay {
|
||||||
|
display: none;
|
||||||
|
position: fixed;
|
||||||
|
inset: 0;
|
||||||
|
background: rgba(0, 0, 0, 0.5);
|
||||||
|
z-index: 300;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: flex-start;
|
||||||
|
padding-top: 12vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-overlay.open {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-modal {
|
||||||
|
background: var(--bg-secondary);
|
||||||
|
border: 1px solid var(--border);
|
||||||
|
border-radius: 8px;
|
||||||
|
width: 90%;
|
||||||
|
max-width: 560px;
|
||||||
|
box-shadow: 0 8px 30px rgba(0, 0, 0, 0.4);
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-input-wrap {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
padding: 12px 16px;
|
||||||
|
border-bottom: 1px solid var(--border);
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-input-wrap svg {
|
||||||
|
flex-shrink: 0;
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
#search-input {
|
||||||
|
flex: 1;
|
||||||
|
background: none;
|
||||||
|
border: none;
|
||||||
|
outline: none;
|
||||||
|
color: var(--text-bright);
|
||||||
|
font-size: 1rem;
|
||||||
|
font-family: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
#search-input::placeholder {
|
||||||
|
color: var(--text-muted);
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-esc {
|
||||||
|
background: var(--bg);
|
||||||
|
color: var(--text-muted);
|
||||||
|
padding: 2px 6px;
|
||||||
|
border-radius: 3px;
|
||||||
|
font-size: 0.7rem;
|
||||||
|
border: 1px solid var(--border);
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-results {
|
||||||
|
list-style: none;
|
||||||
|
max-height: 50vh;
|
||||||
|
overflow-y: auto;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-results:empty::after {
|
||||||
|
content: "";
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-results li {
|
||||||
|
padding: 10px 16px;
|
||||||
|
cursor: pointer;
|
||||||
|
border-bottom: 1px solid var(--border);
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-results li:last-child {
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-results li:hover,
|
||||||
|
.search-results li.active {
|
||||||
|
background: var(--bg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-results li .search-result-title {
|
||||||
|
color: var(--text-bright);
|
||||||
|
font-weight: 600;
|
||||||
|
font-size: 0.9rem;
|
||||||
|
margin-bottom: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-results li .search-result-snippet {
|
||||||
|
color: var(--text-muted);
|
||||||
|
font-size: 0.8rem;
|
||||||
|
line-height: 1.4;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
display: -webkit-box;
|
||||||
|
-webkit-line-clamp: 2;
|
||||||
|
-webkit-box-orient: vertical;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-results li .search-result-snippet mark {
|
||||||
|
background: rgba(255, 215, 0, 0.3);
|
||||||
|
color: var(--text-bright);
|
||||||
|
border-radius: 2px;
|
||||||
|
padding: 0 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-theme="light"] .search-results li .search-result-snippet mark {
|
||||||
|
background: rgba(255, 200, 0, 0.4);
|
||||||
|
color: var(--text);
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-no-results {
|
||||||
|
padding: 24px 16px;
|
||||||
|
text-align: center;
|
||||||
|
color: var(--text-muted);
|
||||||
|
font-size: 0.9rem;
|
||||||
|
}
|
||||||
@@ -41,6 +41,9 @@
|
|||||||
|
|
||||||
</nav>
|
</nav>
|
||||||
<div class="header-tools">
|
<div class="header-tools">
|
||||||
|
<button class="search-btn" aria-label="Search (⌘K)">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>
|
||||||
|
</button>
|
||||||
<button class="theme-toggle" aria-label="Toggle theme"></button>
|
<button class="theme-toggle" aria-label="Toggle theme"></button>
|
||||||
<div class="lang-selector">
|
<div class="lang-selector">
|
||||||
<button class="lang-btn" aria-label="Language">
|
<button class="lang-btn" aria-label="Language">
|
||||||
@@ -89,6 +92,18 @@
|
|||||||
© 2026 yhirose. All rights reserved.
|
© 2026 yhirose. All rights reserved.
|
||||||
</footer>
|
</footer>
|
||||||
|
|
||||||
|
<!-- Search modal -->
|
||||||
|
<div class="search-overlay" id="search-overlay">
|
||||||
|
<div class="search-modal">
|
||||||
|
<div class="search-input-wrap">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>
|
||||||
|
<input type="text" id="search-input" placeholder="Search..." autocomplete="off" spellcheck="false">
|
||||||
|
<kbd class="search-esc">ESC</kbd>
|
||||||
|
</div>
|
||||||
|
<ul class="search-results" id="search-results"></ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<script src="/cpp-httplib/js/main.js"></script>
|
<script src="/cpp-httplib/js/main.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
@@ -41,6 +41,9 @@
|
|||||||
|
|
||||||
</nav>
|
</nav>
|
||||||
<div class="header-tools">
|
<div class="header-tools">
|
||||||
|
<button class="search-btn" aria-label="Search (⌘K)">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>
|
||||||
|
</button>
|
||||||
<button class="theme-toggle" aria-label="Toggle theme"></button>
|
<button class="theme-toggle" aria-label="Toggle theme"></button>
|
||||||
<div class="lang-selector">
|
<div class="lang-selector">
|
||||||
<button class="lang-btn" aria-label="Language">
|
<button class="lang-btn" aria-label="Language">
|
||||||
@@ -88,6 +91,18 @@
|
|||||||
© 2026 yhirose. All rights reserved.
|
© 2026 yhirose. All rights reserved.
|
||||||
</footer>
|
</footer>
|
||||||
|
|
||||||
|
<!-- Search modal -->
|
||||||
|
<div class="search-overlay" id="search-overlay">
|
||||||
|
<div class="search-modal">
|
||||||
|
<div class="search-input-wrap">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>
|
||||||
|
<input type="text" id="search-input" placeholder="Search..." autocomplete="off" spellcheck="false">
|
||||||
|
<kbd class="search-esc">ESC</kbd>
|
||||||
|
</div>
|
||||||
|
<ul class="search-results" id="search-results"></ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<script src="/cpp-httplib/js/main.js"></script>
|
<script src="/cpp-httplib/js/main.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
@@ -41,6 +41,9 @@
|
|||||||
|
|
||||||
</nav>
|
</nav>
|
||||||
<div class="header-tools">
|
<div class="header-tools">
|
||||||
|
<button class="search-btn" aria-label="Search (⌘K)">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>
|
||||||
|
</button>
|
||||||
<button class="theme-toggle" aria-label="Toggle theme"></button>
|
<button class="theme-toggle" aria-label="Toggle theme"></button>
|
||||||
<div class="lang-selector">
|
<div class="lang-selector">
|
||||||
<button class="lang-btn" aria-label="Language">
|
<button class="lang-btn" aria-label="Language">
|
||||||
@@ -214,6 +217,18 @@
|
|||||||
© 2026 yhirose. All rights reserved.
|
© 2026 yhirose. All rights reserved.
|
||||||
</footer>
|
</footer>
|
||||||
|
|
||||||
|
<!-- Search modal -->
|
||||||
|
<div class="search-overlay" id="search-overlay">
|
||||||
|
<div class="search-modal">
|
||||||
|
<div class="search-input-wrap">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>
|
||||||
|
<input type="text" id="search-input" placeholder="Search..." autocomplete="off" spellcheck="false">
|
||||||
|
<kbd class="search-esc">ESC</kbd>
|
||||||
|
</div>
|
||||||
|
<ul class="search-results" id="search-results"></ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<script src="/cpp-httplib/js/main.js"></script>
|
<script src="/cpp-httplib/js/main.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
@@ -41,6 +41,9 @@
|
|||||||
|
|
||||||
</nav>
|
</nav>
|
||||||
<div class="header-tools">
|
<div class="header-tools">
|
||||||
|
<button class="search-btn" aria-label="Search (⌘K)">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>
|
||||||
|
</button>
|
||||||
<button class="theme-toggle" aria-label="Toggle theme"></button>
|
<button class="theme-toggle" aria-label="Toggle theme"></button>
|
||||||
<div class="lang-selector">
|
<div class="lang-selector">
|
||||||
<button class="lang-btn" aria-label="Language">
|
<button class="lang-btn" aria-label="Language">
|
||||||
@@ -507,6 +510,18 @@
|
|||||||
© 2026 yhirose. All rights reserved.
|
© 2026 yhirose. All rights reserved.
|
||||||
</footer>
|
</footer>
|
||||||
|
|
||||||
|
<!-- Search modal -->
|
||||||
|
<div class="search-overlay" id="search-overlay">
|
||||||
|
<div class="search-modal">
|
||||||
|
<div class="search-input-wrap">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>
|
||||||
|
<input type="text" id="search-input" placeholder="Search..." autocomplete="off" spellcheck="false">
|
||||||
|
<kbd class="search-esc">ESC</kbd>
|
||||||
|
</div>
|
||||||
|
<ul class="search-results" id="search-results"></ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<script src="/cpp-httplib/js/main.js"></script>
|
<script src="/cpp-httplib/js/main.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
@@ -41,6 +41,9 @@
|
|||||||
|
|
||||||
</nav>
|
</nav>
|
||||||
<div class="header-tools">
|
<div class="header-tools">
|
||||||
|
<button class="search-btn" aria-label="Search (⌘K)">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>
|
||||||
|
</button>
|
||||||
<button class="theme-toggle" aria-label="Toggle theme"></button>
|
<button class="theme-toggle" aria-label="Toggle theme"></button>
|
||||||
<div class="lang-selector">
|
<div class="lang-selector">
|
||||||
<button class="lang-btn" aria-label="Language">
|
<button class="lang-btn" aria-label="Language">
|
||||||
@@ -462,6 +465,18 @@
|
|||||||
© 2026 yhirose. All rights reserved.
|
© 2026 yhirose. All rights reserved.
|
||||||
</footer>
|
</footer>
|
||||||
|
|
||||||
|
<!-- Search modal -->
|
||||||
|
<div class="search-overlay" id="search-overlay">
|
||||||
|
<div class="search-modal">
|
||||||
|
<div class="search-input-wrap">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>
|
||||||
|
<input type="text" id="search-input" placeholder="Search..." autocomplete="off" spellcheck="false">
|
||||||
|
<kbd class="search-esc">ESC</kbd>
|
||||||
|
</div>
|
||||||
|
<ul class="search-results" id="search-results"></ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<script src="/cpp-httplib/js/main.js"></script>
|
<script src="/cpp-httplib/js/main.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
@@ -41,6 +41,9 @@
|
|||||||
|
|
||||||
</nav>
|
</nav>
|
||||||
<div class="header-tools">
|
<div class="header-tools">
|
||||||
|
<button class="search-btn" aria-label="Search (⌘K)">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>
|
||||||
|
</button>
|
||||||
<button class="theme-toggle" aria-label="Toggle theme"></button>
|
<button class="theme-toggle" aria-label="Toggle theme"></button>
|
||||||
<div class="lang-selector">
|
<div class="lang-selector">
|
||||||
<button class="lang-btn" aria-label="Language">
|
<button class="lang-btn" aria-label="Language">
|
||||||
@@ -285,6 +288,18 @@
|
|||||||
© 2026 yhirose. All rights reserved.
|
© 2026 yhirose. All rights reserved.
|
||||||
</footer>
|
</footer>
|
||||||
|
|
||||||
|
<!-- Search modal -->
|
||||||
|
<div class="search-overlay" id="search-overlay">
|
||||||
|
<div class="search-modal">
|
||||||
|
<div class="search-input-wrap">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>
|
||||||
|
<input type="text" id="search-input" placeholder="Search..." autocomplete="off" spellcheck="false">
|
||||||
|
<kbd class="search-esc">ESC</kbd>
|
||||||
|
</div>
|
||||||
|
<ul class="search-results" id="search-results"></ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<script src="/cpp-httplib/js/main.js"></script>
|
<script src="/cpp-httplib/js/main.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
@@ -41,6 +41,9 @@
|
|||||||
|
|
||||||
</nav>
|
</nav>
|
||||||
<div class="header-tools">
|
<div class="header-tools">
|
||||||
|
<button class="search-btn" aria-label="Search (⌘K)">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>
|
||||||
|
</button>
|
||||||
<button class="theme-toggle" aria-label="Toggle theme"></button>
|
<button class="theme-toggle" aria-label="Toggle theme"></button>
|
||||||
<div class="lang-selector">
|
<div class="lang-selector">
|
||||||
<button class="lang-btn" aria-label="Language">
|
<button class="lang-btn" aria-label="Language">
|
||||||
@@ -209,6 +212,18 @@
|
|||||||
© 2026 yhirose. All rights reserved.
|
© 2026 yhirose. All rights reserved.
|
||||||
</footer>
|
</footer>
|
||||||
|
|
||||||
|
<!-- Search modal -->
|
||||||
|
<div class="search-overlay" id="search-overlay">
|
||||||
|
<div class="search-modal">
|
||||||
|
<div class="search-input-wrap">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>
|
||||||
|
<input type="text" id="search-input" placeholder="Search..." autocomplete="off" spellcheck="false">
|
||||||
|
<kbd class="search-esc">ESC</kbd>
|
||||||
|
</div>
|
||||||
|
<ul class="search-results" id="search-results"></ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<script src="/cpp-httplib/js/main.js"></script>
|
<script src="/cpp-httplib/js/main.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
@@ -41,6 +41,9 @@
|
|||||||
|
|
||||||
</nav>
|
</nav>
|
||||||
<div class="header-tools">
|
<div class="header-tools">
|
||||||
|
<button class="search-btn" aria-label="Search (⌘K)">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>
|
||||||
|
</button>
|
||||||
<button class="theme-toggle" aria-label="Toggle theme"></button>
|
<button class="theme-toggle" aria-label="Toggle theme"></button>
|
||||||
<div class="lang-selector">
|
<div class="lang-selector">
|
||||||
<button class="lang-btn" aria-label="Language">
|
<button class="lang-btn" aria-label="Language">
|
||||||
@@ -267,6 +270,18 @@
|
|||||||
© 2026 yhirose. All rights reserved.
|
© 2026 yhirose. All rights reserved.
|
||||||
</footer>
|
</footer>
|
||||||
|
|
||||||
|
<!-- Search modal -->
|
||||||
|
<div class="search-overlay" id="search-overlay">
|
||||||
|
<div class="search-modal">
|
||||||
|
<div class="search-input-wrap">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>
|
||||||
|
<input type="text" id="search-input" placeholder="Search..." autocomplete="off" spellcheck="false">
|
||||||
|
<kbd class="search-esc">ESC</kbd>
|
||||||
|
</div>
|
||||||
|
<ul class="search-results" id="search-results"></ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<script src="/cpp-httplib/js/main.js"></script>
|
<script src="/cpp-httplib/js/main.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
@@ -41,6 +41,9 @@
|
|||||||
|
|
||||||
</nav>
|
</nav>
|
||||||
<div class="header-tools">
|
<div class="header-tools">
|
||||||
|
<button class="search-btn" aria-label="Search (⌘K)">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>
|
||||||
|
</button>
|
||||||
<button class="theme-toggle" aria-label="Toggle theme"></button>
|
<button class="theme-toggle" aria-label="Toggle theme"></button>
|
||||||
<div class="lang-selector">
|
<div class="lang-selector">
|
||||||
<button class="lang-btn" aria-label="Language">
|
<button class="lang-btn" aria-label="Language">
|
||||||
@@ -256,6 +259,18 @@
|
|||||||
© 2026 yhirose. All rights reserved.
|
© 2026 yhirose. All rights reserved.
|
||||||
</footer>
|
</footer>
|
||||||
|
|
||||||
|
<!-- Search modal -->
|
||||||
|
<div class="search-overlay" id="search-overlay">
|
||||||
|
<div class="search-modal">
|
||||||
|
<div class="search-input-wrap">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>
|
||||||
|
<input type="text" id="search-input" placeholder="Search..." autocomplete="off" spellcheck="false">
|
||||||
|
<kbd class="search-esc">ESC</kbd>
|
||||||
|
</div>
|
||||||
|
<ul class="search-results" id="search-results"></ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<script src="/cpp-httplib/js/main.js"></script>
|
<script src="/cpp-httplib/js/main.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
@@ -41,6 +41,9 @@
|
|||||||
|
|
||||||
</nav>
|
</nav>
|
||||||
<div class="header-tools">
|
<div class="header-tools">
|
||||||
|
<button class="search-btn" aria-label="Search (⌘K)">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>
|
||||||
|
</button>
|
||||||
<button class="theme-toggle" aria-label="Toggle theme"></button>
|
<button class="theme-toggle" aria-label="Toggle theme"></button>
|
||||||
<div class="lang-selector">
|
<div class="lang-selector">
|
||||||
<button class="lang-btn" aria-label="Language">
|
<button class="lang-btn" aria-label="Language">
|
||||||
@@ -308,6 +311,18 @@
|
|||||||
© 2026 yhirose. All rights reserved.
|
© 2026 yhirose. All rights reserved.
|
||||||
</footer>
|
</footer>
|
||||||
|
|
||||||
|
<!-- Search modal -->
|
||||||
|
<div class="search-overlay" id="search-overlay">
|
||||||
|
<div class="search-modal">
|
||||||
|
<div class="search-input-wrap">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>
|
||||||
|
<input type="text" id="search-input" placeholder="Search..." autocomplete="off" spellcheck="false">
|
||||||
|
<kbd class="search-esc">ESC</kbd>
|
||||||
|
</div>
|
||||||
|
<ul class="search-results" id="search-results"></ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<script src="/cpp-httplib/js/main.js"></script>
|
<script src="/cpp-httplib/js/main.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
@@ -41,6 +41,9 @@
|
|||||||
|
|
||||||
</nav>
|
</nav>
|
||||||
<div class="header-tools">
|
<div class="header-tools">
|
||||||
|
<button class="search-btn" aria-label="Search (⌘K)">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>
|
||||||
|
</button>
|
||||||
<button class="theme-toggle" aria-label="Toggle theme"></button>
|
<button class="theme-toggle" aria-label="Toggle theme"></button>
|
||||||
<div class="lang-selector">
|
<div class="lang-selector">
|
||||||
<button class="lang-btn" aria-label="Language">
|
<button class="lang-btn" aria-label="Language">
|
||||||
@@ -440,6 +443,18 @@
|
|||||||
© 2026 yhirose. All rights reserved.
|
© 2026 yhirose. All rights reserved.
|
||||||
</footer>
|
</footer>
|
||||||
|
|
||||||
|
<!-- Search modal -->
|
||||||
|
<div class="search-overlay" id="search-overlay">
|
||||||
|
<div class="search-modal">
|
||||||
|
<div class="search-input-wrap">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>
|
||||||
|
<input type="text" id="search-input" placeholder="Search..." autocomplete="off" spellcheck="false">
|
||||||
|
<kbd class="search-esc">ESC</kbd>
|
||||||
|
</div>
|
||||||
|
<ul class="search-results" id="search-results"></ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<script src="/cpp-httplib/js/main.js"></script>
|
<script src="/cpp-httplib/js/main.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
@@ -41,6 +41,9 @@
|
|||||||
|
|
||||||
</nav>
|
</nav>
|
||||||
<div class="header-tools">
|
<div class="header-tools">
|
||||||
|
<button class="search-btn" aria-label="Search (⌘K)">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>
|
||||||
|
</button>
|
||||||
<button class="theme-toggle" aria-label="Toggle theme"></button>
|
<button class="theme-toggle" aria-label="Toggle theme"></button>
|
||||||
<div class="lang-selector">
|
<div class="lang-selector">
|
||||||
<button class="lang-btn" aria-label="Language">
|
<button class="lang-btn" aria-label="Language">
|
||||||
@@ -121,6 +124,18 @@
|
|||||||
© 2026 yhirose. All rights reserved.
|
© 2026 yhirose. All rights reserved.
|
||||||
</footer>
|
</footer>
|
||||||
|
|
||||||
|
<!-- Search modal -->
|
||||||
|
<div class="search-overlay" id="search-overlay">
|
||||||
|
<div class="search-modal">
|
||||||
|
<div class="search-input-wrap">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>
|
||||||
|
<input type="text" id="search-input" placeholder="Search..." autocomplete="off" spellcheck="false">
|
||||||
|
<kbd class="search-esc">ESC</kbd>
|
||||||
|
</div>
|
||||||
|
<ul class="search-results" id="search-results"></ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<script src="/cpp-httplib/js/main.js"></script>
|
<script src="/cpp-httplib/js/main.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
@@ -41,6 +41,9 @@
|
|||||||
|
|
||||||
</nav>
|
</nav>
|
||||||
<div class="header-tools">
|
<div class="header-tools">
|
||||||
|
<button class="search-btn" aria-label="Search (⌘K)">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>
|
||||||
|
</button>
|
||||||
<button class="theme-toggle" aria-label="Toggle theme"></button>
|
<button class="theme-toggle" aria-label="Toggle theme"></button>
|
||||||
<div class="lang-selector">
|
<div class="lang-selector">
|
||||||
<button class="lang-btn" aria-label="Language">
|
<button class="lang-btn" aria-label="Language">
|
||||||
@@ -89,6 +92,18 @@
|
|||||||
© 2026 yhirose. All rights reserved.
|
© 2026 yhirose. All rights reserved.
|
||||||
</footer>
|
</footer>
|
||||||
|
|
||||||
|
<!-- Search modal -->
|
||||||
|
<div class="search-overlay" id="search-overlay">
|
||||||
|
<div class="search-modal">
|
||||||
|
<div class="search-input-wrap">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>
|
||||||
|
<input type="text" id="search-input" placeholder="Search..." autocomplete="off" spellcheck="false">
|
||||||
|
<kbd class="search-esc">ESC</kbd>
|
||||||
|
</div>
|
||||||
|
<ul class="search-results" id="search-results"></ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<script src="/cpp-httplib/js/main.js"></script>
|
<script src="/cpp-httplib/js/main.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
@@ -41,6 +41,9 @@
|
|||||||
|
|
||||||
</nav>
|
</nav>
|
||||||
<div class="header-tools">
|
<div class="header-tools">
|
||||||
|
<button class="search-btn" aria-label="Search (⌘K)">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>
|
||||||
|
</button>
|
||||||
<button class="theme-toggle" aria-label="Toggle theme"></button>
|
<button class="theme-toggle" aria-label="Toggle theme"></button>
|
||||||
<div class="lang-selector">
|
<div class="lang-selector">
|
||||||
<button class="lang-btn" aria-label="Language">
|
<button class="lang-btn" aria-label="Language">
|
||||||
@@ -88,6 +91,18 @@
|
|||||||
© 2026 yhirose. All rights reserved.
|
© 2026 yhirose. All rights reserved.
|
||||||
</footer>
|
</footer>
|
||||||
|
|
||||||
|
<!-- Search modal -->
|
||||||
|
<div class="search-overlay" id="search-overlay">
|
||||||
|
<div class="search-modal">
|
||||||
|
<div class="search-input-wrap">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>
|
||||||
|
<input type="text" id="search-input" placeholder="Search..." autocomplete="off" spellcheck="false">
|
||||||
|
<kbd class="search-esc">ESC</kbd>
|
||||||
|
</div>
|
||||||
|
<ul class="search-results" id="search-results"></ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<script src="/cpp-httplib/js/main.js"></script>
|
<script src="/cpp-httplib/js/main.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
@@ -41,6 +41,9 @@
|
|||||||
|
|
||||||
</nav>
|
</nav>
|
||||||
<div class="header-tools">
|
<div class="header-tools">
|
||||||
|
<button class="search-btn" aria-label="Search (⌘K)">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>
|
||||||
|
</button>
|
||||||
<button class="theme-toggle" aria-label="Toggle theme"></button>
|
<button class="theme-toggle" aria-label="Toggle theme"></button>
|
||||||
<div class="lang-selector">
|
<div class="lang-selector">
|
||||||
<button class="lang-btn" aria-label="Language">
|
<button class="lang-btn" aria-label="Language">
|
||||||
@@ -214,6 +217,18 @@
|
|||||||
© 2026 yhirose. All rights reserved.
|
© 2026 yhirose. All rights reserved.
|
||||||
</footer>
|
</footer>
|
||||||
|
|
||||||
|
<!-- Search modal -->
|
||||||
|
<div class="search-overlay" id="search-overlay">
|
||||||
|
<div class="search-modal">
|
||||||
|
<div class="search-input-wrap">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>
|
||||||
|
<input type="text" id="search-input" placeholder="Search..." autocomplete="off" spellcheck="false">
|
||||||
|
<kbd class="search-esc">ESC</kbd>
|
||||||
|
</div>
|
||||||
|
<ul class="search-results" id="search-results"></ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<script src="/cpp-httplib/js/main.js"></script>
|
<script src="/cpp-httplib/js/main.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
@@ -41,6 +41,9 @@
|
|||||||
|
|
||||||
</nav>
|
</nav>
|
||||||
<div class="header-tools">
|
<div class="header-tools">
|
||||||
|
<button class="search-btn" aria-label="Search (⌘K)">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>
|
||||||
|
</button>
|
||||||
<button class="theme-toggle" aria-label="Toggle theme"></button>
|
<button class="theme-toggle" aria-label="Toggle theme"></button>
|
||||||
<div class="lang-selector">
|
<div class="lang-selector">
|
||||||
<button class="lang-btn" aria-label="Language">
|
<button class="lang-btn" aria-label="Language">
|
||||||
@@ -507,6 +510,18 @@
|
|||||||
© 2026 yhirose. All rights reserved.
|
© 2026 yhirose. All rights reserved.
|
||||||
</footer>
|
</footer>
|
||||||
|
|
||||||
|
<!-- Search modal -->
|
||||||
|
<div class="search-overlay" id="search-overlay">
|
||||||
|
<div class="search-modal">
|
||||||
|
<div class="search-input-wrap">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>
|
||||||
|
<input type="text" id="search-input" placeholder="Search..." autocomplete="off" spellcheck="false">
|
||||||
|
<kbd class="search-esc">ESC</kbd>
|
||||||
|
</div>
|
||||||
|
<ul class="search-results" id="search-results"></ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<script src="/cpp-httplib/js/main.js"></script>
|
<script src="/cpp-httplib/js/main.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
@@ -41,6 +41,9 @@
|
|||||||
|
|
||||||
</nav>
|
</nav>
|
||||||
<div class="header-tools">
|
<div class="header-tools">
|
||||||
|
<button class="search-btn" aria-label="Search (⌘K)">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>
|
||||||
|
</button>
|
||||||
<button class="theme-toggle" aria-label="Toggle theme"></button>
|
<button class="theme-toggle" aria-label="Toggle theme"></button>
|
||||||
<div class="lang-selector">
|
<div class="lang-selector">
|
||||||
<button class="lang-btn" aria-label="Language">
|
<button class="lang-btn" aria-label="Language">
|
||||||
@@ -462,6 +465,18 @@
|
|||||||
© 2026 yhirose. All rights reserved.
|
© 2026 yhirose. All rights reserved.
|
||||||
</footer>
|
</footer>
|
||||||
|
|
||||||
|
<!-- Search modal -->
|
||||||
|
<div class="search-overlay" id="search-overlay">
|
||||||
|
<div class="search-modal">
|
||||||
|
<div class="search-input-wrap">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>
|
||||||
|
<input type="text" id="search-input" placeholder="Search..." autocomplete="off" spellcheck="false">
|
||||||
|
<kbd class="search-esc">ESC</kbd>
|
||||||
|
</div>
|
||||||
|
<ul class="search-results" id="search-results"></ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<script src="/cpp-httplib/js/main.js"></script>
|
<script src="/cpp-httplib/js/main.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
@@ -41,6 +41,9 @@
|
|||||||
|
|
||||||
</nav>
|
</nav>
|
||||||
<div class="header-tools">
|
<div class="header-tools">
|
||||||
|
<button class="search-btn" aria-label="Search (⌘K)">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>
|
||||||
|
</button>
|
||||||
<button class="theme-toggle" aria-label="Toggle theme"></button>
|
<button class="theme-toggle" aria-label="Toggle theme"></button>
|
||||||
<div class="lang-selector">
|
<div class="lang-selector">
|
||||||
<button class="lang-btn" aria-label="Language">
|
<button class="lang-btn" aria-label="Language">
|
||||||
@@ -285,6 +288,18 @@
|
|||||||
© 2026 yhirose. All rights reserved.
|
© 2026 yhirose. All rights reserved.
|
||||||
</footer>
|
</footer>
|
||||||
|
|
||||||
|
<!-- Search modal -->
|
||||||
|
<div class="search-overlay" id="search-overlay">
|
||||||
|
<div class="search-modal">
|
||||||
|
<div class="search-input-wrap">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>
|
||||||
|
<input type="text" id="search-input" placeholder="Search..." autocomplete="off" spellcheck="false">
|
||||||
|
<kbd class="search-esc">ESC</kbd>
|
||||||
|
</div>
|
||||||
|
<ul class="search-results" id="search-results"></ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<script src="/cpp-httplib/js/main.js"></script>
|
<script src="/cpp-httplib/js/main.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
@@ -41,6 +41,9 @@
|
|||||||
|
|
||||||
</nav>
|
</nav>
|
||||||
<div class="header-tools">
|
<div class="header-tools">
|
||||||
|
<button class="search-btn" aria-label="Search (⌘K)">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>
|
||||||
|
</button>
|
||||||
<button class="theme-toggle" aria-label="Toggle theme"></button>
|
<button class="theme-toggle" aria-label="Toggle theme"></button>
|
||||||
<div class="lang-selector">
|
<div class="lang-selector">
|
||||||
<button class="lang-btn" aria-label="Language">
|
<button class="lang-btn" aria-label="Language">
|
||||||
@@ -209,6 +212,18 @@
|
|||||||
© 2026 yhirose. All rights reserved.
|
© 2026 yhirose. All rights reserved.
|
||||||
</footer>
|
</footer>
|
||||||
|
|
||||||
|
<!-- Search modal -->
|
||||||
|
<div class="search-overlay" id="search-overlay">
|
||||||
|
<div class="search-modal">
|
||||||
|
<div class="search-input-wrap">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>
|
||||||
|
<input type="text" id="search-input" placeholder="Search..." autocomplete="off" spellcheck="false">
|
||||||
|
<kbd class="search-esc">ESC</kbd>
|
||||||
|
</div>
|
||||||
|
<ul class="search-results" id="search-results"></ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<script src="/cpp-httplib/js/main.js"></script>
|
<script src="/cpp-httplib/js/main.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
@@ -41,6 +41,9 @@
|
|||||||
|
|
||||||
</nav>
|
</nav>
|
||||||
<div class="header-tools">
|
<div class="header-tools">
|
||||||
|
<button class="search-btn" aria-label="Search (⌘K)">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>
|
||||||
|
</button>
|
||||||
<button class="theme-toggle" aria-label="Toggle theme"></button>
|
<button class="theme-toggle" aria-label="Toggle theme"></button>
|
||||||
<div class="lang-selector">
|
<div class="lang-selector">
|
||||||
<button class="lang-btn" aria-label="Language">
|
<button class="lang-btn" aria-label="Language">
|
||||||
@@ -267,6 +270,18 @@
|
|||||||
© 2026 yhirose. All rights reserved.
|
© 2026 yhirose. All rights reserved.
|
||||||
</footer>
|
</footer>
|
||||||
|
|
||||||
|
<!-- Search modal -->
|
||||||
|
<div class="search-overlay" id="search-overlay">
|
||||||
|
<div class="search-modal">
|
||||||
|
<div class="search-input-wrap">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>
|
||||||
|
<input type="text" id="search-input" placeholder="Search..." autocomplete="off" spellcheck="false">
|
||||||
|
<kbd class="search-esc">ESC</kbd>
|
||||||
|
</div>
|
||||||
|
<ul class="search-results" id="search-results"></ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<script src="/cpp-httplib/js/main.js"></script>
|
<script src="/cpp-httplib/js/main.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
@@ -41,6 +41,9 @@
|
|||||||
|
|
||||||
</nav>
|
</nav>
|
||||||
<div class="header-tools">
|
<div class="header-tools">
|
||||||
|
<button class="search-btn" aria-label="Search (⌘K)">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>
|
||||||
|
</button>
|
||||||
<button class="theme-toggle" aria-label="Toggle theme"></button>
|
<button class="theme-toggle" aria-label="Toggle theme"></button>
|
||||||
<div class="lang-selector">
|
<div class="lang-selector">
|
||||||
<button class="lang-btn" aria-label="Language">
|
<button class="lang-btn" aria-label="Language">
|
||||||
@@ -256,6 +259,18 @@
|
|||||||
© 2026 yhirose. All rights reserved.
|
© 2026 yhirose. All rights reserved.
|
||||||
</footer>
|
</footer>
|
||||||
|
|
||||||
|
<!-- Search modal -->
|
||||||
|
<div class="search-overlay" id="search-overlay">
|
||||||
|
<div class="search-modal">
|
||||||
|
<div class="search-input-wrap">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>
|
||||||
|
<input type="text" id="search-input" placeholder="Search..." autocomplete="off" spellcheck="false">
|
||||||
|
<kbd class="search-esc">ESC</kbd>
|
||||||
|
</div>
|
||||||
|
<ul class="search-results" id="search-results"></ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<script src="/cpp-httplib/js/main.js"></script>
|
<script src="/cpp-httplib/js/main.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
@@ -41,6 +41,9 @@
|
|||||||
|
|
||||||
</nav>
|
</nav>
|
||||||
<div class="header-tools">
|
<div class="header-tools">
|
||||||
|
<button class="search-btn" aria-label="Search (⌘K)">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>
|
||||||
|
</button>
|
||||||
<button class="theme-toggle" aria-label="Toggle theme"></button>
|
<button class="theme-toggle" aria-label="Toggle theme"></button>
|
||||||
<div class="lang-selector">
|
<div class="lang-selector">
|
||||||
<button class="lang-btn" aria-label="Language">
|
<button class="lang-btn" aria-label="Language">
|
||||||
@@ -308,6 +311,18 @@
|
|||||||
© 2026 yhirose. All rights reserved.
|
© 2026 yhirose. All rights reserved.
|
||||||
</footer>
|
</footer>
|
||||||
|
|
||||||
|
<!-- Search modal -->
|
||||||
|
<div class="search-overlay" id="search-overlay">
|
||||||
|
<div class="search-modal">
|
||||||
|
<div class="search-input-wrap">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>
|
||||||
|
<input type="text" id="search-input" placeholder="Search..." autocomplete="off" spellcheck="false">
|
||||||
|
<kbd class="search-esc">ESC</kbd>
|
||||||
|
</div>
|
||||||
|
<ul class="search-results" id="search-results"></ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<script src="/cpp-httplib/js/main.js"></script>
|
<script src="/cpp-httplib/js/main.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
@@ -41,6 +41,9 @@
|
|||||||
|
|
||||||
</nav>
|
</nav>
|
||||||
<div class="header-tools">
|
<div class="header-tools">
|
||||||
|
<button class="search-btn" aria-label="Search (⌘K)">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>
|
||||||
|
</button>
|
||||||
<button class="theme-toggle" aria-label="Toggle theme"></button>
|
<button class="theme-toggle" aria-label="Toggle theme"></button>
|
||||||
<div class="lang-selector">
|
<div class="lang-selector">
|
||||||
<button class="lang-btn" aria-label="Language">
|
<button class="lang-btn" aria-label="Language">
|
||||||
@@ -440,6 +443,18 @@
|
|||||||
© 2026 yhirose. All rights reserved.
|
© 2026 yhirose. All rights reserved.
|
||||||
</footer>
|
</footer>
|
||||||
|
|
||||||
|
<!-- Search modal -->
|
||||||
|
<div class="search-overlay" id="search-overlay">
|
||||||
|
<div class="search-modal">
|
||||||
|
<div class="search-input-wrap">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>
|
||||||
|
<input type="text" id="search-input" placeholder="Search..." autocomplete="off" spellcheck="false">
|
||||||
|
<kbd class="search-esc">ESC</kbd>
|
||||||
|
</div>
|
||||||
|
<ul class="search-results" id="search-results"></ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<script src="/cpp-httplib/js/main.js"></script>
|
<script src="/cpp-httplib/js/main.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
@@ -41,6 +41,9 @@
|
|||||||
|
|
||||||
</nav>
|
</nav>
|
||||||
<div class="header-tools">
|
<div class="header-tools">
|
||||||
|
<button class="search-btn" aria-label="Search (⌘K)">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>
|
||||||
|
</button>
|
||||||
<button class="theme-toggle" aria-label="Toggle theme"></button>
|
<button class="theme-toggle" aria-label="Toggle theme"></button>
|
||||||
<div class="lang-selector">
|
<div class="lang-selector">
|
||||||
<button class="lang-btn" aria-label="Language">
|
<button class="lang-btn" aria-label="Language">
|
||||||
@@ -121,6 +124,18 @@
|
|||||||
© 2026 yhirose. All rights reserved.
|
© 2026 yhirose. All rights reserved.
|
||||||
</footer>
|
</footer>
|
||||||
|
|
||||||
|
<!-- Search modal -->
|
||||||
|
<div class="search-overlay" id="search-overlay">
|
||||||
|
<div class="search-modal">
|
||||||
|
<div class="search-input-wrap">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>
|
||||||
|
<input type="text" id="search-input" placeholder="Search..." autocomplete="off" spellcheck="false">
|
||||||
|
<kbd class="search-esc">ESC</kbd>
|
||||||
|
</div>
|
||||||
|
<ul class="search-results" id="search-results"></ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<script src="/cpp-httplib/js/main.js"></script>
|
<script src="/cpp-httplib/js/main.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
+217
@@ -78,3 +78,220 @@
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
})();
|
})();
|
||||||
|
|
||||||
|
// Site search (⌘K / Ctrl+K)
|
||||||
|
(function () {
|
||||||
|
var overlay = document.getElementById('search-overlay');
|
||||||
|
var input = document.getElementById('search-input');
|
||||||
|
var resultsList = document.getElementById('search-results');
|
||||||
|
if (!overlay || !input || !resultsList) return;
|
||||||
|
|
||||||
|
var searchBtn = document.querySelector('.search-btn');
|
||||||
|
var pagesData = null; // cached pages-data.json
|
||||||
|
var activeIndex = -1;
|
||||||
|
|
||||||
|
function getCurrentLang() {
|
||||||
|
return document.documentElement.getAttribute('lang') || 'en';
|
||||||
|
}
|
||||||
|
|
||||||
|
function getBasePath() {
|
||||||
|
return document.documentElement.getAttribute('data-base-path') || '';
|
||||||
|
}
|
||||||
|
|
||||||
|
function openSearch() {
|
||||||
|
overlay.classList.add('open');
|
||||||
|
input.value = '';
|
||||||
|
resultsList.innerHTML = '';
|
||||||
|
activeIndex = -1;
|
||||||
|
input.focus();
|
||||||
|
loadPagesData();
|
||||||
|
}
|
||||||
|
|
||||||
|
function closeSearch() {
|
||||||
|
overlay.classList.remove('open');
|
||||||
|
input.value = '';
|
||||||
|
resultsList.innerHTML = '';
|
||||||
|
activeIndex = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
function loadPagesData() {
|
||||||
|
if (pagesData) return;
|
||||||
|
var basePath = getBasePath();
|
||||||
|
fetch(basePath + '/pages-data.json')
|
||||||
|
.then(function (res) { return res.json(); })
|
||||||
|
.then(function (data) { pagesData = data; })
|
||||||
|
.catch(function () { pagesData = []; });
|
||||||
|
}
|
||||||
|
|
||||||
|
function escapeRegExp(s) {
|
||||||
|
return s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
||||||
|
}
|
||||||
|
|
||||||
|
function highlightText(text, query) {
|
||||||
|
if (!query) return text;
|
||||||
|
var escaped = escapeRegExp(query);
|
||||||
|
var re = new RegExp('(' + escaped + ')', 'gi');
|
||||||
|
return text.replace(re, '<mark>$1</mark>');
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildSnippet(body, query) {
|
||||||
|
if (!query || !body) return '';
|
||||||
|
var lower = body.toLowerCase();
|
||||||
|
var idx = lower.indexOf(query.toLowerCase());
|
||||||
|
var start, end, snippet;
|
||||||
|
if (idx === -1) {
|
||||||
|
snippet = body.substring(0, 120);
|
||||||
|
} else {
|
||||||
|
start = Math.max(0, idx - 40);
|
||||||
|
end = Math.min(body.length, idx + query.length + 80);
|
||||||
|
snippet = (start > 0 ? '...' : '') + body.substring(start, end) + (end < body.length ? '...' : '');
|
||||||
|
}
|
||||||
|
return highlightText(snippet, query);
|
||||||
|
}
|
||||||
|
|
||||||
|
function search(query) {
|
||||||
|
if (!pagesData || !query) {
|
||||||
|
resultsList.innerHTML = '';
|
||||||
|
activeIndex = -1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var lang = getCurrentLang();
|
||||||
|
var q = query.toLowerCase();
|
||||||
|
|
||||||
|
// Score and filter
|
||||||
|
var scored = [];
|
||||||
|
for (var i = 0; i < pagesData.length; i++) {
|
||||||
|
var page = pagesData[i];
|
||||||
|
if (page.lang !== lang) continue;
|
||||||
|
|
||||||
|
var score = 0;
|
||||||
|
var titleLower = page.title.toLowerCase();
|
||||||
|
var bodyLower = (page.body || '').toLowerCase();
|
||||||
|
|
||||||
|
if (titleLower.indexOf(q) !== -1) {
|
||||||
|
score += 10;
|
||||||
|
// Bonus for exact title match
|
||||||
|
if (titleLower === q) score += 5;
|
||||||
|
}
|
||||||
|
if (bodyLower.indexOf(q) !== -1) {
|
||||||
|
score += 3;
|
||||||
|
}
|
||||||
|
if (page.section.toLowerCase().indexOf(q) !== -1) {
|
||||||
|
score += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (score > 0) {
|
||||||
|
scored.push({ page: page, score: score });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sort by score descending
|
||||||
|
scored.sort(function (a, b) { return b.score - a.score; });
|
||||||
|
|
||||||
|
// Limit results
|
||||||
|
var results = scored.slice(0, 20);
|
||||||
|
|
||||||
|
if (results.length === 0) {
|
||||||
|
resultsList.innerHTML = '<li class="search-no-results">No results found.</li>';
|
||||||
|
activeIndex = -1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var html = '';
|
||||||
|
for (var j = 0; j < results.length; j++) {
|
||||||
|
var r = results[j];
|
||||||
|
var snippet = buildSnippet(r.page.body, query);
|
||||||
|
html += '<li data-url="' + r.page.url + '">'
|
||||||
|
+ '<div class="search-result-title">' + highlightText(r.page.title, query) + '</div>'
|
||||||
|
+ (snippet ? '<div class="search-result-snippet">' + snippet + '</div>' : '')
|
||||||
|
+ '</li>';
|
||||||
|
}
|
||||||
|
resultsList.innerHTML = html;
|
||||||
|
activeIndex = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
function setActive(index) {
|
||||||
|
var items = resultsList.querySelectorAll('li[data-url]');
|
||||||
|
if (items.length === 0) return;
|
||||||
|
// Remove previous active
|
||||||
|
for (var i = 0; i < items.length; i++) {
|
||||||
|
items[i].classList.remove('active');
|
||||||
|
}
|
||||||
|
if (index < 0) index = items.length - 1;
|
||||||
|
if (index >= items.length) index = 0;
|
||||||
|
activeIndex = index;
|
||||||
|
items[activeIndex].classList.add('active');
|
||||||
|
items[activeIndex].scrollIntoView({ block: 'nearest' });
|
||||||
|
}
|
||||||
|
|
||||||
|
function navigateToActive() {
|
||||||
|
var items = resultsList.querySelectorAll('li[data-url]');
|
||||||
|
if (activeIndex >= 0 && activeIndex < items.length) {
|
||||||
|
var url = items[activeIndex].getAttribute('data-url');
|
||||||
|
if (url) {
|
||||||
|
closeSearch();
|
||||||
|
window.location.href = url;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Event: search button
|
||||||
|
if (searchBtn) {
|
||||||
|
searchBtn.addEventListener('click', function (e) {
|
||||||
|
e.stopPropagation();
|
||||||
|
openSearch();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use capture phase to intercept keys before browser default behavior
|
||||||
|
// (e.g. ESC clearing input text in some browsers)
|
||||||
|
document.addEventListener('keydown', function (e) {
|
||||||
|
if ((e.metaKey || e.ctrlKey) && e.key === 'k') {
|
||||||
|
e.preventDefault();
|
||||||
|
overlay.classList.contains('open') ? closeSearch() : openSearch();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!overlay.classList.contains('open')) return;
|
||||||
|
if (e.key === 'Escape') {
|
||||||
|
e.preventDefault();
|
||||||
|
closeSearch();
|
||||||
|
} else if (e.key === 'ArrowDown') {
|
||||||
|
e.preventDefault();
|
||||||
|
setActive(activeIndex + 1);
|
||||||
|
} else if (e.key === 'ArrowUp') {
|
||||||
|
e.preventDefault();
|
||||||
|
setActive(activeIndex - 1);
|
||||||
|
} else if (e.key === 'Enter') {
|
||||||
|
e.preventDefault();
|
||||||
|
navigateToActive();
|
||||||
|
}
|
||||||
|
}, true); // capture phase
|
||||||
|
|
||||||
|
// Event: click overlay background to close
|
||||||
|
overlay.addEventListener('click', function (e) {
|
||||||
|
if (e.target === overlay) {
|
||||||
|
closeSearch();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Event: click result item
|
||||||
|
resultsList.addEventListener('click', function (e) {
|
||||||
|
var li = e.target.closest('li[data-url]');
|
||||||
|
if (!li) return;
|
||||||
|
var url = li.getAttribute('data-url');
|
||||||
|
if (url) {
|
||||||
|
closeSearch();
|
||||||
|
window.location.href = url;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Event: input for live search
|
||||||
|
var debounceTimer = null;
|
||||||
|
input.addEventListener('input', function () {
|
||||||
|
clearTimeout(debounceTimer);
|
||||||
|
debounceTimer = setTimeout(function () {
|
||||||
|
search(input.value.trim());
|
||||||
|
}, 150);
|
||||||
|
});
|
||||||
|
})();
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
[{"title":"Cookbook","url":"/cpp-httplib/en/cookbook/","lang":"en","section":"cookbook","body":"This section is under construction. Check back soon for a collection of recipes organized by topic."},{"title":"cpp-httplib","url":"/cpp-httplib/en/","lang":"en","section":"","body":"cpp-httplib is an HTTP/HTTPS library for C++. Just copy a single header file, httplib.h , and you're ready to go. When you need a quick HTTP server or client in C++, you want something that just works. That's exactly why I built cpp-httplib. You can start writing both servers and clients in just a few lines of code. The API uses a lambda-based design that feels natural. It runs anywhere you have a C++11 or later compiler. Windows, macOS, Linux — use whatever environment you already have. HTTPS w"},{"title":"Static File Server","url":"/cpp-httplib/en/tour/04-static-file-server/","lang":"en","section":"tour","body":"cpp-httplib can serve static files too — HTML, CSS, images, you name it. No complicated configuration required. One call to set_mount_point() is all it takes. The basics of set_mount_point Let's jump right in. set_mount_point() maps a URL path to a local directory. #include " httplib.h " #include < iostream > int main () { httplib::Server svr; svr. set_mount_point (" / ", " ./html "); std::cout << " Listening on port 8080... " << std::end"},{"title":"Getting Started","url":"/cpp-httplib/en/tour/01-getting-started/","lang":"en","section":"tour","body":"All you need to get started with cpp-httplib is httplib.h and a C++ compiler. Let's download the file and get a Hello World server running. Getting httplib.h You can download it directly from GitHub. Always use the latest version. curl -LO https://github.com/yhirose/cpp-httplib/raw/refs/tags/latest/httplib.h curl -LO https://github.com/yhirose/cpp-httplib/raw/refs/tags/latest/httplib.h Place the downloaded httplib.h in your project directory and you're good to go. Setting Up Your Compiler OS Dev"},{"title":"Basic Server","url":"/cpp-httplib/en/tour/03-basic-server/","lang":"en","section":"tour","body":"In the previous chapter, you sent requests from a client to a test server. Now let's walk through how that server actually works. Starting the Server Once you've registered your routes, call svr.listen() to start the server. svr. listen (" 0.0.0.0 ", 8080 ); svr. listen (" 0.0.0.0 ", 8080 ); The first argument is the host, and the second is the port. \"0.0.0.0\" listens on all network interfaces. Use \"127.0.0.1\" if you want to accept connections from your own machine only. list"},{"title":"Basic Client","url":"/cpp-httplib/en/tour/02-basic-client/","lang":"en","section":"tour","body":"cpp-httplib isn't just for servers -- it also comes with a full HTTP client. Let's use httplib::Client to send GET and POST requests. Preparing a Test Server To try out the client, you need a server that accepts requests. Save the following code, then compile and run it the same way you did in the previous chapter. We'll cover the server details in the next chapter. #include " httplib.h " #include < iostream > int main () { httplib::Server svr; svr. Get (" /hi ", []( co"},{"title":"HTTPS Client","url":"/cpp-httplib/en/tour/06-https-client/","lang":"en","section":"tour","body":"In the previous chapter, you set up OpenSSL. Now let's put it to use with an HTTPS client. You can use the same httplib::Client from Chapter 2. Just pass a URL with the https:// scheme to the constructor. GET Request Let's try accessing a real HTTPS site. #define CPPHTTPLIB_OPENSSL_SUPPORT #include " httplib.h " #include < iostream > int main () { httplib::Client cli (" https://nghttp2.org "); auto res = cli. Get (" / "); if (res) { std::cout << res->"},{"title":"A Tour of cpp-httplib","url":"/cpp-httplib/en/tour/","lang":"en","section":"tour","body":"This is a step-by-step tutorial that walks you through the basics of cpp-httplib. Each chapter builds on the previous one, so please read them in order starting from Chapter 1. Getting Started — Get httplib.h and build a Hello World server Basic Client — Send GET/POST requests and use path parameters Basic Server — Routing, path parameters, and building responses Static File Server — Serve static files TLS Setup — Set up OpenSSL / mbedTLS HTTPS Client — Make requests to HTTPS sites HTTPS Server "},{"title":"What's Next","url":"/cpp-httplib/en/tour/09-whats-next/","lang":"en","section":"tour","body":"Great job finishing the Tour! You now have a solid grasp of the cpp-httplib basics. But there's a lot more to explore. Here's a quick overview of features we didn't cover in the Tour, organized by category. Streaming API When you're working with LLM streaming responses or downloading large files, you don't want to load the entire response into memory. Use stream::Get() to process data chunk by chunk. httplib::Client clLine truncated
|
||||||
Reference in new issue
Block a user