diff --git a/modules/blox-tailwind/archetypes/faq.md b/modules/blox-tailwind/archetypes/faq.md new file mode 100644 index 00000000..7735148c --- /dev/null +++ b/modules/blox-tailwind/archetypes/faq.md @@ -0,0 +1,45 @@ +--- +title: "{{ replace .Name "-" " " | title }}" +date: {{ .Date }} +draft: false + +# Summary for SEO +summary: "" + +# Mark this as an FAQ page to enable FAQPage structured data +faq_page: true + +# Categories and tags +categories: [] +tags: [] + +# Pagefind search metadata (automatically indexed) +# type: faq (auto-added by layout) +# category: first category from categories array above + +# Option 1: Define FAQs inline +faqs: + - question: "What is your question here?" + answer: "Your answer here. Can use **Markdown** formatting." + + - question: "Another question?" + answer: "Another answer with more details." + + # Add more Q&As as needed + +# Option 2: Alternatively, create child pages under this FAQ section +# and they will automatically be included + +# SEO settings +seo: + title: "" + description: "" + +# Show breadcrumb navigation +show_breadcrumb: true +--- + +Add an introductory text here that will appear before the FAQ accordion. + +This is a great place to provide context about the FAQ section. + diff --git a/modules/blox-tailwind/archetypes/questions.md b/modules/blox-tailwind/archetypes/questions.md new file mode 100644 index 00000000..78023ab5 --- /dev/null +++ b/modules/blox-tailwind/archetypes/questions.md @@ -0,0 +1,62 @@ +--- +title: "{{ replace .Name "-" " " | title }}" +date: {{ .Date }} +draft: false + +# The question (can also use title) +question: "{{ replace .Name "-" " " | title }}" + +# Short answer (optional - can also use content below) +answer: "" + +# Summary for SEO and previews +summary: "" + +# Difficulty level (optional) +difficulty: "" # e.g., "Beginner", "Intermediate", "Advanced" + +# Categories and tags for organization +categories: [] +tags: [] + +# Pagefind search metadata (automatically indexed) +# type: questions (auto-added by layout) +# category: first category from categories array above +# difficulty: value from difficulty field below + +# Vote counts (optional - for display and structured data) +upvote_count: 0 +downvote_count: 0 + +# Additional/suggested answers (optional) +# suggested_answer: +# - text: "Alternative answer text here..." +# author: "Author Name" +# date: 2024-01-15 +# upvote_count: 5 + +# Related questions (optional - can also be auto-generated) +# related: +# - link-to-related-question + +# SEO settings +seo: + title: "" + description: "" + +# Show breadcrumb navigation +show_breadcrumb: true +--- + +Write your detailed answer here using Markdown. + +You can include: +- Code blocks +- Images +- Lists +- Links +- And more! + +## Additional Details + +Add sections as needed to provide comprehensive information. diff --git a/modules/blox-tailwind/assets/css/config/safelist.css b/modules/blox-tailwind/assets/css/config/safelist.css index 971a8707..308ca68f 100644 --- a/modules/blox-tailwind/assets/css/config/safelist.css +++ b/modules/blox-tailwind/assets/css/config/safelist.css @@ -3,7 +3,8 @@ /* This ensures Tailwind generates these classes even if not found in templates */ /* Inline safelist for classes used in dynamic content and YAML configuration */ -@source inline("
"); +/* Includes search modal Quick Actions dynamic color classes */ +@source inline("
"); /* Force generation of all CSS custom properties for dynamic usage in YAML front matter */ /* Hidden utility class that forces all color variables to be generated */ diff --git a/modules/blox-tailwind/assets/css/framework/base.css b/modules/blox-tailwind/assets/css/framework/base.css index e111e024..cd3ea9fa 100644 --- a/modules/blox-tailwind/assets/css/framework/base.css +++ b/modules/blox-tailwind/assets/css/framework/base.css @@ -11,6 +11,39 @@ } } +/* Gradient Mesh Animations */ +@keyframes float { + 0%, 100% { + transform: translateY(0) translateX(0); + } + 25% { + transform: translateY(-20px) translateX(10px); + } + 50% { + transform: translateY(-10px) translateX(-10px); + } + 75% { + transform: translateY(-30px) translateX(5px); + } +} + +@keyframes rotate-slow { + from { + transform: rotate(0deg); + } + to { + transform: rotate(360deg); + } +} + +.animate-float { + animation: float 8s ease-in-out infinite; +} + +.animate-rotate-slow { + animation: rotate-slow 20s linear infinite; +} + /* Custom utilities and components */ @utility task-list { list-style: none; diff --git a/modules/blox-tailwind/assets/css/hb-search.css b/modules/blox-tailwind/assets/css/hb-search.css new file mode 100644 index 00000000..39266725 --- /dev/null +++ b/modules/blox-tailwind/assets/css/hb-search.css @@ -0,0 +1,88 @@ +/* Hugo Blox Search - Custom Pagefind Implementation */ + +/* Animations */ +@keyframes spin { + to { transform: rotate(360deg); } +} + +.animate-spin { + animation: spin 1s linear infinite; +} + +/* Search result highlights */ +.search-result mark { + background-color: rgb(254 240 138); + color: rgb(17 24 39); + font-weight: 600; + padding: 0.05rem 0.2rem; + border-radius: 0.125rem; +} + +.dark .search-result mark { + background-color: rgb(133 77 14); + color: rgb(254 240 138); +} + +/* Result hover state */ +.search-result:hover mark { + background-color: rgb(253 224 71); +} + +.dark .search-result:hover mark { + background-color: rgb(161 98 7); +} + +/* Smooth transitions */ +.search-modal-enter { + animation: slideInUp 0.2s ease-out; +} + +@keyframes slideInUp { + from { + opacity: 0; + transform: translateY(1rem) scale(0.95); + } + to { + opacity: 1; + transform: translateY(0) scale(1); + } +} + +/* Loading skeleton */ +.search-skeleton { + background: linear-gradient( + 90deg, + rgb(229 231 235) 25%, + rgb(243 244 246) 50%, + rgb(229 231 235) 75% + ); + background-size: 200% 100%; + animation: shimmer 1.5s infinite; +} + +.dark .search-skeleton { + background: linear-gradient( + 90deg, + rgb(55 65 81) 25%, + rgb(75 85 99) 50%, + rgb(55 65 81) 75% + ); + background-size: 200% 100%; +} + +@keyframes shimmer { + 0% { background-position: 200% 0; } + 100% { background-position: -200% 0; } +} + +/* Keyboard navigation highlight - handled by Alpine :class binding */ +/* Smooth transition for selection state */ +.search-result { + transition: all 0.15s ease; +} + +/* Additional hover effects for keyboard-selected items */ +.search-result:focus-visible { + outline: 2px solid rgb(59 130 246); + outline-offset: -2px; +} \ No newline at end of file diff --git a/modules/blox-tailwind/assets/css/main.css b/modules/blox-tailwind/assets/css/main.css index 77dbcaf6..9e917a5e 100644 --- a/modules/blox-tailwind/assets/css/main.css +++ b/modules/blox-tailwind/assets/css/main.css @@ -35,5 +35,8 @@ @import "views/all.css"; @import "chroma.css"; +/* Hugo Blox Search */ +@import "hb-search.css"; + /* Safelist for dynamic classes */ @import "config/safelist.css"; diff --git a/modules/blox-tailwind/assets/js/hb-search.js b/modules/blox-tailwind/assets/js/hb-search.js index 199f5982..d6b55cac 100644 --- a/modules/blox-tailwind/assets/js/hb-search.js +++ b/modules/blox-tailwind/assets/js/hb-search.js @@ -1,69 +1,32 @@ -// Hugo Blox Search functionality -// Initialize search wrapper element globally -let searchWrapper = null; +// Hugo Blox Search - Custom Pagefind API Implementation +// Search is handled by Alpine.js component in search-modal.html -window.addEventListener("DOMContentLoaded", () => { - const configScript = document.getElementById("search-config"); - if (!configScript) { - // No search on this page. - return; - } - - const searchConfig = JSON.parse(configScript.textContent); - if (!searchConfig || typeof searchConfig.baseUrl === "undefined") { - console.error("Pagefind search config is missing or invalid.", searchConfig); - return; - } - - try { - new PagefindUI({ - element: "#search", - showSubResults: true, - baseUrl: searchConfig.baseUrl, - bundlePath: searchConfig.baseUrl + "pagefind/", +// Additional keyboard shortcuts and utilities +document.addEventListener('DOMContentLoaded', () => { + console.log('✓ Hugo Blox Search initialized (Pagefind Headless API)'); + + // Handle search toggle buttons + const searchButtons = document.querySelectorAll('[data-search-toggle]'); + searchButtons.forEach(button => { + button.addEventListener('click', (e) => { + const prefilledQuery = button.dataset.searchQuery; + + if (window.Alpine && Alpine.store('search')) { + Alpine.store('search').open = true; + + // Pre-fill query if specified + if (prefilledQuery) { + setTimeout(() => { + const searchInput = document.querySelector('[x-ref="searchInput"]'); + if (searchInput) { + searchInput.value = prefilledQuery; + searchInput.dispatchEvent(new Event('input')); + } + }, 100); + } + } }); - } catch (e) { - console.error("Failed to initialize PagefindUI:", e); - return; - } - - // Get search wrapper element - searchWrapper = document.getElementById("search-wrapper"); - - // Add click handlers to triggers - let triggers = document.querySelectorAll("[data-search-toggle]"); - triggers.forEach((trigger) => trigger.addEventListener("click", handleSearchToggle)); -}); - -function handleSearchToggle() { - if (!searchWrapper) return; - - const isHidden = searchWrapper.classList.contains("hidden"); - searchWrapper.classList.toggle("hidden"); - document.body.style.overflow = isHidden ? "hidden" : ""; - - const searchInput = searchWrapper.querySelector("input"); - if (searchInput) { - searchInput.value = ""; - searchInput.focus(); - } - - if (!searchWrapper.classList.contains("hidden")) { - let clearTrigger = document.querySelector(".pagefind-ui__search-clear"); - - if (clearTrigger && !clearTrigger.hasAttribute("listenerOnClick")) { - clearTrigger.setAttribute("listenerOnClick", "true"); - - clearTrigger.addEventListener("click", () => { - searchInput.focus(); - }); - } - } -} - -// Add keyboard shortcut to close search modal with Escape key -document.addEventListener("keydown", (event) => { - if (event.key === "Escape" && searchWrapper && !searchWrapper.classList.contains("hidden")) { - searchWrapper.classList.add("hidden"); - } -}); + }); + + // Note: Keyboard navigation (arrow keys, Enter) is handled by Alpine.js in search-modal.html +}); \ No newline at end of file diff --git a/modules/blox-tailwind/blox/faq/README.md b/modules/blox-tailwind/blox/faq/README.md new file mode 100644 index 00000000..4889adc3 --- /dev/null +++ b/modules/blox-tailwind/blox/faq/README.md @@ -0,0 +1,58 @@ +# FAQ Block + +Display frequently asked questions in an interactive accordion format with automatic FAQPage structured data for SEO. + +## Features + +- ✅ Interactive accordion with Alpine.js +- ✅ FAQPage Schema.org structured data for Google rich results +- ✅ Responsive design with Tailwind CSS +- ✅ Dark mode support +- ✅ Markdown support in answers + +## Usage + +Add to your page's front matter: + +```yaml +sections: + - block: faq + content: + title: Frequently Asked Questions + subtitle: Find answers to common questions + text: Can't find what you're looking for? [Contact us](/contact) + items: + - question: What is Hugo Blox Builder? + answer: Hugo Blox Builder is a no-code website builder framework powered by Hugo and Tailwind CSS. + + - question: Is it free to use? + answer: Yes! Hugo Blox Builder is open source and free to use under the MIT license. + + - question: How do I get started? + answer: | + Getting started is easy: + 1. Choose a template + 2. Click "Use Template" + 3. Customize your content + 4. Deploy to GitHub Pages or Netlify + + button: + text: View All FAQs + url: /faq/ + icon: arrow-right + design: + spacing: + padding: ["6rem", "0", "6rem", "0"] +``` + +## Structured Data + +This block automatically generates FAQPage structured data for better SEO and eligibility for Google's FAQ rich results. + +## Customization + +- **Accordion behavior**: One item open at a time (default) +- **Colors**: Automatically adapts to your theme +- **Spacing**: Customizable via `design.spacing` +- **Background**: Customizable via `design.background.color` + diff --git a/modules/blox-tailwind/blox/faq/block.html b/modules/blox-tailwind/blox/faq/block.html new file mode 100644 index 00000000..0a7c448b --- /dev/null +++ b/modules/blox-tailwind/blox/faq/block.html @@ -0,0 +1,97 @@ +{{- $wcPage := .wcPage -}} +{{- $wcBlock := .wcBlock -}} +{{- $wcIdentifier := .wcIdentifier -}} + +{{/* Enable Alpine.js for interactive accordion */}} +{{ $wcPage.Page.Store.Set "has_alpine" true }} + +{{- $st := $wcBlock.design.spacing | default dict -}} +{{- $pad := $st.padding | default (slice "20px" "0" "20px" "0") -}} +{{- $pad_sm := slice "3rem" "0" -}} +{{- $mar := $st.margin | default (slice "0" "0" "0" "0") -}} + +{{- $bg := $wcBlock.design.background | default dict -}} +{{- $bg_color_val := $bg.color | default "" -}} + +
+
+ + {{- with $wcBlock.content.title -}} +
+

