1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
|
import { html } from './vendor/htm-preact.js';
import { t } from './i18n.js';
import { sourceLabel } from './source-merge.js';
/**
* A group's name with the `@owner` handle under it.
*
* Group names are unique only per owner account (the hub enforces that), so the
* `@handle` is what tells two groups called "photos" apart. `owner` is the
* owner's username for a local group, or the source hub for a federated one
* (decision 5 in ~/next/groupnames.md); the caller decides which.
*
* `inline` renders "name@owner" on one line, for places that cannot take a
* block — a badge, a `confirm()` string built elsewhere.
*/
export function GroupName({ name, owner, inline = false }) {
if (inline) return owner ? `${name}@${owner}` : name;
return html`
<span class="gn">
<span class="gn-name">${name}</span>
${owner && html`<span class="gn-owner">@${owner}</span>`}
</span>
`;
}
/**
* Which group serves an entry, or how many groups have it.
*
* The Search view merges a file several groups share into one entry, so the
* badge under a card cannot always name a group. One source keeps naming it
* and keeps linking to it; more than one becomes a count, and *which* one was
* picked is deliberately not shown (docs/refactoring-search.md §5.5).
*
* `entries` is the whole unit — every episode of a show, every track of an
* album — not the entry the card was drawn from; `sourceLabel` explains why.
* Renders nothing at all on the single-group Group page, where an entry
* carries no group and there is only ever one source anyway.
*
* It lives here rather than in `source-merge.js` because that module is
* executed standalone by its test and must keep importing nothing; and here
* rather than in one of the three apps that need it, because a copy apiece is
* three chances to disagree about what a merged card says.
*
* A `div` by default: the three card badges rely on `text-overflow: ellipsis`,
* which does nothing on an inline box. `link` gives the flat row's inline
* pill instead.
*/
export function SourceTag({ entries, cls, link = false }) {
const { count, name, groupId } = sourceLabel(entries);
if (count > 1) return html`<span class=${cls}>${t('search.n_sources', { n: count })}</span>`;
if (!name) return null;
if (link && groupId) {
return html`<a href="#/group/${groupId}" class=${cls}
onClick=${(e) => e.stopPropagation()}>${name}</a>`;
}
return html`<div class=${cls}>${name}</div>`;
}
|