Skip to content

Commit 692dc8c

Browse files
committed
feat: re-designed search UI and new FAQ and Q&A blocks
- Add search-hero block with ==highlight== syntax and gradient mesh backgrounds - Add knowledge-categories block with dynamic Hugo taxonomy counts - Add trending-questions block with content-driven trending system - Add FAQ/questions layouts with Alpine.js accordions and search integration - Redesign search modal using Pagefind headless API to create custom UI design - Add gradient mesh background system (orbs, waves, dots, grid) to framework - Add i18n support for new blocks - Fix video backgrounds regression in parse_block_v3.html - Add QAPage/FAQPage structured data for SEO optimization
1 parent 3eef2cb commit 692dc8c

40 files changed

Lines changed: 2857 additions & 123 deletions
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
---
2+
title: "{{ replace .Name "-" " " | title }}"
3+
date: {{ .Date }}
4+
draft: false
5+
6+
# Summary for SEO
7+
summary: ""
8+
9+
# Mark this as an FAQ page to enable FAQPage structured data
10+
faq_page: true
11+
12+
# Categories and tags
13+
categories: []
14+
tags: []
15+
16+
# Pagefind search metadata (automatically indexed)
17+
# type: faq (auto-added by layout)
18+
# category: first category from categories array above
19+
20+
# Option 1: Define FAQs inline
21+
faqs:
22+
- question: "What is your question here?"
23+
answer: "Your answer here. Can use **Markdown** formatting."
24+
25+
- question: "Another question?"
26+
answer: "Another answer with more details."
27+
28+
# Add more Q&As as needed
29+
30+
# Option 2: Alternatively, create child pages under this FAQ section
31+
# and they will automatically be included
32+
33+
# SEO settings
34+
seo:
35+
title: ""
36+
description: ""
37+
38+
# Show breadcrumb navigation
39+
show_breadcrumb: true
40+
---
41+
42+
Add an introductory text here that will appear before the FAQ accordion.
43+
44+
This is a great place to provide context about the FAQ section.
45+
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
---
2+
title: "{{ replace .Name "-" " " | title }}"
3+
date: {{ .Date }}
4+
draft: false
5+
6+
# The question (can also use title)
7+
question: "{{ replace .Name "-" " " | title }}"
8+
9+
# Short answer (optional - can also use content below)
10+
answer: ""
11+
12+
# Summary for SEO and previews
13+
summary: ""
14+
15+
# Difficulty level (optional)
16+
difficulty: "" # e.g., "Beginner", "Intermediate", "Advanced"
17+
18+
# Categories and tags for organization
19+
categories: []
20+
tags: []
21+
22+
# Pagefind search metadata (automatically indexed)
23+
# type: questions (auto-added by layout)
24+
# category: first category from categories array above
25+
# difficulty: value from difficulty field below
26+
27+
# Vote counts (optional - for display and structured data)
28+
upvote_count: 0
29+
downvote_count: 0
30+
31+
# Additional/suggested answers (optional)
32+
# suggested_answer:
33+
# - text: "Alternative answer text here..."
34+
# author: "Author Name"
35+
# date: 2024-01-15
36+
# upvote_count: 5
37+
38+
# Related questions (optional - can also be auto-generated)
39+
# related:
40+
# - link-to-related-question
41+
42+
# SEO settings
43+
seo:
44+
title: ""
45+
description: ""
46+
47+
# Show breadcrumb navigation
48+
show_breadcrumb: true
49+
---
50+
51+
Write your detailed answer here using Markdown.
52+
53+
You can include:
54+
- Code blocks
55+
- Images
56+
- Lists
57+
- Links
58+
- And more!
59+
60+
## Additional Details
61+
62+
Add sections as needed to provide comprehensive information.

modules/blox-tailwind/assets/css/config/safelist.css

Lines changed: 2 additions & 1 deletion
Large diffs are not rendered by default.