+ {{ . | markdownify | emojify }} +

+ {{- with $wcBlock.content.subtitle -}} +

+ {{ . | markdownify | emojify }} +

+ {{- end -}} +
+ {{- end -}} + + {{- with $wcBlock.content.text -}} +
+ {{ . | markdownify | emojify }} +
+ {{- end -}} + + {{- $items := $wcBlock.content.items | default slice -}} + + {{- if $items -}} +
+
+ {{- range $index, $item := $items -}} +
+ +
+
+ {{ $item.answer | markdownify | emojify }} +
+
+
+ {{- end -}} +
+
+ {{- end -}} + + {{- with $wcBlock.content.button -}} + + {{- end -}} + +
+
+ diff --git a/modules/blox-tailwind/blox/faq/manifest.json b/modules/blox-tailwind/blox/faq/manifest.json new file mode 100644 index 00000000..529dfca8 --- /dev/null +++ b/modules/blox-tailwind/blox/faq/manifest.json @@ -0,0 +1,9 @@ +{ + "name": "faq", + "version": "1", + "title": "FAQ", + "description": "Display frequently asked questions in an accordion format with SEO-optimized structured data", + "categories": ["content", "interactive"], + "preview": "preview.svg" +} + diff --git a/modules/blox-tailwind/blox/faq/preview.svg b/modules/blox-tailwind/blox/faq/preview.svg new file mode 100644 index 00000000..5e51c7c8 --- /dev/null +++ b/modules/blox-tailwind/blox/faq/preview.svg @@ -0,0 +1,32 @@ + + + + + + + + + + + + + FAQ + + + + What is this feature? + + + + + How does it work? + + + + + Where can I learn more? + + Check our documentation + for detailed guides... + + diff --git a/modules/blox-tailwind/blox/faq/schema.json b/modules/blox-tailwind/blox/faq/schema.json new file mode 100644 index 00000000..3cc84414 --- /dev/null +++ b/modules/blox-tailwind/blox/faq/schema.json @@ -0,0 +1,95 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "object", + "title": "FAQ Block", + "description": "Display frequently asked questions in an accordion format with FAQPage structured data", + "properties": { + "content": { + "type": "object", + "properties": { + "title": { + "type": "string", + "description": "Block title" + }, + "subtitle": { + "type": "string", + "description": "Block subtitle" + }, + "text": { + "type": "string", + "description": "Introductory text (Markdown supported)" + }, + "items": { + "type": "array", + "description": "FAQ items", + "items": { + "type": "object", + "properties": { + "question": { + "type": "string", + "description": "The question" + }, + "answer": { + "type": "string", + "description": "The answer (Markdown supported)" + } + }, + "required": ["question", "answer"] + } + }, + "button": { + "type": "object", + "description": "Call-to-action button", + "properties": { + "text": { + "type": "string", + "description": "Button text" + }, + "url": { + "type": "string", + "description": "Button URL" + }, + "icon": { + "type": "string", + "description": "Button icon name" + } + } + } + } + }, + "design": { + "type": "object", + "properties": { + "spacing": { + "type": "object", + "properties": { + "padding": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Padding [top, right, bottom, left]" + }, + "margin": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Margin [top, right, bottom, left]" + } + } + }, + "background": { + "type": "object", + "properties": { + "color": { + "type": "string", + "description": "Background color CSS class" + } + } + } + } + } + } +} + diff --git a/modules/blox-tailwind/blox/knowledge-categories/block.html b/modules/blox-tailwind/blox/knowledge-categories/block.html new file mode 100644 index 00000000..41db2995 --- /dev/null +++ b/modules/blox-tailwind/blox/knowledge-categories/block.html @@ -0,0 +1,97 @@ +{{- $wcPage := .wcPage -}} +{{- $wcBlock := .wcBlock -}} +{{- $wcIdentifier := .wcIdentifier -}} + +{{- $st := $wcBlock.design.spacing | default dict -}} +{{- $pad := $st.padding | default (slice "4rem" "0" "4rem" "0") -}} + +
+
+ + {{/* Section header */}} + {{ if or $wcBlock.content.title $wcBlock.content.subtitle }} +
+ {{ with $wcBlock.content.title }} +

