feat: 3-column layout with centered results and right column
- results-layout: 3-column grid (1fr | min(768px,100%) | 300px) max-width 1400px, centered - Widen center results column to 768px max - Right column (formerly sidebar): sticky, contains knowledge panel + related searches - Knowledge panel: Wikipedia/infobox summary with optional thumbnail - Related searches: clickable links to refine the query - Empty left buffer creates balanced whitespace on large screens - Responsive: 2-col at 1000px, 1-col at 700px
This commit is contained in:
parent
2d22a8cdbb
commit
4b0cde91ed
4 changed files with 105 additions and 92 deletions
|
|
@ -235,11 +235,22 @@ main {
|
||||||
padding-top: 1.5rem;
|
padding-top: 1.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 3-column layout: empty left buffer | center results | right column
|
||||||
|
max-width 1400px, centered on page */
|
||||||
.results-layout {
|
.results-layout {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: 1fr 220px;
|
grid-template-columns: 1fr min(768px, 100%) 300px;
|
||||||
gap: 2rem;
|
gap: 2rem;
|
||||||
align-items: start;
|
align-items: start;
|
||||||
|
max-width: 1400px;
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 1000px) {
|
||||||
|
.results-layout {
|
||||||
|
grid-template-columns: 1fr 260px;
|
||||||
|
gap: 1.5rem;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 700px) {
|
@media (max-width: 700px) {
|
||||||
|
|
@ -249,7 +260,7 @@ main {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Compact search bar on results page */
|
/* Compact search bar spans all columns */
|
||||||
.search-compact {
|
.search-compact {
|
||||||
grid-column: 1 / -1;
|
grid-column: 1 / -1;
|
||||||
}
|
}
|
||||||
|
|
@ -380,12 +391,15 @@ main {
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ============================================================
|
/* ============================================================
|
||||||
Sidebar
|
Right Column (formerly sidebar)
|
||||||
============================================================ */
|
============================================================ */
|
||||||
|
|
||||||
.sidebar {
|
.right-column {
|
||||||
position: sticky;
|
position: sticky;
|
||||||
top: calc(var(--header-height) + 1.5rem);
|
top: calc(var(--header-height) + 1.5rem);
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.sidebar-card {
|
.sidebar-card {
|
||||||
|
|
@ -393,18 +407,65 @@ main {
|
||||||
border: 1px solid var(--border);
|
border: 1px solid var(--border);
|
||||||
border-radius: var(--radius-md);
|
border-radius: var(--radius-md);
|
||||||
padding: 1rem;
|
padding: 1rem;
|
||||||
margin-bottom: 1rem;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.sidebar-title {
|
.sidebar-card-title {
|
||||||
font-size: 0.75rem;
|
font-size: 0.7rem;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
letter-spacing: 0.05em;
|
letter-spacing: 0.06em;
|
||||||
color: var(--text-muted);
|
color: var(--text-muted);
|
||||||
margin-bottom: 0.75rem;
|
margin-bottom: 0.75rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Knowledge Panel card */
|
||||||
|
.knowledge-panel {
|
||||||
|
background: var(--bg-secondary);
|
||||||
|
border: 1px solid var(--border);
|
||||||
|
border-radius: var(--radius-md);
|
||||||
|
padding: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.knowledge-panel-title {
|
||||||
|
font-size: 1rem;
|
||||||
|
font-weight: 600;
|
||||||
|
color: var(--text-primary);
|
||||||
|
margin-bottom: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.knowledge-panel-content {
|
||||||
|
font-size: 0.875rem;
|
||||||
|
color: var(--text-secondary);
|
||||||
|
line-height: 1.55;
|
||||||
|
}
|
||||||
|
|
||||||
|
.knowledge-panel-thumb {
|
||||||
|
width: 100%;
|
||||||
|
border-radius: var(--radius-sm);
|
||||||
|
margin-bottom: 0.75rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Related searches */
|
||||||
|
.related-searches {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 0.35rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.related-search-link {
|
||||||
|
font-size: 0.85rem;
|
||||||
|
color: var(--accent);
|
||||||
|
text-decoration: none;
|
||||||
|
padding: 0.25rem 0;
|
||||||
|
border-radius: var(--radius-sm);
|
||||||
|
transition: color 0.15s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.related-search-link:hover {
|
||||||
|
color: var(--accent-hover);
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
/* Suggestions in sidebar */
|
/* Suggestions in sidebar */
|
||||||
.suggestion-list {
|
.suggestion-list {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|
|
||||||
|
|
@ -1,94 +1,53 @@
|
||||||
{{define "title"}}{{if .Query}}{{.Query}} — {{end}}{{end}}
|
{{define "title"}}{{if .Query}}{{.Query}} — {{end}}{{end}}
|
||||||
{{define "content"}}
|
{{define "content"}}
|
||||||
<div class="results-layout">
|
<div class="results-layout">
|
||||||
<!-- Left Sidebar -->
|
<!-- Compact search bar spans all columns -->
|
||||||
<aside class="left-sidebar" id="left-sidebar">
|
<div class="search-compact">
|
||||||
<nav class="sidebar-nav">
|
<div class="search-box">
|
||||||
<div class="sidebar-nav-title">Categories</div>
|
<form method="GET" action="/search" role="search" id="search-form">
|
||||||
{{range .Categories}}
|
<input type="text" name="q" id="q" value="{{.Query}}" autocomplete="off" autofocus
|
||||||
<a href="/search?q={{$.Query | urlquery}}&category={{.}}" class="sidebar-nav-item {{if eq $.ActiveCategory .}}active{{end}}">
|
hx-get="/search" hx-target="#results" hx-trigger="keyup changed delay:500ms" hx-include="this">
|
||||||
<span class="sidebar-nav-item-icon">{{index $.CategoryIcons .}}</span>
|
<button type="submit" class="search-box-submit" aria-label="Search">
|
||||||
<span>{{.}}</span>
|
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">
|
||||||
</a>
|
<circle cx="11" cy="11" r="8"/>
|
||||||
{{end}}
|
<path d="m21 21-4.35-4.35"/>
|
||||||
<!-- Disabled categories with no links -->
|
</svg>
|
||||||
{{range .DisabledCategories}}
|
</button>
|
||||||
<span class="sidebar-nav-item disabled">
|
</form>
|
||||||
<span class="sidebar-nav-item-icon">{{index $.CategoryIcons .}}</span>
|
|
||||||
<span>{{.}}</span>
|
|
||||||
</span>
|
|
||||||
{{end}}
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
<form method="GET" action="/search" class="sidebar-filters"
|
|
||||||
hx-get="/search" hx-target="#results" hx-trigger="change" hx-swap="innerHTML">
|
|
||||||
<input type="hidden" name="q" value="{{.Query | urlquery}}">
|
|
||||||
<input type="hidden" name="category" value="{{.ActiveCategory}}">
|
|
||||||
<div class="sidebar-filter-group">
|
|
||||||
<div class="sidebar-filter-label">Time</div>
|
|
||||||
{{range .TimeFilters}}
|
|
||||||
<label class="sidebar-filter-option">
|
|
||||||
<input type="radio" name="time" value="{{.Value}}" {{if eq $.ActiveTime .Value}}checked{{end}}>
|
|
||||||
<span>{{.Label}}</span>
|
|
||||||
</label>
|
|
||||||
{{end}}
|
|
||||||
</div>
|
|
||||||
<div class="sidebar-filter-group">
|
|
||||||
<div class="sidebar-filter-label">Type</div>
|
|
||||||
{{range .TypeFilters}}
|
|
||||||
<label class="sidebar-filter-option">
|
|
||||||
<input type="radio" name="type" value="{{.Value}}" {{if eq $.ActiveType .Value}}checked{{end}}>
|
|
||||||
<span>{{.Label}}</span>
|
|
||||||
</label>
|
|
||||||
{{end}}
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</aside>
|
|
||||||
|
|
||||||
<!-- Center Column -->
|
|
||||||
<div class="results-column">
|
|
||||||
<!-- Compact search bar -->
|
|
||||||
<div class="search-compact">
|
|
||||||
<div class="search-box">
|
|
||||||
<form method="GET" action="/search" role="search" id="search-form">
|
|
||||||
<input type="text" name="q" id="q" value="{{.Query}}" autocomplete="off" autofocus
|
|
||||||
hx-get="/search" hx-target="#results" hx-trigger="keyup changed delay:500ms" hx-include="this">
|
|
||||||
<button type="submit" class="search-box-submit" aria-label="Search">
|
|
||||||
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">
|
|
||||||
<circle cx="11" cy="11" r="8"/>
|
|
||||||
<path d="m21 21-4.35-4.35"/>
|
|
||||||
</svg>
|
|
||||||
</button>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- Mobile filter chips -->
|
<!-- Center: Results -->
|
||||||
<div class="mobile-filter-chips">
|
<div class="results-column" id="results">
|
||||||
<a href="/search?q={{.Query | urlquery}}" class="mobile-filter-chip {{if not .ActiveCategory}}active{{end}}">All</a>
|
|
||||||
{{range .Categories}}
|
|
||||||
<a href="/search?q={{$.Query | urlquery}}&category={{.}}" class="mobile-filter-chip {{if eq $.ActiveCategory .}}active{{end}}">{{.}}</a>
|
|
||||||
{{end}}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Results inner -->
|
|
||||||
{{template "results_inner" .}}
|
{{template "results_inner" .}}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Right Sidebar -->
|
<!-- Right: Knowledge Panel + Related Searches -->
|
||||||
<aside class="right-sidebar" id="sidebar">
|
<aside class="right-column" id="right-column">
|
||||||
|
{{if and .Infoboxes (gt (len .Infoboxes) 0)}}
|
||||||
|
{{with index .Infoboxes 0}}
|
||||||
|
<div class="knowledge-panel">
|
||||||
|
{{if .img_src}}<img class="knowledge-panel-thumb" src="{{.img_src}}" alt="{{.title}}" loading="lazy">{{end}}
|
||||||
|
{{if .title}}<div class="knowledge-panel-title">{{.title}}</div>{{end}}
|
||||||
|
{{if .content}}<div class="knowledge-panel-content">{{.content}}</div>{{end}}
|
||||||
|
</div>
|
||||||
|
{{end}}
|
||||||
|
{{end}}
|
||||||
|
|
||||||
{{if .Suggestions}}
|
{{if .Suggestions}}
|
||||||
<div class="sidebar-card">
|
<div class="sidebar-card">
|
||||||
<div class="sidebar-title">Related Searches</div>
|
<div class="sidebar-card-title">Related Searches</div>
|
||||||
<div class="suggestion-list">
|
<div class="related-searches">
|
||||||
{{range .Suggestions}}<span class="suggestion"><a href="/search?q={{. | urlquery}}">{{.}}</a></span>{{end}}
|
{{range .Suggestions}}
|
||||||
|
<a class="related-search-link" href="/search?q={{. | urlquery}}">{{.}}</a>
|
||||||
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
||||||
{{if .UnresponsiveEngines}}
|
{{if .UnresponsiveEngines}}
|
||||||
<div class="sidebar-card">
|
<div class="sidebar-card">
|
||||||
<div class="sidebar-title">Engines with issues</div>
|
<div class="sidebar-card-title">Engine Status</div>
|
||||||
<ul class="unresponsive-engines">
|
<ul class="unresponsive-engines">
|
||||||
{{range .UnresponsiveEngines}}<li>{{index . 0}}: {{index . 1}}</li>{{end}}
|
{{range .UnresponsiveEngines}}<li>{{index . 0}}: {{index . 1}}</li>{{end}}
|
||||||
</ul>
|
</ul>
|
||||||
|
|
|
||||||
|
|
@ -8,13 +8,6 @@
|
||||||
{{range .Answers}}
|
{{range .Answers}}
|
||||||
<div class="dialog-error">{{.}}</div>
|
<div class="dialog-error">{{.}}</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
{{range .Infoboxes}}
|
|
||||||
<div class="infobox">
|
|
||||||
{{if .title}}<div class="title">{{.title}}</div>{{end}}
|
|
||||||
{{if .content}}<div>{{.content}}</div>{{end}}
|
|
||||||
{{if .img_src}}<img src="{{.img_src}}" alt="{{.title}}">{{end}}
|
|
||||||
</div>
|
|
||||||
{{end}}
|
|
||||||
</div>
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -110,7 +110,7 @@ func init() {
|
||||||
"base.html", "index.html",
|
"base.html", "index.html",
|
||||||
))
|
))
|
||||||
tmplFragment = template.Must(template.New("").Funcs(funcMap).ParseFS(tmplFS,
|
tmplFragment = template.Must(template.New("").Funcs(funcMap).ParseFS(tmplFS,
|
||||||
"results_inner.html", "result_item.html", "video_item.html",
|
"results.html", "results_inner.html", "result_item.html", "video_item.html",
|
||||||
))
|
))
|
||||||
tmplPreferences = template.Must(template.New("").Funcs(funcMap).ParseFS(tmplFS,
|
tmplPreferences = template.Must(template.New("").Funcs(funcMap).ParseFS(tmplFS,
|
||||||
"base.html", "preferences.html",
|
"base.html", "preferences.html",
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue