diff --git a/.github/workflows/guard-translations.yml b/.github/workflows/guard-translations.yml index 633f5497..70caef21 100644 --- a/.github/workflows/guard-translations.yml +++ b/.github/workflows/guard-translations.yml @@ -57,8 +57,14 @@ jobs: # # --diff-filter=MD keeps only Modified and Deleted paths: edits to files that ALREADY exist # on the base branch. Added (A) files are handled separately per client below. - edited="$(git diff --no-renames --diff-filter=MD --name-only "$BASE_SHA" "$HEAD_SHA" || true)" - added="$(git diff --no-renames --diff-filter=A --name-only "$BASE_SHA" "$HEAD_SHA" || true)" + # Three dots, not two. `git diff A B` compares the two trees as they stand, so every + # commit that landed on the base branch after this PR forked shows up as if the PR had + # changed it -- a Weblate sync merging to master made unrelated PRs fail with + # "client_v2/locales/sv/common.json" in the offending list. `git diff A...B` diffs from + # the MERGE BASE instead, which is exactly "what this PR changed" and stays correct no + # matter how far master has moved on. + edited="$(git diff --no-renames --diff-filter=MD --name-only "$BASE_SHA...$HEAD_SHA" || true)" + added="$(git diff --no-renames --diff-filter=A --name-only "$BASE_SHA...$HEAD_SHA" || true)" # Active client: edits to existing non-English files are blocked, new languages are fine. offending_v2="$(printf '%s\n' "$edited" \ diff --git a/client_v2/locales/en/common.json b/client_v2/locales/en/common.json index 6871b959..5cbe8dcd 100644 --- a/client_v2/locales/en/common.json +++ b/client_v2/locales/en/common.json @@ -290,6 +290,8 @@ "library.nUnused": "×{{count}} unused", "library.noLocation": "no location", "library.noValues": "No values", + "library.openGroup": "Open {{name}}", + "library.openManufacturer": "Open manufacturer {{name}}", "library.section.extra": "Extra fields", "library.section.filament": "Filament", "library.section.spool": "Spool", diff --git a/client_v2/src/lib/api/map.ts b/client_v2/src/lib/api/map.ts index b4b6c777..71b7d84a 100644 --- a/client_v2/src/lib/api/map.ts +++ b/client_v2/src/lib/api/map.ts @@ -106,11 +106,19 @@ export function mapGroup(g: Json): GroupSummary { let badge = ''; let colors: string[] = []; let direction: MultiColorDirection | undefined; + // Filament groups carry their manufacturer separately from the subtitle text + // so the header can render it as a link to the vendor (see GroupHeader). + let vendorId: string | undefined; + let vendorName: string | undefined; if (field === 'filament' && g.filament) { const f: Json = g.filament; title = f.name ?? '(unnamed filament)'; - subtitle = `${f.vendor?.name ?? 'No manufacturer'} · ${f.diameter} mm`; + subtitle = `${f.diameter} mm`; + if (f.vendor) { + vendorId = String(f.vendor.id); + vendorName = f.vendor.name ?? '(unnamed manufacturer)'; + } badge = f.material ?? ''; colors = colorsFromApi(f); direction = f.multi_color_direction ?? undefined; @@ -136,6 +144,8 @@ export function mapGroup(g: Json): GroupSummary { title, subtitle, badge, + vendorId, + vendorName, colors, direction, spoolCount: g.spool_count ?? 0, diff --git a/client_v2/src/lib/api/types.ts b/client_v2/src/lib/api/types.ts index ef443610..390ba7fb 100644 --- a/client_v2/src/lib/api/types.ts +++ b/client_v2/src/lib/api/types.ts @@ -29,6 +29,10 @@ export interface GroupSummary { title: string; subtitle: string; badge: string; + /** Filament groups only: the manufacturer, so the header can link to it. + * Both absent when the filament has no manufacturer set. */ + vendorId?: string; + vendorName?: string; colors: string[]; /** Multi-color layout, when grouping by a single filament; undefined otherwise. */ direction?: MultiColorDirection; diff --git a/client_v2/src/lib/components/Breadcrumbs.svelte b/client_v2/src/lib/components/Breadcrumbs.svelte index 9bbe276b..81cecd3b 100644 --- a/client_v2/src/lib/components/Breadcrumbs.svelte +++ b/client_v2/src/lib/components/Breadcrumbs.svelte @@ -51,8 +51,13 @@ font: inherit; text-decoration: none; } + /* Underlined on hover, not just recoloured: a crumb is a short piece of dim + text in a corner, and colour alone left people reading it as a caption rather + than as the way to the manufacturer (#989). */ .crumb:hover { color: var(--accent-link-hover); + text-decoration: underline; + text-underline-offset: 2px; } .current { color: var(--text-2); diff --git a/client_v2/src/lib/components/library/GroupHeader.svelte b/client_v2/src/lib/components/library/GroupHeader.svelte index 469445f9..e37d84ba 100644 --- a/client_v2/src/lib/components/library/GroupHeader.svelte +++ b/client_v2/src/lib/components/library/GroupHeader.svelte @@ -1,7 +1,11 @@ - + you are scrolled deep inside a long group, which is exactly when you want it. + + The entity link is only the title, but its stretched ::after (see the styles) + extends its hit area over the whole row, so the row-wide click target survives + the two links being siblings. That is also what makes `.main:hover` mean + "anywhere on the row except the other two controls", which is the precision the + hover affordance below needs. -->
- - {#if group.colors.length} - - {/if} -
-
- {group.title} - {#if group.badge}{/if} + {#if href} + + + {/if} + {#if group.colors.length} + + {/if} +
+
+ + {group.title} + {#if group.badge}{/if} +
+ {#if group.vendorName || group.subtitle} +
+ + {#if group.vendorName && vendorHref} + + + {group.vendorName} + + {:else if group.vendorName} + {group.vendorName} + {/if} + {#if group.vendorName && group.subtitle}{/if} + {#if group.subtitle}{group.subtitle}{/if}
- {#if group.subtitle}
{group.subtitle}
{/if} -
- -
- {group.meta} - {group.count} -
- + {/if} +
+ +
+ {group.meta} + {group.count} +