Merge branch 'feat/0.6.0/seo' into test

This commit is contained in:
aichy126 2022-12-09 17:10:29 +08:00
commit 6176470f08
5 changed files with 119 additions and 54 deletions

View File

@ -13,6 +13,7 @@ import (
"github.com/answerdev/answer/internal/schema" "github.com/answerdev/answer/internal/schema"
"github.com/answerdev/answer/pkg/converter" "github.com/answerdev/answer/pkg/converter"
"github.com/answerdev/answer/pkg/day" "github.com/answerdev/answer/pkg/day"
"github.com/answerdev/answer/pkg/htmltext"
brotli "github.com/anargu/gin-brotli" brotli "github.com/anargu/gin-brotli"
"github.com/answerdev/answer/internal/base/middleware" "github.com/answerdev/answer/internal/base/middleware"
@ -160,6 +161,9 @@ func NewHTTPServer(debug bool,
"timezone": tz, "timezone": tz,
} }
}, },
"urlTitle": func(title string) string {
return htmltext.UrlTitle(title)
},
} }
r.SetFuncMap(funcMap) r.SetFuncMap(funcMap)

View File

@ -98,8 +98,14 @@ func (tc *TemplateController) Index(ctx *gin.Context) {
siteInfo := tc.SiteInfo(ctx) siteInfo := tc.SiteInfo(ctx)
siteInfo.Canonical = fmt.Sprintf("%s", siteInfo.General.SiteUrl) siteInfo.Canonical = fmt.Sprintf("%s", siteInfo.General.SiteUrl)
UrlUseTitle := false
if siteInfo.General.PermaLink == schema.PermaLinkQuestionIDAndTitle {
UrlUseTitle = true
}
tc.html(ctx, http.StatusOK, "question.html", siteInfo, gin.H{ tc.html(ctx, http.StatusOK, "question.html", siteInfo, gin.H{
"data": data, "data": data,
"useTitle": UrlUseTitle,
"page": templaterender.Paginator(page, req.PageSize, count), "page": templaterender.Paginator(page, req.PageSize, count),
}) })
} }
@ -121,8 +127,14 @@ func (tc *TemplateController) QuestionList(ctx *gin.Context) {
siteInfo := tc.SiteInfo(ctx) siteInfo := tc.SiteInfo(ctx)
siteInfo.Canonical = fmt.Sprintf("%s/questions", siteInfo.General.SiteUrl) siteInfo.Canonical = fmt.Sprintf("%s/questions", siteInfo.General.SiteUrl)
UrlUseTitle := false
if siteInfo.General.PermaLink == schema.PermaLinkQuestionIDAndTitle {
UrlUseTitle = true
}
tc.html(ctx, http.StatusOK, "question.html", siteInfo, gin.H{ tc.html(ctx, http.StatusOK, "question.html", siteInfo, gin.H{
"data": data, "data": data,
"useTitle": UrlUseTitle,
"page": templaterender.Paginator(page, req.PageSize, count), "page": templaterender.Paginator(page, req.PageSize, count),
}) })
} }
@ -310,10 +322,16 @@ func (tc *TemplateController) TagInfo(ctx *gin.Context) {
} }
siteInfo.Keywords = taginifo.DisplayName siteInfo.Keywords = taginifo.DisplayName
UrlUseTitle := false
if siteInfo.General.PermaLink == schema.PermaLinkQuestionIDAndTitle {
UrlUseTitle = true
}
tc.html(ctx, http.StatusOK, "tag-detail.html", siteInfo, gin.H{ tc.html(ctx, http.StatusOK, "tag-detail.html", siteInfo, gin.H{
"tag": taginifo, "tag": taginifo,
"questionList": questionList, "questionList": questionList,
"questionCount": questionCount, "questionCount": questionCount,
"useTitle": UrlUseTitle,
"page": page, "page": page,
}) })
} }

View File

@ -10,7 +10,7 @@
<link rel="canonical" href="{{.siteinfo.Canonical}}" /> <link rel="canonical" href="{{.siteinfo.Canonical}}" />
<link rel="manifest" href="/manifest.json"/> <link rel="manifest" href="/manifest.json"/>
<link href="{{.cssPath}}" rel="stylesheet" /> <link href="{{.cssPath}}" rel="stylesheet" />
<script defer="defer" src="{{.scriptPath}}"></script> <!-- <script defer="defer" src="{{.scriptPath}}"></script> -->
{{if $.siteinfo.JsonLD }}{{ .siteinfo.JsonLD | templateHTML}}{{end}} {{if $.siteinfo.JsonLD }}{{ .siteinfo.JsonLD | templateHTML}}{{end}}
</head> </head>

View File

@ -4,49 +4,74 @@
<div class="col-xxl-7 col-lg-8 col-sm-12"> <div class="col-xxl-7 col-lg-8 col-sm-12">
<div> <div>
<div class="mb-3 d-flex flex-wrap justify-content-between"> <div class="mb-3 d-flex flex-wrap justify-content-between">
<h5 class="fs-5 text-nowrap mb-3 mb-md-0">{{translator $.language "ui.question.all_questions"}}</h5> <h5 class="fs-5 text-nowrap mb-3 mb-md-0">
{{translator $.language "ui.question.all_questions"}}
</h5>
</div> </div>
<div class="border-top border-bottom-0 list-group list-group-flush"> <div class="border-top border-bottom-0 list-group list-group-flush">
{{range .data}} {{range .data}}
<div class="border-bottom pt-3 pb-2 px-0 list-group-item"> <div class="border-bottom pt-3 pb-2 px-0 list-group-item">
<h5 class="text-wrap text-break"> <h5 class="text-wrap text-break">
{{if $.useTitle }}
<a class="link-dark" href="/questions/{{.ID}}/{{urlTitle .Title}}"
>{{.Title}}</a
>
{{else}}
<a class="link-dark" href="/questions/{{.ID}}">{{.Title}}</a> <a class="link-dark" href="/questions/{{.ID}}">{{.Title}}</a>
{{end}}
</h5> </h5>
<div <div
class="d-flex flex-column flex-md-row align-items-md-center fs-14 text-secondary"> class="d-flex flex-column flex-md-row align-items-md-center fs-14 text-secondary"
>
<div class="d-flex"> <div class="d-flex">
<div class="text-secondary me-1"> <div class="text-secondary me-1">
<a href="/users/{{.UserInfo.Username}}"><span <a href="/users/{{.UserInfo.Username}}"
class="me-1 text-break">{{.UserInfo.DisplayName}}</span></a><span ><span class="me-1 text-break"
class="fw-bold" title="Reputation">{{.UserInfo.Rank}}</span> >{{.UserInfo.DisplayName}}</span
></a
><span class="fw-bold" title="Reputation"
>{{.UserInfo.Rank}}</span
>
</div> </div>
{{if eq .CreateTime .UpdateTime}}
{{if eq .CreateTime .UpdateTime}} <time
<time class="text-secondary ms-1" class="text-secondary ms-1"
datetime="{{timeFormatISO $.timezone .CreateTime}}" datetime="{{timeFormatISO $.timezone .CreateTime}}"
title="{{translatorTimeFormatLongDate $.language $.timezone .CreateTime}}">{{translator $.language "ui.question.asked"}} {{translatorTimeFormat $.language $.timezone .CreateTime}} title="{{translatorTimeFormatLongDate $.language $.timezone .CreateTime}}"
>{{translator $.language "ui.question.asked"}}
{{translatorTimeFormat $.language $.timezone .CreateTime}}
</time> </time>
{{else if gt .UpdateTime 0}} {{else if gt .UpdateTime 0}}
<time class="text-secondary ms-1" <time
class="text-secondary ms-1"
datetime="{{timeFormatISO $.timezone .UpdateTime}}" datetime="{{timeFormatISO $.timezone .UpdateTime}}"
title="{{translatorTimeFormatLongDate $.language $.timezone .UpdateTime}}">{{translator $.language "ui.question.modified"}} {{translatorTimeFormat $.language $.timezone .UpdateTime}} title="{{translatorTimeFormatLongDate $.language $.timezone .UpdateTime}}"
>{{translator $.language "ui.question.modified"}}
{{translatorTimeFormat $.language $.timezone .UpdateTime}}
</time> </time>
{{end}} {{end}}
</div> </div>
<div class="ms-0 ms-md-3 mt-2 mt-md-0"> <div class="ms-0 ms-md-3 mt-2 mt-md-0">
<span><i class="br bi-hand-thumbs-up-fill"></i><em <span
class="fst-normal ms-1">{{.VoteCount}}</em></span> ><i class="br bi-hand-thumbs-up-fill"></i
<span class="ms-3"><i ><em class="fst-normal ms-1">{{.VoteCount}}</em></span
class="br bi-chat-square-text-fill"></i><em >
class="fst-normal ms-1">{{.AnswerCount}}</em></span> <span class="ms-3"
<span class="summary-stat ms-3"><i ><i class="br bi-chat-square-text-fill"></i
class="br bi-eye-fill"></i><em class="fst-normal ms-1">{{.ViewCount}}</em></span> ><em class="fst-normal ms-1">{{.AnswerCount}}</em></span
>
<span class="summary-stat ms-3"
><i class="br bi-eye-fill"></i
><em class="fst-normal ms-1">{{.ViewCount}}</em></span
>
</div> </div>
</div> </div>
<div class="question-tags mx-n1 mt-2"> <div class="question-tags mx-n1 mt-2">
{{range .Tags }} {{range .Tags }}
<a href="/tags/{{.SlugName}}" <a
class="badge-tag rounded-1 {{if .Reserved}}badge-tag-reserved{{end}} {{if .Recommend}}badge-tag-required{{end}} m-1"> href="/tags/{{.SlugName}}"
class="badge-tag rounded-1 {{if .Reserved}}badge-tag-reserved{{end}} {{if .Recommend}}badge-tag-required{{end}} m-1"
>
<span class="">{{.SlugName}}</span> <span class="">{{.SlugName}}</span>
</a> </a>
{{end}} {{end}}
@ -59,9 +84,7 @@
</div> </div>
</div> </div>
</div> </div>
<div class="mt-5 mt-lg-0 col-xxl-3 col-lg-4 col-sm-12"> <div class="mt-5 mt-lg-0 col-xxl-3 col-lg-4 col-sm-12"></div>
</div>
</div> </div>
</div> </div>
{{template "footer" .}} {{template "footer" .}}

