fix: add Thumbnail field and video result template
MainResult: add Thumbnail field (used by YouTube, images, etc.) video_item.html: new partial for video results with thumbnail display views.go: add templateForResult func + video_item.html to template parse results_inner.html: dispatch to video_item when Template="videos" kafka.css: add .video-result flex layout with thumbnail styling
This commit is contained in:
parent
af23a63a73
commit
4a6559be62
5 changed files with 79 additions and 23 deletions
|
|
@ -14,16 +14,17 @@ type MainResult struct {
|
||||||
raw map[string]any
|
raw map[string]any
|
||||||
|
|
||||||
// Common fields used by templates (RSS uses: title, url, content, pubdate).
|
// Common fields used by templates (RSS uses: title, url, content, pubdate).
|
||||||
Template string `json:"template"`
|
Template string `json:"template"`
|
||||||
Title string `json:"title"`
|
Title string `json:"title"`
|
||||||
Content string `json:"content"`
|
Content string `json:"content"`
|
||||||
URL *string `json:"url"`
|
URL *string `json:"url"`
|
||||||
Pubdate *string `json:"pubdate"`
|
Pubdate *string `json:"pubdate"`
|
||||||
|
Thumbnail string `json:"thumbnail"`
|
||||||
|
|
||||||
Engine string `json:"engine"`
|
Engine string `json:"engine"`
|
||||||
Score float64 `json:"score"`
|
Score float64 `json:"score"`
|
||||||
Category string `json:"category"`
|
Category string `json:"category"`
|
||||||
Priority string `json:"priority"`
|
Priority string `json:"priority"`
|
||||||
|
|
||||||
Positions []int `json:"positions"`
|
Positions []int `json:"positions"`
|
||||||
Engines []string `json:"engines"`
|
Engines []string `json:"engines"`
|
||||||
|
|
@ -54,6 +55,7 @@ func (mr *MainResult) UnmarshalJSON(data []byte) error {
|
||||||
mr.Title = stringOrEmpty(m["title"])
|
mr.Title = stringOrEmpty(m["title"])
|
||||||
mr.Content = stringOrEmpty(m["content"])
|
mr.Content = stringOrEmpty(m["content"])
|
||||||
mr.Engine = stringOrEmpty(m["engine"])
|
mr.Engine = stringOrEmpty(m["engine"])
|
||||||
|
mr.Thumbnail = stringOrEmpty(m["thumbnail"])
|
||||||
mr.Category = stringOrEmpty(m["category"])
|
mr.Category = stringOrEmpty(m["category"])
|
||||||
mr.Priority = stringOrEmpty(m["priority"])
|
mr.Priority = stringOrEmpty(m["priority"])
|
||||||
|
|
||||||
|
|
@ -93,20 +95,21 @@ func (mr MainResult) MarshalJSON() ([]byte, error) {
|
||||||
|
|
||||||
// Otherwise, marshal the known fields.
|
// Otherwise, marshal the known fields.
|
||||||
m := map[string]any{
|
m := map[string]any{
|
||||||
"template": mr.Template,
|
"template": mr.Template,
|
||||||
"title": mr.Title,
|
"title": mr.Title,
|
||||||
"content": mr.Content,
|
"content": mr.Content,
|
||||||
"url": mr.URL,
|
"url": mr.URL,
|
||||||
"pubdate": mr.Pubdate,
|
"pubdate": mr.Pubdate,
|
||||||
"engine": mr.Engine,
|
"thumbnail": mr.Thumbnail,
|
||||||
"score": mr.Score,
|
"engine": mr.Engine,
|
||||||
"category": mr.Category,
|
"score": mr.Score,
|
||||||
"priority": mr.Priority,
|
"category": mr.Category,
|
||||||
|
"priority": mr.Priority,
|
||||||
"positions": mr.Positions,
|
"positions": mr.Positions,
|
||||||
"engines": mr.Engines,
|
"engines": mr.Engines,
|
||||||
"open_group": mr.OpenGroup,
|
"open_group": mr.OpenGroup,
|
||||||
"close_group": mr.CloseGroup,
|
"close_group": mr.CloseGroup,
|
||||||
"parsed_url": mr.ParsedURL,
|
"parsed_url": mr.ParsedURL,
|
||||||
}
|
}
|
||||||
return json.Marshal(m)
|
return json.Marshal(m)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -805,3 +805,26 @@ html[data-theme="light"] {
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Video result cards */
|
||||||
|
.video-result {
|
||||||
|
display: flex;
|
||||||
|
gap: 1rem;
|
||||||
|
align-items: flex-start;
|
||||||
|
}
|
||||||
|
|
||||||
|
.video-result .result_thumbnail {
|
||||||
|
flex-shrink: 0;
|
||||||
|
width: 180px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.video-result .result_thumbnail img {
|
||||||
|
width: 100%;
|
||||||
|
height: auto;
|
||||||
|
border-radius: var(--radius);
|
||||||
|
}
|
||||||
|
|
||||||
|
.video-result .result_content_wrapper {
|
||||||
|
flex: 1;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -52,7 +52,7 @@
|
||||||
<div id="urls" role="main">
|
<div id="urls" role="main">
|
||||||
{{if .Results}}
|
{{if .Results}}
|
||||||
{{range .Results}}
|
{{range .Results}}
|
||||||
{{template "result_item" .}}
|
{{template (templateForResult .Template) .}}
|
||||||
{{end}}
|
{{end}}
|
||||||
{{else if not .Answers}}
|
{{else if not .Answers}}
|
||||||
<div class="no_results">
|
<div class="no_results">
|
||||||
|
|
|
||||||
22
internal/views/templates/video_item.html
Normal file
22
internal/views/templates/video_item.html
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
{{define "video_item"}}
|
||||||
|
<article class="result video-result">
|
||||||
|
{{if .Thumbnail}}
|
||||||
|
<div class="result_thumbnail">
|
||||||
|
<a href="{{.URL}}" target="_blank" rel="noopener noreferrer">
|
||||||
|
<img src="{{.Thumbnail}}" alt="{{.Title}}" loading="lazy">
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
{{end}}
|
||||||
|
<div class="result_content_wrapper">
|
||||||
|
<h3 class="result_header">
|
||||||
|
<a href="{{.URL}}" target="_blank" rel="noopener noreferrer">{{.Title}}</a>
|
||||||
|
</h3>
|
||||||
|
{{if .Content}}
|
||||||
|
<p class="result_content">{{.Content}}</p>
|
||||||
|
{{end}}
|
||||||
|
{{if .Engine}}
|
||||||
|
<div class="result_engine"><span class="engine">{{.Engine}}</span></div>
|
||||||
|
{{end}}
|
||||||
|
</div>
|
||||||
|
</article>
|
||||||
|
{{end}}
|
||||||
|
|
@ -63,16 +63,24 @@ func init() {
|
||||||
|
|
||||||
funcMap := template.FuncMap{
|
funcMap := template.FuncMap{
|
||||||
"urlquery": template.URLQueryEscaper,
|
"urlquery": template.URLQueryEscaper,
|
||||||
|
// templateForResult returns the template name to use for a result.
|
||||||
|
// Defaults to "result_item"; use "video_item" for video results.
|
||||||
|
"templateForResult": func(tmpl string) string {
|
||||||
|
if tmpl == "videos" {
|
||||||
|
return "video_item"
|
||||||
|
}
|
||||||
|
return "result_item"
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
tmplFull = template.Must(template.New("").Funcs(funcMap).ParseFS(tmplFS,
|
tmplFull = template.Must(template.New("").Funcs(funcMap).ParseFS(tmplFS,
|
||||||
"base.html", "results.html", "results_inner.html", "result_item.html",
|
"base.html", "results.html", "results_inner.html", "result_item.html", "video_item.html",
|
||||||
))
|
))
|
||||||
tmplIndex = template.Must(template.New("").Funcs(funcMap).ParseFS(tmplFS,
|
tmplIndex = template.Must(template.New("").Funcs(funcMap).ParseFS(tmplFS,
|
||||||
"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",
|
"results_inner.html", "result_item.html", "video_item.html",
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue