Files
awesome-ai-dev-tools/site.go
T
tiennm99 eb12bcc2cb feat: replace category with a multi-facet tag vocabulary
A single category could not describe tools that ship as a CLI, an editor
plugin and a desktop app at once, and 7 of the 40 entries were filed
under a surface they only partly match — cline is "an SDK, IDE extension
or CLI assistant" in one `extension` slot, Reasonix ships CLI, desktop
and VS Code under `cli`, warp is a terminal filed as `ide`.

Tags cover five facets: surface (at least one), model access, workflow,
integration, and origin (at most one). tagVocabulary in validate.go is
the single source of truth — the validator, its error messages, and the
dashboard's filter chips all derive from it, the last via a new facets
field in site/data.json.

The dashboard now filters on tags with multi-select chips grouped by
facet: OR within a facet, AND across facets, plus a clear-filters
control, and search matches tags as well as name and description. Only
tags some row actually carries get a chip, so chips and rows cannot
disagree. Tag pills are tinted per facet, replacing the category badge.

All 40 entries are tagged from each repo's own README, topics and docs;
CONTRIBUTING documents every tag and the evidence rule for applying one.
A leftover `category:` key now fails validation with a message naming
its replacement, rather than being silently ignored.

README.md and data/history.jsonl are the regenerated updater output.
2026-09-11 15:40:18 +07:00

70 lines
2.2 KiB
Go

package main
import (
"encoding/json"
"io"
)
// siteRow is one ranked repo in site/data.json, consumed by site/index.html.
type siteRow struct {
Key string `json:"key"` // canonical owner/repo, matches history keys
NameWithOwner string `json:"nameWithOwner"`
URL string `json:"url"`
Stars int `json:"stars"`
Delta7d int `json:"delta7d"`
HasDelta bool `json:"hasDelta"`
Delta30d int `json:"delta30d"`
HasDelta30 bool `json:"hasDelta30"`
Language string `json:"language"`
PushedAt string `json:"pushedAt"`
Description string `json:"description"`
Tags []string `json:"tags"`
Notes string `json:"notes,omitempty"`
Archived bool `json:"archived"`
}
type siteData struct {
UpdatedAt string `json:"updatedAt"`
Rows []siteRow `json:"rows"`
History []Snapshot `json:"history"`
// Facets drives the dashboard's filter chips, so the tag vocabulary is
// defined once in Go rather than duplicated in site/index.html.
Facets []tagFacet `json:"facets"`
}
// writeSiteData emits the JSON payload for the GitHub Pages dashboard.
// The file is generated fresh on every updater run and is not committed;
// the Pages deploy step in the workflow picks it up from the working tree.
func writeSiteData(path string, stats []Stat, deltas7, deltas30 map[string]int, history []Snapshot) error {
rows := make([]siteRow, len(stats))
for i, s := range stats {
delta7, has7 := deltas7[s.CanonicalKey]
delta30, has30 := deltas30[s.CanonicalKey]
rows[i] = siteRow{
Key: s.CanonicalKey,
NameWithOwner: s.NameWithOwner,
URL: s.URL,
Stars: s.Stars,
Delta7d: delta7,
HasDelta: has7,
Delta30d: delta30,
HasDelta30: has30,
Language: s.Language,
PushedAt: s.PushedAt.Format("2006-01-02"),
Description: s.Description,
Tags: s.Tags,
Notes: s.Notes,
Archived: s.IsArchived,
}
}
return atomicWriteFile(path, func(w io.Writer) error {
return json.NewEncoder(w).Encode(siteData{
UpdatedAt: timeNow().UTC().Format("2006-01-02 15:04 UTC"),
Rows: rows,
History: history,
Facets: tagVocabulary,
})
})
}