+ {{ . | markdownify }} +

+ {{ end }} + {{ with $wcBlock.content.subtitle }} +

+ {{ . | markdownify }} +

+ {{ end }} +
+ {{ end }} + + {{/* Categories grid - with dynamic counts from Hugo taxonomy */}} +
+ + {{ range $wcBlock.content.categories }} + {{ $category_name := .category | default .title }} + + {{/* Get actual count from Hugo taxonomy - proper Hugo syntax */}} + {{ $category_url := "" }} + {{ $actual_count := 0 }} + {{ with site.Taxonomies.categories.Get $category_name }} + {{ $actual_count = .Count }} + {{ $category_url = .Page.RelPermalink }} + {{ end }} + + {{/* Only show category if it has content OR if count is explicitly set */}} + {{ if or (gt $actual_count 0) (.count) }} + + + {{/* Icon */}} + {{ with .icon }} +
+ {{ partial "functions/get_icon" (dict "name" .name "attributes" "class=\"h-6 w-6\"") }} +
+ {{ end }} + + {{/* Title */}} +

+ {{ .title }} +

+ + {{/* Description */}} + {{ with .description }} +

+ {{ . }} +

+ {{ end }} + + {{/* Stats - use actual count from taxonomy, fallback to manual count */}} +
+ {{ $display_count := default .count $actual_count }} + {{ if $display_count }} + + {{ $display_count }} {{ cond (eq $display_count 1) (T "article" | default "article") (T "articles" | default "articles") }} + + {{ end }} + + {{ T "browse" | default "Browse" }} → + +
+ + {{/* Hover gradient effect */}} +
+
+ {{ end }} + {{ end }} +
+ + {{/* View all link */}} + {{ with $wcBlock.content.view_all }} + + {{ end }} + +
+
diff --git a/modules/blox-tailwind/blox/knowledge-categories/manifest.json b/modules/blox-tailwind/blox/knowledge-categories/manifest.json new file mode 100644 index 00000000..f67a38b1 --- /dev/null +++ b/modules/blox-tailwind/blox/knowledge-categories/manifest.json @@ -0,0 +1,8 @@ +{ + "name": "knowledge-categories", + "version": "1", + "title": "Knowledge Categories", + "description": "Grid of knowledge base category cards", + "categories": ["content", "navigation"], + "preview": "preview.svg" +} diff --git a/modules/blox-tailwind/blox/knowledge-categories/schema.json b/modules/blox-tailwind/blox/knowledge-categories/schema.json new file mode 100644 index 00000000..d2a534f1 --- /dev/null +++ b/modules/blox-tailwind/blox/knowledge-categories/schema.json @@ -0,0 +1,74 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "object", + "title": "Knowledge Categories Block", + "description": "Grid of knowledge base category cards", + "properties": { + "content": { + "type": "object", + "properties": { + "title": { + "type": "string" + }, + "subtitle": { + "type": "string" + }, + "categories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "description": "Category name (e.g., 'Getting Started', 'ChatGPT') - will be auto-slugified for URL" + }, + "title": { + "type": "string", + "description": "Display title (optional - defaults to category name)" + }, + "description": { + "type": "string" + }, + "icon": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "bg_color": { + "type": "string" + }, + "text_color": { + "type": "string" + } + } + }, + "count": { + "type": "number" + } + } + } + }, + "view_all": { + "type": "object", + "properties": { + "text": { + "type": "string" + }, + "link": { + "type": "string" + } + } + } + } + }, + "design": { + "type": "object", + "properties": { + "spacing": { + "type": "object" + } + } + } + } +} diff --git a/modules/blox-tailwind/blox/search-hero/README.md b/modules/blox-tailwind/blox/search-hero/README.md new file mode 100644 index 00000000..629a1b7b --- /dev/null +++ b/modules/blox-tailwind/blox/search-hero/README.md @@ -0,0 +1,265 @@ +# Search Hero Block + +A modern hero section with prominent search functionality, perfect for knowledge bases and documentation sites. + +## Features + +- 🔍 **Integrated Search** - Opens Hugo Blox search modal +- 💎 **Gradient Text Highlighting** - Eye-catching emphasized text +- 🎨 **Animated Backgrounds** - Gradient mesh with pulsing orbs +- 📊 **Stats Display** - Showcase key metrics +- 🏷️ **Badge Support** - With optional pulsing indicator +- 🔥 **Popular Searches** - Quick suggestion pills +- 📱 **Fully Responsive** - Beautiful on all devices + +## Basic Usage + +```yaml +sections: + - block: search-hero + content: + title: "Your Knowledge Hub" + subtitle: "Find answers to all your questions" +``` + +## Title Highlighting + +Use `==text==` syntax to apply gradient highlighting to any words or phrases: + +### Single Highlight + +```yaml +title: "Master ==AI Tools==" +``` + +**Result**: "Master" in regular text, "AI Tools" with gradient + +### Multiple Highlights + +```yaml +title: "Master ==AI Tools==. ==Boost Your Productivity.==" +``` + +**Result**: Both "AI Tools" and "Boost Your Productivity" highlighted + +### Mid-Sentence Highlighting + +```yaml +title: "Build ==amazing== websites with ==Hugo Blox==" +``` + +**Result**: "amazing" and "Hugo Blox" highlighted within the sentence + +### i18n-Friendly + +```yaml +# en.yaml +- id: hero_title + translation: "Master ==AI Tools==. ==Boost Productivity.==" + +# es.yaml +- id: hero_title + translation: "Domina ==Herramientas IA==. ==Aumenta Productividad.==" +``` + +Each language can highlight naturally! + +## Complete Example + +```yaml +sections: + - block: search-hero + content: + badge: + text: "500+ AI answers added this week" + show_pulse: true # Shows pulsing dot indicator + + title: "Master ==AI Tools==. ==Boost Your Productivity.==" + + subtitle: "Get instant answers to your AI questions from our comprehensive knowledge base." + + search_placeholder: "Ask anything about AI tools, prompts, or workflows..." + + suggestions: + - "ChatGPT prompts" + - "Midjourney tips" + - "AI automation" + - "Claude vs GPT-4" + + stats: + - value: "2,500+" + label: "Expert Answers" + - value: "50K+" + label: "Monthly Users" + - value: "4.9/5" + label: "User Rating" + + design: + background: + gradient_mesh: + enable: true + style: "orbs" # orbs, waves, dots, grid + animation: "pulse" # pulse, float, rotate, none + intensity: "subtle" # subtle, medium, bold + colors: + - "primary-500/20" + - "primary-600/20" + spacing: + padding: ["8rem", "0", "6rem", "0"] +``` + +## Properties + +### Content + +#### `badge` +- **Type**: Object +- **Optional** +- **Properties**: + - `text` (string): Badge text + - `show_pulse` (boolean): Show pulsing dot indicator + +#### `title` +- **Type**: String +- **Required** +- **Description**: Main heading. Use `==text==` for gradient highlighting +- **Example**: `"Build ==Amazing== Websites"` + +#### `subtitle` +- **Type**: String +- **Optional** +- **Description**: Supporting text below title + +#### `search_placeholder` +- **Type**: String +- **Optional** +- **Default**: "Search for answers..." +- **Description**: Placeholder text in search box + +#### `suggestions` +- **Type**: Array of strings +- **Optional** +- **Description**: Quick search suggestion pills +- **Example**: `["Topic 1", "Topic 2"]` + +#### `stats` +- **Type**: Array of objects +- **Optional** +- **Description**: Metrics displayed below search +- **Properties**: + - `value` (string): Metric value (e.g., "2,500+") + - `label` (string): Metric description + +### Design + +See [Gradient Mesh Guide](../../../../GRADIENT_MESH_GUIDE.md) for complete background options. + +## Styling Tips + +### Gradient Colors + +The `==text==` highlighting uses: +```css +background: linear-gradient(to-right, primary-600, primary-500); +background-clip: text; +``` + +This automatically adapts to your site's primary color theme. + +### Stat Layout + +Stats automatically: +- Display in 3-column grid +- Center-aligned +- Responsive on mobile + +### Search Integration + +The search button automatically: +- Opens Hugo Blox search modal +- Works with Cmd+K shortcut +- Supports pre-filled queries from suggestions + +## Examples + +### Knowledge Base (Current) + +```yaml +title: "Master ==AI Tools==. ==Boost Your Productivity.==" +``` + +### Documentation Site + +```yaml +title: "==Comprehensive== Documentation for ==Developers==" +``` + +### Product Landing + +```yaml +title: "Build ==Faster==. Ship ==Better==. Scale ==Effortlessly.==" +``` + +### Academic/Research + +```yaml +title: "Advancing ==Science== Through ==Collaboration==" +``` + +## Best Practices + +### 1. Highlight Key Value Props + +✅ **Good**: Highlight unique value or action words +```yaml +title: "Learn ==Faster== with AI" +``` + +❌ **Bad**: Highlight common words +```yaml +title: "Learn Faster ==with== AI" +``` + +### 2. Don't Over-Highlight + +✅ **Good**: 1-3 highlighted phrases max +```yaml +title: "Master ==AI Tools==. Boost ==Productivity==." +``` + +❌ **Bad**: Everything highlighted +```yaml +title: "==Master== ==AI== ==Tools==. ==Boost== ==Your== ==Productivity==." +``` + +### 3. Keep Highlights Meaningful + +Highlighted text should be: +- **Scannable** - Key phrases users notice first +- **Actionable** - Words that convey benefit +- **Brief** - 1-4 words per highlight + +## Advanced Examples + +### Corporate Landing + +```yaml +title: "Transform ==Your Business== with AI" +``` + +### Educational Platform + +```yaml +title: "Learn ==Smarter==, Not ==Harder==" +``` + +## Technical Notes + +- **Regex Pattern**: `==([^=]+)==` matches text between double equals +- **Processing**: Applied before markdownify, so Markdown works inside highlights +- **Output**: `text` +- **Performance**: No runtime cost, processed at build time + +--- + +**Part of Hugo Blox Builder** - https://hugoblox.com diff --git a/modules/blox-tailwind/blox/search-hero/block.html b/modules/blox-tailwind/blox/search-hero/block.html new file mode 100644 index 00000000..99d10bf6 --- /dev/null +++ b/modules/blox-tailwind/blox/search-hero/block.html @@ -0,0 +1,98 @@ +{{- $wcPage := .wcPage -}} +{{- $wcBlock := .wcBlock -}} +{{- $wcIdentifier := .wcIdentifier -}} + +{{/* Enable Alpine.js for interactivity */}} +{{ $wcPage.Page.Store.Set "has_alpine" true }} + +{{/* Background is now handled by parse_block_v3.html gradient_mesh system */}} +{{/* Content only - wrapper and styling applied by framework */}} +
+
+ + {{/* Badge */}} + {{ with $wcBlock.content.badge }} +
+ {{ with .show_pulse }} + + + + + {{ end }} + {{ .text | markdownify }} +
+ {{ end }} + + {{/* Title - supports ==highlight== syntax for gradient text */}} + {{ $title := $wcBlock.content.title }} + {{/* Replace ==text== with gradient-highlighted spans - supports multiple highlights */}} + {{ $title = replaceRE "==([^=]+)==" "$1" $title }} + +

+ {{ $title | markdownify | emojify | safeHTML }} +

+ + {{/* Subtitle */}} + {{ with $wcBlock.content.subtitle }} +

+ {{ . | markdownify | emojify }} +

+ {{ end }} + + {{/* Search Box - Integrates with Pagefind */}} +
+ + + {{/* Quick search suggestions - Now trigger Pagefind with pre-filled query */}} + {{ with $wcBlock.content.suggestions }} +
+ Popular: + {{ range . }} + + {{ end }} +
+ {{ end }} +
+ + {{/* Stats */}} + {{ if $wcBlock.content.stats }} +
+ {{ range $wcBlock.content.stats }} +
+
{{ .value }}
+
{{ .label }}
+
+ {{ end }} +
+ {{ end }} + +
+
diff --git a/modules/blox-tailwind/blox/search-hero/manifest.json b/modules/blox-tailwind/blox/search-hero/manifest.json new file mode 100644 index 00000000..0d737d97 --- /dev/null +++ b/modules/blox-tailwind/blox/search-hero/manifest.json @@ -0,0 +1,8 @@ +{ + "name": "search-hero", + "version": "1", + "title": "Search Hero", + "description": "Hero section with prominent search for knowledge bases", + "categories": ["hero", "search"], + "preview": "preview.svg" +} diff --git a/modules/blox-tailwind/blox/search-hero/schema.json b/modules/blox-tailwind/blox/search-hero/schema.json new file mode 100644 index 00000000..63eca263 --- /dev/null +++ b/modules/blox-tailwind/blox/search-hero/schema.json @@ -0,0 +1,114 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "object", + "title": "Search Hero Block", + "description": "A hero section with prominent search functionality for knowledge bases", + "properties": { + "content": { + "type": "object", + "properties": { + "badge": { + "type": "object", + "properties": { + "text": { + "type": "string", + "description": "Badge text" + }, + "show_pulse": { + "type": "boolean", + "description": "Show pulsing dot indicator" + } + } + }, + "title": { + "type": "string", + "description": "Main title. Use ==text== syntax to apply gradient highlighting to any words or phrases. Example: 'Master ==AI Tools==. ==Boost Your Productivity.=='" + }, + "subtitle": { + "type": "string", + "description": "Subtitle text" + }, + "search_placeholder": { + "type": "string", + "description": "Search input placeholder" + }, + "suggestions": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Quick search suggestions" + }, + "stats": { + "type": "array", + "items": { + "type": "object", + "properties": { + "value": { + "type": "string", + "description": "Stat value" + }, + "label": { + "type": "string", + "description": "Stat label" + } + } + } + } + } + }, + "design": { + "type": "object", + "properties": { + "spacing": { + "type": "object" + }, + "background": { + "type": "object", + "properties": { + "color": { + "type": "string", + "description": "Background color (Tailwind class)" + }, + "gradient_mesh": { + "type": "object", + "description": "Animated gradient mesh background", + "properties": { + "enable": { + "type": "boolean", + "description": "Enable animated gradient mesh" + }, + "style": { + "type": "string", + "enum": ["orbs", "waves", "dots", "grid"], + "description": "Visual style of gradient mesh", + "default": "orbs" + }, + "animation": { + "type": "string", + "enum": ["pulse", "float", "rotate", "none"], + "description": "Animation type", + "default": "pulse" + }, + "intensity": { + "type": "string", + "enum": ["subtle", "medium", "bold"], + "description": "Visual intensity", + "default": "subtle" + }, + "colors": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Tailwind colors with opacity (e.g., 'primary-500/20')", + "default": ["primary-500/20", "primary-600/20"] + } + } + } + } + } + } + } + } +} diff --git a/modules/blox-tailwind/blox/trending-questions/block.html b/modules/blox-tailwind/blox/trending-questions/block.html new file mode 100644 index 00000000..60c1af21 --- /dev/null +++ b/modules/blox-tailwind/blox/trending-questions/block.html @@ -0,0 +1,165 @@ +{{- $wcPage := .wcPage -}} +{{- $wcBlock := .wcBlock -}} +{{- $wcIdentifier := .wcIdentifier -}} + +{{- $st := $wcBlock.design.spacing | default dict -}} +{{- $pad := $st.padding | default (slice "4rem" "0" "4rem" "0") -}} + +
+
+ +
+
+ {{ with $wcBlock.content.title }} +