View File

@ -4,52 +4,74 @@
<div class="col-xxl-7 col-lg-8 col-sm-12"> <div class="col-xxl-7 col-lg-8 col-sm-12">
<div class="tag-box mb-5"> <div class="tag-box mb-5">
<h3 class="mb-3"> <h3 class="mb-3">
<a class="link-dark" href="/tags/{{$.tag.SlugName}}">{{$.tag.SlugName}}</a> <a class="link-dark" href="/tags/{{$.tag.SlugName}}"
>{{$.tag.SlugName}}</a
>
</h3> </h3>
<p class="text-break"> <p class="text-break">{{templateHTML $.tag.ParsedText}}</p>
{{templateHTML $.tag.ParsedText}}
</p>
</div> </div>
<div> <div>
<div class="mb-3 d-flex flex-wrap justify-content-between"> <div class="mb-3 d-flex flex-wrap justify-content-between">
<h5 class="fs-5 text-nowrap mb-3 mb-md-0"> <h5 class="fs-5 text-nowrap mb-3 mb-md-0">
{{translator ($.language) "ui.question.x_questions" "count" .questionCount}} {{translator ($.language) "ui.question.x_questions" "count"
.questionCount}}
</h5> </h5>
</div> </div>
<div class="border-top border-bottom-0 list-group list-group-flush"> <div class="border-top border-bottom-0 list-group list-group-flush">
{{range .questionList}} {{range .questionList}}
<div class="border-bottom pt-3 pb-2 px-0 list-group-item"> <div class="border-bottom pt-3 pb-2 px-0 list-group-item">
<h5 class="text-wrap text-break"> <h5 class="text-wrap text-break">
{{if $.useTitle }}
<a class="link-dark" href="/questions/{{.ID}}/{{urlTitle .Title}}"
>{{.Title}}</a
>
{{else}}
<a class="link-dark" href="/questions/{{.ID}}">{{.Title}}</a> <a class="link-dark" href="/questions/{{.ID}}">{{.Title}}</a>
{{end}}
</h5> </h5>
<div <div
class="d-flex flex-column flex-md-row align-items-md-center fs-14 text-secondary"> class="d-flex flex-column flex-md-row align-items-md-center fs-14 text-secondary"
>
<div class="d-flex"> <div class="d-flex">
<div class="text-secondary me-1"> <div class="text-secondary me-1">
<a href="/users/{{.UserInfo.Username}}"><span <a href="/users/{{.UserInfo.Username}}"
class="me-1 text-break">{{.UserInfo.DisplayName}}</span></a><span ><span class="me-1 text-break"
class="fw-bold" title="Reputation">{{.UserInfo.Rank}}</span> >{{.UserInfo.DisplayName}}</span
></a
><span class="fw-bold" title="Reputation"
>{{.UserInfo.Rank}}</span
>
</div> </div>
<time class="text-secondary ms-1" <time
class="text-secondary ms-1"
datetime="{{timeFormatISO $.timezone .CreateTime}}" datetime="{{timeFormatISO $.timezone .CreateTime}}"
title="{{translatorTimeFormatLongDate $.language $.timezone .CreateTime}}">{{translator $.language "ui.question.asked"}} {{translatorTimeFormat $.language $.timezone .CreateTime}} title="{{translatorTimeFormatLongDate $.language $.timezone .CreateTime}}"
>{{translator $.language "ui.question.asked"}}
{{translatorTimeFormat $.language $.timezone .CreateTime}}
</time> </time>
</div> </div>
<div class="ms-0 ms-md-3 mt-2 mt-md-0"> <div class="ms-0 ms-md-3 mt-2 mt-md-0">
<span><i class="br bi-hand-thumbs-up-fill"></i><em <span
class="fst-normal ms-1">{{.VoteCount}}</em></span> ><i class="br bi-hand-thumbs-up-fill"></i
<span class="ms-3"><i ><em class="fst-normal ms-1">{{.VoteCount}}</em></span
class="br bi-chat-square-text-fill"></i><em >
class="fst-normal ms-1">{{.AnswerCount}}</em></span> <span class="ms-3"
<span class="summary-stat ms-3"><i ><i class="br bi-chat-square-text-fill"></i
class="br bi-eye-fill"></i><em class="fst-normal ms-1">{{.ViewCount}}</em></span> ><em class="fst-normal ms-1">{{.AnswerCount}}</em></span
>
<span class="summary-stat ms-3"
><i class="br bi-eye-fill"></i
><em class="fst-normal ms-1">{{.ViewCount}}</em></span
>
</div> </div>
</div> </div>
<div class="question-tags mx-n1 mt-2"> <div class="question-tags mx-n1 mt-2">
{{range .Tags }} {{range .Tags }}
<a href="/tags/{{.SlugName}}" <a
class="badge-tag rounded-1 {{if .Reserved}}badge-tag-reserved{{end}} {{if .Recommend}}badge-tag-required{{end}} m-1"> href="/tags/{{.SlugName}}"
class="badge-tag rounded-1 {{if .Reserved}}badge-tag-reserved{{end}} {{if .Recommend}}badge-tag-required{{end}} m-1"
>
<span class="">{{.SlugName}}</span> <span class="">{{.SlugName}}</span>
</a> </a>
{{end}} {{end}}
@ -60,9 +82,7 @@
<div class="mt-4 mb-2 d-flex justify-content-center"></div> <div class="mt-4 mb-2 d-flex justify-content-center"></div>
</div> </div>
</div> </div>
<div class="d-flex justify-content-center"> <div class="d-flex justify-content-center">{{template "page" .}}</div>
{{template "page" .}}
</div>
</div> </div>
</div> </div>
{{template "footer" .}} {{template "footer" .}}