@smartsoft001-mobilems/public-collections-shell-angular 2.119.0 → 2.121.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,17 +1,21 @@
1
1
  import * as i0 from '@angular/core';
2
- import { TemplateRef, ModuleWithProviders, Signal } from '@angular/core';
2
+ import { TemplateRef, ModuleWithProviders, Signal, WritableSignal } from '@angular/core';
3
3
  import * as _smartsoft001_crud_shell_angular from '@smartsoft001/crud-shell-angular';
4
- import { ICrudModuleOptionsWithoutRoutng, CrudFacade, CrudListPageBaseComponent, CrudItemPageBaseComponent, State as State$1, CrudService } from '@smartsoft001/crud-shell-angular';
4
+ import { ICrudModuleOptionsWithoutRoutng, CrudFacade, CrudListPageBaseComponent, CrudItemPageBaseComponent, State as State$1, ICrudFilter, CrudService } from '@smartsoft001/crud-shell-angular';
5
5
  import { IEntity } from '@smartsoft001/domain-core';
6
6
  import * as i1$1 from '@smartsoft001-mobilems/angular';
7
- import { FiltersBaseComponent, CrudBaseService, SeoService, TranslationService } from '@smartsoft001-mobilems/angular';
7
+ import { FiltersBaseComponent, CrudBaseService, SeoService, TranslationService, ICatalog, ICatalogLoadMore, IDictionaryEntry, ICatalogOptions, ICycleTagSearchOptions, ICatalogSort, FileUrlMode, ISeoMetadata } from '@smartsoft001-mobilems/angular';
8
8
  import * as i1 from '@angular/common';
9
- import { PublicCollection } from '@smartsoft001-mobilems/public-collections-domain';
9
+ import { PublicCollection, PublicCollectionItemType } from '@smartsoft001-mobilems/public-collections-domain';
10
10
  import * as dist_packages_public_collections_domain_src from 'dist/packages/public-collections/domain/src';
11
11
  import * as _angular_router from '@angular/router';
12
12
  import { ActivatedRoute } from '@angular/router';
13
13
  import * as _ngrx_store from '@ngrx/store';
14
14
  import { Action } from '@ngrx/store';
15
+ import { ListMode } from '@smartsoft001/angular';
16
+ import { Article } from '@smartsoft001-mobilems/articles-domain';
17
+ import { MsObject } from '@smartsoft001-mobilems/objects-domain';
18
+ import { Observable } from 'rxjs';
15
19
 