+ {{ . | markdownify }} +

+ {{ end }} + {{ with $wcBlock.content.subtitle }} +

+ {{ . | markdownify }} +

+ {{ end }} +
+ + {{ with $wcBlock.content.view_all }} + + {{ end }} +
+ + {{/* Get trending questions dynamically or from static config */}} + {{ $questions := slice }} + + {{/* Method 1: Dynamic - Pull from pages with trending: true */}} + {{ $count := $wcBlock.content.count | default 4 }} + {{ $trending_pages := where site.RegularPages "Params.trending" true }} + {{ $trending_pages = $trending_pages.ByParam "trending_weight" | default ($trending_pages.ByDate.Reverse) }} + {{ $trending_pages = first $count $trending_pages }} + + {{ if $trending_pages }} + {{ range $trending_pages }} + {{ $question_item := dict }} + {{ $question_item = merge $question_item (dict "question" (.Params.question | default .Title)) }} + {{ $question_item = merge $question_item (dict "link" .RelPermalink) }} + {{ $question_item = merge $question_item (dict "answer_preview" (.Params.answer_preview | default .Params.answer | default .Summary | plainify | truncate 150)) }} + + {{/* Optional metadata */}} + {{ with .Params.author }} + {{ $question_item = merge $question_item (dict "author" .) }} + {{ end }} + {{ with .Params.views }} + {{ $question_item = merge $question_item (dict "views" .) }} + {{ end }} + {{ with .Params.upvote_count }} + {{ $question_item = merge $question_item (dict "upvotes" .) }} + {{ end }} + {{ with .Params.badge }} + {{ $question_item = merge $question_item (dict "badge" .) }} + {{ else }} + {{/* Default badges based on metadata */}} + {{ if gt (.Params.upvote_count | default 0) 50 }} + {{ $question_item = merge $question_item (dict "badge" (dict "text" "🔥 Popular" "color" "bg-red-100 text-red-800 dark:bg-red-900/30 dark:text-red-200")) }} + {{ else if .Params.featured }} + {{ $question_item = merge $question_item (dict "badge" (dict "text" "⭐ Featured" "color" "bg-blue-100 text-blue-800 dark:bg-blue-900/30 dark:text-blue-200")) }} + {{ else if (time .Date).After (now.AddDate 0 0 -7) }} + {{ $question_item = merge $question_item (dict "badge" (dict "text" "✨ New" "color" "bg-green-100 text-green-800 dark:bg-green-900/30 dark:text-green-200")) }} + {{ else }} + {{ $question_item = merge $question_item (dict "badge" (dict "text" "🔥 Trending" "color" "bg-amber-100 text-amber-800 dark:bg-amber-900/30 dark:text-amber-200")) }} + {{ end }} + {{ end }} + + {{ $questions = $questions | append $question_item }} + {{ end }} + {{ end }} + + {{/* Method 2: Static fallback - Use config if no trending pages found */}} + {{ if not $questions }} + {{ $questions = $wcBlock.content.questions }} + {{ end }} + + {{/* Questions list or carousel */}} +
+ {{ range $index, $question := $questions }} +
+ + {{/* Badge */}} + {{ with .badge }} +
+ {{ .text }} +
+ {{ end }} + + {{/* Question */}} +

