Skip to content
Draft
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -370,6 +370,10 @@ lint-json-fix: node_modules ## lint and fix json files
watch: ## watch everything and continuously rebuild
@bash tools/watch.sh

.PHONY: watch-sqlite
watch-sqlite: ## watch and use sqlite for testing
@TAGS="sqlite sqlite_unlock_notify" $(MAKE) watch

.PHONY: watch-frontend
watch-frontend: node_modules ## start vite dev server for frontend
NODE_ENV=development pnpm exec vite
Expand Down
11 changes: 11 additions & 0 deletions modules/svg/svg.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"fmt"
"html/template"
"path"
"sort"
"strings"
"sync"

Expand Down Expand Up @@ -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...)
Expand Down
18 changes: 18 additions & 0 deletions routers/web/devtest/devtest.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -180,6 +181,21 @@ func prepareMockDataRelativeTime(ctx *context.Context) {
ctx.Data["TimeFuture1y"] = now.Add(366 * 24 * time.Hour)
}

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":
Expand All @@ -190,6 +206,8 @@ func prepareMockData(ctx *context.Context) {
prepareMockDataBadgeActionsSvg(ctx)
case "/devtest/relative-time":
prepareMockDataRelativeTime(ctx)
case "/devtest/icon-gallery":
prepareMockDataIconGallery(ctx)
}
}

Expand Down
45 changes: 45 additions & 0 deletions templates/devtest/icon-gallery.tmpl
Original file line number Diff line number Diff line change
@@ -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"}}