16
20
  declare class FiltersComponent extends FiltersBaseComponent<PublicCollection> {
17
21
  static ɵfac: i0.ɵɵFactoryDeclaration<FiltersComponent, never>;
@@ -125,10 +129,358 @@ declare function getReducer(): (state: any, action: Action) => State$1<any> | {
125
129
 
126
130
  declare const getPublicCollectionsState: _ngrx_store.MemoizedSelector<object, State, _ngrx_store.DefaultProjectorFn<State>>;
127
131
 
132
+ interface IPublicCollectionPaginator {
133
+ currentPage: number;
134
+ maxPerPage: number;
135
+ totalItemsCount: number;
136
+ totalPagesCount: number;
137
+ }
138
+ interface IPublicCollectionPage extends PublicCollection {
139
+ paginatorDetails?: IPublicCollectionPaginator;
140
+ publicationDate?: string | null;
141
+ cycles?: {
142
+ id: number;
143
+ name: string;
144
+ }[] | null;
145
+ }
146
+ /** How many related articles a collection page shows. */
147
+ declare const PUBLIC_COLLECTION_RELATED_ARTICLES_LIMIT = 20;
148
+ declare class PublicCollectionItemsService extends PublicCollectionsService {
149
+ /**
150
+ * Status of the last failed page load. `getItems` yields `null` both for no
151
+ * data and for an error, so without it a page cannot tell a 404 from a load
152
+ * in progress.
153
+ */
154
+ readonly loadErrorStatus: WritableSignal<number | null>;
155
+ /** A collection page is loading (paging, sorting and "load more" go through `getItems`). */
156
+ readonly loading: WritableSignal<boolean>;
157
+ /**
158
+ * Fetches a page of the collection items. Call in an injection context.
159
+ * The URL (parameter order included) is the transfer cache key: keep it as is.
160
+ */
161
+ getItems(collectionId: string, filter: Signal<ICrudFilter>): Signal<IPublicCollectionPage | null>;
162
+ /**
163
+ * Articles related to the collection. The API answers 404
164
+ * (`NO_RESULTS_FOR_GIVEN_QUERY`) when there are none; that, like any error,
165
+ * is an empty list.
166
+ */
167
+ getRelatedArticles(collectionId: string): Observable<Article[]>;
168
+ private collectionItemsBuildUrl;
169
+ static ɵfac: i0.ɵɵFactoryDeclaration<PublicCollectionItemsService, never>;
170
+ static ɵprov: i0.ɵɵInjectableDeclaration<PublicCollectionItemsService>;
171
+ }
172
+
128
173
  declare const SERVICES: (typeof PublicCollectionsService | {
129
174
  provide: typeof CrudService;
130
175
  useClass: typeof PublicCollectionsService;
131
176
  })[];
132
177
 
133
- export { ComponentsModule, FiltersComponent, ListComponent, PublicCollectionsFacade, PublicCollectionsItemComponent, PublicCollectionsListComponent, PublicCollectionsModule, PublicCollectionsService, PublicCollectionsSharedModule, SERVICES, getPublicCollectionsState, getReducer, initialState };
134
- export type { State };
178
+ /**
179
+ * Filter defaults of the collections list (Muzeum Podlasia): a 3x4 grid, 12
180
+ * collections per page. `sortBy`/`sortDesc` match the toolbar's default label
181
+ * ('Name A to Z'); without them `CrudBaseService` sends `sort=random`.
182
+ */
183
+ declare const COLLECTIONS_CATALOG_DEFAULTS: ICrudFilter;
184
+ /**
185
+ * Query key of the theme tags — cycles (`filter[cycles][]=<id>`; checked on
186
+ * the API: the forms with and without `[]` filter the same, an empty result
187
+ * is a 404).
188
+ */
189
+ declare const COLLECTIONS_CYCLES_FILTER_KEY = "cycles";
190
+ /**
191
+ * Cleans a persisted collections filter: the collections API ignores tags of
192
+ * the former `Keyword` dictionary, so they are not restored as an invisible
193
+ * filter.
194
+ */
195
+ declare function dropLegacyCollectionKeywords(saved: ICrudFilter): ICrudFilter;
196
+ /** List SEO: `<title> - <site>`, a raw description and the canonical url. */
197
+ interface ICollectionsCatalogSeo {
198
+ /** Translation key of the page title, e.g. `PAGE_TITLES.collections`. */
199
+ titleKey: string;
200
+ /** Translation key of the description — not capitalised. */
201
+ descriptionKey: string;
202
+ /** Translation key of the site name. Default `MODEL.mainTitle`. */
203
+ siteNameKey?: string;
204
+ /** Canonical url of the list, e.g. `/kolekcje`. */
205
+ url: string;
206
+ }
207
+ declare const COLLECTIONS_CATALOG_SEO: ICollectionsCatalogSeo;
208
+ /** Focus target and live-region message of „więcej ↓” (load more). */
209
+ interface ICollectionsCatalogLoadMore {
210
+ /** Cards inside `#listContainer`; the first appended one gets the focus. */
211
+ itemSelector?: string;
212
+ /** Translation key announced after a page is appended (`{ count }`). */
213
+ loadedMoreKey?: string;
214
+ }
215
+ interface ICollectionsCatalogOptions extends Partial<Omit<ICatalogOptions, 'facade'>> {
216
+ /** Applied on creation, skipped in a search tab; `null` — no SEO. */
217
+ seo?: ICollectionsCatalogSeo | null;
218
+ /** Opt-in `Cycle` tag dictionary of the tag bar (requests the API). */
219
+ cycleTags?: ICycleTagSearchOptions;
220
+ loadMore?: ICollectionsCatalogLoadMore;
221
+ }
222
+ /**
223
+ * Base of a collections list page on the shared catalog engine
224
+ * (`createCatalog`): first read (also in SSR when the route carries the
225
+ * filter), persistence, sort/size/page, the read guard, cycle tags,
226
+ * „więcej ↓” and the list SEO. The page keeps its template.
227
+ *
228
+ * ```ts
229
+ * export class ListComponent extends CollectionsCatalogBaseComponent {
230
+ * constructor() {
231
+ * super({ cycleTags: { debounceMs: 300 } });
232
+ * }
233
+ * }
234
+ * ```
235
+ *
236
+ * A `#listContainer` element in the template is scrolled to after a page
237
+ * change from the bottom pagination and holds the cards focused by load more.
238
+ */
239
+ declare abstract class CollectionsCatalogBaseComponent extends PublicCollectionsListComponent {
240
+ readonly ListMode: typeof ListMode;
241
+ protected readonly catalog: ICatalog;
242
+ readonly isBrowser: Signal<boolean>;
243
+ /** The route set the filter, so the list is read and rendered in SSR too. */
244
+ readonly routeList: Signal<boolean>;
245
+ readonly listMode: Signal<ListMode>;
246
+ readonly searchEnabled: Signal<boolean | undefined>;
247
+ readonly barPhrase: Signal<string>;
248
+ readonly isLoading: Signal<boolean>;
249
+ readonly hasError: Signal<unknown>;
250
+ readonly totalCount: Signal<number>;
251
+ /** `name-desc` style key for the toolbar. */
252
+ readonly sortKey: Signal<string | undefined>;
253
+ readonly selectedPage: Signal<number>;
254
+ /** „więcej ↓” on mobile (2290:10510) — previous pages' cards + the current. */
255
+ readonly loadMore: ICatalogLoadMore<PublicCollection>;
256
+ /** Screen reader message after cards were appended. */
257
+ readonly loadMoreStatus: WritableSignal<string>;
258
+ /** Phrase of the „Search tags” field (the `q` of the `Cycle` dictionary). */
259
+ readonly tagQuery: WritableSignal<string>;
260
+ /** Theme tags of the filter bar; `[]` without the `cycleTags` option. */
261
+ readonly cycleTags: Signal<IDictionaryEntry[]>;
262
+ /** Selected cycle ids. */
263
+ readonly selectedTagIds: Signal<(number | null)[]>;
264
+ /**
265
+ * Bar chips: selected cycles always first, then the rest of the result — a
266
+ * cycle picked on a tile stays visible and can be unselected even when the
267
+ * „Search tags” phrase does not return it.
268
+ */
269
+ readonly tagChips: Signal<IDictionaryEntry[]>;
270
+ private readonly collectionsCatalogTranslate;
271
+ private readonly collectionsCatalogSeoService;
272
+ private readonly collectionsCatalogBrowser;
273
+ private readonly collectionsCatalogTimeouts;
274
+ private readonly collectionsCatalogListContainer;
275
+ private collectionsCatalogScrollAfterLoad;
276
+ /**
277
+ * Selected cycles — the `cycles` item of the current filter, numeric ids
278
+ * without repeats (`"7"` from a deep link = `7` from the dictionary,
279
+ * review MOB-1815).
280
+ */
281
+ private readonly collectionsCatalogSelectedTags;
282
+ protected constructor(options?: ICollectionsCatalogOptions);
283
+ /** The list root element (`#listContainer`). */
284
+ protected get listContainerElement(): HTMLElement | undefined;
285
+ retryLoad(): void;
286
+ pageChange(page: number): void;
287
+ /** Page change from the bottom pagination — scrolls to the list once loaded. */
288
+ bottomPageChange(page: number): void;
289
+ onSortChange(sort: ICatalogSort): void;
290
+ /** Sort by key (`name-desc`, `random`). */
291
+ sortChange(key: string): void;
292
+ onLimitChange(limit: number | string): void;
293
+ /**
294
+ * Toggles one cycle in the `cycles` item (filter bar and tile pills);
295
+ * unselecting the last one removes the whole query item. Compared by the
296
+ * normalised id: a click on `7` also removes `"7"` from a deep link
297
+ * instead of adding a second filter (review MOB-1815); an added cycle is
298
+ * stored with its numeric id.
299
+ */
300
+ onTagToggle(entry: IDictionaryEntry): void;
301
+ /**
302
+ * Search from the filter bar. In the catalog it patches the filter; in a
303
+ * search tab the phrase lives in the address (MOB-1818) — a new one opens
304
+ * `/wyszukaj/:text/kolekcje`, a blank one `/kolekcje` with the other filters.
305
+ */
306
+ onFilterBarSearch(phrase: string): void;
307
+ onListModeChange(mode: ListMode): void;
308
+ clearAllFilters(): void;
309
+ /**
310
+ * Full list meta (title, description, canonical, og), not in a search tab —
311
+ * there the search page sets them, and the canonical of the list must not
312
+ * point at a phrase url. The description goes out as translated.
313
+ */
314
+ protected applyListSeo(seo: ICollectionsCatalogSeo): void;
315
+ static ɵfac: i0.ɵɵFactoryDeclaration<CollectionsCatalogBaseComponent, never>;
316
+ static ɵdir: i0.ɵɵDirectiveDeclaration<CollectionsCatalogBaseComponent, never, never, {}, {}, never, never, true, never>;
317
+ }
318
+
319
+ /** Local filter of a collection page (Muzeum Podlasia): 20 objects per page, unsorted. */
320
+ declare const COLLECTION_DETAILS_DEFAULTS: ICrudFilter;
321
+ /** An item of a collection page — an object or an article. */
322
+ type CollectionDetailsItem = ({
323
+ type: PublicCollectionItemType.object;
324
+ data: MsObject;
325
+ } | {
326
+ type: PublicCollectionItemType.article;
327
+ data: Article;
328
+ }) & {
329
+ id: string;
330
+ };
331
+ /** A related article link: the id and its plain-text title. */
332
+ interface ICollectionRelatedArticle {
333
+ id: string;
334
+ title: string;
335
+ }
336
+ /** Focus target and live-region message of „więcej ↓” (load more). */
337
+ interface ICollectionDetailsLoadMore {
338
+ /** Cards inside `#listContainer`; the first appended one gets the focus. */
339
+ itemSelector?: string;
340
+ /** Translation key announced after a page is appended (`{ count }`). */
341
+ loadedMoreKey?: string;
342
+ }
343
+ interface ICollectionDetailsOptions {
344
+ /** Initial local filter. Default `COLLECTION_DETAILS_DEFAULTS`. */
345
+ defaults?: ICrudFilter;
346
+ /** `StorageService` key of the grid/list mode — shared with `/obiekty` on purpose. */
347
+ listModeKey?: string;
348
+ /** Below this `innerWidth` the mode is forced and the toggle ignored. Default `768`. */
349
+ mobileBreakpoint?: number;
350
+ /** The mode forced below the breakpoint. Default `ListMode.masonryGrid`. */
351
+ mobileListMode?: ListMode;
352
+ /** Translation key of the site name in the titles. Default `MODEL.mainTitle`. */
353
+ siteNameKey?: string;
354
+ /** `FileUrlService` mode of the hero image. Default `noCache` (MOB-1564, MOB-1850). */
355
+ heroImageMode?: FileUrlMode;
356
+ /** Opt-in related articles (requests `search/Article`). Default `false`. */
357
+ relatedArticles?: boolean;
358
+ loadMore?: ICollectionDetailsLoadMore;
359
+ }
360
+ /**
361
+ * Base of a collection page: the collection with a locally paged list of its
362
+ * items (`PublicCollectionItemsService.getItems`), sort/size/page, 404 vs
363
+ * other load errors, SEO (also in SSR), hero image and meta, opt-in related
364
+ * articles, „więcej ↓” and the grid/list mode. The page keeps its template.
365
+ *
366
+ * ```ts
367
+ * // Muzeum Podlasia
368
+ * export class ItemComponent extends CollectionDetailsBaseComponent {
369
+ * constructor() {
370
+ * super({ relatedArticles: true });
371
+ * }
372
+ * }
373
+ * ```
374
+ *
375
+ * A `#listContainer` element in the template is scrolled to after a page
376
+ * change from the bottom pagination and holds the cards focused by load more.
377
+ */
378
+ declare abstract class CollectionDetailsBaseComponent extends PublicCollectionsItemComponent {
379
+ protected readonly collectionDetailsService: PublicCollectionItemsService;
380
+ private readonly collectionDetailsSeo;
381
+ private readonly collectionDetailsFileUrl;
382
+ private readonly collectionDetailsStorage;
383
+ private readonly collectionDetailsTranslate;
384
+ private readonly collectionDetailsLocale;
385
+ private readonly collectionDetailsDocument;
386
+ private readonly collectionDetailsBrowser;
387
+ private readonly collectionDetailsTimeouts;
388
+ private readonly collectionDetailsListContainer;
389
+ private readonly collectionDetailsMasonry;
390
+ private readonly collectionDetailsOptions;
391
+ private collectionDetailsScrollAfterLoad;
392
+ /** The collection read by the facade or a page of objects by the service. */
393
+ readonly isLoading: Signal<boolean>;
394
+ /** Mode of the objects list — tiles (masonry) or a vertical list. */
395
+ readonly listMode: WritableSignal<ListMode>;
396
+ /** Local filter; a new value triggers a read of the items. */
397
+ readonly localFilter: WritableSignal<ICrudFilter>;
398
+ /** The collection with the current page of items. */
399
+ readonly data: Signal<IPublicCollectionPage | null>;
400
+ /** The current filter as a toolbar option key (e.g. `name-desc`). */
401
+ readonly toolbarSortKey: Signal<string>;
402
+ /**
403
+ * The hero straight from the real file (`noCache` = `filePath` without the
404
+ * extension swap). `FileUrlService.get()` in `cache` mode forces `.jpg` for
405
+ * paths outside `media/dictionaries`/`media/articles`, and the CDN has no
406
+ * preset for `entry_collections` — the `.jpg` ended in 404 /
407
+ * ERR_BLOCKED_BY_ORB (MOB-1564), and the real `.png` came only after
408
+ * hydration through `(error)` (Lighthouse: collection LCP 20 s, MOB-1850).
409
+ */
410
+ readonly heroImageSrc: Signal<string>;
411
+ readonly description: Signal<string>;
412
+ /**
413
+ * „author | date” row under the hero title. `undefined` when there is
414
+ * nothing to show — the hero then renders no paragraph at all.
415
+ */
416
+ readonly heroMeta: Signal<string | undefined>;
417
+ /** The API answered 404 — the page shows „not found” instead of nothing. */
418
+ readonly notFound: Signal<boolean>;
419
+ /** Other load errors — a message with a retry. */
420
+ readonly hasLoadError: Signal<boolean>;
421
+ readonly selectedPage: Signal<number>;
422
+ readonly totalCount: Signal<number>;
423
+ readonly list: Signal<CollectionDetailsItem[]>;
424
+ /** The collection's objects — the grid under „Objects in the collection”. */
425
+ readonly objectItems: Signal<CollectionDetailsItem[]>;
426
+ /**
427
+ * „Unusual stories and articles related to the collection” — articles from
428
+ * `search/Article` with the `relatedEntryCollections` filter (MOB-1601),
429
+ * not from the collection items. The API title may be HTML (`<p>…</p>`)
430
+ * with entities (`&nbsp;`, `&amp;`), so the link gets decoded plain text.
431
+ * `[]` and no request without the `relatedArticles` option.
432
+ */
433
+ readonly relatedArticles: Signal<ICollectionRelatedArticle[]>;
434
+ /** Screen reader message after cards were appended („więcej ↓”). */
435
+ readonly loadMoreStatus: WritableSignal<string>;
436
+ /**
437
+ * „więcej ↓” on mobile („More objects” 2290:10482) — objects of the
438
+ * previous pages + the current one; the focus moves to the first appended
439
+ * card.
440
+ */
441
+ readonly loadMore: ICatalogLoadMore<CollectionDetailsItem>;
442
+ protected constructor(options?: ICollectionDetailsOptions);
443
+ onListMode(value: ListMode): void;
444
+ onToolbarSortChange({ by, desc }: ICatalogSort): void;
445
+ /** Sort by a dropdown key (`name-desc`, `random`). */
446
+ sortChange(key: string): void;
447
+ /** Repeats the last request — a new filter reference forces another call. */
448
+ retryLoad(): void;
449
+ limitChange(value: number | string): void;
450
+ pageChange(page: number): void;
451
+ /** Page change from the bottom pagination — scrolls to the list once loaded. */
452
+ bottomPageChange(page: number): void;
453
+ isObject(type: PublicCollectionItemType): boolean;
454
+ $MsObject(item: unknown): MsObject;
455
+ /** SEO of the collection: `<title> - <site>`, description, image alt. */
456
+ protected buildSeoMetadata(item: IPublicCollectionPage): ISeoMetadata;
457
+ private get collectionDetailsSiteNameKey();
458
+ private collectionDetailsIsMobile;
459
+ private collectionDetailsInitListMode;
460
+ private collectionDetailsFetchSsrSeo;
461
+ private collectionDetailsFormatDate;
462
+ static ɵfac: i0.ɵɵFactoryDeclaration<CollectionDetailsBaseComponent, never>;
463
+ static ɵdir: i0.ɵɵDirectiveDeclaration<CollectionDetailsBaseComponent, never, never, {}, {}, never, never, true, never>;
464
+ }
465
+
466
+ /** How long (ms) the "link copied" message stays after a click. */
467
+ declare const COLLECTION_SHARE_COPIED_TIMEOUT = 3000;
468
+ /**
469
+ * Logic of the "Share collection" button: the native share sheet, or a
470
+ * clipboard copy with a "link copied" flag when the browser has no share sheet.
471
+ * The template stays in the app.
472
+ */
473
+ declare abstract class CollectionShareButtonBaseComponent {
474
+ private readonly collectionShareButtonPlatformId;
475
+ private readonly collectionShareButtonDocument;
476
+ private readonly collectionShareButtonTimeouts;
477
+ protected readonly copied: i0.WritableSignal<boolean>;
478
+ /** How long (ms) "copied" stays on; overridable, read inside `share`. */
479
+ protected readonly collectionShareButtonCopiedTimeout: number;
480
+ protected share(): Promise<void>;
481
+ static ɵfac: i0.ɵɵFactoryDeclaration<CollectionShareButtonBaseComponent, never>;
482
+ static ɵdir: i0.ɵɵDirectiveDeclaration<CollectionShareButtonBaseComponent, never, never, {}, {}, never, never, true, never>;
483
+ }
484
+
485
+ export { COLLECTIONS_CATALOG_DEFAULTS, COLLECTIONS_CATALOG_SEO, COLLECTIONS_CYCLES_FILTER_KEY, COLLECTION_DETAILS_DEFAULTS, COLLECTION_SHARE_COPIED_TIMEOUT, CollectionDetailsBaseComponent, CollectionShareButtonBaseComponent, CollectionsCatalogBaseComponent, ComponentsModule, FiltersComponent, ListComponent, PUBLIC_COLLECTION_RELATED_ARTICLES_LIMIT, PublicCollectionItemsService, PublicCollectionsFacade, PublicCollectionsItemComponent, PublicCollectionsListComponent, PublicCollectionsModule, PublicCollectionsService, PublicCollectionsSharedModule, SERVICES, dropLegacyCollectionKeywords, getPublicCollectionsState, getReducer, initialState };
486
+ export type { CollectionDetailsItem, ICollectionDetailsLoadMore, ICollectionDetailsOptions, ICollectionRelatedArticle, ICollectionsCatalogLoadMore, ICollectionsCatalogOptions, ICollectionsCatalogSeo, IPublicCollectionPage, IPublicCollectionPaginator, State };