зеркало из https://github.com/golang/pkgsite.git
content,internal: add badge generation for package authors
This change creates a badge generation tool page for package authors. A future change will add documenation of this feature and a link to the about page. Fixes golang/go#36982 Change-Id: Ia64ba9db73ed92b853f1f955330caf93d996da91 Reviewed-on: https://go-review.googlesource.com/c/pkgsite/+/241273 Reviewed-by: Andrew Bonventre <andybons@golang.org>
This commit is contained in:
Родитель
103a6b7425
Коммит
d37103e11f
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2019 The Go Authors. All rights reserved.
|
||||
* Copyright 2019-2020 The Go Authors. All rights reserved.
|
||||
* Use of this source code is governed by a BSD-style
|
||||
* license that can be found in the LICENSE file.
|
||||
*/
|
||||
|
@ -1095,6 +1095,64 @@ table.Directories {
|
|||
margin-left: 1.1rem;
|
||||
}
|
||||
|
||||
.Badge-formElement {
|
||||
display: block;
|
||||
font-size: 1rem;
|
||||
margin-top: 1rem;
|
||||
}
|
||||
.Badge-badgeIcon {
|
||||
height: 20px;
|
||||
width: 90px;
|
||||
}
|
||||
.Badge-previewLink,
|
||||
.Badge-formElement > input {
|
||||
display: block;
|
||||
margin-top: 1rem;
|
||||
max-width: 50.25rem;
|
||||
}
|
||||
.Badge-formElement > input {
|
||||
border: 0.0625rem solid var(--gray-8);
|
||||
border-radius: 0.25rem;
|
||||
color: var(--gray-4);
|
||||
font-family: inherit;
|
||||
height: 3rem;
|
||||
padding: 0 2rem 0 0.75rem;
|
||||
text-overflow: ellipsis;
|
||||
width: 100%;
|
||||
}
|
||||
.Badge-formElement > input:focus::placeholder {
|
||||
color: transparent;
|
||||
}
|
||||
.Badge-clickToCopy {
|
||||
background: var(--gray-10) url('/static/img/copy-click.svg') right no-repeat;
|
||||
background-position: right 0.75rem center;
|
||||
}
|
||||
.Badge-submitButton {
|
||||
border: none;
|
||||
border-radius: 0.25rem;
|
||||
background-color: var(--turq-dark);
|
||||
color: var(--white);
|
||||
cursor: pointer;
|
||||
font-family: inherit;
|
||||
height: 2.75rem;
|
||||
width: 7.125rem;
|
||||
}
|
||||
.Badge-snippetContainer {
|
||||
background-color: var(--gray-10);
|
||||
display: block;
|
||||
margin-top: 1rem;
|
||||
max-width: 50.25rem;
|
||||
padding: 1rem;
|
||||
}
|
||||
.Badge-gopherLanding {
|
||||
height: 12.25rem;
|
||||
text-align: center;
|
||||
}
|
||||
.Badge-gopherLanding img {
|
||||
height: 125px;
|
||||
width: auto;
|
||||
}
|
||||
|
||||
/* dialogs, including the jump-to-identifier dialog on documentation pages */
|
||||
|
||||
.Dialog {
|
||||
|
|
|
@ -0,0 +1,57 @@
|
|||
<!--
|
||||
Copyright 2020 The Go Authors. All rights reserved.
|
||||
Use of this source code is governed by a BSD-style
|
||||
license that can be found in the LICENSE file.
|
||||
-->
|
||||
|
||||
{{define "main_content"}}
|
||||
<div class="Container">
|
||||
<div class="Content">
|
||||
<h1 class="Content-header">Create a badge</h1>
|
||||
<p>Create a badge to link to pkg.go.dev from your project website or README file.</p>
|
||||
<label class="Badge-formElement">
|
||||
Badge
|
||||
<div class="Badge-previewLink">
|
||||
<a class="js-badgeExampleButton" href="{{.SiteURL}}/{{.Path}}">
|
||||
<img class="Badge-badgeIcon" src="/static/img/badge.svg" alt="PkgGoDev">
|
||||
</a>
|
||||
</div>
|
||||
</label>
|
||||
<form action="/badge/">
|
||||
<label class="Badge-formElement">
|
||||
URL
|
||||
<input name="path" class="js-toolsPathInput"
|
||||
value="{{if .Path}}{{.SiteURL}}/{{.Path}}{{end}}" placeholder="e.g., https://pkg.go.dev/golang.org/x/pkgsite">
|
||||
</label>
|
||||
<label class="Badge-formElement">
|
||||
<button type="submit" class="Badge-submitButton">Create</button>
|
||||
</label>
|
||||
</form>
|
||||
<div class="Badge-snippetContainer">
|
||||
{{if .Path}}
|
||||
<label class="Badge-formElement">
|
||||
HTML
|
||||
<input title="Click to copy HTML" name="html" class="Badge-clickToCopy js-toolsCopySnippet" type="text"
|
||||
value='<a href="{{.SiteURL}}/{{.Path}}"><img src="{{.SiteURL}}/badge/{{.Path}}" alt="PkgGoDev"></a>' readonly>
|
||||
</label>
|
||||
<label class="Badge-formElement">
|
||||
Markdown
|
||||
<input title="Click to copy markdown" name="markdown" class="Badge-clickToCopy js-toolsCopySnippet" type="text"
|
||||
value="[![PkgGoDev]({{.SiteURL}}/{{.Path}})]({{.SiteURL}}/badge/{{.Path}})" readonly>
|
||||
</label>
|
||||
{{else}}
|
||||
<div class="Badge-gopherLanding">
|
||||
<img src="/static/img/gopher-airplane.svg" alt="The Go Gopher"/>
|
||||
<p>Type a pkg.go.dev URL above to create a badge link.</p>
|
||||
</div>
|
||||
{{end}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
|
||||
{{define "post_content"}}
|
||||
<script>
|
||||
loadScript("/static/js/badge.min.js");
|
||||
</script>
|
||||
{{end}}
|
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
После Ширина: | Высота: | Размер: 6.3 KiB |
|
@ -0,0 +1 @@
|
|||
<svg fill="#00add8" width="13" height="15" xmlns="http://www.w3.org/2000/svg"><path d="M8 0H2a2 2 0 00-2 2v8a2 2 0 002 2V2h8a2 2 0 00-2-2zm3 3H5a2 2 0 00-2 2v8a2 2 0 002 2h6a2 2 0 002-2V5a2 2 0 00-2-2zM5 13h6V5H5v8z" fill-rule="evenodd"/></svg>
|
После Ширина: | Высота: | Размер: 244 B |
|
@ -0,0 +1,30 @@
|
|||
/**
|
||||
* @license
|
||||
* Copyright 2019-2020 The Go Authors. All rights reserved.
|
||||
* Use of this source code is governed by a BSD-style
|
||||
* license that can be found in the LICENSE file.
|
||||
*/
|
||||
|
||||
const snippetEls = document.querySelectorAll('.js-toolsCopySnippet');
|
||||
snippetEls.forEach(inputEl => {
|
||||
inputEl.addEventListener('click', e => {
|
||||
e.preventDefault();
|
||||
e.currentTarget.select();
|
||||
document.execCommand('copy');
|
||||
});
|
||||
});
|
||||
|
||||
const pathEl = document.querySelector('.js-toolsPathInput');
|
||||
const htmlEl = document.querySelector('input[name="html"].js-toolsCopySnippet');
|
||||
const markdownEl = document.querySelector('input[name="markdown"].js-toolsCopySnippet');
|
||||
const badgeEl = document.querySelector('.js-badgeExampleButton');
|
||||
if (pathEl && htmlEl && markdownEl && badgeEl) {
|
||||
pathEl.addEventListener('input', e => {
|
||||
const origin = window.location.origin;
|
||||
const href = `${origin}/${e.target.value}`;
|
||||
const imgSrc = `${origin}/badge/${e.target.value}`;
|
||||
htmlEl.value = `<a href="${href}"><img src="${imgSrc}" alt="PkgGoDev"></a>`;
|
||||
markdownEl.value = `[![PkgGoDev](${href})](${imgSrc})`;
|
||||
badgeEl.href = href;
|
||||
});
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
/*
|
||||
|
||||
Copyright 2019-2020 The Go Authors. All rights reserved.
|
||||
Use of this source code is governed by a BSD-style
|
||||
license that can be found in the LICENSE file.
|
||||
*/
|
||||
var snippetEls=document.querySelectorAll(".js-toolsCopySnippet");snippetEls.forEach(function(a){a.addEventListener("click",function(a){a.preventDefault();a.currentTarget.select();document.execCommand("copy")})});var pathEl=document.querySelector(".js-toolsPathInput"),htmlEl=document.querySelector('input[name="html"].js-toolsCopySnippet'),markdownEl=document.querySelector('input[name="markdown"].js-toolsCopySnippet'),badgeEl=document.querySelector(".js-badgeExampleButton");
|
||||
pathEl&&htmlEl&&markdownEl&&badgeEl&&pathEl.addEventListener("input",function(a){var c=window.location.origin,b=c+"/"+a.target.value;a=c+"/badge/"+a.target.value;htmlEl.value='<a href="'+b+'"><img src="'+a+'" alt="PkgGoDev"></a>';markdownEl.value="[![PkgGoDev]("+b+")]("+a+")";badgeEl.href=b});
|
|
@ -43,6 +43,7 @@ main() {
|
|||
# TODO: once this is not an experiment, add it to the line above.
|
||||
$cmd $JSDIR/completion.min.js $JSDIR/completion.js
|
||||
$cmd $JSDIR/fetch.min.js $JSDIR/fetch.js
|
||||
$cmd $JSDIR/badge.min.js $JSDIR/badge.js
|
||||
$cmd $JSDIR/jump.min.js third_party/dialog-polyfill/dialog-polyfill.js $JSDIR/jump.js
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,43 @@
|
|||
// Copyright 2020 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package frontend
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type badgePage struct {
|
||||
basePage
|
||||
SiteURL string
|
||||
Path string
|
||||
}
|
||||
|
||||
// badgeHandler serves a Go SVG badge image for requests to /badge/<path>
|
||||
// and a badge generation tool page for requests to /badge/[?path=<path>].
|
||||
func (s *Server) badgeHandler(w http.ResponseWriter, r *http.Request) {
|
||||
path := strings.TrimPrefix(r.URL.Path, "/badge/")
|
||||
if path != "" {
|
||||
http.ServeFile(w, r, fmt.Sprintf("%s/img/badge.svg", s.staticPath))
|
||||
return
|
||||
}
|
||||
|
||||
// The user may input a fully qualified URL (https://pkg.go.dev/net/http?tab=doc)
|
||||
// or just a pathname (net/http). Using url.Parse we handle both cases.
|
||||
inputURL := r.URL.Query().Get("path")
|
||||
parsedURL, _ := url.Parse(inputURL)
|
||||
if parsedURL != nil {
|
||||
path = strings.TrimPrefix(parsedURL.RequestURI(), "/")
|
||||
}
|
||||
|
||||
page := badgePage{
|
||||
basePage: s.newBasePage(r, "Badge generation tool"),
|
||||
SiteURL: "https://" + r.Host,
|
||||
Path: path,
|
||||
}
|
||||
s.servePage(r.Context(), w, "badge.tmpl", page)
|
||||
}
|
|
@ -0,0 +1,85 @@
|
|||
// Copyright 2020 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package frontend
|
||||
|
||||
import (
|
||||
"net/http/httptest"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestBadgeHandler_ServeSVG(t *testing.T) {
|
||||
_, handler, _ := newTestServer(t, nil)
|
||||
w := httptest.NewRecorder()
|
||||
handler.ServeHTTP(w, httptest.NewRequest("GET", "/badge/net/http", nil))
|
||||
if got, want := w.Result().Header.Get("Content-Type"), "image/svg+xml"; got != want {
|
||||
t.Errorf("Content-Type = %q, want %q", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBadgeHandler_ServeBadgeTool(t *testing.T) {
|
||||
_, handler, _ := newTestServer(t, nil)
|
||||
|
||||
tests := []struct {
|
||||
url string
|
||||
want string
|
||||
}{
|
||||
{
|
||||
"/badge/",
|
||||
"<p>Type a pkg.go.dev URL above to create a badge link.</p>",
|
||||
},
|
||||
{
|
||||
"/badge/?path=net/http",
|
||||
`<a href="https://example.com/net/http"><img src="https://example.com/badge/net/http" alt="PkgGoDev"></a>`,
|
||||
},
|
||||
{
|
||||
"/badge/?path=net/http?tab=imports",
|
||||
`<a href="https://example.com/net/http?tab=imports"><img src="https://example.com/badge/net/http?tab=imports" alt="PkgGoDev"></a>`,
|
||||
},
|
||||
{
|
||||
"/badge/?path=https://pkg.go.dev/net/http",
|
||||
`<a href="https://example.com/net/http"><img src="https://example.com/badge/net/http" alt="PkgGoDev"></a>`,
|
||||
},
|
||||
{
|
||||
"/badge/?path=https://pkg.go.dev/net/http?tab=imports",
|
||||
`<a href="https://example.com/net/http?tab=imports"><img src="https://example.com/badge/net/http?tab=imports" alt="PkgGoDev"></a>`,
|
||||
},
|
||||
{
|
||||
"/badge/?path=github.com/google/uuid",
|
||||
"[![PkgGoDev](https://example.com/github.com/google/uuid)](https://example.com/badge/github.com/google/uuid)",
|
||||
},
|
||||
{
|
||||
"/badge/?path=github.com/google/uuid?tab=imports",
|
||||
"[![PkgGoDev](https://example.com/github.com/google/uuid?tab=imports)](https://example.com/badge/github.com/google/uuid?tab=imports)",
|
||||
},
|
||||
{
|
||||
"/badge/?path=https://pkg.go.dev/github.com/google/uuid",
|
||||
"[![PkgGoDev](https://example.com/github.com/google/uuid)](https://example.com/badge/github.com/google/uuid)",
|
||||
},
|
||||
{
|
||||
"/badge/?path=https://pkg.go.dev/github.com/google/uuid?tab=imports",
|
||||
"[![PkgGoDev](https://example.com/github.com/google/uuid?tab=imports)](https://example.com/badge/github.com/google/uuid?tab=imports)",
|
||||
},
|
||||
{
|
||||
"/badge/?path=https://google.com",
|
||||
"<p>Type a pkg.go.dev URL above to create a badge link.</p>",
|
||||
},
|
||||
{
|
||||
"/badge/?path=https://google.com/github.com/google/uuid",
|
||||
"[![PkgGoDev](https://example.com/github.com/google/uuid)](https://example.com/badge/github.com/google/uuid)",
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.url, func(t *testing.T) {
|
||||
w := httptest.NewRecorder()
|
||||
handler.ServeHTTP(w, httptest.NewRequest("GET", test.url, nil))
|
||||
got := w.Body.String()
|
||||
if !strings.Contains(w.Body.String(), test.want) {
|
||||
t.Errorf("Expected html substring not found, want %s, got %s", test.want, got)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
|
@ -111,6 +111,7 @@ func (s *Server) Install(handle func(string, http.Handler), redisClient *redis.C
|
|||
handle("/search-help", s.staticPageHandler("search_help.tmpl", "Search Help - go.dev"))
|
||||
handle("/license-policy", s.licensePolicyHandler())
|
||||
handle("/about", http.RedirectHandler("https://go.dev/about", http.StatusFound))
|
||||
handle("/badge/", http.HandlerFunc(s.badgeHandler))
|
||||
handle("/", detailHandler)
|
||||
handle("/autocomplete", http.HandlerFunc(s.handleAutoCompletion))
|
||||
handle("/robots.txt", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
|
@ -415,12 +416,13 @@ func parsePageTemplates(base template.TrustedSource) (map[string]*template.Templ
|
|||
join := template.TrustedSourceJoin
|
||||
|
||||
htmlSets := [][]template.TrustedSource{
|
||||
{tsc("index.tmpl")},
|
||||
{tsc("badge.tmpl")},
|
||||
{tsc("error.tmpl")},
|
||||
{tsc("fetch.tmpl")},
|
||||
{tsc("index.tmpl")},
|
||||
{tsc("license_policy.tmpl")},
|
||||
{tsc("search.tmpl")},
|
||||
{tsc("search_help.tmpl")},
|
||||
{tsc("license_policy.tmpl")},
|
||||
{tsc("overview.tmpl"), tsc("details.tmpl")},
|
||||
{tsc("subdirectories.tmpl"), tsc("details.tmpl")},
|
||||
{tsc("pkg_doc.tmpl"), tsc("details.tmpl")},
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright 2019 The Go Authors. All rights reserved.
|
||||
// Copyright 2019-2020 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
|
@ -15,6 +15,8 @@ var scriptHashes = []string{
|
|||
"'sha256-Ajmr6RIM6VV5w/AraBIyO4/XRyuqJlFVukc7TL6feog='",
|
||||
"'sha256-d6W7MwuGWbguTHRzQhf5QN1jXmNo9Ao218saZkWLWZI='",
|
||||
"'sha256-qPGTOKPn+niRiNKQIEX0Ktwuj+D+iPQWIxnlhPicw58='",
|
||||
// From content/static/html/pages/badge.tmpl
|
||||
"'sha256-T7xOt6cgLji3rhOWyKK7t5XKv8+LASQwOnHiHHy8Kwk='",
|
||||
// From content/static/html/pages/details.tmpl
|
||||
"'sha256-s16e7aT7Gsajq5UH1DbaEFEnNx2VjvS5Xixcxwm4+F8='",
|
||||
// From content/static/html/pages/fetch.tmpl
|
||||
|
|
Загрузка…
Ссылка в новой задаче