commit - 5dfdd66b09fe47403bcc7678f431f06feba5cbb1
commit + 964b49d98af7652f37f0eb6fe170fdca5d444b35
blob - fe60e21b6bd1a72734687ab0197b479fd2332ae8
blob + 60238e8a438264893569d426e11a67367d81bc03
--- internal/service/handlers.go
+++ internal/service/handlers.go
import (
"html/template"
+ "log"
"net/http"
"net/url"
"strings"
-
- "github.com/streatCodes/rss/rss"
)
var templateFuncs = template.FuncMap{
"pathEscape": url.PathEscape,
}
-func render(w http.ResponseWriter, name string, data any) {
+func render(w http.ResponseWriter, name string, data any) error {
tmpl := template.New("").Funcs(templateFuncs)
tmpl = template.Must(tmpl.ParseGlob("internal/templates/*.tmpl"))
- tmpl.ExecuteTemplate(w, name, data)
+ return tmpl.ExecuteTemplate(w, name, data)
}
func (service *Service) homeHandler(w http.ResponseWriter, r *http.Request) {
- render(w, "home", nil)
+ err := render(w, "homePage", nil)
+ if err != nil {
+ log.Printf("Error executing template - %s", err)
+ }
}
func (service *Service) searchHandler(w http.ResponseWriter, r *http.Request) {
render(w, "results", results)
return
}
- render(w, "home", results)
+ err = render(w, "homePage", results)
+ if err != nil {
+ log.Printf("Error executing template - %s", err)
+ }
}
-type ChannelPage struct {
- ShowSubscribeButton bool
- Channel *rss.Channel
-}
-
func (service *Service) channelHandler(w http.ResponseWriter, r *http.Request) {
- channelPage := ChannelPage{ShowSubscribeButton: true}
+ channelPage := ChannelResult{ShowSubscribeButton: true}
channelUrl := strings.TrimPrefix(r.URL.Path, "/channel/")
//Check to see if we have the feed in the database
if channel, err := service.db.GetChannel(channelUrl); channel != nil && err == nil {
- channelPage.Channel = channel
+ channelPage.Channel = *channel
}
- render(w, "channelPage", channelPage)
+ err := render(w, "channelPage", channelPage)
+ if err != nil {
+ log.Printf("Error executing template - %s", err)
+ }
}
blob - 7ed9210fb5ae6c58e79f7f2e061779b2107ecb8d
blob + 0290a91232879dfc969ed229043dc4ca3c74c021
--- internal/service/search.go
+++ internal/service/search.go
)
type ChannelResult struct {
- ChannelUrl string
- Channel rss.Channel
+ ShowSubscribeButton bool
+ ChannelUrl string
+ Channel rss.Channel
}
func (service *Service) findChannel(query string) ([]ChannelResult, error) {
blob - ef0a5d66297f2c3b8c46267193799a428e007726
blob + a5ccabe58f529a1cd5b8be587e00bbb6cfc1fbdc
--- internal/templates/channelPage.tmpl
+++ internal/templates/channelPage.tmpl
{{ define "channelPage" }}
{{ template "header" }}
<main class="search-area">
- Channels todo {{.Channel.Title}}
+ {{ template "channel" . }}
+ TODO Episodes:
+ {{range .Channel.Items}}
+ <p>{{.Title}}</p>
+ {{end}}
</main>
{{ template "footer" }}
{{ end }}
blob - /dev/null
blob + 877c7246e89f9cba24249441307f109be81eb6b2 (mode 644)
--- /dev/null
+++ internal/templates/channel.tmpl
+{{ define "channel" }}
+ <div class="result">
+ <img src="{{ .Channel.Image.Href }}" width="170" height="170" />
+ <div>
+ <hgroup>
+ <div class="flex">
+ <h2>{{ .Channel.Title }}</h2>
+ {{if .ChannelUrl}}<a class="button" href="/channel/{{ .ChannelUrl | pathEscape}}">Episodes</a>{{end}}
+ {{if .ShowSubscribeButton}}<a class="button">Subscribe</a>{{end}}
+ </div>
+ <time datetime="{{ .Channel.PubDate.Format "2006-01-02T15:04:05Z07:00" }}">
+ Last updated {{ .Channel.PubDate | timeAgo }}
+ </time>
+ </hgroup>
+ <p>{{ .Channel.Description }}</p>
+ <div class="tag-line">
+ {{ if gt (len .Channel.Link) 0 }}
+ <a href="{{index .Channel.Link 0}}" class="button">
+ <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="currentColor" class="bi bi-globe2" viewBox="0 0 16 16">
+ <path d="M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8m7.5-6.923c-.67.204-1.335.82-1.887 1.855q-.215.403-.395.872c.705.157 1.472.257 2.282.287zM4.249 3.539q.214-.577.481-1.078a7 7 0 0 1 .597-.933A7 7 0 0 0 3.051 3.05q.544.277 1.198.49zM3.509 7.5c.036-1.07.188-2.087.436-3.008a9 9 0 0 1-1.565-.667A6.96 6.96 0 0 0 1.018 7.5zm1.4-2.741a12.3 12.3 0 0 0-.4 2.741H7.5V5.091c-.91-.03-1.783-.145-2.591-.332M8.5 5.09V7.5h2.99a12.3 12.3 0 0 0-.399-2.741c-.808.187-1.681.301-2.591.332zM4.51 8.5c.035.987.176 1.914.399 2.741A13.6 13.6 0 0 1 7.5 10.91V8.5zm3.99 0v2.409c.91.03 1.783.145 2.591.332.223-.827.364-1.754.4-2.741zm-3.282 3.696q.18.469.395.872c.552 1.035 1.218 1.65 1.887 1.855V11.91c-.81.03-1.577.13-2.282.287zm.11 2.276a7 7 0 0 1-.598-.933 9 9 0 0 1-.481-1.079 8.4 8.4 0 0 0-1.198.49 7 7 0 0 0 2.276 1.522zm-1.383-2.964A13.4 13.4 0 0 1 3.508 8.5h-2.49a6.96 6.96 0 0 0 1.362 3.675c.47-.258.995-.482 1.565-.667m6.728 2.964a7 7 0 0 0 2.275-1.521 8.4 8.4 0 0 0-1.197-.49 9 9 0 0 1-.481 1.078 7 7 0 0 1-.597.933M8.5 11.909v3.014c.67-.204 1.335-.82 1.887-1.855q.216-.403.395-.872A12.6 12.6 0 0 0 8.5 11.91zm3.555-.401c.57.185 1.095.409 1.565.667A6.96 6.96 0 0 0 14.982 8.5h-2.49a13.4 13.4 0 0 1-.437 3.008M14.982 7.5a6.96 6.96 0 0 0-1.362-3.675c-.47.258-.995.482-1.565.667.248.92.4 1.938.437 3.008zM11.27 2.461q.266.502.482 1.078a8.4 8.4 0 0 0 1.196-.49 7 7 0 0 0-2.275-1.52c.218.283.418.597.597.932m-.488 1.343a8 8 0 0 0-.395-.872C9.835 1.897 9.17 1.282 8.5 1.077V4.09c.81-.03 1.577-.13 2.282-.287z"/>
+ </svg>
+ </a>
+ {{ end }}
+ <a href="mailto:{{.Channel.Owner.Email}}" class="button" style="margin-right: 1rem">
+ <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="currentColor" class="bi bi-envelope" viewBox="0 0 16 16">
+ <path d="M0 4a2 2 0 0 1 2-2h12a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2zm2-1a1 1 0 0 0-1 1v.217l7 4.2 7-4.2V4a1 1 0 0 0-1-1zm13 2.383-4.708 2.825L15 11.105zm-.034 6.876-5.64-3.471L8 9.583l-1.326-.795-5.64 3.47A1 1 0 0 0 2 13h12a1 1 0 0 0 .966-.741M1 11.105l4.708-2.897L1 5.383z"/>
+ </svg>
+ </a>
+
+ {{ range .Channel.Categories }}
+ <a class="category">#{{ .Text }}</a>
+ {{ end }}
+ </div>
+ </div>
+ </div>
+{{ end }}
\ No newline at end of file
blob - 23302b9aa8be8f918eb35fbd152ef550a6366a1c (mode 644)
blob + /dev/null
--- internal/templates/home.tmpl
+++ /dev/null
-{{ define "home" }}
-{{ template "header" }}
-<main class="search-area">
- <hgroup class="search-animation">
- <h1>Subscribe to your favourite feed!</h1>
- <div style="display: flex">
- <h3>Your </h3>
- <div class="text-stack">
- <h3>exciting calendar event</h3>
- <h3>top blog</h3>
- <h3>beloved podcast</h3>
- <h3>number one forum thread</h3>
- <h3>go-to YouTube channel</h3>
- </div>
- </div>
- </hgroup>
-
- <form action="/search" hx-get="/search" hx-target="#search-results" hx-push-url="true">
- <div class="search-box">
- <button type="button" aria-label="Filter">
- <svg xmlns="http://www.w3.org/2000/svg" width="22" height="22" fill="currentColor" class="bi bi-filter"
- viewBox="0 0 16 16">
- <path
- d="M6 10.5a.5.5 0 0 1 .5-.5h3a.5.5 0 0 1 0 1h-3a.5.5 0 0 1-.5-.5m-2-3a.5.5 0 0 1 .5-.5h7a.5.5 0 0 1 0 1h-7a.5.5 0 0 1-.5-.5m-2-3a.5.5 0 0 1 .5-.5h11a.5.5 0 0 1 0 1h-11a.5.5 0 0 1-.5-.5" />
- </svg>
- </button>
- <input type="search" autofocus name="search" placeholder="Search for a feed!" />
- <button type="submit" aria-label="Send">
- <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-search"
- viewBox="0 0 16 16">
- <path
- d="M11.742 10.344a6.5 6.5 0 1 0-1.397 1.398h-.001q.044.06.098.115l3.85 3.85a1 1 0 0 0 1.415-1.414l-3.85-3.85a1 1 0 0 0-.115-.1zM12 6.5a5.5 5.5 0 1 1-11 0 5.5 5.5 0 0 1 11 0" />
- </svg>
- </button>
- </div>
- </form>
-
- <div id="search-results">
- {{ template "results" . }}
- </div>
-</main>
-{{ template "footer" }}
-{{ end }}
blob - 659b7e94cc258811911c19033cd2fa7efe7b88b6
blob + 2aab6a3d7f25203a20886b691538fd51768cd146
--- internal/templates/results.tmpl
+++ internal/templates/results.tmpl
{{ define "results" }}
<div class="results">
{{ range . }}
- <div class="result">
- <img src="{{ .Channel.Image.Href }}" width="170" height="170" />
- <div>
- <hgroup>
- <div class="flex">
- <h2>{{ .Channel.Title }}</h2>
- <a class="button" href="/channel/{{ .ChannelUrl | pathEscape}}">Episodes</a>
- </div>
- <time datetime="{{ .Channel.PubDate.Format "2006-01-02T15:04:05Z07:00" }}">
- Last updated {{ .Channel.PubDate | timeAgo }}
- </time>
- </hgroup>
- <p>{{ .Channel.Description }}</p>
- <div class="tag-line">
- {{ if gt (len .Channel.Link) 0 }}
- <a href="{{index .Channel.Link 0}}" class="button">
- <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="currentColor" class="bi bi-globe2" viewBox="0 0 16 16">
- <path d="M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8m7.5-6.923c-.67.204-1.335.82-1.887 1.855q-.215.403-.395.872c.705.157 1.472.257 2.282.287zM4.249 3.539q.214-.577.481-1.078a7 7 0 0 1 .597-.933A7 7 0 0 0 3.051 3.05q.544.277 1.198.49zM3.509 7.5c.036-1.07.188-2.087.436-3.008a9 9 0 0 1-1.565-.667A6.96 6.96 0 0 0 1.018 7.5zm1.4-2.741a12.3 12.3 0 0 0-.4 2.741H7.5V5.091c-.91-.03-1.783-.145-2.591-.332M8.5 5.09V7.5h2.99a12.3 12.3 0 0 0-.399-2.741c-.808.187-1.681.301-2.591.332zM4.51 8.5c.035.987.176 1.914.399 2.741A13.6 13.6 0 0 1 7.5 10.91V8.5zm3.99 0v2.409c.91.03 1.783.145 2.591.332.223-.827.364-1.754.4-2.741zm-3.282 3.696q.18.469.395.872c.552 1.035 1.218 1.65 1.887 1.855V11.91c-.81.03-1.577.13-2.282.287zm.11 2.276a7 7 0 0 1-.598-.933 9 9 0 0 1-.481-1.079 8.4 8.4 0 0 0-1.198.49 7 7 0 0 0 2.276 1.522zm-1.383-2.964A13.4 13.4 0 0 1 3.508 8.5h-2.49a6.96 6.96 0 0 0 1.362 3.675c.47-.258.995-.482 1.565-.667m6.728 2.964a7 7 0 0 0 2.275-1.521 8.4 8.4 0 0 0-1.197-.49 9 9 0 0 1-.481 1.078 7 7 0 0 1-.597.933M8.5 11.909v3.014c.67-.204 1.335-.82 1.887-1.855q.216-.403.395-.872A12.6 12.6 0 0 0 8.5 11.91zm3.555-.401c.57.185 1.095.409 1.565.667A6.96 6.96 0 0 0 14.982 8.5h-2.49a13.4 13.4 0 0 1-.437 3.008M14.982 7.5a6.96 6.96 0 0 0-1.362-3.675c-.47.258-.995.482-1.565.667.248.92.4 1.938.437 3.008zM11.27 2.461q.266.502.482 1.078a8.4 8.4 0 0 0 1.196-.49 7 7 0 0 0-2.275-1.52c.218.283.418.597.597.932m-.488 1.343a8 8 0 0 0-.395-.872C9.835 1.897 9.17 1.282 8.5 1.077V4.09c.81-.03 1.577-.13 2.282-.287z"/>
- </svg>
- </a>
- {{ end }}
- <a href="mailto:{{.Channel.Owner.Email}}" class="button" style="margin-right: 1rem">
- <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="currentColor" class="bi bi-envelope" viewBox="0 0 16 16">
- <path d="M0 4a2 2 0 0 1 2-2h12a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2zm2-1a1 1 0 0 0-1 1v.217l7 4.2 7-4.2V4a1 1 0 0 0-1-1zm13 2.383-4.708 2.825L15 11.105zm-.034 6.876-5.64-3.471L8 9.583l-1.326-.795-5.64 3.47A1 1 0 0 0 2 13h12a1 1 0 0 0 .966-.741M1 11.105l4.708-2.897L1 5.383z"/>
- </svg>
- </a>
-
- {{ range .Channel.Categories }}
- <a class="category">#{{ .Text }}</a>
- {{ end }}
- </div>
- </div>
- </div>
+ {{ template "channel" . }}
{{ end }}
</div>
{{ end }}
\ No newline at end of file
blob - /dev/null
blob + d1df16020a04bda47bd95761a71fffe655c38a5c (mode 644)
--- /dev/null
+++ internal/templates/homePage.tmpl
+{{ define "homePage" }}
+{{ template "header" }}
+<main class="search-area">
+ <hgroup class="search-animation">
+ <h1>Subscribe to your favourite feed!</h1>
+ <div style="display: flex">
+ <h3>Your </h3>
+ <div class="text-stack">
+ <h3>exciting calendar event</h3>
+ <h3>top blog</h3>
+ <h3>beloved podcast</h3>
+ <h3>number one forum thread</h3>
+ <h3>go-to YouTube channel</h3>
+ </div>
+ </div>
+ </hgroup>
+
+ <form action="/search" hx-get="/search" hx-target="#search-results" hx-push-url="true">
+ <div class="search-box">
+ <button type="button" aria-label="Filter">
+ <svg xmlns="http://www.w3.org/2000/svg" width="22" height="22" fill="currentColor" class="bi bi-filter"
+ viewBox="0 0 16 16">
+ <path
+ d="M6 10.5a.5.5 0 0 1 .5-.5h3a.5.5 0 0 1 0 1h-3a.5.5 0 0 1-.5-.5m-2-3a.5.5 0 0 1 .5-.5h7a.5.5 0 0 1 0 1h-7a.5.5 0 0 1-.5-.5m-2-3a.5.5 0 0 1 .5-.5h11a.5.5 0 0 1 0 1h-11a.5.5 0 0 1-.5-.5" />
+ </svg>
+ </button>
+ <input type="search" autofocus name="search" placeholder="Search for a feed!" />
+ <button type="submit" aria-label="Send">
+ <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-search"
+ viewBox="0 0 16 16">
+ <path
+ d="M11.742 10.344a6.5 6.5 0 1 0-1.397 1.398h-.001q.044.06.098.115l3.85 3.85a1 1 0 0 0 1.415-1.414l-3.85-3.85a1 1 0 0 0-.115-.1zM12 6.5a5.5 5.5 0 1 1-11 0 5.5 5.5 0 0 1 11 0" />
+ </svg>
+ </button>
+ </div>
+ </form>
+
+ <div id="search-results">
+ {{ template "results" . }}
+ </div>
+</main>
+{{ template "footer" }}
+{{ end }}
blob - 273cadda4dc38e2b12ef22db0e9ce52b16cc787d
blob + 3e5a16ca63d50b96853d608997b5c9095754578a
--- web/style.css
+++ web/style.css
}
}
-.results .result {
+.result {
background-color: var(--black);
display: flex;
border-radius: 2rem;
padding: 1rem;
box-shadow: var(--shadow);
margin-bottom: 1rem;
+
+ &>div {
+ width: 100%;
+ }
img {
border-radius: 2rem;