@smartsoft001-mobilems/claude-plugins 2.128.0 → 2.129.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.
- package/package.json +1 -1
- package/plugins/mobilems/.claude-plugin/plugin.json +1 -1
- package/plugins/mobilems/skills/mobilems-objects/SKILL.md +16 -11
- package/plugins/mobilems/skills/mobilems-objects/references/lib-contents.md +8 -3
- package/plugins/mobilems/skills/mobilems-objects/scripts/verify-module.sh +29 -0
- package/plugins/mobilems/skills/mobilems-project-init/references/shared-lib.md +2 -0
package/package.json
CHANGED
|
@@ -35,16 +35,21 @@ list — re-implementing framework code is a defect, not a shortcut:
|
|
|
35
35
|
2. [`packages/objects/README.md`](https://github.com/smartsoft001/mobilems-framework/blob/main/packages/objects/README.md) — this module's package catalog
|
|
36
36
|
3. `libs/shared/angular/README.md` — the app's own shared lib (built by `mobilems-project-init`)
|
|
37
37
|
|
|
38
|
-
| Do not hand-roll | Use
|
|
39
|
-
| ----------------------------------------------------------------------------------------------------------------- |
|
|
40
|
-
| a masonry grid (`new Masonry(...)`, per-page masonry JS/CSS) | `<smart-mobilems-masonry-grid>` (`MasonryGridComponent`) with a `#masonryContentTpl`; the `Masonry` provider in step 3 only feeds it
|
|
41
|
-
| filter state / hand-built `query` arrays | `FiltersBaseComponent<MsObject>` + its `FiltersContext` accessors (`searchText`, `keywords`, `page`, `sort`, `onlyImage`, …)
|
|
42
|
-
| list page logic (first read, persistence, SSR read, read guard, load-more, masonry lifecycle, list SEO) | `ObjectsCatalogBaseComponent` (`pages/list` extends it; the app keeps its own markup and `sortOptions` over `isNewType`)
|
|
43
|
-
| detail page logic (SSR SEO, scroll, visit counter, retry, opt-in related / related collections) | `ObjectDetailsBaseComponent` (extends `ObjectsItemComponent`; `pages/item` extends it, `related` and `relatedCollections` are opt-in via the constructor options)
|
|
44
|
-
| object detail field helpers (title, tags, inventory, bibliography, description, related articles, ask-about link) | the `objectTitle`, `tagValues`, `inventoryValues`, `bibliography`, `descriptionHtml`, `relatedArticles`, `askAboutObjectHref` tools
|
|
45
|
-
| gallery / media lists | `ObjectMediaService`
|
|
46
|
-
| visit counter, related objects, collection / archaeological dictionaries | `ObjectsDataService` (extends `ObjectsService`)
|
|
47
|
-
|
|
|
38
|
+
| Do not hand-roll | Use |
|
|
39
|
+
| ----------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
40
|
+
| a masonry grid (`new Masonry(...)`, per-page masonry JS/CSS) | `<smart-mobilems-masonry-grid>` (`MasonryGridComponent`) with a `#masonryContentTpl`; the `Masonry` provider in step 3 only feeds it |
|
|
41
|
+
| filter state / hand-built `query` arrays | `FiltersBaseComponent<MsObject>` + its `FiltersContext` accessors (`searchText`, `keywords`, `page`, `sort`, `onlyImage`, …) |
|
|
42
|
+
| list page logic (first read, persistence, SSR read, read guard, load-more, masonry lifecycle, list SEO) | `ObjectsCatalogBaseComponent` (`pages/list` extends it; the app keeps its own markup and `sortOptions` over `isNewType`) |
|
|
43
|
+
| detail page logic (SSR SEO, scroll, visit counter, retry, opt-in related / related collections) | `ObjectDetailsBaseComponent` (extends `ObjectsItemComponent`; `pages/item` extends it, `related` and `relatedCollections` are opt-in via the constructor options) |
|
|
44
|
+
| object detail field helpers (title, tags, inventory, bibliography, description, related articles, ask-about link) | the `objectTitle`, `tagValues`, `inventoryValues`, `bibliography`, `descriptionHtml`, `relatedArticles`, `askAboutObjectHref` tools |
|
|
45
|
+
| gallery / media lists | `ObjectMediaService` |
|
|
46
|
+
| visit counter, related objects, collection / archaeological dictionaries | `ObjectsDataService` (extends `ObjectsService`) |
|
|
47
|
+
| filter bar (sort / limit, chips, dictionary toggles, year range, theme tags) | `ObjectsFiltersBarBaseComponent` (`components/filters-top` extends it; the app keeps its markup; the cycle theme tags are opt-in with `cycleTags: true`, otherwise no `dictionary/Cycle` request) |
|
|
48
|
+
| search panel (phrase, tags, boolean filters) - Podlasie-style museums only | `ObjectsSearchPanelBaseComponent` (S/T-style museums have no search panel: they use the filters bar only) |
|
|
49
|
+
| advanced filters panel - Podlasie-style museums only | `ObjectsAdvancedFiltersBaseComponent` (the field config `IObjectsAdvancedFilterField[]` stays in the app, the framework exports only the types; S/T-style museums skip it) |
|
|
50
|
+
| share results link | `ObjectsShareResultsBaseComponent` (extends the shared `ShareLinkBaseComponent`; set `objectsShareResultsListPath` for another list) |
|
|
51
|
+
| sort / limit options, sort keys, results URL | `OBJECTS_SORT_OPTIONS`, `OBJECTS_NEW_TYPE_SORT_OPTIONS`, `OBJECTS_LIMIT_OPTIONS`, `objectsSortKey`, `objectsSortFromKey`, `buildObjectsResultsUrl` |
|
|
52
|
+
| media URLs, meta/OG tags, filter dictionaries, modals, WCAG | `FileUrlService`, `SeoService`/`MetaService`, `DictionaryService`, `ModalService`, `WcagService` |
|
|
48
53
|
|
|
49
54
|
Anything the framework genuinely lacks goes into `libs/shared/angular` **once** (and into its
|
|
50
55
|
README) — never a per-module copy. `scripts/verify-module.sh` fails the run on hand-rolled masonry.
|
|
@@ -109,7 +114,7 @@ tab, the grid/list item cards and the object gallery widget.
|
|
|
109
114
|
The cross-cutting rules live in `mobilems-project-init`
|
|
110
115
|
`references/qa-hardening.md`; these are the objects-specific ones:
|
|
111
116
|
|
|
112
|
-
- **Search debounce.**
|
|
117
|
+
- **Search debounce.** For apps that render the panel full-text search with `app-objects-searchbar variant="panel"` (a standalone component: a live debounced search through `searchEvent` / `closeEvent`, an `autofocus` input, never navigates - it does not extend `SearchbarBaseComponent`, which navigates to the search route; the filter bases do not need it), the host must
|
|
113
118
|
re-emit through a handler with `@debounce(250)` (`lodash-decorators`) — without it every keystroke
|
|
114
119
|
hits the API. Collections and news filters already do this; keep the modules consistent.
|
|
115
120
|
- **List page:** show the total result count (`facade.totalCount()`) and add the shared
|
|
@@ -20,8 +20,10 @@ libs/museum-objects/
|
|
|
20
20
|
└── lib/
|
|
21
21
|
├── objects.module.ts # MuseumObjectsModule (references/module-and-routes.md)
|
|
22
22
|
├── objects.routes.ts
|
|
23
|
-
├── components/ # description,
|
|
24
|
-
│ # menu, objects-searchbar (
|
|
23
|
+
├── components/ # description, filters-top (extends ObjectsFiltersBarBaseComponent), high-def-request-modal,
|
|
24
|
+
│ # menu, objects-searchbar (only where the app renders the panel search), tabs/*;
|
|
25
|
+
│ # no filter-input (it comes from the shared lib); Podlasie-style apps also keep
|
|
26
|
+
│ # objects-search-panel and objects-advanced-filters (extend the framework bases)
|
|
25
27
|
├── pages/ # list (ListComponent), item (ItemComponent) + index
|
|
26
28
|
└── services/ # no local objects.service / object-media.service (framework ObjectsDataService, ObjectMediaService)
|
|
27
29
|
```
|
|
@@ -29,7 +31,10 @@ libs/museum-objects/
|
|
|
29
31
|
`pages/list` extends `ObjectsCatalogBaseComponent` (logic only: first read, persistence, SSR read, read guard,
|
|
30
32
|
load-more, masonry lifecycle, list SEO) and keeps the app's own markup and `sortOptions` over `isNewType`;
|
|
31
33
|
`pages/item` extends `ObjectDetailsBaseComponent` (SSR SEO, scroll, visit counter, retry, opt-in related / related
|
|
32
|
-
collections; the app keeps its markup).
|
|
34
|
+
collections; the app keeps its markup). `components/filters-top` extends `ObjectsFiltersBarBaseComponent` (cycle tags
|
|
35
|
+
opt-in); `objects-search-panel` / `objects-advanced-filters` / `objects-share-results`, where an app has them, extend
|
|
36
|
+
`ObjectsSearchPanelBaseComponent` / `ObjectsAdvancedFiltersBaseComponent` / `ObjectsShareResultsBaseComponent`
|
|
37
|
+
(S/T-style museums use the filters bar only). There is no local `objects.service` or `object-media.service`.
|
|
33
38
|
|
|
34
39
|
## Domain entity (verbatim, thread nothing — pure types)
|
|
35
40
|
|
|
@@ -138,6 +138,35 @@ else
|
|
|
138
138
|
pass "no hand-rolled visit counter, SSR apply or media service"
|
|
139
139
|
fi
|
|
140
140
|
|
|
141
|
+
# 7. filter bar logic lives in the framework filters bar base; no local copies of its helpers
|
|
142
|
+
FILTERSF="$LIBDIR/components/filters-top/filters-top.component.ts"
|
|
143
|
+
if [ -f "$FILTERSF" ]; then
|
|
144
|
+
if grep -qE "extends[[:space:]]+ObjectsFiltersBarBaseComponent" "$FILTERSF"; then
|
|
145
|
+
pass "filters-top extends ObjectsFiltersBarBaseComponent"
|
|
146
|
+
else
|
|
147
|
+
bad "components/filters-top/filters-top.component.ts does not extend ObjectsFiltersBarBaseComponent — filter bar logic belongs to the framework base ($FILTERSF)"
|
|
148
|
+
fi
|
|
149
|
+
fi
|
|
150
|
+
if grep -rqE "class RedirectFiltersContext|function buildObjectsResultsUrl" "$LIBDIR" 2>/dev/null; then
|
|
151
|
+
bad "lib contains class RedirectFiltersContext or function buildObjectsResultsUrl — use ObjectsFiltersBarBaseComponent / buildObjectsResultsUrl from the framework:"
|
|
152
|
+
grep -rnE "class RedirectFiltersContext|function buildObjectsResultsUrl" "$LIBDIR" >&2 || true
|
|
153
|
+
else
|
|
154
|
+
pass "no hand-rolled redirect filters context or results URL builder"
|
|
155
|
+
fi
|
|
156
|
+
|
|
157
|
+
# 8. search panel and advanced filters (Podlasie-style apps only) extend the framework bases
|
|
158
|
+
for pair in "objects-search-panel.component.ts:ObjectsSearchPanelBaseComponent" "objects-advanced-filters.component.ts:ObjectsAdvancedFiltersBaseComponent"; do
|
|
159
|
+
fname="${pair%%:*}"
|
|
160
|
+
base="${pair##*:}"
|
|
161
|
+
for found in $(find "$LIBDIR" -name "$fname" 2>/dev/null); do
|
|
162
|
+
if grep -qE "extends[[:space:]]+$base" "$found"; then
|
|
163
|
+
pass "$fname extends $base"
|
|
164
|
+
else
|
|
165
|
+
bad "$fname does not extend $base — its logic belongs to the framework base ($found)"
|
|
166
|
+
fi
|
|
167
|
+
done
|
|
168
|
+
done
|
|
169
|
+
|
|
141
170
|
echo "== Translations (REF_ROOT=${REF_ROOT:-unset}) =="
|
|
142
171
|
# Groups: present in pl+en, no dead references, complete vs the reference repo
|
|
143
172
|
# (export REF_ROOT=<reference-repo-root> to enable the completeness diff).
|
|
@@ -57,6 +57,8 @@ not as copies of the reference logic. The museum keeps its own template and styl
|
|
|
57
57
|
stores (favorites, selection, downloads, recommended items) stay in the museum and reach the base
|
|
58
58
|
through its hooks (`IFavoriteHooks`, `ISelectionActionsFavorites`, `IRecommendedSources`, the abstract `downloadCardsExport`).
|
|
59
59
|
|
|
60
|
+
A share-link button (e.g. `share-results`, collection share) extends `ShareLinkBaseComponent` (`SHARE_LINK_COPIED_TIMEOUT`): implement `shareLinkUrl()`, bind `share()` and `copied()`, write the markup yourself.
|
|
61
|
+
|
|
60
62
|
The same applies to the foundation shared components `favorite-button`, `favorites-notice`,
|
|
61
63
|
`selection-actions`, `download-cards` and `recommended`: extend `FavoriteButtonBaseComponent`,
|
|
62
64
|
`FavoritesNoticeBaseComponent`, `SelectionActionsBaseComponent`, `DownloadCardsBaseComponent` and
|