About: contributor and model credits compiled in (grab bag + table, self-submitted names) (#898)
* About: contributors and models tabs compiled in from contributors.json (grab bag + table, sortable, name toggle) Help > About PhotoCraft gets tabs About · Contributors · Models, following the craftrules standard (standards/contributors.md): contributors/contributors.json is generated by craftrules/scripts/contributors.py and baked into the binary by crates/ui-egui/build.rs as static tables (nothing read at run time; the web build has them too). Each contributor line: @username, opt-in display/real name, PRs, commits, lines +/−/Δ, binary assets +/−, first/last commit. Sortable by every column; alphabetical ignores case and the leading @. The tab is the dialog field `tab`, so agents can switch it with ui.dialog.set. New labels are translated in all eleven catalogs. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Contributors docs: craftrules is two levels up (../../craftrules) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Contributors: self-submitted names in contributors/people.toml; AGENTS.md credit-yourself section build.rs reads contributors/people.toml next to the generated contributors.json and shows a name only for entries the generator verified as written by that person (craftrules standards/contributors.md). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Contributors: regenerate (verified people.toml entries) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * i18n: credits labels for catalogs added on main since this branch Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Contributors: regenerate after rebase onto main Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Contributors: regenerate (verified people.toml entries) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
aaa946b56d
commit
44303db546
18
AGENTS.md
18
AGENTS.md
|
|
@ -131,3 +131,21 @@ Then append a terse entry to `log/devlog.md` (what landed, numbers, what's still
|
|||
nothing is silently dropped from `.pcraft` saves. When you add a doc field, add it to
|
||||
`crates/format/src/manifest.rs` and `convert.rs` with `#[serde(default)]` so older files still load.
|
||||
If the field has a PSD equivalent, map it in `crates/io` too, and keep unknown PSD blocks verbatim.
|
||||
|
||||
## Contributor credits (About window)
|
||||
|
||||
- About ▸ Contributors/Models are compiled into the binary from `contributors/contributors.json`
|
||||
(commit stats; generated, never hand-edit) and `contributors/people.toml` (names people chose for
|
||||
themselves). See `docs/contributors.md`.
|
||||
- **Agents working for a contributor:** when you prepare a PR, check whether your human's GitHub
|
||||
username has a `[people.<username>]` entry in `contributors/people.toml`. If not, ask them once
|
||||
whether they want to be credited by more than their username: a real name, a display name, and/or
|
||||
their public GitHub profile name (`sync_github_name = true`). If yes, add **only their own** entry
|
||||
(copy the template at the top of the file, or run
|
||||
`python3 ../../craftrules/scripts/contributors.py --add-me . --real-name "…" --sync-github-name`)
|
||||
and include it in their PR, committed as them. If no, change nothing: they are credited as
|
||||
`@username` anyway.
|
||||
- Never add, edit, guess or copy anyone else's entry or name (not from git config, commit authors or
|
||||
GitHub profiles). Never hand-edit `contributors.json`.
|
||||
- Maintainers refresh the stats with `python3 ../../craftrules/scripts/contributors.py .` (it also
|
||||
re-verifies who wrote each `people.toml` entry; `--check` only verifies).
|
||||
|
|
|
|||
|
|
@ -3795,6 +3795,7 @@ dependencies = [
|
|||
"serde",
|
||||
"serde_json",
|
||||
"sys-locale",
|
||||
"toml",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
|
|||
|
|
@ -0,0 +1,943 @@
|
|||
{
|
||||
"schema": 1,
|
||||
"repo": "storytold/photocraft",
|
||||
"branch": "main",
|
||||
"head": "aaa946b56df2d74d198c47e67dda35ddce0b3769",
|
||||
"head_date": "2026-10-08T01:20:47Z",
|
||||
"commits": 482,
|
||||
"unattributed_commits": 0,
|
||||
"contributors": [
|
||||
{
|
||||
"login": "echelon",
|
||||
"people_entry": true,
|
||||
"github_name": null,
|
||||
"prs": 124,
|
||||
"commits": 201,
|
||||
"lines_added": 277845,
|
||||
"lines_deleted": 22466,
|
||||
"binary_added": 39,
|
||||
"binary_deleted": 8,
|
||||
"first_commit": "2026-09-30T06:12:04Z",
|
||||
"last_commit": "2026-10-07T22:09:41Z"
|
||||
},
|
||||
{
|
||||
"login": "storybored379",
|
||||
"people_entry": false,
|
||||
"github_name": null,
|
||||
"prs": 8,
|
||||
"commits": 8,
|
||||
"lines_added": 2707,
|
||||
"lines_deleted": 54,
|
||||
"binary_added": 0,
|
||||
"binary_deleted": 0,
|
||||
"first_commit": "2026-10-04T04:57:38Z",
|
||||
"last_commit": "2026-10-05T22:14:20Z"
|
||||
},
|
||||
{
|
||||
"login": "Multipad-cyber",
|
||||
"people_entry": false,
|
||||
"github_name": null,
|
||||
"prs": 3,
|
||||
"commits": 3,
|
||||
"lines_added": 171,
|
||||
"lines_deleted": 27,
|
||||
"binary_added": 0,
|
||||
"binary_deleted": 0,
|
||||
"first_commit": "2026-10-04T05:02:49Z",
|
||||
"last_commit": "2026-10-06T11:43:37Z"
|
||||
},
|
||||
{
|
||||
"login": "torstfugl",
|
||||
"people_entry": false,
|
||||
"github_name": null,
|
||||
"prs": 3,
|
||||
"commits": 3,
|
||||
"lines_added": 377,
|
||||
"lines_deleted": 8,
|
||||
"binary_added": 0,
|
||||
"binary_deleted": 0,
|
||||
"first_commit": "2026-10-04T05:03:49Z",
|
||||
"last_commit": "2026-10-04T16:21:25Z"
|
||||
},
|
||||
{
|
||||
"login": "sommerper",
|
||||
"people_entry": false,
|
||||
"github_name": null,
|
||||
"prs": 9,
|
||||
"commits": 9,
|
||||
"lines_added": 865,
|
||||
"lines_deleted": 148,
|
||||
"binary_added": 0,
|
||||
"binary_deleted": 0,
|
||||
"first_commit": "2026-10-04T14:13:31Z",
|
||||
"last_commit": "2026-10-07T11:12:58Z"
|
||||
},
|
||||
{
|
||||
"login": "Gh0stlyKn1ght",
|
||||
"people_entry": false,
|
||||
"github_name": null,
|
||||
"prs": 4,
|
||||
"commits": 4,
|
||||
"lines_added": 3349,
|
||||
"lines_deleted": 255,
|
||||
"binary_added": 0,
|
||||
"binary_deleted": 0,
|
||||
"first_commit": "2026-10-04T16:31:18Z",
|
||||
"last_commit": "2026-10-05T05:02:40Z"
|
||||
},
|
||||
{
|
||||
"login": "MikeeI",
|
||||
"people_entry": false,
|
||||
"github_name": null,
|
||||
"prs": 22,
|
||||
"commits": 22,
|
||||
"lines_added": 753,
|
||||
"lines_deleted": 178,
|
||||
"binary_added": 0,
|
||||
"binary_deleted": 0,
|
||||
"first_commit": "2026-10-05T04:59:38Z",
|
||||
"last_commit": "2026-10-05T05:37:25Z"
|
||||
},
|
||||
{
|
||||
"login": "tiredIsa",
|
||||
"people_entry": false,
|
||||
"github_name": null,
|
||||
"prs": 5,
|
||||
"commits": 5,
|
||||
"lines_added": 7086,
|
||||
"lines_deleted": 493,
|
||||
"binary_added": 0,
|
||||
"binary_deleted": 0,
|
||||
"first_commit": "2026-10-05T05:01:36Z",
|
||||
"last_commit": "2026-10-07T21:59:16Z"
|
||||
},
|
||||
{
|
||||
"login": "Ni-zav",
|
||||
"people_entry": false,
|
||||
"github_name": null,
|
||||
"prs": 12,
|
||||
"commits": 12,
|
||||
"lines_added": 488,
|
||||
"lines_deleted": 42,
|
||||
"binary_added": 0,
|
||||
"binary_deleted": 0,
|
||||
"first_commit": "2026-10-05T05:01:49Z",
|
||||
"last_commit": "2026-10-07T21:57:43Z"
|
||||
},
|
||||
{
|
||||
"login": "kntrttm",
|
||||
"people_entry": false,
|
||||
"github_name": null,
|
||||
"prs": 3,
|
||||
"commits": 3,
|
||||
"lines_added": 4228,
|
||||
"lines_deleted": 1172,
|
||||
"binary_added": 0,
|
||||
"binary_deleted": 0,
|
||||
"first_commit": "2026-10-05T05:02:52Z",
|
||||
"last_commit": "2026-10-05T23:40:10Z"
|
||||
},
|
||||
{
|
||||
"login": "kevin9327",
|
||||
"people_entry": false,
|
||||
"github_name": null,
|
||||
"prs": 1,
|
||||
"commits": 1,
|
||||
"lines_added": 15,
|
||||
"lines_deleted": 2,
|
||||
"binary_added": 0,
|
||||
"binary_deleted": 0,
|
||||
"first_commit": "2026-10-05T08:14:40Z",
|
||||
"last_commit": "2026-10-05T08:14:40Z"
|
||||
},
|
||||
{
|
||||
"login": "mekanix",
|
||||
"people_entry": false,
|
||||
"github_name": null,
|
||||
"prs": 1,
|
||||
"commits": 1,
|
||||
"lines_added": 29,
|
||||
"lines_deleted": 8,
|
||||
"binary_added": 0,
|
||||
"binary_deleted": 0,
|
||||
"first_commit": "2026-10-05T13:01:58Z",
|
||||
"last_commit": "2026-10-05T13:01:58Z"
|
||||
},
|
||||
{
|
||||
"login": "nuIIpointerexception",
|
||||
"people_entry": false,
|
||||
"github_name": null,
|
||||
"prs": 1,
|
||||
"commits": 1,
|
||||
"lines_added": 82,
|
||||
"lines_deleted": 9,
|
||||
"binary_added": 0,
|
||||
"binary_deleted": 0,
|
||||
"first_commit": "2026-10-05T13:02:14Z",
|
||||
"last_commit": "2026-10-05T13:02:14Z"
|
||||
},
|
||||
{
|
||||
"login": "john8675309",
|
||||
"people_entry": false,
|
||||
"github_name": null,
|
||||
"prs": 1,
|
||||
"commits": 1,
|
||||
"lines_added": 89,
|
||||
"lines_deleted": 0,
|
||||
"binary_added": 0,
|
||||
"binary_deleted": 0,
|
||||
"first_commit": "2026-10-05T13:58:45Z",
|
||||
"last_commit": "2026-10-05T13:58:45Z"
|
||||
},
|
||||
{
|
||||
"login": "CQMHV",
|
||||
"people_entry": false,
|
||||
"github_name": null,
|
||||
"prs": 9,
|
||||
"commits": 9,
|
||||
"lines_added": 2841,
|
||||
"lines_deleted": 23,
|
||||
"binary_added": 2,
|
||||
"binary_deleted": 0,
|
||||
"first_commit": "2026-10-05T22:13:51Z",
|
||||
"last_commit": "2026-10-07T20:43:03Z"
|
||||
},
|
||||
{
|
||||
"login": "kuishou68",
|
||||
"people_entry": false,
|
||||
"github_name": null,
|
||||
"prs": 1,
|
||||
"commits": 1,
|
||||
"lines_added": 6,
|
||||
"lines_deleted": 1931,
|
||||
"binary_added": 0,
|
||||
"binary_deleted": 0,
|
||||
"first_commit": "2026-10-06T11:43:03Z",
|
||||
"last_commit": "2026-10-06T11:43:03Z"
|
||||
},
|
||||
{
|
||||
"login": "midasdf",
|
||||
"people_entry": false,
|
||||
"github_name": null,
|
||||
"prs": 2,
|
||||
"commits": 2,
|
||||
"lines_added": 199,
|
||||
"lines_deleted": 25,
|
||||
"binary_added": 0,
|
||||
"binary_deleted": 0,
|
||||
"first_commit": "2026-10-06T11:44:08Z",
|
||||
"last_commit": "2026-10-07T22:53:56Z"
|
||||
},
|
||||
{
|
||||
"login": "bommerts",
|
||||
"people_entry": false,
|
||||
"github_name": null,
|
||||
"prs": 1,
|
||||
"commits": 1,
|
||||
"lines_added": 30,
|
||||
"lines_deleted": 3,
|
||||
"binary_added": 0,
|
||||
"binary_deleted": 0,
|
||||
"first_commit": "2026-10-06T14:46:41Z",
|
||||
"last_commit": "2026-10-06T14:46:41Z"
|
||||
},
|
||||
{
|
||||
"login": "leonaci",
|
||||
"people_entry": false,
|
||||
"github_name": null,
|
||||
"prs": 1,
|
||||
"commits": 1,
|
||||
"lines_added": 202,
|
||||
"lines_deleted": 26,
|
||||
"binary_added": 0,
|
||||
"binary_deleted": 0,
|
||||
"first_commit": "2026-10-06T15:27:54Z",
|
||||
"last_commit": "2026-10-06T15:27:54Z"
|
||||
},
|
||||
{
|
||||
"login": "juansebsol",
|
||||
"people_entry": false,
|
||||
"github_name": null,
|
||||
"prs": 2,
|
||||
"commits": 2,
|
||||
"lines_added": 800,
|
||||
"lines_deleted": 118,
|
||||
"binary_added": 0,
|
||||
"binary_deleted": 0,
|
||||
"first_commit": "2026-10-06T15:28:09Z",
|
||||
"last_commit": "2026-10-07T12:40:00Z"
|
||||
},
|
||||
{
|
||||
"login": "WildfootW",
|
||||
"people_entry": false,
|
||||
"github_name": null,
|
||||
"prs": 1,
|
||||
"commits": 1,
|
||||
"lines_added": 2027,
|
||||
"lines_deleted": 17,
|
||||
"binary_added": 0,
|
||||
"binary_deleted": 0,
|
||||
"first_commit": "2026-10-06T15:28:23Z",
|
||||
"last_commit": "2026-10-06T15:28:23Z"
|
||||
},
|
||||
{
|
||||
"login": "Mawfyy",
|
||||
"people_entry": false,
|
||||
"github_name": null,
|
||||
"prs": 3,
|
||||
"commits": 3,
|
||||
"lines_added": 2213,
|
||||
"lines_deleted": 4,
|
||||
"binary_added": 0,
|
||||
"binary_deleted": 0,
|
||||
"first_commit": "2026-10-06T15:28:37Z",
|
||||
"last_commit": "2026-10-07T20:12:00Z"
|
||||
},
|
||||
{
|
||||
"login": "petrleocompel",
|
||||
"people_entry": false,
|
||||
"github_name": null,
|
||||
"prs": 1,
|
||||
"commits": 1,
|
||||
"lines_added": 2025,
|
||||
"lines_deleted": 2,
|
||||
"binary_added": 0,
|
||||
"binary_deleted": 0,
|
||||
"first_commit": "2026-10-06T15:29:44Z",
|
||||
"last_commit": "2026-10-06T15:29:44Z"
|
||||
},
|
||||
{
|
||||
"login": "bflatastic",
|
||||
"people_entry": false,
|
||||
"github_name": null,
|
||||
"prs": 35,
|
||||
"commits": 35,
|
||||
"lines_added": 6009,
|
||||
"lines_deleted": 1253,
|
||||
"binary_added": 0,
|
||||
"binary_deleted": 0,
|
||||
"first_commit": "2026-10-07T00:59:14Z",
|
||||
"last_commit": "2026-10-08T01:16:38Z"
|
||||
},
|
||||
{
|
||||
"login": "Pedroj-64",
|
||||
"people_entry": false,
|
||||
"github_name": null,
|
||||
"prs": 2,
|
||||
"commits": 2,
|
||||
"lines_added": 141,
|
||||
"lines_deleted": 9,
|
||||
"binary_added": 0,
|
||||
"binary_deleted": 0,
|
||||
"first_commit": "2026-10-07T03:28:01Z",
|
||||
"last_commit": "2026-10-07T03:43:31Z"
|
||||
},
|
||||
{
|
||||
"login": "floflo777",
|
||||
"people_entry": false,
|
||||
"github_name": null,
|
||||
"prs": 4,
|
||||
"commits": 4,
|
||||
"lines_added": 163,
|
||||
"lines_deleted": 31,
|
||||
"binary_added": 0,
|
||||
"binary_deleted": 0,
|
||||
"first_commit": "2026-10-07T03:34:03Z",
|
||||
"last_commit": "2026-10-07T11:05:38Z"
|
||||
},
|
||||
{
|
||||
"login": "HEOJUNFO",
|
||||
"people_entry": false,
|
||||
"github_name": null,
|
||||
"prs": 2,
|
||||
"commits": 2,
|
||||
"lines_added": 55,
|
||||
"lines_deleted": 0,
|
||||
"binary_added": 0,
|
||||
"binary_deleted": 0,
|
||||
"first_commit": "2026-10-07T03:34:17Z",
|
||||
"last_commit": "2026-10-07T03:34:30Z"
|
||||
},
|
||||
{
|
||||
"login": "Ar-maan05",
|
||||
"people_entry": false,
|
||||
"github_name": null,
|
||||
"prs": 7,
|
||||
"commits": 7,
|
||||
"lines_added": 840,
|
||||
"lines_deleted": 111,
|
||||
"binary_added": 0,
|
||||
"binary_deleted": 0,
|
||||
"first_commit": "2026-10-07T03:34:44Z",
|
||||
"last_commit": "2026-10-07T20:30:52Z"
|
||||
},
|
||||
{
|
||||
"login": "agorevski",
|
||||
"people_entry": false,
|
||||
"github_name": null,
|
||||
"prs": 30,
|
||||
"commits": 30,
|
||||
"lines_added": 3353,
|
||||
"lines_deleted": 404,
|
||||
"binary_added": 0,
|
||||
"binary_deleted": 0,
|
||||
"first_commit": "2026-10-07T03:34:59Z",
|
||||
"last_commit": "2026-10-07T21:14:03Z"
|
||||
},
|
||||
{
|
||||
"login": "naumanAhmed3",
|
||||
"people_entry": false,
|
||||
"github_name": null,
|
||||
"prs": 1,
|
||||
"commits": 1,
|
||||
"lines_added": 14,
|
||||
"lines_deleted": 2,
|
||||
"binary_added": 0,
|
||||
"binary_deleted": 0,
|
||||
"first_commit": "2026-10-07T03:38:32Z",
|
||||
"last_commit": "2026-10-07T03:38:32Z"
|
||||
},
|
||||
{
|
||||
"login": "ljkx",
|
||||
"people_entry": false,
|
||||
"github_name": null,
|
||||
"prs": 5,
|
||||
"commits": 5,
|
||||
"lines_added": 7478,
|
||||
"lines_deleted": 178,
|
||||
"binary_added": 0,
|
||||
"binary_deleted": 0,
|
||||
"first_commit": "2026-10-07T03:43:18Z",
|
||||
"last_commit": "2026-10-08T01:12:38Z"
|
||||
},
|
||||
{
|
||||
"login": "carterwsmith",
|
||||
"people_entry": false,
|
||||
"github_name": null,
|
||||
"prs": 4,
|
||||
"commits": 4,
|
||||
"lines_added": 1213,
|
||||
"lines_deleted": 152,
|
||||
"binary_added": 0,
|
||||
"binary_deleted": 0,
|
||||
"first_commit": "2026-10-07T04:32:23Z",
|
||||
"last_commit": "2026-10-07T22:57:50Z"
|
||||
},
|
||||
{
|
||||
"login": "coygeek",
|
||||
"people_entry": false,
|
||||
"github_name": null,
|
||||
"prs": 1,
|
||||
"commits": 1,
|
||||
"lines_added": 4,
|
||||
"lines_deleted": 0,
|
||||
"binary_added": 0,
|
||||
"binary_deleted": 0,
|
||||
"first_commit": "2026-10-07T04:32:34Z",
|
||||
"last_commit": "2026-10-07T04:32:34Z"
|
||||
},
|
||||
{
|
||||
"login": "neversaynv3r",
|
||||
"people_entry": false,
|
||||
"github_name": null,
|
||||
"prs": 1,
|
||||
"commits": 1,
|
||||
"lines_added": 89,
|
||||
"lines_deleted": 0,
|
||||
"binary_added": 0,
|
||||
"binary_deleted": 0,
|
||||
"first_commit": "2026-10-07T04:40:40Z",
|
||||
"last_commit": "2026-10-07T04:40:40Z"
|
||||
},
|
||||
{
|
||||
"login": "ianswope",
|
||||
"people_entry": false,
|
||||
"github_name": null,
|
||||
"prs": 2,
|
||||
"commits": 2,
|
||||
"lines_added": 82,
|
||||
"lines_deleted": 9,
|
||||
"binary_added": 0,
|
||||
"binary_deleted": 0,
|
||||
"first_commit": "2026-10-07T09:26:01Z",
|
||||
"last_commit": "2026-10-07T19:59:51Z"
|
||||
},
|
||||
{
|
||||
"login": "TheSeanLavery",
|
||||
"people_entry": false,
|
||||
"github_name": null,
|
||||
"prs": 4,
|
||||
"commits": 4,
|
||||
"lines_added": 2205,
|
||||
"lines_deleted": 66,
|
||||
"binary_added": 0,
|
||||
"binary_deleted": 0,
|
||||
"first_commit": "2026-10-07T10:11:06Z",
|
||||
"last_commit": "2026-10-07T11:45:26Z"
|
||||
},
|
||||
{
|
||||
"login": "mnmlyw",
|
||||
"people_entry": false,
|
||||
"github_name": null,
|
||||
"prs": 4,
|
||||
"commits": 4,
|
||||
"lines_added": 330,
|
||||
"lines_deleted": 41,
|
||||
"binary_added": 0,
|
||||
"binary_deleted": 0,
|
||||
"first_commit": "2026-10-07T10:12:13Z",
|
||||
"last_commit": "2026-10-08T01:20:47Z"
|
||||
},
|
||||
{
|
||||
"login": "rosematcha",
|
||||
"people_entry": false,
|
||||
"github_name": null,
|
||||
"prs": 12,
|
||||
"commits": 12,
|
||||
"lines_added": 1700,
|
||||
"lines_deleted": 202,
|
||||
"binary_added": 0,
|
||||
"binary_deleted": 0,
|
||||
"first_commit": "2026-10-07T10:49:53Z",
|
||||
"last_commit": "2026-10-08T00:18:27Z"
|
||||
},
|
||||
{
|
||||
"login": "jason4short",
|
||||
"people_entry": false,
|
||||
"github_name": null,
|
||||
"prs": 8,
|
||||
"commits": 8,
|
||||
"lines_added": 1653,
|
||||
"lines_deleted": 101,
|
||||
"binary_added": 0,
|
||||
"binary_deleted": 0,
|
||||
"first_commit": "2026-10-07T10:58:01Z",
|
||||
"last_commit": "2026-10-07T22:02:34Z"
|
||||
},
|
||||
{
|
||||
"login": "siraxe",
|
||||
"people_entry": false,
|
||||
"github_name": null,
|
||||
"prs": 1,
|
||||
"commits": 1,
|
||||
"lines_added": 276,
|
||||
"lines_deleted": 18,
|
||||
"binary_added": 0,
|
||||
"binary_deleted": 0,
|
||||
"first_commit": "2026-10-07T11:03:49Z",
|
||||
"last_commit": "2026-10-07T11:03:49Z"
|
||||
},
|
||||
{
|
||||
"login": "arpitkjaiswal",
|
||||
"people_entry": false,
|
||||
"github_name": null,
|
||||
"prs": 1,
|
||||
"commits": 1,
|
||||
"lines_added": 19,
|
||||
"lines_deleted": 19,
|
||||
"binary_added": 0,
|
||||
"binary_deleted": 0,
|
||||
"first_commit": "2026-10-07T11:06:21Z",
|
||||
"last_commit": "2026-10-07T11:06:21Z"
|
||||
},
|
||||
{
|
||||
"login": "EthanSuquet",
|
||||
"people_entry": false,
|
||||
"github_name": null,
|
||||
"prs": 5,
|
||||
"commits": 5,
|
||||
"lines_added": 405,
|
||||
"lines_deleted": 56,
|
||||
"binary_added": 0,
|
||||
"binary_deleted": 0,
|
||||
"first_commit": "2026-10-07T11:40:10Z",
|
||||
"last_commit": "2026-10-07T20:50:09Z"
|
||||
},
|
||||
{
|
||||
"login": "alexanderalber",
|
||||
"people_entry": false,
|
||||
"github_name": null,
|
||||
"prs": 3,
|
||||
"commits": 3,
|
||||
"lines_added": 1809,
|
||||
"lines_deleted": 56,
|
||||
"binary_added": 0,
|
||||
"binary_deleted": 0,
|
||||
"first_commit": "2026-10-07T11:42:30Z",
|
||||
"last_commit": "2026-10-07T22:59:39Z"
|
||||
},
|
||||
{
|
||||
"login": "flyyangX",
|
||||
"people_entry": false,
|
||||
"github_name": null,
|
||||
"prs": 1,
|
||||
"commits": 1,
|
||||
"lines_added": 242,
|
||||
"lines_deleted": 53,
|
||||
"binary_added": 0,
|
||||
"binary_deleted": 0,
|
||||
"first_commit": "2026-10-07T11:46:52Z",
|
||||
"last_commit": "2026-10-07T11:46:52Z"
|
||||
},
|
||||
{
|
||||
"login": "leblanc-simon",
|
||||
"people_entry": false,
|
||||
"github_name": null,
|
||||
"prs": 1,
|
||||
"commits": 1,
|
||||
"lines_added": 2527,
|
||||
"lines_deleted": 4,
|
||||
"binary_added": 0,
|
||||
"binary_deleted": 0,
|
||||
"first_commit": "2026-10-07T11:49:30Z",
|
||||
"last_commit": "2026-10-07T11:49:30Z"
|
||||
},
|
||||
{
|
||||
"login": "trokute",
|
||||
"people_entry": false,
|
||||
"github_name": null,
|
||||
"prs": 1,
|
||||
"commits": 1,
|
||||
"lines_added": 2484,
|
||||
"lines_deleted": 1,
|
||||
"binary_added": 0,
|
||||
"binary_deleted": 0,
|
||||
"first_commit": "2026-10-07T11:52:51Z",
|
||||
"last_commit": "2026-10-07T11:52:51Z"
|
||||
},
|
||||
{
|
||||
"login": "ha1des",
|
||||
"people_entry": false,
|
||||
"github_name": null,
|
||||
"prs": 1,
|
||||
"commits": 1,
|
||||
"lines_added": 1328,
|
||||
"lines_deleted": 161,
|
||||
"binary_added": 0,
|
||||
"binary_deleted": 0,
|
||||
"first_commit": "2026-10-07T13:02:58Z",
|
||||
"last_commit": "2026-10-07T13:02:58Z"
|
||||
},
|
||||
{
|
||||
"login": "neko233-com",
|
||||
"people_entry": false,
|
||||
"github_name": null,
|
||||
"prs": 2,
|
||||
"commits": 2,
|
||||
"lines_added": 2719,
|
||||
"lines_deleted": 73,
|
||||
"binary_added": 0,
|
||||
"binary_deleted": 0,
|
||||
"first_commit": "2026-10-07T13:06:33Z",
|
||||
"last_commit": "2026-10-07T20:52:55Z"
|
||||
},
|
||||
{
|
||||
"login": "Sirsyorrz",
|
||||
"people_entry": false,
|
||||
"github_name": null,
|
||||
"prs": 1,
|
||||
"commits": 1,
|
||||
"lines_added": 61,
|
||||
"lines_deleted": 7,
|
||||
"binary_added": 0,
|
||||
"binary_deleted": 0,
|
||||
"first_commit": "2026-10-07T13:11:35Z",
|
||||
"last_commit": "2026-10-07T13:11:35Z"
|
||||
},
|
||||
{
|
||||
"login": "Elvis33LE",
|
||||
"people_entry": false,
|
||||
"github_name": null,
|
||||
"prs": 8,
|
||||
"commits": 8,
|
||||
"lines_added": 3929,
|
||||
"lines_deleted": 91,
|
||||
"binary_added": 0,
|
||||
"binary_deleted": 0,
|
||||
"first_commit": "2026-10-07T13:11:45Z",
|
||||
"last_commit": "2026-10-08T01:10:38Z"
|
||||
},
|
||||
{
|
||||
"login": "cristianmoroaica",
|
||||
"people_entry": false,
|
||||
"github_name": null,
|
||||
"prs": 1,
|
||||
"commits": 1,
|
||||
"lines_added": 34,
|
||||
"lines_deleted": 6,
|
||||
"binary_added": 0,
|
||||
"binary_deleted": 0,
|
||||
"first_commit": "2026-10-07T13:12:11Z",
|
||||
"last_commit": "2026-10-07T13:12:11Z"
|
||||
},
|
||||
{
|
||||
"login": "Webificio",
|
||||
"people_entry": false,
|
||||
"github_name": null,
|
||||
"prs": 1,
|
||||
"commits": 1,
|
||||
"lines_added": 232,
|
||||
"lines_deleted": 2,
|
||||
"binary_added": 0,
|
||||
"binary_deleted": 0,
|
||||
"first_commit": "2026-10-07T13:12:44Z",
|
||||
"last_commit": "2026-10-07T13:12:44Z"
|
||||
},
|
||||
{
|
||||
"login": "mvanhorn",
|
||||
"people_entry": false,
|
||||
"github_name": null,
|
||||
"prs": 4,
|
||||
"commits": 4,
|
||||
"lines_added": 2710,
|
||||
"lines_deleted": 168,
|
||||
"binary_added": 0,
|
||||
"binary_deleted": 0,
|
||||
"first_commit": "2026-10-07T20:09:46Z",
|
||||
"last_commit": "2026-10-07T21:12:52Z"
|
||||
},
|
||||
{
|
||||
"login": "gangldiego",
|
||||
"people_entry": false,
|
||||
"github_name": null,
|
||||
"prs": 1,
|
||||
"commits": 1,
|
||||
"lines_added": 2592,
|
||||
"lines_deleted": 10,
|
||||
"binary_added": 0,
|
||||
"binary_deleted": 0,
|
||||
"first_commit": "2026-10-07T20:11:38Z",
|
||||
"last_commit": "2026-10-07T20:11:38Z"
|
||||
},
|
||||
{
|
||||
"login": "kijoong-kim",
|
||||
"people_entry": false,
|
||||
"github_name": null,
|
||||
"prs": 1,
|
||||
"commits": 1,
|
||||
"lines_added": 1337,
|
||||
"lines_deleted": 539,
|
||||
"binary_added": 0,
|
||||
"binary_deleted": 0,
|
||||
"first_commit": "2026-10-07T20:32:47Z",
|
||||
"last_commit": "2026-10-07T20:32:47Z"
|
||||
},
|
||||
{
|
||||
"login": "Cyanoxide",
|
||||
"people_entry": false,
|
||||
"github_name": null,
|
||||
"prs": 1,
|
||||
"commits": 1,
|
||||
"lines_added": 9,
|
||||
"lines_deleted": 0,
|
||||
"binary_added": 0,
|
||||
"binary_deleted": 0,
|
||||
"first_commit": "2026-10-07T20:34:38Z",
|
||||
"last_commit": "2026-10-07T20:34:38Z"
|
||||
},
|
||||
{
|
||||
"login": "tanish2k09",
|
||||
"people_entry": false,
|
||||
"github_name": null,
|
||||
"prs": 10,
|
||||
"commits": 10,
|
||||
"lines_added": 389,
|
||||
"lines_deleted": 94,
|
||||
"binary_added": 0,
|
||||
"binary_deleted": 0,
|
||||
"first_commit": "2026-10-07T20:39:39Z",
|
||||
"last_commit": "2026-10-07T23:57:32Z"
|
||||
},
|
||||
{
|
||||
"login": "jerrykimo",
|
||||
"people_entry": false,
|
||||
"github_name": null,
|
||||
"prs": 1,
|
||||
"commits": 1,
|
||||
"lines_added": 442,
|
||||
"lines_deleted": 6,
|
||||
"binary_added": 0,
|
||||
"binary_deleted": 0,
|
||||
"first_commit": "2026-10-07T20:57:21Z",
|
||||
"last_commit": "2026-10-07T20:57:21Z"
|
||||
},
|
||||
{
|
||||
"login": "bfenty",
|
||||
"people_entry": false,
|
||||
"github_name": null,
|
||||
"prs": 10,
|
||||
"commits": 10,
|
||||
"lines_added": 490,
|
||||
"lines_deleted": 21,
|
||||
"binary_added": 0,
|
||||
"binary_deleted": 0,
|
||||
"first_commit": "2026-10-07T21:45:54Z",
|
||||
"last_commit": "2026-10-08T01:07:50Z"
|
||||
},
|
||||
{
|
||||
"login": "Luna161",
|
||||
"people_entry": false,
|
||||
"github_name": null,
|
||||
"prs": 4,
|
||||
"commits": 4,
|
||||
"lines_added": 89,
|
||||
"lines_deleted": 15,
|
||||
"binary_added": 0,
|
||||
"binary_deleted": 0,
|
||||
"first_commit": "2026-10-07T22:00:59Z",
|
||||
"last_commit": "2026-10-08T01:04:05Z"
|
||||
},
|
||||
{
|
||||
"login": "abc2cb",
|
||||
"people_entry": false,
|
||||
"github_name": null,
|
||||
"prs": 1,
|
||||
"commits": 1,
|
||||
"lines_added": 1197,
|
||||
"lines_deleted": 27,
|
||||
"binary_added": 0,
|
||||
"binary_deleted": 0,
|
||||
"first_commit": "2026-10-07T22:40:24Z",
|
||||
"last_commit": "2026-10-07T22:40:24Z"
|
||||
},
|
||||
{
|
||||
"login": "remidesbois1",
|
||||
"people_entry": false,
|
||||
"github_name": null,
|
||||
"prs": 1,
|
||||
"commits": 1,
|
||||
"lines_added": 1894,
|
||||
"lines_deleted": 400,
|
||||
"binary_added": 0,
|
||||
"binary_deleted": 0,
|
||||
"first_commit": "2026-10-07T23:05:15Z",
|
||||
"last_commit": "2026-10-07T23:05:15Z"
|
||||
},
|
||||
{
|
||||
"login": "giallorosso84",
|
||||
"people_entry": false,
|
||||
"github_name": null,
|
||||
"prs": 1,
|
||||
"commits": 1,
|
||||
"lines_added": 2188,
|
||||
"lines_deleted": 6,
|
||||
"binary_added": 0,
|
||||
"binary_deleted": 0,
|
||||
"first_commit": "2026-10-07T23:13:01Z",
|
||||
"last_commit": "2026-10-07T23:13:01Z"
|
||||
},
|
||||
{
|
||||
"login": "louwers",
|
||||
"people_entry": false,
|
||||
"github_name": null,
|
||||
"prs": 1,
|
||||
"commits": 1,
|
||||
"lines_added": 2528,
|
||||
"lines_deleted": 21,
|
||||
"binary_added": 0,
|
||||
"binary_deleted": 0,
|
||||
"first_commit": "2026-10-07T23:42:45Z",
|
||||
"last_commit": "2026-10-07T23:42:45Z"
|
||||
},
|
||||
{
|
||||
"login": "simonwjackson",
|
||||
"people_entry": false,
|
||||
"github_name": null,
|
||||
"prs": 1,
|
||||
"commits": 1,
|
||||
"lines_added": 3,
|
||||
"lines_deleted": 2,
|
||||
"binary_added": 0,
|
||||
"binary_deleted": 0,
|
||||
"first_commit": "2026-10-08T00:55:27Z",
|
||||
"last_commit": "2026-10-08T00:55:27Z"
|
||||
},
|
||||
{
|
||||
"login": "ajsongpilot",
|
||||
"people_entry": false,
|
||||
"github_name": null,
|
||||
"prs": 1,
|
||||
"commits": 1,
|
||||
"lines_added": 42,
|
||||
"lines_deleted": 16,
|
||||
"binary_added": 0,
|
||||
"binary_deleted": 0,
|
||||
"first_commit": "2026-10-08T01:09:04Z",
|
||||
"last_commit": "2026-10-08T01:09:04Z"
|
||||
}
|
||||
],
|
||||
"models": [
|
||||
{
|
||||
"id": "anthropic/claude-opus/5.5",
|
||||
"company": "Anthropic",
|
||||
"model": "Claude Opus",
|
||||
"version": "5.5",
|
||||
"commits": 228,
|
||||
"lines_added": 153184,
|
||||
"lines_deleted": 22216
|
||||
},
|
||||
{
|
||||
"id": "anthropic/claude-opus/4.8",
|
||||
"company": "Anthropic",
|
||||
"model": "Claude Opus",
|
||||
"version": "4.8",
|
||||
"commits": 45,
|
||||
"lines_added": 3896,
|
||||
"lines_deleted": 278
|
||||
},
|
||||
{
|
||||
"id": "github/copilot",
|
||||
"company": "GitHub",
|
||||
"model": "Copilot",
|
||||
"version": "",
|
||||
"commits": 6,
|
||||
"lines_added": 1094,
|
||||
"lines_deleted": 61
|
||||
},
|
||||
{
|
||||
"id": "anthropic/claude-mythos/5.1",
|
||||
"company": "Anthropic",
|
||||
"model": "Claude Mythos",
|
||||
"version": "5.1",
|
||||
"commits": 2,
|
||||
"lines_added": 6195,
|
||||
"lines_deleted": 100
|
||||
},
|
||||
{
|
||||
"id": "anthropic/claude-sonnet/5.5",
|
||||
"company": "Anthropic",
|
||||
"model": "Claude Sonnet",
|
||||
"version": "5.5",
|
||||
"commits": 2,
|
||||
"lines_added": 4161,
|
||||
"lines_deleted": 1171
|
||||
},
|
||||
{
|
||||
"id": "alibaba/qwen-flash/3.8",
|
||||
"company": "Alibaba",
|
||||
"model": "Qwen Flash",
|
||||
"version": "3.8",
|
||||
"commits": 1,
|
||||
"lines_added": 25,
|
||||
"lines_deleted": 5
|
||||
},
|
||||
{
|
||||
"id": "anthropic/claude-haiku/4.5",
|
||||
"company": "Anthropic",
|
||||
"model": "Claude Haiku",
|
||||
"version": "4.5",
|
||||
"commits": 1,
|
||||
"lines_added": 134,
|
||||
"lines_deleted": 12
|
||||
},
|
||||
{
|
||||
"id": "cognition/devin",
|
||||
"company": "Cognition",
|
||||
"model": "Devin",
|
||||
"version": "",
|
||||
"commits": 1,
|
||||
"lines_added": 44,
|
||||
"lines_deleted": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
# Contributor names for the About window (craftrules standards/contributors.md).
|
||||
#
|
||||
# Everyone who contributes is credited by GitHub username automatically. Anything more is up to
|
||||
# you: add YOUR OWN entry below, in your own PR (commit it yourself). Never add someone else; a
|
||||
# maintainer may add a person only when that person asked, recording where in consent_source.
|
||||
#
|
||||
# Easiest: python3 ../../craftrules/scripts/contributors.py --add-me . \
|
||||
# [--real-name "Ada Lovelace"] [--display-name "Ada"] [--sync-github-name]
|
||||
#
|
||||
# Or copy this block, replacing your-github-username (every field is optional):
|
||||
#
|
||||
# [people.your-github-username]
|
||||
# real_name = "Your Name" # shown when the viewer picks "Real name"
|
||||
# display_name = "Nickname" # shown when the viewer picks "Display name"
|
||||
# sync_github_name = true # or: use the name on your public GitHub profile as display name
|
||||
#
|
||||
# To remove your names, delete your entry (or set fields empty) in a PR. The next
|
||||
# contributors.py run, and the next build, drop them.
|
||||
|
||||
[people.echelon]
|
||||
real_name = "Brandon Thomas"
|
||||
display_name = "Brandon Thomas"
|
||||
sync_github_name = false
|
||||
|
|
@ -45,3 +45,7 @@ photocraft-codecs = { workspace = true }
|
|||
photocraft-testkit = { workspace = true }
|
||||
# Only for examples/perf_scenarios.rs (a 500-brush .abr for the #210 import row).
|
||||
photocraft-psd = { workspace = true }
|
||||
|
||||
[build-dependencies]
|
||||
serde_json = { workspace = true }
|
||||
toml = "1"
|
||||
|
|
|
|||
|
|
@ -0,0 +1,102 @@
|
|||
//! Bake the contributor credits into the binary as static Rust tables (craftrules
|
||||
//! standards/contributors.md). Nothing is read at run time.
|
||||
//!
|
||||
//! - contributors/contributors.json: commit stats per GitHub username, generated by craftrules
|
||||
//! scripts/contributors.py, which also marks whose people.toml entry it verified.
|
||||
//! - contributors/people.toml: the names people chose for themselves. A name is used only when the
|
||||
//! JSON says the entry was verified (`people_entry`).
|
||||
//!
|
||||
//! A missing or malformed file gives empty tables (or no names) and a warning.
|
||||
|
||||
use std::fmt::Write as _;
|
||||
|
||||
use serde_json::Value;
|
||||
|
||||
fn main() {
|
||||
let dir = std::path::Path::new(env!("CARGO_MANIFEST_DIR")).join("../../contributors");
|
||||
let json = read(&dir.join("contributors.json"), "the About window shows no contributors", |t| serde_json::from_str::<Value>(t).map_err(|e| e.to_string()))
|
||||
.unwrap_or(Value::Null);
|
||||
let people =
|
||||
read(&dir.join("people.toml"), "contributors are shown by username only", |t| t.parse::<toml::Table>().map_err(|e| e.to_string())).unwrap_or_default();
|
||||
let out = std::path::PathBuf::from(std::env::var_os("OUT_DIR").unwrap_or_default()).join("credits.rs");
|
||||
if let Err(e) = std::fs::write(&out, generate(&json, &people)) {
|
||||
println!("cargo::warning=writing {}: {e}", out.display());
|
||||
}
|
||||
}
|
||||
|
||||
fn read<T>(path: &std::path::Path, fallback: &str, parse: impl Fn(&str) -> Result<T, String>) -> Option<T> {
|
||||
println!("cargo::rerun-if-changed={}", path.display());
|
||||
let r = std::fs::read_to_string(path).map_err(|e| e.to_string()).and_then(|t| parse(&t));
|
||||
if let Err(e) = &r {
|
||||
println!("cargo::warning={}: {e}; {fallback}", path.display());
|
||||
}
|
||||
r.ok()
|
||||
}
|
||||
|
||||
/// A non-empty string field of someone's people.toml entry, as a Rust `Option<&str>` literal.
|
||||
fn name(v: Option<&str>) -> String {
|
||||
match v.map(str::trim).filter(|s| !s.is_empty()) {
|
||||
Some(x) => format!("Some({x:?})"),
|
||||
None => "None".into(),
|
||||
}
|
||||
}
|
||||
|
||||
fn s(v: &Value, k: &str) -> String {
|
||||
format!("{:?}", v.get(k).and_then(Value::as_str).unwrap_or(""))
|
||||
}
|
||||
|
||||
fn n(v: &Value, k: &str) -> u64 {
|
||||
v.get(k).and_then(Value::as_u64).unwrap_or(0)
|
||||
}
|
||||
|
||||
fn rows(json: &Value, k: &str) -> Vec<Value> {
|
||||
json.get(k).and_then(Value::as_array).cloned().unwrap_or_default()
|
||||
}
|
||||
|
||||
fn generate(json: &Value, people: &toml::Table) -> String {
|
||||
let mut o = String::new();
|
||||
let _ = writeln!(o, "pub static TOTAL_COMMITS: u64 = {};", n(json, "commits"));
|
||||
let _ = writeln!(o, "pub static CONTRIBUTORS: &[Contributor] = &[");
|
||||
for c in rows(json, "contributors") {
|
||||
let login = c.get("login").and_then(Value::as_str).unwrap_or("");
|
||||
if login.is_empty() {
|
||||
continue;
|
||||
}
|
||||
// Names only from a verified, self-chosen people.toml entry.
|
||||
let entry = people.get("people").and_then(|p| p.get(login)).filter(|_| c.get("people_entry").and_then(Value::as_bool) == Some(true));
|
||||
let field = |k: &str| entry.and_then(|e| e.get(k)).and_then(toml::Value::as_str);
|
||||
let synced = entry.and_then(|e| e.get("sync_github_name")).and_then(toml::Value::as_bool) == Some(true);
|
||||
let display =
|
||||
field("display_name").filter(|s| !s.trim().is_empty()).or_else(|| if synced { c.get("github_name").and_then(Value::as_str) } else { None });
|
||||
let _ = writeln!(
|
||||
o,
|
||||
" Contributor {{ login: {login:?}, display_name: {}, real_name: {}, prs: {}, commits: {}, lines_added: {}, lines_deleted: {}, binary_added: {}, binary_deleted: {}, first_commit: {}, last_commit: {} }},",
|
||||
name(display),
|
||||
name(field("real_name")),
|
||||
n(&c, "prs"),
|
||||
n(&c, "commits"),
|
||||
n(&c, "lines_added"),
|
||||
n(&c, "lines_deleted"),
|
||||
n(&c, "binary_added"),
|
||||
n(&c, "binary_deleted"),
|
||||
s(&c, "first_commit"),
|
||||
s(&c, "last_commit"),
|
||||
);
|
||||
}
|
||||
let _ = writeln!(o, "];");
|
||||
let _ = writeln!(o, "pub static MODELS: &[Model] = &[");
|
||||
for m in rows(json, "models") {
|
||||
let _ = writeln!(
|
||||
o,
|
||||
" Model {{ company: {}, model: {}, version: {}, commits: {}, lines_added: {}, lines_deleted: {} }},",
|
||||
s(&m, "company"),
|
||||
s(&m, "model"),
|
||||
s(&m, "version"),
|
||||
n(&m, "commits"),
|
||||
n(&m, "lines_added"),
|
||||
n(&m, "lines_deleted"),
|
||||
);
|
||||
}
|
||||
let _ = writeln!(o, "];");
|
||||
o
|
||||
}
|
||||
|
|
@ -0,0 +1,398 @@
|
|||
//! The About window's credits: every contributor (GitHub login always; display and real names only
|
||||
//! with recorded consent) and the AI models that helped. The tables are baked into the binary by
|
||||
//! build.rs from contributors/contributors.json (craftrules standards/contributors.md); nothing is
|
||||
//! read at run time. UI strings go through `tl!` (column abbreviations like `+LOC` stay as they are).
|
||||
|
||||
use std::cmp::Ordering;
|
||||
|
||||
use egui::RichText;
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
pub struct Contributor {
|
||||
pub login: &'static str,
|
||||
pub display_name: Option<&'static str>,
|
||||
pub real_name: Option<&'static str>,
|
||||
pub prs: u64,
|
||||
pub commits: u64,
|
||||
pub lines_added: u64,
|
||||
pub lines_deleted: u64,
|
||||
pub binary_added: u64,
|
||||
pub binary_deleted: u64,
|
||||
/// ISO 8601 UTC; empty for someone credited only through a merged PR.
|
||||
pub first_commit: &'static str,
|
||||
pub last_commit: &'static str,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
pub struct Model {
|
||||
pub company: &'static str,
|
||||
pub model: &'static str,
|
||||
pub version: &'static str,
|
||||
pub commits: u64,
|
||||
pub lines_added: u64,
|
||||
pub lines_deleted: u64,
|
||||
}
|
||||
|
||||
include!(concat!(env!("OUT_DIR"), "/credits.rs"));
|
||||
|
||||
/// Which name to show. Display and real names fall back to the `@username` when not given.
|
||||
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
|
||||
pub enum NameMode {
|
||||
#[default]
|
||||
Username,
|
||||
DisplayName,
|
||||
RealName,
|
||||
}
|
||||
|
||||
impl NameMode {
|
||||
pub const ALL: [NameMode; 3] = [NameMode::Username, NameMode::DisplayName, NameMode::RealName];
|
||||
|
||||
pub fn label(self) -> &'static str {
|
||||
match self {
|
||||
NameMode::Username => tl!("Username"),
|
||||
NameMode::DisplayName => tl!("Display name"),
|
||||
NameMode::RealName => tl!("Real name"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
|
||||
pub enum SortKey {
|
||||
Name,
|
||||
Prs,
|
||||
Commits,
|
||||
LinesAdded,
|
||||
LinesDeleted,
|
||||
LinesDelta,
|
||||
BinaryAdded,
|
||||
BinaryDeleted,
|
||||
#[default]
|
||||
FirstCommit,
|
||||
LastCommit,
|
||||
}
|
||||
|
||||
impl SortKey {
|
||||
pub const ALL: [SortKey; 10] = [
|
||||
SortKey::Name,
|
||||
SortKey::Prs,
|
||||
SortKey::Commits,
|
||||
SortKey::LinesAdded,
|
||||
SortKey::LinesDeleted,
|
||||
SortKey::LinesDelta,
|
||||
SortKey::BinaryAdded,
|
||||
SortKey::BinaryDeleted,
|
||||
SortKey::FirstCommit,
|
||||
SortKey::LastCommit,
|
||||
];
|
||||
|
||||
/// Menu label and table header, in the UI language.
|
||||
pub fn label(self) -> (&'static str, &'static str) {
|
||||
match self {
|
||||
SortKey::Name => (tl!("Name (A–Z)"), tl!("Name")),
|
||||
SortKey::Prs => (tl!("Merged PRs"), "PRs"),
|
||||
SortKey::Commits => (tl!("Commits"), tl!("Commits")),
|
||||
SortKey::LinesAdded => (tl!("Lines added"), "+LOC"),
|
||||
SortKey::LinesDeleted => (tl!("Lines deleted"), "−LOC"),
|
||||
SortKey::LinesDelta => (tl!("Line delta"), "ΔLOC"),
|
||||
SortKey::BinaryAdded => (tl!("Binary assets added"), "+Bin"),
|
||||
SortKey::BinaryDeleted => (tl!("Binary assets removed"), "−Bin"),
|
||||
SortKey::FirstCommit => (tl!("First commit"), tl!("First")),
|
||||
SortKey::LastCommit => (tl!("Last commit"), tl!("Last")),
|
||||
}
|
||||
}
|
||||
|
||||
/// Names and dates read naturally oldest/A first; counts read biggest first.
|
||||
pub fn default_ascending(self) -> bool {
|
||||
matches!(self, SortKey::Name | SortKey::FirstCommit | SortKey::LastCommit)
|
||||
}
|
||||
}
|
||||
|
||||
impl Contributor {
|
||||
pub fn name(&self, mode: NameMode) -> String {
|
||||
let chosen = match mode {
|
||||
NameMode::Username => None,
|
||||
NameMode::DisplayName => self.display_name,
|
||||
NameMode::RealName => self.real_name,
|
||||
};
|
||||
chosen.map_or_else(|| format!("@{}", self.login), str::to_string)
|
||||
}
|
||||
|
||||
pub fn lines_delta(&self) -> i128 {
|
||||
i128::from(self.lines_added) - i128::from(self.lines_deleted)
|
||||
}
|
||||
|
||||
/// One line with everything we know, for tooltips.
|
||||
pub fn summary(&self) -> String {
|
||||
crate::i18n::fmt(
|
||||
tl!("@{login}: {prs} PRs, {commits} commits, +{added} / −{deleted} lines (Δ {delta}), +{binAdded} / −{binDeleted} binary assets, {first} – {last}"),
|
||||
&[
|
||||
("login", self.login),
|
||||
("prs", &group(self.prs)),
|
||||
("commits", &group(self.commits)),
|
||||
("added", &group(self.lines_added)),
|
||||
("deleted", &group(self.lines_deleted)),
|
||||
("delta", &signed(self.lines_delta())),
|
||||
("binAdded", &group(self.binary_added)),
|
||||
("binDeleted", &group(self.binary_deleted)),
|
||||
("first", day(self.first_commit)),
|
||||
("last", day(self.last_commit)),
|
||||
],
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/// Alphabetical key: case-insensitive, ignoring the `@` of usernames.
|
||||
fn name_key(name: &str) -> String {
|
||||
name.trim_start_matches('@').to_lowercase()
|
||||
}
|
||||
|
||||
fn compare(a: &Contributor, b: &Contributor, mode: NameMode, key: SortKey) -> Ordering {
|
||||
match key {
|
||||
SortKey::Name => name_key(&a.name(mode)).cmp(&name_key(&b.name(mode))),
|
||||
SortKey::Prs => a.prs.cmp(&b.prs),
|
||||
SortKey::Commits => a.commits.cmp(&b.commits),
|
||||
SortKey::LinesAdded => a.lines_added.cmp(&b.lines_added),
|
||||
SortKey::LinesDeleted => a.lines_deleted.cmp(&b.lines_deleted),
|
||||
SortKey::LinesDelta => a.lines_delta().cmp(&b.lines_delta()),
|
||||
SortKey::BinaryAdded => a.binary_added.cmp(&b.binary_added),
|
||||
SortKey::BinaryDeleted => a.binary_deleted.cmp(&b.binary_deleted),
|
||||
// A PR-only contributor (no commit date) sorts after everyone with a date.
|
||||
SortKey::FirstCommit => dated(a.first_commit).cmp(&dated(b.first_commit)),
|
||||
SortKey::LastCommit => dated(a.last_commit).cmp(&dated(b.last_commit)),
|
||||
}
|
||||
}
|
||||
|
||||
fn dated(d: &str) -> (bool, &str) {
|
||||
(d.is_empty(), d)
|
||||
}
|
||||
|
||||
/// Contributors in display order. Ties fall back to the name (A–Z) so the order is stable.
|
||||
pub fn sorted(list: &[Contributor], mode: NameMode, key: SortKey, ascending: bool) -> Vec<&Contributor> {
|
||||
let mut v: Vec<&Contributor> = list.iter().collect();
|
||||
v.sort_by(|a, b| {
|
||||
let o = compare(a, b, mode, key);
|
||||
let o = if ascending { o } else { o.reverse() };
|
||||
o.then_with(|| compare(a, b, mode, SortKey::Name)).then_with(|| a.login.cmp(b.login))
|
||||
});
|
||||
v
|
||||
}
|
||||
|
||||
fn group(n: u64) -> String {
|
||||
let s = n.to_string();
|
||||
let mut out = String::with_capacity(s.len() + s.len() / 3);
|
||||
for (i, ch) in s.chars().enumerate() {
|
||||
if i > 0 && (s.len() - i).is_multiple_of(3) {
|
||||
out.push(',');
|
||||
}
|
||||
out.push(ch);
|
||||
}
|
||||
out
|
||||
}
|
||||
|
||||
fn signed(n: i128) -> String {
|
||||
let g = group(u64::try_from(n.unsigned_abs()).unwrap_or(u64::MAX));
|
||||
if n < 0 { format!("−{g}") } else { format!("+{g}") }
|
||||
}
|
||||
|
||||
fn day(iso: &str) -> &str {
|
||||
if iso.is_empty() { "—" } else { iso.get(..10).unwrap_or(iso) }
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
struct View {
|
||||
names: NameMode,
|
||||
key: SortKey,
|
||||
ascending: bool,
|
||||
table: bool,
|
||||
}
|
||||
|
||||
impl Default for View {
|
||||
fn default() -> Self {
|
||||
View { names: NameMode::Username, key: SortKey::FirstCommit, ascending: true, table: false }
|
||||
}
|
||||
}
|
||||
|
||||
/// About ▸ Contributors: a name toggle, a sort, and the list as a grab bag or a table.
|
||||
pub fn contributors_ui(ui: &mut egui::Ui) {
|
||||
let id = egui::Id::new("credits_view");
|
||||
let mut v = ui.data_mut(|d| d.get_temp::<View>(id)).unwrap_or_default();
|
||||
ui.horizontal_wrapped(|ui| {
|
||||
ui.label(tl!("Show"));
|
||||
for m in NameMode::ALL {
|
||||
if ui.selectable_label(v.names == m, m.label()).clicked() {
|
||||
v.names = m;
|
||||
}
|
||||
}
|
||||
ui.separator();
|
||||
ui.label(tl!("Sort"));
|
||||
egui::ComboBox::from_id_salt("credits_sort").selected_text(v.key.label().0).show_ui(ui, |ui| {
|
||||
for k in SortKey::ALL {
|
||||
if ui.selectable_label(v.key == k, k.label().0).clicked() {
|
||||
v.key = k;
|
||||
v.ascending = k.default_ascending();
|
||||
}
|
||||
}
|
||||
});
|
||||
if ui.button(if v.ascending { "▲" } else { "▼" }).on_hover_text(tl!("Reverse the order")).clicked() {
|
||||
v.ascending = !v.ascending;
|
||||
}
|
||||
ui.separator();
|
||||
if ui.selectable_label(!v.table, tl!("Grab bag")).clicked() {
|
||||
v.table = false;
|
||||
}
|
||||
if ui.selectable_label(v.table, tl!("Table")).clicked() {
|
||||
v.table = true;
|
||||
}
|
||||
});
|
||||
let list = sorted(CONTRIBUTORS, v.names, v.key, v.ascending);
|
||||
let counts = crate::i18n::fmt(
|
||||
tl!("Contributors: {contributors} · Commits: {commits}"),
|
||||
&[("contributors", &group(list.len() as u64)), ("commits", &group(TOTAL_COMMITS))],
|
||||
);
|
||||
ui.label(RichText::new(counts).small().weak());
|
||||
ui.separator();
|
||||
egui::ScrollArea::both().auto_shrink([false, false]).max_height(340.0).show(ui, |ui| {
|
||||
if list.is_empty() {
|
||||
ui.label(tl!("No contributor data was built into this copy."));
|
||||
} else if v.table {
|
||||
table(ui, &list, &mut v);
|
||||
} else {
|
||||
ui.horizontal_wrapped(|ui| {
|
||||
for (i, c) in list.iter().enumerate() {
|
||||
if i > 0 {
|
||||
ui.label(RichText::new("·").weak());
|
||||
}
|
||||
ui.hyperlink_to(c.name(v.names), format!("https://github.com/{}", c.login)).on_hover_text(c.summary());
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
ui.data_mut(|d| d.insert_temp(id, v));
|
||||
}
|
||||
|
||||
fn table(ui: &mut egui::Ui, list: &[&Contributor], v: &mut View) {
|
||||
egui::Grid::new("credits_table").striped(true).num_columns(SortKey::ALL.len()).show(ui, |ui| {
|
||||
for k in SortKey::ALL {
|
||||
let arrow = if v.key == k { if v.ascending { " ▲" } else { " ▼" } } else { "" };
|
||||
if ui.button(RichText::new(format!("{}{arrow}", k.label().1)).strong()).on_hover_text(k.label().0).clicked() {
|
||||
if v.key == k {
|
||||
v.ascending = !v.ascending;
|
||||
} else {
|
||||
v.key = k;
|
||||
v.ascending = k.default_ascending();
|
||||
}
|
||||
}
|
||||
}
|
||||
ui.end_row();
|
||||
for c in list {
|
||||
ui.hyperlink_to(c.name(v.names), format!("https://github.com/{}", c.login)).on_hover_text(c.summary());
|
||||
ui.label(group(c.prs));
|
||||
ui.label(group(c.commits));
|
||||
ui.label(group(c.lines_added));
|
||||
ui.label(group(c.lines_deleted));
|
||||
ui.label(signed(c.lines_delta()));
|
||||
ui.label(group(c.binary_added));
|
||||
ui.label(group(c.binary_deleted));
|
||||
ui.label(day(c.first_commit));
|
||||
ui.label(day(c.last_commit));
|
||||
ui.end_row();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/// About ▸ Models: AI models credited in Co-Authored-By trailers.
|
||||
pub fn models_ui(ui: &mut egui::Ui) {
|
||||
if MODELS.is_empty() {
|
||||
ui.label(tl!("No model credits were built into this copy."));
|
||||
return;
|
||||
}
|
||||
let assisted: u64 = MODELS.iter().map(|m| m.commits).max().unwrap_or(0).max(1);
|
||||
egui::ScrollArea::both().auto_shrink([false, false]).max_height(340.0).show(ui, |ui| {
|
||||
egui::Grid::new("credits_models").striped(true).num_columns(6).show(ui, |ui| {
|
||||
for h in [tl!("Company"), tl!("Model"), tl!("Version"), tl!("Commits"), tl!("% of all commits"), tl!("Lines +/−")] {
|
||||
ui.label(RichText::new(h).strong());
|
||||
}
|
||||
ui.end_row();
|
||||
for m in MODELS {
|
||||
ui.label(m.company);
|
||||
ui.label(m.model);
|
||||
ui.label(m.version);
|
||||
ui.label(group(m.commits));
|
||||
ui.label(format!("{:.0}%", 100.0 * m.commits as f64 / TOTAL_COMMITS.max(assisted) as f64));
|
||||
ui.label(format!("+{} / −{}", group(m.lines_added), group(m.lines_deleted)));
|
||||
ui.end_row();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
fn c(login: &'static str, display: Option<&'static str>, real: Option<&'static str>, added: u64, deleted: u64, first: &'static str) -> Contributor {
|
||||
Contributor {
|
||||
login,
|
||||
display_name: display,
|
||||
real_name: real,
|
||||
prs: 0,
|
||||
commits: 1,
|
||||
lines_added: added,
|
||||
lines_deleted: deleted,
|
||||
binary_added: 0,
|
||||
binary_deleted: 0,
|
||||
first_commit: first,
|
||||
last_commit: first,
|
||||
}
|
||||
}
|
||||
|
||||
fn people() -> [Contributor; 4] {
|
||||
[
|
||||
c("zed", None, None, 5, 50, "2026-01-02T00:00:00Z"),
|
||||
c("Bob", Some("Ann"), None, 10, 0, "2026-01-01T00:00:00Z"),
|
||||
c("alice", None, None, 7, 1, ""),
|
||||
c("carol", None, Some("Dana"), 1, 0, "2026-01-03T00:00:00Z"),
|
||||
]
|
||||
}
|
||||
|
||||
fn logins(v: &[&Contributor]) -> Vec<&'static str> {
|
||||
v.iter().map(|c| c.login).collect()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn names_fall_back_to_the_username() {
|
||||
let p = c("bob", Some("Bobby"), None, 0, 0, "");
|
||||
assert_eq!(p.name(NameMode::Username), "@bob");
|
||||
assert_eq!(p.name(NameMode::DisplayName), "Bobby");
|
||||
assert_eq!(p.name(NameMode::RealName), "@bob");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn alphabetical_ignores_at_and_case() {
|
||||
let all = people();
|
||||
let v = sorted(&all, NameMode::Username, SortKey::Name, true);
|
||||
assert_eq!(logins(&v), ["alice", "Bob", "carol", "zed"]);
|
||||
let v = sorted(&all, NameMode::DisplayName, SortKey::Name, true);
|
||||
assert_eq!(logins(&v), ["alice", "Bob", "carol", "zed"]); // "Ann" sorts with the @usernames
|
||||
let v = sorted(&all, NameMode::RealName, SortKey::Name, false);
|
||||
assert_eq!(logins(&v), ["zed", "carol", "Bob", "alice"]); // "Dana" between bob and zed
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn delta_and_dates() {
|
||||
let all = people();
|
||||
let v = sorted(&all, NameMode::Username, SortKey::LinesDelta, false);
|
||||
assert_eq!(logins(&v), ["Bob", "alice", "carol", "zed"]);
|
||||
let v = sorted(&all, NameMode::Username, SortKey::FirstCommit, true);
|
||||
assert_eq!(logins(&v), ["Bob", "zed", "carol", "alice"]); // undated last
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn formatting() {
|
||||
assert_eq!(group(1234567), "1,234,567");
|
||||
assert_eq!(group(12), "12");
|
||||
assert_eq!(signed(-1000), "−1,000");
|
||||
assert_eq!(day("2026-10-07T18:45:23Z"), "2026-10-07");
|
||||
assert_eq!(day(""), "—");
|
||||
}
|
||||
}
|
||||
|
|
@ -99,8 +99,15 @@ pub fn show(app: &mut PhotocraftApp, ctx: &egui::Context) {
|
|||
if d.kind == DialogKind::NewDocument {
|
||||
ui.set_min_width(800.0);
|
||||
}
|
||||
// The About window: room for the contributor table, the same width on every tab.
|
||||
let about_tabs = d.kind == DialogKind::About && d.fields.get("systemInfo").and_then(Value::as_bool) != Some(true);
|
||||
if about_tabs {
|
||||
ui.set_min_width(700.0);
|
||||
}
|
||||
ui.set_max_width(wide.unwrap_or(if d.kind == DialogKind::NewDocument {
|
||||
800.0
|
||||
} else if about_tabs {
|
||||
700.0
|
||||
} else if d.kind == DialogKind::LayerStyle || d.fields.contains_key("__export") || crate::color_picker_ui::owns(&d.fields) {
|
||||
600.0
|
||||
} else {
|
||||
|
|
@ -129,6 +136,25 @@ pub fn show(app: &mut PhotocraftApp, ctx: &egui::Context) {
|
|||
}
|
||||
}
|
||||
DialogKind::About => {
|
||||
// Tabs About · Contributors · Models (craftrules standards/contributors.md). The
|
||||
// tab is a dialog field, so automation can switch it with `ui.dialog.set`.
|
||||
let tab = about_tab(&fields);
|
||||
let mut chosen = tab;
|
||||
ui.horizontal(|ui| {
|
||||
for (key, label) in [("about", tl!("About")), ("contributors", tl!("Contributors")), ("models", tl!("Models"))] {
|
||||
if crate::widgets::pill_tab(ui, label, tab == key).clicked() {
|
||||
chosen = key;
|
||||
}
|
||||
}
|
||||
});
|
||||
if chosen != tab {
|
||||
fields.insert("tab".into(), json!(chosen));
|
||||
}
|
||||
ui.add_space(8.0);
|
||||
match chosen {
|
||||
"contributors" => crate::credits::contributors_ui(ui),
|
||||
"models" => crate::credits::models_ui(ui),
|
||||
_ => {
|
||||
ui.label(tl!("PhotoCraft — an open-source, native image editor written in Rust."));
|
||||
ui.label(crate::i18n::fmt(tl!("Version {version}"), &[("version", &photocraft_engine::build_info::long_version())]));
|
||||
ui.add_space(12.0);
|
||||
|
|
@ -140,6 +166,8 @@ pub fn show(app: &mut PhotocraftApp, ctx: &egui::Context) {
|
|||
ui.add_space(10.0);
|
||||
ui.weak("egui · wgpu · photocraft-engine");
|
||||
}
|
||||
}
|
||||
}
|
||||
DialogKind::Command if crate::fill_ui::owns(&fields) => crate::fill_ui::body(app, ui, &mut fields),
|
||||
DialogKind::Command if crate::rasterize_prompt::owns(&fields) => crate::rasterize_prompt::body(ui, &fields),
|
||||
DialogKind::Command if crate::variables_ui::owns(&fields) => crate::variables_ui::body(app, ui, &mut fields),
|
||||
|
|
@ -239,6 +267,15 @@ pub fn show(app: &mut PhotocraftApp, ctx: &egui::Context) {
|
|||
ctx.data_mut(|m| m.insert_temp(egui::Id::new(RECTS), shown));
|
||||
}
|
||||
|
||||
/// The About window's tabs, as stored in its `tab` field.
|
||||
pub const ABOUT_TABS: [&str; 3] = ["about", "contributors", "models"];
|
||||
|
||||
/// The About tab to show: the `tab` field when it names one, otherwise "about".
|
||||
fn about_tab(fields: &serde_json::Map<String, Value>) -> &'static str {
|
||||
let want = fields.get("tab").and_then(Value::as_str).unwrap_or("");
|
||||
ABOUT_TABS.iter().copied().find(|t| *t == want).unwrap_or("about")
|
||||
}
|
||||
|
||||
/// The dialog title as shown: [`title`] in the UI language.
|
||||
fn display_title(d: &Dialog) -> String {
|
||||
match d.kind {
|
||||
|
|
|
|||
|
|
@ -2093,3 +2093,36 @@ cameraRaw Color Barvy
|
|||
Magnetic Lasso Tool Nástroj magnetické laso
|
||||
Frequency Frekvence
|
||||
Use tablet pressure to change pen width Měnit šířku pera přítlakem tabletu
|
||||
|
||||
# About ▸ Contributors / Models (credits, craftrules standards/contributors.md)
|
||||
About O aplikaci
|
||||
Contributors Přispěvatelé
|
||||
Models Modely
|
||||
Sort Řadit
|
||||
Username Uživatelské jméno
|
||||
Display name Zobrazované jméno
|
||||
Real name Skutečné jméno
|
||||
Reverse the order Obrátit pořadí
|
||||
Grab bag Výčet
|
||||
Table Tabulka
|
||||
Name (A–Z) Jméno (A–Z)
|
||||
Merged PRs Sloučené PR
|
||||
Commits Commity
|
||||
Lines added Přidané řádky
|
||||
Lines deleted Smazané řádky
|
||||
Line delta Rozdíl řádků
|
||||
Binary assets added Přidané binární soubory
|
||||
Binary assets removed Odebrané binární soubory
|
||||
First commit První commit
|
||||
First První
|
||||
Last commit Poslední commit
|
||||
Last Poslední
|
||||
Contributors: {contributors} · Commits: {commits} Přispěvatelé: {contributors} · Commity: {commits}
|
||||
No contributor data was built into this copy. Tato kopie neobsahuje údaje o přispěvatelích.
|
||||
No model credits were built into this copy. Tato kopie neobsahuje údaje o modelech.
|
||||
Company Společnost
|
||||
Model Model
|
||||
Version Verze
|
||||
% of all commits % všech commitů
|
||||
Lines +/− Řádky +/−
|
||||
@{login}: {prs} PRs, {commits} commits, +{added} / −{deleted} lines (Δ {delta}), +{binAdded} / −{binDeleted} binary assets, {first} – {last} @{login}: PR: {prs}, commity: {commits}, řádky +{added} / −{deleted} (Δ {delta}), binární soubory +{binAdded} / −{binDeleted}, {first} – {last}
|
||||
|
|
|
|||
|
Can't render this file because it contains an unexpected character in line 6 and column 47.
|
|
|
@ -2135,3 +2135,34 @@
|
|||
Magnetic Lasso Tool Magnetisches-Lasso-Werkzeug
|
||||
Frequency Frequenz
|
||||
Use tablet pressure to change pen width Tablettdruck zum Ändern der Stiftbreite verwenden
|
||||
# About ▸ Contributors / Models (credits, craftrules standards/contributors.md)
|
||||
About Über
|
||||
Contributors Mitwirkende
|
||||
Models Modelle
|
||||
Sort Sortieren
|
||||
Username Benutzername
|
||||
Display name Anzeigename
|
||||
Real name Echter Name
|
||||
Reverse the order Reihenfolge umkehren
|
||||
Grab bag Wortwolke
|
||||
Table Tabelle
|
||||
Name (A–Z) Name (A–Z)
|
||||
Merged PRs Gemergte PRs
|
||||
Commits Commits
|
||||
Lines added Hinzugefügte Zeilen
|
||||
Lines deleted Gelöschte Zeilen
|
||||
Line delta Zeilensaldo
|
||||
Binary assets added Hinzugefügte Binärdateien
|
||||
Binary assets removed Entfernte Binärdateien
|
||||
First commit Erster Commit
|
||||
First Erster
|
||||
Last commit Letzter Commit
|
||||
Last Letzter
|
||||
Contributors: {contributors} · Commits: {commits} Mitwirkende: {contributors} · Commits: {commits}
|
||||
No contributor data was built into this copy. In diese Kopie wurden keine Mitwirkendendaten eingebaut.
|
||||
No model credits were built into this copy. In diese Kopie wurden keine Modellnennungen eingebaut.
|
||||
Company Firma
|
||||
Version Version
|
||||
% of all commits % aller Commits
|
||||
Lines +/− Zeilen +/−
|
||||
@{login}: {prs} PRs, {commits} commits, +{added} / −{deleted} lines (Δ {delta}), +{binAdded} / −{binDeleted} binary assets, {first} – {last} @{login}: {prs} PRs, {commits} Commits, +{added} / −{deleted} Zeilen (Δ {delta}), +{binAdded} / −{binDeleted} Binärdateien, {first} – {last}
|
||||
|
|
|
|||
|
Can't render this file because it contains an unexpected character in line 6 and column 47.
|
|
|
@ -2166,3 +2166,35 @@ cameraRaw Amount Cantidad
|
|||
Magnetic Lasso Tool Herramienta Lazo magnético
|
||||
Frequency Frecuencia
|
||||
Use tablet pressure to change pen width Usar la presión de la tableta para cambiar la anchura del lápiz
|
||||
|
||||
# About ▸ Contributors / Models (credits, craftrules standards/contributors.md)
|
||||
About Acerca de
|
||||
Contributors Colaboradores
|
||||
Models Modelos
|
||||
Sort Ordenar
|
||||
Username Nombre de usuario
|
||||
Display name Nombre visible
|
||||
Real name Nombre real
|
||||
Reverse the order Invertir el orden
|
||||
Grab bag Lista libre
|
||||
Table Tabla
|
||||
Name (A–Z) Nombre (A–Z)
|
||||
Merged PRs PR fusionadas
|
||||
Commits Commits
|
||||
Lines added Líneas añadidas
|
||||
Lines deleted Líneas eliminadas
|
||||
Line delta Balance de líneas
|
||||
Binary assets added Archivos binarios añadidos
|
||||
Binary assets removed Archivos binarios eliminados
|
||||
First commit Primer commit
|
||||
First Primero
|
||||
Last commit Último commit
|
||||
Last Último
|
||||
Contributors: {contributors} · Commits: {commits} Colaboradores: {contributors} · Commits: {commits}
|
||||
No contributor data was built into this copy. Esta copia no incluye datos de colaboradores.
|
||||
No model credits were built into this copy. Esta copia no incluye créditos de modelos.
|
||||
Company Empresa
|
||||
Version Versión
|
||||
% of all commits % de todos los commits
|
||||
Lines +/− Líneas +/−
|
||||
@{login}: {prs} PRs, {commits} commits, +{added} / −{deleted} lines (Δ {delta}), +{binAdded} / −{binDeleted} binary assets, {first} – {last} @{login}: {prs} PR, {commits} commits, +{added} / −{deleted} líneas (Δ {delta}), +{binAdded} / −{binDeleted} archivos binarios, {first} – {last}
|
||||
|
|
|
|||
|
Can't render this file because it contains an unexpected character in line 4 and column 47.
|
|
|
@ -2526,3 +2526,35 @@ cameraRaw Blending Fusion
|
|||
Magnetic Lasso Tool Outil Lasso magnétique
|
||||
Frequency Fréquence
|
||||
Use tablet pressure to change pen width Utiliser la pression de la tablette pour modifier la largeur de la plume
|
||||
|
||||
# About ▸ Contributors / Models (credits, craftrules standards/contributors.md)
|
||||
About À propos
|
||||
Contributors Contributeurs
|
||||
Models Modèles
|
||||
Sort Trier
|
||||
Username Nom d'utilisateur
|
||||
Display name Nom affiché
|
||||
Real name Nom réel
|
||||
Reverse the order Inverser l'ordre
|
||||
Grab bag Vrac
|
||||
Table Tableau
|
||||
Name (A–Z) Nom (A–Z)
|
||||
Merged PRs PR fusionnées
|
||||
Commits Commits
|
||||
Lines added Lignes ajoutées
|
||||
Lines deleted Lignes supprimées
|
||||
Line delta Solde de lignes
|
||||
Binary assets added Fichiers binaires ajoutés
|
||||
Binary assets removed Fichiers binaires supprimés
|
||||
First commit Premier commit
|
||||
First Premier
|
||||
Last commit Dernier commit
|
||||
Last Dernier
|
||||
Contributors: {contributors} · Commits: {commits} Contributeurs : {contributors} · Commits : {commits}
|
||||
No contributor data was built into this copy. Aucune donnée de contributeurs n'est incluse dans cette copie.
|
||||
No model credits were built into this copy. Aucun crédit de modèle n'est inclus dans cette copie.
|
||||
Company Société
|
||||
Version Version
|
||||
% of all commits % de tous les commits
|
||||
Lines +/− Lignes +/−
|
||||
@{login}: {prs} PRs, {commits} commits, +{added} / −{deleted} lines (Δ {delta}), +{binAdded} / −{binDeleted} binary assets, {first} – {last} @{login} : {prs} PR, {commits} commits, +{added} / −{deleted} lignes (Δ {delta}), +{binAdded} / −{binDeleted} fichiers binaires, {first} – {last}
|
||||
|
|
|
|||
|
Can't render this file because it contains an unexpected character in line 6 and column 47.
|
|
|
@ -2513,3 +2513,35 @@ cameraRaw Blending Pembauran
|
|||
Magnetic Lasso Tool Alat Magnetic Lasso
|
||||
Frequency Frekuensi
|
||||
Use tablet pressure to change pen width Gunakan tekanan tablet untuk mengubah lebar pena
|
||||
|
||||
# About ▸ Contributors / Models (credits, craftrules standards/contributors.md)
|
||||
About Tentang
|
||||
Contributors Kontributor
|
||||
Models Model
|
||||
Sort Urutkan
|
||||
Username Nama pengguna
|
||||
Display name Nama tampilan
|
||||
Real name Nama asli
|
||||
Reverse the order Balik urutan
|
||||
Grab bag Daftar bebas
|
||||
Table Tabel
|
||||
Name (A–Z) Nama (A–Z)
|
||||
Merged PRs PR yang digabung
|
||||
Commits Commit
|
||||
Lines added Baris ditambah
|
||||
Lines deleted Baris dihapus
|
||||
Line delta Selisih baris
|
||||
Binary assets added Berkas biner ditambah
|
||||
Binary assets removed Berkas biner dihapus
|
||||
First commit Commit pertama
|
||||
First Pertama
|
||||
Last commit Commit terakhir
|
||||
Last Terakhir
|
||||
Contributors: {contributors} · Commits: {commits} Kontributor: {contributors} · Commit: {commits}
|
||||
No contributor data was built into this copy. Salinan ini tidak memuat data kontributor.
|
||||
No model credits were built into this copy. Salinan ini tidak memuat kredit model.
|
||||
Company Perusahaan
|
||||
Version Versi
|
||||
% of all commits % dari semua commit
|
||||
Lines +/− Baris +/−
|
||||
@{login}: {prs} PRs, {commits} commits, +{added} / −{deleted} lines (Δ {delta}), +{binAdded} / −{binDeleted} binary assets, {first} – {last} @{login}: {prs} PR, {commits} commit, +{added} / −{deleted} baris (Δ {delta}), +{binAdded} / −{binDeleted} berkas biner, {first} – {last}
|
||||
|
|
|
|||
|
Can't render this file because it contains an unexpected character in line 4 and column 47.
|
|
|
@ -2168,3 +2168,35 @@ cameraRaw Amount Quantità
|
|||
Magnetic Lasso Tool Strumento Lazo magnetico
|
||||
Frequency Frequenza
|
||||
Use tablet pressure to change pen width Usa pressione tavoletta per cambiare la larghezza della penna
|
||||
|
||||
# About ▸ Contributors / Models (credits, craftrules standards/contributors.md)
|
||||
About Informazioni
|
||||
Contributors Collaboratori
|
||||
Models Modelli
|
||||
Sort Ordina
|
||||
Username Nome utente
|
||||
Display name Nome visualizzato
|
||||
Real name Nome reale
|
||||
Reverse the order Inverti l'ordine
|
||||
Grab bag Elenco libero
|
||||
Table Tabella
|
||||
Name (A–Z) Nome (A–Z)
|
||||
Merged PRs PR unite
|
||||
Commits Commit
|
||||
Lines added Righe aggiunte
|
||||
Lines deleted Righe eliminate
|
||||
Line delta Differenza righe
|
||||
Binary assets added Risorse binarie aggiunte
|
||||
Binary assets removed Risorse binarie rimosse
|
||||
First commit Primo commit
|
||||
First Primo
|
||||
Last commit Ultimo commit
|
||||
Last Ultimo
|
||||
Contributors: {contributors} · Commits: {commits} Collaboratori: {contributors} · Commit: {commits}
|
||||
No contributor data was built into this copy. Questa copia non include dati sui collaboratori.
|
||||
No model credits were built into this copy. Questa copia non include i crediti dei modelli.
|
||||
Company Azienda
|
||||
Version Versione
|
||||
% of all commits % di tutti i commit
|
||||
Lines +/− Righe +/−
|
||||
@{login}: {prs} PRs, {commits} commits, +{added} / −{deleted} lines (Δ {delta}), +{binAdded} / −{binDeleted} binary assets, {first} – {last} @{login}: {prs} PR, {commits} commit, +{added} / −{deleted} righe (Δ {delta}), +{binAdded} / −{binDeleted} risorse binarie, {first} – {last}
|
||||
|
|
|
|||
|
Can't render this file because it has a wrong number of fields in line 14.
|
|
|
@ -2077,3 +2077,36 @@ cameraRaw Color カラー
|
|||
Magnetic Lasso Tool マグネット選択ツール
|
||||
Frequency 頻度
|
||||
Use tablet pressure to change pen width タブレットの筆圧を使用してペンの幅を変更
|
||||
|
||||
# About ▸ Contributors / Models (credits, craftrules standards/contributors.md)
|
||||
About バージョン情報
|
||||
Contributors コントリビューター
|
||||
Models モデル
|
||||
Sort 並べ替え
|
||||
Username ユーザー名
|
||||
Display name 表示名
|
||||
Real name 本名
|
||||
Reverse the order 順序を反転
|
||||
Grab bag 一覧
|
||||
Table 表
|
||||
Name (A–Z) 名前 (A–Z)
|
||||
Merged PRs マージされた PR
|
||||
Commits コミット
|
||||
Lines added 追加行数
|
||||
Lines deleted 削除行数
|
||||
Line delta 行数の増減
|
||||
Binary assets added 追加したバイナリ
|
||||
Binary assets removed 削除したバイナリ
|
||||
First commit 最初のコミット
|
||||
First 最初
|
||||
Last commit 最後のコミット
|
||||
Last 最後
|
||||
Contributors: {contributors} · Commits: {commits} コントリビューター: {contributors} · コミット: {commits}
|
||||
No contributor data was built into this copy. このコピーにはコントリビューターのデータが含まれていません。
|
||||
No model credits were built into this copy. このコピーにはモデルのクレジットが含まれていません。
|
||||
Company 会社
|
||||
Model モデル
|
||||
Version バージョン
|
||||
% of all commits 全コミットに占める割合 (%)
|
||||
Lines +/− 行数 +/−
|
||||
@{login}: {prs} PRs, {commits} commits, +{added} / −{deleted} lines (Δ {delta}), +{binAdded} / −{binDeleted} binary assets, {first} – {last} @{login}: PR {prs} 件、コミット {commits} 件、行 +{added} / −{deleted} (Δ {delta})、バイナリ +{binAdded} / −{binDeleted}、{first} – {last}
|
||||
|
|
|
|||
|
Can't render this file because it contains an unexpected character in line 6 and column 47.
|
|
|
@ -2679,3 +2679,35 @@ cameraRaw Color 색상
|
|||
Magnetic Lasso Tool 자석 올가미 도구
|
||||
Frequency 빈도
|
||||
Use tablet pressure to change pen width 태블릿 압력을 사용하여 펜 폭 변경
|
||||
|
||||
# About ▸ Contributors / Models (credits, craftrules standards/contributors.md)
|
||||
About 정보
|
||||
Contributors 기여자
|
||||
Models 모델
|
||||
Sort 정렬
|
||||
Username 사용자 이름
|
||||
Display name 표시 이름
|
||||
Real name 실명
|
||||
Reverse the order 순서 뒤집기
|
||||
Grab bag 나열
|
||||
Table 표
|
||||
Name (A–Z) 이름 (A–Z)
|
||||
Merged PRs 병합된 PR
|
||||
Commits 커밋
|
||||
Lines added 추가된 줄
|
||||
Lines deleted 삭제된 줄
|
||||
Line delta 줄 증감
|
||||
Binary assets added 추가된 바이너리
|
||||
Binary assets removed 삭제된 바이너리
|
||||
First commit 첫 커밋
|
||||
First 처음
|
||||
Last commit 마지막 커밋
|
||||
Last 마지막
|
||||
Contributors: {contributors} · Commits: {commits} 기여자: {contributors} · 커밋: {commits}
|
||||
No contributor data was built into this copy. 이 사본에는 기여자 데이터가 포함되어 있지 않습니다.
|
||||
No model credits were built into this copy. 이 사본에는 모델 크레딧이 포함되어 있지 않습니다.
|
||||
Company 회사
|
||||
Version 버전
|
||||
% of all commits 전체 커밋 대비 %
|
||||
Lines +/− 줄 +/−
|
||||
@{login}: {prs} PRs, {commits} commits, +{added} / −{deleted} lines (Δ {delta}), +{binAdded} / −{binDeleted} binary assets, {first} – {last} @{login}: PR {prs}개, 커밋 {commits}개, 줄 +{added} / −{deleted} (Δ {delta}), 바이너리 +{binAdded} / −{binDeleted}, {first} – {last}
|
||||
|
|
|
|||
|
Can't render this file because it has a wrong number of fields in line 10.
|
|
|
@ -2534,3 +2534,34 @@ cameraRaw Whites Brancos
|
|||
Magnetic Lasso Tool Ferramenta Laço magnético
|
||||
Frequency Frequência
|
||||
Use tablet pressure to change pen width Usar a pressão da mesa digitalizadora para alterar a largura da caneta
|
||||
# About ▸ Contributors / Models (credits, craftrules standards/contributors.md)
|
||||
About Sobre
|
||||
Contributors Colaboradores
|
||||
Models Modelos
|
||||
Sort Ordenar
|
||||
Username Nome de usuário
|
||||
Display name Nome de exibição
|
||||
Real name Nome real
|
||||
Reverse the order Inverter a ordem
|
||||
Grab bag Lista corrida
|
||||
Table Tabela
|
||||
Name (A–Z) Nome (A–Z)
|
||||
Merged PRs PRs mesclados
|
||||
Commits Commits
|
||||
Lines added Linhas adicionadas
|
||||
Lines deleted Linhas removidas
|
||||
Line delta Saldo de linhas
|
||||
Binary assets added Arquivos binários adicionados
|
||||
Binary assets removed Arquivos binários removidos
|
||||
First commit Primeiro commit
|
||||
First Primeiro
|
||||
Last commit Último commit
|
||||
Last Último
|
||||
Contributors: {contributors} · Commits: {commits} Colaboradores: {contributors} · Commits: {commits}
|
||||
No contributor data was built into this copy. Esta cópia não inclui dados de colaboradores.
|
||||
No model credits were built into this copy. Esta cópia não inclui créditos de modelos.
|
||||
Company Empresa
|
||||
Version Versão
|
||||
% of all commits % de todos os commits
|
||||
Lines +/− Linhas +/−
|
||||
@{login}: {prs} PRs, {commits} commits, +{added} / −{deleted} lines (Δ {delta}), +{binAdded} / −{binDeleted} binary assets, {first} – {last} @{login}: {prs} PRs, {commits} commits, +{added} / −{deleted} linhas (Δ {delta}), +{binAdded} / −{binDeleted} arquivos binários, {first} – {last}
|
||||
|
|
|
|||
|
Can't render this file because it contains an unexpected character in line 6 and column 47.
|
|
|
@ -2369,3 +2369,35 @@ cameraRaw Roughness Неровность
|
|||
Magnetic Lasso Tool Магнитное лассо
|
||||
Frequency Частота
|
||||
Use tablet pressure to change pen width Использовать нажим планшета для изменения ширины пера
|
||||
|
||||
# About ▸ Contributors / Models (credits, craftrules standards/contributors.md)
|
||||
About О программе
|
||||
Contributors Участники
|
||||
Models Модели
|
||||
Sort Сортировка
|
||||
Username Имя пользователя
|
||||
Display name Отображаемое имя
|
||||
Real name Настоящее имя
|
||||
Reverse the order Обратный порядок
|
||||
Grab bag Списком
|
||||
Table Таблица
|
||||
Name (A–Z) Имя (А–Я)
|
||||
Merged PRs Принятые PR
|
||||
Commits Коммиты
|
||||
Lines added Добавлено строк
|
||||
Lines deleted Удалено строк
|
||||
Line delta Разница строк
|
||||
Binary assets added Добавлено двоичных файлов
|
||||
Binary assets removed Удалено двоичных файлов
|
||||
First commit Первый коммит
|
||||
First Первый
|
||||
Last commit Последний коммит
|
||||
Last Последний
|
||||
Contributors: {contributors} · Commits: {commits} Участники: {contributors} · Коммиты: {commits}
|
||||
No contributor data was built into this copy. В эту копию не встроены данные об участниках.
|
||||
No model credits were built into this copy. В эту копию не встроены сведения о моделях.
|
||||
Company Компания
|
||||
Version Версия
|
||||
% of all commits % от всех коммитов
|
||||
Lines +/− Строки +/−
|
||||
@{login}: {prs} PRs, {commits} commits, +{added} / −{deleted} lines (Δ {delta}), +{binAdded} / −{binDeleted} binary assets, {first} – {last} @{login}: PR: {prs}, коммиты: {commits}, строки +{added} / −{deleted} (Δ {delta}), двоичные файлы +{binAdded} / −{binDeleted}, {first} – {last}
|
||||
|
|
|
|||
|
Can't render this file because it contains an unexpected character in line 6 and column 47.
|
|
|
@ -2102,3 +2102,36 @@ cameraRaw Blending 混合
|
|||
Magnetic Lasso Tool 磁性套索工具
|
||||
Frequency 频率
|
||||
Use tablet pressure to change pen width 使用绘图板压力以更改钢笔宽度
|
||||
|
||||
# About ▸ Contributors / Models (credits, craftrules standards/contributors.md)
|
||||
About 关于
|
||||
Contributors 贡献者
|
||||
Models 模型
|
||||
Sort 排序
|
||||
Username 用户名
|
||||
Display name 显示名称
|
||||
Real name 真实姓名
|
||||
Reverse the order 反转顺序
|
||||
Grab bag 列表
|
||||
Table 表格
|
||||
Name (A–Z) 名称 (A–Z)
|
||||
Merged PRs 已合并的 PR
|
||||
Commits 提交
|
||||
Lines added 新增行数
|
||||
Lines deleted 删除行数
|
||||
Line delta 行数增减
|
||||
Binary assets added 新增二进制文件
|
||||
Binary assets removed 删除二进制文件
|
||||
First commit 首次提交
|
||||
First 首次
|
||||
Last commit 最近提交
|
||||
Last 最近
|
||||
Contributors: {contributors} · Commits: {commits} 贡献者:{contributors} · 提交:{commits}
|
||||
No contributor data was built into this copy. 此副本未内置贡献者数据。
|
||||
No model credits were built into this copy. 此副本未内置模型致谢。
|
||||
Company 公司
|
||||
Model 模型
|
||||
Version 版本
|
||||
% of all commits 占全部提交的 %
|
||||
Lines +/− 行数 +/−
|
||||
@{login}: {prs} PRs, {commits} commits, +{added} / −{deleted} lines (Δ {delta}), +{binAdded} / −{binDeleted} binary assets, {first} – {last} @{login}:{prs} 个 PR,{commits} 次提交,行 +{added} / −{deleted}(Δ {delta}),二进制文件 +{binAdded} / −{binDeleted},{first} – {last}
|
||||
|
|
|
|||
|
Can't render this file because it has a wrong number of fields in line 14.
|
|
|
@ -2071,3 +2071,36 @@ cameraRaw Blending 混合
|
|||
Magnetic Lasso Tool 磁性套索工具
|
||||
Frequency 頻率
|
||||
Use tablet pressure to change pen width 使用繪圖板壓力以變更鋼筆寬度
|
||||
|
||||
# About ▸ Contributors / Models (credits, craftrules standards/contributors.md)
|
||||
About 關於
|
||||
Contributors 貢獻者
|
||||
Models 模型
|
||||
Sort 排序
|
||||
Username 使用者名稱
|
||||
Display name 顯示名稱
|
||||
Real name 真實姓名
|
||||
Reverse the order 反轉順序
|
||||
Grab bag 清單
|
||||
Table 表格
|
||||
Name (A–Z) 名稱 (A–Z)
|
||||
Merged PRs 已合併的 PR
|
||||
Commits 提交
|
||||
Lines added 新增行數
|
||||
Lines deleted 刪除行數
|
||||
Line delta 行數增減
|
||||
Binary assets added 新增二進位檔
|
||||
Binary assets removed 刪除二進位檔
|
||||
First commit 首次提交
|
||||
First 首次
|
||||
Last commit 最近提交
|
||||
Last 最近
|
||||
Contributors: {contributors} · Commits: {commits} 貢獻者:{contributors} · 提交:{commits}
|
||||
No contributor data was built into this copy. 此副本未內建貢獻者資料。
|
||||
No model credits were built into this copy. 此副本未內建模型致謝。
|
||||
Company 公司
|
||||
Model 模型
|
||||
Version 版本
|
||||
% of all commits 佔全部提交的 %
|
||||
Lines +/− 行數 +/−
|
||||
@{login}: {prs} PRs, {commits} commits, +{added} / −{deleted} lines (Δ {delta}), +{binAdded} / −{binDeleted} binary assets, {first} – {last} @{login}:{prs} 個 PR,{commits} 次提交,行 +{added} / −{deleted}(Δ {delta}),二進位檔 +{binAdded} / −{binDeleted},{first} – {last}
|
||||
|
|
|
|||
|
Can't render this file because it contains an unexpected character in line 6 and column 47.
|
|
|
@ -41,6 +41,7 @@ pub mod color_picker_ui;
|
|||
pub mod color_range_ui;
|
||||
pub mod comps_ui;
|
||||
pub mod control;
|
||||
pub mod credits;
|
||||
pub mod crop_ui;
|
||||
pub mod dialogs;
|
||||
pub mod discard_ui;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,57 @@
|
|||
# Contributors in the About window
|
||||
|
||||
**About ▸ Contributors** credits everyone who contributed to PhotoCraft, and **About ▸ Models** credits
|
||||
the AI models named in `Co-Authored-By` trailers. This follows the shared craftrules standard
|
||||
[`standards/contributors.md`](https://github.com/storytold/craftrules/blob/main/standards/contributors.md);
|
||||
this page is the local copy of the decision.
|
||||
|
||||
## Decision
|
||||
|
||||
- Two files, both **compiled into the binary** by the UI crate's `build.rs` (nothing is read from
|
||||
disk or the network at run time; the web build has them too):
|
||||
- [`contributors/contributors.json`](../contributors/contributors.json): commit stats per GitHub
|
||||
username. **Generated** by `craftrules/scripts/contributors.py`; never hand-edit.
|
||||
- [`contributors/people.toml`](../contributors/people.toml): the names people chose for
|
||||
themselves. **Each contributor adds only their own entry**, in their own PR.
|
||||
- Each contributor gets one line: GitHub username (always), display name (opt-in, or their synced
|
||||
GitHub profile name), real name (only if they told us), merged PRs, commits, lines added, lines
|
||||
deleted, binary assets added, binary assets removed, first and last commit date.
|
||||
- The list is shown as a **grab bag** (names flowing as text) or a **table**, in the same order. It
|
||||
sorts by name, PRs, commits, lines added, lines deleted, line delta, binary assets added/removed,
|
||||
first or last commit date. The name toggle cycles **Username → Display name → Real name**; a
|
||||
missing name falls back to `@username`. Alphabetical sorting is case-insensitive and ignores the `@`.
|
||||
|
||||
## In PhotoCraft
|
||||
|
||||
- The About window is `DialogKind::About` in `crates/ui-egui/src/dialogs.rs` (Help ▸ About PhotoCraft).
|
||||
Its tab is the dialog field `tab` (`about`, `contributors`, `models`), so agents can switch it with
|
||||
`ui.dialog.set`. Labels are translated like the rest of the shell (`tl!` + `crates/ui-egui/src/i18n/*.tsv`).
|
||||
|
||||
## Credit yourself
|
||||
|
||||
Add your entry to `contributors/people.toml` in a PR you commit yourself (every field optional):
|
||||
|
||||
```toml
|
||||
[people.your-github-username]
|
||||
real_name = "Your Name"
|
||||
display_name = "Nickname"
|
||||
sync_github_name = true # use the name on your public GitHub profile as display name
|
||||
```
|
||||
|
||||
or, with craftrules checked out next to `craft-apps/`:
|
||||
|
||||
```sh
|
||||
python3 ../../craftrules/scripts/contributors.py --add-me . --real-name "Your Name" --sync-github-name
|
||||
```
|
||||
|
||||
Names show after the next refresh: the script checks that each entry was committed by its own
|
||||
user (or by a maintainer with a `consent_source`). Delete your entry to remove your names.
|
||||
|
||||
## Refreshing (maintainers)
|
||||
|
||||
```sh
|
||||
python3 ../../craftrules/scripts/contributors.py . # regenerate + verify; needs git, Python 3.11+, gh
|
||||
python3 ../../craftrules/scripts/contributors.py --check . # verify people.toml only
|
||||
```
|
||||
|
||||
Commit the updated `contributors/contributors.json`. Git author names and emails are never recorded.
|
||||
Loading…
Reference in New Issue