mirror of https://gitee.com/answerdev/answer.git
Merge branch 'feat/0.6.0/seo' into test
This commit is contained in:
commit
6176470f08
|
@ -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)
|
||||||
|
|
||||||
|
|
|
@ -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,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -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>
|
||||||
|
|
||||||
|
|
|
@ -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" .}}
|
||||||
|
|
|
@ -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" .}}
|
||||||
|
|
Loading…
Reference in New Issue