+ + {{ .question }} + +

+ + {{/* Answer preview */}} + {{ with .answer_preview }} +

+ {{ . }} +

+ {{ end }} + + {{/* Meta info */}} +
+
+ {{ with .author }} + + + + + {{ . }} + + {{ end }} + + {{ with .views }} + + + + + + {{ . }} + + {{ end }} + + {{ with .upvotes }} + + + + + {{ . }} helpful + + {{ end }} +
+ + + Read → + +
+ +
+ {{ end }} +
+ + {{/* Mobile view all link */}} + {{ with $wcBlock.content.view_all }} + + {{ end }} + +
+
\ No newline at end of file diff --git a/modules/blox-tailwind/blox/trending-questions/manifest.json b/modules/blox-tailwind/blox/trending-questions/manifest.json new file mode 100644 index 00000000..dda443e9 --- /dev/null +++ b/modules/blox-tailwind/blox/trending-questions/manifest.json @@ -0,0 +1,8 @@ +{ + "name": "trending-questions", + "version": "1", + "title": "Trending Questions", + "description": "Display trending or featured questions", + "categories": ["content"], + "preview": "preview.svg" +} diff --git a/modules/blox-tailwind/blox/trending-questions/schema.json b/modules/blox-tailwind/blox/trending-questions/schema.json new file mode 100644 index 00000000..6106d480 --- /dev/null +++ b/modules/blox-tailwind/blox/trending-questions/schema.json @@ -0,0 +1,83 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "object", + "title": "Trending Questions Block", + "description": "Display trending or featured questions", + "properties": { + "content": { + "type": "object", + "properties": { + "title": { + "type": "string" + }, + "subtitle": { + "type": "string" + }, + "questions": { + "type": "array", + "items": { + "type": "object", + "properties": { + "question": { + "type": "string" + }, + "answer_preview": { + "type": "string" + }, + "link": { + "type": "string" + }, + "badge": { + "type": "object", + "properties": { + "text": { + "type": "string" + }, + "color": { + "type": "string" + } + } + }, + "author": { + "type": "string" + }, + "views": { + "type": "string" + }, + "upvotes": { + "type": "number" + } + } + } + }, + "view_all": { + "type": "object", + "properties": { + "text": { + "type": "string" + }, + "link": { + "type": "string" + } + } + } + } + }, + "design": { + "type": "object", + "properties": { + "spacing": { + "type": "object" + }, + "background": { + "type": "object", + "properties": { + "color": { + "type": "string" + } + } + } + } + } + } +} diff --git a/modules/blox-tailwind/i18n/en.yaml b/modules/blox-tailwind/i18n/en.yaml index d55ef490..84a26cce 100644 --- a/modules/blox-tailwind/i18n/en.yaml +++ b/modules/blox-tailwind/i18n/en.yaml @@ -335,6 +335,48 @@ - id: authors translation: Authors +- id: qa + translation: Q&A + +- id: questions + translation: Questions + +- id: faq + translation: FAQ + +- id: faqs + translation: FAQs + +- id: docs + translation: Documentation + +- id: question + translation: Question + +- id: answer + translation: Answer + +- id: accepted_answer + translation: Accepted Answer + +- id: other_answers + translation: Other Answers + +- id: related_questions + translation: Related Questions + +- id: browse_by_category + translation: Browse by Category + +- id: search_questions + translation: Search questions... + +- id: no_questions_yet + translation: No questions yet. Check back soon! + +- id: questions_count + translation: questions + # Search - id: search @@ -409,3 +451,18 @@ # Card metadata - id: trending translation: Trending + +- id: article + translation: article + +- id: articles + translation: articles + +- id: browse + translation: Browse + +- id: all + translation: All + +- id: helpful + translation: helpful diff --git a/modules/blox-tailwind/layouts/404.html b/modules/blox-tailwind/layouts/404.html index 1b200117..bbacc5a8 100644 --- a/modules/blox-tailwind/layouts/404.html +++ b/modules/blox-tailwind/layouts/404.html @@ -1,5 +1,6 @@ {{- define "main" -}} -
+{{/* Exclude 404 page from search indexing */}} +

{{ i18n "page_not_found" }}

diff --git a/modules/blox-tailwind/layouts/_partials/components/headers/navbar.html b/modules/blox-tailwind/layouts/_partials/components/headers/navbar.html index f5ed7950..8ace0b83 100644 --- a/modules/blox-tailwind/layouts/_partials/components/headers/navbar.html +++ b/modules/blox-tailwind/layouts/_partials/components/headers/navbar.html @@ -142,7 +142,7 @@ {{ with $show_search }} diff --git a/modules/blox-tailwind/layouts/_partials/components/search-modal.html b/modules/blox-tailwind/layouts/_partials/components/search-modal.html index 70d74e5a..7431520d 100644 --- a/modules/blox-tailwind/layouts/_partials/components/search-modal.html +++ b/modules/blox-tailwind/layouts/_partials/components/search-modal.html @@ -1,20 +1,523 @@ +{{/* Modern Search Modal - Custom Pagefind API Implementation */}}