mirror of
https://github.com/go-gitea/gitea.git
synced 2026-05-12 11:13:21 +02:00
add avatar and iocn gallery to devtest
This commit is contained in:
parent
508da0897f
commit
74c1dff948
@ -7,6 +7,7 @@ import (
|
||||
"fmt"
|
||||
"html/template"
|
||||
"path"
|
||||
"sort"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
@ -78,6 +79,16 @@ func MockIcon(icon string) func() {
|
||||
}
|
||||
}
|
||||
|
||||
// DiscoveredIconNames returns the sorted list of all discovered SVG icon names
|
||||
func DiscoveredIconNames() []string {
|
||||
names := make([]string, 0, len(svgIcons))
|
||||
for name := range svgIcons {
|
||||
names = append(names, name)
|
||||
}
|
||||
sort.Strings(names)
|
||||
return names
|
||||
}
|
||||
|
||||
// RenderHTML renders icons - arguments icon name (string), size (int), class (string)
|
||||
func RenderHTML(icon string, others ...any) template.HTML {
|
||||
result, _ := renderHTML(icon, others...)
|
||||
|
||||
@ -18,6 +18,7 @@ import (
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
"code.gitea.io/gitea/modules/badge"
|
||||
"code.gitea.io/gitea/modules/git"
|
||||
"code.gitea.io/gitea/modules/svg"
|
||||
"code.gitea.io/gitea/modules/templates"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
"code.gitea.io/gitea/services/context"
|
||||
@ -180,6 +181,34 @@ func prepareMockDataRelativeTime(ctx *context.Context) {
|
||||
ctx.Data["TimeFuture1y"] = now.Add(366 * 24 * time.Hour)
|
||||
}
|
||||
|
||||
func prepareMockDataAvatar(ctx *context.Context) {
|
||||
mockUsers, _ := db.Find[user_model.User](ctx, user_model.SearchUserOptions{ListOptions: db.ListOptions{PageSize: 1}})
|
||||
ctx.Data["MockUser"] = mockUsers[0]
|
||||
ctx.Data["AvatarSizes"] = []int{16, 20, 24, 28, 32, 40, 48, 64, 100, 128}
|
||||
ctx.Data["SampleEmails"] = []string{
|
||||
"alice@example.com",
|
||||
"bob@example.org",
|
||||
"charlie@test.io",
|
||||
"devtest@gitea.io",
|
||||
"noreply@example.com",
|
||||
}
|
||||
}
|
||||
|
||||
func prepareMockDataIconGallery(ctx *context.Context) {
|
||||
allNames := svg.DiscoveredIconNames()
|
||||
grouped := map[string][]string{}
|
||||
for _, name := range allNames {
|
||||
prefix := "other"
|
||||
if before, _, ok := strings.Cut(name, "-"); ok {
|
||||
prefix = before
|
||||
}
|
||||
grouped[prefix] = append(grouped[prefix], name)
|
||||
}
|
||||
ctx.Data["IconGroups"] = grouped
|
||||
ctx.Data["IconGroupOrder"] = []string{"octicon", "gitea", "fontawesome", "material", "other"}
|
||||
ctx.Data["IconCount"] = len(allNames)
|
||||
}
|
||||
|
||||
func prepareMockData(ctx *context.Context) {
|
||||
switch ctx.Req.URL.Path {
|
||||
case "/devtest/gitea-ui":
|
||||
@ -190,6 +219,10 @@ func prepareMockData(ctx *context.Context) {
|
||||
prepareMockDataBadgeActionsSvg(ctx)
|
||||
case "/devtest/relative-time":
|
||||
prepareMockDataRelativeTime(ctx)
|
||||
case "/devtest/avatar":
|
||||
prepareMockDataAvatar(ctx)
|
||||
case "/devtest/icon-gallery":
|
||||
prepareMockDataIconGallery(ctx)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
83
templates/devtest/avatar.tmpl
Normal file
83
templates/devtest/avatar.tmpl
Normal file
@ -0,0 +1,83 @@
|
||||
{{template "devtest/devtest-header"}}
|
||||
<div class="page-content devtest ui container">
|
||||
<h1>Avatar</h1>
|
||||
|
||||
<h2>Sizes (via AvatarByEmail)</h2>
|
||||
<p>Using <code>ctx.AvatarUtils.AvatarByEmail</code> at various pixel sizes:</p>
|
||||
<div class="flex-text-block tw-gap-4 tw-items-end">
|
||||
{{range $size := .AvatarSizes}}
|
||||
<div class="tw-flex tw-flex-col tw-items-center tw-gap-1">
|
||||
{{ctx.AvatarUtils.AvatarByEmail "devtest@example.com" "Dev Test" $size}}
|
||||
<code>{{$size}}px</code>
|
||||
</div>
|
||||
{{end}}
|
||||
</div>
|
||||
|
||||
<h2>User Avatars</h2>
|
||||
<p>Using <code>ctx.AvatarUtils.Avatar</code> with a real user and with <code>nil</code> (fallback):</p>
|
||||
<div class="flex-text-block tw-gap-4 tw-items-end">
|
||||
<div class="tw-flex tw-flex-col tw-items-center tw-gap-1">
|
||||
{{ctx.AvatarUtils.Avatar .MockUser 28}}
|
||||
<code>User (28px)</code>
|
||||
</div>
|
||||
<div class="tw-flex tw-flex-col tw-items-center tw-gap-1">
|
||||
{{ctx.AvatarUtils.Avatar .MockUser 40}}
|
||||
<code>User (40px)</code>
|
||||
</div>
|
||||
<div class="tw-flex tw-flex-col tw-items-center tw-gap-1">
|
||||
{{ctx.AvatarUtils.Avatar .MockUser 100}}
|
||||
<code>User (100px)</code>
|
||||
</div>
|
||||
<div class="tw-flex tw-flex-col tw-items-center tw-gap-1">
|
||||
{{ctx.AvatarUtils.Avatar nil 28}}
|
||||
<code>nil fallback (28px)</code>
|
||||
</div>
|
||||
<div class="tw-flex tw-flex-col tw-items-center tw-gap-1">
|
||||
{{ctx.AvatarUtils.Avatar nil 40}}
|
||||
<code>nil fallback (40px)</code>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h2>Custom CSS Classes</h2>
|
||||
<div class="flex-text-block tw-gap-4 tw-items-end">
|
||||
<div class="tw-flex tw-flex-col tw-items-center tw-gap-1">
|
||||
{{ctx.AvatarUtils.Avatar .MockUser 28 "ui avatar tw-align-middle"}}
|
||||
<code>default class</code>
|
||||
</div>
|
||||
<div class="tw-flex tw-flex-col tw-items-center tw-gap-1">
|
||||
{{ctx.AvatarUtils.Avatar .MockUser 28 "ui avatar tw-align-middle tw-rounded-full"}}
|
||||
<code>tw-rounded-full</code>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h2>Inline with Text</h2>
|
||||
<div class="tw-my-2">
|
||||
<span class="flex-text-inline">{{ctx.AvatarUtils.Avatar .MockUser 20 "ui avatar tw-align-middle"}} <a href="#">{{.MockUser.Name}}</a> opened this issue</span>
|
||||
</div>
|
||||
<div class="tw-my-2">
|
||||
<span class="flex-text-inline">{{ctx.AvatarUtils.AvatarByEmail "user1@example.com" "User One" 16}} User One and {{ctx.AvatarUtils.AvatarByEmail "user2@example.com" "User Two" 16}} User Two</span>
|
||||
</div>
|
||||
|
||||
<h2>Avatar with Link (typical pattern)</h2>
|
||||
<div class="flex-text-block tw-gap-4">
|
||||
<a class="flex-text-inline" href="#">{{ctx.AvatarUtils.Avatar .MockUser 28}} <strong>{{.MockUser.Name}}</strong></a>
|
||||
</div>
|
||||
|
||||
<h2>Avatar Upload Cropper</h2>
|
||||
<p>The cropper requires <code>index.js</code> (global init). The HTML structure is shown below for reference:</p>
|
||||
<div class="ui form tw-max-w-lg">
|
||||
{{template "shared/avatar_upload_crop" dict "LabelText" "Choose an avatar"}}
|
||||
</div>
|
||||
|
||||
<h2>Multiple Email Avatars (gravatar hashing)</h2>
|
||||
<p>Different emails produce different fallback avatars:</p>
|
||||
<div class="flex-text-block tw-gap-2">
|
||||
{{range $email := .SampleEmails}}
|
||||
<div class="tw-flex tw-flex-col tw-items-center tw-gap-1">
|
||||
{{ctx.AvatarUtils.AvatarByEmail $email $email 28}}
|
||||
<code class="gt-ellipsis" style="max-width: 100px" title="{{$email}}">{{$email}}</code>
|
||||
</div>
|
||||
{{end}}
|
||||
</div>
|
||||
</div>
|
||||
{{template "devtest/devtest-footer"}}
|
||||
45
templates/devtest/icon-gallery.tmpl
Normal file
45
templates/devtest/icon-gallery.tmpl
Normal file
@ -0,0 +1,45 @@
|
||||
{{template "devtest/devtest-header"}}
|
||||
<div class="page-content devtest ui container">
|
||||
<h1>Icon Gallery</h1>
|
||||
<p>All <strong>{{.IconCount}}</strong> SVG icons available in templates.</p>
|
||||
<p>
|
||||
<input id="icon-search" type="text" placeholder="Filter icons..." class="ui input" style="width: 300px">
|
||||
<label class="gt-checkbox tw-ml-4"><input id="icon-size-toggle" type="checkbox"> Large (24px)</label>
|
||||
</p>
|
||||
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
const search = document.getElementById('icon-search');
|
||||
const sizeToggle = document.getElementById('icon-size-toggle');
|
||||
search.addEventListener('input', () => {
|
||||
const q = search.value.toLowerCase();
|
||||
for (const card of document.querySelectorAll('.icon-card')) {
|
||||
card.style.display = card.getAttribute('data-name').includes(q) ? '' : 'none';
|
||||
}
|
||||
});
|
||||
sizeToggle.addEventListener('change', () => {
|
||||
const size = sizeToggle.checked ? '24' : '16';
|
||||
for (const icon of document.querySelectorAll('.icon-card svg')) {
|
||||
icon.setAttribute('width', size);
|
||||
icon.setAttribute('height', size);
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
{{range $prefix := .IconGroupOrder}}
|
||||
{{$icons := index $.IconGroups $prefix}}
|
||||
{{if $icons}}
|
||||
<h2 id="group-{{$prefix}}">{{$prefix}} <span class="ui grey label">{{len $icons}}</span></h2>
|
||||
<div class="tw-flex tw-flex-wrap tw-gap-2 tw-mb-4">
|
||||
{{range $name := $icons}}
|
||||
<div class="icon-card tw-flex tw-flex-col tw-items-center tw-gap-1 tw-p-2 tw-border tw-border-secondary tw-rounded" style="width: 120px" data-name="{{$name}}" title="{{$name}}">
|
||||
<div class="tw-flex tw-items-center tw-justify-center" style="height: 32px">{{svg $name 16}}</div>
|
||||
<code class="gt-ellipsis" style="max-width: 108px; font-size: 10px">{{$name}}</code>
|
||||
</div>
|
||||
{{end}}
|
||||
</div>
|
||||
{{end}}
|
||||
{{end}}
|
||||
</div>
|
||||
{{template "devtest/devtest-footer"}}
|
||||
Loading…
x
Reference in New Issue
Block a user