modules/blox-tailwind/assets/css/framework/base.css

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,39 @@
1111
}
1212
}
1313

14+
/* Gradient Mesh Animations */
15+
@keyframes float {
16+
0%, 100% {
17+
transform: translateY(0) translateX(0);
18+
}
19+
25% {
20+
transform: translateY(-20px) translateX(10px);
21+
}
22+
50% {
23+
transform: translateY(-10px) translateX(-10px);
24+
}
25+
75% {
26+
transform: translateY(-30px) translateX(5px);
27+
}
28+
}
29+
30+
@keyframes rotate-slow {
31+
from {
32+
transform: rotate(0deg);
33+
}
34+
to {
35+
transform: rotate(360deg);
36+
}
37+
}
38+
39+
.animate-float {
40+
animation: float 8s ease-in-out infinite;
41+
}
42+
43+
.animate-rotate-slow {
44+
animation: rotate-slow 20s linear infinite;
45+
}
46+
1447
/* Custom utilities and components */
1548
@utility task-list {
1649
list-style: none;
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
/* Hugo Blox Search - Custom Pagefind Implementation */
2+
3+
/* Animations */
4+
@keyframes spin {
5+
to { transform: rotate(360deg); }
6+
}
7+
8+
.animate-spin {
9+
animation: spin 1s linear infinite;
10+
}
11+
12+
/* Search result highlights */
13+
.search-result mark {
14+
background-color: rgb(254 240 138);
15+
color: rgb(17 24 39);
16+
font-weight: 600;
17+
padding: 0.05rem 0.2rem;
18+
border-radius: 0.125rem;
19+
}
20+
21+
.dark .search-result mark {
22+
background-color: rgb(133 77 14);
23+
color: rgb(254 240 138);
24+
}
25+
26+
/* Result hover state */
27+
.search-result:hover mark {
28+
background-color: rgb(253 224 71);
29+
}
30+
31+
.dark .search-result:hover mark {
32+
background-color: rgb(161 98 7);
33+
}
34+
35+
/* Smooth transitions */
36+
.search-modal-enter {
37+
animation: slideInUp 0.2s ease-out;
38+
}
39+
40+
@keyframes slideInUp {
41+
from {
42+
opacity: 0;
43+
transform: translateY(1rem) scale(0.95);
44+
}
45+
to {
46+
opacity: 1;
47+
transform: translateY(0) scale(1);
48+
}
49+
}
50+
51+
/* Loading skeleton */
52+
.search-skeleton {
53+
background: linear-gradient(
54+
90deg,
55+
rgb(229 231 235) 25%,
56+
rgb(243 244 246) 50%,
57+
rgb(229 231 235) 75%
58+
);
59+
background-size: 200% 100%;
60+
animation: shimmer 1.5s infinite;
61+
}
62+
63+
.dark .search-skeleton {
64+
background: linear-gradient(
65+
90deg,
66+
rgb(55 65 81) 25%,
67+
rgb(75 85 99) 50%,
68+
rgb(55 65 81) 75%
69+
);
70+
background-size: 200% 100%;
71+
}
72+
73+
@keyframes shimmer {
74+
0% { background-position: 200% 0; }
75+
100% { background-position: -200% 0; }
76+
}
77+
78+
/* Keyboard navigation highlight - handled by Alpine :class binding */
79+
/* Smooth transition for selection state */
80+
.search-result {
81+
transition: all 0.15s ease;
82+
}
83+
84+
/* Additional hover effects for keyboard-selected items */
85+
.search-result:focus-visible {
86+
outline: 2px solid rgb(59 130 246);
87+
outline-offset: -2px;
88+
}

modules/blox-tailwind/assets/css/main.css

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,5 +35,8 @@
3535
@import "views/all.css";
3636
@import "chroma.css";
3737

38+
/* Hugo Blox Search */
39+
@import "hb-search.css";
40+
3841
/* Safelist for dynamic classes */
3942
@import "config/safelist.css";
Lines changed: 31 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -1,69 +1,32 @@
1-
// Hugo Blox Search functionality
2-
// Initialize search wrapper element globally
3-
let searchWrapper = null;
4-
5-
window.addEventListener("DOMContentLoaded", () => {
6-
const configScript = document.getElementById("search-config");
7-
if (!configScript) {
8-
// No search on this page.
9-
return;
10-
}
11-
12-
const searchConfig = JSON.parse(configScript.textContent);
13-
if (!searchConfig || typeof searchConfig.baseUrl === "undefined") {
14-
console.error("Pagefind search config is missing or invalid.", searchConfig);
15-
return;
16-
}
17-
18-
try {
19-
new PagefindUI({
20-
element: "#search",
21-
showSubResults: true,
22-
baseUrl: searchConfig.baseUrl,
23-
bundlePath: searchConfig.baseUrl + "pagefind/",
1+
// Hugo Blox Search - Custom Pagefind API Implementation
2+
// Search is handled by Alpine.js component in search-modal.html
3+
4+
// Additional keyboard shortcuts and utilities
5+
document.addEventListener('DOMContentLoaded', () => {
6+
console.log('✓ Hugo Blox Search initialized (Pagefind Headless API)');
7+
8+
// Handle search toggle buttons
9+
const searchButtons = document.querySelectorAll('[data-search-toggle]');
10+
searchButtons.forEach(button => {
11+
button.addEventListener('click', (e) => {
12+
const prefilledQuery = button.dataset.searchQuery;
13+
14+
if (window.Alpine && Alpine.store('search')) {
15+
Alpine.store('search').open = true;
16+
17+
// Pre-fill query if specified
18+
if (prefilledQuery) {
19+
setTimeout(() => {
20+
const searchInput = document.querySelector('[x-ref="searchInput"]');
21+
if (searchInput) {
22+
searchInput.value = prefilledQuery;
23+
searchInput.dispatchEvent(new Event('input'));
24+
}
25+
}, 100);
26+
}
27+
}
2428
});
25-
} catch (e) {
26-
console.error("Failed to initialize PagefindUI:", e);
27-
return;
28-
}
29-
30-
// Get search wrapper element
31-
searchWrapper = document.getElementById("search-wrapper");
32-
33-
// Add click handlers to triggers
34-
let triggers = document.querySelectorAll("[data-search-toggle]");
35-
triggers.forEach((trigger) => trigger.addEventListener("click", handleSearchToggle));
36-
});
37-
38-
function handleSearchToggle() {
39-
if (!searchWrapper) return;
40-
41-
const isHidden = searchWrapper.classList.contains("hidden");
42-
searchWrapper.classList.toggle("hidden");
43-
document.body.style.overflow = isHidden ? "hidden" : "";
44-
45-
const searchInput = searchWrapper.querySelector("input");
46-
if (searchInput) {
47-
searchInput.value = "";
48-
searchInput.focus();
49-
}
50-
51-
if (!searchWrapper.classList.contains("hidden")) {
52-
let clearTrigger = document.querySelector(".pagefind-ui__search-clear");
53-
54-
if (clearTrigger && !clearTrigger.hasAttribute("listenerOnClick")) {
55-
clearTrigger.setAttribute("listenerOnClick", "true");
56-
57-
clearTrigger.addEventListener("click", () => {
58-
searchInput.focus();
59-
});
60-
}
61-
}
62-
}
63-
64-
// Add keyboard shortcut to close search modal with Escape key
65-
document.addEventListener("keydown", (event) => {
66-
if (event.key === "Escape" && searchWrapper && !searchWrapper.classList.contains("hidden")) {
67-
searchWrapper.classList.add("hidden");
68-
}
69-
});
29+
});
30+
31+
// Note: Keyboard navigation (arrow keys, Enter) is handled by Alpine.js in search-modal.html
32+
});

0 commit comments

Comments
 (0)